// Copyright (C) 2007 Id Software, Inc. // #include "../precompiled.h" #pragma hdrstop #if defined( _DEBUG ) && !defined( ID_REDIRECT_NEWDELETE ) #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #include "TeamManager.h" #include "../structures/DeployRequest.h" #include "../Player.h" #include "../script/Script_Helper.h" #include "../script/Script_ScriptObject.h" #include "../rules/VoteManager.h" #include "../roles/FireTeams.h" #include "../botai/Bot.h" //mal: needed for the bots. #include "../botai/BotThreadData.h" /* =============================================================================== sdTeamManagerLocal =============================================================================== */ /* ================ sdTeamManagerGameState::MakeDefault ================ */ void sdTeamManagerGameState::MakeDefault( void ) { teamData.SetNum( sdTeamManager::GetInstance().GetNumTeams() ); for ( int i = 0; i < teamData.Num(); i++ ) { teamData[ i ].MakeDefault(); } } /* ================ sdTeamManagerGameState::Write ================ */ void sdTeamManagerGameState::Write( idFile* file ) const { for ( int i = 0; i < teamData.Num(); i++ ) { teamData[ i ].Write( file ); } } /* ================ sdTeamManagerGameState::Read ================ */ void sdTeamManagerGameState::Read( idFile* file ) { teamData.SetNum( sdTeamManager::GetInstance().GetNumTeams() ); for ( int i = 0; i < teamData.Num(); i++ ) { teamData[ i ].Read( file ); } } /* ================ sdTeamManagerLocal::sdTeamManagerLocal ================ */ sdTeamManagerLocal::sdTeamManagerLocal( void ) { stateObject.Init( this ); } /* ================ sdTeamManagerLocal::~sdTeamManagerLocal ================ */ sdTeamManagerLocal::~sdTeamManagerLocal( void ) { Shutdown(); } /* ================ sdTeamManagerLocal::Think ================ */ void sdTeamManagerLocal::Think( void ) { int i; for( i = 0; i < teamInfo.Num(); i++ ) { teamInfo[ i ]->Think(); // Gordon: FIXME: This could be done better without polling. if ( teamInfo[ i ]->GetBotTeam() == GDF ) { botThreadData.GetGameWorldState()->gameLocalInfo.nextGDFRespawnTime = ( teamInfo[ i ]->GetTeamRespawnTime() - ( gameLocal.time / 1000 )); } else if ( teamInfo[ i ]->GetBotTeam() == STROGG ) { botThreadData.GetGameWorldState()->gameLocalInfo.nextStroggRespawnTime = ( teamInfo[ i ]->GetTeamRespawnTime() - ( gameLocal.time / 1000 )); } } } /* ================ sdTeamManagerLocal::Init ================ */ void sdTeamManagerLocal::Init( void ) { for( int i = 0; i < gameLocal.declTeamInfoType.Num(); i++ ) { sdTeamInfo* newTeamInfo = new sdTeamInfo(); newTeamInfo->PreInit( i ); teamInfo.Alloc() = newTeamInfo; } teamBits = idMath::BitsForInteger( gameLocal.declTeamInfoType.Num() + 1 ); } /* ================ sdTeamManagerLocal::OnNewMapLoad ================ */ void sdTeamManagerLocal::OnNewMapLoad( void ) { for( int i = 0; i < teamInfo.Num(); i++ ) { teamInfo[ i ]->OnNewMapLoad(); } } /* ================ sdTeamManagerLocal::OnNewScriptLoad ================ */ void sdTeamManagerLocal::OnNewScriptLoad( void ) { for( int i = 0; i < teamInfo.Num(); i++ ) { teamInfo[ i ]->OnNewScriptLoad(); } } /* ================ sdTeamManagerLocal::OnMapStart ================ */ void sdTeamManagerLocal::OnMapStart( void ) { for( int i = 0; i < teamInfo.Num(); i++ ) { teamInfo[ i ]->OnMapStart(); } } /* ================ sdTeamManagerLocal::Shutdown ================ */ void sdTeamManagerLocal::Shutdown( void ) { teamInfo.DeleteContents( true ); } /* ================ sdTeamManagerLocal::GetTeam ================ */ sdTeamInfo* sdTeamManagerLocal::GetTeamSafe( const char* name ) { for( int i = 0; i < teamInfo.Num(); i++ ) { if ( idStr::Icmp( teamInfo[ i ]->GetLookupName(), name ) ) { continue; } return teamInfo[ i ]; } return NULL; } /* ============ sdTeamManagerLocal::GetIndexForTeam ============ */ int sdTeamManagerLocal::GetIndexForTeam( const char* name ) { for( int i = 0; i < teamInfo.Num(); i++ ) { if ( idStr::Icmp( teamInfo[ i ]->GetLookupName(), name ) ) { continue; } return i; } return -1; } /* ================ sdTeamManagerLocal::GetTeam ================ */ sdTeamInfo& sdTeamManagerLocal::GetTeam( const char* name ) { for( int i = 0; i < teamInfo.Num(); i++ ) { if( !idStr::Icmp( teamInfo[ i ]->GetLookupName(), name ) ) { return *teamInfo[ i ]; } } gameLocal.Error( "sdTeamManagerLocal::GetTeam Invalid Team Name '%s'", name ); return *( sdTeamInfo* )NULL; } /* ================ sdTeamManagerLocal::GetTeamByIndex ================ */ sdTeamInfo& sdTeamManagerLocal::GetTeamByIndex( int index ) { if( index < 0 || index >= teamInfo.Num() ) { gameLocal.Warning( "sdTeamManagerLocal::GetTeamByIndex Index OOB %i", index ); return *teamInfo[ 0 ]; } return *teamInfo[ index ]; } /* ================ sdTeamManagerLocal::WriteTeamToStream ================ */ void sdTeamManagerLocal::WriteTeamToStream( sdTeamInfo* newTeam, idFile* file ) const { int newIndex = newTeam ? newTeam->GetIndex() + 1 : 0; file->WriteInt( newIndex ); } /* ================ sdTeamManagerLocal::WriteTeamToStream ================ */ void sdTeamManagerLocal::WriteTeamToStream( sdTeamInfo* newTeam, idBitMsg& msg ) const { int newIndex = newTeam ? newTeam->GetIndex() + 1 : 0; msg.WriteBits( newIndex, teamBits ); } /* ================ sdTeamManagerLocal::WriteTeamToStream ================ */ void sdTeamManagerLocal::WriteTeamToStream( sdTeamInfo* oldTeam, sdTeamInfo* newTeam, idBitMsg& msg ) const { int oldIndex = oldTeam ? oldTeam->GetIndex() + 1 : 0; int newIndex = newTeam ? newTeam->GetIndex() + 1 : 0; msg.WriteDelta( oldIndex, newIndex, teamBits ); } /* ================ sdTeamManagerLocal::ReadTeamFromStream ================ */ sdTeamInfo* sdTeamManagerLocal::ReadTeamFromStream( idFile* file ) const { int teamnum; file->ReadInt( teamnum ); teamnum--; if ( teamnum == -1 ) { return NULL; } return &sdTeamManager::GetInstance().GetTeamByIndex( teamnum ); } /* ================ sdTeamManagerLocal::ReadTeamFromStream ================ */ sdTeamInfo* sdTeamManagerLocal::ReadTeamFromStream( const idBitMsg& msg ) const { int teamnum = msg.ReadBits( teamBits ) - 1; if ( teamnum == -1 ) { return NULL; } return &sdTeamManager::GetInstance().GetTeamByIndex( teamnum ); } /* ================ sdTeamManagerLocal::ReadTeamFromStream ================ */ sdTeamInfo* sdTeamManagerLocal::ReadTeamFromStream( sdTeamInfo* oldTeam, const idBitMsg& msg ) const { int oldIndex = oldTeam ? oldTeam->GetIndex() + 1 : 0; int teamnum = msg.ReadDelta( oldIndex, teamBits ) - 1; if ( teamnum == -1 ) { return NULL; } return &sdTeamManager::GetInstance().GetTeamByIndex( teamnum ); } /* ================ sdTeamManagerLocal::OnScriptChange ================ */ void sdTeamManagerLocal::OnScriptChange( void ) { for( int i = 0; i < teamInfo.Num(); i++ ) { teamInfo[ i ]->OnScriptChange(); } } /* ================ sdTeamManagerLocal::ApplyNetworkState ================ */ void sdTeamManagerLocal::ApplyNetworkState( const sdEntityStateNetworkData& newState ) { NET_GET_NEW( sdTeamManagerGameState ); for ( int i = 0; i < teamInfo.Num(); i++ ) { teamInfo[ i ]->ApplyNetworkState( newData.teamData[ i ] ); } } /* ================ sdTeamManagerLocal::ReadNetworkState ================ */ void sdTeamManagerLocal::ReadNetworkState( const sdEntityStateNetworkData& baseState, sdEntityStateNetworkData& newState, const idBitMsg& msg ) const { NET_GET_STATES( sdTeamManagerGameState ); newData.teamData.SetNum( teamInfo.Num() ); for ( int i = 0; i < teamInfo.Num(); i++ ) { teamInfo[ i ]->ReadNetworkState( baseData.teamData[ i ], newData.teamData[ i ], msg ); } } /* ================ sdTeamManagerLocal::WriteNetworkState ================ */ void sdTeamManagerLocal::WriteNetworkState( const sdEntityStateNetworkData& baseState, sdEntityStateNetworkData& newState, idBitMsg& msg ) const { NET_GET_STATES( sdTeamManagerGameState ); newData.teamData.SetNum( teamInfo.Num() ); for ( int i = 0; i < teamInfo.Num(); i++ ) { teamInfo[ i ]->WriteNetworkState( baseData.teamData[ i ], newData.teamData[ i ], msg ); } } /* ================ sdTeamManagerLocal::CheckNetworkStateChanges ================ */ bool sdTeamManagerLocal::CheckNetworkStateChanges( const sdEntityStateNetworkData& baseState ) const { NET_GET_BASE( sdTeamManagerGameState ); for ( int i = 0; i < teamInfo.Num(); i++ ) { if ( teamInfo[ i ]->CheckNetworkStateChanges( baseData.teamData[ i ] ) ) { return true; } } return false; } /* ================ sdTeamManagerLocal::CreateNetworkStructure ================ */ sdEntityStateNetworkData* sdTeamManagerLocal::CreateNetworkStructure( void ) const { return new sdTeamManagerGameState(); } /* =============================================================================== sdTeamInfo =============================================================================== */ /* ================ sdTeamInfoGameState::MakeDefault ================ */ void sdTeamInfoGameState::MakeDefault( void ) { wins = 0; scriptData.MakeDefault(); } /* ================ sdTeamInfoGameState::MakeDefault ================ */ void sdTeamInfoGameState::Write( idFile* file ) const { file->WriteInt( wins ); scriptData.Write( file ); } /* ================ sdTeamInfoGameState::Read ================ */ void sdTeamInfoGameState::Read( idFile* file ) { file->ReadInt( wins ); scriptData.Read( file ); } extern const idEventDef EV_SyncScriptFieldBroadcast; extern const idEventDef EV_SyncScriptFieldCallback; extern const idEventDef EV_GetName; const idEventDef EV_Team_GetTitle( "getTitle", 'h', DOC_TEXT( "Returns a handle to the localized name of the team." ), 0, NULL ); const idEventDef EV_Team_RegisterDeployable( "registerDeployable", '\0', DOC_TEXT( "Registers an entity as belonging to this team." ), 1, "See also $event:unRegisterDeployable$.", "e", "entity", "Entity to add to the list." ); const idEventDef EV_Team_UnRegisterDeployable( "unRegisterDeployable", '\0', DOC_TEXT( "Removes an entity from this team's list." ), 1, "See also $event:registerDeployable$.", "e", "entity", "Entity to remove from the list." ); const idEventDef EV_Team_RegisterSpawnPoint( "registerSpawnPoint", '\0', DOC_TEXT( "Registers an entity as an active spawn point for this team." ), 1, "See also $event:unRegisterSpawnPoint$.", "e", "entity", "Entity to add to the list." ); const idEventDef EV_Team_UnRegisterSpawnPoint( "unRegisterSpawnPoint", '\0', DOC_TEXT( "Removes an entity from thie team's active spawn points." ), 1, "See also $event:registerSpawnPoint$.", "e", "entity", "Entity to remove from the list." ); const idEventDef EV_Team_SetTeamRearSpawn( "setTeamRearSpawn", '\0', DOC_TEXT( "Marks this entity as the rear spawn for bots to use." ), 1, NULL, "E", "entity", "Entity to mark as the rear spawn." ); CLASS_DECLARATION( idClass, sdTeamInfo ) EVENT( EV_GetName, sdTeamInfo::Event_GetName ) EVENT( EV_Team_GetTitle, sdTeamInfo::Event_GetTitle ) EVENT( EV_Team_RegisterDeployable, sdTeamInfo::Event_RegisterDeployable ) EVENT( EV_Team_UnRegisterDeployable, sdTeamInfo::Event_UnRegisterDeployable ) EVENT( EV_Team_RegisterSpawnPoint, sdTeamInfo::Event_RegisterSpawnPoint ) EVENT( EV_Team_UnRegisterSpawnPoint, sdTeamInfo::Event_UnRegisterSpawnPoint ) EVENT( EV_SyncScriptFieldBroadcast, sdTeamInfo::Event_SyncScriptFieldBroadcast ) EVENT( EV_SyncScriptFieldCallback, sdTeamInfo::Event_SyncScriptFieldCallback ) EVENT( EV_GetKey, sdTeamInfo::Event_GetKey ) EVENT( EV_GetIntKey, sdTeamInfo::Event_GetIntKey ) EVENT( EV_GetFloatKey, sdTeamInfo::Event_GetFloatKey ) EVENT( EV_GetVectorKey, sdTeamInfo::Event_GetVectorKey ) EVENT( EV_GetKeyWithDefault, sdTeamInfo::Event_GetKeyWithDefault ) EVENT( EV_GetIntKeyWithDefault, sdTeamInfo::Event_GetIntKeyWithDefault ) EVENT( EV_GetFloatKeyWithDefault, sdTeamInfo::Event_GetFloatKeyWithDefault ) EVENT( EV_GetVectorKeyWithDefault, sdTeamInfo::Event_GetVectorKeyWithDefault ) EVENT( EV_Team_SetTeamRearSpawn, sdTeamInfo::Event_SetTeamRearSpawn ) END_CLASS const char* fireTeamNames[ sdTeamInfo::MAX_FIRETEAMS ] = { "Alpha", "Beta", "Gamma", "Delta", "Epsilon", "Zeta", "Eta", "Theta" }; /* ================ sdTeamInfo::sdTeamInfo ================ */ sdTeamInfo::sdTeamInfo( void ) : index( -1 ), info( NULL ), passwordCVar( NULL ), lifeStatTitle( NULL ) { wins = 0; info = NULL; defaultClass = NULL; scriptObject = NULL; scriptThread = NULL; allowRespawnFunc = NULL; teamNextRespawnTimeFunc = NULL; rearSpawnBase = NULL; playZoneExitToolTip = NULL; fireTeams = new sdFireTeam[ MAX_FIRETEAMS ]; for ( int i = 0; i < MAX_FIRETEAMS; i++ ) { fireTeams[ i ].SetDefaultName( fireTeamNames[ i ] ); fireTeams[ i ].SetGameTeam( this ); } ResetAll(); } /* ================ sdTeamInfo::sdTeamInfo ================ */ sdTeamInfo::~sdTeamInfo( void ) { delete[] fireTeams; } /* ================ sdTeamInfo::GetFireTeam ================ */ sdFireTeam& sdTeamInfo::GetFireTeam( int index ) { return fireTeams[ index ]; } /* ================ sdTeamInfo::GetFireTeamIndex ================ */ int sdTeamInfo::GetFireTeamIndex( sdFireTeam* fireTeam ) const { if ( fireTeam == NULL ) { return -1; } for ( int i = 0; i < MAX_FIRETEAMS; i++ ) { if ( static_cast( &fireTeams[ i ] ) == fireTeam ) { return i; } } return -1; } /* ================ sdTeamInfo::GetDefaultFireTeamName ================ */ const char* sdTeamInfo::GetDefaultFireTeamName( int index ) { return fireTeamNames[ index ]; } /* ================ sdTeamInfo::PreInit ================ */ void sdTeamInfo::PreInit( int _index ) { index = _index; const sdDeclStringMap* data = gameLocal.declTeamInfoType.LocalFindByIndex( index, false ); lookupname = data->GetName(); } /* ================ sdTeamInfo::OnScriptChange ================ */ void sdTeamInfo::OnScriptChange( void ) { if ( scriptThread != NULL ) { gameLocal.program->FreeThread( scriptThread ); scriptThread = NULL; } if ( scriptObject ) { gameLocal.program->FreeScriptObject( scriptObject ); } } /* ================ sdTeamInfo::Reset ================ */ void sdTeamInfo::Reset( void ) { deployables.Clear(); spawnLocations.Clear(); } /* ================ sdTeamInfo::ResetAll ================ */ void sdTeamInfo::ResetAll( void ) { Reset(); wins = 0; } /* ================ sdTeamInfo::AllowRespawn ================ */ bool sdTeamInfo::AllowRespawn( idPlayer* player ) { sdScriptHelper h1; h1.Push( player->GetScriptObject() ); scriptObject->CallNonBlockingScriptEvent( allowRespawnFunc, h1 ); return gameLocal.program->GetReturnedInteger() != 0; } /* ================ sdTeamInfo::GetTeamRespawnTime ================ */ int sdTeamInfo::GetTeamRespawnTime( void ) { sdScriptHelper h1; scriptObject->CallNonBlockingScriptEvent( teamNextRespawnTimeFunc, h1 ); return idMath::Ftoi( gameLocal.program->GetReturnedFloat() ); } /* ================ sdTeamInfo::OnCampaignChange ================ */ void sdTeamInfo::OnCampaignChange( void ) { ResetAll(); } /* ================ sdTeamInfo::Init ================ */ void sdTeamInfo::Init( void ) { info = gameLocal.declTeamInfoType[ index ]; const idDict& dict = info->GetDict(); title = declHolder.declLocStrType[ dict.GetString( "name" ) ]; if ( title == NULL ) { gameLocal.Error( "sdTeamInfo::Init No Title Provided" ); } winString = declHolder.declLocStrType[ dict.GetString( "match_win_string" ) ]; winStringSW_Speed = declHolder.declLocStrType[ dict.GetString( "match_win_sw_speed" ) ]; winStringSW_XP = declHolder.declLocStrType[ dict.GetString( "match_win_sw_xp" ) ]; winMusic = dict.GetString( "snd_music_won" ); spawnFxName = dict.GetString( "fx_spawn", "fx/teleporterplayer" ); allowRevive = dict.GetBool( "allow_revive" ); crashLandFxName = dict.GetString( "fx_crashland" ); crashLandThreshold = dict.GetFloat( "crashland_threshold" ); parachuteLandFxName = dict.GetString( "fx_parachuteland" ); parachuteLandThreshold = dict.GetFloat( "parachuteland_threshold" ); botTeam = ( playerTeamTypes_t )dict.GetInt( "bot_team" ); highCommandName = declHolder.declLocStrType[ dict.GetString( "high_command_name" ) ]; if ( highCommandName == NULL ) { gameLocal.Warning( "sdTeamInfo::Init No High Command Name Provided" ); } defaultClass = gameLocal.declPlayerClassType[ dict.GetString( "pc_default" ) ]; if( !defaultClass ) { gameLocal.Error( "sdTeamInfo::Init No Default Class Supplied" ); } proficiencyTypes.Clear(); const idKeyValue* kv = NULL; while ( kv = dict.MatchPrefix( "proficiencyList", kv ) ) { const sdDeclProficiencyType* pType = gameLocal.declProficiencyTypeType[ kv->GetValue() ]; if ( !pType ) { gameLocal.Error( "sdTeamInfo::Init Invalid Proficiency Type '%s'", kv->GetValue().c_str() ); } proficiencyTypes.Alloc() = pType; } const char* passwordCVarName = dict.GetString( "cvar_password" ); if ( *passwordCVarName ) { passwordCVar = cvarSystem->Find( passwordCVarName ); if ( !passwordCVar ) { cvarSystem->SetCVarString( passwordCVarName, "", CVAR_NOCHEAT ); passwordCVar = cvarSystem->Find( passwordCVarName ); assert( passwordCVar ); } } else { passwordCVar = NULL; } int count = dict.GetInt( "num_ratings" ); ratings.SetNum( count ); for ( int i = 0; i < count; i++ ) { const char* ratingName = dict.GetString( va( "rating_%i", i + 1 ) ); const sdDeclRating* rating = gameLocal.declRatingType[ ratingName ]; if ( !rating ) { gameLocal.Error( "sdTeamInfo::Init Failed to Load Rating '%s'", ratingName ); } ratings[ i ] = rating; } playZoneExitToolTip = gameLocal.declToolTipType[ dict.GetString( "tt_leavingzone" ) ]; // load lifeStat titles const char* lifeStatName = dict.GetString( "lifestat_title", "blank" ); lifeStatTitle = declHolder.declLocStrType.LocalFind( lifeStatName ); game->CacheDictionaryMedia( dict ); } /* ================ sdTeamInfo::SortPlayers ================ */ void sdTeamInfo::SortPlayers( idStaticList< idPlayer*, MAX_CLIENTS >& list, bool wantSpectators ) { list.Clear(); idStaticList< idPlayer*, MAX_CLIENTS > specList; int i; for( i = 0; i < MAX_CLIENTS; i++ ) { idPlayer* p = gameLocal.GetClient( i ); if( p == NULL ) { continue; } sdTeamInfo* team = p->GetGameTeam(); if( ( team == NULL || *team != *this ) ) { if( !wantSpectators ) { continue; } idPlayer* specClient = p->GetSpectateClient(); if( specClient == NULL || specClient == p ) { continue; } sdTeamInfo* spectatingTeam = specClient->GetGameTeam(); if( spectatingTeam == NULL || *spectatingTeam != *this ) { continue; } specList.Append( p ); continue; } list.Append( p ); } list.Sort( SortPlayersFunc ); // ensure that spectators always report last specList.Sort( SortPlayersFunc ); list.Append( specList ); } /* ================ sdTeamInfo::SortPlayersFunc ================ */ int sdTeamInfo::SortPlayersFunc( const playerPtr_t* a, const playerPtr_t* b ) { return idMath::Ftoi( ( *b )->GetProficiencyTable().GetXP() ) - idMath::Ftoi( ( *a )->GetProficiencyTable().GetXP() ); } /* ================ sdTeamInfo::Think ================ */ void sdTeamInfo::Think( void ) { UpdateScript(); } /* ================ sdTeamInfo::UpdateScript ================ */ void sdTeamInfo::UpdateScript( void ) { if ( !scriptThread || gameLocal.IsPaused() ) { return; } // don't call script until it's done waiting if ( scriptThread->IsWaiting() ) { return; } scriptThread->Execute(); } /* ================ sdTeamInfo::OnNewMapLoad ================ */ void sdTeamInfo::OnNewMapLoad( void ) { Init(); } /* ================ sdTeamInfo::PointInRadar ================ */ idEntity* sdTeamInfo::PointInRadar( const idVec3& _target, radarMasks_t type, const idList< sdRadarLayer* >& list ) { int worldZoneIndex = gameLocal.GetWorldPlayZoneIndex( _target ); idVec2 target = _target.ToVec2(); for ( int index = 0; index < list.Num(); index++ ) { sdRadarLayer* layer = list[ index ]; idEntity* owner = layer->GetOwner(); if ( owner == NULL ) { gameLocal.Warning( "sdTeamInfo::PointInRadar radar layer with NULL owner" ); continue; } if ( ( layer->GetMask() & type ) == 0 ) { continue; } const idVec2& layerOrigin = layer->GetOrigin(); idVec2 currentDir = target - layerOrigin; float currentRange = currentDir.LengthSqr(); if ( currentRange > layer->GetRange() ) { continue; } float maxAngle = layer->GetMaxAngle(); if ( maxAngle < idMath::PI ) { currentDir.NormalizeFast(); float angle = idMath::ACos( currentDir * layer->GetDirection() ); if ( angle > maxAngle ) { continue; } } int radarZoneIndex = gameLocal.GetWorldPlayZoneIndex( idVec3( layerOrigin.x, layerOrigin.y, 0.f ) ); if ( radarZoneIndex != worldZoneIndex ) { return NULL; } return owner; } return NULL; } /* ================ sdTeamInfo::PointInJammer ================ */ idEntity* sdTeamInfo::PointInJammer( const idVec3& target, radarMasks_t type ) { return PointInRadar( target, type, jammerLayers ); } /* ================ sdTeamInfo::PointInRadar ================ */ idEntity* sdTeamInfo::PointInRadar( const idVec3& target, radarMasks_t type ) { return PointInRadar( target, type, radarLayers ); } /* ================ sdTeamInfo::RegisterDeployable ================ */ void sdTeamInfo::RegisterDeployable( idEntity* other ) { AddEntityToList( deployables, other ); } /* ================ sdTeamInfo::UnRegisterDeployable ================ */ void sdTeamInfo::UnRegisterDeployable( idEntity* other ) { RemoveEntityFromList( deployables, other ); } /* ================ sdTeamInfo::RegisterSpawnPoint ================ */ void sdTeamInfo::RegisterSpawnPoint( idEntity* other ) { idEntity* oldDefault = spawnLocations.Num() ? spawnLocations[ 0 ].GetEntity() : NULL; idStr priorityName = va( "spawn_priority_%s", lookupname.c_str() ); int otherPriority = other->spawnArgs.GetInt( priorityName ); int i; for ( i = 0; i < spawnLocations.Num(); ) { idEntity* loc = spawnLocations[ i ]; if ( !loc ) { spawnLocations.RemoveIndex( i ); continue; } int locPriority = loc->spawnArgs.GetInt( priorityName ); if ( locPriority < otherPriority ) { idEntityPtr< idEntity > temp = other; spawnLocations.Insert( temp, i ); break; } i++; } if ( i == spawnLocations.Num() ) { spawnLocations.Alloc() = other; } idEntity* newDefault = spawnLocations[ 0 ]; if ( oldDefault != newDefault ) { gameLocal.localPlayerProperties.OnDefaultSpawnChanged( this, newDefault ); } } /* ================ sdTeamInfo::UnRegisterSpawnPoint ================ */ void sdTeamInfo::UnRegisterSpawnPoint( idEntity* other ) { idEntity* oldDefault = spawnLocations.Num() ? spawnLocations[ 0 ].GetEntity() : NULL; RemoveEntityFromList( spawnLocations, other ); idEntity* newDefault = spawnLocations.Num() ? spawnLocations[ 0 ].GetEntity() : NULL; for ( int i = 0; i < MAX_CLIENTS; i++ ) { idPlayer* player = gameLocal.GetClient( i ); if ( !player || !player->IsTeam( this ) ) { continue; } if ( player->GetSpawnPoint() == other ) { player->SetSpawnPoint( NULL ); } } if ( oldDefault != newDefault ) { gameLocal.localPlayerProperties.OnDefaultSpawnChanged( this, newDefault ); } if ( other == rearSpawnBase.GetEntity() ) { rearSpawnBase = NULL; } } /* ================ sdTeamInfo::ApplyNetworkState ================ */ void sdTeamInfo::ApplyNetworkState( const sdTeamInfoGameState& newData ) { // update state wins = newData.wins; scriptObject->ApplyNetworkState( NSM_BROADCAST, newData.scriptData ); } /* ================ sdTeamInfo::ReadNetworkState ================ */ void sdTeamInfo::ReadNetworkState( const sdTeamInfoGameState& baseData, sdTeamInfoGameState& newData, const idBitMsg& msg ) const { // read state newData.wins = msg.ReadDeltaLong( baseData.wins ); scriptObject->ReadNetworkState( NSM_BROADCAST, baseData.scriptData, newData.scriptData, msg ); } /* ================ sdTeamInfo::WriteNetworkState ================ */ void sdTeamInfo::WriteNetworkState( const sdTeamInfoGameState& baseData, sdTeamInfoGameState& newData, idBitMsg& msg ) const { // update state newData.wins = wins; // write state msg.WriteDeltaLong( baseData.wins, newData.wins ); scriptObject->WriteNetworkState( NSM_BROADCAST, baseData.scriptData, newData.scriptData, msg ); } /* ================ sdTeamInfo::CheckNetworkStateChanges ================ */ bool sdTeamInfo::CheckNetworkStateChanges( const sdTeamInfoGameState& baseData ) const { if ( scriptObject->CheckNetworkStateChanges( NSM_BROADCAST, baseData.scriptData ) ) { return true; } return ( baseData.wins != wins ); } /* ================ sdTeamInfo::CanJoin ================ */ bool sdTeamInfo::CanJoin( idPlayer* player, const char* password, const sdDeclLocStr*& reason ) const { if ( player->IsType( idBot::Type ) ) { return true; } if ( passwordCVar != NULL ) { const char* passwordString = passwordCVar->GetString(); if ( *passwordString != '\0' ) { if ( idStr::Cmp( passwordString, password ) ) { reason = declHolder.declLocStrType[ "teams/messages/wrongpassword" ]; return false; } } } return true; } /* ================ sdTeamInfo::OnNewScriptLoad ================ */ void sdTeamInfo::OnNewScriptLoad( void ) { const char* scriptObjectName = info->GetDict().GetString( "scriptObject", "default" ); scriptObject = gameLocal.program->AllocScriptObject( this, scriptObjectName ); allowRespawnFunc = scriptObject->GetFunction( "OnAllowRespawn" ); teamNextRespawnTimeFunc = scriptObject->GetFunction( "GetNextRespawnTime" ); sdScriptHelper h1; scriptObject->CallNonBlockingScriptEvent( scriptObject->GetPreConstructor(), h1 ); sdScriptHelper h2; scriptObject->CallNonBlockingScriptEvent( scriptObject->GetSyncFunc(), h2 ); const sdProgram::sdFunction* constructor = scriptObject->GetConstructor(); if ( constructor ) { scriptThread = gameLocal.program->CreateThread(); scriptThread->SetName( "sdTeamInfo" ); scriptThread->CallFunction( scriptObject, constructor ); scriptThread->ManualControl(); scriptThread->ManualDelete(); } } /* ================ sdTeamInfo::OnMapStart ================ */ void sdTeamInfo::OnMapStart( void ) { assert( scriptObject ); sdScriptHelper h1; scriptObject->CallNonBlockingScriptEvent( scriptObject->GetFunction( "OnMapStart" ), h1 ); } /* ================ sdTeamInfo::Event_GetName ================ */ void sdTeamInfo::Event_GetName( void ) { sdProgram::ReturnString( lookupname ); } /* ================ sdTeamInfo::Event_GetTitle ================ */ void sdTeamInfo::Event_GetTitle( void ) { sdProgram::ReturnHandle( title->Index() ); } /* ================ sdTeamInfo::Event_RegisterDeployable ================ */ void sdTeamInfo::Event_RegisterDeployable( idEntity* other ) { RegisterDeployable( other ); } /* ================ sdTeamInfo::Event_UnRegisterDeployable ================ */ void sdTeamInfo::Event_UnRegisterDeployable( idEntity* other ) { UnRegisterDeployable( other ); } /* =============== sdTeamInfo::Event_RegisterSpawnPoint =============== */ void sdTeamInfo::Event_RegisterSpawnPoint( idEntity* other ) { RegisterSpawnPoint( other ); } /* =============== sdTeamInfo::Event_UnRegisterSpawnPoint =============== */ void sdTeamInfo::Event_UnRegisterSpawnPoint( idEntity* other ) { UnRegisterSpawnPoint( other ); } /* ================ sdTeamInfo::Event_SyncScriptFieldBroadcast ================ */ void sdTeamInfo::Event_SyncScriptFieldBroadcast( const char* fieldName ) { scriptObject->SetSynced( fieldName, true ); } /* ================ sdTeamInfo::Event_SyncScriptFieldCallback ================ */ void sdTeamInfo::Event_SyncScriptFieldCallback( const char* fieldName, const char* functionName ) { scriptObject->SetSyncCallback( fieldName, functionName ); } class sdFireTeam_InitialCreateFinaliser : public sdVoteFinalizer { public: sdFireTeam_InitialCreateFinaliser( idPlayer* player ) : _player( player ) { } virtual ~sdFireTeam_InitialCreateFinaliser( void ) { } virtual void OnVoteCompleted( bool passed ) const { if ( passed ) { idPlayer* player = _player; if ( player ) { sdTeamInfo* team = player->GetTeam(); if ( team ) { team->CreatePublicFireTeam( player ); } else { assert( false ); } } } } private: idEntityPtr< idPlayer > _player; }; class sdFireTeam_InitialJoinFinaliser : public sdVoteFinalizer { public: sdFireTeam_InitialJoinFinaliser( idPlayer* player, sdFireTeam* fireTeam ) : _fireTeam( fireTeam ), _player( player ) { } virtual ~sdFireTeam_InitialJoinFinaliser( void ) { } virtual void OnVoteCompleted( bool passed ) const { if ( passed ) { idPlayer* player = _player; if ( player ) { _fireTeam->AddMember( player->entityNumber ); } } } private: sdFireTeam* _fireTeam; idEntityPtr< idPlayer > _player; }; /* ================ sdTeamInfo::CreatePrivateFireTeam ================ */ void sdTeamInfo::CreatePrivateFireTeam( idPlayer* player ) { for ( int i = 0; i < MAX_FIRETEAMS; i++ ) { if ( fireTeams[ i ].GetNumMembers() == 0 ) { fireTeams[ i ].AddMember( player->entityNumber ); fireTeams[ i ].SetPrivate( true ); return; } } player->SendLocalisedMessage( declHolder.declLocStrType[ "fireteam/messages/noneleft" ], idWStrList() ); } /* ================ sdTeamInfo::CreatePublicFireTeam ================ */ bool sdTeamInfo::CreatePublicFireTeam( idPlayer* player ) { for ( int i = 0; i < MAX_FIRETEAMS; i++ ) { if ( fireTeams[ i ].GetNumMembers() == 0 ) { fireTeams[ i ].AddMember( player->entityNumber ); fireTeams[ i ].SetPrivate( false ); return true; } } return false; } /* ================ sdTeamInfo::TryFindPrivateFireTeam ================ */ void sdTeamInfo::TryFindPrivateFireTeam( idPlayer* player ) { for ( int i = 0; i < MAX_FIRETEAMS; i++ ) { if ( fireTeams[ i ].GetNumMembers() == 0 ) { sdPlayerVote* vote = sdVoteManager::GetInstance().AllocVote(); if ( !vote ) { return; } vote->DisableFinishMessage(); vote->MakePrivateVote( player ); vote->Tag( VI_FIRETEAM_CREATE, player ); vote->SetText( gameLocal.declToolTipType[ "fireteam_initial_create" ] ); vote->SetFinalizer( new sdFireTeam_InitialCreateFinaliser( player ) ); vote->Start(); return; } else if ( !fireTeams[ i ].IsPrivate() && fireTeams[ i ].GetNumMembers() != sdFireTeam::MaxMembers() ) { sdPlayerVote* vote = sdVoteManager::GetInstance().AllocVote(); if ( !vote ) { return; } vote->DisableFinishMessage(); vote->MakePrivateVote( player ); vote->Tag( VI_FIRETEAM_JOIN, player ); vote->SetText( gameLocal.declToolTipType[ "fireteam_initial_join" ] ); vote->SetFinalizer( new sdFireTeam_InitialJoinFinaliser( player, &fireTeams[ i ] ) ); vote->Start(); return; } } } /* ================ sdTeamInfo::Event_GetKey ================ */ void sdTeamInfo::Event_GetKey( const char *key ) { sdProgram::ReturnString( GetDict().GetString( key ) ); } /* ================ sdTeamInfo::Event_GetIntKey ================ */ void sdTeamInfo::Event_GetIntKey( const char *key ) { sdProgram::ReturnInteger( GetDict().GetInt( key ) ); } /* ================ sdTeamInfo::Event_GetFloatKey ================ */ void sdTeamInfo::Event_GetFloatKey( const char *key ) { sdProgram::ReturnFloat( GetDict().GetFloat( key ) ); } /* ================ sdTeamInfo::Event_GetVectorKey ================ */ void sdTeamInfo::Event_GetVectorKey( const char *key ) { sdProgram::ReturnVector( GetDict().GetVector( key ) ); } /* ================ sdTeamInfo::Event_GetKeyWithDefault ================ */ void sdTeamInfo::Event_GetKeyWithDefault( const char *key, const char* defaultvalue ) { sdProgram::ReturnString( GetDict().GetString( key, defaultvalue ) ); } /* ================ sdTeamInfo::Event_GetIntKeyWithDefault ================ */ void sdTeamInfo::Event_GetIntKeyWithDefault( const char *key, int defaultvalue ) { sdProgram::ReturnFloat( GetDict().GetInt( key, va( "%i", defaultvalue ) ) ); } /* ================ sdTeamInfo::Event_GetFloatKeyWithDefault ================ */ void sdTeamInfo::Event_GetFloatKeyWithDefault( const char *key, float defaultvalue ) { sdProgram::ReturnFloat( GetDict().GetFloat( key, va( "%f", defaultvalue ) ) ); } /* ================ sdTeamInfo::Event_GetVectorKeyWithDefault ================ */ void sdTeamInfo::Event_GetVectorKeyWithDefault( const char *key, const idVec3& defaultvalue ) { sdProgram::ReturnVector( GetDict().GetVector( key, defaultvalue.ToString() ) ); } /* ================ sdTeamInfo::Event_SetTeamRearSpawn ================ */ void sdTeamInfo::Event_SetTeamRearSpawn( idEntity* teamRearSpawnBase ) { rearSpawnBase = teamRearSpawnBase; } /* ============ sdTeamInfo::GetEquivalentClass ============ */ const sdDeclPlayerClass* sdTeamInfo::GetEquivalentClass( const sdDeclPlayerClass& currentClass, const sdTeamInfo& desiredTeam ) const { if( this == &desiredTeam ) { return ¤tClass; } const idDict& dict = desiredTeam.GetDict(); idStr key = va( "pc_team_remap_%s_%s", GetLookupName(), currentClass.GetName() ); const char* remappedClass = dict.GetString( key, "" ); if( idStr::Length( remappedClass ) == 0 ) { return ¤tClass; } return gameLocal.declPlayerClassType.LocalFind( remappedClass, false ); } /* ============ sdTeamInfo::AllocRadarLayer ============ */ sdTeamInfo::sdRadarLayer* sdTeamInfo::AllocRadarLayer( void ) { sdRadarLayer* newLayer = radarAllocator.Alloc(); radarLayers.Alloc() = newLayer; return newLayer; } /* ============ sdTeamInfo::AllocJammerLayer ============ */ sdTeamInfo::sdRadarLayer* sdTeamInfo::AllocJammerLayer( void ) { sdRadarLayer* newLayer = radarAllocator.Alloc(); jammerLayers.Alloc() = newLayer; return newLayer; } /* ============ sdTeamInfo::FreeRadarLayer ============ */ void sdTeamInfo::FreeRadarLayer( sdRadarLayer* layer ) { int index; index = radarLayers.FindIndex( layer ); if ( index != -1 ) { radarLayers.RemoveIndexFast( index ); radarAllocator.Free( layer ); return; } index = jammerLayers.FindIndex( layer ); if ( index != -1 ) { jammerLayers.RemoveIndexFast( index ); radarAllocator.Free( layer ); return; } } /* ============ sdTeamInfo::GetRating ============ */ const sdDeclRating* sdTeamInfo::GetRating( int index ) const { if ( index < 0 || ratings.Num() <= 0 ) { return NULL; } if ( index >= ratings.Num() ) { return ratings[ ratings.Num() - 1 ]; } return ratings[ index ]; } /* ============ sdTeamInfo::GetNumPlayers ============ */ int sdTeamInfo::GetNumPlayers( bool excludeBots ) const { int count = 0; for ( int i = 0; i < MAX_CLIENTS; i++ ) { idPlayer* player = gameLocal.GetClient( i ); if ( player == NULL ) { continue; } if ( player->GetGameTeam() != this ) { continue; } if ( excludeBots ) { if ( player->IsType( idBot::Type ) ) { continue; } } count++; } return count; } /* ============ sdTeamInfo::GetTotalXP ============ */ float sdTeamInfo::GetTotalXP( void ) const { float total = 0; for ( int i = 0; i < MAX_CLIENTS; i++ ) { idPlayer* player = gameLocal.GetClient( i ); if ( player == NULL ) { continue; } if ( player->GetGameTeam() != this ) { continue; } total += player->GetProficiencyTable().GetXP(); } return total; } /* ============ sdTeamInfo::GetHomeBaseSpawn ============ */ idEntity* sdTeamInfo::GetHomeBaseSpawn( void ) { if ( rearSpawnBase == NULL ) { //mal: oops - someone didn't set us up! if ( bot_debug.GetBool() ) { gameLocal.DWarning("Bot Team %s has no valid Rear Spawn Set!", ( botTeam == GDF ) ? "GDF" : "STROGG" ); } } return rearSpawnBase; } /* ============ sdTeamInfo::GetLifeStatTitle ============ */ const sdDeclLocStr* sdTeamInfo::GetLifeStatTitle( void ) const { return lifeStatTitle; }