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.
1084 lines
28 KiB
C++
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);
|
|
}
|
|
}
|