diff --git a/asm/MetroidPrime/CGameProjectile.s b/asm/MetroidPrime/CGameProjectile.s index a8d93c5f..9ec38b50 100644 --- a/asm/MetroidPrime/CGameProjectile.s +++ b/asm/MetroidPrime/CGameProjectile.s @@ -3656,7 +3656,7 @@ lbl_8003A660: /* 8003A69C 000375FC 38 6F 01 70 */ addi r3, r15, 0x170 /* 8003A6A0 00037600 38 A1 00 38 */ addi r5, r1, 0x38 /* 8003A6A4 00037604 38 C1 00 60 */ addi r6, r1, 0x60 -/* 8003A6A8 00037608 48 27 63 45 */ bl "__ct__17CProjectileWeaponFRC28TToken<18CWeaponDescription>RC9CVector3fRC12CTransform4fRC9CVector3f" +/* 8003A6A8 00037608 48 27 63 45 */ bl "__ct__17CProjectileWeaponFRC28TToken<18CWeaponDescription>RC9CVector3fRC12CTransform4fRC9CVector3fi" /* 8003A6AC 0003760C C0 54 00 2C */ lfs f2, 0x2c(r20) /* 8003A6B0 00037610 C0 34 00 1C */ lfs f1, 0x1c(r20) /* 8003A6B4 00037614 C0 14 00 0C */ lfs f0, 0xc(r20) diff --git a/asm/Weapons/CProjectileWeapon.s b/asm/Weapons/CProjectileWeapon.s index d42260bc..189cba03 100644 --- a/asm/Weapons/CProjectileWeapon.s +++ b/asm/Weapons/CProjectileWeapon.s @@ -2084,8 +2084,8 @@ lbl_802B09D0: /* 802B09E4 002AD944 38 21 00 10 */ addi r1, r1, 0x10 /* 802B09E8 002AD948 4E 80 00 20 */ blr -.global "__ct__17CProjectileWeaponFRC28TToken<18CWeaponDescription>RC9CVector3fRC12CTransform4fRC9CVector3f" -"__ct__17CProjectileWeaponFRC28TToken<18CWeaponDescription>RC9CVector3fRC12CTransform4fRC9CVector3f": +.global "__ct__17CProjectileWeaponFRC28TToken<18CWeaponDescription>RC9CVector3fRC12CTransform4fRC9CVector3fi" +"__ct__17CProjectileWeaponFRC28TToken<18CWeaponDescription>RC9CVector3fRC12CTransform4fRC9CVector3fi": /* 802B09EC 002AD94C 94 21 FF 60 */ stwu r1, -0xa0(r1) /* 802B09F0 002AD950 7C 08 02 A6 */ mflr r0 /* 802B09F4 002AD954 3D 20 80 3F */ lis r9, lbl_803EC4E8@ha diff --git a/configure.py b/configure.py index d742bbe2..204b0dac 100755 --- a/configure.py +++ b/configure.py @@ -397,7 +397,7 @@ LIBS = [ "cflags": "$cflags_retro", "host": True, "objects": [ - "Weapons/CProjectileWeapon", + ["Weapons/CProjectileWeapon", False], "Weapons/CProjectileWeaponDataFactory", "Weapons/CCollisionResponseData", ["Weapons/IWeaponRenderer", True], diff --git a/include/Kyoto/Particles/CParticleSwoosh.hpp b/include/Kyoto/Particles/CParticleSwoosh.hpp new file mode 100644 index 00000000..6615f241 --- /dev/null +++ b/include/Kyoto/Particles/CParticleSwoosh.hpp @@ -0,0 +1,38 @@ +#ifndef _CPARTICLESWOOSH +#define _CPARTICLESWOOSH + +#include "Kyoto/Particles/CParticleGen.hpp" + +class CSwooshDescription; +class CParticleSwoosh : public CParticleGen { +public: + CParticleSwoosh(const TToken& desc, int); + ~CParticleSwoosh(); + void Update(double); + void Render() const; + void SetOrientation(const CTransform4f& xf); + void SetTranslation(const CVector3f& vec); + void SetGlobalOrientation(const CTransform4f& xf); + void SetGlobalTranslation(const CVector3f& vec); + void SetGlobalScale(const CVector3f& scale); + void SetLocalScale(const CVector3f& scale); + void SetParticleEmission(bool emission); + void SetModulationColor(const CColor& col); + const CTransform4f& GetOrientation() const; + const CVector3f& GetTranslation() const; + CTransform4f GetGlobalOrientation() const; + CVector3f GetGlobalTranslation() const; + CVector3f GetGlobalScale() const; + bool GetParticleEmission() const; + CColor GetModulationColor() const; + bool IsSystemDeletable() const; + rstl::optional_object GetBounds() const; + int GetParticleCount() const; + bool SystemHasLight() const; + CLight GetLight(); + void DestroyParticles(); + void AddModifier(CWarp* warp); + uint Get4CharId() const; +}; + +#endif // _CPARTICLESWOOSH diff --git a/include/MetroidPrime/Weapons/CProjectileWeapon.hpp b/include/Weapons/CProjectileWeapon.hpp similarity index 67% rename from include/MetroidPrime/Weapons/CProjectileWeapon.hpp rename to include/Weapons/CProjectileWeapon.hpp index 1c8f6568..0fa4c3b7 100644 --- a/include/MetroidPrime/Weapons/CProjectileWeapon.hpp +++ b/include/Weapons/CProjectileWeapon.hpp @@ -3,6 +3,8 @@ #include "types.h" +#include "Weapons/IWeaponProjectile.hpp" + #include "Kyoto/CRandom16.hpp" #include "Kyoto/Graphics/CColor.hpp" #include "Kyoto/Math/CTransform4f.hpp" @@ -17,20 +19,24 @@ class CElementGen; class CModel; class CParticleSwoosh; -class CProjectileWeapon { +class CProjectileWeapon : public IWeaponProjectile { public: - // TODO ctor + CProjectileWeapon(const TToken< CWeaponDescription >&, const CVector3f&, const CTransform4f&, + const CVector3f&, int flags); - virtual ~CProjectileWeapon(); + ~CProjectileWeapon(); virtual void Update(float dt); virtual void AddToRenderer(); virtual void Render(); virtual CVector3f GetTranslation() const; virtual CTransform4f GetTransform() const; - + void SetRelativeOrientation(const CTransform4f& xf); + const CVector3f& GetVelocity() const; // { return xb0_velocity; } - CVector3f GetGravity() const; // { return xbc_gravity; } - static float GetTickPeriod(); // { return 0.0166667f; } + CVector3f GetGravity() const; // { return xbc_gravity; } + static float GetTickPeriod() { return 1.f / 60.f; } + + void UpdateChildParticleSystems(float dt); private: TLockedToken< CWeaponDescription > x4_weaponDesc; @@ -54,13 +60,13 @@ private: int xf0_; int xf4_curFrame; int xf8_lastParticleFrame; - rstl::single_ptr< CElementGen > xfc_APSMGen; - rstl::single_ptr< CElementGen > x100_APS2Gen; - rstl::single_ptr< CElementGen > x104_; - rstl::optional_object< TLockedToken< CModel > > x108_model; - rstl::single_ptr< CParticleSwoosh > x118_swoosh1; - rstl::single_ptr< CParticleSwoosh > x11c_swoosh2; - rstl::single_ptr< CParticleSwoosh > x120_swoosh3; + CElementGen* xfc_APSMGen; + CElementGen* x100_APS2Gen; + CElementGen* x104_; + rstl::optional_object< TCachedToken< CModel > > x108_model; + CParticleSwoosh* x118_swoosh1; + CParticleSwoosh* x11c_swoosh2; + CParticleSwoosh* x120_swoosh3; bool x124_24_active : 1; bool x124_25_APSO : 1; bool x124_26_AP11 : 1; diff --git a/include/Weapons/IWeaponProjectile.hpp b/include/Weapons/IWeaponProjectile.hpp new file mode 100644 index 00000000..c5bcf760 --- /dev/null +++ b/include/Weapons/IWeaponProjectile.hpp @@ -0,0 +1,9 @@ +#ifndef _IWEAPONPROJECTILE +#define _IWEAPONPROJECTILE + +class IWeaponProjectile { +public: + virtual ~IWeaponProjectile() {}; +}; + +#endif // _IWEAPONPROJECTILE diff --git a/src/Weapons/CProjectileWeapon.cpp b/src/Weapons/CProjectileWeapon.cpp new file mode 100644 index 00000000..83b28d0b --- /dev/null +++ b/src/Weapons/CProjectileWeapon.cpp @@ -0,0 +1,124 @@ +#include "Weapons/CProjectileWeapon.hpp" + +#include "Weapons/CWeaponDescription.hpp" + +#include "Kyoto/Math/CloseEnough.hpp" +#include "Kyoto/Math/CRelAngle.hpp" +#include "Kyoto/Particles/CElementGen.hpp" +#include "Kyoto/Particles/CParticleSwoosh.hpp" + +#include "rstl/math.hpp" + +CProjectileWeapon::CProjectileWeapon(const TToken< CWeaponDescription >& desc, + const CVector3f& worldOffset, const CTransform4f& orient, + const CVector3f& scale, int flags) +: x4_weaponDesc(desc) +, x14_localToWorldXf(orient) +, x44_localXf(CTransform4f::Identity()) +, x74_worldOffset(worldOffset) +, x80_localOffset(CVector3f::Zero()) +, x8c_projOffset(CVector3f::Zero()) +, x98_scale(CVector3f(1.f, 1.f, 1.f)) +, xa4_localOffset2(CVector3f::Zero()) +, xb0_velocity(CVector3f::Zero()) +, xbc_gravity(CVector3f::Zero()) +, xc8_ambientLightColor(CColor::White()) +, xd0_curTime(0.0) +, xd8_remainderTime(0.0) +, xe0_maxTurnRate(0.f) +, xe4_flags(flags) +, xe8_lifetime(0) +, xec_childSystemUpdateRate(0) +, xf0_(0) +, xf4_curFrame(0) +, xf8_lastParticleFrame(-1) +, xfc_APSMGen(nullptr) +, x100_APS2Gen(nullptr) +, x104_(nullptr) +, x118_swoosh1(nullptr) +, x11c_swoosh2(nullptr) +, x120_swoosh3(nullptr) +, x124_24_active(true) +, x124_25_APSO(false) +, x124_26_AP11(false) +, x124_27_AP21(false) +, x124_28_AS11(false) +, x124_29_AS12(false) +, x124_30_AS13(false) +, x124_31_VMD2(false) { + CGlobalRandom gr(x10_random); + x124_31_VMD2 = x4_weaponDesc->x10_VMD2; + x124_25_APSO = x4_weaponDesc->x28_APSO; + /* TODO: Getters */ + if (x4_weaponDesc->x34_APSM) { + xfc_APSMGen = + new CElementGen(*x4_weaponDesc->x34_APSM, CElementGen::kMOT_Normal, + (xe4_flags & 0x1) == 0x1 ? CElementGen::kOSF_Two : CElementGen::kOSF_One); + xfc_APSMGen->SetGlobalScale(scale); + } + + if (x4_weaponDesc->x44_APS2) { + x100_APS2Gen = + new CElementGen(*x4_weaponDesc->x44_APS2, CElementGen::kMOT_Normal, + (xe4_flags & 0x1) == 0x1 ? CElementGen::kOSF_Two : CElementGen::kOSF_One); + x100_APS2Gen->SetGlobalScale(scale); + } + if (x4_weaponDesc->x54_ASW1) { + x118_swoosh1 = new CParticleSwoosh(*x4_weaponDesc->x54_ASW1, 0); + x118_swoosh1->SetGlobalScale(scale); + } + if (x4_weaponDesc->x64_ASW2) { + x11c_swoosh2 = new CParticleSwoosh(*x4_weaponDesc->x64_ASW2, 0); + x11c_swoosh2->SetGlobalScale(scale); + } + if (x4_weaponDesc->x74_ASW3) { + x120_swoosh3 = new CParticleSwoosh(*x4_weaponDesc->x74_ASW3, 0); + x120_swoosh3->SetGlobalScale(scale); + } + + if (x4_weaponDesc->x14_PSLT) { + x4_weaponDesc->x14_PSLT->GetValue(0, xe8_lifetime); + } else { + xe8_lifetime = 0x7FFFFF; + } + + if (x4_weaponDesc->x4_IVEC) { + x4_weaponDesc->x4_IVEC->GetValue(0, xb0_velocity); + } + + if (x4_weaponDesc->x0_IORN) { + CTransform4f xf(CTransform4f::Identity()); + CVector3f orn(0.f, 0.f, 0.f); + x4_weaponDesc->x0_IORN->GetValue(0, orn); + xf.RotateLocalX(CRelAngle::FromDegrees(orn.GetX())); + xf.RotateLocalY(CRelAngle::FromDegrees(orn.GetY())); + xf.RotateLocalZ(CRelAngle::FromDegrees(orn.GetZ())); + SetRelativeOrientation(xf); + } else { + SetRelativeOrientation(CTransform4f::Identity()); + } + x108_model = x4_weaponDesc->x84_OHEF; + x124_26_AP11 = x4_weaponDesc->x2a_AP11; + x124_27_AP21 = x4_weaponDesc->x2b_AP21; + x124_28_AS11 = x4_weaponDesc->x2c_AS11; + x124_29_AS12 = x4_weaponDesc->x2d_AS12; + x124_30_AS13 = x4_weaponDesc->x2e_AS13; + UpdateChildParticleSystems(GetTickPeriod()); +} + +CProjectileWeapon::~CProjectileWeapon() { + delete xfc_APSMGen; + delete x100_APS2Gen; + delete x104_; + delete x118_swoosh1; + delete x11c_swoosh2; + delete x120_swoosh3; +} + +void CProjectileWeapon::Update(float dt) { + CGlobalRandom gr(x10_random); + xec_childSystemUpdateRate = 0; + double useDt = close_enough(dt, GetTickPeriod()) ? GetTickPeriod() : dt; + useDt = rstl::max_val(0.0, useDt); + xd0_curTime += useDt; +}