2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-08-08 18:19:07 +00:00

Merge branch 'master' of ssh://git.axiodl.com:6431/AxioDL/urde

This commit is contained in:
Luke Street 2020-09-11 19:28:58 -04:00
commit 93e85e64f6
12 changed files with 857 additions and 34 deletions

View File

@ -82,4 +82,4 @@ build_script:
# Uncomment this to debug AppVeyor failures. # Uncomment this to debug AppVeyor failures.
#on_finish: #on_finish:
# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

View File

@ -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;

View File

@ -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

View File

@ -31,7 +31,7 @@ CDrone::CDrone(TUniqueId uid, std::string_view name, EFlavorType flavor, const C
float f17, float f18, float f19, float f20, CAssetId crscId, float f21, float f22, float f23, float f24, float f17, float f18, float f19, float f20, CAssetId crscId, float f21, float f22, float f23, float f24,
s32 sId, bool b1) s32 sId, bool b1)
: CPatterned(ECharacter::Drone, uid, name, flavor, info, xf, std::move(mData), pInfo, movement, colliderType, bodyType, : CPatterned(ECharacter::Drone, uid, name, flavor, info, xf, std::move(mData), pInfo, movement, colliderType, bodyType,
actParms, EKnockBackVariant(flavor == EFlavorType::Zero)) actParms, flavor == EFlavorType::Zero ? EKnockBackVariant::Medium : EKnockBackVariant::Large)
, x568_(aId1) , x568_(aId1)
, x56c_(g_SimplePool->GetObj({SBIG('CRSC'), crscId})) , x56c_(g_SimplePool->GetObj({SBIG('CRSC'), crscId}))
, x57c_flares(std::move(flares)) , x57c_flares(std::move(flares))
@ -61,7 +61,7 @@ CDrone::CDrone(TUniqueId uid, std::string_view name, EFlavorType flavor, const C
, x65c_(f21) , x65c_(f21)
, x660_(f22) , x660_(f22)
, x664_(f24) , x664_(f24)
, x690_(zeus::CSphere({0.f, 0.f, 1.8f}, 1.1f), CActor::GetMaterialList()) , x690_colSphere(zeus::CSphere({0.f, 0.f, 1.8f}, 1.1f), CActor::GetMaterialList())
, x6b0_pathFind(nullptr, 3 + int(b1), pInfo.GetPathfindingIndex(), 1.f, 2.4f) , x6b0_pathFind(nullptr, 3 + int(b1), pInfo.GetPathfindingIndex(), 1.f, 2.4f)
, x7cc_(CSfxManager::TranslateSFXID(sId)) , x7cc_(CSfxManager::TranslateSFXID(sId))
, x82c_shieldModel(std::make_unique<CModelData>(CStaticRes{aId2, zeus::skOne3f})) , x82c_shieldModel(std::make_unique<CModelData>(CStaticRes{aId2, zeus::skOne3f}))
@ -218,7 +218,7 @@ void CDrone::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateM
} }
case EScriptObjectMessage::Deactivate: case EScriptObjectMessage::Deactivate:
case EScriptObjectMessage::Deleted: { case EScriptObjectMessage::Deleted: {
for (TUniqueId& unkId : x7d4_) { for (TUniqueId& unkId : x7d8_) {
if (unkId != kInvalidUniqueId) { if (unkId != kInvalidUniqueId) {
mgr.FreeScriptObject(unkId); mgr.FreeScriptObject(unkId);
unkId = kInvalidUniqueId; unkId = kInvalidUniqueId;
@ -228,9 +228,11 @@ void CDrone::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateM
mgr.GetPlayerState()->GetStaticInterference().RemoveSource(GetUniqueId()); mgr.GetPlayerState()->GetStaticInterference().RemoveSource(GetUniqueId());
if (x578_lightId != kInvalidUniqueId) { if (x578_lightId != kInvalidUniqueId) {
mgr.FreeScriptObject(x578_lightId); mgr.FreeScriptObject(x578_lightId);
x578_lightId = kInvalidUniqueId;
} }
if (x57a_ != kInvalidUniqueId) { if (x57a_ != kInvalidUniqueId) {
mgr.FreeScriptObject(x57a_); mgr.FreeScriptObject(x57a_);
x57a_ = kInvalidUniqueId;
} }
if (x7d0_) { if (x7d0_) {
@ -243,7 +245,7 @@ void CDrone::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateM
x834_29_codeTrigger = true; x834_29_codeTrigger = true;
break; break;
case EScriptObjectMessage::OnFloor: case EScriptObjectMessage::OnFloor:
if (!x835_26_ && x834_24_) { if (!x835_26_ && x834_24_ && !IsAlive()) {
x835_26_ = true; x835_26_ = true;
MassiveFrozenDeath(mgr); MassiveFrozenDeath(mgr);
} }
@ -279,6 +281,10 @@ void CDrone::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateM
} }
} }
void CDrone::AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) {
CPatterned::AddToRenderer(frustum, mgr);
}
void CDrone::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) { void CDrone::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) {
CPatterned::PreRender(mgr, frustum); CPatterned::PreRender(mgr, frustum);
if (x3fc_flavor == EFlavorType::One) { if (x3fc_flavor == EFlavorType::One) {
@ -313,7 +319,7 @@ void CDrone::Render(CStateManager& mgr) {
} }
bool CDrone::CanRenderUnsorted(const CStateManager& mgr) const { bool CDrone::CanRenderUnsorted(const CStateManager& mgr) const {
if (zeus::close_enough(x5dc_, 0.f)) if (!zeus::close_enough(x5dc_, 0.f))
return false; return false;
return CPatterned::CanRenderUnsorted(mgr); return CPatterned::CanRenderUnsorted(mgr);
} }
@ -399,7 +405,7 @@ void CDrone::DoUserAnimEvent(CStateManager& mgr, const CInt32POINode& node, EUse
const CCollisionPrimitive* CDrone::GetCollisionPrimitive() const { const CCollisionPrimitive* CDrone::GetCollisionPrimitive() const {
if (!x834_28_) if (!x834_28_)
return &x690_; return &x690_colSphere;
return CPatterned::GetCollisionPrimitive(); return CPatterned::GetCollisionPrimitive();
} }
@ -766,6 +772,8 @@ bool CDrone::SpotPlayer(CStateManager& mgr, float arg) {
bool CDrone::AnimOver(CStateManager& mgr, float arg) { return x7c8_ == 2; } bool CDrone::AnimOver(CStateManager& mgr, float arg) { return x7c8_ == 2; }
bool CDrone::AttackOver(CStateManager& mgr, float arg) { return x834_31_attackOver; }
bool CDrone::ShouldAttack(CStateManager& mgr, float arg) { bool CDrone::ShouldAttack(CStateManager& mgr, float arg) {
if (x5d0_ > 0.f) if (x5d0_ > 0.f)
return false; return false;
@ -822,15 +830,19 @@ void CDrone::SetLightEnabled(CStateManager& mgr, bool activate) {
activate ? EScriptObjectMessage::Activate : EScriptObjectMessage::Deactivate); activate ? EScriptObjectMessage::Activate : EScriptObjectMessage::Deactivate);
} }
void CDrone::SetVisorFlareEnabled(CStateManager& mgr, bool activate) {} void CDrone::SetVisorFlareEnabled(CStateManager& mgr, bool activate) {
// TODO implement
}
void CDrone::UpdateVisorFlare(CStateManager& mgr) { void CDrone::UpdateVisorFlare(CStateManager& mgr) {
// TODO: Finish // TODO implement
} }
void CDrone::UpdateTouchBounds(float radius) { void CDrone::UpdateTouchBounds(float radius) {
const zeus::CTransform xf = GetLctrTransform("Skeleton_Root"sv); const zeus::CTransform xf = GetLctrTransform("Skeleton_Root"sv);
const zeus::CVector3f diff = xf.origin - GetTranslation(); const zeus::CVector3f diff = xf.origin - GetTranslation();
x690_colSphere.SetSphereCenter(diff);
x690_colSphere.SetSphereRadius(radius);
SetBoundingBox(zeus::CAABox{diff - radius, diff + radius}); SetBoundingBox(zeus::CAABox{diff - radius, diff + radius});
x6b0_pathFind.SetCharacterRadius(0.25f + radius); x6b0_pathFind.SetCharacterRadius(0.25f + radius);
} }

View File

@ -11,7 +11,6 @@ namespace MP1 {
class CDrone : public CPatterned { class CDrone : public CPatterned {
CAssetId x568_; CAssetId x568_;
TLockedToken<CCollisionResponseData> x56c_; TLockedToken<CCollisionResponseData> x56c_;
CCollisionResponseData* x574_;
TUniqueId x578_lightId = kInvalidUniqueId; TUniqueId x578_lightId = kInvalidUniqueId;
TUniqueId x57a_ = kInvalidUniqueId; TUniqueId x57a_ = kInvalidUniqueId;
std::vector<CVisorFlare::CFlareDef> x57c_flares; std::vector<CVisorFlare::CFlareDef> x57c_flares;
@ -63,18 +62,19 @@ class CDrone : public CPatterned {
zeus::CVector3f x670_; zeus::CVector3f x670_;
zeus::CVector3f x67c_; zeus::CVector3f x67c_;
TUniqueId x688_teamMgr = kInvalidUniqueId; TUniqueId x688_teamMgr = kInvalidUniqueId;
CCollidableSphere x690_; CCollidableSphere x690_colSphere;
CPathFindSearch x6b0_pathFind; CPathFindSearch x6b0_pathFind;
zeus::CAxisAngle x794_; zeus::CAxisAngle x794_;
zeus::CVector3f x7a0_; zeus::CVector3f x7a0_;
zeus::CVector3f x7ac_lightPos; zeus::CVector3f x7ac_lightPos;
float x7b8_ = 0.f; float x7b8_ = 0.f;
float x7bc_ = 0.f; float x7bc_ = 0.f;
float x7c0_ = 0.f;
float x7c4_ = 0.f; float x7c4_ = 0.f;
s32 x7c8_ = 0; s32 x7c8_ = 0;
s16 x7cc_; s16 x7cc_;
CSfxHandle x7d0_; CSfxHandle x7d0_;
rstl::reserved_vector<TUniqueId, 2> x7d4_ = {{kInvalidUniqueId, kInvalidUniqueId}}; rstl::reserved_vector<TUniqueId, 2> x7d8_ = {{kInvalidUniqueId, kInvalidUniqueId}};
rstl::reserved_vector<zeus::CVector3f, 2> x7e0_ = {{zeus::skZero3f, zeus::skZero3f}}; rstl::reserved_vector<zeus::CVector3f, 2> x7e0_ = {{zeus::skZero3f, zeus::skZero3f}};
rstl::reserved_vector<zeus::CVector3f, 2> x7fc_ = {{zeus::skZero3f, zeus::skZero3f}}; rstl::reserved_vector<zeus::CVector3f, 2> x7fc_ = {{zeus::skZero3f, zeus::skZero3f}};
rstl::reserved_vector<float, 2> x818_ = {{0.f, 0.f}}; rstl::reserved_vector<float, 2> x818_ = {{0.f, 0.f}};
@ -89,7 +89,7 @@ class CDrone : public CPatterned {
bool x834_28_ : 1 = false; bool x834_28_ : 1 = false;
bool x834_29_codeTrigger : 1 = false; bool x834_29_codeTrigger : 1 = false;
bool x834_30_visible : 1 = false; bool x834_30_visible : 1 = false;
bool x834_31_ : 1 = false; bool x834_31_attackOver : 1 = false;
bool x835_24_ : 1 = false; bool x835_24_ : 1 = false;
bool x835_25_ : 1; bool x835_25_ : 1;
bool x835_26_ : 1 = false; bool x835_26_ : 1 = false;
@ -121,6 +121,7 @@ public:
void Accept(IVisitor& visitor) override; void Accept(IVisitor& visitor) override;
void Think(float dt, CStateManager& mgr) override; void Think(float dt, CStateManager& mgr) override;
void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) override; void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) override;
void AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) override;
void PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) override; void PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) override;
void Render(CStateManager& mgr) override; void Render(CStateManager& mgr) override;
bool CanRenderUnsorted(const CStateManager& mgr) const override; bool CanRenderUnsorted(const CStateManager& mgr) const override;
@ -154,6 +155,7 @@ public:
bool InRange(CStateManager&, float arg) override; bool InRange(CStateManager&, float arg) override;
bool SpotPlayer(CStateManager&, float arg) override; bool SpotPlayer(CStateManager&, float arg) override;
bool AnimOver(CStateManager&, float arg) override; bool AnimOver(CStateManager&, float arg) override;
bool AttackOver(CStateManager& mgr, float arg) override;
bool ShouldAttack(CStateManager&, float arg) override; bool ShouldAttack(CStateManager&, float arg) override;
bool HearShot(CStateManager&, float arg) override; bool HearShot(CStateManager&, float arg) override;
bool CoverCheck(CStateManager&, float arg) override; bool CoverCheck(CStateManager&, float arg) override;

View File

@ -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)

View File

@ -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

View File

@ -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)) {

View File

@ -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

View File

@ -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

View File

@ -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;

2
amuse

@ -1 +1 @@
Subproject commit f172427991eb2138ad85e89b9482782834ed1d43 Subproject commit 63a58858e80d659f33c5975714b6e4e305429867