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

1084 lines
28 KiB
C++

//===========================================================================//
// File: MWMover.cpp
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 09/09/98 JSE Inital base class based off of Shadowrun/Adept
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Fasa Interactive //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include "MW4Headers.hpp"
#include "MWMover.hpp"
#include "MWObject.hpp"
#include "CombatAI.hpp"
#include <Adept\EntityManager.hpp>
#include <Adept\DamageObject.hpp>
#include <Adept\Effect.hpp>
#include <Adept\Map.hpp>
#include <Adept\Site.hpp>
#include <Adept\Mission.hpp>
#include <Adept\Renderer.hpp>
// ngLog addition
#include "MWApplication.hpp"
#include "Mech.hpp"
extern int g_nMR;
//#############################################################################
//################## Mover::ExecutionStateEngine ########################
//#############################################################################
const StateEngine::StateEntry
MWMover::ExecutionStateEngine::StateEntries[]=
{
STATE_ENTRY(MWMover__ExecutionStateEngine, RegularMotion),
STATE_ENTRY(MWMover__ExecutionStateEngine, CameraMotion)
};
MWMover::ExecutionStateEngine::ClassData*
MWMover::ExecutionStateEngine::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::ExecutionStateEngine::InitializeClass()
{
Check_Object(StateEngine::DefaultData);
Verify(!DefaultData);
DefaultData =
new ClassData(
MWMover__ExecutionStateEngineClassID,
"MWMover::ExecutionStateEngine",
BaseClass::DefaultData,
ELEMENTS(StateEntries), StateEntries,
(Entity::ExecutionStateEngine::Factory)Make,
(Entity::ExecutionStateEngine::FactoryRequest::Factory)
&FactoryRequest::ConstructFactoryRequest
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::ExecutionStateEngine::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWMover::ExecutionStateEngine*
MWMover::ExecutionStateEngine::Make(
MWMover *mover,
FactoryRequest *request
)
{
Check_Object(mover);
Check_Object(request);
MWMover::ExecutionStateEngine *engine;
gos_PushCurrentHeap(Heap);
engine = new MWMover::ExecutionStateEngine(DefaultData, mover, request);
gos_PopCurrentHeap();
return engine;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::ExecutionStateEngine::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
//#############################################################################
//############################### MWMover ##############################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWMover::ClassData*
MWMover::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::InitializeClass()
{
Check_Object(ExecutionStateEngine::DefaultData);
Verify(!DefaultData);
DefaultData =
new ClassData(
MWMoverClassID,
"MechWarrior4::MWMover",
BaseClass::DefaultData,
NULL, 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
);
Register_Object(DefaultData);
INDIRECT_STATE_ATTRIBUTE(
MWMover,
ExecutionState,
executionState,
MWMover__ExecutionStateEngine
);
CUSTOM_DIRECT_ATTRIBUTE(
MWMover,
IsDark,
m_isDark,
int,
IntClassID
);
CUSTOM_DIRECT_ATTRIBUTE(
MWMover,
LTread,
LTread,
AffineMatrix4D,
AffineMatrix4DClassID
);
CUSTOM_DIRECT_ATTRIBUTE(
MWMover,
RTread,
RTread,
AffineMatrix4D,
AffineMatrix4DClassID
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWMover*
MWMover::Make(
CreateMessage *message,
ReplicatorID *base_id
)
{
Check_Object(message);
gos_PushCurrentHeap(Heap);
MWMover *new_entity =
new MWMover(DefaultData, message, base_id, NULL);
gos_PopCurrentHeap();
Check_Object(new_entity);
return new_entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Replicator::CreateMessage*
MWMover::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file)
{
Check_Object(this);
Check_Object(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 armature
//------------------------------------------
//
//Assume that we don't have not changed our armature at all
message->armatureStreamResourceID = armatureStreamResourceID;
message->siteStreamResourceID = siteStreamResourceID;
if((myParentVehicle != NULL) && (myParentVehicle->m_hasExecuted))
{
//If we do then save them to a stream and reset the armatureStreamID
if(!childEntityChain.IsEmpty())
{
DynamicMemoryStream armature_stream(sizeof(WORD));
armature_stream << static_cast<WORD>(0);
ReplicatorID span = ReplicatorID::Null;
ChainIteratorOf<Entity *> child_iterator(&childEntityChain);
Entity *entity;
while((entity = child_iterator.ReadAndNext()) != NULL)
{
Check_Object(entity);
if (entity->IsDerivedFrom(MWMover::DefaultData))
{
Replicator::CreateMessage *create_message =
entity->SaveMakeMessage(&armature_stream, res_file);
if (create_message)
{
Check_Object(create_message);
span += create_message->replicatorID;
armature_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
//-------------------------------------------------------------------------
//
if (armature_stream.GetBytesUsed() > sizeof(WORD))
{
armature_stream.Rewind();
Verify(span.localID > 0);
armature_stream << span.localID;
Resource armature_resource(NULL, res_file);
armature_resource.Save(&armature_stream, NULL);
Check_Object(&armature_resource);
message->armatureStreamResourceID = armature_resource.GetResourceID();
message->replicatorID += span;
}
else
{
message->armatureStreamResourceID = ResourceID::Null;
}
}
message->siteStreamResourceID = ResourceID::Null;
if(!m_sites.IsEmpty())
{
SortedChainIteratorOf<Site*, MString> site_iterator(&m_sites);
Site *site;
DynamicMemoryStream site_stream;
while((site = site_iterator.ReadAndNext()) != NULL)
{
Check_Object(site);
site->SaveToStream(&site_stream);
}
if (site_stream.GetBytesUsed() > 0)
{
site_stream.Rewind();
Resource site_resource(NULL, res_file);
site_resource.Save(&site_stream, NULL);
message->siteStreamResourceID = site_resource.GetResourceID();
}
else
{
message->siteStreamResourceID = ResourceID::Null;
}
}
}
Str_Copy(message->jointName, (char*)instanceName, sizeof(message->jointName));
return message;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWMover::MWMover(
ClassData *class_data,
CreateMessage *message,
ReplicatorID *base_id,
ElementRenderer::Element *element
):
BaseClass(class_data, message, base_id, element),
m_sites(NULL, true)
{
Check_Pointer(this);
Check_Object(message);
if (!instanceName)
instanceName = message->jointName;
myParentVehicle = NULL;
lightIntensity = 0.0f;
armatureStreamResourceID = message->armatureStreamResourceID;
siteStreamResourceID = message->siteStreamResourceID;
if(message->armatureStreamResourceID != ResourceID::Null)
{
LoadArmatureFromResource(
message->armatureStreamResourceID,
base_id
);
}
if(message->siteStreamResourceID != ResourceID::Null)
{
LoadSitesFromResource(message->siteStreamResourceID);
}
m_isDark = 1;
LTread = Stuff::AffineMatrix4D::Identity;
RTread = Stuff::AffineMatrix4D::Identity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MWMover::~MWMover()
{
DESTRUCTOR("Mover");
Check_Object(this);
m_sites.DeletePlugs();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::LoadArmatureFromResource(
const ResourceID &armature_stream_id,
ReplicatorID *base_id
)
{
Resource stream(armature_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);
stream.AdvancePointer(message->messageLength);
}
stream.UnloadData();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::LoadSitesFromResource(const ResourceID &site_stream_id)
{
Resource stream(site_stream_id);
Verify(stream.DoesResourceExist());
while (stream.GetBytesRemaining() > 0)
{
MString site_name;
YawPitchRoll rotation;
Point3D translation;
LinearMatrix4D local_to_parent;
stream >> rotation;
stream >> translation;
stream >> site_name;
local_to_parent.BuildRotation(rotation);
local_to_parent.BuildTranslation(translation);
Site *site = new Site(local_to_parent, this, site_name);
m_sites.AddValue(site, site_name);
}
stream.UnloadData();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::ReuseArmature()
{
Check_Pointer(this);
Entity *entity;
MWMover *mover;
ChainIteratorOf<Entity *> child_iterator(GetChildEntityChain());
if(armatureStreamResourceID != ResourceID::Null)
{
Resource child_stream(armatureStreamResourceID);
child_stream.AdvancePointer(sizeof(WORD));
while (((entity = child_iterator.ReadAndNext()) != NULL) &&
(child_stream.GetBytesRemaining() > 0))
{
if(entity->IsDerivedFrom(MWMover::DefaultData))
{
mover = Cast_Object(MWMover *, entity);
Entity::CreateMessage *entity_message =
Cast_Pointer(Entity::CreateMessage*, child_stream.GetPointer());
mover->ReuseArmature();
mover->Respawn(entity_message);
child_stream.AdvancePointer(entity_message->messageLength);
}
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::Respawn(Entity::CreateMessage *message)
{
Check_Object(this);
Check_Object(message);
BaseClass::Respawn(message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::Reuse(
const CreateMessage *message,
ReplicatorID *base_id
)
{
Check_Object(this);
Check_Object(message);
STOP(("Not implemented"));
BaseClass::Reuse(message, base_id);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::BecomeInteresting(bool render_me)
{
Check_Object(this);
LOAD_LOGIC("Become Interesting::MWMover");
//
//------------------
// Validate children
//------------------
//
ChainIteratorOf<Entity*> children(&childEntityChain);
Entity *entity;
while ((entity = children.ReadAndNext()) != NULL)
{
Check_Object(entity);
// Verify(!entity->IsValid());
entity->BecomeInteresting(render_me);
}
Check_Pointer(Mission::GetInstance());
#if 0
const Mission::GameModel *mission_model = Mission::GetInstance()->GetGameModel();
Check_Object(mission_model);
#endif
if(!Mission::GetInstance()->DoesAllowRunningLights())
{
m_isDark = 1;
}
else
{
m_isDark = 0;
}
//
//-----------------------------
// Now make ourself interesting
//-----------------------------
//
extern char g_SkinSet;
g_SkinSet = GetSkinPrefix();
extern int g_PilotDecal;
extern int g_TeamDecal;
g_PilotDecal = GetPilotDecal();
g_TeamDecal = GetTeamDecal();
BaseClass::BecomeInteresting(render_me);
CheckVideoStates(render_me);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::CheckVideoStates(bool render_me)
{
//Ok here we go...if we are destroyed than we must fake out the watchers
if(IsDestroyed())
{
//Change to prestine state
visualRepresentation = PrestineState;
//Execute
ExecuteChildComponentWebs();
//Change back to its destroyed state
visualRepresentation = DestroyedState;
//Execute
ExecuteChildComponentWebs();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
MWMover::FriendlyFire(const TakeDamageMessage *message)
{
if (GetParentVehicle() != 0)
return GetParentVehicle()->FriendlyFire(message);
return Entity::FriendlyFire(message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::ReactToHit(const Entity__TakeDamageMessage *message,Adept::DamageObject *part_hit)
{
Check_Object(this);
Check_Object(message);
if(myParentVehicle)
{
Check_Object(myParentVehicle);
myParentVehicle->ReactToHit(message,part_hit);
myParentVehicle->NotifyWhoHitMe(message->inflictingEntityID, message->weaponID);
}
if (g_nMR == 2)
return;
// TODO: move this elsewhere; this should be more general and should take near
// misses into account as well as direct hits -- PAULT
if ((GetParentVehicle() != 0) &&
(GetParentVehicle()->GetAI() != 0))
{
switch (message->typeOfDamage)
{
case BeamDamageType:
case MissileDamageType:
case ProjectileDamageType:
{
NotifyAIShot(*(GetParentVehicle()->GetAI()),message->inflictingEntityID);
break;
}
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::ReactToDestruction(int damage_mode, int damage_type)
{
Check_Object(this);
bool kill_self = true;
if(IsDestroyed())
return;
if ((GetParentVehicle() != 0) &&
(GetParentVehicle()->GetAI() != 0) &&
(damageObject != 0) &&
(damageObject->internalDamageObject != 0))
{
GetParentVehicle()->GetAI()->NotifyComponentDestroyed(damageObject->internalDamageObject->damageZone);
}
// MSL 5.07 Advance Mode
MWApplication *m_App;
m_App = MWApplication::GetInstance ();
int m_AdvanceMode = m_App->GetLocalNetParams()->m_advancemodeOn;
// MSL 5.07 Advance Mode
if (!m_AdvanceMode)
{
if ((damage_mode == InternalDamageObject::TorsoLeftDamageMode) ||
(damage_mode == InternalDamageObject::TorsoRightDamageMode))
{
damage_mode = InternalDamageObject::DestructionDamageMode;
}
// if ((damage_mode == InternalDamageObject::ArmLeftDamageMode) ||
// (damage_mode == InternalDamageObject::ArmRightDamageMode))
// {
// damage_mode = InternalDamageObject::DetachableDamageMode;
// }
}
switch(damage_mode)
{
case InternalDamageObject::EngineDamageMode:
{
ResourceID resource_id = ResourceID::Null;
if(myParentVehicle)
{
Check_Object(myParentVehicle);
myParentVehicle->EngineDead ();
const MWObject__GameModel *model = myParentVehicle->GetGameModel();
resource_id = model->partDestructionEffectResource;
}
// MERC Code FIX
// CreatePartDestructionEffect(resource_id);
// DestroyChildren(damage_mode);
break;
}
case InternalDamageObject::GimpLeftDamageMode:
{
ResourceID resource_id = ResourceID::Null;
if(myParentVehicle)
{
Check_Object(myParentVehicle);
myParentVehicle->SetLeftGimp();
myParentVehicle->DestroyLeftLegSpecialZones();
const MWObject__GameModel *model = myParentVehicle->GetGameModel();
resource_id = model->partDestructionEffectResource;
}
CreatePartDestructionEffect(resource_id);
DestroyChildren(damage_mode);
break;
}
case InternalDamageObject::GimpRightDamageMode:
{
ResourceID resource_id = ResourceID::Null;
if(myParentVehicle)
{
Check_Object(myParentVehicle);
myParentVehicle->SetRightGimp();
myParentVehicle->DestroyRightLegSpecialZones();
const MWObject__GameModel *model = myParentVehicle->GetGameModel();
resource_id = model->partDestructionEffectResource;
}
CreatePartDestructionEffect(resource_id);
DestroyChildren(damage_mode);
break;
}
// MSL 5.05 Torso
case InternalDamageObject::ArmLeftDamageMode:
{
ResourceID resource_id = ResourceID::Null;
if(myParentVehicle)
{
Check_Object(myParentVehicle);
myParentVehicle->DestroyLeftArmSpecialZones();
const MWObject__GameModel *model = myParentVehicle->GetGameModel();
resource_id = model->partDestructionEffectResource;
}
CreatePartDestructionEffect(resource_id);
DestroyChildren(damage_mode);
break;
}
// MSL 5.05 Torso
case InternalDamageObject::ArmRightDamageMode:
{
ResourceID resource_id = ResourceID::Null;
if(myParentVehicle)
{
Check_Object(myParentVehicle);
myParentVehicle->DestroyRightArmSpecialZones();
const MWObject__GameModel *model = myParentVehicle->GetGameModel();
resource_id = model->partDestructionEffectResource;
}
CreatePartDestructionEffect(resource_id);
DestroyChildren(damage_mode);
break;
}
case InternalDamageObject::DetachableDamageMode:
{
ResourceID resource_id = ResourceID::Null;
if(myParentVehicle)
{
Check_Object(myParentVehicle);
const MWObject__GameModel *model = myParentVehicle->GetGameModel();
resource_id = model->partDestructionEffectResource;
}
CreatePartDestructionEffect(resource_id);
DestroyChildren(damage_mode);
break;
}
// MSL 5.05 Torso
case InternalDamageObject::TorsoLeftDamageMode:
{
ResourceID resource_id = ResourceID::Null;
if(myParentVehicle)
{
Check_Object(myParentVehicle);
myParentVehicle->DestroyLeftArm();
myParentVehicle->DestroyLeftArmSpecialZones();
myParentVehicle->DestroyLeftTorsoSpecialZones();
const MWObject__GameModel *model = myParentVehicle->GetGameModel();
resource_id = model->partDestructionEffectResource;
}
CreatePartDestructionEffect(resource_id);
DestroyChildren(damage_mode);
break;
}
// MSL 5.05 Torso
case InternalDamageObject::TorsoRightDamageMode:
{
ResourceID resource_id = ResourceID::Null;
if(myParentVehicle)
{
Check_Object(myParentVehicle);
myParentVehicle->DestroyRightArm();
myParentVehicle->DestroyRightArmSpecialZones();
myParentVehicle->DestroyRightTorsoSpecialZones();
const MWObject__GameModel *model = myParentVehicle->GetGameModel();
resource_id = model->partDestructionEffectResource;
}
CreatePartDestructionEffect(resource_id);
DestroyChildren(damage_mode);
break;
}
// MSL 5.03 Gyro Hit
case InternalDamageObject::GyroHitDamageMode:
{
if(myParentVehicle)
{
Check_Object(myParentVehicle);
myParentVehicle->ReactToDestruction(damage_mode, damage_type);
kill_self = false;
}
else
{
DestroyChildren(damage_mode);
}
break;
}
case InternalDamageObject::HeadShotDamageMode:
{
if(myParentVehicle)
{
Check_Object(myParentVehicle);
myParentVehicle->ReactToDestruction(damage_mode, damage_type);
kill_self = false;
}
else
{
DestroyChildren(damage_mode);
}
break;
}
case InternalDamageObject::DestructionDamageMode:
{
if(myParentVehicle)
{
Check_Object(myParentVehicle);
myParentVehicle->ReactToDestruction(damage_mode, damage_type);
kill_self = false;
}
else
{
DestroyChildren(damage_mode);
}
break;
}
}
Check_Object(Mission::GetInstance());
ExecuteChildComponentWebs();
if(kill_self)
Entity::ReactToDestruction(damage_mode, damage_type);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::CreatePartDestructionEffect(const ResourceID& resource_id)
{
Check_Object(this);
if(resource_id != ResourceID::Null)
{
ClassID class_ID;
class_ID = Entity::GetClassIDFromDataListID(resource_id);
Verify(class_ID != NullClassID);
Effect::CreateMessage effect_create_message(
sizeof(Effect::CreateMessage),
DefaultEventPriority,
Entity::CreateMessage::DefaultFlags,
class_ID,
Effect::DefaultFlags,
resource_id,
GetLocalToWorld(),
0.0f,
Entity::ExecutionStateEngine::AlwaysExecuteState,
NameTable::NullObjectID,
Entity::DefaultAlignment
);
MemoryStream stream(&effect_create_message, effect_create_message.messageLength);
Entity *entity;
ReplicatorID effect_id = Connection::Hermit->GetNextReplicatorID();
entity = Entity::CreateEntity(&stream, &effect_id, false);
Check_Object(entity);
// Effect *effect = Cast_Object(Effect *, entity);
Check_Object(Map::GetInstance());
Map::GetInstance()->AddChild(entity);
// effect->SetFollowEntity(this);
// effect->effectOffset = LinearMatrix4D::Identity;
entity->SyncMatrices(true);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::ReactToInternalDamage(int damage_mode)
{
Check_Object(this);
if ((GetParentVehicle() != 0) &&
(GetParentVehicle()->GetAI() != 0))
{
GetParentVehicle()->GetAI()->NotifyInternalHit();
}
switch(damage_mode)
{
case InternalDamageObject::GimpLeftDamageMode:
{
if(myParentVehicle)
{
Check_Object(myParentVehicle);
myParentVehicle->ReactToInternalDamage(damage_mode);
}
break;
}
case InternalDamageObject::GimpRightDamageMode:
{
if(myParentVehicle)
{
Check_Object(myParentVehicle);
myParentVehicle->ReactToInternalDamage(damage_mode);
}
break;
}
case InternalDamageObject::HeadShotDamageMode:
{
if(myParentVehicle)
{
Check_Object(myParentVehicle);
myParentVehicle->HeadShotInternal();
}
break;
}
case InternalDamageObject::GyroHitDamageMode:
{
if(myParentVehicle)
{
Check_Object(myParentVehicle);
myParentVehicle->GyroHitInternal();
}
break;
}
}
// Fix Bug #3100
// Damage Object are now refreshed when a mech sustains internal damage
if ((GetParentVehicle() != 0) &&
(GetParentVehicle()->IsDerivedFrom(Mech::DefaultData)))
{
GetParentVehicle()->ReactToInternalDamage(damage_mode);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::NotifyProjectileApproaching(const Stuff::Point3D& origin)
{
if ((GetParentVehicle() != 0) &&
(GetParentVehicle()->GetAI() != 0))
{
GetParentVehicle()->GetAI()->NotifyProjectileApproaching(origin);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::NotifyAIShot(AI& ai, Adept::ReplicatorID inflicting_entity_id)
{
Connection *connection = Network::GetInstance()->GetConnection(inflicting_entity_id.connectionID);
if (connection == NULL)
return;
Replicator* r = connection->FindReplicator(inflicting_entity_id);
if (r == 0)
{
return;
}
Verify(r->IsDerivedFrom(Entity::DefaultData));
Entity* e = Cast_Object(Entity*,r);
ai.NotifyShot(e->objectID);
if ((GetParentVehicle() != 0) &&
(GetParentVehicle()->GetAlignment() == e->GetAlignment()) &&
(e->IsDerivedFrom(MWObject::DefaultData) == true))
{
MWObject* mwobject = Cast_Object(MWObject*,e);
if (mwobject->GetAI() != 0)
{
mwobject->GetAI()->NotifyLastShotWasFriendlyFire(*GetParentVehicle());
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::ToggleLightsOff(bool toggle) //True if going off
{
Check_Object(this);
ChainIteratorOf<Entity*> children(&childEntityChain);
Entity *entity;
Check_Pointer(Mission::GetInstance());
//
// If running lights aren't allowed, don't allow turning them on
//
if(!Mission::GetInstance()->DoesAllowRunningLights())
{
return;
}
while ((entity = children.ReadAndNext()) != NULL)
{
Check_Object(entity);
if(entity->IsDerivedFrom(MWMover::DefaultData))
{
MWMover *mover = Cast_Object(MWMover *, entity);
mover->ToggleLightsOff(toggle);
}
}
m_isDark = toggle;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::SetDamageObject(DamageObject *damage_object)
{
Check_Object(this);
Check_Object(damage_object);
Entity::SetDamageObject(damage_object);
ConnectSitesToZone(damage_object->internalDamageObject);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::ConnectSitesToZone(InternalDamageObject *zone)
{
Check_Object(this);
Check_Object(zone);
SortedChainIteratorOf<Site *, MString> iterator(&m_sites);
Site *site;
while((site = iterator.ReadAndNext()) != NULL)
{
Check_Object(site);
if(!zone->m_sites.Find(site->GetName()))
zone->m_sites.AddValue(site, site->GetName());
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWMover::PreCollisionExecute(Stuff::Time till)
{
Check_Object(this);
PRECOLLISION_LOGIC("MWMover");
Verify(executionState->GetState() != ExecutionStateEngine::NeverExecuteState);
DetermineUV (GetTimeSlice (till));
BaseClass::PreCollisionExecute(till);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void MWMover::DetermineUV (Stuff::Time slice)
{
Check_Object (this);
Vehicle *vehicle = NULL;
if (IsDerivedFrom(Vehicle::DefaultData))
vehicle = Cast_Object(Vehicle *, this);
else if (myParentVehicle && myParentVehicle->IsDerivedFrom(Vehicle::DefaultData))
vehicle = Cast_Object(Vehicle *, myParentVehicle);
if (!vehicle)
return;
Check_Object(vehicle);
Stuff::Vector3D linearVelocity = vehicle->localSpaceVelocity.linearMotion;
Stuff::Scalar forward = linearVelocity.GetForwardComponent();
if (Stuff::Small_Enough(forward))
return;
const Vehicle__GameModel *model = vehicle->GetGameModel();
Check_Object(model);
Stuff::Scalar treadLength = model->m_treadLength;
if (treadLength<=0)
return;
Verify(treadLength);
forward = forward*(Stuff::Scalar)(slice)/treadLength;
// Treads move in the "backward" direction
// as the vehicles move in the "forward" direction
LTread(3,0) -= forward;
RTread(3,0) -= forward;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
MWMover::ReactToDamageTaken(Stuff::Scalar damage_taken, const Adept::ReplicatorID& inflicting_entity, int weaponID, int damageType)
{
if (myParentVehicle != 0)
{
myParentVehicle->ReactToDamageTaken(damage_taken,inflicting_entity, weaponID, damageType);
}
}