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.
840 lines
23 KiB
C++
840 lines
23 KiB
C++
#include "MW4Headers.hpp"
|
|
|
|
#include "Dropship.hpp"
|
|
|
|
#include <Adept\Effect.hpp>
|
|
#include <Adept\CollisionGrid.hpp>
|
|
#include <Adept\EntityManager.hpp>
|
|
#include <Adept\DamageObject.hpp>
|
|
#include "ai.hpp"
|
|
// MSL 5.04 Dropship
|
|
#include "MWMission.hpp"
|
|
|
|
Scalar FindTerrainHeightFromPoint(const Point3D& point, Adept::Entity* ignore);
|
|
|
|
const Stuff::Time DROPSHIP_TAKEOFF_DELAY = 3.0f;
|
|
|
|
//#############################################################################
|
|
//################## Airplane::ExecutionStateEngine #####################
|
|
//#############################################################################
|
|
|
|
const StateEngine::StateEntry Dropship::ExecutionStateEngine::StateEntries[]=
|
|
{
|
|
STATE_ENTRY(Dropship__ExecutionStateEngine, DoorOpenMotion),
|
|
STATE_ENTRY(Dropship__ExecutionStateEngine, DoorCloseMotion)
|
|
};
|
|
|
|
const Scalar DOOR_MOVE_AMOUNT = 10.0f;
|
|
const Scalar DOOR_OPEN_SPEED = 1.0f; // mps
|
|
|
|
Dropship::ExecutionStateEngine::ClassData* Dropship::ExecutionStateEngine::DefaultData = NULL;
|
|
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Dropship::ExecutionStateEngine::InitializeClass()
|
|
{
|
|
Check_Object(StateEngine::DefaultData);
|
|
Verify(!DefaultData);
|
|
|
|
DefaultData =
|
|
new ClassData(
|
|
Dropship__ExecutionStateEngineClassID,
|
|
"Dropship::ExecutionStateEngine",
|
|
BaseClass::DefaultData,
|
|
ELEMENTS(StateEntries), StateEntries,
|
|
(Entity::ExecutionStateEngine::Factory)Make,
|
|
(Entity::ExecutionStateEngine::FactoryRequest::Factory)
|
|
&FactoryRequest::ConstructFactoryRequest
|
|
);
|
|
Register_Object(DefaultData);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Dropship::ExecutionStateEngine::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Dropship::ExecutionStateEngine* Dropship::ExecutionStateEngine::Make(Dropship *mover,FactoryRequest *request)
|
|
{
|
|
Check_Object(mover);
|
|
Check_Object(request);
|
|
gos_PushCurrentHeap(Heap);
|
|
Dropship::ExecutionStateEngine *engine = new Dropship::ExecutionStateEngine(DefaultData, mover, request);
|
|
gos_PopCurrentHeap();
|
|
return engine;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
int Dropship::ExecutionStateEngine::RequestState(int new_state,void* data)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(owningEntity);
|
|
|
|
//
|
|
//----------------------------------------------
|
|
// Now, switch the state and tickle the watchers
|
|
//----------------------------------------------
|
|
//
|
|
|
|
Dropship *drop;
|
|
drop = Cast_Object(Dropship *, owningEntity);
|
|
if((new_state == DoorOpenMotionState) && (currentState == FlyingMotionState))
|
|
return currentState;
|
|
if((new_state == DoorCloseMotionState) && (currentState != TaxiState))
|
|
return currentState;
|
|
if((new_state == CrashingDeathState) && (currentState == AlwaysExecuteState))
|
|
{
|
|
// airplane->shouldDie = true;
|
|
drop->shouldLeaveReckage = true;
|
|
drop->SetDying();
|
|
return currentState;
|
|
}
|
|
|
|
BaseClass::RequestState(new_state, data);
|
|
|
|
return currentState;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Dropship::ExecutionStateEngine::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
//#############################################################################
|
|
//############################### Helicopter ############################
|
|
//#############################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Dropship::ClassData* Dropship::DefaultData = NULL;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Dropship::InitializeClass()
|
|
{
|
|
Check_Object(ExecutionStateEngine::DefaultData);
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
DropshipClassID,
|
|
"MechWarrior4::Dropship",
|
|
BaseClass::DefaultData,
|
|
NULL, 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 Dropship::TerminateClass()
|
|
{
|
|
Unregister_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Dropship* Dropship::Make(CreateMessage *message,ReplicatorID *base_id)
|
|
{
|
|
Check_Object(message);
|
|
gos_PushCurrentHeap(Heap);
|
|
Dropship *new_entity = new Dropship(DefaultData, message, base_id, NULL);
|
|
gos_PopCurrentHeap();
|
|
Check_Object(new_entity);
|
|
|
|
Check_Object(EntityManager::GetInstance());
|
|
EntityManager::GetInstance()->AddMover(new_entity);
|
|
|
|
return new_entity;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Dropship::Dropship(ClassData *class_data,CreateMessage *message,ReplicatorID *base_id,ElementRenderer::Element *element):
|
|
Helicopter(class_data, message, base_id, element)
|
|
{
|
|
Check_Pointer(this);
|
|
Check_Object(message);
|
|
m_CanDie = false;
|
|
m_NumEngines = 4;
|
|
m_DoorAmount =0;
|
|
m_FirstFrame = true;
|
|
m_DeathStart = 0;
|
|
|
|
m_DoorAR = FindChildMover ("joint_DoorAR");
|
|
m_DoorFR = FindChildMover ("joint_DoorAL");
|
|
m_DoorAL = FindChildMover ("joint_DoorFR");
|
|
m_DoorFL = FindChildMover ("joint_DoorFL");
|
|
m_HasDoors = false;
|
|
if ((m_DoorAR) && (m_DoorFR) && (m_DoorAL) && (m_DoorFL))
|
|
m_HasDoors = true;
|
|
|
|
m_BaseYDoorAR = 0;
|
|
m_BaseYDoorFR = 0;
|
|
m_BaseYDoorAL = 0;
|
|
m_BaseYDoorFL = 0;
|
|
|
|
// MSL 5.04 Dropship
|
|
//should this dropship be scored?
|
|
m_scoreThisDropship = false;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
Dropship::~Dropship()
|
|
{
|
|
Check_Pointer(this);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Dropship::InitializeArmorArray()
|
|
{
|
|
Check_Object(this);
|
|
|
|
for(int i=0; i<12; i++)
|
|
{
|
|
armorArray[i] = -1.0f;
|
|
DamageObject *damage_object = damageObjects.Find(0);
|
|
if(damage_object)
|
|
{
|
|
armorArray[i] = damage_object->armorLevel;
|
|
damage_object->SetArmorArrayEntry(&armorArray[i]);
|
|
}
|
|
else
|
|
{
|
|
armorArray[i] = -1;
|
|
}
|
|
}
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Dropship::Reuse(const CreateMessage *message,ReplicatorID *base_id)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
|
|
STOP(("Not implemented"));
|
|
BaseClass::Reuse(message, base_id);
|
|
}
|
|
|
|
void Dropship::Respawn(Adept::Entity::CreateMessage *message)
|
|
{
|
|
m_NumEngines = 4;
|
|
m_DoorAmount =0;
|
|
m_FirstFrame = true;
|
|
// MSL 5.04 Dropship
|
|
// without these, it keeps dying every 2 seconds
|
|
// m_CanDie = false;
|
|
// m_DeathStart = 0;
|
|
BaseClass::Respawn (message);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Dropship::PreCollisionExecute(Time till)
|
|
{
|
|
Check_Object(this);
|
|
PRECOLLISION_LOGIC("DropShip");
|
|
|
|
BaseClass::PreCollisionExecute(till);
|
|
|
|
//
|
|
//---------------------------------
|
|
// If we aren't executing, stop now
|
|
//---------------------------------
|
|
//
|
|
if ((m_FirstFrame) && (m_HasDoors))
|
|
{
|
|
Point3D loc;
|
|
loc = (Point3D) m_DoorAR->GetLocalToParent ();
|
|
m_BaseYDoorAR = loc.z;
|
|
loc = (Point3D) m_DoorFR->GetLocalToParent ();
|
|
m_BaseYDoorFR = loc.z;
|
|
loc = (Point3D) m_DoorAL->GetLocalToParent ();
|
|
m_BaseYDoorAL = loc.z;
|
|
loc = (Point3D) m_DoorFL->GetLocalToParent ();
|
|
m_BaseYDoorFL = loc.z;
|
|
}
|
|
m_FirstFrame = false;
|
|
Check_Object(executionState);
|
|
int pre_state = executionState->GetState();
|
|
Verify(pre_state != ExecutionStateEngine::NeverExecuteState);
|
|
|
|
if (((!m_crashingEffect.GetCurrent ()) || ((m_DeathStart+2.0) < till)) && m_CanDie)
|
|
{
|
|
Check_Object(executionState);
|
|
|
|
if (m_OnGround)
|
|
shouldLeaveReckage = true;
|
|
else
|
|
shouldLeaveReckage = false;
|
|
shouldDie = true;
|
|
}
|
|
|
|
Scalar time_slice = GetTimeSlice(till);
|
|
Verify(time_slice > 0.0f);
|
|
|
|
switch (pre_state)
|
|
{
|
|
case ExecutionStateEngine::DoorOpenMotionState:
|
|
DoorOpenAnim(time_slice);
|
|
break;
|
|
|
|
case ExecutionStateEngine::DoorCloseMotionState:
|
|
DoorCloseAnim(time_slice);
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool Dropship::orderDoorOpen (void)
|
|
{
|
|
if (executionState->GetState () != ExecutionStateEngine::DoorOpenMotionState)
|
|
{
|
|
executionState->RequestState (ExecutionStateEngine::DoorOpenMotionState);
|
|
return false;
|
|
}
|
|
if ((m_DoorAmount == DOOR_MOVE_AMOUNT) || (!m_HasDoors))
|
|
{
|
|
executionState->RequestState (ExecutionStateEngine::TaxiState);
|
|
m_OnGround = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Dropship::orderDoorClose (void)
|
|
{
|
|
if (executionState->GetState () != ExecutionStateEngine::DoorCloseMotionState)
|
|
{
|
|
executionState->RequestState (ExecutionStateEngine::DoorCloseMotionState);
|
|
return false;
|
|
}
|
|
if ((m_DoorAmount == 0) || (!m_HasDoors))
|
|
{
|
|
executionState->RequestState (ExecutionStateEngine::TaxiState);
|
|
m_OnGround = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Dropship::DoorOpenAnim (Stuff::Time slice)
|
|
{
|
|
if (!m_HasDoors)
|
|
return;
|
|
m_DoorAmount += (Scalar) (slice / DOOR_OPEN_SPEED);
|
|
Clamp (m_DoorAmount,0,DOOR_MOVE_AMOUNT);
|
|
|
|
LinearMatrix4D mat = m_DoorAR->GetLocalToParent ();
|
|
mat(W_Axis, Z_Axis) = m_BaseYDoorAR - m_DoorAmount;
|
|
m_DoorAR->SetNewLocalToParent (mat);
|
|
|
|
mat = m_DoorFR->GetLocalToParent ();
|
|
mat(W_Axis, Z_Axis) = m_BaseYDoorFR - m_DoorAmount;
|
|
m_DoorFR->SetNewLocalToParent (mat);
|
|
|
|
mat = m_DoorAL->GetLocalToParent ();
|
|
mat(W_Axis, Z_Axis) = m_BaseYDoorAL + m_DoorAmount;
|
|
m_DoorAL->SetNewLocalToParent (mat);
|
|
|
|
mat = m_DoorFL->GetLocalToParent ();
|
|
mat(W_Axis, Z_Axis) = m_BaseYDoorFL + m_DoorAmount;
|
|
m_DoorFL->SetNewLocalToParent (mat);
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Dropship::DoorCloseAnim (Stuff::Time slice)
|
|
{
|
|
if (!m_HasDoors)
|
|
return;
|
|
m_DoorAmount -= (Scalar) (slice / DOOR_OPEN_SPEED);
|
|
Clamp (m_DoorAmount,0,DOOR_MOVE_AMOUNT);
|
|
|
|
LinearMatrix4D mat = m_DoorAR->GetLocalToParent ();
|
|
mat(W_Axis, Z_Axis) = m_BaseYDoorAR - m_DoorAmount;
|
|
m_DoorAR->SetNewLocalToParent (mat);
|
|
|
|
mat = m_DoorFR->GetLocalToParent ();
|
|
mat(W_Axis, Z_Axis) = m_BaseYDoorFR - m_DoorAmount;
|
|
m_DoorFR->SetNewLocalToParent (mat);
|
|
|
|
mat = m_DoorAL->GetLocalToParent ();
|
|
mat(W_Axis, Z_Axis) = m_BaseYDoorAL + m_DoorAmount;
|
|
m_DoorAL->SetNewLocalToParent (mat);
|
|
|
|
mat = m_DoorFL->GetLocalToParent ();
|
|
mat(W_Axis, Z_Axis) = m_BaseYDoorFL + m_DoorAmount;
|
|
m_DoorFL->SetNewLocalToParent (mat);
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Dropship::TakeOff(Stuff::Scalar runway_distance)
|
|
{
|
|
Check_Object(this);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
|
|
m_TakeOffStart = gos_GetElapsedTime ()+DROPSHIP_TAKEOFF_DELAY;
|
|
|
|
|
|
takeOffTargetPosition = GetLocalToWorld();
|
|
|
|
Stuff::Line3D line;
|
|
Point3D point;
|
|
|
|
point.x = takeOffTargetPosition.x;
|
|
point.z = takeOffTargetPosition.z;
|
|
point.y = flyingAltitude+100.0f;
|
|
|
|
line.m_length = flyingAltitude+300.0f;
|
|
line.m_direction = Vector3D::Down;
|
|
line.SetOrigin(point);
|
|
|
|
//
|
|
// Prepare query
|
|
//
|
|
Stuff::Normal3D inormal;
|
|
Stuff::Line3D iline;
|
|
Stuff::Normal3D normal;
|
|
Entity::CollisionQuery query(&line, &normal, Entity::CanBeWalkedOnFlag, NULL);
|
|
|
|
//
|
|
// Cast ray
|
|
//
|
|
Adept::Entity *entity_hit;
|
|
Check_Object(CollisionGrid::Instance);
|
|
entity_hit = CollisionGrid::Instance->ProjectLine(&query);
|
|
|
|
line.FindEnd(&point);
|
|
|
|
m_StartTakeoffEffect = true;
|
|
m_EffectGroundPosition = point;
|
|
|
|
// CreateTakeOffEffect();
|
|
// CreateTakeOffGroundEffect(point);
|
|
|
|
takeOffTargetPosition = Vector3D(takeOffTargetPosition.x, point.y + flyingAltitude, takeOffTargetPosition.z);
|
|
|
|
localSpaceDrag.linearMotion = model->linearDragCoefficients;
|
|
localSpaceDrag.angularMotion = model->angularDragCoefficients;
|
|
|
|
LinearMatrix4D world_to_local;
|
|
world_to_local.Invert(GetLocalToWorld());
|
|
localSpaceAcceleration.linearMotion.Multiply(
|
|
worldSpaceAcceleration.linearMotion,
|
|
world_to_local
|
|
);
|
|
localSpaceAcceleration.angularMotion.Multiply(
|
|
worldSpaceAcceleration.angularMotion,
|
|
world_to_local
|
|
);
|
|
Check_Object(executionState);
|
|
executionState->RequestState(ExecutionStateEngine::TakingOffMotionState);
|
|
m_OnGround = false;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Dropship::Land(void)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(executionState);
|
|
|
|
landTargetPosition = GetLocalToWorld();
|
|
|
|
Stuff::Line3D line;
|
|
Point3D point;
|
|
|
|
point.x = landTargetPosition.x;
|
|
point.z = landTargetPosition.z;
|
|
point.y = landTargetPosition.y-10;
|
|
|
|
line.m_length = flyingAltitude+300.0f;
|
|
line.m_direction = Vector3D::Down;
|
|
line.SetOrigin(point);
|
|
|
|
//
|
|
// Prepare query
|
|
//
|
|
Stuff::Normal3D inormal;
|
|
Stuff::Line3D iline;
|
|
Stuff::Normal3D normal;
|
|
Entity::CollisionQuery query(&line, &normal, Entity::CanBeWalkedOnFlag, NULL);
|
|
|
|
//
|
|
// Cast ray
|
|
//
|
|
Adept::Entity *entity_hit;
|
|
Check_Object(CollisionGrid::Instance);
|
|
entity_hit = CollisionGrid::Instance->ProjectLine(&query);
|
|
|
|
line.FindEnd(&point);
|
|
|
|
m_StartLandingEffect = true;
|
|
m_EffectGroundPosition = point;
|
|
// CreateLandingEffect();
|
|
// CreateLandingGroundEffect(point);
|
|
|
|
landTargetPosition = Vector3D(landTargetPosition.x, point.y, landTargetPosition.z);
|
|
|
|
executionState->RequestState(ExecutionStateEngine::LandingMotionState);
|
|
m_OnGround = true;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Dropship::TakeOffThrusterSimulation(Stuff::Time till,const Stuff::Vector3D& new_velocity,const Stuff::Vector3D& instantanious_angular_velocity,bool canswitch)
|
|
{
|
|
Check_Object(this);
|
|
|
|
Point3D current_pos;
|
|
current_pos = GetLocalToWorld();
|
|
Scalar time_slice = GetTimeSlice(till);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
Vector3D new_speed = Vector3D::Identity;
|
|
if (gos_GetElapsedTime () > m_TakeOffStart)
|
|
new_speed.y = 15.0f;
|
|
else
|
|
new_speed.y = 0;
|
|
|
|
Clamp(new_speed.y, 0.0f, model->takeOffSpeed);
|
|
localSpaceVelocity.linearMotion = new_speed;
|
|
worldSpaceVelocity.linearMotion.Multiply(new_speed, GetLocalToWorld());
|
|
|
|
pitchDemand = 0.0f;
|
|
|
|
Vector3D rotation_vector;
|
|
#if 0
|
|
rotation_vector.x = pitchDemand * model->pitchSpeed * time_slice;
|
|
Clamp(rotation_vector.x, -model->pitchDegree, model->pitchDegree);
|
|
rotation_vector.y = (yawDemand * model->fullStopTurnRate);
|
|
rotation_vector.z = (rollDemand * model->fullStopTurnRate);
|
|
#endif
|
|
rotation_vector.x = 0;
|
|
rotation_vector.y = 0;
|
|
rotation_vector.z = 0;
|
|
localSpaceVelocity.angularMotion = rotation_vector;
|
|
worldSpaceVelocity.angularMotion.Multiply(rotation_vector, GetLocalToWorld());
|
|
|
|
//
|
|
//---------------------------------------------------
|
|
// Make a matrix representing the rotation this frame
|
|
//---------------------------------------------------
|
|
//
|
|
Vector3D spin_axis;
|
|
spin_axis.Multiply(worldSpaceVelocity.angularMotion, time_slice);
|
|
UnitQuaternion spin;
|
|
spin = spin_axis;
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// Convert the EulerAngles into a matrix and create the new rotation matrix
|
|
// through concatenation
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
UnitQuaternion rotation;
|
|
rotation = initialLocalToParent;
|
|
UnitQuaternion desire;
|
|
desire.Multiply(rotation, spin);
|
|
LinearMatrix4D new_position(true);
|
|
new_position.BuildRotation(desire);
|
|
|
|
Vector3D delta;
|
|
delta.Multiply(worldSpaceVelocity.linearMotion, time_slice);
|
|
Vector3D rotated_vector;
|
|
rotated_vector.Multiply(delta, new_position);
|
|
|
|
Point3D old_translation(initialLocalToParent);
|
|
Point3D new_translation;
|
|
new_translation.Add(
|
|
old_translation,
|
|
rotated_vector
|
|
);
|
|
new_position.BuildTranslation(new_translation);
|
|
|
|
//
|
|
//----------------------------------------------
|
|
// Adjust position from network
|
|
//----------------------------------------------
|
|
//
|
|
|
|
YawPitchRoll correction_angle;
|
|
Point3D correction_position;
|
|
|
|
GetNetworkAdjustment(time_slice, correction_position, correction_angle);
|
|
|
|
YawPitchRoll new_rotation;
|
|
new_rotation = desire;
|
|
|
|
new_translation += correction_position;
|
|
new_rotation.yaw.angle += correction_angle.yaw.angle;
|
|
new_rotation.pitch.angle += correction_angle.pitch.angle;
|
|
new_rotation.roll.angle += correction_angle.roll.angle;
|
|
|
|
new_position = LinearMatrix4D::Identity;
|
|
new_position.BuildRotation(desire);
|
|
new_position.BuildTranslation(new_translation);
|
|
|
|
//
|
|
//----------------------------------------------
|
|
// Set the new position
|
|
//----------------------------------------------
|
|
//
|
|
|
|
SetNewLocalToParent(new_position);
|
|
|
|
if(current_pos.y >= takeOffTargetPosition.y)
|
|
{
|
|
Check_Object(executionState);
|
|
if(m_takeOffEffect.GetCurrent())
|
|
{
|
|
m_takeOffEffect.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::StoppingState);
|
|
}
|
|
if(m_takeOffGroundEffect.GetCurrent())
|
|
{
|
|
m_takeOffGroundEffect.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::StoppingState);
|
|
}
|
|
executionState->RequestState(ExecutionStateEngine::FlyingMotionState);
|
|
m_OnGround = false;
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void Dropship::LandingMovementSimulation(Stuff::Time till)
|
|
{
|
|
Check_Object(this);
|
|
|
|
Point3D current_pos;
|
|
current_pos = GetLocalToWorld();
|
|
Scalar time_slice = GetTimeSlice(till);
|
|
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
Vector3D new_speed = Vector3D::Identity;
|
|
new_speed.x = 0;
|
|
new_speed.z = 0;
|
|
new_speed.y = -15.0f;
|
|
Clamp(new_speed.y, -model->takeOffSpeed, 0.0f);
|
|
localSpaceVelocity.linearMotion = new_speed;
|
|
worldSpaceVelocity.linearMotion.Multiply(new_speed, GetLocalToWorld());
|
|
|
|
pitchDemand = 0.0f;
|
|
|
|
Vector3D rotation_vector;
|
|
rotation_vector.x = pitchDemand * model->pitchSpeed * time_slice;
|
|
Clamp(rotation_vector.x, -model->pitchDegree, model->pitchDegree);
|
|
rotation_vector.y = (yawDemand * model->fullStopTurnRate);
|
|
rotation_vector.z = (rollDemand * model->fullStopTurnRate);
|
|
localSpaceVelocity.angularMotion = rotation_vector;
|
|
worldSpaceVelocity.angularMotion.Multiply(rotation_vector, GetLocalToWorld());
|
|
|
|
//
|
|
//---------------------------------------------------
|
|
// Make a matrix representing the rotation this frame
|
|
//---------------------------------------------------
|
|
//
|
|
Vector3D spin_axis;
|
|
spin_axis.Multiply(worldSpaceVelocity.angularMotion, time_slice);
|
|
UnitQuaternion spin;
|
|
spin = spin_axis;
|
|
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
// Convert the EulerAngles into a matrix and create the new rotation matrix
|
|
// through concatenation
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
UnitQuaternion rotation;
|
|
rotation = initialLocalToParent;
|
|
UnitQuaternion desire;
|
|
desire.Multiply(rotation, spin);
|
|
LinearMatrix4D new_position(true);
|
|
new_position.BuildRotation(desire);
|
|
|
|
Vector3D delta;
|
|
delta.Multiply(worldSpaceVelocity.linearMotion, time_slice);
|
|
Vector3D rotated_vector;
|
|
rotated_vector.Multiply(delta, new_position);
|
|
|
|
Point3D old_translation(initialLocalToParent);
|
|
Point3D new_translation;
|
|
new_translation.Add(
|
|
old_translation,
|
|
rotated_vector
|
|
);
|
|
new_position.BuildTranslation(new_translation);
|
|
|
|
|
|
//
|
|
//----------------------------------------------
|
|
// Adjust position from network
|
|
//----------------------------------------------
|
|
//
|
|
|
|
YawPitchRoll correction_angle;
|
|
Point3D correction_position;
|
|
|
|
GetNetworkAdjustment(time_slice, correction_position, correction_angle);
|
|
|
|
YawPitchRoll new_rotation;
|
|
new_rotation = desire;
|
|
|
|
new_translation += correction_position;
|
|
new_rotation.yaw.angle += correction_angle.yaw.angle;
|
|
new_rotation.pitch.angle += correction_angle.pitch.angle;
|
|
new_rotation.roll.angle += correction_angle.roll.angle;
|
|
|
|
new_position = LinearMatrix4D::Identity;
|
|
new_position.BuildRotation(desire);
|
|
new_position.BuildTranslation(new_translation);
|
|
|
|
//
|
|
//----------------------------------------------
|
|
// Set the new position
|
|
//----------------------------------------------
|
|
//
|
|
|
|
|
|
SetNewLocalToParent(new_position);
|
|
|
|
Stuff::Point3D fredpos (new_position);
|
|
Stuff::Line3D line;
|
|
Point3D point;
|
|
|
|
point.x = fredpos.x;
|
|
point.z = fredpos.z;
|
|
point.y = flyingAltitude+100.0f;
|
|
|
|
line.m_length = flyingAltitude+300.0f;
|
|
line.m_direction = Vector3D::Down;
|
|
line.SetOrigin(point);
|
|
|
|
//
|
|
// Prepare query
|
|
//
|
|
Stuff::Normal3D inormal;
|
|
Stuff::Line3D iline;
|
|
Stuff::Normal3D normal;
|
|
Entity::CollisionQuery query(&line, &normal, Entity::CanBeWalkedOnFlag, NULL);
|
|
|
|
//
|
|
// Cast ray
|
|
//
|
|
Adept::Entity *entity_hit;
|
|
Check_Object(CollisionGrid::Instance);
|
|
entity_hit = CollisionGrid::Instance->ProjectLine(&query);
|
|
|
|
line.FindEnd(&point);
|
|
|
|
if(fredpos.y <= point.y)
|
|
{
|
|
Check_Object(executionState);
|
|
if(m_landingEffect.GetCurrent())
|
|
{
|
|
m_landingEffect.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::StoppingState);
|
|
}
|
|
if(m_landingGroundEffect.GetCurrent())
|
|
{
|
|
m_landingGroundEffect.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::StoppingState);
|
|
}
|
|
executionState->RequestState(ExecutionStateEngine::TaxiState);
|
|
localSpaceVelocity.linearMotion.x = 0;
|
|
localSpaceVelocity.linearMotion.y = 0;
|
|
localSpaceVelocity.linearMotion.z = 0;
|
|
m_OnGround = true;
|
|
pitchDemand = 0;
|
|
yawDemand = 0;
|
|
rollDemand = 0;
|
|
speedDemand = 0;
|
|
}
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
|
|
void Dropship::TestInstance() const
|
|
{
|
|
Verify(IsDerivedFrom(DefaultData));
|
|
}
|
|
|
|
void Dropship::EngineDead (void)
|
|
{
|
|
m_NumEngines--;
|
|
if (m_NumEngines == 0)
|
|
{
|
|
SelfDestruct ();
|
|
}
|
|
}
|
|
|
|
void Dropship::ReactToDestruction(int damage_mode, int damage_type)
|
|
{
|
|
switch(damage_mode)
|
|
{
|
|
case InternalDamageObject::DestructionDamageMode:
|
|
{
|
|
if((!IsDestroyed()) && (executionState->GetState() != ExecutionStateEngine::CrashingDeathState) && !m_CanDie)
|
|
{
|
|
// MSL 5.04 Dropship
|
|
//added for scoring objective dropships (call it a building) in mission play games
|
|
if (m_scoreThisDropship)
|
|
{
|
|
Check_Object (Mission::GetInstance());
|
|
Mission::GetInstance()->ScoringReactToBuildingDeath (m_whoShotMeLast, GetReplicatorID());
|
|
}
|
|
|
|
if(m_AI)
|
|
{
|
|
Check_Object(m_AI);
|
|
m_AI->Die();
|
|
}
|
|
|
|
m_DeathStart = gos_GetElapsedTime ();
|
|
const GameModel *model = GetGameModel();
|
|
Check_Object(model);
|
|
Effect *effect;
|
|
effect = CreateEffect(model->destroyedEffectResource, this, true);
|
|
if(effect)
|
|
m_crashingEffect.Add(effect);
|
|
m_CanDie = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|