mirror of
https://github.com/celisej567/source-engine.git
synced 2026-01-05 22:09:59 +03:00
1
This commit is contained in:
249
game/server/tf2/basecombatcharacter_tf2.cpp
Normal file
249
game/server/tf2/basecombatcharacter_tf2.cpp
Normal file
@@ -0,0 +1,249 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: TF2 specific CBaseCombatCharacter code.
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "basecombatcharacter.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "tf_player.h"
|
||||
#include "tf_stats.h"
|
||||
|
||||
extern char *g_pszEMPPulseStart;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseCombatCharacter::HasPowerup( int iPowerup )
|
||||
{
|
||||
Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS );
|
||||
return ( m_iPowerups & (1 << iPowerup) ) != 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseCombatCharacter::CanPowerupEver( int iPowerup )
|
||||
{
|
||||
Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS );
|
||||
|
||||
// Only objects use power
|
||||
if ( iPowerup == POWERUP_POWER )
|
||||
return false;
|
||||
|
||||
// Accept everything else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseCombatCharacter::CanPowerupNow( int iPowerup )
|
||||
{
|
||||
Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS );
|
||||
|
||||
if ( !CanPowerupEver(iPowerup) )
|
||||
return false;
|
||||
|
||||
switch( iPowerup )
|
||||
{
|
||||
case POWERUP_BOOST:
|
||||
{
|
||||
// Am I taking EMP damage, or is a technician trying to drain me?
|
||||
if ( HasPowerup( POWERUP_EMP ) || ( (m_flPowerupAttemptTimes[POWERUP_EMP] + 0.5) > gpGlobals->curtime ) )
|
||||
{
|
||||
// Reduce EMP time
|
||||
m_flPowerupEndTimes[POWERUP_EMP] -= 0.05;
|
||||
|
||||
// Don't apply any boost effects
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case POWERUP_EMP:
|
||||
{
|
||||
// Was I just boosted? If so, I don't take EMP damage for a bit
|
||||
if ( (m_flPowerupAttemptTimes[POWERUP_BOOST] + 0.5) > gpGlobals->curtime )
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseCombatCharacter::SetPowerup( int iPowerup, bool bState, float flTime, float flAmount, CBaseEntity *pAttacker, CDamageModifier *pDamageModifier )
|
||||
{
|
||||
Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS );
|
||||
|
||||
// Some powerups trigger their on state continuously, as opposed to turning it on for some time.
|
||||
bool bTriggerStart = ( bState && !HasPowerup( iPowerup ) );
|
||||
if ( bState && iPowerup == POWERUP_BOOST )
|
||||
{
|
||||
// Health boost always triggers
|
||||
bTriggerStart = true;
|
||||
}
|
||||
|
||||
bool bHadPowerup = false;
|
||||
if ( HasPowerup( iPowerup ) && !bState )
|
||||
{
|
||||
bHadPowerup = true;
|
||||
}
|
||||
|
||||
if ( bState )
|
||||
{
|
||||
m_iPowerups |= (1 << iPowerup);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iPowerups &= ~(1 << iPowerup);
|
||||
}
|
||||
|
||||
// Fire start/end triggers
|
||||
if ( bTriggerStart )
|
||||
{
|
||||
PowerupStart( iPowerup, flAmount, pAttacker, pDamageModifier );
|
||||
}
|
||||
else if ( bHadPowerup )
|
||||
{
|
||||
PowerupEnd( iPowerup );
|
||||
}
|
||||
|
||||
// If we've got an active powerup, keep thinking
|
||||
if ( m_iPowerups )
|
||||
{
|
||||
SetContextThink( PowerupThink, gpGlobals->curtime + 0.1, POWERUP_THINK_CONTEXT );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseCombatCharacter::PowerupThink( void )
|
||||
{
|
||||
// If we don't have any powerups, stop thinking
|
||||
if ( !m_iPowerups )
|
||||
return;
|
||||
|
||||
// Check all the powerups
|
||||
for ( int i = 0; i < MAX_POWERUPS; i++ )
|
||||
{
|
||||
// Don't check power, because it never runs out naturally
|
||||
if ( i == POWERUP_POWER )
|
||||
continue;
|
||||
|
||||
if ( m_iPowerups & (1 << i) )
|
||||
{
|
||||
// Should it finish now?
|
||||
if ( m_flPowerupEndTimes[i] < gpGlobals->curtime )
|
||||
{
|
||||
SetPowerup( i, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetNextThink( gpGlobals->curtime + 0.1, POWERUP_THINK_CONTEXT );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseCombatCharacter::AttemptToPowerup( int iPowerup, float flTime, float flAmount, CBaseEntity *pAttacker, CDamageModifier *pDamageModifier )
|
||||
{
|
||||
Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS );
|
||||
|
||||
// Ignore it if I'm dead
|
||||
if ( !IsAlive() )
|
||||
return false;
|
||||
|
||||
m_flPowerupAttemptTimes[iPowerup] = gpGlobals->curtime;
|
||||
|
||||
// If we can't be powerup this type, abort
|
||||
if ( !CanPowerupNow( iPowerup ) )
|
||||
return false;
|
||||
|
||||
// Get the correct duration
|
||||
flTime = PowerupDuration( iPowerup, flTime );
|
||||
m_flPowerupEndTimes[iPowerup] = MAX( m_flPowerupEndTimes[iPowerup], gpGlobals->curtime + flTime );
|
||||
|
||||
// Turn it on
|
||||
SetPowerup( iPowerup, true, flTime, flAmount, pAttacker, pDamageModifier );
|
||||
|
||||
// Add the damage modifier to the player
|
||||
if ( pDamageModifier )
|
||||
{
|
||||
pDamageModifier->AddModifierToEntity( this );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Powerup has just started
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseCombatCharacter::PowerupStart( int iPowerup, float flAmount, CBaseEntity *pAttacker, CDamageModifier *pDamageModifier )
|
||||
{
|
||||
Assert( iPowerup >= 0 && iPowerup < MAX_POWERUPS );
|
||||
|
||||
switch( iPowerup )
|
||||
{
|
||||
case POWERUP_BOOST:
|
||||
{
|
||||
// Players can be boosted over their max
|
||||
int iMaxBoostedHealth;
|
||||
if ( IsPlayer() )
|
||||
{
|
||||
iMaxBoostedHealth = GetMaxHealth() + GetMaxHealth() / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
iMaxBoostedHealth = GetMaxHealth();
|
||||
}
|
||||
|
||||
// Can we boost health further?
|
||||
if ( GetHealth() < iMaxBoostedHealth )
|
||||
{
|
||||
int maxHealthToAdd = iMaxBoostedHealth - GetHealth();
|
||||
|
||||
// It uses floating point in here so it doesn't lose the fractional healing part on small frame times.
|
||||
float flHealthToAdd = flAmount + m_flFractionalBoost;
|
||||
int nHealthToAdd = (int)flHealthToAdd;
|
||||
m_flFractionalBoost = flHealthToAdd - nHealthToAdd;
|
||||
if ( nHealthToAdd )
|
||||
{
|
||||
int nHealthAdded = MIN( nHealthToAdd, maxHealthToAdd );
|
||||
if ( IsPlayer() )
|
||||
{
|
||||
((CBaseTFPlayer*)this)->TakeHealthBoost( nHealthAdded, GetMaxHealth(), 25 );
|
||||
}
|
||||
else
|
||||
{
|
||||
TakeHealth( nHealthAdded, DMG_GENERIC );
|
||||
}
|
||||
|
||||
TFStats()->IncrementPlayerStat( pAttacker, TF_PLAYER_STAT_HEALTH_GIVEN, nHealthAdded );
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case POWERUP_EMP:
|
||||
{
|
||||
// EMP removes adrenalin rush
|
||||
SetPowerup( POWERUP_RUSH, false );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
424
game/server/tf2/bot_base.cpp
Normal file
424
game/server/tf2/bot_base.cpp
Normal file
@@ -0,0 +1,424 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Basic BOT handling.
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "player.h"
|
||||
#include "tf_player.h"
|
||||
#include "menu_base.h"
|
||||
#include "in_buttons.h"
|
||||
#include "movehelper_server.h"
|
||||
#include "weapon_twohandedcontainer.h"
|
||||
|
||||
void ParseCommand( CBaseTFPlayer *pPlayer, const char *pcmd, const char *pargs );
|
||||
void ClientPutInServer( edict_t *pEdict, const char *playername );
|
||||
void Bot_Think( CBaseTFPlayer *pBot );
|
||||
|
||||
ConVar bot_forcefireweapon( "bot_forcefireweapon", "", 0, "Force bots with the specified weapon to fire." );
|
||||
ConVar bot_forceattack2( "bot_forceattack2", "0", 0, "When firing, use attack2." );
|
||||
ConVar bot_forceattackon( "bot_forceattackon", "0", 0, "When firing, don't tap fire, hold it down." );
|
||||
ConVar bot_flipout( "bot_flipout", "0", 0, "When on, all bots fire their guns." );
|
||||
ConVar bot_defend( "bot_defend", "0", 0, "Set to a team number, and that team will all keep their combat shields raised." );
|
||||
ConVar bot_changeclass( "bot_changeclass", "0", 0, "Force all bots to change to the specified class." );
|
||||
static ConVar bot_mimic( "bot_mimic", "0", 0, "Bot uses usercmd of player by index." );
|
||||
|
||||
static int BotNumber = 1;
|
||||
static int g_iNextBotTeam = -1;
|
||||
static int g_iNextBotClass = -1;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Create a new Bot and put it in the game.
|
||||
// Output : Pointer to the new Bot, or NULL if there's no free clients.
|
||||
//-----------------------------------------------------------------------------
|
||||
CBasePlayer *BotPutInServer( bool bFrozen, int iTeam, int iClass )
|
||||
{
|
||||
g_iNextBotTeam = iTeam;
|
||||
g_iNextBotClass = iClass;
|
||||
|
||||
char botname[ 64 ];
|
||||
Q_snprintf( botname, sizeof( botname ), "Bot%02i", BotNumber );
|
||||
|
||||
edict_t *pEdict = NULL;
|
||||
{
|
||||
bool oldLock = engine->LockNetworkStringTables( false );
|
||||
pEdict = engine->CreateFakeClient( botname );
|
||||
engine->LockNetworkStringTables( oldLock );
|
||||
}
|
||||
|
||||
if ( !pEdict )
|
||||
{
|
||||
Msg( "Failed to create Bot.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Allocate a CBasePlayer for the bot, and call spawn
|
||||
ClientPutInServer( pEdict, botname );
|
||||
CBaseTFPlayer *pPlayer = ((CBaseTFPlayer *)CBaseEntity::Instance( pEdict ));
|
||||
pPlayer->ClearFlags();
|
||||
pPlayer->AddFlag( FL_CLIENT | FL_FAKECLIENT );
|
||||
|
||||
if ( bFrozen )
|
||||
pPlayer->AddEFlags( EFL_BOT_FROZEN );
|
||||
|
||||
if ( iTeam != -1 )
|
||||
{
|
||||
pPlayer->ChangeTeam( iTeam );
|
||||
}
|
||||
pPlayer->ForceRespawn();
|
||||
|
||||
BotNumber++;
|
||||
|
||||
return pPlayer;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Run through all the Bots in the game and let them think.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Bot_RunAll( void )
|
||||
{
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( UTIL_PlayerByIndex( i ) );
|
||||
|
||||
if ( pPlayer && (pPlayer->GetFlags() & FL_FAKECLIENT) )
|
||||
{
|
||||
Bot_Think( pPlayer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool backwards;
|
||||
|
||||
float nextturntime;
|
||||
bool lastturntoright;
|
||||
|
||||
float nextstrafetime;
|
||||
float sidemove;
|
||||
|
||||
QAngle forwardAngle;
|
||||
QAngle lastAngles;
|
||||
} botdata_t;
|
||||
|
||||
static botdata_t g_BotData[ MAX_PLAYERS ];
|
||||
|
||||
bool RunMimicCommand( CUserCmd& cmd )
|
||||
{
|
||||
if ( bot_mimic.GetInt() <= 0 )
|
||||
return false;
|
||||
|
||||
if ( bot_mimic.GetInt() > gpGlobals->maxClients )
|
||||
return false;
|
||||
|
||||
|
||||
CBasePlayer *pPlayer = UTIL_PlayerByIndex( bot_mimic.GetInt() );
|
||||
if ( !pPlayer )
|
||||
return false;
|
||||
|
||||
if ( !pPlayer->GetLastUserCommand() )
|
||||
return false;
|
||||
|
||||
cmd = *pPlayer->GetLastUserCommand();
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Simulates a single frame of movement for a player
|
||||
// Input : *fakeclient -
|
||||
// *viewangles -
|
||||
// forwardmove -
|
||||
// sidemove -
|
||||
// upmove -
|
||||
// buttons -
|
||||
// impulse -
|
||||
// msec -
|
||||
// Output : virtual void
|
||||
//-----------------------------------------------------------------------------
|
||||
static void RunPlayerMove( CBaseTFPlayer *fakeclient, const QAngle& viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, float frametime )
|
||||
{
|
||||
if ( !fakeclient )
|
||||
return;
|
||||
|
||||
CUserCmd cmd;
|
||||
|
||||
// Store off the globals.. they're gonna get whacked
|
||||
float flOldFrametime = gpGlobals->frametime;
|
||||
float flOldCurtime = gpGlobals->curtime;
|
||||
|
||||
float flTimeBase = gpGlobals->curtime + gpGlobals->frametime - frametime;
|
||||
fakeclient->SetTimeBase( flTimeBase );
|
||||
|
||||
Q_memset( &cmd, 0, sizeof( cmd ) );
|
||||
|
||||
if ( !RunMimicCommand( cmd ) )
|
||||
{
|
||||
VectorCopy( viewangles, cmd.viewangles );
|
||||
cmd.forwardmove = forwardmove;
|
||||
cmd.sidemove = sidemove;
|
||||
cmd.upmove = upmove;
|
||||
cmd.buttons = buttons;
|
||||
cmd.impulse = impulse;
|
||||
cmd.random_seed = random->RandomInt( 0, 0x7fffffff );
|
||||
}
|
||||
|
||||
MoveHelperServer()->SetHost( fakeclient );
|
||||
fakeclient->PlayerRunCommand( &cmd, MoveHelperServer() );
|
||||
|
||||
// save off the last good usercmd
|
||||
fakeclient->SetLastUserCommand( cmd );
|
||||
|
||||
// Clear out any fixangle that has been set
|
||||
fakeclient->pl.fixangle = FIXANGLE_NONE;
|
||||
|
||||
// Restore the globals..
|
||||
gpGlobals->frametime = flOldFrametime;
|
||||
gpGlobals->curtime = flOldCurtime;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Run this Bot's AI for one frame.
|
||||
//-----------------------------------------------------------------------------
|
||||
void Bot_Think( CBaseTFPlayer *pBot )
|
||||
{
|
||||
// Hack to make Bots use Menus
|
||||
if ( pBot->m_pCurrentMenu == gMenus[MENU_CLASS] )
|
||||
{
|
||||
int iClass = g_iNextBotClass;
|
||||
if ( iClass == -1 )
|
||||
iClass = random->RandomInt( 1, TFCLASS_CLASS_COUNT );
|
||||
|
||||
pBot->m_pCurrentMenu->Input( pBot, iClass );
|
||||
}
|
||||
else if ( bot_changeclass.GetInt() && bot_changeclass.GetInt() != pBot->PlayerClass() )
|
||||
{
|
||||
pBot->m_pCurrentMenu = gMenus[MENU_CLASS];
|
||||
pBot->m_pCurrentMenu->Input( pBot, bot_changeclass.GetInt() );
|
||||
}
|
||||
|
||||
// Make sure we stay being a bot
|
||||
pBot->AddFlag( FL_FAKECLIENT );
|
||||
|
||||
botdata_t *botdata = &g_BotData[ ENTINDEX( pBot->edict() ) - 1 ];
|
||||
|
||||
QAngle vecViewAngles;
|
||||
float forwardmove = 0.0;
|
||||
float sidemove = botdata->sidemove;
|
||||
float upmove = 0.0;
|
||||
unsigned short buttons = 0;
|
||||
byte impulse = 0;
|
||||
float frametime = gpGlobals->frametime;
|
||||
|
||||
vecViewAngles = pBot->GetLocalAngles();
|
||||
|
||||
|
||||
// Create some random values
|
||||
if ( pBot->IsAlive() && (pBot->GetSolid() == SOLID_BBOX) )
|
||||
{
|
||||
trace_t trace;
|
||||
|
||||
// Stop when shot
|
||||
if ( !pBot->IsEFlagSet(EFL_BOT_FROZEN) )
|
||||
{
|
||||
if ( pBot->m_iHealth == 100 )
|
||||
{
|
||||
forwardmove = 600 * ( botdata->backwards ? -1 : 1 );
|
||||
if ( botdata->sidemove != 0.0f )
|
||||
{
|
||||
forwardmove *= random->RandomFloat( 0.1, 1.0f );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
forwardmove = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Only turn if I haven't been hurt
|
||||
if ( !pBot->IsEFlagSet(EFL_BOT_FROZEN) && pBot->m_iHealth == 100 )
|
||||
{
|
||||
Vector vecEnd;
|
||||
Vector forward;
|
||||
|
||||
QAngle angle;
|
||||
float angledelta = 15.0;
|
||||
|
||||
int maxtries = (int)360.0/angledelta;
|
||||
|
||||
if ( botdata->lastturntoright )
|
||||
{
|
||||
angledelta = -angledelta;
|
||||
}
|
||||
|
||||
angle = pBot->GetLocalAngles();
|
||||
|
||||
Vector vecSrc;
|
||||
while ( --maxtries >= 0 )
|
||||
{
|
||||
AngleVectors( angle, &forward );
|
||||
|
||||
vecSrc = pBot->GetLocalOrigin() + Vector( 0, 0, 36 );
|
||||
|
||||
vecEnd = vecSrc + forward * 10;
|
||||
|
||||
UTIL_TraceHull( vecSrc, vecEnd, VEC_HULL_MIN_SCALED( pBot ), VEC_HULL_MAX_SCALED( pBot ),
|
||||
MASK_PLAYERSOLID, pBot, COLLISION_GROUP_NONE, &trace );
|
||||
|
||||
if ( trace.fraction == 1.0 )
|
||||
{
|
||||
if ( gpGlobals->curtime < botdata->nextturntime )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
angle.y += angledelta;
|
||||
|
||||
if ( angle.y > 180 )
|
||||
angle.y -= 360;
|
||||
else if ( angle.y < -180 )
|
||||
angle.y += 360;
|
||||
|
||||
botdata->nextturntime = gpGlobals->curtime + 2.0;
|
||||
botdata->lastturntoright = random->RandomInt( 0, 1 ) == 0 ? true : false;
|
||||
|
||||
botdata->forwardAngle = angle;
|
||||
botdata->lastAngles = angle;
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ( gpGlobals->curtime >= botdata->nextstrafetime )
|
||||
{
|
||||
botdata->nextstrafetime = gpGlobals->curtime + 1.0f;
|
||||
|
||||
if ( random->RandomInt( 0, 5 ) == 0 )
|
||||
{
|
||||
botdata->sidemove = -600.0f + 1200.0f * random->RandomFloat( 0, 2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
botdata->sidemove = 0;
|
||||
}
|
||||
sidemove = botdata->sidemove;
|
||||
|
||||
if ( random->RandomInt( 0, 20 ) == 0 )
|
||||
{
|
||||
botdata->backwards = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
botdata->backwards = false;
|
||||
}
|
||||
}
|
||||
|
||||
pBot->SetLocalAngles( angle );
|
||||
vecViewAngles = angle;
|
||||
}
|
||||
|
||||
// Is my team being forced to defend?
|
||||
if ( bot_defend.GetInt() == pBot->GetTeamNumber() )
|
||||
{
|
||||
buttons |= IN_ATTACK2;
|
||||
}
|
||||
// If bots are being forced to fire a weapon, see if I have it
|
||||
else if ( bot_forcefireweapon.GetString() )
|
||||
{
|
||||
CBaseCombatWeapon *pWeapon = pBot->Weapon_OwnsThisType( bot_forcefireweapon.GetString() );
|
||||
if ( pWeapon )
|
||||
{
|
||||
// Switch to it if we don't have it out
|
||||
CBaseCombatWeapon *pActiveWeapon = pBot->GetActiveWeapon();
|
||||
// Is it a twohandedweapon? If so, get the left weapon
|
||||
CWeaponTwoHandedContainer *pContainer = dynamic_cast< CWeaponTwoHandedContainer * >( pActiveWeapon );
|
||||
if ( pContainer )
|
||||
{
|
||||
pActiveWeapon = pContainer->GetLeftWeapon();
|
||||
}
|
||||
|
||||
// Switch?
|
||||
if ( pActiveWeapon != pWeapon )
|
||||
{
|
||||
pBot->Weapon_Switch( pWeapon );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start firing
|
||||
// Some weapons require releases, so randomise firing
|
||||
if ( bot_forceattackon.GetBool() || (RandomFloat(0.0,1.0) > 0.5) )
|
||||
{
|
||||
buttons |= bot_forceattack2.GetBool() ? IN_ATTACK2 : IN_ATTACK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( bot_flipout.GetInt() )
|
||||
{
|
||||
if ( bot_forceattackon.GetBool() || (RandomFloat(0.0,1.0) > 0.5) )
|
||||
{
|
||||
buttons |= bot_forceattack2.GetBool() ? IN_ATTACK2 : IN_ATTACK;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wait for Reinforcement wave
|
||||
if ( !pBot->IsAlive() )
|
||||
{
|
||||
// Try hitting my buttons occasionally
|
||||
if ( random->RandomInt( 0, 100 ) > 80 )
|
||||
{
|
||||
// Respawn the bot
|
||||
if ( random->RandomInt( 0, 1 ) == 0 )
|
||||
{
|
||||
buttons |= IN_JUMP;
|
||||
}
|
||||
else
|
||||
{
|
||||
buttons = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( bot_flipout.GetInt() >= 2 )
|
||||
{
|
||||
|
||||
QAngle angOffset = RandomAngle( -1, 1 );
|
||||
|
||||
botdata->lastAngles += angOffset;
|
||||
|
||||
for ( int i = 0 ; i < 2; i++ )
|
||||
{
|
||||
if ( fabs( botdata->lastAngles[ i ] - botdata->forwardAngle[ i ] ) > 15.0f )
|
||||
{
|
||||
if ( botdata->lastAngles[ i ] > botdata->forwardAngle[ i ] )
|
||||
{
|
||||
botdata->lastAngles[ i ] = botdata->forwardAngle[ i ] + 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
botdata->lastAngles[ i ] = botdata->forwardAngle[ i ] - 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
botdata->lastAngles[ 2 ] = 0;
|
||||
|
||||
pBot->SetLocalAngles( botdata->lastAngles );
|
||||
}
|
||||
|
||||
RunPlayerMove( pBot, pBot->GetLocalAngles(), forwardmove, sidemove, upmove, buttons, impulse, frametime );
|
||||
}
|
||||
|
||||
|
||||
19
game/server/tf2/bot_base.h
Normal file
19
game/server/tf2/bot_base.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef BOT_BASE_H
|
||||
#define BOT_BASE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
// If iTeam or iClass is -1, then a team or class is randomly chosen.
|
||||
CBasePlayer *BotPutInServer( bool bFrozen, int iTeam, int iClass );
|
||||
|
||||
|
||||
#endif // BOT_BASE_H
|
||||
43
game/server/tf2/c_obj_armor_upgrade.cpp
Normal file
43
game/server/tf2/c_obj_armor_upgrade.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "c_obj_armor_upgrade.h"
|
||||
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_ArmorUpgrade, DT_ArmorUpgrade, CArmorUpgrade)
|
||||
END_RECV_TABLE()
|
||||
|
||||
|
||||
|
||||
C_ArmorUpgrade::C_ArmorUpgrade()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int C_ArmorUpgrade::DrawModel( int flags )
|
||||
{
|
||||
C_BaseEntity *pParent = GetMoveParent();
|
||||
if ( pParent )
|
||||
{
|
||||
C_BaseAnimating *pAnimating = dynamic_cast< C_BaseAnimating* >( pParent );
|
||||
if ( pAnimating )
|
||||
{
|
||||
SetModelPointer( pParent->GetModel() );
|
||||
SetSequence( pAnimating->GetSequence() );
|
||||
m_nSkin = pAnimating->m_nSkin;
|
||||
m_nBody = pAnimating->m_nBody;
|
||||
|
||||
SetLocalOrigin( Vector( 0, 0, 50 ) );
|
||||
SetLocalAngles( QAngle( 0, 0, 0 ) );
|
||||
InvalidateBoneCache();
|
||||
}
|
||||
}
|
||||
|
||||
return BaseClass::DrawModel( 0 );
|
||||
}
|
||||
|
||||
|
||||
32
game/server/tf2/c_obj_armor_upgrade.h
Normal file
32
game/server/tf2/c_obj_armor_upgrade.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_OBJ_ARMOR_UPGRADE_H
|
||||
#define C_OBJ_ARMOR_UPGRADE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "tf_obj_baseupgrade_shared.h"
|
||||
|
||||
|
||||
class C_ArmorUpgrade : public C_BaseObjectUpgrade
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_ArmorUpgrade, C_BaseObjectUpgrade );
|
||||
DECLARE_CLIENTCLASS();
|
||||
C_ArmorUpgrade();
|
||||
|
||||
virtual int DrawModel( int flags );
|
||||
|
||||
|
||||
private:
|
||||
C_ArmorUpgrade( const C_ArmorUpgrade & ) {}
|
||||
};
|
||||
|
||||
|
||||
#endif // C_OBJ_ARMOR_UPGRADE_H
|
||||
331
game/server/tf2/controlzone.cpp
Normal file
331
game/server/tf2/controlzone.cpp
Normal file
@@ -0,0 +1,331 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Complete definition of the ControlZone behavioral entity
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "tf_shareddefs.h"
|
||||
#include "cbase.h"
|
||||
#include "EntityOutput.h"
|
||||
#include "tf_player.h"
|
||||
#include "controlzone.h"
|
||||
#include "team.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Since the control zone is a data only class, force it to always be sent ( shouldn't change often so )
|
||||
// bandwidth usage should be small.
|
||||
// Input : **ppSendTable -
|
||||
// *recipient -
|
||||
// *pvs -
|
||||
// clientArea -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
int CControlZone::UpdateTransmitState()
|
||||
{
|
||||
if ( IsEffectActive( EF_NODRAW ) )
|
||||
{
|
||||
return SetTransmitState( FL_EDICT_DONTSEND );
|
||||
}
|
||||
else
|
||||
{
|
||||
return SetTransmitState( FL_EDICT_ALWAYS );
|
||||
}
|
||||
}
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST(CControlZone, DT_ControlZone)
|
||||
SendPropInt( SENDINFO(m_nZoneNumber), 8, SPROP_UNSIGNED ),
|
||||
END_SEND_TABLE()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( trigger_controlzone, CControlZone);
|
||||
|
||||
BEGIN_DATADESC( CControlZone )
|
||||
|
||||
// outputs
|
||||
DEFINE_OUTPUT( m_ControllingTeam, "ControllingTeam" ),
|
||||
|
||||
// inputs
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "SetTeam", InputSetTeam ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "LockTeam", InputLockControllingTeam ),
|
||||
|
||||
// keys
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_iLockAfterChange, FIELD_INTEGER, "LockAfterChange" ),
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_flTimeTillCaptured, FIELD_FLOAT, "UncontestedTime" ),
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_flTimeTillContested, FIELD_FLOAT, "ContestedTime" ),
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_nZoneNumber, FIELD_INTEGER, "ZoneNumber" ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
|
||||
|
||||
// Control Zone Ent Flags
|
||||
#define CZF_DONT_USE_TOUCHES 1
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Initializes the control zone
|
||||
// Records who was the original controlling team (for control locking)
|
||||
//-----------------------------------------------------------------------------
|
||||
void CControlZone::Spawn( void )
|
||||
{
|
||||
// set the starting controlling team
|
||||
m_ControllingTeam.Set( GetTeamNumber(), this, this );
|
||||
|
||||
// remember who the original controlling team was (for control locking)
|
||||
m_iDefendingTeam = GetTeamNumber();
|
||||
|
||||
// Solid
|
||||
SetSolid( SOLID_BSP );
|
||||
AddSolidFlags( FSOLID_TRIGGER );
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
SetModel( STRING( GetModelName() ) ); // set size and link into world
|
||||
|
||||
// TF2 rules
|
||||
m_flTimeTillContested = 10.0; // Go to contested 10 seconds after enemies enter the zone
|
||||
m_flTimeTillCaptured = 5.0; // Go to captured state as soon as only one team holds the zone
|
||||
|
||||
if ( m_nZoneNumber == 0 )
|
||||
{
|
||||
Warning( "Warning, trigger_controlzone without Zone Number set\n" );
|
||||
}
|
||||
|
||||
m_ZonePlayerList.Purge();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Records that a player has entered the zone, and updates it's state
|
||||
// according, maybe starting to change team.
|
||||
// Input : *pOther - the entity that left the zone
|
||||
//-----------------------------------------------------------------------------
|
||||
void CControlZone::StartTouch( CBaseEntity *pOther )
|
||||
{
|
||||
CBaseTFPlayer *pl = ToBaseTFPlayer( pOther );
|
||||
if ( !pl )
|
||||
return;
|
||||
|
||||
CHandle< CBaseTFPlayer > hHandle;
|
||||
hHandle = pl;
|
||||
|
||||
m_ZonePlayerList.AddToTail( hHandle );
|
||||
|
||||
ReevaluateControllingTeam();
|
||||
|
||||
// Set this player's current zone to this zone
|
||||
pl->SetCurrentZone( this );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Records that a player has left the zone, and updates it's state
|
||||
// according, maybe starting to change team.
|
||||
// Input : *pOther - the entity that left the zone
|
||||
//-----------------------------------------------------------------------------
|
||||
void CControlZone::EndTouch( CBaseEntity *pOther )
|
||||
{
|
||||
CBaseTFPlayer *pl = ToBaseTFPlayer( pOther );
|
||||
if ( !pl )
|
||||
return;
|
||||
|
||||
CHandle< CBaseTFPlayer > hHandle;
|
||||
hHandle = pl;
|
||||
m_ZonePlayerList.FindAndRemove( hHandle );
|
||||
|
||||
ReevaluateControllingTeam();
|
||||
|
||||
// Unset this player's current zone if it's this one
|
||||
if ( pl->GetCurrentZone() == this )
|
||||
pl->SetCurrentZone( NULL );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Checks to see if it's time to change controllers
|
||||
//-----------------------------------------------------------------------------
|
||||
void CControlZone::ReevaluateControllingTeam( void )
|
||||
{
|
||||
// Count the number of players in each team
|
||||
int i;
|
||||
memset( m_iPlayersInZone, 0, sizeof( m_iPlayersInZone ) );
|
||||
for ( i = 0; i < m_ZonePlayerList.Size(); i++ )
|
||||
{
|
||||
if ( m_ZonePlayerList[i] != NULL && (m_ZonePlayerList[i]->GetTeamNumber() > 0) )
|
||||
{
|
||||
m_iPlayersInZone[ m_ZonePlayerList[i]->GetTeamNumber() ] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Abort immediately if we're not using touches to changes teams
|
||||
if ( HasSpawnFlags( CZF_DONT_USE_TOUCHES ) )
|
||||
return;
|
||||
|
||||
// if we're locked in place, no changes can occur to controlling team except through an explicit map ResetTeam
|
||||
if ( m_iLocked )
|
||||
return;
|
||||
|
||||
bool foundAnyTeam = false;
|
||||
int teamFound = 0;
|
||||
|
||||
// check to see if any teams have no players
|
||||
for ( i = 0; i < GetNumberOfTeams(); i++ )
|
||||
{
|
||||
if ( m_iPlayersInZone[i] )
|
||||
{
|
||||
if ( foundAnyTeam )
|
||||
{
|
||||
// we've already found a team, so it's being contested;
|
||||
teamFound = ZONE_CONTESTED;
|
||||
break;
|
||||
}
|
||||
|
||||
foundAnyTeam = true;
|
||||
teamFound = i;
|
||||
}
|
||||
}
|
||||
|
||||
// no one in the area!
|
||||
if ( teamFound == 0 )
|
||||
{
|
||||
// just leave it as it is, let it continue to change team
|
||||
// exception: if the zone state is contested, and there aren't any players in the zone,
|
||||
// just return to the team who used to own the zone.
|
||||
if ( GetTeamNumber() == ZONE_CONTESTED )
|
||||
{
|
||||
ChangeTeam(m_iDefendingTeam);
|
||||
SetControllingTeam( this, m_iDefendingTeam );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// if it's the same controlling team, don't worry about it
|
||||
if ( teamFound == GetTeamNumber() )
|
||||
{
|
||||
// the right team is in control, don't even think of switching
|
||||
m_iTryingToChangeToTeam = 0;
|
||||
SetNextThink( TICK_NEVER_THINK );
|
||||
return;
|
||||
}
|
||||
|
||||
// Find out if the zone isn't owned by anyone at all (hasn't been touched since the map started, and it started un-owned)
|
||||
bool bHasBeenOwned = true;
|
||||
if ( m_iDefendingTeam == 0 && GetTeamNumber() == 0 )
|
||||
bHasBeenOwned = false;
|
||||
|
||||
// if it's not contested, always go to contested mode
|
||||
if ( GetTeamNumber() != ZONE_CONTESTED && teamFound != GetTeamNumber() )
|
||||
{
|
||||
// Unowned zones are captured immediately (no contesting stage)
|
||||
if ( bHasBeenOwned )
|
||||
teamFound = ZONE_CONTESTED;
|
||||
}
|
||||
|
||||
// if it's the team we're trying to change to, don't worry about it
|
||||
if ( teamFound == m_iTryingToChangeToTeam )
|
||||
return;
|
||||
|
||||
// set up the time to change to the new team soon
|
||||
m_iTryingToChangeToTeam = teamFound;
|
||||
|
||||
// changing from contested->uncontested and visa-versa have different delays
|
||||
if ( m_iTryingToChangeToTeam != ZONE_CONTESTED )
|
||||
{
|
||||
if ( !bHasBeenOwned )
|
||||
{
|
||||
DevMsg( 1, "trigger_controlzone: (%s) changing team to %d NOW\n", GetDebugName(), m_iTryingToChangeToTeam );
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
}
|
||||
else
|
||||
{
|
||||
DevMsg( 1, "trigger_controlzone: (%s) changing team to %d in %.2f seconds\n", GetDebugName(), m_iTryingToChangeToTeam, m_flTimeTillCaptured );
|
||||
SetNextThink( gpGlobals->curtime + m_flTimeTillCaptured );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DevMsg( 1, "trigger_controlzone: (%s) changing to contested in %f seconds\n", GetDebugName(), m_flTimeTillContested );
|
||||
SetNextThink( gpGlobals->curtime + m_flTimeTillContested );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Checks to see if an uncontested territory is ready to change state
|
||||
// to the new controlling team.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CControlZone::Think( void )
|
||||
{
|
||||
if ( m_iTryingToChangeToTeam != 0 )
|
||||
{
|
||||
// held zone long enough
|
||||
SetControllingTeam( this, m_iTryingToChangeToTeam );
|
||||
|
||||
// lock against further change if set
|
||||
if ( m_iLockAfterChange )
|
||||
{
|
||||
LockControllingTeam();
|
||||
}
|
||||
|
||||
// Re-evaluate controlling team if we were changing to Contested (enemy may have withdrawn)
|
||||
if ( GetTeamNumber() == ZONE_CONTESTED )
|
||||
{
|
||||
ReevaluateControllingTeam();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: set it so the team can no longer change, until a set controlling team action occurs
|
||||
//-----------------------------------------------------------------------------
|
||||
void CControlZone::InputLockControllingTeam( inputdata_t &inputdata )
|
||||
{
|
||||
LockControllingTeam();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Input handler that sets the controlling team to the activator's team.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CControlZone::InputSetTeam( inputdata_t &inputdata )
|
||||
{
|
||||
// Abort if it's already the defending team
|
||||
if ( inputdata.pActivator->GetTeamNumber() == GetTeamNumber() )
|
||||
return;
|
||||
|
||||
// set the new team
|
||||
ChangeTeam(inputdata.pActivator->GetTeamNumber());
|
||||
SetControllingTeam( inputdata.pActivator, GetTeamNumber() );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Changes the team controlling this zone
|
||||
// Input : newTeam - the new team to change to
|
||||
//-----------------------------------------------------------------------------
|
||||
void CControlZone::SetControllingTeam( CBaseEntity *pActivator, int newTeam )
|
||||
{
|
||||
DevMsg( 1, "trigger_controlzone: (%s) changing team to: %d\n", GetDebugName(), newTeam );
|
||||
|
||||
// remember this team as the defenders of the zone
|
||||
m_iDefendingTeam = GetTeamNumber();
|
||||
|
||||
// reset state, firing the output
|
||||
ChangeTeam(newTeam);
|
||||
m_ControllingTeam.Set( GetTeamNumber(), pActivator, this );
|
||||
m_iLocked = FALSE;
|
||||
m_iTryingToChangeToTeam = 0;
|
||||
SetNextThink( TICK_NEVER_THINK );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CControlZone::LockControllingTeam( void )
|
||||
{
|
||||
// never lock a zone in contested mode
|
||||
if ( GetTeamNumber() == ZONE_CONTESTED )
|
||||
return;
|
||||
|
||||
// zones never lock to the defenders
|
||||
if ( GetTeamNumber() == m_iDefendingTeam )
|
||||
return;
|
||||
|
||||
m_iLocked = TRUE;
|
||||
}
|
||||
|
||||
60
game/server/tf2/controlzone.h
Normal file
60
game/server/tf2/controlzone.h
Normal file
@@ -0,0 +1,60 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Control Zone entity
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef CONTROLZONE_H
|
||||
#define CONTROLZONE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Defines a team zone of control
|
||||
// Usually the parent of many trigger entities
|
||||
//-----------------------------------------------------------------------------
|
||||
class CControlZone : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CControlZone, CBaseEntity );
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
void Spawn( void );
|
||||
void StartTouch( CBaseEntity * );
|
||||
void EndTouch( CBaseEntity * );
|
||||
void Think( void );
|
||||
|
||||
virtual int UpdateTransmitState();
|
||||
|
||||
// input functions
|
||||
void InputLockControllingTeam( inputdata_t &inputdata );
|
||||
void InputSetTeam( inputdata_t &inputdata );
|
||||
|
||||
// internal methods
|
||||
void LockControllingTeam( void );
|
||||
void ReevaluateControllingTeam( void );
|
||||
void SetControllingTeam( CBaseEntity *pActivator, int newTeam );
|
||||
|
||||
// outputs
|
||||
int GetControllingTeam( void ) { return m_ControllingTeam.Get(); };
|
||||
COutputInt m_ControllingTeam; // outputs the team currently controlling this spot, whenever it changes - this is -1 when contended
|
||||
|
||||
public:
|
||||
// Data
|
||||
CNetworkVar( int, m_nZoneNumber );
|
||||
int m_iDefendingTeam; // the original defeind team
|
||||
int m_iLocked; // no more changes, until a reset it called
|
||||
int m_iLockAfterChange; // auto-lock after the control zone changes hands through combat
|
||||
float m_flTimeTillCaptured; // time that the control zone has to be uncontested for it to succesfully change teams
|
||||
float m_flTimeTillContested; // time that the control zone has to be contested for for it to change to Contested mode (no team)
|
||||
int m_iTryingToChangeToTeam; // the team is trying to change to
|
||||
|
||||
CUtlVector< CHandle<CBaseTFPlayer> > m_ZonePlayerList; // List of all players in the zone at the moment
|
||||
int m_iPlayersInZone[MAX_TF_TEAMS+1]; // count of players in the zone divided by team
|
||||
|
||||
DECLARE_DATADESC();
|
||||
};
|
||||
|
||||
#endif // CONTROLZONE_H
|
||||
123
game/server/tf2/demo_entities.cpp
Normal file
123
game/server/tf2/demo_entities.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "ai_basenpc.h"
|
||||
#include "animation.h"
|
||||
#include "vstdlib/random.h"
|
||||
#include "h_cycler.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
class CCycler_TF2Commando : public CCycler
|
||||
{
|
||||
DECLARE_CLASS( CCycler_TF2Commando, CCycler );
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void Think( void );
|
||||
|
||||
// Inputs
|
||||
void InputRaiseShield( inputdata_t &inputdata );
|
||||
void InputLowerShield( inputdata_t &inputdata );
|
||||
|
||||
private:
|
||||
CNetworkVar( bool, m_bShieldActive );
|
||||
CNetworkVar( float, m_flShieldRaiseTime );
|
||||
CNetworkVar( float, m_flShieldLowerTime );
|
||||
};
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST(CCycler_TF2Commando, DT_Cycler_TF2Commando)
|
||||
SendPropInt (SENDINFO(m_bShieldActive), 1, SPROP_UNSIGNED ),
|
||||
SendPropFloat(SENDINFO(m_flShieldRaiseTime), 0, SPROP_NOSCALE ),
|
||||
SendPropFloat(SENDINFO(m_flShieldLowerTime), 0, SPROP_NOSCALE ),
|
||||
END_SEND_TABLE();
|
||||
|
||||
LINK_ENTITY_TO_CLASS( cycler_tf2commando, CCycler_TF2Commando );
|
||||
LINK_ENTITY_TO_CLASS( cycler_aliencommando, CCycler_TF2Commando );
|
||||
|
||||
BEGIN_DATADESC( CCycler_TF2Commando )
|
||||
|
||||
// Inputs
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "RaiseShield", InputRaiseShield ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "LowerShield", InputLowerShield ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCycler_TF2Commando::Spawn( void )
|
||||
{
|
||||
if (GetTeamNumber() == 1)
|
||||
{
|
||||
GenericCyclerSpawn( "models/player/human_commando.mdl", Vector(-16, -16, 0), Vector(16, 16, 72) );
|
||||
}
|
||||
else
|
||||
{
|
||||
GenericCyclerSpawn( "models/player/alien_commando.mdl", Vector(-16, -16, 0), Vector(16, 16, 72) );
|
||||
}
|
||||
|
||||
m_bShieldActive = false;
|
||||
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCycler_TF2Commando::Think( void )
|
||||
{
|
||||
// Change sequence
|
||||
if ( IsSequenceFinished() )
|
||||
{
|
||||
// Raising our shield?
|
||||
if ( m_bShieldActive )
|
||||
{
|
||||
ResetSequence( LookupSequence( "ShieldUpIdle" ) );
|
||||
}
|
||||
else if ( GetSequence() == LookupSequence( "ShieldDown" ) )
|
||||
{
|
||||
ResetSequence( LookupSequence( "Idle" ) );
|
||||
}
|
||||
}
|
||||
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
|
||||
if (m_animate)
|
||||
{
|
||||
StudioFrameAdvance ( );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Input that raises the cycler's shield
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCycler_TF2Commando::InputRaiseShield( inputdata_t &inputdata )
|
||||
{
|
||||
if (m_animate)
|
||||
{
|
||||
m_bShieldActive = true;
|
||||
ResetSequence( LookupSequence( "ShieldUp" ) );
|
||||
m_flShieldRaiseTime = gpGlobals->curtime;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Input that lowers the cycler's shield
|
||||
//-----------------------------------------------------------------------------
|
||||
void CCycler_TF2Commando::InputLowerShield( inputdata_t &inputdata )
|
||||
{
|
||||
if (m_animate)
|
||||
{
|
||||
m_bShieldActive = false;
|
||||
ResetSequence( LookupSequence( "ShieldDown" ) );
|
||||
m_flShieldLowerTime = gpGlobals->curtime;
|
||||
}
|
||||
}
|
||||
|
||||
51
game/server/tf2/entity_burn_effect.cpp
Normal file
51
game/server/tf2/entity_burn_effect.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "entity_burn_effect.h"
|
||||
|
||||
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST_NOBASE( CEntityBurnEffect, DT_EntityBurnEffect )
|
||||
SendPropEHandle( SENDINFO( m_hBurningEntity ) )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
LINK_ENTITY_TO_CLASS( entity_burn_effect, CEntityBurnEffect );
|
||||
|
||||
|
||||
CEntityBurnEffect* CEntityBurnEffect::Create( CBaseEntity *pBurningEntity )
|
||||
{
|
||||
CEntityBurnEffect *pEffect = static_cast<CEntityBurnEffect*>(CreateEntityByName( "entity_burn_effect" ));
|
||||
if ( pEffect )
|
||||
{
|
||||
pEffect->m_hBurningEntity = pBurningEntity;
|
||||
return pEffect;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int CEntityBurnEffect::UpdateTransmitState()
|
||||
{
|
||||
return SetTransmitState( FL_EDICT_FULLCHECK );
|
||||
}
|
||||
|
||||
|
||||
int CEntityBurnEffect::ShouldTransmit( const CCheckTransmitInfo *pInfo )
|
||||
{
|
||||
CBaseEntity *pEnt = m_hBurningEntity;
|
||||
if ( pEnt )
|
||||
return pEnt->ShouldTransmit( pInfo );
|
||||
else
|
||||
return FL_EDICT_DONTSEND;
|
||||
}
|
||||
|
||||
|
||||
|
||||
41
game/server/tf2/entity_burn_effect.h
Normal file
41
game/server/tf2/entity_burn_effect.h
Normal file
@@ -0,0 +1,41 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ENTITY_BURN_EFFECT_H
|
||||
#define ENTITY_BURN_EFFECT_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "baseentity.h"
|
||||
#include "server_class.h"
|
||||
|
||||
|
||||
class CEntityBurnEffect : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
|
||||
DECLARE_CLASS( CEntityBurnEffect, CBaseEntity );
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
static CEntityBurnEffect* Create( CBaseEntity *pBurningEntity );
|
||||
|
||||
|
||||
// Overrides.
|
||||
public:
|
||||
|
||||
virtual int UpdateTransmitState();
|
||||
virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo );
|
||||
|
||||
|
||||
private:
|
||||
CNetworkHandle( CBaseEntity, m_hBurningEntity );
|
||||
};
|
||||
|
||||
|
||||
#endif // ENTITY_BURN_EFFECT_H
|
||||
201
game/server/tf2/env_fallingrocks.cpp
Normal file
201
game/server/tf2/env_fallingrocks.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
|
||||
#define MAX_ROCK_MODELS 6
|
||||
|
||||
// Rock models
|
||||
char *sRockModels[ MAX_ROCK_MODELS ] =
|
||||
{
|
||||
"models/props/cliffside/inhibitor_rocks/inhibitor_rock12.mdl",
|
||||
"models/props/cliffside/inhibitor_rocks/inhibitor_rock13.mdl",
|
||||
"models/props/cliffside/inhibitor_rocks/inhibitor_rock14.mdl",
|
||||
"models/props/cliffside/inhibitor_rocks/inhibitor_rock19.mdl",
|
||||
"models/props/cliffside/inhibitor_rocks/inhibitor_rock20.mdl",
|
||||
"models/props/cliffside/inhibitor_rocks/inhibitor_rock21.mdl",
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A falling rock entity
|
||||
//-----------------------------------------------------------------------------
|
||||
class CFallingRock : public CBaseAnimating
|
||||
{
|
||||
DECLARE_CLASS( CFallingRock, CBaseAnimating );
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
|
||||
CFallingRock( void );
|
||||
virtual void Spawn( void );
|
||||
virtual void VPhysicsUpdate( IPhysicsObject *pPhysics );
|
||||
static CFallingRock *Create( const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecVelocity, const AngularImpulse &vecRotationSpeed );
|
||||
|
||||
void RockTouch( CBaseEntity *pOther );
|
||||
public:
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CFallingRock )
|
||||
|
||||
// functions
|
||||
DEFINE_FUNCTION( RockTouch ),
|
||||
|
||||
END_DATADESC()
|
||||
LINK_ENTITY_TO_CLASS( fallingrock, CFallingRock );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CFallingRock::CFallingRock( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFallingRock::Spawn( void )
|
||||
{
|
||||
SetModel( sRockModels[ random->RandomInt(0,MAX_ROCK_MODELS-1) ] );
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
m_takedamage = DAMAGE_NO;
|
||||
|
||||
// Create the object in the physics system
|
||||
VPhysicsInitNormal( SOLID_BBOX, 0, false );
|
||||
UTIL_SetSize( this, Vector(-4,-4,-4), Vector(4,4,4) );
|
||||
|
||||
SetTouch( RockTouch );
|
||||
SetThink( SUB_Remove );
|
||||
SetNextThink( gpGlobals->curtime + random->RandomFloat( 20.0, 30.0 ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFallingRock::VPhysicsUpdate( IPhysicsObject *pPhysics )
|
||||
{
|
||||
BaseClass::VPhysicsUpdate( pPhysics );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Create a falling rock
|
||||
//-----------------------------------------------------------------------------
|
||||
CFallingRock *CFallingRock::Create( const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecVelocity, const AngularImpulse &vecRotationSpeed )
|
||||
{
|
||||
CFallingRock *pRock = (CFallingRock*)CreateEntityByName("fallingrock");
|
||||
|
||||
UTIL_SetOrigin( pRock, vecOrigin );
|
||||
pRock->SetLocalAngles( vecAngles );
|
||||
pRock->Spawn();
|
||||
|
||||
IPhysicsObject *pPhysicsObject = pRock->VPhysicsGetObject();
|
||||
if ( pPhysicsObject )
|
||||
{
|
||||
pPhysicsObject->AddVelocity( &vecVelocity, &vecRotationSpeed );
|
||||
}
|
||||
|
||||
return pRock;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFallingRock::RockTouch( CBaseEntity *pOther )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A falling rock spawner entity
|
||||
//-----------------------------------------------------------------------------
|
||||
class CEnv_FallingRocks : public CPointEntity
|
||||
{
|
||||
DECLARE_CLASS( CEnv_FallingRocks, CPointEntity );
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void Precache( void );
|
||||
void RockThink( void );
|
||||
void InputSpawnRock( inputdata_t &inputdata );
|
||||
|
||||
public:
|
||||
float m_flFallStrength;
|
||||
float m_flRotationSpeed;
|
||||
float m_flMinSpawnTime;
|
||||
float m_flMaxSpawnTime;
|
||||
COutputEvent m_pOutputRockSpawned;
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CEnv_FallingRocks )
|
||||
|
||||
// Fields
|
||||
DEFINE_KEYFIELD( m_flFallStrength, FIELD_FLOAT, "FallSpeed"),
|
||||
DEFINE_KEYFIELD( m_flRotationSpeed, FIELD_FLOAT, "RotationSpeed"),
|
||||
DEFINE_KEYFIELD( m_flMinSpawnTime, FIELD_FLOAT, "MinSpawnTime"),
|
||||
DEFINE_KEYFIELD( m_flMaxSpawnTime, FIELD_FLOAT, "MaxSpawnTime"),
|
||||
|
||||
// Inputs
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "SpawnRock", InputSpawnRock ),
|
||||
|
||||
// Outputs
|
||||
DEFINE_OUTPUT( m_pOutputRockSpawned, "OnRockSpawned" ),
|
||||
|
||||
// Functions
|
||||
DEFINE_FUNCTION( RockThink ),
|
||||
|
||||
END_DATADESC()
|
||||
LINK_ENTITY_TO_CLASS( env_fallingrocks, CEnv_FallingRocks );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEnv_FallingRocks::Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
SetThink( RockThink );
|
||||
SetNextThink( gpGlobals->curtime + random->RandomFloat( m_flMinSpawnTime, m_flMaxSpawnTime ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEnv_FallingRocks::Precache( void )
|
||||
{
|
||||
for (int i = 0; i < MAX_ROCK_MODELS; i++ )
|
||||
{
|
||||
PrecacheModel( sRockModels[i] );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEnv_FallingRocks::RockThink( void )
|
||||
{
|
||||
// Spawn a rock
|
||||
// Make it aim a little around the angle supplied
|
||||
QAngle angFire = GetAbsAngles();
|
||||
angFire.y += random->RandomFloat( -10, 10 );
|
||||
Vector vecForward;
|
||||
AngleVectors( angFire, &vecForward );
|
||||
CFallingRock::Create( GetAbsOrigin(), GetAbsAngles(), (vecForward * m_flFallStrength), AngularImpulse(0,0,m_flRotationSpeed) );
|
||||
|
||||
// Fire our output
|
||||
m_pOutputRockSpawned.FireOutput( NULL,this );
|
||||
|
||||
SetNextThink( gpGlobals->curtime + random->RandomFloat( m_flMinSpawnTime, m_flMaxSpawnTime ) );
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//------------------------------------------------------------------------------
|
||||
void CEnv_FallingRocks::InputSpawnRock( inputdata_t &inputdata )
|
||||
{
|
||||
RockThink();
|
||||
}
|
||||
618
game/server/tf2/env_meteor.cpp
Normal file
618
game/server/tf2/env_meteor.cpp
Normal file
@@ -0,0 +1,618 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "tf_player.h"
|
||||
#include "Env_Meteor.h"
|
||||
#include "entitylist.h"
|
||||
#include "vphysics_interface.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "mapdata_shared.h"
|
||||
#include "sharedinterface.h"
|
||||
#include "skycamera.h"
|
||||
#include "ispatialpartition.h"
|
||||
#include "gameinterface.h"
|
||||
#include "props.h"
|
||||
#include "tf_func_resource.h"
|
||||
#include "resource_chunk.h"
|
||||
|
||||
|
||||
#include "ndebugoverlay.h"
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Enumerator for swept bbox collision.
|
||||
//
|
||||
class CCollideList : public IEntityEnumerator
|
||||
{
|
||||
public:
|
||||
CCollideList( Ray_t *pRay, CBaseEntity* pIgnoreEntity, int nContentsMask ) :
|
||||
m_Entities( 0, 32 ), m_pIgnoreEntity( pIgnoreEntity ),
|
||||
m_nContentsMask( nContentsMask ), m_pRay(pRay) {}
|
||||
|
||||
virtual bool EnumEntity( IHandleEntity *pHandleEntity )
|
||||
{
|
||||
trace_t tr;
|
||||
enginetrace->ClipRayToEntity( *m_pRay, m_nContentsMask, pHandleEntity, &tr );
|
||||
if (( tr.fraction < 1.0f ) || (tr.startsolid) || (tr.allsolid))
|
||||
{
|
||||
CBaseEntity *pEntity = gEntList.GetBaseEntity( pHandleEntity->GetRefEHandle() );
|
||||
m_Entities.AddToTail( pEntity );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CUtlVector<CBaseEntity*> m_Entities;
|
||||
|
||||
private:
|
||||
CBaseEntity *m_pIgnoreEntity;
|
||||
int m_nContentsMask;
|
||||
Ray_t *m_pRay;
|
||||
};
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Meteor Factory Functions
|
||||
//
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMeteorFactory::CreateMeteor( int nID, int iType,
|
||||
const Vector &vecPosition, const Vector &vecDirection,
|
||||
float flSpeed, float flStartTime, float flDamageRadius,
|
||||
const Vector &vecTriggerMins, const Vector &vecTriggerMaxs )
|
||||
{
|
||||
CEnvMeteor::Create( nID, iType, vecPosition, vecDirection, flSpeed, flStartTime, flDamageRadius,
|
||||
vecTriggerMins, vecTriggerMaxs );
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Meteor Spawner Functions
|
||||
//
|
||||
|
||||
void SendProxy_MeteorTargetPositions( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
|
||||
{
|
||||
CEnvMeteorSpawnerShared *pMeteorSpawner = ( CEnvMeteorSpawnerShared* )pData;
|
||||
pOut->m_Vector[0] = pMeteorSpawner->m_aTargets[iElement].m_vecPosition.x;
|
||||
pOut->m_Vector[1] = pMeteorSpawner->m_aTargets[iElement].m_vecPosition.y;
|
||||
pOut->m_Vector[2] = pMeteorSpawner->m_aTargets[iElement].m_vecPosition.z;
|
||||
}
|
||||
|
||||
void SendProxy_MeteorTargetRadii( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID )
|
||||
{
|
||||
CEnvMeteorSpawnerShared *pMeteorSpawner = ( CEnvMeteorSpawnerShared* )pData;
|
||||
pOut->m_Float = pMeteorSpawner->m_aTargets[iElement].m_flRadius;
|
||||
}
|
||||
|
||||
int SendProxyArrayLength_MeteorTargets( const void *pStruct, int objectID )
|
||||
{
|
||||
CEnvMeteorSpawnerShared *pMeteorSpawner = ( CEnvMeteorSpawnerShared* )pStruct;
|
||||
return pMeteorSpawner->m_aTargets.Count();
|
||||
}
|
||||
|
||||
// Link the name "env_meteorspawner" to the CMeteorSpawner class. This
|
||||
// links the WC entity with the game code.
|
||||
LINK_ENTITY_TO_CLASS( env_meteorspawner, CEnvMeteorSpawner );
|
||||
|
||||
BEGIN_DATADESC( CEnvMeteorSpawner )
|
||||
|
||||
// Key Fields.
|
||||
DEFINE_KEYFIELD( m_SpawnerShared.m_iMeteorType, FIELD_INTEGER, "MeteorType" ),
|
||||
DEFINE_KEYFIELD( m_SpawnerShared.m_bSkybox, FIELD_INTEGER, "SpawnInSkybox" ),
|
||||
DEFINE_KEYFIELD( m_SpawnerShared.m_flMinSpawnTime, FIELD_FLOAT, "SpawnIntervalMin" ),
|
||||
DEFINE_KEYFIELD( m_SpawnerShared.m_flMaxSpawnTime, FIELD_FLOAT, "SpawnIntervalMax" ),
|
||||
DEFINE_KEYFIELD( m_SpawnerShared.m_nMinSpawnCount, FIELD_INTEGER, "SpawnCountMin" ),
|
||||
DEFINE_KEYFIELD( m_SpawnerShared.m_nMaxSpawnCount, FIELD_INTEGER, "SpawnCountMax" ),
|
||||
DEFINE_KEYFIELD( m_SpawnerShared.m_flMinSpeed, FIELD_FLOAT, "MeteorSpeedMin" ),
|
||||
DEFINE_KEYFIELD( m_SpawnerShared.m_flMaxSpeed, FIELD_FLOAT, "MeteorSpeedMax" ),
|
||||
DEFINE_KEYFIELD( m_SpawnerShared.m_flMeteorDamageRadius, FIELD_FLOAT, "MeteorDamageRadius" ),
|
||||
DEFINE_KEYFIELD( m_fDisabled, FIELD_BOOLEAN, "StartDisabled" ),
|
||||
|
||||
// Function Pointers.
|
||||
DEFINE_FUNCTION( MeteorSpawnerThink ),
|
||||
|
||||
// Inputs
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
BEGIN_SEND_TABLE_NOBASE( CEnvMeteorSpawnerShared, DT_EnvMeteorSpawnerShared )
|
||||
// Setup (read from) Worldcraft.
|
||||
SendPropInt ( SENDINFO( m_iMeteorType ), 8, SPROP_UNSIGNED ),
|
||||
SendPropInt ( SENDINFO( m_bSkybox ), 4, SPROP_UNSIGNED ),
|
||||
SendPropFloat ( SENDINFO( m_flMinSpawnTime ), 0, SPROP_NOSCALE ),
|
||||
SendPropFloat ( SENDINFO( m_flMaxSpawnTime ), 0, SPROP_NOSCALE ),
|
||||
SendPropInt ( SENDINFO( m_nMinSpawnCount ), 16, SPROP_UNSIGNED ),
|
||||
SendPropInt ( SENDINFO( m_nMaxSpawnCount ), 16, SPROP_UNSIGNED ),
|
||||
SendPropFloat ( SENDINFO( m_flMinSpeed ), 0, SPROP_NOSCALE ),
|
||||
SendPropFloat ( SENDINFO( m_flMaxSpeed ), 0, SPROP_NOSCALE ),
|
||||
|
||||
// Setup through Init.
|
||||
SendPropFloat ( SENDINFO( m_flStartTime ), -1, SPROP_NOSCALE ),
|
||||
SendPropInt ( SENDINFO( m_nRandomSeed ), -1, SPROP_UNSIGNED ),
|
||||
SendPropVector ( SENDINFO( m_vecMinBounds ), -1, SPROP_NOSCALE ),
|
||||
SendPropVector ( SENDINFO( m_vecMaxBounds ), -1, SPROP_NOSCALE ),
|
||||
SendPropVector ( SENDINFO( m_vecTriggerMins ), -1, SPROP_NOSCALE ),
|
||||
SendPropVector ( SENDINFO( m_vecTriggerMaxs ), -1, SPROP_NOSCALE ),
|
||||
|
||||
// Target List
|
||||
SendPropArray2( SendProxyArrayLength_MeteorTargets,
|
||||
SendPropVector( "meteortargetposition_array_element", 0, 0, 0, SPROP_NOSCALE, 0, 0, SendProxy_MeteorTargetPositions ),
|
||||
16, 0, "meteortargetposition_array" ),
|
||||
|
||||
SendPropArray2( SendProxyArrayLength_MeteorTargets,
|
||||
SendPropFloat( "meteortargetradius_array_element", 0, 0, 0, SPROP_NOSCALE, 0, 0, SendProxy_MeteorTargetRadii ),
|
||||
16, 0, "meteortargetradius_array" )
|
||||
END_SEND_TABLE()
|
||||
|
||||
// This table encodes the CBaseEntity data.
|
||||
IMPLEMENT_SERVERCLASS_ST_NOBASE( CEnvMeteorSpawner, DT_EnvMeteorSpawner )
|
||||
SendPropDataTable ( SENDINFO_DT( m_SpawnerShared ), &REFERENCE_SEND_TABLE( DT_EnvMeteorSpawnerShared ) ),
|
||||
SendPropInt ( SENDINFO( m_fDisabled ), 1, SPROP_UNSIGNED ),
|
||||
END_SEND_TABLE()
|
||||
|
||||
// Meteor Models
|
||||
char *strResourceMeteorModels[2] =
|
||||
{
|
||||
"models/props/common/meteorites/meteor04.mdl",
|
||||
"models/props/common/meteorites/meteor05.mdl",
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
CEnvMeteorSpawner::CEnvMeteorSpawner()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEnvMeteorSpawner::Spawn( void )
|
||||
{
|
||||
// Pre-cache.
|
||||
Precache();
|
||||
|
||||
// Server-side is not visible -- for collision only.
|
||||
SetSolid( SOLID_NONE );
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
AddEffects( EF_NODRAW );
|
||||
|
||||
// Set the "brush model" size and link into the world.
|
||||
SetModel( STRING( GetModelName() ) );
|
||||
|
||||
// Set the think function and time.
|
||||
if ( !m_fDisabled )
|
||||
{
|
||||
SetThink( MeteorSpawnerThink );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEnvMeteorSpawner::InputEnable( inputdata_t &inputdata )
|
||||
{
|
||||
m_fDisabled = false;
|
||||
|
||||
m_SpawnerShared.m_flStartTime = gpGlobals->curtime;
|
||||
m_SpawnerShared.m_flNextSpawnTime = m_SpawnerShared.m_flStartTime + m_SpawnerShared.m_flMaxSpawnTime;
|
||||
|
||||
// Probably should set this as a message begin, etc..... will get to this later!!
|
||||
//
|
||||
// CEntityMessageFilter filter( this, "CEnvMeteorSpawner" );
|
||||
// MessageBegin( filter, 0 );
|
||||
// WRITE_LONG( m_SpawnerShared.m_flStartTime );
|
||||
// WRITE_LONG( m_SpawnerShared.m_flNextSpawnTime );
|
||||
// MessageEnd();
|
||||
|
||||
// Set the think function and time.
|
||||
SetThink( MeteorSpawnerThink );
|
||||
SetNextThink( gpGlobals->curtime + m_SpawnerShared.m_flNextSpawnTime );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEnvMeteorSpawner::InputDisable( inputdata_t &inputdata )
|
||||
{
|
||||
m_fDisabled = true;
|
||||
SetThink( NULL );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEnvMeteorSpawner::Get3DSkyboxWorldBounds( Vector &vecTriggerMins,
|
||||
Vector &vecTriggerMaxs )
|
||||
{
|
||||
CBaseEntity *pEntity = gEntList.FindEntityByClassname( NULL, "trigger_skybox2world" );
|
||||
if ( pEntity && pEntity->edict() )
|
||||
{
|
||||
pEntity->CollisionProp()->WorldSpaceAABB( &vecTriggerMins, &vecTriggerMaxs );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEnvMeteorSpawner::Precache( void )
|
||||
{
|
||||
// Precache the meteor models!
|
||||
for ( int iType = 0; iType < 2; iType++ )
|
||||
{
|
||||
PrecacheModel( strResourceMeteorModels[iType] );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEnvMeteorSpawner::MeteorSpawnerThink( void )
|
||||
{
|
||||
SetNextThink( gpGlobals->curtime + m_SpawnerShared.MeteorThink( gpGlobals->curtime ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
int CEnvMeteorSpawner::ShouldTransmit( const CCheckTransmitInfo *pInfo )
|
||||
{
|
||||
if ( m_SpawnerShared.m_bSkybox )
|
||||
return FL_EDICT_ALWAYS;
|
||||
|
||||
return BaseClass::ShouldTransmit( pInfo );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEnvMeteorSpawner::Activate( void )
|
||||
{
|
||||
// Parse the entity list looking for targets!
|
||||
int nEntityCount = engine->GetEntityCount();
|
||||
for ( int iEntity = 0; iEntity < nEntityCount; ++iEntity )
|
||||
{
|
||||
edict_t *pEdict = engine->PEntityOfEntIndex( iEntity );
|
||||
if ( !pEdict || pEdict->IsFree() )
|
||||
continue;
|
||||
|
||||
CBaseEntity *pEntity = GetContainingEntity( pEdict );
|
||||
if ( !pEntity )
|
||||
continue;
|
||||
|
||||
if ( pEntity->GetFlags()& FL_STATICPROP )
|
||||
continue;
|
||||
|
||||
if ( !Q_strcmp( pEntity->GetClassname(), "env_meteortarget" ) )
|
||||
{
|
||||
CEnvMeteorTarget *pMeteorTarget = static_cast<CEnvMeteorTarget*>( pEntity );
|
||||
if ( pMeteorTarget && pMeteorTarget->m_target != NULL_STRING )
|
||||
{
|
||||
if ( !Q_strcmp( STRING( pMeteorTarget->m_target ), STRING( GetEntityName() ) ) )
|
||||
{
|
||||
m_SpawnerShared.AddToTargetList( pMeteorTarget->GetLocalOrigin(), pMeteorTarget->m_flRadius );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get 3d skybox world trigger bounds.
|
||||
Vector vecTriggerMins, vecTriggerMaxs;
|
||||
Get3DSkyboxWorldBounds( vecTriggerMins, vecTriggerMaxs );
|
||||
|
||||
// Initialize the spawner.
|
||||
float flTime = gpGlobals->curtime;
|
||||
m_SpawnerShared.Init( &m_Factory, 0/* seed */, flTime,
|
||||
WorldAlignMins(), WorldAlignMaxs(), vecTriggerMins, vecTriggerMaxs );
|
||||
|
||||
// Setup next think.
|
||||
if ( !m_fDisabled )
|
||||
{
|
||||
SetNextThink( gpGlobals->curtime + m_SpawnerShared.m_flNextSpawnTime );
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Meteor Target Functions
|
||||
//
|
||||
|
||||
LINK_ENTITY_TO_CLASS( env_meteortarget, CEnvMeteorTarget );
|
||||
|
||||
BEGIN_DATADESC( CEnvMeteorTarget )
|
||||
|
||||
// Key Fields.
|
||||
DEFINE_KEYFIELD( m_flRadius, FIELD_FLOAT, "EffectRadius" ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
CEnvMeteorTarget::CEnvMeteorTarget()
|
||||
{
|
||||
m_iTargetID = -1;
|
||||
m_flRadius = 1.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEnvMeteorTarget::Spawn( void )
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Meteor Functions
|
||||
//
|
||||
|
||||
//
|
||||
// NOTE: The server-side meteor code has not really been tested. I do not
|
||||
// trust that is works correctly and/or cleans itself up nicely!
|
||||
//
|
||||
|
||||
LINK_ENTITY_TO_CLASS( env_meteor, CEnvMeteor );
|
||||
|
||||
BEGIN_DATADESC( CEnvMeteor )
|
||||
|
||||
// Function Pointers.
|
||||
DEFINE_FUNCTION( MeteorSkyboxThink ),
|
||||
DEFINE_FUNCTION( MeteorWorldThink ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
CEnvMeteor::CEnvMeteor()
|
||||
{
|
||||
m_vecMin.Init( -10.0f, -10.0f, -10.0f );
|
||||
m_vecMax.Init( 10.0f, 10.0f, 10.0f );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
CEnvMeteor *CEnvMeteor::Create( int nID, int iMeteorType,
|
||||
const Vector &vecOrigin, const Vector &vecDirection,
|
||||
float flSpeed, float flStartTime, float flDamageRadius,
|
||||
const Vector &vecTriggerMins, const Vector &vecTriggerMaxs )
|
||||
{
|
||||
CEnvMeteor *pMeteor = ( CEnvMeteor* )CreateEntityByName( "env_meteor" );
|
||||
if ( pMeteor )
|
||||
{
|
||||
pMeteor->m_Meteor.Init( nID, flStartTime, METEOR_PASSIVE_TIME, vecOrigin, vecDirection, flSpeed,
|
||||
flDamageRadius, vecTriggerMins, vecTriggerMaxs );
|
||||
|
||||
// If the meteor will never enter the world, then don't bother with a server-side version.
|
||||
if ( pMeteor->m_Meteor.m_flWorldEnterTime == METEOR_INVALID_TIME )
|
||||
{
|
||||
UTIL_Remove( pMeteor );
|
||||
}
|
||||
|
||||
// Handle forward simulation.
|
||||
if ( ( pMeteor->m_Meteor.m_flStartTime + METEOR_MAX_LIFETIME ) < gpGlobals->curtime )
|
||||
{
|
||||
UTIL_Remove( pMeteor );
|
||||
}
|
||||
|
||||
pMeteor->Spawn();
|
||||
pMeteor->SetNextThink( gpGlobals->curtime + pMeteor->m_Meteor.m_flWorldEnterTime );
|
||||
}
|
||||
|
||||
return pMeteor;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEnvMeteor::Spawn( void )
|
||||
{
|
||||
// Pass data.
|
||||
BaseClass::Spawn();
|
||||
|
||||
int iModel = modelinfo->GetModelIndex( "models/props/common/meteorites/meteor04.mdl" );
|
||||
if ( iModel > 0 )
|
||||
{
|
||||
const model_t *pModel = modelinfo->GetModel( iModel );
|
||||
modelinfo->GetModelBounds( pModel, m_vecMin, m_vecMax );
|
||||
}
|
||||
|
||||
// Assumes we start life in a skybox!
|
||||
SetThink( MeteorSkyboxThink );
|
||||
|
||||
m_bPrevInSkybox = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This think function should be called at the time when the meteor
|
||||
// will be leaving the skybox and entering the world.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEnvMeteor::MeteorSkyboxThink( void )
|
||||
{
|
||||
SetThink( MeteorWorldThink );
|
||||
SetNextThink( gpGlobals->curtime + 0.2f );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: This think function simulates (moves/collides) the meteor while in
|
||||
// the world.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CEnvMeteor::MeteorWorldThink( void )
|
||||
{
|
||||
// Get the current time.
|
||||
float flTime = gpGlobals->curtime;
|
||||
|
||||
// Convert if need be!
|
||||
if ( m_bPrevInSkybox )
|
||||
{
|
||||
m_Meteor.ConvertFromSkyboxToWorld();
|
||||
UTIL_SetOrigin( this, m_Meteor.m_vecStartPosition );
|
||||
|
||||
m_bPrevInSkybox = false;
|
||||
}
|
||||
|
||||
// Update meteor position for swept collision test.
|
||||
Vector vecEndPosition;
|
||||
m_Meteor.GetPositionAtTime( flTime, vecEndPosition );
|
||||
|
||||
// Debugging!!
|
||||
// NDebugOverlay::Box( GetAbsOrigin(), m_vecMin * 0.5f, m_vecMax * 0.5f, 255, 255, 0, 0, 5 );
|
||||
// NDebugOverlay::Box( vecEndPosition, m_vecMin, m_vecMax, 255, 0, 0, 0, 5 );
|
||||
|
||||
Ray_t ray;
|
||||
ray.Init( GetAbsOrigin(), vecEndPosition, m_vecMin, m_vecMax );
|
||||
|
||||
CCollideList collideList( &ray, this, MASK_SOLID );
|
||||
enginetrace->EnumerateEntities( ray, false, &collideList );
|
||||
|
||||
// Now get each entity and react accordinly!
|
||||
for( int iEntity = collideList.m_Entities.Count(); --iEntity >= 0; )
|
||||
{
|
||||
CBaseEntity *pEntity = collideList.m_Entities[iEntity];
|
||||
|
||||
if ( pEntity )
|
||||
{
|
||||
Vector vecForceDir = m_Meteor.m_vecDirection;
|
||||
|
||||
// Check for a physics object and apply force!
|
||||
IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject();
|
||||
if ( pPhysObject )
|
||||
{
|
||||
// float flMass = pPhysObject->GetMass();
|
||||
|
||||
// Send it flying!!!
|
||||
vecForceDir *= 5000000000000.0f;
|
||||
pPhysObject->ApplyForceCenter( vecForceDir );
|
||||
}
|
||||
|
||||
if ( pEntity->m_takedamage )
|
||||
{
|
||||
CTakeDamageInfo info( this, this, 200.0f, DMG_CLUB );
|
||||
CalculateExplosiveDamageForce( &info, vecForceDir, pEntity->GetAbsOrigin() );
|
||||
pEntity->TakeDamage( info );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trace_t trace;
|
||||
UTIL_TraceHull( GetAbsOrigin(), vecEndPosition, m_vecMin, m_vecMax,
|
||||
MASK_NPCWORLDSTATIC, this, COLLISION_GROUP_NONE, &trace );
|
||||
if( ( trace.fraction < 1.0f ) && !( trace.surface.flags & SURF_SKY ) )
|
||||
{
|
||||
CBaseEntity *pEntity = trace.m_pEnt;
|
||||
if ( pEntity )
|
||||
{
|
||||
// Hit the world? The meteor is destroyed!
|
||||
if ( pEntity->GetSolid() == SOLID_BSP )
|
||||
{
|
||||
#if 0
|
||||
// Suppress resources for now!!
|
||||
|
||||
// Create a random number or resource chunks.
|
||||
int nChunkCount = random->RandomInt( 0, 4 );
|
||||
for( int iChunk = 0; iChunk < nChunkCount; ++iChunk )
|
||||
{
|
||||
// Generate a random velocity vector.
|
||||
Vector vVelocity = Vector( random->RandomFloat( -20,20 ), random->RandomFloat( -20,20 ), random->RandomFloat( 100,150 ) );
|
||||
CResourceChunk::Create( false, GetAbsOrigin(), vVelocity );
|
||||
}
|
||||
#endif
|
||||
|
||||
// Splash damage!
|
||||
Vector vecImpactPoint;
|
||||
vecImpactPoint = GetAbsOrigin() + ( ( vecEndPosition - GetAbsOrigin() ) * trace.fraction );
|
||||
|
||||
// Debugging!!
|
||||
// NDebugOverlay::Box( vecImpactPoint, m_vecMin, m_vecMax, 0, 255, 0, 0, 5 );
|
||||
|
||||
//Iterate on all entities in the vicinity.
|
||||
for ( CEntitySphereQuery sphere( vecImpactPoint, m_Meteor.GetDamageRadius() ); pEntity = sphere.GetCurrentEntity(); sphere.NextEntity() )
|
||||
{
|
||||
// Get distance to object and use it as a scale value.
|
||||
Vector vecSegment;
|
||||
vecSegment = pEntity->GetAbsOrigin() - vecImpactPoint;
|
||||
float flDistance = vecSegment.Length();
|
||||
|
||||
float flScale = flDistance / ( m_Meteor.GetDamageRadius() * 0.75f );
|
||||
if ( flScale > 1.0f )
|
||||
{
|
||||
flScale = 1.0f;
|
||||
}
|
||||
|
||||
Vector vecForceDir = m_Meteor.m_vecDirection;
|
||||
|
||||
// Check for a physics object and apply force!
|
||||
IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject();
|
||||
if ( pPhysObject )
|
||||
{
|
||||
// float flMass = pPhysObject->GetMass();
|
||||
|
||||
// Send it flying!!!
|
||||
vecForceDir *= 5000000000000.0f * flScale;
|
||||
pPhysObject->ApplyForceCenter( vecForceDir );
|
||||
}
|
||||
|
||||
if ( pEntity->m_takedamage )
|
||||
{
|
||||
CTakeDamageInfo info( this, this, 300.0f * flScale, DMG_CLUB );
|
||||
CalculateExplosiveDamageForce( &info, vecForceDir, pEntity->GetAbsOrigin() );
|
||||
pEntity->TakeDamage( info );
|
||||
}
|
||||
}
|
||||
|
||||
UTIL_Remove( this );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Always move full movement.
|
||||
UTIL_SetOrigin( this, vecEndPosition );
|
||||
SetNextThink( gpGlobals->curtime + 0.2f );
|
||||
|
||||
// Check for death.
|
||||
if ( flTime >= m_Meteor.m_flWorldExitTime )
|
||||
{
|
||||
UTIL_Remove( this );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Shooting Star Spawner Functionality.
|
||||
//
|
||||
|
||||
// Link the name "env_meteorspawner" to the CMeteorSpawner class. This
|
||||
// links the WC entity with the game code.
|
||||
LINK_ENTITY_TO_CLASS( env_shootingstarspawner, CShootingStarSpawner );
|
||||
|
||||
BEGIN_DATADESC( CShootingStarSpawner )
|
||||
|
||||
// keys
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_flSpawnInterval, FIELD_FLOAT, "SpawnInterval" ),
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_bSkybox, FIELD_INTEGER, "SpawnInSkybox" ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( CShootingStarSpawner, DT_ShootingStarSpawner )
|
||||
SendPropFloat( SENDINFO( m_flSpawnInterval ), -1, SPROP_NOSCALE ),
|
||||
END_SEND_TABLE()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CShootingStarSpawner::CShootingStarSpawner()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CShootingStarSpawner::ShouldTransmit( const CCheckTransmitInfo *pInfo )
|
||||
{
|
||||
// Always send shooting star spawners if they are in the skybox!
|
||||
if ( m_bSkybox )
|
||||
return FL_EDICT_ALWAYS ;
|
||||
|
||||
return BaseClass::ShouldTransmit( pInfo );
|
||||
}
|
||||
146
game/server/tf2/env_meteor.h
Normal file
146
game/server/tf2/env_meteor.h
Normal file
@@ -0,0 +1,146 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ENV_METEOR_H
|
||||
#define ENV_METEOR_H
|
||||
#pragma once
|
||||
|
||||
#include "BaseEntity.h"
|
||||
#include "BaseAnimating.h"
|
||||
#include "Env_Meteor_Shared.h"
|
||||
#include "utlvector.h"
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Server-side Meteor Factory Class
|
||||
//
|
||||
class CMeteorFactory : public IMeteorFactory
|
||||
{
|
||||
public:
|
||||
|
||||
void CreateMeteor( int nID, int iType, const Vector &vecPosition,
|
||||
const Vector &vecDirection, float flSpeed, float flStartTime,
|
||||
float flDamageRadius,
|
||||
const Vector &vecTriggerMins, const Vector &vecTriggerMaxs );
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Meteor Spawner Class
|
||||
//
|
||||
class CEnvMeteorSpawner : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
|
||||
DECLARE_CLASS( CEnvMeteorSpawner, CBaseEntity );
|
||||
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
CEnvMeteorSpawner();
|
||||
|
||||
void Spawn( void );
|
||||
void Precache( void );
|
||||
void MeteorSpawnerThink( void );
|
||||
int UpdateTransmitState() { return SetTransmitState( FL_EDICT_FULLCHECK ); }
|
||||
int ShouldTransmit( const CCheckTransmitInfo *pInfo );
|
||||
void Activate( void );
|
||||
|
||||
private:
|
||||
|
||||
// Inputs
|
||||
void InputEnable( inputdata_t &inputdata );
|
||||
void InputDisable( inputdata_t &inputdata );
|
||||
|
||||
void Get3DSkyboxWorldBounds( Vector &vecTriggerMins, Vector &vecTriggerMaxs );
|
||||
|
||||
CMeteorFactory m_Factory;
|
||||
CNetworkVarEmbedded( CEnvMeteorSpawnerShared, m_SpawnerShared );
|
||||
|
||||
CNetworkVar( bool, m_fDisabled ); // Spawner active (trigger). NOTE: uses an f to remain consistent
|
||||
// with entity input system
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Meteor Target Class
|
||||
//
|
||||
class CEnvMeteorTarget : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
|
||||
DECLARE_CLASS( CEnvMeteorTarget, CBaseEntity );
|
||||
DECLARE_DATADESC();
|
||||
|
||||
CEnvMeteorTarget();
|
||||
void Spawn( void );
|
||||
|
||||
int m_iTargetID;
|
||||
float m_flRadius;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Meteor Class
|
||||
//
|
||||
class CEnvMeteor : public CBaseAnimating
|
||||
{
|
||||
|
||||
DECLARE_CLASS( CEnvMeteor, CBaseAnimating );
|
||||
|
||||
public:
|
||||
|
||||
DECLARE_DATADESC();
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Initialization
|
||||
//-------------------------------------------------------------------------
|
||||
CEnvMeteor();
|
||||
static CEnvMeteor *Create( int nID, int iMeteorType, const Vector &vecOrigin,
|
||||
const Vector &vecDirection, float flSpeed, float flStartTime,
|
||||
float flDamageRadius,
|
||||
const Vector &vecTriggerMins, const Vector &vecTriggerMaxs );
|
||||
void Spawn( void );
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Think(s)
|
||||
//-------------------------------------------------------------------------
|
||||
void MeteorSkyboxThink( void );
|
||||
void MeteorWorldThink( void );
|
||||
|
||||
private:
|
||||
|
||||
CEnvMeteorShared m_Meteor;
|
||||
bool m_bPrevInSkybox;
|
||||
Vector m_vecMin, m_vecMax;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Shooting Star Spawner Class
|
||||
//
|
||||
class CShootingStarSpawner : public CBaseEntity
|
||||
{
|
||||
DECLARE_CLASS( CShootingStarSpawner, CBaseEntity );
|
||||
|
||||
public:
|
||||
|
||||
CShootingStarSpawner();
|
||||
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
virtual int UpdateTransmitState() { return SetTransmitState( FL_EDICT_FULLCHECK ); }
|
||||
virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo );
|
||||
|
||||
public:
|
||||
|
||||
CNetworkVar( float, m_flSpawnInterval ); // How often do I spawn shooting stars?
|
||||
bool m_bSkybox; // Is the spawner in the skybox?
|
||||
};
|
||||
|
||||
#endif // ENV_METEOR_H
|
||||
301
game/server/tf2/fire_damage_mgr.cpp
Normal file
301
game/server/tf2/fire_damage_mgr.cpp
Normal file
@@ -0,0 +1,301 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "fire_damage_mgr.h"
|
||||
#include "entity_burn_effect.h"
|
||||
#include "gasoline_blob.h"
|
||||
#include "tf_obj.h"
|
||||
#include "ai_basenpc.h"
|
||||
#include "tf_gamerules.h"
|
||||
|
||||
|
||||
#define FIRE_DAMAGE_APPLY_INTERVAL 0.5 // Apply the damage at this interval.
|
||||
#define FIRE_DECAY_END_VALUE 0.00001
|
||||
|
||||
|
||||
// No more damage from fire can be applied to a player per second.
|
||||
#define MAX_FIRE_DAMAGE_PER_SECOND 15
|
||||
|
||||
// The fire heat uses exponential decay. It goes from MAX_FIRE_DAMAGE_PER_SECOND to
|
||||
// FIRE_DECAY_END_VALUE in FIRE_DECAY_SECONDS.
|
||||
#define FIRE_DECAY_SECONDS 3
|
||||
|
||||
|
||||
ConVar fire_damageall( "fire_damageall", "0", 0, "Enable fire damaging team members." );
|
||||
|
||||
|
||||
bool CFireDamageMgr::Init()
|
||||
{
|
||||
m_flApplyDamageCountdown = FIRE_DAMAGE_APPLY_INTERVAL;
|
||||
|
||||
// Fire decays exponentially: B = A * e^(-kt)
|
||||
// So we set B=FIRE_DECAY_END_VALUE, A=flMaxDamagePerSecond, and t=flFireDecaySeconds, then solve for K.
|
||||
m_flMaxDamagePerSecond = MAX_FIRE_DAMAGE_PER_SECOND;
|
||||
m_flDecayConstant = -log( FIRE_DECAY_END_VALUE / m_flMaxDamagePerSecond ) / FIRE_DECAY_SECONDS;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void CFireDamageMgr::AddDamage( CBaseEntity *pTarget, CBaseEntity *pAttacker, float flDamageAccel, bool bMakeBurnEffect )
|
||||
{
|
||||
FOR_EACH_LL( m_DamageEnts, iDamageEnt )
|
||||
{
|
||||
CDamageEnt *pEnt = &m_DamageEnts[iDamageEnt];
|
||||
|
||||
if ( pEnt->m_hEnt != pTarget )
|
||||
continue;
|
||||
|
||||
for ( int i=0; i < pEnt->m_nAttackers; i++ )
|
||||
{
|
||||
if ( pEnt->m_Attackers[i].m_hAttacker == pAttacker )
|
||||
{
|
||||
pEnt->m_Attackers[i].m_flVelocity += flDamageAccel * gpGlobals->frametime;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( pEnt->m_nAttackers < CDamageEnt::MAX_ATTACKERS )
|
||||
{
|
||||
// Add a new attacker.
|
||||
pEnt->m_Attackers[pEnt->m_nAttackers].Init( pAttacker, flDamageAccel * gpGlobals->frametime );
|
||||
++pEnt->m_nAttackers;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No room for more attackers.
|
||||
Warning( "CFireDamageMgr: ran out of attackers\n" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Add a new CDamageEnt.
|
||||
int iNew = m_DamageEnts.AddToTail();
|
||||
CDamageEnt *pEnt = &m_DamageEnts[iNew];
|
||||
pEnt->m_hEnt = pTarget;
|
||||
pEnt->m_bWasAlive = pTarget->IsAlive();
|
||||
pEnt->m_nAttackers = 1;
|
||||
pEnt->m_Attackers[0].Init( pAttacker, flDamageAccel * gpGlobals->frametime );
|
||||
if ( bMakeBurnEffect )
|
||||
pEnt->m_pBurnEffect = CEntityBurnEffect::Create( pTarget );
|
||||
else
|
||||
pEnt->m_pBurnEffect = NULL;
|
||||
}
|
||||
|
||||
|
||||
void CFireDamageMgr::RemoveDamageEnt( int iEnt )
|
||||
{
|
||||
UTIL_Remove( m_DamageEnts[iEnt].m_pBurnEffect );
|
||||
m_DamageEnts.Remove( iEnt );
|
||||
}
|
||||
|
||||
|
||||
void CFireDamageMgr::FrameUpdatePostEntityThink()
|
||||
{
|
||||
VPROF( "CFireDamageMgr::FrameUpdatePostEntityThink" );
|
||||
float frametime = gpGlobals->frametime;
|
||||
|
||||
// Update the damage countdown.
|
||||
m_flApplyDamageCountdown -= gpGlobals->frametime;
|
||||
bool bApplyDamageThisFrame = false;
|
||||
if ( m_flApplyDamageCountdown <= 0 )
|
||||
{
|
||||
bApplyDamageThisFrame = true;
|
||||
m_flApplyDamageCountdown += FIRE_DAMAGE_APPLY_INTERVAL;
|
||||
}
|
||||
|
||||
|
||||
// (-kt)
|
||||
// Figure out how much all the damage decays this frame: e
|
||||
float flFrameDecay = pow( 2.718281828459045235360, -m_flDecayConstant * frametime );
|
||||
|
||||
|
||||
int iNext;
|
||||
for ( int iCur = m_DamageEnts.Head(); iCur != m_DamageEnts.InvalidIndex(); iCur = iNext )
|
||||
{
|
||||
iNext = m_DamageEnts.Next( iCur );
|
||||
CDamageEnt *pEnt = &m_DamageEnts[iCur];
|
||||
|
||||
|
||||
// If the entity was dead and is now alive, stop damage to them so their new body doesn't burn.
|
||||
if ( !pEnt->m_hEnt.Get() || ( !pEnt->m_bWasAlive && pEnt->m_hEnt->IsAlive() ) )
|
||||
{
|
||||
RemoveDamageEnt( iCur );
|
||||
pEnt = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
pEnt->m_bWasAlive = pEnt->m_hEnt->IsAlive();
|
||||
|
||||
// Sum up each attacker's velocity.
|
||||
float flTotalVelocity = 0;
|
||||
for ( int i=0; i < pEnt->m_nAttackers; i++ )
|
||||
flTotalVelocity += pEnt->m_Attackers[i].m_flVelocity;
|
||||
|
||||
|
||||
// Figure out each attacker's contribution.
|
||||
float flContributionPercent[CDamageEnt::MAX_ATTACKERS];
|
||||
for ( i=0; i < pEnt->m_nAttackers; i++ )
|
||||
flContributionPercent[i] = pEnt->m_Attackers[i].m_flVelocity / flTotalVelocity;
|
||||
|
||||
|
||||
// Decay each attacker's velocity.
|
||||
flTotalVelocity *= flFrameDecay;
|
||||
|
||||
// Uniformly scale each attacker's velocity down so the sum total doesn't exceed our maximum.
|
||||
float flPercentScale = 1;
|
||||
if ( flTotalVelocity > m_flMaxDamagePerSecond )
|
||||
flPercentScale = m_flMaxDamagePerSecond / flTotalVelocity;
|
||||
|
||||
for ( i=0; i < pEnt->m_nAttackers; i++ )
|
||||
{
|
||||
CDamageAttacker *pAttacker = &pEnt->m_Attackers[i];
|
||||
|
||||
pAttacker->m_flVelocity *= flFrameDecay * flPercentScale;
|
||||
|
||||
bool bEntsValid = (pEnt->m_Attackers[i].m_hAttacker.Get() != NULL);
|
||||
if ( !bEntsValid ||
|
||||
pEnt->m_Attackers[i].m_flVelocity <= 0.001 )
|
||||
{
|
||||
if ( bEntsValid )
|
||||
ApplyCollectedDamage( pEnt, i ); // Apply the last-remaining damage from this guy.
|
||||
|
||||
Q_memmove( &pEnt->m_Attackers[i], &pEnt->m_Attackers[i+1], sizeof( pEnt->m_Attackers[0] ) * (pEnt->m_nAttackers-i-1) );
|
||||
Q_memmove( &flContributionPercent[i], &flContributionPercent[i+1], sizeof( flContributionPercent[0] ) * (pEnt->m_nAttackers-i-1) );
|
||||
|
||||
--pEnt->m_nAttackers;
|
||||
if ( pEnt->m_nAttackers == 0 )
|
||||
{
|
||||
// This ent isn't being damaged anymore.
|
||||
RemoveDamageEnt( iCur );
|
||||
break;
|
||||
}
|
||||
|
||||
--i;
|
||||
}
|
||||
|
||||
// Update their current damage sum and maybe apply the damage.
|
||||
pAttacker->m_flDamageSum += pAttacker->m_flVelocity * frametime;
|
||||
if ( bApplyDamageThisFrame )
|
||||
{
|
||||
ApplyCollectedDamage( pEnt, i );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
float GetFireDamageScale( CBaseEntity *pEnt )
|
||||
{
|
||||
// Objects have a lot more health and we want them to take damage faster.
|
||||
if ( dynamic_cast< CBaseObject* >( pEnt ) )
|
||||
return 4;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void CFireDamageMgr::ApplyCollectedDamage( CFireDamageMgr::CDamageEnt *pEnt, int iAttacker )
|
||||
{
|
||||
CDamageAttacker *pAttacker = &pEnt->m_Attackers[iAttacker];
|
||||
|
||||
CTakeDamageInfo info( NULL, pAttacker->m_hAttacker, pAttacker->m_flDamageSum * GetFireDamageScale( pEnt->m_hEnt ), DMG_BURN );
|
||||
pEnt->m_hEnt->TakeDamage( info );
|
||||
|
||||
pAttacker->m_flDamageSum = 0;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------ //
|
||||
// Global functions.
|
||||
// ------------------------------------------------------------------------------------------------ //
|
||||
|
||||
bool IsBurnableEnt( CBaseEntity *pEntity, int iIgnoreTeam )
|
||||
{
|
||||
if ( pEntity->m_takedamage == DAMAGE_NO )
|
||||
return false;
|
||||
|
||||
CGasolineBlob *pBlob = dynamic_cast< CGasolineBlob* >( pEntity );
|
||||
if ( pBlob )
|
||||
{
|
||||
return !pBlob->IsLit();
|
||||
}
|
||||
|
||||
if ( pEntity->GetTeamNumber() == iIgnoreTeam && !fire_damageall.GetInt() )
|
||||
{
|
||||
// Don't damage anyone on the pyro's team (including the pyro himself).
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now only allow specific types of objects to be damaged.
|
||||
if ( dynamic_cast< CBasePlayer* >( pEntity ) ||
|
||||
dynamic_cast< CAI_BaseNPC* >( pEntity ) ||
|
||||
dynamic_cast< CBaseObject* >( pEntity ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int FindBurnableEntsInSphere(
|
||||
CBaseEntity **ents,
|
||||
float *dists,
|
||||
int nMaxEnts,
|
||||
const Vector &vecCenter,
|
||||
float flSearchRadius,
|
||||
CBaseEntity *pOwner )
|
||||
{
|
||||
Assert( nMaxEnts > 0 );
|
||||
int nOutEnts = 0;
|
||||
|
||||
CBaseEntity *pEntity;
|
||||
for ( CEntitySphereQuery sphere( vecCenter, flSearchRadius ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
|
||||
{
|
||||
if ( !IsBurnableEnt( pEntity, pOwner->GetTeamNumber() ) )
|
||||
continue;
|
||||
|
||||
// Make sure it's not blocked.
|
||||
trace_t tr;
|
||||
Vector vCenter = pEntity->WorldSpaceCenter();
|
||||
|
||||
UTIL_TraceLine ( vecCenter, vCenter, MASK_SHOT & (~CONTENTS_HITBOX), NULL, COLLISION_GROUP_NONE, &tr );
|
||||
if ( tr.fraction != 1.0 && tr.m_pEnt != pEntity )
|
||||
continue;
|
||||
|
||||
if ( TFGameRules()->IsTraceBlockedByWorldOrShield( vecCenter, vCenter, pOwner, DMG_BURN | DMG_PROBE, &tr ) )
|
||||
continue;
|
||||
|
||||
// Make sure it's in range.
|
||||
const Vector &mins = pEntity->WorldAlignMins();
|
||||
const Vector &maxs = pEntity->WorldAlignMaxs();
|
||||
float approxTargetRadius = ( Vector( maxs.x, maxs.y, 0 ) - Vector( mins.x, mins.y, 0 )).Length() * 0.5f;
|
||||
|
||||
float flDistFromCenter = ( vecCenter - tr.endpos ).Length() - approxTargetRadius;
|
||||
|
||||
ents[nOutEnts] = pEntity;
|
||||
dists[nOutEnts] = flDistFromCenter;
|
||||
nOutEnts++;
|
||||
if ( nOutEnts >= nMaxEnts )
|
||||
return nOutEnts;
|
||||
}
|
||||
|
||||
return nOutEnts;
|
||||
}
|
||||
|
||||
|
||||
CFireDamageMgr g_FireDamageMgr;
|
||||
|
||||
CFireDamageMgr* GetFireDamageMgr()
|
||||
{
|
||||
return &g_FireDamageMgr;
|
||||
}
|
||||
|
||||
121
game/server/tf2/fire_damage_mgr.h
Normal file
121
game/server/tf2/fire_damage_mgr.h
Normal file
@@ -0,0 +1,121 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef FIRE_DAMAGE_MGR_H
|
||||
#define FIRE_DAMAGE_MGR_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "igamesystem.h"
|
||||
#include "utllinkedlist.h"
|
||||
#include "ehandle.h"
|
||||
|
||||
|
||||
class CEntityBurnEffect;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------ //
|
||||
// CFireDamageMgr.
|
||||
//
|
||||
// This class manages fire damage being applied to entities. It uses velocity, acceleration,
|
||||
// and decay to model fire damage building up, and it puts a cap on the maximum amount of damage
|
||||
// an entity can take from fire during a given frame.
|
||||
// ------------------------------------------------------------------------------------------ //
|
||||
|
||||
class CFireDamageMgr : public CAutoGameSystem
|
||||
{
|
||||
// Overrides.
|
||||
public:
|
||||
|
||||
virtual bool Init();
|
||||
virtual void FrameUpdatePostEntityThink();
|
||||
|
||||
|
||||
public:
|
||||
// Apply fire damage to an entity. flDamageAccel is in units per second, so in the absence of
|
||||
// decay, it equals velocity increase per second.
|
||||
//
|
||||
// NOTE: the damage acceleration should always be greater than the decay per second, or no damage
|
||||
// will be applied since it will decay faster than
|
||||
void AddDamage( CBaseEntity *pTarget, CBaseEntity *pAttacker, float flDamageAccel, bool bMakeBurnEffect );
|
||||
|
||||
|
||||
private:
|
||||
class CDamageAttacker
|
||||
{
|
||||
public:
|
||||
void Init( CBaseEntity *pAttacker, float flVelocity )
|
||||
{
|
||||
m_hAttacker = pAttacker;
|
||||
m_flVelocity = flVelocity;
|
||||
m_flDamageSum = 0;
|
||||
}
|
||||
|
||||
EHANDLE m_hAttacker;
|
||||
float m_flVelocity; // Current damage velocity.
|
||||
|
||||
float m_flDamageSum; // Damage is summed up and applied a couple times per second instead of
|
||||
// each frame since fractional damage is rounded to 1.
|
||||
};
|
||||
|
||||
class CDamageEnt
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
MAX_ATTACKERS = 4
|
||||
};
|
||||
|
||||
bool m_bWasAlive;
|
||||
|
||||
EHANDLE m_hEnt;
|
||||
CHandle<CEntityBurnEffect> m_pBurnEffect;
|
||||
|
||||
// Each attacker gets credit for a portion of
|
||||
CDamageAttacker m_Attackers[MAX_ATTACKERS];
|
||||
int m_nAttackers;
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void ApplyCollectedDamage( CFireDamageMgr::CDamageEnt *pEnt, int iAttacker );
|
||||
void RemoveDamageEnt( int iEnt );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
CUtlLinkedList<CDamageEnt,int> m_DamageEnts;
|
||||
|
||||
float m_flMaxDamagePerSecond;
|
||||
float m_flDecayConstant;
|
||||
|
||||
// This counts down to zero so we only apply fire damage every so often.
|
||||
float m_flApplyDamageCountdown;
|
||||
};
|
||||
|
||||
|
||||
// Returns true if the entity is burnable by the specified team.
|
||||
bool IsBurnableEnt( CBaseEntity *pEntity, int iTeam );
|
||||
|
||||
|
||||
// This is used by the flamethrower and the burning gasoline blobs to find entities to burn.
|
||||
int FindBurnableEntsInSphere(
|
||||
CBaseEntity **ents,
|
||||
float *dists,
|
||||
int nMaxEnts,
|
||||
const Vector &vecCenter,
|
||||
float flSearchRadius,
|
||||
CBaseEntity *pOwner );
|
||||
|
||||
|
||||
CFireDamageMgr* GetFireDamageMgr();
|
||||
|
||||
|
||||
#endif // FIRE_DAMAGE_MGR_H
|
||||
279
game/server/tf2/gasoline_blob.cpp
Normal file
279
game/server/tf2/gasoline_blob.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "gasoline_blob.h"
|
||||
#include "gasoline_shared.h"
|
||||
#include "utllinkedlist.h"
|
||||
#include "fire_damage_mgr.h"
|
||||
#include "tf_gamerules.h"
|
||||
|
||||
|
||||
// Flamethrower blobs wait a bit before they cause damage so they don't hurt the guy
|
||||
// shooting them.
|
||||
#define BLOB_DAMAGE_WAIT_TIME 1.0
|
||||
|
||||
|
||||
// At what heat level does an unlit blob ignite?
|
||||
#define IGNITION_HEAT 0.1
|
||||
|
||||
|
||||
#define FIRE_DAMAGE_SEARCH_DISTANCE 200 // It searches within this sphere for entities to damage.
|
||||
#define FIRE_DAMAGE_DISTANCE 90 // This is how far fire can damage an entity from.
|
||||
|
||||
|
||||
ConVar fire_enable( "fire_enable", "1", 0, "Enable or disable fire." );
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------ //
|
||||
// CGasolineBlob implementation.
|
||||
// ------------------------------------------------------------------------------------------ //
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST_NOBASE( CGasolineBlob, DT_GasolineBlob )
|
||||
SendPropVector( SENDINFO(m_vecOrigin), -1, SPROP_COORD ),
|
||||
SendPropEHandle (SENDINFO_NAME(m_hMoveParent, moveparent)),
|
||||
SendPropFloat( SENDINFO(m_flLitStartTime), -1, SPROP_NOSCALE ),
|
||||
|
||||
SendPropFloat( SENDINFO(m_flCreateTime), -1, SPROP_NOSCALE ),
|
||||
SendPropFloat( SENDINFO(m_flMaxLifetime), -1, SPROP_NOSCALE ),
|
||||
|
||||
SendPropInt( SENDINFO(m_iTeamNum), TEAMNUM_NUM_BITS, 0 ),
|
||||
SendPropInt( SENDINFO( m_BlobFlags ), NUM_BLOB_FLAGS, SPROP_UNSIGNED ),
|
||||
SendPropVector( SENDINFO( m_vSurfaceNormal ), 0, SPROP_NORMAL ),
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
LINK_ENTITY_TO_CLASS( gasoline_blob, CGasolineBlob );
|
||||
|
||||
|
||||
CUtlLinkedList<CGasolineBlob*, int> g_GasolineBlobs;
|
||||
|
||||
|
||||
CGasolineBlob* CGasolineBlob::Create(
|
||||
CBaseEntity *pOwner,
|
||||
const Vector &vOrigin,
|
||||
const Vector &vStartVelocity,
|
||||
bool bUseGravity,
|
||||
float flAirLifetime,
|
||||
float flLifetime )
|
||||
{
|
||||
CGasolineBlob *pBlob = (CGasolineBlob*)CreateEntityByName( "gasoline_blob" );
|
||||
if ( !pBlob )
|
||||
return NULL;
|
||||
|
||||
// The "constructor".
|
||||
pBlob->SetLocalOrigin( vOrigin );
|
||||
pBlob->SetAbsVelocity( vStartVelocity );
|
||||
pBlob->SetThink( &CGasolineBlob::Think );
|
||||
pBlob->SetNextThink( gpGlobals->curtime );
|
||||
pBlob->SetCollisionBounds( Vector( -GASOLINE_BLOB_RADIUS, -GASOLINE_BLOB_RADIUS, -GASOLINE_BLOB_RADIUS ), Vector( GASOLINE_BLOB_RADIUS, GASOLINE_BLOB_RADIUS, GASOLINE_BLOB_RADIUS ) );
|
||||
pBlob->SetMoveType( MOVETYPE_NONE );
|
||||
pBlob->SetSolid( SOLID_BBOX );
|
||||
pBlob->AddSolidFlags( FSOLID_NOT_SOLID );
|
||||
pBlob->AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
|
||||
pBlob->m_BlobFlags = 0;
|
||||
pBlob->m_HeatLevel = 0;
|
||||
pBlob->m_hOwner = pOwner;
|
||||
pBlob->m_flCreateTime = gpGlobals->curtime;
|
||||
pBlob->m_flMaxLifetime = flLifetime;
|
||||
pBlob->m_takedamage = DAMAGE_YES;
|
||||
pBlob->m_flLitStartTime = 0;
|
||||
pBlob->ChangeTeam( pOwner->GetTeamNumber() );
|
||||
|
||||
if ( bUseGravity )
|
||||
pBlob->m_BlobFlags |= BLOBFLAG_USE_GRAVITY;
|
||||
|
||||
pBlob->m_flAirLifetime = flAirLifetime;
|
||||
pBlob->m_flTimeInAir = 0;
|
||||
|
||||
pBlob->SetNextThink( gpGlobals->curtime );
|
||||
g_GasolineBlobs.AddToTail( pBlob );
|
||||
|
||||
return pBlob;
|
||||
}
|
||||
|
||||
|
||||
CGasolineBlob::~CGasolineBlob()
|
||||
{
|
||||
g_GasolineBlobs.Remove( g_GasolineBlobs.Find( this ) );
|
||||
}
|
||||
|
||||
|
||||
void CGasolineBlob::AddAutoBurnBlob( CGasolineBlob *pBlob )
|
||||
{
|
||||
int index = m_AutoBurnBlobs.AddToTail();
|
||||
m_AutoBurnBlobs[index] = pBlob;
|
||||
}
|
||||
|
||||
|
||||
int CGasolineBlob::OnTakeDamage( const CTakeDamageInfo &info )
|
||||
{
|
||||
m_HeatLevel += info.GetDamage();
|
||||
if ( m_HeatLevel >= IGNITION_HEAT )
|
||||
SetLit( true );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void CGasolineBlob::SetLit( bool bLit )
|
||||
{
|
||||
if ( bLit != IsLit() )
|
||||
{
|
||||
if ( bLit )
|
||||
{
|
||||
m_BlobFlags |= BLOBFLAG_LIT;
|
||||
m_flLitStartTime = gpGlobals->curtime;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_BlobFlags &= ~BLOBFLAG_LIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CGasolineBlob::IsLit() const
|
||||
{
|
||||
return (m_BlobFlags & BLOBFLAG_LIT) != 0;
|
||||
}
|
||||
|
||||
|
||||
bool CGasolineBlob::IsStopped() const
|
||||
{
|
||||
return (m_BlobFlags & BLOBFLAG_STOPPED) != 0;
|
||||
}
|
||||
|
||||
|
||||
void CGasolineBlob::AutoBurn_R( CGasolineBlob *pParent )
|
||||
{
|
||||
SetLit( true );
|
||||
|
||||
for ( int i=0; i < m_AutoBurnBlobs.Count(); i++ )
|
||||
{
|
||||
CGasolineBlob *pTestBlob = m_AutoBurnBlobs[i];
|
||||
|
||||
if ( pTestBlob )
|
||||
{
|
||||
if ( pTestBlob != pParent )
|
||||
pTestBlob->AutoBurn_R( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_AutoBurnBlobs.Remove( i );
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CGasolineBlob::Think()
|
||||
{
|
||||
if ( !fire_enable.GetInt() )
|
||||
{
|
||||
UTIL_Remove( this );
|
||||
return;
|
||||
}
|
||||
|
||||
// Decay quickly while in the air.
|
||||
if ( !IsStopped() )
|
||||
{
|
||||
m_flTimeInAir += gpGlobals->frametime;
|
||||
if ( m_flTimeInAir >= m_flAirLifetime )
|
||||
{
|
||||
UTIL_Remove( this );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
float flLifetime = gpGlobals->curtime - m_flCreateTime;
|
||||
if ( flLifetime >= m_flMaxLifetime )
|
||||
{
|
||||
UTIL_Remove( this );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( IsLit() )
|
||||
{
|
||||
// Have we burnt out?
|
||||
float litPercent = 1 - (flLifetime / m_flMaxLifetime);
|
||||
if ( litPercent <= 0 )
|
||||
{
|
||||
UTIL_Remove( this );
|
||||
return;
|
||||
}
|
||||
|
||||
// Look for nearby entities to burn.
|
||||
CBaseEntity *ents[512];
|
||||
float dists[512];
|
||||
int nEnts = FindBurnableEntsInSphere( ents, dists, ARRAYSIZE( ents ), GetAbsOrigin(), FIRE_DAMAGE_SEARCH_DISTANCE, m_hOwner );
|
||||
|
||||
for ( int i=0; i < nEnts; i++ )
|
||||
{
|
||||
float flDistFromBorder = MAX( 0, FIRE_DAMAGE_DISTANCE - dists[i] );
|
||||
if ( flDistFromBorder <= 0 )
|
||||
continue;
|
||||
|
||||
float flDamage = litPercent * flDistFromBorder / FIRE_DAMAGE_DISTANCE * FIRE_DAMAGE_PER_SEC;
|
||||
GetFireDamageMgr()->AddDamage( ents[i], m_hOwner, flDamage, !IsGasolineBlob( ents[i] ) );
|
||||
}
|
||||
|
||||
// Ignite our "auto burn" blobs.
|
||||
AutoBurn_R( NULL );
|
||||
}
|
||||
|
||||
// Figure out where we want to go.
|
||||
if ( !IsStopped() )
|
||||
{
|
||||
// Apply gravity.
|
||||
Vector vecNewVelocity = GetAbsVelocity();
|
||||
if ( m_BlobFlags & BLOBFLAG_USE_GRAVITY )
|
||||
{
|
||||
vecNewVelocity.z -= 800 * gpGlobals->frametime;
|
||||
SetAbsVelocity( vecNewVelocity );
|
||||
}
|
||||
|
||||
Vector vNewPos = GetAbsOrigin() + vecNewVelocity * gpGlobals->frametime;
|
||||
|
||||
// Can we go there?
|
||||
trace_t trace;
|
||||
UTIL_TraceLine( GetAbsOrigin(), vNewPos, CONTENTS_SOLID, NULL, COLLISION_GROUP_NONE, &trace );
|
||||
bool bStopped = (trace.fraction != 1);
|
||||
|
||||
if ( !bStopped )
|
||||
{
|
||||
// Trace against shields.
|
||||
if ( TFGameRules()->IsTraceBlockedByWorldOrShield( GetAbsOrigin(), vNewPos, m_hOwner, DMG_BURN, &trace ) )
|
||||
{
|
||||
// Blobs just fizzle out when they hit a shield.
|
||||
UTIL_Remove( this );
|
||||
}
|
||||
}
|
||||
|
||||
if( bStopped )
|
||||
{
|
||||
SetLocalOrigin( trace.endpos + trace.plane.normal * 2 );
|
||||
|
||||
// Ok, we hit something. Stop moving.
|
||||
m_BlobFlags |= BLOBFLAG_STOPPED;
|
||||
m_vSurfaceNormal = trace.plane.normal;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLocalOrigin( vNewPos );
|
||||
}
|
||||
}
|
||||
|
||||
SetNextThink( gpGlobals->curtime );
|
||||
}
|
||||
|
||||
|
||||
bool IsGasolineBlob( CBaseEntity *pEnt )
|
||||
{
|
||||
return FClassnameIs( pEnt, "gasoline_blob" );
|
||||
}
|
||||
|
||||
93
game/server/tf2/gasoline_blob.h
Normal file
93
game/server/tf2/gasoline_blob.h
Normal file
@@ -0,0 +1,93 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef GASOLINE_BLOB_H
|
||||
#define GASOLINE_BLOB_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "baseentity.h"
|
||||
|
||||
|
||||
class CGasolineBlob : public CBaseEntity
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CGasolineBlob, CBaseEntity );
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
|
||||
// Create a gasoline blob.
|
||||
// flAirLifetime specifies how long it takes to fizzle out in the air.
|
||||
static CGasolineBlob* Create(
|
||||
CBaseEntity *pOwner,
|
||||
const Vector &vOrigin,
|
||||
const Vector &vStartVelocity,
|
||||
bool bUseGravity,
|
||||
float flAirLifetime,
|
||||
float flLifetime );
|
||||
|
||||
virtual ~CGasolineBlob();
|
||||
|
||||
// A lit blob will always apply at least 25% damage to its "auto burn" blob.
|
||||
//
|
||||
// This is used when laying down gasoline blobs in a line. Since it's fairly easy to accidentally
|
||||
// lay down blobs that won't damage each other because they're too far away, the line of blobs
|
||||
// can be linked together using this.
|
||||
void AddAutoBurnBlob( CGasolineBlob *pBlob );
|
||||
|
||||
|
||||
// Overrides.
|
||||
public:
|
||||
|
||||
virtual int OnTakeDamage( const CTakeDamageInfo &info );
|
||||
|
||||
|
||||
|
||||
// Implementation.
|
||||
public:
|
||||
|
||||
bool IsLit() const;
|
||||
bool IsStopped() const;
|
||||
void SetLit( bool bLit );
|
||||
|
||||
void Think();
|
||||
|
||||
void AutoBurn_R( CGasolineBlob *pParent );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
typedef CHandle<CGasolineBlob> CGasolineBlobHandle;
|
||||
CUtlVector<CGasolineBlobHandle> m_AutoBurnBlobs;
|
||||
|
||||
float m_flTimeInAir; // How long we've been in the air.
|
||||
float m_flAirLifetime; // How long we're allowed to exist in the air.
|
||||
|
||||
CNetworkVar( float, m_flLitStartTime ); // What time did the blob become lit at?
|
||||
|
||||
CNetworkVar( int, m_BlobFlags ); // Combination of BLOBFLAG_ defines.
|
||||
|
||||
// This is set at the start and is used to know the percentage of lifetime left.
|
||||
CNetworkVar( float, m_flMaxLifetime );
|
||||
|
||||
// When the blob was created.
|
||||
CNetworkVar( float, m_flCreateTime );
|
||||
|
||||
CNetworkVector( m_vSurfaceNormal ); // This is sent to the client so it can spread the fire out.
|
||||
|
||||
EHANDLE m_hOwner;
|
||||
float m_HeatLevel; // This rises when other flames are nearby until we ignite.
|
||||
};
|
||||
|
||||
|
||||
// Returns true if the entity is a gasoline blob.
|
||||
bool IsGasolineBlob( CBaseEntity *pEnt );
|
||||
|
||||
|
||||
#endif // GASOLINE_BLOB_H
|
||||
587
game/server/tf2/info_act.cpp
Normal file
587
game/server/tf2/info_act.cpp
Normal file
@@ -0,0 +1,587 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "EntityOutput.h"
|
||||
#include "EntityList.h"
|
||||
#include "tf_team.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "baseentity.h"
|
||||
#include "tf_shareddefs.h"
|
||||
#include "info_act.h"
|
||||
|
||||
// Global pointer to the current act
|
||||
CHandle<CInfoAct> g_hCurrentAct;
|
||||
|
||||
BEGIN_DATADESC( CInfoAct )
|
||||
|
||||
// inputs
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Start", InputStart ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "FinishWinNone", InputFinishWinNone ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "FinishWin1", InputFinishWin1 ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "FinishWin2", InputFinishWin2 ),
|
||||
DEFINE_INPUTFUNC( FIELD_FLOAT, "AddTime", InputAddTime ),
|
||||
|
||||
// outputs
|
||||
DEFINE_OUTPUT( m_OnStarted, "OnStarted" ),
|
||||
DEFINE_OUTPUT( m_OnFinishedTeamNone, "OnFinishedWinNone" ),
|
||||
DEFINE_OUTPUT( m_OnFinishedTeam1, "OnFinishedWin1" ),
|
||||
DEFINE_OUTPUT( m_OnFinishedTeam2, "OnFinishedWin2" ),
|
||||
DEFINE_OUTPUT( m_OnTimerExpired, "OnTimerExpired" ),
|
||||
|
||||
DEFINE_OUTPUT( m_Respawn1Team1Events[CInfoAct::RESPAWN_TIMER_90_REMAINING], "OnRespawn1Team1_90sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn1Team1Events[CInfoAct::RESPAWN_TIMER_60_REMAINING], "OnRespawn1Team1_60sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn1Team1Events[CInfoAct::RESPAWN_TIMER_45_REMAINING], "OnRespawn1Team1_45sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn1Team1Events[CInfoAct::RESPAWN_TIMER_30_REMAINING], "OnRespawn1Team1_30sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn1Team1Events[CInfoAct::RESPAWN_TIMER_10_REMAINING], "OnRespawn1Team1_10sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn1Team1Events[CInfoAct::RESPAWN_TIMER_0_REMAINING], "OnRespawn1Team1" ),
|
||||
DEFINE_OUTPUT( m_Respawn1Team1TimeRemaining, "Respawn1Team1TimeRemaining" ),
|
||||
|
||||
DEFINE_OUTPUT( m_Respawn2Team1Events[CInfoAct::RESPAWN_TIMER_90_REMAINING], "OnRespawn2Team1_90sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn2Team1Events[CInfoAct::RESPAWN_TIMER_60_REMAINING], "OnRespawn2Team1_60sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn2Team1Events[CInfoAct::RESPAWN_TIMER_45_REMAINING], "OnRespawn2Team1_45sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn2Team1Events[CInfoAct::RESPAWN_TIMER_30_REMAINING], "OnRespawn2Team1_30sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn2Team1Events[CInfoAct::RESPAWN_TIMER_10_REMAINING], "OnRespawn2Team1_10sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn2Team1Events[CInfoAct::RESPAWN_TIMER_0_REMAINING], "OnRespawn2Team1" ),
|
||||
DEFINE_OUTPUT( m_Respawn2Team1TimeRemaining, "Respawn2Team1TimeRemaining" ),
|
||||
|
||||
DEFINE_OUTPUT( m_Respawn1Team2Events[CInfoAct::RESPAWN_TIMER_90_REMAINING], "OnRespawn1Team2_90sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn1Team2Events[CInfoAct::RESPAWN_TIMER_60_REMAINING], "OnRespawn1Team2_60sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn1Team2Events[CInfoAct::RESPAWN_TIMER_45_REMAINING], "OnRespawn1Team2_45sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn1Team2Events[CInfoAct::RESPAWN_TIMER_30_REMAINING], "OnRespawn1Team2_30sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn1Team2Events[CInfoAct::RESPAWN_TIMER_10_REMAINING], "OnRespawn1Team2_10sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn1Team2Events[CInfoAct::RESPAWN_TIMER_0_REMAINING], "OnRespawn1Team2" ),
|
||||
DEFINE_OUTPUT( m_Respawn1Team2TimeRemaining, "Respawn1Team2TimeRemaining" ),
|
||||
|
||||
DEFINE_OUTPUT( m_Respawn2Team2Events[CInfoAct::RESPAWN_TIMER_90_REMAINING], "OnRespawn2Team2_90sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn2Team2Events[CInfoAct::RESPAWN_TIMER_60_REMAINING], "OnRespawn2Team2_60sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn2Team2Events[CInfoAct::RESPAWN_TIMER_45_REMAINING], "OnRespawn2Team2_45sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn2Team2Events[CInfoAct::RESPAWN_TIMER_30_REMAINING], "OnRespawn2Team2_30sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn2Team2Events[CInfoAct::RESPAWN_TIMER_10_REMAINING], "OnRespawn2Team2_10sec" ),
|
||||
DEFINE_OUTPUT( m_Respawn2Team2Events[CInfoAct::RESPAWN_TIMER_0_REMAINING], "OnRespawn2Team2" ),
|
||||
DEFINE_OUTPUT( m_Respawn2Team2TimeRemaining, "Respawn2Team2TimeRemaining" ),
|
||||
|
||||
DEFINE_OUTPUT( m_Team1RespawnDelayDone, "OnTeam1RespawnDelayDone" ),
|
||||
DEFINE_OUTPUT( m_Team2RespawnDelayDone, "OnTeam2RespawnDelayDone" ),
|
||||
|
||||
// keys
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_iActNumber, FIELD_INTEGER, "ActNumber" ),
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_flActTimeLimit, FIELD_FLOAT, "ActTimeLimit" ),
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_iszIntermissionCamera, FIELD_STRING, "IntermissionCamera" ),
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_nRespawn1Team1Time, FIELD_INTEGER, "Respawn1Team1Time" ),
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_nRespawn2Team1Time, FIELD_INTEGER, "Respawn2Team1Time" ),
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_nRespawn1Team2Time, FIELD_INTEGER, "Respawn1Team2Time" ),
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_nRespawn2Team2Time, FIELD_INTEGER, "Respawn2Team2Time" ),
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_nRespawnTeam1Delay, FIELD_INTEGER, "RespawnTeam1InitialDelay" ),
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_nRespawnTeam2Delay, FIELD_INTEGER, "RespawnTeam2InitialDelay" ),
|
||||
|
||||
// functions
|
||||
DEFINE_FUNCTION( ActThink ),
|
||||
DEFINE_FUNCTION( ActThinkEndActOverlayTime ),
|
||||
DEFINE_FUNCTION( RespawnTimerThink ),
|
||||
DEFINE_FUNCTION( Team1RespawnDelayThink ),
|
||||
DEFINE_FUNCTION( Team2RespawnDelayThink ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST(CInfoAct, DT_InfoAct)
|
||||
SendPropInt(SENDINFO(m_iActNumber), 5 ),
|
||||
SendPropInt(SENDINFO(m_spawnflags), SF_ACT_BITS, SPROP_UNSIGNED ),
|
||||
SendPropFloat(SENDINFO(m_flActTimeLimit), 12 ),
|
||||
SendPropInt(SENDINFO(m_nRespawn1Team1Time), 8 ),
|
||||
SendPropInt(SENDINFO(m_nRespawn2Team1Time), 8 ),
|
||||
SendPropInt(SENDINFO(m_nRespawn1Team2Time), 8 ),
|
||||
SendPropInt(SENDINFO(m_nRespawn2Team2Time), 8 ),
|
||||
SendPropInt(SENDINFO(m_nRespawnTeam1Delay), 8 ),
|
||||
SendPropInt(SENDINFO(m_nRespawnTeam2Delay), 8 ),
|
||||
END_SEND_TABLE();
|
||||
|
||||
LINK_ENTITY_TO_CLASS( info_act, CInfoAct );
|
||||
|
||||
|
||||
#define RESPAWN_TIMER_CONTEXT "RespawnTimerThink"
|
||||
#define RESPAWN_TEAM_1_DELAY_CONTEXT "RespawnTeam1DelayThink"
|
||||
#define RESPAWN_TEAM_2_DELAY_CONTEXT "RespawnTeam2DelayThink"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CInfoAct::CInfoAct( void )
|
||||
{
|
||||
// No act == -1
|
||||
m_iActNumber = -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CInfoAct::UpdateTransmitState()
|
||||
{
|
||||
return SetTransmitState( FL_EDICT_ALWAYS );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::Spawn( void )
|
||||
{
|
||||
m_flActStartedAt = 0;
|
||||
m_iWinners = 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set up respawn timers
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::SetUpRespawnTimers()
|
||||
{
|
||||
// NOTE: Need to add the second there so the respawn timers don't immediately trigger
|
||||
SetContextThink( RespawnTimerThink, gpGlobals->curtime + 1.0f, RESPAWN_TIMER_CONTEXT );
|
||||
|
||||
if (m_nRespawnTeam1Delay != 0)
|
||||
{
|
||||
SetContextThink( Team1RespawnDelayThink, gpGlobals->curtime + m_nRespawnTeam1Delay, RESPAWN_TEAM_1_DELAY_CONTEXT );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Team1RespawnDelayDone.FireOutput( this, this );
|
||||
}
|
||||
|
||||
if (m_nRespawnTeam2Delay != 0)
|
||||
{
|
||||
SetContextThink( Team2RespawnDelayThink, gpGlobals->curtime + m_nRespawnTeam2Delay, RESPAWN_TEAM_2_DELAY_CONTEXT );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Team2RespawnDelayDone.FireOutput( this, this );
|
||||
}
|
||||
}
|
||||
|
||||
void CInfoAct::ShutdownRespawnTimers()
|
||||
{
|
||||
SetContextThink( NULL, 0, RESPAWN_TIMER_CONTEXT );
|
||||
SetContextThink( NULL, 0, RESPAWN_TEAM_1_DELAY_CONTEXT );
|
||||
SetContextThink( NULL, 0, RESPAWN_TEAM_2_DELAY_CONTEXT );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Respawn delay
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::Team1RespawnDelayThink()
|
||||
{
|
||||
m_Team1RespawnDelayDone.FireOutput( this, this );
|
||||
SetContextThink( NULL, 0, RESPAWN_TEAM_1_DELAY_CONTEXT );
|
||||
}
|
||||
|
||||
void CInfoAct::Team2RespawnDelayThink()
|
||||
{
|
||||
m_Team2RespawnDelayDone.FireOutput( this, this );
|
||||
SetContextThink( NULL, 0, RESPAWN_TEAM_2_DELAY_CONTEXT );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Computes the time remaining
|
||||
//-----------------------------------------------------------------------------
|
||||
int CInfoAct::ComputeTimeRemaining( int nPeriod, int nDelay )
|
||||
{
|
||||
if (nPeriod <= 0)
|
||||
return -1;
|
||||
|
||||
int nTimeDelta = (int)(gpGlobals->curtime - m_flActStartedAt);
|
||||
Assert( nTimeDelta >= 0 );
|
||||
nTimeDelta -= nDelay;
|
||||
|
||||
// This case takes care of the initial spawn delay time...
|
||||
if (nTimeDelta <= 0)
|
||||
{
|
||||
return nPeriod - nTimeDelta;
|
||||
}
|
||||
|
||||
int nFactor = nTimeDelta / nPeriod;
|
||||
int nTimeRemainder = nTimeDelta - nFactor * nPeriod;
|
||||
if (nTimeRemainder == 0)
|
||||
return 0;
|
||||
|
||||
return nPeriod - nTimeRemainder;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Fires respawn events
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::FireRespawnEvents( int nTimeRemaining, COutputEvent *pRespawnEvents, COutputInt &respawnTime )
|
||||
{
|
||||
if (nTimeRemaining < 0)
|
||||
return;
|
||||
|
||||
switch (nTimeRemaining)
|
||||
{
|
||||
case 90:
|
||||
pRespawnEvents[RESPAWN_TIMER_90_REMAINING].FireOutput( this, this );
|
||||
break;
|
||||
case 60:
|
||||
pRespawnEvents[RESPAWN_TIMER_60_REMAINING].FireOutput( this, this );
|
||||
break;
|
||||
case 45:
|
||||
pRespawnEvents[RESPAWN_TIMER_45_REMAINING].FireOutput( this, this );
|
||||
break;
|
||||
case 30:
|
||||
pRespawnEvents[RESPAWN_TIMER_30_REMAINING].FireOutput( this, this );
|
||||
break;
|
||||
case 10:
|
||||
pRespawnEvents[RESPAWN_TIMER_10_REMAINING].FireOutput( this, this );
|
||||
break;
|
||||
case 0:
|
||||
pRespawnEvents[RESPAWN_TIMER_0_REMAINING].FireOutput( this, this );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
respawnTime.Set( nTimeRemaining, this, this );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Respawn timers
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::RespawnTimerThink()
|
||||
{
|
||||
int nTimeRemaining = ComputeTimeRemaining( m_nRespawn1Team1Time, m_nRespawnTeam1Delay );
|
||||
FireRespawnEvents( nTimeRemaining, m_Respawn1Team1Events, m_Respawn1Team1TimeRemaining );
|
||||
|
||||
nTimeRemaining = ComputeTimeRemaining( m_nRespawn2Team1Time, m_nRespawnTeam1Delay );
|
||||
FireRespawnEvents( nTimeRemaining, m_Respawn2Team1Events, m_Respawn2Team1TimeRemaining );
|
||||
|
||||
nTimeRemaining = ComputeTimeRemaining( m_nRespawn1Team2Time, m_nRespawnTeam2Delay );
|
||||
FireRespawnEvents( nTimeRemaining, m_Respawn1Team2Events, m_Respawn1Team2TimeRemaining );
|
||||
|
||||
nTimeRemaining = ComputeTimeRemaining( m_nRespawn2Team2Time, m_nRespawnTeam2Delay );
|
||||
FireRespawnEvents( nTimeRemaining, m_Respawn2Team2Events, m_Respawn2Team2TimeRemaining );
|
||||
|
||||
SetNextThink( gpGlobals->curtime + 1.0f, RESPAWN_TIMER_CONTEXT );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The act has started
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::StartAct( void )
|
||||
{
|
||||
// FIXME: Should this change?
|
||||
// Don't allow two simultaneous acts
|
||||
if (g_hCurrentAct)
|
||||
{
|
||||
g_hCurrentAct->FinishAct( );
|
||||
}
|
||||
|
||||
// Set the global act to this
|
||||
g_hCurrentAct = this;
|
||||
|
||||
m_flActStartedAt = gpGlobals->curtime;
|
||||
m_OnStarted.FireOutput( this, this );
|
||||
|
||||
// Do we have a timelimit?
|
||||
if ( m_flActTimeLimit )
|
||||
{
|
||||
SetNextThink( gpGlobals->curtime + m_flActTimeLimit );
|
||||
SetThink( ActThink );
|
||||
}
|
||||
|
||||
SetUpRespawnTimers();
|
||||
|
||||
// Tell all the clients
|
||||
CReliableBroadcastRecipientFilter filter;
|
||||
|
||||
UserMessageBegin( filter, "ActBegin" );
|
||||
WRITE_BYTE( (byte)m_iActNumber );
|
||||
WRITE_FLOAT( m_flActStartedAt );
|
||||
MessageEnd();
|
||||
|
||||
// If we're not an intermission, clean up
|
||||
if ( !HasSpawnFlags( SF_ACT_INTERMISSION ) )
|
||||
{
|
||||
CleanupOnActStart();
|
||||
}
|
||||
|
||||
// Cycle through all players and start the act
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)UTIL_PlayerByIndex( i );
|
||||
if ( pPlayer )
|
||||
{
|
||||
// Am I an intermission?
|
||||
if ( HasSpawnFlags( SF_ACT_INTERMISSION ) )
|
||||
{
|
||||
StartIntermission( pPlayer );
|
||||
}
|
||||
else
|
||||
{
|
||||
StartActOverlayTime( pPlayer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Think again soon, to remove player locks
|
||||
if ( !HasSpawnFlags(SF_ACT_INTERMISSION) )
|
||||
{
|
||||
SetNextThink( gpGlobals->curtime + MIN_ACT_OVERLAY_TIME );
|
||||
SetThink( ActThinkEndActOverlayTime );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Update a client who joined during the middle of an act
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::UpdateClient( CBaseTFPlayer *pPlayer )
|
||||
{
|
||||
CSingleUserRecipientFilter user( pPlayer );
|
||||
user.MakeReliable();
|
||||
|
||||
UserMessageBegin( user, "ActBegin" );
|
||||
WRITE_BYTE( (byte)m_iActNumber );
|
||||
WRITE_FLOAT( m_flActStartedAt );
|
||||
MessageEnd();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The act has finished
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::FinishAct( )
|
||||
{
|
||||
if ( g_hCurrentAct.Get() != this )
|
||||
{
|
||||
DevWarning( 2, "Attempted to finish an act which wasn't started!\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
ShutdownRespawnTimers();
|
||||
|
||||
switch( m_iWinners)
|
||||
{
|
||||
case 0:
|
||||
m_OnFinishedTeamNone.FireOutput( this, this );
|
||||
break;
|
||||
|
||||
case 1:
|
||||
m_OnFinishedTeam1.FireOutput( this, this );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
m_OnFinishedTeam2.FireOutput( this, this );
|
||||
break;
|
||||
|
||||
default:
|
||||
Assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
g_hCurrentAct = NULL;
|
||||
|
||||
// Tell all the clients
|
||||
CReliableBroadcastRecipientFilter filter;
|
||||
UserMessageBegin( filter, "ActEnd" );
|
||||
WRITE_BYTE( m_iWinners );
|
||||
MessageEnd();
|
||||
|
||||
// Am I an intermission?
|
||||
if ( HasSpawnFlags( SF_ACT_INTERMISSION ) )
|
||||
{
|
||||
// Cycle through all players and end the intermission for them
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)UTIL_PlayerByIndex( i );
|
||||
if ( pPlayer )
|
||||
{
|
||||
EndIntermission( pPlayer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::ActThink( void )
|
||||
{
|
||||
m_OnTimerExpired.FireOutput( this,this );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Force the players not to move to give them time to read the act overlays
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::StartActOverlayTime( CBaseTFPlayer *pPlayer )
|
||||
{
|
||||
// Lock the player in place
|
||||
pPlayer->CleanupOnActStart();
|
||||
pPlayer->LockPlayerInPlace();
|
||||
|
||||
if ( pPlayer->GetActiveWeapon() )
|
||||
{
|
||||
pPlayer->GetActiveWeapon()->Holster();
|
||||
}
|
||||
|
||||
pPlayer->m_Local.m_iHideHUD |= (HIDEHUD_WEAPONSELECTION | HIDEHUD_HEALTH);
|
||||
pPlayer->GetLocalData()->m_bForceMapOverview = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Release the players after overlay time has finished
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::EndActOverlayTime( CBaseTFPlayer *pPlayer )
|
||||
{
|
||||
// Release the player
|
||||
pPlayer->UnlockPlayer();
|
||||
|
||||
if ( pPlayer->GetActiveWeapon() )
|
||||
{
|
||||
pPlayer->GetActiveWeapon()->Deploy();
|
||||
}
|
||||
|
||||
pPlayer->m_Local.m_iHideHUD &= ~(HIDEHUD_WEAPONSELECTION | HIDEHUD_HEALTH);
|
||||
pPlayer->GetLocalData()->m_bForceMapOverview = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Unlock the players after an act has started
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::ActThinkEndActOverlayTime( void )
|
||||
{
|
||||
// Cycle through all players and end the intermission for them
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)UTIL_PlayerByIndex( i );
|
||||
if ( pPlayer )
|
||||
{
|
||||
EndActOverlayTime( pPlayer );
|
||||
}
|
||||
}
|
||||
|
||||
// Think again when the act ends, if we have a timelimit
|
||||
if ( m_flActTimeLimit )
|
||||
{
|
||||
SetNextThink( gpGlobals->curtime + m_flActTimeLimit - MIN_ACT_OVERLAY_TIME );
|
||||
SetThink( ActThink );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Clean up entities before a new act starts
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::CleanupOnActStart( void )
|
||||
{
|
||||
// Remove all resource chunks
|
||||
CBaseEntity *pEntity = NULL;
|
||||
while ((pEntity = gEntList.FindEntityByClassname( pEntity, "resource_chunk" )) != NULL)
|
||||
{
|
||||
UTIL_Remove( pEntity );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Intermission handling
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::StartIntermission( CBaseTFPlayer *pPlayer )
|
||||
{
|
||||
// Do we have a camera point?
|
||||
if ( m_iszIntermissionCamera != NULL_STRING )
|
||||
{
|
||||
CBaseEntity *pCamera = gEntList.FindEntityByName( NULL, STRING(m_iszIntermissionCamera) );
|
||||
if ( pCamera )
|
||||
{
|
||||
// Move the player to the camera point
|
||||
pPlayer->SetViewEntity( pCamera );
|
||||
pPlayer->m_Local.m_iHideHUD |= (HIDEHUD_WEAPONSELECTION | HIDEHUD_HEALTH | HIDEHUD_MISCSTATUS);
|
||||
}
|
||||
}
|
||||
|
||||
// Lock the player in place
|
||||
pPlayer->LockPlayerInPlace();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Intermission handling
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::EndIntermission( CBaseTFPlayer *pPlayer )
|
||||
{
|
||||
// Force the player to respawn
|
||||
pPlayer->UnlockPlayer();
|
||||
pPlayer->SetViewEntity( pPlayer );
|
||||
pPlayer->ForceRespawn();
|
||||
pPlayer->m_Local.m_iHideHUD &= ~(HIDEHUD_WEAPONSELECTION | HIDEHUD_HEALTH | HIDEHUD_MISCSTATUS);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Force the act to start
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::InputStart( inputdata_t &inputdata )
|
||||
{
|
||||
StartAct();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Force the act to finish, with team 1 as the winners
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::InputFinishWinNone( inputdata_t &inputdata )
|
||||
{
|
||||
m_iWinners = 0;
|
||||
FinishAct();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Force the act to finish, with team 1 as the winners
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::InputFinishWin1( inputdata_t &inputdata )
|
||||
{
|
||||
m_iWinners = 1;
|
||||
FinishAct();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Force the act to finish, with team 2 as the winners
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::InputFinishWin2( inputdata_t &inputdata )
|
||||
{
|
||||
m_iWinners = 2;
|
||||
FinishAct();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Add time to the act's time
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAct::InputAddTime( inputdata_t &inputdata )
|
||||
{
|
||||
float flNewTime = inputdata.value.Float();
|
||||
|
||||
// Think again when the act ends, if we have a timelimit
|
||||
if ( flNewTime )
|
||||
{
|
||||
m_flActTimeLimit += flNewTime;
|
||||
SetNextThink( GetNextThink() + flNewTime );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CInfoAct::IsAWaitingAct( void )
|
||||
{
|
||||
return HasSpawnFlags(SF_ACT_WAITINGFORGAMESTART);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if the current act (if any) is a waiting act.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CurrentActIsAWaitingAct( void )
|
||||
{
|
||||
if ( g_hCurrentAct )
|
||||
return g_hCurrentAct->IsAWaitingAct();
|
||||
|
||||
return false;
|
||||
}
|
||||
138
game/server/tf2/info_act.h
Normal file
138
game/server/tf2/info_act.h
Normal file
@@ -0,0 +1,138 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef INFO_ACT_H
|
||||
#define INFO_ACT_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
class CBaseTFPlayer;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Map entity that defines an act
|
||||
//-----------------------------------------------------------------------------
|
||||
class CInfoAct : public CBaseEntity
|
||||
{
|
||||
DECLARE_CLASS( CInfoAct, CBaseEntity );
|
||||
public:
|
||||
CInfoAct();
|
||||
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
int UpdateTransmitState();
|
||||
|
||||
void Spawn( void );
|
||||
void StartAct( void );
|
||||
void UpdateClient( CBaseTFPlayer *pPlayer );
|
||||
void FinishAct( void );
|
||||
void ActThink( void );
|
||||
int ActNumber() const;
|
||||
|
||||
void CleanupOnActStart( void );
|
||||
|
||||
bool IsAWaitingAct( void );
|
||||
|
||||
// Act player locking
|
||||
void StartActOverlayTime( CBaseTFPlayer *pPlayer );
|
||||
void EndActOverlayTime( CBaseTFPlayer *pPlayer );
|
||||
void ActThinkEndActOverlayTime( void );
|
||||
|
||||
// Intermissions
|
||||
void StartIntermission( CBaseTFPlayer *pPlayer );
|
||||
void EndIntermission( CBaseTFPlayer *pPlayer );
|
||||
|
||||
int GetMCVTimer( void ) { return m_nRespawn2Team2Time; }
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
RESPAWN_TIMER_90_REMAINING = 0,
|
||||
RESPAWN_TIMER_60_REMAINING,
|
||||
RESPAWN_TIMER_45_REMAINING,
|
||||
RESPAWN_TIMER_30_REMAINING,
|
||||
RESPAWN_TIMER_10_REMAINING,
|
||||
RESPAWN_TIMER_0_REMAINING,
|
||||
|
||||
RESPAWN_TIMER_EVENT_COUNT
|
||||
};
|
||||
|
||||
void SetUpRespawnTimers();
|
||||
void ShutdownRespawnTimers();
|
||||
|
||||
// Inputs
|
||||
void InputStart( inputdata_t &inputdata );
|
||||
void InputFinishWinNone( inputdata_t &inputdata );
|
||||
void InputFinishWin1( inputdata_t &inputdata );
|
||||
void InputFinishWin2( inputdata_t &inputdata );
|
||||
void InputAddTime( inputdata_t &inputdata );
|
||||
|
||||
// Respawn timers
|
||||
void RespawnTimerThink();
|
||||
|
||||
// Respawn delay
|
||||
void Team1RespawnDelayThink();
|
||||
void Team2RespawnDelayThink();
|
||||
|
||||
// Computes the time remaining
|
||||
int ComputeTimeRemaining( int nPeriod, int nDelay );
|
||||
|
||||
// Fires respawn events
|
||||
void FireRespawnEvents( int nTimeRemaining, COutputEvent *pRespawnEvents, COutputInt &respawnTime );
|
||||
|
||||
// Outputs
|
||||
COutputEvent m_OnStarted;
|
||||
COutputEvent m_OnFinishedTeamNone;
|
||||
COutputEvent m_OnFinishedTeam1;
|
||||
COutputEvent m_OnFinishedTeam2;
|
||||
COutputEvent m_OnTimerExpired;
|
||||
|
||||
COutputEvent m_Team1RespawnDelayDone;
|
||||
COutputEvent m_Team2RespawnDelayDone;
|
||||
|
||||
COutputInt m_Respawn1Team1TimeRemaining;
|
||||
COutputInt m_Respawn2Team1TimeRemaining;
|
||||
COutputInt m_Respawn1Team2TimeRemaining;
|
||||
COutputInt m_Respawn2Team2TimeRemaining;
|
||||
|
||||
// A whole buncha respawn timer events
|
||||
COutputEvent m_Respawn1Team1Events[RESPAWN_TIMER_EVENT_COUNT];
|
||||
COutputEvent m_Respawn2Team1Events[RESPAWN_TIMER_EVENT_COUNT];
|
||||
COutputEvent m_Respawn1Team2Events[RESPAWN_TIMER_EVENT_COUNT];
|
||||
COutputEvent m_Respawn2Team2Events[RESPAWN_TIMER_EVENT_COUNT];
|
||||
|
||||
// Respawn timer periods
|
||||
CNetworkVar( int, m_nRespawn1Team1Time );
|
||||
CNetworkVar( int, m_nRespawn1Team2Time );
|
||||
CNetworkVar( int, m_nRespawn2Team1Time );
|
||||
CNetworkVar( int, m_nRespawn2Team2Time );
|
||||
CNetworkVar( int, m_nRespawnTeam1Delay );
|
||||
CNetworkVar( int, m_nRespawnTeam2Delay );
|
||||
|
||||
// Data
|
||||
CNetworkVar( int, m_iActNumber );
|
||||
CNetworkVar( float, m_flActTimeLimit );
|
||||
int m_iWinners;
|
||||
|
||||
// Acts
|
||||
float m_flActStartedAt;
|
||||
|
||||
// Intermissions
|
||||
string_t m_iszIntermissionCamera;
|
||||
};
|
||||
|
||||
inline int CInfoAct::ActNumber() const
|
||||
{
|
||||
return m_iActNumber;
|
||||
}
|
||||
|
||||
extern CHandle<CInfoAct> g_hCurrentAct;
|
||||
|
||||
bool CurrentActIsAWaitingAct( void );
|
||||
|
||||
#endif // INFO_ACT_H
|
||||
72
game/server/tf2/info_add_resources.cpp
Normal file
72
game/server/tf2/info_add_resources.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "EntityOutput.h"
|
||||
#include "EntityList.h"
|
||||
#include "tf_team.h"
|
||||
#include "baseentity.h"
|
||||
#include "tf_stats.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Map entity that gives resources to players passed into it
|
||||
//-----------------------------------------------------------------------------
|
||||
class CInfoAddResources : public CBaseEntity
|
||||
{
|
||||
DECLARE_CLASS( CInfoAddResources, CBaseEntity );
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void Spawn( void );
|
||||
|
||||
// Inputs
|
||||
void InputPlayer( inputdata_t &inputdata );
|
||||
|
||||
public:
|
||||
// Outputs
|
||||
COutputEvent m_OnAdded;
|
||||
|
||||
// Data
|
||||
int m_iResourceAmount;
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CInfoAddResources )
|
||||
|
||||
// inputs
|
||||
DEFINE_INPUTFUNC( FIELD_EHANDLE, "Player", InputPlayer ),
|
||||
|
||||
// outputs
|
||||
DEFINE_OUTPUT( m_OnAdded, "OnAdded" ),
|
||||
|
||||
// keys
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_iResourceAmount, FIELD_INTEGER, "ResourceAmount" ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( info_add_resources, CInfoAddResources );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAddResources::Spawn( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoAddResources::InputPlayer( inputdata_t &inputdata )
|
||||
{
|
||||
CBaseEntity *pEntity = (inputdata.value.Entity()).Get();
|
||||
if ( pEntity && pEntity->IsPlayer() )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)pEntity;
|
||||
pPlayer->AddBankResources( m_iResourceAmount );
|
||||
TFStats()->IncrementPlayerStat( pPlayer, TF_PLAYER_STAT_RESOURCES_ACQUIRED, m_iResourceAmount );
|
||||
}
|
||||
|
||||
m_OnAdded.FireOutput( inputdata.pActivator, this );
|
||||
}
|
||||
217
game/server/tf2/info_buildpoint.cpp
Normal file
217
game/server/tf2/info_buildpoint.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Map entity that allows players to build objects on it
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "EntityOutput.h"
|
||||
#include "EntityList.h"
|
||||
#include "tf_team.h"
|
||||
#include "baseentity.h"
|
||||
#include "info_buildpoint.h"
|
||||
#include "tf_gamerules.h"
|
||||
|
||||
// Spawnflags
|
||||
const int SF_BUILDPOINT_ALLOW_ALL_GUNS = 0x01; // Allow all manned guns to be built on this point
|
||||
const int SF_BUILDPOINT_ALLOW_VEHICLES = 0x02; // Allow all vehicles to be built on this point
|
||||
|
||||
BEGIN_DATADESC( CInfoBuildPoint )
|
||||
|
||||
// keys
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_iszAllowedObject, FIELD_STRING, "AllowedObject" ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( info_buildpoint, CInfoBuildPoint );
|
||||
|
||||
// List of buildpoints
|
||||
CUtlVector<CInfoBuildPoint*> g_MapDefinedBuildPoints;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoBuildPoint::Spawn( void )
|
||||
{
|
||||
g_MapDefinedBuildPoints.AddToTail( this );
|
||||
|
||||
m_iAllowedObjectType = -1;
|
||||
if ( m_iszAllowedObject != NULL_STRING )
|
||||
{
|
||||
for ( int i = 0; i < OBJ_LAST; i++ )
|
||||
{
|
||||
if ( !Q_strcmp( STRING(m_iszAllowedObject), GetObjectInfo(i)->m_pClassName ) )
|
||||
{
|
||||
m_iAllowedObjectType = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoBuildPoint::UpdateOnRemove( void )
|
||||
{
|
||||
g_MapDefinedBuildPoints.FindAndRemove( this );
|
||||
BaseClass::UpdateOnRemove();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Tell me how many build points you have
|
||||
//-----------------------------------------------------------------------------
|
||||
int CInfoBuildPoint::GetNumBuildPoints( void ) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Give me the origin & angles of the specified build point
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CInfoBuildPoint::GetBuildPoint( int iPoint, Vector &vecOrigin, QAngle &vecAngles )
|
||||
{
|
||||
ASSERT( iPoint <= GetNumBuildPoints() );
|
||||
|
||||
vecOrigin = GetAbsOrigin();
|
||||
vecAngles = GetAbsAngles();
|
||||
return true;
|
||||
}
|
||||
|
||||
int CInfoBuildPoint::GetBuildPointAttachmentIndex( int iPoint ) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Can I build the specified object on the specified build point?
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CInfoBuildPoint::CanBuildObjectOnBuildPoint( int iPoint, int iObjectType )
|
||||
{
|
||||
ASSERT( iPoint <= GetNumBuildPoints() );
|
||||
if ( m_hObjectBuiltOnMe )
|
||||
return false;
|
||||
|
||||
// Manned guns?
|
||||
if ( m_spawnflags & SF_BUILDPOINT_ALLOW_ALL_GUNS )
|
||||
{
|
||||
if ( (iObjectType == OBJ_MANNED_PLASMAGUN) ||
|
||||
(iObjectType == OBJ_MANNED_MISSILELAUNCHER) ||
|
||||
(iObjectType == OBJ_MANNED_SHIELD) ||
|
||||
(iObjectType == OBJ_SENTRYGUN_PLASMA) )
|
||||
return true;
|
||||
}
|
||||
|
||||
// Vehicles
|
||||
if ( m_spawnflags & SF_BUILDPOINT_ALLOW_VEHICLES )
|
||||
{
|
||||
if ( IsObjectAVehicle(iObjectType) )
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check our unique
|
||||
if ( m_iAllowedObjectType >= 0 && m_iAllowedObjectType == iObjectType )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: I've finished building the specified object on the specified build point
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoBuildPoint::SetObjectOnBuildPoint( int iPoint, CBaseObject *pObject )
|
||||
{
|
||||
ASSERT( iPoint <= GetNumBuildPoints() );
|
||||
m_hObjectBuiltOnMe = pObject;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get the number of objects build on this entity
|
||||
//-----------------------------------------------------------------------------
|
||||
int CInfoBuildPoint::GetNumObjectsOnMe( void )
|
||||
{
|
||||
if ( m_hObjectBuiltOnMe )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get the first object that's built on me
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseEntity *CInfoBuildPoint::GetFirstObjectOnMe( void )
|
||||
{
|
||||
return m_hObjectBuiltOnMe;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Get the first object of type, return NULL if no such type available
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseObject *CInfoBuildPoint::GetObjectOfTypeOnMe( int iObjectType )
|
||||
{
|
||||
if ( m_hObjectBuiltOnMe )
|
||||
{
|
||||
if ( m_hObjectBuiltOnMe->ObjectType() == iObjectType )
|
||||
return m_hObjectBuiltOnMe;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Remove all objects built on me
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoBuildPoint::RemoveAllObjects( void )
|
||||
{
|
||||
UTIL_Remove( m_hObjectBuiltOnMe );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return the maximum distance that this entity's build points can be snapped to
|
||||
//-----------------------------------------------------------------------------
|
||||
float CInfoBuildPoint::GetMaxSnapDistance( int iPoint )
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if it's possible that build points on this entity may move in local space (i.e. due to animation)
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CInfoBuildPoint::ShouldCheckForMovement( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: I've finished building the specified object on the specified build point
|
||||
//-----------------------------------------------------------------------------
|
||||
int CInfoBuildPoint::FindObjectOnBuildPoint( CBaseObject *pObject )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns an exit point for a vehicle built on a build point...
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoBuildPoint::GetExitPoint( CBaseEntity *pPlayer, int iPoint, Vector *pAbsOrigin, QAngle *pAbsAngles )
|
||||
{
|
||||
// FIXME: In future, we may well want to use specific exit attachments here...
|
||||
GetBuildPoint( iPoint, *pAbsOrigin, *pAbsAngles );
|
||||
|
||||
// Move back along the forward direction a bit...
|
||||
Vector vecForward;
|
||||
AngleVectors( *pAbsAngles, &vecForward );
|
||||
*pAbsOrigin -= vecForward * 60;
|
||||
|
||||
// Now select a good spot to drop onto
|
||||
Vector vNewPos;
|
||||
if ( !EntityPlacementTest(pPlayer, *pAbsOrigin, vNewPos, true) )
|
||||
{
|
||||
Warning("Can't find valid place to exit object.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
*pAbsOrigin = vNewPos;
|
||||
}
|
||||
76
game/server/tf2/info_buildpoint.h
Normal file
76
game/server/tf2/info_buildpoint.h
Normal file
@@ -0,0 +1,76 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Map entity that allows players to build objects on it
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef INFO_BUILDPOINT_H
|
||||
#define INFO_BUILDPOINT_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "ihasbuildpoints.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Map entity that allows players to build objects on it
|
||||
//-----------------------------------------------------------------------------
|
||||
class CInfoBuildPoint : public CBaseEntity, public IHasBuildPoints
|
||||
{
|
||||
DECLARE_CLASS( CInfoBuildPoint, CBaseEntity );
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void Spawn( void );
|
||||
void UpdateOnRemove( void );
|
||||
|
||||
// IHasBuildPoints
|
||||
public:
|
||||
// Tell me how many build points you have
|
||||
virtual int GetNumBuildPoints( void ) const;
|
||||
|
||||
// Give me the origin & angles of the specified build point
|
||||
virtual bool GetBuildPoint( int iPoint, Vector &vecOrigin, QAngle &vecAngles );
|
||||
|
||||
virtual int GetBuildPointAttachmentIndex( int iPoint ) const;
|
||||
|
||||
// Can I build the specified object on the specified build point?
|
||||
virtual bool CanBuildObjectOnBuildPoint( int iPoint, int iObjectType );
|
||||
|
||||
// I've finished building the specified object on the specified build point
|
||||
virtual void SetObjectOnBuildPoint( int iPoint, CBaseObject *pObject );
|
||||
|
||||
// Get the number of objects build on this entity
|
||||
virtual int GetNumObjectsOnMe( void );
|
||||
|
||||
// Get the first object that's built on me
|
||||
virtual CBaseEntity *GetFirstObjectOnMe( void );
|
||||
|
||||
// Get the first object of type, return NULL if no such type available
|
||||
virtual CBaseObject *GetObjectOfTypeOnMe( int iObjectType );
|
||||
|
||||
// Remove all objects built on me
|
||||
virtual void RemoveAllObjects( void );
|
||||
|
||||
// Return the maximum distance that this entity's build points can be snapped to
|
||||
virtual float GetMaxSnapDistance( int iPoint );
|
||||
|
||||
// Return true if it's possible that build points on this entity may move in local space (i.e. due to animation)
|
||||
virtual bool ShouldCheckForMovement( void );
|
||||
|
||||
// I've finished building the specified object on the specified build point
|
||||
virtual int FindObjectOnBuildPoint( CBaseObject *pObject );
|
||||
|
||||
// Returns an exit point for a vehicle built on a build point...
|
||||
virtual void GetExitPoint( CBaseEntity *pPlayer, int iPoint, Vector *pAbsOrigin, QAngle *pAbsAngles );
|
||||
|
||||
|
||||
private:
|
||||
string_t m_iszAllowedObject;
|
||||
int m_iAllowedObjectType;
|
||||
CHandle<CBaseObject> m_hObjectBuiltOnMe;
|
||||
};
|
||||
|
||||
extern CUtlVector<CInfoBuildPoint*> g_MapDefinedBuildPoints;
|
||||
|
||||
#endif // INFO_BUILDPOINT_H
|
||||
107
game/server/tf2/info_customtech.cpp
Normal file
107
game/server/tf2/info_customtech.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Map entity that adds a custom technology to the techtree
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "EntityOutput.h"
|
||||
#include "EntityList.h"
|
||||
#include "tf_team.h"
|
||||
#include "techtree.h"
|
||||
#include "info_customtech.h"
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
BEGIN_DATADESC( CInfoCustomTechnology )
|
||||
|
||||
// outputs
|
||||
DEFINE_OUTPUT( m_flTechPercentage, "TechPercentage" ),
|
||||
|
||||
// keys
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_iszTech , FIELD_STRING, "TechToWatch" ),
|
||||
DEFINE_KEYFIELD_NOT_SAVED( m_iszTechTreeFile , FIELD_STRING, "NewTechFile" ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( CInfoCustomTechnology, DT_InfoCustomTechnology )
|
||||
SendPropString( SENDINFO( m_szTechTreeFile ) ),
|
||||
END_SEND_TABLE();
|
||||
|
||||
LINK_ENTITY_TO_CLASS( info_customtech, CInfoCustomTechnology );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Always transmit
|
||||
//-----------------------------------------------------------------------------
|
||||
int CInfoCustomTechnology::ShouldTransmit( const CCheckTransmitInfo *pInfo )
|
||||
{
|
||||
// Don't need to transmit ones that don't add new techs
|
||||
if ( !m_iszTechTreeFile )
|
||||
return FL_EDICT_DONTSEND;
|
||||
|
||||
// Only transmit to members of my team
|
||||
CBaseEntity* pRecipientEntity = CBaseEntity::Instance( pInfo->m_pClientEnt );
|
||||
if ( InSameTeam( pRecipientEntity ) )
|
||||
{
|
||||
//Msg( "SENDING\n" );
|
||||
return FL_EDICT_ALWAYS;
|
||||
}
|
||||
|
||||
return FL_EDICT_DONTSEND;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoCustomTechnology::Spawn( void )
|
||||
{
|
||||
m_flTechPercentage.Set( 0, this, this );
|
||||
memset( m_szTechTreeFile.GetForModify(), 0, sizeof(m_szTechTreeFile) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Add myself to the technology tree
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoCustomTechnology::Activate( void )
|
||||
{
|
||||
BaseClass::Activate();
|
||||
if ( !GetTeamNumber() )
|
||||
{
|
||||
Msg( "ERROR: info_customtech without a specified team.\n" );
|
||||
UTIL_Remove( this );
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the Team's Technology Tree
|
||||
CTFTeam *pTeam = (CTFTeam *)GetTeam();
|
||||
if ( pTeam )
|
||||
{
|
||||
CTechnologyTree *pTechTree = pTeam->GetTechnologyTree();
|
||||
if ( pTechTree )
|
||||
{
|
||||
// Am I supposed to add some new technologies to the tech tree?
|
||||
if ( m_iszTechTreeFile != NULL_STRING )
|
||||
{
|
||||
pTechTree->AddTechnologyFile( filesystem, GetTeamNumber(), (char*)STRING(m_iszTechTreeFile ) );
|
||||
|
||||
// Tell our clients about the technology
|
||||
Q_strncpy( m_szTechTreeFile.GetForModify(), STRING(m_iszTechTreeFile), sizeof(m_szTechTreeFile) );
|
||||
}
|
||||
|
||||
// Find the technology in the techtree
|
||||
CBaseTechnology *pTechnology = pTechTree->GetTechnology( STRING(m_iszTech) );
|
||||
// Now hook the technology up to me
|
||||
if ( pTechnology )
|
||||
{
|
||||
pTechnology->RegisterWatcher( this );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Update the amount of our technology that's owned
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoCustomTechnology::UpdateTechPercentage( float flPercentage )
|
||||
{
|
||||
m_flTechPercentage.Set( flPercentage, this, this );
|
||||
}
|
||||
43
game/server/tf2/info_customtech.h
Normal file
43
game/server/tf2/info_customtech.h
Normal file
@@ -0,0 +1,43 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef INFO_CUSTOMTECH_H
|
||||
#define INFO_CUSTOMTECH_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "entityoutput.h"
|
||||
#include "baseentity.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Map entity that adds a custom technology to the techtree
|
||||
//-----------------------------------------------------------------------------
|
||||
class CInfoCustomTechnology : public CPointEntity
|
||||
{
|
||||
DECLARE_CLASS( CInfoCustomTechnology, CPointEntity );
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Activate( void );
|
||||
void UpdateTechPercentage( float flPercentage );
|
||||
|
||||
virtual int UpdateTransmitState() { return SetTransmitState( FL_EDICT_FULLCHECK ); };
|
||||
virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo );
|
||||
|
||||
DECLARE_SERVERCLASS();
|
||||
DECLARE_DATADESC();
|
||||
|
||||
public:
|
||||
COutputFloat m_flTechPercentage; // Percentage of the tech that's owned
|
||||
string_t m_iszTech;
|
||||
string_t m_iszTechTreeFile;
|
||||
|
||||
// Sent via datatable
|
||||
CNetworkString( m_szTechTreeFile, 128 );
|
||||
};
|
||||
|
||||
#endif // INFO_CUSTOMTECH_H
|
||||
222
game/server/tf2/info_input_playsound.cpp
Normal file
222
game/server/tf2/info_input_playsound.cpp
Normal file
@@ -0,0 +1,222 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "EntityOutput.h"
|
||||
#include "EntityList.h"
|
||||
#include "tf_team.h"
|
||||
#include "baseentity.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "triggers.h"
|
||||
|
||||
// Spawnflags
|
||||
#define SF_PLAYSOUND_USE_THIS_ORIGIN 0x0001
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Map entity that plays sounds to players
|
||||
//-----------------------------------------------------------------------------
|
||||
class CInfoInputPlaySound : public CBaseEntity
|
||||
{
|
||||
DECLARE_CLASS( CInfoInputPlaySound, CBaseEntity );
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void Precache( void );
|
||||
virtual void Activate( void );
|
||||
|
||||
// Inputs
|
||||
void InputPlaySoundToAll( inputdata_t &inputdata );
|
||||
void InputPlaySoundToTeam1( inputdata_t &inputdata );
|
||||
void InputPlaySoundToTeam2( inputdata_t &inputdata );
|
||||
void InputPlaySoundToPlayer( inputdata_t &inputdata );
|
||||
void InputSetSound( inputdata_t &inputdata );
|
||||
|
||||
// Sound playing
|
||||
void PlaySoundToPlayer( CBaseTFPlayer *pPlayer );
|
||||
void PlaySoundToTeam( CTFTeam *pTeam );
|
||||
|
||||
private:
|
||||
string_t m_iszSound;
|
||||
float m_flVolume;
|
||||
float m_flAttenuation;
|
||||
string_t m_iszTestVolumeName;
|
||||
EHANDLE m_hTestVolume;
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CInfoInputPlaySound )
|
||||
|
||||
// variables
|
||||
DEFINE_KEYFIELD( m_iszSound, FIELD_SOUNDNAME, "Sound" ),
|
||||
DEFINE_KEYFIELD( m_flVolume, FIELD_FLOAT, "Volume" ),
|
||||
DEFINE_KEYFIELD( m_flAttenuation, FIELD_FLOAT, "Attenuation" ),
|
||||
DEFINE_KEYFIELD( m_iszTestVolumeName, FIELD_STRING, "TestVolume" ),
|
||||
|
||||
// inputs
|
||||
DEFINE_INPUTFUNC( FIELD_STRING, "SetSound", InputSetSound ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "PlaySoundToAll", InputPlaySoundToAll ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "PlaySoundToTeam1", InputPlaySoundToTeam1 ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "PlaySoundToTeam2", InputPlaySoundToTeam2 ),
|
||||
DEFINE_INPUTFUNC( FIELD_EHANDLE, "PlaySoundToPlayer", InputPlaySoundToPlayer ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( info_input_playsound, CInfoInputPlaySound );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputPlaySound::Spawn( void )
|
||||
{
|
||||
m_hTestVolume = NULL;
|
||||
Precache();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputPlaySound::Precache( void )
|
||||
{
|
||||
if ( m_iszSound != NULL_STRING )
|
||||
{
|
||||
PrecacheScriptSound( STRING(m_iszSound) );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputPlaySound::Activate( void )
|
||||
{
|
||||
BaseClass::Activate();
|
||||
|
||||
// Find our test volume, if we have one
|
||||
if ( m_iszTestVolumeName != NULL_STRING )
|
||||
{
|
||||
m_hTestVolume = gEntList.FindEntityByName( NULL, STRING(m_iszTestVolumeName) );
|
||||
if ( !m_hTestVolume )
|
||||
{
|
||||
Msg("ERROR: Could not find test volume %s for info_input_playsound.\n", STRING(m_iszTestVolumeName) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure it's a trigger
|
||||
CBaseTrigger *pTrigger = dynamic_cast<CBaseTrigger*>((CBaseEntity*)m_hTestVolume);
|
||||
if ( !pTrigger )
|
||||
{
|
||||
Msg("ERROR: info_input_playsound specifies a volume %s, but it's not a trigger.\n", STRING(m_iszTestVolumeName) );
|
||||
m_hTestVolume = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Play sound to all players
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputPlaySound::InputPlaySoundToAll( inputdata_t &inputdata )
|
||||
{
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( UTIL_PlayerByIndex(i) );
|
||||
if ( pPlayer )
|
||||
{
|
||||
PlaySoundToPlayer( pPlayer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Play sound to all players on team 1
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputPlaySound::InputPlaySoundToTeam1( inputdata_t &inputdata )
|
||||
{
|
||||
PlaySoundToTeam( GetGlobalTFTeam(1) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Play sound to all players on team 2
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputPlaySound::InputPlaySoundToTeam2( inputdata_t &inputdata )
|
||||
{
|
||||
PlaySoundToTeam( GetGlobalTFTeam(2) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Play sound to a specific player
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputPlaySound::InputPlaySoundToPlayer( inputdata_t &inputdata )
|
||||
{
|
||||
CBaseEntity *pEntity = (inputdata.value.Entity()).Get();
|
||||
if ( pEntity && pEntity->IsPlayer() )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)pEntity;
|
||||
PlaySoundToPlayer( pPlayer );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set the sound to play
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputPlaySound::InputSetSound( inputdata_t &inputdata )
|
||||
{
|
||||
m_iszSound = MAKE_STRING( inputdata.value.String() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Play sound to a team
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputPlaySound::PlaySoundToTeam( CTFTeam *pTeam )
|
||||
{
|
||||
for ( int i = 0; i < pTeam->GetNumPlayers(); i++ )
|
||||
{
|
||||
PlaySoundToPlayer( (CBaseTFPlayer*)pTeam->GetPlayer(i) );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Play sound to a player
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputPlaySound::PlaySoundToPlayer( CBaseTFPlayer *pPlayer )
|
||||
{
|
||||
// First, if we have a test volume, make sure the player's within it
|
||||
if ( m_hTestVolume )
|
||||
{
|
||||
CBaseTrigger *pTrigger = (CBaseTrigger *)(CBaseEntity*)m_hTestVolume;
|
||||
if ( !pTrigger->IsTouching( pPlayer ) )
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to see if we're supposed to play it from this entity's location
|
||||
if ( HasSpawnFlags( SF_PLAYSOUND_USE_THIS_ORIGIN ) )
|
||||
{
|
||||
CPASAttenuationFilter filter;
|
||||
filter.AddRecipient( pPlayer );
|
||||
filter.Filter( GetAbsOrigin(), m_flAttenuation );
|
||||
|
||||
EmitSound_t ep;
|
||||
ep.m_nChannel = CHAN_VOICE;
|
||||
ep.m_pSoundName = STRING(m_iszSound);
|
||||
ep.m_flVolume = m_flVolume;
|
||||
ep.m_SoundLevel = ATTN_TO_SNDLVL( m_flAttenuation );
|
||||
|
||||
ep.m_pOrigin = &(GetAbsOrigin());
|
||||
|
||||
EmitSound( filter, entindex(), ep );
|
||||
}
|
||||
else
|
||||
{
|
||||
CSingleUserRecipientFilter filter( pPlayer );
|
||||
|
||||
EmitSound_t ep;
|
||||
ep.m_nChannel = CHAN_VOICE;
|
||||
ep.m_pSoundName = STRING(m_iszSound);
|
||||
ep.m_flVolume = m_flVolume;
|
||||
ep.m_SoundLevel = ATTN_TO_SNDLVL( m_flAttenuation );
|
||||
|
||||
EmitSound( filter, pPlayer->entindex(), ep );
|
||||
}
|
||||
}
|
||||
124
game/server/tf2/info_input_resetbanks.cpp
Normal file
124
game/server/tf2/info_input_resetbanks.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "EntityOutput.h"
|
||||
#include "EntityList.h"
|
||||
#include "tf_team.h"
|
||||
#include "baseentity.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Map entity that resets player's banks
|
||||
//-----------------------------------------------------------------------------
|
||||
class CInfoInputResetBanks : public CBaseEntity
|
||||
{
|
||||
DECLARE_CLASS( CInfoInputResetBanks, CBaseEntity );
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
|
||||
// Inputs
|
||||
void InputResetAll( inputdata_t &inputdata );
|
||||
void InputResetTeam1( inputdata_t &inputdata );
|
||||
void InputResetTeam2( inputdata_t &inputdata );
|
||||
void InputResetPlayer( inputdata_t &inputdata );
|
||||
void InputSetResetAmount( inputdata_t &inputdata );
|
||||
|
||||
// Resetting
|
||||
void ResetPlayersBank( CBaseTFPlayer *pPlayer );
|
||||
void ResetTeamsBanks( CTFTeam *pTeam );
|
||||
|
||||
private:
|
||||
int m_iResetAmount;
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CInfoInputResetBanks )
|
||||
|
||||
// variables
|
||||
DEFINE_KEYFIELD( m_iResetAmount, FIELD_INTEGER, "ResetAmount" ),
|
||||
|
||||
// inputs
|
||||
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetResetAmount", InputSetResetAmount ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "ResetAll", InputResetAll ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "ResetTeam1", InputResetTeam1 ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "ResetTeam2", InputResetTeam2 ),
|
||||
DEFINE_INPUTFUNC( FIELD_EHANDLE, "ResetPlayer", InputResetPlayer ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( info_input_resetbanks, CInfoInputResetBanks );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reset all the player's resource banks
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputResetBanks::InputResetAll( inputdata_t &inputdata )
|
||||
{
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( UTIL_PlayerByIndex(i) );
|
||||
if ( pPlayer )
|
||||
{
|
||||
ResetPlayersBank( pPlayer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reset all of team 1's player's resource banks
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputResetBanks::InputResetTeam1( inputdata_t &inputdata )
|
||||
{
|
||||
ResetTeamsBanks( GetGlobalTFTeam(1) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reset all of team 2's player's resource banks
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputResetBanks::InputResetTeam2( inputdata_t &inputdata )
|
||||
{
|
||||
ResetTeamsBanks( GetGlobalTFTeam(2) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reset a specific player's resource banks
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputResetBanks::InputResetPlayer( inputdata_t &inputdata )
|
||||
{
|
||||
CBaseEntity *pEntity = (inputdata.value.Entity()).Get();
|
||||
if ( pEntity && pEntity->IsPlayer() )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)pEntity;
|
||||
ResetPlayersBank( pPlayer );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set the reset amount
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputResetBanks::InputSetResetAmount( inputdata_t &inputdata )
|
||||
{
|
||||
m_iResetAmount = inputdata.value.Int();
|
||||
Assert( m_iResetAmount >= 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reset the team's resource banks
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputResetBanks::ResetTeamsBanks( CTFTeam *pTeam )
|
||||
{
|
||||
pTeam->SetRecentBankSet( m_iResetAmount );
|
||||
for ( int i = 0; i < pTeam->GetNumPlayers(); i++ )
|
||||
{
|
||||
ResetPlayersBank( (CBaseTFPlayer*)pTeam->GetPlayer(i) );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reset the player's resource bank
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputResetBanks::ResetPlayersBank( CBaseTFPlayer *pPlayer )
|
||||
{
|
||||
pPlayer->SetBankResources( m_iResetAmount );
|
||||
}
|
||||
106
game/server/tf2/info_input_resetobjects.cpp
Normal file
106
game/server/tf2/info_input_resetobjects.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "EntityOutput.h"
|
||||
#include "EntityList.h"
|
||||
#include "tf_team.h"
|
||||
#include "baseentity.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Map entity that resets player's objects
|
||||
//-----------------------------------------------------------------------------
|
||||
class CInfoInputResetObjects : public CBaseEntity
|
||||
{
|
||||
DECLARE_CLASS( CInfoInputResetObjects, CBaseEntity );
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
|
||||
// Inputs
|
||||
void InputResetAll( inputdata_t &inputdata );
|
||||
void InputResetTeam1( inputdata_t &inputdata );
|
||||
void InputResetTeam2( inputdata_t &inputdata );
|
||||
void InputResetPlayer( inputdata_t &inputdata );
|
||||
|
||||
// Resetting
|
||||
void ResetPlayersObjects( CBaseTFPlayer *pPlayer );
|
||||
void ResetTeamsObjects( CTFTeam *pTeam );
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CInfoInputResetObjects )
|
||||
|
||||
// inputs
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "ResetAll", InputResetAll ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "ResetTeam1", InputResetTeam1 ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "ResetTeam2", InputResetTeam2 ),
|
||||
DEFINE_INPUTFUNC( FIELD_EHANDLE, "ResetPlayer", InputResetPlayer ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( info_input_resetobjects, CInfoInputResetObjects );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reset all the player's objects
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputResetObjects::InputResetAll( inputdata_t &inputdata )
|
||||
{
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( UTIL_PlayerByIndex(i) );
|
||||
if ( pPlayer )
|
||||
{
|
||||
ResetPlayersObjects( pPlayer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reset all of team 1's player's objects
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputResetObjects::InputResetTeam1( inputdata_t &inputdata )
|
||||
{
|
||||
ResetTeamsObjects( GetGlobalTFTeam(1) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reset all of team 2's player's objects
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputResetObjects::InputResetTeam2( inputdata_t &inputdata )
|
||||
{
|
||||
ResetTeamsObjects( GetGlobalTFTeam(2) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reset a specific player's objects
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputResetObjects::InputResetPlayer( inputdata_t &inputdata )
|
||||
{
|
||||
CBaseEntity *pEntity = (inputdata.value.Entity()).Get();
|
||||
if ( pEntity && pEntity->IsPlayer() )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)pEntity;
|
||||
ResetPlayersObjects( pPlayer );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reset the team's objects
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputResetObjects::ResetTeamsObjects( CTFTeam *pTeam )
|
||||
{
|
||||
for ( int i = 0; i < pTeam->GetNumPlayers(); i++ )
|
||||
{
|
||||
ResetPlayersObjects( (CBaseTFPlayer*)pTeam->GetPlayer(i) );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reset the player's objects
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputResetObjects::ResetPlayersObjects( CBaseTFPlayer *pPlayer )
|
||||
{
|
||||
pPlayer->RemoveAllObjects( true, 0, true );
|
||||
}
|
||||
121
game/server/tf2/info_input_respawnplayers.cpp
Normal file
121
game/server/tf2/info_input_respawnplayers.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "EntityOutput.h"
|
||||
#include "EntityList.h"
|
||||
#include "tf_team.h"
|
||||
#include "baseentity.h"
|
||||
|
||||
// Spawnflags
|
||||
const int SF_RESPAWNPLAYERS_RESETALL = 0x01; // Respawned players have their inventory completely reset
|
||||
const int SF_RESPAWNPLAYERS_RESETAMMO = 0x02; // Respawned players have their ammo counts reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Map entity that respawns players
|
||||
//-----------------------------------------------------------------------------
|
||||
class CInfoInputRespawnPlayers : public CBaseEntity
|
||||
{
|
||||
DECLARE_CLASS( CInfoInputRespawnPlayers, CBaseEntity );
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
|
||||
// Inputs
|
||||
void InputRespawnAll( inputdata_t &inputdata );
|
||||
void InputRespawnTeam1( inputdata_t &inputdata );
|
||||
void InputRespawnTeam2( inputdata_t &inputdata );
|
||||
void InputRespawnPlayer( inputdata_t &inputdata );
|
||||
|
||||
// Respawning
|
||||
void RespawnPlayer( CBaseTFPlayer *pPlayer );
|
||||
void RespawnTeam( CTFTeam *pTeam );
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CInfoInputRespawnPlayers )
|
||||
|
||||
// inputs
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "RespawnAll", InputRespawnAll ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "RespawnTeam1", InputRespawnTeam1 ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "RespawnTeam2", InputRespawnTeam2 ),
|
||||
DEFINE_INPUTFUNC( FIELD_EHANDLE, "RespawnPlayer", InputRespawnPlayer ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( info_input_respawnplayers, CInfoInputRespawnPlayers );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Respawn all the players
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputRespawnPlayers::InputRespawnAll( inputdata_t &inputdata )
|
||||
{
|
||||
for ( int i = 0; i < MAX_TF_TEAMS; i++ )
|
||||
{
|
||||
RespawnTeam( GetGlobalTFTeam(i+1) );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Respawn all of team 1's players
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputRespawnPlayers::InputRespawnTeam1( inputdata_t &inputdata )
|
||||
{
|
||||
RespawnTeam( GetGlobalTFTeam(1) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Respawn all of team 2's players
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputRespawnPlayers::InputRespawnTeam2( inputdata_t &inputdata )
|
||||
{
|
||||
RespawnTeam( GetGlobalTFTeam(2) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Respawn a specific player
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputRespawnPlayers::InputRespawnPlayer( inputdata_t &inputdata )
|
||||
{
|
||||
CBaseEntity *pEntity = (inputdata.value.Entity()).Get();
|
||||
if ( pEntity && pEntity->IsPlayer() )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)pEntity;
|
||||
RespawnPlayer( pPlayer );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Respawn the team
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputRespawnPlayers::RespawnTeam( CTFTeam *pTeam )
|
||||
{
|
||||
Assert( pTeam );
|
||||
if ( !pTeam )
|
||||
return;
|
||||
|
||||
// Respawn all the players
|
||||
for ( int i = 0; i < pTeam->GetNumPlayers(); i++ )
|
||||
{
|
||||
RespawnPlayer( (CBaseTFPlayer*)pTeam->GetPlayer(i) );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Respawn the player
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoInputRespawnPlayers::RespawnPlayer( CBaseTFPlayer *pPlayer )
|
||||
{
|
||||
// Reset ammo if the spawnflag's set
|
||||
if ( HasSpawnFlags( SF_RESPAWNPLAYERS_RESETALL ) )
|
||||
{
|
||||
pPlayer->ResupplyAmmo( 1.0, RESUPPLY_ALL_FROM_STATION );
|
||||
}
|
||||
else if ( HasSpawnFlags( SF_RESPAWNPLAYERS_RESETAMMO ) )
|
||||
{
|
||||
pPlayer->ResupplyAmmo( 1.0, RESUPPLY_RESPAWN );
|
||||
}
|
||||
|
||||
pPlayer->ForceRespawn();
|
||||
}
|
||||
116
game/server/tf2/info_minimappulse.cpp
Normal file
116
game/server/tf2/info_minimappulse.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "EntityOutput.h"
|
||||
#include "EntityList.h"
|
||||
#include "tf_team.h"
|
||||
#include "baseentity.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Map entity that makes a pulse on the minimap
|
||||
//-----------------------------------------------------------------------------
|
||||
class CInfoMinimapPulse : public CBaseEntity
|
||||
{
|
||||
DECLARE_CLASS( CInfoMinimapPulse, CBaseEntity );
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void Spawn( void );
|
||||
|
||||
// Inputs
|
||||
void InputPulseForAll( inputdata_t &inputdata );
|
||||
void InputPulseForTeam1( inputdata_t &inputdata );
|
||||
void InputPulseForTeam2( inputdata_t &inputdata );
|
||||
void InputPulseForPlayer( inputdata_t &inputdata );
|
||||
|
||||
// Pulsing
|
||||
void PulseForPlayer( CBaseTFPlayer *pPlayer );
|
||||
void PulseForTeam( CTFTeam *pTeam );
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CInfoMinimapPulse )
|
||||
|
||||
// inputs
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "PulseForAll", InputPulseForAll ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "PulseForTeam1", InputPulseForTeam1 ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "PulseForTeam2", InputPulseForTeam2 ),
|
||||
DEFINE_INPUTFUNC( FIELD_EHANDLE, "PulseForPlayer", InputPulseForPlayer ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( info_minimappulse, CInfoMinimapPulse );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoMinimapPulse::Spawn( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Pulse for all the players
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoMinimapPulse::InputPulseForAll( inputdata_t &inputdata )
|
||||
{
|
||||
for ( int i = 0; i < MAX_TF_TEAMS; i++ )
|
||||
{
|
||||
PulseForTeam( GetGlobalTFTeam(i) );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Pulse for all of team 1's players
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoMinimapPulse::InputPulseForTeam1( inputdata_t &inputdata )
|
||||
{
|
||||
PulseForTeam( GetGlobalTFTeam(1) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Pulse for all of team 2's players
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoMinimapPulse::InputPulseForTeam2( inputdata_t &inputdata )
|
||||
{
|
||||
PulseForTeam( GetGlobalTFTeam(2) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Pulse for a specific player
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoMinimapPulse::InputPulseForPlayer( inputdata_t &inputdata )
|
||||
{
|
||||
CBaseEntity *pEntity = (inputdata.value.Entity()).Get();
|
||||
if ( pEntity && pEntity->IsPlayer() )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)pEntity;
|
||||
PulseForPlayer( pPlayer );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Pulse for the team
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoMinimapPulse::PulseForTeam( CTFTeam *pTeam )
|
||||
{
|
||||
// Pulse all the players
|
||||
for ( int i = 0; i < pTeam->GetNumPlayers(); i++ )
|
||||
{
|
||||
PulseForPlayer( (CBaseTFPlayer*)pTeam->GetPlayer(i) );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Make a minimap pulse for the player
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoMinimapPulse::PulseForPlayer( CBaseTFPlayer *pPlayer )
|
||||
{
|
||||
CSingleUserRecipientFilter user( pPlayer );
|
||||
user.MakeReliable();
|
||||
UserMessageBegin( user, "MinimapPulse" );
|
||||
WRITE_VEC3COORD( GetAbsOrigin() );
|
||||
MessageEnd();
|
||||
}
|
||||
71
game/server/tf2/info_output_team.cpp
Normal file
71
game/server/tf2/info_output_team.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "EntityOutput.h"
|
||||
#include "EntityList.h"
|
||||
#include "tf_team.h"
|
||||
#include "baseentity.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Map entity that fires its output with all the players in a team
|
||||
//-----------------------------------------------------------------------------
|
||||
class CInfoOutputTeam : public CBaseEntity
|
||||
{
|
||||
DECLARE_CLASS( CInfoOutputTeam, CBaseEntity );
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void Spawn( void );
|
||||
|
||||
// Inputs
|
||||
void InputFire( inputdata_t &inputdata );
|
||||
|
||||
public:
|
||||
// Outputs
|
||||
COutputEHANDLE m_Player;
|
||||
};
|
||||
|
||||
BEGIN_DATADESC( CInfoOutputTeam )
|
||||
|
||||
// inputs
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "Fire", InputFire ),
|
||||
|
||||
// outputs
|
||||
DEFINE_OUTPUT( m_Player, "Player" ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( info_output_team, CInfoOutputTeam );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoOutputTeam::Spawn( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoOutputTeam::InputFire( inputdata_t &inputdata )
|
||||
{
|
||||
// Loop through all the players on the team and fire our output with each of them.
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( UTIL_PlayerByIndex(i) );
|
||||
if ( pPlayer )
|
||||
{
|
||||
// If we don't belong to a team, loop through all players
|
||||
if ( GetTeamNumber() == 0 || pPlayer->GetTeamNumber() == GetTeamNumber() )
|
||||
{
|
||||
EHANDLE hHandle;
|
||||
hHandle = pPlayer;
|
||||
m_Player.Set( hHandle, inputdata.pActivator, this );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
139
game/server/tf2/info_resourceprocessor.cpp
Normal file
139
game/server/tf2/info_resourceprocessor.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A team's resource processor back at their base
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "tf_team.h"
|
||||
#include "info_resourceprocessor.h"
|
||||
#include "tf_player.h"
|
||||
#include "npc_minicarrier.h"
|
||||
#include "tf_gamerules.h"
|
||||
|
||||
BEGIN_DATADESC( CResourceProcessor )
|
||||
|
||||
// functions
|
||||
DEFINE_FUNCTION( ProcessorTouch ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST(CResourceProcessor, DT_ResourceProcessor)
|
||||
END_SEND_TABLE()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( info_resourceprocessor, CResourceProcessor);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CResourceProcessor::Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
|
||||
SetSolid( SOLID_SLIDEBOX );
|
||||
SetMoveType( MOVETYPE_NONE );
|
||||
AddFlag( FL_NOTARGET );
|
||||
|
||||
UTIL_SetSize( pev, Vector(-32,-32,0), Vector(32,32, 128) );
|
||||
SetModel( "models/objects/obj_resourceprocessor.mdl" );
|
||||
SetTouch( ProcessorTouch );
|
||||
|
||||
m_flHackSpawnHeight = 256;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CResourceProcessor::Precache( void )
|
||||
{
|
||||
PrecacheModel( "models/objects/obj_resourceprocessor.mdl" );
|
||||
|
||||
UTIL_PrecacheOther( "npc_minicarrier" );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CResourceProcessor::Activate( void )
|
||||
{
|
||||
BaseClass::Activate();
|
||||
if ( GetTeamNumber() < 0 || GetTeamNumber() >= GetNumberOfTeams() )
|
||||
{
|
||||
Warning( "Warning, info_resourceprocessor with invalid Team Number set.\n" );
|
||||
UTIL_Remove( this );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CResourceProcessor::ProcessorTouch( CBaseEntity *pOther )
|
||||
{
|
||||
// Players
|
||||
if ( pOther->IsPlayer() )
|
||||
{
|
||||
// Ignore touches from enemy players
|
||||
if ( !InSameTeam( pOther ) )
|
||||
return;
|
||||
|
||||
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)pOther;
|
||||
|
||||
// Remove all the player's resources and add them to the team's stash
|
||||
for ( int i = 0; i < MAX_RESOURCE_TYPES; i++ )
|
||||
{
|
||||
int iCount = pPlayer->GetResourceChunkCount(i, false);
|
||||
if ( iCount )
|
||||
{
|
||||
pPlayer->RemoveResourceChunks( i, iCount, false );
|
||||
AddResources( i, iCount * CHUNK_RESOURCE_VALUE );
|
||||
}
|
||||
|
||||
// Now remove processed versions too
|
||||
iCount = pPlayer->GetResourceChunkCount(i, true);
|
||||
if ( iCount )
|
||||
{
|
||||
pPlayer->RemoveResourceChunks( i, iCount, true );
|
||||
AddResources( i, iCount * PROCESSED_CHUNK_RESOURCE_VALUE );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Add resources to the processor, and hence the team's bank
|
||||
//-----------------------------------------------------------------------------
|
||||
void CResourceProcessor::AddResources( int iResourceType, float flResources )
|
||||
{
|
||||
if ( !GetTeam() )
|
||||
return;
|
||||
|
||||
((CTFTeam *)GetTeam())->AddResources( iResourceType, flResources );
|
||||
((CTFTeam *)GetTeam())->ResourceLoadDeposited();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Spawn a minicarrier
|
||||
//-----------------------------------------------------------------------------
|
||||
void CResourceProcessor::SpawnMiniCarrier( void )
|
||||
{
|
||||
CNPC_MiniCarrier *pMiniCarrier = (CNPC_MiniCarrier*)CreateEntityByName( "npc_minicarrier" );
|
||||
pMiniCarrier->Spawn();
|
||||
pMiniCarrier->ChangeTeam( m_iTeamNumber );
|
||||
|
||||
// Find a clear spot near me & spawn in it
|
||||
if ( !EntityPlacementTest( pMiniCarrier, GetAbsOrigin() + Vector(0,0,m_flHackSpawnHeight),
|
||||
pMiniCarrier->GetAbsOrigin(), false ) )
|
||||
{
|
||||
Warning( "Failed to find empty space to spawn a minicarrier.\n" );
|
||||
( ( CTFTeam * )GetTeam() )->RemoveRobot( pMiniCarrier );
|
||||
UTIL_Remove( pMiniCarrier );
|
||||
return;
|
||||
}
|
||||
|
||||
m_flHackSpawnHeight += 64;
|
||||
|
||||
engine->SetOrigin( pMiniCarrier->pev, pMiniCarrier->GetOrigin() );
|
||||
pMiniCarrier->SetHomeProcessor( this );
|
||||
}
|
||||
270
game/server/tf2/info_vehicle_bay.cpp
Normal file
270
game/server/tf2/info_vehicle_bay.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "EntityOutput.h"
|
||||
#include "EntityList.h"
|
||||
#include "info_vehicle_bay.h"
|
||||
#include "tf_obj.h"
|
||||
#include "tf_player.h"
|
||||
#include "info_act.h"
|
||||
|
||||
extern ConVar tf_fastbuild;
|
||||
|
||||
BEGIN_DATADESC( CInfoVehicleBay )
|
||||
END_DATADESC()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( info_vehicle_bay, CInfoVehicleBay );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoVehicleBay::Spawn( void )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Vehicle bays have 1 build point
|
||||
//-----------------------------------------------------------------------------
|
||||
int CInfoVehicleBay::GetNumBuildPoints( void ) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if the specified object type can be built on this point
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CInfoVehicleBay::CanBuildObjectOnBuildPoint( int iPoint, int iObjectType )
|
||||
{
|
||||
ASSERT( iPoint <= GetNumBuildPoints() );
|
||||
|
||||
// Don't allow building if there's another vehicle in the way
|
||||
|
||||
|
||||
// Only vehicles can be built here
|
||||
return ( iObjectType >= OBJ_BATTERING_RAM );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CInfoVehicleBay::GetBuildPoint( int iPoint, Vector &vecOrigin, QAngle &vecAngles )
|
||||
{
|
||||
ASSERT( iPoint <= GetNumBuildPoints() );
|
||||
|
||||
vecOrigin = GetAbsOrigin();
|
||||
vecAngles = GetAbsAngles();
|
||||
return true;
|
||||
}
|
||||
|
||||
int CInfoVehicleBay::GetBuildPointAttachmentIndex( int iPoint ) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoVehicleBay::SetObjectOnBuildPoint( int iPoint, CBaseObject *pObject )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CInfoVehicleBay::GetNumObjectsOnMe( void )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseEntity *CInfoVehicleBay::GetFirstObjectOnMe( void )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseObject *CInfoVehicleBay::GetObjectOfTypeOnMe( int iObjectType )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CInfoVehicleBay::FindObjectOnBuildPoint( CBaseObject *pObject )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoVehicleBay::GetExitPoint( CBaseEntity *pPlayer, int iPoint, Vector *pAbsOrigin, QAngle *pAbsAngles )
|
||||
{
|
||||
Assert(0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CInfoVehicleBay::RemoveAllObjects( void )
|
||||
{
|
||||
}
|
||||
|
||||
//===================================================================================================================
|
||||
// Vehicle Bay VGui Screen
|
||||
//===================================================================================================================
|
||||
BEGIN_DATADESC( CVGuiScreenVehicleBay )
|
||||
// outputs
|
||||
DEFINE_OUTPUT( m_OnStartedBuild, "OnStartedBuild" ),
|
||||
DEFINE_OUTPUT( m_OnFinishedBuild, "OnFinishedBuild" ),
|
||||
DEFINE_OUTPUT( m_OnReadyToBuildAgain, "OnReadyToBuildAgain" ),
|
||||
|
||||
// functions
|
||||
DEFINE_FUNCTION( BayThink ),
|
||||
END_DATADESC()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( vgui_screen_vehicle_bay, CVGuiScreenVehicleBay );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVGuiScreenVehicleBay::Activate( void )
|
||||
{
|
||||
BaseClass::Activate();
|
||||
|
||||
// Make sure we have a buildpoint specified
|
||||
CBaseEntity *pBuildPoint = gEntList.FindEntityByName( NULL, m_target );
|
||||
if ( !pBuildPoint )
|
||||
{
|
||||
Msg("ERROR: vgui_screen_vehicle_bay with no buildpoint as its target.\n" );
|
||||
UTIL_Remove( this );
|
||||
return;
|
||||
}
|
||||
|
||||
Vector vecOrigin = pBuildPoint->GetAbsOrigin();
|
||||
QAngle vecAngles = pBuildPoint->GetAbsAngles();
|
||||
SetBuildPoint( vecOrigin, vecAngles );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVGuiScreenVehicleBay::SetBuildPoint( Vector &vecOrigin, QAngle &vecAngles )
|
||||
{
|
||||
m_vecBuildPointOrigin = vecOrigin;
|
||||
m_vecBuildPointAngles = vecAngles;
|
||||
m_bBayIsClear = false;
|
||||
|
||||
// Start checking to see when I'm clear again
|
||||
SetThink( BayThink );
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVGuiScreenVehicleBay::BuildVehicle( CBaseTFPlayer *pPlayer, int iObjectType )
|
||||
{
|
||||
if ( !IsObjectAVehicle(iObjectType) )
|
||||
return;
|
||||
Assert( m_vecBuildPointOrigin != vec3_origin );
|
||||
|
||||
// Can't build if the game hasn't started
|
||||
if ( !tf_fastbuild.GetInt() && CurrentActIsAWaitingAct() )
|
||||
{
|
||||
ClientPrint( pPlayer, HUD_PRINTCENTER, "Can't build until the game's started.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Try and spawn the object
|
||||
CBaseEntity *pEntity = CreateEntityByName( GetObjectInfo(iObjectType)->m_pClassName );
|
||||
if ( !pEntity )
|
||||
return;
|
||||
|
||||
if ( !m_bBayIsClear )
|
||||
{
|
||||
ClientPrint( pPlayer, HUD_PRINTCENTER, "Vehicle bay isn't clear.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
pEntity->SetAbsOrigin( m_vecBuildPointOrigin );
|
||||
pEntity->SetAbsAngles( m_vecBuildPointAngles );
|
||||
|
||||
CBaseObject *pObject = dynamic_cast<CBaseObject*>(pEntity);
|
||||
if ( pObject )
|
||||
pObject->AdjustInitialBuildAngles();
|
||||
|
||||
pEntity->Spawn();
|
||||
|
||||
// If it's an object, finish setting it up
|
||||
if ( !pObject )
|
||||
return;
|
||||
|
||||
pObject->StartPlacement( pPlayer );
|
||||
pObject->SetVehicleBay( this );
|
||||
|
||||
// StartBuilding will return false if the player couldn't afford the vehicle
|
||||
if ( !pObject->StartBuilding( pPlayer ) )
|
||||
return;
|
||||
|
||||
// Fire our started-building output
|
||||
m_OnStartedBuild.FireOutput( pPlayer, this );
|
||||
|
||||
m_bBayIsClear = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVGuiScreenVehicleBay::FinishedBuildVehicle( CBaseObject *pObject )
|
||||
{
|
||||
m_OnFinishedBuild.FireOutput( pObject->GetBuilder(), this );
|
||||
|
||||
// Start checking to see when I'm clear again
|
||||
SetThink( BayThink );
|
||||
SetNextThink( gpGlobals->curtime + 0.3 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Check to see if we're clear enough to allow another vehicle to be built here
|
||||
//-----------------------------------------------------------------------------
|
||||
void CVGuiScreenVehicleBay::BayThink( void )
|
||||
{
|
||||
// Get a list of entities around our buildpoint
|
||||
CBaseEntity *pListOfNearbyEntities[100];
|
||||
int iNumberOfNearbyEntities = UTIL_EntitiesInSphere( pListOfNearbyEntities, 100, m_vecBuildPointOrigin, 128, 0 );
|
||||
for ( int i = 0; i < iNumberOfNearbyEntities; i++ )
|
||||
{
|
||||
CBaseEntity *pEntity = pListOfNearbyEntities[i];
|
||||
if ( pEntity->IsSolid( ) )
|
||||
{
|
||||
// Ignore shields..
|
||||
if ( pEntity->GetCollisionGroup() == TFCOLLISION_GROUP_SHIELD )
|
||||
continue;
|
||||
// Ignore func brushes
|
||||
if ( pEntity->GetMoveType() == MOVETYPE_PUSH )
|
||||
continue;
|
||||
|
||||
//NDebugOverlay::EntityBounds( pEntity, 0,255,0,8, 0.1 );
|
||||
|
||||
// Check again soon
|
||||
SetNextThink( gpGlobals->curtime + 1 );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// We're clear
|
||||
m_bBayIsClear = true;
|
||||
SetThink( NULL );
|
||||
|
||||
m_OnReadyToBuildAgain.FireOutput( this, this );
|
||||
}
|
||||
72
game/server/tf2/info_vehicle_bay.h
Normal file
72
game/server/tf2/info_vehicle_bay.h
Normal file
@@ -0,0 +1,72 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef INFO_VEHICLE_BAY_H
|
||||
#define INFO_VEHICLE_BAY_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "ihasbuildpoints.h"
|
||||
#include "vguiscreen.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Entity that provides a place to build a vehicle
|
||||
//-----------------------------------------------------------------------------
|
||||
class CInfoVehicleBay : public CBaseEntity, public IHasBuildPoints
|
||||
{
|
||||
DECLARE_CLASS( CInfoVehicleBay, CBaseEntity );
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
|
||||
void Spawn( void );
|
||||
|
||||
// IHasBuildPoints
|
||||
public:
|
||||
virtual int GetNumBuildPoints( void ) const;
|
||||
virtual bool CanBuildObjectOnBuildPoint( int iPoint, int iObjectType );
|
||||
virtual bool GetBuildPoint( int iPoint, Vector &vecOrigin, QAngle &vecAngles );
|
||||
virtual int GetBuildPointAttachmentIndex( int iPoint ) const;
|
||||
virtual void SetObjectOnBuildPoint( int iPoint, CBaseObject *pObject );
|
||||
virtual int GetNumObjectsOnMe( void );
|
||||
virtual CBaseEntity *GetFirstObjectOnMe( void );
|
||||
virtual CBaseObject *GetObjectOfTypeOnMe( int iObjectType );
|
||||
virtual int FindObjectOnBuildPoint( CBaseObject *pObject );
|
||||
virtual void GetExitPoint( CBaseEntity *pPlayer, int iPoint, Vector *pAbsOrigin, QAngle *pAbsAngles );
|
||||
virtual void RemoveAllObjects( void );
|
||||
virtual float GetMaxSnapDistance( int iPoint ) { return 128; }
|
||||
virtual bool ShouldCheckForMovement( void ) { return false; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Vgui screen for vehicle buying
|
||||
//-----------------------------------------------------------------------------
|
||||
class CVGuiScreenVehicleBay : public CVGuiScreen
|
||||
{
|
||||
DECLARE_CLASS( CVGuiScreenVehicleBay, CVGuiScreen );
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
|
||||
virtual void Activate( void );
|
||||
|
||||
void BuildVehicle( CBaseTFPlayer *pPlayer, int iObjectType );
|
||||
void FinishedBuildVehicle( CBaseObject *pObject );
|
||||
void SetBuildPoint( Vector &vecOrigin, QAngle &vecAngles );
|
||||
|
||||
void BayThink( void );
|
||||
|
||||
private:
|
||||
bool m_bBayIsClear;
|
||||
Vector m_vecBuildPointOrigin;
|
||||
QAngle m_vecBuildPointAngles;
|
||||
|
||||
// Outputs
|
||||
COutputEvent m_OnStartedBuild;
|
||||
COutputEvent m_OnFinishedBuild;
|
||||
COutputEvent m_OnReadyToBuildAgain;
|
||||
};
|
||||
|
||||
#endif // INFO_VEHICLE_BAY_H
|
||||
115
game/server/tf2/mapdata_server.cpp
Normal file
115
game/server/tf2/mapdata_server.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "mapdata_shared.h"
|
||||
#include "sharedinterface.h"
|
||||
#include "baseentity.h"
|
||||
#include "world.h"
|
||||
#include "player.h"
|
||||
|
||||
class CMapData_Server : public IMapData
|
||||
{
|
||||
public:
|
||||
|
||||
// World data queries.
|
||||
void GetMapBounds( Vector &vecMins, Vector &vecMaxs );
|
||||
void GetMapOrigin( Vector &vecOrigin );
|
||||
void GetMapSize( Vector &vecSize );
|
||||
|
||||
// 3D Skybox data queries.
|
||||
void Get3DSkyboxOrigin( Vector &vecOrigin );
|
||||
float Get3DSkyboxScale( void );
|
||||
};
|
||||
|
||||
static CMapData_Server g_MapData;
|
||||
IMapData *g_pMapData = &g_MapData;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapData_Server::GetMapBounds( Vector &vecMins, Vector &vecMaxs )
|
||||
{
|
||||
CWorld *pWorld = static_cast<CWorld*>( GetWorldEntity() );
|
||||
if ( pWorld )
|
||||
{
|
||||
// Get the world bounds.
|
||||
pWorld->GetWorldBounds( vecMins, vecMaxs );
|
||||
|
||||
// Backward compatability...
|
||||
if ( ( vecMins.LengthSqr() == 0.0f ) && ( vecMaxs.LengthSqr() == 0.0f ) )
|
||||
{
|
||||
vecMins.Init( -6500.0f, -6500.0f, -6500.0f );
|
||||
vecMaxs.Init( 6500.0f, 6500.0f, 6500.0f );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert( 0 );
|
||||
vecMins.Init( 0.0f, 0.0f, 0.0f );
|
||||
vecMaxs.Init( 1.0f, 1.0f, 1.0f );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapData_Server::GetMapOrigin( Vector &vecOrigin )
|
||||
{
|
||||
Vector vecMins, vecMaxs;
|
||||
GetMapBounds( vecMins, vecMaxs );
|
||||
VectorAdd( vecMins, vecMaxs, vecOrigin );
|
||||
VectorMultiply( vecOrigin, 0.5f, vecOrigin );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapData_Server::GetMapSize( Vector &vecSize )
|
||||
{
|
||||
Vector vecMins, vecMaxs;
|
||||
GetMapBounds( vecMins, vecMaxs );
|
||||
VectorSubtract( vecMaxs, vecMins, vecSize );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMapData_Server::Get3DSkyboxOrigin( Vector &vecOrigin )
|
||||
{
|
||||
// NOTE: If the player hasn't been created yet -- this doesn't work!!!
|
||||
// We need to pass the data along in the map - requires a tool change.
|
||||
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
|
||||
if ( pPlayer )
|
||||
{
|
||||
CPlayerLocalData *pLocalData = &pPlayer->m_Local;
|
||||
VectorCopy( pLocalData->m_skybox3d.origin, vecOrigin );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Debugging!
|
||||
Assert( 0 );
|
||||
vecOrigin.Init();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
float CMapData_Server::Get3DSkyboxScale( void )
|
||||
{
|
||||
// NOTE: If the player hasn't been created yet -- this doesn't work!!!
|
||||
// We need to pass the data along in the map - requires a tool change.
|
||||
CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
|
||||
if ( pPlayer )
|
||||
{
|
||||
CPlayerLocalData *pLocalData = &pPlayer->m_Local;
|
||||
return pLocalData->m_skybox3d.scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Debugging!
|
||||
Assert( 0 );
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
262
game/server/tf2/menu_base.cpp
Normal file
262
game/server/tf2/menu_base.cpp
Normal file
@@ -0,0 +1,262 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Ugly menus for prototyping
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "player.h"
|
||||
#include "tf_player.h"
|
||||
#include "menu_base.h"
|
||||
#include "tf_team.h"
|
||||
#include "baseviewmodel.h"
|
||||
#include "tf_gamerules.h"
|
||||
#include "tf_class_infiltrator.h"
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// Global list of menus
|
||||
CMenu *gMenus[MENU_LAST];
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Initialize the Global Menu structure
|
||||
//-----------------------------------------------------------------------------
|
||||
void InitializeMenus( void )
|
||||
{
|
||||
gMenus[MENU_DEFAULT] = NULL;
|
||||
gMenus[MENU_TEAM] = new CMenuTeam();
|
||||
gMenus[MENU_CLASS] = new CMenuClass();
|
||||
}
|
||||
|
||||
void DestroyMenus( void )
|
||||
{
|
||||
delete gMenus[MENU_DEFAULT];
|
||||
delete gMenus[MENU_TEAM];
|
||||
delete gMenus[MENU_CLASS];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Base Menu Handling
|
||||
//-----------------------------------------------------------------------------
|
||||
CMenu::CMenu()
|
||||
{
|
||||
memset( m_szMenuString, 0, sizeof(m_szMenuString) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMenu::Display( CBaseTFPlayer *pViewer, int allowed, int display_time )
|
||||
{
|
||||
RecalculateMenu( pViewer );
|
||||
|
||||
// Only display if the menu's not identical to the one the player's already seeing
|
||||
if ( pViewer->m_MenuUpdateTime > gpGlobals->curtime )
|
||||
{
|
||||
if ( (allowed == pViewer->m_MenuSelectionBuffer) && FStrEq( m_szMenuString, pViewer->m_MenuStringBuffer) )
|
||||
return;
|
||||
}
|
||||
pViewer->m_MenuUpdateTime = gpGlobals->curtime + 10;
|
||||
pViewer->m_MenuSelectionBuffer = allowed;
|
||||
|
||||
const char *msg_portion = m_szMenuString;
|
||||
Q_strncpy( pViewer->m_MenuStringBuffer, m_szMenuString, MENU_STRING_BUFFER_SIZE );
|
||||
|
||||
CSingleUserRecipientFilter user( pViewer );
|
||||
user.MakeReliable();
|
||||
|
||||
while ( strlen(msg_portion) >= MENU_MSG_TEXTCHUNK_SIZE )
|
||||
{
|
||||
// split the string
|
||||
char sbuf[MENU_MSG_TEXTCHUNK_SIZE+1];
|
||||
Q_strncpy( sbuf, msg_portion, MENU_MSG_TEXTCHUNK_SIZE+1 );
|
||||
msg_portion += MENU_MSG_TEXTCHUNK_SIZE;
|
||||
|
||||
|
||||
// send the string portion
|
||||
UserMessageBegin( user, "ShowMenu" );
|
||||
WRITE_WORD( allowed );
|
||||
WRITE_CHAR( display_time ); // display time (-1 means unlimited)
|
||||
WRITE_BYTE( TRUE ); // there is more message to come
|
||||
WRITE_STRING( sbuf );
|
||||
MessageEnd();
|
||||
}
|
||||
|
||||
// send the remaining string
|
||||
UserMessageBegin( user, "ShowMenu" );
|
||||
WRITE_WORD( allowed );
|
||||
WRITE_CHAR( display_time ); // display time (-1 means unlimited)
|
||||
WRITE_BYTE( FALSE ); // there is no more message to come
|
||||
WRITE_STRING( (char*)msg_portion );
|
||||
MessageEnd();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMenu::RecalculateMenu( CBaseTFPlayer *pViewer )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CMenu::Input( CBaseTFPlayer *pViewer, int iInput )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Team Menu
|
||||
//-----------------------------------------------------------------------------
|
||||
CMenuTeam::CMenuTeam()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMenuTeam::RecalculateMenu( CBaseTFPlayer *pViewer )
|
||||
{
|
||||
Q_strncpy( m_szMenuString, "Pick a Team: \n\n\n->1. Humans\n\n->2. Aliens\n", sizeof(m_szMenuString) );
|
||||
|
||||
// Allow aborting if they have a class
|
||||
if ( pViewer->GetTeam() )
|
||||
{
|
||||
Q_strncat( m_szMenuString, "\n\n->9. Don't change team.\n", sizeof(m_szMenuString), COPY_ALL_CHARACTERS );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handle input for the Team menu
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CMenuTeam::Input( CBaseTFPlayer *pViewer, int iInput )
|
||||
{
|
||||
// Allow aborting if they have a team
|
||||
if ( pViewer->GetTeam() && iInput == 9 )
|
||||
{
|
||||
pViewer->MenuReset();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (iInput < 0 || iInput >= GetNumberOfTeams())
|
||||
return false;
|
||||
|
||||
// Ignore changeteam requests to their current team
|
||||
if ( pViewer->GetTeam() )
|
||||
{
|
||||
if ( iInput == pViewer->GetTeam()->GetTeamNumber() )
|
||||
{
|
||||
pViewer->MenuReset();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the player to the team and then bring up the Class Menu
|
||||
pViewer->ChangeTeam( iInput );
|
||||
|
||||
// Clear out the class
|
||||
if ( pViewer->GetPlayerClass() )
|
||||
{
|
||||
// Remove all the player's items
|
||||
pViewer->RemoveAllItems( false );
|
||||
pViewer->HideViewModels();
|
||||
pViewer->ClearPlayerClass();
|
||||
}
|
||||
|
||||
pViewer->ForceRespawn();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Class Menu
|
||||
//-----------------------------------------------------------------------------
|
||||
CMenuClass::CMenuClass()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMenuClass::RecalculateMenu( CBaseTFPlayer *pViewer )
|
||||
{
|
||||
if ( !pViewer->GetTeam() )
|
||||
return;
|
||||
|
||||
Q_snprintf( m_szMenuString,sizeof(m_szMenuString), "You are on Team %s\n\n\n\n\n\n\nPick your Class: \n\n\n", pViewer->GetTeam()->GetName() );
|
||||
|
||||
int iClassNum = 1;
|
||||
|
||||
// Check technology for each class
|
||||
for ( int i = 0; i < TFCLASS_CLASS_COUNT; i++ )
|
||||
{
|
||||
char sClass[256];
|
||||
|
||||
if ( !( pViewer->IsClassAvailable( (TFClass)i ) ) )
|
||||
continue;
|
||||
|
||||
int iNumber = pViewer->GetTFTeam()->GetNumOfClass( (TFClass)i );
|
||||
if ( !iNumber )
|
||||
{
|
||||
Q_snprintf( sClass, sizeof(sClass), "->%d. %s\n\n", iClassNum, GetTFClassInfo( i )->m_pClassName );
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_snprintf( sClass, sizeof(sClass), "->%d. %s (%d in your team)\n\n", iClassNum, GetTFClassInfo( i )->m_pClassName, iNumber );
|
||||
}
|
||||
|
||||
Q_strncat( m_szMenuString, sClass,sizeof(m_szMenuString), COPY_ALL_CHARACTERS );
|
||||
iClassNum++;
|
||||
}
|
||||
|
||||
// Allow aborting if they have a class
|
||||
if ( pViewer->GetPlayerClass() )
|
||||
{
|
||||
Q_strncat( m_szMenuString, "\n\n->9. Don't change class.\n", sizeof(m_szMenuString), COPY_ALL_CHARACTERS );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handle input for the Class menu
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CMenuClass::Input( CBaseTFPlayer *pViewer, int iInput )
|
||||
{
|
||||
int iClassNum = 0;
|
||||
|
||||
// Allow aborting if they have a class
|
||||
if ( pViewer->GetPlayerClass() && iInput == 9 )
|
||||
{
|
||||
pViewer->MenuReset();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the class number
|
||||
for ( int i = 1; iInput && i < TFCLASS_CLASS_COUNT; i++ )
|
||||
{
|
||||
if ( !( pViewer->IsClassAvailable( (TFClass)i ) ) )
|
||||
continue;
|
||||
iInput--;
|
||||
iClassNum = i;
|
||||
}
|
||||
|
||||
// Ignore changeclass requests to their current class
|
||||
if ( pViewer->GetPlayerClass() )
|
||||
{
|
||||
if ( (TFClass)iClassNum == pViewer->PlayerClass() )
|
||||
{
|
||||
pViewer->MenuReset();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !pViewer->IsClassAvailable( (TFClass)iClassNum ) )
|
||||
return false;
|
||||
|
||||
pViewer->ChangeClass( (TFClass)iClassNum );
|
||||
pViewer->m_pCurrentMenu = NULL;
|
||||
return true;
|
||||
}
|
||||
77
game/server/tf2/menu_base.h
Normal file
77
game/server/tf2/menu_base.h
Normal file
@@ -0,0 +1,77 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// $Log: $
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef MENU_BASE_H
|
||||
#define MENU_BASE_H
|
||||
#pragma once
|
||||
|
||||
class CBasePlayer;
|
||||
class CMenu;
|
||||
|
||||
enum
|
||||
{
|
||||
MENU_DEFAULT = 0,
|
||||
MENU_TEAM,
|
||||
MENU_CLASS,
|
||||
|
||||
// Insert new Menus here
|
||||
MENU_LAST, // Total Number of menus
|
||||
};
|
||||
|
||||
// Global list of menus
|
||||
extern CMenu *gMenus[];
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Base Menu Class
|
||||
//-----------------------------------------------------------------------------
|
||||
class CMenu
|
||||
{
|
||||
public:
|
||||
CMenu();
|
||||
|
||||
virtual void RecalculateMenu( CBaseTFPlayer *pViewer );
|
||||
virtual void Display( CBaseTFPlayer *pViewer, int allowed = 0xFFFF, int display_time = -1 );
|
||||
virtual bool Input( CBaseTFPlayer *pViewer, int iInput );
|
||||
|
||||
protected:
|
||||
char m_szMenuString[1024];
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Team Menu
|
||||
//-----------------------------------------------------------------------------
|
||||
class CMenuTeam : public CMenu
|
||||
{
|
||||
public:
|
||||
CMenuTeam();
|
||||
|
||||
virtual void RecalculateMenu( CBaseTFPlayer *pViewer );
|
||||
virtual bool Input( CBaseTFPlayer *pViewer, int iInput );
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Class Menu
|
||||
//-----------------------------------------------------------------------------
|
||||
class CMenuClass : public CMenu
|
||||
{
|
||||
public:
|
||||
CMenuClass();
|
||||
|
||||
virtual void RecalculateMenu( CBaseTFPlayer *pViewer );
|
||||
virtual bool Input( CBaseTFPlayer *pViewer, int iInput );
|
||||
};
|
||||
|
||||
|
||||
#endif // MENU_BASE_H
|
||||
257
game/server/tf2/mortar_round.cpp
Normal file
257
game/server/tf2/mortar_round.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "mortar_round.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "tf_gamerules.h"
|
||||
#include "tf_team.h"
|
||||
|
||||
|
||||
|
||||
// Damage CVars
|
||||
ConVar weapon_mortar_shell_damage( "weapon_mortar_shell_damage","0", FCVAR_NONE, "Mortar's standard shell maximum damage" );
|
||||
ConVar weapon_mortar_shell_radius( "weapon_mortar_shell_radius","0", FCVAR_NONE, "Mortar's standard shell splash radius" );
|
||||
ConVar weapon_mortar_starburst_damage( "weapon_mortar_starburst_damage","0", FCVAR_NONE, "Mortar's starburst maximum damage" );
|
||||
ConVar weapon_mortar_starburst_radius( "weapon_mortar_starburst_radius","0", FCVAR_NONE, "Mortar's starburst splash radius" );
|
||||
ConVar weapon_mortar_cluster_shells( "weapon_mortar_cluster_shells","0", FCVAR_NONE, "Number of shells a mortar cluster round bursts into" );
|
||||
|
||||
//=====================================================================================================
|
||||
// MORTAR ROUND
|
||||
//=====================================================================================================
|
||||
BEGIN_DATADESC( CMortarRound )
|
||||
|
||||
// Function Pointers
|
||||
DEFINE_FUNCTION( MissileTouch ),
|
||||
DEFINE_FUNCTION( FallThink ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( mortar_round, CMortarRound );
|
||||
PRECACHE_WEAPON_REGISTER(mortar_round);
|
||||
|
||||
CMortarRound::CMortarRound()
|
||||
{
|
||||
m_pSmokeTrail = NULL;
|
||||
m_pLauncher = NULL;
|
||||
m_iRoundType = MA_SHELL;
|
||||
UseClientSideAnimation();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMortarRound::Precache( void )
|
||||
{
|
||||
PrecacheModel( "models/weapons/w_grenade.mdl" );
|
||||
|
||||
PrecacheScriptSound( "MortarRound.StopSound" );
|
||||
PrecacheScriptSound( "MortarRound.IncomingSound" );
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMortarRound::Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
|
||||
SetMoveType( MOVETYPE_FLYGRAVITY );
|
||||
SetSolid( SOLID_BBOX );
|
||||
SetModel( "models/weapons/w_grenade.mdl" );
|
||||
UTIL_SetSize( this, vec3_origin, vec3_origin );
|
||||
|
||||
SetTouch( MissileTouch );
|
||||
SetCollisionGroup( TFCOLLISION_GROUP_WEAPON );
|
||||
|
||||
// Trail smoke
|
||||
m_pSmokeTrail = SmokeTrail::CreateSmokeTrail();
|
||||
if ( m_pSmokeTrail )
|
||||
{
|
||||
m_pSmokeTrail->m_SpawnRate = 90;
|
||||
m_pSmokeTrail->m_ParticleLifetime = 1.5;
|
||||
m_pSmokeTrail->m_StartColor.Init(0.0, 0.0, 0.0);
|
||||
m_pSmokeTrail->m_EndColor.Init( 0.5,0.5,0.5 );
|
||||
m_pSmokeTrail->m_StartSize = 10;
|
||||
m_pSmokeTrail->m_EndSize = 50;
|
||||
m_pSmokeTrail->m_SpawnRadius = 1;
|
||||
m_pSmokeTrail->m_MinSpeed = 15;
|
||||
m_pSmokeTrail->m_MaxSpeed = 25;
|
||||
m_pSmokeTrail->SetLifetime(15);
|
||||
m_pSmokeTrail->FollowEntity( this );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMortarRound::MissileTouch( CBaseEntity *pOther )
|
||||
{
|
||||
CMortarRound *pRound = dynamic_cast< CMortarRound* >(pOther);
|
||||
if ( pRound )
|
||||
return;
|
||||
|
||||
// Stop emitting smoke/sound
|
||||
m_pSmokeTrail->SetEmit(false);
|
||||
EmitSound( "MortarRound.StopSound" );
|
||||
|
||||
// Create an explosion.
|
||||
if ( m_iRoundType == MA_STARBURST )
|
||||
{
|
||||
// Small explosion, blind people in the area
|
||||
float flBlind = 0;
|
||||
|
||||
// Shift it up a bit for the explosion
|
||||
SetLocalOrigin( GetAbsOrigin() + Vector(0,0,32) );
|
||||
CPASFilter filter( GetAbsOrigin() );
|
||||
te->Explosion( filter, 0.0, &GetAbsOrigin(), g_sModelIndexFireball, 3.0, 15, TE_EXPLFLAG_NONE, 512, 100 );
|
||||
RadiusDamage( CTakeDamageInfo( this, GetOwnerEntity(), weapon_mortar_starburst_damage.GetFloat(), DMG_BLAST ), GetAbsOrigin(), weapon_mortar_starburst_radius.GetFloat(), CLASS_NONE, NULL );
|
||||
|
||||
// Blind all players nearby
|
||||
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( UTIL_PlayerByIndex(i) );
|
||||
if ( pPlayer )
|
||||
{
|
||||
Vector vecSrc = pPlayer->EyePosition();
|
||||
Vector vecToTarget = (vecSrc - GetAbsOrigin());
|
||||
float flLength = VectorNormalize( vecToTarget );
|
||||
// If the player's looking at the grenade, blind him a lot
|
||||
if ( flLength < 2048 )
|
||||
{
|
||||
Vector forward, right, up;
|
||||
AngleVectors( pPlayer->pl.v_angle, &forward, &right, &up );
|
||||
float flDot = DotProduct( vecToTarget, forward );
|
||||
|
||||
// Msg( "Dot: %f\n", flDot );
|
||||
|
||||
// Make sure it's in front of the player
|
||||
if ( flDot < 0.0f )
|
||||
{
|
||||
flDot = fabs( DotProduct(vecToTarget, right ) ) + fabs( DotProduct(vecToTarget, up ) );
|
||||
|
||||
// Open LOS?
|
||||
trace_t tr;
|
||||
UTIL_TraceLine( vecSrc, GetAbsOrigin(), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
|
||||
if ( ( tr.fraction == 1.0f ) || ( tr.m_pEnt == pPlayer ) )
|
||||
{
|
||||
flBlind = flDot;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Blocked blind is only half as effective
|
||||
flBlind = flDot * 0.5;
|
||||
}
|
||||
}
|
||||
else if ( flLength < 512 )
|
||||
{
|
||||
// Otherwise, if the player's near the grenade blind him a little
|
||||
flBlind = 0.2;
|
||||
}
|
||||
|
||||
|
||||
// Flash the screen red
|
||||
color32 white = {255,255,255, 255};
|
||||
white.a = MIN( (flBlind * 255), 255 );
|
||||
UTIL_ScreenFade( pPlayer, white, 0.3, 5.0, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UTIL_Remove( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Large explosion
|
||||
|
||||
// Shift it up a bit for the explosion
|
||||
SetLocalOrigin( GetAbsOrigin() + Vector(0,0,64) );
|
||||
CPASFilter filter( GetAbsOrigin() );
|
||||
te->Explosion( filter, 0.0, &GetAbsOrigin(), g_sModelIndexFireball, 10.0, 15, TE_EXPLFLAG_NONE, 512, 300 );
|
||||
RadiusDamage( CTakeDamageInfo( this, GetOwnerEntity(), weapon_mortar_shell_damage.GetFloat(), DMG_BLAST ), GetAbsOrigin(), weapon_mortar_shell_radius.GetFloat(), CLASS_NONE, NULL );
|
||||
UTIL_Remove( this );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Play a fall sound when the mortar round begins to fall
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMortarRound::FallThink( void )
|
||||
{
|
||||
if ( m_pLauncher )
|
||||
{
|
||||
CRecipientFilter filter;
|
||||
filter.AddAllPlayers();
|
||||
EmitSound( filter, entindex(), "MortarRound.IncomingSound" );
|
||||
|
||||
// Cluster bombs split up in the air
|
||||
if ( m_iRoundType == MA_CLUSTER )
|
||||
{
|
||||
Vector forward, right;
|
||||
QAngle angles;
|
||||
VectorAngles( GetAbsVelocity(), angles );
|
||||
SetLocalAngles( angles );
|
||||
AngleVectors( GetLocalAngles(), &forward, &right, NULL );
|
||||
for ( int i = 0; i < weapon_mortar_cluster_shells.GetInt(); i++ )
|
||||
{
|
||||
Vector vecVelocity = GetAbsVelocity();
|
||||
vecVelocity += forward * random->RandomFloat( -200, 200 );
|
||||
vecVelocity += right * random->RandomFloat( -200, 200 );
|
||||
|
||||
CMortarRound *pRound = CMortarRound::Create( GetAbsOrigin(), vecVelocity, GetOwnerEntity() ? GetOwnerEntity()->edict() : NULL );
|
||||
pRound->SetLauncher( m_pLauncher );
|
||||
pRound->ChangeTeam( GetTeamNumber() );
|
||||
pRound->m_iRoundType = MA_SHELL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Keep a pointer to the Launcher
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMortarRound::SetLauncher( CVehicleMortar *pLauncher )
|
||||
{
|
||||
m_pLauncher = pLauncher;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set the point at which we should start playing the fall sound
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMortarRound::SetFallTime( float flFallTime )
|
||||
{
|
||||
SetThink( FallThink );
|
||||
SetNextThink( gpGlobals->curtime + flFallTime );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set the round's type
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMortarRound::SetRoundType( int iRoundType )
|
||||
{
|
||||
m_iRoundType = iRoundType;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Create a missile
|
||||
//-----------------------------------------------------------------------------
|
||||
CMortarRound* CMortarRound::Create( const Vector &vecOrigin, const Vector &vecVelocity, edict_t *pentOwner = NULL )
|
||||
{
|
||||
CMortarRound *pGrenade = (CMortarRound*)CreateEntityByName("mortar_round");
|
||||
|
||||
UTIL_SetOrigin( pGrenade, vecOrigin );
|
||||
pGrenade->SetOwnerEntity( Instance( pentOwner ) );
|
||||
pGrenade->Spawn();
|
||||
pGrenade->SetAbsVelocity( vecVelocity );
|
||||
QAngle angles;
|
||||
VectorAngles( vecVelocity, angles );
|
||||
pGrenade->SetLocalAngles( angles );
|
||||
|
||||
return pGrenade;
|
||||
}
|
||||
|
||||
48
game/server/tf2/mortar_round.h
Normal file
48
game/server/tf2/mortar_round.h
Normal file
@@ -0,0 +1,48 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef MORTAR_ROUND_H
|
||||
#define MORTAR_ROUND_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "tf_vehicle_mortar.h"
|
||||
#include "smoke_trail.h"
|
||||
|
||||
|
||||
class CMortarRound : public CBaseAnimating
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CMortarRound, CBaseAnimating );
|
||||
|
||||
CMortarRound();
|
||||
|
||||
DECLARE_DATADESC();
|
||||
|
||||
public:
|
||||
virtual void Spawn( void );
|
||||
virtual void Precache( void );
|
||||
virtual void MissileTouch( CBaseEntity *pOther );
|
||||
virtual void FallThink( void );
|
||||
virtual void SetLauncher( CVehicleMortar *pLauncher );
|
||||
virtual void SetFallTime( float flFallTime );
|
||||
virtual void SetRoundType( int iRoundType );
|
||||
|
||||
// Damage type accessors
|
||||
virtual int GetDamageType() const { return DMG_BLAST; }
|
||||
|
||||
static CMortarRound* CMortarRound::Create( const Vector &vecOrigin, const Vector &vecVelocity, edict_t *pentOwner );
|
||||
|
||||
SmokeTrail *m_pSmokeTrail;
|
||||
CHandle<CVehicleMortar> m_pLauncher;
|
||||
int m_iRoundType;
|
||||
};
|
||||
|
||||
|
||||
#endif // MORTAR_ROUND_H
|
||||
577
game/server/tf2/npc_bug_builder.cpp
Normal file
577
game/server/tf2/npc_bug_builder.cpp
Normal file
@@ -0,0 +1,577 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: The builder bug
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "AI_Task.h"
|
||||
#include "AI_Default.h"
|
||||
#include "AI_Schedule.h"
|
||||
#include "AI_Hull.h"
|
||||
#include "AI_Hint.h"
|
||||
#include "AI_Navigator.h"
|
||||
#include "activitylist.h"
|
||||
#include "soundent.h"
|
||||
#include "game.h"
|
||||
#include "NPCEvent.h"
|
||||
#include "tf_player.h"
|
||||
#include "EntityList.h"
|
||||
#include "ndebugoverlay.h"
|
||||
#include "shake.h"
|
||||
#include "monstermaker.h"
|
||||
#include "decals.h"
|
||||
#include "vstdlib/random.h"
|
||||
#include "tf_obj.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "IEffects.h"
|
||||
#include "npc_bug_builder.h"
|
||||
#include "npc_bug_hole.h"
|
||||
|
||||
ConVar npc_bug_builder_health( "npc_bug_builder_health", "100" );
|
||||
|
||||
BEGIN_DATADESC( CNPC_Bug_Builder )
|
||||
|
||||
DEFINE_FIELD( m_flIdleDelay, FIELD_FLOAT ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( npc_bug_builder, CNPC_Bug_Builder );
|
||||
IMPLEMENT_CUSTOM_AI( npc_bug_builder, CNPC_Bug_Builder );
|
||||
|
||||
// Dawdling details
|
||||
// Max & Min distances for dawdle forward movement
|
||||
#define DAWDLE_MIN_DIST 64
|
||||
#define DAWDLE_MAX_DIST 1024
|
||||
|
||||
//==================================================
|
||||
// Bug Conditions
|
||||
//==================================================
|
||||
enum BugConditions
|
||||
{
|
||||
COND_BBUG_RETURN_TO_BUGHOLE = LAST_SHARED_CONDITION,
|
||||
};
|
||||
|
||||
//==================================================
|
||||
// Bug Schedules
|
||||
//==================================================
|
||||
|
||||
enum BugSchedules
|
||||
{
|
||||
SCHED_BBUG_FLEE_ENEMY = LAST_SHARED_SCHEDULE,
|
||||
SCHED_BBUG_RETURN_TO_BUGHOLE,
|
||||
SCHED_BBUG_RETURN_TO_BUGHOLE_AND_REMOVE,
|
||||
SCHED_BBUG_DAWDLE,
|
||||
};
|
||||
|
||||
//==================================================
|
||||
// Bug Tasks
|
||||
//==================================================
|
||||
|
||||
enum BugTasks
|
||||
{
|
||||
TASK_BBUG_GET_PATH_TO_FLEE = LAST_SHARED_TASK,
|
||||
TASK_BBUG_GET_PATH_TO_BUGHOLE,
|
||||
TASK_BBUG_HOLE_REMOVE,
|
||||
TASK_BBUG_GET_PATH_TO_DAWDLE,
|
||||
TASK_BBUG_FACE_DAWDLE,
|
||||
};
|
||||
|
||||
//==================================================
|
||||
// Bug Activities
|
||||
//==================================================
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CNPC_Bug_Builder::CNPC_Bug_Builder( void )
|
||||
{
|
||||
m_flFieldOfView = 0.5f;
|
||||
m_flIdleDelay = 0.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Setup our schedules and tasks, etc.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bug_Builder::InitCustomSchedules( void )
|
||||
{
|
||||
INIT_CUSTOM_AI( CNPC_Bug_Builder );
|
||||
|
||||
// Schedules
|
||||
ADD_CUSTOM_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_FLEE_ENEMY );
|
||||
ADD_CUSTOM_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_RETURN_TO_BUGHOLE );
|
||||
ADD_CUSTOM_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_RETURN_TO_BUGHOLE_AND_REMOVE );
|
||||
ADD_CUSTOM_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_DAWDLE );
|
||||
|
||||
// Conditions
|
||||
ADD_CUSTOM_CONDITION( CNPC_Bug_Builder, COND_BBUG_RETURN_TO_BUGHOLE );
|
||||
|
||||
// Tasks
|
||||
ADD_CUSTOM_TASK( CNPC_Bug_Builder, TASK_BBUG_GET_PATH_TO_FLEE );
|
||||
ADD_CUSTOM_TASK( CNPC_Bug_Builder, TASK_BBUG_GET_PATH_TO_BUGHOLE );
|
||||
ADD_CUSTOM_TASK( CNPC_Bug_Builder, TASK_BBUG_HOLE_REMOVE );
|
||||
ADD_CUSTOM_TASK( CNPC_Bug_Builder, TASK_BBUG_GET_PATH_TO_DAWDLE );
|
||||
ADD_CUSTOM_TASK( CNPC_Bug_Builder, TASK_BBUG_FACE_DAWDLE );
|
||||
|
||||
// Activities
|
||||
//ADD_CUSTOM_ACTIVITY( CNPC_Bug_Builder, ACT_BUG_WARRIOR_DISTRACT );
|
||||
|
||||
AI_LOAD_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_FLEE_ENEMY );
|
||||
AI_LOAD_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_RETURN_TO_BUGHOLE );
|
||||
AI_LOAD_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_RETURN_TO_BUGHOLE_AND_REMOVE );
|
||||
AI_LOAD_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_DAWDLE );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bug_Builder::Spawn( void )
|
||||
{
|
||||
Precache();
|
||||
|
||||
SetModel( BUG_BUILDER_MODEL );
|
||||
|
||||
SetHullType(HULL_TINY);
|
||||
SetHullSizeNormal();
|
||||
SetDefaultEyeOffset();
|
||||
SetViewOffset( (WorldAlignMins() + WorldAlignMaxs()) * 0.5 ); // See from my center
|
||||
SetDistLook( 1024.0 );
|
||||
m_flNextDawdle = 0;
|
||||
|
||||
SetNavType(NAV_GROUND);
|
||||
m_NPCState = NPC_STATE_NONE;
|
||||
SetBloodColor( BLOOD_COLOR_YELLOW );
|
||||
m_iHealth = npc_bug_builder_health.GetFloat();
|
||||
|
||||
SetSolid( SOLID_BBOX );
|
||||
AddSolidFlags( FSOLID_NOT_STANDABLE );
|
||||
SetMoveType( MOVETYPE_STEP );
|
||||
|
||||
CapabilitiesAdd( bits_CAP_MOVE_GROUND );
|
||||
|
||||
NPCInit();
|
||||
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bug_Builder::Precache( void )
|
||||
{
|
||||
PrecacheModel( BUG_BUILDER_MODEL );
|
||||
|
||||
PrecacheScriptSound( "NPC_Bug_Builder.Idle" );
|
||||
PrecacheScriptSound( "NPC_Bug_Builder.Pain" );
|
||||
|
||||
BaseClass::Precache();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int CNPC_Bug_Builder::SelectSchedule( void )
|
||||
{
|
||||
// If I'm not in idle anymore, don't idle
|
||||
if ( m_NPCState != NPC_STATE_IDLE )
|
||||
{
|
||||
m_flNextDawdle = 0;
|
||||
}
|
||||
|
||||
switch ( m_NPCState )
|
||||
{
|
||||
case NPC_STATE_IDLE:
|
||||
{
|
||||
// BugHole might be requesting help
|
||||
if ( HasCondition( COND_BBUG_RETURN_TO_BUGHOLE ) )
|
||||
return SCHED_BBUG_RETURN_TO_BUGHOLE;
|
||||
|
||||
// Setup to dawdle a bit from now
|
||||
if ( !m_flNextDawdle )
|
||||
{
|
||||
m_flNextDawdle = gpGlobals->curtime + random->RandomFloat( 3.0, 5.0 );
|
||||
}
|
||||
else if ( m_flNextDawdle < gpGlobals->curtime )
|
||||
{
|
||||
m_flNextDawdle = 0;
|
||||
return SCHED_BBUG_DAWDLE;
|
||||
}
|
||||
|
||||
// When I take damage, I flee
|
||||
if ( HasCondition( COND_LIGHT_DAMAGE | COND_HEAVY_DAMAGE ) )
|
||||
return SCHED_BBUG_FLEE_ENEMY;
|
||||
|
||||
// Return to my bughole
|
||||
//return SCHED_BBUG_RETURN_TO_BUGHOLE_AND_REMOVE;
|
||||
break;
|
||||
}
|
||||
case NPC_STATE_ALERT:
|
||||
{
|
||||
// BugHole might be requesting help
|
||||
if ( HasCondition( COND_BBUG_RETURN_TO_BUGHOLE ) )
|
||||
return SCHED_BBUG_RETURN_TO_BUGHOLE;
|
||||
|
||||
// When I take damage, I flee
|
||||
if ( HasCondition( COND_LIGHT_DAMAGE ) || HasCondition( COND_HEAVY_DAMAGE ) )
|
||||
return SCHED_BBUG_FLEE_ENEMY;
|
||||
|
||||
break;
|
||||
}
|
||||
case NPC_STATE_COMBAT:
|
||||
{
|
||||
// Did I lose my enemy?
|
||||
if ( HasCondition ( COND_LOST_ENEMY ) || HasCondition ( COND_ENEMY_UNREACHABLE ) )
|
||||
{
|
||||
SetEnemy( NULL );
|
||||
SetState(NPC_STATE_IDLE);
|
||||
return BaseClass::SelectSchedule();
|
||||
}
|
||||
|
||||
// When I take damage, I flee
|
||||
if ( HasCondition( COND_LIGHT_DAMAGE ) || HasCondition( COND_HEAVY_DAMAGE ) )
|
||||
return SCHED_BBUG_FLEE_ENEMY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return BaseClass::SelectSchedule();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pTask -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bug_Builder::StartTask( const Task_t *pTask )
|
||||
{
|
||||
switch ( pTask->iTask )
|
||||
{
|
||||
case TASK_BBUG_GET_PATH_TO_FLEE:
|
||||
{
|
||||
// Always tell our bughole that we're under attack
|
||||
if ( m_hMyBugHole )
|
||||
{
|
||||
m_hMyBugHole->IncomingFleeingBug( this );
|
||||
}
|
||||
|
||||
// If we have no squad, or we couldn't get a path to our squadmate, move to our bughole
|
||||
if ( m_hMyBugHole )
|
||||
{
|
||||
SetTarget( m_hMyBugHole );
|
||||
AI_NavGoal_t goal( GOALTYPE_TARGETENT, vec3_origin, ACT_RUN );
|
||||
if ( GetNavigator()->SetGoal( goal ) )
|
||||
{
|
||||
TaskComplete();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TaskComplete();
|
||||
}
|
||||
break;
|
||||
|
||||
case TASK_BBUG_GET_PATH_TO_BUGHOLE:
|
||||
{
|
||||
// Get a path back to my bughole
|
||||
// If we have no squad, or we couldn't get a path to our squadmate, look for a bughole
|
||||
if ( m_hMyBugHole )
|
||||
{
|
||||
SetTarget( m_hMyBugHole );
|
||||
AI_NavGoal_t goal( GOALTYPE_TARGETENT, vec3_origin, ACT_RUN );
|
||||
if ( GetNavigator()->SetGoal( goal ) )
|
||||
{
|
||||
TaskComplete();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TaskFail( "Couldn't get to bughole." );
|
||||
}
|
||||
break;
|
||||
|
||||
case TASK_BBUG_HOLE_REMOVE:
|
||||
{
|
||||
TaskComplete();
|
||||
|
||||
// Crawl inside the bughole and remove myself
|
||||
AddEffects( EF_NODRAW );
|
||||
AddSolidFlags( FSOLID_NOT_SOLID );
|
||||
Event_Killed( CTakeDamageInfo( this, this, 200, DMG_CRUSH ) );
|
||||
|
||||
// Tell the bughole
|
||||
if ( m_hMyBugHole )
|
||||
{
|
||||
m_hMyBugHole->BugReturned();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TASK_BBUG_GET_PATH_TO_DAWDLE:
|
||||
{
|
||||
// Get a dawdle point ahead of us
|
||||
Vector vecForward, vecTarget;
|
||||
AngleVectors( GetAbsAngles(), &vecForward );
|
||||
VectorMA( GetAbsOrigin(), random->RandomFloat( DAWDLE_MIN_DIST, DAWDLE_MAX_DIST ), vecForward, vecTarget );
|
||||
|
||||
// See how far we could move ahead
|
||||
trace_t tr;
|
||||
UTIL_TraceEntity( this, GetAbsOrigin(), vecTarget, MASK_SOLID, &tr);
|
||||
float flDistance = tr.fraction * (vecTarget - GetAbsOrigin()).Length();
|
||||
if ( flDistance >= DAWDLE_MIN_DIST )
|
||||
{
|
||||
AI_NavGoal_t goal( tr.endpos );
|
||||
GetNavigator()->SetGoal( goal );
|
||||
}
|
||||
|
||||
TaskComplete();
|
||||
}
|
||||
break;
|
||||
|
||||
case TASK_BBUG_FACE_DAWDLE:
|
||||
{
|
||||
// Turn a random amount to the right
|
||||
float flYaw = GetMotor()->GetIdealYaw();
|
||||
flYaw = flYaw + random->RandomFloat( 45, 135 );
|
||||
GetMotor()->SetIdealYaw( UTIL_AngleMod(flYaw) );
|
||||
SetTurnActivity();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
BaseClass::StartTask( pTask );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pTask -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bug_Builder::RunTask( const Task_t *pTask )
|
||||
{
|
||||
switch ( pTask->iTask )
|
||||
{
|
||||
case TASK_BBUG_FACE_DAWDLE:
|
||||
{
|
||||
GetMotor()->UpdateYaw();
|
||||
if ( FacingIdeal() )
|
||||
{
|
||||
TaskComplete();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
BaseClass::RunTask( pTask );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNPC_Bug_Builder::FValidateHintType(CAI_Hint *pHint)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pVictim -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bug_Builder::Event_Killed( const CTakeDamageInfo &info )
|
||||
{
|
||||
BaseClass::Event_Killed( info );
|
||||
|
||||
// Remove myself in a minute
|
||||
if ( !ShouldFadeOnDeath() )
|
||||
{
|
||||
SetThink( SUB_Remove );
|
||||
SetNextThink( gpGlobals->curtime + 20 );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pEvent -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bug_Builder::HandleAnimEvent( animevent_t *pEvent )
|
||||
{
|
||||
BaseClass::HandleAnimEvent( pEvent );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
float CNPC_Bug_Builder::MaxYawSpeed( void )
|
||||
{
|
||||
return 2.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bug_Builder::IdleSound( void )
|
||||
{
|
||||
EmitSound( "NPC_Bug_Builder.Idle" );
|
||||
m_flIdleDelay = gpGlobals->curtime + 4.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bug_Builder::PainSound( const CTakeDamageInfo &info )
|
||||
{
|
||||
EmitSound( "NPC_Bug_Builder.Pain" );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CNPC_Bug_Builder::ShouldPlayIdleSound( void )
|
||||
{
|
||||
//Only do idles in the right states
|
||||
if ( ( m_NPCState != NPC_STATE_IDLE && m_NPCState != NPC_STATE_ALERT ) )
|
||||
return false;
|
||||
|
||||
//Gagged monsters don't talk
|
||||
if ( HasSpawnFlags( SF_NPC_GAG ) )
|
||||
return false;
|
||||
|
||||
//Don't cut off another sound or play again too soon
|
||||
if ( m_flIdleDelay > gpGlobals->curtime )
|
||||
return false;
|
||||
|
||||
//Randomize it a bit
|
||||
if ( random->RandomInt( 0, 20 ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bug_Builder::SetBugHole( CMaker_BugHole *pBugHole )
|
||||
{
|
||||
m_hMyBugHole = pBugHole;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: BugHole is calling me home to defend it
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bug_Builder::ReturnToBugHole( void )
|
||||
{
|
||||
SetCondition( COND_BBUG_RETURN_TO_BUGHOLE );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CNPC_Bug_Builder::AlertSound( void )
|
||||
{
|
||||
if ( GetEnemy() )
|
||||
{
|
||||
//FIXME: We need a better solution for inner-squad alerts!!
|
||||
//SOUND_DANGER is designed to frighten NPC's away. Need a different SOUND_ type.
|
||||
CSoundEnt::InsertSound( SOUND_DANGER, GetEnemy()->GetAbsOrigin(), 1024, 0.5f, this );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Overridden for team handling
|
||||
//-----------------------------------------------------------------------------
|
||||
Disposition_t CNPC_Bug_Builder::IRelationType( CBaseEntity *pTarget )
|
||||
{
|
||||
// Builders ignore everything
|
||||
return D_NU;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Schedules
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//=========================================================
|
||||
// Dawdle around
|
||||
//=========================================================
|
||||
AI_DEFINE_SCHEDULE
|
||||
(
|
||||
SCHED_BBUG_DAWDLE,
|
||||
|
||||
" Tasks"
|
||||
" TASK_SET_TOLERANCE_DISTANCE 32"
|
||||
" TASK_BBUG_GET_PATH_TO_DAWDLE 0"
|
||||
" TASK_RUN_PATH 0"
|
||||
" TASK_WAIT_FOR_MOVEMENT 0"
|
||||
" TASK_BBUG_FACE_DAWDLE 0"
|
||||
" "
|
||||
" Interrupts"
|
||||
" COND_LIGHT_DAMAGE"
|
||||
" COND_HEAVY_DAMAGE"
|
||||
);
|
||||
|
||||
//=========================================================
|
||||
// Flee from our enemy
|
||||
//=========================================================
|
||||
AI_DEFINE_SCHEDULE
|
||||
(
|
||||
SCHED_BBUG_FLEE_ENEMY,
|
||||
|
||||
" Tasks"
|
||||
" TASK_SET_TOLERANCE_DISTANCE 128"
|
||||
" TASK_BBUG_GET_PATH_TO_FLEE 0"
|
||||
" TASK_RUN_PATH 0"
|
||||
" TASK_WAIT_FOR_MOVEMENT 0"
|
||||
" TASK_TURN_RIGHT 180"
|
||||
" "
|
||||
" Interrupts"
|
||||
" COND_ENEMY_DEAD"
|
||||
" COND_LOST_ENEMY"
|
||||
);
|
||||
|
||||
//=========================================================
|
||||
// Retreat to a bughole
|
||||
//=========================================================
|
||||
AI_DEFINE_SCHEDULE
|
||||
(
|
||||
SCHED_BBUG_RETURN_TO_BUGHOLE,
|
||||
|
||||
" Tasks"
|
||||
" TASK_SET_TOLERANCE_DISTANCE 128"
|
||||
" TASK_BBUG_GET_PATH_TO_BUGHOLE 0"
|
||||
" TASK_RUN_PATH 0"
|
||||
" TASK_WAIT_FOR_MOVEMENT 0"
|
||||
" "
|
||||
" Interrupts"
|
||||
" COND_NEW_ENEMY"
|
||||
" COND_HEAR_COMBAT"
|
||||
" COND_HEAR_DANGER"
|
||||
);
|
||||
|
||||
//=========================================================
|
||||
// Return to a bughole and remove myself
|
||||
//=========================================================
|
||||
AI_DEFINE_SCHEDULE
|
||||
(
|
||||
SCHED_BBUG_RETURN_TO_BUGHOLE_AND_REMOVE,
|
||||
|
||||
" Tasks"
|
||||
" TASK_WAIT 5" // Wait for 5-10 seconds to see if anything happens
|
||||
" TASK_WAIT_RANDOM 5"
|
||||
" TASK_SET_TOLERANCE_DISTANCE 128"
|
||||
" TASK_BBUG_GET_PATH_TO_BUGHOLE 0"
|
||||
" TASK_RUN_PATH 0"
|
||||
" TASK_WAIT_FOR_MOVEMENT 0"
|
||||
" TASK_BBUG_HOLE_REMOVE 0"
|
||||
" "
|
||||
" Interrupts"
|
||||
" COND_NEW_ENEMY"
|
||||
" COND_HEAR_COMBAT"
|
||||
" COND_HEAR_DANGER"
|
||||
);
|
||||
|
||||
69
game/server/tf2/npc_bug_builder.h
Normal file
69
game/server/tf2/npc_bug_builder.h
Normal file
@@ -0,0 +1,69 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef NPC_BUG_BUILDER_H
|
||||
#define NPC_BUG_BUILDER_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "AI_BaseNPC.h"
|
||||
|
||||
#define BUG_BUILDER_MODEL "models/npcs/bugs/bug_builder.mdl"
|
||||
|
||||
class CMaker_BugHole;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: BUILDER BUG
|
||||
//-----------------------------------------------------------------------------
|
||||
class CNPC_Bug_Builder : public CAI_BaseNPC
|
||||
{
|
||||
DECLARE_CLASS( CNPC_Bug_Builder, CAI_BaseNPC );
|
||||
public:
|
||||
CNPC_Bug_Builder( void );
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void Precache( void );
|
||||
|
||||
virtual int SelectSchedule( void );
|
||||
virtual void StartTask( const Task_t *pTask );
|
||||
virtual void RunTask( const Task_t *pTask );
|
||||
|
||||
virtual float MaxYawSpeed( void );
|
||||
virtual void HandleAnimEvent( animevent_t *pEvent );
|
||||
virtual void IdleSound( void );
|
||||
virtual void PainSound( const CTakeDamageInfo &info );
|
||||
virtual void AlertSound( void );
|
||||
virtual bool FValidateHintType(CAI_Hint *pHint);
|
||||
|
||||
virtual bool ShouldPlayIdleSound( void );
|
||||
|
||||
virtual Class_T Classify( void ) { return CLASS_ANTLION; }
|
||||
virtual int GetSoundInterests( void ) { return 0; }
|
||||
|
||||
DECLARE_DATADESC();
|
||||
|
||||
// BugHole handling
|
||||
void SetBugHole( CMaker_BugHole *pBugHole );
|
||||
void ReturnToBugHole( void );
|
||||
|
||||
private:
|
||||
virtual Disposition_t IRelationType( CBaseEntity *pTarget );
|
||||
|
||||
void Event_Killed( const CTakeDamageInfo &info );
|
||||
|
||||
float m_flIdleDelay;
|
||||
|
||||
float m_flNextDawdle;
|
||||
|
||||
// BugHole handling
|
||||
CHandle< CMaker_BugHole > m_hMyBugHole;
|
||||
|
||||
DEFINE_CUSTOM_AI;
|
||||
};
|
||||
|
||||
#endif // NPC_BUG_BUILDER_H
|
||||
392
game/server/tf2/npc_bug_hole.cpp
Normal file
392
game/server/tf2/npc_bug_hole.cpp
Normal file
@@ -0,0 +1,392 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Bug hole
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "AI_Task.h"
|
||||
#include "AI_Default.h"
|
||||
#include "AI_Schedule.h"
|
||||
#include "AI_Hull.h"
|
||||
#include "AI_Hint.h"
|
||||
#include "activitylist.h"
|
||||
#include "soundent.h"
|
||||
#include "game.h"
|
||||
#include "NPCEvent.h"
|
||||
#include "tf_player.h"
|
||||
#include "EntityList.h"
|
||||
#include "ndebugoverlay.h"
|
||||
#include "shake.h"
|
||||
#include "monstermaker.h"
|
||||
#include "decals.h"
|
||||
#include "vstdlib/random.h"
|
||||
#include "tf_obj.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "IEffects.h"
|
||||
#include "npc_bug_warrior.h"
|
||||
#include "npc_bug_builder.h"
|
||||
#include "npc_bug_hole.h"
|
||||
|
||||
LINK_ENTITY_TO_CLASS( npc_bughole, CMaker_BugHole );
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST(CMaker_BugHole, DT_Maker_BugHole)
|
||||
END_SEND_TABLE();
|
||||
|
||||
BEGIN_DATADESC( CMaker_BugHole )
|
||||
|
||||
DEFINE_KEYFIELD( m_iMaxPool, FIELD_INTEGER, "PoolSize" ),
|
||||
DEFINE_KEYFIELD( m_flPoolRegenTime, FIELD_FLOAT, "PoolRegen" ),
|
||||
DEFINE_KEYFIELD( m_flPatrolTime, FIELD_FLOAT, "PatrolTime" ),
|
||||
DEFINE_KEYFIELD( m_iszPatrolPathName, FIELD_STRING, "PatrolName" ),
|
||||
DEFINE_KEYFIELD( m_iMaxNumberOfPatrollers, FIELD_INTEGER, "MaxPatrollers" ),
|
||||
DEFINE_KEYFIELD( m_iMaxNumberOfBuilders, FIELD_INTEGER, "MaxBuilders" ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
// Maximum speed at which a bughole thinks. Regen/Spawn times faster than this won't make it work faster.
|
||||
#define BUGHOLE_THINK_SPEED 3.0
|
||||
|
||||
static ConVar npc_bughole_health( "npc_bughole_health","300", FCVAR_NONE, "Bug hole's health." );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CMaker_BugHole::CMaker_BugHole( void)
|
||||
{
|
||||
m_iszNPCClassname_Warrior = MAKE_STRING( "npc_bug_warrior" );
|
||||
m_iszNPCClassname_Builder = MAKE_STRING( "npc_bug_builder" );
|
||||
m_iszNPCClassname = m_iszNPCClassname_Warrior;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::Spawn( void )
|
||||
{
|
||||
// Set these up before calling base spawn
|
||||
m_spawnflags |= SF_NPCMAKER_INF_CHILD;
|
||||
m_bDisabled = true;
|
||||
|
||||
// Start with a full pool
|
||||
m_iPool = m_iMaxPool;
|
||||
|
||||
BaseClass::Spawn();
|
||||
|
||||
// Bug holes are destroyable
|
||||
SetSolid( SOLID_BBOX );
|
||||
SetModel( "models/npcs/bugs/bug_hole.mdl" );
|
||||
m_takedamage = DAMAGE_YES;
|
||||
m_iHealth = npc_bughole_health.GetInt();
|
||||
|
||||
// Setup spawn & regen times
|
||||
m_flNextSpawnTime = 0;
|
||||
m_flNextRegenTime = gpGlobals->curtime + m_flPoolRegenTime;
|
||||
m_flNextPatrolTime = gpGlobals->curtime + m_flPatrolTime;
|
||||
|
||||
// Override the base class think, and think with some random so bugholes don't all think at the same time
|
||||
SetThink ( BugHoleThink );
|
||||
SetNextThink( gpGlobals->curtime + BUGHOLE_THINK_SPEED + random->RandomFloat( -0.5, 0.5 ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::Precache( void )
|
||||
{
|
||||
BaseClass::Precache();
|
||||
|
||||
PrecacheModel( "models/npcs/bugs/bug_hole.mdl" );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::BugHoleThink( void )
|
||||
{
|
||||
// Regenerate our bug pool
|
||||
if ( m_flNextRegenTime < gpGlobals->curtime )
|
||||
{
|
||||
if ( m_iPool < m_iMaxPool )
|
||||
{
|
||||
m_iPool++;
|
||||
}
|
||||
m_flNextRegenTime += m_flPoolRegenTime;
|
||||
}
|
||||
|
||||
// Spawn if we're set to
|
||||
if ( m_flNextSpawnTime && m_flNextSpawnTime < gpGlobals->curtime )
|
||||
{
|
||||
m_flNextSpawnTime = 0;
|
||||
MakeNPC();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If I can see a player, try and spawn a bug
|
||||
CBaseEntity *pList[100];
|
||||
Vector vecDelta( 768, 768, 768 );
|
||||
int count = UTIL_EntitiesInBox( pList, 32, GetAbsOrigin() - vecDelta, GetAbsOrigin() + vecDelta, FL_CLIENT|FL_OBJECT );
|
||||
for ( int i = 0; i < count; i++ )
|
||||
{
|
||||
CBaseEntity *pEnt = pList[i];
|
||||
if ( pEnt->IsAlive() && FVisible(pEnt) )
|
||||
{
|
||||
BugHoleUnderAttack();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send out a patrol if we haven't spawned anything for a long time
|
||||
if ( m_flNextPatrolTime < gpGlobals->curtime )
|
||||
{
|
||||
m_flNextPatrolTime = gpGlobals->curtime + m_flPatrolTime;
|
||||
StartPatrol();
|
||||
CheckBuilder();
|
||||
}
|
||||
|
||||
SetNextThink( gpGlobals->curtime + BUGHOLE_THINK_SPEED );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Spawn a bug, if we're not waiting to spawn one already
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::SpawnBug( float flTime )
|
||||
{
|
||||
// If no time was passed in, spawn immediately
|
||||
if ( !flTime )
|
||||
{
|
||||
MakeNPC();
|
||||
}
|
||||
else if ( !m_flNextSpawnTime )
|
||||
{
|
||||
m_flNextSpawnTime = gpGlobals->curtime + flTime;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::SpawnWarrior( float flTime )
|
||||
{
|
||||
m_iszNPCClassname = m_iszNPCClassname_Warrior;
|
||||
SpawnBug( flTime );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::SpawnBuilder( float flTime )
|
||||
{
|
||||
m_iszNPCClassname = m_iszNPCClassname_Builder;
|
||||
SpawnBug( flTime );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: BugHole has spotted a player near it
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::BugHoleUnderAttack( void )
|
||||
{
|
||||
// Call any patrollers back to defend the base
|
||||
for ( int i = 0; i < m_aWarriorBugs.Size(); i++ )
|
||||
{
|
||||
if ( m_aWarriorBugs[i]->IsPatrolling() )
|
||||
{
|
||||
m_aWarriorBugs[i]->ReturnToBugHole();
|
||||
}
|
||||
}
|
||||
|
||||
// Try and spawn a warrior
|
||||
SpawnWarrior( random->RandomFloat( 1.0, 3.0 ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Send a bug out to patrol
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::StartPatrol( void )
|
||||
{
|
||||
// Don't patrol if I don't have a patrol name
|
||||
if ( !m_iszPatrolPathName || !m_iMaxNumberOfPatrollers )
|
||||
return;
|
||||
|
||||
// If I don't have any children, spawn one for to patrol with
|
||||
if ( m_nLiveChildren < m_iMaxNumberOfPatrollers )
|
||||
{
|
||||
SpawnWarrior(0);
|
||||
|
||||
// Think again to use the bug we just created
|
||||
m_flNextPatrolTime = gpGlobals->curtime + 2.0;
|
||||
}
|
||||
|
||||
// We might have failed due to having none in the pool
|
||||
if ( !m_aWarriorBugs.Size() )
|
||||
return;
|
||||
|
||||
// Count number of bugs patrolling
|
||||
int i, iCount;
|
||||
iCount = 0;
|
||||
for ( i = 0; i < m_aWarriorBugs.Size(); i++ )
|
||||
{
|
||||
if ( m_aWarriorBugs[i]->IsPatrolling() )
|
||||
{
|
||||
iCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Find bugs willing to patrol
|
||||
for ( i = 0; i < m_aWarriorBugs.Size(); i++ )
|
||||
{
|
||||
// Make sure we don't have too many
|
||||
if ( iCount >= m_iMaxNumberOfPatrollers )
|
||||
return;
|
||||
|
||||
if ( m_aWarriorBugs[i]->StartPatrolling( m_iszPatrolPathName ) )
|
||||
{
|
||||
iCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: See if we should spawn a builder bug
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::CheckBuilder( void )
|
||||
{
|
||||
// If my pool is full, and I have spaw builder spots, spawn a builder bug
|
||||
/*
|
||||
if ( m_iPool == m_iMaxPool && m_aBuilderBugs.Size() < m_iMaxNumberOfBuilders )
|
||||
{
|
||||
SpawnBuilder(0);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Bughole makes multiple types of bugs
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::MakeNPC( void )
|
||||
{
|
||||
// Don't try and patrol for a while
|
||||
m_flNextPatrolTime = gpGlobals->curtime + m_flPatrolTime;
|
||||
|
||||
// If my pool is empty, don't spawn a bug
|
||||
if ( !m_iPool )
|
||||
return;
|
||||
|
||||
BaseClass::MakeNPC();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Hook to allow bugs to move before they spawn
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::ChildPreSpawn( CAI_BaseNPC *pChild )
|
||||
{
|
||||
BaseClass::ChildPreSpawn( pChild );
|
||||
|
||||
// Drop the bug down and remove it's onground flag
|
||||
Vector origin = GetLocalOrigin();
|
||||
origin.z -= 64;
|
||||
pChild->SetLocalOrigin( origin );
|
||||
pChild->SetGroundEntity( NULL );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Hook to allow bugs to pack specific data into their known class fields
|
||||
// Input : *pChild - pointer to the spawned entity to work on
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::ChildPostSpawn( CAI_BaseNPC *pChild )
|
||||
{
|
||||
BaseClass::ChildPostSpawn( pChild );
|
||||
|
||||
// May be a warrior or a builder
|
||||
CNPC_Bug_Warrior *pWarrior = dynamic_cast<CNPC_Bug_Warrior*>((CAI_BaseNPC*)pChild);
|
||||
if ( pWarrior )
|
||||
{
|
||||
pWarrior->SetBugHole( this );
|
||||
|
||||
// Add him to my bug list
|
||||
WarriorHandle_t hHandle;
|
||||
hHandle = pWarrior;
|
||||
m_aWarriorBugs.AddToTail( hHandle );
|
||||
}
|
||||
else
|
||||
{
|
||||
CNPC_Bug_Builder *pBuilder = dynamic_cast<CNPC_Bug_Builder*>((CAI_BaseNPC*)pChild);
|
||||
ASSERT( pBuilder );
|
||||
pBuilder->SetBugHole( this );
|
||||
|
||||
// Add him to my bug list
|
||||
BuilderHandle_t hHandle;
|
||||
hHandle = pBuilder;
|
||||
m_aBuilderBugs.AddToTail( hHandle );
|
||||
}
|
||||
|
||||
m_iPool--;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Remove the bug from our list of bugs
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::DeathNotice( CBaseEntity *pVictim )
|
||||
{
|
||||
BaseClass::DeathNotice( pVictim );
|
||||
|
||||
// May be a warrior or a builder
|
||||
CNPC_Bug_Warrior *pWarrior = dynamic_cast<CNPC_Bug_Warrior*>((CAI_BaseNPC*)pVictim);
|
||||
if ( pWarrior )
|
||||
{
|
||||
// Remove him from my list
|
||||
WarriorHandle_t hHandle;
|
||||
hHandle = pWarrior;
|
||||
m_aWarriorBugs.FindAndRemove( hHandle );
|
||||
}
|
||||
else
|
||||
{
|
||||
CNPC_Bug_Builder *pBuilder = dynamic_cast<CNPC_Bug_Builder*>((CAI_BaseNPC*)pVictim);
|
||||
ASSERT( pBuilder );
|
||||
|
||||
// Remove him from my list
|
||||
BuilderHandle_t hHandle;
|
||||
hHandle = pBuilder;
|
||||
m_aBuilderBugs.FindAndRemove( hHandle );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: On death, fall to the ground and vanish
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::Event_Killed( const CTakeDamageInfo &info )
|
||||
{
|
||||
BaseClass::Event_Killed( info );
|
||||
|
||||
SetMoveType( MOVETYPE_FLYGRAVITY );
|
||||
SetGroundEntity( NULL );
|
||||
|
||||
SetThink( SUB_Remove );
|
||||
SetNextThink( gpGlobals->curtime + 5.0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A bug is fleeing to me, see if I want to do anything
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::IncomingFleeingBug( CAI_BaseNPC *pBug )
|
||||
{
|
||||
SpawnWarrior( random->RandomFloat( 3.0, 5.0 ) );
|
||||
|
||||
// If I have available warriors, tell them to engage
|
||||
for ( int i = 0; i < m_aWarriorBugs.Size(); i++ )
|
||||
{
|
||||
m_aWarriorBugs[i]->Assist( pBug );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: One of my bugs has returned to me
|
||||
//-----------------------------------------------------------------------------
|
||||
void CMaker_BugHole::BugReturned( void )
|
||||
{
|
||||
if ( m_iPool < m_iMaxPool )
|
||||
{
|
||||
m_iPool++;
|
||||
}
|
||||
}
|
||||
76
game/server/tf2/npc_bug_hole.h
Normal file
76
game/server/tf2/npc_bug_hole.h
Normal file
@@ -0,0 +1,76 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef NPC_BUG_HOLE_H
|
||||
#define NPC_BUG_HOLE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
class CNPC_Bug_Warrior;
|
||||
class CNPC_Bug_Builder;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: BUG HOLE
|
||||
//-----------------------------------------------------------------------------
|
||||
class CMaker_BugHole : public CNPCMaker
|
||||
{
|
||||
DECLARE_CLASS( CMaker_BugHole, CNPCMaker );
|
||||
public:
|
||||
CMaker_BugHole( void );
|
||||
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void Precache( void );
|
||||
virtual void MakeNPC( void );
|
||||
virtual void ChildPreSpawn( CAI_BaseNPC *pChild );
|
||||
virtual void ChildPostSpawn( CAI_BaseNPC *pChild );
|
||||
virtual void DeathNotice( CBaseEntity *pVictim );
|
||||
virtual void Event_Killed( const CTakeDamageInfo &info );
|
||||
|
||||
// Bug interactions
|
||||
void BugHoleThink( void );
|
||||
void SpawnBug( float flTime );
|
||||
void SpawnWarrior( float flTime );
|
||||
void SpawnBuilder( float flTime );
|
||||
void BugHoleUnderAttack( void );
|
||||
void StartPatrol( void );
|
||||
void CheckBuilder( void );
|
||||
void IncomingFleeingBug( CAI_BaseNPC *pBug );
|
||||
void BugReturned( void );
|
||||
|
||||
private:
|
||||
string_t m_iszNPCClassname_Warrior;
|
||||
string_t m_iszNPCClassname_Builder;
|
||||
|
||||
// Bug pool
|
||||
int m_iPool;
|
||||
int m_iMaxPool;
|
||||
float m_flPoolRegenTime;
|
||||
|
||||
float m_flNextSpawnTime;
|
||||
float m_flNextRegenTime;
|
||||
|
||||
// Patrols
|
||||
int m_iMaxNumberOfPatrollers;
|
||||
float m_flPatrolTime;
|
||||
float m_flNextPatrolTime;
|
||||
string_t m_iszPatrolPathName;
|
||||
|
||||
// Builders
|
||||
int m_iMaxNumberOfBuilders;
|
||||
|
||||
// List of bugs I have out there
|
||||
typedef CHandle<CNPC_Bug_Warrior> WarriorHandle_t;
|
||||
CUtlVector<WarriorHandle_t> m_aWarriorBugs;
|
||||
typedef CHandle<CNPC_Bug_Builder> BuilderHandle_t;
|
||||
CUtlVector<BuilderHandle_t> m_aBuilderBugs;
|
||||
};
|
||||
|
||||
#endif // NPC_BUG_HOLE_H
|
||||
1039
game/server/tf2/npc_bug_warrior.cpp
Normal file
1039
game/server/tf2/npc_bug_warrior.cpp
Normal file
File diff suppressed because it is too large
Load Diff
102
game/server/tf2/npc_bug_warrior.h
Normal file
102
game/server/tf2/npc_bug_warrior.h
Normal file
@@ -0,0 +1,102 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef NPC_BUG_WARRIOR_H
|
||||
#define NPC_BUG_WARRIOR_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "AI_BaseNPC.h"
|
||||
|
||||
// Animation events
|
||||
#define BUG_WARRIOR_AE_MELEE_SOUND1 11 // Start attack sound
|
||||
#define BUG_WARRIOR_AE_MELEE_HIT1 15 // Melee hit, one arm
|
||||
|
||||
// Attack range definitions
|
||||
#define BUG_WARRIOR_MELEE1_RANGE 128.0f
|
||||
#define BUG_WARRIOR_MELEE1_RANGE_MIN 128.0f
|
||||
|
||||
#define BUG_WARRIOR_MODEL "models/npcs/bugs/bug_warrior.mdl"
|
||||
|
||||
class CMaker_BugHole;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: WARRIOR BUG
|
||||
//-----------------------------------------------------------------------------
|
||||
class CNPC_Bug_Warrior : public CAI_BaseNPC
|
||||
{
|
||||
DECLARE_CLASS( CNPC_Bug_Warrior, CAI_BaseNPC );
|
||||
public:
|
||||
CNPC_Bug_Warrior( void );
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void Precache( void );
|
||||
|
||||
virtual int SelectSchedule( void );
|
||||
virtual int TranslateSchedule( int scheduleType );
|
||||
virtual void StartTask( const Task_t *pTask );
|
||||
virtual void RunTask( const Task_t *pTask );
|
||||
virtual bool FValidateHintType(CAI_Hint *pHint);
|
||||
|
||||
virtual void HandleAnimEvent( animevent_t *pEvent );
|
||||
virtual void IdleSound( void );
|
||||
virtual void PainSound( const CTakeDamageInfo &info );
|
||||
virtual void AlertSound( void );
|
||||
virtual bool HandleInteraction( int interactionType, void *data, CBaseCombatCharacter *sender );
|
||||
|
||||
virtual bool ShouldPlayIdleSound( void );
|
||||
|
||||
virtual int MeleeAttack1Conditions( float flDot, float flDist );
|
||||
virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info );
|
||||
|
||||
virtual Class_T Classify( void ) { return CLASS_ANTLION; }
|
||||
|
||||
virtual float MaxYawSpeed ( void );
|
||||
virtual float CalcIdealYaw( const Vector &vecTarget );
|
||||
|
||||
DECLARE_DATADESC();
|
||||
|
||||
// Returns true if the bug should flee
|
||||
bool ShouldFlee( void );
|
||||
|
||||
// Squad handling
|
||||
bool IsAlone( void );
|
||||
|
||||
// BugHole handling
|
||||
void SetBugHole( CMaker_BugHole *pBugHole );
|
||||
void ReturnToBugHole( void );
|
||||
void Assist( CAI_BaseNPC *pBug );
|
||||
|
||||
// Patrolling
|
||||
bool StartPatrolling( string_t iszPatrolPathName );
|
||||
bool IsPatrolling( void );
|
||||
|
||||
private:
|
||||
virtual Disposition_t IRelationType( CBaseEntity *pTarget );
|
||||
virtual int IRelationPriority( CBaseEntity *pTarget );
|
||||
|
||||
void Event_Killed( const CTakeDamageInfo &info );
|
||||
void MeleeAttack( float distance, float damage, QAngle& viewPunch, Vector& shove );
|
||||
|
||||
float m_flIdleDelay;
|
||||
|
||||
// BugHole handling
|
||||
CHandle< CMaker_BugHole > m_hMyBugHole;
|
||||
CHandle< CAI_BaseNPC > m_hAssistTarget;
|
||||
|
||||
// Patrolling
|
||||
string_t m_iszPatrolPathName;
|
||||
int m_iPatrolPoint;
|
||||
|
||||
// Bug's decided he's not fleeing anymore
|
||||
bool m_bFightingToDeath;
|
||||
|
||||
DEFINE_CUSTOM_AI;
|
||||
};
|
||||
|
||||
#endif // NPC_BUG_WARRIOR_H
|
||||
177
game/server/tf2/order_assist.cpp
Normal file
177
game/server/tf2/order_assist.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "order_assist.h"
|
||||
#include "tf_team.h"
|
||||
#include "order_helpers.h"
|
||||
|
||||
|
||||
// If a player has been shot within this time delta, commandos will get orders to assist.
|
||||
#define COMMANDO_ASSIST_SHOT_DELAY 3.0f
|
||||
|
||||
// How close a commando has to be to a teammate to get an assist order.
|
||||
#define COMMAND_ASSIST_DISTANCE 1200
|
||||
#define COMMAND_ASSIST_DISTANCE_SQR (COMMAND_ASSIST_DISTANCE*COMMAND_ASSIST_DISTANCE)
|
||||
|
||||
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( COrderAssist, DT_OrderAssist )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
static bool IsValidFn_OnEnemyTeam( void *pUserData, int a )
|
||||
{
|
||||
edict_t *pEdict = engine->PEntityOfEntIndex( a+1 );
|
||||
if ( !pEdict )
|
||||
return false;
|
||||
|
||||
CBaseEntity *pBaseEntity = CBaseEntity::Instance( pEdict );
|
||||
if ( !pBaseEntity )
|
||||
return false;
|
||||
|
||||
CSortBase *p = (CSortBase*)pUserData;
|
||||
return pBaseEntity->GetTeam() != p->m_pPlayer->GetTeam();
|
||||
}
|
||||
|
||||
|
||||
static bool IsValidFn_PlayersWantingAssist( void *pUserData, int a )
|
||||
{
|
||||
CSortBase *pSortBase = (CSortBase*)pUserData;
|
||||
CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)pSortBase->m_pPlayer->GetTeam()->GetPlayer( a );
|
||||
|
||||
if ( !pPlayer->IsAlive() )
|
||||
{
|
||||
// This guy sure could have used an assist but YOU'RE TOO SLOW!!!
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't try to assist yourself...
|
||||
if ( pPlayer == pSortBase->m_pPlayer )
|
||||
return false;
|
||||
|
||||
// Make sure this guy was shot recently.
|
||||
if ( (gpGlobals->curtime - pPlayer->LastTimeDamagedByEnemy()) > COMMANDO_ASSIST_SHOT_DELAY )
|
||||
return false;
|
||||
|
||||
// Is the guy close enough?
|
||||
if ( pSortBase->m_pPlayer->GetAbsOrigin().DistToSqr( pPlayer->GetAbsOrigin() ) > COMMAND_ASSIST_DISTANCE_SQR )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool COrderAssist::CreateOrder( CPlayerClass *pClass )
|
||||
{
|
||||
// Search for a (live) nearby player who's just been shot.
|
||||
CSortBase info;
|
||||
info.m_pPlayer = pClass->GetPlayer();
|
||||
|
||||
int sorted[512];
|
||||
int nSorted = BuildSortedActiveList(
|
||||
sorted,
|
||||
ARRAYSIZE( sorted ),
|
||||
SortFn_TeamPlayersByDistance,
|
||||
IsValidFn_PlayersWantingAssist,
|
||||
&info,
|
||||
pClass->GetTeam()->GetNumPlayers()
|
||||
);
|
||||
|
||||
if ( nSorted )
|
||||
{
|
||||
COrderAssist *pOrder = new COrderAssist;
|
||||
|
||||
CBaseTFPlayer *pPlayerToAssist = (CBaseTFPlayer*)pClass->GetTeam()->GetPlayer( sorted[0] );
|
||||
|
||||
pClass->GetTeam()->AddOrder(
|
||||
ORDER_ASSIST,
|
||||
pPlayerToAssist,
|
||||
info.m_pPlayer,
|
||||
COMMAND_ASSIST_DISTANCE,
|
||||
25,
|
||||
pOrder );
|
||||
|
||||
// Add the closest enemies.
|
||||
CSortBase enemySortInfo;
|
||||
enemySortInfo.m_pPlayer = pPlayerToAssist;
|
||||
|
||||
int sortedEnemies[256];
|
||||
int nSortedEnemies = BuildSortedActiveList(
|
||||
sortedEnemies,
|
||||
ARRAYSIZE( sortedEnemies ),
|
||||
SortFn_PlayerEntitiesByDistance,
|
||||
IsValidFn_OnEnemyTeam,
|
||||
&info,
|
||||
gpGlobals->maxClients
|
||||
);
|
||||
|
||||
nSortedEnemies = MIN( nSortedEnemies, NUM_ASSIST_ENEMIES );
|
||||
for ( int i=0; i < nSortedEnemies; i++ )
|
||||
{
|
||||
CBaseEntity *pEnt = CBaseEntity::Instance( engine->PEntityOfEntIndex( sortedEnemies[i] + 1 ) );
|
||||
Assert( dynamic_cast<CBasePlayer*>( pEnt ) );
|
||||
pOrder->m_Enemies[i] = pEnt;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool COrderAssist::Update()
|
||||
{
|
||||
if ( !GetTargetEntity() || !GetTargetEntity()->IsAlive() )
|
||||
return true;
|
||||
|
||||
return BaseClass::Update();
|
||||
}
|
||||
|
||||
|
||||
bool COrderAssist::UpdateOnEvent( COrderEvent_Base *pEvent )
|
||||
{
|
||||
if ( !GetTargetEntity() )
|
||||
return true;
|
||||
|
||||
switch( pEvent->GetType() )
|
||||
{
|
||||
// If our boy dies, then he doesn't care about assistance anymore.
|
||||
case ORDER_EVENT_PLAYER_KILLED:
|
||||
{
|
||||
COrderEvent_PlayerKilled *pKilled = (COrderEvent_PlayerKilled*)pEvent;
|
||||
if ( pKilled->m_pPlayer == GetTargetEntity() )
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
// Did we damage one of the enemies?
|
||||
case ORDER_EVENT_PLAYER_DAMAGED:
|
||||
{
|
||||
COrderEvent_PlayerDamaged *pPlayerDamaged = (COrderEvent_PlayerDamaged*)pEvent;
|
||||
if ( pPlayerDamaged->m_TakeDamageInfo.GetInflictor() == GetOwner() )
|
||||
{
|
||||
for ( int i=0; i < NUM_ASSIST_ENEMIES; i++ )
|
||||
{
|
||||
if ( pPlayerDamaged->m_pPlayerDamaged == m_Enemies[i].Get() )
|
||||
{
|
||||
// Reset the timer on the guy we're defending, in case we killed his
|
||||
// attacker really quickly.
|
||||
// CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetTargetEntity();
|
||||
// pPlayer->m_flLastTimeDamagedByEnemy = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return BaseClass::UpdateOnEvent( pEvent );
|
||||
}
|
||||
|
||||
|
||||
51
game/server/tf2/order_assist.h
Normal file
51
game/server/tf2/order_assist.h
Normal file
@@ -0,0 +1,51 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TF_ORDER_ASSIST_H
|
||||
#define TF_ORDER_ASSIST_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "order_player.h"
|
||||
|
||||
|
||||
class CPlayerClass;
|
||||
|
||||
|
||||
class COrderAssist : public COrderPlayer
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( COrderAssist, COrderPlayer );
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
// Create an order for the player.
|
||||
static bool CreateOrder( CPlayerClass *pClass );
|
||||
|
||||
|
||||
// COrder overrides.
|
||||
public:
|
||||
|
||||
virtual bool Update();
|
||||
virtual bool UpdateOnEvent( COrderEvent_Base *pEvent );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
enum
|
||||
{
|
||||
NUM_ASSIST_ENEMIES = 2
|
||||
};
|
||||
|
||||
// The order goes away when the player who has the assist order shoots
|
||||
// one of these enemies.
|
||||
CHandle<CBaseEntity> m_Enemies[NUM_ASSIST_ENEMIES];
|
||||
};
|
||||
|
||||
|
||||
#endif // TF_ORDER_ASSIST_H
|
||||
55
game/server/tf2/order_buildsentrygun.cpp
Normal file
55
game/server/tf2/order_buildsentrygun.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "order_buildsentrygun.h"
|
||||
#include "tf_class_defender.h"
|
||||
#include "tf_team.h"
|
||||
#include "order_helpers.h"
|
||||
|
||||
|
||||
// The defender will get orders to cover objects with sentry guns this far away.
|
||||
#define SENTRYGUN_ORDER_DIST 3500
|
||||
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( COrderBuildSentryGun, DT_OrderBuildSentryGun )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
bool COrderBuildSentryGun::CreateOrder( CPlayerClassDefender *pClass )
|
||||
{
|
||||
if ( !pClass->CanBuildSentryGun() )
|
||||
return false;
|
||||
|
||||
COrderBuildSentryGun *pOrder = new COrderBuildSentryGun;
|
||||
if ( OrderCreator_GenericObject( pClass, OBJ_SENTRYGUN_PLASMA, SENTRYGUN_ORDER_DIST, pOrder ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_RemoveImmediate( pOrder );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool COrderBuildSentryGun::Update()
|
||||
{
|
||||
// If the entity we were supposed to cover with the sentry gun is covered now,
|
||||
// then the order is done.
|
||||
CBaseEntity *pEnt = GetTargetEntity();
|
||||
if( !pEnt || !m_hOwningPlayer.Get() )
|
||||
return true;
|
||||
|
||||
CTFTeam *pTeam = m_hOwningPlayer->GetTFTeam();
|
||||
if( pTeam->IsCoveredBySentryGun( pEnt->GetAbsOrigin() ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
38
game/server/tf2/order_buildsentrygun.h
Normal file
38
game/server/tf2/order_buildsentrygun.h
Normal file
@@ -0,0 +1,38 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ORDER_BUILDSENTRYGUN_H
|
||||
#define ORDER_BUILDSENTRYGUN_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "orders.h"
|
||||
|
||||
|
||||
class CPlayerClassDefender;
|
||||
|
||||
|
||||
class COrderBuildSentryGun : public COrder
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( COrderBuildSentryGun, COrder );
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
// Create an order for the player.
|
||||
static bool CreateOrder( CPlayerClassDefender *pClass );
|
||||
|
||||
|
||||
// COrder overrides.
|
||||
public:
|
||||
|
||||
virtual bool Update( void );
|
||||
};
|
||||
|
||||
|
||||
#endif // ORDER_BUILDSENTRYGUN_H
|
||||
51
game/server/tf2/order_buildshieldwall.cpp
Normal file
51
game/server/tf2/order_buildshieldwall.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "order_buildshieldwall.h"
|
||||
#include "tf_team.h"
|
||||
#include "order_helpers.h"
|
||||
|
||||
|
||||
// The defender will get orders to cover objects with sentry guns this far away.
|
||||
#define SANDBAG_ORDER_DIST 3500
|
||||
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( COrderBuildShieldWall, DT_OrderBuildShieldWall )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
bool COrderBuildShieldWall::CreateOrder( CPlayerClass *pClass )
|
||||
{
|
||||
COrderBuildShieldWall *pOrder = new COrderBuildShieldWall;
|
||||
if ( OrderCreator_GenericObject( pClass, OBJ_SHIELDWALL, 2000, pOrder ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_RemoveImmediate( pOrder );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool COrderBuildShieldWall::Update()
|
||||
{
|
||||
CBaseEntity *pEnt = GetTargetEntity();
|
||||
if( !pEnt )
|
||||
return true;
|
||||
|
||||
if ( !m_hOwningPlayer.Get() || m_hOwningPlayer->CanBuild( OBJ_SHIELDWALL ) != CB_CAN_BUILD )
|
||||
return true;
|
||||
|
||||
CTFTeam *pTeam = m_hOwningPlayer->GetTFTeam();
|
||||
if ( pTeam->GetNumShieldWallsCoveringPosition( pEnt->GetAbsOrigin() ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
35
game/server/tf2/order_buildshieldwall.h
Normal file
35
game/server/tf2/order_buildshieldwall.h
Normal file
@@ -0,0 +1,35 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ORDER_BUILDSHIELDWALL_H
|
||||
#define ORDER_BUILDSHIELDWALL_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "orders.h"
|
||||
|
||||
|
||||
class COrderBuildShieldWall : public COrder
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( COrderBuildShieldWall, COrder );
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
// Create an order for the player.
|
||||
static bool CreateOrder( CPlayerClass *pClass );
|
||||
|
||||
|
||||
// COrder overrides.
|
||||
public:
|
||||
|
||||
virtual bool Update( void );
|
||||
};
|
||||
|
||||
|
||||
#endif // ORDER_BUILDSHIELDWALL_H
|
||||
26
game/server/tf2/order_events.cpp
Normal file
26
game/server/tf2/order_events.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "order_events.h"
|
||||
#include "tf_team.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Fire an event for all teams telling them to update their orders
|
||||
//-----------------------------------------------------------------------------
|
||||
void GlobalOrderEvent( COrderEvent_Base *pOrder )
|
||||
{
|
||||
// Loop through the teams
|
||||
for ( int i = 0; i < GetNumberOfTeams(); i++ )
|
||||
{
|
||||
CTFTeam *pTeam = GetGlobalTFTeam( i );
|
||||
pTeam->UpdateOrdersOnEvent( pOrder );
|
||||
}
|
||||
}
|
||||
110
game/server/tf2/order_events.h
Normal file
110
game/server/tf2/order_events.h
Normal file
@@ -0,0 +1,110 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TF_ORDER_EVENTS_H
|
||||
#define TF_ORDER_EVENTS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "tf_player.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ORDER EVENTS
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ORDER_EVENT_PLAYER_DISCONNECTED, // COrderEvent_PlayerDisconnected
|
||||
ORDER_EVENT_PLAYER_KILLED, // CorderEvent_PlayerKilled
|
||||
ORDER_EVENT_PLAYER_RESPAWNED, // COrderEvent_PlayerRespawned
|
||||
ORDER_EVENT_OBJECT_DESTROYED, // COrderEvent_ObjectDestroyed
|
||||
ORDER_EVENT_PLAYER_DAMAGED // COrderEvent_PlayerDamaged
|
||||
} OrderEventType;
|
||||
|
||||
|
||||
abstract_class COrderEvent_Base
|
||||
{
|
||||
public:
|
||||
virtual OrderEventType GetType() = 0;
|
||||
};
|
||||
|
||||
|
||||
// Fire a global order event. It goes to all orders so they can determine if
|
||||
// they want to react.
|
||||
void GlobalOrderEvent( COrderEvent_Base *pOrder );
|
||||
|
||||
|
||||
class COrderEvent_PlayerDisconnected : public COrderEvent_Base
|
||||
{
|
||||
public:
|
||||
COrderEvent_PlayerDisconnected( CBaseEntity *pPlayer )
|
||||
{
|
||||
m_pPlayer = pPlayer;
|
||||
}
|
||||
|
||||
virtual OrderEventType GetType() { return ORDER_EVENT_PLAYER_DISCONNECTED; }
|
||||
|
||||
CBaseEntity *m_pPlayer;
|
||||
};
|
||||
|
||||
|
||||
class COrderEvent_PlayerKilled : public COrderEvent_Base
|
||||
{
|
||||
public:
|
||||
COrderEvent_PlayerKilled( CBaseEntity *pPlayer )
|
||||
{
|
||||
m_pPlayer = pPlayer;
|
||||
}
|
||||
|
||||
virtual OrderEventType GetType() { return ORDER_EVENT_PLAYER_KILLED; }
|
||||
|
||||
CBaseEntity *m_pPlayer;
|
||||
};
|
||||
|
||||
|
||||
class COrderEvent_PlayerRespawned : public COrderEvent_Base
|
||||
{
|
||||
public:
|
||||
COrderEvent_PlayerRespawned( CBaseEntity *pPlayer )
|
||||
{
|
||||
m_pPlayer = pPlayer;
|
||||
}
|
||||
|
||||
virtual OrderEventType GetType() { return ORDER_EVENT_PLAYER_RESPAWNED; }
|
||||
|
||||
CBaseEntity *m_pPlayer;
|
||||
};
|
||||
|
||||
|
||||
class COrderEvent_ObjectDestroyed : public COrderEvent_Base
|
||||
{
|
||||
public:
|
||||
COrderEvent_ObjectDestroyed( CBaseEntity *pObj )
|
||||
{
|
||||
m_pObject = pObj;
|
||||
}
|
||||
|
||||
virtual OrderEventType GetType() { return ORDER_EVENT_OBJECT_DESTROYED; }
|
||||
|
||||
CBaseEntity *m_pObject;
|
||||
};
|
||||
|
||||
|
||||
class COrderEvent_PlayerDamaged : public COrderEvent_Base
|
||||
{
|
||||
public:
|
||||
virtual OrderEventType GetType() { return ORDER_EVENT_PLAYER_DAMAGED; }
|
||||
|
||||
CBaseEntity *m_pPlayerDamaged;
|
||||
CTakeDamageInfo m_TakeDamageInfo;
|
||||
};
|
||||
|
||||
|
||||
#endif // TF_ORDER_EVENTS_H
|
||||
111
game/server/tf2/order_heal.cpp
Normal file
111
game/server/tf2/order_heal.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "order_heal.h"
|
||||
#include "tf_team.h"
|
||||
#include "tf_playerclass.h"
|
||||
#include "order_helpers.h"
|
||||
|
||||
|
||||
#define MAX_HEAL_DIST 1500
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( COrderHeal, DT_OrderHeal )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
bool IsValidFn_Heal( void *pUserData, int a )
|
||||
{
|
||||
// Can't heal dead players.
|
||||
CSortBase *p = (CSortBase*)pUserData;
|
||||
CBasePlayer *pPlayer = p->m_pPlayer->GetTeam()->GetPlayer( a );
|
||||
|
||||
// Can't heal yourself...
|
||||
if (p->m_pPlayer == pPlayer)
|
||||
return false;
|
||||
|
||||
// Don't heal players that are too far away...
|
||||
const Vector &vPlayer = p->m_pPlayer->GetAbsOrigin();
|
||||
if (vPlayer.DistToSqr(pPlayer->GetAbsOrigin()) > MAX_HEAL_DIST * MAX_HEAL_DIST )
|
||||
return false;
|
||||
|
||||
return pPlayer->IsAlive() && pPlayer->m_iHealth < pPlayer->m_iMaxHealth;
|
||||
}
|
||||
|
||||
|
||||
int SortFn_Heal( void *pUserData, int a, int b )
|
||||
{
|
||||
CSortBase *p = (CSortBase*)pUserData;
|
||||
|
||||
const Vector &vPlayer = p->m_pPlayer->GetAbsOrigin();
|
||||
const Vector &va = p->m_pPlayer->GetTeam()->GetPlayer( a )->GetAbsOrigin();
|
||||
const Vector &vb = p->m_pPlayer->GetTeam()->GetPlayer( b )->GetAbsOrigin();
|
||||
|
||||
return vPlayer.DistToSqr( va ) < vPlayer.DistToSqr( vb );
|
||||
}
|
||||
|
||||
|
||||
bool COrderHeal::CreateOrder( CPlayerClass *pClass )
|
||||
{
|
||||
CTFTeam *pTeam = pClass->GetTeam();
|
||||
|
||||
CSortBase info;
|
||||
info.m_pPlayer = pClass->GetPlayer();
|
||||
|
||||
int sorted[MAX_PLAYERS];
|
||||
int nSorted = BuildSortedActiveList(
|
||||
sorted,
|
||||
MAX_PLAYERS,
|
||||
SortFn_Heal,
|
||||
IsValidFn_Heal,
|
||||
&info,
|
||||
pTeam->GetNumPlayers()
|
||||
);
|
||||
|
||||
if ( nSorted )
|
||||
{
|
||||
COrderHeal *pOrder = new COrderHeal;
|
||||
|
||||
pClass->GetTeam()->AddOrder(
|
||||
ORDER_HEAL,
|
||||
pTeam->GetPlayer( sorted[0] ),
|
||||
pClass->GetPlayer(),
|
||||
1e24,
|
||||
60,
|
||||
pOrder );
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool COrderHeal::Update()
|
||||
{
|
||||
CBaseEntity *pTarget = GetTargetEntity();
|
||||
if ( !pTarget || pTarget->m_iHealth >= pTarget->m_iMaxHealth )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool COrderHeal::UpdateOnEvent( COrderEvent_Base *pEvent )
|
||||
{
|
||||
if ( pEvent->GetType() == ORDER_EVENT_PLAYER_KILLED )
|
||||
{
|
||||
COrderEvent_PlayerKilled *pKilled = (COrderEvent_PlayerKilled*)pEvent;
|
||||
if ( pKilled->m_pPlayer == GetTargetEntity() )
|
||||
return true;
|
||||
}
|
||||
|
||||
return BaseClass::UpdateOnEvent( pEvent );
|
||||
}
|
||||
|
||||
39
game/server/tf2/order_heal.h
Normal file
39
game/server/tf2/order_heal.h
Normal file
@@ -0,0 +1,39 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ORDER_HEAL_H
|
||||
#define ORDER_HEAL_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "order_player.h"
|
||||
|
||||
|
||||
class CPlayerClass;
|
||||
|
||||
|
||||
class COrderHeal : public COrderPlayer
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( COrderHeal, COrderPlayer );
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
// Create an order for the player.
|
||||
static bool CreateOrder( CPlayerClass *pClass );
|
||||
|
||||
|
||||
// COrder overrides.
|
||||
public:
|
||||
|
||||
virtual bool Update();
|
||||
virtual bool UpdateOnEvent( COrderEvent_Base *pEvent );
|
||||
};
|
||||
|
||||
|
||||
#endif // ORDER_HEAL_H
|
||||
345
game/server/tf2/order_helpers.cpp
Normal file
345
game/server/tf2/order_helpers.cpp
Normal file
@@ -0,0 +1,345 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "order_helpers.h"
|
||||
#include "tf_team.h"
|
||||
#include "tf_func_resource.h"
|
||||
#include "tf_obj.h"
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------ //
|
||||
// CSortBase implementation.
|
||||
// ------------------------------------------------------------------------ //
|
||||
|
||||
CSortBase::CSortBase()
|
||||
{
|
||||
m_pPlayer = 0;
|
||||
m_pTeam = 0;
|
||||
}
|
||||
|
||||
|
||||
CTFTeam* CSortBase::GetTeam()
|
||||
{
|
||||
if ( m_pTeam )
|
||||
return m_pTeam;
|
||||
else
|
||||
return m_pPlayer->GetTFTeam();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------ //
|
||||
// Global functions.
|
||||
// ------------------------------------------------------------------------ //
|
||||
|
||||
int SortFn_TeamPlayersByDistance( void *pUserData, int a, int b )
|
||||
{
|
||||
CSortBase *p = (CSortBase*)pUserData;
|
||||
|
||||
const Vector &vPlayer = p->m_pPlayer->GetAbsOrigin();
|
||||
const Vector &va = p->m_pPlayer->GetTeam()->GetPlayer( a )->GetAbsOrigin();
|
||||
const Vector &vb = p->m_pPlayer->GetTeam()->GetPlayer( b )->GetAbsOrigin();
|
||||
|
||||
return vPlayer.DistTo( va ) < vPlayer.DistTo( vb );
|
||||
}
|
||||
|
||||
|
||||
// This is a generic function that takes a number of items and builds a sorted
|
||||
// list of the valid items.
|
||||
int BuildSortedActiveList(
|
||||
int *pList, // This is the list where the final data is placed.
|
||||
int nMaxItems,
|
||||
sortFn pSortFn, // Callbacks.
|
||||
isValidFn pIsValidFn, // This can be null, in which case all items are valid.
|
||||
void *pUserData, // Passed into the function pointers.
|
||||
int nItems // Number of items in the list to sort.
|
||||
)
|
||||
{
|
||||
// First build the list of active items.
|
||||
if( nItems > nMaxItems )
|
||||
nItems = nMaxItems;
|
||||
|
||||
int nActive = 0;
|
||||
for( int i=0; i < nItems; i++ )
|
||||
{
|
||||
if( pIsValidFn )
|
||||
{
|
||||
if( !pIsValidFn( pUserData, i ) )
|
||||
continue;
|
||||
}
|
||||
|
||||
int j;
|
||||
for( j=0; j < nActive; j++ )
|
||||
{
|
||||
Assert( pList[j] < nItems );
|
||||
if( pSortFn( pUserData, i, pList[j] ) > 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Slide everything up.
|
||||
if( nActive )
|
||||
{
|
||||
Q_memmove( &pList[j+1], &pList[j], (nActive-j) * sizeof(int) );
|
||||
}
|
||||
|
||||
// Add the new item to the list.
|
||||
pList[j] = i;
|
||||
++nActive;
|
||||
|
||||
for (int l = 0; l < nActive ; ++l )
|
||||
{
|
||||
Assert( pList[l] < nItems );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nActive;
|
||||
}
|
||||
|
||||
|
||||
// Finds the closest resource zone without the specified object on it and
|
||||
// gives an order to the player to build the object.
|
||||
bool OrderCreator_ResourceZoneObject(
|
||||
CBaseTFPlayer *pPlayer,
|
||||
int objType,
|
||||
COrder *pOrder
|
||||
)
|
||||
{
|
||||
// Can we even build a resource box?
|
||||
if ( pPlayer->CanBuild( objType ) != CB_CAN_BUILD )
|
||||
return false;
|
||||
|
||||
CTFTeam *pTeam = pPlayer->GetTFTeam();
|
||||
if( !pTeam )
|
||||
return false;
|
||||
|
||||
// Let's have one near each resource zone that we own.
|
||||
CResourceZone *pClosest = 0;
|
||||
float flClosestDist = 100000000;
|
||||
|
||||
CBaseEntity *pEntity = NULL;
|
||||
while( (pEntity = gEntList.FindEntityByClassname( pEntity, "trigger_resourcezone" )) != NULL )
|
||||
{
|
||||
CResourceZone *pZone = (CResourceZone*)pEntity;
|
||||
|
||||
// Ignore empty zones and zones not captured by this team.
|
||||
if ( pZone->IsEmpty() || !pZone->GetActive() )
|
||||
continue;
|
||||
|
||||
Vector vZoneCenter = pZone->WorldSpaceCenter();
|
||||
|
||||
// Look for a resource pump on this zone.
|
||||
bool bPump = objType == OBJ_RESOURCEPUMP && pPlayer->NumPumpsOnResourceZone( pZone ) == 0;
|
||||
if ( bPump )
|
||||
{
|
||||
// Make sure it's their preferred tech.
|
||||
float flTestDist = pPlayer->GetAbsOrigin().DistTo( vZoneCenter );
|
||||
if ( flTestDist < flClosestDist )
|
||||
{
|
||||
pClosest = pZone;
|
||||
flClosestDist = flTestDist;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( pClosest )
|
||||
{
|
||||
// No pump here. Build one!
|
||||
pPlayer->GetTFTeam()->AddOrder(
|
||||
ORDER_BUILD,
|
||||
pClosest,
|
||||
pPlayer,
|
||||
1e24,
|
||||
60,
|
||||
pOrder
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int SortFn_PlayerObjectsByDistance( void *pUserData, int a, int b )
|
||||
{
|
||||
CSortBase *pSortBase = (CSortBase*)pUserData;
|
||||
|
||||
CBaseObject* pObjA = pSortBase->m_pPlayer->GetObject(a);
|
||||
CBaseObject* pObjB = pSortBase->m_pPlayer->GetObject(b);
|
||||
if (!pObjA)
|
||||
return false;
|
||||
if (!pObjB)
|
||||
return true;
|
||||
|
||||
const Vector &v = pSortBase->m_pPlayer->GetAbsOrigin();
|
||||
|
||||
return v.DistTo( pObjA->GetAbsOrigin() ) < v.DistTo( pObjB->GetAbsOrigin() );
|
||||
}
|
||||
|
||||
|
||||
int SortFn_TeamObjectsByDistance( void *pUserData, int a, int b )
|
||||
{
|
||||
CSortBase *pSortBase = (CSortBase*)pUserData;
|
||||
|
||||
CBaseObject *pObj1 = pSortBase->m_pPlayer->GetTFTeam()->GetObject( a );
|
||||
CBaseObject *pObj2 = pSortBase->m_pPlayer->GetTFTeam()->GetObject( b );
|
||||
const Vector &v = pSortBase->m_pPlayer->GetAbsOrigin();
|
||||
|
||||
return v.DistTo( pObj1->GetAbsOrigin() ) < v.DistTo( pObj2->GetAbsOrigin() );
|
||||
}
|
||||
|
||||
|
||||
int SortFn_PlayerEntitiesByDistance( void *pUserData, int a, int b )
|
||||
{
|
||||
CSortBase *pSortBase = (CSortBase*)pUserData;
|
||||
|
||||
CBaseEntity *pObj1 = CBaseEntity::Instance( engine->PEntityOfEntIndex( a+1 ) );
|
||||
CBaseEntity *pObj2 = CBaseEntity::Instance( engine->PEntityOfEntIndex( b+1 ) );
|
||||
const Vector &v = pSortBase->m_pPlayer->GetAbsOrigin();
|
||||
|
||||
return v.DistTo( pObj1->GetAbsOrigin() ) < v.DistTo( pObj2->GetAbsOrigin() );
|
||||
}
|
||||
|
||||
|
||||
int SortFn_DistanceAndConcentration( void *pUserData, int a, int b )
|
||||
{
|
||||
CSortBase *p = (CSortBase*)pUserData;
|
||||
|
||||
// Compare distances. Each rope attachment to another ent
|
||||
// subtracts 200 inches, so the order is biased towards covering
|
||||
// groups of objects together.
|
||||
CBaseObject *pObjectA = p->GetTeam()->GetObject( a );
|
||||
CBaseObject *pObjectB = p->GetTeam()->GetObject( b );
|
||||
|
||||
const Vector &vOrigin1 = pObjectA->GetAbsOrigin();
|
||||
const Vector &vOrigin2 = p->GetTeam()->GetObject( b )->GetAbsOrigin();
|
||||
|
||||
float flScore1 = -p->m_pPlayer->GetAbsOrigin().DistTo( vOrigin1 );
|
||||
float flScore2 = -p->m_pPlayer->GetAbsOrigin().DistTo( vOrigin2 );
|
||||
|
||||
flScore1 += pObjectA->RopeCount() * 200;
|
||||
flScore2 += pObjectB->RopeCount() * 200;
|
||||
|
||||
return flScore1 > flScore2;
|
||||
}
|
||||
|
||||
|
||||
bool IsValidFn_NearAndNotCovered( void *pUserData, int a )
|
||||
{
|
||||
CSortBase *p = (CSortBase*)pUserData;
|
||||
CBaseObject *pObj = p->m_pPlayer->GetTFTeam()->GetObject( a );
|
||||
|
||||
// Is the object too far away to be covered?
|
||||
if ( p->m_pPlayer->GetAbsOrigin().DistTo( pObj->GetAbsOrigin() ) > p->m_flMaxDist )
|
||||
return false;
|
||||
|
||||
// Don't cover certain entities (like sentry guns, sand bags, etc).
|
||||
switch( p->m_ObjectType )
|
||||
{
|
||||
case OBJ_SENTRYGUN_PLASMA:
|
||||
{
|
||||
if ( !pObj->WantsCoverFromSentryGun() )
|
||||
return false;
|
||||
|
||||
if ( p->m_pPlayer->GetTFTeam()->IsCoveredBySentryGun( pObj->GetAbsOrigin() ) )
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case OBJ_SHIELDWALL:
|
||||
{
|
||||
if ( !pObj->WantsCover() )
|
||||
return false;
|
||||
|
||||
if ( p->m_pPlayer->GetTFTeam()->GetNumShieldWallsCoveringPosition( pObj->GetAbsOrigin() ) )
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case OBJ_RESUPPLY:
|
||||
{
|
||||
if ( p->m_pPlayer->GetTFTeam()->GetNumResuppliesCoveringPosition( pObj->GetAbsOrigin() ) )
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case OBJ_RESPAWN_STATION:
|
||||
{
|
||||
if ( p->m_pPlayer->GetTFTeam()->GetNumRespawnStationsCoveringPosition( pObj->GetAbsOrigin() ) )
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
Assert( !"Unsupported object type" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool OrderCreator_GenericObject(
|
||||
CPlayerClass *pClass,
|
||||
int objectType,
|
||||
float flMaxDist,
|
||||
COrder *pOrder
|
||||
)
|
||||
{
|
||||
// Can we build one?
|
||||
if ( pClass->CanBuild( objectType ) != CB_CAN_BUILD )
|
||||
return false;
|
||||
|
||||
CBaseTFPlayer *pPlayer = pClass->GetPlayer();
|
||||
CTFTeam *pTeam = pClass->GetTeam();
|
||||
|
||||
// Sort nearby objects.
|
||||
CSortBase info;
|
||||
info.m_pPlayer = pPlayer;
|
||||
info.m_flMaxDist = flMaxDist;
|
||||
info.m_ObjectType = objectType;
|
||||
|
||||
int sorted[MAX_TEAM_OBJECTS];
|
||||
int nSorted = BuildSortedActiveList(
|
||||
sorted, // the sorted list of objects
|
||||
MAX_TEAM_OBJECTS,
|
||||
SortFn_DistanceAndConcentration, // sort on distance and entity concentration
|
||||
IsValidFn_NearAndNotCovered, // filter function
|
||||
&info, // user data
|
||||
pTeam->GetNumObjects() // number of objects to check
|
||||
);
|
||||
|
||||
if( nSorted )
|
||||
{
|
||||
// Ok, make an order to cover the closest object with a sentry gun.
|
||||
CBaseEntity *pEnt = pTeam->GetObject( sorted[0] );
|
||||
|
||||
pTeam->AddOrder(
|
||||
ORDER_BUILD,
|
||||
pEnt,
|
||||
pPlayer,
|
||||
flMaxDist,
|
||||
60,
|
||||
pOrder
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
128
game/server/tf2/order_helpers.h
Normal file
128
game/server/tf2/order_helpers.h
Normal file
@@ -0,0 +1,128 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ORDER_HELPERS_H
|
||||
#define ORDER_HELPERS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "orders.h"
|
||||
|
||||
|
||||
class CTFTeam;
|
||||
|
||||
|
||||
class CSortBase
|
||||
{
|
||||
public:
|
||||
|
||||
CSortBase();
|
||||
|
||||
// Returns m_pTeam, and if that doesn't exist, returns m_pPlayer->GetTFTeam().
|
||||
CTFTeam* GetTeam();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
CBaseTFPlayer *m_pPlayer;
|
||||
|
||||
// If this is left at null, then GetTeam() returns m_pPlayer->GetTFTeam().
|
||||
CTFTeam *m_pTeam;
|
||||
|
||||
// One of the OBJ_ defines telling what type of object it's thinking of building.
|
||||
int m_ObjectType;
|
||||
|
||||
// If the object is further from m_vPlayerOrigin than this, then an order
|
||||
// won't be generated to cover it.
|
||||
float m_flMaxDist;
|
||||
};
|
||||
|
||||
|
||||
// Return positive if iItem1 > iItem2.
|
||||
// Return negative if iItem1 < iItem2.
|
||||
// Return zero if they're equal.
|
||||
typedef int (*sortFn)( void *pUserData, int iItem1, int iItem2 );
|
||||
typedef bool (*isValidFn)( void *pUserData, int iItem );
|
||||
|
||||
|
||||
|
||||
// Index engine->PEntityOfIndex(a+1) and b+1.
|
||||
int SortFn_PlayerEntitiesByDistance( void *pUserData, int a, int b );
|
||||
|
||||
// Helper sort function. Sorts CSortBase::m_pPlayer's objects by distance.
|
||||
// pUserData must be a CSortBase.
|
||||
int SortFn_PlayerObjectsByDistance( void *pUserData, int a, int b );
|
||||
|
||||
// Helper sort function. Sorts CSortBase::m_pPlayer->GetTeam()'s objects by distance.
|
||||
// pUserData must be a CSortBase.
|
||||
int SortFn_TeamObjectsByDistance( void *pUserData, int a, int b );
|
||||
|
||||
// Sort by distance and concentation. pUserData must point at something
|
||||
// derived from CSortBase.
|
||||
int SortFn_DistanceAndConcentration( void *pUserData, int a, int b );
|
||||
|
||||
// pUserData is a CSortBase
|
||||
// a and b index CSortBase::m_pPlayer->GetTeam()->GetPlayer()
|
||||
// Sort players on distance.
|
||||
int SortFn_TeamPlayersByDistance( void *pUserData, int a, int b );
|
||||
|
||||
|
||||
// pUserdata is a CSortBase.
|
||||
//
|
||||
// Rejects the object if:
|
||||
// - it's already covered by CSortBase::m_ObjectType
|
||||
// - it's being ferried
|
||||
// - it's further from the player than CSortBase::m_flMaxDist;
|
||||
//
|
||||
// This function currently supports:
|
||||
// - OBJ_SENTRYGUN_PLASMA
|
||||
// - OBJ_SANDBAG
|
||||
// - OBJ_AUTOREPAIR
|
||||
// - OBJ_SHIELDWALL
|
||||
// - OBJ_RESUPPLY
|
||||
bool IsValidFn_NearAndNotCovered( void *pUserData, int a );
|
||||
|
||||
|
||||
|
||||
// This is a generic function that takes a number of items and builds a sorted
|
||||
// list of the valid items.
|
||||
int BuildSortedActiveList(
|
||||
int *pList, // This is the list where the final data is placed.
|
||||
int nMaxItems,
|
||||
sortFn pSortFn, // Callbacks.
|
||||
isValidFn pIsValidFn, // This can be null, in which case all items are valid.
|
||||
void *pUserData, // Passed into the function pointers.
|
||||
int nItems // Number of items in the list to sort.
|
||||
);
|
||||
|
||||
// Finds the closest resource zone without the specified object on it and
|
||||
// gives an order to the player to build the object.
|
||||
// This function supports OBJ_RESOURCEBOX, OBJ_RESOURCEPUMP, and OBJ_ZONE_INCREASER.
|
||||
bool OrderCreator_ResourceZoneObject(
|
||||
CBaseTFPlayer *pPlayer,
|
||||
int objType,
|
||||
COrder *pOrder
|
||||
);
|
||||
|
||||
// This function is shared by lots of the order creation functions.
|
||||
// It makes an order to create a specific type of object by looking for nearby
|
||||
// concentrations of team objects that aren't "covered" by objectType.
|
||||
//
|
||||
// It uses IsValidFn_NearAndNotCovered, so any object type you specify in here
|
||||
// must be supported in IsValidFn_NearAndNotCovered.
|
||||
bool OrderCreator_GenericObject(
|
||||
CPlayerClass *pClass,
|
||||
int objectType,
|
||||
float flMaxDist,
|
||||
COrder *pOrder
|
||||
);
|
||||
|
||||
|
||||
|
||||
#endif // ORDER_HELPERS_H
|
||||
125
game/server/tf2/order_killmortarguy.cpp
Normal file
125
game/server/tf2/order_killmortarguy.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "order_helpers.h"
|
||||
#include "order_killmortarguy.h"
|
||||
#include "tf_team.h"
|
||||
|
||||
|
||||
#define KILLMORTARGUY_DIST 3500
|
||||
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( COrderKillMortarGuy, DT_OrderKillMortarGuy )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
static bool IsValidFn_DeployedBrianJacobsons( void *pUserData, int iClient )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)UTIL_PlayerByIndex( iClient+1 );
|
||||
if ( !pPlayer || pPlayer->IsClass( TFCLASS_UNDECIDED ) || !pPlayer->GetTeam() )
|
||||
return false;
|
||||
|
||||
// Is this person on an enemy team?
|
||||
CSortBase *pSortBase = (CSortBase*)pUserData;
|
||||
CBaseTFPlayer *pMyPlayer = pSortBase->m_pPlayer;
|
||||
|
||||
if( pPlayer->GetTeam()->GetTeamNumber() == pMyPlayer->GetTeam()->GetTeamNumber() )
|
||||
return false;
|
||||
|
||||
// Is he alive?
|
||||
if( !pPlayer->IsAlive() )
|
||||
return false;
|
||||
|
||||
// ROBIN: Removed mortar object. This needs to handle mortar vehicles instead.
|
||||
// Is he looking surly?
|
||||
//if( pPlayer->GetNumObjects( OBJ_MORTAR ) == 0 )
|
||||
//return false;
|
||||
|
||||
// Is he close enough?
|
||||
if( pMyPlayer->GetAbsOrigin().DistTo( pPlayer->GetAbsOrigin() ) > KILLMORTARGUY_DIST )
|
||||
return false;
|
||||
|
||||
// Is he visible to the tactical?
|
||||
// if( !pMyPlayer->GetTFTeam()->IsEntityVisibleToTactical( pPlayer ) )
|
||||
// return false;
|
||||
|
||||
// KILL HIM!!!
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static int SortFn_PlayerEntsByDistance( void *pUserData, int a, int b )
|
||||
{
|
||||
CBaseEntity *pEdictA = CBaseEntity::Instance( engine->PEntityOfEntIndex( a+1 ) );
|
||||
CBaseEntity *pEdictB = CBaseEntity::Instance( engine->PEntityOfEntIndex( b+1 ) );
|
||||
|
||||
if ( !pEdictA || !pEdictB )
|
||||
return 1;
|
||||
|
||||
CSortBase *pSortBase = (CSortBase*)pUserData;
|
||||
const Vector &v = pSortBase->m_pPlayer->GetAbsOrigin();
|
||||
|
||||
return v.DistTo( pEdictA->GetAbsOrigin() ) < v.DistTo( pEdictB->GetAbsOrigin() );
|
||||
}
|
||||
|
||||
|
||||
bool COrderKillMortarGuy::CreateOrder( CPlayerClass *pClass )
|
||||
{
|
||||
CSortBase info;
|
||||
info.m_pPlayer = pClass->GetPlayer();
|
||||
|
||||
// Look for an enemy sniper visible to the
|
||||
int supports[MAX_PLAYERS];
|
||||
int nSupports = BuildSortedActiveList(
|
||||
supports, // the sorted list
|
||||
MAX_PLAYERS,
|
||||
SortFn_PlayerEntsByDistance, // sort on distance
|
||||
IsValidFn_DeployedBrianJacobsons, // only get deployed support guys
|
||||
&info, // pUserData
|
||||
gpGlobals->maxClients // how many players to look through
|
||||
);
|
||||
|
||||
// Kill the closest punk.
|
||||
if( nSupports )
|
||||
{
|
||||
CBaseTFPlayer *pBrian = (CBaseTFPlayer*)UTIL_PlayerByIndex( supports[0]+1 );
|
||||
Assert( pBrian );
|
||||
|
||||
COrderKillMortarGuy *pOrder = new COrderKillMortarGuy;
|
||||
pClass->GetTeam()->AddOrder(
|
||||
ORDER_KILL,
|
||||
pBrian,
|
||||
pClass->GetPlayer(),
|
||||
1e24,
|
||||
60,
|
||||
pOrder
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool COrderKillMortarGuy::UpdateOnEvent( COrderEvent_Base *pEvent )
|
||||
{
|
||||
if ( pEvent->GetType() == ORDER_EVENT_PLAYER_KILLED )
|
||||
{
|
||||
COrderEvent_PlayerKilled *pKilled = (COrderEvent_PlayerKilled*)pEvent;
|
||||
if ( pKilled->m_pPlayer == GetTargetEntity() )
|
||||
return true;
|
||||
}
|
||||
|
||||
return BaseClass::UpdateOnEvent( pEvent );
|
||||
}
|
||||
|
||||
|
||||
|
||||
38
game/server/tf2/order_killmortarguy.h
Normal file
38
game/server/tf2/order_killmortarguy.h
Normal file
@@ -0,0 +1,38 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ORDER_KILLMORTARGUY_H
|
||||
#define ORDER_KILLMORTARGUY_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "order_player.h"
|
||||
|
||||
|
||||
class CPlayerClass;
|
||||
|
||||
|
||||
class COrderKillMortarGuy : public COrderPlayer
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( COrderKillMortarGuy, COrderPlayer );
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
// Create an order for the player.
|
||||
static bool CreateOrder( CPlayerClass *pClass );
|
||||
|
||||
|
||||
// COrder overrides.
|
||||
public:
|
||||
|
||||
virtual bool UpdateOnEvent( COrderEvent_Base *pEvent );
|
||||
};
|
||||
|
||||
|
||||
#endif // ORDER_KILLMORTARGUY_H
|
||||
77
game/server/tf2/order_mortar_attack.cpp
Normal file
77
game/server/tf2/order_mortar_attack.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "order_mortar_attack.h"
|
||||
#include "tf_team.h"
|
||||
#include "order_helpers.h"
|
||||
#include "tf_obj.h"
|
||||
|
||||
|
||||
// How far away the escort guy will get orders to shell enemy objects.
|
||||
#define ENEMYOBJ_MORTAR_DIST 3000
|
||||
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( COrderMortarAttack, DT_OrderMortarAttack )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
static bool IsValidFn_WithinMortarRange( void *pUserData, int a )
|
||||
{
|
||||
CSortBase *p = (CSortBase*)pUserData;
|
||||
CBaseObject *pObj = p->GetTeam()->GetObject( a );
|
||||
return pObj->GetAbsOrigin().DistTo( p->m_pPlayer->GetAbsOrigin() ) < ENEMYOBJ_MORTAR_DIST;
|
||||
}
|
||||
|
||||
|
||||
bool COrderMortarAttack::CreateOrder( CPlayerClass *pClass )
|
||||
{
|
||||
// Look for some nearby enemy objects that would be fun to destroy.
|
||||
CTFTeam *pEnemyTeam;
|
||||
if ( !pClass->GetTeam() || (pEnemyTeam = pClass->GetTeam()->GetEnemyTeam()) == NULL )
|
||||
return false;
|
||||
|
||||
CBaseTFPlayer *pPlayer = pClass->GetPlayer();
|
||||
|
||||
CSortBase info;
|
||||
info.m_pPlayer = pPlayer;
|
||||
info.m_pTeam = pEnemyTeam;
|
||||
|
||||
int sorted[MAX_TEAM_OBJECTS];
|
||||
int nSorted = BuildSortedActiveList(
|
||||
sorted, // the sorted list of objects
|
||||
MAX_TEAM_OBJECTS,
|
||||
SortFn_DistanceAndConcentration, // sort on distance and entity concentration
|
||||
IsValidFn_WithinMortarRange, // filter function
|
||||
&info, // user data
|
||||
pEnemyTeam->GetNumObjects() // number of objects to check
|
||||
);
|
||||
|
||||
if( nSorted > 0 )
|
||||
{
|
||||
CBaseEntity *pEnt = pEnemyTeam->GetObject( sorted[0] );
|
||||
|
||||
COrderMortarAttack *pOrder = new COrderMortarAttack;
|
||||
|
||||
pClass->GetTeam()->AddOrder(
|
||||
ORDER_MORTAR_ATTACK,
|
||||
pEnt,
|
||||
pPlayer,
|
||||
1e24,
|
||||
40,
|
||||
pOrder
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
29
game/server/tf2/order_mortar_attack.h
Normal file
29
game/server/tf2/order_mortar_attack.h
Normal file
@@ -0,0 +1,29 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ORDER_BUILDMORTAR_H
|
||||
#define ORDER_BUILDMORTAR_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "orders.h"
|
||||
|
||||
|
||||
class COrderMortarAttack : public COrder
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( COrderMortarAttack, COrder );
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
// Create an order for the player.
|
||||
static bool CreateOrder( CPlayerClass *pClass );
|
||||
};
|
||||
|
||||
|
||||
#endif // ORDER_BUILDMORTAR_H
|
||||
26
game/server/tf2/order_player.cpp
Normal file
26
game/server/tf2/order_player.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
|
||||
#include "order_player.h"
|
||||
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( COrderPlayer, DT_OrderPlayer )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
|
||||
bool COrderPlayer::UpdateOnEvent( COrderEvent_Base *pEvent )
|
||||
{
|
||||
// All player orders give up if the player disconnects
|
||||
if ( pEvent->GetType() == ORDER_EVENT_PLAYER_DISCONNECTED )
|
||||
return true;
|
||||
|
||||
return BaseClass::UpdateOnEvent( pEvent );
|
||||
}
|
||||
|
||||
32
game/server/tf2/order_player.h
Normal file
32
game/server/tf2/order_player.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ORDER_PLAYER_H
|
||||
#define ORDER_PLAYER_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "orders.h"
|
||||
|
||||
|
||||
class COrderPlayer : public COrder
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( COrderPlayer, COrder );
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
|
||||
// COrder overrides.
|
||||
public:
|
||||
|
||||
virtual bool UpdateOnEvent( COrderEvent_Base *pEvent );
|
||||
};
|
||||
|
||||
|
||||
#endif // ORDER_PLAYER_H
|
||||
157
game/server/tf2/order_repair.cpp
Normal file
157
game/server/tf2/order_repair.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "order_repair.h"
|
||||
#include "tf_team.h"
|
||||
#include "tf_class_defender.h"
|
||||
#include "order_helpers.h"
|
||||
#include "tf_obj.h"
|
||||
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( COrderRepair, DT_OrderRepair )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
static int SortFn_Defender( void *pUserData, int a, int b )
|
||||
{
|
||||
CSortBase *p = (CSortBase*)pUserData;
|
||||
|
||||
const Vector &vOrigin1 = p->m_pPlayer->GetTFTeam()->GetObject( a )->GetAbsOrigin();
|
||||
const Vector &vOrigin2 = p->m_pPlayer->GetTFTeam()->GetObject( b )->GetAbsOrigin();
|
||||
|
||||
return p->m_pPlayer->GetAbsOrigin().DistTo( vOrigin1 ) < p->m_pPlayer->GetAbsOrigin().DistTo( vOrigin2 );
|
||||
}
|
||||
|
||||
|
||||
static bool IsValidFn_RepairFriendlyObjects( void *pUserData, int a )
|
||||
{
|
||||
// Only pick objects that are damaged.
|
||||
CSortBase *p = (CSortBase*)pUserData;
|
||||
CBaseObject *pObj = p->m_pPlayer->GetTFTeam()->GetObject( a );
|
||||
|
||||
// Skip objects under construction
|
||||
if ( pObj->IsBuilding() )
|
||||
return false;
|
||||
|
||||
return ( pObj->m_iHealth < pObj->m_iMaxHealth );
|
||||
}
|
||||
|
||||
|
||||
static bool IsValidFn_RepairOwnObjects( void *pUserData, int a )
|
||||
{
|
||||
// Only pick objects that are damaged.
|
||||
CSortBase *pSortBase = (CSortBase*)pUserData;
|
||||
CBaseObject *pObj = pSortBase->m_pPlayer->GetObject(a);
|
||||
|
||||
// Skip objects under construction
|
||||
if ( !pObj || pObj->IsBuilding() )
|
||||
return false;
|
||||
|
||||
return pObj->m_iHealth < pObj->m_iMaxHealth;
|
||||
}
|
||||
|
||||
|
||||
bool COrderRepair::CreateOrder_RepairFriendlyObjects( CPlayerClassDefender *pClass )
|
||||
{
|
||||
if( !pClass->CanBuildSentryGun() )
|
||||
return false;
|
||||
|
||||
CBaseTFPlayer *pPlayer = pClass->GetPlayer();
|
||||
CTFTeam *pTeam = pClass->GetTeam();
|
||||
|
||||
// Sort the list and filter out fully healed objects..
|
||||
CSortBase info;
|
||||
info.m_pPlayer = pPlayer;
|
||||
|
||||
int sorted[MAX_TEAM_OBJECTS];
|
||||
int nSorted = BuildSortedActiveList(
|
||||
sorted,
|
||||
MAX_TEAM_OBJECTS,
|
||||
SortFn_Defender,
|
||||
IsValidFn_RepairFriendlyObjects,
|
||||
&info,
|
||||
pTeam->GetNumObjects() );
|
||||
|
||||
// If the player is close enough to the closest damaged object, issue an order.
|
||||
if( nSorted )
|
||||
{
|
||||
CBaseObject *pObjToHeal = pTeam->GetObject( sorted[0] );
|
||||
|
||||
static float flClosestDist = 1024;
|
||||
if( pPlayer->GetAbsOrigin().DistTo( pObjToHeal->GetAbsOrigin() ) < flClosestDist )
|
||||
{
|
||||
COrder *pOrder = new COrderRepair;
|
||||
|
||||
pTeam->AddOrder(
|
||||
ORDER_REPAIR,
|
||||
pObjToHeal,
|
||||
pPlayer,
|
||||
1e24,
|
||||
60,
|
||||
pOrder
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool COrderRepair::CreateOrder_RepairOwnObjects( CPlayerClass *pClass )
|
||||
{
|
||||
CSortBase info;
|
||||
info.m_pPlayer = pClass->GetPlayer();
|
||||
|
||||
int sorted[16];
|
||||
int nSorted = BuildSortedActiveList(
|
||||
sorted,
|
||||
sizeof( sorted ) / sizeof( sorted[0] ),
|
||||
SortFn_PlayerObjectsByDistance,
|
||||
IsValidFn_RepairOwnObjects,
|
||||
&info,
|
||||
info.m_pPlayer->GetObjectCount() );
|
||||
|
||||
if( nSorted )
|
||||
{
|
||||
// Make an order to repair the closest damaged object.
|
||||
CBaseObject *pObj = info.m_pPlayer->GetObject( sorted[0] );
|
||||
if (!pObj)
|
||||
return false;
|
||||
|
||||
COrderRepair *pOrder = new COrderRepair;
|
||||
info.m_pPlayer->GetTFTeam()->AddOrder(
|
||||
ORDER_REPAIR,
|
||||
pObj,
|
||||
info.m_pPlayer,
|
||||
1e24,
|
||||
60,
|
||||
pOrder
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool COrderRepair::Update()
|
||||
{
|
||||
CBaseEntity *pEnt = GetTargetEntity();
|
||||
if( !pEnt )
|
||||
return true;
|
||||
|
||||
// Kill the order when the object is repaired.
|
||||
return pEnt->m_iHealth >= pEnt->m_iMaxHealth;
|
||||
}
|
||||
|
||||
|
||||
42
game/server/tf2/order_repair.h
Normal file
42
game/server/tf2/order_repair.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ORDER_REPAIR_H
|
||||
#define ORDER_REPAIR_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "orders.h"
|
||||
|
||||
|
||||
class CPlayerClass;
|
||||
class CPlayerClassDefender;
|
||||
|
||||
|
||||
class COrderRepair : public COrder
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( COrderRepair, COrder );
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
// Create an order for the defender to fix friendly objects.
|
||||
static bool CreateOrder_RepairFriendlyObjects( CPlayerClassDefender *pClass );
|
||||
|
||||
// Create an order for anyone to repair their own objects.
|
||||
static bool CreateOrder_RepairOwnObjects( CPlayerClass *pClass );
|
||||
|
||||
|
||||
// COrder overrides.
|
||||
public:
|
||||
|
||||
virtual bool Update( void );
|
||||
};
|
||||
|
||||
|
||||
#endif // ORDER_REPAIR_H
|
||||
66
game/server/tf2/order_resourcepump.cpp
Normal file
66
game/server/tf2/order_resourcepump.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "order_resourcepump.h"
|
||||
#include "tf_team.h"
|
||||
#include "tf_obj_resourcepump.h"
|
||||
#include "tf_func_resource.h"
|
||||
#include "order_helpers.h"
|
||||
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( COrderResourcePump, DT_OrderResourcePump )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
bool COrderResourcePump::CreateOrder( CPlayerClass *pClass )
|
||||
{
|
||||
COrderResourcePump *pOrder = new COrderResourcePump;
|
||||
|
||||
if ( OrderCreator_ResourceZoneObject( pClass->GetPlayer(), OBJ_RESOURCEPUMP, pOrder ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_RemoveImmediate( pOrder );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool COrderResourcePump::Update()
|
||||
{
|
||||
// Can they still build resource pumps?
|
||||
if ( !m_hOwningPlayer.Get() || m_hOwningPlayer->CanBuild( OBJ_RESOURCEPUMP ) != CB_CAN_BUILD )
|
||||
return true;
|
||||
|
||||
// Lost our resource zone?
|
||||
if ( !GetTargetEntity() )
|
||||
return true;
|
||||
// Is our target zone now empty?
|
||||
if ( ((CResourceZone*)GetTargetEntity())->IsEmpty() )
|
||||
return true;
|
||||
|
||||
// Have they built a pump on this zone?
|
||||
for( int i=0; i < m_hOwningPlayer->GetObjectCount(); i++ )
|
||||
{
|
||||
CBaseObject *pObj = m_hOwningPlayer->GetObject(i);
|
||||
|
||||
if( pObj && pObj->GetType() == OBJ_RESOURCEPUMP )
|
||||
{
|
||||
CObjectResourcePump *pPump = (CObjectResourcePump*)pObj;
|
||||
CResourceZone *pZone = pPump->GetResourceZone();
|
||||
if( pZone && pZone->entindex() == m_iTargetEntIndex && !pZone->IsEmpty() )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return BaseClass::Update();
|
||||
}
|
||||
|
||||
|
||||
38
game/server/tf2/order_resourcepump.h
Normal file
38
game/server/tf2/order_resourcepump.h
Normal file
@@ -0,0 +1,38 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ORDER_RESOURCEPUMP_H
|
||||
#define ORDER_RESOURCEPUMP_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "orders.h"
|
||||
|
||||
|
||||
class CPlayerClass;
|
||||
|
||||
|
||||
class COrderResourcePump : public COrder
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( COrderResourcePump, COrder );
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
// Create an order for the player.
|
||||
static bool CreateOrder( CPlayerClass *pClass );
|
||||
|
||||
|
||||
// COrder overrides.
|
||||
public:
|
||||
|
||||
virtual bool Update( void );
|
||||
};
|
||||
|
||||
|
||||
#endif // ORDER_RESOURCEPUMP_H
|
||||
54
game/server/tf2/order_resupply.cpp
Normal file
54
game/server/tf2/order_resupply.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "order_resupply.h"
|
||||
#include "tf_team.h"
|
||||
#include "tf_playerclass.h"
|
||||
#include "order_helpers.h"
|
||||
|
||||
|
||||
// Orders to build resupplies near objects come in within this range.
|
||||
#define RESUPPLY_ORDER_MAXDIST 2000
|
||||
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( COrderResupply, DT_OrderResupply )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
bool COrderResupply::CreateOrder( CPlayerClass *pClass )
|
||||
{
|
||||
COrderResupply *pOrder = new COrderResupply;
|
||||
if ( OrderCreator_GenericObject( pClass, OBJ_RESUPPLY, RESUPPLY_ORDER_MAXDIST, pOrder ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UTIL_RemoveImmediate( pOrder );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool COrderResupply::Update()
|
||||
{
|
||||
CBaseEntity *pEnt = GetTargetEntity();
|
||||
if( !pEnt )
|
||||
return true;
|
||||
|
||||
if ( !m_hOwningPlayer.Get() || m_hOwningPlayer->CanBuild( OBJ_RESUPPLY ) != CB_CAN_BUILD )
|
||||
return true;
|
||||
|
||||
CTFTeam *pTeam = m_hOwningPlayer->GetTFTeam();
|
||||
if ( pTeam->GetNumResuppliesCoveringPosition( pEnt->GetAbsOrigin() ) )
|
||||
return true;
|
||||
|
||||
return BaseClass::Update();
|
||||
}
|
||||
|
||||
|
||||
38
game/server/tf2/order_resupply.h
Normal file
38
game/server/tf2/order_resupply.h
Normal file
@@ -0,0 +1,38 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ORDER_RESUPPLY_H
|
||||
#define ORDER_RESUPPLY_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "orders.h"
|
||||
|
||||
|
||||
class CPlayerClass;
|
||||
|
||||
|
||||
class COrderResupply : public COrder
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( COrderResupply, COrder );
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
// Create an order for the player.
|
||||
static bool CreateOrder( CPlayerClass *pClass );
|
||||
|
||||
|
||||
// COrder overrides.
|
||||
public:
|
||||
|
||||
virtual bool Update();
|
||||
};
|
||||
|
||||
|
||||
#endif // ORDER_RESUPPLY_H
|
||||
215
game/server/tf2/orders.cpp
Normal file
215
game/server/tf2/orders.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Order handling
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "orders.h"
|
||||
#include "tf_player.h"
|
||||
#include "tf_func_resource.h"
|
||||
#include "tf_team.h"
|
||||
#include "tf_obj_resourcepump.h"
|
||||
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST(COrder, DT_Order)
|
||||
SendPropInt( SENDINFO(m_iOrderType), 4, SPROP_UNSIGNED ),
|
||||
SendPropInt( SENDINFO(m_iTargetEntIndex), 16, SPROP_UNSIGNED ),
|
||||
END_SEND_TABLE()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( tf_order, COrder );
|
||||
|
||||
|
||||
COrder::COrder()
|
||||
{
|
||||
m_iOrderType = 0;
|
||||
m_iTargetEntIndex = 0;
|
||||
m_hTarget = NULL;
|
||||
m_flDistanceToRemove = 0;
|
||||
m_hOwningPlayer = NULL;
|
||||
m_flDieTime = 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void COrder::UpdateOnRemove( void )
|
||||
{
|
||||
DetachFromPlayer();
|
||||
// Chain at end to mimic destructor unwind order
|
||||
BaseClass::UpdateOnRemove();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Transmit weapon data
|
||||
//-----------------------------------------------------------------------------
|
||||
int COrder::ShouldTransmit( const CCheckTransmitInfo *pInfo )
|
||||
{
|
||||
CBaseEntity* pRecipientEntity = CBaseEntity::Instance( pInfo->m_pClientEnt );
|
||||
|
||||
// If this is a personal order, only send to it's owner
|
||||
if ( GetOwner() )
|
||||
{
|
||||
if ( GetOwner() == pRecipientEntity )
|
||||
return FL_EDICT_ALWAYS;
|
||||
|
||||
return FL_EDICT_DONTSEND;
|
||||
}
|
||||
|
||||
// Otherwise, only send to players on our team
|
||||
if ( InSameTeam( pRecipientEntity ) )
|
||||
return FL_EDICT_ALWAYS;
|
||||
|
||||
return FL_EDICT_DONTSEND;
|
||||
}
|
||||
|
||||
|
||||
void COrder::DetachFromPlayer()
|
||||
{
|
||||
// Detach from our owner.
|
||||
if ( m_hOwningPlayer )
|
||||
{
|
||||
m_hOwningPlayer->SetOrder( NULL );
|
||||
m_hOwningPlayer = NULL;
|
||||
|
||||
if ( GetTeam() )
|
||||
{
|
||||
((CTFTeam*)GetTeam())->RemoveOrder( this );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int COrder::GetType( void )
|
||||
{
|
||||
return m_iOrderType;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseEntity *COrder::GetTargetEntity( void )
|
||||
{
|
||||
return m_hTarget;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void COrder::SetType( int iOrderType )
|
||||
{
|
||||
m_iOrderType = iOrderType;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void COrder::SetTarget( CBaseEntity *pTarget )
|
||||
{
|
||||
m_hTarget = pTarget;
|
||||
if ( m_hTarget )
|
||||
{
|
||||
m_iTargetEntIndex = m_hTarget->entindex();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iTargetEntIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void COrder::SetDistance( float flDistance )
|
||||
{
|
||||
m_flDistanceToRemove = flDistance;
|
||||
}
|
||||
|
||||
|
||||
void COrder::SetLifetime( float flLifetime )
|
||||
{
|
||||
m_flDieTime = gpGlobals->curtime + flLifetime;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: for updates on the order. Return true if the order should be removed.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool COrder::Update( void )
|
||||
{
|
||||
// Orders with no targets & no owners don't go away on their own
|
||||
if ( !GetOwner() )
|
||||
return false;
|
||||
|
||||
// Has it timed out?
|
||||
if( gpGlobals->curtime > m_flDieTime )
|
||||
return true;
|
||||
|
||||
// Check to make sure we're still within the correct distance
|
||||
if ( m_flDistanceToRemove )
|
||||
{
|
||||
CBaseEntity *pTarget = GetTargetEntity();
|
||||
if ( pTarget )
|
||||
{
|
||||
// Have the player and the target moved away from each other?
|
||||
if ( (m_hOwningPlayer->GetAbsOrigin() - pTarget->GetAbsOrigin()).Length() > (m_flDistanceToRemove * 1.25) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: An event for this order's target has arrived. Return true if this order should be removed.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool COrder::UpdateOnEvent( COrderEvent_Base *pEvent )
|
||||
{
|
||||
// Default behavior is to get rid of the order if the object we're referencing
|
||||
// gets destroyed.
|
||||
if ( pEvent->GetType() == ORDER_EVENT_OBJECT_DESTROYED )
|
||||
{
|
||||
COrderEvent_ObjectDestroyed *pObjDestroyed = (COrderEvent_ObjectDestroyed*)pEvent;
|
||||
if ( pObjDestroyed->m_pObject == GetTargetEntity() )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseTFPlayer *COrder::GetOwner( void )
|
||||
{
|
||||
return m_hOwningPlayer;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void COrder::SetOwner( CBaseTFPlayer *pPlayer )
|
||||
{
|
||||
// Null out our m_hOwningPlayer so we don't recurse infinitely.
|
||||
CHandle<CBaseTFPlayer> hPlayer = m_hOwningPlayer;
|
||||
m_hOwningPlayer = 0;
|
||||
|
||||
if ( hPlayer.Get() && (hPlayer != pPlayer) )
|
||||
{
|
||||
Assert( hPlayer->GetOrder() == this );
|
||||
hPlayer->SetOrder( NULL );
|
||||
}
|
||||
|
||||
m_hOwningPlayer = pPlayer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
90
game/server/tf2/orders.h
Normal file
90
game/server/tf2/orders.h
Normal file
@@ -0,0 +1,90 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Order handling
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef ORDERS_H
|
||||
#define ORDERS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
class CTFTeam;
|
||||
class CBaseTFPlayer;
|
||||
|
||||
|
||||
#include "order_events.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Datatable container class for orders
|
||||
//-----------------------------------------------------------------------------
|
||||
class COrder : public CBaseEntity
|
||||
{
|
||||
DECLARE_CLASS( COrder, CBaseEntity );
|
||||
public:
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
COrder();
|
||||
virtual void UpdateOnRemove( void );
|
||||
|
||||
virtual int UpdateTransmitState() { return SetTransmitState( FL_EDICT_FULLCHECK ); }
|
||||
virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo );
|
||||
|
||||
// This is called when removing the order.
|
||||
void DetachFromPlayer();
|
||||
|
||||
|
||||
// Overridables.
|
||||
public:
|
||||
|
||||
// Purpose: for updates on the order. Return true if the order should be removed.
|
||||
virtual bool Update( void );
|
||||
virtual bool UpdateOnEvent( COrderEvent_Base *pEvent );
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
CBaseTFPlayer *GetOwner( void );
|
||||
CBaseEntity *GetTargetEntity( void );
|
||||
int GetType( void );
|
||||
|
||||
void SetOwner( CBaseTFPlayer *pPlayer );
|
||||
void SetType( int iOrderType );
|
||||
void SetTarget( CBaseEntity *pTarget );
|
||||
void SetDistance( float flDistance );
|
||||
void SetLifetime( float flLifetime );
|
||||
|
||||
public:
|
||||
// Sent via datatable
|
||||
CNetworkVar( int, m_iOrderType );
|
||||
float m_flDistanceToRemove;
|
||||
|
||||
// When the order goes away.
|
||||
double m_flDieTime;
|
||||
|
||||
// Personal order owner
|
||||
CHandle< CBaseTFPlayer > m_hOwningPlayer;
|
||||
EHANDLE m_hTarget;
|
||||
CNetworkVar( int, m_iTargetEntIndex );
|
||||
};
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// ORDER CREATION DATA
|
||||
//-----------------------------------------------------------------------------
|
||||
// Time between personal order updates
|
||||
#define PERSONAL_ORDER_UPDATE_TIME 2.0
|
||||
|
||||
// KILL orders
|
||||
#define ORDER_KILL_ENEMY_DISTANCE 2048 // Distance the enemy must be within for this player to receive this order
|
||||
|
||||
// HEAL orders
|
||||
#define ORDER_HEAL_FRIENDLY_DISTANCE 2048 // Distance the friendly must be within this player to receive this order
|
||||
|
||||
#endif // ORDERS_H
|
||||
117
game/server/tf2/ragdoll_shadow.cpp
Normal file
117
game/server/tf2/ragdoll_shadow.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Resource chunks
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "ragdoll_shadow.h"
|
||||
#include "tf_player.h"
|
||||
#include "sendproxy.h"
|
||||
|
||||
// FIXME Hook up a real player standin
|
||||
static char *sRagdollShadowModel = "models/player/human_commando.mdl";
|
||||
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( CRagdollShadow, DT_RagdollShadow )
|
||||
SendPropInt( SENDINFO( m_nPlayer ), 10, SPROP_UNSIGNED ),
|
||||
|
||||
SendPropExclude( "DT_BaseEntity", "m_angAbsRotation[0]" ),
|
||||
SendPropExclude( "DT_BaseEntity", "m_angAbsRotation[1]" ),
|
||||
SendPropExclude( "DT_BaseEntity", "m_angAbsRotation[2]" ),
|
||||
|
||||
END_SEND_TABLE()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( ragdoll_shadow, CRagdollShadow );
|
||||
PRECACHE_REGISTER( ragdoll_shadow );
|
||||
|
||||
CRagdollShadow::CRagdollShadow( void )
|
||||
{
|
||||
m_pPlayer = NULL;
|
||||
m_nPlayer = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CRagdollShadow::Spawn( )
|
||||
{
|
||||
// Init value & model
|
||||
if ( m_pPlayer )
|
||||
{
|
||||
SetModelName( m_pPlayer->GetModelName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
SetModelName( AllocPooledString( sRagdollShadowModel ) );
|
||||
}
|
||||
|
||||
BaseClass::Spawn();
|
||||
|
||||
// Create the object in the physics system
|
||||
IPhysicsObject *pPhysics = VPhysicsInitNormal( SOLID_VPHYSICS, FSOLID_NOT_SOLID, false );
|
||||
// IPhysicsObject *pPhysics = VPhysicsInitNormal( SOLID_VPHYSICS, 0, false );
|
||||
|
||||
// disable physics sounds on this object
|
||||
pPhysics->SetMaterialIndex( physprops->GetSurfaceIndex("default_silent") );
|
||||
|
||||
UTIL_SetSize( this, Vector(-36,-36, 0), Vector(36,36,72) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : **ppSendTable -
|
||||
// *recipient -
|
||||
// *pvs -
|
||||
// clientArea -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
int CRagdollShadow::ShouldTransmit( const CCheckTransmitInfo *pInfo )
|
||||
{
|
||||
// Always send to local player
|
||||
if ( Instance( pInfo->m_pClientEnt ) == GetOwnerEntity() )
|
||||
return FL_EDICT_ALWAYS;
|
||||
|
||||
return BaseClass::ShouldTransmit( pInfo );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CRagdollShadow::Precache( void )
|
||||
{
|
||||
PrecacheModel( sRagdollShadowModel );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Create a resource chunk
|
||||
//-----------------------------------------------------------------------------
|
||||
CRagdollShadow *CRagdollShadow::Create( CBaseTFPlayer *player, const Vector& force )
|
||||
{
|
||||
CRagdollShadow *pRagdollShadow = (CRagdollShadow*)CreateEntityByName("ragdoll_shadow");
|
||||
|
||||
UTIL_SetOrigin( pRagdollShadow, player->GetAbsOrigin() );
|
||||
|
||||
pRagdollShadow->m_pPlayer = player;
|
||||
pRagdollShadow->m_nPlayer = player->entindex();
|
||||
|
||||
pRagdollShadow->Spawn();
|
||||
pRagdollShadow->SetAbsVelocity( force );
|
||||
pRagdollShadow->SetLocalAngles( vec3_angle );
|
||||
pRagdollShadow->SetLocalAngularVelocity( RandomAngle( -100, 100 ) );
|
||||
|
||||
//pRagdollShadow->AddEffects( EF_NODRAW );
|
||||
pRagdollShadow->AddEffects( EF_NOSHADOW );
|
||||
|
||||
pRagdollShadow->m_lifeState = LIFE_DYING;
|
||||
|
||||
IPhysicsObject *pPhysicsObject = pRagdollShadow->VPhysicsGetObject();
|
||||
if ( pPhysicsObject )
|
||||
{
|
||||
AngularImpulse tmp;
|
||||
QAngleToAngularImpulse( pRagdollShadow->GetLocalAngularVelocity(), tmp );
|
||||
pPhysicsObject->AddVelocity( &pRagdollShadow->GetAbsVelocity(), &tmp );
|
||||
}
|
||||
|
||||
return pRagdollShadow;
|
||||
}
|
||||
43
game/server/tf2/ragdoll_shadow.h
Normal file
43
game/server/tf2/ragdoll_shadow.h
Normal file
@@ -0,0 +1,43 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef RAGDOLL_SHADOW_H
|
||||
#define RAGDOLL_SHADOW_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "props.h"
|
||||
|
||||
class CBaseTFPlayer;
|
||||
class IPhysicsObject;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A shadow object used to bound the position of a player ragdoll
|
||||
//-----------------------------------------------------------------------------
|
||||
class CRagdollShadow : public CBaseProp
|
||||
{
|
||||
DECLARE_CLASS( CRagdollShadow, CBaseProp );
|
||||
public:
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
CRagdollShadow( void ) ;
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void Precache( void );
|
||||
|
||||
virtual int UpdateTransmitState() { return SetTransmitState( FL_EDICT_FULLCHECK); }
|
||||
virtual int ShouldTransmit( const CCheckTransmitInfo *pInfo );
|
||||
|
||||
static CRagdollShadow *Create( CBaseTFPlayer *player, const Vector& force );
|
||||
|
||||
public:
|
||||
CBaseTFPlayer *m_pPlayer;
|
||||
CNetworkVar( int, m_nPlayer );
|
||||
};
|
||||
|
||||
#endif // RAGDOLL_SHADOW_H
|
||||
172
game/server/tf2/resource_chunk.cpp
Normal file
172
game/server/tf2/resource_chunk.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Resource chunks
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "tf_func_resource.h"
|
||||
#include "tf_team.h"
|
||||
#include "tf_basecombatweapon.h"
|
||||
#include "tf_obj.h"
|
||||
#include "resource_chunk.h"
|
||||
#include "vstdlib/random.h"
|
||||
#include "tf_stats.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
|
||||
ConVar resource_chunk_value( "resource_chunk_value","20", FCVAR_NONE, "Resource value of a single resource chunk." );
|
||||
ConVar resource_chunk_processed_value( "resource_chunk_processed_value","80", FCVAR_NONE, "Resource value of a single processed resource chunk." );
|
||||
|
||||
// Resource Chunk Models
|
||||
char *sResourceChunkModel = "models/resources/resource_chunk_B.mdl";
|
||||
char *sProcessedResourceChunkModel = "models/resources/processed_resource_chunk_B.mdl";
|
||||
|
||||
BEGIN_DATADESC( CResourceChunk )
|
||||
|
||||
// functions
|
||||
DEFINE_FUNCTION( ChunkTouch ),
|
||||
DEFINE_FUNCTION( ChunkRemove ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST( CResourceChunk, DT_ResourceChunk )
|
||||
END_SEND_TABLE()
|
||||
|
||||
LINK_ENTITY_TO_CLASS( resource_chunk, CResourceChunk );
|
||||
PRECACHE_REGISTER( resource_chunk );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Remove me from any lists I'm in when I'm deleted
|
||||
//-----------------------------------------------------------------------------
|
||||
void CResourceChunk::UpdateOnRemove( void )
|
||||
{
|
||||
if ( m_hZone )
|
||||
{
|
||||
m_hZone->RemoveChunk( this, false );
|
||||
m_hZone = NULL;
|
||||
}
|
||||
|
||||
// Chain at end to mimic destructor unwind order
|
||||
BaseClass::UpdateOnRemove();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CResourceChunk::Spawn( )
|
||||
{
|
||||
// Init model
|
||||
if ( IsProcessed() )
|
||||
{
|
||||
SetModelName( AllocPooledString( sProcessedResourceChunkModel ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
SetModelName( AllocPooledString( sResourceChunkModel ) );
|
||||
}
|
||||
|
||||
BaseClass::Spawn();
|
||||
|
||||
UTIL_SetSize( this, Vector(-4,-4,-4), Vector(4,4,4) );
|
||||
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
|
||||
SetSolid( SOLID_BBOX );
|
||||
AddSolidFlags( FSOLID_TRIGGER );
|
||||
CollisionProp()->UseTriggerBounds( true, 24 );
|
||||
SetCollisionGroup( TFCOLLISION_GROUP_RESOURCE_CHUNK );
|
||||
SetGravity( 1.0 );
|
||||
SetFriction( 1 );
|
||||
SetTouch( ChunkTouch );
|
||||
SetThink( ChunkRemove );
|
||||
SetNextThink( gpGlobals->curtime + random->RandomFloat( 50.0, 80.0 ) ); // Remove myself the
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CResourceChunk::Precache( void )
|
||||
{
|
||||
PrecacheModel( sResourceChunkModel );
|
||||
PrecacheModel( sProcessedResourceChunkModel );
|
||||
PrecacheModel( "sprites/redglow1.vmt" );
|
||||
|
||||
PrecacheScriptSound( "ResourceChunk.Pickup" );
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Create a resource chunk
|
||||
//-----------------------------------------------------------------------------
|
||||
CResourceChunk *CResourceChunk::Create( bool bProcessed, const Vector &vecOrigin, const Vector &vecVelocity )
|
||||
{
|
||||
CResourceChunk *pChunk = (CResourceChunk*)CreateEntityByName("resource_chunk");
|
||||
|
||||
UTIL_SetOrigin( pChunk, vecOrigin );
|
||||
pChunk->m_bIsProcessed = bProcessed;
|
||||
pChunk->m_bBeingCollected = false;
|
||||
pChunk->Spawn();
|
||||
pChunk->SetAbsVelocity( vecVelocity );
|
||||
pChunk->SetLocalAngularVelocity( RandomAngle( -100, 100 ) );
|
||||
pChunk->SetLocalAngles( vec3_angle );
|
||||
|
||||
return pChunk;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: If we're picked up by another pla`yer, give resources to that team
|
||||
//-----------------------------------------------------------------------------
|
||||
void CResourceChunk::ChunkTouch( CBaseEntity *pOther )
|
||||
{
|
||||
if ( pOther->IsPlayer() || pOther->GetServerVehicle() )
|
||||
{
|
||||
// Give the team the resources
|
||||
int iAmountPerPlayer = ((CTFTeam *)pOther->GetTeam())->AddTeamResources( GetResourceValue(), TF_PLAYER_STAT_RESOURCES_ACQUIRED_FROM_CHUNKS );
|
||||
TFStats()->IncrementTeamStat( pOther->GetTeamNumber(), TF_TEAM_STAT_RESOURCE_CHUNKS_COLLECTED, GetResourceValue() );
|
||||
|
||||
pOther->EmitSound( "ResourceChunk.Pickup" );
|
||||
|
||||
// Tell the player
|
||||
CSingleUserRecipientFilter user( (CBasePlayer*)pOther );
|
||||
UserMessageBegin( user, "PickupRes" );
|
||||
WRITE_BYTE( iAmountPerPlayer );
|
||||
MessageEnd();
|
||||
|
||||
// Tell our zone to remove this chunk from it's list
|
||||
if ( m_hZone )
|
||||
{
|
||||
m_hZone->RemoveChunk( this, false );
|
||||
m_hZone = NULL;
|
||||
}
|
||||
|
||||
// Remove this chunk
|
||||
SetTouch( NULL );
|
||||
UTIL_Remove( this );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Remove myself if I'm not being harvested
|
||||
//-----------------------------------------------------------------------------
|
||||
void CResourceChunk::ChunkRemove( void )
|
||||
{
|
||||
// Remove this chunk
|
||||
if ( m_hZone )
|
||||
{
|
||||
m_hZone->RemoveChunk( this, true );
|
||||
m_hZone = NULL;
|
||||
}
|
||||
UTIL_Remove( this );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return the resource value of this chunk
|
||||
//-----------------------------------------------------------------------------
|
||||
float CResourceChunk::GetResourceValue( void )
|
||||
{
|
||||
// Init value & model
|
||||
if ( IsProcessed() )
|
||||
return resource_chunk_processed_value.GetFloat();
|
||||
|
||||
return resource_chunk_value.GetFloat();
|
||||
}
|
||||
52
game/server/tf2/resource_chunk.h
Normal file
52
game/server/tf2/resource_chunk.h
Normal file
@@ -0,0 +1,52 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef RESOURCE_CHUNK_H
|
||||
#define RESOURCE_CHUNK_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "props.h"
|
||||
|
||||
class CResourceZone;
|
||||
|
||||
extern ConVar resource_chunk_value;
|
||||
extern ConVar resource_chunk_processed_value;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A resource chunk that's harvestable by a player
|
||||
//-----------------------------------------------------------------------------
|
||||
class CResourceChunk : public CBaseProp
|
||||
{
|
||||
DECLARE_CLASS( CResourceChunk, CBaseProp );
|
||||
public:
|
||||
DECLARE_DATADESC();
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void Precache( void );
|
||||
virtual void UpdateOnRemove( void );
|
||||
|
||||
void ChunkTouch( CBaseEntity *pOther );
|
||||
void ChunkRemove( void );
|
||||
|
||||
virtual bool IsStandable( const CBaseEntity *pStander ) { return true; } // can pStander stand on this entity?
|
||||
virtual bool IsProcessed( void ) { return m_bIsProcessed; };
|
||||
|
||||
float GetResourceValue( void );
|
||||
|
||||
static CResourceChunk *Create( bool bProcessed, const Vector &vecOrigin, const Vector &vecVelocity );
|
||||
|
||||
public:
|
||||
CHandle<CResourceZone> m_hZone;
|
||||
bool m_bIsProcessed;
|
||||
bool m_bBeingCollected;
|
||||
};
|
||||
|
||||
#endif // RESOURCE_CHUNK_H
|
||||
139
game/server/tf2/sensor_tf_team.cpp
Normal file
139
game/server/tf2/sensor_tf_team.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Definitions of all the entities that control logic flow within a map
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "EntityInput.h"
|
||||
#include "EntityOutput.h"
|
||||
#include "tf_team.h"
|
||||
#include "tf_obj.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Detects a bunch of tf team state
|
||||
//-----------------------------------------------------------------------------
|
||||
class CSensorTFTeam : public CLogicalEntity
|
||||
{
|
||||
DECLARE_CLASS( CSensorTFTeam, CLogicalEntity );
|
||||
|
||||
public:
|
||||
void Spawn( void );
|
||||
void Think( void );
|
||||
|
||||
private:
|
||||
DECLARE_DATADESC();
|
||||
|
||||
// Computes the number of respawns stations on the sensed team
|
||||
int ComputeRespawnCount();
|
||||
|
||||
// outputs
|
||||
COutputInt m_OnRespawnCountChanged;
|
||||
COutputInt m_OnResourceCountChanged;
|
||||
COutputInt m_OnMemberCountChanged;
|
||||
COutputInt m_OnRespawnCountChangedDelta;
|
||||
COutputInt m_OnResourceCountChangedDelta;
|
||||
COutputInt m_OnMemberCountChangedDelta;
|
||||
|
||||
// What team am I sensing?
|
||||
int m_nTeam;
|
||||
CTFTeam *m_pTeam;
|
||||
|
||||
// So we can know when state changes...
|
||||
int m_nRespawnCount;
|
||||
int m_nResourceCount;
|
||||
int m_nMemberCount;
|
||||
};
|
||||
|
||||
|
||||
LINK_ENTITY_TO_CLASS( sensor_tf_team, CSensorTFTeam );
|
||||
|
||||
|
||||
BEGIN_DATADESC( CSensorTFTeam )
|
||||
|
||||
DEFINE_OUTPUT( m_OnRespawnCountChanged, "OnRespawnCountChanged" ),
|
||||
DEFINE_OUTPUT( m_OnResourceCountChanged, "OnResourceCountChanged" ),
|
||||
DEFINE_OUTPUT( m_OnMemberCountChanged, "OnMemberCountChanged" ),
|
||||
DEFINE_OUTPUT( m_OnRespawnCountChangedDelta, "OnRespawnCountChangedDelta" ),
|
||||
DEFINE_OUTPUT( m_OnResourceCountChangedDelta, "OnResourceCountChangedDelta" ),
|
||||
DEFINE_OUTPUT( m_OnMemberCountChangedDelta, "OnMemberCountChangedDelta" ),
|
||||
DEFINE_KEYFIELD( m_nTeam, FIELD_INTEGER, "team"),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Spawn!
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSensorTFTeam::Spawn( void )
|
||||
{
|
||||
// Hook us up to a team...
|
||||
m_pTeam = GetGlobalTFTeam( m_nTeam );
|
||||
|
||||
// Gets us thinkin!
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
|
||||
// Force an output message on our first think
|
||||
m_nRespawnCount = -1;
|
||||
m_nResourceCount = -1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Compute the number of respawn stations on this team
|
||||
//-----------------------------------------------------------------------------
|
||||
int CSensorTFTeam::ComputeRespawnCount()
|
||||
{
|
||||
int nCount = 0;
|
||||
for (int i = m_pTeam->GetNumObjects(); --i >= 0; )
|
||||
{
|
||||
CBaseObject *pObject = m_pTeam->GetObject(i);
|
||||
if ( pObject && (pObject->GetType() == OBJ_RESPAWN_STATION) )
|
||||
{
|
||||
++nCount;
|
||||
}
|
||||
}
|
||||
return nCount;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Forces a recompare
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSensorTFTeam::Think( )
|
||||
{
|
||||
if (!m_pTeam)
|
||||
return;
|
||||
|
||||
// Check for a difference in the number of respawn stations
|
||||
int nRespawnCount = ComputeRespawnCount();
|
||||
if ( nRespawnCount != m_nRespawnCount )
|
||||
{
|
||||
m_OnRespawnCountChangedDelta.Set( nRespawnCount - m_nRespawnCount, this, this );
|
||||
m_nRespawnCount = nRespawnCount;
|
||||
m_OnRespawnCountChanged.Set( m_nRespawnCount, this, this );
|
||||
}
|
||||
|
||||
// Check for a difference in the number of resources harvested
|
||||
if ( m_nResourceCount != m_pTeam->m_flTotalResourcesSoFar )
|
||||
{
|
||||
m_OnResourceCountChangedDelta.Set( m_pTeam->m_flTotalResourcesSoFar - m_nResourceCount, this, this );
|
||||
m_nResourceCount = m_pTeam->m_flTotalResourcesSoFar;
|
||||
m_OnResourceCountChanged.Set( m_nResourceCount, this, this );
|
||||
}
|
||||
|
||||
// Check for a difference in the number of team members
|
||||
if ( m_nMemberCount != m_pTeam->GetNumPlayers() )
|
||||
{
|
||||
m_OnMemberCountChangedDelta.Set( m_pTeam->GetNumPlayers() - m_nMemberCount, this, this );
|
||||
m_nMemberCount = m_pTeam->GetNumPlayers();
|
||||
m_OnMemberCountChanged.Set( m_nMemberCount, this, this );
|
||||
}
|
||||
|
||||
SetNextThink( gpGlobals->curtime + 0.1f );
|
||||
}
|
||||
|
||||
110
game/server/tf2/team_messages.cpp
Normal file
110
game/server/tf2/team_messages.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "player.h"
|
||||
#include "tf_team.h"
|
||||
#include "team_messages.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Create the right class of message based upon the type
|
||||
//-----------------------------------------------------------------------------
|
||||
CTeamMessage *CTeamMessage::Create( CTFTeam *pTeam, int iMessageID, CBaseEntity *pEntity )
|
||||
{
|
||||
CTeamMessage *pMessage = NULL;
|
||||
|
||||
// Create the right type
|
||||
switch ( iMessageID )
|
||||
{
|
||||
// Sound orders
|
||||
case TEAMMSG_REINFORCEMENTS_ARRIVED:
|
||||
pMessage = new CTeamMessage_Sound( pTeam, iMessageID, pEntity, 5.0 );
|
||||
((CTeamMessage_Sound*)pMessage)->SetSound( "TeamMessage.Reinforcements" );
|
||||
break;
|
||||
case TEAMMSG_CARRIER_UNDER_ATTACK:
|
||||
pMessage = new CTeamMessage_Sound( pTeam, iMessageID, pEntity, 10.0 );
|
||||
((CTeamMessage_Sound*)pMessage)->SetSound( "TeamMessage.CarrierAttacked" );
|
||||
break;
|
||||
case TEAMMSG_CARRIER_DESTROYED:
|
||||
pMessage = new CTeamMessage_Sound( pTeam, iMessageID, pEntity, 10.0 );
|
||||
((CTeamMessage_Sound*)pMessage)->SetSound( "TeamMessage.CarrierDestroyed" );
|
||||
break;
|
||||
case TEAMMSG_HARVESTER_UNDER_ATTACK:
|
||||
pMessage = new CTeamMessage_Sound( pTeam, iMessageID, pEntity, 10.0 );
|
||||
((CTeamMessage_Sound*)pMessage)->SetSound( "TeamMessage.HarvesterAttacked" );
|
||||
break;
|
||||
case TEAMMSG_HARVESTER_DESTROYED:
|
||||
pMessage = new CTeamMessage_Sound( pTeam, iMessageID, pEntity, 10.0 );
|
||||
((CTeamMessage_Sound*)pMessage)->SetSound( "TeamMessage.HarvesterDestroyed" );
|
||||
break;
|
||||
case TEAMMSG_NEW_TECH_LEVEL_OPEN:
|
||||
pMessage = new CTeamMessage_Sound( pTeam, iMessageID, pEntity, 10.0 );
|
||||
((CTeamMessage_Sound*)pMessage)->SetSound( "TeamMessage.NewTechLevel" );
|
||||
break;
|
||||
case TEAMMSG_RESOURCE_ZONE_EMPTIED:
|
||||
pMessage = new CTeamMessage_Sound( pTeam, iMessageID, pEntity, 10.0 );
|
||||
((CTeamMessage_Sound*)pMessage)->SetSound( "TeamMessage.ResourceZoneEmpty" );
|
||||
break;
|
||||
case TEAMMSG_CUSTOM_SOUND:
|
||||
pMessage = new CTeamMessage_Sound( pTeam, iMessageID, pEntity, 10.0 );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return pMessage;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CTeamMessage::CTeamMessage( CTFTeam *pTeam, int iMessageID, CBaseEntity *pEntity, float flTTL )
|
||||
{
|
||||
m_pTeam = pTeam;
|
||||
m_iMessageID = iMessageID;
|
||||
m_hEntity = pEntity;
|
||||
m_flTTL = gpGlobals->curtime + flTTL;
|
||||
}
|
||||
|
||||
|
||||
//===============================================================================================================
|
||||
// TEAM MESSAGE SOUND
|
||||
//===============================================================================================================
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CTeamMessage_Sound::CTeamMessage_Sound( CTFTeam *pTeam, int iMessageID, CBaseEntity *pEntity, float flTTL ) :
|
||||
CTeamMessage( pTeam, iMessageID, pEntity, flTTL )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTeamMessage_Sound::SetSound( char *sSound )
|
||||
{
|
||||
CBaseEntity::PrecacheScriptSound( sSound );
|
||||
m_SoundName = sSound;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when the team manager wants me to fire myself
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTeamMessage_Sound::FireMessage( void )
|
||||
{
|
||||
Assert( m_SoundName.String() );
|
||||
|
||||
// Play my sound to all the team's members
|
||||
for ( int i = 0; i < m_pTeam->GetNumPlayers(); i++ )
|
||||
{
|
||||
CBasePlayer *pPlayer = m_pTeam->GetPlayer(i);
|
||||
|
||||
CSingleUserRecipientFilter filter( pPlayer );
|
||||
CBaseEntity::EmitSound( filter, pPlayer->entindex(), m_SoundName.String() );
|
||||
}
|
||||
}
|
||||
83
game/server/tf2/team_messages.h
Normal file
83
game/server/tf2/team_messages.h
Normal file
@@ -0,0 +1,83 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TEAM_MESSAGES_H
|
||||
#define TEAM_MESSAGES_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "utlsymbol.h"
|
||||
|
||||
// Message IDs
|
||||
enum
|
||||
{
|
||||
// Reinforcements
|
||||
TEAMMSG_REINFORCEMENTS_ARRIVED,
|
||||
|
||||
// Carriers / Harvesters
|
||||
TEAMMSG_CARRIER_UNDER_ATTACK,
|
||||
TEAMMSG_CARRIER_DESTROYED,
|
||||
TEAMMSG_HARVESTER_UNDER_ATTACK,
|
||||
TEAMMSG_HARVESTER_DESTROYED,
|
||||
|
||||
// Resources
|
||||
TEAMMSG_RESOURCE_ZONE_EMPTIED,
|
||||
|
||||
// Techtree
|
||||
TEAMMSG_NEW_TECH_LEVEL_OPEN,
|
||||
|
||||
// Custom sounds
|
||||
TEAMMSG_CUSTOM_SOUND,
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Message sent to a team for the purpose of updating its members about some event
|
||||
//-----------------------------------------------------------------------------
|
||||
abstract_class CTeamMessage
|
||||
{
|
||||
public:
|
||||
CTeamMessage( CTFTeam *pTeam, int iMessageID, CBaseEntity *pEntity, float flTTL );
|
||||
|
||||
static CTeamMessage *Create( CTFTeam *pTeam, int iMessageID, CBaseEntity *pEntity );
|
||||
|
||||
// Called when the team manager wants me to fire myself
|
||||
virtual void FireMessage( void ) = 0;
|
||||
|
||||
// Accessors
|
||||
virtual int GetID( void ) { return m_iMessageID; };
|
||||
virtual float GetTTL( void ) { return m_flTTL; };
|
||||
virtual CBaseEntity *GetEntity( void ) { return m_hEntity; };
|
||||
virtual CTFTeam *GetTeam( void ) { return m_pTeam; };
|
||||
|
||||
virtual void SetData( char *pszData ) { return; }
|
||||
|
||||
protected:
|
||||
int m_iMessageID;
|
||||
float m_flTTL;
|
||||
EHANDLE m_hEntity;
|
||||
CTFTeam *m_pTeam;
|
||||
CUtlSymbol m_SoundName;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Team message that plays a sound to the members of the team
|
||||
//-----------------------------------------------------------------------------
|
||||
class CTeamMessage_Sound : public CTeamMessage
|
||||
{
|
||||
public:
|
||||
CTeamMessage_Sound( CTFTeam *pTeam, int iMessageID, CBaseEntity *pEntity, float flTTL );
|
||||
|
||||
// Set my sound
|
||||
virtual void SetSound( char *sSound );
|
||||
// Called when the team manager wants me to fire myself
|
||||
virtual void FireMessage( void );
|
||||
|
||||
virtual void SetData( char *pszData ) { SetSound( pszData ); }
|
||||
};
|
||||
|
||||
#endif // TEAM_MESSAGES_H
|
||||
168
game/server/tf2/tf_accuracy.cpp
Normal file
168
game/server/tf2/tf_accuracy.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: TF2 Accuracy system
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "player.h"
|
||||
#include "tf_player.h"
|
||||
#include "basecombatweapon.h"
|
||||
#include "vstdlib/random.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// THIS ISN'T USED ANYMORE. NO REASON TO MAKE OUR HITSCAN WPNS THIS COMPLEX
|
||||
|
||||
|
||||
|
||||
|
||||
// Accuracy is measured as the weapons spread in inches at 1024 units (~85 feet)
|
||||
// Accuracy is sent to the client, where it's used to generate the size of the accuracy representation.
|
||||
// Accuracy is a "floating" value, in that it's always moving towards a target accuracy, and takes some time to change
|
||||
|
||||
// Accuracy Multipliers
|
||||
// < 1 increases accuracy, > 1 decreases
|
||||
#define ACCMULT_DUCKING 0.75 // Player is ducking
|
||||
#define ACCMULT_RUNNING 1.25 // Player is moving >50% of his max speed
|
||||
|
||||
// Ricochet Multiplier
|
||||
// This works differently to other acc multipliers.
|
||||
#define ACCMULT_RICOCHET 1.0 // Player is being suppressed by bullet fire
|
||||
#define ACC_RICOCHET_TIME 1.0 // Amount of time accuracy is affected by a ricochet near the player
|
||||
#define ACC_RICOCHET_MULTIPLE 0.25 // The effect of ricochets on accuracy is multiplied by this by the number of ricochets nearby
|
||||
#define ACC_RICOCHET_CAP 10 // Maximum number of bullets to register for suppression fire
|
||||
|
||||
#define ACCURACY_CHANGE_SPEED 5
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Calculates the players "accuracy" level
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFPlayer::CalculateAccuracy( void )
|
||||
{
|
||||
static flLastTime = 0;
|
||||
|
||||
// Get the time since the last calculation
|
||||
float flTimeSlice = (gpGlobals->curtime - flLastTime);
|
||||
m_flTargetAccuracy = 0;
|
||||
|
||||
if ( !GetPlayerClass() )
|
||||
return;
|
||||
|
||||
// Get the base accuracy from the current weapon
|
||||
if ( m_hActiveWeapon )
|
||||
{
|
||||
m_flTargetAccuracy = m_hActiveWeapon->GetAccuracy();
|
||||
|
||||
// Accuracy is increased if the player's crouching
|
||||
if ( GetFlags() & FL_DUCKING )
|
||||
m_flTargetAccuracy *= m_hActiveWeapon->GetDuckingMultiplier();
|
||||
|
||||
// Accuracy is decreased if the player's moving
|
||||
if ( m_vecVelocity.Length2D() > ( GetPlayerClass()->GetMaxSpeed() * 0.5 ) )
|
||||
m_flTargetAccuracy *= m_hActiveWeapon->GetRunningMultiplier();
|
||||
}
|
||||
|
||||
// Accuracy is decreased if the player's arms are injured
|
||||
|
||||
// Accuracy is increased if there's an Officer nearby
|
||||
|
||||
// Accuracy is decreased if this player's being supressed (bullets/explosions impacting nearby)
|
||||
float flFarTime = (m_flLastRicochetNearby + ACC_RICOCHET_TIME);
|
||||
if ( gpGlobals->curtime <= flFarTime )
|
||||
m_flTargetAccuracy *= 1 + (m_flNumberOfRicochets * ACC_RICOCHET_MULTIPLE) * (ACCMULT_RICOCHET * ((flFarTime - gpGlobals->curtime) / ACC_RICOCHET_TIME));
|
||||
|
||||
// Accuracy is decreased if the player's just been hit by a bullet/explosion
|
||||
|
||||
// Now float towards the target accuracy
|
||||
if ( m_bSnapAccuracy )
|
||||
{
|
||||
m_bSnapAccuracy = false;
|
||||
m_flAccuracy = m_flTargetAccuracy;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_flAccuracy < m_flTargetAccuracy )
|
||||
{
|
||||
m_flAccuracy += (flTimeSlice * ACCURACY_CHANGE_SPEED);
|
||||
if ( m_flAccuracy > m_flTargetAccuracy )
|
||||
m_flAccuracy = m_flTargetAccuracy ;
|
||||
}
|
||||
else if ( m_flAccuracy > m_flTargetAccuracy )
|
||||
{
|
||||
m_flAccuracy -= (flTimeSlice * ACCURACY_CHANGE_SPEED);
|
||||
if ( m_flAccuracy < m_flTargetAccuracy )
|
||||
m_flAccuracy = m_flTargetAccuracy ;
|
||||
}
|
||||
}
|
||||
|
||||
// Clip to prevent silly accuracies
|
||||
if ( m_flAccuracy > 1024 )
|
||||
m_flAccuracy = 1024;
|
||||
|
||||
flLastTime = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Snap the players accuracy immediately
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFPlayer::SnapAccuracy( void )
|
||||
{
|
||||
m_bSnapAccuracy = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return the player's current accuracy
|
||||
//-----------------------------------------------------------------------------
|
||||
float CBaseTFPlayer::GetAccuracy( void )
|
||||
{
|
||||
return m_flAccuracy;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Bullets / Explosions are hitting near the player. Reduce his/her accuracy.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFPlayer::Supress( void )
|
||||
{
|
||||
if ( gpGlobals->curtime <= (m_flLastRicochetNearby + ACC_RICOCHET_TIME) )
|
||||
{
|
||||
m_flNumberOfRicochets = MIN( ACC_RICOCHET_CAP, m_flNumberOfRicochets + 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_flNumberOfRicochets = 1;
|
||||
}
|
||||
|
||||
m_flLastRicochetNearby = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
Vector CBaseTFPlayer::GenerateFireVector( Vector *viewVector )
|
||||
{
|
||||
// Calculate the weapon spread from the player's accuracy
|
||||
float flAcc = (GetAccuracy() * 0.5) / ACCURACY_DISTANCE;
|
||||
float flAccuracyAngle = RAD2DEG( atan( flAcc ) );
|
||||
// If the user passed in a viewVector, use it, otherwise use player's v_angle
|
||||
Vector angShootAngles = viewVector ? *viewVector : pl->v_angle;
|
||||
if ( flAccuracyAngle )
|
||||
{
|
||||
float x, y, z;
|
||||
do {
|
||||
x = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5);
|
||||
y = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5);
|
||||
z = x*x+y*y;
|
||||
} while (z > 1);
|
||||
|
||||
angShootAngles.x = UTIL_AngleMod( angShootAngles.x + (x * flAccuracyAngle) );
|
||||
angShootAngles.y = UTIL_AngleMod( angShootAngles.y + (y * flAccuracyAngle) );
|
||||
}
|
||||
|
||||
Vector forward;
|
||||
AngleVectors( angShootAngles, &forward );
|
||||
return forward;
|
||||
}
|
||||
34
game/server/tf2/tf_ai_hint.h
Normal file
34
game/server/tf2/tf_ai_hint.h
Normal file
@@ -0,0 +1,34 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TF_AI_HINT_H
|
||||
#define TF_AI_HINT_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//=========================================================
|
||||
// hints - these MUST coincide with the HINTS listed under
|
||||
// info_node in the FGD file!
|
||||
//=========================================================
|
||||
enum TF_Hint_e
|
||||
{
|
||||
HINT_RESOURCE_ZONE_AREA = 2000,
|
||||
|
||||
// The carrier starts at base_area land spot, goes first to
|
||||
// the hover spot, then goes to the dropoff hover spot and
|
||||
// finally to the dropoff landspot
|
||||
HINT_AIR_CARRIER_DROPOFF_POINT_LANDSPOT,
|
||||
HINT_AIR_CARRIER_DROPOFF_POINT_HOVERSPOT,
|
||||
HINT_AIR_CARRIER_BASE_AREA_LANDSPOT,
|
||||
HINT_AIR_CARRIER_BASE_AREA_HOVERSPOT,
|
||||
|
||||
// The ground collector needs hints to drive itself
|
||||
HINT_GROUNDCOLLECTOR_ZONE_ENTRANCE,
|
||||
};
|
||||
|
||||
#endif // TF_AI_HINT_H
|
||||
137
game/server/tf2/tf_basecombatweapon.cpp
Normal file
137
game/server/tf2/tf_basecombatweapon.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Base TF Combat weapon
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "animation.h"
|
||||
#include "tf_player.h"
|
||||
#include "tf_basecombatweapon.h"
|
||||
#include "soundent.h"
|
||||
#include "weapon_twohandedcontainer.h"
|
||||
#include "tf_gamerules.h"
|
||||
#include "tf_obj.h"
|
||||
|
||||
//====================================================================================================
|
||||
// BASE TF MACHINEGUN
|
||||
//====================================================================================================
|
||||
IMPLEMENT_SERVERCLASS_ST(CTFMachineGun, DT_TFMachineGun )
|
||||
END_SEND_TABLE()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTFMachineGun::PrimaryAttack( void )
|
||||
{
|
||||
// Only the player fires this way so we can cast
|
||||
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
|
||||
if (!pPlayer)
|
||||
return;
|
||||
|
||||
// Abort here to handle burst and auto fire modes
|
||||
if ( (GetMaxClip1() != -1 && m_iClip1 == 0) || (GetMaxClip1() == -1 && !pPlayer->GetAmmoCount(m_iPrimaryAmmoType) ) )
|
||||
return;
|
||||
|
||||
pPlayer->DoMuzzleFlash();
|
||||
|
||||
|
||||
// To make the firing framerate independent, we may have to fire more than one bullet here on low-framerate systems,
|
||||
// especially if the weapon we're firing has a really fast rate of fire.
|
||||
if ( GetSequence() != SelectWeightedSequence( ACT_VM_PRIMARYATTACK ))
|
||||
{
|
||||
m_flNextPrimaryAttack = gpGlobals->curtime;
|
||||
}
|
||||
int iBulletsToFire = 0;
|
||||
float fireRate = GetFireRate();
|
||||
|
||||
while ( m_flNextPrimaryAttack <= gpGlobals->curtime )
|
||||
{
|
||||
// MUST call sound before removing a round from the clip of a CMachineGun
|
||||
WeaponSound(SINGLE, m_flNextPrimaryAttack);
|
||||
m_flNextPrimaryAttack = m_flNextPrimaryAttack + fireRate;
|
||||
iBulletsToFire++;
|
||||
}
|
||||
|
||||
// Make sure we don't fire more than the amount in the clip, if this weapon uses clips
|
||||
if ( GetMaxClip1() != -1 )
|
||||
{
|
||||
if ( iBulletsToFire > m_iClip1 )
|
||||
iBulletsToFire = m_iClip1;
|
||||
m_iClip1 -= iBulletsToFire;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( iBulletsToFire > pPlayer->GetAmmoCount(m_iPrimaryAmmoType) )
|
||||
iBulletsToFire = pPlayer->GetAmmoCount(m_iPrimaryAmmoType);
|
||||
pPlayer->RemoveAmmo( iBulletsToFire, m_iPrimaryAmmoType );
|
||||
}
|
||||
|
||||
// Not time to fire any bullets yet?
|
||||
if ( !iBulletsToFire )
|
||||
return;
|
||||
|
||||
// Fire the bullets
|
||||
Vector vecSrc = pPlayer->Weapon_ShootPosition( );
|
||||
Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES );
|
||||
|
||||
// Factor in the view kick
|
||||
AddViewKick();
|
||||
|
||||
float range = m_pRangeCVar ? m_pRangeCVar->GetFloat() : 1024.0f;
|
||||
|
||||
if ( !m_pRangeCVar )
|
||||
{
|
||||
Msg( "Weapon missing m_pRangeCVar!!!\n" );
|
||||
}
|
||||
|
||||
FireBullets( this, iBulletsToFire, vecSrc, vecAiming, GetBulletSpread(), range, m_iPrimaryAmmoType, 2 );
|
||||
|
||||
if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
|
||||
{
|
||||
// HEV suit - indicate out of ammo condition
|
||||
pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
|
||||
}
|
||||
|
||||
PlayAttackAnimation( GetPrimaryAttackActivity() );
|
||||
|
||||
// Register a muzzleflash for the AI
|
||||
pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 0.5 );
|
||||
|
||||
CheckRemoveDisguise();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
const Vector& CTFMachineGun::GetBulletSpread( void )
|
||||
{
|
||||
static Vector cone = VECTOR_CONE_3DEGREES;
|
||||
return cone;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CTFMachineGun::FireBullets( CBaseTFCombatWeapon *pWeapon, int cShots, const Vector &vecSrc, const Vector &vecDirShooting, const Vector &vecSpread, float flDistance, int iBulletType, int iTracerFreq)
|
||||
{
|
||||
if ( CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetOwner() )
|
||||
{
|
||||
float damage = m_pDamageCVar ? m_pDamageCVar->GetFloat() : 1;
|
||||
|
||||
if ( !m_pDamageCVar )
|
||||
{
|
||||
Msg( "Weapon missing m_pDamageCVar!!!!\n" );
|
||||
}
|
||||
|
||||
TFGameRules()->FireBullets( CTakeDamageInfo( this, pPlayer, damage, DMG_BULLET ), cShots, vecSrc, vecDirShooting, vecSpread, flDistance, iBulletType, 4, entindex(), 0 );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
float CTFMachineGun::GetFireRate( void )
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
39
game/server/tf2/tf_basecombatweapon.h
Normal file
39
game/server/tf2/tf_basecombatweapon.h
Normal file
@@ -0,0 +1,39 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: TF's derived BaseCombatWeapon
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TF_BASECOMBATWEAPON_H
|
||||
#define TF_BASECOMBATWEAPON_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "baseplayer_shared.h"
|
||||
#include "basetfplayer_shared.h"
|
||||
#include "basetfcombatweapon_shared.h"
|
||||
|
||||
class CBaseObject;
|
||||
class CBaseTechnology;
|
||||
class CBaseTFPlayer;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Base TF Machinegun
|
||||
//-----------------------------------------------------------------------------
|
||||
class CTFMachineGun : public CBaseTFCombatWeapon
|
||||
{
|
||||
DECLARE_CLASS( CTFMachineGun, CBaseTFCombatWeapon );
|
||||
public:
|
||||
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
virtual void PrimaryAttack( void );
|
||||
virtual void FireBullets( CBaseTFCombatWeapon *pWeapon, int cShots, const Vector &vecSrc, const Vector &vecDirShooting, const Vector &vecSpread, float flDistance, int iBulletType, int iTracerFreq);
|
||||
virtual const Vector& GetBulletSpread( void );
|
||||
virtual float GetFireRate( void );
|
||||
};
|
||||
|
||||
#endif // TF_BASECOMBATWEAPON_H
|
||||
|
||||
762
game/server/tf2/tf_basefourwheelvehicle.cpp
Normal file
762
game/server/tf2/tf_basefourwheelvehicle.cpp
Normal file
@@ -0,0 +1,762 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A moving vehicle that is used as a battering ram
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "tf_basefourwheelvehicle.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "soundenvelope.h"
|
||||
#include "vcollide_parse.h"
|
||||
#include "in_buttons.h"
|
||||
#include "tf_movedata.h"
|
||||
|
||||
#define BASEFOURWHEELEDVEHICLE_THINK_CONTEXT "BaseFourWheeledThink"
|
||||
#define BASEFOURWHEELEDVEHICLE_DEPLOYTHINK_CONTEXT "BaseFourWheeledDeployThink"
|
||||
// HACK HAC
|
||||
#define BASEFOURWHEELEDVEHICLE_STOPTHERODEO_CONTEXT "BaseFourWheeledVehicleStopTheRodeoMadnessThink"
|
||||
|
||||
ConVar road_feel( "road_feel", "0.1", FCVAR_NOTIFY | FCVAR_REPLICATED );
|
||||
extern ConVar tf_fastbuild;
|
||||
|
||||
BEGIN_DATADESC( CBaseTFFourWheelVehicle )
|
||||
|
||||
DEFINE_EMBEDDED( m_VehiclePhysics ),
|
||||
|
||||
DEFINE_INPUTFUNC( FIELD_FLOAT, "Throttle", InputThrottle ),
|
||||
DEFINE_INPUTFUNC( FIELD_FLOAT, "Steer", InputSteering ),
|
||||
DEFINE_INPUTFUNC( FIELD_FLOAT, "Action", InputAction ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ),
|
||||
|
||||
END_DATADESC()
|
||||
|
||||
|
||||
// Used for debugging to make vehicle deploying go really fast.
|
||||
ConVar tf_fastdeploy( "tf_fastdeploy", "0", FCVAR_CHEAT );
|
||||
|
||||
|
||||
IMPLEMENT_SERVERCLASS_ST(CBaseTFFourWheelVehicle, DT_BaseTFFourWheelVehicle)
|
||||
SendPropFloat( SENDINFO( m_flDeployFinishTime ), 0, SPROP_NOSCALE ),
|
||||
SendPropInt( SENDINFO( m_eDeployMode ), NUM_VEHICLE_DEPLOYMODE_BITS, SPROP_UNSIGNED ),
|
||||
SendPropInt( SENDINFO( m_bBoostUpgrade ), 1, SPROP_UNSIGNED ),
|
||||
SendPropInt( SENDINFO( m_nBoostTimeLeft ), 8, SPROP_UNSIGNED ),
|
||||
END_SEND_TABLE()
|
||||
|
||||
ConVar fourwheelvehicle_hit_damage( "fourwheelvehicle_hit_damage","40", FCVAR_NONE, "Four-wheel vehicle hit damage" );
|
||||
ConVar fourwheelvehicle_hit_damage_boostmod( "fourwheelvehicle_hit_damage_boostmod", "1.5", FCVAR_NONE, "Four-wheel vehicle boosted hit damage modifier" );
|
||||
ConVar fourwheelvehicle_hit_mindamagevel( "fourwheelvehicle_hit_mindamagevel","100", FCVAR_NONE, "Four-wheel vehciel hit velocity for min damage" );
|
||||
ConVar fourwheelvehicle_hit_maxdamagevel( "fourwheelvehicle_hit_maxdamagevel","230", FCVAR_NONE, "Four-wheel vehicle hit velocity for max damage" );
|
||||
ConVar fourwheelvehicle_impact_time( "fourwheelvehicle_impact_time", "1.0", FCVAR_NONE, "Four-wheel vehicle impact wait time." );
|
||||
ConVar fourwheelvehicle_hit_damage_player( "fourwheelvehicle_hit_damage_player", "30.0f", FCVAR_NONE, "Four-wheel vehicle hit player damage." );
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
#pragma warning( disable: 4355 )
|
||||
CBaseTFFourWheelVehicle::CBaseTFFourWheelVehicle() : m_VehiclePhysics(this)
|
||||
{
|
||||
m_flDeployFinishTime = -1;
|
||||
}
|
||||
#pragma warning( default: 4355 )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CBaseTFFourWheelVehicle::~CBaseTFFourWheelVehicle ()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Put a vehicle in a deploy state. Turn off the engine and run a
|
||||
// deploy animation.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseTFFourWheelVehicle::Deploy( void )
|
||||
{
|
||||
// Make sure we're allowed to deploy here
|
||||
if ( !IsReadyToDrive() )
|
||||
return false;
|
||||
|
||||
// Check to see if we are already in a deploy mode.
|
||||
if ( m_eDeployMode != VEHICLE_MODE_NORMAL )
|
||||
return false;
|
||||
|
||||
// Disable the vehicle's motion.
|
||||
DisableMotion();
|
||||
|
||||
// Save pre-deploy activity.
|
||||
m_PreDeployActivity = GetActivity();
|
||||
|
||||
// Set the deploying activity - ACT_DEPLOY
|
||||
SetActivity( ACT_DEPLOY );
|
||||
|
||||
// Get the deployment time.
|
||||
float flDeployTime = SequenceDuration();
|
||||
if ( tf_fastdeploy.GetBool() )
|
||||
flDeployTime = 1;
|
||||
|
||||
m_flDeployFinishTime = gpGlobals->curtime + flDeployTime;
|
||||
|
||||
SetContextThink( BaseFourWheeledVehicleDeployThink, gpGlobals->curtime + flDeployTime,
|
||||
BASEFOURWHEELEDVEHICLE_DEPLOYTHINK_CONTEXT );
|
||||
|
||||
// Set the deploy mode.
|
||||
m_eDeployMode = VEHICLE_MODE_DEPLOYING;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Release a vehicle from a deployed state. Run a de-coupling
|
||||
// animation and turn on the vehicle.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::UnDeploy( void )
|
||||
{
|
||||
// Make sure we are deployed.
|
||||
if ( !IsDeployed() )
|
||||
return;
|
||||
|
||||
// Enable motion and turn on the vehicle.
|
||||
EnableMotion();
|
||||
|
||||
// Set the undeploying activity - ACT_UNDEPLOY
|
||||
SetActivity( ACT_UNDEPLOY );
|
||||
|
||||
// Get the undeployment time.
|
||||
float flUnDeployTime = SequenceDuration();
|
||||
if ( tf_fastdeploy.GetBool() )
|
||||
flUnDeployTime = 1;
|
||||
|
||||
m_flDeployFinishTime = gpGlobals->curtime + flUnDeployTime;
|
||||
|
||||
SetContextThink( BaseFourWheeledVehicleDeployThink, gpGlobals->curtime + flUnDeployTime,
|
||||
BASEFOURWHEELEDVEHICLE_DEPLOYTHINK_CONTEXT );
|
||||
|
||||
// Set the deploy mode.
|
||||
m_eDeployMode = VEHICLE_MODE_UNDEPLOYING;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::CancelDeploy( void )
|
||||
{
|
||||
// Check for the deploying state.
|
||||
if ( !IsDeploying() )
|
||||
return;
|
||||
|
||||
// Re-enable the motion.
|
||||
EnableMotion();
|
||||
|
||||
// Reset the activity to the previous activity.
|
||||
SetActivity( m_PreDeployActivity );
|
||||
|
||||
// Reset the deploy mode.
|
||||
m_eDeployMode = VEHICLE_MODE_NORMAL;
|
||||
|
||||
m_flDeployFinishTime = -1;
|
||||
|
||||
// Turn off the context think.
|
||||
SetContextThink( NULL, 0, BASEFOURWHEELEDVEHICLE_DEPLOYTHINK_CONTEXT );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::BaseFourWheeledVehicleDeployThink( void )
|
||||
{
|
||||
// Called from deploy.
|
||||
if ( IsDeploying() )
|
||||
{
|
||||
OnFinishedDeploy();
|
||||
m_flDeployFinishTime = -1;
|
||||
}
|
||||
// Called from undeploy.
|
||||
else if ( IsUndeploying() )
|
||||
{
|
||||
OnFinishedUnDeploy();
|
||||
m_flDeployFinishTime = -1;
|
||||
}
|
||||
|
||||
// Turn off the context think.
|
||||
SetContextThink( NULL, 0, BASEFOURWHEELEDVEHICLE_DEPLOYTHINK_CONTEXT );
|
||||
}
|
||||
|
||||
void CBaseTFFourWheelVehicle::BaseFourWheeledVehicleStopTheRodeoMadnessThink( void )
|
||||
{
|
||||
// HACK HACK: See note above at FinishBuilding call
|
||||
// This resets the handbrake, so the newly placed object doesn't roll down any hills.
|
||||
m_VehiclePhysics.ResetControls();
|
||||
|
||||
// Turn off the context think.
|
||||
SetContextThink( NULL, 0, BASEFOURWHEELEDVEHICLE_STOPTHERODEO_CONTEXT );
|
||||
|
||||
// Start our base think
|
||||
SetContextThink( BaseFourWheeledVehicleThink, gpGlobals->curtime + 0.1, BASEFOURWHEELEDVEHICLE_THINK_CONTEXT );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::OnFinishedDeploy( void )
|
||||
{
|
||||
SetActivity( ACT_DEPLOY_IDLE );
|
||||
m_eDeployMode = VEHICLE_MODE_DEPLOYED;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::OnFinishedUnDeploy( void )
|
||||
{
|
||||
m_eDeployMode = VEHICLE_MODE_NORMAL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Allow the vehicle to move.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::EnableMotion( void )
|
||||
{
|
||||
// Enable vehicle chasis motion.
|
||||
IPhysicsObject *pVehicleObject = VPhysicsGetObject();
|
||||
if ( pVehicleObject )
|
||||
{
|
||||
pVehicleObject->EnableMotion( true );
|
||||
}
|
||||
|
||||
// Enable motion on the tires.
|
||||
m_VehiclePhysics.EnableMotion();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Dis-allow the vehicle to move.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::DisableMotion( void )
|
||||
{
|
||||
// Disable vehicle chasis motion.
|
||||
IPhysicsObject *pVehicleObject = VPhysicsGetObject();
|
||||
if ( pVehicleObject )
|
||||
{
|
||||
pVehicleObject->EnableMotion( false );
|
||||
}
|
||||
|
||||
// Disable motion on the tires.
|
||||
m_VehiclePhysics.DisableMotion();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Precache
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::Precache()
|
||||
{
|
||||
BaseClass::Precache();
|
||||
|
||||
PrecacheScriptSound( "BaseTFFourWheelVehicle.EMP" );
|
||||
PrecacheScriptSound( "BaseTFFourWheelVehicle.RamSound" );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Spawn
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::Spawn( )
|
||||
{
|
||||
SetModel( STRING( GetModelName() ) );
|
||||
// CFourWheelServerVehicle *pServerVehicle = dynamic_cast<CFourWheelServerVehicle*>(GetServerVehicle());
|
||||
// m_VehiclePhysics.SetOuter( this, pServerVehicle );
|
||||
m_VehiclePhysics.Spawn();
|
||||
BaseClass::Spawn();
|
||||
// The base class spawn sets a default collision group, so this needs to
|
||||
// be called post.
|
||||
SetCollisionGroup( COLLISION_GROUP_VEHICLE );
|
||||
|
||||
m_eDeployMode = VEHICLE_MODE_NORMAL;
|
||||
|
||||
SetBoostUpgrade( false );
|
||||
|
||||
m_flNextHitTime = 0.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Teleport
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity )
|
||||
{
|
||||
// We basically just have to make sure the wheels are in the right place
|
||||
// after teleportation occurs
|
||||
matrix3x4_t startMatrixInv;
|
||||
MatrixInvert( EntityToWorldTransform(), startMatrixInv );
|
||||
|
||||
BaseClass::Teleport( newPosition, newAngles, newVelocity );
|
||||
|
||||
// Teleport the vehicle physics from the starting position to the ending one
|
||||
matrix3x4_t relativeTransform;
|
||||
ConcatTransforms( EntityToWorldTransform(), startMatrixInv, relativeTransform );
|
||||
m_VehiclePhysics.Teleport( relativeTransform );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Debugging methods
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::DrawDebugGeometryOverlays()
|
||||
{
|
||||
if (m_debugOverlays & OVERLAY_BBOX_BIT)
|
||||
{
|
||||
m_VehiclePhysics.DrawDebugGeometryOverlays();
|
||||
}
|
||||
BaseClass::DrawDebugGeometryOverlays();
|
||||
}
|
||||
|
||||
int CBaseTFFourWheelVehicle::DrawDebugTextOverlays()
|
||||
{
|
||||
int nOffset = BaseClass::DrawDebugTextOverlays();
|
||||
if (m_debugOverlays & OVERLAY_TEXT_BIT)
|
||||
{
|
||||
nOffset = m_VehiclePhysics.DrawDebugTextOverlays( nOffset );
|
||||
}
|
||||
return nOffset;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseTFFourWheelVehicle::StartBuilding( CBaseEntity *pPlayer )
|
||||
{
|
||||
if (!BaseClass::StartBuilding(pPlayer))
|
||||
return false;
|
||||
|
||||
// Until we're finished building, turn off vphysics-based motion
|
||||
SetSolid( SOLID_VPHYSICS );
|
||||
VPhysicsInitStatic();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::FinishedBuilding( void )
|
||||
{
|
||||
BaseClass::FinishedBuilding();
|
||||
|
||||
char pScriptName[128];
|
||||
Q_snprintf( pScriptName, sizeof( pScriptName ), "scripts/vehicles/%s.txt", GetClassname() );
|
||||
m_VehiclePhysics.Initialize( pScriptName, true );
|
||||
|
||||
// HACK HACK: This is a hack to avoid physics spazzing out on a newly created vehicle with the handbrake
|
||||
// set. We create and activate it, but then release the handbrake for a single Think function call and
|
||||
// then zero out the controls right then. This seems to stabilize something in the physics simulator.
|
||||
m_VehiclePhysics.ReleaseHandbrake();
|
||||
SetContextThink( BaseFourWheeledVehicleStopTheRodeoMadnessThink, gpGlobals->curtime, BASEFOURWHEELEDVEHICLE_STOPTHERODEO_CONTEXT );
|
||||
|
||||
ResetDeteriorationTime();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Input methods
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::InputThrottle( inputdata_t &inputdata )
|
||||
{
|
||||
m_VehiclePhysics.SetThrottle( inputdata.value.Float() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::InputSteering( inputdata_t &inputdata )
|
||||
{
|
||||
m_VehiclePhysics.SetSteering( inputdata.value.Float(), 2*gpGlobals->frametime );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::InputAction( inputdata_t &inputdata )
|
||||
{
|
||||
m_VehiclePhysics.SetAction( inputdata.value.Float() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::InputTurnOn( inputdata_t &inputdata )
|
||||
{
|
||||
if (!m_VehiclePhysics.IsOn())
|
||||
{
|
||||
SetContextThink( BaseFourWheeledVehicleThink, gpGlobals->curtime + 0.1, BASEFOURWHEELEDVEHICLE_THINK_CONTEXT );
|
||||
m_VehiclePhysics.TurnOn( );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::InputTurnOff( inputdata_t &inputdata )
|
||||
{
|
||||
if ( m_VehiclePhysics.IsOn() )
|
||||
{
|
||||
m_VehiclePhysics.TurnOff( );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Input methods
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::BaseFourWheeledVehicleThink()
|
||||
{
|
||||
if (m_VehiclePhysics.Think())
|
||||
{
|
||||
SetNextThink( gpGlobals->curtime, BASEFOURWHEELEDVEHICLE_THINK_CONTEXT );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::VPhysicsUpdate( IPhysicsObject *pPhysics )
|
||||
{
|
||||
// must be a wheel
|
||||
if (!m_VehiclePhysics.VPhysicsUpdate(pPhysics))
|
||||
return;
|
||||
|
||||
BaseClass::VPhysicsUpdate( pPhysics );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Methods related to getting in and out of the vehicle
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::SetPassenger( int nRole, CBasePlayer *pEnt )
|
||||
{
|
||||
if ( nRole == VEHICLE_ROLE_DRIVER )
|
||||
{
|
||||
if (pEnt)
|
||||
{
|
||||
PlayerControlInit( ToBasePlayer(pEnt) );
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerControlShutdown( );
|
||||
}
|
||||
}
|
||||
BaseClass::SetPassenger( nRole, pEnt );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::PlayerControlInit( CBasePlayer *pPlayer )
|
||||
{
|
||||
// Blat out the view offset
|
||||
m_savedViewOffset = pPlayer->GetViewOffset();
|
||||
pPlayer->SetViewOffset( vec3_origin );
|
||||
|
||||
m_playerOn.FireOutput( pPlayer, this, 0 );
|
||||
InputTurnOn( inputdata_t() );
|
||||
|
||||
// Release the handbrake.
|
||||
if ( !IsDeployed() )
|
||||
{
|
||||
m_VehiclePhysics.ReleaseHandbrake();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::ResetUseKey( CBasePlayer *pPlayer )
|
||||
{
|
||||
pPlayer->m_afButtonPressed &= ~IN_USE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::PlayerControlShutdown()
|
||||
{
|
||||
CBasePlayer *pPlayer = GetDriverPlayer();
|
||||
if ( !pPlayer )
|
||||
return;
|
||||
|
||||
ResetUseKey( pPlayer );
|
||||
pPlayer->SetViewOffset( m_savedViewOffset );
|
||||
|
||||
m_playerOff.FireOutput( pPlayer, this, 0 );
|
||||
// clear out the fire buttons
|
||||
m_attackaxis.Set( 0, pPlayer, this );
|
||||
m_attack2axis.Set( 0, pPlayer, this );
|
||||
|
||||
InputTurnOff( inputdata_t() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Powerup has just started
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::PowerupStart( int iPowerup, float flAmount, CBaseEntity *pAttacker, CDamageModifier *pDamageModifier )
|
||||
{
|
||||
switch( iPowerup )
|
||||
{
|
||||
case POWERUP_EMP:
|
||||
m_VehiclePhysics.SetMaxThrottle( 0.1 );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
BaseClass::PowerupStart( iPowerup, flAmount, pAttacker, pDamageModifier );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Powerup has just started
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::PowerupEnd( int iPowerup )
|
||||
{
|
||||
switch ( iPowerup )
|
||||
{
|
||||
case POWERUP_EMP:
|
||||
m_VehiclePhysics.SetMaxThrottle( 1.0 );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
BaseClass::PowerupEnd( iPowerup );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Methods related to actually driving the vehicle
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::DriveVehicle( CBasePlayer *pPlayer, CUserCmd *ucmd )
|
||||
{
|
||||
// Lose control when the player dies
|
||||
if ( pPlayer->IsAlive() == false )
|
||||
return;
|
||||
|
||||
// Only the driver gets to drive.
|
||||
int nRole = GetPassengerRole( pPlayer );
|
||||
if ( nRole != VEHICLE_ROLE_DRIVER )
|
||||
return;
|
||||
|
||||
// No driving in the mothership, kids
|
||||
if ( !tf_fastbuild.GetInt() && !IsReadyToDrive() )
|
||||
{
|
||||
m_VehiclePhysics.SetHandbrake( true );
|
||||
m_VehiclePhysics.SetThrottle( 0 );
|
||||
m_VehiclePhysics.SetSteering( 0, 0 );
|
||||
m_attackaxis.Set( 0, pPlayer, this );
|
||||
m_attack2axis.Set( 0, pPlayer, this );
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the boost time.
|
||||
m_nBoostTimeLeft = m_VehiclePhysics.BoostTimeLeft();
|
||||
|
||||
// If the vehicle's emped, it can't drive
|
||||
if ( HasPowerup( POWERUP_EMP ) )
|
||||
{
|
||||
// Play sounds if they're trying to drive
|
||||
if ( ucmd->buttons & (IN_MOVELEFT | IN_MOVERIGHT | IN_FORWARD | IN_BACK) )
|
||||
{
|
||||
if ( m_flNextEmpSound < gpGlobals->curtime )
|
||||
{
|
||||
EmitSound( "BaseTFFourWheelVehicle.EMP" );
|
||||
m_flNextEmpSound = gpGlobals->curtime + 2.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ResetDeteriorationTime();
|
||||
|
||||
m_VehiclePhysics.UpdateDriverControls( ucmd, TICK_INTERVAL );
|
||||
|
||||
float attack = 0, attack2 = 0;
|
||||
|
||||
if ( pPlayer->m_afButtonPressed & IN_ATTACK )
|
||||
{
|
||||
m_pressedAttack.FireOutput( pPlayer, this, 0 );
|
||||
}
|
||||
if ( pPlayer->m_afButtonPressed & IN_ATTACK2 )
|
||||
{
|
||||
m_pressedAttack2.FireOutput( pPlayer, this, 0 );
|
||||
}
|
||||
|
||||
if ( ucmd->buttons & IN_ATTACK )
|
||||
{
|
||||
attack = 1;
|
||||
}
|
||||
if ( ucmd->buttons & IN_ATTACK2 )
|
||||
{
|
||||
attack2 = 1;
|
||||
}
|
||||
|
||||
m_attackaxis.Set( attack, pPlayer, this );
|
||||
m_attack2axis.Set( attack2, pPlayer, this );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::SetupMove( CBasePlayer *pPlayer, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move )
|
||||
{
|
||||
BaseClass::SetupMove( pPlayer, ucmd, pHelper, move );
|
||||
|
||||
if ( IsDeployed() )
|
||||
return;
|
||||
|
||||
DriveVehicle( pPlayer, ucmd );
|
||||
m_nMovementRole = GetPassengerRole( pPlayer );
|
||||
Assert( m_nMovementRole >= 0 );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::SetBoostUpgrade( bool bBoostUpgrade )
|
||||
{
|
||||
m_bBoostUpgrade = bBoostUpgrade;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseTFFourWheelVehicle::IsBoostable( void )
|
||||
{
|
||||
return m_bBoostUpgrade;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::StartBoost( void )
|
||||
{
|
||||
if ( IsBoostable() )
|
||||
{
|
||||
m_VehiclePhysics.SetBoost( 1.0f );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseTFFourWheelVehicle::IsBoosting( void )
|
||||
{
|
||||
return m_VehiclePhysics.IsBoosting();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Vehicle damage!
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBaseTFFourWheelVehicle::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent )
|
||||
{
|
||||
BaseClass::VPhysicsCollision( index, pEvent );
|
||||
|
||||
int otherIndex = !index;
|
||||
CBaseEntity *pEntity = pEvent->pEntities[otherIndex];
|
||||
|
||||
// We only damage objects...
|
||||
// And only if we're travelling fast enough...
|
||||
Assert( pEntity );
|
||||
if ( !pEntity->IsSolid() )
|
||||
return;
|
||||
|
||||
// Ignore shields..
|
||||
if ( pEntity->GetCollisionGroup() == TFCOLLISION_GROUP_SHIELD )
|
||||
return;
|
||||
|
||||
// Ignore anything that's not an object
|
||||
if ( pEntity->Classify() != CLASS_MILITARY && !pEntity->IsPlayer() )
|
||||
return;
|
||||
|
||||
// Ignore teammates
|
||||
if ( InSameTeam( pEntity ))
|
||||
return;
|
||||
|
||||
// Ignore invulnerable stuff
|
||||
if ( pEntity->m_takedamage == DAMAGE_NO )
|
||||
return;
|
||||
|
||||
// See if we can damage again? (Time-based)
|
||||
if ( m_flNextHitTime > gpGlobals->curtime )
|
||||
return;
|
||||
|
||||
// Do damage based on velocity.
|
||||
Vector vecVelocity = pEvent->preVelocity[index];
|
||||
|
||||
CTakeDamageInfo info;
|
||||
info.SetInflictor( this );
|
||||
info.SetAttacker( GetDriverPlayer() );
|
||||
info.SetDamageType( DMG_CLUB );
|
||||
|
||||
float flMaxDamage = fourwheelvehicle_hit_damage.GetFloat();
|
||||
float flMaxDamageVel = fourwheelvehicle_hit_maxdamagevel.GetFloat();
|
||||
float flMinDamageVel = fourwheelvehicle_hit_mindamagevel.GetFloat();
|
||||
|
||||
float flVel = vecVelocity.Length();
|
||||
if ( flVel < flMinDamageVel )
|
||||
return;
|
||||
|
||||
EmitSound( "BaseTFFourWheelVehicle.RamSound" );
|
||||
|
||||
float flDamageFactor = flMaxDamage;
|
||||
// Special damage for players.
|
||||
if ( pEntity->IsPlayer() )
|
||||
{
|
||||
flDamageFactor = fourwheelvehicle_hit_damage_player.GetFloat();
|
||||
|
||||
if ( IsBoosting() )
|
||||
{
|
||||
flDamageFactor *= 4.0f;
|
||||
}
|
||||
|
||||
// Knock the player up into the air
|
||||
float flForceScale = (flVel*0.5) * 75 * 4;
|
||||
Vector vecForce = vecVelocity;
|
||||
VectorNormalize( vecForce );
|
||||
vecForce.z += 0.7;
|
||||
vecForce *= flForceScale;
|
||||
info.SetDamageForce( vecForce );
|
||||
}
|
||||
// Damage to objects.
|
||||
else
|
||||
{
|
||||
if ( IsBoosting() )
|
||||
{
|
||||
flDamageFactor *= fourwheelvehicle_hit_damage_boostmod.GetFloat();
|
||||
}
|
||||
|
||||
if ( ( flMaxDamageVel > flMinDamageVel ) && ( flVel < flMaxDamageVel ) )
|
||||
{
|
||||
// Use less damage when we're not moving fast enough
|
||||
float flVelocityFactor = ( flVel - flMinDamageVel ) / ( flMaxDamageVel - flMinDamageVel );
|
||||
flVelocityFactor *= flVelocityFactor;
|
||||
flDamageFactor *= flVelocityFactor;
|
||||
}
|
||||
}
|
||||
|
||||
info.SetDamage( flDamageFactor );
|
||||
Vector damagePos;
|
||||
pEvent->pInternalData->GetContactPoint( damagePos );
|
||||
Vector damageForce = pEvent->postVelocity[index] * pEvent->pObjects[index]->GetMass();
|
||||
info.SetDamageForce( damageForce );
|
||||
info.SetDamagePosition( damagePos );
|
||||
PhysCallbackDamage( pEntity, info, *pEvent, index );
|
||||
|
||||
// Set next time hit time
|
||||
m_flNextHitTime = gpGlobals->curtime + fourwheelvehicle_impact_time.GetFloat();
|
||||
}
|
||||
138
game/server/tf2/tf_basefourwheelvehicle.h
Normal file
138
game/server/tf2/tf_basefourwheelvehicle.h
Normal file
@@ -0,0 +1,138 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: A base class that deals with four-wheel vehicles
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TF_BASE_FOUR_WHEEL_VEHICLE_H
|
||||
#define TF_BASE_FOUR_WHEEL_VEHICLE_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "basetfvehicle.h"
|
||||
#include "vphysics/vehicles.h"
|
||||
#include "fourwheelvehiclephysics.h"
|
||||
#include "tf_vehicleshared.h"
|
||||
|
||||
class CMoveData;
|
||||
|
||||
class CBaseTFFourWheelVehicle : public CBaseTFVehicle
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CBaseTFFourWheelVehicle, CBaseTFVehicle );
|
||||
DECLARE_SERVERCLASS();
|
||||
|
||||
public:
|
||||
CBaseTFFourWheelVehicle();
|
||||
~CBaseTFFourWheelVehicle ();
|
||||
|
||||
// CBaseEntity
|
||||
void Spawn();
|
||||
void Precache();
|
||||
void VPhysicsUpdate( IPhysicsObject *pPhysics );
|
||||
void DrawDebugGeometryOverlays();
|
||||
int DrawDebugTextOverlays();
|
||||
void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity );
|
||||
void BaseFourWheeledVehicleThink();
|
||||
void BaseFourWheeledVehicleDeployThink( void );
|
||||
|
||||
// HACK HACK: This is a hack to avoid physics spazzing out on a newly created vehicle with the handbrake
|
||||
// set. We create and activate it, but then release the handbrake for a single Think function call and
|
||||
// then zero out the controls right then. This seems to stabilize something in the physics simulator.
|
||||
void BaseFourWheeledVehicleStopTheRodeoMadnessThink( void );
|
||||
|
||||
virtual bool StartBuilding( CBaseEntity *pPlayer );
|
||||
virtual void FinishedBuilding( void );
|
||||
|
||||
virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move );
|
||||
virtual void ProcessMovement( CBasePlayer *pPlayer, CMoveData *pMoveData );
|
||||
virtual void SetPassenger( int nRole, CBasePlayer *pEnt );
|
||||
|
||||
// Powerup handling
|
||||
virtual void PowerupStart( int iPowerup, float flAmount, CBaseEntity *pAttacker, CDamageModifier *pDamageModifier );
|
||||
virtual void PowerupEnd( int iPowerup );
|
||||
|
||||
// Collision
|
||||
virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent );
|
||||
|
||||
// Inputs
|
||||
void InputThrottle( inputdata_t &inputdata );
|
||||
void InputSteering( inputdata_t &inputdata );
|
||||
void InputAction( inputdata_t &inputdata );
|
||||
void InputTurnOn( inputdata_t &inputdata );
|
||||
void InputTurnOff( inputdata_t &inputdata );
|
||||
|
||||
// Boost
|
||||
void SetBoostUpgrade( bool bBoostUpgrade );
|
||||
bool IsBoostable( void );
|
||||
bool IsBoosting( void );
|
||||
void StartBoost( void );
|
||||
|
||||
bool IsDeployed( void ) { return ( m_eDeployMode == VEHICLE_MODE_DEPLOYED ); }
|
||||
bool IsDeploying( void ) { return ( m_eDeployMode == VEHICLE_MODE_DEPLOYING ); }
|
||||
bool IsUndeploying( void ) { return ( m_eDeployMode == VEHICLE_MODE_UNDEPLOYING ); }
|
||||
bool InDeployMode( void ) { return ( m_eDeployMode != VEHICLE_MODE_NORMAL ); }
|
||||
|
||||
DECLARE_DATADESC();
|
||||
|
||||
// locals
|
||||
protected:
|
||||
// engine sounds
|
||||
void SoundInit();
|
||||
void SoundShutdown();
|
||||
void SoundUpdate( const vehicle_operatingparams_t ¶ms, const vehicleparams_t &vehicle );
|
||||
void CalcWheelData( vehicleparams_t &vehicle );
|
||||
void ResetControls();
|
||||
|
||||
// Deploy
|
||||
bool Deploy( void );
|
||||
void UnDeploy( void );
|
||||
void CancelDeploy( void );
|
||||
virtual void OnFinishedDeploy( void );
|
||||
virtual void OnFinishedUnDeploy( void );
|
||||
|
||||
private:
|
||||
void DriveVehicle( CBasePlayer *pPlayer, CUserCmd *ucmd );
|
||||
void PlayerControlInit( CBasePlayer *pPlayer );
|
||||
void PlayerControlShutdown();
|
||||
void ResetUseKey( CBasePlayer *pPlayer );
|
||||
void InitializePoseParameters();
|
||||
bool ParseVehicleScript( solid_t &solid, vehicleparams_t &vehicle );
|
||||
|
||||
void EnableMotion( void );
|
||||
void DisableMotion( void );
|
||||
|
||||
private:
|
||||
CFourWheelVehiclePhysics m_VehiclePhysics;
|
||||
COutputEvent m_playerOn;
|
||||
COutputEvent m_playerOff;
|
||||
|
||||
COutputEvent m_pressedAttack;
|
||||
COutputEvent m_pressedAttack2;
|
||||
|
||||
COutputFloat m_attackaxis;
|
||||
COutputFloat m_attack2axis;
|
||||
|
||||
int m_nMovementRole;
|
||||
Vector m_savedViewOffset; //[MAX_PASSENGERS];
|
||||
|
||||
float m_flNextEmpSound;
|
||||
|
||||
// Deploy
|
||||
CNetworkVar( VehicleModeDeploy_e, m_eDeployMode );
|
||||
Activity m_PreDeployActivity;
|
||||
|
||||
// Used for vgui screens on the client.
|
||||
CNetworkVar( float, m_flDeployFinishTime );
|
||||
CNetworkVar( bool, m_bBoostUpgrade );
|
||||
CNetworkVar( int, m_nBoostTimeLeft );
|
||||
|
||||
float m_flNextHitTime;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // TF_BASE_FOUR_WHEEL_VEHICLE_H
|
||||
1
game/server/tf2/tf_carrier.cpp
Normal file
1
game/server/tf2/tf_carrier.cpp
Normal file
@@ -0,0 +1 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
1
game/server/tf2/tf_carrier.h
Normal file
1
game/server/tf2/tf_carrier.h
Normal file
@@ -0,0 +1 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
586
game/server/tf2/tf_class_commando.cpp
Normal file
586
game/server/tf2/tf_class_commando.cpp
Normal file
@@ -0,0 +1,586 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: The Commando Player Class
|
||||
//
|
||||
// $Workfile: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "tf_player.h"
|
||||
#include "tf_class_commando.h"
|
||||
#include "tf_vehicle_teleport_station.h"
|
||||
#include "EntityList.h"
|
||||
#include "basecombatweapon.h"
|
||||
#include "weapon_builder.h"
|
||||
#include "tf_obj.h"
|
||||
#include "tf_obj_rallyflag.h"
|
||||
#include "tf_team.h"
|
||||
#include "order_assist.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "weapon_twohandedcontainer.h"
|
||||
#include "weapon_combatshield.h"
|
||||
|
||||
ConVar tf_knockdowntime( "tf_knockdowntime", "3", FCVAR_NONE, "Length of time knocked-down players remain on the ground." );
|
||||
|
||||
// Adrenalin
|
||||
ConVar class_commando_speed( "class_commando_speed","200", FCVAR_NONE, "Commando movement speed." );
|
||||
ConVar class_commando_rush_length( "class_commando_rush_length","10", FCVAR_NONE, "Commando's adrenalin rush length in seconds." );
|
||||
ConVar class_commando_rush_recharge( "class_commando_rush_recharge","60", FCVAR_NONE, "Commando's adrenalin rush recharge time in seconds." );
|
||||
|
||||
ConVar class_commando_battlecry_radius( "class_commando_battlecry_radius","512", FCVAR_NONE, "Commando's battlecry radius." );
|
||||
ConVar class_commando_battlecry_length( "class_commando_battlecry_length","10", FCVAR_NONE, "Length of adrenalin rush given by the Commando's battlecry in seconds." );
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Commando Data Table
|
||||
//
|
||||
BEGIN_SEND_TABLE_NOBASE( CPlayerClassCommando, DT_PlayerClassCommandoData )
|
||||
SendPropInt ( SENDINFO_STRUCTELEM( m_ClassData.m_bCanBullRush ), 1, SPROP_UNSIGNED ),
|
||||
SendPropInt ( SENDINFO_STRUCTELEM( m_ClassData.m_bBullRush ), 1, SPROP_UNSIGNED ),
|
||||
SendPropVector ( SENDINFO_STRUCTELEM( m_ClassData.m_vecBullRushDir ), -1, SPROP_COORD ),
|
||||
SendPropVector ( SENDINFO_STRUCTELEM( m_ClassData.m_vecBullRushViewDir ), -1, SPROP_COORD ),
|
||||
SendPropVector ( SENDINFO_STRUCTELEM( m_ClassData.m_vecBullRushViewGoalDir ), -1, SPROP_COORD ),
|
||||
SendPropFloat ( SENDINFO_STRUCTELEM( m_ClassData.m_flBullRushTime ), 32, SPROP_NOSCALE ),
|
||||
SendPropFloat ( SENDINFO_STRUCTELEM( m_ClassData.m_flDoubleTapForwardTime ), 32, SPROP_NOSCALE ),
|
||||
END_SEND_TABLE()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : const char
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CPlayerClassCommando::GetClassModelString( int nTeam )
|
||||
{
|
||||
if (nTeam == TEAM_HUMANS)
|
||||
return "models/player/human_commando.mdl";
|
||||
else
|
||||
return "models/player/alien_commando.mdl";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPlayerClassCommando::CPlayerClassCommando( CBaseTFPlayer *pPlayer, TFClass iClass ) : CPlayerClass( pPlayer, iClass )
|
||||
{
|
||||
for (int i = 0; i < MAX_TF_TEAMS; ++i)
|
||||
{
|
||||
SetClassModel( MAKE_STRING(GetClassModelString(i)), i );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPlayerClassCommando::~CPlayerClassCommando()
|
||||
{
|
||||
m_aHitPlayers.RemoveAll();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::ClassActivate( void )
|
||||
{
|
||||
BaseClass::ClassActivate();
|
||||
|
||||
// Setup movement data.
|
||||
SetupMoveData();
|
||||
|
||||
// Initialize the shared class data.
|
||||
m_ClassData.m_bCanBullRush = false;
|
||||
m_ClassData.m_bBullRush = false;
|
||||
m_ClassData.m_vecBullRushDir.Init();
|
||||
m_ClassData.m_vecBullRushViewDir.Init();
|
||||
m_ClassData.m_vecBullRushViewGoalDir.Init();
|
||||
m_ClassData.m_flBullRushTime = COMMANDO_TIME_INVALID;
|
||||
m_ClassData.m_flDoubleTapForwardTime = COMMANDO_TIME_INVALID;
|
||||
|
||||
m_bCanRush = false;
|
||||
m_bPersonalRush = false;
|
||||
m_bHasBattlecry = false;
|
||||
m_bCanBoot = false;
|
||||
m_flNextBootCheck = 0.0f; // Time at which to recheck for the automatic melee attack
|
||||
m_bOldBullRush = 0.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::ClassDeactivate( void )
|
||||
{
|
||||
m_hWpnShield = NULL;
|
||||
m_hWpnPlasma = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::CreateClass( void )
|
||||
{
|
||||
BaseClass::CreateClass();
|
||||
|
||||
// Create our two handed weapon layout
|
||||
m_hWpnShield = m_pPlayer->GetCombatShield();
|
||||
|
||||
CWeaponTwoHandedContainer *p = ( CWeaponTwoHandedContainer * )m_pPlayer->Weapon_OwnsThisType( "weapon_twohandedcontainer" );
|
||||
if ( !p )
|
||||
{
|
||||
p = static_cast< CWeaponTwoHandedContainer * >( m_pPlayer->GiveNamedItem( "weapon_twohandedcontainer" ) );
|
||||
}
|
||||
|
||||
if ( p && m_hWpnShield.Get() )
|
||||
{
|
||||
m_hWpnShield->SetReflectViewModelAnimations( true );
|
||||
p->SetWeapons( NULL, m_hWpnShield );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::RespawnClass( void )
|
||||
{
|
||||
BaseClass::RespawnClass();
|
||||
|
||||
m_flNextBootCheck = 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Supply the player with Ammo. Return true if some ammo was given.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPlayerClassCommando::ResupplyAmmo( float flFraction, ResupplyReason_t reason )
|
||||
{
|
||||
bool bGiven = false;
|
||||
|
||||
if ((reason == RESUPPLY_ALL_FROM_STATION) || (reason == RESUPPLY_GRENADES_FROM_STATION))
|
||||
{
|
||||
if (ResupplyAmmoType( 3 * flFraction, "Grenades" ))
|
||||
bGiven = true;
|
||||
if (ResupplyAmmoType( 1, "RallyFlags" ))
|
||||
bGiven = true;
|
||||
if (ResupplyAmmoType( 3, "Rockets" ))
|
||||
bGiven = true;
|
||||
}
|
||||
|
||||
if ((reason == RESUPPLY_ALL_FROM_STATION) || (reason == RESUPPLY_AMMO_FROM_STATION))
|
||||
{
|
||||
if (ResupplyAmmoType( 3, "Rockets" ))
|
||||
bGiven = true;
|
||||
}
|
||||
|
||||
// On respawn, resupply base weapon ammo
|
||||
if ( reason == RESUPPLY_RESPAWN )
|
||||
{
|
||||
}
|
||||
|
||||
if ( BaseClass::ResupplyAmmo(flFraction, reason) )
|
||||
bGiven = true;
|
||||
|
||||
return bGiven;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set commando class specific movement data here.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::SetupMoveData( void )
|
||||
{
|
||||
// Setup Class statistics
|
||||
m_flMaxWalkingSpeed = class_commando_speed.GetFloat();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::SetupSizeData( void )
|
||||
{
|
||||
// Initially set the player to the base player class standing hull size.
|
||||
m_pPlayer->SetCollisionBounds( COMMANDOCLASS_HULL_STAND_MIN, COMMANDOCLASS_HULL_STAND_MAX );
|
||||
m_pPlayer->SetViewOffset( COMMANDOCLASS_VIEWOFFSET_STAND );
|
||||
m_pPlayer->m_Local.m_flStepSize = COMMANDOCLASS_STEPSIZE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if this player's allowed to build another one of the specified objects
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPlayerClassCommando::CanBuild( int iObjectType )
|
||||
{
|
||||
if ( iObjectType == OBJ_RALLYFLAG )
|
||||
{
|
||||
if ( !m_pPlayer->HasNamedTechnology( "com_obj_rallyflag" ) )
|
||||
return CB_NOT_RESEARCHED;
|
||||
}
|
||||
|
||||
return BaseClass::CanBuild( iObjectType );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Object has been built by this player
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::FinishedObject( CBaseObject *pObject )
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Calculate the Commando's Adrenalin Rush from available technologies
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::CalculateRush( void )
|
||||
{
|
||||
// Adrenalin Rush
|
||||
if ( m_pPlayer->HasNamedTechnology( "com_adrenalin_rush" ) )
|
||||
{
|
||||
m_bCanRush = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bCanRush = false;
|
||||
}
|
||||
|
||||
// Battlecry
|
||||
m_bHasBattlecry = m_pPlayer->HasNamedTechnology( "com_adrenalin_battlecry" );
|
||||
|
||||
// Boot
|
||||
// ROBIN: Removed for now
|
||||
m_bCanBoot = false;//m_pPlayer->HasNamedTechnology( "com_automatic_boot" );
|
||||
|
||||
// Killing Rush
|
||||
m_pPlayer->SetRampage( m_pPlayer->HasNamedTechnology( "com_adrenalin_rampage" ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if the player is bullrushing.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPlayerClassCommando::InBullRush( void )
|
||||
{
|
||||
return m_ClassData.m_bBullRush;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if the player's able to bull rush
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPlayerClassCommando::CanBullRush( void )
|
||||
{
|
||||
return m_ClassData.m_bCanBullRush;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Should we take damage-based force?
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPlayerClassCommando::ShouldApplyDamageForce( const CTakeDamageInfo &info )
|
||||
{
|
||||
return !InBullRush();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::BullRushTouch( CBaseEntity *pTouched )
|
||||
{
|
||||
if ( pTouched->IsPlayer() && !pTouched->InSameTeam( m_pPlayer ) )
|
||||
{
|
||||
// Get the player.
|
||||
CBaseTFPlayer *pTFPlayer = ( CBaseTFPlayer* )pTouched;
|
||||
|
||||
// Check to see if we have "touched" this player already this bullrush cycle.
|
||||
if ( m_aHitPlayers.Find( pTFPlayer ) != -1 )
|
||||
return;
|
||||
|
||||
// Hitting the player now.
|
||||
m_aHitPlayers.AddToTail( pTFPlayer );
|
||||
|
||||
// ROBIN: Bullrush now instantly kills again
|
||||
float flDamage = 200;
|
||||
// Calculate the damage a player takes based on distance(time).
|
||||
//float flDamage = 1.0f - ( ( COMMANDO_BULLRUSH_TIME - m_ClassData.m_flBullRushTime ) * ( 1.0f / COMMANDO_BULLRUSH_TIME ) );
|
||||
//flDamage *= 115.0f; // max bullrush damage
|
||||
|
||||
const trace_t &tr = m_pPlayer->GetTouchTrace();
|
||||
CTakeDamageInfo info( m_pPlayer, m_pPlayer, flDamage, DMG_CLUB, DMG_KILL_BULLRUSH );
|
||||
CalculateMeleeDamageForce( &info, (tr.endpos - tr.startpos), tr.endpos );
|
||||
pTFPlayer->TakeDamage( info );
|
||||
|
||||
CPASAttenuationFilter filter( m_pPlayer, "Commando.BullRushFlesh" );
|
||||
CBaseEntity::EmitSound( filter, m_pPlayer->entindex(), "Commando.BullRushFlesh" );
|
||||
|
||||
pTFPlayer->Touch( m_pPlayer );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: New technology has been gained. Recalculate any class specific technology dependencies.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::GainedNewTechnology( CBaseTechnology *pTechnology )
|
||||
{
|
||||
// Technology handling
|
||||
CalculateRush();
|
||||
|
||||
BaseClass::GainedNewTechnology( pTechnology );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when we are about to bullrush.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::PreBullRush( void )
|
||||
{
|
||||
// Set the touch function to look for collisions!
|
||||
SetClassTouch( m_pPlayer, BullRushTouch );
|
||||
|
||||
// Clear the player hit list.
|
||||
m_aHitPlayers.RemoveAll();
|
||||
|
||||
// Start the bull rush sound.
|
||||
CPASAttenuationFilter filter( m_pPlayer, "Commando.BullRushScream" );
|
||||
filter.MakeReliable();
|
||||
CBaseEntity::EmitSound( filter, m_pPlayer->entindex(), "Commando.BullRushScream" );
|
||||
|
||||
// Force the shield down, if it is up.
|
||||
CWeaponTwoHandedContainer *pContainer = dynamic_cast<CWeaponTwoHandedContainer*>( m_pPlayer->GetActiveWeapon() );
|
||||
if ( pContainer )
|
||||
{
|
||||
CWeaponCombatShield *pShield = dynamic_cast<CWeaponCombatShield*>( pContainer->GetRightWeapon() );
|
||||
if ( pShield )
|
||||
{
|
||||
pShield->SetShieldUsable( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called when we finish bullrushing.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::PostBullRush( void )
|
||||
{
|
||||
SetClassTouch( m_pPlayer, NULL );
|
||||
|
||||
// Force the shield down, if it is up.
|
||||
CWeaponTwoHandedContainer *pContainer = dynamic_cast<CWeaponTwoHandedContainer*>( m_pPlayer->GetActiveWeapon() );
|
||||
if ( pContainer )
|
||||
{
|
||||
CWeaponCombatShield *pShield = dynamic_cast<CWeaponCombatShield*>( pContainer->GetRightWeapon() );
|
||||
if ( pShield )
|
||||
{
|
||||
pShield->SetShieldUsable( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called every frame by postthink
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::ClassThink( void )
|
||||
{
|
||||
// Check bullrush
|
||||
m_ClassData.m_bCanBullRush = true;
|
||||
|
||||
// Do the init thing here!
|
||||
if ( m_bOldBullRush != m_ClassData.m_bBullRush )
|
||||
{
|
||||
if ( m_ClassData.m_bBullRush )
|
||||
{
|
||||
PreBullRush();
|
||||
}
|
||||
else
|
||||
{
|
||||
PostBullRush();
|
||||
}
|
||||
|
||||
m_bOldBullRush = (bool)m_ClassData.m_bBullRush;
|
||||
}
|
||||
|
||||
// Check for melee attack
|
||||
if ( m_bCanBoot && m_pPlayer->IsAlive() && m_flNextBootCheck < gpGlobals->curtime )
|
||||
{
|
||||
m_flNextBootCheck = gpGlobals->curtime + 0.2;
|
||||
|
||||
CBaseEntity *pEntity = NULL;
|
||||
Vector vecSrc = m_pPlayer->Weapon_ShootPosition( );
|
||||
Vector vecDir = m_pPlayer->BodyDirection2D( );
|
||||
Vector vecTarget = vecSrc + (vecDir * 48);
|
||||
for ( CEntitySphereQuery sphere( vecTarget, 16 ); pEntity = sphere.GetCurrentEntity(); sphere.NextEntity() )
|
||||
{
|
||||
if ( pEntity->IsPlayer() && (pEntity != m_pPlayer) )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)pEntity;
|
||||
// Target needs to be on the enemy team
|
||||
if ( !pPlayer->IsClass( TFCLASS_UNDECIDED ) && pPlayer->IsAlive() && pPlayer->InSameTeam( m_pPlayer ) == false )
|
||||
{
|
||||
Boot( pPlayer );
|
||||
m_flNextBootCheck = gpGlobals->curtime + 1.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BaseClass::ClassThink();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::StartAdrenalinRush( void )
|
||||
{
|
||||
// Am I actually alive?
|
||||
if ( !m_pPlayer->IsAlive() )
|
||||
return;
|
||||
|
||||
// Do I have rush capability?
|
||||
if ( !m_bCanRush )
|
||||
return;
|
||||
|
||||
m_bPersonalRush = true;
|
||||
|
||||
// Start adrenalin rushing
|
||||
m_pPlayer->AttemptToPowerup( POWERUP_RUSH, class_commando_rush_length.GetFloat() );
|
||||
|
||||
// If I have battlecry, adrenalin up all my nearby teammates
|
||||
if ( m_bHasBattlecry )
|
||||
{
|
||||
// Find nearby teammates
|
||||
for ( int i = 0; i < m_pPlayer->GetTFTeam()->GetNumPlayers(); i++ )
|
||||
{
|
||||
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)m_pPlayer->GetTFTeam()->GetPlayer(i);
|
||||
assert(pPlayer);
|
||||
|
||||
// Is it within range?
|
||||
if ( pPlayer != m_pPlayer && (pPlayer->GetAbsOrigin() - m_pPlayer->GetAbsOrigin()).Length() < class_commando_battlecry_radius.GetFloat() )
|
||||
{
|
||||
// Can I see it?
|
||||
trace_t tr;
|
||||
UTIL_TraceLine( m_pPlayer->EyePosition(), pPlayer->EyePosition(), MASK_SOLID_BRUSHONLY, m_pPlayer, COLLISION_GROUP_NONE, &tr);
|
||||
CBaseEntity *pEntity = tr.m_pEnt;
|
||||
if ( (tr.fraction == 1.0) || ( pEntity == pPlayer ) )
|
||||
{
|
||||
pPlayer->AttemptToPowerup( POWERUP_RUSH, class_commando_battlecry_length.GetFloat() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Automatic Melee Attack
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::Boot( CBaseTFPlayer *pTarget )
|
||||
{
|
||||
CPASAttenuationFilter filter( m_pPlayer, "Commando.BootSwing" );
|
||||
|
||||
CBaseEntity::EmitSound( filter, m_pPlayer->entindex(), "Commando.BootSwing" );
|
||||
CBaseEntity::EmitSound( filter, m_pPlayer->entindex(), "Commando.BootHit" );
|
||||
|
||||
// Damage the target
|
||||
CTakeDamageInfo info( m_pPlayer, m_pPlayer, 25, DMG_CLUB );
|
||||
CalculateMeleeDamageForce( &info, (pTarget->GetAbsOrigin() - m_pPlayer->GetAbsOrigin()), pTarget->GetAbsOrigin() );
|
||||
pTarget->TakeDamage( info );
|
||||
|
||||
Vector vecForward;
|
||||
AngleVectors( m_pPlayer->GetLocalAngles(), &vecForward );
|
||||
// Give it a lot of "in the air"
|
||||
vecForward.z = MAX( 0.8, vecForward.z );
|
||||
VectorNormalize( vecForward );
|
||||
|
||||
// Knock the target to the ground for a few seconds (use default duration)
|
||||
pTarget->KnockDownPlayer( vecForward, 500.0f, tf_knockdowntime.GetFloat() );
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handle custom commands for this playerclass
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPlayerClassCommando::ClientCommand( const char *pcmd )
|
||||
{
|
||||
return BaseClass::ClientCommand( pcmd );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::SetPlayerHull( void )
|
||||
{
|
||||
if ( m_pPlayer->GetFlags() & FL_DUCKING )
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( COMMANDOCLASS_HULL_DUCK_MIN, COMMANDOCLASS_HULL_DUCK_MAX );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( COMMANDOCLASS_HULL_STAND_MIN, COMMANDOCLASS_HULL_STAND_MAX );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::GetPlayerHull( bool bDucking, Vector &vecMin, Vector &vecMax )
|
||||
{
|
||||
if ( bDucking )
|
||||
{
|
||||
VectorCopy( COMMANDOCLASS_HULL_DUCK_MIN, vecMin );
|
||||
VectorCopy( COMMANDOCLASS_HULL_DUCK_MAX, vecMax );
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorCopy( COMMANDOCLASS_HULL_STAND_MIN, vecMin );
|
||||
VectorCopy( COMMANDOCLASS_HULL_STAND_MAX, vecMax );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::CreatePersonalOrder( void )
|
||||
{
|
||||
if ( CreateInitialOrder() )
|
||||
return;
|
||||
|
||||
if ( COrderAssist::CreateOrder( this ) )
|
||||
return;
|
||||
|
||||
BaseClass::CreatePersonalOrder();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::ResetViewOffset( void )
|
||||
{
|
||||
if ( m_pPlayer )
|
||||
{
|
||||
m_pPlayer->SetViewOffset( COMMANDOCLASS_VIEWOFFSET_STAND );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassCommando::InitVCollision( void )
|
||||
{
|
||||
CPhysCollide *pStandModel = PhysCreateBbox( COMMANDOCLASS_HULL_STAND_MIN, COMMANDOCLASS_HULL_STAND_MAX );
|
||||
CPhysCollide *pCrouchModel = PhysCreateBbox( COMMANDOCLASS_HULL_DUCK_MIN, COMMANDOCLASS_HULL_DUCK_MAX );
|
||||
m_pPlayer->SetupVPhysicsShadow( pStandModel, "tfplayer_commando_stand", pCrouchModel, "tfplayer_commando_crouch" );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPlayerClassCommando::CanGetInVehicle( void )
|
||||
{
|
||||
if ( InBullRush() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPlayerClassCommando::ClassCostAdjustment( ResupplyBuyType_t nType )
|
||||
{
|
||||
int nCost = 0;
|
||||
if ( nType != RESUPPLY_BUY_HEALTH )
|
||||
{
|
||||
nCost = RESUPPLY_ROCKET_COST;
|
||||
}
|
||||
|
||||
return nCost;
|
||||
}
|
||||
112
game/server/tf2/tf_class_commando.h
Normal file
112
game/server/tf2/tf_class_commando.h
Normal file
@@ -0,0 +1,112 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TF_CLASS_COMMANDO_H
|
||||
#define TF_CLASS_COMMANDO_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "tf_playerclass.h"
|
||||
#include "TFClassData_Shared.h"
|
||||
#include "basetfcombatweapon_shared.h"
|
||||
|
||||
//=====================================================================
|
||||
// Commando
|
||||
class CPlayerClassCommando : public CPlayerClass
|
||||
{
|
||||
DECLARE_CLASS( CPlayerClassCommando, CPlayerClass );
|
||||
public:
|
||||
CPlayerClassCommando( CBaseTFPlayer *pPlayer, TFClass iClass );
|
||||
virtual ~CPlayerClassCommando();
|
||||
|
||||
virtual void ClassActivate( void );
|
||||
virtual void ClassDeactivate( void );
|
||||
|
||||
virtual const char* GetClassModelString( int nTeam );
|
||||
|
||||
// Class Initialization
|
||||
virtual void CreateClass( void ); // Create the class upon initial spawn
|
||||
virtual void RespawnClass( void ); // Called upon all respawns
|
||||
virtual bool ResupplyAmmo( float flPercentage, ResupplyReason_t reason );
|
||||
virtual void SetupMoveData( void ); // Override class specific movement data here.
|
||||
virtual void SetupSizeData( void ); // Override class specific size data here.
|
||||
virtual void ResetViewOffset( void );
|
||||
|
||||
// Should we take damage-based force?
|
||||
virtual bool ShouldApplyDamageForce( const CTakeDamageInfo &info );
|
||||
|
||||
PlayerClassCommandoData_t *GetClassData( void ) { return &m_ClassData; }
|
||||
|
||||
// Class Abilities
|
||||
virtual void ClassThink( void );
|
||||
|
||||
// Resources
|
||||
int ClassCostAdjustment( ResupplyBuyType_t nType );
|
||||
|
||||
// Objects
|
||||
virtual int CanBuild( int iObjectType );
|
||||
virtual void FinishedObject( CBaseObject *pObject );
|
||||
|
||||
virtual bool ClientCommand( const CCommand &args );
|
||||
virtual void GainedNewTechnology( CBaseTechnology *pTechnology );
|
||||
|
||||
// Adrenalin Rush
|
||||
virtual void CalculateRush( void );
|
||||
virtual void StartAdrenalinRush( void );
|
||||
|
||||
// Automatic Melee Attack
|
||||
virtual void Boot( CBaseTFPlayer *pTarget );
|
||||
|
||||
// Hooks
|
||||
virtual void SetPlayerHull( void );
|
||||
virtual void GetPlayerHull( bool bDucking, Vector &vecMin, Vector &vecMax );
|
||||
|
||||
// Orders.
|
||||
virtual void CreatePersonalOrder( void );
|
||||
|
||||
// Bull Rush.
|
||||
bool InBullRush( void );
|
||||
bool CanBullRush( void );
|
||||
void BullRushTouch( CBaseEntity *pTouched );
|
||||
|
||||
CNetworkVarEmbedded( PlayerClassCommandoData_t, m_ClassData );
|
||||
|
||||
// Player physics shadow.
|
||||
void InitVCollision( void );
|
||||
|
||||
// Vehicle
|
||||
bool CanGetInVehicle( void );
|
||||
|
||||
protected:
|
||||
// BullRush
|
||||
void PreBullRush( void );
|
||||
void PostBullRush( void );
|
||||
|
||||
protected:
|
||||
// Adrenalin Rush
|
||||
bool m_bCanRush; // True if he has the ability to rush
|
||||
bool m_bPersonalRush; // True if this he started his current rush, or outside effect
|
||||
bool m_bHasBattlecry; // True if he has the ability to battlecry
|
||||
|
||||
// Weapons
|
||||
CHandle<CBaseTFCombatWeapon> m_hWpnPlasma;
|
||||
// CHandle<CBaseTFCombatWeapon> m_hWpnGrenade;
|
||||
|
||||
// Automatic Melee Attack
|
||||
bool m_bCanBoot; // True if he has the ability to boot
|
||||
float m_flNextBootCheck; // Time at which to recheck for the automatic melee attack
|
||||
|
||||
bool m_bOldBullRush;
|
||||
|
||||
CUtlVector<CBaseTFPlayer*> m_aHitPlayers; // Player I have hit during this bullrush.
|
||||
};
|
||||
|
||||
EXTERN_SEND_TABLE( DT_PlayerClassCommandoData )
|
||||
|
||||
#endif // TF_CLASS_COMMANDO_H
|
||||
352
game/server/tf2/tf_class_defender.cpp
Normal file
352
game/server/tf2/tf_class_defender.cpp
Normal file
@@ -0,0 +1,352 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: The Defender Player Class
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "tf_player.h"
|
||||
#include "tf_class_defender.h"
|
||||
#include "tf_obj.h"
|
||||
#include "tf_obj_sentrygun.h"
|
||||
#include "basecombatweapon.h"
|
||||
#include "weapon_builder.h"
|
||||
#include "weapon_limpetmine.h"
|
||||
#include "tf_team.h"
|
||||
#include "orders.h"
|
||||
#include "order_repair.h"
|
||||
#include "order_buildsentrygun.h"
|
||||
#include "weapon_twohandedcontainer.h"
|
||||
#include "weapon_combatshield.h"
|
||||
#include "tf_vehicle_teleport_station.h"
|
||||
|
||||
ConVar class_defender_speed( "class_defender_speed","200", FCVAR_NONE, "Defender movement speed" );
|
||||
|
||||
|
||||
// An object must be this close to a sentry gun to be considered covered by it.
|
||||
#define DEFENDER_SENTRY_COVERED_DIST 1000
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Defender Data Table
|
||||
//
|
||||
BEGIN_SEND_TABLE_NOBASE( CPlayerClassDefender, DT_PlayerClassDefenderData )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
bool OrderCreator_BuildSentryGun( CPlayerClassDefender *pClass )
|
||||
{
|
||||
return COrderBuildSentryGun::CreateOrder( pClass );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : const char
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CPlayerClassDefender::GetClassModelString( int nTeam )
|
||||
{
|
||||
if (nTeam == TEAM_HUMANS)
|
||||
return "models/player/human_defender.mdl";
|
||||
else
|
||||
return "models/player/defender.mdl";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Defender
|
||||
//-----------------------------------------------------------------------------
|
||||
CPlayerClassDefender::CPlayerClassDefender( CBaseTFPlayer *pPlayer, TFClass iClass ) : CPlayerClass( pPlayer, iClass )
|
||||
{
|
||||
for (int i = 0; i < MAX_TF_TEAMS; ++i)
|
||||
{
|
||||
SetClassModel( MAKE_STRING(GetClassModelString(i)), i );
|
||||
}
|
||||
}
|
||||
|
||||
CPlayerClassDefender::~CPlayerClassDefender()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassDefender::ClassActivate( void )
|
||||
{
|
||||
BaseClass::ClassActivate();
|
||||
|
||||
// Setup movement data.
|
||||
SetupMoveData();
|
||||
|
||||
m_iNumberOfSentriesAllowed = 0;
|
||||
m_bHasSmarterSentryguns = false;
|
||||
m_bHasSensorSentryguns = false;
|
||||
m_bHasMachinegun = false;
|
||||
m_bHasRocketlauncher = false;
|
||||
m_bHasAntiair = false;
|
||||
|
||||
m_hWpnShield = NULL;
|
||||
m_hWpnPlasma = NULL;
|
||||
memset( &m_ClassData, 0, sizeof( m_ClassData ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassDefender::ClassDeactivate( void )
|
||||
{
|
||||
BaseClass::ClassDeactivate();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassDefender::CreateClass( void )
|
||||
{
|
||||
BaseClass::CreateClass();
|
||||
|
||||
// Create our two handed weapon layout
|
||||
m_hWpnPlasma = static_cast< CBaseTFCombatWeapon * >( m_pPlayer->GiveNamedItem( "weapon_combat_burstrifle" ) );
|
||||
m_hWpnShield = m_pPlayer->GetCombatShield();
|
||||
CWeaponTwoHandedContainer *p = ( CWeaponTwoHandedContainer * )m_pPlayer->Weapon_OwnsThisType( "weapon_twohandedcontainer" );
|
||||
if ( !p )
|
||||
{
|
||||
p = static_cast< CWeaponTwoHandedContainer * >( m_pPlayer->GiveNamedItem( "weapon_twohandedcontainer" ) );
|
||||
}
|
||||
if ( p && m_hWpnShield.Get() && m_hWpnPlasma.Get() )
|
||||
{
|
||||
m_hWpnShield->SetReflectViewModelAnimations( true );
|
||||
p->SetWeapons( m_hWpnPlasma, m_hWpnShield );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPlayerClassDefender::ResupplyAmmo( float flFraction, ResupplyReason_t reason )
|
||||
{
|
||||
bool bGiven = false;
|
||||
if ((reason == RESUPPLY_ALL_FROM_STATION) || (reason == RESUPPLY_AMMO_FROM_STATION))
|
||||
{
|
||||
if (ResupplyAmmoType( 20 * flFraction, "Limpets" ))
|
||||
bGiven = true;
|
||||
|
||||
// Defender doesn't use rockets, but his sentryguns do
|
||||
if (ResupplyAmmoType( 50 * flFraction, "Rockets" ))
|
||||
bGiven = true;
|
||||
}
|
||||
|
||||
if ((reason == RESUPPLY_ALL_FROM_STATION) || (reason == RESUPPLY_GRENADES_FROM_STATION))
|
||||
{
|
||||
}
|
||||
|
||||
// On respawn, resupply base weapon ammo
|
||||
if ( reason == RESUPPLY_RESPAWN )
|
||||
{
|
||||
}
|
||||
|
||||
if ( BaseClass::ResupplyAmmo(flFraction, reason) )
|
||||
bGiven = true;
|
||||
|
||||
return bGiven;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set defender class specific movement data here.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassDefender::SetupMoveData( void )
|
||||
{
|
||||
// Setup Class statistics
|
||||
m_flMaxWalkingSpeed = class_defender_speed.GetFloat();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassDefender::SetupSizeData( void )
|
||||
{
|
||||
// Initially set the player to the base player class standing hull size.
|
||||
m_pPlayer->SetCollisionBounds( DEFENDERCLASS_HULL_STAND_MIN, DEFENDERCLASS_HULL_STAND_MAX );
|
||||
m_pPlayer->SetViewOffset( DEFENDERCLASS_VIEWOFFSET_STAND );
|
||||
m_pPlayer->m_Local.m_flStepSize = DEFENDERCLASS_STEPSIZE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: New technology has been gained. Recalculate any class specific technology dependencies.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassDefender::GainedNewTechnology( CBaseTechnology *pTechnology )
|
||||
{
|
||||
// Calculate the number of sentryguns allowed
|
||||
if ( m_pPlayer->HasNamedTechnology( "sentrygun_three" ) )
|
||||
{
|
||||
m_iNumberOfSentriesAllowed = 3;
|
||||
}
|
||||
else if ( m_pPlayer->HasNamedTechnology( "sentrygun_two" ) )
|
||||
{
|
||||
m_iNumberOfSentriesAllowed = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iNumberOfSentriesAllowed = 1;
|
||||
}
|
||||
|
||||
m_bHasSmarterSentryguns = false;
|
||||
m_bHasSensorSentryguns = false;
|
||||
m_bHasRocketlauncher = false;
|
||||
|
||||
// Sentrygun levels
|
||||
if ( m_pPlayer->HasNamedTechnology( "sentrygun_ai" ) )
|
||||
{
|
||||
m_bHasSmarterSentryguns = true;
|
||||
}
|
||||
if ( m_pPlayer->HasNamedTechnology( "sentrygun_sensors" ) )
|
||||
{
|
||||
m_bHasSensorSentryguns = true;
|
||||
}
|
||||
|
||||
// Sentrygun types
|
||||
if ( m_pPlayer->HasNamedTechnology( "sentrygun_rocket" ) )
|
||||
{
|
||||
m_bHasRocketlauncher = true;
|
||||
}
|
||||
|
||||
UpdateSentrygunTechnology();
|
||||
BaseClass::GainedNewTechnology( pTechnology );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Tell all sentryguns what level of technology the Defender has
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassDefender::UpdateSentrygunTechnology( void )
|
||||
{
|
||||
for (int i = 0; i < m_pPlayer->GetObjectCount(); i++)
|
||||
{
|
||||
CBaseObject *pObj = m_pPlayer->GetObject(i);
|
||||
if ( pObj && pObj->IsSentrygun() )
|
||||
{
|
||||
CObjectSentrygun *pSentry = static_cast<CObjectSentrygun *>(pObj);
|
||||
pSentry->SetTechnology( m_bHasSmarterSentryguns, m_bHasSensorSentryguns );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if this player's allowed to build another one of the specified objects
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPlayerClassDefender::CanBuild( int iObjectType )
|
||||
{
|
||||
// First, check to see if we've got the technology
|
||||
if ( iObjectType == OBJ_SENTRYGUN_ROCKET_LAUNCHER )
|
||||
{
|
||||
if ( !m_bHasRocketlauncher )
|
||||
return CB_NOT_RESEARCHED;
|
||||
}
|
||||
|
||||
return BaseClass::CanBuild( iObjectType );
|
||||
}
|
||||
|
||||
|
||||
int CPlayerClassDefender::CanBuildSentryGun()
|
||||
{
|
||||
return
|
||||
CanBuild( OBJ_SENTRYGUN_ROCKET_LAUNCHER ) == CB_CAN_BUILD ||
|
||||
CanBuild( OBJ_SENTRYGUN_PLASMA ) == CB_CAN_BUILD;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Object has been built by this player
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassDefender::FinishedObject( CBaseObject *pObject )
|
||||
{
|
||||
UpdateSentrygunTechnology();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassDefender::PlayerDied( CBaseEntity *pAttacker )
|
||||
{
|
||||
CWeaponLimpetmine *weapon = (CWeaponLimpetmine*)m_pPlayer->Weapon_OwnsThisType( "weapon_limpetmine" );
|
||||
if ( weapon )
|
||||
{
|
||||
weapon->RemoveDeployedLimpets();
|
||||
}
|
||||
|
||||
BaseClass::PlayerDied( pAttacker );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassDefender::SetPlayerHull( void )
|
||||
{
|
||||
if ( m_pPlayer->GetFlags() & FL_DUCKING )
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( DEFENDERCLASS_HULL_DUCK_MIN, DEFENDERCLASS_HULL_DUCK_MAX );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( DEFENDERCLASS_HULL_STAND_MIN, DEFENDERCLASS_HULL_STAND_MAX );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassDefender::GetPlayerHull( bool bDucking, Vector &vecMin, Vector &vecMax )
|
||||
{
|
||||
if ( bDucking )
|
||||
{
|
||||
VectorCopy( DEFENDERCLASS_HULL_DUCK_MIN, vecMin );
|
||||
VectorCopy( DEFENDERCLASS_HULL_DUCK_MAX, vecMax );
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorCopy( DEFENDERCLASS_HULL_STAND_MIN, vecMin );
|
||||
VectorCopy( DEFENDERCLASS_HULL_STAND_MAX, vecMax );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassDefender::ResetViewOffset( void )
|
||||
{
|
||||
if ( m_pPlayer )
|
||||
{
|
||||
m_pPlayer->SetViewOffset( DEFENDERCLASS_VIEWOFFSET_STAND );
|
||||
}
|
||||
}
|
||||
|
||||
void CPlayerClassDefender::CreatePersonalOrder()
|
||||
{
|
||||
if ( CreateInitialOrder() )
|
||||
return;
|
||||
|
||||
if( COrderRepair::CreateOrder_RepairFriendlyObjects( this ) )
|
||||
return;
|
||||
|
||||
// Alternate between sentrygun and sandbag orders.
|
||||
if ( OrderCreator_BuildSentryGun( this ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BaseClass::CreatePersonalOrder();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassDefender::InitVCollision( void )
|
||||
{
|
||||
CPhysCollide *pStandModel = PhysCreateBbox( DEFENDERCLASS_HULL_STAND_MIN, DEFENDERCLASS_HULL_STAND_MAX );
|
||||
CPhysCollide *pCrouchModel = PhysCreateBbox( DEFENDERCLASS_HULL_DUCK_MIN, DEFENDERCLASS_HULL_DUCK_MAX );
|
||||
m_pPlayer->SetupVPhysicsShadow( pStandModel, "tfplayer_defender_stand", pCrouchModel, "tfplayer_defender_crouch" );
|
||||
}
|
||||
77
game/server/tf2/tf_class_defender.h
Normal file
77
game/server/tf2/tf_class_defender.h
Normal file
@@ -0,0 +1,77 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Defender player class
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TF_CLASS_DEFENDER_H
|
||||
#define TF_CLASS_DEFENDER_H
|
||||
#pragma once
|
||||
|
||||
#include "TFClassData_Shared.h"
|
||||
|
||||
//=====================================================================
|
||||
// Defender
|
||||
class CPlayerClassDefender : public CPlayerClass
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CPlayerClassDefender, CPlayerClass );
|
||||
|
||||
CPlayerClassDefender( CBaseTFPlayer *pPlayer, TFClass iClass );
|
||||
~CPlayerClassDefender();
|
||||
|
||||
virtual void ClassActivate( void );
|
||||
virtual void ClassDeactivate( void );
|
||||
|
||||
virtual const char* GetClassModelString( int nTeam );
|
||||
|
||||
// Class Initialization
|
||||
virtual void CreateClass( void ); // Create the class upon initial spawn
|
||||
virtual bool ResupplyAmmo( float flPercentage, ResupplyReason_t reason );
|
||||
virtual void SetupMoveData( void ); // Override class specific movement data here.
|
||||
virtual void SetupSizeData( void ); // Override class specific size data here.
|
||||
virtual void ResetViewOffset( void );
|
||||
|
||||
PlayerClassDefenderData_t *GetClassData( void ) { return &m_ClassData; }
|
||||
|
||||
virtual void PlayerDied( CBaseEntity *pAttacker );
|
||||
|
||||
virtual void GainedNewTechnology( CBaseTechnology *pTechnology );
|
||||
virtual void UpdateSentrygunTechnology( void );
|
||||
|
||||
// Sentrygun building
|
||||
virtual int CanBuild( int iObjectType );
|
||||
int CanBuildSentryGun();
|
||||
virtual void FinishedObject( CBaseObject *pObject );
|
||||
|
||||
// Orders.
|
||||
virtual void CreatePersonalOrder();
|
||||
|
||||
// Hooks
|
||||
virtual void SetPlayerHull( void );
|
||||
virtual void GetPlayerHull( bool bDucking, Vector &vecMin, Vector &vecMax );
|
||||
|
||||
// Player physics shadow.
|
||||
void InitVCollision( void );
|
||||
|
||||
public:
|
||||
// Sentrygun building
|
||||
int m_iNumberOfSentriesAllowed;
|
||||
bool m_bHasSmarterSentryguns;
|
||||
bool m_bHasSensorSentryguns;
|
||||
// Sentrygun types
|
||||
bool m_bHasMachinegun;
|
||||
bool m_bHasRocketlauncher;
|
||||
bool m_bHasAntiair;
|
||||
|
||||
// Weapons
|
||||
CHandle<CBaseTFCombatWeapon> m_hWpnPlasma;
|
||||
|
||||
private:
|
||||
PlayerClassDefenderData_t m_ClassData;
|
||||
};
|
||||
|
||||
EXTERN_SEND_TABLE( DT_PlayerClassDefenderData )
|
||||
|
||||
#endif // TF_CLASS_DEFENDER_H
|
||||
274
game/server/tf2/tf_class_escort.cpp
Normal file
274
game/server/tf2/tf_class_escort.cpp
Normal file
@@ -0,0 +1,274 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: The Escort Player Class
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "tf_player.h"
|
||||
#include "tf_class_escort.h"
|
||||
#include "basecombatweapon.h"
|
||||
#include "tf_obj_shieldwall.h"
|
||||
#include "weapon_builder.h"
|
||||
#include "tf_shareddefs.h"
|
||||
#include "tf_team.h"
|
||||
#include "orders.h"
|
||||
#include "order_buildshieldwall.h"
|
||||
#include "order_mortar_attack.h"
|
||||
#include "weapon_twohandedcontainer.h"
|
||||
#include "tf_shield.h"
|
||||
#include "iservervehicle.h"
|
||||
#include "weapon_combatshield.h"
|
||||
#include "in_buttons.h"
|
||||
#include "tf_vehicle_teleport_station.h"
|
||||
#include "weapon_shield.h"
|
||||
|
||||
|
||||
ConVar class_escort_speed( "class_escort_speed","200", FCVAR_NONE, "Escort movement speed" );
|
||||
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Escort Data Table
|
||||
//
|
||||
BEGIN_SEND_TABLE_NOBASE( CPlayerClassEscort, DT_PlayerClassEscortData )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
|
||||
bool OrderCreator_Mortar( CPlayerClassEscort *pClass )
|
||||
{
|
||||
return COrderMortarAttack::CreateOrder( pClass );
|
||||
}
|
||||
|
||||
|
||||
bool OrderCreator_ShieldWall( CPlayerClassEscort *pClass )
|
||||
{
|
||||
return COrderBuildShieldWall::CreateOrder( pClass );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : const char
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CPlayerClassEscort::GetClassModelString( int nTeam )
|
||||
{
|
||||
static const char *string = "models/player/alien_escort.mdl";
|
||||
return string;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPlayerClassEscort::CPlayerClassEscort( CBaseTFPlayer *pPlayer, TFClass iClass ) : CPlayerClass( pPlayer, iClass )
|
||||
{
|
||||
for (int i = 0; i < MAX_TF_TEAMS; ++i)
|
||||
{
|
||||
SetClassModel( MAKE_STRING(GetClassModelString(i)), i );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassEscort::SetupSizeData( void )
|
||||
{
|
||||
// Initially set the player to the base player class standing hull size.
|
||||
m_pPlayer->SetCollisionBounds( ESCORTCLASS_HULL_STAND_MIN, ESCORTCLASS_HULL_STAND_MAX );
|
||||
m_pPlayer->SetViewOffset( ESCORTCLASS_VIEWOFFSET_STAND );
|
||||
m_pPlayer->m_Local.m_flStepSize = ESCORTCLASS_STEPSIZE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPlayerClassEscort::~CPlayerClassEscort()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassEscort::ClassActivate( void )
|
||||
{
|
||||
BaseClass::ClassActivate();
|
||||
|
||||
// Setup movement data.
|
||||
m_hWeaponProjectedShield = NULL;
|
||||
SetupMoveData();
|
||||
memset( &m_ClassData, 0, sizeof( m_ClassData ) );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CWeaponShield *CPlayerClassEscort::GetProjectedShield( void )
|
||||
{
|
||||
if ( !m_hWeaponProjectedShield )
|
||||
{
|
||||
m_hWeaponProjectedShield = static_cast< CWeaponShield * >( m_pPlayer->Weapon_OwnsThisType( "weapon_shield" ) );
|
||||
if ( !m_hWeaponProjectedShield )
|
||||
{
|
||||
m_hWeaponProjectedShield = static_cast< CWeaponShield * >( m_pPlayer->GiveNamedItem( "weapon_shield" ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_hWeaponProjectedShield )
|
||||
{
|
||||
m_hWeaponProjectedShield->SetReflectViewModelAnimations( true );
|
||||
}
|
||||
|
||||
return m_hWeaponProjectedShield;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassEscort::CreateClass( void )
|
||||
{
|
||||
BaseClass::CreateClass();
|
||||
|
||||
CWeaponTwoHandedContainer *p = ( CWeaponTwoHandedContainer * )m_pPlayer->Weapon_OwnsThisType( "weapon_twohandedcontainer" );
|
||||
if ( !p )
|
||||
{
|
||||
p = static_cast< CWeaponTwoHandedContainer * >( m_pPlayer->GiveNamedItem( "weapon_twohandedcontainer" ) );
|
||||
}
|
||||
|
||||
CWeaponShield *pShield = GetProjectedShield();
|
||||
if ( p && pShield )
|
||||
{
|
||||
p->SetWeapons( NULL, pShield );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPlayerClassEscort::ResupplyAmmo( float flFraction, ResupplyReason_t reason )
|
||||
{
|
||||
bool bGiven = false;
|
||||
if ((reason == RESUPPLY_ALL_FROM_STATION) || (reason == RESUPPLY_AMMO_FROM_STATION))
|
||||
{
|
||||
if ( ResupplyAmmoType( 200 * flFraction, "Bullets" ) )
|
||||
bGiven = true;
|
||||
}
|
||||
|
||||
if ((reason == RESUPPLY_ALL_FROM_STATION) || (reason == RESUPPLY_GRENADES_FROM_STATION))
|
||||
{
|
||||
if (ResupplyAmmoType( 5 * flFraction, "ShieldGrenades" ))
|
||||
bGiven = true;
|
||||
}
|
||||
|
||||
// On respawn, resupply base weapon ammo
|
||||
if ( reason == RESUPPLY_RESPAWN )
|
||||
{
|
||||
if ( ResupplyAmmoType( 200, "Bullets" ) )
|
||||
bGiven = true;
|
||||
}
|
||||
|
||||
if ( BaseClass::ResupplyAmmo(flFraction, reason) )
|
||||
bGiven = true;
|
||||
|
||||
return bGiven;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set escort class specific movement data here.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassEscort::SetupMoveData( void )
|
||||
{
|
||||
// Setup Class statistics
|
||||
m_flMaxWalkingSpeed = class_escort_speed.GetFloat();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassEscort::SetPlayerHull( void )
|
||||
{
|
||||
if ( m_pPlayer->GetFlags() & FL_DUCKING )
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( ESCORTCLASS_HULL_DUCK_MIN, ESCORTCLASS_HULL_DUCK_MAX );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( ESCORTCLASS_HULL_STAND_MIN, ESCORTCLASS_HULL_STAND_MAX );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassEscort::ResetViewOffset( void )
|
||||
{
|
||||
if ( m_pPlayer )
|
||||
{
|
||||
m_pPlayer->SetViewOffset( ESCORTCLASS_VIEWOFFSET_STAND );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassEscort::PowerupStart( int iPowerup, float flAmount, CBaseEntity *pAttacker, CDamageModifier *pDamageModifier )
|
||||
{
|
||||
/*
|
||||
switch( iPowerup )
|
||||
{
|
||||
case POWERUP_BOOST:
|
||||
// Increase our shield's energy
|
||||
if ( m_hDeployedShield )
|
||||
{
|
||||
m_hDeployedShield->SetPower( m_hDeployedShield->GetPower() + (flAmount * 10) );
|
||||
}
|
||||
break;
|
||||
|
||||
case POWERUP_EMP:
|
||||
if ( m_hDeployedShield )
|
||||
{
|
||||
m_hDeployedShield->SetEMPed( true );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
BaseClass::PowerupStart( iPowerup, flAmount, pAttacker, pDamageModifier );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Powerup has just started
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassEscort::PowerupEnd( int iPowerup )
|
||||
{
|
||||
/*
|
||||
switch( iPowerup )
|
||||
{
|
||||
case POWERUP_EMP:
|
||||
if ( m_hDeployedShield )
|
||||
{
|
||||
m_hDeployedShield->SetEMPed( false );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
BaseClass::PowerupEnd( iPowerup );
|
||||
}
|
||||
64
game/server/tf2/tf_class_escort.h
Normal file
64
game/server/tf2/tf_class_escort.h
Normal file
@@ -0,0 +1,64 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TF_CLASS_ESCORT_H
|
||||
#define TF_CLASS_ESCORT_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "tf_playerclass.h"
|
||||
#include "TFClassData_Shared.h"
|
||||
#include "tf_shieldshared.h"
|
||||
|
||||
class CShield;
|
||||
class CWeaponShield;
|
||||
|
||||
//=====================================================================
|
||||
// Indirect
|
||||
class CPlayerClassEscort : public CPlayerClass
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CPlayerClassEscort, CPlayerClass );
|
||||
|
||||
CPlayerClassEscort( CBaseTFPlayer *pPlayer, TFClass iClass );
|
||||
~CPlayerClassEscort();
|
||||
|
||||
virtual void ClassActivate( void );
|
||||
|
||||
virtual const char* GetClassModelString( int nTeam );
|
||||
|
||||
// Class Initialization
|
||||
virtual void CreateClass( void ); // Create the class upon initial spawn
|
||||
virtual bool ResupplyAmmo( float flPercentage, ResupplyReason_t reason );
|
||||
virtual void SetupMoveData( void ); // Override class specific movement data here.
|
||||
virtual void SetupSizeData( void ); // Override class specific size data here.
|
||||
virtual void ResetViewOffset( void );
|
||||
|
||||
PlayerClassEscortData_t *GetClassData( void ) { return &m_ClassData; }
|
||||
|
||||
// Hooks
|
||||
virtual void SetPlayerHull( void );
|
||||
|
||||
// Powerups
|
||||
virtual void PowerupStart( int iPowerup, float flAmount, CBaseEntity *pAttacker, CDamageModifier *pDamageModifier );
|
||||
virtual void PowerupEnd( int iPowerup );
|
||||
|
||||
private:
|
||||
// Purpose:
|
||||
CWeaponShield *GetProjectedShield( void );
|
||||
|
||||
protected:
|
||||
PlayerClassEscortData_t m_ClassData;
|
||||
CHandle<CWeaponShield> m_hWeaponProjectedShield;
|
||||
};
|
||||
|
||||
EXTERN_SEND_TABLE( DT_PlayerClassEscortData )
|
||||
|
||||
#endif // TF_CLASS_ESCORT_H
|
||||
275
game/server/tf2/tf_class_infiltrator.cpp
Normal file
275
game/server/tf2/tf_class_infiltrator.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: The Infiltrator Player Class
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "orders.h"
|
||||
#include "tf_player.h"
|
||||
#include "tf_class_infiltrator.h"
|
||||
#include "EntityList.h"
|
||||
#include "basecombatweapon.h"
|
||||
#include "menu_base.h"
|
||||
#include "tf_obj.h"
|
||||
#include "tf_team.h"
|
||||
#include "weapon_builder.h"
|
||||
|
||||
ConVar class_infiltrator_speed( "class_infiltrator_speed","200", FCVAR_NONE, "Infiltrator movement speed" );
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Infiltrator Data Table
|
||||
//
|
||||
BEGIN_SEND_TABLE_NOBASE( CPlayerClassInfiltrator, DT_PlayerClassInfiltratorData )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : const char
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CPlayerClassInfiltrator::GetClassModelString( int nTeam )
|
||||
{
|
||||
static const char *string = "models/player/spy.mdl";
|
||||
return string;
|
||||
}
|
||||
|
||||
// Infiltrator
|
||||
CPlayerClassInfiltrator::CPlayerClassInfiltrator( CBaseTFPlayer *pPlayer, TFClass iClass ) : CPlayerClass( pPlayer, iClass )
|
||||
{
|
||||
for (int i = 0; i < MAX_TF_TEAMS; ++i)
|
||||
{
|
||||
SetClassModel( MAKE_STRING(GetClassModelString(i)), i );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPlayerClassInfiltrator::~CPlayerClassInfiltrator()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassInfiltrator::ClassActivate( void )
|
||||
{
|
||||
BaseClass::ClassActivate();
|
||||
|
||||
// Setup movement data.
|
||||
SetupMoveData();
|
||||
|
||||
//m_hAssassinationWeapon = NULL;
|
||||
m_hSwappedWeapon = NULL;
|
||||
|
||||
m_bCanConsumeCorpses = false;
|
||||
m_flStartCamoAt = 0.0f;
|
||||
|
||||
memset( &m_ClassData, 0, sizeof( m_ClassData ) );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Register for precaching.
|
||||
//-----------------------------------------------------------------------------
|
||||
void PrecacheInfiltrator(void *pUser)
|
||||
{
|
||||
}
|
||||
PRECACHE_REGISTER_FN(PrecacheInfiltrator);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassInfiltrator::RespawnClass( void )
|
||||
{
|
||||
BaseClass::RespawnClass();
|
||||
|
||||
m_flStartCamoAt = gpGlobals->curtime + INFILTRATOR_CAMOTIME_AFTER_SPAWN;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPlayerClassInfiltrator::ResupplyAmmo( float flFraction, ResupplyReason_t reason )
|
||||
{
|
||||
bool bGiven = false;
|
||||
if ((reason == RESUPPLY_ALL_FROM_STATION) || (reason == RESUPPLY_AMMO_FROM_STATION))
|
||||
{
|
||||
if (ResupplyAmmoType( 200 * flFraction, "Bullets" ))
|
||||
bGiven = true;
|
||||
if (ResupplyAmmoType( 20 * flFraction, "Limpets" ))
|
||||
bGiven = true;
|
||||
}
|
||||
|
||||
if ( BaseClass::ResupplyAmmo(flFraction, reason) )
|
||||
bGiven = true;
|
||||
return bGiven;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set infiltrator class specific movement data here.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassInfiltrator::SetupMoveData( void )
|
||||
{
|
||||
// Setup Class statistics
|
||||
m_flMaxWalkingSpeed = class_infiltrator_speed.GetFloat();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassInfiltrator::SetupSizeData( void )
|
||||
{
|
||||
// Initially set the player to the base player class standing hull size.
|
||||
m_pPlayer->SetCollisionBounds( INFILTRATORCLASS_HULL_STAND_MIN, INFILTRATORCLASS_HULL_STAND_MAX );
|
||||
m_pPlayer->SetViewOffset( INFILTRATORCLASS_VIEWOFFSET_STAND );
|
||||
m_pPlayer->m_Local.m_flStepSize = INFILTRATORCLASS_STEPSIZE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: New technology has been gained. Recalculate any class specific technology dependencies.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassInfiltrator::GainedNewTechnology( CBaseTechnology *pTechnology )
|
||||
{
|
||||
// Consume corpse technology?
|
||||
m_bCanConsumeCorpses = m_pPlayer->HasNamedTechnology( "inf_consume_corpse" );
|
||||
|
||||
BaseClass::GainedNewTechnology( pTechnology );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if this player's allowed to build another one of the specified objects
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPlayerClassInfiltrator::CanBuild( int iObjectType )
|
||||
{
|
||||
return BaseClass::CanBuild( iObjectType );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called every frame by postthink
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassInfiltrator::ClassThink( void )
|
||||
{
|
||||
BaseClass::ClassThink();
|
||||
|
||||
CheckForAssassination();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The player's just had his camo cleared
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassInfiltrator::ClearCamouflage( void )
|
||||
{
|
||||
float flNewTime = gpGlobals->curtime + INFILTRATOR_RECAMO_TIME;
|
||||
if ( flNewTime > m_flStartCamoAt )
|
||||
{
|
||||
m_flStartCamoAt = flNewTime;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Player's finished disguising.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassInfiltrator::FinishedDisguising( void )
|
||||
{
|
||||
// Remove my camo
|
||||
m_pPlayer->ClearCamouflage();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Player's lost his disguise.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassInfiltrator::StopDisguising( void )
|
||||
{
|
||||
// Remove & restart my camo
|
||||
m_pPlayer->ClearCamouflage();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Handle custom commands for this playerclass
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPlayerClassInfiltrator::ClientCommand( const char *pcmd )
|
||||
{
|
||||
// Toggle thermal vision
|
||||
if ( FStrEq( pcmd, "special" ) )
|
||||
{
|
||||
Assert( m_pPlayer );
|
||||
// Toggle
|
||||
m_pPlayer->SetUsingThermalVision( !m_pPlayer->IsUsingThermalVision() );
|
||||
return true;
|
||||
}
|
||||
|
||||
return BaseClass::ClientCommand( pcmd );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Check to see if I can assassinate anyone
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassInfiltrator::CheckForAssassination( void )
|
||||
{
|
||||
/*
|
||||
// Find my assassination weapon if I haven't already
|
||||
if ( m_hAssassinationWeapon == NULL )
|
||||
{
|
||||
m_hAssassinationWeapon = (CWeaponInfiltrator*)m_pPlayer->Weapon_OwnsThisType( "weapon_infiltrator" );
|
||||
}
|
||||
|
||||
// No Assasination weapon?
|
||||
if ( m_hAssassinationWeapon == NULL )
|
||||
return;
|
||||
|
||||
// If we have a target, bring the assassination weapon up.
|
||||
if ( m_hAssassinationWeapon->GetAssassinationTarget() )
|
||||
{
|
||||
if ( m_pPlayer->GetActiveWeapon() != m_hAssassinationWeapon.Get() )
|
||||
{
|
||||
m_hSwappedWeapon = m_pPlayer->GetActiveWeapon();
|
||||
m_pPlayer->Weapon_Switch( m_hAssassinationWeapon );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have no target. If the assassination weapon's up, put it away.
|
||||
if ( m_pPlayer->GetActiveWeapon() == m_hAssassinationWeapon.Get() )
|
||||
{
|
||||
// Don't switch until the weapon's finished killing people
|
||||
if ( m_pPlayer->GetActiveWeapon()->m_flNextPrimaryAttack <= gpGlobals->curtime )
|
||||
{
|
||||
m_pPlayer->Weapon_Switch( m_hSwappedWeapon );
|
||||
m_hSwappedWeapon = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassInfiltrator::SetPlayerHull( void )
|
||||
{
|
||||
if ( m_pPlayer->GetFlags() & FL_DUCKING )
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( INFILTRATORCLASS_HULL_DUCK_MIN, INFILTRATORCLASS_HULL_DUCK_MAX );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( INFILTRATORCLASS_HULL_STAND_MIN, INFILTRATORCLASS_HULL_STAND_MAX );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassInfiltrator::ResetViewOffset( void )
|
||||
{
|
||||
if ( m_pPlayer )
|
||||
{
|
||||
m_pPlayer->SetViewOffset( INFILTRATORCLASS_VIEWOFFSET_STAND );
|
||||
}
|
||||
}
|
||||
78
game/server/tf2/tf_class_infiltrator.h
Normal file
78
game/server/tf2/tf_class_infiltrator.h
Normal file
@@ -0,0 +1,78 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Infiltrator
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TF_CLASS_INFILTRATOR_H
|
||||
#define TF_CLASS_INFILTRATOR_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#define INFILTRATOR_EAVESDROP_RADIUS 256.0f
|
||||
#define INFILTRATOR_DISGUISE_TIME 3.0f
|
||||
|
||||
// Time after losing camo before the infiltrator can re-camo
|
||||
#define INFILTRATOR_RECAMO_TIME 5.0
|
||||
// Time after spawning that the infilitrator's camo kicks in
|
||||
#define INFILTRATOR_CAMOTIME_AFTER_SPAWN 3.0
|
||||
|
||||
#include "TFClassData_Shared.h"
|
||||
|
||||
class CLootableCorpse;
|
||||
|
||||
//=====================================================================
|
||||
// Infiltrator
|
||||
class CPlayerClassInfiltrator : public CPlayerClass
|
||||
{
|
||||
DECLARE_CLASS( CPlayerClassInfiltrator, CPlayerClass );
|
||||
public:
|
||||
CPlayerClassInfiltrator( CBaseTFPlayer *pPlayer, TFClass iClass );
|
||||
~CPlayerClassInfiltrator();
|
||||
|
||||
virtual void ClassActivate( void );
|
||||
|
||||
virtual const char* GetClassModelString( int nTeam );
|
||||
|
||||
// Class Initialization
|
||||
virtual void RespawnClass( void ); // Called upon all respawns
|
||||
virtual bool ResupplyAmmo( float flPercentage, ResupplyReason_t reason );
|
||||
virtual void SetupMoveData( void ); // Override class specific movement data here.
|
||||
virtual void SetupSizeData( void ); // Override class specific size data here.
|
||||
virtual void ResetViewOffset( void );
|
||||
|
||||
PlayerClassInfiltratorData_t *GetClassData( void ) { return &m_ClassData; }
|
||||
|
||||
virtual void ClassThink( void );
|
||||
virtual void ClearCamouflage( void );
|
||||
|
||||
virtual int CanBuild( int iObjectType );
|
||||
virtual bool ClientCommand( const CCommand &args );
|
||||
virtual void GainedNewTechnology( CBaseTechnology *pTechnology );
|
||||
|
||||
void CheckForAssassination( void );
|
||||
|
||||
// Disguise
|
||||
virtual void FinishedDisguising( void );
|
||||
virtual void StopDisguising( void );
|
||||
|
||||
// Hooks
|
||||
virtual void SetPlayerHull( void );
|
||||
|
||||
protected:
|
||||
bool m_bCanConsumeCorpses;
|
||||
float m_flStartCamoAt;
|
||||
|
||||
// Assassination weapon
|
||||
//CHandle<CWeaponInfiltrator> m_hAssassinationWeapon;
|
||||
CHandle<CBaseCombatWeapon> m_hSwappedWeapon;
|
||||
|
||||
PlayerClassInfiltratorData_t m_ClassData;
|
||||
};
|
||||
|
||||
EXTERN_SEND_TABLE( DT_PlayerClassInfiltratorData )
|
||||
|
||||
#endif // TF_CLASS_INFILTRATOR_H
|
||||
305
game/server/tf2/tf_class_medic.cpp
Normal file
305
game/server/tf2/tf_class_medic.cpp
Normal file
@@ -0,0 +1,305 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: The Medic Player Class
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "basecombatweapon.h"
|
||||
#include "tf_player.h"
|
||||
#include "tf_class_medic.h"
|
||||
#include "tf_obj.h"
|
||||
#include "tf_obj_resupply.h"
|
||||
#include "tf_obj_resourcepump.h"
|
||||
#include "weapon_builder.h"
|
||||
#include "tf_team.h"
|
||||
#include "orders.h"
|
||||
#include "entitylist.h"
|
||||
#include "tf_func_resource.h"
|
||||
#include "order_resupply.h"
|
||||
#include "order_resourcepump.h"
|
||||
#include "order_heal.h"
|
||||
#include "weapon_twohandedcontainer.h"
|
||||
#include "weapon_combatshield.h"
|
||||
|
||||
// Radius buff defines
|
||||
#define RADIUS_BUFF_RANGE 512.0
|
||||
|
||||
#define MEDIC_HEAL_TIME_AFTER_DAMAGE 10.0
|
||||
|
||||
// Medic
|
||||
ConVar class_medic_speed( "class_medic_speed","200", FCVAR_NONE, "Medic movement speed" );
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Medic Data Table
|
||||
//
|
||||
BEGIN_SEND_TABLE_NOBASE( CPlayerClassMedic, DT_PlayerClassMedicData )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : const char
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CPlayerClassMedic::GetClassModelString( int nTeam )
|
||||
{
|
||||
if (nTeam == TEAM_HUMANS)
|
||||
return "models/player/human_medic.mdl";
|
||||
else
|
||||
return "models/player/recon.mdl";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPlayerClassMedic::CPlayerClassMedic( CBaseTFPlayer *pPlayer, TFClass iClass ) : CPlayerClass( pPlayer, iClass )
|
||||
{
|
||||
for (int i = 0; i < MAX_TF_TEAMS; ++i)
|
||||
{
|
||||
SetClassModel( MAKE_STRING(GetClassModelString(i)), i );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassMedic::SetupSizeData( void )
|
||||
{
|
||||
// Initially set the player to the base player class standing hull size.
|
||||
m_pPlayer->SetCollisionBounds( MEDICCLASS_HULL_STAND_MIN, MEDICCLASS_HULL_STAND_MAX );
|
||||
m_pPlayer->SetViewOffset( MEDICCLASS_VIEWOFFSET_STAND );
|
||||
m_pPlayer->m_Local.m_flStepSize = MEDICCLASS_STEPSIZE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPlayerClassMedic::~CPlayerClassMedic()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassMedic::ClassActivate( void )
|
||||
{
|
||||
BaseClass::ClassActivate();
|
||||
|
||||
// Setup movement data.
|
||||
SetupMoveData();
|
||||
|
||||
m_hWpnShield = NULL;
|
||||
m_hWpnPlasma = NULL;
|
||||
|
||||
m_bHasAutoRepair = false;
|
||||
|
||||
m_flNextHealTime = 0;
|
||||
|
||||
memset( &m_ClassData, 0, sizeof( m_ClassData ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassMedic::ClassDeactivate( void )
|
||||
{
|
||||
BaseClass::ClassDeactivate();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassMedic::CreateClass( void )
|
||||
{
|
||||
BaseClass::CreateClass();
|
||||
|
||||
// Create our two handed weapon layout
|
||||
m_hWpnPlasma = static_cast< CBaseTFCombatWeapon * >( m_pPlayer->GiveNamedItem( "weapon_combat_burstrifle" ) );
|
||||
m_hWpnShield = m_pPlayer->GetCombatShield();
|
||||
CWeaponTwoHandedContainer *p = ( CWeaponTwoHandedContainer * )m_pPlayer->Weapon_OwnsThisType( "weapon_twohandedcontainer" );
|
||||
if ( !p )
|
||||
{
|
||||
p = static_cast< CWeaponTwoHandedContainer * >( m_pPlayer->GiveNamedItem( "weapon_twohandedcontainer" ) );
|
||||
}
|
||||
if ( p && m_hWpnShield.Get() && m_hWpnPlasma.Get() )
|
||||
{
|
||||
m_hWpnShield->SetReflectViewModelAnimations( true );
|
||||
p->SetWeapons( m_hWpnPlasma, m_hWpnShield );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassMedic::RespawnClass( void )
|
||||
{
|
||||
BaseClass::RespawnClass();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPlayerClassMedic::ResupplyAmmo( float flFraction, ResupplyReason_t reason )
|
||||
{
|
||||
bool bGiven = false;
|
||||
|
||||
if ((reason == RESUPPLY_ALL_FROM_STATION) || (reason == RESUPPLY_GRENADES_FROM_STATION))
|
||||
{
|
||||
if (ResupplyAmmoType( 3 * flFraction, "Grenades" ))
|
||||
bGiven = true;
|
||||
}
|
||||
|
||||
if ((reason == RESUPPLY_ALL_FROM_STATION) || (reason == RESUPPLY_AMMO_FROM_STATION))
|
||||
{
|
||||
}
|
||||
|
||||
if ( reason == RESUPPLY_RESPAWN )
|
||||
{
|
||||
}
|
||||
|
||||
if ( BaseClass::ResupplyAmmo(flFraction, reason) )
|
||||
bGiven = true;
|
||||
return bGiven;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set medic class specific movement data here.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassMedic::SetupMoveData( void )
|
||||
{
|
||||
// Setup Class statistics
|
||||
m_flMaxWalkingSpeed = class_medic_speed.GetFloat();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called every frame by postthink
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassMedic::ClassThink( void )
|
||||
{
|
||||
// Heal me if it's time (and I'm not dead!)
|
||||
if ( m_pPlayer->IsAlive() && m_flNextHealTime && m_flNextHealTime < gpGlobals->curtime )
|
||||
{
|
||||
if ( m_pPlayer->GetHealth() < m_pPlayer->GetMaxHealth() )
|
||||
{
|
||||
// Heal the player
|
||||
m_pPlayer->TakeHealth( 1.0, DMG_GENERIC );
|
||||
m_flNextHealTime = gpGlobals->curtime + 0.1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_flNextHealTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
BaseClass::ClassThink();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if this player's allowed to build another one of the specified objects
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPlayerClassMedic::CanBuild( int iObjectType )
|
||||
{
|
||||
return BaseClass::CanBuild( iObjectType );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Update abilities based on new technologies gained
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassMedic::GainedNewTechnology( CBaseTechnology *pTechnology )
|
||||
{
|
||||
// Autorepair
|
||||
m_bHasAutoRepair = m_pPlayer->HasNamedTechnology( "obj_autorepair" );
|
||||
|
||||
BaseClass::GainedNewTechnology( pTechnology );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Create a personal order for this player
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassMedic::CreatePersonalOrder( void )
|
||||
{
|
||||
if ( CreateInitialOrder() )
|
||||
return;
|
||||
|
||||
// Check for healing orders.
|
||||
if ( COrderHeal::CreateOrder( this ) )
|
||||
return;
|
||||
|
||||
// Should they build a resource pump?
|
||||
if ( COrderResourcePump::CreateOrder( this ) )
|
||||
return;
|
||||
|
||||
// Build a resupply station?
|
||||
if ( COrderResupply::CreateOrder( this ) )
|
||||
return;
|
||||
|
||||
BaseClass::CreatePersonalOrder();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassMedic::SetPlayerHull( void )
|
||||
{
|
||||
if ( m_pPlayer->GetFlags() & FL_DUCKING )
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( MEDICCLASS_HULL_DUCK_MIN, MEDICCLASS_HULL_DUCK_MAX );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( MEDICCLASS_HULL_STAND_MIN, MEDICCLASS_HULL_STAND_MAX );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassMedic::GetPlayerHull( bool bDucking, Vector &vecMin, Vector &vecMax )
|
||||
{
|
||||
if ( bDucking )
|
||||
{
|
||||
VectorCopy( MEDICCLASS_HULL_DUCK_MIN, vecMin );
|
||||
VectorCopy( MEDICCLASS_HULL_DUCK_MAX, vecMax );
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorCopy( MEDICCLASS_HULL_STAND_MIN, vecMin );
|
||||
VectorCopy( MEDICCLASS_HULL_STAND_MAX, vecMax );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassMedic::ResetViewOffset( void )
|
||||
{
|
||||
if ( m_pPlayer )
|
||||
{
|
||||
m_pPlayer->SetViewOffset( MEDICCLASS_VIEWOFFSET_STAND );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: The player has taken damage. Return the damage done.
|
||||
//-----------------------------------------------------------------------------
|
||||
float CPlayerClassMedic::OnTakeDamage( const CTakeDamageInfo &info )
|
||||
{
|
||||
// Stop healing when taking damage
|
||||
m_flNextHealTime = gpGlobals->curtime + MEDIC_HEAL_TIME_AFTER_DAMAGE;
|
||||
|
||||
return BaseClass::OnTakeDamage( info );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassMedic::InitVCollision( void )
|
||||
{
|
||||
CPhysCollide *pStandModel = PhysCreateBbox( MEDICCLASS_HULL_STAND_MIN, MEDICCLASS_HULL_STAND_MAX );
|
||||
CPhysCollide *pCrouchModel = PhysCreateBbox( MEDICCLASS_HULL_DUCK_MIN, MEDICCLASS_HULL_DUCK_MAX );
|
||||
m_pPlayer->SetupVPhysicsShadow( pStandModel, "tfplayer_medic_stand", pCrouchModel, "tfplayer_medic_crouch" );
|
||||
}
|
||||
73
game/server/tf2/tf_class_medic.h
Normal file
73
game/server/tf2/tf_class_medic.h
Normal file
@@ -0,0 +1,73 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Medic playerclass
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TF_CLASS_MEDIC_H
|
||||
#define TF_CLASS_MEDIC_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "TFClassData_Shared.h"
|
||||
|
||||
//=====================================================================
|
||||
// Medic
|
||||
class CPlayerClassMedic : public CPlayerClass
|
||||
{
|
||||
DECLARE_CLASS( CPlayerClassMedic, CPlayerClass );
|
||||
public:
|
||||
CPlayerClassMedic( CBaseTFPlayer *pPlayer, TFClass iClass );
|
||||
virtual ~CPlayerClassMedic();
|
||||
|
||||
virtual void ClassActivate( void );
|
||||
virtual void ClassDeactivate( void );
|
||||
|
||||
virtual const char* GetClassModelString( int nTeam );
|
||||
|
||||
// Class Initialization
|
||||
virtual void CreateClass( void ); // Create the class upon initial spawn
|
||||
virtual void RespawnClass( void ); // Called upon all respawns
|
||||
virtual bool ResupplyAmmo( float flPercentage, ResupplyReason_t reason );
|
||||
virtual void SetupMoveData( void ); // Override class specific movement data here.
|
||||
virtual void SetupSizeData( void ); // Override class specific size data here.
|
||||
virtual void ResetViewOffset( void );
|
||||
|
||||
PlayerClassMedicData_t *GetClassData( void ) { return &m_ClassData; }
|
||||
|
||||
virtual void ClassThink( void );
|
||||
virtual void GainedNewTechnology( CBaseTechnology *pTechnology );
|
||||
|
||||
// Objects
|
||||
int CanBuild( int iObjectType );
|
||||
|
||||
// Orders
|
||||
virtual void CreatePersonalOrder( void );
|
||||
|
||||
// Hooks
|
||||
virtual void SetPlayerHull( void );
|
||||
virtual void GetPlayerHull( bool bDucking, Vector &vecMin, Vector &vecMax );
|
||||
|
||||
virtual float OnTakeDamage( const CTakeDamageInfo &info );
|
||||
|
||||
// Player physics shadow.
|
||||
void InitVCollision( void );
|
||||
|
||||
protected:
|
||||
|
||||
// Weapons
|
||||
CHandle<CBaseTFCombatWeapon> m_hWpnPlasma;
|
||||
|
||||
bool m_bHasAutoRepair;
|
||||
float m_flNextHealTime;
|
||||
|
||||
PlayerClassMedicData_t m_ClassData;
|
||||
};
|
||||
|
||||
EXTERN_SEND_TABLE( DT_PlayerClassMedicData )
|
||||
|
||||
#endif // TF_CLASS_MEDIC_H
|
||||
164
game/server/tf2/tf_class_pyro.cpp
Normal file
164
game/server/tf2/tf_class_pyro.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "basecombatweapon.h"
|
||||
#include "tf_player.h"
|
||||
#include "tf_class_pyro.h"
|
||||
#include "weapon_twohandedcontainer.h"
|
||||
#include "weapon_gas_can.h"
|
||||
#include "weapon_flame_thrower.h"
|
||||
#include "gasoline_shared.h"
|
||||
#include "weapon_combatshield.h"
|
||||
|
||||
BEGIN_SEND_TABLE_NOBASE( CPlayerClassPyro, DT_PlayerClassPyroData )
|
||||
END_SEND_TABLE()
|
||||
|
||||
|
||||
CPlayerClassPyro::CPlayerClassPyro( CBaseTFPlayer *pPlayer, TFClass iClass ) : CPlayerClass( pPlayer, iClass )
|
||||
{
|
||||
for (int i = 0; i < MAX_TF_TEAMS; ++i)
|
||||
{
|
||||
SetClassModel( MAKE_STRING(GetClassModelString(i)), i );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CPlayerClassPyro::~CPlayerClassPyro()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void CPlayerClassPyro::SetupSizeData()
|
||||
{
|
||||
// Initially set the player to the base player class standing hull size.
|
||||
m_pPlayer->SetCollisionBounds( PYROCLASS_HULL_STAND_MIN, PYROCLASS_HULL_STAND_MAX );
|
||||
m_pPlayer->SetViewOffset( PYROCLASS_VIEWOFFSET_STAND );
|
||||
m_pPlayer->m_Local.m_flStepSize = PYROCLASS_STEPSIZE;
|
||||
}
|
||||
|
||||
|
||||
void CPlayerClassPyro::ClassActivate()
|
||||
{
|
||||
BaseClass::ClassActivate();
|
||||
|
||||
// Setup movement data.
|
||||
SetupMoveData();
|
||||
|
||||
memset( &m_ClassData, 0, sizeof( m_ClassData ) );
|
||||
}
|
||||
|
||||
|
||||
const char *CPlayerClassPyro::GetClassModelString( int nTeam )
|
||||
{
|
||||
if (nTeam == TEAM_HUMANS)
|
||||
return "models/player/medic.mdl";
|
||||
else
|
||||
return "models/player/recon.mdl";
|
||||
}
|
||||
|
||||
|
||||
void CPlayerClassPyro::CreateClass()
|
||||
{
|
||||
BaseClass::CreateClass();
|
||||
|
||||
// Create our two handed weapon layout
|
||||
m_hWpnFlameThrower = static_cast< CWeaponFlameThrower * >( m_pPlayer->GiveNamedItem( "weapon_flame_thrower" ) );
|
||||
m_hWpnGasCan = static_cast< CWeaponGasCan * >( m_pPlayer->GiveNamedItem( "weapon_gas_can" ) );
|
||||
m_hWpnShield = m_pPlayer->GetCombatShield();
|
||||
CWeaponTwoHandedContainer *p = ( CWeaponTwoHandedContainer * )m_pPlayer->Weapon_OwnsThisType( "weapon_twohandedcontainer" );
|
||||
if ( !p )
|
||||
{
|
||||
p = static_cast< CWeaponTwoHandedContainer * >( m_pPlayer->GiveNamedItem( "weapon_twohandedcontainer" ) );
|
||||
}
|
||||
if ( p && m_hWpnShield.Get() && m_hWpnGasCan.Get() )
|
||||
{
|
||||
m_hWpnShield->SetReflectViewModelAnimations( true );
|
||||
p->SetWeapons( m_hWpnGasCan, m_hWpnShield );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassPyro::SetPlayerHull()
|
||||
{
|
||||
if ( m_pPlayer->GetFlags() & FL_DUCKING )
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( PYROCLASS_HULL_DUCK_MIN, PYROCLASS_HULL_DUCK_MAX );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( PYROCLASS_HULL_STAND_MIN, PYROCLASS_HULL_STAND_MAX );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassPyro::GetPlayerHull( bool bDucking, Vector &vecMin, Vector &vecMax )
|
||||
{
|
||||
if ( bDucking )
|
||||
{
|
||||
VectorCopy( PYROCLASS_HULL_DUCK_MIN, vecMin );
|
||||
VectorCopy( PYROCLASS_HULL_DUCK_MAX, vecMax );
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorCopy( PYROCLASS_HULL_STAND_MIN, vecMin );
|
||||
VectorCopy( PYROCLASS_HULL_STAND_MAX, vecMax );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CPlayerClassPyro::ResetViewOffset()
|
||||
{
|
||||
if ( m_pPlayer )
|
||||
{
|
||||
m_pPlayer->SetViewOffset( PYROCLASS_VIEWOFFSET_STAND );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassPyro::InitVCollision()
|
||||
{
|
||||
CPhysCollide *pStandModel = PhysCreateBbox( PYROCLASS_HULL_STAND_MIN, PYROCLASS_HULL_STAND_MAX );
|
||||
CPhysCollide *pCrouchModel = PhysCreateBbox( PYROCLASS_HULL_DUCK_MIN, PYROCLASS_HULL_DUCK_MAX );
|
||||
m_pPlayer->SetupVPhysicsShadow( pStandModel, "tfplayer_medic_stand", pCrouchModel, "tfplayer_medic_crouch" );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPlayerClassPyro::ResupplyAmmo( float flFraction, ResupplyReason_t reason )
|
||||
{
|
||||
bool bGiven = false;
|
||||
|
||||
if ((reason == RESUPPLY_ALL_FROM_STATION) || (reason == RESUPPLY_AMMO_FROM_STATION))
|
||||
{
|
||||
if (ResupplyAmmoType( 80 * flFraction, PYRO_AMMO_TYPE ))
|
||||
bGiven = true;
|
||||
}
|
||||
|
||||
// On respawn, resupply base weapon ammo
|
||||
if ( reason == RESUPPLY_RESPAWN )
|
||||
{
|
||||
if ( ResupplyAmmoType( 30, PYRO_AMMO_TYPE ) )
|
||||
bGiven = true;
|
||||
}
|
||||
|
||||
if ( BaseClass::ResupplyAmmo(flFraction, reason) )
|
||||
bGiven = true;
|
||||
|
||||
return bGiven;
|
||||
}
|
||||
|
||||
57
game/server/tf2/tf_class_pyro.h
Normal file
57
game/server/tf2/tf_class_pyro.h
Normal file
@@ -0,0 +1,57 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TF_CLASS_PYRO_H
|
||||
#define TF_CLASS_PYRO_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
#include "TFClassData_Shared.h"
|
||||
|
||||
|
||||
class CWeaponFlameThrower;
|
||||
class CWeaponGasCan;
|
||||
|
||||
|
||||
//=====================================================================
|
||||
// Medic
|
||||
class CPlayerClassPyro : public CPlayerClass
|
||||
{
|
||||
DECLARE_CLASS( CPlayerClassPyro, CPlayerClass );
|
||||
public:
|
||||
CPlayerClassPyro( CBaseTFPlayer *pPlayer, TFClass iClass );
|
||||
virtual ~CPlayerClassPyro();
|
||||
|
||||
|
||||
// Overrides.
|
||||
public:
|
||||
|
||||
virtual void SetupSizeData();
|
||||
virtual void CreateClass();
|
||||
virtual void SetPlayerHull();
|
||||
virtual void GetPlayerHull( bool bDucking, Vector &vecMin, Vector &vecMax );
|
||||
virtual void ResetViewOffset();
|
||||
virtual void InitVCollision();
|
||||
virtual bool ResupplyAmmo( float flFraction, ResupplyReason_t reason );
|
||||
virtual void ClassActivate();
|
||||
|
||||
virtual const char* GetClassModelString( int nTeam );
|
||||
|
||||
|
||||
private:
|
||||
|
||||
PlayerClassPyroData_t m_ClassData;
|
||||
|
||||
CHandle<CWeaponFlameThrower> m_hWpnFlameThrower;
|
||||
CHandle<CWeaponGasCan> m_hWpnGasCan;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // TF_CLASS_PYRO_H
|
||||
221
game/server/tf2/tf_class_recon.cpp
Normal file
221
game/server/tf2/tf_class_recon.cpp
Normal file
@@ -0,0 +1,221 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: The Recon Player Class
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "tf_player.h"
|
||||
#include "tf_class_recon.h"
|
||||
#include "tf_reconvars.h"
|
||||
#include "in_buttons.h"
|
||||
#include "basecombatweapon.h"
|
||||
#include "tf_obj.h"
|
||||
#include "weapon_builder.h"
|
||||
#include "tf_team.h"
|
||||
#include "tf_func_resource.h"
|
||||
#include "orders.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
|
||||
|
||||
extern short g_sModelIndexFireball;
|
||||
|
||||
ConVar class_recon_speed( "class_recon_speed","250", FCVAR_NONE, "Recon movement speed" );
|
||||
|
||||
// ------------------------------------------------------------------------ //
|
||||
// Globals.
|
||||
// ------------------------------------------------------------------------ //
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Recon Data Table
|
||||
//
|
||||
BEGIN_SEND_TABLE_NOBASE( CPlayerClassRecon, DT_PlayerClassReconData )
|
||||
SendPropInt ( SENDINFO_STRUCTELEM( m_ClassData.m_nJumpCount ), 3, SPROP_UNSIGNED ),
|
||||
SendPropFloat ( SENDINFO_STRUCTELEM( m_ClassData.m_flSuppressionJumpTime ), 32, SPROP_NOSCALE ),
|
||||
SendPropFloat ( SENDINFO_STRUCTELEM( m_ClassData.m_flSuppressionImpactTime ), 32, SPROP_NOSCALE ),
|
||||
SendPropFloat ( SENDINFO_STRUCTELEM( m_ClassData.m_flStickTime ), 32, SPROP_NOSCALE ),
|
||||
SendPropFloat ( SENDINFO_STRUCTELEM( m_ClassData.m_flActiveJumpTime ), 32, SPROP_NOSCALE ),
|
||||
SendPropFloat ( SENDINFO_STRUCTELEM( m_ClassData.m_flImpactDist ), 32, SPROP_NOSCALE ),
|
||||
SendPropVector ( SENDINFO_STRUCTELEM( m_ClassData.m_vecImpactNormal ), -1, SPROP_NORMAL ),
|
||||
SendPropVector ( SENDINFO_STRUCTELEM( m_ClassData.m_vecUnstickVelocity ), -1, SPROP_COORD ),
|
||||
SendPropInt ( SENDINFO_STRUCTELEM( m_ClassData.m_bTrailParticles ), 1, SPROP_UNSIGNED ),
|
||||
END_SEND_TABLE()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : const char
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CPlayerClassRecon::GetClassModelString( int nTeam )
|
||||
{
|
||||
static const char *string = "models/player/recon.mdl";
|
||||
return string;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------ //
|
||||
// CPlayerClassRecon
|
||||
// ------------------------------------------------------------------------ //
|
||||
CPlayerClassRecon::CPlayerClassRecon( CBaseTFPlayer *pPlayer, TFClass iClass ) : CPlayerClass( pPlayer, iClass )
|
||||
{
|
||||
for (int i = 0; i < MAX_TF_TEAMS; ++i)
|
||||
{
|
||||
SetClassModel( MAKE_STRING(GetClassModelString(i)), i );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPlayerClassRecon::~CPlayerClassRecon()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassRecon::ClassActivate( void )
|
||||
{
|
||||
BaseClass::ClassActivate();
|
||||
|
||||
// Setup movement data.
|
||||
SetupMoveData();
|
||||
|
||||
m_bHasRadarScanner = false;
|
||||
|
||||
memset( &m_ClassData, 0, sizeof( m_ClassData ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassRecon::ClassDeactivate( void )
|
||||
{
|
||||
BaseClass::ClassDeactivate();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPlayerClassRecon::ResupplyAmmo( float flFraction, ResupplyReason_t reason )
|
||||
{
|
||||
bool bGiven = false;
|
||||
|
||||
if ((reason == RESUPPLY_ALL_FROM_STATION) || (reason == RESUPPLY_GRENADES_FROM_STATION))
|
||||
{
|
||||
}
|
||||
|
||||
if ((reason == RESUPPLY_ALL_FROM_STATION) || (reason == RESUPPLY_AMMO_FROM_STATION))
|
||||
{
|
||||
}
|
||||
|
||||
if ( BaseClass::ResupplyAmmo(flFraction, reason) )
|
||||
bGiven = true;
|
||||
return bGiven;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set recon class specific movement data here.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassRecon::SetupMoveData( void )
|
||||
{
|
||||
// Setup Class statistics
|
||||
m_flMaxWalkingSpeed = class_recon_speed.GetFloat();
|
||||
|
||||
m_ClassData.m_nJumpCount = 0;
|
||||
m_ClassData.m_flSuppressionJumpTime = -99999;
|
||||
m_ClassData.m_flSuppressionImpactTime = -99999;
|
||||
m_ClassData.m_flActiveJumpTime = -99999;
|
||||
m_ClassData.m_flStickTime = -99999;
|
||||
m_ClassData.m_flImpactDist = -99999;
|
||||
m_ClassData.m_vecImpactNormal.Init();
|
||||
m_ClassData.m_vecUnstickVelocity.Init();
|
||||
m_ClassData.m_bTrailParticles = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassRecon::SetupSizeData( void )
|
||||
{
|
||||
// Initially set the player to the base player class standing hull size.
|
||||
m_pPlayer->SetCollisionBounds( RECONCLASS_HULL_STAND_MIN, RECONCLASS_HULL_STAND_MAX );
|
||||
m_pPlayer->SetViewOffset( RECONCLASS_VIEWOFFSET_STAND );
|
||||
m_pPlayer->m_Local.m_flStepSize = RECONCLASS_STEPSIZE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Return true if this player's allowed to build another one of the specified objects
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPlayerClassRecon::CanBuild( int iObjectType )
|
||||
{
|
||||
return BaseClass::CanBuild( iObjectType );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassRecon::ClassThink()
|
||||
{
|
||||
BaseClass::ClassThink();
|
||||
|
||||
m_ClassData.m_bTrailParticles = (m_pPlayer->IsAlive() && !(m_pPlayer->GetFlags() & FL_ONGROUND));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassRecon::CreatePersonalOrder()
|
||||
{
|
||||
if ( CreateInitialOrder() )
|
||||
return;
|
||||
|
||||
BaseClass::CreatePersonalOrder();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: New technology has been gained. Recalculate any class specific technology dependencies.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassRecon::GainedNewTechnology( CBaseTechnology *pTechnology )
|
||||
{
|
||||
// Radar Scanner
|
||||
if ( m_pPlayer->HasNamedTechnology( "rec_b_radar_scanners" ) )
|
||||
{
|
||||
m_bHasRadarScanner = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bHasRadarScanner = false;
|
||||
}
|
||||
|
||||
BaseClass::GainedNewTechnology( pTechnology );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassRecon::SetPlayerHull( void )
|
||||
{
|
||||
if ( m_pPlayer->GetFlags() & FL_DUCKING )
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( RECONCLASS_HULL_DUCK_MIN, RECONCLASS_HULL_DUCK_MAX );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( RECONCLASS_HULL_STAND_MIN, RECONCLASS_HULL_STAND_MAX );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassRecon::ResetViewOffset( void )
|
||||
{
|
||||
if ( m_pPlayer )
|
||||
{
|
||||
m_pPlayer->SetViewOffset( RECONCLASS_VIEWOFFSET_STAND );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
60
game/server/tf2/tf_class_recon.h
Normal file
60
game/server/tf2/tf_class_recon.h
Normal file
@@ -0,0 +1,60 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef TF_CLASS_RECON_H
|
||||
#define TF_CLASS_RECON_H
|
||||
#pragma once
|
||||
|
||||
#include "TFClassData_Shared.h"
|
||||
#include "tf_playerclass.h"
|
||||
|
||||
class CTFJetpackSteam;
|
||||
class CReconJetpackLevel;
|
||||
|
||||
|
||||
//=====================================================================
|
||||
// Recon
|
||||
class CPlayerClassRecon : public CPlayerClass
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( CPlayerClassRecon, CPlayerClass );
|
||||
|
||||
CPlayerClassRecon( CBaseTFPlayer *pPlayer, TFClass iClass );
|
||||
~CPlayerClassRecon();
|
||||
|
||||
virtual void ClassActivate( void );
|
||||
virtual void ClassDeactivate( void );
|
||||
|
||||
virtual const char* GetClassModelString( int nTeam );
|
||||
|
||||
// Class Initialization
|
||||
virtual bool ResupplyAmmo( float flPercentage, ResupplyReason_t reason );
|
||||
virtual void SetupMoveData( void ); // Override class specific movement data here.
|
||||
virtual void SetupSizeData( void ); // Override class specific size data here.
|
||||
virtual void ResetViewOffset( void );
|
||||
|
||||
PlayerClassReconData_t *GetClassData( void ) { return &m_ClassData; }
|
||||
|
||||
virtual int CanBuild( int iObjectType );
|
||||
|
||||
virtual void ClassThink( void );
|
||||
virtual void GainedNewTechnology( CBaseTechnology *pTechnology );
|
||||
|
||||
virtual void CreatePersonalOrder();
|
||||
|
||||
// Hooks
|
||||
virtual void SetPlayerHull( void );
|
||||
|
||||
CNetworkVarEmbedded( PlayerClassReconData_t, m_ClassData );
|
||||
|
||||
protected:
|
||||
bool m_bHasRadarScanner;
|
||||
};
|
||||
|
||||
EXTERN_SEND_TABLE( DT_PlayerClassReconData )
|
||||
|
||||
#endif // TF_CLASS_RECON_H
|
||||
328
game/server/tf2/tf_class_sapper.cpp
Normal file
328
game/server/tf2/tf_class_sapper.cpp
Normal file
@@ -0,0 +1,328 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: The Sapper Player Class
|
||||
//
|
||||
// $Workfile: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "tf_player.h"
|
||||
#include "tf_class_sapper.h"
|
||||
#include "basecombatweapon.h"
|
||||
#include "weapon_builder.h"
|
||||
#include "tf_team.h"
|
||||
#include "entitylist.h"
|
||||
#include "tf_obj.h"
|
||||
#include "weapon_mortar.h"
|
||||
#include "orders.h"
|
||||
#include "engine/IEngineSound.h"
|
||||
#include "weapon_twohandedcontainer.h"
|
||||
#include "weapon_combatshield.h"
|
||||
#include "tf_vehicle_teleport_station.h"
|
||||
#define EMP_RADIUS_NORMAL ( 512.0f )
|
||||
#define EMP_RADIUS_MEDIUM ( 1024.0f )
|
||||
#define EMP_RADIUS_HUGE ( 4096.0f )
|
||||
|
||||
#define EMP_RECHARGETIME_NORMAL ( 20.0f )
|
||||
#define EMP_RECHARGETIME_FAST ( 15.0f )
|
||||
|
||||
#define EMP_EFFECTTIME_NORMAL ( 10.0f )
|
||||
#define EMP_EFFECTTIME_LONG ( 15.0f )
|
||||
|
||||
ConVar class_sapper_speed( "class_sapper_speed","225", FCVAR_NONE, "Sapper movement speed" );
|
||||
ConVar class_sapper_boost_amount( "class_sapper_boost_amount","35", FCVAR_NONE, "Amount of energy drained for the Sapper to get a boost." );
|
||||
ConVar class_sapper_boost_time( "class_sapper_boost_time","15", FCVAR_NONE, "Sapper's boost time after draining a full charge of boost." );
|
||||
ConVar class_sapper_boost_rate( "class_sapper_boost_rate","1", FCVAR_NONE, "Sapper's boost rate on his self-boost." );
|
||||
ConVar class_sapper_damage_modifier( "class_sapper_damage_modifier", "1.5", 0, "Scales the damage a Sapper does while he's self-boosted." );
|
||||
|
||||
BEGIN_SEND_TABLE_NOBASE( CPlayerClassSapper, DT_PlayerClassSapperData )
|
||||
SendPropFloat( SENDINFO( m_flDrainedEnergy ), 8, SPROP_UNSIGNED, 0.0f, 1.0f ),
|
||||
END_SEND_TABLE()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Output : const char
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CPlayerClassSapper::GetClassModelString( int nTeam )
|
||||
{
|
||||
static const char *string = "models/player/technician.mdl";
|
||||
return string;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sapper
|
||||
//-----------------------------------------------------------------------------
|
||||
CPlayerClassSapper::CPlayerClassSapper( CBaseTFPlayer *pPlayer, TFClass iClass ) : CPlayerClass( pPlayer, iClass )
|
||||
{
|
||||
for (int i = 0; i < MAX_TF_TEAMS; ++i)
|
||||
{
|
||||
SetClassModel( MAKE_STRING(GetClassModelString(i)), i );
|
||||
}
|
||||
|
||||
// Setup movement data.
|
||||
SetupMoveData();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPlayerClassSapper::~CPlayerClassSapper()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Any objects created/owned by class should be allocated and destroyed here
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassSapper::ClassActivate( void )
|
||||
{
|
||||
BaseClass::ClassActivate();
|
||||
|
||||
m_bHasMediumRangeEMP = false;
|
||||
m_bHasFasterRechargingEMP = false;
|
||||
m_bHasHugeRadiusEMP = false;
|
||||
m_bHasLongerLastingEMPEffect = false;
|
||||
|
||||
m_vecLastOrigin.Init();
|
||||
m_flLastMoveTime = 0.0f;
|
||||
|
||||
memset( &m_ClassData, 0, sizeof( m_ClassData ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassSapper::ClassDeactivate( void )
|
||||
{
|
||||
m_DamageModifier.RemoveModifier();
|
||||
BaseClass::ClassDeactivate();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassSapper::CreateClass( void )
|
||||
{
|
||||
BaseClass::CreateClass();
|
||||
|
||||
// Create our two handed weapon layout
|
||||
m_hWpnPlasma = static_cast< CBaseTFCombatWeapon * >( m_pPlayer->GiveNamedItem( "weapon_combat_shotgun" ) );
|
||||
m_hWpnShield = m_pPlayer->GetCombatShield();
|
||||
CWeaponTwoHandedContainer *p = ( CWeaponTwoHandedContainer * )m_pPlayer->Weapon_OwnsThisType( "weapon_twohandedcontainer" );
|
||||
if ( !p )
|
||||
{
|
||||
p = static_cast< CWeaponTwoHandedContainer * >( m_pPlayer->GiveNamedItem( "weapon_twohandedcontainer" ) );
|
||||
}
|
||||
if ( p && m_hWpnShield.Get() && m_hWpnPlasma.Get() )
|
||||
{
|
||||
m_hWpnShield->SetReflectViewModelAnimations( true );
|
||||
p->SetWeapons( m_hWpnPlasma, m_hWpnShield );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassSapper::RespawnClass( void )
|
||||
{
|
||||
BaseClass::RespawnClass();
|
||||
|
||||
// Reset time of last move
|
||||
m_vecLastOrigin.Init();
|
||||
m_flLastMoveTime = 0.0f;
|
||||
m_flDrainedEnergy = 0;
|
||||
m_flBoostEndTime = 0;
|
||||
m_DamageModifier.SetModifier( class_sapper_damage_modifier.GetFloat() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPlayerClassSapper::ResupplyAmmo( float flFraction, ResupplyReason_t reason )
|
||||
{
|
||||
bool bGiven = false;
|
||||
if ((reason == RESUPPLY_ALL_FROM_STATION) || (reason == RESUPPLY_GRENADES_FROM_STATION))
|
||||
{
|
||||
if (ResupplyAmmoType( 3 * flFraction, "Grenades" ))
|
||||
bGiven = true;
|
||||
}
|
||||
|
||||
if ((reason == RESUPPLY_ALL_FROM_STATION) || (reason == RESUPPLY_AMMO_FROM_STATION))
|
||||
{
|
||||
}
|
||||
|
||||
// On respawn, resupply base weapon ammo
|
||||
if ( reason == RESUPPLY_RESPAWN )
|
||||
{
|
||||
}
|
||||
|
||||
if ( BaseClass::ResupplyAmmo(flFraction,reason) )
|
||||
bGiven = true;
|
||||
return bGiven;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set sapper class specific movement data here.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassSapper::SetupMoveData( void )
|
||||
{
|
||||
// Setup Class statistics
|
||||
m_flMaxWalkingSpeed = class_sapper_speed.GetFloat();
|
||||
m_vecLastOrigin.Init();
|
||||
m_flLastMoveTime = 0.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassSapper::SetupSizeData( void )
|
||||
{
|
||||
// Initially set the player to the base player class standing hull size.
|
||||
m_pPlayer->SetCollisionBounds( SAPPERCLASS_HULL_STAND_MIN, SAPPERCLASS_HULL_STAND_MAX );
|
||||
m_pPlayer->SetViewOffset( SAPPERCLASS_VIEWOFFSET_STAND );
|
||||
m_pPlayer->m_Local.m_flStepSize = SAPPERCLASS_STEPSIZE;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: New technology has been gained. Recalculate any class specific technology dependencies.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassSapper::GainedNewTechnology( CBaseTechnology *pTechnology )
|
||||
{
|
||||
m_bHasMediumRangeEMP = false;
|
||||
m_bHasFasterRechargingEMP = false;
|
||||
m_bHasHugeRadiusEMP = false;
|
||||
m_bHasLongerLastingEMPEffect = false;
|
||||
|
||||
if ( m_pPlayer->HasNamedTechnology( "emp1" ) )
|
||||
{
|
||||
m_bHasFasterRechargingEMP = true;
|
||||
}
|
||||
|
||||
if ( m_pPlayer->HasNamedTechnology( "emp3" ) )
|
||||
{
|
||||
m_bHasMediumRangeEMP = true;
|
||||
}
|
||||
|
||||
if ( m_pPlayer->HasNamedTechnology( "emp4" ) )
|
||||
{
|
||||
m_bHasLongerLastingEMPEffect = true;
|
||||
}
|
||||
|
||||
if ( m_pPlayer->HasNamedTechnology( "emp5" ) )
|
||||
{
|
||||
m_bHasHugeRadiusEMP = true;
|
||||
}
|
||||
|
||||
BaseClass::GainedNewTechnology( pTechnology );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassSapper::ClassThink( void )
|
||||
{
|
||||
if ( m_pPlayer->GetLocalOrigin() != m_vecLastOrigin )
|
||||
{
|
||||
m_vecLastOrigin = m_pPlayer->GetLocalOrigin();
|
||||
m_flLastMoveTime = gpGlobals->curtime;
|
||||
}
|
||||
|
||||
// Am I boosting myself?
|
||||
if ( m_pPlayer->IsAlive() && (m_flBoostEndTime > gpGlobals->curtime) )
|
||||
{
|
||||
m_pPlayer->AttemptToPowerup( POWERUP_BOOST, class_sapper_boost_time.GetFloat(), class_sapper_boost_rate.GetFloat() * 0.1, m_pPlayer, &m_DamageModifier );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_DamageModifier.RemoveModifier();
|
||||
}
|
||||
|
||||
BaseClass::ClassThink();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPlayerClassSapper::CheckStationaryTime( float time_required )
|
||||
{
|
||||
// Has enough time passed?
|
||||
if ( gpGlobals->curtime >= m_flLastMoveTime + time_required )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not enough time yet
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassSapper::CreatePersonalOrder( void )
|
||||
{
|
||||
if ( CreateInitialOrder() )
|
||||
return;
|
||||
|
||||
BaseClass::CreatePersonalOrder();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassSapper::SetPlayerHull( void )
|
||||
{
|
||||
if ( m_pPlayer->GetFlags() & FL_DUCKING )
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( SAPPERCLASS_HULL_DUCK_MIN, SAPPERCLASS_HULL_DUCK_MAX );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPlayer->SetCollisionBounds( SAPPERCLASS_HULL_STAND_MIN, SAPPERCLASS_HULL_STAND_MAX );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassSapper::ResetViewOffset( void )
|
||||
{
|
||||
if ( m_pPlayer )
|
||||
{
|
||||
m_pPlayer->SetViewOffset( SAPPERCLASS_VIEWOFFSET_STAND );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassSapper::AddDrainedEnergy( float flEnergy )
|
||||
{
|
||||
// Convert to 0->1
|
||||
flEnergy = ( flEnergy / class_sapper_boost_amount.GetFloat() );
|
||||
m_flDrainedEnergy = MIN( 1.0, m_flDrainedEnergy + flEnergy );
|
||||
|
||||
// Did we hit max?
|
||||
if ( m_flDrainedEnergy >= 1.0 )
|
||||
{
|
||||
m_flDrainedEnergy = 0;
|
||||
|
||||
// Boost the player
|
||||
m_flBoostEndTime = gpGlobals->curtime + class_sapper_boost_time.GetFloat();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
float CPlayerClassSapper::GetDrainedEnergy( void )
|
||||
{
|
||||
return m_flDrainedEnergy;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPlayerClassSapper::DeductDrainedEnergy( float flEnergy )
|
||||
{
|
||||
m_flDrainedEnergy = MAX( 0, m_flDrainedEnergy - flEnergy );
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user