From b29a00a6f4fe760e195b4b8b5d7e8023d4144a99 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Sat, 16 Sep 2023 12:50:25 +0100 Subject: [PATCH] `LoadClassAttributes`: Mandate field order Makes parsing simpler. Additional columns and rows are ignored. --- .../assets/txtdata/classes/README.md | 32 +++--- .../txtdata/classes/barbarian/attributes.tsv | 12 +-- .../txtdata/classes/bard/attributes.tsv | 16 +-- .../txtdata/classes/monk/attributes.tsv | 16 +-- .../txtdata/classes/rogue/attributes.tsv | 16 +-- .../txtdata/classes/sorcerer/attributes.tsv | 16 +-- .../txtdata/classes/warrior/attributes.tsv | 16 +-- Source/data/iterators.hpp | 4 +- Source/playerdat.cpp | 97 +++++++++---------- 9 files changed, 111 insertions(+), 114 deletions(-) diff --git a/Packaging/resources/assets/txtdata/classes/README.md b/Packaging/resources/assets/txtdata/classes/README.md index bbbcd52f85a..92ab3c2fd99 100644 --- a/Packaging/resources/assets/txtdata/classes/README.md +++ b/Packaging/resources/assets/txtdata/classes/README.md @@ -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 diff --git a/Packaging/resources/assets/txtdata/classes/barbarian/attributes.tsv b/Packaging/resources/assets/txtdata/classes/barbarian/attributes.tsv index 95ae7b5186a..58d2dff0ca4 100644 --- a/Packaging/resources/assets/txtdata/classes/barbarian/attributes.tsv +++ b/Packaging/resources/assets/txtdata/classes/barbarian/attributes.tsv @@ -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 diff --git a/Packaging/resources/assets/txtdata/classes/bard/attributes.tsv b/Packaging/resources/assets/txtdata/classes/bard/attributes.tsv index bb3d9b02ae7..42046db254a 100644 --- a/Packaging/resources/assets/txtdata/classes/bard/attributes.tsv +++ b/Packaging/resources/assets/txtdata/classes/bard/attributes.tsv @@ -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 diff --git a/Packaging/resources/assets/txtdata/classes/monk/attributes.tsv b/Packaging/resources/assets/txtdata/classes/monk/attributes.tsv index c20339647e1..bb6e98d41fe 100644 --- a/Packaging/resources/assets/txtdata/classes/monk/attributes.tsv +++ b/Packaging/resources/assets/txtdata/classes/monk/attributes.tsv @@ -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 diff --git a/Packaging/resources/assets/txtdata/classes/rogue/attributes.tsv b/Packaging/resources/assets/txtdata/classes/rogue/attributes.tsv index fe3a7254039..15a7e2e1101 100644 --- a/Packaging/resources/assets/txtdata/classes/rogue/attributes.tsv +++ b/Packaging/resources/assets/txtdata/classes/rogue/attributes.tsv @@ -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 diff --git a/Packaging/resources/assets/txtdata/classes/sorcerer/attributes.tsv b/Packaging/resources/assets/txtdata/classes/sorcerer/attributes.tsv index 39f7308d4d0..188d2d49740 100644 --- a/Packaging/resources/assets/txtdata/classes/sorcerer/attributes.tsv +++ b/Packaging/resources/assets/txtdata/classes/sorcerer/attributes.tsv @@ -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 diff --git a/Packaging/resources/assets/txtdata/classes/warrior/attributes.tsv b/Packaging/resources/assets/txtdata/classes/warrior/attributes.tsv index cac4626d18a..cf3fec85d04 100644 --- a/Packaging/resources/assets/txtdata/classes/warrior/attributes.tsv +++ b/Packaging/resources/assets/txtdata/classes/warrior/attributes.tsv @@ -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 diff --git a/Source/data/iterators.hpp b/Source/data/iterators.hpp index c81745d892b..83f00ee1684 100644 --- a/Source/data/iterators.hpp +++ b/Source/data/iterators.hpp @@ -25,9 +25,9 @@ class DataFileField { static tl::expected 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: diff --git a/Source/playerdat.cpp b/Source/playerdat.cpp index b23efe32969..addab81c6f4 100644 --- a/Source/playerdat.cpp +++ b/Source/playerdat.cpp @@ -11,8 +11,6 @@ #include #include #include -#include -#include #include #include @@ -169,65 +167,64 @@ void LoadClassAttributes(std::string_view classPath, ClassAttributes &out) DataFile::reportFatalError(result.error(), filename); } - struct KeyInfo { - std::variant out; - bool found = false; - }; - std::unordered_map 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 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 ClassAttributesPerClass;