2897 lines
84 KiB
C++
2897 lines
84 KiB
C++
//========= Copyright © 1996-2001, Valve LLC, All rights reserved. ============
|
|
//
|
|
// Purpose: Player for Swarm. This is an invisible entity that doesn't move, representing the commander.
|
|
// The player drives movement of CASW_Marine NPC entities
|
|
//
|
|
// $NoKeywords: $
|
|
//=============================================================================
|
|
|
|
#include "cbase.h"
|
|
#include "asw_player.h"
|
|
#include "in_buttons.h"
|
|
#include "asw_gamerules.h"
|
|
#include "asw_marine_resource.h"
|
|
#include "asw_marine.h"
|
|
#include "asw_marine_speech.h"
|
|
#include "asw_marine_profile.h"
|
|
#include "asw_spawner.h"
|
|
#include "asw_alien.h"
|
|
#include "asw_simple_alien.h"
|
|
#include "asw_pickup.h"
|
|
#include "asw_use_area.h"
|
|
#include "asw_button_area.h"
|
|
#include "asw_weapon.h"
|
|
#include "asw_ammo.h"
|
|
#include "asw_weapon_parse.h"
|
|
#include "asw_computer_area.h"
|
|
#include "asw_hack.h"
|
|
#include "asw_point_camera.h"
|
|
#include "ai_waypoint.h"
|
|
#include "inetchannelinfo.h"
|
|
#include "asw_sentry_base.h"
|
|
#include "asw_shareddefs.h"
|
|
#include "iasw_vehicle.h"
|
|
#include "obstacle_pushaway.h"
|
|
#include "SoundEmitterSystem/isoundemittersystembase.h"
|
|
#include "asw_door.h"
|
|
#include "asw_remote_turret_shared.h"
|
|
#include "asw_weapon_medical_satchel_shared.h"
|
|
#include "Sprite.h"
|
|
#include "physics_prop_ragdoll.h"
|
|
#include "asw_util_shared.h"
|
|
#include "asw_voting_missions.h"
|
|
#include "asw_campaign_save.h"
|
|
#include "gib.h"
|
|
#include "asw_intro_control.h"
|
|
#include "asw_weapon_ammo_bag_shared.h"
|
|
#include "ai_network.h"
|
|
#include "ai_navigator.h"
|
|
#include "ai_node.h"
|
|
#include "datacache/imdlcache.h"
|
|
#include "asw_spawn_manager.h"
|
|
#include "asw_campaign_info.h"
|
|
#include "sendprop_priorities.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
#define ASW_PLAYER_MODEL "models/swarm/marine/Marine.mdl"
|
|
|
|
//#define MARINE_ORDER_DISTANCE 500
|
|
#define MARINE_ORDER_DISTANCE 32000
|
|
|
|
|
|
ConVar asw_blend_test_scale("asw_blend_test_scale", "0.1f", FCVAR_CHEAT);
|
|
ConVar asw_debug_pvs("asw_debug_pvs", "0", FCVAR_CHEAT);
|
|
extern ConVar asw_rts_controls;
|
|
extern ConVar asw_DebugAutoAim;
|
|
extern ConVar asw_debug_marine_damage;
|
|
|
|
// -------------------------------------------------------------------------------- //
|
|
// Player animation event. Sent to the client when a player fires, jumps, reloads, etc..
|
|
// -------------------------------------------------------------------------------- //
|
|
|
|
class CTEPlayerAnimEvent : public CBaseTempEntity
|
|
{
|
|
public:
|
|
DECLARE_CLASS( CTEPlayerAnimEvent, CBaseTempEntity );
|
|
DECLARE_SERVERCLASS();
|
|
|
|
CTEPlayerAnimEvent( const char *name ) : CBaseTempEntity( name )
|
|
{
|
|
}
|
|
|
|
CNetworkHandle( CBasePlayer, m_hPlayer );
|
|
CNetworkVar( int, m_iEvent );
|
|
};
|
|
|
|
IMPLEMENT_SERVERCLASS_ST_NOBASE( CTEPlayerAnimEvent, DT_TEPlayerAnimEvent )
|
|
SendPropEHandle( SENDINFO( m_hPlayer ) ),
|
|
SendPropInt( SENDINFO( m_iEvent ), Q_log2( PLAYERANIMEVENT_COUNT ) + 1, SPROP_UNSIGNED ),
|
|
END_SEND_TABLE()
|
|
|
|
static CTEPlayerAnimEvent g_TEPlayerAnimEvent( "PlayerAnimEvent" );
|
|
|
|
void TE_PlayerAnimEvent( CBasePlayer *pPlayer, PlayerAnimEvent_t event )
|
|
{
|
|
CPVSFilter filter( (const Vector&) pPlayer->EyePosition() );
|
|
|
|
// The player himself doesn't need to be sent his animation events
|
|
// unless cs_showanimstate wants to show them.
|
|
//if ( asw_showanimstate.GetInt() == pPlayer->entindex() )
|
|
//{
|
|
//filter.RemoveRecipient( pPlayer );
|
|
//}
|
|
|
|
g_TEPlayerAnimEvent.m_hPlayer = pPlayer;
|
|
g_TEPlayerAnimEvent.m_iEvent = event;
|
|
g_TEPlayerAnimEvent.Create( filter, 0 );
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------- //
|
|
// Marine animation event.
|
|
// -------------------------------------------------------------------------------- //
|
|
|
|
class CTEMarineAnimEvent : public CBaseTempEntity
|
|
{
|
|
public:
|
|
DECLARE_CLASS( CTEMarineAnimEvent, CBaseTempEntity );
|
|
DECLARE_SERVERCLASS();
|
|
|
|
CTEMarineAnimEvent( const char *name ) : CBaseTempEntity( name )
|
|
{
|
|
}
|
|
|
|
CNetworkHandle( CBasePlayer, m_hExcludePlayer );
|
|
CNetworkHandle( CASW_Marine, m_hMarine );
|
|
CNetworkVar( int, m_iEvent );
|
|
};
|
|
|
|
IMPLEMENT_SERVERCLASS_ST_NOBASE( CTEMarineAnimEvent, DT_TEMarineAnimEvent )
|
|
SendPropEHandle( SENDINFO( m_hMarine ) ),
|
|
SendPropEHandle( SENDINFO( m_hExcludePlayer ) ),
|
|
SendPropInt( SENDINFO( m_iEvent ), Q_log2( PLAYERANIMEVENT_COUNT ) + 1, SPROP_UNSIGNED ),
|
|
END_SEND_TABLE()
|
|
|
|
static CTEMarineAnimEvent g_TEMarineAnimEvent( "MarineAnimEvent" );
|
|
|
|
void TE_MarineAnimEvent( CASW_Marine *pMarine, PlayerAnimEvent_t event )
|
|
{
|
|
CPVSFilter filter( (const Vector&) pMarine->EyePosition() );
|
|
|
|
g_TEMarineAnimEvent.m_hMarine = pMarine;
|
|
g_TEMarineAnimEvent.m_hExcludePlayer = NULL;
|
|
g_TEMarineAnimEvent.m_iEvent = event;
|
|
g_TEMarineAnimEvent.Create( filter, 0 );
|
|
}
|
|
|
|
void TE_MarineAnimEventExceptCommander( CASW_Marine *pMarine, PlayerAnimEvent_t event )
|
|
{
|
|
if (!pMarine)
|
|
return;
|
|
CPVSFilter filter( (const Vector&) pMarine->EyePosition() );
|
|
|
|
if (pMarine->GetCommander() && pMarine->IsInhabited())
|
|
g_TEMarineAnimEvent.m_hExcludePlayer = pMarine->GetCommander();
|
|
else
|
|
g_TEMarineAnimEvent.m_hExcludePlayer = NULL;
|
|
//filter.RemoveRecipient(pMarine->GetCommander());
|
|
g_TEMarineAnimEvent.m_hMarine = pMarine;
|
|
g_TEMarineAnimEvent.m_iEvent = event;
|
|
g_TEMarineAnimEvent.Create( filter, 0 );
|
|
}
|
|
|
|
// NOTE: This animevent won't get recorded in demos properly, since it's not sent to everyone!
|
|
void TE_MarineAnimEventJustCommander( CASW_Marine *pMarine, PlayerAnimEvent_t event )
|
|
{
|
|
if (!pMarine || !pMarine->IsInhabited())
|
|
return;
|
|
|
|
if (!pMarine->GetCommander())
|
|
return;
|
|
|
|
CRecipientFilter filter;
|
|
filter.RemoveAllRecipients();
|
|
filter.AddRecipient(pMarine->GetCommander());
|
|
|
|
g_TEMarineAnimEvent.m_hExcludePlayer = NULL;
|
|
g_TEMarineAnimEvent.m_hMarine = pMarine;
|
|
g_TEMarineAnimEvent.m_iEvent = event;
|
|
g_TEMarineAnimEvent.Create( filter, 0 );
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------- //
|
|
// Tables.
|
|
// -------------------------------------------------------------------------------- //
|
|
|
|
LINK_ENTITY_TO_CLASS( player, CASW_Player );
|
|
PRECACHE_REGISTER(player);
|
|
|
|
IMPLEMENT_SERVERCLASS_ST( CASW_Player, DT_ASW_Player )
|
|
SendPropExclude( "DT_BaseAnimating", "m_flPoseParameter" ),
|
|
SendPropExclude( "DT_BaseAnimating", "m_flPlaybackRate" ),
|
|
SendPropExclude( "DT_BaseAnimating", "m_nSequence" ),
|
|
SendPropExclude( "DT_BaseEntity", "m_angRotation" ),
|
|
SendPropExclude( "DT_BaseAnimatingOverlay", "overlay_vars" ),
|
|
|
|
// cs_playeranimstate and clientside animation takes care of these on the client
|
|
SendPropExclude( "DT_ServerAnimationData" , "m_flCycle" ),
|
|
SendPropExclude( "DT_AnimTimeMustBeFirst" , "m_flAnimTime" ),
|
|
|
|
//SendPropInt (SENDINFO(m_iHealth), 10 ),
|
|
SendPropAngle( SENDINFO_VECTORELEM(m_angEyeAngles, 0), 10, 0, SendProxy_AngleToFloat, SENDPROP_PLAYER_EYE_ANGLES_PRIORITY ),
|
|
SendPropAngle( SENDINFO_VECTORELEM(m_angEyeAngles, 1), 10, 0, SendProxy_AngleToFloat, SENDPROP_PLAYER_EYE_ANGLES_PRIORITY ),
|
|
SendPropAngle( SENDINFO_VECTORELEM(m_angEyeAngles, 2), 10, 0, SendProxy_AngleToFloat, SENDPROP_PLAYER_EYE_ANGLES_PRIORITY ),
|
|
SendPropEHandle( SENDINFO ( m_hMarine ) ),
|
|
SendPropEHandle( SENDINFO( m_hSpectatingMarine ) ),
|
|
SendPropEHandle( SENDINFO( m_hOrderingMarine ) ),
|
|
SendPropEHandle( SENDINFO ( m_pCurrentInfoMessage ) ),
|
|
SendPropEHandle( SENDINFO ( m_hVotingMissions ) ),
|
|
|
|
SendPropInt(SENDINFO(m_iLeaderVoteIndex) ),
|
|
SendPropInt(SENDINFO(m_iKickVoteIndex) ),
|
|
SendPropFloat( SENDINFO( m_fMapGenerationProgress ) ),
|
|
|
|
SendPropTime( SENDINFO( m_flUseKeyDownTime ) ),
|
|
SendPropEHandle( SENDINFO ( m_hUseKeyDownEnt ) ),
|
|
SendPropInt (SENDINFO(m_nChangingSlot)),
|
|
SendPropInt (SENDINFO( m_iMapVoted ) ),
|
|
SendPropInt (SENDINFO( m_iNetworkedXP ) ),
|
|
SendPropInt (SENDINFO( m_iNetworkedPromotion ) ),
|
|
END_SEND_TABLE()
|
|
|
|
BEGIN_DATADESC( CASW_Player )
|
|
DEFINE_FIELD( m_fIsWalking, FIELD_BOOLEAN ),
|
|
DEFINE_FIELD( m_vecLastMarineOrigin, FIELD_VECTOR ),
|
|
DEFINE_FIELD( m_hMarine, FIELD_EHANDLE ),
|
|
DEFINE_FIELD( m_hSpectatingMarine, FIELD_EHANDLE ),
|
|
DEFINE_FIELD( m_vecStoredPosition, FIELD_VECTOR ),
|
|
DEFINE_FIELD( m_pCurrentInfoMessage, FIELD_EHANDLE ),
|
|
DEFINE_FIELD( m_fClearInfoMessageTime, FIELD_FLOAT ),
|
|
//DEFINE_FIELD( m_bLastAttackButton, FIELD_BOOLEAN ), // keep this at no click after restore
|
|
DEFINE_FIELD( m_iUseEntities, FIELD_INTEGER ),
|
|
DEFINE_AUTO_ARRAY( m_hUseEntities, FIELD_EHANDLE ),
|
|
DEFINE_FIELD( m_fBlendAmount, FIELD_FLOAT ),
|
|
DEFINE_FIELD( m_angEyeAngles, FIELD_VECTOR ),
|
|
DEFINE_FIELD( m_iLeaderVoteIndex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( m_iKickVoteIndex, FIELD_INTEGER ),
|
|
DEFINE_FIELD( m_hVotingMissions, FIELD_EHANDLE ),
|
|
DEFINE_FIELD( m_iKLVotesStarted, FIELD_INTEGER ),
|
|
DEFINE_FIELD( m_fLastKLVoteTime, FIELD_TIME ),
|
|
DEFINE_FIELD( m_hOrderingMarine, FIELD_EHANDLE ),
|
|
DEFINE_FIELD( m_vecFreeCamOrigin, FIELD_VECTOR ),
|
|
DEFINE_FIELD( m_bUsedFreeCam, FIELD_BOOLEAN ),
|
|
DEFINE_FIELD( m_bSentJoinedMessage, FIELD_BOOLEAN ),
|
|
DEFINE_FIELD( m_iMapVoted, FIELD_INTEGER ),
|
|
DEFINE_FIELD( m_fLastControlledMarineTime, FIELD_TIME ),
|
|
DEFINE_FIELD( m_vecCrosshairTracePos, FIELD_VECTOR ),
|
|
END_DATADESC()
|
|
|
|
// -------------------------------------------------------------------------------- //
|
|
|
|
void ASW_GetNumAIAwake(const char* szClass, int &iAwake, int &iAsleep, int &iNormal, int &iEfficient, int &iVEfficient, int &iSEfficient, int &iDormant)
|
|
{
|
|
CBaseEntity* pEntity = NULL;
|
|
iAwake = 0;
|
|
iAsleep = 0;
|
|
iNormal = iEfficient = iVEfficient = iSEfficient = iDormant = 0;
|
|
while ((pEntity = gEntList.FindEntityByClassname( pEntity, szClass )) != NULL)
|
|
{
|
|
CAI_BaseNPC* pAI = dynamic_cast<CAI_BaseNPC*>(pEntity);
|
|
if (pAI)
|
|
{
|
|
if (pAI->GetEfficiency() == AIE_NORMAL)
|
|
iNormal++;
|
|
else if (pAI->GetEfficiency() == AIE_EFFICIENT)
|
|
iEfficient++;
|
|
else if (pAI->GetEfficiency() == AIE_VERY_EFFICIENT)
|
|
iVEfficient++;
|
|
else if (pAI->GetEfficiency() == AIE_SUPER_EFFICIENT)
|
|
iSEfficient++;
|
|
else if (pAI->GetEfficiency() == AIE_DORMANT)
|
|
iDormant++;
|
|
|
|
if (pAI->GetSleepState() == AISS_AWAKE)
|
|
iAwake++;
|
|
else
|
|
iAsleep++;
|
|
}
|
|
else
|
|
{
|
|
CASW_Simple_Alien *pSimple = dynamic_cast<CASW_Simple_Alien*>(pEntity);
|
|
if (pSimple)
|
|
{
|
|
if (!pSimple->m_bSleeping)
|
|
iAwake++;
|
|
else
|
|
iAsleep++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ASW_DrawAwakeAI()
|
|
{
|
|
int iAwake = 0;
|
|
int iAsleep = 0;
|
|
int iDormant = 0;
|
|
int iEfficient = 0;
|
|
int iVEfficient = 0;
|
|
int iSEfficient = 0;
|
|
int iNormal = 0;
|
|
int nprintIndex = 0;
|
|
engine->Con_NPrintf( nprintIndex, "AI (awake/asleep) (normal/efficient/very efficient/super efficient/dormant)");
|
|
nprintIndex++;
|
|
engine->Con_NPrintf( nprintIndex, "================================");
|
|
nprintIndex++;
|
|
for ( int i = 0; i < ASWSpawnManager()->GetNumAlienClasses(); i++ )
|
|
{
|
|
ASW_GetNumAIAwake( ASWSpawnManager()->GetAlienClass( i )->m_pszAlienClass, iAwake, iAsleep, iNormal, iEfficient, iVEfficient, iSEfficient, iDormant);
|
|
engine->Con_NPrintf( nprintIndex, "%s: (%d / %d) (%d / %d / %d / %d / %d)\n", ASWSpawnManager()->GetAlienClass( i )->m_pszAlienClass, iAwake, iAsleep, iNormal, iEfficient, iVEfficient, iSEfficient, iDormant );
|
|
nprintIndex++;
|
|
}
|
|
}
|
|
ConVar asw_draw_awake_ai( "asw_draw_awake_ai", "0", FCVAR_CHEAT, "Lists how many of each AI are awake");
|
|
|
|
CASW_Player::CASW_Player()
|
|
{
|
|
m_PlayerAnimState = CreatePlayerAnimState(this, this, LEGANIM_9WAY, false);
|
|
UseClientSideAnimation();
|
|
m_angEyeAngles.Init();
|
|
|
|
SetViewOffset( ASW_PLAYER_VIEW_OFFSET );
|
|
|
|
m_hMarine = NULL;
|
|
m_pCurrentInfoMessage = NULL;
|
|
m_vecLastMarineOrigin = vec3_origin;
|
|
|
|
m_bLastAttackButton= false;
|
|
m_fLastAICountTime = 0;
|
|
m_bAutoReload = true;
|
|
m_bRequestedSpectator = false;
|
|
m_bPrintedWantStartMessage = false;
|
|
m_bPrintedWantsContinueMessage = false;
|
|
m_bFirstInhabit = false;
|
|
m_hUseKeyDownEnt = NULL;
|
|
m_flUseKeyDownTime = 0.0f;
|
|
|
|
m_Local.m_vecPunchAngle.Set( ROLL, 15 );
|
|
m_Local.m_vecPunchAngle.Set( PITCH, 8 );
|
|
m_Local.m_vecPunchAngle.Set( YAW, 0 );
|
|
m_angMarineAutoAim = vec3_angle;
|
|
|
|
m_bPendingSteamStats = false;
|
|
m_flPendingSteamStatsStart = 0.0f;
|
|
m_bHasAwardedXP = false;
|
|
m_bSentPromotedMessage = false;
|
|
|
|
m_nChangingSlot = 0;
|
|
|
|
if (ASWGameRules())
|
|
{
|
|
ASWGameRules()->ClearLeaderKickVotes(this);
|
|
|
|
if (ASWGameRules()->GetGameState() == ASW_GS_INGAME)
|
|
{
|
|
SpectateNextMarine();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
CASW_Player::~CASW_Player()
|
|
{
|
|
m_PlayerAnimState->Release();
|
|
if (ASWGameRules())
|
|
ASWGameRules()->SetMaxMarines(this);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose : Send even though we don't have a model
|
|
//------------------------------------------------------------------------------
|
|
int CASW_Player::UpdateTransmitState()
|
|
{
|
|
// ALWAYS transmit to all clients.
|
|
return SetTransmitState( FL_EDICT_ALWAYS );
|
|
}
|
|
|
|
|
|
CASW_Player *CASW_Player::CreatePlayer( const char *className, edict_t *ed )
|
|
{
|
|
CASW_Player::s_PlayerEdict = ed;
|
|
return (CASW_Player*)CreateEntityByName( className );
|
|
}
|
|
|
|
void CASW_Player::PreThink( void )
|
|
{
|
|
BaseClass::PreThink();
|
|
HandleSpeedChanges();
|
|
}
|
|
|
|
|
|
void CASW_Player::PostThink()
|
|
{
|
|
BaseClass::PostThink();
|
|
|
|
QAngle angles = GetLocalAngles();
|
|
if (GetMarine())
|
|
angles[PITCH] = 0;
|
|
SetLocalAngles( angles );
|
|
|
|
// Store the eye angles pitch so the client can compute its animation state correctly.
|
|
m_angEyeAngles = EyeAngles();
|
|
|
|
m_PlayerAnimState->Update( m_angEyeAngles[YAW], m_angEyeAngles[PITCH] );
|
|
|
|
// find nearby usable items
|
|
FindUseEntities();
|
|
|
|
if (m_pCurrentInfoMessage.Get() && gpGlobals->curtime >= m_fClearInfoMessageTime)
|
|
{
|
|
m_pCurrentInfoMessage = NULL;
|
|
}
|
|
|
|
// clicking while ingame on mission with no marine makes us spectate the next marine
|
|
if ((!GetMarine() || GetMarine()->GetHealth()<=0)
|
|
&& !HasLiveMarines() && ASWGameRules() && ASWGameRules()->GetGameState() == ASW_GS_INGAME)
|
|
{
|
|
//Msg("m_nButtons & IN_ATTACK = %d (m_Local.m_nOldButtons & IN_ATTACK) = %d\n", (m_nButtons & IN_ATTACK), (m_Local.m_nOldButtons & IN_ATTACK));
|
|
bool bClicked = (!m_bLastAttackButton && (m_nButtons & IN_ATTACK));
|
|
|
|
if ( bClicked || ( !GetSpectatingMarine() && gpGlobals->curtime > m_fLastControlledMarineTime + 6.0f ) )
|
|
{
|
|
SpectateNextMarine();
|
|
m_fLastControlledMarineTime = gpGlobals->curtime; // set this again so we don't spam SpectateNextMarine
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_fLastControlledMarineTime = gpGlobals->curtime;
|
|
}
|
|
|
|
m_bLastAttackButton = (m_nButtons & IN_ATTACK);
|
|
|
|
RagdollBlendTest();
|
|
|
|
if (asw_draw_awake_ai.GetBool() && gpGlobals->curtime - m_fLastAICountTime > 2.0f)
|
|
{
|
|
ASW_DrawAwakeAI();
|
|
m_fLastAICountTime = gpGlobals->curtime;
|
|
}
|
|
}
|
|
|
|
CBaseEntity* CASW_Player::GetUseEntity(int i)
|
|
{
|
|
return m_hUseEntities[i];
|
|
}
|
|
|
|
void CASW_Player::Precache()
|
|
{
|
|
PrecacheModel( ASW_PLAYER_MODEL );
|
|
PrecacheModel( "models/swarm/OrderArrow/OrderArrow.mdl" );
|
|
// ASWTODO - precache the actual model set in asw_client_corpse.cpp rather than assuming this one
|
|
PrecacheModel( "models/swarm/colonist/male/malecolonist.mdl" );
|
|
|
|
PrecacheScriptSound( "noslow.BulletTimeIn" );
|
|
PrecacheScriptSound( "noslow.BulletTimeOut" );
|
|
PrecacheScriptSound( "noslow.SingleBreath" );
|
|
PrecacheScriptSound( "Game.ObjectiveComplete" );
|
|
PrecacheScriptSound( "Game.MissionWon" );
|
|
PrecacheScriptSound( "Game.MissionLost" );
|
|
PrecacheScriptSound( "asw_song.stims" );
|
|
//PrecacheScriptSound( "Holdout.GetReadySlide" );
|
|
//PrecacheScriptSound( "Holdout.GetReadySlam" );
|
|
PrecacheScriptSound( "asw_song.statsSuccess" );
|
|
PrecacheScriptSound( "asw_song.statsFail" );
|
|
|
|
if (MarineProfileList())
|
|
{
|
|
MarineProfileList()->PrecacheSpeech(this);
|
|
}
|
|
else
|
|
{
|
|
Msg("Couldn't precache marine speech as profile list isn't created yet\n");
|
|
}
|
|
|
|
BaseClass::Precache();
|
|
}
|
|
|
|
void CASW_Player::Spawn()
|
|
{
|
|
SetModel( ASW_PLAYER_MODEL );
|
|
|
|
BaseClass::Spawn();
|
|
|
|
SetMoveType( MOVETYPE_WALK );
|
|
m_takedamage = DAMAGE_NO;
|
|
m_iKickVoteIndex = -1;
|
|
m_iLeaderVoteIndex = -1;
|
|
BecomeNonSolid();
|
|
|
|
if (ASWGameRules())
|
|
{
|
|
ASWGameRules()->SetMaxMarines();
|
|
|
|
if (ASWGameRules()->IsOutroMap())
|
|
{
|
|
CASW_Intro_Control* pIntro = dynamic_cast<CASW_Intro_Control*>(gEntList.FindEntityByClassname( NULL, "asw_intro_control" ));
|
|
if (pIntro)
|
|
{
|
|
pIntro->PlayerSpawned(this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CASW_Player::DoAnimationEvent( PlayerAnimEvent_t event )
|
|
{
|
|
TE_PlayerAnimEvent( this, event ); // Send to any clients who can see this guy.
|
|
}
|
|
|
|
CBaseCombatWeapon* CASW_Player::ASWAnim_GetActiveWeapon()
|
|
{
|
|
return GetActiveWeapon();
|
|
}
|
|
|
|
void CASW_Player::EmitPrivateSound( const char *soundName, bool bFromMarine )
|
|
{
|
|
CSoundParameters params;
|
|
if (!GetParametersForSound( soundName, params, NULL ))
|
|
return;
|
|
|
|
CSingleUserRecipientFilter filter( this );
|
|
if ( bFromMarine && GetMarine() )
|
|
{
|
|
EmitSound( filter, GetMarine()->entindex(), soundName );
|
|
}
|
|
else
|
|
{
|
|
EmitSound( filter, entindex(), soundName );
|
|
}
|
|
}
|
|
|
|
|
|
bool CASW_Player::ASWAnim_CanMove()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool CASW_Player::ClientCommand( const CCommand &args )
|
|
{
|
|
const char *pcmd = args[0];
|
|
|
|
switch ( ASWGameRules()->GetGameState() )
|
|
{
|
|
case ASW_GS_BRIEFING:
|
|
{
|
|
if ( FStrEq( pcmd, "cl_selectm" ) ) // selecting a marine from the roster
|
|
{
|
|
CASW_Game_Resource *pGameResource = ASWGameResource();
|
|
if (!pGameResource)
|
|
return true;
|
|
|
|
if ( args.ArgC() < 3 )
|
|
{
|
|
Warning( "Player sent bad cl_selectm command\n" );
|
|
}
|
|
|
|
int iRosterIndex = clamp(atoi( args[1] ), 0, ASW_NUM_MARINE_PROFILES-1);
|
|
int nPreferredSlot = atoi( args[2] );
|
|
if (ASWGameRules()->RosterSelect( this, iRosterIndex, nPreferredSlot ) )
|
|
{
|
|
// did they specify a previous inventory selection too?
|
|
if ( args.ArgC() == 6 )
|
|
{
|
|
int iMarineResource = -1;
|
|
for (int i=0;i<pGameResource->GetMaxMarineResources();i++)
|
|
{
|
|
CASW_Marine_Resource *pMR = pGameResource->GetMarineResource(i);
|
|
if (pMR && pMR->GetProfileIndex() == iRosterIndex)
|
|
{
|
|
iMarineResource = i;
|
|
break;
|
|
}
|
|
}
|
|
if (iMarineResource == -1)
|
|
return true;
|
|
|
|
m_bRequestedSpectator = false;
|
|
int primary = atoi( args[3] );
|
|
int secondary = atoi( args[4] );
|
|
int extra = atoi( args[5] );
|
|
|
|
if (primary != -1)
|
|
ASWGameRules()->LoadoutSelect(this, iRosterIndex, 0, primary);
|
|
if (secondary != -1)
|
|
ASWGameRules()->LoadoutSelect(this, iRosterIndex, 1, secondary);
|
|
if (extra != -1)
|
|
ASWGameRules()->LoadoutSelect(this, iRosterIndex, 2, extra);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_dselectm" ) ) // selecting a marine from the roster
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning( "Player sent bad cl_dselectm command\n" );
|
|
return true;
|
|
}
|
|
|
|
if (!ASWGameRules())
|
|
return true;
|
|
|
|
int iRosterIndex = clamp(atoi( args[1] ), 0, ASW_NUM_MARINE_PROFILES-1);
|
|
ASWGameRules()->RosterDeselect(this, iRosterIndex);
|
|
|
|
return true;
|
|
}
|
|
if ( FStrEq( pcmd, "cl_selectsinglem" ) ) // selecting a marine from the roster, deselecting our current
|
|
{
|
|
CASW_Game_Resource *pGameResource = ASWGameResource();
|
|
if (!pGameResource)
|
|
return true;
|
|
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning( "Player sent bad cl_selectsinglem command\n" );
|
|
}
|
|
|
|
// deselect any current marines
|
|
for ( int i = 0; i < ASWGameResource()->GetMaxMarineResources(); i++ )
|
|
{
|
|
CASW_Marine_Resource *pMR = ASWGameResource()->GetMarineResource( i );
|
|
if ( !pMR )
|
|
break;
|
|
|
|
if ( pMR && pMR->GetCommander() == this )
|
|
{
|
|
ASWGameRules()->RosterDeselect( this, pMR->GetProfileIndex() );
|
|
}
|
|
}
|
|
|
|
// now select the new marine
|
|
int iRosterIndex = clamp(atoi( args[1] ), 0, ASW_NUM_MARINE_PROFILES-1);
|
|
if (ASWGameRules()->RosterSelect(this, iRosterIndex))
|
|
{
|
|
|
|
// did they specify a previous inventory selection too?
|
|
if (args.ArgC() == 5)
|
|
{
|
|
int iMarineResource = -1;
|
|
for (int i=0;i<pGameResource->GetMaxMarineResources();i++)
|
|
{
|
|
CASW_Marine_Resource *pMR = pGameResource->GetMarineResource(i);
|
|
if (pMR && pMR->GetProfileIndex() == iRosterIndex)
|
|
{
|
|
iMarineResource = i;
|
|
break;
|
|
}
|
|
}
|
|
if (iMarineResource == -1)
|
|
return true;
|
|
|
|
m_bRequestedSpectator = false;
|
|
int primary = atoi( args[2] );
|
|
int secondary = atoi( args[3] );
|
|
int extra = atoi( args[4] );
|
|
|
|
if (primary != -1)
|
|
ASWGameRules()->LoadoutSelect(this, iRosterIndex, 0, primary);
|
|
if (secondary != -1)
|
|
ASWGameRules()->LoadoutSelect(this, iRosterIndex, 1, secondary);
|
|
if (extra != -1)
|
|
ASWGameRules()->LoadoutSelect(this, iRosterIndex, 2, extra);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_revive" ) ) // revive all dead marines, leader only
|
|
{
|
|
if (ASWGameResource() && ASWGameResource()->m_iLeaderIndex == entindex() && ASWGameRules())
|
|
{
|
|
ASWGameRules()->ReviveDeadMarines();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_wants_start" ) ) // print a message telling the other players that you want to start
|
|
{
|
|
if (ASWGameResource() && ASWGameResource()->m_iLeaderIndex == entindex() && ASWGameRules())
|
|
{
|
|
if (ASWGameRules()->GetGameState() == ASW_GS_BRIEFING)
|
|
{
|
|
if (!m_bPrintedWantStartMessage)
|
|
{
|
|
UTIL_ClientPrintAll( ASW_HUD_PRINTTALKANDCONSOLE, "#asw_wants_start", GetPlayerName() );
|
|
m_bPrintedWantStartMessage = true;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_loadout" ) ) // selecting equipment
|
|
{
|
|
if ( args.ArgC() < 4 )
|
|
{
|
|
Warning( "Player sent bad loadout command\n" );
|
|
}
|
|
|
|
int iProfileIndex = clamp(atoi( args[1] ), 0, ASW_NUM_MARINE_PROFILES-1);
|
|
int iInvSlot = atoi( args[2] );
|
|
int iEquipIndex = atoi( args[3] );
|
|
|
|
ASWGameRules()->LoadoutSelect(this, iProfileIndex, iInvSlot, iEquipIndex);
|
|
|
|
return true;
|
|
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_loadouta" ) ) // selecting equipment
|
|
{
|
|
if ( args.ArgC() < 5 )
|
|
{
|
|
Warning( "Player sent bad loadouta command\n" );
|
|
}
|
|
|
|
int iProfileIndex = clamp(atoi( args[1] ), 0, ASW_NUM_MARINE_PROFILES-1);
|
|
int iPrimary = atoi( args[2] );
|
|
int iSecondary = atoi( args[3] );
|
|
int iExtra = atoi( args[4] );
|
|
|
|
if (iPrimary >=0)
|
|
ASWGameRules()->LoadoutSelect(this, iProfileIndex, 0, iPrimary);
|
|
if (iSecondary >=0)
|
|
ASWGameRules()->LoadoutSelect(this, iProfileIndex, 1, iSecondary);
|
|
if (iExtra >=0)
|
|
ASWGameRules()->LoadoutSelect(this, iProfileIndex, 2, iExtra);
|
|
|
|
return true;
|
|
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_start" ) ) // done selecting, go ingame
|
|
{
|
|
// check if all players are ready, etc
|
|
BecomeNonSolid();
|
|
// send a message to client telling him to close the briefing
|
|
if (ASWGameRules())
|
|
{
|
|
ASWGameRules()->RequestStartMission(this);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_spendskill") )
|
|
{
|
|
if ( args.ArgC() < 3 )
|
|
{
|
|
Warning("Player sent a bad cl_spendskill command\n");
|
|
return false;
|
|
}
|
|
|
|
int iProfileIndex = atoi(args[1]);
|
|
int nSkillSlot = atoi(args[2]);
|
|
|
|
if (iProfileIndex < 0 || iProfileIndex >= ASW_NUM_MARINE_PROFILES )
|
|
return false;
|
|
|
|
if (nSkillSlot < 0 || nSkillSlot >= ASW_SKILL_SLOT_SPARE )
|
|
return false;
|
|
|
|
if (ASWGameRules() && ASWGameRules()->CanSpendPoint(this, iProfileIndex, nSkillSlot))
|
|
ASWGameRules()->SpendSkill(iProfileIndex, nSkillSlot);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_undoskill" ) )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_undoskill command\n");
|
|
return false;
|
|
}
|
|
int iProfileIndex = atoi(args[1]);
|
|
if (iProfileIndex < 0 || iProfileIndex >= ASW_NUM_MARINE_PROFILES )
|
|
return false;
|
|
if (ASWGameRules())
|
|
ASWGameRules()->SkillsUndo(this, iProfileIndex);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_skill_up") )
|
|
{
|
|
if (ASWGameRules())
|
|
ASWGameRules()->RequestSkillUp(this);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_skill_down") )
|
|
{
|
|
if (ASWGameRules())
|
|
ASWGameRules()->RequestSkillDown(this);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_fixedskills") )
|
|
{
|
|
/*
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_fixedskills command\n");
|
|
return false;
|
|
}
|
|
if ( ASWGameRules() && ASWGameRules()->IsCampaignGame() && ASWGameRules()->GetGameState() == ASW_GS_BRIEFING
|
|
&& ASWGameResource()->m_Leader.Get() == this && ASWGameResource() && ASWGameRules()->GetCampaignSave() )
|
|
{
|
|
ASWGameRules()->GetCampaignSave()->m_bFixedSkillPoints = ( atoi( args[1] ) == 1 );
|
|
ASWGameResource()->UpdateMarineSkills( ASWGameRules()->GetCampaignSave() );
|
|
ASWGameRules()->GetCampaignSave()->SaveGameToFile();
|
|
}
|
|
*/
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_carnage") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_carnage command\n");
|
|
return false;
|
|
}
|
|
if (ASWGameRules() && ASWGameResource() && ASWGameResource()->m_Leader.Get() == this)
|
|
ASWGameRules()->SetCarnageMode(atoi(args[1]) == 1);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_uber") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_uber command\n");
|
|
return false;
|
|
}
|
|
if (ASWGameRules() && ASWGameResource() && ASWGameResource()->m_Leader.Get() == this)
|
|
ASWGameRules()->SetUberMode(atoi(args[1]) == 1);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_hardcore") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_hardcore command\n");
|
|
return false;
|
|
}
|
|
if (ASWGameRules() && ASWGameResource() && ASWGameResource()->m_Leader.Get() == this)
|
|
ASWGameRules()->SetHardcoreMode(atoi(args[1]) == 1);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_needtech") )
|
|
{
|
|
if (ASWGameResource()->GetLeader() != this)
|
|
return true;
|
|
if (ASWGameRules() && ASWGameRules()->GetGameState() == ASW_GS_BRIEFING)
|
|
UTIL_ClientPrintAll( ASW_HUD_PRINTTALKANDCONSOLE, "#asw_need_tech" );
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_needequip") )
|
|
{
|
|
if (ASWGameResource()->GetLeader() != this)
|
|
return true;
|
|
if (ASWGameRules() && ASWGameRules()->GetGameState() == ASW_GS_BRIEFING)
|
|
ASWGameRules()->ReportMissingEquipment();
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_needtwoplayers") )
|
|
{
|
|
if (ASWGameRules() && ASWGameRules()->GetGameState() == ASW_GS_BRIEFING)
|
|
ASWGameRules()->ReportNeedTwoPlayers();
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_editing_slot") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_editing_slot command\n");
|
|
return false;
|
|
}
|
|
m_nChangingSlot = atoi( args[1] );
|
|
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_promoted" ) )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_promoted command\n");
|
|
return false;
|
|
}
|
|
if ( !m_bSentPromotedMessage )
|
|
{
|
|
m_bSentPromotedMessage = true;
|
|
int nPromote = atoi( args[1] );
|
|
switch ( nPromote )
|
|
{
|
|
case 1: UTIL_ClientPrintAll( ASW_HUD_PRINTTALKANDCONSOLE, "#asw_player_promoted_1", GetPlayerName() ); break;
|
|
case 2: UTIL_ClientPrintAll( ASW_HUD_PRINTTALKANDCONSOLE, "#asw_player_promoted_2", GetPlayerName() ); break;
|
|
case 3: UTIL_ClientPrintAll( ASW_HUD_PRINTTALKANDCONSOLE, "#asw_player_promoted_3", GetPlayerName() ); break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ASW_GS_INGAME:
|
|
{
|
|
if ( FStrEq( pcmd, "cl_marineface" ) ) // ordering a marine to a certain spot + yaw
|
|
{
|
|
if ( args.ArgC() < 6 )
|
|
{
|
|
Warning( "Player sent bad marine face command\n" );
|
|
}
|
|
|
|
int iMarineEntIndex = atoi( args[1] );
|
|
float fYaw = atof( args[2] );
|
|
float x = atof(args[3]);
|
|
float y = atof(args[4]);
|
|
float z = atof(args[5]);
|
|
//Msg("cl_marineface %f, %f, %f\n", x, y, z);
|
|
Vector vecOrderPos(x, y, z);
|
|
|
|
OrderMarineFace(iMarineEntIndex, fYaw, vecOrderPos);
|
|
|
|
return true;
|
|
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_orderfollow" ) ) // ordering a marine to a follow your current marine
|
|
{
|
|
if ( args.ArgC() < 1 )
|
|
{
|
|
Warning( "Player sent bad cl_orderfollow command\n" );
|
|
}
|
|
|
|
OrderNearbyMarines(this, ASW_ORDER_FOLLOW);
|
|
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_orderhold" ) )
|
|
{
|
|
if ( args.ArgC() < 1 )
|
|
{
|
|
Warning( "Player sent bad cl_orderhold command\n" );
|
|
}
|
|
|
|
OrderNearbyMarines(this, ASW_ORDER_HOLD_POSITION);
|
|
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_mread" ) ) // telling the server you've read an info message
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning( "Player sent bad cl_mread command\n" );
|
|
}
|
|
|
|
int iMessageEntIndex = atoi( args[1] );
|
|
CASW_Info_Message *pMessage = dynamic_cast<CASW_Info_Message*>(CBaseEntity::Instance(iMessageEntIndex));
|
|
if (pMessage)
|
|
{
|
|
pMessage->OnMessageRead(this);
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_emote" ) ) // activating special speech+icon emote
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_emote command\n");
|
|
return false;
|
|
}
|
|
int iEmote = atoi( args[1] );
|
|
CASW_Marine* pMarine = GetMarine();
|
|
if (pMarine && pMarine->GetHealth() > 0)
|
|
{
|
|
pMarine->DoEmote(iEmote);
|
|
}
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_chatter" ) ) // activate a specific chatter
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_chatter command\n");
|
|
return false;
|
|
}
|
|
int iChatter = atoi( args[1] );
|
|
int iSubChatter = -1;
|
|
if (args.ArgC() == 3)
|
|
{
|
|
iSubChatter = atoi( args[2] );
|
|
}
|
|
CASW_Marine* pMarine = GetMarine();
|
|
if (pMarine && pMarine->GetMarineSpeech())
|
|
{
|
|
pMarine->GetMarineSpeech()->ClientRequestChatter(iChatter, iSubChatter);
|
|
}
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_freecam") ) // player is telling server where his freecam is
|
|
{
|
|
if ( args.ArgC() < 4 )
|
|
{
|
|
Warning("Player sent a bad cl_freecam command\n");
|
|
return false;
|
|
}
|
|
|
|
m_bUsedFreeCam = true;
|
|
m_vecFreeCamOrigin.x = atoi( args[1] );
|
|
m_vecFreeCamOrigin.y = atoi( args[2] );
|
|
m_vecFreeCamOrigin.z = atoi( args[3] );
|
|
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_selecthack") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_selecthack command\n");
|
|
return false;
|
|
}
|
|
|
|
int iHackOption = atoi(args[1]);
|
|
if (GetMarine() && GetMarine()->m_hCurrentHack.Get())
|
|
{
|
|
CASW_Hack *pHack = dynamic_cast<CASW_Hack*>(GetMarine()->m_hCurrentHack.Get());
|
|
if (pHack)
|
|
{
|
|
pHack->SelectHackOption(iHackOption);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_stopusing") )
|
|
{
|
|
if (GetMarine() && GetMarine()->m_hUsingEntity.Get())
|
|
GetMarine()->StopUsing();
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_blipspeech") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_blipspeech command\n");
|
|
return false;
|
|
}
|
|
int iTargetMarine = atoi( args[1] );
|
|
if (ASWGameRules())
|
|
ASWGameRules()->BlipSpeech(iTargetMarine);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_viewmail") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_viewmail command\n");
|
|
return false;
|
|
}
|
|
if (GetMarine() && GetMarine()->m_hUsingEntity.Get())
|
|
{
|
|
CASW_Computer_Area *pComputer = dynamic_cast<CASW_Computer_Area*>(GetMarine()->m_hUsingEntity.Get());
|
|
if (pComputer)
|
|
{
|
|
int iMail = clamp(atoi(args[1]), 0, 3);
|
|
pComputer->OnViewMail(GetMarine(), iMail);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_offhand") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_offhand command\n");
|
|
return false;
|
|
}
|
|
int slot = clamp(atoi(args[1]), 0, 2);
|
|
CASW_Marine* pMarine = GetMarine();
|
|
if (pMarine && pMarine->GetHealth()>0 && !(pMarine->GetFlags() & FL_FROZEN))
|
|
{
|
|
|
|
// check we have an item in that slot
|
|
CASW_Weapon* pWeapon = pMarine->GetASWWeapon(slot);
|
|
if (pWeapon && pWeapon->GetWeaponInfo() && pWeapon->GetWeaponInfo()->m_bOffhandActivate)
|
|
{
|
|
pWeapon->OffhandActivate();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_ai_offhand") )
|
|
{
|
|
if ( args.ArgC() < 3 )
|
|
{
|
|
Warning("Player sent a bad cl_ai_offhand command\n");
|
|
return false;
|
|
}
|
|
int slot = clamp( atoi( args[1] ), 0, 2 );
|
|
int marine_index = atoi( args[2] );
|
|
CASW_Marine *pMarine = dynamic_cast<CASW_Marine*>( CBaseEntity::Instance( marine_index ) );
|
|
if ( pMarine && pMarine->GetCommander() == this )
|
|
{
|
|
pMarine->OrderUseOffhandItem( slot, GetCrosshairTracePos() );
|
|
}
|
|
return true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ASW_GS_DEBRIEF:
|
|
{
|
|
if ( FStrEq( pcmd, "cl_wants_continue" ) ) // print a message telling the other players that you want to start
|
|
{
|
|
if (ASWGameResource() && ASWGameResource()->m_iLeaderIndex == entindex() && ASWGameRules())
|
|
{
|
|
if (ASWGameRules()->GetGameState() == ASW_GS_DEBRIEF)
|
|
{
|
|
if (!m_bPrintedWantsContinueMessage)
|
|
{
|
|
UTIL_ClientPrintAll( ASW_HUD_PRINTTALKANDCONSOLE, "#asw_wants_continue", GetPlayerName() );
|
|
m_bPrintedWantsContinueMessage = true;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_wants_returnmap" ) ) // print a message telling the other players that you want to start
|
|
{
|
|
if (ASWGameResource() && ASWGameResource()->m_iLeaderIndex == entindex() && ASWGameRules())
|
|
{
|
|
if (ASWGameRules()->GetGameState() == ASW_GS_DEBRIEF)
|
|
{
|
|
if (!m_bPrintedWantsContinueMessage)
|
|
{
|
|
UTIL_ClientPrintAll( ASW_HUD_PRINTTALKANDCONSOLE, "#asw_wants_returnmap", GetPlayerName() );
|
|
m_bPrintedWantsContinueMessage = true;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( FStrEq( pcmd, "cl_wants_restart" ) ) // print a message telling the other players that you want to start
|
|
{
|
|
if (ASWGameResource() && ASWGameResource()->m_iLeaderIndex == entindex() && ASWGameRules())
|
|
{
|
|
if (ASWGameRules()->GetGameState() == ASW_GS_DEBRIEF)
|
|
{
|
|
if (!m_bPrintedWantsContinueMessage)
|
|
{
|
|
UTIL_ClientPrintAll( ASW_HUD_PRINTTALKANDCONSOLE, "#asw_wants_restart", GetPlayerName() );
|
|
m_bPrintedWantsContinueMessage = true;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_autoreload" ) ) // telling the server you've read an info message
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning( "Player sent bad cl_autoreload command\n" );
|
|
}
|
|
|
|
m_bAutoReload = (atoi(args[1]) == 1);
|
|
return true;
|
|
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_switchm" ) ) // selecting a marine from the roster
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning( "Player sent bad switch marine command\n" );
|
|
}
|
|
|
|
int iMarineIndex = atoi( args[1] ) - 1;
|
|
SwitchMarine(iMarineIndex);
|
|
|
|
return true;
|
|
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_mapline") ) // player is drawing a line on the minimap
|
|
{
|
|
if ( args.ArgC() < 4 )
|
|
{
|
|
Warning("Player sent a bad cl_mapline command\n");
|
|
return false;
|
|
}
|
|
int linetype = clamp(atoi( args[1] ), 0, 1);
|
|
int world_x = atoi( args[2] );
|
|
int world_y = atoi( args[3] );
|
|
|
|
// todo: throttle messages here
|
|
// send user messages to all other clients
|
|
if (ASWGameRules())
|
|
ASWGameRules()->BroadcastMapLine(this, linetype, world_x, world_y);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_campaignnext") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_campaignnext command\n");
|
|
return false;
|
|
}
|
|
// make sure we're leader
|
|
if ( ASWGameResource() && ASWGameResource()->m_iLeaderIndex == entindex() )
|
|
{
|
|
int iTargetMission = atoi( args[1] );
|
|
CASW_Campaign_Info *pCampaign = ASWGameRules()->GetCampaignInfo();
|
|
if ( pCampaign && pCampaign->GetMission( iTargetMission ) )
|
|
{
|
|
ASWGameResource()->m_iNextCampaignMission = iTargetMission;
|
|
}
|
|
// if (ASWGameRules() && ASWGameRules()->GetCampaignSave())
|
|
// {
|
|
// ASWGameRules()->GetCampaignSave()->PlayerVote(this, iTargetMission);
|
|
// }
|
|
}
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_skill") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_skill command\n");
|
|
return false;
|
|
}
|
|
if ( ASWGameRules() )
|
|
{
|
|
ASWGameRules()->RequestSkill( this, atoi(args[1]) );
|
|
}
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_forcelaunch") )
|
|
{
|
|
// make sure we're leader
|
|
if (ASWGameResource() && ASWGameResource()->m_iLeaderIndex == entindex())
|
|
{
|
|
if (ASWGameRules() && ASWGameRules()->GetCampaignSave())
|
|
{
|
|
ASWGameRules()->RequestCampaignMove( ASWGameResource()->m_iNextCampaignMission.Get() );
|
|
//ASWGameRules()->GetCampaignSave()->ForceNextMissionLaunch();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_campaignsas") )
|
|
{
|
|
if (ASWGameRules() && ASWGameRules()->GetGameState() >= ASW_GS_DEBRIEF
|
|
&& ASWGameResource() && ASWGameResource()->GetLeader() == this)
|
|
{
|
|
ASWGameRules()->CampaignSaveAndShowCampaignMap(this, false);
|
|
}
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_forceready") )
|
|
{
|
|
if ( args.ArgC() < 2 || !ASWGameResource() || ASWGameResource()->GetLeader() != this || !ASWGameRules())
|
|
{
|
|
Warning("Player sent a bad cl_forceready command\n");
|
|
return false;
|
|
}
|
|
|
|
int iReadyType = atoi(args[1]);
|
|
if (iReadyType == ASW_FR_BRIEFING && !ASWGameResource()->AtLeastOneMarine()) // don't allow force ready start in briefing if no marines are selected
|
|
return false;
|
|
|
|
ASWGameRules()->SetForceReady(iReadyType);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_restart_mission") )
|
|
{
|
|
// check we're leader and request the restart
|
|
if (ASWGameResource() && ASWGameResource()->GetLeader() == this && ASWGameRules())
|
|
ASWGameRules()->RestartMission(this);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_ready") )
|
|
{
|
|
if ( args.ArgC() < 1 )
|
|
{
|
|
Warning("Player sent a bad cl_ready command\n");
|
|
return false;
|
|
}
|
|
|
|
if (!ASWGameResource() || !ASWGameRules())
|
|
return false;
|
|
|
|
// only allow readiness in briefing and debrief
|
|
if (ASWGameRules()->GetGameState() != ASW_GS_BRIEFING && ASWGameRules()->GetGameState() != ASW_GS_DEBRIEF)
|
|
return false;
|
|
|
|
int iPlayerIndex = entindex() - 1;
|
|
|
|
// player index is out of range
|
|
if (iPlayerIndex < 0 || iPlayerIndex >= ASW_MAX_READY_PLAYERS)
|
|
return false;
|
|
|
|
// mark us as ready or not
|
|
bool bReady = ASWGameResource()->m_bPlayerReady[iPlayerIndex];
|
|
// toggle our ready status
|
|
ASWGameResource()->m_bPlayerReady.Set(iPlayerIndex, !bReady);
|
|
|
|
|
|
ASWGameRules()->SetMaxMarines();
|
|
|
|
// if we have no marines, that means we want to be a spectator
|
|
if (ASWGameRules()->GetGameState() == ASW_GS_BRIEFING && ASWGameResource()->GetNumMarines(this) <= 0)
|
|
m_bRequestedSpectator = true;
|
|
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_spectating") )
|
|
{
|
|
if ( args.ArgC() < 1 )
|
|
{
|
|
Warning("Player sent a bad cl_spectating command\n");
|
|
return false;
|
|
}
|
|
Msg("cl_spectating get game resource=%d\n", ASWGameResource());
|
|
Msg(" gamerules = %d\n", ASWGameRules());
|
|
Msg(" this is leader = %d\n", ASWGameResource() && ASWGameResource()->GetLeader() == this);
|
|
|
|
// remember that this guy wants to spectate (so we can try not to make him leader, ready him up after leaving leader, etc)
|
|
m_bRequestedSpectator = true;
|
|
|
|
if (!ASWGameResource() || !ASWGameRules())
|
|
{
|
|
Msg(" cl_spectating returning false as we don't have game resource or gamerules\n");
|
|
return false;
|
|
}
|
|
|
|
int iPlayerIndex = entindex() - 1;
|
|
Msg(" playerindex = %d\n", iPlayerIndex);
|
|
|
|
// player index is out of range
|
|
if (iPlayerIndex < 0 || iPlayerIndex >= ASW_MAX_READY_PLAYERS)
|
|
{
|
|
Warning("Spectating player index out of range!");
|
|
Msg(" cl_spectating returning false as it's out of range\n");
|
|
return false;
|
|
}
|
|
|
|
Msg(" gamestate = %d (briefing=%d debrief=%d map=%d\n", ASWGameRules()->GetGameState(), ASW_GS_BRIEFING, ASW_GS_DEBRIEF, ASW_GS_CAMPAIGNMAP);
|
|
|
|
if (ASWGameResource()->GetLeader() == this) // leader can't be made ready here (but spectator will be made autoready when he's removed from being leader, later)
|
|
{
|
|
Msg("Spectator is leader, so we're deferring auto ready until he stops. returning true\n");
|
|
if (ASWGameRules()->GetGameState() == ASW_GS_BRIEFING
|
|
|| ASWGameRules()->GetGameState() == ASW_GS_DEBRIEF)
|
|
{
|
|
ASWGameRules()->SetMaxMarines();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// flag us as ready in the briefing/debrief
|
|
if (ASWGameRules()->GetGameState() == ASW_GS_BRIEFING
|
|
|| ASWGameRules()->GetGameState() == ASW_GS_DEBRIEF)
|
|
{
|
|
Msg(" Setting player %d ready\n", iPlayerIndex);
|
|
ASWGameResource()->m_bPlayerReady.Set(iPlayerIndex, true);
|
|
|
|
ASWGameRules()->SetMaxMarines();
|
|
}
|
|
else if (ASWGameRules()->GetGameState() == ASW_GS_CAMPAIGNMAP && ASWGameRules()->GetCampaignSave())
|
|
{
|
|
Msg(" telling campaign save that we're spectating\n", iPlayerIndex);
|
|
ASWGameRules()->GetCampaignSave()->PlayerSpectating(this);
|
|
}
|
|
|
|
Msg(" cl_spectating returning true\n");
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_leadervote") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_leadervote command\n");
|
|
return false;
|
|
}
|
|
int iTargetPlayer = clamp(atoi(args[1]), -1, gpGlobals->maxClients);
|
|
ASWGameRules()->SetLeaderVote(this, iTargetPlayer);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_kickvote") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_kickvote command\n");
|
|
return false;
|
|
}
|
|
int iTargetPlayer = clamp(atoi(args[1]), -1, gpGlobals->maxClients);
|
|
ASWGameRules()->SetKickVote(this, iTargetPlayer);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_vmaplist") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_vmaplist command\n");
|
|
return false;
|
|
}
|
|
int nMissionOffset = atoi(args[1]);
|
|
if (nMissionOffset < 0)
|
|
nMissionOffset = 0;
|
|
VoteMissionList(nMissionOffset, ASW_MISSIONS_PER_PAGE);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_vcampmaplist") )
|
|
{
|
|
if ( args.ArgC() < 3 )
|
|
{
|
|
Warning("Player sent a bad cl_vcampmaplist command\n");
|
|
return false;
|
|
}
|
|
int nCampaignIndex = atoi(args[1]);
|
|
if (nCampaignIndex < 0)
|
|
nCampaignIndex = 0;
|
|
int nMissionOffset = atoi(args[2]);
|
|
if (nMissionOffset < 0)
|
|
nMissionOffset = 0;
|
|
VoteCampaignMissionList(nCampaignIndex, nMissionOffset, ASW_MISSIONS_PER_PAGE);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_vcamplist") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_vcamplist command\n");
|
|
return false;
|
|
}
|
|
int nCampaignOffset = atoi(args[1]);
|
|
if (nCampaignOffset < 0)
|
|
nCampaignOffset = 0;
|
|
VoteCampaignList(nCampaignOffset, ASW_CAMPAIGNS_PER_PAGE);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_vsaveslist") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_vsaveslist command\n");
|
|
return false;
|
|
}
|
|
int nSaveOffset = atoi(args[1]);
|
|
if (nSaveOffset < 0)
|
|
nSaveOffset = 0;
|
|
VoteSavedCampaignList(nSaveOffset, ASW_SAVES_PER_PAGE);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "asw_vote_saved_campaign") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad asw_vote_saved_campaign command\n");
|
|
return false;
|
|
}
|
|
|
|
if (ASWGameRules())
|
|
ASWGameRules()->StartVote(this, ASW_VOTE_SAVED_CAMPAIGN, args[1]);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "asw_vote_campaign") )
|
|
{
|
|
if ( args.ArgC() < 3 )
|
|
{
|
|
Warning("Player sent a bad asw_vote_campaign command\n");
|
|
return false;
|
|
}
|
|
int nCampaignIndex = atoi( args[1] );
|
|
if (ASWGameRules())
|
|
ASWGameRules()->StartVote(this, ASW_VOTE_CHANGE_MISSION, args[2], nCampaignIndex );
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "asw_vote_mission") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad asw_vote_mission command\n");
|
|
return false;
|
|
}
|
|
if (ASWGameRules())
|
|
ASWGameRules()->StartVote(this, ASW_VOTE_CHANGE_MISSION, args[1]);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "vote_yes") )
|
|
{
|
|
if (ASWGameRules())
|
|
ASWGameRules()->CastVote(this, true);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "vote_no") )
|
|
{
|
|
if (ASWGameRules())
|
|
ASWGameRules()->CastVote(this, false);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_ccounts") )
|
|
{
|
|
if ( args.ArgC() < 4 )
|
|
{
|
|
Warning("Player sent a bad cl_ccounts command\n");
|
|
return false;
|
|
}
|
|
m_iClientMissionsCompleted = atoi(args[1]);
|
|
m_iClientCampaignsCompleted = atoi(args[2]);
|
|
m_iClientKills = atoi(args[3]);
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_skip_intro") )
|
|
{
|
|
if (ASWGameRules())
|
|
{
|
|
if (ASWGameRules()->IsIntroMap())
|
|
{
|
|
CASW_Intro_Control* pIntro = dynamic_cast<CASW_Intro_Control*>(gEntList.FindEntityByClassname( NULL, "asw_intro_control" ));
|
|
if (pIntro)
|
|
{
|
|
pIntro->LaunchCampaignMap();
|
|
}
|
|
}
|
|
else if (ASWGameRules()->IsOutroMap())
|
|
{
|
|
CASW_Intro_Control* pIntro = dynamic_cast<CASW_Intro_Control*>(gEntList.FindEntityByClassname( NULL, "asw_intro_control" ));
|
|
if (pIntro)
|
|
{
|
|
pIntro->CheckReconnect();
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_fullyjoined") )
|
|
{
|
|
if (!m_bSentJoinedMessage)
|
|
{
|
|
if (gpGlobals->maxClients > 1)
|
|
{
|
|
//char text[256];
|
|
//Q_snprintf( text,sizeof(text), "%s has joined the game.\n", GetPlayerName() );
|
|
//UTIL_ClientPrintAll( HUD_PRINTTALK, text );
|
|
IGameEvent * event = gameeventmanager->CreateEvent( "player_fullyjoined" );
|
|
if ( event )
|
|
{
|
|
event->SetInt("userid", GetUserID() );
|
|
event->SetString( "name", GetPlayerName() );
|
|
|
|
gameeventmanager->FireEvent( event );
|
|
}
|
|
|
|
// if we're meant to be leader then make it so
|
|
if (ASWGameResource() && !Q_strcmp(GetASWNetworkID(), ASWGameResource()->GetLastLeaderNetworkID()) && ASWGameResource()->GetLeader() != this)
|
|
{
|
|
ASWGameResource()->SetLeader(this);
|
|
UTIL_ClientPrintAll(ASW_HUD_PRINTTALKANDCONSOLE, "#asw_player_made_leader", GetPlayerName());
|
|
Msg("Network ID=%s LastLeaderNetworkID=%s\n", GetASWNetworkID(), ASWGameResource()->GetLastLeaderNetworkID());
|
|
}
|
|
|
|
UTIL_RestartAmbientSounds();
|
|
}
|
|
m_bSentJoinedMessage = true;
|
|
}
|
|
// check for getting back any marines we lost
|
|
bool bReturnedMarines = false;
|
|
CASW_Game_Resource *pGameResource = ASWGameResource();
|
|
if ( pGameResource )
|
|
{
|
|
const char *szNetworkID = GetASWNetworkID();
|
|
for (int i=0;i<pGameResource->GetMaxMarineResources();i++)
|
|
{
|
|
CASW_Marine_Resource* pMR = pGameResource->GetMarineResource( i );
|
|
if ( !pMR )
|
|
continue;
|
|
CASW_Marine *pMarine = pMR->GetMarineEntity();
|
|
|
|
if ( pMarine && !Q_strcmp( pMarine->m_szInitialCommanderNetworkID, szNetworkID ) )
|
|
{
|
|
bool bWasInhabited = pMarine->IsInhabited();
|
|
CASW_Player *pTempCommander = pMarine->GetCommander();
|
|
if ( bWasInhabited && pTempCommander )
|
|
{
|
|
// if another player is currently controlling one of our old marines, have him switch out
|
|
// this will likely be confusing for them! need some message?
|
|
pTempCommander->LeaveMarines();
|
|
}
|
|
Msg("Fully joined, marine %d previous ID = %s my ID = %s\n", i, pMarine->m_szInitialCommanderNetworkID, szNetworkID );
|
|
pMarine->SetCommander( this );
|
|
pMR->SetCommander( this );
|
|
bReturnedMarines = true;
|
|
|
|
// if another player was controlling one of our marines, make sure he switches to one of his own if he can
|
|
if ( bWasInhabited && pTempCommander )
|
|
{
|
|
pTempCommander->SwitchMarine(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( bReturnedMarines )
|
|
{
|
|
Msg(" Fully joined player switching to marine 0\n");
|
|
SwitchMarine(0);
|
|
}
|
|
ASWGameRules()->OnPlayerFullyJoined( this );
|
|
return true;
|
|
}
|
|
else if ( FStrEq( pcmd, "cl_gen_progress") )
|
|
{
|
|
if ( args.ArgC() < 2 )
|
|
{
|
|
Warning("Player sent a bad cl_gen_progress command\n");
|
|
return false;
|
|
}
|
|
m_fMapGenerationProgress = clamp(atof(args[1]), 0.0f, 1.0f);
|
|
return true;
|
|
}
|
|
|
|
return BaseClass::ClientCommand( args );
|
|
}
|
|
|
|
void CASW_Player::BecomeNonSolid()
|
|
{
|
|
m_afPhysicsFlags |= PFLAG_OBSERVER;
|
|
|
|
SetGroundEntity( (CBaseEntity *)NULL );
|
|
|
|
AddSolidFlags( FSOLID_NOT_SOLID );
|
|
RemoveFlag( FL_AIMTARGET ); // don't attract autoaim
|
|
AddFlag( FL_DONTTOUCH ); // stop it touching anything
|
|
AddFlag( FL_NOTARGET ); // stop NPCs noticing it
|
|
|
|
SetMoveType( MOVETYPE_NOCLIP );
|
|
|
|
return;
|
|
}
|
|
|
|
void CASW_Player::OnMarineCommanded( const CASW_Marine *pMarine )
|
|
{
|
|
if ( !ASWGameResource() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
int nNumMarines = 0;
|
|
int nNewMarine = 0;
|
|
|
|
const int max_marines = ASWGameResource()->GetMaxMarineResources();
|
|
for ( int i = 0; i < max_marines; i++ )
|
|
{
|
|
CASW_Marine_Resource* pMR = ASWGameResource()->GetMarineResource( i );
|
|
if ( pMR )
|
|
{
|
|
if ( pMR->m_Commander.Get() == this)
|
|
{
|
|
if ( pMR->GetMarineEntity() == pMarine )
|
|
{
|
|
nNewMarine = nNumMarines;
|
|
}
|
|
|
|
nNumMarines++;
|
|
}
|
|
}
|
|
}
|
|
|
|
IGameEvent * event = gameeventmanager->CreateEvent( "player_commanding" );
|
|
if ( event )
|
|
{
|
|
event->SetInt( "userid", GetUserID() );
|
|
event->SetInt( "new_marine", pMarine->entindex() );
|
|
event->SetInt( "new_index", nNewMarine );
|
|
event->SetInt( "count", nNumMarines );
|
|
gameeventmanager->FireEvent( event );
|
|
}
|
|
}
|
|
|
|
void CASW_Player::SetMarine( CASW_Marine *pMarine )
|
|
{
|
|
if ( pMarine && pMarine != GetMarine() )
|
|
{
|
|
if ( !ASWGameResource() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
int nNumMarines = 0;
|
|
int nOldMarine = 0;
|
|
|
|
const int max_marines = ASWGameResource()->GetMaxMarineResources();
|
|
for ( int i = 0; i < max_marines; ++i )
|
|
{
|
|
CASW_Marine_Resource *pMR = ASWGameResource()->GetMarineResource( i );
|
|
if ( pMR )
|
|
{
|
|
if ( pMR->m_Commander.Get() == this )
|
|
{
|
|
if ( pMR->GetMarineEntity() == GetMarine() )
|
|
{
|
|
nOldMarine = nNumMarines;
|
|
}
|
|
|
|
nNumMarines++;
|
|
}
|
|
}
|
|
}
|
|
|
|
IGameEvent * event = gameeventmanager->CreateEvent( "marine_selected" );
|
|
if ( event )
|
|
{
|
|
event->SetInt( "userid", GetUserID() );
|
|
event->SetInt( "new_marine", pMarine->entindex() );
|
|
event->SetInt( "old_marine", ( GetMarine() ? GetMarine()->entindex() : -1 ) );
|
|
event->SetInt( "old_index", nOldMarine );
|
|
event->SetInt( "count", nNumMarines );
|
|
gameeventmanager->FireEvent( event );
|
|
}
|
|
|
|
m_hMarine = pMarine;
|
|
// make sure our list of usable entities is refreshed
|
|
FindUseEntities();
|
|
}
|
|
}
|
|
|
|
CASW_Marine* CASW_Player::GetMarine()
|
|
{
|
|
return m_hMarine.Get();
|
|
}
|
|
|
|
CASW_Marine* CASW_Player::GetMarine() const
|
|
{
|
|
return m_hMarine.Get();
|
|
}
|
|
|
|
void CASW_Player::SpectateNextMarine()
|
|
{
|
|
CASW_Game_Resource* pGameResource = ASWGameResource();
|
|
if (!pGameResource)
|
|
return;
|
|
CASW_Marine *pFirst = NULL;
|
|
//Msg("CASW_Player::SpectateNextMarine\n");
|
|
|
|
if (GetSpectatingMarine() && GetSpectatingMarine()->GetHealth() <= 0)
|
|
{
|
|
//Msg("clearing initial spectating marine as he's dead\n");
|
|
SetSpectatingMarine(NULL);
|
|
}
|
|
// loop through all marines
|
|
for (int i=0;i<pGameResource->GetMaxMarineResources();i++)
|
|
{
|
|
//Msg("Checking pMR %d\n", i);
|
|
CASW_Marine_Resource* pMR = pGameResource->GetMarineResource(i);
|
|
if (!pMR)
|
|
continue;
|
|
CASW_Marine *pMarine = pMR->GetMarineEntity();
|
|
if (!pMarine || !pMarine->IsAlive() || pMarine->GetHealth() <= 0)
|
|
{
|
|
//Msg(" but he's dead\n");
|
|
continue;
|
|
}
|
|
if (!pFirst)
|
|
{
|
|
pFirst = pMarine;
|
|
//Msg(" set this guy as our first\n");
|
|
}
|
|
if (GetSpectatingMarine() == NULL) // if we're not spectating anything yet, then spectate the first one we find
|
|
{
|
|
//Msg(" We're not spectating anyone, so we're gonna spec this dude\n");
|
|
SetSpectatingMarine(pMarine);
|
|
break;
|
|
}
|
|
if (GetSpectatingMarine() == pMarine) // if we're spectating this one, then clear it, so the next one we find will get set
|
|
{
|
|
//Msg(" we're spectating this dude, so clearing our current spectator\n");
|
|
SetSpectatingMarine(NULL);
|
|
}
|
|
}
|
|
//Msg("end\n");
|
|
// if we're still not spectating anything but we found at least marine, then that means we were spectating the last one in the list and need to set this
|
|
if (GetSpectatingMarine() == NULL && pFirst)
|
|
{
|
|
//Msg(" but we're still not speccing anyone and we have a first set, so speccing that dude\n");
|
|
SetSpectatingMarine(pFirst);
|
|
}
|
|
}
|
|
|
|
void CASW_Player::SetSpectatingMarine(CASW_Marine *pMarine)
|
|
{
|
|
if (pMarine)
|
|
{
|
|
//Msg("Starting spectating marine %s\n", pMarine->GetEntityName());
|
|
m_hSpectatingMarine = pMarine;
|
|
}
|
|
else
|
|
{
|
|
//Msg("Clearing spectating marine\n");
|
|
m_hSpectatingMarine = NULL;
|
|
}
|
|
}
|
|
|
|
CASW_Marine* CASW_Player::GetSpectatingMarine()
|
|
{
|
|
return m_hSpectatingMarine.Get();
|
|
}
|
|
|
|
void CASW_Player::SelectNextMarine(bool bReverse)
|
|
{
|
|
// find index of current marine and our total number of live marines
|
|
CASW_Game_Resource *pGameResource = ASWGameResource();
|
|
if (!pGameResource)
|
|
return;
|
|
|
|
Msg("CASW_Player::SelectNextMarine reverse=%d\n", bReverse);
|
|
|
|
int iMarines = 0;
|
|
int iCurrent = -1;
|
|
for (int i=0;i<pGameResource->GetMaxMarineResources();i++)
|
|
{
|
|
CASW_Marine_Resource *pMR = pGameResource->GetMarineResource(i);
|
|
if (pMR && pMR->GetCommander() == this)
|
|
{
|
|
iMarines++;
|
|
if (pMR->GetMarineEntity() && pMR->GetMarineEntity() == GetMarine())
|
|
iCurrent = iMarines;
|
|
}
|
|
}
|
|
Msg("Marines = %d Current = %d\n", iMarines, iCurrent);
|
|
// if we don't have any of our marines selected (maybe we died), then put us in at the start of the list
|
|
if (iCurrent == -1 && iMarines > 1)
|
|
iCurrent = 1;
|
|
if (iCurrent != -1 && iMarines > 1)
|
|
{
|
|
int iTarget = iCurrent + (bReverse ? -1 : 1);
|
|
if (iTarget <= 0)
|
|
iTarget = iMarines;
|
|
if (iTarget > iMarines)
|
|
iTarget = 1;
|
|
|
|
int k = 6;
|
|
while (!CanSwitchToMarine(iTarget-1) && k >= 0)
|
|
{
|
|
iTarget += (bReverse ? -1 : 1);
|
|
if (iTarget <= 0)
|
|
iTarget = iMarines;
|
|
if (iTarget > iMarines)
|
|
iTarget = 1;
|
|
k--;
|
|
}
|
|
Msg(" wrapped to %d and sent as \n", iTarget, iTarget-1);
|
|
SwitchMarine(iTarget-1);
|
|
// todo: this currently doesn't work properly if we have dead marines! (it'll try to select a dead one and just end up doing nothing)
|
|
//&& pMR->GetHealthPercent() > 0
|
|
}
|
|
}
|
|
|
|
bool CASW_Player::CanSwitchToMarine(int num)
|
|
{
|
|
if (!ASWGameResource())
|
|
return false;
|
|
int max_marines = ASWGameResource()->GetMaxMarineResources();
|
|
for (int i=0;i<max_marines;i++)
|
|
{
|
|
CASW_Marine_Resource* pMR = ASWGameResource()->GetMarineResource(i);
|
|
if (pMR)
|
|
{
|
|
if ((CASW_Player*) pMR->m_Commander == this)
|
|
{
|
|
num--;
|
|
if (num < 0 && pMR->GetMarineEntity() )
|
|
{
|
|
// abort if we're trying to switch to a dead marine
|
|
if (pMR->GetMarineEntity()->GetHealth() <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// select the nth marine in the marine info list owned by this player
|
|
void CASW_Player::SwitchMarine(int num)
|
|
{
|
|
if (!ASWGameResource())
|
|
return;
|
|
int max_marines = ASWGameResource()->GetMaxMarineResources();
|
|
for (int i=0;i<max_marines;i++)
|
|
{
|
|
CASW_Marine_Resource* pMR = ASWGameResource()->GetMarineResource(i);
|
|
if (pMR)
|
|
{
|
|
if ((CASW_Player*) pMR->m_Commander == this)
|
|
{
|
|
num--;
|
|
if (num < 0 && pMR->GetMarineEntity() )
|
|
{
|
|
CASW_Marine *pOldMarine = GetMarine();
|
|
CASW_Marine *pNewMarine = pMR->GetMarineEntity();
|
|
|
|
// abort if we're trying to switch to a dead marine
|
|
if (pNewMarine->GetHealth() <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( pOldMarine )
|
|
{
|
|
if ( pNewMarine == pOldMarine )
|
|
return;
|
|
pOldMarine->UninhabitedBy(this);
|
|
}
|
|
|
|
if (asw_rts_controls.GetBool())
|
|
{
|
|
Msg("RTS controls moving above marine %d\n", num);
|
|
Msg("Marine is at: %f, %f, %f\n", pMR->GetMarineEntity()->GetAbsOrigin().x, pMR->GetMarineEntity()->GetAbsOrigin().y, pMR->GetMarineEntity()->GetAbsOrigin().z);
|
|
Vector vecNewOrigin = pMR->GetMarineEntity()->GetAbsOrigin() + Vector(0, -200, 400);
|
|
SetAbsOrigin( vecNewOrigin );
|
|
Msg("Moved cam to: %f, %f, %f\n", vecNewOrigin.x, vecNewOrigin.y, vecNewOrigin.z);
|
|
return;
|
|
}
|
|
|
|
m_ASWLocal.m_hAutoAimTarget.Set(NULL);
|
|
|
|
SetMarine( pNewMarine );
|
|
SetSpectatingMarine(NULL);
|
|
pNewMarine->SetCommander(this);
|
|
pNewMarine->InhabitedBy(this);
|
|
|
|
if ( gpGlobals->curtime > ASWGameRules()->m_fMissionStartedTime + 5.0f )
|
|
{
|
|
// If it's not the very beginning of the level... go ahead and say it
|
|
pNewMarine->GetMarineSpeech()->Chatter(CHATTER_SELECTION);
|
|
}
|
|
|
|
CASW_SquadFormation *pSquad = pNewMarine->GetSquadFormation();
|
|
if ( pSquad )
|
|
{
|
|
pSquad->ChangeLeader( pNewMarine, false );
|
|
}
|
|
|
|
if ( pOldMarine )
|
|
{
|
|
if ( pOldMarine->GetASWOrders() == ASW_ORDER_HOLD_POSITION )
|
|
{
|
|
pOldMarine->OrdersFromPlayer( this, ASW_ORDER_HOLD_POSITION, pNewMarine, false, GetLocalAngles().y );
|
|
}
|
|
else
|
|
{
|
|
pOldMarine->OrdersFromPlayer( this, ASW_ORDER_FOLLOW, pNewMarine, false );
|
|
}
|
|
}
|
|
|
|
if ( !m_bFirstInhabit )
|
|
{
|
|
//OrderNearbyMarines( this, ASW_ORDER_FOLLOW );
|
|
m_bFirstInhabit = true;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// if we got here, it means we pushed a marine number greater than the number of marines we have
|
|
// check again, this time counting up other player's marines, to see if we're trying to shout out to them (or trying to spectate them, if we're all dead)
|
|
CASW_Marine *pMarine = GetMarine();
|
|
bool bSpectating = (!pMarine || pMarine->GetHealth() <= 0) && !HasLiveMarines();
|
|
for (int i=0;i<max_marines;i++)
|
|
{
|
|
CASW_Marine_Resource* pMR = ASWGameResource()->GetMarineResource(i);
|
|
if (pMR)
|
|
{
|
|
if ((CASW_Player*) pMR->m_Commander != this)
|
|
{
|
|
num--;
|
|
if (num < 0)
|
|
{
|
|
// do a chatter call to this marine
|
|
CASW_Marine_Profile *pProfile = pMR->GetProfile();
|
|
if (pProfile)
|
|
{
|
|
if ( bSpectating && pMR->GetMarineEntity() )
|
|
{
|
|
SetSpectatingMarine( pMR->GetMarineEntity() );
|
|
return;
|
|
}
|
|
else if ( pMarine )
|
|
{
|
|
if (!Q_stricmp(pProfile->m_ShortName, "#asw_name_sarge"))
|
|
pMarine->GetMarineSpeech()->Chatter(CHATTER_SARGE);
|
|
else if (!Q_stricmp(pProfile->m_ShortName, "#asw_name_jaeger"))
|
|
pMarine->GetMarineSpeech()->Chatter(CHATTER_JAEGER);
|
|
else if (!Q_stricmp(pProfile->m_ShortName, "#asw_name_wildcat"))
|
|
pMarine->GetMarineSpeech()->Chatter(CHATTER_WILDCAT);
|
|
else if (!Q_stricmp(pProfile->m_ShortName, "#asw_name_wolfe"))
|
|
pMarine->GetMarineSpeech()->Chatter(CHATTER_WOLFE);
|
|
else if (!Q_stricmp(pProfile->m_ShortName, "#asw_name_faith"))
|
|
pMarine->GetMarineSpeech()->Chatter(CHATTER_FAITH);
|
|
else if (!Q_stricmp(pProfile->m_ShortName, "#asw_name_bastille"))
|
|
pMarine->GetMarineSpeech()->Chatter(CHATTER_BASTILLE);
|
|
else if (!Q_stricmp(pProfile->m_ShortName, "#asw_name_crash"))
|
|
pMarine->GetMarineSpeech()->Chatter(CHATTER_CRASH);
|
|
else if (!Q_stricmp(pProfile->m_ShortName, "#asw_name_flynn"))
|
|
pMarine->GetMarineSpeech()->Chatter(CHATTER_FLYNN);
|
|
else if (!Q_stricmp(pProfile->m_ShortName, "#asw_name_vegas"))
|
|
pMarine->GetMarineSpeech()->Chatter(CHATTER_VEGAS);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void CASW_Player::OrderMarineFace(int iMarine, float fYaw, Vector &vecOrderPos)
|
|
{
|
|
//Msg("Ordering marine %d ", iMarine);
|
|
// check if we were passed an ent index of the marine we're ordering
|
|
CASW_Marine *pTarget = (iMarine == -1) ? NULL : dynamic_cast<CASW_Marine*>(CBaseEntity::Instance(iMarine));
|
|
|
|
CASW_Marine *pMyMarine = GetMarine();
|
|
if (!pMyMarine)
|
|
return;
|
|
|
|
// if we don't have a specific marine to order, find the best one
|
|
if (!pTarget)
|
|
{
|
|
CASW_Game_Resource *pGameResource = ASWGameResource();
|
|
if (!pGameResource)
|
|
return;
|
|
|
|
// if we didn't specify a marine, we'll order the one nearest to the order pos
|
|
|
|
// check if we preselected a specific marine to order
|
|
pTarget = m_hOrderingMarine.Get();
|
|
|
|
// find the nearest marine
|
|
if (!pTarget)
|
|
{
|
|
float nearest_dist = 9999;
|
|
for (int i=0;i<pGameResource->GetMaxMarineResources();i++)
|
|
{
|
|
CASW_Marine_Resource* pMR = pGameResource->GetMarineResource(i);
|
|
if (!pMR)
|
|
continue;
|
|
|
|
CASW_Marine* pMarine = pMR->GetMarineEntity();
|
|
if (!pMarine || pMarine == pMyMarine || pMarine->GetHealth() <= 0 // skip if dead
|
|
|| pMarine->GetCommander() != this)
|
|
continue;
|
|
|
|
float distance = vecOrderPos.DistTo(pMarine->GetAbsOrigin());
|
|
if (pMarine->GetASWOrders() != ASW_ORDER_FOLLOW) // bias against marines that are already holding position somewhere
|
|
distance += 5000;
|
|
if (distance < nearest_dist)
|
|
{
|
|
nearest_dist = distance;
|
|
pTarget = pMarine;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// do an emote
|
|
//pMyMarine->DoEmote(3); // stop
|
|
|
|
if (!pTarget)
|
|
return;
|
|
|
|
pTarget->OrdersFromPlayer(this, ASW_ORDER_MOVE_TO, GetMarine(), true, fYaw, &vecOrderPos);
|
|
}
|
|
|
|
// makes the player uninhabit marines and become free in control of his
|
|
// player entity as normal (this is just for debugging)
|
|
void CASW_Player::LeaveMarines()
|
|
{
|
|
if (GetMarine())
|
|
{
|
|
GetMarine()->UninhabitedBy(this);
|
|
}
|
|
m_hMarine = NULL;
|
|
}
|
|
|
|
void CASW_Player::ChangeName( const char *pszNewName )
|
|
{
|
|
// make sure name is not too long
|
|
char trimmedName[ASW_MAX_PLAYER_NAME_LENGTH];
|
|
Q_strncpy( trimmedName, pszNewName, sizeof( trimmedName ) );
|
|
|
|
const char *pszOldName = GetPlayerName();
|
|
|
|
//char text[256];
|
|
//Q_snprintf( text,sizeof(text), "%s changed name (CASW_Player::ChangeName) to %s\n", pszOldName, trimmedName );
|
|
//UTIL_ClientPrintAll( HUD_PRINTTALK, text );
|
|
|
|
// broadcast event
|
|
IGameEvent * event = gameeventmanager->CreateEvent( "player_changename" );
|
|
if ( event )
|
|
{
|
|
event->SetInt( "userid", GetUserID() );
|
|
event->SetString( "oldname", pszOldName );
|
|
event->SetString( "newname", trimmedName );
|
|
gameeventmanager->FireEvent( event );
|
|
}
|
|
|
|
// change shared player name
|
|
SetPlayerName( trimmedName );
|
|
|
|
// tell engine to use new name
|
|
engine->ClientCommand( edict(), "name \"%s\"", trimmedName );
|
|
}
|
|
|
|
#define ASW_NO_SERVERSIDE_AUTOAIM
|
|
|
|
Vector CASW_Player::GetAutoaimVectorForMarine(CASW_Marine* marine, float flDelta, float flNearMissDelta)
|
|
{
|
|
#ifdef ASW_NO_SERVERSIDE_AUTOAIM
|
|
// test of no serverside autoaim
|
|
Vector forward;
|
|
AngleVectors( EyeAngles(), &forward ); // + m_Local.m_vecPunchAngle
|
|
return forward;
|
|
#else
|
|
//if ( ( ShouldAutoaim() == false ) || ( flDelta == 0 ) )
|
|
if (GetMarine() == NULL)
|
|
{
|
|
Vector forward;
|
|
AngleVectors( EyeAngles(), &forward ); // + m_Local.m_vecPunchAngle
|
|
//Msg("Not autoaiming\n");
|
|
return forward;
|
|
}
|
|
|
|
Vector vecSrc = GetMarine()->Weapon_ShootPosition( );
|
|
float flDist = MAX_COORD_RANGE;
|
|
|
|
QAngle angles = MarineAutoaimDeflection( vecSrc, flDist, flDelta, flNearMissDelta );
|
|
|
|
// update ontarget if changed
|
|
if ( !g_pGameRules->AllowAutoTargetCrosshair() )
|
|
m_fOnTarget = false;
|
|
|
|
if (angles.x > 180)
|
|
angles.x -= 360;
|
|
if (angles.x < -180)
|
|
angles.x += 360;
|
|
if (angles.y > 180)
|
|
angles.y -= 360;
|
|
if (angles.y < -180)
|
|
angles.y += 360;
|
|
|
|
Vector forward;
|
|
AngleVectors( EyeAngles() + angles, &forward ); // + m_Local.m_vecPunchAngle
|
|
|
|
m_angMarineAutoAim = angles;
|
|
|
|
return forward;
|
|
#endif
|
|
}
|
|
|
|
QAngle CASW_Player::MarineAutoaimDeflection( Vector &vecSrc, float flDist, float flDelta, float flNearMissDelta )
|
|
{
|
|
float bestdot;
|
|
Vector bestdir;
|
|
CBaseEntity *bestent;
|
|
trace_t tr;
|
|
Vector v_forward, v_right, v_up;
|
|
|
|
if (ASWGameRules() && ASWGameRules()->IsHardcoreMode())
|
|
return vec3_angle;
|
|
|
|
//if ( ShouldAutoaim() == false )
|
|
//{
|
|
//m_fOnTarget = false;
|
|
//return vec3_angle;
|
|
//}
|
|
|
|
AngleVectors( EyeAngles() + m_angMarineAutoAim, &v_forward, &v_right, &v_up ); // + m_Local.m_vecPunchAngle
|
|
|
|
// try all possible entities
|
|
bestdir = v_forward;
|
|
bestdot = flDelta; // +- 10 degrees
|
|
bestent = NULL;
|
|
|
|
// near misses
|
|
Vector nearmissdir = v_forward;
|
|
float nearmissdot = flNearMissDelta;
|
|
CBaseEntity *nearmissent = NULL;
|
|
|
|
//Reset this data
|
|
m_fOnTarget = false;
|
|
CASW_Weapon* pWeapon = GetMarine() ? GetMarine()->GetActiveASWWeapon() : NULL;
|
|
bool bDoAutoaimEnt = pWeapon && pWeapon->GetAutoAimAmount() >= 0.25f; // only the prifle + autogun show up their autoaim target
|
|
|
|
if (bDoAutoaimEnt || m_ASWLocal.m_hAutoAimTarget.Get())
|
|
m_ASWLocal.m_hAutoAimTarget.Set(NULL);
|
|
//Msg("marine aa def clearing aa ent\n");
|
|
|
|
UTIL_TraceLine( vecSrc, vecSrc + bestdir * flDist, MASK_SHOT, GetMarine(), COLLISION_GROUP_NONE, &tr );
|
|
|
|
CBaseEntity *pEntHit = tr.m_pEnt;
|
|
CBaseEntity* pFlareEnt = NULL;
|
|
|
|
if ( pEntHit && pEntHit->m_takedamage != DAMAGE_NO)
|
|
{
|
|
//m_hAutoAimTarget = pEntHit;
|
|
|
|
// don't look through water
|
|
if (!((GetWaterLevel() != 3 && pEntHit->GetWaterLevel() == 3) || (GetWaterLevel() == 3 && pEntHit->GetWaterLevel() == 0)))
|
|
{
|
|
if ( pEntHit->GetFlags() & FL_AIMTARGET )
|
|
{
|
|
m_fOnTarget = true;
|
|
if (bDoAutoaimEnt)
|
|
m_ASWLocal.m_hAutoAimTarget.Set(pEntHit);
|
|
}
|
|
|
|
//Already on target, don't autoaim
|
|
//Msg("Already on target (%s), not autoaiming\n", pEntHit->GetClassname());
|
|
|
|
return vec3_angle;
|
|
}
|
|
}
|
|
|
|
int count = AimTarget_ListCount();
|
|
//Msg("checking autoaim over %d targets\n", count);
|
|
if ( count )
|
|
{
|
|
CBaseEntity **pList = (CBaseEntity **)stackalloc( sizeof(CBaseEntity *) * count );
|
|
AimTarget_ListCopy( pList, count );
|
|
|
|
for ( int i = 0; i < count; i++ )
|
|
{
|
|
Vector center, center_flat;
|
|
Vector dir, dir_flat;
|
|
float dot, dot_flat;
|
|
CBaseEntity *pEntity = pList[i];
|
|
|
|
//Msg("Checking autoaim vs %d:%s", pEntity->entindex, pEntity->GetClassname());
|
|
|
|
// Don't shoot yourself
|
|
if ( pEntity == this || pEntity == GetMarine())
|
|
{
|
|
//Msg("this is you!, skipping\n");
|
|
continue;
|
|
}
|
|
|
|
if (!pEntity->IsAlive() || !pEntity->edict() )
|
|
{
|
|
//Msg("not alive or not an edict, skipping\n");
|
|
continue;
|
|
}
|
|
|
|
// don't autoaim onto marines
|
|
if (pEntity->Classify() == CLASS_ASW_MARINE)
|
|
continue;
|
|
|
|
//if ( !g_pGameRules->ShouldAutoAim( this, pEntity->edict() ) )
|
|
//continue;
|
|
|
|
// don't look through water
|
|
if ((GetWaterLevel() != 3 && pEntity->GetWaterLevel() == 3) || (GetWaterLevel() == 3 && pEntity->GetWaterLevel() == 0))
|
|
{
|
|
//Msg("not looking through water, skipping\n");
|
|
continue;
|
|
}
|
|
|
|
// Only shoot enemies!
|
|
//if ( IRelationType( pEntity ) != D_HT )
|
|
//{
|
|
//if ( !pEntity->IsPlayer() && !g_pGameRules->IsDeathmatch())
|
|
// Msg( "friend\n");
|
|
//continue;
|
|
//}
|
|
|
|
center = pEntity->BodyTarget( vecSrc );
|
|
center_flat = center;
|
|
center_flat.z = vecSrc.z;
|
|
|
|
dir = (center - vecSrc);
|
|
VectorNormalize( dir );
|
|
|
|
dir_flat = (center_flat - vecSrc);
|
|
VectorNormalize( dir_flat );
|
|
|
|
// make sure it's in front of the player
|
|
if (DotProduct (dir, v_forward ) < 0)
|
|
{
|
|
//Msg("not in front of you, skipping\n");
|
|
continue;
|
|
}
|
|
|
|
dot = fabs( DotProduct (dir, v_right ) )
|
|
+ fabs( DotProduct (dir, v_up ) ) * 0.5;
|
|
|
|
dot_flat = fabs( DotProduct (dir_flat, v_right ) )
|
|
+ fabs( DotProduct (dir_flat, v_up ) ) * 0.5;
|
|
|
|
// tweak for distance
|
|
dot *= 1.0 + 0.2 * ((center - vecSrc).Length() / flDist);
|
|
dot_flat *= 1.0 + 0.2 * ((center - vecSrc).Length() / flDist);
|
|
|
|
// asw: we're only using the flat dot here
|
|
// should really fix this to give priority to aliens that are nearer your z, instead of just nearer on the x and y
|
|
|
|
// asw temp lose the z autoaim
|
|
dot_flat = dot;
|
|
|
|
// check for 'near misses' that change the Z aim only
|
|
if (dot_flat < nearmissdot)
|
|
{
|
|
// todo: check if we have LOS trace?
|
|
nearmissdot = dot_flat;
|
|
nearmissent = pEntity;
|
|
nearmissdir = dir;
|
|
}
|
|
|
|
// check for actual autoaim
|
|
if (dot_flat > bestdot)
|
|
{
|
|
//Msg("too far to turn, skipping\n");
|
|
if (bestent==NULL && dot_flat <= ASW_FLARE_AUTOAIM_DOT
|
|
&& ASWGameRules()->CanFlareAutoaimAt(GetMarine(), pEntity))
|
|
{
|
|
pFlareEnt = pEntity;
|
|
// allow autoaim at this entity because it's inside a flare radius
|
|
if (asw_debug_marine_damage.GetBool())
|
|
Msg("Flare autoaiming!");
|
|
}
|
|
else
|
|
{
|
|
continue; // too far to turn
|
|
}
|
|
}
|
|
|
|
UTIL_TraceLine( vecSrc, center, MASK_SHOT, GetMarine(), COLLISION_GROUP_NONE, &tr );
|
|
|
|
if (tr.fraction != 1.0 && tr.m_pEnt != pEntity )
|
|
{
|
|
//Msg( "hit %s, can't see %s, skipping\n", STRING( tr.u.ent->classname ), STRING( pEdict->classname ) );
|
|
//Msg("Can't see, skipping\n");
|
|
continue;
|
|
}
|
|
|
|
// can shoot at this one
|
|
bestdot = dot_flat;
|
|
bestent = pEntity;
|
|
bestdir = dir;
|
|
//Msg("can see, storing!\n");
|
|
}
|
|
if ( bestent )
|
|
{
|
|
if (asw_DebugAutoAim.GetBool())
|
|
{
|
|
Msg("Autoaiming at a %s dot=%f\n", bestent->GetClassname(), bestdot);
|
|
NDebugOverlay::EntityBounds(bestent, 255,0,0, 255, 1.0f);
|
|
}
|
|
QAngle bestang;
|
|
VectorAngles( bestdir, bestang );
|
|
|
|
bestang -= EyeAngles(); // - m_Local.m_vecPunchAngle
|
|
|
|
if (bDoAutoaimEnt || (pFlareEnt == bestent))
|
|
m_ASWLocal.m_hAutoAimTarget.Set(bestent);
|
|
//Msg("marine aa def setting aa ent to %d\n", bestent->entindex());
|
|
|
|
m_fOnTarget = true;
|
|
|
|
return bestang;
|
|
}
|
|
/*
|
|
else if (nearmissent)
|
|
{
|
|
if (asw_DebugAutoAim.GetBool())
|
|
{
|
|
Msg("Nearmiss aiming at a %s dot=%f\n", nearmissent->GetClassname(), nearmissdot);
|
|
NDebugOverlay::EntityBounds(nearmissent, 0,255,0, 255, 1.0f);
|
|
}
|
|
QAngle bestang;
|
|
Vector verticalonlydir = v_forward;
|
|
verticalonlydir.z = nearmissdir.z;
|
|
VectorAngles( verticalonlydir, bestang );
|
|
|
|
bestang -= EyeAngles(); // - m_Local.m_vecPunchAngle
|
|
|
|
//m_hAutoAimTarget = bestent;
|
|
//m_fOnTarget = true;
|
|
return bestang;
|
|
}
|
|
*/
|
|
}
|
|
|
|
return QAngle( 0, 0, 0 );
|
|
}
|
|
|
|
void CASW_Player::FlashlightTurnOn()
|
|
{
|
|
/*
|
|
if (GetMarine() && !(GetMarine()->GetFlags() & FL_FROZEN)) // don't allow this if the marine is frozen
|
|
GetMarine()->FlashlightToggle();
|
|
else
|
|
BaseClass::FlashlightTurnOn();
|
|
*/
|
|
}
|
|
|
|
void CASW_Player::FlashlightTurnOff()
|
|
{
|
|
/*if (GetMarine())
|
|
GetMarine()->FlashlightTurnOff();
|
|
else
|
|
BaseClass::FlashlightTurnOff();
|
|
*/
|
|
}
|
|
|
|
void OrderNearestHoldingMarineToFollow()
|
|
{
|
|
CASW_Player *pPlayer = ToASW_Player(UTIL_GetCommandClient());;
|
|
CASW_Marine *pMyMarine = pPlayer->GetMarine();
|
|
if (pPlayer && pMyMarine)
|
|
{
|
|
if (pMyMarine->GetFlags() & FL_FROZEN) // don't allow this if the marine is frozen
|
|
return;
|
|
|
|
CASW_Game_Resource *pGameResource = ASWGameResource();
|
|
if (!pGameResource)
|
|
return;
|
|
|
|
// check if we preselected a specific marine to order
|
|
CASW_Marine *pTarget = pPlayer->m_hOrderingMarine.Get();
|
|
|
|
// find the nearest holding marine
|
|
if (!pTarget)
|
|
{
|
|
float nearest_dist = 9999;
|
|
for (int i=0;i<pGameResource->GetMaxMarineResources();i++)
|
|
{
|
|
CASW_Marine_Resource* pMR = pGameResource->GetMarineResource(i);
|
|
if (!pMR)
|
|
continue;
|
|
|
|
CASW_Marine* pMarine = pMR->GetMarineEntity();
|
|
if (!pMarine || pMarine == pMyMarine || pMarine->GetHealth() <= 0 // skip if dead
|
|
|| pMarine->GetASWOrders() == ASW_ORDER_FOLLOW // skip if already following
|
|
|| pMarine->GetCommander() != pPlayer)
|
|
continue;
|
|
|
|
float distance = pMyMarine->GetAbsOrigin().DistTo(pMarine->GetAbsOrigin());
|
|
if (pMarine->GetASWOrders() != ASW_ORDER_HOLD_POSITION) // bias against marines that are already moving somewhere
|
|
distance += 5000;
|
|
if (distance < nearest_dist)
|
|
{
|
|
nearest_dist = distance;
|
|
pTarget = pMarine;
|
|
}
|
|
}
|
|
}
|
|
|
|
// do an emote
|
|
pMyMarine->DoEmote(4); // stop
|
|
|
|
|
|
// abort if we couldn't find another marine to order
|
|
if (!pTarget)
|
|
return;
|
|
|
|
pTarget->OrdersFromPlayer(pPlayer, ASW_ORDER_FOLLOW, pPlayer->GetMarine(), true);
|
|
}
|
|
}
|
|
|
|
void OrderNearbyMarines(CASW_Player *pPlayer, ASW_Orders NewOrders, bool bAcknowledge)
|
|
{
|
|
if ( !pPlayer )
|
|
return;
|
|
|
|
CASW_Marine *pMyMarine = pPlayer->GetMarine();
|
|
if ( pPlayer && pMyMarine )
|
|
{
|
|
if ( pMyMarine->GetFlags() & FL_FROZEN ) // don't allow this if the marine is frozen
|
|
return;
|
|
|
|
// go through all marines and tell them to follow our marine
|
|
CASW_Game_Resource *pGameResource = ASWGameResource();
|
|
if ( !pGameResource )
|
|
return;
|
|
|
|
// do an emote
|
|
if ( NewOrders == ASW_ORDER_HOLD_POSITION && bAcknowledge )
|
|
{
|
|
pMyMarine->DoEmote( 3 ); // go
|
|
}
|
|
|
|
else if ( NewOrders == ASW_ORDER_FOLLOW && bAcknowledge )
|
|
{
|
|
pMyMarine->DoEmote( 4 ); // stop
|
|
}
|
|
|
|
// first count how many marines are in range
|
|
int iNearby = 0;
|
|
for ( int i = 0; i < pGameResource->GetMaxMarineResources(); i++ )
|
|
{
|
|
CASW_Marine_Resource *pMR = pGameResource->GetMarineResource( i );
|
|
if ( !pMR )
|
|
continue;
|
|
|
|
CASW_Marine* pMarine = pMR->GetMarineEntity();
|
|
if ( !pMarine || pMarine == pMyMarine || pMarine->GetCommander() != pPlayer )
|
|
continue;
|
|
|
|
float distance = pMyMarine->GetAbsOrigin().DistTo( pMarine->GetAbsOrigin() );
|
|
if ( distance < MARINE_ORDER_DISTANCE )
|
|
{
|
|
iNearby++;
|
|
}
|
|
}
|
|
|
|
// pick one to chatter
|
|
int iChatter = random->RandomInt( 0, iNearby - 1 ) + 1;
|
|
|
|
// give the orders
|
|
for ( int i = 0; i < pGameResource->GetMaxMarineResources(); i++ )
|
|
{
|
|
CASW_Marine_Resource* pMR = pGameResource->GetMarineResource( i );
|
|
if ( !pMR )
|
|
continue;
|
|
|
|
CASW_Marine* pMarine = pMR->GetMarineEntity();
|
|
if ( !pMarine || pMarine == pMyMarine || pMarine->GetHealth() <= 0 || pMarine->GetCommander() != pPlayer )
|
|
continue;
|
|
|
|
float distance = pMyMarine->GetAbsOrigin().DistTo( pMarine->GetAbsOrigin() );
|
|
if ( distance < MARINE_ORDER_DISTANCE )
|
|
{
|
|
iChatter--;
|
|
pMarine->OrdersFromPlayer( pPlayer, NewOrders, pPlayer->GetMarine(), bAcknowledge && iChatter == 0 );
|
|
}
|
|
}
|
|
|
|
if ( iNearby >= 1 )
|
|
{
|
|
if ( NewOrders == ASW_ORDER_FOLLOW )
|
|
{
|
|
IGameEvent * event = gameeventmanager->CreateEvent( "player_command_follow" );
|
|
if ( event )
|
|
{
|
|
event->SetInt( "userid", pPlayer->GetUserID() );
|
|
gameeventmanager->FireEvent( event );
|
|
}
|
|
}
|
|
else if ( NewOrders == ASW_ORDER_HOLD_POSITION )
|
|
{
|
|
IGameEvent * event = gameeventmanager->CreateEvent( "player_command_hold" );
|
|
if ( event )
|
|
{
|
|
event->SetInt( "userid", pPlayer->GetUserID() );
|
|
gameeventmanager->FireEvent( event );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CASW_Player::ShowInfoMessage(CASW_Info_Message* pMessage)
|
|
{
|
|
if (!pMessage)
|
|
return;
|
|
|
|
m_pCurrentInfoMessage = pMessage;
|
|
m_fClearInfoMessageTime = gpGlobals->curtime + 1.0f;
|
|
}
|
|
|
|
|
|
void CASW_Player::MoveMarineToPredictedPosition()
|
|
{
|
|
CASW_Marine *pMarine = GetMarine();
|
|
if (!pMarine)
|
|
return;
|
|
|
|
m_vecStoredPosition = pMarine->GetAbsOrigin();
|
|
|
|
// sweep a bounding box ahead in the current velocity direction
|
|
Vector vel = pMarine->GetAbsVelocity();
|
|
INetChannelInfo *nci = engine->GetPlayerNetInfo( entindex() );
|
|
if (!nci)
|
|
return;
|
|
float fVelScale = nci->GetLatency( FLOW_OUTGOING );
|
|
Vector dest = m_vecStoredPosition + vel * fVelScale;
|
|
|
|
Ray_t ray;
|
|
trace_t pm;
|
|
ray.Init( m_vecStoredPosition, dest, pMarine->CollisionProp()->OBBMins(), pMarine->CollisionProp()->OBBMaxs() );
|
|
UTIL_TraceRay( ray, MASK_PLAYERSOLID, pMarine, ASW_COLLISION_GROUP_MARINE_POSITION_PREDICTION, &pm );
|
|
|
|
dest = m_vecStoredPosition + vel * fVelScale * pm.fraction;
|
|
pMarine->SetAbsOrigin(dest);
|
|
}
|
|
|
|
void CASW_Player::RestoreMarinePosition()
|
|
{
|
|
CASW_Marine *pMarine = GetMarine();
|
|
if (!pMarine)
|
|
return;
|
|
|
|
pMarine->SetAbsOrigin(m_vecStoredPosition);
|
|
}
|
|
|
|
void CASW_Player::ActivateUseIcon( int iUseEntityIndex, int nHoldType )
|
|
{
|
|
// no using when you're dead
|
|
if (!GetMarine() || GetMarine()->GetHealth()<=0)
|
|
return;
|
|
|
|
if (GetMarine()->GetFlags() & FL_FROZEN) // don't allow this if the marine is frozen
|
|
return;
|
|
|
|
CBaseEntity *pEnt = CBaseEntity::Instance(iUseEntityIndex);
|
|
if (!pEnt)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// check this item is in our usable entities list
|
|
bool bFound = false;
|
|
for (int i=0;i<m_iUseEntities;i++)
|
|
{
|
|
if (pEnt == m_hUseEntities[i].Get())
|
|
{
|
|
bFound = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!bFound)
|
|
return;
|
|
|
|
IASW_Server_Usable_Entity *pUsable = dynamic_cast<IASW_Server_Usable_Entity*>(pEnt);
|
|
if (!pUsable)
|
|
return;
|
|
|
|
pUsable->ActivateUseIcon( GetMarine(), nHoldType );
|
|
}
|
|
|
|
void CASW_Player::SetupVisibility( CBaseEntity *pViewEntity, unsigned char *pvs, int pvssize )
|
|
{
|
|
if (asw_debug_pvs.GetBool())
|
|
{
|
|
Msg("Player:%d SetupVis\n", entindex());
|
|
}
|
|
if (m_bUsedFreeCam)
|
|
{
|
|
if (asw_debug_pvs.GetBool())
|
|
{
|
|
Msg(" freecam %s\n", VecToString(m_vecFreeCamOrigin));
|
|
}
|
|
engine->AddOriginToPVS(m_vecFreeCamOrigin);
|
|
}
|
|
CASW_Marine *pMarine = GetSpectatingMarine();
|
|
bool bSpectating = true;
|
|
if (!pMarine)
|
|
{
|
|
pMarine = GetMarine();
|
|
bSpectating = false;
|
|
}
|
|
if (pMarine)
|
|
{
|
|
// asw - add the marine as our PVS position (since we're using radius based, this will do the job)
|
|
if (pMarine->IsInVehicle())
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
if (pMarine->GetClientsideVehicle() && pMarine->GetClientsideVehicle()->GetEntity())
|
|
engine->AddOriginToPVS(pMarine->GetClientsideVehicle()->GetEntity()->GetAbsOrigin());
|
|
#else
|
|
if (pMarine->GetASWVehicle() && pMarine->GetASWVehicle()->GetEntity())
|
|
engine->AddOriginToPVS(pMarine->GetASWVehicle()->GetEntity()->GetAbsOrigin());
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
//if (asw_debug_pvs.GetBool()) Msg(" Marine %f,%f,%f\n", pMarine->GetAbsOrigin().x, pMarine->GetAbsOrigin().y, pMarine->GetAbsOrigin().z);
|
|
if (asw_debug_pvs.GetBool())
|
|
{
|
|
const Vector pos = pMarine->GetAbsOrigin();
|
|
Msg(" Marine %f,%f,%f\n", pos.x, pos.y, pos.z);
|
|
}
|
|
engine->AddOriginToPVS(pMarine->GetAbsOrigin());
|
|
}
|
|
|
|
// Check for mapper cameras
|
|
CPointCamera *pMapperCamera = GetPointCameraList();
|
|
bool bMapperCam = false;
|
|
for ( int cameraNum = 0; pMapperCamera != NULL; pMapperCamera = pMapperCamera->m_pNext )
|
|
{
|
|
if ( pMapperCamera->IsActive() && !ASW_IsSecurityCam( pMapperCamera ) )
|
|
{
|
|
engine->AddOriginToPVS( pMapperCamera->GetAbsOrigin() );
|
|
bMapperCam = true;
|
|
break;
|
|
}
|
|
|
|
++cameraNum;
|
|
}
|
|
|
|
if (pMarine->m_hUsingEntity.Get())
|
|
{
|
|
CASW_Computer_Area *pComputer = dynamic_cast<CASW_Computer_Area*>(pMarine->m_hUsingEntity.Get());
|
|
if (pComputer)
|
|
{
|
|
if (pComputer->m_iActiveCam == 1 && pComputer->m_hSecurityCam1.Get())
|
|
{
|
|
// if we're here, a computer camera is active
|
|
|
|
// check if any mapper set cameras are active, we shouldn't be on if they are
|
|
CPointCamera *pCam = dynamic_cast<CPointCamera*>( pComputer->m_hSecurityCam1.Get() );
|
|
Assert( pCam );
|
|
|
|
if ( bMapperCam )
|
|
{
|
|
pCam->SetActive(false);
|
|
}
|
|
else
|
|
{
|
|
engine->AddOriginToPVS( pCam->GetAbsOrigin() );
|
|
pCam->SetActive(true);
|
|
CASW_PointCamera *pASWCam = dynamic_cast<CASW_PointCamera*>(pCam);
|
|
if ( pASWCam )
|
|
{
|
|
pASWCam->m_bSecurityCam = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// todo: check which is the cam being used and only activate that one
|
|
// turn off activation when we stop using?
|
|
}
|
|
if (pMarine->IsControllingTurret())
|
|
{
|
|
engine->AddOriginToPVS(pMarine->GetRemoteTurret()->GetAbsOrigin());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//if (asw_debug_pvs.GetBool()) Msg(" Base\n");
|
|
BaseClass::SetupVisibility( pViewEntity, pvs, pvssize );
|
|
}
|
|
}
|
|
|
|
#define ASW_PUSHAWAY_THINK_CONTEXT "CSPushawayThink"
|
|
|
|
void CASW_Player::PushawayThink()
|
|
{
|
|
if (GetMarine() && !GetMarine()->IsInVehicle())
|
|
{
|
|
// Push physics props out of our way.
|
|
PerformObstaclePushaway( GetMarine() );
|
|
}
|
|
SetNextThink( gpGlobals->curtime + PUSHAWAY_THINK_INTERVAL, ASW_PUSHAWAY_THINK_CONTEXT );
|
|
}
|
|
|
|
void CASW_Player::RagdollBlendTest()
|
|
{
|
|
if (!m_pBlendRagdoll)
|
|
return;
|
|
|
|
m_fBlendAmount += gpGlobals->frametime * 0.25f;
|
|
while (m_fBlendAmount > 1.0f)
|
|
m_fBlendAmount -= 1.0f;
|
|
|
|
// sin wave it in and out
|
|
//float fRealBlend = sin(m_fBlendAmount * 6.284);
|
|
float fRealBlend = m_fBlendAmount * 2;
|
|
if (fRealBlend > 1.0f)
|
|
fRealBlend = 2.0f - fRealBlend;
|
|
m_pBlendRagdoll->SetBlendWeight(abs(fRealBlend) * asw_blend_test_scale.GetFloat());
|
|
}
|
|
|
|
void CASW_Player::VoteMissionList(int nMissionOffset, int iNumSlots)
|
|
{
|
|
if (!m_hVotingMissions.Get())
|
|
{
|
|
CASW_Voting_Missions *pVoting = (CASW_Voting_Missions*) CreateEntityByName("asw_voting_missions");
|
|
if (!pVoting)
|
|
return;
|
|
pVoting->Spawn();
|
|
m_hVotingMissions = pVoting;
|
|
}
|
|
m_hVotingMissions->SetListType(this, 1, nMissionOffset, iNumSlots); // 1 = missions
|
|
}
|
|
|
|
void CASW_Player::VoteCampaignMissionList(int nCampaignIndex, int nMissionOffset, int iNumSlots)
|
|
{
|
|
if (!m_hVotingMissions.Get())
|
|
{
|
|
CASW_Voting_Missions *pVoting = (CASW_Voting_Missions*) CreateEntityByName("asw_voting_missions");
|
|
if (!pVoting)
|
|
return;
|
|
pVoting->Spawn();
|
|
m_hVotingMissions = pVoting;
|
|
}
|
|
m_hVotingMissions->SetListType( this, 1, nMissionOffset, iNumSlots, nCampaignIndex ); // 1 = missions
|
|
}
|
|
|
|
void CASW_Player::VoteCampaignList(int nCampaignOffset, int iNumSlots)
|
|
{
|
|
if (!m_hVotingMissions.Get())
|
|
{
|
|
CASW_Voting_Missions *pVoting = (CASW_Voting_Missions*) CreateEntityByName("asw_voting_missions");
|
|
if (!pVoting)
|
|
return;
|
|
pVoting->Spawn();
|
|
m_hVotingMissions = pVoting;
|
|
}
|
|
m_hVotingMissions->SetListType(this, 2, nCampaignOffset, iNumSlots); // 2 = campaigns
|
|
}
|
|
|
|
void CASW_Player::VoteSavedCampaignList(int nSaveOffset, int iNumSlots)
|
|
{
|
|
if (!m_hVotingMissions.Get())
|
|
{
|
|
CASW_Voting_Missions *pVoting = (CASW_Voting_Missions*) CreateEntityByName("asw_voting_missions");
|
|
if (!pVoting)
|
|
return;
|
|
pVoting->Spawn();
|
|
m_hVotingMissions = pVoting;
|
|
}
|
|
m_hVotingMissions->SetListType(this, 3, nSaveOffset, iNumSlots); // 3 = saved campaigns
|
|
}
|
|
|
|
const char* CASW_Player::GetASWNetworkID()
|
|
{
|
|
const char *pszNetworkID = GetNetworkIDString();
|
|
if (!Q_strcmp(pszNetworkID, "UNKNOWN") || !Q_strcmp(pszNetworkID, "HLTV") ||
|
|
!Q_strcmp(pszNetworkID, "STEAM_ID_LAN") || !Q_strcmp(pszNetworkID, "STEAM_ID_PENDING") ||
|
|
!Q_strcmp(pszNetworkID, "STEAM_1:0:0"))
|
|
{
|
|
// player has no valid steam ID, so let's use his IP address instead
|
|
INetChannelInfo *nci = engine->GetPlayerNetInfo( entindex() );
|
|
if (nci)
|
|
{
|
|
pszNetworkID = nci->GetAddress();
|
|
}
|
|
else
|
|
{
|
|
pszNetworkID = GetPlayerName();
|
|
}
|
|
}
|
|
// chop off the steam ID part...
|
|
if (!Q_strncmp("STEAM_ID", pszNetworkID, 8))
|
|
{
|
|
pszNetworkID+=8;
|
|
}
|
|
return pszNetworkID;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Finds the nearest entity in front of the player, preferring
|
|
// collidable entities, but allows selection of enities that are
|
|
// on the other side of walls or objects
|
|
// Input :
|
|
// Output :
|
|
//-----------------------------------------------------------------------------
|
|
CBaseEntity* CASW_Player::FindPickerEntity()
|
|
{
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
|
|
trace_t tr;
|
|
UTIL_TraceLine( GetCrosshairTracePos(),
|
|
GetCrosshairTracePos() + Vector( 0, 0, 10 ),
|
|
MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
|
|
if ( tr.fraction != 1.0 && tr.DidHitNonWorldEntity() )
|
|
{
|
|
return tr.m_pEnt;
|
|
}
|
|
|
|
// If trace fails, look for the nearest entity
|
|
CBaseEntity *pNearestEntity = NULL;
|
|
float fNearestDistance = -1;
|
|
CBaseEntity *pCurrentEntity = gEntList.FirstEnt();
|
|
while ( pCurrentEntity )
|
|
{
|
|
if ( !pCurrentEntity->IsWorld() )
|
|
{
|
|
float fDistance = pCurrentEntity->WorldSpaceCenter().DistTo( GetCrosshairTracePos() );
|
|
if ( fNearestDistance == -1 || fDistance < fNearestDistance )
|
|
{
|
|
pNearestEntity = pCurrentEntity;
|
|
fNearestDistance = fDistance;
|
|
}
|
|
}
|
|
pCurrentEntity = gEntList.NextEnt( pCurrentEntity );
|
|
}
|
|
return pNearestEntity;
|
|
}
|
|
|