User Tools

Site Tools

“Respect.”

return_of_samus:technical_information:screen_transitions

Screen Transitions

 MII Samus Here we shall discuss how to dissect these pesky screen transitions, hopefully once and for all. It is advised that you first read the page on Level Data Banks before continuing on.

Now, as discussed on the previously linked page, every screen has a screen transition index assigned to it. The index refers to a pointer table that starts at 0x142E5 in the ROM. These pointers point to scripts that define the transition's behavior. The scripting “language” used in these transitions will be described below.

The Language

Once the game identifies the script to use, it copies it to $D700 in RAM (which is the easiest place to inspect how they work). From there, it interprets the script byte by byte in a big loop.

First it checks if it has reached the terminating operator ($FF), and exits if that's the case. After that, it masks the right nybble of the current byte (e.g. $B2 becomes $B0), and then goes through the low-level equivalent of a switch statement (or rather, a bunch of if-else statements) to find the routine that matches the operator. After processing the operator's operands, the interpreter loops back to the beginning, where it processes the next operand.

Scripts are limited to 64 (0x40) bytes in length, but you'll literally never hit that limit.

(Note that all 16-bit values (pointers, etc.) are assumed to be little-endian, as usual.)

FF - Terminating Operator

Self-explanatory.

0* - VRAM/data Block Transfer

Copies a block of data starting at a specified bank and address to somewhere in RAM.

Cases:

  • 01 bb ssss dddd llll - Saves bb:ssss as the source of a BG tileset (necessary for saving properly)
  • 02 bb ssss dddd llll - Saves ssss as the source of a sprite tileset (necessary for saving properly)
  • 0* bb ssss dddd llll - Just copies the data.

Operands:

  • b - source bank
  • s - source pointer
  • d - destination pointer
  • l - length (in bytes)

This doesn't seem to be used that often, probably because it's so verbose. The B* operator is typically used instead for loading sprite and background graphics.

1x - Select metatile table

Copies the desired metatile table to $DA00-$DBFF in WRAM.

The metatile table pointer list begins at 0x23F1A in ROM.

For some reason, the pointers are a little out of order.

80 4C (final ruins) should be 3rd
80 4A (inside ruins) should be second
80 48 (bubbles/ruins 3 catacombs) should be first
80 4E (queen room)
80 50 (first/last caves)
80 52 (outside/ship)
94 55 (acid caves down) should be eighth
A8 56 (acid caves up) should be ninth
80 54 (acid caves mid) should be seventh
BC 57 (outside ruins)

2x - Select collision table

Copies the desired collision table to $DC00-$DCFF in WRAM.

The collision table pointer list begins at 0x23EEA in ROM.

3x - Select solidity indexes

Copies the desired solidity indexes to WRAM.

The solidity indexes are stored in a table starting at 0x23EFA. Each entry row is four bytes wide, though only three are used.

The bytes are copied to these locations:

  • $D056 & $D812 - Samus' solidity index
  • $D056 & $D813 - Enemy solidity index
  • $D08A & $D814 - Projectile solidity index

Basically, for Samus, the way it works is that if an 8×8 tile is less than the specified index, then it is treated as a solid. It works the same for enemies and projectiles as well.

4* - Warp

Warps Samus to the specified map and screen.

Form: 4byx

Operands:

  • b - map bank
  • y - y-screen
  • x - x-screen

Note: Place the x/y coordinate one screen “behind” the desired destination.

5* - Retreat from Last Boss

This opcode is used only once, when Samus retreats from the last boss fight by falling through the hole in the floor. It performs several tasks:

  1. Disable LCD interrupt, ending special last boss hblank handling
  2. Move Samus to ($78, $D7)
  3. Set the screen position to ($80, $C0)
  4. Reload the status bar into the window after the last boss had used the window for the last boss head
  5. Flag the screen for a complete update

6* - Change acid & spike damage

Form: 6* xx yy

Operands:

  • xx - acid damage
  • yy - spike damage

I'm not sure if this is ever used, but it's cool at least.

For reference, the default starting values are $02 and $08.

7* - Exit Room After Last Boss Death

This opcode is used only once, when leaving the last boss room after defeating her. It performs the following:

  1. Disable last boss flag (sets $D08B to 0)
  2. Resets the window position to (0, $88) (sets $FF4A and $FF4B to $88 and 7, respectively)
  3. Disables LCD interrupt from last boss fight
  4. Reloads the status bar into the window

8* - Transition to the Queen Fight

Handles a lot of special stuff regarding the queen fight, but not everything.

Form: 8a bbbb cccc dddd eeee

  • a: Bank for current room ($F)
  • b: Scroll Y position ($F48)
  • c: Scroll X position ($EAE)
  • d: Samus Y position ($F02)
  • e: Samus X position ($EDE)

9* - Conditional Operator

Form: 9* nn xxxx

Operands:

  • nn - Number of Metroids
  • xxxx - Transition index

“If the amount of Metroids remaining is less than or equal 'nn', then jump to and do transition 'xxxx' instead.”

This is how the game handles lowering (and raising) acid levels. Keep in mind that earthquakes are handled elsewhere.

Note that this uses the real Metroid counter (memory address $D089), which also accounts for the Metroids in the endgame. Also keep in mind that this value is in binary coded decimal.

A* - Fadeout

When changing tileset, this is typically the first operator in the script.

B* - Load Graphics Page

Forms:

  1. B1 bb xxxx - Load BG graphics page (128 tiles) to $9000 in VRAM.
  2. B2 bb xxxx - Load Sprite graphics page (64 tiles) to $8B00 in VRAM.

Operators:

  • bb - source bank
  • xxxx - source pointer

Cx - Change Music

0 - No change in music.
    - Silences the roar from "song" A below
1 - "The Last Metroid"
2 - Queen Fight
3 - Inside Ruins
4 - Main Tunnels
5 - Ambience 1
6 - Ambience 2
7 - Ambience 3 (bugs)
8 - Omega Metroid Area
9 - Final Ruins
A - No music: SFX - Metroid Queen roar (persists)
B - Final Alarm
C - Metroid Fight
D - Ambience 4
E - SFX: Earthquake
F - Metroid Defeated

Dx - Load Message/Special Graphics

This loads the graphics for the orb, the desired item, the item font (well, up to the number 2), and the corresponding text string to VRAM.

0 - Save ... (just for the message)
1 - Plasma Beam
2 - Ice Beam
3 - Wave Beam
4 - Spazer
5 - Bombs
6 - Screw Attack
7 - Varia Suit
8 - High Jump Boots
9 - Space Jump
A - Spider Ball
B - Spring Ball
C - Energy Tank (unused)
D - Missile Tank (unused)
E - Energy (i.e. refill; again, unused)
F - Missiles (i.e. refill; unused)

Note that, for the last 4 items, their sprites are always in VRAM, and they don't cause text strings to appear, so this is unnecessary for them.

Invalid Operators

The game does not account for operators in the form of E* or F*. Using these will cause the game to freeze, because the interpreter will get stuck in an infinite loop. However, an intrepid hacker could use these to extend this language to do other radical things.

Example 1

This the transition from the save room in the first ruins to the exterior area:

A0 B1 08 BC 69 26 36 19 B2 06 20 5D C5 49 E7 FF

Let's make this easier to read:

A0
B1 08 BC 69 
26 
36 
19 
B2 06 20 5D 
C5 
49 E7 
FF

Hypothetically, we could convert this into some sort of mnemonic or macro-based form (like assembly):

FADE
GFX_BG    08:69BC 
COLLISION 6 
SOLID     6 
METATILE  9 
GFX_SPR   06:5D20 
SONG      5 
WARP      9,E,7 
END

But that would be just silly.

(Someone please do this.)

Example 2

Here's the transition to the first cave with acid.

A0 B1 07 00 68 25 35 B2 06 20 61 4B 0C 90 46 E1 01 18 FF

For reference, this is the transition script referred to in the conditional operator it uses.

16 FF

Deciphering this will be left as an exercise for the reader.

return_of_samus/technical_information/screen_transitions.txt · Last modified: 2018/12/27 03:28 by quantam