From 5bdc5643af43fc45c8c577678db9bb22abff3748 Mon Sep 17 00:00:00 2001 From: Henrique Gemignani Passos Lima Date: Thu, 24 Nov 2022 18:48:00 +0200 Subject: [PATCH] Add CIceBeam --- asm/MetroidPrime/Weapons/CIceBeam.s | 24 ++-- configure.py | 2 +- include/Kyoto/Particles/CElementGen.hpp | 3 + include/MetroidPrime/Weapons/CIceBeam.hpp | 29 ++++- src/MetroidPrime/Weapons/CIceBeam.cpp | 150 ++++++++++++++++++++++ 5 files changed, 193 insertions(+), 15 deletions(-) create mode 100644 src/MetroidPrime/Weapons/CIceBeam.cpp diff --git a/asm/MetroidPrime/Weapons/CIceBeam.s b/asm/MetroidPrime/Weapons/CIceBeam.s index e842b48f..a73b7f36 100644 --- a/asm/MetroidPrime/Weapons/CIceBeam.s +++ b/asm/MetroidPrime/Weapons/CIceBeam.s @@ -3,8 +3,8 @@ .section .data .balign 8 -.global lbl_803DF7E8 -lbl_803DF7E8: +.global __vt__8CIceBeam +__vt__8CIceBeam: # ROM: 0x3DC7E8 .4byte 0 .4byte 0 @@ -14,13 +14,13 @@ lbl_803DF7E8: .4byte PreRenderGunFx__8CIceBeamFRC13CStateManagerRC12CTransform4f .4byte PostRenderGunFx__8CIceBeamFRC13CStateManagerRC12CTransform4f .4byte UpdateGunFx__8CIceBeamFbfRC13CStateManagerRC12CTransform4f - .4byte Fire__8CIceBeamFbfQ212CPlayerState12EChargeStageRC12CTransform4fR13CStateManager9TUniqueId + .4byte Fire__8CIceBeamFbfQ212CPlayerState12EChargeStageRC12CTransform4fR13CStateManager9TUniqueIdff .4byte EnableFx__8CIceBeamFb .4byte EnableSecondaryFx__8CIceBeamFQ210CGunWeapon16ESecondaryFxType .4byte Draw__10CGunWeaponCFbRC13CStateManagerRC12CTransform4fRC11CModelFlagsPC12CActorLights .4byte DrawMuzzleFx__10CGunWeaponCFRC13CStateManager .4byte Update__8CIceBeamFfR13CStateManager - .4byte Load__8CIceBeamFb + .4byte Load__8CIceBeamFR13CStateManagerb .4byte Unload__8CIceBeamFR13CStateManager .4byte IsLoaded__8CIceBeamCFv .4byte 0 @@ -247,8 +247,8 @@ Unload__8CIceBeamFR13CStateManager: /* 800E11BC 000DE11C 38 21 00 10 */ addi r1, r1, 0x10 /* 800E11C0 000DE120 4E 80 00 20 */ blr -.global Load__8CIceBeamFb -Load__8CIceBeamFb: +.global Load__8CIceBeamFR13CStateManagerb +Load__8CIceBeamFR13CStateManagerb: /* 800E11C4 000DE124 94 21 FF F0 */ stwu r1, -0x10(r1) /* 800E11C8 000DE128 7C 08 02 A6 */ mflr r0 /* 800E11CC 000DE12C 90 01 00 14 */ stw r0, 0x14(r1) @@ -271,8 +271,8 @@ Load__8CIceBeamFb: /* 800E1210 000DE170 38 21 00 10 */ addi r1, r1, 0x10 /* 800E1214 000DE174 4E 80 00 20 */ blr -.global Fire__8CIceBeamFbfQ212CPlayerState12EChargeStageRC12CTransform4fR13CStateManager9TUniqueId -Fire__8CIceBeamFbfQ212CPlayerState12EChargeStageRC12CTransform4fR13CStateManager9TUniqueId: +.global Fire__8CIceBeamFbfQ212CPlayerState12EChargeStageRC12CTransform4fR13CStateManager9TUniqueIdff +Fire__8CIceBeamFbfQ212CPlayerState12EChargeStageRC12CTransform4fR13CStateManager9TUniqueIdff: /* 800E1218 000DE178 94 21 FF E0 */ stwu r1, -0x20(r1) /* 800E121C 000DE17C 7C 08 02 A6 */ mflr r0 /* 800E1220 000DE180 90 01 00 24 */ stw r0, 0x24(r1) @@ -695,9 +695,9 @@ __dt__8CIceBeamFv: /* 800E17F8 000DE758 93 C1 00 08 */ stw r30, 8(r1) /* 800E17FC 000DE75C 7C 7E 1B 79 */ or. r30, r3, r3 /* 800E1800 000DE760 41 82 00 D0 */ beq lbl_800E18D0 -/* 800E1804 000DE764 3C 60 80 3E */ lis r3, lbl_803DF7E8@ha +/* 800E1804 000DE764 3C 60 80 3E */ lis r3, __vt__8CIceBeam@ha /* 800E1808 000DE768 34 1E 02 44 */ addic. r0, r30, 0x244 -/* 800E180C 000DE76C 38 03 F7 E8 */ addi r0, r3, lbl_803DF7E8@l +/* 800E180C 000DE76C 38 03 F7 E8 */ addi r0, r3, __vt__8CIceBeam@l /* 800E1810 000DE770 90 1E 00 00 */ stw r0, 0(r30) /* 800E1814 000DE774 41 82 00 24 */ beq lbl_800E1838 /* 800E1818 000DE778 80 7E 02 44 */ lwz r3, 0x244(r30) @@ -772,9 +772,9 @@ __ct__8CIceBeamFUi11EWeaponType9TUniqueId14EMaterialTypesRC9CVector3f: /* 800E1908 000DE868 38 C1 00 08 */ addi r6, r1, 8 /* 800E190C 000DE86C B0 01 00 08 */ sth r0, 8(r1) /* 800E1910 000DE870 48 0D B8 A1 */ bl __ct__10CGunWeaponFUi11EWeaponType9TUniqueId14EMaterialTypesRC9CVector3f -/* 800E1914 000DE874 3C 60 80 3E */ lis r3, lbl_803DF7E8@ha +/* 800E1914 000DE874 3C 60 80 3E */ lis r3, __vt__8CIceBeam@ha /* 800E1918 000DE878 3C 80 80 3D */ lis r4, lbl_803CE598@ha -/* 800E191C 000DE87C 38 03 F7 E8 */ addi r0, r3, lbl_803DF7E8@l +/* 800E191C 000DE87C 38 03 F7 E8 */ addi r0, r3, __vt__8CIceBeam@l /* 800E1920 000DE880 38 61 00 1C */ addi r3, r1, 0x1c /* 800E1924 000DE884 90 1F 00 00 */ stw r0, 0(r31) /* 800E1928 000DE888 38 84 E5 98 */ addi r4, r4, lbl_803CE598@l diff --git a/configure.py b/configure.py index e4a63c34..132e8090 100755 --- a/configure.py +++ b/configure.py @@ -132,7 +132,7 @@ LIBS = [ "MetroidPrime/Weapons/CPlasmaBeam", ["MetroidPrime/Weapons/CPowerBeam", False], "MetroidPrime/Weapons/CWaveBeam", - "MetroidPrime/Weapons/CIceBeam", + ["MetroidPrime/Weapons/CIceBeam", False], ["MetroidPrime/CScriptMailbox", False], ["MetroidPrime/ScriptObjects/CScriptRelay", True], ["MetroidPrime/ScriptObjects/CScriptSpawnPoint", False], diff --git a/include/Kyoto/Particles/CElementGen.hpp b/include/Kyoto/Particles/CElementGen.hpp index a986397b..ee6d6333 100644 --- a/include/Kyoto/Particles/CElementGen.hpp +++ b/include/Kyoto/Particles/CElementGen.hpp @@ -83,6 +83,7 @@ public: static void ShutDown(); void SetGlobalOrientAndTrans(const CTransform4f& xf); + static void SetSubtractBlend(bool subtract) { sSubtractBlend = subtract; } public: TLockedToken< CGenDescription > x1c_genDesc; @@ -160,6 +161,8 @@ public: float x330_LFOR; float x334_LSLA; CColor x338_moduColor; + + static bool sSubtractBlend; }; CHECK_SIZEOF(CElementGen, 0x340) diff --git a/include/MetroidPrime/Weapons/CIceBeam.hpp b/include/MetroidPrime/Weapons/CIceBeam.hpp index 7a38e276..bf747f6a 100644 --- a/include/MetroidPrime/Weapons/CIceBeam.hpp +++ b/include/MetroidPrime/Weapons/CIceBeam.hpp @@ -9,10 +9,35 @@ class CIceBeam : public CGunWeapon { public: CIceBeam(CAssetId characterId, EWeaponType type, TUniqueId playerId, EMaterialTypes playerMaterial, const CVector3f& scale); - ~CIceBeam(); + ~CIceBeam() override; + + // CGunWeapon + void PreRenderGunFx(const CStateManager& mgr, const CTransform4f& xf) override; + void PostRenderGunFx(const CStateManager& mgr, const CTransform4f& xf) override; + void UpdateGunFx(bool shotSmoke, float dt, const CStateManager& mgr, + const CTransform4f& xf) override; + void Update(float dt, CStateManager& mgr) override; + void Fire(bool underwater, float dt, CPlayerState::EChargeStage chargeState, + const CTransform4f& xf, CStateManager& mgr, TUniqueId homingTarget, float chargeFactor1, + float chargeFactor2) override; + + void Load(CStateManager& mgr, bool subtypeBasePose) override; + void Unload(CStateManager& mgr) override; + bool IsLoaded() const override; + + void EnableFx(bool enable) override; + void EnableSecondaryFx(ESecondaryFxType type) override; private: - uchar x21c_pad[0x30]; + TCachedToken< CGenDescription > x21c_iceSmoke; + TCachedToken< CGenDescription > x228_ice2nd1; + TCachedToken< CGenDescription > x234_ice2nd2; + rstl::single_ptr< CElementGen > x240_smokeGen; + rstl::single_ptr< CElementGen > x244_chargeFx; + bool x248_24_loaded : 1; + bool x248_25_inEndFx : 1; + + void ReInitVariables(); }; CHECK_SIZEOF(CIceBeam, 0x24c) diff --git a/src/MetroidPrime/Weapons/CIceBeam.cpp b/src/MetroidPrime/Weapons/CIceBeam.cpp new file mode 100644 index 00000000..be709155 --- /dev/null +++ b/src/MetroidPrime/Weapons/CIceBeam.cpp @@ -0,0 +1,150 @@ +#include "MetroidPrime/Weapons/CIceBeam.hpp" + +#include "MetroidPrime/CStateManager.hpp" +#include "MetroidPrime/SFX/Weapons.h" + +#include "Kyoto/Audio/CSfxHandle.hpp" +#include "Kyoto/Particles/CElementGen.hpp" + +CIceBeam::CIceBeam(CAssetId characterId, EWeaponType type, TUniqueId playerId, + EMaterialTypes playerMaterial, const CVector3f& scale) +: CGunWeapon(characterId, type, playerId, playerMaterial, scale) + +, x21c_iceSmoke(gpSimplePool->GetObj("IceSmoke")) +, x228_ice2nd1(gpSimplePool->GetObj("Ice2nd_1")) +, x234_ice2nd2(gpSimplePool->GetObj("Ice2nd_2")) + +, x248_24_loaded(false) +, x248_25_inEndFx(false) {} + +CIceBeam::~CIceBeam() {} + +void CIceBeam::ReInitVariables() { + x240_smokeGen = nullptr; + x244_chargeFx = nullptr; + x248_24_loaded = false; + x248_25_inEndFx = false; + x1cc_enabledSecondaryEffect = kSFT_None; +} + +void CIceBeam::PreRenderGunFx(const CStateManager& mgr, const CTransform4f& xf) { + // Empty +} + +void CIceBeam::PostRenderGunFx(const CStateManager& mgr, const CTransform4f& xf) { + bool subtractBlend = mgr.GetThermalDrawFlag() == kTD_Hot; + if (subtractBlend) + CElementGen::SetSubtractBlend(true); + if (x240_smokeGen.get()) + x240_smokeGen->Render(); + if (x1cc_enabledSecondaryEffect != kSFT_None && x244_chargeFx.get()) + x244_chargeFx->Render(); + CGunWeapon::PostRenderGunFx(mgr, xf); + if (subtractBlend) + CElementGen::SetSubtractBlend(false); +} + +static const char* LBEAM = "LBEAM"; + +void CIceBeam::UpdateGunFx(bool shotSmoke, float dt, const CStateManager& mgr, + const CTransform4f& xf) { + if (x240_smokeGen.get()) { + CTransform4f beamLoc = x10_solidModelData->GetScaledLocatorTransform(rstl::string_l(LBEAM)); + x240_smokeGen->SetTranslation(beamLoc.GetTranslation()); + x240_smokeGen->SetOrientation(beamLoc.GetRotation()); + x240_smokeGen->Update(dt); + } + + if (x244_chargeFx.get()) { + if (x248_25_inEndFx && x244_chargeFx->IsSystemDeletable()) { + x1cc_enabledSecondaryEffect = kSFT_None; + x244_chargeFx = nullptr; + } + if (x1cc_enabledSecondaryEffect != kSFT_None) { + if (x248_25_inEndFx) { + x244_chargeFx->SetTranslation(xf.GetTranslation()); + x244_chargeFx->SetOrientation(xf.GetRotation()); + } else { + x244_chargeFx->SetGlobalOrientAndTrans(xf); + } + x244_chargeFx->Update(dt); + } + } + + CGunWeapon::UpdateGunFx(shotSmoke, dt, mgr, xf); +} + +void CIceBeam::Update(float dt, CStateManager& mgr) { + CGunWeapon::Update(dt, mgr); + + if (!x248_24_loaded) { + x248_24_loaded = x21c_iceSmoke.IsLoaded() && x228_ice2nd1.IsLoaded() && x234_ice2nd2.IsLoaded(); + if (x248_24_loaded) { + x240_smokeGen = new CElementGen(x21c_iceSmoke); + x240_smokeGen->SetGlobalScale(x4_scale); + x240_smokeGen->SetParticleEmission(false); + } + } +} + +void CIceBeam::Fire(bool underwater, float dt, CPlayerState::EChargeStage chargeState, + const CTransform4f& xf, CStateManager& mgr, TUniqueId homingTarget, + float chargeFactor1, float chargeFactor2) { + static ushort soundId[2] = {SFXwpn_fire_ice_normal, SFXwpn_fire_ice_charged}; + + CGunWeapon::Fire(underwater, dt, chargeState, xf, mgr, homingTarget, chargeFactor1, + chargeFactor2); + NWeaponTypes::play_sfx(soundId[size_t(chargeState)], underwater, false, 0x4a); +} + +void CIceBeam::Load(CStateManager& mgr, bool subtypeBasePose) { + CGunWeapon::Load(mgr, subtypeBasePose); + x21c_iceSmoke.Lock(); + x228_ice2nd1.Lock(); + x234_ice2nd2.Lock(); + x248_25_inEndFx = false; +} + +void CIceBeam::Unload(CStateManager& mgr) { + CGunWeapon::Unload(mgr); + x234_ice2nd2.Unlock(); + x228_ice2nd1.Unlock(); + x21c_iceSmoke.Unlock(); + ReInitVariables(); +} + +bool CIceBeam::IsLoaded() const { return CGunWeapon::IsLoaded() && x248_24_loaded; } + +void CIceBeam::EnableSecondaryFx(ESecondaryFxType type) { + switch (type) { + case kSFT_CancelCharge: + case kSFT_None: + if (x1cc_enabledSecondaryEffect == kSFT_None) + break; + default: + switch (type) { + case kSFT_None: + case kSFT_ToCombo: + case kSFT_CancelCharge: + if (!x248_25_inEndFx) { + x244_chargeFx = new CElementGen(x234_ice2nd2); + x244_chargeFx->SetGlobalScale(x4_scale); + x248_25_inEndFx = true; + x1cc_enabledSecondaryEffect = kSFT_CancelCharge; + } + break; + case kSFT_Charge: + x244_chargeFx = new CElementGen(x228_ice2nd1); + x244_chargeFx->SetGlobalScale(x4_scale); + x1cc_enabledSecondaryEffect = type; + x248_25_inEndFx = false; + break; + } + break; + } +} + +void CIceBeam::EnableFx(bool enable) { + if (x240_smokeGen.get()) + x240_smokeGen->SetParticleEmission(enable); +}