Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
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.
2026-06-24 21:28:16 -05:00

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;
}
}
}