From 04d0cd8532c70143511fd09cfca8a1091cc31d4b Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sun, 2 Apr 2023 01:47:23 -0700 Subject: [PATCH] Adds `OnTransitionEnd` hook to `GameInteractor`, called at the end of a transition after all mid-transition setup is called. (#2635) Transitions final autosave location to `OnTransitionEnd`. Adds functionality to autosave to set a delayed save flag if AutoSave is set to Major or All Items and one is obtained in a grotto, to avoid grotto autosaving but still provide for the autosave when location-based saving is off. Fixes small bug with item lookup where sometimes an item's `modIndex` would sometimes be reported one way, but the way Randomizer does things it would be in a the other `modIndex`, and the lookup would fail. Minor variable name clarification in ItemTableManager. Modifies AutoSave to account for item ID overlap from `MOD_RANDOMIZER` table (all items in the randomizer table is considered major for AutoSave purposes except ice traps). --- .../game-interactor/GameInteractor.h | 1 + .../game-interactor/GameInteractor_Hooks.cpp | 4 + .../game-interactor/GameInteractor_Hooks.h | 1 + .../item-tables/ItemTableManager.cpp | 4 +- .../item-tables/ItemTableManager.h | 2 +- soh/soh/Enhancements/mods.cpp | 124 +++++++++------- soh/soh/OTRGlobals.cpp | 132 ++++++++++++++++++ soh/soh/OTRGlobals.h | 2 + soh/src/code/z_parameter.c | 26 ++-- soh/src/code/z_play.c | 11 +- 10 files changed, 237 insertions(+), 70 deletions(-) diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor.h b/soh/soh/Enhancements/game-interactor/GameInteractor.h index 1489c1d8f..f0ab0363b 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor.h @@ -146,6 +146,7 @@ public: DEFINE_HOOK(OnGameFrameUpdate, void()); DEFINE_HOOK(OnItemReceive, void(GetItemEntry itemEntry)); DEFINE_HOOK(OnSaleEnd, void(GetItemEntry itemEntry)); + DEFINE_HOOK(OnTransitionEnd, void(int16_t sceneNum)); DEFINE_HOOK(OnSceneInit, void(int16_t sceneNum)); DEFINE_HOOK(OnPlayerUpdate, void()); DEFINE_HOOK(OnActorUpdate, void(void* actor)); diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp index 09153f5ed..7bc85e017 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.cpp @@ -22,6 +22,10 @@ void GameInteractor_ExecuteOnSaleEndHooks(GetItemEntry itemEntry) { GameInteractor::Instance->ExecuteHooks(itemEntry); } +void GameInteractor_ExecuteOnTransitionEndHooks(int16_t sceneNum) { + GameInteractor::Instance->ExecuteHooks(sceneNum); +} + void GameInteractor_ExecuteOnSceneInitHooks(int16_t sceneNum) { GameInteractor::Instance->ExecuteHooks(sceneNum); } diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h index 6449c3613..6c0a003b1 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_Hooks.h @@ -6,6 +6,7 @@ extern "C" void GameInteractor_ExecuteOnExitGame(int32_t fileNum); extern "C" void GameInteractor_ExecuteOnGameFrameUpdate(); extern "C" void GameInteractor_ExecuteOnItemReceiveHooks(GetItemEntry itemEntry); extern "C" void GameInteractor_ExecuteOnSaleEndHooks(GetItemEntry itemEntry); +extern "C" void GameInteractor_ExecuteOnTransitionEndHooks(int16_t sceneNum); extern "C" void GameInteractor_ExecuteOnSceneInit(int16_t sceneNum); extern "C" void GameInteractor_ExecuteOnPlayerUpdate(); extern "C" void GameInteractor_ExecuteOnActorUpdate(void* actor); diff --git a/soh/soh/Enhancements/item-tables/ItemTableManager.cpp b/soh/soh/Enhancements/item-tables/ItemTableManager.cpp index 69ac56553..a98a6bddc 100644 --- a/soh/soh/Enhancements/item-tables/ItemTableManager.cpp +++ b/soh/soh/Enhancements/item-tables/ItemTableManager.cpp @@ -20,10 +20,10 @@ bool ItemTableManager::AddItemEntry(uint16_t tableID, uint16_t getItemID, GetIte } catch (const std::out_of_range& oor) { return false; } } -GetItemEntry ItemTableManager::RetrieveItemEntry(uint16_t tableID, uint16_t itemID) { +GetItemEntry ItemTableManager::RetrieveItemEntry(uint16_t tableID, uint16_t getItemID) { try { ItemTable* itemTable = RetrieveItemTable(tableID); - GetItemEntry getItemEntry = itemTable->at(itemID); + GetItemEntry getItemEntry = itemTable->at(getItemID); getItemEntry.drawItemId = getItemEntry.itemId; getItemEntry.drawModIndex = getItemEntry.modIndex; return getItemEntry; diff --git a/soh/soh/Enhancements/item-tables/ItemTableManager.h b/soh/soh/Enhancements/item-tables/ItemTableManager.h index 622782265..e20632f38 100644 --- a/soh/soh/Enhancements/item-tables/ItemTableManager.h +++ b/soh/soh/Enhancements/item-tables/ItemTableManager.h @@ -13,7 +13,7 @@ class ItemTableManager { ~ItemTableManager(); bool AddItemTable(uint16_t tableID); bool AddItemEntry(uint16_t tableID, uint16_t getItemID, GetItemEntry getItemEntry); - GetItemEntry RetrieveItemEntry(uint16_t tableID, uint16_t itemID); + GetItemEntry RetrieveItemEntry(uint16_t tableID, uint16_t getItemID); bool ClearItemTable(uint16_t tableID); private: diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index 917c6b495..6dc595f00 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -11,6 +11,8 @@ extern "C" { extern SaveContext gSaveContext; extern PlayState* gPlayState; } +bool performDelayedSave = false; +bool performSave = false; void RegisterInfiniteMoney() { GameInteractor::Instance->RegisterGameHook([]() { @@ -177,60 +179,81 @@ void AutoSave(GetItemEntry itemEntry) { // Don't autosave during the Ganon fight when picking up the Master Sword // Don't autosave in grottos since resuming from grottos breaks the game. if ((CVarGetInteger("gAutosave", 0) > 0) && (gPlayState != NULL) && (gSaveContext.pendingSale == ITEM_NONE) && - (gPlayState->sceneNum != SCENE_YOUSEI_IZUMI_TATE) && (gPlayState->sceneNum != SCENE_KAKUSIANA) && - (gPlayState->sceneNum != SCENE_KENJYANOMA) && (gPlayState->sceneNum != SCENE_GANON_DEMO) && - (gPlayState->gameplayFrames > 60 && gSaveContext.cutsceneIndex < 0xFFF0)) { - if ((CVarGetInteger("gAutosave", 0) == 2) || (CVarGetInteger("gAutosave", 0) == 5) && (item != ITEM_NONE)) { + (gPlayState->gameplayFrames > 60 && gSaveContext.cutsceneIndex < 0xFFF0) && (gPlayState->sceneNum != SCENE_GANON_DEMO)) { + if (((CVarGetInteger("gAutosave", 0) == 2) || (CVarGetInteger("gAutosave", 0) == 5)) && (item != ITEM_NONE)) { // Autosave for all items - Play_PerformSave(gPlayState); + performSave = true; - } else if ((CVarGetInteger("gAutosave", 0) == 1) || (CVarGetInteger("gAutosave", 0) == 4) && (item != ITEM_NONE)) { + } else if (((CVarGetInteger("gAutosave", 0) == 1) || (CVarGetInteger("gAutosave", 0) == 4)) && (item != ITEM_NONE)) { // Autosave for major items - 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: - case ITEM_NONE: - 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; + if (itemEntry.modIndex == 0) { + 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: + case ITEM_NONE: + break; + case ITEM_BOMBCHU: + case ITEM_BOMBCHUS_5: + case ITEM_BOMBCHUS_20: + if (!CVarGetInteger("gBombchuDrops", 0)) { + performSave = true; + } + break; + default: + performSave = true; + break; + } + } else if (itemEntry.modIndex == 1 && item != RG_ICE_TRAP) { + performSave = true; } + } else if ((CVarGetInteger("gAutosave", 0) > 0 && (CVarGetInteger("gAutosave", 0) < 4))) { + performSave = true; + } + if ((gPlayState->sceneNum == SCENE_YOUSEI_IZUMI_TATE) || (gPlayState->sceneNum == SCENE_KAKUSIANA) || + (gPlayState->sceneNum == SCENE_KENJYANOMA)) { + if ((CVarGetInteger("gAutosave", 0) > 0 && (CVarGetInteger("gAutosave", 0) < 4))) { + performSave = false; + return; + } + if (performSave) { + performSave = false; + performDelayedSave = true; + } + return; + } + if (performSave || performDelayedSave) { + Play_PerformSave(gPlayState); + performSave = false; + performDelayedSave = false; } } } @@ -238,6 +261,7 @@ void AutoSave(GetItemEntry itemEntry) { void RegisterAutoSave() { GameInteractor::Instance->RegisterGameHook([](GetItemEntry itemEntry) { AutoSave(itemEntry); }); GameInteractor::Instance->RegisterGameHook([](GetItemEntry itemEntry) { AutoSave(itemEntry); }); + GameInteractor::Instance->RegisterGameHook([](int32_t sceneNum) { AutoSave(GET_ITEM_NONE); }); } void RegisterRupeeDash() { diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 0738864c9..a7d81c6dc 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -553,6 +553,138 @@ extern "C" void VanillaItemTable_Init() { } } +std::unordered_map ItemIDtoGetItemID{ + { ITEM_ARROWS_LARGE, GI_ARROWS_LARGE }, + { ITEM_ARROWS_MEDIUM, GI_ARROWS_MEDIUM }, + { ITEM_ARROWS_SMALL, GI_ARROWS_SMALL }, + { ITEM_ARROW_FIRE, GI_ARROW_FIRE }, + { ITEM_ARROW_ICE, GI_ARROW_ICE }, + { ITEM_ARROW_LIGHT, GI_ARROW_LIGHT }, + { ITEM_BEAN, GI_BEAN }, + { ITEM_BIG_POE, GI_BIG_POE }, + { ITEM_BLUE_FIRE, GI_BLUE_FIRE }, + { ITEM_BOMB, GI_BOMBS_1 }, + { ITEM_BOMBCHU, GI_BOMBCHUS_10 }, + { ITEM_BOMBCHUS_20, GI_BOMBCHUS_20 }, + { ITEM_BOMBCHUS_5, GI_BOMBCHUS_5 }, + { ITEM_BOMBS_10, GI_BOMBS_10 }, + { ITEM_BOMBS_20, GI_BOMBS_20 }, + { ITEM_BOMBS_30, GI_BOMBS_30 }, + { ITEM_BOMBS_5, GI_BOMBS_5 }, + { ITEM_BOMB_BAG_20, GI_BOMB_BAG_20 }, + { ITEM_BOMB_BAG_30, GI_BOMB_BAG_30 }, + { ITEM_BOMB_BAG_40, GI_BOMB_BAG_40 }, + { ITEM_BOOMERANG, GI_BOOMERANG }, + { ITEM_BOOTS_HOVER, GI_BOOTS_HOVER }, + { ITEM_BOOTS_IRON, GI_BOOTS_IRON }, + { ITEM_BOTTLE, GI_BOTTLE }, + { ITEM_BOW, GI_BOW }, + { ITEM_BRACELET, GI_BRACELET }, + { ITEM_BUG, GI_BUGS }, + { ITEM_BULLET_BAG_30, GI_BULLET_BAG_30 }, + { ITEM_BULLET_BAG_40, GI_BULLET_BAG_40 }, + { ITEM_BULLET_BAG_50, GI_BULLET_BAG_50 }, { ITEM_CHICKEN, GI_CHICKEN }, + { ITEM_CLAIM_CHECK, GI_CLAIM_CHECK }, + { ITEM_COJIRO, GI_COJIRO }, + { ITEM_COMPASS, GI_COMPASS }, + { ITEM_DINS_FIRE, GI_DINS_FIRE }, + { ITEM_DUNGEON_MAP, GI_MAP }, + { ITEM_EYEDROPS, GI_EYEDROPS }, + { ITEM_FAIRY, GI_FAIRY }, + { ITEM_FARORES_WIND, GI_FARORES_WIND }, + { ITEM_FISH, GI_FISH }, + { ITEM_FROG, GI_FROG }, + { ITEM_GAUNTLETS_GOLD, GI_GAUNTLETS_GOLD }, + { ITEM_GAUNTLETS_SILVER, GI_GAUNTLETS_SILVER }, + { ITEM_GERUDO_CARD, GI_GERUDO_CARD }, + { ITEM_HAMMER, GI_HAMMER }, + { ITEM_HEART, GI_HEART }, + { ITEM_HEART_CONTAINER, GI_HEART_CONTAINER }, + { ITEM_HEART_CONTAINER, GI_HEART_CONTAINER_2 }, + { ITEM_HEART_PIECE_2, GI_HEART_PIECE }, + { ITEM_HEART_PIECE_2, GI_HEART_PIECE_WIN }, + { ITEM_HOOKSHOT, GI_HOOKSHOT }, + { ITEM_KEY_BOSS, GI_KEY_BOSS }, + { ITEM_KEY_SMALL, GI_DOOR_KEY }, + { ITEM_KEY_SMALL, GI_KEY_SMALL }, + { ITEM_LENS, GI_LENS }, + { ITEM_LETTER_RUTO, GI_LETTER_RUTO }, + { ITEM_LETTER_ZELDA, GI_LETTER_ZELDA }, + { ITEM_LONGSHOT, GI_LONGSHOT }, + { ITEM_MAGIC_LARGE, GI_MAGIC_LARGE }, + { ITEM_MAGIC_SMALL, GI_MAGIC_SMALL }, + { ITEM_MASK_BUNNY, GI_MASK_BUNNY }, + { ITEM_MASK_GERUDO, GI_MASK_GERUDO }, + { ITEM_MASK_GORON, GI_MASK_GORON }, + { ITEM_MASK_KEATON, GI_MASK_KEATON }, + { ITEM_MASK_SKULL, GI_MASK_SKULL }, + { ITEM_MASK_SPOOKY, GI_MASK_SPOOKY }, + { ITEM_MASK_TRUTH, GI_MASK_TRUTH }, + { ITEM_MASK_ZORA, GI_MASK_ZORA }, + { ITEM_MILK, GI_MILK }, + { ITEM_MILK_BOTTLE, GI_MILK_BOTTLE }, + { ITEM_NAYRUS_LOVE, GI_NAYRUS_LOVE }, + { ITEM_NUT, GI_NUTS_5 }, + { ITEM_NUTS_10, GI_NUTS_10 }, + { ITEM_NUTS_5, GI_NUTS_5 }, + { ITEM_NUTS_5, GI_NUTS_5_2 }, + { ITEM_NUT_UPGRADE_30, GI_NUT_UPGRADE_30 }, + { ITEM_NUT_UPGRADE_40, GI_NUT_UPGRADE_40 }, + { ITEM_OCARINA_FAIRY, GI_OCARINA_FAIRY }, + { ITEM_OCARINA_TIME, GI_OCARINA_OOT }, + { ITEM_ODD_MUSHROOM, GI_ODD_MUSHROOM }, + { ITEM_ODD_POTION, GI_ODD_POTION }, + { ITEM_POCKET_CUCCO, GI_POCKET_CUCCO }, + { ITEM_POCKET_EGG, GI_POCKET_EGG }, + { ITEM_POE, GI_POE }, + { ITEM_POTION_BLUE, GI_POTION_BLUE }, + { ITEM_POTION_GREEN, GI_POTION_GREEN }, + { ITEM_POTION_RED, GI_POTION_RED }, + { ITEM_PRESCRIPTION, GI_PRESCRIPTION }, + { ITEM_QUIVER_40, GI_QUIVER_40 }, + { ITEM_QUIVER_50, GI_QUIVER_50 }, + { ITEM_RUPEE_BLUE, GI_RUPEE_BLUE }, + { ITEM_RUPEE_BLUE, GI_RUPEE_BLUE_LOSE }, + { ITEM_RUPEE_GOLD, GI_RUPEE_GOLD }, + { ITEM_RUPEE_GREEN, GI_RUPEE_GREEN }, + { ITEM_RUPEE_GREEN, GI_RUPEE_GREEN_LOSE }, + { ITEM_RUPEE_PURPLE, GI_RUPEE_PURPLE }, + { ITEM_RUPEE_PURPLE, GI_RUPEE_PURPLE_LOSE }, + { ITEM_RUPEE_RED, GI_RUPEE_RED }, + { ITEM_RUPEE_RED, GI_RUPEE_RED_LOSE }, + { ITEM_SAW, GI_SAW }, + { ITEM_SCALE_GOLDEN, GI_SCALE_GOLD }, + { ITEM_SCALE_SILVER, GI_SCALE_SILVER }, + { ITEM_SEEDS, GI_SEEDS_5 }, + { ITEM_SEEDS_30, GI_SEEDS_30 }, + { ITEM_SHIELD_DEKU, GI_SHIELD_DEKU }, + { ITEM_SHIELD_HYLIAN, GI_SHIELD_HYLIAN }, + { ITEM_SHIELD_MIRROR, GI_SHIELD_MIRROR }, + { ITEM_SKULL_TOKEN, GI_SKULL_TOKEN }, + { ITEM_SLINGSHOT, GI_SLINGSHOT }, + { ITEM_STICK, GI_STICKS_1 }, + { ITEM_STICKS_10, GI_STICKS_10 }, + { ITEM_STICKS_5, GI_STICKS_5 }, + { ITEM_STICK_UPGRADE_20, GI_STICK_UPGRADE_20 }, + { ITEM_STICK_UPGRADE_30, GI_STICK_UPGRADE_30 }, + { ITEM_STONE_OF_AGONY, GI_STONE_OF_AGONY }, + { ITEM_SWORD_BGS, GI_SWORD_BGS }, + { ITEM_SWORD_BGS, GI_SWORD_KNIFE }, + { ITEM_SWORD_BROKEN, GI_SWORD_BROKEN }, + { ITEM_SWORD_KOKIRI, GI_SWORD_KOKIRI }, + { ITEM_TUNIC_GORON, GI_TUNIC_GORON }, + { ITEM_TUNIC_ZORA, GI_TUNIC_ZORA }, + { ITEM_WALLET_ADULT, GI_WALLET_ADULT }, + { ITEM_WALLET_GIANT, GI_WALLET_GIANT }, + { ITEM_WEIRD_EGG, GI_WEIRD_EGG } +}; + +extern "C" uint32_t GetGIID(uint32_t itemID) { + if (ItemIDtoGetItemID.contains(itemID)) + return ItemIDtoGetItemID.at(itemID); + return -1; +} + extern "C" void OTRExtScanner() { auto lst = *OTRGlobals::Instance->context->GetResourceManager()->ListFiles("*.*").get(); diff --git a/soh/soh/OTRGlobals.h b/soh/soh/OTRGlobals.h index 398a91b6c..c77d6f56e 100644 --- a/soh/soh/OTRGlobals.h +++ b/soh/soh/OTRGlobals.h @@ -138,6 +138,8 @@ void Entrance_ClearEntranceTrackingData(void); void Entrance_InitEntranceTrackingData(void); void EntranceTracker_SetCurrentGrottoID(s16 entranceIndex); void EntranceTracker_SetLastEntranceOverride(s16 entranceIndex); + +uint32_t GetGIID(uint32_t itemID); #endif #endif diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index b3cece3b5..488c9a320 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1704,8 +1704,13 @@ u8 Return_Item_Entry(GetItemEntry itemEntry, ItemID returnItem ) { } // Processes Item_Give returns -u8 Return_Item(u8 item, ModIndex modId, ItemID returnItem) { - return Return_Item_Entry(ItemTable_RetrieveEntry(modId, item), returnItem); +u8 Return_Item(u8 itemID, ModIndex modId, ItemID returnItem) { + uint32_t get = GetGIID(itemID); + if (get == -1) { + modId = MOD_RANDOMIZER; + get = itemID; + } + return Return_Item_Entry(ItemTable_RetrieveEntry(modId, get), returnItem); } /** @@ -2313,7 +2318,7 @@ u8 Item_Give(PlayState* play, u8 item) { } u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) { - uint16_t item = giEntry.itemId; + uint16_t item = giEntry.getItemId; uint16_t temp; uint16_t i; uint16_t slot; @@ -6196,11 +6201,16 @@ void Interface_Update(PlayState* play) { Audio_PlaySoundGeneral(NA_SE_SY_RUPY_COUNT, &D_801333D4, 4, &D_801333E0, &D_801333E0, &D_801333E8); } if (gSaveContext.rupeeAccumulator == 0) { - u16 tempSaleItem = gSaveContext.pendingSale; - u16 tempSaleMod = gSaveContext.pendingSaleMod; - gSaveContext.pendingSale = ITEM_NONE; - gSaveContext.pendingSaleMod = MOD_NONE; - GameInteractor_ExecuteOnSaleEndHooks(ItemTable_RetrieveEntry(tempSaleMod,tempSaleItem)); + if (gSaveContext.pendingSale != ITEM_NONE) { + u16 tempSaleItem = gSaveContext.pendingSale; + u16 tempSaleMod = gSaveContext.pendingSaleMod; + gSaveContext.pendingSale = ITEM_NONE; + gSaveContext.pendingSaleMod = MOD_NONE; + if (tempSaleMod == 0) { + tempSaleItem = GetGIID(tempSaleItem); + } + GameInteractor_ExecuteOnSaleEndHooks(ItemTable_RetrieveEntry(tempSaleMod, tempSaleItem)); + } } } else { gSaveContext.rupeeAccumulator = 0; diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index 418eff501..5d280ca0b 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -869,15 +869,8 @@ void Play_Update(PlayState* play) { gTrnsnUnkState = 0; R_UPDATE_RATE = 3; } - - // Autosave on area transition unless you're in a cutscene or a grotto since resuming from grottos breaks the game - // Also don't save when you first load a file to prevent consumables like magic from being lost - // Also don't save if there's a pending shop sale to prevent getting the item for a discount! - if ((CVarGetInteger("gAutosave", 0) >= 1) && (CVarGetInteger("gAutosave", 0) <= 3) && - (gSaveContext.cutsceneIndex < 0xFFF0) && (play->gameplayFrames > 60) && (gSaveContext.pendingSale == ITEM_NONE) && - (play->sceneNum != SCENE_YOUSEI_IZUMI_TATE) && (play->sceneNum != SCENE_KAKUSIANA) && (play->sceneNum != SCENE_KENJYANOMA)) { - Play_PerformSave(play); - } + + GameInteractor_ExecuteOnTransitionEndHooks(play->sceneNum); } play->sceneLoadFlag = 0; } else {