Super Mario Brothers Sprite 0

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

Post Reply
etansivad
Posts: 1
Joined: Thu Nov 01, 2018 7:25 pm

Super Mario Brothers Sprite 0

Post by etansivad » Thu Nov 01, 2018 7:37 pm

I'm trying to better understand how the sprite 0 hits are handled in SMB (And, really, all early NES titles that use it for mid screen splits). Mostly out of curiosity and hacking in general.

I poked around the SMB disassembly: https://gist.github.com/1wErt3r/4048722 (I should also point out that I only understand the basic concepts of assembly -- I'm a DB engineer by trade...)
And found the byte data for sprite 0 is $18, $ff, $23, $58
Sniffing the memory I can see that data at 0x001200 and I can edit it (Using the emulator fceux). I wanted to see what it would do to the screen if it scrolled midscreen or at the top.
Why? Dunno, just like hacking. If I set the value to something like 66 for the first byte, it will move sprite 0 down to the middle of the screen and split it in half. But it then crashes the game once you scroll too far forward. Also, certain values just cause it to crash instantly.

My questions are (And I apologize if these are too basic), what is causing it to crash sporadically? Any other fun things I can do with hacking sprite 0 in early games?

Thank you for your time.

tepples
Posts: 21755
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Super Mario Brothers Sprite 0

Post by tepples » Thu Nov 01, 2018 8:06 pm

The program determines that sprite 0 has been drawn by reading the sprite 0 hit flag (bit 6 of a memory-mapped I/O register at $2002).

Code: Select all

  ; 1. wait for 0 (which happens at end of vblank)
@wait_s0_clear:
  bit $2002  ; copy bit 6 into V flag
  bvs @wait_s0_clear

  ; 1. wait for 1 (when sprite 0 pixel overlaps opaque BG pixel)
@wait_s0_set:
  bit $2002  ; copy bit 6 into V flag
  bvc @wait_s0_set
But when sprite 0 doesn't overlap an opaque part of the background, that bit never becomes true, leaving the CPU in an infinite loop at @wait_s0_set.

It's possible to make a sprite 0 reading routine that is more tolerant of errors, but early games didn't bother. The following routine also allows vblank to end the loop. This will produce a graphical glitch instead of freezing.

Code: Select all

  ; 1. wait for 0 (which happens at end of vblank)
@wait_s0_clear:
  bit $2002  ; copy bit 6 into V flag
  bvs @wait_s0_clear

  ; 2. wait for either sprite 0 or vblank flag to become 1
  lda #$C0  ; bit 7: vblank; bit 6: sprite 0
@wait_s0_set:
  bit $2002  ; copy !(A & [$2002]) into Z flag
  beq @wait_s0_set
  bmi @vblank_hit_instead

User avatar
tokumaru
Posts: 11469
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: Super Mario Brothers Sprite 0

Post by tokumaru » Thu Nov 01, 2018 8:59 pm

A sprite zero hit only happens when an opaque pixel in sprite 0 overlaps an opaque pixel in the background. SMB is full of transparent background areas (e.g. the sky), and if the sprite ends up in one of those areas, the game locks up waiting for a sprite 0 hit that never happens.

User avatar
bazza
Posts: 89
Joined: Fri Nov 24, 2017 1:36 pm
Location: Argentina
Contact:

Supermario picasso

Post by bazza » Mon Jan 28, 2019 6:13 pm

I synth charts of mario and join to the assembled (dissambled mario)
mpv-shot0004.jpg
Attachments
smb-picasso.ips
IPS of "Super Mario Bros (JU) (PRG 0).nes"
(7.3 KiB) Downloaded 109 times

Post Reply