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

1924 lines
50 KiB
C++

//===========================================================================//
// File: Mech.cpp
//---------------------------------------------------------------------------//
// Date Who Modification //
// -------- --- ---------------------------------------------------------- //
// 09/09/98 JSE Inital base class based off of Shadowrun/Adept //
// 09/22/98 BDB Inital base Mech class based off Vehicle //
//---------------------------------------------------------------------------//
// Copyright (C) 1998, Fasa Interactive //
// All Rights reserved worldwide //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL //
//===========================================================================//
#include "MW4Headers.hpp"
#include "Airplane.hpp"
#include "AirplaneAnimationStateEngine.hpp"
#include "helicopter.hpp"
#include "AI.hpp"
#include "aiutils.hpp"
#include "AI_Statistics.hpp"
#include <Adept\EntityManager.hpp>
#include <Adept\DamageObject.hpp>
#include <Adept\Effect.hpp>
#include <Adept\NameTable.hpp>
#include <Adept\CollisionGrid.hpp>
#include <Adept\Map.hpp>
#include <Adept\CollisionVolume.hpp>
stlport::vector<Scalar> *Airplane::m_Heights;
const Stuff::Scalar PlaneHeightSlotSize = 10.0f;
namespace MW4AI
{
extern Stuff::Scalar g_MaxBuildingHeight; // above the ground
extern Stuff::Scalar g_MaxAirHeight; // above the ground, to stay above movers
extern Stuff::Scalar MinZ, MaxZ, MinX, MaxX;
}
//#############################################################################
//################## Airplane::ExecutionStateEngine #####################
//#############################################################################
const StateEngine::StateEntry
Airplane::ExecutionStateEngine::StateEntries[]=
{
STATE_ENTRY(Airplane__ExecutionStateEngine, TakingOffMotion),
STATE_ENTRY(Airplane__ExecutionStateEngine, LandingMotion),
STATE_ENTRY(Airplane__ExecutionStateEngine, CrashingDeath),
STATE_ENTRY(Airplane__ExecutionStateEngine, Taxi),
STATE_ENTRY(Airplane__ExecutionStateEngine, Popup),
STATE_ENTRY(Airplane__ExecutionStateEngine, Popdown),
STATE_ENTRY(Airplane__ExecutionStateEngine, Float)
};
Airplane::ExecutionStateEngine::ClassData*
Airplane::ExecutionStateEngine::DefaultData = NULL;
DWORD MechWarrior4::Executed_Airplane_Count = 0;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Airplane::ExecutionStateEngine::InitializeClass()
{
Check_Object(StateEngine::DefaultData);
Verify(!DefaultData);
DefaultData =
new ClassData(
Airplane__ExecutionStateEngineClassID,
"Airplane::ExecutionStateEngine",
BaseClass::DefaultData,
ELEMENTS(StateEntries), StateEntries,
(Entity::ExecutionStateEngine::Factory)Make,
(Entity::ExecutionStateEngine::FactoryRequest::Factory)
&FactoryRequest::ConstructFactoryRequest
);
Register_Object(DefaultData);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Airplane::ExecutionStateEngine::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Airplane::ExecutionStateEngine*
Airplane::ExecutionStateEngine::Make(
Airplane *mover,
FactoryRequest *request
)
{
Check_Object(mover);
Check_Object(request);
gos_PushCurrentHeap(Heap);
Airplane::ExecutionStateEngine *engine =
new Airplane::ExecutionStateEngine(DefaultData, mover, request);
gos_PopCurrentHeap();
return engine;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
Airplane::ExecutionStateEngine::RequestState(
int new_state,
void* data
)
{
Check_Object(this);
Check_Object(owningEntity);
//
//----------------------------------------------
// Now, switch the state and tickle the watchers
//----------------------------------------------
//
Airplane *airplane;
airplane = Cast_Object(Airplane *, owningEntity);
if((new_state == TakingOffMotionState) && (currentState == FlyingMotionState))
return currentState;
if((new_state == LandingMotionState) && (currentState != FlyingMotionState))
return currentState;
if((new_state == CrashingDeathState) && (currentState == AlwaysExecuteState))
{
// airplane->shouldDie = true;
airplane->shouldLeaveReckage = true;
airplane->SetDying();
return currentState;
}
switch (BaseClass::RequestState(new_state, data))
{
case FlyingMotionState:
airplane->SetInAir();
break;
case TakingOffMotionState:
airplane->SetTakingOff();
break;
}
return currentState;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Airplane::ExecutionStateEngine::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
//#############################################################################
//############################### Airplane ##############################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Airplane::ClassData*
Airplane::DefaultData = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Airplane::InitializeClass()
{
Check_Object(ExecutionStateEngine::DefaultData);
Verify(!DefaultData);
DefaultData =
new ClassData(
AirplaneClassID,
"MechWarrior4::Airplane",
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::Factory)AirplaneAnimationStateEngine::Make
);
Register_Object(DefaultData);
m_Heights = new stlport::vector<Scalar>;
Check_Pointer (m_Heights);
//Dave Need to add attribute entries
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
FlyingAltitude,
flyingAltitude,
Scalar
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
TiltSpeed,
tiltSpeed,
Radian
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
TiltDegree,
tiltDegree,
Radian
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
PercentageOfTurnToStartTilt,
percentageOfTurnToStartTilt,
Scalar
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
PercentageOfSpeedToStartTilt,
percentageOfSpeedToStartTilt,
Scalar
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
MaxTurnAngle,
maxTurnAngle,
Scalar
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
ThrusterAcceleration,
thrusterAcceleration,
Scalar
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
PitchSpeed,
pitchSpeed,
Radian
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
PitchDegree,
pitchDegree,
Radian
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
PercentageOfSpeedToStartPitch,
percentageOfSpeedToStartPitch,
Scalar
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
TakeOffSpeed,
takeOffSpeed,
Scalar
);
CUSTOM_DIRECT_ATTRIBUTE(
Airplane,
TakingOffSFX,
takingOffSFX,
int,
IntClassID
);
CUSTOM_DIRECT_ATTRIBUTE(
Airplane,
InAirSFX,
inAirSFX,
int,
IntClassID
);
CUSTOM_DIRECT_ATTRIBUTE(
Airplane,
IdleSFX,
idleSFX,
int,
IntClassID
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
MaxClimb,
maxClimb,
Scalar
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
MaxDescent,
maxDescent,
Scalar
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
TakeOffResource,
takeOffResource,
ResourceID
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
TakeOffGroundResource,
takeOffGroundResource,
ResourceID
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
LandingResource,
landingResource,
ResourceID
);
DIRECT_GAME_MODEL_ATTRIBUTE(
Airplane__GameModel,
LandingGroundResource,
landingGroundResource,
ResourceID
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Airplane::TerminateClass()
{
Unregister_Object(DefaultData);
delete DefaultData;
DefaultData = NULL;
delete m_Heights;
m_Heights = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Airplane*
Airplane::Make(
CreateMessage *message,
ReplicatorID *base_id
)
{
Check_Object(message);
gos_PushCurrentHeap(Heap);
Airplane *new_entity = new
Airplane(DefaultData, message, base_id, NULL);
gos_PopCurrentHeap();
Check_Object(new_entity);
Check_Object(EntityManager::GetInstance());
EntityManager::GetInstance()->AddMover(new_entity);
return new_entity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Replicator::CreateMessage*
Airplane::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);
message->altitude = flyingAltitude;
return message;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Airplane::Airplane(
ClassData *class_data,
CreateMessage *message,
ReplicatorID *base_id,
ElementRenderer::Element *element
):
Vehicle(class_data, message, base_id, element),
m_PopupHeight(0),
m_PopdownHeight(0),
m_PopupClimbSpeed(0),
m_crashingEffect(NULL)
{
Check_Pointer(this);
Check_Object(message);
HookUpSubsystems();
CommonCreation(message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Airplane::CommonCreation(CreateMessage *message)
{
Check_Object(this);
Check_Object(message);
m_OnGround = true;
takeOffTargetPosition = Point3D::Identity;
tiltAngle = 0.0f;
pitchAngle = 0.0f;
shouldDie = false;
hasTakeOffAnimationLoaded = false;
shouldLeaveReckage = false;
m_Attacking = false;
const GameModel *model = GetGameModel();
Check_Object(model);
m_LastState = ExecutionStateEngine::TaxiState;
flyingAltitude = message->altitude;
m_AttackAltitude = 0;
m_Attacking = false;
if(flyingAltitude == 0.0f)
flyingAltitude = model->flyingAltitude;
// AdjustAltitude ();
Max_Clamp (flyingAltitude,800);
SetIdle();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Airplane::Respawn(Entity__CreateMessage *message)
{
Check_Object(this);
Check_Object(message);
BaseClass::Respawn(message);
CreateMessage *airplane_message = Cast_Pointer(CreateMessage *, message);
CommonCreation(airplane_message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Airplane::LoadAnimationScripts()
{
Vehicle::LoadAnimationScripts();
const GameModel *model = GetGameModel();
Check_Object(model);
if (model->animScriptName[0] != NULL)
{
hasTakeOffAnimationLoaded = true;
Check_Object(animStateEngine);
animStateEngine->RequestState(AirplaneAnimationStateEngine::IdleState);
}
else
{
hasTakeOffAnimationLoaded = false;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Airplane::~Airplane()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Airplane::Reuse(
const CreateMessage *message,
ReplicatorID *base_id
)
{
Check_Object(this);
Check_Object(message);
STOP(("Not implemented"));
BaseClass::Reuse(message, base_id);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Airplane::TurnOff (void)
{
m_LastState = executionState->GetState ();
executionState->RequestState(ExecutionStateEngine::AIMotionState);
}
void Airplane::TurnOn (void)
{
lastParameterization = gos_GetElapsedTime ();
executionState->RequestState(m_LastState);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Airplane::PreCollisionExecute(Time till)
{
Check_Object(this);
PRECOLLISION_LOGIC("Airplane");
BaseClass::PreCollisionExecute(till);
UnitVector3D world_down_in_local;
//
//---------------------------------
// If we aren't executing, stop now
//---------------------------------
//
Check_Object(executionState);
int pre_state = executionState->GetState();
Verify(pre_state != ExecutionStateEngine::NeverExecuteState);
Set_Statistic(Executed_Airplane_Count, Executed_Airplane_Count+1);
Scalar time_slice = GetTimeSlice(till);
Verify(time_slice > 0.0f);
switch (pre_state)
{
case ExecutionStateEngine::TaxiState:
GetLocalToWorld().GetWorldDownInLocal(&world_down_in_local);
localSpaceAcceleration.linearMotion.AddScaled(
localSpaceAcceleration.linearMotion,
world_down_in_local,
g_Gravity
);
ComputeForwardSpeed(time_slice);
UpdateVehiclePosition(time_slice);
break;
case ExecutionStateEngine::FlyingMotionState:
ComputeForwardSpeed(time_slice);
TiltPlane(time_slice);
FlyingMovementSimulation(till);
break;
case ExecutionStateEngine::TakingOffMotionState:
// TakeOffThrusterSimulation(till);
instantaniousAngularVelocity = Stuff::Vector3D::Identity;
animationVelocity = Stuff::Point3D::Identity;
Check_Object(animStateEngine);
if (hasTakeOffAnimationLoaded)
{
animStateEngine->RunStates(time_slice);
TakeOffThrusterSimulation(till, animationVelocity, instantaniousAngularVelocity,false);
if(animStateEngine->CurrentStateLoopedThisFrame())
{
animStateEngine->RequestState(AirplaneAnimationStateEngine::IdleState);
Check_Object(executionState);
executionState->RequestState(ExecutionStateEngine::FlyingMotionState);
currentSpeedMPS = 78.0f; // set to the last animation speed, hack but it works and we are two weeks from shipping.
m_OnGround = false;
}
}
else
{
animationVelocity.z = 10;
animationVelocity.y = 10;
TakeOffThrusterSimulation(till, animationVelocity, instantaniousAngularVelocity,true);
m_OnGround = false;
// executionState->RequestState(ExecutionStateEngine::FlyingMotionState);
}
break;
//SPEW(("daberger","AnimVelocity z: %f y: %f", animationVelocity.z, animationVelocity.y));
case ExecutionStateEngine::LandingMotionState:
TiltPlane(time_slice);
LandingMovementSimulation(till);
break;
case ExecutionStateEngine::CrashingDeathState:
CrashingDeathMovementSimulation(till);
break;
case ExecutionStateEngine::PopupState:
PopUpOrDownSimulation(time_slice,m_PopupHeight);
break;
case ExecutionStateEngine::PopdownState:
PopUpOrDownSimulation(time_slice,m_PopdownHeight);
break;
case ExecutionStateEngine::FloatState:
FloatSimulation(time_slice);
break;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Airplane::ComputeForwardSpeed(Stuff::Scalar time_slice)
{
Check_Object(this);
const GameModel *model = GetGameModel();
Check_Object(model);
//
//----------------------------------------------------
// Set the demands to zero if the vehicle is shut down
//----------------------------------------------------
//
if (vehicleShutDown)
{
speedDemand = 0.0f;
speedDemandKPH = 0.0f;
}
Verify ((model->moveTypeFlag == MWObject__GameModel::FLYER_MOVETYPE)||(model->moveTypeFlag == MWObject__GameModel::HELI_MOVETYPE)||(model->moveTypeFlag == MWObject__GameModel::DROPSHIP_MOVETYPE));
//
//------------------------------------------------------------------------
// Figure out our desired speed. If we are stopped, set the KPH variables
// to zero and quit
//------------------------------------------------------------------------
//
if (speedDemand >= 0.0f)
speedDemandMPS = (speedDemand * GetMaxSpeed());
else
speedDemandMPS = -(speedDemand * model->maxReverseSpeed);
if (speedDemandMPS == 0.0f && currentSpeedMPS == 0.0f)
{
speedDemandKPH = 0.0f;
currentSpeedKPH = 0.0f;
return;
}
//
//--------------------------------------------------------------------
// If we are not going backwards, find out what speed we want after we
// consider braking
//--------------------------------------------------------------------
//
if (currentSpeedMPS >= 0.0f)
{
if (speedDemandMPS > currentSpeedMPS)
{
currentSpeedMPS += (model->acceleration * time_slice);
Max_Clamp(currentSpeedMPS, speedDemandMPS);
}
else if (speedDemandMPS < currentSpeedMPS)
{
currentSpeedMPS -= (model->decceleration * time_slice);
Min_Clamp(currentSpeedMPS, speedDemandMPS);
}
}
else
{
if (speedDemandMPS < currentSpeedMPS)
{
currentSpeedMPS -= (model->acceleration * model->reverseAccelerationMultiplier * time_slice);
Min_Clamp(currentSpeedMPS, speedDemandMPS);
}
else if (speedDemandMPS > currentSpeedMPS)
{
currentSpeedMPS += (model->decceleration * model->reverseDeccelerationMultiplier * time_slice);
Max_Clamp(currentSpeedMPS, speedDemandMPS);
}
}
//
//----------------------------------------------------
// Now adjust all this to the limits in the model file
//----------------------------------------------------
//
Clamp(currentSpeedMPS, model->maxReverseSpeed, GetMaxSpeed());
//
//---------------------------
// Set up the velocity vector
//---------------------------
//
localSpaceVelocity.linearMotion.z = currentSpeedMPS;
//
//----------------------
// Set the KPH variables
//----------------------
//
currentSpeedKPH = currentSpeedMPS * 3.6f;
speedDemandKPH = speedDemandMPS * 3.6f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
Airplane::CollisionHandler(
Stuff::LinearMatrix4D *new_position,
Stuff::DynamicArrayOf<CollisionData> *collisions
)
{
Check_Object(this);
Entity::ExecutionStateEngine *engine = executionState;
if (engine->GetState() == ExecutionStateEngine::NeverExecuteState)
{
Verify(!newCollisions);
delete collisions;
return false;
}
Verify(GetInterestLevel() != DormantInterestLevel);
Verify(EntityManager::GetInstance()->IsInPostCollisionExecution(this));
//
//----------------------------------------------------------
// If we are destroyed, delete the collision list and return
//----------------------------------------------------------
//
if (IsDestroyed())
{
delete collisions;
Verify(!newCollisions);
return false;
}
//
//-----------------------
// Iterate the collisions
//-----------------------
//
for (int i=0; i<collisions->GetLength(); ++i)
{
CollisionData *data = &(*collisions)[i];
Check_Pointer(data);
//
//-------------------------------------------------------------------
// Airplanes don't collide with bridges. The don't collide if flying
//-------------------------------------------------------------------
//
Check_Object(executionState);
if ((executionState->GetState() == ExecutionStateEngine::FlyingMotionState) || // flying airplanes don't collide
(executionState->GetState() == ExecutionStateEngine::PopupState) ||
(executionState->GetState() == ExecutionStateEngine::FloatState) ||
(executionState->GetState() == ExecutionStateEngine::PopdownState))
continue;
//
//----------------------------------------------
// If we are crashing, reset to our old position
//----------------------------------------------
//
if (data->m_otherEntity->IsDerivedFrom (Airplane::DefaultData))
continue;
if(executionState->GetState() == ExecutionStateEngine::CrashingDeathState)
{
Check_Object(entityElement);
*new_position = entityElement->GetNewLocalToParent();
Point3D old_translation(entityElement->GetLocalToParent());
new_position->BuildTranslation(old_translation);
shouldDie = true;
shouldLeaveReckage = false;
DealSplashDamage();
delete collisions;
Verify(!newCollisions);
return true;
}
if (data->m_otherEntity->CanBeWalkedOn())
continue;
}
Verify(!newCollisions);
newCollisions = collisions;
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Airplane::PostCollisionExecute(Time till)
{
Check_Object(this);
POSTCOLLISION_LOGIC("Airplane");
if (executionState->GetState() == ExecutionStateEngine::FlyingMotionState)
worldSpaceVelocity.linearMotion.Multiply(localSpaceVelocity.linearMotion,GetLocalToWorld());
lastParameterization = till;
initialLocalToParent = GetLocalToParent();
initialWorldSpaceVelocity = worldSpaceVelocity,
initialWorldSpaceAcceleration = worldSpaceAcceleration;
if (executionState->GetState() == ExecutionStateEngine::NeverExecuteState)
{
if (oldCollisions)
delete oldCollisions;
oldCollisions = NULL;
if (newCollisions)
delete newCollisions;
newCollisions = NULL;
return;
}
if(shouldDie)
{
const GameModel *model = GetGameModel();
Check_Object(model);
DealSplashDamage();
if(m_crashingEffect.GetCurrent())
{
m_crashingEffect.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::StoppingState);
m_crashingEffect.Remove();
m_OnGround = true;
}
Entity::ReactToDestruction(InternalDamageObject::DestructionDamageMode,ProjectileDamageType);
// SetDestroyedFlag(InternalDamageObject::DestructionDamageMode);
CreateEffect(model->secondaryDestroyedEffectResource, this);
if(shouldLeaveReckage)
{
if(!m_deathEntity.GetCurrent())
{
Entity *death_entity = CreateStaticHermitEntity(model->deathEntityResource);
if(death_entity)
{
m_deathEntity.Remove();
m_deathEntity.Add(death_entity);
}
}
}
RemoveCollision();
if (newCollisions)
{
delete newCollisions;
newCollisions = NULL;
}
// MSL 5.02 bug fix
// bug fix # 6523 - allow dropships to turn off
if ( m_AI && executionState->GetState() == Vehicle::ExecutionStateEngine::AIMotionState)
{
m_AI->TurnOn();
}
executionState->RequestState(ExecutionStateEngine::NeverExecuteState);
m_OnGround = true;
entityElement->SetAlwaysCullMode();
lastParameterization = till;
initialLocalToParent = GetLocalToParent();
SetDead();
SyncMatrices(true);
}
else
{
BaseClass::PostCollisionExecute(till);
}
}
inline Scalar FindTerrainHeight(Line3D& line, Adept::Entity* ignore)
{
Normal3D normal;
Entity::CollisionQuery query(&line, &normal, Entity::CanBeWalkedOnFlag, ignore);
CollisionGrid::Instance->ProjectLine(&query);
Point3D point;
line.FindEnd(&point);
return (point.y);
}
Scalar FindTerrainHeightFromPoint(const Point3D& point, Adept::Entity* ignore)
{
if ((point.x <= MW4AI::MinX) ||
(point.x >= MW4AI::MaxX) ||
(point.z <= MW4AI::MinZ) ||
(point.z >= MW4AI::MaxZ))
{
return (0);
}
Line3D line;
line.m_length = 1200.0f;
line.m_direction = Vector3D::Down;
line.SetOrigin(point);
return (FindTerrainHeight(line,ignore));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Airplane::FlyingMovementSimulation(Stuff::Time till)
{
Check_Object(this);
const GameModel *model = GetGameModel();
Scalar time_slice = GetTimeSlice(till);
Verify(time_slice > 0);
// STOP(("Not finished"));
// ComputeVelocity(time_slice);
const LinearMatrix4D &local_to_world = GetLocalToWorld();
Point3D old_loc(local_to_world);
//
// add the local adjustment to the current position
//
Point3D new_translation;
Vector3D local_motion;
local_motion.Multiply(localSpaceVelocity.linearMotion,local_to_world);
new_translation = old_loc;
new_translation.x += local_motion.x * time_slice;
new_translation.z += local_motion.z * time_slice;
UnitVector3D unit_forward;
local_to_world.GetLocalForwardInWorld(&unit_forward);
Point3D forward(unit_forward);
forward *= 25.0f;
Point3D point(local_to_world);
point += forward;
point.y += 100.0f;
Stuff::Scalar first_y(FindTerrainHeightFromPoint(point,this));
Point3D point2(local_to_world);
forward *= 4.0f;
point2 += forward;
point2.y += 100.0f;
UnitVector3D unit_left;
local_to_world.GetLocalLeftInWorld(&unit_left);
Point3D left(unit_left);
left *= 30.0f;
UnitVector3D unit_right;
local_to_world.GetLocalRightInWorld(&unit_right);
Point3D right(unit_right);
right *= 30.0f;
Point3D point3(point2);
point2 += left;
point3 += right;
Scalar second_y(FindTerrainHeightFromPoint(point2,this));
Scalar third_y(FindTerrainHeightFromPoint(point3,this));
Scalar worst_y(first_y);
if (second_y > worst_y)
{
worst_y = second_y;
}
if (third_y > worst_y)
{
worst_y = third_y;
}
Scalar delta,change;
if (m_Attacking)
delta = (m_AttackAltitude + worst_y) - old_loc.y;
else
delta = (flyingAltitude + worst_y) - old_loc.y;
if (delta > 0)
change = model->maxClimb * time_slice;
else
change = model->maxDescent * time_slice;
Clamp(delta,-change,change);
new_translation.y = old_loc.y + delta;
//
// get the current yawpitchroll from the local to world matrix
//
Scalar temp = Lerp(model->fullStopTurnRate, model->topSpeedTurnRate, currentSpeedMPS/GetMaxSpeed());
YawPitchRoll new_rotation(local_to_world);
temp *= time_slice;
new_rotation.yaw += yawDemand * temp;
new_rotation.pitch += pitchDemand * temp;
new_rotation.roll += rollDemand * temp;
// new_rotation = local_to_world;
new_rotation.yaw += (localSpaceVelocity.angularMotion.y * time_slice);
new_rotation.roll += (localSpaceVelocity.angularMotion.z * time_slice);
// new_rotation.pitch += (localSpaceVelocity.angularMotion.x * time_slice);
new_rotation.roll = -tiltAngle;
new_rotation.pitch = pitchAngle;
//
//----------------------------------------------
// Adjust position from network
//----------------------------------------------
//
YawPitchRoll correction_angle;
Point3D correction_position;
GetNetworkAdjustment(time_slice, correction_position, correction_angle);
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;
//
//----------------------------------------------
// Set the new position
//----------------------------------------------
//
// worldSpaceVelocity.linearMotion.Multiply(localSpaceVelocity.linearMotion,GetLocalToWorld());
LinearMatrix4D new_local_to_world = LinearMatrix4D::Identity;
new_local_to_world.BuildTranslation(new_translation);
new_local_to_world.BuildRotation(new_rotation);
SetNewLocalToParent(new_local_to_world);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Airplane::Land(void)
{
Check_Object(this);
}
void
Airplane::TakeOff(Stuff::Scalar runway_distance)
{
Check_Object(this);
Check_Object(executionState);
Check_Object(animStateEngine);
executionState->RequestState(ExecutionStateEngine::TakingOffMotionState);
m_OnGround = false;
if (hasTakeOffAnimationLoaded)
animStateEngine->RequestState(AirplaneAnimationStateEngine::TakeOffState);
}
void
Airplane::Popup(Stuff::Scalar to_height)
{
Check_Object(this);
Check_Object(executionState);
Check_Object(animStateEngine);
if (executionState->GetState() == Airplane::ExecutionStateEngine::PopupState)
{
return;
}
m_PopdownHeight = ((Stuff::Point3D)GetLocalToWorld()).y;
m_PopupHeight = to_height;
m_PopupClimbSpeed = 0;
m_YPR = GetLocalToWorld();
executionState->RequestState(ExecutionStateEngine::PopupState);
m_OnGround = false;
}
void
Airplane::Popdown(Stuff::Scalar to_height)
{
Check_Object(this);
Check_Object(executionState);
Check_Object(animStateEngine);
if (executionState->GetState() == Airplane::ExecutionStateEngine::PopdownState)
{
return;
}
m_PopupHeight = ((Stuff::Point3D)GetLocalToWorld()).y;
m_PopdownHeight = to_height;
m_PopupClimbSpeed = 0;
m_YPR = GetLocalToWorld();
executionState->RequestState(ExecutionStateEngine::PopdownState);
m_OnGround = false;
}
void
Airplane::Float(const Stuff::Point3D& dest)
{
Check_Object(this);
Check_Object(executionState);
Check_Object(animStateEngine);
if ((executionState->GetState() == Airplane::ExecutionStateEngine::FloatState) &&
(m_FloatTargetPosition == dest))
{
return;
}
m_YPR = GetLocalToWorld();
m_FloatSpeed = 0;
m_FloatTargetPosition = dest;
executionState->RequestState(ExecutionStateEngine::FloatState);
m_OnGround = false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Airplane::TakeOffThrusterSimulation(Stuff::Time till, const Stuff::Vector3D& new_velocity, const Stuff::Vector3D& instantanious_angular_velocity,bool canswitch)
{
Check_Object(this);
Scalar time_slice = GetTimeSlice(till);
if (canswitch)
{
executionState->RequestState(ExecutionStateEngine::FlyingMotionState);
}
//instantanious_angular_velocity.Divide(instantanious_angular_velocity, time_slice);
//
// get the local to world matrix from the locator
//
const Stuff::LinearMatrix4D &local_to_world = GetLocalToWorld();
//
// make a vector of where we want to go
//
Vector3D point = Point3D::Identity;
point.Multiply( new_velocity, time_slice );
//
// put it in local space
//
Vector3D adj;
adj.Multiply(point, local_to_world);
//
// add the local adjustment to the current position
//
Point3D new_translation;
new_translation = local_to_world;
new_translation += adj;
//
// get the current yawpitchroll from the local to world matrix
//
YawPitchRoll new_rotation(YawPitchRoll::Identity);
new_rotation = local_to_world;
//
// then add in the yaw, pitch, and roll demands from the animation
//
new_rotation.yaw += instantanious_angular_velocity.y * time_slice;
new_rotation.pitch += instantanious_angular_velocity.x * time_slice;
new_rotation.roll += instantanious_angular_velocity.z * time_slice;
//
// create a new matrix and build the translation and rotation
//
//
//----------------------------------------------
// Adjust position from network
//----------------------------------------------
//
YawPitchRoll correction_angle;
Point3D correction_position;
GetNetworkAdjustment(time_slice, correction_position, correction_angle);
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;
//
//----------------------------------------------
// Set the new position
//----------------------------------------------
//
LinearMatrix4D new_local_to_world;
new_local_to_world.BuildTranslation(new_translation);
new_local_to_world.BuildRotation(new_rotation);
//
// set the local to parent to the new matrix created above
//
SetNewLocalToParent(new_local_to_world);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Airplane::TakeOffMovementSimulation(Stuff::Time till)
{
Check_Object(this);
Scalar time_slice = GetTimeSlice(till);
Verify(time_slice > 0.0f);
const GameModel *model = GetGameModel();
Check_Object(model);
//
//-------------------------
// Compute the new location
//-------------------------
//
localSpaceVelocity.linearMotion.z += speedDemand * model->thrusterAcceleration * time_slice;
Clamp(localSpaceVelocity.linearMotion.z, 0.0f, GetMaxSpeed());
worldSpaceVelocity.linearMotion.Multiply(localSpaceVelocity.linearMotion, GetLocalToWorld());
Point3D plane_in_world(GetLocalToWorld());
plane_in_world.AddScaled(plane_in_world, worldSpaceVelocity.linearMotion, time_slice);
LinearMatrix4D local_to_new_world(true);
//
//-------------------------
// Compute the new rotation
//-------------------------
//
localSpaceVelocity.angularMotion.x = pitchDemand;
localSpaceVelocity.angularMotion.y = (yawDemand * model->fullStopTurnRate);
localSpaceVelocity.angularMotion.z = (rollDemand * model->fullStopTurnRate);
worldSpaceVelocity.angularMotion.Multiply(localSpaceVelocity.angularMotion, GetLocalToWorld());
//
//---------------------------------------------------
// Make a matrix representing the rotation this frame
//---------------------------------------------------
//
Vector3D world_angular_step;
world_angular_step.Multiply(worldSpaceVelocity.angularMotion, time_slice);
UnitQuaternion spin;
spin = world_angular_step;
//
//-------------------------------------------------------------------------
// Convert the EulerAngles into a matrix and create the new rotation matrix
// through concatenation
//-------------------------------------------------------------------------
//
UnitQuaternion old_world_rotation;
old_world_rotation = initialLocalToParent;
UnitQuaternion new_world_rotation;
new_world_rotation.Multiply(old_world_rotation, spin);
//
//----------------------------------------------
// Adjust position from network
//----------------------------------------------
//
YawPitchRoll correction_angle;
Point3D correction_position;
GetNetworkAdjustment(time_slice, correction_position, correction_angle);
YawPitchRoll new_rotation;
new_rotation = new_world_rotation;
plane_in_world += 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;
//
//----------------------------------------------
// Set the new position
//----------------------------------------------
//
local_to_new_world.BuildTranslation(plane_in_world);
local_to_new_world.BuildRotation(new_rotation);
SetNewLocalToParent(local_to_new_world);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Airplane::CrashingDeathMovementSimulation(Stuff::Time till)
{
Check_Object(this);
Scalar time_slice = GetTimeSlice(till);
Verify(time_slice > 0.0f);
Vector3D new_speed = localSpaceVelocity.linearMotion;
UnitVector3D world_down_in_local,world_forward_in_local;
Vector3D tempvec = Vector3D::Identity;
GetLocalToWorld().GetWorldDownInLocal(&world_down_in_local);
GetLocalToWorld().GetWorldForwardInLocal (&world_forward_in_local);
// new_speed.AddScaled (tempvec,world_forward_in_local,currentSpeedMPS*time_slice);
new_speed.AddScaled (new_speed,world_down_in_local,g_Gravity*time_slice);
// new_speed.y -= g_Gravity * time_slice;
// new_speed.z = Fabs(new_speed.z);
// localSpaceVelocity.linearMotion= new_speed;
worldSpaceVelocity.linearMotion.Multiply(new_speed, GetLocalToWorld());
const Stuff::LinearMatrix4D &local_to_world = GetLocalToWorld();
Vector3D rotation_vector;
rotation_vector.x = 1.0f;
rotation_vector.y = 0.0f;
rotation_vector.z = 0.0f;
localSpaceVelocity.angularMotion = rotation_vector;
worldSpaceVelocity.angularMotion.Multiply(rotation_vector, GetLocalToWorld());
Point3D new_translation;
Vector3D local_motion;
local_motion.Multiply(localSpaceVelocity.linearMotion, GetLocalToWorld());
new_translation = local_to_world;
new_translation.x += local_motion.x * time_slice;
new_translation.y += local_motion.y * time_slice;
new_translation.z += local_motion.z * time_slice;
//
// get the current yawpitchroll from the local to world matrix
//
YawPitchRoll new_rotation(YawPitchRoll::Identity);
new_rotation = local_to_world;
new_rotation.yaw += (localSpaceVelocity.angularMotion.y * time_slice);
new_rotation.pitch += (localSpaceVelocity.angularMotion.x * time_slice);
Max_Clamp(new_rotation.pitch, 1.0f);
new_rotation.roll += (localSpaceVelocity.angularMotion.z * time_slice);
LinearMatrix4D new_local_to_world=LinearMatrix4D::Identity;
//
//----------------------------------------------
// Adjust position from network
//----------------------------------------------
//
YawPitchRoll correction_angle;
Point3D correction_position;
GetNetworkAdjustment(time_slice, correction_position, correction_angle);
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_local_to_world.BuildTranslation(new_translation);
new_local_to_world.BuildRotation(new_rotation);
Stuff::Line3D line;
UnitVector3D forward;
new_local_to_world.GetLocalForwardInWorld(&forward);
line.m_length = 3.5f;
line.m_direction = forward;
Point3D old_translation(GetLocalToWorld());
line.m_origin = old_translation;
SetNewLocalToParent(new_local_to_world);
//
// Prepare query
//
Stuff::Normal3D normal;
CollisionQuery query(&line, &normal, CanBeWalkedOnFlag, this);
//
// Cast ray
//
Adept::Entity *entity_hit;
Check_Object(CollisionGrid::Instance);
entity_hit = CollisionGrid::Instance->ProjectLine(&query);
if(entity_hit != NULL)
{
shouldDie = true;
shouldLeaveReckage = true;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Stuff::Point3D&
Airplane::EstimateFuturePosition(
Stuff::Point3D *new_position,
Stuff::Scalar seconds,
bool consider_terrain
)
{
Check_Object(this);
Check_Pointer(new_position);
//
//-------------------------------------------------
// If we aren't moving, return our current position
//-------------------------------------------------
//
*new_position = GetLocalToWorld();
if ((Small_Enough(currentSpeedMPS)) || (IsDestroyed() == true))
return *new_position;
//
//--------------------------
// Project our forward speed
//--------------------------
//
Stuff::UnitVector3D local_forward;
GetLocalToWorld().GetLocalForwardInWorld(&local_forward);
new_position->AddScaled(*new_position, local_forward, seconds * currentSpeedMPS);
//
//-------------------------------------------------------------
// Assume that we swerve left at 1 mps at full stick deflection
//
// NOTE: This looks like doo-doo too
//-------------------------------------------------------------
//
Stuff::UnitVector3D local_left;
GetLocalToWorld().GetLocalLeftInWorld(&local_left);
new_position->AddScaled(*new_position, local_left, seconds * yawDemand);
return *new_position;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Airplane::LandingMovementSimulation(Stuff::Time till)
{
Check_Object(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Airplane::TiltPlane(Stuff::Scalar time_slice)
{
const GameModel *model = GetGameModel();
Scalar max_turn_band = model->fullStopTurnRate;
Scalar min_turn_band = max_turn_band * model->percentageOfTurnToStartTilt;
Scalar max_speed_band = GetMaxSpeed();
Scalar min_speed_band = max_speed_band * model->percentageOfSpeedToStartTilt;
tiltRequest = 0.0f;
Scalar speed_ratio = 0.0f;
Scalar turn_ratio = 0.0f;
if (yawDemand*model->fullStopTurnRate > min_turn_band || yawDemand*model->fullStopTurnRate < -min_turn_band)
{
if (currentSpeedMPS > min_speed_band)
{
speed_ratio = (currentSpeedMPS - min_speed_band)/(max_speed_band - min_speed_band);
Max_Clamp(speed_ratio, 1.0f);
if (yawDemand > 0)
{
turn_ratio = (yawDemand*model->fullStopTurnRate - min_turn_band)/(max_turn_band - min_turn_band);
Max_Clamp(turn_ratio, 1.0f);
}
else
{
turn_ratio = -(-yawDemand*model->fullStopTurnRate - min_turn_band)/(max_turn_band - min_turn_band);
Min_Clamp(turn_ratio, -1.0f);
}
tiltRequest = model->tiltDegree * turn_ratio * speed_ratio;
}
}
if (tiltAngle < tiltRequest)
{
tiltAngle += (model->tiltSpeed*time_slice);
Max_Clamp(tiltAngle, tiltRequest);
}
else if (tiltAngle > tiltRequest)
{
tiltAngle -= (model->tiltSpeed*time_slice);
Min_Clamp(tiltAngle, tiltRequest);
}
Scalar max_pitch_speed_band = GetMaxSpeed();
Scalar min_pitch_speed_band = max_pitch_speed_band * model->percentageOfSpeedToStartPitch;
pitchRequest = 0.0f;
Scalar pitch_speed_ratio = 0.0f;
if (currentSpeedMPS > min_speed_band)
{
pitch_speed_ratio = (currentSpeedMPS - min_pitch_speed_band)/(max_pitch_speed_band - min_pitch_speed_band);
Max_Clamp(pitch_speed_ratio, 1.0f);
pitchRequest = model->pitchDegree * pitch_speed_ratio;
}
if (pitchAngle < pitchRequest)
{
pitchAngle += (model->pitchSpeed*time_slice);
Max_Clamp(pitchAngle, pitchRequest);
}
else if (pitchAngle > pitchRequest)
{
pitchAngle -= (model->pitchSpeed*time_slice);
Min_Clamp(pitchAngle, pitchRequest);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Airplane::ReactToDestruction(int damage_mode, int damage_type)
{
// if (!IsDestroyed())
// {
// Check_Object(executionState);
// }
switch(damage_mode)
{
case InternalDamageObject::DestructionDamageMode:
{
if((!IsDestroyed()) && (executionState->GetState() != ExecutionStateEngine::CrashingDeathState))
{
Check_Object(executionState);
executionState->RequestState(ExecutionStateEngine::CrashingDeathState);
if(m_AI)
{
Check_Object(m_AI);
m_AI->Die();
}
const GameModel *model = GetGameModel();
Check_Object(model);
Effect *effect;
effect = CreateEffect(model->destroyedEffectResource, this, true);
if(effect)
m_crashingEffect.Add(effect);
// DestroyChildren();
// Entity::ReactToDestruction(damage_mode, damage_type);
break;
}
}
}
#ifdef LAB_ONLY
if (MW4AI::Statistics::Enabled() == true)
{
MW4AI::Statistics::NotifyDestroyed(objectID);
}
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Airplane::TestInstance() const
{
Verify(IsDerivedFrom(DefaultData));
}
void Airplane::AdjustAltitude (void)
{
if (flyingAltitude < MW4AI::g_MaxBuildingHeight)
{
flyingAltitude = MW4AI::g_MaxBuildingHeight+10;
}
Max_Clamp (flyingAltitude,800);
#if 0
stlport::vector<Scalar>::iterator iter;
Scalar min,max;
bool flag;
min = MW4AI::g_MaxBuildingHeight;
max = min;
flag = false;
for (iter = m_Heights->begin ();iter != m_Heights->end ();iter++)
{
if (*iter < min)
min = *iter;
if (*iter > max)
max = *iter;
if (!flag)
{
if (((flyingAltitude+PlaneHeightSlotSize) > *iter) && ((flyingAltitude-PlaneHeightSlotSize) < *iter))
{
flag = true;
}
}
}
flyingAltitude = max + PlaneHeightSlotSize;
m_Heights->push_back (flyingAltitude);
#endif
}
void
Airplane::PopUpOrDownSimulation(Stuff::Scalar time_slice, Stuff::Scalar height)
{
//
//-------------------------
// Determine our current position
//-------------------------
//
Stuff::Point3D my_pos(GetLocalToWorld());
//
//-------------------------
// Figure out whether we want to move up or down
//-------------------------
//
Stuff::Scalar vertical_velocity(0);
if (height > my_pos.y)
{
vertical_velocity = GetGameModel()->maxClimb;
}
else
{
vertical_velocity = -(GetGameModel()->maxDescent);
}
//
//-------------------------
// Set the current fall/climb speed, using acceleration when we start moving and a scaled difference when we're near the destination height
//-------------------------
//
if (Stuff::Fabs(my_pos.y - height) < 8.0f)
{
m_PopupClimbSpeed = (vertical_velocity * (Stuff::Fabs(my_pos.y - height) / 8.0f));
}
else
{
m_PopupClimbSpeed += vertical_velocity * time_slice * 0.4f /* magic number to make it accelerate slowly */;
}
Clamp(m_PopupClimbSpeed,-(GetGameModel()->maxDescent),GetGameModel()->maxClimb);
//
//-------------------------
// Compute the new location
//-------------------------
//
localSpaceVelocity.linearMotion.x = 0;
localSpaceVelocity.linearMotion.y = m_PopupClimbSpeed;
localSpaceVelocity.linearMotion.z = 0;
worldSpaceVelocity.linearMotion.Multiply(localSpaceVelocity.linearMotion,GetLocalToWorld());
Stuff::LinearMatrix4D new_local_to_parent(GetLocalToWorld());
my_pos.AddScaled(my_pos,worldSpaceVelocity.linearMotion,time_slice);
m_YPR.yaw += yawDemand * time_slice;
m_YPR.pitch += pitchDemand * GetGameModel()->fullStopTurnRate * time_slice;
m_YPR.roll += rollDemand * GetGameModel()->fullStopTurnRate * time_slice;
Clamp(m_YPR.pitch,-0.35f,0.35f);
//
//----------------------------------------------
// Adjust position from network
//----------------------------------------------
//
YawPitchRoll correction_angle;
Point3D correction_position;
GetNetworkAdjustment(time_slice, correction_position, correction_angle);
my_pos += correction_position;
m_YPR.yaw.angle += correction_angle.yaw.angle;
m_YPR.pitch.angle += correction_angle.pitch.angle;
m_YPR.roll.angle += correction_angle.roll.angle;
//
//-------------------------------------------------------------------------
// Plug it all into the matrix and make it happen
//-------------------------------------------------------------------------
//
new_local_to_parent.BuildTranslation(my_pos);
new_local_to_parent.BuildRotation(m_YPR);
SetNewLocalToParent(new_local_to_parent);
}
void
Airplane::FloatSimulation(Stuff::Scalar time_slice)
{
//
//-------------------------
// Determine our current position
//-------------------------
//
Stuff::Point3D my_pos(GetLocalToWorld());
//
//-------------------------
// Determine the delta to where we want to be
//-------------------------
//
Stuff::Scalar height = GetHeightAtPoint(m_FloatTargetPosition,this);
if (height == -100000.0f)
{
height = my_pos.y;
}
else
{
height += flyingAltitude;
}
Stuff::Point3D delta;
delta.Subtract(m_FloatTargetPosition,my_pos);
delta.y = height - my_pos.y;
//
//-------------------------
// Determine our velocity
//-------------------------
//
const Stuff::Scalar max_throttle_multiplier(0.8f);
const Stuff::Scalar distance_to_slow_down(25.0f);
if (delta.GetApproximateLength() < distance_to_slow_down)
{
m_FloatSpeed = GetMaxSpeed() * max_throttle_multiplier * (delta.GetApproximateLength() / distance_to_slow_down);
if (m_YPR.roll < 0)
{
rollDemand = -(m_YPR.roll);
}
else
{
rollDemand = m_YPR.roll;
}
}
else
{
m_FloatSpeed += GetGameModel()->acceleration * time_slice;
Clamp(m_FloatSpeed,0,GetMaxSpeed() * max_throttle_multiplier);
if (YawToPoint(GetLocalToWorld(),m_FloatTargetPosition) < 0)
{
if (m_YPR.roll < 0.2f)
{
rollDemand = 0.5f;
}
else
{
rollDemand = -0.1f;
}
}
else
{
if (m_YPR.roll > -0.2f)
{
rollDemand = -0.5f;
}
else
{
rollDemand = 0.1f;
}
}
}
if (Small_Enough(delta.GetLengthSquared()) == true)
{
return;
}
//
//-------------------------
// Multiply the delta
//-------------------------
//
delta.Normalize(delta);
delta *= m_FloatSpeed;
//
//-------------------------
// Compute the new location
//-------------------------
//
worldSpaceVelocity.linearMotion = delta;
localSpaceVelocity.linearMotion.MultiplyByInverse(worldSpaceVelocity.linearMotion,GetLocalToWorld());
Stuff::LinearMatrix4D new_local_to_parent(GetLocalToWorld());
my_pos.AddScaled(my_pos,worldSpaceVelocity.linearMotion,time_slice);
m_YPR.yaw += yawDemand * time_slice;
m_YPR.pitch += pitchDemand * GetGameModel()->fullStopTurnRate * time_slice;
m_YPR.roll += rollDemand * GetGameModel()->fullStopTurnRate * time_slice;
Clamp(m_YPR.roll,-0.2f,0.2f);
Clamp(m_YPR.pitch,-0.35f,0.35f);
//
//----------------------------------------------
// Adjust position from network
//----------------------------------------------
//
YawPitchRoll correction_angle;
Point3D correction_position;
GetNetworkAdjustment(time_slice, correction_position, correction_angle);
my_pos += correction_position;
m_YPR.yaw.angle += correction_angle.yaw.angle;
m_YPR.pitch.angle += correction_angle.pitch.angle;
m_YPR.roll.angle += correction_angle.roll.angle;
Stuff::Point3D p = my_pos;
p.x += 10;
p.z += 10;
Stuff::Scalar y_1(FindTerrainHeightFromPoint(p,this));
p.x -= 20;
p.z -= 20;
Stuff::Scalar y_2(FindTerrainHeightFromPoint(p,this));
Stuff::Scalar y_delta = (flyingAltitude + ((y_1 + y_2) * 0.5f)) - my_pos.y;
Stuff::Scalar change = 0;
const GameModel *model = GetGameModel();
if (y_delta > 0)
change = model->maxClimb * time_slice;
else
change = model->maxDescent * time_slice;
Clamp(y_delta,-change,change);
my_pos.y += y_delta;
//
//-------------------------------------------------------------------------
// Plug it all into the matrix and make it happen
//-------------------------------------------------------------------------
//
new_local_to_parent.BuildTranslation(my_pos);
new_local_to_parent.BuildRotation(m_YPR);
SetNewLocalToParent(new_local_to_parent);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void Airplane::GetNetworkPosition(Stuff::Point3D &current_position, Stuff::YawPitchRoll &current_rotation)
{
int pre_state = executionState->GetState();
switch(pre_state)
{
case ExecutionStateEngine::PopupState:
case ExecutionStateEngine::PopdownState:
case ExecutionStateEngine::FloatState:
current_position = GetLocalToWorld();
current_rotation = m_YPR;
break;
default:
current_position = GetLocalToWorld();
current_rotation = GetLocalToWorld();
break;
}
}