mirror of https://github.com/AxioDL/metaforce.git
initial flamethrower weapon implementation
This commit is contained in:
parent
a2dfd58356
commit
cf86338a84
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
namespace urde {
|
namespace urde {
|
||||||
class CCollisionInfo {
|
class CCollisionInfo {
|
||||||
|
friend class CCollisionInfoList;
|
||||||
|
|
||||||
zeus::CVector3f x0_point;
|
zeus::CVector3f x0_point;
|
||||||
zeus::CVector3f xc_extentX;
|
zeus::CVector3f xc_extentX;
|
||||||
zeus::CVector3f x18_extentY;
|
zeus::CVector3f x18_extentY;
|
||||||
|
|
|
@ -58,5 +58,35 @@ public:
|
||||||
auto end() const noexcept { return x0_list.end(); }
|
auto end() const noexcept { return x0_list.end(); }
|
||||||
auto begin() noexcept { return x0_list.begin(); }
|
auto begin() noexcept { return x0_list.begin(); }
|
||||||
auto begin() const noexcept { return x0_list.begin(); }
|
auto begin() const noexcept { return x0_list.begin(); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AccumulateNewContactsInto(CCollisionInfoList& other_list) {
|
||||||
|
for (CCollisionInfo const& cur_info : x0_list) {
|
||||||
|
bool dont_add_new_info = false;
|
||||||
|
for (CCollisionInfo& other_info : other_list) {
|
||||||
|
if (!zeus::close_enough(other_info.GetPoint(), cur_info.GetPoint(), 0.1f)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
zeus::CVector3f norm = other_info.GetNormalLeft().normalized();
|
||||||
|
if (zeus::close_enough(norm, cur_info.GetNormalLeft(), 1.2f)) {
|
||||||
|
dont_add_new_info = true;
|
||||||
|
other_info.x0_point = (other_info.x0_point + cur_info.x0_point) * 0.5f;
|
||||||
|
other_info.x38_materialLeft.Add(cur_info.x38_materialLeft);
|
||||||
|
other_info.x40_materialRight.Add(cur_info.x40_materialRight);
|
||||||
|
other_info.x48_normalLeft = other_info.x48_normalLeft + cur_info.x48_normalLeft;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!dont_add_new_info) {
|
||||||
|
other_list.Add(cur_info, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (CCollisionInfo& other_info : other_list.x0_list) {
|
||||||
|
other_info.x48_normalLeft.normalize();
|
||||||
|
other_info.x54_normalRight = -other_info.x48_normalLeft;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // namespace urde
|
} // namespace urde
|
||||||
|
|
|
@ -155,6 +155,7 @@ public:
|
||||||
|
|
||||||
CGenDescription* GetDesc() { return x1c_genDesc.GetObj(); }
|
CGenDescription* GetDesc() { return x1c_genDesc.GetObj(); }
|
||||||
const SObjectTag* GetDescTag() const { return x1c_genDesc.GetObjectTag(); }
|
const SObjectTag* GetDescTag() const { return x1c_genDesc.GetObjectTag(); }
|
||||||
|
CGenDescription* GetLoadedDesc() { return x28_loadedGenDesc; }
|
||||||
|
|
||||||
static bool g_ParticleSystemInitialized;
|
static bool g_ParticleSystemInitialized;
|
||||||
static int g_ParticleAliveCount;
|
static int g_ParticleAliveCount;
|
||||||
|
@ -224,6 +225,10 @@ public:
|
||||||
static void SetMoveRedToAlphaBuffer(bool move);
|
static void SetMoveRedToAlphaBuffer(bool move);
|
||||||
|
|
||||||
s32 GetMaxParticles() const { return x90_MAXP; }
|
s32 GetMaxParticles() const { return x90_MAXP; }
|
||||||
|
s32 GetMaxMaxParticles() const { return m_maxMAXP; }
|
||||||
|
|
||||||
|
std::vector<CParticle> const& GetParticles() const { return x30_particles; }
|
||||||
|
std::vector<CParticle> &GetParticles() { return x30_particles; }
|
||||||
};
|
};
|
||||||
ENABLE_BITWISE_ENUM(CElementGen::EOptionalSystemFlags)
|
ENABLE_BITWISE_ENUM(CElementGen::EOptionalSystemFlags)
|
||||||
|
|
||||||
|
|
|
@ -214,6 +214,10 @@ public:
|
||||||
translation += transInc;
|
translation += transInc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<SSwooshData> const& GetSwooshes() const { return x15c_swooshes; }
|
||||||
|
std::vector<SSwooshData>& GetSwooshes() { return x15c_swooshes; }
|
||||||
|
u32 GetCurParticle() const { return x158_curParticle; }
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace urde
|
} // namespace urde
|
||||||
|
|
|
@ -49,8 +49,11 @@ void CUVEAnimTexture::GetValueUV(int frame, SUVElementSet& valOut) const {
|
||||||
|
|
||||||
int tile = int(cvf);
|
int tile = int(cvf);
|
||||||
if (x24_loop) {
|
if (x24_loop) {
|
||||||
if (cvf >= float(x20_tiles)) {
|
// HACK
|
||||||
tile = int(cvf) % x20_tiles;
|
// Check bad values for cvf
|
||||||
|
tile = !(std::isnan(cvf) || std::isinf(cvf)) && int(cvf) >= 0 ? int(cvf) : 0;
|
||||||
|
if (tile >= x20_tiles) {
|
||||||
|
tile = tile % x20_tiles;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cvf >= float(x20_tiles)) {
|
if (cvf >= float(x20_tiles)) {
|
||||||
|
|
|
@ -2,10 +2,29 @@
|
||||||
|
|
||||||
#include "Runtime/CSimplePool.hpp"
|
#include "Runtime/CSimplePool.hpp"
|
||||||
#include "Runtime/CStateManager.hpp"
|
#include "Runtime/CStateManager.hpp"
|
||||||
|
#include "Runtime/Collision/CCollisionInfoList.hpp"
|
||||||
#include "Runtime/GameGlobalObjects.hpp"
|
#include "Runtime/GameGlobalObjects.hpp"
|
||||||
|
#include "Runtime/World/CGameArea.hpp"
|
||||||
#include "Runtime/World/CGameLight.hpp"
|
#include "Runtime/World/CGameLight.hpp"
|
||||||
|
#include "Runtime/World/CPlayer.hpp"
|
||||||
|
#include "Runtime/World/CWorld.hpp"
|
||||||
|
#include "TCastTo.hpp"
|
||||||
|
#include "Runtime/Collision/CCollisionPrimitive.hpp"
|
||||||
|
|
||||||
|
#include "Runtime/World/CPatterned.hpp"
|
||||||
|
#include "Runtime/MP1/World/CFlickerBat.hpp"
|
||||||
|
#include "Runtime/World/CSnakeWeedSwarm.hpp"
|
||||||
|
#include "Runtime/Collision/CMetroidAreaCollider.hpp"
|
||||||
|
#include "Runtime/Collision/CGameCollision.hpp"
|
||||||
|
#include "Runtime/Particle/CParticleGlobals.hpp"
|
||||||
|
#include "Runtime/World/CScriptTrigger.hpp"
|
||||||
|
#include "Runtime/Graphics/CBooRenderer.hpp"
|
||||||
|
|
||||||
namespace urde {
|
namespace urde {
|
||||||
|
namespace {
|
||||||
|
constexpr CMaterialFilter skExcludeProjectilePassthrough =
|
||||||
|
CMaterialFilter::MakeExclude(EMaterialTypes::ProjectilePassthrough);
|
||||||
|
}
|
||||||
|
|
||||||
CNewFlameThrower::CNewFlameThrower(const TToken<CWeaponDescription>& desc, std::string_view name, EWeaponType wType,
|
CNewFlameThrower::CNewFlameThrower(const TToken<CWeaponDescription>& desc, std::string_view name, EWeaponType wType,
|
||||||
const std::array<CAssetId, 8>& resInfo, const zeus::CTransform& xf,
|
const std::array<CAssetId, 8>& resInfo, const zeus::CTransform& xf,
|
||||||
|
@ -27,22 +46,60 @@ CNewFlameThrower::CNewFlameThrower(const TToken<CWeaponDescription>& desc, std::
|
||||||
x334_secondarySparks.GetObj();
|
x334_secondarySparks.GetObj();
|
||||||
x340_swooshCenter.GetObj();
|
x340_swooshCenter.GetObj();
|
||||||
x34c_swooshFire.GetObj();
|
x34c_swooshFire.GetObj();
|
||||||
x380_.resize(3);
|
x380_flameContactPoints.resize(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNewFlameThrower::Think(float dt, CStateManager& mgr) {
|
||||||
|
CWeapon::Think(dt, mgr);
|
||||||
|
|
||||||
|
TAreaId cur_area_id = mgr.GetWorld()->GetCurrentAreaId();
|
||||||
|
mgr.SetActorAreaId(*this, cur_area_id);
|
||||||
|
|
||||||
|
for (TUniqueId& light_id : x3b8_lightIds) {
|
||||||
|
CEntity* light = mgr.ObjectById(light_id);
|
||||||
|
if (light == nullptr) {
|
||||||
|
light_id = kInvalidUniqueId;
|
||||||
|
} else {
|
||||||
|
mgr.SetActorAreaId(*reinterpret_cast<CActor*>(light), cur_area_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNewFlameThrower::Accept(IVisitor& visitor) { visitor.Visit(this); }
|
||||||
|
|
||||||
|
void CNewFlameThrower::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager& mgr) {
|
||||||
|
if (msg == EScriptObjectMessage::Deleted) {
|
||||||
|
mgr.RemoveWeaponId(GetOwnerId(), GetType());
|
||||||
|
DeleteLightObjects(mgr);
|
||||||
|
SetWorldLighting(mgr, mgr.GetPlayer().GetAreaIdAlways(), 4.f, 1.f);
|
||||||
|
} else if (msg == EScriptObjectMessage::Registered) {
|
||||||
|
xe6_27_thermalVisorFlags = 2; // Thermal hot
|
||||||
|
Think(1.f / 60.f, mgr);
|
||||||
|
mgr.AddWeaponId(xec_ownerId, xf0_weaponType);
|
||||||
|
}
|
||||||
|
|
||||||
|
CGameProjectile::AcceptScriptMsg(msg, uid, mgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNewFlameThrower::DeleteLightObjects(CStateManager& mgr) {
|
void CNewFlameThrower::DeleteLightObjects(CStateManager& mgr) {
|
||||||
for (TUniqueId id : x3b8_lightIds)
|
for (TUniqueId const& id : x3b8_lightIds) {
|
||||||
mgr.FreeScriptObject(id);
|
mgr.FreeScriptObject(id);
|
||||||
|
}
|
||||||
x3b8_lightIds.clear();
|
x3b8_lightIds.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CNewFlameThrower::AddToRenderer(zeus::CFrustum const& planes, CStateManager& mgr) {
|
||||||
|
zeus::CAABox sorting_bounds = GetSortingBounds(mgr);
|
||||||
|
EnsureRendered(mgr, x34_transform.origin, sorting_bounds);
|
||||||
|
}
|
||||||
|
|
||||||
void CNewFlameThrower::CreateLightObjects(CStateManager& mgr) {
|
void CNewFlameThrower::CreateLightObjects(CStateManager& mgr) {
|
||||||
DeleteLightObjects(mgr);
|
DeleteLightObjects(mgr);
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 4; ++i) {
|
||||||
TUniqueId uid = mgr.AllocateUniqueId();
|
TUniqueId uid = mgr.AllocateUniqueId();
|
||||||
CLight lObj = x358_mainFireGen->GetLight();
|
CLight lObj = x358_mainFireGen->GetLight();
|
||||||
CGameLight* light = new CGameLight(uid, GetAreaId(), false, "FlamethrowerLight", zeus::CTransform(),
|
CGameLight* light = new CGameLight(uid, GetAreaId(), false, "FlamethrowerLight", zeus::CTransform(), x8_uid, lObj,
|
||||||
x8_uid, lObj, u32(reinterpret_cast<uintptr_t>(this) + (i & 0x1)), 0, 0.f);
|
u32(reinterpret_cast<uintptr_t>(this) + (i & 0x1)), 0, 0.f);
|
||||||
mgr.AddObject(light);
|
mgr.AddObject(light);
|
||||||
x3b8_lightIds.push_back(uid);
|
x3b8_lightIds.push_back(uid);
|
||||||
}
|
}
|
||||||
|
@ -67,7 +124,7 @@ void CNewFlameThrower::StartFiring(const zeus::CTransform& xf, CStateManager& mg
|
||||||
SetActive(true);
|
SetActive(true);
|
||||||
x37c_25_firing = true;
|
x37c_25_firing = true;
|
||||||
x37c_24_renderAuxEffects = true;
|
x37c_24_renderAuxEffects = true;
|
||||||
x374_ = 1;
|
x374_flameState = EFlameState::FireStart;
|
||||||
EnableFx(mgr);
|
EnableFx(mgr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,8 +140,663 @@ bool CNewFlameThrower::AreEffectsFinished() const {
|
||||||
return !(x368_secondarySparksGen && x368_secondarySparksGen->GetParticleCount() != 0);
|
return !(x368_secondarySparksGen && x368_secondarySparksGen->GetParticleCount() != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNewFlameThrower::UpdateFx(const zeus::CTransform& xf, float dt, CStateManager& mgr) {}
|
/* Used for old CNewFlameThrower::RenderParticles
|
||||||
|
|
||||||
void CNewFlameThrower::Reset(CStateManager& mgr, bool deactivate) {}
|
void CNewFlameThrower::LoadParticleGenQuads() {
|
||||||
|
if (!loaded_textures) {
|
||||||
|
beam_filters[0] = std::make_unique<CTexturedQuadFilter>(
|
||||||
|
EFilterType::Add, x358_mainFireGen->GetLoadedDesc()->x54_x40_TEXR->GetValueTexture(0));
|
||||||
|
beam_filters[1] = std::make_unique<CTexturedQuadFilter>(
|
||||||
|
EFilterType::Add, x35c_mainSmokeGen->GetLoadedDesc()->x54_x40_TEXR->GetValueTexture(0));
|
||||||
|
beam_filters[2] = std::make_unique<CTexturedQuadFilter>(
|
||||||
|
EFilterType::Add, x360_secondarySmokeGen->GetLoadedDesc()->x54_x40_TEXR->GetValueTexture(0));
|
||||||
|
beam_filters[3] = std::make_unique<CTexturedQuadFilter>(
|
||||||
|
EFilterType::Add, x364_secondaryFireGen->GetLoadedDesc()->x54_x40_TEXR->GetValueTexture(0));
|
||||||
|
beam_filters[4] = std::make_unique<CTexturedQuadFilter>(
|
||||||
|
EFilterType::Add, x368_secondarySparksGen->GetLoadedDesc()->x54_x40_TEXR->GetValueTexture(0));
|
||||||
|
loaded_textures = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void CNewFlameThrower::Render(CStateManager& mgr) {
|
||||||
|
if (x30_24_active) {
|
||||||
|
x36c_swooshCenterGen->Render();
|
||||||
|
x370_swooshFireGen->Render();
|
||||||
|
|
||||||
|
x368_secondarySparksGen->Render();
|
||||||
|
x364_secondaryFireGen->Render();
|
||||||
|
x360_secondarySmokeGen->Render();
|
||||||
|
x35c_mainSmokeGen->Render();
|
||||||
|
x358_mainFireGen->Render();
|
||||||
|
|
||||||
|
/*RenderBeam({x358_mainFireGen.get(), x35c_mainSmokeGen.get(), x360_secondarySmokeGen.get(),
|
||||||
|
x364_secondaryFireGen.get(), x368_secondarySparksGen.get()});*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Removed this, source function was painfully similar to CElementGen::RenderParticles
|
||||||
|
|
||||||
|
void CNewFlameThrower::RenderParticles(std::array<CElementGen*, 5> const& elem_gens) {
|
||||||
|
LoadParticleGenQuads();
|
||||||
|
zeus::CTransform xf(CGraphics::g_ViewMatrix);
|
||||||
|
zeus::CTransform xf2 = xf;
|
||||||
|
xf2.origin = zeus::skZero3f;
|
||||||
|
zeus::CTransform xf3 = xf2.inverse();
|
||||||
|
zeus::CTransform xf4 = xf3;
|
||||||
|
// CGraphics::SetModelMatrix(xf2);
|
||||||
|
// CGraphics::SetCullMode(ERglCullMode::None);
|
||||||
|
// CGraphics::SetDepthWriteMode(true, ERglEnum::LEqual, false);
|
||||||
|
// CGraphics::SetAlphaCompare(ERglAlphaFunc::Always, 0, ERglAlphaOp::And, ERglAlphaFunc::Always, 0);
|
||||||
|
|
||||||
|
// TODO: check sMoveRedToAlphaBuffer
|
||||||
|
|
||||||
|
// CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::One, ERglBlendFactor::One, ERglLogicOp::Clear);
|
||||||
|
int total_particles = 0;
|
||||||
|
for (CElementGen* elem : elem_gens) {
|
||||||
|
total_particles += elem->GetParticleCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is... something isn't it
|
||||||
|
struct ParticleElement {
|
||||||
|
u16 elem_gen_idx;
|
||||||
|
u16 part_idx;
|
||||||
|
zeus::CVector3f vec;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto* translated_sorted_particles =
|
||||||
|
reinterpret_cast<ParticleElement*>(_alloca(sizeof(ParticleElement) * total_particles));
|
||||||
|
int active_particle_count = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < elem_gens.size(); i++) {
|
||||||
|
CElementGen* elem = elem_gens[i];
|
||||||
|
|
||||||
|
int iter_count = elem->GetParticleCount();
|
||||||
|
for (int j = 0; j < iter_count; j++) {
|
||||||
|
CParticle& part = elem->GetParticles()[j];
|
||||||
|
if (part.x0_endFrame == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ????
|
||||||
|
// translated_sorted_particles[part_idx].vec = xf4 * part.x4_pos;
|
||||||
|
translated_sorted_particles[active_particle_count].vec =
|
||||||
|
xf4 * (((part.x4_pos - part.x10_prevPos) * elem->GetTimeDeltaScale()) + part.x10_prevPos);
|
||||||
|
translated_sorted_particles[active_particle_count].elem_gen_idx = static_cast<u16>(i);
|
||||||
|
translated_sorted_particles[active_particle_count].part_idx = static_cast<u16>(j);
|
||||||
|
|
||||||
|
active_particle_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.report(logvisor::Info, FMT_STRING("Active particle count (render count) {}"), active_particle_count);
|
||||||
|
std::sort(translated_sorted_particles, translated_sorted_particles + active_particle_count,
|
||||||
|
[](ParticleElement const& l, ParticleElement const& r) { return l.vec.y() > r.vec.y(); });
|
||||||
|
|
||||||
|
int last_gen_idx = 0xffff;
|
||||||
|
CElementGen* cur_gen = nullptr;
|
||||||
|
CGenDescription* gen_desc = nullptr;
|
||||||
|
u32 emitter_time = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < active_particle_count; i++) {
|
||||||
|
ParticleElement* pe = translated_sorted_particles + i;
|
||||||
|
if (pe->elem_gen_idx != last_gen_idx) {
|
||||||
|
cur_gen = elem_gens[pe->elem_gen_idx];
|
||||||
|
|
||||||
|
emitter_time = cur_gen->GetEmitterTime();
|
||||||
|
gen_desc = cur_gen->GetLoadedDesc();
|
||||||
|
if (CElementGen::sMoveRedToAlphaBuffer) {
|
||||||
|
// TEV stuff
|
||||||
|
} else {
|
||||||
|
if (gen_desc->x44_26_x30_26_AAPH) {
|
||||||
|
// CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::One,
|
||||||
|
// ERglLogicOp::Clear);
|
||||||
|
} else {
|
||||||
|
// CGraphics::SetBlendMode(ERglBlendMode::Blend, ERglBlendFactor::SrcAlpha, ERglBlendFactor::InvSrcAlpha,
|
||||||
|
// ERglLogicOp::Clear);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// more TEV stuff
|
||||||
|
last_gen_idx = pe->elem_gen_idx;
|
||||||
|
}
|
||||||
|
CParticle& part = cur_gen->GetParticles()[pe->part_idx];
|
||||||
|
|
||||||
|
u32 elapsed_time = emitter_time - part.x28_startFrame - 1;
|
||||||
|
CParticleGlobals::instance()->SetParticleLifetime(part.x0_endFrame - part.x28_startFrame);
|
||||||
|
CParticleGlobals::instance()->UpdateParticleLifetimeTweenValues(elapsed_time);
|
||||||
|
SUVElementSet uvs;
|
||||||
|
|
||||||
|
xf3 = xf2.inverse();
|
||||||
|
zeus::CTransform system_camera_matrix = xf3 * cur_gen->x22c_globalOrientation;
|
||||||
|
xf3 = ((zeus::CTransform::Translate(cur_gen->xe8_globalTranslation) * cur_gen->x10c_globalScaleTransform) * xf3) *
|
||||||
|
cur_gen->x178_localScaleTransform;
|
||||||
|
g_Renderer->SetModelMatrix(xf3);
|
||||||
|
|
||||||
|
gen_desc->x54_x40_TEXR->GetValueUV(elapsed_time, uvs);
|
||||||
|
float ang = zeus::degToRad(part.x30_lineWidthOrRota);
|
||||||
|
float size = part.x2c_lineLengthOrSize * 0.5f;
|
||||||
|
float sin_extent = sinf(ang) * size;
|
||||||
|
float cos_extent = cosf(ang) * size;
|
||||||
|
std::array<CTexturedQuadFilter::Vert, 4> vertices;
|
||||||
|
zeus::CVector3f simd_vec(sin_extent + cos_extent, 0, cos_extent - sin_extent);
|
||||||
|
vertices[0].m_pos = pe->vec + zeus::CVector3f(sin_extent + cos_extent, 0, cos_extent - sin_extent);
|
||||||
|
vertices[0].m_uv = zeus::CVector2f(uvs.xMax, uvs.yMax);
|
||||||
|
|
||||||
|
vertices[1].m_pos = pe->vec - zeus::CVector3f(sin_extent - cos_extent, 0, sin_extent + cos_extent);
|
||||||
|
vertices[1].m_uv = zeus::CVector2f(uvs.xMin, uvs.yMax);
|
||||||
|
|
||||||
|
vertices[2].m_pos = pe->vec - zeus::CVector3f(sin_extent + cos_extent, 0, cos_extent - sin_extent);
|
||||||
|
vertices[2].m_uv = zeus::CVector2f(uvs.xMin, uvs.yMin);
|
||||||
|
|
||||||
|
vertices[3].m_pos = pe->vec + zeus::CVector3f(sin_extent - cos_extent, 0, sin_extent + cos_extent);
|
||||||
|
vertices[3].m_uv = zeus::CVector2f(uvs.xMin, uvs.yMax);
|
||||||
|
|
||||||
|
beam_filters[pe->elem_gen_idx]->drawVerts(part.x34_color, vertices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void CNewFlameThrower::UpdateFx(const zeus::CTransform& xf, float dt, CStateManager& mgr) {
|
||||||
|
if (!x30_24_active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
float active_time =
|
||||||
|
0; // g_Main.x118_avgTickTimePerSec + g_Main.x11c_avgDrawTimePerSec; omitting this until handled by URDE
|
||||||
|
x37c_26_runningSlowish = (active_time > 0.65f);
|
||||||
|
UpdateFlameState(dt, mgr);
|
||||||
|
zeus::CVector3f org = xf.origin;
|
||||||
|
zeus::CTransform rot = xf.getRotation();
|
||||||
|
zeus::CTransform rot_copy(rot);
|
||||||
|
|
||||||
|
x358_mainFireGen->SetTranslation(org);
|
||||||
|
x358_mainFireGen->SetOrientation(rot_copy);
|
||||||
|
x36c_swooshCenterGen->SetTranslation(org);
|
||||||
|
x36c_swooshCenterGen->SetOrientation(rot_copy);
|
||||||
|
x370_swooshFireGen->SetTranslation(org);
|
||||||
|
x370_swooshFireGen->SetOrientation(rot_copy);
|
||||||
|
|
||||||
|
float particle_rate = (x37c_26_runningSlowish ? 1.f : 0.5f);
|
||||||
|
x358_mainFireGen->SetGeneratorRate(particle_rate);
|
||||||
|
x358_mainFireGen->Update(dt);
|
||||||
|
x35c_mainSmokeGen->Update(dt);
|
||||||
|
x360_secondarySmokeGen->Update(dt);
|
||||||
|
x364_secondaryFireGen->Update(dt);
|
||||||
|
x368_secondarySparksGen->Update(dt);
|
||||||
|
x36c_swooshCenterGen->Update(dt);
|
||||||
|
x370_swooshFireGen->Update(dt);
|
||||||
|
rstl::reserved_vector<Cube, 32> collision_list;
|
||||||
|
|
||||||
|
UpdateParticleCollisions(dt, mgr, collision_list);
|
||||||
|
if (collision_list.size() > 0) {
|
||||||
|
for (auto& swoosh : x36c_swooshCenterGen->GetSwooshes()) {
|
||||||
|
for (auto& cube : collision_list) {
|
||||||
|
float dpos = (cube.center - swoosh.xc_translation).magSquared();
|
||||||
|
if (dpos < (cube.bounds * cube.bounds)) {
|
||||||
|
swoosh.x0_active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& particle : x358_mainFireGen->GetParticles()) {
|
||||||
|
for (auto& cube : collision_list) {
|
||||||
|
float dpos = (cube.center - particle.x4_pos).magSquared();
|
||||||
|
if (dpos < (cube.bounds * cube.bounds)) {
|
||||||
|
particle.x0_endFrame = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto& particle : x35c_mainSmokeGen->GetParticles()) {
|
||||||
|
for (auto& cube : collision_list) {
|
||||||
|
float dpos = (cube.center - particle.x4_pos).magSquared();
|
||||||
|
if (dpos < (cube.bounds * cube.bounds)) {
|
||||||
|
particle.x0_endFrame = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (x374_flameState == EFlameState::FireActive) {
|
||||||
|
int free_space = x36c_swooshCenterGen->GetSwooshes().capacity() - x36c_swooshCenterGen->GetSwooshes().size();
|
||||||
|
if (free_space < 4) {
|
||||||
|
const int swoosh_count = static_cast<int>(x36c_swooshCenterGen->GetSwooshes().size());
|
||||||
|
int quarter_behind_cur = ((((swoosh_count / 2) * 3) / 2) + x36c_swooshCenterGen->GetCurParticle()) % swoosh_count;
|
||||||
|
if (x36c_swooshCenterGen->GetSwooshes()[quarter_behind_cur].x0_active) {
|
||||||
|
// Need better names here
|
||||||
|
int next_idx = (quarter_behind_cur + 1) % swoosh_count;
|
||||||
|
auto& swoosh_1 = x36c_swooshCenterGen->GetSwooshes()[quarter_behind_cur];
|
||||||
|
auto& swoosh_2 = x36c_swooshCenterGen->GetSwooshes()[next_idx];
|
||||||
|
zeus::CVector3f delta = swoosh_1.xc_translation - swoosh_2.xc_translation;
|
||||||
|
float f0 = delta.dot(swoosh_1.x38_orientation.frontVector());
|
||||||
|
zeus::CVector3f unk = delta - (swoosh_1.x38_orientation.frontVector() * f0);
|
||||||
|
float tmp = std::clamp(unk.magnitude() * 30.f, 1.f, x37c_26_runningSlowish ? 2.f : 4.f);
|
||||||
|
|
||||||
|
x3b4_numSmokeParticlesSpawned = std::max(static_cast<int>(round(tmp)), x3b4_numSmokeParticlesSpawned - 1);
|
||||||
|
// INSERT
|
||||||
|
if ((x35c_mainSmokeGen->GetParticles().size() + x3b4_numSmokeParticlesSpawned) >
|
||||||
|
x35c_mainSmokeGen->GetMaxMaxParticles()) {
|
||||||
|
x3b4_numSmokeParticlesSpawned = x3b4_numSmokeParticlesSpawned -
|
||||||
|
((x35c_mainSmokeGen->GetParticles().size() + x3b4_numSmokeParticlesSpawned) -
|
||||||
|
x35c_mainSmokeGen->GetMaxMaxParticles());
|
||||||
|
}
|
||||||
|
// END INSERT
|
||||||
|
// This limit shouldn't be needed, m_maxMAXP should be removed?
|
||||||
|
|
||||||
|
x35c_mainSmokeGen->SetTranslation(swoosh_1.xc_translation);
|
||||||
|
x35c_mainSmokeGen->SetOrientation(swoosh_1.x38_orientation);
|
||||||
|
if (x3b4_numSmokeParticlesSpawned > 0) {
|
||||||
|
x35c_mainSmokeGen->ForceParticleCreation(x3b4_numSmokeParticlesSpawned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UpdateLights(mgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: lights don't actually light
|
||||||
|
void CNewFlameThrower::UpdateLights(CStateManager& mgr) {
|
||||||
|
CGlobalRandom rand(x2e8_rand);
|
||||||
|
|
||||||
|
int lit_particle_step = std::max(2, static_cast<int>(x370_swooshFireGen->GetSwooshes().size() / 4));
|
||||||
|
int prev_particle = (x370_swooshFireGen->GetCurParticle() - 1) % x370_swooshFireGen->GetSwooshes().size();
|
||||||
|
|
||||||
|
int lit_particle_offset = 0;
|
||||||
|
const int fire_swoosh_count = static_cast<int>(x370_swooshFireGen->GetSwooshes().size());
|
||||||
|
for (auto& light_id : x3b8_lightIds) {
|
||||||
|
if (TCastToPtr<CGameLight> light = mgr.ObjectById(light_id)) {
|
||||||
|
bool should_light = true;
|
||||||
|
if (fire_swoosh_count <= lit_particle_offset) {
|
||||||
|
should_light = false;
|
||||||
|
}
|
||||||
|
auto& light_swoosh = x370_swooshFireGen->GetSwooshes()[(lit_particle_offset + prev_particle) % fire_swoosh_count];
|
||||||
|
if (!light_swoosh.x0_active) {
|
||||||
|
should_light = false;
|
||||||
|
}
|
||||||
|
light->SetActive(should_light);
|
||||||
|
if (!should_light) {
|
||||||
|
lit_particle_offset += lit_particle_step;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
CLight light_data = x358_mainFireGen->GetLight();
|
||||||
|
if (x304_mainFire.GetObj()->x104_xf0_LCLR.get()) {
|
||||||
|
s32 rand_int = x2e8_rand.Range(0, 16);
|
||||||
|
CParticleGlobals::instance()->SetEmitterTime(rand_int);
|
||||||
|
zeus::CColor out_color(0xffff00ff);
|
||||||
|
x304_mainFire.GetObj()->x104_xf0_LCLR->GetValue(rand_int, out_color);
|
||||||
|
light_data.SetColor(out_color);
|
||||||
|
}
|
||||||
|
if (x304_mainFire.GetObj()->x108_xf4_LINT.get()) {
|
||||||
|
s32 rand_int = x2e8_rand.Range(0, 16);
|
||||||
|
CParticleGlobals::instance()->SetEmitterTime(rand_int);
|
||||||
|
float out_const_attenuation = 1.f;
|
||||||
|
x304_mainFire.GetObj()->x108_xf4_LINT->GetValue(rand_int, out_const_attenuation);
|
||||||
|
light_data.SetAngleAttenuation(out_const_attenuation, 0.f, 0.f);
|
||||||
|
}
|
||||||
|
light->SetLight(light_data);
|
||||||
|
light->SetTranslation(light_swoosh.xc_translation);
|
||||||
|
lit_particle_offset += lit_particle_step;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNewFlameThrower::UpdateParticleCollisions(float dt, CStateManager& mgr,
|
||||||
|
rstl::reserved_vector<Cube, 32>& collisions_out) {
|
||||||
|
x300_wasPointAdded = false;
|
||||||
|
bool any_particle_collisions = false;
|
||||||
|
rstl::reserved_vector<TUniqueId, 1024> near_list_cache;
|
||||||
|
// rstl::reserved_vector<rstl::reserved_vector<, ?>, ?> unk_rstl_vec; // inner vectors of size 0x90c, never used
|
||||||
|
// though
|
||||||
|
CCollisionInfoList cached_cinfo;
|
||||||
|
auto& swoosh_vec = x370_swooshFireGen->GetSwooshes();
|
||||||
|
const int swoosh_count = static_cast<int>(swoosh_vec.size());
|
||||||
|
const int tmp = swoosh_count / 4;
|
||||||
|
const int batch_process_size = tmp < 6 ? 6 : tmp;
|
||||||
|
const int prev_particle = ((swoosh_count + x370_swooshFireGen->GetCurParticle()) - 1) % swoosh_count;
|
||||||
|
int i = 0;
|
||||||
|
while (i < swoosh_count) {
|
||||||
|
int batch_start = i;
|
||||||
|
int batch_end = i + batch_process_size;
|
||||||
|
if (batch_end >= swoosh_count) {
|
||||||
|
batch_end = swoosh_count;
|
||||||
|
}
|
||||||
|
float batch_highest_speed = 0.f;
|
||||||
|
bool processed_swoosh_in_batch = false;
|
||||||
|
zeus::CAABox batch_particle_bounds;
|
||||||
|
// Accumulate bounds of this batch and its max speed
|
||||||
|
for (int j = batch_start; j < batch_end; j++) {
|
||||||
|
if (!swoosh_vec[j].x0_active) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!processed_swoosh_in_batch) {
|
||||||
|
// Retro assigned MIN_FLOAT and MAX_FLOAT, but this should suffice
|
||||||
|
batch_particle_bounds = zeus::CAABox();
|
||||||
|
}
|
||||||
|
processed_swoosh_in_batch = true;
|
||||||
|
batch_particle_bounds.accumulateBounds(swoosh_vec[j].xc_translation);
|
||||||
|
float swoosh_speed_sq = swoosh_vec[j].x74_velocity.magSquared();
|
||||||
|
if (batch_highest_speed < swoosh_speed_sq) {
|
||||||
|
batch_highest_speed = swoosh_speed_sq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
batch_highest_speed = sqrtf(batch_highest_speed) + 0.1f;
|
||||||
|
batch_particle_bounds.accumulateBounds(batch_particle_bounds.min - zeus::CVector3f(batch_highest_speed));
|
||||||
|
batch_particle_bounds.accumulateBounds(batch_particle_bounds.max + zeus::CVector3f(batch_highest_speed));
|
||||||
|
|
||||||
|
near_list_cache.clear();
|
||||||
|
|
||||||
|
CMaterialFilter near_list_filter = CMaterialFilter::MakeIncludeExclude(
|
||||||
|
CMaterialList(EMaterialTypes::Solid), CMaterialList(EMaterialTypes::ProjectilePassthrough));
|
||||||
|
mgr.BuildNearList(near_list_cache, batch_particle_bounds, near_list_filter, mgr.Player());
|
||||||
|
CAreaCollisionCache coll_cache(batch_particle_bounds);
|
||||||
|
CGameCollision::BuildAreaCollisionCache(mgr, coll_cache);
|
||||||
|
|
||||||
|
for (int j = batch_start; j < batch_end; j++) {
|
||||||
|
if (j == prev_particle || !swoosh_vec[j].x0_active) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto& cur_swoosh = swoosh_vec[j];
|
||||||
|
|
||||||
|
CCollidableSphere coll_prim(zeus::CSphere(cur_swoosh.xc_translation, batch_highest_speed),
|
||||||
|
CMaterialList(EMaterialTypes::Solid));
|
||||||
|
CCollisionInfoList coll_info_out;
|
||||||
|
bool collided_static = CGameCollision::DetectStaticCollision_Cached(
|
||||||
|
mgr, coll_cache, coll_prim, zeus::CTransform(), skExcludeProjectilePassthrough, coll_info_out);
|
||||||
|
|
||||||
|
TUniqueId first_actor_hit = kInvalidUniqueId;
|
||||||
|
bool collided_other = FindCollisionInNearList(mgr, near_list_cache, coll_prim, first_actor_hit, coll_info_out);
|
||||||
|
|
||||||
|
if ((collided_static || collided_other) && coll_info_out.GetCount() > 0) {
|
||||||
|
cur_swoosh.x0_active = false;
|
||||||
|
any_particle_collisions = true;
|
||||||
|
cached_cinfo.Clear();
|
||||||
|
coll_info_out.AccumulateNewContactsInto(cached_cinfo);
|
||||||
|
int k = 0;
|
||||||
|
zeus::CVector3f last_added_pt = zeus::skZero3f;
|
||||||
|
for (CCollisionInfo const& info : cached_cinfo) {
|
||||||
|
if (k > 3) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
float overlap_range = x37c_26_runningSlowish ? 1 : 0.75f;
|
||||||
|
int num_overlap = SortAndFindOverlappingPoints(Cube{info.GetPoint(), overlap_range});
|
||||||
|
const int max_overlapping = (x37c_26_runningSlowish ? 2 : 3);
|
||||||
|
if (num_overlap < max_overlapping) {
|
||||||
|
AddContactPoint(info, 10);
|
||||||
|
zeus::CTransform xf = zeus::lookAt(zeus::skZero3f, info.GetNormalLeft(), zeus::skUp);
|
||||||
|
x360_secondarySmokeGen->SetOrientation(xf);
|
||||||
|
x364_secondaryFireGen->SetOrientation(xf);
|
||||||
|
x368_secondarySparksGen->SetOrientation(xf);
|
||||||
|
x360_secondarySmokeGen->SetTranslation(info.GetPoint());
|
||||||
|
x364_secondaryFireGen->SetTranslation(info.GetPoint());
|
||||||
|
x368_secondarySparksGen->SetTranslation(info.GetPoint());
|
||||||
|
|
||||||
|
x360_secondarySmokeGen->ForceParticleCreation(1);
|
||||||
|
x364_secondaryFireGen->ForceParticleCreation(max_overlapping);
|
||||||
|
x368_secondarySparksGen->ForceParticleCreation(x37c_26_runningSlowish ? 3 : 5);
|
||||||
|
if (x37c_26_runningSlowish) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last_added_pt = info.GetPoint();
|
||||||
|
}
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
if (!x37c_26_runningSlowish && !x300_wasPointAdded) {
|
||||||
|
float dist_between = (x2f4_lastParticleCollisionLoc - last_added_pt).magSquared();
|
||||||
|
if (cached_cinfo.GetCount() < 3 || dist_between > 3.0f) {
|
||||||
|
zeus::CVector3f avg_loc = (x2f4_lastParticleCollisionLoc + last_added_pt) * 0.5f;
|
||||||
|
x364_secondaryFireGen->SetTranslation(avg_loc);
|
||||||
|
x364_secondaryFireGen->ForceParticleCreation(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x2f4_lastParticleCollisionLoc = last_added_pt;
|
||||||
|
x300_wasPointAdded = true;
|
||||||
|
|
||||||
|
if (first_actor_hit != kInvalidUniqueId) {
|
||||||
|
if (TCastToPtr<CActor> act = mgr.ObjectById(first_actor_hit)) {
|
||||||
|
if (CanDamageActor(*act, mgr)) {
|
||||||
|
CDamageInfo dmg_info(x12c_curDamageInfo, dt);
|
||||||
|
mgr.ApplyDamage(x8_uid, act->GetUniqueId(), xec_ownerId, dmg_info, xf8_filter,
|
||||||
|
cur_swoosh.x74_velocity.normalized());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CDamageInfo dmg_info(x12c_curDamageInfo, dt);
|
||||||
|
mgr.ApplyDamageToWorld(xec_ownerId, *this, cur_swoosh.xc_translation, dmg_info, xf8_filter);
|
||||||
|
collisions_out.push_back({cur_swoosh.xc_translation, batch_highest_speed});
|
||||||
|
if (collisions_out.size() == 32) {
|
||||||
|
cached_cinfo.Clear();
|
||||||
|
coll_info_out.Clear();
|
||||||
|
near_list_cache.clear();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
cached_cinfo.Clear();
|
||||||
|
}
|
||||||
|
coll_info_out.Clear();
|
||||||
|
}
|
||||||
|
near_list_cache.clear();
|
||||||
|
mgr.BuildNearList(near_list_cache, batch_particle_bounds,
|
||||||
|
CMaterialFilter::MakeInclude(CMaterialList(EMaterialTypes::NonSolidDamageable)), mgr.Player());
|
||||||
|
for (TUniqueId const& uid : near_list_cache) {
|
||||||
|
if (TCastToPtr<CSnakeWeedSwarm> sw = mgr.ObjectById(uid)) {
|
||||||
|
for (int j = batch_start; j < batch_end; j++) {
|
||||||
|
if (j == prev_particle || !swoosh_vec[j].x0_active) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
float damage_radius_multiplier = batch_highest_speed < 1.f ? 1 : batch_highest_speed;
|
||||||
|
sw->HandleRadiusDamage(damage_radius_multiplier * sw->GetWeaponDamageRadius(), mgr,
|
||||||
|
swoosh_vec[j].xc_translation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int j = batch_start; j < batch_end; j++) {
|
||||||
|
if (j == prev_particle || !swoosh_vec[j].x0_active) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto& cur_swoosh = swoosh_vec[j];
|
||||||
|
|
||||||
|
CCollidableSphere coll_prim(zeus::CSphere(cur_swoosh.xc_translation, batch_highest_speed),
|
||||||
|
CMaterialList(EMaterialTypes::Solid));
|
||||||
|
CCollisionInfoList coll_info_out;
|
||||||
|
TUniqueId first_actor_hit;
|
||||||
|
|
||||||
|
FindCollisionInNearList(mgr, near_list_cache, coll_prim, first_actor_hit, coll_info_out);
|
||||||
|
if (first_actor_hit != kInvalidUniqueId) {
|
||||||
|
if (TCastToPtr<CActor> act = mgr.ObjectById(first_actor_hit)) {
|
||||||
|
if (CanDamageActor(*act, mgr)) {
|
||||||
|
CDamageInfo dmg_info(x12c_curDamageInfo, dt);
|
||||||
|
mgr.ApplyDamage(x8_uid, act->GetUniqueId(), xec_ownerId, dmg_info, xf8_filter,
|
||||||
|
cur_swoosh.x74_velocity.normalized());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
coll_info_out.Clear();
|
||||||
|
}
|
||||||
|
i += batch_process_size;
|
||||||
|
}
|
||||||
|
DecrementContactPointTimers();
|
||||||
|
near_list_cache.clear();
|
||||||
|
return any_particle_collisions;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNewFlameThrower::CanDamageActor(CActor& hit_actor, CStateManager& mgr) {
|
||||||
|
CDamageVulnerability const* vuln = hit_actor.GetDamageVulnerability();
|
||||||
|
if (vuln->GetVulnerability(x12c_curDamageInfo.GetWeaponMode(), false) == EVulnerability::PassThrough) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (TCastToPtr<CScriptTrigger> trigger = hit_actor) {
|
||||||
|
CProjectileTouchResult res = CanCollideWithTrigger(*trigger, mgr);
|
||||||
|
return res.GetActorId() != kInvalidUniqueId;
|
||||||
|
}
|
||||||
|
if (TCastToPtr<CScriptPlatform> platform = hit_actor) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (TCastToPtr<CCollisionActor> coll_actor = hit_actor) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (CPatterned::CastTo<MP1::CFlickerBat>(&hit_actor)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
CProjectileTouchResult res = CanCollideWithGameObject(hit_actor, mgr);
|
||||||
|
return res.GetActorId() != kInvalidUniqueId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNewFlameThrower::AddContactPoint(CCollisionInfo const& cinfo, u32 time) {
|
||||||
|
int elem = 0;
|
||||||
|
for (auto& cp_vec : x380_flameContactPoints) {
|
||||||
|
cp_vec.emplace_back(cinfo.GetPoint()[elem], time);
|
||||||
|
elem++;
|
||||||
|
}
|
||||||
|
x37c_27_newPointAdded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CNewFlameThrower::SortAndFindOverlappingPoints(Cube const& box) {
|
||||||
|
if (x37c_27_newPointAdded) {
|
||||||
|
for (auto& component_vec : x380_flameContactPoints) {
|
||||||
|
std::sort(component_vec.begin(), component_vec.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int min_overlap = std::numeric_limits<int>::max();
|
||||||
|
|
||||||
|
for (int i = 0; i < x380_flameContactPoints.size(); i++) {
|
||||||
|
auto const& component_vec = x380_flameContactPoints[i];
|
||||||
|
float search_min = box.center[i] - box.bounds;
|
||||||
|
float search_max = box.center[i] + box.bounds;
|
||||||
|
auto min_result = rstl::binary_find(component_vec.begin(), component_vec.end(), Contact{search_min, 0});
|
||||||
|
auto max_result = rstl::binary_find(component_vec.begin(), component_vec.end(), Contact{search_max, 0});
|
||||||
|
if (min_result == component_vec.end()) {
|
||||||
|
min_result = component_vec.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_overlap = static_cast<int>(max_result - min_result);
|
||||||
|
num_overlap = num_overlap < min_overlap ? num_overlap : min_overlap;
|
||||||
|
if (num_overlap == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
min_overlap = num_overlap;
|
||||||
|
}
|
||||||
|
return min_overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNewFlameThrower::FindCollisionInNearList(CStateManager& mgr,
|
||||||
|
rstl::reserved_vector<TUniqueId, 1024> const& near_list,
|
||||||
|
CCollisionPrimitive const& coll, TUniqueId& first_coll_out,
|
||||||
|
CCollisionInfoList& collisions) {
|
||||||
|
for (TUniqueId const& cur_uid : near_list) {
|
||||||
|
if (TCastToPtr<CActor> near_actor = mgr.ObjectById(cur_uid)) {
|
||||||
|
if (TCastToPtr<CPhysicsActor> pa = *near_actor) {
|
||||||
|
CInternalCollisionStructure::CPrimDesc pa_desc(*pa->GetCollisionPrimitive(), pa->GetMaterialFilter(),
|
||||||
|
pa->GetPrimitiveTransform());
|
||||||
|
CInternalCollisionStructure::CPrimDesc param_desc(coll, skExcludeProjectilePassthrough, zeus::CTransform());
|
||||||
|
|
||||||
|
if (CCollisionPrimitive::Collide(pa_desc, param_desc, collisions)) {
|
||||||
|
first_coll_out = cur_uid;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto bounds = near_actor->GetTouchBounds();
|
||||||
|
if (!bounds.has_value()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
CCollidableAABox coll_aabb(bounds.value(), CMaterialList(EMaterialTypes::Solid));
|
||||||
|
CInternalCollisionStructure::CPrimDesc aabb_desc(coll_aabb, CMaterialFilter::skPassEverything,
|
||||||
|
zeus::CTransform());
|
||||||
|
CInternalCollisionStructure::CPrimDesc param_desc(coll, skExcludeProjectilePassthrough, zeus::CTransform());
|
||||||
|
|
||||||
|
if (CCollisionPrimitive::Collide(param_desc, aabb_desc, collisions)) {
|
||||||
|
first_coll_out = cur_uid;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNewFlameThrower::DecrementContactPointTimers() {
|
||||||
|
for (auto& vec : x380_flameContactPoints) {
|
||||||
|
int end = static_cast<int>(vec.size() - 1);
|
||||||
|
for (size_t i = 0; i < vec.size(); i++) {
|
||||||
|
vec[i].remainingTime--;
|
||||||
|
if (vec[i].remainingTime == 0) {
|
||||||
|
vec[i] = vec[end];
|
||||||
|
vec.pop_back();
|
||||||
|
// forgot to decrement iterator ?
|
||||||
|
// i--;
|
||||||
|
end--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void CNewFlameThrower::Reset(CStateManager& mgr, bool deactivate) {
|
||||||
|
if (deactivate) {
|
||||||
|
SetLightsActive(mgr, false);
|
||||||
|
SetActive(false);
|
||||||
|
x374_flameState = EFlameState::Default;
|
||||||
|
x2ec_particlesDoneTimer = 0.f;
|
||||||
|
x2f0_flamesDoneTimer = 0.f;
|
||||||
|
} else {
|
||||||
|
x374_flameState = EFlameState::FireStopTimer;
|
||||||
|
}
|
||||||
|
x37c_25_firing = false;
|
||||||
|
x358_mainFireGen->SetParticleEmission(false);
|
||||||
|
x35c_mainSmokeGen->SetParticleEmission(false);
|
||||||
|
x36c_swooshCenterGen->SetParticleEmission(false);
|
||||||
|
x370_swooshFireGen->SetParticleEmission(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNewFlameThrower::SetLightsActive(CStateManager& mgr, bool active) {
|
||||||
|
for (TUniqueId const& uid : x3b8_lightIds) {
|
||||||
|
if (TCastToPtr<CGameLight> light = mgr.ObjectById(uid)) {
|
||||||
|
light->SetActive(active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNewFlameThrower::UpdateFlameState(float dt, CStateManager& mgr) {
|
||||||
|
bool flame_light_active = false;
|
||||||
|
switch (x374_flameState) {
|
||||||
|
case EFlameState::FireWaitForParticlesDone:
|
||||||
|
x2ec_particlesDoneTimer += dt;
|
||||||
|
if (x2ec_particlesDoneTimer > 0.1f && AreEffectsFinished()) {
|
||||||
|
x374_flameState = EFlameState::Default;
|
||||||
|
Reset(mgr, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EFlameState::FireStopTimer:
|
||||||
|
flame_light_active = true;
|
||||||
|
x2f0_flamesDoneTimer = (dt * 4) + x2f0_flamesDoneTimer;
|
||||||
|
if (x2f0_flamesDoneTimer > 1.f) {
|
||||||
|
x2f0_flamesDoneTimer = 1.f;
|
||||||
|
x374_flameState = EFlameState::FireWaitForParticlesDone;
|
||||||
|
x37c_24_renderAuxEffects = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EFlameState::FireStart:
|
||||||
|
x374_flameState = EFlameState::FireActive;
|
||||||
|
break;
|
||||||
|
case EFlameState::FireActive:
|
||||||
|
flame_light_active = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const float speed = flame_light_active ? 4.f : 1.f;
|
||||||
|
const float target = flame_light_active ? 0.7f : 1.f;
|
||||||
|
SetWorldLighting(mgr, mgr.GetPlayer().GetAreaIdAlways(), speed, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNewFlameThrower::SetWorldLighting(CStateManager& mgr, TAreaId area, float speed, float target) {
|
||||||
|
if (x37c_28_activeLighting && x378_currentLitArea != kInvalidAreaId) {
|
||||||
|
CGameArea* lit_area = mgr.GetWorld()->GetArea(x378_currentLitArea);
|
||||||
|
// Restore previous area's lighting
|
||||||
|
if (!lit_area->IsPostConstructed()) {
|
||||||
|
lit_area->SetWeaponWorldLighting(1.f, 1.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x378_currentLitArea = area;
|
||||||
|
x37c_28_activeLighting = (target != 1.f);
|
||||||
|
if (x378_currentLitArea != kInvalidAreaId) {
|
||||||
|
CGameArea* lit_area = mgr.GetWorld()->GetArea(x378_currentLitArea);
|
||||||
|
if (!lit_area->IsPostConstructed()) {
|
||||||
|
lit_area->SetWeaponWorldLighting(speed, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace urde
|
} // namespace urde
|
||||||
|
|
|
@ -2,19 +2,45 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <zeus/CFrustum.hpp>
|
||||||
|
|
||||||
#include "Runtime/rstl.hpp"
|
#include "Runtime/rstl.hpp"
|
||||||
#include "Runtime/Weapon/CGameProjectile.hpp"
|
#include "Runtime/Weapon/CGameProjectile.hpp"
|
||||||
|
|
||||||
namespace urde {
|
namespace urde {
|
||||||
|
class CCollisionPrimitive;
|
||||||
|
class CCollisionInfoList;
|
||||||
|
class CCollisionInfo;
|
||||||
|
|
||||||
class CNewFlameThrower : public CGameProjectile {
|
class CNewFlameThrower : public CGameProjectile {
|
||||||
|
struct Contact {
|
||||||
|
Contact(float contact, u32 remainingTime) : contact(contact), remainingTime(remainingTime) {}
|
||||||
|
float contact;
|
||||||
|
u32 remainingTime;
|
||||||
|
bool operator<(Contact const& o) const { return contact < o.contact; }
|
||||||
|
};
|
||||||
|
struct Cube {
|
||||||
|
Cube(zeus::CVector3f center, float bounds) : center(center), bounds(bounds) {}
|
||||||
|
zeus::CVector3f center;
|
||||||
|
float bounds;
|
||||||
|
};
|
||||||
|
enum class EFlameState {
|
||||||
|
Default,
|
||||||
|
FireStart,
|
||||||
|
FireActive,
|
||||||
|
FireStopTimer,
|
||||||
|
FireWaitForParticlesDone
|
||||||
|
};
|
||||||
|
|
||||||
CRandom16 x2e8_rand{99};
|
CRandom16 x2e8_rand{99};
|
||||||
float x2ec_ = 0.f;
|
float x2ec_particlesDoneTimer = 0.f;
|
||||||
float x2f0_ = 0.f;
|
float x2f0_flamesDoneTimer = 0.f;
|
||||||
bool x300_ = false;
|
zeus::CVector3f x2f4_lastParticleCollisionLoc;
|
||||||
|
bool x300_wasPointAdded = false;
|
||||||
TCachedToken<CGenDescription> x304_mainFire;
|
TCachedToken<CGenDescription> x304_mainFire;
|
||||||
TCachedToken<CGenDescription> x310_mainSmoke;
|
TCachedToken<CGenDescription> x310_mainSmoke;
|
||||||
TCachedToken<CGenDescription> x31c_secondarySmoke;
|
TCachedToken<CGenDescription> x31c_secondarySmoke;
|
||||||
|
@ -29,19 +55,39 @@ class CNewFlameThrower : public CGameProjectile {
|
||||||
std::unique_ptr<CElementGen> x368_secondarySparksGen;
|
std::unique_ptr<CElementGen> x368_secondarySparksGen;
|
||||||
std::unique_ptr<CParticleSwoosh> x36c_swooshCenterGen;
|
std::unique_ptr<CParticleSwoosh> x36c_swooshCenterGen;
|
||||||
std::unique_ptr<CParticleSwoosh> x370_swooshFireGen;
|
std::unique_ptr<CParticleSwoosh> x370_swooshFireGen;
|
||||||
u32 x374_ = 0;
|
EFlameState x374_flameState = EFlameState::Default;
|
||||||
TAreaId x378_ = kInvalidAreaId;
|
TAreaId x378_currentLitArea = kInvalidAreaId;
|
||||||
bool x37c_24_renderAuxEffects : 1 = false;
|
bool x37c_24_renderAuxEffects : 1 = false;
|
||||||
bool x37c_25_firing : 1 = false;
|
bool x37c_25_firing : 1 = false;
|
||||||
bool x37c_26_ : 1 = false;
|
bool x37c_26_runningSlowish : 1 = false;
|
||||||
bool x37c_27_ : 1 = true;
|
bool x37c_27_newPointAdded : 1 = true;
|
||||||
bool x37c_28_ : 1 = false;
|
bool x37c_28_activeLighting : 1 = false;
|
||||||
rstl::reserved_vector<std::vector<std::pair<float, u32>>, 3> x380_;
|
rstl::reserved_vector<std::vector<Contact>, 3> x380_flameContactPoints;
|
||||||
u32 x3b4_ = 0;
|
int x3b4_numSmokeParticlesSpawned = 0;
|
||||||
rstl::reserved_vector<TUniqueId, 4> x3b8_lightIds;
|
rstl::reserved_vector<TUniqueId, 4> x3b8_lightIds;
|
||||||
|
|
||||||
|
// std::array<std::unique_ptr<CTexturedQuadFilter>, 5> beam_filters;
|
||||||
|
|
||||||
void DeleteLightObjects(CStateManager& mgr);
|
void DeleteLightObjects(CStateManager& mgr);
|
||||||
void CreateLightObjects(CStateManager& mgr);
|
void CreateLightObjects(CStateManager& mgr);
|
||||||
void EnableFx(CStateManager& mgr);
|
void EnableFx(CStateManager& mgr);
|
||||||
|
void UpdateLights(CStateManager& mgr);
|
||||||
|
bool UpdateParticleCollisions(float dt, CStateManager &mgr,
|
||||||
|
rstl::reserved_vector<Cube, 32> &collisions_out);
|
||||||
|
bool CanDamageActor(CActor &hit_actor, CStateManager &mgr);
|
||||||
|
void AddContactPoint(CCollisionInfo const& cinfo, u32 time);
|
||||||
|
int SortAndFindOverlappingPoints(Cube const& box);
|
||||||
|
bool FindCollisionInNearList(CStateManager &mgr, rstl::reserved_vector<TUniqueId, 1024> const &near_list,
|
||||||
|
CCollisionPrimitive const& coll, TUniqueId &first_coll_out,
|
||||||
|
CCollisionInfoList& collisions);
|
||||||
|
void DecrementContactPointTimers();
|
||||||
|
void SetLightsActive(CStateManager &mgr, bool active);
|
||||||
|
void UpdateFlameState(float dt, CStateManager &mgr);
|
||||||
|
void SetWorldLighting(CStateManager &mgr, TAreaId area, float speed, float target);
|
||||||
|
// void RenderParticles(std::array<CElementGen *, 5> const& elem_gens);
|
||||||
|
|
||||||
|
// void LoadParticleGenQuads();
|
||||||
|
bool loaded_textures = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Resinfo:
|
// Resinfo:
|
||||||
|
@ -62,6 +108,12 @@ public:
|
||||||
bool AreEffectsFinished() const;
|
bool AreEffectsFinished() const;
|
||||||
void UpdateFx(const zeus::CTransform& xf, float dt, CStateManager& mgr);
|
void UpdateFx(const zeus::CTransform& xf, float dt, CStateManager& mgr);
|
||||||
void Reset(CStateManager& mgr, bool deactivate);
|
void Reset(CStateManager& mgr, bool deactivate);
|
||||||
|
void Render(CStateManager& mgr) override;
|
||||||
|
void Think(float dt, CStateManager &mgr) override;
|
||||||
|
std::optional<zeus::CAABox> GetTouchBounds() const override { return {}; }
|
||||||
|
void Accept(IVisitor& visitor) override;
|
||||||
|
void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId uid, CStateManager &mgr) override;
|
||||||
|
void AddToRenderer(zeus::CFrustum const& planes, CStateManager& mgr) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace urde
|
} // namespace urde
|
||||||
|
|
|
@ -106,10 +106,11 @@ public:
|
||||||
void AddToRenderer(const zeus::CFrustum&, CStateManager&) override;
|
void AddToRenderer(const zeus::CFrustum&, CStateManager&) override;
|
||||||
void Touch(CActor&, CStateManager&) override;
|
void Touch(CActor&, CStateManager&) override;
|
||||||
void Think(float, CStateManager&) override;
|
void Think(float, CStateManager&) override;
|
||||||
|
void HandleRadiusDamage(float radius, CStateManager& mgr, const zeus::CVector3f& pos);
|
||||||
|
float GetWeaponDamageRadius() const { return x100_weaponDamageRadius; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void AllocateSkinnedModels(CStateManager& mgr, CModelData::EWhichModel which);
|
void AllocateSkinnedModels(CStateManager& mgr, CModelData::EWhichModel which);
|
||||||
void HandleRadiusDamage(float radius, CStateManager& mgr, const zeus::CVector3f& pos);
|
|
||||||
void FindGround(const CStateManager& mgr);
|
void FindGround(const CStateManager& mgr);
|
||||||
zeus::CAABox GetBoidBox() const;
|
zeus::CAABox GetBoidBox() const;
|
||||||
int GetNumBoidsY() const;
|
int GetNumBoidsY() const;
|
||||||
|
|
Loading…
Reference in New Issue