#include "MW4Headers.hpp" #include "MFB.hpp" #include "gameinfo.hpp" #include "Mech.hpp" #include "Weapon.hpp" #include "MWDamageObject.hpp" #include "CombatAI.hpp" #include "HeatManager.hpp" #include #include #include //############################################################################# //############################### MFB ################################### //############################################################################# const StateEngine::StateEntry MFB::ExecutionStateEngine::StateEntries[]= { STATE_ENTRY(MFB__ExecutionStateEngine, Repair), STATE_ENTRY(MFB__ExecutionStateEngine, OpeningMotion) }; MFB::ExecutionStateEngine::ClassData* MFB::ExecutionStateEngine::DefaultData = NULL; ChainOf *MFB::s_MFBs = NULL; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::ExecutionStateEngine::InitializeClass() { Check_Object(BaseClass::DefaultData); Verify(!DefaultData); DefaultData = new ClassData( MFB__ExecutionStateEngineClassID, "MFB::ExecutionStateEngine", BaseClass::DefaultData, ELEMENTS(StateEntries), StateEntries, (Entity::ExecutionStateEngine::Factory)Make, (Entity::ExecutionStateEngine::FactoryRequest::Factory) &FactoryRequest::ConstructFactoryRequest ); Register_Object(DefaultData); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::ExecutionStateEngine::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MFB::ExecutionStateEngine* MFB::ExecutionStateEngine::Make( MFB *vehicle, FactoryRequest *request ) { Check_Object(vehicle); Check_Object(request); gos_PushCurrentHeap(Heap); MFB::ExecutionStateEngine *engine = new MFB::ExecutionStateEngine(DefaultData, vehicle, request); gos_PopCurrentHeap(); return engine; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int MFB::ExecutionStateEngine::RequestState( int new_state, void* data ) { Check_Object(this); Check_Object(owningEntity); // //------------------------------------------- // If there is no change of state just return //------------------------------------------- // if (new_state == currentState) return currentState; #if 0 MFB *mfb = Cast_Object(MFB*, owningEntity); Check_Object(mfb); #endif switch (BaseClass::RequestState(new_state, data)) { case OpeningMotionState: // mfb->animStateEngine->RequestState(MechAnimationStateEngine::OpeningState); break; } return currentState; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::ExecutionStateEngine::TestInstance() const { Verify(IsDerivedFrom(DefaultData)); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MFB::ClassData* MFB::DefaultData = NULL; DWORD MechWarrior4::Executed_MFB_Count = 0; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::InitializeClass() { Check_Object(MWMover::ExecutionStateEngine::DefaultData); Verify(!DefaultData); DefaultData = new ClassData( MFBClassID, "MechWarrior4::MFB", BaseClass::DefaultData, 0, 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); DIRECT_GAME_MODEL_ATTRIBUTE( MFB__GameModel, RepairEffectResource, m_repairEffectResource, ResourceID ); DIRECT_GAME_MODEL_ATTRIBUTE( MFB__GameModel, RepairCenterOffset, m_repairCenterOffset, Stuff::Vector3D ); DIRECT_GAME_MODEL_ATTRIBUTE( MFB__GameModel, RepairDistance, m_repairDistance, Stuff::Scalar ); s_MFBs = new ChainOf(NULL); Check_Pointer(s_MFBs); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; s_MFBs->DeletePlugs(); delete s_MFBs; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MFB* MFB::Make( CreateMessage *message, ReplicatorID *base_id ) { Check_Object(message); gos_PushCurrentHeap(Heap); MFB *new_entity = new MFB(DefaultData, message, base_id, NULL); gos_PopCurrentHeap(); Check_Object(new_entity); Check_Object(EntityManager::GetInstance()); EntityManager::GetInstance()->AddMover(new_entity); return new_entity; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MFB::MFB( ClassData *class_data, CreateMessage *message, ReplicatorID *base_id, ElementRenderer::Element *element ): Vehicle(class_data, message, base_id, element), m_repairEffect(NULL), m_repairingMech(NULL) { Check_Pointer(this); Check_Object(message); HookUpSubsystems(); CommonCreation(message); s_MFBs->Add(this); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MFB::~MFB() { if(m_weaponIterator) { delete m_weaponIterator; } if(m_internalIterator) { delete m_internalIterator; } if(m_armorIterator) { delete m_armorIterator; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::Reuse( const CreateMessage *message, ReplicatorID *base_id ) { Check_Object(this); Check_Object(message); STOP(("Not implemented")); BaseClass::Reuse(message, base_id); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::CommonCreation(CreateMessage *message) { Check_Object(this); Check_Object(message); //m_RepairDistance = 18.0f; m_CurrentMechUsing = NULL; m_currentState = FixingGimpState; m_nextRepairTime = gos_GetElapsedTime(); m_weaponIterator = NULL; m_internalIterator = NULL; m_armorIterator = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::Respawn(Entity::CreateMessage *message) { Check_Object(this); Check_Object(message); BaseClass::Respawn(message); CreateMessage *vehicle_message = Cast_Pointer(CreateMessage *, message); CommonCreation(vehicle_message); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::TurnOn (void) { lastParameterization = gos_GetElapsedTime (); executionState->RequestState(ExecutionStateEngine::DrivingMotionState); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::PreCollisionExecute(Time till) { Check_Object(this); PRECOLLISION_LOGIC("MFB"); #if defined(LAB_ONLY) if (!instanceName) MWGameInfo::g_LastVehicle[0] = '\0'; else { strncpy(MWGameInfo::g_LastVehicle, instanceName, sizeof(MWGameInfo::g_LastVehicle)-1); MWGameInfo::g_LastVehicle[sizeof(MWGameInfo::g_LastVehicle)-1] = '\0'; } MWGameInfo::g_LastVehiclePos = GetLocalToWorld (); #endif // //------------------------------------------------------------- // Let the base class deal with setting up the motion variables //------------------------------------------------------------- // BaseClass::PreCollisionExecute(till); Set_Statistic(Executed_MFB_Count, Executed_MFB_Count+1); // //---------------------------------------------------------------------- // Any executing vehicle should not be in never execute state and should // always use post collision //---------------------------------------------------------------------- // Check_Object(executionState); int pre_state = executionState->GetState(); Verify(pre_state != ExecutionStateEngine::NeverExecuteState); // //------------------------------------------------------------------------- // Do the appropriate type of simulation. Animated motion state is for BRB //------------------------------------------------------------------------- // Scalar time_slice = GetTimeSlice(till); switch (pre_state) { // //---------------------------------------------------- // Always execute state is for the normal driving code //---------------------------------------------------- // case ExecutionStateEngine::DrivingMotionState: // ComputeForwardSpeed(time_slice); // UpdateVehiclePosition(time_slice); break; // //----------------------------------------------------------- //We need to repair now...some mech powered down inside of us //----------------------------------------------------------- // case ExecutionStateEngine::RepairState: if(gos_GetElapsedTime() > m_nextRepairTime) RepairTargetMech(time_slice); break; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::PostCollisionExecute(Time till) { Check_Object(this); Check_Object(executionState); POSTCOLLISION_LOGIC("MFB"); switch(executionState->GetState()) { case ExecutionStateEngine::RepairState: CreateRepairEffect(); break; } BaseClass::PostCollisionExecute(till); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool MFB::CollisionHandler( Stuff::LinearMatrix4D *new_position, Stuff::DynamicArrayOf *collisions ) { Check_Object(this); Verify(GetInterestLevel() != DormantInterestLevel); Verify(EntityManager::GetInstance()->IsInPostCollisionExecution(this)); Verify(!newCollisions); delete collisions; return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::RepairTargetMech(Scalar time_slice) { Check_Object(this); Mech *mech = m_repairingMech.GetCurrent(); if(mech) { if (mech->vehicleInterface) { mech->vehicleInterface->ReactToEvent (VehicleInterface::MISSILE_LOCKLOST); } Check_Object(mech); if(!mech->vehicleShutDown) { ShutMFBDown(); return; } switch(m_currentState) { case FixingGimpState: { //First check to see if we fix gimp if(mech->IsGimped()) { mech->RepairGimp(); m_nextRepairTime = gos_GetElapsedTime() + 6.0f; m_currentState = ReloadingAmmoState; return; } } case ReloadingAmmoState: { Weapon *weapon; m_currentState = ReloadingAmmoState; while((weapon = m_weaponIterator->ReadAndNext()) != NULL) { Check_Object(weapon); if(weapon->HasFiredAmmo()) { weapon->Reload(); m_nextRepairTime = gos_GetElapsedTime() + 2.0f; return; } } } case ReloadingCoolantState: { m_currentState = ReloadingCoolantState; Check_Object(mech->m_heatManager); if(mech->m_heatManager->GetCoolant() < mech->m_heatManager->GetMaxCoolant()) { mech->m_heatManager->AddCoolant(mech->m_heatManager->GetMaxCoolant()); m_nextRepairTime = gos_GetElapsedTime() + 2.0f; return; } } case FixingInternalState: { MWInternalDamageObject *internal; m_currentState = FixingInternalState; while((internal = m_internalIterator->ReadAndNext()) != NULL) { Check_Object(internal); if(internal->CanRepair()) { internal->Reuse(); m_nextRepairTime = gos_GetElapsedTime() + 0.10f; return; } } } case FixingArmorState: { DamageObject *armor; m_currentState = FixingArmorState; while((armor = m_armorIterator->ReadAndNext()) != NULL) { Check_Object(armor); if(armor->CanRepair()) { armor->Reuse(); // MSL 5.05 Changed Repair time for external armor // m_nextRepairTime = gos_GetElapsedTime() + 0.10f; m_nextRepairTime = gos_GetElapsedTime() + 1.0f; return; } } } } mech->ShutDownRequest(false); if (mech->vehicleInterface) { mech->vehicleInterface->ReactToEvent (VehicleInterface::REPAIR_STOP); } ShutMFBDown(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::StartNewMech(Mech *new_mech) { Check_Object(this); Check_Object(new_mech); m_repairingMech.Remove(); m_repairingMech.Add(new_mech); m_currentState = FixingGimpState; if(m_weaponIterator) { delete m_weaponIterator; } m_weaponIterator = new WeaponIteratorType(&new_mech->weaponChain); if(m_internalIterator) { delete m_internalIterator; } m_internalIterator = new InternalIteratorType(&new_mech->internalDamageObjects); if(m_armorIterator) { delete m_armorIterator; } m_armorIterator = new ArmorIteratorType(&new_mech->damageObjects); Check_Object(executionState); executionState->RequestState(ExecutionStateEngine::RepairState); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::ShutMFBDown() { Check_Object(this); Check_Object(executionState); executionState->RequestState(ExecutionStateEngine::NeverExecuteState); if(m_repairEffect.GetCurrent()) { m_repairEffect.GetCurrent()->executionState->RequestState(Effect::ExecutionStateEngine::StoppingState); m_repairEffect.Remove(); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::CreateRepairEffect() { Check_Object(this); if(!m_repairEffect.GetCurrent()) { const GameModel *model = GetGameModel(); Check_Object(model); Effect *effect = CreateLoopingEffect(model->m_repairEffectResource, this); if(effect) m_repairEffect.Add(effect); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool MFB::IsWithin( Entity *target, Vector3D offset, Scalar distance, bool ignorey ) { Check_Object(this); Check_Object(target); Vector3D target_line = Vector3D::Identity; Point3D our_position; Point3D target_position; target_position = target->GetLocalToWorld(); our_position.Multiply(offset, GetLocalToWorld()); Point3D our_translation; our_translation = GetLocalToWorld(); our_position.Add(our_position, our_translation); if ((our_position.y < -1500) || (target_position.y < -1500)) // units in hell are never near each other return false; if (ignorey) { our_position.y = 0; target_position.y = 0; } target_line.Subtract(target_position, our_position); return target_line.GetLengthSquared() <= (distance * distance); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MFB* MFB::IsWithinMFB(Mech *mech) { Check_Object(mech); MFB *mfb; ChainIteratorOf iterator(s_MFBs); while((mfb = iterator.ReadAndNext()) != NULL) { Check_Object(mfb); //make sure the mfb is not destroyed and the mech is within 10.0 meters if(!mfb->IsDestroyed()) { if(mfb->IsWithin(mech, mfb->GetGameModel()->m_repairCenterOffset, mfb->GetGameModel()->m_repairDistance)) {//if(mech->IsWithin(mfb, mfb->GetGameModel()->m_repairDistance)) // MSL 5.03 Checks for Team Alignment // If your not the same alignment as the MFB you can't use it // MSL 5.05 Checks and allows for No Team if ((mfb->GetAlignment() == mech->GetAlignment()) || (mech->GetTeam() == MWApplication::No_Team)) { if (mech->vehicleInterface) { mech->vehicleInterface->ReactToEvent (VehicleInterface::REPAIR_START); } mfb->StartNewMech(mech); return mfb; } } } } return NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::ReactToDestruction(int damage_mode, int damage_type) { Check_Object(this); if(!IsDestroyed()) { if(m_AI) { Check_Object(m_AI); m_AI->Die(); } SetDestroyedFlag(damage_mode); if (damage_type != SplashDamageType) DealSplashDamage(); MW4AI::g_Rect4DHash->RemovePermRect (this); const GameModel *model = GetGameModel(); Check_Object(model); CreateEffect(model->destroyedEffectResource, (Point3D)GetLocalToWorld()); Entity *death_entity = CreateStaticHermitEntity(model->deathEntityResource); if((death_entity) && (!m_deathEntity.GetCurrent())) { m_deathEntity.Remove(); m_deathEntity.Add(death_entity); } RemoveFromExecution(); } Entity::ReactToDestruction(damage_mode, damage_type); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void MFB::TestInstance() const { Verify(IsDerivedFrom(DefaultData)); }