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
DevilutionX::SDL
sol2::sol2
tl
libdevilutionx_headless_mode
libdevilutionx_sound

37
Source/itemdat.cpp

@ -10,10 +10,12 @@
#include <vector>
#include <expected.hpp>
#include <fmt/format.h>
#include "data/file.hpp"
#include "data/iterators.hpp"
#include "data/record_reader.hpp"
#include "lua/lua_global.hpp"
#include "spelldat.h"
#include "utils/str_cat.hpp"
@ -25,6 +27,9 @@ std::vector<ItemData> AllItemsList;
/** Contains the data related to each unique item ID. */
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. */
std::vector<PLStruct> ItemPrefixes;
@ -559,14 +564,14 @@ void ReadItemPower(RecordReader &reader, std::string_view fieldName, ItemPower &
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);
UniqueItems.clear();
UniqueItems.reserve(dataFile.numRecords());
int32_t currentMappingId = baseMappingId;
UniqueItems.reserve(UniqueItems.size() + dataFile.numRecords());
for (DataFileRecord record : dataFile) {
RecordReader reader { record, filename };
UniqueItem &item = UniqueItems.emplace_back();
@ -583,10 +588,32 @@ void LoadUniqueItemDat()
break;
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();
}
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)
{
DataFile dataFile = DataFile::loadOrDie(filename);

7
Source/itemdat.h

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

2
Source/items.h

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

34
Source/loadsave.cpp

@ -263,7 +263,7 @@ struct LevelConversionData {
MonsterConversionData monsterConversionData[MaxMonsters];
};
void LoadItemData(LoadHelper &file, Item &item)
[[nodiscard]] bool LoadItemData(LoadHelper &file, Item &item)
{
item._iSeed = file.NextLE<uint32_t>();
item._iCreateInfo = file.NextLE<uint16_t>();
@ -321,7 +321,20 @@ void LoadItemData(LoadHelper &file, Item &item)
item._iSplLvlAdd = file.NextLE<int8_t>();
item._iRequest = file.NextBool8();
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._iFMaxDam = file.NextLE<int32_t>();
item._iLMinDam = file.NextLE<int32_t>();
@ -352,11 +365,18 @@ void LoadItemData(LoadHelper &file, Item &item)
else
item._iDamAcFlags = ItemSpecialEffectHf::None;
UpdateHellfireFlag(item, item._iIName);
return true;
}
void LoadAndValidateItemData(LoadHelper &file, Item &item)
{
LoadItemData(file, item);
const bool success = LoadItemData(file, item);
if (!success) {
item.clear();
return;
}
RemoveInvalidItem(item);
}
@ -1052,7 +1072,11 @@ void LoadMatchingItems(LoadHelper &file, const Player &player, const int n, Item
for (int i = 0; i < n; 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())
continue;
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._iRequest ? 1 : 0);
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._iFMaxDam);
file.WriteLE<int32_t>(item._iLMinDam);

11
Source/lua/modules/items.cpp

@ -2,8 +2,11 @@
#include <string_view>
#include <fmt/format.h>
#include <sol/sol.hpp>
#include "data/file.hpp"
#include "itemdat.h"
#include "items.h"
#include "lua/metadoc.hpp"
#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
sol::table LuaItemModule(sol::state_view &lua)
@ -468,6 +477,8 @@ sol::table LuaItemModule(sol::state_view &lua)
sol::table table = lua.create_table();
LuaSetDocFn(table, "addUniqueItemDataFromTsv", "(path: string, baseMappingId: number)", AddUniqueItemDataFromTsv);
return table;
}

4
assets/lua/devilutionx/events.lua

@ -44,6 +44,10 @@ local events = {
LoadModsComplete = CreateEvent(),
__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.
MonsterDataLoaded = CreateEvent(),
__doc_MonsterDataLoaded = "Called after the monster data TSV file has been loaded.",

Loading…
Cancel
Save