//===========================================================================// // 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 #include #include #include #include #include #include stlport::vector *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; 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 *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; iGetLength(); ++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::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 ¤t_position, Stuff::YawPitchRoll ¤t_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; } }