#include "rp.h" #pragma hdrstop #include "chute.h" #include "..\munga\fileutil.h" #include "vtv.h" #include "..\munga\app.h" #include "vtvmppr.h" //############################################################################# // Shared Data Support // Chute::SharedData Chute::DefaultData( Chute::GetClassDerivations(), Chute::MessageHandlers, Chute::GetAttributeIndex(), Chute::StateCount ); Derivation* Chute::GetClassDerivations() { static Derivation classDerivations(VTVSubsystem::GetClassDerivations(), "Chute"); return &classDerivations; } //############################################################################# // Messaging Support // const Receiver::HandlerEntry Chute::MessageHandlerEntries[]= { MESSAGE_ENTRY(Chute, Activate), MESSAGE_ENTRY(Chute, ConfigureMappables), MESSAGE_ENTRY(Chute, ChooseButton) }; Receiver::MessageHandlerSet Chute::MessageHandlers( ELEMENTS(Chute::MessageHandlerEntries), Chute::MessageHandlerEntries, VTVSubsystem::GetMessageHandlers() ); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Chute::ConfigureMappablesMessageHandler( ReceiverDataMessageOf *message ) { Check(this); Check(message); //--------------------------------------------------------------------- // If the hardwired button was pressed, process presses of the mappable // buttons, otherwise it was released, so erase any temporary mappings //--------------------------------------------------------------------- if (message->dataContents > 0) { EnterConfiguration( NULL, // direct target (none here) this, // receiver ActivateMessageID, // activation message ID ChooseButtonMessageID // configuration message ID ); } else { ExitConfiguration(); } Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Chute::ActivateMessageHandler( ReceiverDataMessageOf *message ) { Check(this); Check(message); VTV* vtv = GetEntity(); Check(vtv); Check(application); if ( vtv->GetSimulationState() == VTV::BurningState || application->GetApplicationState() != Application::RunningMission ) { Check_Fpu(); return; } if (message->dataContents > 0) { switch (GetSimulationState()) { case Ready: if (vtv->BoosterOn() || DeviantChute()) { Check_Fpu(); return; } if (chutesRemaining > 0) { SetSimulationState(Deploy); deployTimeUsed = 0.0f; chuteOn = 1; --chutesRemaining; ForceUpdate(); lastPerformance = Now(); AlwaysExecute(); Check_Fpu(); } break; case Dragging: ReleaseChute(); Check_Fpu(); break; } } Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Chute::ChooseButtonMessageHandler( ReceiverDataMessageOf *message ) { if (message->dataContents > 0) { // //--------------------------------------------------------------------- // Find the control manager of the vehicle, and have it turn off an // existing mapping of a given type if it is there, otherwise it should // create a new one //--------------------------------------------------------------------- // VTV* vtv = GetEntity(); Check(vtv); VTVControlsMapper* controls = Cast_Object( VTVControlsMapper*, vtv->GetSubsystem(VTV::ControlsMapperSubsystem) ); Check(controls); controls->AddOrErase(message->dataContents, this, ActivateMessageID); } Check_Fpu(); } //############################################################################# // Attribute Support // const Chute::IndexEntry Chute::AttributePointers[]= { ATTRIBUTE_ENTRY(Chute, TimeToReady, timeToReady), ATTRIBUTE_ENTRY(Chute, ChutesRemaining, chutesRemaining), ATTRIBUTE_ENTRY(Chute, ChuteDirection, chuteDirection), ATTRIBUTE_ENTRY(Chute, ScaleFactor, scaleFactor), ATTRIBUTE_ENTRY(Chute, ChuteOn, chuteOn), ATTRIBUTE_ENTRY(Chute, PercentDone, percentDone) }; Chute::AttributeIndexSet& Chute::GetAttributeIndex() { static Chute::AttributeIndexSet attributeIndex(ELEMENTS(Chute::AttributePointers), Chute::AttributePointers, VTVSubsystem::GetAttributeIndex()); return attributeIndex; } //############################################################################# // Model Support // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Chute::ReadUpdateRecord(Simulation::UpdateRecord *message) { Check(this); Check_Pointer(message); VTVSubsystem::ReadUpdateRecord(message); UpdateRecord* record = (UpdateRecord*) message; chuteDirection = record->chuteDirection; chuteOn = record->chuteOn; scaleFactor = record->scaleFactor; lastPerformance = lastUpdate; Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Chute::WriteUpdateRecord(Simulation::UpdateRecord *record, int update_model) { Check(this); Check_Pointer(record); VTVSubsystem::WriteUpdateRecord(record, update_model); UpdateRecord* update = (UpdateRecord*) record; update->recordLength = sizeof(*update); update->chuteDirection = chuteDirection; update->chuteOn = chuteOn; update->scaleFactor = scaleFactor; Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // static Vector3D forward(0.0f,0.0f,-1.0f); void Chute::ChuteSimulation(Scalar time_slice) { // //------------------------- // Apply the Chute //------------------------- // percentDone = percentDone = (reloadTime - timeToReady)/reloadTime; Check_Fpu(); if(percentDone > 1.0f) { percentDone = 1.0f; } if(percentDone < 0.0f) { percentDone = 0.0f; } Verify(percentDone >= 0.0f); Verify(percentDone <= 1.0f); int sim_state = GetSimulationState(); VTV *vtv = GetEntity(); Check(vtv); switch(sim_state) { case Loading: timeToReady -= time_slice; if (timeToReady <=0.0f) { SetSimulationState(Ready); NeverExecute(); } break; case Dragging: if (DeviantChute() || vtv->BoosterOn()) { ReleaseChute(); } else { ApplyDrag(time_slice); } break; case Deploy: if (DeviantChute() || vtv->BoosterOn()) { ReleaseChute(); } else { deployTimeUsed += time_slice; if (deployTimeUsed >= deployTime) { scaleFactor.x = 1.0f; scaleFactor.y = 1.0f; scaleFactor.z = 1.0f; SetSimulationState(Dragging); ForceUpdate(); } else { deployTimeUsed += time_slice; scaleFactor.y = scaleFactor.x = ScaleXY(); scaleFactor.z = ScaleZ(); deployTimeUsed += time_slice; } AlwaysExecute(); } ApplyDrag(time_slice); break; case Released: SetSimulationState(Loading); break; } Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Chute::PointChute(Scalar) { if (GetSimulationState() != Dragging || GetSimulationState() != Deploy) { Check_Fpu(); return; } VTV* vtv = GetEntity(); Check(vtv); if (!Small_Enough(vtv->localVelocity.linearMotion.LengthSquared())) { chuteDirection.Subtract(vtv->localVelocity.linearMotion, forward); } Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Scalar Chute::ScaleZ() { Scalar top_half = 2*(deployTimeUsed) -1 / (deployTimeUsed) + 1; Scalar bottom_half = 2*(deployTime) -1 / (deployTime) + 1; Scalar result = top_half/bottom_half; Check_Fpu(); return result; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Scalar Chute::ScaleXY() { Scalar top_half = (deployTimeUsed)*(deployTimeUsed)*(deployTimeUsed); Check_Fpu(); Scalar bottom_half = (deployTime)*(deployTime)*(deployTime); Check_Fpu(); Scalar result = top_half/bottom_half; Check_Fpu(); return result; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Chute::ReleaseChute() { SetSimulationState(Released); chuteOn = 0; ForceUpdate(); if (GetEntity()->GetInstance() == VTV::ReplicantInstance) { NeverExecute(); } Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Chute::ApplyDrag(Scalar) { // //-------------------------------------------------------------------------- // Get pointers to the other subsystems we will have to deal with inside the // VTV //-------------------------------------------------------------------------- // VTV* vtv = GetEntity(); // // If slow enough automatically release the chute // Scalar vel2 = vtv->localVelocity.linearMotion.LengthSquared(); if(vel2 < minVelocity) { ReleaseChute(); Check_Fpu(); return; } // // Calculate the direction to point the chute in // chuteDirection.Subtract(vtv->localVelocity.linearMotion, forward); // // Calculate the dragForce to Apply to the VTV // Vector3D force; force.Negate(vtv->localVelocity.linearMotion); force *= dragForce; vtv->ApplyLocalAcceleration(force, chuteOffset); Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int Chute::DeviantChute() { Check(this); VTV *vtv = GetEntity(); Check(vtv); Check_Fpu(); return vtv->localVelocity.linearMotion.z > zDeviation; } //############################################################################# // Damage Support // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Chute::DeathReset(int reset_command) { Check(this); if (reset_command == VTV::FootballReset) { chutesRemaining = chuteCount; } if (reset_command != VTV::MissionReviewReset) { SetSimulationState(Ready); timeToReady = 0.0f; } NeverExecute(); Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Chute::DeathShutdown(int) { chuteOn = False; chuteDirection = Quaternion::Identity; NeverExecute(); Check_Fpu(); } //############################################################################# // Contructor and Destructor // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Chute::Chute( VTV *entity, int subsystem_ID, SubsystemResource *subsystem_resource ): VTVSubsystem( entity, subsystem_ID, subsystem_resource, DefaultData, NULL, // assumes no direct controls mapping Chute::ActivateMessageID // message ID used for activation ), scaleFactor(0.0f,0.0f,0.0f) { //------------------------------------------- // Set values //------------------------------------------- chuteOn = 0; chuteCount = subsystem_resource->chuteCount; chutesRemaining = chuteCount; reloadTime = subsystem_resource->reloadTime; dragForce = subsystem_resource->dragForce; deployTime = subsystem_resource->deployTime; deployTimeUsed = 0.0f; EntitySegment *site_front_segment = entity->GetSegment(subsystem_resource->segmentIndex); chuteOffset = site_front_segment->GetSegmentToEntity(); minVelocity = subsystem_resource->minVelocity * subsystem_resource->minVelocity; zDeviation = subsystem_resource->zDeviation; timeToReady = 0.0f; chuteDirection = Quaternion::Identity; percentDone = 1.0f; SetSimulationState(Ready); SetPerformance(&Chute::ChuteSimulation); NeverExecute(); Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Chute::~Chute() { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical Chute::CreateStreamedSubsystem( NotationFile *model_file, const char *model_name, const char *subsystem_name, SubsystemResource *subsystem_resource, NotationFile *subsystem_file, const ResourceDirectories *directories ) { Check(model_file); Check_Pointer(subsystem_name); Check_Pointer(subsystem_resource); Check(subsystem_file); if ( !Subsystem::CreateStreamedSubsystem( model_file, model_name, subsystem_name, subsystem_resource, subsystem_file, directories ) ) { return False; } subsystem_resource->subsystemModelSize = sizeof(*subsystem_resource); subsystem_resource->classID = RegisteredClass::ChuteClassID; // // Figure out who our voltage source is // if ( !subsystem_file->GetEntry( subsystem_name, "ChuteCount", &subsystem_resource->chuteCount ) ) { std::cerr << subsystem_name << " missing ChuteCount!\n"; return False; } if ( !subsystem_file->GetEntry( subsystem_name, "ReloadTime", &subsystem_resource->reloadTime ) ) { std::cerr << subsystem_name << " missing ReloadTime!\n"; return False; } if ( !subsystem_file->GetEntry( subsystem_name, "DragForce", &subsystem_resource->dragForce ) ) { std::cerr << subsystem_name << " missing DragForce!\n"; return False; } if ( !subsystem_file->GetEntry( subsystem_name, "MinVelocity", &subsystem_resource->minVelocity ) ) { std::cerr << subsystem_name << " missing MinVelocity!\n"; return False; } if ( !subsystem_file->GetEntry( subsystem_name, "DeployTime", &subsystem_resource->deployTime ) ) { std::cerr << subsystem_name << " missing DeployTime!\n"; return False; } Scalar degree; if ( !subsystem_file->GetEntry( subsystem_name, "MaxRotation", °ree ) ) { std::cerr << subsystem_name << " missing MaxRotation!\n"; return False; } else { Radian rad(degree); subsystem_resource->zDeviation = cos(rad); } if (subsystem_resource->dragForce < 0.0f) { std::cerr << subsystem_name << " must have a positive dragForce!\n"; return False; } return True; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Logical Chute::TestInstance() const { return IsDerivedFrom(*GetClassDerivations()); }