273 lines
13 KiB
C++
273 lines
13 KiB
C++
#ifndef PKMNLIB_ANGELSCRIPTSCRIPT_HPP
|
|
#define PKMNLIB_ANGELSCRIPTSCRIPT_HPP
|
|
#include <CreatureLib/Battling/ScriptHandling/Script.hpp>
|
|
#define ANGELSCRIPT_DLL_LIBRARY_IMPORT
|
|
#include <CreatureLib/Core/Exceptions/NotImplementedException.hpp>
|
|
#include <angelscript.h>
|
|
#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
|