Files
firestorm/Gameleap/code/mw4/Code/MW4/MWObject.cpp
T
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

3366 lines
82 KiB
C++

#include "MW4Headers.hpp"
#include "MWObject.hpp"
#include "Subsystem.hpp"
#include "Torso.hpp"
#include "AnimationState.hpp"
#include "MWDamageObject.hpp"
#include "Weapon.hpp"
#include "Sensor.hpp"
#include "Beagle.hpp"
#include "HeatManager.hpp"
#include "AMS.hpp"
#include "SearchLight.hpp"
#include "Mech_AI.hpp"
#include "MWMission.hpp"
#include "gameinfo.hpp"
#include "AI_Statistics.hpp"
#include "obstacle.hpp"
#include "ECM.hpp"
#include "VehicleInterface.hpp"
#include "SubsystemClassData.hpp"
#include "MWApplication.hpp"
#include "DamageDispatch.hpp"
// MSL 5.02 SubSystems
//#include "EnhancedOptics.hpp"
#include "IFF_Jammer.hpp"
#include "AdvancedGyro.hpp"
#include <Adept\DamageObject.hpp>
#include <Adept\EntityManager.hpp>
#include <Adept\Effect.hpp>
#include <Adept\Map.hpp>
#include <Adept\Site.hpp>
#include <Adept\CollisionGrid.hpp>
#include <Adept\CollisionVolume.hpp>
#include <Adept\Renderer.hpp>
extern int g_nMR;
IdleEffectObject::IdleEffectObject() :
Plug(Plug::DefaultData),
idleEffect(NULL),
siteSlot(NULL)
{}
//#############################################################################
//############################### MWObject ##############################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWObject::ClassData*
MWObject::DefaultData = NULL;
const Receiver::MessageEntry
MWObject::MessageEntries[]=
{
MESSAGE_ENTRY(MWObject, TakeDamage)
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::InitializeClass()
{
Check_Object(MWMover::ExecutionStateEngine::DefaultData);
Verify(!DefaultData);
DefaultData =
new ClassData(
MWObjectClassID,
"MechWarrior4::MWObject",
BaseClass::DefaultData,
ELEMENTS(MessageEntries), MessageEntries,
(Entity::Factory)Make,
(Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage,
ExecutionStateEngine::DefaultData,
(Entity::GameModel::Factory)GameModel::ConstructGameModel,
(Entity::GameModel::Factory)GameModel::ConstructOBBStream,
(Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify,
(Entity::GameModel::ModelWrite)GameModel::WriteToText,
(Entity::GameModel::ModelSave)GameModel::SaveGameModel,
AnimationStateEngine::Make
);
Register_Object(DefaultData);
DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
DeathEntityResource,
deathEntityResource,
ResourceID
);
DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
DestroyedEffectResource,
destroyedEffectResource,
ResourceID
);
DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
SecondaryDeathEntityResource,
secondaryDeathEntityResource,
ResourceID
);
DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
SecondaryDestroyedEffectResource,
secondaryDestroyedEffectResource,
ResourceID
);
DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
VehicleTonnage,
vehicleTonnage,
Scalar
);
DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
MaxVehicleTonnage,
maxVehicleTonnage,
Scalar
);
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
EyeSiteName,
eyeSiteName,
const char *,
CharClassID
);
DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
PartDestructionEffectResource,
partDestructionEffectResource,
ResourceID
);
DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
SplashDamageRadius,
splashDamageRadius,
Scalar
);
DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
SplashDamageAmount,
splashDamageAmount,
Scalar
);
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
VehicleBattleValue,
vehicleBattleValue,
int,
IntClassID
);
DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
CoolantEffectResource,
coolantEffectResource,
ResourceID
);
DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
SplashHeatAmount,
splashHeatAmount,
Scalar
);
DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
EjectEffectResource,
ejectEffectResource,
ResourceID
);
CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
NameIndex,
m_nameIndex,
int,
IntClassID
);
DIRECT_GAME_MODEL_ATTRIBUTE(
MWObject__GameModel,
OverHeatEffectResource,
overHeatEffectResource,
ResourceID
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWObject*
MWObject::Make(
CreateMessage *message,
ReplicatorID *base_id
)
{
Check_Object(message);
gos_PushCurrentHeap(Heap);
MWObject *new_object = new
MWObject(DefaultData, message, base_id, NULL);
gos_PopCurrentHeap();
Check_Object(new_object);
return new_object;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Replicator::CreateMessage*
MWObject::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file)
{
Check_Object(this);
Check_Object(stream);
//
//---------------------------------------------------------------------
// Make sure there is enough room for the factory request on the stream
//---------------------------------------------------------------------
//
stream->AllocateBytes(sizeof(CreateMessage));
BaseClass::SaveMakeMessage(stream, res_file);
CreateMessage *message =
Cast_Pointer(CreateMessage*, stream->GetPointer());
message->messageLength = sizeof(*message);
//
//--------------------------------------------
// Create the memory stream for the subsystems
//--------------------------------------------
//
DynamicMemoryStream subsystem_stream(sizeof(WORD));
subsystem_stream << static_cast<WORD>(0);
ReplicatorID span = ReplicatorID::Null;
ChainIteratorOf<Subsystem *> sub_iterator(&subsystemsInVehicle);
Subsystem *subsystem;
while((subsystem = sub_iterator.ReadAndNext()) != NULL)
{
Check_Object(subsystem);
Replicator::CreateMessage *create_message =
subsystem->SaveMakeMessage(&subsystem_stream, res_file);
if (create_message)
{
Check_Object(create_message);
span += create_message->replicatorID;
subsystem_stream.AdvancePointer(create_message->messageLength);
}
}
//
//-------------------------------------------------------------------------
// If we actually wrote out some children, rewind the stream and save it to
// the resource. Otherwise, just set the resourceID to NULL
//-------------------------------------------------------------------------
//
//This stream must be written out to the current res_file and not core.
if (subsystem_stream.GetBytesUsed() > sizeof(WORD))
{
subsystem_stream.Rewind();
Verify(span.localID > 0);
subsystem_stream << span.localID;
MString sub_resource_name = instanceName;
sub_resource_name += "{Subsystem}";
Resource subsystem_resource((const char *)sub_resource_name, res_file);
subsystem_resource.Save(&subsystem_stream, NULL);
Check_Object(&subsystem_resource);
message->subsystemStreamResourceID = subsystem_resource.GetResourceID();
message->replicatorID += span;
}
else
{
message->subsystemStreamResourceID = ResourceID::Null;
}
//
//------------------------------------------------------
//Need to save damage objects and Internal DamageObjects
//------------------------------------------------------
//
//We need to check if we have changed or not...if we have then save to the
//the res file given...if not then we need to just do nothing becuase we are already
//in the core file and just set the message
message->damageStreamResourceID = damageStreamResourceID;
if((m_hasExecuted) && (!m_markedForSalvage))
{
DynamicMemoryStream damage_stream;
DamageObject *damage_object;
SortedChainIteratorOf<DamageObject *, int> damage_iterator(&damageObjects);
damage_stream << damage_iterator.GetSize();
while((damage_object = damage_iterator.ReadAndNext()) != NULL)
{
Check_Object(damage_object);
damage_object->Save(&damage_stream);
}
MWInternalDamageObject *internal_damage_object;
SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&internalDamageObjects);
damage_stream << internal_iterator.GetSize();
while((internal_damage_object = internal_iterator.ReadAndNext()) != NULL)
{
Check_Object(internal_damage_object);
internal_damage_object->Save(&damage_stream);
}
//
//-------------------------------------------------------------------------
// If we actually wrote out some children, rewind the stream and save it to
// the resource. Otherwise, just set the resourceID to NULL
//-------------------------------------------------------------------------
//
if (damage_stream.GetBytesUsed())
{
Resource damage_resource(NULL, res_file);
damage_resource.Save(&damage_stream, NULL);
Check_Object(&damage_resource);
message->damageStreamResourceID = damage_resource.GetResourceID();
}
else
{
message->damageStreamResourceID = ResourceID::Null;
}
}
message->skinPrefix = m_skinPrefix;
message->teamDecal = m_teamDecal;
message->pilotDecal = m_pilotDecal;
message->nameIndex = m_localizeIndex;
message->doesHaveInstanceName = m_doesHaveInstanceName;
return message;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::LoadSubsystemsFromResource(
const ResourceID &subsystem_stream_id,
ReplicatorID *base_id
)
{
Resource stream(subsystem_stream_id);
Verify(stream.DoesResourceExist());
stream.AdvancePointer(sizeof(WORD));
while (stream.GetBytesRemaining() > 0)
{
Entity::CreateMessage *message =
Cast_Pointer(Entity::CreateMessage*, stream.GetPointer());
Entity *entity = CreateEntity(&stream, base_id);
Check_Object(entity);
AddChild(entity);
Subsystem *subsystem;
subsystem = Cast_Object(Subsystem *, entity);
//Dave here is where you want to do a apendparentname function
if (subsystem->IsDerivedFrom(Torso::DefaultData))
{
Torso* torso = Cast_Object(Torso*, subsystem);
if (std::find(m_Torsos.begin(),m_Torsos.end(),torso) == m_Torsos.end())
{
m_Torsos.push_back(torso);
}
}
if (subsystem->IsDerivedFrom(SearchLight::DefaultData))
{
searchLight = Cast_Object(SearchLight *, subsystem);
}
stream.AdvancePointer(message->messageLength);
}
//stream.UnloadData();
m_hasExecuted = false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::LoadDamageObjectsFromResource(
const ResourceID &damage_stream_id
)
{
Resource stream(damage_stream_id);
Verify(stream.DoesResourceExist());
while (stream.GetBytesRemaining() > 0)
{
RegisteredClass::ClassID class_id;
stream >> class_id;
RegisteredClass::ClassData *class_data = NULL;
class_data = RegisteredClass::FindClassData(class_id);
if(class_data == DamageObject::DefaultData)
{
DamageObject *damage_object;
DamageObject::ClassData *damage_class_data =
Cast_Pointer(DamageObject::ClassData*, class_data);
gos_PushCurrentHeap(Heap);
damage_object = new DamageObject(
damage_class_data,
&stream
);
gos_PopCurrentHeap();
Check_Object(damage_object);
damageObjects.AddValue(damage_object, damage_object->armorZone);
}
else
{
MWInternalDamageObject *internal_damage_object;
MWInternalDamageObject::ClassData *damage_class_data =
Cast_Pointer(MWInternalDamageObject::ClassData*, class_data);
gos_PushCurrentHeap(Heap);
internal_damage_object = new MWInternalDamageObject(
damage_class_data,
&stream
);
gos_PopCurrentHeap();
Check_Object(internal_damage_object);
internalDamageObjects.AddValue(
internal_damage_object, internal_damage_object->damageZone);
}
}
stream.UnloadData();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::LoadIdleEffectsFromResource(const ResourceID &effects_stream_id)
{
Resource stream(effects_stream_id);
Verify(stream.DoesResourceExist());
while (stream.GetBytesRemaining() > 0)
{
IdleEffectObject *idle_effect_object;
idle_effect_object = new IdleEffectObject();
stream >> idle_effect_object->effectResourceID;
MString site_name;
stream >> site_name;
idle_effect_object->siteSlot.Remove();
Site *site_pointer = FindSite(site_name);
Check_Object(site_pointer);
idle_effect_object->siteSlot.Add(site_pointer);
idle_effect_object->idleEffect.Remove();
Effect *idle_effect = CreateIdleEffect(idle_effect_object);
Check_Object(idle_effect);
idle_effect_object->idleEffect.Add(idle_effect);
idleEffects.Add(idle_effect_object);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Effect*
MWObject::CreateIdleEffect(IdleEffectObject *effect_object)
{
Check_Object(effect_object);
if(effect_object->effectResourceID == ResourceID::Null)
return NULL;
Resource idle_resource(effect_object->effectResourceID);
if(idle_resource.DoesResourceExist())
{
ClassID class_ID;
class_ID = GetClassIDFromDataListID(effect_object->effectResourceID);
Verify(class_ID != NullClassID);
LinearMatrix4D effect_position = LinearMatrix4D::Identity;
UnitVector3D unit_forward;
Site *site_pointer = effect_object->siteSlot.GetCurrent();
Check_Object(site_pointer);
LinearMatrix4D site_position = site_pointer->GetLocalToWorld();
site_position.GetLocalForwardInWorld(&unit_forward);
effect_position.AlignLocalAxisToWorldVector(unit_forward, Y_Axis, X_Axis, Z_Axis);
Point3D effect_translation;
effect_translation = site_pointer->GetLocalToWorld();
effect_position.BuildTranslation(effect_translation);
Effect::CreateMessage effect_create_message(
sizeof(Effect::CreateMessage),
DefaultEventPriority,
CreateMessage::DefaultFlags,
class_ID,
Effect::DefaultFlags|Effect::LoopFlag,
effect_object->effectResourceID,
effect_position,
0.0f,
ExecutionStateEngine::AlwaysExecuteState,
NameTable::NullObjectID,
Entity::DefaultAlignment
);
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
Entity *entity;
ReplicatorID effect_id = Connection::Hermit->GetNextReplicatorID();
entity = CreateEntity(&stream, &effect_id, false);
Check_Object(Map::GetInstance());
Map::GetInstance()->AddChild(entity);
Effect *effect;
effect = Cast_Object(Effect *, entity);
effect->SetFollowEntity(site_pointer);
entity->SyncMatrices(true);
return effect;
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWObject::MWObject(
ClassData *class_data,
CreateMessage *message,
ReplicatorID *base_id,
ElementRenderer::Element *element
):
MWMover(class_data, message, base_id, element),
armatureChain(NULL),
subsystemsInVehicle(NULL),
executingSubsystems(NULL),
damageObjects(NULL, false),
internalDamageObjects(NULL, true),
idleEffects(NULL),
weaponChain(NULL),
eyeSitePointer(NULL),
sensor(NULL),
beagle(NULL),
ams(NULL),
m_TargetDesirability(desirability_invalid),
entitiesToSync(NULL),
m_FindObjectCache(NULL),
m_FindObjectList(NULL),
m_VisibleOnSensors(true),
splashedEntities(NULL),
// MSL 5.02 SubSystems
// enhancedOptics(NULL),
advancedGyro(NULL),
iff_jammer(NULL)
{
Check_Pointer(this);
Check_Object(message);
CommonCreation(message);
m_AI = NULL;
m_bHasAI = false;
ecm = NULL;
beagle = NULL;
searchLight = NULL;
vehicleInterface = NULL;
invulnerable=false;
m_markedForSalvage = false;
m_localizeIndex = message->nameIndex;
m_doesHaveInstanceName = message->doesHaveInstanceName;
//
//----------------------
// Create the subsystems
//----------------------
//
subsystemStreamResourceID = message->subsystemStreamResourceID;
if(message->subsystemStreamResourceID != ResourceID::Null)
{
LoadSubsystemsFromResource(
message->subsystemStreamResourceID,
base_id
);
}
//
//--------------------------
// Create the damage Objects
//--------------------------
//
damageStreamResourceID = message->damageStreamResourceID;
if(message->damageStreamResourceID != ResourceID::Null)
{
LoadDamageObjectsFromResource(
message->damageStreamResourceID
);
}
const GameModel *game_model = GetGameModel();
Check_Object(game_model);
m_heatManager = NULL;
m_skinPrefix = message->skinPrefix;
m_pilotDecal = message->pilotDecal;
m_teamDecal = message->teamDecal;
MakeArmatureChain();
MakeAnimationArray();
ConnectDamageObjects();
HookUpSubsystems();
InitializeArmorArray ();
//
//------------------------
// Create the Idle Effects
//------------------------
//
if(game_model->idleEffectResourceID != ResourceID::Null)
{
LoadIdleEffectsFromResource(game_model->idleEffectResourceID);
}
//
//------------------------------
// Load up the animation engines
//------------------------------
//
AnimationStateEngine::FactoryRequest request;
request.currentState = AnimationStateEngine::UninitializedState;
animStateEngine = (*((MWObject::ClassData*)GetClassData())->animationStateFactory)(this, &request);
Register_Object(animStateEngine);
const GameModel *model = GetGameModel();
Check_Object(model);
MWApplication *app = MWApplication::GetInstance();
if (game_model->animScriptName[0] != NULL)
{
app->AddToAnimationLoadQue(this);
}
MWMover* eye = FindChildMover(model->eyeSiteName);
if(eye)
eyeSitePointer.Add(eye);
originalCollisionMask = GetCollisionMask();
originalCullMode = GetElement()->GetCullMode();
jointRunningLight = NULL;
jointRunningLight = FindChildMover("joint_runninglights");
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int temporaryQuickIDLookup[COMPRESS_JOINT_COUNT];
void
MWObject::LoadAnimationScripts()
{
for (int i = 0; i < COMPRESS_JOINT_COUNT; ++i)
{
temporaryQuickIDLookup[i] = -1;
}
Stuff::ChainIteratorOf<MWMover*> iterator(&armatureChain);
MWMover *mover;
i = 0;
while ((mover = iterator.ReadAndNext()) != NULL)
{
MString temp;
int index = MW4Animation::CompressName(mover->instanceName, temp);
if (index != -1)
{
Verify(index < COMPRESS_JOINT_COUNT);
Verify(index >= 0);
temporaryQuickIDLookup[index] = i;
}
++i;
}
const GameModel *model = GetGameModel();
Check_Object(model);
if (model->animScriptName[0] != NULL && !animStateEngine->alreadyLoaded)
{
animStateEngine->LoadScript(model->animScriptName);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWObject::InitializeArmorArray()
{
Check_Object(this);
m_HitPoints = 0;
SortedChainIteratorOf<Adept::DamageObject*,int> iter(&damageObjects);
DamageObject *fred;
while ((fred = iter.ReadAndNext ()) != NULL)
{
m_HitPoints += fred->currentArmorValue;
if (fred->internalDamageObject)
{
m_HitPoints += fred->internalDamageObject->currentInternalDamage;
fred->internalDamageObject->SetHitPointPointer (&m_HitPoints);
}
fred->SetHitPointPointer (&m_HitPoints);
}
if (m_HitPoints == 0)
m_HitPoints = 1;
m_MaxHitPoints = m_HitPoints;
for(int i=0; i<12; i++)
{
armorArray[i] = -1.0f;
DamageObject *damage_object = damageObjects.Find(i);
if(damage_object)
{
armorArray[i] = damage_object->armorLevel;
damage_object->SetArmorArrayEntry(&armorArray[i]);
}
else
{
armorArray[i] = -1;
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWObject::CommonCreation(CreateMessage *message)
{
Check_Object(this);
Check_Object(message);
for (int i=0;i<11;i++)
armorArray[i] = -1.0f;
const GameModel *game_model = GetGameModel();
Check_Object(game_model);
vehicleShutDown = false;
vehicleJustPoweredUp = false;
animationVelocity = Vector3D::Identity;
tonage = game_model->vehicleTonnage;
battleValue = game_model->vehicleBattleValue;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWObject::Respawn(Entity::CreateMessage *message)
{
Check_Object(this);
Check_Object(message);
BaseClass::Respawn(message);
CreateMessage *object_message = Cast_Pointer(CreateMessage *, message);
CommonCreation(object_message);
animStateEngine->Reset();
//
//-----------------------------------------
//Load up the Damage Objects and Subsystems
//-----------------------------------------
//
ReuseDamageObjects();
if(object_message->subsystemStreamResourceID != ResourceID::Null)
{
Resource stream(object_message->subsystemStreamResourceID);
Verify(stream.DoesResourceExist());
ReuseSubsystems(&stream);
}
ReuseArmature();
//
// If you set to NeverCullMode, it screws up the sphere sync method.
// this results in splash damage not working after a respawn.
//
// entityElement->SetNeverCullMode();
GetElement()->SetCullMode(originalCullMode );
SetCollisionMask(originalCollisionMask);
if (GetAI() != 0)
{
if (MechWarrior4::AI::GetGraveyard() != 0)
{
MechWarrior4::AI::GetGraveyard()->NotifyCreated(objectID);
}
GetAI()->NotifyRespawned();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWObject::~MWObject()
{
DESTRUCTOR("MWObject");
Unregister_Object(animStateEngine);
delete animStateEngine;
if (animationArray != NULL)
{
Unregister_Pointer(animationArray);
delete[] animationArray;
}
if (lastTriggerArray != NULL)
{
Unregister_Pointer(lastTriggerArray);
delete[] lastTriggerArray;
}
damageObjects.DeletePlugs();
internalDamageObjects.DeletePlugs();
idleEffects.DeletePlugs();
if(m_heatManager)
delete m_heatManager;
if (m_FindObjectCache)
delete m_FindObjectCache;
if (m_FindObjectList)
delete m_FindObjectList;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::MakeAnimationArray()
{
Stuff::ChainIteratorOf<MWMover*> iterator(&armatureChain);
MWMover *mover;
animationArrayCount = iterator.GetSize();
if (animationArrayCount == 0)
{
animationArray = NULL;
lastTriggerArray = NULL;
return;
}
animationArray = new MWMover *[animationArrayCount];
Register_Pointer(animationArray);
lastTriggerArray = new int [animationArrayCount];
Register_Pointer(lastTriggerArray);
for (int counter = 0; counter < animationArrayCount; counter++)
{
lastTriggerArray[counter] = 0;
}
int i = 0;
while ((mover = iterator.ReadAndNext()) != NULL)
{
animationArray[i] = mover;
i++;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::ApplyChannel
(
MW4Animation::ChannelApplication &channel_data,
int joint_index,
void *user_data
)
{
MWObject *mw_object;
mw_object = Cast_Object(MWObject*, user_data);
Stuff::UnitQuaternion rotation;
Stuff::Point3D position;
LinearMatrix4D new_local_to_parent;
MWMover *mover = mw_object->animationArray[joint_index];
Check_Object(mover);
#if 0
const char *compare_name = mover->instanceName;
if((compare_name = strstr(compare_name, "::")) != NULL)
{
compare_name += 2;
}
else
{
compare_name = mover->instanceName;
}
if(!_stricmp(mover->instanceName, "site_eyepoint"))
{
SPEW(("jerryeds", "Animation trying to mess with the eye...bad bad bad!!!!"));
return;
}
#endif
if (channel_data.hasTrigger)
{
if (channel_data.triggerValue != mw_object->lastTriggerArray[joint_index])
{
mw_object->animationTriggerManager.DispatchTriggerMessage(joint_index, channel_data.triggerValue, mw_object);
mw_object->lastTriggerArray[joint_index] = channel_data.triggerValue;
}
}
if (channel_data.hasVelocity)
{
//channel_data.velocityValue.y = 0.0f;
//channel_data.velocityValue.x = 0.0f;
//position.y = channel_data.positionValue.y;
//position.x = channel_data.positionValue.x;
position = mover->GetLocalToParent();
mw_object->animationVelocity = channel_data.velocityValue;
//vehicle->animationVelocity;
}
else
{
if (channel_data.hasPosition)
{
position = channel_data.positionValue;
}
else
{
position = mover->GetLocalToParent();
}
}
if (channel_data.hasAngularVelocity)
{
mw_object->instantaniousAngularVelocity = channel_data.angularVelocityValue;
rotation = mover->GetLocalToParent();
}
else
{
if (channel_data.hasRotation)
{
rotation = channel_data.rotationValue;
}
else
{
rotation = mover->GetLocalToParent();
}
}
Stuff::Scalar small_backup = Stuff::SMALL;
Stuff::SMALL = 1e-3f;
rotation.Normalize();
new_local_to_parent.BuildTranslation(position);
new_local_to_parent.BuildRotation(rotation);
#if defined(_ARMOR)
new_local_to_parent.TestInstance();
#endif
mover->SetNewLocalToParent(new_local_to_parent);
Stuff::SMALL = small_backup;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::MakeArmatureChain()
{
Check_Object(this);
ChainIteratorOf<Entity *> child_iterator(&childEntityChain);
Entity *entity;
//
//Step Through until we find a root mover object
//
while((entity = child_iterator.ReadAndNext()) != NULL)
{
if(entity->IsDerivedFrom(MWMover::DefaultData))
{
MWMover *mover;
mover = Cast_Object(MWMover *, entity);
ConnectMWMover(mover);
entitiesToSync.Add(mover);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::ConnectMWMover(MWMover *mover)
{
Check_Object(this);
ChainIteratorOf<Entity *> child_iterator(mover->GetChildEntityChain());
Entity *entity;
while((entity = child_iterator.ReadAndNext()) != NULL)
{
if(entity->IsDerivedFrom(MWMover::DefaultData))
{
MWMover *child_mover;
child_mover = Cast_Object(MWMover *, entity);
ConnectMWMover(child_mover);
}
}
SortedChainIteratorOf<Site *, MString> site_iterator(&mover->m_sites);
Site *site;
while((site = site_iterator.ReadAndNext()) != NULL)
{
Check_Object(site);
m_sites.AddValue(site, site->GetName());
}
armatureChain.Add(mover);
mover->myParentVehicle = this;
mover->SetSkinPrefix(m_skinPrefix);
mover->SetTeamDecal(m_teamDecal);
mover->SetPilotDecal(m_pilotDecal);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
MWObject::FindChildMoverIndexUserData(
const char *joint_name,
void *user_data
)
{
MWObject *mw_object = (MWObject *)user_data;
Verify(mw_object->IsDerivedFrom(MWObject::DefaultData));
return mw_object->FindChildMoverIndex(joint_name);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
MWObject::FindChildMoverIndex(
const char *temp_name
)
{
MString joint_name;
int index = MW4Animation::UncompressName(temp_name, joint_name);
if (index != -1)
{
if (temporaryQuickIDLookup[index] != -1)
{
return temporaryQuickIDLookup[index];
}
}
else
{
Stuff::ChainIteratorOf<MWMover*> iterator(&armatureChain);
MWMover *mover;
int i = 0;
while ((mover = iterator.ReadAndNext()) != NULL)
{
Check_Object(mover);
const char *compare_name = mover->instanceName;
if (!_stricmp(compare_name, joint_name))
{
Verify(mover == animationArray[i]);
return i;
}
++i;
}
}
return -1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWMover*
MWObject::FindChildMover(
const char *joint_name
)
{
Stuff::ChainIteratorOf<MWMover*> iterator(&armatureChain);
MWMover *mover;
while ((mover = iterator.ReadAndNext()) != NULL)
{
Check_Object(mover);
const char *compare_name = mover->instanceName;
if((compare_name = strstr(compare_name, "::")) != NULL)
{
compare_name += 2;
}
else
{
compare_name = mover->instanceName;
}
if (!_stricmp(compare_name, joint_name))
{
return mover;
}
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::ReuseDamageObjects()
{
Check_Pointer(this);
SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);
SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&internalDamageObjects);
DamageObject *damage_object;
while((damage_object = iterator.ReadAndNext()) != NULL)
{
Check_Object(damage_object);
damage_object->Reuse();
}
InternalDamageObject *internal_object;
while((internal_object = internal_iterator.ReadAndNext()) != NULL)
{
Check_Object(internal_object);
internal_object->Reuse();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::ConnectDamageObjects()
{
Check_Pointer(this);
SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);
SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&internalDamageObjects);
DamageObject *damage_object;
while((damage_object = iterator.ReadAndNext()) != NULL)
{
Check_Object(damage_object);
MWMover *mover;
mover = FindChildMover(damage_object->damageObjectName);
if(mover)
{
Check_Object(mover);
//
//-----------------------------------------------
//Assign Damage Object its internal damage object
//-----------------------------------------------
//
damage_object->internalDamageObject =
internalDamageObjects.Find(damage_object->internalDamageObjectID);
Check_Object(damage_object->internalDamageObject);
damage_object->internalDamageObject->parentEntity =
FindChildMover(damage_object->internalDamageObject->parentEntityName);
damage_object->internalDamageObject->damagePropagationObject =
internalDamageObjects.Find(damage_object->internalDamageObject->damagePropagationZoneID);
mover->SetDamageObject(damage_object);
damage_object->Initialize(mover);
}
else
{
//
//-------------------------------------------------------
//No Name means it is tied to us not part of the armature
//-------------------------------------------------------
//
damage_object->internalDamageObject =
internalDamageObjects.Find(damage_object->internalDamageObjectID);
Check_Object(damage_object->internalDamageObject);
damage_object->internalDamageObject->parentEntity = this;
damage_object->internalDamageObject->damagePropagationObject =
internalDamageObjects.Find(damage_object->internalDamageObject->damagePropagationZoneID);
SetDamageObject(damage_object);
damage_object->Initialize(this);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::AddChild(Entity *entity)
{
Check_Object(this);
Check_Object(entity);
Entity::AddChild(entity);
if (entity->IsDerivedFrom(MWMover::DefaultData))
{
//We must make sure that we are on the armature chain
if(!armatureChain.IsPlugMember(entity))
{
MWMover *mover;
mover = Cast_Object(MWMover *, entity);
armatureChain.Add(mover);
}
}
if(entity->IsDerivedFrom(Subsystem::DefaultData))
{
if(!subsystemsInVehicle.IsPlugMember(entity))
{
Subsystem *subsystem;
subsystem = Cast_Object(Subsystem *, entity);
subsystemsInVehicle.Add(subsystem);
if(subsystem->executionState->GetState() != ExecutionStateEngine::NeverExecuteState)
{
executingSubsystems.Add(subsystem);
}
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::RemoveChild(Entity *entity)
{
Check_Object(this);
Check_Object(entity);
if(entity->IsDerivedFrom(Subsystem::DefaultData))
{
Subsystem *subsystem;
subsystem = Cast_Object(Subsystem *, entity);
subsystemsInVehicle.Remove(subsystem);
executingSubsystems.Remove(subsystem);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::ChildPreCollisionChanged(Entity *entity)
{
Check_Object(this);
Check_Object(entity);
if(entity->IsDerivedFrom(Subsystem::DefaultData))
{
Subsystem *subsystem;
subsystem = Cast_Object(Subsystem *, entity);
if((subsystem->executionState->GetOldState() == ExecutionStateEngine::NeverExecuteState)
&&(subsystem->executionState->GetState() != ExecutionStateEngine::NeverExecuteState))
{
executingSubsystems.Add(subsystem);
}
else if((subsystem->executionState->GetOldState() != ExecutionStateEngine::NeverExecuteState)
&&(subsystem->executionState->GetState() == ExecutionStateEngine::NeverExecuteState))
{
executingSubsystems.Remove(subsystem);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
static Entity*
Find_Child(
Entity *parent,
const char* name
)
{
Check_Object(parent);
Check_Pointer(name);
return Cast_Object(MWObject*, parent)->FindChildMover(name);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::BecomeInteresting(bool render_me)
{
Check_Object(this);
LOAD_LOGIC("Become Interesting::MWObject");
//
//------------------------------------------------------------------------
// The entity version will just load the solid volumes. Go ahead and load
// the stream resource that should be indicated in the game model
//------------------------------------------------------------------------
//
if (!solidVolume && !hierarchicalVolume)
{
const GameModel *game_model = GetGameModel();
Check_Object(game_model);
//
//-------------------------------
// Load in the solid if it exists
//-------------------------------
//
#if defined(LAB_ONLY)
extern char g_LastEntity[255];
if (!instanceName)
g_LastEntity[0] = '\0';
else
{
strncpy(g_LastEntity, instanceName, sizeof(g_LastEntity)-1);
g_LastEntity[sizeof(g_LastEntity)-1] = '\0';
}
#endif
if (game_model->obbStreamResourceID != ResourceID::Null)
{
gos_PushCurrentHeap(Adept::Entity::s_CollisionHeap);
Resource obb_stream(game_model->obbStreamResourceID);
Verify(obb_stream.DoesResourceExist());
solidVolume =
new CollisionVolume(
this,
&obb_stream,
CollisionVolume::ReadOBBVersion(&obb_stream)
);
Check_Object(solidVolume);
gos_PopCurrentHeap();
}
if (game_model->hierarchicalOBBStreamResourceID != ResourceID::Null)
{
gos_PushCurrentHeap(Adept::Entity::s_CollisionHeap);
Resource obb_stream(game_model->hierarchicalOBBStreamResourceID);
Verify(obb_stream.DoesResourceExist());
if (!armatureChain.IsEmpty())
{
hierarchicalVolume =
new CollisionVolume(
this,
Find_Child,
this,
&obb_stream,
CollisionVolume::ReadOBBVersion(&obb_stream)
);
Check_Object(hierarchicalVolume);
}
else
{
#ifdef LAB_ONLY
PAUSE(("Error: %s is missing its armature!", (char*)instanceName));
#endif
if (!solidVolume)
{
solidVolume =
new CollisionVolume(
this,
&obb_stream,
CollisionVolume::ReadOBBVersion(&obb_stream)
);
Check_Object(solidVolume);
}
}
gos_PopCurrentHeap();
}
}
if(!Mission::GetInstance()->DoesAllowRunningLights())
{
DestroyRunningLight();
}
BaseClass::BecomeInteresting(render_me);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::CheckVideoStates(bool render_me)
{
if(render_me && IsDestroyed())
{
entityElement->SetAlwaysCullMode();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::DestroyRunningLight()
{
Check_Object(this);
if(jointRunningLight)
{
Check_Object(jointRunningLight);
jointRunningLight->GetElement()->SetAlwaysCullMode();
if(jointRunningLight->GetSolidVolume() &&
!jointRunningLight->GetSolidVolume()->IsDestroyed())
jointRunningLight->GetSolidVolume()->Destroy();
if(jointRunningLight->GetHierarchicalVolume() &&
!jointRunningLight->GetHierarchicalVolume()->IsDestroyed())
jointRunningLight->GetHierarchicalVolume()->Destroy();
// jointRunningLight->GetElement()->SetAlwaysCullMode();
// jointRunningLight->SetDestroyedFlag(InternalDamageObject::DestructionDamageMode);
// jointRunningLight->SentenceToDeathRow();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::ReuseSubsystems(MemoryStream *stream)
{
Check_Pointer(this);
Stuff::ChainIteratorOf<Subsystem*> iterator(&subsystemsInVehicle);
Subsystem *subsystem;
stream->AdvancePointer(sizeof(WORD));
while (((subsystem = iterator.ReadAndNext()) != NULL) &&
(stream->GetBytesRemaining() > 0))
{
Verify(subsystem->IsDerivedFrom(Subsystem::DefaultData));
Entity::CreateMessage *message =
Cast_Pointer(Entity::CreateMessage*, stream->GetPointer());
subsystem->Respawn(message);
// MSL 5.02 headshot
// bug fix: didn't re-hook these up - note we are explicitly calling the MWObject version
MWObject::AddSubsystem(subsystem);
stream->AdvancePointer(message->messageLength);
}
if(sensor)
{
sensor->SetSensorMode(Sensor::ActiveMode, DoesHaveBeagle());
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::HookUpSubsystems()
{
Stuff::ChainIteratorOf<Subsystem*> iterator(&subsystemsInVehicle);
Subsystem *subsystem;
int weapon_id = 0;
while ((subsystem = iterator.ReadAndNext()) != NULL)
{
Verify(subsystem->IsDerivedFrom(Subsystem::DefaultData));
if(subsystem->ConnectSubsystem())
{
//
//-----------------------------------------------
//Connect the weapons to the correct weapon group
//-----------------------------------------------
//
if(subsystem->IsDerivedFrom(Weapon::DefaultData))
{
Weapon *weapon;
weapon = Cast_Object(Weapon *, subsystem);
weaponChain.Add(weapon);
weapon->SetWeaponID(weapon_id);
++weapon_id;
}
AddSubsystem(subsystem);
}
else
{
RemoveChild(subsystem);
}
}
if(sensor)
{
sensor->SetSensorMode(Sensor::ActiveMode, DoesHaveBeagle());
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::AddSubsystem(Subsystem *subsystem)
{
Check_Object(this);
Check_Object(subsystem);
if(subsystem->IsDerivedFrom(Sensor::DefaultData))
{
sensor = Cast_Object(Sensor *, subsystem);
}
else if (subsystem->IsDerivedFrom(Beagle::DefaultData))
{
beagle = Cast_Object(Beagle *, subsystem);
}
else if (subsystem->IsDerivedFrom(AMS::DefaultData))
{
ams = Cast_Object(AMS *, subsystem);
}
else if(subsystem->IsDerivedFrom(ECM::DefaultData))
{
ecm = Cast_Object(ECM *, subsystem);
}
// MSL 5.02 SubSystems
// else if(subsystem->IsDerivedFrom(EnhancedOptics::DefaultData))
// {
// enhancedOptics = Cast_Object(EnhancedOptics *, subsystem);
// }
else if(subsystem->IsDerivedFrom(IFF_Jammer::DefaultData))
{
iff_jammer = Cast_Object(IFF_Jammer *, subsystem);
}
else if(subsystem->IsDerivedFrom(AdvancedGyro::DefaultData))
{
advancedGyro = Cast_Object(AdvancedGyro *, subsystem);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::RemoveSubsystem(Subsystem *subsystem)
{
Check_Object(this);
Check_Object(subsystem);
if(subsystem->IsDerivedFrom(Weapon::DefaultData))
{
Weapon *weapon;
weapon = Cast_Object(Weapon *, subsystem);
weaponChain.Remove(weapon);
}
else if(subsystem->IsDerivedFrom(Sensor::DefaultData))
{
sensor = NULL;
}
else if (subsystem->IsDerivedFrom(Beagle::DefaultData))
{
beagle = NULL;
}
else if (subsystem->IsDerivedFrom(AMS::DefaultData))
{
ams = NULL;
}
else if(subsystem->IsDerivedFrom(ECM::DefaultData))
{
ecm = NULL;
}
// MSL 5.02 SubSystems
// else if(subsystem->IsDerivedFrom(EnhancedOptics::DefaultData))
// {
// enhancedOptics = NULL;
// }
else if(subsystem->IsDerivedFrom(IFF_Jammer::DefaultData))
{
iff_jammer = NULL;
}
else if(subsystem->IsDerivedFrom(AdvancedGyro::DefaultData))
{
advancedGyro = NULL;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::ReactToDestruction(int damage_mode, int damage_type)
{
Check_Object(this);
switch(damage_mode)
{
case InternalDamageObject::DestructionDamageMode:
{
if(!IsDestroyed())
{
Check_Object(executionState);
// executionState->RequestState(ExecutionStateEngine::DestroyedState);
if(m_AI)
{
Check_Object(m_AI);
m_AI->Die();
}
else
{
MW4AI::g_Rect4DHash->RemovePermRect (this);
}
SetDestroyedFlag(damage_mode);
if (damage_type != SplashDamageType)
DealSplashDamage();
const GameModel *model = GetGameModel();
Check_Object(model);
CreateEffect(model->destroyedEffectResource, this, false);
if(!m_deathEntity.GetCurrent())
{
Entity *death_entity = CreateStaticHermitEntity(model->deathEntityResource);
if(death_entity)
{
m_deathEntity.Remove();
m_deathEntity.Add(death_entity);
}
}
RemoveFromExecution();
// SentenceToDeathRow();
DestroyChildren(damage_mode);
break;
}
}
}
Entity::ReactToDestruction(damage_mode, damage_type);
#ifdef LAB_ONLY
if (MW4AI::Statistics::Enabled() == true)
{
MW4AI::Statistics::NotifyDestroyed(objectID);
}
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWObject::DestroyDamageObjects()
{
SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);
SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&internalDamageObjects);
DamageObject *damage_object;
while((damage_object = iterator.ReadAndNext()) != NULL)
{
Check_Object(damage_object);
damage_object->SilentDestruction();
}
InternalDamageObject *internal_object;
while((internal_object = internal_iterator.ReadAndNext()) != NULL)
{
Check_Object(internal_object);
internal_object->SilentDestruction();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWObject::DealSplashDamage()
{
Check_Object(this);
Check_Object(CollisionGrid::Instance);
extern g_nMR;
if (g_nMR == 2)
return;
if (!Network::GetInstance()->AmIServer())
return;
NetMissionParameters::MWNetMissionParameters *params = MWApplication::GetInstance()->GetLocalNetParams();
if (!params->m_splashOn)
return;
const GameModel *model = GetGameModel();
Check_Object(model);
Verify(splashedEntities.IsEmpty());
splashSize = 0;
if (model->splashDamageAmount > 0.0f)
{
//
// Need to see if the target has a solid volume and if so, use that for the positioning of the target
// bracket.
CollisionVolume * volume;
//
// This code was just getting the torso and using that local to world but the torso location
// was whacked. That should be fixed as a secondary issue, but for here the solid volume is
// good since that is what would be doing ramming damage, etc... anyway.
//
volume = GetSolidVolume();
if (!volume)
{
if (GetTorso())
volume = GetTorso()->GetHierarchicalVolume();
else
volume = GetHierarchicalVolume();
}
Stuff::Sphere sphere;
if (volume)
{
OBB world_bounds;
world_bounds.Multiply(volume->m_localSpaceBounds, GetLocalToWorld());
sphere.center = world_bounds.localToParent;
}
else
{
sphere.center = GetLocalToWorld();
}
sphere.radius = model->splashDamageRadius;
splashSize = 0;
CollisionGrid::Instance->FindEntitiesWithin(sphere, (Adept::CollisionGrid::WithinCallback)SplashCallBack, this);
if (splashSize == 0)
return;
ChainIteratorOf<Entity *> splashed_entities(&splashedEntities);
//
// First, iterate through the list once to clear the been hit flag so we don't do
// double/or more damage to multiple entities, connected to the same damage zones
//
Entity *hit_entity;
while((hit_entity = splashed_entities.ReadAndNext()) != NULL)
{
if (hit_entity->damageObject)
hit_entity->damageObject->ClearTakenDamageFromThisEvent();
}
splashed_entities.First();
NetMissionParameters::MWNetMissionParameters *params = MWApplication::GetInstance()->GetLocalNetParams();
while((hit_entity = splashed_entities.GetCurrent()) != NULL)
{
if (hit_entity->damageObject)
{
//
// If there is a damage object verify we aren't hitting it twice
//
if (!hit_entity->damageObject->GetTakenDamageFromThisEvent())
{
hit_entity->damageObject->SetTakenDamageFromThisEvent() ;
}
else
{
splashed_entities.Remove();
continue;
}
}
Stuff::Point3D ltwEntity;
ltwEntity = hit_entity->GetLocalToWorld();
// MSL 5.06 Armor Mode
MWApplication *m_App;
m_App = MWApplication::GetInstance ();
m_ArmorMode = m_App->GetLocalNetParams()->m_armormodeOn;
Adept::Entity__TakeDamageMessage message(
hit_entity->GetReplicatorID(),
this->GetReplicatorID(),
model->splashDamageAmount * ((Scalar)params->m_splashPercentage*0.01f),
m_ArmorMode,
SplashDamageType,
Normal3D(0.0f, 0.0f, 1.0f),
ltwEntity,
model->splashHeatAmount,
false,
TakeDamageMessage::DefaultWeaponType
);
hit_entity->Receive(&message);
splashed_entities.Remove();
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWObject::SplashCallBack(Adept::Entity *entity, Adept::Entity *original_caller, const Stuff::Sphere &sphere)
{
Check_Object(entity);
Check_Object(original_caller);
MWObject *mwobject = Cast_Object( MWObject*, original_caller);
if (!entity->IsDestroyed())
{
CollisionVolume *volume = entity->GetHierarchicalVolume();
if (volume)
{
volume->FindSolidsWithin(
sphere,
(Adept::CollisionVolume::WithinCallback)SubSplashCallBack,
mwobject,
entity,
entity->GetLocalToWorld()
);
}
else
{
mwobject->splashedEntities.Add(entity);
++mwobject->splashSize;
}
}
}
void MWObject::SubSplashCallBack(CollisionVolume *solid, Entity *original_caller, const Stuff::Sphere &sphere)
{
Check_Object(solid);
Check_Object(original_caller);
MWObject *mwobject = Cast_Object( MWObject*, original_caller);
if (solid->m_entity && !solid->m_entity->IsDestroyed())
{
mwobject->splashedEntities.Add(solid->m_entity);
++mwobject->splashSize;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWObject::TakeSplashDamage(Adept::Entity__TakeDamageMessage *message)
{
Check_Object(this);
Check_Object(CollisionGrid::Instance);
// go thru my damage objects and deal the damage
SortedChainIteratorOf<DamageObject *, int> damage_iterator(&damageObjects);
DamageObject *damage_object;
while((damage_object = damage_iterator.ReadAndNext()) != NULL)
{
damage_object->TakeDamage(message, NULL);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::RemoveFromExecution()
{
Check_Object(this);
Check_Object(entityElement);
Check_Object(executionState);
if (newCollisions)
{
delete newCollisions;
newCollisions = NULL;
}
executionState->RequestState(ExecutionStateEngine::NeverExecuteState);
entityElement->SetAlwaysCullMode();
EntityManager::GetInstance()->RemovePostCollisionExecution(this);
RemoveCollision();
SyncMatrices(true);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::PreCollisionExecute(Stuff::Time till)
{
Check_Object(this);
PRECOLLISION_LOGIC("MWObject");
m_hasExecuted = true;
#if defined(LAB_ONLY)
if (!instanceName)
MWGameInfo::g_LastMWObject[0] = '\0';
else
{
strncpy(MWGameInfo::g_LastMWObject, instanceName, sizeof(MWGameInfo::g_LastMWObject)-1);
MWGameInfo::g_LastMWObject[sizeof(MWGameInfo::g_LastMWObject)-1] = '\0';
}
MWGameInfo::g_LastMWObjectPos = GetLocalToWorld();
#endif
//
//----------------------------------------------
// All MWObjects that execute use post collision
//----------------------------------------------
//
UsePostCollision();
BaseClass::PreCollisionExecute(till);
//
//-------------------------------------------------
// Run the ubsystems, then finally the heat manager
//-------------------------------------------------
//
{
ChainIteratorOf<Subsystem *> sub_iterator(&executingSubsystems);
Subsystem *subsystem;
while((subsystem = sub_iterator.ReadAndNext()) != NULL)
{
Check_Object(subsystem);
subsystem->PreCollisionExecute(till);
Verify(!subsystem->IsUsingPostCollision() || EntityManager::GetInstance()->IsInPostCollisionExecution(subsystem));
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::SyncMatrices(bool update_matrix)
{
Check_Object(this);
SYNC_LOGIC("MWObject");
#if defined(HUNT_BUG)
bool old_update=update_matrix;
if (update_matrix)
{
SPEW((0, "MWObject::SyncMatrices %s(+", GetClassString()));
Spew(0, GetReplicatorID());
SPEW((0, ")"));
}
#endif
Set_Statistic(s_EntitiesSynced, s_EntitiesSynced);
//
//-----------------------------------------
// If we have a dirty locator, sync with it
//-----------------------------------------
//
if (IsMatrixDirty())
{
if (update_matrix)
{
Check_Object(entityElement);
entityElement->Sync();
update_matrix = false;
}
ClearNeedMatrixSync();
}
//
//-----------------------------
// Sync our children's locators
//-----------------------------
//
if (!entitiesToSync.IsEmpty())
{
ChainIteratorOf<MWMover*> children(&entitiesToSync);
Entity *child;
while ((child = children.ReadAndNext()) != NULL)
{
Check_Object(child);
child->SyncMatrices(update_matrix);
}
}
#if defined(HUNT_BUG)
if (old_update)
SPEW((0, ""));
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWObject::PostCollisionExecute(Time till)
{
Check_Object(this);
Check_Object(executionState);
POSTCOLLISION_LOGIC("MWObject");
{for (std::vector<Torso*>::iterator i = m_Torsos.begin();
i != m_Torsos.end();
++i)
{
if ((*i)->followTorsoRequest)
{
gosREPORT(*i,"somehow a mwobject got a follow torso request when it has no torso");
Check_Object(*i);
Point3D target_position = (*i)->torsoRequest;
Point3D distance_to_target;
distance_to_target.MultiplyByInverse(target_position,(*i)->GetTwistJointMatrix());
#if 0
MWMover *eye_site = eyeSitePointer.GetCurrent();
YawPitchRoll twist_offset = YawPitchRoll::Identity;
Point3D local_eye_site_offset_pitch = Point3D::Identity;
Point3D local_eye_site_offset_twist = Point3D::Identity;
if(eye_site)
{
Check_Object(eye_site);
Point3D world_eye_site = (Point3D) eye_site->GetLocalToWorld();
// LinearMatrix4D world_eye_site = eye_site->GetLocalToWorld();
// world_eye_site.Invert();
// LinearMatrix4D local_eye_site_offset = LinearMatrix4D::Identity;
local_eye_site_offset_twist.MultiplyByInverse(world_eye_site, (*i)->GetTwistJointMatrix());
local_eye_site_offset_pitch.MultiplyByInverse(world_eye_site, (*i)->GetPitchJointMatrix());
// twist_offset = (YawPitchRoll) local_eye_site_offset;
}
#endif
Scalar heading_adjustment;
Point3D distance_to_target_pitch;
distance_to_target_pitch.MultiplyByInverse(target_position,(*i)->GetPitchJointMatrix());
if(!Small_Enough(distance_to_target_pitch.z))
{
// heading_adjustment = Arctan(distance_to_target_pitch.y, distance_to_target_pitch.z) - (Arctan(local_eye_site_offset_pitch.y, local_eye_site_offset_pitch.z));;
heading_adjustment = Arctan(distance_to_target_pitch.y, distance_to_target_pitch.z);
if(!Small_Enough(heading_adjustment))
{
Scalar speed_demand;
if (heading_adjustment > (*i)->GetPitchSpeed())
{
speed_demand = 1.0;
}
else
{
speed_demand = heading_adjustment / (*i)->GetPitchSpeed();
speed_demand = Abs(speed_demand);
}
if(heading_adjustment > 0.02) // down
(*i)->pitchDemand = -speed_demand;
if(heading_adjustment < -0.02) // up
(*i)->pitchDemand = speed_demand;
}
}
#if 0
if(eye_site)
{
Check_Object(eye_site);
Point3D world_eye_site = (Point3D) eye_site->GetLocalToWorld();
// LinearMatrix4D world_eye_site = eye_site->GetLocalToWorld();
// world_eye_site.Invert();
// LinearMatrix4D local_eye_site_offset = LinearMatrix4D::Identity;
local_eye_site_offset_twist.MultiplyByInverse(world_eye_site, (*i)->GetTwistJointMatrix());
local_eye_site_offset_pitch.MultiplyByInverse(world_eye_site, (*i)->GetPitchJointMatrix());
// twist_offset = (YawPitchRoll) local_eye_site_offset;
}
#endif
if(!Small_Enough(distance_to_target.z))
{
// heading_adjustment = (Arctan(distance_to_target.x, distance_to_target.z)) + twist_offset.yaw;
// heading_adjustment = (Arctan(distance_to_target.x, distance_to_target.z)) - (Arctan(local_eye_site_offset_twist.x, local_eye_site_offset_twist.z));
heading_adjustment = (Arctan(distance_to_target.x, distance_to_target.z));
if(!Small_Enough(heading_adjustment))
{
Scalar speed_demand;
if (heading_adjustment > (*i)->GetTwistSpeed())
{
speed_demand = 1.0;
}
else
{
speed_demand = heading_adjustment / (*i)->GetTwistSpeed();
speed_demand = Abs(speed_demand);
}
if(heading_adjustment > 0.02) //left
(*i)->yawDemand = speed_demand;
if(heading_adjustment < -0.02) //right
(*i)->yawDemand = -speed_demand;
}
}
}
}}
BaseClass::PostCollisionExecute(till);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Effect*
MWObject::CreateEffect(const Adept::ResourceID& effect_id, MWMover *parent_part, bool follow_joint)
{
if (effect_id == ResourceID::Null)
return NULL;
Resource resource(effect_id);
Verify(resource.DoesResourceExist());
ClassID class_ID;
class_ID = Entity::GetClassIDFromDataListID(effect_id);
Verify(class_ID != NullClassID);
LinearMatrix4D effect_location = GetLocalToWorld();
if(parent_part)
{
Check_Object(parent_part);
effect_location = parent_part->GetLocalToWorld();
}
Effect::CreateMessage effect_create_message(
sizeof(Effect::CreateMessage),
DefaultEventPriority,
Entity::CreateMessage::DefaultFlags,
class_ID,
Effect::DefaultFlags,
effect_id,
effect_location,
0.0f,
Entity::ExecutionStateEngine::AlwaysExecuteState,
NameTable::NullObjectID,
Entity::DefaultAlignment
);
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
Effect *entity;
ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
entity = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
Check_Object(entity);
Check_Object(Map::GetInstance());
Map::GetInstance()->AddChild(entity);
if (parent_part != NULL && follow_joint)
{
entity->SetFollowEntity(parent_part);
entity->PlaceOnEntity();
}
entity->SyncMatrices(true);
return entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Effect*
MWObject::CreateEffect(const Adept::ResourceID& effect_id, Site *parent_part, bool follow_joint)
{
if (effect_id == ResourceID::Null)
return NULL;
Resource resource(effect_id);
Verify(resource.DoesResourceExist());
ClassID class_ID;
class_ID = Entity::GetClassIDFromDataListID(effect_id);
Verify(class_ID != NullClassID);
LinearMatrix4D effect_location = GetLocalToWorld();
if(parent_part)
{
Check_Object(parent_part);
effect_location = parent_part->GetLocalToWorld();
}
Effect::CreateMessage effect_create_message(
sizeof(Effect::CreateMessage),
DefaultEventPriority,
Entity::CreateMessage::DefaultFlags,
class_ID,
Effect::DefaultFlags,
effect_id,
effect_location,
0.0f,
Entity::ExecutionStateEngine::AlwaysExecuteState,
NameTable::NullObjectID,
Entity::DefaultAlignment
);
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
Effect *entity;
ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
entity = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
Check_Object(entity);
Check_Object(Map::GetInstance());
Map::GetInstance()->AddChild(entity);
if (parent_part != NULL && follow_joint)
{
entity->SetFollowEntity(parent_part);
entity->PlaceOnSite();
}
entity->SyncMatrices(true);
return entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Effect*
MWObject::CreateLoopingEffect(const Adept::ResourceID& effect_id, MWMover *parent_part, bool follow_joint)
{
if (effect_id == ResourceID::Null)
return NULL;
Resource resource(effect_id);
Verify(resource.DoesResourceExist());
ClassID class_ID;
class_ID = Entity::GetClassIDFromDataListID(effect_id);
Verify(class_ID != NullClassID);
LinearMatrix4D effect_location = GetLocalToWorld();
if(parent_part)
{
Check_Object(parent_part);
effect_location = parent_part->GetLocalToWorld();
}
Effect::CreateMessage effect_create_message(
sizeof(Effect::CreateMessage),
DefaultEventPriority,
Entity::CreateMessage::DefaultFlags,
class_ID,
Effect::DefaultFlags|Effect::LoopFlag,
effect_id,
effect_location,
0.0f,
Entity::ExecutionStateEngine::AlwaysExecuteState,
NameTable::NullObjectID,
Entity::DefaultAlignment
);
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
Effect *entity;
ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
entity = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
Check_Object(entity);
Check_Object(Map::GetInstance());
Map::GetInstance()->AddChild(entity);
if (parent_part != NULL && follow_joint)
{
entity->SetFollowEntity(parent_part);
entity->PlaceOnEntity();
}
entity->SyncMatrices(true);
return entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Effect*
MWObject::CreateLoopingEffect(const Adept::ResourceID& effect_id, const Point3D &location)
{
if (effect_id == ResourceID::Null)
return NULL;
Resource resource(effect_id);
Verify(resource.DoesResourceExist());
ClassID class_ID;
class_ID = Entity::GetClassIDFromDataListID(effect_id);
Verify(class_ID != NullClassID);
LinearMatrix4D effect_location = LinearMatrix4D::Identity;
effect_location.BuildTranslation(location);
Effect::CreateMessage effect_create_message(
sizeof(Effect::CreateMessage),
DefaultEventPriority,
Entity::CreateMessage::DefaultFlags,
class_ID,
Effect::DefaultFlags|Effect::LoopFlag,
effect_id,
effect_location,
0.0f,
Entity::ExecutionStateEngine::AlwaysExecuteState,
NameTable::NullObjectID,
Entity::DefaultAlignment
);
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
Effect *entity;
ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
entity = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
Check_Object(entity);
Check_Object(Map::GetInstance());
Map::GetInstance()->AddChild(entity);
entity->SyncMatrices(true);
return entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Effect*
MWObject::CreateLoopingEffect(const Adept::ResourceID& effect_id, Site *parent_part, bool follow_joint)
{
if (effect_id == ResourceID::Null)
return NULL;
Resource resource(effect_id);
Verify(resource.DoesResourceExist());
ClassID class_ID;
class_ID = Entity::GetClassIDFromDataListID(effect_id);
Verify(class_ID != NullClassID);
LinearMatrix4D effect_location = GetLocalToWorld();
if(parent_part)
{
Check_Object(parent_part);
effect_location = parent_part->GetLocalToWorld();
}
Effect::CreateMessage effect_create_message(
sizeof(Effect::CreateMessage),
DefaultEventPriority,
Entity::CreateMessage::DefaultFlags,
class_ID,
Effect::DefaultFlags|Effect::LoopFlag,
effect_id,
effect_location,
0.0f,
Entity::ExecutionStateEngine::AlwaysExecuteState,
NameTable::NullObjectID,
Entity::DefaultAlignment
);
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
Effect *entity;
ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
entity = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
Check_Object(entity);
Check_Object(Map::GetInstance());
Map::GetInstance()->AddChild(entity);
if (parent_part != NULL && follow_joint)
{
entity->SetFollowEntity(parent_part);
entity->PlaceOnSite();
}
entity->SyncMatrices(true);
return entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Effect*
MWObject::CreateEffect(const Adept::ResourceID& effect_id, const Point3D &location)
{
if (effect_id == ResourceID::Null)
return NULL;
Resource resource(effect_id);
Verify(resource.DoesResourceExist());
ClassID class_ID;
class_ID = Entity::GetClassIDFromDataListID(effect_id);
Verify(class_ID != NullClassID);
LinearMatrix4D effect_location = LinearMatrix4D::Identity;
effect_location.BuildTranslation(location);
Effect::CreateMessage effect_create_message(
sizeof(Effect::CreateMessage),
DefaultEventPriority,
Entity::CreateMessage::DefaultFlags,
class_ID,
Effect::DefaultFlags,
effect_id,
effect_location,
0.0f,
Entity::ExecutionStateEngine::AlwaysExecuteState,
NameTable::NullObjectID,
Entity::DefaultAlignment
);
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
Effect *entity;
ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
entity = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
Check_Object(entity);
Check_Object(Map::GetInstance());
Map::GetInstance()->AddChild(entity);
entity->SyncMatrices(true);
return entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// MSL 5.03 Glass
Effect*
MWObject::CreateEffect(const Adept::ResourceID& effect_id, const Point3D &location, const Vector3D &vector)
{
if (effect_id == ResourceID::Null)
return NULL;
Resource resource(effect_id);
Verify(resource.DoesResourceExist());
ClassID class_ID;
class_ID = Entity::GetClassIDFromDataListID(effect_id);
Verify(class_ID != NullClassID);
LinearMatrix4D effect_location = LinearMatrix4D::Identity;
effect_location.AlignLocalAxisToWorldVector(vector, Y_Axis, X_Axis, Z_Axis);
effect_location.BuildTranslation(location);
Effect::CreateMessage effect_create_message(
sizeof(Effect::CreateMessage),
DefaultEventPriority,
Entity::CreateMessage::DefaultFlags,
class_ID,
Effect::DefaultFlags,
effect_id,
effect_location,
0.0f,
Entity::ExecutionStateEngine::AlwaysExecuteState,
NameTable::NullObjectID,
Entity::DefaultAlignment
);
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
Effect *entity;
ReplicatorID effect_rep_id = Connection::Hermit->GetNextReplicatorID();
entity = Cast_Object(Effect *,Entity::CreateEntity(&stream, &effect_rep_id, false));
Check_Object(entity);
Check_Object(Map::GetInstance());
Map::GetInstance()->AddChild(entity);
entity->SyncMatrices(true);
return entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Entity *
MWObject::CreateStaticHermitEntity(ResourceID entity_id)
{
if(entity_id == ResourceID::Null)
return false;
ClassID class_ID;
class_ID = GetClassIDFromDataListID(entity_id);
Verify(class_ID != NullClassID);
unsigned flags = HermitMode;
Entity::CreateMessage entity_create_message(
sizeof(Entity::CreateMessage),
DefaultEventPriority,
CreateMessage::DefaultFlags,
class_ID,
flags,
entity_id,
GetLocalToWorld(),
0.0f,
ExecutionStateEngine::NeverExecuteState,
NameTable::NullObjectID,
Entity::DefaultAlignment
);
MemoryStream stream(&entity_create_message, entity_create_message.messageLength);
Entity *entity;
ReplicatorID beam_id = Connection::Hermit->GetNextReplicatorID();
entity = CreateEntity(&stream, &beam_id, false);
Check_Object(entity);
entity->SetPropType(MissionPropType);
Map::GetInstance()->AddChild(entity);
entity->SyncMatrices(true);
return entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
void MWObject::AttachAI (AI *ai)
{
Check_Object (this);
if (ai != 0)
{
Check_Object (ai);
}
m_AI = ai;
}
void MWObject::SentenceToDeathRow()
{
Check_Object(this);
if (m_AI)
m_AI->SentenceToDeathRow ();
BaseClass::SentenceToDeathRow ();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const MWObject::GroupList&
MWObject::GetGroups() const
{
return m_groups;
}
MWObject::GroupList&
MWObject::GetGroups()
{
return m_groups;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
MWObject::GetSensorMode()
{
Check_Object(this);
if(sensor)
{
Check_Object(sensor);
return sensor->sensorMode;
}
return Sensor::ActiveMode;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
MWObject::DoesHaveBeagle()
{
Check_Object(this);
if(beagle)
return true;
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::AddStatsToString(std::string& s)
{
s += instanceName;
if ((DamageDispatch::GetGlobalInvulnerability() == true) &&
(IsPlayerVehicle() == true))
{
s += " (INVULNERABLE)";
}
if (GetTargetDesirability() == desirability_never)
{
s += " (IGNORE)";
}
if (IsDestroyed() == true)
{
s += " (DEAD)";
}
char temp[80];
if(isPlayerVehicle)
{
if(VehicleInterface::GetInstance())
{
s += "\nTARGETMATERIAL: ";
int material_num = VehicleInterface::GetInstance()->targetQuery.m_material;
const char *material = MaterialTypeAsciiToText(material_num);
sprintf(temp,"%s\n",(char *)material);
s += temp;
}
}
s += "\nTONNAGE: ";
sprintf(temp,"%d",(int)GetTonage());
s += temp;
s += "\nBATTLEVALUE: ";
sprintf(temp,"%d",(int)GetBattleValue());
s += temp;
s += "\nHEAT: ";
if(m_heatManager)
sprintf(temp,"%f",m_heatManager->GetHeat());
else
sprintf(temp,"NA");
s += temp;
s += "\nCOOLANT: ";
if(m_heatManager)
sprintf(temp,"%f",m_heatManager->GetCoolant());
else
sprintf(temp, "NA");
s += temp;
s += "\nPOSITION: x=";
Point3D pos = (Point3D)GetLocalToWorld();
s += ScalarToString(pos.x);
s += ", z=";
s += ScalarToString(pos.z);
s += "\n";
if (GetTorso() != 0)
{
s += "Torso: y=";
sprintf(temp,"%.2f p=%.2f\n",GetTorso()->yawValue,GetTorso()->pitchValue);
s += temp;
}
if (GetTargetDesirability() >= 0)
{
sprintf(temp,"Target Desirability: %d\n",(int)(GetTargetDesirability() * 100));
s += temp;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::AddDamageInfoToString(std::string& s)
{
Check_Object(this);
char temp[80];
SortedChainIteratorOf<MWInternalDamageObject *, int> internal_iterator(&internalDamageObjects);
SortedChainIteratorOf<DamageObject*, int> damage_iterator(&damageObjects);
s += "\nARMOR\n";
DamageObject *damage_object;
while((damage_object = damage_iterator.ReadAndNext()) != NULL)
{
Check_Object(damage_object);
s += damage_object->damageObjectName;
sprintf(temp, "base: %.2f current: %.2f\n", damage_object->baseArmorValue, damage_object->currentArmorValue);
s += temp;
}
s += "\nINTERNAL\n";
MWInternalDamageObject *internal_object;
while((internal_object = internal_iterator.ReadAndNext()) != NULL)
{
Check_Object(internal_object);
s += InternalDamageObject::InternalZoneAsciiToText(internal_object->damageZone);
sprintf(temp, "Mode: %s\n", InternalDamageObject::DamageModeAsciiToText(internal_object->damageMode));
s += temp;
sprintf(temp, "base: %.2f current: %.2f\n", internal_object->baseInternalDamage, internal_object->currentInternalDamage);
s += temp;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::NotifyProjectileApproaching(const Stuff::Point3D& origin)
{
BaseClass::NotifyProjectileApproaching(origin);
if (GetAI() != 0)
{
GetAI()->NotifyProjectileApproaching(origin);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::NotifyOfMissileLock()
{
Check_Object(this);
if(vehicleInterface)
vehicleInterface->ReactToEvent (VehicleInterface::MISSILE_LOCKED_ON_ME);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceID
MWObject::ReactToMissileApproach(Scalar distance, const Point3D& current_position)
{
Check_Object(this);
if(GetAMS())
{
const AMS__GameModel *model = GetAMS()->GetGameModel();
Check_Object(model);
if(GetAMS()->DoesHaveAmmo())
{
GetAMS()->SubtractAmmo(1);
return model->amsEffectResource;
}
}
return ResourceID::Null;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::SetTargetDesirability(Stuff::Scalar desirability)
{
if (desirability == desirability_never)
{
Verify(Adept::EntityManager::GetInstance() != 0);
NameTable *table = NameTable::GetInstance();
{
int size(table->nameTableArray[NameTable::VehicleArray].GetLength());
{for (int i = 0;
i < size;
++i)
{
NameTableEntry *data = &table->nameTableArray [NameTable::VehicleArray][i];
Adept::Entity* ent = data->dataPointer->GetCurrent ();
if ((ent != 0) &&
(ent->IsDerivedFrom(MWObject::DefaultData) == true))
{
MWObject* mwobject = Cast_Object(MWObject*,ent);
if (mwobject->GetAI() != 0)
{
mwobject->GetAI()->EnsureNotTargeting(objectID);
}
}
}}
}
{
int size(table->nameTableArray[NameTable::TurretArray].GetLength());
{for (int i = 0;
i < size;
++i)
{
NameTableEntry *data = &table->nameTableArray [NameTable::TurretArray][i];
Adept::Entity* ent = data->dataPointer->GetCurrent ();
if ((ent != 0) &&
(ent->IsDerivedFrom(MWObject::DefaultData) == true))
{
MWObject* mwobject = Cast_Object(MWObject*,ent);
if (mwobject->GetAI() != 0)
{
mwobject->GetAI()->EnsureNotTargeting(objectID);
}
}
}}
}
}
else
{
if (desirability != desirability_invalid)
{
Verify(desirability >= 0);
Verify(desirability <= 1);
}
}
m_TargetDesirability = desirability;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Scalar
MWObject::GetTargetDesirability() const
{
return (m_TargetDesirability);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::NotifyFired(const Adept::Entity::CollisionQuery& query)
{
if (GetAI() != 0)
{
GetAI()->NotifyShotFired(query,*this);
}
if ((GetSensor() == 0) ||
(query.m_line == 0))
{
return;
}
const MechWarrior4::Sensor::sensorDataArray& sensed_data = GetSensor()->GetSensorData();
{for (int i = 0;
i < sensed_data.GetLength();
++i)
{
MechWarrior4::SensorData* d = sensed_data[i];
if ((d != 0) &&
(d->object.GetCurrent() != 0) &&
(d->object.GetCurrent() != this) &&
(d->object.GetCurrent()->IsDerivedFrom(MWObject::DefaultData)))
{
MWObject* that = Cast_Object(MWObject*,d->object.GetCurrent());
Check_Object(that);
if (that->GetAI() != 0)
{
that->GetAI()->NotifyShotFired(query,*this);
}
}
}}
// special case for shutdown mechs since they don't appear on sensors
MechAI::NotifyShutDownMechsShotFired(query,*this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::NotifyInTargetingReticule(MWObject& who)
{
if (GetAI() != 0)
{
GetAI()->NotifyInTargetingReticule(who);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
MWObject::CollisionHandler(
Stuff::LinearMatrix4D *new_position,
Stuff::DynamicArrayOf<CollisionData> *collisions
)
{
Check_Object(this);
Verify(GetInterestLevel() != DormantInterestLevel);
Verify(EntityManager::GetInstance()->IsInPostCollisionExecution(this));
STOP(("What are we doing here?!?!"));
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::GetLineOfSight(Stuff::LinearMatrix4D& line_of_sight)
{
if ((GetTorso()) &&
(GetTorso()->twistJoint))
{
line_of_sight = GetTorso()->twistJoint->GetLocalToWorld();
}
else
{
if (eyeSitePointer.GetCurrent())
{
line_of_sight = eyeSitePointer.GetCurrent()->GetLocalToWorld();
}
else
{
line_of_sight = GetLocalToWorld();
}
}
Adept::InternalDamageObject* torso_zone = internalDamageObjects.Find(Adept::InternalDamageObject::CenterTorsoZone);
if ((torso_zone != 0) &&
(torso_zone->parentEntity != 0))
{
line_of_sight.BuildTranslation((Stuff::Point3D)torso_zone->parentEntity->GetLocalToWorld());
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Point3D
MWObject::GetLineOfSight()
{
Adept::InternalDamageObject* torso_zone = internalDamageObjects.Find(Adept::InternalDamageObject::CenterTorsoZone);
if ((torso_zone != 0) &&
(torso_zone->parentEntity != 0))
{
return (torso_zone->parentEntity->GetLocalToWorld());
}
if ((GetTorso()) &&
(GetTorso()->twistJoint))
{
return (GetTorso()->twistJoint->GetLocalToWorld());
}
if (eyeSitePointer.GetCurrent())
{
return (eyeSitePointer.GetCurrent()->GetLocalToWorld());
}
Point3D p(GetLocalToWorld());
p.y += 1.0f;
return (p);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::ReactToHit(const Entity__TakeDamageMessage *message,Adept::DamageObject *part_hit)
{
Check_Object(this);
Check_Object(message);
if (g_nMR == 2)
return;
if (IsDestroyed())
return;
#ifdef LAB_ONLY
if ((GetOwner() != 0) &&
(MW4AI::Statistics::Enabled() == true))
{
Connection *connection = Network::GetInstance()->GetConnection(message->inflictingEntityID.connectionID);
if (connection == NULL)
return;
Replicator* r = connection->FindReplicator(message->inflictingEntityID);
if (r != 0)
{
Verify(r->IsDerivedFrom(Entity::DefaultData));
Entity* e = Cast_Object(Entity*,r);
MW4AI::Statistics::NotifyDamageTaken(objectID,e->objectID,message->amountOfDamage,message->typeOfDamage);
}
}
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Point3D&
MWObject::EstimateFuturePosition(
Stuff::Point3D* new_position,
Stuff::Scalar seconds,
bool consider_terrain
)
{
Check_Object(this);
return *new_position = GetLocalToWorld();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::Reuse(
const CreateMessage *message,
ReplicatorID *base_id
)
{
Check_Object(this);
Check_Object(message);
STOP(("Not implemented"));
BaseClass::Reuse(message, base_id);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::ToggleSearchLight()
{
Check_Object(this);
Check_Object(Mission::GetInstance());
if(Mission::GetInstance()->DoesAllowSearchLights())
{
if(searchLight)
{
if(IsSearchLightOn())
{
//
// [johnyo] 08/27/00 PreviousSearchLight code is experimental code that I have checked in to keep a backup
// of only. It may be ripped out shortly if the effect that it was intended to have isn't
// put into the game
//
// if (IsPlayerVehicle())
// Mission::GetInstance()->ResetMissionLights();
searchLight->HideBeam();
// SetSearchLightMode(true);
}
else
{
// if (IsPlayerVehicle())
// Mission::GetInstance()->SetSearchLightMissionLights();
searchLight->ShowBeam();
// SetSearchLightMode(false);
}
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::TurnOnSearchLight()
{
Check_Object(this);
Check_Object(Mission::GetInstance());
// MSL 5.02 SearchLight
// if(Mission::GetInstance()->m_isNightMission)
if(Mission::GetInstance()->DoesAllowSearchLights())
{
// if (IsPlayerVehicle())
// Mission::GetInstance()->SetSearchLightMissionLights();
if(searchLight)
searchLight->ShowBeam();
// SetSearchLightMode(true);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::TurnOffSearchLight()
{
Check_Object(this);
// MWMission *mw_mission = Cast_Object(MWMission *, MWMission::GetInstance());
// mw_mission->ResetMissionLights();
if(searchLight)
searchLight->HideBeam();
// SetSearchLightMode(false);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
MWObject::IsSearchLightOn()
{
Check_Object(this);
if(searchLight)
return searchLight->isLightOn;
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Scalar
MWObject::FriendlyFireDamageMultiplier() const
{
return (1);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::TakeDamageMessageHandler(const TakeDamageMessage *message)
{
Check_Object(this);
Check_Object(message);
Verify(message->messageID == TakeDamageMessageID);
if(damageObject)
{
damageObject->TakeDamage((TakeDamageMessage *)message, this);
}
DamageObject *damage_object;
SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);
while((damage_object = iterator.ReadAndNext()) != NULL)
{
Check_Object(damage_object);
if(damage_object != damageObject)
{
damage_object->TakeDamage((TakeDamageMessage *)message, NULL);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
char*
MWObject::GetObjectName()
{
Check_Object(this);
Check_Object(MWApplication::GetInstance());
if(m_doesHaveInstanceName)
{
if((m_localizeIndex > -1) && (!isPlayerVehicle))
{
return MWApplication::GetInstance()->GetLocString(m_localizeIndex);
}
else
{
return (char *)instanceName;
}
}
else
{
if(isPlayerVehicle)
return (char *)instanceName;
}
const GameModel *model = GetGameModel();
Check_Object(model);
return MWApplication::GetInstance()->GetLocString(model->m_nameIndex);
}
char* MWObject::GetModelName()
{
Check_Object(this);
Check_Object(MWApplication::GetInstance());
const GameModel *model = GetGameModel();
Check_Object(model);
return MWApplication::GetInstance()->GetLocString(model->m_nameIndex);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
MWObject::GetVisibleOnSensors() const
{
return (m_VisibleOnSensors);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWObject::SetVisibleOnSensors(bool visible)
{
m_VisibleOnSensors = visible;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
MWObject::DoesHaveAvailableTonage(Stuff::Scalar tons)
{
Check_Object(this);
const GameModel *model = GetGameModel();
Check_Object(model);
return (tonage + tons) <= model->maxVehicleTonnage + 0.01f;
}
void MWObject::EngineDead (void)
{
STOP (("Only a drop ship should handle this function"));
}
#ifdef _DEBUG
Adept::Site* MWObject::FindSite(const char *site_name)
{
Check_Object(this);
Check_Pointer(site_name);
Adept::Site* pSite = m_sites.Find(site_name);
if (pSite) {
Check_Object(pSite->GetParent());
}
return pSite;
}
#endif // _DEBUG
void MWObject::SetDmgModifier (int nIdx, int nDmgFactor)
{
// nIdx : 0: default, 1: splash
gosASSERT((0 <= nIdx) && (nIdx < 2));
// nDmgFactor: < 0 - restore
// nDmgFactor: == 0 - store
// nDmgFactor: > 0 - set damage modifier as (nDmgFactor/10000.0)
Check_Pointer(this);
SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);
DamageObject *damage_object;
nIdx *= 2;
if (nDmgFactor < 0) { // restore
while((damage_object = iterator.ReadAndNext()) != NULL)
{
Check_Object(damage_object);
damage_object->SetDamageModifier(nIdx, damage_object->GetDamageModifier(nIdx + 1));
}
} else if (nDmgFactor == 0) {
while((damage_object = iterator.ReadAndNext()) != NULL)
{
Check_Object(damage_object);
damage_object->SetDamageModifier(nIdx + 1, damage_object->GetDamageModifier(nIdx));
}
} else {
Stuff::Scalar f = static_cast<Stuff::Scalar>(nDmgFactor / 10000.0);
while((damage_object = iterator.ReadAndNext()) != NULL)
{
Check_Object(damage_object);
damage_object->SetDamageModifier(nIdx, f);
}
}
}
void MWObject::RepairDamage (Stuff::Scalar fRepair)
{
// jcem
Check_Pointer(this);
if (fRepair <= 0.0f)
return;
if (1.0f < fRepair)
fRepair = 1.0f;
SortedChainIteratorOf<DamageObject *, int> iterator(&damageObjects);
DamageObject *damage_object;
while((damage_object = iterator.ReadAndNext()) != NULL)
{
Check_Object(damage_object);
damage_object->RepairDamage(fRepair);
}
}