//===========================================================================// // File: Subsystem.cpp //---------------------------------------------------------------------------// // Date Who Modification // // -------- --- ---------------------------------------------------------- // // 09/09/98 JSE Inital base class based off of Shadowrun/Adept //---------------------------------------------------------------------------// // Copyright (C) 1998, Fasa Interactive // // All Rights reserved worldwide // // This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL // //===========================================================================// #include "MW4Headers.hpp" #include "Subsystem.hpp" #include "MWDamageObject.hpp" #include "Vehicle.hpp" #include "SubsystemClassData.hpp" #include "VehicleInterface.hpp" #include //############################################################################# //########################## ExecutionStateEngine ####################### //############################################################################# Subsystem::ExecutionStateEngine::ClassData* Subsystem::ExecutionStateEngine::DefaultData = NULL; const StateEngine::StateEntry Subsystem::ExecutionStateEngine::StateEntries[]= { STATE_ENTRY(Subsystem__ExecutionStateEngine, Damaged), STATE_ENTRY(Subsystem__ExecutionStateEngine, Destroyed) }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Subsystem::ExecutionStateEngine::InitializeClass() { Check_Object(StateEngine::DefaultData); Verify(!DefaultData); DefaultData = new ClassData( Subsystem__ExecutionStateEngineClassID, "Subsystem::ExecutionStateEngine", Entity::ExecutionStateEngine::DefaultData, ELEMENTS(StateEntries), StateEntries, (Entity::ExecutionStateEngine::Factory)Make, (Entity::ExecutionStateEngine::FactoryRequest::Factory) &FactoryRequest::ConstructFactoryRequest ); Register_Object(DefaultData); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Subsystem::ExecutionStateEngine::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Subsystem::ExecutionStateEngine* Subsystem::ExecutionStateEngine::Make( Subsystem *subsystem, FactoryRequest *request ) { Check_Object(subsystem); Check_Object(request); gos_PushCurrentHeap(Heap); Subsystem::ExecutionStateEngine *engine = new Subsystem::ExecutionStateEngine(DefaultData, subsystem, request); gos_PopCurrentHeap(); return engine; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int Subsystem::ExecutionStateEngine::RequestState( int new_state, void* data ) { Check_Object(this); Check_Object(owningEntity); // //------------------------------ // Quick exit if no state change //------------------------------ // if (new_state == currentState) return currentState; // //------------------------------------------------------------------- // Once destroyed, always destroyed until we tell it to never execute //------------------------------------------------------------------- // if (currentState == DestroyedState && new_state != NeverExecuteState) return currentState; // //--------------------------------------------------------------------- // State engine is being called directly here because we don't want the // automatic execute/not-execute functionality in entity to operate. // What we want is for destroyed state to destroy the subsystem, never // execute state to turn it off, and anything else to turn it on //--------------------------------------------------------------------- // Subsystem *subsystem; subsystem = Cast_Object(Subsystem *, owningEntity); switch (BaseClass::BaseClass::RequestState(new_state, data)) { case DestroyedState: subsystem->DestroySubsystem(); break; case NeverExecuteState: if (oldState != NeverExecuteState) owningEntity->EnterNeverExecuteState(); break; default: if (oldState == NeverExecuteState) owningEntity->LeaveNeverExecuteState(); break; } return currentState; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Subsystem::ExecutionStateEngine::TestInstance() const { Verify(IsDerivedFrom(DefaultData)); } //############################################################################# //############################### Subsystem ############################## //############################################################################# Subsystem::ClassData* Subsystem::DefaultData = NULL; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Subsystem::InitializeClass() { Verify(!DefaultData); DefaultData = new ClassData( SubsystemClassID, "MechWarrior4::Subsystem", Entity::DefaultData, 0, NULL, (Entity::Factory)Make, (Entity::CreateMessage::Factory)CreateMessage::ConstructCreateMessage, ExecutionStateEngine::DefaultData, (Entity::GameModel::Factory)GameModel::ConstructGameModel, NULL, (Entity::GameModel::ReadAndVerifier)GameModel::ReadAndVerify, (Entity::GameModel::ModelWrite)GameModel::WriteToText, (Entity::GameModel::ModelSave)GameModel::SaveGameModel, (Subsystem::StreamCreate)CreateStream ); Register_Object(DefaultData); CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE( Subsystem__GameModel, TotalSlotsTaken, totalSlotsTaken, int, IntClassID ); DIRECT_GAME_MODEL_ATTRIBUTE( Subsystem__GameModel, Tonage, tonage, Scalar ); CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE( Subsystem__GameModel, BattleValue, battleValue, int, IntClassID ); CUSTOM_DIRECT_GAME_MODEL_ATTRIBUTE( Subsystem__GameModel, ItemID, itemID, int, IntClassID ); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Subsystem::TerminateClass() { Unregister_Object(DefaultData); delete DefaultData; DefaultData = NULL; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Subsystem* Subsystem::Make( CreateMessage *message, ReplicatorID *base_id ) { Check_Object(message); gos_PushCurrentHeap(Heap); Subsystem *new_entity = new Subsystem(DefaultData, message, base_id, NULL); gos_PopCurrentHeap(); Check_Object(new_entity); return new_entity; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Replicator::CreateMessage* Subsystem::SaveMakeMessage(MemoryStream *stream, ResourceFile *res_file) { Check_Object(this); Check_Object(stream); stream->AllocateBytes(sizeof(CreateMessage)); Entity::SaveMakeMessage(stream, res_file); CreateMessage *message = Cast_Pointer(CreateMessage*, stream->GetPointer()); message->messageLength = sizeof(*message); message->subsystemIndex = subsystemIndex; message->locationID = internalLocation; message->criticalHitsTaken = critHitsTaken; return message; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Subsystem::Subsystem( ClassData *class_data, CreateMessage *message, ReplicatorID *base_id, ElementRenderer::Element *element ): Entity(class_data, message, base_id, element) { Check_Pointer(this); Check_Object(message); subsystemIndex = message->subsystemIndex; internalLocation = (char)message->locationID; critHitsTaken = message->criticalHitsTaken; parentAsVehicle = NULL; containedInSlotType = -1; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // MWObject* Subsystem::GetParentVehicle() { Check_Object(GetParentEntity()); Verify(GetParentEntity()->IsDerivedFrom(MWObject::DefaultData)); return (MWObject *)GetParentEntity(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Vehicle* Subsystem::GetParentAsVehicle() { return parentAsVehicle; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Subsystem::~Subsystem() { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Subsystem::Reuse( const CreateMessage *message, ReplicatorID *base_id ) { Check_Object(this); STOP(("Not implemented")); Entity::Reuse(message, base_id); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // //Must call this virtual function in the inherited method!!!! bool Subsystem::ConnectSubsystem() { Check_Object(this); MWInternalDamageObject *internal_structure; const GameModel *model = GetGameModel(); Check_Object(model); MWObject *parent_vehicle; parent_vehicle = GetParentVehicle(); Check_Object(parent_vehicle); int old_level = Stuff::ArmorLevel; if (Stuff::ArmorLevel == 4) Stuff::ArmorLevel = 3; if(parent_vehicle->IsDerivedFrom(Vehicle::DefaultData)) parentAsVehicle = Cast_Object(Vehicle *, parent_vehicle); // cant call cast object due to armor level four // we are in parent_vehicles contructor // if we call that dynamic cast will fail Stuff::ArmorLevel = old_level; internal_structure = parent_vehicle->internalDamageObjects.Find(internalLocation); if (internal_structure != 0) { Check_Object(internal_structure); if(parent_vehicle->DoesHaveAvailableTonage(model->tonage)) { if(internal_structure->AddSubsystem(this)) { parent_vehicle->AddTonage(model->tonage); parent_vehicle->AddBattleValue(model->battleValue); return true; } } } return false; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Subsystem::Respawn(Entity::CreateMessage *message) { Check_Object(this); Check_Object(message); Entity::Respawn(message); //If we were destroyed then we must re add ourselves! MWObject *parent_vehicle; parent_vehicle = GetParentVehicle(); Check_Object(parent_vehicle); MWInternalDamageObject *internal_structure; internal_structure = parent_vehicle->internalDamageObjects.Find(internalLocation); Check_Object(internal_structure); if(!internal_structure->subsystemChain.IsPlugMember(this)) { internal_structure->subsystemChain.Add(this); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // bool Subsystem::DisconnectSubsystem() { Check_Object(this); MWObject *parent_vehicle; parent_vehicle = GetParentVehicle(); Check_Object(parent_vehicle); const GameModel *model = GetGameModel(); Check_Object(model); parent_vehicle->SubtractTonage(model->tonage); parent_vehicle->AddBattleValue(-model->battleValue); MWInternalDamageObject *zone = parent_vehicle->internalDamageObjects.Find(internalLocation); if(zone) { zone->FreeAvailableSlots(containedInSlotType, model->totalSlotsTaken); } return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool Subsystem::TakeCriticalHit() { Check_Object(this); Check_Object(executionState); executionState->RequestState(ExecutionStateEngine::DestroyedState); return true; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Subsystem::DestroySubsystem() { Check_Object(this); MWObject *parent_vehicle; parent_vehicle = GetParentVehicle(); Check_Object(parent_vehicle); const GameModel *model = GetGameModel(); Check_Object(model); parent_vehicle->SubtractTonage(model->tonage); parent_vehicle->SubtractBattleValue(model->battleValue); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Subsystem::BecomeInteresting(bool render_me) { Check_Object(this); LOAD_LOGIC("Become Interesting::Subsystem"); BaseClass::BecomeInteresting(render_me); ElementRenderer::Element *element = GetElement(); Check_Object(element); element->SetAlwaysCullMode(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Subsystem::CreateStream(ResourceID data_list, MemoryStream *stream) { Check_Pointer(stream); stream->AllocateBytes(sizeof(Subsystem__CreateMessage)); Subsystem__CreateMessage *create_message = Cast_Pointer( Subsystem__CreateMessage *, stream->GetPointer()); create_message->alignment = Entity::DefaultAlignment; create_message->initialAge = 0.0f; create_message->replicatorFlags = 0; create_message->dataListID = data_list; create_message->classID = GetClassIDFromDataListID(data_list); create_message->localToParent = LinearMatrix4D::Identity; create_message->executionState.currentState = ExecutionStateEngine::NeverExecuteState; create_message->nameID = NameTable::NullObjectID; create_message->replicatorID.connectionID = 0; create_message->replicatorID.localID = 1; create_message->subsystemIndex = 0; create_message->criticalHitsTaken = 0; //This should be updated elsewhere. create_message->locationID = 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Subsystem::TestInstance() const { Verify(IsDerivedFrom(DefaultData)); }