diff --git a/dGame/EntityManager.cpp b/dGame/EntityManager.cpp index f7faa5f1..026fc02a 100644 --- a/dGame/EntityManager.cpp +++ b/dGame/EntityManager.cpp @@ -52,23 +52,41 @@ std::vector EntityManager::m_GhostingExcludedLOTs = { 4967 }; +template +void ParseDelimSetting(std::set& setting, const std::string_view settingName, const char delim = ',') { + const auto str = Game::config->GetValue(settingName.data()); + setting.clear(); + for (const auto& strVal : GeneralUtils::SplitString(str, delim)) { + const auto val = GeneralUtils::TryParse(strVal); + if (val) { + setting.insert(val.value()); + } + } +} + void EntityManager::ReloadConfig() { 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); + m_HardcoreLoseUscoreOnDeathPercent = hcUscorePercent.empty() ? 10 : GeneralUtils::TryParse(hcUscorePercent).value_or(10); auto hcUscoreMult = Game::config->GetValue("hardcore_uscore_enemies_multiplier"); - m_HardcoreUscoreEnemiesMultiplier = hcUscoreMult.empty() ? 2 : std::stoi(hcUscoreMult); + m_HardcoreUscoreEnemiesMultiplier = hcUscoreMult.empty() ? 2 : GeneralUtils::TryParse(hcUscoreMult).value_or(2); auto hcDropInv = Game::config->GetValue("hardcore_dropinventory_on_death"); m_HardcoreDropinventoryOnDeath = hcDropInv.empty() ? false : (hcDropInv == "1"); - auto hcExcludedItemDrops = Game::config->GetValue("hardcore_excluded_item_drops"); - m_HardcoreExcludedItemDrops.clear(); - for (const auto& strLot : GeneralUtils::SplitString(hcExcludedItemDrops, ',')) { - const auto lot = GeneralUtils::TryParse(strLot); - if (lot) { - m_HardcoreExcludedItemDrops.insert(lot.value()); - } - } + ParseDelimSetting(m_HardcoreExcludedItemDrops, "hardcore_excluded_item_drops"); + + // We don't need to save the worlds, just need to check if this one is in the list + std::set worlds; + ParseDelimSetting(worlds, "hardcore_uscore_reduced_worlds"); + m_HardcoreUscoreReduced = worlds.contains(Game::zoneManager->GetZoneID().GetMapID()); + + ParseDelimSetting(m_HardcoreUscoreReducedLots, "hardcore_uscore_reduced_lots"); + ParseDelimSetting(m_HardcoreUscoreExcludedEnemies, "hardcore_uscore_excluded_enemies"); + ParseDelimSetting(m_HardcoreDisabledWorlds, "hardcore_disabled_worlds"); + + auto hcXpReduction = Game::config->GetValue("hardcore_uscore_reduction"); + m_HardcoreUscoreReduction = hcXpReduction.empty() ? 1.0f : GeneralUtils::TryParse(hcXpReduction).value_or(1.0f); + m_HardcoreMode = GetHardcoreDisabledWorlds().contains(Game::zoneManager->GetZoneID().GetMapID()) ? false : m_HardcoreMode; } void EntityManager::Initialize() { diff --git a/dGame/EntityManager.h b/dGame/EntityManager.h index 066ebb66..549c922e 100644 --- a/dGame/EntityManager.h +++ b/dGame/EntityManager.h @@ -76,6 +76,11 @@ public: const bool GetHardcoreDropinventoryOnDeath() { return m_HardcoreDropinventoryOnDeath; }; const uint32_t GetHardcoreUscoreEnemiesMultiplier() { return m_HardcoreUscoreEnemiesMultiplier; }; const std::set& GetHardcoreExcludedItemDrops() { return m_HardcoreExcludedItemDrops; }; + const float& GetHardcoreUscoreReduction() const { return m_HardcoreUscoreReduction; }; + bool GetHardcoreUscoreReduced() const { return m_HardcoreUscoreReduced; }; + const std::set& GetHardcoreUscoreReducedLots() const { return m_HardcoreUscoreReducedLots; }; + const std::set& GetHardcoreUscoreExcludedEnemies() const { return m_HardcoreUscoreExcludedEnemies; }; + const std::set& GetHardcoreDisabledWorlds() const { return m_HardcoreDisabledWorlds; }; // Messaging bool SendMessage(GameMessages::GameMsg& msg) const; @@ -115,6 +120,11 @@ private: bool m_HardcoreDropinventoryOnDeath; uint32_t m_HardcoreUscoreEnemiesMultiplier; std::set m_HardcoreExcludedItemDrops; + float m_HardcoreUscoreReduction{}; + bool m_HardcoreUscoreReduced{}; + std::set m_HardcoreUscoreReducedLots{}; + std::set m_HardcoreUscoreExcludedEnemies{}; + std::set m_HardcoreDisabledWorlds{}; }; #endif // ENTITYMANAGER_H diff --git a/dGame/dComponents/DestroyableComponent.cpp b/dGame/dComponents/DestroyableComponent.cpp index 18319a3e..512ac150 100644 --- a/dGame/dComponents/DestroyableComponent.cpp +++ b/dGame/dComponents/DestroyableComponent.cpp @@ -667,11 +667,6 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32 return; } - //check if hardcore mode is enabled - if (Game::entityManager->GetHardcoreMode()) { - DoHardcoreModeDrops(source); - } - Smash(source, eKillType::VIOLENT, u"", skillID); } @@ -699,6 +694,11 @@ void DestroyableComponent::NotifySubscribers(Entity* attacker, uint32_t damage) } void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType, const std::u16string& deathType, uint32_t skillID) { + //check if hardcore mode is enabled + if (Game::entityManager->GetHardcoreMode()) { + DoHardcoreModeDrops(source); + } + if (m_iHealth > 0) { SetArmor(0); SetHealth(0); @@ -1026,13 +1026,19 @@ void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source) { //award the player some u-score: auto* player = Game::entityManager->GetEntity(source); if (player && player->IsPlayer()) { + const auto lot = m_Parent->GetLOT(); auto* playerStats = player->GetComponent(); - if (playerStats && GetMaxHealth() > 0) { + if (playerStats && GetMaxHealth() > 0 && !Game::entityManager->GetHardcoreUscoreExcludedEnemies().contains(lot)) { //get the maximum health from this enemy: auto maxHealth = GetMaxHealth(); + const auto uscoreMultiplier = Game::entityManager->GetHardcoreUscoreEnemiesMultiplier(); + const bool isUscoreReducedLot = + Game::entityManager->GetHardcoreUscoreReducedLots().contains(lot) || + Game::entityManager->GetHardcoreUscoreReduced(); + const auto uscoreReduction = isUscoreReducedLot ? Game::entityManager->GetHardcoreUscoreReduction() : 1.0f; - int uscore = maxHealth * Game::entityManager->GetHardcoreUscoreEnemiesMultiplier(); - LOG("Rewarding player %llu with %i uscore for killing enemy %i", player->GetObjectID(), uscore, m_Parent->GetLOT()); + int uscore = maxHealth * Game::entityManager->GetHardcoreUscoreEnemiesMultiplier() * uscoreReduction; + LOG("Rewarding player %llu with %i uscore for killing enemy %i", player->GetObjectID(), uscore, lot); playerStats->SetUScore(playerStats->GetUScore() + uscore); GameMessages::SendModifyLEGOScore(player, player->GetSystemAddress(), uscore, eLootSourceType::MISSION); diff --git a/resources/worldconfig.ini b/resources/worldconfig.ini index 3579be89..9631183a 100644 --- a/resources/worldconfig.ini +++ b/resources/worldconfig.ini @@ -83,3 +83,19 @@ auto_reject_empty_properties=0 # comma delimited list of items to not drop in hardcore mode hardcore_excluded_item_drops=6086,7044 + +# Reduces the UScore gained from the below uscore_reduction config options by x (i.e. uscoreGained * hardcore_uscore_reduction) +hardcore_uscore_reduction= + +# Any given enemy will only have its uscore gain reduced 1 time +# Worlds that should have their uscore reduction applied at a global level (i.e. for worlds with lots of skeletons) +hardcore_uscore_reduced_worlds= + +# Specific LOTs that should have their uscore reduced (i.e. for worlds with a mix of skeletons and normal enemies) +hardcore_uscore_reduced_lots= + +# Excludes this comma delimited list of LOTs from giving UScore in hardcore mode +hardcore_uscore_excluded_enemies= + +# Disables hardcore mode for specific worlds, if hardcore is enabled +hardcore_disabled_worlds=