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.
438 lines
12 KiB
C++
438 lines
12 KiB
C++
#include "MW4Headers.hpp"
|
|
|
|
#include "Field_Base.hpp"
|
|
#include "moverai.hpp"
|
|
#include "mech.hpp"
|
|
#include <Adept\EntityManager.hpp>
|
|
|
|
const Scalar DOOR_MOVE_AMOUNT = 6.5f; //m
|
|
const Scalar LIFT_MOVE_AMOUNT = 10.0f; //m
|
|
const Scalar LIFT_OPEN_SPEED = 1.0f; // mps
|
|
const Scalar DOOR_OPEN_SPEED = (DOOR_MOVE_AMOUNT/(LIFT_MOVE_AMOUNT/LIFT_OPEN_SPEED)); // mps
|
|
|
|
//#############################################################################
|
|
//############################# FieldBase ################################
|
|
//#############################################################################
|
|
|
|
const StateEngine::StateEntry
|
|
FieldBase::ExecutionStateEngine::StateEntries[]=
|
|
{
|
|
STATE_ENTRY(FieldBase__ExecutionStateEngine, OpenDoor),
|
|
STATE_ENTRY(FieldBase__ExecutionStateEngine, CloseDoor)
|
|
};
|
|
|
|
|
|
FieldBase::ExecutionStateEngine::ClassData* FieldBase::ExecutionStateEngine::DefaultData = NULL;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FieldBase::ExecutionStateEngine::InitializeClass()
|
|
{
|
|
Check_Object(BaseClass::DefaultData);
|
|
Verify(!DefaultData);
|
|
|
|
DefaultData =
|
|
new ClassData(
|
|
FieldBase__ExecutionStateEngineClassID,
|
|
"FieldBase::ExecutionStateEngine",
|
|
BaseClass::DefaultData,
|
|
ELEMENTS(StateEntries), StateEntries,
|
|
(Entity::ExecutionStateEngine::Factory)Make,
|
|
(Entity::ExecutionStateEngine::FactoryRequest::Factory)
|
|
&FactoryRequest::ConstructFactoryRequest
|
|
);
|
|
Register_Object(DefaultData);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FieldBase::ExecutionStateEngine::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
FieldBase::ExecutionStateEngine* FieldBase::ExecutionStateEngine::Make(FieldBase *vehicle,FactoryRequest *request)
|
|
{
|
|
Check_Object(vehicle);
|
|
Check_Object(request);
|
|
gos_PushCurrentHeap(Heap);
|
|
FieldBase::ExecutionStateEngine *engine = new FieldBase::ExecutionStateEngine(DefaultData, vehicle, request);
|
|
gos_PopCurrentHeap();
|
|
return engine;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int FieldBase::ExecutionStateEngine::RequestState(int new_state,void* data)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(owningEntity);
|
|
|
|
//
|
|
//-------------------------------------------
|
|
// If there is no change of state just return
|
|
//-------------------------------------------
|
|
//
|
|
|
|
// FieldBase *base = Cast_Object (FieldBase *,owningEntity);
|
|
if (new_state == currentState)
|
|
return currentState;
|
|
|
|
switch (new_state)
|
|
{
|
|
case RepairState:
|
|
if (currentState != CloseDoorState)
|
|
{
|
|
new_state = CloseDoorState;
|
|
}
|
|
break;
|
|
case NeverExecuteState:
|
|
if ((currentState == RepairState) || (currentState == CloseDoorState))
|
|
{
|
|
new_state = OpenDoorState;
|
|
}
|
|
break;
|
|
break;
|
|
}
|
|
|
|
BaseClass::RequestState(new_state, data);
|
|
|
|
return currentState;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FieldBase::ExecutionStateEngine::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
FieldBase::ClassData* FieldBase::DefaultData = NULL;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FieldBase::InitializeClass()
|
|
{
|
|
Check_Object(MWMover::ExecutionStateEngine::DefaultData);
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
FieldBaseClassID,
|
|
"MechWarrior4::FieldBase",
|
|
BaseClass::DefaultData,
|
|
0, NULL,
|
|
(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);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FieldBase::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
FieldBase* FieldBase::Make(
|
|
CreateMessage *message,
|
|
ReplicatorID *base_id
|
|
)
|
|
{
|
|
Check_Object(message);
|
|
gos_PushCurrentHeap(Heap);
|
|
FieldBase *new_entity = new FieldBase(DefaultData, message, base_id, NULL);
|
|
gos_PopCurrentHeap();
|
|
Check_Object(new_entity);
|
|
|
|
|
|
Check_Object(EntityManager::GetInstance());
|
|
EntityManager::GetInstance()->AddMover(new_entity);
|
|
return new_entity;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
FieldBase::FieldBase(
|
|
ClassData *class_data,
|
|
CreateMessage *message,
|
|
ReplicatorID *base_id,
|
|
ElementRenderer::Element *element
|
|
):
|
|
MFB(class_data, message, base_id, element)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(message);
|
|
|
|
|
|
CommonCreation(message);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
FieldBase::~FieldBase()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FieldBase::Reuse(const CreateMessage *message,ReplicatorID *base_id)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
STOP(("Not implemented"));
|
|
BaseClass::Reuse(message, base_id);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FieldBase::CommonCreation(CreateMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
m_FirstFrame = true;
|
|
//m_RepairDistance = 9.0f;
|
|
|
|
m_DoorAR = FindChildMover ("joint_DoorAR");
|
|
m_DoorFR = FindChildMover ("joint_DoorAL");
|
|
m_DoorAL = FindChildMover ("joint_DoorFR");
|
|
m_DoorFL = FindChildMover ("joint_DoorFL");
|
|
m_Lift = FindChildMover ("joint_Lift");
|
|
m_HasDoors = false;
|
|
if ((m_DoorAR) && (m_DoorFR) && (m_DoorAL) && (m_DoorFL) && (m_Lift))
|
|
m_HasDoors = true;
|
|
m_BaseYDoorAR = 0;
|
|
m_BaseYDoorFR = 0;
|
|
m_BaseYDoorAL = 0;
|
|
m_BaseYDoorFL = 0;
|
|
m_BaseYLift = 0;
|
|
|
|
m_LiftAmount =0;
|
|
m_DoorAmount =0;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FieldBase::Respawn(Entity::CreateMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
BaseClass::Respawn(message);
|
|
CreateMessage *vehicle_message = Cast_Pointer(CreateMessage *, message);
|
|
CommonCreation(vehicle_message);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FieldBase::TurnOn (void)
|
|
{
|
|
lastParameterization = gos_GetElapsedTime ();
|
|
executionState->RequestState(ExecutionStateEngine::DrivingMotionState);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FieldBase::PreCollisionExecute(Time till)
|
|
{
|
|
Check_Object(this);
|
|
|
|
PRECOLLISION_LOGIC("MFB");
|
|
|
|
//
|
|
//-------------------------------------------------------------
|
|
// Let the base class deal with setting up the motion variables
|
|
//-------------------------------------------------------------
|
|
//
|
|
if ((m_FirstFrame) && (m_HasDoors))
|
|
{
|
|
Point3D loc;
|
|
loc = (Point3D) m_DoorAR->GetLocalToParent ();
|
|
m_BaseYDoorAR = loc.x;
|
|
loc = (Point3D) m_DoorFR->GetLocalToParent ();
|
|
m_BaseYDoorFR = loc.x;
|
|
loc = (Point3D) m_DoorAL->GetLocalToParent ();
|
|
m_BaseYDoorAL = loc.x;
|
|
loc = (Point3D) m_DoorFL->GetLocalToParent ();
|
|
m_BaseYDoorFL = loc.x;
|
|
loc = (Point3D) m_Lift->GetLocalToParent ();
|
|
m_BaseYLift = loc.y;
|
|
}
|
|
m_FirstFrame = false;
|
|
|
|
BaseClass::PreCollisionExecute(till);
|
|
|
|
|
|
Check_Object(executionState);
|
|
int pre_state = executionState->GetState();
|
|
Verify(pre_state != ExecutionStateEngine::NeverExecuteState);
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// Do the appropriate type of simulation. Animated motion state is for BRB
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
Scalar time_slice = GetTimeSlice(till);
|
|
switch (pre_state)
|
|
{
|
|
//
|
|
//----------------------------------------------------
|
|
// Always execute state is for the normal driving code
|
|
//----------------------------------------------------
|
|
//
|
|
case ExecutionStateEngine::OpenDoorState:
|
|
DoorOpenAnim (time_slice);
|
|
if ((m_DoorAmount == 0) || (!m_HasDoors))
|
|
{
|
|
executionState->RequestState (ExecutionStateEngine::NeverExecuteState);
|
|
if (m_repairingMech.GetCurrent ())
|
|
{
|
|
AI *ai;
|
|
ai = m_repairingMech.GetCurrent ()->GetAI ();
|
|
if (ai && ai->IsDerivedFrom (MoverAI::DefaultData))
|
|
{
|
|
MoverAI *move;
|
|
move = Cast_Object (MoverAI *,ai);
|
|
move->NextFieldBase ();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
//
|
|
//-----------------------------------------------------------
|
|
//We need to repair now...some mech powered down inside of us
|
|
//-----------------------------------------------------------
|
|
//
|
|
case ExecutionStateEngine::CloseDoorState:
|
|
DoorCloseAnim (time_slice);
|
|
if ((m_DoorAmount == DOOR_MOVE_AMOUNT) || (!m_HasDoors))
|
|
executionState->RequestState (ExecutionStateEngine::RepairState);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FieldBase::DoorOpenAnim (Stuff::Time slice)
|
|
{
|
|
if (!m_HasDoors)
|
|
return;
|
|
m_DoorAmount -= (Scalar) (slice / DOOR_OPEN_SPEED);
|
|
Clamp (m_DoorAmount,0,DOOR_MOVE_AMOUNT);
|
|
m_LiftAmount -= (Scalar) (slice / LIFT_OPEN_SPEED);
|
|
Clamp (m_LiftAmount,0,LIFT_MOVE_AMOUNT);
|
|
|
|
LinearMatrix4D mat = m_DoorAR->GetLocalToParent ();
|
|
mat(W_Axis, X_Axis) = m_BaseYDoorAR + m_DoorAmount;
|
|
m_DoorAR->SetNewLocalToParent (mat);
|
|
|
|
mat = m_DoorFR->GetLocalToParent ();
|
|
mat(W_Axis, X_Axis) = m_BaseYDoorFR - m_DoorAmount;
|
|
m_DoorFR->SetNewLocalToParent (mat);
|
|
|
|
mat = m_DoorAL->GetLocalToParent ();
|
|
mat(W_Axis, X_Axis) = m_BaseYDoorAL + m_DoorAmount;
|
|
m_DoorAL->SetNewLocalToParent (mat);
|
|
|
|
mat = m_DoorFL->GetLocalToParent ();
|
|
mat(W_Axis, X_Axis) = m_BaseYDoorFL - m_DoorAmount;
|
|
m_DoorFL->SetNewLocalToParent (mat);
|
|
|
|
mat = m_Lift->GetLocalToParent ();
|
|
mat(W_Axis, Y_Axis) = m_BaseYLift - m_LiftAmount;
|
|
m_Lift->SetNewLocalToParent (mat);
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FieldBase::DoorCloseAnim (Stuff::Time slice)
|
|
{
|
|
if (!m_HasDoors)
|
|
return;
|
|
m_DoorAmount += (Scalar) (slice / DOOR_OPEN_SPEED);
|
|
Clamp (m_DoorAmount,0,DOOR_MOVE_AMOUNT);
|
|
m_LiftAmount += (Scalar) (slice / LIFT_OPEN_SPEED);
|
|
Clamp (m_LiftAmount,0,LIFT_MOVE_AMOUNT);
|
|
|
|
LinearMatrix4D mat = m_DoorAR->GetLocalToParent ();
|
|
mat(W_Axis, X_Axis) = m_BaseYDoorAR + m_DoorAmount;
|
|
m_DoorAR->SetNewLocalToParent (mat);
|
|
|
|
mat = m_DoorFR->GetLocalToParent ();
|
|
mat(W_Axis, X_Axis) = m_BaseYDoorFR - m_DoorAmount;
|
|
m_DoorFR->SetNewLocalToParent (mat);
|
|
|
|
mat = m_DoorAL->GetLocalToParent ();
|
|
mat(W_Axis, X_Axis) = m_BaseYDoorAL + m_DoorAmount;
|
|
m_DoorAL->SetNewLocalToParent (mat);
|
|
|
|
mat = m_DoorFL->GetLocalToParent ();
|
|
mat(W_Axis, X_Axis) = m_BaseYDoorFL - m_DoorAmount;
|
|
m_DoorFL->SetNewLocalToParent (mat);
|
|
|
|
mat = m_Lift->GetLocalToParent ();
|
|
mat(W_Axis, Y_Axis) = m_BaseYLift - m_LiftAmount;
|
|
m_Lift->SetNewLocalToParent (mat);
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
bool FieldBase::CollisionHandler(Stuff::LinearMatrix4D *new_position,Stuff::DynamicArrayOf<CollisionData> *collisions)
|
|
{
|
|
Check_Object(this);
|
|
Verify(GetInterestLevel() != DormantInterestLevel);
|
|
|
|
Verify(!newCollisions);
|
|
delete collisions;
|
|
return false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FieldBase::ReactToDestruction(int damage_mode, int damage_type)
|
|
{
|
|
if (m_repairingMech.GetCurrent ())
|
|
{
|
|
AI *ai;
|
|
m_repairingMech.GetCurrent ()->ShutDownRequest(false);
|
|
ai = m_repairingMech.GetCurrent ()->GetAI ();
|
|
if (ai && ai->IsDerivedFrom (MoverAI::DefaultData))
|
|
{
|
|
MoverAI *move;
|
|
move = Cast_Object (MoverAI *,ai);
|
|
move->FieldBaseDead ();
|
|
}
|
|
}
|
|
MFB::ReactToDestruction (damage_mode,damage_type);
|
|
}
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void FieldBase::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|