diff --git a/conanfile.py b/conanfile.py index 0a5496a..f8ab0d6 100644 --- a/conanfile.py +++ b/conanfile.py @@ -40,7 +40,7 @@ class PkmnLibConan(ConanFile): self.options["AngelScript"].link_std_statically = True def requirements(self): - self.requires("CreatureLib/15523a18a556dedf5b27212264a871260608abb6@creaturelib/master") + self.requires("CreatureLib/7e0a1ec033f476dba24a7d091df997f31e2ac076@creaturelib/master") if self.options.script_handler == "angelscript": self.requires("AngelScript/2.34@AngelScript/Deukhoofd") else: diff --git a/src/AngelScript/AngelScripResolver.cpp b/src/AngelScript/AngelScripResolver.cpp index df013c9..740298d 100644 --- a/src/AngelScript/AngelScripResolver.cpp +++ b/src/AngelScript/AngelScripResolver.cpp @@ -1,6 +1,11 @@ #include "AngelScripResolver.hpp" +#define AS_USE_ACCESSORS +#include "../../extern/angelscript_addons/scriptarray/scriptarray.h" +#undef AS_USE_ACCESSORS #include "../../extern/angelscript_addons/scripthelper/scripthelper.h" #include "../../extern/angelscript_addons/scriptstdstring/scriptstdstring.h" +#include "TypeRegistry/Battling/RegisterExecutingAttack.hpp" +#include "TypeRegistry/Battling/RegisterPokemonClass.hpp" #include "TypeRegistry/Library/RegisterGrowthRateTypes.hpp" #include "TypeRegistry/Library/RegisterItemTypes.hpp" #include "TypeRegistry/Library/RegisterMoveTypes.hpp" @@ -15,23 +20,35 @@ CreatureLib::Battling::ScriptResolver* PkmnLib::Battling::BattleLibrary::CreateS void AngelScripResolver::Initialize(CreatureLib::Battling::BattleLibrary* library) { _engine = asCreateScriptEngine(); + int32_t r = _engine->SetMessageCallback(asFUNCTION(MessageCallback), nullptr, asCALL_CDECL); + if (r < 0) + throw CreatureException("Registering message callback failed."); + _engine->SetEngineProperty(asEP_DISALLOW_EMPTY_LIST_ELEMENTS, true); _engine->SetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE, true); _engine->SetEngineProperty(asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT, true); _engine->SetEngineProperty(asEP_AUTO_GARBAGE_COLLECT, false); _engine->SetEngineProperty(asEP_REQUIRE_ENUM_SCOPE, true); - int32_t r = _engine->SetMessageCallback(asFUNCTION(MessageCallback), nullptr, asCALL_CDECL); - if (r < 0) - throw CreatureException("Registering message callback failed."); - RegisterStdString(_engine); + + // Register Script Array type + RegisterScriptArray(_engine, true); + r = _engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(Print), asCALL_CDECL); if (r < 0) throw CreatureException("Registering print function failed."); + RegisterTypes(); RegisterExceptionRoutines(_engine); + _mainModule = _engine->GetModule("pkmn", asGM_ALWAYS_CREATE); + + _contextPool = new ContextPool(_engine); +} + +void AngelScripResolver::RegisterTypes() { + // Register static library types RegisterSpeciesTypes::Register(_engine); RegisterItemTypes::Register(_engine); RegisterMoveTypes::Register(_engine); @@ -39,10 +56,11 @@ void AngelScripResolver::Initialize(CreatureLib::Battling::BattleLibrary* librar RegisterTypeLibrary::Register(_engine); RegisterStaticLibraryTypes::Register(_engine); - _mainModule = _engine->GetModule("pkmn", asGM_ALWAYS_CREATE); - - _contextPool = new ContextPool(_engine); + // Register battle types + RegisterPokemonClass::Register(_engine); + RegisterExecutingAttack::Register(_engine); } + AngelScriptTypeInfo* AngelScripResolver::GetTypeInfo(const std::string& name) { auto find = _types.find(name); if (find != _types.end()) { diff --git a/src/AngelScript/AngelScripResolver.hpp b/src/AngelScript/AngelScripResolver.hpp index 8184903..a4b7fcf 100644 --- a/src/AngelScript/AngelScripResolver.hpp +++ b/src/AngelScript/AngelScripResolver.hpp @@ -22,6 +22,8 @@ private: static void Print(const std::string& str) { std::cout << str << std::endl; } AngelScriptTypeInfo* GetTypeInfo(const std::string& name); + void RegisterTypes(); + public: ~AngelScripResolver() override { delete _contextPool; diff --git a/src/AngelScript/TypeRegistry/Battling/RegisterBattleLibrary.cpp b/src/AngelScript/TypeRegistry/Battling/RegisterBattleLibrary.cpp new file mode 100644 index 0000000..4487a37 --- /dev/null +++ b/src/AngelScript/TypeRegistry/Battling/RegisterBattleLibrary.cpp @@ -0,0 +1,14 @@ +#include "RegisterBattleLibrary.hpp" +#include +#include "../../../Battling/Library/DamageLibrary.hpp" + +void RegisterBattleLibrary::Register(asIScriptEngine* engine) { + RegisterDamageLibrary(engine); +} +void RegisterBattleLibrary::RegisterDamageLibrary(asIScriptEngine* engine) { + [[maybe_unused]] int r = engine->RegisterObjectType("DamageLibrary", 0, asOBJ_REF | asOBJ_NOCOUNT); + assert(r >= 0); + r = engine->RegisterObjectMethod("DamageLibrary", "int GetDamage() const", + asMETHOD(PkmnLib::Battling::DamageLibrary, GetDamage), asCALL_THISCALL); + assert(r >= 0); +} diff --git a/src/AngelScript/TypeRegistry/Battling/RegisterBattleLibrary.hpp b/src/AngelScript/TypeRegistry/Battling/RegisterBattleLibrary.hpp new file mode 100644 index 0000000..080fb62 --- /dev/null +++ b/src/AngelScript/TypeRegistry/Battling/RegisterBattleLibrary.hpp @@ -0,0 +1,11 @@ +#ifndef PKMNLIB_REGISTERBATTLELIBRARY_HPP +#define PKMNLIB_REGISTERBATTLELIBRARY_HPP + +#include +class RegisterBattleLibrary { + static void RegisterDamageLibrary(asIScriptEngine* engine); +public: + static void Register(asIScriptEngine* engine); +}; + +#endif // PKMNLIB_REGISTERBATTLELIBRARY_HPP diff --git a/src/AngelScript/TypeRegistry/Battling/RegisterExecutingAttack.cpp b/src/AngelScript/TypeRegistry/Battling/RegisterExecutingAttack.cpp new file mode 100644 index 0000000..007d9a2 --- /dev/null +++ b/src/AngelScript/TypeRegistry/Battling/RegisterExecutingAttack.cpp @@ -0,0 +1,71 @@ +#include "RegisterExecutingAttack.hpp" +#include +#include + +void RegisterExecutingAttack::Register(asIScriptEngine* engine) { + RegisterHitData(engine); + RegisterTargetData(engine); + RegisterExecutingAttackType(engine); +} +void RegisterExecutingAttack::RegisterHitData(asIScriptEngine* engine) { + [[maybe_unused]] int r = engine->RegisterObjectType("HitData", 0, asOBJ_REF | asOBJ_NOCOUNT); + assert(r >= 0); + r = engine->RegisterObjectMethod("HitData", "bool get_IsCritical() const property", + asMETHOD(CreatureLib::Battling::ExecutingAttack::HitData, IsCritical), + asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("HitData", "uint8 get_BasePower() const property", + asMETHOD(CreatureLib::Battling::ExecutingAttack::HitData, GetBasePower), + asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("HitData", "float get_Effectiveness() const property", + asMETHOD(CreatureLib::Battling::ExecutingAttack::HitData, GetEffectiveness), + asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("HitData", "float get_Damage() const property", + asMETHOD(CreatureLib::Battling::ExecutingAttack::HitData, GetDamage), + asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("HitData", "uint8 get_Type() const property", + asMETHOD(CreatureLib::Battling::ExecutingAttack::HitData, GetType), + asCALL_THISCALL); + assert(r >= 0); +} +void RegisterExecutingAttack::RegisterTargetData(asIScriptEngine* engine) { + [[maybe_unused]] int r = engine->RegisterObjectType("TargetData", 0, asOBJ_REF | asOBJ_NOCOUNT); + assert(r >= 0); + r = engine->RegisterObjectMethod("TargetData", "uint8 get_NumberOfHits() const property", + asMETHOD(CreatureLib::Battling::ExecutingAttack::TargetData, GetNumberOfHits), + asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("TargetData", "bool get_IsHit() const property", + asMETHOD(CreatureLib::Battling::ExecutingAttack::TargetData, IsHit), + asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("TargetData", "HitData@ GetHit(uint8 index) const", + asMETHOD(CreatureLib::Battling::ExecutingAttack::TargetData, GetHit), + asCALL_THISCALL); + assert(r >= 0); + +} +void RegisterExecutingAttack::RegisterExecutingAttackType(asIScriptEngine* engine) { + [[maybe_unused]] int r = engine->RegisterObjectType("ExecutingMove", 0, asOBJ_REF | asOBJ_NOCOUNT); + assert(r >= 0); + r = engine->RegisterObjectMethod("ExecutingMove", "TargetData& GetAttackDataForTarget(Pokemon@ pkmn) const", + asMETHOD(CreatureLib::Battling::ExecutingAttack, GetAttackDataForTarget), + asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("ExecutingMove", "bool IsPokemonTarget(Pokemon@ pkmn) const", + asMETHOD(CreatureLib::Battling::ExecutingAttack, IsCreatureTarget), + asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("ExecutingMove", "Pokemon@ get_User() const property", + asMETHOD(CreatureLib::Battling::ExecutingAttack, GetUser), + asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("ExecutingMove", "LearnedMove@ get_Move() const property", + asMETHOD(CreatureLib::Battling::ExecutingAttack, GetAttack), + asCALL_THISCALL); + assert(r >= 0); + +} diff --git a/src/AngelScript/TypeRegistry/Battling/RegisterExecutingAttack.hpp b/src/AngelScript/TypeRegistry/Battling/RegisterExecutingAttack.hpp new file mode 100644 index 0000000..f4b2383 --- /dev/null +++ b/src/AngelScript/TypeRegistry/Battling/RegisterExecutingAttack.hpp @@ -0,0 +1,14 @@ +#ifndef PKMNLIB_REGISTEREXECUTINGATTACK_HPP +#define PKMNLIB_REGISTEREXECUTINGATTACK_HPP + +#include + +class RegisterExecutingAttack { + static void RegisterHitData(asIScriptEngine* engine); + static void RegisterTargetData(asIScriptEngine* engine); + static void RegisterExecutingAttackType(asIScriptEngine* engine); +public: + static void Register(asIScriptEngine* engine); +}; + +#endif // PKMNLIB_REGISTEREXECUTINGATTACK_HPP diff --git a/src/AngelScript/TypeRegistry/Battling/RegisterPokemonClass.cpp b/src/AngelScript/TypeRegistry/Battling/RegisterPokemonClass.cpp new file mode 100644 index 0000000..4ae4b22 --- /dev/null +++ b/src/AngelScript/TypeRegistry/Battling/RegisterPokemonClass.cpp @@ -0,0 +1,124 @@ +#include "RegisterPokemonClass.hpp" +#include +#include +#include "../../../Battling/Pokemon/Pokemon.hpp" + +// Hack to handle AngelScript not recognizing different sized enums on fields, and returning invalid values due to it. +#define ENUM__SIZE_WRAPPER(name, type, func) \ + int32_t name(type* obj) { return static_cast(obj->func()); } + +void RegisterPokemonClass::Register(asIScriptEngine* engine) { + RegisterDamageSource(engine); + RegisterMoveLearnMethod(engine); + RegisterLearnedAttack(engine); + RegisterPokemonType(engine); +} + +void RegisterPokemonClass::RegisterDamageSource(asIScriptEngine* engine) { + [[maybe_unused]] int r = engine->RegisterEnum("DamageSource"); + assert(r >= 0); + r = engine->RegisterEnumValue("DamageSource", "AttackDamage", + (int)CreatureLib::Battling::DamageSource::AttackDamage); + assert(r >= 0); +} + +void RegisterPokemonClass::RegisterMoveLearnMethod(asIScriptEngine* engine) { + [[maybe_unused]] int r = engine->RegisterEnum("MoveLearnMethod"); + assert(r >= 0); + r = engine->RegisterEnumValue("MoveLearnMethod", "Unknown", (int)CreatureLib::Battling::AttackLearnMethod::Unknown); + assert(r >= 0); + r = engine->RegisterEnumValue("MoveLearnMethod", "Level", (int)CreatureLib::Battling::AttackLearnMethod::Level); + assert(r >= 0); +} + +ENUM__SIZE_WRAPPER(LearnedMove_LearnMethodWrapper, CreatureLib::Battling::LearnedAttack, GetLearnMethod) + +void RegisterPokemonClass::RegisterLearnedAttack(asIScriptEngine* engine) { + [[maybe_unused]] int r = engine->RegisterObjectType("LearnedMove", 0, asOBJ_REF | asOBJ_NOCOUNT); + assert(r >= 0); + r = engine->RegisterObjectMethod("LearnedMove", "const MoveData@ get_MoveData() const property", + asMETHOD(CreatureLib::Battling::LearnedAttack, GetAttack), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("LearnedMove", "uint8 get_MaxUses() const property", + asMETHOD(CreatureLib::Battling::LearnedAttack, GetMaxUses), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("LearnedMove", "uint8 get_RemainingUses() const property", + asMETHOD(CreatureLib::Battling::LearnedAttack, GetRemainingUses), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("LearnedMove", "Gender get_LearnMethod() const property", + asFUNCTION(LearnedMove_LearnMethodWrapper), asCALL_CDECL_OBJLAST); + assert(r >= 0); +} + +ENUM__SIZE_WRAPPER(Pkmn_GenderWrapper, PkmnLib::Battling::Pokemon, GetGender) + +void RegisterPokemonClass::RegisterPokemonType(asIScriptEngine* engine) { + [[maybe_unused]]int r = engine->RegisterObjectType("Pokemon", 0, asOBJ_REF | asOBJ_NOCOUNT); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "const Species@ get_Species() const property", + asMETHOD(PkmnLib::Battling::Pokemon, GetSpecies), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "const Forme@ get_Forme() const property", + asMETHOD(PkmnLib::Battling::Pokemon, GetForme), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "uint8 get_Level() const property", + asMETHOD(PkmnLib::Battling::Pokemon, GetLevel), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "uint32 get_Experience() const property", + asMETHOD(PkmnLib::Battling::Pokemon, GetExperience), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "Gender get_Gender() const property", asFUNCTION(Pkmn_GenderWrapper), + asCALL_CDECL_OBJLAST); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "uint8 get_Coloring() const property", + asMETHOD(PkmnLib::Battling::Pokemon, GetColoring), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "const Item@ get_HeldItem() const property", + asMETHOD(PkmnLib::Battling::Pokemon, GetHeldItem), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "uint32 get_CurrentHealth() const property", + asMETHOD(PkmnLib::Battling::Pokemon, GetCurrentHealth), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "const string& get_Nickname() const property", + asMETHOD(PkmnLib::Battling::Pokemon, GetNickname), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "const string& get_ActiveAbility() const property", + asMETHOD(PkmnLib::Battling::Pokemon, GetActiveTalent), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "bool get_IsFainted() const property", + asMETHOD(PkmnLib::Battling::Pokemon, IsFainted), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "uint8[]@ GetTypes() const", + asMETHOD(PkmnLib::Battling::Pokemon, GetTypes), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "bool HasType(uint8 type) const", + asMETHOD(PkmnLib::Battling::Pokemon, HasType), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "void Damage(uint32 type, DamageSource source)", + asMETHOD(PkmnLib::Battling::Pokemon, Damage), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "void OverrideActiveAbility(const string &in ability)", + asMETHOD(PkmnLib::Battling::Pokemon, OverrideActiveTalent), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "LearnedMove@[]@ get_Moves() const property", + asMETHOD(PkmnLib::Battling::Pokemon, GetAttacks), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "const Species@ get_DisplaySpecies() const property", + asMETHOD(PkmnLib::Battling::Pokemon, GetDisplaySpecies), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "const Species@ get_DisplayForme() const property", + asMETHOD(PkmnLib::Battling::Pokemon, GetDisplayVariant), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "uint32 GetFlatStat(Statistic stat) const", + asMETHOD(PkmnLib::Battling::Pokemon, GetFlatStat), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "uint32 GetBoostedStat(Statistic stat) const", + asMETHOD(PkmnLib::Battling::Pokemon, GetBoostedStat), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "uint32 GetBaseStat(Statistic stat) const", + asMETHOD(PkmnLib::Battling::Pokemon, GetBaseStat), asCALL_THISCALL); + assert(r >= 0); + r = engine->RegisterObjectMethod("Pokemon", "int8 GetStatBoost(Statistic stat) const", + asMETHOD(PkmnLib::Battling::Pokemon, GetStatBoost), asCALL_THISCALL); + assert(r >= 0); +} \ No newline at end of file diff --git a/src/AngelScript/TypeRegistry/Battling/RegisterPokemonClass.hpp b/src/AngelScript/TypeRegistry/Battling/RegisterPokemonClass.hpp new file mode 100644 index 0000000..691659f --- /dev/null +++ b/src/AngelScript/TypeRegistry/Battling/RegisterPokemonClass.hpp @@ -0,0 +1,14 @@ +#ifndef PKMNLIB_REGISTERPOKEMONCLASS_HPP +#define PKMNLIB_REGISTERPOKEMONCLASS_HPP + +#include +class RegisterPokemonClass { + static void RegisterDamageSource(asIScriptEngine* engine); + static void RegisterMoveLearnMethod(asIScriptEngine* engine); + static void RegisterLearnedAttack(asIScriptEngine* engine); + static void RegisterPokemonType(asIScriptEngine* engine); +public: + static void Register(asIScriptEngine* engine); +}; + +#endif // PKMNLIB_REGISTERPOKEMONCLASS_HPP diff --git a/src/Battling/Library/BattleLibrary.hpp b/src/Battling/Library/BattleLibrary.hpp index 4150232..71d3531 100644 --- a/src/Battling/Library/BattleLibrary.hpp +++ b/src/Battling/Library/BattleLibrary.hpp @@ -3,13 +3,14 @@ #include #include "../../Library/PokemonLibrary.hpp" +#include "DamageLibrary.hpp" #include "StatCalculator.hpp" namespace PkmnLib::Battling { class BattleLibrary : public CreatureLib::Battling::BattleLibrary { public: BattleLibrary(Library::PokemonLibrary* staticLib, StatCalculator* statCalculator, - CreatureLib::Battling::DamageLibrary* damageLibrary, + DamageLibrary* damageLibrary, CreatureLib::Battling::ExperienceLibrary* experienceLibrary, CreatureLib::Battling::ScriptResolver* scriptResolver, CreatureLib::Battling::MiscLibrary* miscLibrary) diff --git a/src/Battling/Library/DamageLibrary.cpp b/src/Battling/Library/DamageLibrary.cpp new file mode 100644 index 0000000..ccd684c --- /dev/null +++ b/src/Battling/Library/DamageLibrary.cpp @@ -0,0 +1,68 @@ +#include "DamageLibrary.hpp" +#include "../Pokemon/Pokemon.hpp" +int PkmnLib::Battling::DamageLibrary::GetDamage(CreatureLib::Battling::ExecutingAttack* attack, + CreatureLib::Battling::Creature* target, uint8_t hitIndex) const { + auto levelMod = static_cast(2 * attack->GetUser()->GetLevel()); + auto hit = attack->GetAttackDataForTarget(target).GetHit(hitIndex); + auto bp = hit->GetBasePower(); + auto statMod = GetStatModifier(attack, target, hitIndex); + // HOOK: Modify stat modifier + int damage = static_cast((((levelMod * static_cast(bp) * statMod) / 50) + 2) * + GetDamageModifier(attack, target, hitIndex)); + // HOOK: Override damage + return damage; +} +int PkmnLib::Battling::DamageLibrary::GetBasePower(CreatureLib::Battling::ExecutingAttack* attack, + CreatureLib::Battling::Creature* target, uint8_t hitIndex) const { + auto bp = attack->GetAttack()->GetAttack()->GetBasePower(); + // HOOK: modify base power. + return bp; +} +float PkmnLib::Battling::DamageLibrary::GetStatModifier(CreatureLib::Battling::ExecutingAttack* attack, + CreatureLib::Battling::Creature* target, + uint8_t hitIndex) const { + auto user = attack->GetUser(); + // HOOK: allow overriding for which users stat we use. + auto hit = attack->GetAttackDataForTarget(target).GetHit(hitIndex); + CreatureLib::Core::Statistic offensiveStat; + CreatureLib::Core::Statistic defensiveStat; + auto learnedMove = dynamic_cast(attack->GetAttack()); + auto moveData = learnedMove->GetMoveData(); + if (moveData->GetCategory() == Library::MoveCategory::Physical) { + offensiveStat = Library::Statistic::PhysicalAttack; + defensiveStat = Library::Statistic::PhysicalDefense; + } else { + offensiveStat = Library::Statistic::SpecialAttack; + defensiveStat = Library::Statistic::SpecialDefense; + } + + auto bypassDefensive = hit->IsCritical() && target->GetStatBoost(defensiveStat) > 0; + // HOOK: allow bypassing defensive stat modifiers. + auto bypassOffensive = hit->IsCritical() && user->GetStatBoost(offensiveStat) < 0; + // HOOK: Allow bypassing offensive stat modifiers. + + float offensiveValue; + float defensiveValue; + + if (bypassOffensive) { + offensiveValue = user->GetFlatStat(offensiveStat); + } else { + offensiveValue = user->GetBoostedStat(offensiveStat); + } + if (bypassDefensive) { + defensiveValue = target->GetFlatStat(defensiveStat); + } else { + defensiveValue = target->GetBoostedStat(defensiveStat); + } + + return offensiveValue / defensiveValue; +} +float PkmnLib::Battling::DamageLibrary::GetDamageModifier(CreatureLib::Battling::ExecutingAttack* attack, + CreatureLib::Battling::Creature* target, + uint8_t hitIndex) const { + float mod = 1; + auto hit = attack->GetAttackDataForTarget(target).GetHit(hitIndex); + mod *= hit->GetEffectiveness(); + // HOOK: Modify damage modifier. + return mod; +} diff --git a/src/Battling/Library/DamageLibrary.hpp b/src/Battling/Library/DamageLibrary.hpp new file mode 100644 index 0000000..7388be1 --- /dev/null +++ b/src/Battling/Library/DamageLibrary.hpp @@ -0,0 +1,20 @@ +#ifndef PKMNLIB_DAMAGELIBRARY_HPP +#define PKMNLIB_DAMAGELIBRARY_HPP + +#include +namespace PkmnLib::Battling { + class DamageLibrary : public CreatureLib::Battling::DamageLibrary { + public: + int GetDamage(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, + uint8_t hitIndex) const override; + + int GetBasePower(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, + uint8_t hitIndex) const override; + float GetStatModifier(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, + uint8_t hitIndex) const override; + float GetDamageModifier(CreatureLib::Battling::ExecutingAttack* attack, CreatureLib::Battling::Creature* target, + uint8_t hitIndex) const override; + }; +} + +#endif // PKMNLIB_DAMAGELIBRARY_HPP diff --git a/src/Battling/Pokemon/LearnedMove.hpp b/src/Battling/Pokemon/LearnedMove.hpp index d45cb7a..9ea4355 100644 --- a/src/Battling/Pokemon/LearnedMove.hpp +++ b/src/Battling/Pokemon/LearnedMove.hpp @@ -5,9 +5,11 @@ #include "../../Library/Moves/MoveData.hpp" namespace PkmnLib::Battling { class LearnedMove : public CreatureLib::Battling::LearnedAttack { - public: + public: LearnedMove(const Library::MoveData* move, CreatureLib::Battling::AttackLearnMethod learnMethod) - : CreatureLib::Battling::LearnedAttack(move, learnMethod){} + : CreatureLib::Battling::LearnedAttack(move, learnMethod) {} + + const Library::MoveData* GetMoveData() const { return dynamic_cast(GetAttack()); } }; } diff --git a/src/Battling/Pokemon/Pokemon.hpp b/src/Battling/Pokemon/Pokemon.hpp index 23d4417..cef9e34 100644 --- a/src/Battling/Pokemon/Pokemon.hpp +++ b/src/Battling/Pokemon/Pokemon.hpp @@ -29,10 +29,12 @@ namespace PkmnLib::Battling { heldItem, nickname, talent, std::move(moves)), _individualValues(individualValues), _effortValues(effortValues), _nature(nature) {} - const Library::Nature& GetNature() const; - uint8_t GetIndividualValue(CreatureLib::Core::Statistic stat) const { - return _individualValues.GetStat(stat); + const Library::PokemonForme* GetForme() const { + return dynamic_cast(GetVariant()); } + + const Library::Nature& GetNature() const; + uint8_t GetIndividualValue(CreatureLib::Core::Statistic stat) const { return _individualValues.GetStat(stat); } uint8_t GetEffortValue(CreatureLib::Core::Statistic stat) const { return _effortValues.GetStat(stat); } }; } diff --git a/tests/TestLibrary/TestLibrary.hpp b/tests/TestLibrary/TestLibrary.hpp index ef01e44..b8ba8d2 100644 --- a/tests/TestLibrary/TestLibrary.hpp +++ b/tests/TestLibrary/TestLibrary.hpp @@ -23,7 +23,7 @@ public: auto statCalc = new PkmnLib::Battling::StatCalculator(); auto scriptResolver = PkmnLib::Battling::BattleLibrary::CreateScriptResolver(); auto lib = new PkmnLib::Battling::BattleLibrary( - BuildStaticLibrary(), statCalc, new CreatureLib::Battling::DamageLibrary(), + BuildStaticLibrary(), statCalc, new PkmnLib::Battling::DamageLibrary(), new CreatureLib::Battling::ExperienceLibrary(), scriptResolver, new CreatureLib::Battling::MiscLibrary()); scriptResolver->Initialize(lib);