diff --git a/Runtime/Weapon/CWaveBuster.cpp b/Runtime/Weapon/CWaveBuster.cpp index 492f5a97c..89df3012b 100644 --- a/Runtime/Weapon/CWaveBuster.cpp +++ b/Runtime/Weapon/CWaveBuster.cpp @@ -25,8 +25,8 @@ CWaveBuster::CWaveBuster(const TToken& desc, EWeaponType typ , x360_busterSwoosh2(g_SimplePool->GetObj("BusterSwoosh2")) , x36c_busterSparks(g_SimplePool->GetObj("BusterSparks")) , x378_busterLight(g_SimplePool->GetObj("BusterLight")) -, m_lineRenderer1(CLineRenderer::EPrimitiveMode::LineStrip, 36, nullptr, true) -, m_lineRenderer2(CLineRenderer::EPrimitiveMode::LineStrip, 36, nullptr, true) { +, m_lineRenderer1(CLineRenderer::EPrimitiveMode::LineStrip, 36 * 6, nullptr, true) +, m_lineRenderer2(CLineRenderer::EPrimitiveMode::LineStrip, 36 * 6, nullptr, true) { x354_busterSwoosh1.GetObj(); x360_busterSwoosh2.GetObj(); x36c_busterSparks.GetObj(); @@ -35,6 +35,11 @@ CWaveBuster::CWaveBuster(const TToken& desc, EWeaponType typ x388_busterSwoosh2Gen = std::make_unique(x360_busterSwoosh2, 0); x38c_busterSparksGen = std::make_unique(x36c_busterSparks); x390_busterLightGen = std::make_unique(x378_busterLight); + + for (size_t i = 0; i < x384_busterSwoosh1Gen->GetSwooshDataCount() - 1; i++) { + x384_busterSwoosh1Gen->ForceOneUpdate(0.f); + x388_busterSwoosh2Gen->ForceOneUpdate(0.f); + } } void CWaveBuster::Accept(IVisitor& visitor) { visitor.Visit(this); } @@ -50,14 +55,12 @@ void CWaveBuster::Think(float dt, CStateManager& mgr) { } x3d0_27_ = false; x3d0_28_ = false; - zeus::CVector3f local_160 = x2e8_originalXf.origin; - zeus::CVector3f local_184 = x2e8_originalXf.frontVector(); - zeus::CVector3f local_16c = local_184.normalized(); + const zeus::CVector3f beamForward = x2e8_originalXf.frontVector().normalized(); - float dVar17 = 0.f; - if (!x3d0_25_ && !x3d0_26_) { + float beamDistance = 25.f; + if (!x3d0_25_ && !x3d0_26_trackingTarget) { TUniqueId uid = kInvalidUniqueId; - CRayCastResult res = SeekDamageTarget(uid, local_160, local_16c, mgr, dt); + CRayCastResult res = SeekDamageTarget(uid, x2e8_originalXf.origin, beamForward, mgr, dt); if (res.IsValid() && res.GetT() < 25.f) { if (TCastToPtr act = mgr.ObjectById(uid)) { act->Touch(*this, mgr); @@ -67,13 +70,13 @@ void CWaveBuster::Think(float dt, CStateManager& mgr) { x3d0_28_ = true; } x3d0_27_ = true; - dVar17 = res.GetT(); + beamDistance = res.GetT(); } } - if (x2c0_homingTargetId == kInvalidUniqueId || !x3d0_26_) { - dVar17 = std::max(1.f, dVar17); - x348_targetPoint = local_160 + (dVar17 * local_16c); + if (x2c0_homingTargetId == kInvalidUniqueId || !x3d0_26_trackingTarget) { + beamDistance = std::max(1.f, beamDistance); + x348_targetPoint = x2e8_originalXf.origin + (beamDistance * beamForward); if (!x3d0_25_) { const float x = mgr.GetActiveRandom()->Range(-1.f, 1.f); const float z = mgr.GetActiveRandom()->Range(-1.f, 1.f); @@ -90,14 +93,15 @@ void CWaveBuster::Think(float dt, CStateManager& mgr) { ResetBeam(true); } - zeus::CVector3f vec = x2c0_homingTargetId != kInvalidUniqueId && x3d0_26_ + zeus::CVector3f vec = x2c0_homingTargetId != kInvalidUniqueId && x3d0_26_trackingTarget ? GetTransform() * zeus::CTransform::RotateY(x3c4_) * zeus::CVector3f{0.f, -3.f, -1.5f} - : (GetTranslation() + -1.5f) * GetTransform().basis[1].normalized(); + : (GetTransform().frontVector() * -1.5f) + GetTransform().origin; if (x3a0_ >= 0.5f || x2c0_homingTargetId == kInvalidUniqueId) { - x330_ = x324_; - x324_ = vec; + x330_ = x324_bezierC; + x324_bezierC = vec; + x3a0_ = 0.5f; } else { - x324_ = x330_ * (1.f - x330_) + vec * (x3a0_ / 0.5f); + x324_bezierC = x330_ * (1.f - x330_) + vec * (x3a0_ / 0.5f); x3a0_ += 0.125f * dt; } @@ -111,12 +115,12 @@ void CWaveBuster::Think(float dt, CStateManager& mgr) { } } - x3c8_ += 20.f * dt; - if (x3c8_ > 1.f) { - ++x3cc_; - if (x3cc_ > 2) - x3cc_ = 0; - x3c8_ = 0.f; + x3c8_innerSwooshColorT += 20.f * dt; + if (x3c8_innerSwooshColorT > 1.f) { + ++x3cc_innerSwooshColorIdx; + if (x3cc_innerSwooshColorIdx > 2) + x3cc_innerSwooshColorIdx = 0; + x3c8_innerSwooshColorT = 0.f; } x38c_busterSparksGen->Update(dt); } @@ -143,8 +147,8 @@ void CWaveBuster::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId senderId, // Thermal hot xe6_27_thermalVisorFlags = 2; - x318_ = x2e8_originalXf.origin; - x324_ = x34_transform.origin; + x318_bezierB = x2e8_originalXf.origin; + x324_bezierC = x34_transform.origin; x330_ = x34_transform.origin; } @@ -165,7 +169,10 @@ void CWaveBuster::UpdateFx(const zeus::CTransform& xf, float dt, CStateManager& } x2e8_originalXf = xf; - x398_ -= std::max(0.f, x398_ - (60.f * dt)); + x398_spiralOffset -= 60.f * dt; + if (x398_spiralOffset < 0.f) { + x398_spiralOffset = 2.f * M_PIF; + } x170_projectile.SetVelocity(zeus::CVector3f{0.f, x3d0_25_ ? 1.6f : 0.f, 0.f}); } @@ -177,16 +184,16 @@ void CWaveBuster::ResetBeam(bool deactivate) { SetActive(false); x3d0_24_firing = false; x38c_busterSparksGen->SetParticleEmission(false); - x398_ = 2.f * M_PIF; + x398_spiralOffset = 2.f * M_PIF; } } void CWaveBuster::SetNewTarget(TUniqueId id, CStateManager& mgr) { x2c0_homingTargetId = id; if (id == kInvalidUniqueId) { - x3d0_26_ = false; + x3d0_26_trackingTarget = false; } else { - x3d0_26_ = true; + x3d0_26_trackingTarget = true; CSfxManager::AddEmitter(SFXsfx06FF, GetTranslation(), zeus::skZero3f, true, false, 255, kInvalidAreaId); mgr.GetRumbleManager().Rumble(mgr, ERumbleFxId::PlayerBump, 0.5f, ERumblePriority::Three); } @@ -199,35 +206,40 @@ void CWaveBuster::RenderParticles() { {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; + zeus::CTransform originalRotation = x2e8_originalXf.getRotation(); 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; + const zeus::CColor col = zeus::CColor::lerp(skCols[x3cc_innerSwooshColorIdx], skCols[x3cc_innerSwooshColorIdx + 1], x3c8_innerSwooshColorT); + float prevSwoosh2Rot = x388_busterSwoosh2Gen->GetSwooshData(x388_busterSwoosh2Gen->GetSwooshDataCount() - 1).x30_irot; + float prevSwoosh1Rot = x384_busterSwoosh1Gen->GetSwooshData(x384_busterSwoosh1Gen->GetSwooshDataCount() - 1).x30_irot; + + float t = 0.f; + for (int i = 0; i < x384_busterSwoosh1Gen->GetSwooshDataCount(); i++) { + zeus::CVector3f point = zeus::getBezierPoint(GetTranslation(), x324_bezierC, x318_bezierB, x2e8_originalXf.origin, t); + CParticleSwoosh::SSwooshData& swoosh1 = x384_busterSwoosh1Gen->GetSwooshData(i); + CParticleSwoosh::SSwooshData& swoosh2 = x388_busterSwoosh2Gen->GetSwooshData(i); - 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; + + swoosh1.x38_orientation = originalRotation; + swoosh2.x38_orientation = originalRotation; + swoosh2.x6c_color = col; - float dVar6 = swoosh1.x30_irot; - float dVar7 = swoosh2.x30_irot; - swoosh1.x30_irot = dVar9; - swoosh2.x30_irot = dVar8; + + const float curSwoosh1Rot = swoosh1.x30_irot; + const float curSwoosh2Rot = swoosh2.x30_irot; + + swoosh1.x30_irot = prevSwoosh1Rot; + swoosh2.x30_irot = prevSwoosh2Rot; + x38c_busterSparksGen->SetTranslation(point); - fVar1 = dVar10 + 0.4f; - ++iVar3; - dVar8 = dVar7; - dVar9 = dVar6; + x38c_busterSparksGen->ForceParticleCreation(1); + t += 0.04f; + + prevSwoosh1Rot = curSwoosh1Rot; + prevSwoosh2Rot = curSwoosh2Rot; } + x38c_busterSparksGen->SetParticleEmission(false); x384_busterSwoosh1Gen->Render(GetActorLights()); x388_busterSwoosh2Gen->Render(GetActorLights()); @@ -237,29 +249,31 @@ void CWaveBuster::RenderParticles() { void CWaveBuster::RenderBeam() { const zeus::CTransform inv = x2e8_originalXf.inverse(); const zeus::CVector3f vecA = inv * x2e8_originalXf.origin; - const zeus::CVector3f vecB = inv * x318_; - const zeus::CVector3f vecC = inv * x324_; + const zeus::CVector3f vecB = inv * x318_bezierB; + const zeus::CVector3f vecC = inv * x324_bezierC; const zeus::CVector3f vecD = inv * GetTranslation(); - float variation = 0.f; - rstl::reserved_vector linePoints; // Used to be L2Cache access - linePoints.resize(36); + float spiralRadius = 0.f; + rstl::reserved_vector linePoints; // Used to be L2Cache access + linePoints.resize(36 * 6); float t = 0.16; zeus::CVector3f lastPoint = vecA; + int splineBaseIndex = 0; while (t <= 1.f) { const zeus::CVector3f point = zeus::getBezierPoint(vecA, vecB, vecC, vecD, t); float angle = 0.f; for (size_t i = 0; i < 36; ++i) { const float randX = x394_rand.Range(-0.041667f, 0.041667f); const float randZ = x394_rand.Range(-0.041667f, 0.041667f); - const float offX = variation * std::cos(angle + x398_) + randX; - const float offZ = variation * std::sin(angle + x398_) + randZ; - const float d = angle / (2.f * M_PIF); - linePoints[i] = lastPoint * (1.f - d) + point * d + zeus::CVector3f{offX, 0.f, offZ}; + const float offX = spiralRadius * std::cos(angle + x398_spiralOffset) + randX; + const float offZ = spiralRadius * std::sin(angle + x398_spiralOffset) + randZ; + const float angleRad = angle / (2.f * M_PIF); + linePoints[i + splineBaseIndex] = lastPoint * (1.f - angleRad) + point * angleRad + zeus::CVector3f{offX, 0.f, offZ}; angle += zeus::degToRad(10.f); } - variation = 0.25f; + spiralRadius = 0.25f; t += 0.16; lastPoint = point; + splineBaseIndex += 36; } g_Renderer->SetModelMatrix(x2e8_originalXf); m_lineRenderer1.Reset(); @@ -283,15 +297,16 @@ CRayCastResult CWaveBuster::SeekDamageTarget(TUniqueId& uid, const zeus::CVector CRayCastResult physRes; CRayCastResult actRes; RayCastTarget(mgr, physId, actId, pos, dir, 25.f, physRes, actRes); - if (actRes.IsValid() && ApplyDamageToTarget(physId, actRes, physRes, res, mgr, dt)) { - uid = actId; - return actRes; - } if (physRes.IsValid() && ApplyDamageToTarget(actId, actRes, physRes, res, mgr, dt)) { uid = physId; return physRes; } + + if (actRes.IsValid() && ApplyDamageToTarget(physId, actRes, physRes, res, mgr, dt)) { + uid = actId; + return actRes; + } return res; } @@ -315,16 +330,16 @@ bool CWaveBuster::ApplyDamageToTarget(TUniqueId damagee, const CRayCastResult& a void CWaveBuster::UpdateTargetSeek(float dt, CStateManager& mgr) { TUniqueId uid = kInvalidUniqueId; SeekTarget(dt, uid, mgr); - if (x2c0_homingTargetId == kInvalidUniqueId && !x3d0_26_ && + if (x2c0_homingTargetId == kInvalidUniqueId && !x3d0_26_trackingTarget && (GetTranslation() - x2e8_originalXf.origin).magSquared() > 625.f) { x3d0_25_ = false; } else if (const TCastToConstPtr act = mgr.GetObjectById(x2c0_homingTargetId)) { zeus::CVector3f vec = zeus::skForward; - if (GetViewAngleToTarget(vec, *act) <= zeus::degToRad(90.f) && x3d0_26_) { + if (GetViewAngleToTarget(vec, *act) <= zeus::degToRad(90.f) && x3d0_26_trackingTarget) { x3d0_25_ = false; } else { x2c0_homingTargetId = kInvalidUniqueId; - x3d0_26_ = false; + x3d0_26_trackingTarget = false; } } } @@ -333,8 +348,8 @@ void CWaveBuster::UpdateTargetDamage(float dt, CStateManager& mgr) { if (const TCastToConstPtr act = mgr.GetObjectById(x2c0_homingTargetId)) { const CHealthInfo* hInfo = act->GetHealthInfo(mgr); if (hInfo != nullptr && hInfo->GetHP() > 0.f) { - x33c_ = act->GetAimPosition(mgr, 0.f); - SetTranslation(x33c_); + x33c_homingTargetPoint = act->GetAimPosition(mgr, 0.f); + SetTranslation(x33c_homingTargetPoint); mgr.ApplyDamage(GetUniqueId(), x2c0_homingTargetId, GetOwnerId(), CDamageInfo(x12c_curDamageInfo, dt), xf8_filter, zeus::skZero3f); return; @@ -383,7 +398,7 @@ bool CWaveBuster::UpdateBeamFrame(CStateManager& mgr, float dt) { x3ac_ += x3a4_ * dt; x3b0_ += x3b4_ * dt; x3c4_ += x3bc_ * dt; - x318_ = x2e8_originalXf * zeus::CTransform::RotateY(x3ac_) * + x318_bezierB = 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); } @@ -411,27 +426,28 @@ void CWaveBuster::RayCastTarget(CStateManager& mgr, TUniqueId& physId, TUniqueId length = 100000.f; } - float prevT = length; + float nearestPhysT = length; + float nearestActorT = length; for (TUniqueId uid : nearList) { if (const TCastToConstPtr pAct = mgr.GetObjectById(uid)) { CRayCastResult res = pAct->GetCollisionPrimitive()->CastRay(start, end, length, xf8_filter, pAct->GetPrimitiveTransform()); - if (!res.IsValid() || res.GetT() >= length) { + if (!res.IsValid() || res.GetT() >= nearestPhysT) { continue; } actorRes = res; actId = pAct->GetUniqueId(); - prevT = res.GetT(); + nearestPhysT = res.GetT(); } else if (const TCastToConstPtr act = mgr.GetObjectById(uid)) { if (auto bounds = act->GetTouchBounds()) { - CCollidableAABox collidableBox{*bounds, GetMaterialList()}; + CCollidableAABox collidableBox(*bounds, act->GetMaterialList()); CRayCastResult res = collidableBox.CastRay(start, end, length, xf8_filter, zeus::CTransform{}); - if (!res.IsValid() || res.GetT() >= prevT) { + if (!res.IsValid() || res.GetT() >= nearestActorT) { continue; } actorRes = res; actId = act->GetUniqueId(); - prevT = res.GetT(); + nearestActorT = res.GetT(); } } } @@ -452,7 +468,7 @@ CRayCastResult CWaveBuster::SeekTarget(float dt, TUniqueId& uid, CStateManager& if (uid == kInvalidUniqueId || uid != x2c0_homingTargetId) { x2c0_homingTargetId = kInvalidUniqueId; } else { - x3d0_26_ = true; + x3d0_26_trackingTarget = true; CSfxManager::AddEmitter(SFXsfx06FF, res.GetPoint(), zeus::skZero3f, true, false, 255, kInvalidAreaId); } } @@ -460,4 +476,4 @@ CRayCastResult CWaveBuster::SeekTarget(float dt, TUniqueId& uid, CStateManager& return res; } -} // namespace metaforce \ No newline at end of file +} // namespace metaforce diff --git a/Runtime/Weapon/CWaveBuster.hpp b/Runtime/Weapon/CWaveBuster.hpp index 3c9f2dfa8..ab9bea9e0 100644 --- a/Runtime/Weapon/CWaveBuster.hpp +++ b/Runtime/Weapon/CWaveBuster.hpp @@ -13,10 +13,12 @@ namespace metaforce { class CWaveBuster : public CGameProjectile { zeus::CTransform x2e8_originalXf; - zeus::CVector3f x318_; - zeus::CVector3f x324_; + // Wavebuster is rendered as a cubic bezier + // points A & D are at the arm cannon and endpoint/target respectively + zeus::CVector3f x318_bezierB; + zeus::CVector3f x324_bezierC; zeus::CVector3f x330_; - zeus::CVector3f x33c_; + zeus::CVector3f x33c_homingTargetPoint; zeus::CVector3f x348_targetPoint; TCachedToken x354_busterSwoosh1; TCachedToken x360_busterSwoosh2; @@ -27,7 +29,7 @@ class CWaveBuster : public CGameProjectile { std::unique_ptr x38c_busterSparksGen; std::unique_ptr x390_busterLightGen; CRandom16 x394_rand{99}; - float x398_ = 2.f * M_PIF; + float x398_spiralOffset = 2.f * M_PIF; float x39c_ = 0.5f; float x3a0_ = 0.5f; float x3a4_ = 0.f; @@ -39,13 +41,13 @@ class CWaveBuster : public CGameProjectile { float x3bc_ = 0.f; float x3c0_ = 0.f; float x3c4_ = 0.f; - float x3c8_ = 0.f; - u32 x3cc_ = 0; - bool x3d0_24_firing : 1; - bool x3d0_25_ : 1; - bool x3d0_26_ : 1; - bool x3d0_27_ : 1; - bool x3d0_28_ : 1; + float x3c8_innerSwooshColorT = 0.f; + u32 x3cc_innerSwooshColorIdx = 0; + bool x3d0_24_firing : 1 = true; + bool x3d0_25_ : 1 = true; + bool x3d0_26_trackingTarget : 1 = false; + bool x3d0_27_ : 1 = false; + bool x3d0_28_ : 1 = true; CLineRenderer m_lineRenderer1; CLineRenderer m_lineRenderer2;