summaryrefslogtreecommitdiff
path: root/game/server/tf2/tf_obj_mortar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/server/tf2/tf_obj_mortar.cpp')
-rw-r--r--game/server/tf2/tf_obj_mortar.cpp266
1 files changed, 266 insertions, 0 deletions
diff --git a/game/server/tf2/tf_obj_mortar.cpp b/game/server/tf2/tf_obj_mortar.cpp
new file mode 100644
index 0000000..2473519
--- /dev/null
+++ b/game/server/tf2/tf_obj_mortar.cpp
@@ -0,0 +1,266 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Indirect's mortar object
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "tf_player.h"
+#include "tf_team.h"
+#include "basecombatweapon.h"
+#include "tf_obj.h"
+#include "tf_obj_mortar.h"
+#include "techtree.h"
+#include "tf_shareddefs.h"
+#include "weapon_mortar.h"
+#include "vstdlib/random.h"
+#include "movevars_shared.h"
+#include "mortar_round.h"
+
+
+LINK_ENTITY_TO_CLASS(obj_mortar, CObjectMortar);
+PRECACHE_REGISTER(obj_mortar);
+
+IMPLEMENT_SERVERCLASS_ST(CObjectMortar, DT_ObjectMortar)
+ SendPropInt( SENDINFO( m_iRoundType ), 8, SPROP_UNSIGNED, 0 ),
+ SendPropArray( SendPropInt( SENDINFO_ARRAY(m_iMortarRounds), 7, 0 ), m_iMortarRounds ),
+END_SEND_TABLE();
+
+BEGIN_DATADESC( CObjectMortar )
+
+ DEFINE_THINKFUNC( ReloadingThink ),
+
+END_DATADESC()
+
+// Mortar size
+#define MORTAR_MINS Vector(-16, -16, 0)
+#define MORTAR_MAXS Vector( 16, 16, 64)
+
+ConVar obj_mortar_health( "obj_mortar_health","200", FCVAR_NONE, "Mortar object health" );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CObjectMortar::CObjectMortar()
+{
+ for ( int i=0; i < m_iMortarRounds.Count(); i++ )
+ m_iMortarRounds.Set( i, 0 );
+ m_flLastBlastTime = -1;
+ UseClientSideAnimation();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CObjectMortar::Spawn()
+{
+ SetModel( "models/objects/obj_mortar.mdl" );
+
+ SetSolid( SOLID_BBOX );
+ UTIL_SetSize(this, MORTAR_MINS, MORTAR_MAXS);
+ m_takedamage = DAMAGE_YES;
+ m_iHealth = obj_mortar_health.GetInt();
+ m_iRoundType = MA_SHELL;
+ m_iSalvoLeft = MORTAR_SALVO_SIZE;
+ m_fObjectFlags |= OF_DONT_PREVENT_BUILD_NEAR_OBJ;
+
+ SetType( OBJ_MORTAR );
+
+ // Fill out the ammo levels
+ for ( int i = 0; i < MA_LASTAMMOTYPE; i++ )
+ {
+ m_iMortarRounds.Set( i, MortarAmmoMax[i] );
+ }
+
+ BaseClass::Spawn();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CObjectMortar::Precache()
+{
+ PrecacheModel( "models/objects/obj_mortar.mdl" );
+ PrecacheVGuiScreen( "screen_obj_mortar" );
+}
+
+//-----------------------------------------------------------------------------
+// Gets info about the control panels
+//-----------------------------------------------------------------------------
+void CObjectMortar::GetControlPanelInfo( int nPanelIndex, const char *&pPanelName )
+{
+ pPanelName = "screen_obj_mortar";
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CObjectMortar::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
+{
+ // Sapper removal
+ if ( RemoveEnemyAttachments( pActivator ) )
+ return;
+
+ if ( pActivator == GetOwner() )
+ {
+ int iOldType = m_iRoundType;
+ m_iRoundType += 1;
+
+ // Cycle to the next ammo type
+ while ( m_iRoundType != iOldType )
+ {
+ // Hit the end of the round types?
+ if ( m_iRoundType == MA_LASTAMMOTYPE )
+ {
+ m_iRoundType = MA_SHELL;
+ break;
+ }
+
+ // Does this round type need a technology?
+ if ( MortarAmmoTechs[ m_iRoundType ] && MortarAmmoTechs[ m_iRoundType ][0] )
+ {
+ // Does the player have the technology?
+ if ( GetOwner() && GetOwner()->HasNamedTechnology( MortarAmmoTechs[ m_iRoundType ] ) )
+ {
+ // Do we have ammo?
+ if ( m_iMortarRounds[ m_iRoundType ] > 0 )
+ break;
+ }
+ }
+
+ // Go to the next round type
+ m_iRoundType += 1;
+ }
+ }
+ else
+ {
+ // Let other team's technician try to subvert it
+ BaseClass::Use( pActivator, pCaller, useType, value );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Fire a round from the mortar
+//-----------------------------------------------------------------------------
+bool CObjectMortar::FireMortar( float flFiringPower, float flFiringAccuracy, bool bRangeUpgraded, bool bAccuracyUpgraded )
+{
+ // Are we reloading?
+ if ( IsReloading() )
+ return false;
+ // Do we have any ammo of this type left?
+ if ( m_iMortarRounds[ m_iRoundType ] != -1 && m_iMortarRounds[ m_iRoundType ] == 0 )
+ return false;
+
+ // Get target distance
+ float flDistance;
+ if ( bRangeUpgraded )
+ {
+ flDistance = MORTAR_RANGE_MIN + (flFiringPower * (MORTAR_RANGE_MAX_UPGRADED - MORTAR_RANGE_MIN));
+ }
+ else
+ {
+ flDistance = MORTAR_RANGE_MIN + (flFiringPower * (MORTAR_RANGE_MAX_INITIAL - MORTAR_RANGE_MIN));
+ }
+
+ // Factor in inaccuracy
+ float flInaccuracy;
+ if ( bAccuracyUpgraded )
+ {
+ flInaccuracy = MORTAR_INACCURACY_MAX_UPGRADED * (flFiringAccuracy * 4); // flFiringAccuracy is a range from -0.25 to 0.25
+ }
+ else
+ {
+ flInaccuracy = MORTAR_INACCURACY_MAX_INITIAL * (flFiringAccuracy * 4); // flFiringAccuracy is a range from -0.25 to 0.25
+ }
+ flDistance += (flDistance * MORTAR_DIST_INACCURACY) * random->RandomFloat( -flInaccuracy, flInaccuracy );
+
+ Vector forward, right;
+ AngleVectors( GetAbsAngles(), &forward, &right, NULL );
+ Vector vecTargetOrg = GetAbsOrigin() + (forward * flDistance);
+ // Add in sideways inaccuracy
+ vecTargetOrg += (right * (flDistance * flInaccuracy) );
+
+ // Trace down from the sky and find the point we're actually going to hit
+ trace_t tr;
+ Vector vecSky = vecTargetOrg + Vector(0,0,1024);
+ UTIL_TraceLine( vecSky, vecTargetOrg, MASK_ALL, this, COLLISION_GROUP_NONE, &tr );
+ vecTargetOrg = tr.endpos;
+
+ Vector vecMidPoint = vec3_origin;
+ // Start with a low arc, and keep aiming higher until we've got a roughly clear shot
+ for (int i = 2048; i <= 4096; i += 1024)
+ {
+ trace_t tr1;
+ trace_t tr2;
+
+ vecMidPoint = Vector(0,0,i) + GetAbsOrigin() + (vecTargetOrg - GetAbsOrigin()) * 0.5;
+ UTIL_TraceLine(GetAbsOrigin(), vecMidPoint, MASK_ALL, this, COLLISION_GROUP_NONE, &tr1);
+ UTIL_TraceLine(vecMidPoint, vecTargetOrg, MASK_ALL, this, COLLISION_GROUP_NONE, &tr2);
+
+ // Clear shot?
+ // We want a clear shot for the first half, and a fairly clear shot on the fall
+ if ( tr1.fraction == 1 && tr2.fraction > 0.5 )
+ break;
+ }
+
+ // How high should we travel to reach the apex
+ float distance1 = (vecMidPoint.z - GetAbsOrigin().z);
+ float distance2 = (vecMidPoint.z - vecTargetOrg.z);
+
+ // How long will it take to travel this distance
+ float flGravity = GetCurrentGravity();
+ float time1 = sqrt( distance1 / (0.5 * flGravity) );
+ float time2 = sqrt( distance2 / (0.5 * flGravity) );
+ if (time1 < 0.1)
+ return false;
+
+ // how hard to launch to get there in time.
+ Vector vecTargetVel = (vecTargetOrg - GetLocalOrigin()) / (time1 + time2);
+ vecTargetVel.z = flGravity * time1;
+
+ // Create the round
+ CMortarRound *pRound = CMortarRound::Create( GetLocalOrigin(), vecTargetVel, edict() );
+ pRound->ChangeTeam( GetTeamNumber() );
+ pRound->SetFallTime( time1 * 0.5 ); // Start a falling sound just a bit before we begin to fall
+ pRound->SetRoundType( m_iRoundType );
+
+ // Decrease ammo count
+ if ( m_iMortarRounds[ m_iRoundType ] > 0 )
+ {
+ m_iMortarRounds.Set( m_iRoundType, m_iMortarRounds[m_iRoundType]-1 );
+ }
+
+ // Decrease salvo count
+ if ( m_iSalvoLeft )
+ {
+ m_iSalvoLeft--;
+ if ( m_iSalvoLeft <= 0 )
+ {
+ // Time to reload
+ StartReloading();
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Start reloading our next salvo
+//-----------------------------------------------------------------------------
+void CObjectMortar::StartReloading( void )
+{
+ SetThink( ReloadingThink );
+ SetNextThink( gpGlobals->curtime + MORTAR_RELOAD_TIME );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Finish reloading our salvo
+//-----------------------------------------------------------------------------
+void CObjectMortar::ReloadingThink( void )
+{
+ SetThink( NULL );
+
+ m_iSalvoLeft = MORTAR_SALVO_SIZE;
+}
+