#pragma once #include #include "Runtime/RetroTypes.hpp" #include "Runtime/Collision/CCollidableSphere.hpp" #include "Runtime/Collision/CCollisionInfoList.hpp" #include "Runtime/Graphics/CRainSplashGenerator.hpp" #include "Runtime/Particle/CElementGen.hpp" #include "Runtime/Particle/CParticleSwoosh.hpp" #include "Runtime/World/CActor.hpp" #include "Runtime/World/CMorphBallShadow.hpp" #include "Runtime/World/CWorldShadow.hpp" #include "Runtime/World/ScriptObjectSupport.hpp" #include #include #include namespace metaforce { class CActorLights; class CDamageInfo; class CPlayer; class CScriptWater; class CStateManager; struct CFinalInput; class CMorphBall { public: enum class EBallBoostState { BoostAvailable, BoostDisabled }; enum class ESpiderBallState { Inactive, Active }; enum class EBombJumpState { BombJumpAvailable, BombJumpDisabled }; private: struct CSpiderBallElectricityManager { u32 x0_effectIdx; u32 x4_lifetime; u32 x8_curFrame = 0; CSpiderBallElectricityManager(u32 effectIdx, u32 lifetime) : x0_effectIdx(effectIdx), x4_lifetime(lifetime) {} }; CPlayer& x0_player; s32 x4_loadedModelId = -1; u32 x8_ballGlowColorIdx = 0; float xc_radius; zeus::CVector3f x10_boostControlForce; zeus::CVector3f x1c_controlForce; bool x28_tireMode = false; float x2c_tireLeanAngle = 0.f; float x30_ballTiltAngle = 0.f; CCollidableSphere x38_collisionSphere; std::unique_ptr x58_ballModel; u32 x5c_ballModelShader = 0; std::unique_ptr x60_spiderBallGlassModel; u32 x64_spiderBallGlassModelShader = 0; std::unique_ptr x68_lowPolyBallModel; u32 x6c_lowPolyBallModelShader = 0; std::unique_ptr x70_frozenBallModel; CCollisionInfoList x74_collisionInfos; u32 xc78_ = 0; ESpiderBallState x187c_spiderBallState = ESpiderBallState::Inactive; zeus::CVector3f x1880_playerToSpiderNormal; float x188c_spiderPullMovement = 1.f; zeus::CVector3f x1890_spiderTrackPoint; zeus::CVector3f x189c_spiderInterpBetweenPoints; zeus::CVector3f x18a8_spiderBetweenPoints; float x18b4_linVelDamp = 0.f; float x18b8_angVelDamp = 0.f; bool x18bc_spiderNearby = false; bool x18bd_touchingSpider = false; bool x18be_spiderBallSwinging = false; bool x18bf_spiderSwingInAir = true; bool x18c0_isSpiderSurface = false; zeus::CTransform x18c4_spiderSurfaceTransform; float x18f4_spiderSurfacePivotAngle = 0.f; float x18f8_spiderSurfacePivotTargetAngle = 0.f; float x18fc_refPullVel = 0.f; float x1900_playerToSpiderTrackDist = 0.f; float x1904_swingControlDir = 0.f; float x1908_swingControlTime = 0.f; zeus::CVector2f x190c_normSpiderSurfaceForces; float x1914_spiderTrackForceMag = 0.f; float x1918_spiderViewControlMag = 0.f; float x191c_damageTimer = 0.f; bool x1920_spiderForcesReset = false; zeus::CTransform x1924_surfaceToWorld; bool x1954_isProjectile = false; std::vector x1958_animationTokens; TToken x1968_slowBlueTailSwoosh; TToken x1970_slowBlueTailSwoosh2; TToken x1978_jaggyTrail; TToken x1980_wallSpark; TToken x1988_ballInnerGlow; TToken x1990_spiderBallMagnetEffect; TToken x1998_boostBallGlow; TToken x19a0_spiderElectric; TToken x19a8_morphBallTransitionFlash; TToken x19b0_effect_morphBallIceBreak; std::unique_ptr x19b8_slowBlueTailSwooshGen; std::unique_ptr x19bc_slowBlueTailSwooshGen2; std::unique_ptr x19c0_slowBlueTailSwoosh2Gen; std::unique_ptr x19c4_slowBlueTailSwoosh2Gen2; std::unique_ptr x19c8_jaggyTrailGen; std::unique_ptr x19cc_wallSparkGen; std::unique_ptr x19d0_ballInnerGlowGen; std::unique_ptr x19d4_spiderBallMagnetEffectGen; std::unique_ptr x19d8_boostBallGlowGen; std::unique_ptr x19dc_morphBallTransitionFlashGen; std::unique_ptr x19e0_effect_morphBallIceBreakGen; rstl::reserved_vector, bool>, 32> x19e4_spiderElectricGens; std::list x1b6c_activeSpiderElectricList; CRandom16 x1b80_rand{99}; rstl::reserved_vector, 8> x1b84_wakeEffects; rstl::reserved_vector, 8> x1bc8_wakeEffectGens; s32 x1c0c_wakeEffectIdx = -1; TUniqueId x1c10_ballInnerGlowLight = kInvalidUniqueId; std::unique_ptr x1c14_worldShadow; std::unique_ptr x1c18_actorLights; std::unique_ptr x1c1c_rainSplashGen; float x1c20_tireFactor = 0.f; float x1c24_maxTireFactor = 0.5f; float x1c28_tireInterpSpeed = 1.f; bool x1c2c_tireInterpolating = false; float x1c30_boostOverLightFactor = 0.f; float x1c34_boostLightFactor = 0.f; float x1c38_spiderLightFactor = 0.f; TReservedAverage x1c3c_ballOrientAvg = {{}}; TReservedAverage x1c90_ballPosAvg = {{}}; TReservedAverage x1cd0_liftSpeedAvg = {{}}; TReservedAverage x1d10_liftControlForceAvg = {{}}; u32 x1dc8_failsafeCounter = 0; zeus::CVector3f x1dcc_; zeus::CVector3f x1dd8_; bool x1de4_24_inBoost : 1 = false; bool x1de4_25_boostEnabled : 1 = true; float x1de8_boostChargeTime = 0.f; float x1dec_timeNotInBoost = 0.f; float x1df0_ = 0.f; float x1df4_boostDrainTime = 0.f; bool x1df8_24_inHalfPipeMode : 1 = false; bool x1df8_25_inHalfPipeModeInAir : 1 = false; bool x1df8_26_touchedHalfPipeRecently : 1 = false; bool x1df8_27_ballCloseToCollision : 1 = false; float x1dfc_touchHalfPipeCooldown = 0.f; float x1e00_disableControlCooldown = 0.f; float x1e04_touchHalfPipeRecentCooldown = 0.f; zeus::CVector3f x1e08_prevHalfPipeNormal; zeus::CVector3f x1e14_halfPipeNormal; u32 x1e20_ballAnimIdx = 0; CSfxHandle x1e24_boostSfxHandle; CSfxHandle x1e28_wallHitSfxHandle; CSfxHandle x1e2c_rollSfxHandle; CSfxHandle x1e30_spiderSfxHandle; u16 x1e34_rollSfx = 0xffff; u16 x1e36_landSfx = 0xffff; u32 x1e38_wallSparkFrameCountdown = 0; EBallBoostState x1e3c_boostState = EBallBoostState::BoostAvailable; EBombJumpState x1e40_bombJumpState = EBombJumpState::BombJumpAvailable; float x1e44_damageEffect = 0.f; float x1e48_damageEffectDecaySpeed = 0.f; float x1e4c_damageTime = 0.f; std::unique_ptr x1e50_shadow; void LoadAnimationTokens(std::string_view ancsName); void InitializeWakeEffects(); static std::unique_ptr GetMorphBallModel(const char* name, float radius); void SelectMorphBallSounds(const CMaterialList& mat); void UpdateMorphBallSounds(float dt); static zeus::CVector3f TransformSpiderBallForcesXY(const zeus::CVector2f& forces, CStateManager& mgr); static zeus::CVector3f TransformSpiderBallForcesXZ(const zeus::CVector2f& forces, CStateManager& mgr); void ResetSpiderBallForces(); static void PointGenerator(void* ctx, const std::vector>& vn); public: CMorphBall(CPlayer& player, float radius); void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr); const CCollidableSphere& GetCollidableSphere() const { return x38_collisionSphere; } bool IsProjectile() const { return x1954_isProjectile; } void GetBallContactMaterials() const {} void GetWallBumpCounter() const {} void GetBoostChargeTimer() const {} bool IsBoosting() const { return x1de4_24_inBoost; } float GetBallRadius() const; float GetBallTouchRadius() const; float ForwardInput(const CFinalInput& input) const; float BallTurnInput(const CFinalInput& input) const; void ComputeBallMovement(const CFinalInput& input, CStateManager& mgr, float dt); bool IsMovementAllowed() const; void UpdateSpiderBall(const CFinalInput& input, CStateManager& mgr, float dt); void ApplySpiderBallSwingingForces(const CFinalInput& input, CStateManager& mgr, float dt); void ApplySpiderBallRollForces(const CFinalInput& input, CStateManager& mgr, float dt); zeus::CVector2f CalculateSpiderBallAttractionSurfaceForces(const CFinalInput& input) const; bool CheckForSwitchToSpiderBallSwinging(CStateManager& mgr) const; bool FindClosestSpiderBallWaypoint(CStateManager& mgr, const zeus::CVector3f& ballCenter, zeus::CVector3f& closestPoint, zeus::CVector3f& interpDeltaBetweenPoints, zeus::CVector3f& deltaBetweenPoints, float& distance, zeus::CVector3f& normal, bool& isSurface, zeus::CTransform& surfaceTransform) const; void SetSpiderBallSwingingState(bool active); float GetSpiderBallControllerMovement(const CFinalInput& input) const; void ResetSpiderBallSwingControllerMovementTimer(); void UpdateSpiderBallSwingControllerMovementTimer(float movement, float dt); float GetSpiderBallSwingControllerMovementScalar() const; void CreateSpiderBallParticles(const zeus::CVector3f& ballPos, const zeus::CVector3f& trackPoint); void ComputeMarioMovement(const CFinalInput& input, CStateManager& mgr, float dt); void SetSpiderBallState(ESpiderBallState state) { x187c_spiderBallState = state; } zeus::CTransform GetSwooshToWorld() const; zeus::CTransform GetBallToWorld() const; zeus::CTransform CalculateSurfaceToWorld(const zeus::CVector3f& trackNormal, const zeus::CVector3f& trackPoint, const zeus::CVector3f& ballDir) const; bool CalculateBallContactInfo(zeus::CVector3f& normal, zeus::CVector3f& point) const; void UpdateBallDynamics(CStateManager& mgr, float dt); void SwitchToMarble(); void SwitchToTire(); void Update(float dt, CStateManager& mgr); void DeleteLight(CStateManager& mgr); void SetBallLightActive(CStateManager& mgr, bool active); void EnterMorphBallState(CStateManager& mgr); void LeaveMorphBallState(CStateManager& mgr); void UpdateEffects(float dt, CStateManager& mgr); void ComputeBoostBallMovement(const CFinalInput& input, CStateManager& mgr, float dt); void EnterBoosting(CStateManager& mgr); void LeaveBoosting(); void CancelBoosting(); bool UpdateMarbleDynamics(CStateManager& mgr, float dt, const zeus::CVector3f& point); void ApplyFriction(float); void DampLinearAndAngularVelocities(float linDamp, float angDamp); float GetMinimumAlignmentSpeed() const; void PreRender(CStateManager& mgr, const zeus::CFrustum& frustum); void Render(const CStateManager& mgr, const CActorLights* lights) const; void ResetMorphBallTransitionFlash(); void UpdateMorphBallTransitionFlash(float dt); void RenderMorphBallTransitionFlash(const CStateManager&) const; void UpdateIceBreakEffect(float dt); void RenderIceBreakEffect(const CStateManager& mgr) const; bool IsMorphBallTransitionFlashValid() const { return x19dc_morphBallTransitionFlashGen != nullptr; } void RenderDamageEffects(const CStateManager& mgr, const zeus::CTransform& xf) const; void UpdateHalfPipeStatus(CStateManager& mgr, float dt); bool GetIsInHalfPipeMode() const { return x1df8_24_inHalfPipeMode; } void SetIsInHalfPipeMode(bool b) { x1df8_24_inHalfPipeMode = b; } bool GetIsInHalfPipeModeInAir() const { return x1df8_25_inHalfPipeModeInAir; } void SetIsInHalfPipeModeInAir(bool b) { x1df8_25_inHalfPipeModeInAir = b; } bool GetTouchedHalfPipeRecently() const { return x1df8_26_touchedHalfPipeRecently; } void SetTouchedHalfPipeRecently(bool b) { x1df8_26_touchedHalfPipeRecently = b; } void DisableHalfPipeStatus(); bool BallCloseToCollision(const CStateManager& mgr, float dist, const CMaterialFilter& filter) const; void CollidedWith(TUniqueId id, const CCollisionInfoList& list, CStateManager& mgr); bool IsInFrustum(const zeus::CFrustum& frustum) const; void ComputeLiftForces(const zeus::CVector3f& controlForce, const zeus::CVector3f& velocity, const CStateManager& mgr); float CalculateSurfaceFriction() const; void ApplyGravity(const CStateManager& mgr); void SpinToSpeed(float holdMag, const zeus::CVector3f& torque, float mag); float ComputeMaxSpeed() const; void Touch(CActor& actor, CStateManager& mgr); bool IsClimbable(const CCollisionInfo& cinfo) const; void FluidFXThink(CActor::EFluidState state, CScriptWater& water, CStateManager& mgr); void LoadMorphBallModel(CStateManager& mgr); void AddSpiderBallElectricalEffect(); void UpdateSpiderBallElectricalEffects(); void RenderSpiderBallElectricalEffect() const; void RenderEnergyDrainEffects(const CStateManager& mgr) const; void TouchModel(const CStateManager& mgr) const; void SetAsProjectile() { x1954_isProjectile = true; } EBallBoostState GetBallBoostState() const { return x1e3c_boostState; } void SetBallBoostState(EBallBoostState state) { x1e3c_boostState = state; } EBombJumpState GetBombJumpState() const { return x1e40_bombJumpState; } void SetBombJumpState(EBombJumpState state) { x1e40_bombJumpState = state; } void TakeDamage(float dam); void DrawBallShadow(const CStateManager& mgr); void DeleteBallShadow(); void CreateBallShadow(); void RenderToShadowTex(CStateManager& mgr); void StartLandingSfx(); ESpiderBallState GetSpiderBallState() const { return x187c_spiderBallState; } void SetDamageTimer(float t) { x191c_damageTimer = t; } void Stop(); void StopSounds(); void StopEffects(); CModelData& GetMorphballModelData() const { return *x58_ballModel; } u32 GetMorphballModelShader() const { return x5c_ballModelShader; } bool GetBoostEnabled() const { return x1de4_25_boostEnabled; } void SetBoostEnabed(bool b) { x1de4_25_boostEnabled = b; } bool IsInBoost() const { return x1de4_24_inBoost; } float GetBoostChargeTime() const { return x1de8_boostChargeTime; } // Contains red, green, and blue channel values using ColorArray = std::array; static const std::array BallGlowColors; static const std::array BallTransFlashColors; static const std::array BallAuxGlowColors; }; } // namespace metaforce