2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-05-13 17:11:22 +00:00
metaforce/Runtime/Weapon/CPlasmaProjectile.cpp
Lioncash 221cc5c6b8 RuntimeCommonB: Normalize cpp file includes
Like the prior changes normalizing the inclusions within headers, this
tackles the cpp files of the RuntimeCommonB target, making these source
files consistent with their headers.
2019-12-22 18:12:04 -05:00

448 lines
18 KiB
C++

#include "Runtime/Weapon/CPlasmaProjectile.hpp"
#include "Runtime/CSimplePool.hpp"
#include "Runtime/CStateManager.hpp"
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Graphics/CBooRenderer.hpp"
#include "Runtime/World/CGameLight.hpp"
#include "Runtime/World/CHUDBillboardEffect.hpp"
#include "Runtime/World/CPlayer.hpp"
#include "TCastTo.hpp" // Generated file, do not modify include path
namespace urde {
CPlasmaProjectile::RenderObjects::RenderObjects(boo::IGraphicsDataFactory::Context& ctx,
boo::ObjToken<boo::ITexture> tex,
boo::ObjToken<boo::ITexture> glowTex)
: m_beamStrip1(ctx, 8, CColoredStripShader::Mode::Additive, {})
, m_beamStrip2(ctx, 10, CColoredStripShader::Mode::FullAdditive, tex)
, m_beamStrip3(ctx, 18, CColoredStripShader::Mode::FullAdditive, tex)
, m_beamStrip4(ctx, 14, CColoredStripShader::Mode::Additive, glowTex)
, m_beamStrip1Sub(ctx, 8, CColoredStripShader::Mode::Subtractive, {})
, m_beamStrip2Sub(ctx, 10, CColoredStripShader::Mode::Subtractive, tex)
, m_beamStrip3Sub(ctx, 18, CColoredStripShader::Mode::Subtractive, tex)
, m_beamStrip4Sub(ctx, 14, CColoredStripShader::Mode::Subtractive, glowTex)
, m_motionBlurStrip(ctx, 16, CColoredStripShader::Mode::Alpha, {}) {}
CPlasmaProjectile::CPlasmaProjectile(const TToken<CWeaponDescription>& wDesc, std::string_view name, EWeaponType wType,
const CBeamInfo& bInfo, const zeus::CTransform& xf, EMaterialTypes matType,
const CDamageInfo& dInfo, TUniqueId uid, TAreaId aid, TUniqueId owner,
const PlayerEffectResoures& res, bool growingBeam, EProjectileAttrib attribs)
: CBeamProjectile(wDesc, name, wType, xf, bInfo.GetLength(), bInfo.GetRadius(), bInfo.GetTravelSpeed(), matType,
dInfo, uid, aid, owner, attribs, growingBeam)
, x478_beamAttributes(bInfo.GetBeamAttributes())
, x47c_lifeTime(bInfo.GetLifeTime())
, x480_pulseSpeed(bInfo.GetPulseSpeed())
, x484_shutdownTime(bInfo.GetShutdownTime())
, x488_expansionSpeed(bInfo.GetExpansionSpeed())
, x48c_(bInfo.GetLength() / 32.f)
, x490_innerColor(bInfo.GetInnerColor())
, x494_outerColor(bInfo.GetOuterColor()) {
x4e8_texture = g_SimplePool->GetObj(SObjectTag{FOURCC('TXTR'), bInfo.GetTextureId()});
x4f4_glowTexture = g_SimplePool->GetObj(SObjectTag{FOURCC('TXTR'), bInfo.GetGlowTextureId()});
x500_contactFxDesc = g_SimplePool->GetObj(SObjectTag{FOURCC('PART'), bInfo.GetContactFxId()});
x50c_pulseFxDesc = g_SimplePool->GetObj(SObjectTag{FOURCC('PART'), bInfo.GetPulseFxId()});
x518_contactGen = std::make_unique<CElementGen>(x500_contactFxDesc, CElementGen::EModelOrientationType::One);
x51c_pulseGen = std::make_unique<CElementGen>(x50c_pulseFxDesc, CElementGen::EModelOrientationType::Normal);
x524_freezeSteamTxtr = res[0];
x528_freezeIceTxtr = res[1];
if (res[2] != UINT64_MAX)
x52c_visorElectric = g_SimplePool->GetObj(SObjectTag{FOURCC('ELSC'), res[2]});
if (res[3] != UINT64_MAX)
x538_visorParticle = g_SimplePool->GetObj(SObjectTag{FOURCC('PART'), res[3]});
x544_freezeSfx = CSfxManager::TranslateSFXID(res[4]);
x546_electricSfx = CSfxManager::TranslateSFXID(res[5]);
x548_25_enableEnergyPulse = true;
x548_28_drawOwnerFirst = growingBeam;
x518_contactGen->SetGlobalScale(zeus::CVector3f(bInfo.GetContactFxScale()));
x51c_pulseGen->SetGlobalScale(zeus::CVector3f(bInfo.GetPulseFxScale()));
x518_contactGen->SetParticleEmission(false);
x51c_pulseGen->SetParticleEmission(false);
CGraphics::CommitResources([this](boo::IGraphicsDataFactory::Context& ctx) {
m_renderObjs.emplace(ctx, x4e8_texture->GetBooTexture(), x4f4_glowTexture->GetBooTexture());
return true;
} BooTrace);
}
void CPlasmaProjectile::Accept(IVisitor& visitor) { visitor.Visit(this); }
void CPlasmaProjectile::SetLightsActive(bool active, CStateManager& mgr) {
for (TUniqueId lid : x468_lights) {
if (lid != kInvalidUniqueId) {
if (TCastToPtr<CGameLight> light = mgr.ObjectById(lid)) {
light->SetActive(active);
}
}
}
}
void CPlasmaProjectile::CreatePlasmaLights(u32 sourceId, const CLight& l, CStateManager& mgr) {
DeletePlasmaLights(mgr);
x468_lights.reserve(3);
for (int i = 0; i < 3; ++i) {
TUniqueId lid = mgr.AllocateUniqueId();
auto* light =
new CGameLight(lid, GetAreaId(), GetActive(), ""sv, GetTransform(), GetUniqueId(), l, sourceId, 0, 0.f);
mgr.AddObject(light);
x468_lights.push_back(lid);
}
}
void CPlasmaProjectile::DeletePlasmaLights(CStateManager& mgr) {
for (TUniqueId lid : x468_lights)
mgr.FreeScriptObject(lid);
x468_lights.clear();
}
void CPlasmaProjectile::UpdateLights(float expansion, float dt, CStateManager& mgr) {
if (x520_weaponGen) {
x520_weaponGen->Update(dt);
CLight l = x520_weaponGen->GetLight();
l.SetColor(zeus::CColor::lerp(zeus::skClear, l.GetColor(), expansion));
float halfLen = 0.5f * GetCurrentLength();
float y = 0.f;
for (TUniqueId lid : x468_lights) {
if (TCastToPtr<CGameLight> light = mgr.ObjectById(lid)) {
light->SetTransform({});
light->SetTranslation(GetBeamTransform() * zeus::CVector3f(0.f, y, 0.f));
light->SetLight(l);
}
y += halfLen;
}
}
}
void CPlasmaProjectile::UpdateEnergyPulse(float dt) {
if (GetDamageType() != EDamageType::None && x548_25_enableEnergyPulse) {
x4d8_energyPulseTimer -= dt;
if (x4d8_energyPulseTimer <= 0.f) {
x4d8_energyPulseTimer = 2.f * dt;
x51c_pulseGen->SetParticleEmission(true);
float t = GetCurrentLength() / GetMaxLength();
for (float i = 0.f; i <= t; i += 0.1f) {
float y = i * GetMaxLength() + x4cc_energyPulseStartY;
if (y > GetCurrentLength())
continue;
x51c_pulseGen->SetTranslation({0.f, y, 0.f});
x51c_pulseGen->ForceParticleCreation(1);
}
x51c_pulseGen->SetGlobalOrientAndTrans(GetBeamTransform());
x51c_pulseGen->SetParticleEmission(false);
}
}
x51c_pulseGen->Update(dt);
}
void CPlasmaProjectile::RenderMotionBlur() const {
CGraphics::SetModelMatrix({});
zeus::CColor color1 = x494_outerColor;
zeus::CColor color2 = x494_outerColor;
color1.a() = 63.f / 255.f;
color2.a() = 0.f;
CColoredStripShader::Vert verts[16];
for (int i = 0; i < 8; ++i) {
auto& v1 = verts[i * 2];
auto& v2 = verts[i * 2 + 1];
v1.m_pos = GetBeamTransform().origin;
v1.m_color = zeus::CColor::lerp(color1, color2, i / 8.f);
v2.m_pos = GetPointCache()[i];
v2.m_color = v1.m_color;
}
m_renderObjs->m_motionBlurStrip.draw(zeus::skWhite, 16, verts);
}
void CPlasmaProjectile::RenderBeam(s32 subdivs, float width, const zeus::CColor& color, s32 flags,
CColoredStripShader& shader) const {
// Flags: 0x1: textured, 0x2: length controlled UVY 0x4: alpha controlled additive blend,
// 0x8: glow texture, 0x10: subtractive blend
if ((flags & 0x1) == 0 || (flags & 0x8) ? x4f4_glowTexture.IsLoaded() : x4e8_texture.IsLoaded()) {
float angIncrement = 2.f * M_PIF / float(subdivs);
float uvY1 = -(x4cc_energyPulseStartY / 16.f);
float uvY2 = (uvY1 + float((flags & 0x3) == 0x3) != 0.f) ? 2.f : 0.5f * GetCurrentLength();
CColoredStripShader::Vert verts[18];
s32 numNodes = subdivs + 1;
float angle = 0.f;
bool flip = false;
for (s32 i = 0; i < numNodes; ++i) {
CColoredStripShader::Vert& v0 = verts[i * 2];
CColoredStripShader::Vert& v1 = verts[i * 2 + 1];
float x = std::cos(angle);
float y = std::sin(angle);
float uvX;
if (flags & 0x8)
uvX = 0.5f * y;
else if (flip)
uvX = width;
else
uvX = 0.f;
flip ^= true;
v0.m_pos = zeus::CVector3f(width * x, 0.f, width * y);
v0.m_color = color;
v0.m_uv = zeus::CVector2f(uvX, uvY1);
v1.m_pos = zeus::CVector3f(width * x, GetCurrentLength(), width * y);
v1.m_color = color;
v1.m_uv = zeus::CVector2f(uvX, uvY2);
angle += angIncrement;
}
shader.draw(zeus::skWhite, numNodes * 2, verts);
}
}
void CPlasmaProjectile::ResetBeam(CStateManager& mgr, bool fullReset) {
if (fullReset) {
SetActive(false);
SetLightsActive(false, mgr);
x4bc_lifeTimer = 0.f;
x4c0_expansionT = 0.f;
x4c8_beamAngle = 0.f;
x4d0_shutdownTimer = 0.f;
x4d4_contactPulseTimer = 0.f;
x4d8_energyPulseTimer = 0.f;
x4dc_playerEffectPulseTimer = 0.f;
x4b4_expansionState = EExpansionState::Inactive;
x548_26_firing = false;
x518_contactGen->SetParticleEmission(false);
x51c_pulseGen->SetParticleEmission(false);
} else {
x548_26_firing = false;
x4b4_expansionState = EExpansionState::Release;
x518_contactGen->SetParticleEmission(false);
x51c_pulseGen->SetParticleEmission(false);
}
}
float CPlasmaProjectile::UpdateBeamState(float dt, CStateManager& mgr) {
switch (x4b4_expansionState) {
case EExpansionState::Attack:
if (x4c0_expansionT > 0.5f)
x4b4_expansionState = EExpansionState::Sustain;
else
x4c0_expansionT += dt * x488_expansionSpeed;
break;
case EExpansionState::Sustain:
if (x478_beamAttributes & 0x4) {
if (x4bc_lifeTimer > x47c_lifeTime)
x4b4_expansionState = EExpansionState::Release;
else
x4bc_lifeTimer += dt;
}
break;
case EExpansionState::Release:
x4c0_expansionT += dt * x488_expansionSpeed;
if (x4c0_expansionT > 1.f) {
x4c0_expansionT = 1.f;
x4b4_expansionState = EExpansionState::Done;
x548_25_enableEnergyPulse = false;
}
break;
case EExpansionState::Done:
x4d0_shutdownTimer += dt;
if (x4d0_shutdownTimer > x484_shutdownTime &&
(!x518_contactGen || x518_contactGen->GetParticleCountAll() == 0)) {
x4b4_expansionState = EExpansionState::Inactive;
ResetBeam(mgr, true);
}
break;
default:
break;
}
return -4.f * x4c0_expansionT * (x4c0_expansionT - 1.f);
}
void CPlasmaProjectile::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) {
switch (msg) {
case EScriptObjectMessage::Registered: {
xe6_27_thermalVisorFlags = 2;
const SChildGeneratorDesc& apsm = x170_projectile.GetWeaponDescription()->x34_APSM;
if (apsm)
x520_weaponGen = std::make_unique<CElementGen>(apsm.m_token);
if (x520_weaponGen && x520_weaponGen->SystemHasLight())
CreatePlasmaLights(x170_projectile.GetWeaponDescription().GetObjectTag()->id.Value(),
x520_weaponGen->GetLight(), mgr);
else
x520_weaponGen.reset();
if (x548_28_drawOwnerFirst)
xc6_nextDrawNode = xec_ownerId;
mgr.AddWeaponId(xec_ownerId, xf0_weaponType);
break;
}
case EScriptObjectMessage::Deleted:
mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType);
DeletePlasmaLights(mgr);
if (x548_29_activePlayerPhazon) {
mgr.GetPlayer().DecrementEnvironmentDamage();
x548_29_activePlayerPhazon = false;
}
break;
default:
break;
}
CGameProjectile::AcceptScriptMsg(msg, sender, mgr);
}
void CPlasmaProjectile::MakeBillboardEffect(const std::optional<TToken<CGenDescription>>& particle,
const std::optional<TToken<CElectricDescription>>& electric,
std::string_view name, CStateManager& mgr) {
auto* effect = new CHUDBillboardEffect(particle, electric, mgr.AllocateUniqueId(), true, name,
CHUDBillboardEffect::GetNearClipDistance(mgr),
CHUDBillboardEffect::GetScaleForPOV(mgr),
zeus::skWhite, zeus::skOne3f, zeus::skZero3f);
mgr.AddObject(effect);
}
void CPlasmaProjectile::UpdatePlayerEffects(float dt, CStateManager& mgr) {
x4dc_playerEffectPulseTimer -= dt;
if ((x4b4_expansionState == EExpansionState::Attack || x4b4_expansionState == EExpansionState::Sustain) &&
x4dc_playerEffectPulseTimer <= 0.f && GetDamageType() == EDamageType::Actor &&
GetCollisionActorId() == mgr.GetPlayer().GetUniqueId()) {
if ((x478_beamAttributes & 0x8) && !x548_29_activePlayerPhazon) {
x548_29_activePlayerPhazon = true;
x4e4_playerDamageTimer = 0.f;
mgr.GetPlayer().IncrementEnvironmentDamage();
}
switch (xf0_weaponType) {
case EWeaponType::Ice:
mgr.GetPlayer().Freeze(mgr, x524_freezeSteamTxtr, x544_freezeSfx, x528_freezeIceTxtr);
break;
case EWeaponType::Wave:
if (x52c_visorElectric) {
MakeBillboardEffect({}, {x52c_visorElectric}, "PlasmaElectricFx"sv, mgr);
CSfxManager::SfxStart(x546_electricSfx, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
mgr.GetPlayer().SetHudDisable(3.f, 0.5f, 2.5f);
mgr.GetPlayer().SetOrbitRequestForTarget(mgr.GetPlayer().GetOrbitTargetId(),
CPlayer::EPlayerOrbitRequest::ActivateOrbitSource, mgr);
mgr.GetPlayerState()->GetStaticInterference().AddSource(GetUniqueId(), 0.2f, 3.f);
}
break;
case EWeaponType::Plasma:
if (x538_visorParticle)
MakeBillboardEffect({x538_visorParticle}, {}, "PlasmaVisorFx"sv, mgr);
break;
default:
break;
}
x4dc_playerEffectPulseTimer = 0.75f;
}
if (x548_29_activePlayerPhazon) {
CDamageInfo scaledDamage(x498_phazonDamage, dt);
mgr.ApplyDamage(GetUniqueId(), mgr.GetPlayer().GetUniqueId(), xec_ownerId, scaledDamage, xf8_filter,
zeus::skZero3f);
x4e4_playerDamageTimer += dt;
if (x4e4_playerDamageTimer >= x4e0_playerDamageDuration) {
mgr.GetPlayer().DecrementEnvironmentDamage();
x4e4_playerDamageTimer = 0.f;
x548_29_activePlayerPhazon = false;
}
}
}
void CPlasmaProjectile::UpdateFx(const zeus::CTransform& xf, float dt, CStateManager& mgr) {
if (!GetActive())
return;
x548_27_texturesLoaded = x4e8_texture.IsLoaded() && x4f4_glowTexture.IsLoaded();
CauseDamage(x4b4_expansionState == EExpansionState::Attack || x4b4_expansionState == EExpansionState::Sustain);
CBeamProjectile::UpdateFx(xf, dt, mgr);
UpdatePlayerEffects(dt, mgr);
if (x478_beamAttributes & 0x1) {
for (int i = 7; i > 0; --i)
PointCache()[i] = PointCache()[i - 1];
PointCache()[0] = GetCurrentPos();
}
if (x518_contactGen) {
x4d4_contactPulseTimer -= dt;
if ((GetDamageType() != EDamageType::None ? x548_25_enableEnergyPulse : false) && x4d4_contactPulseTimer <= 0.f) {
x518_contactGen->SetOrientation(zeus::lookAt(zeus::skZero3f, GetSurfaceNormal()));
x518_contactGen->SetTranslation(GetSurfaceNormal() * 0.001f + GetCurrentPos());
x518_contactGen->SetParticleEmission(true);
x4d4_contactPulseTimer = 1.f / 16.f;
} else {
x518_contactGen->SetParticleEmission(false);
}
x518_contactGen->Update(dt);
}
float modulation = UpdateBeamState(dt, mgr);
UpdateEnergyPulse(dt);
x4c8_beamAngle += 720.f * dt;
if (x4c8_beamAngle > 360.f)
x4c8_beamAngle = 0.f;
x4b8_beamWidth = modulation * GetMaxRadius();
x4c4_expansion = modulation;
x4cc_energyPulseStartY += dt * x480_pulseSpeed;
if (x4cc_energyPulseStartY > 5.f)
x4cc_energyPulseStartY = 0.f;
UpdateLights(modulation, dt, mgr);
}
void CPlasmaProjectile::Fire(const zeus::CTransform& xf, CStateManager& mgr, bool b) {
SetActive(true);
SetLightsActive(true, mgr);
x548_25_enableEnergyPulse = true;
x548_26_firing = true;
x548_24_ = b;
x4b4_expansionState = EExpansionState::Attack;
if (x478_beamAttributes & 0x1)
std::fill(PointCache().begin(), PointCache().end(), xf.origin);
}
void CPlasmaProjectile::Touch(CActor& other, CStateManager& mgr) {
// Empty
}
bool CPlasmaProjectile::CanRenderUnsorted(const CStateManager& mgr) const {
return false;
}
void CPlasmaProjectile::AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const {
if (GetActive()) {
g_Renderer->AddParticleGen(*x518_contactGen);
if (x478_beamAttributes & 0x2) {
g_Renderer->AddParticleGen(*x51c_pulseGen);
}
}
EnsureRendered(mgr, GetBeamTransform().origin, GetSortingBounds(mgr));
}
void CPlasmaProjectile::Render(const CStateManager& mgr) const {
if (!GetActive())
return;
SCOPED_GRAPHICS_DEBUG_GROUP("CPlasmaProjectile::Render", zeus::skOrange);
zeus::CTransform xf = GetBeamTransform();
// Subtractive blending for xray
s32 flags = mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay ? 0x10 : 0x0;
if ((x478_beamAttributes & 0x1) == 0)
xf.origin += mgr.GetCameraManager()->GetGlobalCameraTranslation(mgr);
// Z test, no write
if ((x478_beamAttributes & 0x1) && x548_25_enableEnergyPulse && x4b4_expansionState != EExpansionState::Attack)
RenderMotionBlur();
// Pass1: alpha-controlled additive
CGraphics::SetModelMatrix(xf);
RenderBeam(3, 0.25f * x4b8_beamWidth, zeus::CColor(1.f, 0.3f), flags | 0x4,
(flags & 0x10) ? m_renderObjs->m_beamStrip1Sub : m_renderObjs->m_beamStrip1);
// Pass2: textured
CGraphics::SetModelMatrix(xf * zeus::CTransform::RotateY(zeus::degToRad(x4c8_beamAngle)));
RenderBeam(4, 0.5f * x4b8_beamWidth, x490_innerColor, flags | 0x1,
(flags & 0x10) ? m_renderObjs->m_beamStrip2Sub : m_renderObjs->m_beamStrip2);
// Pass3: textured | length-controlled UVY
CGraphics::SetModelMatrix(xf * zeus::CTransform::RotateY(zeus::degToRad(-x4c8_beamAngle)));
RenderBeam(8, x4b8_beamWidth, x494_outerColor, flags | 0x3,
(flags & 0x10) ? m_renderObjs->m_beamStrip3Sub : m_renderObjs->m_beamStrip3);
// Pass4: textured | alpha-controlled additive | glow texture
CGraphics::SetModelMatrix(xf);
RenderBeam(6, 1.25f * x4b8_beamWidth, x494_outerColor, flags | 0xd,
(flags & 0x10) ? m_renderObjs->m_beamStrip4Sub : m_renderObjs->m_beamStrip4);
}
} // namespace urde