mirror of
https://github.com/HarbourMasters/Shipwright
synced 2026-04-23 08:14:31 +00:00
579 lines
23 KiB
C++
579 lines
23 KiB
C++
#pragma once
|
|
|
|
#ifndef GameInteractor_h
|
|
#define GameInteractor_h
|
|
|
|
#include "libultraship/libultraship.h"
|
|
#include "vanilla-behavior/GIVanillaBehavior.h"
|
|
#include <z64.h>
|
|
|
|
typedef enum {
|
|
/* 0x00 */ GI_LINK_SIZE_NORMAL,
|
|
/* 0x01 */ GI_LINK_SIZE_GIANT,
|
|
/* 0x02 */ GI_LINK_SIZE_MINISH,
|
|
/* 0x03 */ GI_LINK_SIZE_PAPER,
|
|
/* 0x03 */ GI_LINK_SIZE_SQUISHED,
|
|
/* 0x04 */ GI_LINK_SIZE_RESET
|
|
} GILinkSize;
|
|
|
|
typedef enum {
|
|
/* 0x00 */ GI_GRAVITY_LEVEL_LIGHT,
|
|
/* 0x01 */ GI_GRAVITY_LEVEL_NORMAL,
|
|
/* 0x02 */ GI_GRAVITY_LEVEL_HEAVY,
|
|
} GIGravityLevel;
|
|
|
|
typedef enum {
|
|
/* 0x00 */ GI_BUTTONS_CBUTTONS,
|
|
/* 0x01 */ GI_BUTTONS_DPAD,
|
|
} GIButtonSet;
|
|
|
|
typedef enum {
|
|
/* */ GI_TIMEOFDAY_DAWN = 32768,
|
|
/* */ GI_TIMEOFDAY_NOON = 49152,
|
|
/* */ GI_TIMEOFDAY_DUSK = 0,
|
|
/* */ GI_TIMEOFDAY_MIDNIGHT = 16384,
|
|
} GITimeOfDay;
|
|
|
|
typedef enum {
|
|
/* 0x00 */ GI_COSMETICS_TUNICS,
|
|
/* 0x01 */ GI_COSMETICS_NAVI,
|
|
/* 0x02 */ GI_COSMETICS_HAIR,
|
|
} GICosmeticCategories;
|
|
|
|
typedef enum {
|
|
/* 0x00 */ GI_COLOR_RED,
|
|
/* 0x01 */ GI_COLOR_GREEN,
|
|
/* 0x02 */ GI_COLOR_BLUE,
|
|
/* 0x03 */ GI_COLOR_ORANGE,
|
|
/* 0x04 */ GI_COLOR_YELLOW,
|
|
/* 0x05 */ GI_COLOR_PURPLE,
|
|
/* 0x06 */ GI_COLOR_PINK,
|
|
/* 0x07 */ GI_COLOR_BROWN,
|
|
/* 0x08 */ GI_COLOR_BLACK,
|
|
} GIColors;
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
uint8_t GameInteractor_NoUIActive();
|
|
GILinkSize GameInteractor_GetLinkSize();
|
|
void GameInteractor_SetLinkSize(GILinkSize size);
|
|
uint8_t GameInteractor_InvisibleLinkActive();
|
|
uint8_t GameInteractor_OneHitKOActive();
|
|
uint8_t GameInteractor_PacifistModeActive();
|
|
uint8_t GameInteractor_DisableZTargetingActive();
|
|
uint8_t GameInteractor_ReverseControlsActive();
|
|
int32_t GameInteractor_DefenseModifier();
|
|
float GameInteractor_MovementSpeedMultiplier();
|
|
GIGravityLevel GameInteractor_GravityLevel();
|
|
uint32_t GameInteractor_GetEmulatedButtons();
|
|
void GameInteractor_SetEmulatedButtons(uint32_t buttons);
|
|
uint8_t GameInteractor_GetRandomBombFuseTimerActive();
|
|
uint8_t GameInteractor_GetDisableLedgeGrabsActive();
|
|
uint8_t GameInteractor_GetRandomWindActive();
|
|
uint8_t GameInteractor_GetRandomBonksActive();
|
|
uint8_t GameInteractor_GetSlipperyFloorActive();
|
|
uint8_t GameInteractor_SecondCollisionUpdate();
|
|
void GameInteractor_SetTriforceHuntPieceGiven(uint8_t state);
|
|
void GameInteractor_SetTriforceHuntCreditsWarpActive(uint8_t state);
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
#include <stdarg.h>
|
|
#include <map>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
#include <functional>
|
|
#include <cstring>
|
|
|
|
#include <version>
|
|
#ifdef __cpp_lib_source_location
|
|
#include <source_location>
|
|
#else
|
|
#pragma message("Compiling without <source_location> support, the Hook Debugger will not be available")
|
|
#endif
|
|
|
|
#include "GameInteractionEffect.h"
|
|
|
|
typedef uint32_t HOOK_ID;
|
|
|
|
enum HookType {
|
|
HOOK_TYPE_NORMAL,
|
|
HOOK_TYPE_ID,
|
|
HOOK_TYPE_PTR,
|
|
HOOK_TYPE_FILTER,
|
|
};
|
|
|
|
struct HookRegisteringInfo {
|
|
bool valid;
|
|
const char* file;
|
|
std::uint_least32_t line;
|
|
std::uint_least32_t column;
|
|
const char* function;
|
|
HookType type;
|
|
|
|
HookRegisteringInfo()
|
|
: valid(false), file("unknown file"), line(0), column(0), function("unknown function"), type(HOOK_TYPE_NORMAL) {
|
|
}
|
|
|
|
HookRegisteringInfo(const char* _file, std::uint_least32_t _line, std::uint_least32_t _column,
|
|
const char* _function, HookType _type)
|
|
: valid(true), file(_file), line(_line), column(_column), function(_function), type(_type) {
|
|
// Trim off user parent directories
|
|
const char* trimmed = strstr(_file, "soh/soh/");
|
|
if (trimmed != nullptr) {
|
|
file = trimmed;
|
|
}
|
|
}
|
|
};
|
|
|
|
struct HookInfo {
|
|
uint32_t calls;
|
|
HookRegisteringInfo registering;
|
|
};
|
|
|
|
#ifdef __cpp_lib_source_location
|
|
#define GET_CURRENT_REGISTERING_INFO(type) \
|
|
(HookRegisteringInfo{ location.file_name(), location.line(), location.column(), location.function_name(), type })
|
|
#else
|
|
#define GET_CURRENT_REGISTERING_INFO(type) (HookRegisteringInfo{})
|
|
#endif
|
|
|
|
#define REGISTER_VB_SHOULD(flag, body) \
|
|
GameInteractor::Instance->RegisterGameHookForID<GameInteractor::OnVanillaBehavior>( \
|
|
flag, [](GIVanillaBehavior _, bool* should, va_list _originalArgs) { \
|
|
va_list args; \
|
|
va_copy(args, _originalArgs); \
|
|
body; \
|
|
va_end(args); \
|
|
})
|
|
|
|
#define COND_HOOK(hookType, condition, body) \
|
|
{ \
|
|
static HOOK_ID hookId = 0; \
|
|
GameInteractor::Instance->UnregisterGameHook<GameInteractor::hookType>(hookId); \
|
|
hookId = 0; \
|
|
if (condition) { \
|
|
hookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::hookType>(body); \
|
|
} \
|
|
}
|
|
#define COND_ID_HOOK(hookType, id, condition, body) \
|
|
{ \
|
|
static HOOK_ID hookId = 0; \
|
|
GameInteractor::Instance->UnregisterGameHookForID<GameInteractor::hookType>(hookId); \
|
|
hookId = 0; \
|
|
if (condition) { \
|
|
hookId = GameInteractor::Instance->RegisterGameHookForID<GameInteractor::hookType>(id, body); \
|
|
} \
|
|
}
|
|
#define COND_VB_SHOULD(id, condition, body) \
|
|
{ \
|
|
static HOOK_ID hookId = 0; \
|
|
GameInteractor::Instance->UnregisterGameHookForID<GameInteractor::OnVanillaBehavior>(hookId); \
|
|
hookId = 0; \
|
|
if (condition) { \
|
|
hookId = REGISTER_VB_SHOULD(id, body); \
|
|
} \
|
|
}
|
|
|
|
class GameInteractor {
|
|
public:
|
|
static GameInteractor* Instance;
|
|
|
|
// Game State
|
|
class State {
|
|
public:
|
|
static bool NoUIActive;
|
|
static GILinkSize LinkSize;
|
|
static bool InvisibleLinkActive;
|
|
static bool OneHitKOActive;
|
|
static bool PacifistModeActive;
|
|
static bool DisableZTargetingActive;
|
|
static bool ReverseControlsActive;
|
|
static int32_t DefenseModifier;
|
|
static float MovementSpeedMultiplier;
|
|
static GIGravityLevel GravityLevel;
|
|
static uint32_t EmulatedButtons;
|
|
static uint8_t RandomBombFuseTimerActive;
|
|
static uint8_t DisableLedgeGrabsActive;
|
|
static uint8_t RandomWindActive;
|
|
static uint8_t RandomWindSecondsSinceLastDirectionChange;
|
|
static uint8_t RandomBonksActive;
|
|
static uint8_t SlipperyFloorActive;
|
|
static uint8_t SecondCollisionUpdate;
|
|
static uint8_t TriforceHuntPieceGiven;
|
|
static uint8_t TriforceHuntCreditsWarpActive;
|
|
|
|
static void SetPacifistMode(bool active);
|
|
};
|
|
|
|
// Effects
|
|
static GameInteractionEffectQueryResult CanApplyEffect(GameInteractionEffectBase& effect);
|
|
static GameInteractionEffectQueryResult ApplyEffect(GameInteractionEffectBase& effect);
|
|
static GameInteractionEffectQueryResult RemoveEffect(RemovableGameInteractionEffect& effect);
|
|
|
|
// Game Hooks
|
|
//
|
|
// Hooks should be idempotent and execution order is not guaranteed.
|
|
// If two operations must happen in a specific order, they should be placed in the same hook.
|
|
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;
|
|
|
|
// Used for the hook debugger
|
|
inline static std::map<HOOK_ID, HookInfo> hookData;
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
template <typename H> std::map<uint32_t, HookInfo>* GetHookData() {
|
|
return &RegisteredGameHooks<H>::hookData;
|
|
}
|
|
|
|
// General Hooks
|
|
template <typename H>
|
|
#ifdef __cpp_lib_source_location
|
|
HOOK_ID RegisterGameHook(typename H::fn h, const std::source_location location = std::source_location::current()) {
|
|
#else
|
|
HOOK_ID RegisterGameHook(typename H::fn h) {
|
|
#endif
|
|
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX)
|
|
this->nextHookId = 1;
|
|
while (RegisteredGameHooks<H>::functions.find(this->nextHookId) != RegisteredGameHooks<H>::functions.end()) {
|
|
this->nextHookId++;
|
|
}
|
|
|
|
RegisteredGameHooks<H>::functions[this->nextHookId] = h;
|
|
RegisteredGameHooks<H>::hookData[this->nextHookId] =
|
|
HookInfo{ 0, GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_NORMAL) };
|
|
return this->nextHookId++;
|
|
}
|
|
|
|
template <typename H> void UnregisterGameHook(HOOK_ID hookId) {
|
|
if (hookId == 0)
|
|
return;
|
|
HooksToUnregister<H>::hooks.push_back(hookId);
|
|
}
|
|
|
|
template <typename H, typename... Args> void ExecuteHooks(Args&&... args) {
|
|
// Remove pending hooks for this type
|
|
for (auto& hookId : HooksToUnregister<H>::hooks) {
|
|
RegisteredGameHooks<H>::functions.erase(hookId);
|
|
RegisteredGameHooks<H>::hookData.erase(hookId);
|
|
}
|
|
HooksToUnregister<H>::hooks.clear();
|
|
// Execute hooks
|
|
for (auto& hook : RegisteredGameHooks<H>::functions) {
|
|
hook.second(std::forward<Args>(args)...);
|
|
RegisteredGameHooks<H>::hookData[hook.first].calls += 1;
|
|
}
|
|
}
|
|
|
|
// ID based Hooks
|
|
template <typename H>
|
|
#ifdef __cpp_lib_source_location
|
|
HOOK_ID RegisterGameHookForID(int32_t id, typename H::fn h,
|
|
std::source_location location = std::source_location::current()) {
|
|
#else
|
|
HOOK_ID RegisterGameHookForID(int32_t id, typename H::fn h) {
|
|
#endif
|
|
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX)
|
|
this->nextHookId = 1;
|
|
while (RegisteredGameHooks<H>::functionsForID[id].find(this->nextHookId) !=
|
|
RegisteredGameHooks<H>::functionsForID[id].end()) {
|
|
this->nextHookId++;
|
|
}
|
|
|
|
RegisteredGameHooks<H>::functionsForID[id][this->nextHookId] = h;
|
|
RegisteredGameHooks<H>::hookData[this->nextHookId] = HookInfo{ 0, GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_ID) };
|
|
return this->nextHookId++;
|
|
}
|
|
|
|
template <typename H> void UnregisterGameHookForID(HOOK_ID hookId) {
|
|
if (hookId == 0)
|
|
return;
|
|
HooksToUnregister<H>::hooksForID.push_back(hookId);
|
|
}
|
|
|
|
template <typename H, typename... Args> void ExecuteHooksForID(int32_t id, Args&&... args) {
|
|
// Remove pending hooks for this type
|
|
for (auto hookIdIt = HooksToUnregister<H>::hooksForID.begin();
|
|
hookIdIt != HooksToUnregister<H>::hooksForID.end();) {
|
|
bool remove = false;
|
|
|
|
if (RegisteredGameHooks<H>::functionsForID[id].size() == 0) {
|
|
break;
|
|
}
|
|
|
|
for (auto it = RegisteredGameHooks<H>::functionsForID[id].begin();
|
|
it != RegisteredGameHooks<H>::functionsForID[id].end();) {
|
|
if (it->first == *hookIdIt) {
|
|
it = RegisteredGameHooks<H>::functionsForID[id].erase(it);
|
|
RegisteredGameHooks<H>::hookData.erase(*hookIdIt);
|
|
remove = true;
|
|
break;
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
|
|
if (remove) {
|
|
hookIdIt = HooksToUnregister<H>::hooksForID.erase(hookIdIt);
|
|
} else {
|
|
++hookIdIt;
|
|
}
|
|
}
|
|
// Execute hooks
|
|
for (auto& hook : RegisteredGameHooks<H>::functionsForID[id]) {
|
|
hook.second(std::forward<Args>(args)...);
|
|
RegisteredGameHooks<H>::hookData[hook.first].calls += 1;
|
|
}
|
|
}
|
|
|
|
// PTR based Hooks
|
|
template <typename H>
|
|
#ifdef __cpp_lib_source_location
|
|
HOOK_ID RegisterGameHookForPtr(uintptr_t ptr, typename H::fn h,
|
|
const std::source_location location = std::source_location::current()) {
|
|
#else
|
|
HOOK_ID RegisterGameHookForPtr(uintptr_t ptr, typename H::fn h) {
|
|
#endif
|
|
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX)
|
|
this->nextHookId = 1;
|
|
while (RegisteredGameHooks<H>::functionsForPtr[ptr].find(this->nextHookId) !=
|
|
RegisteredGameHooks<H>::functionsForPtr[ptr].end()) {
|
|
this->nextHookId++;
|
|
}
|
|
|
|
RegisteredGameHooks<H>::functionsForPtr[ptr][this->nextHookId] = h;
|
|
RegisteredGameHooks<H>::hookData[this->nextHookId] = HookInfo{ 0, GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_PTR) };
|
|
return this->nextHookId++;
|
|
}
|
|
|
|
template <typename H> void UnregisterGameHookForPtr(HOOK_ID hookId) {
|
|
if (hookId == 0)
|
|
return;
|
|
HooksToUnregister<H>::hooksForPtr.push_back(hookId);
|
|
}
|
|
|
|
template <typename H, typename... Args> void ExecuteHooksForPtr(uintptr_t ptr, Args&&... args) {
|
|
// Remove pending hooks for this type
|
|
for (auto hookIdIt = HooksToUnregister<H>::hooksForPtr.begin();
|
|
hookIdIt != HooksToUnregister<H>::hooksForPtr.end();) {
|
|
bool remove = false;
|
|
|
|
if (RegisteredGameHooks<H>::functionsForPtr[ptr].size() == 0) {
|
|
break;
|
|
}
|
|
|
|
for (auto it = RegisteredGameHooks<H>::functionsForPtr[ptr].begin();
|
|
it != RegisteredGameHooks<H>::functionsForPtr[ptr].end();) {
|
|
if (it->first == *hookIdIt) {
|
|
it = RegisteredGameHooks<H>::functionsForPtr[ptr].erase(it);
|
|
RegisteredGameHooks<H>::hookData.erase(*hookIdIt);
|
|
remove = true;
|
|
break;
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
|
|
if (remove) {
|
|
hookIdIt = HooksToUnregister<H>::hooksForPtr.erase(hookIdIt);
|
|
} else {
|
|
++hookIdIt;
|
|
}
|
|
}
|
|
// Execute hooks
|
|
for (auto& hook : RegisteredGameHooks<H>::functionsForPtr[ptr]) {
|
|
hook.second(std::forward<Args>(args)...);
|
|
RegisteredGameHooks<H>::hookData[hook.first].calls += 1;
|
|
}
|
|
}
|
|
|
|
// Filter based Hooks
|
|
template <typename H>
|
|
#ifdef __cpp_lib_source_location
|
|
HOOK_ID RegisterGameHookForFilter(typename H::filter f, typename H::fn h,
|
|
const std::source_location location = std::source_location::current()) {
|
|
#else
|
|
HOOK_ID RegisterGameHookForFilter(typename H::filter f, typename H::fn h) {
|
|
#endif
|
|
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX)
|
|
this->nextHookId = 1;
|
|
while (RegisteredGameHooks<H>::functionsForFilter.find(this->nextHookId) !=
|
|
RegisteredGameHooks<H>::functionsForFilter.end()) {
|
|
this->nextHookId++;
|
|
}
|
|
|
|
RegisteredGameHooks<H>::functionsForFilter[this->nextHookId] = std::make_pair(f, h);
|
|
RegisteredGameHooks<H>::hookData[this->nextHookId] =
|
|
HookInfo{ 0, GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_FILTER) };
|
|
return this->nextHookId++;
|
|
}
|
|
|
|
template <typename H> void UnregisterGameHookForFilter(HOOK_ID hookId) {
|
|
if (hookId == 0)
|
|
return;
|
|
HooksToUnregister<H>::hooksForFilter.push_back(hookId);
|
|
}
|
|
|
|
template <typename H, typename... Args> void ExecuteHooksForFilter(Args&&... args) {
|
|
// Remove pending hooks for this type
|
|
for (auto& hookId : HooksToUnregister<H>::hooksForFilter) {
|
|
RegisteredGameHooks<H>::functionsForFilter.erase(hookId);
|
|
RegisteredGameHooks<H>::hookData.erase(hookId);
|
|
}
|
|
HooksToUnregister<H>::hooksForFilter.clear();
|
|
// Execute hooks
|
|
for (auto& hook : RegisteredGameHooks<H>::functionsForFilter) {
|
|
if (hook.second.first(std::forward<Args>(args)...)) {
|
|
hook.second.second(std::forward<Args>(args)...);
|
|
RegisteredGameHooks<H>::hookData[hook.first].calls += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename H> void ProcessUnregisteredHooks() {
|
|
// Normal
|
|
for (auto& hookId : HooksToUnregister<H>::hooks) {
|
|
RegisteredGameHooks<H>::functions.erase(hookId);
|
|
RegisteredGameHooks<H>::hookData.erase(hookId);
|
|
}
|
|
HooksToUnregister<H>::hooks.clear();
|
|
|
|
// ID
|
|
for (auto& hookId : HooksToUnregister<H>::hooksForID) {
|
|
for (auto& idGroup : RegisteredGameHooks<H>::functionsForID) {
|
|
for (auto it = idGroup.second.begin(); it != idGroup.second.end();) {
|
|
if (it->first == hookId) {
|
|
it = idGroup.second.erase(it);
|
|
RegisteredGameHooks<H>::hookData.erase(hookId);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
HooksToUnregister<H>::hooksForID.clear();
|
|
|
|
// Ptr
|
|
for (auto& hookId : HooksToUnregister<H>::hooksForPtr) {
|
|
for (auto& ptrGroup : RegisteredGameHooks<H>::functionsForPtr) {
|
|
for (auto it = ptrGroup.second.begin(); it != ptrGroup.second.end();) {
|
|
if (it->first == hookId) {
|
|
it = ptrGroup.second.erase(it);
|
|
RegisteredGameHooks<H>::hookData.erase(hookId);
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
HooksToUnregister<H>::hooksForPtr.clear();
|
|
|
|
// Filter
|
|
for (auto& hookId : HooksToUnregister<H>::hooksForFilter) {
|
|
RegisteredGameHooks<H>::functionsForFilter.erase(hookId);
|
|
RegisteredGameHooks<H>::hookData.erase(hookId);
|
|
}
|
|
HooksToUnregister<H>::hooksForFilter.clear();
|
|
}
|
|
|
|
void RemoveAllQueuedHooks() {
|
|
#define DEFINE_HOOK(name, _) ProcessUnregisteredHooks<name>();
|
|
|
|
#include "GameInteractor_HookTable.h"
|
|
|
|
#undef DEFINE_HOOK
|
|
}
|
|
|
|
class HookFilter {
|
|
public:
|
|
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) {
|
|
return [id, params](Actor* actor) { return actor->id == id && actor->params == params; };
|
|
}
|
|
// For use with Should hooks
|
|
static auto SActorMatchIdAndParams(int16_t id, int16_t params) {
|
|
return [id, params](Actor* actor, bool* result) { return actor->id == id && actor->params == params; };
|
|
}
|
|
};
|
|
|
|
#define DEFINE_HOOK(name, args) \
|
|
struct name { \
|
|
typedef std::function<void args> fn; \
|
|
typedef std::function<bool args> filter; \
|
|
}
|
|
|
|
#include "GameInteractor_HookTable.h"
|
|
|
|
#undef DEFINE_HOOK
|
|
|
|
// Helpers
|
|
static bool IsSaveLoaded(bool allowDbgSave = false);
|
|
static bool IsGameplayPaused();
|
|
static bool CanSpawnActor();
|
|
static bool CanAddOrTakeAmmo(int16_t amount, int16_t item);
|
|
|
|
class RawAction {
|
|
public:
|
|
static void SetSceneFlag(int16_t sceneNum, int16_t flagType, int16_t flag);
|
|
static void UnsetSceneFlag(int16_t sceneNum, int16_t flagType, int16_t flag);
|
|
static bool CheckFlag(int16_t flagType, int16_t flag);
|
|
static void SetFlag(int16_t flagType, int16_t chestNum);
|
|
static void UnsetFlag(int16_t flagType, int16_t chestNum);
|
|
static void AddOrRemoveHealthContainers(int16_t amount);
|
|
static void AddOrRemoveMagic(int8_t amount);
|
|
static void HealOrDamagePlayer(int16_t hearts);
|
|
static void SetPlayerHealth(int16_t hearts);
|
|
static void SetLinkInvisibility(bool active);
|
|
static void SetWeatherStorm(bool active);
|
|
static void ForceEquipBoots(int8_t boots);
|
|
static void FreezePlayer();
|
|
static void BurnPlayer();
|
|
static void ElectrocutePlayer();
|
|
static void KnockbackPlayer(float strength);
|
|
static void GiveOrTakeShield(int32_t shield);
|
|
static void ForceInterfaceUpdate();
|
|
static void UpdateActor(void* refActor);
|
|
static void TeleportPlayer(int32_t nextEntrance);
|
|
static void ClearAssignedButtons(uint8_t buttonSet);
|
|
static void SetTimeOfDay(uint32_t time);
|
|
static void SetCollisionViewer(bool active);
|
|
static void EmulateButtonPress(int32_t button);
|
|
static void AddOrTakeAmmo(int16_t amount, int16_t item);
|
|
static void EmulateRandomButtonPress(uint32_t chancePercentage = 100);
|
|
static void SetRandomWind(bool active);
|
|
static void SetPlayerInvincibility(bool active);
|
|
static void ClearCutscenePointer();
|
|
|
|
static GameInteractionEffectQueryResult SpawnEnemyWithOffset(uint32_t enemyId, int32_t enemyParams,
|
|
std::string nameTag = "");
|
|
static GameInteractionEffectQueryResult SpawnActor(uint32_t actorId, int32_t actorParams,
|
|
std::string nameTag = "");
|
|
};
|
|
};
|
|
|
|
#undef GET_CURRENT_REGISTERING_INFO
|
|
|
|
#endif /* __cplusplus */
|
|
#endif /* GameInteractor_h */
|