diff --git a/dGame/dComponents/ModelComponent.cpp b/dGame/dComponents/ModelComponent.cpp index 85d206e2..2c975136 100644 --- a/dGame/dComponents/ModelComponent.cpp +++ b/dGame/dComponents/ModelComponent.cpp @@ -29,19 +29,22 @@ ModelComponent::ModelComponent(Entity* parent, const int32_t componentID) : Comp bool ModelComponent::OnResetModelToDefaults(GameMessages::GameMsg& msg) { auto& reset = static_cast(msg); - for (auto& behavior : m_Behaviors) behavior.HandleMsg(reset); - GameMessages::UnSmash unsmash; - unsmash.target = GetParent()->GetObjectID(); - unsmash.duration = 0.0f; - unsmash.Send(UNASSIGNED_SYSTEM_ADDRESS); + if (reset.bResetBehaviors) for (auto& behavior : m_Behaviors) behavior.HandleMsg(reset); - m_Parent->SetPosition(m_OriginalPosition); - m_Parent->SetRotation(m_OriginalRotation); + if (reset.bUnSmash) { + GameMessages::UnSmash unsmash; + unsmash.target = GetParent()->GetObjectID(); + unsmash.duration = 0.0f; + unsmash.Send(UNASSIGNED_SYSTEM_ADDRESS); + m_NumActiveUnSmash = 0; + } + + if (reset.bResetPos) m_Parent->SetPosition(m_OriginalPosition); + if (reset.bResetRot) m_Parent->SetRotation(m_OriginalRotation); m_Parent->SetVelocity(NiPoint3Constant::ZERO); m_Speed = 3.0f; m_NumListeningInteract = 0; - m_NumActiveUnSmash = 0; m_NumActiveAttack = 0; GameMessages::SetFaction set{}; diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 1b52d67a..65349852 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -848,6 +848,11 @@ namespace GameMessages { struct ResetModelToDefaults : public GameMsg { ResetModelToDefaults() : GameMsg(MessageType::Game::RESET_MODEL_TO_DEFAULTS) {} + + bool bResetPos{ true }; + bool bResetRot{ true }; + bool bUnSmash{ true }; + bool bResetBehaviors{ true }; }; struct EmotePlayed : public GameMsg { diff --git a/dGame/dPropertyBehaviors/PropertyBehavior.cpp b/dGame/dPropertyBehaviors/PropertyBehavior.cpp index 0eb3f9df..d52a5380 100644 --- a/dGame/dPropertyBehaviors/PropertyBehavior.cpp +++ b/dGame/dPropertyBehaviors/PropertyBehavior.cpp @@ -5,6 +5,7 @@ #include "ControlBehaviorMsgs.h" #include "tinyxml2.h" #include "ModelComponent.h" +#include "StringifiedEnum.h" #include @@ -178,13 +179,33 @@ void PropertyBehavior::Deserialize(const tinyxml2::XMLElement& behavior) { } void PropertyBehavior::Update(float deltaTime, ModelComponent& modelComponent) { - for (auto& state : m_States | std::views::values) state.Update(deltaTime, modelComponent); + auto& activeState = GetActiveState(); + UpdateResult updateResult{}; + activeState.Update(deltaTime, modelComponent, updateResult); + if (updateResult.newState.has_value() && updateResult.newState.value() != m_ActiveState) { + LOG("Behavior %llu is changing from state %s to %s", StringifiedEnum::ToString(m_ActiveState).data(), StringifiedEnum::ToString(updateResult.newState.value()).data()); + GameMessages::ResetModelToDefaults resetMsg{}; + resetMsg.bResetPos = false; + resetMsg.bResetRot = false; + resetMsg.bUnSmash = false; + resetMsg.bResetBehaviors = false; + modelComponent.OnResetModelToDefaults(resetMsg); + HandleMsg(resetMsg); + m_ActiveState = updateResult.newState.value(); + } } void PropertyBehavior::OnChatMessageReceived(const std::string& sMessage) { - for (auto& state : m_States | std::views::values) state.OnChatMessageReceived(sMessage); + auto& activeState = GetActiveState(); + activeState.OnChatMessageReceived(sMessage); } void PropertyBehavior::OnHit() { - for (auto& state : m_States | std::views::values) state.OnHit(); + auto& activeState = GetActiveState(); + activeState.OnHit(); +} + +State& PropertyBehavior::GetActiveState() { + DluAssert(m_States.contains(m_ActiveState)); + return m_States[m_ActiveState]; } diff --git a/dGame/dPropertyBehaviors/PropertyBehavior.h b/dGame/dPropertyBehaviors/PropertyBehavior.h index f6a6be10..4fca613b 100644 --- a/dGame/dPropertyBehaviors/PropertyBehavior.h +++ b/dGame/dPropertyBehaviors/PropertyBehavior.h @@ -1,18 +1,23 @@ #ifndef __PROPERTYBEHAVIOR__H__ #define __PROPERTYBEHAVIOR__H__ +#include "BehaviorStates.h" #include "State.h" +#include + namespace tinyxml2 { class XMLElement; } -enum class BehaviorState : uint32_t; - class AMFArrayValue; class BehaviorMessageBase; class ModelComponent; +struct UpdateResult { + std::optional newState; +}; + /** * Represents the Entity of a Property Behavior and holds data associated with the behavior */ @@ -45,6 +50,7 @@ public: void OnHit(); private: + State& GetActiveState(); // The current active behavior state. Behaviors can only be in ONE state at a time. BehaviorState m_ActiveState; diff --git a/dGame/dPropertyBehaviors/State.cpp b/dGame/dPropertyBehaviors/State.cpp index 5a2828e4..82d7ae0b 100644 --- a/dGame/dPropertyBehaviors/State.cpp +++ b/dGame/dPropertyBehaviors/State.cpp @@ -163,8 +163,8 @@ void State::Deserialize(const tinyxml2::XMLElement& state) { } } -void State::Update(float deltaTime, ModelComponent& modelComponent) { - for (auto& strip : m_Strips) strip.Update(deltaTime, modelComponent); +void State::Update(float deltaTime, ModelComponent& modelComponent, UpdateResult& updateResult) { + for (auto& strip : m_Strips) strip.Update(deltaTime, modelComponent, updateResult); } void State::OnChatMessageReceived(const std::string& sMessage) { diff --git a/dGame/dPropertyBehaviors/State.h b/dGame/dPropertyBehaviors/State.h index a8d03ba7..436bb210 100644 --- a/dGame/dPropertyBehaviors/State.h +++ b/dGame/dPropertyBehaviors/State.h @@ -9,6 +9,7 @@ namespace tinyxml2 { class AMFArrayValue; class ModelComponent; +struct UpdateResult; class State { public: @@ -21,7 +22,7 @@ public: void Serialize(tinyxml2::XMLElement& state) const; void Deserialize(const tinyxml2::XMLElement& state); - void Update(float deltaTime, ModelComponent& modelComponent); + void Update(float deltaTime, ModelComponent& modelComponent, UpdateResult& updateResult); void OnChatMessageReceived(const std::string& sMessage); void OnHit(); diff --git a/dGame/dPropertyBehaviors/Strip.cpp b/dGame/dPropertyBehaviors/Strip.cpp index 330284a9..4ddc96cb 100644 --- a/dGame/dPropertyBehaviors/Strip.cpp +++ b/dGame/dPropertyBehaviors/Strip.cpp @@ -160,13 +160,14 @@ void Strip::SpawnDrop(LOT dropLOT, Entity& entity) { } } -void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent) { +void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent, UpdateResult& updateResult) { auto& entity = *modelComponent.GetParent(); auto& nextAction = GetNextAction(); auto number = nextAction.GetValueParameterDouble(); auto valueStr = nextAction.GetValueParameterString(); auto numberAsInt = static_cast(number); auto nextActionType = GetNextAction().GetType(); + LOG_DEBUG("Processing Strip Action: %s with number %.2f and string %s", nextActionType.data(), number, valueStr.data()); // TODO replace with switch case and nextActionType with enum /* BEGIN Move */ @@ -223,7 +224,8 @@ void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent) { unsmash.Send(UNASSIGNED_SYSTEM_ADDRESS); modelComponent.AddUnSmash(); - m_PausedTime = number; + // since it may take time for the message to relay to clients + m_PausedTime = number + 0.5f; } else if (nextActionType == "Wait") { m_PausedTime = number; } else if (nextActionType == "Chat") { @@ -258,6 +260,21 @@ void Strip::ProcNormalAction(float deltaTime, ModelComponent& modelComponent) { for (; numberAsInt > 0; numberAsInt--) SpawnDrop(6431, entity); // 1 Armor powerup } /* END Gameplay */ + /* BEGIN StateMachine */ + else if (nextActionType == "ChangeStateHome") { + updateResult.newState = BehaviorState::HOME_STATE; + } else if (nextActionType == "ChangeStateCircle") { + updateResult.newState = BehaviorState::CIRCLE_STATE; + } else if (nextActionType == "ChangeStateSquare") { + updateResult.newState = BehaviorState::SQUARE_STATE; + } else if (nextActionType == "ChangeStateDiamond") { + updateResult.newState = BehaviorState::DIAMOND_STATE; + } else if (nextActionType == "ChangeStateTriangle") { + updateResult.newState = BehaviorState::TRIANGLE_STATE; + } else if (nextActionType == "ChangeStateStar") { + updateResult.newState = BehaviorState::STAR_STATE; + } + /* END StateMachine*/ else { static std::set g_WarnedActions; if (!g_WarnedActions.contains(nextActionType.data())) { @@ -330,7 +347,7 @@ bool Strip::CheckMovement(float deltaTime, ModelComponent& modelComponent) { return moveFinished; } -void Strip::Update(float deltaTime, ModelComponent& modelComponent) { +void Strip::Update(float deltaTime, ModelComponent& modelComponent, UpdateResult& updateResult) { // No point in running a strip with only one action. // Strips are also designed to have 2 actions or more to run. if (!HasMinimumActions()) return; @@ -354,9 +371,9 @@ void Strip::Update(float deltaTime, ModelComponent& modelComponent) { // Check for trigger blocks and if not a trigger block proc this blocks action if (m_NextActionIndex == 0) { + LOG("Behavior strip started %s", nextAction.GetType().data()); if (nextAction.GetType() == "OnInteract") { modelComponent.AddInteract(); - } else if (nextAction.GetType() == "OnChat") { // logic here if needed } else if (nextAction.GetType() == "OnAttack") { @@ -365,7 +382,7 @@ void Strip::Update(float deltaTime, ModelComponent& modelComponent) { Game::entityManager->SerializeEntity(entity); m_WaitingForAction = true; } else { // should be a normal block - ProcNormalAction(deltaTime, modelComponent); + ProcNormalAction(deltaTime, modelComponent, updateResult); } } diff --git a/dGame/dPropertyBehaviors/Strip.h b/dGame/dPropertyBehaviors/Strip.h index 1a61afd5..330aafbc 100644 --- a/dGame/dPropertyBehaviors/Strip.h +++ b/dGame/dPropertyBehaviors/Strip.h @@ -12,6 +12,7 @@ namespace tinyxml2 { class AMFArrayValue; class ModelComponent; +struct UpdateResult; class Strip { public: @@ -33,9 +34,9 @@ public: // Checks the movement logic for whether or not to proceed // Returns true if the movement can continue, false if it needs to wait more. bool CheckMovement(float deltaTime, ModelComponent& modelComponent); - void Update(float deltaTime, ModelComponent& modelComponent); + void Update(float deltaTime, ModelComponent& modelComponent, UpdateResult& updateResult); void SpawnDrop(LOT dropLOT, Entity& entity); - void ProcNormalAction(float deltaTime, ModelComponent& modelComponent); + void ProcNormalAction(float deltaTime, ModelComponent& modelComponent, UpdateResult& updateResult); void RemoveStates(ModelComponent& modelComponent) const; // 2 actions are required for strips to work