You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
266 lines
7.9 KiB
266 lines
7.9 KiB
//========= 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; |
|
} |
|
|
|
|