#include "DeveloperTools.h" #include "BenPort.h" #include "public/bridge/consolevariablebridge.h" #include "2s2h/GameInteractor/GameInteractor.h" #include "2s2h/ShipInit.hpp" extern "C" { #include "macros.h" #include "z64actor.h" #include "z64save.h" #include "variables.h" #include "overlays/kaleido_scope/ovl_kaleido_scope/z_kaleido_scope.h" void Sram_InitDebugSave(void); void Flags_SetWeekEventReg(s32 flag); void Inventory_ChangeUpgrade(s16 upgrade, u32 value); void Inventory_SetWorldMapCloudVisibility(s16 tingleIndex); extern u16 sPersistentCycleWeekEventRegs[ARRAY_COUNT(gSaveContext.save.saveInfo.weekEventReg)]; } #define CVAR_DEBUG_MODE_NAME "gDeveloperTools.DebugEnabled" #define CVAR_DEBUG_MODE CVarGetInteger(CVAR_DEBUG_MODE_NAME, 0) #define CVAR_SAVE_FILE_MODE_NAME "gDeveloperTools.DebugSaveFileMode" #define CVAR_SAVE_FILE_MODE CVarGetInteger(CVAR_SAVE_FILE_MODE_NAME, DEBUG_SAVE_INFO_NONE) void SetSaveFileInfo() { u8 playerName[8]; // Copy player name and set back after debug save init memcpy(playerName, gSaveContext.save.saveInfo.playerData.playerName, sizeof(playerName)); Sram_InitDebugSave(); memcpy(gSaveContext.save.saveInfo.playerData.playerName, playerName, sizeof(playerName)); // Place link at entrance from clock tower gSaveContext.save.entrance = ENTRANCE(SOUTH_CLOCK_TOWN, 0); gSaveContext.save.cutsceneIndex = 0; gSaveContext.save.saveInfo.checksum = 1; // Prevent first Song of Time reset from forcing Deku Link and having to learn Song of Healing gSaveContext.save.saveInfo.playerData.threeDayResetCount = 1; if (CVAR_SAVE_FILE_MODE == DEBUG_SAVE_INFO_COMPLETE) { gSaveContext.save.saveInfo.playerData.doubleDefense = true; gSaveContext.save.saveInfo.playerData.health = 20 * 0x10; gSaveContext.save.saveInfo.playerData.healthCapacity = 20 * 0x10; gSaveContext.save.saveInfo.playerData.isDoubleMagicAcquired = true; gSaveContext.save.saveInfo.playerData.magicLevel = 2; gSaveContext.save.saveInfo.playerData.magic = MAGIC_DOUBLE_METER; gSaveContext.save.saveInfo.playerData.owlActivationFlags = (1 << (OWL_WARP_STONE_TOWER + 1)) - 1; gSaveContext.save.saveInfo.playerData.unk_20 = OWL_WARP_CLOCK_TOWN; gSaveContext.save.saveInfo.inventory.defenseHearts = 20; gSaveContext.save.saveInfo.regionsVisited = (1 << REGION_MAX) - 1; gSaveContext.magicCapacity = MAGIC_DOUBLE_METER; Inventory_ChangeUpgrade(UPG_WALLET, 2); Inventory_ChangeUpgrade(UPG_BOMB_BAG, 3); Inventory_ChangeUpgrade(UPG_QUIVER, 3); for (int32_t i = 0; i < TINGLE_MAP_MAX; i++) { Inventory_SetWorldMapCloudVisibility(i); } gSaveContext.save.saveInfo.playerData.rupees = CUR_CAPACITY(UPG_WALLET); AMMO(ITEM_BOW) = CUR_CAPACITY(UPG_QUIVER); AMMO(ITEM_BOMB) = AMMO(ITEM_BOMBCHU) = CUR_CAPACITY(UPG_BOMB_BAG); AMMO(ITEM_DEKU_STICK) = CUR_CAPACITY(UPG_DEKU_STICKS); AMMO(ITEM_DEKU_NUT) = CUR_CAPACITY(UPG_DEKU_NUTS); AMMO(ITEM_MAGIC_BEANS) = 20; AMMO(ITEM_POWDER_KEG) = 1; SET_EQUIP_VALUE(EQUIP_TYPE_SHIELD, EQUIP_VALUE_SHIELD_MIRROR); SET_EQUIP_VALUE(EQUIP_TYPE_SWORD, EQUIP_VALUE_SWORD_GILDED); BUTTON_ITEM_EQUIP(0, EQUIP_SLOT_B) = ITEM_SWORD_GILDED; for (int32_t i = SLOT_BOTTLE_1; i <= SLOT_BOTTLE_6; i++) { if (gSaveContext.save.saveInfo.inventory.items[i] == ITEM_NONE) { gSaveContext.save.saveInfo.inventory.items[i] = ITEM_BOTTLE; } } for (int32_t i = QUEST_REMAINS_ODOLWA; i <= QUEST_BOMBERS_NOTEBOOK; i++) { if (i != QUEST_SHIELD && i != QUEST_SWORD && i != QUEST_SONG_SARIA && i != QUEST_SONG_SUN) { SET_QUEST_ITEM(i); } } // Use the persistent cycle events to set what a 100% save would normally keep for (int32_t i = 0; i < ARRAY_COUNT(sPersistentCycleWeekEventRegs); i++) { u16 isPersistentBits = sPersistentCycleWeekEventRegs[i]; // Force all bits on gSaveContext.save.saveInfo.weekEventReg[i] = 0xFF; // Then unset any bits that aren't persistent for (int32_t j = 0; j < 8; j++) { if (!(isPersistentBits & 3)) { gSaveContext.save.saveInfo.weekEventReg[i] = gSaveContext.save.saveInfo.weekEventReg[i] & (0xFF ^ (1 << j)); } isPersistentBits >>= 2; } } } } void RegisterDebugSaveCreate() { COND_HOOK(OnSaveInit, CVAR_SAVE_FILE_MODE != DEBUG_SAVE_INFO_NONE && CVAR_DEBUG_MODE, [](s16 fileNum) { SetSaveFileInfo(); }); } #define CVAR_PREVENT_ACTOR_UPDATE_NAME "gDeveloperTools.PreventActorUpdate" #define CVAR_PREVENT_ACTOR_UPDATE CVarGetInteger(CVAR_PREVENT_ACTOR_UPDATE_NAME, 0) void RegisterPreventActorUpdateHooks() { COND_HOOK(ShouldActorUpdate, CVAR_PREVENT_ACTOR_UPDATE && CVAR_DEBUG_MODE, [](Actor* actor, bool* result) { *result = false; }); } #define CVAR_PREVENT_ACTOR_DRAW_NAME "gDeveloperTools.PreventActorDraw" #define CVAR_PREVENT_ACTOR_DRAW CVarGetInteger(CVAR_PREVENT_ACTOR_DRAW_NAME, 0) void RegisterPreventActorDrawHooks() { COND_HOOK(ShouldActorDraw, CVAR_PREVENT_ACTOR_DRAW && CVAR_DEBUG_MODE, [](Actor* actor, bool* result) { *result = false; }); } #define CVAR_PREVENT_ACTOR_INIT_NAME "gDeveloperTools.PreventActorInit" #define CVAR_PREVENT_ACTOR_INIT CVarGetInteger(CVAR_PREVENT_ACTOR_INIT_NAME, 0) void RegisterPreventActorInitHooks() { static HOOK_ID hookId = 0; if (hookId != 0) { GameInteractor::Instance->UnregisterGameHookForFilter(hookId); hookId = 0; } if (CVAR_PREVENT_ACTOR_INIT && CVAR_DEBUG_MODE) { hookId = GameInteractor::Instance->RegisterGameHookForFilter( GameInteractor::HookFilter::SActorNotPlayer, [](Actor* actor, bool* result) { *result = false; }); } } void RegisterDebugMode() { // Disable various debug options when toggled off if (!CVAR_DEBUG_MODE) { CVarSetInteger(CVAR_SAVE_FILE_MODE_NAME, DEBUG_SAVE_INFO_NONE); CVarSetInteger(CVAR_PREVENT_ACTOR_UPDATE_NAME, 0); CVarSetInteger(CVAR_PREVENT_ACTOR_DRAW_NAME, 0); CVarSetInteger(CVAR_PREVENT_ACTOR_INIT_NAME, 0); CVarSetInteger("gDeveloperTools.DisableObjectDependency", 0); if (gPlayState != NULL) { gPlayState->frameAdvCtx.enabled = false; } } } RegisterShipInitFunc initFuncDebugMode(RegisterDebugMode, { CVAR_DEBUG_MODE_NAME }); RegisterShipInitFunc initFuncSaveFile(RegisterDebugSaveCreate, { CVAR_SAVE_FILE_MODE_NAME, CVAR_DEBUG_MODE_NAME }); RegisterShipInitFunc initFuncActorUpdate(RegisterPreventActorUpdateHooks, { CVAR_PREVENT_ACTOR_UPDATE_NAME, CVAR_DEBUG_MODE_NAME }); RegisterShipInitFunc initFuncActorDraw(RegisterPreventActorDrawHooks, { CVAR_PREVENT_ACTOR_DRAW_NAME, CVAR_DEBUG_MODE_NAME }); RegisterShipInitFunc initFuncActorInit(RegisterPreventActorInitHooks, { CVAR_PREVENT_ACTOR_INIT_NAME, CVAR_DEBUG_MODE_NAME });