From 84302c45f3b289d38d8d09ef76e4b992d97807c8 Mon Sep 17 00:00:00 2001 From: ephphatha Date: Thu, 23 Sep 2021 20:35:27 +1000 Subject: [PATCH] Extract common logic for saving items to a save file This was duplicated for saving from the menu and transitioning to a new level --- Source/loadsave.cpp | 62 ++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 21 deletions(-) diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index 3b49e048d..e287a14e1 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -1503,6 +1503,41 @@ void SavePortal(SaveHelper *file, int i) file->WriteLE(pPortal->setlvl ? 1 : 0); } +/** + * @brief Saves items on the current dungeon floor + * @param file interface to the save file + * @return a map converting from runtime item indexes to the relative position in the save file, used by SaveDroppedItemLocations + * @see SaveDroppedItemLocations +*/ +std::unordered_map SaveDroppedItems(SaveHelper &file) +{ + // Vanilla Diablo/Hellfire initialise the ActiveItems and AvailableItems arrays based on saved data, so write valid values for compatibility + for (int i = 0; i < MAXITEMS; i++) + file.WriteLE(i); // Strictly speaking everything from ActiveItemCount onwards is unused but no harm writing non-zero values here. + for (int i = 0; i < MAXITEMS; i++) + file.WriteLE((i + ActiveItemCount) % MAXITEMS); + + std::unordered_map itemIndexes = { { 0, 0 } }; + for (int i = 0; i < ActiveItemCount; i++) { + itemIndexes[ActiveItems[i] + 1] = i + 1; + SaveItem(file, Items[ActiveItems[i]]); + } + return itemIndexes; +} + +/** + * @brief Saves the position of dropped items (in dItem) + * @param file interface to the save file + * @param indexMap a map converting from runtime item indexes to the relative position in the save file +*/ +void SaveDroppedItemLocations(SaveHelper &file, const std::unordered_map &itemIndexes) +{ + for (int j = 0; j < MAXDUNY; j++) { + for (int i = 0; i < MAXDUNX; i++) // NOLINT(modernize-loop-convert) + file.WriteLE(itemIndexes.at(dItem[i][j])); + } +} + const int DiabloItemSaveSize = 368; const int HellfireItemSaveSize = 372; @@ -2016,12 +2051,8 @@ void SaveGameData() SaveLighting(&file, &VisionList[i]); } - for (int itemId : ActiveItems) - file.WriteLE(itemId); - for (int itemId : AvailableItems) - file.WriteLE(itemId); - for (int i = 0; i < ActiveItemCount; i++) - SaveItem(file, Items[ActiveItems[i]]); + auto itemIndexes = SaveDroppedItems(file); + for (bool uniqueItemFlag : UniqueItemFlags) file.WriteLE(uniqueItemFlag ? 1 : 0); @@ -2037,10 +2068,8 @@ void SaveGameData() for (int i = 0; i < MAXDUNX; i++) // NOLINT(modernize-loop-convert) file.WriteLE(dPlayer[i][j]); } - for (int j = 0; j < MAXDUNY; j++) { - for (int i = 0; i < MAXDUNX; i++) // NOLINT(modernize-loop-convert) - file.WriteLE(dItem[i][j]); - } + + SaveDroppedItemLocations(file, itemIndexes); if (leveltype != DTYPE_TOWN) { for (int j = 0; j < MAXDUNY; j++) { @@ -2128,22 +2157,13 @@ void SaveLevel() SaveObject(file, Objects[ActiveObjects[i]]); } - for (int itemId : ActiveItems) - file.WriteLE(itemId); - for (int itemId : AvailableItems) - file.WriteLE(itemId); - - for (int i = 0; i < ActiveItemCount; i++) - SaveItem(file, Items[ActiveItems[i]]); + auto itemIndexes = SaveDroppedItems(file); for (int j = 0; j < MAXDUNY; j++) { for (int i = 0; i < MAXDUNX; i++) // NOLINT(modernize-loop-convert) file.WriteLE(static_cast(dFlags[i][j] & DungeonFlag::SavedFlags)); } - for (int j = 0; j < MAXDUNY; j++) { - for (int i = 0; i < MAXDUNX; i++) // NOLINT(modernize-loop-convert) - file.WriteLE(dItem[i][j]); - } + SaveDroppedItemLocations(file, itemIndexes); if (leveltype != DTYPE_TOWN) { for (int j = 0; j < MAXDUNY; j++) {