From e69eacaa9bd65ab2d6f1c42749f5a0734423f3c9 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 22 Aug 2021 12:10:26 +0200 Subject: [PATCH] Set up standard functions for building tools --- BuildItems.cpp | 101 ++++++++++++++++++++++++++++ BuildItems.hpp | 10 +++ BuildLibrary.hpp | 61 +++++++++++++++++ BuildMoves.cpp | 113 ++++++++++++++++++++++++++++++++ BuildMoves.hpp | 11 ++++ BuildNatures.cpp | 86 ++++++++++++++++++++++++ BuildNatures.hpp | 10 +++ BuildSpecies.cpp | 145 +++++++++++++++++++++++++++++++++++++++++ BuildSpecies.hpp | 22 +++++++ BuildTypes.cpp | 68 +++++++++++++++++++ BuildTypes.hpp | 13 ++++ GrowthRatesBuilder.cpp | 25 +++++++ GrowthRatesBuilder.hpp | 33 ++++++++++ 13 files changed, 698 insertions(+) create mode 100644 BuildItems.cpp create mode 100644 BuildItems.hpp create mode 100644 BuildLibrary.hpp create mode 100644 BuildMoves.cpp create mode 100644 BuildMoves.hpp create mode 100644 BuildNatures.cpp create mode 100644 BuildNatures.hpp create mode 100644 BuildSpecies.cpp create mode 100644 BuildSpecies.hpp create mode 100644 BuildTypes.cpp create mode 100644 BuildTypes.hpp create mode 100644 GrowthRatesBuilder.cpp create mode 100644 GrowthRatesBuilder.hpp diff --git a/BuildItems.cpp b/BuildItems.cpp new file mode 100644 index 0000000..a3b0c5d --- /dev/null +++ b/BuildItems.cpp @@ -0,0 +1,101 @@ +#include "BuildItems.hpp" +#include +#include +#include "../../extern/json.hpp" +using json = nlohmann::json; + +#define GET(o, objectKey, key) \ + auto _##objectKey = o[#objectKey]; \ + if (_##objectKey.is_null()) { \ + std::cout << "Failed to retrieve key '" << #objectKey << "' for object with value '" << key << "' in file '" \ + << path << "'\n"; \ + return nullptr; \ + } + +static CreatureLib::Library::ItemCategory ParseItemCategory(std::string& in) { + std::transform(in.begin(), in.end(), in.end(), tolower); + if (in == "item") + return CreatureLib::Library::ItemCategory::MiscItem; + if (in == "medicine") + return CreatureLib::Library::ItemCategory::Medicine; + if (in == "berry") + return CreatureLib::Library::ItemCategory::Berry; + if (in == "mail") + return CreatureLib::Library::ItemCategory::Mail; + if (in == "key") + return CreatureLib::Library::ItemCategory::KeyItem; + if (in == "pokeball") + return CreatureLib::Library::ItemCategory::CaptureDevice; + if (in == "tm") + return CreatureLib::Library::ItemCategory::MoveLearner; + std::cout << "Unknown Item Type: '" << in << "'\n"; + return static_cast(255); +} + +PkmnLib::Library::ItemLibrary* BuildItems::Build(const std::string& path) { + std::ifstream fileStream(path.c_str()); + if (fileStream.fail()) { + std::cout << "Failed to load Items data file at '" << path << "'\n"; + return nullptr; + } + auto lib = new PkmnLib::Library::ItemLibrary(); + json j; + fileStream >> j; + for (const auto& i : j.items()) { + if (i.key().starts_with("$")) { + continue; + } + auto val = i.value(); + GET(val, name, i); + GET(val, itemType, i); + GET(val, flags, i); + GET(val, price, i); + GET(val, flingPower, i); + auto itemTypeStr = _itemType.get(); + CreatureLib::Library::ItemCategory itemType = ParseItemCategory(itemTypeStr); + if (static_cast(itemType) == 255) + return nullptr; + + auto flags = std::unordered_set(); + for (auto flagIndex : _flags.items()) { + flags.insert(ArbUt::StringView(flagIndex.value().get().c_str())); + } + + CreatureLib::Library::SecondaryEffect* effect = nullptr; + auto effectJson = val["effect"]; + if (effectJson != nullptr) { + auto effectName = effectJson["name"]; + auto parametersJson = effectJson["parameters"]; + ArbUt::List parameters; + if (parametersJson != nullptr) { + for (auto& kv : parametersJson.items()) { + auto& p = kv.value(); + auto t = p.type(); + switch (t) { + case json::value_t::boolean: + parameters.Append(new CreatureLib::Library::EffectParameter(p.get())); + break; + case json::value_t::number_integer: + case json::value_t::number_unsigned: + parameters.Append(new CreatureLib::Library::EffectParameter(p.get())); + break; + case json::value_t::number_float: + parameters.Append(new CreatureLib::Library::EffectParameter(p.get())); + break; + default: continue; + } + } + } + effect = new CreatureLib::Library::SecondaryEffect( + 100, ArbUt::StringView(effectName.get().c_str()), parameters); + } + + auto item = new PkmnLib::Library::Item(ArbUt::StringView(_name.get().c_str()), itemType, + CreatureLib::Library::BattleItemCategory::None, _price.get(), + effect, flags, _flingPower.get()); + lib->Insert(item->GetName(), item); + } + return lib; +} + +#undef GET \ No newline at end of file diff --git a/BuildItems.hpp b/BuildItems.hpp new file mode 100644 index 0000000..82b18e2 --- /dev/null +++ b/BuildItems.hpp @@ -0,0 +1,10 @@ +#ifndef GEN7TESTS_BUILDITEMS_HPP +#define GEN7TESTS_BUILDITEMS_HPP + +#include +class BuildItems { +public: + static PkmnLib::Library::ItemLibrary* Build(const std::string& path); +}; + +#endif // GEN7TESTS_BUILDITEMS_HPP diff --git a/BuildLibrary.hpp b/BuildLibrary.hpp new file mode 100644 index 0000000..5f52e5c --- /dev/null +++ b/BuildLibrary.hpp @@ -0,0 +1,61 @@ +#ifndef PKMNLIB_AI_BUILDLIBRARY_HPP +#define PKMNLIB_AI_BUILDLIBRARY_HPP + +#include +#include +#include "BuildMoves.hpp" +#include "BuildNatures.hpp" +#include "BuildSpecies.hpp" +#include "BuildTypes.hpp" +#include "GrowthRatesBuilder.hpp" + +class BuildLibrary { + static PkmnLib::Library::TimeOfDay GetTime() { return PkmnLib::Library::TimeOfDay::Morning; } + +public: + static PkmnLib::Battling::BattleLibrary* Build(const std::string& pathString) { + auto path = std::filesystem::path(pathString); + auto* typesLibrary = BuildTypes::Build(path / "Types.csv"); + auto* natureLibrary = BuildNatures::Build(path / "Natures.csv"); + auto* movesLibrary = BuildMoves::Build(path / "Moves.json", typesLibrary); + auto* speciesLibrary = BuildSpecies::BuildLibrary(path / "Pokemon.json", typesLibrary, movesLibrary); + auto* itemsLibrary = BuildItems::Build(path / "Items.json"); + auto* growthRates = GrowthRatesBuilder::Build(path / "GrowthRates.json"); + auto scriptsPath = path / "Scripts"; + + if (typesLibrary == nullptr || speciesLibrary == nullptr || natureLibrary == nullptr || + movesLibrary == nullptr || itemsLibrary == nullptr || growthRates == nullptr) { + return nullptr; + } + + auto settings = new PkmnLib::Library::LibrarySettings(100, 4, 4096); + auto staticLibrary = new PkmnLib::Library::PokemonLibrary(settings, speciesLibrary, movesLibrary, itemsLibrary, + growthRates, typesLibrary, natureLibrary); + + auto scriptResolver = PkmnLib::Battling::BattleLibrary::CreateScriptResolver(); + + auto battleLib = new PkmnLib::Battling::BattleLibrary( + staticLibrary, new PkmnLib::Battling::StatCalculator(), new PkmnLib::Battling::DamageLibrary(), + new PkmnLib::Battling::ExperienceLibrary(), scriptResolver, new PkmnLib::Battling::MiscLibrary(GetTime)); + + scriptResolver->Initialize(battleLib); + + auto asScriptResolver = dynamic_cast(scriptResolver); + + for (const auto& dirEntry : std::filesystem::recursive_directory_iterator(scriptsPath)) { + if (dirEntry.is_directory()) + continue; + if (dirEntry.path().parent_path().stem() == "Interfaces") + continue; + if (dirEntry.path().extension() != ".as") + continue; + std::ifstream in(dirEntry.path()); + std::string contents((std::istreambuf_iterator(in)), std::istreambuf_iterator()); + asScriptResolver->CreateScript(dirEntry.path().c_str(), contents.c_str()); + } + asScriptResolver->FinalizeModule(); + return battleLib; + } +}; + +#endif // PKMNLIB_AI_BUILDLIBRARY_HPP diff --git a/BuildMoves.cpp b/BuildMoves.cpp new file mode 100644 index 0000000..08dd5b4 --- /dev/null +++ b/BuildMoves.cpp @@ -0,0 +1,113 @@ +#include "BuildMoves.hpp" +#include +#include +#include "../../extern/json.hpp" +using json = nlohmann::json; + +#define GET(o, objectKey, key) \ + auto _##objectKey = o[#objectKey]; \ + if (_##objectKey.is_null()) { \ + std::cout << "Failed to retrieve key '" << #objectKey << "' for object with value '" << key << "' in file '" \ + << path << "'\n"; \ + return nullptr; \ + } + +static PkmnLib::Library::MoveCategory ParseCategory(const std::string& input) { + if (input == "physical") + return PkmnLib::Library::MoveCategory::Physical; + else if (input == "special") + return PkmnLib::Library::MoveCategory::Special; + else if (input == "status") + return PkmnLib::Library::MoveCategory::Status; + std::cout << "Invalid move category '" << input << ".\n"; + return static_cast(255); +} + +PkmnLib::Library::MoveLibrary* BuildMoves::Build(const std::string& path, + const CreatureLib::Library::TypeLibrary* types) { + std::ifstream fileStream(path.c_str()); + if (fileStream.fail()) { + std::cout << "Failed to load Move data file at '" << path << "'\n"; + return nullptr; + } + auto lib = new PkmnLib::Library::MoveLibrary(); + json j; + fileStream >> j; + for (const auto& i : j["data"].items()) { + auto val = i.value(); + GET(val, name, i); + GET(val, type, i); + GET(val, power, i); + GET(val, pp, i); + GET(val, accuracy, i); + GET(val, priority, i); + GET(val, target, i); + GET(val, category, i); + GET(val, flags, i); + if (_pp.get() == 0) + continue; + auto type = types->GetTypeId(ArbUt::StringView(_type.get().c_str())); + auto category = ParseCategory(_category.get()); + if (static_cast(category) == 255) + return nullptr; + CreatureLib::Library::AttackTarget target; + if (!CreatureLib::Library::AttackTargetHelper::TryParse(_target.get().c_str(), target)) { + std::cout << "Invalid target: '" << _target.get() << "' for move with name '" + << _name.get() << "'\n"; + return nullptr; + } + auto flags = std::unordered_set(); + for (auto flagIndex : _flags.items()) { + flags.insert(ArbUt::StringView(flagIndex.value().get().c_str())); + } + CreatureLib::Library::SecondaryEffect* effect = nullptr; + auto jsonEffect = val["effect"]; + if (jsonEffect != nullptr) { + auto name = jsonEffect["name"]; + auto chanceJson = jsonEffect["chance"]; + auto parametersJson = jsonEffect["parameters"]; + if (name != nullptr) { + ArbUt::List parameters; + auto chance = -1.0f; + if (chanceJson != nullptr) { + chance = chanceJson.get(); + } + + if (parametersJson != nullptr) { + for (auto& kv : parametersJson.items()) { + auto& p = kv.value(); + auto t = p.type(); + switch (t) { + case json::value_t::boolean: + parameters.Append(new CreatureLib::Library::EffectParameter(p.get())); + break; + case json::value_t::number_integer: + case json::value_t::number_unsigned: + parameters.Append(new CreatureLib::Library::EffectParameter(p.get())); + break; + case json::value_t::number_float: + parameters.Append(new CreatureLib::Library::EffectParameter(p.get())); + break; + default: continue; + } + } + } + effect = new CreatureLib::Library::SecondaryEffect( + chance, ArbUt::StringView(name.get().c_str()), parameters); + } + } + if (effect == nullptr) { + effect = new CreatureLib::Library::SecondaryEffect(); + } + + auto move = new PkmnLib::Library::MoveData(ArbUt::StringView(_name.get().c_str()), type, category, + _power.get(), _accuracy.get(), _pp.get(), + target, _priority.get(), effect, flags); + + lib->Insert(ArbUt::StringView(move->GetName().c_str()), move); + } + + return lib; +} + +#undef GET \ No newline at end of file diff --git a/BuildMoves.hpp b/BuildMoves.hpp new file mode 100644 index 0000000..5501498 --- /dev/null +++ b/BuildMoves.hpp @@ -0,0 +1,11 @@ +#ifndef GEN7TESTS_BUILDMOVES_HPP +#define GEN7TESTS_BUILDMOVES_HPP + +#include +#include +class BuildMoves { +public: + static PkmnLib::Library::MoveLibrary* Build(const std::string& path, const CreatureLib::Library::TypeLibrary* types); +}; + +#endif // GEN7TESTS_BUILDMOVES_HPP diff --git a/BuildNatures.cpp b/BuildNatures.cpp new file mode 100644 index 0000000..95677a7 --- /dev/null +++ b/BuildNatures.cpp @@ -0,0 +1,86 @@ +#include "BuildNatures.hpp" +#include +#include +#include + +static CreatureLib::Library::Statistic ParseStatistic(const std::string& stat) { + if (stat.empty()) + return static_cast(255); + if (stat == "Attack") + return CreatureLib::Library::Statistic::PhysicalAttack; + if (stat == "Defense") + return CreatureLib::Library::Statistic::PhysicalDefense; + if (stat == "SpecialAttack") + return CreatureLib::Library::Statistic::MagicalAttack; + if (stat == "SpecialDefense") + return CreatureLib::Library::Statistic::MagicalDefense; + if (stat == "Speed") + return CreatureLib::Library::Statistic::Speed; + std::cout << "Invalid stat was given: '" << stat << "'.\n"; + return static_cast(254); +} + +PkmnLib::Library::NatureLibrary* BuildNatures::Build(const std::string& path) { + std::ifstream file(path); + if (file.fail()) { + std::cout << "Failed to load Natures data file at '" << path << "'\n"; + return nullptr; + } + + std::string line; + if (!std::getline(file, line)) { + std::cout << "Failed to read Natures data file at '" << path << "'\n"; + return nullptr; + } + auto divider = ','; + if (strncmp(line.c_str(), "sep=", 4) == 0) { + divider = line[4]; + std::getline(file, line); + } + auto library = new PkmnLib::Library::NatureLibrary(); + std::string substr; + while (std::getline(file, line)) { + size_t lastStart = 0; + uint8_t current = 0; + std::string natureName; + std::string increasedStat; + std::string decreasedStat; + + for (size_t i = 0; i < line.length(); i++) { + if (line[i] == divider) { + switch (current) { + case 0: natureName = line.substr(lastStart, i - lastStart); break; + case 1: increasedStat = line.substr(lastStart, i - lastStart); break; + case 2: decreasedStat = line.substr(lastStart, i - lastStart); break; + default: + std::cout << "Unknown field in nature data: '" << line.substr(lastStart, i - lastStart) + << "'.\n"; + return nullptr; + } + lastStart = i + 1; + current++; + } + } + if (current == 2) + decreasedStat = line.substr(lastStart, line.length() - lastStart); + + auto parsedIncreased = ParseStatistic(increasedStat); + float increasedModifier = 1.1; + if (static_cast(parsedIncreased) == 254) + return nullptr; + if (static_cast(parsedIncreased) == 255) + increasedModifier = 1.0; + + auto parsedDecreased = ParseStatistic(decreasedStat); + float decreasedModifier = 0.9; + if (static_cast(parsedDecreased) == 254) + return nullptr; + if (static_cast(parsedDecreased) == 255) + decreasedModifier = 1.0; + + library->LoadNature( + ArbUt::StringView(natureName.c_str()), + new PkmnLib::Library::Nature(parsedIncreased, parsedDecreased, increasedModifier, decreasedModifier)); + } + return library; +} diff --git a/BuildNatures.hpp b/BuildNatures.hpp new file mode 100644 index 0000000..8e84876 --- /dev/null +++ b/BuildNatures.hpp @@ -0,0 +1,10 @@ +#ifndef GEN7TESTS_BUILDNATURES_HPP +#define GEN7TESTS_BUILDNATURES_HPP + +#include +class BuildNatures { +public: + static PkmnLib::Library::NatureLibrary* Build(const std::string& path); +}; + +#endif // GEN7TESTS_BUILDNATURES_HPP diff --git a/BuildSpecies.cpp b/BuildSpecies.cpp new file mode 100644 index 0000000..48da639 --- /dev/null +++ b/BuildSpecies.cpp @@ -0,0 +1,145 @@ +#include "BuildSpecies.hpp" +#include +#include + +#define GET(o, objectKey, key) \ + auto _##objectKey = o[#objectKey]; \ + if (_##objectKey.is_null()) { \ + std::cout << "Failed to retrieve key '" << #objectKey << "' for object with key '" << key << "' in file '" \ + << path << "'\n"; \ + return nullptr; \ + } + +PkmnLib::Library::SpeciesLibrary* BuildSpecies::BuildLibrary(const std::string& path, + const CreatureLib::Library::TypeLibrary* types, + const PkmnLib::Library::MoveLibrary* moveLibrary) { + std::ifstream fileStream(path.c_str()); + if (fileStream.fail()) { + std::cout << "Failed to load Pokemon data file at '" << path << "'\n"; + return nullptr; + } + auto lib = new PkmnLib::Library::SpeciesLibrary(); + json j; + fileStream >> j; + + for (json::iterator it = j.begin(); it != j.end(); ++it) { + if (it.key().starts_with("$")) { + continue; + } + auto val = it.value(); + GET(val, id, it.key()); + GET(val, species, it.key()); + GET(val, genderRatio, it.key()); + GET(val, growthRate, it.key()); + GET(val, baseHappiness, it.key()); + GET(val, catchRate, it.key()); + GET(val, color, it.key()); + GET(val, genderDifference, it.key()); + GET(val, eggGroups, it.key()); + GET(val, eggCycles, it.key()); + GET(val, tags, it.key()); + GET(val, formes, it.key()); + + PkmnLib::Library::PokemonSpecies* species = nullptr; + + ArbUt::List eggGroups; + for (const auto& eg : _eggGroups) { + eggGroups.Append(eg.get().c_str()); + } + + auto defaultForme = _formes["default"]; + if (!defaultForme.is_null()) { + auto forme = BuildForme("default", defaultForme, it.key(), path, types, moveLibrary); + species = new PkmnLib::Library::PokemonSpecies( + _id.get(), ArbUt::StringView(_species.get().c_str()), forme, + _genderRatio.get() / static_cast(100), + ArbUt::StringView(_growthRate.get().c_str()), _catchRate.get(), + _baseHappiness.get(), eggGroups); + } + + for (json::iterator formeIt = _formes.begin(); formeIt != _formes.end(); ++formeIt) { + if (formeIt.key() == "default") { + continue; + } + auto forme = BuildForme(formeIt.key(), formeIt.value(), it.key(), path, types, moveLibrary); + if (forme == nullptr) + return nullptr; + if (species == nullptr) { + species = new PkmnLib::Library::PokemonSpecies( + _id.get(), ArbUt::StringView(_species.get().c_str()), forme, + static_cast(_genderRatio.get()) / static_cast(100), + ArbUt::StringView(_growthRate.get().c_str()), _catchRate.get(), + _baseHappiness.get(), eggGroups); + } else { + if (species->HasForme(ArbUt::StringView(formeIt.key().c_str()))) { + std::cout << "Species '" << it.key() << "' has duplicate forme '" << formeIt.key() + << "'. Skipping.\n"; + delete forme; + continue; + } + species->SetVariant(ArbUt::StringView(formeIt.key().c_str()), forme); + } + } + if (species == nullptr) { + std::cout << "Pokemon with key '" << it.key() << "' does not have any formes.\n"; + return nullptr; + } + lib->Insert(ArbUt::StringView(it.key().c_str()), species); + } + return lib; +} + +static CreatureLib::Library::StatisticSet ParseStatistics(json& json) { + return CreatureLib::Library::StatisticSet( + json["hp"].get(), json["attack"].get(), json["defense"].get(), + json["specialAttack"].get(), json["specialDefense"].get(), json["speed"].get()); +} + +const PkmnLib::Library::PokemonForme* BuildSpecies::BuildForme(const std::string& name, json& forme, + const std::string& baseKeyName, const std::string& path, + const CreatureLib::Library::TypeLibrary* typeLibrary, + const PkmnLib::Library::MoveLibrary* moveLibrary) { + GET(forme, abilities, baseKeyName << " -> " << name); + GET(forme, hiddenAbilities, baseKeyName << " -> " << name); + GET(forme, baseStats, baseKeyName << " -> " << name); + GET(forme, evReward, baseKeyName << " -> " << name); + GET(forme, types, baseKeyName << " -> " << name); + GET(forme, height, baseKeyName << " -> " << name); + GET(forme, weight, baseKeyName << " -> " << name); + GET(forme, baseExp, baseKeyName << " -> " << name); + GET(forme, moves, baseKeyName << " -> " << name); + + auto typeStrings = _types.get>(); + auto types = ArbUt::List(typeStrings.size()); + for (size_t i = 0; i < typeStrings.size(); i++) { + types.Append(typeLibrary->GetTypeId(ArbUt::StringView(typeStrings[i].c_str()))); + } + auto stats = ParseStatistics(_baseStats); + + auto abilityStrings = _abilities.get>(); + auto abilities = ArbUt::List(abilityStrings.size()); + for (size_t i = 0; i < abilityStrings.size(); i++) { + abilities.Append(ArbUt::StringView(abilityStrings[i].c_str())); + } + auto hiddenAbilityStrings = _abilities.get>(); + auto hiddenAbilities = ArbUt::List(hiddenAbilityStrings.size()); + for (size_t i = 0; i < hiddenAbilityStrings.size(); i++) { + hiddenAbilities.Append(ArbUt::StringView(abilityStrings[i].c_str())); + } + + auto moves = new PkmnLib::Library::LearnableMoves(100); + auto movesJson = forme["moves"]; + auto levelMovesJson = movesJson["levelMoves"]; + for (auto& levelMoveObj : levelMovesJson) { + auto levelMoveName = levelMoveObj["name"].get(); + auto level = levelMoveObj["level"].get(); + auto move = moveLibrary->Get(ArbUt::StringView(levelMoveName.c_str(), levelMoveName.size())); + moves->AddLevelAttack(level, move.ForceAs()); + } + + return new PkmnLib::Library::PokemonForme(ArbUt::StringView(name.c_str()), _height.get(), + _weight.get(), _baseExp.get(), types, stats, abilities, + hiddenAbilities, moves); +} + +#undef GET \ No newline at end of file diff --git a/BuildSpecies.hpp b/BuildSpecies.hpp new file mode 100644 index 0000000..d49afa2 --- /dev/null +++ b/BuildSpecies.hpp @@ -0,0 +1,22 @@ +#ifndef GEN7TESTS_BUILDSPECIES_HPP +#define GEN7TESTS_BUILDSPECIES_HPP +#define LEVEL_U8 1 +#include +#include +#include +#include "../../extern/json.hpp" +using json = nlohmann::json; + +class BuildSpecies { + static const PkmnLib::Library::PokemonForme* BuildForme(const std::string& name, json& forme, + const std::string& baseKeyName, const std::string& path, + const CreatureLib::Library::TypeLibrary* typeLibrary, + const PkmnLib::Library::MoveLibrary* moveLibrary); + +public: + static PkmnLib::Library::SpeciesLibrary* BuildLibrary(const std::string& path, + const CreatureLib::Library::TypeLibrary* types, + const PkmnLib::Library::MoveLibrary* moveLibrary); +}; + +#endif // GEN7TESTS_BUILDSPECIES_HPP diff --git a/BuildTypes.cpp b/BuildTypes.cpp new file mode 100644 index 0000000..01266e8 --- /dev/null +++ b/BuildTypes.cpp @@ -0,0 +1,68 @@ +#include "BuildTypes.hpp" + +CreatureLib::Library::TypeLibrary* BuildTypes::Build(const std::string& path) { + std::ifstream file(path); + if (file.fail()) { + std::cout << "Failed to load Types data file at '" << path << "'\n"; + return nullptr; + } + + std::string line; + if (!std::getline(file, line)) { + std::cout << "Failed to read Types data file at '" << path << "'\n"; + return nullptr; + } + auto divider = ','; + if (strncmp(line.c_str(), "sep=", 4) == 0) { + divider = line[4]; + std::getline(file, line); + } + auto* library = new CreatureLib::Library::TypeLibrary(); + + bool hasSkippedFirst = false; + size_t lastStart = 0; + std::vector types; + for (size_t i = 0; i < line.length(); i++) { + if (line[i] == divider) { + auto substr = line.substr(lastStart, i - lastStart); + lastStart = i + 1; + if (hasSkippedFirst) { + auto val = library->RegisterType(ArbUt::StringView(substr.c_str())); + types.push_back(val); + } else { + hasSkippedFirst = true; + } + i++; + } + } + auto substr = line.substr(lastStart, line.length() - lastStart); + auto val = library->RegisterType(ArbUt::StringView(substr.c_str())); + types.push_back(val); + + while (std::getline(file, line)) { + uint8_t attackingType = 0; + bool gotType = false; + lastStart = 0; + int current = 0; + for (size_t i = 0; i < line.length(); i++) { + if (line[i] == divider) { + substr = line.substr(lastStart, i - lastStart); + lastStart = i + 1; + if (gotType) { + auto eff = std::atof(substr.c_str()); + library->SetEffectiveness(attackingType, types[current], eff); + current++; + } else { + gotType = true; + attackingType = library->GetTypeId(ArbUt::StringView(substr.c_str())); + } + i++; + } + } + substr = line.substr(lastStart, line.length() - lastStart); + auto eff = std::atof(substr.c_str()); + library->SetEffectiveness(attackingType, types[current], eff); + } + + return library; +} diff --git a/BuildTypes.hpp b/BuildTypes.hpp new file mode 100644 index 0000000..f75a6ba --- /dev/null +++ b/BuildTypes.hpp @@ -0,0 +1,13 @@ +#ifndef GEN7TESTS_BUILDTYPES_HPP +#define GEN7TESTS_BUILDTYPES_HPP +#include +#include +#include +#include + +class BuildTypes { +public: + static CreatureLib::Library::TypeLibrary* Build(const std::string& path); +}; + +#endif // GEN7TESTS_BUILDTYPES_HPP diff --git a/GrowthRatesBuilder.cpp b/GrowthRatesBuilder.cpp new file mode 100644 index 0000000..368a1b2 --- /dev/null +++ b/GrowthRatesBuilder.cpp @@ -0,0 +1,25 @@ +#include "GrowthRatesBuilder.hpp" +#include +#include +#include "../../extern/json.hpp" +using json = nlohmann::json; + +CreatureLib::Library::GrowthRateLibrary* GrowthRatesBuilder::Build(const std::string& path) { + std::ifstream fileStream(path.c_str()); + if (fileStream.fail()) { + std::cout << "Failed to load Pokemon data file at '" << path << "'\n"; + return nullptr; + } + auto lib = new CreatureLib::Library::GrowthRateLibrary(); + json j; + fileStream >> j; + + for (const auto& i : j.items()) { + const auto& name = i.key(); + auto values = i.value(); + lib->AddGrowthRate(ArbUt::StringView(name.c_str()), + new LookupGrowthRate(values.get>())); + } + + return lib; +} diff --git a/GrowthRatesBuilder.hpp b/GrowthRatesBuilder.hpp new file mode 100644 index 0000000..7bf1576 --- /dev/null +++ b/GrowthRatesBuilder.hpp @@ -0,0 +1,33 @@ +#ifndef GEN7TESTS_GROWTHRATESBUILDER_HPP +#define GEN7TESTS_GROWTHRATESBUILDER_HPP + +#define LEVEL_U8 1 +#include +#include +#include +#include + +class LookupGrowthRate : public CreatureLib::Library::GrowthRate { + std::vector _experience; + +public: + LookupGrowthRate(std::vector experience) : _experience(std::move(experience)) {} + + [[nodiscard]] uint8_t CalculateLevel(uint32_t experience) const override { + for (size_t i = 0; i < _experience.size(); i++) { + if (_experience[i] > experience) { + return i; + } + } + return _experience[_experience.size() - 1]; + } + + [[nodiscard]] uint32_t CalculateExperience(uint8_t level) const override { return _experience[level - 1]; } +}; + +class GrowthRatesBuilder { +public: + static CreatureLib::Library::GrowthRateLibrary* Build(const std::string& file); +}; + +#endif // GEN7TESTS_GROWTHRATESBUILDER_HPP