From 52ce2af7c5eca2b5ff6a5965405f4307e6ad7b24 Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Sun, 3 Nov 2024 15:24:48 -0500 Subject: [PATCH 01/14] Make illegal items unusable --- Source/CMakeLists.txt | 2 + Source/common/validation.cpp | 121 +++++++++++++++++++++++++++++++++++ Source/common/validation.h | 17 +++++ Source/items.cpp | 28 +++++++- Source/msg.cpp | 2 +- Source/pack.cpp | 104 +----------------------------- Source/pack.h | 4 -- Source/player.h | 17 +++++ 8 files changed, 185 insertions(+), 110 deletions(-) create mode 100644 Source/common/validation.cpp create mode 100644 Source/common/validation.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index f291841044c..35c734a1bd1 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -55,6 +55,8 @@ set(libdevilutionx_SRCS towners.cpp track.cpp + common/validation.cpp + controls/axis_direction.cpp controls/controller.cpp controls/controller_buttons.cpp diff --git a/Source/common/validation.cpp b/Source/common/validation.cpp new file mode 100644 index 00000000000..25367d7bcf3 --- /dev/null +++ b/Source/common/validation.cpp @@ -0,0 +1,121 @@ +/** + * @file common/validation.cpp + * + * Implementation of functions for validation of player and item data. + */ + +#include "common/validation.h" + +#include + +#include "items.h" +#include "monstdat.h" + +namespace devilution { + +namespace { + +bool hasMultipleFlags(uint16_t flags) +{ + return (flags & (flags - 1)) > 0; +} + +} // namespace + +bool IsCreationFlagComboValid(uint16_t iCreateInfo) +{ + iCreateInfo = iCreateInfo & ~CF_LEVEL; + const bool isTownItem = (iCreateInfo & CF_TOWN) != 0; + const bool isPregenItem = (iCreateInfo & CF_PREGEN) != 0; + const bool isUsefulItem = (iCreateInfo & CF_USEFUL) == CF_USEFUL; + + if (isPregenItem) { + // Pregen flags are discarded when an item is picked up, therefore impossible to have in the inventory + return false; + } + if (isUsefulItem && (iCreateInfo & ~CF_USEFUL) != 0) + return false; + if (isTownItem && hasMultipleFlags(iCreateInfo)) { + // Items from town can only have 1 towner flag + return false; + } + return true; +} + +bool IsTownItemValid(uint16_t iCreateInfo, uint8_t maxCharacterLevel) +{ + const uint8_t level = iCreateInfo & CF_LEVEL; + const bool isBoyItem = (iCreateInfo & CF_BOY) != 0; + const uint8_t maxTownItemLevel = 30; + + // Wirt items in multiplayer are equal to the level of the player, therefore they cannot exceed the max character level + if (isBoyItem && level <= maxCharacterLevel) + return true; + + return level <= maxTownItemLevel; +} + +bool IsUniqueMonsterItemValid(uint16_t iCreateInfo, uint32_t dwBuff) +{ + const uint8_t level = iCreateInfo & CF_LEVEL; + + // Check all unique monster levels to see if they match the item level + for (const UniqueMonsterData &uniqueMonsterData : UniqueMonstersData) { + const auto &uniqueMonsterLevel = static_cast(MonstersData[uniqueMonsterData.mtype].level); + + if (IsAnyOf(uniqueMonsterData.mtype, MT_DEFILER, MT_NAKRUL, MT_HORKDMN)) { + // These monsters don't use their mlvl for item generation + continue; + } + + if (level == uniqueMonsterLevel) { + // If the ilvl matches the mlvl, we confirm the item is legitimate + return true; + } + } + + return false; +} + +bool IsDungeonItemValid(uint16_t iCreateInfo, uint32_t dwBuff) +{ + const uint8_t level = iCreateInfo & CF_LEVEL; + const bool isHellfireItem = (dwBuff & CF_HELLFIRE) != 0; + + // Check all monster levels to see if they match the item level + for (int16_t i = 0; i < static_cast(NUM_MTYPES); i++) { + const auto &monsterData = MonstersData[i]; + auto monsterLevel = static_cast(monsterData.level); + + if (i != MT_DIABLO && monsterData.availability == MonsterAvailability::Never) { + // Skip monsters that are unable to appear in the game + continue; + } + + if (i == MT_DIABLO && !isHellfireItem) { + // Adjust The Dark Lord's mlvl if the item isn't a Hellfire item to match the Diablo mlvl + monsterLevel -= 15; + } + + if (level == monsterLevel) { + // If the ilvl matches the mlvl, we confirm the item is legitimate + return true; + } + } + + if (isHellfireItem) { + uint8_t hellfireMaxDungeonLevel = 24; + + // Hellfire adjusts the currlevel minus 7 in dungeon levels 20-24 for generating items + hellfireMaxDungeonLevel -= 7; + return level <= (hellfireMaxDungeonLevel * 2); + } + + uint8_t diabloMaxDungeonLevel = 16; + + // Diablo doesn't have containers that drop items in dungeon level 16, therefore we decrement by 1 + diabloMaxDungeonLevel--; + return level <= (diabloMaxDungeonLevel * 2); +} + +} // namespace devilution diff --git a/Source/common/validation.h b/Source/common/validation.h new file mode 100644 index 00000000000..9aaf5396118 --- /dev/null +++ b/Source/common/validation.h @@ -0,0 +1,17 @@ +/** + * @file common/validation.h + * + * Interface of functions for validation of player and item data. + */ +#pragma once + +#include + +namespace devilution { + +bool IsCreationFlagComboValid(uint16_t iCreateInfo); +bool IsTownItemValid(uint16_t iCreateInfo, uint8_t maxCharacterLevel); +bool IsUniqueMonsterItemValid(uint16_t iCreateInfo, uint32_t dwBuff); +bool IsDungeonItemValid(uint16_t iCreateInfo, uint32_t dwBuff); + +} // namespace devilution diff --git a/Source/items.cpp b/Source/items.cpp index 96c1f1d9475..cae27125502 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -512,13 +512,35 @@ void CalcSelfItems(Player &player) const int currdex = std::max(0, da + player._pBaseDex); changeflag = false; + // Iterate over equipped items and remove stat bonuses if they are not valid for (Item &equipment : EquippedPlayerItemsRange(player)) { if (!equipment._iStatFlag) continue; - if (currstr >= equipment._iMinStr - && currmag >= equipment._iMinMag - && currdex >= equipment._iMinDex) + bool isValid = true; + + if (equipment.IDidx != IDI_GOLD) { + if (!IsCreationFlagComboValid(equipment._iCreateInfo)) + isValid = false; + } + + if ((equipment._iCreateInfo & CF_TOWN) != 0) { + if (!IsTownItemValid(equipment._iCreateInfo, player.getMaxCharacterLevel())) + isValid = false; + } else if ((equipment._iCreateInfo & CF_USEFUL) == CF_UPER15) { + if (!IsUniqueMonsterItemValid(equipment._iCreateInfo, equipment.dwBuff)) + isValid = false; + } else { + if (!IsDungeonItemValid(equipment._iCreateInfo, equipment.dwBuff)) + isValid = false; + } + + if (currstr < equipment._iMinStr + && currmag < equipment._iMinMag + && currdex < equipment._iMinDex) + isValid = false; + + if (isValid) continue; changeflag = true; diff --git a/Source/msg.cpp b/Source/msg.cpp index cbcfd6bcb31..5d67263c950 100644 --- a/Source/msg.cpp +++ b/Source/msg.cpp @@ -1044,7 +1044,7 @@ bool IsPItemValid(const TCmdPItem &message, const Player &player) if (idx != IDI_GOLD) ValidateField(creationFlags, IsCreationFlagComboValid(creationFlags)); if ((creationFlags & CF_TOWN) != 0) - ValidateField(creationFlags, IsTownItemValid(creationFlags, player)); + ValidateField(creationFlags, IsTownItemValid(creationFlags, player.getMaxCharacterLevel())); else if ((creationFlags & CF_USEFUL) == CF_UPER15) ValidateFields(creationFlags, dwBuff, IsUniqueMonsterItemValid(creationFlags, dwBuff)); else if ((dwBuff & CF_HELLFIRE) != 0 && AllItemsList[idx].iMiscId == IMISC_BOOK) diff --git a/Source/pack.cpp b/Source/pack.cpp index d1c0f37c2c6..4667bcde60d 100644 --- a/Source/pack.cpp +++ b/Source/pack.cpp @@ -7,6 +7,7 @@ #include +#include "common/validation.h" #include "engine/random.hpp" #include "init.h" #include "loadsave.h" @@ -75,109 +76,8 @@ void VerifyGoldSeeds(Player &player) } } -bool hasMultipleFlags(uint16_t flags) -{ - return (flags & (flags - 1)) > 0; -} - } // namespace -bool IsCreationFlagComboValid(uint16_t iCreateInfo) -{ - iCreateInfo = iCreateInfo & ~CF_LEVEL; - const bool isTownItem = (iCreateInfo & CF_TOWN) != 0; - const bool isPregenItem = (iCreateInfo & CF_PREGEN) != 0; - const bool isUsefulItem = (iCreateInfo & CF_USEFUL) == CF_USEFUL; - - if (isPregenItem) { - // Pregen flags are discarded when an item is picked up, therefore impossible to have in the inventory - return false; - } - if (isUsefulItem && (iCreateInfo & ~CF_USEFUL) != 0) - return false; - if (isTownItem && hasMultipleFlags(iCreateInfo)) { - // Items from town can only have 1 towner flag - return false; - } - return true; -} - -bool IsTownItemValid(uint16_t iCreateInfo, const Player &player) -{ - const uint8_t level = iCreateInfo & CF_LEVEL; - const bool isBoyItem = (iCreateInfo & CF_BOY) != 0; - const uint8_t maxTownItemLevel = 30; - - // Wirt items in multiplayer are equal to the level of the player, therefore they cannot exceed the max character level - if (isBoyItem && level <= player.getMaxCharacterLevel()) - return true; - - return level <= maxTownItemLevel; -} - -bool IsUniqueMonsterItemValid(uint16_t iCreateInfo, uint32_t dwBuff) -{ - const uint8_t level = iCreateInfo & CF_LEVEL; - - // Check all unique monster levels to see if they match the item level - for (const UniqueMonsterData &uniqueMonsterData : UniqueMonstersData) { - const auto &uniqueMonsterLevel = static_cast(MonstersData[uniqueMonsterData.mtype].level); - - if (IsAnyOf(uniqueMonsterData.mtype, MT_DEFILER, MT_NAKRUL, MT_HORKDMN)) { - // These monsters don't use their mlvl for item generation - continue; - } - - if (level == uniqueMonsterLevel) { - // If the ilvl matches the mlvl, we confirm the item is legitimate - return true; - } - } - - return false; -} - -bool IsDungeonItemValid(uint16_t iCreateInfo, uint32_t dwBuff) -{ - const uint8_t level = iCreateInfo & CF_LEVEL; - const bool isHellfireItem = (dwBuff & CF_HELLFIRE) != 0; - - // Check all monster levels to see if they match the item level - for (int16_t i = 0; i < static_cast(NUM_MTYPES); i++) { - const auto &monsterData = MonstersData[i]; - auto monsterLevel = static_cast(monsterData.level); - - if (i != MT_DIABLO && monsterData.availability == MonsterAvailability::Never) { - // Skip monsters that are unable to appear in the game - continue; - } - - if (i == MT_DIABLO && !isHellfireItem) { - // Adjust The Dark Lord's mlvl if the item isn't a Hellfire item to match the Diablo mlvl - monsterLevel -= 15; - } - - if (level == monsterLevel) { - // If the ilvl matches the mlvl, we confirm the item is legitimate - return true; - } - } - - if (isHellfireItem) { - uint8_t hellfireMaxDungeonLevel = 24; - - // Hellfire adjusts the currlevel minus 7 in dungeon levels 20-24 for generating items - hellfireMaxDungeonLevel -= 7; - return level <= (hellfireMaxDungeonLevel * 2); - } - - uint8_t diabloMaxDungeonLevel = 16; - - // Diablo doesn't have containers that drop items in dungeon level 16, therefore we decrement by 1 - diabloMaxDungeonLevel--; - return level <= (diabloMaxDungeonLevel * 2); -} - bool RecreateHellfireSpellBook(const Player &player, const TItem &packedItem, Item *item) { Item spellBook {}; @@ -545,7 +445,7 @@ bool UnPackNetItem(const Player &player, const ItemNetPack &packedItem, Item &it if (idx != IDI_GOLD) ValidateField(creationFlags, IsCreationFlagComboValid(creationFlags)); if ((creationFlags & CF_TOWN) != 0) - ValidateField(creationFlags, IsTownItemValid(creationFlags, player)); + ValidateField(creationFlags, IsTownItemValid(creationFlags, player.getMaxCharacterLevel())); else if ((creationFlags & CF_USEFUL) == CF_UPER15) ValidateFields(creationFlags, dwBuff, IsUniqueMonsterItemValid(creationFlags, dwBuff)); else if ((dwBuff & CF_HELLFIRE) != 0 && AllItemsList[idx].iMiscId == IMISC_BOOK) diff --git a/Source/pack.h b/Source/pack.h index 4dd20121272..460e2471d18 100644 --- a/Source/pack.h +++ b/Source/pack.h @@ -142,10 +142,6 @@ struct PlayerNetPack { }; #pragma pack(pop) -bool IsCreationFlagComboValid(uint16_t iCreateInfo); -bool IsTownItemValid(uint16_t iCreateInfo, const Player &player); -bool IsUniqueMonsterItemValid(uint16_t iCreateInfo, uint32_t dwBuff); -bool IsDungeonItemValid(uint16_t iCreateInfo, uint32_t dwBuff); bool RecreateHellfireSpellBook(const Player &player, const TItem &packedItem, Item *item = nullptr); void PackPlayer(PlayerPack &pPack, const Player &player); void UnPackPlayer(const PlayerPack &pPack, Player &player); diff --git a/Source/player.h b/Source/player.h index 2a6a1d6b194..d8610df176c 100644 --- a/Source/player.h +++ b/Source/player.h @@ -11,6 +11,7 @@ #include #include +#include "common/validation.h" #include "diablo.h" #include "engine.h" #include "engine/actor_position.hpp" @@ -400,6 +401,22 @@ struct Player { bool CanUseItem(const Item &item) const { + if (item.IDidx != IDI_GOLD) { + if (!IsCreationFlagComboValid(item._iCreateInfo)) + return false; + } + + if ((item._iCreateInfo & CF_TOWN) != 0) { + if (!IsTownItemValid(item._iCreateInfo, getMaxCharacterLevel())) + return false; + } else if ((item._iCreateInfo & CF_USEFUL) == CF_UPER15) { + if (!IsUniqueMonsterItemValid(item._iCreateInfo, item.dwBuff)) + return false; + } else { + if (!IsDungeonItemValid(item._iCreateInfo, item.dwBuff)) + return false; + } + return _pStrength >= item._iMinStr && _pMagic >= item._iMinMag && _pDexterity >= item._iMinDex; From a289bffb77c3772464c9dd00977864f0871a4082 Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Sun, 3 Nov 2024 16:11:17 -0500 Subject: [PATCH 02/14] Fixes --- Source/items.cpp | 4 ++-- test/player_test.cpp | 1 + test/writehero_test.cpp | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Source/items.cpp b/Source/items.cpp index cae27125502..b7f0cf44f04 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -536,8 +536,8 @@ void CalcSelfItems(Player &player) } if (currstr < equipment._iMinStr - && currmag < equipment._iMinMag - && currdex < equipment._iMinDex) + || currmag < equipment._iMinMag + || currdex < equipment._iMinDex) isValid = false; if (isValid) diff --git a/test/player_test.cpp b/test/player_test.cpp index 40dec523fac..bda987d3a6e 100644 --- a/test/player_test.cpp +++ b/test/player_test.cpp @@ -189,6 +189,7 @@ TEST(Player, CreatePlayer) ASSERT_TRUE(HaveSpawn() || HaveDiabdat()); LoadPlayerDataFiles(); + LoadMonsterData(); LoadItemData(); Players.resize(1); CreatePlayer(Players[0], HeroClass::Rogue); diff --git a/test/writehero_test.cpp b/test/writehero_test.cpp index adef0be6db6..e2c483d1d87 100644 --- a/test/writehero_test.cpp +++ b/test/writehero_test.cpp @@ -386,6 +386,7 @@ TEST(Writehero, pfile_write_hero) LoadSpellData(); LoadPlayerDataFiles(); + LoadMonsterData(); LoadItemData(); _uiheroinfo info {}; info.heroclass = HeroClass::Rogue; From 5d6e93f5e0fd9a623be51ecdf223a0ac082a5ac9 Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Mon, 11 Nov 2024 21:41:35 -0500 Subject: [PATCH 03/14] common -> items --- Source/CMakeLists.txt | 4 ++-- Source/{common => items}/validation.cpp | 4 ++-- Source/{common => items}/validation.h | 2 +- Source/pack.cpp | 2 +- Source/player.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) rename Source/{common => items}/validation.cpp (94%) rename Source/{common => items}/validation.h (90%) diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 35c734a1bd1..ab806098763 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -55,8 +55,6 @@ set(libdevilutionx_SRCS towners.cpp track.cpp - common/validation.cpp - controls/axis_direction.cpp controls/controller.cpp controls/controller_buttons.cpp @@ -122,6 +120,8 @@ set(libdevilutionx_SRCS engine/render/scrollrt.cpp engine/render/text_render.cpp + items/validation.cpp + levels/crypt.cpp levels/drlg_l1.cpp levels/drlg_l2.cpp diff --git a/Source/common/validation.cpp b/Source/items/validation.cpp similarity index 94% rename from Source/common/validation.cpp rename to Source/items/validation.cpp index 25367d7bcf3..dd39eff76f1 100644 --- a/Source/common/validation.cpp +++ b/Source/items/validation.cpp @@ -1,10 +1,10 @@ /** - * @file common/validation.cpp + * @file items/validation.cpp * * Implementation of functions for validation of player and item data. */ -#include "common/validation.h" +#include "items/validation.h" #include diff --git a/Source/common/validation.h b/Source/items/validation.h similarity index 90% rename from Source/common/validation.h rename to Source/items/validation.h index 9aaf5396118..4a78c6c471b 100644 --- a/Source/common/validation.h +++ b/Source/items/validation.h @@ -1,5 +1,5 @@ /** - * @file common/validation.h + * @file items/validation.h * * Interface of functions for validation of player and item data. */ diff --git a/Source/pack.cpp b/Source/pack.cpp index 4667bcde60d..3e368f815fd 100644 --- a/Source/pack.cpp +++ b/Source/pack.cpp @@ -7,9 +7,9 @@ #include -#include "common/validation.h" #include "engine/random.hpp" #include "init.h" +#include "items/validation.h" #include "loadsave.h" #include "playerdat.hpp" #include "plrmsg.h" diff --git a/Source/player.h b/Source/player.h index d8610df176c..c555722834a 100644 --- a/Source/player.h +++ b/Source/player.h @@ -11,7 +11,6 @@ #include #include -#include "common/validation.h" #include "diablo.h" #include "engine.h" #include "engine/actor_position.hpp" @@ -21,6 +20,7 @@ #include "engine/point.hpp" #include "interfac.h" #include "items.h" +#include "items/validation.h" #include "levels/gendung.h" #include "multi.h" #include "playerdat.hpp" From acff115b370856aead7594749e12f6a7e6abf1d5 Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Mon, 11 Nov 2024 21:50:53 -0500 Subject: [PATCH 04/14] Move to helper function --- Source/items.cpp | 18 +----------------- Source/items/validation.cpp | 18 ++++++++++++++++++ Source/items/validation.h | 1 + 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/Source/items.cpp b/Source/items.cpp index b7f0cf44f04..9129be6fd9d 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -517,23 +517,7 @@ void CalcSelfItems(Player &player) if (!equipment._iStatFlag) continue; - bool isValid = true; - - if (equipment.IDidx != IDI_GOLD) { - if (!IsCreationFlagComboValid(equipment._iCreateInfo)) - isValid = false; - } - - if ((equipment._iCreateInfo & CF_TOWN) != 0) { - if (!IsTownItemValid(equipment._iCreateInfo, player.getMaxCharacterLevel())) - isValid = false; - } else if ((equipment._iCreateInfo & CF_USEFUL) == CF_UPER15) { - if (!IsUniqueMonsterItemValid(equipment._iCreateInfo, equipment.dwBuff)) - isValid = false; - } else { - if (!IsDungeonItemValid(equipment._iCreateInfo, equipment.dwBuff)) - isValid = false; - } + bool isValid = IsItemValid(player, equipment); if (currstr < equipment._iMinStr || currmag < equipment._iMinMag diff --git a/Source/items/validation.cpp b/Source/items/validation.cpp index dd39eff76f1..fd397f0dfd0 100644 --- a/Source/items/validation.cpp +++ b/Source/items/validation.cpp @@ -10,6 +10,7 @@ #include "items.h" #include "monstdat.h" +#include "player.h" namespace devilution { @@ -118,4 +119,21 @@ bool IsDungeonItemValid(uint16_t iCreateInfo, uint32_t dwBuff) return level <= (diabloMaxDungeonLevel * 2); } +bool IsItemValid(const Player &player, const Item &item) +{ + bool isValid = true; + + if (item.IDidx != IDI_GOLD) + isValid = isValid && IsCreationFlagComboValid(item._iCreateInfo); + + if ((item._iCreateInfo & CF_TOWN) != 0) + isValid = isValid && IsTownItemValid(item._iCreateInfo, player.getMaxCharacterLevel()); + else if ((item._iCreateInfo & CF_USEFUL) == CF_UPER15) + isValid = isValid && IsUniqueMonsterItemValid(item._iCreateInfo, item.dwBuff); + + isValid = isValid && IsDungeonItemValid(item._iCreateInfo, item.dwBuff); + + return isValid; +} + } // namespace devilution diff --git a/Source/items/validation.h b/Source/items/validation.h index 4a78c6c471b..95689f0117d 100644 --- a/Source/items/validation.h +++ b/Source/items/validation.h @@ -13,5 +13,6 @@ bool IsCreationFlagComboValid(uint16_t iCreateInfo); bool IsTownItemValid(uint16_t iCreateInfo, uint8_t maxCharacterLevel); bool IsUniqueMonsterItemValid(uint16_t iCreateInfo, uint32_t dwBuff); bool IsDungeonItemValid(uint16_t iCreateInfo, uint32_t dwBuff); +bool IsItemValid(const Player &player, const Item &item); } // namespace devilution From a9849dda5543dad3cf14d4707b9bf4f243e3ab16 Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Mon, 11 Nov 2024 21:59:26 -0500 Subject: [PATCH 05/14] Fix non-updating items --- Source/items/validation.h | 3 +++ Source/loadsave.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/items/validation.h b/Source/items/validation.h index 95689f0117d..5a7346cf7c0 100644 --- a/Source/items/validation.h +++ b/Source/items/validation.h @@ -7,6 +7,9 @@ #include +struct Item; +struct Player; + namespace devilution { bool IsCreationFlagComboValid(uint16_t iCreateInfo); diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index df2f2453925..dd57a29467d 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -579,7 +579,7 @@ void LoadPlayer(LoadHelper &file, Player &player) sgGameInitInfo.nDifficulty = static_cast<_difficulty>(file.NextLE()); player.pDamAcFlags = static_cast(file.NextLE()); file.Skip(20); // Available bytes - CalcPlrItemVals(player, false); + CalcPlrInv(player, false); player.executedSpell = player.queuedSpell; // Ensures backwards compatibility From 9ce6e95ab59d3a5aedd27f273fd7c3947e37cb9f Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Mon, 11 Nov 2024 22:41:49 -0500 Subject: [PATCH 06/14] Shop prices --- Source/items.cpp | 14 +++++++------- Source/items.h | 5 +++++ Source/items/validation.cpp | 16 +++++++++++++++- Source/items/validation.h | 1 + Source/loadsave.cpp | 22 ---------------------- 5 files changed, 28 insertions(+), 30 deletions(-) diff --git a/Source/items.cpp b/Source/items.cpp index 9129be6fd9d..c90232cae12 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -1958,7 +1958,7 @@ void SpawnOnePremium(Item &premiumItem, int plvl, const Player &player) GetItemBonus(player, premiumItem, plvl / 2, plvl, true, !gbIsHellfire); if (!gbIsHellfire) { - if (premiumItem._iIvalue <= 140000) { + if (premiumItem._iIvalue <= MAX_VENDOR_VALUE) { break; } } else { @@ -1995,7 +1995,7 @@ void SpawnOnePremium(Item &premiumItem, int plvl, const Player &player) break; } itemValue = itemValue * 4 / 5; // avoids forced int > float > int conversion - if (premiumItem._iIvalue <= 200000 + if (premiumItem._iIvalue <= MAX_VENDOR_VALUE_HF && premiumItem._iMinStr <= strength && premiumItem._iMinMag <= magic && premiumItem._iMinDex <= dexterity @@ -4371,10 +4371,10 @@ void SpawnSmith(int lvl) { constexpr int PinnedItemCount = 0; - int maxValue = 140000; + int maxValue = MAX_VENDOR_VALUE; int maxItems = 19; if (gbIsHellfire) { - maxValue = 200000; + maxValue = MAX_VENDOR_VALUE_HF; maxItems = 24; } @@ -4442,7 +4442,7 @@ void SpawnWitch(int lvl) int bookCount = 0; const int pinnedBookCount = gbIsHellfire ? RandomIntLessThan(MaxPinnedBookCount) : 0; const int itemCount = RandomIntBetween(10, gbIsHellfire ? 24 : 17); - const int maxValue = gbIsHellfire ? 200000 : 140000; + const int maxValue = gbIsHellfire ? MAX_VENDOR_VALUE_HF : MAX_VENDOR_VALUE; for (int i = 0; i < WITCH_ITEMS; i++) { Item &item = WitchItems[i]; @@ -4527,7 +4527,7 @@ void SpawnBoy(int lvl) GetItemBonus(*MyPlayer, BoyItem, lvl, 2 * lvl, true, true); if (!gbIsHellfire) { - if (BoyItem._iIvalue > 90000) { + if (BoyItem._iIvalue > MAX_BOY_VALUE) { keepgoing = true; // prevent breaking the do/while loop too early by failing hellfire's condition in while continue; } @@ -4602,7 +4602,7 @@ void SpawnBoy(int lvl) } } while (keepgoing || (( - BoyItem._iIvalue > 200000 + BoyItem._iIvalue > MAX_BOY_VALUE_HF || BoyItem._iMinStr > strength || BoyItem._iMinMag > magic || BoyItem._iMinDex > dexterity diff --git a/Source/items.h b/Source/items.h index 014f90e415f..3315241b306 100644 --- a/Source/items.h +++ b/Source/items.h @@ -29,6 +29,11 @@ namespace devilution { // Item indestructible durability #define DUR_INDESTRUCTIBLE 255 +#define MAX_VENDOR_VALUE 140000 +#define MAX_VENDOR_VALUE_HF 200000 +#define MAX_BOY_VALUE 90000 +#define MAX_BOY_VALUE_HF 200000 + enum item_quality : uint8_t { ITEM_QUALITY_NORMAL, ITEM_QUALITY_MAGIC, diff --git a/Source/items/validation.cpp b/Source/items/validation.cpp index fd397f0dfd0..158e6044e02 100644 --- a/Source/items/validation.cpp +++ b/Source/items/validation.cpp @@ -56,6 +56,20 @@ bool IsTownItemValid(uint16_t iCreateInfo, uint8_t maxCharacterLevel) return level <= maxTownItemLevel; } +bool IsShopPriceValid(const Item &item) +{ + const int boyPriceLimit = gbIsHellfire ? MAX_BOY_VALUE_HF : MAX_BOY_VALUE; + if ((item._iCreateInfo & CF_BOY) != 0 && item._iIvalue > boyPriceLimit) + return false; + + const uint16_t smithOrWitch = CF_SMITH | CF_SMITHPREMIUM | CF_WITCH; + const int smithAndWitchPriceLimit = gbIsHellfire ? MAX_VENDOR_VALUE_HF : MAX_VENDOR_VALUE; + if ((item._iCreateInfo & smithOrWitch) != 0 && item._iIvalue > smithAndWitchPriceLimit) + return false; + + return true; +} + bool IsUniqueMonsterItemValid(uint16_t iCreateInfo, uint32_t dwBuff) { const uint8_t level = iCreateInfo & CF_LEVEL; @@ -127,7 +141,7 @@ bool IsItemValid(const Player &player, const Item &item) isValid = isValid && IsCreationFlagComboValid(item._iCreateInfo); if ((item._iCreateInfo & CF_TOWN) != 0) - isValid = isValid && IsTownItemValid(item._iCreateInfo, player.getMaxCharacterLevel()); + isValid = isValid && IsTownItemValid(item._iCreateInfo, player.getMaxCharacterLevel()) && IsShopPriceValid(item); else if ((item._iCreateInfo & CF_USEFUL) == CF_UPER15) isValid = isValid && IsUniqueMonsterItemValid(item._iCreateInfo, item.dwBuff); diff --git a/Source/items/validation.h b/Source/items/validation.h index 5a7346cf7c0..ba66195b741 100644 --- a/Source/items/validation.h +++ b/Source/items/validation.h @@ -14,6 +14,7 @@ namespace devilution { bool IsCreationFlagComboValid(uint16_t iCreateInfo); bool IsTownItemValid(uint16_t iCreateInfo, uint8_t maxCharacterLevel); +bool IsShopPriceValid(const Item &item); bool IsUniqueMonsterItemValid(uint16_t iCreateInfo, uint32_t dwBuff); bool IsDungeonItemValid(uint16_t iCreateInfo, uint32_t dwBuff); bool IsItemValid(const Player &player, const Item &item); diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index dd57a29467d..d604ab1f53f 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -969,24 +969,6 @@ bool LevelFileExists(SaveWriter &archive) return archive.HasFile(szName); } -bool IsShopPriceValid(const Item &item) -{ - const int boyPriceLimit = 90000; - if (!gbIsHellfire && (item._iCreateInfo & CF_BOY) != 0 && item._iIvalue > boyPriceLimit) - return false; - - const int premiumPriceLimit = 140000; - if (!gbIsHellfire && (item._iCreateInfo & CF_SMITHPREMIUM) != 0 && item._iIvalue > premiumPriceLimit) - return false; - - const uint16_t smithOrWitch = CF_SMITH | CF_WITCH; - const int smithAndWitchPriceLimit = gbIsHellfire ? 200000 : 140000; - if ((item._iCreateInfo & smithOrWitch) != 0 && item._iIvalue > smithAndWitchPriceLimit) - return false; - - return true; -} - void LoadMatchingItems(LoadHelper &file, const Player &player, const int n, Item *pItem) { Item heroItem; @@ -1012,10 +994,6 @@ void LoadMatchingItems(LoadHelper &file, const Player &player, const int n, Item unpackedItem._iMaxCharges = std::clamp(heroItem._iMaxCharges, 0, unpackedItem._iMaxCharges); unpackedItem._iCharges = std::clamp(heroItem._iCharges, 0, unpackedItem._iMaxCharges); } - if (!IsShopPriceValid(unpackedItem)) { - unpackedItem.clear(); - continue; - } if (gbIsHellfire) { unpackedItem._iPLToHit = ClampToHit(unpackedItem, heroItem._iPLToHit); // Oil of Accuracy unpackedItem._iMaxDam = ClampMaxDam(unpackedItem, heroItem._iMaxDam); // Oil of Sharpness From 9b81bb73bb60b1d08f5ce956abe3580d7baee7da Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Mon, 11 Nov 2024 22:50:55 -0500 Subject: [PATCH 07/14] Minor cleanup --- Source/items/validation.cpp | 6 +++--- Source/items/validation.h | 2 +- Source/msg.cpp | 2 +- Source/pack.cpp | 2 +- Source/player.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Source/items/validation.cpp b/Source/items/validation.cpp index 158e6044e02..10ab86be53b 100644 --- a/Source/items/validation.cpp +++ b/Source/items/validation.cpp @@ -43,14 +43,14 @@ bool IsCreationFlagComboValid(uint16_t iCreateInfo) return true; } -bool IsTownItemValid(uint16_t iCreateInfo, uint8_t maxCharacterLevel) +bool IsTownItemValid(uint16_t iCreateInfo, const Player &player) { const uint8_t level = iCreateInfo & CF_LEVEL; const bool isBoyItem = (iCreateInfo & CF_BOY) != 0; const uint8_t maxTownItemLevel = 30; // Wirt items in multiplayer are equal to the level of the player, therefore they cannot exceed the max character level - if (isBoyItem && level <= maxCharacterLevel) + if (isBoyItem && level <= player.getMaxCharacterLevel()) return true; return level <= maxTownItemLevel; @@ -141,7 +141,7 @@ bool IsItemValid(const Player &player, const Item &item) isValid = isValid && IsCreationFlagComboValid(item._iCreateInfo); if ((item._iCreateInfo & CF_TOWN) != 0) - isValid = isValid && IsTownItemValid(item._iCreateInfo, player.getMaxCharacterLevel()) && IsShopPriceValid(item); + isValid = isValid && IsTownItemValid(item._iCreateInfo, player) && IsShopPriceValid(item); else if ((item._iCreateInfo & CF_USEFUL) == CF_UPER15) isValid = isValid && IsUniqueMonsterItemValid(item._iCreateInfo, item.dwBuff); diff --git a/Source/items/validation.h b/Source/items/validation.h index ba66195b741..91657b42d1f 100644 --- a/Source/items/validation.h +++ b/Source/items/validation.h @@ -13,7 +13,7 @@ struct Player; namespace devilution { bool IsCreationFlagComboValid(uint16_t iCreateInfo); -bool IsTownItemValid(uint16_t iCreateInfo, uint8_t maxCharacterLevel); +bool IsTownItemValid(uint16_t iCreateInfo, const Player &player); bool IsShopPriceValid(const Item &item); bool IsUniqueMonsterItemValid(uint16_t iCreateInfo, uint32_t dwBuff); bool IsDungeonItemValid(uint16_t iCreateInfo, uint32_t dwBuff); diff --git a/Source/msg.cpp b/Source/msg.cpp index 5d67263c950..cbcfd6bcb31 100644 --- a/Source/msg.cpp +++ b/Source/msg.cpp @@ -1044,7 +1044,7 @@ bool IsPItemValid(const TCmdPItem &message, const Player &player) if (idx != IDI_GOLD) ValidateField(creationFlags, IsCreationFlagComboValid(creationFlags)); if ((creationFlags & CF_TOWN) != 0) - ValidateField(creationFlags, IsTownItemValid(creationFlags, player.getMaxCharacterLevel())); + ValidateField(creationFlags, IsTownItemValid(creationFlags, player)); else if ((creationFlags & CF_USEFUL) == CF_UPER15) ValidateFields(creationFlags, dwBuff, IsUniqueMonsterItemValid(creationFlags, dwBuff)); else if ((dwBuff & CF_HELLFIRE) != 0 && AllItemsList[idx].iMiscId == IMISC_BOOK) diff --git a/Source/pack.cpp b/Source/pack.cpp index 3e368f815fd..ead5c464d87 100644 --- a/Source/pack.cpp +++ b/Source/pack.cpp @@ -445,7 +445,7 @@ bool UnPackNetItem(const Player &player, const ItemNetPack &packedItem, Item &it if (idx != IDI_GOLD) ValidateField(creationFlags, IsCreationFlagComboValid(creationFlags)); if ((creationFlags & CF_TOWN) != 0) - ValidateField(creationFlags, IsTownItemValid(creationFlags, player.getMaxCharacterLevel())); + ValidateField(creationFlags, IsTownItemValid(creationFlags, player)); else if ((creationFlags & CF_USEFUL) == CF_UPER15) ValidateFields(creationFlags, dwBuff, IsUniqueMonsterItemValid(creationFlags, dwBuff)); else if ((dwBuff & CF_HELLFIRE) != 0 && AllItemsList[idx].iMiscId == IMISC_BOOK) diff --git a/Source/player.h b/Source/player.h index c555722834a..5fa8aa69654 100644 --- a/Source/player.h +++ b/Source/player.h @@ -407,7 +407,7 @@ struct Player { } if ((item._iCreateInfo & CF_TOWN) != 0) { - if (!IsTownItemValid(item._iCreateInfo, getMaxCharacterLevel())) + if (!IsTownItemValid(item._iCreateInfo, *this)) return false; } else if ((item._iCreateInfo & CF_USEFUL) == CF_UPER15) { if (!IsUniqueMonsterItemValid(item._iCreateInfo, item.dwBuff)) From 9e61053a87b104729e0d0c516f46062bb0accf7f Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Mon, 11 Nov 2024 22:52:37 -0500 Subject: [PATCH 08/14] Cleanup CanUseItem() --- Source/player.h | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/Source/player.h b/Source/player.h index 5fa8aa69654..1a4f5daffce 100644 --- a/Source/player.h +++ b/Source/player.h @@ -401,21 +401,8 @@ struct Player { bool CanUseItem(const Item &item) const { - if (item.IDidx != IDI_GOLD) { - if (!IsCreationFlagComboValid(item._iCreateInfo)) - return false; - } - - if ((item._iCreateInfo & CF_TOWN) != 0) { - if (!IsTownItemValid(item._iCreateInfo, *this)) - return false; - } else if ((item._iCreateInfo & CF_USEFUL) == CF_UPER15) { - if (!IsUniqueMonsterItemValid(item._iCreateInfo, item.dwBuff)) - return false; - } else { - if (!IsDungeonItemValid(item._iCreateInfo, item.dwBuff)) - return false; - } + if (!IsItemValid(*this, item)) + return false; return _pStrength >= item._iMinStr && _pMagic >= item._iMinMag From 540d7edba6d2ce3513f31a0643fea78181e053c2 Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Mon, 11 Nov 2024 22:54:32 -0500 Subject: [PATCH 09/14] convert macros to constexpr --- Source/items.cpp | 14 +++++++------- Source/items.h | 8 ++++---- Source/items/validation.cpp | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Source/items.cpp b/Source/items.cpp index c90232cae12..3e0b0bd4c37 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -1958,7 +1958,7 @@ void SpawnOnePremium(Item &premiumItem, int plvl, const Player &player) GetItemBonus(player, premiumItem, plvl / 2, plvl, true, !gbIsHellfire); if (!gbIsHellfire) { - if (premiumItem._iIvalue <= MAX_VENDOR_VALUE) { + if (premiumItem._iIvalue <= MaxVendorValue) { break; } } else { @@ -1995,7 +1995,7 @@ void SpawnOnePremium(Item &premiumItem, int plvl, const Player &player) break; } itemValue = itemValue * 4 / 5; // avoids forced int > float > int conversion - if (premiumItem._iIvalue <= MAX_VENDOR_VALUE_HF + if (premiumItem._iIvalue <= MaxVendorValueHf && premiumItem._iMinStr <= strength && premiumItem._iMinMag <= magic && premiumItem._iMinDex <= dexterity @@ -4371,10 +4371,10 @@ void SpawnSmith(int lvl) { constexpr int PinnedItemCount = 0; - int maxValue = MAX_VENDOR_VALUE; + int maxValue = MaxVendorValue; int maxItems = 19; if (gbIsHellfire) { - maxValue = MAX_VENDOR_VALUE_HF; + maxValue = MaxVendorValueHf; maxItems = 24; } @@ -4442,7 +4442,7 @@ void SpawnWitch(int lvl) int bookCount = 0; const int pinnedBookCount = gbIsHellfire ? RandomIntLessThan(MaxPinnedBookCount) : 0; const int itemCount = RandomIntBetween(10, gbIsHellfire ? 24 : 17); - const int maxValue = gbIsHellfire ? MAX_VENDOR_VALUE_HF : MAX_VENDOR_VALUE; + const int maxValue = gbIsHellfire ? MaxVendorValueHf : MaxVendorValue; for (int i = 0; i < WITCH_ITEMS; i++) { Item &item = WitchItems[i]; @@ -4527,7 +4527,7 @@ void SpawnBoy(int lvl) GetItemBonus(*MyPlayer, BoyItem, lvl, 2 * lvl, true, true); if (!gbIsHellfire) { - if (BoyItem._iIvalue > MAX_BOY_VALUE) { + if (BoyItem._iIvalue > MaxBoyValue) { keepgoing = true; // prevent breaking the do/while loop too early by failing hellfire's condition in while continue; } @@ -4602,7 +4602,7 @@ void SpawnBoy(int lvl) } } while (keepgoing || (( - BoyItem._iIvalue > MAX_BOY_VALUE_HF + BoyItem._iIvalue > MaxBoyValueHf || BoyItem._iMinStr > strength || BoyItem._iMinMag > magic || BoyItem._iMinDex > dexterity diff --git a/Source/items.h b/Source/items.h index 3315241b306..7ac6ff2d58c 100644 --- a/Source/items.h +++ b/Source/items.h @@ -29,10 +29,10 @@ namespace devilution { // Item indestructible durability #define DUR_INDESTRUCTIBLE 255 -#define MAX_VENDOR_VALUE 140000 -#define MAX_VENDOR_VALUE_HF 200000 -#define MAX_BOY_VALUE 90000 -#define MAX_BOY_VALUE_HF 200000 +constexpr int MaxVendorValue = 140000; +constexpr int MaxVendorValueHf = 200000; +constexpr int MaxBoyValue = 90000; +constexpr int MaxBoyValueHf = 200000; enum item_quality : uint8_t { ITEM_QUALITY_NORMAL, diff --git a/Source/items/validation.cpp b/Source/items/validation.cpp index 10ab86be53b..afea210d695 100644 --- a/Source/items/validation.cpp +++ b/Source/items/validation.cpp @@ -58,12 +58,12 @@ bool IsTownItemValid(uint16_t iCreateInfo, const Player &player) bool IsShopPriceValid(const Item &item) { - const int boyPriceLimit = gbIsHellfire ? MAX_BOY_VALUE_HF : MAX_BOY_VALUE; + const int boyPriceLimit = gbIsHellfire ? MaxBoyValueHf : MaxBoyValue; if ((item._iCreateInfo & CF_BOY) != 0 && item._iIvalue > boyPriceLimit) return false; const uint16_t smithOrWitch = CF_SMITH | CF_SMITHPREMIUM | CF_WITCH; - const int smithAndWitchPriceLimit = gbIsHellfire ? MAX_VENDOR_VALUE_HF : MAX_VENDOR_VALUE; + const int smithAndWitchPriceLimit = gbIsHellfire ? MaxVendorValueHf : MaxVendorValue; if ((item._iCreateInfo & smithOrWitch) != 0 && item._iIvalue > smithAndWitchPriceLimit) return false; From d7a648354846e54d07b9479ad97ec5821dc7a9bf Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Mon, 11 Nov 2024 23:05:03 -0500 Subject: [PATCH 10/14] Clean up IsItemValid() --- Source/items/validation.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Source/items/validation.cpp b/Source/items/validation.cpp index afea210d695..6f3949ab2e9 100644 --- a/Source/items/validation.cpp +++ b/Source/items/validation.cpp @@ -135,19 +135,21 @@ bool IsDungeonItemValid(uint16_t iCreateInfo, uint32_t dwBuff) bool IsItemValid(const Player &player, const Item &item) { - bool isValid = true; - - if (item.IDidx != IDI_GOLD) - isValid = isValid && IsCreationFlagComboValid(item._iCreateInfo); + if (item.IDidx != IDI_GOLD && !IsCreationFlagComboValid(item._iCreateInfo)) + return false; - if ((item._iCreateInfo & CF_TOWN) != 0) - isValid = isValid && IsTownItemValid(item._iCreateInfo, player) && IsShopPriceValid(item); - else if ((item._iCreateInfo & CF_USEFUL) == CF_UPER15) - isValid = isValid && IsUniqueMonsterItemValid(item._iCreateInfo, item.dwBuff); + if ((item._iCreateInfo & CF_TOWN) != 0) { + if (!IsTownItemValid(item._iCreateInfo, player) || !IsShopPriceValid(item)) + return false; + } else if ((item._iCreateInfo & CF_USEFUL) == CF_UPER15) { + if (!IsUniqueMonsterItemValid(item._iCreateInfo, item.dwBuff)) + return false; + } - isValid = isValid && IsDungeonItemValid(item._iCreateInfo, item.dwBuff); + if (!IsDungeonItemValid(item._iCreateInfo, item.dwBuff)) + return false; - return isValid; + return true; } } // namespace devilution From c7f12df2ed5f3bce2e7299cf6b91b7978cf3587b Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Mon, 11 Nov 2024 23:17:20 -0500 Subject: [PATCH 11/14] Fix error --- Source/items/validation.h | 1 + Source/player.cpp | 10 ++++++++++ Source/player.h | 10 +--------- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Source/items/validation.h b/Source/items/validation.h index 91657b42d1f..98bbabc6b27 100644 --- a/Source/items/validation.h +++ b/Source/items/validation.h @@ -7,6 +7,7 @@ #include +// Forward declared structs to avoid circular dependencies struct Item; struct Player; diff --git a/Source/player.cpp b/Source/player.cpp index 36eef40d5da..e7752e9f7e8 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -1527,6 +1527,16 @@ void Player::CalcScrolls() EnsureValidReadiedSpell(*this); } +bool Player::CanUseItem(const Item &item) const +{ + if (!IsItemValid(*this, item)) + return false; + + return _pStrength >= item._iMinStr + && _pMagic >= item._iMinMag + && _pDexterity >= item._iMinDex; +} + void Player::RemoveInvItem(int iv, bool calcScrolls) { if (this == MyPlayer) { diff --git a/Source/player.h b/Source/player.h index 1a4f5daffce..a3b7ff75a81 100644 --- a/Source/player.h +++ b/Source/player.h @@ -399,15 +399,7 @@ struct Player { void CalcScrolls(); - bool CanUseItem(const Item &item) const - { - if (!IsItemValid(*this, item)) - return false; - - return _pStrength >= item._iMinStr - && _pMagic >= item._iMinMag - && _pDexterity >= item._iMinDex; - } + bool CanUseItem(const Item &item) const; bool CanCleave() { From 6af8e4a8d06d1d3362d8e693bd0715b134c76854 Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Mon, 11 Nov 2024 23:26:46 -0500 Subject: [PATCH 12/14] Update missiles_test.cpp --- test/missiles_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/missiles_test.cpp b/test/missiles_test.cpp index 3841f43288b..09b1c590411 100644 --- a/test/missiles_test.cpp +++ b/test/missiles_test.cpp @@ -45,7 +45,7 @@ TEST(Missiles, RotateBlockedMissileArrow) *MyPlayer = {}; LoadMissileData(); - Player &player = Players[0]; + devilution::Player &player = Players[0]; // missile can be a copy or a reference, there's no nullptr check and the functions that use it don't expect the instance to be part of a global structure so it doesn't really matter for this use. Missile missile = *AddMissile({ 0, 0 }, { 0, 0 }, Direction::South, MissileID::Arrow, TARGET_MONSTERS, player, 0, 0); From 0950bf2421b8c3eb606ee13d9515194979423e8d Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Mon, 11 Nov 2024 23:28:11 -0500 Subject: [PATCH 13/14] Fix tests --- test/player_test.cpp | 4 ++-- test/player_test.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/player_test.cpp b/test/player_test.cpp index bda987d3a6e..80d538b11e2 100644 --- a/test/player_test.cpp +++ b/test/player_test.cpp @@ -14,7 +14,7 @@ extern bool TestPlayerDoGotHit(Player &player); int RunBlockTest(int frames, ItemSpecialEffect flags) { - Player &player = Players[0]; + devilution::Player &player = Players[0]; player._pHFrames = frames; player._pIFlags = flags; @@ -90,7 +90,7 @@ TEST(Player, PM_DoGotHit) } } -static void AssertPlayer(Player &player) +static void AssertPlayer(devilution::Player &player) { ASSERT_EQ(CountU8(player._pSplLvl, 64), 0); ASSERT_EQ(Count8(player.InvGrid, InventoryGridCells), 1); diff --git a/test/player_test.h b/test/player_test.h index 539010ee75d..fdc797ccff9 100644 --- a/test/player_test.h +++ b/test/player_test.h @@ -10,9 +10,9 @@ using namespace devilution; -static size_t CountItems(Item *items, int n) +static size_t CountItems(devilution::Item *items, int n) { - return std::count_if(items, items + n, [](Item x) { return !x.isEmpty(); }); + return std::count_if(items, items + n, [](devilution::Item x) { return !x.isEmpty(); }); } static size_t Count8(int8_t *ints, int n) From 819a41c0b266e218c43241e4303953257cadb4c8 Mon Sep 17 00:00:00 2001 From: Eric Robinson Date: Thu, 14 Nov 2024 19:12:43 -0500 Subject: [PATCH 14/14] Update stores_test.cpp --- test/stores_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/stores_test.cpp b/test/stores_test.cpp index 0e4d60e29e9..b4c2e16124a 100644 --- a/test/stores_test.cpp +++ b/test/stores_test.cpp @@ -8,7 +8,7 @@ namespace { TEST(Stores, AddStoreHoldRepair_magic) { - Item *item; + devilution::Item *item; item = &PlayerItems[0]; @@ -41,7 +41,7 @@ TEST(Stores, AddStoreHoldRepair_magic) TEST(Stores, AddStoreHoldRepair_normal) { - Item *item; + devilution::Item *item; item = &PlayerItems[0];