From 8934274c6734d714f0d803a298308bd92831888b Mon Sep 17 00:00:00 2001 From: David Chavez Date: Wed, 15 Feb 2023 20:30:34 +0100 Subject: [PATCH] [GameInteractor] Game Hooks (#2481) --- soh/CMakeLists.txt | 14 ++ .../game-interactor/GameInteractor.h | 27 +++ .../game-interactor/GameInteractor_Hooks.cpp | 29 +++ .../game-interactor/GameInteractor_Hooks.h | 10 + soh/soh/Enhancements/mods/modhooks.cpp | 68 +++++++ soh/soh/Enhancements/mods/modhooks.h | 5 + soh/soh/OTRGlobals.cpp | 5 +- soh/soh/SaveManager.cpp | 4 + soh/soh/z_play_otr.cpp | 3 + soh/src/code/z_parameter.c | 186 +++++++----------- 10 files changed, 230 insertions(+), 121 deletions(-) create mode 100644 soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp create mode 100644 soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h create mode 100644 soh/soh/Enhancements/mods/modhooks.cpp create mode 100644 soh/soh/Enhancements/mods/modhooks.h diff --git a/soh/CMakeLists.txt b/soh/CMakeLists.txt index 89d7da99e..036d1abd4 100644 --- a/soh/CMakeLists.txt +++ b/soh/CMakeLists.txt @@ -258,8 +258,14 @@ set(Header_Files__soh__Enhancements__item_tables source_group("Header Files\\soh\\Enhancements\\item-tables" FILES ${Header_Files__soh__Enhancements__item_tables}) +set(Header_Files__soh__Enhancements__mods + "soh/Enhancements/mods/modhooks.h" +) +source_group("Header Files\\soh\\Enhancements\\mods" FILES ${Header_Files__soh__Enhancements__mods}) + set(Header_Files__soh__Enhancements__game_interactor "soh/Enhancements/game-interactor/GameInteractor.h" + "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" "soh/Enhancements/game-interactor/GameInteractionEffect.h" ) source_group("Header Files\\soh\\Enhancements\\game-interactor" FILES ${Header_Files__soh__Enhancements__game_interactor}) @@ -609,9 +615,15 @@ set(Source_Files__soh__Enhancements__item_tables source_group("Source Files\\soh\\Enhancements\\item-tables" FILES ${Source_Files__soh__Enhancements__item_tables}) +set(Source_Files__soh__Enhancements__mods + "soh/Enhancements/mods/modhooks.cpp" +) +source_group("Source Files\\soh\\Enhancements\\mods" FILES ${Source_Files__soh__Enhancements__mods}) + set(Source_Files__soh__Enhancements__game_interactor "soh/Enhancements/game-interactor/GameInteractor.cpp" "soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp" + "soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp" "soh/Enhancements/game-interactor/GameInteractor_State.cpp" "soh/Enhancements/game-interactor/GameInteractionEffect.cpp" ) @@ -1835,6 +1847,7 @@ set(ALL_FILES ${Header_Files__soh__Enhancements__randomizer__3drando} ${Header_Files__soh__Enhancements__item_tables} ${Header_Files__soh__Enhancements__custom_message} + ${Header_Files__soh__Enhancements__mods} ${Header_Files__soh__Enhancements__game_interactor} ${Header_Files__soh__Enhancements__crowd_control} ${Source_Files__soh} @@ -1849,6 +1862,7 @@ set(ALL_FILES ${Source_Files__soh__Enhancements__randomizer__3drando__location_access} ${Source_Files__soh__Enhancements__item_tables} ${Source_Files__soh__Enhancements__custom_message} + ${Source_Files__soh__Enhancements__mods} ${Source_Files__soh__Enhancements__game_interactor} ${Source_Files__soh__Enhancements__crowd_control} ${Source_Files__src__boot} diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor.h b/soh/soh/Enhancements/game-interactor/GameInteractor.h index 5ebfc24f0..5e50ecc06 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor.h @@ -4,6 +4,7 @@ #define GameInteractor_h #include "GameInteractionEffect.h" +#include "z64.h" typedef enum { /* 0x00 */ GI_LINK_SIZE_NORMAL, @@ -39,6 +40,15 @@ GIGravityLevel GameInteractor_GravityLevel(); #ifdef __cplusplus + +#include +#include + +#define DEFINE_HOOK(name, type) \ + struct name { \ + typedef std::function fn; \ + } + class GameInteractor { public: static GameInteractor* Instance; @@ -65,6 +75,23 @@ public: static GameInteractionEffectQueryResult ApplyEffect(GameInteractionEffectBase* effect); static GameInteractionEffectQueryResult RemoveEffect(GameInteractionEffectBase* effect); + // Game Hooks + template struct RegisteredGameHooks { inline static std::vector functions; }; + template void RegisterGameHook(typename H::fn h) { RegisteredGameHooks::functions.push_back(h); } + template void ExecuteHooks(Args&&... args) { + for (auto& fn : RegisteredGameHooks::functions) { + fn(std::forward(args)...); + } + } + + DEFINE_HOOK(OnReceiveItem, void(u8 item)); + DEFINE_HOOK(OnSceneInit, void(s16 sceneNum)); + + + DEFINE_HOOK(OnSaveFile, void(int fileNum)); + DEFINE_HOOK(OnLoadFile, void(int fileNum)); + DEFINE_HOOK(OnDeleteFile, void(int fileNum)); + // Helpers static bool IsSaveLoaded(); static bool IsGameplayPaused(); diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp new file mode 100644 index 000000000..8706c0807 --- /dev/null +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp @@ -0,0 +1,29 @@ +#include "GameInteractor_Hooks.h" + +extern "C" { +extern PlayState* gPlayState; +} + +// MARK: - Gameplay + +void GameInteractor_ExecuteOnReceiveItemHooks(u8 item) { + GameInteractor::Instance->ExecuteHooks(item); +} + +void GameInteractor_ExecuteOnSceneInitHooks(s16 sceneNum) { + GameInteractor::Instance->ExecuteHooks(sceneNum); +} + +// MARK: - Save Files + +void GameInteractor_ExecuteOnSaveFile(int fileNum) { + GameInteractor::Instance->ExecuteHooks(fileNum); +} + +void GameInteractor_ExecuteOnLoadFile(int fileNum) { + GameInteractor::Instance->ExecuteHooks(fileNum); +} + +void GameInteractor_ExecuteOnDeleteFile(int fileNum) { + GameInteractor::Instance->ExecuteHooks(fileNum); +} diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h new file mode 100644 index 000000000..0eb96e579 --- /dev/null +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h @@ -0,0 +1,10 @@ +#include "GameInteractor.h" + +// MARK: - Gameplay +extern "C" void GameInteractor_ExecuteOnReceiveItemHooks(u8 item); +extern "C" void GameInteractor_ExecuteOnSceneInit(s16 sceneNum); + +// MARK: - Save Files +extern "C" void GameInteractor_ExecuteOnSaveFile(int fileNum); +extern "C" void GameInteractor_ExecuteOnLoadFile(int fileNum); +extern "C" void GameInteractor_ExecuteOnDeleteFile(int fileNum); diff --git a/soh/soh/Enhancements/mods/modhooks.cpp b/soh/soh/Enhancements/mods/modhooks.cpp new file mode 100644 index 000000000..510f09017 --- /dev/null +++ b/soh/soh/Enhancements/mods/modhooks.cpp @@ -0,0 +1,68 @@ +#include "soh/Enhancements/game-interactor/GameInteractor.h" +#include + +extern "C" { +#include +extern SaveContext gSaveContext; +extern PlayState* gPlayState; +extern void Play_PerformSave(PlayState* play); +} + +void RegisterAutoSaveOnReceiveItem() { + GameInteractor::Instance->RegisterGameHook([](u8 item) { + if (CVarGetInteger("gAutosave", 0) && (gPlayState != NULL) && (gPlayState->sceneNum != SCENE_KENJYANOMA) && (gSaveContext.pendingSale == ITEM_NONE) && (gPlayState->sceneNum != SCENE_GANON_DEMO)) { + if (CVarGetInteger("gAutosaveAllItems", 0)) { + Play_PerformSave(gPlayState); + } else if (CVarGetInteger("gAutosaveMajorItems", 1)) { + switch (item) { + case ITEM_STICK: + case ITEM_NUT: + case ITEM_BOMB: + case ITEM_BOW: + case ITEM_SEEDS: + case ITEM_FISHING_POLE: + case ITEM_MAGIC_SMALL: + case ITEM_MAGIC_LARGE: + case ITEM_INVALID_4: + case ITEM_INVALID_5: + case ITEM_INVALID_6: + case ITEM_INVALID_7: + case ITEM_HEART: + case ITEM_RUPEE_GREEN: + case ITEM_RUPEE_BLUE: + case ITEM_RUPEE_RED: + case ITEM_RUPEE_PURPLE: + case ITEM_RUPEE_GOLD: + case ITEM_INVALID_8: + case ITEM_STICKS_5: + case ITEM_STICKS_10: + case ITEM_NUTS_5: + case ITEM_NUTS_10: + case ITEM_BOMBS_5: + case ITEM_BOMBS_10: + case ITEM_BOMBS_20: + case ITEM_BOMBS_30: + case ITEM_ARROWS_SMALL: + case ITEM_ARROWS_MEDIUM: + case ITEM_ARROWS_LARGE: + case ITEM_SEEDS_30: + break; + case ITEM_BOMBCHU: + case ITEM_BOMBCHUS_5: + case ITEM_BOMBCHUS_20: + if (!CVarGetInteger("gBombchuDrops", 0)) { + Play_PerformSave(gPlayState); + } + break; + default: + Play_PerformSave(gPlayState); + break; + } + } + } + }); +} + +extern "C" void RegisterModHooks() { + RegisterAutoSaveOnReceiveItem(); +} diff --git a/soh/soh/Enhancements/mods/modhooks.h b/soh/soh/Enhancements/mods/modhooks.h new file mode 100644 index 000000000..96b0da8e6 --- /dev/null +++ b/soh/soh/Enhancements/mods/modhooks.h @@ -0,0 +1,5 @@ +#ifdef __cplusplus +extern "C" { + void RegisterModHooks(void); +} +#endif diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index c81be9a98..6dfa5290a 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -73,8 +73,9 @@ CrowdControl* CrowdControl::Instance; #endif +#include "Enhancements/mods/modhooks.h" #include "Enhancements/game-interactor/GameInteractor.h" -#include "libultraship/libultraship.h" +#include // Resource Types/Factories #include "soh/resource/type/Animation.h" @@ -584,6 +585,8 @@ extern "C" void InitOTR() { OTRExtScanner(); VanillaItemTable_Init(); + RegisterModHooks(); + time_t now = time(NULL); tm *tm_now = localtime(&now); if (tm_now->tm_mon == 11 && tm_now->tm_mday >= 24 && tm_now->tm_mday <= 25) { diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 611abb667..6a816cf92 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -1,5 +1,6 @@ #include "SaveManager.h" #include "OTRGlobals.h" +#include "Enhancements/game-interactor/GameInteractor.h" #include "z64.h" #include "functions.h" @@ -693,6 +694,7 @@ void SaveManager::SaveFile(int fileNum) { #endif InitMeta(fileNum); + GameInteractor::Instance->ExecuteHooks(fileNum); } void SaveManager::SaveGlobal() { @@ -754,6 +756,7 @@ void SaveManager::LoadFile(int fileNum) { break; } InitMeta(fileNum); + GameInteractor::Instance->ExecuteHooks(fileNum); } bool SaveManager::SaveFile_Exist(int fileNum) { @@ -1680,6 +1683,7 @@ void SaveManager::DeleteZeldaFile(int fileNum) { } fileMetaInfo[fileNum].valid = false; fileMetaInfo[fileNum].randoSave = false; + GameInteractor::Instance->ExecuteHooks(fileNum); } bool SaveManager::IsRandoFile() { diff --git a/soh/soh/z_play_otr.cpp b/soh/soh/z_play_otr.cpp index d79111777..b178cbf49 100644 --- a/soh/soh/z_play_otr.cpp +++ b/soh/soh/z_play_otr.cpp @@ -2,6 +2,7 @@ #include #include "soh/resource/type/Scene.h" #include +#include "soh/Enhancements/game-interactor/GameInteractor.h" #include "global.h" #include "vt.h" #include @@ -81,6 +82,8 @@ void OTRPlay_InitScene(PlayState* play, s32 spawn) { .get()); auto data2 = ResourceMgr_LoadVtxByCRC(0x68d4ea06044e228f);*/ + + GameInteractor::Instance->ExecuteHooks(play->sceneNum); volatile int a = 0; } diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 167716ccd..a694781ad 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1738,7 +1738,7 @@ u8 Item_Give(PlayState* play, u8 item) { func_8006D0AC(play); } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if ((item >= ITEM_SONG_MINUET) && (item <= ITEM_SONG_STORMS)) { gSaveContext.inventory.questItems |= gBitFlags[item - ITEM_SONG_MINUET + QUEST_SONG_MINUET]; @@ -1750,7 +1750,7 @@ u8 Item_Give(PlayState* play, u8 item) { gBitFlags[item - ITEM_SONG_MINUET + QUEST_SONG_MINUET], gBitFlags[item - ITEM_SONG_MINUET]); osSyncPrintf(VT_RST); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if ((item >= ITEM_KOKIRI_EMERALD) && (item <= ITEM_ZORA_SAPPHIRE)) { gSaveContext.inventory.questItems |= gBitFlags[item - ITEM_KOKIRI_EMERALD + QUEST_KOKIRI_EMERALD]; @@ -1759,7 +1759,7 @@ u8 Item_Give(PlayState* play, u8 item) { osSyncPrintf("精霊石 = %x\n", gSaveContext.inventory.questItems); // "Spiritual Stones = %x" osSyncPrintf(VT_RST); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if ((item == ITEM_STONE_OF_AGONY) || (item == ITEM_GERUDO_CARD)) { gSaveContext.inventory.questItems |= gBitFlags[item - ITEM_STONE_OF_AGONY + QUEST_STONE_OF_AGONY]; @@ -1768,7 +1768,7 @@ u8 Item_Give(PlayState* play, u8 item) { osSyncPrintf("アイテム = %x\n", gSaveContext.inventory.questItems); // "Items = %x" osSyncPrintf(VT_RST); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_SKULL_TOKEN) { gSaveContext.inventory.questItems |= gBitFlags[item - ITEM_SKULL_TOKEN + QUEST_SKULL_TOKEN]; @@ -1779,7 +1779,7 @@ u8 Item_Give(PlayState* play, u8 item) { osSyncPrintf("Nコイン = %x(%d)\n", gSaveContext.inventory.questItems, gSaveContext.inventory.gsTokens); osSyncPrintf(VT_RST); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if ((item >= ITEM_SWORD_KOKIRI) && (item <= ITEM_SWORD_BGS)) { gSaveContext.inventory.equipment |= gBitFlags[item - ITEM_SWORD_KOKIRI] << gEquipShifts[EQUIP_SWORD]; @@ -1811,19 +1811,19 @@ u8 Item_Give(PlayState* play, u8 item) { } } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if ((item >= ITEM_SHIELD_DEKU) && (item <= ITEM_SHIELD_MIRROR)) { gSaveContext.inventory.equipment |= (gBitFlags[item - ITEM_SHIELD_DEKU] << gEquipShifts[EQUIP_SHIELD]); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if ((item >= ITEM_TUNIC_KOKIRI) && (item <= ITEM_TUNIC_ZORA)) { gSaveContext.inventory.equipment |= (gBitFlags[item - ITEM_TUNIC_KOKIRI] << gEquipShifts[EQUIP_TUNIC]); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if ((item >= ITEM_BOOTS_KOKIRI) && (item <= ITEM_BOOTS_HOVER)) { gSaveContext.inventory.equipment |= (gBitFlags[item - ITEM_BOOTS_KOKIRI] << gEquipShifts[EQUIP_BOOTS]); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if ((item == ITEM_KEY_BOSS) || (item == ITEM_COMPASS) || (item == ITEM_DUNGEON_MAP)) { // Boss Key, Compass, and Dungeon Map exceptions for rando. @@ -1840,7 +1840,7 @@ u8 Item_Give(PlayState* play, u8 item) { } else { gSaveContext.inventory.dungeonItems[gSaveContext.mapIndex] |= gBitFlags[item - ITEM_KEY_BOSS]; } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_KEY_SMALL) { // Small key exceptions for rando with keysanity off. @@ -1851,11 +1851,11 @@ u8 Item_Give(PlayState* play, u8 item) { gSaveContext.sohStats.dungeonKeys[13]++; if (gSaveContext.inventory.dungeonKeys[13] < 0) { gSaveContext.inventory.dungeonKeys[13] = 1; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else { gSaveContext.inventory.dungeonKeys[13]++; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } } @@ -1864,11 +1864,11 @@ u8 Item_Give(PlayState* play, u8 item) { gSaveContext.sohStats.dungeonKeys[6]++; if (gSaveContext.inventory.dungeonKeys[6] < 0) { gSaveContext.inventory.dungeonKeys[6] = 1; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else { gSaveContext.inventory.dungeonKeys[6]++; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } } @@ -1876,11 +1876,11 @@ u8 Item_Give(PlayState* play, u8 item) { gSaveContext.sohStats.dungeonKeys[gSaveContext.mapIndex]++; if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] < 0) { gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = 1; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else { gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex]++; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } } else if ((item == ITEM_QUIVER_30) || (item == ITEM_BOW)) { @@ -1888,7 +1888,7 @@ u8 Item_Give(PlayState* play, u8 item) { Inventory_ChangeUpgrade(UPG_QUIVER, 1); INV_CONTENT(ITEM_BOW) = ITEM_BOW; AMMO(ITEM_BOW) = CAPACITY(UPG_QUIVER, 1); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else { AMMO(ITEM_BOW)++; @@ -1899,29 +1899,29 @@ u8 Item_Give(PlayState* play, u8 item) { } else if (item == ITEM_QUIVER_40) { Inventory_ChangeUpgrade(UPG_QUIVER, 2); AMMO(ITEM_BOW) = CAPACITY(UPG_QUIVER, 2); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_QUIVER_50) { Inventory_ChangeUpgrade(UPG_QUIVER, 3); AMMO(ITEM_BOW) = CAPACITY(UPG_QUIVER, 3); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_BULLET_BAG_40) { Inventory_ChangeUpgrade(UPG_BULLET_BAG, 2); AMMO(ITEM_SLINGSHOT) = CAPACITY(UPG_BULLET_BAG, 2); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_BULLET_BAG_50) { Inventory_ChangeUpgrade(UPG_BULLET_BAG, 3); AMMO(ITEM_SLINGSHOT) = CAPACITY(UPG_BULLET_BAG, 3); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_BOMB_BAG_20) { if (CUR_UPG_VALUE(UPG_BOMB_BAG) == 0) { Inventory_ChangeUpgrade(UPG_BOMB_BAG, 1); INV_CONTENT(ITEM_BOMB) = ITEM_BOMB; AMMO(ITEM_BOMB) = CAPACITY(UPG_BOMB_BAG, 1); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else { AMMO(ITEM_BOMB)++; @@ -1932,46 +1932,46 @@ u8 Item_Give(PlayState* play, u8 item) { } else if (item == ITEM_BOMB_BAG_30) { Inventory_ChangeUpgrade(UPG_BOMB_BAG, 2); AMMO(ITEM_BOMB) = CAPACITY(UPG_BOMB_BAG, 2); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_BOMB_BAG_40) { Inventory_ChangeUpgrade(UPG_BOMB_BAG, 3); AMMO(ITEM_BOMB) = CAPACITY(UPG_BOMB_BAG, 3); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_BRACELET) { Inventory_ChangeUpgrade(UPG_STRENGTH, 1); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_GAUNTLETS_SILVER) { Inventory_ChangeUpgrade(UPG_STRENGTH, 2); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_GAUNTLETS_GOLD) { Inventory_ChangeUpgrade(UPG_STRENGTH, 3); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_SCALE_SILVER) { Inventory_ChangeUpgrade(UPG_SCALE, 1); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_SCALE_GOLDEN) { Inventory_ChangeUpgrade(UPG_SCALE, 2); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_WALLET_ADULT) { Inventory_ChangeUpgrade(UPG_WALLET, 1); if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_FULL_WALLETS)) { Rupees_ChangeBy(200); } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_WALLET_GIANT) { Inventory_ChangeUpgrade(UPG_WALLET, 2); if (gSaveContext.n64ddFlag && Randomizer_GetSettingValue(RSK_FULL_WALLETS)) { Rupees_ChangeBy(500); } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_STICK_UPGRADE_20) { if (gSaveContext.inventory.items[slot] == ITEM_NONE) { @@ -1979,7 +1979,7 @@ u8 Item_Give(PlayState* play, u8 item) { } Inventory_ChangeUpgrade(UPG_STICKS, 2); AMMO(ITEM_STICK) = CAPACITY(UPG_STICKS, 2); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_STICK_UPGRADE_30) { if (gSaveContext.inventory.items[slot] == ITEM_NONE) { @@ -1987,7 +1987,7 @@ u8 Item_Give(PlayState* play, u8 item) { } Inventory_ChangeUpgrade(UPG_STICKS, 3); AMMO(ITEM_STICK) = CAPACITY(UPG_STICKS, 3); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_NUT_UPGRADE_30) { if (gSaveContext.inventory.items[slot] == ITEM_NONE) { @@ -1995,7 +1995,7 @@ u8 Item_Give(PlayState* play, u8 item) { } Inventory_ChangeUpgrade(UPG_NUTS, 2); AMMO(ITEM_NUT) = CAPACITY(UPG_NUTS, 2); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_NUT_UPGRADE_40) { if (gSaveContext.inventory.items[slot] == ITEM_NONE) { @@ -2003,7 +2003,7 @@ u8 Item_Give(PlayState* play, u8 item) { } Inventory_ChangeUpgrade(UPG_NUTS, 3); AMMO(ITEM_NUT) = CAPACITY(UPG_NUTS, 3); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_LONGSHOT) { INV_CONTENT(item) = item; @@ -2037,7 +2037,7 @@ u8 Item_Give(PlayState* play, u8 item) { } } } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_STICK) { if (gSaveContext.inventory.items[slot] == ITEM_NONE) { @@ -2090,40 +2090,40 @@ u8 Item_Give(PlayState* play, u8 item) { if ((AMMO(ITEM_BOMB) += 1) > CUR_CAPACITY(UPG_BOMB_BAG)) { AMMO(ITEM_BOMB) = CUR_CAPACITY(UPG_BOMB_BAG); } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if ((item >= ITEM_BOMBS_5) && (item <= ITEM_BOMBS_30)) { if ((AMMO(ITEM_BOMB) += sAmmoRefillCounts[item - ITEM_BOMBS_5]) > CUR_CAPACITY(UPG_BOMB_BAG)) { AMMO(ITEM_BOMB) = CUR_CAPACITY(UPG_BOMB_BAG); } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_BOMBCHU) { if (gSaveContext.inventory.items[slot] == ITEM_NONE) { INV_CONTENT(ITEM_BOMBCHU) = ITEM_BOMBCHU; AMMO(ITEM_BOMBCHU) = 10; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else { AMMO(ITEM_BOMBCHU) += 10; if (AMMO(ITEM_BOMBCHU) > 50) { AMMO(ITEM_BOMBCHU) = 50; } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } } else if ((item == ITEM_BOMBCHUS_5) || (item == ITEM_BOMBCHUS_20)) { if (gSaveContext.inventory.items[slot] == ITEM_NONE) { INV_CONTENT(ITEM_BOMBCHU) = ITEM_BOMBCHU; AMMO(ITEM_BOMBCHU) += sAmmoRefillCounts[item - ITEM_BOMBCHUS_5 + 8]; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else { AMMO(ITEM_BOMBCHU) += sAmmoRefillCounts[item - ITEM_BOMBCHUS_5 + 8]; if (AMMO(ITEM_BOMBCHU) > 50) { AMMO(ITEM_BOMBCHU) = 50; } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } } else if ((item >= ITEM_ARROWS_SMALL) && (item <= ITEM_ARROWS_LARGE)) { @@ -2135,13 +2135,13 @@ u8 Item_Give(PlayState* play, u8 item) { osSyncPrintf("%d本 Item_MaxGet=%d\n", AMMO(ITEM_BOW), CUR_CAPACITY(UPG_QUIVER)); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_BOW; } else if (item == ITEM_SLINGSHOT) { Inventory_ChangeUpgrade(UPG_BULLET_BAG, 1); INV_CONTENT(ITEM_SLINGSHOT) = ITEM_SLINGSHOT; AMMO(ITEM_SLINGSHOT) = 30; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_SEEDS) { AMMO(ITEM_SLINGSHOT) += 5; @@ -2152,11 +2152,11 @@ u8 Item_Give(PlayState* play, u8 item) { if (!(gSaveContext.itemGetInf[1] & 8)) { gSaveContext.itemGetInf[1] |= 8; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_SEEDS; } else if (item == ITEM_SEEDS_30) { AMMO(ITEM_SLINGSHOT) += 30; @@ -2167,15 +2167,15 @@ u8 Item_Give(PlayState* play, u8 item) { if (!(gSaveContext.itemGetInf[1] & 8)) { gSaveContext.itemGetInf[1] |= 8; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_SEEDS; } else if (item == ITEM_OCARINA_FAIRY) { INV_CONTENT(ITEM_OCARINA_FAIRY) = ITEM_OCARINA_FAIRY; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_OCARINA_TIME) { INV_CONTENT(ITEM_OCARINA_TIME) = ITEM_OCARINA_TIME; @@ -2208,7 +2208,7 @@ u8 Item_Give(PlayState* play, u8 item) { } } } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_BEAN) { if (gSaveContext.inventory.items[slot] == ITEM_NONE) { @@ -2219,25 +2219,25 @@ u8 Item_Give(PlayState* play, u8 item) { AMMO(ITEM_BEAN)++; BEANS_BOUGHT++; } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if ((item == ITEM_HEART_PIECE_2) || (item == ITEM_HEART_PIECE)) { gSaveContext.inventory.questItems += 1 << (QUEST_HEART_PIECE + 4); gSaveContext.sohStats.heartPieces++; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_HEART_CONTAINER) { gSaveContext.healthCapacity += 0x10; gSaveContext.health += 0x10; gSaveContext.sohStats.heartContainers++; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_HEART) { osSyncPrintf("回復ハート回復ハート回復ハート\n"); // "Recovery Heart" if (play != NULL) { Health_ChangeBy(play, 0x10); } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return item; } else if (item == ITEM_MAGIC_SMALL) { if (gSaveContext.magicState != 10) { @@ -2252,11 +2252,11 @@ u8 Item_Give(PlayState* play, u8 item) { if (!(gSaveContext.infTable[25] & 0x100)) { gSaveContext.infTable[25] |= 0x100; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return item; } else if (item == ITEM_MAGIC_LARGE) { if (gSaveContext.magicState != 10) { @@ -2270,15 +2270,15 @@ u8 Item_Give(PlayState* play, u8 item) { if (!(gSaveContext.infTable[25] & 0x100)) { gSaveContext.infTable[25] |= 0x100; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return item; } else if ((item >= ITEM_RUPEE_GREEN) && (item <= ITEM_INVALID_8)) { Rupees_ChangeBy(sAmmoRefillCounts[item - ITEM_RUPEE_GREEN + 10]); - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } else if (item == ITEM_BOTTLE) { temp = SLOT(item); @@ -2286,7 +2286,7 @@ u8 Item_Give(PlayState* play, u8 item) { for (i = 0; i < 4; i++) { if (gSaveContext.inventory.items[temp + i] == ITEM_NONE) { gSaveContext.inventory.items[temp + i] = item; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } } @@ -2318,7 +2318,7 @@ u8 Item_Give(PlayState* play, u8 item) { } gSaveContext.inventory.items[temp + i] = item; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } } @@ -2326,7 +2326,7 @@ u8 Item_Give(PlayState* play, u8 item) { for (i = 0; i < 4; i++) { if (gSaveContext.inventory.items[temp + i] == ITEM_NONE) { gSaveContext.inventory.items[temp + i] = item; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } } @@ -2354,13 +2354,13 @@ u8 Item_Give(PlayState* play, u8 item) { } else { gSaveContext.equips.buttonItems[i] = ITEM_NONE; } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } } } - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return ITEM_NONE; } @@ -2368,7 +2368,7 @@ u8 Item_Give(PlayState* play, u8 item) { osSyncPrintf("Item_Register(%d)=%d %d\n", slot, item, temp); INV_CONTENT(item) = item; - PerformAutosave(play, item); + GameInteractor_ExecuteOnReceiveItemHooks(item); return temp; } @@ -2721,60 +2721,6 @@ u8 Item_CheckObtainability(u8 item) { return gSaveContext.inventory.items[slot]; } -// Save when receiving an item, unless it's purchased from a shop -void PerformAutosave(PlayState* play, u8 item) { - if (CVarGetInteger("gAutosave", 0) && (play != NULL) && (play->sceneNum != SCENE_KENJYANOMA) && (gSaveContext.pendingSale == ITEM_NONE) && (play->sceneNum != SCENE_GANON_DEMO)) { - if (CVarGetInteger("gAutosaveAllItems", 0)) { - Play_PerformSave(play); - } else if (CVarGetInteger("gAutosaveMajorItems", 1)) { - switch (item) { - case ITEM_STICK: - case ITEM_NUT: - case ITEM_BOMB: - case ITEM_BOW: - case ITEM_SEEDS: - case ITEM_FISHING_POLE: - case ITEM_MAGIC_SMALL: - case ITEM_MAGIC_LARGE: - case ITEM_INVALID_4: - case ITEM_INVALID_5: - case ITEM_INVALID_6: - case ITEM_INVALID_7: - case ITEM_HEART: - case ITEM_RUPEE_GREEN: - case ITEM_RUPEE_BLUE: - case ITEM_RUPEE_RED: - case ITEM_RUPEE_PURPLE: - case ITEM_RUPEE_GOLD: - case ITEM_INVALID_8: - case ITEM_STICKS_5: - case ITEM_STICKS_10: - case ITEM_NUTS_5: - case ITEM_NUTS_10: - case ITEM_BOMBS_5: - case ITEM_BOMBS_10: - case ITEM_BOMBS_20: - case ITEM_BOMBS_30: - case ITEM_ARROWS_SMALL: - case ITEM_ARROWS_MEDIUM: - case ITEM_ARROWS_LARGE: - case ITEM_SEEDS_30: - break; - case ITEM_BOMBCHU: - case ITEM_BOMBCHUS_5: - case ITEM_BOMBCHUS_20: - if (!CVarGetInteger("gBombchuDrops", 0)) { - Play_PerformSave(play); - } - break; - default: - Play_PerformSave(play); - break; - } - } - } -} - void Inventory_DeleteItem(u16 item, u16 invSlot) { s16 i; @@ -6300,7 +6246,7 @@ void Interface_Update(PlayState* play) { if (gSaveContext.rupeeAccumulator == 0) { u16 tempSaleItem = gSaveContext.pendingSale; gSaveContext.pendingSale = ITEM_NONE; - PerformAutosave(play, tempSaleItem); + GameInteractor_ExecuteOnReceiveItemHooks(tempSaleItem); } } else { gSaveContext.rupeeAccumulator = 0;