diff options
Diffstat (limited to 'game/server/tf2/tf_obj_mortar.cpp')
| -rw-r--r-- | game/server/tf2/tf_obj_mortar.cpp | 266 |
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; +} + |