mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-11-29 12:52:18 -05:00
[GameInteractor] Introduce GameFrameUpdate Hook and Migrate Cheats (#2554)
This commit is contained in:
parent
afc61e65ee
commit
c91a044d46
@ -86,6 +86,7 @@ public:
|
||||
|
||||
DEFINE_HOOK(OnLoadGame, void(int32_t fileNum));
|
||||
DEFINE_HOOK(OnExitGame, void(int32_t fileNum));
|
||||
DEFINE_HOOK(OnGameFrameUpdate, void());
|
||||
DEFINE_HOOK(OnReceiveItem, void(u8 item));
|
||||
DEFINE_HOOK(OnSceneInit, void(s16 sceneNum));
|
||||
DEFINE_HOOK(OnPlayerUpdate, void());
|
||||
|
@ -14,6 +14,10 @@ void GameInteractor_ExecuteOnExitGame(int32_t fileNum) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnExitGame>(fileNum);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnGameFrameUpdate() {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnGameFrameUpdate>();
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnReceiveItemHooks(u8 item) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnReceiveItem>(item);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
// MARK: - Gameplay
|
||||
extern "C" void GameInteractor_ExecuteOnLoadGame(int32_t fileNum);
|
||||
extern "C" void GameInteractor_ExecuteOnExitGame(int32_t fileNum);
|
||||
extern "C" void GameInteractor_ExecuteOnGameFrameUpdate();
|
||||
extern "C" void GameInteractor_ExecuteOnReceiveItemHooks(u8 item);
|
||||
extern "C" void GameInteractor_ExecuteOnSceneInit(s16 sceneNum);
|
||||
extern "C" void GameInteractor_ExecuteOnPlayerUpdate();
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
extern "C" {
|
||||
#include <z64.h>
|
||||
#include "macros.h"
|
||||
#include "variables.h"
|
||||
extern SaveContext gSaveContext;
|
||||
extern PlayState* gPlayState;
|
||||
extern void Play_PerformSave(PlayState* play);
|
||||
@ -11,9 +13,170 @@ extern s32 Health_ChangeBy(PlayState* play, s16 healthChange);
|
||||
extern void Rupees_ChangeBy(s16 rupeeChange);
|
||||
}
|
||||
|
||||
void RegisterAutoSaveOnReceiveItemHook() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnReceiveItem>([](u8 item) {
|
||||
void RegisterInfiniteMoney() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (CVarGetInteger("gInfiniteMoney", 0) != 0) {
|
||||
if (gSaveContext.rupees < CUR_CAPACITY(UPG_WALLET)) {
|
||||
gSaveContext.rupees = CUR_CAPACITY(UPG_WALLET);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterInfiniteHealth() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (CVarGetInteger("gInfiniteHealth", 0) != 0) {
|
||||
if (gSaveContext.health < gSaveContext.healthCapacity) {
|
||||
gSaveContext.health = gSaveContext.healthCapacity;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterInfiniteAmmo() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (CVarGetInteger("gInfiniteAmmo", 0) != 0) {
|
||||
// Deku Sticks
|
||||
if (AMMO(ITEM_STICK) < CUR_CAPACITY(UPG_STICKS)) {
|
||||
AMMO(ITEM_STICK) = CUR_CAPACITY(UPG_STICKS);
|
||||
}
|
||||
|
||||
// Deku Nuts
|
||||
if (AMMO(ITEM_NUT) < CUR_CAPACITY(UPG_NUTS)) {
|
||||
AMMO(ITEM_NUT) = CUR_CAPACITY(UPG_NUTS);
|
||||
}
|
||||
|
||||
// Bombs
|
||||
if (AMMO(ITEM_BOMB) < CUR_CAPACITY(UPG_BOMB_BAG)) {
|
||||
AMMO(ITEM_BOMB) = CUR_CAPACITY(UPG_BOMB_BAG);
|
||||
}
|
||||
|
||||
// Fairy Bow (Ammo)
|
||||
if (AMMO(ITEM_BOW) < CUR_CAPACITY(UPG_QUIVER)) {
|
||||
AMMO(ITEM_BOW) = CUR_CAPACITY(UPG_QUIVER);
|
||||
}
|
||||
|
||||
// Fairy Slingshot (Ammo)
|
||||
if (AMMO(ITEM_SLINGSHOT) < CUR_CAPACITY(UPG_BULLET_BAG)) {
|
||||
AMMO(ITEM_SLINGSHOT) = CUR_CAPACITY(UPG_BULLET_BAG);
|
||||
}
|
||||
|
||||
// Bombchus (max: 50, no upgrades)
|
||||
if (INV_CONTENT(ITEM_BOMBCHU) == ITEM_BOMBCHU && AMMO(ITEM_BOMBCHU) < 50) {
|
||||
AMMO(ITEM_BOMBCHU) = 50;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterInfiniteMagic() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (CVarGetInteger("gInfiniteMagic", 0) != 0) {
|
||||
if (gSaveContext.isMagicAcquired && gSaveContext.magic != (gSaveContext.isDoubleMagicAcquired + 1) * 0x30) {
|
||||
gSaveContext.magic = (gSaveContext.isDoubleMagicAcquired + 1) * 0x30;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterInfiniteNayrusLove() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (CVarGetInteger("gInfiniteNayru", 0) != 0) {
|
||||
gSaveContext.nayrusLoveTimer = 0x44B;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterMoonJumpOnL() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (CVarGetInteger("gMoonJumpOnL", 0) != 0) {
|
||||
if (gPlayState) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
|
||||
if (CHECK_BTN_ANY(gPlayState->state.input[0].cur.button, BTN_L)) {
|
||||
player->actor.velocity.y = 6.34375f;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void RegisterInfiniteISG() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (CVarGetInteger("gEzISG", 0) != 0) {
|
||||
if (gPlayState) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
player->swordState = 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterUnrestrictedItems() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (CVarGetInteger("gNoRestrictItems", 0) != 0) {
|
||||
if (gPlayState) {
|
||||
u8 sunsBackup = gPlayState->interfaceCtx.restrictions.sunsSong;
|
||||
memset(&gPlayState->interfaceCtx.restrictions, 0, sizeof(gPlayState->interfaceCtx.restrictions));
|
||||
gPlayState->interfaceCtx.restrictions.sunsSong = sunsBackup;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterFreezeTime() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([]() {
|
||||
if (CVarGetInteger("gFreezeTime", 0) != 0) {
|
||||
if (CVarGetInteger("gPrevTime", -1) == -1) {
|
||||
CVarSetInteger("gPrevTime", gSaveContext.dayTime);
|
||||
}
|
||||
|
||||
int32_t prevTime = CVarGetInteger("gPrevTime", gSaveContext.dayTime);
|
||||
gSaveContext.dayTime = prevTime;
|
||||
} else {
|
||||
CVarSetInteger("gPrevTime", -1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Switches Link's age and respawns him at the last entrance he entered.
|
||||
void RegisterSwitchAge() {
|
||||
bool warped = false;
|
||||
Vec3f playerPos;
|
||||
int16_t playerYaw;
|
||||
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([&warped, &playerPos, &playerYaw]() {
|
||||
if (CVarGetInteger("gSwitchAge", 0) != 0) {
|
||||
CVarSetInteger("gSwitchAge", 0);
|
||||
if (gPlayState) {
|
||||
playerPos = GET_PLAYER(gPlayState)->actor.world.pos;
|
||||
playerYaw = GET_PLAYER(gPlayState)->actor.shape.rot.y;
|
||||
gPlayState->nextEntranceIndex = gSaveContext.entranceIndex;
|
||||
gPlayState->sceneLoadFlag = 0x14;
|
||||
gPlayState->fadeTransition = 11;
|
||||
gSaveContext.nextTransitionType = 11;
|
||||
warped = true;
|
||||
if (gPlayState->linkAgeOnLoad == 1) {
|
||||
gPlayState->linkAgeOnLoad = 0;
|
||||
} else {
|
||||
gPlayState->linkAgeOnLoad = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gPlayState) {
|
||||
if (warped && gPlayState->sceneLoadFlag != 0x0014 && gSaveContext.nextTransitionType == 255) {
|
||||
GET_PLAYER(gPlayState)->actor.shape.rot.y = playerYaw;
|
||||
GET_PLAYER(gPlayState)->actor.world.pos = playerPos;
|
||||
warped = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void RegisterAutoSave() {
|
||||
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnReceiveItem>([](u8 item) {
|
||||
// Don't autosave immediately after buying items from shops to prevent getting them for free!
|
||||
// Don't autosave in the Chamber of Sages since resuming from that map breaks the game
|
||||
// Don't autosave during the Ganon fight when picking up the Master Sword
|
||||
@ -99,6 +262,16 @@ void RegisterRupeeDash() {
|
||||
}
|
||||
|
||||
void InitMods() {
|
||||
RegisterInfiniteMoney();
|
||||
RegisterInfiniteHealth();
|
||||
RegisterInfiniteAmmo();
|
||||
RegisterInfiniteMagic();
|
||||
RegisterInfiniteNayrusLove();
|
||||
RegisterMoonJumpOnL();
|
||||
RegisterInfiniteISG();
|
||||
RegisterUnrestrictedItems();
|
||||
RegisterFreezeTime();
|
||||
RegisterSwitchAge();
|
||||
RegisterRupeeDash();
|
||||
RegisterAutoSaveOnReceiveItemHook();
|
||||
RegisterAutoSave();
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <string.h>
|
||||
#include "global.h"
|
||||
#include "vt.h"
|
||||
#include "soh/Enhancements/game-interactor/GameInteractor.h"
|
||||
|
||||
SpeedMeter D_801664D0;
|
||||
struct_801664F0 D_801664F0;
|
||||
@ -9,10 +10,6 @@ VisMono sMonoColors;
|
||||
ViMode sViMode;
|
||||
FaultClient sGameFaultClient;
|
||||
u16 sLastButtonPressed;
|
||||
int32_t warpTime = 0;
|
||||
bool warped = false;
|
||||
Vec3f playerPos;
|
||||
int16_t playerYaw;
|
||||
|
||||
// Forward declared, because this in a C++ header.
|
||||
int gfx_create_framebuffer(uint32_t width, uint32_t height);
|
||||
@ -328,138 +325,9 @@ void GameState_Update(GameState* gameState) {
|
||||
func_800C49F4(gfxCtx);
|
||||
}
|
||||
|
||||
// -----------------------
|
||||
// Cheats hooks
|
||||
// -----------------------
|
||||
|
||||
// Inf Money
|
||||
if (CVarGetInteger("gInfiniteMoney", 0) != 0) {
|
||||
if (gSaveContext.rupees < CUR_CAPACITY(UPG_WALLET)) {
|
||||
gSaveContext.rupees = CUR_CAPACITY(UPG_WALLET);
|
||||
}
|
||||
}
|
||||
|
||||
// Inf Health
|
||||
if (CVarGetInteger("gInfiniteHealth", 0) != 0) {
|
||||
if (gSaveContext.health < gSaveContext.healthCapacity) {
|
||||
gSaveContext.health = gSaveContext.healthCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
// Inf Ammo
|
||||
if (CVarGetInteger("gInfiniteAmmo", 0) != 0) {
|
||||
// Deku Sticks
|
||||
if (AMMO(ITEM_STICK) < CUR_CAPACITY(UPG_STICKS)) {
|
||||
AMMO(ITEM_STICK) = CUR_CAPACITY(UPG_STICKS);
|
||||
}
|
||||
|
||||
// Deku Nuts
|
||||
if (AMMO(ITEM_NUT) < CUR_CAPACITY(UPG_NUTS)) {
|
||||
AMMO(ITEM_NUT) = CUR_CAPACITY(UPG_NUTS);
|
||||
}
|
||||
|
||||
// Bombs
|
||||
if (AMMO(ITEM_BOMB) < CUR_CAPACITY(UPG_BOMB_BAG)) {
|
||||
AMMO(ITEM_BOMB) = CUR_CAPACITY(UPG_BOMB_BAG);
|
||||
}
|
||||
|
||||
// Fairy Bow (Ammo)
|
||||
if (AMMO(ITEM_BOW) < CUR_CAPACITY(UPG_QUIVER)) {
|
||||
AMMO(ITEM_BOW) = CUR_CAPACITY(UPG_QUIVER);
|
||||
}
|
||||
|
||||
// Fairy Slingshot (Ammo)
|
||||
if (AMMO(ITEM_SLINGSHOT) < CUR_CAPACITY(UPG_BULLET_BAG)) {
|
||||
AMMO(ITEM_SLINGSHOT) = CUR_CAPACITY(UPG_BULLET_BAG);
|
||||
}
|
||||
|
||||
// Bombchus (max: 50, no upgrades)
|
||||
if (INV_CONTENT(ITEM_BOMBCHU) == ITEM_BOMBCHU && AMMO(ITEM_BOMBCHU) < 50) {
|
||||
AMMO(ITEM_BOMBCHU) = 50;
|
||||
}
|
||||
}
|
||||
|
||||
// Inf Magic
|
||||
if (CVarGetInteger("gInfiniteMagic", 0) != 0) {
|
||||
if (gSaveContext.isMagicAcquired && gSaveContext.magic != (gSaveContext.isDoubleMagicAcquired + 1) * 0x30) {
|
||||
gSaveContext.magic = (gSaveContext.isDoubleMagicAcquired + 1) * 0x30;
|
||||
}
|
||||
}
|
||||
|
||||
// Inf Nayru's Love Timer
|
||||
if (CVarGetInteger("gInfiniteNayru", 0) != 0) {
|
||||
gSaveContext.nayrusLoveTimer = 0x44B;
|
||||
}
|
||||
|
||||
// Moon Jump On L
|
||||
if (CVarGetInteger("gMoonJumpOnL", 0) != 0) {
|
||||
if (gPlayState) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
|
||||
if (CHECK_BTN_ANY(gPlayState->state.input[0].cur.button, BTN_L)) {
|
||||
player->actor.velocity.y = 6.34375f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Permanent infinite sword glitch (ISG)
|
||||
if (CVarGetInteger("gEzISG", 0) != 0) {
|
||||
if (gPlayState) {
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
player->swordState = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Unrestricted Items
|
||||
if (CVarGetInteger("gNoRestrictItems", 0) != 0) {
|
||||
if (gPlayState) {
|
||||
u8 sunsBackup = gPlayState->interfaceCtx.restrictions.sunsSong;
|
||||
memset(&gPlayState->interfaceCtx.restrictions, 0, sizeof(gPlayState->interfaceCtx.restrictions));
|
||||
gPlayState->interfaceCtx.restrictions.sunsSong = sunsBackup;
|
||||
}
|
||||
}
|
||||
|
||||
// Freeze Time
|
||||
if (CVarGetInteger("gFreezeTime", 0) != 0) {
|
||||
if (CVarGetInteger("gPrevTime", -1) == -1) {
|
||||
CVarSetInteger("gPrevTime", gSaveContext.dayTime);
|
||||
}
|
||||
|
||||
int32_t prevTime = CVarGetInteger("gPrevTime", gSaveContext.dayTime);
|
||||
gSaveContext.dayTime = prevTime;
|
||||
} else {
|
||||
CVarSetInteger("gPrevTime", -1);
|
||||
}
|
||||
|
||||
//Switches Link's age and respawns him at the last entrance he entered.
|
||||
if (CVarGetInteger("gSwitchAge", 0) != 0) {
|
||||
CVarSetInteger("gSwitchAge", 0);
|
||||
if (gPlayState) {
|
||||
playerPos = GET_PLAYER(gPlayState)->actor.world.pos;
|
||||
playerYaw = GET_PLAYER(gPlayState)->actor.shape.rot.y;
|
||||
gPlayState->nextEntranceIndex = gSaveContext.entranceIndex;
|
||||
gPlayState->sceneLoadFlag = 0x14;
|
||||
gPlayState->fadeTransition = 11;
|
||||
gSaveContext.nextTransitionType = 11;
|
||||
warped = true;
|
||||
if (gPlayState->linkAgeOnLoad == 1) {
|
||||
gPlayState->linkAgeOnLoad = 0;
|
||||
} else {
|
||||
gPlayState->linkAgeOnLoad = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gPlayState) {
|
||||
if (warped && gPlayState->sceneLoadFlag != 0x0014 && gSaveContext.nextTransitionType == 255) {
|
||||
GET_PLAYER(gPlayState)->actor.shape.rot.y = playerYaw;
|
||||
GET_PLAYER(gPlayState)->actor.world.pos = playerPos;
|
||||
warped = false;
|
||||
}
|
||||
}
|
||||
|
||||
gSaveContext.language = CVarGetInteger("gLanguages", LANGUAGE_ENG);
|
||||
|
||||
GameInteractor_ExecuteOnGameFrameUpdate();
|
||||
gameState->frames++;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user