From 32b3333bfbb9186b2faae2b25a845e7cba6fb8cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pir=C3=B3g?= <69601940+aetn23@users.noreply.github.com> Date: Sun, 28 Aug 2022 17:35:58 +0200 Subject: [PATCH] Exp overflow fix (#5070) --- Source/loadsave.cpp | 5 +++-- Source/monster.cpp | 8 +------- Source/monster.h | 25 ++++++++++++++++++++++++- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index 69da533b1..6ca3babf4 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -27,6 +27,7 @@ #include "lighting.h" #include "menu.h" #include "missiles.h" +#include "monster.h" #include "mpq/mpq_writer.hpp" #include "pfile.h" #include "qol/stash.h" @@ -632,7 +633,7 @@ void LoadMonster(LoadHelper *file, Monster &monster) monster.whoHit = file->NextLE(); monster.level = file->NextLE(); file->Skip(1); // Alignment - monster.exp = file->NextLE(); + file->Skip(2); // Skip exp - now calculated from monstdat when the monster dies if (monster.isPlayerMinion()) // Don't skip for golems monster.toHit = file->NextLE(); @@ -1398,7 +1399,7 @@ void SaveMonster(SaveHelper *file, Monster &monster) file->WriteLE(monster.whoHit); file->WriteLE(monster.level); file->Skip(1); // Alignment - file->WriteLE(monster.exp); + file->WriteLE(static_cast(std::min(std::numeric_limits::max(), monster.exp(sgGameInitInfo.nDifficulty)))); file->WriteLE(static_cast(std::min(monster.toHit, std::numeric_limits::max()))); // For backwards compatibility file->WriteLE(monster.minDamage); diff --git a/Source/monster.cpp b/Source/monster.cpp index 6edfa73d4..10a44b1a8 100644 --- a/Source/monster.cpp +++ b/Source/monster.cpp @@ -156,7 +156,6 @@ void InitMonster(Monster &monster, Direction rd, size_t typeIndex, Point positio monster.rndItemSeed = AdvanceRndSeed(); monster.aiSeed = AdvanceRndSeed(); monster.whoHit = 0; - monster.exp = monster.data().exp; monster.toHit = monster.data().toHit; monster.minDamage = monster.data().minDamage; monster.maxDamage = monster.data().maxDamage; @@ -185,7 +184,6 @@ void InitMonster(Monster &monster, Direction rd, size_t typeIndex, Point positio monster.maxHitPoints += 64; monster.hitPoints = monster.maxHitPoints; monster.level += 15; - monster.exp = 2 * (monster.exp + 1000); monster.toHit += NightmareToHitBonus; monster.minDamage = 2 * (monster.minDamage + 2); monster.maxDamage = 2 * (monster.maxDamage + 2); @@ -201,7 +199,6 @@ void InitMonster(Monster &monster, Direction rd, size_t typeIndex, Point positio monster.maxHitPoints += 192; monster.hitPoints = monster.maxHitPoints; monster.level += 30; - monster.exp = 4 * (monster.exp + 1000); monster.toHit += HellToHitBonus; monster.minDamage = 4 * monster.minDamage + 6; monster.maxDamage = 4 * monster.maxDamage + 6; @@ -3108,7 +3105,6 @@ void PrepareUniqueMonst(Monster &monster, UniqueMonsterType monsterType, size_t monster.level = monster.data().level + 5; } - monster.exp *= 2; monster.maxHitPoints = uniqueMonsterData.mmaxhp << 6; if (!gbIsMultiplayer) @@ -3148,7 +3144,6 @@ void PrepareUniqueMonst(Monster &monster, UniqueMonsterType monsterType, size_t monster.maxHitPoints += 64; monster.level += 15; monster.hitPoints = monster.maxHitPoints; - monster.exp = 2 * (monster.exp + 1000); monster.minDamage = 2 * (monster.minDamage + 2); monster.maxDamage = 2 * (monster.maxDamage + 2); monster.minDamageSpecial = 2 * (monster.minDamageSpecial + 2); @@ -3161,7 +3156,6 @@ void PrepareUniqueMonst(Monster &monster, UniqueMonsterType monsterType, size_t monster.maxHitPoints += 192; monster.level += 30; monster.hitPoints = monster.maxHitPoints; - monster.exp = 4 * (monster.exp + 1000); monster.minDamage = 4 * monster.minDamage + 6; monster.maxDamage = 4 * monster.maxDamage + 6; monster.minDamageSpecial = 4 * monster.minDamageSpecial + 6; @@ -3663,7 +3657,7 @@ void M_StartHit(Monster &monster, const Player &player, int dam) void MonsterDeath(Monster &monster, Direction md, bool sendmsg) { if (!monster.isPlayerMinion()) - AddPlrMonstExper(monster.level, monster.exp, monster.whoHit); + AddPlrMonstExper(monster.level, monster.exp(sgGameInitInfo.nDifficulty), monster.whoHit); MonsterKillCounts[monster.type().type]++; monster.hitPoints = 0; diff --git a/Source/monster.h b/Source/monster.h index cbc47f007..4d0115467 100644 --- a/Source/monster.h +++ b/Source/monster.h @@ -195,7 +195,7 @@ struct Monster { // note: missing field _mAFNum uint32_t rndItemSeed; /** Seed used to determine AI behaviour/sync sounds in multiplayer games? */ uint32_t aiSeed; - uint16_t exp; + uint16_t toHit; uint16_t toHitSpecial; uint16_t resistance; @@ -317,6 +317,29 @@ struct Monster { // note: missing field _mAFNum return pgettext("monster", data().name); } + /** + * @brief Calculates monster's experience points. + * Fetches base exp value from @p MonstersData array. + * @param difficulty - difficulty on which calculation is performed + * @return Monster's experience points, including bonuses from difficulty and monster being unique + */ + unsigned int exp(_difficulty difficulty) const + { + unsigned int monsterExp = data().exp; + + if (difficulty == DIFF_NIGHTMARE) { + monsterExp = 2 * (monsterExp + 1000); + } else if (difficulty == DIFF_HELL) { + monsterExp = 4 * (monsterExp + 1000); + } + + if (isUnique()) { + monsterExp *= 2; + } + + return monsterExp; + } + /** * @brief Returns the network identifier for this monster *