From b931819aeeaec54637835cf44ada6359129b80d7 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 16 Feb 2020 13:08:04 +0100 Subject: [PATCH] More tests, initial tests for Absorb --- conanfile.py | 2 +- src/BuildData/BuildItems.cpp | 2 +- src/BuildData/BuildMoves.cpp | 6 ++-- src/BuildData/BuildSpecies.cpp | 7 +++- src/LibraryTests/SpeciesTests.cpp | 43 +++++++++++++++++++++++ src/ScriptTests/Moves/Absorb.cpp | 57 +++++++++++++++++++++++++++++++ src/main.cpp | 55 ++++++++++++++++++++++++++--- 7 files changed, 161 insertions(+), 11 deletions(-) create mode 100644 src/LibraryTests/SpeciesTests.cpp create mode 100644 src/ScriptTests/Moves/Absorb.cpp diff --git a/conanfile.py b/conanfile.py index a6e08b2..da4fc70 100644 --- a/conanfile.py +++ b/conanfile.py @@ -26,4 +26,4 @@ class PkmnLibConan(ConanFile): self.copy("*.dll", "bin", "bin") def requirements(self): - self.requires("PkmnLib/eeedbdac030b9dc72b5e70b215f4fe7173a42f46@pkmnlib/master") + self.requires("PkmnLib/a31477d4cb787ae81dce63cda23e48a3635570ef@pkmnlib/master") diff --git a/src/BuildData/BuildItems.cpp b/src/BuildData/BuildItems.cpp index 74d83b5..63a3a65 100644 --- a/src/BuildData/BuildItems.cpp +++ b/src/BuildData/BuildItems.cpp @@ -48,7 +48,7 @@ PkmnLib::Library::ItemLibrary* BuildItems::Build(const std::string& path) { auto item = new PkmnLib::Library::Item( _name.get(), itemType, CreatureLib::Library::BattleItemCategory::None, _price.get(), _flags.get>(), _flingPower.get()); - lib->LoadItem(item->GetName(), item); + lib->Insert(item->GetName().c_str(), item); } return lib; } diff --git a/src/BuildData/BuildMoves.cpp b/src/BuildData/BuildMoves.cpp index b517a73..a2de94d 100644 --- a/src/BuildData/BuildMoves.cpp +++ b/src/BuildData/BuildMoves.cpp @@ -51,9 +51,7 @@ PkmnLib::Library::MoveLibrary* BuildMoves::Build(const std::string& path, if (static_cast(category) == 255) return nullptr; CreatureLib::Library::AttackTarget target; - try { - target = CreatureLib::Library::AttackTargetHelper::Parse(_target.get(), true); - } catch (const CreatureException& e) { + 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; @@ -62,7 +60,7 @@ PkmnLib::Library::MoveLibrary* BuildMoves::Build(const std::string& path, _name.get(), type, category, _power.get(), _accuracy.get(), _pp.get(), target, _priority.get(), _flags.get>()); - lib->LoadAttack(move->GetName(), move); + lib->Insert(move->GetName().c_str(), move); } return lib; diff --git a/src/BuildData/BuildSpecies.cpp b/src/BuildData/BuildSpecies.cpp index 6d37e39..710b664 100644 --- a/src/BuildData/BuildSpecies.cpp +++ b/src/BuildData/BuildSpecies.cpp @@ -60,6 +60,11 @@ PkmnLib::Library::SpeciesLibrary* BuildSpecies::BuildLibrary(const std::string& static_cast(_genderRatio.get()) / static_cast(100), _growthRate.get(), _catchRate.get(), _baseHappiness.get()); } else { + if (species->HasForme(formeIt.key())){ + std::cout << "Species '" << it.key() << "' has duplicate forme '" << formeIt.key() << "'. Skipping.\n"; + delete forme; + continue; + } species->SetVariant(formeIt.key(), forme); } } @@ -67,7 +72,7 @@ PkmnLib::Library::SpeciesLibrary* BuildSpecies::BuildLibrary(const std::string& std::cout << "Pokemon with key '" << it.key() << "' does not have any formes.\n"; return nullptr; } - lib->LoadSpecies(it.key(), species); + lib->Insert(it.key().c_str(), species); } return lib; } diff --git a/src/LibraryTests/SpeciesTests.cpp b/src/LibraryTests/SpeciesTests.cpp new file mode 100644 index 0000000..8afba2c --- /dev/null +++ b/src/LibraryTests/SpeciesTests.cpp @@ -0,0 +1,43 @@ +#include "../../extern/catch.hpp" +#include "../Library.hpp" + +#define ENSURE_SPECIES_EXISTS(species) \ + CHECK(library->GetSpeciesLibrary()->Get(#species)->GetName() == #species); + + +TEST_CASE("Species - Ensure relevant species exist", "[species]") { + auto library = Library::GetLibrary(); + ENSURE_SPECIES_EXISTS(charizard); + ENSURE_SPECIES_EXISTS(pikachu); +} + +TEST_CASE("Species - Ensure species count is valid", "[species]") { + auto library = Library::GetLibrary(); + CHECK(library->GetSpeciesLibrary()->GetCount() == 802); +} + +TEST_CASE("Species - Ensure each species has a default forme", "[species]") { + auto library = Library::GetLibrary(); + auto iterator = library->GetSpeciesLibrary()->GetIterator(); + size_t i = 0; + for (const auto& v: iterator){ + REQUIRE(v.second->HasVariant("default")); + CHECK(v.second->GetVariant("default")->GetName() == "default"); + i++; + } + REQUIRE(i == 802); +} + +TEST_CASE("Species - Ensure each forme has abilities", "[species]") { + auto library = Library::GetLibrary(); + auto iterator = library->GetSpeciesLibrary()->GetIterator(); + size_t i = 0; + for (const auto& v: iterator){ + for (const auto& forme: v.second->GetVariantsIterator()){ + auto abilities = forme.second->GetTalents(); + CHECK(!abilities.empty()); + } + i++; + } + REQUIRE(i == 802); +} \ No newline at end of file diff --git a/src/ScriptTests/Moves/Absorb.cpp b/src/ScriptTests/Moves/Absorb.cpp new file mode 100644 index 0000000..bb1c1ab --- /dev/null +++ b/src/ScriptTests/Moves/Absorb.cpp @@ -0,0 +1,57 @@ +#include +#include +#include "../../../extern/catch.hpp" +#include "../../Library.hpp" + +TEST_CASE("Absorb - Heals on use", "[moves]") { + auto library = Library::GetLibrary(); + auto userMon = PkmnLib::Battling::CreatePokemon(library, "charizard", 50) + .LearnMove("absorb", CreatureLib::Battling::AttackLearnMethod::Unknown) + ->Build(); + userMon->Damage(50, CreatureLib::Battling::DamageSource::AttackDamage); + auto targetMon = PkmnLib::Battling::CreatePokemon(library, "venusaur", 50).Build(); + auto executingMove = + new CreatureLib::Battling::ExecutingAttack({targetMon}, 1, userMon, userMon->GetMoves()[0], nullptr); + executingMove->GetAttackDataForTarget(targetMon)->GetHit(0)->SetDamage(50); + + auto script = library->LoadScript(CreatureLib::Battling::ScriptResolver::ScriptCategory::Attack, "Absorb"); + REQUIRE(script != nullptr); + try{ + script->OnSecondaryEffect(executingMove, targetMon, 0); + } + catch (const CreatureException& e){ + FAIL(e.what()); + } + CHECK(userMon->GetCurrentHealth() == userMon->GetMaxHealth() - 25); + delete script; + delete executingMove; + delete targetMon; + delete userMon; +} + +TEST_CASE("Absorb - Heals more with big root", "[moves]") { + auto library = Library::GetLibrary(); + auto userMon = PkmnLib::Battling::CreatePokemon(library, "charizard", 50) + .LearnMove("absorb", CreatureLib::Battling::AttackLearnMethod::Unknown) + ->WithHeldItem("big_root") + ->Build(); + userMon->Damage(50, CreatureLib::Battling::DamageSource::AttackDamage); + auto targetMon = PkmnLib::Battling::CreatePokemon(library, "venusaur", 50).Build(); + auto executingMove = + new CreatureLib::Battling::ExecutingAttack({targetMon}, 1, userMon, userMon->GetMoves()[0], nullptr); + executingMove->GetAttackDataForTarget(targetMon)->GetHit(0)->SetDamage(50); + + auto script = library->LoadScript(CreatureLib::Battling::ScriptResolver::ScriptCategory::Attack, "Absorb"); + REQUIRE(script != nullptr); + try{ + script->OnSecondaryEffect(executingMove, targetMon, 0); + } + catch (const CreatureException& e){ + FAIL(e.what()); + } + CHECK(userMon->GetCurrentHealth() == userMon->GetMaxHealth() - 18); + delete script; + delete executingMove; + delete targetMon; + delete userMon; +} diff --git a/src/main.cpp b/src/main.cpp index 41395cc..753afd5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,5 @@ #define CATCH_CONFIG_RUNNER +#include #include "../extern/catch.hpp" #include "BuildData/BuildItems.hpp" #include "BuildData/BuildMoves.hpp" @@ -8,6 +9,35 @@ #include "BuildData/GrowthRatesBuilder.hpp" #include "Library.hpp" +static const char* ScriptsPath = nullptr; + +static constexpr const char* GetCategoryPath(CreatureLib::Battling::ScriptResolver::ScriptCategory category){ + switch (category){ + case CreatureLib::Battling::ScriptResolver::ScriptCategory::Attack: return "Moves"; + case CreatureLib::Battling::ScriptResolver::ScriptCategory::Talent: return "Abilities"; + case CreatureLib::Battling::ScriptResolver::ScriptCategory::Status: return "Status"; + case CreatureLib::Battling::ScriptResolver::ScriptCategory::Creature: return "Pokemon"; + case CreatureLib::Battling::ScriptResolver::ScriptCategory::Battle: return "Battle"; + case CreatureLib::Battling::ScriptResolver::ScriptCategory::Side: return "Side"; + } +} + + +static const char* LoadFunc(CreatureLib::Battling::ScriptResolver::ScriptCategory category, const char* scriptName){ + auto categoryStr = GetCategoryPath(category); + char fullPath[strlen(ScriptsPath) + 1 + strlen(categoryStr) + 1 + strlen(scriptName) + 3]; + strcpy(fullPath, ScriptsPath); + strcat(fullPath, "/"); + strcat(fullPath, categoryStr); + strcat(fullPath, "/"); + strcat(fullPath, scriptName); + strcat(fullPath, ".as"); + std::ifstream in(fullPath); + std::string contents((std::istreambuf_iterator(in)), std::istreambuf_iterator()); + char res[contents.size()]; + return strcpy(res, contents.c_str()); +} + int main(int argc, char* argv[]) { Catch::Session session; @@ -17,6 +47,7 @@ int main(int argc, char* argv[]) { std::string moveFile = "Moves.json"; std::string itemsFile = "Items.json"; std::string growthRatesFile = "GrowthRates.json"; + std::string scriptsPath = "Scripts"; using namespace Catch::clara; auto cli = session.cli() | Opt(pokemonFile, "Species")["--species"]("Which species file to load.") | @@ -24,7 +55,8 @@ int main(int argc, char* argv[]) { Opt(naturesFile, "Natures")["--natures"]("Which Natures file to load.") | Opt(moveFile, "Moves")["--moves"]("Which Moves file to load.") | Opt(itemsFile, "Items")["--items"]("Which Items file to load.") | - Opt(growthRatesFile, "Growthrates")["--growthrates"]("Which Growthrates file to load."); + Opt(growthRatesFile, "Growthrates")["--growthrates"]("Which Growthrates file to load.") | + Opt(scriptsPath, "Scripts")["--scripts"]("Which Scripts path to load scripts from."); session.cli(cli); @@ -38,16 +70,31 @@ int main(int argc, char* argv[]) { auto movesLibrary = BuildMoves::Build(moveFile, typesLibrary); auto itemsLibrary = BuildItems::Build(itemsFile); auto growthRates = GrowthRatesBuilder::Build(growthRatesFile); + ScriptsPath = scriptsPath.c_str(); if (typesLibrary == nullptr || speciesLibrary == nullptr || natureLibrary == nullptr || movesLibrary == nullptr || itemsLibrary == nullptr || growthRates == nullptr) return 1; auto settings = new PkmnLib::Library::LibrarySettings(100, 4, 4096); - auto library = new PkmnLib::Library::PokemonLibrary(settings, speciesLibrary, movesLibrary, itemsLibrary, - growthRates, typesLibrary, natureLibrary); + auto staticLibrary = new PkmnLib::Library::PokemonLibrary(settings, speciesLibrary, movesLibrary, itemsLibrary, + growthRates, typesLibrary, natureLibrary); - Library::SetStaticLib(library); + auto scriptResolver = PkmnLib::Battling::BattleLibrary::CreateScriptResolver(); + + auto battleLib = new PkmnLib::Battling::BattleLibrary( + staticLibrary, new PkmnLib::Battling::StatCalculator(), new PkmnLib::Battling::DamageLibrary(), + new CreatureLib::Battling::ExperienceLibrary(), scriptResolver, new CreatureLib::Battling::MiscLibrary()); + + scriptResolver->Initialize(battleLib); + + auto asScriptResolver = dynamic_cast(scriptResolver); + asScriptResolver->SetCreateFunction(LoadFunc); + asScriptResolver->CreateScript(CreatureLib::Battling::ScriptResolver::ScriptCategory::Attack, "absorb"); + asScriptResolver->FinalizeModule(); + + Library::SetStaticLib(staticLibrary); + Library::SetLibrary(battleLib); return session.run(); } \ No newline at end of file