Skip to content

Commit

Permalink
Extract spell data to a TSV
Browse files Browse the repository at this point in the history
  • Loading branch information
glebm committed Dec 5, 2023
1 parent 2da492d commit 124d113
Show file tree
Hide file tree
Showing 13 changed files with 368 additions and 77 deletions.
1 change: 1 addition & 0 deletions CMake/Assets.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ set(devilutionx_assets
txtdata/monsters/monstdat.tsv
txtdata/monsters/unique_monstdat.tsv
txtdata/sound/effects.tsv
txtdata/spells/spelldat.tsv
ui_art/diablo.pal
ui_art/hellfire.pal
ui_art/creditsw.clx
Expand Down
42 changes: 41 additions & 1 deletion Source/data/iterators.hpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#pragma once

#include <charconv>
#include <optional>
#include <ostream>

#include <expected.hpp>
#include <function_ref.hpp>

#include "parser.hpp"
#include "utils/parse_int.hpp"
#include "utils/str_cat.hpp"
#include "utils/str_split.hpp"

namespace devilution {
Expand Down Expand Up @@ -157,6 +158,45 @@ class DataFileField {
return parseIntArray<T>(destination.data(), N);
}

template <typename T, typename ParseFn>
[[nodiscard]] tl::expected<void, std::string> parseEnumArray(T *destination, size_t n, std::optional<T> fillMissing, ParseFn &&parseFn)
{
size_t i = 0;
const std::string_view str = value();
if (!str.empty()) {
for (const std::string_view part : SplitByChar(str, ',')) {
if (i == n)
return tl::make_unexpected(StrCat("Too many values, max: ", n));
auto result = parseFn(part);
if (!result.has_value()) {
return tl::make_unexpected(std::move(result).error());
}
destination[i++] = *result;
}
}
if (i != n) {
if (!fillMissing.has_value()) {
return tl::make_unexpected(StrCat("Too few values, expected ", n, " got ", i));
}
while (i < n) {
destination[i++] = *fillMissing;
}
}
return {};
}

template <typename T, size_t N, typename ParseFn>
[[nodiscard]] tl::expected<void, std::string> parseEnumArray(T (&destination)[N], std::optional<T> fillMissing, ParseFn &&parseFn)
{
return parseEnumArray<T, ParseFn>(destination, N, std::move(fillMissing), std::forward<ParseFn>(parseFn));
}

template <typename T, size_t N, typename ParseFn>
[[nodiscard]] tl::expected<void, std::string> parseIntArray(std::array<T, N> &destination, std::optional<T> fillMissing, ParseFn &&parseFn)
{
return parseEnumArray<T, ParseFn>(destination.data(), N, std::move(fillMissing), std::forward<ParseFn>(parseFn));
}

template <typename T, typename ParseFn>
[[nodiscard]] tl::expected<void, std::string> parseEnumList(T &destination, ParseFn &&parseFn)
{
Expand Down
37 changes: 21 additions & 16 deletions Source/data/record_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,50 +28,51 @@ class RecordReader {
typename std::enable_if_t<std::is_integral_v<T>, void>
readInt(std::string_view name, T &out)
{
advance();
DataFileField field = *it_;
DataFileField field = nextField();
failOnError(field.parseInt(out), name, field);
}

template <typename T>
typename std::enable_if_t<std::is_integral_v<T>, void>
readOptionalInt(std::string_view name, T &out)
{
advance();
DataFileField field = *it_;
DataFileField field = nextField();
if (field.value().empty()) return;
failOnError(field.parseInt(out), name, field);
}

template <typename T, size_t N>
void readIntArray(std::string_view name, T (&out)[N])
{
advance();
DataFileField field = *it_;
DataFileField field = nextField();
failOnError(field.parseIntArray(out), name, field);
}

template <typename T, size_t N, typename F>
void readEnumArray(std::string_view name, std::optional<T> fillMissing, T (&out)[N], F &&parseFn)
{
DataFileField field = nextField();
failOnError(field.parseEnumArray(out, fillMissing, parseFn), name, field, DataFileField::Error::InvalidValue);
}

template <typename T, size_t N>
void readIntArray(std::string_view name, std::array<T, N> &out)
{
advance();
DataFileField field = *it_;
DataFileField field = nextField();
failOnError(field.parseIntArray(out), name, field);
}

template <typename T>
typename std::enable_if_t<std::is_integral_v<T>, void>
readFixed6(std::string_view name, T &out)
{
advance();
DataFileField field = *it_;
DataFileField field = nextField();
failOnError(field.parseFixed6(out), name, field);
}

void readBool(std::string_view name, bool &out)
{
advance();
DataFileField field = *it_;
DataFileField field = nextField();
failOnError(field.parseBool(out), name, field);
}

Expand All @@ -84,8 +85,7 @@ class RecordReader {
template <typename T, typename F>
void read(std::string_view name, T &out, F &&parseFn)
{
advance();
DataFileField field = *it_;
DataFileField field = nextField();
tl::expected<T, std::string> result = parseFn(field.value());
failOnError(result, name, field, DataFileField::Error::InvalidValue);
out = *std::move(result);
Expand All @@ -94,8 +94,7 @@ class RecordReader {
template <typename T, typename F>
void readEnumList(std::string_view name, T &out, F &&parseFn)
{
advance();
DataFileField field = *it_;
DataFileField field = nextField();
failOnError(field.parseEnumList(out, std::forward<F>(parseFn)),
name, field, DataFileField::Error::InvalidValue);
}
Expand All @@ -109,6 +108,12 @@ class RecordReader {

void advance();

DataFileField nextField()
{
advance();
return *it_;
}

private:
template <typename T>
void failOnError(const tl::expected<T, DataFileField::Error> &result, std::string_view name, const DataFileField &field)
Expand Down
1 change: 1 addition & 0 deletions Source/diablo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2476,6 +2476,7 @@ int DiabloMain(int argc, char **argv)
LoadPlayerDataFiles();

// TODO: We can probably load this much later (when the game is starting).
LoadSpellData();
LoadMissileData();
LoadMonsterData();
LoadItemData();
Expand Down
Loading

0 comments on commit 124d113

Please sign in to comment.