summaryrefslogtreecommitdiff
path: root/game/shared/tfc/tfc_gamerules.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/tfc/tfc_gamerules.cpp')
-rw-r--r--game/shared/tfc/tfc_gamerules.cpp422
1 files changed, 422 insertions, 0 deletions
diff --git a/game/shared/tfc/tfc_gamerules.cpp b/game/shared/tfc/tfc_gamerules.cpp
new file mode 100644
index 0000000..20e208d
--- /dev/null
+++ b/game/shared/tfc/tfc_gamerules.cpp
@@ -0,0 +1,422 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: The TF Game rules
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "tfc_gamerules.h"
+#include "ammodef.h"
+#include "KeyValues.h"
+#include "weapon_tfcbase.h"
+
+
+#ifdef CLIENT_DLL
+
+ #include "c_tfc_player.h"
+
+#else
+
+ #include "voice_gamemgr.h"
+ #include "team.h"
+ #include "tfc_bot_temp.h"
+ #include "tfc_player.h"
+ #include "tfc_timer.h"
+ #include "tfc_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( CTFCGameRules );
+
+
+BEGIN_NETWORK_TABLE_NOBASE( CTFCGameRules, DT_TFCGameRules )
+END_NETWORK_TABLE()
+
+
+LINK_ENTITY_TO_CLASS( tfc_gamerules, CTFCGameRulesProxy );
+IMPLEMENT_NETWORKCLASS_ALIASED( TFCGameRulesProxy, DT_TFCGameRulesProxy )
+
+
+#ifdef CLIENT_DLL
+ void RecvProxy_TFCGameRules( const RecvProp *pProp, void **pOut, void *pData, int objectID )
+ {
+ CTFCGameRules *pRules = TFCGameRules();
+ Assert( pRules );
+ *pOut = pRules;
+ }
+
+ BEGIN_RECV_TABLE( CTFCGameRulesProxy, DT_TFCGameRulesProxy )
+ RecvPropDataTable( "tfc_gamerules_data", 0, 0, &REFERENCE_RECV_TABLE( DT_TFCGameRules ), RecvProxy_TFCGameRules )
+ END_RECV_TABLE()
+#else
+ void *SendProxy_TFCGameRules( const SendProp *pProp, const void *pStructBase, const void *pData, CSendProxyRecipients *pRecipients, int objectID )
+ {
+ CTFCGameRules *pRules = TFCGameRules();
+ Assert( pRules );
+ pRecipients->SetAllRecipients();
+ return pRules;
+ }
+
+ BEGIN_SEND_TABLE( CTFCGameRulesProxy, DT_TFCGameRulesProxy )
+ SendPropDataTable( "tfc_gamerules_data", 0, &REFERENCE_SEND_TABLE( DT_TFCGameRules ), SendProxy_TFCGameRules )
+ END_SEND_TABLE()
+#endif
+
+
+ConVar mp_fadetoblack(
+ "mp_fadetoblack",
+ "0",
+ FCVAR_REPLICATED,
+ "fade a player's screen to black when he dies" );
+
+
+// (We clamp ammo ourselves elsewhere).
+ConVar ammo_max( "ammo_max", "5000", FCVAR_REPLICATED );
+
+
+CTFCGameRules::CTFCGameRules()
+{
+ CTF_Map = true;
+
+#ifdef GAME_DLL
+ // Create the team managers
+ for ( int i = 0; i < ARRAYSIZE( teamnames ); i++ )
+ {
+ CTeam *pTeam = static_cast<CTeam*>(CreateEntityByName( "tfc_team_manager" ));
+ pTeam->Init( teamnames[i], i );
+
+ g_Teams.AddToTail( pTeam );
+ }
+#endif
+}
+
+
+#ifdef CLIENT_DLL
+
+
+#else
+
+
+ int cease_fire;
+ int no_cease_fire_text;
+
+
+ // --------------------------------------------------------------------------------------------------- //
+ // 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 TFC.
+ void InitBodyQue()
+ {
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ //-----------------------------------------------------------------------------
+ CTFCGameRules::~CTFCGameRules()
+ {
+ // 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 CTFCGameRules::ClientCommand( CBaseEntity *pEdict, const CCommand &args )
+ {
+ CTFCPlayer *pPlayer = ToTFCPlayer( pEdict );
+
+ if( pPlayer->ClientCommand( args ) )
+ return true;
+
+ return BaseClass::ClientCommand( pEdict, args );
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose: Player has just spawned. Equip them.
+ //-----------------------------------------------------------------------------
+
+ void CTFCGameRules::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 CTFCGameRules::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(); 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 CTFCGameRules::Think()
+ {
+ Timer_UpdateAll();
+
+ BaseClass::Think();
+ }
+
+ const char *CTFCGameRules::GetChatPrefix( bool bTeamOnly, CBasePlayer *pPlayer )
+ {
+ return "(chat prefix)";
+ }
+
+
+ bool CTFCGameRules::IsInPreMatch() const
+ {
+ // TFCTODO return (cb_prematch_time > gpGlobals->time)
+ return false;
+ }
+
+ float CTFCGameRules::GetPreMatchEndTime() const
+ {
+ //TFCTODO: implement this.
+ return gpGlobals->curtime;
+ }
+
+ void CTFCGameRules::TFCGoToIntermission()
+ {
+ // TFCTODO: implement this.
+ Assert( false );
+ }
+
+
+#endif
+
+
+bool CTFCGameRules::ShouldCollide( int collisionGroup0, int collisionGroup1 )
+{
+ if ( collisionGroup0 > collisionGroup1 )
+ {
+ // swap so that lowest is always first
+ swap(collisionGroup0,collisionGroup1);
+ }
+
+ //Don't stand on COLLISION_GROUP_WEAPONs
+ if( collisionGroup0 == COLLISION_GROUP_PLAYER_MOVEMENT &&
+ collisionGroup1 == COLLISION_GROUP_WEAPON )
+ {
+ return false;
+ }
+
+ if ( collisionGroup0 == COLLISION_GROUP_PLAYER )
+ {
+ // Players don't collide with objects or other players
+ if ( collisionGroup1 == COLLISION_GROUP_PLAYER )
+ return false;
+ }
+
+ if ( collisionGroup1 == COLLISION_GROUP_PLAYER_MOVEMENT )
+ {
+ // This is only for probing, so it better not be on both sides!!!
+ Assert( collisionGroup0 != COLLISION_GROUP_PLAYER_MOVEMENT );
+
+ // No collide with players any more
+ // Nor with objects or grenades
+ switch ( collisionGroup0 )
+ {
+ default:
+ break;
+ case COLLISION_GROUP_PLAYER:
+ 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;
+
+ // Start at 1 here and skip the dummy ammo type to make CAmmoDef use the same indices
+ // as our #defines.
+ for ( int i=1; i < TFC_NUM_AMMO_TYPES; i++ )
+ {
+ def.AddAmmoType( g_AmmoTypeNames[i], DMG_BULLET, TRACER_LINE, 0, 0, "ammo_max", 2400, 10, 14 );
+ Assert( def.Index( g_AmmoTypeNames[i] ) == i );
+ }
+ }
+
+ return &def;
+}
+
+