/*** * * Copyright (c) 1996-2002, Valve LLC. All rights reserved. * * This product contains software technology licensed from Id * Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. * All Rights Reserved. * * Use, distribution, and modification of this source code and/or resulting * object code is restricted to non-commercial enhancements to products from * Valve LLC. All other use, distribution, or modification is prohibited * without written permission from Valve LLC. * ****/ // ------------------------------------------- // // maprules.cpp // // This module contains entities for implementing/changing game // rules dynamically within each map (.BSP) // // ------------------------------------------- #include "extdll.h" #include "eiface.h" #include "util.h" #include "gamerules.h" //#include "maprules.h" //empty file #include "cbase.h" #include "player.h" class CRuleEntity : public CBaseEntity { public: void Spawn( void ); void KeyValue( KeyValueData *pkvd ); virtual int Save( CSave &save ); virtual int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; void SetMaster( int iszMaster ) { m_iszMaster = iszMaster; } protected: BOOL CanFireForActivator( CBaseEntity *pActivator ); private: string_t m_iszMaster; }; TYPEDESCRIPTION CRuleEntity::m_SaveData[] = { DEFINE_FIELD( CRuleEntity, m_iszMaster, FIELD_STRING), }; IMPLEMENT_SAVERESTORE( CRuleEntity, CBaseEntity ) void CRuleEntity::Spawn( void ) { pev->solid = SOLID_NOT; pev->movetype = MOVETYPE_NONE; pev->effects = EF_NODRAW; } void CRuleEntity::KeyValue( KeyValueData *pkvd ) { if( FStrEq(pkvd->szKeyName, "master" ) ) { SetMaster( ALLOC_STRING( pkvd->szValue ) ); pkvd->fHandled = TRUE; } else CBaseEntity::KeyValue( pkvd ); } BOOL CRuleEntity::CanFireForActivator( CBaseEntity *pActivator ) { if (!pActivator) { return TRUE; } else if ( m_iszMaster ) { if( UTIL_IsMasterTriggered( m_iszMaster, pActivator ) ) return TRUE; else return FALSE; } return TRUE; } // // CRulePointEntity -- base class for all rule "point" entities (not brushes) // class CRulePointEntity : public CRuleEntity { public: void Spawn( void ); }; void CRulePointEntity::Spawn( void ) { CRuleEntity::Spawn(); pev->frame = 0; pev->model = 0; } // // CRuleBrushEntity -- base class for all rule "brush" entities (not brushes) // Default behavior is to set up like a trigger, invisible, but keep the model for volume testing // class CRuleBrushEntity : public CRuleEntity { public: void Spawn( void ); private: }; void CRuleBrushEntity::Spawn( void ) { SET_MODEL( edict(), STRING(pev->model) ); CRuleEntity::Spawn(); } // CGameScore / game_score -- award points to player / team // Points +/- total // Flag: Allow negative scores SF_SCORE_NEGATIVE // Flag: Award points to team in teamplay SF_SCORE_TEAM #define SF_SCORE_NEGATIVE 0x0001 #define SF_SCORE_TEAM 0x0002 class CGameScore : public CRulePointEntity { public: void Spawn( void ); void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); void KeyValue( KeyValueData *pkvd ); inline int Points( void ) { return (int)pev->frags; } inline BOOL AllowNegativeScore( void ) { return pev->spawnflags & SF_SCORE_NEGATIVE; } inline BOOL AwardToTeam( void ) { return pev->spawnflags & SF_SCORE_TEAM; } inline void SetPoints( int points ) { pev->frags = points; } private: }; LINK_ENTITY_TO_CLASS( game_score, CGameScore ) void CGameScore::Spawn( void ) { CRulePointEntity::Spawn(); } void CGameScore::KeyValue( KeyValueData *pkvd ) { if( FStrEq( pkvd->szKeyName, "points" ) ) { SetPoints( atoi( pkvd->szValue ) ); pkvd->fHandled = TRUE; } else CRulePointEntity::KeyValue( pkvd ); } void CGameScore::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if( !CanFireForActivator( pActivator ) ) return; // Only players can use this if( pActivator->IsPlayer() ) { if( AwardToTeam() ) { pActivator->AddPointsToTeam( Points(), AllowNegativeScore() ); } else { pActivator->AddPoints( Points(), AllowNegativeScore() ); } } } // CGameEnd / game_end -- Ends the game in MP class CGameEnd : public CRulePointEntity { public: void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); private: }; LINK_ENTITY_TO_CLASS( game_end, CGameEnd ) void CGameEnd::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if( !CanFireForActivator( pActivator ) ) return; g_pGameRules->EndMultiplayerGame(); } // // CGameText / game_text -- NON-Localized HUD Message (use env_message to display a titles.txt message) // Flag: All players SF_ENVTEXT_ALLPLAYERS // #define SF_ENVTEXT_ALLPLAYERS 0x0001 #define SF_ENVTEXT_ONLY_ONCE 0x0002 class CGameText : public CRulePointEntity { public: void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); void KeyValue( KeyValueData *pkvd ); virtual int Save( CSave &save ); virtual int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; inline BOOL MessageToAll( void ) { return (pev->spawnflags & SF_ENVTEXT_ALLPLAYERS); } inline void MessageSet( const char *pMessage ) { pev->message = ALLOC_STRING(pMessage); } inline const char *MessageGet( void ) { return STRING(pev->message); } void EXPORT TriggerThink( void ); private: hudtextparms_t m_textParms; CBaseEntity *m_pActivator; }; LINK_ENTITY_TO_CLASS( game_text, CGameText ) // Save parms as a block. Will break save/restore if the structure changes, but this entity didn't ship with Half-Life, so // it can't impact saved Half-Life games. TYPEDESCRIPTION CGameText::m_SaveData[] = { DEFINE_ARRAY( CGameText, m_textParms, FIELD_CHARACTER, sizeof(hudtextparms_t) ), DEFINE_FIELD( CGameText, m_pActivator, FIELD_CLASSPTR ), }; IMPLEMENT_SAVERESTORE( CGameText, CRulePointEntity ) void CGameText::KeyValue( KeyValueData *pkvd ) { if( FStrEq( pkvd->szKeyName, "channel" ) ) { m_textParms.channel = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "x" ) ) { m_textParms.x = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq(pkvd->szKeyName, "y" ) ) { m_textParms.y = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "effect" ) ) { m_textParms.effect = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "color" ) ) { int color[4]; UTIL_StringToIntArray( color, 4, pkvd->szValue ); m_textParms.r1 = color[0]; m_textParms.g1 = color[1]; m_textParms.b1 = color[2]; m_textParms.a1 = color[3]; pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "color2" ) ) { int color[4]; UTIL_StringToIntArray( color, 4, pkvd->szValue ); m_textParms.r2 = color[0]; m_textParms.g2 = color[1]; m_textParms.b2 = color[2]; m_textParms.a2 = color[3]; pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "fadein" ) ) { m_textParms.fadeinTime = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "fadeout" ) ) { m_textParms.fadeoutTime = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "holdtime" ) ) { m_textParms.holdTime = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq(pkvd->szKeyName, "fxtime" ) ) { m_textParms.fxTime = atof( pkvd->szValue ); pkvd->fHandled = TRUE; } else CRulePointEntity::KeyValue( pkvd ); } void CGameText::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if( !CanFireForActivator( pActivator ) ) return; if( MessageToAll() ) { UTIL_HudMessageAll( m_textParms, MessageGet() ); } else { if ( pActivator && pActivator->IsNetClient() ) { UTIL_HudMessage( pActivator, m_textParms, MessageGet() ); } } if ( pev->target ) { m_pActivator = pActivator; SetThink(&CGameText:: TriggerThink ); SetNextThink( m_textParms.fadeinTime + m_textParms.holdTime + m_textParms.fadeoutTime ); // ALERT(at_console, "GameText sets NextThink = %f\n", m_textParms.fadeinTime + m_textParms.holdTime + m_textParms.fadeoutTime); } else if ( pev->spawnflags & SF_ENVTEXT_ONLY_ONCE ) { SetThink(&CGameText:: SUB_Remove ); SetNextThink( 0.1 ); } } //LRC void CGameText::TriggerThink( void ) { // ALERT(at_console, "GameText uses targets\n"); SUB_UseTargets( m_pActivator, USE_TOGGLE, 0 ); if ( pev->spawnflags & SF_ENVTEXT_ONLY_ONCE ) { SetThink(&CGameText:: SUB_Remove ); SetNextThink( 0.1 ); } } // // CGameTeamMaster / game_team_master -- "Masters" like multisource, but based on the team of the activator // Only allows mastered entity to fire if the team matches my team // // team index (pulled from server team list "mp_teamlist" // Flag: Remove on Fire // Flag: Any team until set? -- Any team can use this until the team is set (otherwise no teams can use it) // #define SF_TEAMMASTER_FIREONCE 0x0001 #define SF_TEAMMASTER_ANYTEAM 0x0002 class CGameTeamMaster : public CRulePointEntity { public: void KeyValue( KeyValueData *pkvd ); void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); // int ObjectCaps( void ) { return CRulePointEntity:: ObjectCaps() | FCAP_MASTER; } BOOL IsTriggered( CBaseEntity *pActivator ); const char *TeamID( void ); inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMMASTER_FIREONCE) ? TRUE : FALSE; } inline BOOL AnyTeam( void ) { return (pev->spawnflags & SF_TEAMMASTER_ANYTEAM) ? TRUE : FALSE; } private: BOOL TeamMatch( CBaseEntity *pActivator ); int m_teamIndex; USE_TYPE triggerType; }; LINK_ENTITY_TO_CLASS( game_team_master, CGameTeamMaster ) void CGameTeamMaster::KeyValue( KeyValueData *pkvd ) { if( FStrEq( pkvd->szKeyName, "teamindex" ) ) { m_teamIndex = atoi( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "triggerstate" ) ) { int type = atoi( pkvd->szValue ); switch( type ) { case 0: triggerType = USE_OFF; break; case 2: triggerType = USE_TOGGLE; break; default: triggerType = USE_ON; break; } pkvd->fHandled = TRUE; } else CRulePointEntity::KeyValue( pkvd ); } void CGameTeamMaster::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if( !CanFireForActivator( pActivator ) ) return; if( useType == USE_SET ) { if( value < 0 ) { m_teamIndex = -1; } else { m_teamIndex = g_pGameRules->GetTeamIndex( pActivator->TeamID() ); } return; } if( TeamMatch( pActivator ) ) { SUB_UseTargets( pActivator, triggerType, value ); if( RemoveOnFire() ) UTIL_Remove( this ); } } BOOL CGameTeamMaster::IsTriggered( CBaseEntity *pActivator ) { return TeamMatch( pActivator ); } const char *CGameTeamMaster::TeamID( void ) { if( m_teamIndex < 0 ) // Currently set to "no team" return ""; return g_pGameRules->GetIndexedTeamName( m_teamIndex ); // UNDONE: Fill this in with the team from the "teamlist" } BOOL CGameTeamMaster::TeamMatch( CBaseEntity *pActivator ) { if( m_teamIndex < 0 && AnyTeam() ) return TRUE; if( !pActivator ) return FALSE; return UTIL_TeamsMatch( pActivator->TeamID(), TeamID() ); } // // CGameTeamSet / game_team_set -- Changes the team of the entity it targets to the activator's team // Flag: Fire once // Flag: Clear team -- Sets the team to "NONE" instead of activator #define SF_TEAMSET_FIREONCE 0x0001 #define SF_TEAMSET_CLEARTEAM 0x0002 class CGameTeamSet : public CRulePointEntity { public: void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_TEAMSET_FIREONCE) ? TRUE : FALSE; } inline BOOL ShouldClearTeam( void ) { return (pev->spawnflags & SF_TEAMSET_CLEARTEAM) ? TRUE : FALSE; } private: }; LINK_ENTITY_TO_CLASS( game_team_set, CGameTeamSet ) void CGameTeamSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if( !CanFireForActivator( pActivator ) ) return; if( ShouldClearTeam() ) { SUB_UseTargets( pActivator, USE_SET, -1 ); } else { SUB_UseTargets( pActivator, USE_SET, 0 ); } if( RemoveOnFire() ) { UTIL_Remove( this ); } } // // CGamePlayerZone / game_player_zone -- players in the zone fire my target when I'm fired // // Needs master? class CGamePlayerZone : public CRuleBrushEntity { public: void KeyValue( KeyValueData *pkvd ); void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); virtual int Save( CSave &save ); virtual int Restore( CRestore &restore ); static TYPEDESCRIPTION m_SaveData[]; private: string_t m_iszInTarget; string_t m_iszOutTarget; string_t m_iszInCount; string_t m_iszOutCount; }; LINK_ENTITY_TO_CLASS( game_zone_player, CGamePlayerZone ) TYPEDESCRIPTION CGamePlayerZone::m_SaveData[] = { DEFINE_FIELD( CGamePlayerZone, m_iszInTarget, FIELD_STRING ), DEFINE_FIELD( CGamePlayerZone, m_iszOutTarget, FIELD_STRING ), DEFINE_FIELD( CGamePlayerZone, m_iszInCount, FIELD_STRING ), DEFINE_FIELD( CGamePlayerZone, m_iszOutCount, FIELD_STRING ), }; IMPLEMENT_SAVERESTORE( CGamePlayerZone, CRuleBrushEntity ) void CGamePlayerZone::KeyValue( KeyValueData *pkvd ) { if( FStrEq(pkvd->szKeyName, "intarget" ) ) { m_iszInTarget = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "outtarget" ) ) { m_iszOutTarget = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "incount" ) ) { m_iszInCount = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } else if( FStrEq( pkvd->szKeyName, "outcount" ) ) { m_iszOutCount = ALLOC_STRING( pkvd->szValue ); pkvd->fHandled = TRUE; } else CRuleBrushEntity::KeyValue( pkvd ); } void CGamePlayerZone::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { int playersInCount = 0; int playersOutCount = 0; if( !CanFireForActivator( pActivator ) ) return; CBaseEntity *pPlayer = NULL; for( int i = 1; i <= gpGlobals->maxClients; i++ ) { pPlayer = UTIL_PlayerByIndex( i ); if ( pPlayer ) { TraceResult trace; int hullNumber; BOOL inside = FALSE; if (pev->origin == g_vecZero) //LRC - to support movewith { hullNumber = human_hull; if( pPlayer->pev->flags & FL_DUCKING ) { hullNumber = head_hull; } UTIL_TraceModel( pPlayer->pev->origin, pPlayer->pev->origin, hullNumber, edict(), &trace ); inside = trace.fStartSolid; } else { //LIMITATION: this doesn't allow for non-cuboid game_zone_player entities. // (is that a problem?) inside = this->Intersects(pPlayer); } if ( inside ) { playersInCount++; if( m_iszInTarget ) { FireTargets( STRING( m_iszInTarget ), pPlayer, pActivator, useType, value ); } } else { playersOutCount++; if( m_iszOutTarget ) { FireTargets( STRING( m_iszOutTarget ), pPlayer, pActivator, useType, value ); } } } } if( m_iszInCount ) { FireTargets( STRING( m_iszInCount ), pActivator, this, USE_SET, playersInCount ); } if( m_iszOutCount ) { FireTargets( STRING( m_iszOutCount ), pActivator, this, USE_SET, playersOutCount ); } } // // CGamePlayerHurt / game_player_hurt -- Damages the player who fires it // Flag: Fire once #define SF_PKILL_FIREONCE 0x0001 class CGamePlayerHurt : public CRulePointEntity { public: void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PKILL_FIREONCE) ? TRUE : FALSE; } private: }; LINK_ENTITY_TO_CLASS( game_player_hurt, CGamePlayerHurt ) void CGamePlayerHurt::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if( !CanFireForActivator( pActivator ) ) return; if( pActivator->IsPlayer() ) { if( pev->dmg < 0 ) pActivator->TakeHealth( -pev->dmg, DMG_GENERIC ); else pActivator->TakeDamage( pev, pev, pev->dmg, DMG_GENERIC ); } SUB_UseTargets( pActivator, useType, value ); if( RemoveOnFire() ) { UTIL_Remove( this ); } } // // CGameCounter / game_counter -- Counts events and fires target // Flag: Fire once // Flag: Reset on Fire #define SF_GAMECOUNT_FIREONCE 0x0001 #define SF_GAMECOUNT_RESET 0x0002 class CGameCounter : public CRulePointEntity { public: void Spawn( void ); void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_FIREONCE) ? TRUE : FALSE; } inline BOOL ResetOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNT_RESET) ? TRUE : FALSE; } inline void CountUp( void ) { pev->frags++; } inline void CountDown( void ) { pev->frags--; } inline void ResetCount( void ) { pev->frags = pev->dmg; } inline int CountValue( void ) { return (int)pev->frags; } inline int LimitValue( void ) { return (int)pev->health; } inline BOOL HitLimit( void ) { return CountValue() == LimitValue(); } private: inline void SetCountValue( int value ) { pev->frags = value; } inline void SetInitialValue( int value ) { pev->dmg = value; } }; LINK_ENTITY_TO_CLASS( game_counter, CGameCounter ) void CGameCounter::Spawn( void ) { // Save off the initial count SetInitialValue( CountValue() ); CRulePointEntity::Spawn(); } void CGameCounter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if( !CanFireForActivator( pActivator ) ) return; switch( useType ) { case USE_ON: case USE_TOGGLE: CountUp(); break; case USE_OFF: CountDown(); break; case USE_SET: SetCountValue( (int)value ); break; case USE_KILL: case USE_SAME: case USE_NOT: break; default: break; } if( HitLimit() ) { SUB_UseTargets( pActivator, USE_TOGGLE, 0 ); if( RemoveOnFire() ) { UTIL_Remove( this ); } if( ResetOnFire() ) { ResetCount(); } } } // // CGameCounterSet / game_counter_set -- Sets the counter's value // Flag: Fire once #define SF_GAMECOUNTSET_FIREONCE 0x0001 class CGameCounterSet : public CRulePointEntity { public: void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_GAMECOUNTSET_FIREONCE) ? TRUE : FALSE; } private: }; LINK_ENTITY_TO_CLASS( game_counter_set, CGameCounterSet ) void CGameCounterSet::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if( !CanFireForActivator( pActivator ) ) return; SUB_UseTargets( pActivator, USE_SET, pev->frags ); if( RemoveOnFire() ) { UTIL_Remove( this ); } } // // CGamePlayerEquip / game_playerequip -- Sets the default player equipment // Flag: USE Only #define SF_PLAYEREQUIP_USEONLY 0x0001 #define MAX_EQUIP 32 class CGamePlayerEquip : public CRulePointEntity { public: void KeyValue( KeyValueData *pkvd ); void Touch( CBaseEntity *pOther ); void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); inline BOOL UseOnly( void ) { return (pev->spawnflags & SF_PLAYEREQUIP_USEONLY) ? TRUE : FALSE; } private: void EquipPlayer( CBaseEntity *pPlayer ); string_t m_weaponNames[MAX_EQUIP]; int m_weaponCount[MAX_EQUIP]; }; LINK_ENTITY_TO_CLASS( game_player_equip, CGamePlayerEquip ) void CGamePlayerEquip::KeyValue( KeyValueData *pkvd ) { CRulePointEntity::KeyValue( pkvd ); if( !pkvd->fHandled ) { for( int i = 0; i < MAX_EQUIP; i++ ) { if( !m_weaponNames[i] ) { char tmp[128]; UTIL_StripToken( pkvd->szKeyName, tmp ); m_weaponNames[i] = ALLOC_STRING( tmp ); m_weaponCount[i] = atoi( pkvd->szValue ); m_weaponCount[i] = Q_max( 1, m_weaponCount[i] ); pkvd->fHandled = TRUE; break; } } } } void CGamePlayerEquip::Touch( CBaseEntity *pOther ) { if( !CanFireForActivator( pOther ) ) return; if( UseOnly() ) return; EquipPlayer( pOther ); } void CGamePlayerEquip::EquipPlayer( CBaseEntity *pEntity ) { CBasePlayer *pPlayer = NULL; if( pEntity->IsPlayer() ) { pPlayer = (CBasePlayer *)pEntity; } if( !pPlayer ) return; for( int i = 0; i < MAX_EQUIP; i++ ) { if( !m_weaponNames[i] ) break; for( int j = 0; j < m_weaponCount[i]; j++ ) { pPlayer->GiveNamedItem( STRING( m_weaponNames[i] ) ); } } } void CGamePlayerEquip::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { EquipPlayer( pActivator ); } // // CGamePlayerTeam / game_player_team -- Changes the team of the player who fired it // Flag: Fire once // Flag: Kill Player // Flag: Gib Player #define SF_PTEAM_FIREONCE 0x0001 #define SF_PTEAM_KILL 0x0002 #define SF_PTEAM_GIB 0x0004 class CGamePlayerTeam : public CRulePointEntity { public: void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); private: inline BOOL RemoveOnFire( void ) { return (pev->spawnflags & SF_PTEAM_FIREONCE) ? TRUE : FALSE; } inline BOOL ShouldKillPlayer( void ) { return (pev->spawnflags & SF_PTEAM_KILL) ? TRUE : FALSE; } inline BOOL ShouldGibPlayer( void ) { return (pev->spawnflags & SF_PTEAM_GIB) ? TRUE : FALSE; } const char *TargetTeamName( const char *pszTargetName ); }; LINK_ENTITY_TO_CLASS( game_player_team, CGamePlayerTeam ) const char *CGamePlayerTeam::TargetTeamName( const char *pszTargetName ) { CBaseEntity *pTeamEntity = NULL; while( ( pTeamEntity = UTIL_FindEntityByTargetname( pTeamEntity, pszTargetName ) ) != NULL ) { if( FClassnameIs( pTeamEntity->pev, "game_team_master" ) ) return pTeamEntity->TeamID(); } return NULL; } void CGamePlayerTeam::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { if( !CanFireForActivator( pActivator ) ) return; if( pActivator->IsPlayer() ) { const char *pszTargetTeam = TargetTeamName( STRING(pev->target) ); if ( pszTargetTeam ) { CBasePlayer *pPlayer = (CBasePlayer *)pActivator; g_pGameRules->ChangePlayerTeam( pPlayer, pszTargetTeam, ShouldKillPlayer(), ShouldGibPlayer() ); } } if( RemoveOnFire() ) { UTIL_Remove( this ); } }