From edef3c6449e49f832da0878c6c6924a9263b7463 Mon Sep 17 00:00:00 2001 From: nn <53490794+nn357@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:13:21 +0900 Subject: [PATCH 01/21] initial comit --- patches/ips/animated_map_tiles.ips | Bin 0 -> 322 bytes patches/rom_map/Bank DF.txt | 2 +- patches/src/animated_map_tiles.asm | 189 +++++++++++++++++++++++++++ rust/maprando/src/patch.rs | 18 ++- rust/maprando/src/patch/map_tiles.rs | 65 +++++---- 5 files changed, 239 insertions(+), 35 deletions(-) create mode 100644 patches/ips/animated_map_tiles.ips create mode 100644 patches/src/animated_map_tiles.asm diff --git a/patches/ips/animated_map_tiles.ips b/patches/ips/animated_map_tiles.ips new file mode 100644 index 0000000000000000000000000000000000000000..cb89d495533485d991d455f2a9b25cde294d6a91 GIT binary patch literal 322 zcmWG=3~}~g6trewQ(E)r{;OAvB619@N`645{v#nq1qKoUBLfoy3j+s(0D}TUH^(6Z zk6TgRt5-5G^uOb*>t6uEU+WeyFzgh1bUs?X?tBTxY<%n9-}5ae^Vtc8!%x4D&BAfb0-^ln+!q{}Myp t%KHrSuQ1dB9X9_eLtU3dCOg9_gd_I$88Bz8uKJ|`w5d0lJ=@ja4FJqYY~KI? literal 0 HcmV?d00001 diff --git a/patches/rom_map/Bank DF.txt b/patches/rom_map/Bank DF.txt index 270a1b95f..d3c7e2386 100644 --- a/patches/rom_map/Bank DF.txt +++ b/patches/rom_map/Bank DF.txt @@ -2,7 +2,7 @@ D4DF - D761: ; credits.asm D91B - DF0A: ; credits.asm E000 - E127: ; credits.asm E200 - E212: ; alternate_door_colors.asm -E212 - FEEF: [free] +E212 - FEEF: ; animate_map_tiles.asm - todo: measure where this patch ends FEF0 - FEFF: seed name (null-terminated ASCII string) FF00 - FF03: display seed / internal seed hash FF04 - FF04: [free] diff --git a/patches/src/animated_map_tiles.asm b/patches/src/animated_map_tiles.asm new file mode 100644 index 000000000..a2fbd56bc --- /dev/null +++ b/patches/src/animated_map_tiles.asm @@ -0,0 +1,189 @@ +;; Animated Maptiles for pause map double_item rooms +;; nn_357 + +lorom +arch 65816 + +!bank_df_free_space_start = $dfe212 ; values in this table are overwritten in patch.rs +!bank_df_free_space_end = $dffeef + +!tile_timer = $7e09ee +!tile_state = $7e09a0 +!interval = 48 +!current_area = $7e1f5b +!animate_mask = $7ef5a0 + +; Vanilla hooks + +org $82913B ;;; $9120: Pause menu - index 0: map screen ;;; + jsl AnimateTile + nop + nop + + +;$82:941E C9 07 00 CMP #$0007 ;\ +;$82:9421 30 03 BMI $03 [$9426] ;} If [area index] >= debug: +;$82:9423 A9 00 00 LDA #$0000 ; A = 0 +org $82941e ;;; TBD - Hook somewhere before the pause map VRAM buffer is cleared by the FX routine. + jsl BuildAnimateBitMask + nop + +; Custom code + +org !bank_df_free_space_start + +; area, vram_dest, tile_a, tile b +; tile_a will be set to FFFF on the server side if both items are of the same type so it is never animated as it will just waste cycles reloading an identical tile. + +DoubleItemTable: + dw $0000, $0000, $0000, $0000 ; Billy Mays + dw $0000, $0000, $0000, $0000 ; West Sand Pit + dw $0000, $0000, $0000, $0000 ; Watering Hole + dw $0000, $0000, $0000, $0000 ; Green Pirates Shaft + dw $0000, $0000, $0000, $0000 ; Green Brinstar Reserve + dw $0000, $0000, $0000, $0000 ; Norfair Reserve + + +RowBitMasks: + dw $0001, $0002, $0004, $0008, $0010, $0020 + +BuildAnimateBitMask: + + ; entry + phb + php + rep #$30 + pha + phx + phy + phk + plb + + lda #$0000 + sta !tile_timer + sta !tile_state + sta !animate_mask + + ldy #$0000 + +.loop + lda.w DoubleItemTable,y + cmp !current_area + bne .next_entry + + lda.w DoubleItemTable+2,y + sec + sbc #$3000 + asl + tax + + lda $7e4000,x + cmp.w DoubleItemTable+4,y + bne .next_entry + + tya + lsr + lsr + tax + lda.w RowBitMasks,x + ora !animate_mask + sta !animate_mask + +.next_entry + tya + clc + adc #$0008 + tay + cpy #$0030 + bne .loop + + ; cleanup + ply + plx + pla + plp + plb + cmp #$0007 + bmi .skip + lda #$0000 +.skip + rtl + + +AnimateTile: + php + rep #$30 + phx + phy + phb + phk + plb + + lda !tile_timer + inc + sta !tile_timer + cmp #!interval + bcc .done + + lda #$0000 + sta !tile_timer + lda !tile_state + eor #$0002 ; state is now 0 or 2 = byte offset of tile_a / tile_b + sta !tile_state + + lda !animate_mask + beq .done + pha ; running copy of the mask, shifted once per entry + + ldy #$0000 ; table offset + ldx $0330 ; VRAM write queue index + +.loop + lda $01,s + lsr + sta $01,s + bcc .next ; row bit not set + + lda DoubleItemTable,y + cmp !current_area + bne .next + + lda #$0002 + sta $7e00d0,x ; size + tya + clc + adc #DoubleItemTable+4 + adc !tile_state + sta $7e00d2,x ; source = tile_a or tile_b + lda #$00DF + sta $7e00d4,x ; bank (the dest write below overwrites the stray high byte) + lda DoubleItemTable+2,y + sta $7e00d5,x ; VRAM dest + txa + clc + adc #$0007 + tax + +.next + tya + clc + adc #$0008 + tay + cpy #$0030 + bne .loop + + stx $0330 + pla + +.done + plb + ply + plx + plp + lda #$0000 + sta $0763 + rtl + + print pc + + assert pc() <= !bank_df_free_space_end \ No newline at end of file diff --git a/rust/maprando/src/patch.rs b/rust/maprando/src/patch.rs index e968239a4..468b119fe 100644 --- a/rust/maprando/src/patch.rs +++ b/rust/maprando/src/patch.rs @@ -489,6 +489,7 @@ impl Patcher<'_> { "fix_choot", "resource_collection_hudcap", "item_count", + "animated_map_tiles", ]; patches.push("new_game"); @@ -1069,16 +1070,13 @@ impl Patcher<'_> { } fn get_arrow_xy(&self, door: &RoomGeometryDoor) -> (isize, isize) { - if door.direction == "left" { - (door.x as isize - 1, door.y as isize) - } else if door.direction == "right" { - (door.x as isize + 1, door.y as isize) - } else if door.direction == "up" { - (door.x as isize, door.y as isize - 1) - } else if door.direction == "down" { - (door.x as isize, door.y as isize + 1) - } else { - panic!("Unrecognized door direction: {}", door.direction); + let (x, y) = (door.x as isize, door.y as isize); + match door.direction.as_str() { + "left" => (x - 1, y), + "right" => (x + 1, y), + "up" => (x, y - 1), + "down" => (x, y + 1), + other => panic!("Unrecognized door direction: {}", other), } } diff --git a/rust/maprando/src/patch/map_tiles.rs b/rust/maprando/src/patch/map_tiles.rs index 921e2f0be..f7b59d9b7 100644 --- a/rust/maprando/src/patch/map_tiles.rs +++ b/rust/maprando/src/patch/map_tiles.rs @@ -2689,6 +2689,38 @@ impl<'a> MapPatcher<'a> { Ok(()) } + fn write_double_item_table( + &mut self, + area_data: &[Vec<(ItemIdx, RoomId, MapTile)>], + ) -> Result<()> { + let mut doubles: Vec<[u16; 4]> = vec![]; + for (area_idx, data) in area_data.iter().enumerate() { + for (i, (_, _, a)) in data.iter().enumerate() { + for (_, _, b) in &data[i + 1..] { + if a.coords != b.coords { + continue; + } + let wa = self.index_tile(a.clone(), None)? as u16; + let wb = self.index_tile(b.clone(), None)? as u16; + let x = a.coords.0 as isize - self.area_offset_x[area_idx]; + let y = a.coords.1 as isize - self.area_offset_y[area_idx]; + let dest = 0x3000 + xy_to_map_offset(x, y) / 2; + let tile_a = if wa == wb { 0xFFFF } else { wb }; + doubles.push([area_idx as u16, dest as u16, tile_a, wa]); + } + } + } + assert!(doubles.len() <= 6); + doubles.resize(6, [0xFFFF, 0, 0xFFFF, 0]); + for (i, e) in doubles.iter().enumerate() { + for (j, &w) in e.iter().enumerate() { + self.rom + .write_u16(snes2pc(0xDFE212 + i * 8 + j * 2), w as isize)?; + } + } + Ok(()) + } + fn indicate_items(&mut self) -> Result<()> { for (i, &item) in self.randomization.item_placement.iter().enumerate() { let (room_id, node_id) = self.game_data.item_locations[i]; @@ -2703,42 +2735,26 @@ impl<'a> MapPatcher<'a> { .objectives .contains(&Objective::BombTorizo) { - // If BT is an objective, we don't draw item dot there since an objective X tile will be drawn instead. continue; } let item_ptr = self.game_data.node_ptr_map[&(room_id, node_id)]; let item_idx = self.rom.read_u8(item_ptr + 4)? as usize; - let room_ptr = self.game_data.room_ptr_by_id[&room_id]; - let room_idx = self.game_data.room_idx_by_ptr[&room_ptr]; let room = &self.game_data.room_geometry[room_idx]; let area = self.map.area[room_idx]; let (x, y) = find_item_xy(item_ptr, &room.items)?; let orig_tile = self.get_room_tile(room_id, x, y).unwrap().clone(); let mut tile = orig_tile.clone(); tile.faded = MapTileFade::None; - if [MapTileInterior::HiddenItem, MapTileInterior::DoubleItem].contains(&tile.interior) { - tile.interior = MapTileInterior::Item; - } - tile.interior = get_item_interior(item, self.settings); self.dynamic_tile_data[area].push((item_idx, room_id, tile.clone())); - match self.customize_settings.item_dot_change { - ItemDotChange::Fade => { - tile.interior = apply_item_interior(orig_tile.clone(), item, self.settings); - tile.faded = MapTileFade::Faded; - self.set_room_tile(room_id, x, y, tile.clone()); - } - ItemDotChange::Disappear => { - tile.interior = apply_item_interior(orig_tile.clone(), item, self.settings); - tile.faded = MapTileFade::Disappeared; - self.set_room_tile(room_id, x, y, tile.clone()); - } - ItemDotChange::Stay => { - tile.interior = apply_item_interior(orig_tile.clone(), item, self.settings); - tile.faded = MapTileFade::None; - self.set_room_tile(room_id, x, y, tile.clone()); - } - } + + tile.interior = apply_item_interior(orig_tile, item, self.settings); + tile.faded = match self.customize_settings.item_dot_change { + ItemDotChange::Fade => MapTileFade::Faded, + ItemDotChange::Disappear => MapTileFade::Disappeared, + ItemDotChange::Stay => MapTileFade::None, + }; + self.set_room_tile(room_id, x, y, tile); } Ok(()) @@ -3379,6 +3395,7 @@ impl<'a> MapPatcher<'a> { } self.sort_dynamic_tile_data()?; self.write_dynamic_tile_data(&self.dynamic_tile_data.clone())?; + self.write_double_item_table(&self.dynamic_tile_data.clone())?; self.create_room_map_tilemaps()?; if self.settings.quality_of_life_settings.hazard_markers { self.write_hazard_tiles()?; From 6fe065aba9dc8f1364b12c4a284217a2e1632bce Mon Sep 17 00:00:00 2001 From: nn <53490794+nn357@users.noreply.github.com> Date: Fri, 16 Oct 2026 14:30:26 +0900 Subject: [PATCH 02/21] patch update rust math is probably wrong... check it later --- patches/ips/animated_map_tiles.ips | Bin 322 -> 326 bytes patches/rom_map/Bank DF.txt | 3 ++- patches/src/animated_map_tiles.asm | 8 ++++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/patches/ips/animated_map_tiles.ips b/patches/ips/animated_map_tiles.ips index cb89d495533485d991d455f2a9b25cde294d6a91..b16f0ee9638151075487e7a9ddf55bb7a9f40312 100644 GIT binary patch delta 33 ocmX@abc|_&2p@-%-=q7lfI$C|5ToKmMZJl>bxa-%6VH?Z0PXw@z5oCK delta 32 ocmX@cbckt!2sf*e-=q7l^dAW^Doiv~oan$mF{p;oVB&=`0Kc>g$^ZZW diff --git a/patches/rom_map/Bank DF.txt b/patches/rom_map/Bank DF.txt index d3c7e2386..208ed95fa 100644 --- a/patches/rom_map/Bank DF.txt +++ b/patches/rom_map/Bank DF.txt @@ -2,7 +2,8 @@ D4DF - D761: ; credits.asm D91B - DF0A: ; credits.asm E000 - E127: ; credits.asm E200 - E212: ; alternate_door_colors.asm -E212 - FEEF: ; animate_map_tiles.asm - todo: measure where this patch ends +E212 - E333: ; animate_map_tiles.asm +E333 - FEF0: [free] FEF0 - FEFF: seed name (null-terminated ASCII string) FF00 - FF03: display seed / internal seed hash FF04 - FF04: [free] diff --git a/patches/src/animated_map_tiles.asm b/patches/src/animated_map_tiles.asm index a2fbd56bc..194995286 100644 --- a/patches/src/animated_map_tiles.asm +++ b/patches/src/animated_map_tiles.asm @@ -9,7 +9,7 @@ arch 65816 !tile_timer = $7e09ee !tile_state = $7e09a0 -!interval = 48 +!interval = #$0048 !current_area = $7e1f5b !animate_mask = $7ef5a0 @@ -27,6 +27,10 @@ org $82913B ;;; $9120: Pause menu - index 0: map screen ;;; org $82941e ;;; TBD - Hook somewhere before the pause map VRAM buffer is cleared by the FX routine. jsl BuildAnimateBitMask nop + nop + nop + nop + ; Custom code @@ -122,7 +126,7 @@ AnimateTile: lda !tile_timer inc sta !tile_timer - cmp #!interval + cmp !interval bcc .done lda #$0000 From f8c3e7535764c8d0010de716415c16f2adb1d847 Mon Sep 17 00:00:00 2001 From: nn <53490794+nn357@users.noreply.github.com> Date: Fri, 16 Oct 2026 17:56:01 +0900 Subject: [PATCH 03/21] fix small error in asm bank DF doesn't mirror loram so use long address --- patches/ips/animated_map_tiles.ips | Bin 326 -> 330 bytes patches/rom_map/Bank DF.txt | 4 ++-- patches/src/animated_map_tiles.asm | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/patches/ips/animated_map_tiles.ips b/patches/ips/animated_map_tiles.ips index b16f0ee9638151075487e7a9ddf55bb7a9f40312..f2ef6bc8240ae5b383ee52a00dae173398b2aa27 100644 GIT binary patch delta 76 zcmX@cbc$($BBSa=L&b>>{1b!fm9kbcF!aCUtXsc;v(A%=p&v-CU+}f=Ly*S;28Q(p e%yp|KesmV;>IbqiR#*Mf04ncIX3uu@cLM-G3LMS= delta 72 zcmX@bbc|_&BBSC&L&b>>{1b!f71CBRF!aCUtXsc;v(A%=p&v-CU+}f=gP+F&28MM8 b%o9I53-uW=XRNOJr2$mho6Mf=>hA^szT6s) diff --git a/patches/rom_map/Bank DF.txt b/patches/rom_map/Bank DF.txt index 208ed95fa..d0c18f7aa 100644 --- a/patches/rom_map/Bank DF.txt +++ b/patches/rom_map/Bank DF.txt @@ -2,8 +2,8 @@ D4DF - D761: ; credits.asm D91B - DF0A: ; credits.asm E000 - E127: ; credits.asm E200 - E212: ; alternate_door_colors.asm -E212 - E333: ; animate_map_tiles.asm -E333 - FEF0: [free] +E212 - E337: ; animated_map_tiles.asm +E337 - FEF0: [free] FEF0 - FEFF: seed name (null-terminated ASCII string) FF00 - FF03: display seed / internal seed hash FF04 - FF04: [free] diff --git a/patches/src/animated_map_tiles.asm b/patches/src/animated_map_tiles.asm index 194995286..dadca4493 100644 --- a/patches/src/animated_map_tiles.asm +++ b/patches/src/animated_map_tiles.asm @@ -140,7 +140,8 @@ AnimateTile: pha ; running copy of the mask, shifted once per entry ldy #$0000 ; table offset - ldx $0330 ; VRAM write queue index + lda.l $7e0330 + tax .loop lda $01,s @@ -176,7 +177,8 @@ AnimateTile: cpy #$0030 bne .loop - stx $0330 + txa + sta.l $7e0330 pla .done From 928ff279e1feb85462bf7fbc289445fd834feb20 Mon Sep 17 00:00:00 2001 From: nn <53490794+nn357@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:44:35 +0900 Subject: [PATCH 04/21] make animated tiles a toggle --- patches/src/animated_map_tiles.asm | 31 ++++++++----------- .../Community Race Season 5.json | 1 + rust/data/presets/full-settings/Default.json | 1 + .../full-settings/Mentor Tournament.json | 1 + .../Summer Series Expert Challenge.json | 1 + .../data/presets/quality-of-life/Default.json | 1 + rust/data/presets/quality-of-life/High.json | 1 + rust/data/presets/quality-of-life/Low.json | 1 + rust/data/presets/quality-of-life/Max.json | 1 + rust/data/presets/quality-of-life/Off.json | 1 + .../generate/help/quality/animated_tiles.html | 24 ++++++++++++++ .../templates/generate/quality_of_life.html | 19 ++++++++++++ .../templates/generate/scripts.html | 2 ++ rust/maprando/src/patch.rs | 5 ++- rust/maprando/src/patch/map_tiles.rs | 4 ++- rust/maprando/src/settings.rs | 4 +++ rust/maprando/tests/logic_scenarios.rs | 1 + 17 files changed, 79 insertions(+), 20 deletions(-) create mode 100644 rust/maprando-web/templates/generate/help/quality/animated_tiles.html diff --git a/patches/src/animated_map_tiles.asm b/patches/src/animated_map_tiles.asm index dadca4493..f8d1cf93f 100644 --- a/patches/src/animated_map_tiles.asm +++ b/patches/src/animated_map_tiles.asm @@ -20,15 +20,11 @@ org $82913B ;;; $9120: Pause menu - index 0: map screen ;;; nop nop - -;$82:941E C9 07 00 CMP #$0007 ;\ -;$82:9421 30 03 BMI $03 [$9426] ;} If [area index] >= debug: -;$82:9423 A9 00 00 LDA #$0000 ; A = 0 -org $82941e ;;; TBD - Hook somewhere before the pause map VRAM buffer is cleared by the FX routine. +org $82941e ;;; ;;; $93C3: Load pause menu map tilemap and area label ;;; jsl BuildAnimateBitMask - nop - nop - nop + nop ;$82:941E C9 07 00 CMP #$0007 ;\ + nop ;$82:9421 30 03 BMI $03 [$9426] ;} If [area index] >= debug: + nop ;$82:9423 A9 00 00 LDA #$0000 ; A = 0 nop @@ -38,6 +34,7 @@ org !bank_df_free_space_start ; area, vram_dest, tile_a, tile b ; tile_a will be set to FFFF on the server side if both items are of the same type so it is never animated as it will just waste cycles reloading an identical tile. +; table is ordered by area for the 6 double_item rooms, upto 6, if small maps / missing etc table is padded with FFFF to fill this table. DoubleItemTable: dw $0000, $0000, $0000, $0000 ; Billy Mays @@ -107,9 +104,9 @@ BuildAnimateBitMask: pla plp plb - cmp #$0007 - bmi .skip - lda #$0000 + cmp #$0007 ; + bmi .skip ; hijacked code. (dont' think this does anything in MapRando anyway, it's for Debug options but restore it regardless.) + lda #$0000 ; .skip rtl @@ -132,7 +129,7 @@ AnimateTile: lda #$0000 sta !tile_timer lda !tile_state - eor #$0002 ; state is now 0 or 2 = byte offset of tile_a / tile_b + eor #$0002 ; byte offset of tile_a / tile_b sta !tile_state lda !animate_mask @@ -147,7 +144,7 @@ AnimateTile: lda $01,s lsr sta $01,s - bcc .next ; row bit not set + bcc .next ; bit not set lda DoubleItemTable,y cmp !current_area @@ -161,7 +158,7 @@ AnimateTile: adc !tile_state sta $7e00d2,x ; source = tile_a or tile_b lda #$00DF - sta $7e00d4,x ; bank (the dest write below overwrites the stray high byte) + sta $7e00d4,x ; bank (dest write below overwrites the stray high byte) lda DoubleItemTable+2,y sta $7e00d5,x ; VRAM dest txa @@ -186,10 +183,8 @@ AnimateTile: ply plx plp - lda #$0000 - sta $0763 + lda #$0000 + sta $0763 rtl - print pc - assert pc() <= !bank_df_free_space_end \ No newline at end of file diff --git a/rust/data/presets/full-settings/Community Race Season 5.json b/rust/data/presets/full-settings/Community Race Season 5.json index 76e75fad1..d3d2cb6f9 100644 --- a/rust/data/presets/full-settings/Community Race Season 5.json +++ b/rust/data/presets/full-settings/Community Race Season 5.json @@ -4755,6 +4755,7 @@ "room_outline_revealed": true, "opposite_area_revealed": true, "hazard_markers": true, + "animated_tiles": true, "mother_brain_fight": "Short", "supers_double": true, "escape_autosave": true, diff --git a/rust/data/presets/full-settings/Default.json b/rust/data/presets/full-settings/Default.json index 17dbbb6d2..200f24740 100644 --- a/rust/data/presets/full-settings/Default.json +++ b/rust/data/presets/full-settings/Default.json @@ -4667,6 +4667,7 @@ "room_outline_revealed": true, "opposite_area_revealed": false, "hazard_markers": true, + "animated_tiles": true, "mother_brain_fight": "Short", "supers_double": true, "escape_autosave": true, diff --git a/rust/data/presets/full-settings/Mentor Tournament.json b/rust/data/presets/full-settings/Mentor Tournament.json index b2434bf56..098cd5f8b 100644 --- a/rust/data/presets/full-settings/Mentor Tournament.json +++ b/rust/data/presets/full-settings/Mentor Tournament.json @@ -4755,6 +4755,7 @@ "room_outline_revealed": true, "opposite_area_revealed": true, "hazard_markers": true, + "animated_tiles": true, "mother_brain_fight": "Short", "supers_double": true, "escape_autosave": true, diff --git a/rust/data/presets/full-settings/Summer Series Expert Challenge.json b/rust/data/presets/full-settings/Summer Series Expert Challenge.json index 354a7ec3d..ac16c85ab 100644 --- a/rust/data/presets/full-settings/Summer Series Expert Challenge.json +++ b/rust/data/presets/full-settings/Summer Series Expert Challenge.json @@ -4667,6 +4667,7 @@ "room_outline_revealed": true, "opposite_area_revealed": true, "hazard_markers": true, + "animated_tiles": true, "mother_brain_fight": "Short", "supers_double": true, "escape_autosave": true, diff --git a/rust/data/presets/quality-of-life/Default.json b/rust/data/presets/quality-of-life/Default.json index f67c790f2..4a66aedad 100644 --- a/rust/data/presets/quality-of-life/Default.json +++ b/rust/data/presets/quality-of-life/Default.json @@ -48,6 +48,7 @@ "room_outline_revealed": true, "opposite_area_revealed": false, "hazard_markers": true, + "animated_tiles": true, "mother_brain_fight": "Short", "supers_double": true, "escape_autosave": true, diff --git a/rust/data/presets/quality-of-life/High.json b/rust/data/presets/quality-of-life/High.json index cb08afbde..29c8d8b22 100644 --- a/rust/data/presets/quality-of-life/High.json +++ b/rust/data/presets/quality-of-life/High.json @@ -48,6 +48,7 @@ "room_outline_revealed": true, "opposite_area_revealed": true, "hazard_markers": true, + "animated_tiles": true, "mother_brain_fight": "Short", "supers_double": true, "escape_autosave": true, diff --git a/rust/data/presets/quality-of-life/Low.json b/rust/data/presets/quality-of-life/Low.json index 6cd0fca4d..62e50b68a 100644 --- a/rust/data/presets/quality-of-life/Low.json +++ b/rust/data/presets/quality-of-life/Low.json @@ -48,6 +48,7 @@ "room_outline_revealed": false, "opposite_area_revealed": false, "hazard_markers": true, + "animated_tiles": true, "mother_brain_fight": "Short", "supers_double": true, "escape_autosave": true, diff --git a/rust/data/presets/quality-of-life/Max.json b/rust/data/presets/quality-of-life/Max.json index c2f1c8802..85c54343f 100644 --- a/rust/data/presets/quality-of-life/Max.json +++ b/rust/data/presets/quality-of-life/Max.json @@ -48,6 +48,7 @@ "room_outline_revealed": true, "opposite_area_revealed": true, "hazard_markers": true, + "animated_tiles": true, "mother_brain_fight": "Skip", "supers_double": true, "escape_autosave": true, diff --git a/rust/data/presets/quality-of-life/Off.json b/rust/data/presets/quality-of-life/Off.json index b3e42e4dd..85876e374 100644 --- a/rust/data/presets/quality-of-life/Off.json +++ b/rust/data/presets/quality-of-life/Off.json @@ -48,6 +48,7 @@ "room_outline_revealed": false, "opposite_area_revealed": false, "hazard_markers": false, + "animated_tiles": false, "mother_brain_fight": "Vanilla", "supers_double": false, "escape_autosave": false, diff --git a/rust/maprando-web/templates/generate/help/quality/animated_tiles.html b/rust/maprando-web/templates/generate/help/quality/animated_tiles.html new file mode 100644 index 000000000..1ef624951 --- /dev/null +++ b/rust/maprando-web/templates/generate/help/quality/animated_tiles.html @@ -0,0 +1,24 @@ + \ No newline at end of file diff --git a/rust/maprando-web/templates/generate/quality_of_life.html b/rust/maprando-web/templates/generate/quality_of_life.html index 12946a159..af0550677 100644 --- a/rust/maprando-web/templates/generate/quality_of_life.html +++ b/rust/maprando-web/templates/generate/quality_of_life.html @@ -180,6 +180,24 @@

Quality-of-life options

+ +
+
+ + +
+
+ + + + +
+
@@ -872,6 +890,7 @@

Quality-of-life options

{% include "help/quality/room_outline.html" %} {% include "help/quality/opposite_area_revealed.html" %} {% include "help/quality/hazard_markers.html" %} +{% include "help/quality/animated_tiles.html" %} {% include "help/quality/mother_brain_fight.html" %} {% include "help/quality/supers_double.html" %} diff --git a/rust/maprando-web/templates/generate/scripts.html b/rust/maprando-web/templates/generate/scripts.html index baf301086..e72b32bd7 100644 --- a/rust/maprando-web/templates/generate/scripts.html +++ b/rust/maprando-web/templates/generate/scripts.html @@ -304,6 +304,7 @@ "room_outline_revealed": formData.get("room_outline_revealed") == "true", "opposite_area_revealed": formData.get("opposite_area_revealed") == "true", "hazard_markers": formData.get("hazard_markers") == "true", + "animated_tiles": formData.get("animated_tiles") == "true", "mother_brain_fight": formData.get("mother_brain_fight"), "supers_double": formData.get("supers_double") == "true", "escape_autosave": formData.get("escape_autosave") == "true", @@ -598,6 +599,7 @@ applyRadioValue("roomOutlineRevealed", preset.room_outline_revealed); applyRadioValue("oppositeAreaRevealed", preset.opposite_area_revealed); applyRadioValue("hazardMarkers", preset.hazard_markers); + applyRadioValue("animatedTiles", preset.animated_tiles); applyRadioValue("motherBrainFight", preset.mother_brain_fight); applyRadioValue("supersDouble", preset.supers_double); applyRadioValue("escapeAutosave", preset.escape_autosave); diff --git a/rust/maprando/src/patch.rs b/rust/maprando/src/patch.rs index 468b119fe..fc83f0ed2 100644 --- a/rust/maprando/src/patch.rs +++ b/rust/maprando/src/patch.rs @@ -489,7 +489,6 @@ impl Patcher<'_> { "fix_choot", "resource_collection_hudcap", "item_count", - "animated_map_tiles", ]; patches.push("new_game"); @@ -578,6 +577,10 @@ impl Patcher<'_> { patches.push("crash_handle_base"); } + if self.settings.quality_of_life_settings.animated_tiles{ + patches.push("animated_map_tiles"); + } + let fixes = &self.settings.quality_of_life_settings.crash_fixes; if fixes.spring_ball != FixMode::Crash { diff --git a/rust/maprando/src/patch/map_tiles.rs b/rust/maprando/src/patch/map_tiles.rs index f7b59d9b7..3de2d844f 100644 --- a/rust/maprando/src/patch/map_tiles.rs +++ b/rust/maprando/src/patch/map_tiles.rs @@ -3395,7 +3395,9 @@ impl<'a> MapPatcher<'a> { } self.sort_dynamic_tile_data()?; self.write_dynamic_tile_data(&self.dynamic_tile_data.clone())?; - self.write_double_item_table(&self.dynamic_tile_data.clone())?; + if self.settings.quality_of_life_settings.animated_tiles { + self.write_double_item_table(&self.dynamic_tile_data.clone())?; + } self.create_room_map_tilemaps()?; if self.settings.quality_of_life_settings.hazard_markers { self.write_hazard_tiles()?; diff --git a/rust/maprando/src/settings.rs b/rust/maprando/src/settings.rs index c92f8891a..604431254 100644 --- a/rust/maprando/src/settings.rs +++ b/rust/maprando/src/settings.rs @@ -316,6 +316,7 @@ pub struct QualityOfLifeSettings { pub room_outline_revealed: bool, pub opposite_area_revealed: bool, pub hazard_markers: bool, + pub animated_tiles: bool, // End game: pub mother_brain_fight: MotherBrainFight, pub supers_double: bool, @@ -1332,6 +1333,9 @@ fn upgrade_qol_settings(settings: &mut serde_json::Value) -> Result<()> { if !qol_settings.contains_key("hazard_markers") { qol_settings.insert("hazard_markers".to_string(), true.into()); } + if !qol_settings.contains_key("animated_tiles") { + qol_settings.insert("animated_tiles".to_string(), true.into()); + } if !qol_settings.contains_key("persist_flash_suit") { qol_settings.insert("persist_flash_suit".to_string(), false.into()); } diff --git a/rust/maprando/tests/logic_scenarios.rs b/rust/maprando/tests/logic_scenarios.rs index 2372b6d37..b4c636137 100644 --- a/rust/maprando/tests/logic_scenarios.rs +++ b/rust/maprando/tests/logic_scenarios.rs @@ -270,6 +270,7 @@ fn get_settings(scenario: &Scenario) -> Result { room_outline_revealed: false, opposite_area_revealed: false, hazard_markers: false, + animated_tiles: false, mother_brain_fight: maprando::settings::MotherBrainFight::Vanilla, supers_double: false, escape_autosave: false, From c6bee727a85e18c06db653f5609837f1dc1ebf97 Mon Sep 17 00:00:00 2001 From: nn <53490794+nn357@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:50:41 +0900 Subject: [PATCH 05/21] typo --- rust/maprando-web/templates/generate/quality_of_life.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/maprando-web/templates/generate/quality_of_life.html b/rust/maprando-web/templates/generate/quality_of_life.html index af0550677..cf0cf5b1d 100644 --- a/rust/maprando-web/templates/generate/quality_of_life.html +++ b/rust/maprando-web/templates/generate/quality_of_life.html @@ -184,7 +184,7 @@

Quality-of-life options

From 2298716729bf396a4d1ad66dbc8473d1a8484879 Mon Sep 17 00:00:00 2001 From: nn <53490794+nn357@users.noreply.github.com> Date: Sat, 17 Oct 2026 03:10:43 +0900 Subject: [PATCH 06/21] optimization --- patches/ips/animated_map_tiles.ips | Bin 330 -> 338 bytes patches/rom_map/Bank DF.txt | 4 ++-- patches/src/animated_map_tiles.asm | 21 ++++++++++++++------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/patches/ips/animated_map_tiles.ips b/patches/ips/animated_map_tiles.ips index f2ef6bc8240ae5b383ee52a00dae173398b2aa27..97773895aa522613dea606a7774ea2db84528d0b 100644 GIT binary patch delta 52 zcmX@bbctz#BBSm^L&b>>{1bz6`PaYWtdlxvz%ZfeR#dn5>WP<1`TK!F8Y>wXdXw3+ HUH#nv1p^b1 delta 44 zcmcb_bc$($BBSa=L&b>>{1bz6g>OZ5d#_&qj Date: Sat, 17 Oct 2026 15:45:27 +0900 Subject: [PATCH 07/21] ignore palette bits (allows flipping to continute while item(s) are uncollected even if tile has been marked as explored) --- patches/ips/animated_map_tiles.ips | Bin 338 -> 377 bytes patches/src/animated_map_tiles.asm | 52 ++++++++++++++++++--------- rust/maprando/src/patch/map_tiles.rs | 4 +-- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/patches/ips/animated_map_tiles.ips b/patches/ips/animated_map_tiles.ips index 97773895aa522613dea606a7774ea2db84528d0b..6e7e52bd30e9c73384a98f4ee877cc1f3dc8d4f4 100644 GIT binary patch delta 227 zcmcb_^pi;`z%j(xgHh0$flX=sqx-L3F^b4Ba47kKn6F;xKN4aLnP{ju(Sd(rkiMYG zPLW3zFBuHDR_$kSsMGxacw)aC6V*^uOb*(^$#C(3{MjJ@KSWeVNAs28Q(p z%yp|4GkP^MP6*v8^yqxFeBA|~Td1Zm$at(@z*%>Jb*I>)2Iid-kC++f15MB9lE`Fm z_%;6$L)}UyhWQtOR2{?oD-3l&-Se+9)B&a08CK1Z$mC#HalnA#!pyFIpk*1WtA2r9 L!3K1OtG^ondSzHk delta 190 zcmey#bcsnRz%j(xgHh0$flX=6qx-L3F^b4Ba47kKn6F;xKN4cpooJ{y(Sd(rkiM?s zPLW3zFBuHDR_$kSsJkil=mP%?FRxX5ogVQo_*&Nw#4{u^IT%(PFkrZFdg4Y&rU_LO zZ^#$~c`RUHSZ}~ww`wt?S2N=T!<|Bp&PU7FUC>y`#4!H?14x(Hqx=P&b@MMV)UCWf j*@IC=ac@^YP)Ek MapPatcher<'a> { if a.coords != b.coords { continue; } - let wa = self.index_tile(a.clone(), None)? as u16; - let wb = self.index_tile(b.clone(), None)? as u16; + let wa = self.index_tile(a.clone(), None)? & !0x1C00; + let wb = self.index_tile(b.clone(), None)? & !0x1C00; let x = a.coords.0 as isize - self.area_offset_x[area_idx]; let y = a.coords.1 as isize - self.area_offset_y[area_idx]; let dest = 0x3000 + xy_to_map_offset(x, y) / 2; From b19fff8ae540bbf4e119bc68c36ca8f89bb4a05a Mon Sep 17 00:00:00 2001 From: nn <53490794+nn357@users.noreply.github.com> Date: Sat, 17 Oct 2026 16:06:41 +0900 Subject: [PATCH 08/21] add check to bitmask to don't animate if item b is collected --- patches/src/animated_map_tiles.asm | 33 ++++++++++++++++++---------- rust/maprando/src/patch/map_tiles.rs | 19 +++++++++++----- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/patches/src/animated_map_tiles.asm b/patches/src/animated_map_tiles.asm index fe1707c68..691a3e109 100644 --- a/patches/src/animated_map_tiles.asm +++ b/patches/src/animated_map_tiles.asm @@ -37,12 +37,12 @@ org !bank_df_free_space_start ; table is ordered by area for the 6 double_item rooms, upto 6, if small maps / missing etc table is padded with FFFF to fill this table. DoubleItemTable: - dw $0000, $0000, $0000, $0000 ; Billy Mays - dw $0000, $0000, $0000, $0000 ; West Sand Pit - dw $0000, $0000, $0000, $0000 ; Watering Hole - dw $0000, $0000, $0000, $0000 ; Green Pirates Shaft - dw $0000, $0000, $0000, $0000 ; Green Brinstar Reserve - dw $0000, $0000, $0000, $0000 ; Norfair Reserve + dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ; Billy Mays + dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ; West Sand Pit + dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ; Watering Hole + dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ; Green Pirates Shaft + dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ; Green Brinstar Reserve + dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ; Norfair Reserve RowBitMasks: @@ -79,14 +79,22 @@ BuildAnimateBitMask: tax lda $7e4000,x - and #$e3ff ; remove the pallete bits to keep animation running if tiles have been marked as explored. + and #$E3FF cmp.w DoubleItemTable+4,y bne .next_entry + lda.w DoubleItemTable+8,y + tax + lda $7ed870,x + and.w DoubleItemTable+10,y + bne .next_entry + tya lsr lsr + lsr tax + lda.w RowBitMasks,x ora !animate_mask sta !animate_mask @@ -94,11 +102,11 @@ BuildAnimateBitMask: .next_entry tya clc - adc #$0008 + adc #$0010 tay - cpy #$0030 + cpy #$0060 bne .loop - + ; cleanup ply plx @@ -196,9 +204,9 @@ AnimateTile: .next tya clc - adc #$0008 + adc #$0010 tay - cpy #$0030 + cpy #$0060 bne .loop txa @@ -214,4 +222,5 @@ AnimateTile: sta $0763 rtl + print pc assert pc() <= !bank_df_free_space_end \ No newline at end of file diff --git a/rust/maprando/src/patch/map_tiles.rs b/rust/maprando/src/patch/map_tiles.rs index 780eb8987..e479cebca 100644 --- a/rust/maprando/src/patch/map_tiles.rs +++ b/rust/maprando/src/patch/map_tiles.rs @@ -2693,9 +2693,9 @@ impl<'a> MapPatcher<'a> { &mut self, area_data: &[Vec<(ItemIdx, RoomId, MapTile)>], ) -> Result<()> { - let mut doubles: Vec<[u16; 4]> = vec![]; + let mut doubles: Vec<[u16; 8]> = vec![]; for (area_idx, data) in area_data.iter().enumerate() { - for (i, (_, _, a)) in data.iter().enumerate() { + for (i, (item_a, _, a)) in data.iter().enumerate() { for (_, _, b) in &data[i + 1..] { if a.coords != b.coords { continue; @@ -2706,16 +2706,25 @@ impl<'a> MapPatcher<'a> { let y = a.coords.1 as isize - self.area_offset_y[area_idx]; let dest = 0x3000 + xy_to_map_offset(x, y) / 2; let tile_a = if wa == wb { 0xFFFF } else { wb }; - doubles.push([area_idx as u16, dest as u16, tile_a, wa]); + doubles.push([ + area_idx as u16, + dest as u16, + tile_a, + wa, + (item_a / 8) as u16, + 1u16 << (item_a % 8), + 0, + 0, + ]); } } } assert!(doubles.len() <= 6); - doubles.resize(6, [0xFFFF, 0, 0xFFFF, 0]); + doubles.resize(6, [0xFFFF, 0, 0xFFFF, 0, 0, 0, 0, 0]); for (i, e) in doubles.iter().enumerate() { for (j, &w) in e.iter().enumerate() { self.rom - .write_u16(snes2pc(0xDFE212 + i * 8 + j * 2), w as isize)?; + .write_u16(snes2pc(0xDFE212 + i * 16 + j * 2), w as isize)?; } } Ok(()) From d86326711e3346e3563b162c3c37a21af1661a33 Mon Sep 17 00:00:00 2001 From: nn <53490794+nn357@users.noreply.github.com> Date: Sat, 17 Oct 2026 16:29:09 +0900 Subject: [PATCH 09/21] fix palette issue --- patches/rom_map/Bank DF.txt | 4 +-- patches/src/animated_map_tiles.asm | 38 ++++++++-------------------- rust/maprando/src/patch/map_tiles.rs | 4 +-- 3 files changed, 14 insertions(+), 32 deletions(-) diff --git a/patches/rom_map/Bank DF.txt b/patches/rom_map/Bank DF.txt index 4c3135987..23e6b3f16 100644 --- a/patches/rom_map/Bank DF.txt +++ b/patches/rom_map/Bank DF.txt @@ -2,8 +2,8 @@ D4DF - D761: ; credits.asm D91B - DF0A: ; credits.asm E000 - E127: ; credits.asm E200 - E212: ; alternate_door_colors.asm -E212 - E33F: ; animated_map_tiles.asm -E33F - FEF0: [free] +E212 - E3A4: ; animated_map_tiles.asm +E3A4 - FEF0: [free] FEF0 - FEFF: seed name (null-terminated ASCII string) FF00 - FF03: display seed / internal seed hash FF04 - FF04: [free] diff --git a/patches/src/animated_map_tiles.asm b/patches/src/animated_map_tiles.asm index 691a3e109..572b7f160 100644 --- a/patches/src/animated_map_tiles.asm +++ b/patches/src/animated_map_tiles.asm @@ -79,7 +79,6 @@ BuildAnimateBitMask: tax lda $7e4000,x - and #$E3FF cmp.w DoubleItemTable+4,y bne .next_entry @@ -166,36 +165,17 @@ AnimateTile: cmp !current_area bne .next - phx - lda DoubleItemTable+2,y - sec - sbc #$3000 - asl - tax - lda $7e4000,x - and #$1C00 - pha - lda !tile_state - bne .tile_b - lda DoubleItemTable+4,y - bra .merge -.tile_b - lda DoubleItemTable+6,y -.merge - ora $01,s - sta $7e4000,x - pla - txa - clc - adc #$4000 - plx - sta $7e00d2,x lda #$0002 - sta $7e00d0,x - lda #$007E + sta $7e00d0,x ; size + tya + clc + adc #DoubleItemTable+4 + adc !tile_state + sta $7e00d2,x ; source = tile_a or tile_b + lda #$00DF sta $7e00d4,x ; bank (dest write below overwrites the stray high byte) lda DoubleItemTable+2,y - sta $7e00d5,x + sta $7e00d5,x ; VRAM dest txa clc adc #$0007 @@ -222,5 +202,7 @@ AnimateTile: sta $0763 rtl + print pc + assert pc() <= !bank_df_free_space_end \ No newline at end of file diff --git a/rust/maprando/src/patch/map_tiles.rs b/rust/maprando/src/patch/map_tiles.rs index e479cebca..7f995128f 100644 --- a/rust/maprando/src/patch/map_tiles.rs +++ b/rust/maprando/src/patch/map_tiles.rs @@ -2700,8 +2700,8 @@ impl<'a> MapPatcher<'a> { if a.coords != b.coords { continue; } - let wa = self.index_tile(a.clone(), None)? & !0x1C00; - let wb = self.index_tile(b.clone(), None)? & !0x1C00; + let wa = self.index_tile(a.clone(), None)? & 0x1C00; + let wb = self.index_tile(b.clone(), None)? & 0x1C00; let x = a.coords.0 as isize - self.area_offset_x[area_idx]; let y = a.coords.1 as isize - self.area_offset_y[area_idx]; let dest = 0x3000 + xy_to_map_offset(x, y) / 2; From d2aa19a716bcb2f9a75c573698e9ba55fc11d650 Mon Sep 17 00:00:00 2001 From: nn <53490794+nn357@users.noreply.github.com> Date: Sat, 17 Oct 2026 16:39:52 +0900 Subject: [PATCH 10/21] more palette stuff --- patches/rom_map/Bank DF.txt | 4 +-- patches/src/animated_map_tiles.asm | 41 ++++++++++++++++++++++------ rust/maprando/src/patch/map_tiles.rs | 16 ++++++----- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/patches/rom_map/Bank DF.txt b/patches/rom_map/Bank DF.txt index 23e6b3f16..61835cca8 100644 --- a/patches/rom_map/Bank DF.txt +++ b/patches/rom_map/Bank DF.txt @@ -2,8 +2,8 @@ D4DF - D761: ; credits.asm D91B - DF0A: ; credits.asm E000 - E127: ; credits.asm E200 - E212: ; alternate_door_colors.asm -E212 - E3A4: ; animated_map_tiles.asm -E3A4 - FEF0: [free] +E212 - E37D: ; animated_map_tiles.asm +E37D - FEF0: [free] FEF0 - FEFF: seed name (null-terminated ASCII string) FF00 - FF03: display seed / internal seed hash FF04 - FF04: [free] diff --git a/patches/src/animated_map_tiles.asm b/patches/src/animated_map_tiles.asm index 572b7f160..8ccd5af9b 100644 --- a/patches/src/animated_map_tiles.asm +++ b/patches/src/animated_map_tiles.asm @@ -47,6 +47,9 @@ DoubleItemTable: RowBitMasks: dw $0001, $0002, $0004, $0008, $0010, $0020 + +VisitedRowMasks: + dw $0101, $0202, $0404, $0808, $1010, $2020 BuildAnimateBitMask: @@ -72,29 +75,40 @@ BuildAnimateBitMask: cmp !current_area bne .next_entry + lda.w DoubleItemTable+8,y + tax + lda $7ed870,x + and.w DoubleItemTable+10,y + bne .next_entry + lda.w DoubleItemTable+2,y sec sbc #$3000 asl tax - lda $7e4000,x cmp.w DoubleItemTable+4,y + beq .revealed + cmp.w DoubleItemTable+12,y bne .next_entry - lda.w DoubleItemTable+8,y + tya + lsr + lsr + lsr tax - lda $7ed870,x - and.w DoubleItemTable+10,y - bne .next_entry + lda.w VisitedRowMasks,x + bra .set_mask +.revealed tya lsr lsr lsr tax - lda.w RowBitMasks,x + +.set_mask ora !animate_mask sta !animate_mask @@ -105,7 +119,7 @@ BuildAnimateBitMask: tay cpy #$0060 bne .loop - + ; cleanup ply plx @@ -167,11 +181,20 @@ AnimateTile: lda #$0002 sta $7e00d0,x ; size + lda $01,s + and #$0080 + lsr + lsr + lsr + lsr + clc + adc !tile_state + sta $7e00d2,x tya clc adc #DoubleItemTable+4 - adc !tile_state - sta $7e00d2,x ; source = tile_a or tile_b + adc $7e00d2,x + sta $7e00d2,x ; source = tile_a or tile_b, revealed or visited lda #$00DF sta $7e00d4,x ; bank (dest write below overwrites the stray high byte) lda DoubleItemTable+2,y diff --git a/rust/maprando/src/patch/map_tiles.rs b/rust/maprando/src/patch/map_tiles.rs index 7f995128f..523696199 100644 --- a/rust/maprando/src/patch/map_tiles.rs +++ b/rust/maprando/src/patch/map_tiles.rs @@ -2700,27 +2700,29 @@ impl<'a> MapPatcher<'a> { if a.coords != b.coords { continue; } - let wa = self.index_tile(a.clone(), None)? & 0x1C00; - let wb = self.index_tile(b.clone(), None)? & 0x1C00; + let wa = self.index_tile(a.clone(), None)? | 0x1C00; + let wb = self.index_tile(b.clone(), None)? | 0x1C00; + let wa2 = (wa & !0x1C00) | 0x0800; + let wb2 = (wb & !0x1C00) | 0x0800; let x = a.coords.0 as isize - self.area_offset_x[area_idx]; let y = a.coords.1 as isize - self.area_offset_y[area_idx]; let dest = 0x3000 + xy_to_map_offset(x, y) / 2; - let tile_a = if wa == wb { 0xFFFF } else { wb }; + let same = wa == wb; doubles.push([ area_idx as u16, dest as u16, - tile_a, + if same { 0xFFFF } else { wb }, wa, (item_a / 8) as u16, 1u16 << (item_a % 8), - 0, - 0, + if same { 0xFFFF } else { wb2 }, + wa2, ]); } } } assert!(doubles.len() <= 6); - doubles.resize(6, [0xFFFF, 0, 0xFFFF, 0, 0, 0, 0, 0]); + doubles.resize(6, [0xFFFF, 0, 0xFFFF, 0, 0, 0, 0xFFFF, 0]); for (i, e) in doubles.iter().enumerate() { for (j, &w) in e.iter().enumerate() { self.rom From ad8a20bf20a6cdf5c693767a733569817dfe0969 Mon Sep 17 00:00:00 2001 From: nn <53490794+nn357@users.noreply.github.com> Date: Sat, 17 Oct 2026 17:08:28 +0900 Subject: [PATCH 11/21] update bank notes update bank useage notes. --- patches/rom_map/Bank DF.txt | 4 ++-- patches/src/animated_map_tiles.asm | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/patches/rom_map/Bank DF.txt b/patches/rom_map/Bank DF.txt index 61835cca8..d5f022047 100644 --- a/patches/rom_map/Bank DF.txt +++ b/patches/rom_map/Bank DF.txt @@ -2,8 +2,8 @@ D4DF - D761: ; credits.asm D91B - DF0A: ; credits.asm E000 - E127: ; credits.asm E200 - E212: ; alternate_door_colors.asm -E212 - E37D: ; animated_map_tiles.asm -E37D - FEF0: [free] +E212 - E3AA: ; animated_map_tiles.asm +E3AA - FEF0: [free] FEF0 - FEFF: seed name (null-terminated ASCII string) FF00 - FF03: display seed / internal seed hash FF04 - FF04: [free] diff --git a/patches/src/animated_map_tiles.asm b/patches/src/animated_map_tiles.asm index 8ccd5af9b..bbe1dfa82 100644 --- a/patches/src/animated_map_tiles.asm +++ b/patches/src/animated_map_tiles.asm @@ -5,7 +5,7 @@ lorom arch 65816 !bank_df_free_space_start = $dfe212 ; values in this table are overwritten in patch.rs -!bank_df_free_space_end = $dffeef +!bank_df_free_space_end = $dffe3af !tile_timer = $7e09ee !tile_state = $7e09a0 @@ -195,7 +195,7 @@ AnimateTile: adc #DoubleItemTable+4 adc $7e00d2,x sta $7e00d2,x ; source = tile_a or tile_b, revealed or visited - lda #$00DF + lda #$00df sta $7e00d4,x ; bank (dest write below overwrites the stray high byte) lda DoubleItemTable+2,y sta $7e00d5,x ; VRAM dest @@ -225,7 +225,4 @@ AnimateTile: sta $0763 rtl - - print pc - - assert pc() <= !bank_df_free_space_end \ No newline at end of file +assert pc() <= !bank_df_free_space_end \ No newline at end of file From e0fe4b3dc4b9eb63a0de5c0d9bd9635fe9a5d17b Mon Sep 17 00:00:00 2001 From: nn <53490794+nn357@users.noreply.github.com> Date: Sat, 17 Oct 2026 19:09:00 +0900 Subject: [PATCH 12/21] cleanup ram locations and update notes / ram map --- patches/rom_map/RAM.txt | 3 ++- patches/src/animated_map_tiles.asm | 40 ++++++++++++++++++------------ 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/patches/rom_map/RAM.txt b/patches/rom_map/RAM.txt index 43f496c4e..6a1ad7731 100644 --- a/patches/rom_map/RAM.txt +++ b/patches/rom_map/RAM.txt @@ -48,7 +48,8 @@ $7EF597-$7EF599: split_speed.asm $7EF59A-$7EF59C: reserve_backward_fill.asm $7EF59C-$7EF59E: crash_handle_xmode.asm $7EF59E-$7EF5A0: trimmed_fanfare.asm -$7EF5A0-$7EFE00: [FREE] +$7EF5A0-$7EF5A6: animated_map_tiles.asm +$7EF5A6-$7EFE00: [FREE] $7EFE00: map area (copy of $1F5B to be saved to SRAM) $7EFE02: map area explored mask $7EFE04: copy of $1F5D (to be saved to SRAM for escape autosave) diff --git a/patches/src/animated_map_tiles.asm b/patches/src/animated_map_tiles.asm index bbe1dfa82..97964a0be 100644 --- a/patches/src/animated_map_tiles.asm +++ b/patches/src/animated_map_tiles.asm @@ -4,16 +4,16 @@ lorom arch 65816 -!bank_df_free_space_start = $dfe212 ; values in this table are overwritten in patch.rs +!bank_df_free_space_start = $dfe212 ; this location must match fn write_double_item_table in map_tiles.rs !bank_df_free_space_end = $dffe3af -!tile_timer = $7e09ee -!tile_state = $7e09a0 -!interval = #$0030 +!interval = #$0030 !current_area = $7e1f5b -!animate_mask = $7ef5a0 +!animate_mask = $7ef5a0 +!tile_timer = $7ef5a2 +!tile_state = $7ef5a4 -; Vanilla hooks +;;; Vanilla hooks org $82913B ;;; $9120: Pause menu - index 0: map screen ;;; jsl AnimateTile @@ -22,21 +22,30 @@ org $82913B ;;; $9120: Pause menu - index 0: map screen ;;; org $82941e ;;; ;;; $93C3: Load pause menu map tilemap and area label ;;; jsl BuildAnimateBitMask - nop ;$82:941E C9 07 00 CMP #$0007 ;\ - nop ;$82:9421 30 03 BMI $03 [$9426] ;} If [area index] >= debug: - nop ;$82:9423 A9 00 00 LDA #$0000 ; A = 0 + nop + nop + nop nop -; Custom code +;;; Custom code org !bank_df_free_space_start -; area, vram_dest, tile_a, tile b -; tile_a will be set to FFFF on the server side if both items are of the same type so it is never animated as it will just waste cycles reloading an identical tile. -; table is ordered by area for the 6 double_item rooms, upto 6, if small maps / missing etc table is padded with FFFF to fill this table. +; the contents of this table is modified by fn write_double_item_table in map_tiles.rs +; +; +0 area index [table is generated in area order of the rooms] +; +2 VRAM tilemap dest +; +4 tile_a, the priority tile, revealed (palette 7). $FFFF if both items are the same type, so it never matches and tries to flip a tile to an identical tile +; +6 tile_b, the other item’s tile, revealed (palette 7) +; +8 byte offset of tile_b’s item in the collected-items array at $7ED870 +; +10 bit mask for tile_b’s item within that byte +; +12 tile_a for visited tiles (palette 2). $FFFF if same type +; +14 tile_b for visited tiles (palette 2) -DoubleItemTable: +; Padding: unused entries are $FFFF, $0000, $FFFF, $0000, $0000, $0000, $FFFF, $0000. + +DoubleItemTable: dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ; Billy Mays dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ; West Sand Pit dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ; Watering Hole @@ -44,6 +53,7 @@ DoubleItemTable: dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ; Green Brinstar Reserve dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ; Norfair Reserve +; Mask layout: !animate_mask uses bit n for “animate entry n” and bit n+8 for “entry n is visited” (VisitedRowMasks). RowBitMasks: dw $0001, $0002, $0004, $0008, $0010, $0020 @@ -53,7 +63,6 @@ VisitedRowMasks: BuildAnimateBitMask: - ; entry phb php rep #$30 @@ -120,7 +129,6 @@ BuildAnimateBitMask: cpy #$0060 bne .loop - ; cleanup ply plx pla From 7269634d24ac6c5da875e1f08d4191ceedbdb8c2 Mon Sep 17 00:00:00 2001 From: nn <53490794+nn357@users.noreply.github.com> Date: Sun, 18 Oct 2026 00:51:24 +0900 Subject: [PATCH 13/21] include up to date ips --- patches/ips/animated_map_tiles.ips | Bin 377 -> 445 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/patches/ips/animated_map_tiles.ips b/patches/ips/animated_map_tiles.ips index 6e7e52bd30e9c73384a98f4ee877cc1f3dc8d4f4..2bb64b9a96d961cf1e7a5a488b4d8c187c6beaa9 100644 GIT binary patch literal 445 zcmWG=3~}~g6trewQ(}F5|J5r-5jh49rLIRn=BrowkAxU!FwhtDFx)Bf$l@h~0oSVi3=VZS#U6d&zbW_Vg47HzFRxX5>mD_5Kv+eO_<^Q? zOqwB)DZsGeKmx;sbydGIG*+KvXE0y}+LjHpc|FiZsgni_8+br=YXC)ili9OxMRmj7 zvmWRkPbLPCv(^I*`;g)RblG|X=DJmj8NHerCpg1gX|aKpE(HX0&e!<-0>hA^s D_Cb)i literal 377 zcmWG=3~}~g6trewQ(FJ%{;OAvB618IN`4^bt5^Dugcw5@NCb=wObjdx91H>s3Jl#G zhYUP!MR~7Y$-vP6jIP%TLP42et*h7|`47%rTs`jw%v`XoDp0W;9dY@qq;f#yn`G+@}k z1F}H_DB7FMo_#B-8*b}*psk)v3?R$b0}cC7<^i;Sy#aIGs>O_6&5RR5VQ%rch3Xgv z84r-&3#>cE9yKuUlz7C Date: Sun, 18 Oct 2026 01:32:46 +0900 Subject: [PATCH 14/21] formatting >.< --- rust/maprando/src/patch.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/maprando/src/patch.rs b/rust/maprando/src/patch.rs index fc83f0ed2..034fab69d 100644 --- a/rust/maprando/src/patch.rs +++ b/rust/maprando/src/patch.rs @@ -571,16 +571,16 @@ impl Patcher<'_> { patches.push("missile_refill_all"); } + if self.settings.quality_of_life_settings.animated_tiles { + patches.push("animated_map_tiles"); + } + if self.settings.quality_of_life_settings.crash_fixes.preset != Some(CrashFixesPreset::Crash) { patches.push("crash_handle_base"); } - if self.settings.quality_of_life_settings.animated_tiles{ - patches.push("animated_map_tiles"); - } - let fixes = &self.settings.quality_of_life_settings.crash_fixes; if fixes.spring_ball != FixMode::Crash { From f9231c803c74e82a230ec3161fdf3ed2180bc319 Mon Sep 17 00:00:00 2001 From: nn <53490794+nn357@users.noreply.github.com> Date: Sun, 18 Oct 2026 14:08:38 +0900 Subject: [PATCH 15/21] make BT animate between objective tile / item --- patches/ips/animated_map_tiles.ips | Bin 445 -> 465 bytes patches/rom_map/Bank DF.txt | 4 +- patches/src/animated_map_tiles.asm | 11 ++-- .../generate/help/quality/animated_tiles.html | 1 + rust/maprando/src/patch/map_tiles.rs | 48 +++++++++++++++--- 5 files changed, 49 insertions(+), 15 deletions(-) diff --git a/patches/ips/animated_map_tiles.ips b/patches/ips/animated_map_tiles.ips index 2bb64b9a96d961cf1e7a5a488b4d8c187c6beaa9..44ad13d54a09ec921413bfee1f4c3691220fb557 100644 GIT binary patch delta 135 zcmdnXe34lxz%j(xgHh0$flW#B@%>k?7)9h5IF#l+0y1B{(tjkxxMreZ;6w*`8Ab*s z1{MYm1_1^I1_uU4MkXc}77h*p0R;sIhl#WNWF|an;F#g%<+W;W(k?7)9h5IFz~`0hzB}=|2);oH5ZbL4uKiiGhWI zgF%2nfq{{ciHU`UgF`?-L1E%LKbg8m4IDGPyu4QJEqcVi;A>q!5YLdv6ku3!AYrlu g<3fo9h6}5^`VE-tGFDgp(pbsB(3{Mj?dtCa096z#PXGV_ diff --git a/patches/rom_map/Bank DF.txt b/patches/rom_map/Bank DF.txt index d5f022047..285b758b5 100644 --- a/patches/rom_map/Bank DF.txt +++ b/patches/rom_map/Bank DF.txt @@ -2,8 +2,8 @@ D4DF - D761: ; credits.asm D91B - DF0A: ; credits.asm E000 - E127: ; credits.asm E200 - E212: ; alternate_door_colors.asm -E212 - E3AA: ; animated_map_tiles.asm -E3AA - FEF0: [free] +E212 - E3BE: ; animated_map_tiles.asm +E3BE - FEF0: [free] FEF0 - FEFF: seed name (null-terminated ASCII string) FF00 - FF03: display seed / internal seed hash FF04 - FF04: [free] diff --git a/patches/src/animated_map_tiles.asm b/patches/src/animated_map_tiles.asm index 97964a0be..78e533d1f 100644 --- a/patches/src/animated_map_tiles.asm +++ b/patches/src/animated_map_tiles.asm @@ -52,14 +52,15 @@ DoubleItemTable: dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ; Green Pirates Shaft dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ; Green Brinstar Reserve dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ; Norfair Reserve + dw $0000, $0000, $0000, $0000, $0000, $0000, $0000, $0000 ; Bomb Torizo (when it's an objective) ; Mask layout: !animate_mask uses bit n for “animate entry n” and bit n+8 for “entry n is visited” (VisitedRowMasks). RowBitMasks: - dw $0001, $0002, $0004, $0008, $0010, $0020 - + dw $0001, $0002, $0004, $0008, $0010, $0020, $0040 + VisitedRowMasks: - dw $0101, $0202, $0404, $0808, $1010, $2020 + dw $0101, $0202, $0404, $0808, $1010, $2020, $4040 BuildAnimateBitMask: @@ -126,7 +127,7 @@ BuildAnimateBitMask: clc adc #$0010 tay - cpy #$0060 + cpy #$0070 bne .loop ply @@ -217,7 +218,7 @@ AnimateTile: clc adc #$0010 tay - cpy #$0060 + cpy #$0070 bne .loop txa diff --git a/rust/maprando-web/templates/generate/help/quality/animated_tiles.html b/rust/maprando-web/templates/generate/help/quality/animated_tiles.html index 1ef624951..ead20edff 100644 --- a/rust/maprando-web/templates/generate/help/quality/animated_tiles.html +++ b/rust/maprando-web/templates/generate/help/quality/animated_tiles.html @@ -14,6 +14,7 @@

Animated Map Tiles

  • Norfair Reserve
  • Watering Hole
  • West Sand Pit +
  • Bomb Torizo (If it is an objective)