// 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 "Tasks.h" #include "../Player.h" #include "../interfaces/TaskInterface.h" #include "../script/Script_Helper.h" #include "../script/Script_ScriptObject.h" #include "../roles/WayPointManager.h" #include "FireTeams.h" #include "../rules/GameRules.h" #include "../rules/VoteManager.h" /* =============================================================================== sdPlayerTask =============================================================================== */ const idEventDef EV_PlayerTask_Complete( "complete", '\0', DOC_TEXT( "Marks the task as complete, and gives any bonus associated with it to players on it." ), 0, NULL ); const idEventDef EV_PlayerTask_SetTimeout( "setTimeout", '\0', DOC_TEXT( "Marks the task to auto free itself once the timeout has expired." ), 1, "Timeouts do not apply to mission or objective level tasks.", "f", "timeout", "Timeout in seconds." ); const idEventDef EV_PlayerTask_Free( "free", '\0', DOC_TEXT( "Removes the task." ), 0, "This does the same as $event:remove$." ); const idEventDef EV_PlayerTask_SetUserCreated( "setUserCreated", '\0', DOC_TEXT( "Marks a task as user created, this will demote it to task level from whatever its current level is." ), 0, NULL ); const idEventDef EV_PlayerTask_IsUserCreated( "isUserCreated", 'b', DOC_TEXT( "Returns whether the task has been marked as user created or not." ), 0, NULL ); const idEventDef EV_PlayerTask_GetTaskEntity( "getTaskEntity", 'e', DOC_TEXT( "Returns the entity associated with this task." ), 0, NULL ); const idEventDef EV_PlayerTask_SetTargetPos( "setLocation", '\0', DOC_TEXT( "Sets a fixed location for the specified task waypoint." ), 2, NULL, "d", "index", "Index of the waypoint.", "v", "position", "Fixed position for the waypoint." ); const idEventDef EV_PlayerTask_SetWayPointState( "setWayPointState", '\0', DOC_TEXT( "Sets the visibility state for the specified task waypoint." ), 2, NULL, "d", "index", "Index of the waypoint.", "b", "state", "State to set." ); const idEventDef EV_PlayerTask_GiveObjectiveProficiency( "giveObjectiveProficiency", '\0', DOC_TEXT( "Gives class XP to all players elligible for the task." ), 2, NULL, "f", "count", "Amount of XP to give.", "s", "reason", "Reason to record in log." ); const idEventDef EV_PlayerTask_FlashIcon( "flashWorldIcon", '\0', DOC_TEXT( "Flash the icon for a set time." ), 1, NULL, "d", "time", "Time to flash in milliseconds." ); CLASS_DECLARATION( idClass, sdPlayerTask ) EVENT( EV_PlayerTask_Complete, sdPlayerTask::Event_Complete ) EVENT( EV_PlayerTask_SetTimeout, sdPlayerTask::Event_SetTimeout ) EVENT( EV_PlayerTask_Free, sdPlayerTask::Event_Free ) EVENT( EV_SafeRemove, sdPlayerTask::Event_Free ) // Gordon: Also handle remove nicely, in case people use it EVENT( EV_PlayerTask_SetUserCreated, sdPlayerTask::Event_SetUserCreated ) EVENT( EV_PlayerTask_IsUserCreated, sdPlayerTask::Event_IsUserCreated ) EVENT( EV_PlayerTask_GetTaskEntity, sdPlayerTask::Event_GetTaskEntity ) EVENT( EV_PlayerTask_SetTargetPos, sdPlayerTask::Event_SetTargetPos ) EVENT( EV_PlayerTask_SetWayPointState, sdPlayerTask::Event_SetWayPointState ) EVENT( EV_GetKey, sdPlayerTask::Event_GetKey ) EVENT( EV_GetIntKey, sdPlayerTask::Event_GetIntKey ) EVENT( EV_GetFloatKey, sdPlayerTask::Event_GetFloatKey ) EVENT( EV_GetVectorKey, sdPlayerTask::Event_GetVectorKey ) EVENT( EV_GetKeyWithDefault, sdPlayerTask::Event_GetKeyWithDefault ) EVENT( EV_GetIntKeyWithDefault, sdPlayerTask::Event_GetIntKeyWithDefault ) EVENT( EV_GetFloatKeyWithDefault, sdPlayerTask::Event_GetFloatKeyWithDefault ) EVENT( EV_GetVectorKeyWithDefault, sdPlayerTask::Event_GetVectorKeyWithDefault ) EVENT( EV_PlayerTask_GiveObjectiveProficiency, sdPlayerTask::Event_GiveObjectiveProficiency ) EVENT( EV_PlayerTask_FlashIcon, sdPlayerTask::Event_FlashIcon ) END_CLASS /* ================ sdPlayerTask::sdPlayerTask ================ */ sdPlayerTask::sdPlayerTask( void ) : _taskInfo( NULL ), _flags( 0 ), _endTime( -1 ), _scriptObject( NULL ), _xp( 0.0f ), _wayPointEnabled( false ) { _node.SetOwner( this ); _worldNode.SetOwner( this ); _objectiveNode.SetOwner( this ); } /* ================ sdPlayerTask::Create ================ */ void sdPlayerTask::Create( int taskIndex, const sdDeclPlayerTask* taskInfo ) { _creationTime = gameLocal.time; _taskInfo = taskInfo; _taskIndex = taskIndex; _xp = _taskInfo->GetData().GetFloat( "xp" ); _wayPointEnabled = false; if ( taskInfo->IsTask() ) { _flags |= TF_USERCREATED; } _wayPointInfo.SetNum( Min( taskInfo->GetNumWayPoints(), MAX_WAYPOINTS ) ); for ( int i = 0; i < _wayPointInfo.Num(); i++ ) { _wayPointInfo[ i ].fixed = false; _wayPointInfo[ i ].enabled = true; _wayPointInfo[ i ].offset.Zero(); _wayPointInfo[ i ].wayPoint = NULL; } _scriptObject = gameLocal.program->AllocScriptObject( this, taskInfo->GetScriptObject() ); sdScriptHelper h1; _scriptObject->CallNonBlockingScriptEvent( _scriptObject->GetPreConstructor(), h1 ); } /* ================ sdPlayerTask::SetEntity ================ */ void sdPlayerTask::SetEntity( int spawnId ) { _entity.ForceSpawnId( spawnId ); } /* ================ sdPlayerTask::~sdPlayerTask ================ */ sdPlayerTask::~sdPlayerTask( void ) { if ( _scriptObject ) { sdScriptHelper h1; _scriptObject->CallNonBlockingScriptEvent( _scriptObject->GetDestructor(), h1 ); gameLocal.program->FreeScriptObject( _scriptObject ); } HideWayPoint(); if ( gameLocal.isServer ) { sdTaskMessage msg( this, TM_REMOVE ); msg.Send( sdReliableMessageClientInfoAll() ); } } /* ================ sdPlayerTask::Think ================ */ void sdPlayerTask::Think( void ) { for ( int i = 0; i < _wayPointInfo.Num(); i++ ) { if ( _wayPointInfo[ i ].wayPoint == NULL ) { continue; } _wayPointInfo[ i ].wayPoint->SetText( GetTitle() ); } } /* ================ sdPlayerTask::GetHandle ================ */ taskHandle_t sdPlayerTask::GetHandle( void ) const { return _taskIndex; } /* ================ sdPlayerTask::GetTimeLimit ================ */ const char* sdPlayerTask::GetTimeLimit( void ) const { int limit = _taskInfo->GetTimeLimit(); if ( limit <= 0 ) { return idStr::MS2HMS( gameLocal.rules->GetGameTime() ); } int ms = limit - ( gameLocal.time - _creationTime ); return idStr::MS2HMS( ms ); } /* ================ sdPlayerTask::UpdateObjectiveWayPoint ================ */ void sdPlayerTask::UpdateObjectiveWayPoint( void ) { idPlayer* localPlayer = gameLocal.GetLocalPlayer(); if ( localPlayer == NULL ) { return; } sdTeamInfo* team = localPlayer->GetGameTeam(); if ( team == NULL || team != _taskInfo->GetTeam() ) { HideWayPoint(); } else { ShowWayPoint(); } } /* ============ sdPlayerTask::GetXP ============ */ float sdPlayerTask::GetXP() const { return _xp; } /* ================ sdPlayerTask::ShowWayPoint ================ */ void sdPlayerTask::ShowWayPoint( void ) { _wayPointEnabled = true; for ( int i = 0; i < _wayPointInfo.Num(); i++ ) { ShowWayPoint( i ); } } /* ================ sdPlayerTask::ShowWayPoint ================ */ void sdPlayerTask::ShowWayPoint( int i ) { if ( _wayPointInfo[ i ].wayPoint != NULL ) { return; } if ( !_wayPointInfo[ i ].enabled ) { return; } const idDict& waypointData = _taskInfo->GetWayPointData( i ); const char* materialName; const char* offScreenMaterialName; if ( IsUserCreated() ) { materialName = waypointData.GetString( "mtr_user_waypoint" ); offScreenMaterialName = waypointData.GetString( "mtr_user_waypoint_offscreen" ); } else { materialName = waypointData.GetString( "mtr_waypoint" ); offScreenMaterialName = waypointData.GetString( "mtr_waypoint_offscreen" ); } const idMaterial* material = gameLocal.declMaterialType[ materialName ]; if ( material == NULL ) { gameLocal.Warning( "sdPlayerTask::ShowWayPoint Invalid Material '%s'", materialName ); return; } const idMaterial* offScreenMaterial = gameLocal.declMaterialType[ offScreenMaterialName ]; if ( offScreenMaterial == NULL ) { gameLocal.Warning( "sdPlayerTask::ShowWayPoint Invalid Offscreen Material '%s'", offScreenMaterialName ); return; } sdWayPoint* wayPoint = sdWayPointManager::GetInstance().AllocWayPoint(); if ( wayPoint == NULL ) { return; } _wayPointInfo[ i ].wayPoint = wayPoint; if ( _wayPointInfo[ i ].fixed ) { wayPoint->SetOrigin( _wayPointInfo[ i ].offset ); } wayPoint->SetOwner( _entity ); wayPoint->SetMinRange( waypointData.GetFloat( "min_range", "320" ) ); wayPoint->SetMaterial( material ); wayPoint->SetOffScreenMaterial( offScreenMaterial ); if ( IsUserCreated() ) { float range; if ( waypointData.GetFloat( "range", "", range ) ) { wayPoint->SetRange( range ); } } else { wayPoint->SetAlwaysActive(); } if ( waypointData.GetBool( "team_colored" ) ) { wayPoint->SetTeamColored(); } if ( IsObjective() || IsMission() || _taskInfo->NoOcclusion() ) { wayPoint->SetCheckLineOfSight( false ); } wayPoint->SetBracketed( waypointData.GetBool( "bracketed" ) ); if ( waypointData.GetBool( "bracket_use_rendermodel" ) ) { wayPoint->UseRenderModel(); } idVec3 mins, maxs; if ( waypointData.GetVector( "bracket_mins", NULL, mins ) && waypointData.GetVector( "bracket_maxs", NULL, maxs ) ) { wayPoint->SetBounds( idBounds( mins, maxs ) ); } } /* ================ sdPlayerTask::HideWayPoint ================ */ void sdPlayerTask::HideWayPoint( void ) { _wayPointEnabled = false; for ( int i = 0; i < _wayPointInfo.Num(); i++ ) { HideWayPoint( i ); } } /* ================ sdPlayerTask::HideWayPoint ================ */ void sdPlayerTask::HideWayPoint( int i ) { if ( _wayPointInfo[ i ].wayPoint == NULL ) { return; } sdWayPointManager::GetInstance().FreeWayPoint( _wayPointInfo[ i ].wayPoint ); _wayPointInfo[ i ].wayPoint = NULL; } /* ================ sdPlayerTask::ProcessTitle ================ */ idWStr& sdPlayerTask::ProcessTitle( const wchar_t* text, idWStr& output ) const { output.Empty(); const wchar_t* p = text; while ( *p ) { if ( *p == L'%' ) { p++; if( !*p ) { break; } switch ( *p ) { case L'%': output += L'%'; p++; break; case L'r': { idEntity* other = GetEntity(); idPlayer* player = gameLocal.GetLocalPlayer(); if ( !other || !player ) { output += L"???"; } else { float range = idMath::Sqrt( gameLocal.RangeSquare( player, other ) ); output += va( L"%im", ( int )( InchesToMetres( range ) ) ); } p++; break; } case L'n': { idEntity* other = GetEntity(); if ( other ) { idWStr name; other->GetTaskName( name ); output += name; } p++; break; } case L'm': { idWStr timeLimit( va( L"%hs", GetTimeLimit() ) ); timeLimit += L" "; if ( timeLimit.Find( L':' ) != idWStr::INVALID_POSITION ) { timeLimit += common->LocalizeText( "game/tasks/min" ); } else { timeLimit += common->LocalizeText( "game/tasks/sec" ); } output += timeLimit; p++; break; } default: output += L'%'; break; } } else { output += *p; p++; } } return output; } /* ================ sdPlayerTask::GetTitle ================ */ const wchar_t* sdPlayerTask::GetTitle( idPlayer* player ) const { const sdDeclLocStr* title = NULL; if ( IsObjective() ) { title = _taskInfo->GetFriendlyTitle(); if ( player == NULL ) { player = gameLocal.GetLocalPlayer(); } if ( player != NULL ) { if ( IsPlayerEligible( player ) ) { title = _taskInfo->GetTitle(); } } } else { title = _taskInfo->GetTitle(); } if ( title == NULL ) { return L""; } return ProcessTitle( title->GetText(), _titleBuffer ).c_str(); } /* ================ sdPlayerTask::GetCompletedTitle ================ */ const wchar_t* sdPlayerTask::GetCompletedTitle( idPlayer* player ) const { const sdDeclLocStr* title = NULL; if ( IsObjective() ) { if( player == NULL ) { player = gameLocal.GetLocalPlayer(); } if ( player != NULL ) { if ( IsPlayerEligible( player ) ) { title = _taskInfo->GetCompletedTitle(); } else { title = _taskInfo->GetCompletedFriendlyTitle(); } } } else { title = _taskInfo->GetCompletedTitle(); } if ( title == NULL ) { return L""; } return ProcessTitle( title->GetText(), _titleBuffer ).c_str(); } /* ================ sdPlayerTask::SetWayPointState ================ */ bool sdPlayerTask::SetWayPointState( int index, bool state ) { if ( index < 0 || index >= _wayPointInfo.Num() ) { gameLocal.Warning( "sdPlayerTask::SetWayPointState Index Out Of Range" ); return false; } if ( _wayPointInfo[ index ].enabled == state ) { return false; } _wayPointInfo[ index ].enabled = state; if ( state ) { if ( _wayPointEnabled ) { ShowWayPoint( index ); } } else { HideWayPoint( index ); } return true; } /* ================ sdPlayerTask::SetTargetPos ================ */ bool sdPlayerTask::SetTargetPos( int index, const idVec3& target ) { if ( index < 0 || index >= _wayPointInfo.Num() ) { gameLocal.Warning( "sdPlayerTask::SetTargetPos Index Out Of Range" ); return false; } _wayPointInfo[ index ].fixed = true; _wayPointInfo[ index ].offset = target; if ( _wayPointInfo[ index ].wayPoint != NULL ) { _wayPointInfo[ index ].wayPoint->SetOrigin( target ); } return true; } /* ================ sdPlayerTask::SetComplete ================ */ void sdPlayerTask::SetComplete( void ) { if ( IsComplete() ) { return; } idPlayer* localPlayer = gameLocal.GetLocalPlayer(); if ( localPlayer != NULL ) { if ( localPlayer->GetActiveTaskHandle() == GetHandle() ) { gameLocal.localPlayerProperties.OnTaskCompleted( this ); } else if ( IsObjective() ) { if ( _taskInfo->GetTeam() == localPlayer->GetGameTeam() ) { gameLocal.localPlayerProperties.OnTaskCompleted( this ); } } } _flags |= TF_COMPLETE; if ( !gameLocal.isClient ) { sdProficiencyManager::GetInstance().GiveMissionProficiency( this, GetInfo()->GetXPBonus() ); } if ( gameLocal.isServer ) { sdTaskMessage msg( this, TM_COMPLETE ); msg.Send( sdReliableMessageClientInfoAll() ); } } /* ================ sdPlayerTask::SetUserCreated ================ */ void sdPlayerTask::SetUserCreated( void ) { if ( IsUserCreated() ) { return; } _flags |= TF_USERCREATED; if ( gameLocal.isServer ) { sdTaskMessage msg( this, TM_USER_CREATED ); msg.Send( sdReliableMessageClientInfoAll() ); } } /* ================ sdPlayerTask::SetTimeout ================ */ void sdPlayerTask::SetTimeout( int duration ) { _endTime = gameLocal.time + duration; } /* ================ sdPlayerTask::IsAvailable ================ */ bool sdPlayerTask::IsAvailable( idPlayer* player ) const { if ( _flags & TF_COMPLETE || IsUserCreated() || IsObjective() || !IsPlayerEligible( player ) ) { return false; } return true; } /* ================ sdPlayerTask::OnPlayerJoined ================ */ void sdPlayerTask::OnPlayerJoined( idPlayer* player ) { *_players.Alloc() = player; } /* ================ sdPlayerTask::OnPlayerLeft ================ */ void sdPlayerTask::OnPlayerLeft( idPlayer* player ) { _players.Remove( player ); } /* ============ sdPlayerTask::SelectWayPoints ============ */ void sdPlayerTask::SelectWayPoints( int time ) { for( int i = 0; i < _wayPointInfo.Num(); i++ ) { if( _wayPointInfo[ i ].wayPoint != NULL ) { _wayPointInfo[ i ].wayPoint->SetSelected( time ); } } } /* ================ sdPlayerTask::IsPlayerEligible ================ */ bool sdPlayerTask::IsPlayerEligible( idPlayer* player ) const { return _taskInfo->GetEligibility().Check( player, _entity ); } /* ================ sdPlayerTask::HandleMessage ================ */ void sdPlayerTask::HandleMessage( taskMessageType_t type, const idBitMsg& msg ) { switch ( type ) { case TM_USER_CREATED: { SetUserCreated(); break; } case TM_COMPLETE: { SetComplete(); break; } case TM_SETLOCATIION: { int index = msg.ReadLong(); idVec3 location = msg.ReadVector(); SetTargetPos( index, location ); break; } case TM_VISSTATE: { int index = msg.ReadLong(); bool state = msg.ReadBool(); SetWayPointState( index, state ); break; } default: { gameLocal.Error( "sdPlayerTask::HandleMessage Invalid Message Type '%i'", type ); break; } } } /* ================ sdPlayerTask::HandleMessage ================ */ void sdPlayerTask::HandleMessage( const idBitMsg& msg ) { if ( gameLocal.isServer ) { return; // listen servers should ignore these } taskMessageType_t type = ( taskMessageType_t )msg.ReadBits( idMath::BitsForInteger( TM_NUM_MESSAGES ) ); taskHandle_t handle = msg.ReadBits( sdPlayerTask::TASK_BITS ); switch ( type ) { case TM_FULLSTATE: { int taskInfoIndex = msg.ReadBits( idMath::BitsForInteger( gameLocal.declPlayerTaskType.Num() ) ); int spawnId = msg.ReadLong(); sdTaskManager::GetInstance().AllocTask( handle, gameLocal.declPlayerTaskType[ taskInfoIndex ], spawnId ); sdPlayerTask* task = sdTaskManager::GetInstance().TaskForHandle( handle ); assert( task ); task->ReadInitialState( msg ); break; } case TM_CREATE: { int taskInfoIndex = msg.ReadBits( idMath::BitsForInteger( gameLocal.declPlayerTaskType.Num() ) ); int spawnId = msg.ReadLong(); sdTaskManager::GetInstance().AllocTask( handle, gameLocal.declPlayerTaskType[ taskInfoIndex ], spawnId ); break; } case TM_REMOVE: { sdTaskManager::GetInstance().FreeTask( handle ); break; } default: { sdPlayerTask* task = sdTaskManager::GetInstance().TaskForHandle( handle ); if ( task ) { task->HandleMessage( type, msg ); } else { gameLocal.Warning( "sdPlayerTask::HandleMessage Received Message for Un-allocated task" ); } } } } /* ================ sdPlayerTask::Write ================ */ void sdPlayerTask::Write( idFile* file ) const { file->WriteInt( GetHandle() ); file->WriteInt( _taskInfo->Index() ); file->WriteInt( _entity.GetSpawnId() ); file->WriteInt( _flags ); int count = _wayPointInfo.Num(); file->WriteInt( count ); for ( int i = 0; i < count; i++ ) { file->WriteBool( _wayPointInfo[ i ].enabled ); file->WriteBool( _wayPointInfo[ i ].fixed ); file->WriteVec3( _wayPointInfo[ i ].offset ); } } /* ================ sdPlayerTask::Read ================ */ void sdPlayerTask::Read( idFile* file ) { int handle; file->ReadInt( handle ); int taskInfoIndex; file->ReadInt( taskInfoIndex ); int spawnId; file->ReadInt( spawnId ); sdTaskManager::GetInstance().AllocTask( handle, gameLocal.declPlayerTaskType[ taskInfoIndex ], spawnId ); sdPlayerTask* task = sdTaskManager::GetInstance().TaskForHandle( handle ); assert( task ); task->ReadInitialState( file ); } /* ================ sdPlayerTask::WriteInitialState ================ */ void sdPlayerTask::WriteInitialState( const sdReliableMessageClientInfoBase& target ) const { sdTaskMessage msg( this, TM_FULLSTATE ); msg.WriteBits( _taskInfo->Index(), idMath::BitsForInteger( gameLocal.declPlayerTaskType.Num() ) ); msg.WriteLong( _entity.GetSpawnId() ); msg.WriteBits( _flags, NUM_TASKFLAGS ); for ( int i = 0; i < _wayPointInfo.Num(); i++ ) { msg.WriteBool( _wayPointInfo[ i ].fixed ); msg.WriteBool( _wayPointInfo[ i ].enabled ); if ( _wayPointInfo[ i ].fixed ) { msg.WriteVector( _wayPointInfo[ i ].offset ); } } msg.Send( target ); } /* ================ sdPlayerTask::ReadInitialState ================ */ void sdPlayerTask::ReadInitialState( const idBitMsg& msg ) { _flags = msg.ReadBits( NUM_TASKFLAGS ); for ( int i = 0; i < _wayPointInfo.Num(); i++ ) { _wayPointInfo[ i ].fixed = msg.ReadBool(); _wayPointInfo[ i ].enabled = msg.ReadBool(); if ( _wayPointInfo[ i ].fixed ) { _wayPointInfo[ i ].offset = msg.ReadVector(); } } } /* ================ sdPlayerTask::ReadInitialState ================ */ void sdPlayerTask::ReadInitialState( idFile* file ) { file->ReadInt( _flags ); int count; file->ReadInt( count ); _wayPointInfo.SetNum( count ); for ( int i = 0; i < count; i++ ) { file->ReadBool( _wayPointInfo[ i ].enabled ); file->ReadBool( _wayPointInfo[ i ].fixed ); file->ReadVec3( _wayPointInfo[ i ].offset ); } } /* ================ sdPlayerTask::FlashIcon ================ */ void sdPlayerTask::FlashIcon( int time ) { for ( int i = 0; i < _wayPointInfo.Num(); i++ ) { if ( _wayPointInfo[ i ].wayPoint != NULL ) { _wayPointInfo[ i ].wayPoint->SetFlashEndTime( gameLocal.ToGuiTime( gameLocal.time ) + time ); } } } /* ================ sdPlayerTask::Event_Complete ================ */ void sdPlayerTask::Event_Complete( void ) { if ( gameLocal.isClient ) { assert( false ); return; } SetComplete(); } /* ================ sdPlayerTask::Event_SetTimeout ================ */ void sdPlayerTask::Event_SetTimeout( float duration ) { if ( gameLocal.isClient ) { assert( false ); return; } SetTimeout( SEC2MS( duration ) ); } /* ================ sdPlayerTask::Event_Free ================ */ void sdPlayerTask::Event_Free( void ) { if ( gameLocal.isClient ) { assert( false ); return; } sdTaskManager::GetInstance().FreeTask( _taskIndex ); } /* ================ sdPlayerTask::Event_GetTaskEntity ================ */ void sdPlayerTask::Event_GetTaskEntity( void ) { sdProgram::ReturnEntity( GetEntity() ); } /* ================ sdPlayerTask::Event_SetTargetPos ================ */ void sdPlayerTask::Event_SetTargetPos( int index, const idVec3& position ) { if ( gameLocal.isClient ) { assert( false ); return; } if ( SetTargetPos( index, position ) ) { if ( gameLocal.isServer ) { sdTaskMessage msg( this, TM_SETLOCATIION ); msg.WriteLong( index ); msg.WriteVector( position ); msg.Send( sdReliableMessageClientInfoAll() ); } } } /* ================ sdPlayerTask::Event_SetWayPointState ================ */ void sdPlayerTask::Event_SetWayPointState( int index, bool state ) { if ( gameLocal.isClient ) { assert( false ); return; } if ( SetWayPointState( index, state ) ) { if ( gameLocal.isServer ) { sdTaskMessage msg( this, TM_VISSTATE ); msg.WriteLong( index ); msg.WriteBool( state ); msg.Send( sdReliableMessageClientInfoAll() ); } } } /* ================ sdPlayerTask::Event_GetKey ================ */ void sdPlayerTask::Event_GetKey( const char *key ) { sdProgram::ReturnString( _taskInfo->GetData().GetString( key ) ); } /* ================ sdPlayerTask::Event_GetIntKey ================ */ void sdPlayerTask::Event_GetIntKey( const char *key ) { sdProgram::ReturnInteger( _taskInfo->GetData().GetInt( key ) ); } /* ================ sdPlayerTask::Event_GetFloatKey ================ */ void sdPlayerTask::Event_GetFloatKey( const char *key ) { sdProgram::ReturnFloat( _taskInfo->GetData().GetFloat( key ) ); } /* ================ sdPlayerTask::Event_GetVectorKey ================ */ void sdPlayerTask::Event_GetVectorKey( const char *key ) { sdProgram::ReturnVector( _taskInfo->GetData().GetVector( key ) ); } /* ================ sdPlayerTask::Event_GetKeyWithDefault ================ */ void sdPlayerTask::Event_GetKeyWithDefault( const char *key, const char* defaultvalue ) { sdProgram::ReturnString( _taskInfo->GetData().GetString( key, defaultvalue ) ); } /* ================ sdPlayerTask::Event_GetIntKeyWithDefault ================ */ void sdPlayerTask::Event_GetIntKeyWithDefault( const char *key, int defaultvalue ) { sdProgram::ReturnFloat( _taskInfo->GetData().GetInt( key, va( "%i", defaultvalue ) ) ); } /* ================ sdPlayerTask::Event_GetFloatKeyWithDefault ================ */ void sdPlayerTask::Event_GetFloatKeyWithDefault( const char *key, float defaultvalue ) { sdProgram::ReturnFloat( _taskInfo->GetData().GetFloat( key, va( "%f", defaultvalue ) ) ); } /* ================ sdPlayerTask::Event_GetVectorKeyWithDefault ================ */ void sdPlayerTask::Event_GetVectorKeyWithDefault( const char *key, const idVec3& defaultvalue ) { sdProgram::ReturnVector( _taskInfo->GetData().GetVector( key, defaultvalue.ToString() ) ); } /* ================ sdPlayerTask::Event_GiveObjectiveProficiency ================ */ void sdPlayerTask::Event_GiveObjectiveProficiency( float count, const char* reason ) { if ( !IsObjective() ) { return; } sdTeamInfo* team = _taskInfo->GetTeam(); if ( team == NULL ) { return; } sdProficiencyManagerLocal& manager = sdProficiencyManager::GetInstance(); for ( int i = 0; i < MAX_CLIENTS; i++ ) { idPlayer* player = gameLocal.GetClient( i ); if ( player == NULL ) { continue; } if ( player->GetGameTeam() != team ) { continue; } const sdDeclPlayerClass* cls = player->GetInventory().GetClass(); if ( cls == NULL ) { continue; } if ( cls->GetNumProficiencies() < 1 ) { continue; } manager.GiveProficiency( cls->GetProficiency( 0 ).index, count, player, 1.f, reason ); } } /* ================ sdPlayerTask::Event_SetUserCreated ================ */ void sdPlayerTask::Event_SetUserCreated( void ) { if ( gameLocal.isClient ) { return; } SetUserCreated(); } /* ================ sdPlayerTask::Event_IsUserCreated ================ */ void sdPlayerTask::Event_IsUserCreated( void ) { sdProgram::ReturnBoolean( IsUserCreated() ); } /* ================ sdPlayerTask::Event_FlashIcon ================ */ void sdPlayerTask::Event_FlashIcon( int time ) { FlashIcon( time ); } /* =============================================================================== sdTaskManagerLocal =============================================================================== */ const idEventDef EV_TaskManager_AllocEntityTask( "allocEntityTask", 'o', DOC_TEXT( "Allocates a mission and returns the object. If the allocation fails for any reason the result will be $null$." ), 2, "Task objects are of type $class:sdPlayerTask$.", "d", "index", "Index of the $decl:task$ to use.", "e", "owner", "Entity which the task will be associated with." ); CLASS_DECLARATION( idClass, sdTaskManagerLocal ) EVENT( EV_TaskManager_AllocEntityTask, sdTaskManagerLocal::Event_AllocEntityTask ) END_CLASS /* ================ sdTaskManagerLocal::sdTaskManagerLocal ================ */ sdTaskManagerLocal::sdTaskManagerLocal( void ) : _scriptObject( NULL ) { } /* ================ sdTaskManagerLocal::~sdTaskManagerLocal ================ */ sdTaskManagerLocal::~sdTaskManagerLocal( void ) { } /* ================ sdTaskManagerLocal::Init ================ */ void sdTaskManagerLocal::Init( void ) { Shutdown(); _objectiveTasks.SetNum( sdTeamManager::GetInstance().GetNumTeams() ); _taskList.SetNum( sdPlayerTask::MAX_TASKS ); _freeTasks.SetNum( sdPlayerTask::MAX_TASKS ); for ( int i = 0; i < sdPlayerTask::MAX_TASKS; i++ ) { _taskList[ i ] = NULL; _freeTasks[ i ] = sdPlayerTask::MAX_TASKS - i - 1; } } /* ================ sdTaskManagerLocal::Shutdown ================ */ void sdTaskManagerLocal::Shutdown( void ) { CheckForLeaks(); for ( int i = 0; i < MAX_CLIENTS; i++ ) { idPlayer* player = gameLocal.GetClient( i ); if ( player == NULL ) { continue; } player->GetTaskList().SetNum( 0 ); player->SetManualTaskSelection( false ); } _taskList.DeleteContents( true ); _freeTasks.Clear(); _objectiveTasks.SetNum( 0, false ); } /* ================ sdTaskManagerLocal::OnNewTask ================ */ void sdTaskManagerLocal::OnNewTask( sdPlayerTask* task ) { task->GetNode().AddToEnd( _activeTasks ); if ( task->IsObjective() ) { sdTeamInfo* taskTeam = task->GetInfo()->GetTeam(); if ( taskTeam != NULL ) { task->GetObjectiveNode().AddToEnd( _objectiveTasks[ taskTeam->GetIndex() ] ); task->UpdateObjectiveWayPoint(); } } idPlayer* localPlayer = gameLocal.GetLocalPlayer(); if ( localPlayer != NULL ) { if ( task->IsAvailable( localPlayer ) ) { gameLocal.localPlayerProperties.OnNewTask( task ); } } } /* ================ sdTaskManagerLocal::AllocTask ================ */ sdPlayerTask* sdTaskManagerLocal::AllocTask( const sdDeclPlayerTask* taskInfo, idEntity* object ) { if ( gameLocal.isClient ) { return NULL; } if ( _freeTasks.Num() == 0 ) { gameLocal.Warning( "sdTaskManagerLocal::AllocTask No Free Tasks" ); return NULL; } int index = _freeTasks[ _freeTasks.Num() - 1 ]; _freeTasks.RemoveIndex( _freeTasks.Num() - 1 ); assert( _taskList[ index ] == NULL ); _taskList[ index ] = new sdPlayerTask(); _taskList[ index ]->Create( index, taskInfo ); _taskList[ index ]->SetEntity( gameLocal.GetSpawnId( object ) ); _taskList[ index ]->WriteInitialState( sdReliableMessageClientInfoAll() ); OnNewTask( _taskList[ index ] ); return _taskList[ index ]; } /* ================ sdTaskManagerLocal::AllocTask ================ */ void sdTaskManagerLocal::AllocTask( taskHandle_t handle, const sdDeclPlayerTask* taskInfo, int spawnId ) { assert( _taskList[ handle ] == NULL ); _taskList[ handle ] = new sdPlayerTask(); _taskList[ handle ]->Create( handle, taskInfo ); _taskList[ handle ]->SetEntity( spawnId ); OnNewTask( _taskList[ handle ] ); } /* ================ sdTaskManagerLocal::FreeTask ================ */ void sdTaskManagerLocal::FreeTask( taskHandle_t handle ) { sdPlayerTask* task = TaskForHandle( handle ); if ( !task ) { return; } if ( !task->IsComplete() ) { idPlayer* localPlayer = gameLocal.GetLocalPlayer(); if ( localPlayer != NULL && localPlayer->GetActiveTaskHandle() == handle ) { gameLocal.localPlayerProperties.OnTaskExpired( task ); } } for ( int i = 0; i < MAX_CLIENTS; i++ ) { idPlayer* player = gameLocal.GetClient( i ); if ( player == NULL ) { continue; } player->GetTaskList().Remove( task ); if ( !gameLocal.isClient ) { if ( player->GetActiveTaskHandle() == handle ) { player->SetActiveTask( taskHandle_t() ); player->SetManualTaskSelection( false ); } } } int index = task->GetIndex(); delete task; _taskList[ index ] = NULL; if ( !gameLocal.isClient ) { if ( _freeTasks.FindIndex( index ) != -1 ) { gameLocal.Warning( "sdTaskManagerLocal::FreeTask - Freed an already free task '%d'", index ); } else { int* freeTask = _freeTasks.Alloc(); if ( freeTask == NULL ) { gameLocal.Error( "sdTaskManagerLocal::FreeTask - free tasks exceeded MAX_TASKS" ); } *freeTask = index; } } } /* ================ sdTaskManagerLocal::Write ================ */ void sdTaskManagerLocal::Write( idFile* file ) const { file->WriteInt( _activeTasks.Num() ); for ( sdPlayerTask* task = _activeTasks.Next(); task; task = task->GetNode().Next() ) { task->Write( file ); } } /* ================ sdTaskManagerLocal::Read ================ */ void sdTaskManagerLocal::Read( idFile* file ) { int count; file->ReadInt( count ); for ( int i = 0; i < count; i++ ) { sdPlayerTask::Read( file ); } } /* ================ sdTaskManagerLocal::IsTaskValid ================ */ bool sdTaskManagerLocal::IsTaskValid( idPlayer* player, taskHandle_t taskHandle, bool onlyCheckInitialFT ) { if ( taskHandle < 0 || taskHandle >= sdPlayerTask::MAX_TASKS ) { return false; } sdPlayerTask* task = TaskForHandle( taskHandle ); if ( task == NULL ) { return false; } sdFireTeam* fireTeam = gameLocal.rules->GetPlayerFireTeam( player->entityNumber ); if ( fireTeam != NULL ) { if ( fireTeam->GetCommander() != player ) { return false; } if ( player->GetTaskList().FindIndex( task ) == -1 ) { bool pass = false; for ( int i = 0; i < fireTeam->GetNumMembers(); i++ ) { idPlayer* p = fireTeam->GetMember( i ); if ( p == player ) { continue; } if ( onlyCheckInitialFT ) { if ( p->GetTaskList().Num() < 1 ) { continue; } if ( p->GetTaskList()[ 0 ] == task ) { pass = true; break; } } else { if ( p->GetTaskList().FindIndex( task ) != -1 ) { pass = true; break; } } } if ( !pass ) { return false; } } } else { if ( player->GetTaskList().FindIndex( task ) == -1 ) { return false; } } return true; } /* ================ sdTaskManagerLocal::SelectTask ================ */ void sdTaskManagerLocal::SelectTask( idPlayer* player, taskHandle_t taskHandle ) { if ( !taskHandle.IsValid() ) { // Gordon: always let the player choose "no task" == objective player->SetActiveTask( taskHandle ); player->SetManualTaskSelection( true ); return; } if ( player->GetActiveTaskHandle() == taskHandle ) { return; } if ( !IsTaskValid( player, taskHandle, true ) ) { return; } player->SetActiveTask( taskHandle ); player->SetManualTaskSelection( true ); } /* ================ sdTaskManagerLocal::WriteInitialReliableMessages ================ */ void sdTaskManagerLocal::WriteInitialReliableMessages( const sdReliableMessageClientInfoBase& target ) const { for ( sdPlayerTask* task = _activeTasks.Next(); task; task = task->GetNode().Next() ) { task->WriteInitialState( target ); } } idCVar g_debugWorldTasks( "g_debugWorldTasks", "0", CVAR_BOOL | CVAR_CHEAT, "draws a sphere around ranged based tasks" ); /* ================ sdTaskManagerLocal::Think ================ */ void sdTaskManagerLocal::Think( void ) { if ( !gameLocal.isClient ) { sdPlayerTask* task; sdPlayerTask* nextTask; for ( task = _activeTasks.Next(); task; task = nextTask ) { nextTask = task->GetNode().Next(); int endTime = task->GetEndTime(); if ( endTime >= 0 && gameLocal.time > endTime && !( task->IsObjective() || task->IsMission() ) ) { FreeTask( task->GetHandle() ); continue; } int timeLimit = task->GetInfo()->GetTimeLimit(); if ( timeLimit != -1 && !( task->IsObjective() || task->IsMission() ) ) { endTime = task->GetStartTime() + timeLimit; if ( gameLocal.time > endTime ) { FreeTask( task->GetHandle() ); continue; } } } sdTeamManagerLocal& manager = sdTeamManager::GetInstance(); idEntity* entity; sdTaskInterface* iface; for ( entity = _taskEntities.Next(); entity; entity = iface->GetNode().Next() ) { iface = entity->GetTaskInterface(); if ( entity->fl.spotted ) { continue; } sdTeamInfo* team = entity->GetGameTeam(); if ( team == NULL ) { continue; } const idVec3& origin = entity->GetPhysics()->GetOrigin(); if ( team->PointInJammer( origin, RM_RADAR ) ) { continue; } for ( int i = 0; i < manager.GetNumTeams(); i++ ) { sdTeamInfo& otherTeam = manager.GetTeamByIndex( i ); if ( otherTeam == *team ) { continue; } idEntity* other = otherTeam.PointInRadar( origin, RM_RADAR ); if ( other == NULL ) { continue; } entity->SetSpotted( other ); break; } } } for ( sdPlayerTask* task = _activeTasks.Next(); task; task = task->GetNode().Next() ) { task->Think(); } idPlayer* localPlayer = gameLocal.GetLocalPlayer(); sdFireTeam* ft = NULL; if ( localPlayer != NULL ) { ft = gameLocal.rules->GetPlayerFireTeam( localPlayer->entityNumber ); if ( ft && !ft->IsCommander( localPlayer ) ) { ft = NULL; } } for ( int i = 0; i < MAX_CLIENTS; i++ ) { idPlayer* player = gameLocal.GetClient( i ); if ( player == NULL ) { continue; } if ( gameLocal.isClient ) { if ( ft == NULL ) { if ( player != localPlayer ) { continue; } } else { if ( !ft->IsMember( player ) ) { continue; } } } playerTaskList_t& taskList = player->GetTaskList(); taskList.SetNum( 0 ); for ( sdPlayerTask* task = _activeTasks.Next(); task; task = task->GetNode().Next() ) { bool isAvailable = task->IsAvailable( player ); if ( isAvailable ) { sdPlayerTask** newTask = taskList.Alloc(); if ( newTask == NULL ) { gameLocal.Error( "sdTaskManagerLocal::Think - taskList exceeded MAX_TASKS" ); } *newTask = task; if ( player == localPlayer ) { float currentRange = 0.f; idEntity* other = task->GetEntity(); if ( other != NULL ) { currentRange = idMath::Sqrt( gameLocal.RangeSquare( other, player ) ); } task->SetCurrentRange( currentRange ); } } if ( player == localPlayer ) { if ( task->HasEligibleWayPoint() ) { if ( isAvailable || task->IsPlayerEligible( player ) ) { task->ShowWayPoint(); } else { task->HideWayPoint(); } } } } taskList.Sort( SortTasksByPriority ); if ( !gameLocal.isClient && !player->userInfo.isBot ) { bool canSelectTask = true; sdFireTeam* fireTeam = gameLocal.rules->GetPlayerFireTeam( player->entityNumber ); if ( fireTeam != NULL ) { canSelectTask = fireTeam->GetCommander() == player; } if ( canSelectTask && !player->GetManualTaskSelection() ) { if ( player->GetActiveTask() == NULL ) { if ( taskList.Num() > 0 ) { player->SetActiveTask( taskList[ 0 ]->GetHandle() ); } } } } } if ( !gameLocal.isClient ) { for ( int i = 0; i < MAX_CLIENTS; i++ ) { idPlayer* player = gameLocal.GetClient( i ); if ( player == NULL ) { continue; } taskHandle_t taskHandle = player->GetActiveTaskHandle(); if ( taskHandle.IsValid() ) { if ( !IsTaskValid( player, taskHandle, false ) ) { player->SetActiveTask( taskHandle_t() ); player->SetManualTaskSelection( false ); } } } } } /* ================ sdTaskManagerLocal::AddTaskEntity ================ */ void sdTaskManagerLocal::AddTaskEntity( idLinkList< idEntity >& entity ) { entity.AddToEnd( _taskEntities ); } /* ================ sdTaskManagerLocal::SortTasksByPriority ================ */ int sdTaskManagerLocal::SortTasksByPriority( const taskPtr_t* a, const taskPtr_t* b ) { int diff = ( *a )->GetPriority() - ( *b )->GetPriority(); if ( diff != 0 ) { return diff; } diff = idMath::Ftoi( idMath::Ceil( ( *a )->GetCurrentRange() - ( *b )->GetCurrentRange() ) ); return diff; } /* ================ sdTaskManagerLocal::CheckForLeaks ================ */ void sdTaskManagerLocal::CheckForLeaks( void ) { #if 0 for ( sdPlayerTask* task = _activeTasks.Next(); task; task = task->GetNode().Next() ) { gameLocal.Printf( "Task '%ls' not freed\n", task->GetTitle() ); } #endif // 0 } /* ================ sdTaskManagerLocal::OnNewScriptLoad ================ */ void sdTaskManagerLocal::OnNewScriptLoad( void ) { _scriptObject = gameLocal.program->AllocScriptObject( this, "taskManagerType" ); sdScriptHelper h1; _scriptObject->CallNonBlockingScriptEvent( _scriptObject->GetPreConstructor(), h1 ); const sdProgram::sdFunction* constructor = _scriptObject->GetConstructor(); if ( constructor ) { sdProgramThread* scriptThread = gameLocal.program->CreateThread(); scriptThread->SetName( "sdTaskManagerLocal" ); scriptThread->CallFunction( _scriptObject, constructor ); scriptThread->DelayedStart( 0 ); scriptThread->GetAutoNode().AddToEnd( _scriptObject->GetAutoThreads() ); } } /* ================ sdTaskManagerLocal::OnMapStart ================ */ void sdTaskManagerLocal::OnMapStart( void ) { if ( _scriptObject ) { const sdProgram::sdFunction* callback = _scriptObject->GetFunction( "OnMapStart" ); if ( callback ) { sdProgramThread* scriptThread = gameLocal.program->CreateThread(); scriptThread->SetName( "sdTaskManagerLocal" ); scriptThread->CallFunction( _scriptObject, callback ); scriptThread->DelayedStart( 0 ); scriptThread->GetAutoNode().AddToEnd( _scriptObject->GetAutoThreads() ); } } } /* ================ sdTaskManagerLocal::OnMapShutdown ================ */ void sdTaskManagerLocal::OnMapShutdown( void ) { if ( _scriptObject ) { sdScriptHelper h1; _scriptObject->CallNonBlockingScriptEvent( _scriptObject->GetFunction( "OnMapShutdown" ), h1 ); } Shutdown(); } /* ================ sdTaskManagerLocal::OnScriptChange ================ */ void sdTaskManagerLocal::OnScriptChange( void ) { if ( _scriptObject ) { sdScriptHelper h1; _scriptObject->CallNonBlockingScriptEvent( _scriptObject->GetDestructor(), h1 ); gameLocal.program->FreeScriptObject( _scriptObject ); } } /* ============ sdTaskManagerLocal::Event_AllocEntityTask ============ */ void sdTaskManagerLocal::Event_AllocEntityTask( int taskIndex, idEntity* object ) { const sdDeclPlayerTask* taskInfo = gameLocal.declPlayerTaskType[ taskIndex ]; if ( !taskInfo ) { sdProgram::ReturnObject( NULL ); return; } sdPlayerTask* task = AllocTask( taskInfo, object ); if ( !task ) { sdProgram::ReturnObject( NULL ); return; } sdProgram::ReturnObject( task->GetScriptObject() ); } /* ============ sdTaskManagerLocal::BuildTaskList ============ */ void sdTaskManagerLocal::BuildTaskList( idPlayer* player, playerTaskList_t& list ) { sdFireTeam* fireTeam = gameLocal.rules->GetPlayerFireTeam( player->entityNumber ); if ( fireTeam != NULL ) { if ( fireTeam->GetCommander() == player ) { list = player->GetTaskList(); for ( int i = 0; i < fireTeam->GetNumMembers(); i++ ) { idPlayer* other = fireTeam->GetMember( i ); if ( other == player ) { continue; } if ( other->GetTaskList().Num() < 1 ) { continue; } list.AddUnique( other->GetTaskList()[ 0 ] ); } } } else { list = player->GetTaskList(); } } /* ============ sdTaskManagerLocal::GetObjectiveTasks ============ */ const sdPlayerTask::nodeType_t& sdTaskManagerLocal::GetObjectiveTasks( const sdTeamInfo* team ) { return _objectiveTasks[ team->GetIndex() ]; } /* ============ sdTaskManagerLocal::OnLocalTeamChanged ============ */ void sdTaskManagerLocal::OnLocalTeamChanged( void ) { for ( int i = 0; i < _objectiveTasks.Num(); i++ ) { sdPlayerTask::nodeType_t& node = _objectiveTasks[ i ]; for ( sdPlayerTask* task = node.Next(); task != NULL; task = task->GetObjectiveNode().Next() ) { task->UpdateObjectiveWayPoint(); } } }