#include "MetroidPrime/Weapons/CPowerBeam.hpp" #include "MetroidPrime/SFX/Weapons.h" #include "Kyoto/Audio/CSfxHandle.hpp" #include "Kyoto/Graphics/CGraphics.hpp" #include "Kyoto/Particles/CElementGen.hpp" #include "MetaRender/CCubeRenderer.hpp" CPowerBeam::CPowerBeam(CAssetId characterId, EWeaponType type, TUniqueId playerId, EMaterialTypes playerMaterial, const CVector3f& scale) : CGunWeapon(characterId, type, playerId, playerMaterial, scale) , x21c_shotSmoke(gpSimplePool->GetObj("ShotSmoke")) , x228_power2nd1(gpSimplePool->GetObj("Power2nd_1")) , x23c_smokeTimer(0.f) , x240_smokeState(kSS_Inactive) , x244_24(false) , x244_25_loaded(false) {} CPowerBeam::~CPowerBeam() {} void CPowerBeam::ReInitVariables() { x234_shotSmokeGen = nullptr; x238_power2ndGen = nullptr; x23c_smokeTimer = 0.f; x240_smokeState = kSS_Inactive; x244_24 = false; x244_25_loaded = false; x1cc_enabledSecondaryEffect = kSFT_None; } void CPowerBeam::PreRenderGunFx(const CStateManager& mgr, const CTransform4f& xf) { CTransform4f backupView = CGraphics::GetViewMatrix(); CGraphics::SetViewPointMatrix(xf.GetInverse() * backupView); gpRender->SetModelMatrix(CTransform4f::Identity()); if (!x234_shotSmokeGen.null() && x240_smokeState != kSS_Inactive) x234_shotSmokeGen->Render(); CGraphics::SetViewPointMatrix(backupView); } void CPowerBeam::PostRenderGunFx(const CStateManager& mgr, const CTransform4f& xf) { if (x1cc_enabledSecondaryEffect != kSFT_None && !x238_power2ndGen.null()) x238_power2ndGen->Render(); CGunWeapon::PostRenderGunFx(mgr, xf); } void CPowerBeam::UpdateGunFx(bool shotSmoke, float dt, const CStateManager& mgr, const CTransform4f& xf) { switch (x240_smokeState) { case kSS_Inactive: if (shotSmoke) { if (!x234_shotSmokeGen.null()) x234_shotSmokeGen->SetParticleEmission(true); x23c_smokeTimer = 2.f; x240_smokeState = kSS_Active; } break; case kSS_Active: if (x23c_smokeTimer > 0.f) { x23c_smokeTimer -= dt; } else { if (!x234_shotSmokeGen.null()) x234_shotSmokeGen->SetParticleEmission(false); x240_smokeState = kSS_Done; } // [[fallthrough]]; case kSS_Done: if (!x234_shotSmokeGen.null()) { CTransform4f locator = x10_solidModelData->GetScaledLocatorTransform( rstl::string_l(CGunWeapon::skMuzzleLocator)); x234_shotSmokeGen->SetGlobalTranslation(locator.GetTranslation()); x234_shotSmokeGen->Update(dt); if (x240_smokeState == kSS_Done && x234_shotSmokeGen->GetSystemCount() == 0) x240_smokeState = kSS_Inactive; } else { x240_smokeState = kSS_Inactive; } break; } if (x1cc_enabledSecondaryEffect != kSFT_None && !x238_power2ndGen.null()) { x238_power2ndGen->SetGlobalOrientAndTrans(xf); x238_power2ndGen->Update(dt); } CGunWeapon::UpdateGunFx(shotSmoke, dt, mgr, xf); } void CPowerBeam::Update(float dt, CStateManager& mgr) { CGunWeapon::Update(dt, mgr); if (IsLoaded()) return; if (CGunWeapon::IsLoaded() && !x244_25_loaded) { x244_25_loaded = x21c_shotSmoke.TryCache() && x228_power2nd1.TryCache(); if (x244_25_loaded) { x234_shotSmokeGen = rs_new CElementGen(x21c_shotSmoke); x234_shotSmokeGen->SetParticleEmission(false); } } } void CPowerBeam::Fire(bool underwater, float dt, CPlayerState::EChargeStage chargeState, const CTransform4f& xf, CStateManager& mgr, TUniqueId homingTarget, float chargeFactor1, float chargeFactor2) { static const ushort skSoundId[] = { SFXwpn_fire_power_normal, SFXwpn_fire_power_charged, }; CGunWeapon::Fire(underwater, dt, chargeState, xf, mgr, homingTarget, chargeFactor1, chargeFactor2); NWeaponTypes::play_sfx(skSoundId[size_t(chargeState)], underwater, false, 0x4a); } void CPowerBeam::Load(CStateManager& mgr, bool subtypeBasePose) { CGunWeapon::Load(mgr, subtypeBasePose); x21c_shotSmoke.Lock(); x228_power2nd1.Lock(); } void CPowerBeam::Unload(CStateManager& mgr) { CGunWeapon::Unload(mgr); x228_power2nd1.Unlock(); x21c_shotSmoke.Unlock(); ReInitVariables(); } bool CPowerBeam::IsLoaded() const { return CGunWeapon::IsLoaded() && x244_25_loaded; } void CPowerBeam::EnableSecondaryFx(ESecondaryFxType type) { switch (type) { case kSFT_None: case kSFT_ToCombo: case kSFT_CancelCharge: if (x1cc_enabledSecondaryEffect != kSFT_None && !x238_power2ndGen.null()) x238_power2ndGen->SetParticleEmission(false); x1cc_enabledSecondaryEffect = kSFT_None; break; case kSFT_Charge: x238_power2ndGen = rs_new CElementGen(x228_power2nd1); x238_power2ndGen->SetGlobalScale(x4_scale); x1cc_enabledSecondaryEffect = type; break; default: break; } }