prime/src/MetroidPrime/Weapons/CElectricBeamProjectile.cpp

124 lines
4.2 KiB
C++

#include "MetroidPrime/Weapons/CElectricBeamProjectile.hpp"
#include "MetaRender/CCubeRenderer.hpp"
#include "Kyoto/Math/CloseEnough.hpp"
#include "Kyoto/Particles/CElementGen.hpp"
#include "Kyoto/Particles/CParticleElectric.hpp"
#include "rstl/math.hpp"
CElectricBeamProjectile::CElectricBeamProjectile(const TToken< CWeaponDescription >& wDesc,
EWeaponType wType, const SElectricBeamInfo& elec,
const CTransform4f& xf, EMaterialTypes matTypes,
const CDamageInfo& dInfo, TUniqueId uid,
TAreaId areaId, TUniqueId owner,
EProjectileAttrib attribs)
: CBeamProjectile(wDesc, rstl::string_l("ElectricBeamProjectile"), wType, xf, elec.x8_maxLength,
elec.xc_radius, elec.x10_travelSpeed, matTypes, dInfo, uid, areaId, owner,
attribs, false)
, x468_electric(rs_new CParticleElectric(elec.x0_electricDescription))
, x46c_genDescription(gpSimplePool->GetObj(SObjectTag('PART', elec.x14_particleId)))
, x478_elementGen(rs_new CElementGen(x46c_genDescription))
, x47c_fadeSpeed(elec.x18_fadeSpeed)
, x484_damageTimer(0.f)
, x488_damageInterval(elec.x1c_damageInterval)
, x48c_(false) {
x478_elementGen->SetParticleEmission(false);
x468_electric->SetParticleEmission(false);
}
void CElectricBeamProjectile::Accept(IVisitor& visitor) { visitor.Visit(*this); }
void CElectricBeamProjectile::Touch(CActor&, CStateManager&) {}
void CElectricBeamProjectile::AddToRenderer(const CFrustumPlanes&, const CStateManager& mgr) const {
if (GetActive()) {
gpRender->AddParticleGen(*x478_elementGen);
gpRender->AddParticleGen(*x468_electric);
}
}
void CElectricBeamProjectile::UpdateFx(const CTransform4f& xf, float dt, CStateManager& mgr) {
if (!GetActive())
return;
if (x484_damageTimer <= 0.f)
CauseDamage(true);
if (GetDamageType() == kDT_Actor) {
x484_damageTimer = x488_damageInterval;
CauseDamage(false);
}
x484_damageTimer -= dt;
if (!close_enough(x47c_fadeSpeed, 0.f)) {
float fVar1 = x48c_ ? 1.f : -1.f;
x480_intensity = rstl::min_val(1.f, dt * (fVar1 / x47c_fadeSpeed) + x480_intensity);
if (x480_intensity < 0.f) {
ResetBeam(mgr, true);
}
} else {
x480_intensity = 1.f;
}
CBeamProjectile::UpdateFx(xf, dt, mgr);
x478_elementGen->SetModulationColor(
CColor::Lerp(CColor::Black(), CColor::White(), x480_intensity));
bool hasDamage = GetDamageType() != kDT_None;
if (hasDamage) {
x478_elementGen->SetGlobalOrientation(
CTransform4f::LookAt(CVector3f::Zero(), GetSurfaceNormal(), CVector3f::Up()));
x478_elementGen->SetGlobalTranslation(GetCurrentPos() + (0.001f * GetSurfaceNormal()));
}
x478_elementGen->SetParticleEmission(hasDamage);
x478_elementGen->Update(dt);
x468_electric->SetModulationColor(CColor::Lerp(CColor::Black(), CColor::White(), x480_intensity));
x468_electric->SetParticleEmission(true);
CVector3f dist = GetCurrentPos() - GetBeamTransform().GetTranslation();
if (dist.CanBeNormalized()) {
dist.Normalize();
}
x468_electric->SetOverrideIPos(GetBeamTransform().GetTranslation());
x468_electric->SetOverrideIVel(dist);
x468_electric->SetOverrideFPos(GetCurrentPos());
x468_electric->SetOverrideFVel(-dist);
x468_electric->Update(dt);
}
void CElectricBeamProjectile::ResetBeam(CStateManager& mgr, bool b) {
if (b) {
SetActive(false);
x478_elementGen->SetParticleEmission(false);
x468_electric->SetParticleEmission(false);
CBeamProjectile::ResetBeam(mgr, true);
} else {
x48c_ = false;
}
}
void CElectricBeamProjectile::Fire(const CTransform4f&, CStateManager&, bool) {
x48c_ = true;
SetActive(true);
x480_intensity = 0.f;
}
void CElectricBeamProjectile::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid,
CStateManager& mgr) {
switch (msg) {
case kSM_Registered:
mgr.AddWeaponId(GetOwnerId(), GetType());
CauseDamage(true);
break;
case kSM_Deleted:
DeleteProjectileLight(mgr);
break;
default:
break;
}
CGameProjectile::AcceptScriptMsg(msg, uid, mgr);
}