#include "MW4Headers.hpp" #include "Helicopter.hpp" #include #include #include //############################################################################# //############################### 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)); }