Actions

SCHG

Difference between revisions of "Sonic the Hedgehog 2 (16-bit)"

From Sonic Retro

(ROM Hacking: Aurochs is BACK, baby.)
(ROM Hacking: Aurochs provides a better explanation for block and metablock mappings)
Line 428: Line 428:
 
For details of the palette data format, see [[Palette#Megadrive_Palette|Megadrive Palettes]].
 
For details of the palette data format, see [[Palette#Megadrive_Palette|Megadrive Palettes]].
  
====Pattern Load Queues====
+
====Pattern Load Requests====
Not to be confused with animated pattern load queues (which require that the art be uncompressed), pattern load queues tell the game engine where to get Nemesis-compressed art data and where to put it. The format is rather simple, and can be described with this pseudocode:
+
Nemesis named this structure the "pattern load queue". However, this name tends to confuse the RAM structure (which is actually a queue) with the ROM structure (which is a set of data to be loaded into the queue).
 +
 
 +
PLRs tell the game engine where to get Nemesis-compressed art data and where to put it. The format is rather simple, and can be described with this pseudocode:
  
 
<pre>
 
<pre>
struct plqItem{
+
struct plr{
 
   long *compPattern;
 
   long *compPattern;
 
   word vramStartLoc;
 
   word vramStartLoc;
 
};
 
};
  
struct plqLength03{
+
struct plrList03{
   const word itemCount == 3;
+
   const word plrCount == 3;
   plqItem itemArray[3]
+
   plr plrArray[3]
} plq000;
+
} plr000;
 
</pre>
 
</pre>
  
<tt>itemCount</tt> is the length of <tt>itemArray</tt>. <tt>compPattern</tt> is a pointer to Nemesis-compressed patterns, and <tt>vramStartLoc</tt> is the VRAM address where the patterns are to be decompressed to.
+
<tt>plrCount</tt> is the length of <tt>plrArray</tt>. <tt>compPattern</tt> is a pointer to Nemesis-compressed patterns, and <tt>vramStartLoc</tt> is the VRAM address where the patterns are to be decompressed to.
 +
 
 +
The RAM queue has space for 20 PLRs. Note that the routines that load PLRs into the queue do not do any bounds checking, and it is quite easy to create a buffer overrun condition. Further, both lists seem to be moved into the queue at the same time, so even if neither one is longer than 20 requests, they can still overrun the queue and destroy the variables that are stored just beyond it. ''''Make sure that the primary and secondary PLR lists are no more than 20 requests long.''''
  
 
===Object Editing===
 
===Object Editing===
Line 662: Line 666:
 
See the [[Sonic Community Hacking Guide/Sonic 2/Level Specific|level specific hacking info]] for the locations of level layout data.
 
See the [[Sonic Community Hacking Guide/Sonic 2/Level Specific|level specific hacking info]] for the locations of level layout data.
  
===16x16 block mappings===
+
===Block mappings===
These are compressed in [[Kosinski compression|Kosinski format]], so to edit them you will need to decompress them first. (I recommend using TSDC for this)
+
These are compressed in [[Kosinski compression|Kosinski format]], so to edit them you will need to decompress them first.
 +
 
 +
<pre>
 +
struct blockElement {
 +
    int cellProperties : 5;        // c
 +
    int vramCellIndex  : 11; };    // i
 +
// cccc ciii iiii iiii
 +
 
 +
blockElement (*blockMap)[0x100][4] = 0xFFFF0000;
 +
 
 +
struct metaBlockElement {
 +
    int : 4;                      // x
 +
    int blockIndex : 12; };        // I
 +
// xxxx IIII IIII IIII
 +
 
 +
metaBlockElement (*metaBlockMap)[0x300][8] = 0xFFFF9000;
 +
</pre>
 +
 
 +
A block is an array of four <tt>blockElement</tt>s. <tt>blockElement->cellProperties</tt> describes the palette line and orientation of the cell. The actual mapping of block elements is like this:
 +
<pre>
 +
0 1
 +
2 3
 +
</pre>
  
16x16 are made by putting four 8x8 art tiles together. Each 16x16 block is 8 bytes long. There are two bytes per 8x8 tile. The first nibble determins which pallet line to use, and weather is should be flipped. Then the three nibbles after that determine what 8x8 tile to use. Past the value of 800, the block number restarts back at block 0, but the block is mirrored. The first 16x16 block should always be made up of fully transparent tiles.  
+
Metablocks are basically arrays of indeces into <tt>blockMap</tt>. <tt>metaBlockElement->blockIndex</tt> provides the first index into <tt>blockMap</tt>; the upper four bits of the element appear to be unused.
  
Refer to this chart for a explination of the first nibble:  (Thanks to [[Nemesis]] for the chart)
+
[[Nemesis]] provides this chart of values for the upper four bits of <tt>cellProperties</tt>. The LSB mirrors the cell.
  
 
{| border="1"
 
{| border="1"

Revision as of 16:40, 31 July 2006

This is the Sonic Community Hacking Guide for Sonic the Hedgehog 2. It's still mostly trying to copy and correct Nemesis's guide, but it's still useful.

ROM Hacking

Art Editing

There are several different tools that can be used to edit art besides the hex editor. SonED is probably the best tool to use for editing level art, and can also be used on palettes. HivePal is also a great tool for editing palettes. Sonik Sprite is useful for editing uncompressed art; it gets its name from its ability to edit Sonic's sprites. LOst Library is most likely the best choice for editing compressed art in the Nemesis format.

If, however, you still want to do it yourself, your best bet is to download the Sonic 2 Split disassembly here. Decompress the archive into a new folder, and place your S2 ROM, in binary format and named "S2.bin", in that folder. Run the batch file "split.bat". This will split up all the art into its own binary files, which you can then decompress and edit. When you're done, run "combine.bat".

Uncompressed Art Locations

Most of this information was taken from Nemesis's guide. Please excuse any mistakes or misunderstandings, as that guide wasn't exactly well-written. A description is written in parentheses after the original name if I deem it necessary; if I don't know what it is, "Unknown" appears in that place. Please correct this if you know. It doesn't list the number of blocks taken up, so if you know, put it in. Otherwise, I'll find out eventually.

Offset Description # of blocks
Zone Independent
$50000 Sonic  ?
$64180 Tails  ?
$71FFC Splash  ?
$7287C Spindash smoke  ?
$7A1A0 Signpost  ?
$7AF82 Drowning countdown  ?
$7CD30 Option and level select menu background  ?
Emerald Hill Zone
$49714 Animated flowers  ?
$49914 Pulsing orb on walls  ?
Chemical Plant Zone
$4FAFE Part of background  ?
Aquatic Ruin Zone
$4FCFE Waterfall  ?
Casino Night Zone
$4D4FE Flipping square in foreground  ?
$4EEFE Slot machine pictures  ?
Hill Top Zone
$49714 Animated flowers  ?
$4A33E Clouds from background  ?
$4B73E Lava  ?
Mystic Cave Zone
$894E4 Rocks that fall from ceiling during boss fight  ?
Oil Ocean Zone
$49914 Pulsing orb on walls  ?
$4BF7E Pulsing ball  ?
$4C0FE Square rotating around ball (Unknown)  ?
$4C4FE Oil  ?
Metropolis Zone
$4A73E Rotating net  ?
$4B73E Lava  ?
$4BD3E Parts of background  ?
Death Egg Zone
$4FAFE Part of background  ?

Compressed Art Locations - Nemesis format

See SCHG:Sonic 2/Nemesis Compressed Art.

Compressed Art Locations - Kosinski format

  • $95C24 - EHZ/HTZ main level patterns
  • $9DB64 - MTZ main level patterns
  • $A4204 - OOZ main level patterns
  • $A9D74 - MCZ main level patterns
  • $B0894 - CNZ main level patterns
  • $B6174 - CPZ/DEZ main level patterns
  • $BCC24 - ARZ main level patterns
  • $C5004 - SCZ/WFZ main level patterns
  • $DCA38 - Special stage floor patterns

Palette Editing

Usually, it's not really necessary to edit a palette in hex. Palette editors give you instant feedback for each RGB value, and the palette can be easily saved as a separate binary and reimported into the ROM. However, it is sometimes desireable or necessary to do it in hex, and it can't hurt to know how it's done.

These are the ROM offsets of the palettes in Sonic 2, as listed by HivePal:

Name Offset
Sega Sonic $2902
Title Screen (Sonic) $133EC
Title Screen (Tails) $2942
Title Screen (Main) $1340C
Title Screen Water $1E5A
Sonic and Tails $29E2
Sonic to Super Sonic $2246
Super Sonic $2276
Title Cards $2A02
Emerald Hill $2A22
Emerald Hill/Aquatic Ruin Rotating Water $1E7A
Wood $2A82
Wood Conveyor Belts $1F1A
Metropolis $2AE2
Metropolis Cycle #1 $1F2A
Metropolis Cycle #2 $1F36
Metropolis Cycle #3 $1F42
Wing Fortress $2B42
Wing Fortress Fire Cycle $20A2
Hill Top $2BA2
Hill Top Lava $1E9A
Hidden Palace $2C02
Hidden Palace (Sonic & Tails Under Water) $2C62
Hidden Palace Underwater Tiles Pallete $2C82
Hidden Palace Water Cycle $1F56
Hidden Palace Underwater Cycle $1F66
Oil Ocean (Do not edit or you'll get a huge mess unless you know how to fix it!) $2CE2
Oil Ocean Oil $1F76
Mystic Cave $2D42
Mystic Cave Lanterns $1F86
Casino Night $2DA2
Casino Night Cycle 1 $1F8E
Casino Night Cycle 2 $1FA0
Casino Night Cycle 3 $1FB2
Casino Night Cycle 4 $1FC4
Chemical Plant $2E02
Chemical Plant Sonic & Tails Underwater $2E62
Chemical Plant Underwater $2E82
Chemical Plant Underwater Sonic to Super Sonic $22C6
Chemical Plant Underwater Super Sonic $22F6
Chemical Plant Cycle 1 $2022
Chemical Plant Cycle 2 $2058
Chemical Plant Cycle 3 $2082
Chemical Plant Cycle 4 $20E2
Death Egg $2EE2
Aquatic Ruin $2F42
Sonic & Tails Underwater (Aquatic Ruin) $2FA2
Aquatic Ruin Underwater $2FC2
Sonic to Super Sonic Underwater (Aquatic Ruin) $2346
Aquatic Ruin Underwater Super Sonic $2376
Sky Chase $3022
Menus $30E2
Special Stage Main $3162
Special Stage Sonic $3182
Special Stage Tails $31A2
Special Stage 1 $31C2
Special Stage 2 $31E2
Special Stage 3 $3202
Special Stage 4 $3222
Special Stage 5 $3242
Special Stage 6 $3262
Special Stage 7 $3282
Special Stag 1 2p $32A2
Special Stage 2 2p $32C2
Special Stage 3 2p $32E2
Special Stage Chaos Emerald $35F92
Special Stage Results Screen $3302
Emerald Hill Icon $9880
Metropolis Icon $98A0
Hill Top Icon $98C0
Hidden Palace Icon $98E0
Oil Ocean Icon $9900
Mystic Cave Icon $9920
Casino Night Icon $9940
Chemical Plant Icon $9960
Aquatic Ruin Icon $9980
Sky Chase Icon $99A0
Wing Fortress Icon $99C0
Death Egg Icon $99E0
Special Stage Icon $9A00
X 2 Player Versus Icon $9A20
Sound Test Icon $9A40
Ending Grey Cutscenes $AD1E
Ending Main $ACBE
Ending Sonic $AC7E
Ending Tails $AC9E
Ending Super Sonic $AD3E
Unknown 1 $3082
Unknown 2 $30A2
Oil Ocean Zone Boss (Pallete line 1) $30C2

For details of the palette data format, see Megadrive Palettes.

Pattern Load Requests

Nemesis named this structure the "pattern load queue". However, this name tends to confuse the RAM structure (which is actually a queue) with the ROM structure (which is a set of data to be loaded into the queue).

PLRs tell the game engine where to get Nemesis-compressed art data and where to put it. The format is rather simple, and can be described with this pseudocode:

struct plr{
  long *compPattern;
  word vramStartLoc;
};

struct plrList03{
  const word plrCount == 3;
  plr plrArray[3]
} plr000;

plrCount is the length of plrArray. compPattern is a pointer to Nemesis-compressed patterns, and vramStartLoc is the VRAM address where the patterns are to be decompressed to.

The RAM queue has space for 20 PLRs. Note that the routines that load PLRs into the queue do not do any bounds checking, and it is quite easy to create a buffer overrun condition. Further, both lists seem to be moved into the queue at the same time, so even if neither one is longer than 20 requests, they can still overrun the queue and destroy the variables that are stored just beyond it. 'Make sure that the primary and secondary PLR lists are no more than 20 requests long.'

Object Editing

Sounds

If you change the "ring" sound effect, all objects using that sound will have the new sound. This may not be desired, however - you may have only wanted the Super Ring powerup to play the new sound. With this list, you can edit the sound effect that an object plays. If you change the sound for the Super Ring power-up, only the Super Ring will have the new sound. Note that you are not changing any sound effects - you are only changing which effect will play.

These notes are for those who don't want see the programming stuff of the objects to change its sounds.

To change the sound, first, take a value from the sound test (Ex: 1-up sound is $18) , add $80 to it and you get $98. This is the way you have to replace sounds (take a value from sound test, add $80 to it, and after that, insert the byte in the offset where you wish change the sound.)

Offset List

The following list is the offset where you will place the new sound. I not will make a list with the values and its respective sounds. Use the trick (explained above) and Sound Test. Of course you can place the objects in any level you want (see Object Placement below), I'm just saying the level the object is used in for a better description.

Level Description Offset
ALL Invincibility power-up $12A81
ALL Shield power-up $12A37
ALL Super Ring $129CD
ALL Lamp Post: $1F191
Casino Night Bumper $1F7F5
ALL Red and Yellow Springs Facing Up $18A69
ALL Red and Yellow Springs Facing Right $18BBF
ALL Red Spring Facing Down $18D63
Chemical Plant Speed booster $223DB
Chemical Plant Blue worm (The sound is repeated 3 Times.) $224EA
Aquatic Ruin Arrow launcher $257B7
Casino Night Slot machine cage $2BE1F
Casino Night Point cage $2BE6B
Hill Top Zip line $21E75
Casino Night Blue Bumper $2C577
Casino Night Green flipper $2B30B
Casino Night Orange flipper $2B3BF
Casino Night Impulse spring facing up $2AE4F
Wing Fortress Propellor (repeat infinitely) $3B3A3

Object Pointer List

See SCHG:Sonic 2/Object Pointers.

Sprite table (aka mappings)

Reference
The sprite table data can be expressed with this pseudocode:

struct spriteTablePiece{
  byte yPosition;
  byte shape;
  byte attributes1P;
  byte artOffset2P;
  byte attributes2P;
  byte artOffset2P;
  word xPosition;
};

struct spriteTableLenghth03{
  const word length == 3;
  spriteTablePiece table[3];
} spriteTable01;
  • The value of shape can range from $00 (1x1) to $0F (4x4). $01 is a 1x2 sprite, $02 is a 1x3 sprite, $04 is a 2x1 sprite, and so on.
  • attributes1P and attributes2P are bitfields that controls various sprite attributes:
Bit Attribute
3 Flip sprite horizontally
4 Flip sprite vertically
5 Palette line +1
6 Palette line +2
7 Keep sprite in forground
  • artOffset1P and artOffset2P control the offset from the object's base tile that the sprite should start reading from. For example, if the object's art started a tile $3F0, and artOffset1P was $06, then the sprite would start reading its art at $3F6.

Question: Are xPosition and yPosition offsets from the object's current position?

Object Placement

There are six bites in one object definition. The first two bytes are the X position of the object, and the next two bytes are the Y position. The 5th byte is the reference number on the object pointer list (see above), and the 6th byte is an optional declaration to use for defining that object's behavior and/or animation. This will depend on the object. See the level specific hacking info for the locations of the object lists.

The 6th byte, the object subtype, is loaded in the 28th byte of the SST of that object (see below).

Ring Placement

There are four bytes for every ring object. The first 2 bytes are X coordinates, after that there is one nibble to determine how many rings, then three nibbles (or one nibble and one byte) for the Y coordinates. After you are done adding all your rings for the level, "FF FF" will end the ring data. A format would look like this:

XX XX TY YY

Where X represents X position, Y represents Y position, and T represents type, as per the table below.

Example: 03 46 10 2B

If you see this, then you will get two horizontal rings at X = 0346 Y = 02B. The "1" determines how many rings there are, and what direction they go. (horizontal or vertical) Here is what you get for each value:

Value Rings
0 1 Horizontal
1 2 Horizontal
2 3 Horizontal
3 4 Horizontal
4 5 Horizontal
5 6 Horizontal
6 7 Horizontal
7 8 Horizontal
8 1 Vertical
9 2 Vertical
A 3 Vertical
B 4 Vertical
C 5 Vertical
D 6 Vertical
E 7 Vertical
F 8 Vertical

See the level specific hacking info for the locations of the ring data.

Level Layout

Level layouts are compressed in Kosinski format, so to edit them you will need to decompress them first. (I recommend using TSDC for this)

Level layouts are pretty simple. There is one byte per 128x128 tile to place on the map. The blocks are put together from left to right, top to bottom. Each horizontal row is 60 bytes long. The rows are interlaced between the foreground and the background, so that there are 60 bytes for the first row of the foreground, then 60 bytes for the first row of the background, then 60 bytes for the second row of the foreground, etc.

See the level specific hacking info for the locations of level layout data.

Block mappings

These are compressed in Kosinski format, so to edit them you will need to decompress them first.

struct blockElement {
    int cellProperties : 5;        // c
    int vramCellIndex  : 11; };    // i
// cccc ciii iiii iiii

blockElement (*blockMap)[0x100][4] = 0xFFFF0000;

struct metaBlockElement {
    int : 4;                       // x
    int blockIndex : 12; };        // I
// xxxx IIII IIII IIII

metaBlockElement (*metaBlockMap)[0x300][8] = 0xFFFF9000;

A block is an array of four blockElements. blockElement->cellProperties describes the palette line and orientation of the cell. The actual mapping of block elements is like this:

0 1
2 3

Metablocks are basically arrays of indeces into blockMap. metaBlockElement->blockIndex provides the first index into blockMap; the upper four bits of the element appear to be unused.

Nemesis provides this chart of values for the upper four bits of cellProperties. The LSB mirrors the cell.

Value Pallet Line Flipped
Horizntally
Flipped
Vertically
0 1 n n
1 1 n y
2 2 n n
3 2 n y
4 3 n n
5 3 n y
6 4 n n
7 4 n y
8 1 n n
9 1 y n
A 2 n n
B 2 y n
C 3 n n
D 3 y n
E 4 n n
F 4 y n

See the level specific hacking info for the locations of 16x16 data.

Text Editing

[to be filled later]

Level event scripts

Also known as "dynamic screen resizing" or "dynamic level events", this code is used to create effects unique to a certain Zone or Act. I have no further information to contribute on the subject, as I know absolutely nothing about it.

RAM Hacking

Main System Memory Locations

These are significant locations in the system memory. Note that any numbers entered (for example, score or number of rings) will have to be converted to hex before putting them in.

These are the offsets in RAM. To convert them to Genecyst savestate offsets, add $2478.

RAM offset Description
$EE00-$EE01 Camera's X position.
$EE04-$EE05 Camera's Y position.
$EE06-$EE0B Unknown
$EE0C-$EE0D Some sort of variable for use in rasterised level deformation
$EE0E-$EEC5 Unknown
$EEC6-$EEC7 "Screen Y end location"; this could be either the maximum value of the camera's Y position or the edge of the camera at its maximum position. Nemesis didn't make this very clear.
$EEC8-$EEC9 "Screen X start location"; most certainly at the left side of the level.
$EECA-$EECB "Screen X end location"; should be at least $30 less than the end of the level, otherwise, Sonic will fall off the screen.
$EECC-$EECD "Screen Y start location"; note that if $FF00 is placed in both the start and the end, the screen will be Y wrapped. Y wrapping should not be used on levels with water - note what happened in the beta's Hidden Palace Zone.
$EECE-$EECF Maximum camera scroll speed
$F600 Master level trigger. Tells the game what it should be doing. Values:
  • $00 - Sega logo
  • $04 - Title screen
  • $08 - Demo (return to title screen at 27 seconds)
  • $0C - Normal level (Level loop, when it has been loaded)
  • $8C - Load level stuff (call it restart if you want)
  • $10 - Special stage
  • $14 - Continue screen
  • $18 - 2P vs. result
  • $1C - 2P vs. level select
  • $20 - Game end sequence
  • $24 - Options menu
  • $28 - Level select
$F604 This bitfield tells which button(s) on Controller 1, if any, are being pressed. Format is:
  • Bit 0 - Up
  • Bit 1 - Down
  • Bit 2 - Left
  • Bit 3 - Right
  • Bit 4 - B
  • Bit 5 - C
  • Bit 6 - A
  • Bit 7 - Start

Updated by a subroutine which is called from the Vertical Interrupt, thus it's updated for every frame.There's no need to call that subroutine manually if the Interrupts are on (Which is always, except if an internal error happens.)

$F605 Same as $F604, but tells which buttons are being held down.
$F606 Same as $F604, but for Controller 2.
$F607 Same as $F606, but tells which buttons are being held down.
$F648-$F649 Current water level. Should be a valid Y-axis value. Remember, the top of the level is $0000, and the bottom of the level is $FFFF (I think).
$F650-$F651 The level that the water should be at. If this is different than the value above, the water will move until they are the same.
$F652 Water level change speed. If set to $00, the water level won't change.
$F65E Super Sonic palette counter. Decremented with every frame. How it works, exactly, is not known.
$F65F Sets the rotating palette for Super Sonic.
$F670 Super Sonic ring drain counter. This is updated each frame, so the counter is set to 60 ($3C) on consoles operating in 60Hz mode, or 50 ($32) in consoles operating in 50Hz mode. After each frame, the code subtracts 1. One ring is removed when this counter reaches zero; in other words, each second.
$F730 Water flag. Must be set for any of the other water variables to have any effect. Note that levels without water don't have an underwater palette; you must set one or everything below the water level will be black.
$F760-$F761 Sonic's top speed
$F762-$F763 Sonic's acceleration
$F764-$F765 Sonic's deceleration
$F76C Routine counter for the object placement engine?
$F76E-$F76F Unknown
$F770-$F773
$F774-$F777
$F778-$F77B
$F77C-$F77F
Sprite loading addresses. Tells the game where in the ROM to get sprite info.
$F78C-$F78D Unknown
$F7AA Seems to be clear during normal play, but set to some value during a boss fight. That value may be the current Zone number.
$F7DA Seems to be a count of the number of screens since the start point (which is set at FF = 0) What? Explain please.
$F7DB Unknown (may be unused)
$FE00 Start of the system stack. Note that the stack grows up rather than down. This means that when something is pushed onto the stack, the SP is decremented, and when something is popped from it, the SP is incermented.
$FE06 Object currently selected in debug mode.
$FE09 Object placement mode flag.
$FE10 The current Zone. This is the value assigned to the Zone, not its position in the level list.
$FE11 Act number
$FE12 Number of lives.
$FE16 Current special stage.
$FE18 Number of continues.
$FE19 Super Sonic flag. Setting this will load the Super Sonic tiles, adjust Sonic's jump height, and start draining rings, but it will not load the rotating palette, change acceleration, max speed, or deceleration, or make him invincible.
$FE1D Flag determines if the rings counter needs to be updated
$FE1E Flag determines if the timer needs to be updated
$FE1F Flag determines if the score counter needs to be updated
$FE20-$FE21 Ring count
$FE23 Minutes on clock. Should not go above $09, or the clock will look like shit.
$FE24 Seconds. This one shouldn't go above $3B, for the same reason.
$FE25 Milliseconds. I don't know what'll happen if this goes out of range, but it's probably not good.
$FE26-$FE29 Score
$FE30 Greatest reference number of passed star poles
$FEC0-$FEC1 Tails's max speed
$FEC2-$FEC3 Tails's acceleration
$FEC4-$FEC5 Tails's deceleration
$FEC6 Tails's lives
$FF40-$FF41 Number of rings to collect before a perfect is scored
$FF70-$FF71 "Player in special stage"; variable tested by a lot of other routines, so it may have other meanings
$FF72-$FF73 Player option (Sonic and Tails - 0, Sonic alone - 1, Tails alone - 2)
$FF74-$FF75 2P mode items (teleport only, all kinds items - which is which?)
$FF82-$FF83 Item in level select menu that's selected (set to 16 to see the HPZ picture)
$FF85 Sound currently selected in sound test; value retained when options menu is exited
$FF86 Selection on Title Screen
$FF88 Selection on 2 Player Level Select Menu
$FF90-$FF91 Zone music currently playing. Used for quick access when switching music.
$FF8C Box slected in options menu
$FFB0 Special stage completed flag
$FFB1 Number of emeralds collected so far
$FFB2-$FFB8 Array of finished special stages. Each byte represents one stage.
$FFD0 Level select flag
$FFD1 Slow motion flag
$FFD8-$FFD9 2P mode flag
$FFE1 Play specified sound effect. Not sure how it works.
$FFE4 Play specified music. These are the actual playlist values, NOT the sound test values. To convert from sound test to playlist, add $80 to the sound test value. For example, putting in $96 here will play the Super Sonic music; putting in $97 will play the invincibility music.
$FFF0-$FFF1 Demo mode flag
$FFD4 Unknown cheat value
$FFFA Debug mode flag

Object Status Table Format

The starting offset in RAM for this list is $B000. The first object is always Sonic; the second is always Tails. After this, there is a gap, and the list picks up again at $B400. Each object is alloted a block of $40 bytes. I will use the beginning of a block as a reference point. Note that many of these variables are object-specific - for example, some of them only make sense for Sonic, and some only work on badniks.

Offset Description
$00 Object number. See object list above.
$01 Action flags. The bitfield looks like this:
  • Bit 0 is the horizontal mirror flag. If set, the object will be flipped on its horizontal axis.
  • Bit 1 is the vertical mirror flag.
  • Bit 2 is the coordinate system flag. If clear, the object will be positioned by absolute screen coordinates. This is used for things like the HUD and menu options. If set, the object will be positioned by the playfield coordinates, i.e. where it is in a level. Sonic and Tails use both positioning systems (though I don't know how Tails uses it in a Sonic and Tails game).
  • Bits 3, 4, and 5 are either unused, or their purpose is unknown.
  • Bit 6 is not used in this game.
  • Bit 7 is the draw object flag. It will be set if the object was onscreen when it came time to draw things. Otherwise, it is clear. There should be no reason to edit this flag, but it's good to know what it does.
$02-$03 Starting art block. This is the block number in the VDP. Note that there is logical repetition in the VDP block list, so if you get a number higher than the number of blocks, simply subtract the number of blocks repeatedly until you get a reasonable number.
$04-$07 Object's mappings offset
$08-$09 If the object is Sonic or Tails, this is the X playfield coordinate. Otherwise:
  • If in playfield positioning mode, it is the X playfield coordinate.
  • If in screen postioning mode, it is the screen coordinate.
$0A-$0B If the object is Sonic or Tails, this is the X screen coordinate. Otherwise:
  • If in playfield positioning mode, it is unused.
  • If in screen positioning mode, it's the Y screen coordinate.
$0C-$0D If the object is Sonic or Tails, this is the Y playfield coordinate. Otherwise:
  • If in playfield positioning mode, it is the Y playfield coordinate.
  • If in screen positioning mode, it is unused.
$0E-$0F If the object is Sonic or Tails, this is the Y screen coordinate. Otherwise:
  • It's unused.
$10-$11 X speed
$12-$13 Y speed
$14-$15 Potential speed (inertia).
$16 Height/2
$17 Width/2
$18 Sprite priority (00 = front).
$19 Width of the object, in pixels
$1A Current animation frame to display.
$1B Current frame in animation script.
$1C Animation number.
$1D Restart animation flag (when $1D is not equal to $1C, animation restarts)
$1E Animation frame duration (time until next frame).
$20 Collision response bitfield. Tells what the object will do if hit by the character. The bitfield is in the format TTSS SSSS. TT is the type of collision - 00 is enemy, 01 is some event, 10 is harm, and 11 seems to be a special thing for the starpole. SS SSSS is the size, but the format is unknown.
$21 Custom collision property, for special interaction with Sonic. This is used by bosses, badniks, bumpers and other objects. The way in which this byte is used is different for each object. Bosses use this byte as a hit counter.
$22 Object's orientation. $00 is normal, $01 is X flipped, $02 is Y flipped, and $03 is X-Y flipped. These values repeat until $FF. Note that this byte has a different meaning for Sonic and Tails (see below).
$23 Respawn index reference number, used by badniks, rings and monitors. Each destroyable object is assigned an index number (01, 02, 03 etc.) which refers to a list at $FC00 in the RAM.
$24 Routine counter.
$25 Second routine counter. This is used for some of the more complicated objects.
$26-$27 Angle.
$28 Object subtype. For example, the current monitor selected. See the Object List above for values. Has a different meaning for Sonic and Tails.
Object-specific variables
Offset Description
$22 Sonic and Tails: Special bitfield. Counting from the least significant bit:
Bit Hex Description
0 $01 Orientation. Clear is left and set is right.
1 $02 Set if Sonic/Tails is in the air (jump counts).
2 $04 Set if jumping or rolling.
3 $08 Set if Sonic/Tails isn't on the ground but shouldn't fall. (Usually when he is on a object that should stop him falling, like a platform or a bridge.)
4 $10 Set if jumping after rolling.
5 $20 Set if pushing something.
6 $40 Set if underwater.
7 $80 Unused.

You can add the hex values together to use multiple settings at once. Also notice that the first 4 bits (0-3) are used in the character object as a second routine counter.

$28 Sonic and Tails: Seconds of air left. Usually $1E; it decrements every second while the player is underwater. Beeps on $18, $13, and $0E. Countdown starts on $0B.
$2B Sonic and Tails: Another bitfield.
Bit Hex Description
0 $01 Shield flag. Can be set to create the effect of having a shield, though the graphics will not be loaded.
1 $02 Sets invincibility. Behaves like you would expect. No graphics are loaded when set manually.
2 $04 Speed Shoes flag. (Doesn't have visible effect in game)
3 $08 Unused
4 $10 Unused
5 $20 Unused
6 $40 Unused
7 $80 Sets infinite inertia. While Sonic is in collision with the ground, he will continue moving in the same direction and at the same speed that he was moving before (even if that speed was zero). You can still jump and control him in midair. (A few movement routines are skipped if it's set, which produces this effect.)
$30-$31 Sonic and Tails: Remaining invunerability time. Starts at $0078 after Sonic is hit, and seems to decrement every frame until it reaches $0000.
$32-$33 Sonic and Tails: Remaining time of invincibility.
$34-$35 Sonic and Tails: Remaining time of Speed Shoes.
$36 Sonic and Tails: Seems to be related with the collision block boundaries (this isn't a flag)
$37 Sonic and Tails: Seems to be related with the collision block boundaries (the opposite side of $36) (this isn't a flag)
$39 Sonic and Tails: Set if charging a spindash.
$3A-$3B Sonic and Tails: Spindash counter. Cleared when the spindash is started. After each subsequent "rev", $200 is added to the counter, which then rapidly decreases (the algorithm is to logically shift the value right by five bits and subtract the results from the original). It maxes out at $800. The game looks at the high-order byte to determine how fast the character should move after the dash is released.
$3C Sonic and Tails: Set if jumping.
Sonic Community Hacking Guide
General
SonED2 Manual | Subroutine Equivalency List
Game-Specific
Sonic the Hedgehog (16-bit) | Sonic the Hedgehog (8-bit) | Sonic CD (prototype 510) | Sonic CD | Sonic CD (PC) | Sonic CD (2011) | Sonic 2 (Simon Wai prototype) | Sonic 2 (16-bit) | Sonic 2 (Master System) | Sonic 3 | Sonic 3 & Knuckles | Chaotix | Sonic Jam | Sonic Jam 6 | Sonic Adventure | Sonic Adventure DX: Director's Cut | Sonic Adventure DX: PC | Sonic Adventure (2010) | Sonic Adventure 2 | Sonic Adventure 2: Battle | Sonic Adventure 2 (PC) | Sonic Heroes | Sonic Riders | Sonic the Hedgehog (2006) | Sonic & Sega All-Stars Racing | Sonic Unleashed (Xbox 360/PS3) | Sonic Colours | Sonic Generations | Sonic Forces
Technical information
Sonic Eraser | Sonic 2 (Nick Arcade prototype) | Sonic CD (prototype; 1992-12-04) | Dr. Robotnik's Mean Bean Machine | Sonic Triple Trouble | Tails Adventures | Sonic Crackers | Sonic 3D: Flickies' Island | Sonic & Knuckles Collection | Sonic R | Sonic Shuffle | Sonic Advance | Sonic Advance 3 | Sonic Battle | Shadow the Hedgehog | Sonic Rush | Sonic Classic Collection | Sonic Free Riders | Sonic Lost World
Legacy Guides
The Nemesis Hacking Guides The Esrael Hacking Guides
ROM: Sonic 1 | Sonic 2 | Sonic 2 Beta | Sonic 3

Savestate: Sonic 1 | Sonic 2 Beta/Final | Sonic 3

Sonic 1 (English / Portuguese) | Sonic 2 Beta (English / Portuguese) | Sonic 2 and Knuckles (English / Portuguese)
Move to Sega Retro
Number Systems (or scrap) | Assembly Hacking Guide | 68000 Instruction Set | 68000 ASM-to-Hex Code Reference | SMPS Music Hacking Guide | Mega Drive technical information