diff --git a/Runtime/MP1/World/CPhazonHealingNodule.cpp b/Runtime/MP1/World/CPhazonHealingNodule.cpp index f8b3c79af..dc046e201 100644 --- a/Runtime/MP1/World/CPhazonHealingNodule.cpp +++ b/Runtime/MP1/World/CPhazonHealingNodule.cpp @@ -1,6 +1,7 @@ #include "Runtime/MP1/World/CPhazonHealingNodule.hpp" #include "Runtime/CSimplePool.hpp" +#include "Runtime/CStateManager.hpp" #include "Runtime/GameGlobalObjects.hpp" #include "Runtime/World/CPatternedInfo.hpp" @@ -8,16 +9,162 @@ namespace urde::MP1 { CPhazonHealingNodule::CPhazonHealingNodule(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, CModelData&& mData, const CActorParameters& actParams, const CPatternedInfo& pInfo, - CAssetId particleDescId, std::string str) + CAssetId particleDescId, std::string actorLctr) : CPatterned(ECharacter::PhazonHealingNodule, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo, EMovementType::Flyer, EColliderType::One, EBodyType::Restricted, actParams, EKnockBackVariant::Medium) -, x570_(g_SimplePool->GetObj(SObjectTag{SBIG('ELSC'), particleDescId})) -, x580_(pInfo.GetHealthInfo()) -, x58c_(std::move(str)) { +, x570_electricDesc(g_SimplePool->GetObj(SObjectTag{SBIG('ELSC'), particleDescId})) +, x580_initialHealthInfo(pInfo.GetHealthInfo()) +, x58c_actorLctr(std::move(actorLctr)) { const CMaterialFilter& filter = GetMaterialFilter(); CMaterialList include = filter.GetIncludeList(); CMaterialList exclude = filter.GetExcludeList(); exclude.Add(EMaterialTypes::Character); SetMaterialFilter(CMaterialFilter::MakeIncludeExclude(include, exclude)); } + +void CPhazonHealingNodule::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) { + switch (msg) { + case EScriptObjectMessage::Decrement: + x568_active = 0; + x57c_particleElectric.reset(); + x56c_emitting = false; + break; + case EScriptObjectMessage::Increment: + x568_active = 1; + break; + case EScriptObjectMessage::Reset: + *HealthInfo(mgr) = x580_initialHealthInfo; + break; + case EScriptObjectMessage::Registered: + if (!GetBodyController()->GetActive()) { + GetBodyController()->Activate(mgr); + } + // TODO remove const_cast + *const_cast(GetDamageVulnerability()) = CDamageVulnerability::ImmuneVulnerabilty(); + GetKnockBackController().SetAutoResetImpulse(false); + GetBodyController()->SetLocomotionType(pas::ELocomotionType::Relaxed); + RemoveMaterial(EMaterialTypes::Target, EMaterialTypes::Orbit, mgr); + AddMaterial(EMaterialTypes::Immovable, mgr); + break; + case EScriptObjectMessage::InitializedInArea: + CPatterned::AcceptScriptMsg(msg, uid, mgr); + for (const auto& conn : GetConnectionList()) { + auto connId = mgr.GetIdForScript(conn.x8_objId); + if (conn.x0_state == EScriptObjectState::Patrol && connId != kInvalidUniqueId && + conn.x4_msg == EScriptObjectMessage::Activate) { + x56e_connId = connId; + } + } + break; + default: + CPatterned::AcceptScriptMsg(msg, uid, mgr); + break; + } +} + +void CPhazonHealingNodule::Death(CStateManager& mgr, const zeus::CVector3f& direction, EScriptObjectState state) { + SendScriptMsgs(EScriptObjectState::Dead, mgr, EScriptObjectMessage::None); + SendScriptMsgs(EScriptObjectState::DeathRattle, mgr, EScriptObjectMessage::None); +} + +void CPhazonHealingNodule::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, + float dt) { + if (type == EUserEventType::EndAction) { + x56c_emitting = false; + x57c_particleElectric.reset(); + } else if (type == EUserEventType::BeginAction) { + x56c_emitting = true; + x57c_particleElectric = std::make_unique(x570_electricDesc); + x57c_particleElectric->SetParticleEmission(true); + } else { + CPatterned::DoUserAnimEvent(mgr, node, type, dt); + } +} + +void CPhazonHealingNodule::Faint(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Update) { + if (x588_state == 0) { + if (GetBodyController()->GetCurrentStateId() == pas::EAnimationState::Step) { + x588_state = 2; + GetBodyController()->SetLocomotionType(pas::ELocomotionType::Relaxed); + } else { + GetBodyController()->GetCommandMgr().DeliverCmd( + CBCStepCmd(pas::EStepDirection::Backward, pas::EStepType::Normal)); + } + } else if (x588_state == 2 && GetBodyController()->GetCurrentStateId() != pas::EAnimationState::Step) { + x588_state = 3; + } + } else if (msg == EStateMsg::Activate) { + x588_state = 0; + } +} + +void CPhazonHealingNodule::Growth(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Update) { + if (x588_state == 0) { + if (GetBodyController()->GetCurrentStateId() == pas::EAnimationState::Step) { + x588_state = 2; + } else { + GetBodyController()->GetCommandMgr().DeliverCmd( + CBCStepCmd(pas::EStepDirection::Forward, pas::EStepType::Normal)); + } + } else if (x588_state == 2 && GetBodyController()->GetCurrentStateId() != pas::EAnimationState::Step) { + x588_state = 3; + } + } else if (msg == EStateMsg::Activate) { + x588_state = 0; + GetBodyController()->SetLocomotionType(pas::ELocomotionType::Lurk); + } +} + +void CPhazonHealingNodule::KnockBack(const zeus::CVector3f& vec, CStateManager& mgr, const CDamageInfo& info, + EKnockBackType type, bool inDeferred, float magnitude) {} + +void CPhazonHealingNodule::Lurk(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + GetBodyController()->SetLocomotionType(pas::ELocomotionType::Lurk); + } +} + +void CPhazonHealingNodule::Patrol(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + GetBodyController()->SetLocomotionType(pas::ELocomotionType::Relaxed); + RemoveMaterial(EMaterialTypes::Target, EMaterialTypes::Orbit, mgr); + } +} + +void CPhazonHealingNodule::Render(const CStateManager& mgr) const { + if (x57c_particleElectric) { + x57c_particleElectric->Render(); + } + CPatterned::Render(mgr); +} + +void CPhazonHealingNodule::Think(float dt, CStateManager& mgr) { + if (GetActive()) { + CPatterned::Think(dt, mgr); + if (HealthInfo(mgr)->GetHP() <= 0.f) { + x57c_particleElectric.reset(); + x56c_emitting = false; + x330_stateMachineState.SetState(mgr, *this, GetStateMachine(), "Patrol"sv); + x568_active = 0; + } + if (x57c_particleElectric) { + UpdateParticleElectric(mgr); + x57c_particleElectric->Update(dt); + } + } +} + +void CPhazonHealingNodule::UpdateParticleElectric(CStateManager& mgr) { + if (!x57c_particleElectric) { + return; + } + if (auto entity = static_cast(mgr.GetObjectById(x56e_connId))) { + auto electricityLctrXf = GetLctrTransform("Electricity_LCTR"sv); + auto actorLctrXf = entity->GetLctrTransform(x58c_actorLctr); + x57c_particleElectric->SetOverrideIPos(electricityLctrXf.origin); + x57c_particleElectric->SetOverrideFPos(actorLctrXf.origin); + } +} } // namespace urde::MP1 diff --git a/Runtime/MP1/World/CPhazonHealingNodule.hpp b/Runtime/MP1/World/CPhazonHealingNodule.hpp index d8e6274fe..c2a9450a3 100644 --- a/Runtime/MP1/World/CPhazonHealingNodule.hpp +++ b/Runtime/MP1/World/CPhazonHealingNodule.hpp @@ -6,19 +6,35 @@ namespace urde::MP1 { class CPhazonHealingNodule : public CPatterned { private: - int x568_ = 0; - u8 x56c_ = 0; - TUniqueId x56e_ = kInvalidUniqueId; - TCachedToken x570_; - std::unique_ptr x57c_; // was rstl::rc_ptr - CHealthInfo x580_; - int x588_ = 0; // not init in ctr - std::string x58c_; + int x568_active = 0; + bool x56c_emitting = false; + TUniqueId x56e_connId = kInvalidUniqueId; + TCachedToken x570_electricDesc; + std::unique_ptr x57c_particleElectric; // was rstl::rc_ptr + CHealthInfo x580_initialHealthInfo; + int x588_state = 0; // not init in ctr; same as CElitePirate::EState? + std::string x58c_actorLctr; // u32 x59c_; public: CPhazonHealingNodule(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, CModelData&& mData, const CActorParameters& actParams, const CPatternedInfo& pInfo, - CAssetId particleDescId, std::string str); + CAssetId particleDescId, std::string actorLctr); + + void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) override; + void DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) override; + void Render(const CStateManager& mgr) const override; + void Think(float dt, CStateManager& mgr) override; + + void Death(CStateManager& mgr, const zeus::CVector3f& direction, EScriptObjectState state) override; + void Faint(CStateManager& mgr, EStateMsg msg, float dt) override; + void Growth(CStateManager& mgr, EStateMsg msg, float dt) override; + void KnockBack(const zeus::CVector3f& vec, CStateManager& mgr, const CDamageInfo& info, EKnockBackType type, + bool inDeferred, float magnitude) override; + void Lurk(CStateManager& mgr, EStateMsg msg, float dt) override; + void Patrol(CStateManager& mgr, EStateMsg msg, float dt) override; + +private: + void UpdateParticleElectric(CStateManager& mgr); }; } // namespace urde::MP1