Projectile/Weapon imps, nearly match CProjectileWeapon

This commit is contained in:
Phillip Stephens 2024-12-26 14:51:03 -08:00
parent c8a64745df
commit fa78ba920b
14 changed files with 840 additions and 13 deletions

View File

@ -12,7 +12,7 @@ jobs:
strategy:
fail-fast: false
matrix:
version: [GM8E01_00] # GM8E01_01, GM8E01_48
version: [GM8E01_00, GM8E01_01] #, GM8E01_48
steps:
# Checkout the repository

View File

@ -11761,7 +11761,7 @@ fn_802AE990 = .text:0x802AE990; // type:function size:0x2A0
fn_802AEC30 = .text:0x802AEC30; // type:function size:0x18
fn_802AEC48 = .text:0x802AEC48; // type:function size:0xC0
GetBounds__17CProjectileWeaponCFv = .text:0x802AED08; // type:function size:0x400 scope:global
SetGlobalSeed__17CProjectileWeaponFUs = .text:0x802AF108; // type:function size:0x8 scope:global
SetGlobalSeed__17CProjectileWeaponFUi = .text:0x802AF108; // type:function size:0x8 scope:global
GetGravity__17CProjectileWeaponCFv = .text:0x802AF110; // type:function size:0x8 scope:global
SetGravity__17CProjectileWeaponFRC9CVector3f = .text:0x802AF118; // type:function size:0x1C scope:global
GetVelocity__17CProjectileWeaponCFv = .text:0x802AF134; // type:function size:0x8 scope:global
@ -18623,8 +18623,8 @@ lbl_803EC448 = .data:0x803EC448; // type:object size:0x28
__vt__23CCollidableOBBTreeGroup = .data:0x803EC470; // type:object size:0x28 scope:global
__vt__60TObjOwnerDerivedFromIObj<32CCollidableOBBTreeGroupContainer> = .data:0x803EC498; // type:object size:0x10
jumptable_803EC4A8 = .data:0x803EC4A8; // type:object size:0x20 scope:local
lbl_803EC4C8 = .data:0x803EC4C8; // type:object size:0x20
lbl_803EC4E8 = .data:0x803EC4E8; // type:object size:0x20
__vt__17CProjectileWeapon = .data:0x803EC4C8; // type:object size:0x20
__vt__17IWeaponProjectile = .data:0x803EC4E8; // type:object size:0x20 scope:weak
lbl_803EC508 = .data:0x803EC508; // type:object size:0x10
lbl_803EC518 = .data:0x803EC518; // type:object size:0x10
__vt__22CDefaultWeaponRenderer = .data:0x803EC528; // type:object size:0x10 scope:weak

View File

@ -11761,7 +11761,7 @@ fn_802AE990 = .text:0x802AEA3C; // type:function size:0x2A0 scope:global
fn_802AEC30 = .text:0x802AECDC; // type:function size:0x18 scope:global
fn_802AEC48 = .text:0x802AECF4; // type:function size:0xC0 scope:global
GetBounds__17CProjectileWeaponCFv = .text:0x802AEDB4; // type:function size:0x400 scope:global
SetGlobalSeed__17CProjectileWeaponFUs = .text:0x802AF1B4; // type:function size:0x8 scope:global
SetGlobalSeed__17CProjectileWeaponFUi = .text:0x802AF1B4; // type:function size:0x8 scope:global
GetGravity__17CProjectileWeaponCFv = .text:0x802AF1BC; // type:function size:0x8 scope:global
SetGravity__17CProjectileWeaponFRC9CVector3f = .text:0x802AF1C4; // type:function size:0x1C scope:global
GetVelocity__17CProjectileWeaponCFv = .text:0x802AF1E0; // type:function size:0x8 scope:global
@ -17741,7 +17741,7 @@ lbl_803D62D0 = .rodata:0x803D62D0; // type:object size:0x20
lbl_803D62F0 = .rodata:0x803D62F0; // type:object size:0x8
lbl_803D62F8 = .rodata:0x803D62F8; // type:object size:0x20
lbl_803D6318 = .rodata:0x803D6318; // type:object size:0x50
lbl_803D6368 = .rodata:0x803D6368; // type:object size:0x8
@stringBase0 = .rodata:0x803D6368; // type:object size:0x7 scope:local data:string_table
lbl_803D6370 = .rodata:0x803D6370; // type:object size:0x8
lbl_803D6378 = .rodata:0x803D6378; // type:object size:0x80
lbl_803D63F8 = .rodata:0x803D63F8; // type:object size:0x178 data:4byte
@ -18657,8 +18657,8 @@ lbl_803EC628 = .data:0x803EC628; // type:object size:0x28
lbl_803EC650 = .data:0x803EC650; // type:object size:0x28
lbl_803EC678 = .data:0x803EC678; // type:object size:0x10
jumptable_803EC688 = .data:0x803EC688; // type:object size:0x20 scope:local
lbl_803EC6A8 = .data:0x803EC6A8; // type:object size:0x20
lbl_803EC6C8 = .data:0x803EC6C8; // type:object size:0x20
__vt__17CProjectileWeapon = .data:0x803EC6A8; // type:object size:0x20
__vt__17IWeaponProjectile = .data:0x803EC6C8; // type:object size:0x20 scope:weak
lbl_803EC6E8 = .data:0x803EC6E8; // type:object size:0x10
lbl_803EC6F8 = .data:0x803EC6F8; // type:object size:0x10
__vt__22CDefaultWeaponRenderer = .data:0x803EC708; // type:object size:0x10
@ -21051,7 +21051,7 @@ lbl_805A880C = .sdata:0x805A880C; // type:object size:0x1 data:byte
lbl_805A8810 = .sdata:0x805A8810; // type:object size:0x8 data:4byte
lbl_805A8818 = .sdata:0x805A8818; // type:object size:0x8 data:4byte
lbl_805A8820 = .sdata:0x805A8820; // type:object size:0x8
lbl_805A8828 = .sdata:0x805A8828; // type:object size:0x8 data:4byte
skGlobalSeed__17CProjectileWeapon = .sdata:0x805A8828; // type:object size:0x4 data:4byte
sWeaponRenderer__15IWeaponRenderer = .sdata:0x805A8830; // type:object size:0x8 data:4byte
lbl_805A8838 = .sdata:0x805A8838; // type:object size:0x4 data:float
lbl_805A883C = .sdata:0x805A883C; // type:object size:0x4 data:float

View File

@ -77,6 +77,7 @@ public:
int GetMaxParticles() const { return x90_MAXP; }
int GetEmitterTime() const;
int GetSystemCount();
void EndLifetime();
int GetCumulativeParticleCount() const { return x260_cumulativeParticles; }
bool IsIndirectTextured()

View File

@ -0,0 +1,97 @@
#ifndef _CPARTICLESWOOSH_HPP
#define _CPARTICLESWOOSH_HPP
#include "Kyoto/CRandom16.hpp"
#include "Kyoto/Graphics/CColor.hpp"
#include "Kyoto/Math/CTransform4f.hpp"
#include "Kyoto/Particles/CParticleGen.hpp"
#include "Kyoto/Particles/IElement.hpp"
#include "Kyoto/TToken.hpp"
#include "MetroidPrime/CParticleDatabase.hpp"
#include "dolphin/gx/GXEnum.h"
class CParticleSwoosh : public CParticleGen {
public:
struct SSwooshData {};
CParticleSwoosh(TToken< CSwooshDescription > desc, int i);
~CParticleSwoosh();
void Update(double);
void Render() const;
void SetOrientation(const CTransform4f& orientation);
void SetTranslation(const CVector3f& translation);
void SetGlobalOrientation(const CTransform4f& orientation);
void SetGlobalTranslation(const CVector3f& translation);
void SetGlobalScale(const CVector3f& scale);
void SetLocalScale(const CVector3f& scale);
void SetParticleEmission(bool emission);
void SetModulationColor(const CColor& col);
void SetGeneratorRate(float rate) {}
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< CAABox > GetBounds() const;
int GetParticleCount() const;
bool SystemHasLight() const;
CLight GetLight();
void DestroyParticles();
void AddModifier(CWarp*);
uint Get4CharId() const;
void SetWarmUp() { x1d0_26_forceOneUpdate = true; }
private:
TLockedToken< CSwooshDescription > x1c_desc;
uint x28_curFrame;
int x2c_PSLT;
double x30_curTime;
CVector3f x38_translation;
CTransform4f x44_orientation;
CTransform4f x74_invOrientation;
CVector3f xa4_globalTranslation;
CTransform4f xa4_globalOrientation;
CVector3f xe0_globalScale;
CTransform4f xec_scaleXf;
CTransform4f x11c_invScaleXf;
CVector3f x14c_localScale;
uint x158_curParticle;
rstl::vector< SSwooshData > x15c_swooshes;
rstl::vector< CVector3f > x16c_p0;
rstl::vector< CVector3f > x17c_p1;
rstl::vector< CVector3f > x18c_p2;
rstl::vector< CVector3f > x19c_p3;
uint x1ac_particleCount;
int x1b0_SPLN;
int x1b4_LENG;
int x1b8_SIDE;
GXPrimitive x1bc_prim;
CRandom16 x1c0_rand;
float x1c4_;
float x1c8_;
float x1cc_TSPN;
bool x1d0_24_emitting : 1;
bool x1d0_25_AALP : 1;
bool x1d0_26_forceOneUpdate : 1;
bool x1d0_27_renderGaps : 1;
bool x1d0_28_LLRD : 1;
bool x1d0_29_VLS1 : 1;
bool x1d0_30_VLS2 : 1;
bool x1d0_31_constantTex : 1;
bool x1d1_24_constantUv : 1;
SUVElementSet x1d4_uvs;
CTexture* x1e4_tex;
float x1e8_uvSpan;
int x1ec_TSPN;
CVector3f x1f0_aabbMin;
CVector3f x1fc_aabbMax;
float x208_maxRadius;
CColor x20c_moduColor;
};
#endif // _CPARTICLESWOOSH_HPP

View File

@ -35,7 +35,7 @@ public:
void PostRenderFogs() override;
void SetModelMatrix(const CTransform4f& xf) override;
void AddParticleGen(const CParticleGen& gen) override;
void AddParticleGen2() override;
void AddParticleGen(const CParticleGen& gen, const CVector3f&, const CAABox&) override;
void AddPlaneObject() override;
void AddDrawable(const void* obj, const CVector3f& pos, const CAABox& bounds, int mode,
IRenderer::EDrawableSorting sorting) override;

View File

@ -2,6 +2,7 @@
#define _IRENDERER
#include "types.h"
#include <dolphin/gx/GXEnum.h>
#include "rstl/pair.hpp"
#include "rstl/vector.hpp"
@ -46,7 +47,7 @@ public:
virtual void PostRenderFogs();
virtual void SetModelMatrix(const CTransform4f& xf);
virtual void AddParticleGen(const CParticleGen& gen);
virtual void AddParticleGen2();
virtual void AddParticleGen(const CParticleGen& gen, const CVector3f&, const CAABox&);
virtual void AddPlaneObject();
virtual void AddDrawable(const void* obj, const CVector3f& pos, const CAABox& bounds, int mode,
IRenderer::EDrawableSorting sorting);

View File

@ -0,0 +1,18 @@
#ifndef _COLLISIONRESPONSEDATA_HPP
#define _COLLISIONRESPONSEDATA_HPP
#include "MetroidPrime/ActorCommon.hpp"
#include "Weapons/CDecalDescription.hpp"
#include <rstl/optional_object.hpp>
class CCollisionResponseData {
public:
rstl::optional_object< TLockedToken< CDecalDescription > >
GetDecalDescription(EWeaponCollisionResponseTypes type) const;
rstl::optional_object< TLockedToken< CGenDescription > >
GetParticleDescription(EWeaponCollisionResponseTypes type) const;
uint GetSoundEffectId(EWeaponCollisionResponseTypes type) const;
float GetAudibleRange() const;
float GetAudibleFallOff() const;
};
#endif

View File

@ -0,0 +1,104 @@
#ifndef _CPROJECTILEWEAPON_HPP
#define _CPROJECTILEWEAPON_HPP
#include <Kyoto/CRandom16.hpp>
#include <Kyoto/Graphics/CColor.hpp>
#include <Kyoto/Math/CTransform4f.hpp>
#include <Kyoto/Particles/CElementGen.hpp>
#include <Kyoto/Particles/CParticleSwoosh.hpp>
#include <Kyoto/TToken.hpp>
#include <rstl/single_ptr.hpp>
#include "Kyoto/Math/CMatrix4f.hpp"
#include "Kyoto/Particles/CGenDescription.hpp"
#include "MetroidPrime/ActorCommon.hpp"
#include "MetroidPrime/Weapons/WeaponTypes.hpp"
#include "Weapons/CDecalDescription.hpp"
#include "Weapons/CWeaponDescription.hpp"
#include "Weapons/IWeaponProjectile.hpp"
#include "rstl/optional_object.hpp"
class CProjectileWeapon : public IWeaponProjectile {
static uint skGlobalSeed;
CProjectileWeapon(const TToken< CWeaponDescription >& description, const CVector3f& worldOffset,
const CTransform4f& localToWorld, const CVector3f& scale, int flags);
~CProjectileWeapon();
static float GetTickPeriod();
bool Update(float dt);
void UpdateParticleFX();
const CTransform4f GetTransform() const;
CTransform4f GetTransform();
const CVector3f GetTranslation() const;
void SetRelativeOrientation(const CTransform4f& orient);
void SetWorldSpaceOrientation(const CTransform4f& orient);
void UpdatePSTranslationAndOrientation();
void UpdateChildParticleSystems(float dt);
const bool IsSystemDeletable() const;
void Render() const;
void AddToRenderer() const;
void RenderParticles() const;
rstl::optional_object< TLockedToken< CGenDescription > >
CollisionOccured(const EWeaponCollisionResponseTypes colType, const bool deflected,
const bool useTarget, const CVector3f& pos, const CVector3f& normal,
const CVector3f& target);
uint GetSoundIdForCollision(EWeaponCollisionResponseTypes type) const;
rstl::optional_object< TLockedToken< CDecalDescription > >
GetDecalForCollision(EWeaponCollisionResponseTypes type) const;
float GetAudibleRange() const;
float GetAudibleFallOff() const;
float GetMaxTurnRate() const;
void SetVelocity(const CVector3f& velocity);
const CVector3f& GetVelocity() const;
void SetGravity(const CVector3f& gravity);
const CVector3f& GetGravity() const;
static void SetGlobalSeed(uint seed);
rstl::optional_object< CAABox > GetBounds() const;
private:
TLockedToken< CWeaponDescription > x4_weaponDesc;
CRandom16 x10_random;
CTransform4f x14_localToWorldXf;
CTransform4f x44_localXf;
CVector3f x74_worldOffset;
CVector3f x80_localOffset;
CVector3f x8c_projOffset;
CVector3f x98_scale;
CVector3f xa4_localOffset2;
CVector3f xb0_velocity;
CVector3f xbc_gravity;
CColor xc8_ambientLightColor;
double xd0_curTime;
double xd8_remainderTime;
float xe0_maxTurnRate;
int xe4_flags;
int xe8_lifetime;
int xec_childSystemUpdateRate;
int xf0_;
int xf4_curFrame;
int xf8_lastParticleFrame;
CElementGen* xfc_APSMGen;
CElementGen* x100_APS2Gen;
CElementGen* x104_;
rstl::optional_object< TLockedToken< 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;
bool x124_27_AP21 : 1;
bool x124_28_AS11 : 1;
bool x124_29_AS12 : 1;
bool x124_30_AS13 : 1;
bool x124_31_VMD2 : 1;
};
#endif // _CPROJECTILEWEAPON_HPP

View File

@ -15,11 +15,13 @@ class CCollisionResponseData;
class CWeaponDescription {
public:
typedef rstl::optional_object< TCachedToken< CModel > > TParticleModel;
typedef rstl::optional_object< TLockedToken< CModel > > TParticleModel;
typedef rstl::optional_object< TCachedToken< CGenDescription > > TChildGeneratorDesc;
typedef rstl::optional_object< TCachedToken< CSwooshDescription > > TSwooshGeneratorDesc;
typedef rstl::optional_object< TCachedToken< CCollisionResponseData > > TCollisionResponseDesc;
const TCollisionResponseDesc& GetCollisionResponse() const { return x94_COLR; }
const TParticleModel& GetOHEF() const { return x84_OHEF; }
CWeaponDescription();
~CWeaponDescription();
CVectorElement* x0_IORN;

View File

@ -0,0 +1,17 @@
#ifndef _IWEAPONPROJECTILE_HPP
#define _IWEAPONPROJECTILE_HPP
class CVector3f;
class CTransform4f;
class IWeaponProjectile {
public:
virtual ~IWeaponProjectile() {};
virtual bool Update(float dt) = 0;
virtual void AddToRenderer() const = 0;
virtual void Render() const = 0;
virtual const CVector3f GetTranslation() const = 0;
virtual const CTransform4f GetTransform() const = 0;
};
#endif // _IWEAPONPROJECTILE_HPP

View File

@ -10,6 +10,7 @@ public:
virtual ~IWeaponRenderer() = 0;
virtual void AddParticleGen(const CParticleGen& gen) = 0;
static void SetRenderer(IWeaponRenderer* renderer) { sWeaponRenderer = renderer; }
static IWeaponRenderer* GetRenderer() { return sWeaponRenderer; }
private:
static IWeaponRenderer* sWeaponRenderer;

View File

@ -36,6 +36,7 @@
#include "MetaRender/CCubeRenderer.hpp"
#include "Weapons/IWeaponRenderer.hpp"
#include "math.h"
static float kVerticalAngleTable[3] = {-30.f, 0.f, 30.f};
@ -364,7 +365,7 @@ void CPlayerGun::PreRender(CStateManager& mgr, const CFrustumPlanes& frustum,
}
if (x833_28_phazonBeamActive) {
gpRender->AllocatePhazonSuitMaskTexture();
IWeaponRenderer::SetRenderer(IWeaponRenderer *renderer)->AllocatePhazonSuitMaskTexture();
}
}

View File

@ -0,0 +1,585 @@
#include "Weapons/CProjectileWeapon.hpp"
#include "Kyoto/Graphics/CLight.hpp"
#include "Kyoto/Math/CVector3f.hpp"
#include "Weapons/IWeaponRenderer.hpp"
#include "rstl/optional_object.hpp"
#include <Kyoto/Alloc/CMemory.hpp>
#include <Kyoto/CRandom16.hpp>
#include <Kyoto/Graphics/CGraphics.hpp>
#include <Kyoto/Graphics/CModel.hpp>
#include <Kyoto/Graphics/CModelFlags.hpp>
#include <Kyoto/Math/CRelAngle.hpp>
#include <Kyoto/Math/CTransform4f.hpp>
#include <Kyoto/Math/CloseEnough.hpp>
#include <Kyoto/Particles/CElementGen.hpp>
#include <Kyoto/Particles/CParticleGlobals.hpp>
#include <Kyoto/Particles/CParticleSwoosh.hpp>
#include <Kyoto/TToken.hpp>
#include <MetaRender/CCubeRenderer.hpp>
#include <Weapons/CCollisionResponseData.hpp>
uint CProjectileWeapon::skGlobalSeed = 99;
float CProjectileWeapon::GetTickPeriod() { return 1 / 60.f; }
CProjectileWeapon::CProjectileWeapon(const TToken< CWeaponDescription >& description,
const CVector3f& worldOffset, const CTransform4f& localToWorld,
const CVector3f& scale, int flags)
: x4_weaponDesc(description)
, x10_random(skGlobalSeed)
, x14_localToWorldXf(localToWorld)
, 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 __(x10_random);
x124_31_VMD2 = x4_weaponDesc->x10_VMD2;
x124_25_APSO = x4_weaponDesc->x28_APSO;
uint unk = xe4_flags & 1;
if (x4_weaponDesc->x34_APSM) {
xfc_APSMGen = rs_new CElementGen(*x4_weaponDesc->x34_APSM, CElementGen::kMOT_Normal,
unk ? CElementGen::kOSF_Two : CElementGen::kOSF_One);
xfc_APSMGen->SetGlobalScale(scale);
}
if (x4_weaponDesc->x44_APS2) {
x100_APS2Gen = rs_new CElementGen(*x4_weaponDesc->x44_APS2, CElementGen::kMOT_Normal,
unk ? CElementGen::kOSF_Two : CElementGen::kOSF_One);
x100_APS2Gen->SetGlobalScale(scale);
}
if (x4_weaponDesc->x54_ASW1) {
x118_swoosh1 = rs_new CParticleSwoosh(*x4_weaponDesc->x54_ASW1, 0);
x118_swoosh1->SetGlobalScale(scale);
}
if (x4_weaponDesc->x64_ASW2) {
x11c_swoosh2 = rs_new CParticleSwoosh(*x4_weaponDesc->x64_ASW2, 0);
x11c_swoosh2->SetGlobalScale(scale);
}
if (x4_weaponDesc->x74_ASW3) {
x120_swoosh3 = rs_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 orient(CTransform4f::Identity());
CVector3f angle(0.f, 0.f, 0.f);
x4_weaponDesc->x0_IORN->GetValue(0, angle);
CRelAngle relAngleX = CRelAngle::FromDegrees(angle.GetX());
orient.RotateLocalX(relAngleX);
CRelAngle relAngleY = CRelAngle::FromDegrees(angle.GetY());
orient.RotateLocalY(relAngleY);
CRelAngle relAngleZ = CRelAngle::FromDegrees(angle.GetZ());
orient.RotateLocalZ(relAngleZ);
SetRelativeOrientation(orient);
} else {
SetRelativeOrientation(CTransform4f::Identity());
}
if (x4_weaponDesc->GetOHEF()) {
x108_model = *x4_weaponDesc->GetOHEF();
}
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(1.f / 60.f);
}
CProjectileWeapon::~CProjectileWeapon() {
delete xfc_APSMGen;
delete x100_APS2Gen;
delete x104_;
delete x118_swoosh1;
delete x11c_swoosh2;
delete x120_swoosh3;
}
inline f32 val() { return 1.0f; }
bool CProjectileWeapon::Update(float dt) {
CGlobalRandom __(x10_random);
double actualTime = xf4_curFrame * (1.0 / 60.0);
xec_childSystemUpdateRate = 0;
double useDt = close_enough(dt, 1.f / 60.f) ? 1.0 / 60.0 : dt;
useDt *= val();
if (useDt < 0.f) {
useDt = 0.f;
}
xd0_curTime += useDt;
while (actualTime < xd0_curTime && !close_enough(actualTime, xd0_curTime)) {
if (xf4_curFrame < xe8_lifetime) {
CParticleGlobals::SetEmitterTime(xf4_curFrame);
CParticleGlobals::SetParticleLifetime(xe8_lifetime);
CParticleGlobals::UpdateParticleLifetimeTweenValues(xf4_curFrame);
UpdatePSTranslationAndOrientation();
}
actualTime += 1.f / 60.f;
++xf4_curFrame;
++xec_childSystemUpdateRate;
}
if (close_enough(actualTime, xd0_curTime)) {
xd0_curTime = actualTime;
}
xd8_remainderTime = (float)((actualTime - xd0_curTime) / 60.0);
if (xf4_curFrame < xe8_lifetime) {
xe0_maxTurnRate = 0.f;
if (CRealElement* trat = x4_weaponDesc->x30_TRAT) {
trat->GetValue(0, xe0_maxTurnRate);
}
}
return false;
}
void CProjectileWeapon::UpdateParticleFX() {
for (int i = 0; i < xec_childSystemUpdateRate; ++i) {
UpdateChildParticleSystems(1.f / 60.f);
}
}
const CTransform4f CProjectileWeapon::GetTransform() const {
return x14_localToWorldXf * x44_localXf;
}
CTransform4f CProjectileWeapon::GetTransform() { return x14_localToWorldXf * x44_localXf; }
const CVector3f CProjectileWeapon::GetTranslation() const {
return x14_localToWorldXf * (x80_localOffset + x44_localXf * x8c_projOffset) + x74_worldOffset;
}
void CProjectileWeapon::SetRelativeOrientation(const CTransform4f& orient) { x44_localXf = orient; }
void CProjectileWeapon::SetWorldSpaceOrientation(const CTransform4f& orient) {
x44_localXf = x14_localToWorldXf.GetInverse() * orient;
}
void CProjectileWeapon::UpdatePSTranslationAndOrientation() {
if (xe8_lifetime >= xf4_curFrame && x124_24_active) {
if (CModVectorElement* psvm = x4_weaponDesc->xc_PSVM) {
psvm->GetValue(xf4_curFrame, xb0_velocity, x80_localOffset);
}
if (x124_31_VMD2) {
x80_localOffset += x44_localXf * xb0_velocity;
} else {
x80_localOffset += xb0_velocity;
}
xb0_velocity += xbc_gravity / 60.f;
if (CVectorElement* psov = x4_weaponDesc->x8_PSOV) {
CVector3f orient(0.f, 0.f, 0.f);
psov->GetValue(xf4_curFrame, orient);
CTransform4f xf = x44_localXf;
xf.RotateLocalX(CRelAngle::FromDegrees(orient.GetX()));
xf.RotateLocalY(CRelAngle::FromDegrees(orient.GetY()));
xf.RotateLocalZ(CRelAngle::FromDegrees(orient.GetZ()));
SetRelativeOrientation(xf);
}
if (CVectorElement* pscl = x4_weaponDesc->x18_PSCL) {
pscl->GetValue(xf4_curFrame, x98_scale);
}
if (CColorElement* pcol = x4_weaponDesc->x1c_PCOL) {
pcol->GetValue(xf4_curFrame, xc8_ambientLightColor);
}
if (CVectorElement* pofs = x4_weaponDesc->x20_POFS) {
pofs->GetValue(xf4_curFrame, xa4_localOffset2);
}
if (CVectorElement* ofst = x4_weaponDesc->x24_OFST) {
ofst->GetValue(xf4_curFrame, x8c_projOffset);
}
}
}
void CProjectileWeapon::UpdateChildParticleSystems(float dt) {
double useDt = (close_enough(dt, 1.f / 60.f)) ? 1.0 / 60.0 : dt;
if (xfc_APSMGen) {
if (xf8_lastParticleFrame != xf4_curFrame) {
if (xf4_curFrame > xe8_lifetime) {
xfc_APSMGen->SetParticleEmission(false);
xfc_APSMGen->EndLifetime();
} else {
if (x124_26_AP11) {
xfc_APSMGen->SetGlobalTranslation(GetTranslation());
} else {
xfc_APSMGen->SetTranslation(GetTranslation());
}
if (x124_25_APSO) {
xfc_APSMGen->SetOrientation(GetTransform());
}
}
}
xfc_APSMGen->Update(useDt);
if (xfc_APSMGen->IsSystemDeletable() == TRUE) {
delete xfc_APSMGen;
xfc_APSMGen = nullptr;
}
}
if (x100_APS2Gen) {
if (xf8_lastParticleFrame != xf4_curFrame) {
if (xf4_curFrame > xe8_lifetime) {
x100_APS2Gen->SetParticleEmission(false);
x100_APS2Gen->EndLifetime();
} else {
if (x124_27_AP21) {
x100_APS2Gen->SetGlobalTranslation(GetTranslation());
} else {
x100_APS2Gen->SetTranslation(GetTranslation());
}
if (x124_25_APSO) {
x100_APS2Gen->SetOrientation(GetTransform());
}
}
}
x100_APS2Gen->Update(useDt);
if (x100_APS2Gen->IsSystemDeletable() == TRUE) {
delete x100_APS2Gen;
x100_APS2Gen = nullptr;
}
}
if (x118_swoosh1) {
if (xf8_lastParticleFrame != xf4_curFrame) {
if (xf4_curFrame > xe8_lifetime) {
x118_swoosh1->SetParticleEmission(false);
} else {
if (x124_28_AS11) {
x118_swoosh1->SetGlobalTranslation(GetTranslation());
} else {
x118_swoosh1->SetTranslation(GetTranslation());
}
x118_swoosh1->SetOrientation(GetTransform());
}
}
x118_swoosh1->SetWarmUp();
x118_swoosh1->Update(0.0);
if (x118_swoosh1->IsSystemDeletable() == TRUE) {
delete x118_swoosh1;
x118_swoosh1 = nullptr;
}
}
if (x11c_swoosh2) {
if (xf8_lastParticleFrame != xf4_curFrame) {
if (xf4_curFrame > xe8_lifetime) {
x11c_swoosh2->SetParticleEmission(false);
} else {
if (x124_29_AS12) {
x11c_swoosh2->SetGlobalTranslation(GetTranslation());
} else {
x11c_swoosh2->SetTranslation(GetTranslation());
}
x11c_swoosh2->SetOrientation(GetTransform());
}
}
x11c_swoosh2->SetWarmUp();
x11c_swoosh2->Update(0.0);
if (x11c_swoosh2->IsSystemDeletable() == TRUE) {
delete x11c_swoosh2;
x11c_swoosh2 = nullptr;
}
}
if (x120_swoosh3) {
if (xf8_lastParticleFrame != xf4_curFrame) {
if (xf4_curFrame > xe8_lifetime) {
x120_swoosh3->SetParticleEmission(false);
} else {
if (x124_30_AS13) {
x120_swoosh3->SetGlobalTranslation(GetTranslation());
} else {
x120_swoosh3->SetTranslation(GetTranslation());
}
x120_swoosh3->SetOrientation(GetTransform());
}
}
x120_swoosh3->SetWarmUp();
x120_swoosh3->Update(0.0);
if (x120_swoosh3->IsSystemDeletable() == TRUE) {
delete x120_swoosh3;
x120_swoosh3 = nullptr;
}
}
if (x104_) {
x104_->Update(useDt);
if (x104_->IsSystemDeletable() == TRUE) {
delete x104_;
x104_ = nullptr;
}
}
xf8_lastParticleFrame = xf4_curFrame;
}
const bool CProjectileWeapon::IsSystemDeletable() const {
bool ret = true;
if (xfc_APSMGen && !xfc_APSMGen->IsSystemDeletable()) {
ret = false;
} else if (x100_APS2Gen && !x100_APS2Gen->IsSystemDeletable()) {
ret = false;
} else if (x118_swoosh1 && !x118_swoosh1->IsSystemDeletable()) {
ret = false;
} else if (x11c_swoosh2 && !x11c_swoosh2->IsSystemDeletable()) {
ret = false;
} else if (x120_swoosh3 && !x120_swoosh3->IsSystemDeletable()) {
ret = false;
} else if (x104_ && !x104_->IsSystemDeletable()) {
ret = false;
} else if (x124_24_active) {
ret = xf4_curFrame >= xe8_lifetime;
}
return ret;
}
void CProjectileWeapon::Render() const {
if (xf4_curFrame <= xe8_lifetime && x124_24_active && x108_model) {
CTransform4f localXf = CTransform4f::Translate(
x80_localOffset + (x44_localXf * x8c_projOffset) + xa4_localOffset2);
CTransform4f worldXf = CTransform4f::Translate(x74_worldOffset);
CTransform4f scaleXf =
CTransform4f::Scale(x98_scale.GetX(), x98_scale.GetY(), x98_scale.GetZ());
CGraphics::SetModelMatrix(worldXf * x14_localToWorldXf * localXf * scaleXf * x44_localXf);
CLight light = CLight::BuildLocalAmbient(CVector3f::Zero(), xc8_ambientLightColor);
(*x108_model)->Draw(CModelFlags(CModelFlags::kT_Opaque, 1.f));
}
}
void CProjectileWeapon::AddToRenderer() const {
if (xfc_APSMGen)
IWeaponRenderer::GetRenderer()->AddParticleGen(*xfc_APSMGen);
if (x100_APS2Gen)
IWeaponRenderer::GetRenderer()->AddParticleGen(*x100_APS2Gen);
if (x118_swoosh1)
IWeaponRenderer::GetRenderer()->AddParticleGen(*x118_swoosh1);
if (x11c_swoosh2)
IWeaponRenderer::GetRenderer()->AddParticleGen(*x11c_swoosh2);
if (x120_swoosh3)
IWeaponRenderer::GetRenderer()->AddParticleGen(*x120_swoosh3);
if (x104_)
IWeaponRenderer::GetRenderer()->AddParticleGen(*x104_);
}
void CProjectileWeapon::RenderParticles() const {
if (xfc_APSMGen) {
xfc_APSMGen->Render();
}
if (x100_APS2Gen) {
x100_APS2Gen->Render();
}
if (x118_swoosh1) {
x118_swoosh1->Render();
}
if (x11c_swoosh2) {
x11c_swoosh2->Render();
}
if (x120_swoosh3) {
x120_swoosh3->Render();
}
if (x104_) {
x104_->Render();
}
}
rstl::optional_object< TLockedToken< CGenDescription > > CProjectileWeapon::CollisionOccured(
const EWeaponCollisionResponseTypes colType, const bool deflected, const bool useTarget,
const CVector3f& pos, const CVector3f& normal, const CVector3f& target) {
x80_localOffset = x14_localToWorldXf.TransposeRotate(pos - x74_worldOffset) - x8c_projOffset;
if (deflected) {
CVector3f posToTarget = target - GetTranslation();
if (useTarget && posToTarget.CanBeNormalized()) {
SetWorldSpaceOrientation(CTransform4f::LookAt(CVector3f::Zero(), posToTarget.AsNormalized()));
} else {
CVector3f col = GetTransform().GetColumn(kDY);
CVector3f lookPos = (CVector3f::Dot(normal, col) * 2.f) * normal;
CVector3f lookPos2 = col - lookPos;
CTransform4f lookXf = CTransform4f::LookAt(CVector3f::Zero(), lookPos2, normal);
SetWorldSpaceOrientation(lookXf);
}
return rstl::optional_object_null();
}
x124_24_active = false;
if (xfc_APSMGen) {
xfc_APSMGen->SetParticleEmission(false);
}
if (x100_APS2Gen) {
x100_APS2Gen->SetParticleEmission(false);
}
if (x118_swoosh1) {
x118_swoosh1->SetParticleEmission(false);
}
if (x11c_swoosh2) {
x11c_swoosh2->SetParticleEmission(false);
}
if (x120_swoosh3) {
x120_swoosh3->SetParticleEmission(false);
}
if (!x4_weaponDesc->x94_COLR) {
return rstl::optional_object_null();
}
TToken< CCollisionResponseData > tok = (*x4_weaponDesc->GetCollisionResponse());
return tok->GetParticleDescription(colType);
}
uint CProjectileWeapon::GetSoundIdForCollision(EWeaponCollisionResponseTypes type) const {
if (!x4_weaponDesc->GetCollisionResponse()) {
return -1;
}
TToken< CCollisionResponseData > tok = (*x4_weaponDesc->GetCollisionResponse());
return tok->GetSoundEffectId(type);
}
rstl::optional_object< TLockedToken< CDecalDescription > >
CProjectileWeapon::GetDecalForCollision(EWeaponCollisionResponseTypes type) const {
if (!x4_weaponDesc->GetCollisionResponse()) {
return rstl::optional_object_null();
}
TToken< CCollisionResponseData > tok = (*x4_weaponDesc->GetCollisionResponse());
return tok->GetDecalDescription(type);
}
float CProjectileWeapon::GetAudibleRange() const {
if (!x4_weaponDesc->GetCollisionResponse()) {
return 0.f;
}
TToken< CCollisionResponseData > tok = (*x4_weaponDesc->GetCollisionResponse());
return tok->GetAudibleRange();
}
float CProjectileWeapon::GetAudibleFallOff() const {
if (!x4_weaponDesc->GetCollisionResponse()) {
return 0.f;
}
TToken< CCollisionResponseData > tok = (*x4_weaponDesc->GetCollisionResponse());
return tok->GetAudibleFallOff();
}
float CProjectileWeapon::GetMaxTurnRate() const { return xe0_maxTurnRate; }
void CProjectileWeapon::SetVelocity(const CVector3f& velocity) { xb0_velocity = velocity; }
const CVector3f& CProjectileWeapon::GetVelocity() const { return xb0_velocity; }
void CProjectileWeapon::SetGravity(const CVector3f& gravity) { xbc_gravity = gravity; }
const CVector3f& CProjectileWeapon::GetGravity() const { return xbc_gravity; }
void CProjectileWeapon::SetGlobalSeed(uint seed) { skGlobalSeed = seed; }
rstl::optional_object< CAABox > CProjectileWeapon::GetBounds() const {
CAABox ret = CAABox::MakeMaxInvertedBox();
bool hasBox = false;
if (xfc_APSMGen) {
rstl::optional_object< CAABox > bounds = xfc_APSMGen->GetBounds();
if (bounds) {
CAABox& b = *bounds;
ret.AccumulateBounds(b.GetMinPoint());
ret.AccumulateBounds(b.GetMaxPoint());
hasBox = true;
}
}
if (x100_APS2Gen) {
rstl::optional_object< CAABox > bounds = x100_APS2Gen->GetBounds();
if (bounds) {
CAABox& b = *bounds;
ret.AccumulateBounds(b.GetMinPoint());
ret.AccumulateBounds(b.GetMaxPoint());
hasBox = true;
}
}
if (x118_swoosh1) {
rstl::optional_object< CAABox > bounds = x118_swoosh1->GetBounds();
if (bounds) {
CAABox& b = *bounds;
ret.AccumulateBounds(b.GetMinPoint());
ret.AccumulateBounds(b.GetMaxPoint());
hasBox = true;
}
}
if (x11c_swoosh2) {
rstl::optional_object< CAABox > bounds = x11c_swoosh2->GetBounds();
if (bounds) {
CAABox& b = *bounds;
ret.AccumulateBounds(b.GetMinPoint());
ret.AccumulateBounds(b.GetMaxPoint());
hasBox = true;
}
}
if (x120_swoosh3) {
rstl::optional_object< CAABox > bounds = x120_swoosh3->GetBounds();
if (bounds) {
CAABox& b = *bounds;
ret.AccumulateBounds(b.GetMinPoint());
ret.AccumulateBounds(b.GetMaxPoint());
hasBox = true;
}
}
if (hasBox) {
return ret;
}
return rstl::optional_object_null();
}