From cb2f902194ca882fcc65622bebc7a0623fc37d49 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 13 Mar 2022 14:16:28 +0100 Subject: [PATCH] Initial work on capturing of Pokemon --- src/Battling/Library/CaptureLibrary.cpp | 41 +++++++++++++++++++ src/Battling/Library/CaptureLibrary.hpp | 20 +++++++++ src/Battling/PkmnItemUseScript.hpp | 16 ++++++++ src/Battling/PkmnScript.hpp | 2 + .../AngelScript/AngelScriptItemUseScript.cpp | 17 ++++++-- .../AngelScript/AngelScriptItemUseScript.hpp | 9 +++- .../AngelScript/AngelScriptResolver.cpp | 2 +- .../AngelScript/AngelScriptResolver.hpp | 2 +- .../AngelScript/AngelScriptScript.cpp | 8 ++++ .../AngelScript/AngelScriptScript.hpp | 2 + .../AngelScript/AngelScriptTypeInfo.hpp | 2 + .../TypeRegistry/BasicScriptClass.cpp | 1 + 12 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 src/Battling/Library/CaptureLibrary.cpp create mode 100644 src/Battling/Library/CaptureLibrary.hpp create mode 100644 src/Battling/PkmnItemUseScript.hpp diff --git a/src/Battling/Library/CaptureLibrary.cpp b/src/Battling/Library/CaptureLibrary.cpp new file mode 100644 index 0000000..27cb04b --- /dev/null +++ b/src/Battling/Library/CaptureLibrary.cpp @@ -0,0 +1,41 @@ +#include "CaptureLibrary.hpp" +#include "../PkmnItemUseScript.hpp" +#include "../PkmnScriptHook.hpp" + +namespace PkmnLib::Battling { + CaptureLibrary::CaptureResult CaptureLibrary::TryCatch(Pokemon* pokemon, Library::Item* catchItem, + ArbUt::Random* random) const { + auto hpMax = pokemon->GetMaxHealth(); + auto hpCurrent = pokemon->GetCurrentHealth(); + auto rate = pokemon->GetSpecies()->GetCaptureRate(); + + u8 bonusBall = 1; + auto* itemScript = + dynamic_cast(pokemon->GetLibrary()->GetScriptResolver()->LoadItemScript(catchItem)); + itemScript->ModifyPokeballCatchBonus(pokemon, &bonusBall); + + u8 bonusStatus = 1; + PKMN_HOOK(ModifyCaptureRateBonus, pokemon, pokemon, catchItem, &bonusStatus); + + auto modifiedCatchRate = (((3.0 * hpMax) - (2.0 * hpCurrent)) * rate * bonusBall) / (3.0 * hpMax); + modifiedCatchRate *= bonusStatus; + + auto shakeProbability = 65536 / pow((255.0 / modifiedCatchRate), 0.1875); + + u8 shakes = 0; + if (modifiedCatchRate >= 255) { + shakes = 4; + } + + // FIXME: Implement critical capture + + for (; shakes < 4; shakes++) { + auto randomNumber = random->GetUnsigned(65536); + if (randomNumber >= shakeProbability) { + break; + } + } + auto success = shakes == 4; + return CaptureResult{.WasCaught = success, .Shakes = shakes, .WasCritical = false}; + } +} diff --git a/src/Battling/Library/CaptureLibrary.hpp b/src/Battling/Library/CaptureLibrary.hpp new file mode 100644 index 0000000..e6a6219 --- /dev/null +++ b/src/Battling/Library/CaptureLibrary.hpp @@ -0,0 +1,20 @@ +#ifndef PKMNLIB_CAPTURELIBRARY_HPP +#define PKMNLIB_CAPTURELIBRARY_HPP + +#include +#include "../Pokemon/Pokemon.hpp" +namespace PkmnLib::Battling { + class CaptureLibrary { + public: + struct CaptureResult { + bool WasCaught; + u8 Shakes; + bool WasCritical; + }; + + CaptureResult TryCatch(Pokemon* pokemon, Library::Item* catchItem, ArbUt::Random* random) const; + }; +} + + +#endif // PKMNLIB_CAPTURELIBRARY_HPP diff --git a/src/Battling/PkmnItemUseScript.hpp b/src/Battling/PkmnItemUseScript.hpp new file mode 100644 index 0000000..ead2a35 --- /dev/null +++ b/src/Battling/PkmnItemUseScript.hpp @@ -0,0 +1,16 @@ +#ifndef PKMNLIB_PKMNITEMUSESCRIPT_HPP +#define PKMNLIB_PKMNITEMUSESCRIPT_HPP + +#include +namespace PkmnLib::Battling { + class Pokemon; + + class PkmnItemUseScript : public CreatureLib::Battling::ItemUseScript { + public: + virtual void ModifyPokeballCatchBonus(Pokemon* pokemon, u8* catchBonus) const { + (void)pokemon; + (void)catchBonus; + } + }; +} +#endif // PKMNLIB_PKMNITEMUSESCRIPT_HPP diff --git a/src/Battling/PkmnScript.hpp b/src/Battling/PkmnScript.hpp index 6af72d6..8fe4c5c 100644 --- a/src/Battling/PkmnScript.hpp +++ b/src/Battling/PkmnScript.hpp @@ -36,6 +36,8 @@ namespace PkmnLib::Battling { CreatureLib::Battling::Creature* target, u8 hitIndex, float* modifier){}; virtual void ModifyDefensiveStatValue(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, u8 hitIndex, float* modifier){}; + virtual void ModifyCaptureRateBonus(CreatureLib::Battling::Creature* pokemon, + CreatureLib::Library::Item* catchItem, u8* modifier){}; }; } diff --git a/src/ScriptResolving/AngelScript/AngelScriptItemUseScript.cpp b/src/ScriptResolving/AngelScript/AngelScriptItemUseScript.cpp index 5e0c9e3..04b89b3 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptItemUseScript.cpp +++ b/src/ScriptResolving/AngelScript/AngelScriptItemUseScript.cpp @@ -71,9 +71,8 @@ void AngelScriptItemUseScript::OnUse(CreatureLib::Battling::Battle* battle) cons } AngelScriptUtils::AngelscriptFunctionCall( __OnUse.Function, _resolver->GetContextPool(), _scriptObject, _resolver, ""_cnc, - [&]([[maybe_unused]] asIScriptContext* ctx) { - ctx->SetArgObject(0, battle); - }, [&]([[maybe_unused]] asIScriptContext* ctx) {}); + [&]([[maybe_unused]] asIScriptContext* ctx) { ctx->SetArgObject(0, battle); }, + [&]([[maybe_unused]] asIScriptContext* ctx) {}); } void AngelScriptItemUseScript::OnCreatureUse(CreatureLib::Battling::Creature* creature, bool isBattle) const { if (!__OnPokemonUse.Exists) { @@ -87,3 +86,15 @@ void AngelScriptItemUseScript::OnCreatureUse(CreatureLib::Battling::Creature* cr }, [&]([[maybe_unused]] asIScriptContext* ctx) {}); } +void AngelScriptItemUseScript::ModifyPokeballCatchBonus(PkmnLib::Battling::Pokemon* pokemon, u8* catchBonus) const { + if (!__ModifyPokeballCatchBonus.Exists) { + return; + } + AngelScriptUtils::AngelscriptFunctionCall( + __ModifyPokeballCatchBonus.Function, _resolver->GetContextPool(), _scriptObject, _resolver, ""_cnc, + [&]([[maybe_unused]] asIScriptContext* ctx) { + ctx->SetArgObject(0, (void*)pokemon); + ctx->SetArgAddress(1, catchBonus); + }, + [&]([[maybe_unused]] asIScriptContext* ctx) {}); +} diff --git a/src/ScriptResolving/AngelScript/AngelScriptItemUseScript.hpp b/src/ScriptResolving/AngelScript/AngelScriptItemUseScript.hpp index 751f268..a581fe0 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptItemUseScript.hpp +++ b/src/ScriptResolving/AngelScript/AngelScriptItemUseScript.hpp @@ -3,11 +3,12 @@ #include #include +#include "../../Battling/PkmnItemUseScript.hpp" #include "TypeRegistry/NativeArray.hpp" class AngelScriptResolver; -class AngelScriptItemUseScript final : public CreatureLib::Battling::ItemUseScript { +class AngelScriptItemUseScript final : public PkmnLib::Battling::PkmnItemUseScript { public: AngelScriptItemUseScript(asIScriptObject* scriptObject, AngelScriptResolver* resolver) : _scriptObject(scriptObject), _resolver(resolver) {} @@ -27,6 +28,7 @@ public: void OnUse(CreatureLib::Battling::Battle* battle) const override; void OnCreatureUse(CreatureLib::Battling::Creature* creature, bool isBattle) const override; + void ModifyPokeballCatchBonus(PkmnLib::Battling::Pokemon* pokemon, u8* catchBonus) const override; private: asIScriptObject* _scriptObject; @@ -50,13 +52,16 @@ private: #define ITEM_USE_SCRIPT_HOOK_FUNCTION(name, decl) FunctionInfo __##name = Initialize(decl); - ITEM_USE_SCRIPT_HOOK_FUNCTION(OnInitialize, "void OnInitialize(const BattleLibrary@ library, const narray@ parameters)"); + ITEM_USE_SCRIPT_HOOK_FUNCTION( + OnInitialize, "void OnInitialize(const BattleLibrary@ library, const narray@ parameters)"); ITEM_USE_SCRIPT_HOOK_FUNCTION(IsItemUsable, "bool IsItemUsable()"); ITEM_USE_SCRIPT_HOOK_FUNCTION(IsPokemonUseItem, "bool IsPokemonUseItem()"); ITEM_USE_SCRIPT_HOOK_FUNCTION(IsUseValidForPokemon, "bool IsUseValidForPokemon(Pokemon@ target)"); ITEM_USE_SCRIPT_HOOK_FUNCTION(IsHoldable, "bool IsHoldable()"); ITEM_USE_SCRIPT_HOOK_FUNCTION(OnUse, "void OnUse()"); ITEM_USE_SCRIPT_HOOK_FUNCTION(OnPokemonUse, "void OnPokemonUse(Pokemon@ target)"); + ITEM_USE_SCRIPT_HOOK_FUNCTION(ModifyPokeballCatchBonus, + "void ModifyPokeballCatchBonus(Pokemon@ target, uint8& catchBonus)"); }; #endif // PKMNLIB_ANGELSCRIPTITEMUSESCRIPT_HPP diff --git a/src/ScriptResolving/AngelScript/AngelScriptResolver.cpp b/src/ScriptResolving/AngelScript/AngelScriptResolver.cpp index c3c1bee..41004a7 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptResolver.cpp +++ b/src/ScriptResolving/AngelScript/AngelScriptResolver.cpp @@ -193,7 +193,7 @@ CreatureLib::Battling::BattleScript* AngelScriptResolver::LoadScript(const ArbUt return new AngelScriptScript(owner, ownerType, this, t.value(), obj, _contextPool); } -CreatureLib::Battling::ItemUseScript* AngelScriptResolver::LoadItemScript(const CreatureLib::Library::Item* item) { +PkmnLib::Battling::PkmnItemUseScript* AngelScriptResolver::LoadItemScript(const CreatureLib::Library::Item* item) { auto v = this->_itemUseScripts.TryGet(item); if (v.has_value()) { return v.value(); diff --git a/src/ScriptResolving/AngelScript/AngelScriptResolver.hpp b/src/ScriptResolving/AngelScript/AngelScriptResolver.hpp index a5c4f3b..2c72872 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptResolver.hpp +++ b/src/ScriptResolving/AngelScript/AngelScriptResolver.hpp @@ -69,7 +69,7 @@ public: CreatureLib::Battling::BattleScript* LoadScript(const ArbUt::OptionalBorrowedPtr& owner, ScriptCategory category, const ArbUt::StringView& scriptName) override; - CreatureLib::Battling::ItemUseScript* LoadItemScript(const CreatureLib::Library::Item* item) override; + PkmnLib::Battling::PkmnItemUseScript* LoadItemScript(const CreatureLib::Library::Item* item) override; ArbUt::OptionalBorrowedPtr LoadEvolutionScript(const ArbUt::StringView& view) override; diff --git a/src/ScriptResolving/AngelScript/AngelScriptScript.cpp b/src/ScriptResolving/AngelScript/AngelScriptScript.cpp index 5a3143d..2faae5c 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptScript.cpp +++ b/src/ScriptResolving/AngelScript/AngelScriptScript.cpp @@ -463,3 +463,11 @@ void AngelScriptScript::ChangeSpeed(CreatureLib::Battling::BaseTurnChoice* choic ctx->SetArgAddress(1, (void*)speed); }); } +void AngelScriptScript::ModifyCaptureRateBonus(CreatureLib::Battling::Creature* pokemon, + CreatureLib::Library::Item* catchItem, u8* modifier) { + CALL_HOOK(ModifyCaptureRateBonus, { + ctx->SetArgObject(0, (void*)pokemon); + ctx->SetArgObject(1, (void*)catchItem); + ctx->SetArgAddress(2, (void*)modifier); + }); +} diff --git a/src/ScriptResolving/AngelScript/AngelScriptScript.hpp b/src/ScriptResolving/AngelScript/AngelScriptScript.hpp index 7ddfa6b..e4ee2ef 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptScript.hpp +++ b/src/ScriptResolving/AngelScript/AngelScriptScript.hpp @@ -163,6 +163,8 @@ public: CreatureLib::Battling::Creature* target, u8 hitIndex, float* modifier) override; void ModifyDefensiveStatValue(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, u8 hitIndex, float* modifier) override; + void ModifyCaptureRateBonus(CreatureLib::Battling::Creature* pokemon, CreatureLib::Library::Item* catchItem, + u8* modifier) override; }; #undef CALL_HOOK diff --git a/src/ScriptResolving/AngelScript/AngelScriptTypeInfo.hpp b/src/ScriptResolving/AngelScript/AngelScriptTypeInfo.hpp index 29805f7..ef117a2 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptTypeInfo.hpp +++ b/src/ScriptResolving/AngelScript/AngelScriptTypeInfo.hpp @@ -206,6 +206,8 @@ public: ModifyDefensiveStatValue, "void ModifyDefensiveStatValue(ExecutingMove@ attack, Pokemon@ target, uint8 hit, float& defensiveStatValue)"); SCRIPT_HOOK_FUNCTION(OnAfterHeldItemConsume, "void OnAfterHeldItemConsume(Pokemon@ target, const Item@ item)"); + SCRIPT_HOOK_FUNCTION(ModifyCaptureRateBonus, + "void ModifyCaptureRateBonus(Pokemon@ target, const Item@ item, uint8& bonus)"); }; #undef SCRIPT_HOOK_FUNCTION diff --git a/src/ScriptResolving/AngelScript/TypeRegistry/BasicScriptClass.cpp b/src/ScriptResolving/AngelScript/TypeRegistry/BasicScriptClass.cpp index b53612a..db3ab14 100644 --- a/src/ScriptResolving/AngelScript/TypeRegistry/BasicScriptClass.cpp +++ b/src/ScriptResolving/AngelScript/TypeRegistry/BasicScriptClass.cpp @@ -89,6 +89,7 @@ shared abstract class ItemUseScript { void OnUse(Battle@ battle) { }; void OnPokemonUse(Pokemon@ target, bool isBattle) { }; + void ModifyPokeballCatchBonus(Pokemon@ target, uint8& catchBonus){}; } )"); Ensure(r >= 0);