diff --git a/patches/ips/escape.ips b/patches/ips/escape.ips index 14c924830..f80451da6 100644 Binary files a/patches/ips/escape.ips and b/patches/ips/escape.ips differ diff --git a/patches/ips/escape_items.ips b/patches/ips/escape_items.ips index 0c1a28af8..0c832380f 100644 Binary files a/patches/ips/escape_items.ips and b/patches/ips/escape_items.ips differ diff --git a/patches/ips/item_count.ips b/patches/ips/item_count.ips new file mode 100644 index 000000000..00911fa38 Binary files /dev/null and b/patches/ips/item_count.ips differ diff --git a/patches/ips/new_game.ips b/patches/ips/new_game.ips index 5328994b3..8cb3a2425 100644 Binary files a/patches/ips/new_game.ips and b/patches/ips/new_game.ips differ diff --git a/patches/rom_map/Bank 8B.txt b/patches/rom_map/Bank 8B.txt index 356d55b11..335df27b5 100644 --- a/patches/rom_map/Bank 8B.txt +++ b/patches/rom_map/Bank 8B.txt @@ -1,3 +1,4 @@ F760 - F769: ; escape_items.asm F770 - F893: ; credits.asm F900 - F91B: ; escape.asm +F91B - FB06: ; item_count.asm \ No newline at end of file diff --git a/patches/rom_map/Bank B5.txt b/patches/rom_map/Bank B5.txt index 7466a087e..09881a741 100644 --- a/patches/rom_map/Bank B5.txt +++ b/patches/rom_map/Bank B5.txt @@ -8,7 +8,7 @@ FE06 - FE07: Initial items equipped (to be copied to $09A2) FE08 - FE09: Initial beams collected (to be copied to $09A8) FE0A - FE0B: Initial beams equipped (to be copied to $09A6) FE0C - FE11: Initial boss bits (to be copied to $7ED828-2E) -FE12 - FE51: Initial item bits (to be copied to $7ED870-B0) +FE12 - FE51: Initial item bits (to be copied to $7ED870-B0); [new_game.asm, item_count.asm] FE52 - FE53: Initial energy (to be copied to $09C2) FE54 - FE55: Initial max energy (to be copied to $09C4) FE56 - FE57: Initial reserves (to be copied to $09D6) diff --git a/patches/rom_map/Bank DF.txt b/patches/rom_map/Bank DF.txt index e4411ab9c..270a1b95f 100644 --- a/patches/rom_map/Bank DF.txt +++ b/patches/rom_map/Bank DF.txt @@ -5,10 +5,11 @@ E200 - E212: ; alternate_door_colors.asm E212 - FEEF: [free] FEF0 - FEFF: seed name (null-terminated ASCII string) FF00 - FF03: display seed / internal seed hash -FF04 - FF04: [FREE] +FF04 - FF04: [free] FF05 - FF06: randomizer settings: - bitmask $0001: walljump-boots item enabled - bitmask $0002: split speedbooster item enabled FF07 - FF08: number of frames of artificial lag to add to the unpause black screen FF09 - FF0D: randomizer settings: skill/progression/qol/objectives/maplayout (autotracker use) - stored as single byte ordinal numbers, if a setting has a custom option then byte is set to 0 +FF0E - FF0F: sum of unplaced / nothing items (used for item credits fractional display with stop item placement early) diff --git a/patches/rom_map/RAM.txt b/patches/rom_map/RAM.txt index 97a1939d0..43f496c4e 100644 --- a/patches/rom_map/RAM.txt +++ b/patches/rom_map/RAM.txt @@ -4,8 +4,7 @@ $CF: vanilla_bugfixes.asm (used by crash dialogues to prevent unpause from reset $09EC: number of disabled ETanks (saved to SRAM) $0A1A: previous reserve health (reserve_hud.asm) $1F5B: map area (like $079F) -$1F5D: items collected before getting them all for free at hyper beam (to use in "rate for collecting items" - after credits). This is a snapshot of $09A4, captured in `escape.asm`, at the time of getting hyper beam. +$1F5D: [free]. $1F60: fast_reload.asm $1F62: map area backup in pause menu (like $079F) $1F64: escape refill complete diff --git a/patches/src/escape.asm b/patches/src/escape.asm index e195f1974..4e5a0d152 100644 --- a/patches/src/escape.asm +++ b/patches/src/escape.asm @@ -650,17 +650,17 @@ assert pc() <= !bank_a7_free_space_end ; Include walljump boots and split-speed in item collection count post-credits -org $8BE65B - LDX #$001A +;org $8BE65B +; LDX #$001A -org $8BE661 - BIT item_bits,x +;org $8BE661 + ; BIT item_bits,x -org !bank_8b_free_space_start -item_bits: - dw $0001, $0020, $0004, $1000, $0002, $0008, $0100, $0200, $2000, $4000, $8000, $0400, $0040, $0080 +;org !bank_8b_free_space_start +;item_bits: +; dw $0001, $0020, $0004, $1000, $0002, $0008, $0100, $0200, $2000, $4000, $8000, $0400, $0040, $0080 -assert pc() <= !bank_8b_free_space_end +;assert pc() <= !bank_8b_free_space_end org $82E026 jsr enemy_gfx_load_hook diff --git a/patches/src/escape_items.asm b/patches/src/escape_items.asm index 75ea62033..2f82244a0 100644 --- a/patches/src/escape_items.asm +++ b/patches/src/escape_items.asm @@ -6,8 +6,8 @@ org $A9CD12 org $A9FB70 get_hyper_beam: jsl $91E4AD ; run the hi-jacked instruction - lda $09A4 - sta $1F5D ; take a snapshot of items collected, to use in "rate for collecting items" percentage after credits. + ; lda $09A4 + ; sta $1F5D ; take a snapshot of items collected, to use in "rate for collecting items" percentage after credits. lda #$F72F sta $09A2 ; all items equipped (including WallJump = $0400) sta $09A4 ; all items collected @@ -20,43 +20,43 @@ get_hyper_beam: jsl $809A3E ; Add x-ray to HUD tilemap rtl -warnpc $A9FC00 +assert pc() <= $A9FC00 ; hi-jack item percentage count -org $8BE62F - jsr fix_item_percent +;org $8BE62F +; jsr fix_item_percent ; free space in bank $8B -org $8BF760 -fix_item_percent: +;org $8BF760 +;fix_item_percent: ; restore snapshot of items collected to their state before getting them all with hyper beam (except that ; any items collected during the escape also count). - lda $1F5D - sta $09A4 + ;lda $1F5D + ;sta $09A4 - ldx #$0008 ; run hi-jacked instruction - rts -warnpc $8BF770 + ;ldx #$0008 ; run hi-jacked instruction + ;rts +;warnpc $8BF770 -org $848902 - jsr escape_collect_item +;org $848902 +; jsr escape_collect_item -org $848929 - jsr escape_collect_item +;org $848929 +; jsr escape_collect_item -org $848950 - jsr escape_collect_item +;org $848950 +; jsr escape_collect_item ; free space in bank $84 -org $84F300 -escape_collect_item: - sta $09A4 ; run hi-jacked instruction +;org $84F300 +;escape_collect_item: +; sta $09A4 ; run hi-jacked instruction ; add collected item to snapshot, to count toward item collection percentage ; (this only matters for items collected during escape) - lda $1F5D - ora $0000, y - sta $1F5D +; lda $1F5D +; ora $0000, y +; sta $1F5D - rts -warnpc $84F380 \ No newline at end of file +; rts +;warnpc $84F380 \ No newline at end of file diff --git a/patches/src/item_count.asm b/patches/src/item_count.asm new file mode 100644 index 000000000..4bedec399 --- /dev/null +++ b/patches/src/item_count.asm @@ -0,0 +1,243 @@ +; Sum item bits to calculate collection percent. +; +; credits % is displayed as a fraction if every item isn't placed. +; nn_357 / StagShot + +!bank_8b_free_space_start = $8bf91b +!bank_8b_free_space_end = $8bfb06 +!nothing_item_total = $dfff0e ; overwritten by patch.rs, contains the sum of 'nothing' +!initial_item_bits = $b5fe12 ; modified by patch.rs, also used in new_game.asm +!item_count = $12 + +org !nothing_item_total + dw $0000 + +;;; $E627: Instruction - draw item percentage count ;;; + +org $8be627 +itempercent: + php + phb + phk + plb + rep #$30 + phx + phy + jsr countitems + lda !nothing_item_total + bne .fractional + + lda !item_count + and #$00ff + cmp #$0064 + bne .not_100 + + lda $e745 ; 100% completion + sta $7e339c + lda $e747 + sta $7e33dc + lda $e741 + sta $7e339e + lda $e743 + sta $7e33de + lda $e741 + sta $7e33a0 + lda $e743 + sta $7e33e0 + bra .percent_symbol + +.not_100 + ldx #$0002 + jsr .digit2 + bra .percent_symbol + +.fractional + jsr load_fractional_tiles + lda #$0064 + sec + sbc !nothing_item_total + sta $14 + + lda !item_count + and #$00ff + ldx #$0000 + jsr .digit2 + + lda $14 + ldx #$0006 + jsr .digit2 + + lda #$3888 ; add custom '/' tile to tilemap + sta $7e33a0 + lda #$3898 + sta $7e33e0 + bra .finished + +.percent_symbol + lda #$386a + sta $7e33a2 + lda #$387a + sta $7e33e2 +.finished + ply + plx + plb + plp + rts + +.digit2 + sta $4204 + sep #$20 + lda #$0A + sta $4206 + nop #6 + rep #$20 + lda $4214 + asl a + asl a + tay + lda $e741,y + sta $7e339c,x + lda $e743,y + sta $7e33dc,x + lda $4216 + asl a + asl a + tay + lda $e741,y + sta $7e339e,x + lda $e743,y + sta $7e33de,x + rts + +assert pc() <= $8be741 ; Tilemap values for decimal digits: + +org !bank_8b_free_space_start + +countitems: + php + sep #$30 + + lda #$00 + sta !item_count + ldy #$00 + +.loop + ldx offsettable,y + lda !initial_item_bits,x + eor #$ff + and $7ed870,x + and masktable,y + tax + lda bitcounttable,x + clc + adc !item_count + sta !item_count + + iny + cpy #$0f + bne .loop + + plp + rts + +load_fractional_tiles: + php + sep #$30 +WaitVB: + lda $4212 + and #$80 + beq WaitVB + + lda #$80 ; top_slash → $4880 + sta $2115 + lda #$80 + sta $2116 + lda #$48 + sta $2117 + + lda #$01 + sta $4300 + lda #$18 + sta $4301 + lda.b #top_slash + sta $4302 + lda.b #top_slash>>8 + sta $4303 + lda #$8b + sta $4304 + lda #$20 + sta $4305 + stz $4306 + lda #$01 + sta $420B + + lda #$80 ; bottom_slash → $4980 + sta $2116 + lda #$49 + sta $2117 + + lda.b #bottom_slash + sta $4302 + lda.b #bottom_slash>>8 + sta $4303 + lda #$20 + sta $4305 + stz $4306 + lda #$01 + sta $420B + + plp + rts + +top_slash: + db $00, $07, $02, $0D, $06, $09, $06, $09 + db $0C, $13, $0C, $32, $18, $26, $18, $24 + db $00, $00, $00, $00, $00, $00, $00, $00 + db $00, $00, $00, $00, $00, $00, $00, $00 + +bottom_slash: + db $18, $64, $30, $4C, $30, $C8, $60, $98 + db $60, $90, $40, $B0, $00, $E0, $00, $00 + db $00, $00, $00, $00, $00, $00, $00, $00 + db $00, $00, $00, $00, $00, $00, $00, $00 + +offsettable: + db $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$10,$11,$12,$13 + +masktable: ; collected item bits + db %11111111 ; $00 - all + db %11111111 ; $01 - all + db %11101111 ; $02 - not bit 4 + db %11111111 ; $03 - all + db %11111110 ; $04 - not bit 0 + db %00011111 ; $05 - not bits 5,6,7 + db %11111111 ; $06 - all + db %11111111 ; $07 - all + db %11011111 ; $08 - no bit 5 + db %11111110 ; $09 - not bit 0 + db %00000001 ; $0A - only bit 0 + db %11111111 ; $10 - all + db %11111111 ; $11 - all + db %11111111 ; $12 - all + db %00000101 ; $13 - only bits 0 and 2 + +bitcounttable: + db $00,$01,$01,$02,$01,$02,$02,$03,$01,$02,$02,$03,$02,$03,$03,$04 + db $01,$02,$02,$03,$02,$03,$03,$04,$02,$03,$03,$04,$03,$04,$04,$05 + db $01,$02,$02,$03,$02,$03,$03,$04,$02,$03,$03,$04,$03,$04,$04,$05 + db $02,$03,$03,$04,$03,$04,$04,$05,$03,$04,$04,$05,$04,$05,$05,$06 + db $01,$02,$02,$03,$02,$03,$03,$04,$02,$03,$03,$04,$03,$04,$04,$05 + db $02,$03,$03,$04,$03,$04,$04,$05,$03,$04,$04,$05,$04,$05,$05,$06 + db $02,$03,$03,$04,$03,$04,$04,$05,$03,$04,$04,$05,$04,$05,$05,$06 + db $03,$04,$04,$05,$04,$05,$05,$06,$04,$05,$05,$06,$05,$06,$06,$07 + db $01,$02,$02,$03,$02,$03,$03,$04,$02,$03,$03,$04,$03,$04,$04,$05 + db $02,$03,$03,$04,$03,$04,$04,$05,$03,$04,$04,$05,$04,$05,$05,$06 + db $02,$03,$03,$04,$03,$04,$04,$05,$03,$04,$04,$05,$04,$05,$05,$06 + db $03,$04,$04,$05,$04,$05,$05,$06,$04,$05,$05,$06,$05,$06,$06,$07 + db $02,$03,$03,$04,$03,$04,$04,$05,$03,$04,$04,$05,$04,$05,$05,$06 + db $03,$04,$04,$05,$04,$05,$05,$06,$04,$05,$05,$06,$05,$06,$06,$07 + db $03,$04,$04,$05,$04,$05,$05,$06,$04,$05,$05,$06,$05,$06,$06,$07 + db $04,$05,$05,$06,$05,$06,$06,$07,$05,$06,$06,$07,$06,$07,$07,$08 + +assert pc() <= !bank_8b_free_space_end \ No newline at end of file diff --git a/patches/src/new_game.asm b/patches/src/new_game.asm index 6bc8eefef..546771aeb 100644 --- a/patches/src/new_game.asm +++ b/patches/src/new_game.asm @@ -127,9 +127,6 @@ startup: dex bne .item_bits_loop - ; Set items collected for escape (to make item collection rate show 100%, only applicable for "Escape" start): - lda #$F32F - sta $1F5D ; Unlock Tourian statues room (to avoid camera glitching when entering from bottom, and also to ensure game is ; beatable since we don't take it into account as an obstacle in the item randomization logic) diff --git a/rust/maprando/src/patch.rs b/rust/maprando/src/patch.rs index a05f7ea5f..52e4f4e5e 100644 --- a/rust/maprando/src/patch.rs +++ b/rust/maprando/src/patch.rs @@ -487,6 +487,7 @@ impl Patcher<'_> { "fix_dust_torizo", "fix_choot", "resource_collection_hudcap", + "item_count", ]; patches.push("new_game"); @@ -839,6 +840,7 @@ impl Patcher<'_> { } fn place_items(&mut self) -> Result<()> { + let mut nothing_count: isize = 0; for (&item, &loc) in iter::zip( &self.randomization.item_placement, &self.game_data.item_locations, @@ -848,6 +850,7 @@ impl Patcher<'_> { let new_plm_type = item_to_plm_type(item, orig_plm_type); self.rom.write_u16(item_plm_ptr, new_plm_type)?; if item == Item::Nothing { + nothing_count += 1; let idx = self.rom.read_u16(item_plm_ptr + 4).unwrap() as usize; self.nothing_item_bitmask[idx >> 3] |= 1 << (idx & 7); @@ -859,6 +862,7 @@ impl Patcher<'_> { } } } + self.rom.write_u16(snes2pc(0xdfff0e), nothing_count)?; Ok(()) } @@ -2419,7 +2423,6 @@ impl Patcher<'_> { // Use Tourian load station 2, set up in escape_autosave.asm self.rom.write_u16(initial_area_addr, 5)?; self.rom.write_u16(initial_load_station_addr, 2)?; - // Set all bosses defeated: self.rom.write_n(initial_boss_bits, &[7, 7, 7, 7, 7, 7])?;