add hl1,portal,dod source code

This commit is contained in:
nillerusr
2022-04-16 12:05:19 +03:00
parent bc6873014e
commit 23a370d9bb
524 changed files with 174173 additions and 0 deletions
+141
View File
@@ -0,0 +1,141 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "dod_ammo_box.h"
#include "dod_player.h"
#include "dod_gamerules.h"
BEGIN_DATADESC( CAmmoBox )
DEFINE_THINKFUNC( FlyThink ),
DEFINE_ENTITYFUNC( BoxTouch ),
END_DATADESC();
LINK_ENTITY_TO_CLASS( dod_ammo_box, CAmmoBox );
void CAmmoBox::Spawn( void )
{
Precache( );
SetModel( "models/ammo/ammo_us.mdl" );
BaseClass::Spawn();
SetNextThink( gpGlobals->curtime + 0.75f );
SetThink( &CAmmoBox::FlyThink );
SetTouch( &CAmmoBox::BoxTouch );
m_hOldOwner = GetOwnerEntity();
}
void CAmmoBox::Precache( void )
{
PrecacheModel( "models/ammo/ammo_axis.mdl" );
PrecacheModel( "models/ammo/ammo_us.mdl" );
}
CAmmoBox *CAmmoBox::Create( const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity *pOwner, int team )
{
CAmmoBox *p = static_cast<CAmmoBox *> ( CBaseAnimating::Create( "dod_ammo_box", vecOrigin, vecAngles, pOwner ) );
p->SetAmmoTeam( team );
return p;
}
void CAmmoBox::SetAmmoTeam( int team )
{
switch( team )
{
case TEAM_ALLIES:
{
SetModel( "models/ammo/ammo_us.mdl" );
}
break;
case TEAM_AXIS:
{
SetModel( "models/ammo/ammo_axis.mdl" );
}
break;
default:
Assert(0);
break;
}
m_iAmmoTeam = team;
}
void CAmmoBox::FlyThink( void )
{
SetOwnerEntity( NULL ); //so our owner can pick it back up
}
void CAmmoBox::BoxTouch( CBaseEntity *pOther )
{
Assert( pOther );
if( !pOther->IsPlayer() )
return;
if( !pOther->IsAlive() )
return;
//Don't let the person who threw this ammo pick it up until it hits the ground.
//This way we can throw ammo to people, but not touch it as soon as we throw it ourselves
if( GetOwnerEntity() == pOther )
return;
CDODPlayer *pPlayer = ToDODPlayer( pOther );
Assert( pPlayer );
if( pPlayer->GetTeamNumber() != m_iAmmoTeam )
return;
if( pPlayer == m_hOldOwner )
{
//don't give ammo, just give him his drop again
pPlayer->ReturnGenericAmmo();
UTIL_Remove(this);
}
else
{
//See if they can use some ammo, if so, remove the box
if( pPlayer->GiveGenericAmmo() )
UTIL_Remove(this);
}
}
bool CAmmoBox::MyTouch( CBasePlayer *pBasePlayer )
{
if ( !pBasePlayer )
{
Assert( false );
return false;
}
if( !pBasePlayer->IsAlive() )
return false;
if( pBasePlayer->GetTeamNumber() != m_iAmmoTeam )
return false;
CDODPlayer *pPlayer = ToDODPlayer( pBasePlayer );
if( pPlayer == m_hOldOwner )
{
//don't give ammo, just give him his drop again
pPlayer->ReturnGenericAmmo();
UTIL_Remove(this);
}
else
{
//See if they can use some ammo, if so, remove the box
if( pPlayer->GiveGenericAmmo() )
UTIL_Remove(this);
}
return true;
}
+43
View File
@@ -0,0 +1,43 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef AMMO_BOX_H
#define AMMO_BOX_H
#ifdef _WIN32
#pragma once
#endif
#include "items.h"
class CAmmoBox : public CItem
{
public:
DECLARE_CLASS( CAmmoBox, CItem );
CAmmoBox() {}
virtual void Spawn();
virtual void Precache();
void EXPORT FlyThink( void );
void EXPORT BoxTouch( CBaseEntity *pOther );
bool MyTouch( CBasePlayer *pBasePlayer );
static CAmmoBox *Create( const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity *pOwner, int team );
void SetAmmoTeam( int team );
private:
EHANDLE m_hOldOwner;
int m_iAmmoTeam;
private:
CAmmoBox( const CAmmoBox & );
DECLARE_DATADESC();
};
#endif //GENERIC_AMMO_H
+590
View File
@@ -0,0 +1,590 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "dod_area_capture.h"
#include "dod_player.h"
#include "dod_gamerules.h"
#include "dod_control_point.h"
#include "dod_team.h"
#include "dod_objective_resource.h"
//-------------------------------------------------------------------
// CAreaCapture
// An area entity that players must remain in in order to active another entity
// Triggers are fired on start of capture, on end of capture and on broken capture
// Can either be capped by both teams at once, or just by one
// Time to capture and number of people required to capture are both passed by the mapper
BEGIN_DATADESC(CAreaCapture)
// Touch functions
DEFINE_FUNCTION( AreaTouch ),
// Think functions
DEFINE_THINKFUNC( Think ),
// Keyfields
DEFINE_KEYFIELD( m_iszCapPointName, FIELD_STRING, "area_cap_point" ),
DEFINE_KEYFIELD( m_nAlliesNumCap, FIELD_INTEGER, "area_allies_numcap" ),
DEFINE_KEYFIELD( m_nAxisNumCap, FIELD_INTEGER, "area_axis_numcap" ),
DEFINE_KEYFIELD( m_flCapTime, FIELD_FLOAT, "area_time_to_cap" ),
DEFINE_KEYFIELD( m_bAlliesCanCap, FIELD_BOOLEAN, "area_allies_cancap" ),
DEFINE_KEYFIELD( m_bAxisCanCap, FIELD_BOOLEAN, "area_axis_cancap" ),
DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ),
// Inputs
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "RoundInit", InputRoundInit ),
// Outputs
DEFINE_OUTPUT( m_AlliesStartOutput, "OnAlliesStartCap" ),
DEFINE_OUTPUT( m_AlliesBreakOutput, "OnAlliesBreakCap" ),
DEFINE_OUTPUT( m_AlliesCapOutput, "OnAlliesEndCap" ),
DEFINE_OUTPUT( m_AxisStartOutput, "OnAxisStartCap" ),
DEFINE_OUTPUT( m_AxisBreakOutput, "OnAxisBreakCap" ),
DEFINE_OUTPUT( m_AxisCapOutput, "OnAxisEndCap" ),
DEFINE_OUTPUT( m_StartOutput, "OnStartCap" ),
DEFINE_OUTPUT( m_BreakOutput, "OnBreakCap" ),
DEFINE_OUTPUT( m_CapOutput, "OnEndCap" ),
// DEFINE_OUTPUT( m_OnStartCap, "OnStartCap" );
// DEFINE_OUTPUT( m_OnBreakCap,
// DEFINE_OUTPUT( m_OnEnterNoObj, "OnEnterNoObj" );
END_DATADESC();
LINK_ENTITY_TO_CLASS( dod_capture_area, CAreaCapture );
void CAreaCapture::Spawn( void )
{
BaseClass::Spawn();
InitTrigger();
Precache();
m_iAreaIndex = -1;
SetTouch ( &CAreaCapture::AreaTouch );
m_bCapturing = false;
m_nCapturingTeam = TEAM_UNASSIGNED;
m_nOwningTeam = TEAM_UNASSIGNED;
m_fTimeRemaining = 0.0f;
SetNextThink( gpGlobals->curtime + AREA_THINK_TIME );
if( m_nAlliesNumCap < 1 )
m_nAlliesNumCap = 1;
if( m_nAxisNumCap < 1 )
m_nAxisNumCap = 1;
m_bDisabled = false;
m_iCapAttemptNumber = 0;
}
void CAreaCapture::Precache( void )
{
}
bool CAreaCapture::KeyValue( const char *szKeyName, const char *szValue )
{
return BaseClass::KeyValue( szKeyName, szValue );
}
//sends to all players at the start of the round
//needed?
void CAreaCapture::area_SetIndex( int index )
{
m_iAreaIndex = index;
}
bool CAreaCapture::IsActive( void )
{
return !m_bDisabled;
}
void CAreaCapture::AreaTouch( CBaseEntity *pOther )
{
//if they are touching, set their SIGNAL flag on, and their m_iCapAreaNum to ours
//then in think do all the scoring
if( !IsActive() )
return;
//Don't cap areas unless the round is running
if( DODGameRules()->State_Get() != STATE_RND_RUNNING || DODGameRules()->IsInWarmup() )
return;
Assert( m_iAreaIndex != -1 );
if( m_pPoint )
{
m_nOwningTeam = m_pPoint->GetOwner();
}
//dont touch for non-alive or non-players
if( !pOther->IsPlayer() )
return;
if( !pOther->IsAlive() )
return;
CDODPlayer *pPlayer = ToDODPlayer(pOther);
ASSERT( pPlayer );
if ( pPlayer->GetTeamNumber() != m_nOwningTeam )
{
bool bAbleToCap = ( pPlayer->GetTeamNumber() == TEAM_ALLIES && m_bAlliesCanCap ) ||
( pPlayer->GetTeamNumber() == TEAM_AXIS && m_bAxisCanCap );
if ( bAbleToCap )
pPlayer->HintMessage( HINT_IN_AREA_CAP );
}
pPlayer->m_signals.Signal( SIGNAL_CAPTUREAREA );
//add them to this area
pPlayer->SetCapAreaIndex( m_iAreaIndex );
if ( m_pPoint )
{
pPlayer->SetCPIndex( m_pPoint->GetPointIndex() );
}
}
/* three ways to be capturing a cap area
* 1) have the required number of people in the area
* 2) have less than the required number on your team, new required num is everyone
* 3) have less than the required number alive, new required is numAlive, but time is lengthened
*/
ConVar dod_simulatemultiplecappers( "dod_simulatemultiplecappers", "1", FCVAR_CHEAT );
void CAreaCapture::Think( void )
{
SetNextThink( gpGlobals->curtime + AREA_THINK_TIME );
if( DODGameRules()->State_Get() != STATE_RND_RUNNING )
{
// If we were being capped, cancel it
if( m_nNumAllies > 0 || m_nNumAxis > 0 )
{
m_nNumAllies = 0;
m_nNumAxis = 0;
SendNumPlayers();
if( m_pPoint )
{
g_pObjectiveResource->SetCappingTeam( m_pPoint->GetPointIndex(), TEAM_UNASSIGNED );
}
}
return;
}
// go through our list of players
int iNumAllies = 0;
int iNumAxis = 0;
CDODPlayer *pFirstAlliedTouching = NULL;
CDODPlayer *pFirstAxisTouching = NULL;
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBaseEntity *ent = UTIL_PlayerByIndex( i );
if ( ent )
{
CDODPlayer *pPlayer = ToDODPlayer(ent);
//First check if the player is in fact in this area
if ( ( pPlayer->m_signals.GetState() & SIGNAL_CAPTUREAREA ) &&
pPlayer->GetCapAreaIndex() == m_iAreaIndex &&
pPlayer->IsAlive() ) // alive check is kinda unnecessary, but there is some
// case where non-present people are messing up this count
{
if ( pPlayer->GetTeamNumber() == TEAM_ALLIES )
{
if ( iNumAllies == 0 )
pFirstAlliedTouching = pPlayer;
iNumAllies++;
}
else if ( pPlayer->GetTeamNumber() == TEAM_AXIS )
{
if ( iNumAxis == 0 )
pFirstAxisTouching = pPlayer;
iNumAxis++;
}
}
}
}
iNumAllies *= dod_simulatemultiplecappers.GetInt();
iNumAxis *= dod_simulatemultiplecappers.GetInt();
if( iNumAllies != m_nNumAllies || iNumAxis != m_nNumAxis )
{
m_nNumAllies = iNumAllies;
m_nNumAxis = iNumAxis;
SendNumPlayers();
}
// when a player blocks, tell them the cap index and attempt number
// only give successive blocks to them if the attempt number is different
if( m_bCapturing )
{
//its a regular cap
//Subtract some time from the cap
m_fTimeRemaining -= AREA_THINK_TIME;
//if both teams are in the area
if( iNumAllies > 0 && iNumAxis > 0 )
{
// See if anyone gets credit for the block
float flPercentToGo = m_fTimeRemaining / m_flCapTime;
if ( flPercentToGo <= 0.5 && m_pPoint )
{
// find the first player that is not on the capturing team
// they have just broken a cap and should be rewarded
// tell the player the capture attempt number, for checking later
CDODPlayer *pBlockingPlayer = ( m_nCapturingTeam == TEAM_ALLIES ) ? pFirstAxisTouching : pFirstAlliedTouching;
if ( pBlockingPlayer )
{
if ( pBlockingPlayer->GetCapAreaIndex() == m_iAreaIndex &&
pBlockingPlayer->GetLastBlockCapAttempt() == m_iCapAttemptNumber )
{
// this is a repeat block on the same cap, ignore it
NULL;
}
else
{
m_pPoint->CaptureBlocked( pBlockingPlayer );
pBlockingPlayer->StoreCaptureBlock( m_iAreaIndex, m_iCapAttemptNumber );
}
}
}
BreakCapture( false );
return;
}
//if no-one is in the area
if( iNumAllies == 0 && iNumAxis == 0 )
{
BreakCapture( true );
return;
}
if( m_nCapturingTeam == TEAM_ALLIES )
{
if( iNumAllies < m_nAlliesNumCap )
{
BreakCapture( true );
}
}
else if( m_nCapturingTeam == TEAM_AXIS )
{
if( iNumAxis < m_nAxisNumCap )
{
BreakCapture( true );
}
}
//if the cap is done
if( m_fTimeRemaining <= 0 )
{
EndCapture( m_nCapturingTeam );
return; //we're done
}
}
else //not capturing yet
{
bool bStarted = false;
if( iNumAllies > 0 && iNumAxis <= 0 && m_bAlliesCanCap && m_nOwningTeam != TEAM_ALLIES )
{
if( iNumAllies >= m_nAlliesNumCap )
{
m_iCappingRequired = m_nAlliesNumCap;
m_iCappingPlayers = iNumAllies;
StartCapture( TEAM_ALLIES, CAPTURE_NORMAL );
bStarted = true;
}
}
else if( iNumAxis > 0 && iNumAllies <= 0 && m_bAxisCanCap && m_nOwningTeam != TEAM_AXIS )
{
if( iNumAxis >= m_nAxisNumCap )
{
m_iCappingRequired = m_nAxisNumCap;
m_iCappingPlayers = iNumAxis;
StartCapture( TEAM_AXIS, CAPTURE_NORMAL );
bStarted = true;
}
}
}
}
void CAreaCapture::SetOwner( int team )
{
//break any current capturing
BreakCapture( false );
//set the owner to the passed value
m_nOwningTeam = team;
g_pObjectiveResource->SetOwningTeam( m_pPoint->GetPointIndex(), m_nOwningTeam );
}
void CAreaCapture::SendNumPlayers( CBasePlayer *pPlayer )
{
if( !m_pPoint )
return;
int index = m_pPoint->GetPointIndex();
g_pObjectiveResource->SetNumPlayers( index, TEAM_ALLIES, m_nNumAllies );
g_pObjectiveResource->SetNumPlayers( index, TEAM_AXIS, m_nNumAxis );
}
void CAreaCapture::StartCapture( int team, int capmode )
{
int iNumCappers = 0;
//trigger start
if( team == TEAM_ALLIES )
{
m_AlliesStartOutput.FireOutput(this,this);
iNumCappers = m_nAlliesNumCap;
}
else if( team == TEAM_AXIS )
{
m_AxisStartOutput.FireOutput(this,this);
iNumCappers = m_nAxisNumCap;
}
m_StartOutput.FireOutput(this,this);
m_nCapturingTeam = team;
m_fTimeRemaining = m_flCapTime;
m_bCapturing = true;
m_iCapMode = capmode;
if( m_pPoint )
{
//send a message that we're starting to cap this area
g_pObjectiveResource->SetCappingTeam( m_pPoint->GetPointIndex(), m_nCapturingTeam );
}
}
#define MAX_AREA_CAPPERS 9
void CAreaCapture::EndCapture( int team )
{
m_iCapAttemptNumber++;
//do the triggering
if( team == TEAM_ALLIES )
{
m_AlliesCapOutput.FireOutput(this,this);
}
else if( team == TEAM_AXIS )
{
m_AxisCapOutput.FireOutput(this,this);
}
m_CapOutput.FireOutput(this,this);
m_iCappingRequired = 0;
m_iCappingPlayers = 0;
int numcappers = 0;
int cappingplayers[MAX_AREA_CAPPERS];
CDODPlayer *pCappingPlayer = NULL;
CDODTeam *pTeam = GetGlobalDODTeam(team);
if ( pTeam )
{
int iCount = pTeam->GetNumPlayers();
for ( int i=0;i<iCount;i++ )
{
CDODPlayer *pPlayer = ToDODPlayer( pTeam->GetPlayer(i) );
if ( pPlayer )
{
if( ( pPlayer->m_signals.GetState() & SIGNAL_CAPTUREAREA ) &&
pPlayer->GetCapAreaIndex() == m_iAreaIndex &&
pPlayer->IsAlive() )
{
if( pCappingPlayer == NULL )
pCappingPlayer = pPlayer;
if ( numcappers < MAX_AREA_CAPPERS-1 )
{
cappingplayers[numcappers] = pPlayer->entindex();
numcappers++;
}
}
}
}
}
if ( numcappers < MAX_AREA_CAPPERS )
{
cappingplayers[numcappers] = 0; //null terminate :)
}
m_nOwningTeam = team;
m_bCapturing = false;
m_fTimeRemaining = 0.0f;
//there may have been more than one capper, but only report this one.
//he hasnt gotten points yet, and his name will go in the cap string if its needed
//first capper gets name sent and points given by flag.
//other cappers get points manually above, no name in message
//send the player in the cap string
if( m_pPoint )
{
DODGameRules()->CapEvent( CAP_EVENT_FLAG, m_nOwningTeam );
g_pObjectiveResource->SetOwningTeam( m_pPoint->GetPointIndex(), m_nOwningTeam );
m_pPoint->SetOwner( m_nOwningTeam, true, numcappers, cappingplayers );
}
}
void CAreaCapture::BreakCapture( bool bNotEnoughPlayers )
{
if( m_bCapturing )
{
m_iCappingRequired = 0;
m_iCappingPlayers = 0;
if( m_nCapturingTeam == TEAM_ALLIES )
m_AlliesBreakOutput.FireOutput(this,this);
else if( m_nCapturingTeam == TEAM_AXIS )
m_AxisBreakOutput.FireOutput(this,this);
m_BreakOutput.FireOutput(this,this);
m_bCapturing = false;
if( m_pPoint )
{
g_pObjectiveResource->SetCappingTeam( m_pPoint->GetPointIndex(), TEAM_UNASSIGNED );
}
if ( bNotEnoughPlayers )
{
m_iCapAttemptNumber++;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CAreaCapture::InputDisable( inputdata_t &inputdata )
{
m_bDisabled = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CAreaCapture::InputEnable( inputdata_t &inputdata )
{
m_bDisabled = false;
}
void CAreaCapture::InputRoundInit( inputdata_t &inputdata )
{
// find the flag we're linked to
if( !m_pPoint )
{
m_pPoint = dynamic_cast<CControlPoint*>( gEntList.FindEntityByName(NULL, STRING(m_iszCapPointName) ) );
if ( m_pPoint )
{
m_pPoint->SetNumCappersRequired( m_nAlliesNumCap, m_nAxisNumCap );
g_pObjectiveResource->SetCPRequiredCappers( m_pPoint->GetPointIndex(), m_nAlliesNumCap, m_nAxisNumCap );
g_pObjectiveResource->SetCPCapTime( m_pPoint->GetPointIndex(), m_flCapTime, m_flCapTime );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Check if this player's death causes a block
// return FALSE if the player is not in this area
// return TRUE otherwise ( eg player is in area, but his death does not cause break )
//-----------------------------------------------------------------------------
bool CAreaCapture::CheckIfDeathCausesBlock( CDODPlayer *pVictim, CDODPlayer *pKiller )
{
// This shouldn't happen
if ( !pVictim || !pKiller )
{
Assert( !"Why are null players getting here?" );
return false;
}
// make sure this player is in this area
if ( pVictim->GetCapAreaIndex() != m_iAreaIndex )
return false;
// Teamkills shouldn't give a block reward
if ( pVictim->GetTeamNumber() == pKiller->GetTeamNumber() )
return true;
// return if the area is not being capped
if ( !m_bCapturing )
return true;
int iTeam = pVictim->GetTeamNumber();
// return if this player's team is not capping the area
if ( iTeam != m_nCapturingTeam )
return true;
bool bBlocked = false;
if ( m_nCapturingTeam == TEAM_ALLIES )
{
if ( m_nNumAllies-1 < m_nAlliesNumCap )
bBlocked = true;
}
else if ( m_nCapturingTeam == TEAM_AXIS )
{
if ( m_nNumAxis-1 < m_nAxisNumCap )
bBlocked = true;
}
// break early incase we kill multiple people in the same frame
if ( bBlocked )
{
m_pPoint->CaptureBlocked( pKiller );
BreakCapture( false );
}
return true;
}
+104
View File
@@ -0,0 +1,104 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DOD_AREA_CAPTURE_H
#define DOD_AREA_CAPTURE_H
#ifdef _WIN32
#pragma once
#endif
#include "triggers.h"
#include "dod_control_point.h"
#define AREA_ATTEND_TIME 0.7f
#define AREA_THINK_TIME 0.1f
#define CAPTURE_NORMAL 0
#define CAPTURE_CATCHUP_ALIVEPLAYERS 1
#define MAX_CLIENT_AREAS 128
class CAreaCapture : public CBaseTrigger
{
public:
DECLARE_CLASS( CAreaCapture, CBaseTrigger );
virtual void Spawn( void );
virtual void Precache( void );
virtual bool KeyValue( const char *szKeyName, const char *szValue );
void area_SetIndex( int index );
bool IsActive( void );
bool CheckIfDeathCausesBlock( CDODPlayer *pVictim, CDODPlayer *pKiller );
private:
void EXPORT AreaTouch( CBaseEntity *pOther );
void Think( void );
void StartCapture( int team, int capmode );
void EndCapture( int team );
void BreakCapture( bool bNotEnoughPlayers );
void SwitchCapture( int team );
void SendNumPlayers( CBasePlayer *pPlayer = NULL );
void SetOwner( int team ); //sets the owner of this point - useful for resetting all to -1
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
void InputRoundInit( inputdata_t &inputdata );
private:
int m_iCapMode; //which capture mode we're in
int m_bCapturing;
int m_nCapturingTeam; //the team that is capturing this point
int m_nOwningTeam; //the team that has captured this point
float m_flCapTime; //the total time it takes to capture the area, in seconds
float m_fTimeRemaining; //the time left in the capture
int m_nAlliesNumCap; //number of allies required to cap
int m_nAxisNumCap; //number of axis required to cap
int m_nNumAllies;
int m_nNumAxis;
bool m_bAlliesCanCap;
bool m_bAxisCanCap;
//used for catchup capping
int m_iCappingRequired; //how many players are currently capping
int m_iCappingPlayers; //how many are required?
bool m_bActive;
COutputEvent m_AlliesStartOutput;
COutputEvent m_AlliesBreakOutput;
COutputEvent m_AlliesCapOutput;
COutputEvent m_AxisStartOutput;
COutputEvent m_AxisBreakOutput;
COutputEvent m_AxisCapOutput;
COutputEvent m_StartOutput;
COutputEvent m_BreakOutput;
COutputEvent m_CapOutput;
int m_iAreaIndex; //index of this area among all other areas
CControlPoint *m_pPoint; //the capture point that we are linked to!
bool m_bRequiresObject;
string_t m_iszCapPointName; //name of the cap point that we're linked to
int m_iCapAttemptNumber; // number used to keep track of discrete cap attempts, for block tracking
DECLARE_DATADESC();
};
#endif //DOD_AREA_CAPTURE_H
+526
View File
@@ -0,0 +1,526 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "dod_basegrenade.h"
#include "dod_player.h"
#include "dod_gamerules.h"
#include "func_break.h"
#include "physics_saverestore.h"
#include "grenadetrail.h"
#include "fx_dod_shared.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
float GetCurrentGravity( void );
ConVar dod_grenadegravity( "dod_grenadegravity", "-420", FCVAR_CHEAT, "gravity applied to grenades", true, -2000, true, -300 );
extern ConVar dod_bonusround;
IMotionEvent::simresult_e CGrenadeController::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular )
{
linear.x = linear.y = 0;
linear.z = dod_grenadegravity.GetFloat();
angular.x = angular.y = angular.z = 0;
return SIM_GLOBAL_ACCELERATION;
}
BEGIN_SIMPLE_DATADESC( CGrenadeController )
END_DATADESC()
BEGIN_DATADESC( CDODBaseGrenade )
DEFINE_THINKFUNC( DetonateThink ),
DEFINE_EMBEDDED( m_GrenadeController ),
DEFINE_PHYSPTR( m_pMotionController ), // probably not necessary
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST( CDODBaseGrenade, DT_DODBaseGrenade )
SendPropVector( SENDINFO( m_vInitialVelocity ),
20, // nbits
0, // flags
-3000, // low value
3000 // high value
)
END_SEND_TABLE()
CDODBaseGrenade::CDODBaseGrenade()
{
}
CDODBaseGrenade::~CDODBaseGrenade( void )
{
if ( m_pMotionController != NULL )
{
physenv->DestroyMotionController( m_pMotionController );
m_pMotionController = NULL;
}
}
void CDODBaseGrenade::Spawn( void )
{
m_bUseVPhysics = true;
BaseClass::Spawn();
SetSolid( SOLID_BBOX ); // So it will collide with physics props!
UTIL_SetSize( this, Vector(-4,-4,-4), Vector(4,4,4) );
if( m_bUseVPhysics )
{
SetCollisionGroup( COLLISION_GROUP_WEAPON );
IPhysicsObject *pPhysicsObject = VPhysicsInitNormal( SOLID_BBOX, 0, false );
if ( pPhysicsObject )
{
m_pMotionController = physenv->CreateMotionController( &m_GrenadeController );
m_pMotionController->AttachObject( pPhysicsObject, true );
pPhysicsObject->EnableGravity( false );
}
m_takedamage = DAMAGE_EVENTS_ONLY;
}
else
{
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM );
m_takedamage = DAMAGE_NO;
}
AddSolidFlags( FSOLID_NOT_STANDABLE );
m_iHealth = 1;
SetFriction( GetGrenadeFriction() );
SetElasticity( GetGrenadeElasticity() );
// Remember our owner's team
ChangeTeam( GetThrower()->GetTeamNumber() );
m_flDamage = 150;
m_DmgRadius = m_flDamage * 2.5f;
// Don't collide with players on the owner's team for the first bit of our life
m_flCollideWithTeammatesTime = gpGlobals->curtime + 0.25;
m_bCollideWithTeammates = false;
SetThink( &CDODBaseGrenade::DetonateThink );
SetNextThink( gpGlobals->curtime + 0.1 );
}
void CDODBaseGrenade::Precache( void )
{
BaseClass::Precache();
PrecacheParticleSystem( "grenadetrail" );
PrecacheParticleSystem( "riflegrenadetrail" );
PrecacheParticleSystem( "explosioncore_midair" );
PrecacheParticleSystem( "explosioncore_floor" );
}
void CDODBaseGrenade::DetonateThink( void )
{
if (!IsInWorld())
{
Remove( );
return;
}
if ( gpGlobals->curtime > m_flCollideWithTeammatesTime && m_bCollideWithTeammates == false )
{
m_bCollideWithTeammates = true;
}
Vector foo;
AngularImpulse a;
VPhysicsGetObject()->GetVelocity( &foo, &a );
if( gpGlobals->curtime > m_flDetonateTime )
{
Detonate();
return;
}
if (GetWaterLevel() != 0)
{
SetAbsVelocity( GetAbsVelocity() * 0.5 );
}
SetNextThink( gpGlobals->curtime + 0.2 );
}
//Sets the time at which the grenade will explode
void CDODBaseGrenade::SetDetonateTimerLength( float timer )
{
m_flDetonateTime = gpGlobals->curtime + timer;
}
void CDODBaseGrenade::ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity )
{
//Assume all surfaces have the same elasticity
float flSurfaceElasticity = 1.0;
//Don't bounce off of players with perfect elasticity
if( trace.m_pEnt && trace.m_pEnt->IsPlayer() )
{
flSurfaceElasticity = 0.3;
}
float flTotalElasticity = GetElasticity() * flSurfaceElasticity;
flTotalElasticity = clamp( flTotalElasticity, 0.0f, 0.9f );
// NOTE: A backoff of 2.0f is a reflection
Vector vecAbsVelocity;
PhysicsClipVelocity( GetAbsVelocity(), trace.plane.normal, vecAbsVelocity, 2.0f );
vecAbsVelocity *= flTotalElasticity;
// Get the total velocity (player + conveyors, etc.)
VectorAdd( vecAbsVelocity, GetBaseVelocity(), vecVelocity );
float flSpeedSqr = DotProduct( vecVelocity, vecVelocity );
// Stop if on ground.
if ( trace.plane.normal.z > 0.7f ) // Floor
{
// Verify that we have an entity.
CBaseEntity *pEntity = trace.m_pEnt;
Assert( pEntity );
// Are we on the ground?
if ( vecVelocity.z < ( GetCurrentGravity() * gpGlobals->frametime ) )
{
if ( pEntity->IsStandable() )
{
SetGroundEntity( pEntity );
}
vecAbsVelocity.z = 0.0f;
}
SetAbsVelocity( vecAbsVelocity );
if ( flSpeedSqr < ( 30 * 30 ) )
{
if ( pEntity->IsStandable() )
{
SetGroundEntity( pEntity );
}
// Reset velocities.
SetAbsVelocity( vec3_origin );
SetLocalAngularVelocity( vec3_angle );
}
else
{
Vector vecDelta = GetBaseVelocity() - vecAbsVelocity;
Vector vecBaseDir = GetBaseVelocity();
VectorNormalize( vecBaseDir );
float flScale = vecDelta.Dot( vecBaseDir );
VectorScale( vecAbsVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, vecVelocity );
VectorMA( vecVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, GetBaseVelocity() * flScale, vecVelocity );
PhysicsPushEntity( vecVelocity, &trace );
}
}
else
{
// If we get *too* slow, we'll stick without ever coming to rest because
// we'll get pushed down by gravity faster than we can escape from the wall.
if ( flSpeedSqr < ( 30 * 30 ) )
{
// Reset velocities.
SetAbsVelocity( vec3_origin );
SetLocalAngularVelocity( vec3_angle );
}
else
{
SetAbsVelocity( vecAbsVelocity );
}
}
BounceSound();
}
char *CDODBaseGrenade::GetExplodingClassname( void )
{
Assert( !"Baseclass must implement this" );
return NULL;
}
void CDODBaseGrenade::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( !CanBePickedUp() )
return;
if ( !pActivator->IsPlayer() )
return;
CDODPlayer *pPlayer = ToDODPlayer( pActivator );
//Don't pick up grenades while deployed
CBaseCombatWeapon *pWpn = pPlayer->GetActiveWeapon();
if ( pWpn && !pWpn->CanHolster() )
{
return;
}
DODRoundState state = DODGameRules()->State_Get();
if ( dod_bonusround.GetBool() )
{
int team = pPlayer->GetTeamNumber();
// if its after the round and bonus round is on, we can only pick it up if we are winners
if ( team == TEAM_ALLIES && state == STATE_AXIS_WIN )
return;
if ( team == TEAM_AXIS && state == STATE_ALLIES_WIN )
return;
}
else
{
// if its after the round, and bonus round is off, don't allow anyone to pick it up
if ( state != STATE_RND_RUNNING )
return;
}
OnPickedUp();
char *szClsName = GetExplodingClassname();
Assert( szClsName );
CBaseCombatWeapon *pWeapon = dynamic_cast<CBaseCombatWeapon *>( pPlayer->GiveNamedItem( szClsName ) );
Assert( pWeapon && "Wpn pointer has to be valid for us to pick up this grenade" );
if( pWeapon )
{
variant_t flDetTime;
flDetTime.SetFloat( m_flDetonateTime );
pWeapon->AcceptInput( "DetonateTime", this, this, flDetTime, 0 );
#ifdef DBGFLAG_ASSERT
bool bSuccess =
#endif
pPlayer->Weapon_Switch( pWeapon );
Assert( bSuccess );
//Remove the one we picked up
SetThink( NULL );
UTIL_Remove( this );
}
}
int CDODBaseGrenade::OnTakeDamage( const CTakeDamageInfo &info )
{
if( info.GetDamageType() & DMG_BULLET )
{
// Don't allow players to shoot grenades
return 0;
}
else if( info.GetDamageType() & DMG_BLAST )
{
// Don't allow explosion force to move grenades
return 0;
}
VPhysicsTakeDamage( info );
return BaseClass::OnTakeDamage( info );
}
void CDODBaseGrenade::Detonate()
{
// Don't explode after the round has ended
if ( dod_bonusround.GetBool() == false && DODGameRules()->State_Get() != STATE_RND_RUNNING )
{
SetDamage( 0 );
}
// stun players in a radius
const float flStunDamage = 100;
CTakeDamageInfo info( this, GetThrower(), GetBlastForce(), GetAbsOrigin(), flStunDamage, DMG_STUN );
DODGameRules()->RadiusStun( info, GetAbsOrigin(), m_DmgRadius );
BaseClass::Detonate();
}
bool CDODBaseGrenade::CreateVPhysics()
{
// Create the object in the physics system
VPhysicsInitNormal( SOLID_BBOX, 0, false );
return true;
}
void CDODBaseGrenade::Explode( trace_t *pTrace, int bitsDamageType )
{
SetModelName( NULL_STRING );//invisible
AddSolidFlags( FSOLID_NOT_SOLID );
m_takedamage = DAMAGE_NO;
// Pull out of the wall a bit
if ( pTrace->fraction != 1.0 )
{
SetAbsOrigin( pTrace->endpos + (pTrace->plane.normal * 0.6) );
}
// Explosion effect on client
Vector vecOrigin = GetAbsOrigin();
CPVSFilter filter( vecOrigin );
TE_DODExplosion( filter, 0.0f, vecOrigin, pTrace->plane.normal );
// Use the thrower's position as the reported position
Vector vecReported = GetThrower() ? GetThrower()->GetAbsOrigin() : vec3_origin;
CTakeDamageInfo info( this, GetThrower(), GetBlastForce(), GetAbsOrigin(), m_flDamage, bitsDamageType, 0, &vecReported );
RadiusDamage( info, vecOrigin, GetDamageRadius(), CLASS_NONE, NULL );
// Don't decal players with scorch.
if ( pTrace->m_pEnt && !pTrace->m_pEnt->IsPlayer() )
{
UTIL_DecalTrace( pTrace, "Scorch" );
}
SetThink( &CBaseGrenade::SUB_Remove );
SetTouch( NULL );
AddEffects( EF_NODRAW );
SetAbsVelocity( vec3_origin );
SetNextThink( gpGlobals->curtime );
}
// this will hit only things that are in newCollisionGroup, but NOT in collisionGroupAlreadyChecked
class CTraceFilterCollisionGroupDelta : public CTraceFilterEntitiesOnly
{
public:
// It does have a base, but we'll never network anything below here..
DECLARE_CLASS_NOBASE( CTraceFilterCollisionGroupDelta );
CTraceFilterCollisionGroupDelta( const IHandleEntity *passentity, int collisionGroupAlreadyChecked, int newCollisionGroup )
: m_pPassEnt(passentity), m_collisionGroupAlreadyChecked( collisionGroupAlreadyChecked ), m_newCollisionGroup( newCollisionGroup )
{
}
virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
{
if ( !PassServerEntityFilter( pHandleEntity, m_pPassEnt ) )
return false;
CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
if ( pEntity )
{
if ( g_pGameRules->ShouldCollide( m_collisionGroupAlreadyChecked, pEntity->GetCollisionGroup() ) )
return false;
if ( g_pGameRules->ShouldCollide( m_newCollisionGroup, pEntity->GetCollisionGroup() ) )
return true;
}
return false;
}
protected:
const IHandleEntity *m_pPassEnt;
int m_collisionGroupAlreadyChecked;
int m_newCollisionGroup;
};
const float GRENADE_COEFFICIENT_OF_RESTITUTION = 0.2f;
void CDODBaseGrenade::VPhysicsUpdate( IPhysicsObject *pPhysics )
{
BaseClass::VPhysicsUpdate( pPhysics );
Vector vel;
AngularImpulse angVel;
pPhysics->GetVelocity( &vel, &angVel );
Vector start = GetAbsOrigin();
// find all entities that my collision group wouldn't hit, but COLLISION_GROUP_NONE would and bounce off of them as a ray cast
CTraceFilterCollisionGroupDelta filter( this, GetCollisionGroup(), COLLISION_GROUP_NONE );
trace_t tr;
UTIL_TraceLine( start, start + vel * gpGlobals->frametime, CONTENTS_HITBOX|CONTENTS_MONSTER|CONTENTS_SOLID, &filter, &tr );
bool bHitTeammate = false;
if ( m_bCollideWithTeammates == false && tr.m_pEnt && tr.m_pEnt->IsPlayer() && tr.m_pEnt->GetTeamNumber() == GetTeamNumber() )
{
bHitTeammate = true;
}
if ( tr.startsolid )
{
if ( m_bInSolid == false && bHitTeammate == false )
{
// UNDONE: Do a better contact solution that uses relative velocity?
vel *= -GRENADE_COEFFICIENT_OF_RESTITUTION; // bounce backwards
pPhysics->SetVelocity( &vel, NULL );
}
m_bInSolid = true;
return;
}
m_bInSolid = false;
if ( tr.DidHit() && bHitTeammate == false )
{
Vector dir = vel;
VectorNormalize(dir);
float flPercent = vel.Length() / 2000;
float flDmg = 5 * flPercent;
// send a tiny amount of damage so the character will react to getting bonked
CTakeDamageInfo info( this, GetThrower(), pPhysics->GetMass() * vel, GetAbsOrigin(), flDmg, DMG_CRUSH );
tr.m_pEnt->DispatchTraceAttack( info, dir, &tr );
ApplyMultiDamage();
if ( vel.Length() > 1000 )
{
CTakeDamageInfo stunInfo( this, GetThrower(), vec3_origin, GetAbsOrigin(), flDmg, DMG_STUN );
tr.m_pEnt->TakeDamage( stunInfo );
}
// reflect velocity around normal
vel = -2.0f * tr.plane.normal * DotProduct(vel,tr.plane.normal) + vel;
// absorb 80% in impact
vel *= GetElasticity();
angVel *= -0.5f;
pPhysics->SetVelocity( &vel, &angVel );
}
}
float CDODBaseGrenade::GetElasticity( void )
{
return GRENADE_COEFFICIENT_OF_RESTITUTION;
}
const float DOD_GRENADE_WINDOW_BREAK_DAMPING_AMOUNT = 0.5f;
// If we hit a window, let it break and continue on our way
// with a damped speed
void CDODBaseGrenade::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent )
{
CBreakable *pBreakable = dynamic_cast<CBreakable*>( pEvent->pEntities[!index] );
if ( pBreakable && pBreakable->GetMaterialType() == matGlass && VPhysicsGetObject() )
{
// don't stop, go through this entity after breaking it
Vector dampedVelocity = DOD_GRENADE_WINDOW_BREAK_DAMPING_AMOUNT * pEvent->preVelocity[index];
VPhysicsGetObject()->SetVelocity( &dampedVelocity, &pEvent->preAngularVelocity[index] );
}
else
BaseClass::VPhysicsCollision( index, pEvent );
}
+106
View File
@@ -0,0 +1,106 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DOD_BASEGRENADE_H
#define DOD_BASEGRENADE_H
#ifdef _WIN32
#pragma once
#endif
#include "weapon_dodbase.h"
#include "basegrenade_shared.h"
class CGrenadeTrail;
class CGrenadeController : public IMotionEvent
{
DECLARE_SIMPLE_DATADESC();
public:
virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular );
};
class CDODBaseGrenade : public CBaseGrenade
{
public:
DECLARE_CLASS( CDODBaseGrenade, CBaseGrenade );
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
CDODBaseGrenade();
virtual ~CDODBaseGrenade();
virtual void Spawn();
virtual void Precache( void );
static inline float GetGrenadeGravity() { return 0.4f; }
static inline const float GetGrenadeFriction() { return 0.5f; }
static inline const float GetGrenadeElasticity() { return 0.2f; }
void DetonateThink( void );
virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual char *GetExplodingClassname( void );
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() | FCAP_IMPULSE_USE | FCAP_USE_IN_RADIUS; }
virtual int OnTakeDamage( const CTakeDamageInfo &info );
virtual void Detonate();
bool CreateVPhysics();
virtual void VPhysicsUpdate( IPhysicsObject *pPhysics );
virtual void VPhysicsCollision( int index, gamevcollisionevent_t *pEvent );
virtual void Explode( trace_t *pTrace, int bitsDamageType );
void SetupInitialTransmittedGrenadeVelocity( const Vector &velocity )
{
m_vInitialVelocity = velocity;
}
CGrenadeController m_GrenadeController;
IPhysicsMotionController *m_pMotionController;
virtual bool CanBePickedUp( void ) { return true; }
virtual void OnPickedUp( void ) {}
virtual float GetElasticity();
virtual DODWeaponID GetEmitterWeaponID() { return m_EmitterWeaponID; }
protected:
//Set the time to detonate ( now + timer )
virtual void SetDetonateTimerLength( float timer );
float m_flDetonateTime;
//Custom collision to allow for constant elasticity on hit surfaces
virtual void ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity );
bool m_bUseVPhysics;
DODWeaponID m_EmitterWeaponID;
private:
CDODBaseGrenade( const CDODBaseGrenade & );
bool m_bInSolid;
// This gets sent to the client and placed in the client's interpolation history
// so the projectile starts out moving right off the bat.
CNetworkVector( m_vInitialVelocity );
float m_flCollideWithTeammatesTime;
bool m_bCollideWithTeammates;
};
#endif // DOD_BASEGRENADE_H
+294
View File
@@ -0,0 +1,294 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "dod_baserocket.h"
#include "explode.h"
#include "dod_shareddefs.h"
#include "dod_gamerules.h"
#include "fx_dod_shared.h"
BEGIN_DATADESC( CDODBaseRocket )
// Function Pointers
DEFINE_FUNCTION( RocketTouch ),
DEFINE_THINKFUNC( FlyThink ),
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST( CDODBaseRocket, DT_DODBaseRocket )
SendPropVector( SENDINFO( m_vInitialVelocity ),
20, // nbits
0, // flags
-3000, // low value
3000 // high value
)
END_NETWORK_TABLE()
LINK_ENTITY_TO_CLASS( base_rocket, CDODBaseRocket );
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CDODBaseRocket::CDODBaseRocket()
{
}
CDODBaseRocket::~CDODBaseRocket()
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBaseRocket::Precache( void )
{
PrecacheScriptSound( "Weapon_Bazooka.Shoot" );
PrecacheParticleSystem( "rockettrail" );
}
ConVar mp_rocketdamage( "mp_rocketdamage", "150", FCVAR_GAMEDLL | FCVAR_CHEAT );
ConVar mp_rocketradius( "mp_rocketradius", "200", FCVAR_GAMEDLL | FCVAR_CHEAT );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBaseRocket::Spawn( void )
{
Precache();
SetSolid( SOLID_BBOX );
Assert( GetModel() ); //derived classes must have set model
UTIL_SetSize( this, -Vector(2,2,2), Vector(2,2,2) );
SetTouch( &CDODBaseRocket::RocketTouch );
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM );
m_takedamage = DAMAGE_NO;
SetGravity( 0.1 );
SetDamage( mp_rocketdamage.GetFloat() );
AddFlag( FL_OBJECT );
SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
EmitSound( "Weapon_Bazooka.Shoot" );
m_flCollideWithTeammatesTime = gpGlobals->curtime + 0.25;
m_bCollideWithTeammates = false;
SetThink( &CDODBaseRocket::FlyThink );
SetNextThink( gpGlobals->curtime );
}
unsigned int CDODBaseRocket::PhysicsSolidMaskForEntity( void ) const
{
int teamContents = 0;
if ( m_bCollideWithTeammates == false )
{
// Only collide with the other team
teamContents = ( GetTeamNumber() == TEAM_ALLIES ) ? CONTENTS_TEAM1 : CONTENTS_TEAM2;
}
else
{
// Collide with both teams
teamContents = CONTENTS_TEAM1 | CONTENTS_TEAM2;
}
return BaseClass::PhysicsSolidMaskForEntity() | CONTENTS_HITBOX | teamContents;
}
//-----------------------------------------------------------------------------
// Purpose: Stops any kind of tracking and shoots dumb
//-----------------------------------------------------------------------------
void CDODBaseRocket::Fire( void )
{
SetThink( NULL );
SetMoveType( MOVETYPE_FLY );
SetModel("models/weapons/w_missile.mdl");
UTIL_SetSize( this, vec3_origin, vec3_origin );
EmitSound( "Weapon_Bazooka.Shoot" );
}
//-----------------------------------------------------------------------------
// The actual explosion
//-----------------------------------------------------------------------------
void CDODBaseRocket::DoExplosion( trace_t *pTrace )
{
/*
// Explode
ExplosionCreate(
GetAbsOrigin(), //DMG_ROCKET
GetAbsAngles(),
GetOwnerEntity(),
GetDamage(), //magnitude
mp_rocketradius.GetFloat(), //radius
SF_ENVEXPLOSION_NOSPARKS | SF_ENVEXPLOSION_NODLIGHTS | SF_ENVEXPLOSION_NOSMOKE,
0.0f, //explosion force
this); //inflictor
*/
// Pull out of the wall a bit
if ( pTrace->fraction != 1.0 )
{
SetAbsOrigin( pTrace->endpos + (pTrace->plane.normal * 0.6) );
}
// Explosion effect on client
Vector vecOrigin = GetAbsOrigin();
CPVSFilter filter( vecOrigin );
TE_DODExplosion( filter, 0.0f, vecOrigin, pTrace->plane.normal );
CTakeDamageInfo info( this, GetOwnerEntity(), vec3_origin, GetAbsOrigin(), GetDamage(), DMG_BLAST, 0 );
RadiusDamage( info, vecOrigin, mp_rocketradius.GetFloat() /* GetDamageRadius() */, CLASS_NONE, NULL );
// stun players in a radius
const float flStunDamage = 75;
const float flRadius = 150;
CTakeDamageInfo stunInfo( this, GetOwnerEntity(), vec3_origin, GetAbsOrigin(), flStunDamage, DMG_STUN );
DODGameRules()->RadiusStun( stunInfo, GetAbsOrigin(), flRadius );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBaseRocket::Explode( void )
{
// Don't explode against the skybox. Just pretend that
// the missile flies off into the distance.
const trace_t &tr = CBaseEntity::GetTouchTrace();
const trace_t *p = &tr;
trace_t *newTrace = const_cast<trace_t*>(p);
DoExplosion( newTrace );
if ( newTrace->m_pEnt && !newTrace->m_pEnt->IsPlayer() )
UTIL_DecalTrace( newTrace, "Scorch" );
StopSound( "Weapon_Bazooka.Shoot" );
UTIL_Remove( this );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pOther -
//-----------------------------------------------------------------------------
void CDODBaseRocket::RocketTouch( CBaseEntity *pOther )
{
Assert( pOther );
if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) )
return;
if ( pOther->GetCollisionGroup() == COLLISION_GROUP_WEAPON )
return;
// if we hit the skybox, just disappear
const trace_t &tr = CBaseEntity::GetTouchTrace();
const trace_t *p = &tr;
trace_t *newTrace = const_cast<trace_t*>(p);
if( tr.surface.flags & SURF_SKY )
{
UTIL_Remove( this );
return;
}
if( !pOther->IsPlayer() && pOther->m_takedamage == DAMAGE_YES )
{
CTakeDamageInfo info;
info.SetAttacker( this );
info.SetInflictor( this );
info.SetDamage( 50 );
info.SetDamageForce( vec3_origin ); // don't worry about this not having a damage force.
// It will explode on touch and impart its own forces
info.SetDamageType( DMG_CLUB );
Vector dir;
AngleVectors( GetAbsAngles(), &dir );
pOther->DispatchTraceAttack( info, dir, newTrace );
ApplyMultiDamage();
if( pOther->IsAlive() )
{
Explode();
}
// if it's not alive, continue flying
}
else
{
Explode();
}
}
void CDODBaseRocket::FlyThink( void )
{
QAngle angles;
VectorAngles( GetAbsVelocity(), angles );
SetAbsAngles( angles );
if ( gpGlobals->curtime > m_flCollideWithTeammatesTime && m_bCollideWithTeammates == false )
{
m_bCollideWithTeammates = true;
}
SetNextThink( gpGlobals->curtime + 0.1f );
}
//-----------------------------------------------------------------------------
// Purpose:
//
// Input : &vecOrigin -
// &vecAngles -
// NULL -
//
// Output : CDODBaseRocket
//-----------------------------------------------------------------------------
CDODBaseRocket *CDODBaseRocket::Create( const char *szClassname, const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity *pOwner = NULL )
{
CDODBaseRocket *pMissile = (CDODBaseRocket *) CBaseEntity::Create( szClassname, vecOrigin, vecAngles, pOwner );
pMissile->SetOwnerEntity( pOwner );
pMissile->Spawn();
Vector vecForward;
AngleVectors( vecAngles, &vecForward );
Vector vRocket = vecForward * 1300;
pMissile->SetAbsVelocity( vRocket );
pMissile->SetupInitialTransmittedGrenadeVelocity( vRocket );
pMissile->SetAbsAngles( vecAngles );
// remember what team we should be on
pMissile->ChangeTeam( pOwner->GetTeamNumber() );
return pMissile;
}
void CDODBaseRocket::SetupInitialTransmittedGrenadeVelocity( const Vector &velocity )
{
m_vInitialVelocity = velocity;
}
+67
View File
@@ -0,0 +1,67 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef DOD_BASEROCKET_H
#define DOD_BASEROCKET_H
#ifdef _WIN32
#pragma once
#endif
#include "cbase.h"
#include "baseanimating.h"
#include "smoke_trail.h"
#include "weapon_dodbase.h"
class RocketTrail;
//================================================
// CDODBaseRocket
//================================================
class CDODBaseRocket : public CBaseAnimating
{
DECLARE_CLASS( CDODBaseRocket, CBaseAnimating );
public:
CDODBaseRocket();
~CDODBaseRocket();
void Spawn( void );
void Precache( void );
void RocketTouch( CBaseEntity *pOther );
void Explode( void );
void Fire( void );
virtual float GetDamage() { return m_flDamage; }
virtual void SetDamage(float flDamage) { m_flDamage = flDamage; }
unsigned int PhysicsSolidMaskForEntity( void ) const;
static CDODBaseRocket *Create( const char *szClassname, const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity *pOwner );
void SetupInitialTransmittedGrenadeVelocity( const Vector &velocity );
virtual DODWeaponID GetEmitterWeaponID() { return WEAPON_NONE; Assert(0); }
protected:
virtual void DoExplosion( trace_t *pTrace );
void FlyThink( void );
float m_flDamage;
CNetworkVector( m_vInitialVelocity );
private:
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
float m_flCollideWithTeammatesTime;
bool m_bCollideWithTeammates;
};
#endif // DOD_BASEROCKET_H
+144
View File
@@ -0,0 +1,144 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "dod_player.h"
#include "dod_bombtarget.h"
#include "triggers.h"
class CDODBombDispenserMapIcon;
class CDODBombDispenser : public CBaseTrigger
{
public:
DECLARE_CLASS( CDODBombDispenser, CBaseTrigger );
DECLARE_DATADESC();
virtual void Spawn( void );
void EXPORT Touch( CBaseEntity *pOther );
bool IsActive( void ) { return !m_bDisabled; }
private:
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
// Which team to give bombs to. TEAM_UNASSIGNED gives to both
int m_iDispenseToTeam;
// Is this area giving out bombs?
bool m_bActive;
};
BEGIN_DATADESC(CDODBombDispenser)
// Touch functions
DEFINE_FUNCTION( Touch ),
// Inputs
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_KEYFIELD( m_iDispenseToTeam, FIELD_INTEGER, "dispense_team" ),
DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ),
END_DATADESC();
LINK_ENTITY_TO_CLASS( dod_bomb_dispenser, CDODBombDispenser );
void CDODBombDispenser::Spawn( void )
{
BaseClass::Spawn();
InitTrigger();
SetTouch( &CDODBombDispenser::Touch );
m_bDisabled = false;
// make our map icon entity
#ifdef DBGFLAG_ASSERT
CBaseEntity *pIcon =
#endif
CBaseEntity::Create( "dod_bomb_dispenser_icon", WorldSpaceCenter(), GetAbsAngles(), this );
Assert( pIcon );
}
void CDODBombDispenser::Touch( CBaseEntity *pOther )
{
if ( m_bDisabled )
return;
if( !pOther->IsPlayer() )
return;
if( !pOther->IsAlive() )
return;
if ( m_iDispenseToTeam != TEAM_UNASSIGNED && pOther->GetTeamNumber() != m_iDispenseToTeam )
return;
CDODPlayer *pPlayer = ToDODPlayer( pOther );
pPlayer->HintMessage( HINT_BOMB_PICKUP );
switch( pPlayer->GetTeamNumber() )
{
case TEAM_ALLIES:
case TEAM_AXIS:
{
if ( pPlayer->Weapon_OwnsThisType( "weapon_basebomb" ) == NULL )
{
pPlayer->GiveNamedItem( "weapon_basebomb" );
CPASFilter filter( pPlayer->WorldSpaceCenter() );
pPlayer->EmitSound( filter, pPlayer->entindex(), "Weapon_C4.PickUp" );
}
}
break;
default:
break;
}
}
void CDODBombDispenser::InputEnable( inputdata_t &inputdata )
{
m_bDisabled = false;
}
void CDODBombDispenser::InputDisable( inputdata_t &inputdata )
{
m_bDisabled = true;
}
class CDODBombDispenserMapIcon : public CBaseEntity
{
public:
DECLARE_CLASS( CDODBombDispenserMapIcon, CBaseEntity );
DECLARE_NETWORKCLASS();
virtual int UpdateTransmitState( void )
{
if ( (( CDODBombDispenser * )GetOwnerEntity())->IsActive() )
{
return SetTransmitState( FL_EDICT_ALWAYS );
}
else
{
return SetTransmitState( FL_EDICT_DONTSEND );
}
}
};
IMPLEMENT_SERVERCLASS_ST(CDODBombDispenserMapIcon, DT_DODBombDispenserMapIcon)
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( dod_bomb_dispenser_icon, CDODBombDispenserMapIcon );
+767
View File
@@ -0,0 +1,767 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "dod_player.h"
#include "dod_gamerules.h"
#include "dod_shareddefs.h"
#include "dod_bombtarget.h"
#include "basecombatweapon.h"
#include "weapon_dodbasebomb.h"
#include "dod_team.h"
#include "dod_shareddefs.h"
#include "dod_objective_resource.h"
BEGIN_DATADESC(CDODBombTarget)
DEFINE_KEYFIELD( m_iszCapPointName, FIELD_STRING, "target_control_point" ),
DEFINE_KEYFIELD( m_iBombingTeam, FIELD_INTEGER, "bombing_team" ),
DEFINE_KEYFIELD( m_iTimerAddSeconds, FIELD_INTEGER, "add_timer_seconds" ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
DEFINE_OUTPUT( m_OnBecomeActive, "OnBombTargetActivated" ),
DEFINE_OUTPUT( m_OnBecomeInactive, "OnBombTargetDeactivated" ),
DEFINE_OUTPUT( m_OnBombPlanted, "OnBombPlanted" ),
DEFINE_OUTPUT( m_OnBombExploded, "OnBombExploded" ),
DEFINE_OUTPUT( m_OnBombDisarmed, "OnBombDefused" ),
DEFINE_KEYFIELD( m_bStartDisabled, FIELD_INTEGER, "StartDisabled" ),
DEFINE_USEFUNC( State_Use ),
DEFINE_THINKFUNC( State_Think ),
END_DATADESC();
IMPLEMENT_SERVERCLASS_ST(CDODBombTarget, DT_DODBombTarget)
SendPropInt( SENDINFO(m_iState), 3 ),
SendPropInt( SENDINFO(m_iBombingTeam), 3 ),
SendPropModelIndex( SENDINFO(m_iTargetModel) ),
SendPropModelIndex( SENDINFO(m_iUnavailableModel) ),
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( dod_bomb_target, CDODBombTarget );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::Spawn( void )
{
m_pControlPoint = NULL;
Precache();
SetTouch( NULL );
SetUse( &CDODBombTarget::State_Use );
SetThink( &CDODBombTarget::State_Think );
SetNextThink( gpGlobals->curtime + 0.1 );
m_pCurStateInfo = NULL;
if ( m_bStartDisabled )
State_Transition( BOMB_TARGET_INACTIVE );
else
State_Transition( BOMB_TARGET_ACTIVE );
BaseClass::Spawn();
// incase we have any animating bomb models
SetPlaybackRate( 1.0 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::Precache( void )
{
BaseClass::Precache();
PrecacheModel( DOD_BOMB_TARGET_MODEL_ARMED );
m_iTargetModel = PrecacheModel( DOD_BOMB_TARGET_MODEL_TARGET );
m_iUnavailableModel = PrecacheModel( DOD_BOMB_TARGET_MODEL_UNAVAILABLE );
}
//-----------------------------------------------------------------------------
// Purpose: change use flags based on state
//-----------------------------------------------------------------------------
int CDODBombTarget::ObjectCaps()
{
int caps = BaseClass::ObjectCaps();
if ( State_Get() != BOMB_TARGET_INACTIVE )
{
caps |= (FCAP_CONTINUOUS_USE | FCAP_USE_IN_RADIUS);
}
return caps;
}
//-----------------------------------------------------------------------------
// Purpose: timer length accessor
//-----------------------------------------------------------------------------
float CDODBombTarget::GetBombTimerLength( void )
{
return DOD_BOMB_TIMER_LENGTH;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::State_Transition( BombTargetState newState )
{
State_Leave();
State_Enter( newState );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::State_Enter( BombTargetState newState )
{
m_pCurStateInfo = State_LookupInfo( newState );
if ( 0 )
{
if ( m_pCurStateInfo )
Msg( "DODRoundState: entering '%s'\n", m_pCurStateInfo->m_pStateName );
else
Msg( "DODRoundState: entering #%d\n", newState );
}
// Initialize the new state.
if ( m_pCurStateInfo && m_pCurStateInfo->pfnEnterState )
(this->*m_pCurStateInfo->pfnEnterState)();
m_iState = (int)newState;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::State_Leave()
{
if ( m_pCurStateInfo && m_pCurStateInfo->pfnLeaveState )
{
(this->*m_pCurStateInfo->pfnLeaveState)();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::State_Think()
{
if ( m_pCurStateInfo && m_pCurStateInfo->pfnThink )
{
(this->*m_pCurStateInfo->pfnThink)();
}
SetNextThink( gpGlobals->curtime + 0.1 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::State_Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( m_pCurStateInfo && m_pCurStateInfo->pfnUse )
{
(this->*m_pCurStateInfo->pfnUse)( pActivator, pCaller, useType, value );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CDODBombTargetStateInfo* CDODBombTarget::State_LookupInfo( BombTargetState state )
{
static CDODBombTargetStateInfo bombTargetStateInfos[] =
{
{ BOMB_TARGET_INACTIVE, "BOMB_TARGET_INACTIVE", &CDODBombTarget::State_Enter_INACTIVE, NULL, NULL, NULL },
{ BOMB_TARGET_ACTIVE, "BOMB_TARGET_ACTIVE", &CDODBombTarget::State_Enter_ACTIVE, NULL, NULL, &CDODBombTarget::State_Use_ACTIVE },
{ BOMB_TARGET_ARMED, "BOMB_TARGET_ARMED", &CDODBombTarget::State_Enter_ARMED, &CDODBombTarget::State_Leave_Armed, &CDODBombTarget::State_Think_ARMED, &CDODBombTarget::State_Use_ARMED }
};
for ( int i=0; i < ARRAYSIZE( bombTargetStateInfos ); i++ )
{
if ( bombTargetStateInfos[i].m_iState == state )
return &bombTargetStateInfos[i];
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::State_Enter_INACTIVE( void )
{
// go invisible
AddEffects( EF_NODRAW );
m_OnBecomeInactive.FireOutput( this, this );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::State_Enter_ACTIVE( void )
{
RemoveEffects( EF_NODRAW );
// set transparent model
SetModel( DOD_BOMB_TARGET_MODEL_TARGET );
m_OnBecomeActive.FireOutput( this, this );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::State_Enter_ARMED( void )
{
RemoveEffects( EF_NODRAW );
// set solid model
SetModel( DOD_BOMB_TARGET_MODEL_ARMED );
// start count down
m_flExplodeTime = gpGlobals->curtime + GetBombTimerLength();
m_OnBombPlanted.FireOutput( this, this );
// tell CP our time until detonation
CControlPoint *pCP = GetControlPoint();
if ( pCP )
{
pCP->BombPlanted( GetBombTimerLength(), m_pPlantingPlayer );
}
EmitSound( "Weapon_C4.Fuse" );
static int iWickSeq = LookupSequence( "w_tnt_wick" );
ResetSequence( iWickSeq );
}
void CDODBombTarget::State_Leave_Armed( void )
{
StopSound( "Weapon_C4.Fuse" );
}
void CDODBombTarget::ResetDefuse( int index )
{
DefusingPlayer *pRec = &m_DefusingPlayers[index];
Assert( pRec );
if ( pRec && pRec->m_pPlayer )
{
pRec->m_pPlayer->SetDefusing( NULL );
//cancel the progress bar
pRec->m_pPlayer->SetProgressBarTime( 0 );
}
m_DefusingPlayers.Remove( index );
// if noone else is defusing, set objective resource to not be defusing
if ( m_DefusingPlayers.Count() <= 0 )
{
CControlPoint *pCP = GetControlPoint();
if ( pCP )
{
g_pObjectiveResource->SetBombBeingDefused( pCP->GetPointIndex(), false );
}
}
}
#include "IEffects.h"
void TE_Sparks( IRecipientFilter& filter, float delay,
const Vector *pos, int nMagnitude, int nTrailLength, const Vector *pDir );
extern short g_sModelIndexFireball;
void CDODBombTarget::Explode( void )
{
// output the explosion
EmitSound( "Weapon_C4.Explode" );
Vector origin = GetAbsOrigin();
CPASFilter filter( origin );
te->Explosion( filter, -1.0, // don't apply cl_interp delay
&origin,
g_sModelIndexFireball,
20, //scale
25,
TE_EXPLFLAG_NONE,
0,
0 );
float flDamage = 200;
float flDmgRadius = flDamage * 2.5;
// do a separate radius damage that ignores the world for added damage!
CTakeDamageInfo dmgInfo( this, m_pPlantingPlayer, vec3_origin, origin, flDamage, DMG_BLAST | DMG_BOMB );
DODGameRules()->RadiusDamage( dmgInfo, origin, flDmgRadius, CLASS_NONE, NULL, true );
// stun players in a radius
const float flStunDamage = 100;
CTakeDamageInfo stunInfo( this, this, vec3_origin, GetAbsOrigin(), flStunDamage, DMG_STUN );
DODGameRules()->RadiusStun( stunInfo, GetAbsOrigin(), flDmgRadius );
State_Transition( BOMB_TARGET_INACTIVE );
m_OnBombExploded.FireOutput( this, this );
// tell CP bomb is no longer active
CControlPoint *pCP = GetControlPoint();
if ( pCP )
{
CDODPlayer *pPlayer = m_pPlantingPlayer;
if ( !pPlayer || !pPlayer->IsConnected() )
{
// pick a random player from the bombing team
// hax - if we are debug and team is 0, use allies
if ( m_iBombingTeam == TEAM_UNASSIGNED )
m_iBombingTeam = TEAM_ALLIES;
CDODTeam *pTeam = GetGlobalDODTeam( m_iBombingTeam );
pPlayer = NULL;
if ( pTeam->GetNumPlayers() > 0 )
{
pPlayer = ToDODPlayer( pTeam->GetPlayer( 0 ) );
if ( !pPlayer || !pPlayer->IsConnected() )
{
// bad situation, abandon here
pPlayer = NULL;
}
}
}
pCP->BombExploded( pPlayer, m_iBombingTeam );
g_pObjectiveResource->SetBombBeingDefused( pCP->GetPointIndex(), false );
}
// If we add time to the round timer, tell Gamerules
// Don't do this if this bomb ended the game
if ( m_iTimerAddSeconds > 0 )
{
if ( m_pPlantingPlayer && FStrEq( STRING(gpGlobals->mapname), "dod_jagd" ) )
{
// if the timer is 0:00 or less, achievement time
if ( DODGameRules()->GetTimerSeconds() <= 0 )
{
m_pPlantingPlayer->AwardAchievement( ACHIEVEMENT_DOD_JAGD_OVERTIME_CAP );
}
}
if ( DODGameRules()->State_Get() == STATE_RND_RUNNING )
{
DODGameRules()->AddTimerSeconds( m_iTimerAddSeconds );
}
}
}
void CDODBombTarget::BombDefused( CDODPlayer *pDefuser )
{
// tell CP bomb is no longer active
CControlPoint *pCP = GetControlPoint();
if ( pCP )
{
pCP->BombDisarmed( pDefuser );
}
if ( pDefuser )
{
pDefuser->StatEvent_BombDefused();
}
State_Transition( BOMB_TARGET_ACTIVE );
m_OnBombDisarmed.FireOutput( this, this );
}
bool CDODBombTarget::CanPlayerStartDefuse( CDODPlayer *pPlayer )
{
if ( !pPlayer || !pPlayer->IsAlive() || !pPlayer->IsConnected() )
{
// if the defuser is not alive or has disconnected, reset
return false;
}
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
{
// they are not on the ground, remove them
pPlayer->HintMessage( HINT_BOMB_DEFUSE_ONGROUND );
return false;
}
Vector vecDist = ( pPlayer->GetAbsOrigin() - GetAbsOrigin() );
float flDist = vecDist.Length();
if ( flDist > DOD_BOMB_DEFUSE_MAXDIST ) // PLAYER_USE_RADIUS is not actually used by the playerUse code!!
{
// they are too far away to continue ( or start ) defusing
return false;
}
return true;
}
bool CDODBombTarget::CanPlayerContinueDefusing( CDODPlayer *pPlayer, DefusingPlayer *pDefuseRecord )
{
if ( !pDefuseRecord || pDefuseRecord->m_flDefuseTimeoutTime < gpGlobals->curtime )
{
// they have not updated their +use in a while, assume they stopped
return false;
}
return CanPlayerStartDefuse( pPlayer );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::State_Think_ARMED( void )
{
// count down
if ( DODGameRules()->State_Get() != STATE_RND_RUNNING )
{
State_Transition( BOMB_TARGET_ACTIVE );
// reset the timer
CControlPoint *pCP = GetControlPoint();
if ( pCP )
{
pCP->CancelBombPlanted();
}
}
// manually advance frame so that it matches bomb timer length.
float flTimerLength = GetBombTimerLength();
float flTimeLeft = m_flExplodeTime - gpGlobals->curtime;
SetCycle( clamp( 1.0 - ( flTimeLeft / flTimerLength ), 0.0, 1.0 ) );
static int iAttachment = LookupAttachment( "wick" );//ed awesome
Vector pos;
QAngle ang;
GetAttachment( iAttachment, pos, ang );
Vector forward;
AngleVectors( ang, &forward );
CPVSFilter filter( pos );
TE_Sparks( filter, 0.0, &pos, 1, 1, &forward );
// So long as we have valid defusers, we will not explode
if ( m_DefusingPlayers.Count() > 0 )
{
// remove the undesirables
// make sure they are on ground still
// see if they have completed the defuse
for ( int i=m_DefusingPlayers.Count()-1;i>=0;i-- )
{
DefusingPlayer *pDefuseRecord = &m_DefusingPlayers[i];
CDODPlayer *pPlayer = pDefuseRecord->m_pPlayer;
if ( !CanPlayerContinueDefusing( pPlayer, pDefuseRecord ) )
{
ResetDefuse( i );
}
else
{
// they are still a valid defuser
// if their defuse complete time has passed
if ( pDefuseRecord->m_flDefuseCompleteTime < gpGlobals->curtime )
{
// Defuse Complete
BombDefused( pPlayer );
// remove everyone from the list
for ( int j=m_DefusingPlayers.Count()-1;j>=0;j-- )
{
ResetDefuse( j );
}
// break out of this loop
i = -1;
}
}
}
}
else if ( gpGlobals->curtime > m_flExplodeTime )
{
// no defusers, time is up
Explode();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::State_Use_ACTIVE( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
CDODPlayer *pPlayer = ToDODPlayer( pActivator );
if ( !CanPlantHere( pPlayer ) )
return;
Vector pos = pPlayer->WorldSpaceCenter();
float flDist = ( pos - GetAbsOrigin() ).Length();
if ( flDist > DOD_BOMB_PLANT_RADIUS )
{
return;
}
if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
{
pPlayer->HintMessage( HINT_BOMB_DEFUSE_ONGROUND, true );
return;
}
CBaseCombatWeapon *pWeapon = NULL;
if ( ( pWeapon = pPlayer->Weapon_OwnsThisType( "weapon_basebomb" ) ) != NULL )
{
CDODBaseBombWeapon *pBomb = dynamic_cast<CDODBaseBombWeapon *>( pWeapon );
if ( pBomb )
{
// switch to their bomb, they will have to hit primary attack
pPlayer->Weapon_Switch( pBomb );
if ( pBomb == pPlayer->GetActiveWeapon() )
{
pBomb->PrimaryAttack();
}
}
}
else
{
// they don't have a bomb - play hint message
pPlayer->HintMessage( HINT_NEED_BOMB );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::CompletePlanting( CDODPlayer *pPlantingPlayer )
{
if ( pPlantingPlayer && ( pPlantingPlayer->GetTeamNumber() == m_iBombingTeam || m_iBombingTeam == TEAM_UNASSIGNED ) )
{
m_pPlantingPlayer = pPlantingPlayer;
State_Transition( BOMB_TARGET_ARMED );
}
}
DefusingPlayer *CDODBombTarget::FindDefusingPlayer( CDODPlayer *pPlayer )
{
DefusingPlayer *pRec = NULL;
for ( int i=0;i<m_DefusingPlayers.Count();i++ )
{
if ( m_DefusingPlayers[i].m_pPlayer == pPlayer )
{
pRec = &m_DefusingPlayers[i];
break;
}
}
return pRec;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::State_Use_ARMED( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
// check for people disarming
CDODPlayer *pPlayer = ToDODPlayer( pActivator );
if ( !pPlayer || pPlayer->GetTeamNumber() == m_iBombingTeam || pPlayer->GetTeamNumber() == TEAM_SPECTATOR )
return;
// check for distance, offground etc
if ( CanPlayerStartDefuse( pPlayer ) == false )
{
return;
}
DefusingPlayer *pDefusingPlayerRecord = FindDefusingPlayer( pPlayer );
// See if we already added this player to the defusing list
if ( pDefusingPlayerRecord )
{
// They are still defusing for the next 0.2 seconds
pDefusingPlayerRecord->m_flDefuseTimeoutTime = gpGlobals->curtime + 0.2;
}
else
{
// add player to the list
DefusingPlayer defusingPlayer;
defusingPlayer.m_pPlayer = pPlayer;
defusingPlayer.m_flDefuseCompleteTime = gpGlobals->curtime + DOD_BOMB_DEFUSE_TIME;
defusingPlayer.m_flDefuseTimeoutTime = gpGlobals->curtime + 0.2;
m_DefusingPlayers.AddToTail( defusingPlayer );
// tell the player they are defusing
pPlayer->SetDefusing( this );
pPlayer->SetProgressBarTime( DOD_BOMB_DEFUSE_TIME );
CControlPoint *pCP = GetControlPoint();
if ( pCP )
{
g_pObjectiveResource->SetBombBeingDefused( pCP->GetPointIndex(), true );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::InputEnable( inputdata_t &inputdata )
{
if ( m_pCurStateInfo && m_pCurStateInfo->m_iState == BOMB_TARGET_INACTIVE )
{
State_Transition( BOMB_TARGET_ACTIVE );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::InputDisable( inputdata_t &inputdata )
{
if ( m_pCurStateInfo && m_pCurStateInfo->m_iState != BOMB_TARGET_INACTIVE )
{
if ( m_pCurStateInfo->m_iState == BOMB_TARGET_ARMED )
{
// if planting, tell our cp we're not planting anymore
CControlPoint *pCP = GetControlPoint();
if ( pCP )
{
pCP->CancelBombPlanted();
}
}
State_Transition( BOMB_TARGET_INACTIVE );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CControlPoint *CDODBombTarget::GetControlPoint( void )
{
if ( !m_pControlPoint )
{
if ( m_iszCapPointName == NULL_STRING )
return NULL;
// try to find it
m_pControlPoint = dynamic_cast<CControlPoint *>( gEntList.FindEntityByName( NULL, STRING(m_iszCapPointName) ) );
if ( !m_pControlPoint )
Warning( "Could not find dod_control_point named \"%s\" for dod_bomb_target \"%s\"\n", STRING(m_iszCapPointName), STRING( GetEntityName() ) );
}
return m_pControlPoint;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CDODBombTarget::CanPlantHere( CDODPlayer *pPlayer )
{
if ( !m_pCurStateInfo )
return false;
if ( m_pCurStateInfo->m_iState != BOMB_TARGET_ACTIVE )
return false;
if ( pPlayer->GetTeamNumber() != m_iBombingTeam && m_iBombingTeam != TEAM_UNASSIGNED )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODBombTarget::DefuseBlocked( CDODPlayer *pAttacker )
{
CControlPoint *pPoint = GetControlPoint();
if ( !pPoint )
return;
IGameEvent *event = gameeventmanager->CreateEvent( "dod_capture_blocked" );
if ( event )
{
event->SetInt( "cp", pPoint->GetPointIndex() );
event->SetString( "cpname", pPoint->GetName() );
event->SetInt( "blocker", pAttacker->entindex() );
event->SetInt( "priority", 9 );
event->SetBool( "bomb", true );
gameeventmanager->FireEvent( event );
}
pAttacker->AddScore( PLAYER_POINTS_FOR_BLOCK );
pAttacker->Stats_AreaDefended();
}
void CDODBombTarget::PlantBlocked( CDODPlayer *pAttacker )
{
CControlPoint *pPoint = GetControlPoint();
if ( !pPoint )
return;
IGameEvent *event = gameeventmanager->CreateEvent( "dod_capture_blocked" );
if ( event )
{
event->SetInt( "cp", pPoint->GetPointIndex() );
event->SetString( "cpname", pPoint->GetName() );
event->SetInt( "blocker", pAttacker->entindex() );
event->SetInt( "priority", 9 );
event->SetBool( "bomb", true );
gameeventmanager->FireEvent( event );
}
pAttacker->AddScore( PLAYER_POINTS_FOR_BLOCK );
pAttacker->Stats_AreaDefended();
}
+154
View File
@@ -0,0 +1,154 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef DOD_BOMBTARGET_H
#define DOD_BOMBTARGET_H
#ifdef _WIN32
#pragma once
#endif
#include "baseanimating.h"
#include "dod_control_point.h"
#define DOD_BOMB_TARGET_MODEL_ARMED "models/weapons/w_tnt.mdl"
#define DOD_BOMB_TARGET_MODEL_TARGET "models/weapons/w_tnt_red.mdl"
#define DOD_BOMB_TARGET_MODEL_UNAVAILABLE "models/weapons/w_tnt_grey.mdl"
class CDODBombTarget;
class CDODBombTargetStateInfo
{
public:
BombTargetState m_iState;
const char *m_pStateName;
void (CDODBombTarget::*pfnEnterState)(); // Init and deinit the state.
void (CDODBombTarget::*pfnLeaveState)();
void (CDODBombTarget::*pfnThink)(); // Do a PreThink() in this state.
void (CDODBombTarget::*pfnUse)( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
};
struct DefusingPlayer
{
CHandle<CDODPlayer> m_pPlayer;
float m_flDefuseTimeoutTime;
float m_flDefuseCompleteTime;
};
class CDODBombTarget : public CBaseAnimating
{
public:
DECLARE_CLASS( CDODBombTarget, CBaseAnimating );
DECLARE_DATADESC();
DECLARE_NETWORKCLASS();
CDODBombTarget() {}
virtual void Spawn( void );
virtual void Precache( void );
// Set these flags so players can use the bomb target ( for planting or defusing )
virtual int ObjectCaps( void );
// Inputs
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
// State Functions
void State_Transition( BombTargetState newState );
void State_Enter( BombTargetState newState );
void State_Leave();
void State_Think();
void State_Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
int State_Get( void ) { return m_iState; }
CDODBombTargetStateInfo* State_LookupInfo( BombTargetState state );
// Enter
void State_Enter_INACTIVE( void );
void State_Enter_ACTIVE( void );
void State_Enter_ARMED( void );
// Leave
void State_Leave_Armed( void );
// Think
void State_Think_ARMED( void );
// Use
void State_Use_ACTIVE( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void State_Use_ARMED( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
float GetBombTimerLength( void );
// Get the dod_control_point that we're linked to
CControlPoint *GetControlPoint( void );
bool CanPlantHere( CDODPlayer *pPlayer );
void CompletePlanting( CDODPlayer *pPlantingPlayer );
void DefuseBlocked( CDODPlayer *pAttacker );
void PlantBlocked( CDODPlayer *pAttacker );
int GetTimerAddSeconds( void ) { return m_iTimerAddSeconds; }
int GetBombingTeam( void ) { return m_iBombingTeam; }
DefusingPlayer *FindDefusingPlayer( CDODPlayer *pPlayer );
void Explode( void );
void BombDefused( CDODPlayer *pDefuser );
void ResetDefuse( int index );
bool CanPlayerStartDefuse( CDODPlayer *pPlayer );
bool CanPlayerContinueDefusing( CDODPlayer *pPlayer, DefusingPlayer *pDefuseRecord );
private:
// Control Point we're linked to
string_t m_iszCapPointName;
CControlPoint *m_pControlPoint;
// Outputs
COutputEvent m_OnBecomeActive;
COutputEvent m_OnBecomeInactive;
COutputEvent m_OnBombPlanted;
COutputEvent m_OnBombExploded;
COutputEvent m_OnBombDisarmed;
// state
CNetworkVar( int, m_iState );
CDODBombTargetStateInfo *m_pCurStateInfo;
bool m_bStartDisabled;
// timers for armed state
float m_flExplodeTime;
float m_flNextAnnounce;
// player that planted this bomb
CHandle<CDODPlayer> m_pPlantingPlayer;
// The team that is allowed to plant bombs here
CNetworkVar( int, m_iBombingTeam );
// network the model indices of active bomb so we can change per-team
CNetworkVar( int, m_iTargetModel );
CNetworkVar( int, m_iUnavailableModel );
int m_iTimerAddSeconds;
// List of defusing players and time until completion
CUtlVector< DefusingPlayer > m_DefusingPlayers;
private:
CDODBombTarget( const CDODBombTarget & );
};
#endif //DOD_BOMBTARGET_H
+453
View File
@@ -0,0 +1,453 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Basic BOT handling.
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "player.h"
#include "dod_player.h"
#include "in_buttons.h"
#include "movehelper_server.h"
void ClientPutInServer( edict_t *pEdict, const char *playername );
void Bot_Think( CDODPlayer *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." );
ConVar bot_zombie( "bot_zombie", "0", 0, "Brraaaaaiiiins." );
static ConVar bot_mimic( "bot_mimic", "0", 0, "Bot uses usercmd of player by index." );
static ConVar bot_mimic_yaw_offset( "bot_mimic_yaw_offset", "0", 0, "Offsets the bot yaw." );
ConVar bot_attack( "bot_attack", "0", 0, "Shoot!" );
ConVar bot_sendcmd( "bot_sendcmd", "", 0, "Forces bots to send the specified command." );
ConVar bot_crouch( "bot_crouch", "0", 0, "Bot crouches" );
static int BotNumber = 1;
static int g_iNextBotTeam = -1;
static int g_iNextBotClass = -1;
typedef struct
{
bool backwards;
float nextturntime;
bool lastturntoright;
float nextstrafetime;
float sidemove;
QAngle forwardAngle;
QAngle lastAngles;
float m_flJoinTeamTime;
int m_WantedTeam;
int m_WantedClass;
} botdata_t;
static botdata_t g_BotData[ MAX_PLAYERS ];
//-----------------------------------------------------------------------------
// 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 );
// This is an evil hack, but we use it to prevent sv_autojointeam from kicking in.
edict_t *pEdict = engine->CreateFakeClient( botname );
if (!pEdict)
{
Msg( "Failed to create Bot.\n");
return NULL;
}
// Allocate a CBasePlayer for the bot, and call spawn
//ClientPutInServer( pEdict, botname );
CDODPlayer *pPlayer = ((CDODPlayer *)CBaseEntity::Instance( pEdict ));
pPlayer->ClearFlags();
pPlayer->AddFlag( FL_CLIENT | FL_FAKECLIENT );
if ( bFrozen )
pPlayer->AddEFlags( EFL_BOT_FROZEN );
BotNumber++;
g_BotData[pPlayer->entindex()-1].m_WantedTeam = iTeam;
g_BotData[pPlayer->entindex()-1].m_WantedClass = iClass;
g_BotData[pPlayer->entindex()-1].m_flJoinTeamTime = gpGlobals->curtime + 0.3;
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++ )
{
CDODPlayer *pPlayer = ToDODPlayer( UTIL_PlayerByIndex( i ) );
if ( pPlayer && (pPlayer->GetFlags() & FL_FAKECLIENT) )
{
Bot_Think( pPlayer );
}
}
}
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();
cmd.viewangles[YAW] += bot_mimic_yaw_offset.GetFloat();
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( CDODPlayer *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 ) && !bot_zombie.GetBool() )
{
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 );
}
if( bot_crouch.GetInt() )
cmd.buttons |= IN_DUCK;
if ( bot_attack.GetBool() )
cmd.buttons |= IN_ATTACK;
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( CDODPlayer *pBot )
{
// 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->GetTeamNumber() == TEAM_UNASSIGNED && gpGlobals->curtime > botdata->m_flJoinTeamTime )
{
pBot->HandleCommand_JoinTeam( botdata->m_WantedTeam );
}
else if ( pBot->GetTeamNumber() != TEAM_UNASSIGNED && pBot->m_Shared.PlayerClass() == PLAYERCLASS_UNDEFINED )
{
// If they're on a team but haven't picked a class, choose a random class..
pBot->HandleCommand_JoinClass( botdata->m_WantedClass );
pBot->DODRespawn();
}
else 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();
// 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;
}
if ( RandomFloat(0.0,1.0) > 0.9 )
buttons |= IN_RELOAD;
}
if ( Q_strlen( bot_sendcmd.GetString() ) > 0 )
{
//send the cmd from this bot
CCommand args;
args.Tokenize( bot_sendcmd.GetString() );
pBot->ClientCommand( args );
bot_sendcmd.SetValue("");
}
}
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 )
{
botdata->lastAngles.x = sin( gpGlobals->curtime + pBot->entindex() ) * 90;
botdata->lastAngles.y = AngleNormalize( ( gpGlobals->curtime * 1.7 + pBot->entindex() ) * 45 );
botdata->lastAngles.z = 0.0;
// botdata->lastAngles = QAngle( 0, 0, 0 );
/*
QAngle angOffset = RandomAngle( -1, 1 );
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;
*/
float speed = 300; // sin( gpGlobals->curtime / 1.7 + pBot->entindex() ) * 600;
forwardmove = sin( gpGlobals->curtime + pBot->entindex() ) * speed;
sidemove = cos( gpGlobals->curtime * 2.3 + pBot->entindex() ) * speed;
if (sin(gpGlobals->curtime ) < -0.5)
{
buttons |= IN_DUCK;
}
else if (sin(gpGlobals->curtime ) < 0.5)
{
buttons |= IN_WALK;
}
pBot->SetLocalAngles( botdata->lastAngles );
}
RunPlayerMove( pBot, pBot->GetLocalAngles(), forwardmove, sidemove, upmove, buttons, impulse, frametime );
}
+19
View 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
+236
View File
@@ -0,0 +1,236 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
/*
===== tf_client.cpp ========================================================
HL2 client/server game specific stuff
*/
#include "cbase.h"
#include "player.h"
#include "gamerules.h"
#include "entitylist.h"
#include "physics.h"
#include "game.h"
#include "ai_network.h"
#include "ai_node.h"
#include "ai_hull.h"
#include "shake.h"
#include "player_resource.h"
#include "engine/IEngineSound.h"
#include "dod_player.h"
#include "dod_gamerules.h"
#include "tier0/vprof.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern CBaseEntity *FindPickerEntity( CBasePlayer *pPlayer );
extern bool g_fGameOver;
void FinishClientPutInServer( CDODPlayer *pPlayer )
{
pPlayer->InitialSpawn();
pPlayer->Spawn();
if (!pPlayer->IsBot())
{
// When the player first joins the server, they
pPlayer->m_takedamage = DAMAGE_NO;
pPlayer->pl.deadflag = true;
pPlayer->m_lifeState = LIFE_DEAD;
pPlayer->AddEffects( EF_NODRAW );
pPlayer->SetThink( NULL );
if ( 1 )
{
pPlayer->ChangeTeam( TEAM_UNASSIGNED );
// Move them to the first intro camera.
pPlayer->MoveToNextIntroCamera();
pPlayer->SetMoveType( MOVETYPE_NONE );
}
}
char sName[128];
Q_strncpy( sName, pPlayer->GetPlayerName(), sizeof( sName ) );
// First parse the name and remove any %'s
for ( char *pApersand = sName; pApersand != NULL && *pApersand != 0; pApersand++ )
{
// Replace it with a space
if ( *pApersand == '%' )
*pApersand = ' ';
}
// notify other clients of player joining the game
UTIL_ClientPrintAll( HUD_PRINTNOTIFY, "#Game_connected", sName[0] != 0 ? sName : "<unconnected>" );
}
/*
===========
ClientPutInServer
called each time a player is spawned into the game
============
*/
void ClientPutInServer( edict_t *pEdict, const char *playername )
{
// Allocate a CBaseTFPlayer for pev, and call spawn
CDODPlayer *pPlayer = CDODPlayer::CreatePlayer( "player", pEdict );
pPlayer->SetPlayerName( playername );
}
void ClientActive( edict_t *pEdict, bool bLoadGame )
{
// Can't load games in CS!
Assert( !bLoadGame );
CDODPlayer *pPlayer = ToDODPlayer( CBaseEntity::Instance( pEdict ) );
FinishClientPutInServer( pPlayer );
}
/*
===============
const char *GetGameDescription()
Returns the descriptive name of this .dll. E.g., Half-Life, or Team Fortress 2
===============
*/
const char *GetGameDescription()
{
if ( g_pGameRules ) // this function may be called before the world has spawned, and the game rules initialized
return g_pGameRules->GetGameDescription();
else
return "Day of Defeat";
}
int g_iHelmetModels[NUM_HELMETS];
//-----------------------------------------------------------------------------
// Purpose: Precache game-specific models & sounds
//-----------------------------------------------------------------------------
void ClientGamePrecache( void )
{
// Materials used by the client effects
CBaseEntity::PrecacheModel( "sprites/white.vmt" );
CBaseEntity::PrecacheModel( "sprites/physbeam.vmt" );
for( int i=0;i<NUM_HELMETS;i++ )
{
g_iHelmetModels[i] = CBaseEntity::PrecacheModel( m_pszHelmetModels[i] );
}
// Moved to pure_server_minimal.txt
// // Sniper scope
// engine->ForceExactFile( "sprites/scopes/scope_spring_ul.vmt" );
// engine->ForceExactFile( "sprites/scopes/scope_spring_ul.vtf" );
// engine->ForceExactFile( "sprites/scopes/scope_spring_ur.vmt" );
// engine->ForceExactFile( "sprites/scopes/scope_spring_ur.vtf" );
// engine->ForceExactFile( "sprites/scopes/scope_spring_ll.vmt" );
// engine->ForceExactFile( "sprites/scopes/scope_spring_ll.vtf" );
// engine->ForceExactFile( "sprites/scopes/scope_spring_lr.vmt" );
// engine->ForceExactFile( "sprites/scopes/scope_spring_lr.vtf" );
//
// engine->ForceExactFile( "sprites/scopes/scope_k43_ul.vmt" );
// engine->ForceExactFile( "sprites/scopes/scope_k43_ul.vtf" );
// engine->ForceExactFile( "sprites/scopes/scope_k43_ur.vmt" );
// engine->ForceExactFile( "sprites/scopes/scope_k43_ur.vtf" );
// engine->ForceExactFile( "sprites/scopes/scope_k43_ll.vmt" );
// engine->ForceExactFile( "sprites/scopes/scope_k43_ll.vtf" );
// engine->ForceExactFile( "sprites/scopes/scope_k43_lr.vmt" );
// engine->ForceExactFile( "sprites/scopes/scope_k43_lr.vtf" );
//
// // Smoke grenade-related files
// engine->ForceExactFile( "particle/particle_smokegrenade1.vmt" );
// engine->ForceExactFile( "particle/particle_smokegrenade.vtf" );
// engine->ForceExactFile( "effects/stun.vmt" );
//
// // DSP presets - don't want people avoiding the deafening + ear ring
// engine->ForceExactFile( "scripts/dsp_presets.txt" );
//
// // force weapon scripts because people are dirty cheaters
// engine->ForceExactFile( "scripts/weapon_30cal.ctx");
// engine->ForceExactFile( "scripts/weapon_amerknife.ctx");
// engine->ForceExactFile( "scripts/weapon_bar.ctx");
// engine->ForceExactFile( "scripts/weapon_bazooka.ctx");
// engine->ForceExactFile( "scripts/weapon_c96.ctx");
// engine->ForceExactFile( "scripts/weapon_colt.ctx");
// engine->ForceExactFile( "scripts/weapon_frag_ger.ctx");
// engine->ForceExactFile( "scripts/weapon_frag_ger_live.ctx");
// engine->ForceExactFile( "scripts/weapon_frag_us.ctx");
// engine->ForceExactFile( "scripts/weapon_frag_us_live.ctx");
// engine->ForceExactFile( "scripts/weapon_garand.ctx");
// engine->ForceExactFile( "scripts/weapon_k98.ctx");
// engine->ForceExactFile( "scripts/weapon_k98_scoped.ctx");
// engine->ForceExactFile( "scripts/weapon_m1carbine.ctx");
// engine->ForceExactFile( "scripts/weapon_mg42.ctx");
// engine->ForceExactFile( "scripts/weapon_mp40.ctx");
// engine->ForceExactFile( "scripts/weapon_mp44.ctx");
// engine->ForceExactFile( "scripts/weapon_p38.ctx");
// engine->ForceExactFile( "scripts/weapon_pschreck.ctx");
// engine->ForceExactFile( "scripts/weapon_riflegren_ger.ctx");
// engine->ForceExactFile( "scripts/weapon_riflegren_ger_live.ctx");
// engine->ForceExactFile( "scripts/weapon_riflegren_us.ctx");
// engine->ForceExactFile( "scripts/weapon_riflegren_us_live.ctx");
// engine->ForceExactFile( "scripts/weapon_smoke_ger.ctx");
// engine->ForceExactFile( "scripts/weapon_smoke_us.ctx");
// engine->ForceExactFile( "scripts/weapon_spade.ctx");
// engine->ForceExactFile( "scripts/weapon_spring.ctx");
// engine->ForceExactFile( "scripts/weapon_thompson.ctx");
}
// called by ClientKill and DeadThink
void respawn( CBaseEntity *pEdict, bool fCopyCorpse )
{
if (gpGlobals->coop || gpGlobals->deathmatch)
{
if ( fCopyCorpse )
{
// make a copy of the dead body for appearances sake
dynamic_cast< CBasePlayer* >( pEdict )->CreateCorpse();
}
// respawn player
pEdict->Spawn();
}
else
{ // restart the entire server
engine->ServerCommand("reload\n");
}
}
void GameStartFrame( void )
{
VPROF( "GameStartFrame" );
if ( g_fGameOver )
return;
gpGlobals->teamplay = teamplay.GetInt() ? true : false;
extern void Bot_RunAll();
Bot_RunAll();
}
//=========================================================
// instantiate the proper game rules object
//=========================================================
void InstallGameRules()
{
CreateGameRulesObject( "CDODGameRules" );
}
+738
View File
@@ -0,0 +1,738 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "dod_shareddefs.h"
#include "dod_control_point.h"
#include "dod_player.h"
#include "dod_gamerules.h"
#include "dod_team.h"
#include "dod_objective_resource.h"
#include "dod_control_point_master.h"
LINK_ENTITY_TO_CLASS( dod_control_point, CControlPoint );
#define OBJ_ICON_NEUTRAL_FLAG 0
#define OBJ_ICON_ALLIES_FLAG 1
#define OBJ_ICON_AXIS_FLAG 2
BEGIN_DATADESC(CControlPoint)
DEFINE_KEYFIELD( m_iszPrintName, FIELD_STRING, "point_printname" ),
DEFINE_KEYFIELD( m_iszAlliesCapSound, FIELD_STRING, "point_allies_capsound" ),
DEFINE_KEYFIELD( m_iszAxisCapSound, FIELD_STRING, "point_axis_capsound" ),
DEFINE_KEYFIELD( m_iszResetSound, FIELD_STRING, "point_resetsound" ),
DEFINE_KEYFIELD( m_iszAlliesModel, FIELD_STRING, "point_allies_model" ),
DEFINE_KEYFIELD( m_iszAxisModel, FIELD_STRING, "point_axis_model" ),
DEFINE_KEYFIELD( m_iszResetModel, FIELD_STRING, "point_reset_model" ),
DEFINE_KEYFIELD( m_iCPGroup, FIELD_INTEGER, "point_group" ),
DEFINE_KEYFIELD( m_iTimedPointsAllies, FIELD_INTEGER, "point_timedpoints_allies" ),
DEFINE_KEYFIELD( m_iTimedPointsAxis, FIELD_INTEGER, "point_timedpoints_axis" ),
DEFINE_KEYFIELD( m_iBombsRequired, FIELD_INTEGER, "point_num_bombs" ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetOwner", InputSetOwner ),
DEFINE_INPUTFUNC( FIELD_VOID, "ShowModel", InputShowModel ),
DEFINE_INPUTFUNC( FIELD_VOID, "HideModel", InputHideModel ),
DEFINE_OUTPUT( m_AlliesCapOutput, "OnAlliesCap" ), // these are fired whenever the point changes modes
DEFINE_OUTPUT( m_AxisCapOutput, "OnAxisCap" ),
DEFINE_OUTPUT( m_PointResetOutput, "OnCapReset" ),
DEFINE_OUTPUT( m_OwnerChangedToAllies, "AlliesCapturePoint" ), // these are fired when a team does the work to change the owner
DEFINE_OUTPUT( m_OwnerChangedToAxis, "AxisCapturePoint" ),
END_DATADESC();
CControlPoint::CControlPoint( )
{
m_iPointIndex = -1;
m_bPointVisible = false;
m_iAlliesIcon = 0;
m_iAxisIcon = 0;
m_iNeutralIcon = 0;
m_iNeutralIcon = 0;
//default group is 0 for backwards compatibility
m_iAlliesModelBodygroup = 0;
m_iAxisModelBodygroup = 0;
m_iResetModelBodygroup = 0;
m_bBombPlanted = false;
}
void CControlPoint::Spawn( void )
{
Precache();
SetTouch( NULL );
InternalSetOwner( m_iDefaultOwner, false ); //init the owner of this point
SetActive( !m_bStartDisabled );
BaseClass::Spawn();
UseClientSideAnimation();
SetPlaybackRate( 1.0 );
SetCycle( random->RandomFloat( 0, 1.0 ) );
m_iAlliesRequired = 0;
m_iAxisRequired = 0;
if ( FBitSet( m_spawnflags, CAP_POINT_HIDE_MODEL ) )
{
AddEffects( EF_NODRAW );
}
m_iBombsRemaining = m_iBombsRequired;
}
void CControlPoint::SetNumCappersRequired( int alliesRequired, int axisRequired )
{
m_iAlliesRequired = alliesRequired;
m_iAxisRequired = axisRequired;
}
//================================
// InputReset
// Used by ControlMaster to this point to its default owner
//================================
void CControlPoint::InputReset( inputdata_t &input )
{
InternalSetOwner( m_iDefaultOwner, false );
g_pObjectiveResource->SetOwningTeam( GetPointIndex(), m_iTeam );
}
//================================
// InputReset
// Used by Area caps to set the owner
//================================
void CControlPoint::InputSetOwner( inputdata_t &input )
{
int team = input.value.Int();
Assert( team == TEAM_UNASSIGNED || team == TEAM_ALLIES || team == TEAM_AXIS );
Assert( input.pCaller );
Assert( input.pCaller->IsPlayer() );
CDODPlayer *pPlayer = ToDODPlayer( input.pCaller );
int iCappingPlayer = pPlayer->entindex();
// Only allow cp caps when round is running ( but not when in warmup )
if( DODGameRules()->State_Get() == STATE_RND_RUNNING &&
!DODGameRules()->IsInWarmup() )
{
InternalSetOwner( team, true, 1, &iCappingPlayer );
g_pObjectiveResource->SetOwningTeam( GetPointIndex(), m_iTeam );
}
}
void CControlPoint::SetOwner( int owner, bool bMakeSound, int iNumCappers, int *pCappingPlayers )
{
// Only allow cp caps when round is running ( but not when in warmup )
if( DODGameRules()->State_Get() == STATE_RND_RUNNING &&
!DODGameRules()->IsInWarmup() )
{
InternalSetOwner( owner, bMakeSound, iNumCappers, pCappingPlayers );
g_pObjectiveResource->SetOwningTeam( GetPointIndex(), m_iTeam );
}
}
void CControlPoint::InputShowModel( inputdata_t &input )
{
RemoveEffects( EF_NODRAW );
}
void CControlPoint::InputHideModel( inputdata_t &input )
{
AddEffects( EF_NODRAW );
}
int CControlPoint::GetCurrentHudIconIndex( void )
{
return GetHudIconIndexForTeam( GetOwner() );
}
int CControlPoint::GetHudIconIndexForTeam( int team )
{
int icon = m_iNeutralIcon;
switch( team )
{
case TEAM_ALLIES:
icon = m_iAlliesIcon;
break;
case TEAM_AXIS:
icon = m_iAxisIcon;
break;
case TEAM_UNASSIGNED:
icon = m_iNeutralIcon;
break;
default:
Assert( !"Bad team in GetHudIconIndexForTeam()" );
break;
}
return icon;
}
int CControlPoint::GetTimerCapHudIcon( void )
{
return m_iTimerCapIcon;
}
int CControlPoint::GetBombedHudIcon( void )
{
return m_iBombedIcon;
}
// SetOwner
// ========
// Sets the new owner of the point
// plays the appropriate sound
// and shows the right model
void CControlPoint::InternalSetOwner( int owner, bool bMakeSound, int iNumCappers, int *pCappingPlayers )
{
m_iTeam = owner;
switch ( m_iTeam )
{
case TEAM_UNASSIGNED:
{
if( bMakeSound )
{
CBroadcastRecipientFilter filter;
EmitSound( filter, entindex(), STRING(m_iszResetSound) );
}
SetModel( STRING(m_iszResetModel) );
SetBodygroup( 0, m_iResetModelBodygroup );
m_PointResetOutput.FireOutput( this, this );
}
break;
case TEAM_ALLIES:
{
if( bMakeSound )
{
CBroadcastRecipientFilter filter;
EmitSound( filter, entindex(), STRING(m_iszAlliesCapSound) );
}
SetModel( STRING(m_iszAlliesModel) );
SetBodygroup( 0, m_iAlliesModelBodygroup );
m_AlliesCapOutput.FireOutput( this, this );
}
break;
case TEAM_AXIS:
{
if( bMakeSound )
{
CBroadcastRecipientFilter filter;
EmitSound( filter, entindex(), STRING(m_iszAxisCapSound) );
}
SetModel( STRING(m_iszAxisModel) );
SetBodygroup( 0, m_iAxisModelBodygroup );
m_AxisCapOutput.FireOutput( this, this );
}
break;
default:
Assert(0);
break;
}
if( bMakeSound ) //make sure this is a real cap and not a reset
{
for( int i=0;i<iNumCappers;i++ )
{
int playerIndex = pCappingPlayers[i];
Assert( playerIndex > 0 && playerIndex <= gpGlobals->maxClients );
CDODPlayer *pPlayer = ToDODPlayer( UTIL_PlayerByIndex( playerIndex ) );
Assert( pPlayer );
if ( pPlayer )
{
pPlayer->AddScore( PLAYER_POINTS_FOR_CAP );
pPlayer->Stats_AreaCaptured();
DODGameRules()->Stats_PlayerCap( pPlayer->GetTeamNumber(), pPlayer->m_Shared.DesiredPlayerClass() );
// count bomb plants as point capture
//if ( !m_bSetOwnerIsBombPlant )
{
pPlayer->StatEvent_PointCaptured();
}
}
}
if ( m_iTeam == TEAM_ALLIES )
{
m_OwnerChangedToAllies.FireOutput( this, this );
}
else if ( m_iTeam == TEAM_AXIS )
{
m_OwnerChangedToAxis.FireOutput( this, this );
}
}
if( bMakeSound && m_iTeam != TEAM_UNASSIGNED && iNumCappers > 0 ) //dont print message if its a reset
SendCapString( m_iTeam, iNumCappers, pCappingPlayers );
// have control point master check the win conditions now!
CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "dod_control_point_master" );
while( pEnt )
{
CControlPointMaster *pMaster = dynamic_cast<CControlPointMaster *>( pEnt );
if ( pMaster->IsActive() )
{
pMaster->CheckWinConditions();
}
pEnt = gEntList.FindEntityByClassname( pEnt, "dod_control_point_master" );
}
// Capping the last flag achievement
if ( ( DODGameRules()->State_Get() == STATE_ALLIES_WIN && m_iTeam == TEAM_ALLIES ) ||
( DODGameRules()->State_Get() == STATE_AXIS_WIN && m_iTeam == TEAM_AXIS ) )
{
// limit to flag cap maps
if ( m_iBombsRequired == 0 )
{
for ( int i=0;i<iNumCappers;i++ )
{
CDODPlayer *pDODPlayer = ToDODPlayer( UTIL_PlayerByIndex( pCappingPlayers[i] ) );
if ( pDODPlayer )
{
pDODPlayer->AwardAchievement( ACHIEVEMENT_DOD_CAP_LAST_FLAG );
}
}
}
}
}
void CControlPoint::SendCapString( int team, int iNumCappers, int *pCappingPlayers )
{
if( strlen( STRING(m_iszPrintName) ) <= 0 )
return;
IGameEvent * event = gameeventmanager->CreateEvent( "dod_point_captured" );
if ( event )
{
event->SetInt( "cp", m_iPointIndex );
event->SetString( "cpname", STRING(m_iszPrintName) );
char cappers[9]; // pCappingPlayers is max length 8
int i;
for( i=0;i<iNumCappers;i++ )
{
cappers[i] = (char)pCappingPlayers[i];
}
cappers[i] = '\0';
// pCappingPlayers is a null terminated list of player indeces
event->SetString( "cappers", cappers );
event->SetInt( "priority", 9 );
event->SetBool( "bomb", m_bSetOwnerIsBombPlant );
gameeventmanager->FireEvent( event );
}
}
void CControlPoint::CaptureBlocked( CDODPlayer *pPlayer )
{
if( strlen( STRING(m_iszPrintName) ) <= 0 )
return;
IGameEvent *event = gameeventmanager->CreateEvent( "dod_capture_blocked" );
if ( event )
{
event->SetInt( "cp", m_iPointIndex );
event->SetString( "cpname", STRING(m_iszPrintName) );
event->SetInt( "blocker", pPlayer->entindex() );
event->SetInt( "priority", 9 );
event->SetBool( "bomb", GetBombsRemaining() > 0 );
gameeventmanager->FireEvent( event );
}
pPlayer->AddScore( PLAYER_POINTS_FOR_BLOCK );
if ( GetBombsRemaining() <= 0 ) // no bomb blocks ( kills planter or defuser )
{
pPlayer->StatEvent_CaptureBlocked();
}
pPlayer->Stats_AreaDefended();
DODGameRules()->Stats_PlayerDefended( pPlayer->GetTeamNumber(), pPlayer->m_Shared.DesiredPlayerClass() );
}
// GetOwner
// ========
// returns the current owner
// 2 for allies
// 3 for axis
// 0 if noone owns it
int CControlPoint::GetOwner( void ) const
{
return m_iTeam;
}
int CControlPoint::GetDefaultOwner( void ) const
{
return m_iDefaultOwner;
}
int CControlPoint::GetCPGroup( void )
{
return m_iCPGroup;
}
// PointValue
// ==========
// returns the time-based point value of this control point
int CControlPoint::PointValue( void )
{
// teams earn 0 points for a flag they start with
// after that its 1 additional point for each flag closer to the spawn.
int value = 0;
if ( FBitSet( m_spawnflags, CAP_POINT_TICK_FOR_BOMBS_REMAINING ) )
{
value = m_iBombsRemaining;
}
else if ( GetOwner() == m_iDefaultOwner )
{
value = 0;
}
else
{
if ( GetOwner() == TEAM_ALLIES )
{
value = m_iTimedPointsAllies;
}
else if ( GetOwner() == TEAM_AXIS )
{
value = m_iTimedPointsAxis;
}
}
return value;
}
//precache the necessary models and sounds
void CControlPoint::Precache( void )
{
if ( m_iszAlliesCapSound != NULL_STRING )
{
PrecacheScriptSound( STRING(m_iszAlliesCapSound) );
}
if ( m_iszAxisCapSound != NULL_STRING )
{
PrecacheScriptSound( STRING(m_iszAxisCapSound) );
}
if ( m_iszResetSound != NULL_STRING )
{
PrecacheScriptSound( STRING(m_iszResetSound) );
}
PrecacheModel( STRING( m_iszAlliesModel ) );
PrecacheModel( STRING( m_iszAxisModel ) );
PrecacheModel( STRING( m_iszResetModel ) );
PrecacheMaterial( STRING( m_iszAlliesIcon ) );
m_iAlliesIcon = GetMaterialIndex( STRING( m_iszAlliesIcon ) );
Assert( m_iAlliesIcon != 0 );
PrecacheMaterial( STRING( m_iszAxisIcon ) );
m_iAxisIcon = GetMaterialIndex( STRING( m_iszAxisIcon ) );
Assert( m_iAxisIcon != 0 );
PrecacheMaterial( STRING( m_iszNeutralIcon ) );
m_iNeutralIcon = GetMaterialIndex( STRING( m_iszNeutralIcon ) );
Assert( m_iNeutralIcon != 0 );
if ( strlen( STRING( m_iszTimerCapIcon ) ) > 0 )
{
PrecacheMaterial( STRING( m_iszTimerCapIcon ) );
m_iTimerCapIcon = GetMaterialIndex( STRING( m_iszTimerCapIcon ) );
}
if ( strlen( STRING( m_iszBombedIcon ) ) > 0 )
{
PrecacheMaterial( STRING( m_iszBombedIcon ) );
m_iBombedIcon = GetMaterialIndex( STRING( m_iszBombedIcon ) );
}
if( !m_iNeutralIcon || !m_iAxisIcon || !m_iAlliesIcon )
{
Warning( "Invalid hud icon material in control point ( point index %d )\n", GetPointIndex() );
}
}
// Keyvalue
// ========
// this function interfaces with the keyvalues set by the mapper
//
// Values:
// point_name - the name of the point displayed in the capture string ( and ControlStatus command )
// point_reset_time - time after which the point spontaneously resets - currently not used
// point_default_owner - the owner of this point at the start and after resets
// point_allies_capsound |
// point_axis_capsound | the sounds that are made when the points are capped by each team
// point_resetsound |
//
// point_allies_model |
// point_axis_model | the models that the ent is set to after each team caps it
// point_reset_model |
//point_team_points - number of team points to give to the capper's team for capping
bool CControlPoint::KeyValue( const char *szKeyName, const char *szValue )
{
if (FStrEq(szKeyName, "point_default_owner"))
{
m_iDefaultOwner = atoi(szValue);
Assert( m_iDefaultOwner == TEAM_ALLIES ||
m_iDefaultOwner == TEAM_AXIS ||
m_iDefaultOwner == TEAM_UNASSIGNED );
if( m_iDefaultOwner != TEAM_ALLIES &&
m_iDefaultOwner != TEAM_AXIS &&
m_iDefaultOwner != TEAM_UNASSIGNED )
{
Warning( "dod_control_point with bad point_default_owner - probably '1'\n" );
m_iDefaultOwner = TEAM_UNASSIGNED;
}
}
else if (FStrEq(szKeyName, "point_allies_model_bodygroup"))
{
m_iAlliesModelBodygroup = atoi(szValue);
}
else if (FStrEq(szKeyName, "point_axis_model_bodygroup"))
{
m_iAxisModelBodygroup = atoi(szValue);
}
else if (FStrEq(szKeyName, "point_reset_model_bodygroup"))
{
m_iResetModelBodygroup = atoi(szValue);
}
else if (FStrEq(szKeyName, "point_index"))
{
m_iPointIndex = atoi(szValue);
}
else if (FStrEq(szKeyName, "point_hud_icon_allies"))
{
m_iszAlliesIcon = AllocPooledString(szValue);
}
else if (FStrEq(szKeyName, "point_hud_icon_axis"))
{
m_iszAxisIcon = AllocPooledString(szValue);
}
else if (FStrEq(szKeyName, "point_hud_icon_neutral"))
{
m_iszNeutralIcon = AllocPooledString(szValue);
}
else if (FStrEq(szKeyName, "point_hud_icon_timercap"))
{
m_iszTimerCapIcon = AllocPooledString(szValue);
}
else if (FStrEq(szKeyName, "point_hud_icon_bombed"))
{
m_iszBombedIcon = AllocPooledString(szValue);
}
else
return CBaseEntity::KeyValue( szKeyName, szValue );
return true;
}
void CControlPoint::SetActive( bool active )
{
m_bActive = active;
if( active )
{
RemoveEffects( EF_NODRAW );
}
else
{
AddEffects( EF_NODRAW );
}
}
void CControlPoint::BombPlanted( float flTimerLength, CDODPlayer *pPlantingPlayer )
{
if ( m_bBombPlanted == true )
{
Warning( "ERROR - dod_control_point only supports one bomb being planted at once\n" );
return;
}
//send it to everyone
IGameEvent *event = gameeventmanager->CreateEvent( "dod_bomb_planted" );
if ( event )
{
int iOppositeTeam = ( pPlantingPlayer->GetTeamNumber() == TEAM_ALLIES ) ? TEAM_AXIS : TEAM_ALLIES;
event->SetInt( "team", iOppositeTeam );
event->SetInt( "cp", m_iPointIndex );
event->SetString( "cpname", STRING(m_iszPrintName) );
event->SetInt( "userid", pPlantingPlayer->GetUserID() );
gameeventmanager->FireEvent( event );
}
m_bBombPlanted = true;
m_flBombExplodeTime = gpGlobals->curtime + flTimerLength;
// give the planter a point
pPlantingPlayer->AddScore( PLAYER_POINTS_FOR_BOMB_PLANT );
pPlantingPlayer->StatEvent_BombPlanted();
// set hud display
// this triggers the countdown ( using a shared, constant bomb timer )
g_pObjectiveResource->SetBombPlanted( GetPointIndex(), true );
}
void CControlPoint::BombExploded( CDODPlayer *pPlantingPlayer /* = NULL */, int iPlantingTeam /* = TEAM_UNASSIGNED */ )
{
m_bBombPlanted = false;
m_iBombsRemaining -= 1;
g_pObjectiveResource->SetBombsRemaining( GetPointIndex(), m_iBombsRemaining );
if ( pPlantingPlayer )
{
IGameEvent *event = gameeventmanager->CreateEvent( "dod_bomb_exploded" );
if ( event )
{
event->SetInt( "cp", m_iPointIndex );
event->SetString( "cpname", STRING(m_iszPrintName) );
event->SetInt( "userid", pPlantingPlayer->GetUserID() );
gameeventmanager->FireEvent( event );
}
pPlantingPlayer->Stats_BombDetonated();
int iCappingPlayer = pPlantingPlayer->entindex();
DODGameRules()->CapEvent( CAP_EVENT_BOMB, iPlantingTeam );
if ( m_iBombsRemaining <= 0 )
{
m_bSetOwnerIsBombPlant = true;
InternalSetOwner( iPlantingTeam, true, 1, &iCappingPlayer );
g_pObjectiveResource->SetOwningTeam( GetPointIndex(), GetOwner() );
m_bSetOwnerIsBombPlant = false;
// top up points so it equals PLAYER_POINTS_FOR_BOMB_EXPLODED
pPlantingPlayer->AddScore( PLAYER_POINTS_FOR_BOMB_EXPLODED - PLAYER_POINTS_FOR_CAP );
}
else
{
// give that bomber a point!
pPlantingPlayer->AddScore( PLAYER_POINTS_FOR_BOMB_EXPLODED );
pPlantingPlayer->Stats_AreaCaptured();
pPlantingPlayer->StatEvent_PointCaptured();
// send something to death notices to show that something was accomplished
IGameEvent * event = gameeventmanager->CreateEvent( "dod_point_captured" );
if ( event )
{
event->SetInt( "cp", m_iPointIndex );
event->SetString( "cpname", STRING(m_iszPrintName) );
char cappers[3];
cappers[0] = iCappingPlayer;
cappers[1] = '\0';
// pCappingPlayers is a null terminated list of player indeces
event->SetString( "cappers", cappers );
event->SetInt( "priority", 9 );
event->SetBool( "bomb", true );
gameeventmanager->FireEvent( event );
}
}
}
else
{
if ( m_iBombsRemaining <= 0 )
{
// get the opposite team
int team = ( GetOwner() == TEAM_ALLIES ) ? TEAM_AXIS : TEAM_ALLIES;
InternalSetOwner( team, true );
g_pObjectiveResource->SetOwningTeam( GetPointIndex(), GetOwner() );
}
}
g_pObjectiveResource->SetBombPlanted( GetPointIndex(), false );
}
void CControlPoint::BombDisarmed( CDODPlayer *pDisarmingPlayer )
{
CancelBombPlanted();
CaptureBlocked( pDisarmingPlayer );
IGameEvent *event = gameeventmanager->CreateEvent( "dod_bomb_defused" );
if ( event )
{
event->SetInt( "cp", m_iPointIndex );
event->SetString( "cpname", STRING(m_iszPrintName) );
event->SetInt( "userid", pDisarmingPlayer->GetUserID() );
event->SetInt( "team", pDisarmingPlayer->GetTeamNumber() );
gameeventmanager->FireEvent( event );
}
}
void CControlPoint::CancelBombPlanted( void )
{
m_bBombPlanted = false;
// reset hud display
g_pObjectiveResource->SetBombPlanted( GetPointIndex(), false );
}
+164
View File
@@ -0,0 +1,164 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DOD_CONTROL_POINT_H
#define DOD_CONTROL_POINT_H
#ifdef _WIN32
#pragma once
#endif
#include "dod_player.h"
#define CAP_ICON_ALLIES_FLAG 1
#define CAP_ICON_BRIT_FLAG 27 //from dod_objectives.cpp
#define CAP_POINT_HIDEFLAG (1<<0)
#define CAP_POINT_HIDE_MODEL (1<<1)
#define CAP_POINT_TICK_FOR_BOMBS_REMAINING (1<<2)
#define PLAYER_POINTS_FOR_CAP 1
#define PLAYER_POINTS_FOR_BLOCK 1
#define PLAYER_POINTS_FOR_BOMB_PLANT 1
#define PLAYER_POINTS_FOR_BOMB_EXPLODED 3
class CControlPoint : public CBaseAnimating
{
public:
DECLARE_CLASS( CControlPoint, CBaseAnimating );
DECLARE_DATADESC();
CControlPoint();
virtual void Spawn( void );
virtual bool KeyValue( const char *szKeyName, const char *szValue );
virtual void Precache( void );
void Reset( void );
//Inputs
inline void Enable( inputdata_t &input ) { SetActive( false ); }
inline void Disable( inputdata_t &input ) { SetActive( true ); }
void InputReset( inputdata_t &input );
void InputSetOwner( inputdata_t &input );
void InputShowModel( inputdata_t &input );
void InputHideModel( inputdata_t &input );
int PointValue( void );
void RoundRespawn( void ); //Mugsy - resetting
void TriggerTargets( void );
void SetActive( bool active );
bool PointIsVisible( void ) { return !( FBitSet( m_spawnflags, CAP_POINT_HIDEFLAG ) ); }
void SendCapString( int team, int iNumCappers, int *pCappingPlayers );
void SetOwner( int team, bool bMakeSound = true, int iNumCappers = 0, int *iCappingPlayers = NULL );
int GetOwner( void ) const;
int GetDefaultOwner( void ) const;
inline const char *GetName( void ) { return STRING(m_iszPrintName); }
int GetCPGroup( void );
int GetPointIndex( void ) { return m_iPointIndex; } //the mapper set index
void SetPointIndex( int index ) { m_iPointIndex = index; }
int GetAlliesIcon( void ) { return m_iAlliesIcon; }
int GetAxisIcon( void ) { return m_iAxisIcon; }
int GetNeutralIcon( void ) { return m_iNeutralIcon; }
int GetCurrentHudIconIndex( void );
int GetHudIconIndexForTeam( int team );
int GetTimerCapHudIcon( void );
int GetBombedHudIcon( void );
inline bool IsActive( void ) { return m_bActive; }
void SetNumCappersRequired( int alliesRequired, int axisRequired );
void CaptureBlocked( CDODPlayer *pPlayer );
// Bomb interface
void BombPlanted( float flTimerLength, CDODPlayer *pPlantingPlayer );
void BombExploded( CDODPlayer *pPlantingPlayer = NULL, int iPlantingTeam = TEAM_UNASSIGNED );
void BombDisarmed( CDODPlayer *pDisarmingPlayer );
void CancelBombPlanted( void );
int GetBombsRemaining( void ) { return m_iBombsRemaining; } // total bombs required
int GetBombsRequired( void ) { return m_iBombsRequired; } // number of bombs remaining
private:
void InternalSetOwner( int team, bool bMakeSound = true, int iNumCappers = 0, int *iCappingPlayers = NULL );
int m_iTeam; //0 - clear, 2 - allies, 3 - axis
int m_iDefaultOwner; //team that initially owns the cap point
int m_iIndex; //the index of this point in the controlpointArray
string_t m_iszPrintName;
string_t m_iszAlliesCapSound; //the sound to play on cap
string_t m_iszAxisCapSound;
string_t m_iszResetSound;
string_t m_iszAlliesModel; //models to set the ent to on capture
string_t m_iszAxisModel;
string_t m_iszResetModel;
int m_iAlliesModelBodygroup;//which bodygroup to use in the model
int m_iAxisModelBodygroup;
int m_iResetModelBodygroup;
COutputEvent m_AlliesCapOutput; //outputs to fire when capped
COutputEvent m_AxisCapOutput;
COutputEvent m_PointResetOutput;
COutputEvent m_OwnerChangedToAllies;
COutputEvent m_OwnerChangedToAxis;
int m_iAlliesIcon; //custom hud sprites for cap point
int m_iAxisIcon;
int m_iNeutralIcon;
int m_iTimerCapIcon;
int m_iBombedIcon;
string_t m_iszAlliesIcon;
string_t m_iszAxisIcon;
string_t m_iszNeutralIcon;
string_t m_iszTimerCapIcon;
string_t m_iszBombedIcon;
int m_bPointVisible; //should this capture point be visible on the hud?
int m_iPointIndex; //the mapper set index value of this control point
int m_iCPGroup; //the group that this control point belongs to
bool m_bActive; //
string_t m_iszName; //Name used in cap messages
bool m_bStartDisabled;
int m_iAlliesRequired; // if we're controlled by an area cap,
int m_iAxisRequired; // these hold the number of cappers required. Used to calc point value
int m_iTimedPointsAllies; // timed points value of this flag, per team
int m_iTimedPointsAxis;
bool m_bBombPlanted;
float m_flBombExplodeTime;
int m_iBombsRemaining;
int m_iBombsRequired; // number of bombs required to flip this control point
bool m_bSetOwnerIsBombPlant; // temp flag to indicate if the set owner we're doing is the result of a bomb
private:
CControlPoint( const CControlPoint & );
};
#endif //DOD_CONTROL_POINT_H
@@ -0,0 +1,587 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "dod_control_point_master.h"
BEGIN_DATADESC( CControlPointMaster )
DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ),
DEFINE_KEYFIELD( m_iTimerLength, FIELD_INTEGER, "cpm_timer_length" ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
DEFINE_INPUTFUNC( FIELD_VOID, "RoundInit", InputRoundInit ),
DEFINE_FUNCTION( CPMThink ),
DEFINE_OUTPUT( m_AlliesWinOutput, "OnAlliesWin" ),
DEFINE_OUTPUT( m_AxisWinOutput, "OnAxisWin" ),
DEFINE_INPUTFUNC( FIELD_INTEGER, "AddTimerSeconds", InputAddTimerSeconds ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( dod_control_point_master, CControlPointMaster );
CControlPointMaster::CControlPointMaster()
{
m_bUseTimer = false;
m_iTimerTeam = TEAM_UNASSIGNED;
SetDefLessFunc( m_ControlPoints );
}
void CControlPointMaster::Spawn( void )
{
SetTouch( NULL );
m_bFoundPoints = false;
BaseClass::Spawn();
}
ConVar mp_tickpointinterval( "mp_tickpointinterval", "30", FCVAR_GAMEDLL, "Delay between point gives.", true, 1, false, 0 );
void CControlPointMaster::RoundRespawn( void )
{
m_fGivePointsTime = gpGlobals->curtime + mp_tickpointinterval.GetInt();
}
// KeyValue
// ========
// this function interfaces with the keyvalues set by the mapper
//
// Values
// point_give_delay_time - how often to give time based points ( seconds )
// allies_capture_target - target to fire on allies complete capture
// axis_capture_target - target to fire on axis complete capture
bool CControlPointMaster::KeyValue( const char *szKeyName, const char *szValue )
{
if (FStrEq(szKeyName, "cpm_use_timer"))
{
m_bUseTimer = ( atoi(szValue) > 0 );
}
else if (FStrEq(szKeyName, "cpm_timer_team"))
{
m_iTimerTeam = atoi(szValue);
}
else
{
return CBaseEntity::KeyValue( szKeyName, szValue );
}
return true;
}
void CControlPointMaster::Reset( void )
{
}
bool CControlPointMaster::FindControlPoints( void )
{
//go through all the points
CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "dod_control_point" );
int numFound = 0;
while( pEnt )
{
CControlPoint *pPoint = (CControlPoint *)pEnt;
if( pPoint->IsActive() )
{
int index = pPoint->GetPointIndex();
Assert( index >= 0 );
if( m_ControlPoints.Find( index ) == m_ControlPoints.InvalidIndex())
{
DevMsg( 2, "Adding control point %s with index %d\n", pPoint->GetName(), index );
m_ControlPoints.Insert( index, pPoint );
numFound++;
}
else
{
Warning( "!!!!\nMultiple control points with the same index, duplicates ignored\n!!!!\n" );
UTIL_Remove( pPoint );
}
}
pEnt = gEntList.FindEntityByClassname( pEnt, "dod_control_point" );
}
if( numFound > MAX_CONTROL_POINTS )
{
Warning( "Too many control points! Max is %d\n", MAX_CONTROL_POINTS );
}
//Remap the indeces of the control points so they are 0-based
//======================
unsigned int j;
bool bHandled[MAX_CONTROL_POINTS];
memset( bHandled, 0, sizeof(bHandled) );
unsigned int numPoints = m_ControlPoints.Count();
unsigned int newIndex = 0;
while( newIndex < numPoints )
{
//Find the lowest numbered, unhandled point
int lowestIndex = -1;
int lowestValue = 999;
//find the lowest unhandled index
for( j=0; j<numPoints; j++ )
{
if( !bHandled[j] && m_ControlPoints[j]->GetPointIndex() < lowestValue )
{
lowestIndex = j;
lowestValue = m_ControlPoints[j]->GetPointIndex();
}
}
//Don't examine this point again
Assert( lowestIndex >= 0 );
bHandled[lowestIndex] = true;
//Give it its new index
m_ControlPoints[lowestIndex]->SetPointIndex( newIndex );
newIndex++;
}
if( m_ControlPoints.Count() == 0 )
{
Warning( "Error! No control points found in map!\n");
return false;
}
g_pObjectiveResource->SetNumControlPoints( m_ControlPoints.Count() );
unsigned int i;
for( i=0;i<m_ControlPoints.Count();i++ )
{
CControlPoint *pPoint = m_ControlPoints[i];
int iPointIndex = m_ControlPoints[i]->GetPointIndex();
g_pObjectiveResource->SetOwningTeam( iPointIndex, pPoint->GetOwner() );
g_pObjectiveResource->SetCPVisible( iPointIndex, pPoint->PointIsVisible() );
g_pObjectiveResource->SetCPPosition( iPointIndex, pPoint->GetAbsOrigin() );
g_pObjectiveResource->SetBombsRequired( iPointIndex, pPoint->GetBombsRequired() );
g_pObjectiveResource->SetBombsRemaining( iPointIndex, pPoint->GetBombsRemaining() );
g_pObjectiveResource->SetCPIcons( iPointIndex,
pPoint->GetHudIconIndexForTeam(TEAM_ALLIES),
pPoint->GetHudIconIndexForTeam(TEAM_AXIS),
pPoint->GetHudIconIndexForTeam(TEAM_UNASSIGNED),
pPoint->GetTimerCapHudIcon(),
pPoint->GetBombedHudIcon() );
}
return true;
}
// Think
// =====
// Think is called every 0.1 seconds and checks the status of all the control points
// if one team owns them all, it gives points and resets
// Think also gives the time based points at the specified time intervals
//
// I moved the search for spawn points to the initial think - sometimes the points spawned
// after the master and it wasnt finding them.
void CControlPointMaster::CPMThink( void )
{
// search for all "dod_control_point" entities in the map
// and put them in the array
// only done the first Think
//try to establish if any dod_area_capture ents are linked to our flags
//via dod_point_relay
//if there exists a point relay that has this as the target,
//AND there exists a capture area that has that relay as a target
//then we have our area!
//every think
//go through all the control points and make sure theyre the same as the last think
//check masters
//if they are, do nothing
//else
//
//Note! Only one cpm should ever be active at the same time
//funny things may happen if there are two of em!
//if we are recently mastered on or off, touch the cps
//---------------------------------------------------------------------------
//below here we shouldn't execute unless we are an active control point master
//if the round has been decided, don't do any more thinking
//if this cpm is not active, dont' do any thinking
int iRoundState = DODGameRules()->State_Get();
// No points or triggering new wins if we are not active
if( m_bDisabled || iRoundState != STATE_RND_RUNNING )
{
SetContextThink( &CControlPointMaster::CPMThink, gpGlobals->curtime + 0.2, FLAGS_CONTEXT );
return;
}
// is it time to give time-based points yet?
if( gpGlobals->curtime > m_fGivePointsTime )
{
int AlliesPoints = 0;
int AxisPoints = 0;
//give points based on who owns what
unsigned int i;
for( i=0;i<m_ControlPoints.Count();i++ )
{
switch( m_ControlPoints[i]->GetOwner() )
{
case TEAM_ALLIES:
AlliesPoints += m_ControlPoints[i]->PointValue();
break;
case TEAM_AXIS:
AxisPoints += m_ControlPoints[i]->PointValue();
break;
default:
break;
}
}
//================
//give team points
//================
// See if there are players active on these teams
bool bFoundAllies = ( GetGlobalTeam(TEAM_ALLIES)->GetNumPlayers() > 0 );
bool bFoundAxis = ( GetGlobalTeam(TEAM_AXIS)->GetNumPlayers() > 0 );
bool bReportScore = true;
// don't give team points to a team with no-one on it!
if( AlliesPoints > 0 && bFoundAllies && DODGameRules()->State_Get() == STATE_RND_RUNNING )
{
if( bReportScore )
{
if (AlliesPoints == 1)
UTIL_ClientPrintAll( HUD_PRINTTALK, "#game_score_allie_point" );
else
{
char buf[8];
Q_snprintf( buf, sizeof(buf), "%d", AlliesPoints );
UTIL_ClientPrintAll( HUD_PRINTTALK, "#game_score_allie_points", buf );
}
}
GetGlobalTeam(TEAM_ALLIES)->AddScore( AlliesPoints );
IGameEvent *event = gameeventmanager->CreateEvent( "dod_tick_points" );
if ( event )
{
event->SetInt( "team", TEAM_ALLIES );
event->SetInt( "score", AlliesPoints );
event->SetInt( "totalscore", GetGlobalTeam(TEAM_ALLIES)->GetScore() );
gameeventmanager->FireEvent( event );
}
}
if( AxisPoints > 0 && bFoundAxis && DODGameRules()->State_Get() == STATE_RND_RUNNING )
{
if( bReportScore )
{
if (AxisPoints == 1)
UTIL_ClientPrintAll( HUD_PRINTTALK, "#game_score_axis_point" );
else
{
char buf[8];
Q_snprintf( buf, sizeof(buf), "%d", AxisPoints );
UTIL_ClientPrintAll( HUD_PRINTTALK, "#game_score_axis_points", buf );
}
}
GetGlobalTeam(TEAM_AXIS)->AddScore( AxisPoints );
IGameEvent *event = gameeventmanager->CreateEvent( "dod_tick_points" );
if ( event )
{
event->SetInt( "team", TEAM_AXIS );
event->SetInt( "score", AxisPoints );
event->SetInt( "totalscore", GetGlobalTeam(TEAM_AXIS)->GetScore() );
gameeventmanager->FireEvent( event );
}
}
// the next time we'll give points
m_fGivePointsTime = gpGlobals->curtime + mp_tickpointinterval.GetInt();
}
// If we call this from dod_control_point, this function should never
// trigger a win. but we'll leave it here just incase.
CheckWinConditions();
// the next time we 'think'
SetContextThink( &CControlPointMaster::CPMThink, gpGlobals->curtime + 0.2, FLAGS_CONTEXT );
}
void CControlPointMaster::CheckWinConditions( void )
{
// ============
// Check that the points aren't all held by one team
// if they are this will reset the round
// and will reset all the points
// ============
switch( TeamOwnsAllPoints() )
{
case TEAM_ALLIES: //allies own all
{
TeamWins( TEAM_ALLIES );
}
break;
case TEAM_AXIS: //axis owns all
{
TeamWins( TEAM_AXIS );
}
break;
default:
break;
}
}
void CControlPointMaster::InputRoundInit( inputdata_t &input )
{
//clear out old control points
m_ControlPoints.RemoveAll();
//find the control points
//if successful, do CPMThink
if( FindControlPoints() )
{
SetContextThink( &CControlPointMaster::CPMThink, gpGlobals->curtime + 0.1, FLAGS_CONTEXT );
}
//init the ClientAreas
int index = 0;
CBaseEntity *pEnt = gEntList.FindEntityByClassname( NULL, "dod_capture_area" );
while( pEnt )
{
CAreaCapture *pArea = (CAreaCapture *)pEnt;
Assert( pArea );
pArea->area_SetIndex( index );
index++;
pEnt = gEntList.FindEntityByClassname( pEnt, "dod_capture_area" );
}
g_pObjectiveResource->ResetControlPoints();
}
void CControlPointMaster::FireTeamWinOutput( int iWinningTeam )
{
switch( iWinningTeam )
{
case TEAM_ALLIES:
m_AlliesWinOutput.FireOutput(this,this);
break;
case TEAM_AXIS:
m_AxisWinOutput.FireOutput(this,this);
break;
default:
Assert(0);
break;
}
}
void CControlPointMaster::TeamWins( int iWinningTeam )
{
DODGameRules()->SetWinningTeam( iWinningTeam );
FireTeamWinOutput( iWinningTeam );
}
void CControlPointMaster::BecomeActive( void )
{
Assert( m_bDisabled );
m_bDisabled = false;
}
void CControlPointMaster::BecomeInactive( void )
{
Assert( !m_bDisabled );
m_bDisabled = true;
}
int CControlPointMaster::GetPointOwner( int point )
{
Assert( point >= 0 );
Assert( point < MAX_CONTROL_POINTS );
CControlPoint *pPoint = m_ControlPoints[point];
if( pPoint )
{
return pPoint->GetOwner();
}
else
return TEAM_UNASSIGNED;
}
// TeamOwnsAllPoints
// =================
// This function returns the team that owns all
// the cap points. if its not the case that one
// team owns them all, it returns 0
// New - cps are now broken into groups.
// A team can win by owning all flags within a single group.
// Can be passed an overriding team. If this is not null, the passed team
// number will be used for that cp. Used to predict if that CP changing would
// win the game.
int CControlPointMaster::TeamOwnsAllPoints( CControlPoint *pOverridePoint /* = NULL */, int iOverrideNewTeam /* = TEAM_UNASSIGNED */ )
{
unsigned int i;
int iWinningTeam[MAX_CONTROL_POINT_GROUPS];
for( i=0;i<MAX_CONTROL_POINT_GROUPS;i++ )
{
iWinningTeam[i] = TEAM_INVALID;
}
// if TEAM_INVALID, haven't found a flag for this group yet
// if TEAM_UNASSIGNED, the group is still being contested
// for each control point
for( i=0;i<m_ControlPoints.Count();i++ )
{
int group = m_ControlPoints[i]->GetCPGroup();
int owner = m_ControlPoints[i]->GetOwner();
if ( pOverridePoint == m_ControlPoints[i] )
{
owner = iOverrideNewTeam;
}
// the first one we find in this group, set the win to true
if ( iWinningTeam[group] == TEAM_INVALID )
{
iWinningTeam[group] = owner;
}
// unassigned means this group is already contested, move on
else if ( iWinningTeam[group] == TEAM_UNASSIGNED )
{
continue;
}
// if we find another one in the group that isn't the same owner, set the win to false
else if ( owner != iWinningTeam[group] )
{
iWinningTeam[group] = TEAM_UNASSIGNED;
}
}
// report the first win we find as the winner
for ( i=0;i<MAX_CONTROL_POINT_GROUPS;i++ )
{
if ( iWinningTeam[i] == TEAM_ALLIES || iWinningTeam[i] == TEAM_AXIS )
return iWinningTeam[i];
}
// no wins yet
return TEAM_UNASSIGNED;
}
// an advantage flag is a flag that we've taken that didn't initially
// belong to our team
int CControlPointMaster::CountAdvantageFlags( int team )
{
int numFlags = 0;
unsigned int i;
for( i = 0;i<m_ControlPoints.Count();i++ )
{
CControlPoint *pPoint = m_ControlPoints[i];
if ( pPoint->GetOwner() != pPoint->GetDefaultOwner() )
{
if ( pPoint->GetOwner() == team )
{
// we own a flag we didn't initially
numFlags++;
}
else //
{
// the enemy owns one of our flags
numFlags--;
}
}
}
return numFlags;
}
void CControlPointMaster::InputAddTimerSeconds( inputdata_t &inputdata )
{
DODGameRules()->AddTimerSeconds( inputdata.value.Int() );
}
void CControlPointMaster::GetTimerData( int &iTimerSeconds, int &iTimerWinTeam )
{
iTimerSeconds = m_iTimerLength;
iTimerWinTeam = m_iTimerTeam;
}
bool CControlPointMaster::WouldNewCPOwnerWinGame( CControlPoint *pPoint, int iNewOwner )
{
return ( TeamOwnsAllPoints( pPoint, iNewOwner ) == iNewOwner );
}
int CControlPointMaster::GetNumPoints( void )
{
return m_ControlPoints.Count();
}
CControlPoint *CControlPointMaster::GetCPByIndex( int index )
{
CControlPoint *pPoint = NULL;
if ( index >= 0 && index < (int)m_ControlPoints.Count() )
{
pPoint = m_ControlPoints[index];
}
return pPoint;
}
// custom scoring entity
BEGIN_DATADESC( CDODCustomScoring )
DEFINE_INPUTFUNC( FIELD_INTEGER, "GiveTickPoints", InputGivePoints ),
DEFINE_KEYFIELD( m_iPointTeam, FIELD_INTEGER, "TeamNum" ),
DEFINE_KEYFIELD( m_iTickLength, FIELD_INTEGER, "point_give_delay" ),
DEFINE_KEYFIELD( m_iPointsToGive, FIELD_INTEGER, "point_give_amount" ),
DEFINE_KEYFIELD( m_iNumPointGives, FIELD_INTEGER, "point_give_max_times" ),
DEFINE_THINKFUNC( PointsThink ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( dod_scoring, CDODCustomScoring );
+222
View File
@@ -0,0 +1,222 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DOD_CONTROL_POINT_MASTER_H
#define DOD_CONTROL_POINT_MASTER_H
#ifdef _WIN32
#pragma once
#endif
#include "utlmap.h"
#include "dod_shareddefs.h"
#include "dod_team.h"
#include "dod_gamerules.h"
#include "dod_control_point.h"
#include "dod_area_capture.h"
#include "dod_objective_resource.h"
#include "GameEventListener.h"
// ====================
// Control Point Master
// ====================
// One ControlPointMaster is spawned per level. Shortly after spawning it detects all the Control
// points in the map and puts them into the m_ControlPoints. From there it detects the state
// where all points are captured and resets them if necessary It gives points every time interval to
// the owners of the points
// ====================
#define TIMER_CONTEXT "TIMER_CONTEXT"
#define FLAGS_CONTEXT "FLAGS_CONTEXT"
class CControlPointMaster : public CBaseEntity
{
public:
DECLARE_CLASS( CControlPointMaster, CBaseEntity );
CControlPointMaster();
virtual void Spawn( void );
virtual bool KeyValue( const char *szKeyName, const char *szValue );
int GetNumPoints( void );
int GetPointOwner( int point );
void Reset( void );
void RoundRespawn( void );
int CountAdvantageFlags( int team );
bool IsActive( void ) { return ( m_bDisabled == false ); }
bool IsUsingRoundTimer( void ) { return m_bUseTimer; }
void GetTimerData( int &iTimerSeconds, int &iTimerWinTeam );
void FireTeamWinOutput( int iWinningTeam );
void CheckWinConditions( void );
bool WouldNewCPOwnerWinGame( CControlPoint *pPoint, int iNewOwner );
CControlPoint *GetCPByIndex( int index );
private:
void BecomeActive( void );
void BecomeInactive( void );
void EXPORT CPMThink( void );
int TeamOwnsAllPoints( CControlPoint *pOverridePoint = NULL, int iOverrideNewTeam = TEAM_UNASSIGNED );
void TeamWins( int team );
bool FindControlPoints( void ); //look in the map to find active control points
void InputAddTimerSeconds( inputdata_t &inputdata );
CUtlMap<int, CControlPoint *> m_ControlPoints;
bool m_bFoundPoints; //true when the control points have been found and the array is initialized
float m_fGivePointsTime; //the time at which we give points for holding control points
DECLARE_DATADESC();
bool m_bDisabled; //is this CPM active or not
void InputEnable( inputdata_t &inputdata ) { BecomeInactive(); }
void InputDisable( inputdata_t &inputdata ) { BecomeActive(); }
void InputRoundInit( inputdata_t &inputdata );
void InputRoundStart( inputdata_t &inputdata );
bool m_bUseTimer;
int m_iTimerTeam;
int m_iTimerLength;
COutputEvent m_AlliesWinOutput;
COutputEvent m_AxisWinOutput;
};
class CDODCustomScoring : public CBaseEntity, public CGameEventListener
{
public:
DECLARE_CLASS( CDODCustomScoring, CBaseEntity );
DECLARE_DATADESC();
CDODCustomScoring()
{
ListenForGameEvent( "dod_round_win" );
ListenForGameEvent( "dod_round_active" );
}
virtual void Spawn( void )
{
Assert( m_iPointTeam == TEAM_ALLIES || m_iPointTeam == TEAM_AXIS );
}
virtual void FireGameEvent( IGameEvent *event )
{
const char *eventName = event->GetName();
if ( !Q_strcmp( eventName, "dod_round_win" ) )
{
int team = event->GetInt( "team" );
if ( team == m_iPointTeam )
{
GiveRemainingPoints();
}
// stop giving points, round is over
SetThink( NULL ); // think no more!
}
else if ( !Q_strcmp( eventName, "dod_round_active" ) )
{
StartGivingPoints();
}
}
// Needs to be activated by gamerules
void StartGivingPoints( void )
{
if ( m_iNumPointGives <= 0 )
return;
if ( m_iPointsToGive <= 0 )
return;
m_iRemainingPoints = m_iNumPointGives * m_iPointsToGive;
SetThink( &CDODCustomScoring::PointsThink );
SetNextThink( gpGlobals->curtime + m_iTickLength );
}
// Give this team all the points that they would have gotten had we continued
void GiveRemainingPoints( void )
{
GivePoints( m_iRemainingPoints );
}
// input to give tick points to our team
void InputGivePoints( inputdata_t &inputdata )
{
int iPoints = inputdata.value.Int();
GetGlobalTeam(m_iPointTeam)->AddScore( MAX( iPoints, 0 ) );
}
// accessor for our point team
int GetPointTeam( void )
{
return m_iPointTeam;
}
private:
void GivePoints( int points )
{
GetGlobalTeam(m_iPointTeam)->AddScore( MAX( points, 0 ) );
m_iRemainingPoints -= points;
if ( points > 0 )
{
if ( points == 1 )
{
UTIL_ClientPrintAll( HUD_PRINTTALK, "#game_score_allie_point" );
}
else
{
char buf[8];
Q_snprintf( buf, sizeof(buf), "%d", points );
UTIL_ClientPrintAll( HUD_PRINTTALK, "#game_score_allie_points", buf );
}
IGameEvent *event = gameeventmanager->CreateEvent( "dod_tick_points" );
if ( event )
{
event->SetInt( "team", m_iPointTeam );
event->SetInt( "score", points );
event->SetInt( "totalscore", GetGlobalTeam(m_iPointTeam)->GetScore() );
gameeventmanager->FireEvent( event );
}
}
}
void PointsThink( void )
{
GivePoints( m_iPointsToGive );
SetNextThink( gpGlobals->curtime + m_iTickLength );
}
int m_iPointTeam; // team to give points to
int m_iPointsToGive; // points to give per tick
int m_iRemainingPoints; // total number of points we have left to give
int m_iTickLength; // time between point gives
int m_iNumPointGives; // number of times we're planning on giving out points
};
#endif //DOD_CONTROL_POINT_MASTER_H
+90
View File
@@ -0,0 +1,90 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "dod_cvars.h"
/*
// Gameplay
cvar_t cvar_forcechasecam = {"mp_forcechasecam", "1", FCVAR_SERVER };
cvar_t cvar_forcecamera = {"mp_forcecamera", "1", FCVAR_SERVER };
// Clan cvars
cvar_t cvar_waveTime = {"mp_clan_respawntime", "0", FCVAR_SERVER };
cvar_t cvar_clanRestartRound = {"mp_clan_restartround", "0", FCVAR_SERVER };
cvar_t cvar_clanReadyRestart = {"mp_clan_readyrestart", "0", FCVAR_SERVER };
cvar_t cvar_clanMatchWarmup = {"mp_clan_match_warmup", "0", FCVAR_SERVER };
cvar_t cvar_clanMatch = {"mp_clan_match", "0", FCVAR_SERVER };
cvar_t cvar_clanTimer = {"mp_clan_timer", "20", FCVAR_SERVER };
cvar_t cvar_clanScoring = {"mp_clan_scoring", "0", FCVAR_SERVER };
cvar_t cvar_clanScoringValuesAllies = {"mp_clan_scoring_values_allies", "111111", FCVAR_SERVER };
cvar_t cvar_clanScoringValuesAxis = {"mp_clan_scoring_values_axis", "111111", FCVAR_SERVER };
cvar_t cvar_clanScoringDelay = {"mp_clan_scoring_delay", "60", FCVAR_SERVER };
cvar_t cvar_clanReadyString = {"mp_clan_ready_signal", "ready", FCVAR_SERVER };
cvar_t cvar_clanScoringBonusAllies = {"mp_clan_scoring_bonus_allies", "-1", FCVAR_SERVER };
cvar_t cvar_clanScoringBonusAxis = {"mp_clan_scoring_bonus_axis", "-1", FCVAR_SERVER };
// Other Server Cvars ( Not FCVAR_SERVER! )
//===================
cvar_t cvar_nummapmarkers = {"mp_nummapmarkers", "1" };
cvar_t cvar_markerstaytime = {"mp_markerstaytime", "30"};
cvar_t cvar_teamSpectators = {"mp_allowspectators", "1" };
cvar_t cvar_logScores = {"mp_log_scores", "0" };
cvar_t cvar_logScoresDelay = {"mp_log_scores_delay", "60"};
cvar_t cvar_tkPenalty = {"mp_tkpenalty", "6" };
* now mp_limitteams * cvar_t cvar_teamOver = {"mp_teamlimit", "2" };
cvar_t cvar_deathMsg = {"mp_deathmsg", "1" };
cvar_t cvar_chatMsg = {"mp_chatmsg", "1" };
cvar_t cvar_alliesclasses = {"mp_alliesclasses", "-1"};
cvar_t cvar_axisclasses = {"mp_axisclasses", "-1"};
*/
ConVar mp_winlimit( "mp_winlimit", "0", FCVAR_REPLICATED | FCVAR_NOTIFY, "Max score one team can reach before server changes maps", true, 0, false, 0 );
ConVar mp_clan_restartround( "mp_clan_restartround", "0", FCVAR_GAMEDLL, "If non-zero, the round will restart in the specified number of seconds" );
ConVar mp_limitteams(
"mp_limitteams",
"2",
FCVAR_REPLICATED,
"Max # of players 1 team can have over another",
true, 1, // min value
true, 20 // max value
);
ConVar mp_autokick(
"mp_autokick",
"0",
FCVAR_REPLICATED,
"Kick idle/team-killing players" );
ConVar mp_combinemglimits(
"mp_combinemglimits",
"0",
FCVAR_REPLICATED,
"Set to 1 to combine the class limit cvars for mg34 and mg42. New limit is sum of two" );
// Class limit cvars
// welcome to ugly-town
ConVar mp_limitAlliesRifleman( "mp_limit_allies_rifleman", "-1", FCVAR_REPLICATED, "Class limit for team: Allies class: Rifleman" );
ConVar mp_limitAlliesAssault( "mp_limit_allies_assault", "-1", FCVAR_REPLICATED, "Class limit for team: Allies class: Assault" );
ConVar mp_limitAlliesSupport( "mp_limit_allies_support", "-1", FCVAR_REPLICATED, "Class limit for team: Allies class: Support" );
ConVar mp_limitAlliesSniper( "mp_limit_allies_sniper", "-1", FCVAR_REPLICATED, "Class limit for team: Allies class: Sniper" );
ConVar mp_limitAlliesMachinegun( "mp_limit_allies_mg", "-1", FCVAR_REPLICATED, "Class limit for team: Allies class: Machinegunner" );
ConVar mp_limitAlliesRocket( "mp_limit_allies_rocket", "-1", FCVAR_REPLICATED, "Class limit for team: Allies class: Rocket" );
ConVar mp_limitAxisRifleman( "mp_limit_axis_rifleman", "-1", FCVAR_REPLICATED, "Class limit for team: Axis class: Rifleman" );
ConVar mp_limitAxisAssault( "mp_limit_axis_assault", "-1", FCVAR_REPLICATED, "Class limit for team: Axis class: Assault" );
ConVar mp_limitAxisSupport( "mp_limit_axis_support", "-1", FCVAR_REPLICATED, "Class limit for team: Axis class: Support" );
ConVar mp_limitAxisSniper( "mp_limit_axis_sniper", "-1", FCVAR_REPLICATED, "Class limit for team: Axis class: Sniper" );
ConVar mp_limitAxisMachinegun( "mp_limit_axis_mg", "-1", FCVAR_REPLICATED, "Class limit for team: Axis class: Machinegunner" );
ConVar mp_limitAxisRocket( "mp_limit_axis_rocket", "-1", FCVAR_REPLICATED, "Class limit for team: Axis class: Rocket" );
+42
View File
@@ -0,0 +1,42 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef DOD_CVARS_H
#define DOD_CVARS_H
#ifdef _WIN32
#pragma once
#endif
#define MAX_INTERMISSION_TIME 120
extern ConVar mp_limitteams;
extern ConVar mp_autokick;
extern ConVar mp_clan_restartround;
extern ConVar mp_clan_readyrestart;
extern ConVar mp_clan_ready_signal;
extern ConVar mp_warmup_time;
extern ConVar mp_combinemglimits;
extern ConVar mp_restartwarmup;
extern ConVar mp_cancelwarmup;
extern ConVar mp_winlimit;
extern ConVar mp_limitAlliesRifleman;
extern ConVar mp_limitAlliesAssault;
extern ConVar mp_limitAlliesSupport;
extern ConVar mp_limitAlliesSniper;
extern ConVar mp_limitAlliesMachinegun;
extern ConVar mp_limitAlliesRocket;
extern ConVar mp_limitAxisRifleman;
extern ConVar mp_limitAxisAssault;
extern ConVar mp_limitAxisSupport;
extern ConVar mp_limitAxisSniper;
extern ConVar mp_limitAxisMachinegun;
extern ConVar mp_limitAxisRocket;
#endif //DOD_CVARS_H
+547
View File
@@ -0,0 +1,547 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "../EventLog.h"
#include "team.h"
#include "KeyValues.h"
#include "dod_shareddefs.h"
#include "dod_team.h"
#define LOG_DETAIL_ENEMY_ATTACKS 1
#define LOG_DETAIL_TEAMMATE_ATTACKS 2
ConVar mp_logdetail( "mp_logdetail", "0", FCVAR_NONE, "Logs attacks. Values are: 0=off, 1=enemy, 2=teammate, 3=both)", true, 0.0f, true, 3.0f );
class CDODEventLog : public CEventLog
{
private:
typedef CEventLog BaseClass;
public:
bool PrintEvent( IGameEvent * event ) // override virtual function
{
if ( !PrintDodEvent( event ) ) // allow DOD to override logging
{
return BaseClass::PrintEvent( event );
}
else
{
return true;
}
}
bool Init()
{
BaseClass::Init();
ListenForGameEvent( "player_death" );
ListenForGameEvent( "player_hurt" );
ListenForGameEvent( "player_changeclass" );
ListenForGameEvent( "dod_warmup_begins" );
ListenForGameEvent( "dod_warmup_ends" );
ListenForGameEvent( "dod_round_start" );
ListenForGameEvent( "dod_restart_round" );
ListenForGameEvent( "dod_ready_restart" );
ListenForGameEvent( "dod_allies_ready" );
ListenForGameEvent( "dod_axis_ready" );
ListenForGameEvent( "dod_round_restart_seconds" );
ListenForGameEvent( "dod_team_scores" );
ListenForGameEvent( "dod_round_win" );
ListenForGameEvent( "dod_tick_points" );
ListenForGameEvent( "dod_game_over" );
ListenForGameEvent( "dod_point_captured" );
ListenForGameEvent( "dod_capture_blocked" );
ListenForGameEvent( "dod_bomb_planted" );
ListenForGameEvent( "dod_bomb_exploded" );
ListenForGameEvent( "dod_bomb_defused" );
ListenForGameEvent( "dod_kill_planter" );
ListenForGameEvent( "dod_kill_defuser" );
return true;
}
protected:
bool PrintDodEvent( IGameEvent * event ) // print Mod specific logs
{
const char *eventName = event->GetName();
if ( !Q_strncmp( eventName, "server_", strlen("server_")) )
{
return false; // ignore server_ messages
}
if ( FStrEq( eventName, "player_death" ) )
{
const int userid = event->GetInt( "userid" );
CBasePlayer *pPlayer = UTIL_PlayerByUserId( userid );
if ( !pPlayer )
{
return false;
}
const int attackerid = event->GetInt("attacker" );
const char *weapon = event->GetString( "weapon" );
CBasePlayer *pAttacker = UTIL_PlayerByUserId( attackerid );
if ( pPlayer == pAttacker )
{
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
pPlayer->GetTeam()->GetName(),
weapon
);
}
else if ( pAttacker )
{
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\"\n",
pAttacker->GetPlayerName(),
attackerid,
pAttacker->GetNetworkIDString(),
pAttacker->GetTeam()->GetName(),
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
pPlayer->GetTeam()->GetName(),
weapon
);
}
else
{
// killed by the world
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" committed suicide with \"world\"\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
pPlayer->GetTeam()->GetName()
);
}
// Domination and Revenge
// pAttacker //int attackerid = engine->GetPlayerForUserID( event->GetInt( "attacker" ) );
// pPlayer //int userid = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
if ( event->GetInt( "dominated" ) > 0 && pAttacker )
{
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"domination\" against \"%s<%i><%s><%s>\"\n",
pAttacker->GetPlayerName(),
attackerid,
pAttacker->GetNetworkIDString(),
pAttacker->GetTeam()->GetName(),
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
pPlayer->GetTeam()->GetName()
);
}
if ( event->GetInt( "revenge" ) > 0 && pAttacker )
{
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"revenge\" against \"%s<%i><%s><%s>\"\n",
pAttacker->GetPlayerName(),
attackerid,
pAttacker->GetNetworkIDString(),
pAttacker->GetTeam()->GetName(),
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
pPlayer->GetTeam()->GetName()
);
}
return true;
}
else if ( FStrEq( eventName, "player_hurt" ) )
{
const int userid = event->GetInt( "userid" );
CBasePlayer *pPlayer = UTIL_PlayerByUserId( userid );
if ( !pPlayer )
{
return false;
}
const int attackerid = event->GetInt("attacker" );
const char *weapon = event->GetString( "weapon" );
CBasePlayer *pAttacker = UTIL_PlayerByUserId( attackerid );
if ( !pAttacker )
{
return false;
}
bool isTeamAttack = ( (pPlayer->GetTeamNumber() == pAttacker->GetTeamNumber() ) && (pPlayer != pAttacker) );
int detail = mp_logdetail.GetInt();
if ( ( isTeamAttack && ( detail & LOG_DETAIL_TEAMMATE_ATTACKS ) ) ||
( !isTeamAttack && ( detail & LOG_DETAIL_ENEMY_ATTACKS ) ) )
{
int hitgroup = event->GetInt( "hitgroup" );
const char *hitgroupStr = "GENERIC";
switch ( hitgroup )
{
case HITGROUP_GENERIC:
hitgroupStr = "generic";
break;
case HITGROUP_HEAD:
hitgroupStr = "head";
break;
case HITGROUP_CHEST:
hitgroupStr = "chest";
break;
case HITGROUP_STOMACH:
hitgroupStr = "stomach";
break;
case HITGROUP_LEFTARM:
hitgroupStr = "left arm";
break;
case HITGROUP_RIGHTARM:
hitgroupStr = "right arm";
break;
case HITGROUP_LEFTLEG:
hitgroupStr = "left leg";
break;
case HITGROUP_RIGHTLEG:
hitgroupStr = "right leg";
break;
}
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" attacked \"%s<%i><%s><%s>\" with \"%s\" (damage \"%d\") (health \"%d\") (hitgroup \"%s\")\n",
pAttacker->GetPlayerName(),
attackerid,
pAttacker->GetNetworkIDString(),
pAttacker->GetTeam()->GetName(),
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
pPlayer->GetTeam()->GetName(),
weapon,
event->GetInt( "damage" ),
event->GetInt( "health" ),
hitgroupStr );
}
return true;
}
else if ( FStrEq( eventName, "player_changeclass" ) )
{
const int userid = event->GetInt( "userid" );
CBasePlayer *pPlayer = UTIL_PlayerByUserId( userid );
if ( !pPlayer )
{
return false;
}
int iClass = event->GetInt("class");
int iTeam = pPlayer->GetTeamNumber();
if ( iTeam != TEAM_ALLIES && iTeam != TEAM_AXIS )
return true;
CDODTeam *pTeam = GetGlobalDODTeam( iTeam );
if ( iClass == PLAYERCLASS_RANDOM )
{
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" changed role to \"Random\"\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
pTeam->GetName()
);
}
else if ( iClass < GetGlobalDODTeam(iTeam)->GetNumPlayerClasses() )
{
const CDODPlayerClassInfo &pInfo = GetGlobalDODTeam(iTeam)->GetPlayerClassInfo( iClass );
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" changed role to \"%s\"\n",
pPlayer->GetPlayerName(),
userid,
pPlayer->GetNetworkIDString(),
pTeam->GetName(),
pInfo.m_szPrintName
);
}
return true;
}
else if ( FStrEq( eventName, "dod_warmup_begins" ) )
{
UTIL_LogPrintf( "World triggered \"Warmup_Begin\"\n" );
return true;
}
else if ( FStrEq( eventName, "dod_warmup_ends" ) )
{
UTIL_LogPrintf( "World triggered \"Warmup_Ends\"\n" );
return true;
}
else if ( FStrEq( eventName, "dod_round_start" ) )
{
UTIL_LogPrintf("World triggered \"Round_Start\"\n");
return true;
}
else if ( FStrEq( eventName, "dod_restart_round" ) )
{
UTIL_LogPrintf("World triggered \"Round_Restart\"\n");
return true;
}
else if ( FStrEq( eventName, "dod_ready_restart" ) )
{
UTIL_LogPrintf( "World triggered \"Ready_Restart_Begin\"\n" );
return true;
}
else if ( FStrEq( eventName, "dod_allies_ready" ) )
{
UTIL_LogPrintf("World triggered \"Allies Ready\"\n");
return true;
}
else if ( FStrEq( eventName, "dod_axis_ready" ) )
{
UTIL_LogPrintf("World triggered \"Axis Ready\"\n");
return true;
}
else if ( FStrEq( eventName, "dod_round_restart_seconds" ) )
{
UTIL_LogPrintf( "World triggered \"Round_Restart_In\" (delay \"%d\")\n", event->GetInt("seconds") );
return true;
}
else if ( FStrEq( eventName, "dod_team_scores" ) )
{
int iAlliesRoundsWon = event->GetInt( "allies_caps" );
int iAlliesTickPoints = event->GetInt( "allies_tick" );
int iNumAllies = event->GetInt( "allies_players" );
int iAxisRoundsWon = event->GetInt( "axis_caps" );
int iAxisTickPoints = event->GetInt( "axis_tick" );
int iNumAxis = event->GetInt( "axis_players" );
UTIL_LogPrintf( "Team \"Allies\" triggered \"team_scores\" (roundswon \"%d\") (tickpoints \"%d\") (numplayers \"%d\")\n", iAlliesRoundsWon, iAlliesTickPoints, iNumAllies );
UTIL_LogPrintf( "Team \"Allies\" triggered \"team_scores\" (roundswon \"%d\") (tickpoints \"%d\") (numplayers \"%d\")\n", iAxisRoundsWon, iAxisTickPoints, iNumAxis );
return true;
}
else if ( FStrEq( eventName, "dod_round_win" ) )
{
CDODTeam *pTeam = GetGlobalDODTeam( event->GetInt( "team" ) );
UTIL_LogPrintf( "Team \"%s\" triggered \"round_win\" (rounds_won \"%d\") (numplayers \"%d\")\n",
pTeam->GetName(),
pTeam->GetRoundsWon(),
pTeam->GetNumPlayers() );
return true;
}
else if ( FStrEq( eventName, "dod_tick_points" ) )
{
CDODTeam *pTeam = GetGlobalDODTeam( event->GetInt( "team" ) );
int iScore = event->GetInt( "score" );
int iTotalScore = event->GetInt( "totalscore" );
UTIL_LogPrintf( "Team \"%s\" triggered \"tick_score\" (score \"%i\") (totalscore \"%d\") (numplayers \"%d\")\n",
pTeam->GetName(),
iScore,
iTotalScore,
pTeam->GetNumPlayers() );
return true;
}
else if ( FStrEq( eventName, "dod_game_over" ) )
{
UTIL_LogPrintf( "World triggered \"Game_Over\" reason \"%s\"\n", event->GetString( "reason" ) );
return true;
}
else if ( FStrEq( eventName, "dod_point_captured" ) )
{
// identifier of the area "cp" "cpname"
int iPointIndex = event->GetInt( "cp" );
const char *szPointName = event->GetString( "cpname" );
const char *szCappers = event->GetString( "cappers" );
int iNumCappers = Q_strlen( szCappers );
if ( iNumCappers <= 0 )
return true;
//"Team "Allies" captured location "<3><#map_flag_2nd_axis>" with "2"
// players (1 "Matt<UID><STEAMID><TEAM>") (2 "Player2<2><STEAMID><TEAM>")
char buf[512];
for ( int i=0;i<iNumCappers;i++ )
{
int iPlayerIndex = szCappers[i];
Assert( iPlayerIndex != '\0' && iPlayerIndex > 0 && iPlayerIndex < MAX_PLAYERS );
CBasePlayer *pPlayer = UTIL_PlayerByIndex( iPlayerIndex );
if ( i == 0 )
{
Q_snprintf( buf, sizeof(buf), "Team \"%s\" triggered \"captured_loc\" (flagindex \"%d\") (flagname \"%s\") (numplayers \"%d\") ",
pPlayer->GetTeam()->GetName(),
iPointIndex,
szPointName,
iNumCappers );
}
char playerBuf[256];
Q_snprintf( playerBuf, sizeof(playerBuf), "(player \"%s<%i><%s><%s>\") ",
pPlayer->GetPlayerName(),
pPlayer->GetUserID(),
pPlayer->GetNetworkIDString(),
pPlayer->GetTeam()->GetName() );
Q_strncat( buf, playerBuf, sizeof(buf), COPY_ALL_CHARACTERS );
}
UTIL_LogPrintf( "%s\n", buf );
}
else if ( FStrEq( eventName, "dod_capture_blocked" ) )
{
int iPointIndex = event->GetInt( "cp" );
const char *szPointName = event->GetString( "cpname" );
int iBlocker = event->GetInt( "blocker" );
CBasePlayer *pPlayer = UTIL_PlayerByIndex( iBlocker );
if ( !pPlayer )
return false;
// "Matt<2><UNKNOWN><Allies>" triggered "capblock" (flagindex "2") (flagname "#map_flag_2nd_axis")
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"capblock\" (flagindex \"%d\") (flagname \"%s\")\n",
pPlayer->GetPlayerName(),
pPlayer->GetUserID(),
pPlayer->GetNetworkIDString(),
pPlayer->GetTeam()->GetName(),
iPointIndex,
szPointName );
}
else if ( FStrEq( eventName, "dod_bomb_planted" ) )
{
int iPointIndex = event->GetInt( "cp" );
const char *szPointName = event->GetString( "cpname" );
int iPlanter = event->GetInt( "userid" );
CBasePlayer *pPlayer = UTIL_PlayerByUserId( iPlanter );
if ( !pPlayer )
return false;
// "Matt<2><UNKNOWN><Allies>" triggered "bomb_plant" (flagindex "2") (flagname "#map_flag_2nd_axis")
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"bomb_plant\" (flagindex \"%d\") (flagname \"%s\")\n",
pPlayer->GetPlayerName(),
pPlayer->GetUserID(),
pPlayer->GetNetworkIDString(),
pPlayer->GetTeam()->GetName(),
iPointIndex,
szPointName );
return true;
}
else if ( FStrEq( eventName, "dod_bomb_defused" ) )
{
int iPointIndex = event->GetInt( "cp" );
const char *szPointName = event->GetString( "cpname" );
int iDefuser = event->GetInt( "userid" );
CBasePlayer *pPlayer = UTIL_PlayerByUserId( iDefuser );
if ( !pPlayer )
return false;
// "Matt<2><UNKNOWN><Allies>" triggered "bomb_defuse" (flagindex "2") (flagname "#map_flag_2nd_axis")
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"bomb_defuse\" (flagindex \"%d\") (flagname \"%s\")\n",
pPlayer->GetPlayerName(),
pPlayer->GetUserID(),
pPlayer->GetNetworkIDString(),
pPlayer->GetTeam()->GetName(),
iPointIndex,
szPointName );
return true;
}
else if ( FStrEq( eventName, "dod_kill_planter" ) )
{
int iKiller = event->GetInt( "userid" );
CBasePlayer *pPlayer = UTIL_PlayerByUserId( iKiller );
if ( !pPlayer )
return false;
int iVictim = event->GetInt( "victimid" );
CBasePlayer *pVictim = UTIL_PlayerByUserId( iVictim );
if ( !pVictim )
return false;
// "Matt<2><UNKNOWN><Allies>" triggered "kill_planter" against "Fred<3><UNKNOWN><Axis>"
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"kill_planter\" against \"%s<%i><%s><%s>\"\n",
pPlayer->GetPlayerName(),
pPlayer->GetUserID(),
pPlayer->GetNetworkIDString(),
pPlayer->GetTeam()->GetName(),
pVictim->GetPlayerName(),
pVictim->GetUserID(),
pVictim->GetNetworkIDString(),
pVictim->GetTeam()->GetName() );
return true;
}
else if ( FStrEq( eventName, "dod_kill_defuser" ) )
{
int iKiller = event->GetInt( "userid" );
CBasePlayer *pPlayer = UTIL_PlayerByUserId( iKiller );
if ( !pPlayer )
return false;
int iVictim = event->GetInt( "victimid" );
CBasePlayer *pVictim = UTIL_PlayerByUserId( iVictim );
if ( !pVictim )
return false;
// "Matt<2><UNKNOWN><Allies>" triggered "kill_defuser" against "Fred<3><UNKNOWN><Axis>"
UTIL_LogPrintf( "\"%s<%i><%s><%s>\" triggered \"kill_defuser\" against \"%s<%i><%s><%s>\"\n",
pPlayer->GetPlayerName(),
pPlayer->GetUserID(),
pPlayer->GetNetworkIDString(),
pPlayer->GetTeam()->GetName(),
pVictim->GetPlayerName(),
pVictim->GetUserID(),
pVictim->GetNetworkIDString(),
pVictim->GetTeam()->GetName() );
return true;
}
return false;
}
};
CDODEventLog g_DODEventLog;
//-----------------------------------------------------------------------------
// Singleton access
//-----------------------------------------------------------------------------
IGameSystem* GameLogSystem()
{
return &g_DODEventLog;
}
+30
View File
@@ -0,0 +1,30 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "gameinterface.h"
#include "mapentities.h"
#include "dod_gameinterface.h"
// -------------------------------------------------------------------------------------------- //
// Mod-specific CServerGameClients implementation.
// -------------------------------------------------------------------------------------------- //
void CServerGameClients::GetPlayerLimits( int& minplayers, int& maxplayers, int &defaultMaxPlayers ) const
{
minplayers = 2; // Force multiplayer.
maxplayers = MAX_PLAYERS;
defaultMaxPlayers = 32;
}
// -------------------------------------------------------------------------------------------- //
// Mod-specific CServerGameDLL implementation.
// -------------------------------------------------------------------------------------------- //
void CServerGameDLL::LevelInit_ParseAllEntities( const char *pMapEntities )
{
}
+15
View File
@@ -0,0 +1,15 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DOD_GAMEINTERFACE_H
#define DOD_GAMEINTERFACE_H
#ifdef _WIN32
#pragma once
#endif
#include "gameinterface.h"
#endif // DOD_GAMEINTERFACE_H
+150
View File
@@ -0,0 +1,150 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: dod game stats
//
// $NoKeywords: $
//=============================================================================//
// Some tricky business here - we don't want to include the precompiled header for the statreader
// and trying to #ifdef it out does funky things like ignoring the #endif. Define our header file
// separately and include it based on the switch
#include "cbase.h"
#ifdef GAME_DLL
#include "weapon_dodbase.h"
#endif
#include <tier0/platform.h>
#include "dod_gamestats.h"
int iDistanceStatWeapons[DOD_NUM_DISTANCE_STAT_WEAPONS] =
{
WEAPON_COLT,
WEAPON_P38,
WEAPON_C96,
WEAPON_GARAND,
WEAPON_GARAND_ZOOMED,
WEAPON_M1CARBINE,
WEAPON_K98,
WEAPON_K98_ZOOMED,
WEAPON_SPRING,
WEAPON_SPRING_ZOOMED,
WEAPON_K98_SCOPED,
WEAPON_K98_SCOPED_ZOOMED,
WEAPON_THOMPSON,
WEAPON_MP40,
WEAPON_MP44,
WEAPON_MP44_SEMIAUTO,
WEAPON_BAR,
WEAPON_BAR_SEMIAUTO,
WEAPON_30CAL,
WEAPON_30CAL_UNDEPLOYED,
WEAPON_MG42,
WEAPON_MG42_UNDEPLOYED,
};
// Send hit/shots only for the following weapons
int iNoDistStatWeapons[DOD_NUM_NODIST_STAT_WEAPONS] =
{
WEAPON_AMERKNIFE,
WEAPON_SPADE,
WEAPON_BAZOOKA,
WEAPON_PSCHRECK,
WEAPON_FRAG_US,
WEAPON_FRAG_GER,
WEAPON_FRAG_US_LIVE,
WEAPON_FRAG_GER_LIVE,
WEAPON_RIFLEGREN_US,
WEAPON_RIFLEGREN_GER,
WEAPON_RIFLEGREN_US_LIVE,
WEAPON_RIFLEGREN_GER_LIVE,
WEAPON_THOMPSON_PUNCH,
WEAPON_MP40_PUNCH,
};
int iWeaponBucketDistances[DOD_NUM_WEAPON_DISTANCE_BUCKETS-1] =
{
50,
150,
300,
450,
700,
1000,
1300,
1600,
2000
};
#ifndef GAME_DLL
const char * s_WeaponAliasInfo[] =
{
"none", // WEAPON_NONE = 0,
//Melee
"amerknife", //WEAPON_AMERKNIFE,
"spade", //WEAPON_SPADE,
//Pistols
"colt", //WEAPON_COLT,
"p38", //WEAPON_P38,
"c96", //WEAPON_C96
//Rifles
"garand", //WEAPON_GARAND,
"m1carbine", //WEAPON_M1CARBINE,
"k98", //WEAPON_K98,
//Sniper Rifles
"spring", //WEAPON_SPRING,
"k98_scoped", //WEAPON_K98_SCOPED,
//SMG
"thompson", //WEAPON_THOMPSON,
"mp40", //WEAPON_MP40,
"mp44", //WEAPON_MP44,
"bar", //WEAPON_BAR,
//Machine guns
"30cal", //WEAPON_30CAL,
"mg42", //WEAPON_MG42,
//Rocket weapons
"bazooka", //WEAPON_BAZOOKA,
"pschreck", //WEAPON_PSCHRECK,
//Grenades
"frag_us", //WEAPON_FRAG_US,
"frag_ger", //WEAPON_FRAG_GER,
"frag_us_live", //WEAPON_FRAG_US_LIVE
"frag_ger_live", //WEAPON_FRAG_GER_LIVE
"smoke_us", //WEAPON_SMOKE_US
"smoke_ger", //WEAPON_SMOKE_GER
"riflegren_us", //WEAPON_RIFLEGREN_US
"riflegren_ger", //WEAPON_RIFLEGREN_GER
"riflegren_us_live", //WEAPON_RIFLEGREN_US_LIVE
"riflegren_ger_live", //WEAPON_RIFLEGREN_GER_LIVE
// not actually separate weapons, but defines used in stats recording
"thompson_punch", //WEAPON_THOMPSON_PUNCH
"mp40_punch", //WEAPON_MP40_PUNCH
"garand_zoomed", //WEAPON_GARAND_ZOOMED,
"k98_zoomed", //WEAPON_K98_ZOOMED
"spring_zoomed", //WEAPON_SPRING_ZOOMED
"k98_scoped_zoomed", //WEAPON_K98_SCOPED_ZOOMED
"30cal_undeployed", //WEAPON_30CAL_UNDEPLOYED,
"mg42_undeployed", //WEAPON_MG42_UNDEPLOYED,
"bar_semiauto", //WEAPON_BAR_SEMIAUTO,
"mp44_semiauto", //WEAPON_MP44_SEMIAUTO,
0, // end of list marker
};
#endif
+175
View File
@@ -0,0 +1,175 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: The dod game stats header
//
// $NoKeywords: $
//=============================================================================//
#ifndef DOD_GAMESTATS_H
#define DOD_GAMESTATS_H
#ifdef _WIN32
#pragma once
#endif
// Redefine some things for the stat reader so it doesn't have to include weapon_dodbase.h
#ifndef GAME_DLL
typedef enum
{
WEAPON_NONE = 0,
//Melee
WEAPON_AMERKNIFE,
WEAPON_SPADE,
//Pistols
WEAPON_COLT,
WEAPON_P38,
WEAPON_C96,
//Rifles
WEAPON_GARAND,
WEAPON_M1CARBINE,
WEAPON_K98,
//Sniper Rifles
WEAPON_SPRING,
WEAPON_K98_SCOPED,
//SMG
WEAPON_THOMPSON,
WEAPON_MP40,
WEAPON_MP44,
WEAPON_BAR,
//Machine guns
WEAPON_30CAL,
WEAPON_MG42,
//Rocket weapons
WEAPON_BAZOOKA,
WEAPON_PSCHRECK,
//Grenades
WEAPON_FRAG_US,
WEAPON_FRAG_GER,
WEAPON_FRAG_US_LIVE,
WEAPON_FRAG_GER_LIVE,
WEAPON_SMOKE_US,
WEAPON_SMOKE_GER,
WEAPON_RIFLEGREN_US,
WEAPON_RIFLEGREN_GER,
WEAPON_RIFLEGREN_US_LIVE,
WEAPON_RIFLEGREN_GER_LIVE,
// not actually separate weapons, but defines used in stats recording
// find a better way to do this without polluting the list of actual weapons.
WEAPON_THOMPSON_PUNCH,
WEAPON_MP40_PUNCH,
WEAPON_GARAND_ZOOMED,
WEAPON_K98_ZOOMED,
WEAPON_SPRING_ZOOMED,
WEAPON_K98_SCOPED_ZOOMED,
WEAPON_30CAL_UNDEPLOYED,
WEAPON_MG42_UNDEPLOYED,
WEAPON_BAR_SEMIAUTO,
WEAPON_MP44_SEMIAUTO,
WEAPON_MAX, // number of weapons weapon index
} DODWeaponID;
#endif // ndef WEAPON_NONE
#define DOD_STATS_BLOB_VERSION 2 // changed to 2 for the orange box beta
#define DOD_NUM_DISTANCE_STAT_WEAPONS 22
#define DOD_NUM_NODIST_STAT_WEAPONS 14
#define DOD_NUM_WEAPON_DISTANCE_BUCKETS 10
extern int iDistanceStatWeapons[DOD_NUM_DISTANCE_STAT_WEAPONS];
extern int iNoDistStatWeapons[DOD_NUM_NODIST_STAT_WEAPONS];
extern int iWeaponBucketDistances[DOD_NUM_WEAPON_DISTANCE_BUCKETS-1];
#ifndef GAME_DLL
extern const char * s_WeaponAliasInfo[];
#endif
typedef struct
{
char szGameName[8];
byte iVersion;
char szMapName[32];
char ipAddr[4];
short port;
int serverid;
} gamestats_header_t;
// Stats for bullet weapons - includes distance of hits
typedef struct
{
short iNumAttacks; // times fired
short iNumHits; // times hit
// distance buckets - distances are defined per-weapon ( 0 is closest, buckets-1 farthest )
short iDistanceBuckets[DOD_NUM_WEAPON_DISTANCE_BUCKETS];
} dod_gamestats_weapon_distance_t;
// Stats for non-bullet weapons
typedef struct
{
short iNumAttacks; // times fired
short iNumHits; // times hit
} dod_gamestats_weapon_nodist_t;
typedef struct
{
gamestats_header_t header;
// Team Scores
byte iNumAlliesWins;
byte iNumAxisWins;
short iAlliesTickPoints;
short iAxisTickPoints;
short iMinutesPlayed; // time spent on the map rotation
// Player Data
short iMinutesPlayedPerClass_Allies[7]; // includes random
short iMinutesPlayedPerClass_Axis[7]; // includes random
short iKillsPerClass_Allies[6];
short iKillsPerClass_Axis[6];
short iSpawnsPerClass_Allies[6];
short iSpawnsPerClass_Axis[6];
short iCapsPerClass_Allies[6];
short iCapsPerClass_Axis[6];
byte iDefensesPerClass_Allies[6];
byte iDefensesPerClass_Axis[6];
// Server Settings
// assume these class limits don't change through the course of the map
byte iClassLimits_Allies[6];
byte iClassLimits_Axis[6];
// Weapon Data
dod_gamestats_weapon_distance_t weaponStatsDistance[DOD_NUM_DISTANCE_STAT_WEAPONS]; // 14 * 22 = 308 bytes
dod_gamestats_weapon_nodist_t weaponStats[DOD_NUM_NODIST_STAT_WEAPONS]; // 4 * 14 = 56 bytes
// how many times a weapon was picked up ?
} dod_gamestats_t;
#endif // DOD_GAMESTATS_H
+76
View File
@@ -0,0 +1,76 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "dod_handgrenade.h"
#include "dod_shareddefs.h"
#define GRENADE_MODEL "models/Weapons/w_frag.mdl"
LINK_ENTITY_TO_CLASS( grenade_frag_us, CDODHandGrenade );
PRECACHE_WEAPON_REGISTER( grenade_frag_us );
CDODHandGrenade* CDODHandGrenade::Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
float timer,
DODWeaponID weaponID )
{
CDODHandGrenade *pGrenade = (CDODHandGrenade*)CBaseEntity::Create( "grenade_frag_us", position, angles, pOwner );
Assert( pGrenade );
if( !pGrenade )
return NULL;
IPhysicsObject *pPhysicsObject = pGrenade->VPhysicsGetObject();
if ( pPhysicsObject )
{
pPhysicsObject->AddVelocity( &velocity, &angVelocity );
}
// Who threw this grenade
pGrenade->SetThrower( pOwner );
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
// How long until we explode
pGrenade->SetDetonateTimerLength( timer );
// Save the weapon id for stats purposes
pGrenade->m_EmitterWeaponID = weaponID;
return pGrenade;
}
void CDODHandGrenade::Spawn()
{
SetModel( GRENADE_MODEL );
BaseClass::Spawn();
}
void CDODHandGrenade::Precache()
{
PrecacheModel( GRENADE_MODEL );
PrecacheScriptSound( "HEGrenade.Bounce" );
BaseClass::Precache();
}
void CDODHandGrenade::BounceSound( void )
{
EmitSound( "HEGrenade.Bounce" );
}
//Pass the classname of the exploding version of this grenade.
char *CDODHandGrenade::GetExplodingClassname()
{
return "weapon_frag_us_live";
}
+48
View File
@@ -0,0 +1,48 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DOD_HANDGRENADE_H
#define DOD_HANDGRENADE_H
#ifdef _WIN32
#pragma once
#endif
#include "dod_basegrenade.h"
class CDODHandGrenade : public CDODBaseGrenade
{
public:
DECLARE_CLASS( CDODHandGrenade, CDODBaseGrenade );
// Overrides.
public:
CDODHandGrenade() {}
virtual void Spawn();
virtual void Precache();
virtual void BounceSound( void );
// Grenade stuff.
public:
static CDODHandGrenade* Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
float timer,
DODWeaponID weaponID );
void SetTimer( float timer );
virtual char *GetExplodingClassname();
private:
float m_flDetonateTime;
};
#endif // DOD_HANDGRENADE_H
+140
View File
@@ -0,0 +1,140 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "hltvdirector.h"
class CDODHLTVDirector : public CHLTVDirector
{
public:
DECLARE_CLASS( CDODHLTVDirector, CHLTVDirector );
const char** GetModEvents();
void SetHLTVServer( IHLTVServer *hltv );
void CreateShotFromEvent( CHLTVGameEvent *event );
};
void CDODHLTVDirector::SetHLTVServer( IHLTVServer *hltv )
{
BaseClass::SetHLTVServer( hltv );
if ( m_pHLTVServer )
{
// mod specific events the director uses to find interesting shots
ListenForGameEvent( "dod_point_captured" );
ListenForGameEvent( "dod_capture_blocked" );
}
}
void CDODHLTVDirector::CreateShotFromEvent( CHLTVGameEvent *event )
{
// show event at least for 2 more seconds after it occured
const char *name = event->m_Event->GetName();
IGameEvent *shot = NULL;
if ( !Q_strcmp( "dod_point_captured", name ) ||
!Q_strcmp( "dod_capture_blocked", name ) )
{
// try to find a capper or blocker
const char *text = event->m_Event->GetString("blocker");
int playerIndex = text[0];
if ( playerIndex < 1 )
{
// maybe its a capper ?
text = event->m_Event->GetString("cappers");
playerIndex = text[0];
}
// if we found one, show him
if ( playerIndex > 0 )
{
// shot player as primary, hostage as secondary target
shot = gameeventmanager->CreateEvent( "hltv_chase", true );
shot->SetInt( "target1", playerIndex );
shot->SetInt( "target2", 0 );
shot->SetFloat( "distance", 96.0f );
shot->SetInt( "theta", 0 );
shot->SetInt( "phi", 20 );
// shot 2 seconds after event
m_nNextShotTick = MIN( m_nNextShotTick, (event->m_Tick+TIME_TO_TICKS(2.0)) );
m_iPVSEntity = playerIndex;
}
}
else
{
// let baseclass create a shot
BaseClass::CreateShotFromEvent( event );
return;
}
if ( shot )
{
m_pHLTVServer->BroadcastEvent( shot );
gameeventmanager->FreeEvent( shot );
DevMsg("DrcCmd: %s\n", name );
}
}
const char** CDODHLTVDirector::GetModEvents()
{
// game events relayed to spectator clients
static const char *s_modevents[] =
{
"hltv_status",
"hltv_chat",
"player_connect",
"player_disconnect",
"player_team",
"player_info",
"server_cvar",
"player_death",
"player_chat",
"round_start",
"round_end",
// additional DoD:S events:
"player_changeclass",
"dod_warmup_begins",
"dod_warmup_ends",
"dod_round_start",
"dod_restart_round",
"dod_ready_restart",
"dod_allies_ready",
"dod_axis_ready",
"dod_round_restart_seconds",
"dod_team_scores",
"dod_round_win",
"dod_tick_points",
"dod_game_over",
"dod_broadcast_audio",
"dod_point_captured",
"dod_capture_blocked",
"dod_top_cappers",
"dod_timer_flash",
"dod_bomb_planted",
NULL
};
return s_modevents;
}
static CDODHLTVDirector s_HLTVDirector; // singleton
EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CHLTVDirector, IHLTVDirector, INTERFACEVERSION_HLTVDIRECTOR, s_HLTVDirector );
CHLTVDirector* HLTVDirector()
{
return &s_HLTVDirector;
}
IGameSystem* HLTVDirectorSystem()
{
return &s_HLTVDirector;
}
+29
View File
@@ -0,0 +1,29 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "dod_location.h"
#include "tier0/memdbgon.h"
LINK_ENTITY_TO_CLASS( dod_location, CDODLocation );
void CDODLocation::Spawn( void )
{
BaseClass::Spawn();
}
bool CDODLocation::KeyValue( const char *szKeyName, const char *szValue )
{
if (FStrEq(szKeyName, "location_name")) //name of this location
{
Q_strncpy( m_szLocationName, szValue, sizeof(m_szLocationName) );
}
else
return CBaseEntity::KeyValue( szKeyName, szValue );
return true;
}
+38
View File
@@ -0,0 +1,38 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#ifndef DOD_LOCATION_H
#define DOD_LOCATION_H
#ifdef _WIN32
#pragma once
#endif
#include "baseentity.h"
//a location on the map that players can refernce in their say messages
//with the %l escape sequence
class CDODLocation : public CBaseEntity
{
public:
DECLARE_CLASS( CDODLocation, CBaseEntity );
CDODLocation()
{
m_szLocationName[0] = '\0';
}
virtual void Spawn( void );
virtual bool KeyValue( const char *szKeyName, const char *szValue );
inline const char *GetName( void ) { return m_szLocationName; }
private:
char m_szLocationName[64];
private:
CDODLocation( const CDODLocation & );
};
#endif //DOD_LOCATION_H
+226
View File
@@ -0,0 +1,226 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Entity that propagates general data needed by clients for every player.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "dod_objective_resource.h"
#include "shareddefs.h"
#include <coordsize.h>
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Datatable
IMPLEMENT_SERVERCLASS_ST_NOBASE(CDODObjectiveResource, DT_DODObjectiveResource)
SendPropInt( SENDINFO(m_iNumControlPoints), 4, SPROP_UNSIGNED ),
// data variables
SendPropArray( SendPropVector( SENDINFO_ARRAY(m_vCPPositions), -1, SPROP_COORD), m_vCPPositions ),
SendPropArray3( SENDINFO_ARRAY3(m_bCPIsVisible), SendPropInt( SENDINFO_ARRAY(m_bCPIsVisible), 1, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iAlliesIcons), SendPropInt( SENDINFO_ARRAY(m_iAlliesIcons), 8, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iAxisIcons), SendPropInt( SENDINFO_ARRAY(m_iAxisIcons), 8, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iNeutralIcons), SendPropInt( SENDINFO_ARRAY(m_iNeutralIcons), 8, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iTimerCapIcons), SendPropInt( SENDINFO_ARRAY(m_iTimerCapIcons), 8, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iBombedIcons), SendPropInt( SENDINFO_ARRAY(m_iBombedIcons), 8, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iAlliesReqCappers), SendPropInt( SENDINFO_ARRAY(m_iAlliesReqCappers), 4, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iAxisReqCappers), SendPropInt( SENDINFO_ARRAY(m_iAxisReqCappers), 4, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_flAlliesCapTime), SendPropTime( SENDINFO_ARRAY(m_flAlliesCapTime) ) ),
SendPropArray3( SENDINFO_ARRAY3(m_flAxisCapTime), SendPropTime( SENDINFO_ARRAY(m_flAxisCapTime) ) ),
SendPropArray3( SENDINFO_ARRAY3(m_bBombPlanted), SendPropInt( SENDINFO_ARRAY(m_bBombPlanted), 1, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iBombsRequired), SendPropInt( SENDINFO_ARRAY(m_iBombsRequired), 2, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iBombsRemaining), SendPropInt( SENDINFO_ARRAY(m_iBombsRemaining), 2, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_bBombBeingDefused), SendPropInt( SENDINFO_ARRAY(m_bBombBeingDefused), 1, SPROP_UNSIGNED ) ),
// state variables
SendPropArray3( SENDINFO_ARRAY3(m_iNumAllies), SendPropInt( SENDINFO_ARRAY(m_iNumAllies), 4, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iNumAxis), SendPropInt( SENDINFO_ARRAY(m_iNumAxis), 4, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iCappingTeam), SendPropInt( SENDINFO_ARRAY(m_iCappingTeam), 4, SPROP_UNSIGNED ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iOwner), SendPropInt( SENDINFO_ARRAY(m_iOwner), 4, SPROP_UNSIGNED ) ),
END_SEND_TABLE()
BEGIN_DATADESC( CDODObjectiveResource )
END_DATADESC()
LINK_ENTITY_TO_CLASS( dod_objective_resource, CDODObjectiveResource );
CDODObjectiveResource *g_pObjectiveResource;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODObjectiveResource::Spawn( void )
{
m_iNumControlPoints = 0;
for ( int i=0; i < MAX_CONTROL_POINTS; i++ )
{
// data variables
m_vCPPositions.Set( i, vec3_origin );
m_bCPIsVisible.Set( i, true );
m_iAlliesIcons.Set( i, 0 );
m_iAxisIcons.Set( i, 0 );
m_iNeutralIcons.Set( i, 0 );
m_iTimerCapIcons.Set( i, 0 );
m_iBombedIcons.Set( i, 0 );
m_iAlliesReqCappers.Set( i, 0 );
m_iAxisReqCappers.Set( i, 0 );
m_flAlliesCapTime.Set( i, 0.0f );
m_flAxisCapTime.Set( i, 0.0f );
m_bBombPlanted.Set( i, 0 );
m_iBombsRequired.Set( i, 0 );
m_iBombsRemaining.Set( i, 0 );
m_bBombBeingDefused.Set( i, 0 );
// state variables
m_iNumAllies.Set( i, 0 );
m_iNumAxis.Set( i, 0 );
m_iCappingTeam.Set( i, TEAM_UNASSIGNED );
m_iOwner.Set( i, TEAM_UNASSIGNED );
}
}
//-----------------------------------------------------------------------------
// Purpose: The objective resource is always transmitted to clients
//-----------------------------------------------------------------------------
int CDODObjectiveResource::UpdateTransmitState()
{
// ALWAYS transmit to all clients.
return SetTransmitState( FL_EDICT_ALWAYS );
}
//-----------------------------------------------------------------------------
// Purpose: Round is starting, reset state
//-----------------------------------------------------------------------------
void CDODObjectiveResource::ResetControlPoints( void )
{
for ( int i=0; i < MAX_CONTROL_POINTS; i++ )
{
m_iNumAllies.Set( i, 0 );
m_iNumAxis.Set( i, 0 );
m_iCappingTeam.Set( i, TEAM_UNASSIGNED );
m_bBombPlanted.Set( i, 0 );
m_bBombBeingDefused.Set( i, 0 );
}
}
//-----------------------------------------------------------------------------
// Purpose: Data setting functions
//-----------------------------------------------------------------------------
void CDODObjectiveResource::SetNumControlPoints( int num )
{
Assert( num <= MAX_CONTROL_POINTS );
m_iNumControlPoints = num;
}
void CDODObjectiveResource::SetCPIcons( int index, int iAlliesIcon, int iAxisIcon, int iNeutralIcon, int iTimerCapIcon, int iBombedIcon )
{
AssertValidIndex(index);
m_iAlliesIcons.Set( index, iAlliesIcon);
m_iAxisIcons.Set( index, iAxisIcon );
m_iNeutralIcons.Set( index, iNeutralIcon );
m_iTimerCapIcons.Set( index, iTimerCapIcon );
m_iBombedIcons.Set( index, iBombedIcon );
}
void CDODObjectiveResource::SetCPPosition( int index, const Vector& vPosition )
{
AssertValidIndex(index);
m_vCPPositions.Set( index, vPosition );
}
void CDODObjectiveResource::SetCPVisible( int index, bool bVisible )
{
AssertValidIndex(index);
m_bCPIsVisible.Set( index, bVisible );
}
void CDODObjectiveResource::SetCPRequiredCappers( int index, int iReqAllies, int iReqAxis )
{
AssertValidIndex(index);
m_iAlliesReqCappers.Set( index, iReqAllies );
m_iAxisReqCappers.Set( index, iReqAxis );
}
void CDODObjectiveResource::SetCPCapTime( int index, float flAlliesCapTime, float flAxisCapTime )
{
AssertValidIndex(index);
m_flAlliesCapTime.Set( index, flAlliesCapTime );
m_flAxisCapTime.Set( index, flAxisCapTime );
}
//-----------------------------------------------------------------------------
// Purpose: Data setting functions
//-----------------------------------------------------------------------------
void CDODObjectiveResource::SetNumPlayers( int index, int team, int iNumPlayers )
{
AssertValidIndex(index);
switch( team )
{
case TEAM_ALLIES:
m_iNumAllies.Set( index, iNumPlayers );
break;
case TEAM_AXIS:
m_iNumAxis.Set( index, iNumPlayers );
break;
default:
Assert( 0 );
break;
}
}
void CDODObjectiveResource::StartCap( int index, int team )
{
AssertValidIndex(index);
m_iCappingTeam.Set( index, team );
}
void CDODObjectiveResource::SetOwningTeam( int index, int team )
{
AssertValidIndex(index);
m_iOwner.Set( index, team );
// clear the capper
m_iCappingTeam.Set( index, TEAM_UNASSIGNED );
}
void CDODObjectiveResource::SetCappingTeam( int index, int team )
{
AssertValidIndex(index);
m_iCappingTeam.Set( index, team );
}
void CDODObjectiveResource::SetBombPlanted( int index, bool bPlanted )
{
AssertValidIndex(index);
m_bBombPlanted.Set( index, bPlanted );
}
void CDODObjectiveResource::SetBombBeingDefused( int index, bool bBeingDefused )
{
AssertValidIndex(index);
m_bBombBeingDefused.Set( index, bBeingDefused );
}
void CDODObjectiveResource::SetBombsRequired( int index, int iBombsRequired )
{
AssertValidIndex(index);
m_iBombsRequired.Set( index, iBombsRequired );
}
void CDODObjectiveResource::SetBombsRemaining( int index, int iBombsRemaining )
{
AssertValidIndex(index);
m_iBombsRemaining.Set( index, iBombsRemaining );
}
+86
View File
@@ -0,0 +1,86 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: DOD's objective resource, transmits all objective states to players
//
// $NoKeywords: $
//=============================================================================//
#ifndef DOD_OBJECTIVE_RESOURCE_H
#define DOD_OBJECTIVE_RESOURCE_H
#ifdef _WIN32
#pragma once
#endif
#include "dod_shareddefs.h"
class CDODObjectiveResource : public CBaseEntity
{
DECLARE_CLASS( CDODObjectiveResource, CBaseEntity );
public:
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
virtual void Spawn( void );
virtual int UpdateTransmitState(void);
void ResetControlPoints( void );
// Data functions, called to set up the state at the beginning of a round
void SetNumControlPoints( int num );
void SetCPIcons( int index, int iAlliesIcon, int iAxisIcon, int iNeutralIcon, int iTimerCapIcon, int iBombedIcon );
void SetCPPosition( int index, const Vector& vPosition );
void SetCPVisible( int index, bool bVisible );
void SetCPRequiredCappers( int index, int iReqAllies, int iReqAxis );
void SetCPCapTime( int index, float flAlliesCapTime, float flAxisCapTime );
// State functions, called many times
void SetNumPlayers( int index, int team, int iNumPlayers );
void StartCap( int index, int team );
void SetOwningTeam( int index, int team );
void SetCappingTeam( int index, int team );
void SetBombPlanted( int index, bool bPlanted );
void SetBombsRequired( int index, int iBombsRequired );
void SetBombsRemaining( int index, int iBombsRemaining );
void SetBombBeingDefused( int index, bool bBeingDefused );
void AssertValidIndex( int index )
{
Assert( 0 <= index && index <= MAX_CONTROL_POINTS && index < m_iNumControlPoints );
}
private:
CNetworkVar( int, m_iNumControlPoints );
// data variables
CNetworkArray( Vector, m_vCPPositions, MAX_CONTROL_POINTS );
CNetworkArray( int, m_bCPIsVisible, MAX_CONTROL_POINTS );
CNetworkArray( int, m_iAlliesIcons, MAX_CONTROL_POINTS );
CNetworkArray( int, m_iAxisIcons, MAX_CONTROL_POINTS );
CNetworkArray( int, m_iNeutralIcons, MAX_CONTROL_POINTS );
CNetworkArray( int, m_iTimerCapIcons, MAX_CONTROL_POINTS );
CNetworkArray( int, m_iBombedIcons, MAX_CONTROL_POINTS );
CNetworkArray( int, m_iAlliesReqCappers,MAX_CONTROL_POINTS );
CNetworkArray( int, m_iAxisReqCappers, MAX_CONTROL_POINTS );
CNetworkArray( float, m_flAlliesCapTime, MAX_CONTROL_POINTS );
CNetworkArray( float, m_flAxisCapTime, MAX_CONTROL_POINTS );
CNetworkArray( int, m_bBombPlanted, MAX_CONTROL_POINTS );
CNetworkArray( int, m_iBombsRequired, MAX_CONTROL_POINTS );
CNetworkArray( int, m_iBombsRemaining, MAX_CONTROL_POINTS );
CNetworkArray( int, m_bBombBeingDefused,MAX_CONTROL_POINTS );
// state variables
// change when players enter/exit an area
CNetworkArray( int, m_iNumAllies, MAX_CONTROL_POINTS );
CNetworkArray( int, m_iNumAxis, MAX_CONTROL_POINTS );
// changes when a cap starts. start and end times are calculated on client
CNetworkArray( int, m_iCappingTeam, MAX_CONTROL_POINTS );
// changes when a point is successfully captured
CNetworkArray( int, m_iOwner, MAX_CONTROL_POINTS );
};
extern CDODObjectiveResource *g_pObjectiveResource;
#endif //DOD_OBJECTIVE_RESOURCE_H
File diff suppressed because it is too large Load Diff
+661
View File
@@ -0,0 +1,661 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Player for HL1.
//
// $NoKeywords: $
//=============================================================================//
#ifndef DOD_PLAYER_H
#define DOD_PLAYER_H
#pragma once
#include "basemultiplayerplayer.h"
#include "server_class.h"
#include "dod_playeranimstate.h"
#include "dod_shareddefs.h"
#include "dod_player_shared.h"
#include "unisignals.h"
#include "dod_statmgr.h"
#include "utlmap.h"
#include "steam/steam_gameserver.h"
#include "hintsystem.h"
// Function table for each player state.
class CDODPlayerStateInfo
{
public:
DODPlayerState m_iPlayerState;
const char *m_pStateName;
void (CDODPlayer::*pfnEnterState)(); // Init and deinit the state.
void (CDODPlayer::*pfnLeaveState)();
void (CDODPlayer::*pfnPreThink)(); // Do a PreThink() in this state.
};
class CDODPlayer;
//=======================================
//Record of either damage taken or given.
//Contains the player name that we hurt or that hurt us,
//and the total damage
//=======================================
class CDamageRecord
{
public:
CDamageRecord( const char *pszName, int iLifeID, int iDamage )
{
Q_strncpy( m_szPlayerName, pszName, MAX_PLAYER_NAME_LENGTH );
m_iDamage = iDamage;
m_iNumHits = 1;
m_iLifeID = iLifeID;
}
void AddDamage( int iDamage )
{
m_iDamage += iDamage;
m_iNumHits++;
}
char *GetPlayerName( void ) { return m_szPlayerName; }
int GetDamage( void ) { return m_iDamage; }
int GetNumHits( void ) { return m_iNumHits; }
int GetLifeID( void ) { return m_iLifeID; }
private:
char m_szPlayerName[MAX_PLAYER_NAME_LENGTH];
int m_iLifeID; // life ID of the player when this damage was done
int m_iDamage; //how much damage was done
int m_iNumHits; //how many hits
};
#define SIGNAL_CAPTUREAREA (1<<0)
class CDODBombTarget;
class CDODPlayerStatProperty
{
DECLARE_CLASS_NOBASE( CDODPlayerStatProperty );
public:
CDODPlayerStatProperty()
{
m_iCurrentLifePlayerClass = -1;
m_bRecordingStats = false;
ResetPerLifeStats();
}
~CDODPlayerStatProperty() {}
void SetClassAndTeamForThisLife( int iPlayerClass, int iTeam );
void IncrementPlayerClassStat( DODStatType_t statType, int iValue = 1 );
void IncrementWeaponStat( DODWeaponID iWeaponID, DODStatType_t statType, int iValue = 1 );
// reset per life stats
void ResetPerLifeStats( void );
// send this life's worth of data to the client
void SendStatsToPlayer( CDODPlayer *pPlayer );
private:
bool m_bRecordingStats; // not recording until we get a valid class. stop recording when we join spectator
int m_iCurrentLifePlayerClass;
int m_iCurrentLifePlayerTeam;
// single life's worth of player stats
dod_stat_accumulator_t m_PlayerStatsPerLife;
// single life's worth of weapon stats
dod_stat_accumulator_t m_WeaponStatsPerLife[WEAPON_MAX];
bool m_bWeaponStatsDirty[WEAPON_MAX];
};
//=============================================================================
// >> Day of Defeat player
//=============================================================================
class CDODPlayer : public CBaseMultiplayerPlayer
{
public:
DECLARE_CLASS( CDODPlayer, CBaseMultiplayerPlayer );
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
CDODPlayer();
~CDODPlayer();
static CDODPlayer *CreatePlayer( const char *className, edict_t *ed );
static CDODPlayer* Instance( int iEnt );
// This passes the event to the client's and server's CPlayerAnimState.
void DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 );
void SetupBones( matrix3x4_t *pBoneToWorld, int boneMask );
virtual void Precache();
void PrecachePlayerModel( const char *szPlayerModel );
virtual void Spawn();
virtual void InitialSpawn( void );
virtual void CheatImpulseCommands( int iImpulse );
virtual void PlayerRunCommand( CUserCmd *ucmd, IMoveHelper *moveHelper );
virtual void PreThink();
virtual void PostThink();
virtual int OnTakeDamage( const CTakeDamageInfo &inputInfo );
virtual int OnTakeDamage_Alive( const CTakeDamageInfo &info );
virtual void Event_Killed( const CTakeDamageInfo &info );
virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator );
void Pain( void );
void OnDamagedByExplosion( const CTakeDamageInfo &info );
void OnDamageByStun( const CTakeDamageInfo &info );
void DeafenThink( void );
virtual void UpdateGeigerCounter( void ) {}
virtual void CheckTrainUpdate( void ) {}
virtual void CreateViewModel( int viewmodelindex = 0 );
virtual bool SetObserverMode(int mode); // sets new observer mode, returns true if successful
virtual bool ModeWantsSpectatorGUI( int iMode ) { return ( iMode != OBS_MODE_DEATHCAM && iMode != OBS_MODE_FREEZECAM ); }
// from CBasePlayer
void SetupVisibility( CBaseEntity *pViewEntity, unsigned char *pvs, int pvssize );
CBaseEntity* EntSelectSpawnPoint();
void ChangeTeam( int iTeamNum );
bool CanMove( void ) const;
virtual void SharedSpawn();
void CheckProneMoveSound( int groundspeed, bool onground );
virtual void UpdateStepSound( surfacedata_t *psurface, const Vector &vecOrigin, const Vector &vecVelocity );
virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force );
virtual const Vector GetPlayerMins( void ) const; // uses local player
virtual const Vector GetPlayerMaxs( void ) const; // uses local player
void DODRespawn( void );
virtual void SetAnimation( PLAYER_ANIM playerAnim );
CBaseEntity * GiveNamedItem( const char *pszName, int iSubType = 0 );
bool Weapon_CanSwitchTo( CBaseCombatWeapon *pWeapon );
void SetScore( int score );
void AddScore( int num );
int GetScore( void ) { return m_iScore; }
int m_iScore;
// Simulates a single frame of movement for a player
void RunPlayerMove( const QAngle& viewangles, float forwardmove, float sidemove, float upmove, unsigned short buttons, byte impulse, float frametime );
//Damage record functions
void RecordDamageTaken( CDODPlayer *pAttacker, int iDamageTaken );
void RecordWorldDamageTaken( int iDamageTaken );
void RecordDamageGiven( CDODPlayer *pVictim, int iDamageGiven );
void ResetDamageCounters(); //Reset all lists
void OutputDamageTaken( void );
void OutputDamageGiven( void );
// Voice Commands
//============
void HandleCommand_Voice( const char *pcmd ); // player submitted a raw voice_ command
void HandleCommand_HandSignal( const char *pcmd ); // player wants to show a hand signal
void VoiceCommand( int iVoiceCommand ); // internal voice command function
void HandSignal( int iSignal ); // same for hand signals
float m_flNextVoice;
float m_flNextHandSignal;
void PopHelmet( Vector vecDir, Vector vecForceOrigin );
bool DropActiveWeapon( void );
bool DropPrimaryWeapon( void );
bool DODWeaponDrop( CBaseCombatWeapon *pWeapon, bool bThrowForward );
bool BumpWeapon( CBaseCombatWeapon *pBaseWeapon );
CWeaponDODBase* GetActiveDODWeapon() const;
virtual void AttemptToExitFreezeCam( void );
//Generic Ammo
//============
void DropGenericAmmo( void );
void ReturnGenericAmmo( void );
bool GiveGenericAmmo( void );
bool m_bHasGenericAmmo;
void ResetBleeding( void );
void Bandage( void ); // stops the bleeding
void SetBandager( CDODPlayer *pPlayer );
bool IsBeingBandaged( void );
EHANDLE m_hBandager;
//Area Signals
//============
//to determine if the player is in a sandbag trigger
CUnifiedSignals m_signals; // Player signals (buy zone, bomb zone, etc.)
int m_iCapAreaIconIndex; //which area's icon to show - we are not necessarily capping it.
int m_iObjectAreaIndex; //if the player is in an object cap area, which one?
void SetCapAreaIndex( int index );
int GetCapAreaIndex( void );
void ClearCapAreaIndex() { SetCapAreaIndex(-1); }
void SetCPIndex( int index );
float m_fHandleSignalsTime; //time to next check the area signals
void HandleSignals( void ); //check if signals need to do anything, like turn icons on or off
bool ShouldAutoReload( void ) { return m_bAutoReload; }
void SetAutoReload( bool bAutoReload ) { m_bAutoReload = bAutoReload; }
bool ShouldAutoRezoom( void ) { return m_bAutoRezoom; }
void SetAutoRezoom( bool bAutoRezoom ) { m_bAutoRezoom = bAutoRezoom; }
// Hints
virtual CHintSystem *Hints( void ) { return &m_Hints; }
// Reset all scores
void ResetScores( void );
int GetHealthAsString( char *pDest, int iDestSize );
int GetLastPlayerIDAsString( char *pDest, int iDestSize );
int GetClosestPlayerHealthAsString( char *pDest, int iDestSize );
int GetPlayerClassAsString( char *pDest, int iDestSize );
int GetNearestLocationAsString( char *pDest, int iDestSize );
int GetTimeleftAsString( char *pDest, int iDestSize );
int GetStringForEscapeSequence( char c, char *pDest, int iDestSize );
virtual void CheckChatText( char *p, int bufsize );
void PushawayThink();
void DestroyRagdoll( void );
virtual bool CanHearChatFrom( CBasePlayer *pPlayer );
virtual void CommitSuicide( bool bExplode = false, bool bForce = false );
virtual void CommitSuicide( const Vector &vecForce, bool bExplode = false, bool bForce = false );
virtual bool StartReplayMode( float fDelay, float fDuration, int iEntity );
virtual void StopReplayMode();
void PickUpWeapon( CWeaponDODBase *pWeapon );
int GetPriorityForPickUpEnt( CBaseEntity *pEnt );
virtual CBaseEntity *FindUseEntity();
virtual void ComputeWorldSpaceSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs );
bool ShouldCollide( int collisionGroup, int contentsMask ) const;
void SetDeathFlags( int iDeathFlags ) { m_iDeathFlags = iDeathFlags; }
int GetDeathFlags() { return m_iDeathFlags; }
void RemoveNemesisRelationships();
virtual void OnAchievementEarned( int iAchievement );
void RecalculateAchievementAwardsMask();
bool ShouldInstantRespawn( void );
void StatEvent_UploadStats( void );
void StatEvent_KilledPlayer( DODWeaponID iKillingWeapon );
void StatEvent_WasKilled( void );
void StatEvent_RoundWin( void );
void StatEvent_RoundLoss( void );
void StatEvent_PointCaptured( void );
void StatEvent_CaptureBlocked( void );
void StatEvent_BombPlanted( void );
void StatEvent_BombDefused( void );
void StatEvent_ScoredDomination( void );
void StatEvent_ScoredRevenge( void );
void StatEvent_WeaponFired( DODWeaponID iWeaponID );
void StatEvent_WeaponHit( DODWeaponID iWeaponID, bool bWasHeadshot );
// ------------------------------------------------------------------------------------------------ //
// Player state management.
// ------------------------------------------------------------------------------------------------ //
public:
void State_Transition( DODPlayerState newState );
DODPlayerState State_Get() const; // Get the current state.
void MoveToNextIntroCamera(); //Cycle view through available intro cameras
bool ClientCommand( const CCommand &args );
virtual bool IsReadyToPlay( void );
void FireBullets( const FireBulletsInfo_t &info );
bool CanAttack( void );
void SetBazookaDeployed( bool bDeployed ) { m_bBazookaDeployed = bDeployed; }
// from cbasecombatcharacter
virtual void InitVCollision( const Vector &vecAbsOrigin, const Vector &vecAbsVelocity );
virtual void VPhysicsShadowUpdate( IPhysicsObject *pPhysics );
void DeathSound( const CTakeDamageInfo &info );
Activity TranslateActivity( Activity baseAct, bool *pRequired = NULL );
CNetworkVar( float, m_flStunDuration );
CNetworkVar( float, m_flStunMaxAlpha );
// Stats Functions
void Stats_WeaponFired( int weaponID );
void Stats_WeaponHit( CDODPlayer *pVictim, int weaponID, int iDamage, int iDamageGiven, int hitgroup, float flHitDistance );
void Stats_HitByWeapon( CDODPlayer *pAttacker, int weaponID, int iDamage, int iDamageGiven, int hitgroup );
void Stats_KilledPlayer( CDODPlayer *pVictim, int weaponID );
void Stats_KilledByPlayer( CDODPlayer *pAttacker, int weaponID );
void Stats_AreaDefended( void );
void Stats_AreaCaptured( void );
void Stats_BonusRoundKill( void );
void Stats_BombDetonated( void );
void PrintLifetimeStats( void );
// Called whenever this player fires a shot.
void NoteWeaponFired();
virtual bool WantsLagCompensationOnEntity( const CBasePlayer *pPlayer, const CUserCmd *pCmd, const CBitVec<MAX_EDICTS> *pEntityTransmitBits ) const;
void TallyLatestTimePlayedPerClass( int iOldTeam, int iOldClass );
void ResetProgressBar( void );
void SetProgressBarTime( int barTime );
void StoreCaptureBlock( int iAreaIndex, int iCapAttempt );
int GetLastBlockCapAttempt( void );
int GetLastBlockAreaIndex( void );
public:
CNetworkVarEmbedded( CDODPlayerShared, m_Shared );
int m_flNextTimeCheck; // Next time the player can execute a "timeleft" command
Vector m_lastStandingPos; // used by the gamemovement code for finding ladders
void SetSprinting( bool bIsSprinting );
void SetDefusing( CDODBombTarget *pTarget );
bool m_bIsDefusing;
CHandle<CDODBombTarget> m_pDefuseTarget;
void SetPlanting( CDODBombTarget *pTarget );
bool m_bIsPlanting;
CHandle<CDODBombTarget> m_pPlantTarget;
// Achievements
void HandleHeadshotAchievement( int iNumHeadshots );
void HandleDeployedMGKillCount( int iNumDeployedKills );
int GetDeployedKillStreak( void );
void HandleEnemyWeaponsAchievement( int iNumEnemyWpnKills );
void ResetComboWeaponKill( void );
void HandleComboWeaponKill( int iWeaponType );
virtual void PlayUseDenySound();
int iNumKilledByUnanswered[MAX_PLAYERS+1]; // how many unanswered kills this player has been dealt by every other player
#if !defined(NO_STEAM)
STEAM_GAMESERVER_CALLBACK( CDODPlayer, OnGSStatsReceived, GSStatsReceived_t, m_CallbackGSStatsReceived );
#endif
private:
bool SelectSpawnSpot( const char *pEntClassName, CBaseEntity* &pSpot );
CBaseEntity *SelectSpawnSpot( CUtlVector<EHANDLE> *pSpawnPoints, int &iLastSpawnIndex );
// Copyed from EyeAngles() so we can send it to the client.
CNetworkQAngle( m_angEyeAngles );
IDODPlayerAnimState *m_PlayerAnimState;
int FlashlightIsOn( void );
void FlashlightTurnOn( void );
void FlashlightTurnOff( void );
void ShowClassSelectMenu();
void CheckRotateIntroCam( void );
void State_Enter( DODPlayerState newState ); // Initialize the new state.
void State_Leave(); // Cleanup the previous state.
void State_PreThink(); // Update the current state.
// Specific state handler functions.
void State_Enter_WELCOME();
void State_PreThink_WELCOME();
void State_Enter_PICKINGTEAM();
void State_Enter_PICKINGCLASS();
void State_PreThink_PICKING();
void State_Enter_ACTIVE();
void State_PreThink_ACTIVE();
void State_Enter_OBSERVER_MODE();
void State_PreThink_OBSERVER_MODE();
void State_Enter_DEATH_ANIM();
void State_PreThink_DEATH_ANIM();
virtual void PlayerDeathThink();
// When the player joins, it cycles their view between trigger_camera entities.
// This is the current camera, and the time that we'll switch to the next one.
EHANDLE m_pIntroCamera;
float m_fIntroCamTime;
// Find the state info for the specified state.
static CDODPlayerStateInfo* State_LookupInfo( DODPlayerState state );
// This tells us which state the player is currently in (joining, observer, dying, etc).
// Each state has a well-defined set of parameters that go with it (ie: observer is movetype_noclip, non-solid,
// invisible, etc).
CNetworkVar( DODPlayerState, m_iPlayerState );
// Tracks our ragdoll entity.
CNetworkHandle( CBaseEntity, m_hRagdoll ); // networked entity handle
float m_flLastMovement; // Time the player last moved, used for mp_autokick
void InitProne( void );
void InitSprinting( void );
bool IsSprinting( void );
bool CanSprint( void );
int m_iDeathFlags; // death notice flags related to domination/revenge
CNetworkVar( int, m_iAchievementAwardsMask );
protected:
void CreateRagdollEntity();
void PhysObjectSleep();
void PhysObjectWake();
private:
friend void Bot_Think( CDODPlayer *pBot ); // needs to use the HandleCommand_ stuff.
bool HandleCommand_JoinTeam( int iTeam );
bool HandleCommand_JoinClass( int iClass );
CDODPlayerStateInfo *m_pCurStateInfo; // This can be NULL if no state info is defined for m_iPlayerState.
bool m_bTeamChanged; //have we changed teams this spawn? Used to enforce one team switch per death rule
float m_flNextStaminaThink; //time to do next stamina gain
CNetworkVar( float, m_flStamina ); //stamina for sprinting, jumping etc
Vector m_vecTotalBulletForce; //Accumulator for bullet force in a single frame
bool m_bBazookaDeployed;
//A list of damage given
CUtlLinkedList< CDamageRecord *, int > m_DamageGivenList;
//A list of damage taken
CUtlLinkedList< CDamageRecord *, int > m_DamageTakenList;
bool m_bSlowedByHit;
float m_flUnslowTime;
int m_iPlayerSpeed; //last updated player max speed
bool SetSpeed( int speed );
bool m_bAutoReload; // does the player want to autoreload their weapon when empty
bool m_bAutoRezoom; // does the player want to re-zoom after each shot for sniper rifles and bazookas
float m_flIdleTime; // next time we should do a deep idle
bool m_bIsSprinting;
CNetworkVar( bool, m_bSpawnInterpCounter );
CHintSystem m_Hints;
float m_flMinNextStepSoundTime;
int m_LastHitGroup; // the last body region that took damage
int m_LastDamageType; // the type of damage we last took
bool m_bPlayingProneMoveSound;
int m_iCapAreaIndex;
// Last usercmd we shot a bullet on.
int m_iLastWeaponFireUsercmd;
CNetworkVar( float, m_flProgressBarStartTime );
CNetworkVar( int, m_iProgressBarDuration );
// blocking abuse protection
int m_iLastBlockAreaIndex;
int m_iLastBlockCapAttempt;
// Achievements Data
int m_iComboWeaponKillMask;
bool m_bAbortFreezeCam;
bool m_bPlayedFreezeCamSound;
CDODPlayerStatProperty m_StatProperty;
EHANDLE m_hLastDroppedWeapon;
EHANDLE m_hLastDroppedAmmoBox;
float m_flTimeAsClassAccumulator;
public:
// LifeID is a unique int assigned to a player each time they spawn
int GetLifeID() { return m_iLifeID; }
int m_iLifeID;
// Stats variables
//==================
// stats related to each weapon ( shots taken and given )
weaponstat_t m_WeaponStats[MAX_WEAPONS];
// a list of players I have killed ( by userid )
CUtlMap<int, playerstat_t, int> m_KilledPlayers;
// a list of players that have killed me ( by userid )
CUtlMap<int, playerstat_t, int> m_KilledByPlayers;
// start time - used to calc total time played
// time played per class
float m_flTimePlayedPerClass_Allies[7]; //0-5, 6 is random
float m_flTimePlayedPerClass_Axis[7]; //0-5, 6 is random
float m_flLastClassChangeTime;
// area cap stats
int m_iNumAreaDefenses;
int m_iNumAreaCaptures;
int m_iNumBonusRoundKills;
// Per-Round Stats
//================
virtual void ResetPerRoundStats( void )
{
m_iPerRoundCaptures = 0;
m_iPerRoundDefenses = 0;
m_iPerRoundBombsDetonated = 0;
m_iPerRoundKills = 0;
}
int GetPerRoundCaps( void )
{
return m_iPerRoundCaptures;
}
int GetPerRoundDefenses( void )
{
return m_iPerRoundDefenses;
}
int GetPerRoundBombsDetonated( void )
{
return m_iPerRoundBombsDetonated;
}
int GetPerRoundKills( void )
{
return m_iPerRoundKills;
}
int m_iPerRoundCaptures; // how many caps this round
int m_iPerRoundDefenses; // how many defenses this round
int m_iPerRoundBombsDetonated;
int m_iPerRoundKills;
};
inline CDODPlayer *ToDODPlayer( CBaseEntity *pEntity )
{
if ( !pEntity || !pEntity->IsPlayer() )
return NULL;
#ifdef _DEBUG
Assert( dynamic_cast<CDODPlayer*>( pEntity ) != 0 );
#endif
return static_cast< CDODPlayer* >( pEntity );
}
inline DODPlayerState CDODPlayer::State_Get() const
{
return m_iPlayerState;
}
#endif //DOD_PLAYER_H
+63
View File
@@ -0,0 +1,63 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: DOD's custom CPlayerResource
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "dod_player.h"
#include "player_resource.h"
#include "dod_player_resource.h"
#include <coordsize.h>
// Datatable
IMPLEMENT_SERVERCLASS_ST(CDODPlayerResource, DT_DODPlayerResource)
SendPropArray3( SENDINFO_ARRAY3(m_iObjScore), SendPropInt( SENDINFO_ARRAY(m_iObjScore), 12 ) ),
SendPropArray3( SENDINFO_ARRAY3(m_iPlayerClass), SendPropInt( SENDINFO_ARRAY(m_iPlayerClass), 4 ) ),
END_SEND_TABLE()
BEGIN_DATADESC( CDODPlayerResource )
// DEFINE_ARRAY( m_iObjScore, FIELD_INTEGER, MAX_PLAYERS+1 ),
// DEFINE_ARRAY( m_iPlayerClass, FIELD_INTEGER, MAX_PLAYERS+1 ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( dod_player_manager, CDODPlayerResource );
CDODPlayerResource::CDODPlayerResource( void )
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDODPlayerResource::UpdatePlayerData( void )
{
int i;
for ( i = 1; i <= gpGlobals->maxClients; i++ )
{
CDODPlayer *pPlayer = (CDODPlayer*)UTIL_PlayerByIndex( i );
if ( pPlayer && pPlayer->IsConnected() )
{
m_iObjScore.Set( i, pPlayer->GetScore() );
m_iPlayerClass.Set( i, pPlayer->m_Shared.PlayerClass() );
}
}
BaseClass::UpdatePlayerData();
}
void CDODPlayerResource::Spawn( void )
{
int i;
for ( i=0; i < MAX_PLAYERS+1; i++ )
{
m_iObjScore.Set( i, 0 );
m_iPlayerClass.Set( i, PLAYERCLASS_UNDEFINED );
}
BaseClass::Spawn();
}
+32
View File
@@ -0,0 +1,32 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: DOD's custom CPlayerResource
//
// $NoKeywords: $
//=============================================================================//
#ifndef DOD_PLAYER_RESOURCE_H
#define DOD_PLAYER_RESOURCE_H
#ifdef _WIN32
#pragma once
#endif
class CDODPlayerResource : public CPlayerResource
{
DECLARE_CLASS( CDODPlayerResource, CPlayerResource );
public:
DECLARE_SERVERCLASS();
DECLARE_DATADESC();
CDODPlayerResource();
virtual void UpdatePlayerData( void );
virtual void Spawn( void );
protected:
CNetworkArray( int, m_iObjScore, MAX_PLAYERS+1 );
CNetworkArray( int, m_iPlayerClass, MAX_PLAYERS+1 );
};
#endif // DOD_PLAYER_RESOURCE_H
+80
View File
@@ -0,0 +1,80 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "player_command.h"
#include "igamemovement.h"
#include "in_buttons.h"
#include "ipredictionsystem.h"
#include "dod_player.h"
static CMoveData g_MoveData;
CMoveData *g_pMoveData = &g_MoveData;
IPredictionSystem *IPredictionSystem::g_pPredictionSystems = NULL;
//-----------------------------------------------------------------------------
// Sets up the move data for TF2
//-----------------------------------------------------------------------------
class CDODPlayerMove : public CPlayerMove
{
DECLARE_CLASS( CDODPlayerMove, CPlayerMove );
public:
//virtual void StartCommand( CBasePlayer *player, CUserCmd *cmd );
virtual void SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move );
virtual void FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move );
};
// PlayerMove Interface
static CDODPlayerMove g_PlayerMove;
//-----------------------------------------------------------------------------
// Singleton accessor
//-----------------------------------------------------------------------------
CPlayerMove *PlayerMove()
{
return &g_PlayerMove;
}
//-----------------------------------------------------------------------------
// Main setup, finish
//-----------------------------------------------------------------------------
/*
void CDODPlayerMove::StartCommand( CBasePlayer *player, CUserCmd *cmd )
{
BaseClass::StartCommand( player, cmd );
}
*/
//-----------------------------------------------------------------------------
// Purpose: This is called pre player movement and copies all the data necessary
// from the player for movement. (Server-side, the client-side version
// of this code can be found in prediction.cpp.)
//-----------------------------------------------------------------------------
void CDODPlayerMove::SetupMove( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper *pHelper, CMoveData *move )
{
player->AvoidPhysicsProps( ucmd );
BaseClass::SetupMove( player, ucmd, pHelper, move );
}
//-----------------------------------------------------------------------------
// Purpose: This is called post player movement to copy back all data that
// movement could have modified and that is necessary for future
// movement. (Server-side, the client-side version of this code can
// be found in prediction.cpp.)
//-----------------------------------------------------------------------------
void CDODPlayerMove::FinishMove( CBasePlayer *player, CUserCmd *ucmd, CMoveData *move )
{
// Call the default FinishMove code.
BaseClass::FinishMove( player, ucmd, move );
}
+72
View File
@@ -0,0 +1,72 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "dod_riflegrenade_ger.h"
#include "dod_shareddefs.h"
#define GRENADE_MODEL "models/Weapons/w_k98_rg_grenade.mdl"
LINK_ENTITY_TO_CLASS( grenade_riflegren_ger, CDODRifleGrenadeGER );
PRECACHE_WEAPON_REGISTER( grenade_riflegren_ger );
IMPLEMENT_SERVERCLASS_ST( CDODRifleGrenadeGER, DT_DODRifleGrenadeGER )
END_SEND_TABLE()
CDODRifleGrenadeGER* CDODRifleGrenadeGER::Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
float timer,
DODWeaponID weaponID )
{
CDODRifleGrenadeGER *pGrenade = (CDODRifleGrenadeGER*)CBaseEntity::Create( "grenade_riflegren_ger", position, angles, pOwner );
Assert( pGrenade );
if( !pGrenade )
return NULL;
IPhysicsObject *pPhysicsObject = pGrenade->VPhysicsGetObject();
if ( pPhysicsObject )
{
pPhysicsObject->AddVelocity( &velocity, &angVelocity );
}
// Who threw this grenade
pGrenade->SetThrower( pOwner );
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
// How long until we explode
pGrenade->SetDetonateTimerLength( timer );
// Save the weapon id for stats purposes
pGrenade->m_EmitterWeaponID = weaponID;
return pGrenade;
}
void CDODRifleGrenadeGER::Spawn()
{
SetModel( GRENADE_MODEL );
BaseClass::Spawn();
}
void CDODRifleGrenadeGER::Precache()
{
PrecacheModel( GRENADE_MODEL );
PrecacheScriptSound( "HEGrenade.Bounce" );
BaseClass::Precache();
}
//Pass the classname of the exploding version of this grenade.
char *CDODRifleGrenadeGER::GetExplodingClassname()
{
return "weapon_riflegren_ger_live";
}
+49
View File
@@ -0,0 +1,49 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DOD_RIFLEGRENADE_GER_H
#define DOD_RIFLEGRENADE_GER_H
#ifdef _WIN32
#pragma once
#endif
#include "dod_basegrenade.h"
class CDODRifleGrenadeGER : public CDODBaseGrenade
{
public:
DECLARE_CLASS( CDODRifleGrenadeGER, CDODBaseGrenade );
DECLARE_SERVERCLASS();
// Overrides
public:
CDODRifleGrenadeGER() {}
virtual void Spawn();
virtual void Precache();
// Grenade stuff.
public:
static CDODRifleGrenadeGER* Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
float timer,
DODWeaponID weaponID );
virtual char *GetExplodingClassname();
virtual float GetElasticity() { return 0.05; }
private:
float m_flDetonateTime;
};
#endif // DOD_RIFLEGRENADE_GER_H
+72
View File
@@ -0,0 +1,72 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "dod_riflegrenade_us.h"
#include "dod_shareddefs.h"
#define GRENADE_MODEL "models/Weapons/w_garand_rg_grenade.mdl"
LINK_ENTITY_TO_CLASS( grenade_riflegren_us, CDODRifleGrenadeUS );
PRECACHE_WEAPON_REGISTER( grenade_riflegren_us );
IMPLEMENT_SERVERCLASS_ST( CDODRifleGrenadeUS, DT_DODRifleGrenadeUS )
END_SEND_TABLE()
CDODRifleGrenadeUS* CDODRifleGrenadeUS::Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
float timer,
DODWeaponID weaponID )
{
CDODRifleGrenadeUS *pGrenade = (CDODRifleGrenadeUS*)CBaseEntity::Create( "grenade_riflegren_us", position, angles, pOwner );
Assert( pGrenade );
if( !pGrenade )
return NULL;
IPhysicsObject *pPhysicsObject = pGrenade->VPhysicsGetObject();
if ( pPhysicsObject )
{
pPhysicsObject->AddVelocity( &velocity, &angVelocity );
}
// Who threw this grenade
pGrenade->SetThrower( pOwner );
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
// How long until we explode
pGrenade->SetDetonateTimerLength( timer );
// Save the weapon id for stats purposes
pGrenade->m_EmitterWeaponID = weaponID;
return pGrenade;
}
void CDODRifleGrenadeUS::Spawn()
{
SetModel( GRENADE_MODEL );
BaseClass::Spawn();
}
void CDODRifleGrenadeUS::Precache()
{
PrecacheModel( GRENADE_MODEL );
PrecacheScriptSound( "HEGrenade.Bounce" );
BaseClass::Precache();
}
//Pass the classname of the exploding version of this grenade.
char *CDODRifleGrenadeUS::GetExplodingClassname()
{
return "weapon_riflegren_us_live";
}
+49
View File
@@ -0,0 +1,49 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DOD_RIFLEGRENADE_US_H
#define DOD_RIFLEGRENADE_US_H
#ifdef _WIN32
#pragma once
#endif
#include "dod_basegrenade.h"
class CDODRifleGrenadeUS : public CDODBaseGrenade
{
public:
DECLARE_CLASS( CDODRifleGrenadeUS, CDODBaseGrenade );
DECLARE_NETWORKCLASS();
// Overrides.
public:
CDODRifleGrenadeUS() {}
virtual void Spawn();
virtual void Precache();
// Grenade stuff.
public:
static CDODRifleGrenadeUS* Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
float timer,
DODWeaponID weaponID );
virtual char *GetExplodingClassname();
virtual float GetElasticity() { return 0.05; }
private:
float m_flDetonateTime;
};
#endif // DOD_RIFLEGRENADE_US_H
+121
View File
@@ -0,0 +1,121 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "dod_smokegrenade.h"
#include "particle_parse.h"
LINK_ENTITY_TO_CLASS( grenade_smoke, CDODSmokeGrenade );
PRECACHE_WEAPON_REGISTER( grenade_smoke );
BEGIN_DATADESC( CDODSmokeGrenade )
DEFINE_THINKFUNC( Think_Emit ),
DEFINE_THINKFUNC( Think_Fade ),
DEFINE_THINKFUNC( Think_Remove )
END_DATADESC()
IMPLEMENT_SERVERCLASS_ST( CDODSmokeGrenade, DT_DODSmokeGrenade )
SendPropTime(SENDINFO(m_flSmokeSpawnTime) ),
END_SEND_TABLE()
void CDODSmokeGrenade::Spawn()
{
BaseClass::Spawn();
SetThink( &CDODSmokeGrenade::Think_Emit );
SetNextThink( gpGlobals->curtime + 0.5 );
m_bInitialSmoke = false;
m_flRemoveTime = -1;
m_flSmokeSpawnTime = 0;
}
void CDODSmokeGrenade::Precache()
{
PrecacheScriptSound( "SmokeGrenade.Bounce" );
PrecacheParticleSystem( "smokegrenade" );
PrecacheParticleSystem( "smokegrenade_jet" );
BaseClass::Precache();
}
void CDODSmokeGrenade::BounceSound( void )
{
EmitSound( "SmokeGrenade.Bounce" );
}
void CDODSmokeGrenade::Think_Emit( void )
{
// if we're stationary and have not yet created smoke, do so now
Vector vel;
AngularImpulse a;
VPhysicsGetObject()->GetVelocity( &vel, &a );
if ( vel.Length() < 15.0 && !m_bInitialSmoke )
{
VPhysicsGetObject()->EnableMotion( false );
// Smoke Cloud
DispatchParticleEffect( "smokegrenade", GetAbsOrigin(), vec3_angle );
// Smoke Jet
DispatchParticleEffect( "smokegrenade_jet", PATTACH_POINT, this, "jet" );
EmitSound( "BaseSmokeEffect.Sound" );
m_flRemoveTime = gpGlobals->curtime + 10;
m_bInitialSmoke = true;
m_flSmokeSpawnTime = gpGlobals->curtime;
}
// if its past our bedtime, fade out
if ( m_flRemoveTime > 0 && gpGlobals->curtime > m_flRemoveTime )
{
m_nRenderMode = kRenderTransColor;
SetThink( &CDODSmokeGrenade::Think_Fade );
}
SetNextThink( gpGlobals->curtime + 0.1 );
}
// Fade the projectile out over time before making it disappear
void CDODSmokeGrenade::Think_Fade()
{
m_bFading = true;
SetNextThink( gpGlobals->curtime );
color32 c = GetRenderColor();
c.a -= 1;
SetRenderColor( c.r, c.b, c.g, c.a );
if ( !c.a )
{
SetModelName( NULL_STRING );//invisible
SetNextThink( gpGlobals->curtime + 10 );
SetThink( &CDODSmokeGrenade::Think_Remove ); // Spit out smoke for 10 seconds.
SetSolid( SOLID_NONE );
}
}
void CDODSmokeGrenade::Think_Remove()
{
// stop all effects
StopParticleEffects( this );
SetModelName( NULL_STRING );//invisible
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
UTIL_Remove( this );
}
void CDODSmokeGrenade::Detonate( void )
{
// Intentionally blank - our detonate does nothing
}
+42
View File
@@ -0,0 +1,42 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DOD_SMOKEGRENADE_H
#define DOD_SMOKEGRENADE_H
#ifdef _WIN32
#pragma once
#endif
#include "dod_basegrenade.h"
class CDODSmokeGrenade : public CDODBaseGrenade
{
public:
DECLARE_CLASS( CDODSmokeGrenade, CDODBaseGrenade );
DECLARE_DATADESC();
DECLARE_SERVERCLASS();
virtual void Spawn();
virtual void Precache();
virtual void BounceSound( void );
virtual void Detonate();
virtual bool CanBePickedUp( void ) { return false; }
void Think_Emit();
void Think_Fade();
void Think_Remove();
private:
bool m_bFading;
bool m_bInitialSmoke;
float m_flRemoveTime;
CNetworkVar( float, m_flSmokeSpawnTime );
};
#endif // DOD_SMOKEGRENADE_H
+53
View File
@@ -0,0 +1,53 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "dod_smokegrenade_ger.h"
#define GRENADE_MODEL "models/Weapons/w_smoke_ger.mdl"
LINK_ENTITY_TO_CLASS( grenade_smoke_ger, CDODSmokeGrenadeGER );
PRECACHE_WEAPON_REGISTER( grenade_smoke_ger );
CDODSmokeGrenadeGER* CDODSmokeGrenadeGER::Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner )
{
CDODSmokeGrenadeGER *pGrenade = (CDODSmokeGrenadeGER*)CBaseEntity::Create( "grenade_smoke_ger", position, angles, pOwner );
Assert( pGrenade );
if( !pGrenade )
return NULL;
IPhysicsObject *pPhysicsObject = pGrenade->VPhysicsGetObject();
if ( pPhysicsObject )
{
pPhysicsObject->AddVelocity( &velocity, &angVelocity );
}
// Who threw this grenade
pGrenade->SetThrower( pOwner );
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
return pGrenade;
}
void CDODSmokeGrenadeGER::Spawn()
{
SetModel( GRENADE_MODEL );
BaseClass::Spawn();
}
void CDODSmokeGrenadeGER::Precache()
{
PrecacheModel( GRENADE_MODEL );
BaseClass::Precache();
}
+38
View File
@@ -0,0 +1,38 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DOD_SMOKEGRENADE_GER_H
#define DOD_SMOKEGRENADE_GER_H
#ifdef _WIN32
#pragma once
#endif
#include "dod_smokegrenade.h"
class CDODSmokeGrenadeGER : public CDODSmokeGrenade
{
public:
DECLARE_CLASS( CDODSmokeGrenadeGER, CDODSmokeGrenade );
// Overrides.
public:
CDODSmokeGrenadeGER() {}
virtual void Spawn();
virtual void Precache();
// Grenade stuff.
public:
static CDODSmokeGrenadeGER* Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner );
virtual DODWeaponID GetEmitterWeaponID() { return WEAPON_SMOKE_GER; }
};
#endif // DOD_SMOKEGRENADE_GER_H
+53
View File
@@ -0,0 +1,53 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "dod_smokegrenade_us.h"
#define GRENADE_MODEL "models/Weapons/w_smoke_us.mdl"
LINK_ENTITY_TO_CLASS( grenade_smoke_us, CDODSmokeGrenadeUS );
PRECACHE_WEAPON_REGISTER( grenade_smoke_us );
CDODSmokeGrenadeUS* CDODSmokeGrenadeUS::Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner )
{
CDODSmokeGrenadeUS *pGrenade = (CDODSmokeGrenadeUS*)CBaseEntity::Create( "grenade_smoke_us", position, angles, pOwner );
Assert( pGrenade );
if( !pGrenade )
return NULL;
IPhysicsObject *pPhysicsObject = pGrenade->VPhysicsGetObject();
if ( pPhysicsObject )
{
pPhysicsObject->AddVelocity( &velocity, &angVelocity );
}
// Who threw this grenade
pGrenade->SetThrower( pOwner );
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
return pGrenade;
}
void CDODSmokeGrenadeUS::Spawn()
{
SetModel( GRENADE_MODEL );
BaseClass::Spawn();
}
void CDODSmokeGrenadeUS::Precache()
{
PrecacheModel( GRENADE_MODEL );
BaseClass::Precache();
}
+38
View File
@@ -0,0 +1,38 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DOD_SMOKEGRENADE_US_H
#define DOD_SMOKEGRENADE_US_H
#ifdef _WIN32
#pragma once
#endif
#include "dod_smokegrenade.h"
class CDODSmokeGrenadeUS : public CDODSmokeGrenade
{
public:
DECLARE_CLASS( CDODSmokeGrenadeUS, CDODSmokeGrenade );
// Overrides.
public:
CDODSmokeGrenadeUS() {}
virtual void Spawn();
virtual void Precache();
// Grenade stuff.
public:
static CDODSmokeGrenadeUS* Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner );
virtual DODWeaponID GetEmitterWeaponID() { return WEAPON_SMOKE_US; }
};
#endif // DOD_SMOKEGRENADE_US_H
+82
View File
@@ -0,0 +1,82 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Handle stats game events and route them to the appropriate place
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "KeyValues.h"
#include "dod_statmgr.h"
#include "dod_player.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CDODStatManager::CDODStatManager()
{
}
bool CDODStatManager::Init()
{
ListenForGameEvent( "player_death" );
ListenForGameEvent( "dod_stats_weapon_attack" );
ListenForGameEvent( "dod_stats_player_damage" );
ListenForGameEvent( "dod_stats_player_killed" );
return BaseClass::Init();
}
void CDODStatManager::FireGameEvent( IGameEvent *event )
{
const char *eventName = event->GetName();
if ( FStrEq( eventName, "dod_stats_weapon_attack" ) )
{
CDODPlayer *pAttacker = ToDODPlayer( UTIL_PlayerByUserId( event->GetInt("attacker") ) );
Assert( pAttacker );
if ( pAttacker )
pAttacker->Stats_WeaponFired( event->GetInt("weapon") );
}
else if ( FStrEq( eventName, "dod_stats_player_damage" ) )
{
CDODPlayer *pAttacker = ToDODPlayer( UTIL_PlayerByUserId( event->GetInt("attacker") ) );
int iVictimID = event->GetInt("victim");
CDODPlayer *pVictim = ToDODPlayer( UTIL_PlayerByUserId( iVictimID ) );
// discard damage to teammates or to yourself
if ( ( pAttacker == NULL ) || ( pVictim->GetTeamNumber() == pAttacker->GetTeamNumber() ) )
return;
int weaponID = event->GetInt("weapon");
int iDamage = event->GetInt("damage");
int iDamageGiven = event->GetInt("damage_given");
float flDistance = event->GetFloat("distance");
int hitgroup = event->GetInt("hitgroup");
pAttacker->Stats_WeaponHit( pVictim, weaponID, iDamage, iDamageGiven, hitgroup, flDistance );
pVictim->Stats_HitByWeapon( pAttacker, weaponID, iDamage, iDamageGiven, hitgroup );
}
else if ( FStrEq( eventName, "dod_stats_player_killed" ) )
{
int iVictimID = event->GetInt("victim");
CDODPlayer *pVictim = ToDODPlayer( UTIL_PlayerByUserId( iVictimID ) );
CDODPlayer *pAttacker = ToDODPlayer( UTIL_PlayerByUserId( event->GetInt("attacker") ) );
// discard kills to teammates or to yourself
if ( ( pAttacker == NULL ) || ( pVictim->GetTeamNumber() == pAttacker->GetTeamNumber() ) )
return;
int weaponID = event->GetInt("weapon");
pAttacker->Stats_KilledPlayer( pVictim, weaponID );
pVictim->Stats_KilledByPlayer( pAttacker, weaponID );
}
}
CDODStatManager g_DODStatMgr;
+78
View File
@@ -0,0 +1,78 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DOD_STATMGR_H
#define DOD_STATMGR_H
#ifdef _WIN32
#pragma once
#endif
#include "GameEventListener.h"
#include <igamesystem.h>
// Structure that holds all information related to how a player related to a
//
typedef struct
{
// shots taken
int m_iNumShotsTaken;
// shots hit
int m_iNumShotsHit;
// total damage given
int m_iTotalDamageGiven;
// average distance of hit shots
float m_flAverageHitDistance;
// total kills
int m_iNumKills;
// times we hit each hitgroup
int m_iBodygroupsHit[7];
// times hit by this weapon
int m_iNumHitsTaken;
// total damage given to us
int m_iTotalDamageTaken;
// times killed by this weapon
int m_iTimesKilled;
// times we were hit in each hitgroup
int m_iHitInBodygroups[8];
} weaponstat_t;
// Can be used to represent a victim and how many times we killed him,
// or as an attacker, how many times we were killed by this person
typedef struct
{
char m_szPlayerName[MAX_PLAYER_NAME_LENGTH]; // when we add this player, store the player name
int m_iUserID; // player that did the killing
int m_iKills; // number of kills
int m_iTotalDamage; // amount of damage
} playerstat_t;
class CDODStatManager : public CGameEventListener, public CAutoGameSystem
{
private:
typedef CBaseGameSystem BaseClass;
public:
CDODStatManager();
public: // IGameEventListener Interface
virtual void FireGameEvent( IGameEvent * event );
public: // CBaseGameSystem overrides
virtual bool Init();
//virtual void Shutdown() {}
};
#endif // DOD_STATMGR_H
+78
View File
@@ -0,0 +1,78 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "dod_stickgrenade.h"
#include "dod_shareddefs.h"
#define GRENADE_MODEL "models/Weapons/w_stick.mdl"
LINK_ENTITY_TO_CLASS( grenade_frag_ger, CDODStickGrenade );
PRECACHE_WEAPON_REGISTER( grenade_frag_ger );
CDODStickGrenade* CDODStickGrenade::Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
float timer,
DODWeaponID weaponID )
{
CDODStickGrenade *pGrenade = (CDODStickGrenade*)CBaseEntity::Create( "grenade_frag_ger", position, angles, pOwner );
Assert( pGrenade );
if( !pGrenade )
return NULL;
IPhysicsObject *pPhysicsObject = pGrenade->VPhysicsGetObject();
if ( pPhysicsObject )
{
pPhysicsObject->AddVelocity( &velocity, &angVelocity );
}
pGrenade->SetupInitialTransmittedGrenadeVelocity( velocity );
// Who threw this grenade
pGrenade->SetThrower( pOwner );
pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
// How long until we explode
pGrenade->SetDetonateTimerLength( timer );
// Save the weapon id for stats purposes
pGrenade->m_EmitterWeaponID = weaponID;
return pGrenade;
}
void CDODStickGrenade::Spawn()
{
SetModel( GRENADE_MODEL );
BaseClass::Spawn();
}
void CDODStickGrenade::Precache()
{
PrecacheModel( GRENADE_MODEL );
PrecacheScriptSound( "HEGrenade.Bounce" );
BaseClass::Precache();
}
void CDODStickGrenade::BounceSound( void )
{
EmitSound( "HEGrenade.Bounce" );
}
//Pass the classname of the exploding version of this grenade.
char *CDODStickGrenade::GetExplodingClassname()
{
return "weapon_frag_ger_live";
}
+50
View File
@@ -0,0 +1,50 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef DOD_STICKGRENADE_H
#define DOD_STICKGRENADE_H
#ifdef _WIN32
#pragma once
#endif
#include "dod_basegrenade.h"
class CDODStickGrenade : public CDODBaseGrenade
{
public:
DECLARE_CLASS( CDODStickGrenade, CDODBaseGrenade );
// Overrides.
public:
CDODStickGrenade() {}
virtual void Spawn();
virtual void Precache();
virtual void BounceSound( void );
// Grenade stuff.
public:
static CDODStickGrenade* Create(
const Vector &position,
const QAngle &angles,
const Vector &velocity,
const AngularImpulse &angVelocity,
CBaseCombatCharacter *pOwner,
float timer,
DODWeaponID weaponID );
void SetTimer( float timer );
virtual char *GetExplodingClassname();
private:
float m_flDetonateTime;
CDODStickGrenade( const CDODStickGrenade & );
};
#endif // DOD_STICKGRENADE_H
+168
View File
@@ -0,0 +1,168 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Team management class. Contains all the details for a specific team
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "dod_team.h"
#include "entitylist.h"
#include "dod_shareddefs.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Datatable
IMPLEMENT_SERVERCLASS_ST(CDODTeam, DT_DODTeam)
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( dod_team_manager, CDODTeam );
//-----------------------------------------------------------------------------
// Purpose: Get a pointer to the specified TF team manager
//-----------------------------------------------------------------------------
CDODTeam *GetGlobalDODTeam( int iIndex )
{
return (CDODTeam*)GetGlobalTeam( iIndex );
}
//-----------------------------------------------------------------------------
// Purpose: Needed because this is an entity, but should never be used
//-----------------------------------------------------------------------------
void CDODTeam::Init( const char *pName, int iNumber )
{
BaseClass::Init( pName, iNumber );
// Only detect changes every half-second.
NetworkProp()->SetUpdateInterval( 0.75f );
m_hPlayerClassInfoHandles.Purge();
}
void CDODTeam::AddPlayerClass( const char *szClassName )
{
PLAYERCLASS_FILE_INFO_HANDLE hPlayerClassInfo;
if ( ReadPlayerClassDataFromFileForSlot( filesystem, szClassName, &hPlayerClassInfo, GetEncryptionKey() ) )
{
m_hPlayerClassInfoHandles.AddToTail( hPlayerClassInfo );
}
else
{
Assert( !"missing playerclass script file" );
Msg( "Missing playerclass script file for class: %s\n", szClassName );
}
}
const CDODPlayerClassInfo &CDODTeam::GetPlayerClassInfo( int iPlayerClass ) const
{
Assert( iPlayerClass >= 0 && iPlayerClass < m_hPlayerClassInfoHandles.Count() );
const FilePlayerClassInfo_t *pPlayerClassInfo = GetFilePlayerClassInfoFromHandle( m_hPlayerClassInfoHandles[iPlayerClass] );
const CDODPlayerClassInfo *pDODInfo;
#ifdef _DEBUG
pDODInfo = dynamic_cast< const CDODPlayerClassInfo* >( pPlayerClassInfo );
Assert( pDODInfo );
#else
pDODInfo = static_cast< const CDODPlayerClassInfo* >( pPlayerClassInfo );
#endif
return *pDODInfo;
}
bool CDODTeam::IsClassOnTeam( const char *pszClassName, int &iClassNum ) const
{
iClassNum = PLAYERCLASS_UNDEFINED;
// Random is always on every team
if( FStrEq( pszClassName, "cls_random" ) )
{
iClassNum = PLAYERCLASS_RANDOM;
return true;
}
for( int i=0;i<m_hPlayerClassInfoHandles.Count(); i++ )
{
FilePlayerClassInfo_t *pPlayerClassInfo = GetFilePlayerClassInfoFromHandle( m_hPlayerClassInfoHandles[i] );
if( stricmp( pszClassName, pPlayerClassInfo->m_szSelectCmd ) == 0 )
{
iClassNum = i;
return true;
}
}
return false;
}
void CDODTeam::ResetScores( void )
{
SetRoundsWon(0);
SetScore(0);
}
//==================================
// TEAMS!
//==================================
// US REGULARS
//==================
class CDODTeam_Allies : public CDODTeam
{
DECLARE_CLASS( CDODTeam_Allies, CDODTeam );
DECLARE_SERVERCLASS();
virtual void Init( const char *pName, int iNumber )
{
BaseClass::Init( pName, iNumber );
int i = 0;
while( pszTeamAlliesClasses[i] != NULL )
{
AddPlayerClass( pszTeamAlliesClasses[i] );
i++;
}
}
virtual const char *GetTeamName( void ) { return "#Teamname_Allies"; }
};
IMPLEMENT_SERVERCLASS_ST(CDODTeam_Allies, DT_DODTeam_Allies)
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( dod_team_allies, CDODTeam_Allies );
// AXIS REGULAR
//==================
class CDODTeam_Axis : public CDODTeam
{
DECLARE_CLASS( CDODTeam_Axis, CDODTeam );
DECLARE_SERVERCLASS();
virtual void Init( const char *pName, int iNumber )
{
BaseClass::Init( pName, iNumber );
int i = 0;
while( pszTeamAxisClasses[i] != NULL )
{
AddPlayerClass( pszTeamAxisClasses[i] );
i++;
}
}
virtual const char *GetTeamName( void ) { return "#Teamname_Allies"; }
};
IMPLEMENT_SERVERCLASS_ST(CDODTeam_Axis, DT_DODTeam_Axis)
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( dod_team_axis, CDODTeam_Axis );
+60
View File
@@ -0,0 +1,60 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Team management class. Contains all the details for a specific team
//
// $NoKeywords: $
//=============================================================================//
#ifndef DOD_TEAM_H
#define DOD_TEAM_H
#ifdef _WIN32
#pragma once
#endif
#include "utlvector.h"
#include "team.h"
#include "playerclass_info_parse.h"
#include "dod_playerclass_info_parse.h"
#include "dod_shareddefs.h"
#include "dod_player.h"
typedef CUtlLinkedList< PLAYERCLASS_FILE_INFO_HANDLE, int > PlayerClassInfoList;
//-----------------------------------------------------------------------------
// Purpose: Team Manager
//-----------------------------------------------------------------------------
class CDODTeam : public CTeam
{
DECLARE_CLASS( CDODTeam, CTeam );
DECLARE_SERVERCLASS();
public:
// Initialization
virtual void Init( const char *pName, int iNumber );
CDODPlayerClassInfo const &GetPlayerClassInfo( int iPlayerClass ) const;
const unsigned char *GetEncryptionKey( void ) { return g_pGameRules->GetEncryptionKey(); }
virtual void AddPlayerClass( const char *pszClassName );
bool IsClassOnTeam( const char *pszClassName, int &iClassNum ) const;
int GetNumPlayerClasses( void ) { return m_hPlayerClassInfoHandles.Count(); }
void ResetScores( void );
virtual const char *GetTeamName( void ) { return "#Teamname_Spectators"; }
virtual CDODPlayer *GetDODPlayer( int iIndex ) { return ToDODPlayer(GetPlayer(iIndex)); }
private:
CUtlVector < PLAYERCLASS_FILE_INFO_HANDLE > m_hPlayerClassInfoHandles;
};
extern CDODTeam *GetGlobalDODTeam( int iIndex );
#endif // TF_TEAM_H
+109
View File
@@ -0,0 +1,109 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "grenadetrail.h"
#include "dt_send.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define GRENADETRAIL_ENTITYNAME "env_grenadetrail"
//-----------------------------------------------------------------------------
//Data table
//-----------------------------------------------------------------------------
IMPLEMENT_SERVERCLASS_ST(CGrenadeTrail, DT_GrenadeTrail)
SendPropFloat(SENDINFO(m_SpawnRate), 8, 0, 1, 1024),
SendPropFloat(SENDINFO(m_ParticleLifetime), 16, SPROP_ROUNDUP, 0.1, 100),
SendPropFloat(SENDINFO(m_StopEmitTime), 0, SPROP_NOSCALE),
SendPropBool(SENDINFO(m_bEmit) ),
SendPropInt(SENDINFO(m_nAttachment), 32 ),
END_SEND_TABLE()
BEGIN_DATADESC( CGrenadeTrail )
DEFINE_KEYFIELD( m_SpawnRate, FIELD_FLOAT, "spawnrate" ),
DEFINE_KEYFIELD( m_ParticleLifetime, FIELD_FLOAT, "lifetime" ),
DEFINE_FIELD( m_StopEmitTime, FIELD_TIME ),
DEFINE_FIELD( m_bEmit, FIELD_BOOLEAN ),
DEFINE_FIELD( m_nAttachment, FIELD_INTEGER ),
END_DATADESC()
LINK_ENTITY_TO_CLASS(env_grenadetrail, CGrenadeTrail);
//-----------------------------------------------------------------------------
// Purpose:
// Output :
//-----------------------------------------------------------------------------
CGrenadeTrail::CGrenadeTrail()
{
m_SpawnRate = 10;
m_ParticleLifetime = 5;
m_StopEmitTime = 0; // Don't stop emitting particles
m_bEmit = true;
m_nAttachment = 0;
}
//-----------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//-----------------------------------------------------------------------------
void CGrenadeTrail::SetEmit(bool bVal)
{
m_bEmit = bVal;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : CGrenadeTrail*
//-----------------------------------------------------------------------------
CGrenadeTrail* CGrenadeTrail::CreateGrenadeTrail()
{
CBaseEntity *pEnt = CreateEntityByName(GRENADETRAIL_ENTITYNAME);
if(pEnt)
{
CGrenadeTrail *pTrail = dynamic_cast<CGrenadeTrail*>(pEnt);
if(pTrail)
{
pTrail->Activate();
return pTrail;
}
else
{
UTIL_Remove(pEnt);
}
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Attach the smoke trail to an entity or point
// Input : index - entity that has the attachment
// attachment - point to attach to
//-----------------------------------------------------------------------------
void CGrenadeTrail::FollowEntity( CBaseEntity *pEntity, const char *pAttachmentName )
{
// For attachments
if ( pAttachmentName && pEntity && pEntity->GetBaseAnimating() )
{
m_nAttachment = pEntity->GetBaseAnimating()->LookupAttachment( pAttachmentName );
}
else
{
m_nAttachment = 0;
}
BaseClass::FollowEntity( pEntity );
}
+31
View File
@@ -0,0 +1,31 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
#ifndef GRENADE_TRAIL_H
#define GRENADE_TRAIL_H
#include "baseparticleentity.h"
//==================================================
// SmokeTrail
//==================================================
class CGrenadeTrail : public CBaseParticleEntity
{
DECLARE_DATADESC();
public:
DECLARE_CLASS( CGrenadeTrail, CBaseParticleEntity );
DECLARE_SERVERCLASS();
CGrenadeTrail();
void SetEmit(bool bVal);
void FollowEntity( CBaseEntity *pEntity, const char *pAttachmentName = NULL);
static CGrenadeTrail* CreateGrenadeTrail();
public:
CNetworkVar( float, m_SpawnRate ); // How many particles per second.
CNetworkVar( float, m_ParticleLifetime ); // How long do the particles live?
CNetworkVar( bool, m_bEmit );
CNetworkVar( float, m_StopEmitTime ); // When do I stop emitting particles?
CNetworkVar( int, m_nAttachment );
};
#endif //GRENADE_TRAIL_H
+123
View File
@@ -0,0 +1,123 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "holiday_gift.h"
#include "dod_shareddefs.h"
#define CHRISTMAS_MODEL "models/items/dod_gift.mdl"
LINK_ENTITY_TO_CLASS( holiday_gift, CHolidayGift );
PRECACHE_WEAPON_REGISTER( holiday_gift );
//-----------------------------------------------------------------------------
CHolidayGift* CHolidayGift::Create( const Vector &position, const QAngle &angles, const QAngle &eyeAngles, const Vector &velocity, CBaseCombatCharacter *pOwner )
{
CHolidayGift *pGift = (CHolidayGift*)CBaseEntity::Create( "holiday_gift", position, angles, pOwner );
if ( pGift )
{
pGift->AddSpawnFlags( SF_NORESPAWN );
Vector vecRight, vecUp;
AngleVectors( eyeAngles, NULL, &vecRight, &vecUp );
// Calculate the initial impulse on the gift.
Vector vecImpulse( 0.0f, 0.0f, 0.0f );
vecImpulse += vecUp * random->RandomFloat( 0, 0.25 );
vecImpulse += vecRight * random->RandomFloat( -0.25, 0.25 );
VectorNormalize( vecImpulse );
vecImpulse *= random->RandomFloat( 100.0, 150.0 );
vecImpulse += velocity;
// Cap the impulse.
float flSpeed = vecImpulse.Length();
if ( flSpeed > 300.0 )
{
VectorScale( vecImpulse, 300.0 / flSpeed, vecImpulse );
}
pGift->SetMoveType( MOVETYPE_FLYGRAVITY );
pGift->SetAbsVelocity( vecImpulse * 2.f + Vector(0,0,200) );
pGift->SetAbsAngles( QAngle(0,0,0) );
pGift->UseClientSideAnimation();
pGift->ResetSequence( pGift->LookupSequence("idle") );
pGift->EmitSound( "Christmas.GiftDrop" );
pGift->ActivateWhenAtRest();
}
return pGift;
}
//-----------------------------------------------------------------------------
void CHolidayGift::Precache()
{
BaseClass::Precache();
PrecacheModel( CHRISTMAS_MODEL );
PrecacheScriptSound( "Christmas.GiftDrop" );
PrecacheScriptSound( "Christmas.GiftPickup" );
}
//-----------------------------------------------------------------------------
void CHolidayGift::Spawn( void )
{
BaseClass::Spawn();
SetModel( CHRISTMAS_MODEL );
// Die in 30 seconds
SetContextThink( &CBaseEntity::SUB_Remove, gpGlobals->curtime + 30, "DIE_THINK" );
SetContextThink( &CHolidayGift::DropSoundThink, gpGlobals->curtime + 0.2f, "SOUND_THINK" );
}
//-----------------------------------------------------------------------------
void CHolidayGift::DropSoundThink( void )
{
EmitSound( "Christmas.GiftDrop" );
}
//-----------------------------------------------------------------------------
bool CHolidayGift::MyTouch( CBasePlayer *pPlayer )
{
if( !pPlayer )
return false;
if( !pPlayer->IsAlive() )
return false;
if ( pPlayer->IsBot() )
return false;
if ( ( pPlayer->GetTeamNumber() != TEAM_ALLIES ) && ( pPlayer->GetTeamNumber() != TEAM_AXIS ) )
return false;
// Send a message for the achievement tracking.
IGameEvent *event = gameeventmanager->CreateEvent( "christmas_gift_grab" );
if ( event )
{
event->SetInt( "userid", pPlayer->GetUserID() );
gameeventmanager->FireEvent( event );
}
pPlayer->EmitSound( "Christmas.GiftPickup" );
return true;
}
//-----------------------------------------------------------------------------
void CHolidayGift::ItemTouch( CBaseEntity *pOther )
{
if ( pOther->IsWorld() )
{
Vector absVel = GetAbsVelocity();
SetAbsVelocity( Vector( 0,0,absVel.z ) );
return;
}
BaseClass::ItemTouch( pOther );
}
+36
View File
@@ -0,0 +1,36 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef HOLIDAY_GIFT_H
#define HOLIDAY_GIFT_H
#ifdef _WIN32
#pragma once
#endif
#include "items.h"
class CHolidayGift: public CItem
{
public:
DECLARE_CLASS( CHolidayGift, CItem );
public:
virtual void Precache();
virtual void Spawn( void );
virtual bool MyTouch( CBasePlayer *pBasePlayer );
virtual void ItemTouch( CBaseEntity *pOther );
void DropSoundThink( void );
public:
static CHolidayGift* Create( const Vector &position, const QAngle &angles, const QAngle &eyeAngles, const Vector &velocity, CBaseCombatCharacter *pOwner );
};
#endif // HOLIDAY_GIFT_H
+30
View File
@@ -0,0 +1,30 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "rocket_bazooka.h"
LINK_ENTITY_TO_CLASS( rocket_bazooka, CBazookaRocket );
PRECACHE_WEAPON_REGISTER( rocket_bazooka );
void CBazookaRocket::Spawn( void )
{
SetModel( BAZOOKA_ROCKET_MODEL );
BaseClass::Spawn();
}
void CBazookaRocket::Precache( void )
{
PrecacheModel( BAZOOKA_ROCKET_MODEL );
BaseClass::Precache();
}
CBazookaRocket *CBazookaRocket::Create( const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity *pOwner )
{
return static_cast<CBazookaRocket *> ( CDODBaseRocket::Create( "rocket_bazooka", vecOrigin, vecAngles, pOwner ) );
}
+36
View File
@@ -0,0 +1,36 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef ROCKET_BAZOOKA_H
#define ROCKET_BAZOOKA_H
#ifdef _WIN32
#pragma once
#endif
#define BAZOOKA_ROCKET_MODEL "models/weapons/w_bazooka_rocket.mdl"
#include "dod_baserocket.h"
class CBazookaRocket : public CDODBaseRocket
{
public:
DECLARE_CLASS( CBazookaRocket, CDODBaseRocket );
CBazookaRocket() {}
virtual void Spawn();
virtual void Precache();
static CBazookaRocket *Create( const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity *pOwner );
virtual DODWeaponID GetEmitterWeaponID() { return WEAPON_BAZOOKA; }
private:
CBazookaRocket( const CBazookaRocket & );
};
#endif //ROCKET_BAZOOKA_H
+30
View File
@@ -0,0 +1,30 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "rocket_pschreck.h"
LINK_ENTITY_TO_CLASS( rocket_pschreck, CPschreckRocket );
PRECACHE_WEAPON_REGISTER( rocket_pschreck );
void CPschreckRocket::Spawn( void )
{
SetModel( PSCHRECK_ROCKET_MODEL );
BaseClass::Spawn();
}
void CPschreckRocket::Precache( void )
{
PrecacheModel( PSCHRECK_ROCKET_MODEL );
BaseClass::Precache();
}
CPschreckRocket *CPschreckRocket::Create( const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity *pOwner )
{
return static_cast<CPschreckRocket *> ( CDODBaseRocket::Create( "rocket_pschreck", vecOrigin, vecAngles, pOwner ) );
}
+36
View File
@@ -0,0 +1,36 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef ROCKET_PSCHRECK_H
#define ROCKET_PSCHRECK_H
#ifdef _WIN32
#pragma once
#endif
#define PSCHRECK_ROCKET_MODEL "models/weapons/w_panzerschreck_rocket.mdl"
#include "dod_baserocket.h"
class CPschreckRocket : public CDODBaseRocket
{
public:
DECLARE_CLASS( CPschreckRocket, CDODBaseRocket );
CPschreckRocket() {}
virtual void Spawn();
virtual void Precache();
static CPschreckRocket *Create( const Vector &vecOrigin, const QAngle &vecAngles, CBaseEntity *pOwner );
virtual DODWeaponID GetEmitterWeaponID() { return WEAPON_PSCHRECK; }
private:
CPschreckRocket( const CPschreckRocket & );
};
#endif //ROCKET_PSCHRECK_H
+114
View File
@@ -0,0 +1,114 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basetempentity.h"
#define NUM_BULLET_SEED_BITS 8
//-----------------------------------------------------------------------------
// Purpose: Display's a blood sprite
//-----------------------------------------------------------------------------
class CTEFireBullets : public CBaseTempEntity
{
public:
DECLARE_CLASS( CTEFireBullets, CBaseTempEntity );
DECLARE_SERVERCLASS();
CTEFireBullets( const char *name );
virtual ~CTEFireBullets( void );
virtual void Create( IRecipientFilter& filter, float delay = 0.0f );
public:
CNetworkVar( int, m_iPlayer );
CNetworkVector( m_vecOrigin );
CNetworkQAngle( m_vecAngles );
CNetworkVar( int, m_iWeaponID );
CNetworkVar( int, m_iMode );
CNetworkVar( int, m_iSeed );
CNetworkVar( float, m_flSpread );
};
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
//-----------------------------------------------------------------------------
CTEFireBullets::CTEFireBullets( const char *name ) :
CBaseTempEntity( name )
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTEFireBullets::~CTEFireBullets( void )
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : msg_dest -
// delay -
// *origin -
// *recipient -
//-----------------------------------------------------------------------------
void CTEFireBullets::Create( IRecipientFilter& filter, float delay )
{
engine->PlaybackTempEntity( filter, delay,
(void *)this, GetServerClass()->m_pTable, GetServerClass()->m_ClassID );
}
IMPLEMENT_SERVERCLASS_ST_NOBASE(CTEFireBullets, DT_TEFireBullets)
SendPropVector( SENDINFO(m_vecOrigin), -1, SPROP_COORD ),
SendPropAngle( SENDINFO_VECTORELEM( m_vecAngles, 0 ), 13, 0 ),
SendPropAngle( SENDINFO_VECTORELEM( m_vecAngles, 1 ), 13, 0 ),
SendPropInt( SENDINFO( m_iWeaponID ), 5, SPROP_UNSIGNED ), // max 31 weapons
SendPropInt( SENDINFO( m_iMode ), 1, SPROP_UNSIGNED ),
SendPropInt( SENDINFO( m_iSeed ), NUM_BULLET_SEED_BITS, SPROP_UNSIGNED ),
SendPropInt( SENDINFO( m_iPlayer ), 6, SPROP_UNSIGNED ), // max 64 players, see MAX_PLAYERS
SendPropFloat( SENDINFO( m_flSpread ), 10, 0, 0, 1 ),
END_SEND_TABLE()
// Singleton
static CTEFireBullets g_TEFireBullets( "FireBullets" );
void TE_FireBullets(
int iPlayerIndex,
const Vector &vOrigin,
const QAngle &vAngles,
int iWeaponID,
int iMode,
int iSeed,
float flSpread )
{
CPASFilter filter( vOrigin );
filter.UsePredictionRules();
g_TEFireBullets.m_iPlayer = iPlayerIndex-1;
g_TEFireBullets.m_vecOrigin = vOrigin;
g_TEFireBullets.m_vecAngles = vAngles;
g_TEFireBullets.m_iSeed = iSeed;
g_TEFireBullets.m_flSpread = flSpread;
g_TEFireBullets.m_iMode = iMode;
g_TEFireBullets.m_iWeaponID = iWeaponID;
Assert( iSeed < (1 << NUM_BULLET_SEED_BITS) );
g_TEFireBullets.Create( filter, 0 );
}
+25
View File
@@ -0,0 +1,25 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef TE_FIREBULLETS_H
#define TE_FIREBULLETS_H
#ifdef _WIN32
#pragma once
#endif
void TE_FireBullets(
int iPlayerIndex,
const Vector &vOrigin,
const QAngle &vAngles,
int iWeaponID,
int iMode,
int iSeed,
float flSpread
);
#endif // TE_FIREBULLETS_H
+76
View File
@@ -0,0 +1,76 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef __UNISIGNALS_H__
#define __UNISIGNALS_H__
// Unified signals allow state updating to be performed at one point in the
// calling code. The sequence of events is:
//
// 1. Signal( whatever ), Signal( whatever ), etc.
// 2. ( GetState() & Update() ) to get only the changes since the last update
// 3. Goto 1
//
// Or, alternately:
//
// 1. Signal( whatever ), Signal( whatever ), etc.
// 2. Update()
// 3. GetState()
// 4. Goto 1
class CUnifiedSignals
{
public:
inline CUnifiedSignals();
inline int Update(); // Returns a mask for the changed state bits; signals are cleared after this update is performed
inline void Signal( int flSignal ); // ORed combo of BPSIG_xxx bits
inline int GetState(); // Returns the current state (ORed combo of BPSIG_xxx flags)
private:
int m_flSignal; // States to trigger
int m_flState; // States after the previous update
};
inline CUnifiedSignals::CUnifiedSignals()
{
m_flSignal = 0;
m_flState = 0;
}
inline int CUnifiedSignals::Update()
{
int old = m_flState;
m_flState = m_flSignal;
m_flSignal = 0;
return m_flState ^ old;
}
inline void CUnifiedSignals::Signal( int flSignal )
{
m_flSignal |= flSignal;
}
inline int CUnifiedSignals::GetState()
{
return m_flState;
}
#endif // __UNISIGNALS_H__
+215
View File
@@ -0,0 +1,215 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "hl1_ai_basenpc.h"
#include "scripted.h"
#include "soundent.h"
#include "animation.h"
#include "entitylist.h"
#include "ai_navigator.h"
#include "ai_motor.h"
#include "player.h"
#include "vstdlib/random.h"
#include "engine/IEngineSound.h"
#include "npcevent.h"
#include "effect_dispatch_data.h"
#include "te_effect_dispatch.h"
#include "cplane.h"
#include "ai_squad.h"
#define HUMAN_GIBS 1
#define ALIEN_GIBS 2
//=========================================================
// NoFriendlyFire - checks for possibility of friendly fire
//
// Builds a large box in front of the grunt and checks to see
// if any squad members are in that box.
//=========================================================
bool CHL1BaseNPC::NoFriendlyFire( void )
{
if ( !m_pSquad )
{
return true;
}
CPlane backPlane;
CPlane leftPlane;
CPlane rightPlane;
Vector vecLeftSide;
Vector vecRightSide;
Vector v_left;
Vector vForward, vRight, vUp;
QAngle vAngleToEnemy;
if ( GetEnemy() != NULL )
{
//!!!BUGBUG - to fix this, the planes must be aligned to where the monster will be firing its gun, not the direction it is facing!!!
VectorAngles( ( GetEnemy()->WorldSpaceCenter() - GetAbsOrigin() ), vAngleToEnemy );
AngleVectors ( vAngleToEnemy, &vForward, &vRight, &vUp );
}
else
{
// if there's no enemy, pretend there's a friendly in the way, so the grunt won't shoot.
return false;
}
vecLeftSide = GetAbsOrigin() - ( vRight * ( WorldAlignSize().x * 1.5 ) );
vecRightSide = GetAbsOrigin() + ( vRight * ( WorldAlignSize().x * 1.5 ) );
v_left = vRight * -1;
leftPlane.InitializePlane ( vRight, vecLeftSide );
rightPlane.InitializePlane ( v_left, vecRightSide );
backPlane.InitializePlane ( vForward, GetAbsOrigin() );
AISquadIter_t iter;
for ( CAI_BaseNPC *pSquadMember = m_pSquad->GetFirstMember( &iter ); pSquadMember; pSquadMember = m_pSquad->GetNextMember( &iter ) )
{
if ( pSquadMember == NULL )
continue;
if ( pSquadMember == this )
continue;
if ( backPlane.PointInFront ( pSquadMember->GetAbsOrigin() ) &&
leftPlane.PointInFront ( pSquadMember->GetAbsOrigin() ) &&
rightPlane.PointInFront ( pSquadMember->GetAbsOrigin()) )
{
// this guy is in the check volume! Don't shoot!
return false;
}
}
return true;
}
void CHL1BaseNPC::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
{
if ( info.GetDamage() >= 1.0 && !(info.GetDamageType() & DMG_SHOCK ) )
{
UTIL_BloodSpray( ptr->endpos, vecDir, BloodColor(), 4, FX_BLOODSPRAY_ALL );
}
BaseClass::TraceAttack( info, vecDir, ptr, pAccumulator );
}
bool CHL1BaseNPC::ShouldGib( const CTakeDamageInfo &info )
{
if ( info.GetDamageType() & DMG_NEVERGIB )
return false;
if ( ( g_pGameRules->Damage_ShouldGibCorpse( info.GetDamageType() ) && m_iHealth < GIB_HEALTH_VALUE ) || ( info.GetDamageType() & DMG_ALWAYSGIB ) )
return true;
return false;
}
bool CHL1BaseNPC::HasHumanGibs( void )
{
Class_T myClass = Classify();
if ( myClass == CLASS_HUMAN_MILITARY ||
myClass == CLASS_PLAYER_ALLY ||
myClass == CLASS_HUMAN_PASSIVE ||
myClass == CLASS_PLAYER )
return true;
return false;
}
bool CHL1BaseNPC::HasAlienGibs( void )
{
Class_T myClass = Classify();
if ( myClass == CLASS_ALIEN_MILITARY ||
myClass == CLASS_ALIEN_MONSTER ||
myClass == CLASS_INSECT ||
myClass == CLASS_ALIEN_PREDATOR ||
myClass == CLASS_ALIEN_PREY )
return true;
return false;
}
void CHL1BaseNPC::Precache( void )
{
PrecacheModel( "models/gibs/agibs.mdl" );
PrecacheModel( "models/gibs/hgibs.mdl" );
BaseClass::Precache();
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CHL1BaseNPC::CorpseGib( const CTakeDamageInfo &info )
{
CEffectData data;
data.m_vOrigin = WorldSpaceCenter();
data.m_vNormal = data.m_vOrigin - info.GetDamagePosition();
VectorNormalize( data.m_vNormal );
data.m_flScale = RemapVal( m_iHealth, 0, -500, 1, 3 );
data.m_flScale = clamp( data.m_flScale, 1, 3 );
if ( HasAlienGibs() )
data.m_nMaterial = ALIEN_GIBS;
else if ( HasHumanGibs() )
data.m_nMaterial = HUMAN_GIBS;
data.m_nColor = BloodColor();
DispatchEffect( "HL1Gib", data );
CSoundEnt::InsertSound( SOUND_MEAT, GetAbsOrigin(), 256, 0.5f, this );
/// BaseClass::CorpseGib( info );
return true;
}
int CHL1BaseNPC::IRelationPriority( CBaseEntity *pTarget )
{
return BaseClass::IRelationPriority( pTarget );
}
void CHL1BaseNPC::EjectShell( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int iType )
{
CEffectData data;
data.m_vStart = vecVelocity;
data.m_vOrigin = vecOrigin;
data.m_vAngles = QAngle( 0, rotation, 0 );
data.m_fFlags = iType;
DispatchEffect( "HL1ShellEject", data );
}
// HL1 version - never return Ragdoll as the automatic schedule at the end of a
// scripted sequence
int CHL1BaseNPC::SelectDeadSchedule()
{
// Alread dead (by animation event maybe?)
// Is it safe to set it to SCHED_NONE?
if ( m_lifeState == LIFE_DEAD )
return SCHED_NONE;
CleanupOnDeath();
return SCHED_DIE;
}
+51
View File
@@ -0,0 +1,51 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base combat character with no AI
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#ifndef HL1_AI_BASENPC_H
#define HL1_AI_BASENPC_H
#ifdef _WIN32
#pragma once
#endif
#include "ai_basenpc.h"
#include "ai_motor.h"
//=============================================================================
// >> CHL1NPCTalker
//=============================================================================
class CHL1BaseNPC : public CAI_BaseNPC
{
DECLARE_CLASS( CHL1BaseNPC, CAI_BaseNPC );
public:
CHL1BaseNPC( void )
{
}
void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator );
bool ShouldGib( const CTakeDamageInfo &info );
bool CorpseGib( const CTakeDamageInfo &info );
bool HasAlienGibs( void );
bool HasHumanGibs( void );
void Precache( void );
int IRelationPriority( CBaseEntity *pTarget );
bool NoFriendlyFire( void );
void EjectShell( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int iType );
virtual int SelectDeadSchedule();
};
#endif //HL1_AI_BASENPC_H
+86
View File
@@ -0,0 +1,86 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "hl1_basecombatweapon_shared.h"
#include "effect_dispatch_data.h"
#include "te_effect_dispatch.h"
BEGIN_DATADESC( CBaseHL1CombatWeapon )
DEFINE_THINKFUNC( FallThink ),
END_DATADESC();
void CBaseHL1CombatWeapon::Precache()
{
BaseClass::Precache();
PrecacheScriptSound( "BaseCombatWeapon.WeaponDrop" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseHL1CombatWeapon::FallInit( void )
{
SetModel( GetWorldModel() );
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_TRIGGER );
AddSolidFlags( FSOLID_NOT_SOLID );
SetPickupTouch();
SetThink( &CBaseHL1CombatWeapon::FallThink );
SetNextThink( gpGlobals->curtime + 0.1f );
// HACKHACK - On ground isn't always set, so look for ground underneath
trace_t tr;
UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - Vector(0,0,2), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
if ( tr.fraction < 1.0 )
{
SetGroundEntity( tr.m_pEnt );
}
SetViewOffset( Vector(0,0,8) );
}
//-----------------------------------------------------------------------------
// Purpose: Items that have just spawned run this think to catch them when
// they hit the ground. Once we're sure that the object is grounded,
// we change its solid type to trigger and set it in a large box that
// helps the player get it.
//-----------------------------------------------------------------------------
void CBaseHL1CombatWeapon::FallThink ( void )
{
SetNextThink( gpGlobals->curtime + 0.1f );
if ( GetFlags() & FL_ONGROUND )
{
// clatter if we have an owner (i.e., dropped by someone)
// don't clatter if the gun is waiting to respawn (if it's waiting, it is invisible!)
if ( GetOwnerEntity() )
{
EmitSound( "BaseCombatWeapon.WeaponDrop" );
}
// lie flat
QAngle ang = GetAbsAngles();
ang.x = 0;
ang.z = 0;
SetAbsAngles( ang );
Materialize();
SetSize( Vector( -24, -24, 0 ), Vector( 24, 24, 16 ) );
}
}
+116
View File
@@ -0,0 +1,116 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "decals.h"
#include "basecombatcharacter.h"
#include "shake.h"
#include "engine/IEngineSound.h"
#include "soundent.h"
#include "entitylist.h"
#include "hl1_basegrenade.h"
extern short g_sModelIndexFireball; // (in combatweapon.cpp) holds the index for the fireball
extern short g_sModelIndexWExplosion; // (in combatweapon.cpp) holds the index for the underwater explosion
unsigned int CHL1BaseGrenade::PhysicsSolidMaskForEntity( void ) const
{
return BaseClass::PhysicsSolidMaskForEntity() | CONTENTS_HITBOX;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHL1BaseGrenade::Precache()
{
BaseClass::Precache();
PrecacheScriptSound( "BaseGrenade.Explode" );
}
void CHL1BaseGrenade::Explode( trace_t *pTrace, int bitsDamageType )
{
float flRndSound;// sound randomizer
SetModelName( NULL_STRING );//invisible
AddSolidFlags( FSOLID_NOT_SOLID );
m_takedamage = DAMAGE_NO;
// Pull out of the wall a bit
if ( pTrace->fraction != 1.0 )
{
SetLocalOrigin( pTrace->endpos + (pTrace->plane.normal * 0.6) );
}
Vector vecAbsOrigin = GetAbsOrigin();
int contents = UTIL_PointContents ( vecAbsOrigin );
if ( pTrace->fraction != 1.0 )
{
Vector vecNormal = pTrace->plane.normal;
const surfacedata_t *pdata = physprops->GetSurfaceData( pTrace->surface.surfaceProps );
CPASFilter filter( vecAbsOrigin );
te->Explosion( filter, 0.0,
&vecAbsOrigin,
!( contents & MASK_WATER ) ? g_sModelIndexFireball : g_sModelIndexWExplosion,
m_DmgRadius * .03,
25,
TE_EXPLFLAG_NONE,
m_DmgRadius,
m_flDamage,
&vecNormal,
(char) pdata->game.material );
}
else
{
CPASFilter filter( vecAbsOrigin );
te->Explosion( filter, 0.0,
&vecAbsOrigin,
!( contents & MASK_WATER ) ? g_sModelIndexFireball : g_sModelIndexWExplosion,
m_DmgRadius * .03,
25,
TE_EXPLFLAG_NONE,
m_DmgRadius,
m_flDamage );
}
CSoundEnt::InsertSound ( SOUND_COMBAT, GetAbsOrigin(), BASEGRENADE_EXPLOSION_VOLUME, 3.0 );
// Use the owner's position as the reported position
Vector vecReported = GetThrower() ? GetThrower()->GetAbsOrigin() : vec3_origin;
CTakeDamageInfo info( this, GetThrower(), GetBlastForce(), GetAbsOrigin(), m_flDamage, bitsDamageType, 0, &vecReported );
RadiusDamage( info, GetAbsOrigin(), m_DmgRadius, CLASS_NONE, NULL );
UTIL_DecalTrace( pTrace, "Scorch" );
flRndSound = random->RandomFloat( 0 , 1 );
EmitSound( "BaseGrenade.Explode" );
SetTouch( NULL );
AddEffects( EF_NODRAW );
SetAbsVelocity( vec3_origin );
SetThink( &CBaseGrenade::Smoke );
SetNextThink( gpGlobals->curtime + 0.3);
if ( GetWaterLevel() == 0 )
{
int sparkCount = random->RandomInt( 0,3 );
QAngle angles;
VectorAngles( pTrace->plane.normal, angles );
for ( int i = 0; i < sparkCount; i++ )
Create( "spark_shower", GetAbsOrigin(), angles, NULL );
}
}
+42
View File
@@ -0,0 +1,42 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef HL1_BASEGRENADE_H
#define HL1_BASEGRENADE_H
#ifdef _WIN32
#pragma once
#endif
#include "basegrenade_shared.h"
class CHL1BaseGrenade : public CBaseGrenade
{
DECLARE_CLASS( CHL1BaseGrenade, CBaseGrenade );
public:
virtual void Precache();
void Explode( trace_t *pTrace, int bitsDamageType );
unsigned int PhysicsSolidMaskForEntity( void ) const;
};
class CHandGrenade : public CHL1BaseGrenade
{
public:
DECLARE_CLASS( CHandGrenade, CHL1BaseGrenade );
DECLARE_DATADESC();
void Spawn( void );
void Precache( void );
void BounceSound( void );
void BounceTouch( CBaseEntity *pOther );
void ShootTimed( CBaseCombatCharacter *pOwner, Vector vecVelocity, float flTime );
};
#endif // HL1_BASEGRENADE_H
+199
View File
@@ -0,0 +1,199 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
/*
===== tf_client.cpp ========================================================
HL1 client/server game specific stuff
*/
#include "cbase.h"
#include "hl1_player.h"
#include "hl1mp_player.h"
#include "hl1_gamerules.h"
#include "gamerules.h"
#include "teamplay_gamerules.h"
#include "entitylist.h"
#include "physics.h"
#include "game.h"
#include "player_resource.h"
#include "engine/IEngineSound.h"
#include "tier0/vprof.h"
void Host_Say( edict_t *pEdict, bool teamonly );
extern CBaseEntity* FindPickerEntityClass( CBasePlayer *pPlayer, char *classname );
extern bool g_fGameOver;
/*
===========
ClientPutInServer
called each time a player is spawned into the game
============
*/
void ClientPutInServer( edict_t *pEdict, const char *playername )
{
CHL1_Player *pPlayer = NULL;
// Allocate a CBasePlayer for pev, and call spawn
if ( g_pGameRules->IsMultiplayer() )
pPlayer = CHL1_Player::CreatePlayer( "player_mp", pEdict );
else
pPlayer = CHL1_Player::CreatePlayer( "player", pEdict );
pPlayer->SetPlayerName( playername );
}
void ClientActive( edict_t *pEdict, bool bLoadGame )
{
CHL1_Player *pPlayer = dynamic_cast< CHL1_Player* >( CBaseEntity::Instance( pEdict ) );
pPlayer->InitialSpawn();
if ( !bLoadGame )
{
pPlayer->Spawn();
}
}
/*
===============
const char *GetGameDescription()
Returns the descriptive name of this .dll. E.g., Half-Life, or Team Fortress 2
===============
*/
const char *GetGameDescription()
{
if ( g_pGameRules ) // this function may be called before the world has spawned, and the game rules initialized
return g_pGameRules->GetGameDescription();
else
return "Half-Life 1";
}
//-----------------------------------------------------------------------------
// Purpose: Given a player and optional name returns the entity of that
// classname that the player is nearest facing
//
// Input :
// Output :
//-----------------------------------------------------------------------------
CBaseEntity* FindEntity( edict_t *pEdict, char *classname)
{
// If no name was given set bits based on the picked
if (FStrEq(classname,""))
{
return (FindPickerEntityClass( static_cast<CBasePlayer*>(GetContainingEntity(pEdict)), classname ));
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Precache game-specific models & sounds
//-----------------------------------------------------------------------------
void ClientGamePrecache( void )
{
// Multiplayer uses different models, and more of them.
if ( g_pGameRules->IsMultiplayer() )
{
CBaseEntity::PrecacheModel("models/player/mp/barney/barney.mdl");
CBaseEntity::PrecacheModel("models/player/mp/gina/gina.mdl");
CBaseEntity::PrecacheModel("models/player/mp/gman/gman.mdl");
CBaseEntity::PrecacheModel("models/player/mp/gordon/gordon.mdl");
CBaseEntity::PrecacheModel("models/player/mp/helmet/helmet.mdl");
CBaseEntity::PrecacheModel("models/player/mp/hgrunt/hgrunt.mdl");
CBaseEntity::PrecacheModel("models/player/mp/robo/robo.mdl");
CBaseEntity::PrecacheModel("models/player/mp/scientist/scientist.mdl");
CBaseEntity::PrecacheModel("models/player/mp/zombie/zombie.mdl");
CBaseEntity::PrecacheModel("models/player.mdl" );
}
else
{
CBaseEntity::PrecacheModel("models/player.mdl" );
}
CBaseEntity::PrecacheModel( "models/gibs/agibs.mdl" );
CBaseEntity::PrecacheScriptSound( "Player.UseDeny" );
}
// called by ClientKill and DeadThink
void respawn( CBaseEntity *pEdict, bool fCopyCorpse )
{
if (gpGlobals->coop || gpGlobals->deathmatch)
{
if ( fCopyCorpse )
{
// make a copy of the dead body for appearances sake
((CHL1MP_Player *)pEdict)->CreateCorpse();
}
// respawn player
pEdict->Spawn();
}
else
{ // restart the entire server
engine->ServerCommand("reload\n");
}
}
void GameStartFrame( void )
{
VPROF("GameStartFrame()");
if ( g_fGameOver )
return;
gpGlobals->teamplay = (teamplay.GetInt() != 0);
#ifdef DEBUG
extern void Bot_RunAll();
Bot_RunAll();
#endif
}
//=========================================================
// instantiate the proper game rules object
//=========================================================
void InstallGameRules()
{
engine->ServerCommand( "exec game.cfg\n" );
engine->ServerExecute( );
if ( !gpGlobals->deathmatch )
{
// generic half-life
CreateGameRulesObject( "CHalfLife1" );
return;
}
else
{
CreateGameRulesObject( "CHL1MPRules" );
return;
if ( teamplay.GetInt() > 0 )
{
// teamplay
CreateGameRulesObject( "CTeamplayRules" );
return;
}
// vanilla deathmatch
CreateGameRulesObject( "CMultiplayRules" );
return;
}
CreateGameRulesObject( "CHalfLife1" );
}
File diff suppressed because it is too large Load Diff
+73
View File
@@ -0,0 +1,73 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef HL1_ENTS_H
#define HL1_ENTS_H
#ifdef _WIN32
#pragma once
#endif
/**********************
Pendulum
/**********************/
class CPendulum : public CBaseToggle
{
DECLARE_CLASS( CPendulum, CBaseToggle );
public:
void Spawn ( void );
void KeyValue( KeyValueData *pkvd );
void Swing( void );
void PendulumUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void Stop( void );
void Touch( CBaseEntity *pOther );
void RopeTouch ( CBaseEntity *pOther );// this touch func makes the pendulum a rope
void Blocked( CBaseEntity *pOther );
// Input handlers.
void InputActivate( inputdata_t &inputdata );
DECLARE_DATADESC();
float m_flAccel; // Acceleration
float m_flTime;
float m_flDamp;
float m_flMaxSpeed;
float m_flDampSpeed;
QAngle m_vCenter;
QAngle m_vStart;
float m_flBlockDamage;
EHANDLE m_hEnemy;
};
class CHL1Gib : public CBaseEntity
{
DECLARE_CLASS( CHL1Gib, CBaseEntity );
public:
void Spawn( const char *szGibModel );
void BounceGibTouch ( CBaseEntity *pOther );
void StickyGibTouch ( CBaseEntity *pOther );
void WaitTillLand( void );
void LimitVelocity( void );
virtual int ObjectCaps( void ) { return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; }
static void SpawnHeadGib( CBaseEntity *pVictim );
static void SpawnRandomGibs( CBaseEntity *pVictim, int cGibs, int human );
static void SpawnStickyGibs( CBaseEntity *pVictim, Vector vecOrigin, int cGibs );
int m_bloodColor;
int m_cBloodDecals;
int m_material;
float m_lifeTime;
DECLARE_DATADESC();
};
#endif // HL1_ENTS_H
+219
View File
@@ -0,0 +1,219 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "player.h"
#include "mathlib/mathlib.h"
#include "ai_speech.h"
#include "stringregistry.h"
#include "gamerules.h"
#include "game.h"
#include <ctype.h>
#include "entitylist.h"
#include "vstdlib/random.h"
#include "engine/IEngineSound.h"
#include "ndebugoverlay.h"
#include "soundscape.h"
#define SPEAKER_START_SILENT 1 // wait for trigger 'on' to start announcements
// ===================================================================================
//
// Speaker class. Used for announcements per level, for door lock/unlock spoken voice.
//
class CSpeaker : public CPointEntity
{
DECLARE_CLASS( CSpeaker, CPointEntity );
public:
bool KeyValue( const char *szKeyName, const char *szValue );
void Spawn( void );
void Precache( void );
void ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void SpeakerThink( void );
virtual int ObjectCaps( void ) { return (CBaseEntity::ObjectCaps() & ~FCAP_ACROSS_TRANSITION); }
int m_preset; // preset number
string_t m_iszMessage;
DECLARE_DATADESC();
};
LINK_ENTITY_TO_CLASS( speaker, CSpeaker );
BEGIN_DATADESC( CSpeaker )
DEFINE_FIELD( m_preset, FIELD_INTEGER ),
DEFINE_KEYFIELD( m_iszMessage, FIELD_STRING, "message" ),
DEFINE_THINKFUNC( SpeakerThink ),
DEFINE_USEFUNC( ToggleUse ),
END_DATADESC()
//
// ambient_generic - general-purpose user-defined static sound
//
void CSpeaker::Spawn( void )
{
char* szSoundFile = (char*) STRING( m_iszMessage );
if ( !m_preset && ( m_iszMessage == NULL_STRING || strlen( szSoundFile ) < 1 ) )
{
Msg( "SPEAKER with no Level/Sentence! at: %f, %f, %f\n", GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z );
SetNextThink( gpGlobals->curtime + 0.1 );
SetThink( &CSpeaker::SUB_Remove );
return;
}
SetSolid( SOLID_NONE );
SetMoveType( MOVETYPE_NONE );
SetThink(&CSpeaker::SpeakerThink);
SetNextThink( TICK_NEVER_THINK );
// allow on/off switching via 'use' function.
SetUse ( &CSpeaker::ToggleUse );
Precache( );
}
#define ANNOUNCE_MINUTES_MIN 0.25
#define ANNOUNCE_MINUTES_MAX 2.25
void CSpeaker::Precache( void )
{
if ( !FBitSet ( GetSpawnFlags(), SPEAKER_START_SILENT ) )
// set first announcement time for random n second
SetNextThink( gpGlobals->curtime + random->RandomFloat( 5.0, 15.0 ) );
}
void CSpeaker::SpeakerThink( void )
{
char* szSoundFile = NULL;
float flvolume = m_iHealth * 0.1;
int flags = 0;
int pitch = 100;
// Wait for the talking characters to finish first.
if ( !g_AIFriendliesTalkSemaphore.IsAvailable( this ) || !g_AIFoesTalkSemaphore.IsAvailable( this ) )
{
float releaseTime = MAX( g_AIFriendliesTalkSemaphore.GetReleaseTime(), g_AIFoesTalkSemaphore.GetReleaseTime() );
SetNextThink( gpGlobals->curtime + releaseTime + random->RandomFloat( 5, 10 ) );
return;
}
if (m_preset)
{
// go lookup preset text, assign szSoundFile
switch (m_preset)
{
case 1: szSoundFile = "C1A0_"; break;
case 2: szSoundFile = "C1A1_"; break;
case 3: szSoundFile = "C1A2_"; break;
case 4: szSoundFile = "C1A3_"; break;
case 5: szSoundFile = "C1A4_"; break;
case 6: szSoundFile = "C2A1_"; break;
case 7: szSoundFile = "C2A2_"; break;
case 8: szSoundFile = "C2A3_"; break;
case 9: szSoundFile = "C2A4_"; break;
case 10: szSoundFile = "C2A5_"; break;
case 11: szSoundFile = "C3A1_"; break;
case 12: szSoundFile = "C3A2_"; break;
}
} else
szSoundFile = (char*) STRING( m_iszMessage );
if (szSoundFile[0] == '!')
{
// play single sentence, one shot
UTIL_EmitAmbientSound ( GetSoundSourceIndex(), GetAbsOrigin(), szSoundFile,
flvolume, SNDLVL_120dB, flags, pitch);
// shut off and reset
SetNextThink( TICK_NEVER_THINK );
}
else
{
// make random announcement from sentence group
if ( SENTENCEG_PlayRndSz( edict(), szSoundFile, flvolume, SNDLVL_120dB, flags, pitch) < 0 )
Msg( "Level Design Error!\nSPEAKER has bad sentence group name: %s\n",szSoundFile);
// set next announcement time for random 5 to 10 minute delay
SetNextThink ( gpGlobals->curtime +
random->RandomFloat( ANNOUNCE_MINUTES_MIN * 60.0, ANNOUNCE_MINUTES_MAX * 60.0 ) );
// time delay until it's ok to speak: used so that two NPCs don't talk at once
g_AIFriendliesTalkSemaphore.Acquire( 5, this );
g_AIFoesTalkSemaphore.Acquire( 5, this );
}
return;
}
//
// ToggleUse - if an announcement is pending, cancel it. If no announcement is pending, start one.
//
void CSpeaker::ToggleUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
int fActive = (GetNextThink() > 0.0);
// fActive is TRUE only if an announcement is pending
if ( useType != USE_TOGGLE )
{
// ignore if we're just turning something on that's already on, or
// turning something off that's already off.
if ( (fActive && useType == USE_ON) || (!fActive && useType == USE_OFF) )
return;
}
if ( useType == USE_ON )
{
// turn on announcements
SetNextThink( gpGlobals->curtime + 0.1 );
return;
}
if ( useType == USE_OFF )
{
// turn off announcements
SetNextThink( TICK_NEVER_THINK );
return;
}
// Toggle announcements
if ( fActive )
{
// turn off announcements
SetNextThink( TICK_NEVER_THINK );
}
else
{
// turn on announcements
SetNextThink( gpGlobals->curtime + 0.1 );
}
}
// KeyValue - load keyvalue pairs into member data
// NOTE: called BEFORE spawn!
bool CSpeaker::KeyValue( const char *szKeyName, const char *szValue )
{
// preset
if (FStrEq(szKeyName, "preset"))
{
m_preset = atoi(szValue);
return true;
}
else
return BaseClass::KeyValue( szKeyName, szValue );
}
+55
View File
@@ -0,0 +1,55 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "../EventLog.h"
class CHL1EventLog : public CEventLog
{
private:
typedef CEventLog BaseClass;
public:
virtual ~CHL1EventLog() {};
public:
bool PrintEvent( IGameEvent * event ) // override virtual function
{
if ( BaseClass::PrintEvent( event ) )
{
return true;
}
if ( Q_strcmp(event->GetName(), "hl1_") == 0 )
{
return PrintHL1Event( event );
}
return false;
}
protected:
bool PrintHL1Event( IGameEvent * event ) // print Mod specific logs
{
// const char * name = event->GetName() + Q_strlen("hl1_"); // remove prefix
return false;
}
};
CHL1EventLog g_HL1EventLog;
//-----------------------------------------------------------------------------
// Singleton access
//-----------------------------------------------------------------------------
IGameSystem* GameLogSystem()
{
return &g_HL1EventLog;
}
+239
View File
@@ -0,0 +1,239 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
/*
===== h_battery.cpp ========================================================
battery-related code
*/
#include "cbase.h"
#include "gamerules.h"
#include "player.h"
#include "engine/IEngineSound.h"
#include "in_buttons.h"
ConVar sk_suitcharger( "sk_suitcharger","0" );
#define HL1_MAX_ARMOR 100
class CRecharge : public CBaseToggle
{
public:
DECLARE_CLASS( CRecharge, CBaseToggle );
void Spawn( );
virtual void Precache();
bool CreateVPhysics();
void Off(void);
void Recharge(void);
bool KeyValue( const char *szKeyName, const char *szValue );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int ObjectCaps( void ) { return (BaseClass::ObjectCaps() | m_iCaps ); }
DECLARE_DATADESC();
float m_flNextCharge;
int m_iReactivate ; // DeathMatch Delay until reactvated
int m_iJuice;
int m_iOn; // 0 = off, 1 = startup, 2 = going
float m_flSoundTime;
int m_iCaps;
COutputFloat m_OutRemainingCharge;
};
BEGIN_DATADESC( CRecharge )
DEFINE_FIELD( m_flNextCharge, FIELD_TIME ),
DEFINE_FIELD( m_iReactivate, FIELD_INTEGER),
DEFINE_FIELD( m_iJuice, FIELD_INTEGER),
DEFINE_FIELD( m_iOn, FIELD_INTEGER),
DEFINE_FIELD( m_flSoundTime, FIELD_TIME ),
DEFINE_FIELD( m_iCaps, FIELD_INTEGER ),
// Function Pointers
DEFINE_FUNCTION( Off ),
DEFINE_FUNCTION( Recharge ),
DEFINE_OUTPUT(m_OutRemainingCharge, "OutRemainingCharge"),
END_DATADESC()
LINK_ENTITY_TO_CLASS(func_recharge, CRecharge);
bool CRecharge::KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq(szKeyName, "style") ||
FStrEq(szKeyName, "height") ||
FStrEq(szKeyName, "value1") ||
FStrEq(szKeyName, "value2") ||
FStrEq(szKeyName, "value3"))
{
}
else if (FStrEq(szKeyName, "dmdelay"))
{
m_iReactivate = atoi(szValue);
}
else
return BaseClass::KeyValue( szKeyName, szValue );
return true;
}
void CRecharge::Spawn()
{
Precache( );
SetSolid( SOLID_BSP );
SetMoveType( MOVETYPE_PUSH );
SetModel( STRING( GetModelName() ) );
m_iJuice = sk_suitcharger.GetFloat();
SetTextureFrameIndex( 0 );
m_iCaps = FCAP_CONTINUOUS_USE;
CreateVPhysics();
}
void CRecharge::Precache()
{
BaseClass::Precache();
PrecacheScriptSound( "SuitRecharge.Deny" );
PrecacheScriptSound( "SuitRecharge.Start" );
PrecacheScriptSound( "SuitRecharge.ChargingLoop" );
}
bool CRecharge::CreateVPhysics()
{
VPhysicsInitStatic();
return true;
}
void CRecharge::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
// Make sure that we have a caller
if (!pActivator)
return;
// if it's not a player, ignore
if ( !pActivator->IsPlayer() )
return;
CBasePlayer *pPlayer = dynamic_cast<CBasePlayer *>( pActivator );
if ( pPlayer == NULL )
return;
// Reset to a state of continuous use.
m_iCaps = FCAP_CONTINUOUS_USE;
// if there is no juice left, turn it off
if (m_iJuice <= 0)
{
SetTextureFrameIndex( 1 );
Off();
}
// if the player doesn't have the suit, or there is no juice left, make the deny noise
if ( m_iJuice <= 0 )
{
if (m_flSoundTime <= gpGlobals->curtime)
{
m_flSoundTime = gpGlobals->curtime + 0.62;
EmitSound( "SuitRecharge.Deny" );
}
return;
}
// If we're over our limit, debounce our keys
if ( pPlayer->ArmorValue() >= HL1_MAX_ARMOR)
{
// Make the user re-use me to get started drawing health.
pPlayer->m_afButtonPressed &= ~IN_USE;
m_iCaps = FCAP_IMPULSE_USE;
EmitSound( "SuitRecharge.Deny" );
return;
}
SetNextThink( gpGlobals->curtime + 0.25 );
SetThink(&CRecharge::Off);
// Time to recharge yet?
if (m_flNextCharge >= gpGlobals->curtime)
return;
m_hActivator = pActivator;
// Play the on sound or the looping charging sound
if (!m_iOn)
{
m_iOn++;
EmitSound( "SuitRecharge.Start" );
m_flSoundTime = 0.56 + gpGlobals->curtime;
}
if ((m_iOn == 1) && (m_flSoundTime <= gpGlobals->curtime))
{
m_iOn++;
CPASAttenuationFilter filter( this, "SuitRecharge.ChargingLoop" );
filter.MakeReliable();
EmitSound( filter, entindex(), "SuitRecharge.ChargingLoop" );
}
CBasePlayer *pl = (CBasePlayer *) m_hActivator.Get();
// charge the player
if (pl->ArmorValue() < HL1_MAX_ARMOR)
{
m_iJuice--;
pl->IncrementArmorValue( 1, HL1_MAX_ARMOR );
}
// Send the output.
float flRemaining = m_iJuice / sk_suitcharger.GetFloat();
m_OutRemainingCharge.Set(flRemaining, pActivator, this);
// govern the rate of charge
m_flNextCharge = gpGlobals->curtime + 0.1;
}
void CRecharge::Recharge(void)
{
m_iJuice = sk_suitcharger.GetFloat();
SetTextureFrameIndex( 0 );
SetThink( &CBaseEntity::SUB_DoNothing );
}
void CRecharge::Off(void)
{
// Stop looping sound.
if (m_iOn > 1)
{
StopSound( "SuitRecharge.ChargingLoop" );
}
m_iOn = 0;
if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHEVChargerRechargeTime() ) > 0) )
{
SetNextThink( gpGlobals->curtime + m_iReactivate );
SetThink(&CRecharge::Recharge);
}
else
SetThink( NULL );
}
File diff suppressed because it is too large Load Diff
+160
View File
@@ -0,0 +1,160 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "hl1_grenade_mp5.h"
#include "hl1mp_weapon_mp5.h"
#include "soundent.h"
#include "decals.h"
#include "shake.h"
#include "smoke_trail.h"
#include "vstdlib/random.h"
#include "engine/IEngineSound.h"
#include "world.h"
extern short g_sModelIndexFireball;
extern short g_sModelIndexWExplosion;
extern ConVar sk_plr_dmg_mp5_grenade;
extern ConVar sk_max_mp5_grenade;
extern ConVar sk_mp5_grenade_radius;
BEGIN_DATADESC( CGrenadeMP5 )
// SR-BUGBUG: These are borked!!!!
// float m_fSpawnTime;
// Function pointers
DEFINE_ENTITYFUNC( GrenadeMP5Touch ),
DEFINE_FIELD( m_fSpawnTime, FIELD_TIME ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( grenade_mp5, CGrenadeMP5 );
void CGrenadeMP5::Spawn( void )
{
Precache( );
SetSolid( SOLID_BBOX );
SetMoveType( MOVETYPE_FLY );
AddFlag( FL_GRENADE );
SetModel( "models/grenade.mdl" );
//UTIL_SetSize(this, Vector(-3, -3, -3), Vector(3, 3, 3));
UTIL_SetSize(this, Vector(0, 0, 0), Vector(0, 0, 0));
SetUse( &CBaseGrenade::DetonateUse );
SetTouch( &CGrenadeMP5::GrenadeMP5Touch );
SetNextThink( gpGlobals->curtime + 0.1f );
m_flDamage = sk_plr_dmg_mp5_grenade.GetFloat();
m_DmgRadius = sk_mp5_grenade_radius.GetFloat();
m_takedamage = DAMAGE_YES;
m_bIsLive = true;
m_iHealth = 1;
SetGravity( UTIL_ScaleForGravity( 400 ) ); // use a lower gravity for grenades to make them easier to see
SetFriction( 0.8 );
SetSequence( 0 );
m_fSpawnTime = gpGlobals->curtime;
}
void CGrenadeMP5::Event_Killed( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, int bitsDamageType )
{
Detonate( );
}
void CGrenadeMP5::GrenadeMP5Touch( CBaseEntity *pOther )
{
if ( !pOther->IsSolid() )
return;
// If I'm live go ahead and blow up
if (m_bIsLive)
{
Detonate();
}
else
{
// If I'm not live, only blow up if I'm hitting an chacter that
// is not the owner of the weapon
CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pOther );
if (pBCC && GetThrower() != pBCC)
{
m_bIsLive = true;
Detonate();
}
}
}
void CGrenadeMP5::Detonate(void)
{
if (!m_bIsLive)
{
return;
}
m_bIsLive = false;
m_takedamage = DAMAGE_NO;
CPASFilter filter( GetAbsOrigin() );
te->Explosion( filter, 0.0,
&GetAbsOrigin(),
GetWaterLevel() == 0 ? g_sModelIndexFireball : g_sModelIndexWExplosion,
(m_flDamage - 50) * .60,
15,
TE_EXPLFLAG_NONE,
m_DmgRadius,
m_flDamage );
trace_t tr;
tr = CBaseEntity::GetTouchTrace();
if ( (tr.m_pEnt != GetWorldEntity()) || (tr.hitbox != 0) )
{
// non-world needs smaller decals
UTIL_DecalTrace( &tr, "SmallScorch");
}
else
{
UTIL_DecalTrace( &tr, "Scorch" );
}
CSoundEnt::InsertSound ( SOUND_COMBAT, GetAbsOrigin(), BASEGRENADE_EXPLOSION_VOLUME, 3.0 );
RadiusDamage ( CTakeDamageInfo( this, GetThrower(), m_flDamage, DMG_BLAST ), GetAbsOrigin(), m_flDamage * 2.5, CLASS_NONE, NULL );
CPASAttenuationFilter filter2( this );
EmitSound( filter2, entindex(), "GrenadeMP5.Detonate" );
if ( GetWaterLevel() == 0 )
{
int sparkCount = random->RandomInt( 0,3 );
QAngle angles;
VectorAngles( tr.plane.normal, angles );
for ( int i = 0; i < sparkCount; i++ )
Create( "spark_shower", GetAbsOrigin(), angles, NULL );
}
UTIL_Remove( this );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeMP5::Precache( void )
{
BaseClass::Precache();
PrecacheModel( "models/grenade.mdl" );
PrecacheScriptSound( "GrenadeMP5.Detonate" );
}
+42
View File
@@ -0,0 +1,42 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Projectile shot from the MP5
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef GRENADEMP5_H
#define GRENADEMP5_H
#include "hl1_basegrenade.h"
#define MAX_MP5_NO_COLLIDE_TIME 0.2
class SmokeTrail;
class CWeaponMP5;
class CGrenadeMP5 : public CHL1BaseGrenade
{
DECLARE_CLASS( CGrenadeMP5, CHL1BaseGrenade );
public:
float m_fSpawnTime;
void Spawn( void );
void Precache( void );
void GrenadeMP5Touch( CBaseEntity *pOther );
void Event_Killed( CBaseEntity *pInflictor, CBaseEntity *pAttacker, float flDamage, int bitsDamageType );
public:
void EXPORT Detonate(void);
DECLARE_DATADESC();
};
#endif //GRENADEMP5_H
+171
View File
@@ -0,0 +1,171 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "hl1_grenade_spit.h"
#include "soundent.h"
#include "decals.h"
#include "smoke_trail.h"
#include "hl2_shareddefs.h"
#include "vstdlib/random.h"
#include "engine/IEngineSound.h"
ConVar sk_bullsquid_dmg_spit ( "sk_bullsquid_dmg_spit", "0" );
BEGIN_DATADESC( CGrenadeSpit )
// Function pointers
DEFINE_THINKFUNC( SpitThink ),
DEFINE_ENTITYFUNC( GrenadeSpitTouch ),
//DEFINE_FIELD( m_nSquidSpitSprite, FIELD_INTEGER ),
DEFINE_FIELD( m_fSpitDeathTime, FIELD_TIME ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( grenade_spit, CGrenadeSpit );
void CGrenadeSpit::Spawn( void )
{
Precache( );
SetSolid( SOLID_BBOX );
SetMoveType( MOVETYPE_FLYGRAVITY );
// FIXME, if these is a sprite, then we need a base class derived from CSprite rather than
// CBaseAnimating. pev->scale becomes m_flSpriteScale in that case.
SetModel( "models/spitball_large.mdl" );
UTIL_SetSize(this, Vector(-3, -3, -3), Vector(3, 3, 3));
m_nRenderMode = kRenderTransAdd;
SetRenderColor( 255, 255, 255, 255 );
m_nRenderFX = kRenderFxNone;
SetThink( &CGrenadeSpit::SpitThink );
SetUse( &CBaseGrenade::DetonateUse );
SetTouch( &CGrenadeSpit::GrenadeSpitTouch );
SetNextThink( gpGlobals->curtime + 0.1f );
m_flDamage = sk_bullsquid_dmg_spit.GetFloat();
m_DmgRadius = 60.0f;
m_takedamage = DAMAGE_YES;
m_iHealth = 1;
SetGravity( SPIT_GRAVITY );
SetFriction( 0.8 );
SetSequence( 1 );
SetCollisionGroup( HL2COLLISION_GROUP_SPIT );
}
void CGrenadeSpit::SetSpitSize(int nSize)
{
switch (nSize)
{
case SPIT_LARGE:
{
SetModel( "models/spitball_large.mdl" );
break;
}
case SPIT_MEDIUM:
{
SetModel( "models/spitball_medium.mdl" );
break;
}
case SPIT_SMALL:
{
SetModel( "models/spitball_small.mdl" );
break;
}
}
}
void CGrenadeSpit::Event_Killed( const CTakeDamageInfo &info )
{
Detonate( );
}
void CGrenadeSpit::GrenadeSpitTouch( CBaseEntity *pOther )
{
if (m_fSpitDeathTime != 0)
{
return;
}
if ( pOther->GetCollisionGroup() == HL2COLLISION_GROUP_SPIT)
{
return;
}
if ( !pOther->m_takedamage )
{
// make a splat on the wall
trace_t tr;
UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + GetAbsVelocity() * 10, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
UTIL_DecalTrace(&tr, "BeerSplash" );
// make some flecks
CPVSFilter filter( tr.endpos );
te->SpriteSpray( filter, 0.0,
&tr.endpos, &tr.plane.normal, m_nSquidSpitSprite, random->RandomInt( 90, 160 ), 50, random->RandomInt ( 5, 15 ) );
}
else
{
RadiusDamage ( CTakeDamageInfo( this, GetThrower(), m_flDamage, DMG_BLAST ), GetAbsOrigin(), m_DmgRadius, CLASS_NONE, NULL );
}
Detonate();
}
void CGrenadeSpit::SpitThink( void )
{
if (m_fSpitDeathTime != 0 &&
m_fSpitDeathTime < gpGlobals->curtime)
{
UTIL_Remove( this );
}
SetNextThink( gpGlobals->curtime + 0.1f );
}
void CGrenadeSpit::Detonate(void)
{
m_takedamage = DAMAGE_NO;
int iPitch;
// splat sound
iPitch = random->RandomFloat( 90, 110 );
EmitSound( "GrenadeSpit.Acid" );
EmitSound( "GrenadeSpit.Hit" );
UTIL_Remove( this );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeSpit::Precache( void )
{
m_nSquidSpitSprite = PrecacheModel("sprites/bigspit.vmt");// client side spittle.
PrecacheModel("models/spitball_large.mdl");
PrecacheModel("models/spitball_medium.mdl");
PrecacheModel("models/spitball_small.mdl");
PrecacheScriptSound( "GrenadeSpit.Acid" );
PrecacheScriptSound( "GrenadeSpit.Hit" );
}
CGrenadeSpit::CGrenadeSpit(void)
{
}
+49
View File
@@ -0,0 +1,49 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Projectile shot by bullsquid
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef GRENADESPIT_H
#define GRENADESPIT_H
#include "hl1_basegrenade.h"
enum SpitSize_e
{
SPIT_SMALL,
SPIT_MEDIUM,
SPIT_LARGE,
};
#define SPIT_GRAVITY 0.9
class CGrenadeSpit : public CHL1BaseGrenade
{
public:
DECLARE_CLASS( CGrenadeSpit, CHL1BaseGrenade );
void Spawn( void );
void Precache( void );
void SpitThink( void );
void GrenadeSpitTouch( CBaseEntity *pOther );
void Event_Killed( const CTakeDamageInfo &info );
void SetSpitSize(int nSize);
int m_nSquidSpitSprite;
float m_fSpitDeathTime; // If non-zero won't detonate
void EXPORT Detonate(void);
CGrenadeSpit(void);
DECLARE_DATADESC();
};
#endif //GRENADESPIT_H
+410
View File
@@ -0,0 +1,410 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Ammo boxes for HL1
//
//=============================================================================//
#include "cbase.h"
#include "player.h"
#include "gamerules.h"
#include "items.h"
#include "hl1_items.h"
// ========================================================================
// >> Crossbow bolts
// ========================================================================
#define AMMO_CROSSBOW_GIVE 5
#define AMMO_CROSSBOW_MODEL "models/w_crossbow_clip.mdl"
class CCrossbowAmmo : public CHL1Item
{
public:
DECLARE_CLASS( CCrossbowAmmo, CHL1Item );
void Spawn( void )
{
Precache();
SetModel( AMMO_CROSSBOW_MODEL );
BaseClass::Spawn();
}
void Precache( void )
{
PrecacheModel( AMMO_CROSSBOW_MODEL );
}
bool MyTouch( CBasePlayer *pPlayer )
{
if (pPlayer->GiveAmmo( AMMO_CROSSBOW_GIVE, "XBowBolt" ) )
{
if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_NO )
{
UTIL_Remove( this );
}
return true;
}
return false;
}
};
LINK_ENTITY_TO_CLASS(ammo_crossbow, CCrossbowAmmo);
PRECACHE_REGISTER(ammo_crossbow);
// ========================================================================
// >> Egon ammo
// ========================================================================
#define AMMO_EGON_GIVE 20
#define AMMO_EGON_MODEL "models/w_chainammo.mdl"
class CEgonAmmo : public CHL1Item
{
public:
DECLARE_CLASS( CEgonAmmo, CHL1Item );
void Spawn( void )
{
Precache();
SetModel( AMMO_EGON_MODEL );
BaseClass::Spawn();
}
void Precache( void )
{
PrecacheModel ( AMMO_EGON_MODEL );
}
bool MyTouch( CBasePlayer *pPlayer )
{
if (pPlayer->GiveAmmo( AMMO_EGON_GIVE, "Uranium" ) )
{
if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_NO )
{
UTIL_Remove( this );
}
return true;
}
return false;
}
};
LINK_ENTITY_TO_CLASS(ammo_egonclip, CEgonAmmo);
PRECACHE_REGISTER(ammo_egonclip);
// ========================================================================
// >> Gauss ammo
// ========================================================================
#define AMMO_GAUSS_GIVE 20
#define AMMO_GAUSS_MODEL "models/w_gaussammo.mdl"
class CGaussAmmo : public CHL1Item
{
public:
DECLARE_CLASS( CGaussAmmo, CHL1Item );
void Spawn( void )
{
Precache();
SetModel( AMMO_GAUSS_MODEL );
BaseClass::Spawn();
}
void Precache( void )
{
PrecacheModel ( AMMO_GAUSS_MODEL );
}
bool MyTouch( CBasePlayer *pPlayer )
{
if (pPlayer->GiveAmmo( AMMO_GAUSS_GIVE, "Uranium" ) )
{
if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_NO )
{
UTIL_Remove( this );
}
return true;
}
return false;
}
};
LINK_ENTITY_TO_CLASS(ammo_gaussclip, CGaussAmmo);
PRECACHE_REGISTER(ammo_gaussclip);
// ========================================================================
// >> Glock ammo
// ========================================================================
#define AMMO_GLOCK_GIVE 18
#define AMMO_GLOCK_MODEL "models/w_9mmclip.mdl"
class CGlockAmmo : public CHL1Item
{
public:
DECLARE_CLASS( CGlockAmmo, CHL1Item );
void Spawn( void )
{
Precache();
SetModel( AMMO_GLOCK_MODEL );
BaseClass::Spawn();
}
void Precache( void )
{
PrecacheModel ( AMMO_GLOCK_MODEL );
}
bool MyTouch( CBasePlayer *pPlayer )
{
if (pPlayer->GiveAmmo( AMMO_GLOCK_GIVE, "9mmRound" ) )
{
if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_NO )
{
UTIL_Remove( this );
}
return true;
}
return false;
}
};
LINK_ENTITY_TO_CLASS(ammo_glockclip, CGlockAmmo);
PRECACHE_REGISTER(ammo_glockclip);
LINK_ENTITY_TO_CLASS(ammo_9mmclip, CGlockAmmo);
PRECACHE_REGISTER(ammo_9mmclip);
// ========================================================================
// >> MP5 ammo
// ========================================================================
#define AMMO_MP5_GIVE 50
#define AMMO_MP5_MODEL "models/w_9mmARclip.mdl"
class CMP5AmmoClip : public CHL1Item
{
public:
DECLARE_CLASS( CMP5AmmoClip, CHL1Item );
void Spawn( void )
{
Precache();
SetModel( AMMO_MP5_MODEL );
BaseClass::Spawn();
}
void Precache( void )
{
PrecacheModel ( AMMO_MP5_MODEL );
}
bool MyTouch( CBasePlayer *pPlayer )
{
if (pPlayer->GiveAmmo( AMMO_MP5_GIVE, "9mmRound" ) )
{
if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_NO )
{
UTIL_Remove( this );
}
return true;
}
return false;
}
};
LINK_ENTITY_TO_CLASS(ammo_mp5clip, CMP5AmmoClip);
PRECACHE_REGISTER(ammo_mp5clip);
LINK_ENTITY_TO_CLASS(ammo_9mmar, CMP5AmmoClip);
PRECACHE_REGISTER(ammo_9mmar);
// ========================================================================
// >> MP5Chain (?) ammo
// ========================================================================
#define AMMO_MP5CHAIN_GIVE 200
#define AMMO_MP5CHAIN_MODEL "models/w_chainammo.mdl"
class CMP5Chainammo : public CHL1Item
{
public:
DECLARE_CLASS( CMP5Chainammo, CHL1Item );
void Spawn( void )
{
Precache();
SetModel( AMMO_MP5CHAIN_MODEL );
BaseClass::Spawn();
}
void Precache( void )
{
PrecacheModel ( AMMO_MP5CHAIN_MODEL );
}
bool MyTouch( CBasePlayer *pPlayer )
{
if (pPlayer->GiveAmmo( AMMO_MP5CHAIN_GIVE, "9mmRound" ) )
{
if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_NO )
{
UTIL_Remove( this );
}
return true;
}
return false;
}
};
LINK_ENTITY_TO_CLASS(ammo_9mmbox, CMP5Chainammo);
PRECACHE_REGISTER(ammo_9mmbox);
// ========================================================================
// >> MP5 grenades
// ========================================================================
#define AMMO_MP5GRENADE_GIVE 2
#define AMMO_MP5GRENADE_MODEL "models/w_ARgrenade.mdl"
class CMP5AmmoGrenade : public CHL1Item
{
public:
DECLARE_CLASS( CMP5AmmoGrenade, CHL1Item );
void Spawn( void )
{
Precache();
SetModel( AMMO_MP5GRENADE_MODEL );
BaseClass::Spawn();
}
void Precache( void )
{
PrecacheModel ( AMMO_MP5GRENADE_MODEL );
}
bool MyTouch( CBasePlayer *pPlayer )
{
if (pPlayer->GiveAmmo( AMMO_MP5GRENADE_GIVE, "MP5_Grenade" ) )
{
if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_NO )
{
UTIL_Remove( this );
}
return true;
}
return false;
}
};
LINK_ENTITY_TO_CLASS(ammo_mp5grenades, CMP5AmmoGrenade);
PRECACHE_REGISTER(ammo_mp5grenades);
LINK_ENTITY_TO_CLASS(ammo_argrenades, CMP5AmmoGrenade);
PRECACHE_REGISTER(ammo_argrenades);
// ========================================================================
// >> 357 ammo
// ========================================================================
#define AMMO_357_GIVE 6
#define AMMO_357_MODEL "models/w_357ammobox.mdl"
class CPythonAmmo : public CHL1Item
{
public:
DECLARE_CLASS( CPythonAmmo, CHL1Item );
void Spawn( void )
{
Precache();
SetModel( AMMO_357_MODEL );
BaseClass::Spawn();
}
void Precache( void )
{
PrecacheModel ( AMMO_357_MODEL );
}
bool MyTouch( CBasePlayer *pPlayer )
{
if (pPlayer->GiveAmmo( AMMO_357_GIVE, "357Round" ) )
{
if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_NO )
{
UTIL_Remove( this );
}
return true;
}
return false;
}
};
LINK_ENTITY_TO_CLASS(ammo_357, CPythonAmmo);
PRECACHE_REGISTER(ammo_357);
// ========================================================================
// >> RPG rockets
// ========================================================================
#define AMMO_RPG_GIVE 1
#define AMMO_RPG_MODEL "models/w_rpgammo.mdl"
class CRpgAmmo : public CHL1Item
{
public:
DECLARE_CLASS( CRpgAmmo, CHL1Item );
void Spawn( void )
{
Precache();
SetModel( AMMO_RPG_MODEL );
BaseClass::Spawn();
}
void Precache( void )
{
PrecacheModel ( AMMO_RPG_MODEL );
}
bool MyTouch( CBasePlayer *pPlayer )
{
int nGive;
if ( g_pGameRules->IsMultiplayer() )
{
// hand out more ammo per rocket in multiplayer.
nGive = AMMO_RPG_GIVE * 2;
}
else
{
nGive = AMMO_RPG_GIVE;
}
if (pPlayer->GiveAmmo( nGive, "RPG_Rocket" ) )
{
if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_NO )
{
UTIL_Remove( this );
}
return true;
}
return false;
}
};
LINK_ENTITY_TO_CLASS(ammo_rpgclip, CRpgAmmo);
PRECACHE_REGISTER(ammo_rpgclip);
// ========================================================================
// >> Shotgun ammo
// ========================================================================
#define AMMO_SHOTGUN_GIVE 12
#define AMMO_SHOTGUN_MODEL "models/w_shotbox.mdl"
class CShotgunAmmo : public CHL1Item
{
public:
DECLARE_CLASS( CShotgunAmmo, CHL1Item );
void Spawn( void )
{
Precache();
SetModel( AMMO_SHOTGUN_MODEL );
BaseClass::Spawn();
}
void Precache( void )
{
PrecacheModel ( AMMO_SHOTGUN_MODEL );
}
bool MyTouch( CBasePlayer *pPlayer )
{
if (pPlayer->GiveAmmo( AMMO_SHOTGUN_GIVE, "Buckshot" ) )
{
if ( g_pGameRules->ItemShouldRespawn( this ) == GR_ITEM_RESPAWN_NO )
{
UTIL_Remove( this );
}
return true;
}
return false;
}
};
LINK_ENTITY_TO_CLASS(ammo_buckshot, CShotgunAmmo);
PRECACHE_REGISTER(ammo_buckshot);
+78
View File
@@ -0,0 +1,78 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Handling for the suit batteries.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "player.h"
#include "basecombatweapon.h"
#include "gamerules.h"
#include "items.h"
#include "engine/IEngineSound.h"
#include "hl1_items.h"
#define BATTERY_MODEL "models/w_battery.mdl"
ConVar sk_battery( "sk_battery","0" );
class CItemBattery : public CHL1Item
{
public:
DECLARE_CLASS( CItemBattery, CHL1Item );
void Spawn( void )
{
Precache( );
SetModel( BATTERY_MODEL );
BaseClass::Spawn( );
}
void Precache( void )
{
PrecacheModel( BATTERY_MODEL );
PrecacheScriptSound( "Item.Pickup" );
}
bool MyTouch( CBasePlayer *pPlayer )
{
if ((pPlayer->ArmorValue() < MAX_NORMAL_BATTERY) && pPlayer->IsSuitEquipped())
{
int pct;
char szcharge[64];
pPlayer->IncrementArmorValue( sk_battery.GetFloat(), MAX_NORMAL_BATTERY );
CPASAttenuationFilter filter( pPlayer, "Item.Pickup" );
EmitSound( filter, pPlayer->entindex(), "Item.Pickup" );
CSingleUserRecipientFilter user( pPlayer );
user.MakeReliable();
UserMessageBegin( user, "ItemPickup" );
WRITE_STRING( GetClassname() );
MessageEnd();
// Suit reports new power level
// For some reason this wasn't working in release build -- round it.
pct = (int)( (float)(pPlayer->ArmorValue() * 100.0) * (1.0/MAX_NORMAL_BATTERY) + 0.5);
pct = (pct / 5);
if (pct > 0)
pct--;
Q_snprintf( szcharge,sizeof(szcharge),"!HEV_%1dP", pct );
//UTIL_EmitSoundSuit(edict(), szcharge);
pPlayer->SetSuitUpdate(szcharge, FALSE, SUIT_NEXT_IN_30SEC);
return true;
}
return false;
}
};
LINK_ENTITY_TO_CLASS(item_battery, CItemBattery);
PRECACHE_REGISTER(item_battery);
+384
View File
@@ -0,0 +1,384 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "gamerules.h"
#include "player.h"
#include "items.h"
#include "engine/IEngineSound.h"
#include "hl1_items.h"
#include "in_buttons.h"
ConVar sk_healthkit( "sk_healthkit","0" );
ConVar sk_healthvial( "sk_healthvial","0" );
ConVar sk_healthcharger( "sk_healthcharger","0" );
//-----------------------------------------------------------------------------
// Small health kit. Heals the player when picked up.
//-----------------------------------------------------------------------------
class CHealthKit : public CHL1Item
{
public:
DECLARE_CLASS( CHealthKit, CHL1Item );
void Spawn( void );
void Precache( void );
bool MyTouch( CBasePlayer *pPlayer );
};
LINK_ENTITY_TO_CLASS( item_healthkit, CHealthKit );
PRECACHE_REGISTER(item_healthkit);
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHealthKit::Spawn( void )
{
Precache();
SetModel( "models/w_medkit.mdl" );
BaseClass::Spawn();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHealthKit::Precache( void )
{
PrecacheModel("models/w_medkit.mdl");
PrecacheScriptSound( "HealthKit.Touch" );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pPlayer -
// Output :
//-----------------------------------------------------------------------------
bool CHealthKit::MyTouch( CBasePlayer *pPlayer )
{
if ( pPlayer->TakeHealth( sk_healthkit.GetFloat(), DMG_GENERIC ) )
{
CSingleUserRecipientFilter user( pPlayer );
user.MakeReliable();
UserMessageBegin( user, "ItemPickup" );
WRITE_STRING( GetClassname() );
MessageEnd();
CPASAttenuationFilter filter( pPlayer, "HealthKit.Touch" );
EmitSound( filter, pPlayer->entindex(), "HealthKit.Touch" );
if ( g_pGameRules->ItemShouldRespawn( this ) )
{
Respawn();
}
else
{
UTIL_Remove(this);
}
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Small dynamically dropped health kit
//-----------------------------------------------------------------------------
class CHealthVial : public CHL1Item
{
public:
DECLARE_CLASS( CHealthVial, CHL1Item );
void Spawn( void )
{
Precache();
SetModel( "models/healthvial.mdl" );
BaseClass::Spawn();
}
void Precache( void )
{
PrecacheModel("models/healthvial.mdl");
PrecacheScriptSound( "HealthVial.Touch" );
}
bool MyTouch( CBasePlayer *pPlayer )
{
if ( pPlayer->TakeHealth( sk_healthvial.GetFloat(), DMG_GENERIC ) )
{
CSingleUserRecipientFilter user( pPlayer );
user.MakeReliable();
UserMessageBegin( user, "ItemPickup" );
WRITE_STRING( GetClassname() );
MessageEnd();
CPASAttenuationFilter filter( pPlayer, "HealthVial.Touch" );
EmitSound( filter, pPlayer->entindex(), "HealthVial.Touch" );
if ( g_pGameRules->ItemShouldRespawn( this ) )
{
Respawn();
}
else
{
UTIL_Remove(this);
}
return true;
}
return false;
}
};
LINK_ENTITY_TO_CLASS( item_healthvial, CHealthVial );
PRECACHE_REGISTER( item_healthvial );
//-----------------------------------------------------------------------------
// Wall mounted health kit. Heals the player when used.
//-----------------------------------------------------------------------------
class CWallHealth : public CBaseToggle
{
public:
DECLARE_CLASS( CWallHealth, CBaseToggle );
void Spawn( );
void Precache( void );
bool CreateVPhysics(void);
void Off(void);
void Recharge(void);
bool KeyValue( const char *szKeyName, const char *szValue );
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() | m_iCaps; }
float m_flNextCharge;
int m_iReactivate ; // DeathMatch Delay until reactvated
int m_iJuice;
int m_iOn; // 0 = off, 1 = startup, 2 = going
float m_flSoundTime;
int m_iCaps;
DECLARE_DATADESC();
};
LINK_ENTITY_TO_CLASS(func_healthcharger, CWallHealth);
BEGIN_DATADESC( CWallHealth )
DEFINE_FIELD( m_flNextCharge, FIELD_TIME),
DEFINE_FIELD( m_iReactivate, FIELD_INTEGER),
DEFINE_FIELD( m_iJuice, FIELD_INTEGER),
DEFINE_FIELD( m_iOn, FIELD_INTEGER),
DEFINE_FIELD( m_flSoundTime, FIELD_TIME),
DEFINE_FIELD( m_iCaps, FIELD_INTEGER ),
// Function Pointers
DEFINE_FUNCTION( Off ),
DEFINE_FUNCTION( Recharge ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pkvd -
//-----------------------------------------------------------------------------
bool CWallHealth::KeyValue( const char *szKeyName, const char *szValue )
{
if (FStrEq(szKeyName, "style") ||
FStrEq(szKeyName, "height") ||
FStrEq(szKeyName, "value1") ||
FStrEq(szKeyName, "value2") ||
FStrEq(szKeyName, "value3"))
{
return(true);
}
else if (FStrEq(szKeyName, "dmdelay"))
{
m_iReactivate = atoi(szValue);
return(true);
}
return(BaseClass::KeyValue( szKeyName, szValue ));
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWallHealth::Spawn(void)
{
Precache( );
SetSolid( SOLID_BSP );
SetMoveType( MOVETYPE_PUSH );
SetModel( STRING( GetModelName() ) );
m_iJuice = sk_healthcharger.GetFloat();
SetTextureFrameIndex( 0 );
m_iCaps = FCAP_CONTINUOUS_USE;
CreateVPhysics();
}
//-----------------------------------------------------------------------------
bool CWallHealth::CreateVPhysics(void)
{
VPhysicsInitStatic();
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWallHealth::Precache(void)
{
PrecacheScriptSound( "WallHealth.Deny" );
PrecacheScriptSound( "WallHealth.Start" );
PrecacheScriptSound( "WallHealth.LoopingContinueCharge" );
PrecacheScriptSound( "WallHealth.Recharge" );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pActivator -
// *pCaller -
// useType -
// value -
//-----------------------------------------------------------------------------
void CWallHealth::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
// Make sure that we have a caller
if (!pActivator)
return;
// if it's not a player, ignore
if ( !pActivator->IsPlayer() )
return;
// Reset to a state of continuous use.
m_iCaps = FCAP_CONTINUOUS_USE;
// if there is no juice left, turn it off
if (m_iJuice <= 0)
{
Off();
SetTextureFrameIndex( 1 );
}
CBasePlayer *pPlayer = ToBasePlayer( pActivator );
// if the player doesn't have the suit, or there is no juice left, make the deny noise.
if ((m_iJuice <= 0) || (!(pPlayer->m_Local.m_bWearingSuit)))
{
if (m_flSoundTime <= gpGlobals->curtime)
{
m_flSoundTime = gpGlobals->curtime + 0.62;
EmitSound( "WallHealth.Deny" );
}
return;
}
if( pActivator->GetHealth() >= pActivator->GetMaxHealth() )
{
CBasePlayer *pPlayer = dynamic_cast<CBasePlayer *>(pActivator);
if( pPlayer )
{
pPlayer->m_afButtonPressed &= ~IN_USE;
}
// Make the user re-use me to get started drawing health.
m_iCaps = FCAP_IMPULSE_USE;
EmitSound( "WallHealth.Deny" );
return;
}
SetNextThink( gpGlobals->curtime + 0.25 );
SetThink(&CWallHealth::Off);
// Time to recharge yet?
if (m_flNextCharge >= gpGlobals->curtime)
return;
// Play the on sound or the looping charging sound
if (!m_iOn)
{
m_iOn++;
EmitSound( "WallHealth.Start" );
m_flSoundTime = 0.56 + gpGlobals->curtime;
}
if ((m_iOn == 1) && (m_flSoundTime <= gpGlobals->curtime))
{
m_iOn++;
CPASAttenuationFilter filter( this, "WallHealth.LoopingContinueCharge" );
filter.MakeReliable();
EmitSound( filter, entindex(), "WallHealth.LoopingContinueCharge" );
}
// charge the player
if ( pActivator->TakeHealth( 1, DMG_GENERIC ) )
{
m_iJuice--;
}
// govern the rate of charge
m_flNextCharge = gpGlobals->curtime + 0.1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWallHealth::Recharge(void)
{
EmitSound( "WallHealth.Recharge" );
m_iJuice = sk_healthcharger.GetFloat();
SetTextureFrameIndex( 0 );
SetThink( NULL );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWallHealth::Off(void)
{
// Stop looping sound.
if (m_iOn > 1)
StopSound( "WallHealth.LoopingContinueCharge" );
m_iOn = 0;
if ((!m_iJuice) && ( ( m_iReactivate = g_pGameRules->FlHealthChargerRechargeTime() ) > 0) )
{
SetNextThink( gpGlobals->curtime + m_iReactivate );
SetThink(&CWallHealth::Recharge);
}
else
SetThink( NULL );
}
+61
View File
@@ -0,0 +1,61 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "player.h"
#include "gamerules.h"
#include "items.h"
#include "hl1_items.h"
#include "hl1_player.h"
class CItemLongJump : public CHL1Item
{
public:
DECLARE_CLASS( CItemLongJump, CHL1Item );
void Spawn( void )
{
Precache( );
SetModel( "models/w_longjump.mdl" );
BaseClass::Spawn( );
CollisionProp()->UseTriggerBounds( true, 16.0f );
}
void Precache( void )
{
PrecacheModel ("models/w_longjump.mdl");
}
bool MyTouch( CBasePlayer *pPlayer )
{
CHL1_Player *pHL1Player = (CHL1_Player*)pPlayer;
if ( pHL1Player->m_bHasLongJump == true )
{
return false;
}
if ( pHL1Player->IsSuitEquipped() )
{
pHL1Player->m_bHasLongJump = true;// player now has longjump module
CSingleUserRecipientFilter user( pHL1Player );
user.MakeReliable();
UserMessageBegin( user, "ItemPickup" );
WRITE_STRING( STRING(m_iClassname) );
MessageEnd();
UTIL_EmitSoundSuit( pHL1Player->edict(), "!HEV_A1" ); // Play the longjump sound UNDONE: Kelly? correct sound?
return true;
}
return false;
}
};
LINK_ENTITY_TO_CLASS( item_longjump, CItemLongJump );
PRECACHE_REGISTER(item_longjump);
+61
View File
@@ -0,0 +1,61 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
/*
===== item_suit.cpp ========================================================
handling for the player's suit.
*/
#include "cbase.h"
#include "player.h"
#include "gamerules.h"
#include "items.h"
#include "hl1_items.h"
#define SF_SUIT_SHORTLOGON 0x0001
#define SUIT_MODEL "models/w_suit.mdl"
extern int gEvilImpulse101;
class CItemSuit : public CHL1Item
{
public:
DECLARE_CLASS( CItemSuit, CHL1Item );
void Spawn( void )
{
Precache( );
SetModel( SUIT_MODEL );
BaseClass::Spawn( );
CollisionProp()->UseTriggerBounds( true, 12.0f );
}
void Precache( void )
{
PrecacheModel( SUIT_MODEL );
}
bool MyTouch( CBasePlayer *pPlayer )
{
if ( pPlayer->IsSuitEquipped() )
return false;
if( !gEvilImpulse101 )
{
if ( HasSpawnFlags( SF_SUIT_SHORTLOGON ) )
UTIL_EmitSoundSuit(pPlayer->edict(), "!HEV_A0"); // short version of suit logon,
else
UTIL_EmitSoundSuit(pPlayer->edict(), "!HEV_AAx"); // long version of suit logon
}
pPlayer->EquipSuit();
return true;
}
};
LINK_ENTITY_TO_CLASS(item_suit, CItemSuit);
PRECACHE_REGISTER(item_suit);
+45
View File
@@ -0,0 +1,45 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "player.h"
#include "items.h"
#include "gamerules.h"
#include "hl1_items.h"
void CHL1Item::Spawn( void )
{
SetMoveType( MOVETYPE_FLYGRAVITY );
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_NOT_STANDABLE | FSOLID_TRIGGER );
CollisionProp()->UseTriggerBounds( true, 24.0f );
SetCollisionGroup( COLLISION_GROUP_DEBRIS );
SetTouch( &CItem::ItemTouch );
#ifdef HL1_DLL
if ( g_pGameRules->IsMultiplayer() )
AddEffects( EF_NOSHADOW );
#endif
}
void CHL1Item::Activate( void )
{
BaseClass::Activate();
if ( UTIL_DropToFloor( this, MASK_SOLID ) == 0 )
{
Warning( "Item %s fell out of level at %f,%f,%f\n", GetClassname(), GetAbsOrigin().x, GetAbsOrigin().y, GetAbsOrigin().z);
UTIL_Remove( this );
return;
}
}
+26
View File
@@ -0,0 +1,26 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef HL1_ITEMS_H
#define HL1_ITEMS_H
#ifdef _WIN32
#pragma once
#endif
#include "items.h"
class CHL1Item : public CItem
{
public:
DECLARE_CLASS( CHL1Item, CItem );
void Spawn( void );
void Activate( void );
};
#endif // HL1_ITEMS_H
+294
View File
@@ -0,0 +1,294 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: An entity that creates NPCs in the game.
//
//=============================================================================//
#include "cbase.h"
#include "entityapi.h"
#include "entityoutput.h"
#include "ai_basenpc.h"
#include "hl1_monstermaker.h"
#include "mapentities.h"
BEGIN_DATADESC( CNPCMaker )
DEFINE_KEYFIELD( m_iMaxNumNPCs, FIELD_INTEGER, "monstercount" ),
DEFINE_KEYFIELD( m_iMaxLiveChildren, FIELD_INTEGER, "MaxLiveChildren" ),
DEFINE_KEYFIELD( m_flSpawnFrequency, FIELD_FLOAT, "delay" ),
DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ),
DEFINE_KEYFIELD( m_iszNPCClassname, FIELD_STRING, "monstertype" ),
DEFINE_FIELD( m_cLiveChildren, FIELD_INTEGER ),
DEFINE_FIELD( m_flGround, FIELD_FLOAT ),
// Inputs
DEFINE_INPUTFUNC( FIELD_VOID, "Spawn", InputSpawnNPC ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
// Outputs
DEFINE_OUTPUT( m_OnSpawnNPC, "OnSpawnNPC" ),
// Function Pointers
DEFINE_THINKFUNC( MakerThink ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( monstermaker, CNPCMaker );
//-----------------------------------------------------------------------------
// Purpose: Spawn
//-----------------------------------------------------------------------------
void CNPCMaker::Spawn( void )
{
SetSolid( SOLID_NONE );
m_cLiveChildren = 0;
Precache();
// If I can make an infinite number of NPC, force them to fade
if ( m_spawnflags & SF_NPCMAKER_INF_CHILD )
{
m_spawnflags |= SF_NPCMAKER_FADE;
}
//Start on?
if ( m_bDisabled == false )
{
SetThink ( &CNPCMaker::MakerThink );
SetNextThink( gpGlobals->curtime + m_flSpawnFrequency );
}
else
{
//wait to be activated.
SetThink ( &CBaseEntity::SUB_DoNothing );
}
m_flGround = 0;
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether or not it is OK to make an NPC at this instant.
//-----------------------------------------------------------------------------
bool CNPCMaker::CanMakeNPC( void )
{
if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren )
{// not allowed to make a new one yet. Too many live ones out right now.
return false;
}
if ( !m_flGround )
{
// set altitude. Now that I'm activated, any breakables, etc should be out from under me.
trace_t tr;
UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() - Vector ( 0, 0, 2048 ), MASK_NPCSOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
m_flGround = tr.endpos.z;
}
Vector mins = GetAbsOrigin() - Vector( 34, 34, 0 );
Vector maxs = GetAbsOrigin() + Vector( 34, 34, 0 );
maxs.z = GetAbsOrigin().z;
//Only adjust for the ground if we want it
if ( ( m_spawnflags & SF_NPCMAKER_NO_DROP ) == false )
{
mins.z = m_flGround;
}
CBaseEntity *pList[128];
int count = UTIL_EntitiesInBox( pList, 128, mins, maxs, FL_CLIENT|FL_NPC );
if ( count )
{
//Iterate through the list and check the results
for ( int i = 0; i < count; i++ )
{
//Don't build on top of another entity
if ( pList[i] == NULL )
continue;
//If one of the entities is solid, then we can't spawn now
if ( ( pList[i]->GetSolidFlags() & FSOLID_NOT_SOLID ) == false )
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: If this had a finite number of children, return true if they've all
// been created.
//-----------------------------------------------------------------------------
bool CNPCMaker::IsDepleted()
{
if ( (m_spawnflags & SF_NPCMAKER_INF_CHILD) || m_iMaxNumNPCs > 0 )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Toggle the spawner's state
//-----------------------------------------------------------------------------
void CNPCMaker::Toggle( void )
{
if ( m_bDisabled )
{
Enable();
}
else
{
Disable();
}
}
//-----------------------------------------------------------------------------
// Purpose: Start the spawner
//-----------------------------------------------------------------------------
void CNPCMaker::Enable( void )
{
// can't be enabled once depleted
if ( IsDepleted() )
return;
m_bDisabled = false;
SetThink ( &CNPCMaker::MakerThink );
SetNextThink( gpGlobals->curtime );
}
//-----------------------------------------------------------------------------
// Purpose: Stop the spawner
//-----------------------------------------------------------------------------
void CNPCMaker::Disable( void )
{
m_bDisabled = true;
SetThink ( NULL );
}
//-----------------------------------------------------------------------------
// Purpose: Input handler that spawns an NPC.
//-----------------------------------------------------------------------------
void CNPCMaker::InputSpawnNPC( inputdata_t &inputdata )
{
MakeNPC();
}
//-----------------------------------------------------------------------------
// Purpose: Input hander that starts the spawner
//-----------------------------------------------------------------------------
void CNPCMaker::InputEnable( inputdata_t &inputdata )
{
Enable();
}
//-----------------------------------------------------------------------------
// Purpose: Input hander that stops the spawner
//-----------------------------------------------------------------------------
void CNPCMaker::InputDisable( inputdata_t &inputdata )
{
Disable();
}
//-----------------------------------------------------------------------------
// Purpose: Input hander that toggles the spawner
//-----------------------------------------------------------------------------
void CNPCMaker::InputToggle( inputdata_t &inputdata )
{
Toggle();
}
//-----------------------------------------------------------------------------
// Purpose: Precache the target NPC
//-----------------------------------------------------------------------------
void CNPCMaker::Precache( void )
{
BaseClass::Precache();
UTIL_PrecacheOther( STRING( m_iszNPCClassname ) );
}
//-----------------------------------------------------------------------------
// Purpose: Creates the NPC.
//-----------------------------------------------------------------------------
void CNPCMaker::MakeNPC( void )
{
if (!CanMakeNPC())
{
return;
}
CBaseEntity *pent = (CBaseEntity*)CreateEntityByName( STRING(m_iszNPCClassname) );
if ( !pent )
{
Warning("NULL Ent in NPCMaker!\n" );
return;
}
m_OnSpawnNPC.FireOutput( this, this );
pent->SetLocalOrigin( GetAbsOrigin() );
pent->SetLocalAngles( GetAbsAngles() );
pent->AddSpawnFlags( SF_NPC_FALL_TO_GROUND );
if ( m_spawnflags & SF_NPCMAKER_FADE )
{
pent->AddSpawnFlags( SF_NPC_FADE_CORPSE );
}
DispatchSpawn( pent );
pent->SetOwnerEntity( this );
m_cLiveChildren++;// count this NPC
if (!(m_spawnflags & SF_NPCMAKER_INF_CHILD))
{
m_iMaxNumNPCs--;
if ( IsDepleted() )
{
// Disable this forever. Don't kill it because it still gets death notices
SetThink( NULL );
SetUse( NULL );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Creates a new NPC every so often.
//-----------------------------------------------------------------------------
void CNPCMaker::MakerThink ( void )
{
SetNextThink( gpGlobals->curtime + m_flSpawnFrequency );
MakeNPC();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pVictim -
//-----------------------------------------------------------------------------
void CNPCMaker::DeathNotice( CBaseEntity *pVictim )
{
// ok, we've gotten the deathnotice from our child, now clear out its owner if we don't want it to fade.
m_cLiveChildren--;
}
+71
View File
@@ -0,0 +1,71 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef MONSTERMAKER_H
#define MONSTERMAKER_H
#ifdef _WIN32
#pragma once
#endif
#include "cbase.h"
//-----------------------------------------------------------------------------
// Spawnflags
//-----------------------------------------------------------------------------
#define SF_NPCMAKER_START_ON 1 // start active ( if has targetname )
#define SF_NPCMAKER_NPCCLIP 8 // Children are blocked by NPCclip
#define SF_NPCMAKER_FADE 16 // Children's corpses fade
#define SF_NPCMAKER_INF_CHILD 32 // Infinite number of children
#define SF_NPCMAKER_NO_DROP 64 // Do not adjust for the ground's position when checking for spawn
class CNPCMaker : public CBaseEntity
{
public:
DECLARE_CLASS( CNPCMaker, CBaseEntity );
CNPCMaker(void) {}
void Spawn( void );
void Precache( void );
void MakerThink( void );
bool CanMakeNPC( void );
void DeathNotice( CBaseEntity *pChild );// NPC maker children use this to tell the NPC maker that they have died.
void MakeNPC( void );
// Input handlers
void InputSpawnNPC( inputdata_t &inputdata );
void InputEnable( inputdata_t &inputdata );
void InputDisable( inputdata_t &inputdata );
void InputToggle( inputdata_t &inputdata );
// State changers
void Toggle( void );
void Enable( void );
void Disable( void );
bool IsDepleted();
DECLARE_DATADESC();
int m_iMaxNumNPCs; // max number of NPCs this ent can create
float m_flSpawnFrequency; // delay (in secs) between spawns
int m_iMaxLiveChildren; // max number of NPCs that this maker may have out at one time.
string_t m_iszNPCClassname; // classname of the NPC(s) that will be created.
COutputEvent m_OnSpawnNPC;
int m_cLiveChildren;// how many NPCs made by this NPC maker that are currently alive
float m_flGround; // z coord of the ground under me, used to make sure no NPCs are under the maker when it drops a new child
bool m_bDisabled;
};
#endif // MONSTERMAKER_H
+858
View File
@@ -0,0 +1,858 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Bullseyes act as targets for other NPC's to attack and to trigger
// events
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "ai_default.h"
#include "ai_task.h"
#include "ai_schedule.h"
#include "ai_node.h"
#include "ai_hull.h"
#include "ai_hint.h"
#include "ai_route.h"
#include "soundent.h"
#include "game.h"
#include "npcevent.h"
#include "entitylist.h"
#include "activitylist.h"
#include "animation.h"
#include "basecombatweapon.h"
#include "IEffects.h"
#include "vstdlib/random.h"
#include "engine/IEngineSound.h"
#include "ammodef.h"
#include "hl1_ai_basenpc.h"
#define AFLOCK_MAX_RECRUIT_RADIUS 1024
#define AFLOCK_FLY_SPEED 125
#define AFLOCK_TURN_RATE 75
#define AFLOCK_ACCELERATE 10
#define AFLOCK_CHECK_DIST 192
#define AFLOCK_TOO_CLOSE 100
#define AFLOCK_TOO_FAR 256
//=========================================================
//=========================================================
class CNPC_FlockingFlyerFlock : public CHL1BaseNPC
{
DECLARE_CLASS( CNPC_FlockingFlyerFlock, CHL1BaseNPC );
public:
void Spawn( void );
void Precache( void );
bool KeyValue( const char *szKeyName, const char *szValue );
void SpawnFlock( void );
// Sounds are shared by the flock
static void PrecacheFlockSounds( void );
DECLARE_DATADESC();
int m_cFlockSize;
float m_flFlockRadius;
};
BEGIN_DATADESC( CNPC_FlockingFlyerFlock )
DEFINE_FIELD( m_cFlockSize, FIELD_INTEGER ),
DEFINE_FIELD( m_flFlockRadius, FIELD_FLOAT ),
END_DATADESC()
class CNPC_FlockingFlyer : public CHL1BaseNPC
{
DECLARE_CLASS( CNPC_FlockingFlyer, CHL1BaseNPC );
public:
void Spawn( void );
void Precache( void );
void SpawnCommonCode( void );
void IdleThink( void );
void BoidAdvanceFrame( void );
void Start( void );
bool FPathBlocked( void );
void FlockLeaderThink( void );
void SpreadFlock( void );
void SpreadFlock2( void );
void MakeSound( void );
void FlockFollowerThink( void );
void Event_Killed( const CTakeDamageInfo &info );
void FallHack( void );
//void Poop ( void ); Adrian - wtf?!
int IsLeader( void ) { return m_pSquadLeader == this; }
int InSquad( void ) { return m_pSquadLeader != NULL; }
int SquadCount( void );
void SquadRemove( CNPC_FlockingFlyer *pRemove );
void SquadUnlink( void );
void SquadAdd( CNPC_FlockingFlyer *pAdd );
void SquadDisband( void );
CNPC_FlockingFlyer *m_pSquadLeader;
CNPC_FlockingFlyer *m_pSquadNext;
bool m_fTurning;// is this boid turning?
bool m_fCourseAdjust;// followers set this flag TRUE to override flocking while they avoid something
bool m_fPathBlocked;// TRUE if there is an obstacle ahead
Vector m_vecReferencePoint;// last place we saw leader
Vector m_vecAdjustedVelocity;// adjusted velocity (used when fCourseAdjust is TRUE)
float m_flGoalSpeed;
float m_flLastBlockedTime;
float m_flFakeBlockedTime;
float m_flAlertTime;
float m_flFlockNextSoundTime;
float m_flTempVar;
DECLARE_DATADESC();
};
BEGIN_DATADESC( CNPC_FlockingFlyer )
DEFINE_FIELD( m_pSquadLeader, FIELD_CLASSPTR ),
DEFINE_FIELD( m_pSquadNext, FIELD_CLASSPTR ),
DEFINE_FIELD( m_fTurning, FIELD_BOOLEAN ),
DEFINE_FIELD( m_fCourseAdjust, FIELD_BOOLEAN ),
DEFINE_FIELD( m_fPathBlocked, FIELD_BOOLEAN ),
DEFINE_FIELD( m_vecReferencePoint, FIELD_POSITION_VECTOR ),
DEFINE_FIELD( m_vecAdjustedVelocity, FIELD_VECTOR ),
DEFINE_FIELD( m_flGoalSpeed, FIELD_FLOAT ),
DEFINE_FIELD( m_flLastBlockedTime, FIELD_TIME ),
DEFINE_FIELD( m_flFakeBlockedTime, FIELD_TIME ),
DEFINE_FIELD( m_flAlertTime, FIELD_TIME ),
DEFINE_THINKFUNC( IdleThink ),
DEFINE_THINKFUNC( Start ),
DEFINE_THINKFUNC( FlockLeaderThink ),
DEFINE_THINKFUNC( FlockFollowerThink ),
DEFINE_THINKFUNC( FallHack ),
DEFINE_FIELD( m_flFlockNextSoundTime, FIELD_TIME ),
DEFINE_FIELD( m_flTempVar, FIELD_FLOAT ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( monster_flyer, CNPC_FlockingFlyer );
LINK_ENTITY_TO_CLASS( monster_flyer_flock, CNPC_FlockingFlyerFlock );
bool CNPC_FlockingFlyerFlock::KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq( szKeyName, "iFlockSize" ) )
{
m_cFlockSize = atoi( szValue );
return true;
}
else if ( FStrEq( szKeyName, "flFlockRadius" ) )
{
m_flFlockRadius = atof( szValue );
return true;
}
else
BaseClass::KeyValue( szKeyName, szValue );
return false;
}
//=========================================================
//=========================================================
void CNPC_FlockingFlyerFlock::Spawn( void )
{
Precache( );
SetRenderColor( 255, 255, 255, 255 );
SpawnFlock();
SetThink( &CBaseEntity::SUB_Remove );
SetNextThink( gpGlobals->curtime + 0.1f );
}
//=========================================================
//=========================================================
void CNPC_FlockingFlyerFlock::Precache( void )
{
//PRECACHE_MODEL("models/aflock.mdl");
PrecacheModel("models/boid.mdl");
PrecacheFlockSounds();
}
void CNPC_FlockingFlyerFlock::SpawnFlock( void )
{
float R = m_flFlockRadius;
int iCount;
Vector vecSpot;
CNPC_FlockingFlyer *pBoid, *pLeader;
pLeader = pBoid = NULL;
for ( iCount = 0 ; iCount < m_cFlockSize ; iCount++ )
{
pBoid = CREATE_ENTITY( CNPC_FlockingFlyer, "monster_flyer" );
if ( !pLeader )
{
// make this guy the leader.
pLeader = pBoid;
pLeader->m_pSquadLeader = pLeader;
pLeader->m_pSquadNext = NULL;
}
vecSpot.x = random->RandomFloat( -R, R );
vecSpot.y = random->RandomFloat( -R, R );
vecSpot.z = random->RandomFloat( 0, 16 );
vecSpot = GetAbsOrigin() + vecSpot;
UTIL_SetOrigin( pBoid, vecSpot);
pBoid->SetMoveType( MOVETYPE_FLY );
pBoid->SpawnCommonCode();
pBoid->SetGroundEntity( NULL );
pBoid->SetAbsVelocity( Vector ( 0, 0, 0 ) );
pBoid->SetAbsAngles( GetAbsAngles() );
pBoid->SetCycle( 0 );
pBoid->SetThink( &CNPC_FlockingFlyer::IdleThink );
pBoid->SetNextThink( gpGlobals->curtime + 0.2 );
if ( pBoid != pLeader )
{
pLeader->SquadAdd( pBoid );
}
}
}
void CNPC_FlockingFlyerFlock::PrecacheFlockSounds( void )
{
}
//=========================================================
//=========================================================
void CNPC_FlockingFlyer::Spawn( )
{
Precache( );
SpawnCommonCode();
SetCycle( 0 );
SetNextThink( gpGlobals->curtime + 0.1f );
SetThink( &CNPC_FlockingFlyer::IdleThink );
}
//=========================================================
//=========================================================
void CNPC_FlockingFlyer::SpawnCommonCode( )
{
m_lifeState = LIFE_ALIVE;
SetClassname( "monster_flyer" );
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_NOT_STANDABLE );
SetMoveType( MOVETYPE_FLY );
m_takedamage = DAMAGE_NO;
m_iHealth = 1;
m_fPathBlocked = FALSE;// obstacles will be detected
m_flFieldOfView = 0.2;
m_flTempVar = 0;
//SET_MODEL(ENT(pev), "models/aflock.mdl");
SetModel( "models/boid.mdl" );
// UTIL_SetSize(this, Vector(0,0,0), Vector(0,0,0));
UTIL_SetSize(this, Vector(-5,-5,0), Vector(5,5,2));
}
//=========================================================
//=========================================================
void CNPC_FlockingFlyer::Precache( )
{
//PRECACHE_MODEL("models/aflock.mdl");
PrecacheModel("models/boid.mdl");
CNPC_FlockingFlyerFlock::PrecacheFlockSounds();
PrecacheScriptSound( "FlockingFlyer.Alert" );
PrecacheScriptSound( "FlockingFlyer.Idle" );
}
//=========================================================
//=========================================================
void CNPC_FlockingFlyer::IdleThink( void )
{
SetNextThink( gpGlobals->curtime + 0.2 );
// see if there's a client in the same pvs as the monster
if ( !FNullEnt( UTIL_FindClientInPVS( edict() ) ) )
{
SetThink( &CNPC_FlockingFlyer::Start );
SetNextThink( gpGlobals->curtime + 0.1f );
}
}
//=========================================================
//
// SquadUnlink(), Unlink the squad pointers.
//
//=========================================================
void CNPC_FlockingFlyer::SquadUnlink( void )
{
m_pSquadLeader = NULL;
m_pSquadNext = NULL;
}
//=========================================================
//
// SquadAdd(), add pAdd to my squad
//
//=========================================================
void CNPC_FlockingFlyer::SquadAdd( CNPC_FlockingFlyer *pAdd )
{
ASSERT( pAdd!=NULL );
ASSERT( !pAdd->InSquad() );
ASSERT( this->IsLeader() );
pAdd->m_pSquadNext = m_pSquadNext;
m_pSquadNext = pAdd;
pAdd->m_pSquadLeader = this;
}
//=========================================================
//
// SquadRemove(), remove pRemove from my squad.
// If I am pRemove, promote m_pSquadNext to leader
//
//=========================================================
void CNPC_FlockingFlyer::SquadRemove( CNPC_FlockingFlyer *pRemove )
{
ASSERT( pRemove!=NULL );
ASSERT( this->IsLeader() );
ASSERT( pRemove->m_pSquadLeader == this );
if ( SquadCount() > 2 )
{
// Removing the leader, promote m_pSquadNext to leader
if ( pRemove == this )
{
CNPC_FlockingFlyer *pLeader = m_pSquadNext;
// copy the enemy LKP to the new leader
// if ( GetEnemy() )
// pLeader->m_vecEnemyLKP = m_vecEnemyLKP;
if ( pLeader )
{
CNPC_FlockingFlyer *pList = pLeader;
while ( pList )
{
pList->m_pSquadLeader = pLeader;
pList = pList->m_pSquadNext;
}
}
SquadUnlink();
}
else // removing a node
{
CNPC_FlockingFlyer *pList = this;
// Find the node before pRemove
while ( pList->m_pSquadNext != pRemove )
{
// assert to test valid list construction
ASSERT( pList->m_pSquadNext != NULL );
pList = pList->m_pSquadNext;
}
// List validity
ASSERT( pList->m_pSquadNext == pRemove );
// Relink without pRemove
pList->m_pSquadNext = pRemove->m_pSquadNext;
// Unlink pRemove
pRemove->SquadUnlink();
}
}
else
SquadDisband();
}
//=========================================================
//
// SquadCount(), return the number of members of this squad
// callable from leaders & followers
//
//=========================================================
int CNPC_FlockingFlyer::SquadCount( void )
{
CNPC_FlockingFlyer *pList = m_pSquadLeader;
int squadCount = 0;
while ( pList )
{
squadCount++;
pList = pList->m_pSquadNext;
}
return squadCount;
}
//=========================================================
//
// SquadDisband(), Unlink all squad members
//
//=========================================================
void CNPC_FlockingFlyer::SquadDisband( void )
{
CNPC_FlockingFlyer *pList = m_pSquadLeader;
CNPC_FlockingFlyer *pNext;
while ( pList )
{
pNext = pList->m_pSquadNext;
pList->SquadUnlink();
pList = pNext;
}
}
//=========================================================
// Start - player enters the pvs, so get things going.
//=========================================================
void CNPC_FlockingFlyer::Start( void )
{
SetNextThink( gpGlobals->curtime + 0.1f );
if ( IsLeader() )
{
SetThink( &CNPC_FlockingFlyer::FlockLeaderThink );
}
else
{
SetThink( &CNPC_FlockingFlyer::FlockFollowerThink );
}
SetActivity ( ACT_FLY );
ResetSequenceInfo( );
BoidAdvanceFrame( );
m_flSpeed = AFLOCK_FLY_SPEED;// no delay!
}
//=========================================================
//=========================================================
void CNPC_FlockingFlyer::BoidAdvanceFrame ( void )
{
float flapspeed = ( m_flSpeed - m_flTempVar ) / AFLOCK_ACCELERATE;
m_flTempVar = m_flTempVar * .8 + m_flSpeed * .2;
if (flapspeed < 0) flapspeed = -flapspeed;
if (flapspeed < 0.25) flapspeed = 0.25;
if (flapspeed > 1.9) flapspeed = 1.9;
m_flPlaybackRate = flapspeed;
QAngle angVel = GetLocalAngularVelocity();
// lean
angVel.x = - GetAbsAngles().x + flapspeed * 5;
// bank
angVel.z = - GetAbsAngles().z + angVel.y;
SetLocalAngularVelocity( angVel );
// pev->framerate = flapspeed;
StudioFrameAdvance();
}
//=========================================================
// Leader boids use this think every tenth
//=========================================================
void CNPC_FlockingFlyer::FlockLeaderThink( void )
{
trace_t tr;
Vector vecDist;// used for general measurements
Vector vecDir;// used for general measurements
float flLeftSide;
float flRightSide;
Vector vForward, vRight, vUp;
SetNextThink( gpGlobals->curtime + 0.1f );
AngleVectors ( GetAbsAngles(), &vForward, &vRight, &vUp );
// is the way ahead clear?
if ( !FPathBlocked () )
{
// if the boid is turning, stop the trend.
if ( m_fTurning )
{
m_fTurning = FALSE;
QAngle angVel = GetLocalAngularVelocity();
angVel.y = 0;
SetLocalAngularVelocity( angVel );
}
m_fPathBlocked = FALSE;
if ( m_flSpeed <= AFLOCK_FLY_SPEED )
m_flSpeed += 5;
SetAbsVelocity( vForward * m_flSpeed );
BoidAdvanceFrame( );
return;
}
// IF we get this far in the function, the leader's path is blocked!
m_fPathBlocked = TRUE;
if ( !m_fTurning)// something in the way and boid is not already turning to avoid
{
// measure clearance on left and right to pick the best dir to turn
UTIL_TraceLine(GetAbsOrigin(), GetAbsOrigin() + vRight * AFLOCK_CHECK_DIST, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
vecDist = (tr.endpos - GetAbsOrigin());
flRightSide = vecDist.Length();
UTIL_TraceLine(GetAbsOrigin(), GetAbsOrigin() - vRight * AFLOCK_CHECK_DIST, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
vecDist = (tr.endpos - GetAbsOrigin());
flLeftSide = vecDist.Length();
// turn right if more clearance on right side
if ( flRightSide > flLeftSide )
{
QAngle angVel = GetLocalAngularVelocity();
angVel.y = -AFLOCK_TURN_RATE;
SetLocalAngularVelocity( angVel );
m_fTurning = TRUE;
}
// default to left turn :)
else if ( flLeftSide > flRightSide )
{
QAngle angVel = GetLocalAngularVelocity();
angVel.y = AFLOCK_TURN_RATE;
SetLocalAngularVelocity( angVel );
m_fTurning = TRUE;
}
else
{
// equidistant. Pick randomly between left and right.
m_fTurning = TRUE;
QAngle angVel = GetLocalAngularVelocity();
if ( random->RandomInt( 0, 1 ) == 0 )
{
angVel.y = AFLOCK_TURN_RATE;
}
else
{
angVel.y = -AFLOCK_TURN_RATE;
}
SetLocalAngularVelocity( angVel );
}
}
SpreadFlock( );
SetAbsVelocity( vForward * m_flSpeed );
// check and make sure we aren't about to plow into the ground, don't let it happen
UTIL_TraceLine(GetAbsOrigin(), GetAbsOrigin() - vUp * 16, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
if (tr.fraction != 1.0 && GetAbsVelocity().z < 0 )
{
Vector vecVel = GetAbsVelocity();
vecVel.z = 0;
SetAbsVelocity( vecVel );
}
// maybe it did, though.
if ( GetFlags() & FL_ONGROUND )
{
UTIL_SetOrigin( this, GetAbsOrigin() + Vector ( 0 , 0 , 1 ) );
Vector vecVel = GetAbsVelocity();
vecVel.z = 0;
SetAbsVelocity( vecVel );
}
if ( m_flFlockNextSoundTime < gpGlobals->curtime )
{
// MakeSound();
m_flFlockNextSoundTime = gpGlobals->curtime + random->RandomFloat( 1, 3 );
}
BoidAdvanceFrame( );
return;
}
//=========================================================
// FBoidPathBlocked - returns TRUE if there is an obstacle ahead
//=========================================================
bool CNPC_FlockingFlyer::FPathBlocked( void )
{
trace_t tr;
Vector vecDist;// used for general measurements
Vector vecDir;// used for general measurements
bool fBlocked;
Vector vForward, vRight, vUp;
if ( m_flFakeBlockedTime > gpGlobals->curtime )
{
m_flLastBlockedTime = gpGlobals->curtime;
return TRUE;
}
// use VELOCITY, not angles, not all boids point the direction they are flying
//vecDir = UTIL_VecToAngles( pevBoid->velocity );
AngleVectors ( GetAbsAngles(), &vForward, &vRight, &vUp );
fBlocked = FALSE;// assume the way ahead is clear
// check for obstacle ahead
UTIL_TraceLine(GetAbsOrigin(), GetAbsOrigin() + vForward * AFLOCK_CHECK_DIST, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
if (tr.fraction != 1.0)
{
m_flLastBlockedTime = gpGlobals->curtime;
fBlocked = TRUE;
}
// extra wide checks
UTIL_TraceLine(GetAbsOrigin() + vRight * 12, GetAbsOrigin() + vRight * 12 + vForward * AFLOCK_CHECK_DIST, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
if (tr.fraction != 1.0)
{
m_flLastBlockedTime = gpGlobals->curtime;
fBlocked = TRUE;
}
UTIL_TraceLine(GetAbsOrigin() - vRight * 12, GetAbsOrigin() - vRight * 12 + vForward * AFLOCK_CHECK_DIST, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
if (tr.fraction != 1.0)
{
m_flLastBlockedTime = gpGlobals->curtime;
fBlocked = TRUE;
}
if ( !fBlocked && gpGlobals->curtime - m_flLastBlockedTime > 6 )
{
// not blocked, and it's been a few seconds since we've actually been blocked.
m_flFakeBlockedTime = gpGlobals->curtime + random->RandomInt(1, 3);
}
return fBlocked;
}
//=========================================================
// Searches for boids that are too close and pushes them away
//=========================================================
void CNPC_FlockingFlyer::SpreadFlock( )
{
Vector vecDir;
float flSpeed;// holds vector magnitude while we fiddle with the direction
CNPC_FlockingFlyer *pList = m_pSquadLeader;
while ( pList )
{
if ( pList != this && ( GetAbsOrigin() - pList->GetAbsOrigin() ).Length() <= AFLOCK_TOO_CLOSE )
{
// push the other away
vecDir = ( pList->GetAbsOrigin() - GetAbsOrigin() );
VectorNormalize( vecDir );
// store the magnitude of the other boid's velocity, and normalize it so we
// can average in a course that points away from the leader.
flSpeed = pList->GetAbsVelocity().Length();
Vector vecVel = pList->GetAbsVelocity();
VectorNormalize( vecVel );
pList->SetAbsVelocity( ( vecVel + vecDir ) * 0.5 * flSpeed );
}
pList = pList->m_pSquadNext;
}
}
//=========================================================
// Alters the caller's course if he's too close to others
//
// This function should **ONLY** be called when Caller's velocity is normalized!!
//=========================================================
void CNPC_FlockingFlyer::SpreadFlock2 ( )
{
Vector vecDir;
CNPC_FlockingFlyer *pList = m_pSquadLeader;
while ( pList )
{
if ( pList != this && ( GetAbsOrigin() - pList->GetAbsOrigin() ).Length() <= AFLOCK_TOO_CLOSE )
{
vecDir = ( GetAbsOrigin() - pList->GetAbsOrigin() );
VectorNormalize( vecDir );
SetAbsVelocity( ( GetAbsVelocity() + vecDir ) );
}
pList = pList->m_pSquadNext;
}
}
//=========================================================
//=========================================================
void CNPC_FlockingFlyer::MakeSound( void )
{
if ( m_flAlertTime > gpGlobals->curtime )
{
CPASAttenuationFilter filter1( this );
// make agitated sounds
EmitSound( filter1, entindex(), "FlockingFlyer.Alert" );
return;
}
// make normal sound
CPASAttenuationFilter filter2( this );
EmitSound( filter2, entindex(), "FlockingFlyer.Idle" );
}
//=========================================================
// follower boids execute this code when flocking
//=========================================================
void CNPC_FlockingFlyer::FlockFollowerThink( void )
{
Vector vecDist;
Vector vecDir;
Vector vecDirToLeader;
float flDistToLeader;
SetNextThink( gpGlobals->curtime + 0.1f );
if ( IsLeader() || !InSquad() )
{
// the leader has been killed and this flyer suddenly finds himself the leader.
SetThink ( &CNPC_FlockingFlyer::FlockLeaderThink );
return;
}
vecDirToLeader = ( m_pSquadLeader->GetAbsOrigin() - GetAbsOrigin() );
flDistToLeader = vecDirToLeader.Length();
// match heading with leader
SetAbsAngles( m_pSquadLeader->GetAbsAngles() );
//
// We can see the leader, so try to catch up to it
//
if ( FInViewCone ( m_pSquadLeader ) )
{
// if we're too far away, speed up
if ( flDistToLeader > AFLOCK_TOO_FAR )
{
m_flGoalSpeed = m_pSquadLeader->GetAbsVelocity().Length() * 1.5;
}
// if we're too close, slow down
else if ( flDistToLeader < AFLOCK_TOO_CLOSE )
{
m_flGoalSpeed = m_pSquadLeader->GetAbsVelocity().Length() * 0.5;
}
}
else
{
// wait up! the leader isn't out in front, so we slow down to let him pass
m_flGoalSpeed = m_pSquadLeader->GetAbsVelocity().Length() * 0.5;
}
SpreadFlock2();
Vector vecVel = GetAbsVelocity();
m_flSpeed = vecVel.Length();
VectorNormalize( vecVel );
// if we are too far from leader, average a vector towards it into our current velocity
if ( flDistToLeader > AFLOCK_TOO_FAR )
{
VectorNormalize( vecDirToLeader );
vecVel = (vecVel + vecDirToLeader) * 0.5;
}
// clamp speeds and handle acceleration
if ( m_flGoalSpeed > AFLOCK_FLY_SPEED * 2 )
{
m_flGoalSpeed = AFLOCK_FLY_SPEED * 2;
}
if ( m_flSpeed < m_flGoalSpeed )
{
m_flSpeed += AFLOCK_ACCELERATE;
}
else if ( m_flSpeed > m_flGoalSpeed )
{
m_flSpeed -= AFLOCK_ACCELERATE;
}
SetAbsVelocity( vecVel * m_flSpeed );
BoidAdvanceFrame( );
}
//=========================================================
//=========================================================
void CNPC_FlockingFlyer::Event_Killed( const CTakeDamageInfo &info )
{
CNPC_FlockingFlyer *pSquad;
pSquad = (CNPC_FlockingFlyer *)m_pSquadLeader;
while ( pSquad )
{
pSquad->m_flAlertTime = gpGlobals->curtime + 15;
pSquad = (CNPC_FlockingFlyer *)pSquad->m_pSquadNext;
}
if ( m_pSquadLeader )
{
m_pSquadLeader->SquadRemove( this );
}
m_lifeState = LIFE_DEAD;
m_flPlaybackRate = 0;
IncrementInterpolationFrame();
UTIL_SetSize( this, Vector(0,0,0), Vector(0,0,0) );
SetMoveType( MOVETYPE_FLYGRAVITY );
SetThink ( &CNPC_FlockingFlyer::FallHack );
SetNextThink( gpGlobals->curtime + 0.1f );
}
void CNPC_FlockingFlyer::FallHack( void )
{
if ( GetFlags() & FL_ONGROUND )
{
CBaseEntity *groundentity = GetContainingEntity( GetGroundEntity()->edict() );
if ( !FClassnameIs ( groundentity, "worldspawn" ) )
{
SetGroundEntity( NULL );
SetNextThink( gpGlobals->curtime + 0.1f );
}
else
{
SetAbsVelocity( Vector( 0, 0, 0 ) );
SetThink( NULL );
}
}
}
File diff suppressed because it is too large Load Diff
+766
View File
@@ -0,0 +1,766 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "ai_default.h"
#include "ai_task.h"
#include "ai_schedule.h"
#include "ai_node.h"
#include "ai_hull.h"
#include "ai_hint.h"
#include "ai_memory.h"
#include "ai_route.h"
#include "ai_motor.h"
#include "soundent.h"
#include "game.h"
#include "npcevent.h"
#include "entitylist.h"
#include "activitylist.h"
#include "hl1_basegrenade.h"
#include "animation.h"
#include "IEffects.h"
#include "vstdlib/random.h"
#include "engine/IEngineSound.h"
#include "ammodef.h"
#include "soundenvelope.h"
#include "hl1_CBaseHelicopter.h"
#include "ndebugoverlay.h"
#include "smoke_trail.h"
#include "beam_shared.h"
#include "grenade_homer.h"
#define HOMER_TRAIL0_LIFE 0.1
#define HOMER_TRAIL1_LIFE 0.2
#define HOMER_TRAIL2_LIFE 3.0// 1.0
#define SF_NOTRANSITION 128
extern short g_sModelIndexFireball;
class CNPC_Apache : public CBaseHelicopter
{
DECLARE_CLASS( CNPC_Apache, CBaseHelicopter );
public:
DECLARE_DATADESC();
void Spawn( void );
void Precache( void );
int BloodColor( void ) { return DONT_BLEED; }
Class_T Classify( void ) { return CLASS_HUMAN_MILITARY; };
void InitializeRotorSound( void );
void LaunchRocket( Vector &viewDir, int damage, int radius, Vector vecLaunchPoint );
void Flight( void );
bool FireGun( void );
void AimRocketGun( void );
void FireRocket( void );
void DyingThink( void );
int ObjectCaps( void );
void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator );
/* bool OnInternalDrawModel( ClientModelRenderInfo_t *pInfo )
{
BaseClass::OnInteralDrawModel( pInfo );
Vector origin = GetAbsOrigin();
origin.z += 32;
SetAbsOrigin( origin );
}*/
/*( void SetAbsOrigin( const Vector& absOrigin )
{
((Vector&)absOrigin).z += 32;
BaseClass::SetAbsOrigin( absOrigin );
}*/
/* int Save( CSave &save );
int Restore( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
void Spawn( void );
void Precache( void );
void Killed( entvars_t *pevAttacker, int iGib );
void GibMonster( void );
void EXPORT HuntThink( void );
void EXPORT FlyTouch( CBaseEntity *pOther );
void EXPORT CrashTouch( CBaseEntity *pOther );
void EXPORT DyingThink( void );
void EXPORT StartupUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void EXPORT NullThink( void );
void ShowDamage( void );
void Flight( void );
void FireRocket( void );
BOOL FireGun( void );
int TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType );
void TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType);*/
int m_iRockets;
float m_flForce;
float m_flNextRocket;
int m_iAmmoType;
Vector m_vecTarget;
Vector m_posTarget;
Vector m_vecDesired;
Vector m_posDesired;
Vector m_vecGoal;
QAngle m_angGun;
int m_iSoundState; // don't save this
int m_iExplode;
int m_iBodyGibs;
int m_nDebrisModel;
float m_flGoalSpeed;
CHandle<SmokeTrail> m_hSmoke;
CBeam *m_pBeam;
};
BEGIN_DATADESC( CNPC_Apache )
DEFINE_FIELD( m_iRockets, FIELD_INTEGER ),
DEFINE_FIELD( m_flForce, FIELD_FLOAT ),
DEFINE_FIELD( m_flNextRocket, FIELD_TIME ),
DEFINE_FIELD( m_vecTarget, FIELD_VECTOR ),
DEFINE_FIELD( m_posTarget, FIELD_POSITION_VECTOR ),
DEFINE_FIELD( m_vecDesired, FIELD_VECTOR ),
DEFINE_FIELD( m_posDesired, FIELD_POSITION_VECTOR ),
DEFINE_FIELD( m_vecGoal, FIELD_VECTOR ),
DEFINE_FIELD( m_angGun, FIELD_VECTOR ),
DEFINE_FIELD( m_flLastSeen, FIELD_TIME ),
DEFINE_FIELD( m_flPrevSeen, FIELD_TIME ),
// DEFINE_FIELD( m_iSoundState, FIELD_INTEGER ),
// DEFINE_FIELD( m_iSpriteTexture, FIELD_INTEGER ),
// DEFINE_FIELD( m_iExplode, FIELD_INTEGER ),
// DEFINE_FIELD( m_iBodyGibs, FIELD_INTEGER ),
DEFINE_FIELD( m_pBeam, FIELD_CLASSPTR ),
DEFINE_FIELD( m_flGoalSpeed, FIELD_FLOAT ),
DEFINE_FIELD( m_hSmoke, FIELD_EHANDLE ),
END_DATADESC()
ConVar sk_apache_health( "sk_apache_health","100");
static Vector s_vecSurroundingMins( -300, -300, -172);
static Vector s_vecSurroundingMaxs(300, 300, 8);
void CNPC_Apache::Spawn( void )
{
Precache( );
SetModel( "models/apache.mdl" );
BaseClass::Spawn();
AddFlag( FL_NPC );
SetSolid( SOLID_BBOX );
SetMoveType( MOVETYPE_STEP );
AddFlag( FL_FLY );
m_iHealth = sk_apache_health.GetFloat();
m_flFieldOfView = -0.707; // 270 degrees
m_fHelicopterFlags = BITS_HELICOPTER_MISSILE_ON | BITS_HELICOPTER_GUN_ON;
InitBoneControllers();
SetRenderColor( 255, 255, 255, 255 );
m_iRockets = 10;
UTIL_SetSize( this, Vector( -32, -32, -32 ), Vector( 32, 32, 32 ) );
//CollisionProp()->SetSurroundingBoundsType( USE_SPECIFIED_BOUNDS, &s_vecSurroundingMins, &s_vecSurroundingMaxs );
//AddSolidFlags( FSOLID_CUSTOMRAYTEST | FSOLID_CUSTOMBOXTEST );
m_hSmoke = NULL;
}
LINK_ENTITY_TO_CLASS ( monster_apache, CNPC_Apache );
int CNPC_Apache::ObjectCaps( void )
{
if ( GetSpawnFlags() & SF_NOTRANSITION )
return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION;
else
return BaseClass::ObjectCaps();
}
void CNPC_Apache::Precache( void )
{
// Get to tha chopper!
PrecacheModel( "models/apache.mdl" );
PrecacheScriptSound( "Apache.Rotor" );
m_nDebrisModel = PrecacheModel( "models/metalplategibs_green.mdl" );
// Gun
PrecacheScriptSound( "Apache.FireGun" );
m_iAmmoType = GetAmmoDef()->Index("9mmRound");
// Rockets
UTIL_PrecacheOther( "grenade_homer" );
PrecacheScriptSound( "Apache.RPG" );
PrecacheModel( "models/weapons/w_missile.mdl" );
BaseClass::Precache();
}
void CNPC_Apache::InitializeRotorSound( void )
{
CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController();
CPASAttenuationFilter filter( this );
m_pRotorSound = controller.SoundCreate( filter, entindex(), "Apache.Rotor" );
BaseClass::InitializeRotorSound();
}
void CNPC_Apache::Flight( void )
{
StudioFrameAdvance( );
float flDistToDesiredPosition = (GetAbsOrigin() - m_vecDesiredPosition).Length();
// NDebugOverlay::Line(GetAbsOrigin(), m_vecDesiredPosition, 0,0,255, true, 0.1);
if (m_flGoalSpeed < 800 )
m_flGoalSpeed += GetAcceleration();
// Vector vecGoalOrientation;
if (flDistToDesiredPosition > 250) // 500
{
Vector v1 = (m_vecTargetPosition - GetAbsOrigin());
Vector v2 = (m_vecDesiredPosition - GetAbsOrigin());
VectorNormalize( v1 );
VectorNormalize( v2 );
if (m_flLastSeen + 90 > gpGlobals->curtime && DotProduct( v1, v2 ) > 0.25)
{
m_vecGoalOrientation = ( m_vecTargetPosition - GetAbsOrigin());
}
else
{
m_vecGoalOrientation = (m_vecDesiredPosition - GetAbsOrigin());
}
VectorNormalize( m_vecGoalOrientation );
}
else
{
AngleVectors( GetGoalEnt()->GetAbsAngles(), &m_vecGoalOrientation );
}
// SetGoalOrientation( vecGoalOrientation );
if (GetGoalEnt())
{
// ALERT( at_console, "%.0f\n", flLength );
if ( HasReachedTarget() )
{
// If we get this close to the desired position, it's assumed that we've reached
// the desired position, so move on.
// Fire target that I've reached my goal
m_AtTarget.FireOutput( GetGoalEnt(), this );
OnReachedTarget( GetGoalEnt() );
SetGoalEnt( gEntList.FindEntityByName( NULL, GetGoalEnt()->m_target ) );
if (GetGoalEnt())
{
m_vecDesiredPosition = GetGoalEnt()->GetAbsOrigin();
// Vector vecGoalOrientation;
AngleVectors( GetGoalEnt()->GetAbsAngles(), &m_vecGoalOrientation );
// SetGoalOrientation( vecGoalOrientation );
flDistToDesiredPosition = (GetAbsOrigin() - m_vecDesiredPosition).Length();
}
}
}
else
{
// If we can't find a new target, just stay where we are.
m_vecDesiredPosition = GetAbsOrigin();
}
// tilt model 5 degrees
QAngle angAdj = QAngle( 5.0, 0, 0 );
// estimate where I'll be facing in one seconds
Vector forward, right, up;
AngleVectors( GetAbsAngles() + GetLocalAngularVelocity() * 2 + angAdj, &forward, &right, &up );
// Vector vecEst1 = GetAbsOrigin() + pev->velocity + gpGlobals->v_up * m_flForce - Vector( 0, 0, 384 );
// float flSide = DotProduct( m_posDesired - vecEst1, gpGlobals->v_right );
QAngle angVel = GetLocalAngularVelocity();
float flSide = DotProduct( m_vecGoalOrientation, right );
if (flSide < 0)
{
if ( angVel.y < 60)
{
angVel.y += 8; // 9 * (3.0/2.0);
}
}
else
{
if ( angVel.y > -60)
{
angVel.y -= 8; // 9 * (3.0/2.0);
}
}
angVel.y *= 0.98;
SetLocalAngularVelocity( angVel );
Vector vecVel = GetAbsVelocity();
// estimate where I'll be in two seconds
AngleVectors( GetAbsAngles() + GetLocalAngularVelocity() * 1 + angAdj, &forward, &right, &up );
Vector vecEst = GetAbsOrigin() + vecVel * 2.0 + up * m_flForce * 20 - Vector( 0, 0, 384 * 2 );
// add immediate force
AngleVectors( GetAbsAngles() + angAdj, &forward, &right, &up );
vecVel.x += up.x * m_flForce;
vecVel.y += up.y * m_flForce;
vecVel.z += up.z * m_flForce;
// add gravity
vecVel.z -= 38.4; // 32ft/sec
float flSpeed = vecVel.Length();
float flDir = DotProduct( Vector( forward.x, forward.y, 0 ), Vector( vecVel.x, vecVel.y, 0 ) );
if (flDir < 0)
flSpeed = -flSpeed;
float flDist = DotProduct( m_vecDesiredPosition - vecEst, forward );
// float flSlip = DotProduct( pev->velocity, gpGlobals->v_right );
float flSlip = -DotProduct( m_vecDesiredPosition - vecEst, right );
angVel = GetLocalAngularVelocity();
// fly sideways
if (flSlip > 0)
{
if (GetAbsAngles().z > -30 && angVel.z > -15)
angVel.z -= 4;
else
angVel.z += 2;
}
else
{
if (GetAbsAngles().z < 30 && angVel.z < 15)
angVel.z += 4;
else
angVel.z -= 2;
}
SetLocalAngularVelocity( angVel );
// sideways drag
vecVel.x = vecVel.x * (1.0 - fabs( right.x ) * 0.05);
vecVel.y = vecVel.y * (1.0 - fabs( right.y ) * 0.05);
vecVel.z = vecVel.z * (1.0 - fabs( right.z ) * 0.05);
// general drag
vecVel = vecVel * 0.995;
// Set final computed velocity
SetAbsVelocity( vecVel );
// apply power to stay correct height
if (m_flForce < 80 && vecEst.z < m_vecDesiredPosition.z)
{
m_flForce += 12;
}
else if (m_flForce > 30)
{
if (vecEst.z > m_vecDesiredPosition.z)
m_flForce -= 8;
}
angVel = GetLocalAngularVelocity();
// pitch forward or back to get to target
if (flDist > 0 && flSpeed < m_flGoalSpeed && GetAbsAngles().x + angVel.x < 40)
{
// ALERT( at_console, "F " );
// lean forward
angVel.x += 12.0;
}
else if (flDist < 0 && flSpeed > -50 && GetAbsAngles().x + angVel.x > -20)
{
// ALERT( at_console, "B " );
// lean backward
angVel.x -= 12.0;
}
else if (GetAbsAngles().x + angVel.x < 0)
{
// ALERT( at_console, "f " );
angVel.x += 4.0;
}
else if (GetAbsAngles().x + angVel.x > 0)
{
// ALERT( at_console, "b " );
angVel.x -= 4.0;
}
// Set final computed angular velocity
SetLocalAngularVelocity( angVel );
// ALERT( at_console, "%.0f %.0f : %.0f %.0f : %.0f %.0f : %.0f\n", GetAbsOrigin().x, pev->velocity.x, flDist, flSpeed, GetAbsAngles().x, pev->avelocity.x, m_flForce );
// ALERT( at_console, "%.0f %.0f : %.0f %0.f : %.0f\n", GetAbsOrigin().z, pev->velocity.z, vecEst.z, m_posDesired.z, m_flForce );
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
#define CHOPPER_AP_GUN_TIP 0
#define CHOPPER_AP_GUN_BASE 1
#define CHOPPER_BC_GUN_YAW 0
#define CHOPPER_BC_GUN_PITCH 1
#define CHOPPER_BC_POD_PITCH 2
bool CNPC_Apache::FireGun( )
{
if ( !GetEnemy() )
return false;
Vector vForward, vRight, vUp;
AngleVectors( GetAbsAngles(), &vForward, &vUp, &vRight );
Vector posGun;
QAngle angGun;
GetAttachment( 1, posGun, angGun );
Vector vecTarget = (m_vecTargetPosition - posGun);
VectorNormalize( vecTarget );
Vector vecOut;
vecOut.x = DotProduct( vForward, vecTarget );
vecOut.y = -DotProduct( vUp, vecTarget );
vecOut.z = DotProduct( vRight, vecTarget );
QAngle angles;
VectorAngles( vecOut, angles );
angles.y = AngleNormalize(angles.y);
angles.x = AngleNormalize(angles.x);
if (angles.x > m_angGun.x)
m_angGun.x = MIN( angles.x, m_angGun.x + 12 );
if (angles.x < m_angGun.x)
m_angGun.x = MAX( angles.x, m_angGun.x - 12 );
if (angles.y > m_angGun.y)
m_angGun.y = MIN( angles.y, m_angGun.y + 12 );
if (angles.y < m_angGun.y)
m_angGun.y = MAX( angles.y, m_angGun.y - 12 );
// hacks - shouldn't be hardcoded, oh well.
// limit it so it doesn't pop if you try to set it to the max value
m_angGun.y = clamp( m_angGun.y, -89.9, 89.9 );
m_angGun.x = clamp( m_angGun.x, -9.9, 44.9 );
m_angGun.y = SetBoneController( 0, m_angGun.y );
m_angGun.x = SetBoneController( 1, m_angGun.x );
Vector posBarrel;
QAngle angBarrel;
GetAttachment( 0, posBarrel, angBarrel );
Vector forward;
AngleVectors( angBarrel + m_angGun, &forward );
Vector2D vec2LOS = ( GetEnemy()->GetAbsOrigin() - GetAbsOrigin() ).AsVector2D();
vec2LOS.NormalizeInPlace();
float flDot = vec2LOS.Dot( forward.AsVector2D() );
//forward
// NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + ( forward * 200 ), 255,0,0, false, 0.1);
//LOS
// NDebugOverlay::Line( posGun, m_vecTargetPosition , 0,0,255, false, 0.1);
// NDebugOverlay::Box( GetAbsOrigin(), s_vecSurroundingMins, s_vecSurroundingMaxs, 0, 255,0, false, 0.1);
if ( flDot > 0.98 )
{
CPASAttenuationFilter filter( this, 0.2f );
EmitSound( filter, entindex(), "Apache.FireGun" );//<<TEMP>>temp sound
// gun is a bit dodgy, just fire at the target if we are close
FireBullets( 1, posGun, vecTarget, VECTOR_CONE_4DEGREES, 8192, m_iAmmoType, 2 );
return true;
}
return false;
}
void CNPC_Apache::FireRocket( void )
{
static float side = 1.0;
static int count;
Vector vForward, vRight, vUp;
AngleVectors( GetAbsAngles(), &vForward, &vRight, &vUp );
Vector vecSrc = GetAbsOrigin() + 1.5 * ( vForward * 21 + vRight * 70 * side + vUp * -79 );
// pick firing pod to launch from
switch( m_iRockets % 5)
{
case 0: vecSrc = vecSrc + vRight * 10; break;
case 1: vecSrc = vecSrc - vRight * 10; break;
case 2: vecSrc = vecSrc + vUp * 10; break;
case 3: vecSrc = vecSrc - vUp * 10; break;
case 4: break;
}
Vector vTargetDir = m_vecTargetPosition - GetAbsOrigin();
VectorNormalize ( vTargetDir );
LaunchRocket( vTargetDir, 100, 150, vecSrc);
m_iRockets--;
side = - side;
}
void CNPC_Apache::AimRocketGun( void )
{
Vector vForward, vRight, vUp;
if (m_iRockets <= 0)
return;
Vector vTargetDir = m_vecTargetPosition - GetAbsOrigin();
VectorNormalize ( vTargetDir );
AngleVectors( GetAbsAngles(), &vForward, &vRight, &vUp );
Vector vecEst = ( vForward * 800 + GetAbsVelocity());
VectorNormalize ( vecEst );
trace_t tr1;
UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vecEst * 4096, MASK_ALL, this, COLLISION_GROUP_NONE, &tr1);
// NDebugOverlay::Line(GetAbsOrigin(), tr1.endpos, 255,255,0, false, 0.1);
UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vTargetDir * 4096, MASK_ALL, this, COLLISION_GROUP_NONE, &tr1);
// NDebugOverlay::Line(GetAbsOrigin(), tr1.endpos, 0,255,0, false, 0.1);
// ALERT( at_console, "%d %d %d %4.2f\n", GetAbsAngles().x < 0, DotProduct( pev->velocity, gpGlobals->v_forward ) > -100, m_flNextRocket < gpGlobals->curtime, DotProduct( m_vecTarget, vecEst ) );
if ((m_iRockets % 2) == 1)
{
FireRocket( );
m_flNextRocket = gpGlobals->curtime + 0.5;
if (m_iRockets <= 0)
{
m_flNextRocket = gpGlobals->curtime + 10;
m_iRockets = 10;
}
}
else if (DotProduct( GetAbsVelocity(), vForward ) > -100 && m_flNextRocket < gpGlobals->curtime)
{
if (m_flLastSeen + 60 > gpGlobals->curtime)
{
if (GetEnemy() != NULL)
{
// make sure it's a good shot
//if (DotProduct( vTargetDir, vecEst) > 0.5)
{
trace_t tr;
UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vecEst * 4096, MASK_ALL, this, COLLISION_GROUP_NONE, &tr);
// NDebugOverlay::Line(GetAbsOrigin(), tr.endpos, 255,0,255, false, 5);
// if ((tr.endpos - m_vecTargetPosition).Length() < 512)
if ((tr.endpos - m_vecTargetPosition).Length() < 1024)
FireRocket( );
}
}
else
{
trace_t tr;
UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vecEst * 4096, MASK_ALL, this, COLLISION_GROUP_NONE, &tr);
// just fire when close
if ((tr.endpos - m_vecTargetPosition).Length() < 512)
FireRocket( );
}
}
}
}
#define MISSILE_HOMING_STRENGTH 0.3
#define MISSILE_HOMING_DELAY 5.0
#define MISSILE_HOMING_RAMP_UP 0.5
#define MISSILE_HOMING_DURATION 1.0
#define MISSILE_HOMING_RAMP_DOWN 0.5
void CNPC_Apache::LaunchRocket( Vector &viewDir, int damage, int radius, Vector vecLaunchPoint )
{
CGrenadeHomer *pGrenade = CGrenadeHomer::CreateGrenadeHomer(
MAKE_STRING("models/weapons/w_missile.mdl"),
MAKE_STRING( "Apache.RPG" ),
vecLaunchPoint, vec3_angle, edict() );
pGrenade->Spawn( );
pGrenade->SetHoming(MISSILE_HOMING_STRENGTH, MISSILE_HOMING_DELAY,
MISSILE_HOMING_RAMP_UP, MISSILE_HOMING_DURATION,
MISSILE_HOMING_RAMP_DOWN);
pGrenade->SetDamage( damage );
pGrenade->m_DmgRadius = radius;
pGrenade->Launch( this, GetEnemy(), viewDir * 1500, 500, 0, HOMER_SMOKE_TRAIL_ON );
}
//-----------------------------------------------------------------------------
// Purpose: Lame, temporary death
//-----------------------------------------------------------------------------
void CNPC_Apache::DyingThink( void )
{
StudioFrameAdvance( );
SetNextThink( gpGlobals->curtime + 0.1f );
if( gpGlobals->curtime > m_flNextCrashExplosion )
{
CPASFilter pasFilter( GetAbsOrigin() );
Vector pos;
pos = GetAbsOrigin();
pos.x += random->RandomFloat( -150, 150 );
pos.y += random->RandomFloat( -150, 150 );
pos.z += random->RandomFloat( -150, -50 );
te->Explosion( pasFilter, 0.0, &pos, g_sModelIndexFireball, 10, 15, TE_EXPLFLAG_NONE, 100, 0 );
Vector vecSize = Vector( 500, 500, 60 );
CPVSFilter pvsFilter( GetAbsOrigin() );
te->BreakModel( pvsFilter, 0.0, GetAbsOrigin(), vec3_angle, vecSize, vec3_origin,
m_nDebrisModel, 100, 0, 2.5, BREAK_METAL );
m_flNextCrashExplosion = gpGlobals->curtime + random->RandomFloat( 0.3, 0.5 );
}
QAngle angVel = GetLocalAngularVelocity();
if( angVel.y < 400 )
{
angVel.y *= 1.1;
SetLocalAngularVelocity( angVel );
}
Vector vecImpulse( 0, 0, -38.4 ); // gravity - 32ft/sec
ApplyAbsVelocityImpulse( vecImpulse );
if( m_hSmoke )
{
m_hSmoke->SetLifetime(0.1f);
m_hSmoke = NULL;
}
}
void CNPC_Apache::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
{
CTakeDamageInfo dmgInfo = info;
// HITGROUPS don't work currently.
// ignore blades
//if (ptr->hitgroup == 6 && (info.GetDamageType() & (DMG_ENERGYBEAM|DMG_BULLET|DMG_CLUB)))
// return;
// hit hard, hits cockpit
if (info.GetDamage() > 50 || ptr->hitgroup == 1 || ptr->hitgroup == 2 || ptr->hitgroup == 3 )
{
// ALERT( at_console, "%map .0f\n", flDamage );
AddMultiDamage( dmgInfo, this );
if ( info.GetDamage() > 50 )
{
if ( m_hSmoke == NULL && (m_hSmoke = SmokeTrail::CreateSmokeTrail()) != NULL )
{
m_hSmoke->m_Opacity = 1.0f;
m_hSmoke->m_SpawnRate = 60;
m_hSmoke->m_ParticleLifetime = 1.3f;
m_hSmoke->m_StartColor.Init( 0.65f, 0.65f , 0.65f );
m_hSmoke->m_EndColor.Init( 0.65f, 0.65f, 0.65f );
m_hSmoke->m_StartSize = 12;
m_hSmoke->m_EndSize = 64;
m_hSmoke->m_SpawnRadius = 8;
m_hSmoke->m_MinSpeed = 2;
m_hSmoke->m_MaxSpeed = 24;
m_hSmoke->SetLifetime( 1e6 );
m_hSmoke->FollowEntity( this );
}
}
}
else
{
// do half damage in the body
dmgInfo.ScaleDamage(0.5);
AddMultiDamage( dmgInfo, this );
g_pEffects->Ricochet( ptr->endpos, ptr->plane.normal );
}
if ( m_iHealth < 10 )
{
if ( m_hSmoke == NULL && (m_hSmoke = SmokeTrail::CreateSmokeTrail()) != NULL )
{
m_hSmoke->m_Opacity = 1.0f;
m_hSmoke->m_SpawnRate = 60;
m_hSmoke->m_ParticleLifetime = 1.3f;
m_hSmoke->m_StartColor.Init( 0.65f, 0.65f , 0.65f );
m_hSmoke->m_EndColor.Init( 0.65f, 0.65f, 0.65f );
m_hSmoke->m_StartSize = 12;
m_hSmoke->m_EndSize = 64;
m_hSmoke->m_SpawnRadius = 8;
m_hSmoke->m_MinSpeed = 2;
m_hSmoke->m_MaxSpeed = 24;
m_hSmoke->SetLifetime( 1e6 );
m_hSmoke->FollowEntity( this );
}
}
}
+516
View File
@@ -0,0 +1,516 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: barnacle - stationary ceiling mounted 'fishing' monster
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "hl1_npc_barnacle.h"
#include "npcevent.h"
#include "gib.h"
#include "ai_default.h"
#include "activitylist.h"
#include "hl2_player.h"
#include "vstdlib/random.h"
#include "physics_saverestore.h"
#include "vcollide_parse.h"
#include "engine/IEngineSound.h"
ConVar sk_barnacle_health( "sk_barnacle_health","25");
//-----------------------------------------------------------------------------
// Private activities.
//-----------------------------------------------------------------------------
static int ACT_EAT = 0;
//-----------------------------------------------------------------------------
// Interactions
//-----------------------------------------------------------------------------
int g_interactionBarnacleVictimDangle = 0;
int g_interactionBarnacleVictimReleased = 0;
int g_interactionBarnacleVictimGrab = 0;
LINK_ENTITY_TO_CLASS( monster_barnacle, CNPC_Barnacle );
IMPLEMENT_CUSTOM_AI( monster_barnacle, CNPC_Barnacle );
//-----------------------------------------------------------------------------
// Purpose: Initialize the custom schedules
// Input :
// Output :
//-----------------------------------------------------------------------------
void CNPC_Barnacle::InitCustomSchedules(void)
{
INIT_CUSTOM_AI(CNPC_Barnacle);
ADD_CUSTOM_ACTIVITY(CNPC_Barnacle, ACT_EAT);
g_interactionBarnacleVictimDangle = CBaseCombatCharacter::GetInteractionID();
g_interactionBarnacleVictimReleased = CBaseCombatCharacter::GetInteractionID();
g_interactionBarnacleVictimGrab = CBaseCombatCharacter::GetInteractionID();
}
BEGIN_DATADESC( CNPC_Barnacle )
DEFINE_FIELD( m_flAltitude, FIELD_FLOAT ),
DEFINE_FIELD( m_flKillVictimTime, FIELD_TIME ),
DEFINE_FIELD( m_cGibs, FIELD_INTEGER ),// barnacle loads up on gibs each time it kills something.
DEFINE_FIELD( m_fLiftingPrey, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flTongueAdj, FIELD_FLOAT ),
DEFINE_FIELD( m_flIgnoreTouchesUntil, FIELD_TIME ),
// Function pointers
DEFINE_THINKFUNC( BarnacleThink ),
DEFINE_THINKFUNC( WaitTillDead ),
END_DATADESC()
//=========================================================
// Classify - indicates this monster's place in the
// relationship table.
//=========================================================
Class_T CNPC_Barnacle::Classify ( void )
{
return CLASS_ALIEN_MONSTER;
}
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//
// Returns number of events handled, 0 if none.
//=========================================================
void CNPC_Barnacle::HandleAnimEvent( animevent_t *pEvent )
{
switch( pEvent->event )
{
case BARNACLE_AE_PUKEGIB:
CGib::SpawnRandomGibs( this, 1, GIB_HUMAN );
break;
default:
BaseClass::HandleAnimEvent( pEvent );
break;
}
}
//=========================================================
// Spawn
//=========================================================
void CNPC_Barnacle::Spawn()
{
Precache( );
SetModel( "models/barnacle.mdl" );
UTIL_SetSize( this, Vector(-16, -16, -32), Vector(16, 16, 0) );
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_NOT_STANDABLE );
SetMoveType( MOVETYPE_NONE );
SetBloodColor( BLOOD_COLOR_GREEN );
m_iHealth = sk_barnacle_health.GetFloat();
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_NPCState = NPC_STATE_NONE;
m_flKillVictimTime = 0;
m_cGibs = 0;
m_fLiftingPrey = FALSE;
m_takedamage = DAMAGE_YES;
InitBoneControllers();
InitTonguePosition();
// set eye position
SetDefaultEyeOffset();
SetActivity ( ACT_IDLE );
SetThink ( &CNPC_Barnacle::BarnacleThink );
SetNextThink( gpGlobals->curtime + 0.5f );
//Do not have a shadow
AddEffects( EF_NOSHADOW );
m_flIgnoreTouchesUntil = gpGlobals->curtime;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
int CNPC_Barnacle::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo )
{
CTakeDamageInfo info = inputInfo;
if ( info.GetDamageType() & DMG_CLUB )
{
info.SetDamage( m_iHealth );
}
return BaseClass::OnTakeDamage_Alive( info );
}
//-----------------------------------------------------------------------------
// Purpose: Initialize tongue position when first spawned
// Input :
// Output :
//-----------------------------------------------------------------------------
void CNPC_Barnacle::InitTonguePosition( void )
{
CBaseEntity *pTouchEnt;
float flLength;
pTouchEnt = TongueTouchEnt( &flLength );
m_flAltitude = flLength;
Vector origin;
QAngle angle;
GetAttachment( "TongueEnd", origin, angle );
m_flTongueAdj = origin.z - GetAbsOrigin().z;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPC_Barnacle::BarnacleThink ( void )
{
CBaseEntity *pTouchEnt;
float flLength;
SetNextThink( gpGlobals->curtime + 0.1f );
if (CAI_BaseNPC::m_nDebugBits & bits_debugDisableAI)
{
// AI Disabled, don't do anything
}
else if ( GetEnemy() != NULL )
{
// barnacle has prey.
if ( !GetEnemy()->IsAlive() )
{
// someone (maybe even the barnacle) killed the prey. Reset barnacle.
m_fLiftingPrey = FALSE;// indicate that we're not lifting prey.
SetEnemy( NULL );
return;
}
CBaseCombatCharacter* pVictim = GetEnemyCombatCharacterPointer();
Assert( pVictim );
if ( m_fLiftingPrey )
{
if ( GetEnemy() != NULL && pVictim->m_lifeState == LIFE_DEAD )
{
// crap, someone killed the prey on the way up.
SetEnemy( NULL );
m_fLiftingPrey = FALSE;
return;
}
// still pulling prey.
Vector vecNewEnemyOrigin = GetEnemy()->GetLocalOrigin();
vecNewEnemyOrigin.x = GetLocalOrigin().x;
vecNewEnemyOrigin.y = GetLocalOrigin().y;
// guess as to where their neck is
// FIXME: remove, ask victim where their neck is
vecNewEnemyOrigin.x -= 6 * cos(GetEnemy()->GetLocalAngles().y * M_PI/180.0);
vecNewEnemyOrigin.y -= 6 * sin(GetEnemy()->GetLocalAngles().y * M_PI/180.0);
m_flAltitude -= BARNACLE_PULL_SPEED;
vecNewEnemyOrigin.z += BARNACLE_PULL_SPEED;
if ( fabs( GetLocalOrigin().z - ( vecNewEnemyOrigin.z + GetEnemy()->GetViewOffset().z ) ) < BARNACLE_BODY_HEIGHT )
{
// prey has just been lifted into position ( if the victim origin + eye height + 8 is higher than the bottom of the barnacle, it is assumed that the head is within barnacle's body )
m_fLiftingPrey = FALSE;
CPASAttenuationFilter filter( this );
EmitSound( filter, entindex(), "Barnacle.Bite");
// Take a while to kill the player
m_flKillVictimTime = gpGlobals->curtime + 10;
if ( pVictim )
{
pVictim->DispatchInteraction( g_interactionBarnacleVictimDangle, NULL, this );
SetActivity ( (Activity)ACT_EAT );
}
}
CBaseEntity *pEnemy = GetEnemy();
trace_t trace;
UTIL_TraceEntity( pEnemy, pEnemy->GetAbsOrigin(), vecNewEnemyOrigin, MASK_SOLID_BRUSHONLY, pEnemy, COLLISION_GROUP_NONE, &trace );
if( trace.fraction != 1.0 )
{
// The victim cannot be moved from their current origin to this new origin. So drop them.
SetEnemy( NULL );
m_fLiftingPrey = FALSE;
if( pEnemy->MyCombatCharacterPointer() )
{
pEnemy->MyCombatCharacterPointer()->DispatchInteraction( g_interactionBarnacleVictimReleased, NULL, this );
}
// Ignore touches long enough to let the victim move away.
m_flIgnoreTouchesUntil = gpGlobals->curtime + 1.5;
SetActivity( ACT_IDLE );
return;
}
UTIL_SetOrigin ( GetEnemy(), vecNewEnemyOrigin );
}
else
{
// prey is lifted fully into feeding position and is dangling there.
if ( m_flKillVictimTime != -1 && gpGlobals->curtime > m_flKillVictimTime )
{
// kill!
if ( pVictim )
{
// DMG_CRUSH added so no physics force is generated
pVictim->TakeDamage( CTakeDamageInfo( this, this, pVictim->m_iHealth, DMG_SLASH | DMG_ALWAYSGIB | DMG_CRUSH ) );
m_cGibs = 3;
}
return;
}
// bite prey every once in a while
if ( pVictim && ( random->RandomInt( 0, 49 ) == 0 ) )
{
CPASAttenuationFilter filter( this );
EmitSound( filter, entindex(), "Barnacle.Chew" );
if ( pVictim )
{
pVictim->DispatchInteraction( g_interactionBarnacleVictimDangle, NULL, this );
}
}
}
}
else
{
// barnacle has no prey right now, so just idle and check to see if anything is touching the tongue.
// If idle and no nearby client, don't think so often. Client should be out of PVS and not within 50 feet.
if ( !UTIL_FindClientInPVS(edict()) )
{
CBasePlayer *pPlayer = UTIL_PlayerByIndex(1);
if( pPlayer )
{
Vector vecDist = pPlayer->GetAbsOrigin() - GetAbsOrigin();
if( vecDist.Length2DSqr() >= Square(600.0f) )
{
SetNextThink( gpGlobals->curtime + 1.5f );
}
}
}
if ( IsActivityFinished() )
{// this is done so barnacle will fidget.
SetActivity ( ACT_IDLE );
}
if ( m_cGibs && random->RandomInt(0,99) == 1 )
{
// cough up a gib.
CGib::SpawnRandomGibs( this, 1, GIB_HUMAN );
m_cGibs--;
CPASAttenuationFilter filter( this );
EmitSound( filter, entindex(), "Barnacle.Chew" );
}
pTouchEnt = TongueTouchEnt( &flLength );
//NDebugOverlay::Box( GetAbsOrigin() - Vector( 0, 0, flLength ), Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), 255,0,0, 0, 0.1 );
if ( pTouchEnt != NULL )
{
// tongue is fully extended, and is touching someone.
CBaseCombatCharacter* pBCC = (CBaseCombatCharacter *)pTouchEnt;
// FIXME: humans should return neck position
Vector vecGrabPos = pTouchEnt->GetAbsOrigin();
if ( pBCC && pBCC->DispatchInteraction( g_interactionBarnacleVictimGrab, &vecGrabPos, this ) )
{
CPASAttenuationFilter filter( this );
EmitSound( filter, entindex(), "Barnacle.Alert" );
SetSequenceByName ( "attack1" );
SetEnemy( pTouchEnt );
pTouchEnt->SetMoveType( MOVETYPE_FLY );
pTouchEnt->SetAbsVelocity( vec3_origin );
pTouchEnt->SetBaseVelocity( vec3_origin );
Vector origin = GetAbsOrigin();
origin.z = pTouchEnt->GetAbsOrigin().z;
pTouchEnt->SetLocalOrigin( origin );
m_fLiftingPrey = TRUE;// indicate that we should be lifting prey.
m_flKillVictimTime = -1;// set this to a bogus time while the victim is lifted.
m_flAltitude = (GetAbsOrigin().z - vecGrabPos.z);
}
}
else
{
// calculate a new length for the tongue to be clear of anything else that moves under it.
if ( m_flAltitude < flLength )
{
// if tongue is higher than is should be, lower it kind of slowly.
m_flAltitude += BARNACLE_PULL_SPEED;
}
else
{
m_flAltitude = flLength;
}
}
}
// ALERT( at_console, "tounge %f\n", m_flAltitude + m_flTongueAdj );
//NDebugOverlay::Box( GetAbsOrigin() - Vector( 0, 0, m_flAltitude ), Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), 255,255,255, 0, 0.1 );
SetBoneController( 0, -(m_flAltitude + m_flTongueAdj) );
StudioFrameAdvance();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPC_Barnacle::Event_Killed( const CTakeDamageInfo &info )
{
AddSolidFlags( FSOLID_NOT_SOLID );
m_takedamage = DAMAGE_NO;
m_lifeState = LIFE_DEAD;
if ( GetEnemy() != NULL )
{
CBaseCombatCharacter *pVictim = GetEnemyCombatCharacterPointer();
if ( pVictim )
{
pVictim->DispatchInteraction( g_interactionBarnacleVictimReleased, NULL, this );
}
}
CGib::SpawnRandomGibs( this, 4, GIB_HUMAN );
CPASAttenuationFilter filter( this );
EmitSound( filter, entindex(), "Barnacle.Die" );
SetActivity ( ACT_DIESIMPLE );
SetBoneController( 0, 0 );
StudioFrameAdvance();
SetNextThink( gpGlobals->curtime + 0.1f );
SetThink ( &CNPC_Barnacle::WaitTillDead );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CNPC_Barnacle::WaitTillDead ( void )
{
SetNextThink( gpGlobals->curtime + 0.1f );
StudioFrameAdvance();
DispatchAnimEvents ( this );
if ( IsActivityFinished() )
{
// death anim finished.
StopAnimation();
SetThink ( NULL );
}
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CNPC_Barnacle::Precache()
{
PrecacheModel("models/barnacle.mdl");
PrecacheScriptSound( "Barnacle.Bite" );
PrecacheScriptSound( "Barnacle.Chew" );
PrecacheScriptSound( "Barnacle.Alert" );
PrecacheScriptSound( "Barnacle.Die" );
BaseClass::Precache();
}
//=========================================================
// TongueTouchEnt - does a trace along the barnacle's tongue
// to see if any entity is touching it. Also stores the length
// of the trace in the int pointer provided.
//=========================================================
#define BARNACLE_CHECK_SPACING 8
CBaseEntity *CNPC_Barnacle::TongueTouchEnt ( float *pflLength )
{
trace_t tr;
float length;
// trace once to hit architecture and see if the tongue needs to change position.
UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() - Vector ( 0 , 0 , 2048 ),
MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
length = fabs( GetAbsOrigin().z - tr.endpos.z );
// Pull it up a tad
length -= 16;
if ( pflLength )
{
*pflLength = length;
}
// Don't try to touch any prey.
if ( m_flIgnoreTouchesUntil > gpGlobals->curtime )
return NULL;
Vector delta = Vector( BARNACLE_CHECK_SPACING, BARNACLE_CHECK_SPACING, 0 );
Vector mins = GetAbsOrigin() - delta;
Vector maxs = GetAbsOrigin() + delta;
maxs.z = GetAbsOrigin().z;
// Take our current tongue's length or a point higher if we hit a wall
// NOTENOTE: (this relieves the need to know if the tongue is currently moving)
mins.z -= MIN( m_flAltitude, length );
CBaseEntity *pList[10];
int count = UTIL_EntitiesInBox( pList, 10, mins, maxs, (FL_CLIENT|FL_NPC) );
if ( count )
{
for ( int i = 0; i < count; i++ )
{
CBaseCombatCharacter *pVictim = ToBaseCombatCharacter( pList[ i ] );
bool bCanHurt = false;
if ( IRelationType( pList[i] ) == D_HT || IRelationType( pList[i] ) == D_FR )
bCanHurt = true;
if ( pList[i] != this && bCanHurt == true && pVictim->m_lifeState == LIFE_ALIVE )
{
return pList[i];
}
}
}
return NULL;
}
+63
View File
@@ -0,0 +1,63 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base combat character with no AI
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#ifndef HL1_NPC_BARNACLE_H
#define HL1_NPC_BARNACLE_H
#include "hl1_ai_basenpc.h"
#include "rope_physics.h"
#define BARNACLE_BODY_HEIGHT 44 // how 'tall' the barnacle's model is.
#define BARNACLE_PULL_SPEED 8
#define BARNACLE_KILL_VICTIM_DELAY 5 // how many seconds after pulling prey in to gib them.
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
#define BARNACLE_AE_PUKEGIB 2
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CNPC_Barnacle : public CHL1BaseNPC
{
DECLARE_CLASS( CNPC_Barnacle, CHL1BaseNPC );
public:
void Spawn( void );
void InitTonguePosition( void );
void Precache( void );
CBaseEntity* TongueTouchEnt ( float *pflLength );
Class_T Classify ( void );
void HandleAnimEvent( animevent_t *pEvent );
void BarnacleThink ( void );
void WaitTillDead ( void );
void Event_Killed( const CTakeDamageInfo &info );
int OnTakeDamage_Alive( const CTakeDamageInfo &info );
DECLARE_DATADESC();
float m_flAltitude;
float m_flKillVictimTime;
int m_cGibs;// barnacle loads up on gibs each time it kills something.
bool m_fLiftingPrey;
float m_flTongueAdj;
float m_flIgnoreTouchesUntil;
public:
DEFINE_CUSTOM_AI;
};
#endif //HL1_NPC_BARNACLE_H
+938
View File
@@ -0,0 +1,938 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Bullseyes act as targets for other NPC's to attack and to trigger
// events
//
// $Workfile: $
// $Date: $
//
//-----------------------------------------------------------------------------
// $Log: $
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "ai_default.h"
#include "ai_task.h"
#include "ai_schedule.h"
#include "ai_node.h"
#include "ai_hull.h"
#include "ai_hint.h"
#include "ai_memory.h"
#include "ai_route.h"
#include "ai_motor.h"
#include "hl1_npc_barney.h"
#include "soundent.h"
#include "game.h"
#include "npcevent.h"
#include "entitylist.h"
#include "activitylist.h"
#include "animation.h"
#include "basecombatweapon.h"
#include "IEffects.h"
#include "vstdlib/random.h"
#include "engine/IEngineSound.h"
#include "ammodef.h"
#include "ai_behavior_follow.h"
#include "AI_Criteria.h"
#include "SoundEmitterSystem/isoundemittersystembase.h"
#define BA_ATTACK "BA_ATTACK"
#define BA_MAD "BA_MAD"
#define BA_SHOT "BA_SHOT"
#define BA_KILL "BA_KILL"
#define BA_POK "BA_POK"
ConVar sk_barney_health( "sk_barney_health","35");
//=========================================================
// Monster's Anim Events Go Here
//=========================================================
// first flag is barney dying for scripted sequences?
#define BARNEY_AE_DRAW ( 2 )
#define BARNEY_AE_SHOOT ( 3 )
#define BARNEY_AE_HOLSTER ( 4 )
#define BARNEY_BODY_GUNHOLSTERED 0
#define BARNEY_BODY_GUNDRAWN 1
#define BARNEY_BODY_GUNGONE 2
//---------------------------------------------------------
// Save/Restore
//---------------------------------------------------------
BEGIN_DATADESC( CNPC_Barney )
DEFINE_FIELD( m_fGunDrawn, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flPainTime, FIELD_TIME ),
DEFINE_FIELD( m_flCheckAttackTime, FIELD_TIME ),
DEFINE_FIELD( m_fLastAttackCheck, FIELD_BOOLEAN ),
DEFINE_THINKFUNC( SUB_LVFadeOut ),
//DEFINE_FIELD( m_iAmmoType, FIELD_INTEGER ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( monster_barney, CNPC_Barney );
static BOOL IsFacing( CBaseEntity *pevTest, const Vector &reference )
{
Vector vecDir = (reference - pevTest->GetAbsOrigin());
vecDir.z = 0;
VectorNormalize( vecDir );
Vector forward;
QAngle angle;
angle = pevTest->GetAbsAngles();
angle.x = 0;
AngleVectors( angle, &forward );
// He's facing me, he meant it
if ( DotProduct( forward, vecDir ) > 0.96 ) // +/- 15 degrees or so
{
return TRUE;
}
return FALSE;
}
//=========================================================
// Spawn
//=========================================================
void CNPC_Barney::Spawn()
{
Precache( );
SetModel( "models/barney.mdl");
SetRenderColor( 255, 255, 255, 255 );
SetHullType(HULL_HUMAN);
SetHullSizeNormal();
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_NOT_STANDABLE );
SetMoveType( MOVETYPE_STEP );
m_bloodColor = BLOOD_COLOR_RED;
m_iHealth = sk_barney_health.GetFloat();
SetViewOffset( Vector ( 0, 0, 100 ) );// position of the eyes relative to monster's origin.
m_flFieldOfView = VIEW_FIELD_WIDE; // NOTE: we need a wide field of view so npc will notice player and say hello
m_NPCState = NPC_STATE_NONE;
SetBodygroup( 1, 0 );
m_fGunDrawn = false;
CapabilitiesClear();
CapabilitiesAdd( bits_CAP_MOVE_GROUND | bits_CAP_OPEN_DOORS | bits_CAP_AUTO_DOORS | bits_CAP_USE | bits_CAP_DOORS_GROUP);
CapabilitiesAdd( bits_CAP_INNATE_RANGE_ATTACK1 | bits_CAP_TURN_HEAD | bits_CAP_ANIMATEDFACE );
NPCInit();
SetUse( &CNPC_Barney::FollowerUse );
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CNPC_Barney::Precache()
{
m_iAmmoType = GetAmmoDef()->Index("9mmRound");
PrecacheModel("models/barney.mdl");
PrecacheScriptSound( "Barney.FirePistol" );
PrecacheScriptSound( "Barney.Pain" );
PrecacheScriptSound( "Barney.Die" );
// every new barney must call this, otherwise
// when a level is loaded, nobody will talk (time is reset to 0)
TalkInit();
BaseClass::Precache();
}
void CNPC_Barney::ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet )
{
BaseClass::ModifyOrAppendCriteria( criteriaSet );
bool predisaster = FBitSet( m_spawnflags, SF_NPC_PREDISASTER ) ? true : false;
criteriaSet.AppendCriteria( "disaster", predisaster ? "[disaster::pre]" : "[disaster::post]" );
}
// Init talk data
void CNPC_Barney::TalkInit()
{
BaseClass::TalkInit();
// get voice for head - just one barney voice for now
GetExpresser()->SetVoicePitch( 100 );
}
//=========================================================
// GetSoundInterests - returns a bit mask indicating which types
// of sounds this monster regards.
//=========================================================
int CNPC_Barney::GetSoundInterests ( void)
{
return SOUND_WORLD |
SOUND_COMBAT |
SOUND_CARCASS |
SOUND_MEAT |
SOUND_GARBAGE |
SOUND_DANGER |
SOUND_PLAYER;
}
//=========================================================
// Classify - indicates this monster's place in the
// relationship table.
//=========================================================
Class_T CNPC_Barney::Classify ( void )
{
return CLASS_PLAYER_ALLY;
}
//=========================================================
// ALertSound - barney says "Freeze!"
//=========================================================
void CNPC_Barney::AlertSound( void )
{
if ( GetEnemy() != NULL )
{
if ( IsOkToSpeak() )
{
Speak( BA_ATTACK );
}
}
}
//=========================================================
// SetYawSpeed - allows each sequence to have a different
// turn rate associated with it.
//=========================================================
void CNPC_Barney::SetYawSpeed ( void )
{
int ys;
ys = 0;
switch ( GetActivity() )
{
case ACT_IDLE:
ys = 70;
break;
case ACT_WALK:
ys = 70;
break;
case ACT_RUN:
ys = 90;
break;
default:
ys = 70;
break;
}
GetMotor()->SetYawSpeed( ys );
}
//=========================================================
// CheckRangeAttack1
//=========================================================
bool CNPC_Barney::CheckRangeAttack1 ( float flDot, float flDist )
{
if ( gpGlobals->curtime > m_flCheckAttackTime )
{
trace_t tr;
Vector shootOrigin = GetAbsOrigin() + Vector( 0, 0, 55 );
CBaseEntity *pEnemy = GetEnemy();
Vector shootTarget = ( (pEnemy->BodyTarget( shootOrigin ) - pEnemy->GetAbsOrigin()) + GetEnemyLKP() );
UTIL_TraceLine ( shootOrigin, shootTarget, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr);
m_flCheckAttackTime = gpGlobals->curtime + 1;
if ( tr.fraction == 1.0 || ( tr.m_pEnt != NULL && tr.m_pEnt == pEnemy) )
m_fLastAttackCheck = TRUE;
else
m_fLastAttackCheck = FALSE;
m_flCheckAttackTime = gpGlobals->curtime + 1.5;
}
return m_fLastAttackCheck;
}
//------------------------------------------------------------------------------
// Purpose : For innate range attack
// Input :
// Output :
//------------------------------------------------------------------------------
int CNPC_Barney::RangeAttack1Conditions( float flDot, float flDist )
{
if (GetEnemy() == NULL)
{
return( COND_NONE );
}
else if ( flDist > 1024 )
{
return( COND_TOO_FAR_TO_ATTACK );
}
else if ( flDot < 0.5 )
{
return( COND_NOT_FACING_ATTACK );
}
if ( CheckRangeAttack1 ( flDot, flDist ) )
return( COND_CAN_RANGE_ATTACK1 );
return COND_NONE;
}
//=========================================================
// BarneyFirePistol - shoots one round from the pistol at
// the enemy barney is facing.
//=========================================================
void CNPC_Barney::BarneyFirePistol ( void )
{
Vector vecShootOrigin;
vecShootOrigin = GetAbsOrigin() + Vector( 0, 0, 55 );
Vector vecShootDir = GetShootEnemyDir( vecShootOrigin );
QAngle angDir;
VectorAngles( vecShootDir, angDir );
// SetBlending( 0, angDir.x );
DoMuzzleFlash();
FireBullets(1, vecShootOrigin, vecShootDir, VECTOR_CONE_2DEGREES, 1024, m_iAmmoType );
int pitchShift = random->RandomInt( 0, 20 );
// Only shift about half the time
if ( pitchShift > 10 )
pitchShift = 0;
else
pitchShift -= 5;
CPASAttenuationFilter filter( this );
EmitSound_t params;
params.m_pSoundName = "Barney.FirePistol";
params.m_flVolume = 1;
params.m_nChannel= CHAN_WEAPON;
params.m_SoundLevel = SNDLVL_NORM;
params.m_nPitch = 100 + pitchShift;
EmitSound( filter, entindex(), params );
CSoundEnt::InsertSound ( SOUND_COMBAT, GetAbsOrigin(), 384, 0.3 );
// UNDONE: Reload?
m_cAmmoLoaded--;// take away a bullet!
}
int CNPC_Barney::OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo )
{
// make sure friends talk about it if player hurts talkmonsters...
int ret = BaseClass::OnTakeDamage_Alive( inputInfo );
if ( !IsAlive() || m_lifeState == LIFE_DYING )
return ret;
if ( m_NPCState != NPC_STATE_PRONE && ( inputInfo.GetAttacker()->GetFlags() & FL_CLIENT ) )
{
// This is a heurstic to determine if the player intended to harm me
// If I have an enemy, we can't establish intent (may just be crossfire)
if ( GetEnemy() == NULL )
{
// If the player was facing directly at me, or I'm already suspicious, get mad
if ( HasMemory( bits_MEMORY_SUSPICIOUS ) || IsFacing( inputInfo.GetAttacker(), GetAbsOrigin() ) )
{
// Alright, now I'm pissed!
Speak( BA_MAD );
Remember( bits_MEMORY_PROVOKED );
StopFollowing();
}
else
{
// Hey, be careful with that
Speak( BA_SHOT );
Remember( bits_MEMORY_SUSPICIOUS );
}
}
else if ( !(GetEnemy()->IsPlayer()) && m_lifeState == LIFE_ALIVE )
{
Speak( BA_SHOT );
}
}
return ret;
}
//=========================================================
// PainSound
//=========================================================
void CNPC_Barney::PainSound( const CTakeDamageInfo &info )
{
if (gpGlobals->curtime < m_flPainTime)
return;
m_flPainTime = gpGlobals->curtime + random->RandomFloat( 0.5, 0.75 );
CPASAttenuationFilter filter( this );
CSoundParameters params;
if ( GetParametersForSound( "Barney.Pain", params, NULL ) )
{
params.pitch = GetExpresser()->GetVoicePitch();
EmitSound_t ep( params );
EmitSound( filter, entindex(), ep );
}
}
//=========================================================
// DeathSound
//=========================================================
void CNPC_Barney::DeathSound( const CTakeDamageInfo &info )
{
CPASAttenuationFilter filter( this );
CSoundParameters params;
if ( GetParametersForSound( "Barney.Die", params, NULL ) )
{
params.pitch = GetExpresser()->GetVoicePitch();
EmitSound_t ep( params );
EmitSound( filter, entindex(), ep );
}
}
void CNPC_Barney::TraceAttack( const CTakeDamageInfo &inputInfo, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator )
{
CTakeDamageInfo info = inputInfo;
switch( ptr->hitgroup )
{
case HITGROUP_CHEST:
case HITGROUP_STOMACH:
if ( info.GetDamageType() & (DMG_BULLET | DMG_SLASH | DMG_BLAST) )
{
info.ScaleDamage( 0.5f );
}
break;
case 10:
if ( info.GetDamageType() & (DMG_BULLET | DMG_SLASH | DMG_CLUB) )
{
info.SetDamage( info.GetDamage() - 20 );
if ( info.GetDamage() <= 0 )
{
g_pEffects->Ricochet( ptr->endpos, ptr->plane.normal );
info.SetDamage( 0.01 );
}
}
// always a head shot
ptr->hitgroup = HITGROUP_HEAD;
break;
}
BaseClass::TraceAttack( info, vecDir, ptr, pAccumulator );
}
void CNPC_Barney::Event_Killed( const CTakeDamageInfo &info )
{
if ( m_nBody < BARNEY_BODY_GUNGONE )
{
// drop the gun!
Vector vecGunPos;
QAngle angGunAngles;
CBaseEntity *pGun = NULL;
SetBodygroup( 1, BARNEY_BODY_GUNGONE);
GetAttachment( "0", vecGunPos, angGunAngles );
angGunAngles.y += 180;
pGun = DropItem( "weapon_glock", vecGunPos, angGunAngles );
}
SetUse( NULL );
BaseClass::Event_Killed( info );
if ( UTIL_IsLowViolence() )
{
SUB_StartLVFadeOut( 0.0f );
}
}
void CNPC_Barney::SUB_StartLVFadeOut( float delay, bool notSolid )
{
SetThink( &CNPC_Barney::SUB_LVFadeOut );
SetNextThink( gpGlobals->curtime + delay );
SetRenderColorA( 255 );
m_nRenderMode = kRenderNormal;
if ( notSolid )
{
AddSolidFlags( FSOLID_NOT_SOLID );
SetLocalAngularVelocity( vec3_angle );
}
}
void CNPC_Barney::SUB_LVFadeOut( void )
{
if( VPhysicsGetObject() )
{
if( VPhysicsGetObject()->GetGameFlags() & FVPHYSICS_PLAYER_HELD || GetEFlags() & EFL_IS_BEING_LIFTED_BY_BARNACLE )
{
// Try again in a few seconds.
SetNextThink( gpGlobals->curtime + 5 );
SetRenderColorA( 255 );
return;
}
}
float dt = gpGlobals->frametime;
if ( dt > 0.1f )
{
dt = 0.1f;
}
m_nRenderMode = kRenderTransTexture;
int speed = MAX(3,256*dt); // fade out over 3 seconds
SetRenderColorA( UTIL_Approach( 0, m_clrRender->a, speed ) );
NetworkStateChanged();
if ( m_clrRender->a == 0 )
{
UTIL_Remove(this);
}
else
{
SetNextThink( gpGlobals->curtime );
}
}
void CNPC_Barney::StartTask( const Task_t *pTask )
{
BaseClass::StartTask( pTask );
}
void CNPC_Barney::RunTask( const Task_t *pTask )
{
switch ( pTask->iTask )
{
case TASK_RANGE_ATTACK1:
if (GetEnemy() != NULL && (GetEnemy()->IsPlayer()))
{
m_flPlaybackRate = 1.5;
}
BaseClass::RunTask( pTask );
break;
default:
BaseClass::RunTask( pTask );
break;
}
}
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//
// Returns number of events handled, 0 if none.
//=========================================================
void CNPC_Barney::HandleAnimEvent( animevent_t *pEvent )
{
switch( pEvent->event )
{
case BARNEY_AE_SHOOT:
BarneyFirePistol();
break;
case BARNEY_AE_DRAW:
// barney's bodygroup switches here so he can pull gun from holster
SetBodygroup( 1, BARNEY_BODY_GUNDRAWN);
m_fGunDrawn = true;
break;
case BARNEY_AE_HOLSTER:
// change bodygroup to replace gun in holster
SetBodygroup( 1, BARNEY_BODY_GUNHOLSTERED);
m_fGunDrawn = false;
break;
default:
BaseClass::HandleAnimEvent( pEvent );
}
}
//=========================================================
// AI Schedules Specific to this monster
//=========================================================
int CNPC_Barney::TranslateSchedule( int scheduleType )
{
switch( scheduleType )
{
case SCHED_ARM_WEAPON:
if ( GetEnemy() != NULL )
{
// face enemy, then draw.
return SCHED_BARNEY_ENEMY_DRAW;
}
break;
// Hook these to make a looping schedule
case SCHED_TARGET_FACE:
{
int baseType;
// call base class default so that scientist will talk
// when 'used'
baseType = BaseClass::TranslateSchedule( scheduleType );
if ( baseType == SCHED_IDLE_STAND )
return SCHED_BARNEY_FACE_TARGET;
else
return baseType;
}
break;
case SCHED_TARGET_CHASE:
{
return SCHED_BARNEY_FOLLOW;
break;
}
case SCHED_IDLE_STAND:
{
int baseType;
// call base class default so that scientist will talk
// when 'used'
baseType = BaseClass::TranslateSchedule( scheduleType );
if ( baseType == SCHED_IDLE_STAND )
return SCHED_BARNEY_IDLE_STAND;
else
return baseType;
}
break;
case SCHED_TAKE_COVER_FROM_ENEMY:
case SCHED_CHASE_ENEMY:
{
if ( HasCondition( COND_HEAVY_DAMAGE ) )
return SCHED_TAKE_COVER_FROM_ENEMY;
// No need to take cover since I can see him
// SHOOT!
if ( HasCondition( COND_CAN_RANGE_ATTACK1 ) && m_fGunDrawn )
return SCHED_RANGE_ATTACK1;
}
break;
}
return BaseClass::TranslateSchedule( scheduleType );
}
//=========================================================
// SelectSchedule - Decides which type of schedule best suits
// the monster's current state and conditions. Then calls
// monster's member function to get a pointer to a schedule
// of the proper type.
//=========================================================
int CNPC_Barney::SelectSchedule( void )
{
if ( m_NPCState == NPC_STATE_COMBAT || GetEnemy() != NULL )
{
// Priority action!
if (!m_fGunDrawn )
return SCHED_ARM_WEAPON;
}
if ( GetFollowTarget() == NULL )
{
if ( HasCondition( COND_PLAYER_PUSHING ) && !(GetSpawnFlags() & SF_NPC_PREDISASTER ) ) // Player wants me to move
return SCHED_HL1TALKER_FOLLOW_MOVE_AWAY;
}
if ( BehaviorSelectSchedule() )
return BaseClass::SelectSchedule();
if ( HasCondition( COND_HEAR_DANGER ) )
{
CSound *pSound;
pSound = GetBestSound();
ASSERT( pSound != NULL );
if ( pSound && pSound->IsSoundType( SOUND_DANGER ) )
return SCHED_TAKE_COVER_FROM_BEST_SOUND;
}
if ( HasCondition( COND_ENEMY_DEAD ) && IsOkToSpeak() )
{
Speak( BA_KILL );
}
switch( m_NPCState )
{
case NPC_STATE_COMBAT:
{
// dead enemy
if ( HasCondition( COND_ENEMY_DEAD ) )
return BaseClass::SelectSchedule(); // call base class, all code to handle dead enemies is centralized there.
// always act surprized with a new enemy
if ( HasCondition( COND_NEW_ENEMY ) && HasCondition( COND_LIGHT_DAMAGE) )
return SCHED_SMALL_FLINCH;
if ( HasCondition( COND_HEAVY_DAMAGE ) )
return SCHED_TAKE_COVER_FROM_ENEMY;
if ( !HasCondition(COND_SEE_ENEMY) )
{
// we can't see the enemy
if ( !HasCondition(COND_ENEMY_OCCLUDED) )
{
// enemy is unseen, but not occluded!
// turn to face enemy
return SCHED_COMBAT_FACE;
}
else
{
return SCHED_CHASE_ENEMY;
}
}
}
break;
case NPC_STATE_ALERT:
case NPC_STATE_IDLE:
if ( HasCondition( COND_LIGHT_DAMAGE ) || HasCondition( COND_HEAVY_DAMAGE ) )
{
// flinch if hurt
return SCHED_SMALL_FLINCH;
}
if ( GetEnemy() == NULL && GetFollowTarget() )
{
if ( !GetFollowTarget()->IsAlive() )
{
// UNDONE: Comment about the recently dead player here?
StopFollowing();
break;
}
else
{
return SCHED_TARGET_FACE;
}
}
// try to say something about smells
TrySmellTalk();
break;
}
return BaseClass::SelectSchedule();
}
NPC_STATE CNPC_Barney::SelectIdealState ( void )
{
return BaseClass::SelectIdealState();
}
void CNPC_Barney::DeclineFollowing( void )
{
if ( CanSpeakAfterMyself() )
{
Speak( BA_POK );
}
}
bool CNPC_Barney::CanBecomeRagdoll( void )
{
if ( UTIL_IsLowViolence() )
{
return false;
}
return BaseClass::CanBecomeRagdoll();
}
bool CNPC_Barney::ShouldGib( const CTakeDamageInfo &info )
{
if ( UTIL_IsLowViolence() )
{
return false;
}
return BaseClass::ShouldGib( info );
}
//------------------------------------------------------------------------------
//
// Schedules
//
//------------------------------------------------------------------------------
AI_BEGIN_CUSTOM_NPC( monster_barney, CNPC_Barney )
//=========================================================
// > SCHED_BARNEY_FOLLOW
//=========================================================
DEFINE_SCHEDULE
(
SCHED_BARNEY_FOLLOW,
" Tasks"
// " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_BARNEY_STOP_FOLLOWING"
" TASK_GET_PATH_TO_TARGET 0"
" TASK_MOVE_TO_TARGET_RANGE 180"
" TASK_SET_SCHEDULE SCHEDULE:SCHED_TARGET_FACE"
" "
" Interrupts"
" COND_NEW_ENEMY"
" COND_LIGHT_DAMAGE"
" COND_HEAVY_DAMAGE"
" COND_HEAR_DANGER"
" COND_PROVOKED"
)
//=========================================================
// > SCHED_BARNEY_ENEMY_DRAW
//=========================================================
DEFINE_SCHEDULE
(
SCHED_BARNEY_ENEMY_DRAW,
" Tasks"
" TASK_STOP_MOVING 0"
" TASK_FACE_ENEMY 0"
" TASK_PLAY_SEQUENCE_FACE_ENEMY ACTIVITY:ACT_ARM"
" "
" Interrupts"
)
//=========================================================
// > SCHED_BARNEY_FACE_TARGET
//=========================================================
DEFINE_SCHEDULE
(
SCHED_BARNEY_FACE_TARGET,
" Tasks"
" TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
" TASK_FACE_TARGET 0"
" TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
" TASK_SET_SCHEDULE SCHEDULE:SCHED_BARNEY_FOLLOW"
" "
" Interrupts"
" COND_GIVE_WAY"
" COND_NEW_ENEMY"
" COND_LIGHT_DAMAGE"
" COND_HEAVY_DAMAGE"
" COND_PROVOKED"
" COND_HEAR_DANGER"
)
//=========================================================
// > SCHED_BARNEY_IDLE_STAND
//=========================================================
DEFINE_SCHEDULE
(
SCHED_BARNEY_IDLE_STAND,
" Tasks"
" TASK_STOP_MOVING 0"
" TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
" TASK_WAIT 2"
" TASK_TALKER_HEADRESET 0"
" "
" Interrupts"
" COND_NEW_ENEMY"
" COND_LIGHT_DAMAGE"
" COND_HEAVY_DAMAGE"
" COND_PROVOKED"
" COND_HEAR_COMBAT"
" COND_SMELL"
)
AI_END_CUSTOM_NPC()
//=========================================================
// DEAD BARNEY PROP
//
// Designer selects a pose in worldcraft, 0 through num_poses-1
// this value is added to what is selected as the 'first dead pose'
// among the monster's normal animations. All dead poses must
// appear sequentially in the model file. Be sure and set
// the m_iFirstPose properly!
//
//=========================================================
class CNPC_DeadBarney : public CAI_BaseNPC
{
DECLARE_CLASS( CNPC_DeadBarney, CAI_BaseNPC );
public:
void Spawn( void );
Class_T Classify ( void ) { return CLASS_NONE; }
bool KeyValue( const char *szKeyName, const char *szValue );
float MaxYawSpeed ( void ) { return 8.0f; }
int m_iPose;// which sequence to display -- temporary, don't need to save
int m_iDesiredSequence;
static char *m_szPoses[3];
DECLARE_DATADESC();
};
char *CNPC_DeadBarney::m_szPoses[] = { "lying_on_back", "lying_on_side", "lying_on_stomach" };
bool CNPC_DeadBarney::KeyValue( const char *szKeyName, const char *szValue )
{
if ( FStrEq( szKeyName, "pose" ) )
m_iPose = atoi( szValue );
else
BaseClass::KeyValue( szKeyName, szValue );
return true;
}
LINK_ENTITY_TO_CLASS( monster_barney_dead, CNPC_DeadBarney );
BEGIN_DATADESC( CNPC_DeadBarney )
END_DATADESC()
//=========================================================
// ********** DeadBarney SPAWN **********
//=========================================================
void CNPC_DeadBarney::Spawn( void )
{
PrecacheModel("models/barney.mdl");
SetModel( "models/barney.mdl");
ClearEffects();
SetSequence( 0 );
m_bloodColor = BLOOD_COLOR_RED;
SetRenderColor( 255, 255, 255, 255 );
SetSequence( m_iDesiredSequence = LookupSequence( m_szPoses[m_iPose] ) );
if ( GetSequence() == -1 )
{
Msg ( "Dead barney with bad pose\n" );
}
// Corpses have less health
m_iHealth = 0.0;//gSkillData.barneyHealth;
NPCInitDead();
}
+81
View File
@@ -0,0 +1,81 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef NPC_BARNEY_H
#define NPC_BARNEY_H
#include "hl1_npc_talker.h"
//=========================================================
//=========================================================
class CNPC_Barney : public CHL1NPCTalker
{
DECLARE_CLASS( CNPC_Barney, CHL1NPCTalker );
public:
DECLARE_DATADESC();
virtual void ModifyOrAppendCriteria( AI_CriteriaSet& set );
void Precache( void );
void Spawn( void );
void TalkInit( void );
void StartTask( const Task_t *pTask );
void RunTask( const Task_t *pTask );
int GetSoundInterests ( void );
Class_T Classify ( void );
void AlertSound( void );
void SetYawSpeed ( void );
bool CheckRangeAttack1 ( float flDot, float flDist );
void BarneyFirePistol ( void );
int OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo );
void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator );
void Event_Killed( const CTakeDamageInfo &info );
void PainSound( const CTakeDamageInfo &info );
void DeathSound( const CTakeDamageInfo &info );
void HandleAnimEvent( animevent_t *pEvent );
int TranslateSchedule( int scheduleType );
int SelectSchedule( void );
void DeclineFollowing( void );
bool CanBecomeRagdoll( void );
bool ShouldGib( const CTakeDamageInfo &info );
int RangeAttack1Conditions( float flDot, float flDist );
void SUB_StartLVFadeOut( float delay = 10.0f, bool bNotSolid = true );
void SUB_LVFadeOut( void );
NPC_STATE SelectIdealState ( void );
bool m_fGunDrawn;
float m_flPainTime;
float m_flCheckAttackTime;
bool m_fLastAttackCheck;
int m_iAmmoType;
enum
{
SCHED_BARNEY_FOLLOW = BaseClass::NEXT_SCHEDULE,
SCHED_BARNEY_ENEMY_DRAW,
SCHED_BARNEY_FACE_TARGET,
SCHED_BARNEY_IDLE_STAND,
SCHED_BARNEY_STOP_FOLLOWING,
};
DEFINE_CUSTOM_AI;
};
#endif //NPC_BARNEY_H
File diff suppressed because it is too large Load Diff
+86
View File
@@ -0,0 +1,86 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "ai_default.h"
#include "ai_task.h"
#include "ai_schedule.h"
#include "ai_node.h"
#include "ai_hull.h"
#include "ai_hint.h"
#include "ai_memory.h"
#include "ai_route.h"
#include "ai_motor.h"
#include "soundent.h"
#include "game.h"
#include "npcevent.h"
#include "entitylist.h"
#include "activitylist.h"
#include "animation.h"
#include "basecombatweapon.h"
#include "IEffects.h"
#include "vstdlib/random.h"
#include "engine/IEngineSound.h"
#include "ammodef.h"
#include "hl1_ai_basenpc.h"
class CNPC_Bloater : public CHL1BaseNPC
{
DECLARE_CLASS( CNPC_Bloater, CHL1BaseNPC );
public:
void Spawn( void );
void Precache( void );
/*void SetYawSpeed( void );
int Classify ( void );
void HandleAnimEvent( MonsterEvent_t *pEvent );
void PainSound( const CTakeDamageInfo &info );
void AlertSound( void );
void IdleSound( void );
void AttackSnd( void );
// No range attacks
BOOL CheckRangeAttack1 ( float flDot, float flDist ) { return FALSE; }
BOOL CheckRangeAttack2 ( float flDot, float flDist ) { return FALSE; }
int TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType );*/
};
LINK_ENTITY_TO_CLASS( monster_bloater, CNPC_Bloater );
//=========================================================
// Spawn
//=========================================================
void CNPC_Bloater::Spawn()
{
Precache( );
SetModel( "models/floater.mdl");
// UTIL_SetSize( this, VEC_HUMAN_HULL_MIN, VEC_HUMAN_HULL_MAX );
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_NOT_STANDABLE );
SetMoveType( MOVETYPE_FLY );
m_spawnflags |= FL_FLY;
m_bloodColor = BLOOD_COLOR_GREEN;
m_iHealth = 40;
// pev->view_ofs = VEC_VIEW;// position of the eyes relative to monster's origin.
m_flFieldOfView = 0.5;// indicates the width of this monster's forward view cone ( as a dotproduct result )
m_NPCState = NPC_STATE_NONE;
SetRenderColor( 255, 255, 255, 255 );
NPCInit();
}
//=========================================================
// Precache - precaches all resources this monster needs
//=========================================================
void CNPC_Bloater::Precache()
{
PrecacheModel("models/floater.mdl");
}
File diff suppressed because it is too large Load Diff
+68
View File
@@ -0,0 +1,68 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef NPC_BULLSQUID_H
#define NPC_BULLSQUID_H
#include "hl1_ai_basenpc.h"
class CNPC_Bullsquid : public CHL1BaseNPC
{
DECLARE_CLASS( CNPC_Bullsquid, CHL1BaseNPC );
public:
void Spawn( void );
void Precache( void );
Class_T Classify( void );
void IdleSound( void );
void PainSound( const CTakeDamageInfo &info );
void AlertSound( void );
void DeathSound( const CTakeDamageInfo &info );
void AttackSound( void );
float MaxYawSpeed( void );
void HandleAnimEvent( animevent_t *pEvent );
int RangeAttack1Conditions( float flDot, float flDist );
int MeleeAttack1Conditions( float flDot, float flDist );
int MeleeAttack2Conditions( float flDot, float flDist );
bool FValidateHintType ( CAI_Hint *pHint );
void RemoveIgnoredConditions( void );
Disposition_t IRelationType( CBaseEntity *pTarget );
int OnTakeDamage_Alive( const CTakeDamageInfo &inputInfo );
int GetSoundInterests ( void );
void RunAI ( void );
virtual void OnListened ( void );
int SelectSchedule( void );
int TranslateSchedule( int scheduleType );
bool FInViewCone ( Vector pOrigin );
bool FVisible ( Vector vecOrigin );
void StartTask ( const Task_t *pTask );
void RunTask ( const Task_t *pTask );
NPC_STATE SelectIdealState ( void );
DEFINE_CUSTOM_AI;
DECLARE_DATADESC()
private:
bool m_fCanThreatDisplay;// this is so the squid only does the "I see a headcrab!" dance one time.
float m_flLastHurtTime;// we keep track of this, because if something hurts a squid, it will forget about its love of headcrabs for a while.
float m_flNextSpitTime;// last time the bullsquid used the spit attack.
float m_flHungryTime;// set this is a future time to stop the monster from eating for a while.
};
#endif // NPC_BULLSQUID_H

Some files were not shown because too many files have changed in this diff Show More