1703 lines
43 KiB
C++
1703 lines
43 KiB
C++
// 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();
|
|
}
|
|
}
|
|
}
|