Skip to content

Fix Platform Failing to Lower After Defeating Big Octo#6622

Open
unreference wants to merge 1 commit into
HarbourMasters:developfrom
unreference:fix/big-octo-platform-fail
Open

Fix Platform Failing to Lower After Defeating Big Octo#6622
unreference wants to merge 1 commit into
HarbourMasters:developfrom
unreference:fix/big-octo-platform-fail

Conversation

@unreference
Copy link
Copy Markdown

@unreference unreference commented May 15, 2026

This fixes #4339.

After defeating Big Octo, the platform sometimes fails to lower, softlocking dungeon progression. One comment that stuck out to me and one I was able to also experience when trying to reproduce the bug was the platform not rotating during the fight before it occurs.

I added diagnostic logging to the Big Octo platform state machine and Big Octo's death sequence and was able to get "successful" logs twice. In both failures:

  • Flags_SetClear for room 6 was confirmed to fire on Big Octo's death
  • The platform's BattleInProgress function never detected the clear flag

This means that the platform was not in BattleInProgress when Big Octo died, despite plenty of time for the cutscene sequence to complete.

BgBdanObjects_OctoPlatform_BattleInProgress is the only state that checks for Flags_GetClear, and the platform itself has to pass through a multi-state cutscene sequence to reach it:

  1. WaitForRutoToStartCutscene
  2. RaiseToUpperPosition
  3. WaitForRutoToAdvanceCutscene
  4. PauseBeforeDescending
  5. DescendWithBigOcto
  6. WaitForBigOctoToStartBattle
  7. BattleInProgress

If the platform fails to reach BattleInProgress for any reason -- or is knocked out of it -- Big Octo's death goes permanently unacknowledged. The clear flag is set but never read. This is actually a structural vulnerability on original hardware as well, but there are never enough differing variables to trigger it.

To fix this, a fallback check was added to BgBdanObjects_Update to detect when Big Octo has been defeated but the platform has not yet responded:

    if (thisx->params == 0 && Flags_GetClear(play, thisx->room) && !Flags_GetSwitch(play, this->switchFlag)) {
        Flags_SetSwitch(play, this->switchFlag);
        this->dyna.actor.home.rot.y = (s16)(this->dyna.actor.shape.rot.y + 0x2000) & 0xC000;
        this->actionFunc = BgBdanObjects_SinkToFloorHeight;
    }

This mirrors the existing transition in BattleInProgress:

if (Flags_GetClear(play, this->dyna.actor.room)) {
Flags_SetSwitch(play, this->switchFlag);
this->dyna.actor.home.rot.y = (s16)(this->dyna.actor.shape.rot.y + 0x2000) & 0xC000;
this->actionFunc = BgBdanObjects_SinkToFloorHeight;

The three conditions ensure it only fires when the bug is actively occurring:

  • params == 0: Only the Big Octo platform variant, not the elevator or water objects
  • Flags_GetClear: Big Octo is dead -- this flag is only set by En_Bigokuta's death sequence
  • !Flags_GetSwitch: The platform has not already begun its descent -- the switch flag is set by both the normal BattleInProgress path and the Init reentry path, so this condition is false during all post-battle states

There is no combination of normal gameplay states where all three conditions are true simultaneously unless the bug has occurred. The switch flag life cycle for the Big Octo platform (params == 0) is:

  1. Init (pre-Ruto): Flags_SetSwitch -> switch on
  2. PauseBeforeDescending (timer == 0): Flags_UnsetSwitch -> switch off
  3. BattleInProgress (clear flag detected): Flags_SetSwitch -> switch on

The fallback only fires between steps 2 and 3 -- when the switch is off and the clear flag is set -- which is exactly the window where the bug manifests.

This bug is incredibly difficult to reproduce reliably. My two reproductions captured via logging both occurred in randomizer seeds on the first-visit path, with Big Octo defeated quickly via Deku Stick jump slash. In the second instance, Big Octo entered his retreat state on battle start which is an impossibility -- he is hardcoded to always move toward Link first. This, along with the platform not rotating during the battle, heavily suggests memory corruption as the underlying trigger, but this is hard to prove and the structural fix addresses the symptom regardless of root cause.

@unreference unreference changed the base branch from develop to develop-ackbar May 15, 2026 23:42
@unreference unreference changed the base branch from develop-ackbar to develop May 15, 2026 23:44
// when Big Octo dies, the clear flag goes permanently unread. This fallback catches that case: the clear flag is
// only ever set by Big Octo's death, and the switch flag is only set once the platform has already begun its
// descent.
if (thisx->params == 0 && Flags_GetClear(play, thisx->room) && !Flags_GetSwitch(play, this->switchFlag)) {
Copy link
Copy Markdown
Member

@serprex serprex May 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this only happen due to cutscene skips?

code should be made as a timesaver hook

Copy link
Copy Markdown
Author

@unreference unreference May 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Investigated this angle a bit. The VB_PLAY_ONEPOINT_ACTOR_CS hook fires identically in both successful and failed rando runs. Vanilla runs without the timesaver show the same flag sequence, so the timesaver does not seem to be a factor.

OnePointCutscene_Attention does route through OnePointCutscene_Init, so the ACTOR_BG_BDAN_SWITCH skip in the timesave handler does fire after Big Octo dies, but the Bdan switch is ACTORCAT_SWITCH (cat 0) and the platform is ACTORCAT_BG (cat 1). The switch skip happens one frame after the platform has already transitioned to SinkToFloorHeight, so it can't interfere.

Failed run 1:

[11:06:04.065] VB_PLAY_ONEPOINT_ACTOR_CS ID:198 Cat:6
[11:06:39.708] Clear Flag Set - 0x6

Failed run 2:

[11:14:26.621] VB_PLAY_ONEPOINT_ACTOR_CS ID:198 Cat:6
[11:15:17.470] Clear Flag Set - 0x6

No fail, rando:

[04:55:28.234] VB_PLAY_ONEPOINT_ACTOR_CS ID:198 Cat:6
[04:55:46.784] Clear Flag Set - 0x6
[04:55:46.834] Switch Flag Set - 0x1f

No fail, vanilla:

[04:52:53.185] Clear Flag Set - 0x6
[04:52:53.251] Switch Flag Set - 0x1f

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why doesn't this show up on console?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A little suspect in general that this actually happens without the cutscene skip, as this bug definitely didn't exist in Ship before we had those.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[rando] Bigocto platform didn't lower

3 participants