Files
firestorm/Gameleap/code/mw4/Code/MW4/Helicopter.cpp
T
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

628 lines
17 KiB
C++

#include "MW4Headers.hpp"
#include "Helicopter.hpp"
#include <Adept\Effect.hpp>
#include <Adept\CollisionGrid.hpp>
#include <Adept\EntityManager.hpp>
//#############################################################################
//############################### Helicopter ############################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Helicopter::ClassData*
Helicopter::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Helicopter::InitializeClass()
{
Check_Object(ExecutionStateEngine::DefaultData);
Verify(!DefaultData);
DefaultData =
new ClassData(
HelicopterClassID,
"MechWarrior4::Helicopter",
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
Helicopter::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Helicopter*
Helicopter::Make(
CreateMessage *message,
ReplicatorID *base_id
)
{
Check_Object(message);
gos_PushCurrentHeap(Heap);
Helicopter *new_entity = new
Helicopter(DefaultData, message, base_id, NULL);
gos_PopCurrentHeap();
Check_Object(new_entity);
Check_Object(EntityManager::GetInstance());
EntityManager::GetInstance()->AddMover(new_entity);
return new_entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Helicopter::Helicopter(
ClassData *class_data,
CreateMessage *message,
ReplicatorID *base_id,
ElementRenderer::Element *element
):
Airplane(class_data, message, base_id, element),
m_takeOffEffect(NULL),
m_takeOffGroundEffect(NULL),
m_landingEffect(NULL),
m_landingGroundEffect(NULL)
{
Check_Pointer(this);
Check_Object(message);
CommonCreation(message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Helicopter::~Helicopter()
{
Check_Pointer(this);
if(m_takeOffEffect.GetCurrent())
delete m_takeOffEffect.GetCurrent();
if(m_takeOffGroundEffect.GetCurrent())
delete m_takeOffGroundEffect.GetCurrent();
if(m_landingEffect.GetCurrent())
delete m_landingEffect.GetCurrent();
if(m_landingGroundEffect.GetCurrent())
delete m_landingGroundEffect.GetCurrent();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Helicopter::CommonCreation(CreateMessage *message)
{
Check_Object(this);
Check_Object(message);
m_StartTakeoffEffect = false;
m_StartLandingEffect = false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Helicopter::Respawn(Entity__CreateMessage *message)
{
Check_Object(this);
Check_Object(message);
BaseClass::Respawn(message);
CreateMessage *helicopter_message = Cast_Pointer(CreateMessage *, message);
CommonCreation(helicopter_message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Helicopter::Reuse(
const CreateMessage *message,
ReplicatorID *base_id
)
{
Check_Object(this);
Check_Object(message);
STOP(("Not implemented"));
BaseClass::Reuse(message, base_id);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Helicopter::PostCollisionExecute(Time till)
{
Check_Object(this);
if (m_StartTakeoffEffect)
{
CreateTakeOffEffect();
CreateTakeOffGroundEffect(m_EffectGroundPosition);
m_StartTakeoffEffect = false;
}
if (m_StartLandingEffect)
{
CreateLandingEffect();
CreateLandingGroundEffect(m_EffectGroundPosition);
m_StartLandingEffect = false;
}
Airplane::PostCollisionExecute (till);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Helicopter::TakeOff(Stuff::Scalar runway_distance)
{
Check_Object(this);
const GameModel *model = GetGameModel();
Check_Object(model);
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 Helicopter::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 Helicopter::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;
new_speed.y = model->takeOffSpeed;
new_speed.x = new_speed.z = 0;
Clamp(new_speed.y, 0.0f, model->takeOffSpeed);
localSpaceVelocity.linearMotion = new_speed;
worldSpaceVelocity.linearMotion = localSpaceVelocity.linearMotion; // helicopters go straight up
// worldSpaceVelocity.linearMotion.Multiply(new_speed, GetLocalToWorld());
pitchDemand = 0.3f;
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);
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 Helicopter::LandingMovementSimulation(Stuff::Time till)
{
Check_Object(this);
speedDemand = 0.0f;
speedDemandKPH = 0.0f;
currentSpeedMPS = 0;
speedDemandMPS = 0;
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.y = -model->takeOffSpeed;
new_speed.x = new_speed.z = 0;
Clamp(new_speed.y, -model->takeOffSpeed, 0.0f);
localSpaceVelocity.linearMotion = new_speed;
worldSpaceVelocity.linearMotion = localSpaceVelocity.linearMotion; // helicopters come straight down
// worldSpaceVelocity.linearMotion.Multiply(new_speed, GetLocalToWorld());
if (pitchAngle < 0)
{
pitchAngle += (model->pitchSpeed*time_slice);
Max_Clamp(pitchAngle, 0);
}
else if (pitchAngle > 0)
{
pitchAngle -= (model->pitchSpeed*time_slice);
Min_Clamp(pitchAngle, 0);
}
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_rotation.pitch = pitchAngle;
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(new_rotation);
new_position.BuildTranslation(new_translation);
pitchAngle = new_rotation.pitch;
//
//----------------------------------------------
// Set the new position
//----------------------------------------------
//
SetNewLocalToParent(new_position);
if(current_pos.y <= landTargetPosition.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::NeverExecuteState);
m_OnGround = false;
pitchDemand = 0;
yawDemand = 0;
rollDemand = 0;
speedDemand = 0;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Helicopter::CreateTakeOffEffect()
{
Check_Object(this);
const GameModel *model = GetGameModel();
Check_Object(model);
if(model->takeOffResource != ResourceID::Null)
{
if(!m_takeOffEffect.GetCurrent())
{
Effect *effect = CreateLoopingEffect(model->takeOffResource, this, true);
if(effect)
m_takeOffEffect.Add(effect);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Helicopter::CreateTakeOffGroundEffect(Point3D point)
{
Check_Object(this);
const GameModel *model = GetGameModel();
Check_Object(model);
if(model->takeOffGroundResource != ResourceID::Null)
{
if(!m_takeOffGroundEffect.GetCurrent())
{
Effect *effect = CreateLoopingEffect(model->takeOffGroundResource, point);
if(effect)
m_takeOffGroundEffect.Add(effect);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Helicopter::CreateLandingEffect()
{
Check_Object(this);
const GameModel *model = GetGameModel();
Check_Object(model);
if(model->landingResource != ResourceID::Null)
{
if(!m_landingEffect.GetCurrent())
{
Effect *effect = CreateLoopingEffect(model->landingResource, this, true);
if(effect)
m_landingEffect.Add(effect);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Helicopter::CreateLandingGroundEffect(Point3D point)
{
Check_Object(this);
const GameModel *model = GetGameModel();
Check_Object(model);
if(model->landingGroundResource != ResourceID::Null)
{
if(!m_landingGroundEffect.GetCurrent())
{
Effect *effect = CreateLoopingEffect(model->landingGroundResource, point);
if(effect)
m_landingGroundEffect.Add(effect);
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Helicopter::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}