diff --git a/src/ScriptResolving/AngelScript/AngelScriptFunctionCall.hpp b/src/ScriptResolving/AngelScript/AngelScriptFunctionCall.hpp index 2946ca5..1eba00d 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptFunctionCall.hpp +++ b/src/ScriptResolving/AngelScript/AngelScriptFunctionCall.hpp @@ -31,6 +31,7 @@ public: } else { ctx->PopState(); } + printf("%s\n", err.str().c_str()); throw ArbUt::Exception(err.str()); } if (newContext) { diff --git a/src/ScriptResolving/AngelScript/AngelScriptResolver.cpp b/src/ScriptResolving/AngelScript/AngelScriptResolver.cpp index f155d76..7cf6ac6 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptResolver.cpp +++ b/src/ScriptResolving/AngelScript/AngelScriptResolver.cpp @@ -32,7 +32,10 @@ static void TranslateException(asIScriptContext* ctx, void* /*userParam*/) { try { // Retrow the original exception so we can catch it again throw; - } catch (std::exception& e) { + } catch (ArbUt::Exception& e) { + // Tell the VM the type of exception that occurred + ctx->SetException(e.what()); + }catch (std::exception& e) { // Tell the VM the type of exception that occurred ctx->SetException(e.what()); } catch (...) { diff --git a/src/ScriptResolving/AngelScript/AngelScriptResolver.hpp b/src/ScriptResolving/AngelScript/AngelScriptResolver.hpp index ed24b8d..6efe35f 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptResolver.hpp +++ b/src/ScriptResolving/AngelScript/AngelScriptResolver.hpp @@ -84,7 +84,10 @@ public: asITypeInfo* t; auto v = _baseTypes.TryGet(name); if (!v.has_value()) { - t = this->_engine->GetTypeInfoByDecl(name.c_str()); + t = _mainModule->GetTypeInfoByName(name.c_str()); + if (t == NULL){ + t = _engine->GetTypeInfoByDecl(name.c_str()); + } _baseTypes.Insert(name, t); } else { t = v.value(); diff --git a/src/ScriptResolving/AngelScript/AngelScriptScript.hpp b/src/ScriptResolving/AngelScript/AngelScriptScript.hpp index a56ef2a..a61e1c9 100644 --- a/src/ScriptResolving/AngelScript/AngelScriptScript.hpp +++ b/src/ScriptResolving/AngelScript/AngelScriptScript.hpp @@ -25,6 +25,8 @@ public: ~AngelScriptScript() override { _obj->Release(); } + inline asIScriptObject* GetRawAngelscriptObject() const noexcept { return _obj; } + [[nodiscard]] const ArbUt::StringView& GetName() const noexcept override { return _type->GetName(); } const AngelScriptTypeInfo* GetType() const noexcept { return _type; } diff --git a/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterBattleClass.cpp b/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterBattleClass.cpp index 2b48291..1005daf 100644 --- a/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterBattleClass.cpp +++ b/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterBattleClass.cpp @@ -2,6 +2,7 @@ #include #include #include "../../../../Battling/Battle/Battle.hpp" +#include "../../AngelScriptScript.hpp" #include "../HelperFile.hpp" void RegisterBattleClass::Register(asIScriptEngine* engine) { @@ -50,6 +51,11 @@ CreatureLib::Battling::BattleSide* GetBattleSideWrapper(PkmnLib::Battling::Battl return battle->GetSides()[index]; } +static asIScriptObject* AddVolatileWrapper(PkmnLib::Battling::Battle* obj, const ArbUt::StringView& name) { + auto* scriptObject = (AngelScriptScript*)obj->AddVolatileScript(name); + return scriptObject->GetRawAngelscriptObject(); +} + void RegisterBattleClass::RegisterBattleSide(asIScriptEngine* engine) { int r = engine->RegisterObjectMethod( "BattleSide", "bool SwapPositions(uint8 a, uint8 b)", @@ -81,9 +87,8 @@ void RegisterBattleClass::RegisterBattle(asIScriptEngine* engine) { r = engine->RegisterObjectMethod("Battle", "ChoiceQueue@ get_TurnQueue() const property", asFUNCTION(GetCurrentTurnQueueWrapper), asCALL_CDECL_OBJFIRST); Ensure(r >= 0); - r = engine->RegisterObjectMethod( - "Battle", "void AddVolatile(const constString &in name) const", - asMETHODPR(PkmnLib::Battling::Battle, AddVolatileScript, (const ArbUt::StringView&), void), asCALL_THISCALL); + r = engine->RegisterObjectMethod("Battle", "ref@ AddVolatile(const constString &in name) const", + asFUNCTION(AddVolatileWrapper), asCALL_CDECL_OBJFIRST); Ensure(r >= 0); r = engine->RegisterObjectMethod( "Battle", "void RemoveVolatile(const constString &in name) const", diff --git a/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterPokemonClass.cpp b/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterPokemonClass.cpp index bd21a3e..1f2052b 100644 --- a/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterPokemonClass.cpp +++ b/src/ScriptResolving/AngelScript/TypeRegistry/Battling/RegisterPokemonClass.cpp @@ -1,8 +1,11 @@ #include "RegisterPokemonClass.hpp" #include #include "../../../../../extern/angelscript_addons/scriptarray/scriptarray.h" +#include "../../../../../extern/angelscript_addons/scripthandle/scripthandle.h" #include "../../../../Battling/PkmnDamageSource.hpp" #include "../../../../Battling/Pokemon/Pokemon.hpp" +#include "../../AngelScriptResolver.hpp" +#include "../../AngelScriptScript.hpp" #include "../HelperFile.hpp" // Hack to handle AngelScript not recognizing different sized enums on fields, and returning invalid values due to it. @@ -87,6 +90,15 @@ OPTIONAL_BORROWED_PTR_GETTER_FUNC(PkmnLib::Battling::Pokemon, const CreatureLib: OPTIONAL_BORROWED_PTR_GETTER_FUNC(PkmnLib::Battling::Pokemon, CreatureLib::Battling::Battle, GetBattle); OPTIONAL_BORROWED_PTR_GETTER_FUNC(PkmnLib::Battling::Pokemon, CreatureLib::Battling::BattleSide, GetBattleSide); +static CScriptHandle AddVolatileWrapper(PkmnLib::Battling::Pokemon* obj, const ArbUt::StringView& name) { + auto handle = CScriptHandle(); + auto *resolver = static_cast(obj->GetLibrary()->GetScriptResolver().get()); + auto script = static_cast(obj->AddVolatileScript(name))->GetRawAngelscriptObject(); + script->AddRef(); + handle.Set(script, resolver->GetBaseType("PkmnScript")); + return handle; +} + void RegisterPokemonClass::RegisterPokemonType(asIScriptEngine* engine) { [[maybe_unused]] int r = engine->RegisterObjectType("Pokemon", 0, asOBJ_REF | asOBJ_NOCOUNT); Ensure(r >= 0); @@ -177,9 +189,8 @@ void RegisterPokemonClass::RegisterPokemonType(asIScriptEngine* engine) { r = engine->RegisterObjectMethod("Pokemon", "int8 GetStatBoost(Statistic stat) const", asMETHOD(PkmnLib::Battling::Pokemon, GetStatBoost), asCALL_THISCALL); Ensure(r >= 0); - r = engine->RegisterObjectMethod( - "Pokemon", "void AddVolatile(const constString &in name) const", - asMETHODPR(PkmnLib::Battling::Pokemon, AddVolatileScript, (const ArbUt::StringView&), void), asCALL_THISCALL); + r = engine->RegisterObjectMethod("Pokemon", "ref@ AddVolatile(const constString &in name)", + asFUNCTION(AddVolatileWrapper), asCALL_CDECL_OBJFIRST); Ensure(r >= 0); r = engine->RegisterObjectMethod( "Pokemon", "void RemoveVolatile(const constString &in name) const", diff --git a/tests/ScriptTests/BaseScriptClassTests.cpp b/tests/ScriptTests/BaseScriptClassTests.cpp index b4a6a5b..0e4bca4 100644 --- a/tests/ScriptTests/BaseScriptClassTests.cpp +++ b/tests/ScriptTests/BaseScriptClassTests.cpp @@ -5,7 +5,7 @@ #include "../TestLibrary/TestLibrary.hpp" #define AS_CLASS(name, contents) \ - { #name, "namespace Pokemon{ [Pokemon effect=" #name "] class " #name " : PkmnScript { " contents "}}" } + { #name, "namespace Pokemon{ [Pokemon effect=" #name "] shared class " #name " : PkmnScript { " contents "}}" } static std::unordered_map _scripts = std::unordered_map{ AS_CLASS(blankScript, ), @@ -53,8 +53,11 @@ void StopBeforeAttack(ExecutingMove@ attack, bool& result) override{ R"(void IsInvulnerable(ExecutingMove@ attack, Pokemon@ target, bool& result) override{ result = !result; })"), AS_CLASS(OnAttackMissScript, - "int value = 0; void OnAttackMiss(ExecutingMove@ attack, Pokemon@ target) override { value++; } " - "int GetValue() { return value; }"), + R"( +int value = 0; +void OnAttackMiss(ExecutingMove@ attack, Pokemon@ target) override { value++; } +int GetValue() { return value; } +)"), AS_CLASS( ChangeAttackTypeScript, R"(void ChangeAttackType(ExecutingMove@ attack, Pokemon@ target, uint8 hit, uint8& outType) override{outType = 1; };)"), @@ -64,15 +67,31 @@ void StopBeforeAttack(ExecutingMove@ attack, bool& result) override{ AS_CLASS( PreventSecondaryEffectsScript, R"(void PreventSecondaryEffects(ExecutingMove@ attack, Pokemon@ target, uint8 hit, bool& result) override{ result = !result; })"), - AS_CLASS(OnSecondaryEffectScript, "int value = 0; void OnSecondaryEffect(ExecutingMove@ attack, Pokemon@ target, " - "uint8 hit) override { value++; } " - "int GetValue() { return value; }"), + AS_CLASS(OnSecondaryEffectScript, R"( +int value = 0; +void OnSecondaryEffect(ExecutingMove@ attack, Pokemon@ target, uint8 hit) override { + value++; +} +int GetValue() { return value; })"), AS_CLASS(OnAfterHitsScript, "int value = 0; void OnAfterHits(ExecutingMove@ attack, Pokemon@ target) override { value++; } " "int GetValue() { return value; }"), AS_CLASS(throwScript, R"(void PreventAttack(ExecutingMove@ attack, bool& result) override{ throw("test exception"); })"), + AS_CLASS(AddVolatileModMain, + R"( +void OnSecondaryEffect(ExecutingMove@ attack, Pokemon@ target, uint8 hit) override { + auto script = cast(target.AddVolatile("AddVolatileModSecondary")); + script.value++; +}; +)"), + AS_CLASS(AddVolatileModSecondary, + R"( +int value = 0; +int GetValue() { return value; } +)"), + }; static AngelScriptResolver* _resolverCache = nullptr; @@ -354,4 +373,37 @@ TEST_CASE("Handle script exceptions.") { throw ArbUt::Exception("Didn't throw"); } +TEST_CASE("Add Volatile with return script function") { + auto statCalc = new PkmnLib::Battling::StatCalculator(); + + auto resolver = dynamic_cast(PkmnLib::Battling::BattleLibrary::CreateScriptResolver()); + auto mainLib = new PkmnLib::Battling::BattleLibrary( + TestLibrary::BuildStaticLibrary(), statCalc, new PkmnLib::Battling::DamageLibrary(), + new PkmnLib::Battling::ExperienceLibrary(), resolver, new PkmnLib::Battling::MiscLibrary()); + resolver->Initialize(mainLib); + for (auto kv : _scripts) { + resolver->CreateScript(kv.first, kv.second); + } + resolver->FinalizeModule(); + + auto script = GetScript(mainLib, "AddVolatileModMain"_cnc); + auto mon = PkmnLib::Battling::CreatePokemon(mainLib, "testSpecies"_cnc, 30).Build(); + + script->OnSecondaryEffect(nullptr, mon, 0); + + auto scriptObjOption = const_cast(mon->GetScriptIterator()).GetNextNotNull(); + REQUIRE(scriptObjOption.has_value()); + REQUIRE(scriptObjOption.value()->GetName() == "AddVolatileModSecondary"_cnc); + auto scriptObj = scriptObjOption.value(); + auto script2 = scriptObj.As(); + auto ctxPool = script2->GetContextPool(); + auto ctx = ctxPool->RequestContext(); + script2->PrepareMethod("GetValue"_cnc, ctx); + REQUIRE(ctx->Execute() == asEXECUTION_FINISHED); + REQUIRE(ctx->GetReturnDWord() == 1); + ctxPool->ReturnContextToPool(ctx); + + delete script; +} + #endif \ No newline at end of file