Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
1066 lines
26 KiB
C++
1066 lines
26 KiB
C++
#include "MW4Headers.hpp"
|
|
|
|
#include "Sensor.hpp"
|
|
#include "Vehicle.hpp"
|
|
#include "Building.hpp"
|
|
#include "MWPlayer.hpp"
|
|
#include "SubsystemClassData.hpp"
|
|
#include "mwmission.hpp"
|
|
#include "vehicleinterface.hpp"
|
|
#include "narc.hpp"
|
|
#include "mwapplication.hpp"
|
|
|
|
#include <Adept\EntityManager.hpp>
|
|
#include <Adept\CollisionGrid.hpp>
|
|
#include <Adept\NameTable.hpp>
|
|
|
|
#ifdef NEW_SENSOR_TIMING
|
|
__int64 tSensorTime;
|
|
__int64 tSensorFillTime;
|
|
__int64 tSensorCheckTime;
|
|
__int64 tVehicleTime;
|
|
DWORD tTotalSensorsExecuted;
|
|
#endif;
|
|
|
|
Stuff::Time Sensor::s_LastSensorCheck = 0;
|
|
|
|
// jcem - begin
|
|
#define UNLIMITED_RADAR_RANGE 6000.0f
|
|
extern bool g_bUnlimitedRadarRange;
|
|
// jcem - end
|
|
HGOSHEAP
|
|
g_SensorHeap = NULL;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
SensorData::SensorData(
|
|
MWObject *entity,
|
|
Scalar target_distance_squared,
|
|
int target_alignment,
|
|
int chasis_type
|
|
)
|
|
: Plug(Plug::DefaultData),
|
|
object(NULL)
|
|
{
|
|
object.Add(entity);
|
|
distanceSquared = target_distance_squared;
|
|
alignment = target_alignment;
|
|
chasisType = chasis_type;
|
|
}
|
|
|
|
SensorData::SensorData()
|
|
: Plug (Plug::DefaultData)
|
|
, object(NULL)
|
|
, distanceSquared(0.0f)
|
|
, alignment(-1)
|
|
, chasisType(-1)
|
|
{
|
|
}
|
|
|
|
SensorData::~SensorData()
|
|
{
|
|
}
|
|
|
|
//#############################################################################
|
|
//########################## ExecutionStateEngine #######################
|
|
//#############################################################################
|
|
|
|
Sensor::ExecutionStateEngine::ClassData*
|
|
Sensor::ExecutionStateEngine::DefaultData = NULL;
|
|
|
|
const StateEngine::StateEntry
|
|
Sensor::ExecutionStateEngine::StateEntries[]=
|
|
{
|
|
STATE_ENTRY(Sensor__ExecutionStateEngine, Active),
|
|
STATE_ENTRY(Sensor__ExecutionStateEngine, Passive),
|
|
STATE_ENTRY(Sensor__ExecutionStateEngine, Beagle)
|
|
};
|
|
|
|
DECLARE_TIMER(static, Sensor_Time);
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Sensor::ExecutionStateEngine::InitializeClass()
|
|
{
|
|
Check_Object(StateEngine::DefaultData);
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
Sensor__ExecutionStateEngineClassID,
|
|
"Sensor::ExecutionStateEngine",
|
|
Subsystem::ExecutionStateEngine::DefaultData,
|
|
ELEMENTS(StateEntries), StateEntries,
|
|
(Entity::ExecutionStateEngine::Factory)Make,
|
|
(Entity::ExecutionStateEngine::FactoryRequest::Factory)
|
|
&FactoryRequest::ConstructFactoryRequest
|
|
);
|
|
Register_Object(DefaultData);
|
|
|
|
#ifdef NEW_SENSOR_TIMING
|
|
AddStatistic("Sensors", "%", gos_timedata, (void*)&tSensorTime, 0);
|
|
AddStatistic("Sensor Fill", "%", gos_timedata, (void*)&tSensorFillTime, 0);
|
|
AddStatistic("Sensor Check", "%", gos_timedata, (void*)&tSensorCheckTime, 0);
|
|
AddStatistic("Vehicle Time", "%", gos_timedata, (void*)&tVehicleTime, 0);
|
|
AddStatistic("Total Sensors", "%", gos_DWORD, (void*)&tTotalSensorsExecuted, Stat_AutoReset + Stat_Graph);
|
|
#endif
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Sensor::ExecutionStateEngine::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Sensor::ExecutionStateEngine*
|
|
Sensor::ExecutionStateEngine::Make(
|
|
Sensor *weapon,
|
|
FactoryRequest *request
|
|
)
|
|
{
|
|
Check_Object(weapon);
|
|
Check_Object(request);
|
|
gos_PushCurrentHeap(Heap);
|
|
Sensor::ExecutionStateEngine *sensor =
|
|
new Sensor::ExecutionStateEngine(DefaultData, weapon, request);
|
|
gos_PopCurrentHeap();
|
|
return sensor;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Sensor::ExecutionStateEngine::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
//#############################################################################
|
|
//############################### Sensor ##############################
|
|
//#############################################################################
|
|
|
|
Sensor::ClassData*
|
|
Sensor::DefaultData = NULL;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Sensor::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
SensorClassID,
|
|
"MechWarrior4::Sensor",
|
|
Subsystem::DefaultData,
|
|
0, NULL,
|
|
(Entity::Factory)Make,
|
|
(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
|
|
ExecutionStateEngine::DefaultData,
|
|
(Entity::GameModel::Factory)GameModel::ConstructGameModel,
|
|
NULL,
|
|
(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
|
|
(Entity::GameModel::ModelWrite)GameModel::WriteToText,
|
|
(Entity::GameModel::ModelSave)GameModel::SaveGameModel,
|
|
(Subsystem::StreamCreate)CreateStream
|
|
);
|
|
Register_Object(DefaultData);
|
|
|
|
Initialize_Timer(Sensor_Time, "Sensor Time");
|
|
|
|
Verify(!g_SensorHeap);
|
|
g_SensorHeap = gos_CreateMemoryHeap("Sensor");
|
|
Check_Pointer(g_SensorHeap);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Sensor::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
|
|
Check_Pointer(g_SensorHeap);
|
|
gos_DestroyMemoryHeap(g_SensorHeap);
|
|
g_SensorHeap = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Sensor*
|
|
Sensor::Make(
|
|
CreateMessage *message,
|
|
ReplicatorID *base_id
|
|
)
|
|
{
|
|
Check_Object(message);
|
|
gos_PushCurrentHeap(Heap);
|
|
Sensor *new_entity =
|
|
new Sensor(DefaultData, message, base_id, NULL);
|
|
gos_PopCurrentHeap();
|
|
Check_Object(new_entity);
|
|
return new_entity;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Sensor::Sensor(
|
|
ClassData *class_data,
|
|
CreateMessage *message,
|
|
ReplicatorID *base_id,
|
|
ElementRenderer::Element *element
|
|
):
|
|
Subsystem(class_data, message, base_id, element),
|
|
m_nearestEnemy(NULL),
|
|
m_nearestFriendly(NULL),
|
|
m_LastTimeUpdatedBuildingData(0),
|
|
m_ContainsEntityLastIndex(0),
|
|
m_ShutdownRange(0),
|
|
m_PassiveRange(0),
|
|
m_ECMRange(0),
|
|
m_NormalRange(0),
|
|
m_LastUpdateTime(0),
|
|
m_NeedsSensorRefresh(false)
|
|
{
|
|
Check_Object(message);
|
|
|
|
numberOfContacts = 0;
|
|
numberOfBuildingContacts = 0;
|
|
m_UpdateTime = 2.0f;
|
|
|
|
gos_PushCurrentHeap(g_SensorHeap);
|
|
for(int i=0;i<32;i++)
|
|
{
|
|
sensorData[i] = new SensorData();
|
|
Register_Object(sensorData[i]);
|
|
}
|
|
for(i=0;i<32;i++)
|
|
{
|
|
buildingData[i] = new SensorData();
|
|
Register_Object(buildingData[i]);
|
|
}
|
|
|
|
gos_PopCurrentHeap();
|
|
|
|
executionTimer = Stuff::Random::GetFraction()*2.0f;
|
|
m_maxRange = 1000.0f;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Sensor::~Sensor()
|
|
{
|
|
for(int i=0;i<32;i++)
|
|
{
|
|
Unregister_Object(sensorData[i]);
|
|
delete sensorData[i];
|
|
}
|
|
for(i=0;i<32;i++)
|
|
{
|
|
Unregister_Object(buildingData[i]);
|
|
delete buildingData[i];
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Sensor::CheckBuilding(Entity *entity, Entity *original_caller)
|
|
{
|
|
Check_Object(entity);
|
|
Check_Object(original_caller);
|
|
|
|
Sensor *sensor = Cast_Object(Sensor*, original_caller);
|
|
MWObject *mw_object = sensor->GetParentVehicle();
|
|
|
|
int execution_state = sensor->executionState->GetState();
|
|
Scalar target_distance_squared = mw_object->GetDistanceSquaredFrom(entity, true);
|
|
if((!entity->IsDestroyed()) &&
|
|
(entity->GetAlignment() != mw_object->GetAlignment()) &&
|
|
(entity->GetAlignment() != Entity::DefaultAlignment))
|
|
{
|
|
switch(execution_state)
|
|
{
|
|
case ExecutionStateEngine::ActiveState:
|
|
if(target_distance_squared <= 1000000)
|
|
{
|
|
Verify(entity->IsDerivedFrom(Building::DefaultData));
|
|
MWObject *building = Cast_Object(MWObject *, entity);
|
|
AddBuildingContact(building, target_distance_squared);
|
|
}
|
|
break;
|
|
case ExecutionStateEngine::BeagleState:
|
|
if(target_distance_squared <= 1440000)
|
|
{
|
|
Verify(entity->IsDerivedFrom(Building::DefaultData));
|
|
MWObject *building = Cast_Object(MWObject *, entity);
|
|
AddBuildingContact(building, target_distance_squared);
|
|
}
|
|
break;
|
|
case ExecutionStateEngine::PassiveState:
|
|
if(target_distance_squared <= 625000)
|
|
{
|
|
Verify(entity->IsDerivedFrom(Building::DefaultData));
|
|
MWObject *building = Cast_Object(MWObject *, entity);
|
|
AddBuildingContact(building, target_distance_squared);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Sensor::PreCollisionExecute(Time till)
|
|
{
|
|
Check_Object(this);
|
|
PRECOLLISION_LOGIC("Subsystem::Sensor");
|
|
|
|
//
|
|
//--------------------------------------------
|
|
//Need to check for vehicles within our radius
|
|
//--------------------------------------------
|
|
//
|
|
Start_Timer(Sensor_Time);
|
|
|
|
if (m_NeedsSensorRefresh == true)
|
|
{
|
|
if (s_LastSensorCheck != gos_GetElapsedTime())
|
|
{
|
|
Refresh();
|
|
s_LastSensorCheck = gos_GetElapsedTime();
|
|
Stop_Timer(Sensor_Time);
|
|
}
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (GetParentVehicle()->IsPlayerVehicle() == false)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (executionTimer < m_UpdateTime)
|
|
{
|
|
Stuff::Scalar time_slice = GetTimeSlice(till);
|
|
executionTimer += time_slice;
|
|
|
|
Stop_Timer(Sensor_Time);
|
|
return;
|
|
}
|
|
|
|
Refresh();
|
|
|
|
lastExecuted = till;
|
|
Stop_Timer(Sensor_Time);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Sensor::Refresh()
|
|
{
|
|
executionTimer = 0.0f;
|
|
m_NeedsSensorRefresh = false;
|
|
|
|
#ifdef NEW_SENSOR_TIMING
|
|
++tTotalSensorsExecuted;
|
|
#endif
|
|
|
|
m_nearestEnemy.Remove();
|
|
m_nearestEnemyRange = 0.0f;
|
|
m_nearestFriendly.Remove();
|
|
m_nearestFriendlyRange = 0.0f;
|
|
numberOfContacts = 0;
|
|
|
|
CheckForContacts_VehiclesAndTurrets();
|
|
CheckForNarc();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
const Sensor::sensorDataArray& Sensor::RefreshAndGetSensorData()
|
|
{
|
|
Start_Timer(Sensor_Time);
|
|
|
|
if (m_LastUpdateTime + 2.0f < (Stuff::Scalar)gos_GetElapsedTime())
|
|
{
|
|
MWMission *mission = Cast_Object (MWMission *,MWMission::GetInstance ());
|
|
Check_Object (mission);
|
|
if (mission->m_VehicleAndTurretCellMap.ChecksumMatches(GetParentVehicle()->GetLocalToWorld(),
|
|
GetMaxRange(),
|
|
m_ChecksumList) == false)
|
|
{
|
|
if (s_LastSensorCheck == gos_GetElapsedTime())
|
|
{
|
|
m_NeedsSensorRefresh = true;
|
|
|
|
Stop_Timer(Sensor_Time);
|
|
return (GetSensorData());
|
|
}
|
|
|
|
Refresh();
|
|
s_LastSensorCheck = gos_GetElapsedTime();
|
|
}
|
|
|
|
m_LastUpdateTime = (Stuff::Scalar)gos_GetElapsedTime();
|
|
}
|
|
|
|
Stop_Timer(Sensor_Time);
|
|
return (GetSensorData());
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Sensor::CheckForNarc (void)
|
|
{
|
|
if (!GetParentVehicle ()->vehicleInterface)
|
|
return;
|
|
MWMission *mission = Cast_Object (MWMission *,MWMission::GetInstance ());
|
|
Check_Object (mission);
|
|
Narc *narc;
|
|
narc = mission->GetNarc(GetParentVehicle()->GetAlignment());
|
|
if (!narc)
|
|
{
|
|
GetParentVehicle ()->vehicleInterface->ReactToEvent (VehicleInterface::NARC_SIGNAL_STOP);
|
|
return;
|
|
}
|
|
Scalar target_distance_squared = GetParentVehicle ()->GetDistanceSquaredFrom(narc, true);
|
|
// MSL - Changed to reflect Max range of LRM missiles
|
|
// Also changed to give tone if Inside that range...
|
|
// if (target_distance_squared > (GetMaxRange()*GetMaxRange())) // jcem use func instead of variable directly...
|
|
// MSL - if there is a function that checks for Max Range of a Weapon then change 2400.0f to that function
|
|
// checking max range of LRM
|
|
if (target_distance_squared < (1800.0f*1800.0f)) // jcem use func instead of variable directly...
|
|
{
|
|
{
|
|
GetParentVehicle ()->vehicleInterface->ReactToEvent (VehicleInterface::NARC_SIGNAL_START);
|
|
}
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Sensor::CheckForContacts_Buildings()
|
|
{
|
|
#ifdef NEW_SENSOR_TIMING
|
|
__int64 start_time = GetCycles();
|
|
#endif
|
|
|
|
MWMission *mission = Cast_Object (MWMission *,MWMission::GetInstance ());
|
|
Check_Object (mission);
|
|
|
|
m_ParentVehiclePos = GetParentVehicle()->GetLocalToWorld();
|
|
|
|
DetermineRanges();
|
|
|
|
SensorCellMap::list_type object_list;
|
|
|
|
#ifdef NEW_SENSOR_TIMING
|
|
__int64 fill_start = GetCycles();
|
|
#endif
|
|
|
|
mission->m_BuildingCellMap.Fill(GetParentVehicle()->GetLocalToWorld(),
|
|
GetMaxRange(),
|
|
object_list,
|
|
m_BuildingChecksumList);
|
|
|
|
#ifdef NEW_SENSOR_TIMING
|
|
tSensorFillTime += GetCycles() - fill_start;
|
|
__int64 check_start = GetCycles();
|
|
#endif
|
|
|
|
{for (SensorCellMap::list_type::const_iterator i = object_list.begin();
|
|
i != object_list.end();
|
|
++i)
|
|
{
|
|
CheckBuilding(*i,this);
|
|
}}
|
|
|
|
#ifdef NEW_SENSOR_TIMING
|
|
tSensorCheckTime += GetCycles() - check_start;
|
|
tSensorTime += GetCycles() - start_time;
|
|
#endif
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Sensor::CheckForContacts_VehiclesAndTurrets()
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(NameTable::GetInstance());
|
|
|
|
#ifdef NEW_SENSOR_TIMING
|
|
__int64 start_time = GetCycles();
|
|
#endif
|
|
|
|
MWMission *mission = Cast_Object (MWMission *,MWMission::GetInstance ());
|
|
Check_Object (mission);
|
|
|
|
m_ParentVehiclePos = GetParentVehicle()->GetLocalToWorld();
|
|
|
|
DetermineRanges();
|
|
|
|
SensorCellMap::list_type object_list;
|
|
|
|
#ifdef NEW_SENSOR_TIMING
|
|
__int64 fill_start = GetCycles();
|
|
#endif
|
|
|
|
mission->m_VehicleAndTurretCellMap.Fill(GetParentVehicle()->GetLocalToWorld(),
|
|
GetMaxRange(),
|
|
object_list,
|
|
m_ChecksumList);
|
|
|
|
#ifdef NEW_SENSOR_TIMING
|
|
tSensorFillTime += GetCycles() - fill_start;
|
|
__int64 check_start = GetCycles();
|
|
#endif
|
|
|
|
{for (SensorCellMap::list_type::const_iterator i = object_list.begin();
|
|
i != object_list.end();
|
|
++i)
|
|
{
|
|
CheckEntity(**i);
|
|
}}
|
|
|
|
#ifdef NEW_SENSOR_TIMING
|
|
tSensorCheckTime += GetCycles() - check_start;
|
|
tSensorTime += GetCycles() - start_time;
|
|
#endif
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Sensor::UpdateBuildingData()
|
|
{
|
|
Check_Object(this);
|
|
|
|
numberOfBuildingContacts = 0;
|
|
CheckForContacts_Buildings();
|
|
|
|
m_LastTimeUpdatedBuildingData = (Scalar)gos_GetElapsedTime();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Sensor::DestroySubsystem()
|
|
{
|
|
Check_Object(this);
|
|
|
|
// numberOfContacts = 0;
|
|
// Subsystem::DestroySubsystem();
|
|
// EnterNeverExecuteState();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Sensor::AddBuildingContact(MWObject *vehicle, Scalar target_distance_squared)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(vehicle);
|
|
|
|
if(numberOfBuildingContacts < 32)
|
|
{
|
|
buildingData[numberOfBuildingContacts]->object.Remove();
|
|
buildingData[numberOfBuildingContacts]->object.Add(vehicle);
|
|
buildingData[numberOfBuildingContacts]->distanceSquared = target_distance_squared;
|
|
buildingData[numberOfBuildingContacts]->alignment = vehicle->GetAlignment();
|
|
++numberOfBuildingContacts;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Sensor::SetSensorMode(int mode, bool has_beagle)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(executionState);
|
|
|
|
sensorMode = mode;
|
|
|
|
switch(mode)
|
|
{
|
|
case ActiveMode:
|
|
if(has_beagle)
|
|
{
|
|
executionState->RequestState(ExecutionStateEngine::BeagleState);
|
|
m_maxRange = 1200.0f;
|
|
}
|
|
else
|
|
{
|
|
executionState->RequestState(ExecutionStateEngine::ActiveState);
|
|
m_maxRange = 1000.0f;
|
|
}
|
|
break;
|
|
case PassiveMode:
|
|
executionState->RequestState(ExecutionStateEngine::PassiveState);
|
|
m_maxRange = 250.0f;
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool Sensor::SensorDataOK(SensorData& data, int alignment)
|
|
{
|
|
MWObject *veh;
|
|
|
|
veh = GetParentVehicle();
|
|
int rel_align;
|
|
if ((data.object.GetCurrent() == 0) || (data.object.GetCurrent()->IsDestroyed()))
|
|
return false;
|
|
|
|
rel_align = veh->GetRelativeAlignment (data.alignment);
|
|
return (rel_align == alignment);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Entity*
|
|
Sensor::GetNextEnemy(Entity *current_enemy, bool previous)
|
|
{
|
|
Check_Object(this);
|
|
if (MWApplication::GetInstance()->networkingFlag)
|
|
{
|
|
NetMissionParameters::MWNetMissionParameters *params = MWApplication::GetInstance()->GetLocalNetParams();
|
|
if ((params->m_radarMode != 0) && (params->m_radarMode != 3))
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
if(current_enemy)
|
|
{
|
|
for(int i=0; i< numberOfContacts; i++)
|
|
{
|
|
if(sensorData[i]->object.GetCurrent() == current_enemy)
|
|
{
|
|
if (previous == false)
|
|
{
|
|
for(int q=(i+1); q< numberOfContacts; q++)
|
|
{
|
|
if (SensorDataOK(*sensorData[q],Entity::Enemy) == true)
|
|
return sensorData[q]->object.GetCurrent();
|
|
}
|
|
for(int y=0; y<=i; y++)
|
|
{
|
|
if (SensorDataOK(*sensorData[y],Entity::Enemy) == true)
|
|
return sensorData[y]->object.GetCurrent();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(int q=(i-1); q >= 0; --q)
|
|
{
|
|
if (SensorDataOK(*sensorData[q],Entity::Enemy) == true)
|
|
return sensorData[q]->object.GetCurrent();
|
|
}
|
|
for(int y=(numberOfContacts - 1); y > i; --y)
|
|
{
|
|
if (SensorDataOK(*sensorData[y],Entity::Enemy) == true)
|
|
return sensorData[y]->object.GetCurrent();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for(int i=0; i< numberOfContacts; i++)
|
|
{
|
|
if (SensorDataOK(*sensorData[i],Entity::Enemy) == true)
|
|
return sensorData[i]->object.GetCurrent();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Entity*
|
|
Sensor::GetNearestEnemy()
|
|
{
|
|
Check_Object(this);
|
|
Entity * entity = m_nearestEnemy.GetCurrent();
|
|
if (MWApplication::GetInstance()->networkingFlag)
|
|
{
|
|
NetMissionParameters::MWNetMissionParameters *params = MWApplication::GetInstance()->GetLocalNetParams();
|
|
if ((params->m_radarMode != 0) && (params->m_radarMode != 3))
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
if (entity)
|
|
{
|
|
if (entity->IsDestroyed())
|
|
{
|
|
m_NeedsSensorRefresh = true;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return entity;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Entity*
|
|
Sensor::GetNextFriendly(Entity *current_friendly, bool previous)
|
|
{
|
|
Check_Object(this);
|
|
if (MWApplication::GetInstance()->networkingFlag)
|
|
{
|
|
NetMissionParameters::MWNetMissionParameters *params = MWApplication::GetInstance()->GetLocalNetParams();
|
|
if (params->m_radarMode == 2)
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
if(current_friendly)
|
|
{
|
|
for(int i=0; i< numberOfContacts; i++)
|
|
{
|
|
if(sensorData[i]->object.GetCurrent() == current_friendly)
|
|
{
|
|
if (previous == false)
|
|
{
|
|
for(int q=(i + 1); q< numberOfContacts; q++)
|
|
{
|
|
if (SensorDataOK(*sensorData[q],Entity::Player) == true)
|
|
return sensorData[q]->object.GetCurrent();
|
|
}
|
|
for(int y=0; y<=i; y++)
|
|
{
|
|
if (SensorDataOK(*sensorData[y],Entity::Player) == true)
|
|
return sensorData[y]->object.GetCurrent();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(int q=(i-1); q >= 0; --q)
|
|
{
|
|
if (SensorDataOK(*sensorData[q],Entity::Player) == true)
|
|
return sensorData[q]->object.GetCurrent();
|
|
}
|
|
for(int y=(numberOfContacts - 1); y > i; --y)
|
|
{
|
|
if (SensorDataOK(*sensorData[y],Entity::Player) == true)
|
|
return sensorData[y]->object.GetCurrent();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for(int i=0; i< numberOfContacts; i++)
|
|
{
|
|
if (SensorDataOK(*sensorData[i],Entity::Player) == true)
|
|
return sensorData[i]->object.GetCurrent();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Entity*
|
|
Sensor::GetNearestFriendly()
|
|
{
|
|
Check_Object(this);
|
|
if (MWApplication::GetInstance()->networkingFlag)
|
|
{
|
|
NetMissionParameters::MWNetMissionParameters *params = MWApplication::GetInstance()->GetLocalNetParams();
|
|
if (params->m_radarMode == 2)
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
return m_nearestFriendly.GetCurrent();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Scalar
|
|
Sensor::GetMaxRange()
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(executionState);
|
|
|
|
// jcem - begin
|
|
if (g_bUnlimitedRadarRange)
|
|
return UNLIMITED_RADAR_RANGE;
|
|
// jcem - end
|
|
|
|
return m_maxRange;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Sensor::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Scalar
|
|
Sensor::GetLastTimeUpdatedBuildingData() const
|
|
{
|
|
return (m_LastTimeUpdatedBuildingData);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
Sensor::ContainsEntity(Adept::Entity* entity)
|
|
{
|
|
if ((m_ContainsEntityLastIndex < numberOfContacts) &&
|
|
(sensorData[m_ContainsEntityLastIndex]->object.GetCurrent() == entity))
|
|
{
|
|
return (true);
|
|
}
|
|
|
|
{for (int i = 0;
|
|
i < numberOfContacts;
|
|
++i)
|
|
{
|
|
if (sensorData[i]->object.GetCurrent() == entity)
|
|
{
|
|
m_ContainsEntityLastIndex = i;
|
|
return (true);
|
|
}
|
|
}}
|
|
|
|
if ((entity != 0) &&
|
|
(entity->IsDerivedFrom(Building::DefaultData) == true))
|
|
{
|
|
{for (int i = 0;
|
|
i < numberOfBuildingContacts;
|
|
++i)
|
|
{
|
|
if (buildingData[i]->object.GetCurrent() == entity)
|
|
{
|
|
m_ContainsEntityLastIndex = numberOfContacts;
|
|
return (true);
|
|
}
|
|
}}
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool
|
|
Sensor::CanSeeEntity(MWObject& mwobject)
|
|
{
|
|
if ((mwobject.IsDestroyed() == true) ||
|
|
(&mwobject == GetParentVehicle()) ||
|
|
(mwobject.GetVisibleOnSensors() == false))
|
|
{
|
|
return (false);
|
|
}
|
|
|
|
if (mwobject.IsPlayerVehicle() == true)
|
|
{
|
|
if (mwobject.executionState->GetState() == Entity::ExecutionStateEngine::NeverExecuteState)
|
|
{
|
|
return (false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (mwobject.HasAI() == 0)
|
|
{
|
|
if ((MWApplication::GetInstance()->networkingFlag == false) ||
|
|
(mwobject.IsDerivedFrom(Mech::DefaultData) == false))
|
|
{
|
|
return (false);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (true);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Stuff::Scalar
|
|
Sensor::SquaredRangeToEntity(MWObject& mwobject)
|
|
{
|
|
Scalar x_delta = mwobject.GetLocalToWorld()(W_Axis, X_Axis) - m_ParentVehiclePos.x;
|
|
x_delta *= x_delta;
|
|
|
|
Scalar z_delta = mwobject.GetLocalToWorld()(W_Axis, Z_Axis) - m_ParentVehiclePos.z;
|
|
z_delta *= z_delta;
|
|
|
|
return(x_delta + z_delta);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Stuff::Scalar
|
|
Sensor::CurrentMaxDetectionRangeTo(MWObject& mwobject)
|
|
{
|
|
if (mwobject.vehicleShutDown == true)
|
|
{
|
|
return (m_ShutdownRange);
|
|
}
|
|
|
|
if (mwobject.GetSensorMode() == PassiveMode)
|
|
{
|
|
return (m_PassiveRange);
|
|
}
|
|
|
|
if (mwobject.DoesHaveECM() == true)
|
|
{
|
|
return (m_ECMRange);
|
|
}
|
|
|
|
return (m_NormalRange);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Sensor::CheckEntity(MWObject& mwobject)
|
|
{
|
|
Check_Object(executionState);
|
|
|
|
if (CanSeeEntity(mwobject) == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Stuff::Scalar detection_range_squared = CurrentMaxDetectionRangeTo(mwobject);
|
|
|
|
if (detection_range_squared == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Stuff::Scalar target_distance_squared = SquaredRangeToEntity(mwobject);
|
|
|
|
if (target_distance_squared > detection_range_squared)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (GetParentVehicle()->vehicleInterface)
|
|
{
|
|
if ((mwobject.vehicleJustPoweredUp) &&
|
|
(GetParentVehicle()->GetRelativeAlignment(mwobject.GetAlignment()) == Adept::Entity::Enemy))
|
|
{
|
|
mwobject.vehicleJustPoweredUp = false;
|
|
GetParentVehicle()->vehicleInterface->ReactToEvent(VehicleInterface::NEW_VEHICLE_RADAR_POWER_UP);
|
|
}
|
|
}
|
|
|
|
int mwobject_alignment(mwobject.GetAlignment());
|
|
int my_alignment(GetParentVehicle()->GetAlignment());
|
|
|
|
if (mwobject_alignment != my_alignment)
|
|
{
|
|
if (mwobject_alignment != Entity::DefaultAlignment)
|
|
{
|
|
if ((!m_nearestEnemy.GetCurrent()) ||
|
|
(m_nearestEnemyRange > target_distance_squared))
|
|
{
|
|
m_nearestEnemy.Remove();
|
|
m_nearestEnemy.Add((Entity *)&mwobject);
|
|
m_nearestEnemyRange = target_distance_squared;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((!m_nearestFriendly.GetCurrent()) ||
|
|
(m_nearestFriendlyRange > target_distance_squared))
|
|
{
|
|
m_nearestFriendly.Remove();
|
|
m_nearestFriendly.Add((Entity *)&mwobject);
|
|
m_nearestFriendlyRange = target_distance_squared;
|
|
}
|
|
}
|
|
|
|
if (numberOfContacts < 32)
|
|
{
|
|
SensorData* sensor_data = sensorData[numberOfContacts];
|
|
sensor_data->object.Remove();
|
|
sensor_data->object.Add(&mwobject);
|
|
sensor_data->distanceSquared = target_distance_squared;
|
|
sensor_data->alignment = mwobject_alignment;
|
|
|
|
++numberOfContacts;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
Sensor::DetermineRanges()
|
|
{
|
|
MWMission *mission = Cast_Object (MWMission *,MWMission::GetInstance ());
|
|
Check_Object (mission);
|
|
// jcem - begin
|
|
if (g_bUnlimitedRadarRange) {
|
|
m_PassiveRange = m_ECMRange = m_NormalRange = m_ShutdownRange = UNLIMITED_RADAR_RANGE * UNLIMITED_RADAR_RANGE;
|
|
return;
|
|
}
|
|
// jcem - end
|
|
switch (executionState->GetState())
|
|
{
|
|
case ExecutionStateEngine::ActiveState:
|
|
{
|
|
m_PassiveRange = 500.0f * 500.0f;
|
|
m_ECMRange = 500.0f * 500.0f;
|
|
m_NormalRange = 1000.0f * 1000.0f;
|
|
// MSL 5.04 Modified Shutdown Range
|
|
// m_ShutdownRange = 50.0f * 50.0f;
|
|
// MSL 5.05 Modified Shutdown Range
|
|
m_ShutdownRange = 500.0f * 500.0f;
|
|
break;
|
|
}
|
|
case ExecutionStateEngine::BeagleState:
|
|
{
|
|
m_PassiveRange = 600.0f * 600.0f;
|
|
// MSL 5.04 Modified Beagle Range
|
|
m_ECMRange = 700.0f * 700.0f;
|
|
m_NormalRange = 1200.0f * 1200.0f;
|
|
// m_ShutdownRange = 100.0f * 100.0f;
|
|
// MSL 5.05 Modified Shutdown Range
|
|
m_ShutdownRange = 600.0f * 600.0f;
|
|
break;
|
|
}
|
|
case ExecutionStateEngine::PassiveState:
|
|
{
|
|
m_ECMRange = 100.0f * 100.0f;
|
|
m_NormalRange = 250.0f * 250.0f;
|
|
m_ShutdownRange = 0;
|
|
m_PassiveRange = 0;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
m_ShutdownRange = 0;
|
|
m_PassiveRange = 0;
|
|
m_ECMRange = 0;
|
|
m_NormalRange = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|