Thursday, June 8, 2017

What are sewers?

The term "sewer" was also coined by GoldS in his legendary Sonic 3 and Knuckles Glitches and Oversights series, and refers to the area below the level where the normal layout ends, and insanity ensues.


The reason why this happens is that, much like before, the developers didn't set the vertical size for levels they thought you would never get to the bottom of, leaving it at the default value of $1000 pixels. But what exactly is down there?

First, you might've noticed I left something out when I talked about loopbacks being shifted up from the actual level:


So what's in that little corner, past the actual level and underneath the loopback? Well, turns out that after the layout for Plane A comes the layout for Plane B, so if you go down there, you can see background chunks in the foreground layer and get a different perspective on the background tile replacement trick.


If you go below this area, though, you'll find the same pattern repeating over and over. It repeats because it's reading the same row of chunks over and over, and that brings me to the other thing I glossed over in the last post: how does the game "know" where each row is supposed to start?

Sonic Retro wiki gives us the answer. Before the actual chunk data, the layout contains 64 word-sized pointers which don't make much sense inside the ROM, but when the layout is copied to RAM address $8000, they become pointers to the start of each chunk row in RAM, alternating between foreground and background rows:
 00 70  00 04  00 18  00 08  80 88  8B 08  80 F8  8B 0C 
 81 68  8B 10  81 D8  8B 14  82 48  8B 18  82 B8  8B 1C 
 83 28  8B 20  83 98  8B 24  84 08  00 00  84 78  00 00 
 84 E8  00 00  85 58  00 00  85 C8  00 00  86 38  00 00  
 86 A8  00 00  87 18  00 00  87 88  00 00  87 F8  00 00 
 88 68  00 00  88 D8  00 00  89 48  00 00  89 B8  00 00 
 8A 28  00 00  8A 98  00 00  00 00  00 00  00 00  00 00 
 00 00  00 00  00 00  00 00  00 00  00 00  00 00  00 00 
 00 00  00 00  00 00  00 00  B4 26  00 00  38 38  00 00

        Foreground rows             Background rows  
After a while, the pointers peter out and are all left at zero, which accounts for the repeating chunk rows in the sewers. But what is a zeroed pointer pointing at?

A naïve answer would be to say that since these are RAM pointers, and RAM address $0000 stores chunk definitions, the sewer rows are paradoxically reading chunk definitions as a chunk layout. In reality, though, when the pointers are loaded to an address register, they get sign-extended to 32-bit addresses. Because the pointers are normally $8000-based, they get sign-extended to address $FFFF8000, which maps to 68000 RAM. The zeroed pointers however, are sign-extended to address $00000000, which ends up mapping to the beginning of the ROM!

That means when you're in the sewers, what you're looking at, and possibly even walking and jumping on, is actually the 68000 vector table at the start of the ROM.
Vectors:    dc.l    $00000000,      EntryPoint,     ErrorTrap,      ErrorTrap       ; 0
            dc.l    ErrorTrap,      ErrorTrap,      ErrorTrap,      ErrorTrap       ; 4
            dc.l    ErrorTrap,      ErrorTrap,      ErrorTrap,      ErrorTrap       ; 8
            dc.l    ErrorTrap,      ErrorTrap,      ErrorTrap,      ErrorTrap       ; 12
            dc.l    ErrorTrap,      ErrorTrap,      ErrorTrap,      ErrorTrap       ; 16
            dc.l    ErrorTrap,      ErrorTrap,      ErrorTrap,      ErrorTrap       ; 20
            dc.l    ErrorTrap,      ErrorTrap,      ErrorTrap,      ErrorTrap       ; 24
            dc.l    H_int_jump,     ErrorTrap,      V_int_jump,     ErrorTrap       ; 28
            dc.l    ErrorTrap,      ErrorTrap,      ErrorTrap,      ErrorTrap       ; 32
            dc.l    ErrorTrap,      ErrorTrap,      ErrorTrap,      ErrorTrap       ; 36
            dc.l    ErrorTrap,      ErrorTrap,      ErrorTrap,      ErrorTrap       ; 40
            dc.l    ErrorTrap,      ErrorTrap,      ErrorTrap,      ErrorTrap       ; 44
            dc.l    ErrorTrap,      ErrorTrap,      ErrorTrap,      ErrorTrap       ; 48
            dc.l    ErrorTrap,      ErrorTrap,      ErrorTrap,      ErrorTrap       ; 52
            dc.l    ErrorTrap,      ErrorTrap,      ErrorTrap,      ErrorTrap       ; 56
            dc.l    ErrorTrap,      ErrorTrap,      ErrorTrap,      ErrorTrap       ; 60

5 comments:

  1. Should I assume this has something to do with the game crashing or behaving erratically when the camera points at very high X positions? (ie: S3 MGZ Miniboss Crash; the LRZ "MegaGlitch")

    ReplyDelete
    Replies
    1. No, there's nothing "unstable" about sewers or loopbacks; the game is just interpreting random data as a level layout.

      I'm not sure exactly what causes the MGZ1->MGZ2 crash, but I can hazard a guess. Might be fun to look into that, actually!

      Delete
  2. Huh. I wonder then what is that exactly causes a crash there.
    Aside from using glitches to get the camera X position high enough, using a PAR code to disable the boundaries and getting to about X 0xA000 IIRC causes palette glitches or crashes, and even when objects aren't processed, going even further eventually crashes the game.

    Though, strangely, even if the camera doesn't follow Sonic, wrapping around the level in debug mode has a chance to crash or jump to Blue Spheres at certain points (ie: Sandopolis Act 1)
    What is going on there?

    ReplyDelete
  3. Great article, it is necessary to clean the sewers, and this company شركة تسليك مجاري بالرياض helped me with that

    ReplyDelete