3090 lines
98 KiB
C++
3090 lines
98 KiB
C++
// File header
|
|
#include "Task/Scenario/ScenarioDebug.h"
|
|
#include "Task/Scenario/Types/TaskUseScenario.h"
|
|
#include "Task/Default/TaskUnalerted.h"
|
|
#include "Task/Response/TaskFlee.h"
|
|
|
|
#if SCENARIO_DEBUG
|
|
|
|
// Framework headers
|
|
#include "fwdebug/vectormap.h"
|
|
#include "fwsys/metadatastore.h"
|
|
|
|
// Game headers
|
|
#include "ai/ambient/AmbientModelSetManager.h"
|
|
#include "ai/Ambient/ConditionalAnimManager.h"
|
|
#include "ai/BlockingBounds.h"
|
|
#include "bank/button.h"
|
|
#include "camera/CamInterface.h"
|
|
#include "camera/debug/DebugDirector.h"
|
|
#include "debug/Debug.h"
|
|
#include "Event/Events.h"
|
|
#include "game/Clock.h"
|
|
#include "Network/Network.h"
|
|
#include "Peds/ped.h"
|
|
#include "Peds/PedDebugVisualiser.h"
|
|
#include "peds/PedFactory.h"
|
|
#include "Peds/PedIntelligence.h"
|
|
#include "Peds/pedplacement.h"
|
|
#include "Peds/pedpopulation.h"
|
|
#include "Peds/PopZones.h"
|
|
#include "physics/physics.h"
|
|
#include "scene/FocusEntity.h"
|
|
#include "scene/world/GameWorld.h"
|
|
#include "script/script_brains.h"
|
|
#include "script/script_cars_and_peds.h"
|
|
#include "streaming/streaming.h"
|
|
#include "task/General/TaskBasic.h"
|
|
#include "Task/Default/AmbientAnimationManager.h"
|
|
#include "Task/Default/Patrol/PatrolRoutes.h"
|
|
#include "Task/Default/TaskAmbient.h"
|
|
#include "Task/Default/TaskUnalerted.h"
|
|
#include "Task/Default/TaskWander.h"
|
|
#include "task/Scenario/info/ScenarioActionCondition.h"
|
|
#include "Task/Scenario/info/ScenarioInfoManager.h"
|
|
#include "task/Scenario/ScenarioChainingTests.h"
|
|
#include "Task/Scenario/ScenarioManager.h"
|
|
#include "task/Scenario/ScenarioPoint.h"
|
|
#include "Task/Scenario/ScenarioPointManager.h"
|
|
#include "Task/Scenario/ScenarioPointRegion.h"
|
|
#include "Task/Scenario/ScenarioVehicleManager.h"
|
|
#include "Task/Scenario/Types/TaskParkedVehicleScenario.h"
|
|
#include "Task/Scenario/Types/TaskUseScenario.h"
|
|
#include "task/Response/TaskFlee.h"
|
|
#include "weapons/WeaponChannel.h"
|
|
#include "modelinfo/ModelInfo_Factories.h"
|
|
|
|
AI_OPTIMISATIONS()
|
|
|
|
// Static initialisation
|
|
bkBank* CScenarioDebug::ms_pBank = NULL;
|
|
bkButton* CScenarioDebug::ms_pCreateEditorButton = NULL;
|
|
bkButton* CScenarioDebug::ms_pCreateConditionalAnimsButton = NULL;
|
|
bkButton* CScenarioDebug::ms_pCreateDebugButton = NULL;
|
|
bkButton* CScenarioDebug::ms_pCreateModelSetsButton = NULL;
|
|
bkButton* CScenarioDebug::ms_pCreateOtherButton = NULL;
|
|
bkButton* CScenarioDebug::ms_pCreateScenarioInfoButton = NULL;
|
|
|
|
atArray<const char*> CScenarioDebug::ms_szScenarioNames;
|
|
s32 CScenarioDebug::ms_iScenarioComboIndex = 0;
|
|
s32 CScenarioDebug::ms_iAvailabilityComboIndex = 0;
|
|
atArray<CScenarioDebug::ConditionalAnimData> CScenarioDebug::ms_ConditionalAnims;
|
|
atArray<const char*> CScenarioDebug::ms_ConditionalAnimNames;
|
|
s32 CScenarioDebug::ms_iAmbientContextComboIndex = 0;
|
|
atQueue<CScenarioDebug::ScenarioPointMemory, 32> CScenarioDebug::ms_WarpToNearestAlreadyVisited;
|
|
int CScenarioDebug::ms_NextScenarioPropIndex = 0;
|
|
int CScenarioDebug::ms_WarpToNearestScenarioType = -1;
|
|
RegdObj CScenarioDebug::ms_DebugScenarioProp;
|
|
bool CScenarioDebug::ms_UseFixedPhysicsForProps = false;
|
|
bool CScenarioDebug::ms_UseScenarioCreateProp = true;
|
|
bool CScenarioDebug::ms_UseScenarioFindExisting = true;
|
|
bool CScenarioDebug::ms_UseScenarioWarp = true;
|
|
bool CScenarioDebug::ms_StopTargetPedImmediate = true;
|
|
bool CScenarioDebug::ms_bPlayBaseClip = true;
|
|
bool CScenarioDebug::ms_bInstantlyBlendInBaseClip = true;
|
|
bool CScenarioDebug::ms_bPlayIdleClips = true;
|
|
bool CScenarioDebug::ms_bPickPermanentProp = true;
|
|
bool CScenarioDebug::ms_bForcePropCreation = true;
|
|
bool CScenarioDebug::ms_bOverrideInitialIdleTime = false;
|
|
CScenarioEditor CScenarioDebug::ms_Editor;
|
|
bank_float CScenarioDebug::ms_fRenderDistance = 100.0f;
|
|
bank_bool CScenarioDebug::ms_bRenderScenarioPoints = false;
|
|
bank_bool CScenarioDebug::ms_bRenderStationaryReactionsPointsOnly = false;
|
|
bank_bool CScenarioDebug::ms_bRenderOnlyChainedPoints = false;
|
|
bank_bool CScenarioDebug::ms_bRenderChainPointUsage = false;
|
|
bank_bool CScenarioDebug::ms_bRenderScenarioPointsDisabled = false;
|
|
bank_bool CScenarioDebug::ms_bRenderScenarioPointsOnlyInPopZone = false;
|
|
bank_bool CScenarioDebug::ms_bDisableScenariosWithNoClipData = false;
|
|
bank_bool CScenarioDebug::ms_bRenderScenarioPointRegionBounds = false;
|
|
bank_bool CScenarioDebug::ms_bRenderScenarioPointsOnlyInTimePeriod = false;
|
|
bank_bool CScenarioDebug::ms_bRenderScenarioPointsOnlyInTimePeriodCurrent = false;
|
|
bank_u32 CScenarioDebug::ms_iRenderScenarioPointsOnlyInTimePeriodStart = 0;
|
|
bank_u32 CScenarioDebug::ms_iRenderScenarioPointsOnlyInTimePeriodEnd = 24;
|
|
bank_float CScenarioDebug::ms_fPointHandleLength = 0.5f;
|
|
bank_float CScenarioDebug::ms_fPointHandleRadius = 0.05f;
|
|
bank_float CScenarioDebug::ms_fPointDrawRadius = 0.1f;
|
|
bank_bool CScenarioDebug::ms_bRenderIntoVectorMap = false;
|
|
bank_bool CScenarioDebug::ms_bRenderSpawnHistory = false;
|
|
bank_bool CScenarioDebug::ms_bRenderSpawnHistoryText = false;
|
|
bank_bool CScenarioDebug::ms_bRenderSpawnHistoryTextPed = true;
|
|
bank_bool CScenarioDebug::ms_bRenderSpawnHistoryTextVeh = true;
|
|
bank_bool CScenarioDebug::ms_bDisplayScenarioModelSetsOnVectorMap = false;
|
|
bank_bool CScenarioDebug::ms_bAnimDebugDisableSPRender = false; //set in CScenarioAnimDebugHelper
|
|
bank_bool CScenarioDebug::ms_bRenderScenarioSpawnCheckCache = false;
|
|
bank_bool CScenarioDebug::ms_bRenderPointText = true;
|
|
bank_bool CScenarioDebug::ms_bRenderPointRadius = true;
|
|
bank_bool CScenarioDebug::ms_bRenderPointAddress = false;
|
|
bank_bool CScenarioDebug::ms_bRenderClusterInfo = false;
|
|
bank_bool CScenarioDebug::ms_bRenderClusterReport = false;
|
|
bank_bool CScenarioDebug::ms_bRenderNonRegionSpatialArray = false;
|
|
bank_bool CScenarioDebug::ms_bRenderSummaryInfo = false;
|
|
bank_bool CScenarioDebug::ms_bRenderPopularTypesInSummary = false;
|
|
bank_bool CScenarioDebug::ms_bRenderSelectedTypeOnly = false;
|
|
bank_bool CScenarioDebug::ms_bRestrictVehicleAttractionToSelectedPoint = false;
|
|
bank_bool CScenarioDebug::ms_bRenderSelectedScenarioGroup = false;
|
|
|
|
bkButton* CScenarioDebug::ms_pCreateScenarioReactsButton = NULL;
|
|
bkButton* CScenarioDebug::ms_pTriggerReactsButton = NULL;
|
|
bkButton* CScenarioDebug::ms_pTriggerAllReactsButton = NULL;
|
|
bkButton* CScenarioDebug::ms_pSpawnScenarioButton = NULL;
|
|
bkButton* CScenarioDebug::ms_pCleanUpScenarioButton = NULL;
|
|
bkButton* CScenarioDebug::ms_pSpawnPropButton = NULL;
|
|
bkCombo* CScenarioDebug::ms_scenarioGroupCombo = NULL;
|
|
atArray<const char*> CScenarioDebug::ms_szScenarioTypeNames;
|
|
atArray<const char*> CScenarioDebug::ms_szPropSetNames;
|
|
atArray<const char*> CScenarioDebug::ms_szPedModelNames;
|
|
atArray<const char*> CScenarioDebug::ms_szReactionTypeNames;
|
|
atArray<CPedModelInfo*> CScenarioDebug::ms_PedModelInfoArray;
|
|
RegdPed CScenarioDebug::ms_pScenarioPed;
|
|
RegdObj CScenarioDebug::ms_pScenarioProp;
|
|
RegdPed CScenarioDebug::ms_pReactionPed;
|
|
s32* CScenarioDebug::ms_pedSortArray = NULL;
|
|
int CScenarioDebug::ms_iScenarioTypeIndex = 0;
|
|
s32 CScenarioDebug::ms_iScenarioGroupIndex = 0;
|
|
int CScenarioDebug::ms_iPropSetIndex = 0;
|
|
int CScenarioDebug::ms_iPedModelIndex = 0;
|
|
int CScenarioDebug::ms_iReactPedModelIndex = 0;
|
|
int CScenarioDebug::ms_iReactionTypeIndex = 0;
|
|
float CScenarioDebug::ms_fReactionHeading = 90.0f;
|
|
float CScenarioDebug::ms_fReactionDistance = 2.0f;
|
|
float CScenarioDebug::ms_fDistanceFromPlayer = 10.0f;
|
|
float CScenarioDebug::ms_fTimeToLeave = -1.0f;
|
|
float CScenarioDebug::ms_fTimeBetweenReactions = 10.0f;
|
|
bool CScenarioDebug::ms_bSpawnPedToUsePropScenario = true;
|
|
bool CScenarioDebug::ms_bTriggerOnFocusPed = false;
|
|
bool CScenarioDebug::ms_bPlayIntro = true;
|
|
bool CScenarioDebug::ms_bDontSpawnReactionPed = false;
|
|
|
|
static bool ms_bTriggerAllReacts = false;
|
|
static bool ms_bRetryTriggerReaction = false;
|
|
static float ms_fTimeBetweenReactsCountdown = 0.0f;
|
|
|
|
static const char* s_szAvaliablityNames[] = {"Both", "Sp Only", "Mp Only"};
|
|
|
|
void CScenarioDebug::InitBank()
|
|
{
|
|
if(ms_pBank)
|
|
{
|
|
ShutdownBank();
|
|
}
|
|
|
|
// Create the weapons bank
|
|
ms_pBank = &BANKMGR.CreateBank("Scenarios", 0, 0, false);
|
|
if(weaponVerifyf(ms_pBank, "Failed to create Scenarios. bank"))
|
|
{
|
|
ms_pCreateEditorButton = ms_pBank->AddButton("Create Scenario Editor widgets", &CScenarioDebug::CreateEditorBank);
|
|
ms_pCreateDebugButton = ms_pBank->AddButton("Create Scenario Debug widgets", &CScenarioDebug::CreateDebugBank);
|
|
ms_pCreateConditionalAnimsButton = ms_pBank->AddButton("Create Conditional Anims widgets", &CScenarioDebug::CreateConditionalAnimsBank);
|
|
ms_pCreateModelSetsButton = ms_pBank->AddButton("Create Ambient Model Sets widgets", &CScenarioDebug::CreateModelSetsBank);
|
|
ms_pCreateScenarioInfoButton = ms_pBank->AddButton("Create Scenarios Info widgets", &CScenarioDebug::CreateScenarioInfoBank);
|
|
ms_pCreateScenarioReactsButton = ms_pBank->AddButton("Create Scenario Reacts Debug widgets", &CScenarioDebug::CreateScenarioReactsDebugBank);
|
|
ms_pCreateOtherButton = ms_pBank->AddButton("Create Other Scenario widgets", &CScenarioDebug::CreateOtherBank);
|
|
}
|
|
}
|
|
|
|
int CScenarioDebug::CompareModelInfos(const void* pVoidA, const void* pVoidB)
|
|
{
|
|
const s32* pA = (const s32*)pVoidA;
|
|
const s32* pB = (const s32*)pVoidB;
|
|
|
|
return stricmp(CScenarioDebug::ms_PedModelInfoArray[*pA]->GetModelName(), CScenarioDebug::ms_PedModelInfoArray[*pB]->GetModelName());
|
|
}
|
|
|
|
void CScenarioDebug::SpawnProp()
|
|
{
|
|
//check if the prop is valid
|
|
if (ms_iPropSetIndex == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ms_pScenarioProp)
|
|
{
|
|
CObjectPopulation::DestroyObject(ms_pScenarioProp);
|
|
ms_pScenarioProp = NULL;
|
|
}
|
|
|
|
u32 nModelIndex = CModelInfo::GetModelIdFromName(ms_szPropSetNames[ms_iPropSetIndex]).GetModelIndex();
|
|
fwModelId modelId((strLocalIndex(nModelIndex)));
|
|
if (CModelInfo::IsValidModelInfo(nModelIndex))
|
|
{
|
|
//load the selected object
|
|
CBaseModelInfo* pModelInfo = CModelInfo::GetBaseModelInfo(modelId);
|
|
if(pModelInfo == NULL)
|
|
{
|
|
Displayf("CScenarioDebug::SpawnProp - Invalid model: %d", nModelIndex);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (!pModelInfo->GetIsTypeObject())
|
|
{
|
|
Displayf("This is not a prop, bad naming convention. No object created.");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
ms_pScenarioProp = CObjectPopulation::CreateObject(modelId, ENTITY_OWNEDBY_RANDOM, true);
|
|
}
|
|
|
|
if (ms_pScenarioProp)
|
|
{
|
|
Matrix34 tempMat;
|
|
tempMat.Identity();
|
|
|
|
// generate position
|
|
Vector3 vForward = VEC3_ZERO;
|
|
Vector3 vPosition = VEC3_ZERO;
|
|
float fHeading = 0.0f;
|
|
|
|
CEntity *pEnt = CGameWorld::FindLocalPlayer();
|
|
if (pEnt && pEnt->GetIsTypePed())
|
|
{
|
|
vForward = VEC3V_TO_VECTOR3(pEnt->GetTransform().GetB());
|
|
vPosition = VEC3V_TO_VECTOR3(pEnt->GetTransform().GetPosition());
|
|
fHeading = (RtoD * pEnt->GetTransform().GetHeading()) + 180.0f;
|
|
|
|
if (fHeading < 0.0f)
|
|
{
|
|
fHeading += 360.0f;
|
|
}
|
|
if (fHeading > 360.0f)
|
|
{
|
|
fHeading -= 360.0f;
|
|
}
|
|
}
|
|
vForward *= (ms_fDistanceFromPlayer + 2.0f); // 1.1f is to offset its location from the spawned prop's position
|
|
vPosition += vForward;
|
|
vPosition.z -= 1.0f; // adjust prop location slightly
|
|
|
|
float fSetHeading = (DtoR * fHeading);
|
|
fSetHeading = fwAngle::LimitRadianAngleSafe(fSetHeading);
|
|
tempMat.RotateFullZ(fSetHeading);
|
|
tempMat.d += vPosition;
|
|
|
|
if (!ms_pScenarioProp->GetTransform().IsMatrix())
|
|
{
|
|
#if ENABLE_MATRIX_MEMBER
|
|
Mat34V trans = MATRIX34_TO_MAT34V(tempMat);
|
|
ms_pScenarioProp->SetTransform(trans);
|
|
ms_pScenarioProp->SetTransformScale(1.0f, 1.0f);
|
|
#else
|
|
fwMatrixTransform* trans = rage_new fwMatrixTransform(MATRIX34_TO_MAT34V(tempMat));
|
|
ms_pScenarioProp->SetTransform(trans);
|
|
#endif
|
|
}
|
|
ms_pScenarioProp->SetMatrix(tempMat);
|
|
|
|
if (fragInst* pInst = ms_pScenarioProp->GetFragInst())
|
|
{
|
|
pInst->SetResetMatrix(tempMat);
|
|
}
|
|
CGameWorld::Add(ms_pScenarioProp, CGameWorld::OUTSIDE );
|
|
|
|
CObject* pDynamicEnt = static_cast<CObject*>(ms_pScenarioProp.Get());
|
|
pDynamicEnt->GetPortalTracker()->RequestRescanNextUpdate();
|
|
pDynamicEnt->GetPortalTracker()->Update(VEC3V_TO_VECTOR3(ms_pScenarioProp->GetTransform().GetPosition()));
|
|
|
|
pDynamicEnt->SetupMissionState();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CScenarioDebug::SpawnScenario()
|
|
{
|
|
// spawn ped and prop (if any)
|
|
SpawnScenarioPed();
|
|
SpawnProp();
|
|
|
|
if (!ms_pScenarioPed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
s32 scenarioType = CScenarioManager::GetScenarioTypeFromName(ms_szScenarioTypeNames[ms_iScenarioTypeIndex]);
|
|
if (scenarioType != Scenario_Invalid)
|
|
{
|
|
int flags = 0;
|
|
if (!ms_bSpawnPedToUsePropScenario || ms_pScenarioProp == NULL)
|
|
{
|
|
flags |= CTaskUseScenario::SF_StartInCurrentPosition;
|
|
}
|
|
else
|
|
{
|
|
flags |= CTaskUseScenario::SF_GotoPositionTaskSet;
|
|
}
|
|
if (!ms_bPlayIntro)
|
|
{
|
|
flags &= ~CTaskUseScenario::SF_StartInCurrentPosition;
|
|
flags |= CTaskUseScenario::SF_SkipEnterClip;
|
|
flags |= CTaskUseScenario::SF_Warp;
|
|
}
|
|
if (ms_fTimeToLeave < 0.0f)
|
|
{
|
|
flags |= CTaskUseScenario::SF_IdleForever;
|
|
}
|
|
|
|
CScenarioDebugClosestFilterScenarioType filter(scenarioType);
|
|
filter.m_IgnoreInUse = true;
|
|
CScenarioPoint* sp = GetClosestScenarioPoint(ms_pScenarioPed->GetTransform().GetPosition(), filter);
|
|
if(sp)
|
|
{
|
|
// Are we close to a point?
|
|
Vector3 vecDistance = VEC3V_TO_VECTOR3(sp->GetPosition() - ms_pScenarioPed->GetTransform().GetPosition());
|
|
if (vecDistance.Mag2() > rage::square(ms_fDistanceFromPlayer))
|
|
{
|
|
flags |= CTaskUseScenario::SF_SkipEnterClip;
|
|
}
|
|
|
|
CTaskUseScenario* pUseScenarioTask = rage_new CTaskUseScenario(scenarioType, sp, flags);
|
|
if (ms_fTimeToLeave > 0.0f)
|
|
{
|
|
pUseScenarioTask->SetTimeToLeave(ms_fTimeToLeave / 1000.0f);
|
|
}
|
|
pUseScenarioTask->CreateProp();
|
|
|
|
CTaskUnalerted* pUnalertedTask = rage_new CTaskUnalerted(pUseScenarioTask, sp, scenarioType);
|
|
ms_pScenarioPed->GetPedIntelligence()->AddTaskDefault(pUnalertedTask);
|
|
return;
|
|
}
|
|
|
|
CTaskUseScenario* pUseScenarioTask = rage_new CTaskUseScenario(scenarioType, flags);
|
|
if (ms_fTimeToLeave > 0.0f)
|
|
{
|
|
pUseScenarioTask->SetTimeToLeave(ms_fTimeToLeave / 1000.0f);
|
|
}
|
|
pUseScenarioTask->CreateProp();
|
|
|
|
ms_pScenarioPed->GetPedIntelligence()->AddTaskAtPriority(pUseScenarioTask, PED_TASK_PRIORITY_PRIMARY);
|
|
}
|
|
}
|
|
|
|
void CScenarioDebug::CleanUpScenarioReactInfo()
|
|
{
|
|
// remove prop, scenario ped, and scenario react ped if these exist
|
|
if (ms_pScenarioPed)
|
|
{
|
|
CPedFactory::GetFactory()->DestroyPed(ms_pScenarioPed);
|
|
ms_pScenarioPed = NULL;
|
|
}
|
|
if (ms_pReactionPed)
|
|
{
|
|
CPedFactory::GetFactory()->DestroyPed(ms_pReactionPed);
|
|
ms_pReactionPed = NULL;
|
|
}
|
|
if (ms_pScenarioProp)
|
|
{
|
|
CObjectPopulation::DestroyObject(ms_pScenarioProp);
|
|
ms_pScenarioProp = NULL;
|
|
}
|
|
}
|
|
|
|
void CScenarioDebug::SpawnReactionPed(const Vector3& vSpawnPosition)
|
|
{
|
|
if (ms_pReactionPed)
|
|
{
|
|
CPedFactory::GetFactory()->DestroyPed(ms_pReactionPed);
|
|
ms_pReactionPed = NULL;
|
|
}
|
|
|
|
if (!ms_bDontSpawnReactionPed)
|
|
{
|
|
ms_pReactionPed = SpawnPed(vSpawnPosition, 0.0f, false);
|
|
}
|
|
}
|
|
|
|
void CScenarioDebug::SpawnScenarioPed()
|
|
{
|
|
if (ms_pScenarioPed)
|
|
{
|
|
CPedFactory::GetFactory()->DestroyPed(ms_pScenarioPed);
|
|
ms_pScenarioPed = NULL;
|
|
}
|
|
|
|
float fHeading = 0.0f;
|
|
|
|
Vector3 vForward = VEC3_ZERO;
|
|
Vector3 vSpawnPosition = VEC3_ZERO;
|
|
CEntity *pEnt = CGameWorld::FindLocalPlayer();
|
|
if (pEnt && pEnt->GetIsTypePed())
|
|
{
|
|
vForward = VEC3V_TO_VECTOR3(pEnt->GetTransform().GetB());
|
|
vSpawnPosition = VEC3V_TO_VECTOR3(pEnt->GetTransform().GetPosition());
|
|
fHeading = (RtoD * pEnt->GetTransform().GetHeading()) + 180.0f;
|
|
|
|
if (fHeading < 0.0f)
|
|
{
|
|
fHeading += 360.0f;
|
|
}
|
|
if (fHeading > 360.0f)
|
|
{
|
|
fHeading -= 360.0f;
|
|
}
|
|
}
|
|
vForward *= ms_fDistanceFromPlayer;
|
|
vSpawnPosition += vForward;
|
|
|
|
ms_pScenarioPed = SpawnPed(vSpawnPosition, fHeading);
|
|
}
|
|
|
|
CPed* CScenarioDebug::SpawnPed(const Vector3& vSpawnPosition, float fHeading, bool bScenarioPed)
|
|
{
|
|
CPed *pPed = NULL;
|
|
Vector3 TempCoors = Vector3(vSpawnPosition);
|
|
|
|
// If coordinates are valid, and either there's no networking enabled, or we have a valid handler...
|
|
if (ABS(TempCoors.x) < WORLDLIMITS_XMAX && ABS(TempCoors.y) < WORLDLIMITS_YMAX &&
|
|
(!CNetwork::IsNetworkOpen() || CTheScripts::GetCurrentGtaScriptHandlerNetwork()))
|
|
{
|
|
u32 nModelIndex = bScenarioPed
|
|
? CModelInfo::GetModelIdFromName(ms_szPedModelNames[ms_iPedModelIndex]).GetModelIndex()
|
|
: CModelInfo::GetModelIdFromName(ms_szPedModelNames[ms_iReactPedModelIndex]).GetModelIndex();
|
|
fwModelId modelId((strLocalIndex(nModelIndex)));
|
|
if (CModelInfo::IsValidModelInfo(nModelIndex))
|
|
{
|
|
//load the selected ped
|
|
CBaseModelInfo* pModelInfo = CModelInfo::GetBaseModelInfo(modelId);
|
|
if(pModelInfo == NULL)
|
|
{
|
|
Displayf("CScenarioDebug::SpawnPed - Invalid model: %d", nModelIndex);
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
if (pModelInfo->GetModelType() == MI_TYPE_PED)
|
|
{
|
|
if (!CModelInfo::HaveAssetsLoaded(modelId))
|
|
{
|
|
CModelInfo::RequestAssets(modelId, STRFLAG_FORCE_LOAD | STRFLAG_PRIORITY_LOAD);
|
|
CStreaming::LoadAllRequestedObjects(true);
|
|
}
|
|
if (!CModelInfo::HaveAssetsLoaded(modelId))
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (pModelInfo->GetDrawable() || pModelInfo->GetFragType())
|
|
{
|
|
// want to pass matrix into PedFactory
|
|
if (TempCoors.z <= INVALID_MINIMUM_WORLD_Z)
|
|
{
|
|
TempCoors.z = WorldProbe::FindGroundZForCoord(BOTTOM_SURFACE, TempCoors.x, TempCoors.y);
|
|
}
|
|
|
|
float fSetHeading = (DtoR * fHeading);
|
|
fSetHeading = fwAngle::LimitRadianAngleSafe(fSetHeading);
|
|
|
|
Matrix34 TempMat;
|
|
TempMat.Identity();
|
|
TempMat.RotateFullZ(fSetHeading);
|
|
TempMat.d = TempCoors;
|
|
|
|
// use pedfactory to create the ped:
|
|
const CControlledByInfo localAiControl(false, false);
|
|
pPed = CPedFactory::GetFactory()->CreatePed(localAiControl, modelId, &TempMat, true, true, true);
|
|
|
|
if (pPed)
|
|
{
|
|
pPed->SetVarRandom(PV_FLAG_NONE, PV_FLAG_NONE, NULL, NULL, NULL, PV_RACE_UNIVERSAL);
|
|
pPed->SetDesiredHeading( fSetHeading );
|
|
pPed->SetHeading( fSetHeading );
|
|
pPed->SetLodDistance(CPed::ms_uMissionPedLodDistance);
|
|
|
|
CScriptEntities::ClearSpaceForMissionEntity(pPed);
|
|
pPed->ActivatePhysics();
|
|
|
|
CGameWorld::Add(pPed, CGameWorld::OUTSIDE );
|
|
|
|
pPed->GetPortalTracker()->RequestRescanNextUpdate();
|
|
pPed->GetPortalTracker()->Update(VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return pPed;
|
|
}
|
|
|
|
void CScenarioDebug::TriggerAllReacts()
|
|
{
|
|
ms_iReactionTypeIndex = 0;
|
|
ms_bSpawnPedToUsePropScenario = true;
|
|
ms_bTriggerAllReacts = true;
|
|
ms_bPlayIntro = true;
|
|
ms_fTimeBetweenReactsCountdown = 0.0f;
|
|
}
|
|
|
|
void CScenarioDebug::TriggerReacts()
|
|
{
|
|
CPed* pPed = ms_pScenarioPed;
|
|
|
|
if (ms_bTriggerOnFocusPed)
|
|
{
|
|
pPed = CPedDebugVisualiserMenu::GetFocusPed();
|
|
if (!pPed)
|
|
{
|
|
pPed = ms_pScenarioPed; // maybe this was checked by accident?
|
|
}
|
|
}
|
|
|
|
if (pPed)
|
|
{
|
|
// early out
|
|
CTaskUseScenario* pTask = static_cast<CTaskUseScenario *>(pPed->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_USE_SCENARIO));
|
|
if (!pTask)
|
|
{
|
|
ms_bRetryTriggerReaction = true; // try one more time
|
|
return;
|
|
}
|
|
|
|
Vector3 direction = VEC3V_TO_VECTOR3(pPed->GetTransform().GetB());
|
|
Vector3 eventPosition = VEC3V_TO_VECTOR3(pPed->GetTransform().GetPosition());
|
|
|
|
float fSin = sinf(ms_fReactionHeading);
|
|
float fCos = cosf(ms_fReactionHeading);
|
|
|
|
Vector3 eventDirection = Vector3(direction.GetX() * fCos - direction.GetY() * fSin, direction.GetX() * fSin + direction.GetY() * fCos, direction.GetZ());
|
|
|
|
eventDirection *= ms_fReactionDistance;
|
|
eventPosition += eventDirection;
|
|
|
|
// always spawn the ped now for visual clarity
|
|
SpawnReactionPed(eventPosition);
|
|
|
|
// if we have the ped, use it, otherwise use the eventPosition
|
|
CAITarget target;
|
|
if (ms_pReactionPed)
|
|
{
|
|
target = CAITarget(ms_pReactionPed);
|
|
}
|
|
else
|
|
{
|
|
target = CAITarget(eventPosition);
|
|
}
|
|
|
|
// preset the position
|
|
CEventScenarioForceAction e;
|
|
Vector3 position;
|
|
target.GetPosition(position);
|
|
e.SetSourcePos(position);
|
|
|
|
switch (ms_iReactionTypeIndex)
|
|
{
|
|
case 0: // PanicExitToFlee
|
|
{
|
|
e.SetForceActionType(eScenarioActionFlee);
|
|
e.SetTask(rage_new CTaskSmartFlee(target));
|
|
}
|
|
break;
|
|
case 1: // PanicExitToCombat
|
|
{
|
|
e.SetForceActionType(eScenarioActionCombatExit);
|
|
e.SetTask(rage_new CTaskThreatResponse(ms_pReactionPed));
|
|
}
|
|
break;
|
|
case 2: // TriggerAggroThenExit
|
|
{
|
|
e.SetForceActionType(eScenarioActionThreatResponseExit);
|
|
e.SetTask(rage_new CTaskThreatResponse(ms_pReactionPed));
|
|
}
|
|
break;
|
|
case 3: // TriggerShockAnimation
|
|
{
|
|
e.SetForceActionType(eScenarioActionShockReaction);
|
|
e.SetTask(rage_new CTaskThreatResponse(ms_pReactionPed));
|
|
}
|
|
break;
|
|
case 4: // TriggerHeadLook
|
|
{
|
|
e.SetForceActionType(eScenarioActionHeadTrack);
|
|
}
|
|
break;
|
|
default:
|
|
; // do nothing
|
|
}
|
|
|
|
// finally, add the event
|
|
pPed->GetPedIntelligence()->AddEvent(e);
|
|
}
|
|
}
|
|
|
|
void CScenarioDebug::CreateScenarioReactsDebugBank()
|
|
{
|
|
aiAssertf(ms_pBank, "Scenario bank needs to be created first");
|
|
aiAssertf(ms_pCreateScenarioReactsButton, "Scenario bank needs to be created first");
|
|
|
|
// remove the button. don't want it clickable again
|
|
ms_pCreateScenarioReactsButton->Destroy();
|
|
ms_pCreateScenarioReactsButton = NULL;
|
|
|
|
// grab the bank
|
|
bkBank* pBank = ms_pBank;
|
|
|
|
// clean up the data
|
|
ms_szScenarioTypeNames.Reset();
|
|
ms_szPropSetNames.Reset();
|
|
ms_szPedModelNames.Reset();
|
|
|
|
// get the data for the scenario type combo box
|
|
const int typeCount = SCENARIOINFOMGR.GetScenarioCount(true);
|
|
ms_szScenarioTypeNames.Reserve(typeCount);
|
|
for (s32 i = 0; i < typeCount; ++i)
|
|
{
|
|
ms_szScenarioTypeNames.Grow() = SCENARIOINFOMGR.GetNameForScenario(i);
|
|
}
|
|
|
|
// get the data for the scenario propset to use combo box
|
|
ms_szPropSetNames.PushAndGrow("INVALID");
|
|
|
|
//look through the permanent archetypes
|
|
const u32 maxModelInfos = CModelInfo::GetMaxModelInfos();
|
|
for (u32 i = CModelInfo::GetStartModelInfos(); i < maxModelInfos; ++i)
|
|
{
|
|
CBaseModelInfo* modelInfo = CModelInfo::GetBaseModelInfo(fwModelId(strLocalIndex(i)));
|
|
|
|
if (modelInfo && modelInfo->GetModelName())
|
|
{
|
|
atString searchText("prop_");
|
|
atString modelName(modelInfo->GetModelName());
|
|
searchText.Lowercase();
|
|
modelName.Lowercase();
|
|
if (modelName.IndexOf(searchText) >= 0)
|
|
{
|
|
if (modelInfo->GetModelType() != MI_TYPE_PED && modelInfo->GetModelType() != MI_TYPE_VEHICLE)
|
|
{
|
|
if (modelInfo->GetModelName())
|
|
{
|
|
// Add the object name to the array of model names
|
|
ms_szPropSetNames.PushAndGrow(modelInfo->GetModelName());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ms_szPropSetNames.GetCount() > 1)
|
|
{
|
|
// Sort the model names alphabetically
|
|
std::sort(&ms_szPropSetNames[1], &ms_szPropSetNames[1] + ms_szPropSetNames.GetCount() - 1, AlphabeticalSort());
|
|
}
|
|
|
|
const int propSetCount = ms_szPropSetNames.size();
|
|
|
|
// get the data for the scenario ped and scenario reaction ped models to use combo box
|
|
// num ped models
|
|
fwArchetypeDynamicFactory<CPedModelInfo>& pedModelInfoStore = CModelInfo::GetPedModelInfoStore();
|
|
pedModelInfoStore.GatherPtrs(ms_PedModelInfoArray);
|
|
const int pedModelCount = ms_PedModelInfoArray.GetCount();
|
|
ms_szPedModelNames.Reserve(pedModelCount);
|
|
|
|
// create the sort array
|
|
if (ms_pedSortArray)
|
|
{
|
|
delete[] ms_pedSortArray; // shouldn't happen, but may if multiple button click events happen...
|
|
}
|
|
ms_pedSortArray = rage_new s32[pedModelCount];
|
|
for(u32 i = 0; i < pedModelCount; ++i)
|
|
{
|
|
ms_pedSortArray[i] = i;
|
|
}
|
|
|
|
//get the modelInfo associated with this ped ID
|
|
qsort(ms_pedSortArray, pedModelCount, sizeof(s32), CompareModelInfos);
|
|
for(u32 i = 0; i < pedModelCount; ++i)
|
|
{
|
|
ms_szPedModelNames.PushAndGrow(ms_PedModelInfoArray[ms_pedSortArray[i]]->GetModelName());
|
|
}
|
|
|
|
// grab the data for the reaction type to use
|
|
ms_szReactionTypeNames.PushAndGrow("PanicExitToFlee");
|
|
ms_szReactionTypeNames.PushAndGrow("PanicExitToCombat");
|
|
ms_szReactionTypeNames.PushAndGrow("TriggerAggroThenExit");
|
|
ms_szReactionTypeNames.PushAndGrow("TriggerShockAnimation");
|
|
ms_szReactionTypeNames.PushAndGrow("TriggerHeadLook");
|
|
const int reactionTypeCount = ms_szReactionTypeNames.size();
|
|
|
|
// add the widgets
|
|
pBank->PushGroup("Scenario Reacts Debug", false);
|
|
{
|
|
pBank->PushGroup("Base Scenario Info", false);
|
|
{
|
|
pBank->AddCombo("Scenario Type", &CScenarioDebug::ms_iScenarioTypeIndex, typeCount, &CScenarioDebug::ms_szScenarioTypeNames[0]);
|
|
pBank->AddCombo("Scenario Ped Model", &CScenarioDebug::ms_iPedModelIndex, pedModelCount, &CScenarioDebug::ms_szPedModelNames[0]);
|
|
pBank->AddSlider("Distance From Player", &CScenarioDebug::ms_fDistanceFromPlayer, 0.0f, 100.0f, 1.0f);
|
|
pBank->AddSlider("Time To Leave Scenario (ms)", &CScenarioDebug::ms_fTimeToLeave, -1.0f, 10000.0f, 1.0f);
|
|
pBank->AddToggle("Play Intro", &CScenarioDebug::ms_bPlayIntro);
|
|
ms_pSpawnScenarioButton = ms_pBank->AddButton("Spawn Scenario", &CScenarioDebug::SpawnScenario);
|
|
|
|
pBank->AddSeparator();
|
|
|
|
ms_pCleanUpScenarioButton = ms_pBank->AddButton("Clean up", &CScenarioDebug::CleanUpScenarioReactInfo);
|
|
}
|
|
pBank->PopGroup();
|
|
|
|
pBank->AddSeparator();
|
|
|
|
pBank->PushGroup("Scenario Prop Info", false);
|
|
{
|
|
pBank->AddCombo("Scenario PropSet Model", &CScenarioDebug::ms_iPropSetIndex, propSetCount, &CScenarioDebug::ms_szPropSetNames[0]);
|
|
pBank->AddToggle("Have Scenario Ped Spawn And Use Prop Scenario", &CScenarioDebug::ms_bSpawnPedToUsePropScenario);
|
|
ms_pSpawnPropButton = ms_pBank->AddButton("Spawn Prop", &CScenarioDebug::SpawnProp);
|
|
}
|
|
pBank->PopGroup();
|
|
|
|
pBank->AddSeparator();
|
|
|
|
pBank->PushGroup("Force Scenario Reactions", false);
|
|
{
|
|
pBank->AddCombo("Scenario Reaction Type", &CScenarioDebug::ms_iReactionTypeIndex, reactionTypeCount, &CScenarioDebug::ms_szReactionTypeNames[0]);
|
|
pBank->AddCombo("Scenario React Ped Model", &CScenarioDebug::ms_iReactPedModelIndex, pedModelCount, &CScenarioDebug::ms_szPedModelNames[0]);
|
|
pBank->AddToggle("Trigger Event on Focus Ped", &CScenarioDebug::ms_bTriggerOnFocusPed);
|
|
pBank->AddToggle("Dont Spawn Reaction Ped", &CScenarioDebug::ms_bDontSpawnReactionPed);
|
|
ms_pTriggerReactsButton = ms_pBank->AddButton("Trigger Scenario Reaction", &CScenarioDebug::TriggerReacts);
|
|
pBank->AddSlider("Relative Heading From Scenario Ped to Cause Reaction", &CScenarioDebug::ms_fReactionHeading, -180.0f, 180.0f, 1.0f);
|
|
pBank->AddSlider("Relative Distance From Scenario Ped to Cause Reaction", &CScenarioDebug::ms_fReactionDistance, 0.0f, 100.0f, 1.0f);
|
|
pBank->AddSlider("Time between Reactions (sec)", &CScenarioDebug::ms_fTimeBetweenReactions, 0.0f, 100.0f, 1.0f);
|
|
ms_pTriggerAllReactsButton = ms_pBank->AddButton("Trigger All Scenario Reactions", &CScenarioDebug::TriggerAllReacts);
|
|
}
|
|
pBank->PopGroup();
|
|
}
|
|
pBank->PopGroup();
|
|
}
|
|
|
|
void CScenarioDebug::CreateEditorBank()
|
|
{
|
|
aiAssertf(ms_pBank, "Scenario bank needs to be created first");
|
|
aiAssertf(ms_pCreateEditorButton, "Scenario bank needs to be created first");
|
|
|
|
ms_pCreateEditorButton->Destroy();
|
|
ms_pCreateEditorButton = NULL;
|
|
|
|
// FF: In case the user didn't run with -scenarioedit, we need to flush the loaded files,
|
|
// set the NOT_IN_PLACE_LOADABLE flag, and load them back again. Otherwise, we would get crashes
|
|
// when trying to manipulate the runtime structures (acceleration grid, etc).
|
|
parStructure* pointRegStruct = CScenarioPointRegion::parser_GetStaticStructure();
|
|
if (pointRegStruct)
|
|
{
|
|
if(!pointRegStruct->GetFlags().IsSet(parStructure::NOT_IN_PLACE_LOADABLE))
|
|
{
|
|
aiDisplayf("Scenario editor may become enabled, reloading scenario point files to set NOT_IN_PLACE_LOADABLE.");
|
|
SCENARIOPOINTMGR.BankLoad();
|
|
ms_Editor.PostLoadData();
|
|
|
|
g_fwMetaDataStore.SetAllowLoadInResourceMem(false);
|
|
pointRegStruct->GetFlags().Set(parStructure::NOT_IN_PLACE_LOADABLE);
|
|
}
|
|
}
|
|
|
|
|
|
bkBank* pBank = ms_pBank;
|
|
ms_Editor.AddWidgets(pBank);
|
|
}
|
|
|
|
void CScenarioDebug::CreateConditionalAnimsBank()
|
|
{
|
|
aiAssertf(ms_pBank, "Scenario bank needs to be created first");
|
|
aiAssertf(ms_pCreateConditionalAnimsButton, "Scenario bank needs to be created first");
|
|
|
|
ms_pCreateConditionalAnimsButton->Destroy();
|
|
ms_pCreateConditionalAnimsButton = NULL;
|
|
bkBank* pBank = ms_pBank;
|
|
|
|
CONDITIONALANIMSMGR.AddWidgets(*pBank);
|
|
}
|
|
|
|
void CScenarioDebug::CreateDebugBank()
|
|
{
|
|
aiAssertf(ms_pBank, "Scenario bank needs to be created first");
|
|
aiAssertf(ms_pCreateDebugButton, "Scenario bank needs to be created first");
|
|
|
|
ms_pCreateDebugButton->Destroy();
|
|
ms_pCreateDebugButton = NULL;
|
|
bkBank* pBank = ms_pBank;
|
|
|
|
ms_Editor.RebuildScenarioGroupNameList();
|
|
|
|
pBank->PushGroup("Debug", false);
|
|
|
|
pBank->AddToggle("Render Selected Type Only", &ms_bRenderSelectedTypeOnly);
|
|
pBank->AddToggle("Render Summary", &ms_bRenderSummaryInfo);
|
|
pBank->AddToggle("Render Type Popularity in Summary", &ms_bRenderPopularTypesInSummary);
|
|
pBank->AddToggle("Render Scenario Points", &ms_bRenderScenarioPoints);
|
|
pBank->AddToggle("Render Point Text", &ms_bRenderPointText);
|
|
pBank->AddToggle("Render Point Radius", &ms_bRenderPointRadius);
|
|
pBank->AddToggle("Render Point Address", &ms_bRenderPointAddress);
|
|
pBank->AddToggle("Render stationary reactions points only", &ms_bRenderStationaryReactionsPointsOnly);
|
|
pBank->AddToggle("Render Chained Points ONLY", &ms_bRenderOnlyChainedPoints);
|
|
pBank->AddToggle("Render Chained Points USAGE", &ms_bRenderChainPointUsage);
|
|
pBank->AddToggle("Render Cluster Info", &ms_bRenderClusterInfo);
|
|
//pBank->AddToggle("Render Cluster Report", &ms_bRenderClusterReport);
|
|
pBank->AddSlider("Render Distance", &ms_fRenderDistance, 1.0f, 10000.0f, 10.0f);
|
|
pBank->AddToggle("Render Region Bounds", &ms_bRenderScenarioPointRegionBounds);
|
|
pBank->AddToggle("Render In Vector Map", &ms_bRenderIntoVectorMap);
|
|
pBank->AddToggle("Render Disabled (Group/Mode) Scenario Points", &ms_bRenderScenarioPointsDisabled);
|
|
pBank->AddToggle("Render Spawn History Links", &ms_bRenderSpawnHistory);
|
|
pBank->AddToggle("Render Spawn History Text", &ms_bRenderSpawnHistoryText);
|
|
pBank->AddToggle("Render Spawn History Text Ped", &ms_bRenderSpawnHistoryTextPed);
|
|
pBank->AddToggle("Render Spawn History Text Vehicle", &ms_bRenderSpawnHistoryTextVeh);
|
|
pBank->AddButton("Clear Spawn History", datCallback(CFA(CScenarioDebug::ClearSpawnHistoryCB)));
|
|
pBank->AddToggle("Render Non Region Point Spatial Array", &ms_bRenderNonRegionSpatialArray);
|
|
pBank->AddCombo("Restrict By Availability", &ms_iAvailabilityComboIndex, 3, &s_szAvaliablityNames[0]);
|
|
pBank->AddToggle("Restrict Render to Current PopZone", &ms_bRenderScenarioPointsOnlyInPopZone);
|
|
pBank->AddToggle("Render Scenario Spawn Check Cache", &ms_bRenderScenarioSpawnCheckCache);
|
|
pBank->AddSeparator();
|
|
pBank->AddToggle("Restrict Render to Time Period", &ms_bRenderScenarioPointsOnlyInTimePeriod);
|
|
pBank->AddSlider("Start Time", &ms_iRenderScenarioPointsOnlyInTimePeriodStart, 0, 24, 1);
|
|
pBank->AddSlider("End Time", &ms_iRenderScenarioPointsOnlyInTimePeriodEnd, 0, 24, 1);
|
|
pBank->AddToggle("Use Current Time", &ms_bRenderScenarioPointsOnlyInTimePeriodCurrent);
|
|
pBank->AddSeparator();
|
|
pBank->AddToggle("Disable Incomplete Scenarios", &ms_bDisableScenariosWithNoClipData);
|
|
pBank->AddToggle("Prevent Base Anim Streaming", &CTaskAmbientClips::sm_DebugPreventBaseAnimStreaming);
|
|
|
|
const int count = SCENARIOINFOMGR.GetScenarioCount(true);
|
|
|
|
ms_szScenarioNames.Reset();
|
|
ms_szScenarioNames.Reserve(count);
|
|
|
|
for (s32 i = 0; i < count; ++i)
|
|
{
|
|
ms_szScenarioNames.Grow() = SCENARIOINFOMGR.GetNameForScenario(i);
|
|
}
|
|
|
|
if(count)
|
|
{
|
|
pBank->AddCombo("Scenarios", &ms_iScenarioComboIndex, count, &ms_szScenarioNames[0]);
|
|
}
|
|
|
|
pBank->AddToggle("Render Selected Scenario Group", &ms_bRenderSelectedScenarioGroup);
|
|
ms_scenarioGroupCombo = pBank->AddCombo("SelectedGroup", &ms_iScenarioGroupIndex, ms_Editor.m_GroupNames.GetCount(), &ms_Editor.m_GroupNames[0]);
|
|
//B*134849, 242822
|
|
pBank->AddButton("Warp to (Next) Nearest", WarpToNextNearestScenarioCB);
|
|
pBank->AddButton("Warp to Previous", WarpToPreviousScenarioCB);
|
|
|
|
pBank->AddSeparator();
|
|
pBank->AddButton("Set Target Ped to Use Selected Scenario", CreateAndActivateScenarioOnSelectedPedCB, "Find or create a scenario of the requested type, and make the focus ped use it, either warping or navigating to it.");
|
|
pBank->AddToggle("Create Prop Scenario is Attached to", &ms_UseScenarioCreateProp, NullCB, "If the selected scenario type is attached to a prop, create a matching prop first.");
|
|
pBank->AddToggle("Use Fixed Physics for Props", &ms_UseFixedPhysicsForProps, NullCB, "");
|
|
pBank->AddToggle("Try to Find Existing Scenario", &ms_UseScenarioFindExisting, NullCB, "Look for existing scenarios of the matching type before creating a new one.");
|
|
pBank->AddToggle("Warp to Scenario", &ms_UseScenarioWarp, NullCB, "When using the selected scenario, warp straight into it rather than navigating.");
|
|
pBank->AddSeparator();
|
|
pBank->AddButton("Stop Target Ped Using Scenario", DeActivateScenarioOnSelectedPedCB, "Stop the focus ped from using a scenario, either immediately or by playing exit animations");
|
|
pBank->AddToggle("Stop Immediately", &ms_StopTargetPedImmediate, NullCB, "When stopping the ped from using a scenario, stop immediately without playing exit animations.");
|
|
pBank->AddSeparator();
|
|
pBank->AddButton("Destroy Prop Created for Attached Scenario", DestroyScenarioProp, "If \"Set Target Ped to Use Selected Scenario\" has created a prop, destroy it.");
|
|
pBank->AddSeparator();
|
|
pBank->AddButton("Load Prop Offsets from Clips", LoadPropOffsetsCB);
|
|
|
|
|
|
pBank->AddButton("Force spawn in area", ForceSpawnInAreaCB, "Define the area using the measuring");
|
|
pBank->AddToggle("Display scenario blocking areas.", &CScenarioBlockingAreas::ms_bRenderScenarioBlockingAreas);
|
|
//pBank->AddColor("Scenario blocking areas debug draw color", &CScenarioBlockingAreas::ms_RenderScenarioBlockingAreasColor);
|
|
|
|
pBank->AddButton("Remove all random peds", CPedPopulation::RemoveAllRandomPeds);
|
|
pBank->AddToggle("Only allow selected scenario to attract vehicles.", &ms_bRestrictVehicleAttractionToSelectedPoint);
|
|
|
|
pBank->PushGroup("Vehicle Scenarios", false);
|
|
CScenarioManager::GetVehicleScenarioManager().AddWidgets(*pBank);
|
|
pBank->PopGroup();
|
|
|
|
pBank->PushGroup("Chain Tests", false);
|
|
CScenarioManager::GetChainTests().AddWidgets(*pBank);
|
|
pBank->PopGroup();
|
|
|
|
pBank->PushGroup("Clusters", false);
|
|
SCENARIOCLUSTERING.AddStaticWidgets(*pBank);
|
|
pBank->PopGroup();
|
|
|
|
pBank->PopGroup(); // "Debug"
|
|
}
|
|
|
|
void CScenarioDebug::CreateModelSetsBank()
|
|
{
|
|
aiAssertf(ms_pBank, "Scenario bank needs to be created first");
|
|
aiAssertf(ms_pCreateModelSetsButton, "Scenario bank needs to be created first");
|
|
|
|
ms_pCreateModelSetsButton->Destroy();
|
|
ms_pCreateModelSetsButton = NULL;
|
|
bkBank* pBank = ms_pBank;
|
|
|
|
CAmbientModelSetManager::GetInstance().AddWidgets(*pBank);
|
|
}
|
|
|
|
void CScenarioDebug::CreateOtherBank()
|
|
{
|
|
aiAssertf(ms_pBank, "Scenario bank needs to be created first");
|
|
aiAssertf(ms_pCreateOtherButton, "Scenario bank needs to be created first");
|
|
|
|
ms_pCreateOtherButton->Destroy();
|
|
ms_pCreateOtherButton = NULL;
|
|
bkBank* pBank = ms_pBank;
|
|
|
|
SCENARIOPOINTMGR.AddWidgets(pBank);
|
|
|
|
pBank->PushGroup("Ambient clips", false);
|
|
pBank->AddButton("Give focus ped random prop", GiveRandomProp, "Gives the focus ped a random prop");
|
|
pBank->AddButton("Reload Ambient.dat", ReloadAmbientData);
|
|
pBank->AddToggle("Block ambient clips", &CTaskAmbientClips::BLOCK_ALL_AMBIENT_IDLES);
|
|
|
|
// Build an array of the names of conditional animations, for the combo box,
|
|
// with a parallel array to keep track of the entries the names refer to.
|
|
ms_ConditionalAnims.Reset();
|
|
ms_ConditionalAnimNames.Reset();
|
|
const int numGroups = CONDITIONALANIMSMGR.GetNumConditionalAnimsGroups();
|
|
for(int i = 0; i < numGroups; i++)
|
|
{
|
|
const CConditionalAnimsGroup& grp = CONDITIONALANIMSMGR.GetConditionalAnimsGroupByIndex(i);
|
|
const int numAnimsInGroup = grp.GetNumAnims();
|
|
for(int j = 0; j < numAnimsInGroup; j++)
|
|
{
|
|
const CConditionalAnims* pAnims = grp.GetAnims(j);
|
|
if(pAnims)
|
|
{
|
|
ConditionalAnimData& d = ms_ConditionalAnims.Grow();
|
|
d.m_Group = &grp;
|
|
d.m_AnimIndexWithinGroup = j;
|
|
ms_ConditionalAnimNames.Grow() = pAnims->GetName();
|
|
}
|
|
}
|
|
}
|
|
|
|
if(ms_ConditionalAnimNames.GetCount() > 0)
|
|
{
|
|
pBank->AddCombo("Ambient Contexts", &ms_iAmbientContextComboIndex, ms_ConditionalAnimNames.GetCount(), &ms_ConditionalAnimNames[0]);
|
|
}
|
|
pBank->AddToggle("Play Base Clip", &ms_bPlayBaseClip);
|
|
pBank->AddToggle("Instantly Blend Base Clip", &ms_bInstantlyBlendInBaseClip);
|
|
pBank->AddToggle("Play Idle Clips", &ms_bPlayIdleClips);
|
|
pBank->AddToggle("Pick Permanent Prop", &ms_bPickPermanentProp);
|
|
pBank->AddToggle("Force Prop Creation", &ms_bForcePropCreation);
|
|
pBank->AddToggle("Override Initial Idle Time", &ms_bOverrideInitialIdleTime);
|
|
pBank->AddButton("Give Focus Ped Ambient Task", GivePedAmbientTaskCB);
|
|
pBank->PopGroup();
|
|
|
|
pBank->PushGroup("Ambient Scenario Peds", false);
|
|
pBank->AddToggle("Toggle render routes", &CPatrolRoutes::ms_bRenderRoutes );
|
|
pBank->AddToggle("Toggle render 2D Effects", &CPatrolRoutes::ms_bRender2DEffects);
|
|
// pBank->AddSlider("Max dist difference before trying to using nav mesh path", &CTaskControlScenario::ms_fDistToleranceBeforeTryingNavMesh, 1.0f, 10.0f, 1.0f);
|
|
// pBank->AddSlider("Max time to wait before checking dist difference", &CTaskControlScenario::ms_fTimeToleranceBeforeTryingNavMesh, 2.0f, 10.0f, 1.0f);
|
|
pBank->AddSlider("Sq Dist Spawn Ped Away From Another ped", &CPedPopulation::ms_fCloseSpawnPointDistControlSq, 100.0f, 1000.0f, 10.0f);
|
|
pBank->AddSlider("Sq Random offset Dist Spawn Ped Away From Another ped", &CPedPopulation::ms_fCloseSpawnPointDistControlOffsetSq, 100.0f, 1000.0f, 10.0f);
|
|
pBank->PopGroup();
|
|
}
|
|
|
|
void CScenarioDebug::CreateScenarioInfoBank()
|
|
{
|
|
aiAssertf(ms_pBank, "Scenario bank needs to be created first");
|
|
aiAssertf(ms_pCreateScenarioInfoButton, "Scenario bank needs to be created first");
|
|
|
|
ms_pCreateScenarioInfoButton->Destroy();
|
|
ms_pCreateScenarioInfoButton = NULL;
|
|
bkBank* pBank = ms_pBank;
|
|
|
|
SCENARIOINFOMGR.AddWidgets(*pBank);
|
|
}
|
|
|
|
void CScenarioDebug::ShutdownBank()
|
|
{
|
|
if (ms_pedSortArray)
|
|
{
|
|
delete[] ms_pedSortArray;
|
|
ms_pedSortArray = NULL;
|
|
}
|
|
|
|
if(ms_pBank)
|
|
{
|
|
BANKMGR.DestroyBank(*ms_pBank);
|
|
}
|
|
|
|
ms_pBank = NULL;
|
|
ms_pCreateEditorButton = NULL;
|
|
ms_pCreateDebugButton = NULL;
|
|
ms_pCreateOtherButton = NULL;
|
|
ms_pCreateConditionalAnimsButton = NULL;
|
|
ms_pCreateModelSetsButton = NULL;
|
|
ms_pCreateScenarioInfoButton = NULL;
|
|
ms_pCreateScenarioReactsButton = NULL;
|
|
ms_pTriggerReactsButton = NULL;
|
|
ms_pTriggerAllReactsButton = NULL;
|
|
ms_pSpawnScenarioButton = NULL;
|
|
ms_pCleanUpScenarioButton = NULL;
|
|
ms_pSpawnPropButton = NULL;
|
|
}
|
|
|
|
void CScenarioDebug::DebugUpdate()
|
|
{
|
|
if (ms_bTriggerAllReacts)
|
|
{
|
|
if (ms_bRetryTriggerReaction)
|
|
{
|
|
TriggerReacts();
|
|
ms_bRetryTriggerReaction = false;
|
|
}
|
|
ms_fTimeBetweenReactsCountdown -= fwTimer::GetTimeStep();
|
|
if (ms_fTimeBetweenReactsCountdown < 0.0f)
|
|
{
|
|
ms_fTimeBetweenReactsCountdown += ms_fTimeBetweenReactions;
|
|
SpawnScenario();
|
|
TriggerReacts();
|
|
++ms_iReactionTypeIndex;
|
|
|
|
if (ms_iReactionTypeIndex == ms_szReactionTypeNames.size())
|
|
{
|
|
ms_iReactionTypeIndex = 0;
|
|
ms_bTriggerAllReacts = false;
|
|
ms_fTimeBetweenReactsCountdown = ms_fTimeBetweenReactions;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CScenarioDebug::DebugRender()
|
|
{
|
|
if (CControlMgr::GetKeyboard().GetKeyJustDown(KEY_S, KEYBOARD_MODE_DEBUG_CTRL) && !CDebug::IsDebugRecorderDisplayEnabled())
|
|
{
|
|
//Toggle scenario point display ...
|
|
ms_bRenderScenarioPoints = !ms_bRenderScenarioPoints;
|
|
}
|
|
|
|
CScenarioManager::GetVehicleScenarioManager().DebugRender();
|
|
|
|
CScenarioManager::GetChainTests().DebugDraw();
|
|
|
|
if (ms_bRenderClusterInfo)
|
|
{
|
|
SCENARIOCLUSTERING.DebugRender();
|
|
}
|
|
|
|
if (ms_bDisplayScenarioModelSetsOnVectorMap)
|
|
{
|
|
RenderModelSetsOnVectorMap();
|
|
}
|
|
|
|
#if !__FINAL
|
|
if(ms_bRenderScenarioSpawnCheckCache)
|
|
{
|
|
CScenarioManager::GetSpawnCheckCache().DebugDraw();
|
|
}
|
|
#endif // !__FINAL
|
|
|
|
#if __DEV
|
|
if (ms_bRenderNonRegionSpatialArray)
|
|
{
|
|
const CSpatialArray* sparray = SCENARIOPOINTMGR.GetNonRegionSpatialArray();
|
|
if (sparray)
|
|
{
|
|
sparray->DebugDraw();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (ms_bRenderSummaryInfo)
|
|
{
|
|
SCENARIOPOINTMGR.RenderPointSummary();
|
|
}
|
|
|
|
bool editing = CScenarioDebug::ms_Editor.IsEditing();
|
|
if (!ms_bRenderScenarioPointRegionBounds &&
|
|
!ms_bRenderScenarioPoints &&
|
|
!editing &&
|
|
!ms_bRenderChainPointUsage &&
|
|
!ms_bRenderSpawnHistory &&
|
|
!ms_bRenderSpawnHistoryText &&
|
|
!ms_bRenderClusterReport
|
|
)
|
|
{
|
|
return;//not drawing anything.
|
|
}
|
|
|
|
#if DR_ENABLED
|
|
int mousex = ioMouse::GetX();
|
|
int mouseY = ioMouse::GetY();
|
|
|
|
debugPlayback::OnScreenOutput screenSpew(10.0f);
|
|
screenSpew.m_fMouseX = (float)mousex;
|
|
screenSpew.m_fMouseY = (float)mouseY;
|
|
screenSpew.m_Color.Set(200,200,200,255);
|
|
screenSpew.m_HighlightColor.Set(255,0,0,255);
|
|
screenSpew.m_fXPosition = 50.0f;
|
|
screenSpew.m_fYPosition = 50.0f;
|
|
#endif
|
|
|
|
if (ms_bRenderSpawnHistory)
|
|
{
|
|
CScenarioManager::sm_SpawnHistory.DebugRender();
|
|
}
|
|
|
|
if (ms_bRenderSpawnHistoryText)
|
|
{
|
|
#if DR_ENABLED
|
|
CScenarioManager::sm_SpawnHistory.DebugRenderToScreen(screenSpew);
|
|
#endif
|
|
}
|
|
|
|
if (ms_bRenderClusterReport)
|
|
{
|
|
#if DR_ENABLED
|
|
SCENARIOCLUSTERING.DebugReport(screenSpew);
|
|
#endif
|
|
}
|
|
|
|
CPopZone* pZone = NULL;
|
|
if(ms_bRenderScenarioPointsOnlyInPopZone)
|
|
{
|
|
Vector3 pPos = camInterface::GetPos();
|
|
pZone = CPopZones::FindSmallestForPosition(&pPos, ZONECAT_ANY, ZONETYPE_ANY);
|
|
}
|
|
|
|
#if DR_ENABLED
|
|
if (ms_bRenderChainPointUsage)
|
|
{
|
|
//Draw the titles ...
|
|
screenSpew.AddLine("Scenario Point Chain User Info - %d/%d", CScenarioPointChainUseInfo::_ms_pPool->GetNoOfUsedSpaces(), CScenarioPointChainUseInfo::_ms_pPool->GetSize());
|
|
char buffer[RAGE_MAX_PATH];
|
|
formatf(buffer, RAGE_MAX_PATH, "%-32s%8s%8s%10s%24s%10s%15s%10s%6s%11s%5s", "Region", "Chain", "Node", "User Add", "Ped", "Ped Add", "Veh", "Veh Add", "Dummy", "Ref Count", "Hist");
|
|
screenSpew.AddLine(buffer);
|
|
}
|
|
#endif
|
|
|
|
//Region Points
|
|
const int rcount = SCENARIOPOINTMGR.GetNumRegions();
|
|
for (int r = 0; r < rcount; r++)
|
|
{
|
|
const CScenarioPointRegion* region = SCENARIOPOINTMGR.GetRegion(r);
|
|
//draw the region bounds
|
|
if(ms_bRenderScenarioPointRegionBounds || (editing && ms_Editor.IsEditingRegion(r)))
|
|
{
|
|
Color32 color = Color_RoyalBlue1;
|
|
if (region)
|
|
{
|
|
//Streamed in ...
|
|
color = Color_green4;
|
|
}
|
|
const spdAABB& aabb = SCENARIOPOINTMGR.GetRegionAABB(r);
|
|
grcDebugDraw::BoxAxisAligned(aabb.GetMin(), aabb.GetMax(), color, false);
|
|
|
|
if (ms_bRenderIntoVectorMap)
|
|
{
|
|
fwVectorMap::Draw3DBoundingBoxOnVMap(aabb, color);
|
|
}
|
|
}
|
|
|
|
if (region)
|
|
{
|
|
const CScenarioPointRegionEditInterface bankRegion(*region);
|
|
|
|
// we can now debug draw everything else.
|
|
if (ms_bRenderScenarioPoints || editing)
|
|
{
|
|
//Points
|
|
const int pcount = bankRegion.GetNumPoints();
|
|
for (int p = 0; p < pcount; p++)
|
|
{
|
|
RenderPoint(bankRegion.GetPoint(p), r, editing, pZone, NULL, p);
|
|
}
|
|
|
|
//ClusterPoints
|
|
const int ccount = bankRegion.GetNumClusters();
|
|
for (int c = 0; c < ccount; c++)
|
|
{
|
|
const int cpcount = bankRegion.GetNumClusteredPoints(c);
|
|
for (int cp = 0; cp < cpcount; cp++)
|
|
{
|
|
RenderPoint(bankRegion.GetClusteredPoint(c, cp), r, editing, pZone, NULL, cp);
|
|
}
|
|
}
|
|
|
|
// Draw the active entity override points in this region.
|
|
// Note: this does not draw override points in regions that are not streamed in,
|
|
// but I'm leaning towards removing those when the region gets streamed out anyway.
|
|
const int numOverrides = region->GetNumEntityOverrides();
|
|
for(int i = 0; i < numOverrides; i++)
|
|
{
|
|
const CScenarioEntityOverride& override = bankRegion.GetEntityOverride(i);
|
|
if(override.m_EntityCurrentlyAttachedTo)
|
|
{
|
|
for(int j = 0; j < override.m_ScenarioPointsInUse.GetCount(); j++)
|
|
{
|
|
const CScenarioPoint* pt = override.m_ScenarioPointsInUse[j];
|
|
if(pt)
|
|
{
|
|
RenderPoint(*pt, r, editing, pZone, &override, j);
|
|
}
|
|
}
|
|
|
|
if(!override.m_ScenarioPointsInUse.GetCount())
|
|
{
|
|
Assert(override.m_SpecificallyPreventArtPoints);
|
|
CEntity* pEntity = override.m_EntityCurrentlyAttachedTo;
|
|
if(pEntity)
|
|
{
|
|
|
|
Color32 color(150,222,209,255);
|
|
if(editing)
|
|
{
|
|
if(!ms_Editor.IsRegionSelected(r))
|
|
{
|
|
color.Set(100,100,100, 192); // Not in the current region.
|
|
}
|
|
else if(ms_Editor.IsEntitySelected(pEntity))
|
|
{
|
|
color.Set(255,16,16, 192); // Selected entity.
|
|
}
|
|
}
|
|
|
|
const Vec3V posV = pEntity->GetTransform().Transform(Average(VECTOR3_TO_VEC3V(pEntity->GetBoundingBoxMin()), VECTOR3_TO_VEC3V(pEntity->GetBoundingBoxMax())));
|
|
char text[128];
|
|
int numTexts = 0;
|
|
|
|
formatf(text, "Spawning disabled");
|
|
grcDebugDraw::Text(posV, color, 0, numTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text, false);
|
|
|
|
formatf(text, "Region %s", GetRegionDisplayName(r));
|
|
grcDebugDraw::Text(posV, color, 0, numTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text, false);
|
|
|
|
formatf(text, "Attached to %s.", pEntity->GetModelName());
|
|
grcDebugDraw::Text(posV, color, 0, numTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text, false);
|
|
|
|
if(override.m_EntityMayNotAlwaysExist)
|
|
{
|
|
formatf(text, "May not always exist.");
|
|
grcDebugDraw::Text(posV, color, 0, numTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
const Vec3V camPosV = VECTOR3_TO_VEC3V(camInterface::GetPos());
|
|
const ScalarV distSqV = DistSquared(camPosV, override.m_EntityPosition);
|
|
if(IsLessThanAll(distSqV, ScalarV(ms_fRenderDistance*ms_fRenderDistance)))
|
|
{
|
|
char text[128];
|
|
int numTexts = 0;
|
|
|
|
Color32 color = Color_grey40;
|
|
#if SCENARIO_VERIFY_ENTITY_OVERRIDES
|
|
if (ms_Editor.GetSelectedOverrideWithNoPropIndex() == i)
|
|
{
|
|
color = Color_brown;
|
|
}
|
|
else if(override.m_VerificationStatus == CScenarioEntityOverride::kVerificationStatusBroken)
|
|
{
|
|
if(override.m_EntityMayNotAlwaysExist)
|
|
{
|
|
color = Color_orange;
|
|
}
|
|
else
|
|
{
|
|
color = Color_red;
|
|
}
|
|
}
|
|
else if(override.m_VerificationStatus == CScenarioEntityOverride::kVerificationStatusBrokenProp)
|
|
{
|
|
color = Color_orange;
|
|
}
|
|
else if(override.m_VerificationStatus == CScenarioEntityOverride::kVerificationStatusWorking)
|
|
{
|
|
color = Color_DarkGreen;
|
|
}
|
|
else if(override.m_VerificationStatus == CScenarioEntityOverride::kVerificationStatusStruggling)
|
|
{
|
|
color = Color_yellow;
|
|
}
|
|
#endif // SCENARIO_VERIFY_ENTITY_OVERRIDES
|
|
|
|
const Vec3V posV = override.m_EntityPosition;
|
|
|
|
if(override.m_EntityMayNotAlwaysExist)
|
|
{
|
|
formatf(text, "May not always exist.");
|
|
grcDebugDraw::Text(posV, color, 0, numTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text, false);
|
|
}
|
|
|
|
formatf(text, "Override not bound to prop: %s", override.m_EntityType.GetCStr());
|
|
grcDebugDraw::Text(posV, color, 0, numTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text, false);
|
|
|
|
formatf(text, "Region %s", GetRegionDisplayName(r));
|
|
grcDebugDraw::Text(posV, color, 0, numTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text, false);
|
|
|
|
if(override.m_ScenarioPoints.GetCount())
|
|
{
|
|
formatf(text, "Attached scenarios:");
|
|
grcDebugDraw::Text(posV, color, 0, numTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text, false);
|
|
|
|
for(int i = 0; i < override.m_ScenarioPoints.GetCount(); i++)
|
|
{
|
|
formatf(text, " %s", override.m_ScenarioPoints[i].m_spawnType.GetCStr());
|
|
grcDebugDraw::Text(posV, color, 0, numTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text, false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(override.m_SpecificallyPreventArtPoints)
|
|
{
|
|
formatf(text, "No scenarios, just for disabling spawning");
|
|
}
|
|
else
|
|
{
|
|
formatf(text, "Possibly invalid, no scenarios found");
|
|
}
|
|
grcDebugDraw::Text(posV, color, 0, numTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Chaining Graph
|
|
const CScenarioChainingGraph& graph = bankRegion.GetChainingGraph();
|
|
const int numEdges = graph.GetNumEdges();
|
|
for(int e = 0; e < numEdges; e++)
|
|
{
|
|
RenderChainEdge(graph, graph.GetEdge(e), editing, pZone);
|
|
}
|
|
}
|
|
|
|
//Render the Chaining stats
|
|
if (ms_bRenderChainPointUsage)
|
|
{
|
|
#if DR_ENABLED
|
|
const CScenarioChainingGraph& graph = bankRegion.GetChainingGraph();
|
|
|
|
const char* rname = SCENARIOPOINTMGR.GetRegionName(r);
|
|
int length = istrlen(rname);
|
|
int noff = 0;
|
|
for (int c = 0; c < length; c++)
|
|
{
|
|
if (rname[c] == '/' || rname[c] == '\\')
|
|
{
|
|
noff = c+1;
|
|
}
|
|
}
|
|
const char* name = &rname[noff];
|
|
graph.RenderUsage(name, screenSpew);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
#if DR_ENABLED
|
|
if(ms_bRenderChainPointUsage)
|
|
{
|
|
for(int u=0; u < CScenarioPointChainUseInfo::_ms_pPool->GetSize(); u++)
|
|
{
|
|
CScenarioPointChainUseInfo* pUser = CScenarioPointChainUseInfo::_ms_pPool->GetSlot(u);
|
|
if(pUser && !pUser->IsIndexInfoValid())
|
|
{
|
|
CScenarioChain::RenderUsageSingle("-none-", *pUser, screenSpew);
|
|
}
|
|
}
|
|
}
|
|
#endif // DR_ENABLED
|
|
|
|
//Entity Points
|
|
if (ms_bRenderScenarioPoints || editing)
|
|
{
|
|
int eCount = SCENARIOPOINTMGR.GetNumEntityPoints();
|
|
int p;
|
|
for (p = 0; p < eCount; ++p)
|
|
{
|
|
const CScenarioPoint& pt = SCENARIOPOINTMGR.GetEntityPoint(p);
|
|
if(!pt.IsEntityOverridePoint())
|
|
{
|
|
RenderPoint(pt, -1, editing, pZone);
|
|
}
|
|
}
|
|
int wCount = SCENARIOPOINTMGR.GetNumWorldPoints();
|
|
for (p = 0; p < wCount; ++p)
|
|
{
|
|
RenderPoint(SCENARIOPOINTMGR.GetWorldPoint(p), -1, editing, pZone);
|
|
}
|
|
}
|
|
|
|
//Editor specific rendering
|
|
if (editing)
|
|
{
|
|
ms_Editor.Render();
|
|
}
|
|
}
|
|
|
|
//Random colors to use for debug display.
|
|
u32 s_ColorArray[] = {
|
|
0xffA57069
|
|
,0xff441906
|
|
,0xff5E1580
|
|
,0xff6E3A50
|
|
,0xffA129AB
|
|
,0xffB50256
|
|
,0xffCABD3B
|
|
,0xff48A5E3
|
|
,0xff5518F6
|
|
,0xff998B22
|
|
,0xff6E770D
|
|
,0xffED79AA
|
|
,0xff5E3F41
|
|
,0xff296326
|
|
,0xffABF272
|
|
,0xff5E0D51
|
|
,0xffA4E1E9
|
|
,0xffC38F2C
|
|
,0xff146788
|
|
,0xffD34D6B
|
|
,0xffFBA080
|
|
,0xff124042
|
|
,0xff905108
|
|
,0xffE1D495
|
|
,0xffD6814F
|
|
,0xffD3A733
|
|
,0xff756C6A
|
|
,0xffFFB41C
|
|
,0xffDFDA46
|
|
,0xff01D921
|
|
,0xff805278
|
|
,0xff6FECC4
|
|
,0xff7B4205
|
|
,0xffED5C89
|
|
,0xff28A01D
|
|
,0xff19D6C5
|
|
,0xffF25EF1
|
|
,0xff26C69D
|
|
,0xffC8A142
|
|
,0xffB7B57C
|
|
,0xff396003
|
|
,0xff6F5CD5
|
|
,0xffD0BA74
|
|
,0xff74D262
|
|
,0xff519071
|
|
,0xffDAB4BB
|
|
,0xff71BCD8
|
|
,0xff1B9D60
|
|
,0xff2E4F0A
|
|
,0xff26CB73
|
|
,0xffD4D998
|
|
,0xff40AFD8
|
|
,0xff8F32CA
|
|
,0xff2E87E9
|
|
,0xff200EC7
|
|
,0xff2ACF35
|
|
,0xff885282
|
|
,0xffA11E3D
|
|
,0xff96C1DB
|
|
,0xffA0CAF9
|
|
,0xffA11E3D
|
|
,0xff48F9B8
|
|
,0xffC69D5C
|
|
,0xffBE28F0
|
|
,0xff4A0050
|
|
,0xff981C62
|
|
,0xff4AA346
|
|
,0xffC0D5E2
|
|
,0xff290420
|
|
,0xff56B661
|
|
,0xff6097C0
|
|
,0xff91B45F
|
|
,0xffB1086E
|
|
,0xffB88BDA
|
|
,0xffC20886
|
|
,0xff9F6363
|
|
,0xff304F59
|
|
,0xffF0AF91
|
|
,0xffE49607
|
|
,0xff0C9042
|
|
,0xff7E1E18
|
|
,0xff25874E
|
|
,0xff13EC27
|
|
,0xffD0C77C
|
|
,0xffE7888D
|
|
,0xffA0BCED
|
|
,0xff412D86
|
|
,0xffBA996C
|
|
,0xff14DDB4
|
|
,0xff9AC234
|
|
,0xff0D5B94
|
|
,0xff9E5BBE
|
|
,0xff168B0E
|
|
,0xff7125FE
|
|
,0xff9896BC
|
|
,0xffBB9073
|
|
,0xff4019BD
|
|
,0xff8D3093
|
|
,0xffF15164
|
|
,0xff00D968
|
|
,0xff61301B
|
|
,0xff36B507
|
|
,0xff38568E
|
|
,0xffA70F97
|
|
,0xff3A703E
|
|
,0xff89FC91
|
|
,0xff7D7338
|
|
,0xffB600D8
|
|
,0xffF70F69
|
|
,0xff7D7338
|
|
,0xffC21CFB
|
|
,0xffE796AC
|
|
,0xffE63E60
|
|
,0xff65775D
|
|
,0xff0C64A0
|
|
,0xffC73D33
|
|
,0xff81A185
|
|
,0xffE6B142
|
|
,0xff1B892D
|
|
,0xff63AD85
|
|
,0xffE4C220
|
|
,0xff5A20CA
|
|
,0xff5B01D5
|
|
,0xff3F0B83
|
|
,0xff9F73DF
|
|
,0xff8C35E5
|
|
,0xff54074D
|
|
,0xff1A91B6
|
|
};
|
|
|
|
void CScenarioDebug::RenderModelSetsOnVectorMap()
|
|
{
|
|
//Find the points within the radius
|
|
Vector3 pPos = camInterface::GetPos();
|
|
CScenarioPoint* areaPoints[CScenarioPointManager::kMaxPtsInArea];
|
|
const s32 foundCount = SCENARIOPOINTMGR.FindPointsInArea(RCC_VEC3V(pPos), ScalarV(100.0f), areaPoints, NELEM(areaPoints));
|
|
|
|
char text[128];
|
|
float lines = 0;
|
|
const float offset = 0.015f;
|
|
short textPrinted[20];
|
|
for (int i = 0; i < NELEM(textPrinted); i++)
|
|
{
|
|
textPrinted[i] = -1;
|
|
}
|
|
const float spawnradius = 5.0f; //read from somewhere ...
|
|
int totalPedSets = CAmbientModelSetManager::GetInstance().GetNumModelSets(CAmbientModelSetManager::kPedModelSets);
|
|
for (int i = 0; i < foundCount; i++)
|
|
{
|
|
const CScenarioPoint& point = *(areaPoints[i]);
|
|
|
|
const CEntity* pEntity = point.GetEntity();
|
|
if((pEntity && (!pEntity->m_nFlags.bWillSpawnPeds && !point.IsEntityOverridePoint()))
|
|
|| point.IsFlagSet(CScenarioPointFlags::NoSpawn))
|
|
{
|
|
continue;
|
|
}
|
|
if(!CScenarioManager::CheckScenarioPointMapData(point))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const int virtualType = point.GetScenarioTypeVirtualOrReal();
|
|
const int numRealTypes = SCENARIOINFOMGR.GetNumRealScenarioTypes(virtualType);
|
|
|
|
for(int j = 0; j < numRealTypes; j++)
|
|
{
|
|
if(!CScenarioManager::CheckScenarioPointEnabled(point, j))
|
|
{
|
|
continue;
|
|
}
|
|
if(!CScenarioManager::CheckScenarioPointTimesAndProbability(point, false, false, j))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const int realType = SCENARIOINFOMGR.GetRealScenarioType(virtualType, j);
|
|
const CScenarioInfo* pScenarioInfo = CScenarioManager::GetScenarioInfo(realType);
|
|
if(pScenarioInfo && pScenarioInfo->GetSpawnProbability() <= 0.0f)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//Modelset
|
|
bool drawSet = false;
|
|
CAmbientModelSetManager::ModelSetType setType = CAmbientModelSetManager::kPedModelSets;
|
|
if(CScenarioManager::IsVehicleScenarioType(point.GetScenarioTypeVirtualOrReal()))
|
|
{
|
|
setType = CAmbientModelSetManager::kVehicleModelSets;
|
|
}
|
|
unsigned modelSetId = point.GetModelSetIndex();
|
|
if(modelSetId != CScenarioPointManager::kNoCustomModelSet)
|
|
{
|
|
drawSet = true;
|
|
}
|
|
else
|
|
{
|
|
if (pScenarioInfo && pScenarioInfo->GetModelSet() && pScenarioInfo->GetIsFlagSet(CScenarioInfoFlags::ForceModel))
|
|
{
|
|
u32 modelSetHash = pScenarioInfo->GetModelSet()->GetHash();
|
|
modelSetHash = CScenarioManager::LegacyDefaultModelSetConvert(modelSetHash);
|
|
if(modelSetHash !=0 && modelSetHash!=CScenarioManager::MODEL_SET_USE_POPULATION)
|
|
{
|
|
// Even if this is a vehicle scenario, CScenarioInfo::GetModelSet() is still a ped model set.
|
|
setType = CAmbientModelSetManager::kPedModelSets;
|
|
|
|
int index = CAmbientModelSetManager::GetInstance().GetModelSetIndexFromHash(setType, modelSetHash);
|
|
if (aiVerifyf(index != -1, "Unknown %s modelset hash %d 0x%x", (setType == CAmbientModelSetManager::kPedModelSets) ? "Ped" : "Vehicle", modelSetHash, modelSetHash))
|
|
{
|
|
Assign(modelSetId, (unsigned)index);
|
|
drawSet = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(drawSet)
|
|
{
|
|
//figure out color.
|
|
const int colorCnt = NELEM(s_ColorArray);
|
|
const int colorOff = (setType == CAmbientModelSetManager::kVehicleModelSets) ? totalPedSets : 0;
|
|
const int colorIdx = (modelSetId + colorOff) % colorCnt;
|
|
const Color32 color = Color32(s_ColorArray[colorIdx]);
|
|
|
|
//Draw
|
|
fwVectorMap::DrawCircle(VEC3V_TO_VECTOR3(point.GetPosition()), spawnradius, color, false);
|
|
|
|
//figure out if we drew text before
|
|
bool drawText = true;
|
|
int cur = 0;
|
|
const int maxPrint = NELEM(textPrinted);
|
|
while(cur < maxPrint && textPrinted[cur] != -1)
|
|
{
|
|
if (textPrinted[cur] == (int)(modelSetId + colorOff))
|
|
{
|
|
drawText = false;
|
|
break;
|
|
}
|
|
cur++;
|
|
}
|
|
|
|
//draw it if we can.
|
|
if (drawText && aiVerifyf(cur < maxPrint, "CScenarioDebug::RenderModelSetsOnVectorMap Not enough elements in printed text history please add more."))
|
|
{
|
|
formatf(text, "%s", CAmbientModelSetManager::GetInstance().GetModelSet(setType, modelSetId).GetName());
|
|
grcDebugDraw::Text(Vec2V(0.75f, 0.12f+(lines*offset)), color, text, false, 1.0f, 1.0f);
|
|
lines += 1.0f;
|
|
Assign(textPrinted[cur], (int)(modelSetId + colorOff));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CScenarioDebug::RenderPoint(const CScenarioPoint& point, int regionIndex, bool editorActive, CPopZone* pZone, const CScenarioEntityOverride* pEntityOverride, int index)
|
|
{
|
|
if (CanRenderPoint(point, pZone) && !ms_bAnimDebugDisableSPRender)
|
|
{
|
|
Color32 color = Color_grey;
|
|
Vec3V vPos = point.GetPosition();
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Text display
|
|
char text[128];
|
|
point.FindDebugColourAndText(&color, text, sizeof(text));
|
|
if (!point.IsEditable() && point.IsFromRsc())
|
|
{
|
|
// Override the color for none editable points
|
|
color = Color_blue;
|
|
}
|
|
if (ms_bRenderPointText)
|
|
{
|
|
s32 iNumTexts = 0;
|
|
grcDebugDraw::Text(vPos, color, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text);
|
|
|
|
if (point.HasTimeOverride())
|
|
{
|
|
formatf( text, "Time (Overridden: %i -> %i)", point.GetTimeStartOverride(), point.GetTimeEndOverride() );
|
|
Color32 col = Color_red;
|
|
if (CClock::IsTimeInRange(point.GetTimeStartOverride(), point.GetTimeEndOverride()))
|
|
{
|
|
col = Color_green;
|
|
}
|
|
grcDebugDraw::Text(vPos, col, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text);
|
|
}
|
|
else
|
|
{
|
|
formatf( text, "Time (Default for scenario)");
|
|
grcDebugDraw::Text(vPos, Color_blue, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text);
|
|
}
|
|
|
|
if(point.IsAvailability(CScenarioPoint::kOnlySp))
|
|
{
|
|
Color32 col = CNetwork::IsGameInProgress() ? Color_red : Color_green;
|
|
grcDebugDraw::Text(vPos, col, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "Only in SP");
|
|
}
|
|
else if(point.IsAvailability(CScenarioPoint::kOnlyMp))
|
|
{
|
|
Color32 col = CNetwork::IsGameInProgress() ? Color_green : Color_red;
|
|
grcDebugDraw::Text(vPos, col, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "Only in MP");
|
|
}
|
|
|
|
if(point.HasTimeTillPedLeaves())
|
|
{
|
|
float time = point.GetTimeTillPedLeaves();
|
|
if(time < 0.0f)
|
|
{
|
|
formatf(text, "Never leave.");
|
|
}
|
|
else
|
|
{
|
|
formatf(text, "Leave after %.0f s", time);
|
|
}
|
|
grcDebugDraw::Text(vPos, color, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text);
|
|
}
|
|
|
|
if(point.HasProbabilityOverride())
|
|
{
|
|
if(point.GetProbabilityOverrideAsIntPercentage() < 100)
|
|
{
|
|
Color32 col = CScenarioManager::CheckScenarioProbability(&point, -1 /* shouldn't be used */) ? Color_green : Color_red;
|
|
formatf(text, "Probability %.0f %% (from point).", 100.0f*point.GetProbabilityOverride());
|
|
grcDebugDraw::Text(vPos, col, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const int scenarioType = point.GetScenarioTypeVirtualOrReal();
|
|
if(!SCENARIOINFOMGR.IsVirtualIndex(scenarioType))
|
|
{
|
|
CScenarioInfo* pInfo = SCENARIOINFOMGR.GetScenarioInfoByIndex(scenarioType);
|
|
if(pInfo && pInfo->GetSpawnProbability() < 0.999f && pInfo->GetSpawnProbability() > 0.001f)
|
|
{
|
|
Color32 col = CScenarioManager::CheckScenarioProbability(&point, scenarioType) ? Color_green : Color_red;
|
|
formatf(text, "Probability %.0f %% (from type).", 100.0f*pInfo->GetSpawnProbability());
|
|
grcDebugDraw::Text(vPos, col, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (point.GetScenarioGroup() != CScenarioPointManager::kNoGroup)
|
|
{
|
|
const CScenarioPointGroup& grp = SCENARIOPOINTMGR.GetGroupByIndex(point.GetScenarioGroup()-1);
|
|
formatf(text, "Group %s", grp.GetName());
|
|
grcDebugDraw::Text(vPos, color, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
{
|
|
//model set info ...
|
|
CAmbientModelSetManager::ModelSetType setType = CAmbientModelSetManager::kPedModelSets;
|
|
const char* type = "Ped";
|
|
if(CScenarioManager::IsVehicleScenarioType(point.GetScenarioTypeVirtualOrReal()))
|
|
{
|
|
setType = CAmbientModelSetManager::kVehicleModelSets;
|
|
type = "Vehicle";
|
|
}
|
|
|
|
if (point.GetModelSetIndex() == CScenarioPointManager::kNoCustomModelSet)
|
|
{
|
|
formatf(text, "%s ModelSet UsePopulation", type);
|
|
}
|
|
else
|
|
{
|
|
formatf(text, "%s ModelSet %s", type, CAmbientModelSetManager::GetInstance().GetModelSet(setType, point.GetModelSetIndex()).GetName());
|
|
}
|
|
grcDebugDraw::Text(vPos, color, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text);
|
|
}
|
|
|
|
float fRadius = point.GetRadius();
|
|
if (fRadius > 0.0f)
|
|
{
|
|
formatf(text, "Radius: %2f", fRadius);
|
|
grcDebugDraw::Text(vPos, color, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text);
|
|
}
|
|
|
|
if (point.IsFlagSet(CScenarioPointFlags::StationaryReactions))
|
|
{
|
|
formatf(text, "Stationary reactions enabled.");
|
|
grcDebugDraw::Text(vPos, color, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text);
|
|
}
|
|
|
|
|
|
if (regionIndex != -1)
|
|
{
|
|
// Since peds can now only start using chains at a node with no incoming links, it's handy
|
|
// to have some visual indication of which ones those are.
|
|
if(point.IsChained())
|
|
{
|
|
const CScenarioPointRegion* region = SCENARIOPOINTMGR.GetRegion(regionIndex);
|
|
Assert(region);//any point with a regionIndex must have a streamed in region.
|
|
|
|
if(!region->IsChainedWithIncomingEdges(point))
|
|
{
|
|
grcDebugDraw::Text(vPos, color, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "Chain entry point");
|
|
}
|
|
}
|
|
|
|
//Display the name of the region this point is in
|
|
const char* name = GetRegionDisplayName(regionIndex);
|
|
|
|
char interiorInfo[256];
|
|
interiorInfo[0] = '\0';
|
|
const unsigned int interiorId = point.GetInterior();
|
|
if(interiorId != CScenarioPointManager::kNoInterior)
|
|
{
|
|
const char* interiorName = SCENARIOPOINTMGR.GetInteriorName(interiorId - 1);
|
|
formatf(interiorInfo, " (in %s)", interiorName);
|
|
}
|
|
|
|
formatf(text, "Region %s%s", name, interiorInfo);
|
|
grcDebugDraw::Text(vPos, color, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text);
|
|
|
|
formatf(text, "Source %s", GetRegionSource(regionIndex));
|
|
grcDebugDraw::Text(vPos, color, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text);
|
|
|
|
if(point.GetRequiredIMap() != CScenarioPointManager::kNoRequiredIMap)
|
|
{
|
|
u32 rimHash = SCENARIOPOINTMGR.GetRequiredIMapHash(point.GetRequiredIMap());
|
|
strLocalIndex rimSlot = strLocalIndex(SCENARIOPOINTMGR.GetRequiredIMapSlotId(point.GetRequiredIMap()));
|
|
const char* status = "not found";
|
|
bool loaded = false;
|
|
if(rimSlot.Get() != CScenarioPointManager::kRequiredImapIndexInMapDataStoreNotFound)
|
|
{
|
|
fwMapDataDef* def = fwMapDataStore::GetStore().GetSlot(rimSlot);
|
|
if(def)
|
|
{
|
|
if(def->IsLoaded())
|
|
{
|
|
status = "loaded";
|
|
loaded = true;
|
|
}
|
|
else
|
|
{
|
|
status = "not loaded";
|
|
}
|
|
}
|
|
}
|
|
|
|
Color32 col = loaded ? Color_green : Color_red;
|
|
|
|
atHashString str(rimHash);
|
|
formatf(text, "Requires IMAP %s (%s)", str.GetCStr(), status);
|
|
grcDebugDraw::Text(vPos, col, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text);
|
|
}
|
|
|
|
if(point.IsEntityOverridePoint())
|
|
{
|
|
CEntity* pEntity = point.GetEntity();
|
|
if(Verifyf(pEntity, "Expected entity if m_bEntityOverridePoint is set."))
|
|
{
|
|
formatf(text, "Attached to %s", pEntity->GetModelName());
|
|
grcDebugDraw::Text(vPos, color, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text);
|
|
|
|
if(pEntityOverride && pEntityOverride->m_EntityMayNotAlwaysExist)
|
|
{
|
|
formatf(text, "Prop may not always exist.");
|
|
grcDebugDraw::Text(vPos, color, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// obstructed text
|
|
Color32 col = point.IsObstructed() ? Color_red : Color_green;
|
|
formatf(text, "Obstructed: %s PointIndex %d", point.IsObstructed() ? "true" : "false", index);
|
|
grcDebugDraw::Text(vPos, col, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), text);
|
|
if (point.IsObstructed())
|
|
{
|
|
grcDebugDraw::Sphere(vPos, 0.5f, col, true);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//Point
|
|
const Vec3V vPos2 = vPos + Vec3V(0.0f,0.0f,ms_fPointDrawRadius*2.0f);
|
|
const Vec3V vHandleOffset = point.GetDirection() * ScalarV(ms_fPointHandleLength);
|
|
|
|
bool selected = false;
|
|
if (editorActive && ms_Editor.IsPointSelected(point))
|
|
{
|
|
color.Set(255,16,16, 192); // selected point is red
|
|
selected = true;
|
|
}
|
|
else if (editorActive && regionIndex != -1 && !ms_Editor.IsRegionSelected(regionIndex))
|
|
{
|
|
color.Set(100,100,100, 192); // non selected region points are grey
|
|
}
|
|
|
|
if(point.IsEntityOverridePoint())
|
|
{
|
|
CEntity* pEntity = point.GetEntity();
|
|
if(pEntity)
|
|
{
|
|
Color32 colorDimmed = color;
|
|
colorDimmed.SetAlpha(colorDimmed.GetAlpha()/2);
|
|
|
|
const Vec3V entityPosV = pEntity->GetTransform().Transform(Average(VECTOR3_TO_VEC3V(pEntity->GetBoundingBoxMin()), VECTOR3_TO_VEC3V(pEntity->GetBoundingBoxMax())));
|
|
grcDebugDraw::Line(point.GetPosition(), entityPosV, colorDimmed);
|
|
}
|
|
}
|
|
|
|
if (point.IsFromRsc())
|
|
{
|
|
grcDebugDraw::Cone(vPos, vPos2, ms_fPointDrawRadius, color, true);
|
|
}
|
|
else
|
|
{
|
|
grcDebugDraw::Sphere(vPos, ms_fPointDrawRadius, color);
|
|
}
|
|
grcDebugDraw::Line(vPos, vPos + vHandleOffset, color);
|
|
|
|
// Render associated area of this point.
|
|
if (ms_bRenderPointRadius)
|
|
{
|
|
float fRadius = point.GetRadius();
|
|
if (fRadius > 0.0f)
|
|
{
|
|
grcDebugDraw::Circle(vPos, fRadius, color, Vec3V(V_X_AXIS_WZERO), Vec3V(V_Y_AXIS_WZERO));
|
|
}
|
|
}
|
|
|
|
if (ms_bRenderIntoVectorMap)
|
|
{
|
|
fwVectorMap::DrawCircle(VEC3V_TO_VECTOR3(vPos), ms_fPointDrawRadius, color, false);
|
|
|
|
// if (!point.IsFlagSet(CScenarioPointFlags::NoSpawn))
|
|
// {
|
|
// Color32 color = Color_yellow4;
|
|
// if (point.IsInCluster())
|
|
// {
|
|
// color = Color_orange;
|
|
// if (point.GetUses())
|
|
// {
|
|
// color = Color_blue4;
|
|
// }
|
|
// }
|
|
// else if (point.GetUses())
|
|
// {
|
|
// color = Color_green2;
|
|
// }
|
|
//
|
|
// color.SetAlpha(128);
|
|
// static float sphereSize = 50.0f;
|
|
// fwVectorMap::DrawCircle(VEC3V_TO_VECTOR3(vPos), sphereSize, color);
|
|
// }
|
|
}
|
|
|
|
if (editorActive && selected && point.IsEditable())
|
|
{
|
|
if (ms_Editor.IsPointHandleHovered(point))
|
|
{
|
|
color.Set(255,255,16, 192); // hovered point handle is yellow
|
|
}
|
|
//draw the handle for changing the direction
|
|
grcDebugDraw::Sphere(vPos + vHandleOffset, ms_fPointHandleRadius, color, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CScenarioDebug::IsTimeInRange(u32 currHour, u32 startHour, u32 endHour)
|
|
{
|
|
if (startHour <= endHour)
|
|
{
|
|
if (currHour>=startHour && currHour<endHour)
|
|
{
|
|
return true;
|
|
}
|
|
else if (startHour == endHour && currHour == startHour)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else if (currHour>=startHour || currHour<endHour)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CScenarioDebug::CanRenderPoint(const CScenarioPoint& point, CPopZone* pZone)
|
|
{
|
|
if (ms_bRenderOnlyChainedPoints && !point.IsChained())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (ms_bRenderStationaryReactionsPointsOnly && !point.IsFlagSet(CScenarioPointFlags::StationaryReactions))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!CanRenderPointType(point.GetScenarioTypeVirtualOrReal()))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Check if all of the real scenario types are disabled.
|
|
const int numReal = SCENARIOINFOMGR.GetNumRealScenarioTypes(point.GetScenarioTypeVirtualOrReal());
|
|
bool enabled = false;
|
|
for(int i = 0; i < numReal; i++)
|
|
{
|
|
if(CScenarioManager::CheckScenarioPointEnabled(point, i))
|
|
{
|
|
enabled = true;
|
|
break;
|
|
}
|
|
}
|
|
const bool disabled = !enabled;
|
|
if(disabled && !ms_bRenderScenarioPointsDisabled)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const Vec3V v3Pos = point.GetPosition();
|
|
|
|
//Radius
|
|
const Vec3V vCameraPosition = VECTOR3_TO_VEC3V( camInterface::GetPos() );
|
|
const float distance2 = DistSquared( vCameraPosition, v3Pos).Getf();
|
|
if (distance2 > ms_fRenderDistance*ms_fRenderDistance)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//Frustum -- using the handle length because that is the longest part of the point
|
|
if (!camInterface::IsSphereVisibleInGameViewport(VEC3V_TO_VECTOR3(v3Pos), ms_fPointHandleLength))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (ms_bRenderSelectedScenarioGroup && (point.GetScenarioGroup() != (u32)ms_iScenarioGroupIndex))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//PopZone
|
|
Vector3 vPos = VEC3V_TO_VECTOR3(v3Pos);
|
|
bool passPopZone = (!pZone || (pZone && CPopZones::DoesPointLiesWithinPopZone( &vPos, pZone ) ));
|
|
|
|
//Time period
|
|
bool passTimePeriod = true;
|
|
if (ms_bRenderScenarioPointsOnlyInTimePeriod)
|
|
{
|
|
// if the point has no time restriction then it is always valid.
|
|
if (point.HasTimeOverride())
|
|
{
|
|
passTimePeriod = false;
|
|
|
|
// If the current time is within the restricted time
|
|
if (ms_bRenderScenarioPointsOnlyInTimePeriodCurrent)
|
|
{
|
|
if (IsTimeInRange(CClock::GetHour(), (u32)point.GetTimeStartOverride(), (u32)point.GetTimeEndOverride()))
|
|
passTimePeriod = true;
|
|
}
|
|
else
|
|
{
|
|
for (int hour = 0; hour < 24; hour++)
|
|
{
|
|
//If the time is in the points time
|
|
if (IsTimeInRange(hour, (u32)point.GetTimeStartOverride(), (u32)point.GetTimeEndOverride()))
|
|
{
|
|
//If the time is in the restricted time ...
|
|
if (IsTimeInRange(hour, ms_iRenderScenarioPointsOnlyInTimePeriodStart, ms_iRenderScenarioPointsOnlyInTimePeriodEnd))
|
|
{
|
|
passTimePeriod = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool passAvaliability = true;
|
|
if (
|
|
ms_iAvailabilityComboIndex != CScenarioPoint::kBoth &&
|
|
ms_iAvailabilityComboIndex != point.GetAvailability()
|
|
)
|
|
{
|
|
passAvaliability = false;
|
|
}
|
|
|
|
return (passPopZone && passTimePeriod && passAvaliability);
|
|
}
|
|
|
|
bool CScenarioDebug::CanRenderPointType(unsigned pointTypeVirtualOrReal)
|
|
{
|
|
// Check if the tickbox is enabled.
|
|
if (!ms_bRenderSelectedTypeOnly)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Check if the point type is the same as the currently selected type in the editor.
|
|
if (CScenarioDebug::ms_Editor.GetSelectedSpawnTypeIndex() == (int)pointTypeVirtualOrReal)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void CScenarioDebug::RenderChainEdge(const CScenarioChainingGraph& graph, const CScenarioChainingEdge& edge, bool editorActive, CPopZone* pZone)
|
|
{
|
|
const CScenarioPoint* pointFrom = graph.GetChainingNodeScenarioPoint(edge.GetNodeIndexFrom());
|
|
const CScenarioPoint* pointTo = graph.GetChainingNodeScenarioPoint(edge.GetNodeIndexTo());
|
|
if (pointFrom && pointTo) //both valid
|
|
{
|
|
if (!CanRenderPoint(*pointFrom, pZone) && !CanRenderPoint(*pointTo, pZone))
|
|
{
|
|
//Find the closest point on the edge to the camera
|
|
Vec3V vCameraPos = VECTOR3_TO_VEC3V(camInterface::GetPos());
|
|
Vec3V vClosestPoint = geomPoints::FindClosestPointSegToPoint(pointFrom->GetPosition(), pointTo->GetPosition() - pointFrom->GetPosition(), vCameraPos);
|
|
const float distance2 = DistSquared(vCameraPos, vClosestPoint).Getf();
|
|
if (distance2 > ms_fRenderDistance*ms_fRenderDistance)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//if one of the points is null then draw anyway
|
|
const CScenarioChainingNode& nodeFrom = graph.GetNode(edge.GetNodeIndexFrom());
|
|
const CScenarioChainingNode& nodeTo = graph.GetNode(edge.GetNodeIndexTo());
|
|
|
|
bool incomplete = false;
|
|
Vec3V pos1V;
|
|
if(pointFrom)
|
|
{
|
|
pos1V = pointFrom->GetPosition();
|
|
}
|
|
else
|
|
{
|
|
pos1V = nodeFrom.m_Position;
|
|
incomplete = true;
|
|
}
|
|
|
|
Vec3V pos2V;
|
|
if(pointTo)
|
|
{
|
|
pos2V = pointTo->GetPosition();
|
|
}
|
|
else
|
|
{
|
|
pos2V = nodeTo.m_Position;
|
|
incomplete = true;
|
|
}
|
|
|
|
Color32 color = CScenarioChainingEdge::GetNavModeColor(edge.GetNavMode());
|
|
if(incomplete)
|
|
{
|
|
color.Set(128, 128, 128, 255);
|
|
}
|
|
|
|
if (editorActive)
|
|
{
|
|
//check to see if the point is selected/hovered on/other?
|
|
if (ms_Editor.IsEdgeSelected(edge))
|
|
{
|
|
color.Set(255,16,16, 192); // selected edge is red
|
|
}
|
|
// else if (ms_Editor.IsEdgeHovered(edge))
|
|
// {
|
|
// color.Set(255,255,16, 192); // hovered edge is yellow
|
|
// }
|
|
}
|
|
|
|
grcDebugDraw::Arrow(pos1V, pos2V, 0.3f, color);
|
|
|
|
const CScenarioChainingEdge::eAction action = edge.GetAction();
|
|
if(action != CScenarioChainingEdge::kActionDefault && action < CScenarioChainingEdge::kNumActions)
|
|
{
|
|
grcDebugDraw::Text(Average(pos1V, pos2V), color, CScenarioChainingEdge::sm_ActionNames[(int)action], false);
|
|
}
|
|
|
|
if (ms_bRenderIntoVectorMap)
|
|
{
|
|
fwVectorMap::DrawLine(VEC3V_TO_VECTOR3(pos1V), VEC3V_TO_VECTOR3(pos2V), color, color);
|
|
}
|
|
}
|
|
|
|
|
|
const char* CScenarioDebug::GetRegionDisplayName(int regionIndex)
|
|
{
|
|
const char* name = SCENARIOPOINTMGR.GetRegionName(regionIndex);
|
|
int length = istrlen(name);
|
|
int offset = 0;
|
|
for (int c = 0; c < length; c++)
|
|
{
|
|
if (name[c] == '/' || name[c] == '\\')
|
|
{
|
|
offset = c+1;
|
|
}
|
|
}
|
|
return name + offset;
|
|
}
|
|
|
|
const char* CScenarioDebug::GetRegionSource(int regionIndex)
|
|
{
|
|
const char* name = SCENARIOPOINTMGR.GetRegionSource(regionIndex);
|
|
return name;
|
|
}
|
|
|
|
CPed* CScenarioDebug::GetFocusPed()
|
|
{
|
|
CEntity *pEnt = CGameWorld::FindLocalPlayer();
|
|
if(!pEnt || !pEnt->GetIsTypePed())
|
|
{
|
|
return NULL;
|
|
}
|
|
return static_cast<CPed*>(pEnt);
|
|
}
|
|
|
|
|
|
void CScenarioDebug::WarpToNextNearestScenarioCB()
|
|
{
|
|
CPed* pFocusPed = GetFocusPed();
|
|
if(!pFocusPed)
|
|
{
|
|
return;
|
|
}
|
|
const Vec3V playerPosV = pFocusPed->GetTransform().GetPosition();
|
|
|
|
// Clear the memory if the type changed.
|
|
const int scenarioType = ms_iScenarioComboIndex;
|
|
if(scenarioType != ms_WarpToNearestScenarioType)
|
|
{
|
|
ms_WarpToNearestScenarioType = scenarioType;
|
|
ms_WarpToNearestAlreadyVisited.Reset();
|
|
}
|
|
|
|
// Prepare to loop until success, which normally would just take one iteration.
|
|
int found = 0;
|
|
int iter = 0;
|
|
while(1)
|
|
{
|
|
iter++;
|
|
if(iter > ms_WarpToNearestAlreadyVisited.GetSize())
|
|
{
|
|
// This is mostly a safety mechanism that's not expected to really happen, to make sure
|
|
// we can't end up in an infinite loop. Probably possible to hit this now if you put more scenario
|
|
// points in one single place than we have entries for in ms_WarpToNearestAlreadyVisited.
|
|
break;
|
|
}
|
|
|
|
// Look for a scenario of the right type, which we haven't warped to recently.
|
|
CScenarioDebugClosestFilterNotVisited filterVisited(scenarioType);
|
|
CScenarioPoint* pFoundPoint = GetClosestScenarioPoint(playerPosV, filterVisited);
|
|
|
|
if(pFoundPoint)
|
|
{
|
|
// If the memory is full, drop the oldest entry.
|
|
if(ms_WarpToNearestAlreadyVisited.IsFull())
|
|
{
|
|
ms_WarpToNearestAlreadyVisited.Drop();
|
|
}
|
|
|
|
// Remember that we have warped here.
|
|
ScenarioPointMemory m;
|
|
m.m_pScenarioPoint = pFoundPoint;
|
|
ms_WarpToNearestAlreadyVisited.Push(m);
|
|
|
|
// Try to warp to the new point.
|
|
if(WarpTo(*pFocusPed, *pFoundPoint))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// In this case, we may already be in the right spot. Since we've added this point to the memory
|
|
// now, just by doing another iteration we have a good chance of finding a different point.
|
|
found++;
|
|
}
|
|
else
|
|
{
|
|
// If we couldn't find any scenario which hasn't already been visited, we drop the oldest
|
|
// entry in the memory and try again, or break if the memory is empty.
|
|
if(ms_WarpToNearestAlreadyVisited.IsEmpty())
|
|
{
|
|
break;
|
|
}
|
|
ms_WarpToNearestAlreadyVisited.Drop();
|
|
}
|
|
}
|
|
|
|
// Whenever we didn't teleport successfully, give some written feedback to the user.
|
|
if(!found)
|
|
{
|
|
Displayf("No scenario points of type %s found.", ms_szScenarioNames[ms_iScenarioComboIndex]);
|
|
}
|
|
else
|
|
{
|
|
Displayf("No other scenario points of type %s found.", ms_szScenarioNames[ms_iScenarioComboIndex]);
|
|
}
|
|
}
|
|
|
|
|
|
void CScenarioDebug::WarpToPreviousScenarioCB()
|
|
{
|
|
CPed* pFocusPed = GetFocusPed();
|
|
if(!pFocusPed)
|
|
{
|
|
return;
|
|
}
|
|
const Vec3V playerPosV = pFocusPed->GetTransform().GetPosition();
|
|
|
|
// Clear the memory if the type changed.
|
|
const int scenarioType = ms_iScenarioComboIndex;
|
|
if(scenarioType != ms_WarpToNearestScenarioType)
|
|
{
|
|
ms_WarpToNearestScenarioType = scenarioType;
|
|
ms_WarpToNearestAlreadyVisited.Reset();
|
|
}
|
|
|
|
// Start looking back in the memory of previously visited scenarios.
|
|
while(!ms_WarpToNearestAlreadyVisited.IsEmpty())
|
|
{
|
|
// atQueue is normally FIFO, so we pop from the "end" to get the most recently
|
|
// visited one.
|
|
const ScenarioPointMemory& m = ms_WarpToNearestAlreadyVisited.PopEnd();
|
|
|
|
// While we already have the pointers we need, we can't be sure that the scenario
|
|
// and entity are still valid. By using GetClosestScenarioPoint(), we know that
|
|
// what we are about to access will be valid (in the unlikely very worst case,
|
|
// we could possibly find a different object if the same locations in memory got reused
|
|
// for other objects).
|
|
if (!m.m_pScenarioPoint)
|
|
continue;
|
|
|
|
CScenarioDebugClosestFilterSpecific filter(scenarioType, m.m_pScenarioPoint);
|
|
CScenarioPoint* pFoundPoint = GetClosestScenarioPoint(playerPosV, filter);
|
|
|
|
// Try to warp if this point existed.
|
|
if(pFoundPoint)
|
|
{
|
|
if(WarpTo(*pFocusPed, *pFoundPoint))
|
|
{
|
|
// Success!
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Queue empty, make sure to give some feedback.
|
|
Displayf("No previous scenario of type %s is stored.", ms_szScenarioNames[ms_iScenarioComboIndex]);
|
|
}
|
|
|
|
|
|
bool CScenarioDebug::WarpTo(CPed& focusPed, const CScenarioPoint& scenarioPt)
|
|
{
|
|
Vector3 pointPos = VEC3V_TO_VECTOR3(scenarioPt.GetPosition());
|
|
// Add on a little bit to spawn in front of the point
|
|
Vector3 vDir = VEC3V_TO_VECTOR3(scenarioPt.GetDirection()) * 2.0f; // 2 meters away
|
|
pointPos += vDir;
|
|
// Need to get this to ground level
|
|
if(!CPedPlacement::FindZCoorForPed(BOTTOM_SURFACE,&pointPos, NULL, NULL, NULL, 1.0f, 99.5f, ArchetypeFlags::GTA_ALL_MAP_TYPES|ArchetypeFlags::GTA_VEHICLE_TYPE, NULL, false))
|
|
{
|
|
// If this fails, just assume the point is on ground level and add the Root offset
|
|
pointPos.z += PED_HUMAN_GROUNDTOROOTOFFSET;
|
|
}
|
|
|
|
Vec3V pointPosV = VECTOR3_TO_VEC3V(pointPos);
|
|
Vec3V focusPedPosV = focusPed.GetTransform().GetPosition();
|
|
ScalarV distThresholdSqV(0.2f);
|
|
ScalarV distSqV = DistSquared(pointPosV, focusPedPosV);
|
|
if(IsLessThanAll(distSqV, distThresholdSqV))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
focusPed.SetPosition(pointPos);
|
|
return true;
|
|
}
|
|
|
|
|
|
void CScenarioDebug::CreateAndActivateScenarioOnSelectedPedCB()
|
|
{
|
|
// Get the ped to use, and its position.
|
|
CEntity* pEnt = CDebugScene::FocusEntities_Get(0);
|
|
if(!pEnt)
|
|
{
|
|
pEnt = CGameWorld::FindLocalPlayer();
|
|
}
|
|
if(!pEnt || !pEnt->GetIsTypePed())
|
|
{
|
|
return;
|
|
}
|
|
CPed* pFocusPed = static_cast<CPed*>(pEnt);
|
|
const Vec3V pedPosV = pFocusPed->GetTransform().GetPosition();
|
|
|
|
CScenarioPoint* pPropScenarioPoint = NULL;
|
|
|
|
// Get the scenario type. This is the same as the index in the combobox now, but that wouldn't
|
|
// necessarily be the case if we wanted to sort the entries or something.
|
|
const int scenarioTypeToCreate = ms_iScenarioComboIndex;
|
|
|
|
CVehicle* pVehicleForScenario = NULL;
|
|
bool usesPoint = true;
|
|
|
|
bool needVehicle = false;
|
|
eVehicleScenarioType vehScenarioType = VSCENARIO_TYPE_UNKNOWN;
|
|
const CScenarioInfo* pScenarioInfo = NULL;
|
|
if(!SCENARIOINFOMGR.IsVirtualIndex(scenarioTypeToCreate))
|
|
{
|
|
pScenarioInfo = CScenarioManager::GetScenarioInfo(scenarioTypeToCreate);
|
|
if(pScenarioInfo->GetIsClass<CScenarioParkedVehicleInfo>())
|
|
{
|
|
needVehicle = true;
|
|
usesPoint = false;
|
|
vehScenarioType = static_cast<const CScenarioParkedVehicleInfo*>(pScenarioInfo)->GetVehicleScenarioType();
|
|
Displayf("Looking for a nearby vehicle for scenario %s:", pScenarioInfo->GetName());
|
|
}
|
|
}
|
|
|
|
if(needVehicle)
|
|
{
|
|
bool listedAny = false;
|
|
ScalarV closestDistSqV(square(30.0f));
|
|
CEntityScannerIterator nearbyVehicles = pFocusPed->GetPedIntelligence()->GetNearbyVehicles();
|
|
for( CEntity* pEnt = nearbyVehicles.GetFirst(); pEnt; pEnt = nearbyVehicles.GetNext())
|
|
{
|
|
CVehicle* pVehicle = static_cast<CVehicle*>(pEnt);
|
|
if(!pVehicle)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
listedAny = true;
|
|
|
|
const Vec3V vehiclePosV = pVehicle->GetTransform().GetPosition();
|
|
Printf(" %s at (%.0f, %.0f, %.0f): ", pVehicle->GetVehicleModelInfo()->GetModelName(),
|
|
vehiclePosV.GetXf(), vehiclePosV.GetYf(), vehiclePosV.GetZf());
|
|
|
|
if(pVehicle->GetVelocity().Mag2() >= square(0.1f))
|
|
{
|
|
Printf("moving, can't be used\n");
|
|
continue;
|
|
}
|
|
|
|
if(vehScenarioType == VSCENARIO_TYPE_BROKEN_DOWN_VEHICLE)
|
|
{
|
|
if(!CTaskParkedVehicleScenario::CanVehicleBeUsedForBrokenDownScenario(*pVehicle))
|
|
{
|
|
Printf("not allowed for broken down vehicle scenario\n");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
const ScalarV distSqV = DistSquared(pedPosV, vehiclePosV);
|
|
if(IsGreaterThanAll(distSqV, closestDistSqV))
|
|
{
|
|
Printf("too far away\n");
|
|
continue;
|
|
}
|
|
|
|
Printf("can be used\n");
|
|
closestDistSqV = distSqV;
|
|
pVehicleForScenario = pVehicle;
|
|
}
|
|
|
|
if(!listedAny)
|
|
{
|
|
Displayf("no vehicles nearby");
|
|
}
|
|
}
|
|
|
|
// If desired, look for an existing scenario.
|
|
if(usesPoint && ms_UseScenarioFindExisting)
|
|
{
|
|
CScenarioDebugClosestFilterScenarioType filter(scenarioTypeToCreate);
|
|
filter.m_IgnoreInUse = true;
|
|
CScenarioPoint* sp = GetClosestScenarioPoint(pedPosV, filter);
|
|
if(sp)
|
|
{
|
|
Vec3V ptPosV = sp->GetPosition();
|
|
ScalarV distSqThresholdV(square(8.0f));
|
|
if(IsLessThanAll(DistSquared(pedPosV, ptPosV), distSqThresholdV))
|
|
{
|
|
pPropScenarioPoint = sp;
|
|
Displayf("Found existing %s scenario.", ms_szScenarioNames[ms_iScenarioComboIndex]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we don't have a scenario to use yet, consider creating a prop with the desired
|
|
// scenario attached to it, if possible.
|
|
if(usesPoint && ms_UseScenarioCreateProp && !pPropScenarioPoint)
|
|
{
|
|
// Destroy any existing prop.
|
|
DestroyScenarioProp();
|
|
|
|
// Set up an array of prop types we can choose from.
|
|
static const int kMaxPropTypesUsingScenario = 128;
|
|
fwModelId propsToChooseFrom[kMaxPropTypesUsingScenario];
|
|
int numPropsToChooseFrom = 0;
|
|
|
|
// Loop over all models and look for prop types with the right scenario attached.
|
|
const int maxModelInfos = CModelInfo::GetMaxModelInfos();
|
|
for(int i = 0; i < maxModelInfos; i++)
|
|
{
|
|
// Check if this is an object with scenarios attached.
|
|
fwModelId modelId(strLocalIndex((u32)i));
|
|
CBaseModelInfo* modelInfo = CModelInfo::GetBaseModelInfo(modelId);
|
|
if(!modelInfo || !modelInfo->GetIsTypeObject() || !modelInfo->GetHasSpawnPoints())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Loop over the scenarios to see if any are of the right type.
|
|
GET_2D_EFFECTS_NOLIGHTS(modelInfo);
|
|
for(int j = 0; j < iNumEffects; j++)
|
|
{
|
|
Assert(pa2dEffects);
|
|
C2dEffect* pEffect = (*pa2dEffects)[j];
|
|
if(!pEffect)
|
|
{
|
|
continue;
|
|
}
|
|
if(pEffect->GetType() != ET_SPAWN_POINT)
|
|
{
|
|
continue;
|
|
}
|
|
const CSpawnPoint* spawnPt = pEffect->GetSpawnPoint();
|
|
if(!spawnPt)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
const int scenarioType = spawnPt->iType;
|
|
if(scenarioType == scenarioTypeToCreate && numPropsToChooseFrom < kMaxPropTypesUsingScenario)
|
|
{
|
|
// Found one, add to the array.
|
|
propsToChooseFrom[numPropsToChooseFrom++] = modelId;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// List all prop types that use the scenario, could be useful.
|
|
if(numPropsToChooseFrom > 0)
|
|
{
|
|
Displayf("Scenario is attached to the following props:");
|
|
for(int i = 0; i < numPropsToChooseFrom; i++)
|
|
{
|
|
CBaseModelInfo* pOtherModelInfo = CModelInfo::GetBaseModelInfo(propsToChooseFrom[i]);
|
|
if(!pOtherModelInfo)
|
|
{
|
|
continue;
|
|
}
|
|
Displayf(" %s", pOtherModelInfo->GetModelName());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Displayf("Scenario is not attached to any props.");
|
|
}
|
|
|
|
// Check if we found anything.
|
|
if(numPropsToChooseFrom > 0)
|
|
{
|
|
// Cycle through the props in order.
|
|
int chosen = ms_NextScenarioPropIndex;
|
|
if(chosen >= numPropsToChooseFrom)
|
|
{
|
|
chosen = 0;
|
|
}
|
|
ms_NextScenarioPropIndex = chosen + 1;
|
|
|
|
fwModelId modelId = propsToChooseFrom[chosen];
|
|
CBaseModelInfo* pModelInfo = CModelInfo::GetBaseModelInfo(modelId);
|
|
if(Verifyf(pModelInfo, "Expected model info."))
|
|
{
|
|
// Note: most of this object creation code was adapted from DisplayObject()
|
|
// in 'Debug.cpp'.
|
|
|
|
// Set up a matrix with a random rotation around the Z axis.
|
|
Matrix34 testMat;
|
|
testMat.Identity();
|
|
testMat.MakeRotateZ(g_ReplayRand.GetFloat()*2*PI);
|
|
|
|
// Compute the matrix to spawn at, in front of the debug camera or near the player.
|
|
Vector3 vecCreateOffset = camInterface::GetFront();
|
|
vecCreateOffset.z = 0.0f;
|
|
vecCreateOffset *= 2.0f + pModelInfo->GetBoundingSphereRadius();
|
|
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
|
|
if(debugDirector.IsFreeCamActive())
|
|
{
|
|
testMat.d = camInterface::GetPos();
|
|
testMat.d += vecCreateOffset;
|
|
}
|
|
else
|
|
{
|
|
if(ms_UseScenarioWarp)
|
|
{
|
|
// If warping and not using the debug camera, we don't add the camera's
|
|
// forward vector, because it's annoying if we keep translating around the world.
|
|
testMat.d = RCC_VECTOR3(pedPosV);
|
|
}
|
|
else
|
|
{
|
|
testMat.d = CGameWorld::FindLocalPlayerCoors();
|
|
testMat.d += vecCreateOffset;
|
|
}
|
|
}
|
|
|
|
// Stream in the object (note: not sure if we are supposed to unrequest the object somehow).
|
|
if(!CModelInfo::HaveAssetsLoaded(modelId))
|
|
{
|
|
CModelInfo::RequestAssets(modelId, STRFLAG_DONTDELETE|STRFLAG_FORCE_LOAD|STRFLAG_PRIORITY_LOAD);
|
|
CStreaming::LoadAllRequestedObjects(true);
|
|
}
|
|
|
|
// Create the object.
|
|
CObject* pObject = CObjectPopulation::CreateObject(modelId, ENTITY_OWNEDBY_RANDOM, true);
|
|
if(pObject)
|
|
{
|
|
// Create a transform and add to the world.
|
|
if (!pObject->GetTransform().IsMatrix())
|
|
{
|
|
//should never come here if ENABLE_MATRIX_MEMBER is set
|
|
#if ENABLE_MATRIX_MEMBER
|
|
Mat34V trans(V_IDENTITY);
|
|
ms_pScenarioProp->SetTransform(trans);
|
|
ms_pScenarioProp->SetTransformScale(1.0f, 1.0f);
|
|
#else
|
|
fwTransform *trans = rage_new fwMatrixTransform();
|
|
pObject->SetTransform(trans);
|
|
#endif
|
|
}
|
|
pObject->SetMatrix(testMat, true);
|
|
if(fragInst* pInst = pObject->GetFragInst())
|
|
{
|
|
pInst->SetResetMatrix(testMat);
|
|
}
|
|
CGameWorld::Add(pObject, CGameWorld::OUTSIDE );
|
|
|
|
// Snap to the ground.
|
|
pObject->PlaceOnGroundProperly(10.0f, false);
|
|
|
|
if(ms_UseFixedPhysicsForProps)
|
|
{
|
|
pObject->SetFixedPhysics(true);
|
|
}
|
|
|
|
// Next, we'll look for scenarios on the prop, as there may be more than one.
|
|
static const int kMaxPtsPerProp = 32;
|
|
CScenarioPoint* ptsOnProp[kMaxPtsPerProp];
|
|
int numPtsOnProp = SCENARIOPOINTMGR.FindPointsOfTypeForEntity(scenarioTypeToCreate, pObject, ptsOnProp, NELEM(ptsOnProp));
|
|
|
|
// Pick one at random.
|
|
if(Verifyf(numPtsOnProp > 0, "Expected scenario points on prop."))
|
|
{
|
|
const int ptIndex = g_ReplayRand.GetRanged(0, numPtsOnProp - 1);
|
|
pPropScenarioPoint = ptsOnProp[ptIndex];
|
|
}
|
|
|
|
Displayf("Created prop %s for %s scenario.", pModelInfo->GetModelName(), ms_szScenarioNames[ms_iScenarioComboIndex]);
|
|
|
|
ms_DebugScenarioProp = pObject;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool bUsePointForTask = true;
|
|
|
|
// If we haven't created or found a scenario already, create a temporary object now.
|
|
CScenarioPoint tempPoint;
|
|
if(usesPoint && !pPropScenarioPoint)
|
|
{
|
|
if(!taskVerifyf(CScenarioPoint::GetPool()->GetNoOfFreeSpaces() > 0, "Out of CScenarioPoint objects."))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Vec3V scenarioPosV = pedPosV;
|
|
|
|
// If warping, we use the ped's current position. If not, we find a point
|
|
// in front of the camera or near the player.
|
|
if(!ms_UseScenarioWarp)
|
|
{
|
|
Vec3V vecCreateOffsetV = RCC_VEC3V(camInterface::GetFront());
|
|
vecCreateOffsetV.SetZ(ScalarV(V_ZERO));
|
|
vecCreateOffsetV = Scale(vecCreateOffsetV, ScalarV(V_TWO));
|
|
|
|
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
|
|
if(debugDirector.IsFreeCamActive())
|
|
{
|
|
scenarioPosV = RCC_VEC3V(camInterface::GetPos());
|
|
scenarioPosV += vecCreateOffsetV;
|
|
}
|
|
else
|
|
{
|
|
scenarioPosV = VECTOR3_TO_VEC3V(CGameWorld::FindLocalPlayerCoors());
|
|
scenarioPosV += vecCreateOffsetV;
|
|
}
|
|
}
|
|
|
|
// Need to get this to ground level.
|
|
CPedPlacement::FindZCoorForPed(BOTTOM_SURFACE,&RC_VECTOR3(scenarioPosV), NULL, NULL, NULL, 0.5f, 99.5f, ArchetypeFlags::GTA_ALL_MAP_TYPES|ArchetypeFlags::GTA_VEHICLE_TYPE, NULL, true);
|
|
|
|
// Make use of this temporary object on the stack. It will never be inserted in the world
|
|
// as a scenario point, it's just used to set up the ped's task/position/heading.
|
|
pPropScenarioPoint = &tempPoint;
|
|
|
|
Assert((unsigned)scenarioTypeToCreate < MAX_SCENARIO_TYPES);
|
|
pPropScenarioPoint->SetScenarioType((unsigned)scenarioTypeToCreate);
|
|
|
|
Vector3 forward = VEC3V_TO_VECTOR3(pFocusPed->GetTransform().GetB());
|
|
pPropScenarioPoint->SetDirection(rage::Atan2f(-forward.x, forward.y));
|
|
pPropScenarioPoint->SetPosition(scenarioPosV);
|
|
pPropScenarioPoint->SetTimeStartOverride(0);
|
|
pPropScenarioPoint->SetTimeEndOverride(24);
|
|
pPropScenarioPoint->SetModelSetIndex(CScenarioPointManager::kNoCustomModelSet);
|
|
pPropScenarioPoint->SetInteriorState(CScenarioPoint::IS_Outside);
|
|
pPropScenarioPoint->SetScenarioGroup(CScenarioPointManager::kNoGroup);
|
|
pPropScenarioPoint->SetAvailability(CScenarioPoint::kBoth);
|
|
pPropScenarioPoint->SetEditable(false);
|
|
|
|
bUsePointForTask = false;
|
|
|
|
Displayf("Created temporary %s scenario.", ms_szScenarioNames[ms_iScenarioComboIndex]);
|
|
}
|
|
Assert(!usesPoint || pPropScenarioPoint);
|
|
|
|
|
|
bool bStartInCurrentPos = !ms_UseScenarioWarp;
|
|
|
|
if(pScenarioInfo && pScenarioInfo->GetIsClass<CScenarioParkedVehicleInfo>())
|
|
{
|
|
if(pVehicleForScenario)
|
|
{
|
|
CTask* pScenarioTask = pScenarioTask = rage_new CTaskParkedVehicleScenario(scenarioTypeToCreate, pVehicleForScenario);
|
|
pFocusPed->GetPedIntelligence()->AddTaskDefault(pScenarioTask);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
int scenarioTypeToCreateReal = CScenarioManager::ChooseRealScenario(scenarioTypeToCreate, pFocusPed);
|
|
|
|
pScenarioInfo = CScenarioManager::GetScenarioInfo(scenarioTypeToCreateReal);
|
|
|
|
float headingOut = 0.0f;
|
|
Vector3 posOut;
|
|
CTask* pScenarioTask = CScenarioManager::SetupScenarioAndTask( scenarioTypeToCreateReal, posOut, headingOut, *pPropScenarioPoint, 0, bStartInCurrentPos, bUsePointForTask, true );
|
|
aiTask* pControlTask = CScenarioManager::SetupScenarioControlTask(*pFocusPed, *pScenarioInfo, pScenarioTask, pPropScenarioPoint, scenarioTypeToCreateReal);
|
|
pFocusPed->GetPedIntelligence()->AddTaskDefault(pControlTask);
|
|
}
|
|
}
|
|
|
|
void CScenarioDebug::DeActivateScenarioOnSelectedPedCB()
|
|
{
|
|
CEntity* pEnt = CDebugScene::FocusEntities_Get(0);
|
|
if (!pEnt)
|
|
{
|
|
pEnt = CGameWorld::FindLocalPlayer();
|
|
}
|
|
|
|
if( pEnt && pEnt->GetIsTypePed() )
|
|
{
|
|
CPed* pFocusPed = static_cast<CPed*>(pEnt);
|
|
|
|
CTask* pScenarioTask = pFocusPed->GetPedIntelligence()->GetTaskActive();
|
|
if(pScenarioTask)
|
|
{
|
|
CTask::AbortPriority pri = ms_StopTargetPedImmediate ? CTask::ABORT_PRIORITY_IMMEDIATE : CTask::ABORT_PRIORITY_URGENT;
|
|
pScenarioTask->MakeAbortable(pri, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CScenarioDebug::DestroyScenarioProp()
|
|
{
|
|
if(!ms_DebugScenarioProp)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CObject* prop = ms_DebugScenarioProp;
|
|
CGameWorld::Remove(prop);
|
|
CObjectPopulation::DestroyObject(prop);
|
|
ms_DebugScenarioProp = NULL;
|
|
}
|
|
|
|
void CScenarioDebug::LoadPropOffsetsCB()
|
|
{
|
|
s32 iNumScenarios = SCENARIOINFOMGR.GetScenarioCount(false);
|
|
|
|
for (s32 i=0; i<iNumScenarios; i++)
|
|
{
|
|
CScenarioInfo* pScenarioInfo = SCENARIOINFOMGR.GetScenarioInfoByIndex(i);
|
|
if (taskVerifyf(pScenarioInfo, "NULL scenario info"))
|
|
{
|
|
if (pScenarioInfo->GetSpawnPropOffsetDictHash() != 0 && pScenarioInfo->GetSpawnPropOffsetClipHash() !=0)
|
|
{
|
|
strLocalIndex iDictIndex = fwAnimManager::FindSlotFromHashKey(pScenarioInfo->GetSpawnPropOffsetDictHash());
|
|
if (taskVerifyf(iDictIndex != -1, "Couldn't find clip dictionary %s", pScenarioInfo->GetSpawnPropIntroDictName()))
|
|
{
|
|
// Stream in the clip dictionary
|
|
CStreaming::RequestObject(iDictIndex, fwAnimManager::GetStreamingModuleId(), STRFLAG_FORCE_LOAD);
|
|
CStreaming::LoadAllRequestedObjects();
|
|
const crClip* pClip = fwAnimManager::GetClipIfExistsByDictIndex(iDictIndex.Get(), pScenarioInfo->GetSpawnPropOffsetClipHash());
|
|
if (taskVerifyf(pClip, "Couldn't find clip %s in dictionary %s", pScenarioInfo->GetSpawnPropIntroClipName(), pScenarioInfo->GetSpawnPropIntroDictName()))
|
|
{
|
|
Vector3 vTransOffset(Vector3::ZeroType);
|
|
Quaternion qRotationalOffset(0.0f, 0.0f, 0.0f, 1.0f);
|
|
if (fwAnimHelpers::ApplyInitialOffsetFromClip(*pClip, vTransOffset, qRotationalOffset))
|
|
{
|
|
pScenarioInfo->SetSpawnPropOffset(vTransOffset);
|
|
pScenarioInfo->SetSpawnPropRotationalOffset(qRotationalOffset);
|
|
}
|
|
}
|
|
CStreaming::RemoveObject(iDictIndex, fwAnimManager::GetStreamingModuleId());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CScenarioDebug::ForceSpawnInAreaCB()
|
|
{
|
|
Vector3 v1, v2;
|
|
if( !CPhysics::GetMeasuringToolPos( 0, v1 ) ||
|
|
!CPhysics::GetMeasuringToolPos( 1, v2 ) )
|
|
{
|
|
v1 = VEC3V_TO_VECTOR3(CGameWorld::FindLocalPlayer()->GetTransform().GetPosition());
|
|
v2 = v1;
|
|
v2.x += 80.0f;
|
|
}
|
|
const bool allowDeepInteriors = true;
|
|
CPedPopulation::GenerateScenarioPedsInSpecificArea(v1, allowDeepInteriors, (v1-v2).Mag(), 100);
|
|
}
|
|
|
|
void CScenarioDebug::ClearSpawnHistoryCB()
|
|
{
|
|
CScenarioManager::GetSpawnHistory().ClearHistory();
|
|
CScenarioManager::GetVehicleScenarioManager().ClearAttractionTimers();
|
|
}
|
|
|
|
void CScenarioDebug::ReloadAmbientData()
|
|
{
|
|
// CAmbientAnimationManager::UnloadData();
|
|
// CAmbientAnimationManager::LoadData();
|
|
}
|
|
|
|
void CScenarioDebug::GiveRandomProp()
|
|
{
|
|
for(int i = 0; i < CDebugScene::FOCUS_ENTITIES_MAX; ++i)
|
|
{
|
|
CEntity* pEnt = CDebugScene::FocusEntities_Get(i);
|
|
if( pEnt && pEnt->GetIsTypePed() )
|
|
{
|
|
CPed* pFocusPed = static_cast<CPed*>(pEnt);
|
|
|
|
u32 uiPropHash;
|
|
int animIndex = -1;
|
|
const CConditionalAnimsGroup* pGrp = CONDITIONALANIMSMGR.GetConditionalAnimsGroup("WANDER");
|
|
CScenarioCondition::sScenarioConditionData conditionData;
|
|
conditionData.pPed = pFocusPed;
|
|
if( pGrp && CAmbientAnimationManager::RandomlyChoosePropForSpawningPed( conditionData, pGrp, uiPropHash, animIndex, -1) )
|
|
{
|
|
const CConditionalAnims* pAnims = pGrp->GetAnims(animIndex);
|
|
strStreamingObjectName prop;
|
|
prop.SetHash( uiPropHash );
|
|
CTaskAmbientClips* pTask = static_cast<CTaskAmbientClips *>(pFocusPed->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_AMBIENT_CLIPS));
|
|
if (pTask)
|
|
{
|
|
pTask->GivePedProp( prop, pAnims->GetCreatePropInLeftHand(), pAnims->ShouldDestroyPropInsteadOfDropping() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CScenarioDebug::GivePedAmbientTaskCB()
|
|
{
|
|
CEntity* pEnt = CDebugScene::FocusEntities_Get(0);
|
|
|
|
if (!pEnt)
|
|
{
|
|
pEnt = CGameWorld::FindLocalPlayer();
|
|
}
|
|
|
|
if (pEnt && pEnt->GetIsTypePed() && ms_ConditionalAnimNames.GetCount() > 0)
|
|
{
|
|
CPed* pFocusPed = static_cast<CPed*>(pEnt);
|
|
const ConditionalAnimData& d = ms_ConditionalAnims[ms_iAmbientContextComboIndex];
|
|
|
|
CTaskComplexControlMovement* pControlTask = static_cast<CTaskComplexControlMovement*>(pFocusPed->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_COMPLEX_CONTROL_MOVEMENT));
|
|
if (pControlTask)
|
|
{
|
|
u32 flags = GetAmbientFlags();
|
|
pControlTask->SetNewMainSubtask(rage_new CTaskAmbientClips(flags, d.m_Group, d.m_AnimIndexWithinGroup));
|
|
}
|
|
else
|
|
{
|
|
// They weren't running a complex control movement task, so at least give them wander with the given animations.
|
|
CTaskWander* pTaskWander = rage_new CTaskWander(MOVEBLENDRATIO_WALK, pFocusPed->GetCurrentHeading(), d.m_Group, d.m_AnimIndexWithinGroup);
|
|
|
|
// Possibly create a prop.
|
|
if (ms_bPickPermanentProp)
|
|
{
|
|
pTaskWander->CreateProp();
|
|
}
|
|
|
|
// Decide if we should ignore probability when creating the prop.
|
|
if (ms_bForcePropCreation)
|
|
{
|
|
pTaskWander->ForceCreateProp();
|
|
}
|
|
|
|
// Give the focus ped the wander task.
|
|
pFocusPed->GetPedIntelligence()->AddEvent(CEventGivePedTask(PED_TASK_PRIORITY_PRIMARY, pTaskWander));
|
|
}
|
|
}
|
|
}
|
|
|
|
u32 CScenarioDebug::GetAmbientFlags()
|
|
{
|
|
u32 iFlags = 0;
|
|
if (ms_bPlayBaseClip) iFlags |= CTaskAmbientClips::Flag_PlayBaseClip;
|
|
if (ms_bInstantlyBlendInBaseClip) iFlags |= CTaskAmbientClips::Flag_PlayIdleClips;
|
|
if (ms_bPlayIdleClips) iFlags |= CTaskAmbientClips::Flag_PlayIdleClips;
|
|
if (ms_bPickPermanentProp) iFlags |= CTaskAmbientClips::Flag_PickPermanentProp;
|
|
if (ms_bForcePropCreation) iFlags |= CTaskAmbientClips::Flag_ForcePropInPickPermanent;
|
|
if (ms_bOverrideInitialIdleTime) iFlags |= CTaskAmbientClips::Flag_OverrideInitialIdleTime;
|
|
return iFlags;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Scenario filters
|
|
|
|
CScenarioDebug::CScenarioDebugClosestFilterScenarioInUse::CScenarioDebugClosestFilterScenarioInUse()
|
|
: m_IgnoreInUse(false)
|
|
{
|
|
}
|
|
|
|
bool CScenarioDebug::CScenarioDebugClosestFilterScenarioInUse::Match(const CScenarioPoint& scenarioPt) const
|
|
{
|
|
if (m_IgnoreInUse && CPedPopulation::IsEffectInUse(scenarioPt))
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
CScenarioDebug::CScenarioDebugClosestFilterScenarioType::CScenarioDebugClosestFilterScenarioType(int scenarioType)
|
|
: CScenarioDebugClosestFilterScenarioInUse()
|
|
, m_ScenarioType(scenarioType)
|
|
{
|
|
}
|
|
|
|
bool CScenarioDebug::CScenarioDebugClosestFilterScenarioType::Match(const CScenarioPoint& scenarioPt) const
|
|
{
|
|
if(!CScenarioDebugClosestFilterScenarioInUse::Match(scenarioPt))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return scenarioPt.GetScenarioTypeVirtualOrReal() == m_ScenarioType;
|
|
}
|
|
|
|
|
|
CScenarioDebug::CScenarioDebugClosestFilterNotVisited::CScenarioDebugClosestFilterNotVisited(int scenarioType)
|
|
: CScenarioDebugClosestFilterScenarioType(scenarioType)
|
|
{
|
|
}
|
|
|
|
|
|
bool CScenarioDebug::CScenarioDebugClosestFilterNotVisited::Match(const CScenarioPoint& scenarioPt) const
|
|
{
|
|
if(!CScenarioDebugClosestFilterScenarioType::Match(scenarioPt))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const int numVisited = CScenarioDebug::ms_WarpToNearestAlreadyVisited.GetCount();
|
|
for(int j = 0; j < numVisited; j++)
|
|
{
|
|
if(CScenarioDebug::ms_WarpToNearestAlreadyVisited[j].m_pScenarioPoint == &scenarioPt)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
CScenarioDebug::CScenarioDebugClosestFilterSpecific::CScenarioDebugClosestFilterSpecific(int scenarioType, CScenarioPoint* pScenarioPoint)
|
|
: CScenarioDebugClosestFilterScenarioType(scenarioType)
|
|
, m_pScenarioPoint(pScenarioPoint)
|
|
{
|
|
}
|
|
|
|
|
|
bool CScenarioDebug::CScenarioDebugClosestFilterSpecific::Match(const CScenarioPoint& scenarioPt) const
|
|
{
|
|
if(!CScenarioDebugClosestFilterScenarioType::Match(scenarioPt))
|
|
{
|
|
return false;
|
|
}
|
|
if(&scenarioPt != m_pScenarioPoint)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
CScenarioPoint* CScenarioDebug::GetClosestScenarioPoint(Vec3V_In fromPos, const CScenarioDebugClosestFilter& filter)
|
|
{
|
|
const Vec3V fromPosV = fromPos;
|
|
float fFoundPointDistanceSq = FLT_MAX;
|
|
CScenarioPoint* pFoundPoint = NULL;
|
|
|
|
//Check the regions ... first ...
|
|
int activeRegionCnt = SCENARIOPOINTMGR.GetNumActiveRegions();
|
|
for (int r = 0; r < activeRegionCnt; r++)
|
|
{
|
|
CScenarioPointRegion& region = SCENARIOPOINTMGR.GetActiveRegion(r);
|
|
CScenarioPointRegionEditInterface bankRegion(region);
|
|
pFoundPoint = bankRegion.FindClosestPoint(fromPosV, filter, pFoundPoint, &fFoundPointDistanceSq);
|
|
}
|
|
|
|
//Check the entity points ...
|
|
s32 count = SCENARIOPOINTMGR.GetNumEntityPoints();
|
|
for(s32 i = 0; i < count; i++)
|
|
{
|
|
CScenarioPoint& spoint = SCENARIOPOINTMGR.GetEntityPoint(i);
|
|
|
|
const Vec3V posV = spoint.GetPosition();
|
|
const float distanceSq = DistSquared(posV, fromPosV).Getf();
|
|
if(distanceSq < fFoundPointDistanceSq)
|
|
{
|
|
if(filter.Match(spoint))
|
|
{
|
|
fFoundPointDistanceSq = distanceSq;
|
|
pFoundPoint = &spoint;
|
|
}
|
|
}
|
|
}
|
|
|
|
count = SCENARIOPOINTMGR.GetNumWorldPoints();
|
|
for(s32 i = 0; i < count; i++)
|
|
{
|
|
CScenarioPoint& spoint = SCENARIOPOINTMGR.GetWorldPoint(i);
|
|
|
|
const Vec3V posV = spoint.GetPosition();
|
|
const float distanceSq = DistSquared(posV, fromPosV).Getf();
|
|
if(distanceSq < fFoundPointDistanceSq)
|
|
{
|
|
if(filter.Match(spoint))
|
|
{
|
|
fFoundPointDistanceSq = distanceSq;
|
|
pFoundPoint = &spoint;
|
|
}
|
|
}
|
|
}
|
|
return pFoundPoint;
|
|
}
|
|
|
|
void CScenarioDebug::UpdateScenarioGroupCombo()
|
|
{
|
|
if (!ms_scenarioGroupCombo)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ms_scenarioGroupCombo->UpdateCombo("SelectedGroup", &ms_iScenarioGroupIndex, ms_Editor.m_GroupNames.GetCount(), &ms_Editor.m_GroupNames[0]);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#endif // SCENARIO_DEBUG
|