diff --git a/src/.gitignore b/src/.gitignore index e69de29..cbc684b 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -0,0 +1 @@ +/sm.vcxproj.user diff --git a/src/funcs.h b/src/funcs.h index 3b0d5e9..5e7d987 100644 --- a/src/funcs.h +++ b/src/funcs.h @@ -3559,7 +3559,7 @@ void MaridiaLargeSnail_Func_9(void); void MaridiaLargeSnail_Init(void); void MaridiaLargeSnail_Main(void); void MaridiaLargeSnail_Shot(void); -void MaridiaLargeSnail_Touch(uint16 k); +void MaridiaLargeSnail_Touch(void); void MaridiaSpikeyShell_1(void); void MaridiaSpikeyShell_2(void); void MaridiaSpikeyShell_3(void); diff --git a/src/main.c b/src/main.c index d8f1763..c8a6dc2 100644 --- a/src/main.c +++ b/src/main.c @@ -35,6 +35,7 @@ static void HandleGamepadInput(int button, bool pressed); static void HandleInput(int keyCode, int keyMod, bool pressed); void OpenGLRenderer_Create(struct RendererFuncs *funcs); +bool g_debug_flag; bool g_is_turbo; bool g_is_turbo; bool g_want_dump_memmap_flags; @@ -311,6 +312,10 @@ int main(int argc, char** argv) { } else { SwitchDirectory(); } + if (argc >= 1 && strcmp(argv[0], "--debug") == 0) { + g_debug_flag = true; + argc -= 1, argv += 1; + } ParseConfigFile(config_file); g_snes_width = (g_config.extended_aspect_ratio * 2 + 256); diff --git a/src/sm.vcxproj.user b/src/sm.vcxproj.user deleted file mode 100644 index 531c9a5..0000000 --- a/src/sm.vcxproj.user +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - WindowsLocalDebugger - - - - - WindowsLocalDebugger - - - - - WindowsLocalDebugger - - - - - WindowsLocalDebugger - - \ No newline at end of file diff --git a/src/sm_82.c b/src/sm_82.c index 18aef8d..14d2089 100644 --- a/src/sm_82.c +++ b/src/sm_82.c @@ -269,7 +269,7 @@ void LoadStdBG3andSpriteTilesClearTilemaps(void) { // 0x8282E2 CoroutineRet GameState_32_MadeItToCeresElevator(void) { // 0x828367 if (timer_status) DrawTimer(); - GameState_8_MainGameplay(); + COROUTINE_AWAIT_ONLY(GameState_8_MainGameplay()); bool v0 = (--reached_ceres_elevator_fade_timer & 0x8000u) != 0; if (!reached_ceres_elevator_fade_timer || v0) { ++game_state; @@ -282,7 +282,7 @@ CoroutineRet GameState_32_MadeItToCeresElevator(void) { // 0x828367 CoroutineRet GameState_33_BlackoutFromCeres(void) { // 0x828388 if (timer_status) DrawTimer(); - GameState_8_MainGameplay(); + COROUTINE_AWAIT_ONLY(GameState_8_MainGameplay()); HandleFadeOut(); if (reg_INIDISP == 0x80) { EnableNMI(); @@ -314,7 +314,7 @@ CoroutineRet GameState_33_BlackoutFromCeres(void) { // 0x828388 } CoroutineRet GameState_35_TimeUp(void) { // 0x828411 - GameState_8_MainGameplay(); + COROUTINE_AWAIT_ONLY(GameState_8_MainGameplay()); palette_change_denom = 8; if (AdvancePaletteFadeForAllPalettes()) { game_state = kGameState_36_WhitingOutFromTimeUp; @@ -361,7 +361,7 @@ CoroutineRet GameState_36_WhitingOutFromTimeUp(void) { // 0x828431 } CoroutineRet GameState_38_SamusEscapesFromZebes(void) { // 0x8284BD - GameState_8_MainGameplay(); + COROUTINE_AWAIT_ONLY(GameState_8_MainGameplay()); HandleFadeOut(); if (reg_INIDISP == 0x80) { EnableNMI(); @@ -389,7 +389,7 @@ CoroutineRet GameState_38_SamusEscapesFromZebes(void) { // 0x8284BD } CoroutineRet GameState_41_TransitionToDemo(void) { // 0x82852D - GameState_8_MainGameplay(); + COROUTINE_AWAIT_ONLY(GameState_8_MainGameplay()); HdmaObjectHandler(); ++game_state; reg_INIDISP = 15; @@ -399,7 +399,7 @@ CoroutineRet GameState_41_TransitionToDemo(void) { // 0x82852D CoroutineRet GameState_42_PlayingDemo_Async(void) { // 0x828548 COROUTINE_BEGIN(coroutine_state_3, 0) // assert(0); - GameState_8_MainGameplay(); + COROUTINE_AWAIT(2, GameState_8_MainGameplay()); if (joypad1_newkeys) { substate = 1; goto LABEL_10; @@ -763,7 +763,7 @@ CoroutineRet GameState_39_EndingAndCredits(void) { // 0x828B13 } CoroutineRet GameState_7_MainGameplayFadeIn(void) { // 0x828B20 - GameState_8_MainGameplay(); + COROUTINE_AWAIT_ONLY(GameState_8_MainGameplay()); HandleFadeIn(); if (reg_INIDISP == 15) { screen_fade_delay = 0; @@ -976,7 +976,7 @@ void DrawOptionsMenuSpritemaps(void) { // 0x828CA1 } CoroutineRet GameState_12_Pausing_Darkening_Async(void) { // 0x828CCF - GameState_8_MainGameplay(); + COROUTINE_AWAIT_ONLY(GameState_8_MainGameplay()); HandleFadeOut(); if ((reg_INIDISP & 0xF) == 0) { EnableNMI(); @@ -1465,7 +1465,7 @@ CoroutineRet GameState_17_Unpausing_Async(void) { // 0x829367 } CoroutineRet GameState_18_Unpausing(void) { // 0x8293A1 - GameState_8_MainGameplay(); + COROUTINE_AWAIT_ONLY(GameState_8_MainGameplay()); HandleFadeIn(); if (reg_INIDISP == 15) { screen_fade_delay = 0; @@ -3750,12 +3750,13 @@ void HandleSamusOutOfHealthAndGameTile(void) { // 0x82DB69 } CoroutineRet GameState_27_ReserveTanksAuto(void) { // 0x82DC10 - if (RefillHealthFromReserveTanks()) { + // todo: Ugly to inspect GameState_8_MainGameplay's coroutine_state_1 like this. + if (coroutine_state_1 == 0 && RefillHealthFromReserveTanks()) { time_is_frozen_flag = 0; game_state = kGameState_8_MainGameplay; CallSomeSamusCode(0x10u); } - GameState_8_MainGameplay(); + COROUTINE_AWAIT_ONLY(GameState_8_MainGameplay()); Samus_LowHealthCheck_0(); return kCoroutineNone; } @@ -3782,18 +3783,14 @@ LABEL_9: } CoroutineRet GameState_19_SamusNoHealth(void) { // 0x82DC80 - uint16 j; - uint16 k; - uint16 m; - - GameState_8_MainGameplay(); + COROUTINE_AWAIT_ONLY(GameState_8_MainGameplay()); for (int i = 255; i >= 0; --i) ram3000.pause_menu_map_tilemap[i + 384] = palette_buffer[i]; - for (j = 382; (j & 0x8000u) == 0; j -= 2) + for (int j = 382; (j & 0x8000u) == 0; j -= 2) target_palettes[j >> 1] = 0; - for (k = 94; (k & 0x8000u) == 0; k -= 2) + for (int k = 94; (k & 0x8000u) == 0; k -= 2) target_palettes[(k >> 1) + 208] = 0; - for (m = 30; (m & 0x8000u) == 0; m -= 2) + for (int m = 30; (m & 0x8000u) == 0; m -= 2) target_palettes[(m >> 1) + 192] = palette_buffer[(m >> 1) + 192]; game_options_screen_index = 3; g_word_7E0DE4 = 0; @@ -3809,7 +3806,7 @@ CoroutineRet GameState_19_SamusNoHealth(void) { // 0x82DC80 } CoroutineRet GameState_20_SamusNoHealth_BlackOut(void) { // 0x82DCE0 - GameState_8_MainGameplay(); + COROUTINE_AWAIT_ONLY(GameState_8_MainGameplay()); palette_change_denom = 6; if (AdvancePaletteFadeForAllPalettes()) { WaitUntilEndOfVblankAndClearHdma(); diff --git a/src/sm_a0.c b/src/sm_a0.c index affdc06..c8978aa 100644 --- a/src/sm_a0.c +++ b/src/sm_a0.c @@ -755,7 +755,7 @@ void CallEnemyAi(uint32 ea) { case fnLowerNorfairRio_Main: LowerNorfairRio_Main(); return; case fnMaridiaLargeSnail_Init: MaridiaLargeSnail_Init(); return; case fnMaridiaLargeSnail_Main: MaridiaLargeSnail_Main(); return; - case fnMaridiaLargeSnail_Touch: MaridiaLargeSnail_Touch(cur_enemy_index); return; + case fnMaridiaLargeSnail_Touch: MaridiaLargeSnail_Touch(); return; case fnMaridiaLargeSnail_Shot: MaridiaLargeSnail_Shot(); return; case fnHirisingSlowfalling_Init: HirisingSlowfalling_Init(); return; case fnHirisingSlowfalling_Main: HirisingSlowfalling_Main(); return; @@ -2401,7 +2401,7 @@ void CallHitboxTouch(uint32 ea) { switch (ea) { case fnEnemy_NormalTouchAI_A0: Enemy_NormalTouchAI_A0(); return; // 0xa08023 case fnMaridiaLargeSnail_Func_12: MaridiaLargeSnail_Func_12(); return; // 0xa2d388 - case fnMaridiaLargeSnail_Touch: MaridiaLargeSnail_Touch(cur_enemy_index); return; // 0xa2d38c + case fnMaridiaLargeSnail_Touch: MaridiaLargeSnail_Touch(); return; // 0xa2d38c case fnEnemy_NormalTouchAI_A4: Enemy_NormalTouchAI_A4(); return; // 0xa48023 case fnCrocomire_Func_92: Crocomire_Func_92(); return; // 0xa4b93d case fnnullsub_34: return; // 0xa4b950 diff --git a/src/sm_a2.c b/src/sm_a2.c index 703f40d..5e3fd21 100644 --- a/src/sm_a2.c +++ b/src/sm_a2.c @@ -3314,10 +3314,11 @@ void MaridiaLargeSnail_Func_11(void) { // 0xA2CFFF void MaridiaLargeSnail_Func_12(void) { // 0xA2D388 Enemy_NormalTouchAI_A2(); - MaridiaLargeSnail_Touch(cur_enemy_index); + MaridiaLargeSnail_Touch(); } -void MaridiaLargeSnail_Touch(uint16 k) { // 0xA2D38C +void MaridiaLargeSnail_Touch() { // 0xA2D38C + uint16 k = cur_enemy_index; if (!CheckIfEnemyTouchesSamus(k)) { if ((int16)(samus_x_pos - Get_MaridiaLargeSnail(cur_enemy_index)->base.x_pos) < 0) extra_samus_x_displacement -= 4; diff --git a/src/sm_cpu_infra.c b/src/sm_cpu_infra.c index 22939c4..f348c86 100644 --- a/src/sm_cpu_infra.c +++ b/src/sm_cpu_infra.c @@ -164,6 +164,8 @@ static const uint32 kPatchedCarrys[] = { 0x80A7D6, 0x80A99B, 0x818AA7, + 0x94B176, + 0x94B156, // room_width_in_blocks etc 0x80ab5d, @@ -225,6 +227,7 @@ static const uint32 kPatchedCarrys[] = { 0xA9D500, 0xA9D537, 0xA9DCDB, + }; static uint8 kPatchedCarrysOrg[arraysize(kPatchedCarrys)]; @@ -298,6 +301,9 @@ uint32 PatchBugs(uint32 mode, uint32 addr) { } else if (FixBugHook(0x82B15B)) { if ((uint8)pausemenu_equipment_category_item != 3) return 0x82AFD9; + } else if (FixBugHook(0xA2D38C)) { + // MaridiaLargeSnail_Touch uses uninitialized X + g_cpu->x = cur_enemy_index; } return 0; @@ -777,6 +783,17 @@ void DrawFrameToPpu(void) { g_snes->cpu->nmiWanted = false; } +extern bool g_debug_flag; + +void SaveBugSnapshot() { + if (!g_debug_flag && g_got_mismatch_count == 0) { + char buffer[64]; + snprintf(buffer, sizeof(buffer), "saves/bug-%d.sav", (int)time(NULL)); + RtlSaveSnapshot(buffer, true); + } + g_got_mismatch_count = 5 * 60; +} + void RunOneFrameOfGame_Both(void) { g_snes->ppu = g_snes->snes_ppu; MakeSnapshot(&g_snapshot_before); @@ -811,19 +828,12 @@ again_mine: g_snes->ppu = g_snes->snes_ppu; RestoreSnapshot(&g_snapshot_before); - if (g_got_mismatch_count == 0) { - char buffer[64]; - snprintf(buffer, sizeof(buffer), "saves/bug-%d.sav", (int)time(NULL)); - RtlSaveSnapshot(buffer, true); - } - g_got_mismatch_count = 5 * 60; + if (g_debug_flag) + goto again_theirs; -#if defined(_DEBUG) && 0 - goto again_theirs; -#else + SaveBugSnapshot(); RunOneFrameOfGame_Emulated(); goto getout; -#endif } g_snes->ppu = g_snes->snes_ppu; @@ -839,6 +849,13 @@ getout: coroutine_state_0 = 3; } + if (menu_index & 0xff00) { + printf("MENU INDEX TOO BIG!\n"); + SaveBugSnapshot(); + menu_index &= 0xff; + } + + if (g_got_mismatch_count) g_got_mismatch_count--; } @@ -847,14 +864,15 @@ void RtlRunFrameCompare(uint16 input, int run_what) { g_snes->input1->currentState = input; if (g_runmode == RM_THEIRS) { - assert(0); + RunOneFrameOfGame_Emulated(); + DrawFrameToPpu(); + } else if (g_runmode == RM_MINE) { g_use_my_apu_code = true; - g_snes->hPos = 1364 - 2, g_snes->vPos = 262 - 1; - snes_handle_pos_stuff(g_snes); g_snes->runningWhichVersion = 0xff; RunOneFrameOfGame(); + DrawFrameToPpu(); g_snes->runningWhichVersion = 0; } else { g_use_my_apu_code = true; diff --git a/src/snes/cpu.c b/src/snes/cpu.c index e6ad932..9b24136 100644 --- a/src/snes/cpu.c +++ b/src/snes/cpu.c @@ -727,8 +727,8 @@ uint32_t pc_hist[8], pc_hist_ctr; uint32_t pc_bp = 0; static void cpu_doOpcode(Cpu* cpu, uint8_t opcode) { -// pc_hist[pc_hist_ctr] = cpu->k << 16 | cpu->pc; -// pc_hist_ctr = (pc_hist_ctr + 1) & 7; + pc_hist[pc_hist_ctr] = cpu->k << 16 | cpu->pc; + pc_hist_ctr = (pc_hist_ctr + 1) & 7; if (((cpu->k << 16) | cpu->pc - 1) == pc_bp) { opcode += 0; } @@ -747,6 +747,7 @@ restart: cpu->k = cpu_pullByte(cpu); break; case 0xe5: + case 0xe9: case 0xed: cpu->c = 1; goto restart; case 0x65: case 0x6d: @@ -1336,7 +1337,15 @@ restart: } case 0x5c: { // jml abl uint16_t value = cpu_readOpcodeWord(cpu); - cpu->k = cpu_readOpcode(cpu); + uint8_t new_k = cpu_readOpcode(cpu); + if (new_k == 0x80 && value == 0x8573) { + printf("Current PC = 0x%x\n", cpu->k << 16 | cpu->pc); + for (int i = 0; i < 8; i++) { + printf("PC history: 0x%x\n", pc_hist[(pc_hist_ctr + i) & 7]); + } + Die("The game has crashed!\n"); + } + cpu->k = new_k; cpu->pc = value; break; }