CWaveBuster: Near complete implementation

This commit is contained in:
Phillip Stephens 2020-04-12 02:40:51 -07:00 committed by Luke Street
parent 7d7a8673b7
commit 2cf0bd6784
4 changed files with 281 additions and 34 deletions

View File

@ -23,7 +23,7 @@ class CSwooshDescription;
class CParticleSwoosh : public CParticleGen {
friend class CParticleSwooshShaders;
public:
struct SSwooshData {
bool x0_active;
float x4_leftRad;
@ -56,6 +56,7 @@ class CParticleSwoosh : public CParticleGen {
, x74_velocity(vel) {}
};
private:
TLockedToken<CSwooshDescription> x1c_desc;
u32 x28_curFrame = 0;
int x2c_PSLT = 0;
@ -162,6 +163,11 @@ public:
void Reset() override {}
FourCC Get4CharId() const override { return FOURCC('SWHC'); }
void SetRenderGaps(bool r) { x1d0_27_renderGaps = r; }
size_t GetSwooshDataCount() const { return x15c_swooshes.size(); }
SSwooshData& GetSwooshData(size_t idx) { return x15c_swooshes[idx]; }
const SSwooshData& GetSwooshData(size_t idx) const { return x15c_swooshes[idx]; }
std::vector<SSwooshData>& GetSwooshVector() { return x15c_swooshes; }
const std::vector<SSwooshData>& GetSwooshVector() const { return x15c_swooshes; }
void DoWarmupUpdate() {
x1d0_26_forceOneUpdate = true;

View File

@ -335,11 +335,9 @@ TUniqueId CAuxWeapon::HasTarget(const CStateManager& mgr) const {
}
void CAuxWeapon::SetNewTarget(TUniqueId targetId, CStateManager& mgr) {
if (x74_firingBeamId == CPlayerState::EBeamId::Wave) {
if (auto* wb = static_cast<CWaveBuster*>(mgr.ObjectById(x70_waveBusterId))) {
wb->SetNewTarget(targetId);
}
}
if (x74_firingBeamId == CPlayerState::EBeamId::Wave)
if (auto* wb = static_cast<CWaveBuster*>(mgr.ObjectById(x70_waveBusterId)))
wb->SetNewTarget(targetId, mgr);
}
} // namespace metaforce

View File

@ -2,22 +2,27 @@
#include "Runtime/CSimplePool.hpp"
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/CStateManager.hpp"
#include "Runtime/Input/CRumbleManager.hpp"
#include "Runtime/World/CGameLight.hpp"
#include "Runtime/World/CWorld.hpp"
#include "DataSpec/DNAMP1/SFX/Weapons.h"
#include "TCastTo.hpp" // Generated file, do not modify include path
namespace metaforce {
CWaveBuster::CWaveBuster(const TToken<CWeaponDescription>& desc, EWeaponType type, const zeus::CTransform& xf,
EMaterialTypes matType, const CDamageInfo& dInfo, TUniqueId uid, TAreaId aid, TUniqueId owner,
TUniqueId homingTarget, EProjectileAttrib attrib)
: CGameProjectile(true, desc, "WaveBuster", type, xf, matType, dInfo, uid, aid, owner, homingTarget, attrib, false,
zeus::skOne3f, {}, -1, false)
, x2e8_originalXf(xf)
, x348_targetPoint(x2e8_originalXf.basis[1].normalized() * 25.f + x2e8_originalXf.origin)
, x354_busterSwoosh1(g_SimplePool->GetObj("BusterSwoosh1"))
, x360_busterSwoosh2(g_SimplePool->GetObj("BusterSwoosh2"))
, x36c_busterSparks(g_SimplePool->GetObj("BusterSparks"))
, x378_busterLight(g_SimplePool->GetObj("BusterLight")) {
EMaterialTypes matType, const CDamageInfo& dInfo, TUniqueId uid, TAreaId aid, TUniqueId owner,
TUniqueId homingTarget, EProjectileAttrib attrib)
: CGameProjectile(true, desc, "WaveBuster", type, xf, matType, dInfo, uid, aid, owner, homingTarget, attrib, false,
zeus::skOne3f, {}, -1, false)
, x2e8_originalXf(xf)
, x348_targetPoint(x2e8_originalXf.basis[1].normalized() * 25.f + x2e8_originalXf.origin)
, x354_busterSwoosh1(g_SimplePool->GetObj("BusterSwoosh1"))
, x360_busterSwoosh2(g_SimplePool->GetObj("BusterSwoosh2"))
, x36c_busterSparks(g_SimplePool->GetObj("BusterSparks"))
, x378_busterLight(g_SimplePool->GetObj("BusterLight")) {
x354_busterSwoosh1.GetObj();
x360_busterSwoosh2.GetObj();
x36c_busterSparks.GetObj();
@ -28,14 +33,98 @@ CWaveBuster::CWaveBuster(const TToken<CWeaponDescription>& desc, EWeaponType typ
x390_busterLightGen = std::make_unique<CElementGen>(x378_busterLight);
}
void CWaveBuster::UpdateFx(const zeus::CTransform& xf, float dt, CStateManager& mgr) {}
void CWaveBuster::ResetBeam(bool deactivate) {}
void CWaveBuster::SetNewTarget(TUniqueId id) {}
void CWaveBuster::Accept(IVisitor& visitor) { visitor.Visit(this); }
void CWaveBuster::Think(float dt, CStateManager& mgr) {
CWeapon::Think(dt, mgr);
if (!GetActive())
return;
if (GetAreaIdAlways() != mgr.GetWorld()->GetCurrentAreaId()) {
mgr.SetActorAreaId(*this, mgr.GetWorld()->GetCurrentAreaId());
}
x3d0_27_ = false;
x3d0_28_ = false;
zeus::CVector3f local_160 = x2e8_originalXf.origin;
zeus::CVector3f local_184 = x2e8_originalXf.basis[1];
zeus::CVector3f local_16c = local_184.normalized();
float dVar17 = 0.f;
if (!x3d0_25_ && !x3d0_26_) {
TUniqueId uid = kInvalidUniqueId;
CRayCastResult res = sub_801be010(uid, local_160, local_16c, mgr);
if (res.IsValid() && res.GetT() < 25.f) {
if (TCastToPtr<CActor> act = mgr.ObjectById(uid)) {
act->Touch(*this, mgr);
mgr.ApplyDamage(GetUniqueId(), act->GetUniqueId(), GetOwnerId(), CDamageInfo(x12c_curDamageInfo, dt),
xf8_filter, GetTransform().basis[1]);
} else {
x3d0_28_ = true;
}
x3d0_27_ = true;
dVar17 = res.GetT();
}
}
if (x2c0_homingTargetId == kInvalidUniqueId || !x3d0_26_) {
dVar17 = std::max(1.f, dVar17);
x348_targetPoint = local_160 + (dVar17 * local_16c);
if (!x3d0_25_) {
const float x = mgr.GetActiveRandom()->Range(-1.f, 1.f);
const float z = mgr.GetActiveRandom()->Range(-1.f, 1.f);
x348_targetPoint += zeus::CVector3f{x, 0.f, z};
SetTranslation(x348_targetPoint);
} else {
sub_801bf598(dt, mgr);
}
} else {
UpdateTargetDamage(dt, mgr);
}
if (UpdateTargetSeek(dt, mgr)) {
ResetBeam(true);
}
zeus::CVector3f vec = x2c0_homingTargetId != kInvalidUniqueId && x3d0_26_
? GetTransform() * zeus::CTransform::RotateY(x3c4_) * zeus::CVector3f{0.f, -3.f, -1.5f}
: (GetTranslation() + -1.5f) * GetTransform().basis[1].normalized();
if (x3a0_ >= 0.5f || x2c0_homingTargetId == kInvalidUniqueId) {
x330_ = x324_;
x324_ = vec;
} else {
x324_ = x330_ * (1.f - x330_) + vec * (x3a0_ / 0.5f);
x3a0_ += 0.125f * dt;
}
if (x2c8_projectileLight != kInvalidUniqueId) {
x390_busterLightGen->Update(dt);
if (TCastToPtr<CGameLight> light = mgr.ObjectById(x2c8_projectileLight)) {
light->SetTransform(GetTransform());
if (x390_busterLightGen && x390_busterLightGen->SystemHasLight()) {
light->SetLight(x390_busterLightGen->GetLight());
}
}
}
x3c8_ += 20.f * dt;
if (x3c8_ > 1.f) {
++x3cc_;
if (x3cc_ > 2)
x3cc_ = 0;
x3c8_ = 0.f;
}
x38c_busterSparksGen->Update(dt);
}
void CWaveBuster::AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) {
EnsureRendered(mgr, x2e8_originalXf.origin, GetSortingBounds(mgr));
}
void CWaveBuster::Render(CStateManager& mgr) {
sub_801be350();
sub_801be5c0();
CWeapon::Render(mgr);
}
void CWaveBuster::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId senderId, CStateManager& mgr) {
if (msg == EScriptObjectMessage::Deleted) {
DeleteProjectileLight(mgr);
@ -56,11 +145,6 @@ void CWaveBuster::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId senderId,
CGameProjectile::AcceptScriptMsg(msg, senderId, mgr);
}
void CWaveBuster::AddToRenderer([[maybe_unused]] const zeus::CFrustum& frustum, CStateManager& mgr) {
const auto bounds = GetSortingBounds(mgr);
EnsureRendered(mgr, x2e8_originalXf.origin, bounds);
}
std::optional<zeus::CAABox> CWaveBuster::GetTouchBounds() const {
if (x3d0_28_) {
return std::nullopt;
@ -69,4 +153,154 @@ std::optional<zeus::CAABox> CWaveBuster::GetTouchBounds() const {
return GetProjectileBounds();
}
} // namespace metaforce
void CWaveBuster::UpdateFx(const zeus::CTransform& xf, float dt, CStateManager& mgr) {
if (!GetActive())
return;
x398_ -= std::max(0.f, x398_ - (60.f * dt));
x170_projectile.SetVelocity(zeus::CVector3f{0.f, x3d0_25_ ? 1.6f : 0.f, 0.f});
}
void CWaveBuster::ResetBeam(bool deactivate) {
if (!deactivate) {
x38c_busterSparksGen->SetParticleEmission(false);
x3d0_24_firing = false;
} else {
SetActive(false);
x3d0_24_firing = false;
x38c_busterSparksGen->SetParticleEmission(false);
x398_ = 2.f * M_PIF;
}
}
void CWaveBuster::SetNewTarget(TUniqueId id, CStateManager& mgr) {
x2c0_homingTargetId = id;
if (id == kInvalidUniqueId) {
x3d0_26_ = false;
} else {
x3d0_26_ = true;
CSfxManager::AddEmitter(SFXsfx06FF, GetTranslation(), zeus::skZero3f, true, false, 255, kInvalidAreaId);
mgr.GetRumbleManager().Rumble(mgr, ERumbleFxId::PlayerBump, 0.5f, ERumblePriority::Three);
}
}
void CWaveBuster::sub_801be350() {
static constexpr std::array<zeus::CColor, 4> skCols = {{
zeus::skWhite,
{1.f, 0.f, 1.f, 1.f},
{1.f, 0.f, 0.f, 1.f},
{0.f, 0.f, 1.f, 1.f},
}};
zeus::CTransform CStack152 = x2e8_originalXf.getRotation();
zeus::CVector3f local_d4 = x2e8_originalXf.origin;
x38c_busterSparksGen->SetParticleEmission(true);
zeus::CColor col = zeus::CColor::lerp(skCols[x3cc_], skCols[x3cc_ + 1], x3c8_);
float dVar8 = x388_busterSwoosh2Gen->GetSwooshData(x388_busterSwoosh2Gen->GetSwooshDataCount()).x30_irot;
float dVar9 = x384_busterSwoosh1Gen->GetSwooshData(x384_busterSwoosh1Gen->GetSwooshDataCount()).x30_irot;
float fVar1 = 0.f;
int iVar3 = 0;
while (iVar3 < x384_busterSwoosh1Gen->GetSwooshDataCount()) {
float dVar10 = fVar1;
auto& swoosh1 = x384_busterSwoosh1Gen->GetSwooshData(iVar3);
auto& swoosh2 = x388_busterSwoosh2Gen->GetSwooshData(iVar3);
zeus::CVector3f point = zeus::getBezierPoint(GetTranslation(), x324_, x318_, local_d4, fVar1);
swoosh1.xc_translation = point;
swoosh2.xc_translation = point;
swoosh1.x38_orientation = CStack152;
swoosh2.x38_orientation = CStack152;
swoosh2.x6c_color = col;
float dVar6 = swoosh1.x30_irot;
float dVar7 = swoosh2.x30_irot;
swoosh1.x30_irot = dVar9;
swoosh2.x30_irot = dVar8;
x38c_busterSparksGen->SetTranslation(point);
fVar1 = dVar10 + 0.4f;
++iVar3;
dVar8 = dVar7;
dVar9 = dVar6;
}
x38c_busterSparksGen->SetParticleEmission(false);
x384_busterSwoosh1Gen->Render(GetActorLights());
x388_busterSwoosh2Gen->Render(GetActorLights());
x38c_busterSparksGen->Render(GetActorLights());
}
void CWaveBuster::sub_801be5c0() {}
CRayCastResult CWaveBuster::sub_801be010(TUniqueId uid, const zeus::CVector3f& p1, const zeus::CVector3f& p2,
CStateManager& mgr) {
return CRayCastResult();
}
void CWaveBuster::sub_801bf598(float dt, CStateManager& mgr) {}
void CWaveBuster::UpdateTargetDamage(float dt, CStateManager& mgr) {
if (const TCastToConstPtr<CActor> act = mgr.GetObjectById(x2c0_homingTargetId)) {
const CHealthInfo* hInfo = act->GetHealthInfo(mgr);
if (hInfo && hInfo->GetHP() > 0.f) {
x33c_ = act->GetAimPosition(mgr, 0.f);
SetTranslation(x33c_);
mgr.ApplyDamage(GetUniqueId(), x2c0_homingTargetId, GetOwnerId(), CDamageInfo(x12c_curDamageInfo, dt), xf8_filter,
zeus::skZero3f);
return;
}
}
SetTransform(zeus::lookAt(GetTranslation(), x348_targetPoint + (0.001f * x2e8_originalXf.basis[1].normalized())));
x2c0_homingTargetId = kInvalidUniqueId;
x39c_ = 0.f;
x3a0_ = 0.f;
}
bool CWaveBuster::UpdateTargetSeek(float dt, CStateManager& mgr) {
zeus::CVector3f local_ac = zeus::skForward;
float viewAngle = 0.f;
if (const TCastToConstPtr<CActor> act = mgr.GetObjectById(x2c0_homingTargetId)) {
const CHealthInfo* hInfo = act->GetHealthInfo(mgr);
if (hInfo && hInfo->GetHP() > 0.f) {
if ((act->GetTranslation() - x2e8_originalXf.origin).magnitude() > 10000.f)
return true;
}
viewAngle = GetViewAngleToTarget(local_ac, *act);
}
x3a8_ -= dt;
if (x3a8_ <= 0.f) {
const float dVar10 = mgr.GetActiveRandom()->Range(0.f, 2 * M_PIF);
const float dVar9 = mgr.GetActiveRandom()->Range(0.05f, 0.25f);
x3a4_ = (1.f / dVar9) * (dVar10 - x3ac_);
x3a8_ = dVar9;
}
x3b8_ -= dt;
if (x3b8_ <= 0.f) {
const float dVar10 = mgr.GetActiveRandom()->Range(0.f, 0.5f);
const float dVar9 = mgr.GetActiveRandom()->Range(0.1f, 0.5f);
x3b4_ = (1.f / dVar9) * (dVar10 - x3b0_);
x3b8_ = dVar9;
}
x3c0_ -= dt;
if (x3c0_ <= 0.f) {
const float dVar10 = mgr.GetActiveRandom()->Range(0.f, 2 * M_PIF);
const float dVar9 = mgr.GetActiveRandom()->Range(0.05f, 0.25f);
x3bc_ = (1.f / dVar9) * (dVar10 - x3ac_);
x3c0_ = dVar9;
}
x3ac_ += x3a4_ * dt;
x3b0_ += x3b4_ * dt;
x3c4_ += x3bc_ * dt;
x318_ = x2e8_originalXf * zeus::CTransform::RotateY(x3ac_) *
zeus::CVector3f(0.f, 2.f, 1.5f * ((x2c0_homingTargetId == kInvalidUniqueId ? 1.f : 1.25f) - x3b0_ * x3b0_));
return viewAngle > zeus::degToRad(90.f);
}
float CWaveBuster::GetViewAngleToTarget(zeus::CVector3f& p1, const CActor& act) {
p1 = act.GetTranslation() - x2e8_originalXf.origin;
if (!p1.canBeNormalized()) {
p1 = GetTransform().basis[1];
} else {
p1.normalize();
}
return zeus::CVector2f::getAngleDiff(x2e8_originalXf.basis[1].toVec2f(), p1.toVec2f());
}
} // namespace metaforce

View File

@ -27,6 +27,7 @@ class CWaveBuster : public CGameProjectile {
std::unique_ptr<CElementGen> x38c_busterSparksGen;
std::unique_ptr<CElementGen> x390_busterLightGen;
CRandom16 x394_rand{99};
float x398_ = 2.f*M_PIF;
float x39c_ = 0.5f;
float x3a0_ = 0.5f;
float x3a4_ = 0.f;
@ -46,20 +47,28 @@ class CWaveBuster : public CGameProjectile {
bool x3d0_27_ : 1 = false;
bool x3d0_28_ : 1 = true;
void sub_801be350();
void sub_801be5c0();
CRayCastResult sub_801be010(TUniqueId uid, const zeus::CVector3f& p1, const zeus::CVector3f& p2, CStateManager& mgr);
void sub_801bf598(float dt, CStateManager& mgr);
void UpdateTargetDamage(float dt, CStateManager& mgr);
bool UpdateTargetSeek(float dt, CStateManager& mgr);
float GetViewAngleToTarget(zeus::CVector3f& p1, const CActor& act);
public:
DEFINE_ENTITY
CWaveBuster(const TToken<CWeaponDescription>& desc, EWeaponType type, const zeus::CTransform& xf,
EMaterialTypes matType, const CDamageInfo& dInfo, TUniqueId uid, TAreaId aid, TUniqueId owner,
TUniqueId homingTarget, EProjectileAttrib attrib);
void Accept(IVisitor& visitor) override;
void Think(float dt, CStateManager& mgr) override;
void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) override;
void AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) override;
void Render(CStateManager& mgr) override;
std::optional<zeus::CAABox> GetTouchBounds() const override;
bool IsFiring() const { return x3d0_24_firing; }
void UpdateFx(const zeus::CTransform& xf, float dt, CStateManager& mgr);
void ResetBeam(bool deactivate);
void SetNewTarget(TUniqueId id);
void Accept(IVisitor& visitor) override;
void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId senderId, CStateManager& mgr) override;
void AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) override;
std::optional<zeus::CAABox> GetTouchBounds() const override;
void SetNewTarget(TUniqueId id, CStateManager& mgr);
};
} // namespace metaforce