From d4efd4caa145836ca128d41e297be027fd9fa739 Mon Sep 17 00:00:00 2001 From: Henrique Gemignani Passos Lima Date: Thu, 8 Dec 2022 00:48:51 +0200 Subject: [PATCH] Add CWaveBeam Former-commit-id: c1d11e570133f341bf1d2b58b9fc9208af423099 --- asm/MetroidPrime/Weapons/CGunWeapon.s | 6 +- asm/MetroidPrime/Weapons/CWaveBeam.s | 40 ++-- configure.py | 2 +- .../Kyoto/Particles/CElectricDescription.hpp | 40 ++++ include/MetroidPrime/Weapons/CGunWeapon.hpp | 4 +- include/MetroidPrime/Weapons/CWaveBeam.hpp | 31 ++- src/MetroidPrime/Weapons/CGunWeapon.cpp | 2 +- src/MetroidPrime/Weapons/CWaveBeam.cpp | 180 ++++++++++++++++++ 8 files changed, 277 insertions(+), 28 deletions(-) create mode 100644 include/Kyoto/Particles/CElectricDescription.hpp create mode 100644 src/MetroidPrime/Weapons/CWaveBeam.cpp diff --git a/asm/MetroidPrime/Weapons/CGunWeapon.s b/asm/MetroidPrime/Weapons/CGunWeapon.s index 7e2649a5..2c6c3c4c 100644 --- a/asm/MetroidPrime/Weapons/CGunWeapon.s +++ b/asm/MetroidPrime/Weapons/CGunWeapon.s @@ -2230,7 +2230,7 @@ lbl_801BBB34: /* 801BBB40 001B8AA0 57 25 10 3A */ slwi r5, r25, 2 /* 801BBB44 001B8AA4 88 03 02 20 */ lbz r0, 0x220(r3) /* 801BBB48 001B8AA8 51 20 36 72 */ rlwimi r0, r9, 6, 0x19, 0x19 -/* 801BBB4C 001B8AAC 38 82 A9 D0 */ addi r4, r2, lbl_805AC6F0@sda21 +/* 801BBB4C 001B8AAC 38 82 A9 D0 */ addi r4, r2, skShootAnim__10CGunWeapon@sda21 /* 801BBB50 001B8AB0 C0 02 A9 D8 */ lfs f0, lbl_805AC6F8@sda21(r2) /* 801BBB54 001B8AB4 98 03 02 20 */ stb r0, 0x220(r3) /* 801BBB58 001B8AB8 38 00 FF FF */ li r0, -1 @@ -4017,8 +4017,8 @@ lbl_805AC6EC: # ROM: 0x3F8F8C .4byte lbl_803D19D7 -.global lbl_805AC6F0 -lbl_805AC6F0: +.global skShootAnim__10CGunWeapon +skShootAnim__10CGunWeapon: # ROM: 0x3F8F90 .4byte 0x00000004 .4byte 0x00000003 diff --git a/asm/MetroidPrime/Weapons/CWaveBeam.s b/asm/MetroidPrime/Weapons/CWaveBeam.s index 0e570750..84bae6ef 100644 --- a/asm/MetroidPrime/Weapons/CWaveBeam.s +++ b/asm/MetroidPrime/Weapons/CWaveBeam.s @@ -7,8 +7,8 @@ lbl_ctor: .section .data .balign 8 -.global lbl_803DF7A0 -lbl_803DF7A0: +.global __vt__9CWaveBeam +__vt__9CWaveBeam: # ROM: 0x3DC7A0 .4byte 0 .4byte 0 @@ -18,13 +18,13 @@ lbl_803DF7A0: .4byte PreRenderGunFx__10CGunWeaponFRC13CStateManagerRC12CTransform4f .4byte PostRenderGunFx__9CWaveBeamFRC13CStateManagerRC12CTransform4f .4byte UpdateGunFx__9CWaveBeamFbfRC13CStateManagerRC12CTransform4f - .4byte Fire__9CWaveBeamFbfQ212CPlayerState12EChargeStageRC12CTransform4fR13CStateManager9TUniqueId + .4byte Fire__9CWaveBeamFbfQ212CPlayerState12EChargeStageRC12CTransform4fR13CStateManager9TUniqueIdff .4byte EnableFx__10CGunWeaponFb .4byte EnableSecondaryFx__9CWaveBeamFQ210CGunWeapon16ESecondaryFxType .4byte Draw__10CGunWeaponCFbRC13CStateManagerRC12CTransform4fRC11CModelFlagsPC12CActorLights .4byte DrawMuzzleFx__10CGunWeaponCFRC13CStateManager .4byte Update__9CWaveBeamFfR13CStateManager - .4byte Load__9CWaveBeamFb + .4byte Load__9CWaveBeamFR13CStateManagerb .4byte Unload__9CWaveBeamFR13CStateManager .4byte IsLoaded__9CWaveBeamCFv .4byte 0 @@ -33,8 +33,8 @@ lbl_803DF7A0: .balign 8 # CWaveBeam -.global lbl_805A8EB8 -lbl_805A8EB8: +.global skShotAnglePitch +skShotAnglePitch: .skip 0x8 .section .sdata2, "a" @@ -75,8 +75,8 @@ lbl_805AACB0: # ROM: 0x3F7550 .double 4.503601774854144E15 -.global lbl_805AACB8 -lbl_805AACB8: +.global skShotAnglePitchSource +skShotAnglePitchSource: # ROM: 0x3F7558 .4byte 0x42F00000 .4byte 0 @@ -318,8 +318,8 @@ Unload__9CWaveBeamFR13CStateManager: /* 800E03E0 000DD340 38 21 00 10 */ addi r1, r1, 0x10 /* 800E03E4 000DD344 4E 80 00 20 */ blr -.global Load__9CWaveBeamFb -Load__9CWaveBeamFb: +.global Load__9CWaveBeamFR13CStateManagerb +Load__9CWaveBeamFR13CStateManagerb: /* 800E03E8 000DD348 94 21 FF F0 */ stwu r1, -0x10(r1) /* 800E03EC 000DD34C 7C 08 02 A6 */ mflr r0 /* 800E03F0 000DD350 90 01 00 14 */ stw r0, 0x14(r1) @@ -340,8 +340,8 @@ Load__9CWaveBeamFb: /* 800E042C 000DD38C 38 21 00 10 */ addi r1, r1, 0x10 /* 800E0430 000DD390 4E 80 00 20 */ blr -.global Fire__9CWaveBeamFbfQ212CPlayerState12EChargeStageRC12CTransform4fR13CStateManager9TUniqueId -Fire__9CWaveBeamFbfQ212CPlayerState12EChargeStageRC12CTransform4fR13CStateManager9TUniqueId: +.global Fire__9CWaveBeamFbfQ212CPlayerState12EChargeStageRC12CTransform4fR13CStateManager9TUniqueIdff +Fire__9CWaveBeamFbfQ212CPlayerState12EChargeStageRC12CTransform4fR13CStateManager9TUniqueIdff: /* 800E0434 000DD394 94 21 FE 10 */ stwu r1, -0x1f0(r1) /* 800E0438 000DD398 7C 08 02 A6 */ mflr r0 /* 800E043C 000DD39C 90 01 01 F4 */ stw r0, 0x1f4(r1) @@ -380,7 +380,7 @@ lbl_800E04AC: /* 800E04BC 000DD41C 3C 60 80 3D */ lis r3, lbl_803CE568@ha /* 800E04C0 000DD420 C3 A2 8F 88 */ lfs f29, lbl_805AACA8@sda21(r2) /* 800E04C4 000DD424 EF 80 00 72 */ fmuls f28, f0, f1 -/* 800E04C8 000DD428 C3 CD A2 F8 */ lfs f30, lbl_805A8EB8@sda21(r13) +/* 800E04C8 000DD428 C3 CD A2 F8 */ lfs f30, skShotAnglePitch@sda21(r13) /* 800E04CC 000DD42C 7F 53 02 14 */ add r26, r19, r0 /* 800E04D0 000DD430 CB E2 8F 90 */ lfd f31, lbl_805AACB0@sda21(r2) /* 800E04D4 000DD434 3B E3 E5 68 */ addi r31, r3, lbl_803CE568@l @@ -519,7 +519,7 @@ lbl_800E06A4: /* 800E06D0 000DD630 56 A5 10 3A */ slwi r5, r21, 2 /* 800E06D4 000DD634 88 03 02 20 */ lbz r0, 0x220(r3) /* 800E06D8 000DD638 51 20 36 72 */ rlwimi r0, r9, 6, 0x19, 0x19 -/* 800E06DC 000DD63C 38 82 A9 D0 */ addi r4, r2, lbl_805AC6F0@sda21 +/* 800E06DC 000DD63C 38 82 A9 D0 */ addi r4, r2, skShootAnim__10CGunWeapon@sda21 /* 800E06E0 000DD640 C0 02 8F 8C */ lfs f0, lbl_805AACAC@sda21(r2) /* 800E06E4 000DD644 98 03 02 20 */ stb r0, 0x220(r3) /* 800E06E8 000DD648 38 00 FF FF */ li r0, -1 @@ -897,9 +897,9 @@ __dt__9CWaveBeamFv: /* 800E0C28 000DDB88 93 C1 00 08 */ stw r30, 8(r1) /* 800E0C2C 000DDB8C 7C 7E 1B 79 */ or. r30, r3, r3 /* 800E0C30 000DDB90 41 82 00 EC */ beq lbl_800E0D1C -/* 800E0C34 000DDB94 3C 60 80 3E */ lis r3, lbl_803DF7A0@ha +/* 800E0C34 000DDB94 3C 60 80 3E */ lis r3, __vt__9CWaveBeam@ha /* 800E0C38 000DDB98 34 1E 02 54 */ addic. r0, r30, 0x254 -/* 800E0C3C 000DDB9C 38 03 F7 A0 */ addi r0, r3, lbl_803DF7A0@l +/* 800E0C3C 000DDB9C 38 03 F7 A0 */ addi r0, r3, __vt__9CWaveBeam@l /* 800E0C40 000DDBA0 90 1E 00 00 */ stw r0, 0(r30) /* 800E0C44 000DDBA4 41 82 00 24 */ beq lbl_800E0C68 /* 800E0C48 000DDBA8 80 7E 02 54 */ lwz r3, 0x254(r30) @@ -982,9 +982,9 @@ __ct__9CWaveBeamFUi11EWeaponType9TUniqueId14EMaterialTypesRC9CVector3f: /* 800E0D54 000DDCB4 38 C1 00 08 */ addi r6, r1, 8 /* 800E0D58 000DDCB8 B0 01 00 08 */ sth r0, 8(r1) /* 800E0D5C 000DDCBC 48 0D C4 55 */ bl __ct__10CGunWeaponFUi11EWeaponType9TUniqueId14EMaterialTypesRC9CVector3f -/* 800E0D60 000DDCC0 3C 60 80 3E */ lis r3, lbl_803DF7A0@ha +/* 800E0D60 000DDCC0 3C 60 80 3E */ lis r3, __vt__9CWaveBeam@ha /* 800E0D64 000DDCC4 3C 80 80 3D */ lis r4, lbl_803CE568@ha -/* 800E0D68 000DDCC8 38 03 F7 A0 */ addi r0, r3, lbl_803DF7A0@l +/* 800E0D68 000DDCC8 38 03 F7 A0 */ addi r0, r3, __vt__9CWaveBeam@l /* 800E0D6C 000DDCCC 38 61 00 24 */ addi r3, r1, 0x24 /* 800E0D70 000DDCD0 90 1F 00 00 */ stw r0, 0(r31) /* 800E0D74 000DDCD4 38 84 E5 68 */ addi r4, r4, lbl_803CE568@l @@ -1078,8 +1078,8 @@ __ct__9CWaveBeamFUi11EWeaponType9TUniqueId14EMaterialTypesRC9CVector3f: .global __sinit_CWaveBeam_cpp __sinit_CWaveBeam_cpp: -/* 800E0ED4 000DDE34 C0 02 8F 98 */ lfs f0, lbl_805AACB8@sda21(r2) -/* 800E0ED8 000DDE38 D0 0D A2 F8 */ stfs f0, lbl_805A8EB8@sda21(r13) +/* 800E0ED4 000DDE34 C0 02 8F 98 */ lfs f0, skShotAnglePitchSource@sda21(r2) +/* 800E0ED8 000DDE38 D0 0D A2 F8 */ stfs f0, skShotAnglePitch@sda21(r13) /* 800E0EDC 000DDE3C 4E 80 00 20 */ blr .section .rodata diff --git a/configure.py b/configure.py index 0435801a..42b90aab 100755 --- a/configure.py +++ b/configure.py @@ -109,7 +109,7 @@ LIBS = [ "MetroidPrime/Factories/CStateMachineFactory", ["MetroidPrime/Weapons/CPlasmaBeam", False], ["MetroidPrime/Weapons/CPowerBeam", False], - "MetroidPrime/Weapons/CWaveBeam", + ["MetroidPrime/Weapons/CWaveBeam", False], ["MetroidPrime/Weapons/CIceBeam", False], ["MetroidPrime/CScriptMailbox", False], ["MetroidPrime/ScriptObjects/CScriptRelay", True], diff --git a/include/Kyoto/Particles/CElectricDescription.hpp b/include/Kyoto/Particles/CElectricDescription.hpp new file mode 100644 index 00000000..e075625b --- /dev/null +++ b/include/Kyoto/Particles/CElectricDescription.hpp @@ -0,0 +1,40 @@ +#ifndef _CELECTRICDESCRIPTION +#define _CELECTRICDESCRIPTION + +#include "Kyoto/Particles/CParticleDataFactory.hpp" + +class CColorElement; +class CEmitterElement; +class CIntElement; +class CRealElement; + +// using SParticleModel = STokenDesc; +// using SChildGeneratorDesc = STokenDesc; +// using SSwooshGeneratorDesc = STokenDesc; +// using SElectricGeneratorDesc = STokenDesc; + +class CElectricDescription { +public: + CIntElement* x0_LIFE; + CIntElement* x4_SLIF; + CRealElement* x8_GRAT; + CIntElement* xc_SCNT; + CIntElement* x10_SSEG; + CColorElement* x14_COLR; + CEmitterElement* x18_IEMT; + CEmitterElement* x1c_FEMT; + CRealElement* x20_AMPL; + CRealElement* x24_AMPD; + CRealElement* x28_LWD1; + CRealElement* x2c_LWD2; + CRealElement* x30_LWD3; + CColorElement* x34_LCL1; + CColorElement* x38_LCL2; + CColorElement* x3c_LCL3; + // SSwooshGeneratorDesc x40_SSWH; + // SChildGeneratorDesc x50_GPSM; + // SChildGeneratorDesc x60_EPSM; + // bool x70_ZERY = false; +}; + +#endif // _CELECTRICDESCRIPTION diff --git a/include/MetroidPrime/Weapons/CGunWeapon.hpp b/include/MetroidPrime/Weapons/CGunWeapon.hpp index 99e33419..bd274818 100644 --- a/include/MetroidPrime/Weapons/CGunWeapon.hpp +++ b/include/MetroidPrime/Weapons/CGunWeapon.hpp @@ -96,7 +96,9 @@ public: rstl::optional_object< CModelData >& SolidModelData() { return x10_solidModelData; } const CModelData& GetSolidModelData() const { return x10_solidModelData.data(); } + EWeaponType GetWeaponType() const { return x1c0_weaponType; } TUniqueId GetPlayerId() const { return x1c4_playerId; } + EMaterialTypes GetPlayerMaterial() const { return x1c8_playerMaterial; } CAABox GetBounds() const; CAABox GetBounds(const CTransform4f& xf) const; @@ -162,7 +164,7 @@ protected: bool x218_28_suitArmLocked : 1; bool x218_29_drawHologram : 1; - static int skShootAnim[2]; + static const int skShootAnim[2]; void AllocResPools(CPlayerState::EBeamId beam); void FreeResPools(); diff --git a/include/MetroidPrime/Weapons/CWaveBeam.hpp b/include/MetroidPrime/Weapons/CWaveBeam.hpp index 9d6f977e..ad391114 100644 --- a/include/MetroidPrime/Weapons/CWaveBeam.hpp +++ b/include/MetroidPrime/Weapons/CWaveBeam.hpp @@ -5,14 +5,41 @@ #include "MetroidPrime/Weapons/CGunWeapon.hpp" +#include "rstl/single_ptr.hpp" + +class CElectricDescription; +class CParticleElectric; + class CWaveBeam : public CGunWeapon { public: CWaveBeam(CAssetId characterId, EWeaponType type, TUniqueId playerId, EMaterialTypes playerMaterial, const CVector3f& scale); - ~CWaveBeam(); + ~CWaveBeam() override; + + void PostRenderGunFx(const CStateManager& mgr, const CTransform4f& xf) override; + void UpdateGunFx(bool shotSmoke, float dt, const CStateManager& mgr, + const CTransform4f& xf) override; + void Fire(bool underwater, float dt, CPlayerState::EChargeStage chargeState, + const CTransform4f& xf, CStateManager& mgr, TUniqueId homingTarget, float chargeFactor1, + float chargeFactor2) override; + void EnableSecondaryFx(ESecondaryFxType type) override; + void Update(float dt, CStateManager& mgr) override; + void Load(CStateManager& mgr, bool subtypeBasePose) override; + void Unload(CStateManager& mgr) override; + bool IsLoaded() const override; private: - uchar x21c_pad[0x40]; + TCachedToken< CWeaponDescription > x21c_waveBeam; + TCachedToken< CElectricDescription > x228_wave2nd1; + TCachedToken< CElectricDescription > x234_wave2nd2; + TCachedToken< CGenDescription > x240_wave2nd3; + float x24c_effectTimer; + rstl::single_ptr< CParticleElectric > x250_chargeElec; + rstl::single_ptr< CElementGen > x254_chargeFx; + bool x258_24_loaded : 1; + bool x258_25_effectTimerActive : 1; + + void ReInitVariables(); }; CHECK_SIZEOF(CWaveBeam, 0x25c) diff --git a/src/MetroidPrime/Weapons/CGunWeapon.cpp b/src/MetroidPrime/Weapons/CGunWeapon.cpp index 638619f2..c6eec6ba 100644 --- a/src/MetroidPrime/Weapons/CGunWeapon.cpp +++ b/src/MetroidPrime/Weapons/CGunWeapon.cpp @@ -375,7 +375,7 @@ void CGunWeapon::DrawHologram(const CStateManager& mgr, const CTransform4f& xf, } } -int CGunWeapon::skShootAnim[2] = {4, 3}; +const int CGunWeapon::skShootAnim[2] = {4, 3}; static float kChargeScaleFactor = 1.0f; diff --git a/src/MetroidPrime/Weapons/CWaveBeam.cpp b/src/MetroidPrime/Weapons/CWaveBeam.cpp new file mode 100644 index 00000000..f166297e --- /dev/null +++ b/src/MetroidPrime/Weapons/CWaveBeam.cpp @@ -0,0 +1,180 @@ +#include "MetroidPrime/Weapons/CWaveBeam.hpp" + +#include "MetroidPrime/CAnimData.hpp" +#include "MetroidPrime/CAnimPlaybackParms.hpp" +#include "MetroidPrime/CStateManager.hpp" +#include "MetroidPrime/SFX/Weapons.h" +#include "MetroidPrime/Weapons/CEnergyProjectile.hpp" + +#include "Kyoto/Audio/CSfxHandle.hpp" +#include "Kyoto/Audio/CSfxManager.hpp" +#include "Kyoto/Math/CMath.hpp" +#include "Kyoto/Math/CRelAngle.hpp" +#include "Kyoto/Particles/CElectricDescription.hpp" +#include "Kyoto/Particles/CElementGen.hpp" +#include "Kyoto/Particles/CParticleElectric.hpp" + +static float skShotAnglePitchSource = 120.f; +static const float skShotAnglePitch = skShotAnglePitchSource; + +static const ushort kSoundId[2] = { + SFXwpn_fire_wave_normal, + SFXwpn_fire_wave_charged, +}; + +CWaveBeam::CWaveBeam(CAssetId characterId, EWeaponType type, TUniqueId playerId, + EMaterialTypes playerMaterial, const CVector3f& scale) +: CGunWeapon(characterId, type, playerId, playerMaterial, scale) +, x21c_waveBeam(gpSimplePool->GetObj("WaveBeam")) +, x228_wave2nd1(gpSimplePool->GetObj("Wave2nd_1")) +, x234_wave2nd2(gpSimplePool->GetObj("Wave2nd_2")) +, x240_wave2nd3(gpSimplePool->GetObj("Wave2nd_3")) +, x24c_effectTimer(0.f) +, x258_24_loaded(false) +, x258_25_effectTimerActive(false) {} + +CWaveBeam::~CWaveBeam() {} + +void CWaveBeam::ReInitVariables() { + x24c_effectTimer = 0.f; + x250_chargeElec = nullptr; + x254_chargeFx = nullptr; + x258_24_loaded = false; + x258_25_effectTimerActive = false; + x1cc_enabledSecondaryEffect = kSFT_None; +} + +void CWaveBeam::PostRenderGunFx(const CStateManager& mgr, const CTransform4f& xf) { + if (x1cc_enabledSecondaryEffect != kSFT_None) { + if (x254_chargeFx.get()) + x254_chargeFx->Render(); + if (x250_chargeElec.get()) + x250_chargeElec->Render(); + } + CGunWeapon::PostRenderGunFx(mgr, xf); +} + +void CWaveBeam::UpdateGunFx(bool shotSmoke, float dt, const CStateManager& mgr, + const CTransform4f& xf) { + if (x1cc_enabledSecondaryEffect != kSFT_None) { + if (x258_25_effectTimerActive && x24c_effectTimer < 0.f) { + x1cc_enabledSecondaryEffect = kSFT_None; + x24c_effectTimer = 0.f; + x258_25_effectTimerActive = false; + } else { + if (x254_chargeFx.get()) { + x254_chargeFx->SetGlobalTranslation(xf.GetTranslation()); + x254_chargeFx->SetGlobalOrientation(xf.GetRotation()); + x254_chargeFx->Update(dt); + } + if (x250_chargeElec.get()) { + x250_chargeElec->SetGlobalTranslation(xf.GetTranslation()); + x250_chargeElec->SetGlobalOrientation(xf.GetRotation()); + x250_chargeElec->Update(dt); + } + } + if (x258_25_effectTimerActive && x24c_effectTimer > 0.f) + x24c_effectTimer -= dt; + } + CGunWeapon::UpdateGunFx(shotSmoke, dt, mgr, xf); +} + +void CWaveBeam::Update(float dt, CStateManager& mgr) { + CGunWeapon::Update(dt, mgr); + if (IsLoaded()) + return; + + if (CGunWeapon::IsLoaded() && !x258_24_loaded) { + x258_24_loaded = x228_wave2nd1.IsLoaded() && x234_wave2nd2.IsLoaded() && + x240_wave2nd3.IsLoaded() && x21c_waveBeam.IsLoaded(); + } +} + +void CWaveBeam::Fire(bool underwater, float dt, CPlayerState::EChargeStage chargeState, + const CTransform4f& xf, CStateManager& mgr, TUniqueId homingTarget, + float chargeFactor1, float chargeFactor2) { + if (chargeState != CPlayerState::kCS_Normal) { + CGunWeapon::Fire(underwater, dt, chargeState, xf, mgr, homingTarget, chargeFactor1, + chargeFactor2); + } else { + float randAng = mgr.Random()->Float() * 360.f; + for (int i = 0; i < 3; ++i) { + CTransform4f shotXf = + xf * CTransform4f::RotateY(CRelAngle::FromDegrees((randAng + i) * skShotAnglePitch)); + CEnergyProjectile* proj = new CEnergyProjectile( + true, x144_weapons[chargeState], GetWeaponType(), shotXf, GetPlayerMaterial(), + GetDamageInfo(mgr, chargeState, chargeFactor1), mgr.AllocateUniqueId(), kInvalidAreaId, + GetPlayerId(), homingTarget, kPA_ArmCannon, underwater, CVector3f(1.f, 1.f, 1.f), + rstl::optional_object_null(), CSfxManager::kInternalInvalidSfxId, false); + mgr.AddObject(proj); + proj->Think(dt, mgr); + } + } + + if (chargeState != CPlayerState::kCS_Normal) + x218_25_enableCharge = true; + + NWeaponTypes::play_sfx(kSoundId[size_t(chargeState)], underwater, false, 0x4a); + x10_solidModelData->AnimationData()->EnableLooping(false); + const CAnimPlaybackParms parms(skShootAnim[chargeState], -1, 1.f, true); + x10_solidModelData->AnimationData()->SetAnimation(parms, false); +} + +void CWaveBeam::Load(CStateManager& mgr, bool subtypeBasePose) { + CGunWeapon::Load(mgr, subtypeBasePose); + x228_wave2nd1.Lock(); + x234_wave2nd2.Lock(); + x240_wave2nd3.Lock(); + x21c_waveBeam.Lock(); +} + +void CWaveBeam::Unload(CStateManager& mgr) { + CGunWeapon::Unload(mgr); + x21c_waveBeam.Unlock(); + x240_wave2nd3.Unlock(); + x234_wave2nd2.Unlock(); + x228_wave2nd1.Unlock(); + ReInitVariables(); +} + +bool CWaveBeam::IsLoaded() const { return CGunWeapon::IsLoaded() && x258_24_loaded; } + +void CWaveBeam::EnableSecondaryFx(ESecondaryFxType type) { + switch (type) { + case kSFT_None: + x1cc_enabledSecondaryEffect = kSFT_None; + break; + case kSFT_CancelCharge: + if (x1cc_enabledSecondaryEffect == kSFT_None) + break; + // [[fallthrough]]; + default: + if (x1cc_enabledSecondaryEffect != kSFT_ToCombo) { + CToken fx = type == kSFT_Charge ? x228_wave2nd1 : x234_wave2nd2; + x250_chargeElec = new CParticleElectric(fx); + x250_chargeElec->SetGlobalScale(x4_scale); + } + switch (type) { + case kSFT_Charge: + x254_chargeFx = nullptr; + break; + case kSFT_CancelCharge: + if (x1cc_enabledSecondaryEffect != kSFT_CancelCharge) { + x258_25_effectTimerActive = true; + x24c_effectTimer = 3.f; + if (x254_chargeFx.get()) + x254_chargeFx->SetParticleEmission(false); + } + break; + case kSFT_ToCombo: + x254_chargeFx = new CElementGen(x240_wave2nd3); + x254_chargeFx->SetGlobalScale(x4_scale); + x24c_effectTimer = 0.f; + x258_25_effectTimerActive = true; + break; + default: + break; + } + x1cc_enabledSecondaryEffect = type; + } +}