diff --git a/Runtime/AutoMapper/CAutoMapper.cpp b/Runtime/AutoMapper/CAutoMapper.cpp index f13e03012..de0c070e8 100644 --- a/Runtime/AutoMapper/CAutoMapper.cpp +++ b/Runtime/AutoMapper/CAutoMapper.cpp @@ -1472,7 +1472,7 @@ void CAutoMapper::Draw(const CStateManager& mgr, const zeus::CTransform& xf, flo beaconAlpha = loc.x4_beaconAlpha; } if (beaconAlpha > 0.f) { - const std::array verts{{ + constexpr std::array verts{{ {{-4.f, -8.f, 8.f}, {0.f, 1.f}}, {{-4.f, -8.f, 0.f}, {0.f, 0.f}}, {{4.f, -8.f, 8.f}, {1.f, 1.f}}, @@ -1486,7 +1486,7 @@ void CAutoMapper::Draw(const CStateManager& mgr, const zeus::CTransform& xf, flo colorAlpha *= mapAlpha; zeus::CColor color = zeus::skWhite; color.a() = colorAlpha; - filter.drawVerts(color, verts.data()); + filter.drawVerts(color, verts); } } } diff --git a/Runtime/AutoMapper/CMappableObject.cpp b/Runtime/AutoMapper/CMappableObject.cpp index c79ccf24f..5305e4808 100644 --- a/Runtime/AutoMapper/CMappableObject.cpp +++ b/Runtime/AutoMapper/CMappableObject.cpp @@ -170,13 +170,13 @@ void CMappableObject::Draw(int curArea, const CMapWorldInfo& mwInfo, float alpha m_texQuadFilter.emplace(EFilterType::Add, tex, CTexturedQuadFilter::ZTest::GEqual); } - const std::array verts{{ + constexpr std::array verts{{ {{-2.6f, 0.f, 2.6f}, {0.f, 1.f}}, {{-2.6f, 0.f, -2.6f}, {0.f, 0.f}}, {{2.6f, 0.f, 2.6f}, {1.f, 1.f}}, {{2.6f, 0.f, -2.6f}, {1.f, 0.f}}, }}; - m_texQuadFilter->drawVerts(iconColor, verts.data()); + m_texQuadFilter->drawVerts(iconColor, verts); } } diff --git a/Runtime/Graphics/CSimpleShadow.cpp b/Runtime/Graphics/CSimpleShadow.cpp index 8e9f6164c..973a9fe39 100644 --- a/Runtime/Graphics/CSimpleShadow.cpp +++ b/Runtime/Graphics/CSimpleShadow.cpp @@ -39,10 +39,12 @@ void CSimpleShadow::Render(const TLockedToken& tex) { m_filter.emplace(EFilterType::InvDstMultiply, tex, CTexturedQuadFilter::ZTest::LEqual); float radius = x34_radius * x30_scale; - CTexturedQuadFilter::Vert verts[] = {{{-radius, 0.f, -radius}, {0.f, 0.f}}, - {{radius, 0.f, -radius}, {0.f, 1.f}}, - {{-radius, 0.f, radius}, {1.f, 0.f}}, - {{radius, 0.f, radius}, {1.f, 1.f}}}; + const std::array verts{{ + {{-radius, 0.f, -radius}, {0.f, 0.f}}, + {{radius, 0.f, -radius}, {0.f, 1.f}}, + {{-radius, 0.f, radius}, {1.f, 0.f}}, + {{radius, 0.f, radius}, {1.f, 1.f}}, + }}; m_filter->drawVerts(zeus::skWhite, verts); } diff --git a/Runtime/Graphics/Shaders/CTexturedQuadFilter.cpp b/Runtime/Graphics/Shaders/CTexturedQuadFilter.cpp index a9a9f78e3..bcad25682 100644 --- a/Runtime/Graphics/Shaders/CTexturedQuadFilter.cpp +++ b/Runtime/Graphics/Shaders/CTexturedQuadFilter.cpp @@ -258,10 +258,10 @@ void CTexturedQuadFilter::drawCropped(const zeus::CColor& color, float uvScale) CGraphics::DrawArray(0, 4); } -void CTexturedQuadFilter::drawVerts(const zeus::CColor& color, const Vert verts[4], float lod) { +void CTexturedQuadFilter::drawVerts(const zeus::CColor& color, std::array verts, float lod) { SCOPED_GRAPHICS_DEBUG_GROUP("CTexturedQuadFilter::drawVerts", zeus::skMagenta); - m_vbo->load(verts, sizeof(Vert) * 4); + m_vbo->load(verts.data(), sizeof(Vert) * verts.size()); m_uniform.m_matrix = CGraphics::GetPerspectiveProjectionMatrix(true) * CGraphics::g_GXModelView.toMatrix4f(); m_uniform.m_color = color; @@ -269,7 +269,7 @@ void CTexturedQuadFilter::drawVerts(const zeus::CColor& color, const Vert verts[ m_uniBuf->load(&m_uniform, sizeof(m_uniform)); CGraphics::SetShaderDataBinding(m_dataBind); - CGraphics::DrawArray(0, 4); + CGraphics::DrawArray(0, verts.size()); } void CTexturedQuadFilter::DrawFilter(EFilterShape shape, const zeus::CColor& color, float t) { diff --git a/Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp b/Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp index a035394e5..00d7569d6 100644 --- a/Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp +++ b/Runtime/Graphics/Shaders/CTexturedQuadFilter.hpp @@ -53,7 +53,7 @@ public: CTexturedQuadFilter& operator=(CTexturedQuadFilter&&) = default; void draw(const zeus::CColor& color, float uvScale, const zeus::CRectangle& rect = DefaultRect, float z = 0.f); void drawCropped(const zeus::CColor& color, float uvScale); - void drawVerts(const zeus::CColor& color, const Vert verts[4], float lod = 0.f); + void drawVerts(const zeus::CColor& color, std::array verts, float lod = 0.f); void DrawFilter(EFilterShape shape, const zeus::CColor& color, float t); const TLockedToken& GetTex() const { return m_tex; } const boo::ObjToken& GetBooTex() const { return m_booTex; } diff --git a/Runtime/GuiSys/CAuiImagePane.cpp b/Runtime/GuiSys/CAuiImagePane.cpp index 298819b0d..6691ac541 100644 --- a/Runtime/GuiSys/CAuiImagePane.cpp +++ b/Runtime/GuiSys/CAuiImagePane.cpp @@ -90,14 +90,14 @@ void CAuiImagePane::DoDrawImagePane(const zeus::CColor& color, const CTexture& t }}; if (noBlur) { - quad.drawVerts(useColor, verts.data()); + quad.drawVerts(useColor, verts); } else if ((x14c_deResFactor == 0.f && alpha == 1.f) || tex.GetNumMips() == 1) { - quad.drawVerts(useColor, verts.data(), 0.f); + quad.drawVerts(useColor, verts, 0.f); } else { const float tmp = (1.f - x14c_deResFactor) * alpha; const float tmp3 = 1.f - tmp * tmp * tmp; const float mip = tmp3 * static_cast(tex.GetNumMips() - 1); - quad.drawVerts(useColor, verts.data(), mip); + quad.drawVerts(useColor, verts, mip); } } diff --git a/Runtime/GuiSys/CScanDisplay.cpp b/Runtime/GuiSys/CScanDisplay.cpp index 8a78f3906..2ed7305f5 100644 --- a/Runtime/GuiSys/CScanDisplay.cpp +++ b/Runtime/GuiSys/CScanDisplay.cpp @@ -45,12 +45,12 @@ void CScanDisplay::CDataDot::Draw(const zeus::CColor& col, float radius) { CGraphics::SetModelMatrix(xf); zeus::CColor useColor = col; useColor.a() *= x24_alpha; - const CTexturedQuadFilter::Vert verts[4] = { + const std::array verts{{ {{-radius, 0.f, radius}, {0.f, 1.f}}, {{-radius, 0.f, -radius}, {0.f, 0.f}}, {{radius, 0.f, radius}, {1.f, 1.f}}, {{radius, 0.f, -radius}, {1.f, 0.f}}, - }; + }}; m_quad.drawVerts(useColor, verts); } } diff --git a/Runtime/MP1/CInGameGuiManager.cpp b/Runtime/MP1/CInGameGuiManager.cpp index 31a4dd461..e076f4065 100644 --- a/Runtime/MP1/CInGameGuiManager.cpp +++ b/Runtime/MP1/CInGameGuiManager.cpp @@ -614,11 +614,11 @@ void CInGameGuiManager::Draw(CStateManager& stateMgr) { if (!m_deathRenderTexQuad) m_deathRenderTexQuad.emplace(EFilterType::Blend, CGraphics::g_SpareTexture.get()); - m_deathRenderTexQuad->drawVerts(zeus::CColor(1.f, colT), verts.data()); + m_deathRenderTexQuad->drawVerts(zeus::CColor(1.f, colT), verts); if (!m_deathDotQuad) m_deathDotQuad.emplace(EFilterType::Multiply, x50_deathDot); - m_deathDotQuad->drawVerts(zeus::CColor(1.f, colT), verts.data()); + m_deathDotQuad->drawVerts(zeus::CColor(1.f, colT), verts); } } } diff --git a/Runtime/MP1/CPlayerVisor.cpp b/Runtime/MP1/CPlayerVisor.cpp index 2c6ba0d2e..d1602cf8e 100644 --- a/Runtime/MP1/CPlayerVisor.cpp +++ b/Runtime/MP1/CPlayerVisor.cpp @@ -372,12 +372,12 @@ void CPlayerVisor::DrawScanEffect(const CStateManager& mgr, CTargetingManager* t const float uvX1 = float(rect.x4_left + rect.xc_width) / float(g_Viewport.x8_width); const float uvY0 = float(rect.x8_top) / float(g_Viewport.xc_height); const float uvY1 = float(rect.x8_top + rect.x10_height) / float(g_Viewport.xc_height); - CTexturedQuadFilter::Vert rttVerts[4] = { + std::array rttVerts{{ {{-5.f, 0.f, 4.45f}, {uvX0, uvY0}}, {{5.f, 0.f, 4.45f}, {uvX1, uvY0}}, {{-5.f, 0.f, -4.45f}, {uvX0, uvY1}}, {{5.f, 0.f, -4.45f}, {uvX1, uvY1}}, - }; + }}; if (CGraphics::g_BooPlatform == boo::IGraphicsDataFactory::Platform::OpenGL) { rttVerts[0].m_uv.y() = uvY1; rttVerts[1].m_uv.y() = uvY1; diff --git a/Runtime/MP1/World/CElitePirate.cpp b/Runtime/MP1/World/CElitePirate.cpp index cf0e74303..dbb6d549c 100644 --- a/Runtime/MP1/World/CElitePirate.cpp +++ b/Runtime/MP1/World/CElitePirate.cpp @@ -611,7 +611,7 @@ void CElitePirate::SpecialAttack(CStateManager& mgr, EStateMsg msg, float) { } } else if (x568_state == EState::Two) { if (x450_bodyController->GetCurrentStateId() == pas::EAnimationState::ProjectileAttack) { - x450_bodyController->GetCommandMgr().DeliverTargetVector(mgr.GetPlayer().GetTranslation()); + x450_bodyController->GetCommandMgr().DeliverTargetVector(mgr.GetPlayer().GetTranslation() - GetTranslation()); } else { x568_state = EState::Over; } diff --git a/Runtime/MP1/World/CElitePirate.hpp b/Runtime/MP1/World/CElitePirate.hpp index 6abacb4cb..0a77b2987 100644 --- a/Runtime/MP1/World/CElitePirate.hpp +++ b/Runtime/MP1/World/CElitePirate.hpp @@ -77,6 +77,15 @@ public: }; class CElitePirate : public CPatterned { +protected: + enum class EState { + Invalid = -1, + Zero = 0, + One = 1, + Two = 2, + Over = 3, + }; + private: struct SUnknownStruct { private: @@ -90,14 +99,6 @@ private: void Clear() { x4_.clear(); } }; - enum class EState { - Invalid = -1, - Zero = 0, - One = 1, - Two = 2, - Over = 3, - }; - EState x568_state = EState::Invalid; CDamageVulnerability x56c_vulnerability; std::unique_ptr x5d4_collisionActorMgr; @@ -189,12 +190,28 @@ public: virtual void SetupHealthInfo(CStateManager& mgr); virtual void SetLaunchersActive(CStateManager& mgr, bool val); virtual SShockWaveData GetShockWaveData() const { - return {x5d8_data.GetXF8(), x5d8_data.GetXFC(), x5d8_data.GetX118(), x5d8_data.GetX11C()}; + return {x5d8_data.GetXF8(), x5d8_data.GetXFC(), 16.5217f, x5d8_data.GetX118(), x5d8_data.GetX11C()}; } -private: - void SetupPathFindSearch(); +protected: void SetShotAt(bool val, CStateManager& mgr); + void CreateGrenadeLauncher(CStateManager& mgr, TUniqueId uid); + zeus::CVector3f GetLockOnPosition(const CActor* actor) const; + bool ShouldFireFromLauncher(CStateManager& mgr, TUniqueId launcherId); + bool ShouldCallForBackupFromLauncher(const CStateManager& mgr, TUniqueId uid) const; + void SetupLauncherHealthInfo(CStateManager& mgr, TUniqueId uid); + void SetLauncherActive(CStateManager& mgr, bool val, TUniqueId uid); + void SetupPathFindSearch(); + void UpdateActorTransform(CStateManager& mgr, TUniqueId& uid, std::string_view name); + + const CElitePirateData& GetData() const { return x5d8_data; } + EState GetState() const { return x568_state; } + void SetState(EState state) { x568_state = state; } + TUniqueId GetLauncherId() const { return x772_launcherId; } + void SetAlert(bool val) { x988_28_alert = val; } + const CCollisionActorManager& GetCollisionActorManager() const { return *x5d4_collisionActorMgr; } + +private: bool IsArmClawCollider(TUniqueId uid, const rstl::reserved_vector& vec) const; void AddSphereCollisionList(const SSphereJointInfo* joints, size_t count, std::vector& outJoints) const; @@ -204,12 +221,8 @@ private: void SetupCollisionActorInfo(CStateManager& mgr); bool IsArmClawCollider(std::string_view name, std::string_view locator, const SJointInfo* info, size_t infoCount) const; - void CreateGrenadeLauncher(CStateManager& mgr, TUniqueId uid); void ApplyDamageToHead(CStateManager& mgr, TUniqueId uid); void CreateEnergyAbsorb(CStateManager& mgr, const zeus::CTransform& xf); - void SetupLauncherHealthInfo(CStateManager& mgr, TUniqueId uid); - void SetLauncherActive(CStateManager& mgr, bool val, TUniqueId uid); - zeus::CVector3f GetLockOnPosition(const CActor* actor) const; bool CanKnockBack(const CDamageInfo& info) const; void UpdateDestPos(CStateManager& mgr); void CheckAttackChance(CStateManager& mgr); @@ -218,13 +231,10 @@ private: bool IsAttractingEnergy() const; void UpdateTimers(float dt); void UpdatePositionHistory(); - void UpdateActorTransform(CStateManager& mgr, TUniqueId& uid, std::string_view name); void UpdateHealthInfo(CStateManager& mgr); void ExtendTouchBounds(const CStateManager& mgr, const rstl::reserved_vector& uids, const zeus::CVector3f& vec) const; - bool ShouldFireFromLauncher(CStateManager& mgr, TUniqueId launcherId); - bool ShouldCallForBackupFromLauncher(const CStateManager& mgr, TUniqueId uid) const; bool IsClosestEnergyAttractor(const CStateManager& mgr, const rstl::reserved_vector& charNearList, const zeus::CVector3f& projectilePos) const; }; -} // namespace urde +} // namespace urde::MP1 diff --git a/Runtime/MP1/World/CGrenadeLauncher.cpp b/Runtime/MP1/World/CGrenadeLauncher.cpp index b84047e5b..c7bc7b28a 100644 --- a/Runtime/MP1/World/CGrenadeLauncher.cpp +++ b/Runtime/MP1/World/CGrenadeLauncher.cpp @@ -131,8 +131,7 @@ void CGrenadeLauncher::PreRender(CStateManager& mgr, const zeus::CFrustum& frust // Original code redundantly sets a() = 1.f xb4_drawFlags.addColor = x3f4_color3; } else { - xb4_drawFlags = CModelFlags{5, 0, 3, zeus::skWhite}; - xb4_drawFlags.addColor = x3f4_color3; + xb4_drawFlags = CModelFlags{5, 0, 3, x3f4_color3}; } CActor::PreRender(mgr, frustum); } @@ -152,7 +151,7 @@ void CGrenadeLauncher::Think(float dt, CStateManager& mgr) { UpdateCollision(); UpdateColor(dt); - sub_8022f9e0(mgr, dt); + UpdateFollowPlayer(mgr, dt); UpdateDamageTime(dt); const SAdvancementDeltas& deltas = CActor::UpdateAnimation(dt, mgr, true); @@ -212,13 +211,14 @@ void CGrenadeLauncher::CreateExplosion(CStateManager& mgr) { CSfxManager::SfxStart(x2d0_data.GetExplosionSfx(), 1.f, 1.f, false, 0x7f, false, kInvalidAreaId); } -void CGrenadeLauncher::sub_8022f9e0(CStateManager& mgr, float dt) { +void CGrenadeLauncher::UpdateFollowPlayer(CStateManager& mgr, float dt) { CModelData* modelData = GetModelData(); CAnimData* animData = nullptr; - if (modelData != nullptr && (animData = modelData->GetAnimationData()) != nullptr && x258_started == 1 && x3fe_) { + if (modelData != nullptr && (animData = modelData->GetAnimationData()) != nullptr && x258_started == 1 && + x3fe_followPlayer) { const zeus::CVector3f target = mgr.GetPlayer().GetAimPosition(mgr, 0.f) - GetTranslation(); - const zeus::CVector3f rot = GetTransform().rotate({target.x(), target.y(), 0.f}); // TODO double check + const zeus::CVector3f rot = GetTransform().transposeRotate({target.x(), target.y(), 0.f}); if (rot.canBeNormalized()) { constexpr float p36d = zeus::degToRad(36.476f); diff --git a/Runtime/MP1/World/CGrenadeLauncher.hpp b/Runtime/MP1/World/CGrenadeLauncher.hpp index 10cfa1d6e..2993176fd 100644 --- a/Runtime/MP1/World/CGrenadeLauncher.hpp +++ b/Runtime/MP1/World/CGrenadeLauncher.hpp @@ -88,7 +88,7 @@ private: float x3f8_explodePlayerDistance; bool x3fc_launchGrenade = false; bool x3fd_visible = true; - bool x3fe_ = true; + bool x3fe_followPlayer = true; public: CGrenadeLauncher(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, @@ -108,6 +108,10 @@ public: void Think(float dt, CStateManager& mgr) override; void Touch(CActor& act, CStateManager& mgr) override; + void SetColor(const zeus::CColor& color) { x3f4_color3 = color; } + void SetVisible(bool val) { x3fd_visible = val; } + void SetFollowPlayer(bool val) { x3fe_followPlayer = val; } + static zeus::CVector3f GrenadeTarget(const CStateManager& mgr); static void CalculateGrenadeTrajectory(const zeus::CVector3f& target, const zeus::CVector3f& origin, const SGrenadeTrajectoryInfo& info, float& angleOut, float& velocityOut); @@ -117,7 +121,7 @@ private: void UpdateColor(float arg); void UpdateDamageTime(float arg); void CreateExplosion(CStateManager& mgr); - void sub_8022f9e0(CStateManager& mgr, float dt); + void UpdateFollowPlayer(CStateManager& mgr, float dt); void sub_80230438(); void LaunchGrenade(CStateManager& mgr); }; diff --git a/Runtime/MP1/World/CMakeLists.txt b/Runtime/MP1/World/CMakeLists.txt index e0c88ce2e..f48042339 100644 --- a/Runtime/MP1/World/CMakeLists.txt +++ b/Runtime/MP1/World/CMakeLists.txt @@ -29,6 +29,8 @@ set(MP1_WORLD_SOURCES CNewIntroBoss.hpp CNewIntroBoss.cpp COmegaPirate.hpp COmegaPirate.cpp CParasite.hpp CParasite.cpp + CPhazonHealingNodule.hpp CPhazonHealingNodule.cpp + CPhazonPool.hpp CPhazonPool.cpp CPuddleSpore.hpp CPuddleSpore.cpp CPuddleToadGamma.hpp CPuddleToadGamma.cpp CPuffer.hpp CPuffer.cpp diff --git a/Runtime/MP1/World/COmegaPirate.cpp b/Runtime/MP1/World/COmegaPirate.cpp index 16f462ec6..16d674d25 100644 --- a/Runtime/MP1/World/COmegaPirate.cpp +++ b/Runtime/MP1/World/COmegaPirate.cpp @@ -1,12 +1,1426 @@ #include "Runtime/MP1/World/COmegaPirate.hpp" +#include "Runtime/Camera/CGameCamera.hpp" +#include "Runtime/Collision/CCollisionActor.hpp" +#include "Runtime/Collision/CCollisionActorManager.hpp" +#include "Runtime/Collision/CGameCollision.hpp" +#include "Runtime/CSimplePool.hpp" +#include "Runtime/GameGlobalObjects.hpp" +#include "Runtime/Graphics/CBooRenderer.hpp" +#include "Runtime/Weapon/CGameProjectile.hpp" +#include "Runtime/World/CPlayer.hpp" +#include "Runtime/World/CScriptEffect.hpp" +#include "Runtime/World/CScriptPlatform.hpp" +#include "Runtime/World/CScriptSound.hpp" +#include "Runtime/World/CScriptWaypoint.hpp" +#include "Runtime/World/CWorld.hpp" + +#include "TCastTo.hpp" // Generated file, do not modify include path + namespace urde::MP1 { -COmegaPirate::CFlash::CFlash(TUniqueId uid, const CEntityInfo& info, const zeus::CVector3f& pos, CToken& p4, float p5) +namespace { +constexpr std::array skSphereJoints{{ + {"lockon_target_LCTR", 1.f}, +}}; + +constexpr std::array skObbJoints{{ + {"Spine_2", "Collar", zeus::skOne3f}, + {"R_toe_1", "R_ankle", zeus::skOne3f}, + {"L_toe_1", "L_ankle", zeus::skOne3f}, + {"R_knee", "R_ankle", zeus::skOne3f}, + {"L_knee", "L_ankle", zeus::skOne3f}, + {"R_elbow", "R_wrist", zeus::skOne3f}, + {"L_elbow", "L_wrist", zeus::skOne3f}, + {"R_wrist", "R_index_1", zeus::skOne3f}, + {"L_wrist", "L_index_1", zeus::skOne3f}, + {"R_index_1", "R_index_3_SDK", zeus::CVector3f{2.f}}, + {"L_index_1", "L_index_3_SDK", zeus::CVector3f{2.f}}, +}}; +} // namespace + +COmegaPirate::CFlash::CFlash(TUniqueId uid, const CEntityInfo& info, const zeus::CVector3f& pos, + TLockedToken& thermalSpot, float delay) : CActor(uid, true, "Omega Pirate Flash", info, zeus::CTransform::Translate(pos), CModelData::CModelDataNull(), {}, - CActorParameters::None(), kInvalidUniqueId) {} + CActorParameters::None(), kInvalidUniqueId) +, xf4_delay(delay) +, m_thermalSpotAdd(EFilterType::Add, thermalSpot) +, m_thermalSpotSubtract(EFilterType::Subtract, thermalSpot) {} + +void COmegaPirate::CFlash::Accept(IVisitor& visitor) { visitor.Visit(this); } + +void COmegaPirate::CFlash::Think(float dt, CStateManager& mgr) { + CEntity::Think(dt, mgr); + xf4_delay -= dt; + if (xf4_delay > 0.f) { + return; + } + + xf8_time += dt; + float intensity = xf8_time; + if (intensity <= 0.75f) { + intensity /= 0.75f; + } else { + intensity = 1.f - (intensity - 0.75f) / 0.25f; + } + const CGameCamera* const camera = mgr.GetCameraManager()->GetCurrentCamera(mgr); + const zeus::CVector3f dist = (GetTranslation() - camera->GetTranslation()).normalized(); + float dot = dist.dot(camera->GetTransform().frontVector()); + float dVar4 = 0.f; + if (dot >= 0.f) { + dVar4 = dot * dot; + } + xfc_size = dVar4 * intensity; + if (xf8_time > 1.f) { + mgr.FreeScriptObject(GetUniqueId()); + } +} + +void COmegaPirate::CFlash::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) { + mgr.RenderLast(GetUniqueId()); + // if (xf0_thermalSpot == nullptr && xe8_thermalSpotToken.IsLocked() && xe8_thermalSpotToken.HasReference()) { + // xf0_thermalSpot = xe8_thermalSpotToken.GetObj(); + // } +} + +void COmegaPirate::CFlash::AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) {} + +void COmegaPirate::CFlash::Render(CStateManager& mgr) { + const CPlayerState::EPlayerVisor visor = mgr.GetPlayerState()->GetActiveVisor(mgr); + if (visor == CPlayerState::EPlayerVisor::Thermal) { + return; + } + + float sizeMul = 35.f; + CTexturedQuadFilter* filter = nullptr; + if (visor == CPlayerState::EPlayerVisor::XRay) { + // CGraphics::SetBlendMode(ERglBlendMode::Subtract, ERglBlendFactor::One, ERglBlendFactor::Zero, + // ERglLogicOp::Clear); + filter = &m_thermalSpotSubtract; + sizeMul = 60.f; + } else { + // CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::One, + // ERglLogicOp::Clear); + filter = &m_thermalSpotAdd; + } + + float size = xfc_size * sizeMul; + const auto rightVec = size * CGraphics::g_ViewMatrix.rightVector(); + const auto upVec = size * CGraphics::g_ViewMatrix.upVector(); + const auto rvS = GetTranslation() - rightVec; + const auto rvP = GetTranslation() + rightVec; + CGraphics::SetModelMatrix(zeus::CTransform()); + const std::array verts{{ + {rvS + upVec, {0.f, 0.f}}, + {rvP + upVec, {0.f, 1.f}}, + {rvS - upVec, {1.f, 0.f}}, + {rvP - upVec, {1.f, 1.f}}, + }}; + filter->drawVerts(zeus::CColor{1.f, std::min(1.f, size)}, verts); +} COmegaPirate::COmegaPirate(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, CModelData&& mData, const CPatternedInfo& pInfo, const CActorParameters& actParms, CElitePirateData data, CAssetId w1, CAssetId w2, CAssetId w3) -: CElitePirate(uid, name, info, xf, std::move(mData), pInfo, actParms, data) {} +: CElitePirate(uid, name, info, xf, std::move(mData), pInfo, actParms, data) +, x9d0_initialScale(GetModelData()->GetScale()) +, x9f0_skeletonModel(*g_SimplePool, w1, w2, w3, 0, 0) +, xb70_thermalSpot(g_SimplePool->GetObj("Thermal_Spot_2"sv)) { + x9a4_scriptWaypointPlatforms.reserve(3); + x9b8_scriptEffects.reserve(24); + x9dc_scriptPlatforms.reserve(4); + xaa0_scriptSounds.reserve(4); + xab4_.reserve(3); + xb7c_.resize(4, 0); + + SetMass(100000.f); + + CMaterialFilter filter = GetMaterialFilter(); + filter.ExcludeList().Add( + CMaterialList{EMaterialTypes::Character, EMaterialTypes::CollisionActor, EMaterialTypes::Platform}); + SetMaterialFilter(filter); + + GetSearchPath()->SetPadding(20.f); +} + +void COmegaPirate::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) { + switch (msg) { + default: + CElitePirate::AcceptScriptMsg(msg, uid, mgr); + break; + case EScriptObjectMessage::Activate: + CElitePirate::AcceptScriptMsg(msg, uid, mgr); + xa38_collisionActorMgr1->SetActive(mgr, true); + xa9c_collisionActorMgr2->SetActive(mgr, true); + GetKnockBackController().SetAutoResetImpulse(false); + if (auto* entity = mgr.ObjectById(x990_launcherId2)) { + entity->SetActive(true); + } + break; + case EScriptObjectMessage::Deactivate: + CElitePirate::AcceptScriptMsg(msg, uid, mgr); + xa38_collisionActorMgr1->SetActive(mgr, false); + xa9c_collisionActorMgr2->SetActive(mgr, false); + if (auto* entity = mgr.ObjectById(x990_launcherId2)) { + entity->SetActive(false); + } + break; + case EScriptObjectMessage::Decrement: + x9ec_decrement = true; + break; + case EScriptObjectMessage::Increment: + SetShotAt(true, mgr); + break; + case EScriptObjectMessage::Open: + xb7c_[3] -= xb7c_[3] == 0 ? 0 : 1; + break; + case EScriptObjectMessage::Reset: + xb78_codeTrigger = true; + break; + case EScriptObjectMessage::SetToMax: + xa3c_hearPlayer = true; + break; + case EScriptObjectMessage::SetToZero: + xb7c_[2] -= xb7c_[2] == 0 ? 0 : 1; + break; + case EScriptObjectMessage::Start: + x3b4_speed = 1.f; + ++xade_armorPiecesDestroyed; + if (xade_armorPiecesDestroyed < 4) { + GetBodyController()->GetCommandMgr().DeliverCmd(CBCKnockBackCmd(zeus::skLeft, pas::ESeverity::One)); + } + break; + case EScriptObjectMessage::Stop: + DeathDestroy(mgr); + break; + case EScriptObjectMessage::StopAndReset: + xb7c_[1] -= xb7c_[1] == 0 ? 0 : 1; + break; + case EScriptObjectMessage::UNKM18: + xb7c_[0] -= xb7c_[0] == 0 ? 0 : 1; + break; + case EScriptObjectMessage::Action: + x3b4_speed = 1.f; + ++xade_armorPiecesDestroyed; + if (xade_armorPiecesDestroyed < 4) { + GetBodyController()->GetCommandMgr().DeliverCmd(CBCKnockBackCmd(zeus::skRight, pas::ESeverity::One)); + } + break; + case EScriptObjectMessage::Alert: + CElitePirate::AcceptScriptMsg(msg, uid, mgr); + break; + case EScriptObjectMessage::Touched: + CElitePirate::AcceptScriptMsg(msg, uid, mgr); + if (uid == x990_launcherId2 && x990_launcherId2 != kInvalidUniqueId) { + SetShotAt(true, mgr); + } + if (TCastToPtr actor = mgr.ObjectById(uid)) { + if (TCastToPtr player = mgr.ObjectById(actor->GetLastTouchedObject())) { + if (x420_curDamageRemTime <= 0.f) { + mgr.ApplyDamage(GetUniqueId(), player->GetUniqueId(), GetUniqueId(), GetContactDamage(), + CMaterialFilter::MakeInclude({EMaterialTypes::Solid}), zeus::skZero3f); + x420_curDamageRemTime = x424_damageWaitTime; + } + } + } + break; + case EScriptObjectMessage::Registered: + CElitePirate::AcceptScriptMsg(msg, uid, mgr); + x990_launcherId2 = mgr.AllocateUniqueId(); + CreateGrenadeLauncher(mgr, x990_launcherId2); + SetupCollisionManager(mgr); + GetBodyController()->SetLocomotionType(pas::ELocomotionType::Internal8); + x402_27_noXrayModel = false; + xa4c_initialXf = x34_transform; + xa98_maxEnergy = HealthInfo(mgr)->GetHP(); + if (auto* actor = static_cast(mgr.ObjectById(GetLauncherId()))) { + actor->RemoveMaterial(EMaterialTypes::Scannable, mgr); + } + if (auto* actor = static_cast(mgr.ObjectById(x990_launcherId2))) { + actor->RemoveMaterial(EMaterialTypes::Scannable, mgr); + } + GetKnockBackController().SetAutoResetImpulse(false); + SetupPathFindSearch(); + break; + case EScriptObjectMessage::Deleted: + CElitePirate::AcceptScriptMsg(msg, uid, mgr); + xa38_collisionActorMgr1->Destroy(mgr); + xa9c_collisionActorMgr2->Destroy(mgr); + mgr.FreeScriptObject(x990_launcherId2); + break; + case EScriptObjectMessage::InitializedInArea: + CElitePirate::AcceptScriptMsg(msg, uid, mgr); + + for (const SConnection& conn : GetConnectionList()) { + TUniqueId connId = mgr.GetIdForScript(conn.x8_objId); + if (connId == kInvalidUniqueId || conn.x0_state != EScriptObjectState::Attack) { + continue; + } + + if (conn.x4_msg == EScriptObjectMessage::Activate) { + if (TCastToPtr effect = mgr.ObjectById(connId)) { + x9b8_scriptEffects.emplace_back(connId, effect->GetName()); + } else if (TCastToPtr platform = mgr.ObjectById(connId)) { + x9dc_scriptPlatforms.emplace_back(connId, platform->GetName()); + platform->AddMaterial(EMaterialTypes::Target, EMaterialTypes::Orbit, EMaterialTypes::Character, mgr); + platform->RemoveMaterial(EMaterialTypes::Scannable, mgr); + CMaterialList excludes = platform->GetMaterialFilter().GetExcludeList(); + excludes.Add({EMaterialTypes::Player, EMaterialTypes::Character, EMaterialTypes::CollisionActor}); + CMaterialList includes = GetMaterialFilter().GetIncludeList(); + platform->SetMaterialFilter(CMaterialFilter::MakeIncludeExclude(includes, excludes)); + xae4_platformVuln = *platform->GetDamageVulnerability(); + xb54_platformColor = platform->GetDrawFlags().x4_color; + } else if (TCastToPtr sound = mgr.ObjectById(connId)) { + xaa0_scriptSounds.emplace_back(connId, sound->GetName()); + } + } else if (conn.x4_msg == EScriptObjectMessage::Follow) { + if (TCastToPtr waypoint = mgr.ObjectById(connId)) { + std::vector waypointPlatformIds; + waypointPlatformIds.reserve(3); + for (const SConnection& waypointConn : waypoint->GetConnectionList()) { + auto waypointConnId = mgr.GetIdForScript(waypointConn.x8_objId); + if (TCastToPtr platform = mgr.ObjectById(waypointConnId)) { + platform->AddMaterial(EMaterialTypes::Target, EMaterialTypes::Orbit, mgr); + waypointPlatformIds.push_back(waypointConnId); + } + } + x9a4_scriptWaypointPlatforms.emplace_back(connId, waypointPlatformIds); + } + } + } + break; + case EScriptObjectMessage::Damage: + if (uid == x990_launcherId2 && x990_launcherId2 != kInvalidUniqueId) { + GetBodyController()->GetCommandMgr().DeliverCmd( + CBCKnockBackCmd(GetTransform().frontVector(), pas::ESeverity::Eight)); + } + CElitePirate::AcceptScriptMsg(msg, uid, mgr); + if (uid == xa46_ && xa7c_xrayAlphaState == EXRayFadeState::WaitForTrigger) { + xa7c_xrayAlphaState = EXRayFadeState::FadeOut; + xa84_xrayAlphaStateTime = 0.f; + } + break; + case EScriptObjectMessage::InvulnDamage: + if (const TCastToConstPtr projectile = mgr.GetObjectById(uid)) { + if (xa4a_heartVisible) { + mgr.ApplyDamage(uid, xa46_, projectile->GetOwnerId(), projectile->GetDamageInfo(), + CMaterialFilter::MakeInclude({EMaterialTypes::Solid}), zeus::skZero3f); + } + } + SetShotAt(true, mgr); + } +} + +bool COmegaPirate::AggressionCheck(CStateManager& mgr, float arg) { + return x990_launcherId2 == kInvalidUniqueId && CElitePirate::AggressionCheck(mgr, arg); +} + +void COmegaPirate::Attack(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + x402_28_isMakingBigStrike = true; + x504_damageDur = 1.f; + } else if (msg == EStateMsg::Deactivate) { + x402_28_isMakingBigStrike = false; + x504_damageDur = 0.f; + } + CElitePirate::Attack(mgr, msg, dt); +} + +bool COmegaPirate::CodeTrigger(CStateManager&, float) { return xb78_codeTrigger; } + +void COmegaPirate::Cover(CStateManager& mgr, EStateMsg msg, float dt) { + CElitePirate::Cover(mgr, msg, dt); + if (msg == EStateMsg::Activate) { + xad4_cachedSpeed = x3b4_speed; + xad8_cover = true; + } else if (msg == EStateMsg::Deactivate) { + xad8_cover = false; + } +} + +bool COmegaPirate::CoverBlown(CStateManager&, float) { + if (x9b4_) { + x9b4_ = false; + xb5c_ = 0.f; + return true; + } + return false; +} + +void COmegaPirate::Dizzy(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + xa44_targetable = true; + } else if (msg == EStateMsg::Update) { + GetBodyController()->GetCommandMgr().DeliverCmd(CBCLoopReactionCmd(pas::EReactionType::Two)); + } else if (msg == EStateMsg::Deactivate) { + GetBodyController()->GetCommandMgr().DeliverCmd(CBodyStateCmd(EBodyStateCmd::ExitState)); + } +} + +void COmegaPirate::DoubleSnap(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + SendScriptMsgs(EScriptObjectState::MaxReached, mgr, EScriptObjectMessage::None); + SetShotAt(false, mgr); + SetState(CElitePirate::EState::Zero); + xa44_targetable = false; + xa4a_heartVisible = false; + xa88_xrayFadeInTrigger = false; + xa8c_ = 3.f; + for (auto& entry : x9dc_scriptPlatforms) { + if (auto* platform = static_cast(mgr.ObjectById(entry.first))) { + platform->SetActive(true); + platform->SetDamageVulnerability(xae4_platformVuln); + platform->AddMaterial(EMaterialTypes::Orbit, EMaterialTypes::Target, mgr); + platform->SetDisableXRayAlpha(false); + platform->SetXRayFog(true); + } + } + xb64_ = 17.f; + AddMaterial(EMaterialTypes::Scannable, mgr); + } else if (msg == EStateMsg::Update) { + if (GetState() == CElitePirate::EState::Zero) { + if (GetBodyController()->GetCurrentStateId() == pas::EAnimationState::Step) { + SetState(CElitePirate::EState::Two); + } else { + GetBodyController()->GetCommandMgr().DeliverCmd( + CBCStepCmd(pas::EStepDirection::Backward, pas::EStepType::BreakDodge)); + } + } else if (GetState() == CElitePirate::EState::Two && + GetBodyController()->GetCurrentStateId() != pas::EAnimationState::Step) { + SetState(CElitePirate::EState::Over); + } + } else if (msg == EStateMsg::Deactivate) { + if (auto* launcher = static_cast(mgr.ObjectById(GetLauncherId()))) { + launcher->SetFollowPlayer(true); + } + if (auto* launcher = static_cast(mgr.ObjectById(x990_launcherId2))) { + launcher->SetFollowPlayer(true); + } + } +} + +void COmegaPirate::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) { + switch (type) { + case EUserEventType::EggLay: + if (x990_launcherId2 != kInvalidUniqueId) { + if (auto* entity = mgr.ObjectById(x990_launcherId2)) { + mgr.SendScriptMsg(entity, GetUniqueId(), EScriptObjectMessage::Action); + } + } + break; + case EUserEventType::FadeIn: + x9a1_fadeIn = true; + break; + case EUserEventType::FadeOut: + if (x994_normalFadeState != ENormalFadeState::Two && x9a1_fadeIn) { + x994_normalFadeState = ENormalFadeState::One; + xa30_skeletonFadeState = ESkeletonFadeState::FadeIn; + } + break; + case EUserEventType::ObjectPickUp: + xab4_.clear(); + xac8_ = 0; + ++xacc_; + if (xac4_ == 0) { + sub_8028cbec(2, mgr); + } else if (xac4_ == 1) { + sub_8028cbec(1, mgr); + sub_8028cbec(1, mgr); + } else if (xac4_ == 2) { + sub_8028cbec(2, mgr); + sub_8028cbec(1, mgr); + } else if (xac4_ == 3) { + sub_8028cbec(1, mgr); + sub_8028cbec(1, mgr); + sub_8028cbec(1, mgr); + } + SendScriptMsgs(EScriptObjectState::Arrived, mgr, EScriptObjectMessage::None); + break; + case EUserEventType::Projectile: + case EUserEventType::DamageOn: + case EUserEventType::DamageOff: + case EUserEventType::ScreenShake: + case EUserEventType::BeginAction: + case EUserEventType::BecomeShootThrough: + default: + CElitePirate::DoUserAnimEvent(mgr, node, type, dt); + } +} + +void COmegaPirate::Enraged(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + SetState(EState::Zero); + } else if (msg == EStateMsg::Update) { + if (GetState() == CElitePirate::EState::Zero) { + if (GetBodyController()->GetCurrentStateId() == pas::EAnimationState::Taunt) { + SetState(CElitePirate::EState::Two); + } else { + GetBodyController()->GetCommandMgr().DeliverCmd(CBCTauntCmd(pas::ETauntType::Zero)); + } + } else if (GetState() == CElitePirate::EState::Two && + GetBodyController()->GetCurrentStateId() != pas::EAnimationState::Taunt) { + SetState(CElitePirate::EState::Over); + } + } else if (msg == EStateMsg::Deactivate) { + xadf_launcher1FollowPlayer = true; + xae0_launcher2FollowPlayer = true; + } +} + +void COmegaPirate::Explode(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + SetState(EState::Zero); + xad0_scaleUpTrigger = false; + } else if (msg == EStateMsg::Update) { + if (GetState() == CElitePirate::EState::Zero) { + if (GetBodyController()->GetCurrentStateId() == pas::EAnimationState::Step) { + SetState(CElitePirate::EState::Two); + } else { + GetBodyController()->GetCommandMgr().DeliverCmd( + CBCStepCmd(pas::EStepDirection::Forward, pas::EStepType::Dodge)); + } + } else if (GetState() == CElitePirate::EState::Two && + GetBodyController()->GetCurrentStateId() != pas::EAnimationState::Step) { + SetState(CElitePirate::EState::Over); + } + } else if (msg == EStateMsg::Deactivate) { + GetBodyController()->SetLocomotionType(xa40_locomotionType); + } +} + +void COmegaPirate::Faint(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + GetBodyController()->GetCommandMgr().DeliverCmd(CBCLoopReactionCmd(pas::EReactionType::Zero)); + xa44_targetable = true; + xa4a_heartVisible = true; + if (xa7c_xrayAlphaState == EXRayFadeState::WaitForTrigger) { + xa8c_ = 0.333f; + } + for (const auto& entry : x9dc_scriptPlatforms) { + if (auto* platform = static_cast(mgr.ObjectById(entry.first))) { + platform->SetActive(true); + } + } + } else if (msg == EStateMsg::Update) { + if (xb4c_armorPiecesHealed < 4 && x9c8_scaleState == EScaleState::None && xb58_ >= 2.5f) { + float alpha = std::min(xb50_, 1.f); + float invAlpha = 1.f - alpha; + size_t idx = 0; + for (const auto& entry : x9dc_scriptPlatforms) { + if (auto* platform = static_cast(mgr.ObjectById(entry.first))) { + if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay) { + if (xb4c_armorPiecesHealed > idx) { + CModelFlags flags{5, 0, 3, zeus::skBlack}; + platform->SetDrawFlags(flags); + } else if (xb4c_armorPiecesHealed == idx) { + if (!xb6e_) { + SendScriptMsgs(EScriptObjectState::Entered, mgr, EScriptObjectMessage::None); + xb6e_ = true; + } + CModelFlags flags{5, 0, 3, zeus::CColor{invAlpha, alpha}}; + platform->SetDrawFlags(flags); + } + } else { + CModelFlags flags{5, 0, 3, zeus::CColor{1.f, 0.f}}; + platform->SetDrawFlags(flags); + } + } + ++idx; + } + if (xb50_ > 1.f) { + ++xb4c_armorPiecesHealed; + xb50_ = 0.f; + xb58_ = 0.f; + xb6e_ = false; + } + xb50_ += dt; + } + xb58_ += dt; + GetBodyController()->GetCommandMgr().DeliverCmd(CBCLoopReactionCmd(pas::EReactionType::Zero)); + } else if (msg == EStateMsg::Deactivate) { + GetBodyController()->GetCommandMgr().DeliverCmd(CBodyStateCmd(EBodyStateCmd::ExitState)); + if (xb58_ >= 2.5f) { + ++xb4c_armorPiecesHealed; + } + } +} + +void COmegaPirate::Growth(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + x9c8_scaleState = EScaleState::ScaleDownY; + xad0_scaleUpTrigger = false; + RemoveMaterial(EMaterialTypes::RadarObject, EMaterialTypes::Scannable, mgr); + xb6c_ = false; + xb6d_ = false; + ProcessSoundEvent(SFXsfx0B27, 1.f, 0, 0.1f, 1000.f, 0.16f, 1.f, zeus::skZero3f, GetTranslation(), + mgr.GetNextAreaId(), mgr, false); + } else if (msg == EStateMsg::Update) { + if (xb68_ == 0) { + if (x330_stateMachineState.GetTime() > 0.3f * xb64_ && !xb6c_) { + SendScriptMsgs(EScriptObjectState::Exited, mgr, EScriptObjectMessage::None); + xb6c_ = true; + } + if (x330_stateMachineState.GetTime() > 0.6f * xb64_ && !xb6d_) { + SendScriptMsgs(EScriptObjectState::Exited, mgr, EScriptObjectMessage::None); + xb6d_ = true; + } + } else if (x330_stateMachineState.GetTime() > 0.5f * xb64_ && !xb6c_) { + SendScriptMsgs(EScriptObjectState::Exited, mgr, EScriptObjectMessage::None); + xb6c_ = true; + } + } else if (msg == EStateMsg::Deactivate) { + TeleportToFurthestPlatform(mgr); + xad0_scaleUpTrigger = true; + AddMaterial(EMaterialTypes::RadarObject, mgr); + ProcessSoundEvent(SFXsfx0B28, 1.f, 0, 0.1f, 1000.f, 0.16f, 1.f, zeus::skZero3f, GetTranslation(), + mgr.GetNextAreaId(), mgr, false); + } +} + +void COmegaPirate::JumpBack(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + SetShotAt(false, mgr); + SetState(CElitePirate::EState::Two); + xade_armorPiecesDestroyed = 0; + xadf_launcher1FollowPlayer = false; + xae0_launcher2FollowPlayer = false; + xb68_ = 0; + xa40_locomotionType = GetBodyController()->GetLocomotionType(); + GetBodyController()->SetLocomotionType(pas::ELocomotionType::Internal5); + GetBodyController()->GetCommandMgr().DeliverCmd( + CBCKnockBackCmd(GetTransform().frontVector(), pas::ESeverity::Five)); + for (const auto& entry : x9dc_scriptPlatforms) { + if (auto* platform = static_cast(mgr.ObjectById(entry.first))) { + platform->SetActive(false); + } + } + } else if (msg == EStateMsg::Update) { + if (GetState() == CElitePirate::EState::Two && + GetBodyController()->GetCurrentStateId() != pas::EAnimationState::KnockBack) { + SetState(CElitePirate::EState::Over); + } + } +} + +bool COmegaPirate::Landed(CStateManager& mgr, float arg) { + fmt::print(FMT_STRING("OMEGA: {} pieces healed\n"), xb4c_armorPiecesHealed); + return xb4c_armorPiecesHealed == 4; +} + +zeus::CVector3f COmegaPirate::GetOrbitPosition(const CStateManager& mgr) const { + if (x990_launcherId2 != kInvalidUniqueId && + mgr.GetPlayerState()->GetCurrentVisor() == CPlayerState::EPlayerVisor::Thermal) { + if (const auto* actor = static_cast(mgr.GetObjectById(x990_launcherId2))) { + return GetLockOnPosition(actor); + } + } + return CElitePirate::GetOrbitPosition(mgr); +} + +bool COmegaPirate::HearPlayer(CStateManager& mgr, float arg) { return xa3c_hearPlayer; } + +void COmegaPirate::PathFind(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + xad4_cachedSpeed = x3b4_speed; + x3b4_speed = 1.4f * xad4_cachedSpeed; + } else if (msg == EStateMsg::Update) { + if (GetBodyController()->GetCurrentStateId() == pas::EAnimationState::KnockBack) { + x3b4_speed = xad4_cachedSpeed; + } else if (xad4_cachedSpeed == x3b4_speed) { + x3b4_speed = 1.4f * xad4_cachedSpeed; + } + } else if (msg == EStateMsg::Deactivate) { + x3b4_speed = xad4_cachedSpeed; + } + CElitePirate::PathFind(mgr, msg, dt); +} + +void COmegaPirate::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) { + CElitePirate::PreRender(mgr, frustum); + if (mgr.GetPlayerState()->GetCurrentVisor() == CPlayerState::EPlayerVisor::XRay) { + xb4_drawFlags = CModelFlags{1, 0, 3, zeus::CColor{xa80_xrayAlpha}}; + } +} + +void COmegaPirate::Render(CStateManager& mgr) { + auto* mData = GetModelData(); + auto* animData = mData->GetAnimationData(); + + CGraphics::SetModelMatrix(GetTransform() * zeus::CTransform::Scale(mData->GetScale())); + + if (mgr.GetPlayerState()->GetCurrentVisor() != CPlayerState::EPlayerVisor::XRay && xa2c_skeletonAlpha > 0.f) { + const CModelFlags flags{5, 0, 3, zeus::CColor{1.f, xa2c_skeletonAlpha}}; + animData->Render(x9f0_skeletonModel, flags, std::nullopt, nullptr); + } + if (x9a0_visible) { + bool isXRay = mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay; + if (isXRay) { + g_Renderer->SetWorldFog(ERglFogMode::None, 0.f, 1.f, zeus::skBlack); + const CModelFlags flags{5, 0, 1, zeus::CColor{1.f, 0.2f}}; + auto& model = *animData->GetModelData().GetObj(); + animData->Render(model, flags, std::nullopt, nullptr); + } + CPatterned::Render(mgr); + if (isXRay) { + mgr.SetupFogForArea(GetAreaIdAlways()); + } + } +} + +void COmegaPirate::Retreat(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + SetShotAt(false, mgr); + SetState(CElitePirate::EState::Zero); + SendScriptMsgs(EScriptObjectState::Inside, mgr, EScriptObjectMessage::None); + xad0_scaleUpTrigger = false; + xa44_targetable = false; + xa4a_heartVisible = false; + xb5c_ = 0.f; + xb60_ = 0.f; + xb64_ = 5.f; + ++xb68_; + } else if (msg == EStateMsg::Update) { + if (GetState() == CElitePirate::EState::Zero) { + if (GetBodyController()->GetCurrentStateId() == pas::EAnimationState::Step) { + SetState(CElitePirate::EState::Two); + } else { + GetBodyController()->GetCommandMgr().DeliverCmd( + CBCStepCmd(pas::EStepDirection::Forward, pas::EStepType::BreakDodge)); + } + } else if (GetState() == CElitePirate::EState::Two && + GetBodyController()->GetCurrentStateId() != pas::EAnimationState::Step) { + SetState(CElitePirate::EState::Over); + } + } +} + +void COmegaPirate::Run(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + xad4_cachedSpeed = x3b4_speed; + x3b4_speed = 1.4f * xad4_cachedSpeed; + } else if (msg == EStateMsg::Update) { + if (GetBodyController()->GetCurrentStateId() == pas::EAnimationState::KnockBack) { + x3b4_speed = xad4_cachedSpeed; + } else if (xad4_cachedSpeed == x3b4_speed) { + x3b4_speed = 1.4f * xad4_cachedSpeed; + } + } else if (msg == EStateMsg::Deactivate) { + x3b4_speed = xad4_cachedSpeed; + } + CElitePirate::Run(mgr, msg, dt); +} + +bool COmegaPirate::ShotAt(CStateManager& mgr, float arg) { return CElitePirate::ShotAt(mgr, arg); } + +bool COmegaPirate::ShouldCallForBackup(CStateManager& mgr, float arg) { + if (CElitePirate::ShouldCallForBackup(mgr, arg)) { + return ShouldCallForBackupFromLauncher(mgr, x990_launcherId2); + } + return false; +} + +bool COmegaPirate::ShouldFire(CStateManager& mgr, float arg) { + if (CElitePirate::ShouldFire(mgr, arg)) { + return ShouldFireFromLauncher(mgr, x990_launcherId2); + } + return false; +} + +bool COmegaPirate::ShouldMove(CStateManager& mgr, float arg) { return xb64_ < x330_stateMachineState.GetTime(); } + +void COmegaPirate::Shuffle(CStateManager& mgr, EStateMsg msg, float dt) {} + +void COmegaPirate::Skid(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + SetState(EState::Zero); + } else if (msg == EStateMsg::Update) { + if (GetState() == CElitePirate::EState::Zero) { + if (GetBodyController()->GetCurrentStateId() == pas::EAnimationState::Step) { + SetState(CElitePirate::EState::Two); + } else { + GetBodyController()->GetCommandMgr().DeliverCmd( + CBCStepCmd(pas::EStepDirection::Forward, pas::EStepType::Normal)); + } + } else if (GetState() == CElitePirate::EState::Two && + GetBodyController()->GetCurrentStateId() != pas::EAnimationState::Step) { + SetState(CElitePirate::EState::Over); + } + } +} + +void COmegaPirate::Suck(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + SetState(CElitePirate::EState::Zero); + xa7c_xrayAlphaState = EXRayFadeState::FadeOut; + xa88_xrayFadeInTrigger = true; + } else if (msg == EStateMsg::Update) { + if (GetState() == CElitePirate::EState::Zero) { + if (GetBodyController()->GetCurrentStateId() == pas::EAnimationState::Step) { + SetState(CElitePirate::EState::Two); + } else { + GetBodyController()->GetCommandMgr().DeliverCmd( + CBCStepCmd(pas::EStepDirection::Backward, pas::EStepType::Normal)); + GetBodyController()->SetLocomotionType(pas::ELocomotionType::Relaxed); + } + } else if (GetState() == CElitePirate::EState::Two && + GetBodyController()->GetCurrentStateId() != pas::EAnimationState::Step) { + SetState(CElitePirate::EState::Over); + } + } else if (msg == EStateMsg::Deactivate) { + for (const auto& entry : x9dc_scriptPlatforms) { + if (auto* platform = static_cast(mgr.ObjectById(entry.first))) { + platform->SetDamageVulnerability(CDamageVulnerability::ImmuneVulnerabilty()); + platform->RemoveMaterial(EMaterialTypes::Target, EMaterialTypes::Orbit, mgr); + platform->SetDisableXRayAlpha(true); + CModelFlags flags{5, 0, 3, zeus::CColor{1.f, 0.f}}; + platform->SetDrawFlags(flags); + platform->SetXRayFog(false); + } + } + xb50_ = 0.f; + xb58_ = 2.5f; + xb4c_armorPiecesHealed = 0; + } +} + +void COmegaPirate::TargetPatrol(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + xad4_cachedSpeed = x3b4_speed; + x3b4_speed = 1.4f * xad4_cachedSpeed; + } else if (msg == EStateMsg::Update) { + if (GetBodyController()->GetCurrentStateId() == pas::EAnimationState::KnockBack) { + x3b4_speed = xad4_cachedSpeed; + } else if (xad4_cachedSpeed == x3b4_speed) { + x3b4_speed = 1.4f * xad4_cachedSpeed; + } + } else if (msg == EStateMsg::Deactivate) { + x3b4_speed = xad4_cachedSpeed; + } + CElitePirate::TargetPatrol(mgr, msg, dt); +} + +void COmegaPirate::Think(float dt, CStateManager& mgr) { + if (!GetActive()) { + return; + } + + SetAlert(true); + CElitePirate::Think(dt, mgr); + + { + float maxHealth = xa98_maxEnergy; + CHealthInfo* healthInfo = HealthInfo(mgr); + if (healthInfo->GetHP() > 0.2f * maxHealth) { + if (healthInfo->GetHP() > 0.7f * maxHealth) { + if (xacc_ > 4) { + xac4_ = 1; + } + } else { + xac4_ = 2; + } + } else { + xac4_ = 3; + } + } + + UpdateActorTransform(mgr, x990_launcherId2, "grenadeLauncher2_LCTR"sv); + + UpdateNormalAlpha(mgr, dt); + UpdateSkeletonAlpha(mgr, dt); + UpdateXRayAlpha(mgr, dt); + if ((!x9a1_fadeIn || xa4a_heartVisible) && mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay && xa44_targetable) { + AddMaterial(EMaterialTypes::Target, EMaterialTypes::Orbit, mgr); + if (x9c8_scaleState == EScaleState::WaitForTrigger) { + xa38_collisionActorMgr1->SetActive(mgr, false); + xa9c_collisionActorMgr2->SetActive(mgr, false); + } else { + xa38_collisionActorMgr1->SetActive(mgr, true); + xa9c_collisionActorMgr2->SetActive(mgr, true); + if (auto* entity = mgr.ObjectById(xa48_)) { + entity->SetActive(false); + } + } + } else { + RemoveMaterial(EMaterialTypes::Target, EMaterialTypes::Orbit, mgr); + xa38_collisionActorMgr1->SetActive(mgr, false); + if (x9a1_fadeIn) { + xa9c_collisionActorMgr2->SetActive(mgr, true); + if (auto* entity = mgr.ObjectById(xa48_)) { + entity->SetActive(true); + } + } else { + xa9c_collisionActorMgr2->SetActive(mgr, false); + if (auto* entity = mgr.ObjectById(xa48_)) { + entity->SetActive(false); + } + } + } + + UpdateScale(mgr, dt); + xa38_collisionActorMgr1->Update(dt, mgr, CCollisionActorManager::EUpdateOptions::ObjectSpace); + xa9c_collisionActorMgr2->Update(dt, mgr, CCollisionActorManager::EUpdateOptions::ObjectSpace); + + if (auto* entity = static_cast(mgr.ObjectById(xa46_))) { + float hp = GetHealthInfo(mgr)->GetHP(); + *HealthInfo(mgr) = *entity->GetHealthInfo(mgr); + float hpChange = hp - GetHealthInfo(mgr)->GetHP(); + xb5c_ += hpChange; + xb60_ += hpChange; + } + + if (GetHealthInfo(mgr)->GetHP() > 0.f) { + if (xb5c_ <= 100.f) { + if (xb60_ > 20.f) { + GetBodyController()->GetCommandMgr().DeliverCmd( + CBCAdditiveReactionCmd(pas::EAdditiveReactionType::One, 1.f, false)); + xb60_ = 0.f; + } + } else { + x9b4_ = true; + } + } else { + DeathDestroy(mgr); + } + + sub_8028c704(mgr, dt); + + for (auto& entry : x9dc_scriptPlatforms) { + auto* platform = static_cast(mgr.ObjectById(entry.first)); + if ((!xb78_codeTrigger && !xb79_) || xa4a_heartVisible) { + platform->RemoveMaterial(EMaterialTypes::Target, EMaterialTypes::Orbit, mgr); + } else { + platform->AddMaterial(EMaterialTypes::Target, EMaterialTypes::Orbit, mgr); + } + } + + { + const CPlayerState& playerState = *mgr.GetPlayerState(); + CPlayer& player = mgr.GetPlayer(); + if (GetCollisionActorManager().GetActive() && playerState.IsFiringComboBeam() && + playerState.GetCurrentBeam() == CPlayerState::EBeamId::Wave && xad8_cover) { + AddMaterial(EMaterialTypes::Target, mgr); + player.ResetAimTargetPrediction(GetUniqueId()); + for (auto& entry : x9dc_scriptPlatforms) { + if (auto* platform = static_cast(mgr.ObjectById(entry.first))) { + platform->RemoveMaterial(EMaterialTypes::Target, mgr); + } + } + player.GetPlayerGun()->GetAuxWeapon().SetNewTarget(GetUniqueId(), mgr); + } else if (!xa4a_heartVisible) { + RemoveMaterial(EMaterialTypes::Target, mgr); + for (auto& entry : x9dc_scriptPlatforms) { + if (auto* platform = static_cast(mgr.ObjectById(entry.first))) { + platform->AddMaterial(EMaterialTypes::Target, mgr); + } + } + CAuxWeapon& weapon = player.GetPlayerGun()->GetAuxWeapon(); + if (weapon.HasTarget(mgr) == GetUniqueId()) { + if (player.ValidateOrbitTargetId(player.GetOrbitTargetId(), mgr) == CPlayer::EOrbitValidationResult::OK) { + weapon.SetNewTarget(player.GetOrbitTargetId(), mgr); + } else { + weapon.SetNewTarget(kInvalidUniqueId, mgr); + } + } + } + } + + if (auto* launcher = static_cast(mgr.ObjectById(GetLauncherId()))) { + launcher->SetFollowPlayer(xadf_launcher1FollowPlayer); + } + if (auto* launcher = static_cast(mgr.ObjectById(x990_launcherId2))) { + launcher->SetFollowPlayer(xae0_launcher2FollowPlayer); + } + + if (x9ec_decrement) { + x9ec_decrement = false; + x330_stateMachineState.SetState(mgr, *this, GetStateMachine(), "JumpBack"sv); + } + + if (xb68_ > 1) { + DoUserAnimEvent(mgr, CInt32POINode{}, EUserEventType::ObjectPickUp, dt); + xb68_ = 0; + } + + if (xb8c_ > 0.f) { + const zeus::CAABox& box = GetBoundingBox(); + CGameCollision::AvoidStaticCollisionWithinRadius(mgr, *this, 8, dt, 1.f, 1.5f * (box.max.x() - box.min.x()), + 10000.f, 0.25f); + xb8c_ = 0.f; + } + xb8c_ += dt; +} + +void COmegaPirate::WallDetach(CStateManager& mgr, EStateMsg msg, float dt) { + if (msg == EStateMsg::Activate) { + SetState(CElitePirate::EState::Zero); + } else if (msg == EStateMsg::Update) { + if (GetState() == CElitePirate::EState::Zero) { + if (GetBodyController()->GetCurrentStateId() == pas::EAnimationState::Step) { + SetState(CElitePirate::EState::Two); + } else { + GetBodyController()->GetCommandMgr().DeliverCmd(CBCStepCmd(pas::EStepDirection::Left, pas::EStepType::Dodge)); + } + } else if (GetState() == CElitePirate::EState::Two && + GetBodyController()->GetCurrentStateId() != pas::EAnimationState::Step) { + SetState(CElitePirate::EState::Over); + } + } else if (msg == EStateMsg::Deactivate) { + mgr.SetBossParams(GetUniqueId(), xa98_maxEnergy, 89); + xb79_ = true; + } +} + +void COmegaPirate::WallHang(CStateManager& mgr, EStateMsg msg, float dt) {} + +void COmegaPirate::SetupHealthInfo(CStateManager& mgr) { + CElitePirate::SetupHealthInfo(mgr); + SetupLauncherHealthInfo(mgr, x990_launcherId2); +} + +void COmegaPirate::SetLaunchersActive(CStateManager& mgr, bool val) { + CElitePirate::SetLaunchersActive(mgr, val); + SetLauncherActive(mgr, val, x990_launcherId2); +} + +void COmegaPirate::CreateFlash(CStateManager& mgr, float arg) { + mgr.AddObject(new CFlash(mgr.AllocateUniqueId(), CEntityInfo{GetAreaIdAlways(), CEntity::NullConnectionList}, + GetRenderBounds().center(), xb70_thermalSpot, arg)); +} + +void COmegaPirate::SetupCollisionManager(CStateManager& mgr) { + std::vector sphereJoints; + sphereJoints.reserve(skSphereJoints.size()); + AddSphereCollisionList(skSphereJoints.data(), skSphereJoints.size(), sphereJoints); + xa38_collisionActorMgr1 = + std::make_unique(mgr, GetUniqueId(), GetAreaIdAlways(), sphereJoints, true); + SetupCollisionActorInfo1(xa38_collisionActorMgr1, mgr); + xa46_ = xa38_collisionActorMgr1->GetCollisionDescFromIndex(0).GetCollisionActorId(); + if (auto* actor = static_cast(mgr.ObjectById(xa46_))) { + *actor->HealthInfo(mgr) = *HealthInfo(mgr); + } + + std::vector obbJoints; + obbJoints.reserve(skObbJoints.size()); + AddOBBAutoSizeCollisionList(skObbJoints.data(), skObbJoints.size(), obbJoints); + xa9c_collisionActorMgr2 = + std::make_unique(mgr, GetUniqueId(), GetAreaIdAlways(), obbJoints, true); + SetupCollisionActorInfo2(xa9c_collisionActorMgr2, mgr); + xa48_ = xa9c_collisionActorMgr2->GetCollisionDescFromIndex(0).GetCollisionActorId(); +} + +void COmegaPirate::AddSphereCollisionList(const SSphereJointInfo* joints, size_t count, + std::vector& outJoints) const { + const CAnimData* animData = GetModelData()->GetAnimationData(); + for (size_t i = 0; i < count; ++i) { + const auto& joint = joints[i]; + const CSegId seg = animData->GetLocatorSegId(joint.name); + if (seg.IsInvalid()) { + continue; + } + outJoints.emplace_back(CJointCollisionDescription::SphereCollision(seg, joint.radius, joint.name, 0.001f)); + } +} + +void COmegaPirate::AddOBBAutoSizeCollisionList(const SOBBJointInfo* joints, size_t count, + std::vector& outJoints) const { + const CAnimData* animData = GetModelData()->GetAnimationData(); + for (size_t i = 0; i < count; ++i) { + const auto& joint = joints[i]; + const CSegId from = animData->GetLocatorSegId(joint.from); + const CSegId to = animData->GetLocatorSegId(joint.to); + if (to.IsInvalid() || from.IsInvalid()) { + continue; + } + outJoints.emplace_back(CJointCollisionDescription::OBBAutoSizeCollision( + from, to, joint.bounds, CJointCollisionDescription::EOrientationType::One, + "Omega_Pirate_OBB_"s + std::to_string(i), 0.001f)); + } +} + +void COmegaPirate::SetupCollisionActorInfo1(const std::unique_ptr& actMgr, CStateManager& mgr) { + for (size_t i = 0; i < actMgr->GetNumCollisionActors(); ++i) { + const auto& colDesc = actMgr->GetCollisionDescFromIndex(i); + const TUniqueId uid = colDesc.GetCollisionActorId(); + if (TCastToPtr act = mgr.ObjectById(uid)) { + act->AddMaterial(EMaterialTypes::ScanPassthrough, EMaterialTypes::CameraPassthrough, EMaterialTypes::AIJoint, + EMaterialTypes::Immovable, mgr); + const CMaterialFilter& selfFilter = GetMaterialFilter(); + const CMaterialFilter& actFilter = act->GetMaterialFilter(); + CMaterialFilter filter = + CMaterialFilter::MakeIncludeExclude(selfFilter.GetIncludeList(), selfFilter.GetExcludeList()); + filter.IncludeList().Add(actFilter.GetIncludeList()); + filter.ExcludeList().Add(actFilter.GetExcludeList()); + filter.ExcludeList().Add(EMaterialTypes::Platform); + act->SetMaterialFilter(filter); + act->RemoveMaterial(EMaterialTypes::ProjectilePassthrough, mgr); + } + } +} + +void COmegaPirate::SetupCollisionActorInfo2(const std::unique_ptr& actMgr, CStateManager& mgr) { + for (size_t i = 0; i < actMgr->GetNumCollisionActors(); ++i) { + const auto& colDesc = actMgr->GetCollisionDescFromIndex(i); + const TUniqueId uid = colDesc.GetCollisionActorId(); + if (TCastToPtr act = mgr.ObjectById(uid)) { + act->AddMaterial(EMaterialTypes::ScanPassthrough, EMaterialTypes::CameraPassthrough, EMaterialTypes::AIJoint, + EMaterialTypes::Immovable, mgr); + const CMaterialFilter& selfFilter = GetMaterialFilter(); + const CMaterialFilter& actFilter = act->GetMaterialFilter(); + CMaterialFilter filter = + CMaterialFilter::MakeIncludeExclude(selfFilter.GetIncludeList(), selfFilter.GetExcludeList()); + filter.IncludeList().Add(actFilter.GetIncludeList()); + filter.IncludeList().Add(EMaterialTypes::Player); + filter.ExcludeList().Add(actFilter.GetExcludeList()); + filter.ExcludeList().Remove(EMaterialTypes::Player); + filter.ExcludeList().Add(EMaterialTypes::Platform); + act->SetMaterialFilter(filter); + act->RemoveMaterial(EMaterialTypes::ProjectilePassthrough, mgr); + act->SetDamageVulnerability(CDamageVulnerability::ReflectVulnerabilty()); + } + } +} + +u8 COmegaPirate::sub_8028bfac() const { + std::array arr{0, 0, 0, 0}; + for (const auto i : xab4_) { + ++arr[i]; + } + u8 ret = 0; + for (size_t i = 0; i < arr.size(); ++i) { + if (xb7c_[i] != 0 || arr[i] != 0) { + ++ret; + } + } + return ret; +} + +void COmegaPirate::sub_8028cbec(u32 arg, CStateManager& mgr) { + int i = mgr.GetActiveRandom()->Next() % 4; + u32 v = 3 - (xab4_.size() + sub_8028c230()); + u32 ct = std::min(arg, v); + + if (sub_8028bfac() < 2) { + for (u32 n = 0; n < ct; ++n) { + xab4_.push_back(i); + } + } else { + sub_8028c840(ct, mgr); + } +} + +u8 COmegaPirate::sub_8028c230() const { return xb7c_[0] + xb7c_[1] + xb7c_[2] + xb7c_[3]; } + +void COmegaPirate::sub_8028c840(u32 arg, CStateManager& mgr) { + std::array arr{0, 0, 0, 0}; + for (const auto i : xab4_) { + ++arr[i]; + } + std::vector vec; + for (size_t i = 0; i < arr.size(); ++i) { + if (xb7c_[i] != 0 || arr[i] != 0) { + vec.push_back(i); + } + } + if (vec.empty()) { + sub_8028cbec(arg, mgr); + } else { + s32 rand = mgr.GetActiveRandom()->Next(); + int sz = vec.size(); + int val = vec[rand - (rand / sz) * sz]; + u32 v = 3 - (xab4_.size() + sub_8028c230()); + u32 ct = std::min(arg, v); + for (u32 n = 0; n < ct; ++n) { + xab4_.push_back(val); + } + } +} + +void COmegaPirate::TeleportToFurthestPlatform(CStateManager& mgr) { + size_t waypointIdx = 0; + float maxDist = 0.f; + zeus::CVector3f pos; + for (size_t i = 0; i < x9a4_scriptWaypointPlatforms.size(); ++i) { + const auto& entry = x9a4_scriptWaypointPlatforms[i]; + if (TCastToConstPtr waypoint = mgr.GetObjectById(entry.first)) { + auto waypointPos = waypoint->GetTranslation(); + float dist = (mgr.GetPlayer().GetTranslation() - waypointPos).magnitude(); + if (dist > maxDist && waypoint->GetUniqueId() != xada_lastWaypointId) { + waypointIdx = i; + maxDist = dist; + pos = waypointPos; + } + } + } + SetTranslation(FindGround(pos, mgr)); + + auto waypointId = x9a4_scriptWaypointPlatforms[waypointIdx].first; + xada_lastWaypointId = waypointId; + if (TCastToPtr waypoint = mgr.ObjectById(waypointId)) { + waypoint->SendScriptMsgs(EScriptObjectState::Arrived, mgr, EScriptObjectMessage::None); + } + + const zeus::CVector2f distXY = (mgr.GetPlayer().GetTranslation().toVec2f() - GetTranslation().toVec2f()).normalized(); + const zeus::CVector2f frontVecXY = GetTransform().frontVector().toVec2f().normalized(); + const zeus::CQuaternion quat = + zeus::CQuaternion::shortestRotationArc(zeus::CVector3f{frontVecXY, 0.f}, zeus::CVector3f{distXY, 0.f}); + SetTransform(zeus::CTransform{GetTransform().basis * zeus::CMatrix3f{quat}, GetTranslation()}); +} + +zeus::CVector3f COmegaPirate::FindGround(const zeus::CVector3f& pos, CStateManager& mgr) const { + auto result = mgr.RayStaticIntersection(pos, zeus::skDown, 30.f, CMaterialFilter::MakeInclude(EMaterialTypes::Solid)); + if (result.IsValid()) { + return result.GetPoint(); + } + return pos; +} + +void COmegaPirate::UpdateNormalAlpha(CStateManager& mgr, float dt) { + if (x994_normalFadeState == ENormalFadeState::One) { + x99c_normalAlpha = 1.f - std::min(x998_normalFadeTime, 1.25f) / 1.25f; + x42c_color.a() = x99c_normalAlpha; + if (x998_normalFadeTime > 1.25f) { + x994_normalFadeState = ENormalFadeState::Two; + x9a1_fadeIn = false; + x998_normalFadeTime = 0.f; + } + x998_normalFadeTime += dt; + x9a0_visible = true; + } else if (x994_normalFadeState == ENormalFadeState::Two) { + x99c_normalAlpha = 0.f; + if (x998_normalFadeTime > 1.5f && x9a1_fadeIn) { + CreateFlash(mgr, 0.f); + x994_normalFadeState = ENormalFadeState::Three; + x998_normalFadeTime = 0.f; + } + x998_normalFadeTime += dt; + x9a0_visible = false; + } else if (x994_normalFadeState == ENormalFadeState::Three) { + x99c_normalAlpha = std::min(x998_normalFadeTime, 1.f) / 1.25f; + if (x998_normalFadeTime > 1.f) { + x994_normalFadeState = ENormalFadeState::Zero; + x998_normalFadeTime = 0.f; + } + x998_normalFadeTime += dt; + x9a0_visible = true; + } else { + x99c_normalAlpha = 1.f; + x9a0_visible = true; + } + + float alpha = x99c_normalAlpha; + if (mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay) { + alpha = 0.f; + x99c_normalAlpha = 1.f; + x9a0_visible = true; + } + x42c_color.a() = x99c_normalAlpha; + + if (alpha >= 1.f) { + if (auto* launcher = static_cast(mgr.ObjectById(GetLauncherId()))) { + launcher->SetVisible(true); + launcher->SetColor(zeus::CColor{0.f}); + } + if (auto* launcher = static_cast(mgr.ObjectById(x990_launcherId2))) { + launcher->SetVisible(true); + launcher->SetColor(zeus::CColor{0.f}); + } + } else { + if (auto* launcher = static_cast(mgr.ObjectById(GetLauncherId()))) { + launcher->SetColor(zeus::CColor{1.f, alpha}); + launcher->SetVisible(alpha != 0.f); + } + if (auto* launcher = static_cast(mgr.ObjectById(x990_launcherId2))) { + launcher->SetColor(zeus::CColor{1.f, alpha}); + launcher->SetVisible(alpha != 0.f); + } + } +} + +void COmegaPirate::sub_8028c704(CStateManager& mgr, float dt) { + int idx = xac8_; + if (idx >= xab4_.size()) { + return; + } + + if (xab0_ <= 0.f) { + ++xac8_; + int val = xab4_[idx]; + if (val == 0) { + SendScriptMsgs(EScriptObjectState::Closed, mgr, EScriptObjectMessage::None); + xb7c_[0]++; + } else if (val == 1) { + SendScriptMsgs(EScriptObjectState::Open, mgr, EScriptObjectMessage::None); + xb7c_[1]++; + } else if (val == 2) { + SendScriptMsgs(EScriptObjectState::CloseIn, mgr, EScriptObjectMessage::None); + xb7c_[2]++; + } else if (val == 3) { + SendScriptMsgs(EScriptObjectState::Modify, mgr, EScriptObjectMessage::None); + xb7c_[3]++; + } + xab0_ = 1.5f; + } + xab0_ -= dt; +} + +void COmegaPirate::UpdateXRayAlpha(CStateManager& mgr, float dt) { + if (xa7c_xrayAlphaState == EXRayFadeState::FadeIn) { + xa80_xrayAlpha = std::min(xa84_xrayAlphaStateTime, xa90_) / xa90_; + if (xa90_ < xa84_xrayAlphaStateTime) { + xa7c_xrayAlphaState = EXRayFadeState::None; + xa84_xrayAlphaStateTime = 0.f; + } + xa84_xrayAlphaStateTime += dt; + } else if (xa7c_xrayAlphaState == EXRayFadeState::WaitForTrigger) { + xa80_xrayAlpha = 0.f; + if ((xa94_ < xa84_xrayAlphaStateTime) && !xa88_xrayFadeInTrigger) { + xa7c_xrayAlphaState = EXRayFadeState::FadeIn; + xa84_xrayAlphaStateTime = 0.f; + } + xa84_xrayAlphaStateTime += dt; + } else if (xa7c_xrayAlphaState == EXRayFadeState::FadeOut) { + xa80_xrayAlpha = 1.f - std::min(xa84_xrayAlphaStateTime, xa8c_) / xa8c_; + if (xa8c_ < xa84_xrayAlphaStateTime) { + xa7c_xrayAlphaState = EXRayFadeState::WaitForTrigger; + xa84_xrayAlphaStateTime = 0.f; + } + xa84_xrayAlphaStateTime += dt; + } else { + xa80_xrayAlpha = 1.f; + } +} + +void COmegaPirate::UpdateScale(CStateManager& mgr, float dt) { + auto* modelData = GetModelData(); + zeus::CVector3f scale = modelData->GetScale(); + switch (x9c8_scaleState) { + case EScaleState::None: + default: + return; + case EScaleState::ScaleDownX: + scale.x() = x9d0_initialScale.x() * std::min(1.f, 0.005f + (1.f - std::min(x9cc_scaleTime, 0.25f) / 0.25f)); + if (x9cc_scaleTime > 0.25f) { + x9c8_scaleState = EScaleState::ScaleDownZ; + x9cc_scaleTime = 0.f; + } + x9cc_scaleTime += dt; + break; + case EScaleState::ScaleDownY: + scale.y() = x9d0_initialScale.y() * std::min(1.f, 0.005f + (1.f - std::min(x9cc_scaleTime, 0.25f) / 0.25f)); + if (x9cc_scaleTime > 0.25f) { + x9c8_scaleState = EScaleState::ScaleDownX; + x9cc_scaleTime = 0.f; + } + x9cc_scaleTime += dt; + break; + case EScaleState::ScaleDownZ: + scale.z() = x9d0_initialScale.z() * std::min(1.f, 0.005f + (1.f - std::min(x9cc_scaleTime, 0.25f) / 0.25f)); + if (x9cc_scaleTime > 0.25f) { + x9c8_scaleState = EScaleState::WaitForTrigger; + x9cc_scaleTime = 0.f; + } + x9cc_scaleTime += dt; + break; + case EScaleState::WaitForTrigger: + if (x9cc_scaleTime > 0.1f && xad0_scaleUpTrigger) { + x9c8_scaleState = EScaleState::ScaleUpZ; + x9cc_scaleTime = 0.f; + } + x9cc_scaleTime += dt; + break; + case EScaleState::ScaleUpX: + scale.x() = x9d0_initialScale.x() * std::min(1.f, 0.005f + std::min(x9cc_scaleTime, 0.25f) / 0.25f); + if (x9cc_scaleTime > 0.25f) { + x9c8_scaleState = EScaleState::ScaleUpY; + x9cc_scaleTime = 0.f; + } + x9cc_scaleTime += dt; + break; + case EScaleState::ScaleUpY: + scale.y() = x9d0_initialScale.y() * std::min(1.f, 0.005f + std::min(x9cc_scaleTime, 0.25f) / 0.25f); + if (x9cc_scaleTime > 0.25f) { + x9c8_scaleState = EScaleState::None; + x9cc_scaleTime = 0.f; + } + x9cc_scaleTime += dt; + break; + case EScaleState::ScaleUpZ: + scale.z() = x9d0_initialScale.z() * std::min(1.f, 0.005f + std::min(x9cc_scaleTime, 0.25f) / 0.25f); + if (x9cc_scaleTime > 0.25f) { + x9c8_scaleState = EScaleState::ScaleUpX; + x9cc_scaleTime = 0.f; + } + x9cc_scaleTime += dt; + break; + } + + modelData->SetScale(scale); + if (auto* launcher = static_cast(mgr.ObjectById(GetLauncherId()))) { + launcher->GetModelData()->SetScale(scale); + } + if (auto* launcher = static_cast(mgr.ObjectById(x990_launcherId2))) { + launcher->GetModelData()->SetScale(scale); + } + for (const auto& entry : x9dc_scriptPlatforms) { + if (auto* platform = static_cast(mgr.ObjectById(entry.first))) { + platform->GetModelData()->SetScale(scale); + } + } +} + +void COmegaPirate::UpdateSkeletonAlpha(CStateManager& mgr, float dt) { + if (xa30_skeletonFadeState == ESkeletonFadeState::FadeOut) { + xa2c_skeletonAlpha = 1.f - std::min(xa34_skeletonStateTime, 1.f); + if (xa34_skeletonStateTime > 1.f) { + xa30_skeletonFadeState = ESkeletonFadeState::None; + xa34_skeletonStateTime = 0.f; + } + xa34_skeletonStateTime += dt; + } else if (xa30_skeletonFadeState == ESkeletonFadeState::Flash) { + xa2c_skeletonAlpha = 1.f; + if (xa34_skeletonStateTime > 1.f) { + xa30_skeletonFadeState = ESkeletonFadeState::FadeOut; + xa34_skeletonStateTime = 0.f; + CreateFlash(mgr, 0.75f); + } + xa34_skeletonStateTime += dt; + } else if (xa30_skeletonFadeState == ESkeletonFadeState::FadeIn) { + xa2c_skeletonAlpha = std::min(xa34_skeletonStateTime, 1.f); + if (xa34_skeletonStateTime > 1.f) { + xa30_skeletonFadeState = ESkeletonFadeState::Flash; + xa34_skeletonStateTime = 0.f; + } + xa34_skeletonStateTime += dt; + } else { + xa2c_skeletonAlpha = 0.f; + } +} + +void COmegaPirate::DeathDestroy(CStateManager& mgr) { + RemoveEmitter(); + SetTransform(xa4c_initialXf); + x9a1_fadeIn = true; + xa4a_heartVisible = false; + SendScriptMsgs(EScriptObjectState::DeathRattle, mgr, EScriptObjectMessage::None); + SendScriptMsgs(EScriptObjectState::Dead, mgr, EScriptObjectMessage::None); + SendScriptMsgs(EScriptObjectState::Inside, mgr, EScriptObjectMessage::None); + for (auto& entry : x9dc_scriptPlatforms) { + if (auto* platform = static_cast(mgr.ObjectById(entry.first))) { + platform->SetActive(false); + platform->RemoveMaterial(EMaterialTypes::Target, EMaterialTypes::Orbit, mgr); + mgr.FreeScriptObject(entry.first); + } + } + x9dc_scriptPlatforms.clear(); + + if (auto* launcher = static_cast(mgr.ObjectById(GetLauncherId()))) { + launcher->SetActive(false); + } + if (auto* launcher = static_cast(mgr.ObjectById(x990_launcherId2))) { + launcher->SetActive(false); + } + SetActive(false); + mgr.SetBossParams(kInvalidUniqueId, 0.f, 89); + xa38_collisionActorMgr1->SetActive(mgr, false); + xa9c_collisionActorMgr2->SetActive(mgr, false); +} } // namespace urde::MP1 diff --git a/Runtime/MP1/World/COmegaPirate.hpp b/Runtime/MP1/World/COmegaPirate.hpp index 369393aa5..ca0306c09 100644 --- a/Runtime/MP1/World/COmegaPirate.hpp +++ b/Runtime/MP1/World/COmegaPirate.hpp @@ -7,18 +7,185 @@ class COmegaPirate : public CElitePirate { private: class CFlash : public CActor { private: - CToken xe8_; - int xf0_; - float xf4_; - float xf8_; - float xfc_; + // TToken xe8_thermalSpotToken; + // CTexture* xf0_thermalSpot = nullptr; + float xf4_delay; + float xf8_time = 0.f; + float xfc_size = 0.f; - CFlash(TUniqueId uid, const CEntityInfo& info, const zeus::CVector3f& pos, CToken& p4, float p5); + CTexturedQuadFilter m_thermalSpotAdd; + CTexturedQuadFilter m_thermalSpotSubtract; + + public: + CFlash(TUniqueId uid, const CEntityInfo& info, const zeus::CVector3f& pos, TLockedToken& thermalSpot, + float delay); + + void Accept(IVisitor& visitor) override; + void Think(float dt, CStateManager& mgr) override; + void PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) override; + void AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) override; + void Render(CStateManager& mgr) override; }; + TUniqueId x990_launcherId2 = kInvalidUniqueId; + enum class ENormalFadeState { + Zero, + One, + Two, + Three, + } x994_normalFadeState = ENormalFadeState::Zero; + float x998_normalFadeTime = 0.f; + float x99c_normalAlpha = 1.f; + bool x9a0_visible = true; + bool x9a1_fadeIn = true; + std::vector>> x9a4_scriptWaypointPlatforms; + bool x9b4_ = false; + std::vector> x9b8_scriptEffects; + enum class EScaleState { + None, + ScaleDownX, + ScaleDownY, + ScaleDownZ, + WaitForTrigger, + ScaleUpX, + ScaleUpY, + ScaleUpZ, + } x9c8_scaleState = EScaleState::None; + float x9cc_scaleTime = 0.f; + zeus::CVector3f x9d0_initialScale; + std::vector> x9dc_scriptPlatforms; + bool x9ec_decrement = false; + CSkinnedModel x9f0_skeletonModel; + float xa2c_skeletonAlpha = 0.f; + enum class ESkeletonFadeState { + None, + FadeOut, + Flash, + FadeIn, + } xa30_skeletonFadeState = ESkeletonFadeState::None; + float xa34_skeletonStateTime = 0.f; + std::unique_ptr xa38_collisionActorMgr1; + bool xa3c_hearPlayer = false; + pas::ELocomotionType xa40_locomotionType = pas::ELocomotionType::Relaxed; + bool xa44_targetable = false; + TUniqueId xa46_ = kInvalidUniqueId; + TUniqueId xa48_ = kInvalidUniqueId; + bool xa4a_heartVisible = false; + zeus::CTransform xa4c_initialXf; + enum class EXRayFadeState { + None, + FadeIn, + WaitForTrigger, + FadeOut, + } xa7c_xrayAlphaState = EXRayFadeState::None; + float xa80_xrayAlpha = 1.f; + float xa84_xrayAlphaStateTime = 0.f; + bool xa88_xrayFadeInTrigger = false; + float xa8c_ = 3.f; + float xa90_ = 1.f; + float xa94_ = 1.f; + float xa98_maxEnergy = 0.f; + std::unique_ptr xa9c_collisionActorMgr2; + std::vector> xaa0_scriptSounds; + float xab0_ = 0.f; + std::vector xab4_; + int xac4_ = 0; + int xac8_ = 0; + int xacc_ = 0; + bool xad0_scaleUpTrigger = false; + float xad4_cachedSpeed = 1.f; + bool xad8_cover = false; + TUniqueId xada_lastWaypointId = kInvalidUniqueId; + bool xadc_ = false; + bool xadd_ = false; + u8 xade_armorPiecesDestroyed = 0; + bool xadf_launcher1FollowPlayer = true; + bool xae0_launcher2FollowPlayer = true; + CDamageVulnerability xae4_platformVuln = CDamageVulnerability::NormalVulnerabilty(); + int xb4c_armorPiecesHealed = 0; + float xb50_ = 0.f; + zeus::CColor xb54_platformColor = zeus::skWhite; + float xb58_ = 2.5f; + float xb5c_ = 0.f; + float xb60_ = 0.f; + float xb64_ = 17.f; + int xb68_ = 0; + bool xb6c_ = false; + bool xb6d_ = false; + bool xb6e_ = false; + TLockedToken xb70_thermalSpot; // was TToken + bool xb78_codeTrigger = false; + bool xb79_ = false; + std::vector xb7c_; + float xb8c_ = 0.f; // not initialized in ctr + public: COmegaPirate(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, CModelData&& mData, const CPatternedInfo& pInfo, const CActorParameters& actParms, CElitePirateData data, CAssetId w1, CAssetId w2, CAssetId w3); + + void Think(float dt, CStateManager& mgr) override; + void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) override; + void PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) override; + void Render(CStateManager& mgr) override; + zeus::CVector3f GetOrbitPosition(const CStateManager& mgr) const override; + void DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) override; + void PathFind(CStateManager& mgr, EStateMsg msg, float dt) override; + void TargetPatrol(CStateManager& mgr, EStateMsg msg, float dt) override; + void Run(CStateManager& mgr, EStateMsg msg, float dt) override; + void Attack(CStateManager& mgr, EStateMsg msg, float dt) override; + void JumpBack(CStateManager& mgr, EStateMsg msg, float dt) override; + void DoubleSnap(CStateManager& mgr, EStateMsg msg, float dt) override; + void Shuffle(CStateManager& mgr, EStateMsg msg, float dt) override; + void Skid(CStateManager& mgr, EStateMsg msg, float dt) override; + void Suck(CStateManager& mgr, EStateMsg msg, float dt) override; + void Explode(CStateManager& mgr, EStateMsg msg, float dt) override; + void Retreat(CStateManager& mgr, EStateMsg msg, float dt) override; + void Cover(CStateManager& mgr, EStateMsg msg, float dt) override; + void WallHang(CStateManager& mgr, EStateMsg msg, float dt) override; + void WallDetach(CStateManager& mgr, EStateMsg msg, float dt) override; + void Enraged(CStateManager& mgr, EStateMsg msg, float dt) override; + void Growth(CStateManager& mgr, EStateMsg msg, float dt) override; + void Faint(CStateManager& mgr, EStateMsg msg, float dt) override; + void Dizzy(CStateManager& mgr, EStateMsg msg, float dt) override; + + bool Landed(CStateManager& mgr, float arg) override; + bool HearPlayer(CStateManager& mgr, float arg) override; + bool CoverBlown(CStateManager& mgr, float arg) override; + bool AggressionCheck(CStateManager& mgr, float arg) override; + bool ShouldFire(CStateManager& mgr, float arg) override; + bool ShouldMove(CStateManager& mgr, float arg) override; + bool ShotAt(CStateManager& mgr, float arg) override; + bool CodeTrigger(CStateManager& mgr, float arg) override; + bool ShouldCallForBackup(CStateManager& mgr, float arg) override; + bool HasWeakPointHead() const override { return false; } + bool IsElitePirate() const override { return false; } + void SetupHealthInfo(CStateManager& mgr) override; + void SetLaunchersActive(CStateManager& mgr, bool val) override; + SShockWaveData GetShockWaveData() const override { + return {GetData().GetXF8(), GetData().GetXFC(), 24.78255f, GetData().GetX118(), GetData().GetX11C()}; + } + +private: + void CreateFlash(CStateManager& mgr, float arg); + void SetupCollisionManager(CStateManager& mgr); + void AddSphereCollisionList(const SSphereJointInfo* joints, size_t count, + std::vector& outJoints) const; + void AddOBBAutoSizeCollisionList(const SOBBJointInfo* joints, size_t count, + std::vector& outJoints) const; + void SetupCollisionActorInfo1(const std::unique_ptr& actMgr, CStateManager& mgr); + void SetupCollisionActorInfo2(const std::unique_ptr& actMgr, CStateManager& mgr); + void sub_8028cbec(u32 arg, CStateManager& mgr); + u8 sub_8028c230() const; + u8 sub_8028bfac() const; + void TeleportToFurthestPlatform(CStateManager& mgr); + void UpdateNormalAlpha(CStateManager& mgr, float dt); + void sub_8028c704(CStateManager& mgr, float dt); + void UpdateXRayAlpha(CStateManager& mgr, float dt); + void UpdateScale(CStateManager& mgr, float dt); + void UpdateSkeletonAlpha(CStateManager& mgr, float dt); + void DeathDestroy(CStateManager& mgr); + void sub_8028c840(u32 arg, CStateManager& mgr); + zeus::CVector3f FindGround(const zeus::CVector3f& pos, CStateManager& mgr) const; }; } // namespace urde::MP1 diff --git a/Runtime/MP1/World/CPhazonHealingNodule.cpp b/Runtime/MP1/World/CPhazonHealingNodule.cpp new file mode 100644 index 000000000..45a1533ed --- /dev/null +++ b/Runtime/MP1/World/CPhazonHealingNodule.cpp @@ -0,0 +1,186 @@ +#include "Runtime/MP1/World/CPhazonHealingNodule.hpp" + +#include "Runtime/CSimplePool.hpp" +#include "Runtime/CStateManager.hpp" +#include "Runtime/GameGlobalObjects.hpp" +#include "Runtime/World/CPatternedInfo.hpp" + +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 actorLctr) +: CPatterned(ECharacter::PhazonHealingNodule, uid, name, EFlavorType::Zero, info, xf, std::move(mData), pInfo, + EMovementType::Flyer, EColliderType::One, EBodyType::Restricted, actParams, EKnockBackVariant::Medium) +, 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(CStateManager& mgr) { + if (x57c_particleElectric) { + x57c_particleElectric->Render(); + } + CPatterned::Render(mgr); +} + +void CPhazonHealingNodule::Think(float dt, CStateManager& mgr) { + if (!GetActive()) { + return; + } + + 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); + } +} + +bool CPhazonHealingNodule::AnimOver(CStateManager&, float arg) { return x588_state == 3; } + +bool CPhazonHealingNodule::InRange(CStateManager&, float arg) { return x568_active == 0; } + +bool CPhazonHealingNodule::InDetectionRange(CStateManager&, float arg) { return x568_active == 1; } + +void CPhazonHealingNodule::MassiveDeath(CStateManager& mgr) { Death(mgr, zeus::skZero3f, EScriptObjectState::Dead); } + +void CPhazonHealingNodule::MassiveFrozenDeath(CStateManager& mgr) { + Death(mgr, zeus::skZero3f, EScriptObjectState::Dead); +} + +void CPhazonHealingNodule::PhazeOut(CStateManager& mgr) { Death(mgr, zeus::skZero3f, EScriptObjectState::Dead); } +} // namespace urde::MP1 diff --git a/Runtime/MP1/World/CPhazonHealingNodule.hpp b/Runtime/MP1/World/CPhazonHealingNodule.hpp new file mode 100644 index 000000000..d068d822e --- /dev/null +++ b/Runtime/MP1/World/CPhazonHealingNodule.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "Runtime/World/CPatterned.hpp" +#include "Runtime/Particle/CParticleElectric.hpp" + +namespace urde::MP1 { +class CPhazonHealingNodule : public CPatterned { +private: + 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: + DEFINE_PATTERNED(PhazonHealingNodule); + + 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 actorLctr); + + void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) override; + void DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUserEventType type, float dt) override; + void Render(CStateManager& mgr) 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; + + bool InRange(CStateManager &, float arg) override; + bool InDetectionRange(CStateManager &, float arg) override; + bool AnimOver(CStateManager &, float arg) override; + + void MassiveDeath(CStateManager &mgr) override; + void MassiveFrozenDeath(CStateManager &mgr) override; + void PhazeOut(CStateManager &) override; + +private: + void UpdateParticleElectric(CStateManager& mgr); +}; +} // namespace urde::MP1 diff --git a/Runtime/MP1/World/CPhazonPool.cpp b/Runtime/MP1/World/CPhazonPool.cpp new file mode 100644 index 000000000..96d8596c3 --- /dev/null +++ b/Runtime/MP1/World/CPhazonPool.cpp @@ -0,0 +1,272 @@ +#include "Runtime/MP1/World/CPhazonPool.hpp" + +#include "Runtime/CSimplePool.hpp" +#include "Runtime/CStateManager.hpp" +#include "Runtime/GameGlobalObjects.hpp" +#include "Runtime/Graphics/CBooRenderer.hpp" + +#include "TCastTo.hpp" // Generated file, do not modify include path + +namespace urde::MP1 { +CPhazonPool::CPhazonPool(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, + const zeus::CVector3f& scale, bool active, CAssetId w1, CAssetId w2, CAssetId w3, CAssetId w4, + u32 p11, const CDamageInfo& dInfo, const zeus::CVector3f& orientedForce, + ETriggerFlags triggerFlags, bool p15, float p16, float p17, float p18, float p19) +: CScriptTrigger(uid, name, info, xf.origin, zeus::skNullBox, dInfo, orientedForce, triggerFlags, active, false, false) +, x168_modelData1(std::make_unique(CStaticRes{w1, zeus::skOne3f})) +, x16c_modelData2(std::make_unique(CStaticRes{w2, zeus::skOne3f})) +, x190_scale(scale) +, x19c_(p16) +, x1a0_(p16) +, x1bc_(p17) +, x1c0_(p19) +, x1c8_(p18) +, x1d8_(p11) +, x1e0_24_(p15) +, x1e0_25_(false) { + if (w3.IsValid()) { + x170_elementGen1 = std::make_unique(g_SimplePool->GetObj(SObjectTag{SBIG('PART'), w3})); + x170_elementGen1->SetParticleEmission(false); + } + if (w4.IsValid()) { + x174_elementGen2 = std::make_unique(g_SimplePool->GetObj(SObjectTag{SBIG('PART'), w4})); + x174_elementGen2->SetGlobalScale(x190_scale); + x174_elementGen2->SetParticleEmission(false); + } +} + +void CPhazonPool::Accept(IVisitor& visitor) { visitor.Visit(this); } + +void CPhazonPool::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) { + switch (msg) { + case EScriptObjectMessage::Activate: + case EScriptObjectMessage::Open: + UpdateParticleGens(mgr); + break; + case EScriptObjectMessage::Close: + if (!x1e0_25_) { + x1e0_25_ = true; + x1c4_ = 0.f; + SetEmitParticles(false); + } + break; + case EScriptObjectMessage::Decrement: + if (x1dc_ == 2) { + x1cc_ += 1.f; + } + break; + case EScriptObjectMessage::Registered: + if (x170_elementGen1) { + x170_elementGen1->SetGlobalTranslation(GetTranslation()); + } + if (x168_modelData1) { + x178_bounds = x168_modelData1->GetBounds(); + } else { + x178_bounds = zeus::CAABox{0.5f * -x190_scale, 0.5f * x190_scale}; + } + x130_bounds = zeus::CAABox{x178_bounds.min * x190_scale, x178_bounds.max * x190_scale}; + break; + case EScriptObjectMessage::Deleted: + RemoveInhabitants(mgr); + break; + default: + break; + } + CScriptTrigger::AcceptScriptMsg(msg, uid, mgr); +} + +void CPhazonPool::AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) { + if (GetActive()) { + if (x170_elementGen1) { + g_Renderer->AddParticleGen(*x170_elementGen1); + } + if (x174_elementGen2) { + g_Renderer->AddParticleGen(*x174_elementGen2); + } + } + CActor::AddToRenderer(frustum, mgr); + CActor::EnsureRendered(mgr); +} + +std::optional CPhazonPool::GetTouchBounds() const { return CScriptTrigger::GetTouchBounds(); } + +void CPhazonPool::Render(CStateManager& mgr) { + CActor::Render(mgr); + bool discard = x1a4_ < 0.25f; + const CModelFlags flags{5, 0, static_cast(discard ? 3 : 0), zeus::CColor{1.f, x1a4_}}; + if (x168_modelData1) { + x168_modelData1->Render(mgr, GetTransform() * zeus::CTransform::RotateZ(x1ac_rotZ), nullptr, flags); + } + if (x16c_modelData2) { + const zeus::CTransform rot = zeus::CTransform::RotateZ(x1ac_rotZ) * zeus::CTransform::RotateX(x1ac_rotZ) * + zeus::CTransform::RotateY(x1a8_rotY); + x16c_modelData2->Render(mgr, GetTransform() * rot, nullptr, flags); + } +} + +void CPhazonPool::Think(float dt, CStateManager& mgr) { + if (!GetActive()) { + return; + } + + CScriptTrigger::Think(dt, mgr); + UpdateInhabitants(mgr); + const zeus::CVector3f scale = (x1dc_ == 1 ? x1a4_ : 1.f) * x190_scale; + SetTransform({zeus::CMatrix3f{scale}, GetTranslation()}); + x130_bounds = zeus::CAABox{x178_bounds.min * scale, x178_bounds.max * scale}; + x1a8_rotY += dt * x1b0_; + x1ac_rotZ += dt * x1b4_; + if (x1a8_rotY > zeus::degToRad(360.f)) { + x1a8_rotY = 0.f; + } + if (x1ac_rotZ > zeus::degToRad(360.f)) { + x1ac_rotZ = 0.f; + } + if (x170_elementGen1) { + x170_elementGen1->SetModulationColor(zeus::CColor{x1a4_, x1a4_, x1a4_, x1a4_}); + x170_elementGen1->SetGlobalScale(zeus::CVector3f{scale.x()}); + x170_elementGen1->Update(dt); + } + if (x174_elementGen2) { + x174_elementGen2->Update(dt); + } + + bool shouldFree = false; + if (x1dc_ == 1) { + x1d4_ += dt; + if (x1d4_ > 2.f) { + x1d4_ = 2.f; + x1a4_ += dt * x1b8_; + if (x1a4_ > 1.f) { + x1a4_ = 1.f; + x1dc_ = 2; + SetEmitParticles(true); + if (x174_elementGen2) { + x174_elementGen2->SetParticleEmission(true); + } + } + } + } else if (x1dc_ == 2) { + float dVar5 = 0.f; + if (x1e0_24_ || x1e0_25_) { + x1c4_ -= dt; + if (x1c4_ <= 0.f) { + x1c4_ = 0.f; + dVar5 = dt; + } + x1a0_ -= x1bc_ * (dt * x1cc_) + dVar5; + x1a4_ = x1a0_ / x19c_; + if (x1a4_ < 0.001f) { + if (x1e0_24_) { + shouldFree = true; + } else { + SetCallTouch(false); + if (x1e0_25_) { + x1dc_ = 0; + SetActive(false); + } else { + x1dc_ = 3; + x1d0_ = x1c8_; + } + } + SetEmitParticles(false); + } + x1cc_ = 0.f; + } + } else if (x1dc_ == 3) { + x1d0_ -= dt; + if (x1d0_ <= 0.f) { + x1d0_ = 0.f; + UpdateParticleGens(mgr); + } + } + if (shouldFree) { + mgr.FreeScriptObject(GetUniqueId()); + } +} + +void CPhazonPool::Touch(CActor& actor, CStateManager& mgr) { + if (!GetActive() || x1dc_ != 2) { + return; + } + + CScriptTrigger::Touch(actor, mgr); + if (actor.GetMaterialList().HasMaterial(EMaterialTypes::PlatformSlave)) { + return; + } + + for (auto& entry : x150_inhabitants) { + if (entry.first == actor.GetUniqueId()) { + entry.second = true; + return; + } + } + + if (actor.GetTouchBounds().has_value()) { + x150_inhabitants.emplace_back(actor.GetUniqueId(), true); + mgr.SendScriptMsg(&actor, GetUniqueId(), EScriptObjectMessage::AddPhazonPoolInhabitant); + } +} + +void CPhazonPool::UpdateInhabitants(CStateManager& mgr) { + auto iter = x150_inhabitants.begin(); + const auto end = x150_inhabitants.end(); + while (iter != end) { + TCastToPtr actor = mgr.ObjectById(iter->first); + if (actor) { + if (actor->GetTouchBounds().has_value()) { + (void)GetTriggerBoundsWR(); // unused? + } + } + if (!actor || !iter->second) { + iter = x150_inhabitants.erase(iter); + if (actor) { + mgr.SendScriptMsg(actor, GetUniqueId(), EScriptObjectMessage::RemovePhazonPoolInhabitant); + } + } else { + mgr.SendScriptMsg(actor, GetUniqueId(), EScriptObjectMessage::UpdatePhazonPoolInhabitant); + iter->second = false; + iter++; + } + } +} + +void CPhazonPool::UpdateParticleGens(CStateManager& mgr) { + x1b0_ = mgr.GetActiveRandom()->Range(-0.5f, 0.5f); + x1b4_ = mgr.GetActiveRandom()->Range(-1.f, 1.f); + x1b8_ = mgr.GetActiveRandom()->Range(0.25f, 2.f); + x1cc_ = 0.f; + x1d4_ = 0.f; + x1c4_ = x1c0_; + x1a0_ = x19c_; + x1dc_ = 1; + x1e0_25_ = false; + if (x170_elementGen1) { + x170_elementGen1->SetGlobalTranslation(GetTranslation()); + x170_elementGen1->SetParticleEmission(false); + } + if (x174_elementGen2) { + x174_elementGen2->SetGlobalTranslation(GetTranslation()); + x174_elementGen2->SetParticleEmission(true); + } +} + +void CPhazonPool::RemoveInhabitants(CStateManager& mgr) { + auto iter = x150_inhabitants.begin(); + const auto end = x150_inhabitants.end(); + while (iter != end) { + if (TCastToPtr actor = mgr.ObjectById(iter->first)) { + iter = x150_inhabitants.erase(iter); + mgr.SendScriptMsg(actor, GetUniqueId(), EScriptObjectMessage::RemovePhazonPoolInhabitant); + } else { + iter++; + } + } +} + +void CPhazonPool::SetEmitParticles(bool val) { + if (x170_elementGen1) { + x170_elementGen1->SetParticleEmission(val); + } +} +} // namespace urde::MP1 diff --git a/Runtime/MP1/World/CPhazonPool.hpp b/Runtime/MP1/World/CPhazonPool.hpp new file mode 100644 index 000000000..2c5cb7c2e --- /dev/null +++ b/Runtime/MP1/World/CPhazonPool.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include "Runtime/World/CScriptTrigger.hpp" + +#include "Runtime/Particle/CElementGen.hpp" + +namespace urde::MP1 { +class CPhazonPool : public CScriptTrigger { +private: + std::list> x150_inhabitants; + std::unique_ptr x168_modelData1; + std::unique_ptr x16c_modelData2; + std::unique_ptr x170_elementGen1; + std::unique_ptr x174_elementGen2; + zeus::CAABox x178_bounds = zeus::skNullBox; + zeus::CVector3f x190_scale; + float x19c_; + float x1a0_; + float x1a4_ = 0.001f; + float x1a8_rotY = 0.f; + float x1ac_rotZ = 0.f; + float x1b0_ = 0.f; + float x1b4_ = 0.f; + float x1b8_ = 0.f; + float x1bc_; + float x1c0_; + float x1c4_ = 0.f; + float x1c8_; + float x1cc_ = 0.f; + float x1d0_ = 0.f; + float x1d4_ = 0.f; + u32 x1d8_; + u32 x1dc_ = 0; + bool x1e0_24_ : 1; + bool x1e0_25_ : 1; + +public: + CPhazonPool(TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, + const zeus::CVector3f& scale, bool active, CAssetId w1, CAssetId w2, CAssetId w3, CAssetId w4, u32 p11, + const CDamageInfo& dInfo, const zeus::CVector3f& orientedForce, ETriggerFlags triggerFlags, bool p15, + float p16, float p17, float p18, float p19); + + void Accept(IVisitor& visitor) override; + void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) override; + void AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) override; + [[nodiscard]] std::optional GetTouchBounds() const override; + void Render(CStateManager& mgr) override; + void Think(float dt, CStateManager& mgr) override; + void Touch(CActor& actor, CStateManager& mgr) override; + +private: + void UpdateInhabitants(CStateManager& mgr); + void UpdateParticleGens(CStateManager& mgr); + void RemoveInhabitants(CStateManager& mgr); + void SetEmitParticles(bool val); +}; +} // namespace urde::MP1 diff --git a/Runtime/MP1/World/CShockWave.hpp b/Runtime/MP1/World/CShockWave.hpp index 0eb5589f5..089fe3239 100644 --- a/Runtime/MP1/World/CShockWave.hpp +++ b/Runtime/MP1/World/CShockWave.hpp @@ -12,14 +12,14 @@ private: CDamageInfo x8_damageInfo; float x24_ = 0.f; float x28_ = 0.5f; - float x2c_ = 16.5217f; + float x2c_; float x30_ = 0.f; CAssetId x34_weaponDesc; u16 x38_electrocuteSfx; public: - SShockWaveData(CAssetId part, const CDamageInfo& dInfo, CAssetId weapon, u16 sfx) - : x4_particleDesc(part), x8_damageInfo(dInfo), x34_weaponDesc(weapon), x38_electrocuteSfx(sfx) {} + SShockWaveData(CAssetId part, const CDamageInfo& dInfo, float x2c, CAssetId weapon, u16 sfx) + : x4_particleDesc(part), x8_damageInfo(dInfo), x2c_(x2c), x34_weaponDesc(weapon), x38_electrocuteSfx(sfx) {} [[nodiscard]] CAssetId GetParticleDescId() const { return x4_particleDesc; } [[nodiscard]] const CDamageInfo& GetDamageInfo() const { return x8_damageInfo; } diff --git a/Runtime/MP1/World/CThardus.cpp b/Runtime/MP1/World/CThardus.cpp index 0961b8c14..c081a6e37 100644 --- a/Runtime/MP1/World/CThardus.cpp +++ b/Runtime/MP1/World/CThardus.cpp @@ -995,7 +995,7 @@ void CThardus::RenderFlare(const CStateManager& mgr, float t) { {{min.x() - offset.x(), min.y() - offset.y(), min.z() - offset.z()}, {1.f, 0.f}}, }}; - m_flareFilter->drawVerts({t, t}, verts.data()); + m_flareFilter->drawVerts({t, t}, verts); } #if 0 @@ -1023,4 +1023,4 @@ zeus::CVector3f CThardus::sub801de550(const CStateManager& mgr) const { return {}; } -} // namespace urde::MP1 \ No newline at end of file +} // namespace urde::MP1 diff --git a/Runtime/Particle/CElementGen.cpp b/Runtime/Particle/CElementGen.cpp index 88a3b754c..ec0f5c34c 100644 --- a/Runtime/Particle/CElementGen.cpp +++ b/Runtime/Particle/CElementGen.cpp @@ -935,7 +935,7 @@ void CElementGen::RenderModels(const CActorLights* actorLights) { rot = orient * rot; CParticleGlobals::instance()->SetEmitterTime(x74_curFrame); - zeus::CColor col = {1.f, 1.f, 1.f, 1.f}; + zeus::CColor col = x338_moduColor; zeus::CVector3f pmopVec; auto matrixIt = x50_parentMatrices.begin(); @@ -992,8 +992,10 @@ void CElementGen::RenderModels(const CActorLights* actorLights) { } CColorElement* pmcl = desc->x78_x64_PMCL.get(); - if (pmcl) + if (pmcl) { pmcl->GetValue(partFrame, col); + col *= x338_moduColor; + } CGraphics::SetModelMatrix((x10c_globalScaleTransform * partTrans) * x178_localScaleTransform); @@ -1040,11 +1042,10 @@ void CElementGen::RenderModels(const CActorLights* actorLights) { model->Draw({5, 0, 1, zeus::CColor(1.f, 0.5f)}); } else if (desc->x44_31_x31_25_PMAB) { model->Draw({7, 0, 1, col}); + } else if (1.f == col.a()) { + model->Draw({0, 0, 3, zeus::skWhite}); } else { - if (1.f == col.a()) - model->Draw({0, 0, 3, zeus::skWhite}); - else - model->Draw({5, 0, 1, col}); + model->Draw({5, 0, 1, zeus::CColor(1.f, col.a())}); } } diff --git a/Runtime/Particle/CParticleElectric.hpp b/Runtime/Particle/CParticleElectric.hpp index 7a77b089e..2760922de 100644 --- a/Runtime/Particle/CParticleElectric.hpp +++ b/Runtime/Particle/CParticleElectric.hpp @@ -10,7 +10,9 @@ #include "Runtime/CToken.hpp" #include "Runtime/rstl.hpp" #include "Runtime/Graphics/CLineRenderer.hpp" +#include "Runtime/Particle/CElementGen.hpp" #include "Runtime/Particle/CParticleGen.hpp" +#include "Runtime/Particle/CParticleSwoosh.hpp" #include #include @@ -19,8 +21,6 @@ namespace urde { class CElectricDescription; -class CElementGen; -class CParticleSwoosh; class CParticleElectric : public CParticleGen { static u16 g_GlobalSeed; diff --git a/Runtime/Weapon/CPlayerGun.hpp b/Runtime/Weapon/CPlayerGun.hpp index 4cb11cf2f..f5a3d2460 100644 --- a/Runtime/Weapon/CPlayerGun.hpp +++ b/Runtime/Weapon/CPlayerGun.hpp @@ -356,6 +356,7 @@ public: void DropBomb(EBWeapon weapon, CStateManager& mgr); TUniqueId DropPowerBomb(CStateManager& mgr); void SetActorAttached(bool b) { x835_31_actorAttached = b; } + CAuxWeapon& GetAuxWeapon() const { return *x744_auxWeapon; } }; } // namespace urde diff --git a/Runtime/World/CActor.hpp b/Runtime/World/CActor.hpp index 5913d3279..4ddc866ca 100644 --- a/Runtime/World/CActor.hpp +++ b/Runtime/World/CActor.hpp @@ -184,6 +184,7 @@ public: float GetAverageAnimVelocity(int anim) const; u8 GetTargetableVisorFlags() const { return xe6_31_targetableVisorFlags; } bool GetIsTargetable() const { return xe7_31_targetable; } + const CModelFlags& GetDrawFlags() const { return xb4_drawFlags; } void SetDrawFlags(const CModelFlags& flags) { xb4_drawFlags = flags; } void SetModelData(std::unique_ptr&& mData); u8 GetFluidCounter() const { return xe6_24_fluidCounter; } diff --git a/Runtime/World/CPatterned.hpp b/Runtime/World/CPatterned.hpp index e008cfdd1..16dcbbdd2 100644 --- a/Runtime/World/CPatterned.hpp +++ b/Runtime/World/CPatterned.hpp @@ -361,6 +361,7 @@ public: const CBodyController* GetBodyController() const { return x450_bodyController.get(); } CBodyController* GetBodyController() { return x450_bodyController.get(); } const CKnockBackController& GetKnockBackController() const { return x460_knockBackController; } + CKnockBackController& GetKnockBackController() { return x460_knockBackController; } void SetupPlayerCollision(bool); CGameProjectile* LaunchProjectile(const zeus::CTransform& gunXf, CStateManager& mgr, int maxAllowed, EProjectileAttrib attrib, bool playerHoming, diff --git a/Runtime/World/CScriptEffect.cpp b/Runtime/World/CScriptEffect.cpp index 48407c0ab..85f568ee5 100644 --- a/Runtime/World/CScriptEffect.cpp +++ b/Runtime/World/CScriptEffect.cpp @@ -75,6 +75,7 @@ CScriptEffect::CScriptEffect(TUniqueId uid, std::string_view name, const CEntity xf4_electric->SetGlobalTranslation(xf.origin); xf4_electric->SetGlobalScale(scale); xf4_electric->SetParticleEmission(active); + xf4_electric->SetModulationColor(lParms.GetNoLightsAmbient()); } xe7_29_drawEnabled = true; } @@ -96,7 +97,6 @@ void CScriptEffect::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CSt x104_particleSystem->SetOrientation(newXf); x104_particleSystem->SetGlobalTranslation(GetTranslation()); x104_particleSystem->SetGlobalScale(scale); - x104_particleSystem->SetParticleEmission(oldActive); x104_particleSystem->SetModulationColor(color); x104_particleSystem->SetModelsUseLights(x138_actorLights != nullptr); } @@ -110,7 +110,6 @@ void CScriptEffect::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CSt xf4_electric->SetOrientation(newXf); xf4_electric->SetGlobalTranslation(GetTranslation()); xf4_electric->SetGlobalScale(scale); - xf4_electric->SetParticleEmission(oldActive); xf4_electric->SetModulationColor(color); } } @@ -151,28 +150,30 @@ void CScriptEffect::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CSt mgr.SendScriptMsg(light, uid, msg); if (oldActive != GetActive()) { - std::vector playIds; - for (const SConnection& conn : x20_conns) { - if (conn.x0_state != EScriptObjectState::Play || conn.x4_msg != EScriptObjectMessage::Activate) { - continue; + if (GetActive()) { + std::vector playIds; + for (const SConnection& conn : x20_conns) { + if (conn.x0_state != EScriptObjectState::Play || conn.x4_msg != EScriptObjectMessage::Activate) { + continue; + } + + const TUniqueId scriptId = mgr.GetIdForScript(conn.x8_objId); + if (scriptId != kInvalidUniqueId) { + playIds.push_back(scriptId); + } } - const TUniqueId scriptId = mgr.GetIdForScript(conn.x8_objId); - if (scriptId != kInvalidUniqueId) { - playIds.push_back(scriptId); - } - } - - if (playIds.size() > 0) { - TCastToConstPtr otherAct = - mgr.GetObjectById(playIds[u32(0.99f * playIds.size() * mgr.GetActiveRandom()->Float())]); - if (otherAct) { - if (light) - light->SetTransform(otherAct->GetTransform()); - else + if (!playIds.empty()) { + TCastToConstPtr otherAct = + mgr.GetObjectById(playIds[u32(0.99f * playIds.size() * mgr.GetActiveRandom()->Float())]); + if (otherAct) { SetTransform(otherAct->GetTransform()); + if (light) + light->SetTransform(otherAct->GetTransform()); + } } } + x110_24_enable = true; if (x104_particleSystem) x104_particleSystem->SetParticleEmission(GetActive()); diff --git a/Runtime/World/CScriptPlatform.cpp b/Runtime/World/CScriptPlatform.cpp index 2297bb12e..4bab7cffa 100644 --- a/Runtime/World/CScriptPlatform.cpp +++ b/Runtime/World/CScriptPlatform.cpp @@ -20,19 +20,19 @@ namespace urde { constexpr auto skPlatformMaterialList = CMaterialList{EMaterialTypes::Solid, EMaterialTypes::Immovable, EMaterialTypes::Platform, EMaterialTypes::Occluder}; -CScriptPlatform::CScriptPlatform( - TUniqueId uid, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf, CModelData&& mData, - const CActorParameters& actParms, const zeus::CAABox& aabb, float speed, bool detectCollision, float xrayAlpha, - bool active, const CHealthInfo& hInfo, const CDamageVulnerability& dVuln, - const std::optional>& dcln, bool rainSplashes, - u32 maxRainSplashes, u32 rainGenRate) +CScriptPlatform::CScriptPlatform(TUniqueId uid, std::string_view name, const CEntityInfo& info, + const zeus::CTransform& xf, CModelData&& mData, const CActorParameters& actParms, + const zeus::CAABox& aabb, float speed, bool detectCollision, float xrayAlpha, + bool active, const CHealthInfo& hInfo, const CDamageVulnerability& dVuln, + std::optional> dcln, + bool rainSplashes, u32 maxRainSplashes, u32 rainGenRate) : CPhysicsActor(uid, active, name, info, xf, std::move(mData), skPlatformMaterialList, aabb, SMoverData(15000.f), actParms, 0.3f, 0.1f) , x25c_currentSpeed(speed) , x28c_initialHealth(hInfo) , x294_health(hInfo) , x29c_damageVuln(dVuln) -, x304_treeGroupContainer(dcln) { +, x304_treeGroupContainer(std::move(dcln)) { x348_xrayAlpha = xrayAlpha; x34c_maxRainSplashes = maxRainSplashes; x350_rainGenRate = rainGenRate; @@ -402,7 +402,7 @@ void CScriptPlatform::BuildSlaveList(CStateManager& mgr) { void CScriptPlatform::AddRider(std::vector& riders, TUniqueId riderId, const CPhysicsActor* ridee, CStateManager& mgr) { - const auto search = + const auto& search = std::find_if(riders.begin(), riders.end(), [riderId](const SRiders& r) { return r.x0_uid == riderId; }); if (search == riders.end()) { zeus::CTransform xf; @@ -417,7 +417,7 @@ void CScriptPlatform::AddRider(std::vector& riders, TUniqueId riderId, } void CScriptPlatform::AddSlave(TUniqueId id, CStateManager& mgr) { - const auto search = std::find_if(x338_slavesDynamic.begin(), x338_slavesDynamic.end(), + const auto& search = std::find_if(x338_slavesDynamic.begin(), x338_slavesDynamic.end(), [id](const SRiders& r) { return r.x0_uid == id; }); if (search != x338_slavesDynamic.end()) { return; diff --git a/Runtime/World/CScriptPlatform.hpp b/Runtime/World/CScriptPlatform.hpp index db0d1d915..0d000ffe0 100644 --- a/Runtime/World/CScriptPlatform.hpp +++ b/Runtime/World/CScriptPlatform.hpp @@ -30,7 +30,7 @@ struct SRiders { }; class CScriptPlatform : public CPhysicsActor { - u32 x254_; + // u32 x254_; TUniqueId x258_currentWaypoint = kInvalidUniqueId; TUniqueId x25a_targetWaypoint = kInvalidUniqueId; float x25c_currentSpeed; @@ -82,8 +82,8 @@ public: CModelData&& mData, const CActorParameters& actParms, const zeus::CAABox& aabb, float speed, bool detectCollision, float xrayAlpha, bool active, const CHealthInfo& hInfo, const CDamageVulnerability& dVuln, - const std::optional>& dcln, - bool rainSplashes, u32 maxRainSplashes, u32 rainGenRate); + std::optional> dcln, bool rainSplashes, + u32 maxRainSplashes, u32 rainGenRate); void Accept(IVisitor& visitor) override; void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&) override; @@ -111,8 +111,11 @@ public: TUniqueId GetWaypoint(CStateManager&); const CDamageVulnerability* GetDamageVulnerability() const override { return &x29c_damageVuln; } + void SetDamageVulnerability(const CDamageVulnerability& vuln) { x29c_damageVuln = vuln; } CHealthInfo* HealthInfo(CStateManager&) override { return &x294_health; } void SetControlledAnimation(bool controlled) { x356_25_controlledAnimation = controlled; } + void SetDisableXRayAlpha(bool val) { x356_30_disableXrayAlpha = val; } + void SetXRayFog(bool val) { x356_31_xrayFog = val; } virtual void SplashThink(const zeus::CAABox&, const CFluidPlane&, float, CStateManager&) const; virtual zeus::CQuaternion Move(float, CStateManager&); diff --git a/Runtime/World/ScriptLoader.cpp b/Runtime/World/ScriptLoader.cpp index b2fca89dc..e7985007b 100644 --- a/Runtime/World/ScriptLoader.cpp +++ b/Runtime/World/ScriptLoader.cpp @@ -33,6 +33,8 @@ #include "Runtime/MP1/World/CNewIntroBoss.hpp" #include "Runtime/MP1/World/COmegaPirate.hpp" #include "Runtime/MP1/World/CParasite.hpp" +#include "Runtime/MP1/World/CPhazonHealingNodule.hpp" +#include "Runtime/MP1/World/CPhazonPool.hpp" #include "Runtime/MP1/World/CPuddleSpore.hpp" #include "Runtime/MP1/World/CPuddleToadGamma.hpp" #include "Runtime/MP1/World/CPuffer.hpp" @@ -3645,7 +3647,6 @@ CEntity* ScriptLoader::LoadOmegaPirate(CStateManager& mgr, CInputStream& in, int return nullptr; } -#if 0 SScaledActorHead actHead = LoadScaledActorHead(in, mgr); auto pair = CPatternedInfo::HasCorrectParameterCount(in); if (!pair.first) { @@ -3665,18 +3666,62 @@ CEntity* ScriptLoader::LoadOmegaPirate(CStateManager& mgr, CInputStream& in, int return new MP1::COmegaPirate(mgr.AllocateUniqueId(), actHead.x0_name, info, actHead.x10_transform, std::move(mData), pInfo, actParms, elitePirateData, CAssetId(in), CAssetId(in), CAssetId(in)); -#else - return nullptr; -#endif } CEntity* ScriptLoader::LoadPhazonPool(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) { - return nullptr; + if (!EnsurePropertyCount(propCount, 18, "PhazonPool")) { + return nullptr; + } + + SScaledActorHead actHead = LoadScaledActorHead(in, mgr); + bool active = in.readBool(); + CAssetId w1{in}; + CAssetId w2{in}; + CAssetId w3{in}; + CAssetId w4{in}; + u32 u1 = in.readUint32Big(); + CDamageInfo dInfo{in}; + zeus::CVector3f orientedForce{in.readVec3f()}; + ETriggerFlags triggerFlags = static_cast(in.readUint32Big()); + float f1 = in.readFloatBig(); + float f2 = in.readFloatBig(); + float f3 = in.readFloatBig(); + bool b2 = in.readBool(); + float f4 = in.readFloatBig(); + + return new MP1::CPhazonPool(mgr.AllocateUniqueId(), actHead.x0_name, info, + zeus::CTransform::Translate(actHead.x10_transform.origin), actHead.x40_scale, active, w1, + w2, w3, w4, u1, dInfo, orientedForce, triggerFlags, b2, f1, f2, f3, f4); } CEntity* ScriptLoader::LoadPhazonHealingNodule(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) { - return nullptr; + if (!EnsurePropertyCount(propCount, 9, "PhazonHealingNodule")) { + return nullptr; + } + + SScaledActorHead actHead = LoadScaledActorHead(in, mgr); + auto pair = CPatternedInfo::HasCorrectParameterCount(in); + if (!pair.first) { + return nullptr; + } + + CPatternedInfo pInfo(in, pair.second); + CActorParameters actParms = LoadActorParameters(in); + + in.readBool(); + CAssetId w1{in}; + std::string w2 = in.readString(); + + if (!pInfo.GetAnimationParameters().GetACSFile().IsValid()) { + return nullptr; + } + + CModelData mData(CAnimRes(pInfo.GetAnimationParameters().GetACSFile(), pInfo.GetAnimationParameters().GetCharacter(), + actHead.x40_scale, pInfo.GetAnimationParameters().GetInitialAnimation(), true)); + + return new MP1::CPhazonHealingNodule(mgr.AllocateUniqueId(), actHead.x0_name, info, actHead.x10_transform, + std::move(mData), actParms, pInfo, w1, std::move(w2)); } CEntity* ScriptLoader::LoadNewCameraShaker(CStateManager& mgr, CInputStream& in, int propCount,