From 4a3096178416cbb666ce74af02821607eba9d268 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 05:04:36 +0000 Subject: [PATCH] Co-op: clear a placed partner's spawn bit so currents lift him Native spawns store HP|$80 in .27 and the world actor's arrival clears bit 7; co-op's partner placement stores HP|$80 too, but nothing ever cleared it, so Zero kept it all stage. Contact damage ignores the bit, but Launch Octopus's current generator ($28) skips such a body: with the replay running its four $82:D7D7 boxes on Zero's body every frame (the trace shows eight queries per frame), Zero was still never flagged. Clear the bit for a living partner in play at frame end. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Tu7jQG5NbXoKrTYTT7y7n3 --- docs/coop-interaction-ownership.md | 1 + src/mmx_coop.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/docs/coop-interaction-ownership.md b/docs/coop-interaction-ownership.md index 3e49ee6..b1a89a1 100644 --- a/docs/coop-interaction-ownership.md +++ b/docs/coop-interaction-ownership.md @@ -42,6 +42,7 @@ The partner never triggers or advances these. | Stage death and checkpoint | `death_hook` (`$00:9D9E`, `$00:9AC7`, `$81:8A5C..8B0B`) | A death with a living partner runs the native death pose, but the partner keeps playing (`solo_death`). A whole-team death resets to P1 at the checkpoint. | No change expected. | | E-tank elevator carry | `lift_rtl_hook`, `MmxCoopLiftCarry` | The handler carries the projected body; co-op carries the partner by the same distance. | Both ride; not ownership. | | Sprite priority (`.11` bits 4-5) | `MmxCoopSyncPriority` (frame end) | Stage sections write the priority to the world actor once (Storm Eagle's ship sets priority 3). The living partner copies the world actor's bits every frame. | No change expected. | +| Partner "in play" bit (`.27` bit 7) | `MmxCoopSyncPriority` (frame end) | Spawns store HP\|`$80` and death stores `$80`; the world actor's arrival clears the bit, but a placed partner kept it permanently. Launch Octopus's current generator (`$28`) ignores bodies with it set. A living partner in play now has it cleared each frame. | Both seats. | | Ground-shock stun (action `$36`, Flame Mammoth's stomp) | `MmxCoopSyncPriority` (frame end) | The boss tests only the projected world actor. When the world actor enters `$36`, a grounded, living partner enters it the same frame. | Both seats. | ## 2. Both players, through a partner retry diff --git a/src/mmx_coop.c b/src/mmx_coop.c index bc6cb34..bc9c2ed 100644 --- a/src/mmx_coop.c +++ b/src/mmx_coop.c @@ -1008,6 +1008,13 @@ void MmxCoopSyncPriority(uint8_t *r) { * Left 0, X's wrapped to 255 and kept him stunned ~288 frames. */ body[2]=0x36;body[3]=0;body[0x85]=world[0x85]; } + /* .27 bit 7 marks a body not yet (or no longer) in play: spawns store + * HP|$80 and death stores $80. The world actor's arrival clears it, but a + * placed partner kept it for good. Contact damage ignores it; Launch + * Octopus's current generator ($28) does not, so it never lifted him. */ + if((body[0x27]&128) && (body[0x27]&127) && !(world[0x27]&128) && action!=0x0c && + !MmxCoopTransitionActive()) + body[0x27]&=127; } static void eagle_lift_hook(CpuState *cpu,uint32_t pc) { if(!enabled || !state.initialized || state.menu_owner || state.scene_owner) return;