diff options
Diffstat (limited to 'game/shared/tf2/tf_gamerules.cpp')
| -rw-r--r-- | game/shared/tf2/tf_gamerules.cpp | 2242 |
1 files changed, 2242 insertions, 0 deletions
diff --git a/game/shared/tf2/tf_gamerules.cpp b/game/shared/tf2/tf_gamerules.cpp new file mode 100644 index 0000000..cf9b980 --- /dev/null +++ b/game/shared/tf2/tf_gamerules.cpp @@ -0,0 +1,2242 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: The TF Game rules +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "tf_gamerules.h" +#include "tf_shareddefs.h" +#include "ammodef.h" +#include "basetfcombatweapon_shared.h" +#include <KeyValues.h> + + +#ifdef CLIENT_DLL + + #include "c_shield.h" + #include "c_te_effect_dispatch.h" + #define CShield C_Shield + +#else + + #include "tf_shield.h" + #include "te_effect_dispatch.h" + #include "player.h" + #include "tf_player.h" + #include "game.h" + #include "gamerules.h" + #include "teamplay_gamerules.h" + #include "menu_base.h" + #include "ammodef.h" + #include "techtree.h" + #include "tf_team.h" + #include "tf_shield.h" + #include "mathlib/mathlib.h" + #include "entitylist.h" + #include "basecombatweapon.h" + #include "voice_gamemgr.h" + #include "tf_class_infiltrator.h" + #include "team_messages.h" + #include "ndebugoverlay.h" + #include "bot_base.h" + #include "vstdlib/random.h" + #include "info_act.h" + #include "igamesystem.h" + #include "filesystem.h" + #include "info_vehicle_bay.h" + #include "IserverVehicle.h" + #include "weapon_builder.h" + #include "weapon_objectselection.h" + #include "tf_player_resource.h" + +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +REGISTER_GAMERULES_CLASS( CTeamFortress ); + + +#ifdef CLIENT_DLL + + +#else + + #define MAX_OBJECT_COMMAND_DISTANCE 120.0f + + class CVoiceGameMgrHelper : public IVoiceGameMgrHelper + { + public: + virtual bool CanPlayerHearPlayer( CBasePlayer *pListener, CBasePlayer *pTalker ) + { + // Gagged players can't talk at all + if ( ((CBaseTFPlayer*)pTalker)->CanSpeak() == false ) + return false; + + // 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; + + + // Load the objects.txt file. + class CObjectsFileLoad : public CAutoGameSystem + { + public: + virtual bool Init() + { + LoadObjectInfos( filesystem ); + return true; + } + } g_ObjectsFileLoad; + + + + extern bool g_fGameOver; + float g_flNextReinforcementTime = 0.0f; + extern ConVar tf_knockdowntime; + + // Time between reinforcements + #define REINFORCEMENT_TIME 15.0 + + ConVar sk_plr_dmg_grenade ( "sk_plr_dmg_grenade","0"); + + char *sTeamNames[] = + { + "Unassigned", + "Spectator", + "Human", + "Alien", + }; + + // Handle the "PossessBot" command. + void PossessBot_f() + { + CBaseTFPlayer *pPlayer = CBaseTFPlayer::Instance( UTIL_GetCommandClientIndex() ); + if ( !pPlayer ) + return; + + // Put the local player in control of this bot. + if ( args.ArgC() != 2 ) + { + Warning( "PossessBot <client index>\n" ); + return; + } + + int iBotClient = atoi( args[1) ); + int iBotEnt = iBotClient + 1; + + if ( iBotClient < 0 || + iBotClient >= gpGlobals->maxClients || + pPlayer->entindex() == iBotEnt ) + { + Warning( "PossessBot <client index>\n" ); + } + else + { + edict_t *pPlayerData = pPlayer->edict(); + edict_t *pBotData = engine->PEntityOfEntIndex( iBotEnt ); + if ( pBotData && pBotData->GetUnknown() ) + { + // SWAP EDICTS + + // Backup things we don't want to swap. + edict_t oldPlayerData = *pPlayerData; + edict_t oldBotData = *pBotData; + + // Swap edicts. + edict_t tmp = *pPlayerData; + *pPlayerData = *pBotData; + *pBotData = tmp; + + CBaseEntity *pPlayerBaseEnt = CBaseEntity::Instance( pPlayerData ); + CBaseEntity *pBotBaseEnt = CBaseEntity::Instance( pBotData ); + + // Make the other a bot and make the player not a bot. + pPlayerBaseEnt->RemoveFlag( FL_FAKECLIENT ); + pBotBaseEnt->AddFlag( FL_FAKECLIENT ); + + // Point the CBaseEntities at the right players. + pPlayerBaseEnt->NetworkProp()->SetEdict( pPlayerData ); + pBotBaseEnt->NetworkProp()->SetEdict( pBotData ); + + // Freeze the bot. + pBotBaseEnt->AddEFlags( EFL_BOT_FROZEN ); + + // Remove orders to both of them.. + CTFTeam *pTeam = pPlayer->GetTFTeam(); + if ( pTeam ) + { + pTeam->RemoveOrdersToPlayer( (CBaseTFPlayer*)pPlayerBaseEnt ); + pTeam->RemoveOrdersToPlayer( (CBaseTFPlayer*)pBotBaseEnt ); + } + } + } + } + + + // Handler for the "bot" command. + CON_COMMAND_F( "bot", "Add a bot.", FCVAR_CHEAT ) + { + CBaseTFPlayer *pPlayer = CBaseTFPlayer::Instance( UTIL_GetCommandClientIndex() ); + + // The bot command uses switches like command-line switches. + // -count <count> tells how many bots to spawn. + // -team <index> selects the bot's team. Default is -1 which chooses randomly. + // Note: if you do -team !, then it + // -class <index> selects the bot's class. Default is -1 which chooses randomly. + // -frozen prevents the bots from running around when they spawn in. + + // Look at -count. + int count = args.FindArgInt( "-count", 1 ); + count = clamp( count, 1, 16 ); + + int iTeam = -1; + const char *pVal = args.FindArg( "-team" ); + if ( pVal ) + { + if ( pVal[0] == '!' ) + { + iTeam = pPlayer->GetTFTeam()->GetEnemyTeam()->GetTeamNumber(); + } + else + { + iTeam = atoi( pVal ); + iTeam = clamp( iTeam, 0, (GetNumberOfTeams()-1) ); + } + } + + int iClass = args.FindArgInt( "-class", -1 ); + iClass = clamp( iClass, -1, TFCLASS_CLASS_COUNT ); + if ( iClass == TFCLASS_UNDECIDED ) + iClass = TFCLASS_RECON; + + // Look at -frozen. + bool bFrozen = !!args.FindArg( "-frozen" ); + + // Ok, spawn all the bots. + while ( --count >= 0 ) + { + BotPutInServer( bFrozen, iTeam, iClass ); + } + } + + + ConCommand cc_PossessBot( "PossessBot", PossessBot_f, "Toggle. Possess a bot.\n\tArguments: <bot client number>", FCVAR_CHEAT ); + + + Vector MaybeDropToGround( + CBaseEntity *pMainEnt, + bool bDropToGround, + const Vector &vPos, + const Vector &vMins, + const Vector &vMaxs ) + { + if ( bDropToGround ) + { + trace_t trace; + UTIL_TraceHull( vPos, vPos + Vector( 0, 0, -500 ), vMins, vMaxs, MASK_SOLID, pMainEnt, COLLISION_GROUP_NONE, &trace ); + return trace.endpos; + } + else + { + return vPos; + } + } + + + //----------------------------------------------------------------------------- + // Purpose: This function can be used to find a valid placement location for an entity. + // Given an origin to start looking from and a minimum radius to place the entity at, + // it will sweep out a circle around vOrigin and try to find a valid spot (on the ground) + // where mins and maxs will fit. + // Input : *pMainEnt - Entity to place + // &vOrigin - Point to search around + // fRadius - Radius to search within + // nTries - Number of tries to attempt + // &mins - mins of the Entity + // &maxs - maxs of the Entity + // &outPos - Return point + // Output : Returns true and fills in outPos if it found a spot. + //----------------------------------------------------------------------------- + bool EntityPlacementTest( CBaseEntity *pMainEnt, const Vector &vOrigin, Vector &outPos, bool bDropToGround ) + { + // This function moves the box out in each dimension in each step trying to find empty space like this: + // + // X + // X X + // Step 1: X Step 2: XXX Step 3: XXXXX + // X X + // X + // + + Vector mins, maxs; + pMainEnt->CollisionProp()->WorldSpaceAABB( &mins, &maxs ); + mins -= pMainEnt->GetAbsOrigin(); + maxs -= pMainEnt->GetAbsOrigin(); + + // Put some padding on their bbox. + float flPadSize = 5; + Vector vTestMins = mins - Vector( flPadSize, flPadSize, flPadSize ); + Vector vTestMaxs = maxs + Vector( flPadSize, flPadSize, flPadSize ); + + // First test the starting origin. + if ( UTIL_IsSpaceEmpty( pMainEnt, vOrigin + vTestMins, vOrigin + vTestMaxs ) ) + { + outPos = MaybeDropToGround( pMainEnt, bDropToGround, vOrigin, vTestMins, vTestMaxs ); + return true; + } + + Vector vDims = vTestMaxs - vTestMins; + + + // Keep branching out until we get too far. + int iCurIteration = 0; + int nMaxIterations = 15; + + int offset = 0; + do + { + for ( int iDim=0; iDim < 3; iDim++ ) + { + float flCurOffset = offset * vDims[iDim]; + + for ( int iSign=0; iSign < 2; iSign++ ) + { + Vector vBase = vOrigin; + vBase[iDim] += (iSign*2-1) * flCurOffset; + + if ( UTIL_IsSpaceEmpty( pMainEnt, vBase + vTestMins, vBase + vTestMaxs ) ) + { + // Ensure that there is a clear line of sight from the spawnpoint entity to the actual spawn point. + // (Useful for keeping things from spawning behind walls near a spawn point) + trace_t tr; + UTIL_TraceLine( vOrigin, vBase, MASK_SOLID, pMainEnt, COLLISION_GROUP_NONE, &tr ); + + if ( tr.fraction != 1.0 ) + { + continue; + } + + outPos = MaybeDropToGround( pMainEnt, bDropToGround, vBase, vTestMins, vTestMaxs ); + return true; + } + } + } + + ++offset; + } while ( iCurIteration++ < nMaxIterations ); + + // Warning( "EntityPlacementTest for ent %d:%s failed!\n", pMainEnt->entindex(), pMainEnt->GetClassname() ); + return false; + } + + + //----------------------------------------------------------------------------- + // Purpose: + //----------------------------------------------------------------------------- + CBaseEntity *CTeamFortress::GetPlayerSpawnSpot( CBasePlayer *pPlayer ) + { + CBaseEntity *pSpawnSpot = pPlayer->EntSelectSpawnPoint(); + + // Make sure the spawn spot isn't blocked... + Vector vecTestOrg = pSpawnSpot->GetAbsOrigin(); + + vecTestOrg.z += pPlayer->WorldAlignSize().z * 0.5; + Vector origin; + EntityPlacementTest( pPlayer, vecTestOrg, origin, true ); + + // Move the player to the place it said. + pPlayer->Teleport( &origin, NULL, NULL ); + + pPlayer->SetAbsVelocity( vec3_origin ); + pPlayer->SetLocalAngles( pSpawnSpot->GetLocalAngles() ); + pPlayer->m_Local.m_vecPunchAngle = vec3_angle; + pPlayer->SnapEyeAngles( pSpawnSpot->GetLocalAngles() ); + + return pSpawnSpot; + } + + //----------------------------------------------------------------------------- + // Purpose: + //----------------------------------------------------------------------------- + CTeamFortress::CTeamFortress() + { + m_bAllowWeaponSwitch = true; + + // Create the team managers + for ( int i = 0; i < MAX_TF_TEAMS; i++ ) + { + CTFTeam *pTeam = static_cast<CTFTeam*>(CreateEntityByName( "tf_team_manager" )); + pTeam->Init( sTeamNames[i], i ); + + g_Teams.AddToTail( pTeam ); + } + + // Create the hint manager + CBaseEntity::Create( "tf_hintmanager", vec3_origin, vec3_angle ); + } + + //----------------------------------------------------------------------------- + // Purpose: + //----------------------------------------------------------------------------- + CTeamFortress::~CTeamFortress() + { + // Note, don't delete each team since they are in the gEntList and will + // automatically be deleted from there, instead. + g_Teams.Purge(); + } + + //----------------------------------------------------------------------------- + // Purpose: + //----------------------------------------------------------------------------- + void CTeamFortress::UpdateClientData( CBasePlayer *player ) + { + } + + //----------------------------------------------------------------------------- + // Purpose: Called after every level and load change + //----------------------------------------------------------------------------- + void CTeamFortress::LevelInitPostEntity() + { + g_flNextReinforcementTime = gpGlobals->curtime + REINFORCEMENT_TIME; + BaseClass::LevelInitPostEntity(); + } + + void CTeamFortress::CreateStandardEntities() + { + // Create the player resource + g_pPlayerResource = (CPlayerResource*)CBaseEntity::Create( "tf_player_manager", vec3_origin, vec3_angle ); + } + + //----------------------------------------------------------------------------- + // Purpose: The gamerules think function + //----------------------------------------------------------------------------- + void CTeamFortress::Think( void ) + { + BaseClass::Think(); + + // Check the reinforcement time + if ( g_flNextReinforcementTime <= gpGlobals->curtime ) + { + //Msg( "Reinforcement Tick\n" ); + + // Reinforce any dead players + for ( int i = 1; i <= gpGlobals->maxClients; i++ ) + { + CBaseTFPlayer *pPlayer = ToBaseTFPlayer( UTIL_PlayerByIndex(i) ); + if ( pPlayer ) + { + // Ready to respawn? + if ( pPlayer->IsReadyToReinforce() ) + { + pPlayer->Reinforce(); + //pPlayer->GetTFTeam()->PostMessage( TEAMMSG_REINFORCEMENTS_ARRIVED ); + } + } + } + + g_flNextReinforcementTime += REINFORCEMENT_TIME; + } + + // Tell each Team to think + for ( int i = 0; i < GetNumberOfTeams(); i++ ) + { + GetGlobalTeam( i )->Think(); + } + } + + //----------------------------------------------------------------------------- + // Purpose: Player has just left the game + //----------------------------------------------------------------------------- + void CTeamFortress::ClientDisconnected( edict_t *pClient ) + { + CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)CBaseEntity::Instance( pClient ); + if ( pPlayer ) + { + // Tell all orders that this player's left + COrderEvent_PlayerDisconnected order( pPlayer ); + GlobalOrderEvent( &order ); + + // Delete this player's playerclass + pPlayer->ClearPlayerClass(); + } + + BaseClass::ClientDisconnected( pClient ); + } + + //----------------------------------------------------------------------------- + // Purpose: TF2 Specific Client Commands + // Input : + // Output : + //----------------------------------------------------------------------------- + bool CTeamFortress::ClientCommand( CBaseEntity *pEdict, const CCommand &args ) + { + CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)pEdict; + + const char *pcmd = args[0]; + if ( FStrEq( pcmd, "objcmd" ) ) + { + if ( args.ArgC() < 3 ) + return true; + + int entindex = atoi( args[1] ); + edict_t* pEdict = INDEXENT(entindex); + if (pEdict) + { + CBaseEntity* pBaseEntity = GetContainingEntity(pEdict); + CBaseObject* pObject = dynamic_cast<CBaseObject*>(pBaseEntity); + if (pObject && pObject->InSameTeam(pPlayer)) + { + // We have to be relatively close to the object too... + + // FIXME: When I put in a better dismantle solution (namely send the dismantle + // command along with a cancledismantle command), re-enable this. + // Also, need to solve the problem of control panels on large objects + // For the battering ram, for instance, this distance is too far. + + // float flDistSq = pObject->GetAbsOrigin().DistToSqr( pPlayer->GetAbsOrigin() ); + // if (flDistSq <= (MAX_OBJECT_COMMAND_DISTANCE * MAX_OBJECT_COMMAND_DISTANCE)) + { + CCommand objectArgs( args.ArgC() - 2, &args.ArgV()[2]); + pObject->ClientCommand( pPlayer, objectArgs ); + } + } + } + + return true; + } + + if ( FStrEq( pcmd, "buildvehicle" ) ) + { + if ( args.ArgC() < 3 ) + return true; + + int entindex = atoi( args[1] ); + int ivehicle = atoi( args[2] ); + edict_t *pEdict = INDEXENT(entindex); + if (pEdict) + { + CBaseEntity *pBaseEntity = GetContainingEntity(pEdict); + CVGuiScreenVehicleBay *pBayScreen = dynamic_cast<CVGuiScreenVehicleBay*>(pBaseEntity); + if ( pBayScreen && pBayScreen->InSameTeam(pPlayer) ) + { + // Need the same logic as objcmd above to ensure the player's near the vehicle bay vgui screen + pBayScreen->BuildVehicle( pPlayer, ivehicle ); + } + } + + return true; + } + + // TF Commands + if ( FStrEq( pcmd, "menuselect" ) ) + { + if ( pPlayer->m_pCurrentMenu == NULL ) + return true; + if ( args.ArgC() < 2 ) + return true; + + int slot = atoi( args[1] ); + + // select the item from the current menu + if ( pPlayer->m_pCurrentMenu->Input( pPlayer, slot ) == false ) + { + // invalid selection, force menu refresh + pPlayer->m_MenuUpdateTime = gpGlobals->curtime; + pPlayer->m_MenuRefreshTime = gpGlobals->curtime; + } + return true; + } + else if ( FStrEq( pcmd, "changeclass" ) ) + { + pPlayer->m_pCurrentMenu = gMenus[MENU_CLASS]; + pPlayer->m_MenuUpdateTime = gpGlobals->curtime; + pPlayer->m_MenuRefreshTime = gpGlobals->curtime; + return true; + } + else if ( FStrEq( pcmd, "changeteam" ) ) + { + pPlayer->m_pCurrentMenu = gMenus[MENU_TEAM]; + pPlayer->m_MenuUpdateTime = gpGlobals->curtime; + pPlayer->m_MenuRefreshTime = gpGlobals->curtime; + return true; + } + else if ( FStrEq( pcmd, "tactical" ) ) + { + bool bTactical = args[1][0] == '!' ? !pPlayer->GetLocalData()->m_nInTacticalView : (atoi( args[1] ) ? true : false); + + pPlayer->ShowTacticalView( bTactical ); + return true; + } + else if ( FStrEq( pcmd, "tech" ) ) + { + CTFTeam *pTFTeam = pPlayer->GetTFTeam(); + if ( !pTFTeam ) + return true; + + if ( args.ArgC() == 2 ) + { + const char *name = args[1]; + + CBaseTechnology *tech = pTFTeam->m_pTechnologyTree->GetTechnology( name ); + if ( tech ) + { + pTFTeam->EnableTechnology( tech ); + } + } + else + { + Msg( "usage: tech <name>\n" ); + } + return true; + } + else if ( FStrEq( pcmd, "techall" ) ) + { + if ( pPlayer->GetTFTeam() ) + { + pPlayer->GetTFTeam()->EnableAllTechnologies(); + } + return true; + } + else if ( FStrEq( pcmd, "tank" ) ) + { + CBaseEntity::Create( "tank", pPlayer->WorldSpaceCenter(), pPlayer->GetLocalAngles() ); + } + else if ( FStrEq( pcmd, "addres" ) || FStrEq( pcmd, "ar" ) ) + { + if ( args.ArgC() == 3 ) + { + int team = atoi( args[1] ); + float flResourceAmount = atof( args[2] ); + if ( team >= 0 && team < GetNumberOfTeams() ) + { + GetGlobalTFTeam( team )->AddTeamResources( flResourceAmount ); + } + } + else + { + Msg( "usage: ar <team 1 : 2> <amount>\n" ); + } + return true; + } + else if ( FStrEq( pcmd, "preftech" ) ) + { + CTFTeam *pTFTeam = pPlayer->GetTFTeam(); + if ( !pTFTeam ) + return true; + + if ( args.ArgC() == 2 ) + { + int iPrefTechIndex = atoi( args[1] ); + + pPlayer->SetPreferredTechnology( pTFTeam->m_pTechnologyTree, iPrefTechIndex ); + + } + return true; + } + else if( FStrEq( pcmd, "decaltest" ) ) + { + trace_t trace; + int entityIndex; + Vector vForward; + + AngleVectors( pEdict->GetAbsAngles(), &vForward, NULL, NULL ); + + UTIL_TraceLine( pEdict->GetAbsOrigin(), pEdict->GetAbsOrigin() + vForward * 10000, MASK_SOLID_BRUSHONLY, pEdict, COLLISION_GROUP_NONE, &trace ); + + entityIndex = trace.GetEntityIndex(); + + int id = UTIL_PrecacheDecal( "decals/tscorch", true ); + CBroadcastRecipientFilter filter; + te->BSPDecal( filter, 0.0, + &trace.endpos, entityIndex, id ); + + return true; + } + else if( FStrEq( pcmd, "killorder" ) ) + { + if( pPlayer->GetTFTeam() ) + pPlayer->GetTFTeam()->RemoveOrdersToPlayer( pPlayer ); + + return true; + } + else if( BaseClass::ClientCommand( pEdict, args ) ) + { + return true; + } + else + { + return pPlayer->ClientCommand( args ); + } + + return false; + } + + //----------------------------------------------------------------------------- + // Purpose: Player has just spawned. Equip them. + //----------------------------------------------------------------------------- + void CTeamFortress::PlayerSpawn( CBasePlayer *pPlayer ) + { + pPlayer->EquipSuit(); + } + + //----------------------------------------------------------------------------- + // Purpose: + //----------------------------------------------------------------------------- + bool CTeamFortress::PlayFootstepSounds( CBasePlayer *pl ) + { + if ( footsteps.GetInt() == 0 ) + return false; + + CBaseTFPlayer *tfPlayer = static_cast< CBaseTFPlayer * >( pl ); + if ( tfPlayer ) + { + if ( tfPlayer->IsKnockedDown() ) + { + return false; + } + } + + // only make step sounds in multiplayer if the player is moving fast enough + if ( pl->IsOnLadder() || pl->GetAbsVelocity().Length2D() > 100 ) + return true; + + return false; + } + + //----------------------------------------------------------------------------- + // Purpose: Remove falling damage for jetpacking recons + //----------------------------------------------------------------------------- + float CTeamFortress::FlPlayerFallDamage( CBasePlayer *pPlayer ) + { + int iFallDamage = (int)falldamage.GetFloat(); + + CBaseTFPlayer *pTFPlayer = (CBaseTFPlayer *)pPlayer; + if ( pTFPlayer->IsClass( TFCLASS_RECON ) ) + return 0; + + switch ( iFallDamage ) + { + case 1://progressive + pPlayer->m_Local.m_flFallVelocity -= PLAYER_MAX_SAFE_FALL_SPEED; + return pPlayer->m_Local.m_flFallVelocity * DAMAGE_FOR_FALL_SPEED; + break; + default: + case 0:// fixed + return 10; + break; + } + } + + + //----------------------------------------------------------------------------- + // Is the ray blocked by enemy shields? + //----------------------------------------------------------------------------- + bool CTeamFortress::IsBlockedByEnemyShields( const Vector& src, const Vector& end, int nFriendlyTeam ) + { + // Iterate over all shields on the same team, disable them so + // we don't intersect with them... + CShield::ActivateShields( false, nFriendlyTeam ); + + bool bBlocked = CShield::IsBlockedByShields( src, end ); + + CShield::ActivateShields( true, nFriendlyTeam ); + + return bBlocked; + } + + + //----------------------------------------------------------------------------- + // Traces a line vs a shield, returns damage reduction + //----------------------------------------------------------------------------- + float CTeamFortress::WeaponTraceEntity( CBaseEntity *pEntity, + const Vector &src, const Vector &end, unsigned int mask, trace_t *pTrace ) + { + int damageType = pEntity->GetDamageType(); + + // Iterate over all shields on the same team, disable them so + // we don't intersect with them... + CShield::ActivateShields( false, pEntity->GetTeamNumber() ); + + // Trace it baby... + float damage = 1.0f; + bool done; + do + { + // FIXME: Optimize so we don't test the same ray but start at the + // previous collision point + done = true; + UTIL_TraceEntity( pEntity, src, end, mask, pTrace ); + + // Shield check... + if (pTrace->fraction != 1.0) + { + CBaseEntity *pCollidedEntity = pTrace->m_pEnt; + + // Did we hit a shield? + CShield* pShield = dynamic_cast<CShield*>(pCollidedEntity); + if (pShield) + { + Vector vecDir; + VectorSubtract( end, src, vecDir ); + + // Let's see if we let this damage type through... + if (pShield->ProtectionAmount( damageType ) == 1.0f) + { + // We deflected all of the damage + pShield->RegisterDeflection( vecDir, damageType, pTrace ); + damage = 0.0f; + } + else + { + // We deflected part of the damage, but we need to trace again + // only this time we can't let the shield register a collision + damage *= 1.0f - pShield->ProtectionAmount( damageType ); + + // FIXME: DMG_BULLET should be something else + pShield->RegisterPassThru( vecDir, damageType, pTrace ); + pShield->ActivateCollisions( false ); + + done = false; + } + } + } + } + while (!done); + + // Reduce the damage dealt... but don't worry about if if the + // shield actually deflected it. In that case, we actually want + // explosive things to explode at full blast power. The shield will prevent + // the blast damage to things behind the shield + if (damage != 0.0) + { + pEntity->SetDamage(pEntity->GetDamage() * damage); + } + + // Reactivate all shields + CShield::ActivateShields( true ); + return damage; + } + + //----------------------------------------------------------------------------- + // Purpose: Is trace blocked by a world or a shield? + //----------------------------------------------------------------------------- + bool CTeamFortress::IsTraceBlockedByWorldOrShield( const Vector& src, const Vector& end, CBaseEntity *pShooter, int damageType, trace_t* pTrace ) + { + // Iterate over all shields on the same team, disable them so + // we don't intersect with them... + CShield::ActivateShields( false, pShooter->GetTeamNumber() ); + + //NDebugOverlay::Line( src, pTrace->endpos, 255,255,255, true, 5.0 ); + //NDebugOverlay::Box( pTrace->endpos, Vector(-2,-2,-2), Vector(2,2,2), 255,255,255, true, 5.0 ); + + // Now make sure there isn't something other than team players in the way. + class CShieldWorldFilter : public CTraceFilterSimple + { + public: + CShieldWorldFilter( CBaseEntity *pShooter ) : CTraceFilterSimple( pShooter, TFCOLLISION_GROUP_WEAPON ) + { + } + + virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask ) + { + CBaseEntity *pEnt = static_cast<CBaseEntity*>(pHandleEntity); + + // Did we hit a brushmodel? + if ( pEnt->GetSolid() == SOLID_BSP ) + return true; + + // Ignore collisions with everything but shields + if ( pEnt->GetCollisionGroup() != TFCOLLISION_GROUP_SHIELD ) + return false; + + return CTraceFilterSimple::ShouldHitEntity( pHandleEntity, contentsMask ); + } + }; + + trace_t tr; + CShieldWorldFilter shieldworldFilter( pShooter ); + UTIL_TraceLine( src, end, MASK_SOLID, &shieldworldFilter, pTrace ); + + // Shield check... + if (pTrace->fraction != 1.0) + { + CBaseEntity *pEntity = pTrace->m_pEnt; + CShield* pShield = dynamic_cast<CShield*>(pEntity); + if (pShield) + { + Vector vecDir; + VectorSubtract( end, src, vecDir ); + + // We deflected all of the damage + pShield->RegisterDeflection( vecDir, damageType, pTrace ); + } + } + + // Reactivate all shields + CShield::ActivateShields( true ); + return ( pTrace->fraction < 1.0 ); + } + + //----------------------------------------------------------------------------- + // Default implementation of radius damage + //----------------------------------------------------------------------------- + void CTeamFortress::RadiusDamage( const CTakeDamageInfo &info, const Vector &vecSrcIn, float flRadius, int iClassIgnore ) + { + 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; + + // in case grenade is lying on the ground + // Is this even needed anymore? Grenades already jump up in their explode code... + vecSrc.z += 1; + + // 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 ) + continue; + + // blast's don't tavel into or out of water + if (bInWater && pEntity->GetWaterLevel() == 0) + continue; + if (!bInWater && pEntity->GetWaterLevel() == 3) + continue; + + // Copy initial values out of the info + CTakeDamageInfo subInfo = info; + if ( !subInfo.GetAttacker() ) + { + subInfo.SetAttacker( subInfo.GetInflictor() ); + } + + // Don't bother with hitboxes on this test + vecSpot = pEntity->WorldSpaceCenter( ); + WeaponTraceLine ( vecSrc, vecSpot, MASK_SHOT & (~CONTENTS_HITBOX), subInfo.GetInflictor(), subInfo.GetDamageType(), &tr ); + if ( tr.fraction != 1.0 && tr.m_pEnt != pEntity ) + continue; + + // We're going to need to see if it actually hit a shield + // 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; + } + + // decrease damage for an ent that's farther from the bomb. + flAdjustedDamage = ( vecSrc - tr.endpos ).Length() * falloff; + flAdjustedDamage = subInfo.GetDamage() - flAdjustedDamage; + if ( flAdjustedDamage > 0 ) + { + // Knockdown + // For now, just use damage. Eventually we should do it on a per-weapon basis. + /* + if ( pEntity->IsPlayer() && flAdjustedDamage > 40 ) + { + Vector vecForce = vecSpot - vecSrc; + // Reduce the Z component and increase the X,Y + vecForce.x *= 3.0; + vecForce.y *= 3.0; + vecForce.z *= 0.5; + VectorNormalize( vecForce ); + ((CBaseTFPlayer*)pEntity)->KnockDownPlayer( vecForce, flAdjustedDamage * 15.0f, tf_knockdowntime.GetFloat() ); + } + */ + + // Msg( "hit %s\n", pEntity->GetClassname() ); + subInfo.SetDamage( flAdjustedDamage ); + + Vector dir = tr.endpos - vecSrc; + if ( VectorNormalize( dir ) == 0 ) + { + dir = vecSpot - vecSrc; + VectorNormalize( dir ); + } + + // If we don't have a damage force, manufacture one + if ( subInfo.GetDamagePosition() == vec3_origin || subInfo.GetDamageForce() == vec3_origin ) + { + CalculateExplosiveDamageForce( &subInfo, dir, vecSrc ); + } + + if (tr.fraction != 1.0) + { + ClearMultiDamage( ); + + pEntity->DispatchTraceAttack( subInfo, dir, &tr ); + ApplyMultiDamage(); + } + else + { + pEntity->TakeDamage( subInfo ); + } + } + } + } + } + + //----------------------------------------------------------------------------- + // Purpose: Find out if this player had an assistant when he killed an enemy + //----------------------------------------------------------------------------- + CBasePlayer *CTeamFortress::GetDeathAssistant( CBaseEntity *pKiller, CBaseEntity *pInflictor ) + { + if ( !pKiller || pKiller->Classify() != CLASS_PLAYER ) + return NULL; + + CBaseTFPlayer *pAssistant = NULL; + + // Killing entity might be specifying a scorer player + IScorer *pScorerInterface = dynamic_cast<IScorer*>( pKiller ); + if ( pScorerInterface ) + { + pAssistant = (CBaseTFPlayer*)pScorerInterface->GetAssistant(); + } + + // Inflicting entity might be specifying a scoring player + if ( !pAssistant ) + { + pScorerInterface = dynamic_cast<IScorer*>( pInflictor ); + if ( pScorerInterface ) + { + pAssistant = (CBaseTFPlayer*)pScorerInterface->GetAssistant(); + } + } + + // Don't allow self assistance + Assert( pAssistant != pKiller ); + return pAssistant; + } + + //----------------------------------------------------------------------------- + // Purpose: + // Input : *pVictim - + // *pKiller - + // *pInflictor - + //----------------------------------------------------------------------------- + void CTeamFortress::DeathNotice( CBasePlayer *pVictim, const CTakeDamageInfo &info ) + { + // Work out what killed the player, and send a message to all clients about it + const char *killer_weapon_name = "world"; // by default, the player is killed by the world + int killer_index = 0; + int assist_index = 0; + + // Find the killer & the scorer + CBaseEntity *pInflictor = info.GetInflictor(); + CBaseEntity *pKiller = info.GetAttacker(); + CBasePlayer *pScorer = GetDeathScorer( pKiller, pInflictor ); + CBasePlayer *pAssistant = GetDeathAssistant( pKiller, pInflictor ); + + if ( pAssistant ) + { + assist_index = pAssistant->entindex(); + } + + // Custom kill type? + if ( info.GetDamageCustom() ) + { + killer_weapon_name = GetDamageCustomString( info ); + if ( pScorer ) + { + killer_index = pScorer->entindex(); + } + } + else + { + // Is the killer a client? + if ( pScorer ) + { + killer_index = pScorer->entindex(); + + if ( pInflictor ) + { + if ( pInflictor == pScorer ) + { + // If the inflictor is the killer, then it must be their current weapon doing the damage + if ( pScorer->GetActiveWeapon() ) + { + killer_weapon_name = pScorer->GetActiveWeapon()->GetDeathNoticeName(); + } + } + else + { + killer_weapon_name = STRING( pInflictor->m_iClassname ); // it's just that easy + } + } + } + else + { + killer_weapon_name = STRING( pInflictor->m_iClassname ); + } + + // strip the NPC_* or weapon_* from the inflictor's classname + if ( strncmp( killer_weapon_name, "weapon_", 7 ) == 0 ) + { + killer_weapon_name += 7; + } + else if ( strncmp( killer_weapon_name, "NPC_", 8 ) == 0 ) + { + killer_weapon_name += 8; + } + else if ( strncmp( killer_weapon_name, "func_", 5 ) == 0 ) + { + killer_weapon_name += 5; + } + } + +/* CReliableBroadcastRecipientFilter filter; + UserMessageBegin( filter, "DeathMsg" ); + WRITE_BYTE( killer_index ); // the killer + WRITE_BYTE( assist_index ); // the assistant, if any + WRITE_BYTE( ENTINDEX(pVictim->edict()) ); // the victim + WRITE_STRING( killer_weapon_name ); // what they were killed by (should this be a string?) + MessageEnd(); + + // Did he kill himself? + if ( pVictim == pScorer ) + { + UTIL_LogPrintf( "\"%s<%i>\" killed self with %s\n", pVictim->GetPlayerName(), engine->GetPlayerUserId( pVictim->edict() ), killer_weapon_name ); + } + else if ( pScorer ) + { + UTIL_LogPrintf( "\"%s<%i>\" killed \"%s<%i>\" with %s\n", pScorer->GetPlayerName() ), + engine->GetPlayerUserId( pScorer->edict() ), + pVictim->GetPlayerName(), + engine->GetPlayerUserId( pVictim->edict() ), + killer_weapon_name ); + } + else + { + // killed by the world + UTIL_LogPrintf( "\"%s<%i>\" killed by world with %s\n", pVictim->GetPlayerName(), engine->GetPlayerUserId( pVictim->edict() ), killer_weapon_name ); + } */ + + KeyValues * event = new KeyValues( "player_death" ); + event->SetInt("killer", pScorer ? pScorer->GetUserID() : 0 ); + event->SetInt("victim", pVictim->GetUserID() ); + event->SetString("weapon", killer_weapon_name ); + + gameeventmanager->FireEvent( event ); + } + + //----------------------------------------------------------------------------- + // Purpose: Custom kill types for TF + //----------------------------------------------------------------------------- + const char *CTeamFortress::GetDamageCustomString( const CTakeDamageInfo &info ) + { + switch( info.GetDamageCustom() ) + { + case DMG_KILL_BULLRUSH: + return "bullrush"; + break; + default: + break; + }; + + return "INVALID CUSTOM KILL TYPE"; + } + + //----------------------------------------------------------------------------- + // Purpose: + // Input : *pListener - + // *pSpeaker - + // Output : Returns true on success, false on failure. + //----------------------------------------------------------------------------- + bool CTeamFortress::PlayerCanHearChat( CBasePlayer *pListener, CBasePlayer *pSpeaker ) + { + if ( BaseClass::PlayerCanHearChat( pListener, pSpeaker ) ) + { + return true; + } + + CBaseTFPlayer *listener = static_cast< CBaseTFPlayer * >( pListener ); + CBaseTFPlayer *speaker = static_cast< CBaseTFPlayer * >( pSpeaker ); + + if ( listener && speaker ) + { + if ( listener->IsClass( TFCLASS_INFILTRATOR ) ) + { + Vector delta; + delta = listener->EarPosition() - speaker->GetAbsOrigin(); + if ( delta.Length() < INFILTRATOR_EAVESDROP_RADIUS ) + { + return true; + } + } + } + + return false; + } + + + void CTeamFortress::InitDefaultAIRelationships( void ) + { + // Allocate memory for default relationships + CBaseCombatCharacter::AllocateDefaultRelationships(); + + // -------------------------------------------------------------- + // First initialize table so we can report missing relationships + // -------------------------------------------------------------- + int i, j; + for (i=0;i<NUM_AI_CLASSES;i++) + { + for (j=0;j<NUM_AI_CLASSES;j++) + { + // By default all relationships are neutral of priority zero + CBaseCombatCharacter::SetDefaultRelationship( (Class_T)i, (Class_T)j, D_NU, 0 ); + } + } + + // ------------------------------------------------------------ + // > CLASS_ANTLION + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_PLAYER, D_HT, 5); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_BARNACLE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_CITIZEN_PASSIVE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_CITIZEN_REBEL, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_COMBINE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_CONSCRIPT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_HEADCRAB, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_MANHACK, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_METROPOLICE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_MILITARY, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_MISSILE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_SCANNER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_STALKER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_VORTIGAUNT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_ZOMBIE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_PROTOSNIPER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_ANTLION, D_LI, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ANTLION, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_BARNACLE + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_PLAYER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_BARNACLE, D_LI, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_CITIZEN_PASSIVE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_CITIZEN_REBEL, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_COMBINE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_CONSCRIPT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_HEADCRAB, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_MANHACK, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_METROPOLICE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_MILITARY, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_MISSILE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_SCANNER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_STALKER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_VORTIGAUNT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_ZOMBIE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BARNACLE, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_BULLSEYE + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_PLAYER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_ANTLION, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_BARNACLE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_CITIZEN_PASSIVE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_CITIZEN_REBEL, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_COMBINE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_CONSCRIPT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_HEADCRAB, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_MANHACK, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_METROPOLICE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_MILITARY, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_MISSILE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_SCANNER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_STALKER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_VORTIGAUNT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_ZOMBIE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_BULLSEYE, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_CITIZEN_PASSIVE + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_PLAYER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_BARNACLE, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_CITIZEN_PASSIVE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_CITIZEN_REBEL, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_COMBINE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_CONSCRIPT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_HEADCRAB, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_MANHACK, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_METROPOLICE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_MILITARY, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_MISSILE, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_SCANNER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_STALKER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_VORTIGAUNT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_ZOMBIE, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_PASSIVE, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_CITIZEN_REBEL + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_PLAYER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_BARNACLE, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_CITIZEN_PASSIVE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_CITIZEN_REBEL, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_COMBINE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_CONSCRIPT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_HEADCRAB, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_MANHACK, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_METROPOLICE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_MILITARY, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_MISSILE, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_SCANNER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_STALKER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_VORTIGAUNT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_ZOMBIE, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CITIZEN_REBEL, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_COMBINE + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_PLAYER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_BARNACLE, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_CITIZEN_PASSIVE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_CITIZEN_REBEL, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_COMBINE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_CONSCRIPT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_HEADCRAB, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_MANHACK, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_METROPOLICE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_MILITARY, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_MISSILE, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_SCANNER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_STALKER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_VORTIGAUNT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_ZOMBIE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_COMBINE, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_CONSCRIPT + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_PLAYER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_BARNACLE, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_CITIZEN_PASSIVE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_CITIZEN_REBEL, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_COMBINE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_CONSCRIPT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_HEADCRAB, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_MANHACK, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_METROPOLICE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_MILITARY, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_MISSILE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_SCANNER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_STALKER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_VORTIGAUNT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_ZOMBIE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_CONSCRIPT, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_FLARE + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_PLAYER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_ANTLION, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_BARNACLE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_CITIZEN_PASSIVE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_CITIZEN_REBEL, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_COMBINE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_CONSCRIPT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_HEADCRAB, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_MANHACK, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_METROPOLICE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_MILITARY, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_MISSILE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_SCANNER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_STALKER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_VORTIGAUNT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_ZOMBIE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_FLARE, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_HEADCRAB + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_PLAYER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_BARNACLE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_CITIZEN_PASSIVE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_CITIZEN_REBEL, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_COMBINE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_CONSCRIPT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_HEADCRAB, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_MANHACK, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_METROPOLICE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_MILITARY, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_MISSILE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_SCANNER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_STALKER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_VORTIGAUNT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_ZOMBIE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_HEADCRAB, CLASS_EARTH_FAUNA, D_NU, 0); + + + // ------------------------------------------------------------ + // > CLASS_MANHACK + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_PLAYER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_BARNACLE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_CITIZEN_PASSIVE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_CITIZEN_REBEL, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_COMBINE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_CONSCRIPT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_HEADCRAB, D_HT,-1); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_MANHACK, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_METROPOLICE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_MILITARY, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_MISSILE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_SCANNER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_STALKER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_VORTIGAUNT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_ZOMBIE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MANHACK, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_METROPOLICE + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_PLAYER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_BARNACLE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_CITIZEN_PASSIVE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_CITIZEN_REBEL, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_COMBINE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_CONSCRIPT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_HEADCRAB, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_MANHACK, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_METROPOLICE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_MILITARY, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_MISSILE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_SCANNER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_STALKER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_VORTIGAUNT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_ZOMBIE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_METROPOLICE, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_MILITARY + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_PLAYER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_BARNACLE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_CITIZEN_PASSIVE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_CITIZEN_REBEL, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_COMBINE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_CONSCRIPT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_HEADCRAB, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_MANHACK, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_METROPOLICE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_MILITARY, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_MISSILE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_SCANNER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_STALKER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_VORTIGAUNT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_ZOMBIE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MILITARY, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_MISSILE + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_PLAYER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_BARNACLE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_CITIZEN_PASSIVE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_CITIZEN_REBEL, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_COMBINE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_CONSCRIPT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_HEADCRAB, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_MANHACK, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_METROPOLICE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_MILITARY, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_MISSILE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_SCANNER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_STALKER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_VORTIGAUNT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_ZOMBIE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_MISSILE, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_NONE + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_PLAYER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_ANTLION, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_BARNACLE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_CITIZEN_PASSIVE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_CITIZEN_REBEL, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_COMBINE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_CONSCRIPT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_HEADCRAB, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_MANHACK, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_METROPOLICE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_MILITARY, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_SCANNER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_STALKER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_VORTIGAUNT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_ZOMBIE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_NONE, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_PLAYER + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_PLAYER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_BARNACLE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_BULLSEYE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_CITIZEN_PASSIVE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_CITIZEN_REBEL, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_COMBINE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_CONSCRIPT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_HEADCRAB, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_MANHACK, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_METROPOLICE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_MILITARY, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_MISSILE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_SCANNER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_STALKER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_VORTIGAUNT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_ZOMBIE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_PROTOSNIPER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PLAYER, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_SCANNER + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_PLAYER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_BARNACLE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_CITIZEN_PASSIVE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_CITIZEN_REBEL, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_COMBINE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_CONSCRIPT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_HEADCRAB, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_MANHACK, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_METROPOLICE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_MILITARY, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_MISSILE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_SCANNER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_STALKER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_VORTIGAUNT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_ZOMBIE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_SCANNER, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_STALKER + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_PLAYER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_BARNACLE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_CITIZEN_PASSIVE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_CITIZEN_REBEL, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_COMBINE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_CONSCRIPT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_HEADCRAB, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_MANHACK, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_METROPOLICE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_MILITARY, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_MISSILE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_SCANNER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_STALKER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_VORTIGAUNT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_ZOMBIE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_STALKER, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_VORTIGAUNT + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_PLAYER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_BARNACLE, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_CITIZEN_PASSIVE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_CITIZEN_REBEL, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_COMBINE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_CONSCRIPT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_HEADCRAB, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_MANHACK, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_METROPOLICE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_MILITARY, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_MISSILE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_SCANNER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_STALKER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_VORTIGAUNT, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_ZOMBIE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_VORTIGAUNT, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_ZOMBIE + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_PLAYER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_BARNACLE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_CITIZEN_PASSIVE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_CITIZEN_REBEL, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_COMBINE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_CONSCRIPT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_HEADCRAB, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_MANHACK, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_METROPOLICE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_MILITARY, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_MISSILE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_SCANNER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_STALKER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_VORTIGAUNT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_ZOMBIE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_ZOMBIE, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_PROTOSNIPER + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_NONE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_PLAYER, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_ANTLION, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_BARNACLE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_BULLSEYE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_CITIZEN_PASSIVE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_CITIZEN_REBEL, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_COMBINE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_CONSCRIPT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_FLARE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_HEADCRAB, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_MANHACK, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_METROPOLICE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_MILITARY, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_MISSILE, D_NU, 5); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_SCANNER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_STALKER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_VORTIGAUNT, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_ZOMBIE, D_HT, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_PROTOSNIPER, CLASS_EARTH_FAUNA, D_NU, 0); + + // ------------------------------------------------------------ + // > CLASS_EARTH_FAUNA + // + // Fears pretty much everything except other earth fauna: + // + // 5. Fears flares and missiles most of all. + // 4. Fears flying machines next. + // 3. Fears aliens next. + // 2. Fears combine human military next. + // 1. Fears humans next. + // 0. Fears the player the least. + // + // ------------------------------------------------------------ + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_NONE, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_PLAYER, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_ANTLION, D_FR, 2); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_BARNACLE, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_BULLSEYE, D_FR, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_CITIZEN_PASSIVE, D_FR, 1); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_CITIZEN_REBEL, D_FR, 1); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_COMBINE, D_FR, 3); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_CONSCRIPT, D_FR, 1); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_FLARE, D_FR, 5); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_HEADCRAB, D_FR, 2); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_MANHACK, D_FR, 4); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_METROPOLICE, D_FR, 1); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_MILITARY, D_FR, 1); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_MISSILE, D_FR, 5); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_SCANNER, D_FR, 4); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_STALKER, D_FR, 2); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_VORTIGAUNT, D_FR, 2); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_ZOMBIE, D_FR, 1); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_PROTOSNIPER, D_NU, 0); + CBaseCombatCharacter::SetDefaultRelationship(CLASS_EARTH_FAUNA, CLASS_EARTH_FAUNA, D_LI, 0); + } + + //----------------------------------------------------------------------------- + // Purpose: Return a pointer to the opposing team + //----------------------------------------------------------------------------- + CTFTeam *GetOpposingTeam( CTeam *pTeam ) + { + // Hacky! + if ( pTeam->GetTeamNumber() == 1 ) + return GetGlobalTFTeam( 2 ); + + return GetGlobalTFTeam( 1 ); + } + + + //------------------------------------------------------------------------------ + // Purpose : Return classify text for classify type + //------------------------------------------------------------------------------ + const char *CTeamFortress::AIClassText(int classType) + { + switch (classType) + { + case CLASS_NONE: return "CLASS_NONE"; + case CLASS_PLAYER: return "CLASS_PLAYER"; + case CLASS_ANTLION: return "CLASS_ANTLION"; + case CLASS_BARNACLE: return "CLASS_BARNACLE"; + case CLASS_BULLSEYE: return "CLASS_BULLSEYE"; + case CLASS_CITIZEN_PASSIVE: return "CLASS_CITIZEN_PASSIVE"; + case CLASS_CITIZEN_REBEL: return "CLASS_CITIZEN_REBEL"; + case CLASS_COMBINE: return "CLASS_COMBINE"; + case CLASS_CONSCRIPT: return "CLASS_CONSCRIPT"; + case CLASS_HEADCRAB: return "CLASS_HEADCRAB"; + case CLASS_MANHACK: return "CLASS_MANHACK"; + case CLASS_METROPOLICE: return "CLASS_METROPOLICE"; + case CLASS_MILITARY: return "CLASS_MILITARY"; + case CLASS_SCANNER: return "CLASS_SCANNER"; + case CLASS_STALKER: return "CLASS_STALKER"; + case CLASS_VORTIGAUNT: return "CLASS_VORTIGAUNT"; + case CLASS_ZOMBIE: return "CLASS_ZOMBIE"; + case CLASS_PROTOSNIPER: return "CLASS_PROTOSNIPER"; + case CLASS_MISSILE: return "CLASS_MISSILE"; + case CLASS_FLARE: return "CLASS_FLARE"; + case CLASS_EARTH_FAUNA: return "CLASS_EARTH_FAUNA"; + + default: return "MISSING CLASS in ClassifyText()"; + } + } + + //----------------------------------------------------------------------------- + // Purpose: When gaining new technologies in TF, prevent auto switching if we + // receive a weapon during the switch + // Input : *pPlayer - + // *pWeapon - + // Output : Returns true on success, false on failure. + //----------------------------------------------------------------------------- + bool CTeamFortress::FShouldSwitchWeapon( CBasePlayer *pPlayer, CBaseCombatWeapon *pWeapon ) + { + if ( !GetAllowWeaponSwitch() ) + return false; + + // Never auto switch to object placement + if ( dynamic_cast<CWeaponBuilder*>(pWeapon) ) + return false; + if ( dynamic_cast<CWeaponObjectSelection*>(pWeapon) ) + return false; + + return BaseClass::FShouldSwitchWeapon( pPlayer, pWeapon ); + } + + //----------------------------------------------------------------------------- + // Purpose: + // Input : allow - + //----------------------------------------------------------------------------- + void CTeamFortress::SetAllowWeaponSwitch( bool allow ) + { + m_bAllowWeaponSwitch = allow; + } + + //----------------------------------------------------------------------------- + // Purpose: + // Output : Returns true on success, false on failure. + //----------------------------------------------------------------------------- + bool CTeamFortress::GetAllowWeaponSwitch( void ) + { + return m_bAllowWeaponSwitch; + } + + //----------------------------------------------------------------------------- + // Purpose: + // Input : *pPlayer - + // Output : const char + //----------------------------------------------------------------------------- + const char *CTeamFortress::SetDefaultPlayerTeam( CBasePlayer *pPlayer ) + { + Assert( pPlayer ); + // int clientIndex = pPlayer->entindex(); + // engine->SetClientKeyValue( clientIndex, engine->GetInfoKeyBuffer( pPlayer->edict() ), "model", "" ); + return BaseClass::SetDefaultPlayerTeam( pPlayer ); + } + + // Called when game rules are destroyed by CWorld + void CTeamFortress::LevelShutdown( void ) + { + g_flNextReinforcementTime = 0.0f; + + g_hCurrentAct = NULL; + + BaseClass::LevelShutdown(); + } + + void InitBodyQue(void) + { + // FIXME: Make this work + } + +#endif + + +// ----------------------------------------------------------------------------- // +// Shared CTeamFortress code. +// ----------------------------------------------------------------------------- // + +//----------------------------------------------------------------------------- +// Purpose: Send the appropriate weapon impact +//----------------------------------------------------------------------------- +void WeaponImpact( trace_t *tr, Vector vecDir, bool bHurt, CBaseEntity *pEntity, int iDamageType ) +{ + // If we hit a combat shield, play the hit effect + if ( iDamageType & (DMG_PLASMA | DMG_ENERGYBEAM) ) + { + if ( bHurt ) + { + Assert( pEntity ); + bool bHitHandheldShield = (pEntity->IsPlayer() && ((CBaseTFPlayer*)pEntity)->IsHittingShield( vecDir, NULL )); + if ( bHitHandheldShield ) + { + UTIL_ImpactTrace( tr, iDamageType, "PlasmaShield" ); + } + else + { + // Client waits for server version +#ifndef CLIENT_DLL + // Make sure the server sends to us, even though we're predicting + CDisablePredictionFiltering dpf; + UTIL_ImpactTrace( tr, iDamageType, "PlasmaHurt" ); +#endif + } + } + else + { + UTIL_ImpactTrace( tr, iDamageType, "PlasmaUnhurt" ); + } + } + else + { + if ( bHurt ) + { + Assert( pEntity ); + bool bHitHandheldShield = (pEntity->IsPlayer() && ((CBaseTFPlayer*)pEntity)->IsHittingShield( vecDir, NULL )); + if ( bHitHandheldShield ) + { + UTIL_ImpactTrace( tr, iDamageType, "ImpactShield" ); + } + else + { + // Client waits for server version +#ifndef CLIENT_DLL + // Make sure the server sends to us, even though we're predicting + CDisablePredictionFiltering dpf; + UTIL_ImpactTrace( tr, iDamageType, "Impact" ); +#endif + } + } + else + { + UTIL_ImpactTrace( tr, iDamageType, "ImpactUnhurt" ); + } + } +} + + +static bool CheckCollisionGroupPlayerMovement( int collisionGroup0, int collisionGroup1 ) +{ + if ( collisionGroup0 == COLLISION_GROUP_PLAYER ) + { + // Players don't collide with objects or other players + if ( collisionGroup1 == COLLISION_GROUP_PLAYER || collisionGroup1 == TFCOLLISION_GROUP_OBJECT ) + 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; + case TFCOLLISION_GROUP_OBJECT_SOLIDTOPLAYERMOVEMENT: + // Certain objects are still solid to player movement + return true; + case TFCOLLISION_GROUP_COMBATOBJECT: + case TFCOLLISION_GROUP_OBJECT: + return false; + case TFCOLLISION_GROUP_GRENADE: + case COLLISION_GROUP_DEBRIS: + return false; + } + } + + return true; +} + + +void CTeamFortress::WeaponTraceLine( const Vector& src, const Vector& end, unsigned int mask, CBaseEntity *pShooter, int damageType, trace_t* pTrace ) +{ + // Iterate over all shields on the same team, disable them so + // we don't intersect with them... + CShield::ActivateShields( false, pShooter->GetTeamNumber() ); + + UTIL_TraceLine(src, end, mask, pShooter, TFCOLLISION_GROUP_WEAPON, pTrace); + +// NDebugOverlay::Line( src, pTrace->endpos, 255,255,255, true, 5.0 ); +// NDebugOverlay::Box( pTrace->endpos, Vector(-2,-2,-2), Vector(2,2,2), 255,255,255, true, 5.0 ); + + // Shield check... + if (pTrace->fraction != 1.0) + { + CBaseEntity *pEntity = pTrace->m_pEnt; + CShield* pShield = dynamic_cast<CShield*>(pEntity); + if (pShield) + { + Vector vecDir; + VectorSubtract( end, src, vecDir ); + + // We deflected all of the damage + pShield->RegisterDeflection( vecDir, damageType, pTrace ); + } + } + + // Reactivate all shields + CShield::ActivateShields( true ); +} + + +bool CTeamFortress::ShouldCollide( int collisionGroup0, int collisionGroup1 ) +{ + if ( collisionGroup0 > collisionGroup1 ) + { + // swap so that lowest is always first + swap(collisionGroup0,collisionGroup1); + } + + // Ignore base class HL2 definition for COLLISION_GROUP_WEAPON, change to COLLISION_GROUP_NONE + if ( collisionGroup0 == COLLISION_GROUP_WEAPON ) + { + collisionGroup0 = COLLISION_GROUP_NONE; + } + if ( collisionGroup1 == COLLISION_GROUP_WEAPON ) + { + collisionGroup1 = COLLISION_GROUP_NONE; + } + + // Shields collide with weapons + grenades only + if ( collisionGroup0 == TFCOLLISION_GROUP_SHIELD ) + { + return ((collisionGroup1 == TFCOLLISION_GROUP_WEAPON) || (collisionGroup1 == TFCOLLISION_GROUP_GRENADE)); + } + + // Weapons can collide with things (players) in vehicles. + if( collisionGroup0 == COLLISION_GROUP_IN_VEHICLE && collisionGroup1 == TFCOLLISION_GROUP_WEAPON ) + { + return true; + } + + // COLLISION TEST: + // Players don't collide with other players or objects + if ( !CheckCollisionGroupPlayerMovement( collisionGroup0, collisionGroup1 ) ) + return false; + // Reciprocal test + if ( !CheckCollisionGroupPlayerMovement( collisionGroup1, collisionGroup0 ) ) + return false; + + // Grenades don't collide with debris + if ( collisionGroup1 == TFCOLLISION_GROUP_GRENADE ) + { + if ( collisionGroup0 == COLLISION_GROUP_DEBRIS ) + return false; + } + + // Combat objects don't collide with players + if ( collisionGroup1 == TFCOLLISION_GROUP_COMBATOBJECT ) + { + if ( collisionGroup0 == COLLISION_GROUP_PLAYER ) + return false; + } + + // Resource chunks don't collide with each other or vehicles + if ( collisionGroup1 == TFCOLLISION_GROUP_RESOURCE_CHUNK ) + { + if ( collisionGroup0 == TFCOLLISION_GROUP_RESOURCE_CHUNK ) + return false; +// if ( collisionGroup0 == COLLISION_GROUP_VEHICLE ) +// return false; + } + + return BaseClass::ShouldCollide( collisionGroup0, collisionGroup1 ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Fire a generic bullet +//----------------------------------------------------------------------------- +void CTeamFortress::FireBullets( const CTakeDamageInfo &info, int cShots, const Vector &vecSrc, const Vector &vecDirShooting, + const Vector &vecSpread, float flDistance, int iAmmoType, + int iTracerFreq, int firingEntID, int attachmentID, const char *sCustomTracer ) +{ + static int tracerCount; + bool tracer; + trace_t tr; + CTakeDamageInfo subInfo = info; + CBaseTFCombatWeapon *pWeapon = dynamic_cast<CBaseTFCombatWeapon*>(info.GetInflictor()); + + Assert( subInfo.GetInflictor() ); + + // Default attacker is the inflictor + if ( subInfo.GetAttacker() == NULL ) + { + subInfo.SetAttacker( subInfo.GetInflictor() ); + } + + // -------------------------------------------------- + // Get direction vectors for spread + // -------------------------------------------------- + Vector vecUp = Vector(0,0,1); + Vector vecRight; + CrossProduct ( vecDirShooting, vecUp, vecRight ); + CrossProduct ( vecDirShooting, -vecRight, vecUp ); + +#ifndef CLIENT_DLL + ClearMultiDamage(); +#endif + + int seed = 0; + + for (int iShot = 0; iShot < cShots; iShot++) + { + // get circular gaussian spread + float x, y, z; + + do + { + float x1, x2, y1, y2; + + // Note the additional seed because otherwise we get the same set of random #'s and will get stuck + // in an infinite loop here potentially + // FIXME: Can we use a gaussian random # function instead? ywb + if ( CBaseEntity::GetPredictionRandomSeed() != -1 ) + { + x1 = SHARED_RANDOMFLOAT_SEED( -0.5, 0.5, ++seed ); + x2 = SHARED_RANDOMFLOAT_SEED( -0.5, 0.5, ++seed ); + y1 = SHARED_RANDOMFLOAT_SEED( -0.5, 0.5, ++seed ); + y2 = SHARED_RANDOMFLOAT_SEED( -0.5, 0.5, ++seed ); + } + else + { + x1 = RandomFloat( -0.5, 0.5 ); + x2 = RandomFloat( -0.5, 0.5 ); + y1 = RandomFloat( -0.5, 0.5 ); + y2 = RandomFloat( -0.5, 0.5 ); + } + + x = x1 + x2; + y = y1 + y2; + + z = x*x+y*y; + } while (z > 1); + + Vector vecDir = vecDirShooting + x * vecSpread.x * vecRight + y * vecSpread.y * vecUp; + Vector vecEnd = vecSrc + vecDir * flDistance; + + // Try the trace + WeaponTraceLine( vecSrc, vecEnd, MASK_SHOT, subInfo.GetInflictor(), subInfo.GetDamageType(), &tr ); + + tracer = false; + if (iTracerFreq != 0 && (tracerCount++ % iTracerFreq) == 0) + { + Vector vecTracerSrc; + + // adjust tracer position for player + if ( subInfo.GetInflictor()->IsPlayer() ) + { + Vector forward, right; + CBasePlayer *pPlayer = ToBasePlayer( subInfo.GetInflictor() ); + pPlayer->EyeVectors( &forward, &right, NULL ); + vecTracerSrc = vecSrc + Vector ( 0 , 0 , -4 ) + right * 2 + forward * 16; + } + else + { + vecTracerSrc = vecSrc; + } + + if ( iTracerFreq != 1 ) // guns that always trace also always decal + tracer = true; + + if ( sCustomTracer ) + { + UTIL_Tracer( vecTracerSrc, tr.endpos, subInfo.GetInflictor()->entindex(), TRACER_DONT_USE_ATTACHMENT, 0, false, (char*)sCustomTracer ); + } + else + { + UTIL_Tracer( vecTracerSrc, tr.endpos, subInfo.GetInflictor()->entindex() ); + } + } + + // do damage, paint decals + if ( tr.fraction != 1.0 ) + { + CBaseEntity *pEntity = tr.m_pEnt; + + // NOTE: If we want to know more than whether or not the entity can actually be hurt + // for the purposes of impact effects, the client needs to know a lot more. + bool bTargetCouldBeHurt = false; + if ( pEntity->m_takedamage ) + { + if ( !pEntity->InSameTeam( subInfo.GetInflictor() ) ) + { + bTargetCouldBeHurt = true; + } +#ifndef CLIENT_DLL + subInfo.SetDamagePosition( vecSrc ); + // Hit the target + pEntity->DispatchTraceAttack( subInfo, vecDir, &tr ); +#endif + } + + // No decal if we hit a shield + if ( pEntity->GetCollisionGroup() != TFCOLLISION_GROUP_SHIELD ) + { + WeaponImpact( &tr, vecDir, bTargetCouldBeHurt, pEntity, subInfo.GetDamageType() ); + } + } + + if ( pWeapon ) + { + pWeapon->BulletWasFired( vecSrc, tr.endpos ); + } + } + + // Apply any damage we've stacked up +#ifndef CLIENT_DLL + ApplyMultiDamage(); +#endif +} + + + +//----------------------------------------------------------------------------- +// Purpose: Init TF2 ammo definitions +//----------------------------------------------------------------------------- +CAmmoDef *GetAmmoDef() +{ + static CAmmoDef def; + static bool bInitted = false; + + if ( !bInitted ) + { + bInitted = true; + + def.AddAmmoType("Bullets", DMG_BULLET, TRACER_LINE, 0, 0, INFINITE_AMMO, 0, 0); + def.AddAmmoType("Rockets", DMG_BLAST, TRACER_LINE, 0, 0, 6, 0, 0); + def.AddAmmoType("Grenades", DMG_BLAST, TRACER_LINE, 0, 0, 3, 0, 0); + def.AddAmmoType("ShieldGrenades", DMG_ENERGYBEAM, TRACER_LINE, 0, 0, 5, 0, 0); + def.AddAmmoType("ShotgunEnergy", DMG_ENERGYBEAM, TRACER_LINE, 0, 0, INFINITE_AMMO, 0, 0); + def.AddAmmoType("PlasmaGrenade", DMG_ENERGYBEAM|DMG_BLAST, TRACER_LINE, 0, 0, 30, 0, 0); + def.AddAmmoType("ResourceChunks", DMG_GENERIC,TRACER_LINE, 0, 0, 4, 0, 0); // Resource chunks + def.AddAmmoType("Limpets", DMG_BLAST, TRACER_LINE, 0, 0, 40, 0, 0); + def.AddAmmoType("Gasoline", DMG_BURN, TRACER_LINE, 0, 0, 80, 0, 0); + + // Combat Objects + def.AddAmmoType("RallyFlags", DMG_GENERIC, TRACER_NONE, 0, 0, 1, 0, 0); + def.AddAmmoType("EMPGenerators", DMG_GENERIC, TRACER_NONE, 0, 0, 1, 0, 0); + } + + return &def; +} |