Files
GTASource/game/task/System/TaskTreePed.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

241 lines
6.5 KiB
C++

//Game headers.
#include "animation\AnimDefines.h"
#include "Event\Events.h"
#include "Peds\Ped.h"
#include "Peds\PedIntelligence.h"
#include "peds\PedTaskRecord.h"
#include "Peds\QueriableInterface.h"
#include "Task\System\TaskManager.h"
#include "Task\System\TaskTree.h"
#include "Task\System\TaskTreePed.h"
#include "Task\System\Task.h"
#include "Task\System\TaskClassInfo.h"
#include "Task\System\TaskFSMClone.h"
#include "Task\Default\TaskWander.h"
#include "Task\General\TaskBasic.h"
#include "Task\Movement\TaskGoto.h"
#include "Task\Vehicle\TaskCarCollisionResponse.h"
#include "Task/System/TaskMove.h"
#include "Task/System/Task.h"
// rage headers
#include "Profile/timebars.h"
AI_OPTIMISATIONS()
//
//
//
CTaskTreePed::CTaskTreePed(s32 iNumberOfPriorities, fwEntity *pPed, s32 iEventResponsePriority, s32 iDefaultPriority/* = -1*/) :
CTaskTree( pPed, iNumberOfPriorities ),
m_iEventResponsePriority(iEventResponsePriority),
m_iDefaultPriority(iDefaultPriority)
{
Assert(pPed);
Assert(dynamic_cast<CPed*>(pPed));
m_pPed = (static_cast<CPed*>(pPed));
}
//
//
//
void CTaskTreePed::SetTask(aiTask* pTask, const int iPriority, const bool UNUSED_PARAM(bForceNewTask))
{
taskFatalAssertf(iPriority >= 0 && iPriority < m_Tasks.GetCount(), "aiTaskTree::SetTask: iPriority [%d] out of range [0,%d]", iPriority, m_Tasks.GetCount());
#if !__FINAL
if(pTask)
{
for(s32 i = MAX_TASK_HISTORY-1; i > 0; i--)
{
m_TaskHistory[i] = m_TaskHistory[i-1];
}
m_TaskHistory[0] = pTask->GetTaskType();
#if AI_OPTIMISATIONS_OFF
taskAssertf( pTask == NULL || TASKCLASSINFOMGR.TaskNameExists(pTask->GetTaskType()), "Task (%s) doesn't have a definition", pTask->GetName().c_str());
#endif
}
#endif // !__FINAL
if(m_iDefaultPriority >= 0)
{
//don't allow default tasks to be replaced when a default task is being processed
//don't allow default tasks to be replaced within makeabortable
if( iPriority == m_iDefaultPriority &&
m_Tasks[iPriority] != NULL &&
( m_iPriorityBeingProcessed == m_iDefaultPriority || m_Tasks[iPriority]->GetIsFlagSet(aiTaskFlags::InMakeAbortable) ) )
{
delete pTask;
return;
}
}
// Don't allow SetTask to be called when the we are currently in MakeAbortable,
// and this will cause a crash as we'll be operating on a deleted pointer
taskFatalAssertf(!m_Tasks[iPriority] || !m_Tasks[iPriority]->GetIsFlagSet(aiTaskFlags::InMakeAbortable), "Replacing task [%s] with [%s] while it is in MakeAbortable which will cause a crash", m_Tasks[iPriority]->GetName().c_str(), pTask->GetName().c_str());
#if __ASSERT
if(pTask && ((CTask*)pTask)->IsMoveTask())
{
//TODO
//m_pEntity->GetPedIntelligence()->PrintTasks();
Assertf( !pTask || !((CTask*)pTask)->IsMoveTask(), "Move task %s is being added to the main task tree! Please include the debug spew with the bug report, it will help us find out how this happened.", (const char*)pTask->GetName());
}
#endif
// tasks cannot be started on peds controlled by a remote machine in a network game, or on peds that are
// in the process of having their control passed to another machine
bool canAddTask = true;
if(m_pPed->IsNetworkClone())
{
CNetObjPed *netObjPed = static_cast<CNetObjPed *>(m_pPed->GetNetworkObject());
if(netObjPed && !netObjPed->CanSetTask())
{
canAddTask = false;
}
}
if(!canAddTask)
{
if(pTask)
delete pTask;
return;
}
// Make sure any lower priority tasks are aborted:
for( s32 i = iPriority; i < GetPriorityCount(); i++ )
{
CEventNewTask event(pTask, iPriority);
if( m_Tasks[i] && !m_Tasks[i]->GetIsFlagSet(aiTaskFlags::IsAborted) )
{
if( !m_Tasks[i]->MakeAbortable( CTask::ABORT_PRIORITY_URGENT, &event ) )
m_Tasks[i]->MakeAbortable( CTask::ABORT_PRIORITY_IMMEDIATE, &event );
#if __DEBUG
Assertf(m_Tasks[i]->GetIsFlagSet(aiTaskFlags::IsAborted),"Task not aborted before a new one is added!");
#endif
}
}
//If the new task is a null task then delete the current task
//and set the current task to null.
if(!pTask && m_Tasks[iPriority])
{
DeleteTask(m_Tasks[iPriority]);
m_Tasks[iPriority]=0;
return;
}
//Don't set the same task.
if(m_Tasks[iPriority]==pTask)
{
return;
}
if(m_Tasks[iPriority])
{
DeleteTask(m_Tasks[iPriority]);
}
m_Tasks[iPriority]=pTask;
//make sure there is always a default task
if( m_Tasks[iPriority] == NULL && iPriority == m_iDefaultPriority )
{
SetTask( GetDefaultTask(), m_iDefaultPriority );
}
m_Tasks[iPriority]->SetEntity(m_pEntity);
// Ensure the active priority is up to date
m_iActivePriority = ComputeActiveTaskPriority();
}
//-------------------------------------------------------------------------
// process tasks
//-------------------------------------------------------------------------
void CTaskTreePed::Process(float fTimeStep)
{
//if there is no default main task create one.
if(m_iDefaultPriority >= 0)//is the default priority set
{
if( m_Tasks[m_iDefaultPriority] == NULL )
SetTask( GetDefaultTask(), m_iDefaultPriority);
}
//main tasks
UpdateTasks( false, m_iDefaultPriority, fTimeStep);
}
//-------------------------------------------------------------------------
// Write out the current main tasks to the queriable interface
//-------------------------------------------------------------------------
void CTaskTreePed::WriteTasksToQueriableInterface( CQueriableInterface* pInterface )
{
// we should never be writing tasks to a cloned ped!
Assert(!(m_pPed && m_pPed->IsNetworkClone()));
// First reset the existing task list
pInterface->ResetTaskInfo();
// Set if this set of tasks is running
bool bTaskActive = true;
bool bNonTemporaryTaskTreeFound = false;
//Add in tasks from the physical and temporary response tasks, also the first nonp-temporary
// slot (i.e. non-temp event response or primary or default, whichever is first
CTask* pTask = NULL;
for( s32 i=0; i<GetPriorityCount(); i++ )
{
if(m_Tasks[i])
{
pTask = static_cast<CTask*>(m_Tasks[i].Get());
// Add task information in for each task
while( pTask )
{
pInterface->AddTaskInformation( pTask, bTaskActive, i, m_pEntity );
pTask = pTask->GetSubTask();
// Only add the top task of any subsequent task priorities
if( bNonTemporaryTaskTreeFound )
{
break;
}
}
// Only add one full tree of non-temporary event responses
if(m_iEventResponsePriority >= 0)
{
if( i > m_iEventResponsePriority )
{
bNonTemporaryTaskTreeFound = true;
}
}
// Any task below the top level isn't active
bTaskActive = false;
}
}
}
//
//
//
aiTask* CTaskTreePed::GetDefaultTask()
{
if(m_pPed)
{
return m_pPed->ComputeDefaultTask(*m_pPed);
}
return NULL;
}