Browse Source

Added Lua Bindings for Adding Unique Items

pull/6727/merge
Andrettin 7 months ago committed by GitHub
parent
commit
e2e8446be1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      Source/CMakeLists.txt
  2. 37
      Source/itemdat.cpp
  3. 7
      Source/itemdat.h
  4. 2
      Source/items.h
  5. 34
      Source/loadsave.cpp
  6. 11
      Source/lua/modules/items.cpp
  7. 4
      assets/lua/devilutionx/events.lua

1
Source/CMakeLists.txt

@ -473,6 +473,7 @@ add_devilutionx_object_library(libdevilutionx_items
) )
target_link_dependencies(libdevilutionx_items PUBLIC target_link_dependencies(libdevilutionx_items PUBLIC
DevilutionX::SDL DevilutionX::SDL
sol2::sol2
tl tl
libdevilutionx_headless_mode libdevilutionx_headless_mode
libdevilutionx_sound libdevilutionx_sound

37
Source/itemdat.cpp

@ -10,10 +10,12 @@
#include <vector> #include <vector>
#include <expected.hpp> #include <expected.hpp>
#include <fmt/format.h>
#include "data/file.hpp" #include "data/file.hpp"
#include "data/iterators.hpp" #include "data/iterators.hpp"
#include "data/record_reader.hpp" #include "data/record_reader.hpp"
#include "lua/lua_global.hpp"
#include "spelldat.h" #include "spelldat.h"
#include "utils/str_cat.hpp" #include "utils/str_cat.hpp"
@ -25,6 +27,9 @@ std::vector<ItemData> AllItemsList;
/** Contains the data related to each unique item ID. */ /** Contains the data related to each unique item ID. */
std::vector<UniqueItem> UniqueItems; std::vector<UniqueItem> UniqueItems;
/** Contains unique item mapping IDs, with unique item indices assigned to them. This is used for loading saved games. */
ankerl::unordered_dense::map<int32_t, int32_t> UniqueItemMappingIdsToIndices;
/** Contains the data related to each item prefix. */ /** Contains the data related to each item prefix. */
std::vector<PLStruct> ItemPrefixes; std::vector<PLStruct> ItemPrefixes;
@ -559,14 +564,14 @@ void ReadItemPower(RecordReader &reader, std::string_view fieldName, ItemPower &
reader.readOptionalInt(StrCat(fieldName, ".value2"), power.param2); reader.readOptionalInt(StrCat(fieldName, ".value2"), power.param2);
} }
void LoadUniqueItemDat() } // namespace
void LoadUniqueItemDatFromFile(DataFile &dataFile, std::string_view filename, int32_t baseMappingId)
{ {
const std::string_view filename = "txtdata\\items\\unique_itemdat.tsv";
DataFile dataFile = DataFile::loadOrDie(filename);
dataFile.skipHeaderOrDie(filename); dataFile.skipHeaderOrDie(filename);
UniqueItems.clear(); int32_t currentMappingId = baseMappingId;
UniqueItems.reserve(dataFile.numRecords()); UniqueItems.reserve(UniqueItems.size() + dataFile.numRecords());
for (DataFileRecord record : dataFile) { for (DataFileRecord record : dataFile) {
RecordReader reader { record, filename }; RecordReader reader { record, filename };
UniqueItem &item = UniqueItems.emplace_back(); UniqueItem &item = UniqueItems.emplace_back();
@ -583,10 +588,32 @@ void LoadUniqueItemDat()
break; break;
ReadItemPower(reader, StrCat("power", i), item.powers[item.UINumPL++]); ReadItemPower(reader, StrCat("power", i), item.powers[item.UINumPL++]);
} }
item.mappingId = currentMappingId;
const auto [it, inserted] = UniqueItemMappingIdsToIndices.emplace(item.mappingId, static_cast<int32_t>(UniqueItems.size()) - 1);
if (!inserted) {
DisplayFatalErrorAndExit("Adding Unique Item Failed", fmt::format("A unique item already exists for mapping ID {}.", item.mappingId));
}
++currentMappingId;
} }
UniqueItems.shrink_to_fit(); UniqueItems.shrink_to_fit();
} }
namespace {
void LoadUniqueItemDat()
{
const std::string_view filename = "txtdata\\items\\unique_itemdat.tsv";
DataFile dataFile = DataFile::loadOrDie(filename);
UniqueItems.clear();
UniqueItemMappingIdsToIndices.clear();
LoadUniqueItemDatFromFile(dataFile, filename, 0);
LuaEvent("UniqueItemDataLoaded");
}
void LoadItemAffixesDat(std::string_view filename, std::vector<PLStruct> &out) void LoadItemAffixesDat(std::string_view filename, std::vector<PLStruct> &out)
{ {
DataFile dataFile = DataFile::loadOrDie(filename); DataFile dataFile = DataFile::loadOrDie(filename);

7
Source/itemdat.h

@ -9,11 +9,15 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#include <ankerl/unordered_dense.h>
#include "objdat.h" #include "objdat.h"
#include "spelldat.h" #include "spelldat.h"
namespace devilution { namespace devilution {
class DataFile;
/** @todo add missing values and apply */ /** @todo add missing values and apply */
enum _item_indexes : int16_t { // TODO defines all indexes in AllItemsList enum _item_indexes : int16_t { // TODO defines all indexes in AllItemsList
IDI_GOLD, IDI_GOLD,
@ -637,13 +641,16 @@ struct UniqueItem {
uint8_t UINumPL; uint8_t UINumPL;
int UIValue; int UIValue;
ItemPower powers[6]; ItemPower powers[6];
int32_t mappingId;
}; };
extern DVL_API_FOR_TEST std::vector<ItemData> AllItemsList; extern DVL_API_FOR_TEST std::vector<ItemData> AllItemsList;
extern std::vector<PLStruct> ItemPrefixes; extern std::vector<PLStruct> ItemPrefixes;
extern std::vector<PLStruct> ItemSuffixes; extern std::vector<PLStruct> ItemSuffixes;
extern DVL_API_FOR_TEST std::vector<UniqueItem> UniqueItems; extern DVL_API_FOR_TEST std::vector<UniqueItem> UniqueItems;
extern ankerl::unordered_dense::map<int32_t, int32_t> UniqueItemMappingIdsToIndices;
void LoadUniqueItemDatFromFile(DataFile &dataFile, std::string_view filename, int32_t baseMappingId);
void LoadItemData(); void LoadItemData();
} // namespace devilution } // namespace devilution

2
Source/items.h

@ -43,7 +43,7 @@ enum item_quality : uint8_t {
ITEM_QUALITY_UNIQUE, ITEM_QUALITY_UNIQUE,
}; };
enum _unique_items : int8_t { enum _unique_items : int32_t {
UITEM_CLEAVER, UITEM_CLEAVER,
UITEM_SKCROWN, UITEM_SKCROWN,
UITEM_INFRARING, UITEM_INFRARING,

34
Source/loadsave.cpp

@ -263,7 +263,7 @@ struct LevelConversionData {
MonsterConversionData monsterConversionData[MaxMonsters]; MonsterConversionData monsterConversionData[MaxMonsters];
}; };
void LoadItemData(LoadHelper &file, Item &item) [[nodiscard]] bool LoadItemData(LoadHelper &file, Item &item)
{ {
item._iSeed = file.NextLE<uint32_t>(); item._iSeed = file.NextLE<uint32_t>();
item._iCreateInfo = file.NextLE<uint16_t>(); item._iCreateInfo = file.NextLE<uint16_t>();
@ -321,7 +321,20 @@ void LoadItemData(LoadHelper &file, Item &item)
item._iSplLvlAdd = file.NextLE<int8_t>(); item._iSplLvlAdd = file.NextLE<int8_t>();
item._iRequest = file.NextBool8(); item._iRequest = file.NextBool8();
file.Skip(2); // Alignment file.Skip(2); // Alignment
item._iUid = file.NextLE<int32_t>();
const int32_t uniqueMappingId = file.NextLE<int32_t>();
if (item._iMagical == ITEM_QUALITY_UNIQUE) {
const auto findIt = UniqueItemMappingIdsToIndices.find(uniqueMappingId);
if (findIt == UniqueItemMappingIdsToIndices.end()) {
return false;
}
const int uniqueIndex = findIt->second;
item._iUid = uniqueIndex;
} else {
item._iUid = 0;
}
item._iFMinDam = file.NextLE<int32_t>(); item._iFMinDam = file.NextLE<int32_t>();
item._iFMaxDam = file.NextLE<int32_t>(); item._iFMaxDam = file.NextLE<int32_t>();
item._iLMinDam = file.NextLE<int32_t>(); item._iLMinDam = file.NextLE<int32_t>();
@ -352,11 +365,18 @@ void LoadItemData(LoadHelper &file, Item &item)
else else
item._iDamAcFlags = ItemSpecialEffectHf::None; item._iDamAcFlags = ItemSpecialEffectHf::None;
UpdateHellfireFlag(item, item._iIName); UpdateHellfireFlag(item, item._iIName);
return true;
} }
void LoadAndValidateItemData(LoadHelper &file, Item &item) void LoadAndValidateItemData(LoadHelper &file, Item &item)
{ {
LoadItemData(file, item); const bool success = LoadItemData(file, item);
if (!success) {
item.clear();
return;
}
RemoveInvalidItem(item); RemoveInvalidItem(item);
} }
@ -1052,7 +1072,11 @@ void LoadMatchingItems(LoadHelper &file, const Player &player, const int n, Item
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
Item &unpackedItem = pItem[i]; Item &unpackedItem = pItem[i];
LoadItemData(file, heroItem); const bool success = LoadItemData(file, heroItem);
if (!success) {
heroItem.clear();
unpackedItem = Item();
}
if (unpackedItem.isEmpty() || heroItem.isEmpty()) if (unpackedItem.isEmpty() || heroItem.isEmpty())
continue; continue;
if (unpackedItem._iSeed != heroItem._iSeed) if (unpackedItem._iSeed != heroItem._iSeed)
@ -1190,7 +1214,7 @@ void SaveItem(SaveHelper &file, const Item &item)
file.WriteLE<int8_t>(item._iSplLvlAdd); file.WriteLE<int8_t>(item._iSplLvlAdd);
file.WriteLE<int8_t>(item._iRequest ? 1 : 0); file.WriteLE<int8_t>(item._iRequest ? 1 : 0);
file.Skip(2); // Alignment file.Skip(2); // Alignment
file.WriteLE<int32_t>(item._iUid); file.WriteLE<int32_t>(UniqueItems[item._iUid].mappingId);
file.WriteLE<int32_t>(item._iFMinDam); file.WriteLE<int32_t>(item._iFMinDam);
file.WriteLE<int32_t>(item._iFMaxDam); file.WriteLE<int32_t>(item._iFMaxDam);
file.WriteLE<int32_t>(item._iLMinDam); file.WriteLE<int32_t>(item._iLMinDam);

11
Source/lua/modules/items.cpp

@ -2,8 +2,11 @@
#include <string_view> #include <string_view>
#include <fmt/format.h>
#include <sol/sol.hpp> #include <sol/sol.hpp>
#include "data/file.hpp"
#include "itemdat.h"
#include "items.h" #include "items.h"
#include "lua/metadoc.hpp" #include "lua/metadoc.hpp"
#include "player.h" #include "player.h"
@ -451,6 +454,12 @@ void RegisterItemSpecialEffectHfEnum(sol::state_view &lua)
}); });
} }
void AddUniqueItemDataFromTsv(const std::string_view path, const int32_t baseMappingId)
{
DataFile dataFile = DataFile::loadOrDie(path);
LoadUniqueItemDatFromFile(dataFile, path, baseMappingId);
}
} // namespace } // namespace
sol::table LuaItemModule(sol::state_view &lua) sol::table LuaItemModule(sol::state_view &lua)
@ -468,6 +477,8 @@ sol::table LuaItemModule(sol::state_view &lua)
sol::table table = lua.create_table(); sol::table table = lua.create_table();
LuaSetDocFn(table, "addUniqueItemDataFromTsv", "(path: string, baseMappingId: number)", AddUniqueItemDataFromTsv);
return table; return table;
} }

4
assets/lua/devilutionx/events.lua

@ -44,6 +44,10 @@ local events = {
LoadModsComplete = CreateEvent(), LoadModsComplete = CreateEvent(),
__doc_LoadModsComplete = "Called after all mods have been loaded.", __doc_LoadModsComplete = "Called after all mods have been loaded.",
---Called after the unique item data TSV file has been loaded.
UniqueItemDataLoaded = CreateEvent(),
__doc_UniqueItemDataLoaded = "Called after the unique item data TSV file has been loaded.",
---Called after the monster data TSV file has been loaded. ---Called after the monster data TSV file has been loaded.
MonsterDataLoaded = CreateEvent(), MonsterDataLoaded = CreateEvent(),
__doc_MonsterDataLoaded = "Called after the monster data TSV file has been loaded.", __doc_MonsterDataLoaded = "Called after the monster data TSV file has been loaded.",

Loading…
Cancel
Save