diff --git a/Editor/main.cpp b/Editor/main.cpp index e40cf657e..f0dd8e582 100644 --- a/Editor/main.cpp +++ b/Editor/main.cpp @@ -59,7 +59,6 @@ struct Application : boo::IApplicationCallback hecl::Runtime::FileStoreManager m_fileMgr; hecl::CVarManager m_cvarManager; hecl::CVarCommons m_cvarCommons; - hecl::Console m_console; std::unique_ptr m_viewManager; bool m_running = true; @@ -67,12 +66,9 @@ struct Application : boo::IApplicationCallback Application() : m_fileMgr(_S("urde")), m_cvarManager(m_fileMgr), - m_cvarCommons(m_cvarManager), - m_console(&m_cvarManager) + m_cvarCommons(m_cvarManager) { - //hecl::Console::RegisterLogger(&m_console); m_viewManager = std::make_unique(m_fileMgr, m_cvarManager); - m_console.registerCommand("quit", "Quits application instantly", "", std::bind(&Application::quit, this, std::placeholders::_1, std::placeholders::_2)); } virtual ~Application() = default; @@ -147,11 +143,6 @@ struct Application : boo::IApplicationCallback { return m_cvarCommons.getDeepColor(); } - - void quit(hecl::Console* con = nullptr, const std::vector& arg = std::vector()) - { - m_running = false; - } }; } diff --git a/Runtime/CGameOptions.cpp b/Runtime/CGameOptions.cpp index 36cd8b033..4109e464e 100644 --- a/Runtime/CGameOptions.cpp +++ b/Runtime/CGameOptions.cpp @@ -56,7 +56,8 @@ const std::pair GameOptionsRegistry[] = {5, VisorOpts}, {5, DisplayOpts}, {4, SoundOpts}, - {4, ControllerOpts} + {4, ControllerOpts}, + {0, nullptr} }; CPersistentOptions::CPersistentOptions(CBitStreamReader& stream) diff --git a/Runtime/CPlayerState.cpp b/Runtime/CPlayerState.cpp index 57b795e02..6fb941e84 100644 --- a/Runtime/CPlayerState.cpp +++ b/Runtime/CPlayerState.cpp @@ -14,7 +14,7 @@ const u32 CPlayerState::PowerUpMaxValues[41] = 1, 1, 1, 14, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; -const char* PowerUpNames[41]= +const char* CPlayerState::PowerUpNames[41]= { "Power Beam", "Ice Beam", @@ -69,9 +69,14 @@ CPlayerState::CPlayerState() CPlayerState::CPlayerState(CBitStreamReader& stream) : x188_staticIntf(5) { - x4_enabledItems = stream.ReadEncoded(0x20); - u32 tmp = stream.ReadEncoded(0x20); - xc_health.SetHP(*reinterpret_cast(&tmp)); + x4_enabledItems = u32(stream.ReadEncoded(0x20u)); + union + { + float fHP; + u32 iHP; + } hp; + hp.iHP = u32(stream.ReadEncoded(0x20u)); + xc_health.SetHP(hp.fHP); x8_currentBeam = EBeamId(stream.ReadEncoded(CBitStreamReader::GetBitCount(5))); x20_currentSuit = EPlayerSuit(stream.ReadEncoded(CBitStreamReader::GetBitCount(4))); x24_powerups.resize(41); @@ -80,8 +85,8 @@ CPlayerState::CPlayerState(CBitStreamReader& stream) if (PowerUpMaxValues[i] == 0) continue; - u32 a = stream.ReadEncoded(CBitStreamReader::GetBitCount(PowerUpMaxValues[i])); - u32 b = stream.ReadEncoded(CBitStreamReader::GetBitCount(PowerUpMaxValues[i])); + u32 a = u32(stream.ReadEncoded(CBitStreamReader::GetBitCount(PowerUpMaxValues[i]))); + u32 b = u32(stream.ReadEncoded(CBitStreamReader::GetBitCount(PowerUpMaxValues[i]))); x24_powerups[i] = CPowerUp(a, b); } @@ -93,15 +98,20 @@ CPlayerState::CPlayerState(CBitStreamReader& stream) x170_scanTimes.emplace_back(state.first, time); } - x180_scanCompletionRate.first = stream.ReadEncoded(CBitStreamReader::GetBitCount(0x100)); - x180_scanCompletionRate.second = stream.ReadEncoded(CBitStreamReader::GetBitCount(0x100)); + x180_scanCompletionRate.first = u32(stream.ReadEncoded(CBitStreamReader::GetBitCount(0x100u))); + x180_scanCompletionRate.second = u32(stream.ReadEncoded(CBitStreamReader::GetBitCount(0x100u))); } void CPlayerState::PutTo(CBitStreamWriter& stream) { stream.WriteEncoded(x4_enabledItems, 32); - float hp = xc_health.GetHP(); - stream.WriteEncoded(*reinterpret_cast(&hp), 32); + union + { + float fHP; + u32 iHP; + } hp; + hp.fHP = xc_health.GetHP(); + stream.WriteEncoded(hp.iHP, 32); stream.WriteEncoded(u32(x8_currentBeam), CBitStreamWriter::GetBitCount(5)); stream.WriteEncoded(u32(x20_currentSuit), CBitStreamWriter::GetBitCount(4)); for (u32 i = 0; i < x24_powerups.size(); ++i) @@ -262,8 +272,8 @@ void CPlayerState::UpdateVisorTransition(float dt) if (x14_currentVisor == x18_transitioningVisor) { x1c_visorTransitionFactor += dt; - if (x1c_visorTransitionFactor > 0.2) - x1c_visorTransitionFactor = 0.2; + if (x1c_visorTransitionFactor > 0.2f) + x1c_visorTransitionFactor = 0.2f; } else { @@ -338,7 +348,7 @@ u32 CPlayerState::GetItemAmount(CPlayerState::EItemType type) const return 0; } -void CPlayerState::DecrPickup(CPlayerState::EItemType type, s32 amount) +void CPlayerState::DecrPickup(CPlayerState::EItemType type, u32 amount) { if (type >= EItemType::Max) return; @@ -347,14 +357,11 @@ void CPlayerState::DecrPickup(CPlayerState::EItemType type, s32 amount) x24_powerups[u32(type)].x0_amount -= amount; } -void CPlayerState::IncrPickup(EItemType type, s32 amount) +void CPlayerState::IncrPickup(EItemType type, u32 amount) { if (type >= EItemType::Max) return; - if (amount < 0) - return; - switch(type) { case EItemType::Missiles: @@ -376,31 +383,29 @@ void CPlayerState::IncrPickup(EItemType type, s32 amount) case EItemType::Newborn: { CPowerUp& pup = x24_powerups[u32(type)]; - pup.x0_amount = std::min(pup.x0_amount + amount, pup.x4_capacity); + pup.x0_amount = std::min(pup.x0_amount + u32(amount), pup.x4_capacity); if (type == EItemType::EnergyTanks) IncrPickup(EItemType::HealthRefill, 9999); break; } case EItemType::HealthRefill: - { - float health = CalculateHealth(amount); - xc_health.SetHP(std::min(health, xc_health.GetHP() + amount)); - } + xc_health.SetHP(std::min(amount + xc_health.GetHP(), CalculateHealth())); + [[fallthrough]]; default: break; } } -void CPlayerState::ResetAndIncrPickUp(CPlayerState::EItemType type, s32 amount) +void CPlayerState::ResetAndIncrPickUp(CPlayerState::EItemType type, u32 amount) { x24_powerups[u32(type)].x0_amount = 0; IncrPickup(type, amount); } -float CPlayerState::CalculateHealth(u32 health) +float CPlayerState::CalculateHealth() { - return (GetBaseHealthCapacity() + (health * GetEnergyTankCapacity())); + return (GetEnergyTankCapacity() * x24_powerups[u32(EItemType::EnergyTanks)].x0_amount) + GetBaseHealthCapacity(); } void CPlayerState::InitializePowerUp(CPlayerState::EItemType type, u32 capacity) @@ -408,8 +413,8 @@ void CPlayerState::InitializePowerUp(CPlayerState::EItemType type, u32 capacity) if (type >= EItemType::Max) return; - CPowerUp& pup = x24_powerups[(u32)type]; - pup.x4_capacity = zeus::clamp(u32(0), pup.x4_capacity + capacity, PowerUpMaxValues[u32(type)]); + CPowerUp& pup = x24_powerups[u32(type)]; + pup.x4_capacity = zeus::clamp(0u, pup.x4_capacity + capacity, PowerUpMaxValues[u32(type)]); pup.x0_amount = std::min(pup.x0_amount, pup.x4_capacity); if (type >= EItemType::PowerSuit && type <= EItemType::PhazonSuit) { diff --git a/Runtime/CPlayerState.hpp b/Runtime/CPlayerState.hpp index 5ebd471f4..1bfdc3eca 100644 --- a/Runtime/CPlayerState.hpp +++ b/Runtime/CPlayerState.hpp @@ -102,12 +102,13 @@ public: private: static const u32 PowerUpMaxValues[41]; + static const char* PowerUpNames[41]; struct CPowerUp { - int x0_amount = 0; - int x4_capacity = 0; + u32 x0_amount = 0; + u32 x4_capacity = 0; CPowerUp() {} - CPowerUp(int amount, int capacity) : x0_amount(amount), x4_capacity(capacity) {} + CPowerUp(u32 amount, u32 capacity) : x0_amount(amount), x4_capacity(capacity) {} }; union { @@ -161,12 +162,12 @@ public: bool HasPowerUp(EItemType type) const; u32 GetItemCapacity(EItemType type) const; u32 GetItemAmount(EItemType type) const; - void DecrPickup(EItemType type, s32 amount); - void IncrPickup(EItemType type, s32 amount); - void ResetAndIncrPickUp(EItemType type, s32 amount); + void DecrPickup(EItemType type, u32 amount); + void IncrPickup(EItemType type, u32 amount); + void ResetAndIncrPickUp(EItemType type, u32 amount); static float GetEnergyTankCapacity() { return 100.f; } static float GetBaseHealthCapacity() { return 99.f; } - float CalculateHealth(u32 health); + float CalculateHealth(); void ReInitalizePowerUp(EItemType type, u32 capacity); void InitializePowerUp(EItemType type, u32 capacity); u32 GetLogScans() const { return x180_scanCompletionRate.first; } @@ -182,6 +183,7 @@ public: CPlayerState(); CPlayerState(CBitStreamReader& stream); void PutTo(CBitStreamWriter& stream); + static u32 GetPowerUpMaxValue(EItemType type) { return PowerUpMaxValues[u32(type)]; } }; } diff --git a/Runtime/Camera/CCameraFilter.hpp b/Runtime/Camera/CCameraFilter.hpp index b38d9f825..3bea74ac7 100644 --- a/Runtime/Camera/CCameraFilter.hpp +++ b/Runtime/Camera/CCameraFilter.hpp @@ -52,6 +52,7 @@ protected: TLockedToken x24_texObj; // Used to be auto_ptr float GetT(bool invert) const; public: + virtual ~CCameraFilterPassBase() = default; virtual void Update(float dt)=0; virtual void SetFilter(EFilterType type, EFilterShape shape, float time, const zeus::CColor& color, CAssetId txtr)=0; diff --git a/Runtime/Character/CBodyState.hpp b/Runtime/Character/CBodyState.hpp index 1df3a49e8..7b9bee575 100644 --- a/Runtime/Character/CBodyState.hpp +++ b/Runtime/Character/CBodyState.hpp @@ -13,6 +13,7 @@ class CActor; class CBodyState { public: + virtual ~CBodyState() = default; virtual bool IsInAir(const CBodyController&) const { return false; } virtual bool IsDead() const { return false; } virtual bool IsDying() const { return false; } diff --git a/Runtime/Collision/CBallFilter.cpp b/Runtime/Collision/CBallFilter.cpp index 2d8ee1e64..62134f8a0 100644 --- a/Runtime/Collision/CBallFilter.cpp +++ b/Runtime/Collision/CBallFilter.cpp @@ -1,11 +1,11 @@ #include "CBallFilter.hpp" - +#include "CollisionUtil.hpp" namespace urde { void CBallFilter::Filter(const CCollisionInfoList& in, CCollisionInfoList& out) const { - + CollisionUtil::AddAverageToFront(in, out); } } diff --git a/Runtime/Collision/CollisionUtil.cpp b/Runtime/Collision/CollisionUtil.cpp index 086b1c3c4..b7d5d298b 100644 --- a/Runtime/Collision/CollisionUtil.cpp +++ b/Runtime/Collision/CollisionUtil.cpp @@ -4,7 +4,6 @@ namespace urde::CollisionUtil { - bool LineIntersectsOBBox(const zeus::COBBox& obb, const zeus::CMRay& ray, float& d) { zeus::CVector3f norm; @@ -1236,4 +1235,8 @@ bool AABox_AABox_Moving(const zeus::CAABox& aabb0, const zeus::CAABox& aabb1, co return true; } +void AddAverageToFront(const CCollisionInfoList& in, CCollisionInfoList& out) +{ + +} } diff --git a/Runtime/Collision/CollisionUtil.hpp b/Runtime/Collision/CollisionUtil.hpp index da39e47e0..9704a9868 100644 --- a/Runtime/Collision/CollisionUtil.hpp +++ b/Runtime/Collision/CollisionUtil.hpp @@ -47,6 +47,7 @@ bool MovingSphereAABox(const zeus::CSphere& sphere, const zeus::CAABox& aabb, co double& d, zeus::CVector3f& point, zeus::CVector3f& normal); bool AABox_AABox_Moving(const zeus::CAABox& aabb0, const zeus::CAABox& aabb1, const zeus::CVector3f& dir, double& d, zeus::CVector3f& point, zeus::CVector3f& normal); +void AddAverageToFront(const CCollisionInfoList& in, CCollisionInfoList& out); } } #endif // __URDE_COLLISIONUTIL_HPP__ diff --git a/Runtime/Graphics/CBooRenderer.cpp b/Runtime/Graphics/CBooRenderer.cpp index 8e7a06495..83a0ac5b3 100644 --- a/Runtime/Graphics/CBooRenderer.cpp +++ b/Runtime/Graphics/CBooRenderer.cpp @@ -731,6 +731,11 @@ CBooRenderer::CBooRenderer(IObjectStore& store, IFactory& resFac) m_nextFogVolumeFilter = m_fogVolumeFilters.end(); } +CBooRenderer::~CBooRenderer() +{ + g_Renderer = nullptr; +} + void CBooRenderer::AddWorldSurfaces(CBooModel& model) { CBooSurface* surf = model.x3c_firstSortedSurface; diff --git a/Runtime/Graphics/CBooRenderer.hpp b/Runtime/Graphics/CBooRenderer.hpp index df64b848d..3a98223d4 100644 --- a/Runtime/Graphics/CBooRenderer.hpp +++ b/Runtime/Graphics/CBooRenderer.hpp @@ -203,6 +203,7 @@ class CBooRenderer : public IRenderer public: CBooRenderer(IObjectStore& store, IFactory& resFac); + ~CBooRenderer(); void AddWorldSurfaces(CBooModel& model); diff --git a/Runtime/Graphics/CModel.hpp b/Runtime/Graphics/CModel.hpp index 7994f3f9f..77cc562a4 100644 --- a/Runtime/Graphics/CModel.hpp +++ b/Runtime/Graphics/CModel.hpp @@ -201,6 +201,7 @@ private: static CBooModel* g_LastModelCached; static bool g_DummyTextures; + static bool g_RenderModelBlack; public: ~CBooModel(); @@ -269,6 +270,7 @@ public: static void DisableShadowMaps(); static void SetDummyTextures(bool b) { g_DummyTextures = b; } + static void SetRenderModelBlack(bool b) { g_RenderModelBlack = b; } }; class CModel diff --git a/Runtime/Graphics/CModelBoo.cpp b/Runtime/Graphics/CModelBoo.cpp index ccd449a37..368cf6694 100644 --- a/Runtime/Graphics/CModelBoo.cpp +++ b/Runtime/Graphics/CModelBoo.cpp @@ -47,6 +47,7 @@ void CBooModel::KillCachedViewDepState() } bool CBooModel::g_DummyTextures = false; +bool CBooModel::g_RenderModelBlack = false; zeus::CVector3f CBooModel::g_ReflectViewPos = {}; @@ -1095,10 +1096,18 @@ void CBooModel::DrawAlpha(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose) const { + CModelFlags rFlags = flags; + /* Check if we're overriding with RenderModelBlack */ + if (g_RenderModelBlack) + { + rFlags.m_extendedShader = EExtendedShader::SolidColor; + rFlags.x4_color = zeus::CColor::skBlack; + } + if (TryLockTextures()) { - UpdateUniformData(flags, cskr, pose); - DrawAlphaSurfaces(flags); + UpdateUniformData(rFlags, cskr, pose); + DrawAlphaSurfaces(rFlags); } } @@ -1106,10 +1115,17 @@ void CBooModel::DrawNormal(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose) const { + CModelFlags rFlags = flags; + /* Check if we're overriding with RenderModelBlack */ + if (g_RenderModelBlack) + { + rFlags.m_extendedShader = EExtendedShader::SolidColor; + rFlags.x4_color = zeus::CColor::skBlack; + } if (TryLockTextures()) { - UpdateUniformData(flags, cskr, pose); - DrawNormalSurfaces(flags); + UpdateUniformData(rFlags, cskr, pose); + DrawNormalSurfaces(rFlags); } } @@ -1117,10 +1133,18 @@ void CBooModel::Draw(const CModelFlags& flags, const CSkinRules* cskr, const CPoseAsTransforms* pose) const { + CModelFlags rFlags = flags; + /* Check if we're overriding with RenderModelBlack */ + if (g_RenderModelBlack) + { + rFlags.m_extendedShader = EExtendedShader::SolidColor; + rFlags.x4_color = zeus::CColor::skBlack; + } + if (TryLockTextures()) { - UpdateUniformData(flags, cskr, pose); - DrawSurfaces(flags); + UpdateUniformData(rFlags, cskr, pose); + DrawSurfaces(rFlags); } } diff --git a/Runtime/Graphics/Shaders/TMultiBlendShader.hpp b/Runtime/Graphics/Shaders/TMultiBlendShader.hpp index f1cb6d694..67b080868 100644 --- a/Runtime/Graphics/Shaders/TMultiBlendShader.hpp +++ b/Runtime/Graphics/Shaders/TMultiBlendShader.hpp @@ -19,6 +19,7 @@ public: { virtual boo::ObjToken BuildShaderDataBinding(boo::IGraphicsDataFactory::Context& ctx, EFilterType type, ShaderImp& filter)=0; + virtual ~IDataBindingFactory() = default; }; static std::unique_ptr m_bindFactory; diff --git a/Runtime/Graphics/Shaders/TShader.hpp b/Runtime/Graphics/Shaders/TShader.hpp index 32ecd93e5..033a839a0 100644 --- a/Runtime/Graphics/Shaders/TShader.hpp +++ b/Runtime/Graphics/Shaders/TShader.hpp @@ -18,6 +18,7 @@ public: { virtual boo::ObjToken BuildShaderDataBinding(boo::IGraphicsDataFactory::Context& ctx, ShaderImp& filter)=0; + virtual ~IDataBindingFactory() = default; }; static std::unique_ptr m_bindFactory; diff --git a/Runtime/GuiSys/CHudMissileInterface.cpp b/Runtime/GuiSys/CHudMissileInterface.cpp index afdd37190..77236dbf0 100644 --- a/Runtime/GuiSys/CHudMissileInterface.cpp +++ b/Runtime/GuiSys/CHudMissileInterface.cpp @@ -180,6 +180,7 @@ void CHudMissileInterface::Update(float dt, const CStateManager& mgr) { case EInventoryStatus::Warning: string = g_MainStringTable->GetString(12); // Missiles Low + break; case EInventoryStatus::Depleted: string = g_MainStringTable->GetString(13); // Depleted default: break; diff --git a/Runtime/IMain.hpp b/Runtime/IMain.hpp index 0df0ef1bd..0c90571fd 100644 --- a/Runtime/IMain.hpp +++ b/Runtime/IMain.hpp @@ -10,6 +10,7 @@ namespace hecl { class CVarManager; +class Console; } namespace urde @@ -51,6 +52,7 @@ public: virtual void SetFlowState(EFlowState) = 0; virtual size_t GetExpectedIdSize() const = 0; virtual void WarmupShaders() = 0; + virtual hecl::Console* Console() const = 0; }; } diff --git a/Runtime/IOStreams.hpp b/Runtime/IOStreams.hpp index 2f7e1f35e..fe96ddd8d 100644 --- a/Runtime/IOStreams.hpp +++ b/Runtime/IOStreams.hpp @@ -18,9 +18,9 @@ struct CBitStreamReader : athena::io::MemoryReader u32 x1c_val = 0; u32 x20_bitOffset = 0; public: - static s32 GetBitCount(s32 maxVal) + static u32 GetBitCount(u32 maxVal) { - s32 ret = 0; + u32 ret = 0; while (maxVal != 0) { maxVal /= 2; diff --git a/Runtime/MP1/MP1.cpp b/Runtime/MP1/MP1.cpp index fd0f4999d..0ffd3c202 100644 --- a/Runtime/MP1/MP1.cpp +++ b/Runtime/MP1/MP1.cpp @@ -57,6 +57,12 @@ #include +namespace hecl +{ + extern CVar* com_enableCheats; + extern CVar* com_developer; +}; + namespace urde { URDE_DECL_SPECIALIZE_SHADER(CParticleSwooshShaders) @@ -357,6 +363,16 @@ void CGameGlobalObjects::AddPaksAndFactories() } } +CGameGlobalObjects::~CGameGlobalObjects() +{ + g_ResFactory = nullptr; + g_SimplePool = nullptr; + g_CharFactoryBuilder = nullptr; + g_AiFuncMap = nullptr; + g_GameState = nullptr; + g_TweakManager = nullptr; +} + void CMain::AddWorldPaks() { CResLoader* loader = g_ResFactory->GetResLoader(); @@ -431,6 +447,60 @@ void CMain::EnsureWorldPakReady(CAssetId mlvl) /* TODO: Schedule resource list load for World Pak containing mlvl */ } +void CMain::Give(hecl::Console* console, const std::vector& args) +{ + if (!hecl::com_developer->toBoolean()) + { + console->report(hecl::Console::Level::Info, "Cheats are only available in developer mode"); + return; + } + + if (!hecl::com_enableCheats->toBoolean()) + { + console->report(hecl::Console::Level::Info, "Cheats are not enabled"); + return; + } + + if (args.size() < 1 || (!g_GameState || !g_GameState->GetPlayerState())) + return; + + std::string type = args[0]; + athena::utility::tolower(type); + console->report(hecl::Console::Level::Info, "Cheater....., Greatly increasing Metroid encounters, have fun!"); + std::shared_ptr pState = g_GameState->GetPlayerState(); + if (type == "all") + { + for (u32 item = 0; item < u32(CPlayerState::EItemType::Max); ++item) + { + pState->ReInitalizePowerUp(CPlayerState::EItemType(item), + CPlayerState::GetPowerUpMaxValue(CPlayerState::EItemType(item))); + pState->IncrPickup(CPlayerState::EItemType(item), + CPlayerState::GetPowerUpMaxValue(CPlayerState::EItemType(item))); + } + pState->IncrPickup(CPlayerState::EItemType::HealthRefill, 99999); + } + else if (type == "missile") + { + s32 missiles = 250; + if (args.size() == 2) + { + missiles = s32(strtol(args[1].c_str(), nullptr, 10)); + missiles = zeus::clamp(-250, missiles, 250); + } + + u32 curCap = pState->GetItemCapacity(CPlayerState::EItemType::Missiles); + if (missiles > 0 && curCap < u32(missiles)) + { + u32 tmp = ((u32(missiles) / 5) + (missiles % 5)) * 5; + pState->ReInitalizePowerUp(CPlayerState::EItemType::Missiles, tmp); + } + if (missiles > 0) + pState->IncrPickup(CPlayerState::EItemType::Missiles, u32(missiles)); + else + pState->DecrPickup(CPlayerState::EItemType::Missiles, zeus::clamp(0u, u32(abs(missiles)), pState->GetItemAmount(CPlayerState::EItemType::Missiles))); + } +} + void CMain::StreamNewGameState(CBitStreamReader& r, u32 idx) { bool fusionBackup = g_GameState->SystemOptions().GetPlayerFusionSuitActive(); @@ -486,8 +556,7 @@ void CMain::UpdateDiscordPresence(CAssetId worldSTRG) { if (CPlayerState* pState = g_GameState->GetPlayerState().get()) { - u32 itemPercent = u32(std::ceil(pState->CalculateItemCollectionRate() * 100.f / - pState->GetPickupTotal())); + u32 itemPercent = pState->CalculateItemCollectionRate() * 100 / pState->GetPickupTotal(); if (DiscordItemPercent != itemPercent) { DiscordItemPercent = itemPercent; @@ -534,6 +603,9 @@ void CMain::Init(const hecl::Runtime::FileStoreManager& storeMgr, m_cvarMgr = cvarMgr; m_console = std::make_unique(m_cvarMgr); m_console->registerCommand("quit"sv, "Quits the game immediately"sv, ""sv, std::bind(&CMain::quit, this, std::placeholders::_1, std::placeholders::_2)); + m_console->registerCommand("Give"sv, "Gives the player the specified item, maxing it out"sv, ""sv, std::bind(&CMain::Give, this, std::placeholders::_1, std::placeholders::_2)); + + InitializeSubsystems(storeMgr); x128_globalObjects.PostInitialize(); x70_tweaks.RegisterTweaks(m_cvarMgr); @@ -672,6 +744,7 @@ void CMain::ShutdownSubsystems() void CMain::Shutdown() { + m_console->unregisterCommand("Give"); x164_archSupport.reset(); ShutdownSubsystems(); TShader::Shutdown(); diff --git a/Runtime/MP1/MP1.hpp b/Runtime/MP1/MP1.hpp index 966aaa9b5..6f1971a66 100644 --- a/Runtime/MP1/MP1.hpp +++ b/Runtime/MP1/MP1.hpp @@ -101,6 +101,8 @@ public: g_TweakManager = &x150_tweakManager; } + ~CGameGlobalObjects(); + void PostInitialize() { AddPaksAndFactories(); @@ -260,6 +262,7 @@ private: std::vector m_warmupTags; std::vector::iterator m_warmupIt; bool m_needsWarmupClear = false; + bool m_doQuit = false; void InitializeSubsystems(const hecl::Runtime::FileStoreManager& storeMgr); static void InitializeDiscord(); @@ -297,8 +300,8 @@ public: void MemoryCardInitializePump(); - bool CheckReset() { return false; } - bool CheckTerminate() { return false; } + bool CheckReset() { return m_doQuit; } + bool CheckTerminate() { return m_doQuit; } void DrawDebugMetrics(double, CStopWatch&) {} void DoPredrawMetrics() {} void FillInAssetIDs(); @@ -323,7 +326,10 @@ public: size_t GetExpectedIdSize() const { return sizeof(u32); } void quit(hecl::Console*, const std::vector&) { + m_doQuit = true; } + void Give(hecl::Console*, const std::vector&); + hecl::Console* Console() const { return m_console.get(); } }; } diff --git a/Runtime/Particle/CElementGen.cpp b/Runtime/Particle/CElementGen.cpp index f69b9ee0c..52bf256d9 100644 --- a/Runtime/Particle/CElementGen.cpp +++ b/Runtime/Particle/CElementGen.cpp @@ -435,7 +435,7 @@ void CElementGen::UpdateExistingParticles() x25c_activeParticleCount = 0; CParticleGlobals::SetEmitterTime(x74_curFrame); - CParticleGlobals::g_particleAccessParameters = nullptr; + CParticleGlobals::g_particleAccessParameters = &x60_advValues[x25c_activeParticleCount]; for (auto it = x30_particles.begin(); it != x30_particles.end();) { @@ -1276,7 +1276,7 @@ void CElementGen::RenderLines() m_lineRenderer->AddVertex(p1, particle.x34_color, constWidth, {uvs.xMin, uvs.yMin}); m_lineRenderer->AddVertex(p2, particle.x34_color, constWidth, {uvs.xMax, uvs.yMax}); } - else + else if (widt) { float width = 1.f; widt->GetValue(0, width); diff --git a/Runtime/World/CActor.cpp b/Runtime/World/CActor.cpp index 55d43184b..b849df8c5 100644 --- a/Runtime/World/CActor.cpp +++ b/Runtime/World/CActor.cpp @@ -40,7 +40,7 @@ CActor::CActor(TUniqueId uid, bool active, std::string_view name, const CEntityI xd0_thermalMag = params.x64_thermalMag; xd8_nonLoopingSfxHandles.resize(2); xe4_27_notInSortedLists = true; - xe4_28_ = true; + xe4_28_transformDirty = true; xe4_29_actorLightsDirty = true; xe4_31_lightsDirty = true; xe5_27_useInSortedLists = true; @@ -542,7 +542,7 @@ void CActor::SetRotation(const zeus::CQuaternion &q) { x34_transform = q.toTransform(x34_transform.origin); xe4_27_notInSortedLists = true; - xe4_28_ = true; + xe4_28_transformDirty = true; xe4_29_actorLightsDirty = true; } @@ -550,7 +550,7 @@ void CActor::SetTranslation(const zeus::CVector3f& tr) { x34_transform.origin = tr; xe4_27_notInSortedLists = true; - xe4_28_ = true; + xe4_28_transformDirty = true; xe4_29_actorLightsDirty = true; } @@ -558,7 +558,7 @@ void CActor::SetTransform(const zeus::CTransform& tr) { x34_transform = tr; xe4_27_notInSortedLists = true; - xe4_28_ = true; + xe4_28_transformDirty = true; xe4_29_actorLightsDirty = true; } diff --git a/Runtime/World/CActor.hpp b/Runtime/World/CActor.hpp index 5202243d5..7ce23346e 100644 --- a/Runtime/World/CActor.hpp +++ b/Runtime/World/CActor.hpp @@ -55,7 +55,7 @@ protected: { u8 xe4_24_nextNonLoopingSfxHandle : 3; bool xe4_27_notInSortedLists : 1; - bool xe4_28_ : 1; + bool xe4_28_transformDirty : 1; bool xe4_29_actorLightsDirty : 1; bool xe4_30_outOfFrustum : 1; bool xe4_31_lightsDirty : 1; @@ -108,7 +108,7 @@ public: virtual void SetActive(bool active) { xe4_27_notInSortedLists = true; - xe4_28_ = true; + xe4_28_transformDirty = true; xe4_29_actorLightsDirty = true; xe7_29_actorActive = active; CEntity::SetActive(active); diff --git a/Runtime/World/CExplosion.cpp b/Runtime/World/CExplosion.cpp index c934bee7c..67628832e 100644 --- a/Runtime/World/CExplosion.cpp +++ b/Runtime/World/CExplosion.cpp @@ -1,5 +1,9 @@ #include "CExplosion.hpp" +#include "CStateManager.hpp" +#include "CGameLight.hpp" #include "TCastTo.hpp" +#include "Graphics/CBooRenderer.hpp" +#include "GameGlobalObjects.hpp" namespace urde { @@ -13,9 +17,9 @@ CExplosion::CExplosion(const TLockedToken& particle, TUniqueId flags & 0x2 ? CElementGen::EOptionalSystemFlags::Two : CElementGen::EOptionalSystemFlags::One); xf0_particleDesc = particle.GetObj(); - xf4_24_ = flags & 0x4; + xf4_24_renderThermalHot = flags & 0x4; xf4_25_ = true; - xf4_26_ = flags & 0x8; + xf4_26_renderXray = flags & 0x8; xe6_27_thermalVisorFlags = flags & 0x1 ? 1 : 2; xe8_particleGen->SetGlobalTranslation(xf.origin); xe8_particleGen->SetOrientation(xf.getRotation()); @@ -27,4 +31,95 @@ void CExplosion::Accept(IVisitor& visitor) { visitor.Visit(this); } + +void CExplosion::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) +{ + if (msg == EScriptObjectMessage::Deleted) + { + if (xec_explosionLight != kInvalidUniqueId) + mgr.FreeScriptObject(xec_explosionLight); + } + else if (msg == EScriptObjectMessage::Registered) + { + if (xe8_particleGen->SystemHasLight()) + { + xec_explosionLight = mgr.AllocateUniqueId(); + mgr.AddObject(new CGameLight(xec_explosionLight, GetAreaIdAlways(), true, "ExplodePLight_" + x10_name, x34_transform, + GetUniqueId(), xe8_particleGen->GetLight(), 1, /*xf0_particleDesc*/ 0, 0.f)); + } + } + + CActor::AcceptScriptMsg(msg, sender, mgr); + + if (xec_explosionLight != kInvalidUniqueId) + mgr.SendScriptMsgAlways(sender, xec_explosionLight, msg); +} + +void CExplosion::Think(float dt, CStateManager& mgr) +{ + if (xe4_28_transformDirty) + { + xe8_particleGen->SetGlobalTranslation(GetTranslation()); + xe8_particleGen->SetGlobalOrientation(GetTransform().getRotation()); + xe4_28_transformDirty = false; + } + xe8_particleGen->Update(dt); + + if (xec_explosionLight != kInvalidUniqueId) + { + TCastToPtr light = mgr.ObjectById(xec_explosionLight); + if (light && x30_24_active) + light->SetLight(xe8_particleGen->GetLight()); + } + + xf8_time += dt; + + if (xf8_time > 15.f || xe8_particleGen->IsSystemDeletable()) + mgr.FreeScriptObject(GetUniqueId()); +} + +void CExplosion::PreRender(CStateManager& mgr, const zeus::CFrustum& frustum) +{ + CActor::PreRender(mgr, frustum); + xe4_30_outOfFrustum = !xf4_25_ || !frustum.aabbFrustumTest(x9c_renderBounds); +} + +void CExplosion::AddToRenderer(const zeus::CFrustum& frustum, const CStateManager& mgr) const +{ + if (xe4_30_outOfFrustum) + return; + + if (!(xf4_24_renderThermalHot && mgr.GetThermalDrawFlag() == EThermalDrawFlag::Hot) + && !(xf4_26_renderXray && mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay)) + { + g_Renderer->AddParticleGen(*xe8_particleGen.get()); + return; + } + + EnsureRendered(mgr); +} + +void CExplosion::Render(const CStateManager& mgr) const +{ + if (mgr.GetThermalDrawFlag() == EThermalDrawFlag::Hot && xf4_24_renderThermalHot) + { + CElementGen::SetSubtractBlend(true); + CBooModel::SetRenderModelBlack(true); + xe8_particleGen->Render(); + CBooModel::SetRenderModelBlack(false); + CElementGen::SetSubtractBlend(false); + return; + } + + CElementGen::SetSubtractBlend(xf4_24_renderThermalHot); + CGraphics::SetFog(ERglFogMode::PerspLin, 0.f, 74.f, zeus::CColor::skBlack); + xe8_particleGen->Render(); + mgr.SetupFogForArea(GetAreaIdAlways()); + CElementGen::SetSubtractBlend(false); +} + +bool CExplosion::CanRenderUnsorted(const CStateManager &) const +{ + return false; +} } diff --git a/Runtime/World/CExplosion.hpp b/Runtime/World/CExplosion.hpp index 6b4e9aebc..7f3788ec3 100644 --- a/Runtime/World/CExplosion.hpp +++ b/Runtime/World/CExplosion.hpp @@ -11,12 +11,12 @@ namespace urde class CExplosion : public CEffect { std::unique_ptr xe8_particleGen; - TUniqueId xec_ = kInvalidUniqueId; + TUniqueId xec_explosionLight = kInvalidUniqueId; const CGenDescription* xf0_particleDesc; - bool xf4_24_:1; + bool xf4_24_renderThermalHot:1; bool xf4_25_:1; - bool xf4_26_:1; - float xf8_ = 0.f; + bool xf4_26_renderXray:1; + float xf8_time = 0.f; public: CExplosion(const TLockedToken& particle, TUniqueId uid, bool active, @@ -24,6 +24,12 @@ public: u32, const zeus::CVector3f& scale, const zeus::CColor& color); void Accept(IVisitor&); + void AcceptScriptMsg(EScriptObjectMessage, TUniqueId, CStateManager&); + void Think(float, CStateManager&); + void PreRender(CStateManager&, const zeus::CFrustum&); + void AddToRenderer(const zeus::CFrustum&, const CStateManager&) const; + void Render(const CStateManager&) const; + bool CanRenderUnsorted(const CStateManager&) const; }; } diff --git a/hecl b/hecl index 343aae42e..2461e787a 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit 343aae42e2ff945ed5436a3c250901a2101db625 +Subproject commit 2461e787a92af6400b15ef110dc837918c39b4ce