// System routines #include "sm_rtl.h" #include "ida_types.h" #include "variables.h" #include "funcs.h" #include "enemy_types.h" #include "spc_player.h" #define kMusicPointers (*(LongPtr*)RomFixedPtr(0x8fe7e1)) #define kTimerDigitsSpritemapPtr ((uint16*)RomFixedPtr(0x809fd4)) #define kLoadStationLists ((uint16*)RomFixedPtr(0x80c4b5)) #define off_80CD46 ((uint16*)RomFixedPtr(0x80cd46)) void APU_UploadBank(uint32 addr) { // 0x808028 if (!g_use_my_apu_code) return; RtlApuUpload(RomPtr(addr)); } uint16 NextRandom(void) { // 0x808111 uint16 RegWord = LOBYTE(random_number) * 5; uint8 Reg = HIBYTE(random_number) * 5; int carry = HIBYTE(RegWord) + Reg + 1; HIBYTE(RegWord) = carry; uint16 result = (carry >> 8) + RegWord + 17; random_number = result; return result; } void ReleaseButtonsFilter(uint16 v0) { // 0x808146 timed_held_input_timer_reset = v0; bool v1 = ((uint16)~joypad1_newkeys & joypad1_lastkeys) == joypad_released_keys; joypad_released_keys = ~joypad1_newkeys & joypad1_lastkeys; if (!v1) { timed_held_input_timer = timed_held_input_timer_reset; timed_held_input = 0; goto LABEL_6; } if ((--timed_held_input_timer & 0x8000) == 0) { timed_held_input = 0; goto LABEL_6; } timed_held_input_timer = 0; previous_timed_held_input = timed_held_input; timed_held_input = ~joypad1_newkeys & joypad1_lastkeys; LABEL_6: newly_held_down_timed_held_input = timed_held_input & (previous_timed_held_input ^ timed_held_input); } uint16 PrepareBitAccess(uint16 a) { // 0x80818E bitmask = 1 << (a & 7); return a >> 3; } void SetBossBitForCurArea(uint16 a) { // 0x8081A6 boss_bits_for_area[area_index] |= a; } void ClearBossBitForCurArea(uint16 a) { // 0x8081C0 boss_bits_for_area[area_index] &= ~a; } uint8 CheckBossBitForCurArea(uint16 a) { // 0x8081DC return (a & boss_bits_for_area[area_index]) != 0; } void SetEventHappened(uint16 a) { // 0x8081FA uint16 v1 = PrepareBitAccess(a); events_that_happened[v1] |= bitmask; } void ClearEventHappened(uint16 v0) { // 0x808212 uint16 v1 = PrepareBitAccess(v0); events_that_happened[v1] &= ~bitmask; } uint16 CheckEventHappened(uint16 a) { // 0x808233 uint16 idx = PrepareBitAccess(a); return (bitmask & events_that_happened[idx]) != 0; } void CopySuperMetroidString(void) { // 0x80824F memcpy(&g_sram[0x1fe0], "supermetroid", 12); RtlWriteSram(); } void VerifySRAM(void) { // 0x808261 num_demo_sets = 3; if (LoadFromSram(0) && LoadFromSram(1) && LoadFromSram(2)) { memcpy(&g_sram[0x1fe0], "madadameyohn", 12); RtlWriteSram(); } else { if (!memcmp(&g_sram[0x1fe0], "supermetroid", 12)) num_demo_sets = 4; } } uint32 Multiply16x16(uint16 a, uint16 j) { // 0x8082D6 uint32 result = (uint32)a * (uint32)j; return result; } CoroutineRet WaitForNMI_Async(void) { // 0x808338 // Return 0 from this routine as soon as the coroutine has finished if (coroutine_completion_flags) { coroutine_completion_flags = 0; return 0; } waiting_for_nmi = 1; coroutine_completion_flags = 1; return 1; } CoroutineRet WaitForNMI_NoUpdate_Async(void) { // Return 0 from this routine as soon as the coroutine has finished if (coroutine_completion_flags) { coroutine_completion_flags = 0; return 0; } coroutine_completion_flags = 1; return 1; } void EnableNMI(void) { // 0x80834B uint8 v0 = reg_NMITIMEN | 0x80; WriteReg(NMITIMEN, reg_NMITIMEN | 0x80); reg_NMITIMEN = v0; } void DisableNMI(void) { // 0x80835D uint8 v0 = reg_NMITIMEN & 0x7F; WriteReg(NMITIMEN, reg_NMITIMEN & 0x7F); reg_NMITIMEN = v0; } void ScreenOff(void) { reg_INIDISP |= 0x80; } void ScreenOn(void) { reg_INIDISP &= ~0x80; } void memset7E(uint16 *k, uint16 a, uint16 j) { // 0x8083F6 do { *k++ = a; } while (j -= 2); } CoroutineRet Vector_RESET_Async(void) { // 0x80841C COROUTINE_BEGIN(coroutine_state_0, 1) WriteReg(MEMSEL, 1); reg_MEMSEL = 1; // Removed code to wait 4 frames uint16 bak = bug_fix_counter; memset(g_ram, 0, 8192); bug_fix_counter = bak; COROUTINE_AWAIT(2, InitializeIoDisplayLogo_Async()); COROUTINE_MANUAL_POS(3); // Soft reset position APU_UploadBank(0xCF8000); WriteReg(INIDISP, 0x8F); bak = bug_fix_counter; memset(g_ram, 0, 0x10000); bug_fix_counter = bak; WriteReg(NMITIMEN, 0); reg_NMITIMEN = 0; reg_INIDISP = 0x8f; InitializeCpuIoRegs(); InitializePpuIoRegs(); WriteLotsOf0x1c2f(); sfx_readpos[0] = 0; sfx_readpos[1] = 0; sfx_readpos[2] = 0; sfx_writepos[0] = 0; sfx_writepos[1] = 0; sfx_writepos[2] = 0; sfx_state[0] = 0; sfx_state[1] = 0; sfx_state[2] = 0; sfx_cur[0] = 0; sfx_cur[1] = 0; sfx_cur[2] = 0; sfx_clear_delay[0] = 0; sfx_clear_delay[1] = 0; sfx_clear_delay[2] = 0; sfx1_queue[0] = 0; sfx2_queue[0] = 0; sfx3_queue[0] = 0; oam_next_ptr = 0; reg_OAMaddr_UNUSED = 0; ClearOamExt(); ClearUnusedOam(); nmi_copy_samus_halves = 0; nmi_copy_samus_top_half_src = 0; nmi_copy_samus_bottom_half_src = 0; EnableNMI(); RtlApuWrite(APUI00, 0); RtlApuWrite(APUI02, 0); // Removed code to wait 4 frames random_number = 97; music_timer = 0; music_queue_delay[0] = 0; music_queue_delay[1] = 0; music_queue_delay[2] = 0; music_queue_delay[3] = 0; music_queue_delay[4] = 0; music_queue_delay[5] = 0; music_queue_delay[6] = 0; music_queue_delay[7] = 0; enable_debug = 0; VerifySRAM(); debug_disable_sounds = 0; sound_handler_downtime = 0; COROUTINE_END(2); } void InvalidInterrupt_Crash(void) { // 0x808573 printf("InvalidInterrupt_Crash\n"); Unreachable(); for (;;); } void LoadMirrorOfExploredMapTiles(void) { // 0x80858C uint16 v1 = swap16(area_index); uint16 v2 = 0; do { *(uint16 *)&map_tiles_explored[v2] = explored_map_tiles_saved[v1 >> 1]; v1 += 2; v2 += 2; } while ((int16)(v2 - 256) < 0); has_area_map = map_station_byte_array[area_index]; } void SaveExploredMapTilesToSaved(void) { // 0x8085C6 uint16 v1 = swap16(area_index); uint16 v2 = 0; do { explored_map_tiles_saved[v1 >> 1] = *(uint16 *)&map_tiles_explored[v2]; v1 += 2; v2 += 2; } while ((int16)(v2 - 256) < 0); if (has_area_map) *(uint16 *)&map_station_byte_array[area_index] |= 0xFF; } void InitializeCpuIoRegs(void) { // 0x80875D WriteReg(NMITIMEN, 1); reg_NMITIMEN = 1; WriteReg(WRIO, 0); WriteReg(WRMPYA, 0); WriteReg(WRMPYB, 0); WriteReg(WRDIVL, 0); WriteReg(WRDIVH, 0); WriteReg(WRDIVB, 0); WriteReg(HTIMEL, 0); WriteReg(HTIMEH, 0); WriteReg(VTIMEL, 0); WriteReg(VTIMEH, 0); WriteReg(MDMAEN, 0); WriteReg(HDMAEN, 0); reg_HDMAEN = 0; WriteReg(MEMSEL, 1); reg_MEMSEL = 1; } void InitializePpuIoRegs(void) { // 0x808792 WriteReg(INIDISP, 0x8F); reg_INIDISP = 0x8f; WriteReg(OBSEL, 3); reg_OBSEL = 3; WriteReg(OAMADDL, 0); LOBYTE(reg_OAMaddr_UNUSED) = 0; WriteReg(OAMADDH, 0x80); HIBYTE(reg_OAMaddr_UNUSED) = 0x80; WriteReg(OAMDATA, 0); WriteReg(OAMDATA, 0); WriteReg(BGMODE, 9); reg_BGMODE = 9; WriteReg(MOSAIC, 0); reg_MOSAIC = 0; WriteReg(BG1SC, 0x40); reg_BG1SC = 64; WriteReg(BG2SC, 0x44); reg_BG2SC = 68; WriteReg(BG3SC, 0x48); reg_BG3SC = 72; WriteReg(BG4SC, 0); reg_BG4SC = 0; WriteReg(BG12NBA, 0); reg_BG12NBA = 0; WriteReg(BG34NBA, 5); reg_BG34NBA = 5; WriteReg(BG1HOFS, 0); WriteReg(BG1HOFS, 0); WriteReg(BG1VOFS, 0); WriteReg(BG1VOFS, 0); WriteReg(BG2HOFS, 0); WriteReg(BG2HOFS, 0); WriteReg(BG2VOFS, 0); WriteReg(BG2VOFS, 0); WriteReg(BG3HOFS, 0); WriteReg(BG3HOFS, 0); WriteReg(BG3VOFS, 0); WriteReg(BG3VOFS, 0); WriteReg(BG4HOFS, 0); WriteReg(BG4HOFS, 0); WriteReg(BG4VOFS, 0); WriteReg(BG4VOFS, 0); WriteReg(VMAIN, 0); WriteReg(M7SEL, 0); reg_M7SEL = 0; WriteReg(M7A, 0); WriteReg(M7B, 0); WriteReg(M7C, 0); WriteReg(M7D, 0); WriteReg(M7X, 0); WriteReg(M7Y, 0); WriteReg(W12SEL, 0); reg_W12SEL = 0; WriteReg(W34SEL, 0); reg_W34SEL = 0; WriteReg(WOBJSEL, 0); reg_WOBJSEL = 0; WriteReg(WH0, 0); reg_WH0 = 0; WriteReg(WH1, 0xF8); reg_WH1 = -8; WriteReg(WH2, 0); reg_WH2 = 0; WriteReg(WH3, 0); reg_WH3 = 0; WriteReg(WBGLOG, 0); reg_WBGLOG = 0; WriteReg(WOBJLOG, 0); reg_WOBJLOG = 0; WriteReg(TM, 0x11); reg_TM = 17; WriteReg(TMW, 0x11); reg_TMW = 17; WriteReg(TS, 2); reg_TS = 2; WriteReg(TSW, 2); reg_TSW = 2; WriteReg(CGWSEL, 2); next_gameplay_CGWSEL = 2; WriteReg(CGADSUB, 0xA1); next_gameplay_CGADSUB = -95; WriteReg(COLDATA, 0xE0); WriteReg(COLDATA, 0xE0); WriteReg(COLDATA, 0x80); reg_COLDATA[0] = 0x80; WriteReg(COLDATA, 0x40); reg_COLDATA[1] = 64; WriteReg(COLDATA, 0x20); reg_COLDATA[2] = 32; WriteReg(SETINI, 0); reg_SETINI = 0; } void WriteLotsOf0x1c2f(void) { // 0x8088D1 sub_8088EB(0x1C2F); sub_8088FE(0x1C2F); sub_808911(0x1C2F); } void sub_8088EB(uint16 a) { // 0x8088EB memset7E((uint16*)(g_ram + 0x3000), a, 0x800); } void sub_8088FE(uint16 a) { // 0x8088FE memset7E((uint16 *)(g_ram + 0x4000), a, 0x800); } void sub_808911(uint16 a) { // 0x808911 memset7E((uint16 *)(g_ram + 0x6000), a, 0x800); } void HandleFadeOut(void) { // 0x808924 if ((int16)(screen_fade_counter - 1) < 0) { screen_fade_counter = screen_fade_delay; if ((reg_INIDISP & 0xF) != 0) { if ((reg_INIDISP & 0xF) == 1) reg_INIDISP = 0x80; else reg_INIDISP = (reg_INIDISP & 0xF) - 1; } } else { --screen_fade_counter; } } void HandleFadeIn(void) { // 0x80894D if ((int16)(screen_fade_counter - 1) < 0) { screen_fade_counter = screen_fade_delay; if (((reg_INIDISP + 1) & 0xF) != 0) reg_INIDISP = (reg_INIDISP + 1) & 0xF; } else { --screen_fade_counter; } } void ClearUnusedOam(void) { for (int i = oam_next_ptr >> 2; i < 0x80; i++) oam_ent[i].ycoord = 0xf0; oam_next_ptr = 0; } void ClearOamExt(void) { // 0x808B1A memset(oam_ext, 0, sizeof(oam_ext[0]) * 16); } void QueueMode7Transfers(uint8 db, uint16 k) { // 0x808B4F const uint8 *p = RomPtrWithBank(db, k); uint8 *dst = (uint8 *)mode7_write_queue + mode7_vram_write_queue_tail; for (;;) { int f = GET_BYTE(p); if (f & 0x80) { dst[9] = 0; memcpy(dst, p, 9); p += 9, dst += 9; } else if (f & 0x40) { dst[7] = 0; memcpy(dst, p, 7); p += 7, dst += 7; } else { break; } } mode7_vram_write_queue_tail = dst - (uint8 *)mode7_write_queue; } void NMI_ProcessMode7Queue(void) { // 0x808BBA if (mode7_vram_write_queue_tail) { NMI_ProcessMode7QueueInner(&g_ram[0x2D0]); *(uint16 *)&mode7_write_queue[0].field_0 = 0; mode7_vram_write_queue_tail = 0; } } void NMI_ProcessMode7QueueInner(const uint8 *p) { // 0x808BD3 while (1) { uint8 v2; while (1) { v2 = *p; if ((v2 & 0x80) == 0) break; WriteReg(DMAP1, v2 & 0x1F); Mode7CgvmWriteQueue *v5 = (Mode7CgvmWriteQueue *)p; WriteRegWord(A1T1L, v5->src_addr.addr); WriteReg(A1B1, v5->src_addr.bank); WriteRegWord(DAS1L, v5->count); if (v2 & 0x40) WriteReg(BBAD1, 0x19); else WriteReg(BBAD1, 0x18); WriteRegWord(VMADDL, v5->vram_addr); WriteReg(VMAIN, v5->vmain); WriteReg(MDMAEN, 2); p += sizeof(Mode7CgvmWriteQueue); } if (!(v2 & 0x40)) break; WriteReg(DMAP1, v2 & 0x1F); WriteRegWord(A1T1L, *(uint16 *)(p + 1)); WriteReg(A1B1, p[3]); WriteRegWord(DAS1L, *((uint16 *)p + 2)); WriteReg(BBAD1, 0x22); WriteReg(CGADD, p[6]); WriteReg(MDMAEN, 2); p += 7; } } void NMI_ProcessVramWriteQueue(void) { // 0x808C83 if (vram_write_queue_tail) { gVramWriteEntry(vram_write_queue_tail)->size = 0; WriteRegWord(DMAP1, 0x1801); for (int i = 0; ; i += 7) { VramWriteEntry *e = gVramWriteEntry(i); if (!e->size) break; WriteRegWord(DAS1L, e->size); WriteRegWord(A1T1L, e->src.addr); WriteReg(A1B1, e->src.bank); WriteRegWord(VMAIN, sign16(e->vram_dst) ? 0x81 : 0x80); WriteRegWord(VMADDL, e->vram_dst); WriteReg(MDMAEN, 2); } } vram_write_queue_tail = 0; Nmi_ProcessHorizScrollingDma(); Nmi_ProcessVertScrollingDma(); } void Nmi_ProcessHorizScrollingDma(void) { // 0x808CD8 WriteReg(VMAIN, 0x81); if ((uint8)bg1_update_col_enable) { LOBYTE(bg1_update_col_enable) = 0; uint16 v0 = bg1_update_col_unwrapped_dst; WriteRegWord(VMADDL, bg1_update_col_unwrapped_dst); WriteRegWord(DMAP1, 0x1801); WriteRegWord(A1T1L, ADDR16_OF_RAM(*bg1_column_update_tilemap_left_halves)); WriteReg(A1B1, 0x7E); uint16 v1 = bg1_update_col_unwrapped_size; WriteRegWord(DAS1L, bg1_update_col_unwrapped_size); WriteReg(MDMAEN, 2); WriteRegWord(VMADDL, v0 + 1); WriteRegWord(DAS1L, v1); WriteRegWord(A1T1L, ADDR16_OF_RAM(*bg1_column_update_tilemap_right_halves)); WriteReg(MDMAEN, 2); WriteRegWord(A1T1L, bg1_update_col_wrapped_left_src); uint16 v2 = bg1_update_col_wrapped_size; if (bg1_update_col_wrapped_size) { WriteRegWord(DAS1L, bg1_update_col_wrapped_size); uint16 v3 = bg1_update_col_wrapped_dst; WriteRegWord(VMADDL, bg1_update_col_wrapped_dst); WriteReg(MDMAEN, 2); WriteRegWord(VMADDL, v3 + 1); WriteRegWord(DAS1L, v2); WriteRegWord(A1T1L, bg1_update_col_wrapped_right_src); WriteReg(MDMAEN, 2); } } if ((uint8)bg2_update_col_enable) { LOBYTE(bg2_update_col_enable) = 0; uint16 v4 = bg2_update_col_unwrapped_dst; WriteRegWord(VMADDL, bg2_update_col_unwrapped_dst); WriteRegWord(DMAP1, 0x1801); WriteRegWord(A1T1L, ADDR16_OF_RAM(*bg2_column_update_tilemap_left_halves)); WriteReg(A1B1, 0x7E); uint16 v5 = bg2_update_col_unwrapped_size; WriteRegWord(DAS1L, bg2_update_col_unwrapped_size); WriteReg(MDMAEN, 2); WriteRegWord(VMADDL, v4 + 1); WriteRegWord(DAS1L, v5); WriteRegWord(A1T1L, ADDR16_OF_RAM(*bg2_column_update_tilemap_right_halves)); WriteReg(MDMAEN, 2); WriteRegWord(A1T1L, bg2_update_col_wrapped_left_src); uint16 v6 = bg2_update_col_wrapped_size; if (bg2_update_col_wrapped_size) { WriteRegWord(DAS1L, bg2_update_col_wrapped_size); uint16 v7 = bg2_update_col_wrapped_dst; WriteRegWord(VMADDL, bg2_update_col_wrapped_dst); WriteReg(MDMAEN, 2); WriteRegWord(VMADDL, v7 + 1); WriteRegWord(DAS1L, v6); WriteRegWord(A1T1L, bg2_update_col_wrapped_right_src); WriteReg(MDMAEN, 2); } } } void Nmi_ProcessVertScrollingDma(void) { // 0x808DAC WriteReg(VMAIN, 0x80); if ((uint8)bg1_update_row_enable) { LOBYTE(bg1_update_row_enable) = 0; uint16 v0 = bg1_update_row_unwrapped_dst; WriteRegWord(VMADDL, bg1_update_row_unwrapped_dst); WriteRegWord(DMAP1, 0x1801); WriteRegWord(A1T1L, ADDR16_OF_RAM(*bg1_column_update_tilemap_top_halves)); WriteReg(A1B1, 0x7E); uint16 v1 = bg1_update_row_unwrapped_size; WriteRegWord(DAS1L, bg1_update_row_unwrapped_size); WriteReg(MDMAEN, 2); WriteRegWord(VMADDL, v0 | 0x20); WriteRegWord(DAS1L, v1); WriteRegWord(A1T1L, ADDR16_OF_RAM(*bg1_column_update_tilemap_bottom_halves)); WriteReg(MDMAEN, 2); WriteRegWord(A1T1L, bg1_update_row_wrapped_top_src); uint16 v2 = bg1_update_row_wrapped_size; if (bg1_update_row_wrapped_size) { WriteRegWord(DAS1L, bg1_update_row_wrapped_size); uint16 v3 = bg1_update_row_wrapped_dst; WriteRegWord(VMADDL, bg1_update_row_wrapped_dst); WriteReg(MDMAEN, 2); WriteRegWord(VMADDL, v3 | 0x20); WriteRegWord(DAS1L, v2); WriteRegWord(A1T1L, bg1_update_row_wrapped_bottom_src); WriteReg(MDMAEN, 2); } } if ((uint8)bg2_update_row_enable) { LOBYTE(bg2_update_row_enable) = 0; uint16 v4 = bg2_update_row_unwrapped_dst; WriteRegWord(VMADDL, bg2_update_row_unwrapped_dst); WriteRegWord(DMAP1, 0x1801); WriteRegWord(A1T1L, ADDR16_OF_RAM(*bg2_column_update_tilemap_top_halves)); WriteReg(A1B1, 0x7E); uint16 v5 = bg2_update_row_unwrapped_size; WriteRegWord(DAS1L, bg2_update_row_unwrapped_size); WriteReg(MDMAEN, 2); WriteRegWord(VMADDL, v4 | 0x20); WriteRegWord(DAS1L, v5); WriteRegWord(A1T1L, ADDR16_OF_RAM(*bg2_column_update_tilemap_bottom_halves)); WriteReg(MDMAEN, 2); WriteRegWord(A1T1L, bg2_update_row_wrapped_top_src); uint16 v6 = bg2_update_row_wrapped_size; if (bg2_update_row_wrapped_size) { WriteRegWord(DAS1L, bg2_update_row_wrapped_size); uint16 v7 = bg2_update_row_wrapped_dst; WriteRegWord(VMADDL, bg2_update_row_wrapped_dst); WriteReg(MDMAEN, 2); WriteRegWord(VMADDL, v7 | 0x20); WriteRegWord(DAS1L, v6); WriteRegWord(A1T1L, bg2_update_row_wrapped_bottom_src); WriteReg(MDMAEN, 2); } } } void NMI_ProcessVramReadQueue(void) { // 0x808EA2 if ((uint8)vram_read_queue_tail) { *((uint8 *)&vram_read_queue[0].vram_target + (uint8)vram_read_queue_tail) = 0; int v0 = 0; WriteReg(VMAIN, 0x80); while (vram_read_queue[v0].vram_target) { WriteRegWord(VMADDL, vram_read_queue[v0].vram_target); ReadRegWord(RDVRAML); WriteRegWord(DMAP1, vram_read_queue[v0].dma_parameters); WriteRegWord(A1T1L, vram_read_queue[v0].src.addr); WriteRegWord(A1T1H, *(VoidP *)((uint8 *)&vram_read_queue[v0].src.addr + 1)); WriteRegWord(DAS1L, vram_read_queue[v0].size); WriteRegWord(DAS10, 0); WriteRegWord(A2A1H, 0); WriteReg(MDMAEN, 2); ++v0; } LOBYTE(vram_read_queue_tail) = 0; } } uint8 HasQueuedMusic(void) { // 0x808EF4 int v0 = 14; while (!music_queue_delay[v0 >> 1]) { v0 -= 2; if (v0 < 0) return 0; } return 1; } void HandleMusicQueue(void) { // 0x808F0C bool v0 = music_timer-- == 1; if ((music_timer & 0x8000) == 0) { if (!v0) return; if ((music_entry & 0x8000) != 0) { music_data_index = (uint8)music_entry; cur_music_track = -1; APU_UploadBank(Load24((LongPtr *)((uint8 *)&kMusicPointers + (uint8)music_entry))); cur_music_track = 0; int v5 = music_queue_read_pos; music_queue_track[v5 >> 1] = 0; music_queue_delay[v5 >> 1] = 0; music_queue_read_pos = (v5 + 2) & 0xE; sound_handler_downtime = 8; return; } uint8 v1 = music_entry & 0x7F; music_track_index = music_entry & 0x7F; RtlApuWrite(APUI00, music_entry & 0x7F); cur_music_track = v1; sound_handler_downtime = 8; int v2 = music_queue_read_pos; music_queue_track[v2 >> 1] = 0; music_queue_delay[v2 >> 1] = 0; music_queue_read_pos = (v2 + 2) & 0xE; } if (music_queue_read_pos == music_queue_write_pos) { music_timer = 0; } else { int v4 = music_queue_read_pos >> 1; music_entry = music_queue_track[v4]; music_timer = music_queue_delay[v4]; } } void QueueMusic_Delayed8(uint16 a) { // 0x808FC1 int8 v1; if (game_state < kGameState_40_TransitionToDemo && ((music_queue_write_pos + 2) & 0xE) != music_queue_read_pos) { v1 = music_queue_write_pos; int v2 = music_queue_write_pos >> 1; music_queue_track[v2] = a; music_queue_delay[v2] = 8; music_queue_write_pos = (v1 + 2) & 0xE; } } void QueueMusic_DelayedY(uint16 a, uint16 j) { // 0x808FF7 if (game_state < 0x28) { int v2 = music_queue_write_pos; music_queue_track[v2 >> 1] = a; int v4 = j; if (j < 8) v4 = 8; music_queue_delay[v2 >> 1] = v4; music_queue_write_pos = (v2 + 2) & 0xE; } } void QueueSfx1_Max15(uint16 a) { // 0x809021 QueueSfx1_Internal(a << 8 | 15); } void QueueSfx1_Max9(uint16 a) { // 0x80902B QueueSfx1_Internal(a << 8 | 9); } void QueueSfx1_Max3(uint16 a) { // 0x809035 QueueSfx1_Internal(a << 8 | 3); } void QueueSfx1_Max1(uint16 a) { // 0x80903F QueueSfx1_Internal(a << 8 | 1); } void QueueSfx1_Max6(uint16 a) { // 0x809049 QueueSfx1_Internal(a << 8 | 6); } void QueueSfx1_Internal(uint16 a) { // 0x809051 sfx_max_queued[0] = a; if (((sfx_writepos[0] - sfx_readpos[0]) & 0xF) < (uint8)a) { uint8 v2 = GET_HIBYTE(a); if (!debug_disable_sounds && game_state < 0x28 && (power_bomb_explosion_status & 0x8000) == 0) { uint8 v1 = sfx_writepos[0]; uint8 v3 = sfx_writepos[0] + 1; if (v3 >= 0x10) v3 = 0; if (v3 == sfx_readpos[0]) { if (v2 < sfx1_queue[v1]) sfx1_queue[v1] = v2; } else { sfx1_queue[sfx_writepos[0]] = v2; sfx_writepos[0] = v3; sfx1_queue[v3] = 0; } } } } void QueueSfx2_Max15(uint16 a) { // 0x8090A3 QueueSfx2_Internal(a << 8 | 15); } void QueueSfx2_Max9(uint16 a) { // 0x8090AD QueueSfx2_Internal(a << 8 | 9); } void QueueSfx2_Max3(uint16 a) { // 0x8090B7 QueueSfx2_Internal(a << 8 | 3); } void QueueSfx2_Max1(uint16 a) { // 0x8090C1 QueueSfx2_Internal(a << 8 | 1); } void QueueSfx2_Max6(uint16 a) { // 0x8090CB QueueSfx2_Internal(a << 8 | 6); } void QueueSfx2_Internal(uint16 a) { // 0x8090D3 sfx_max_queued[1] = a; if (((sfx_writepos[1] - sfx_readpos[1]) & 0xF) < (uint8)a) { uint8 v2 = GET_HIBYTE(a); if (!debug_disable_sounds && game_state < 0x28 && (power_bomb_explosion_status & 0x8000) == 0) { uint8 v1 = sfx_writepos[1]; uint8 v3 = sfx_writepos[1] + 1; if (v3 >= 0x10) v3 = 0; if (v3 == sfx_readpos[1]) { if (v2 < sfx2_queue[v1]) sfx2_queue[v1] = v2; } else { sfx2_queue[sfx_writepos[1]] = v2; sfx_writepos[1] = v3; sfx2_queue[v3] = 0; } } } } void QueueSfx3_Max15(uint16 a) { // 0x809125 QueueSfx3_Internal(a << 8 | 15); } void QueueSfx3_Max9(uint16 a) { // 0x80912F QueueSfx3_Internal(a << 8 | 9); } void QueueSfx3_Max3(uint16 a) { // 0x809139 QueueSfx3_Internal(a << 8 | 3); } void QueueSfx3_Max1(uint16 a) { // 0x809143 QueueSfx3_Internal(a << 8 | 1); } void QueueSfx3_Max6(uint16 a) { // 0x80914D QueueSfx3_Internal(a << 8 | 6); } void QueueSfx3_Internal(uint16 a) { // 0x809155 sfx_max_queued[2] = a; if (((sfx_writepos[2] - sfx_readpos[2]) & 0xF) < (uint8)a) { uint8 v2 = GET_HIBYTE(a); if (!debug_disable_sounds && game_state < 0x28 && (power_bomb_explosion_status & 0x8000) == 0) { uint8 v1 = sfx_writepos[2]; uint8 v3 = sfx_writepos[2] + 1; if (v3 >= 0x10) v3 = 0; if (v3 == sfx_readpos[2]) { if (v2 < sfx3_queue[v1]) sfx3_queue[v1] = v2; } else { sfx3_queue[sfx_writepos[2]] = v2; sfx_writepos[2] = v3; sfx3_queue[v3] = 0; } } } } void SetupDmaTransfer(const void *p) { // 0x8091A9 const StartDmaCopy *s = (const StartDmaCopy *)p; int v2 = s->chan * 16; WriteRegWord((SnesRegs)(v2 + DMAP0), *(uint16 *)&s->dmap); WriteRegWord((SnesRegs)(v2 + A1T0L), *(uint16 *)&s->a1.addr); WriteReg((SnesRegs)(v2 + A1B0), s->a1.bank); WriteRegWord((SnesRegs)(v2 + DAS0L), s->das); } void NmiUpdateIoRegisters(void) { // 0x8091EE WriteReg(NMITIMEN, reg_NMITIMEN); WriteReg(INIDISP, reg_INIDISP); WriteReg(OBSEL, reg_OBSEL); WriteReg(BGMODE, reg_BGMODE); WriteReg(MOSAIC, reg_MOSAIC); WriteReg(BG1SC, reg_BG1SC); WriteReg(BG2SC, reg_BG2SC); WriteReg(BG3SC, reg_BG3SC); WriteReg(BG4SC, reg_BG4SC); WriteReg(BG12NBA, reg_BG12NBA); WriteReg(BG34NBA, reg_BG34NBA); WriteReg(M7SEL, reg_M7SEL); WriteReg(W12SEL, reg_W12SEL); WriteReg(W34SEL, reg_W34SEL); WriteReg(WOBJSEL, reg_WOBJSEL); WriteReg(WH0, reg_WH0); WriteReg(WH1, reg_WH1); WriteReg(WH2, reg_WH2); WriteReg(WH3, reg_WH3); WriteReg(WBGLOG, reg_WBGLOG); WriteReg(WOBJLOG, reg_WOBJLOG); gameplay_TM = reg_TM; WriteReg(TM, reg_TM); WriteReg(TMW, reg_TMW); WriteReg(TS, reg_TS); WriteReg(TSW, reg_TSW); WriteReg(CGWSEL, reg_CGWSEL); WriteReg(CGADSUB, reg_CGADSUB); gameplay_CGWSEL = next_gameplay_CGWSEL; gameplay_CGADSUB = next_gameplay_CGADSUB; WriteReg(COLDATA, reg_COLDATA[0]); WriteReg(COLDATA, reg_COLDATA[1]); WriteReg(COLDATA, reg_COLDATA[2]); WriteReg(SETINI, reg_SETINI); WriteReg(BG1HOFS, reg_BG1HOFS); WriteReg(BG1HOFS, HIBYTE(reg_BG1HOFS)); WriteReg(BG1VOFS, reg_BG1VOFS); WriteReg(BG1VOFS, HIBYTE(reg_BG1VOFS)); WriteReg(BG2HOFS, reg_BG2HOFS); WriteReg(BG2HOFS, HIBYTE(reg_BG2HOFS)); WriteReg(BG2VOFS, reg_BG2VOFS); WriteReg(BG2VOFS, HIBYTE(reg_BG2VOFS)); WriteReg(BG3HOFS, reg_BG3HOFS); WriteReg(BG3HOFS, HIBYTE(reg_BG3HOFS)); WriteReg(BG3VOFS, reg_BG3VOFS); WriteReg(BG3VOFS, HIBYTE(reg_BG3VOFS)); WriteReg(BG4HOFS, reg_BG4HOFS); WriteReg(BG4HOFS, HIBYTE(reg_BG4HOFS)); WriteReg(BG4VOFS, reg_BG4VOFS); WriteReg(BG4VOFS, HIBYTE(reg_BG4VOFS)); HIBYTE(hdma_data_table_in_ceres) = reg_BGMODE_fake; if ((reg_BGMODE & 7) == 7 || (reg_BGMODE_fake & 7) == 7) { WriteReg(M7A, reg_M7A); WriteReg(M7A, HIBYTE(reg_M7A)); WriteReg(M7B, reg_M7B); WriteReg(M7B, HIBYTE(reg_M7B)); WriteReg(M7C, reg_M7C); WriteReg(M7C, HIBYTE(reg_M7C)); WriteReg(M7D, reg_M7D); WriteReg(M7D, HIBYTE(reg_M7D)); WriteReg(M7X, reg_M7X); WriteReg(M7X, HIBYTE(reg_M7X)); WriteReg(M7Y, reg_M7Y); WriteReg(M7Y, HIBYTE(reg_M7Y)); } } void NmiUpdatePalettesAndOam(void) { // 0x80933A WriteRegWord(DMAP0, 0x400); WriteRegWord(A1T0L, ADDR16_OF_RAM(*oam_ent)); WriteReg(A1B0, 0); WriteRegWord(DAS0L, 0x220); WriteRegWord(OAMADDL, 0); WriteRegWord(DMAP1, 0x2200); WriteRegWord(A1T1L, ADDR16_OF_RAM(*palette_buffer)); WriteReg(A1B1, 0x7E); WriteRegWord(DAS1L, 0x200); WriteReg(CGADD, 0); WriteReg(MDMAEN, 3); } void NmiTransferSamusToVram(void) { // 0x809376 WriteReg(VMAIN, 0x80); if ((uint8)nmi_copy_samus_halves) { const uint8 *rp = RomPtr_92(nmi_copy_samus_top_half_src); WriteRegWord(VMADDL, 0x6000); WriteRegWord(DMAP1, 0x1801); uint16 v0 = GET_WORD(rp + 0); WriteRegWord(A1T1L, v0); WriteRegWord(A1B1, GET_WORD(rp + 2)); uint16 v2 = GET_WORD(rp + 3); WriteRegWord(DAS1L, v2); WriteReg(MDMAEN, 2); WriteRegWord(VMADDL, 0x6100); WriteRegWord(A1T1L, v0 + v2); if (GET_WORD(rp + 5)) { WriteRegWord(DAS1L, GET_WORD(rp + 5)); WriteReg(MDMAEN, 2); } } if (HIBYTE(nmi_copy_samus_halves)) { const uint8 *rp = RomPtr_92(nmi_copy_samus_bottom_half_src); WriteRegWord(VMADDL, 0x6080); WriteRegWord(DMAP1, 0x1801); uint16 v4 = GET_WORD(rp + 0); WriteRegWord(A1T1L, v4); WriteRegWord(A1B1, GET_WORD(rp + 2)); uint16 v6 = GET_WORD(rp + 3); WriteRegWord(DAS1L, v6); WriteReg(MDMAEN, 2); WriteRegWord(VMADDL, 0x6180); WriteRegWord(A1T1L, v4 + v6); if (GET_WORD(rp + 5)) { WriteRegWord(DAS1L, GET_WORD(rp + 5)); WriteReg(MDMAEN, 2); } } } void NmiProcessAnimtilesVramTransfers(void) { // 0x809416 if ((animtiles_enable_flag & 0x8000) != 0) { for (int i = 10; (i & 0x80) == 0; i -= 2) { int v1 = i >> 1; if (animtiles_ids[v1]) { if (animtiles_src_ptr[v1]) { WriteRegWord(A1T0L, animtiles_src_ptr[v1]); WriteReg(A1B0, 0x87); WriteRegWord(DMAP0, 0x1801); WriteRegWord(DAS0L, animtiles_sizes[v1]); WriteRegWord(VMADDL, animtiles_vram_ptr[v1]); WriteReg(VMAIN, 0x80); WriteReg(MDMAEN, 1); animtiles_src_ptr[v1] = 0; } } } } } void ReadJoypadInputs(void) { // 0x809459 uint16 RegWord = ReadRegWord(JOY1L); joypad1_lastkeys = RegWord; joypad1_newkeys = RegWord & (joypad1_prev ^ RegWord); joypad1_newkeys2_UNUSED = RegWord & (joypad1_prev ^ RegWord); if (RegWord && RegWord == joypad1_prev) { if (!--joypad1_keyrepeat_ctr) { joypad1_newkeys2_UNUSED = joypad1_lastkeys; joypad1_keyrepeat_ctr = joypad_ctr_repeat_next; } } else { joypad1_keyrepeat_ctr = joypad_ctr_repeat_first; } joypad1_prev = joypad1_lastkeys; if (enable_debug) { uint16 v1 = ReadRegWord(JOY2L); joypad2_last = v1; joypad2_new_keys = v1 & (joypad2_prev ^ v1); joypad2_newkeys2 = v1 & (joypad2_prev ^ v1); if (v1 && v1 == joypad2_prev) { if (!--joypad2_keyrepeat_ctr) { joypad2_newkeys2 = joypad2_last; joypad2_keyrepeat_ctr = joypad_ctr_repeat_next; } } else { joypad2_keyrepeat_ctr = joypad_ctr_repeat_first; } joypad2_prev = joypad2_last; if (is_uploading_apu || joypad1_lastkeys != (kButton_Select | kButton_Start | kButton_L | kButton_R)) { if (enable_debug) { joypad_dbg_1 = 0; joypad_dbg_2 = 0; if ((joypad_dbg_flags & 0x4000) == 0) { if ((joypad1_lastkeys & (kButton_Select | kButton_L)) == (kButton_Select | kButton_L)) { joypad_dbg_1 = joypad1_newkeys; joypad1_lastkeys = 0; joypad1_newkeys = 0; } if ((joypad1_lastkeys & (kButton_Select | kButton_R)) == (kButton_Select | kButton_R)) { joypad_dbg_2 = joypad1_newkeys; joypad1_lastkeys = 0; joypad1_newkeys = 0; } if ((joypad_dbg_2 & 0x80) != 0) *(uint16 *)®_NMITIMEN ^= 0x30; if ((joypad_dbg_2 & 0x8000) != 0) { bool v2 = (~joypad_dbg_flags & 0x8000) != 0; joypad_dbg_flags ^= 0x8000; if (v2) { joypad_dbg_missiles_swap = samus_missiles; joypad_dbg_super_missiles_swap = samus_super_missiles; joypad_dbg_power_bombs_swap = samus_power_bombs; samus_missiles = 0; samus_super_missiles = 0; samus_power_bombs = 0; } else { samus_missiles = joypad_dbg_missiles_swap; samus_super_missiles = joypad_dbg_super_missiles_swap; samus_power_bombs = joypad_dbg_power_bombs_swap; } } if ((joypad_dbg_2 & 0x40) != 0) joypad_dbg_flags ^= 0x2000; } } else { joypad_dbg_1 = 0; joypad_dbg_2 = 0; joypad2_last &= 0x10; joypad2_new_keys &= 0x10; } } else { debug_disable_sounds = 0; SoftReset(); } } } void Vector_NMI(void) { // 0x809583 if (waiting_for_nmi) { NmiUpdatePalettesAndOam(); NmiTransferSamusToVram(); NmiProcessAnimtilesVramTransfers(); NmiUpdateIoRegisters(); for (int i = 0; i != 6; ++i) { if (hdma_object_channels_bitmask[i]) WriteRegWord((SnesRegs)(LOBYTE(hdma_object_bank_slot[i]) + 17154), hdma_object_table_pointers[i]); } if (reg_BGMODE == 7 || reg_BGMODE_fake == 7) NMI_ProcessMode7Queue(); NMI_ProcessVramWriteQueue(); NMI_ProcessVramReadQueue(); WriteReg(HDMAEN, reg_HDMAEN); waiting_for_nmi = 0; nmi_frames_missed = 0; ++nmi_frame_counter_byte; ++nmi_frame_counter_word; } else if (++nmi_frames_missed >= nmi_frames_missed_max) { nmi_frames_missed_max = nmi_frames_missed; } ++nmi_frame_counter_including_lag; } void Irq_DoorTransitionVramUpdate(void) { // 0x809632 WriteReg(INIDISP, 0x80); WriteRegWord(VMADDL, door_transition_vram_update_dst); WriteRegWord(DMAP1, 0x1801); WriteRegWord(A1T1L, door_transition_vram_update_src.addr); WriteReg(A1B1, door_transition_vram_update_src.bank); WriteRegWord(DAS1L, door_transition_vram_update_size); WriteReg(VMAIN, 0x80); WriteReg(MDMAEN, 2); door_transition_vram_update_enabled &= ~0x8000; WriteReg(INIDISP, 0xF); } void WaitForIrqDoorTransitionVramUpdate(void) { door_transition_vram_update_enabled |= 0x8000; Irq_DoorTransitionVramUpdate(); } void IrqHandler_SetResult(uint16 a, uint16 y, uint16 x) { // printf("Setting irq next: %d, %d, %d\n", a, x, y); cur_irq_handler = a; WriteRegWord(VTIMEL, y); WriteRegWord(HTIMEL, x); } void IrqHandler_0_Nothing(void) { // 0x80966E uint16 a = irqhandler_next_handler; irqhandler_next_handler = 0; IrqHandler_SetResult(a, 0, 0); } void IrqHandler_2_DisableIRQ(void) { // 0x809680 *(uint16 *)®_NMITIMEN &= ~0x30; IrqHandler_SetResult(0, 0, 0); } void IrqHandler_4_Main_BeginHudDraw(void) { // 0x80968B WriteReg(BG3SC, 0x5A); WriteReg(CGWSEL, 0); WriteReg(CGADSUB, 0); WriteReg(TM, 4); IrqHandler_SetResult(6, 31, 152); } void IrqHandler_6_Main_EndHudDraw(void) { // 0x8096A9 WriteReg(CGWSEL, gameplay_CGWSEL); WriteReg(CGADSUB, gameplay_CGADSUB); WriteReg(BG3SC, gameplay_BG3SC); WriteReg(TM, gameplay_TM); uint16 a = irqhandler_next_handler; irqhandler_next_handler = 0; IrqHandler_SetResult(a ? a : 4, 0, 152); } void IrqHandler_8_StartOfDoor_BeginHud(void) { // 0x8096D3 WriteReg(BG3SC, 0x5A); WriteReg(TM, 4); WriteReg(CGWSEL, 0); WriteReg(CGADSUB, 0); IrqHandler_SetResult(10, 31, 152); } void IrqHandler_10_StartOfDoor_EndHud(void) { // 0x8096F1 uint8 v0; if (((previous_cre_bitset | cre_bitset) & 1) != 0) v0 = 16; else v0 = 17; WriteReg(TM, v0); uint16 a = irqhandler_next_handler; irqhandler_next_handler = 0; IrqHandler_SetResult(a ? a : 8, 0, 152); } void IrqHandler_12_Draygon_BeginHud(void) { // 0x80971A WriteReg(TM, 4); WriteReg(CGWSEL, 0); WriteReg(CGADSUB, 0); IrqHandler_SetResult(14, 31, 152); } void IrqHandler_14_Draygon_EndHud(void) { // 0x809733 WriteReg(BG3SC, gameplay_BG3SC); WriteReg(CGWSEL, gameplay_CGWSEL); WriteReg(CGADSUB, gameplay_CGADSUB); uint16 a = irqhandler_next_handler; irqhandler_next_handler = 0; IrqHandler_SetResult(a ? a : 12, 0, 152); } void IrqHandler_16_VerticalDoor_BeginHud(void) { // 0x809758 WriteReg(TM, 4); WriteReg(CGWSEL, 0); WriteReg(CGADSUB, 0); IrqHandler_SetResult(18, 31, 152); } void IrqHandler_18_VerticalDoor_EndHud(void) { // 0x809771 uint8 v0; if (((previous_cre_bitset | cre_bitset) & 1) != 0) v0 = 16; else v0 = 17; WriteReg(TM, v0); WriteReg(CGWSEL, 0); WriteReg(CGADSUB, 0); // if ((door_transition_vram_update_enabled & 0x8000) != 0) // Irq_DoorTransitionVramUpdate(); if ((door_transition_flag & 0x8000) == 0) Irq_FollowDoorTransition(); IrqHandler_SetResult(20, 216, 152); } void IrqHandler_20_VerticalDoor_EndDraw(void) { // 0x8097A9 // *(uint16 *)&waiting_for_nmi = 1; uint16 a = irqhandler_next_handler; irqhandler_next_handler = 0; IrqHandler_SetResult(a ? a : 16, 0, 152); } void IrqHandler_22_HorizDoor_BeginHud(void) { // 0x8097C1 WriteReg(TM, 4); WriteReg(CGWSEL, 0); WriteReg(CGADSUB, 0); IrqHandler_SetResult(24, 31, 152); } void IrqHandler_24_HorizDoor_EndHud(void) { // 0x8097DA uint8 v0; if (((previous_cre_bitset | cre_bitset) & 1) != 0) v0 = 16; else v0 = 17; WriteReg(TM, v0); WriteReg(CGWSEL, 0); WriteReg(CGADSUB, 0); if ((door_transition_flag & 0x8000) == 0) Irq_FollowDoorTransition(); IrqHandler_SetResult(26, 160, 152); } void IrqHandler_26_HorizDoor_EndDraw(void) { // 0x80980A uint16 a = irqhandler_next_handler; irqhandler_next_handler = 0; IrqHandler_SetResult(a ? a : 22, 0, 152); } void EnableIrqInterrupts(void) { // 0x80982A WriteRegWord(VTIMEL, 0); WriteRegWord(HTIMEL, 152); *(uint16 *)®_NMITIMEN |= 0x30; } void EnableIrqInterruptsNow(void) { // 0x809841 WriteRegWord(VTIMEL, 0); WriteRegWord(HTIMEL, 152); *(uint16 *)®_NMITIMEN |= 0x30; WriteReg(NMITIMEN, reg_NMITIMEN); } void DisableIrqInterrupts(void) { // 0x80985F *(uint16 *)®_NMITIMEN &= ~0x30; } static Func_V *const kIrqHandlers[14] = { // 0x80986A IrqHandler_0_Nothing, IrqHandler_2_DisableIRQ, IrqHandler_4_Main_BeginHudDraw, IrqHandler_6_Main_EndHudDraw, IrqHandler_8_StartOfDoor_BeginHud, IrqHandler_10_StartOfDoor_EndHud, IrqHandler_12_Draygon_BeginHud, IrqHandler_14_Draygon_EndHud, IrqHandler_16_VerticalDoor_BeginHud, IrqHandler_18_VerticalDoor_EndHud, IrqHandler_20_VerticalDoor_EndDraw, IrqHandler_22_HorizDoor_BeginHud, IrqHandler_24_HorizDoor_EndHud, IrqHandler_26_HorizDoor_EndDraw, }; void Vector_IRQ(void) { kIrqHandlers[cur_irq_handler >> 1](); } static const uint16 kHudTilemaps[32] = { // 0x8099CF 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c1d, 0x2c1d, 0x2c1d, 0x2c1d, 0x2c1d, 0x2c1c, }; static const uint16 kHudTilemaps_Row1to3[96] = { 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c12, 0x2c12, 0x2c23, 0x2c12, 0x2c12, 0x2c1e, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2822, 0x2822, 0x2823, 0x2813, 0x2c14, 0x2c1e, 0x2c0f, 0x2c0b, 0x2c0c, 0x2c0d, 0x2c32, 0x2c0f, 0x2c09, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c0f, 0x2c12, 0x2c12, 0xa824, 0x2815, 0x2c16, 0x2c1e, }; static const uint16 kHudTilemaps_AutoReserve[12] = { 0x3c33, 0x3c46, 0x3c47, 0x3c48, 0xbc33, 0xbc46, 0x2c33, 0x2c46, 0x2c47, 0x2c48, 0xac33, 0xac46 }; static const uint16 kHudTilemaps_Missiles[22] = { 0x344b, 0x3449, 0x744b, 0x344c, 0x344a, 0x744c, 0x3434, 0x7434, 0x3435, 0x7435, 0x3436, 0x7436, 0x3437, 0x7437, 0x3438, 0x7438, 0x3439, 0x7439, 0x343a, 0x743a, 0x343b, 0x743b, }; void AddMissilesToHudTilemap(void) { if ((hud_tilemap[10] & 0x3FF) == 15) { hud_tilemap[10] = kHudTilemaps_Missiles[0]; hud_tilemap[11] = kHudTilemaps_Missiles[1]; hud_tilemap[12] = kHudTilemaps_Missiles[2]; hud_tilemap[42] = kHudTilemaps_Missiles[3]; hud_tilemap[43] = kHudTilemaps_Missiles[4]; hud_tilemap[44] = kHudTilemaps_Missiles[5]; } } void AddSuperMissilesToHudTilemap(void) { // 0x809A0E AddToTilemapInner(0x1C, (const uint16*)RomPtr_80(addr_kHudTilemaps_Missiles + 12)); } void AddPowerBombsToHudTilemap(void) { // 0x809A1E AddToTilemapInner(0x22, (const uint16 *)RomPtr_80(addr_kHudTilemaps_Missiles + 20)); } void AddGrappleToHudTilemap(void) { // 0x809A2E AddToTilemapInner(0x28, (const uint16 *)RomPtr_80(addr_kHudTilemaps_Missiles + 28)); } void AddXrayToHudTilemap(void) { // 0x809A3E AddToTilemapInner(0x2E, (const uint16 *)RomPtr_80(addr_kHudTilemaps_Missiles + 36)); } void AddToTilemapInner(uint16 k, const uint16 *j) { // 0x809A4C int v2 = k >> 1; if ((hud_tilemap[v2] & 0x3FF) == 15) { hud_tilemap[v2] = j[0]; hud_tilemap[v2 + 1] = j[1]; hud_tilemap[v2 + 32] = j[2]; hud_tilemap[v2 + 33] = j[3]; } } void InitializeHud(void) { // 0x809A79 WriteRegWord(VMADDL, addr_unk_605800); WriteRegWord(VMAIN, 0x80); static const StartDmaCopy unk_809A8F = { 1, 1, 0x18, LONGPTR(0x80988b), 0x0040 }; SetupDmaTransfer(&unk_809A8F); WriteReg(MDMAEN, 2); for (int i = 0; i != 192; i += 2) hud_tilemap[i >> 1] = kHudTilemaps_Row1to3[i >> 1]; if ((equipped_items & 0x8000) != 0) AddXrayToHudTilemap(); if ((equipped_items & 0x4000) != 0) AddGrappleToHudTilemap(); if (samus_max_missiles) AddMissilesToHudTilemap(); if (samus_max_super_missiles) AddSuperMissilesToHudTilemap(); if (samus_max_power_bombs) AddPowerBombsToHudTilemap(); samus_prev_health = 0; samus_prev_missiles = 0; samus_prev_super_missiles = 0; samus_prev_power_bombs = 0; samus_prev_hud_item_index = 0; InitializeMiniMapBroken(); if (samus_max_missiles) DrawThreeHudDigits(addrl_kDigitTilesetsWeapon, samus_missiles, 0x94); if (samus_max_super_missiles) DrawTwoHudDigits(addrl_kDigitTilesetsWeapon, samus_super_missiles, 0x9C); if (samus_max_power_bombs) DrawTwoHudDigits(addrl_kDigitTilesetsWeapon, samus_power_bombs, 0xA2); ToggleHudItemHighlight(hud_item_index, 0x1000); ToggleHudItemHighlight(samus_prev_hud_item_index, 0x1400); HandleHudTilemap(); } static const uint16 kEnergyTankIconTilemapOffsets[14] = { 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 2, 4, 6, 8, 0xa, 0xc, 0xe }; void HandleHudTilemap(void) { // 0x809B44 if (reserve_health_mode == 1) { const uint16 *v1 = (const uint16 *)RomPtr_80(addr_kHudTilemaps_AutoReserve); if (!samus_reserve_health) v1 += 6; hud_tilemap[8] = v1[0]; hud_tilemap[9] = v1[1]; hud_tilemap[40] = v1[2]; hud_tilemap[41] = v1[3]; hud_tilemap[72] = v1[4]; hud_tilemap[73] = v1[5]; } if (samus_health != samus_prev_health) { samus_prev_health = samus_health; uint16 r20 = SnesDivide(samus_health, 100); uint16 r18 = SnesModulus(samus_health, 100); int v2 = 0; int n = SnesDivide(samus_max_health, 100) + 1; do { if (!--n) break; uint16 v3 = 13360; if (r20) { --r20; v3 = 10289; } hud_tilemap[kEnergyTankIconTilemapOffsets[v2 >> 1] >> 1] = v3; v2 += 2; } while ((int16)(v2 - 28) < 0); DrawTwoHudDigits(addrl_kDigitTilesetsHealth, r18, 0x8C); } if (samus_max_missiles && samus_missiles != samus_prev_missiles) { samus_prev_missiles = samus_missiles; DrawThreeHudDigits(addrl_kDigitTilesetsWeapon, samus_missiles, 0x94); } if (samus_max_super_missiles && samus_super_missiles != samus_prev_super_missiles) { samus_prev_super_missiles = samus_super_missiles; if ((joypad_dbg_flags & 0x1F40) != 0) DrawThreeHudDigits(addrl_kDigitTilesetsWeapon, samus_prev_super_missiles, 0x9C); else DrawTwoHudDigits(addrl_kDigitTilesetsWeapon, samus_prev_super_missiles, 0x9C); } if (samus_max_power_bombs && samus_power_bombs != samus_prev_power_bombs) { samus_prev_power_bombs = samus_power_bombs; DrawTwoHudDigits(addrl_kDigitTilesetsWeapon, samus_power_bombs, 0xA2); } if (hud_item_index != samus_prev_hud_item_index) { ToggleHudItemHighlight(hud_item_index, 0x1000); ToggleHudItemHighlight(samus_prev_hud_item_index, 0x1400); samus_prev_hud_item_index = hud_item_index; if (samus_movement_type != 3 && samus_movement_type != 20 && grapple_beam_function == 0xC4F0 && !time_is_frozen_flag) { QueueSfx1_Max6(0x39); } } uint16 v4 = 5120; if ((nmi_frame_counter_byte & 0x10) != 0) v4 = 4096; ToggleHudItemHighlight(samus_auto_cancel_hud_item_index, v4); uint16 v5 = vram_write_queue_tail; gVramWriteEntry(vram_write_queue_tail)->size = 192; v5 += 2; gVramWriteEntry(v5)->size = ADDR16_OF_RAM(*hud_tilemap); v5 += 2; gVramWriteEntry(v5++)->size = 126; gVramWriteEntry(v5)->size = addr_unk_605820; vram_write_queue_tail = v5 + 2; } static const uint16 kHudItemTilemapOffsets[5] = { 0x14, 0x1c, 0x22, 0x28, 0x2e }; void ToggleHudItemHighlight(uint16 a, uint16 k) { // 0x809CEA int16 v2; hud_item_tilemap_palette_bits = k; v2 = a - 1; if (v2 >= 0) { int v3 = kHudItemTilemapOffsets[v2] >> 1; if (hud_tilemap[v3] != 11279) hud_tilemap[v3] = hud_item_tilemap_palette_bits | hud_tilemap[v3] & 0xE3FF; if (hud_tilemap[v3 + 1] != 11279) hud_tilemap[v3 + 1] = hud_item_tilemap_palette_bits | hud_tilemap[v3 + 1] & 0xE3FF; if (hud_tilemap[v3 + 32] != 11279) hud_tilemap[v3 + 32] = hud_item_tilemap_palette_bits | hud_tilemap[v3 + 32] & 0xE3FF; if (hud_tilemap[v3 + 33] != 11279) hud_tilemap[v3 + 33] = hud_item_tilemap_palette_bits | hud_tilemap[v3 + 33] & 0xE3FF; if (!(2 * v2)) { if (hud_tilemap[v3 + 2] != 11279) hud_tilemap[v3 + 2] = hud_item_tilemap_palette_bits | hud_tilemap[v3 + 2] & 0xE3FF; if (hud_tilemap[v3 + 34] != 11279) hud_tilemap[v3 + 34] = hud_item_tilemap_palette_bits | hud_tilemap[v3 + 34] & 0xE3FF; } } } void DrawThreeHudDigits(uint32 addr, uint16 a, uint16 k) { // 0x809D78 hud_tilemap[k >> 1] = GET_WORD(RomPtr(addr + 2 * (a / 100))); DrawTwoHudDigits(addr, a % 100, k + 2); } void DrawTwoHudDigits(uint32 addr, uint16 a, uint16 k) { // 0x809D98 int v3 = k >> 1; hud_tilemap[v3] = GET_WORD(RomPtr(addr + 2 * (a / 10))); hud_tilemap[v3 + 1] = GET_WORD(RomPtr(addr + 2 * (a % 10))); } static Func_U8 *const kTimerProcessFuncs[7] = { // 0x809DE7 ProcessTimer_Empty, ProcessTimer_CeresStart, ProcessTimer_MotherBrainStart, ProcessTimer_InitialDelay, ProcessTimer_MovementDelayed, ProcessTimer_MovingIntoPlace, ProcessTimer_Decrement, }; uint8 ProcessTimer(void) { return kTimerProcessFuncs[(uint8)timer_status](); } uint8 ProcessTimer_CeresStart(void) { // 0x809E09 ClearTimerRam(); SetTimerMinutes(0x100); timer_status = -32765; return 0; } uint8 ProcessTimer_Empty(void) { // 0x809E1A return 0; } uint8 ProcessTimer_MotherBrainStart(void) { // 0x809E1C ClearTimerRam(); SetTimerMinutes(0x300); timer_status = -32765; return 0; } uint8 ProcessTimer_InitialDelay(void) { // 0x809E2F LOBYTE(timer_x_pos) = timer_x_pos + 1; if ((uint8)timer_x_pos >= 0x10) LOBYTE(timer_status) = timer_status + 1; return 0; } uint8 ProcessTimer_MovementDelayed(void) { // 0x809E41 LOBYTE(timer_x_pos) = timer_x_pos + 1; if ((uint8)timer_x_pos >= 0x60) { LOBYTE(timer_x_pos) = 0; LOBYTE(timer_status) = timer_status + 1; } return ProcessTimer_Decrement(); } uint8 ProcessTimer_MovingIntoPlace(void) { // 0x809E58 int v0 = 0; uint16 v1 = timer_x_pos + 224; if ((uint16)(timer_x_pos + 224) >= 0xDC00) { v0 = 1; v1 = -9216; } timer_x_pos = v1; uint16 v2 = timer_y_pos - 193; if ((uint16)(timer_y_pos - 193) < 0x3000) { ++v0; v2 = 12288; } timer_y_pos = v2; if (v0 == 2) ++timer_status; return ProcessTimer_Decrement(); } void SetTimerMinutes(uint16 a) { // 0x809E8C *(uint16 *)&timer_centiseconds = 0; *(uint16 *)&timer_seconds = a; } void ClearTimerRam(void) { // 0x809E93 timer_x_pos = 0x8000; timer_y_pos = 0x8000; *(uint16 *)&timer_centiseconds = 0; *(uint16 *)&timer_seconds = 0; timer_status = 0; } bool DecrementDecimal(uint8 *number, uint8 value) { int result = (*number & 0xf) + (~value & 0xf) + 1; if (result < 0x10) result = (result - 0x6) & ((result - 0x6 < 0) ? 0xf : 0x1f); result = (*number & 0xf0) + (~value & 0xf0) + result; if (result < 0x100) result -= 0x60; *number = result; return result < 0x100; } uint8 ProcessTimer_Decrement(void) { // 0x809EA9 static const uint8 kTimerCentisecondDecrements[128] = { 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 2, 1, 2, 2, 1, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, 2, 2, }; if (DecrementDecimal(&timer_centiseconds, kTimerCentisecondDecrements[nmi_frame_counter_word & 0x7f])) { if (DecrementDecimal(&timer_seconds, 1)) { if (DecrementDecimal(&timer_minutes, 1)) { timer_centiseconds = 0; timer_seconds = 0; timer_minutes = 0; } else { timer_seconds = 0x59; } } } return (timer_centiseconds | timer_seconds | timer_minutes) == 0; } void DrawTimer(void) { // 0x809F6C DrawTimerSpritemap(0, addr_word_80A060); DrawTwoTimerDigits(*(uint16 *)&timer_minutes, 0xFFE4); DrawTwoTimerDigits(*(uint16 *)&timer_seconds, 0xFFFC); DrawTwoTimerDigits(*(uint16 *)&timer_centiseconds, 0x14); } void DrawTwoTimerDigits(uint16 a, uint16 k) { // 0x809F95 DrawTimerSpritemap(k, kTimerDigitsSpritemapPtr[(a & 0xF0) >> 4]); DrawTimerSpritemap(k + 8, kTimerDigitsSpritemapPtr[a & 0xF]); } void DrawTimerSpritemap(uint16 a, uint16 j) { // 0x809FB3 DrawSpritemap(0x80, j, a + HIBYTE(timer_x_pos), HIBYTE(timer_y_pos), 2560); } CoroutineRet StartGameplay_Async(void) { // 0x80A07B COROUTINE_BEGIN(coroutine_state_2, 0) WriteRegWord(MDMAEN, 0); scrolling_finished_hook = 0; music_data_index = 0; music_track_index = 0; timer_status = 0; ResetSoundQueues(); debug_disable_sounds = -1; DisableNMI(); DisableIrqInterrupts(); LoadDestinationRoomThings(); COROUTINE_AWAIT(1, Play20FramesOfMusic_Async()); ClearAnimtiles(); WaitUntilEndOfVblankAndClearHdma(); InitializeSpecialEffectsForNewRoom(); ClearPLMs(); ClearEnemyProjectiles(); ClearPaletteFXObjects(); UpdateBeamTilesAndPalette(); LoadColorsForSpritesBeamsAndEnemies(); LoadEnemies(); LoadRoomMusic(); COROUTINE_AWAIT(2, Play20FramesOfMusic_Async()); UpdateMusicTrackIndex(); NullFunc(); ClearBG2Tilemap(); LoadLevelDataAndOtherThings(); LoadFXHeader(); LoadLibraryBackground(); CalculateLayer2Xpos(); CalculateLayer2Ypos(); bg2_x_scroll = layer2_x_pos; bg2_y_scroll = layer2_y_pos; CalculateBgScrolls(); DisplayViewablePartOfRoom(); EnableNMI(); irqhandler_next_handler = (room_loading_irq_handler == 0) ? 4 : room_loading_irq_handler; EnableIrqInterrupts(); COROUTINE_AWAIT(3, Play20FramesOfMusic_Async()); SpawnHardcodedPlm((SpawnHardcodedPlmArgs) { 0x08, 0x08, 0xb7eb }); door_transition_function = FUNC16(DoorTransition_FadeInScreenAndFinish); COROUTINE_END(0); } CoroutineRet Play20FramesOfMusic_Async(void) { // 0x80A12B COROUTINE_BEGIN(coroutine_state_3, 0) EnableNMI(); for(my_counter = 0; my_counter != 20; my_counter++) { HandleMusicQueue(); COROUTINE_AWAIT(1, WaitForNMI_Async()); } DisableNMI(); COROUTINE_END(0); } void ResumeGameplay(void) { // 0x80A149 WriteRegWord(MDMAEN, 0); DisableNMI(); DisableIrqInterrupts(); LoadCRETilesTilesetTilesAndPalette(); LoadLibraryBackground(); DisplayViewablePartOfRoom(); LoadRoomPlmGfx(); EnableNMI(); EnableIrqInterrupts(); } void DisplayViewablePartOfRoom(void) { // 0x80A176 int v1, v2, v3; v1 = (reg_BG1SC - reg_BG2SC) << 8; size_of_bg2 = v1 & 0xF800; CalculateBgScrollAndLayerPositionBlocks(); v2 = 0; do { v3 = v2; blocks_to_update_x_block = layer1_x_block; blocks_to_update_y_block = layer1_y_block; vram_blocks_to_update_x_block = bg1_x_block; vram_blocks_to_update_y_block = bg1_y_block; UploadLevelDataColumn(); if (!(layer2_scroll_x & 1)) { blocks_to_update_x_block = layer2_x_block; blocks_to_update_y_block = layer2_y_block; vram_blocks_to_update_x_block = bg2_x_block; vram_blocks_to_update_y_block = bg2_y_block; UploadBackgroundDataColumn(); } NMI_ProcessVramWriteQueue(); ++layer1_x_block; ++bg1_x_block; ++layer2_x_block; ++bg2_x_block; ++v2; } while (v3 != 16); } void QueueClearingOfFxTilemap(void) { // 0x80A211 for (int i = 3838; i >= 0; i -= 2) *(uint16 *)((uint8 *)ram4000.xray_tilemaps + (uint16)i) = 6222; uint16 v1 = vram_write_queue_tail; VramWriteEntry *v2 = gVramWriteEntry(vram_write_queue_tail); v2->size = 3840; v2->src.addr = ADDR16_OF_RAM(ram4000); *(uint16 *)&v2->src.bank = 126; v2->vram_dst = addr_unk_605880; vram_write_queue_tail = v1 + 7; } void ClearBG2Tilemap(void) { // 0x80A23F WriteRegWord(VMADDL, 0x4800); WriteRegWord(DMAP1, 0x1808); WriteRegWord(A1T1L, 0xA29A); WriteRegWord(A1B1, 0x80); WriteRegWord(DAS1L, 0x800); WriteReg(VMAIN, 0); WriteReg(MDMAEN, 2); WriteRegWord(VMADDL, 0x4800); WriteRegWord(DMAP1, 0x1908); WriteRegWord(A1T1L, 0xA29A); WriteRegWord(A1B1, 0x80); WriteRegWord(DAS1L, 0x800); WriteReg(VMAIN, 0x80); WriteReg(MDMAEN, 2); } void ClearFXTilemap(void) { // 0x80A29C WriteRegWord(VMADDL, 0x5880); WriteRegWord(DMAP1, 0x1808); WriteRegWord(A1T1L, 0xA2F7); WriteRegWord(A1B1, 0x80); WriteRegWord(DAS1L, 0x780); WriteReg(VMAIN, 0); WriteReg(MDMAEN, 2); WriteRegWord(VMADDL, 0x5880); WriteRegWord(DMAP1, 0x1908); WriteRegWord(A1T1L, 0xA2F8); WriteRegWord(A1B1, 0x80); WriteRegWord(DAS1L, 0x780); WriteReg(VMAIN, 0x80); WriteReg(MDMAEN, 2); } uint8 CalculateLayer2Xpos(void) { // 0x80A2F9 if (!layer2_scroll_x) { layer2_x_pos = layer1_x_pos; return 0; } if (layer2_scroll_x != 1) { int t = layer2_scroll_x & 0xFE; uint8 var933 = t * LOBYTE(layer1_x_pos) >> 8; layer2_x_pos = t * HIBYTE(layer1_x_pos) + var933; return 0; } return 1; } uint8 CalculateLayer2Ypos(void) { // 0x80A33A if (!layer2_scroll_y) { layer2_y_pos = layer1_y_pos; return 0; } if (layer2_scroll_y != 1) { int t = layer2_scroll_y & 0xFE; uint8 var933 = t * (uint8)layer1_y_pos >> 8; layer2_y_pos = t * HIBYTE(layer1_y_pos) + var933; return 0; } return 1; } void CalculateBgScrolls(void) { // 0x80A37B reg_BG1HOFS = bg1_x_offset + layer1_x_pos; reg_BG1VOFS = bg1_y_offset + layer1_y_pos; reg_BG2HOFS = bg2_x_scroll + layer2_x_pos; reg_BG2VOFS = bg2_y_scroll + layer2_y_pos; } void UpdateScrollVarsUpdateMap(void) { // 0x80A3A0 CalculateBgScrolls(); UpdateBgGraphicsWhenScrolling(); } void CalculateLayer2PosAndScrollsWhenScrolling(void) { // 0x80A3AB if (!time_is_frozen_flag) { reg_BG1HOFS = bg1_x_offset + layer1_x_pos; reg_BG1VOFS = bg1_y_offset + layer1_y_pos; if (!CalculateLayer2Xpos()) reg_BG2HOFS = bg2_x_scroll + layer2_x_pos; if (!CalculateLayer2Ypos()) reg_BG2VOFS = bg2_y_scroll + layer2_y_pos; UpdateBgGraphicsWhenScrolling(); } } void UpdateBgGraphicsWhenScrolling(void) { // 0x80A3DF CalculateBgScrollAndLayerPositionBlocks(); int v0 = 0; bool v1 = (int16)(layer1_x_block - previous_layer1_x_block) < 0; if (layer1_x_block != previous_layer1_x_block) { previous_layer1_x_block = layer1_x_block; if (!v1) v0 = 16; blocks_to_update_x_block = layer1_x_block + v0; vram_blocks_to_update_x_block = bg1_x_block + v0; blocks_to_update_y_block = layer1_y_block; vram_blocks_to_update_y_block = bg1_y_block; UploadLevelDataColumn(); } if (!(layer2_scroll_x & 1)) { int v2 = 0; bool v3 = (int16)(layer2_x_block - previous_layer2_x_block) < 0; if (layer2_x_block != previous_layer2_x_block) { previous_layer2_x_block = layer2_x_block; if (!v3) v2 = 16; blocks_to_update_x_block = layer2_x_block + v2; vram_blocks_to_update_x_block = bg2_x_block + v2; blocks_to_update_y_block = layer2_y_block; vram_blocks_to_update_y_block = bg2_y_block; UploadBackgroundDataColumn(); } } int v4 = 1; bool v5 = (int16)(layer1_y_block - previous_layer1_y_block) < 0; if (layer1_y_block != previous_layer1_y_block) { previous_layer1_y_block = layer1_y_block; if (!v5) v4 = 15; blocks_to_update_y_block = layer1_y_block + v4; vram_blocks_to_update_y_block = bg1_y_block + v4; blocks_to_update_x_block = layer1_x_block; vram_blocks_to_update_x_block = bg1_x_block; UpdateLevelDataRow(); } if (!(layer2_scroll_y & 1)) { int v6 = 1; bool v7 = (int16)(layer2_y_block - previous_layer2_y_block) < 0; if (layer2_y_block != previous_layer2_y_block) { previous_layer2_y_block = layer2_y_block; if (!v7) v6 = 15; blocks_to_update_y_block = layer2_y_block + v6; vram_blocks_to_update_y_block = bg2_y_block + v6; blocks_to_update_x_block = layer2_x_block; vram_blocks_to_update_x_block = bg2_x_block; UpdateBackgroundDataRow(); } } } void CalculateBgScrollAndLayerPositionBlocks(void) { // 0x80A4BB bg1_x_block = reg_BG1HOFS >> 4; bg2_x_block = reg_BG2HOFS >> 4; uint16 v0 = layer1_x_pos >> 4; if (((layer1_x_pos >> 4) & 0x800) != 0) v0 |= 0xF000; layer1_x_block = v0; uint16 v1 = layer2_x_pos >> 4; if (((layer2_x_pos >> 4) & 0x800) != 0) v1 |= 0xF000; layer2_x_block = v1; bg1_y_block = reg_BG1VOFS >> 4; bg2_y_block = reg_BG2VOFS >> 4; uint16 v2 = layer1_y_pos >> 4; if (((layer1_y_pos >> 4) & 0x800) != 0) v2 |= 0xF000; layer1_y_block = v2; uint16 v3 = layer2_y_pos >> 4; if (((layer2_y_pos >> 4) & 0x800) != 0) v3 |= 0xF000; layer2_y_block = v3; } void HandleAutoscrolling_X(void) { // 0x80A528 int16 v1; int16 v3; int16 v6; uint16 v4; uint16 var933; if (!time_is_frozen_flag) { uint16 var939 = layer1_x_pos; if ((layer1_x_pos & 0x8000) != 0) layer1_x_pos = 0; uint16 v0 = swap16(room_width_in_scrolls - 1); if (v0 < layer1_x_pos) layer1_x_pos = v0; v1 = HIBYTE(layer1_x_pos); uint16 v2 = Mult8x8((uint16)(layer1_y_pos + 128) >> 8, room_width_in_scrolls) + v1; if (scrolls[v2]) { if (scrolls[(uint16)(v2 + 1)]) return; var933 = layer1_x_pos & 0xFF00; uint16 v5 = var939 - absolute_moved_last_frame_x - 2; if ((int16)(v5 - (layer1_x_pos & 0xFF00)) < 0) { v4 = var933; } else { var939 = v5; v6 = HIBYTE(var939); if (scrolls[(uint16)(Mult8x8((uint16)(layer1_y_pos + 128) >> 8, room_width_in_scrolls) + v6)]) v4 = var939; else v4 = (var939 & 0xFF00) + 256; } } else { var933 = (layer1_x_pos & 0xFF00) + 256; if ((uint16)(absolute_moved_last_frame_x + var939 + 2) >= var933) { v4 = var933; } else { var939 += absolute_moved_last_frame_x + 2; v3 = (uint8)(HIBYTE(var939) + 1); if (scrolls[(uint16)(Mult8x8((uint16)(layer1_y_pos + 128) >> 8, room_width_in_scrolls) + v3)]) v4 = var939; else v4 = var939 & 0xFF00; } } layer1_x_pos = v4; } } void HandleScrollingWhenTriggeringScrollRight(void) { // 0x80A641 int16 v1; uint16 var939 = layer1_x_pos; if ((int16)(ideal_layer1_xpos - layer1_x_pos) < 0) { layer1_x_pos = ideal_layer1_xpos; layer1_x_subpos = 0; } uint16 v0 = swap16(room_width_in_scrolls - 1); if (v0 >= layer1_x_pos) { v1 = HIBYTE(layer1_x_pos); uint16 RegWord = Mult8x8((uint16)(layer1_y_pos + 128) >> 8, room_width_in_scrolls); if (!scrolls[(uint16)(RegWord + 1 + v1)]) { uint16 var933 = layer1_x_pos & 0xFF00; uint16 v4 = var939 - absolute_moved_last_frame_x - 2; if ((int16)(v4 - (layer1_x_pos & 0xFF00)) < 0) v4 = var933; layer1_x_pos = v4; } } else { layer1_x_pos = v0; } } void HandleScrollingWhenTriggeringScrollLeft(void) { // 0x80A6BB int16 v0; uint16 var939 = layer1_x_pos; if ((int16)(layer1_x_pos - ideal_layer1_xpos) < 0) { layer1_x_pos = ideal_layer1_xpos; layer1_x_subpos = 0; } if ((layer1_x_pos & 0x8000) == 0) { v0 = HIBYTE(layer1_x_pos); uint16 prod = Mult8x8((uint16)(layer1_y_pos + 128) >> 8, room_width_in_scrolls); if (!scrolls[(uint16)(prod + v0)]) { uint16 var933 = (layer1_x_pos & 0xFF00) + 256; uint16 v1 = absolute_moved_last_frame_x + var939 + 2; if (v1 >= var933) v1 = var933; layer1_x_pos = v1; } } else { layer1_x_pos = 0; } } void HandleAutoscrolling_Y(void) { // 0x80A731 int16 v1; int16 v2; int16 v4; int16 v7; int16 v10; uint16 v8; if (!time_is_frozen_flag) { uint16 v0 = 0; v1 = (uint16)(layer1_x_pos + 128) >> 8; uint16 r20 = Mult8x8(HIBYTE(layer1_y_pos), room_width_in_scrolls) + v1; if (scrolls[r20] != 1) v0 = 31; uint16 var933 = v0; uint16 var939 = layer1_y_pos; if ((layer1_y_pos & 0x8000) != 0) layer1_y_pos = 0; LOBYTE(v2) = (uint16)(room_height_in_scrolls - 1) >> 8; HIBYTE(v2) = room_height_in_scrolls - 1; uint16 v3 = var933 + v2; if (v3 < layer1_y_pos) layer1_y_pos = v3; v4 = (uint16)(layer1_x_pos + 128) >> 8; uint16 v5 = Mult8x8(HIBYTE(layer1_y_pos), room_width_in_scrolls) + v4; if (!scrolls[v5]) { uint16 var935 = (layer1_y_pos & 0xFF00) + 256; uint16 v6 = absolute_moved_last_frame_y + var939 + 2; if (v6 >= var935) { v8 = var935; } else { var939 += absolute_moved_last_frame_y + 2; v7 = (uint16)(layer1_x_pos + 128) >> 8; uint16 prod = Mult8x8(HIBYTE(v6) + 1, room_width_in_scrolls); if (scrolls[(uint16)(prod + v7)]) v8 = var939; else v8 = var939 & 0xFF00; } layer1_y_pos = v8; return; } if (!scrolls[(uint16)(room_width_in_scrolls + v5)]) { uint16 var937 = var933 + (layer1_y_pos & 0xFF00); if (var937 < layer1_y_pos) { uint16 v9 = var939 - absolute_moved_last_frame_y - 2; if ((int16)(v9 - var937) < 0) { v8 = var937; } else { var939 = v9; uint16 prod = Mult8x8(HIBYTE(v9), room_width_in_scrolls); v10 = (uint16)(layer1_x_pos + 128) >> 8; if (scrolls[(uint16)(prod + v10)]) v8 = var939; else v8 = (var939 & 0xFF00) + 256; } layer1_y_pos = v8; return; } } } } void HandleScrollingWhenTriggeringScrollDown(void) { // 0x80A893 uint16 var939 = layer1_y_pos; int v0 = 0; uint16 prod = Mult8x8(HIBYTE(layer1_y_pos), room_width_in_scrolls); uint16 v1 = (uint16)(layer1_x_pos + 128) >> 8; uint16 r20 = prod + v1; if (scrolls[r20] != 1) v0 = 31; uint16 var933 = v0; if ((int16)(ideal_layer1_ypos - layer1_y_pos) < 0) { layer1_y_pos = ideal_layer1_ypos; layer1_y_subpos = 0; } uint16 v2 = swap16(room_height_in_scrolls - 1); uint16 var937 = var933 + v2; if ((uint16)(var933 + v2) < layer1_y_pos || !scrolls[(uint16)(room_width_in_scrolls + r20)] && (var937 = var933 + (layer1_y_pos & 0xFF00), var937 < layer1_y_pos)) { uint16 v3 = var939 - absolute_moved_last_frame_y - 2; if ((int16)(v3 - var937) < 0) v3 = var937; layer1_y_pos = v3; } } void HandleScrollingWhenTriggeringScrollUp(void) { // 0x80A936 int16 v0; uint16 var939 = layer1_y_pos; if ((int16)(layer1_y_pos - ideal_layer1_ypos) < 0) { layer1_y_pos = ideal_layer1_ypos; layer1_y_subpos = 0; } if ((layer1_y_pos & 0x8000) == 0) { uint16 prod = Mult8x8(HIBYTE(layer1_y_pos), room_width_in_scrolls); v0 = (uint16)(layer1_x_pos + 128) >> 8; if (!scrolls[(uint16)(prod + v0)]) { uint16 var933 = (layer1_y_pos & 0xFF00) + 256; uint16 v1 = absolute_moved_last_frame_y + var939 + 2; if (v1 >= var933) v1 = var933; layer1_y_pos = v1; } } else { layer1_y_pos = 0; } } void DebugScrollPosSaveLoad(void) { // 0x80A9AC if ((joypad2_new_keys & 0x40) != 0) ++debug_saveload_scrollpos_toggle; if (debug_saveload_scrollpos_toggle & 1) { layer1_x_pos = debug_saved_xscroll; layer1_y_pos = debug_saved_yscroll; } else { debug_saved_xscroll = layer1_x_pos; debug_saved_yscroll = layer1_y_pos; } } void UploadBackgroundDataColumn(void) { // 0x80A9D6 UpdateLevelOrBackgroundDataColumn(0x1c); } void UploadLevelDataColumn(void) { // 0x80A9DB UpdateLevelOrBackgroundDataColumn(0); } void UpdateLevelOrBackgroundDataColumn(uint16 k) { // 0x80A9DE if (!irq_enable_mode7) { uint16 prod = Mult8x8(blocks_to_update_y_block, room_width_in_blocks); uint16 v1 = blocks_to_update_x_block; uint16 v2 = 2 * (prod + v1) + 2; if (k) v2 += 0x9600; copywithflip_src.addr = v2; copywithflip_src.bank = 127; uint16 v3 = (4 * vram_blocks_to_update_y_block) & 0x3C; *(uint16 *)((uint8 *)&bg1_update_col_wrapped_size + k) = v3; *(uint16 *)((uint8 *)&bg1_update_col_unwrapped_size + k) = (v3 ^ 0x3F) + 1; prod = Mult8x8(vram_blocks_to_update_y_block & 0xF, 0x40); uint16 var935 = vram_blocks_to_update_x_block & 0x1F; uint16 v4 = 2 * var935; uint16 var933 = prod + v4; uint16 v5 = addr_unk_605000; if (var935 >= 0x10) v5 = addr_unk_6053E0; if (k) v5 -= size_of_bg2; uint16 var937 = v5; *(uint16 *)((uint8 *)&bg1_update_col_unwrapped_dst + k) = var933 + v5; *(uint16 *)((uint8 *)&bg1_update_col_wrapped_dst + k) = var935 + var935 + var937; uint16 v6 = ADDR16_OF_RAM(*bg1_column_update_tilemap_left_halves); uint16 v7 = 0; if (k) { v6 = ADDR16_OF_RAM(*bg2_column_update_tilemap_left_halves); v7 = 264; } uint16 v8 = *(uint16 *)((uint8 *)&bg1_update_col_unwrapped_size + k) + v6; *(uint16 *)((uint8 *)&bg1_update_col_wrapped_left_src + k) = v8; *(uint16 *)((uint8 *)&bg1_update_col_wrapped_right_src + k) = v8 + 64; var937 = v7; uint16 t2 = k; uint16 v9 = 0; uint16 var939 = 16; do { uint16 var93B = IndirReadWord(copywithflip_src, v9); uint16 v10 = var93B & 0x3FF; uint16 v17 = v9; uint16 v11 = var937; uint16 v12 = var93B & 0xC00; if ((var93B & 0xC00) != 0) { if (v12 == 1024) { uint16 v14 = var937 >> 1; bg1_column_update_tilemap_left_halves[v14] = tile_table.tables[v10].top_right ^ 0x4000; bg1_column_update_tilemap_right_halves[v14] = tile_table.tables[v10].top_left ^ 0x4000; bg1_column_update_tilemap_left_halves[v14 + 1] = tile_table.tables[v10].bottom_right ^ 0x4000; bg1_column_update_tilemap_right_halves[v14 + 1] = tile_table.tables[v10].bottom_left ^ 0x4000; } else { uint16 v15 = var937 >> 1; uint16 v16; if (v12 == 2048) { bg1_column_update_tilemap_left_halves[v15] = tile_table.tables[v10].bottom_left ^ 0x8000; bg1_column_update_tilemap_right_halves[v15] = tile_table.tables[v10].bottom_right ^ 0x8000; bg1_column_update_tilemap_left_halves[v15 + 1] = tile_table.tables[v10].top_left ^ 0x8000; v16 = tile_table.tables[v10].top_right ^ 0x8000; } else { bg1_column_update_tilemap_left_halves[v15] = tile_table.tables[v10].bottom_right ^ 0xC000; bg1_column_update_tilemap_right_halves[v15] = tile_table.tables[v10].bottom_left ^ 0xC000; bg1_column_update_tilemap_left_halves[v15 + 1] = tile_table.tables[v10].top_right ^ 0xC000; v16 = tile_table.tables[v10].top_left ^ 0xC000; } bg1_column_update_tilemap_right_halves[v15 + 1] = v16; } } else { uint16 v13 = var937 >> 1; bg1_column_update_tilemap_left_halves[v13] = tile_table.tables[v10].top_left; bg1_column_update_tilemap_right_halves[v13] = tile_table.tables[v10].top_right; bg1_column_update_tilemap_left_halves[v13 + 1] = tile_table.tables[v10].bottom_left; bg1_column_update_tilemap_right_halves[v13 + 1] = tile_table.tables[v10].bottom_right; } var937 = v11 + 4; v9 = room_width_in_blocks * 2 + v17; --var939; } while (var939); ++ *(uint16 *)((uint8 *)&bg1_update_col_enable + t2); } } void UpdateBackgroundDataRow(void) { // 0x80AB70 UpdateLevelOrBackgroundDataRow(0x1c); } void UpdateLevelDataRow(void) { // 0x80AB75 UpdateLevelOrBackgroundDataRow(0); } void UpdateLevelOrBackgroundDataRow(uint16 v0) { // 0x80AB78 if (!irq_enable_mode7) { uint16 prod = Mult8x8(blocks_to_update_y_block, room_width_in_blocks); uint16 v1 = blocks_to_update_x_block; uint16 v2 = 2 * (prod + v1) + 2; if (v0) v2 -= 27136; copywithflip_src.addr = v2; copywithflip_src.bank = 127; uint16 var933 = vram_blocks_to_update_x_block & 0xF; *(uint16 *)((uint8 *)&bg1_update_row_unwrapped_size + v0) = 4 * (16 - var933); *(uint16 *)((uint8 *)&bg1_update_row_wrapped_size + v0) = 4 * (var933 + 1); prod = Mult8x8(vram_blocks_to_update_y_block & 0xF, 0x40); uint16 var935 = vram_blocks_to_update_x_block & 0x1F; uint16 v3 = 2 * var935; var933 = prod + v3; uint16 var937 = addr_unk_605400; uint16 v4 = addr_unk_605000; if (var935 >= 0x10) { var937 = addr_unk_605000; v4 = addr_unk_6053E0; } if (v0) v4 -= size_of_bg2; *(uint16 *)((uint8 *)&bg1_update_row_unwrapped_dst + v0) = var933 + v4; uint16 v5 = var937; if (v0) v5 = var937 - size_of_bg2; *(uint16 *)((uint8 *)&bg1_update_row_wrapped_dst + v0) = prod + v5; uint16 v6 = ADDR16_OF_RAM(*bg1_column_update_tilemap_top_halves); uint16 v7 = 0; if (v0) { v6 = ADDR16_OF_RAM(*bg2_column_update_tilemap_top_halves); v7 = 264; } uint16 v8 = *(uint16 *)((uint8 *)&bg1_update_row_unwrapped_size + v0) + v6; *(uint16 *)((uint8 *)&bg1_update_row_wrapped_top_src + v0) = v8; *(uint16 *)((uint8 *)&bg1_update_row_wrapped_bottom_src + v0) = v8 + 68; var937 = v7; uint16 t2 = v0; uint16 v9 = 0; uint16 var939 = 17; do { uint16 var93B = IndirReadWord(copywithflip_src, v9); uint16 v10 = var93B & 0x3FF; uint16 v17 = v9; uint16 v11 = var937; uint16 v12 = var93B & 0xC00; if ((var93B & 0xC00) != 0) { if (v12 == 1024) { uint16 v14 = var937 >> 1; bg1_column_update_tilemap_top_halves[v14] = tile_table.tables[v10].top_right ^ 0x4000; bg1_column_update_tilemap_top_halves[v14 + 1] = tile_table.tables[v10].top_left ^ 0x4000; bg1_column_update_tilemap_bottom_halves[v14] = tile_table.tables[v10].bottom_right ^ 0x4000; bg1_column_update_tilemap_bottom_halves[v14 + 1] = tile_table.tables[v10].bottom_left ^ 0x4000; } else { uint16 v15 = var937 >> 1; uint16 v16; if (v12 == 2048) { bg1_column_update_tilemap_top_halves[v15] = tile_table.tables[v10].bottom_left ^ 0x8000; bg1_column_update_tilemap_top_halves[v15 + 1] = tile_table.tables[v10].bottom_right ^ 0x8000; bg1_column_update_tilemap_bottom_halves[v15] = tile_table.tables[v10].top_left ^ 0x8000; v16 = tile_table.tables[v10].top_right ^ 0x8000; } else { bg1_column_update_tilemap_top_halves[v15] = tile_table.tables[v10].bottom_right ^ 0xC000; bg1_column_update_tilemap_top_halves[v15 + 1] = tile_table.tables[v10].bottom_left ^ 0xC000; bg1_column_update_tilemap_bottom_halves[v15] = tile_table.tables[v10].top_right ^ 0xC000; v16 = tile_table.tables[v10].top_left ^ 0xC000; } bg1_column_update_tilemap_bottom_halves[v15 + 1] = v16; } } else { uint16 v13 = var937 >> 1; bg1_column_update_tilemap_top_halves[v13] = tile_table.tables[v10].top_left; bg1_column_update_tilemap_top_halves[v13 + 1] = tile_table.tables[v10].top_right; bg1_column_update_tilemap_bottom_halves[v13] = tile_table.tables[v10].bottom_left; bg1_column_update_tilemap_bottom_halves[v13 + 1] = tile_table.tables[v10].bottom_right; } var937 = v11 + 4; v9 = v17 + 2; --var939; } while (var939); ++ *(uint16 *)((uint8 *)&bg1_update_row_enable + t2); } } void FixDoorsMovingUp(void) { // 0x80AD1D door_transition_frame_counter = 0; CalculateBgScrollAndLayerPositionBlocks(); UpdatePreviousLayerBlocks(); ++previous_layer1_y_block; ++previous_layer2_y_block; DoorTransition_Up(); } static Func_V *const kDoorTransitionSetupFuncs[4] = { // 0x80AD30 DoorTransitionScrollingSetup_Right, DoorTransitionScrollingSetup_Left, DoorTransitionScrollingSetup_Down, DoorTransitionScrollingSetup_Up, }; void DoorTransitionScrollingSetup(void) { layer1_x_pos = door_destination_x_pos; layer1_y_pos = door_destination_y_pos; kDoorTransitionSetupFuncs[door_direction & 3](); } void DoorTransitionScrollingSetup_Right(void) { // 0x80AD4A CalculateLayer2Xpos(); layer2_x_pos -= 256; CalculateLayer2Ypos(); layer1_x_pos -= 256; UpdateBgScrollOffsets(); CalculateBgScrollAndLayerPositionBlocks(); UpdatePreviousLayerBlocks(); --previous_layer1_x_block; --previous_layer2_x_block; DoorTransition_Right(); } void DoorTransitionScrollingSetup_Left(void) { // 0x80AD74 CalculateLayer2Xpos(); layer2_x_pos += 256; CalculateLayer2Ypos(); layer1_x_pos += 256; UpdateBgScrollOffsets(); CalculateBgScrollAndLayerPositionBlocks(); UpdatePreviousLayerBlocks(); ++previous_layer1_x_block; ++previous_layer2_x_block; DoorTransition_Left(); } void DoorTransitionScrollingSetup_Down(void) { // 0x80AD9E CalculateLayer2Xpos(); CalculateLayer2Ypos(); layer2_y_pos -= 224; layer1_y_pos -= 224; UpdateBgScrollOffsets(); CalculateBgScrollAndLayerPositionBlocks(); UpdatePreviousLayerBlocks(); --previous_layer1_y_block; --previous_layer2_y_block; DoorTransition_Down(); } void DoorTransitionScrollingSetup_Up(void) { // 0x80ADC8 CalculateLayer2Xpos(); uint16 v1 = layer1_y_pos; layer1_y_pos += 31; CalculateLayer2Ypos(); layer2_y_pos += 224; layer1_y_pos = v1 + 256; UpdateBgScrollOffsets(); door_destination_y_pos += 32; CalculateBgScrollAndLayerPositionBlocks(); UpdatePreviousLayerBlocks(); ++previous_layer1_y_block; ++previous_layer2_y_block; --layer1_y_pos; DoorTransition_Up(); } void UpdatePreviousLayerBlocks(void) { // 0x80AE10 previous_layer1_x_block = layer1_x_block; previous_layer2_x_block = layer2_x_block; previous_layer1_y_block = layer1_y_block; previous_layer2_y_block = layer2_y_block; } void UpdateBgScrollOffsets(void) { // 0x80AE29 bg1_x_offset = reg_BG1HOFS - layer1_x_pos; bg1_y_offset = reg_BG1VOFS - layer1_y_pos; bg2_x_scroll = reg_BG2HOFS - layer1_x_pos; bg2_y_scroll = reg_BG2VOFS - layer1_y_pos; } static Func_U8 *const kDoorTransitionFuncs[4] = { DoorTransition_Right, DoorTransition_Left, DoorTransition_Down, DoorTransition_Up, }; void Irq_FollowDoorTransition(void) { if (kDoorTransitionFuncs[door_direction & 3]()) { layer1_x_pos = door_destination_x_pos; layer1_y_pos = door_destination_y_pos; door_transition_flag |= 0x8000; } } uint8 DoorTransition_Right(void) { // 0x80AE7E uint16 v2 = door_transition_frame_counter; AddToHiLo(&samus_x_pos, &samus_x_subpos, __PAIR32__(samus_door_transition_speed, samus_door_transition_subspeed)); samus_prev_x_pos = samus_x_pos; layer1_x_pos += 4; layer2_x_pos += 4; UpdateScrollVarsUpdateMap(); door_transition_frame_counter = v2 + 1; if (v2 != 63) return 0; UpdateScrollVarsUpdateMap(); return 1; } uint8 DoorTransition_Left(void) { // 0x80AEC2 uint16 v2 = door_transition_frame_counter; AddToHiLo(&samus_x_pos, &samus_x_subpos, -IPAIR32(samus_door_transition_speed, samus_door_transition_subspeed)); samus_prev_x_pos = samus_x_pos; layer1_x_pos -= 4; layer2_x_pos -= 4; UpdateScrollVarsUpdateMap(); door_transition_frame_counter = v2 + 1; return v2 == 63; } uint8 DoorTransition_Down(void) { // 0x80AF02 uint16 v6 = door_transition_frame_counter; if (door_transition_frame_counter) { if (door_transition_frame_counter < 0x39) { AddToHiLo(&samus_y_pos, &samus_y_subpos, __PAIR32__(samus_door_transition_speed, samus_door_transition_subspeed)); samus_prev_y_pos = samus_y_pos; layer1_y_pos += 4; layer2_y_pos += 4; UpdateScrollVarsUpdateMap(); } } else { uint16 v5 = reg_BG1VOFS; uint16 v4 = reg_BG2VOFS; uint16 v3 = layer1_y_pos; layer1_y_pos -= 15; uint16 v2 = layer2_y_pos; layer2_y_pos -= 15; CalculateBgScrollAndLayerPositionBlocks(); UpdatePreviousLayerBlocks(); --previous_layer1_y_block; --previous_layer2_y_block; UpdateScrollVarsUpdateMap(); layer2_y_pos = v2; layer1_y_pos = v3; reg_BG2VOFS = v4; reg_BG1VOFS = v5; } door_transition_frame_counter = v6 + 1; if ((uint16)(v6 + 1) < 0x39) return 0; UpdateScrollVarsUpdateMap(); return 1; } uint8 DoorTransition_Up(void) { // 0x80AF89 uint16 v6 = door_transition_frame_counter; if (door_transition_frame_counter) { AddToHiLo(&samus_y_pos, &samus_y_subpos, -IPAIR32(samus_door_transition_speed, samus_door_transition_subspeed)); samus_prev_y_pos = samus_y_pos; layer1_y_pos -= 4; layer2_y_pos -= 4; if (door_transition_frame_counter >= 5) { UpdateScrollVarsUpdateMap(); } else { reg_BG1HOFS = bg1_x_offset + layer1_x_pos; reg_BG1VOFS = bg1_y_offset + layer1_y_pos; reg_BG2HOFS = bg2_x_scroll + layer2_x_pos; reg_BG2VOFS = bg2_y_scroll + layer2_y_pos; } } else { uint16 v5 = reg_BG1VOFS; uint16 v4 = reg_BG2VOFS; uint16 v3 = layer1_y_pos; layer1_y_pos -= 16; uint16 v2 = layer2_y_pos; layer2_y_pos -= 16; CalculateBgScrollAndLayerPositionBlocks(); UpdatePreviousLayerBlocks(); ++previous_layer1_y_block; ++previous_layer2_y_block; UpdateScrollVarsUpdateMap(); layer2_y_pos = v2; layer1_y_pos = v3; reg_BG2VOFS = v4; reg_BG1VOFS = v5; } door_transition_frame_counter = v6 + 1; return v6 == 56; } void ConfigureMode7RotationMatrix(void) { // 0x80B0C2 if (irq_enable_mode7) { if ((nmi_frame_counter_word & 7) == 0) { reg_M7B = kSinCosTable8bit_Sext[((uint8)mode7_rotation_angle) + 64]; reg_M7C = -reg_M7B; reg_M7A = kSinCosTable8bit_Sext[((uint8)(mode7_rotation_angle + 64)) + 64]; reg_M7D = reg_M7A; ++mode7_rotation_angle; } } } static uint32 decompress_src; static uint8 DecompNextByte() { uint8 b = *RomPtr(decompress_src); if ((decompress_src++ & 0xffff) == 0xffff) decompress_src += 0x8000; return b; } void DecompressToMem(uint32 src, uint8 *decompress_dst) { // 0x80B119 decompress_src = src; int src_pos, dst_pos = 0; while (1) { int len; uint8 cmd, b; b = DecompNextByte(); if (b == 0xFF) break; if ((b & 0xE0) == 0xE0) { cmd = (8 * b) & 0xE0; len = ((b & 3) << 8 | DecompNextByte()) + 1; } else { cmd = b & 0xE0; len = (b & 0x1F) + 1; } if (cmd & 0x80) { uint8 want_xor = cmd & 0x20 ? 0xff : 0; if (cmd >= 0xC0) { src_pos = dst_pos - DecompNextByte(); } else { src_pos = DecompNextByte(); src_pos += DecompNextByte() * 256; } do { b = decompress_dst[src_pos++] ^ want_xor; decompress_dst[dst_pos++] = b; } while (--len); } else { switch (cmd) { case 0x20: b = DecompNextByte(); do { decompress_dst[dst_pos++] = b; } while (--len); break; case 0x40: { b = DecompNextByte(); uint8 b2 = DecompNextByte(); do { decompress_dst[dst_pos++] = b; if (!--len) break; decompress_dst[dst_pos++] = b2; } while (--len); break; } case 0x60: b = DecompNextByte(); do { decompress_dst[dst_pos++] = b++; } while (--len); break; default: do { b = DecompNextByte(); decompress_dst[dst_pos++] = b; } while (--len); break; } } } } static uint8 ReadPpuByte(uint16 addr) { WriteRegWord(VMADDL, addr >> 1); ReadRegWord(RDVRAML); // latch uint16 data = ReadRegWord(RDVRAML); return (addr & 1) ? GET_HIBYTE(data) : data; } void DecompressToVRAM(uint32 src, uint16 dst_addr) { // 0x80B271 decompress_src = src; int src_pos, dst_pos = dst_addr; while (1) { int len; uint8 b = DecompNextByte(), cmd; if (b == 0xFF) break; if ((b & 0xE0) == 0xE0) { cmd = (8 * b) & 0xE0; len = ((b & 3) << 8 | DecompNextByte()) + 1; } else { cmd = b & 0xE0; len = (b & 0x1F) + 1; } if (cmd & 0x80) { uint8 want_xor = cmd & 0x20 ? 0xff : 0; if (cmd >= 0xC0) { src_pos = dst_pos - DecompNextByte(); } else { src_pos = DecompNextByte(); src_pos += DecompNextByte() * 256; src_pos += dst_addr; } do { b = ReadPpuByte(src_pos++) ^ want_xor; WriteRegWord(VMADDL, dst_pos >> 1); WriteReg(VMDATAL + (dst_pos++ & 1), b); } while (--len); } else { switch (cmd) { case 0x20: b = DecompNextByte(); do { WriteReg(VMDATAL + (dst_pos++ & 1), b); } while (--len); break; case 0x40: { b = DecompNextByte(); uint8 b2 = DecompNextByte(); do { WriteReg(VMDATAL + (dst_pos++ & 1), b); if (!--len) break; WriteReg(VMDATAL + (dst_pos++ & 1), b2); } while (--len); break; } case 0x60: b = DecompNextByte(); do { WriteReg(VMDATAL + (dst_pos++ & 1), b++); } while (--len); break; default: do { b = DecompNextByte(); WriteReg(VMDATAL + (dst_pos++ & 1), b++); } while (--len); break; } } } } void LoadFromLoadStation(void) { // 0x80C437 save_station_lockout_flag = 1; const uint16 *v0 = (const uint16 *)RomPtr_80(kLoadStationLists[area_index] + 14 * load_station_index); room_ptr = *v0; door_def_ptr = v0[1]; door_bts = v0[2]; layer1_x_pos = v0[3]; bg1_x_offset = layer1_x_pos; layer1_y_pos = v0[4]; bg1_y_offset = layer1_y_pos; samus_y_pos = layer1_y_pos + v0[5]; samus_prev_y_pos = samus_y_pos; samus_x_pos = v0[6] + layer1_x_pos + 128; samus_prev_x_pos = samus_x_pos; reg_BG1HOFS = 0; reg_BG1VOFS = 0; LOBYTE(area_index) = get_RoomDefHeader(room_ptr)->area_index_; LOBYTE(debug_disable_minimap) = 0; } void SetElevatorsAsUsed(void) { // 0x80CD07 const uint8 *v0 = RomPtr_80(off_80CD46[area_index] + 4 * ((elevator_door_properties_orientation & 0xF) - 1)); used_save_stations_and_elevators[v0[0]] |= v0[1]; used_save_stations_and_elevators[v0[2]] |= v0[3]; }