From 2fc3a563c9da566bc67122818d3763815f68ec59 Mon Sep 17 00:00:00 2001 From: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com> Date: Mon, 13 Jan 2025 18:17:12 +0000 Subject: [PATCH 01/60] fix spirit MQ south child climb chest logic (#4850) --- .../randomizer/location_access/dungeons/bottom_of_the_well.cpp | 2 +- .../randomizer/location_access/dungeons/spirit_temple.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp index 588d32bf1..4ad3f7528 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/bottom_of_the_well.cpp @@ -49,7 +49,7 @@ void RegionTable_Init_BottomOfTheWell() { LOCATION(RC_BOTTOM_OF_THE_WELL_FRONT_LEFT_FAKE_WALL_CHEST, true), LOCATION(RC_BOTTOM_OF_THE_WELL_RIGHT_BOTTOM_FAKE_WALL_CHEST, true), LOCATION(RC_BOTTOM_OF_THE_WELL_COMPASS_CHEST, true), - //N64 has no extra check here, but I can't get past without dealing with the spider or taking a hit + //N64 has no extra check here, but I can't get past without dealing with the spider or taking a hit, they probably assume sticks LOCATION(RC_BOTTOM_OF_THE_WELL_CENTER_SKULLTULA_CHEST, logic->CanPassEnemy(RE_BIG_SKULLTULA) || logic->TakeDamage()), //Not technically behind a wall, but still logically needs lens due to pits LOCATION(RC_BOTTOM_OF_THE_WELL_BACK_LEFT_BOMBABLE_CHEST, logic->HasExplosives()), diff --git a/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp b/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp index 30481922c..36ee1d5ab 100644 --- a/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp +++ b/soh/soh/Enhancements/randomizer/location_access/dungeons/spirit_temple.cpp @@ -267,7 +267,7 @@ void RegionTable_Init_SpiritTemple() { LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_NORTH_CHEST, MQSpiritSharedBrokenWallRoom(RR_SPIRIT_TEMPLE_MQ_BROKEN_WALL_ROOM, []{return logic->CanKillEnemy(RE_BEAMOS);})), //Sunlights only temp spawn this chest, which is unintuitive/a bug. //chest is only reachable as adult glitchlessly, so we can skip the shared in favour of IsAdult as adult access is always Certain - LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, logic->IsAdult && logic->HasExplosives() && (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS)) && logic->CanUse(RG_HOOKSHOT)), + LOCATION(RC_SPIRIT_TEMPLE_MQ_CHILD_CLIMB_SOUTH_CHEST, logic->IsAdult && (logic->HasExplosives() || (ctx->GetOption(RSK_SUNLIGHT_ARROWS) && logic->CanUse(RG_LIGHT_ARROWS))) && logic->CanUse(RG_HOOKSHOT)), }, { //Exits Entrance(RR_SPIRIT_TEMPLE_MQ_UNDER_LIKE_LIKE, []{return logic->CanHitSwitch();}), From 0d80c4695f1ca275167821b42377741fc0828c58 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Tue, 14 Jan 2025 21:49:49 -0700 Subject: [PATCH 02/60] Change `UnregisterGameHook` type for freestanding handler to `OnVanillaBehavior` to match registration type. (#4883) --- soh/soh/Enhancements/randomizer/hook_handlers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index 409fa45d1..86fb79418 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -2392,7 +2392,7 @@ void RandomizerRegisterHooks() { GameInteractor::Instance->UnregisterGameHook(shufflePotsOnActorInitHook); GameInteractor::Instance->UnregisterGameHook(shufflePotsOnVanillaBehaviorHook); - GameInteractor::Instance->UnregisterGameHook(shuffleFreestandingOnVanillaBehaviorHook); + GameInteractor::Instance->UnregisterGameHook(shuffleFreestandingOnVanillaBehaviorHook); onFlagSetHook = 0; onSceneFlagSetHook = 0; From 7f31fd2e4ee0f2facafec4aaba5591fed52da9f5 Mon Sep 17 00:00:00 2001 From: Pepe20129 <72659707+Pepe20129@users.noreply.github.com> Date: Wed, 15 Jan 2025 13:04:47 +0100 Subject: [PATCH 03/60] Organize ship specific save context additions (#4597) * Basic restructure * Undo most randomizerInf changes for now * Small fixes * Fix linux & mac builds? * Fix remnants of randomizerInf changes * Post-merge fix * Post-merge fix --- soh/include/z64save.h | 64 +++-- soh/soh/Enhancements/boss-rush/BossRush.cpp | 57 ++-- soh/soh/Enhancements/debugconsole.cpp | 2 +- .../Enhancements/debugger/debugSaveEditor.cpp | 16 +- soh/soh/Enhancements/enemyrandomizer.cpp | 2 +- .../GameInteractor_RawAction.cpp | 14 +- soh/soh/Enhancements/gameplaystats.cpp | 264 +++++++++--------- soh/soh/Enhancements/gameplaystats.h | 14 +- soh/soh/Enhancements/kaleido.cpp | 2 +- soh/soh/Enhancements/mods.cpp | 112 ++++---- .../randomizer/adult_trade_shuffle.c | 6 +- .../randomizer/adult_trade_shuffle.h | 2 +- soh/soh/Enhancements/randomizer/draw.cpp | 4 +- .../Enhancements/randomizer/hook_handlers.cpp | 2 +- .../randomizer/location_access.cpp | 2 +- soh/soh/Enhancements/randomizer/logic.cpp | 25 +- .../Enhancements/randomizer/randomizer.cpp | 40 +-- .../randomizer/randomizer_check_tracker.cpp | 2 +- .../randomizer/randomizer_entrance.c | 8 +- .../randomizer/randomizer_item_tracker.cpp | 14 +- soh/soh/Enhancements/randomizer/savefile.cpp | 40 +-- .../Enhancements/timesplits/TimeSplits.cpp | 4 +- soh/soh/OTRGlobals.cpp | 4 +- soh/soh/SaveManager.cpp | 242 ++++++++-------- soh/src/code/z_actor.c | 33 ++- soh/src/code/z_demo.c | 4 +- soh/src/code/z_draw.c | 2 +- soh/src/code/z_kaleido_scope_call.c | 8 +- soh/src/code/z_parameter.c | 58 ++-- soh/src/code/z_play.c | 96 +++---- soh/src/code/z_room.c | 20 +- soh/src/code/z_sram.c | 6 +- soh/src/overlays/actors/ovl_En_Box/z_en_box.c | 2 +- soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c | 4 +- soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c | 4 +- .../overlays/actors/ovl_En_GirlA/z_en_girla.c | 80 +++--- soh/src/overlays/actors/ovl_En_Js/z_en_js.c | 4 +- .../overlays/actors/ovl_En_Kusa/z_en_kusa.c | 4 +- soh/src/overlays/actors/ovl_En_Ta/z_en_ta.c | 4 +- .../actors/ovl_Obj_Tsubo/z_obj_tsubo.c | 4 +- .../actors/ovl_player_actor/z_player.c | 36 +-- .../ovl_file_choose/z_file_choose.c | 24 +- 42 files changed, 695 insertions(+), 640 deletions(-) diff --git a/soh/include/z64save.h b/soh/include/z64save.h index 47a2d18c4..7138d0e0a 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -157,6 +157,42 @@ typedef struct { char hintText[200]; } HintLocationRando; +#pragma region SoH + +typedef struct ShipRandomizerSaveContextData { + u16 adultTradeItems; + u8 triforcePiecesCollected; +} ShipRandomizerSaveContextData; + +typedef struct ShipBossRushSaveContextData { + u32 isPaused; + u8 options[BR_OPTIONS_MAX]; +} ShipBossRushSaveContextData; + +typedef union ShipQuestSpecificSaveContextData { + ShipRandomizerSaveContextData randomizer; + ShipBossRushSaveContextData bossRush; +} ShipQuestSpecificSaveContextData; + +typedef struct ShipQuestSaveContextData { + u8 id; + ShipQuestSpecificSaveContextData data; +} ShipQuestSaveContextData; + +typedef struct ShipSaveContextData { + u16 pendingSale; + u16 pendingSaleMod; + u8 pendingIceTrapCount; + SohStats stats; + FaroresWindData backupFW; + ShipQuestSaveContextData quest; + u8 maskMemory; + //TODO: Move non-rando specific flags to a new sohInf and move the remaining randomizerInf to ShipRandomizerSaveContextData + u16 randomizerInf[(RAND_INF_MAX + 15) / 16]; +} ShipSaveContextData; + +#pragma endregion + typedef struct { /* 0x0000 */ s32 entranceIndex; // start of `save` substruct, originally called "memory" /* 0x0004 */ s32 linkAge; // 0: Adult; 1: Child (see enum `LinkAge`) @@ -270,25 +306,7 @@ typedef struct { /* 0x1420 */ s16 worldMapArea; /* 0x1422 */ s16 sunsSongState; // controls the effects of suns song /* 0x1424 */ s16 healthAccumulator; - // #region SOH [General] - // Upstream TODO: Move these to their own struct or name to more obviously specific to SoH - /* */ u16 pendingSale; - /* */ u16 pendingSaleMod; - /* */ uint8_t questId; - /* */ uint32_t isBossRushPaused; - /* */ uint8_t bossRushOptions[BR_OPTIONS_MAX]; - /* */ u8 pendingIceTrapCount; - /* */ SohStats sohStats; - /* */ FaroresWindData backupFW; - /* */ u8 maskMemory; - // #endregion - // #region SOH [Randomizer] - // Upstream TODO: Move these to their own struct or name to more obviously specific to Randomizer - /* */ u16 randomizerInf[(RAND_INF_MAX + 15) / 16]; - /* */ u8 mqDungeonCount; - /* */ u16 adultTradeItems; - /* */ u8 triforcePiecesCollected; - // #endregion + /* */ ShipSaveContextData ship; } SaveContext; // size = 0x1428 typedef enum { @@ -298,10 +316,10 @@ typedef enum { /* 03 */ QUEST_BOSSRUSH, } Quest; -#define IS_VANILLA (gSaveContext.questId == QUEST_NORMAL) -#define IS_MASTER_QUEST (gSaveContext.questId == QUEST_MASTER) -#define IS_RANDO (gSaveContext.questId == QUEST_RANDOMIZER) -#define IS_BOSS_RUSH (gSaveContext.questId == QUEST_BOSSRUSH) +#define IS_VANILLA (gSaveContext.ship.quest.id == QUEST_NORMAL) +#define IS_MASTER_QUEST (gSaveContext.ship.quest.id == QUEST_MASTER) +#define IS_RANDO (gSaveContext.ship.quest.id == QUEST_RANDOMIZER) +#define IS_BOSS_RUSH (gSaveContext.ship.quest.id == QUEST_BOSSRUSH) typedef enum { /* 0x00 */ BTN_ENABLED, diff --git a/soh/soh/Enhancements/boss-rush/BossRush.cpp b/soh/soh/Enhancements/boss-rush/BossRush.cpp index d4997cca9..96220f057 100644 --- a/soh/soh/Enhancements/boss-rush/BossRush.cpp +++ b/soh/soh/Enhancements/boss-rush/BossRush.cpp @@ -265,10 +265,10 @@ void BossRush_HandleBlueWarp(PlayState* play, f32 warpPosX, f32 warpPosZ) { gSaveContext.linkAge = LINK_AGE_ADULT; // Change to Adult Link. - if (gSaveContext.bossRushOptions[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_ALL) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_ALL) { BossRush_SetEquipment(LINK_AGE_ADULT); // Warp to credits. - } else if (gSaveContext.bossRushOptions[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_CHILD) { + } else if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_CHILD) { play->nextEntranceIndex = ENTR_CHAMBER_OF_THE_SAGES_0; gSaveContext.nextCutsceneIndex = 0xFFF2; play->transitionTrigger = TRANS_TRIGGER_START; @@ -285,14 +285,14 @@ void BossRush_HandleBlueWarp(PlayState* play, f32 warpPosX, f32 warpPosZ) { void BossRush_HandleBlueWarpHeal(PlayState* play) { // This function gets called multiple times per blue warp, so only heal when player isn't at max HP. - if (gSaveContext.bossRushOptions[BR_OPTIONS_HEAL] == BR_CHOICE_HEAL_EVERYBOSS && + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_HEAL] == BR_CHOICE_HEAL_EVERYBOSS && gSaveContext.health != gSaveContext.healthCapacity) { Health_ChangeBy(play, 320); } } void BossRush_HandleCompleteBoss(PlayState* play) { - gSaveContext.isBossRushPaused = 1; + gSaveContext.ship.quest.data.bossRush.isPaused = true; switch (play->sceneNum) { case SCENE_DEKU_TREE_BOSS: Flags_SetEventChkInf(EVENTCHKINF_USED_DEKU_TREE_BLUE_WARP); @@ -323,16 +323,16 @@ void BossRush_HandleCompleteBoss(PlayState* play) { } // Fully heal the player after Ganondorf - if (gSaveContext.bossRushOptions[BR_OPTIONS_HEAL] == BR_CHOICE_HEAL_EVERYBOSS && + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_HEAL] == BR_CHOICE_HEAL_EVERYBOSS && play->sceneNum == SCENE_GANONDORF_BOSS) { Health_ChangeBy(play, 320); } - if ((CheckDungeonCount() == 3 && gSaveContext.bossRushOptions[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_CHILD) || + if ((CheckDungeonCount() == 3 && gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_CHILD) || play->sceneNum == SCENE_GANON_BOSS) { - gSaveContext.sohStats.playTimer += 2; - gSaveContext.sohStats.gameComplete = 1; - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_BOSSRUSH_FINISH] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.playTimer += 2; + gSaveContext.ship.stats.gameComplete = 1; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_BOSSRUSH_FINISH] = GAMEPLAYSTAT_TOTAL_TIME; } } @@ -344,14 +344,14 @@ void BossRush_InitSave() { gSaveContext.playerName[i] = brPlayerName[i]; } - gSaveContext.questId = QUEST_BOSSRUSH; - gSaveContext.isBossRushPaused = 1; + gSaveContext.ship.quest.id = QUEST_BOSSRUSH; + gSaveContext.ship.quest.data.bossRush.isPaused = true; gSaveContext.entranceIndex = ENTR_CHAMBER_OF_THE_SAGES_0; gSaveContext.cutsceneIndex = 0x8000; gSaveContext.isMagicAcquired = 1; // Set magic - if (gSaveContext.bossRushOptions[BR_OPTIONS_MAGIC] == BR_CHOICE_MAGIC_SINGLE) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_MAGIC] == BR_CHOICE_MAGIC_SINGLE) { gSaveContext.magicLevel = 1; gSaveContext.magic = 48; } else { @@ -362,7 +362,7 @@ void BossRush_InitSave() { // Set health u16 health = 16; - switch (gSaveContext.bossRushOptions[BR_OPTIONS_HEARTS]) { + switch (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_HEARTS]) { case BR_CHOICE_HEARTS_7: health *= 7; break; @@ -399,8 +399,9 @@ void BossRush_InitSave() { gSaveContext.eventChkInf[7] |= 0x80; // bongo bongo // Sets all rando flags to false - for (s32 i = 0; i < ARRAY_COUNT(gSaveContext.randomizerInf); i++) { - gSaveContext.randomizerInf[i] = 0; + // Boss Rush currently uses 2 randomizer flags (RAND_INF_DUNGEONS_DONE_SPIRIT_TEMPLE & RAND_INF_DUNGEONS_DONE_SHADOW_TEMPLE) + for (s32 i = 0; i < ARRAY_COUNT(gSaveContext.ship.randomizerInf); i++) { + gSaveContext.ship.randomizerInf[i] = 0; } // Set items @@ -411,11 +412,11 @@ void BossRush_InitSave() { ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE, }; - if (gSaveContext.bossRushOptions[BR_OPTIONS_LONGSHOT] == BR_CHOICE_LONGSHOT_YES) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_LONGSHOT] == BR_CHOICE_LONGSHOT_YES) { brItems[9] = ITEM_LONGSHOT; } - switch (gSaveContext.bossRushOptions[BR_OPTIONS_BOTTLE]) { + switch (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BOTTLE]) { case BR_CHOICE_BOTTLE_EMPTY: brItems[18] = ITEM_BOTTLE; break; @@ -435,7 +436,7 @@ void BossRush_InitSave() { break; } - if (gSaveContext.bossRushOptions[BR_OPTIONS_BUNNYHOOD] == BR_CHOICE_BUNNYHOOD_YES) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BUNNYHOOD] == BR_CHOICE_BUNNYHOOD_YES) { brItems[23] = ITEM_MASK_BUNNY; } @@ -446,9 +447,9 @@ void BossRush_InitSave() { // Set consumable counts std::array brAmmo = { 5, 5, 10, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - if (gSaveContext.bossRushOptions[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_FULL) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_FULL) { brAmmo = { 10, 20, 20, 30, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - } else if (gSaveContext.bossRushOptions[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_MAXED) { + } else if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_MAXED) { brAmmo = { 30, 40, 40, 50, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; } @@ -462,17 +463,17 @@ void BossRush_InitSave() { gSaveContext.inventory.equipment |= 1 << 4; // Deku Shield gSaveContext.inventory.equipment |= 1 << 6; // Mirror Shield gSaveContext.inventory.equipment |= 1 << 9; // Goron Tunic - if (gSaveContext.bossRushOptions[BR_OPTIONS_BGS] == BR_CHOICE_BGS_YES) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BGS] == BR_CHOICE_BGS_YES) { gSaveContext.inventory.equipment |= 1 << 2; // Biggoron Sword gSaveContext.bgsFlag = 1; } - if (gSaveContext.bossRushOptions[BR_OPTIONS_HOVERBOOTS] == BR_CHOICE_HOVERBOOTS_YES) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_HOVERBOOTS] == BR_CHOICE_HOVERBOOTS_YES) { gSaveContext.inventory.equipment |= 1 << 14; // Hover Boots } // Upgrades u8 upgradeLevel = 1; - if (gSaveContext.bossRushOptions[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_MAXED) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_AMMO] == BR_CHOICE_AMMO_MAXED) { upgradeLevel = 3; } Inventory_ChangeUpgrade(UPG_QUIVER, upgradeLevel); @@ -483,12 +484,12 @@ void BossRush_InitSave() { Inventory_ChangeUpgrade(UPG_STRENGTH, 1); // Set flags and Link's age based on chosen settings. - if (gSaveContext.bossRushOptions[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_ADULT || - gSaveContext.bossRushOptions[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_GANONDORF_GANON) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_ADULT || + gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_GANONDORF_GANON) { Flags_SetEventChkInf(EVENTCHKINF_USED_DEKU_TREE_BLUE_WARP); Flags_SetEventChkInf(EVENTCHKINF_USED_DODONGOS_CAVERN_BLUE_WARP); Flags_SetEventChkInf(EVENTCHKINF_USED_JABU_JABUS_BELLY_BLUE_WARP); - if (gSaveContext.bossRushOptions[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_GANONDORF_GANON) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_BOSSES] == BR_CHOICE_BOSSES_GANONDORF_GANON) { Flags_SetEventChkInf(EVENTCHKINF_USED_FOREST_TEMPLE_BLUE_WARP); Flags_SetEventChkInf(EVENTCHKINF_USED_FIRE_TEMPLE_BLUE_WARP); Flags_SetEventChkInf(EVENTCHKINF_USED_WATER_TEMPLE_BLUE_WARP); @@ -516,7 +517,7 @@ void BossRush_OnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li switch (id) { // Allow not healing before ganon case VB_GANON_HEAL_BEFORE_FIGHT: { - if (gSaveContext.bossRushOptions[BR_OPTIONS_HEAL] == BR_CHOICE_HEAL_NEVER) { + if (gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_HEAL] == BR_CHOICE_HEAL_NEVER) { *should = false; } break; @@ -669,7 +670,7 @@ void BossRush_OnActorInitHandler(void* actorRef) { void BossRush_OnSceneInitHandler(s16 sceneNum) { // Unpause the timer when the scene loaded isn't the Chamber of Sages. if (sceneNum != SCENE_CHAMBER_OF_THE_SAGES) { - gSaveContext.isBossRushPaused = 0; + gSaveContext.ship.quest.data.bossRush.isPaused = false; } } diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp index 76f903eb1..580fafc14 100644 --- a/soh/soh/Enhancements/debugconsole.cpp +++ b/soh/soh/Enhancements/debugconsole.cpp @@ -470,7 +470,7 @@ static bool FWHandler(std::shared_ptr Console, const std::vector< break; case 2: //backup if (CVarGetInteger(CVAR_ENHANCEMENT("BetterFarore"), 0)) { - gSaveContext.fw = gSaveContext.backupFW; + gSaveContext.fw = gSaveContext.ship.backupFW; gSaveContext.fw.set = 1; INFO_MESSAGE("[SOH] Backup FW data copied! Reload scene to take effect."); return 0; diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 83fe7f676..5fedd54be 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -314,7 +314,7 @@ void DrawInfoTab() { UIWidgets::InsertHelpHoverText("Z-Targeting behavior"); if (IS_RANDO && OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT)) { - ImGui::InputScalar("Triforce Pieces", ImGuiDataType_U8, &gSaveContext.triforcePiecesCollected); + ImGui::InputScalar("Triforce Pieces", ImGuiDataType_U8, &gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected); UIWidgets::InsertHelpHoverText("Currently obtained Triforce Pieces. For Triforce Hunt."); } @@ -416,17 +416,17 @@ void DrawBGSItemFlag(uint8_t itemID) { ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(slotEntry.name), ImVec2(32.0f, 32.0f), ImVec2(0, 0), ImVec2(1, 1)); ImGui::SameLine(); int tradeIndex = itemID - ITEM_POCKET_EGG; - bool hasItem = (gSaveContext.adultTradeItems & (1 << tradeIndex)) != 0; + bool hasItem = (gSaveContext.ship.quest.data.randomizer.adultTradeItems & (1 << tradeIndex)) != 0; bool shouldHaveItem = hasItem; ImGui::Checkbox(("##adultTradeFlag" + std::to_string(itemID)).c_str(), &shouldHaveItem); if (hasItem != shouldHaveItem) { if (shouldHaveItem) { - gSaveContext.adultTradeItems |= (1 << tradeIndex); + gSaveContext.ship.quest.data.randomizer.adultTradeItems |= (1 << tradeIndex); if (INV_CONTENT(ITEM_TRADE_ADULT) == ITEM_NONE) { INV_CONTENT(ITEM_TRADE_ADULT) = ITEM_POCKET_EGG + tradeIndex; } } else { - gSaveContext.adultTradeItems &= ~(1 << tradeIndex); + gSaveContext.ship.quest.data.randomizer.adultTradeItems &= ~(1 << tradeIndex); Inventory_ReplaceItem(gPlayState, itemID, Randomizer_GetNextAdultTradeItem()); } } @@ -477,7 +477,7 @@ void DrawInventoryTab() { if (ImGui::Button("##itemNonePicker", ImVec2(32.0f, 32.0f))) { gSaveContext.inventory.items[selectedIndex] = ITEM_NONE; if (selectedIndex == SLOT_TRADE_ADULT) { - gSaveContext.adultTradeItems = 0; + gSaveContext.ship.quest.data.randomizer.adultTradeItems = 0; } ImGui::CloseCurrentPopup(); } @@ -517,7 +517,7 @@ void DrawInventoryTab() { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_ADULT_TRADE) && selectedIndex == SLOT_TRADE_ADULT && slotEntry.id >= ITEM_POCKET_EGG && slotEntry.id <= ITEM_CLAIM_CHECK) { - gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(slotEntry.id); + gSaveContext.ship.quest.data.randomizer.adultTradeItems |= ADULT_TRADE_FLAG(slotEntry.id); } ImGui::CloseCurrentPopup(); } @@ -923,7 +923,7 @@ void DrawFlagsTab() { DrawFlagTableArray16(flagTable, j, gSaveContext.eventInf[j]); break; case RANDOMIZER_INF: - DrawFlagTableArray16(flagTable, j, gSaveContext.randomizerInf[j]); + DrawFlagTableArray16(flagTable, j, gSaveContext.ship.randomizerInf[j]); break; } }); @@ -1305,7 +1305,7 @@ void DrawQuestStatusTab() { ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(itemMapping[ITEM_KEY_SMALL].name), ImVec2(lineHeight, lineHeight)); ImGui::SameLine(); if (ImGui::InputScalar("##Keys", ImGuiDataType_S8, gSaveContext.inventory.dungeonKeys + dungeonItemsScene)) { - gSaveContext.sohStats.dungeonKeys[dungeonItemsScene] = gSaveContext.inventory.dungeonKeys[dungeonItemsScene]; + gSaveContext.ship.stats.dungeonKeys[dungeonItemsScene] = gSaveContext.inventory.dungeonKeys[dungeonItemsScene]; }; } else { // dungeonItems is size 20 but dungeonKeys is size 19, so there are no keys for the last scene (Barinade's Lair) diff --git a/soh/soh/Enhancements/enemyrandomizer.cpp b/soh/soh/Enhancements/enemyrandomizer.cpp index 89aab7e00..73042b25f 100644 --- a/soh/soh/Enhancements/enemyrandomizer.cpp +++ b/soh/soh/Enhancements/enemyrandomizer.cpp @@ -305,7 +305,7 @@ EnemyEntry GetRandomizedEnemyEntry(uint32_t seed) { GetSelectedEnemies(); } if (CVarGetInteger(CVAR_ENHANCEMENT("RandomizedEnemies"), ENEMY_RANDOMIZER_OFF) == ENEMY_RANDOMIZER_RANDOM_SEEDED) { - uint32_t finalSeed = seed + (IS_RANDO ? Rando::Context::GetInstance()->GetSettings()->GetSeed() : gSaveContext.sohStats.fileCreatedAt); + uint32_t finalSeed = seed + (IS_RANDO ? Rando::Context::GetInstance()->GetSettings()->GetSeed() : gSaveContext.ship.stats.fileCreatedAt); Random_Init(finalSeed); uint32_t randomNumber = Random(0, RANDOMIZED_ENEMY_SPAWN_TABLE_SIZE); return selectedEnemyList[randomNumber]; diff --git a/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp b/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp index bb04e72b8..aa8c72d00 100644 --- a/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp +++ b/soh/soh/Enhancements/game-interactor/GameInteractor_RawAction.cpp @@ -238,7 +238,12 @@ void GameInteractor::RawAction::SetFlag(int16_t flagType, int16_t flag) { gSaveContext.eventInf[flag >> 4] |= (1 << (flag & 0xF)); break; case FlagType::FLAG_RANDOMIZER_INF: - gSaveContext.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); + if (!IS_RANDO) { + LUSLOG_ERROR("Tried to set randomizerInf flag outside of rando (%d)", flag); + assert(false); + break; + } + gSaveContext.ship.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); break; case FlagType::FLAG_GS_TOKEN: SET_GS_FLAGS((flag & 0x1F00) >> 8, flag & 0xFF); @@ -261,7 +266,12 @@ void GameInteractor::RawAction::UnsetFlag(int16_t flagType, int16_t flag) { gSaveContext.eventInf[flag >> 4] &= ~(1 << (flag & 0xF)); break; case FlagType::FLAG_RANDOMIZER_INF: - gSaveContext.randomizerInf[flag >> 4] &= ~(1 << (flag & 0xF)); + if (!IS_RANDO) { + LUSLOG_ERROR("Tried to unset randomizerInf flag outside of rando (%d)", flag); + assert(false); + break; + } + gSaveContext.ship.randomizerInf[flag >> 4] &= ~(1 << (flag & 0xF)); break; } }; diff --git a/soh/soh/Enhancements/gameplaystats.cpp b/soh/soh/Enhancements/gameplaystats.cpp index 3f7691741..ddff16c7d 100644 --- a/soh/soh/Enhancements/gameplaystats.cpp +++ b/soh/soh/Enhancements/gameplaystats.cpp @@ -252,7 +252,7 @@ typedef struct { // Timestamps are an array of structs, each with a name, time, and color // Names and colors are set up at the bottom of this file -// Times are stored in gSaveContext.sohStats.itemTimestamp +// Times are stored in gSaveContext.ship.stats.itemTimestamp TimestampInfo itemTimestampDisplay[TIMESTAMP_MAX]; TimestampInfo sceneTimestampDisplay[8191]; //std::vector sceneTimestampDisplay; @@ -287,25 +287,25 @@ extern "C" char* GameplayStats_GetCurrentTime() { } void LoadStatsVersion1() { - SaveManager::Instance->LoadCharArray("buildVersion", gSaveContext.sohStats.buildVersion, - ARRAY_COUNT(gSaveContext.sohStats.buildVersion)); - SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.sohStats.buildVersionMajor); - SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.sohStats.buildVersionMinor); - SaveManager::Instance->LoadData("buildVersionPatch", gSaveContext.sohStats.buildVersionPatch); + SaveManager::Instance->LoadCharArray("buildVersion", gSaveContext.ship.stats.buildVersion, + ARRAY_COUNT(gSaveContext.ship.stats.buildVersion)); + SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.ship.stats.buildVersionMajor); + SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.ship.stats.buildVersionMinor); + SaveManager::Instance->LoadData("buildVersionPatch", gSaveContext.ship.stats.buildVersionPatch); - SaveManager::Instance->LoadData("heartPieces", gSaveContext.sohStats.heartPieces); - SaveManager::Instance->LoadData("heartContainers", gSaveContext.sohStats.heartContainers); - SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.dungeonKeys[i]); + SaveManager::Instance->LoadData("heartPieces", gSaveContext.ship.stats.heartPieces); + SaveManager::Instance->LoadData("heartContainers", gSaveContext.ship.stats.heartContainers); + SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.ship.stats.dungeonKeys), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.dungeonKeys[i]); }); - SaveManager::Instance->LoadData("rtaTiming", gSaveContext.sohStats.rtaTiming); - SaveManager::Instance->LoadData("fileCreatedAt", gSaveContext.sohStats.fileCreatedAt); - SaveManager::Instance->LoadData("playTimer", gSaveContext.sohStats.playTimer); - SaveManager::Instance->LoadData("pauseTimer", gSaveContext.sohStats.pauseTimer); - SaveManager::Instance->LoadArray("itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); + SaveManager::Instance->LoadData("rtaTiming", gSaveContext.ship.stats.rtaTiming); + SaveManager::Instance->LoadData("fileCreatedAt", gSaveContext.ship.stats.fileCreatedAt); + SaveManager::Instance->LoadData("playTimer", gSaveContext.ship.stats.playTimer); + SaveManager::Instance->LoadData("pauseTimer", gSaveContext.ship.stats.pauseTimer); + SaveManager::Instance->LoadArray("itemTimestamps", ARRAY_COUNT(gSaveContext.ship.stats.itemTimestamp), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.itemTimestamp[i]); }); - SaveManager::Instance->LoadArray("sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [&](size_t i) { + SaveManager::Instance->LoadArray("sceneTimestamps", ARRAY_COUNT(gSaveContext.ship.stats.sceneTimestamps), [&](size_t i) { SaveManager::Instance->LoadStruct("", [&]() { int scene, room, sceneTime, roomTime, isRoom; SaveManager::Instance->LoadData("scene", scene); @@ -316,63 +316,63 @@ void LoadStatsVersion1() { if (scene == 0 && room == 0 && sceneTime == 0 && roomTime == 0 && isRoom == 0) { return; } - gSaveContext.sohStats.sceneTimestamps[i].scene = scene; - gSaveContext.sohStats.sceneTimestamps[i].room = room; - gSaveContext.sohStats.sceneTimestamps[i].sceneTime = sceneTime; - gSaveContext.sohStats.sceneTimestamps[i].roomTime = roomTime; - gSaveContext.sohStats.sceneTimestamps[i].isRoom = isRoom; + gSaveContext.ship.stats.sceneTimestamps[i].scene = scene; + gSaveContext.ship.stats.sceneTimestamps[i].room = room; + gSaveContext.ship.stats.sceneTimestamps[i].sceneTime = sceneTime; + gSaveContext.ship.stats.sceneTimestamps[i].roomTime = roomTime; + gSaveContext.ship.stats.sceneTimestamps[i].isRoom = isRoom; }); }); - SaveManager::Instance->LoadData("tsIdx", gSaveContext.sohStats.tsIdx); - SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); + SaveManager::Instance->LoadData("tsIdx", gSaveContext.ship.stats.tsIdx); + SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.ship.stats.count), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.count[i]); }); - SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); + SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.ship.stats.scenesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.scenesDiscovered[i]); }); - SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); + SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.ship.stats.entrancesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.entrancesDiscovered[i]); }); } void SaveStats(SaveContext* saveContext, int sectionID, bool fullSave) { - SaveManager::Instance->SaveData("buildVersion", saveContext->sohStats.buildVersion); - SaveManager::Instance->SaveData("buildVersionMajor", saveContext->sohStats.buildVersionMajor); - SaveManager::Instance->SaveData("buildVersionMinor", saveContext->sohStats.buildVersionMinor); - SaveManager::Instance->SaveData("buildVersionPatch", saveContext->sohStats.buildVersionPatch); + SaveManager::Instance->SaveData("buildVersion", saveContext->ship.stats.buildVersion); + SaveManager::Instance->SaveData("buildVersionMajor", saveContext->ship.stats.buildVersionMajor); + SaveManager::Instance->SaveData("buildVersionMinor", saveContext->ship.stats.buildVersionMinor); + SaveManager::Instance->SaveData("buildVersionPatch", saveContext->ship.stats.buildVersionPatch); - SaveManager::Instance->SaveData("heartPieces", saveContext->sohStats.heartPieces); - SaveManager::Instance->SaveData("heartContainers", saveContext->sohStats.heartContainers); - SaveManager::Instance->SaveArray("dungeonKeys", ARRAY_COUNT(saveContext->sohStats.dungeonKeys), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.dungeonKeys[i]); + SaveManager::Instance->SaveData("heartPieces", saveContext->ship.stats.heartPieces); + SaveManager::Instance->SaveData("heartContainers", saveContext->ship.stats.heartContainers); + SaveManager::Instance->SaveArray("dungeonKeys", ARRAY_COUNT(saveContext->ship.stats.dungeonKeys), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->ship.stats.dungeonKeys[i]); }); - SaveManager::Instance->SaveData("rtaTiming", saveContext->sohStats.rtaTiming); - SaveManager::Instance->SaveData("fileCreatedAt", saveContext->sohStats.fileCreatedAt); - SaveManager::Instance->SaveData("playTimer", saveContext->sohStats.playTimer); - SaveManager::Instance->SaveData("pauseTimer", saveContext->sohStats.pauseTimer); - SaveManager::Instance->SaveArray("itemTimestamps", ARRAY_COUNT(saveContext->sohStats.itemTimestamp), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.itemTimestamp[i]); + SaveManager::Instance->SaveData("rtaTiming", saveContext->ship.stats.rtaTiming); + SaveManager::Instance->SaveData("fileCreatedAt", saveContext->ship.stats.fileCreatedAt); + SaveManager::Instance->SaveData("playTimer", saveContext->ship.stats.playTimer); + SaveManager::Instance->SaveData("pauseTimer", saveContext->ship.stats.pauseTimer); + SaveManager::Instance->SaveArray("itemTimestamps", ARRAY_COUNT(saveContext->ship.stats.itemTimestamp), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->ship.stats.itemTimestamp[i]); }); - SaveManager::Instance->SaveArray("sceneTimestamps", ARRAY_COUNT(saveContext->sohStats.sceneTimestamps), [&](size_t i) { - if (saveContext->sohStats.sceneTimestamps[i].scene != 254 && saveContext->sohStats.sceneTimestamps[i].room != 254) { + SaveManager::Instance->SaveArray("sceneTimestamps", ARRAY_COUNT(saveContext->ship.stats.sceneTimestamps), [&](size_t i) { + if (saveContext->ship.stats.sceneTimestamps[i].scene != 254 && saveContext->ship.stats.sceneTimestamps[i].room != 254) { SaveManager::Instance->SaveStruct("", [&]() { - SaveManager::Instance->SaveData("scene", saveContext->sohStats.sceneTimestamps[i].scene); - SaveManager::Instance->SaveData("room", saveContext->sohStats.sceneTimestamps[i].room); - SaveManager::Instance->SaveData("sceneTime", saveContext->sohStats.sceneTimestamps[i].sceneTime); - SaveManager::Instance->SaveData("roomTime", saveContext->sohStats.sceneTimestamps[i].roomTime); - SaveManager::Instance->SaveData("isRoom", saveContext->sohStats.sceneTimestamps[i].isRoom); + SaveManager::Instance->SaveData("scene", saveContext->ship.stats.sceneTimestamps[i].scene); + SaveManager::Instance->SaveData("room", saveContext->ship.stats.sceneTimestamps[i].room); + SaveManager::Instance->SaveData("sceneTime", saveContext->ship.stats.sceneTimestamps[i].sceneTime); + SaveManager::Instance->SaveData("roomTime", saveContext->ship.stats.sceneTimestamps[i].roomTime); + SaveManager::Instance->SaveData("isRoom", saveContext->ship.stats.sceneTimestamps[i].isRoom); }); } }); - SaveManager::Instance->SaveData("tsIdx", saveContext->sohStats.tsIdx); - SaveManager::Instance->SaveArray("counts", ARRAY_COUNT(saveContext->sohStats.count), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.count[i]); + SaveManager::Instance->SaveData("tsIdx", saveContext->ship.stats.tsIdx); + SaveManager::Instance->SaveArray("counts", ARRAY_COUNT(saveContext->ship.stats.count), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->ship.stats.count[i]); }); - SaveManager::Instance->SaveArray("scenesDiscovered", ARRAY_COUNT(saveContext->sohStats.scenesDiscovered), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.scenesDiscovered[i]); + SaveManager::Instance->SaveArray("scenesDiscovered", ARRAY_COUNT(saveContext->ship.stats.scenesDiscovered), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->ship.stats.scenesDiscovered[i]); }); - SaveManager::Instance->SaveArray("entrancesDiscovered", ARRAY_COUNT(saveContext->sohStats.entrancesDiscovered), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.entrancesDiscovered[i]); + SaveManager::Instance->SaveArray("entrancesDiscovered", ARRAY_COUNT(saveContext->ship.stats.entrancesDiscovered), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->ship.stats.entrancesDiscovered[i]); }); } @@ -443,16 +443,16 @@ void DrawGameplayStatsHeader() { } else { GameplayStatsRow("Build Version:", (char*)gBuildVersion); } - if (gSaveContext.sohStats.rtaTiming) { - GameplayStatsRow("Total Time (RTA):", formatTimestampGameplayStat(GAMEPLAYSTAT_TOTAL_TIME), gSaveContext.sohStats.gameComplete ? COLOR_GREEN : COLOR_WHITE); + if (gSaveContext.ship.stats.rtaTiming) { + GameplayStatsRow("Total Time (RTA):", formatTimestampGameplayStat(GAMEPLAYSTAT_TOTAL_TIME), gSaveContext.ship.stats.gameComplete ? COLOR_GREEN : COLOR_WHITE); } else { - GameplayStatsRow("Total Game Time:", formatTimestampGameplayStat(GAMEPLAYSTAT_TOTAL_TIME), gSaveContext.sohStats.gameComplete ? COLOR_GREEN : COLOR_WHITE); + GameplayStatsRow("Total Game Time:", formatTimestampGameplayStat(GAMEPLAYSTAT_TOTAL_TIME), gSaveContext.ship.stats.gameComplete ? COLOR_GREEN : COLOR_WHITE); } if (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.ShowAdditionalTimers"), 0)) { // !Only display total game time - GameplayStatsRow("Gameplay Time:", formatTimestampGameplayStat(gSaveContext.sohStats.playTimer / 2), COLOR_GREY); - GameplayStatsRow("Pause Menu Time:", formatTimestampGameplayStat(gSaveContext.sohStats.pauseTimer / 3), COLOR_GREY); - GameplayStatsRow("Time in scene:", formatTimestampGameplayStat(gSaveContext.sohStats.sceneTimer / 2), COLOR_LIGHT_BLUE); - GameplayStatsRow("Time in room:", formatTimestampGameplayStat(gSaveContext.sohStats.roomTimer / 2), COLOR_LIGHT_BLUE); + GameplayStatsRow("Gameplay Time:", formatTimestampGameplayStat(gSaveContext.ship.stats.playTimer / 2), COLOR_GREY); + GameplayStatsRow("Pause Menu Time:", formatTimestampGameplayStat(gSaveContext.ship.stats.pauseTimer / 3), COLOR_GREY); + GameplayStatsRow("Time in scene:", formatTimestampGameplayStat(gSaveContext.ship.stats.sceneTimer / 2), COLOR_LIGHT_BLUE); + GameplayStatsRow("Time in room:", formatTimestampGameplayStat(gSaveContext.ship.stats.roomTimer / 2), COLOR_LIGHT_BLUE); } if (gPlayState != NULL && CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.ShowDebugInfo"), 0)) { // && display debug info GameplayStatsRow("play->sceneNum:", formatHexGameplayStat(gPlayState->sceneNum), COLOR_YELLOW); @@ -468,7 +468,7 @@ void DrawGameplayStatsTimestampsTab() { // Set up the array of item timestamps and then sort it chronologically for (int i = 0; i < TIMESTAMP_MAX; i++) { strcpy(itemTimestampDisplay[i].name, itemTimestampDisplayName[i]); - itemTimestampDisplay[i].time = gSaveContext.sohStats.itemTimestamp[i]; + itemTimestampDisplay[i].time = gSaveContext.ship.stats.itemTimestamp[i]; itemTimestampDisplay[i].color = itemTimestampDisplayColor[i]; } @@ -497,18 +497,18 @@ void DrawGameplayStatsCountsTab() { for (int i = COUNT_ENEMIES_DEFEATED_ANUBIS; i <= COUNT_ENEMIES_DEFEATED_WOLFOS; i++) { if (i == COUNT_ENEMIES_DEFEATED_FLOORMASTER) { // Special case: You must kill 3 mini Floormasters for it count as one defeated Floormaster - enemiesDefeated += gSaveContext.sohStats.count[i] / 3; + enemiesDefeated += gSaveContext.ship.stats.count[i] / 3; } else { - enemiesDefeated += gSaveContext.sohStats.count[i]; + enemiesDefeated += gSaveContext.ship.stats.count[i]; } } // Sum of all ammo used for (int i = COUNT_AMMO_USED_STICK; i <= COUNT_AMMO_USED_BEAN; i++) { - ammoUsed += gSaveContext.sohStats.count[i]; + ammoUsed += gSaveContext.ship.stats.count[i]; } // Sum of all button presses for (int i = COUNT_BUTTON_PRESSES_A; i <= COUNT_BUTTON_PRESSES_START; i++) { - buttonPresses += gSaveContext.sohStats.count[i]; + buttonPresses += gSaveContext.ship.stats.count[i]; } ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, { 4.0f, 4.0f }); @@ -520,47 +520,47 @@ void DrawGameplayStatsCountsTab() { if (ImGui::TreeNodeEx("Enemy Details...", ImGuiTreeNodeFlags_NoTreePushOnOpen)) { for (int i = COUNT_ENEMIES_DEFEATED_ANUBIS; i <= COUNT_ENEMIES_DEFEATED_WOLFOS; i++) { if (i == COUNT_ENEMIES_DEFEATED_FLOORMASTER) { - GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.sohStats.count[i] / 3)); + GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.ship.stats.count[i] / 3)); } else { - GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.sohStats.count[i])); + GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.ship.stats.count[i])); } } } } - GameplayStatsRow("Rupees Collected:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_RUPEES_COLLECTED])); + GameplayStatsRow("Rupees Collected:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_RUPEES_COLLECTED])); UIWidgets::Tooltip("Includes rupees collected with a full wallet."); - GameplayStatsRow("Rupees Spent:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_RUPEES_SPENT])); - GameplayStatsRow("Chests Opened:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_CHESTS_OPENED])); + GameplayStatsRow("Rupees Spent:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_RUPEES_SPENT])); + GameplayStatsRow("Chests Opened:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_CHESTS_OPENED])); GameplayStatsRow("Ammo Used:", formatIntGameplayStat(ammoUsed)); if (ammoUsed > 0) { ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::TreeNodeEx("Ammo Details...", ImGuiTreeNodeFlags_NoTreePushOnOpen)) { for (int i = COUNT_AMMO_USED_STICK; i <= COUNT_AMMO_USED_BEAN; i++) { - GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.sohStats.count[i])); + GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.ship.stats.count[i])); } } } - GameplayStatsRow("Damage Taken:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_DAMAGE_TAKEN])); - GameplayStatsRow("Sword Swings:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_SWORD_SWINGS])); - GameplayStatsRow("Steps Taken:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_STEPS])); + GameplayStatsRow("Damage Taken:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_DAMAGE_TAKEN])); + GameplayStatsRow("Sword Swings:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_SWORD_SWINGS])); + GameplayStatsRow("Steps Taken:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_STEPS])); // If using MM Bunny Hood enhancement, show how long it's been equipped (not counting pause time) - if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA || gSaveContext.sohStats.count[COUNT_TIME_BUNNY_HOOD] > 0) { - GameplayStatsRow("Bunny Hood Time:", formatTimestampGameplayStat(gSaveContext.sohStats.count[COUNT_TIME_BUNNY_HOOD] / 2)); + if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA || gSaveContext.ship.stats.count[COUNT_TIME_BUNNY_HOOD] > 0) { + GameplayStatsRow("Bunny Hood Time:", formatTimestampGameplayStat(gSaveContext.ship.stats.count[COUNT_TIME_BUNNY_HOOD] / 2)); } - GameplayStatsRow("Rolls:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_ROLLS])); - GameplayStatsRow("Bonks:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_BONKS])); - GameplayStatsRow("Sidehops:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_SIDEHOPS])); - GameplayStatsRow("Backflips:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_BACKFLIPS])); - GameplayStatsRow("Ice Traps:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_ICE_TRAPS])); - GameplayStatsRow("Pauses:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_PAUSES])); - GameplayStatsRow("Pots Smashed:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_POTS_BROKEN])); - GameplayStatsRow("Bushes Cut:", formatIntGameplayStat(gSaveContext.sohStats.count[COUNT_BUSHES_CUT])); + GameplayStatsRow("Rolls:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_ROLLS])); + GameplayStatsRow("Bonks:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_BONKS])); + GameplayStatsRow("Sidehops:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_SIDEHOPS])); + GameplayStatsRow("Backflips:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_BACKFLIPS])); + GameplayStatsRow("Ice Traps:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_ICE_TRAPS])); + GameplayStatsRow("Pauses:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_PAUSES])); + GameplayStatsRow("Pots Smashed:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_POTS_BROKEN])); + GameplayStatsRow("Bushes Cut:", formatIntGameplayStat(gSaveContext.ship.stats.count[COUNT_BUSHES_CUT])); GameplayStatsRow("Buttons Pressed:", formatIntGameplayStat(buttonPresses)); if (buttonPresses > 0) { ImGui::TableNextRow(); ImGui::TableNextColumn(); if (ImGui::TreeNodeEx("Buttons...", ImGuiTreeNodeFlags_NoTreePushOnOpen)) { for (int i = COUNT_BUTTON_PRESSES_A; i <= COUNT_BUTTON_PRESSES_START; i++) { - GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.sohStats.count[i])); + GameplayStatsRow(countMappings[i], formatIntGameplayStat(gSaveContext.ship.stats.count[i])); } } } @@ -569,25 +569,25 @@ void DrawGameplayStatsCountsTab() { } void DrawGameplayStatsBreakdownTab() { - for (int i = 0; i < gSaveContext.sohStats.tsIdx; i++) { - std::string sceneName = ResolveSceneID(gSaveContext.sohStats.sceneTimestamps[i].scene, gSaveContext.sohStats.sceneTimestamps[i].room); + for (int i = 0; i < gSaveContext.ship.stats.tsIdx; i++) { + std::string sceneName = ResolveSceneID(gSaveContext.ship.stats.sceneTimestamps[i].scene, gSaveContext.ship.stats.sceneTimestamps[i].room); std::string name; - if (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) && gSaveContext.sohStats.sceneTimestamps[i].scene != SCENE_GROTTOS) { - name = fmt::format("{:s} Room {:d}", sceneName, gSaveContext.sohStats.sceneTimestamps[i].room); + if (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) && gSaveContext.ship.stats.sceneTimestamps[i].scene != SCENE_GROTTOS) { + name = fmt::format("{:s} Room {:d}", sceneName, gSaveContext.ship.stats.sceneTimestamps[i].room); } else { name = sceneName; } strcpy(sceneTimestampDisplay[i].name, name.c_str()); - sceneTimestampDisplay[i].time = CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) ? - gSaveContext.sohStats.sceneTimestamps[i].roomTime : gSaveContext.sohStats.sceneTimestamps[i].sceneTime; + sceneTimestampDisplay[i].time = CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) ? + gSaveContext.ship.stats.sceneTimestamps[i].roomTime : gSaveContext.ship.stats.sceneTimestamps[i].sceneTime; sceneTimestampDisplay[i].color = COLOR_GREY; - sceneTimestampDisplay[i].isRoom = gSaveContext.sohStats.sceneTimestamps[i].isRoom; + sceneTimestampDisplay[i].isRoom = gSaveContext.ship.stats.sceneTimestamps[i].isRoom; } ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, { 4.0f, 4.0f }); ImGui::BeginTable("gameplayStatsCounts", 1, ImGuiTableFlags_BordersOuter); ImGui::TableSetupColumn("stat", ImGuiTableColumnFlags_WidthStretch); - for (int i = 0; i < gSaveContext.sohStats.tsIdx; i++) { + for (int i = 0; i < gSaveContext.ship.stats.tsIdx; i++) { TimestampInfo tsInfo = sceneTimestampDisplay[i]; bool canShow = !tsInfo.isRoom || CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0); if (tsInfo.time > 0 && strnlen(tsInfo.name, 40) > 1 && canShow) { @@ -595,10 +595,10 @@ void DrawGameplayStatsBreakdownTab() { } } std::string toPass; - if (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) && gSaveContext.sohStats.sceneNum != SCENE_GROTTOS) { - toPass = fmt::format("{:s} Room {:d}", ResolveSceneID(gSaveContext.sohStats.sceneNum, gSaveContext.sohStats.roomNum), gSaveContext.sohStats.roomNum); + if (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) && gSaveContext.ship.stats.sceneNum != SCENE_GROTTOS) { + toPass = fmt::format("{:s} Room {:d}", ResolveSceneID(gSaveContext.ship.stats.sceneNum, gSaveContext.ship.stats.roomNum), gSaveContext.ship.stats.roomNum); } else { - toPass = ResolveSceneID(gSaveContext.sohStats.sceneNum, gSaveContext.sohStats.roomNum); + toPass = ResolveSceneID(gSaveContext.ship.stats.sceneNum, gSaveContext.ship.stats.roomNum); } GameplayStatsRow(toPass.c_str(), formatTimestampGameplayStat(CURRENT_MODE_TIMER / 2)); ImGui::EndTable(); @@ -611,14 +611,14 @@ void DrawGameplayStatsOptionsTab() { UIWidgets::PaddedEnhancementCheckbox("Show latest timestamps on top", CVAR_ENHANCEMENT("GameplayStats.ReverseTimestamps"), true, false); UIWidgets::PaddedEnhancementCheckbox("Room Breakdown", CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), true, false); ImGui::SameLine(); - UIWidgets::InsertHelpHoverText("Allows a more in-depth perspective of time spent in a certain map."); + UIWidgets::InsertHelpHoverText("Allows a more in-depth perspective of time spent in a certain map."); UIWidgets::PaddedEnhancementCheckbox("RTA Timing on new files", CVAR_ENHANCEMENT("GameplayStats.RTATiming"), true, false); ImGui::SameLine(); UIWidgets::InsertHelpHoverText( "Timestamps are relative to starting timestamp rather than in game time, usually necessary for races/speedruns.\n\n" "Starting timestamp is on first non-c-up input after intro cutscene.\n\n" "NOTE: THIS NEEDS TO BE SET BEFORE CREATING A FILE TO TAKE EFFECT" - ); + ); UIWidgets::PaddedEnhancementCheckbox("Show additional detail timers", CVAR_ENHANCEMENT("GameplayStats.ShowAdditionalTimers"), true, false); UIWidgets::PaddedEnhancementCheckbox("Show Debug Info", CVAR_ENHANCEMENT("GameplayStats.ShowDebugInfo")); } @@ -645,46 +645,46 @@ void GameplayStatsWindow::DrawElement() { } ImGui::EndTabBar(); } - + ImGui::Text("Note: Gameplay stats are saved to the current file and will be\nlost if you quit without saving."); } void InitStats(bool isDebug) { - gSaveContext.sohStats.heartPieces = isDebug ? 8 : 0; - gSaveContext.sohStats.heartContainers = isDebug ? 8 : 0; - for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys); dungeon++) { - gSaveContext.sohStats.dungeonKeys[dungeon] = isDebug ? 8 : 0; + gSaveContext.ship.stats.heartPieces = isDebug ? 8 : 0; + gSaveContext.ship.stats.heartContainers = isDebug ? 8 : 0; + for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.ship.stats.dungeonKeys); dungeon++) { + gSaveContext.ship.stats.dungeonKeys[dungeon] = isDebug ? 8 : 0; } - gSaveContext.sohStats.rtaTiming = CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RTATiming"), 0); - gSaveContext.sohStats.fileCreatedAt = 0; - gSaveContext.sohStats.playTimer = 0; - gSaveContext.sohStats.pauseTimer = 0; - for (int timestamp = 0; timestamp < ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp); timestamp++) { - gSaveContext.sohStats.itemTimestamp[timestamp] = 0; + gSaveContext.ship.stats.rtaTiming = CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RTATiming"), 0); + gSaveContext.ship.stats.fileCreatedAt = 0; + gSaveContext.ship.stats.playTimer = 0; + gSaveContext.ship.stats.pauseTimer = 0; + for (int timestamp = 0; timestamp < ARRAY_COUNT(gSaveContext.ship.stats.itemTimestamp); timestamp++) { + gSaveContext.ship.stats.itemTimestamp[timestamp] = 0; } - for (int timestamp = 0; timestamp < ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps); timestamp++) { - gSaveContext.sohStats.sceneTimestamps[timestamp].sceneTime = 0; - gSaveContext.sohStats.sceneTimestamps[timestamp].roomTime = 0; - gSaveContext.sohStats.sceneTimestamps[timestamp].scene = 254; - gSaveContext.sohStats.sceneTimestamps[timestamp].room = 254; - gSaveContext.sohStats.sceneTimestamps[timestamp].isRoom = 0; + for (int timestamp = 0; timestamp < ARRAY_COUNT(gSaveContext.ship.stats.sceneTimestamps); timestamp++) { + gSaveContext.ship.stats.sceneTimestamps[timestamp].sceneTime = 0; + gSaveContext.ship.stats.sceneTimestamps[timestamp].roomTime = 0; + gSaveContext.ship.stats.sceneTimestamps[timestamp].scene = 254; + gSaveContext.ship.stats.sceneTimestamps[timestamp].room = 254; + gSaveContext.ship.stats.sceneTimestamps[timestamp].isRoom = 0; } - gSaveContext.sohStats.tsIdx = 0; - for (int count = 0; count < ARRAY_COUNT(gSaveContext.sohStats.count); count++) { - gSaveContext.sohStats.count[count] = 0; + gSaveContext.ship.stats.tsIdx = 0; + for (int count = 0; count < ARRAY_COUNT(gSaveContext.ship.stats.count); count++) { + gSaveContext.ship.stats.count[count] = 0; } - gSaveContext.sohStats.gameComplete = false; - for (int scenesIdx = 0; scenesIdx < ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered); scenesIdx++) { - gSaveContext.sohStats.scenesDiscovered[scenesIdx] = 0; + gSaveContext.ship.stats.gameComplete = false; + for (int scenesIdx = 0; scenesIdx < ARRAY_COUNT(gSaveContext.ship.stats.scenesDiscovered); scenesIdx++) { + gSaveContext.ship.stats.scenesDiscovered[scenesIdx] = 0; } - for (int entrancesIdx = 0; entrancesIdx < ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered); entrancesIdx++) { - gSaveContext.sohStats.entrancesDiscovered[entrancesIdx] = 0; + for (int entrancesIdx = 0; entrancesIdx < ARRAY_COUNT(gSaveContext.ship.stats.entrancesDiscovered); entrancesIdx++) { + gSaveContext.ship.stats.entrancesDiscovered[entrancesIdx] = 0; } - SohUtils::CopyStringToCharArray(gSaveContext.sohStats.buildVersion, std::string((char*)gBuildVersion), - ARRAY_COUNT(gSaveContext.sohStats.buildVersion)); - gSaveContext.sohStats.buildVersionMajor = gBuildVersionMajor; - gSaveContext.sohStats.buildVersionMinor = gBuildVersionMinor; - gSaveContext.sohStats.buildVersionPatch = gBuildVersionPatch; + SohUtils::CopyStringToCharArray(gSaveContext.ship.stats.buildVersion, std::string((char*)gBuildVersion), + ARRAY_COUNT(gSaveContext.ship.stats.buildVersion)); + gSaveContext.ship.stats.buildVersionMajor = gBuildVersionMajor; + gSaveContext.ship.stats.buildVersionMinor = gBuildVersionMinor; + gSaveContext.ship.stats.buildVersionPatch = gBuildVersionPatch; } // Entries listed here will have a timestamp shown in the stat window diff --git a/soh/soh/Enhancements/gameplaystats.h b/soh/soh/Enhancements/gameplaystats.h index 9d41f2560..27d811b8a 100644 --- a/soh/soh/Enhancements/gameplaystats.h +++ b/soh/soh/Enhancements/gameplaystats.h @@ -19,14 +19,14 @@ extern "C" { // Total gameplay time is tracked in tenths of seconds // I.E. game time counts frames at 20fps/2, pause time counts frames at 30fps/3 // Frame counts in z_play.c and z_kaleido_scope_call.c -#define GAMEPLAYSTAT_TOTAL_TIME (gSaveContext.sohStats.rtaTiming ?\ - (!gSaveContext.sohStats.gameComplete ?\ - (!gSaveContext.sohStats.fileCreatedAt ? 0 : ((GetUnixTimestamp() - gSaveContext.sohStats.fileCreatedAt) / 100)) :\ - (gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GANON])) :\ - (gSaveContext.sohStats.playTimer / 2 + gSaveContext.sohStats.pauseTimer / 3)) +#define GAMEPLAYSTAT_TOTAL_TIME (gSaveContext.ship.stats.rtaTiming ?\ + (!gSaveContext.ship.stats.gameComplete ?\ + (!gSaveContext.ship.stats.fileCreatedAt ? 0 : ((GetUnixTimestamp() - gSaveContext.ship.stats.fileCreatedAt) / 100)) :\ + (gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_GANON])) :\ + (gSaveContext.ship.stats.playTimer / 2 + gSaveContext.ship.stats.pauseTimer / 3)) #define CURRENT_MODE_TIMER (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.RoomBreakdown"), 0) ?\ - gSaveContext.sohStats.roomTimer :\ - gSaveContext.sohStats.sceneTimer) + gSaveContext.ship.stats.roomTimer :\ + gSaveContext.ship.stats.sceneTimer) void InitStatTracker(); diff --git a/soh/soh/Enhancements/kaleido.cpp b/soh/soh/Enhancements/kaleido.cpp index 36cf9d0a2..42c135c94 100644 --- a/soh/soh/Enhancements/kaleido.cpp +++ b/soh/soh/Enhancements/kaleido.cpp @@ -124,7 +124,7 @@ namespace Rando { mEntries.push_back( std::make_shared( gTriforcePieceTex, G_IM_FMT_RGBA, G_IM_SIZ_32b, 32, 32, Color_RGBA8{ 255,255,255,255 }, 0, - yOffset, reinterpret_cast(&gSaveContext.triforcePiecesCollected), + yOffset, reinterpret_cast(&gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected), ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).GetContextOptionIndex() + 1, ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_TOTAL).GetContextOptionIndex() + 1)); yOffset += 18; diff --git a/soh/soh/Enhancements/mods.cpp b/soh/soh/Enhancements/mods.cpp index ac76ef53d..19cd34b89 100644 --- a/soh/soh/Enhancements/mods.cpp +++ b/soh/soh/Enhancements/mods.cpp @@ -272,7 +272,7 @@ void AutoSave(GetItemEntry itemEntry) { // 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 - if ((CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) != AUTOSAVE_OFF) && (gPlayState != NULL) && (gSaveContext.pendingSale == ITEM_NONE) && + if ((CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) != AUTOSAVE_OFF) && (gPlayState != NULL) && (gSaveContext.ship.pendingSale == ITEM_NONE) && (gPlayState->gameplayFrames > 60 && gSaveContext.cutsceneIndex < 0xFFF0) && (gPlayState->sceneNum != SCENE_GANON_BOSS) && (gPlayState->sceneNum != SCENE_CHAMBER_OF_THE_SAGES)) { if (((CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) == AUTOSAVE_LOCATION_AND_ALL_ITEMS) || (CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) == AUTOSAVE_ALL_ITEMS)) && (item != ITEM_NONE)) { // Autosave for all items @@ -409,8 +409,8 @@ void UpdatePermanentHeartLossState() { if (!GameInteractor::IsSaveLoaded()) return; if (!CVarGetInteger(CVAR_ENHANCEMENT("PermanentHeartLoss"), 0) && hasAffectedHealth) { - uint8_t heartContainers = gSaveContext.sohStats.heartContainers; // each worth 16 health - uint8_t heartPieces = gSaveContext.sohStats.heartPieces; // each worth 4 health, but only in groups of 4 + uint8_t heartContainers = gSaveContext.ship.stats.heartContainers; // each worth 16 health + uint8_t heartPieces = gSaveContext.ship.stats.heartPieces; // each worth 4 health, but only in groups of 4 uint8_t startingHealth = 16 * (IS_RANDO ? (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_STARTING_HEARTS) + 1) : 3); @@ -508,7 +508,7 @@ void RegisterDaytimeGoldSkultullas() { bool IsHyperBossesActive() { return CVarGetInteger(CVAR_ENHANCEMENT("HyperBosses"), 0) || - (IS_BOSS_RUSH && gSaveContext.bossRushOptions[BR_OPTIONS_HYPERBOSSES] == BR_CHOICE_HYPERBOSSES_YES); + (IS_BOSS_RUSH && gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_HYPERBOSSES] == BR_CHOICE_HYPERBOSSES_YES); } void UpdateHyperBossesState() { @@ -667,7 +667,7 @@ void UpdateMirrorModeState(int32_t sceneNum) { if (mirroredMode == MIRRORED_WORLD_RANDOM_SEEDED || mirroredMode == MIRRORED_WORLD_DUNGEONS_RANDOM_SEEDED) { uint32_t seed = sceneNum + (IS_RANDO ? Rando::Context::GetInstance()->GetSettings()->GetSeed() - : gSaveContext.sohStats.fileCreatedAt); + : gSaveContext.ship.stats.fileCreatedAt); Random_Init(seed); } @@ -849,60 +849,60 @@ void RegisterEnemyDefeatCounts() { GameInteractor::Instance->RegisterGameHook([](void* refActor) { Actor* actor = static_cast(refActor); if (uniqueEnemyIdToStatCount.contains(actor->id)) { - gSaveContext.sohStats.count[uniqueEnemyIdToStatCount[actor->id]]++; + gSaveContext.ship.stats.count[uniqueEnemyIdToStatCount[actor->id]]++; } else { switch (actor->id) { case ACTOR_EN_BB: if (actor->params == ENBB_GREEN || actor->params == ENBB_GREEN_BIG) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_GREEN]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_GREEN]++; } else if (actor->params == ENBB_BLUE) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_BLUE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_BLUE]++; } else if (actor->params == ENBB_WHITE) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_WHITE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_WHITE]++; } else if (actor->params == ENBB_RED) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_RED]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_BUBBLE_RED]++; } break; case ACTOR_EN_DEKUBABA: if (actor->params == DEKUBABA_BIG) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DEKU_BABA_BIG]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_DEKU_BABA_BIG]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DEKU_BABA]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_DEKU_BABA]++; } break; case ACTOR_EN_ZF: if (actor->params == ENZF_TYPE_DINOLFOS) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_DINOLFOS]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_DINOLFOS]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_LIZALFOS]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_LIZALFOS]++; } break; case ACTOR_EN_RD: if (actor->params >= -1) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_REDEAD]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_REDEAD]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_GIBDO]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_GIBDO]++; } break; case ACTOR_EN_IK: if (actor->params == 0) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_IRON_KNUCKLE_NABOORU]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_IRON_KNUCKLE_NABOORU]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_IRON_KNUCKLE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_IRON_KNUCKLE]++; } break; case ACTOR_EN_FIREFLY: if (actor->params == KEESE_NORMAL_FLY || actor->params == KEESE_NORMAL_PERCH) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_KEESE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_KEESE]++; } else if (actor->params == KEESE_FIRE_FLY || actor->params == KEESE_FIRE_PERCH) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_KEESE_FIRE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_KEESE_FIRE]++; } else if (actor->params == KEESE_ICE_FLY) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_KEESE_ICE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_KEESE_ICE]++; } break; @@ -910,80 +910,80 @@ void RegisterEnemyDefeatCounts() { { EnReeba* reeba = (EnReeba*)actor; if (reeba->isBig) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_LEEVER_BIG]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_LEEVER_BIG]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_LEEVER]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_LEEVER]++; } } break; case ACTOR_EN_MB: if (actor->params == 0) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_MOBLIN_CLUB]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_MOBLIN_CLUB]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_MOBLIN]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_MOBLIN]++; } break; case ACTOR_EN_PEEHAT: if (actor->params == PEAHAT_TYPE_LARVA) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_PEAHAT_LARVA]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_PEAHAT_LARVA]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_PEAHAT]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_PEAHAT]++; } break; - + case ACTOR_EN_POH: if (actor->params == EN_POH_FLAT || actor->params == EN_POH_SHARP) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE_COMPOSER]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_POE_COMPOSER]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_POE]++; } break; case ACTOR_EN_PO_FIELD: if (actor->params == EN_PO_FIELD_BIG) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE_BIG]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_POE_BIG]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_POE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_POE]++; } break; case ACTOR_EN_ST: if (actor->params == 1) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA_BIG]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA_BIG]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA]++; } break; case ACTOR_EN_SW: if (((actor->params & 0xE000) >> 0xD) != 0) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA_GOLD]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_SKULLTULA_GOLD]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_SKULLWALLTULA]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_SKULLWALLTULA]++; } break; case ACTOR_EN_TP: if (actor->params == TAILPASARAN_HEAD) { // Only count the head, otherwise each body segment will increment - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_TAILPASARAN]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_TAILPASARAN]++; } break; case ACTOR_EN_TITE: if (actor->params == TEKTITE_BLUE) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_TEKTITE_BLUE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_TEKTITE_BLUE]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_TEKTITE_RED]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_TEKTITE_RED]++; } break; case ACTOR_EN_WF: if (actor->params == WOLFOS_WHITE) { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_WOLFOS_WHITE]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_WOLFOS_WHITE]++; } else { - gSaveContext.sohStats.count[COUNT_ENEMIES_DEFEATED_WOLFOS]++; + gSaveContext.ship.stats.count[COUNT_ENEMIES_DEFEATED_WOLFOS]++; } break; } @@ -996,35 +996,35 @@ void RegisterBossDefeatTimestamps() { Actor* actor = static_cast(refActor); switch (actor->id) { case ACTOR_BOSS_DODONGO: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_KING_DODONGO] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_KING_DODONGO] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_FD2: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_VOLVAGIA] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_VOLVAGIA] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_GANON: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GANONDORF] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_GANONDORF] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_GANON2: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GANON] = GAMEPLAYSTAT_TOTAL_TIME; - gSaveContext.sohStats.gameComplete = true; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_GANON] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.gameComplete = true; break; case ACTOR_BOSS_GANONDROF: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_PHANTOM_GANON] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_PHANTOM_GANON] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_GOMA: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GOHMA] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_GOHMA] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_MO: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_MORPHA] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_MORPHA] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_SST: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_BONGO_BONGO] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_BONGO_BONGO] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_TW: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_TWINROVA] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_TWINROVA] = GAMEPLAYSTAT_TOTAL_TIME; break; case ACTOR_BOSS_VA: - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_BARINADE] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_BARINADE] = GAMEPLAYSTAT_TOTAL_TIME; break; } }); @@ -1193,10 +1193,10 @@ void UpdateHurtContainerModeState(bool newState) { } hurtEnabled = newState; - uint16_t getHeartPieces = gSaveContext.sohStats.heartPieces / 4; - uint16_t getHeartContainers = gSaveContext.sohStats.heartContainers; - - if (hurtEnabled) { + uint16_t getHeartPieces = gSaveContext.ship.stats.heartPieces / 4; + uint16_t getHeartContainers = gSaveContext.ship.stats.heartContainers; + + if (hurtEnabled) { gSaveContext.healthCapacity = 320 - ((getHeartPieces + getHeartContainers) * 16); } else { gSaveContext.healthCapacity = 48 + ((getHeartPieces + getHeartContainers) * 16); diff --git a/soh/soh/Enhancements/randomizer/adult_trade_shuffle.c b/soh/soh/Enhancements/randomizer/adult_trade_shuffle.c index c1acc100b..4bf481d2a 100644 --- a/soh/soh/Enhancements/randomizer/adult_trade_shuffle.c +++ b/soh/soh/Enhancements/randomizer/adult_trade_shuffle.c @@ -4,7 +4,7 @@ #include "macros.h" void Randomizer_ConsumeAdultTradeItem(PlayState* play, u8 itemId) { - gSaveContext.adultTradeItems &= ~ADULT_TRADE_FLAG(itemId); + gSaveContext.ship.quest.data.randomizer.adultTradeItems &= ~ADULT_TRADE_FLAG(itemId); Inventory_ReplaceItem(play, itemId, Randomizer_GetNextAdultTradeItem()); } @@ -13,7 +13,7 @@ u8 Randomizer_GetNextAdultTradeItem() { u8 currentTradeItemIndex = INV_CONTENT(ITEM_TRADE_ADULT) - ITEM_POCKET_EGG; for (int i = 0; i < numTradeItems; i++) { u8 tradeIndex = (currentTradeItemIndex + i + 1) % numTradeItems; - if (gSaveContext.adultTradeItems & (1 << tradeIndex)) { + if (gSaveContext.ship.quest.data.randomizer.adultTradeItems & (1 << tradeIndex)) { return ITEM_POCKET_EGG + tradeIndex; } } @@ -25,7 +25,7 @@ u8 Randomizer_GetPrevAdultTradeItem() { u8 currentTradeItemIndex = INV_CONTENT(ITEM_TRADE_ADULT) - ITEM_POCKET_EGG; for (int i = 0; i < numTradeItems; i++) { u8 tradeIndex = (currentTradeItemIndex - i - 1 + numTradeItems) % numTradeItems; - if (gSaveContext.adultTradeItems & (1 << tradeIndex)) { + if (gSaveContext.ship.quest.data.randomizer.adultTradeItems & (1 << tradeIndex)) { return ITEM_POCKET_EGG + tradeIndex; } } diff --git a/soh/soh/Enhancements/randomizer/adult_trade_shuffle.h b/soh/soh/Enhancements/randomizer/adult_trade_shuffle.h index 13d905026..f9894cf4e 100644 --- a/soh/soh/Enhancements/randomizer/adult_trade_shuffle.h +++ b/soh/soh/Enhancements/randomizer/adult_trade_shuffle.h @@ -4,7 +4,7 @@ #include #define ADULT_TRADE_FLAG(itemId) (1 << (itemId - ITEM_POCKET_EGG)) -#define PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(itemID) (gSaveContext.adultTradeItems & ADULT_TRADE_FLAG(itemID)) +#define PLAYER_HAS_SHUFFLED_ADULT_TRADE_ITEM(itemID) (IS_RANDO && gSaveContext.ship.quest.data.randomizer.adultTradeItems & ADULT_TRADE_FLAG(itemID)) void Randomizer_ConsumeAdultTradeItem(PlayState* play, u8 itemId); u8 Randomizer_GetNextAdultTradeItem(); diff --git a/soh/soh/Enhancements/randomizer/draw.cpp b/soh/soh/Enhancements/randomizer/draw.cpp index bd7f92a84..f83786fd9 100644 --- a/soh/soh/Enhancements/randomizer/draw.cpp +++ b/soh/soh/Enhancements/randomizer/draw.cpp @@ -263,7 +263,7 @@ extern "C" void Randomizer_DrawTriforcePiece(PlayState* play, GetItemEntry getIt Gfx_SetupDL_25Xlu(play->state.gfxCtx); - uint8_t current = gSaveContext.triforcePiecesCollected; + uint8_t current = gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected; Matrix_Scale(0.035f, 0.035f, 0.035f, MTXMODE_APPLY); @@ -287,7 +287,7 @@ extern "C" void Randomizer_DrawTriforcePieceGI(PlayState* play, GetItemEntry get Gfx_SetupDL_25Xlu(play->state.gfxCtx); - uint8_t current = gSaveContext.triforcePiecesCollected; + uint8_t current = gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected; uint8_t required = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1; Matrix_Scale(triforcePieceScale, triforcePieceScale, triforcePieceScale, MTXMODE_APPLY); diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index 86fb79418..14d4195d0 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -1010,7 +1010,7 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l Item_Give(gPlayState, item00->itemEntry.itemId); } else if (item00->itemEntry.modIndex == MOD_RANDOMIZER) { if (item00->itemEntry.getItemId == RG_ICE_TRAP) { - gSaveContext.pendingIceTrapCount++; + gSaveContext.ship.pendingIceTrapCount++; } else { Randomizer_Item_Give(gPlayState, item00->itemEntry); } diff --git a/soh/soh/Enhancements/randomizer/location_access.cpp b/soh/soh/Enhancements/randomizer/location_access.cpp index 7c9cf7e7f..d3a17a0b9 100644 --- a/soh/soh/Enhancements/randomizer/location_access.cpp +++ b/soh/soh/Enhancements/randomizer/location_access.cpp @@ -267,7 +267,7 @@ void RegionTable_Init() { }, { //Locations LOCATION(RC_LINKS_POCKET, true), - LOCATION(RC_TRIFORCE_COMPLETED, logic->GetSaveContext()->triforcePiecesCollected >= ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).GetContextOptionIndex() + 1;), + LOCATION(RC_TRIFORCE_COMPLETED, logic->GetSaveContext()->ship.quest.data.randomizer.triforcePiecesCollected >= ctx->GetOption(RSK_TRIFORCE_HUNT_PIECES_REQUIRED).GetContextOptionIndex() + 1;), LOCATION(RC_SARIA_SONG_HINT, logic->CanUse(RG_SARIAS_SONG)), }, { //Exits diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index 2b92484b3..85104d825 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -1625,7 +1625,7 @@ namespace Rando { SetRandoInf(RandoGetToRandInf.at(randoGet), state); break; case RG_TRIFORCE_PIECE: - mSaveContext->triforcePiecesCollected += (!state ? -1 : 1); + mSaveContext->ship.quest.data.randomizer.triforcePiecesCollected += (!state ? -1 : 1); break; case RG_BOMBCHU_5: case RG_BOMBCHU_10: @@ -1881,14 +1881,13 @@ namespace Rando { mSaveContext->sceneFlags[5].swch = 0x40000000; // SoH specific - mSaveContext->backupFW = mSaveContext->fw; - mSaveContext->pendingSale = ITEM_NONE; - mSaveContext->pendingSaleMod = MOD_NONE; - mSaveContext->isBossRushPaused = 0; - mSaveContext->pendingIceTrapCount = 0; + mSaveContext->ship.backupFW = mSaveContext->fw; + mSaveContext->ship.pendingSale = ITEM_NONE; + mSaveContext->ship.pendingSaleMod = MOD_NONE; + mSaveContext->ship.pendingIceTrapCount = 0; // Init with normal quest unless only an MQ rom is provided - mSaveContext->questId = OTRGlobals::Instance->HasOriginal() ? QUEST_NORMAL : QUEST_MASTER; + mSaveContext->ship.quest.id = OTRGlobals::Instance->HasOriginal() ? QUEST_NORMAL : QUEST_MASTER; //RANDOTODO (ADD ITEMLOCATIONS TO GSAVECONTEXT) } @@ -1937,16 +1936,16 @@ namespace Rando { bool Logic::HasAdultTrade(uint32_t itemID) { int tradeIndex = itemID - ITEM_POCKET_EGG; - return mSaveContext->adultTradeItems & (1 << tradeIndex); + return mSaveContext->ship.quest.data.randomizer.adultTradeItems & (1 << tradeIndex); } void Logic::SetAdultTrade(uint32_t itemID, bool state) { int tradeIndex = itemID - ITEM_POCKET_EGG; if (!state) { - mSaveContext->adultTradeItems &= ~(1 << tradeIndex); + mSaveContext->ship.quest.data.randomizer.adultTradeItems &= ~(1 << tradeIndex); } else { - mSaveContext->adultTradeItems |= (1 << tradeIndex); + mSaveContext->ship.quest.data.randomizer.adultTradeItems |= (1 << tradeIndex); } } @@ -1981,15 +1980,15 @@ namespace Rando { } bool Logic::CheckRandoInf(uint32_t flag) { - return mSaveContext->randomizerInf[flag >> 4] & (1 << (flag & 0xF)); + return mSaveContext->ship.randomizerInf[flag >> 4] & (1 << (flag & 0xF)); } void Logic::SetRandoInf(uint32_t flag, bool state) { if (!state) { - mSaveContext->randomizerInf[flag >> 4] &= ~(1 << (flag & 0xF)); + mSaveContext->ship.randomizerInf[flag >> 4] &= ~(1 << (flag & 0xF)); } else { - mSaveContext->randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); + mSaveContext->ship.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); } } diff --git a/soh/soh/Enhancements/randomizer/randomizer.cpp b/soh/soh/Enhancements/randomizer/randomizer.cpp index b6c520ceb..1dcdb5506 100644 --- a/soh/soh/Enhancements/randomizer/randomizer.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer.cpp @@ -2787,7 +2787,7 @@ void CreateTriforcePieceMessages() { CustomMessage Randomizer::GetTriforcePieceMessage() { // Item is only given after the textbox, so reflect that inside the textbox. - uint8_t current = gSaveContext.triforcePiecesCollected + 1; + uint8_t current = gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected + 1; uint8_t required = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1; uint8_t remaining = required - current; float percentageCollected = (float)current / (float)required; @@ -3330,7 +3330,7 @@ void CreateFireTempleGoronMessages() { CustomMessage Randomizer::GetGoronMessage(u16 index) { CustomMessage messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, goronIDs[index]); messageEntry.Replace("[[days]]", std::to_string(gSaveContext.totalDays)); - messageEntry.Replace("[[a_btn]]", std::to_string(gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_A])); + messageEntry.Replace("[[a_btn]]", std::to_string(gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_A])); messageEntry.Format(); return messageEntry; } @@ -3339,15 +3339,15 @@ void Randomizer::CreateCustomMessages() { // RANDTODO: Translate into french and german and replace GIMESSAGE_UNTRANSLATED // with GIMESSAGE(getItemID, itemID, english, german, french). const std::array getItemMessages = {{ - GIMESSAGE(RG_GREG_RUPEE, ITEM_MASK_GORON, + GIMESSAGE(RG_GREG_RUPEE, ITEM_MASK_GORON, "You found %gGreg%w!", "%gGreg%w! Du hast ihn wirklich gefunden!", "Félicitation! Vous avez trouvé %gGreg%w!"), - GIMESSAGE(RG_MASTER_SWORD, ITEM_SWORD_MASTER, + GIMESSAGE(RG_MASTER_SWORD, ITEM_SWORD_MASTER, "You found the %gMaster Sword%w!", "Du erhältst das %gMaster-Schwert%w!", "Vous obtenez %gl'Épée de Légende%w!"), - GIMESSAGE(RG_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE, + GIMESSAGE(RG_BOTTLE_WITH_BLUE_FIRE, ITEM_BLUE_FIRE, "You got a %rBottle with Blue &Fire%w! Use it to melt Red Ice!", "Du erhältst eine %rFlasche mit&blauem Feuer%w! Nutze es um&%rRotes Eis%w zu schmelzen!", "Vous obtenez une %rBouteille avec&une Flamme Bleue%w! Utilisez-la&pour faire fondre la %rGlace&Rouge%w!"), @@ -3453,7 +3453,7 @@ void Randomizer::CreateCustomMessages() { "You found a %yGerudo Training &Grounds %wKeyring!", "Du erhältst ein %rSchlüsselbund%w&für die %yGerudo-Trainingsarena%w!", "Vous obtenez un trousseau de&clés du %yGymnase Gerudo%w!"), - GIMESSAGE(RG_GANONS_CASTLE_KEY_RING, ITEM_KEY_SMALL, + GIMESSAGE(RG_GANONS_CASTLE_KEY_RING, ITEM_KEY_SMALL, "You found a %rGanon's Castle &%wKeyring!", "Du erhältst ein %rSchlüsselbund%w&für %rGanons Schloß%w!", "Vous obtenez un trousseau de&clés du %rChâteau de Ganon%w!"), @@ -3706,28 +3706,28 @@ void Randomizer_GameplayStats_SetTimestamp(uint16_t item) { // Use ITEM_KEY_BOSS to timestamp Ganon's boss key if (item == RG_GANONS_CASTLE_BOSS_KEY) { - gSaveContext.sohStats.itemTimestamp[ITEM_KEY_BOSS] = time; + gSaveContext.ship.stats.itemTimestamp[ITEM_KEY_BOSS] = time; } // Count any bottled item as a bottle if (item >= RG_EMPTY_BOTTLE && item <= RG_BOTTLE_WITH_BIG_POE) { - if (gSaveContext.sohStats.itemTimestamp[ITEM_BOTTLE] == 0) { - gSaveContext.sohStats.itemTimestamp[ITEM_BOTTLE] = time; + if (gSaveContext.ship.stats.itemTimestamp[ITEM_BOTTLE] == 0) { + gSaveContext.ship.stats.itemTimestamp[ITEM_BOTTLE] = time; } return; } // Count any bombchu pack as bombchus if ((item >= RG_BOMBCHU_5 && item <= RG_BOMBCHU_20) || item == RG_PROGRESSIVE_BOMBCHUS) { - if (gSaveContext.sohStats.itemTimestamp[ITEM_BOMBCHU] = 0) { - gSaveContext.sohStats.itemTimestamp[ITEM_BOMBCHU] = time; + if (gSaveContext.ship.stats.itemTimestamp[ITEM_BOMBCHU] = 0) { + gSaveContext.ship.stats.itemTimestamp[ITEM_BOMBCHU] = time; } return; } if (item == RG_MAGIC_SINGLE) { - gSaveContext.sohStats.itemTimestamp[ITEM_SINGLE_MAGIC] = time; + gSaveContext.ship.stats.itemTimestamp[ITEM_SINGLE_MAGIC] = time; } if (item == RG_DOUBLE_DEFENSE) { - gSaveContext.sohStats.itemTimestamp[ITEM_DOUBLE_DEFENSE] = time; + gSaveContext.ship.stats.itemTimestamp[ITEM_DOUBLE_DEFENSE] = time; } } @@ -3920,7 +3920,7 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) { } if ((item >= RG_FOREST_TEMPLE_SMALL_KEY) && (item <= RG_GANONS_CASTLE_SMALL_KEY)) { - gSaveContext.sohStats.dungeonKeys[mapIndex]++; + gSaveContext.ship.stats.dungeonKeys[mapIndex]++; if (gSaveContext.inventory.dungeonKeys[mapIndex] < 0) { gSaveContext.inventory.dungeonKeys[mapIndex] = 1; } else { @@ -3930,7 +3930,7 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) { } if ((item >= RG_FOREST_TEMPLE_KEY_RING) && (item <= RG_GANONS_CASTLE_KEY_RING)) { - gSaveContext.sohStats.dungeonKeys[mapIndex] = numOfKeysOnKeyring; + gSaveContext.ship.stats.dungeonKeys[mapIndex] = numOfKeysOnKeyring; gSaveContext.inventory.dungeonKeys[mapIndex] = numOfKeysOnKeyring; return Return_Item_Entry(giEntry, RG_NONE); } @@ -3989,16 +3989,16 @@ extern "C" u16 Randomizer_Item_Give(PlayState* play, GetItemEntry giEntry) { case RG_GREG_RUPEE: Rupees_ChangeBy(1); Flags_SetRandomizerInf(RAND_INF_GREG_FOUND); - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_FOUND_GREG] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_FOUND_GREG] = GAMEPLAYSTAT_TOTAL_TIME; break; case RG_TRIFORCE_PIECE: - gSaveContext.triforcePiecesCollected++; + gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected++; GameInteractor_SetTriforceHuntPieceGiven(true); // Teleport to credits when goal is reached. - if (gSaveContext.triforcePiecesCollected == (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1)) { - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_TRIFORCE_COMPLETED] = GAMEPLAYSTAT_TOTAL_TIME; - gSaveContext.sohStats.gameComplete = 1; + if (gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected == (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1)) { + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_TRIFORCE_COMPLETED] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.gameComplete = 1; Flags_SetRandomizerInf(RAND_INF_GRANT_GANONS_BOSSKEY); Play_PerformSave(play); GameInteractor_SetTriforceHuntCreditsWarpActive(true); diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index 0af0b0128..ecd572ab9 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -1360,7 +1360,7 @@ bool IsVisibleInCheckTracker(RandomizerCheck rc) { OTRGlobals::Instance->gRandoContext->IsQuestOfLocationActive(rc) ) || (loc->GetRCType() == RCTYPE_SHOP && showShops && !hideShopUnshuffledChecks); } else { - return loc->IsVanillaCompletion() && (!loc->IsDungeon() || (loc->IsDungeon() && loc->GetQuest() == gSaveContext.questId)); + return loc->IsVanillaCompletion() && (!loc->IsDungeon() || (loc->IsDungeon() && loc->GetQuest() == gSaveContext.ship.quest.id)); } } diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance.c b/soh/soh/Enhancements/randomizer/randomizer_entrance.c index 7a492fe9c..14d630005 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance.c +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance.c @@ -740,7 +740,7 @@ u8 Entrance_GetIsSceneDiscovered(u8 sceneNum) { u32 idx = sceneNum / bitsPerIndex; if (idx < SAVEFILE_SCENES_DISCOVERED_IDX_COUNT) { u32 sceneBit = 1 << (sceneNum - (idx * bitsPerIndex)); - return (gSaveContext.sohStats.scenesDiscovered[idx] & sceneBit) != 0; + return (gSaveContext.ship.stats.scenesDiscovered[idx] & sceneBit) != 0; } return 0; } @@ -754,7 +754,7 @@ void Entrance_SetSceneDiscovered(u8 sceneNum) { u32 idx = sceneNum / bitsPerIndex; if (idx < SAVEFILE_SCENES_DISCOVERED_IDX_COUNT) { u32 sceneBit = 1 << (sceneNum - (idx * bitsPerIndex)); - gSaveContext.sohStats.scenesDiscovered[idx] |= sceneBit; + gSaveContext.ship.stats.scenesDiscovered[idx] |= sceneBit; } // Save scenesDiscovered Save_SaveSection(SECTION_ID_SCENES); @@ -765,7 +765,7 @@ u8 Entrance_GetIsEntranceDiscovered(u16 entranceIndex) { u32 idx = entranceIndex / bitsPerIndex; if (idx < SAVEFILE_ENTRANCES_DISCOVERED_IDX_COUNT) { u32 entranceBit = 1 << (entranceIndex - (idx * bitsPerIndex)); - return (gSaveContext.sohStats.entrancesDiscovered[idx] & entranceBit) != 0; + return (gSaveContext.ship.stats.entrancesDiscovered[idx] & entranceBit) != 0; } return 0; } @@ -782,7 +782,7 @@ void Entrance_SetEntranceDiscovered(u16 entranceIndex, u8 isReversedEntrance) { u32 idx = entranceIndex / bitsPerIndex; if (idx < SAVEFILE_ENTRANCES_DISCOVERED_IDX_COUNT) { u32 entranceBit = 1 << (entranceIndex - (idx * bitsPerIndex)); - gSaveContext.sohStats.entrancesDiscovered[idx] |= entranceBit; + gSaveContext.ship.stats.entrancesDiscovered[idx] |= entranceBit; // Set reverse entrance when not decoupled if (!Randomizer_GetSettingValue(RSK_DECOUPLED_ENTRANCES) && !isReversedEntrance) { diff --git a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp index 4c5ba4714..2517923fd 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp @@ -411,17 +411,17 @@ ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) { break; case ITEM_HEART_CONTAINER: result.maxCapacity = result.currentCapacity = 8; - result.currentAmmo = gSaveContext.sohStats.heartContainers; + result.currentAmmo = gSaveContext.ship.stats.heartContainers; break; case ITEM_HEART_PIECE: result.maxCapacity = result.currentCapacity = 36; - result.currentAmmo = gSaveContext.sohStats.heartPieces; + result.currentAmmo = gSaveContext.ship.stats.heartPieces; break; case ITEM_KEY_SMALL: // Though the ammo/capacity naming doesn't really make sense for keys, we are // hijacking the same system to display key counts as there are enough similarities result.currentAmmo = MAX(gSaveContext.inventory.dungeonKeys[item.data], 0); - result.currentCapacity = gSaveContext.sohStats.dungeonKeys[item.data]; + result.currentCapacity = gSaveContext.ship.stats.dungeonKeys[item.data]; switch (item.data) { case SCENE_FOREST_TEMPLE: result.maxCapacity = FOREST_TEMPLE_SMALL_KEY_MAX; @@ -582,11 +582,11 @@ void DrawItemCount(ItemTrackerItem item, bool hideMax) { std::string maxString = ""; uint8_t piecesRequired = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1); uint8_t piecesTotal = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_TRIFORCE_HUNT_PIECES_TOTAL) + 1); - ImU32 currentColor = gSaveContext.triforcePiecesCollected >= piecesRequired ? IM_COL_GREEN : IM_COL_WHITE; + ImU32 currentColor = gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected >= piecesRequired ? IM_COL_GREEN : IM_COL_WHITE; ImU32 maxColor = IM_COL_GREEN; int32_t trackerTriforcePieceNumberDisplayMode = CVarGetInteger(CVAR_TRACKER_ITEM("TriforcePieceCounts"), TRIFORCE_PIECE_COLLECTED_REQUIRED_MAX); - currentString += std::to_string(gSaveContext.triforcePiecesCollected); + currentString += std::to_string(gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected); currentString += "/"; // gItemTrackerTriforcePieceTrack if (trackerTriforcePieceNumberDisplayMode == TRIFORCE_PIECE_COLLECTED_REQUIRED_MAX) { @@ -651,11 +651,11 @@ void DrawItem(ItemTrackerItem item) { switch (item.id) { case ITEM_HEART_CONTAINER: actualItemId = item.id; - hasItem = gSaveContext.sohStats.heartContainers > 0; + hasItem = gSaveContext.ship.stats.heartContainers > 0; break; case ITEM_HEART_PIECE: actualItemId = item.id; - hasItem = gSaveContext.sohStats.heartPieces > 0; + hasItem = gSaveContext.ship.stats.heartPieces > 0; break; case ITEM_MAGIC_SMALL: case ITEM_MAGIC_LARGE: diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp index eb081552f..44a4a859e 100644 --- a/soh/soh/Enhancements/randomizer/savefile.cpp +++ b/soh/soh/Enhancements/randomizer/savefile.cpp @@ -25,7 +25,7 @@ void StartingItemGive(GetItemEntry getItemEntry, RandomizerCheck randomizerCheck Item_Give(NULL, getItemEntry.itemId); } else if (getItemEntry.modIndex == MOD_RANDOMIZER) { if (getItemEntry.getItemId == RG_ICE_TRAP) { - gSaveContext.pendingIceTrapCount++; + gSaveContext.ship.pendingIceTrapCount++; } else { Randomizer_Item_Give(NULL, getItemEntry); } @@ -174,22 +174,22 @@ void SetStartingItems() { } if (Randomizer_GetSettingValue(RSK_KEYSANITY) == RO_DUNGEON_ITEM_LOC_STARTWITH) { - gSaveContext.inventory.dungeonKeys[SCENE_FOREST_TEMPLE] = FOREST_TEMPLE_SMALL_KEY_MAX; // Forest - gSaveContext.sohStats.dungeonKeys[SCENE_FOREST_TEMPLE] = FOREST_TEMPLE_SMALL_KEY_MAX; // Forest - gSaveContext.inventory.dungeonKeys[SCENE_FIRE_TEMPLE] = FIRE_TEMPLE_SMALL_KEY_MAX; // Fire - gSaveContext.sohStats.dungeonKeys[SCENE_FIRE_TEMPLE] = FIRE_TEMPLE_SMALL_KEY_MAX; // Fire - gSaveContext.inventory.dungeonKeys[SCENE_WATER_TEMPLE] = WATER_TEMPLE_SMALL_KEY_MAX; // Water - gSaveContext.sohStats.dungeonKeys[SCENE_WATER_TEMPLE] = WATER_TEMPLE_SMALL_KEY_MAX; // Water - gSaveContext.inventory.dungeonKeys[SCENE_SPIRIT_TEMPLE] = SPIRIT_TEMPLE_SMALL_KEY_MAX; // Spirit - gSaveContext.sohStats.dungeonKeys[SCENE_SPIRIT_TEMPLE] = SPIRIT_TEMPLE_SMALL_KEY_MAX; // Spirit - gSaveContext.inventory.dungeonKeys[SCENE_SHADOW_TEMPLE] = SHADOW_TEMPLE_SMALL_KEY_MAX; // Shadow - gSaveContext.sohStats.dungeonKeys[SCENE_SHADOW_TEMPLE] = SHADOW_TEMPLE_SMALL_KEY_MAX; // Shadow - gSaveContext.inventory.dungeonKeys[SCENE_BOTTOM_OF_THE_WELL] = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX; // BotW - gSaveContext.sohStats.dungeonKeys[SCENE_BOTTOM_OF_THE_WELL] = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX; // BotW + gSaveContext.inventory.dungeonKeys[SCENE_FOREST_TEMPLE] = FOREST_TEMPLE_SMALL_KEY_MAX; // Forest + gSaveContext.ship.stats.dungeonKeys[SCENE_FOREST_TEMPLE] = FOREST_TEMPLE_SMALL_KEY_MAX; // Forest + gSaveContext.inventory.dungeonKeys[SCENE_FIRE_TEMPLE] = FIRE_TEMPLE_SMALL_KEY_MAX; // Fire + gSaveContext.ship.stats.dungeonKeys[SCENE_FIRE_TEMPLE] = FIRE_TEMPLE_SMALL_KEY_MAX; // Fire + gSaveContext.inventory.dungeonKeys[SCENE_WATER_TEMPLE] = WATER_TEMPLE_SMALL_KEY_MAX; // Water + gSaveContext.ship.stats.dungeonKeys[SCENE_WATER_TEMPLE] = WATER_TEMPLE_SMALL_KEY_MAX; // Water + gSaveContext.inventory.dungeonKeys[SCENE_SPIRIT_TEMPLE] = SPIRIT_TEMPLE_SMALL_KEY_MAX; // Spirit + gSaveContext.ship.stats.dungeonKeys[SCENE_SPIRIT_TEMPLE] = SPIRIT_TEMPLE_SMALL_KEY_MAX; // Spirit + gSaveContext.inventory.dungeonKeys[SCENE_SHADOW_TEMPLE] = SHADOW_TEMPLE_SMALL_KEY_MAX; // Shadow + gSaveContext.ship.stats.dungeonKeys[SCENE_SHADOW_TEMPLE] = SHADOW_TEMPLE_SMALL_KEY_MAX; // Shadow + gSaveContext.inventory.dungeonKeys[SCENE_BOTTOM_OF_THE_WELL] = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX; // BotW + gSaveContext.ship.stats.dungeonKeys[SCENE_BOTTOM_OF_THE_WELL] = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX; // BotW gSaveContext.inventory.dungeonKeys[SCENE_GERUDO_TRAINING_GROUND] = GERUDO_TRAINING_GROUND_SMALL_KEY_MAX; // GTG - gSaveContext.sohStats.dungeonKeys[SCENE_GERUDO_TRAINING_GROUND] = GERUDO_TRAINING_GROUND_SMALL_KEY_MAX; // GTG - gSaveContext.inventory.dungeonKeys[SCENE_INSIDE_GANONS_CASTLE] = GANONS_CASTLE_SMALL_KEY_MAX; // Ganon - gSaveContext.sohStats.dungeonKeys[SCENE_INSIDE_GANONS_CASTLE] = GANONS_CASTLE_SMALL_KEY_MAX; // Ganon + gSaveContext.ship.stats.dungeonKeys[SCENE_GERUDO_TRAINING_GROUND] = GERUDO_TRAINING_GROUND_SMALL_KEY_MAX; // GTG + gSaveContext.inventory.dungeonKeys[SCENE_INSIDE_GANONS_CASTLE] = GANONS_CASTLE_SMALL_KEY_MAX; // Ganon + gSaveContext.ship.stats.dungeonKeys[SCENE_INSIDE_GANONS_CASTLE] = GANONS_CASTLE_SMALL_KEY_MAX; // Ganon } else if (Randomizer_GetSettingValue(RSK_KEYSANITY) == RO_DUNGEON_ITEM_LOC_VANILLA) { // Logic cannot handle vanilla key layout in some dungeons // this is because vanilla expects the dungeon major item to be @@ -198,7 +198,7 @@ void SetStartingItems() { if (ResourceMgr_IsSceneMasterQuest(SCENE_SPIRIT_TEMPLE)) { // MQ Spirit needs 3 keys gSaveContext.inventory.dungeonKeys[SCENE_SPIRIT_TEMPLE] = 3; - gSaveContext.sohStats.dungeonKeys[SCENE_SPIRIT_TEMPLE] = 3; + gSaveContext.ship.stats.dungeonKeys[SCENE_SPIRIT_TEMPLE] = 3; } } @@ -220,10 +220,10 @@ extern "C" void Randomizer_InitSaveFile() { ctx->GetLogic()->SetSaveContext(&gSaveContext); // Starts pending ice traps out at 0 before potentially incrementing them down the line. - gSaveContext.pendingIceTrapCount = 0; + gSaveContext.ship.pendingIceTrapCount = 0; // Reset triforce pieces collected - gSaveContext.triforcePiecesCollected = 0; + gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected = 0; // Set Cutscene flags and texts to skip them Flags_SetEventChkInf(EVENTCHKINF_FIRST_SPOKE_TO_MIDO); @@ -262,7 +262,7 @@ extern "C" void Randomizer_InitSaveFile() { // shuffle adult trade quest if (Randomizer_GetSettingValue(RSK_SHUFFLE_ADULT_TRADE)) { - gSaveContext.adultTradeItems = 0; + gSaveContext.ship.quest.data.randomizer.adultTradeItems = 0; } // remove One Time scrubs with scrubsanity off diff --git a/soh/soh/Enhancements/timesplits/TimeSplits.cpp b/soh/soh/Enhancements/timesplits/TimeSplits.cpp index 01faf7bf5..b17f95b82 100644 --- a/soh/soh/Enhancements/timesplits/TimeSplits.cpp +++ b/soh/soh/Enhancements/timesplits/TimeSplits.cpp @@ -345,8 +345,8 @@ void HandleDragAndDrop(std::vector& objectList, int targetIndex, co } void TimeSplitCompleteSplits() { - gSaveContext.sohStats.itemTimestamp[TIMESTAMP_DEFEAT_GANON] = GAMEPLAYSTAT_TOTAL_TIME; - gSaveContext.sohStats.gameComplete = true; + gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_GANON] = GAMEPLAYSTAT_TOTAL_TIME; + gSaveContext.ship.stats.gameComplete = true; } void TimeSplitsSkipSplit(uint32_t index) { diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 7856de88f..3cf63f18b 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -2322,10 +2322,10 @@ extern "C" int CustomMessage_RetrieveIfExists(PlayState* play) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, textId, MF_FORMATTED); } else if (textId == TEXT_HEART_CONTAINER && CVarGetInteger(CVAR_ENHANCEMENT("InjectItemCounts.HeartContainer"), 0)) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_HEART_CONTAINER, MF_FORMATTED); - messageEntry.Replace("[[heartContainerCount]]", std::to_string(gSaveContext.sohStats.heartContainers + 1)); + messageEntry.Replace("[[heartContainerCount]]", std::to_string(gSaveContext.ship.stats.heartContainers + 1)); } else if (textId >= TEXT_HEART_PIECE && textId < TEXT_HEART_CONTAINER && CVarGetInteger(CVAR_ENHANCEMENT("InjectItemCounts.HeartPiece"), 0)) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_HEART_PIECE, MF_FORMATTED); - messageEntry.Replace("[[heartPieceCount]]", std::to_string(gSaveContext.sohStats.heartPieces + 1)); + messageEntry.Replace("[[heartPieceCount]]", std::to_string(gSaveContext.ship.stats.heartPieces + 1)); } else if (textId == TEXT_MARKET_GUARD_NIGHT && CVarGetInteger(CVAR_ENHANCEMENT("MarketSneak"), 0) && play->sceneNum == SCENE_MARKET_ENTRANCE_NIGHT) { messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_MARKET_GUARD_NIGHT, MF_FORMATTED); } diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 36de01199..be5c88a5e 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -218,11 +218,11 @@ void SaveManager::LoadRandomizerVersion1() { } randoContext->AddHint(RH_GANONDORF_JOKE, Rando::Hint(RH_GANONDORF_JOKE, {CustomMessage(ganonText)})); - SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.adultTradeItems); + SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.ship.quest.data.randomizer.adultTradeItems); - SaveManager::Instance->LoadData("triforcePiecesCollected", gSaveContext.triforcePiecesCollected); + SaveManager::Instance->LoadData("triforcePiecesCollected", gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected); - SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.pendingIceTrapCount); + SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.ship.pendingIceTrapCount); size_t merchantPricesSize = 0; @@ -348,11 +348,11 @@ void SaveManager::LoadRandomizerVersion2() { SaveManager::Instance->LoadData("warpPreludeText", warpPreludeText); randoContext->AddHint(RH_PRELUDE_WARP_LOC, Rando::Hint(RH_PRELUDE_WARP_LOC, {CustomMessage(warpPreludeText)})); - SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.adultTradeItems); + SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.ship.quest.data.randomizer.adultTradeItems); - SaveManager::Instance->LoadData("triforcePiecesCollected", gSaveContext.triforcePiecesCollected); + SaveManager::Instance->LoadData("triforcePiecesCollected", gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected); - SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.pendingIceTrapCount); + SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.ship.pendingIceTrapCount); std::shared_ptr randomizer = OTRGlobals::Instance->gRandomizer; @@ -445,11 +445,11 @@ void SaveManager::LoadRandomizerVersion3() { randoContext->AddHint(hint, Rando::Hint(hint, json)); }); - SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.adultTradeItems); + SaveManager::Instance->LoadData("adultTradeItems", gSaveContext.ship.quest.data.randomizer.adultTradeItems); - SaveManager::Instance->LoadData("triforcePiecesCollected", gSaveContext.triforcePiecesCollected); + SaveManager::Instance->LoadData("triforcePiecesCollected", gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected); - SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.pendingIceTrapCount); + SaveManager::Instance->LoadData("pendingIceTrapCount", gSaveContext.ship.pendingIceTrapCount); std::shared_ptr randomizer = OTRGlobals::Instance->gRandomizer; @@ -473,7 +473,7 @@ void SaveManager::LoadRandomizerVersion3() { void SaveManager::SaveRandomizer(SaveContext* saveContext, int sectionID, bool fullSave) { - if(saveContext->questId != QUEST_RANDOMIZER) return; + if(saveContext->ship.quest.id != QUEST_RANDOMIZER) return; auto randoContext = Rando::Context::GetInstance(); SaveManager::Instance->SaveArray("itemLocations", RC_MAX, [&](size_t i) { @@ -582,11 +582,11 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext, int sectionID, bool f }); }); - SaveManager::Instance->SaveData("adultTradeItems", saveContext->adultTradeItems); + SaveManager::Instance->SaveData("adultTradeItems", saveContext->ship.quest.data.randomizer.adultTradeItems); - SaveManager::Instance->SaveData("triforcePiecesCollected", saveContext->triforcePiecesCollected); + SaveManager::Instance->SaveData("triforcePiecesCollected", saveContext->ship.quest.data.randomizer.triforcePiecesCollected); - SaveManager::Instance->SaveData("pendingIceTrapCount", saveContext->pendingIceTrapCount); + SaveManager::Instance->SaveData("pendingIceTrapCount", saveContext->ship.pendingIceTrapCount); std::shared_ptr randomizer = OTRGlobals::Instance->gRandomizer; @@ -701,10 +701,10 @@ void SaveManager::InitMeta(int fileNum) { // we don't actually require a vanilla OTR. fileMetaInfo[fileNum].requiresOriginal = !IS_MASTER_QUEST && (!IS_RANDO || randoContext->GetDungeons()->CountMQ() < 12); - fileMetaInfo[fileNum].buildVersionMajor = gSaveContext.sohStats.buildVersionMajor; - fileMetaInfo[fileNum].buildVersionMinor = gSaveContext.sohStats.buildVersionMinor; - fileMetaInfo[fileNum].buildVersionPatch = gSaveContext.sohStats.buildVersionPatch; - SohUtils::CopyStringToCharArray(fileMetaInfo[fileNum].buildVersion, gSaveContext.sohStats.buildVersion, + fileMetaInfo[fileNum].buildVersionMajor = gSaveContext.ship.stats.buildVersionMajor; + fileMetaInfo[fileNum].buildVersionMinor = gSaveContext.ship.stats.buildVersionMinor; + fileMetaInfo[fileNum].buildVersionPatch = gSaveContext.ship.stats.buildVersionPatch; + SohUtils::CopyStringToCharArray(fileMetaInfo[fileNum].buildVersion, gSaveContext.ship.stats.buildVersion, ARRAY_COUNT(fileMetaInfo[fileNum].buildVersion)); } @@ -821,8 +821,9 @@ void SaveManager::InitFileNormal() { for (int flag = 0; flag < ARRAY_COUNT(gSaveContext.infTable); flag++) { gSaveContext.infTable[flag] = 0; } - for (int flag = 0; flag < ARRAY_COUNT(gSaveContext.randomizerInf); flag++) { - gSaveContext.randomizerInf[flag] = 0; + // Currently randomizer flags are accessible from all quests + for (int flag = 0; flag < ARRAY_COUNT(gSaveContext.ship.randomizerInf); flag++) { + gSaveContext.ship.randomizerInf[flag] = 0; } gSaveContext.worldMapAreaData = 0; gSaveContext.scarecrowLongSongSet = 0; @@ -856,15 +857,14 @@ void SaveManager::InitFileNormal() { gSaveContext.sceneFlags[5].swch = 0x40000000; // SoH specific - gSaveContext.backupFW = gSaveContext.fw; - gSaveContext.pendingSale = ITEM_NONE; - gSaveContext.pendingSaleMod = MOD_NONE; - gSaveContext.isBossRushPaused = 0; - gSaveContext.pendingIceTrapCount = 0; - gSaveContext.maskMemory = PLAYER_MASK_NONE; + gSaveContext.ship.backupFW = gSaveContext.fw; + gSaveContext.ship.pendingSale = ITEM_NONE; + gSaveContext.ship.pendingSaleMod = MOD_NONE; + gSaveContext.ship.pendingIceTrapCount = 0; + gSaveContext.ship.maskMemory = PLAYER_MASK_NONE; // Init with normal quest unless only an MQ rom is provided - gSaveContext.questId = OTRGlobals::Instance->HasOriginal() ? QUEST_NORMAL : QUEST_MASTER; + gSaveContext.ship.quest.id = OTRGlobals::Instance->HasOriginal() ? QUEST_NORMAL : QUEST_MASTER; //RANDOTODO (ADD ITEMLOCATIONS TO GSAVECONTEXT) } @@ -1436,7 +1436,7 @@ void SaveManager::LoadBaseVersion1() { int isRando = 0; SaveManager::Instance->LoadData("n64ddFlag", isRando); if (isRando) { - gSaveContext.questId = QUEST_RANDOMIZER; + gSaveContext.ship.quest.id = QUEST_RANDOMIZER; } SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); SaveManager::Instance->LoadData("health", gSaveContext.health); @@ -1561,8 +1561,8 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadData("angle", gSaveContext.horseData.angle); }); - SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]); + SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.ship.randomizerInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.randomizerInf[i]); }); } @@ -1581,7 +1581,7 @@ void SaveManager::LoadBaseVersion2() { int isRando = 0; SaveManager::Instance->LoadData("n64ddFlag", isRando); if (isRando) { - gSaveContext.questId = QUEST_RANDOMIZER; + gSaveContext.ship.quest.id = QUEST_RANDOMIZER; } SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); SaveManager::Instance->LoadData("health", gSaveContext.health); @@ -1648,26 +1648,26 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadData("gsTokens", gSaveContext.inventory.gsTokens); }); SaveManager::Instance->LoadStruct("sohStats", []() { - SaveManager::Instance->LoadData("heartPieces", gSaveContext.sohStats.heartPieces); - SaveManager::Instance->LoadData("heartContainers", gSaveContext.sohStats.heartContainers); - SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.dungeonKeys[i]); + SaveManager::Instance->LoadData("heartPieces", gSaveContext.ship.stats.heartPieces); + SaveManager::Instance->LoadData("heartContainers", gSaveContext.ship.stats.heartContainers); + SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.ship.stats.dungeonKeys), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.dungeonKeys[i]); }); - SaveManager::Instance->LoadData("rtaTiming", gSaveContext.sohStats.rtaTiming); - SaveManager::Instance->LoadData("fileCreatedAt", gSaveContext.sohStats.fileCreatedAt); - SaveManager::Instance->LoadData("playTimer", gSaveContext.sohStats.playTimer); - SaveManager::Instance->LoadData("pauseTimer", gSaveContext.sohStats.pauseTimer); - SaveManager::Instance->LoadArray("timestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); + SaveManager::Instance->LoadData("rtaTiming", gSaveContext.ship.stats.rtaTiming); + SaveManager::Instance->LoadData("fileCreatedAt", gSaveContext.ship.stats.fileCreatedAt); + SaveManager::Instance->LoadData("playTimer", gSaveContext.ship.stats.playTimer); + SaveManager::Instance->LoadData("pauseTimer", gSaveContext.ship.stats.pauseTimer); + SaveManager::Instance->LoadArray("timestamps", ARRAY_COUNT(gSaveContext.ship.stats.itemTimestamp), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.itemTimestamp[i]); }); - SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); + SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.ship.stats.count), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.count[i]); }); - SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); + SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.ship.stats.scenesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.scenesDiscovered[i]); }); - SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); + SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.ship.stats.entrancesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.entrancesDiscovered[i]); }); }); SaveManager::Instance->LoadArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) { @@ -1745,13 +1745,13 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadData("angle", gSaveContext.horseData.angle); }); - SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]); + SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.ship.randomizerInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.randomizerInf[i]); }); int isMQ = 0; SaveManager::Instance->LoadData("isMasterQuest", isMQ); if (isMQ) { - gSaveContext.questId = QUEST_MASTER; + gSaveContext.ship.quest.id = QUEST_MASTER; } // Workaround for breaking save compatibility from 5.0.2 -> 5.1.0 in commit d7c35221421bf712b5ead56a360f81f624aca4bc @@ -1797,7 +1797,7 @@ void SaveManager::LoadBaseVersion3() { int isRando = 0; SaveManager::Instance->LoadData("n64ddFlag", isRando); if (isRando) { - gSaveContext.questId = QUEST_RANDOMIZER; + gSaveContext.ship.quest.id = QUEST_RANDOMIZER; } SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); SaveManager::Instance->LoadData("health", gSaveContext.health); @@ -1864,43 +1864,43 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("gsTokens", gSaveContext.inventory.gsTokens); }); SaveManager::Instance->LoadStruct("sohStats", []() { - SaveManager::Instance->LoadCharArray("buildVersion", gSaveContext.sohStats.buildVersion, - ARRAY_COUNT(gSaveContext.sohStats.buildVersion)); - SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.sohStats.buildVersionMajor); - SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.sohStats.buildVersionMinor); - SaveManager::Instance->LoadData("buildVersionPatch", gSaveContext.sohStats.buildVersionPatch); + SaveManager::Instance->LoadCharArray("buildVersion", gSaveContext.ship.stats.buildVersion, + ARRAY_COUNT(gSaveContext.ship.stats.buildVersion)); + SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.ship.stats.buildVersionMajor); + SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.ship.stats.buildVersionMinor); + SaveManager::Instance->LoadData("buildVersionPatch", gSaveContext.ship.stats.buildVersionPatch); - SaveManager::Instance->LoadData("heartPieces", gSaveContext.sohStats.heartPieces); - SaveManager::Instance->LoadData("heartContainers", gSaveContext.sohStats.heartContainers); - SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.dungeonKeys[i]); + SaveManager::Instance->LoadData("heartPieces", gSaveContext.ship.stats.heartPieces); + SaveManager::Instance->LoadData("heartContainers", gSaveContext.ship.stats.heartContainers); + SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.ship.stats.dungeonKeys), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.dungeonKeys[i]); }); - SaveManager::Instance->LoadData("rtaTiming", gSaveContext.sohStats.rtaTiming); - SaveManager::Instance->LoadData("fileCreatedAt", gSaveContext.sohStats.fileCreatedAt); - SaveManager::Instance->LoadData("playTimer", gSaveContext.sohStats.playTimer); - SaveManager::Instance->LoadData("pauseTimer", gSaveContext.sohStats.pauseTimer); - SaveManager::Instance->LoadArray("itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); + SaveManager::Instance->LoadData("rtaTiming", gSaveContext.ship.stats.rtaTiming); + SaveManager::Instance->LoadData("fileCreatedAt", gSaveContext.ship.stats.fileCreatedAt); + SaveManager::Instance->LoadData("playTimer", gSaveContext.ship.stats.playTimer); + SaveManager::Instance->LoadData("pauseTimer", gSaveContext.ship.stats.pauseTimer); + SaveManager::Instance->LoadArray("itemTimestamps", ARRAY_COUNT(gSaveContext.ship.stats.itemTimestamp), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.itemTimestamp[i]); }); - SaveManager::Instance->LoadArray("sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [](size_t i) { + SaveManager::Instance->LoadArray("sceneTimestamps", ARRAY_COUNT(gSaveContext.ship.stats.sceneTimestamps), [](size_t i) { SaveManager::Instance->LoadStruct("", [&i]() { - SaveManager::Instance->LoadData("scene", gSaveContext.sohStats.sceneTimestamps[i].scene); - SaveManager::Instance->LoadData("room", gSaveContext.sohStats.sceneTimestamps[i].room); - SaveManager::Instance->LoadData("sceneTime", gSaveContext.sohStats.sceneTimestamps[i].sceneTime); - SaveManager::Instance->LoadData("roomTime", gSaveContext.sohStats.sceneTimestamps[i].roomTime); - SaveManager::Instance->LoadData("isRoom", gSaveContext.sohStats.sceneTimestamps[i].isRoom); + SaveManager::Instance->LoadData("scene", gSaveContext.ship.stats.sceneTimestamps[i].scene); + SaveManager::Instance->LoadData("room", gSaveContext.ship.stats.sceneTimestamps[i].room); + SaveManager::Instance->LoadData("sceneTime", gSaveContext.ship.stats.sceneTimestamps[i].sceneTime); + SaveManager::Instance->LoadData("roomTime", gSaveContext.ship.stats.sceneTimestamps[i].roomTime); + SaveManager::Instance->LoadData("isRoom", gSaveContext.ship.stats.sceneTimestamps[i].isRoom); }); }); - SaveManager::Instance->LoadData("tsIdx", gSaveContext.sohStats.tsIdx); - SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); + SaveManager::Instance->LoadData("tsIdx", gSaveContext.ship.stats.tsIdx); + SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.ship.stats.count), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.count[i]); }); - SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); + SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.ship.stats.scenesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.scenesDiscovered[i]); }); - SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); + SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.ship.stats.entrancesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.stats.entrancesDiscovered[i]); }); }); SaveManager::Instance->LoadArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) { @@ -1978,27 +1978,27 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("angle", gSaveContext.horseData.angle); }); - SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]); + SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.ship.randomizerInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.randomizerInf[i]); }); int isMQ = 0; SaveManager::Instance->LoadData("isMasterQuest", isMQ); if (isMQ) { - gSaveContext.questId = QUEST_MASTER; + gSaveContext.ship.quest.id = QUEST_MASTER; } SaveManager::Instance->LoadStruct("backupFW", []() { SaveManager::Instance->LoadStruct("pos", []() { - SaveManager::Instance->LoadData("x", gSaveContext.backupFW.pos.x); - SaveManager::Instance->LoadData("y", gSaveContext.backupFW.pos.y); - SaveManager::Instance->LoadData("z", gSaveContext.backupFW.pos.z); + SaveManager::Instance->LoadData("x", gSaveContext.ship.backupFW.pos.x); + SaveManager::Instance->LoadData("y", gSaveContext.ship.backupFW.pos.y); + SaveManager::Instance->LoadData("z", gSaveContext.ship.backupFW.pos.z); }); - SaveManager::Instance->LoadData("yaw", gSaveContext.backupFW.yaw); - SaveManager::Instance->LoadData("playerParams", gSaveContext.backupFW.playerParams); - SaveManager::Instance->LoadData("entranceIndex", gSaveContext.backupFW.entranceIndex); - SaveManager::Instance->LoadData("roomIndex", gSaveContext.backupFW.roomIndex); - SaveManager::Instance->LoadData("set", gSaveContext.backupFW.set); - SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.backupFW.tempSwchFlags); - SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.backupFW.tempCollectFlags); + SaveManager::Instance->LoadData("yaw", gSaveContext.ship.backupFW.yaw); + SaveManager::Instance->LoadData("playerParams", gSaveContext.ship.backupFW.playerParams); + SaveManager::Instance->LoadData("entranceIndex", gSaveContext.ship.backupFW.entranceIndex); + SaveManager::Instance->LoadData("roomIndex", gSaveContext.ship.backupFW.roomIndex); + SaveManager::Instance->LoadData("set", gSaveContext.ship.backupFW.set); + SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.ship.backupFW.tempSwchFlags); + SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.ship.backupFW.tempCollectFlags); }); SaveManager::Instance->LoadData("dogParams", gSaveContext.dogParams); } @@ -2018,7 +2018,7 @@ void SaveManager::LoadBaseVersion4() { int isRando = 0; SaveManager::Instance->LoadData("n64ddFlag", isRando); if (isRando) { - gSaveContext.questId = QUEST_RANDOMIZER; + gSaveContext.ship.quest.id = QUEST_RANDOMIZER; } SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); SaveManager::Instance->LoadData("health", gSaveContext.health); @@ -2159,30 +2159,30 @@ void SaveManager::LoadBaseVersion4() { SaveManager::Instance->LoadData("angle", gSaveContext.horseData.angle); }); - SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]); + SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.ship.randomizerInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.ship.randomizerInf[i]); }); int isMQ = 0; SaveManager::Instance->LoadData("isMasterQuest", isMQ); if (isMQ) { - gSaveContext.questId = QUEST_MASTER; + gSaveContext.ship.quest.id = QUEST_MASTER; } SaveManager::Instance->LoadStruct("backupFW", []() { SaveManager::Instance->LoadStruct("pos", []() { - SaveManager::Instance->LoadData("x", gSaveContext.backupFW.pos.x); - SaveManager::Instance->LoadData("y", gSaveContext.backupFW.pos.y); - SaveManager::Instance->LoadData("z", gSaveContext.backupFW.pos.z); + SaveManager::Instance->LoadData("x", gSaveContext.ship.backupFW.pos.x); + SaveManager::Instance->LoadData("y", gSaveContext.ship.backupFW.pos.y); + SaveManager::Instance->LoadData("z", gSaveContext.ship.backupFW.pos.z); }); - SaveManager::Instance->LoadData("yaw", gSaveContext.backupFW.yaw); - SaveManager::Instance->LoadData("playerParams", gSaveContext.backupFW.playerParams); - SaveManager::Instance->LoadData("entranceIndex", gSaveContext.backupFW.entranceIndex); - SaveManager::Instance->LoadData("roomIndex", gSaveContext.backupFW.roomIndex); - SaveManager::Instance->LoadData("set", gSaveContext.backupFW.set); - SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.backupFW.tempSwchFlags); - SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.backupFW.tempCollectFlags); + SaveManager::Instance->LoadData("yaw", gSaveContext.ship.backupFW.yaw); + SaveManager::Instance->LoadData("playerParams", gSaveContext.ship.backupFW.playerParams); + SaveManager::Instance->LoadData("entranceIndex", gSaveContext.ship.backupFW.entranceIndex); + SaveManager::Instance->LoadData("roomIndex", gSaveContext.ship.backupFW.roomIndex); + SaveManager::Instance->LoadData("set", gSaveContext.ship.backupFW.set); + SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.ship.backupFW.tempSwchFlags); + SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.ship.backupFW.tempCollectFlags); }); SaveManager::Instance->LoadData("dogParams", gSaveContext.dogParams); - SaveManager::Instance->LoadData("maskMemory", gSaveContext.maskMemory); + SaveManager::Instance->LoadData("maskMemory", gSaveContext.ship.maskMemory); } void SaveManager::SaveBase(SaveContext* saveContext, int sectionID, bool fullSave) { @@ -2197,7 +2197,7 @@ void SaveManager::SaveBase(SaveContext* saveContext, int sectionID, bool fullSav SaveManager::Instance->SaveArray("playerName", ARRAY_COUNT(saveContext->playerName), [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->playerName[i]); }); - SaveManager::Instance->SaveData("n64ddFlag", saveContext->questId == QUEST_RANDOMIZER); + SaveManager::Instance->SaveData("n64ddFlag", saveContext->ship.quest.id == QUEST_RANDOMIZER); SaveManager::Instance->SaveData("healthCapacity", saveContext->healthCapacity); SaveManager::Instance->SaveData("health", saveContext->health); SaveManager::Instance->SaveData("magicLevel", saveContext->magicLevel); @@ -2333,26 +2333,26 @@ void SaveManager::SaveBase(SaveContext* saveContext, int sectionID, bool fullSav SaveManager::Instance->SaveData("angle", saveContext->horseData.angle); }); - SaveManager::Instance->SaveArray("randomizerInf", ARRAY_COUNT(saveContext->randomizerInf), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->randomizerInf[i]); + SaveManager::Instance->SaveArray("randomizerInf", ARRAY_COUNT(saveContext->ship.randomizerInf), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->ship.randomizerInf[i]); }); - SaveManager::Instance->SaveData("isMasterQuest", saveContext->questId == QUEST_MASTER); + SaveManager::Instance->SaveData("isMasterQuest", saveContext->ship.quest.id == QUEST_MASTER); SaveManager::Instance->SaveStruct("backupFW", [&]() { SaveManager::Instance->SaveStruct("pos", [&]() { - SaveManager::Instance->SaveData("x", saveContext->backupFW.pos.x); - SaveManager::Instance->SaveData("y", saveContext->backupFW.pos.y); - SaveManager::Instance->SaveData("z", saveContext->backupFW.pos.z); + SaveManager::Instance->SaveData("x", saveContext->ship.backupFW.pos.x); + SaveManager::Instance->SaveData("y", saveContext->ship.backupFW.pos.y); + SaveManager::Instance->SaveData("z", saveContext->ship.backupFW.pos.z); }); - SaveManager::Instance->SaveData("yaw", saveContext->backupFW.yaw); - SaveManager::Instance->SaveData("playerParams", saveContext->backupFW.playerParams); - SaveManager::Instance->SaveData("entranceIndex", saveContext->backupFW.entranceIndex); - SaveManager::Instance->SaveData("roomIndex", saveContext->backupFW.roomIndex); - SaveManager::Instance->SaveData("set", saveContext->backupFW.set); - SaveManager::Instance->SaveData("tempSwchFlags", saveContext->backupFW.tempSwchFlags); - SaveManager::Instance->SaveData("tempCollectFlags", saveContext->backupFW.tempCollectFlags); + SaveManager::Instance->SaveData("yaw", saveContext->ship.backupFW.yaw); + SaveManager::Instance->SaveData("playerParams", saveContext->ship.backupFW.playerParams); + SaveManager::Instance->SaveData("entranceIndex", saveContext->ship.backupFW.entranceIndex); + SaveManager::Instance->SaveData("roomIndex", saveContext->ship.backupFW.roomIndex); + SaveManager::Instance->SaveData("set", saveContext->ship.backupFW.set); + SaveManager::Instance->SaveData("tempSwchFlags", saveContext->ship.backupFW.tempSwchFlags); + SaveManager::Instance->SaveData("tempCollectFlags", saveContext->ship.backupFW.tempCollectFlags); }); SaveManager::Instance->SaveData("dogParams", saveContext->dogParams); - SaveManager::Instance->SaveData("maskMemory", saveContext->maskMemory); + SaveManager::Instance->SaveData("maskMemory", saveContext->ship.maskMemory); } // Load a string into a char array based on size and ensuring it is null terminated when overflowed diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 70c7a3233..306a4f89c 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -4982,15 +4982,33 @@ void Flags_UnsetEventInf(s32 flag) { * Tests if "randomizerInf" flag is set. */ s32 Flags_GetRandomizerInf(RandomizerInf flag) { - return gSaveContext.randomizerInf[flag >> 4] & (1 << (flag & 0xF)); + // Randomizer flags are currently accessible from any quest (boss rush as an example) + /* + if (!IS_RANDO) { + LUSLOG_ERROR("Tried to get randomizerInf flag \"%d\" outside of rando", flag); + assert(false); + return 0; + } + */ + + return gSaveContext.ship.randomizerInf[flag >> 4] & (1 << (flag & 0xF)); } /** * Sets "randomizerInf" flag. */ void Flags_SetRandomizerInf(RandomizerInf flag) { + // Randomizer flags are currently accessible from any quest (boss rush as an example) + /* + if (!IS_RANDO) { + LUSLOG_ERROR("Tried to set randomizerInf flag \"%d\" outside of rando", flag); + assert(false); + return; + } + */ + s32 previouslyOff = !Flags_GetRandomizerInf(flag); - gSaveContext.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); + gSaveContext.ship.randomizerInf[flag >> 4] |= (1 << (flag & 0xF)); if (previouslyOff) { LUSLOG_INFO("RandomizerInf Flag Set - %#x", flag); GameInteractor_ExecuteOnFlagSet(FLAG_RANDOMIZER_INF, flag); @@ -5001,8 +5019,17 @@ void Flags_SetRandomizerInf(RandomizerInf flag) { * Unsets "randomizerInf" flag. */ void Flags_UnsetRandomizerInf(RandomizerInf flag) { + // Randomizer flags are currently accessible from any quest (boss rush as an example) + /* + if (!IS_RANDO) { + LUSLOG_ERROR("Tried to unset randomizerInf flag \"%d\" outside of rando", flag); + assert(false); + return; + } + */ + s32 previouslyOn = Flags_GetRandomizerInf(flag); - gSaveContext.randomizerInf[flag >> 4] &= ~(1 << (flag & 0xF)); + gSaveContext.ship.randomizerInf[flag >> 4] &= ~(1 << (flag & 0xF)); if (previouslyOn) { LUSLOG_INFO("RandomizerInf Flag Unset - %#x", flag); GameInteractor_ExecuteOnFlagUnset(FLAG_RANDOMIZER_INF, flag); diff --git a/soh/src/code/z_demo.c b/soh/src/code/z_demo.c index 4943b8390..9821b8d26 100644 --- a/soh/src/code/z_demo.c +++ b/soh/src/code/z_demo.c @@ -626,8 +626,8 @@ void Cutscene_Command_Terminator(PlayState* play, CutsceneContext* csCtx, CsCmdB break; case 8: if (CVarGetInteger(CVAR_ENHANCEMENT("BetterFarore"), 0)) { - FaroresWindData tempFW = gSaveContext.backupFW; - gSaveContext.backupFW = gSaveContext.fw; + FaroresWindData tempFW = gSaveContext.ship.backupFW; + gSaveContext.ship.backupFW = gSaveContext.fw; gSaveContext.fw = tempFW; } else { gSaveContext.fw.set = 0; diff --git a/soh/src/code/z_draw.c b/soh/src/code/z_draw.c index e27f230b1..523f65bbd 100644 --- a/soh/src/code/z_draw.c +++ b/soh/src/code/z_draw.c @@ -1046,7 +1046,7 @@ void GetItem_DrawTriforcePiece(PlayState* play, s16 drawId) { Matrix_Scale(0.035f, 0.035f, 0.035f, MTXMODE_APPLY); - uint8_t index = gSaveContext.triforcePiecesCollected % 3; + uint8_t index = gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected % 3; Gfx* triforcePieceDL; switch (index) { diff --git a/soh/src/code/z_kaleido_scope_call.c b/soh/src/code/z_kaleido_scope_call.c index 196e20041..bc21b9b55 100644 --- a/soh/src/code/z_kaleido_scope_call.c +++ b/soh/src/code/z_kaleido_scope_call.c @@ -59,9 +59,9 @@ void KaleidoScopeCall_Update(PlayState* play) { GameInteractor_ExecuteOnKaleidoUpdate(); - if (!gSaveContext.sohStats.gameComplete && - (!IS_BOSS_RUSH || !gSaveContext.isBossRushPaused)) { - gSaveContext.sohStats.pauseTimer++; + if (!gSaveContext.ship.stats.gameComplete && + (!IS_BOSS_RUSH || !gSaveContext.ship.quest.data.bossRush.isPaused)) { + gSaveContext.ship.stats.pauseTimer++; } if ((pauseCtx->state != 0) || (pauseCtx->debugState != 0)) { @@ -73,7 +73,7 @@ void KaleidoScopeCall_Update(PlayState* play) { pauseCtx->unk_1E4 = 0; pauseCtx->unk_1EC = 0; pauseCtx->state = (pauseCtx->state & 0xFFFF) + 1; - gSaveContext.sohStats.count[COUNT_PAUSES]++; + gSaveContext.ship.stats.count[COUNT_PAUSES]++; } } else if (pauseCtx->state == 8) { HREG(80) = 7; diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index 396188b48..39c6e111d 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -1812,7 +1812,7 @@ void func_80084BF4(PlayState* play, u16 flag) { void GameplayStats_SetTimestamp(PlayState* play, u8 item) { // If we already have a timestamp for this item, do nothing - if (gSaveContext.sohStats.itemTimestamp[item] != 0){ + if (gSaveContext.ship.stats.itemTimestamp[item] != 0){ return; } // Use ITEM_KEY_BOSS only for Ganon's boss key - not any other boss keys @@ -1831,20 +1831,20 @@ void GameplayStats_SetTimestamp(PlayState* play, u8 item) { // Count any bottled item as a bottle if (item >= ITEM_BOTTLE && item <= ITEM_POE) { - if (gSaveContext.sohStats.itemTimestamp[ITEM_BOTTLE] == 0) { - gSaveContext.sohStats.itemTimestamp[ITEM_BOTTLE] = time; + if (gSaveContext.ship.stats.itemTimestamp[ITEM_BOTTLE] == 0) { + gSaveContext.ship.stats.itemTimestamp[ITEM_BOTTLE] = time; } return; } // Count any bombchu pack as bombchus if (item == ITEM_BOMBCHU || (item >= ITEM_BOMBCHUS_5 && item <= ITEM_BOMBCHUS_20)) { - if (gSaveContext.sohStats.itemTimestamp[ITEM_BOMBCHU] == 0) { - gSaveContext.sohStats.itemTimestamp[ITEM_BOMBCHU] = time; + if (gSaveContext.ship.stats.itemTimestamp[ITEM_BOMBCHU] == 0) { + gSaveContext.ship.stats.itemTimestamp[ITEM_BOMBCHU] = time; } return; } - gSaveContext.sohStats.itemTimestamp[item] = time; + gSaveContext.ship.stats.itemTimestamp[item] = time; GameInteractor_ExecuteOnTimestamp(item); } @@ -2338,7 +2338,7 @@ u8 Item_Give(PlayState* play, u8 item) { return Return_Item(item, MOD_NONE, ITEM_NONE); } else if ((item == ITEM_HEART_PIECE_2) || (item == ITEM_HEART_PIECE)) { gSaveContext.inventory.questItems += 1 << (QUEST_HEART_PIECE + 4); - gSaveContext.sohStats.heartPieces++; + gSaveContext.ship.stats.heartPieces++; return Return_Item(item, MOD_NONE, ITEM_NONE); } else if (item == ITEM_HEART_CONTAINER) { if (!CVarGetInteger(CVAR_ENHANCEMENT("HurtContainer"), 0)) { @@ -2348,7 +2348,7 @@ u8 Item_Give(PlayState* play, u8 item) { gSaveContext.healthCapacity -= 0x10; gSaveContext.health -= 0x10; } - gSaveContext.sohStats.heartContainers++; + gSaveContext.ship.stats.heartContainers++; return Return_Item(item, MOD_NONE, ITEM_NONE); } else if (item == ITEM_HEART) { osSyncPrintf("回復ハート回復ハート回復ハート\n"); // "Recovery Heart" @@ -2447,7 +2447,7 @@ u8 Item_Give(PlayState* play, u8 item) { } if (item >= ITEM_POCKET_EGG) { - gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(item); + gSaveContext.ship.quest.data.randomizer.adultTradeItems |= ADULT_TRADE_FLAG(item); } temp = INV_CONTENT(item); @@ -2763,8 +2763,8 @@ bool Inventory_HatchPocketCucco(PlayState* play) { return 0; } - gSaveContext.adultTradeItems &= ~ADULT_TRADE_FLAG(ITEM_POCKET_EGG); - gSaveContext.adultTradeItems |= ADULT_TRADE_FLAG(ITEM_POCKET_CUCCO); + gSaveContext.ship.quest.data.randomizer.adultTradeItems &= ~ADULT_TRADE_FLAG(ITEM_POCKET_EGG); + gSaveContext.ship.quest.data.randomizer.adultTradeItems |= ADULT_TRADE_FLAG(ITEM_POCKET_CUCCO); Inventory_ReplaceItem(play, ITEM_POCKET_EGG, ITEM_POCKET_CUCCO); return 1; } @@ -2882,7 +2882,7 @@ s32 Health_ChangeBy(PlayState* play, s16 healthChange) { gSaveContext.healthCapacity); if (healthChange < 0) { - gSaveContext.sohStats.count[COUNT_DAMAGE_TAKEN] += -healthChange; + gSaveContext.ship.stats.count[COUNT_DAMAGE_TAKEN] += -healthChange; } // If one-hit ko mode is on, any damage kills you and you cannot gain health. @@ -2952,10 +2952,10 @@ void Rupees_ChangeBy(s16 rupeeChange) { } if (rupeeChange > 0) { - gSaveContext.sohStats.count[COUNT_RUPEES_COLLECTED] += rupeeChange; + gSaveContext.ship.stats.count[COUNT_RUPEES_COLLECTED] += rupeeChange; } if (rupeeChange < 0) { - gSaveContext.sohStats.count[COUNT_RUPEES_SPENT] += -rupeeChange; + gSaveContext.ship.stats.count[COUNT_RUPEES_SPENT] += -rupeeChange; } } @@ -2963,25 +2963,25 @@ void GameplayStats_UpdateAmmoUsed(s16 item, s16 ammoUsed) { switch (item) { case ITEM_STICK: - gSaveContext.sohStats.count[COUNT_AMMO_USED_STICK] += ammoUsed; + gSaveContext.ship.stats.count[COUNT_AMMO_USED_STICK] += ammoUsed; break; case ITEM_NUT: - gSaveContext.sohStats.count[COUNT_AMMO_USED_NUT] += ammoUsed; + gSaveContext.ship.stats.count[COUNT_AMMO_USED_NUT] += ammoUsed; break; case ITEM_BOMB: - gSaveContext.sohStats.count[COUNT_AMMO_USED_BOMB] += ammoUsed; + gSaveContext.ship.stats.count[COUNT_AMMO_USED_BOMB] += ammoUsed; break; case ITEM_BOW: - gSaveContext.sohStats.count[COUNT_AMMO_USED_ARROW] += ammoUsed; + gSaveContext.ship.stats.count[COUNT_AMMO_USED_ARROW] += ammoUsed; break; case ITEM_SLINGSHOT: - gSaveContext.sohStats.count[COUNT_AMMO_USED_SEED] += ammoUsed; + gSaveContext.ship.stats.count[COUNT_AMMO_USED_SEED] += ammoUsed; break; case ITEM_BOMBCHU: - gSaveContext.sohStats.count[COUNT_AMMO_USED_BOMBCHU] += ammoUsed; + gSaveContext.ship.stats.count[COUNT_AMMO_USED_BOMBCHU] += ammoUsed; break; case ITEM_BEAN: - gSaveContext.sohStats.count[COUNT_AMMO_USED_BEAN] += ammoUsed; + gSaveContext.ship.stats.count[COUNT_AMMO_USED_BEAN] += ammoUsed; break; default: break; @@ -6122,7 +6122,7 @@ void Interface_Draw(PlayState* play) { void Interface_DrawTotalGameplayTimer(PlayState* play) { // Draw timer based on the Gameplay Stats total time. - if ((IS_BOSS_RUSH && gSaveContext.bossRushOptions[BR_OPTIONS_TIMER] == BR_CHOICE_TIMER_YES) || + if ((IS_BOSS_RUSH && gSaveContext.ship.quest.data.bossRush.options[BR_OPTIONS_TIMER] == BR_CHOICE_TIMER_YES) || (CVarGetInteger(CVAR_ENHANCEMENT("GameplayStats.ShowIngameTimer"), 0) && gSaveContext.fileNum >= 0 && gSaveContext.fileNum <= 2)) { s32 X_Margins_Timer = 0; @@ -6202,9 +6202,9 @@ void Interface_DrawTotalGameplayTimer(PlayState* play) { (rectTop + rectHeight) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); // Draw regular text. Change color based on if the timer is paused, running or the game is completed. - if (gSaveContext.sohStats.gameComplete) { + if (gSaveContext.ship.stats.gameComplete) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 120, 255, 0, 255); - } else if (gSaveContext.isBossRushPaused && !gSaveContext.sohStats.rtaTiming) { + } else if (IS_BOSS_RUSH && gSaveContext.ship.quest.data.bossRush.isPaused && !gSaveContext.ship.stats.rtaTiming) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 150, 150, 150, 255); } else { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, 255); @@ -6429,11 +6429,11 @@ void Interface_Update(PlayState* play) { } else { gSaveContext.rupeeAccumulator = 0; } - if (gSaveContext.rupeeAccumulator == 0 && gSaveContext.pendingSale != ITEM_NONE) { - u16 tempSaleItem = gSaveContext.pendingSale; - u16 tempSaleMod = gSaveContext.pendingSaleMod; - gSaveContext.pendingSale = ITEM_NONE; - gSaveContext.pendingSaleMod = MOD_NONE; + if (gSaveContext.rupeeAccumulator == 0 && gSaveContext.ship.pendingSale != ITEM_NONE) { + u16 tempSaleItem = gSaveContext.ship.pendingSale; + u16 tempSaleMod = gSaveContext.ship.pendingSaleMod; + gSaveContext.ship.pendingSale = ITEM_NONE; + gSaveContext.ship.pendingSaleMod = MOD_NONE; if (tempSaleMod == MOD_NONE) { GetItemID getItemID = RetrieveGetItemIDFromItemID(tempSaleItem); RandomizerGet randomizerGet = RetrieveRandomizerGetFromItemID(tempSaleItem); diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index df1314e71..cc7af190d 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -646,32 +646,32 @@ void Play_Init(GameState* thisx) { gSaveContext.respawnFlag = 0; // #region SOH [Stats] - if (gSaveContext.sohStats.sceneNum != gPlayState->sceneNum) { - u16 idx = gSaveContext.sohStats.tsIdx; - gSaveContext.sohStats.sceneTimestamps[idx].sceneTime = gSaveContext.sohStats.sceneTimer / 2; - gSaveContext.sohStats.sceneTimestamps[idx].roomTime = gSaveContext.sohStats.roomTimer / 2; - gSaveContext.sohStats.sceneTimestamps[idx].scene = gSaveContext.sohStats.sceneNum; - gSaveContext.sohStats.sceneTimestamps[idx].room = gSaveContext.sohStats.roomNum; - gSaveContext.sohStats.sceneTimestamps[idx].isRoom = - gPlayState->sceneNum == gSaveContext.sohStats.sceneTimestamps[idx].scene && - gPlayState->roomCtx.curRoom.num != gSaveContext.sohStats.sceneTimestamps[idx].room; - gSaveContext.sohStats.tsIdx++; - gSaveContext.sohStats.sceneTimer = 0; - gSaveContext.sohStats.roomTimer = 0; - } else if (gSaveContext.sohStats.roomNum != gPlayState->roomCtx.curRoom.num) { - u16 idx = gSaveContext.sohStats.tsIdx; - gSaveContext.sohStats.sceneTimestamps[idx].roomTime = gSaveContext.sohStats.roomTimer / 2; - gSaveContext.sohStats.sceneTimestamps[idx].scene = gSaveContext.sohStats.sceneNum; - gSaveContext.sohStats.sceneTimestamps[idx].room = gSaveContext.sohStats.roomNum; - gSaveContext.sohStats.sceneTimestamps[idx].isRoom = - gPlayState->sceneNum == gSaveContext.sohStats.sceneTimestamps[idx].scene && - gPlayState->roomCtx.curRoom.num != gSaveContext.sohStats.sceneTimestamps[idx].room; - gSaveContext.sohStats.tsIdx++; - gSaveContext.sohStats.roomTimer = 0; + if (gSaveContext.ship.stats.sceneNum != gPlayState->sceneNum) { + u16 idx = gSaveContext.ship.stats.tsIdx; + gSaveContext.ship.stats.sceneTimestamps[idx].sceneTime = gSaveContext.ship.stats.sceneTimer / 2; + gSaveContext.ship.stats.sceneTimestamps[idx].roomTime = gSaveContext.ship.stats.roomTimer / 2; + gSaveContext.ship.stats.sceneTimestamps[idx].scene = gSaveContext.ship.stats.sceneNum; + gSaveContext.ship.stats.sceneTimestamps[idx].room = gSaveContext.ship.stats.roomNum; + gSaveContext.ship.stats.sceneTimestamps[idx].isRoom = + gPlayState->sceneNum == gSaveContext.ship.stats.sceneTimestamps[idx].scene && + gPlayState->roomCtx.curRoom.num != gSaveContext.ship.stats.sceneTimestamps[idx].room; + gSaveContext.ship.stats.tsIdx++; + gSaveContext.ship.stats.sceneTimer = 0; + gSaveContext.ship.stats.roomTimer = 0; + } else if (gSaveContext.ship.stats.roomNum != gPlayState->roomCtx.curRoom.num) { + u16 idx = gSaveContext.ship.stats.tsIdx; + gSaveContext.ship.stats.sceneTimestamps[idx].roomTime = gSaveContext.ship.stats.roomTimer / 2; + gSaveContext.ship.stats.sceneTimestamps[idx].scene = gSaveContext.ship.stats.sceneNum; + gSaveContext.ship.stats.sceneTimestamps[idx].room = gSaveContext.ship.stats.roomNum; + gSaveContext.ship.stats.sceneTimestamps[idx].isRoom = + gPlayState->sceneNum == gSaveContext.ship.stats.sceneTimestamps[idx].scene && + gPlayState->roomCtx.curRoom.num != gSaveContext.ship.stats.sceneTimestamps[idx].room; + gSaveContext.ship.stats.tsIdx++; + gSaveContext.ship.stats.roomTimer = 0; } - gSaveContext.sohStats.sceneNum = gPlayState->sceneNum; - gSaveContext.sohStats.roomNum = gPlayState->roomCtx.curRoom.num; + gSaveContext.ship.stats.sceneNum = gPlayState->sceneNum; + gSaveContext.ship.stats.roomNum = gPlayState->roomCtx.curRoom.num; // #endregion #if 0 @@ -741,28 +741,28 @@ void Play_Update(PlayState* play) { } // #region SOH [Stats] Gameplay stats: Count button presses - if (!gSaveContext.sohStats.gameComplete) { - if (CHECK_BTN_ALL(input[0].press.button, BTN_A)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_A]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_B)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_B]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_CUP)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CUP]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_CRIGHT)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CRIGHT]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_CLEFT)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CLEFT]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_CDOWN)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_CDOWN]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_DUP)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DUP]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_DRIGHT)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DRIGHT]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_DDOWN)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DDOWN]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_DLEFT)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_DLEFT]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_L)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_L]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_R)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_R]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_Z)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_Z]++;} - if (CHECK_BTN_ALL(input[0].press.button, BTN_START)) {gSaveContext.sohStats.count[COUNT_BUTTON_PRESSES_START]++;} + if (!gSaveContext.ship.stats.gameComplete) { + if (CHECK_BTN_ALL(input[0].press.button, BTN_A)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_A]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_B)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_B]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_CUP)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_CUP]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_CRIGHT)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_CRIGHT]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_CLEFT)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_CLEFT]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_CDOWN)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_CDOWN]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_DUP)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_DUP]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_DRIGHT)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_DRIGHT]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_DDOWN)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_DDOWN]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_DLEFT)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_DLEFT]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_L)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_L]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_R)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_R]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_Z)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_Z]++;} + if (CHECK_BTN_ALL(input[0].press.button, BTN_START)) {gSaveContext.ship.stats.count[COUNT_BUTTON_PRESSES_START]++;} // Start RTA timing on first non-c-up input after intro cutscene if ( - !gSaveContext.sohStats.fileCreatedAt && !Player_InCsMode(play) && + !gSaveContext.ship.stats.fileCreatedAt && !Player_InCsMode(play) && ((input[0].press.button && input[0].press.button != 0x8) || input[0].rel.stick_x != 0 || input[0].rel.stick_y != 0) ) { - gSaveContext.sohStats.fileCreatedAt = GetUnixTimestamp(); + gSaveContext.ship.stats.fileCreatedAt = GetUnixTimestamp(); } } // #endregion @@ -1146,14 +1146,14 @@ void Play_Update(PlayState* play) { func_800AA178(true); // Gameplay stat tracking - if (!gSaveContext.sohStats.gameComplete && - (!IS_BOSS_RUSH || !gSaveContext.isBossRushPaused)) { - gSaveContext.sohStats.playTimer++; - gSaveContext.sohStats.sceneTimer++; - gSaveContext.sohStats.roomTimer++; + if (!gSaveContext.ship.stats.gameComplete && + (!IS_BOSS_RUSH || !gSaveContext.ship.quest.data.bossRush.isPaused)) { + gSaveContext.ship.stats.playTimer++; + gSaveContext.ship.stats.sceneTimer++; + gSaveContext.ship.stats.roomTimer++; if (CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA && Player_GetMask(play) == PLAYER_MASK_BUNNY) { - gSaveContext.sohStats.count[COUNT_TIME_BUNNY_HOOD]++; + gSaveContext.ship.stats.count[COUNT_TIME_BUNNY_HOOD]++; } } @@ -2220,7 +2220,7 @@ void Play_PerformSave(PlayState* play) { uint8_t triforceHuntCompleted = IS_RANDO && - gSaveContext.triforcePiecesCollected == (Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1) && + gSaveContext.ship.quest.data.randomizer.triforcePiecesCollected == (Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT_PIECES_REQUIRED) + 1) && Randomizer_GetSettingValue(RSK_TRIFORCE_HUNT); if (CVarGetInteger(CVAR_ENHANCEMENT("Autosave"), AUTOSAVE_OFF) != AUTOSAVE_OFF || triforceHuntCompleted) { Overlay_DisplayText(3.0f, "Game Saved"); diff --git a/soh/src/code/z_room.c b/soh/src/code/z_room.c index 2e8cdc655..fdd8f78f8 100644 --- a/soh/src/code/z_room.c +++ b/soh/src/code/z_room.c @@ -653,14 +653,14 @@ void func_80097534(PlayState* play, RoomContext* roomCtx) { Map_SavePlayerInitialInfo(play); } Audio_SetEnvReverb(play->roomCtx.curRoom.echo); - u8 idx = gSaveContext.sohStats.tsIdx; - gSaveContext.sohStats.sceneTimestamps[idx].scene = gSaveContext.sohStats.sceneNum; - gSaveContext.sohStats.sceneTimestamps[idx].room = gSaveContext.sohStats.roomNum; - gSaveContext.sohStats.sceneTimestamps[idx].roomTime = gSaveContext.sohStats.roomTimer / 2; - gSaveContext.sohStats.sceneTimestamps[idx].isRoom = - gPlayState->sceneNum == gSaveContext.sohStats.sceneTimestamps[idx].scene && - gPlayState->roomCtx.curRoom.num != gSaveContext.sohStats.sceneTimestamps[idx].room; - gSaveContext.sohStats.tsIdx++; - gSaveContext.sohStats.roomNum = roomCtx->curRoom.num; - gSaveContext.sohStats.roomTimer = 0; + u8 idx = gSaveContext.ship.stats.tsIdx; + gSaveContext.ship.stats.sceneTimestamps[idx].scene = gSaveContext.ship.stats.sceneNum; + gSaveContext.ship.stats.sceneTimestamps[idx].room = gSaveContext.ship.stats.roomNum; + gSaveContext.ship.stats.sceneTimestamps[idx].roomTime = gSaveContext.ship.stats.roomTimer / 2; + gSaveContext.ship.stats.sceneTimestamps[idx].isRoom = + gPlayState->sceneNum == gSaveContext.ship.stats.sceneTimestamps[idx].scene && + gPlayState->roomCtx.curRoom.num != gSaveContext.ship.stats.sceneTimestamps[idx].room; + gSaveContext.ship.stats.tsIdx++; + gSaveContext.ship.stats.roomNum = roomCtx->curRoom.num; + gSaveContext.ship.stats.roomTimer = 0; } diff --git a/soh/src/code/z_sram.c b/soh/src/code/z_sram.c index adea0cbbf..d6141d78b 100644 --- a/soh/src/code/z_sram.c +++ b/soh/src/code/z_sram.c @@ -142,7 +142,7 @@ void Sram_OpenSave() { } if (!CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0)) { - gSaveContext.maskMemory = PLAYER_MASK_NONE; + gSaveContext.ship.maskMemory = PLAYER_MASK_NONE; } osSyncPrintf("scene_no = %d\n", gSaveContext.entranceIndex); @@ -252,11 +252,11 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) { u8 currentQuest = fileChooseCtx->questType[fileChooseCtx->buttonIndex]; if (currentQuest == QUEST_RANDOMIZER && (Randomizer_IsSeedGenerated() || Randomizer_IsSpoilerLoaded())) { - gSaveContext.questId = QUEST_RANDOMIZER; + gSaveContext.ship.quest.id = QUEST_RANDOMIZER; Randomizer_InitSaveFile(); } else { - gSaveContext.questId = currentQuest; + gSaveContext.ship.quest.id = currentQuest; } Save_SaveFile(); diff --git a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c index bcb0cb1fc..b6fb10f3c 100644 --- a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c +++ b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c @@ -487,7 +487,7 @@ void EnBox_Open(EnBox* this, PlayState* play) { if (Animation_OnFrame(&this->skelanime, 30.0f)) { sfxId = NA_SE_EV_TBOX_UNLOCK; - gSaveContext.sohStats.count[COUNT_CHESTS_OPENED]++; + gSaveContext.ship.stats.count[COUNT_CHESTS_OPENED]++; } else if (Animation_OnFrame(&this->skelanime, 90.0f)) { sfxId = NA_SE_EV_TBOX_OPEN; } diff --git a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c index fb665f74d..e79b7c7c8 100644 --- a/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c +++ b/soh/src/overlays/actors/ovl_En_Dns/z_en_dns.c @@ -391,8 +391,8 @@ void func_809EFDD0(EnDns* this, PlayState* play) { pendingGetItemId = this->dnsItemEntry->getItemId; } GetItemEntry itemEntry = ItemTable_Retrieve(pendingGetItemId); - gSaveContext.pendingSale = itemEntry.itemId; - gSaveContext.pendingSaleMod = itemEntry.modIndex; + gSaveContext.ship.pendingSale = itemEntry.itemId; + gSaveContext.ship.pendingSaleMod = itemEntry.modIndex; Actor_OfferGetItem(&this->actor, play, pendingGetItemId, 130.0f, 100.0f); } diff --git a/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c b/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c index 497ba9388..82ae493db 100644 --- a/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c +++ b/soh/src/overlays/actors/ovl_En_Ds/z_en_ds.c @@ -206,8 +206,8 @@ void EnDs_OfferBluePotion(EnDs* this, PlayState* play) { if (GameInteractor_Should(VB_GIVE_ITEM_FROM_GRANNYS_SHOP, true, this)) { GetItemEntry itemEntry = ItemTable_Retrieve(GI_POTION_BLUE); Actor_OfferGetItem(&this->actor, play, GI_POTION_BLUE, 10000.0f, 50.0f); - gSaveContext.pendingSale = itemEntry.itemId; - gSaveContext.pendingSaleMod = itemEntry.modIndex; + gSaveContext.ship.pendingSale = itemEntry.itemId; + gSaveContext.ship.pendingSaleMod = itemEntry.modIndex; this->actionFunc = EnDs_GiveBluePotion; } diff --git a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c index b1ecb001e..3343fb615 100644 --- a/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c +++ b/soh/src/overlays/actors/ovl_En_GirlA/z_en_girla.c @@ -880,16 +880,16 @@ s32 EnGirlA_CanBuy_Randomizer(PlayState* play, EnGirlA* this) { void EnGirlA_ItemGive_Arrows(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Inventory_ChangeAmmo(ITEM_BOW, this->itemCount); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_Bombs(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; switch (this->itemCount) { case 5: Item_Give(play, ITEM_BOMBS_5); @@ -909,8 +909,8 @@ void EnGirlA_ItemGive_Bombs(PlayState* play, EnGirlA* this) { void EnGirlA_ItemGive_DekuNuts(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; switch (this->itemCount) { case 5: Item_Give(play, ITEM_NUTS_5); @@ -924,16 +924,16 @@ void EnGirlA_ItemGive_DekuNuts(PlayState* play, EnGirlA* this) { void EnGirlA_ItemGive_DekuSticks(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_STICK); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_Longsword(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; func_800849EC(play); gSaveContext.swordHealth = 8; Rupees_ChangeBy(-this->basePrice); @@ -941,86 +941,86 @@ void EnGirlA_ItemGive_Longsword(PlayState* play, EnGirlA* this) { void EnGirlA_ItemGive_HylianShield(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_SHIELD_HYLIAN); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_DekuShield(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_SHIELD_DEKU); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_GoronTunic(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_TUNIC_GORON); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_ZoraTunic(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_TUNIC_ZORA); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_Health(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Health_ChangeBy(play, this->itemCount); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_MilkBottle(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_MILK_BOTTLE); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_WeirdEgg(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_WEIRD_EGG); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_Unk19(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_Unk20(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_DekuSeeds(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Item_Give(play, ITEM_SEEDS_30); Rupees_ChangeBy(-this->basePrice); } void EnGirlA_ItemGive_BottledItem(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; switch (this->actor.params) { case SI_FISH: Item_Give(play, ITEM_FISH); @@ -1066,8 +1066,8 @@ void EnGirlA_ItemGive_Randomizer(PlayState* play, EnGirlA* this) { void EnGirlA_BuyEvent_ShieldDiscount(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; if (this->actor.params == SI_HYLIAN_SHIELD) { if (Flags_GetInfTable(INFTABLE_SHOWED_ZELDAS_LETTER_TO_GATE_GUARD)) { Rupees_ChangeBy(-(this->basePrice - sShieldDiscounts[(s32)Rand_ZeroFloat(7.9f)])); @@ -1079,22 +1079,22 @@ void EnGirlA_BuyEvent_ShieldDiscount(PlayState* play, EnGirlA* this) { void EnGirlA_BuyEvent_GoronTunic(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Rupees_ChangeBy(-this->basePrice); } void EnGirlA_BuyEvent_ZoraTunic(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Rupees_ChangeBy(-this->basePrice); } void EnGirlA_BuyEvent_ObtainBombchuPack(PlayState* play, EnGirlA* this) { GetItemEntry entry = ItemTable_Retrieve(this->getItemId); - gSaveContext.pendingSale = entry.itemId; - gSaveContext.pendingSaleMod = entry.modIndex; + gSaveContext.ship.pendingSale = entry.itemId; + gSaveContext.ship.pendingSaleMod = entry.modIndex; Rupees_ChangeBy(-this->basePrice); // Normally, buying a bombchu pack sets a flag indicating the pack is now sold out diff --git a/soh/src/overlays/actors/ovl_En_Js/z_en_js.c b/soh/src/overlays/actors/ovl_En_Js/z_en_js.c index 26e004f2f..48e62e400 100644 --- a/soh/src/overlays/actors/ovl_En_Js/z_en_js.c +++ b/soh/src/overlays/actors/ovl_En_Js/z_en_js.c @@ -135,8 +135,8 @@ void func_80A89160(EnJs* this, PlayState* play) { En_Js_SetupAction(this, func_80A8910C); } else { GetItemEntry itemEntry = ItemTable_Retrieve(GI_BOMBCHUS_10); - gSaveContext.pendingSale = itemEntry.itemId; - gSaveContext.pendingSaleMod = itemEntry.modIndex; + gSaveContext.ship.pendingSale = itemEntry.itemId; + gSaveContext.ship.pendingSaleMod = itemEntry.modIndex; Actor_OfferGetItem(&this->actor, play, GI_BOMBCHUS_10, 10000.0f, 50.0f); } } diff --git a/soh/src/overlays/actors/ovl_En_Kusa/z_en_kusa.c b/soh/src/overlays/actors/ovl_En_Kusa/z_en_kusa.c index 7389db34b..07274cad4 100644 --- a/soh/src/overlays/actors/ovl_En_Kusa/z_en_kusa.c +++ b/soh/src/overlays/actors/ovl_En_Kusa/z_en_kusa.c @@ -310,7 +310,7 @@ void EnKusa_Main(EnKusa* this, PlayState* play) { EnKusa_SpawnFragments(this, play); EnKusa_DropCollectible(this, play); SoundSource_PlaySfxAtFixedWorldPos(play, &this->actor.world.pos, 20, NA_SE_EV_PLANT_BROKEN); - gSaveContext.sohStats.count[COUNT_BUSHES_CUT]++; + gSaveContext.ship.stats.count[COUNT_BUSHES_CUT]++; if ((this->actor.params >> 4) & 1) { EnKusa_SpawnBugs(this, play); @@ -379,7 +379,7 @@ void EnKusa_Fall(EnKusa* this, PlayState* play) { if (this->actor.bgCheckFlags & 0xB) { if (!(this->actor.bgCheckFlags & 0x20)) { SoundSource_PlaySfxAtFixedWorldPos(play, &this->actor.world.pos, 20, NA_SE_EV_PLANT_BROKEN); - gSaveContext.sohStats.count[COUNT_BUSHES_CUT]++; + gSaveContext.ship.stats.count[COUNT_BUSHES_CUT]++; } EnKusa_SpawnFragments(this, play); EnKusa_DropCollectible(this, play); diff --git a/soh/src/overlays/actors/ovl_En_Ta/z_en_ta.c b/soh/src/overlays/actors/ovl_En_Ta/z_en_ta.c index 1e923335b..d2e1d109a 100644 --- a/soh/src/overlays/actors/ovl_En_Ta/z_en_ta.c +++ b/soh/src/overlays/actors/ovl_En_Ta/z_en_ta.c @@ -917,8 +917,8 @@ void func_80B15FE8(EnTa* this, PlayState* play) { EnTa_SetupAction(this, EnTa_GiveItemInLonLonHouse, EnTa_AnimRunToEnd); Rupees_ChangeBy(-30); GetItemEntry itemEntry = ItemTable_Retrieve(GI_MILK); - gSaveContext.pendingSale = itemEntry.itemId; - gSaveContext.pendingSaleMod = itemEntry.modIndex; + gSaveContext.ship.pendingSale = itemEntry.itemId; + gSaveContext.ship.pendingSaleMod = itemEntry.modIndex; Actor_OfferGetItem(&this->actor, play, GI_MILK, 10000.0f, 50.0f); break; } diff --git a/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c b/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c index 4cdc67e44..5c2c58dc4 100644 --- a/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c +++ b/soh/src/overlays/actors/ovl_Obj_Tsubo/z_obj_tsubo.c @@ -189,7 +189,7 @@ void ObjTsubo_AirBreak(ObjTsubo* this, PlayState* play) { sObjectIds[(this->actor.params >> 8) & 1], D_80BA1B8C[(this->actor.params >> 8) & 1]); } func_80033480(play, &this->actor.world.pos, 30.0f, 4, 20, 50, 1); - gSaveContext.sohStats.count[COUNT_POTS_BROKEN]++; + gSaveContext.ship.stats.count[COUNT_POTS_BROKEN]++; } void ObjTsubo_WaterBreak(ObjTsubo* this, PlayState* play) { @@ -218,7 +218,7 @@ void ObjTsubo_WaterBreak(ObjTsubo* this, PlayState* play) { (Rand_ZeroOne() * 95.0f) + 15.0f, 0, 32, 70, KAKERA_COLOR_NONE, sObjectIds[(this->actor.params >> 8) & 1], D_80BA1B8C[(this->actor.params >> 8) & 1]); } - gSaveContext.sohStats.count[COUNT_POTS_BROKEN]++; + gSaveContext.ship.stats.count[COUNT_POTS_BROKEN]++; } void ObjTsubo_SetupWaitForObject(ObjTsubo* this) { diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 8d229178b..496899bc6 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -1789,9 +1789,9 @@ void Player_PlaySteppingSfx(Player* this, f32 pitchAdjustment) { func_800F4010(&this->actor.projectedPos, sfxId, pitchAdjustment); // Gameplay stats: Count footsteps // Only count while game isn't complete and don't count Link's idle animations or crawling in crawlspaces - if (!gSaveContext.sohStats.gameComplete && !(this->stateFlags2 & PLAYER_STATE2_IDLE_FIDGET) && + if (!gSaveContext.ship.stats.gameComplete && !(this->stateFlags2 & PLAYER_STATE2_IDLE_FIDGET) && !(this->stateFlags2 & PLAYER_STATE2_CRAWLING)) { - gSaveContext.sohStats.count[COUNT_STEPS]++; + gSaveContext.ship.stats.count[COUNT_STEPS]++; } } @@ -2379,7 +2379,7 @@ void func_80833A20(Player* this, s32 newMeleeWeaponState) { } if (this->heldItemAction >= PLAYER_IA_SWORD_MASTER && this->heldItemAction <= PLAYER_IA_SWORD_BIGGORON) { - gSaveContext.sohStats.count[COUNT_SWORD_SWINGS]++; + gSaveContext.ship.stats.count[COUNT_SWORD_SWINGS]++; } } @@ -3484,7 +3484,7 @@ void Player_UseItem(PlayState* play, Player* this, s32 item) { this->currentMask = itemAction - PLAYER_IA_MASK_KEATON + 1; } - gSaveContext.maskMemory = this->currentMask; + gSaveContext.ship.maskMemory = this->currentMask; func_808328EC(this, NA_SE_PL_CHANGE_ARMS); } else if (((itemAction >= PLAYER_IA_OCARINA_FAIRY) && (itemAction <= PLAYER_IA_OCARINA_OF_TIME)) || @@ -5538,7 +5538,7 @@ void func_8083A0F4(PlayState* play, Player* this) { Player_SetupAction(play, this, Player_Action_8084F608, 0); this->stateFlags1 |= PLAYER_STATE1_IN_CUTSCENE; if (!CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0) || !CVarGetInteger(CVAR_ENHANCEMENT("AdultMasks"), 0)) { - gSaveContext.maskMemory = PLAYER_MASK_NONE; + gSaveContext.ship.maskMemory = PLAYER_MASK_NONE; } } else { LinkAnimationHeader* anim; @@ -6267,7 +6267,7 @@ void Player_SetupRoll(Player* this, PlayState* play) { LinkAnimation_PlayOnceSetSpeed(play, &this->skelAnime, GET_PLAYER_ANIM(PLAYER_ANIMGROUP_landing_roll, this->modelAnimType), 1.25f * sWaterSpeedFactor); - gSaveContext.sohStats.count[COUNT_ROLLS]++; + gSaveContext.ship.stats.count[COUNT_ROLLS]++; } s32 Player_TryRoll(Player* this, PlayState* play) { @@ -6326,10 +6326,10 @@ s32 Player_ActionHandler_10(Player* this, PlayState* play) { func_8083BCD0(this, play, controlStickDirection); if (controlStickDirection == 1 || controlStickDirection == 3) { - gSaveContext.sohStats.count[COUNT_SIDEHOPS]++; + gSaveContext.ship.stats.count[COUNT_SIDEHOPS]++; } if (controlStickDirection == 2) { - gSaveContext.sohStats.count[COUNT_BACKFLIPS]++; + gSaveContext.ship.stats.count[COUNT_BACKFLIPS]++; } return 1; @@ -7254,8 +7254,8 @@ void func_8083E4C4(PlayState* play, Player* this, GetItemEntry* giEntry) { s32 Player_ActionHandler_2(Player* this, PlayState* play) { Actor* interactedActor; - if(gSaveContext.pendingIceTrapCount) { - gSaveContext.pendingIceTrapCount--; + if(gSaveContext.ship.pendingIceTrapCount) { + gSaveContext.ship.pendingIceTrapCount--; GameInteractor_ExecuteOnItemReceiveHooks(ItemTable_RetrieveEntry(MOD_RANDOMIZER, RG_ICE_TRAP)); if (CVarGetInteger(CVAR_ENHANCEMENT("ExtraTraps.Enabled"), 0)) { return 1; @@ -7266,7 +7266,7 @@ s32 Player_ActionHandler_2(Player* this, PlayState* play) { this->getItemId = GI_NONE; this->getItemEntry = (GetItemEntry) GET_ITEM_NONE; // Gameplay stats: Increment Ice Trap count - gSaveContext.sohStats.count[COUNT_ICE_TRAPS]++; + gSaveContext.ship.stats.count[COUNT_ICE_TRAPS]++; return 1; } @@ -7295,7 +7295,7 @@ s32 Player_ActionHandler_2(Player* this, PlayState* play) { Player_SetPendingFlag(this, play); Message_StartTextbox(play, 0xF8, NULL); Audio_PlayFanfare(NA_BGM_SMALL_ITEM_GET); - gSaveContext.pendingIceTrapCount++; + gSaveContext.ship.pendingIceTrapCount++; return 1; } @@ -9513,7 +9513,7 @@ void func_80843AE8(PlayState* play, Player* this) { } else if (play->gameOverCtx.state == GAMEOVER_DEATH_WAIT_GROUND) { play->gameOverCtx.state = GAMEOVER_DEATH_DELAY_MENU; if (!CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0)) { - gSaveContext.maskMemory = PLAYER_MASK_NONE; + gSaveContext.ship.maskMemory = PLAYER_MASK_NONE; } } } @@ -9818,7 +9818,7 @@ void Player_Action_Roll(Player* this, PlayState* play) { Player_PlayVoiceSfx(this, NA_SE_VO_LI_CLIMB_END); this->av2.bonked = 1; - gSaveContext.sohStats.count[COUNT_BONKS]++; + gSaveContext.ship.stats.count[COUNT_BONKS]++; GameInteractor_ExecuteOnPlayerBonk(); return; @@ -10806,9 +10806,9 @@ void Player_Init(Actor* thisx, PlayState* play2) { //keep masks thru loading zones if (CVarGetInteger(CVAR_ENHANCEMENT("PersistentMasks"), 0)) { if (INV_CONTENT(ITEM_TRADE_CHILD) == ITEM_SOLD_OUT) { - gSaveContext.maskMemory = PLAYER_MASK_NONE; + gSaveContext.ship.maskMemory = PLAYER_MASK_NONE; } - this->currentMask = gSaveContext.maskMemory; + this->currentMask = gSaveContext.ship.maskMemory; } Player_InitCommon(this, play, gPlayerSkelHeaders[((void)0, gSaveContext.linkAge)]); // `giObjectSegment` is used for both "get item" objects and title cards. The maximum size for @@ -14282,7 +14282,7 @@ s32 func_8084DFF4(PlayState* play, Player* this) { // #region SOH [Randomizer] TODO Better Ice trap handling? if (this->getItemEntry.itemId == RG_ICE_TRAP && this->getItemEntry.modIndex == MOD_RANDOMIZER) { this->unk_862 = 0; - gSaveContext.pendingIceTrapCount++; + gSaveContext.ship.pendingIceTrapCount++; Player_SetPendingFlag(this, play); } // #endregion @@ -14460,7 +14460,7 @@ void Player_Action_8084E6D4(Player* this, PlayState* play) { this->actor.world.pos.y + 100.0f, this->actor.world.pos.z, 0, 0, 0, 0, true); func_8083C0E8(this, play); } else if (IS_RANDO) { - gSaveContext.pendingIceTrapCount++; + gSaveContext.ship.pendingIceTrapCount++; Player_SetPendingFlag(this, play); func_8083C0E8(this, play); } else { diff --git a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c index 9b964054e..dbff0955a 100644 --- a/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c +++ b/soh/src/overlays/gamestates/ovl_file_choose/z_file_choose.c @@ -989,7 +989,7 @@ void DrawSeedHashSprites(FileChooseContext* this) { this->configMode == CM_NAME_ENTRY_TO_RANDOMIZER_SETTINGS_MENU || this->configMode == CM_START_NAME_ENTRY || this->configMode == CM_START_RANDOMIZER_SETTINGS_MENU) || this->configMode == CM_RANDOMIZER_SETTINGS_MENU) && - gSaveContext.questId == QUEST_RANDOMIZER)) { + gSaveContext.ship.quest.id == QUEST_RANDOMIZER)) { gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF); u16 xStart = 64; @@ -1298,7 +1298,7 @@ void FileChoose_UpdateQuestMenu(GameState* thisx) { } if (CHECK_BTN_ALL(input->press.button, BTN_A)) { - gSaveContext.questId = this->questType[this->buttonIndex]; + gSaveContext.ship.quest.id = this->questType[this->buttonIndex]; if (this->questType[this->buttonIndex] == QUEST_BOSSRUSH) { Audio_PlaySoundGeneral(NA_SE_SY_FSEL_DECIDE_L, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); @@ -1393,17 +1393,17 @@ void FileChoose_UpdateBossRushMenu(GameState* thisx) { if (ABS(this->stickRelX) > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT | BTN_DRIGHT))) { if (this->stickRelX > 30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DRIGHT))) { // If exceeding the amount of choices for the selected option, cycle back to the first. - if ((gSaveContext.bossRushOptions[this->bossRushIndex] + 1) == BossRush_GetSettingOptionsAmount(this->bossRushIndex)) { - gSaveContext.bossRushOptions[this->bossRushIndex] = 0; + if ((gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex] + 1) == BossRush_GetSettingOptionsAmount(this->bossRushIndex)) { + gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex] = 0; } else { - gSaveContext.bossRushOptions[this->bossRushIndex]++; + gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex]++; } } else if (this->stickRelX < -30 || (dpad && CHECK_BTN_ANY(input->press.button, BTN_DLEFT))) { // If cycling back when already at the first choice for the selected option, cycle back to the last choice. - if ((gSaveContext.bossRushOptions[this->bossRushIndex] - 1) < 0) { - gSaveContext.bossRushOptions[this->bossRushIndex] = BossRush_GetSettingOptionsAmount(this->bossRushIndex) - 1; + if ((gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex] - 1) < 0) { + gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex] = BossRush_GetSettingOptionsAmount(this->bossRushIndex) - 1; } else { - gSaveContext.bossRushOptions[this->bossRushIndex]--; + gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex]--; } } @@ -1411,10 +1411,10 @@ void FileChoose_UpdateBossRushMenu(GameState* thisx) { } if (sLastBossRushOptionIndex != this->bossRushIndex || - sLastBossRushOptionValue != gSaveContext.bossRushOptions[this->bossRushIndex]) { - GameInteractor_ExecuteOnUpdateFileBossRushOptionSelection(this->bossRushIndex, gSaveContext.bossRushOptions[this->bossRushIndex]); + sLastBossRushOptionValue != gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex]) { + GameInteractor_ExecuteOnUpdateFileBossRushOptionSelection(this->bossRushIndex, gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex]); sLastBossRushOptionIndex = this->bossRushIndex; - sLastBossRushOptionValue = gSaveContext.bossRushOptions[this->bossRushIndex]; + sLastBossRushOptionValue = gSaveContext.ship.quest.data.bossRush.options[this->bossRushIndex]; } if (CHECK_BTN_ALL(input->press.button, BTN_B)) { @@ -2408,7 +2408,7 @@ void FileChoose_DrawWindowContents(GameState* thisx) { 65, (87 + textYOffset), 255, 255, 80, textAlpha, 0.8f, true); // Selected choice for option. - uint16_t finalKerning = Interface_DrawTextLine(this->state.gfxCtx, BossRush_GetSettingChoiceName(i, gSaveContext.bossRushOptions[i], gSaveContext.language), + uint16_t finalKerning = Interface_DrawTextLine(this->state.gfxCtx, BossRush_GetSettingChoiceName(i, gSaveContext.ship.quest.data.bossRush.options[i], gSaveContext.language), 165, (87 + textYOffset), 255, 255, 255, textAlpha, 0.8f, true); // Draw arrows around selected option. From ce289c0be9c40e8869f2ba4f4246ccb1aedb940b Mon Sep 17 00:00:00 2001 From: Pepper0ni <93387759+Pepper0ni@users.noreply.github.com> Date: Wed, 15 Jan 2025 12:05:52 +0000 Subject: [PATCH 04/60] Properly store starting age in spoiler log (#4873) * properly store starting age in spoiler log * convert ResolvedStatingAge to a setting to store it in the save --- .../Enhancements/randomizer/3drando/fill.cpp | 10 ++++----- .../randomizer/3drando/spoiler_log.cpp | 21 ++++++++++++------- soh/soh/Enhancements/randomizer/entrance.cpp | 4 ++-- .../randomizer/location_access.cpp | 8 +++---- soh/soh/Enhancements/randomizer/logic.cpp | 2 +- .../Enhancements/randomizer/randomizerTypes.h | 1 + .../randomizer/randomizer_check_tracker.cpp | 2 +- soh/soh/Enhancements/randomizer/savefile.cpp | 2 +- soh/soh/Enhancements/randomizer/settings.cpp | 12 ++++------- soh/soh/Enhancements/randomizer/settings.h | 9 -------- 10 files changed, 32 insertions(+), 39 deletions(-) diff --git a/soh/soh/Enhancements/randomizer/3drando/fill.cpp b/soh/soh/Enhancements/randomizer/3drando/fill.cpp index 248fd960d..c86b7eff9 100644 --- a/soh/soh/Enhancements/randomizer/3drando/fill.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/fill.cpp @@ -130,14 +130,14 @@ static bool UpdateToDAccess(Entrance* entrance, Region* connection) { static void ValidateOtherEntrance(GetAccessibleLocationsStruct& gals) { auto ctx = Rando::Context::GetInstance(); // Condition for validating Temple of Time Access - if (!gals.foundTempleOfTime && ((ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD && RegionTable(RR_TEMPLE_OF_TIME)->Adult()) || - (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_ADULT && RegionTable(RR_TEMPLE_OF_TIME)->Child()))) { + if (!gals.foundTempleOfTime && ((ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD) && RegionTable(RR_TEMPLE_OF_TIME)->Adult()) || + (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_ADULT) && RegionTable(RR_TEMPLE_OF_TIME)->Child()))) { gals.foundTempleOfTime = true; } // Condition for validating a valid starting region if (!gals.validatedStartingRegion) { - bool childAccess = ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD || RegionTable(RR_TOT_BEYOND_DOOR_OF_TIME)->Child(); - bool adultAccess = ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_ADULT || RegionTable(RR_TOT_BEYOND_DOOR_OF_TIME)->Adult(); + bool childAccess = ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD) || RegionTable(RR_TOT_BEYOND_DOOR_OF_TIME)->Child(); + bool adultAccess = ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_ADULT) || RegionTable(RR_TOT_BEYOND_DOOR_OF_TIME)->Adult(); Region* kokiri = RegionTable(RR_KOKIRI_FOREST); Region* kakariko = RegionTable(RR_KAKARIKO_VILLAGE); @@ -168,7 +168,7 @@ static void ValidateSphereZero(GetAccessibleLocationsStruct& gals){ // Apply all items that are necessary for checking all location access ApplyAllAdvancmentItems(); // Reset access as the non-starting age - if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { + if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD)) { for (RandomizerRegion regionKey : gals.regionPool) { RegionTable(regionKey)->adultDay = false; RegionTable(regionKey)->adultNight = false; diff --git a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp index bed532e9b..10c1afb60 100644 --- a/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp +++ b/soh/soh/Enhancements/randomizer/3drando/spoiler_log.cpp @@ -206,14 +206,19 @@ static void WriteMasterQuestDungeons() { } // Writes the required trials to the spoiler log, if there are any. -static void WriteRequiredTrials() { - auto ctx = Rando::Context::GetInstance(); - for (const auto& trial : ctx->GetTrials()->GetTrialList()) { - if (trial->IsRequired()) { - std::string trialName = trial->GetName().GetForCurrentLanguage(MF_CLEAN); - jsonData["requiredTrials"].push_back(RemoveLineBreaks(trialName)); - } +static void WriteChosenOptions() { + auto ctx = Rando::Context::GetInstance(); + for (const auto& trial : ctx->GetTrials()->GetTrialList()) { + if (trial->IsRequired()) { + std::string trialName = trial->GetName().GetForCurrentLanguage(MF_CLEAN); + jsonData["requiredTrials"].push_back(RemoveLineBreaks(trialName)); } + } + if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_ADULT)){ + jsonData["SelectedStartingAge"] = "Adult"; + } else { + jsonData["SelectedStartingAge"] = "Child"; + } } // Writes the intended playthrough to the spoiler log, separated into spheres. @@ -331,7 +336,7 @@ const char* SpoilerLog_Write() { WriteStartingInventory(); WriteEnabledTricks(); WriteMasterQuestDungeons(); - WriteRequiredTrials(); + WriteChosenOptions(); WritePlaythrough(); ctx->playthroughLocations.clear(); diff --git a/soh/soh/Enhancements/randomizer/entrance.cpp b/soh/soh/Enhancements/randomizer/entrance.cpp index 1e28aa2c3..910467e81 100644 --- a/soh/soh/Enhancements/randomizer/entrance.cpp +++ b/soh/soh/Enhancements/randomizer/entrance.cpp @@ -536,10 +536,10 @@ static bool ValidateWorld(Entrance* entrancePlaced) { // The player should be able to get back to ToT after going through time, without having collected any items // This is important to ensure that the player never loses access to the pedestal after going through time - if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD && !RegionTable(RR_TEMPLE_OF_TIME)->Adult()) { + if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD) && !RegionTable(RR_TEMPLE_OF_TIME)->Adult()) { SPDLOG_DEBUG("Path to Temple of Time as adult is not guaranteed\n"); return false; - } else if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_ADULT && + } else if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_ADULT) && !RegionTable(RR_TEMPLE_OF_TIME)->Child()) { SPDLOG_DEBUG("Path to Temple of Time as child is not guaranteed\n"); return false; diff --git a/soh/soh/Enhancements/randomizer/location_access.cpp b/soh/soh/Enhancements/randomizer/location_access.cpp index d3a17a0b9..64f0b23d5 100644 --- a/soh/soh/Enhancements/randomizer/location_access.cpp +++ b/soh/soh/Enhancements/randomizer/location_access.cpp @@ -438,13 +438,13 @@ namespace Regions { } if (/*Settings::HasNightStart TODO:: Randomize Starting Time*/ false) { - if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { + if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD)) { RegionTable(RR_ROOT)->childNight = true; } else { RegionTable(RR_ROOT)->adultNight = true; } } else { - if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { + if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD)) { RegionTable(RR_ROOT)->childDay = true; } else { RegionTable(RR_ROOT)->adultDay = true; @@ -465,13 +465,13 @@ namespace Regions { } if (/*Settings::HasNightStart TODO:: Randomize Starting Time*/ false) { - if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { + if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD)) { RegionTable(RR_ROOT)->childNight = true; } else { RegionTable(RR_ROOT)->adultNight = true; } } else { - if (ctx->GetSettings()->ResolvedStartingAge() == RO_AGE_CHILD) { + if (ctx->GetOption(RSK_SELECTED_STARTING_AGE).Is(RO_AGE_CHILD)) { RegionTable(RR_ROOT)->childDay = true; } else { RegionTable(RR_ROOT)->adultDay = true; diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index 85104d825..b107ea939 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -2149,7 +2149,7 @@ namespace Rando { //Other AtDay = false; AtNight = false; - GetSaveContext()->linkAge = !ctx->GetSettings()->ResolvedStartingAge(); + GetSaveContext()->linkAge = !ctx->GetOption(RSK_SELECTED_STARTING_AGE).GetContextOptionIndex(); //Events ShowedMidoSwordAndShield = false; diff --git a/soh/soh/Enhancements/randomizer/randomizerTypes.h b/soh/soh/Enhancements/randomizer/randomizerTypes.h index 87ba34adf..703b2a301 100644 --- a/soh/soh/Enhancements/randomizer/randomizerTypes.h +++ b/soh/soh/Enhancements/randomizer/randomizerTypes.h @@ -5098,6 +5098,7 @@ typedef enum { RSK_ZORAS_FOUNTAIN, RSK_SLEEPING_WATERFALL, RSK_STARTING_AGE, + RSK_SELECTED_STARTING_AGE, RSK_GERUDO_FORTRESS, RSK_RAINBOW_BRIDGE, RSK_RAINBOW_BRIDGE_STONE_COUNT, diff --git a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp index ecd572ab9..c65c3c00d 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp +++ b/soh/soh/Enhancements/randomizer/randomizer_check_tracker.cpp @@ -490,7 +490,7 @@ void CheckTrackerLoadGame(int32_t fileNum) { } } if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING && IS_RANDO) { - s8 startingAge = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_STARTING_AGE); + uint8_t startingAge = OTRGlobals::Instance->gRandoContext->GetOption(RSK_SELECTED_STARTING_AGE).GetContextOptionIndex(); RandomizerCheckArea startingArea; switch (startingAge) { case RO_AGE_CHILD: diff --git a/soh/soh/Enhancements/randomizer/savefile.cpp b/soh/soh/Enhancements/randomizer/savefile.cpp index 44a4a859e..af7abd49e 100644 --- a/soh/soh/Enhancements/randomizer/savefile.cpp +++ b/soh/soh/Enhancements/randomizer/savefile.cpp @@ -272,7 +272,7 @@ extern "C" void Randomizer_InitSaveFile() { Flags_SetRandomizerInf(RAND_INF_SCRUBS_PURCHASED_HF_DEKU_SCRUB_GROTTO); } - int startingAge = OTRGlobals::Instance->gRandoContext->GetSettings()->ResolvedStartingAge(); + int startingAge = OTRGlobals::Instance->gRandoContext->GetOption(RSK_SELECTED_STARTING_AGE).GetContextOptionIndex(); switch (startingAge) { case RO_AGE_ADULT: // Adult gSaveContext.linkAge = LINK_AGE_ADULT; diff --git a/soh/soh/Enhancements/randomizer/settings.cpp b/soh/soh/Enhancements/randomizer/settings.cpp index f5abde703..0c5e6c41c 100644 --- a/soh/soh/Enhancements/randomizer/settings.cpp +++ b/soh/soh/Enhancements/randomizer/settings.cpp @@ -126,6 +126,7 @@ void Settings::CreateOptions() { mOptions[RSK_GANONS_TRIALS] = Option::U8("Ganon's Trials", {"Skip", "Set Number", "Random Number"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GanonTrial"), mOptionDescriptions[RSK_GANONS_TRIALS], WidgetType::Combobox, RO_GANONS_TRIALS_SET_NUMBER); mOptions[RSK_TRIAL_COUNT] = Option::U8("Ganon's Trials Count", {NumOpts(0, 6)}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("GanonTrialCount"), mOptionDescriptions[RSK_TRIAL_COUNT], WidgetType::Slider, 6, true); mOptions[RSK_STARTING_AGE] = Option::U8("Starting Age", {"Child", "Adult", "Random"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("StartingAge"), mOptionDescriptions[RSK_STARTING_AGE], WidgetType::Combobox, RO_AGE_CHILD); + mOptions[RSK_SELECTED_STARTING_AGE] = Option::U8("Selected Starting Age", {"Child", "Adult"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("SelectedStartingAge"), mOptionDescriptions[RSK_STARTING_AGE], WidgetType::Combobox, RO_AGE_CHILD); mOptions[RSK_SHUFFLE_ENTRANCES] = Option::Bool("Shuffle Entrances"); mOptions[RSK_SHUFFLE_DUNGEON_ENTRANCES] = Option::U8("Dungeon Entrances", {"Off", "On", "On + Ganon"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleDungeonsEntrances"), mOptionDescriptions[RSK_SHUFFLE_DUNGEON_ENTRANCES], WidgetType::Combobox, RO_DUNGEON_ENTRANCE_SHUFFLE_OFF); mOptions[RSK_SHUFFLE_BOSS_ENTRANCES] = Option::U8("Boss Entrances", {"Off", "Age Restricted", "Full"}, OptionCategory::Setting, CVAR_RANDOMIZER_SETTING("ShuffleBossEntrances"), mOptionDescriptions[RSK_SHUFFLE_BOSS_ENTRANCES], WidgetType::Combobox, RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF); @@ -1327,11 +1328,6 @@ std::vector