#ifndef PKMNLIB_ANGELSCRIPTSCRIPT_HPP #define PKMNLIB_ANGELSCRIPTSCRIPT_HPP #include #define ANGELSCRIPT_DLL_LIBRARY_IMPORT #include #include #include "../../Battling/PkmnScript.hpp" #include "AngelScriptTypeInfo.hpp" #include "ContextPool.hpp" class AngelScriptScript : public PkmnLib::Battling::PkmnScript { private: AngelScriptTypeInfo* _type = nullptr; ContextPool* _ctxPool = nullptr; asIScriptObject* _obj = nullptr; public: AngelScriptScript(const std::string& name, AngelScriptTypeInfo* type, asIScriptObject* obj, ContextPool* ctxPool) : PkmnLib::Battling::PkmnScript(name), _type(type), _ctxPool(ctxPool), _obj(obj) {} ~AngelScriptScript() override { _obj->Release(); } asIScriptFunction* PrepareMethod(const char* name, asIScriptContext* ctx) { auto func = _type->GetFunction(name); ctx->Prepare(func); ctx->SetObject(_obj); return func; } ContextPool* GetContextPool() { return _ctxPool; } #define CALL_HOOK(name, setup) \ auto s = _type->Get##name(); \ if (!s.Exists) \ return; \ auto ctx = asGetActiveContext(); \ bool newContext = false; \ if (ctx == nullptr) { \ ctx = _ctxPool->RequestContext(); \ newContext = true; \ } else { \ ctx->PushState(); \ } \ ctx->Prepare(s.Function); \ ctx->SetObject(_obj); \ setup; \ auto scriptResult = ctx->Execute(); \ if (scriptResult != asEXECUTION_FINISHED) { \ if (scriptResult == asEXECUTION_EXCEPTION) { \ std::stringstream err; \ err << "Script exception in script '" << GetName() << "', line " << ctx->GetExceptionLineNumber() \ << ". Message: '" << ctx->GetExceptionString() << "'."; \ throw CreatureException(err.str()); \ } \ throw CreatureException("Script didn't finish properly; message " + std::to_string(scriptResult)); \ } \ if (newContext) { \ _ctxPool->ReturnContextToPool(ctx); \ } else { \ ctx->PopState(); \ } void Stack() override { CALL_HOOK(Stack, ); } void OnRemove() override { CALL_HOOK(OnRemove, ); } void OnBeforeTurn(const CreatureLib::Battling::BaseTurnChoice* choice) override { throw NotImplementedException(); // TODO } void ChangeAttack(CreatureLib::Battling::AttackTurnChoice* choice, std::string* outAttack) override { throw NotImplementedException(); // TODO } void PreventAttack(CreatureLib::Battling::ExecutingAttack* attack, bool* outResult) override { CALL_HOOK(PreventAttack, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgAddress(1, outResult); }) } void FailAttack(CreatureLib::Battling::ExecutingAttack* attack, bool* outFailed) override { CALL_HOOK(FailAttack, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgAddress(1, outFailed); }) } void StopBeforeAttack(CreatureLib::Battling::ExecutingAttack* attack, bool* outResult) override { CALL_HOOK(StopBeforeAttack, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgAddress(1, outResult); }) } void OnBeforeAttack(CreatureLib::Battling::ExecutingAttack* attack) override { CALL_HOOK(OnBeforeAttack, { ctx->SetArgObject(0, (void*)attack); }) } void FailIncomingAttack(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, bool* outResult) override { CALL_HOOK(FailIncomingAttack, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgAddress(2, outResult); }) } void IsInvulnerable(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, bool* outResult) override { CALL_HOOK(IsInvulnerable, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgAddress(2, outResult); }) } void OnAttackMiss(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target) override { CALL_HOOK(OnAttackMiss, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); }) } void ChangeAttackType(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, uint8_t hitNumber, uint8_t* outType) override { CALL_HOOK(ChangeAttackType, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgByte(2, hitNumber); ctx->SetArgAddress(3, outType); }) } void OnStatusMove(const CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, uint8_t hitNumber) override { CALL_HOOK(OnStatusMove, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgByte(2, hitNumber); }) } void PreventSecondaryEffects(const CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, uint8_t hitNumber, bool* outResult) override { CALL_HOOK(PreventSecondaryEffects, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgByte(2, hitNumber); ctx->SetArgAddress(3, outResult); }) } void OnSecondaryEffect(const CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, uint8_t hitNumber) override { CALL_HOOK(OnSecondaryEffect, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgByte(2, hitNumber); }) } void OnAfterHits(const CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target) override { CALL_HOOK(OnAfterHits, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); }) } void PreventSelfSwitch(const CreatureLib::Battling::SwitchTurnChoice* choice, bool* outResult) override { throw NotImplementedException(); // TODO } void ModifyEffectChance(const CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, float* chance) override { CALL_HOOK(ModifyEffectChance, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgAddress(2, chance); }) } void ModifyIncomingEffectChance(const CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, float* chance) override { CALL_HOOK(ModifyIncomingEffectChance, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgAddress(2, chance); }) } void OverrideBasePower(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, uint8_t hitIndex, uint8_t* basePower) override { CALL_HOOK(OverrideBasePower, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgByte(2, hitIndex); ctx->SetArgAddress(3, basePower); }) } void ChangeDamageStatsUser(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, uint8_t hitIndex, CreatureLib::Battling::Creature** statsUser) override { CALL_HOOK(ChangeDamageStatsUser, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgByte(2, hitIndex); ctx->SetArgAddress(3, statsUser); }) } void BypassDefensiveStat(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, uint8_t hitIndex, bool* bypass) override { CALL_HOOK(BypassDefensiveStat, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgByte(2, hitIndex); ctx->SetArgAddress(3, bypass); }) } void BypassOffensiveStat(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, uint8_t hitIndex, bool* bypass) override { CALL_HOOK(BypassOffensiveStat, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgByte(2, hitIndex); ctx->SetArgAddress(3, bypass); }) } void ModifyStatModifier(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, uint8_t hitIndex, float* modifier) override { CALL_HOOK(ModifyStatModifier, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgByte(2, hitIndex); ctx->SetArgAddress(3, modifier); }) } void ModifyDamageModifier(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, uint8_t hitIndex, float* modifier) override { CALL_HOOK(ModifyDamageModifier, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgByte(2, hitIndex); ctx->SetArgAddress(3, modifier); }) } void OverrideDamage(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, uint8_t hitIndex, int32_t* damage) override { CALL_HOOK(OverrideDamage, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgByte(2, hitIndex); ctx->SetArgAddress(3, damage); }) } //////////////////// // PkmnLib methods// //////////////////// void ModifyCriticalStage(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, uint8_t hit, uint8_t* critStage) override { CALL_HOOK(ModifyCriticalStage, { ctx->SetArgObject(0, (void*)attack); ctx->SetArgObject(1, (void*)target); ctx->SetArgByte(2, hit); ctx->SetArgAddress(3, critStage); }) } }; #undef CALL_HOOK #endif // PKMNLIB_ANGELSCRIPTSCRIPT_HPP