diff --git a/src/sm_85.c b/src/sm_85.c index 2aa7436..909cd40 100644 --- a/src/sm_85.c +++ b/src/sm_85.c @@ -344,7 +344,7 @@ CoroutineRet HandleMessageBoxInteraction_Async(void) { // 0x85846D do { COROUTINE_AWAIT(3, WaitForNMI_NoUpdate_Async()); ReadJoypadInputs(); - } while (!joypad1_lastkeys); + } while ((bug_fix_counter < 1 ? joypad1_newkeys : joypad1_lastkeys) == 0); } GETOUT:; COROUTINE_END(0); diff --git a/src/sm_a4.c b/src/sm_a4.c index 2e8ca5d..d37c1b9 100644 --- a/src/sm_a4.c +++ b/src/sm_a4.c @@ -27,7 +27,7 @@ static const uint16 g_word_A486A4 = 0x640; #define g_word_A49BC7 (*(uint16*)RomPtr(0xa49bc7)) #define g_word_A49BC9 (*(uint16*)RomPtr(0xa49bc9)) #define g_word_A49BCB (*(uint16*)RomPtr(0xa49bcb)) -#define g_byte_A49697 ((uint8*)RomPtr(0xa49697)) +#define kCrocoVlineRandomPos ((uint8*)RomPtr(0xa49697)) #define g_word_A49BBD ((uint16*)RomPtr(0xa49bbd)) #define g_word_A498CA ((uint16*)RomPtr(0xa498ca)) #define g_word_A499CB ((uint16*)RomPtr(0xa499cb)) @@ -394,7 +394,7 @@ void Crocomire_Init(void) { // 0xA48A5A if ((*(uint16 *)&boss_bits_for_area[area_index] & 2) != 0) { *(uint16 *)scrolls = 257; *(uint16 *)&scrolls[2] = 257; - *(uint16 *)&g_byte_7E0688 = 0; + croco_target_0688 = 0; Enemy_Crocomire *E = Get_Crocomire(0); E->base.properties = E->base.properties & 0x7BFF | 0x400; static const SpawnHardcodedPlmArgs unk_A48AFA = { 0x20, 0x03, 0xb753 }; @@ -419,7 +419,7 @@ void Crocomire_Init(void) { // 0xA48A5A vram_write_queue_tail = v6 + 7; } else { DisableMinimapAndMarkBossRoomAsExplored(); - g_word_7E069A = 0; + croco_word_7E069A = 0; Enemy_Crocomire *E = Get_Crocomire(cur_enemy_index); E->crocom_var_A = 0; E->crocom_var_E = 0; @@ -815,7 +815,7 @@ void Crocomire_Func_49(void) { // 0xA49099 Get_Crocomire(0x40u)->base.properties |= 0x200u; SpawnHardcodedPlm(&unk_A490D4); camera_distance_index = 0; - *(uint16 *)&g_byte_7E0688 = 0; + croco_target_0688 = 0; } } @@ -1018,8 +1018,8 @@ void Crocomire_92D8(void) { // 0xA492D8 void Crocomire_Func_57(void) { // 0xA49341 int i; - *(uint16 *)&g_byte_7E068C = 48; - *(uint16 *)&g_byte_7E0688 = 48; + croco_word_068C = 48; + croco_target_0688 = 48; Enemy_Crocomire *E = Get_Crocomire(cur_enemy_index); ++E->crocom_var_A; ++E->crocom_var_A; @@ -1074,8 +1074,8 @@ void Crocomire_Func_59(void) { // 0xA493ED ++E->crocom_var_A; ++E->crocom_var_A; E->base.instruction_timer = 1; - *(uint16 *)&g_byte_7E068C = 48; - *(uint16 *)&g_byte_7E0688 = 48; + croco_word_068C = 48; + croco_target_0688 = 48; E->base.current_instruction = addr_kCrocomire_Ilist_BF7E; uint16 v1 = 0; do { @@ -1100,15 +1100,15 @@ void Crocomire_Func_60(void) { // 0xA4943D ++E->crocom_var_A; ++E->crocom_var_A; g_word_7E0692 = 256; - g_word_7E0690 = 0; - g_word_7E0698 = *(uint16 *)((char *)&g_word_A49BC5 + g_word_7E069A); + croco_cur_vline_idx = 0; + g_word_7E0698 = *(uint16 *)((char *)&g_word_A49BC5 + croco_word_7E069A); g_word_7E0694 = g_word_7E0698; - g_word_7E0696 = *(uint16 *)((char *)&g_word_A49BC7 + g_word_7E069A); - g_word_7E068E = *(uint16 *)((char *)&g_word_A49BC9 + g_word_7E069A); + g_word_7E0696 = *(uint16 *)((char *)&g_word_A49BC7 + croco_word_7E069A); + g_word_7E068E = *(uint16 *)((char *)&g_word_A49BC9 + croco_word_7E069A); R0_.addr = 0; - *(uint16 *)&R0_.bank = *(uint16 *)((char *)&g_word_A49BCB + g_word_7E069A); + *(uint16 *)&R0_.bank = *(uint16 *)((char *)&g_word_A49BCB + croco_word_7E069A); uint16 v6; - for (i = g_word_7E069A + 8; ; i = v6 + 4) { + for (i = croco_word_7E069A + 8; ; i = v6 + 4) { uint16 v2 = *(uint16 *)((char *)&g_word_A49BC5 + i); if (v2 == 0xFFFF) break; @@ -1123,10 +1123,10 @@ void Crocomire_Func_60(void) { // 0xA4943D --R18_; } while ((R18_ & 0x8000u) == 0); } - g_word_7E069A = i + 2; + croco_word_7E069A = i + 2; g_word_7E068A = i + 2; for (j = 128; j >= 0; j -= 2) - *(uint16 *)&g_byte_7E069C[(uint16)j] = 0; + *(uint16 *)&croco_vline_height[(uint16)j] = 0; } void Crocomire_Func_61(void) { // 0xA494B2 @@ -1215,11 +1215,10 @@ void Crocomire_Func_65(void) { // 0xA49580 if ((int16)(g_word_7E0692 - 20480) >= 0) { LABEL_4:; Enemy_Crocomire *EK = Get_Crocomire(cur_enemy_index); - ++EK->crocom_var_A; - ++EK->crocom_var_A; - for (i = g_word_7E069A; *(uint16 *)((char *)&g_word_A49BC5 + i) != 0xFFFF; i += 8) + EK->crocom_var_A += 2; + for (i = croco_word_7E069A; *(uint16 *)((char *)&g_word_A49BC5 + i) != 0xFFFF; i += 8) ; - g_word_7E069A = i + 2; + croco_word_7E069A = i + 2; hdma_object_channels_bitmask[E0->crocom_var_1F >> 1] = 0; return; } @@ -1272,63 +1271,58 @@ void Crocomire_Func_66(void) { // 0xA49653 } -static const uint8 g_byte_A49BBD[8] = { 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe }; +static const uint8 kCrocoEraseLineMasks[8] = { 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe }; +// Used when dissolving the crocomire thing uint16 Crocomire_Func_67(void) { // 0xA496C8 VramWriteEntry *v9; - uint16 result = 0; - R18_ = g_byte_7E068C; + int n = croco_word_068C; R20_ = 0; R22_ = 0; - uint16 v2 = g_word_7E0690; while (1) { - LOBYTE(result) = g_byte_A49697[v2]; - if ((int8)(g_byte_7E069C[result] - g_byte_7E0688) < 0) + if (croco_cur_vline_idx > 48) // bugfix + return 1; + int rr = kCrocoVlineRandomPos[croco_cur_vline_idx]; + if ((int8)(croco_vline_height[rr] - croco_target_0688) < 0) break; - if ((int16)(++v2 - 128) >= 0) { - LOBYTE(g_word_7E0690) = 0; + if (++croco_cur_vline_idx >= 128) { + croco_cur_vline_idx = 0; return 0; } } - g_word_7E0690 = v2; - result = v2 & 7; - uint16 v3 = result; + assert(croco_cur_vline_idx <= 48); + int vline_idx = kCrocoVlineRandomPos[croco_cur_vline_idx]; + uint8 mask = kCrocoEraseLineMasks[vline_idx & 7]; do { - uint16 v4 = g_byte_A49697[g_word_7E0690]; - R20_ = 4 * (v4 & 0xFFF8); - R20_ += 2 * (g_byte_7E069C[v4] & 7); - uint16 v5 = R20_ + ((*(uint16 *)&g_byte_7E069C[v4] & 0xFFF8) << 6); - ram4000.backups.field_0[v5] &= g_byte_A49BBD[v3]; - ram4000.backups.field_0[v5 + 1] &= g_byte_A49BBD[v3]; - ram4000.backups.field_0[v5 + 16] &= g_byte_A49BBD[v3]; - ram4000.backups.field_0[v5 + 17] &= g_byte_A49BBD[v3]; - uint8 v6 = g_byte_A49697[g_word_7E0690]; - if (g_byte_7E069C[v6] == 48) + int q = croco_vline_height[vline_idx]; + int j = 2 * (q & 7) + ((q & ~7) << 6) + 4 * (vline_idx & ~7); + ram4000.backups.field_0[j + 0] &= mask; + ram4000.backups.field_0[j + 1] &= mask; + ram4000.backups.field_0[j + 16] &= mask; + ram4000.backups.field_0[j + 17] &= mask; + + if (croco_vline_height[vline_idx] == 48) break; - ++ *(uint16 *)&g_byte_7E069C[v6]; - R22_ = g_byte_7E069C[v6]; + croco_vline_height[vline_idx]++; --R18_; - } while (R18_); + } while (--n); + uint16 v7, v8; while (1) { - v7 = g_word_7E068A + g_word_7E069A; + v7 = g_word_7E068A + croco_word_7E069A; v8 = vram_write_queue_tail; - if (*(uint16 *)((char *)&g_word_A49BC5 + (uint16)(g_word_7E068A + g_word_7E069A)) != 0xFFFF) + if (*(uint16 *)((char *)&g_word_A49BC5 + v7) != 0xFFFF) break; g_word_7E068A = 0; } v9 = gVramWriteEntry(vram_write_queue_tail); - v9->size = *(uint16 *)((char *)&g_word_A49BC5 + (uint16)(g_word_7E068A + g_word_7E069A)); + v9->size = *(uint16 *)((char *)&g_word_A49BC5 + v7); v9->src.addr = *(uint16 *)((char *)&g_word_A49BCB + v7); *(uint16 *)&v9->src.bank = *(uint16 *)((char *)&g_word_A49BC9 + v7); v9->vram_dst = *(uint16 *)((char *)&g_word_A49BC7 + v7); vram_write_queue_tail = v8 + 7; g_word_7E068A += 8; - uint16 v10 = g_word_7E0690; - if (!sign16(g_word_7E0690 - 128)) - g_word_7E0690 = 0; - g_word_7E0690 = v10; return 1; } @@ -1419,8 +1413,8 @@ void Crocomire_Func_71(void) { // 0xA4990A uint16 crocom_var_D = E->crocom_var_D; if (crocom_var_D) { E->crocom_var_D = crocom_var_D - 1; - v3 = *(uint16 *)&g_byte_7E0688; - int v4 = *(uint16 *)&g_byte_7E0688 >> 1; + v3 = croco_target_0688; + int v4 = croco_target_0688 >> 1; if (g_word_A499CB[v4] != 0xFFFF) { uint16 v5 = vram_write_queue_tail; v6 = gVramWriteEntry(vram_write_queue_tail); @@ -1430,7 +1424,7 @@ void Crocomire_Func_71(void) { // 0xA4990A R18_ = (reg_OBSEL & 7) << 13; v6->vram_dst = g_word_A499CB[v4] + R18_; vram_write_queue_tail = v5 + 7; - *(uint16 *)&g_byte_7E0688 = v3 + 2; + croco_target_0688 = v3 + 2; } } else { E->base.x_pos = 480; diff --git a/src/sm_cpu_infra.c b/src/sm_cpu_infra.c index f348c86..b7b3484 100644 --- a/src/sm_cpu_infra.c +++ b/src/sm_cpu_infra.c @@ -304,6 +304,16 @@ uint32 PatchBugs(uint32 mode, uint32 addr) { } else if (FixBugHook(0xA2D38C)) { // MaridiaLargeSnail_Touch uses uninitialized X g_cpu->x = cur_enemy_index; + } else if (FixBugHook(0xA4970F)) { + // Crocomire_Func_67 does weird things + g_cpu->a &= 0xff; + g_cpu->y = g_cpu->x & 0x7; + } else if (FixBugHook(0xA496E0)) { + if (g_cpu->x > 48) { + croco_cur_vline_idx = g_cpu->x; + g_cpu->mf = 0; + return 0xA497CE; + } } return 0; @@ -351,7 +361,7 @@ static void VerifySnapshotsEq(Snapshot *b, Snapshot *a, Snapshot *prev) { memcpy(&b->ram[0x1f5b], &a->ram[0x1f5b], 0x100 - 0x5b); // stacck memcpy(&b->ram[0x44], &a->ram[0x44], 3); // decompress_dst_tmp memcpy(&b->ram[0x19b3], &a->ram[0x19b3], 1); // mode7_spawn_param - memcpy(&b->ram[0x12], &a->ram[0x12], 2); // R18 + memcpy(&b->ram[0x12], &a->ram[0x12], 6); // R18, R20, R22 memcpy(&b->ram[0x1993], &a->ram[0x1993], 2); // enemy_projectile_init_param memcpy(&b->ram[0x49], &a->ram[0x49], 1); // decompress_src.bank memcpy(&b->ram[0x1B9D], &a->ram[0x1B9D], 2); // cinematic_spawn_param @@ -539,6 +549,14 @@ void FixupCarry(uint32 addr) { *RomPtr(addr) = 0; } +void RtlUpdateSnesPatchForBugfix() { + // Patch HandleMessageBoxInteraction logic + { uint8 t[] = { 0x20, 0x50, 0x96, 0x60 }; PatchBytes(0x8584A3, t, sizeof(t)); } + // while ((bug_fix_counter < 1 ? joypad1_newkeys : joypad1_lastkeys) == 0); + { uint8 t[] = { 0x20, 0x36, 0x81, 0x22, 0x59, 0x94, 0x80, 0xc2, 0x30, 0xa5, (bug_fix_counter < 1) ? 0x8f : 0x85, 0xf0, 0xf3, 0x60 }; PatchBytes(0x859650, t, sizeof(t)); } + { uint8 t[] = { 0x18, 0x18 }; PatchBytes(0x8584CC, t, sizeof(t)); } // Don't wait 2 loops +} + Snes *SnesInit(const char *filename) { g_snes = snes_init(g_ram); @@ -668,11 +686,6 @@ Snes *SnesInit(const char *filename) { { uint8 t[] = { 0x18, 0x18, 0x18 }; PatchBytes(0x8580DC, t, sizeof(t)); } // Remove MsgBoxDelayFrames_2 { uint8 t[] = { 0x18, 0x18, 0x18 }; PatchBytes(0x8580F2, t, sizeof(t)); } // Remove MsgBoxDelayFrames_2 - // Patch HandleMessageBoxInteraction logic - { uint8 t[] = { 0x20, 0x50, 0x96, 0x60 }; PatchBytes(0x8584A3, t, sizeof(t)); } - { uint8 t[] = { 0x20, 0x36, 0x81, 0x22, 0x59, 0x94, 0x80, 0xc2, 0x30, 0xa5, 0x8b, 0xf0, 0xf3, 0x60 }; PatchBytes(0x859650, t, sizeof(t)); } - { uint8 t[] = { 0x18, 0x18 }; PatchBytes(0x8584CC, t, sizeof(t)); } // Don't wait 2 loops - // Patch RestorePpuForMessageBox { uint8 t[] = { 0x18, 0x18, 0x18 }; PatchBytes(0x85861C, t, sizeof(t)); } // WaitForNMI_NoUpdate { uint8 t[] = { 0x18, 0x18, 0x18 }; PatchBytes(0x858651, t, sizeof(t)); } // WaitForNMI_NoUpdate @@ -726,7 +739,9 @@ Snes *SnesInit(const char *filename) { { uint8 t[] = { 0x18, 0x18, 0x18 }; PatchBytes(0x828A72, t, sizeof(t)); } // SfxHandlers_2_ClearRequest { uint8 t[] = { 0x18, 0x18, 0x18, 0x80 }; PatchBytes(0x828A80, t, sizeof(t)); } // SfxHandlers_3_WaitForAck { uint8 t[] = { 0x06 }; PatchBytes(0x828A67, t, sizeof(t)); } // sfx_clear_delay - + + RtlUpdateSnesPatchForBugfix(); + for (size_t i = 0; i != arraysize(kPatchedCarrys); i++) { uint8 t = *RomPtr(kPatchedCarrys[i]); if (t) { diff --git a/src/sm_rtl.c b/src/sm_rtl.c index 692ce30..ba93f3d 100644 --- a/src/sm_rtl.c +++ b/src/sm_rtl.c @@ -245,10 +245,6 @@ void StateRecorder_Load(StateRecorder *sr, FILE *f, bool replay_mode) { if (!is_reset) RtlRestoreMusicAfterLoad_Locked(false); - // For some reason couroutine_state is not 1... - if (g_snes->cpu->k == 0x00 && g_snes->cpu->pc == 0x841c) - coroutine_state_0 = 1; - // Temporarily fix reset state // if (g_snes->cpu->k == 0x82 && g_snes->cpu->pc == 0xf716) // g_snes->cpu->pc = 0xf71c; @@ -387,6 +383,11 @@ void RtlStopReplay(void) { StateRecorder_StopReplay(&state_recorder); } +enum { + // Version was bumped to 1 after I fixed bug #1 + kCurrentBugFixCounter = 1, +}; + bool RtlRunFrame(int inputs) { // Avoid up/down and left/right from being pressed at the same time if ((inputs & 0x30) == 0x30) inputs ^= 0x30; @@ -402,6 +403,15 @@ bool RtlRunFrame(int inputs) { if (state_recorder.snapshot_flags & 1) { state_recorder.snapshot_flags &= ~1; inputs = state_recorder.last_inputs; + } else { + if (bug_fix_counter != kCurrentBugFixCounter) { + printf("bug_fix_counter %d => %d\n", bug_fix_counter, kCurrentBugFixCounter); + if (bug_fix_counter < kCurrentBugFixCounter) { + bug_fix_counter = kCurrentBugFixCounter; + StateRecorder_RecordPatchByte(&state_recorder, (uint8 *)&bug_fix_counter - g_ram, (uint8 *)&bug_fix_counter, 2); + RtlUpdateSnesPatchForBugfix(); + } + } } StateRecorder_Record(&state_recorder, inputs); diff --git a/src/sm_rtl.h b/src/sm_rtl.h index d13b4c4..1fc4159 100644 --- a/src/sm_rtl.h +++ b/src/sm_rtl.h @@ -176,6 +176,7 @@ bool RtlRunFrame(int inputs); void RtlReadSram(); void RtlWriteSram(); void RtlSaveSnapshot(const char *filename, bool saving_with_bug); +void RtlUpdateSnesPatchForBugfix(); uint16 Mult8x8(uint8 a, uint8 b); uint16 SnesDivide(uint16 a, uint8 b); diff --git a/src/variables.h b/src/variables.h index caf7ae1..01c073b 100644 --- a/src/variables.h +++ b/src/variables.h @@ -127,6 +127,10 @@ #define coroutine_completion_flags (*(uint8*)(g_ram+0x782)) #define my_counter (*(uint16*)(g_ram+0x77E)) +// Keep track of which bug fixes have been made to prevent +// replays from desyncing. +#define bug_fix_counter (*(uint16*)(g_ram+0x1FF00)) + #define g_word_7E0596 (*(uint16*)(g_ram+0x596)) #define g_word_7E0598 (*(uint16*)(g_ram+0x598)) #define set_to_e0_by_scrolling_sky (*(uint16*)(g_ram+0x59A)) @@ -205,17 +209,17 @@ #define sfx2_queue ((uint8*)(g_ram+0x666)) #define sfx3_queue ((uint8*)(g_ram+0x676)) #define sound_handler_downtime (*(uint16*)(g_ram+0x686)) -#define g_byte_7E0688 (*(uint8*)(g_ram+0x688)) +#define croco_target_0688 (*(uint16*)(g_ram+0x688)) #define g_word_7E068A (*(uint16*)(g_ram+0x68A)) -#define g_byte_7E068C (*(uint8*)(g_ram+0x68C)) +#define croco_word_068C (*(uint8*)(g_ram+0x68C)) #define g_word_7E068E (*(uint16*)(g_ram+0x68E)) -#define g_word_7E0690 (*(uint16*)(g_ram+0x690)) +#define croco_cur_vline_idx (*(uint16*)(g_ram+0x690)) #define g_word_7E0692 (*(uint16*)(g_ram+0x692)) #define g_word_7E0694 (*(uint16*)(g_ram+0x694)) #define g_word_7E0696 (*(uint16*)(g_ram+0x696)) #define g_word_7E0698 (*(uint16*)(g_ram+0x698)) -#define g_word_7E069A (*(uint16*)(g_ram+0x69A)) -#define g_byte_7E069C ((uint8*)(g_ram+0x69C)) +#define croco_word_7E069A (*(uint16*)(g_ram+0x69A)) +#define croco_vline_height ((uint8*)(g_ram+0x69C)) #define UNUSED_byte_7E071C (*(uint8*)(g_ram+0x71C)) #define nmi_copy_samus_halves (*(uint16*)(g_ram+0x71D)) #define nmi_copy_samus_top_half_src (*(uint16*)(g_ram+0x71F))