Browse Source

Use unsigned types for player experience and related values

pull/2585/head
ephphatha 5 years ago committed by Anders Jenbo
parent
commit
8f2e94ae4d
  1. 12
      Source/loadsave.cpp
  2. 20
      Source/objects.cpp
  3. 2
      Source/pack.h
  4. 19
      Source/player.cpp
  5. 7
      Source/player.h
  6. 2
      Source/qol/xpbar.cpp

12
Source/loadsave.cpp

@ -409,9 +409,9 @@ void LoadPlayer(LoadHelper *file, int p)
player._pLevel = file->NextLE<int8_t>(); player._pLevel = file->NextLE<int8_t>();
player._pMaxLvl = file->NextLE<int8_t>(); player._pMaxLvl = file->NextLE<int8_t>();
file->Skip(2); // Alignment file->Skip(2); // Alignment
player._pExperience = file->NextLE<int32_t>(); player._pExperience = file->NextLE<uint32_t>();
player._pMaxExp = file->NextLE<int32_t>(); file->Skip<uint32_t>(); // Skip _pMaxExp - unused
player._pNextExper = file->NextLE<int32_t>(); player._pNextExper = file->NextLE<uint32_t>(); // This can be calculated based on pLevel (which in turn could be calculated based on pExperience)
player._pArmorClass = file->NextLE<int8_t>(); player._pArmorClass = file->NextLE<int8_t>();
player._pMagResist = file->NextLE<int8_t>(); player._pMagResist = file->NextLE<int8_t>();
player._pFireResist = file->NextLE<int8_t>(); player._pFireResist = file->NextLE<int8_t>();
@ -1081,9 +1081,9 @@ void SavePlayer(SaveHelper *file, int p)
file->WriteLE<int8_t>(player._pLevel); file->WriteLE<int8_t>(player._pLevel);
file->WriteLE<int8_t>(player._pMaxLvl); file->WriteLE<int8_t>(player._pMaxLvl);
file->Skip(2); // Alignment file->Skip(2); // Alignment
file->WriteLE<int32_t>(player._pExperience); file->WriteLE<uint32_t>(player._pExperience);
file->WriteLE<int32_t>(player._pMaxExp); file->Skip<uint32_t>(); // Skip _pMaxExp
file->WriteLE<int32_t>(player._pNextExper); file->WriteLE<uint32_t>(player._pNextExper);
file->WriteLE<int8_t>(player._pArmorClass); file->WriteLE<int8_t>(player._pArmorClass);
file->WriteLE<int8_t>(player._pMagResist); file->WriteLE<int8_t>(player._pMagResist);
file->WriteLE<int8_t>(player._pFireResist); file->WriteLE<int8_t>(player._pFireResist);

20
Source/objects.cpp

@ -3408,19 +3408,17 @@ bool OperateShrineGlowing(int pnum)
auto &myPlayer = Players[MyPlayerId]; auto &myPlayer = Players[MyPlayerId];
int playerXP = myPlayer._pExperience; // Add 0-5 points to Magic (0.1% of the players XP)
int magicGain = playerXP / 1000; ModifyPlrMag(MyPlayerId, std::min(myPlayer._pExperience / 1000, 5U));
int xpLoss = 0;
if (playerXP > 5000) { // Take 5% of the players experience to offset the bonus, unless they're very low level in which case take all their experience.
magicGain = 5; if (myPlayer._pExperience > 5000)
xpLoss = static_cast<int>(playerXP * 0.95); myPlayer._pExperience = static_cast<uint32_t>(myPlayer._pExperience * 0.95);
} else
ModifyPlrMag(MyPlayerId, magicGain); myPlayer._pExperience = 0;
myPlayer._pExperience = xpLoss;
if (sgOptions.Gameplay.bExperienceBar) { if (sgOptions.Gameplay.bExperienceBar)
force_redraw = 255; force_redraw = 255;
}
CheckStats(Players[pnum]); CheckStats(Players[pnum]);

2
Source/pack.h

@ -46,7 +46,7 @@ struct PkPlayerStruct {
uint8_t pBaseVit; uint8_t pBaseVit;
int8_t pLevel; int8_t pLevel;
uint8_t pStatPts; uint8_t pStatPts;
int32_t pExperience; uint32_t pExperience;
int32_t pGold; int32_t pGold;
int32_t pHPBase; int32_t pHPBase;
int32_t pMaxHPBase; int32_t pMaxHPBase;

19
Source/player.cpp

@ -92,7 +92,7 @@ int BlockBonuses[enum_size<HeroClass>::value] = {
}; };
/** Specifies the experience point limit of each level. */ /** Specifies the experience point limit of each level. */
int ExpLvlsTbl[MAXCHARLEVEL] = { uint32_t ExpLvlsTbl[MAXCHARLEVEL] = {
0, 0,
2000, 2000,
4620, 4620,
@ -2477,7 +2477,6 @@ void CreatePlayer(int playerId, HeroClass c)
player._pMaxLvl = player._pLevel; player._pMaxLvl = player._pLevel;
player._pExperience = 0; player._pExperience = 0;
player._pMaxExp = player._pExperience;
player._pNextExper = ExpLvlsTbl[1]; player._pNextExper = ExpLvlsTbl[1];
player._pArmorClass = 0; player._pArmorClass = 0;
if (player._pClass == HeroClass::Barbarian) { if (player._pClass == HeroClass::Barbarian) {
@ -2647,8 +2646,6 @@ void NextPlrLevel(int pnum)
CalcPlrInv(pnum, true); CalcPlrInv(pnum, true);
} }
#define MAXEXP 2000000000
void AddPlrExperience(int pnum, int lvl, int exp) void AddPlrExperience(int pnum, int lvl, int exp)
{ {
if (pnum != MyPlayerId) { if (pnum != MyPlayerId) {
@ -2665,21 +2662,21 @@ void AddPlrExperience(int pnum, int lvl, int exp)
} }
// Adjust xp based on difference in level between player and monster // Adjust xp based on difference in level between player and monster
exp = std::max(static_cast<int>(exp * (1 + (lvl - player._pLevel) / 10.0)), 0); uint32_t clampedExp = std::max(static_cast<int>(exp * (1 + (lvl - player._pLevel) / 10.0)), 0);
// Prevent power leveling // Prevent power leveling
if (gbIsMultiplayer) { if (gbIsMultiplayer) {
auto clampedPlayerLevel = clamp(static_cast<int>(player._pLevel), 0, 50); const uint32_t clampedPlayerLevel = clamp(static_cast<int>(player._pLevel), 0, 50);
// for low level characters experience gain is capped to 1/20 of current levels xp // 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. // 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.
exp = std::min({ exp, /* level 0-5: */ ExpLvlsTbl[clampedPlayerLevel] / 20, /* level 6-50: */ 200 * clampedPlayerLevel }); clampedExp = std::min({ clampedExp, /* level 0-5: */ ExpLvlsTbl[clampedPlayerLevel] / 20U, /* level 6-50: */ 200U * clampedPlayerLevel });
} }
player._pExperience += exp; constexpr uint32_t MaxExperience = 2000000000U;
if (player._pExperience > MAXEXP || player._pExperience < 0) {
player._pExperience = MAXEXP; // 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
} player._pExperience = std::min(player._pExperience + clampedExp, MaxExperience);
if (sgOptions.Gameplay.bExperienceBar) { if (sgOptions.Gameplay.bExperienceBar) {
force_redraw = 255; force_redraw = 255;

7
Source/player.h

@ -227,9 +227,8 @@ struct PlayerStruct {
int _pManaPer; int _pManaPer;
int8_t _pLevel; int8_t _pLevel;
int8_t _pMaxLvl; int8_t _pMaxLvl;
int _pExperience; uint32_t _pExperience;
int _pMaxExp; uint32_t _pNextExper;
int _pNextExper;
int8_t _pArmorClass; int8_t _pArmorClass;
int8_t _pMagResist; int8_t _pMagResist;
int8_t _pFireResist; int8_t _pFireResist;
@ -603,6 +602,6 @@ extern int StrengthTbl[enum_size<HeroClass>::value];
extern int MagicTbl[enum_size<HeroClass>::value]; extern int MagicTbl[enum_size<HeroClass>::value];
extern int DexterityTbl[enum_size<HeroClass>::value]; extern int DexterityTbl[enum_size<HeroClass>::value];
extern int VitalityTbl[enum_size<HeroClass>::value]; extern int VitalityTbl[enum_size<HeroClass>::value];
extern int ExpLvlsTbl[MAXCHARLEVEL]; extern uint32_t ExpLvlsTbl[MAXCHARLEVEL];
} // namespace devilution } // namespace devilution

2
Source/qol/xpbar.cpp

@ -89,7 +89,7 @@ void DrawXPBar(const Surface &out)
return; return;
} }
const int prevXp = ExpLvlsTbl[charLevel - 1]; const uint64_t prevXp = ExpLvlsTbl[charLevel - 1];
if (player._pExperience < prevXp) if (player._pExperience < prevXp)
return; return;

Loading…
Cancel
Save