From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/game/shared/gamerules.cpp | 1760 +++++++++++++++++++------------------- 1 file changed, 880 insertions(+), 880 deletions(-) (limited to 'mp/src/game/shared/gamerules.cpp') diff --git a/mp/src/game/shared/gamerules.cpp b/mp/src/game/shared/gamerules.cpp index b0be8603..81fa7bfa 100644 --- a/mp/src/game/shared/gamerules.cpp +++ b/mp/src/game/shared/gamerules.cpp @@ -1,880 +1,880 @@ -//========= Copyright Valve Corporation, All rights reserved. ============// -// -// Purpose: -// -//=============================================================================// - -#include "cbase.h" -#include "gamerules.h" -#include "ammodef.h" -#include "tier0/vprof.h" -#include "KeyValues.h" -#include "iachievementmgr.h" - -#ifdef CLIENT_DLL - - #include "usermessages.h" - -#else - - #include "player.h" - #include "teamplay_gamerules.h" - #include "game.h" - #include "entitylist.h" - #include "basecombatweapon.h" - #include "voice_gamemgr.h" - #include "globalstate.h" - #include "player_resource.h" - #include "tactical_mission.h" - #include "gamestats.h" - -#endif - -// memdbgon must be the last include file in a .cpp file!!! -#include "tier0/memdbgon.h" - - -ConVar g_Language( "g_Language", "0", FCVAR_REPLICATED ); -ConVar sk_autoaim_mode( "sk_autoaim_mode", "1", FCVAR_ARCHIVE | FCVAR_REPLICATED ); - -#ifndef CLIENT_DLL -ConVar log_verbose_enable( "log_verbose_enable", "0", FCVAR_GAMEDLL, "Set to 1 to enable verbose server log on the server." ); -ConVar log_verbose_interval( "log_verbose_interval", "3.0", FCVAR_GAMEDLL, "Determines the interval (in seconds) for the verbose server log." ); -#endif // CLIENT_DLL - -static CViewVectors g_DefaultViewVectors( - Vector( 0, 0, 64 ), //VEC_VIEW (m_vView) - - Vector(-16, -16, 0 ), //VEC_HULL_MIN (m_vHullMin) - Vector( 16, 16, 72 ), //VEC_HULL_MAX (m_vHullMax) - - Vector(-16, -16, 0 ), //VEC_DUCK_HULL_MIN (m_vDuckHullMin) - Vector( 16, 16, 36 ), //VEC_DUCK_HULL_MAX (m_vDuckHullMax) - Vector( 0, 0, 28 ), //VEC_DUCK_VIEW (m_vDuckView) - - Vector(-10, -10, -10 ), //VEC_OBS_HULL_MIN (m_vObsHullMin) - Vector( 10, 10, 10 ), //VEC_OBS_HULL_MAX (m_vObsHullMax) - - Vector( 0, 0, 14 ) //VEC_DEAD_VIEWHEIGHT (m_vDeadViewHeight) -); - - -// ------------------------------------------------------------------------------------ // -// CGameRulesProxy implementation. -// ------------------------------------------------------------------------------------ // - -CGameRulesProxy *CGameRulesProxy::s_pGameRulesProxy = NULL; - -IMPLEMENT_NETWORKCLASS_ALIASED( GameRulesProxy, DT_GameRulesProxy ) - -// Don't send any of the CBaseEntity stuff.. -BEGIN_NETWORK_TABLE_NOBASE( CGameRulesProxy, DT_GameRulesProxy ) -END_NETWORK_TABLE() - - -CGameRulesProxy::CGameRulesProxy() -{ - // allow map placed proxy entities to overwrite the static one - if ( s_pGameRulesProxy ) - { -#ifndef CLIENT_DLL - UTIL_Remove( s_pGameRulesProxy ); -#endif - s_pGameRulesProxy = NULL; - } - s_pGameRulesProxy = this; -} - -CGameRulesProxy::~CGameRulesProxy() -{ - if ( s_pGameRulesProxy == this ) - { - s_pGameRulesProxy = NULL; - } -} - -int CGameRulesProxy::UpdateTransmitState() -{ -#ifndef CLIENT_DLL - // ALWAYS transmit to all clients. - return SetTransmitState( FL_EDICT_ALWAYS ); -#else - return 0; -#endif - -} - -void CGameRulesProxy::NotifyNetworkStateChanged() -{ - if ( s_pGameRulesProxy ) - s_pGameRulesProxy->NetworkStateChanged(); -} - - - -ConVar old_radius_damage( "old_radiusdamage", "0.0", FCVAR_REPLICATED ); - -#ifdef CLIENT_DLL //{ - -bool CGameRules::IsBonusChallengeTimeBased( void ) -{ - return true; -} - -bool CGameRules::IsLocalPlayer( int nEntIndex ) -{ - C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); - return ( pLocalPlayer && pLocalPlayer == ClientEntityList().GetEnt( nEntIndex ) ); -} - -CGameRules::CGameRules() : CAutoGameSystemPerFrame( "CGameRules" ) -{ - Assert( !g_pGameRules ); - g_pGameRules = this; -} - -#else //}{ - -// In tf_gamerules.cpp or hl_gamerules.cpp. -extern IVoiceGameMgrHelper *g_pVoiceGameMgrHelper; - - -CGameRules* g_pGameRules = NULL; -extern bool g_fGameOver; - -//----------------------------------------------------------------------------- -// constructor, destructor -//----------------------------------------------------------------------------- -CGameRules::CGameRules() : CAutoGameSystemPerFrame( "CGameRules" ) -{ - Assert( !g_pGameRules ); - g_pGameRules = this; - - GetVoiceGameMgr()->Init( g_pVoiceGameMgrHelper, gpGlobals->maxClients ); - ClearMultiDamage(); - - m_flNextVerboseLogOutput = 0.0f; -} - -//----------------------------------------------------------------------------- -// Purpose: Return true if the specified player can carry any more of the ammo type -//----------------------------------------------------------------------------- -bool CGameRules::CanHaveAmmo( CBaseCombatCharacter *pPlayer, int iAmmoIndex ) -{ - if ( iAmmoIndex > -1 ) - { - // Get the max carrying capacity for this ammo - int iMaxCarry = GetAmmoDef()->MaxCarry( iAmmoIndex ); - - // Does the player have room for more of this type of ammo? - if ( pPlayer->GetAmmoCount( iAmmoIndex ) < iMaxCarry ) - return true; - } - - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: Return true if the specified player can carry any more of the ammo type -//----------------------------------------------------------------------------- -bool CGameRules::CanHaveAmmo( CBaseCombatCharacter *pPlayer, const char *szName ) -{ - return CanHaveAmmo( pPlayer, GetAmmoDef()->Index(szName) ); -} - -//========================================================= -//========================================================= -CBaseEntity *CGameRules::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) -{ - CBaseEntity *pSpawnSpot = pPlayer->EntSelectSpawnPoint(); - Assert( pSpawnSpot ); - - pPlayer->SetLocalOrigin( pSpawnSpot->GetAbsOrigin() + Vector(0,0,1) ); - pPlayer->SetAbsVelocity( vec3_origin ); - pPlayer->SetLocalAngles( pSpawnSpot->GetLocalAngles() ); - pPlayer->m_Local.m_vecPunchAngle = vec3_angle; - pPlayer->m_Local.m_vecPunchAngleVel = vec3_angle; - pPlayer->SnapEyeAngles( pSpawnSpot->GetLocalAngles() ); - - return pSpawnSpot; -} - -// checks if the spot is clear of players -bool CGameRules::IsSpawnPointValid( CBaseEntity *pSpot, CBasePlayer *pPlayer ) -{ - CBaseEntity *ent = NULL; - - if ( !pSpot->IsTriggered( pPlayer ) ) - { - return false; - } - - for ( CEntitySphereQuery sphere( pSpot->GetAbsOrigin(), 128 ); (ent = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity() ) - { - // if ent is a client, don't spawn on 'em - if ( ent->IsPlayer() && ent != pPlayer ) - return false; - } - - return true; -} - -//========================================================= -//========================================================= -bool CGameRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon ) -{ -/* - if ( pWeapon->m_pszAmmo1 ) - { - if ( !CanHaveAmmo( pPlayer, pWeapon->m_iPrimaryAmmoType ) ) - { - // we can't carry anymore ammo for this gun. We can only - // have the gun if we aren't already carrying one of this type - if ( pPlayer->Weapon_OwnsThisType( pWeapon ) ) - { - return FALSE; - } - } - } - else - { - // weapon doesn't use ammo, don't take another if you already have it. - if ( pPlayer->Weapon_OwnsThisType( pWeapon ) ) - { - return FALSE; - } - } -*/ - // note: will fall through to here if GetItemInfo doesn't fill the struct! - return TRUE; -} - -//========================================================= -// load the SkillData struct with the proper values based on the skill level. -//========================================================= -void CGameRules::RefreshSkillData ( bool forceUpdate ) -{ -#ifndef CLIENT_DLL - if ( !forceUpdate ) - { - if ( GlobalEntity_IsInTable( "skill.cfg" ) ) - return; - } - GlobalEntity_Add( "skill.cfg", STRING(gpGlobals->mapname), GLOBAL_ON ); - -#if !defined( TF_DLL ) && !defined( DOD_DLL ) - char szExec[256]; -#endif - - ConVarRef skill( "skill" ); - - SetSkillLevel( skill.IsValid() ? skill.GetInt() : 1 ); - -#ifdef HL2_DLL - // HL2 current only uses one skill config file that represents MEDIUM skill level and - // synthesizes EASY and HARD. (sjb) - Q_snprintf( szExec,sizeof(szExec), "exec skill_manifest.cfg\n" ); - - engine->ServerCommand( szExec ); - engine->ServerExecute(); -#else - -#if !defined( TF_DLL ) && !defined( DOD_DLL ) - Q_snprintf( szExec,sizeof(szExec), "exec skill%d.cfg\n", GetSkillLevel() ); - - engine->ServerCommand( szExec ); - engine->ServerExecute(); -#endif // TF_DLL && DOD_DLL - -#endif // HL2_DLL -#endif // CLIENT_DLL -} - - -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -bool IsExplosionTraceBlocked( trace_t *ptr ) -{ - if( ptr->DidHitWorld() ) - return true; - - if( ptr->m_pEnt == NULL ) - return false; - - if( ptr->m_pEnt->GetMoveType() == MOVETYPE_PUSH ) - { - // All doors are push, but not all things that push are doors. This - // narrows the search before we start to do classname compares. - if( FClassnameIs(ptr->m_pEnt, "prop_door_rotating") || - FClassnameIs(ptr->m_pEnt, "func_door") || - FClassnameIs(ptr->m_pEnt, "func_door_rotating") ) - return true; - } - - return false; -} - -//----------------------------------------------------------------------------- -// Default implementation of radius damage -//----------------------------------------------------------------------------- -#define ROBUST_RADIUS_PROBE_DIST 16.0f // If a solid surface blocks the explosion, this is how far to creep along the surface looking for another way to the target -void CGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore ) -{ - const int MASK_RADIUS_DAMAGE = MASK_SHOT&(~CONTENTS_HITBOX); - CBaseEntity *pEntity = NULL; - trace_t tr; - float flAdjustedDamage, falloff; - Vector vecSpot; - - Vector vecSrc = vecSrcIn; - - if ( flRadius ) - falloff = info.GetDamage() / flRadius; - else - falloff = 1.0; - - int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; - -#ifdef HL2_DLL - if( bInWater ) - { - // Only muffle the explosion if deeper than 2 feet in water. - if( !(UTIL_PointContents(vecSrc + Vector(0, 0, 24)) & MASK_WATER) ) - { - bInWater = false; - } - } -#endif // HL2_DLL - - vecSrc.z += 1;// in case grenade is lying on the ground - - float flHalfRadiusSqr = Square( flRadius / 2.0f ); - - // iterate on all entities in the vicinity. - for ( CEntitySphereQuery sphere( vecSrc, flRadius ); (pEntity = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity() ) - { - // This value is used to scale damage when the explosion is blocked by some other object. - float flBlockedDamagePercent = 0.0f; - - if ( pEntity == pEntityIgnore ) - continue; - - if ( pEntity->m_takedamage == DAMAGE_NO ) - continue; - - // 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; - - // Check that the explosion can 'see' this entity. - vecSpot = pEntity->BodyTarget( vecSrc, false ); - UTIL_TraceLine( vecSrc, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); - - if( old_radius_damage.GetBool() ) - { - if ( tr.fraction != 1.0 && tr.m_pEnt != pEntity ) - continue; - } - else - { - if ( tr.fraction != 1.0 ) - { - if ( IsExplosionTraceBlocked(&tr) ) - { - if( ShouldUseRobustRadiusDamage( pEntity ) ) - { - if( vecSpot.DistToSqr( vecSrc ) > flHalfRadiusSqr ) - { - // Only use robust model on a target within one-half of the explosion's radius. - continue; - } - - Vector vecToTarget = vecSpot - tr.endpos; - VectorNormalize( vecToTarget ); - - // We're going to deflect the blast along the surface that - // interrupted a trace from explosion to this target. - Vector vecUp, vecDeflect; - CrossProduct( vecToTarget, tr.plane.normal, vecUp ); - CrossProduct( tr.plane.normal, vecUp, vecDeflect ); - VectorNormalize( vecDeflect ); - - // Trace along the surface that intercepted the blast... - UTIL_TraceLine( tr.endpos, tr.endpos + vecDeflect * ROBUST_RADIUS_PROBE_DIST, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); - //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 255, 0, false, 10 ); - - // ...to see if there's a nearby edge that the explosion would 'spill over' if the blast were fully simulated. - UTIL_TraceLine( tr.endpos, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); - //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 10 ); - - if( tr.fraction != 1.0 && tr.DidHitWorld() ) - { - // Still can't reach the target. - continue; - } - // else fall through - } - else - { - continue; - } - } - - // UNDONE: Probably shouldn't let children block parents either? Or maybe those guys should set their owner if they want this behavior? - // HL2 - Dissolve damage is not reduced by interposing non-world objects - if( tr.m_pEnt && tr.m_pEnt != pEntity && tr.m_pEnt->GetOwnerEntity() != pEntity ) - { - // Some entity was hit by the trace, meaning the explosion does not have clear - // line of sight to the entity that it's trying to hurt. If the world is also - // blocking, we do no damage. - CBaseEntity *pBlockingEntity = tr.m_pEnt; - //Msg( "%s may be blocked by %s...", pEntity->GetClassname(), pBlockingEntity->GetClassname() ); - - UTIL_TraceLine( vecSrc, vecSpot, CONTENTS_SOLID, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); - - if( tr.fraction != 1.0 ) - { - continue; - } - - // Now, if the interposing object is physics, block some explosion force based on its mass. - if( pBlockingEntity->VPhysicsGetObject() ) - { - const float MASS_ABSORB_ALL_DAMAGE = 350.0f; - float flMass = pBlockingEntity->VPhysicsGetObject()->GetMass(); - float scale = flMass / MASS_ABSORB_ALL_DAMAGE; - - // Absorbed all the damage. - if( scale >= 1.0f ) - { - continue; - } - - ASSERT( scale > 0.0f ); - flBlockedDamagePercent = scale; - //Msg(" Object (%s) weighing %fkg blocked %f percent of explosion damage\n", pBlockingEntity->GetClassname(), flMass, scale * 100.0f); - } - else - { - // Some object that's not the world and not physics. Generically block 25% damage - flBlockedDamagePercent = 0.25f; - } - } - } - } - // decrease damage for an ent that's farther from the bomb. - flAdjustedDamage = ( vecSrc - tr.endpos ).Length() * falloff; - flAdjustedDamage = info.GetDamage() - flAdjustedDamage; - - if ( flAdjustedDamage <= 0 ) - { - continue; - } - - // the explosion can 'see' this entity, so hurt them! - if (tr.startsolid) - { - // if we're stuck inside them, fixup the position and distance - tr.endpos = vecSrc; - tr.fraction = 0.0; - } - - CTakeDamageInfo adjustedInfo = info; - //Msg("%s: Blocked damage: %f percent (in:%f out:%f)\n", pEntity->GetClassname(), flBlockedDamagePercent * 100, flAdjustedDamage, flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); - adjustedInfo.SetDamage( flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); - - // Now make a consideration for skill level! - if( info.GetAttacker() && info.GetAttacker()->IsPlayer() && pEntity->IsNPC() ) - { - // An explosion set off by the player is harming an NPC. Adjust damage accordingly. - adjustedInfo.AdjustPlayerDamageInflictedForSkillLevel(); - } - - Vector dir = vecSpot - vecSrc; - VectorNormalize( dir ); - - // If we don't have a damage force, manufacture one - if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) - { - if ( !( adjustedInfo.GetDamageType() & DMG_PREVENT_PHYSICS_FORCE ) ) - { - CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc ); - } - } - 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 ); - } - - if ( tr.fraction != 1.0 && pEntity == tr.m_pEnt ) - { - ClearMultiDamage( ); - pEntity->DispatchTraceAttack( adjustedInfo, dir, &tr ); - ApplyMultiDamage(); - } - else - { - pEntity->TakeDamage( adjustedInfo ); - } - - // Now hit all triggers along the way that respond to damage... - pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, tr.endpos, dir ); - -#if defined( GAME_DLL ) - if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() && ToBaseCombatCharacter( tr.m_pEnt ) ) - { - - // This is a total hack!!! - bool bIsPrimary = true; - CBasePlayer *player = ToBasePlayer( info.GetAttacker() ); - CBaseCombatWeapon *pWeapon = player->GetActiveWeapon(); - if ( pWeapon && FClassnameIs( pWeapon, "weapon_smg1" ) ) - { - bIsPrimary = false; - } - - gamestats->Event_WeaponHit( player, bIsPrimary, (pWeapon != NULL) ? player->GetActiveWeapon()->GetClassname() : "NULL", info ); - } -#endif - } -} - - -bool CGameRules::ClientCommand( CBaseEntity *pEdict, const CCommand &args ) -{ - if( pEdict->IsPlayer() ) - { - if( GetVoiceGameMgr()->ClientCommand( static_cast(pEdict), args ) ) - return true; - } - - return false; -} - - -void CGameRules::FrameUpdatePostEntityThink() -{ - VPROF( "CGameRules::FrameUpdatePostEntityThink" ); - Think(); -} - -// Hook into the convar from the engine -ConVar skill( "skill", "1" ); - -void CGameRules::Think() -{ - GetVoiceGameMgr()->Update( gpGlobals->frametime ); - SetSkillLevel( skill.GetInt() ); - - if ( log_verbose_enable.GetBool() ) - { - if ( m_flNextVerboseLogOutput < gpGlobals->curtime ) - { - ProcessVerboseLogOutput(); - m_flNextVerboseLogOutput = gpGlobals->curtime + log_verbose_interval.GetFloat(); - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Called at the end of GameFrame (i.e. after all game logic has run this frame) -//----------------------------------------------------------------------------- -void CGameRules::EndGameFrame( void ) -{ - // If you hit this assert, it means something called AddMultiDamage() and didn't ApplyMultiDamage(). - // The g_MultiDamage.m_hAttacker & g_MultiDamage.m_hInflictor should give help you figure out the culprit. - Assert( g_MultiDamage.IsClear() ); - if ( !g_MultiDamage.IsClear() ) - { - Warning("Unapplied multidamage left in the system:\nTarget: %s\nInflictor: %s\nAttacker: %s\nDamage: %.2f\n", - g_MultiDamage.GetTarget()->GetDebugName(), - g_MultiDamage.GetInflictor()->GetDebugName(), - g_MultiDamage.GetAttacker()->GetDebugName(), - g_MultiDamage.GetDamage() ); - ApplyMultiDamage(); - } -} - -//----------------------------------------------------------------------------- -// trace line rules -//----------------------------------------------------------------------------- -float CGameRules::WeaponTraceEntity( CBaseEntity *pEntity, const Vector &vecStart, const Vector &vecEnd, - unsigned int mask, trace_t *ptr ) -{ - UTIL_TraceEntity( pEntity, vecStart, vecEnd, mask, ptr ); - return 1.0f; -} - - -void CGameRules::CreateStandardEntities() -{ - g_pPlayerResource = (CPlayerResource*)CBaseEntity::Create( "player_manager", vec3_origin, vec3_angle ); - g_pPlayerResource->AddEFlags( EFL_KEEP_ON_RECREATE_ENTITIES ); -} - -//----------------------------------------------------------------------------- -// Purpose: Inform client(s) they can mark the indicated achievement as completed (SERVER VERSION) -// Input : filter - which client(s) to send this to -// iAchievementID - The enumeration value of the achievement to mark (see TODO:Kerry, what file will have the mod's achievement enum?) -//----------------------------------------------------------------------------- -void CGameRules::MarkAchievement( IRecipientFilter& filter, char const *pchAchievementName ) -{ - gamestats->Event_IncrementCountedStatistic( vec3_origin, pchAchievementName, 1.0f ); - - IAchievementMgr *pAchievementMgr = engine->GetAchievementMgr(); - if ( !pAchievementMgr ) - return; - pAchievementMgr->OnMapEvent( pchAchievementName ); -} - -#endif //} !CLIENT_DLL - - -// ----------------------------------------------------------------------------- // -// Shared CGameRules implementation. -// ----------------------------------------------------------------------------- // - -CGameRules::~CGameRules() -{ - Assert( g_pGameRules == this ); - g_pGameRules = NULL; -} - -bool CGameRules::SwitchToNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon ) -{ - return false; -} - -CBaseCombatWeapon *CGameRules::GetNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon ) -{ - return NULL; -} - -bool CGameRules::ShouldCollide( int collisionGroup0, int collisionGroup1 ) -{ - if ( collisionGroup0 > collisionGroup1 ) - { - // swap so that lowest is always first - ::V_swap(collisionGroup0,collisionGroup1); - } - -#ifndef HL2MP - if ( (collisionGroup0 == COLLISION_GROUP_PLAYER || collisionGroup0 == COLLISION_GROUP_PLAYER_MOVEMENT) && - collisionGroup1 == COLLISION_GROUP_PUSHAWAY ) - { - return false; - } -#endif - - if ( collisionGroup0 == COLLISION_GROUP_DEBRIS && collisionGroup1 == COLLISION_GROUP_PUSHAWAY ) - { - // let debris and multiplayer objects collide - return true; - } - - // -------------------------------------------------------------------------- - // NOTE: All of this code assumes the collision groups have been sorted!!!! - // NOTE: Don't change their order without rewriting this code !!! - // -------------------------------------------------------------------------- - - // Don't bother if either is in a vehicle... - if (( collisionGroup0 == COLLISION_GROUP_IN_VEHICLE ) || ( collisionGroup1 == COLLISION_GROUP_IN_VEHICLE )) - return false; - - if ( ( collisionGroup1 == COLLISION_GROUP_DOOR_BLOCKER ) && ( collisionGroup0 != COLLISION_GROUP_NPC ) ) - return false; - - if ( ( collisionGroup0 == COLLISION_GROUP_PLAYER ) && ( collisionGroup1 == COLLISION_GROUP_PASSABLE_DOOR ) ) - return false; - - if ( collisionGroup0 == COLLISION_GROUP_DEBRIS || collisionGroup0 == COLLISION_GROUP_DEBRIS_TRIGGER ) - { - // put exceptions here, right now this will only collide with COLLISION_GROUP_NONE - return false; - } - - // Dissolving guys only collide with COLLISION_GROUP_NONE - if ( (collisionGroup0 == COLLISION_GROUP_DISSOLVING) || (collisionGroup1 == COLLISION_GROUP_DISSOLVING) ) - { - if ( collisionGroup0 != COLLISION_GROUP_NONE ) - return false; - } - - // doesn't collide with other members of this group - // or debris, but that's handled above - if ( collisionGroup0 == COLLISION_GROUP_INTERACTIVE_DEBRIS && collisionGroup1 == COLLISION_GROUP_INTERACTIVE_DEBRIS ) - return false; - -#ifndef HL2MP - // This change was breaking HL2DM - // Adrian: TEST! Interactive Debris doesn't collide with the player. - if ( collisionGroup0 == COLLISION_GROUP_INTERACTIVE_DEBRIS && ( collisionGroup1 == COLLISION_GROUP_PLAYER_MOVEMENT || collisionGroup1 == COLLISION_GROUP_PLAYER ) ) - return false; -#endif - - if ( collisionGroup0 == COLLISION_GROUP_BREAKABLE_GLASS && collisionGroup1 == COLLISION_GROUP_BREAKABLE_GLASS ) - return false; - - // interactive objects collide with everything except debris & interactive debris - if ( collisionGroup1 == COLLISION_GROUP_INTERACTIVE && collisionGroup0 != COLLISION_GROUP_NONE ) - return false; - - // Projectiles hit everything but debris, weapons, + other projectiles - if ( collisionGroup1 == COLLISION_GROUP_PROJECTILE ) - { - if ( collisionGroup0 == COLLISION_GROUP_DEBRIS || - collisionGroup0 == COLLISION_GROUP_WEAPON || - collisionGroup0 == COLLISION_GROUP_PROJECTILE ) - { - return false; - } - } - - // Don't let vehicles collide with weapons - // Don't let players collide with weapons... - // Don't let NPCs collide with weapons - // Weapons are triggers, too, so they should still touch because of that - if ( collisionGroup1 == COLLISION_GROUP_WEAPON ) - { - if ( collisionGroup0 == COLLISION_GROUP_VEHICLE || - collisionGroup0 == COLLISION_GROUP_PLAYER || - collisionGroup0 == COLLISION_GROUP_NPC ) - { - return false; - } - } - - // collision with vehicle clip entity?? - if ( collisionGroup0 == COLLISION_GROUP_VEHICLE_CLIP || collisionGroup1 == COLLISION_GROUP_VEHICLE_CLIP ) - { - // yes then if it's a vehicle, collide, otherwise no collision - // vehicle sorts lower than vehicle clip, so must be in 0 - if ( collisionGroup0 == COLLISION_GROUP_VEHICLE ) - return true; - // vehicle clip against non-vehicle, no collision - return false; - } - - return true; -} - - -const CViewVectors* CGameRules::GetViewVectors() const -{ - return &g_DefaultViewVectors; -} - - -//----------------------------------------------------------------------------- -// Purpose: Returns how much damage the given ammo type should do to the victim -// when fired by the attacker. -// Input : pAttacker - Dude what shot the gun. -// pVictim - Dude what done got shot. -// nAmmoType - What been shot out. -// Output : How much hurt to put on dude what done got shot (pVictim). -//----------------------------------------------------------------------------- -float CGameRules::GetAmmoDamage( CBaseEntity *pAttacker, CBaseEntity *pVictim, int nAmmoType ) -{ - float flDamage = 0; - CAmmoDef *pAmmoDef = GetAmmoDef(); - - if ( pAttacker->IsPlayer() ) - { - flDamage = pAmmoDef->PlrDamage( nAmmoType ); - } - else - { - flDamage = pAmmoDef->NPCDamage( nAmmoType ); - } - - return flDamage; -} - - -#ifndef CLIENT_DLL -const char *CGameRules::GetChatPrefix( bool bTeamOnly, CBasePlayer *pPlayer ) -{ - if ( pPlayer && pPlayer->IsAlive() == false ) - { - if ( bTeamOnly ) - return "*DEAD*(TEAM)"; - else - return "*DEAD*"; - } - - return ""; -} - -void CGameRules::CheckHaptics(CBasePlayer* pPlayer) -{ - // NVNT see if the client of pPlayer is using a haptic device. - const char *pszHH = engine->GetClientConVarValue( pPlayer->entindex(), "hap_HasDevice" ); - if( pszHH ) - { - int iHH = atoi( pszHH ); - pPlayer->SetHaptics( iHH != 0 ); - } -} - -void CGameRules::ClientSettingsChanged( CBasePlayer *pPlayer ) -{ - const char *pszName = engine->GetClientConVarValue( pPlayer->entindex(), "name" ); - - const char *pszOldName = pPlayer->GetPlayerName(); - - // msg everyone if someone changes their name, and it isn't the first time (changing no name to current name) - // Note, not using FStrEq so that this is case sensitive - if ( pszOldName[0] != 0 && Q_strcmp( pszOldName, pszName ) ) - { - char text[256]; - Q_snprintf( text,sizeof(text), "%s changed name to %s\n", pszOldName, pszName ); - - UTIL_ClientPrintAll( HUD_PRINTTALK, text ); - - IGameEvent * event = gameeventmanager->CreateEvent( "player_changename" ); - if ( event ) - { - event->SetInt( "userid", pPlayer->GetUserID() ); - event->SetString( "oldname", pszOldName ); - event->SetString( "newname", pszName ); - gameeventmanager->FireEvent( event ); - } - - pPlayer->SetPlayerName( pszName ); - } - - const char *pszFov = engine->GetClientConVarValue( pPlayer->entindex(), "fov_desired" ); - if ( pszFov ) - { - int iFov = atoi(pszFov); - iFov = clamp( iFov, 75, 90 ); - pPlayer->SetDefaultFOV( iFov ); - } - - // NVNT see if this user is still or has began using a haptic device - const char *pszHH = engine->GetClientConVarValue( pPlayer->entindex(), "hap_HasDevice" ); - if( pszHH ) - { - int iHH = atoi( pszHH ); - pPlayer->SetHaptics( iHH != 0 ); - } -} - -CTacticalMissionManager *CGameRules::TacticalMissionManagerFactory( void ) -{ - return new CTacticalMissionManager; -} - -#endif +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "gamerules.h" +#include "ammodef.h" +#include "tier0/vprof.h" +#include "KeyValues.h" +#include "iachievementmgr.h" + +#ifdef CLIENT_DLL + + #include "usermessages.h" + +#else + + #include "player.h" + #include "teamplay_gamerules.h" + #include "game.h" + #include "entitylist.h" + #include "basecombatweapon.h" + #include "voice_gamemgr.h" + #include "globalstate.h" + #include "player_resource.h" + #include "tactical_mission.h" + #include "gamestats.h" + +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +ConVar g_Language( "g_Language", "0", FCVAR_REPLICATED ); +ConVar sk_autoaim_mode( "sk_autoaim_mode", "1", FCVAR_ARCHIVE | FCVAR_REPLICATED ); + +#ifndef CLIENT_DLL +ConVar log_verbose_enable( "log_verbose_enable", "0", FCVAR_GAMEDLL, "Set to 1 to enable verbose server log on the server." ); +ConVar log_verbose_interval( "log_verbose_interval", "3.0", FCVAR_GAMEDLL, "Determines the interval (in seconds) for the verbose server log." ); +#endif // CLIENT_DLL + +static CViewVectors g_DefaultViewVectors( + Vector( 0, 0, 64 ), //VEC_VIEW (m_vView) + + Vector(-16, -16, 0 ), //VEC_HULL_MIN (m_vHullMin) + Vector( 16, 16, 72 ), //VEC_HULL_MAX (m_vHullMax) + + Vector(-16, -16, 0 ), //VEC_DUCK_HULL_MIN (m_vDuckHullMin) + Vector( 16, 16, 36 ), //VEC_DUCK_HULL_MAX (m_vDuckHullMax) + Vector( 0, 0, 28 ), //VEC_DUCK_VIEW (m_vDuckView) + + Vector(-10, -10, -10 ), //VEC_OBS_HULL_MIN (m_vObsHullMin) + Vector( 10, 10, 10 ), //VEC_OBS_HULL_MAX (m_vObsHullMax) + + Vector( 0, 0, 14 ) //VEC_DEAD_VIEWHEIGHT (m_vDeadViewHeight) +); + + +// ------------------------------------------------------------------------------------ // +// CGameRulesProxy implementation. +// ------------------------------------------------------------------------------------ // + +CGameRulesProxy *CGameRulesProxy::s_pGameRulesProxy = NULL; + +IMPLEMENT_NETWORKCLASS_ALIASED( GameRulesProxy, DT_GameRulesProxy ) + +// Don't send any of the CBaseEntity stuff.. +BEGIN_NETWORK_TABLE_NOBASE( CGameRulesProxy, DT_GameRulesProxy ) +END_NETWORK_TABLE() + + +CGameRulesProxy::CGameRulesProxy() +{ + // allow map placed proxy entities to overwrite the static one + if ( s_pGameRulesProxy ) + { +#ifndef CLIENT_DLL + UTIL_Remove( s_pGameRulesProxy ); +#endif + s_pGameRulesProxy = NULL; + } + s_pGameRulesProxy = this; +} + +CGameRulesProxy::~CGameRulesProxy() +{ + if ( s_pGameRulesProxy == this ) + { + s_pGameRulesProxy = NULL; + } +} + +int CGameRulesProxy::UpdateTransmitState() +{ +#ifndef CLIENT_DLL + // ALWAYS transmit to all clients. + return SetTransmitState( FL_EDICT_ALWAYS ); +#else + return 0; +#endif + +} + +void CGameRulesProxy::NotifyNetworkStateChanged() +{ + if ( s_pGameRulesProxy ) + s_pGameRulesProxy->NetworkStateChanged(); +} + + + +ConVar old_radius_damage( "old_radiusdamage", "0.0", FCVAR_REPLICATED ); + +#ifdef CLIENT_DLL //{ + +bool CGameRules::IsBonusChallengeTimeBased( void ) +{ + return true; +} + +bool CGameRules::IsLocalPlayer( int nEntIndex ) +{ + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + return ( pLocalPlayer && pLocalPlayer == ClientEntityList().GetEnt( nEntIndex ) ); +} + +CGameRules::CGameRules() : CAutoGameSystemPerFrame( "CGameRules" ) +{ + Assert( !g_pGameRules ); + g_pGameRules = this; +} + +#else //}{ + +// In tf_gamerules.cpp or hl_gamerules.cpp. +extern IVoiceGameMgrHelper *g_pVoiceGameMgrHelper; + + +CGameRules* g_pGameRules = NULL; +extern bool g_fGameOver; + +//----------------------------------------------------------------------------- +// constructor, destructor +//----------------------------------------------------------------------------- +CGameRules::CGameRules() : CAutoGameSystemPerFrame( "CGameRules" ) +{ + Assert( !g_pGameRules ); + g_pGameRules = this; + + GetVoiceGameMgr()->Init( g_pVoiceGameMgrHelper, gpGlobals->maxClients ); + ClearMultiDamage(); + + m_flNextVerboseLogOutput = 0.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: Return true if the specified player can carry any more of the ammo type +//----------------------------------------------------------------------------- +bool CGameRules::CanHaveAmmo( CBaseCombatCharacter *pPlayer, int iAmmoIndex ) +{ + if ( iAmmoIndex > -1 ) + { + // Get the max carrying capacity for this ammo + int iMaxCarry = GetAmmoDef()->MaxCarry( iAmmoIndex ); + + // Does the player have room for more of this type of ammo? + if ( pPlayer->GetAmmoCount( iAmmoIndex ) < iMaxCarry ) + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Return true if the specified player can carry any more of the ammo type +//----------------------------------------------------------------------------- +bool CGameRules::CanHaveAmmo( CBaseCombatCharacter *pPlayer, const char *szName ) +{ + return CanHaveAmmo( pPlayer, GetAmmoDef()->Index(szName) ); +} + +//========================================================= +//========================================================= +CBaseEntity *CGameRules::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) +{ + CBaseEntity *pSpawnSpot = pPlayer->EntSelectSpawnPoint(); + Assert( pSpawnSpot ); + + pPlayer->SetLocalOrigin( pSpawnSpot->GetAbsOrigin() + Vector(0,0,1) ); + pPlayer->SetAbsVelocity( vec3_origin ); + pPlayer->SetLocalAngles( pSpawnSpot->GetLocalAngles() ); + pPlayer->m_Local.m_vecPunchAngle = vec3_angle; + pPlayer->m_Local.m_vecPunchAngleVel = vec3_angle; + pPlayer->SnapEyeAngles( pSpawnSpot->GetLocalAngles() ); + + return pSpawnSpot; +} + +// checks if the spot is clear of players +bool CGameRules::IsSpawnPointValid( CBaseEntity *pSpot, CBasePlayer *pPlayer ) +{ + CBaseEntity *ent = NULL; + + if ( !pSpot->IsTriggered( pPlayer ) ) + { + return false; + } + + for ( CEntitySphereQuery sphere( pSpot->GetAbsOrigin(), 128 ); (ent = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity() ) + { + // if ent is a client, don't spawn on 'em + if ( ent->IsPlayer() && ent != pPlayer ) + return false; + } + + return true; +} + +//========================================================= +//========================================================= +bool CGameRules::CanHavePlayerItem( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon ) +{ +/* + if ( pWeapon->m_pszAmmo1 ) + { + if ( !CanHaveAmmo( pPlayer, pWeapon->m_iPrimaryAmmoType ) ) + { + // we can't carry anymore ammo for this gun. We can only + // have the gun if we aren't already carrying one of this type + if ( pPlayer->Weapon_OwnsThisType( pWeapon ) ) + { + return FALSE; + } + } + } + else + { + // weapon doesn't use ammo, don't take another if you already have it. + if ( pPlayer->Weapon_OwnsThisType( pWeapon ) ) + { + return FALSE; + } + } +*/ + // note: will fall through to here if GetItemInfo doesn't fill the struct! + return TRUE; +} + +//========================================================= +// load the SkillData struct with the proper values based on the skill level. +//========================================================= +void CGameRules::RefreshSkillData ( bool forceUpdate ) +{ +#ifndef CLIENT_DLL + if ( !forceUpdate ) + { + if ( GlobalEntity_IsInTable( "skill.cfg" ) ) + return; + } + GlobalEntity_Add( "skill.cfg", STRING(gpGlobals->mapname), GLOBAL_ON ); + +#if !defined( TF_DLL ) && !defined( DOD_DLL ) + char szExec[256]; +#endif + + ConVarRef skill( "skill" ); + + SetSkillLevel( skill.IsValid() ? skill.GetInt() : 1 ); + +#ifdef HL2_DLL + // HL2 current only uses one skill config file that represents MEDIUM skill level and + // synthesizes EASY and HARD. (sjb) + Q_snprintf( szExec,sizeof(szExec), "exec skill_manifest.cfg\n" ); + + engine->ServerCommand( szExec ); + engine->ServerExecute(); +#else + +#if !defined( TF_DLL ) && !defined( DOD_DLL ) + Q_snprintf( szExec,sizeof(szExec), "exec skill%d.cfg\n", GetSkillLevel() ); + + engine->ServerCommand( szExec ); + engine->ServerExecute(); +#endif // TF_DLL && DOD_DLL + +#endif // HL2_DLL +#endif // CLIENT_DLL +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool IsExplosionTraceBlocked( trace_t *ptr ) +{ + if( ptr->DidHitWorld() ) + return true; + + if( ptr->m_pEnt == NULL ) + return false; + + if( ptr->m_pEnt->GetMoveType() == MOVETYPE_PUSH ) + { + // All doors are push, but not all things that push are doors. This + // narrows the search before we start to do classname compares. + if( FClassnameIs(ptr->m_pEnt, "prop_door_rotating") || + FClassnameIs(ptr->m_pEnt, "func_door") || + FClassnameIs(ptr->m_pEnt, "func_door_rotating") ) + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Default implementation of radius damage +//----------------------------------------------------------------------------- +#define ROBUST_RADIUS_PROBE_DIST 16.0f // If a solid surface blocks the explosion, this is how far to creep along the surface looking for another way to the target +void CGameRules::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore, CBaseEntity *pEntityIgnore ) +{ + const int MASK_RADIUS_DAMAGE = MASK_SHOT&(~CONTENTS_HITBOX); + CBaseEntity *pEntity = NULL; + trace_t tr; + float flAdjustedDamage, falloff; + Vector vecSpot; + + Vector vecSrc = vecSrcIn; + + if ( flRadius ) + falloff = info.GetDamage() / flRadius; + else + falloff = 1.0; + + int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; + +#ifdef HL2_DLL + if( bInWater ) + { + // Only muffle the explosion if deeper than 2 feet in water. + if( !(UTIL_PointContents(vecSrc + Vector(0, 0, 24)) & MASK_WATER) ) + { + bInWater = false; + } + } +#endif // HL2_DLL + + vecSrc.z += 1;// in case grenade is lying on the ground + + float flHalfRadiusSqr = Square( flRadius / 2.0f ); + + // iterate on all entities in the vicinity. + for ( CEntitySphereQuery sphere( vecSrc, flRadius ); (pEntity = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity() ) + { + // This value is used to scale damage when the explosion is blocked by some other object. + float flBlockedDamagePercent = 0.0f; + + if ( pEntity == pEntityIgnore ) + continue; + + if ( pEntity->m_takedamage == DAMAGE_NO ) + continue; + + // 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; + + // Check that the explosion can 'see' this entity. + vecSpot = pEntity->BodyTarget( vecSrc, false ); + UTIL_TraceLine( vecSrc, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); + + if( old_radius_damage.GetBool() ) + { + if ( tr.fraction != 1.0 && tr.m_pEnt != pEntity ) + continue; + } + else + { + if ( tr.fraction != 1.0 ) + { + if ( IsExplosionTraceBlocked(&tr) ) + { + if( ShouldUseRobustRadiusDamage( pEntity ) ) + { + if( vecSpot.DistToSqr( vecSrc ) > flHalfRadiusSqr ) + { + // Only use robust model on a target within one-half of the explosion's radius. + continue; + } + + Vector vecToTarget = vecSpot - tr.endpos; + VectorNormalize( vecToTarget ); + + // We're going to deflect the blast along the surface that + // interrupted a trace from explosion to this target. + Vector vecUp, vecDeflect; + CrossProduct( vecToTarget, tr.plane.normal, vecUp ); + CrossProduct( tr.plane.normal, vecUp, vecDeflect ); + VectorNormalize( vecDeflect ); + + // Trace along the surface that intercepted the blast... + UTIL_TraceLine( tr.endpos, tr.endpos + vecDeflect * ROBUST_RADIUS_PROBE_DIST, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); + //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 255, 0, false, 10 ); + + // ...to see if there's a nearby edge that the explosion would 'spill over' if the blast were fully simulated. + UTIL_TraceLine( tr.endpos, vecSpot, MASK_RADIUS_DAMAGE, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); + //NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, false, 10 ); + + if( tr.fraction != 1.0 && tr.DidHitWorld() ) + { + // Still can't reach the target. + continue; + } + // else fall through + } + else + { + continue; + } + } + + // UNDONE: Probably shouldn't let children block parents either? Or maybe those guys should set their owner if they want this behavior? + // HL2 - Dissolve damage is not reduced by interposing non-world objects + if( tr.m_pEnt && tr.m_pEnt != pEntity && tr.m_pEnt->GetOwnerEntity() != pEntity ) + { + // Some entity was hit by the trace, meaning the explosion does not have clear + // line of sight to the entity that it's trying to hurt. If the world is also + // blocking, we do no damage. + CBaseEntity *pBlockingEntity = tr.m_pEnt; + //Msg( "%s may be blocked by %s...", pEntity->GetClassname(), pBlockingEntity->GetClassname() ); + + UTIL_TraceLine( vecSrc, vecSpot, CONTENTS_SOLID, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); + + if( tr.fraction != 1.0 ) + { + continue; + } + + // Now, if the interposing object is physics, block some explosion force based on its mass. + if( pBlockingEntity->VPhysicsGetObject() ) + { + const float MASS_ABSORB_ALL_DAMAGE = 350.0f; + float flMass = pBlockingEntity->VPhysicsGetObject()->GetMass(); + float scale = flMass / MASS_ABSORB_ALL_DAMAGE; + + // Absorbed all the damage. + if( scale >= 1.0f ) + { + continue; + } + + ASSERT( scale > 0.0f ); + flBlockedDamagePercent = scale; + //Msg(" Object (%s) weighing %fkg blocked %f percent of explosion damage\n", pBlockingEntity->GetClassname(), flMass, scale * 100.0f); + } + else + { + // Some object that's not the world and not physics. Generically block 25% damage + flBlockedDamagePercent = 0.25f; + } + } + } + } + // decrease damage for an ent that's farther from the bomb. + flAdjustedDamage = ( vecSrc - tr.endpos ).Length() * falloff; + flAdjustedDamage = info.GetDamage() - flAdjustedDamage; + + if ( flAdjustedDamage <= 0 ) + { + continue; + } + + // the explosion can 'see' this entity, so hurt them! + if (tr.startsolid) + { + // if we're stuck inside them, fixup the position and distance + tr.endpos = vecSrc; + tr.fraction = 0.0; + } + + CTakeDamageInfo adjustedInfo = info; + //Msg("%s: Blocked damage: %f percent (in:%f out:%f)\n", pEntity->GetClassname(), flBlockedDamagePercent * 100, flAdjustedDamage, flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); + adjustedInfo.SetDamage( flAdjustedDamage - (flAdjustedDamage * flBlockedDamagePercent) ); + + // Now make a consideration for skill level! + if( info.GetAttacker() && info.GetAttacker()->IsPlayer() && pEntity->IsNPC() ) + { + // An explosion set off by the player is harming an NPC. Adjust damage accordingly. + adjustedInfo.AdjustPlayerDamageInflictedForSkillLevel(); + } + + Vector dir = vecSpot - vecSrc; + VectorNormalize( dir ); + + // If we don't have a damage force, manufacture one + if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) + { + if ( !( adjustedInfo.GetDamageType() & DMG_PREVENT_PHYSICS_FORCE ) ) + { + CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc ); + } + } + 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 ); + } + + if ( tr.fraction != 1.0 && pEntity == tr.m_pEnt ) + { + ClearMultiDamage( ); + pEntity->DispatchTraceAttack( adjustedInfo, dir, &tr ); + ApplyMultiDamage(); + } + else + { + pEntity->TakeDamage( adjustedInfo ); + } + + // Now hit all triggers along the way that respond to damage... + pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, tr.endpos, dir ); + +#if defined( GAME_DLL ) + if ( info.GetAttacker() && info.GetAttacker()->IsPlayer() && ToBaseCombatCharacter( tr.m_pEnt ) ) + { + + // This is a total hack!!! + bool bIsPrimary = true; + CBasePlayer *player = ToBasePlayer( info.GetAttacker() ); + CBaseCombatWeapon *pWeapon = player->GetActiveWeapon(); + if ( pWeapon && FClassnameIs( pWeapon, "weapon_smg1" ) ) + { + bIsPrimary = false; + } + + gamestats->Event_WeaponHit( player, bIsPrimary, (pWeapon != NULL) ? player->GetActiveWeapon()->GetClassname() : "NULL", info ); + } +#endif + } +} + + +bool CGameRules::ClientCommand( CBaseEntity *pEdict, const CCommand &args ) +{ + if( pEdict->IsPlayer() ) + { + if( GetVoiceGameMgr()->ClientCommand( static_cast(pEdict), args ) ) + return true; + } + + return false; +} + + +void CGameRules::FrameUpdatePostEntityThink() +{ + VPROF( "CGameRules::FrameUpdatePostEntityThink" ); + Think(); +} + +// Hook into the convar from the engine +ConVar skill( "skill", "1" ); + +void CGameRules::Think() +{ + GetVoiceGameMgr()->Update( gpGlobals->frametime ); + SetSkillLevel( skill.GetInt() ); + + if ( log_verbose_enable.GetBool() ) + { + if ( m_flNextVerboseLogOutput < gpGlobals->curtime ) + { + ProcessVerboseLogOutput(); + m_flNextVerboseLogOutput = gpGlobals->curtime + log_verbose_interval.GetFloat(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Called at the end of GameFrame (i.e. after all game logic has run this frame) +//----------------------------------------------------------------------------- +void CGameRules::EndGameFrame( void ) +{ + // If you hit this assert, it means something called AddMultiDamage() and didn't ApplyMultiDamage(). + // The g_MultiDamage.m_hAttacker & g_MultiDamage.m_hInflictor should give help you figure out the culprit. + Assert( g_MultiDamage.IsClear() ); + if ( !g_MultiDamage.IsClear() ) + { + Warning("Unapplied multidamage left in the system:\nTarget: %s\nInflictor: %s\nAttacker: %s\nDamage: %.2f\n", + g_MultiDamage.GetTarget()->GetDebugName(), + g_MultiDamage.GetInflictor()->GetDebugName(), + g_MultiDamage.GetAttacker()->GetDebugName(), + g_MultiDamage.GetDamage() ); + ApplyMultiDamage(); + } +} + +//----------------------------------------------------------------------------- +// trace line rules +//----------------------------------------------------------------------------- +float CGameRules::WeaponTraceEntity( CBaseEntity *pEntity, const Vector &vecStart, const Vector &vecEnd, + unsigned int mask, trace_t *ptr ) +{ + UTIL_TraceEntity( pEntity, vecStart, vecEnd, mask, ptr ); + return 1.0f; +} + + +void CGameRules::CreateStandardEntities() +{ + g_pPlayerResource = (CPlayerResource*)CBaseEntity::Create( "player_manager", vec3_origin, vec3_angle ); + g_pPlayerResource->AddEFlags( EFL_KEEP_ON_RECREATE_ENTITIES ); +} + +//----------------------------------------------------------------------------- +// Purpose: Inform client(s) they can mark the indicated achievement as completed (SERVER VERSION) +// Input : filter - which client(s) to send this to +// iAchievementID - The enumeration value of the achievement to mark (see TODO:Kerry, what file will have the mod's achievement enum?) +//----------------------------------------------------------------------------- +void CGameRules::MarkAchievement( IRecipientFilter& filter, char const *pchAchievementName ) +{ + gamestats->Event_IncrementCountedStatistic( vec3_origin, pchAchievementName, 1.0f ); + + IAchievementMgr *pAchievementMgr = engine->GetAchievementMgr(); + if ( !pAchievementMgr ) + return; + pAchievementMgr->OnMapEvent( pchAchievementName ); +} + +#endif //} !CLIENT_DLL + + +// ----------------------------------------------------------------------------- // +// Shared CGameRules implementation. +// ----------------------------------------------------------------------------- // + +CGameRules::~CGameRules() +{ + Assert( g_pGameRules == this ); + g_pGameRules = NULL; +} + +bool CGameRules::SwitchToNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon ) +{ + return false; +} + +CBaseCombatWeapon *CGameRules::GetNextBestWeapon( CBaseCombatCharacter *pPlayer, CBaseCombatWeapon *pCurrentWeapon ) +{ + return NULL; +} + +bool CGameRules::ShouldCollide( int collisionGroup0, int collisionGroup1 ) +{ + if ( collisionGroup0 > collisionGroup1 ) + { + // swap so that lowest is always first + ::V_swap(collisionGroup0,collisionGroup1); + } + +#ifndef HL2MP + if ( (collisionGroup0 == COLLISION_GROUP_PLAYER || collisionGroup0 == COLLISION_GROUP_PLAYER_MOVEMENT) && + collisionGroup1 == COLLISION_GROUP_PUSHAWAY ) + { + return false; + } +#endif + + if ( collisionGroup0 == COLLISION_GROUP_DEBRIS && collisionGroup1 == COLLISION_GROUP_PUSHAWAY ) + { + // let debris and multiplayer objects collide + return true; + } + + // -------------------------------------------------------------------------- + // NOTE: All of this code assumes the collision groups have been sorted!!!! + // NOTE: Don't change their order without rewriting this code !!! + // -------------------------------------------------------------------------- + + // Don't bother if either is in a vehicle... + if (( collisionGroup0 == COLLISION_GROUP_IN_VEHICLE ) || ( collisionGroup1 == COLLISION_GROUP_IN_VEHICLE )) + return false; + + if ( ( collisionGroup1 == COLLISION_GROUP_DOOR_BLOCKER ) && ( collisionGroup0 != COLLISION_GROUP_NPC ) ) + return false; + + if ( ( collisionGroup0 == COLLISION_GROUP_PLAYER ) && ( collisionGroup1 == COLLISION_GROUP_PASSABLE_DOOR ) ) + return false; + + if ( collisionGroup0 == COLLISION_GROUP_DEBRIS || collisionGroup0 == COLLISION_GROUP_DEBRIS_TRIGGER ) + { + // put exceptions here, right now this will only collide with COLLISION_GROUP_NONE + return false; + } + + // Dissolving guys only collide with COLLISION_GROUP_NONE + if ( (collisionGroup0 == COLLISION_GROUP_DISSOLVING) || (collisionGroup1 == COLLISION_GROUP_DISSOLVING) ) + { + if ( collisionGroup0 != COLLISION_GROUP_NONE ) + return false; + } + + // doesn't collide with other members of this group + // or debris, but that's handled above + if ( collisionGroup0 == COLLISION_GROUP_INTERACTIVE_DEBRIS && collisionGroup1 == COLLISION_GROUP_INTERACTIVE_DEBRIS ) + return false; + +#ifndef HL2MP + // This change was breaking HL2DM + // Adrian: TEST! Interactive Debris doesn't collide with the player. + if ( collisionGroup0 == COLLISION_GROUP_INTERACTIVE_DEBRIS && ( collisionGroup1 == COLLISION_GROUP_PLAYER_MOVEMENT || collisionGroup1 == COLLISION_GROUP_PLAYER ) ) + return false; +#endif + + if ( collisionGroup0 == COLLISION_GROUP_BREAKABLE_GLASS && collisionGroup1 == COLLISION_GROUP_BREAKABLE_GLASS ) + return false; + + // interactive objects collide with everything except debris & interactive debris + if ( collisionGroup1 == COLLISION_GROUP_INTERACTIVE && collisionGroup0 != COLLISION_GROUP_NONE ) + return false; + + // Projectiles hit everything but debris, weapons, + other projectiles + if ( collisionGroup1 == COLLISION_GROUP_PROJECTILE ) + { + if ( collisionGroup0 == COLLISION_GROUP_DEBRIS || + collisionGroup0 == COLLISION_GROUP_WEAPON || + collisionGroup0 == COLLISION_GROUP_PROJECTILE ) + { + return false; + } + } + + // Don't let vehicles collide with weapons + // Don't let players collide with weapons... + // Don't let NPCs collide with weapons + // Weapons are triggers, too, so they should still touch because of that + if ( collisionGroup1 == COLLISION_GROUP_WEAPON ) + { + if ( collisionGroup0 == COLLISION_GROUP_VEHICLE || + collisionGroup0 == COLLISION_GROUP_PLAYER || + collisionGroup0 == COLLISION_GROUP_NPC ) + { + return false; + } + } + + // collision with vehicle clip entity?? + if ( collisionGroup0 == COLLISION_GROUP_VEHICLE_CLIP || collisionGroup1 == COLLISION_GROUP_VEHICLE_CLIP ) + { + // yes then if it's a vehicle, collide, otherwise no collision + // vehicle sorts lower than vehicle clip, so must be in 0 + if ( collisionGroup0 == COLLISION_GROUP_VEHICLE ) + return true; + // vehicle clip against non-vehicle, no collision + return false; + } + + return true; +} + + +const CViewVectors* CGameRules::GetViewVectors() const +{ + return &g_DefaultViewVectors; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns how much damage the given ammo type should do to the victim +// when fired by the attacker. +// Input : pAttacker - Dude what shot the gun. +// pVictim - Dude what done got shot. +// nAmmoType - What been shot out. +// Output : How much hurt to put on dude what done got shot (pVictim). +//----------------------------------------------------------------------------- +float CGameRules::GetAmmoDamage( CBaseEntity *pAttacker, CBaseEntity *pVictim, int nAmmoType ) +{ + float flDamage = 0; + CAmmoDef *pAmmoDef = GetAmmoDef(); + + if ( pAttacker->IsPlayer() ) + { + flDamage = pAmmoDef->PlrDamage( nAmmoType ); + } + else + { + flDamage = pAmmoDef->NPCDamage( nAmmoType ); + } + + return flDamage; +} + + +#ifndef CLIENT_DLL +const char *CGameRules::GetChatPrefix( bool bTeamOnly, CBasePlayer *pPlayer ) +{ + if ( pPlayer && pPlayer->IsAlive() == false ) + { + if ( bTeamOnly ) + return "*DEAD*(TEAM)"; + else + return "*DEAD*"; + } + + return ""; +} + +void CGameRules::CheckHaptics(CBasePlayer* pPlayer) +{ + // NVNT see if the client of pPlayer is using a haptic device. + const char *pszHH = engine->GetClientConVarValue( pPlayer->entindex(), "hap_HasDevice" ); + if( pszHH ) + { + int iHH = atoi( pszHH ); + pPlayer->SetHaptics( iHH != 0 ); + } +} + +void CGameRules::ClientSettingsChanged( CBasePlayer *pPlayer ) +{ + const char *pszName = engine->GetClientConVarValue( pPlayer->entindex(), "name" ); + + const char *pszOldName = pPlayer->GetPlayerName(); + + // msg everyone if someone changes their name, and it isn't the first time (changing no name to current name) + // Note, not using FStrEq so that this is case sensitive + if ( pszOldName[0] != 0 && Q_strcmp( pszOldName, pszName ) ) + { + char text[256]; + Q_snprintf( text,sizeof(text), "%s changed name to %s\n", pszOldName, pszName ); + + UTIL_ClientPrintAll( HUD_PRINTTALK, text ); + + IGameEvent * event = gameeventmanager->CreateEvent( "player_changename" ); + if ( event ) + { + event->SetInt( "userid", pPlayer->GetUserID() ); + event->SetString( "oldname", pszOldName ); + event->SetString( "newname", pszName ); + gameeventmanager->FireEvent( event ); + } + + pPlayer->SetPlayerName( pszName ); + } + + const char *pszFov = engine->GetClientConVarValue( pPlayer->entindex(), "fov_desired" ); + if ( pszFov ) + { + int iFov = atoi(pszFov); + iFov = clamp( iFov, 75, 90 ); + pPlayer->SetDefaultFOV( iFov ); + } + + // NVNT see if this user is still or has began using a haptic device + const char *pszHH = engine->GetClientConVarValue( pPlayer->entindex(), "hap_HasDevice" ); + if( pszHH ) + { + int iHH = atoi( pszHH ); + pPlayer->SetHaptics( iHH != 0 ); + } +} + +CTacticalMissionManager *CGameRules::TacticalMissionManagerFactory( void ) +{ + return new CTacticalMissionManager; +} + +#endif -- cgit v1.2.3