Skip to content

Commit

Permalink
LoadClassAttributes: Mandate field order
Browse files Browse the repository at this point in the history
Makes parsing simpler.

Additional columns and rows are ignored.
  • Loading branch information
glebm committed Sep 17, 2023
1 parent 5ae44d7 commit b29a00a
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 114 deletions.
32 changes: 16 additions & 16 deletions Packaging/resources/assets/txtdata/classes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ There is one folder per class.

Attribute | Description
-------------:|--------------------------------------
`baseStr` | Class Starting Strength Stat
`baseMag` | Class Starting Magic Stat
`baseDex` | Class Starting Dexterity Stat
`baseVit` | Class Starting Vitality Stat
`maxStr` | Class Maximum Strength Stat
`maxMag` | Class Maximum Magic Stat
`maxDex` | Class Maximum Dexterity Stat
`maxVit` | Class Maximum Vitality Stat
`baseStr` | Class Starting Strength Stat, uint8_t
`baseMag` | Class Starting Magic Stat, uint8_t
`baseDex` | Class Starting Dexterity Stat, uint8_t
`baseVit` | Class Starting Vitality Stat, uint8_t
`maxStr` | Class Maximum Strength Stat, uint8_t
`maxMag` | Class Maximum Magic Stat, uint8_t
`maxDex` | Class Maximum Dexterity Stat, uint8_t
`maxVit` | Class Maximum Vitality Stat, uint8_t
`blockBonus` | Class Block Bonus, %
`adjLife` | Class Life Adjustment, 1/64
`adjMana` | Class Mana Adjustment, 1/64
`lvlLife` | Life gained on level up, 1/64
`lvlMana` | Mana gained on level up, 1/64
`chrLife` | Life from base Vitality, 1/64
`chrMana` | Mana from base Magic, 1/64
`itmLife` | Life from item bonus Vitality, 1/64
`itmMana` | Mana from item bonus Magic, 1/64
`adjLife` | Class Life Adjustment, decimal
`adjMana` | Class Mana Adjustment, decimal
`lvlLife` | Life gained on level up, decimal
`lvlMana` | Mana gained on level up, decimal
`chrLife` | Life from base Vitality, decimal
`chrMana` | Mana from base Magic, decimal
`itmLife` | Life from item bonus Vitality, decimal
`itmMana` | Mana from item bonus Magic, decimal
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ maxMag 0
maxDex 55
maxVit 150
blockBonus 30
adjLife 1152
adjLife 18
adjMana 0
lvlLife 128
lvlLife 2
lvlMana 0
chrLife 128
chrMana 64
itmLife 160
itmMana 64
chrLife 2
chrMana 1
itmLife 2.5
itmMana 1
16 changes: 8 additions & 8 deletions Packaging/resources/assets/txtdata/classes/bard/attributes.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ maxMag 120
maxDex 120
maxVit 100
blockBonus 25
adjLife 1472
adjMana 192
lvlLife 128
lvlMana 128
chrLife 64
chrMana 96
itmLife 96
itmMana 112
adjLife 23
adjMana 3
lvlLife 2
lvlMana 2
chrLife 1
chrMana 1.5
itmLife 1.5
itmMana 1.75
16 changes: 8 additions & 8 deletions Packaging/resources/assets/txtdata/classes/monk/attributes.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ maxMag 80
maxDex 150
maxVit 80
blockBonus 25
adjLife 1472
adjMana 352
lvlLife 128
lvlMana 128
chrLife 64
chrMana 64
itmLife 96
itmMana 96
adjLife 23
adjMana 5.5
lvlLife 2
lvlMana 2
chrLife 1
chrMana 1
itmLife 1.5
itmMana 1.5
16 changes: 8 additions & 8 deletions Packaging/resources/assets/txtdata/classes/rogue/attributes.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ maxMag 70
maxDex 250
maxVit 80
blockBonus 20
adjLife 1472
adjMana 352
lvlLife 128
lvlMana 128
chrLife 64
chrMana 64
itmLife 96
itmMana 96
adjLife 23
adjMana 5.5
lvlLife 2
lvlMana 2
chrLife 1
chrMana 1
itmLife 1.5
itmMana 1.5
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ maxMag 250
maxDex 85
maxVit 80
blockBonus 10
adjLife 576
adjMana -128
lvlLife 64
lvlMana 128
chrLife 64
chrMana 128
itmLife 64
itmMana 128
adjLife 9
adjMana -2
lvlLife 1
lvlMana 2
chrLife 1
chrMana 2
itmLife 1
itmMana 2
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ maxMag 50
maxDex 60
maxVit 100
blockBonus 30
adjLife 1152
adjMana -64
lvlLife 128
lvlMana 64
chrLife 128
chrMana 64
itmLife 128
itmMana 64
adjLife 18
adjMana -1
lvlLife 2
lvlMana 1
chrLife 2
chrMana 1
itmLife 2
itmMana 1
4 changes: 2 additions & 2 deletions Source/data/iterators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ class DataFileField {

static tl::expected<void, Error> mapError(std::errc ec)
{
switch (ec) {
case std::errc():
if (ec == std::errc())
return {};
switch (ec) {
case std::errc::result_out_of_range:
return tl::unexpected { Error::OutOfRange };
case std::errc::invalid_argument:
Expand Down
97 changes: 47 additions & 50 deletions Source/playerdat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
#include <bitset>
#include <charconv>
#include <cstdint>
#include <unordered_map>
#include <variant>
#include <vector>

#include <expected.hpp>
Expand Down Expand Up @@ -169,65 +167,64 @@ void LoadClassAttributes(std::string_view classPath, ClassAttributes &out)
DataFile::reportFatalError(result.error(), filename);
}

struct KeyInfo {
std::variant<uint8_t *, int16_t *> out;
bool found = false;
};
std::unordered_map<std::string_view, KeyInfo> keyToField {
{ "baseStr", KeyInfo { &out.baseStr } },
{ "baseMag", KeyInfo { &out.baseMag } },
{ "baseDex", KeyInfo { &out.baseDex } },
{ "baseVit", KeyInfo { &out.baseVit } },
{ "maxStr", KeyInfo { &out.maxStr } },
{ "maxMag", KeyInfo { &out.maxMag } },
{ "maxDex", KeyInfo { &out.maxDex } },
{ "maxVit", KeyInfo { &out.maxVit } },
{ "blockBonus", KeyInfo { &out.blockBonus } },
{ "adjLife", KeyInfo { &out.adjLife } },
{ "adjMana", KeyInfo { &out.adjMana } },
{ "lvlLife", KeyInfo { &out.lvlLife } },
{ "lvlMana", KeyInfo { &out.lvlMana } },
{ "chrLife", KeyInfo { &out.chrLife } },
{ "chrMana", KeyInfo { &out.chrMana } },
{ "itmLife", KeyInfo { &out.itmLife } },
{ "itmMana", KeyInfo { &out.itmMana } },
};
for (DataFileRecord record : dataFile) {
auto recordIt = dataFile.begin();
const auto recordEnd = dataFile.end();

const auto getValueField = [&](std::string_view expectedKey) {
if (recordIt == recordEnd) {
app_fatal(fmt::format("Missing field {} in {}", expectedKey, filename));
}
DataFileRecord record = *recordIt;
FieldIterator fieldIt = record.begin();
const FieldIterator endField = record.end();

const std::string_view key = (*fieldIt).value();
if (key != expectedKey) {
app_fatal(fmt::format("Unexpected field in {}: got {}, expected {}", filename, key, expectedKey));
}

++fieldIt;
if (fieldIt == endField) {
DataFile::reportFatalError(DataFile::Error::NotEnoughColumns, filename);
}
DataFileField valueField = *fieldIt;
return *fieldIt;
};

auto mappingIt = keyToField.find(key);
if (mappingIt == keyToField.end()) {
app_fatal(fmt::format("Unknown field {} in {}", key, filename));
}
KeyInfo &keyInfo = mappingIt->second;
if (keyInfo.found) {
app_fatal(fmt::format("Duplicate field {} in {}", key, filename));
}
std::visit([&](auto *outField) {
auto parseIntResult = valueField.parseInt(*outField);
if (parseIntResult != std::errc()) {
DataFile::reportFatalFieldError(parseIntResult, filename, "Value", valueField);
const auto valueReader = [&](auto &&readFn) {
return [&](std::string_view expectedKey, auto &outValue) {
DataFileField valueField = getValueField(expectedKey);
if (const tl::expected<void, devilution::DataFileField::Error> result = readFn(valueField, outValue);
!result.has_value()) {
DataFile::reportFatalFieldError(result.error(), filename, "Value", valueField);
}
},
keyInfo.out);
keyInfo.found = true;

++fieldIt;
}
++recordIt;
};
};

for (const auto &[key, keyInfo] : keyToField) {
if (!keyInfo.found) {
app_fatal(fmt::format("Missing field {} in {}", key, filename));
}
}
const auto readInt = valueReader([](DataFileField &valueField, auto &outValue) {
return valueField.parseInt(outValue);
});
const auto readDecimal = valueReader([](DataFileField &valueField, auto &outValue) {
return valueField.parseFixed6(outValue);
});

readInt("baseStr", out.baseStr);
readInt("baseMag", out.baseMag);
readInt("baseDex", out.baseDex);
readInt("baseVit", out.baseVit);
readInt("maxStr", out.maxStr);
readInt("maxMag", out.maxMag);
readInt("maxDex", out.maxDex);
readInt("maxVit", out.maxVit);
readInt("blockBonus", out.blockBonus);
readDecimal("adjLife", out.adjLife);
readDecimal("adjMana", out.adjMana);
readDecimal("lvlLife", out.lvlLife);
readDecimal("lvlMana", out.lvlMana);
readDecimal("chrLife", out.chrLife);
readDecimal("chrMana", out.chrMana);
readDecimal("itmLife", out.itmLife);
readDecimal("itmMana", out.itmMana);
}

std::vector<ClassAttributes> ClassAttributesPerClass;
Expand Down

0 comments on commit b29a00a

Please sign in to comment.