metaforce/Runtime/World/CActorModelParticles.cpp

684 lines
22 KiB
C++
Raw Normal View History

#include "Runtime/World/CActorModelParticles.hpp"
#include <algorithm>
#include <array>
#include "Runtime/CDependencyGroup.hpp"
#include "Runtime/CSimplePool.hpp"
#include "Runtime/CStateManager.hpp"
#include "Runtime/GameGlobalObjects.hpp"
#include "Runtime/Graphics/CBooRenderer.hpp"
#include "Runtime/Graphics/CSkinnedModel.hpp"
#include "Runtime/Particle/CElementGen.hpp"
#include "Runtime/Particle/CGenDescription.hpp"
#include "Runtime/Particle/CParticleElectric.hpp"
#include "Runtime/World/CPatterned.hpp"
#include "Runtime/World/CScriptPlayerActor.hpp"
#include "Runtime/World/CWorld.hpp"
2021-04-10 08:42:06 +00:00
namespace metaforce {
2018-12-08 01:49:15 +00:00
static bool IsMediumOrLarge(const CActor& act) {
if (const TCastToConstPtr<CPatterned> pat = act) {
2018-12-08 05:30:43 +00:00
return pat->GetKnockBackController().GetVariant() != EKnockBackVariant::Small;
}
2018-12-08 05:30:43 +00:00
return false;
2018-12-08 01:49:15 +00:00
}
CActorModelParticles::CItem::CItem(const CEntity& ent, CActorModelParticles& parent)
2021-06-07 19:29:18 +00:00
: x0_id(ent.GetUniqueId()), x4_areaId(ent.GetAreaIdAlways()), xdc_ashy(parent.x48_ashy), x128_parent(parent) {
2018-12-13 07:39:16 +00:00
x8_onFireGens.resize(8);
2018-12-08 05:30:43 +00:00
}
2018-12-13 07:39:16 +00:00
static s32 GetNextBestPt(s32 start, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn,
CRandom16& rnd) {
2018-12-08 05:30:43 +00:00
const zeus::CVector3f& startVec = vn[start].first;
2018-12-13 07:39:16 +00:00
s32 ret = start;
float maxMag = 0.f;
2018-12-08 05:30:43 +00:00
for (s32 i = 0; i < 10; ++i) {
2018-12-13 07:39:16 +00:00
s32 idx = rnd.Range(0, s32(vn.size()) - 1);
2018-12-08 05:30:43 +00:00
const zeus::CVector3f& rndVec = vn[idx].first;
float mag = (startVec - rndVec).magSquared();
2018-12-13 07:39:16 +00:00
if (mag > maxMag) {
2018-12-08 05:30:43 +00:00
ret = idx;
2018-12-13 07:39:16 +00:00
maxMag = mag;
2017-07-30 11:00:30 +00:00
}
2018-12-08 05:30:43 +00:00
}
return ret;
}
void CActorModelParticles::CItem::GeneratePoints(const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) {
2018-12-13 07:39:16 +00:00
for (std::pair<std::unique_ptr<CElementGen>, u32>& pair : x8_onFireGens) {
2018-12-08 05:30:43 +00:00
if (pair.first) {
CRandom16 rnd(pair.second);
2018-12-13 07:39:16 +00:00
const zeus::CVector3f& vec = vn[rnd.Float() * (vn.size() - 1)].first;
pair.first->SetTranslation(xec_particleOffsetScale * vec);
2017-07-30 11:00:30 +00:00
}
2018-12-08 05:30:43 +00:00
}
2018-12-13 07:39:16 +00:00
if (x84_ashMaxParticles > 0) {
CRandom16 rnd(x88_ashSeed);
s32 count = (x84_ashMaxParticles >= 16 ? 16 : x84_ashMaxParticles);
s32 idx = x80_ashPointIterator;
2018-12-08 05:30:43 +00:00
for (u32 i = 0; i < count; ++i) {
idx = GetNextBestPt(idx, vn, rnd);
2018-12-13 07:39:16 +00:00
x78_ashGen->SetTranslation(xec_particleOffsetScale * vn[idx].first);
2018-12-08 05:30:43 +00:00
zeus::CVector3f v = vn[idx].second;
if (v.canBeNormalized()) {
v.normalize();
2021-06-07 19:29:18 +00:00
x78_ashGen->SetOrientation(zeus::CTransform{v.cross(zeus::skUp), v, zeus::skUp, zeus::skZero3f});
2018-12-08 05:30:43 +00:00
}
2018-12-13 07:39:16 +00:00
x78_ashGen->ForceParticleCreation(1);
2017-07-30 11:00:30 +00:00
}
2018-12-13 07:39:16 +00:00
x84_ashMaxParticles -= count;
x88_ashSeed = rnd.GetSeed();
x80_ashPointIterator = idx;
2018-12-08 05:30:43 +00:00
}
2017-07-30 11:00:30 +00:00
2018-12-13 07:39:16 +00:00
if (xb0_icePointIterator != -1) {
CRandom16 rnd(xb4_iceSeed);
2017-07-30 11:00:30 +00:00
2018-12-08 05:30:43 +00:00
std::unique_ptr<CElementGen> iceGen = x128_parent.MakeIceGen();
2018-12-13 07:39:16 +00:00
iceGen->SetGlobalOrientAndTrans(xf8_iceXf);
2017-07-30 11:00:30 +00:00
2018-12-13 07:39:16 +00:00
s32 idx = GetNextBestPt(xb0_icePointIterator, vn, rnd);
iceGen->SetTranslation(xec_particleOffsetScale * vn[idx].first);
2017-07-30 11:00:30 +00:00
2018-12-13 07:39:16 +00:00
iceGen->SetOrientation(zeus::CTransform::MakeRotationsBasedOnY(zeus::CUnitVector3f(vn[idx].second)));
2017-08-01 10:08:42 +00:00
2018-12-13 07:39:16 +00:00
x8c_iceGens.push_back(std::move(iceGen));
xb0_icePointIterator = (x8c_iceGens.size() == 4 ? -1 : idx);
2018-12-08 05:30:43 +00:00
}
2018-12-13 07:39:16 +00:00
if (xc0_electricGen && xc0_electricGen->GetParticleEmission()) {
CRandom16 rnd(xcc_electricSeed);
2018-12-08 05:30:43 +00:00
u32 end = 1;
2017-07-31 10:47:04 +00:00
#if 0
2018-12-13 07:39:16 +00:00
if (4 < 1)
end = 4;
2017-07-31 10:47:04 +00:00
#endif
2018-12-13 07:39:16 +00:00
s32 idx = xc8_electricPointIterator;
2018-12-08 05:30:43 +00:00
for (u32 i = 0; i < end; ++i) {
2018-12-13 07:39:16 +00:00
xc0_electricGen->SetOverrideIPos(vn[rnd.Range(0, s32(vn.size()) - 1)].first * xec_particleOffsetScale);
idx = rnd.Range(0, s32(vn.size()) - 1);
xc0_electricGen->SetOverrideFPos(vn[idx].first * xec_particleOffsetScale);
xc0_electricGen->ForceParticleCreation(1);
2017-07-31 10:47:04 +00:00
}
2018-12-13 07:39:16 +00:00
xcc_electricSeed = rnd.GetSeed();
xc8_electricPointIterator = idx;
2018-12-08 05:30:43 +00:00
}
2018-12-13 07:39:16 +00:00
if (xd4_rainSplashGen)
xd4_rainSplashGen->GeneratePoints(vn);
2018-12-08 05:30:43 +00:00
}
bool CActorModelParticles::CItem::UpdateOnFire(float dt, CActor* actor, CStateManager& mgr) {
2018-12-13 07:39:16 +00:00
bool effectActive = false;
bool sfxActive = false;
2018-12-08 05:30:43 +00:00
x6c_onFireDelayTimer -= dt;
if (x6c_onFireDelayTimer < 0.f)
x6c_onFireDelayTimer = 0.f;
if (x134_lockDeps & 0x1) {
2018-12-13 07:39:16 +00:00
if (x128_parent.xe6_loadedDeps & 0x1) {
2018-12-08 05:30:43 +00:00
if (x70_onFire && actor) {
2018-12-13 07:39:16 +00:00
bool doCreate = true;
if (x78_ashGen || xdc_ashy) {
doCreate = false;
2018-12-08 05:30:43 +00:00
} else if (!IsMediumOrLarge(*actor)) {
2018-12-13 07:39:16 +00:00
int activeParts = 0;
for (const auto& p : x8_onFireGens)
2018-12-08 05:30:43 +00:00
if (p.first)
2018-12-13 07:39:16 +00:00
++activeParts;
if (activeParts >= 4)
doCreate = false;
2018-12-08 05:30:43 +00:00
}
2018-12-13 07:39:16 +00:00
if (doCreate) {
for (auto& p : x8_onFireGens) {
2018-12-08 05:30:43 +00:00
if (!p.first) {
p.second = mgr.GetActiveRandom()->Next();
p.first = x128_parent.MakeOnFireGen();
x6c_onFireDelayTimer = 0.3f;
break;
2018-12-08 01:49:15 +00:00
}
2018-12-08 05:30:43 +00:00
}
2018-12-08 01:49:15 +00:00
}
2018-12-08 05:30:43 +00:00
if (!x74_sfx) {
x74_sfx = CSfxManager::AddEmitter(SFXsfx0480 + (IsMediumOrLarge(*actor) ? 1 : 0), actor->GetTranslation(),
zeus::skZero3f, true, true, 0x7f, kInvalidAreaId);
2018-12-08 01:49:15 +00:00
}
2018-12-08 05:30:43 +00:00
x70_onFire = false;
}
2018-12-13 07:39:16 +00:00
for (auto& p : x8_onFireGens) {
2018-12-08 05:30:43 +00:00
if (p.first) {
if (p.first->IsSystemDeletable())
p.first.reset();
else if (actor)
p.first->SetGlobalOrientAndTrans(actor->GetTransform());
p.first->Update(dt);
2018-12-13 07:39:16 +00:00
effectActive = true;
sfxActive = true;
2018-12-08 01:49:15 +00:00
}
2018-12-08 05:30:43 +00:00
}
} else {
2018-12-13 07:39:16 +00:00
effectActive = true;
2018-12-08 01:49:15 +00:00
}
2018-12-08 05:30:43 +00:00
}
if (x74_sfx) {
2018-12-13 07:39:16 +00:00
if (sfxActive) {
CSfxManager::UpdateEmitter(x74_sfx, xf8_iceXf.origin, zeus::skZero3f, 1.f);
2018-12-08 05:30:43 +00:00
} else {
CSfxManager::RemoveEmitter(x74_sfx);
x74_sfx.reset();
2018-12-08 01:49:15 +00:00
}
2018-12-08 05:30:43 +00:00
}
2018-12-13 07:39:16 +00:00
if (!effectActive)
2018-12-08 05:30:43 +00:00
Unlock(EDependency::OnFire);
2018-12-13 07:39:16 +00:00
return effectActive;
2018-12-08 01:49:15 +00:00
}
2018-12-13 07:39:16 +00:00
bool CActorModelParticles::CItem::UpdateAshGen(float dt, CActor* actor, CStateManager& mgr) {
if (x78_ashGen) {
if (x84_ashMaxParticles == 0 && x78_ashGen->IsSystemDeletable()) {
x78_ashGen.reset();
} else {
if (actor)
x78_ashGen->SetGlobalOrientAndTrans(actor->GetTransform());
x78_ashGen->Update(dt);
return true;
}
} else if (x134_lockDeps & 0x4 && actor) {
if (x128_parent.xe6_loadedDeps & 0x4) {
x78_ashGen = x128_parent.MakeAshGen();
x80_ashPointIterator = 0;
x78_ashGen->SetGlobalOrientAndTrans(actor->GetTransform());
x84_ashMaxParticles = s32((IsMediumOrLarge(*actor) ? 1.f : 0.3f) * x78_ashGen->GetMaxParticles());
x88_ashSeed = mgr.GetActiveRandom()->Next();
}
return true;
}
Unlock(EDependency::Ash);
return false;
}
2018-12-08 01:49:15 +00:00
2018-12-13 07:39:16 +00:00
bool CActorModelParticles::CItem::UpdateIceGen(float dt, CActor* actor, CStateManager& mgr) {
if (xb0_icePointIterator != -1)
return true;
if (!x8c_iceGens.empty()) {
bool active = false;
for (auto& p : x8c_iceGens) {
if (!p->IsSystemDeletable())
active = true;
p->Update(dt);
}
if (!active)
x8c_iceGens.clear();
else
return true;
} else if (x134_lockDeps & 0x2 && actor) {
if (x128_parent.xe6_loadedDeps & 0x2) {
xb0_icePointIterator = 0;
xb4_iceSeed = mgr.GetActiveRandom()->Next();
}
return true;
}
Unlock(EDependency::Ice);
return false;
}
2018-12-08 01:49:15 +00:00
2018-12-13 07:39:16 +00:00
bool CActorModelParticles::CItem::UpdateFirePop(float dt, CActor* actor, CStateManager& mgr) {
if (xb8_firePopGen) {
if (xb8_firePopGen->IsSystemDeletable()) {
xb8_firePopGen.reset();
} else {
xb8_firePopGen->Update(dt);
return true;
}
} else if (x134_lockDeps & 0x8 && actor) {
if (x128_parent.xe6_loadedDeps & 0x8) {
xb8_firePopGen = x128_parent.MakeFirePopGen();
xb8_firePopGen->SetGlobalOrientation(actor->GetTransform());
xb8_firePopGen->SetGlobalTranslation(actor->GetRenderBounds().center());
}
return true;
}
Unlock(EDependency::FirePop);
return false;
}
2018-12-08 01:49:15 +00:00
2018-12-13 07:39:16 +00:00
bool CActorModelParticles::CItem::UpdateElectric(float dt, CActor* actor, CStateManager& mgr) {
if (xc0_electricGen) {
if (xc0_electricGen->IsSystemDeletable()) {
xc0_electricGen.reset();
} else {
if (actor && actor->GetActive()) {
xc0_electricGen->SetGlobalOrientation(actor->GetTransform().getRotation());
xc0_electricGen->SetGlobalTranslation(actor->GetTranslation());
}
if (!actor || actor->GetActive()) {
xc0_electricGen->SetModulationColor(xd0_electricColor);
xc0_electricGen->Update(dt);
return true;
}
}
} else if (x134_lockDeps & 0x10) {
if (x128_parent.xe6_loadedDeps & 0x10) {
xc0_electricGen = x128_parent.MakeElectricGen();
xc0_electricGen->SetModulationColor(xd0_electricColor);
xc8_electricPointIterator = 0;
xcc_electricSeed = mgr.GetActiveRandom()->Next();
}
return true;
}
Unlock(EDependency::Electric);
return false;
}
2018-12-08 01:49:15 +00:00
2018-12-13 07:39:16 +00:00
bool CActorModelParticles::CItem::UpdateRainSplash(float dt, CActor* actor, CStateManager& mgr) {
if (xd4_rainSplashGen) {
if (!xd4_rainSplashGen->IsRaining()) {
xd4_rainSplashGen.reset();
} else {
xd4_rainSplashGen->Update(dt, mgr);
return true;
}
}
return false;
}
2017-03-26 05:53:04 +00:00
2018-12-13 07:39:16 +00:00
bool CActorModelParticles::CItem::UpdateBurn(float dt, CActor* actor, CStateManager& mgr) {
if (!actor)
xdc_ashy.Unlock();
return xdc_ashy.IsLocked();
}
2018-12-08 01:49:15 +00:00
2018-12-13 07:39:16 +00:00
bool CActorModelParticles::CItem::UpdateIcePop(float dt, CActor* actor, CStateManager& mgr) {
if (xe4_icePopGen) {
if (xe4_icePopGen->IsSystemDeletable()) {
xe4_icePopGen.reset();
} else {
xe4_icePopGen->Update(dt);
return true;
}
} else if (x134_lockDeps & 0x20 && actor) {
if (x128_parent.xe6_loadedDeps & 0x20) {
xe4_icePopGen = x128_parent.MakeIcePopGen();
xe4_icePopGen->SetGlobalOrientation(actor->GetTransform());
xe4_icePopGen->SetGlobalTranslation(actor->GetRenderBounds().center());
}
return true;
}
Unlock(EDependency::IcePop);
return false;
}
2017-03-26 05:53:04 +00:00
2018-12-08 05:30:43 +00:00
bool CActorModelParticles::CItem::Update(float dt, CStateManager& mgr) {
CActor* act = static_cast<CActor*>(mgr.ObjectById(x0_id));
if (act && act->HasModelData() && !act->GetModelData()->IsNull()) {
xec_particleOffsetScale = act->GetModelData()->GetScale();
2018-12-13 07:39:16 +00:00
xf8_iceXf = act->GetTransform();
2018-12-08 05:30:43 +00:00
x4_areaId = act->GetAreaIdAlways();
} else {
x0_id = kInvalidUniqueId;
2018-12-13 07:39:16 +00:00
x84_ashMaxParticles = 0;
xb0_icePointIterator = -1;
if (xc0_electricGen)
xc0_electricGen->SetParticleEmission(false);
2018-12-08 05:30:43 +00:00
if (x74_sfx) {
CSfxManager::RemoveEmitter(x74_sfx);
x74_sfx.reset();
2018-12-08 01:49:15 +00:00
}
2018-12-13 07:39:16 +00:00
x130_remTime -= dt;
if (x130_remTime <= 0.f)
2018-12-08 05:30:43 +00:00
return false;
}
bool ret = false;
if (UpdateOnFire(dt, act, mgr))
ret = true;
2018-12-13 07:39:16 +00:00
if (UpdateAshGen(dt, act, mgr))
2018-12-08 05:30:43 +00:00
ret = true;
2018-12-13 07:39:16 +00:00
if (UpdateIceGen(dt, act, mgr))
2018-12-08 05:30:43 +00:00
ret = true;
if (UpdateFirePop(dt, act, mgr))
ret = true;
if (UpdateElectric(dt, act, mgr))
ret = true;
2018-12-13 07:39:16 +00:00
if (UpdateRainSplash(dt, act, mgr))
2018-12-08 05:30:43 +00:00
ret = true;
2018-12-13 07:39:16 +00:00
if (UpdateBurn(dt, act, mgr))
2018-12-08 05:30:43 +00:00
ret = true;
if (UpdateIcePop(dt, act, mgr))
ret = true;
return ret;
}
void CActorModelParticles::CItem::Lock(EDependency d) {
if (!(x134_lockDeps & (1 << int(d)))) {
x128_parent.IncrementDependency(d);
x134_lockDeps |= (1 << int(d));
}
}
void CActorModelParticles::CItem::Unlock(EDependency d) {
if (x134_lockDeps & (1 << int(d))) {
x128_parent.DecrementDependency(d);
x134_lockDeps &= ~(1 << int(d));
}
}
void CActorModelParticles::DecrementDependency(EDependency d) {
Dependency& dep = x50_dgrps[int(d)];
dep.Decrement();
if (dep.x10_refCount == 0) {
2018-12-13 07:39:16 +00:00
xe4_loadingDeps &= ~(1 << int(d));
xe6_loadedDeps &= ~(1 << int(d));
xe5_justLoadedDeps &= ~(1 << int(d));
2018-12-08 05:30:43 +00:00
}
}
void CActorModelParticles::IncrementDependency(EDependency d) {
x50_dgrps[int(d)].Increment();
2018-12-13 07:39:16 +00:00
if (!(xe6_loadedDeps & (1 << int(d))))
xe4_loadingDeps |= (1 << int(d));
2018-12-08 05:30:43 +00:00
}
CActorModelParticles::Dependency CActorModelParticles::GetParticleDGRPTokens(std::string_view name) const {
2018-12-08 05:30:43 +00:00
Dependency ret = {};
TToken<CDependencyGroup> dgrp = g_SimplePool->GetObj(name);
const auto& vector = dgrp->GetObjectTagVector();
ret.x0_tokens.reserve(vector.size());
for (const SObjectTag& tag : vector) {
2018-12-08 05:30:43 +00:00
ret.x0_tokens.push_back(g_SimplePool->GetObj(tag));
}
2018-12-08 05:30:43 +00:00
return ret;
}
2018-12-08 05:30:43 +00:00
void CActorModelParticles::LoadParticleDGRPs() {
static constexpr std::array particleDGRPs{
"Effect_OnFire_DGRP"sv, "Effect_IceBreak_DGRP"sv, "Effect_Ash_DGRP"sv,
"Effect_FirePop_DGRP"sv, "Effect_Electric_DGRP"sv, "Effect_IcePop_DGRP"sv,
};
for (const auto& dgrp : particleDGRPs) {
x50_dgrps.push_back(GetParticleDGRPTokens(dgrp));
}
}
2018-12-08 05:30:43 +00:00
std::unique_ptr<CElementGen> CActorModelParticles::MakeOnFireGen() const {
return std::make_unique<CElementGen>(x18_onFire);
}
2021-06-07 19:29:18 +00:00
std::unique_ptr<CElementGen> CActorModelParticles::MakeAshGen() const { return std::make_unique<CElementGen>(x20_ash); }
2018-12-08 05:30:43 +00:00
std::unique_ptr<CElementGen> CActorModelParticles::MakeIceGen() const {
return std::make_unique<CElementGen>(x28_iceBreak);
}
2018-12-08 05:30:43 +00:00
std::unique_ptr<CElementGen> CActorModelParticles::MakeFirePopGen() const {
return std::make_unique<CElementGen>(x30_firePop);
}
2018-12-08 05:30:43 +00:00
std::unique_ptr<CElementGen> CActorModelParticles::MakeIcePopGen() const {
return std::make_unique<CElementGen>(x38_icePop);
}
2018-12-08 05:30:43 +00:00
std::unique_ptr<CParticleElectric> CActorModelParticles::MakeElectricGen() const {
return std::make_unique<CParticleElectric>(x40_electric);
}
2018-12-08 05:30:43 +00:00
CActorModelParticles::CActorModelParticles() {
x18_onFire = g_SimplePool->GetObj("Effect_OnFire");
x20_ash = g_SimplePool->GetObj("Effect_Ash");
x28_iceBreak = g_SimplePool->GetObj("Effect_IceBreak");
x30_firePop = g_SimplePool->GetObj("Effect_FirePop");
x38_icePop = g_SimplePool->GetObj("Effect_IcePop");
x40_electric = g_SimplePool->GetObj("Effect_Electric");
x48_ashy = g_SimplePool->GetObj("TXTR_Ashy");
LoadParticleDGRPs();
}
2018-12-08 05:30:43 +00:00
void CActorModelParticles::AddStragglersToRenderer(const CStateManager& mgr) {
bool isNotCold = mgr.GetThermalDrawFlag() != EThermalDrawFlag::Cold;
bool isNotHot = mgr.GetThermalDrawFlag() != EThermalDrawFlag::Hot;
2018-12-08 05:30:43 +00:00
for (CItem& item : x0_items) {
if (item.x4_areaId != kInvalidAreaId) {
const CGameArea* area = mgr.GetWorld()->GetAreaAlways(item.x4_areaId);
if (!area->IsPostConstructed())
continue;
CGameArea::EOcclusionState occState = area->GetPostConstructed()->x10dc_occlusionState;
if (occState == CGameArea::EOcclusionState::Occluded)
continue;
}
if (mgr.GetObjectById(item.x0_id) &&
((isNotCold && item.x12c_24_thermalCold) || (isNotHot && item.x12c_25_thermalHot))) {
item.x12c_24_thermalCold = false;
item.x12c_25_thermalHot = false;
continue;
}
if (isNotCold) {
// Hot Draw
for (auto& entry : item.x8_onFireGens) {
std::unique_ptr<CElementGen>& gen = entry.first;
if (gen) {
2018-12-08 05:30:43 +00:00
g_Renderer->AddParticleGen(*gen);
}
2018-12-08 05:30:43 +00:00
}
2018-12-13 07:39:16 +00:00
if (mgr.GetThermalDrawFlag() != EThermalDrawFlag::Hot && item.x78_ashGen)
g_Renderer->AddParticleGen(*item.x78_ashGen);
if (item.xb8_firePopGen)
g_Renderer->AddParticleGen(*item.xb8_firePopGen);
if (item.xc0_electricGen)
g_Renderer->AddParticleGen(*item.xc0_electricGen);
}
2018-12-08 05:30:43 +00:00
if (isNotHot) {
/* Cold Draw */
2018-12-13 07:39:16 +00:00
for (std::unique_ptr<CElementGen>& gen : item.x8c_iceGens)
2018-12-08 05:30:43 +00:00
g_Renderer->AddParticleGen(*gen);
2018-12-13 07:39:16 +00:00
if (item.xe4_icePopGen)
g_Renderer->AddParticleGen(*item.xe4_icePopGen);
2018-12-08 05:30:43 +00:00
}
if (isNotCold) {
/* Thermal Reset */
item.x12c_24_thermalCold = false;
item.x12c_25_thermalHot = false;
}
}
}
2018-12-13 07:39:16 +00:00
void CActorModelParticles::UpdateLoad() {
if (!xe4_loadingDeps) {
return;
}
xe5_justLoadedDeps = 0;
for (size_t i = 0; i < x50_dgrps.size(); ++i) {
if ((xe4_loadingDeps & (1U << i)) != 0) {
x50_dgrps[i].UpdateLoad();
if (x50_dgrps[i].x14_loaded) {
xe5_justLoadedDeps |= (1U << i);
xe4_loadingDeps &= ~(1U << i);
2018-12-13 07:39:16 +00:00
}
}
}
xe6_loadedDeps |= xe5_justLoadedDeps;
2018-12-13 07:39:16 +00:00
}
void CActorModelParticles::Update(float dt, CStateManager& mgr) {
UpdateLoad();
for (auto it = x0_items.begin(); it != x0_items.end();) {
if (!it->Update(dt, mgr)) {
if (CActor* act = static_cast<CActor*>(mgr.ObjectById(it->x0_id)))
act->SetPointGeneratorParticles(false);
it = x0_items.erase(it);
continue;
}
++it;
}
}
2017-03-24 05:30:16 +00:00
void CActorModelParticles::PointGenerator(void* ctx,
2018-12-08 05:30:43 +00:00
const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn) {
static_cast<CItem*>(ctx)->GeneratePoints(vn);
2017-03-26 05:53:04 +00:00
}
2018-12-08 05:30:43 +00:00
void CActorModelParticles::SetupHook(TUniqueId uid) {
const auto search = FindSystem(uid);
if (search == x0_items.cend()) {
return;
}
CSkinnedModel::SetPointGeneratorFunc(&*search, PointGenerator);
2017-03-26 05:53:04 +00:00
}
std::list<CActorModelParticles::CItem>::iterator CActorModelParticles::FindSystem(TUniqueId uid) {
return std::find_if(x0_items.begin(), x0_items.end(), [uid](const auto& entry) { return entry.x0_id == uid; });
}
2018-12-08 05:30:43 +00:00
std::list<CActorModelParticles::CItem>::const_iterator CActorModelParticles::FindSystem(TUniqueId uid) const {
return std::find_if(x0_items.begin(), x0_items.end(), [uid](const auto& entry) { return entry.x0_id == uid; });
2017-03-26 05:53:04 +00:00
}
2018-12-08 05:30:43 +00:00
std::list<CActorModelParticles::CItem>::iterator CActorModelParticles::FindOrCreateSystem(CActor& act) {
if (act.GetPointGeneratorParticles()) {
for (auto it = x0_items.begin(); it != x0_items.end(); ++it)
if (it->x0_id == act.GetUniqueId())
return it;
}
2018-05-14 04:38:58 +00:00
2018-12-08 05:30:43 +00:00
act.SetPointGeneratorParticles(true);
return x0_items.emplace(x0_items.end(), act, *this);
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
void CActorModelParticles::StartIce(CActor& act) {
auto iter = FindOrCreateSystem(act);
2018-12-13 07:39:16 +00:00
iter->Lock(EDependency::Ice);
2018-09-14 00:49:34 +00:00
}
2017-07-14 05:14:19 +00:00
2018-12-08 05:30:43 +00:00
void CActorModelParticles::StartElectric(CActor& act) {
auto iter = FindOrCreateSystem(act);
2018-12-13 07:39:16 +00:00
if (iter->xc0_electricGen && !iter->xc0_electricGen->GetParticleEmission())
iter->xc0_electricGen->SetParticleEmission(true);
2018-11-06 06:16:12 +00:00
}
2018-12-08 05:30:43 +00:00
void CActorModelParticles::StopElectric(CActor& act) {
if (act.GetPointGeneratorParticles()) {
auto iter = FindSystem(act.GetUniqueId());
2018-12-13 07:39:16 +00:00
if (iter != x0_items.cend() && iter->xc0_electricGen)
iter->xc0_electricGen->SetParticleEmission(false);
2018-12-08 05:30:43 +00:00
}
2017-07-14 05:14:19 +00:00
}
2018-12-13 07:39:16 +00:00
void CActorModelParticles::LoadAndStartElectric(CActor& act) {
2018-12-08 05:30:43 +00:00
auto iter = FindOrCreateSystem(act);
2018-12-13 07:39:16 +00:00
if (!iter->xc0_electricGen)
iter->Lock(EDependency::Electric);
2018-12-08 05:30:43 +00:00
else {
2018-12-13 07:39:16 +00:00
if (!iter->xc0_electricGen->GetParticleEmission())
iter->xc0_electricGen->SetParticleEmission(true);
2018-12-08 05:30:43 +00:00
}
2018-12-08 01:49:15 +00:00
}
2018-12-08 05:30:43 +00:00
void CActorModelParticles::StopThermalHotParticles(CActor& act) {
if (act.GetPointGeneratorParticles()) {
auto iter = FindSystem(act.GetUniqueId());
if (iter != x0_items.cend()) {
2018-12-13 07:39:16 +00:00
for (auto& part : iter->x8_onFireGens)
2018-12-08 05:30:43 +00:00
if (part.first)
part.first->SetParticleEmission(false);
2018-11-06 06:16:12 +00:00
}
2018-12-08 05:30:43 +00:00
}
2018-11-06 06:16:12 +00:00
}
2018-12-08 05:30:43 +00:00
void CActorModelParticles::StartBurnDeath(CActor& act) {
auto iter = FindOrCreateSystem(act);
u16 sfx = SFXeff_x_smallburndeath_lp_00 - s16(IsMediumOrLarge(act));
CSfxManager::AddEmitter(sfx, act.GetTranslation(), zeus::skZero3f, true, false, 0x7f, kInvalidAreaId);
2018-12-08 05:30:43 +00:00
iter->xdc_ashy.Lock();
2018-11-06 06:16:12 +00:00
}
2018-12-08 05:30:43 +00:00
void CActorModelParticles::EnsureElectricLoaded(CActor& act) {
auto iter = FindOrCreateSystem(act);
2018-12-13 07:39:16 +00:00
iter->Lock(EDependency::IcePop);
2018-11-06 06:16:12 +00:00
}
2018-12-08 05:30:43 +00:00
void CActorModelParticles::EnsureFirePopLoaded(CActor& act) {
auto iter = FindOrCreateSystem(act);
iter->Lock(EDependency::FirePop);
2018-11-06 06:16:12 +00:00
}
2018-12-08 05:30:43 +00:00
void CActorModelParticles::EnsureIceBreakLoaded(CActor& act) {
auto iter = FindOrCreateSystem(act);
2018-12-13 07:39:16 +00:00
iter->Lock(EDependency::Ash);
2018-11-06 06:16:12 +00:00
}
2018-12-08 05:30:43 +00:00
void CActorModelParticles::LightDudeOnFire(CActor& act) {
auto iter = FindOrCreateSystem(act);
iter->Lock(EDependency::OnFire);
if (iter->x6c_onFireDelayTimer <= 0.f)
iter->x70_onFire = true;
2018-11-08 00:53:38 +00:00
}
2018-12-08 05:30:43 +00:00
const CTexture* CActorModelParticles::GetAshyTexture(const CActor& act) {
auto iter = FindSystem(act.GetUniqueId());
if (iter != x0_items.cend() && iter->xdc_ashy && iter->xdc_ashy.IsLoaded()) {
iter->xdc_ashy->GetBooTexture()->setClampMode(boo::TextureClampMode::ClampToEdge);
return iter->xdc_ashy.GetObj();
}
return nullptr;
2018-11-06 06:16:12 +00:00
}
2018-12-08 05:30:43 +00:00
void CActorModelParticles::AddRainSplashGenerator(CActor& act, CStateManager& mgr, u32 maxSplashes, u32 genRate,
float minZ) {
auto it = FindOrCreateSystem(act);
2018-12-13 07:39:16 +00:00
if (it->xd4_rainSplashGen)
2018-12-08 05:30:43 +00:00
return;
2018-05-14 04:38:58 +00:00
2018-12-08 05:30:43 +00:00
if (act.GetModelData() && !act.GetModelData()->IsNull())
2018-12-13 07:39:16 +00:00
it->xd4_rainSplashGen =
2018-12-08 05:30:43 +00:00
std::make_unique<CRainSplashGenerator>(act.GetModelData()->GetScale(), maxSplashes, genRate, minZ, 0.1875f);
2018-05-14 04:38:58 +00:00
}
2018-12-08 05:30:43 +00:00
void CActorModelParticles::RemoveRainSplashGenerator(CActor& act) {
auto it = FindOrCreateSystem(act);
2018-12-13 07:39:16 +00:00
it->xd4_rainSplashGen.reset();
2018-05-14 04:38:58 +00:00
}
2018-12-13 07:39:16 +00:00
void CActorModelParticles::Render(const CStateManager& mgr, const CActor& actor) const {
zeus::CTransform backupModel = CGraphics::g_GXModelMatrix;
auto search = FindSystem(actor.GetUniqueId());
if (search == x0_items.end())
return;
if (search->x4_areaId != kInvalidAreaId) {
const CGameArea* area = mgr.GetWorld()->GetAreaAlways(search->x4_areaId);
if (!area->IsPostConstructed())
return;
if (area->GetOcclusionState() == CGameArea::EOcclusionState::Occluded)
return;
}
if (mgr.GetThermalDrawFlag() != EThermalDrawFlag::Cold) {
for (const auto& gen : search->x8_onFireGens)
2019-01-05 08:34:09 +00:00
if (gen.first)
gen.first->Render();
2018-12-13 07:39:16 +00:00
if (mgr.GetThermalDrawFlag() != EThermalDrawFlag::Hot && search->x78_ashGen)
search->x78_ashGen->Render();
if (search->xb8_firePopGen)
search->xb8_firePopGen->Render();
if (search->xc0_electricGen)
search->xc0_electricGen->Render();
search->x134_lockDeps |= 0x80;
}
if (mgr.GetThermalDrawFlag() != EThermalDrawFlag::Hot) {
for (const auto& gen : search->x8c_iceGens)
gen->Render();
if (search->xd4_rainSplashGen && actor.GetModelData() && !actor.GetModelData()->IsNull())
search->xd4_rainSplashGen->Draw(actor.GetTransform());
if (search->xe4_icePopGen)
search->xe4_icePopGen->Render();
search->x134_lockDeps |= 0x40;
}
CGraphics::SetModelMatrix(backupModel);
}
2018-02-05 06:56:09 +00:00
2021-04-10 08:42:06 +00:00
} // namespace metaforce