metaforce/Runtime/Weapon/CProjectileWeapon.cpp

510 lines
15 KiB
C++
Raw Normal View History

2017-03-24 05:30:16 +00:00
#include "CProjectileWeapon.hpp"
2018-02-10 06:26:12 +00:00
#include "Graphics/CModel.hpp"
#include "Particle/CParticleGlobals.hpp"
2018-02-12 05:30:21 +00:00
#include "GameGlobalObjects.hpp"
#include "Graphics/CBooRenderer.hpp"
2017-03-24 05:30:16 +00:00
namespace urde
{
2017-06-11 02:57:35 +00:00
u16 CProjectileWeapon::g_GlobalSeed = 99;
2017-03-24 05:30:16 +00:00
2018-02-10 06:26:12 +00:00
CProjectileWeapon::CProjectileWeapon(const TToken<CWeaponDescription>& wDesc, const zeus::CVector3f& worldOffset,
const zeus::CTransform& localToWorld, const zeus::CVector3f& scale, s32 flags)
: x4_weaponDesc(wDesc), x10_random(g_GlobalSeed), x14_localToWorldXf(localToWorld), x74_worldOffset(worldOffset),
xe4_flags(flags)
{
2018-02-10 06:26:12 +00:00
x124_24_active = true;
CGlobalRandom gr(x10_random);
x124_31_VMD2 = x4_weaponDesc->x10_VMD2;
x124_25_APSO = x4_weaponDesc->x28_APSO;
if (x4_weaponDesc->x34_APSM)
{
xfc_APSMGen = std::make_unique<CElementGen>(x4_weaponDesc->x34_APSM.m_token,
CElementGen::EModelOrientationType::Normal,
(xe4_flags & 0x1) == 0x1 ?
CElementGen::EOptionalSystemFlags::Two :
CElementGen::EOptionalSystemFlags::One);
xfc_APSMGen->SetGlobalScale(scale);
}
if (x4_weaponDesc->x44_APS2)
{
x100_APS2Gen = std::make_unique<CElementGen>(x4_weaponDesc->x44_APS2.m_token,
CElementGen::EModelOrientationType::Normal,
(xe4_flags & 0x1) == 0x1 ?
CElementGen::EOptionalSystemFlags::Two :
CElementGen::EOptionalSystemFlags::One);
x100_APS2Gen->SetGlobalScale(scale);
}
if (x4_weaponDesc->x54_ASW1)
{
x118_swoosh1 = std::make_unique<CParticleSwoosh>(x4_weaponDesc->x54_ASW1.m_token, 0);
x118_swoosh1->SetGlobalScale(scale);
}
if (x4_weaponDesc->x64_ASW2)
{
x11c_swoosh2 = std::make_unique<CParticleSwoosh>(x4_weaponDesc->x64_ASW2.m_token, 0);
x11c_swoosh2->SetGlobalScale(scale);
}
if (x4_weaponDesc->x74_ASW3)
{
x120_swoosh3 = std::make_unique<CParticleSwoosh>(x4_weaponDesc->x74_ASW3.m_token, 0);
x120_swoosh3->SetGlobalScale(scale);
}
if (CIntElement* pslt = x4_weaponDesc->x14_PSLT.get())
pslt->GetValue(0, xe8_lifetime);
else
xe8_lifetime = 0x7FFFFF;
if (CVectorElement* ivec = x4_weaponDesc->x4_IVEC.get())
ivec->GetValue(0, xb0_velocity);
if (CVectorElement* iorn = x4_weaponDesc->x0_IORN.get())
{
zeus::CTransform xf;
zeus::CVector3f orn;
iorn->GetValue(0, orn);
xf.rotateLocalX(zeus::degToRad(orn.x));
xf.rotateLocalY(zeus::degToRad(orn.y));
xf.rotateLocalZ(zeus::degToRad(orn.z));
SetRelativeOrientation(xf);
}
else
{
SetRelativeOrientation(zeus::CTransform::Identity());
}
if (x4_weaponDesc->x84_OHEF)
x108_model.emplace(x4_weaponDesc->x84_OHEF.m_token);
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);
}
2017-03-24 05:30:16 +00:00
2018-02-09 07:12:26 +00:00
zeus::CTransform CProjectileWeapon::GetTransform() const
{
return x14_localToWorldXf * x44_localXf;
}
zeus::CVector3f CProjectileWeapon::GetTranslation() const
{
2018-02-10 06:26:12 +00:00
return x14_localToWorldXf * (x44_localXf * x8c_projOffset + x80_localOffset) + x74_worldOffset;
2018-02-09 07:12:26 +00:00
}
2018-02-12 05:30:21 +00:00
rstl::optional_object<zeus::CAABox> CProjectileWeapon::GetBounds() const
{
zeus::CAABox aabb;
bool ret = false;
if (xfc_APSMGen)
{
if (auto b = xfc_APSMGen->GetBounds())
{
aabb.accumulateBounds(*b);
ret = true;
}
}
if (x100_APS2Gen)
{
if (auto b = x100_APS2Gen->GetBounds())
{
aabb.accumulateBounds(*b);
ret = true;
}
}
if (x118_swoosh1)
{
if (auto b = x118_swoosh1->GetBounds())
{
aabb.accumulateBounds(*b);
ret = true;
}
}
if (x11c_swoosh2)
{
if (auto b = x11c_swoosh2->GetBounds())
{
aabb.accumulateBounds(*b);
ret = true;
}
}
if (x120_swoosh3)
{
if (auto b = x120_swoosh3->GetBounds())
{
aabb.accumulateBounds(*b);
ret = true;
}
}
if (ret)
return {aabb};
return {};
}
2018-02-10 06:26:12 +00:00
float CProjectileWeapon::GetAudibleFallOff() const
2018-02-09 07:12:26 +00:00
{
2018-02-10 06:26:12 +00:00
if (!x4_weaponDesc->x94_COLR)
return 0.f;
return x4_weaponDesc->x94_COLR.m_res->GetAudibleFallOff();
}
2018-02-09 07:12:26 +00:00
2018-02-10 06:26:12 +00:00
float CProjectileWeapon::GetAudibleRange() const
{
if (!x4_weaponDesc->x94_COLR)
return 0.f;
return x4_weaponDesc->x94_COLR.m_res->GetAudibleRange();
2018-02-09 07:12:26 +00:00
}
2018-02-10 06:26:12 +00:00
rstl::optional_object<TLockedToken<CDecalDescription>>
CProjectileWeapon::GetDecalForCollision(EWeaponCollisionResponseTypes type) const
2018-02-09 07:12:26 +00:00
{
2018-02-10 06:26:12 +00:00
if (!x4_weaponDesc->x94_COLR)
return {};
return x4_weaponDesc->x94_COLR.m_res->GetDecalDescription(type);
}
2018-02-09 07:12:26 +00:00
2018-02-10 06:26:12 +00:00
u16 CProjectileWeapon::GetSoundIdForCollision(EWeaponCollisionResponseTypes type) const
{
if (!x4_weaponDesc->x94_COLR)
return 0xffff;
return u16(x4_weaponDesc->x94_COLR.m_res->GetSoundEffectId(type));
2018-02-09 07:12:26 +00:00
}
2018-02-10 06:26:12 +00:00
rstl::optional_object<TLockedToken<CGenDescription>>
2018-02-12 05:30:21 +00:00
CProjectileWeapon::CollisionOccured(EWeaponCollisionResponseTypes type, bool deflected, bool useTarget,
const zeus::CVector3f& pos, const zeus::CVector3f& normal,
2018-02-10 06:26:12 +00:00
const zeus::CVector3f& target)
2018-02-09 07:12:26 +00:00
{
2018-02-12 05:30:21 +00:00
x80_localOffset = x14_localToWorldXf.transposeRotate(pos - x74_worldOffset) - x8c_projOffset;
2018-02-10 06:26:12 +00:00
zeus::CVector3f posToTarget = target - GetTranslation();
2018-02-12 05:30:21 +00:00
if (deflected)
2018-02-10 06:26:12 +00:00
{
2018-02-12 05:30:21 +00:00
if (useTarget && posToTarget.canBeNormalized())
2018-02-10 06:26:12 +00:00
{
SetWorldSpaceOrientation(zeus::lookAt(zeus::CVector3f::skZero, posToTarget.normalized()));
}
else
{
zeus::CTransform xf = GetTransform();
SetWorldSpaceOrientation(
2018-02-12 05:30:21 +00:00
zeus::lookAt(zeus::CVector3f::skZero, xf.basis[1] - normal * (normal.dot(xf.basis[1]) * 2.f), normal));
2018-02-10 06:26:12 +00:00
}
return {};
}
else
{
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 {};
return x4_weaponDesc->x94_COLR.m_res->GetParticleDescription(type);
}
}
2018-02-09 07:12:26 +00:00
2018-02-10 06:26:12 +00:00
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();
}
2018-02-12 05:30:21 +00:00
void CProjectileWeapon::AddToRenderer() const
2018-02-10 06:26:12 +00:00
{
if (xfc_APSMGen)
2018-02-12 05:30:21 +00:00
g_Renderer->AddParticleGen(*xfc_APSMGen);
2018-02-10 06:26:12 +00:00
if (x100_APS2Gen)
2018-02-12 05:30:21 +00:00
g_Renderer->AddParticleGen(*x100_APS2Gen);
2018-02-10 06:26:12 +00:00
if (x118_swoosh1)
2018-02-12 05:30:21 +00:00
g_Renderer->AddParticleGen(*x118_swoosh1);
2018-02-10 06:26:12 +00:00
if (x11c_swoosh2)
2018-02-12 05:30:21 +00:00
g_Renderer->AddParticleGen(*x11c_swoosh2);
2018-02-10 06:26:12 +00:00
if (x120_swoosh3)
2018-02-12 05:30:21 +00:00
g_Renderer->AddParticleGen(*x120_swoosh3);
2018-02-10 06:26:12 +00:00
if (x104_)
2018-02-12 05:30:21 +00:00
g_Renderer->AddParticleGen(*x104_);
2018-02-10 06:26:12 +00:00
}
void CProjectileWeapon::Render() const
{
if (xf4_curFrame > xe8_lifetime || !x124_24_active || !x108_model)
return;
CGraphics::SetModelMatrix(zeus::CTransform::Translate(x74_worldOffset) * x14_localToWorldXf *
zeus::CTransform::Translate(x44_localXf * x8c_projOffset + x80_localOffset + xa4_localOffset2) *
zeus::CTransform::Scale(x98_scale) * x44_localXf);
std::vector<CLight> useLights;
useLights.push_back(CLight::BuildLocalAmbient({}, xc8_ambientLightColor));
const_cast<CModel&>(**x108_model).GetInstance().ActivateLights(useLights);
CModelFlags flags(0, 0, 3, zeus::CColor::skWhite);
(*x108_model)->Draw(flags);
}
bool CProjectileWeapon::IsSystemDeletable() const
{
if (xfc_APSMGen && !xfc_APSMGen->IsSystemDeletable())
return false;
if (x100_APS2Gen && !x100_APS2Gen->IsSystemDeletable())
return false;
if (x118_swoosh1 && !x118_swoosh1->IsSystemDeletable())
return false;
if (x11c_swoosh2 && !x11c_swoosh2->IsSystemDeletable())
return false;
if (x120_swoosh3 && !x120_swoosh3->IsSystemDeletable())
return false;
if (x104_ && !x104_->IsSystemDeletable())
return false;
if (x124_24_active)
return xf4_curFrame >= xe8_lifetime;
return true;
2018-02-09 07:12:26 +00:00
}
void CProjectileWeapon::UpdateChildParticleSystems(float dt)
{
2018-02-10 06:26:12 +00:00
double useDt;
if (zeus::close_enough(dt, 1.f / 60.f))
useDt = 1.0 / 60.0;
else
useDt = 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())
xfc_APSMGen.reset();
}
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())
x100_APS2Gen.reset();
}
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->DoWarmupUpdate();
if (x118_swoosh1->IsSystemDeletable())
x118_swoosh1.reset();
}
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->DoWarmupUpdate();
if (x11c_swoosh2->IsSystemDeletable())
x11c_swoosh2.reset();
}
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->DoWarmupUpdate();
if (x120_swoosh3->IsSystemDeletable())
x120_swoosh3.reset();
}
if (x104_)
{
x104_->Update(useDt);
if (x104_->IsSystemDeletable())
x104_.reset();
}
xf8_lastParticleFrame = xf4_curFrame;
}
void CProjectileWeapon::UpdatePSTranslationAndOrientation()
{
if (xe8_lifetime < xf4_curFrame || !x124_24_active)
return;
if (CModVectorElement* psvm = x4_weaponDesc->xc_PSVM.get())
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.get())
{
zeus::CVector3f orient;
psov->GetValue(xf4_curFrame, orient);
zeus::CTransform xf = x44_localXf;
xf.rotateLocalX(zeus::degToRad(orient.x));
xf.rotateLocalY(zeus::degToRad(orient.y));
xf.rotateLocalZ(zeus::degToRad(orient.z));
SetRelativeOrientation(xf);
}
if (CVectorElement* pscl = x4_weaponDesc->x18_PSCL.get())
pscl->GetValue(xf4_curFrame, x98_scale);
if (CColorElement* pcol = x4_weaponDesc->x1c_PCOL.get())
pcol->GetValue(xf4_curFrame, xc8_ambientLightColor);
if (CVectorElement* pofs = x4_weaponDesc->x20_POFS.get())
pofs->GetValue(xf4_curFrame, xa4_localOffset2);
2018-02-09 07:12:26 +00:00
2018-02-10 06:26:12 +00:00
if (CVectorElement* ofst = x4_weaponDesc->x24_OFST.get())
ofst->GetValue(xf4_curFrame, x8c_projOffset);
2018-02-09 07:12:26 +00:00
}
void CProjectileWeapon::SetWorldSpaceOrientation(const zeus::CTransform& xf)
{
x44_localXf = x14_localToWorldXf.inverse() * xf;
}
2018-02-10 06:26:12 +00:00
void CProjectileWeapon::UpdateParticleFX()
{
for (int i=0 ; i<xec_childSystemUpdateRate ; ++i)
UpdateChildParticleSystems(1.f / 60.f);
}
void CProjectileWeapon::Update(float dt)
{
CGlobalRandom gr(x10_random);
xec_childSystemUpdateRate = 0;
double useDt;
if (zeus::close_enough(dt, 1.f / 60.f))
useDt = 1.0 / 60.0;
else
useDt = dt;
useDt = std::max(0.0, useDt);
xd0_curTime += useDt;
double actualTime = xf4_curFrame * (1.0 / 60.0);
while (actualTime < xd0_curTime && !zeus::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.0 / 60.0);
++xf4_curFrame;
++xec_childSystemUpdateRate;
}
if (zeus::close_enough(actualTime, xd0_curTime))
xd0_curTime = actualTime;
xd8_remainderTime = (actualTime - xd0_curTime) * 60.0;
if (xf4_curFrame < xe8_lifetime)
{
xe0_maxTurnRate = 0.f;
if (CRealElement* trat = x4_weaponDesc->x30_TRAT.get())
trat->GetValue(0, xe0_maxTurnRate);
}
}
2017-03-24 05:30:16 +00:00
}