diff --git a/mio-modding-api/dllmain.cpp b/mio-modding-api/dllmain.cpp index 964b258..57394ce 100644 --- a/mio-modding-api/dllmain.cpp +++ b/mio-modding-api/dllmain.cpp @@ -7,6 +7,7 @@ namespace ModAPI { // Constant addresses namespace Addresses { + uintptr_t g_BaseAddr; void* g_PlayerStaminaAddr = nullptr; void* g_PlayerVelocityXAddr = nullptr; void* g_PlayerVelocityYAddr = nullptr; @@ -14,6 +15,7 @@ namespace ModAPI { void* g_MoveByMethodAddr = nullptr; void* g_PlayerObjAddr = nullptr; void* g_HitEnemyAddress = nullptr; + void* g_GiveFlagAddress = nullptr; } // Base address for pointer chain @@ -71,8 +73,11 @@ void LoadMemoryAddresses() { uintptr_t saveArraySizeAddr = baseAddr + 0x1116bf0; uintptr_t hitEnemyFunctionAddress = baseAddr + 0x75ed70; + uintptr_t giveFlagFunctionAddress = baseAddr + 0x060ee40; // Store the address + ModAPI::Addresses::g_BaseAddr = baseAddr; + ModAPI::Pointers::g_PlayerLocationBasePtr = (void**)playerLocationBasePtrAddr; ModAPI::Pointers::g_PlayerHealthBasePtr = (void**)playerHealthBasePtrAddr; ModAPI::Pointers::g_PlayerNacreBasePtr = (void**)playerNacreBasePtrAddr; @@ -90,6 +95,7 @@ void LoadMemoryAddresses() { ModAPI::Addresses::g_PlayerVelocityYAddr = (void*)(plrObjAddr + 0x47C); ModAPI::Addresses::g_HitEnemyAddress = (void*)hitEnemyFunctionAddress; + ModAPI::Addresses::g_GiveFlagAddress = (void*)giveFlagFunctionAddress; } extern "C" __declspec(dllexport) void ModInit(char* id) { diff --git a/mio-modding-api/hooks.cpp b/mio-modding-api/hooks.cpp index 9aa4ff2..b867baa 100644 --- a/mio-modding-api/hooks.cpp +++ b/mio-modding-api/hooks.cpp @@ -14,7 +14,7 @@ namespace ModAPI { NOINLINE void __cdecl ResolveOnHitEnemyHook(uintptr_t enemy_info_address, uintptr_t hit_info_address) { // Run all functions connected to this event - for (int i = 0; i < hitenemy_hooks.size(); i++) { + for(int i = 0; i < hitenemy_hooks.size(); i++) { hitenemy_hooks[i](enemy_info_address, hit_info_address); } // Run the original Enemy Hit function (at the address provided in enemyhit_trampoline) @@ -28,6 +28,30 @@ namespace ModAPI { hitenemy_hooks.push_back(callback); } } + namespace Flags { + // Functions hooked to OnHitEnemy + std::vector> giveflag_hooks; + + uintptr_t giveflag_trampoline = NULL; + + NOINLINE void __cdecl ResolveOnGiveFlag(uintptr_t unknown, ModAPI::SaveData::GameString flag, int32_t amount) { + // Run all functions connected to this event + ModAPI::SaveData::GameString modifiableFlag = flag; + int32_t modifiableAmount = amount; + for(int i = 0; i < giveflag_hooks.size(); i++) { + giveflag_hooks[i](unknown, &modifiableFlag, &modifiableAmount); + } + // Run the original Enemy Hit function (at the address provided in enemyhit_trampoline) + typedef int func(uintptr_t, ModAPI::SaveData::GameString, int32_t); + func* trampoline = (func*)(giveflag_trampoline); + int i = trampoline(unknown, modifiableFlag, modifiableAmount); + } + + // Enter a function to call it when an enemy is hit. Parameters are the addresses of enemy data and hit data. + MODDING_API void RunOnGiveFlag(std::function callback) { + giveflag_hooks.push_back(callback); + } + } namespace Time { float g_timeScale = 1.0f; @@ -81,6 +105,8 @@ namespace ModAPI { MODDING_API void InitializeHooks() { static PLH::NatDetour enemyhit_hook_detour = PLH::NatDetour((uintptr_t)ModAPI::Addresses::g_HitEnemyAddress, (uintptr_t)Combat::ResolveOnHitEnemyHook, &Combat::hitenemy_trampoline); enemyhit_hook_detour.hook(); + static PLH::NatDetour giveflag_hook_detour = PLH::NatDetour((uintptr_t)ModAPI::Addresses::g_GiveFlagAddress, (uintptr_t)Flags::ResolveOnGiveFlag, &Flags::giveflag_trampoline); + giveflag_hook_detour.hook(); static PLH::NatDetour rtlqpc_detour = PLH::NatDetour( (uintptr_t)GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlQueryPerformanceCounter"), diff --git a/mio-modding-api/mio-modding-api.h b/mio-modding-api/mio-modding-api.h index c0b53d0..a0aa05c 100644 --- a/mio-modding-api/mio-modding-api.h +++ b/mio-modding-api/mio-modding-api.h @@ -117,6 +117,8 @@ namespace ModAPI { * instead of accessing these directly. */ namespace Addresses { + extern uintptr_t g_BaseAddr; ///< Base Address for the mio.exe. + extern void* g_PlayerStaminaAddr; ///< Direct address of the player's stamina value. extern void* g_PlayerVelocityXAddr; ///< Direct address of the player's X velocity value, offset from the player object. extern void* g_PlayerVelocityYAddr; ///< Direct address of the player's Y velocity value, offset from the player object. @@ -124,6 +126,7 @@ namespace ModAPI { extern void* g_PlayerObjAddr; ///< Direct address of the player object. extern void* g_HitEnemyAddress; ///< Address of the game's internal hit enemy function. extern void* g_MenuStateAddr; ///< Direct address of the current menu state value. + extern void* g_GiveFlagAddress; ///< Address of the game's internal give flag function. } // namespace Addresses /** @@ -268,6 +271,10 @@ namespace ModAPI { char* data; ///< Pointer to the string data. uint32_t size; ///< Length of the string in bytes. uint32_t unused; ///< Padding - do not use. + GameString(char* data) { + this->data = data; + size = strlen(data); + } } GameString; static_assert(sizeof(GameString) == 16, "GameString size mismatch — struct layout may be wrong"); @@ -362,6 +369,13 @@ namespace ModAPI { * @return True on success, false if the entry was not found. */ MODDING_API bool SetSaveEntryValueFlags(const char* name, uint32_t flags); + /** + * @brief Increases the amount for a flag + * @param flag The flag to increase. + * @param amount The amount to increase the flag by. + * @return The game's internal return value from the give flag method. + */ + MODDING_API char* GiveFlag(const char* flag, int32_t amount); } } // namespace SaveData @@ -538,6 +552,23 @@ namespace ModAPI { MODDING_API void RunOnHitEnemy(std::function callback); } // namespace Combat + /** + * @brief Hooks related to flags. + */ + namespace Flags { + /** + * @brief Registers a callback to be invoked whenever the player is given a flag. + * + * Multiple callbacks can be registered and all will fire on each hit. + * + * @param callback Function to call on enemy hit. Receives two arguments: + * - An unknown pointer to an object (uintptr_t) + * - A pointer to the GameString for the flag type, You may modify this pointer (GameString*) + * - A pointer to the amount of the flag, You may modify this pointer (int32_t*) + */ + MODDING_API void RunOnGiveFlag(std::function callback); + } // namespace Flags + /** * @brief Hooks related to game time. */ diff --git a/mio-modding-api/save-data.cpp b/mio-modding-api/save-data.cpp index 5b71208..8774933 100644 --- a/mio-modding-api/save-data.cpp +++ b/mio-modding-api/save-data.cpp @@ -1,5 +1,6 @@ #include "Windows.h" #include "mio-modding-api.h" +#include using SaveEntry = ModAPI::SaveData::SaveEntry; @@ -100,7 +101,16 @@ namespace ModAPI { } entry->value.flags = flags; return true; - } + } + MODDING_API char* GiveFlag(const char* flag, int32_t amount) { + uintptr_t globalAddr = ModAPI::Addresses::g_BaseAddr + 0x10efbf0; + GameString flagStr = GameString((char*)flag); + return ModAPI::Util::CallAssembly( + ModAPI::Addresses::g_GiveFlagAddress, + globalAddr, + flagStr, + amount); + } } } } \ No newline at end of file