|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: The TF Game rules
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "sdk_gamerules.h"
#include "ammodef.h"
#include "KeyValues.h"
#include "weapon_sdkbase.h"
#ifdef CLIENT_DLL
#else
#include "voice_gamemgr.h"
#include "team.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#ifndef CLIENT_DLL
LINK_ENTITY_TO_CLASS(info_player_terrorist, CPointEntity); LINK_ENTITY_TO_CLASS(info_player_counterterrorist,CPointEntity); #endif
REGISTER_GAMERULES_CLASS( CSDKGameRules );
BEGIN_NETWORK_TABLE_NOBASE( CSDKGameRules, DT_SDKGameRules ) END_NETWORK_TABLE()
LINK_ENTITY_TO_CLASS( sdk_gamerules, CSDKGameRulesProxy ); IMPLEMENT_NETWORKCLASS_ALIASED( SDKGameRulesProxy, DT_SDKGameRulesProxy )
#ifdef CLIENT_DLL
void RecvProxy_SDKGameRules( const RecvProp *pProp, void **pOut, void *pData, int objectID ) { CSDKGameRules *pRules = SDKGameRules(); Assert( pRules ); *pOut = pRules; }
BEGIN_RECV_TABLE( CSDKGameRulesProxy, DT_SDKGameRulesProxy ) RecvPropDataTable( "sdk_gamerules_data", 0, 0, &REFERENCE_RECV_TABLE( DT_SDKGameRules ), RecvProxy_SDKGameRules ) END_RECV_TABLE() #else
void *SendProxy_SDKGameRules( const SendProp *pProp, const void *pStructBase, const void *pData, CSendProxyRecipients *pRecipients, int objectID ) { CSDKGameRules *pRules = SDKGameRules(); Assert( pRules ); pRecipients->SetAllRecipients(); return pRules; }
BEGIN_SEND_TABLE( CSDKGameRulesProxy, DT_SDKGameRulesProxy ) SendPropDataTable( "sdk_gamerules_data", 0, &REFERENCE_SEND_TABLE( DT_SDKGameRules ), SendProxy_SDKGameRules ) END_SEND_TABLE() #endif
#ifdef CLIENT_DLL
#else
// --------------------------------------------------------------------------------------------------- //
// Voice helper
// --------------------------------------------------------------------------------------------------- //
class CVoiceGameMgrHelper : public IVoiceGameMgrHelper { public: virtual bool CanPlayerHearPlayer( CBasePlayer *pListener, CBasePlayer *pTalker ) { // Dead players can only be heard by other dead team mates
if ( pTalker->IsAlive() == false ) { if ( pListener->IsAlive() == false ) return ( pListener->InSameTeam( pTalker ) );
return false; }
return ( pListener->InSameTeam( pTalker ) ); } }; CVoiceGameMgrHelper g_VoiceGameMgrHelper; IVoiceGameMgrHelper *g_pVoiceGameMgrHelper = &g_VoiceGameMgrHelper;
// --------------------------------------------------------------------------------------------------- //
// Globals.
// --------------------------------------------------------------------------------------------------- //
// NOTE: the indices here must match TEAM_TERRORIST, TEAM_CT, TEAM_SPECTATOR, etc.
char *sTeamNames[] = { "Unassigned", "Spectator", "Terrorist", "Counter-Terrorist" };
// --------------------------------------------------------------------------------------------------- //
// Global helper functions.
// --------------------------------------------------------------------------------------------------- //
// World.cpp calls this but we don't use it in SDK.
void InitBodyQue() { }
// --------------------------------------------------------------------------------------------------- //
// CSDKGameRules implementation.
// --------------------------------------------------------------------------------------------------- //
CSDKGameRules::CSDKGameRules() { // Create the team managers
for ( int i = 0; i < ARRAYSIZE( sTeamNames ); i++ ) { CTeam *pTeam = static_cast<CTeam*>(CreateEntityByName( "sdk_team_manager" )); pTeam->Init( sTeamNames[i], i );
g_Teams.AddToTail( pTeam ); } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CSDKGameRules::~CSDKGameRules() { // Note, don't delete each team since they are in the gEntList and will
// automatically be deleted from there, instead.
g_Teams.Purge(); }
//-----------------------------------------------------------------------------
// Purpose: TF2 Specific Client Commands
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CSDKGameRules::ClientCommand( CBaseEntity *pEdict, const CCommand &args ) { return BaseClass::ClientCommand( pEdict, args ); }
//-----------------------------------------------------------------------------
// Purpose: Player has just spawned. Equip them.
//-----------------------------------------------------------------------------
void CSDKGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore ) { RadiusDamage( info, vecSrcIn, flRadius, iClassIgnore, false ); }
// Add the ability to ignore the world trace
void CSDKGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, bool bIgnoreWorld ) { CBaseEntity *pEntity = NULL; trace_t tr; float flAdjustedDamage, falloff; Vector vecSpot; Vector vecToTarget; Vector vecEndPos;
Vector vecSrc = vecSrcIn;
if ( flRadius ) falloff = info.GetDamage() / flRadius; else falloff = 1.0;
int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; vecSrc.z += 1;// in case grenade is lying on the ground
// iterate on all entities in the vicinity.
for ( CEntitySphereQuery sphere( vecSrc, flRadius ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) { if ( pEntity->m_takedamage != DAMAGE_NO ) { // UNDONE: this should check a damage mask, not an ignore
if ( iClassIgnore != CLASS_NONE && pEntity->Classify() == iClassIgnore ) {// houndeyes don't hurt other houndeyes with their attack
continue; }
// blast's don't tavel into or out of water
if (bInWater && pEntity->GetWaterLevel() == 0) continue; if (!bInWater && pEntity->GetWaterLevel() == 3) continue;
// radius damage can only be blocked by the world
vecSpot = pEntity->BodyTarget( vecSrc );
bool bHit = false;
if( bIgnoreWorld ) { vecEndPos = vecSpot; bHit = true; } else { UTIL_TraceLine( vecSrc, vecSpot, MASK_SOLID_BRUSHONLY, info.GetInflictor(), COLLISION_GROUP_NONE, &tr );
if (tr.startsolid) { // if we're stuck inside them, fixup the position and distance
tr.endpos = vecSrc; tr.fraction = 0.0; }
vecEndPos = tr.endpos;
if( tr.fraction == 1.0 || tr.m_pEnt == pEntity ) { bHit = true; } }
if ( bHit ) { // the explosion can 'see' this entity, so hurt them!
//vecToTarget = ( vecSrc - vecEndPos );
vecToTarget = ( vecEndPos - vecSrc );
// decrease damage for an ent that's farther from the bomb.
flAdjustedDamage = vecToTarget.Length() * falloff; flAdjustedDamage = info.GetDamage() - flAdjustedDamage; if ( flAdjustedDamage > 0 ) { CTakeDamageInfo adjustedInfo = info; adjustedInfo.SetDamage( flAdjustedDamage );
Vector dir = vecToTarget; VectorNormalize( dir );
// If we don't have a damage force, manufacture one
if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) { CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc, 1.5 /* explosion scale! */ ); } else { // Assume the force passed in is the maximum force. Decay it based on falloff.
float flForce = adjustedInfo.GetDamageForce().Length() * falloff; adjustedInfo.SetDamageForce( dir * flForce ); adjustedInfo.SetDamagePosition( vecSrc ); }
pEntity->TakeDamage( adjustedInfo ); // Now hit all triggers along the way that respond to damage...
pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, vecEndPos, dir ); } } } } }
void CSDKGameRules::Think() { BaseClass::Think(); }
#endif
bool CSDKGameRules::ShouldCollide( int collisionGroup0, int collisionGroup1 ) { if ( collisionGroup0 > collisionGroup1 ) { // swap so that lowest is always first
swap(collisionGroup0,collisionGroup1); } //Don't stand on COLLISION_GROUP_WEAPON
if( collisionGroup0 == COLLISION_GROUP_PLAYER_MOVEMENT && collisionGroup1 == COLLISION_GROUP_WEAPON ) { return false; } return BaseClass::ShouldCollide( collisionGroup0, collisionGroup1 ); }
//-----------------------------------------------------------------------------
// Purpose: Init CS ammo definitions
//-----------------------------------------------------------------------------
// shared ammo definition
// JAY: Trying to make a more physical bullet response
#define BULLET_MASS_GRAINS_TO_LB(grains) (0.002285*(grains)/16.0f)
#define BULLET_MASS_GRAINS_TO_KG(grains) lbs2kg(BULLET_MASS_GRAINS_TO_LB(grains))
// exaggerate all of the forces, but use real numbers to keep them consistent
#define BULLET_IMPULSE_EXAGGERATION 1
// convert a velocity in ft/sec and a mass in grains to an impulse in kg in/s
#define BULLET_IMPULSE(grains, ftpersec) ((ftpersec)*12*BULLET_MASS_GRAINS_TO_KG(grains)*BULLET_IMPULSE_EXAGGERATION)
CAmmoDef* GetAmmoDef() { static CAmmoDef def; static bool bInitted = false;
if ( !bInitted ) { bInitted = true; // def.AddAmmoType( BULLET_PLAYER_50AE, DMG_BULLET, TRACER_LINE, 0, 0, "ammo_50AE_max", 2400, 0, 10, 14 );
def.AddAmmoType( AMMO_GRENADE, DMG_BLAST, TRACER_LINE, 0, 0, 1/*max carry*/, 1, 0 ); def.AddAmmoType( AMMO_BULLETS, DMG_BULLET, TRACER_LINE, 0, 0, 1/*max carry*/, 1, 0 ); }
return &def; }
#ifndef CLIENT_DLL
const char *CSDKGameRules::GetChatPrefix( bool bTeamOnly, CBasePlayer *pPlayer ) { return "(chat prefix)"; }
#endif
//-----------------------------------------------------------------------------
// Purpose: Find the relationship between players (teamplay vs. deathmatch)
//-----------------------------------------------------------------------------
int CSDKGameRules::PlayerRelationship( CBaseEntity *pPlayer, CBaseEntity *pTarget ) { #ifndef CLIENT_DLL
// half life multiplay has a simple concept of Player Relationships.
// you are either on another player's team, or you are not.
if ( !pPlayer || !pTarget || !pTarget->IsPlayer() || IsTeamplay() == false ) return GR_NOTTEAMMATE;
if ( (*GetTeamID(pPlayer) != '\0') && (*GetTeamID(pTarget) != '\0') && !stricmp( GetTeamID(pPlayer), GetTeamID(pTarget) ) ) return GR_TEAMMATE;
#endif
return GR_NOTTEAMMATE; }
|