From 71e39dda6f511625f0f73d37a071a79e797c5a31 Mon Sep 17 00:00:00 2001 From: ephphatha Date: Thu, 23 Sep 2021 19:09:04 +1000 Subject: [PATCH] Extract common logic for loading items from a save This was duplicated for loading a save from the menu and transitioning to a new level --- Source/items.cpp | 6 ++++ Source/loadsave.cpp | 67 +++++++++++++++++++++++++++++++-------------- 2 files changed, 53 insertions(+), 20 deletions(-) diff --git a/Source/items.cpp b/Source/items.cpp index 7b80995e9..3eff6392f 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -42,6 +42,12 @@ namespace devilution { Item Items[MAXITEMS + 1]; int ActiveItems[MAXITEMS]; int ActiveItemCount; +/** + * @brief Contains indexes of empty spaces in Items. + * + * This array effectively duplicates ActiveItems due to differences in implementation to other fixed buffers. + * Eventually this can be removed and Items can be treated the same as how Missiles are tracked + */ int AvailableItems[MAXITEMS]; bool ShowUniqueItemInfoBox; CornerStoneStruct CornerStone; diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index 10aa07dfe..3b49e048d 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -885,6 +885,46 @@ void LoadMatchingItems(LoadHelper &file, const int n, Item *pItem) } } +/** + * @brief Loads items on the current dungeon floor + * @param file interface to the save file + * @return a map converting from item indexes as recorded in the save file to the appropriate Items array index, used by LoadDroppedItemLocations + * @see LoadDroppedItemLocations +*/ +std::unordered_map LoadDroppedItems(LoadHelper &file) +{ + std::unordered_map itemIndexes = { { 0, 0 } }; + for (uint8_t i = 0; i < ActiveItemCount; i++) { + // Load the current item indexes to remap dItem values as needed. + itemIndexes[file.NextLE() + 1] = i + 1; // adding 1 as dItem values use 0 for no item, and index + 1 for the actual item ID + } + file.Skip(MAXITEMS * 2 - static_cast(ActiveItemCount)); // Skip loading the rest of ActiveItems and AvailableItems, the indices are initialised below based on the number of active items + + for (int i = 0; i < MAXITEMS; i++) { + if (i < ActiveItemCount) + LoadItem(file, Items[i]); + + // Initialise the ActiveItems and AvailableItems arrays so the existing logic for dropping items can stay unchanged + ActiveItems[i] = i; + AvailableItems[i] = (i + ActiveItemCount) % MAXITEMS; + } + + return itemIndexes; +} + +/** + * @brief Helper to initialise dItem based on runtime item indexes + * @param file interface to the save file + * @param indexMap a map converting from save file item indexes to the appropriate Items array index +*/ +void LoadDroppedItemLocations(LoadHelper &file, const std::unordered_map &indexMap) +{ + for (int j = 0; j < MAXDUNY; j++) { + for (int i = 0; i < MAXDUNX; i++) // NOLINT(modernize-loop-convert) + dItem[i][j] = indexMap.at(file.NextLE()); + } +} + void RemoveEmptyLevelItems() { for (int i = ActiveItemCount; i > 0; i--) { @@ -1788,12 +1828,8 @@ void LoadGame(bool firstflag) LoadLighting(&file, &VisionList[i]); } - for (int &itemId : ActiveItems) - itemId = file.NextLE(); - for (int &itemId : AvailableItems) - itemId = file.NextLE(); - for (int i = 0; i < ActiveItemCount; i++) - LoadItem(file, Items[ActiveItems[i]]); + auto itemIndexes = LoadDroppedItems(file); + for (bool &uniqueItemFlag : UniqueItemFlags) uniqueItemFlag = file.NextBool8(); @@ -1809,10 +1845,8 @@ void LoadGame(bool firstflag) for (int i = 0; i < MAXDUNX; i++) // NOLINT(modernize-loop-convert) dPlayer[i][j] = file.NextLE(); } - for (int j = 0; j < MAXDUNY; j++) { - for (int i = 0; i < MAXDUNX; i++) // NOLINT(modernize-loop-convert) - dItem[i][j] = file.NextLE(); - } + + LoadDroppedItemLocations(file, itemIndexes); if (leveltype != DTYPE_TOWN) { for (int j = 0; j < MAXDUNY; j++) { @@ -2177,21 +2211,14 @@ void LoadLevel() } } - for (int &itemId : ActiveItems) - itemId = file.NextLE(); - for (int &itemId : AvailableItems) - itemId = file.NextLE(); - for (int i = 0; i < ActiveItemCount; i++) - LoadItem(file, Items[ActiveItems[i]]); + auto itemIndexes = LoadDroppedItems(file); for (int j = 0; j < MAXDUNY; j++) { for (int i = 0; i < MAXDUNX; i++) // NOLINT(modernize-loop-convert) dFlags[i][j] = static_cast(file.NextLE()) & DungeonFlag::LoadedFlags; } - for (int j = 0; j < MAXDUNY; j++) { - for (int i = 0; i < MAXDUNX; i++) // NOLINT(modernize-loop-convert) - dItem[i][j] = file.NextLE(); - } + + LoadDroppedItemLocations(file, itemIndexes); if (leveltype != DTYPE_TOWN) { for (int j = 0; j < MAXDUNY; j++) {