Files

400 lines
15 KiB
C++
Raw Permalink Normal View History

2024-01-17 17:52:49 +00:00
#ifndef GAME_INTERACTOR_H
#define GAME_INTERACTOR_H
#include <stdarg.h>
2024-01-17 17:52:49 +00:00
#ifdef __cplusplus
#include <string>
2024-01-17 17:52:49 +00:00
extern "C" {
#endif
2024-06-02 21:18:16 -04:00
#include "z64.h"
2024-01-17 17:52:49 +00:00
#ifdef __cplusplus
}
#endif
2024-04-28 19:27:28 -05:00
typedef enum {
FLAG_NONE,
FLAG_WEEK_EVENT_REG,
FLAG_EVENT_INF,
FLAG_SCENES_VISIBLE,
FLAG_OWL_ACTIVATION,
FLAG_PERM_SCENE_CHEST,
FLAG_PERM_SCENE_SWITCH,
FLAG_PERM_SCENE_CLEARED_ROOM,
FLAG_PERM_SCENE_COLLECTIBLE,
FLAG_PERM_SCENE_UNK_14,
FLAG_PERM_SCENE_ROOMS,
FLAG_CYCL_SCENE_CHEST,
FLAG_CYCL_SCENE_SWITCH,
FLAG_CYCL_SCENE_CLEARED_ROOM,
FLAG_CYCL_SCENE_COLLECTIBLE,
} FlagType;
2024-04-17 21:29:15 -05:00
typedef enum {
// Vanilla condition: gSaveContext.showTitleCard
2024-10-05 10:02:53 -05:00
VB_SHOW_TITLE_CARD,
VB_PLAY_ENTRANCE_CS,
VB_DISABLE_FD_MASK,
VB_DOGGY_RACE_SET_MAX_SPEED,
VB_LOWER_RAZOR_SWORD_DURABILITY,
VB_SET_BLAST_MASK_COOLDOWN_TIMER,
VB_PATCH_POWER_CROUCH_STAB,
VB_PATCH_SIDEROLL,
VB_TATL_CONVERSATION_AVAILABLE,
VB_PREVENT_MASK_TRANSFORMATION_CS,
VB_RESET_PUTAWAY_TIMER,
VB_SET_CLIMB_SPEED,
VB_PREVENT_CLOCK_DISPLAY,
VB_SONG_AVAILABLE_TO_PLAY,
VB_USE_CUSTOM_CAMERA,
VB_DELETE_OWL_SAVE,
VB_MSG_SCRIPT_DEL_ITEM,
2024-10-05 10:02:53 -05:00
VB_CONSIDER_BUNNY_HOOD_EQUIPPED,
VB_USE_ITEM_EQUIP_MASK,
VB_KALEIDO_DISPLAY_ITEM_TEXT,
VB_USE_ITEM_CONSIDER_LINK_HUMAN,
VB_DRAW_ITEM_EQUIPPED_OUTLINE,
VB_PLAY_TRANSITION_CS,
VB_TATL_INTERUPT_MSG3,
VB_TATL_INTERUPT_MSG6,
VB_ITEM_BE_RESTRICTED,
VB_FLIP_HOP_VARIABLE,
VB_DISABLE_LETTERBOX,
VB_CLOCK_TOWER_OPENING_CONSIDER_THIS_FIRST_CYCLE,
VB_DRAW_SLIME_BODY_ITEM,
VB_ZTARGET_SPEED_CHECK,
2024-10-07 12:02:36 -04:00
VB_THIEF_BIRD_STEAL,
VB_PLAY_CREMIA_HUG_CUTSCENE,
VB_FD_ALWAYS_WIELD_SWORD,
VB_SHOULD_PUTAWAY,
VB_ELEGY_CHECK_SCENE,
VB_NEED_SCARECROW_SONG,
VB_CHECK_HELD_ITEM_BUTTON_PRESS,
VB_MAGIC_SPIN_ATTACK_CHECK_FORM,
VB_TRANSFORM_THUNDER_MATRIX,
2024-04-17 21:29:15 -05:00
} GIVanillaBehavior;
2024-01-17 17:52:49 +00:00
2024-05-21 23:00:22 -05:00
typedef enum {
GI_INVERT_CAMERA_RIGHT_STICK_X,
GI_INVERT_CAMERA_RIGHT_STICK_Y,
2024-10-02 22:44:36 -05:00
GI_INVERT_MOVEMENT_X,
GI_INVERT_SHIELD_X,
GI_INVERT_SHOP_X,
GI_INVERT_HORSE_X,
GI_INVERT_ZORA_SWIM_X,
GI_INVERT_DEBUG_DPAD_X,
GI_INVERT_TELESCOPE_X,
2024-10-06 20:55:16 -05:00
GI_INVERT_FIRST_PERSON_AIM_X,
GI_INVERT_FIRST_PERSON_AIM_Y,
GI_INVERT_FIRST_PERSON_GYRO_X,
GI_INVERT_FIRST_PERSON_GYRO_Y,
GI_INVERT_FIRST_PERSON_RIGHT_STICK_X,
GI_INVERT_FIRST_PERSON_RIGHT_STICK_Y,
GI_INVERT_FIRST_PERSON_MOVING_X,
2024-05-21 23:00:22 -05:00
} GIInvertType;
typedef enum {
GI_DPAD_OCARINA,
GI_DPAD_EQUIP,
} GIDpadType;
2024-01-17 17:52:49 +00:00
#ifdef __cplusplus
#include <vector>
#include <functional>
2024-01-28 22:02:30 +00:00
#include <unordered_map>
#include <cstdint>
2024-05-20 18:19:38 -04:00
#include <algorithm>
2024-01-17 17:52:49 +00:00
2024-04-17 21:29:15 -05:00
typedef uint32_t HOOK_ID;
#define DEFINE_HOOK(name, args) \
struct name { \
typedef std::function<void args> fn; \
typedef std::function<bool args> filter; \
2024-01-17 17:52:49 +00:00
}
class GameInteractor {
2024-05-22 09:52:56 -04:00
public:
2024-01-17 17:52:49 +00:00
static GameInteractor* Instance;
// Game State
2024-05-22 09:52:56 -04:00
class State {};
2024-01-17 17:52:49 +00:00
// Game Hooks
2024-04-17 21:29:15 -05:00
HOOK_ID nextHookId = 1;
template <typename H> struct RegisteredGameHooks {
inline static std::unordered_map<HOOK_ID, typename H::fn> functions;
inline static std::unordered_map<int32_t, std::unordered_map<HOOK_ID, typename H::fn>> functionsForID;
inline static std::unordered_map<uintptr_t, std::unordered_map<HOOK_ID, typename H::fn>> functionsForPtr;
inline static std::unordered_map<HOOK_ID, std::pair<typename H::filter, typename H::fn>> functionsForFilter;
};
template <typename H> struct HooksToUnregister {
inline static std::vector<HOOK_ID> hooks;
inline static std::vector<HOOK_ID> hooksForID;
inline static std::vector<HOOK_ID> hooksForPtr;
inline static std::vector<HOOK_ID> hooksForFilter;
};
// General Hooks
template <typename H> HOOK_ID RegisterGameHook(typename H::fn h) {
2024-05-22 09:52:56 -04:00
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX)
this->nextHookId = 1;
2024-01-28 22:02:30 +00:00
while (RegisteredGameHooks<H>::functions.find(this->nextHookId) != RegisteredGameHooks<H>::functions.end()) {
this->nextHookId++;
}
RegisteredGameHooks<H>::functions[this->nextHookId] = h;
return this->nextHookId++;
}
2024-04-17 21:29:15 -05:00
template <typename H> void UnregisterGameHook(HOOK_ID hookId) {
2024-05-22 09:52:56 -04:00
if (hookId == 0)
return;
2024-04-17 21:29:15 -05:00
HooksToUnregister<H>::hooks.push_back(hookId);
2024-01-28 22:02:30 +00:00
}
2024-01-17 17:52:49 +00:00
template <typename H, typename... Args> void ExecuteHooks(Args&&... args) {
2024-01-28 22:02:30 +00:00
for (auto& hookId : HooksToUnregister<H>::hooks) {
RegisteredGameHooks<H>::functions.erase(hookId);
}
HooksToUnregister<H>::hooks.clear();
for (auto& hook : RegisteredGameHooks<H>::functions) {
hook.second(std::forward<Args>(args)...);
2024-01-17 17:52:49 +00:00
}
}
2024-04-17 21:29:15 -05:00
// ID based Hooks
template <typename H> HOOK_ID RegisterGameHookForID(int32_t id, typename H::fn h) {
2024-05-22 09:52:56 -04:00
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX)
this->nextHookId = 1;
while (RegisteredGameHooks<H>::functionsForID[id].find(this->nextHookId) !=
RegisteredGameHooks<H>::functionsForID[id].end()) {
2024-04-17 21:29:15 -05:00
this->nextHookId++;
}
2024-01-17 17:52:49 +00:00
2024-04-17 21:29:15 -05:00
RegisteredGameHooks<H>::functionsForID[id][this->nextHookId] = h;
return this->nextHookId++;
}
template <typename H> void UnregisterGameHookForID(HOOK_ID hookId) {
2024-05-22 09:52:56 -04:00
if (hookId == 0)
return;
2024-04-17 21:29:15 -05:00
HooksToUnregister<H>::hooksForID.push_back(hookId);
}
template <typename H, typename... Args> void ExecuteHooksForID(int32_t id, Args&&... args) {
for (auto& hookId : HooksToUnregister<H>::hooksForID) {
2024-05-22 09:52:56 -04:00
for (auto it = RegisteredGameHooks<H>::functionsForID[id].begin();
it != RegisteredGameHooks<H>::functionsForID[id].end();) {
2024-04-17 21:29:15 -05:00
if (it->first == hookId) {
it = RegisteredGameHooks<H>::functionsForID[id].erase(it);
2024-05-22 09:52:56 -04:00
HooksToUnregister<H>::hooksForID.erase(std::remove(HooksToUnregister<H>::hooksForID.begin(),
HooksToUnregister<H>::hooksForID.end(), hookId),
HooksToUnregister<H>::hooksForID.end());
2024-04-17 21:29:15 -05:00
} else {
++it;
}
}
}
for (auto& hook : RegisteredGameHooks<H>::functionsForID[id]) {
hook.second(std::forward<Args>(args)...);
}
}
2024-01-17 17:52:49 +00:00
2024-04-17 21:29:15 -05:00
// PTR based Hooks
template <typename H> HOOK_ID RegisterGameHookForPtr(uintptr_t ptr, typename H::fn h) {
2024-05-22 09:52:56 -04:00
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX)
this->nextHookId = 1;
while (RegisteredGameHooks<H>::functionsForPtr[ptr].find(this->nextHookId) !=
RegisteredGameHooks<H>::functionsForPtr[ptr].end()) {
2024-04-17 21:29:15 -05:00
this->nextHookId++;
}
RegisteredGameHooks<H>::functionsForPtr[ptr][this->nextHookId] = h;
return this->nextHookId++;
}
template <typename H> void UnregisterGameHookForPtr(HOOK_ID hookId) {
2024-05-22 09:52:56 -04:00
if (hookId == 0)
return;
2024-04-17 21:29:15 -05:00
HooksToUnregister<H>::hooksForPtr.push_back(hookId);
}
template <typename H, typename... Args> void ExecuteHooksForPtr(uintptr_t ptr, Args&&... args) {
for (auto& hookId : HooksToUnregister<H>::hooksForPtr) {
2024-05-22 09:52:56 -04:00
for (auto it = RegisteredGameHooks<H>::functionsForPtr[ptr].begin();
it != RegisteredGameHooks<H>::functionsForPtr[ptr].end();) {
2024-04-17 21:29:15 -05:00
if (it->first == hookId) {
it = RegisteredGameHooks<H>::functionsForPtr[ptr].erase(it);
2024-05-22 09:52:56 -04:00
HooksToUnregister<H>::hooksForPtr.erase(std::remove(HooksToUnregister<H>::hooksForPtr.begin(),
HooksToUnregister<H>::hooksForPtr.end(),
hookId),
HooksToUnregister<H>::hooksForPtr.end());
2024-04-17 21:29:15 -05:00
} else {
++it;
}
}
}
for (auto& hook : RegisteredGameHooks<H>::functionsForPtr[ptr]) {
hook.second(std::forward<Args>(args)...);
}
}
// Filter based Hooks
template <typename H> HOOK_ID RegisterGameHookForFilter(typename H::filter f, typename H::fn h) {
2024-05-22 09:52:56 -04:00
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX)
this->nextHookId = 1;
while (RegisteredGameHooks<H>::functionsForFilter.find(this->nextHookId) !=
RegisteredGameHooks<H>::functionsForFilter.end()) {
2024-04-17 21:29:15 -05:00
this->nextHookId++;
}
RegisteredGameHooks<H>::functionsForFilter[this->nextHookId] = std::make_pair(f, h);
return this->nextHookId++;
}
template <typename H> void UnregisterGameHookForFilter(HOOK_ID hookId) {
2024-05-22 09:52:56 -04:00
if (hookId == 0)
return;
2024-04-17 21:29:15 -05:00
HooksToUnregister<H>::hooksForFilter.push_back(hookId);
}
template <typename H, typename... Args> void ExecuteHooksForFilter(Args&&... args) {
for (auto& hookId : HooksToUnregister<H>::hooksForFilter) {
RegisteredGameHooks<H>::functionsForFilter.erase(hookId);
}
HooksToUnregister<H>::hooksForFilter.clear();
for (auto& hook : RegisteredGameHooks<H>::functionsForFilter) {
if (hook.second.first(std::forward<Args>(args)...)) {
hook.second.second(std::forward<Args>(args)...);
}
}
}
class HookFilter {
2024-05-22 09:52:56 -04:00
public:
2024-04-17 21:29:15 -05:00
static auto ActorNotPlayer(Actor* actor) {
return actor->id != ACTOR_PLAYER;
}
// For use with Should hooks
static auto SActorNotPlayer(Actor* actor, bool* result) {
return actor->id != ACTOR_PLAYER;
}
static auto ActorMatchIdAndParams(int16_t id, int16_t params) {
2024-05-22 09:52:56 -04:00
return [id, params](Actor* actor) { return actor->id == id && actor->params == params; };
2024-04-17 21:29:15 -05:00
}
// For use with Should hooks
static auto SActorMatchIdAndParams(int16_t id, int16_t params) {
2024-05-22 09:52:56 -04:00
return [id, params](Actor* actor, bool* result) { return actor->id == id && actor->params == params; };
2024-04-17 21:29:15 -05:00
}
2024-01-17 17:52:49 +00:00
};
DEFINE_HOOK(OnFileDropped, (std::string path));
2024-04-17 21:29:15 -05:00
DEFINE_HOOK(OnGameStateMainFinish, ());
DEFINE_HOOK(OnGameStateDrawFinish, ());
DEFINE_HOOK(OnGameStateUpdate, ());
2024-06-24 23:16:10 -05:00
DEFINE_HOOK(OnConsoleLogoUpdate, ());
2024-06-02 21:18:16 -04:00
DEFINE_HOOK(OnKaleidoUpdate, (PauseContext * pauseCtx));
DEFINE_HOOK(BeforeKaleidoDrawPage, (PauseContext * pauseCtx, u16 pauseIndex));
DEFINE_HOOK(AfterKaleidoDrawPage, (PauseContext * pauseCtx, u16 pauseIndex));
DEFINE_HOOK(OnSaveInit, (s16 fileNum));
2024-05-03 02:07:33 +02:00
DEFINE_HOOK(BeforeEndOfCycleSave, ());
DEFINE_HOOK(AfterEndOfCycleSave, ());
2024-05-24 20:01:48 +02:00
DEFINE_HOOK(BeforeMoonCrashSaveReset, ());
2024-04-17 21:29:15 -05:00
2024-04-28 19:27:28 -05:00
DEFINE_HOOK(OnSceneInit, (s8 sceneId, s8 spawnNum));
DEFINE_HOOK(OnRoomInit, (s8 sceneId, s8 roomNum));
DEFINE_HOOK(AfterRoomSceneCommands, (s8 sceneId, s8 roomNum));
2024-09-13 10:10:59 -04:00
DEFINE_HOOK(OnPlayDrawWorldEnd, ());
DEFINE_HOOK(OnPlayDestroy, ());
2024-04-28 19:27:28 -05:00
2024-05-22 09:52:56 -04:00
DEFINE_HOOK(ShouldActorInit, (Actor * actor, bool* should));
DEFINE_HOOK(OnActorInit, (Actor * actor));
DEFINE_HOOK(ShouldActorUpdate, (Actor * actor, bool* should));
DEFINE_HOOK(OnActorUpdate, (Actor * actor));
DEFINE_HOOK(ShouldActorDraw, (Actor * actor, bool* should));
DEFINE_HOOK(OnActorDraw, (Actor * actor));
DEFINE_HOOK(OnActorKill, (Actor * actor));
2024-09-13 10:10:59 -04:00
DEFINE_HOOK(OnActorDestroy, (Actor * actor));
DEFINE_HOOK(OnPlayerPostLimbDraw, (Player * player, s32 limbIndex));
2024-04-28 19:27:28 -05:00
DEFINE_HOOK(OnSceneFlagSet, (s16 sceneId, FlagType flagType, u32 flag));
DEFINE_HOOK(OnSceneFlagUnset, (s16 sceneId, FlagType flagType, u32 flag));
DEFINE_HOOK(OnFlagSet, (FlagType flagType, u32 flag));
DEFINE_HOOK(OnFlagUnset, (FlagType flagType, u32 flag));
DEFINE_HOOK(AfterCameraUpdate, (Camera * camera));
2024-05-22 09:52:56 -04:00
DEFINE_HOOK(OnCameraChangeModeFlags, (Camera * camera));
DEFINE_HOOK(OnCameraChangeSettingsFlags, (Camera * camera));
2024-05-22 09:52:56 -04:00
DEFINE_HOOK(OnPassPlayerInputs, (Input * input));
2024-04-28 19:27:28 -05:00
DEFINE_HOOK(OnOpenText, (u16 textId));
DEFINE_HOOK(ShouldItemGive, (u8 item, bool* should));
DEFINE_HOOK(OnItemGive, (u8 item));
2024-04-17 21:29:15 -05:00
DEFINE_HOOK(ShouldVanillaBehavior, (GIVanillaBehavior flag, bool* should, va_list originalArgs));
2024-01-17 17:52:49 +00:00
};
2024-04-17 21:29:15 -05:00
extern "C" {
2024-01-17 17:52:49 +00:00
#endif // __cplusplus
2024-04-17 21:29:15 -05:00
void GameInteractor_ExecuteOnGameStateMainFinish();
void GameInteractor_ExecuteOnGameStateDrawFinish();
void GameInteractor_ExecuteOnGameStateUpdate();
2024-06-24 23:16:10 -05:00
void GameInteractor_ExecuteOnConsoleLogoUpdate();
2024-06-02 21:18:16 -04:00
void GameInteractor_ExecuteOnKaleidoUpdate(PauseContext* pauseCtx);
void GameInteractor_ExecuteBeforeKaleidoDrawPage(PauseContext* pauseCtx, u16 pauseIndex);
void GameInteractor_ExecuteAfterKaleidoDrawPage(PauseContext* pauseCtx, u16 pauseIndex);
void GameInteractor_ExecuteOnSaveInit(s16 fileNum);
2024-05-03 02:07:33 +02:00
void GameInteractor_ExecuteBeforeEndOfCycleSave();
void GameInteractor_ExecuteAfterEndOfCycleSave();
2024-05-24 20:01:48 +02:00
void GameInteractor_ExecuteBeforeMoonCrashSaveReset();
2024-04-17 21:29:15 -05:00
2024-04-28 19:27:28 -05:00
void GameInteractor_ExecuteOnSceneInit(s16 sceneId, s8 spawnNum);
void GameInteractor_ExecuteOnRoomInit(s16 sceneId, s8 roomNum);
void GameInteractor_ExecuteAfterRoomSceneCommands(s16 sceneId, s8 roomNum);
2024-09-13 10:10:59 -04:00
void GameInteractor_ExecuteOnPlayDrawWorldEnd();
void GameInteractor_ExecuteOnPlayDestroy();
2024-04-28 19:27:28 -05:00
2024-04-17 21:29:15 -05:00
bool GameInteractor_ShouldActorInit(Actor* actor);
void GameInteractor_ExecuteOnActorInit(Actor* actor);
bool GameInteractor_ShouldActorUpdate(Actor* actor);
void GameInteractor_ExecuteOnActorUpdate(Actor* actor);
bool GameInteractor_ShouldActorDraw(Actor* actor);
void GameInteractor_ExecuteOnActorDraw(Actor* actor);
2024-04-28 19:27:28 -05:00
void GameInteractor_ExecuteOnActorKill(Actor* actor);
2024-09-13 10:10:59 -04:00
void GameInteractor_ExecuteOnActorDestroy(Actor* actor);
void GameInteractor_ExecuteOnPlayerPostLimbDraw(Player* player, s32 limbIndex);
2024-04-28 19:27:28 -05:00
void GameInteractor_ExecuteOnSceneFlagSet(s16 sceneId, FlagType flagType, u32 flag);
void GameInteractor_ExecuteOnSceneFlagUnset(s16 sceneId, FlagType flagType, u32 flag);
void GameInteractor_ExecuteOnFlagSet(FlagType flagType, u32 flag);
void GameInteractor_ExecuteOnFlagUnset(FlagType flagType, u32 flag);
void GameInteractor_ExecuteAfterCameraUpdate(Camera* camera);
void GameInteractor_ExecuteOnCameraChangeModeFlags(Camera* camera);
void GameInteractor_ExecuteOnCameraChangeSettingsFlags(Camera* camera);
void GameInteractor_ExecuteOnPassPlayerInputs(Input* input);
2024-04-28 19:27:28 -05:00
void GameInteractor_ExecuteOnOpenText(u16 textId);
bool GameInteractor_ShouldItemGive(u8 item);
void GameInteractor_ExecuteOnItemGive(u8 item);
2024-04-17 21:29:15 -05:00
bool GameInteractor_Should(GIVanillaBehavior flag, uint32_t result, ...);
2024-05-22 09:52:56 -04:00
#define REGISTER_VB_SHOULD(flag, body) \
GameInteractor::Instance->RegisterGameHookForID<GameInteractor::ShouldVanillaBehavior>( \
flag, [](GIVanillaBehavior _, bool* should, va_list originalArgs) { \
va_list args; \
va_copy(args, originalArgs); \
body; \
va_end(args); \
})
2024-04-17 21:29:15 -05:00
2024-05-21 23:00:22 -05:00
int GameInteractor_InvertControl(GIInvertType type);
uint32_t GameInteractor_Dpad(GIDpadType type, uint32_t buttonCombo);
2024-05-21 23:00:22 -05:00
2024-04-17 21:29:15 -05:00
#ifdef __cplusplus
}
#endif
#endif // GAME_INTERACTOR_H