From 486f5ca3e8c042e145a24c503e81a45d1741eadc Mon Sep 17 00:00:00 2001 From: ephphatha Date: Sun, 23 Jul 2023 14:07:07 +1000 Subject: [PATCH] Replace ExpLvlsTbl global with helper function --- Source/player.cpp | 15 ++++++++------- Source/playerdat.cpp | 11 ++++++++++- Source/playerdat.hpp | 2 +- Source/qol/xpbar.cpp | 10 +++++----- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/Source/player.cpp b/Source/player.cpp index 84504c32a..0a131d5cc 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -2308,7 +2308,7 @@ void CreatePlayer(Player &player, HeroClass c) player._pMaxManaBase = player._pMana; player._pExperience = 0; - player._pNextExper = ExpLvlsTbl[1]; + player._pNextExper = GetNextExperienceThresholdForLevel(player._pLevel); player._pArmorClass = 0; player._pLightRad = 10; player._pInfraFlag = false; @@ -2397,7 +2397,7 @@ void NextPlrLevel(Player &player) } else { player._pStatPts += 5; } - player._pNextExper = ExpLvlsTbl[std::min(player._pLevel, MaxCharacterLevel - 1)]; + player._pNextExper = GetNextExperienceThresholdForLevel(player._pLevel); int hp = PlayersData[static_cast(player._pClass)].lvlLife; @@ -2447,14 +2447,15 @@ void AddPlrExperience(Player &player, int lvl, int exp) // Prevent power leveling if (gbIsMultiplayer) { - const uint32_t clampedPlayerLevel = std::clamp(static_cast(player._pLevel), 1, MaxCharacterLevel); + // Use a minimum of 1 so level 0 characters can still gain experience + const uint32_t clampedPlayerLevel = static_cast(std::max(static_cast(player._pLevel), 1)); // for low level characters experience gain is capped to 1/20 of current levels xp // for high level characters experience gain is capped to 200 * current level - this is a smaller value than 1/20 of the exp needed for the next level after level 5. - clampedExp = std::min({ clampedExp, /* level 0-5: */ ExpLvlsTbl[clampedPlayerLevel] / 20U, /* level 6-50: */ 200U * clampedPlayerLevel }); + clampedExp = std::min({ clampedExp, /* level 1-5: */ GetNextExperienceThresholdForLevel(clampedPlayerLevel) / 20U, /* level 6-50: */ 200U * clampedPlayerLevel }); } - const uint32_t MaxExperience = ExpLvlsTbl[MaxCharacterLevel - 1]; + const uint32_t MaxExperience = GetNextExperienceThresholdForLevel(MaxCharacterLevel); // Overflow is only possible if a kill grants more than (2^32-1 - MaxExperience) XP in one go, which doesn't happen in normal gameplay. Clamp to experience required to reach max level player._pExperience = std::min(player._pExperience + clampedExp, MaxExperience); @@ -2465,7 +2466,7 @@ void AddPlrExperience(Player &player, int lvl, int exp) // Increase player level if applicable int newLvl = player._pLevel; - while (newLvl < MaxCharacterLevel && player._pExperience >= ExpLvlsTbl[newLvl]) { + while (newLvl < MaxCharacterLevel && player._pExperience >= GetNextExperienceThresholdForLevel(newLvl)) { newLvl++; } if (newLvl != player._pLevel) { @@ -2547,7 +2548,7 @@ void InitPlayer(Player &player, bool firstTime) SpellID s = PlayersData[static_cast(player._pClass)].skill; player._pAblSpells = GetSpellBitmask(s); - player._pNextExper = ExpLvlsTbl[std::min(player._pLevel, MaxCharacterLevel - 1)]; + player._pNextExper = GetNextExperienceThresholdForLevel(player._pLevel); player._pInvincible = false; if (&player == MyPlayer) { diff --git a/Source/playerdat.cpp b/Source/playerdat.cpp index ab7292c83..103cbe83f 100644 --- a/Source/playerdat.cpp +++ b/Source/playerdat.cpp @@ -6,6 +6,8 @@ #include "playerdat.hpp" +#include +#include #include #include "items.h" @@ -15,8 +17,9 @@ namespace devilution { +namespace { /** Specifies the experience point limit of each level. */ -const uint32_t ExpLvlsTbl[MaxCharacterLevel] = { +const std::array ExpLvlsTbl { 0, 2000, 4620, @@ -68,6 +71,12 @@ const uint32_t ExpLvlsTbl[MaxCharacterLevel] = { 1082908612, 1310707109 }; +} // namespace + +uint32_t GetNextExperienceThresholdForLevel(int level) +{ + return ExpLvlsTbl[std::clamp(level, 0, static_cast(ExpLvlsTbl.size()) - 1)]; +} const _sfx_id herosounds[enum_size::value][enum_size::value] = { // clang-format off diff --git a/Source/playerdat.hpp b/Source/playerdat.hpp index 7e10c3af4..3203503db 100644 --- a/Source/playerdat.hpp +++ b/Source/playerdat.hpp @@ -136,7 +136,7 @@ struct PlayerAnimData { }; extern const _sfx_id herosounds[enum_size::value][enum_size::value]; -extern const uint32_t ExpLvlsTbl[MaxCharacterLevel]; +uint32_t GetNextExperienceThresholdForLevel(int level); extern const PlayerData PlayersData[]; extern const PlayerSpriteData PlayersSpriteData[]; extern const PlayerAnimData PlayersAnimData[]; diff --git a/Source/qol/xpbar.cpp b/Source/qol/xpbar.cpp index 647610603..16b962b77 100644 --- a/Source/qol/xpbar.cpp +++ b/Source/qol/xpbar.cpp @@ -85,12 +85,12 @@ void DrawXPBar(const Surface &out) return; } - const uint64_t prevXp = ExpLvlsTbl[charLevel - 1]; + const uint64_t prevXp = GetNextExperienceThresholdForLevel(charLevel - 1); if (player._pExperience < prevXp) return; uint64_t prevXpDelta1 = player._pExperience - prevXp; - uint64_t prevXpDelta = ExpLvlsTbl[charLevel] - prevXp; + uint64_t prevXpDelta = GetNextExperienceThresholdForLevel(charLevel) - prevXp; uint64_t fullBar = BarWidth * prevXpDelta1 / prevXpDelta; // Figure out how much to fill the last pixel of the XP bar, to make it gradually appear with gained XP @@ -128,7 +128,7 @@ bool CheckXPBarInfo() // Show a maximum level indicator for max level players. InfoColor = UiFlags::ColorWhitegold; - AddPanelString(fmt::format(fmt::runtime(_("Experience: {:s}")), FormatInteger(ExpLvlsTbl[charLevel - 1]))); + AddPanelString(fmt::format(fmt::runtime(_("Experience: {:s}")), FormatInteger(GetNextExperienceThresholdForLevel(charLevel - 1)))); AddPanelString(_("Maximum Level")); return true; @@ -137,8 +137,8 @@ bool CheckXPBarInfo() InfoColor = UiFlags::ColorWhite; AddPanelString(fmt::format(fmt::runtime(_("Experience: {:s}")), FormatInteger(player._pExperience))); - AddPanelString(fmt::format(fmt::runtime(_("Next Level: {:s}")), FormatInteger(ExpLvlsTbl[charLevel]))); - AddPanelString(fmt::format(fmt::runtime(_("{:s} to Level {:d}")), FormatInteger(ExpLvlsTbl[charLevel] - player._pExperience), charLevel + 1)); + AddPanelString(fmt::format(fmt::runtime(_("Next Level: {:s}")), FormatInteger(GetNextExperienceThresholdForLevel(charLevel)))); + AddPanelString(fmt::format(fmt::runtime(_("{:s} to Level {:d}")), FormatInteger(GetNextExperienceThresholdForLevel(charLevel) - player._pExperience), charLevel + 1)); return true; }