commit e69eacaa9bd65ab2d6f1c42749f5a0734423f3c9 Author: Deukhoofd Date: Sun Aug 22 12:10:26 2021 +0200 Set up standard functions for building tools 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