From 872270704c44408cbc466526c5e891a839b6c722 Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Thu, 12 Jan 2023 13:16:24 -0600 Subject: [PATCH] Hardmode cleanups (#954) * load values once so that it doesn't check every time don't return, just skip don't realod char * address feedback * don't drop the only item you can't get again * address most feedback * move settings for HC mode * fix comment * claenup whitespace --- dGame/EntityManager.cpp | 11 ++ dGame/EntityManager.h | 11 ++ dGame/dComponents/DestroyableComponent.cpp | 145 +++++++++++---------- dGame/dComponents/DestroyableComponent.h | 3 + 4 files changed, 100 insertions(+), 70 deletions(-) diff --git a/dGame/EntityManager.cpp b/dGame/EntityManager.cpp index 99ead79d..67553b41 100644 --- a/dGame/EntityManager.cpp +++ b/dGame/EntityManager.cpp @@ -18,6 +18,7 @@ #include "Game.h" #include "dLogger.h" #include "MessageIdentifiers.h" +#include "dConfig.h" EntityManager* EntityManager::m_Address = nullptr; @@ -58,6 +59,16 @@ void EntityManager::Initialize() { m_GhostingExcludedZones.end(), dZoneManager::Instance()->GetZoneID().GetMapID() ) == m_GhostingExcludedZones.end(); + + // grab hardcore mode settings and load them with sane defaults + auto hcmode = Game::config->GetValue("hardcore_mode"); + m_HardcoreMode = hcmode.empty() ? false : (hcmode == "1"); + auto hcUscorePercent = Game::config->GetValue("hardcore_lose_uscore_on_death_percent"); + m_HardcoreLoseUscoreOnDeathPercent = hcUscorePercent.empty() ? 10 : std::stoi(hcUscorePercent); + auto hcUscoreMult = Game::config->GetValue("hardcore_uscore_enemies_multiplier"); + m_HardcoreUscoreEnemiesMultiplier = hcUscoreMult.empty() ? 2 : std::stoi(hcUscoreMult); + auto hcDropInv = Game::config->GetValue("hardcore_dropinventory_on_death"); + m_HardcoreDropinventoryOnDeath = hcDropInv.empty() ? false : (hcDropInv == "1"); } EntityManager::~EntityManager() { diff --git a/dGame/EntityManager.h b/dGame/EntityManager.h index 36bc5962..8a930de3 100644 --- a/dGame/EntityManager.h +++ b/dGame/EntityManager.h @@ -78,6 +78,11 @@ public: static bool IsExcludedFromGhosting(LOT lot); + const bool GetHardcoreMode() { return m_HardcoreMode; }; + const uint32_t GetHardcoreLoseUscoreOnDeathPercent() { return m_HardcoreLoseUscoreOnDeathPercent; }; + const bool GetHardcoreDropinventoryOnDeath() { return m_HardcoreDropinventoryOnDeath; }; + const uint32_t GetHardcoreUscoreEnemiesMultiplier() { return m_HardcoreUscoreEnemiesMultiplier; }; + private: static EntityManager* m_Address; //For singleton method static std::vector m_GhostingExcludedZones; @@ -102,6 +107,12 @@ private: // Map of spawnname to entity object ID std::unordered_map m_SpawnPoints; + + // hardcore mode vars + bool m_HardcoreMode; + uint32_t m_HardcoreLoseUscoreOnDeathPercent; + bool m_HardcoreDropinventoryOnDeath; + uint32_t m_HardcoreUscoreEnemiesMultiplier; }; #endif // ENTITYMANAGER_H diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index 0e8ce56e..1455ce58 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -668,77 +668,10 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32 } //check if hardcore mode is enabled - if (Game::config->GetValue("hardcore_mode") == "1") { - //check if this is a player: - if (m_Parent->GetLOT() == 1) { - //get hardcore_lose_uscore_on_death_percent from dconfig: - auto hardcoreLoseUscoreOnDeathPercent = std::stoi(Game::config->GetValue("hardcore_lose_uscore_on_death_percent")); - - //remove hardcore_lose_uscore_on_death_percent from the player's uscore: - auto* character = m_Parent->GetComponent(); - auto uscore = character->GetUScore(); - - auto uscoreToLose = uscore * hardcoreLoseUscoreOnDeathPercent / 100; - character->SetUScore(uscore - uscoreToLose); - - GameMessages::SendModifyLEGOScore(m_Parent, m_Parent->GetSystemAddress(), -uscoreToLose, eLootSourceType::LOOT_SOURCE_MISSION); - - // Reload the player - EntityManager::Instance()->DestructEntity(m_Parent); - EntityManager::Instance()->ConstructEntity(m_Parent); - - auto hardcoreDropinventoryOnDeath = (bool)std::stoi(Game::config->GetValue("hardcore_dropinventory_on_death")); - - if (hardcoreDropinventoryOnDeath == false) return; - - //drop all items from inventory: - auto* inventory = m_Parent->GetComponent(); - - //get the items inventory: - auto items = inventory->GetInventory(eInventoryType::ITEMS); - auto itemMap = items->GetItems(); - for (const auto& item : itemMap) { - //drop the item: - GameMessages::SendDropClientLoot(m_Parent, source, item.second->GetLot(), 0, m_Parent->GetPosition(), item.second->GetCount()); - - item.second->SetCount(0, false, false); - } - - EntityManager::Instance()->SerializeEntity(m_Parent); - - //get character: - auto* chars = m_Parent->GetCharacter(); - if (chars) { - auto coins = chars->GetCoins(); - - //lose all coins: - chars->SetCoins(0, eLootSourceType::LOOT_SOURCE_NONE); - - //drop all coins: - GameMessages::SendDropClientLoot(m_Parent, source, 0, coins, m_Parent->GetPosition(), 0); - } - } else { - //award the player some u-score: - auto* player = EntityManager::Instance()->GetEntity(source); - if (player && player->GetLOT() == 1) { - auto* playerStats = player->GetComponent(); - if (playerStats) { - //get the maximum health from this enemy: - auto maxHealth = GetMaxHealth(); - - //get the u-score to award from dconfig: - auto hardcoreUscoreEnemiesMultiplier = std::stoi(Game::config->GetValue("hardcore_uscore_enemies_multiplier")); - int uscore = maxHealth * hardcoreUscoreEnemiesMultiplier; - - playerStats->SetUScore(playerStats->GetUScore() + uscore); - GameMessages::SendModifyLEGOScore(player, player->GetSystemAddress(), uscore, eLootSourceType::LOOT_SOURCE_MISSION); - - EntityManager::Instance()->SerializeEntity(m_Parent); - } - } - } + if (EntityManager::Instance()->GetHardcoreMode()) { + DoHardcoreModeDrops(source); } - + Smash(source, eKillType::VIOLENT, u"", skillID); } @@ -1045,3 +978,75 @@ void DestroyableComponent::FixStats() { void DestroyableComponent::AddOnHitCallback(const std::function& callback) { m_OnHitCallbacks.push_back(callback); } + +void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source){ + //check if this is a player: + if (m_Parent->IsPlayer()) { + //remove hardcore_lose_uscore_on_death_percent from the player's uscore: + auto* character = m_Parent->GetComponent(); + auto uscore = character->GetUScore(); + + auto uscoreToLose = uscore * (EntityManager::Instance()->GetHardcoreLoseUscoreOnDeathPercent() / 100); + character->SetUScore(uscore - uscoreToLose); + + GameMessages::SendModifyLEGOScore(m_Parent, m_Parent->GetSystemAddress(), -uscoreToLose, eLootSourceType::LOOT_SOURCE_MISSION); + + if (EntityManager::Instance()->GetHardcoreDropinventoryOnDeath()) { + //drop all items from inventory: + auto* inventory = m_Parent->GetComponent(); + if (inventory) { + //get the items inventory: + auto items = inventory->GetInventory(eInventoryType::ITEMS); + if (items){ + auto itemMap = items->GetItems(); + if (!itemMap.empty()){ + for (const auto& item : itemMap) { + //drop the item: + if (!item.second) continue; + // don't drop the thinkng cap + if (item.second->GetLot() == 6086) continue; + GameMessages::SendDropClientLoot(m_Parent, source, item.second->GetLot(), 0, m_Parent->GetPosition(), item.second->GetCount()); + item.second->SetCount(0, false, false); + } + EntityManager::Instance()->SerializeEntity(m_Parent); + } + } + } + } + + //get character: + auto* chars = m_Parent->GetCharacter(); + if (chars) { + auto coins = chars->GetCoins(); + + //lose all coins: + chars->SetCoins(0, eLootSourceType::LOOT_SOURCE_NONE); + + //drop all coins: + GameMessages::SendDropClientLoot(m_Parent, source, LOT_NULL, coins, m_Parent->GetPosition()); + } + + // Reload the player since we can't normally reduce uscore from the server and we want the UI to update + // do this last so we don't get killed.... again + EntityManager::Instance()->DestructEntity(m_Parent); + EntityManager::Instance()->ConstructEntity(m_Parent); + return; + } + + //award the player some u-score: + auto* player = EntityManager::Instance()->GetEntity(source); + if (player && player->IsPlayer()) { + auto* playerStats = player->GetComponent(); + if (playerStats) { + //get the maximum health from this enemy: + auto maxHealth = GetMaxHealth(); + + int uscore = maxHealth * EntityManager::Instance()->GetHardcoreUscoreEnemiesMultiplier(); + + playerStats->SetUScore(playerStats->GetUScore() + uscore); + GameMessages::SendModifyLEGOScore(player, player->GetSystemAddress(), uscore, eLootSourceType::LOOT_SOURCE_MISSION); + + EntityManager::Instance()->SerializeEntity(m_Parent); + } + } +} diff --git a/dGame/dComponents/DestroyableComponent.h b/dGame/dComponents/DestroyableComponent.h index 2736f47c..854144d9 100644 --- a/dGame/dComponents/DestroyableComponent.h +++ b/dGame/dComponents/DestroyableComponent.h @@ -452,6 +452,9 @@ public: void Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd); void Unsubscribe(LWOOBJID scriptObjId); + // handle hardcode mode drops + void DoHardcoreModeDrops(const LWOOBJID source); + private: /** * Whether or not the health should be serialized