Actions

SCHG

SCHG:Sonic 3 & Knuckles/RAM Editing

From Sonic Retro

SCHG: Sonic 3 & Knuckles
Main Article
Art Editing
Editing Art
Uncompressed Art
Nemesis Format Art
Kosinski Format Art
Palette Editing
Palette Locations
Pattern Load Requests
Object Editing
Editing Objects
Object Pointers
Object Pointer List #1
Object Pointer List #2
Objects not in either list
Sprite Mappings
Dynamic PLCs
Level Editing
Editing Levels
Object Placement
Ring Placement
Level Layout
16x16 Block Mappings
128x128 Block Mappings
Music Editing
Editing Music
Pointer Format
Header Format
DAC Samples
Universal Voice Bank
Music Pointers (Sonic & Knuckles)
Music Pointers (Sonic 3)
RAM Editing
Editing RAM
Main System Memory Locations
Object Status Table Format

Main System Memory Locations

This is a map of 68k memory as used by the main gameplay engine. Note that any numbers entered (for example, score or number of rings) will have to be converted to hex first.

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

RAM offset Description
$0000-$7FFF 128x128 mappings
$8000-$8FFF Level layout
$9000-$A9FF 16x16 mappings
$AA00-$ABFF Pattern decompression buffer
$AC00-$AFFF Sprite table input. Consists of 8 different priority levels, each level taking up $80 bytes. The first word of each level is the number of objects currently in that priority level multiplied by 2, and the next $3F words are the addresses in RAM (inside the object RAM space) of the objects on that priority level. The information in this table is processed by BuildSprites to create the actual sprite table
$B000-$CFCB Object attribute table
$D000-$DFFF Kosinski decompression buffer
$E000-$E37F Horizontal scroll buffer
$E380 Number of objects currently in collision response list, multiplied by 2.
$E382-$E3FF Collision response list. The format is one word per object, where the word is the starting address of the object's status table. Only objects in this list are processed by the collision response routine.
$E400-$E4FF In 1-player mode, this is Sonic's statistic recording buffer, used by Tails' AI. In 2-player mode, this is player 2's position table.
$E438-$E439 The number of blue spheres remaining to be collected in a Special Stage.
$E43A-$E43B The number of rings collected in a Special Stage.
$E43D Special Stage ring collection flags. Bit 0 is set when 50 rings have been collected, bit 1 is set for 100 rings, bit 2 for 200 rings, and bit 7 has an unknown purpose.
$E43E-$E43F Number of frames remaining till the speed of a Special Stage increases. Initial value is 1800 (i.e. 30 seconds in 60Hz mode) for regular special stages and 2700 (i.e. 45 seconds in 60Hz mode) for Blue Spheres special stages.
$E442-$E443 Total rings remaining to be collected in a Special Stage. A 50000 points perfect bonus is awarded for collecting all the rings.
$E444-$E445 Special Stage speed. Starts off at $1000 and is incremented by $400 every time the speed increase timer expires until it reaches $2000.
$E500-$E5FF Position table for player 1
$E600-$E653 Saved competition mode data
$E660-$E663 Long pointer to the currently-playing save slot's data in memory. Set to $FFFFE6AC when playing save slot 1, $FFFFE6B6 when playing save slot 2, etc.
$E6AC-$E6FF Variables for each save slot. The format is $A bytes long:
Hex Value Description
$00-$01 Word Slot State
$8000 New Game
$0000 Game in Progress
$0100 Game Complete
$0200 Game Complete with all Chaos Emeralds
$0300 Game Complete with all Super Emeralds
$02 Byte Current Character
$00 Sonic And Tails
$10 Sonic
$20 Tails
$30 Knuckles
$03 Byte Current Level
$0C Last level for knuckles
$0D Last level for Sonic without chaos/super emeralds, or Tails
$0E Last level for Sonic with at least all Chaos Emeralds
$04 Byte Unknown
$05 Byte Something with Special Stages Array
$06 Byte Something with Collecting a Chaos Emerald
$07 Byte Something with Collecting a Super Emerald
$08 Byte Current Number of lives
$09 Byte Current Number of Continues
  • Note that byte $02 also keeps a record of special stages played through, whether you won or lost it. It updates by $01's.
$E700-$EAFF Ring status table. The format is two bytes per ring, these bytes being 0000 while the ring has yet to be consumed, serving as a ring destruction timer while the ring is being consumed, and being set to FFFF when the ring has been fully consumed.
$EB00-$EDFF Object respawn table. Each object which is part of a level's object placement gets an entry in this table, and whenever the objects manager creates a new object, it sets bit 7 of the object's entry in the object respawn table. While bit 7 is set, the object will not be loaded again by the objects manager. The other seven bits of the entry are free for use by the object - for example, monitors set bit 0 to signify a broken monitor. Since every object which is part of the level's object placement has an entry in this table, the maximum number of objects any level can have in its object placement is 768, although the only level that gets close to that number is AIZ 2, with 751 objects.
$EE00-$EE01 Variable set by the horizontal scroll manager to the difference between the old and new camera X positions, multiplied by 256
$EE02-$EE03 Variable set by the vertical scroll manager to the difference between the old and new camera Y positions, multiplied by 256
$EE04-$EE05 Variable set by the horizontal scroll manager to the difference between the old and new camera X positions for player 2, multiplied by 256
$EE06-$EE07 Variable set by the vertical scroll manager to the difference between the old and new camera Y positions for player 2, multiplied by 256
$EE0A Scroll lock for player 1 - if this is set, scrolling routines won't be called
$EE0B Scroll lock for player 2 - if this is set, scrolling routines won't be called
$EE12-$EE13 Screen Y end
$EE14-$EE15 Screen X start
$EE16-$EE17 Screen X end
$EE18-$EE19 Screen Y start
$EE1A-$EE1B Screen Y end location for Sonic; the maximum value for camera Y position. Like $EE12, but changes slowly instead of instantly when the level Y boundary changes.
$EE24 X scroll delay value. If this is non-zero and its value is a, X scrolling will be based on the player's position a-1 frames ago instead of on the player's current position. Used for example by the Spin Dash and fire dash
$EE26-$EE27 Index into Player 1's statistics recording buffer and position table
$EE28 X scroll delay value for player 2. If this is non-zero and its value is a, X scrolling will be based on the player's position a-1 frames ago instead of on the player's current position. Used for example by the Spin Dash and fire dash
$EE2A-$EE2B Index into Player 2's position table
$EE2C-$EE2D Camera Y position bias.
$EE2E-$EE2F Camera Y position bias for player 2.
$EE33 Routine counter for Dynamic Screen Resizing. (Dynamic Level Events)
$EE42-$EE45 Address (in the ROM) of the first ring whose X position is greater than or equal to the current camera X value minus 8.
$EE46-$EE49 Address (in the ROM) of the first ring whose X position is greater than or equal to the current camera X value + $148.
$EE4A-$EE4B Address (in the ring status table) of the first ring whose X position is greater than or equal to the current camera X value minus 8.
$EE4E Apparent current zone. This is identical to $FE10
$EE4F Apparent current act. Unlike $FE11, this is only incremented by the actual end of act score tally, so it differs from $FE11 in levels like AIZ, where $FE11 is set to 1 as soon as the first cutscene is over, while this is incremented only after the end of act points tally. God knows why they didn't use this for level music choosing routines.
$EE60 Camera X for the second player in 2p mode
$EE64 Camera Y for the second player in 2p mode
$EE68 Copy of camera X for the second player in 2p mode for rasters
$EE6C Copy of camera Y for the second player in 2p mode for rasters
$EE78 Camera X
$EE7C Camera Y
$EE80 Copy of Camera X for Rasters
$EE84 Copy of Camera Y for Rasters
$EEC0-$EEC1 Screen event routine counter. Each routine is 4 units, so this counter can only contain multiples of 4. Affects AIZ2, FBZ2, LBZ2, MHZ2, SOZ2, SSZ1, SSZ2, DEZ2, DDZ, the slot machine bonus stage, the LRZ boss act, the DEZ boss act and the ending sequence.
$EEC2-$EEC3 Trigger event routine counter. Each routine is 4 units, so this counter can only contain multiples of 4. Affects all levels except for the bonus stages, DDZ, and MHZ1. For some reason, the ICZ1 screen event routine also uses this counter, so both the screen and trigger event routines are linked in that act.
$EEC4-$EEC5 Some kind of flag used by level scripts. Only ever seems to be set to $0000, $0055, $FF00 or $FFFF.
$EEC6-$EEC7 Like $EEC4, this only ever seems to be set to $0000, $0055, $FF00 or $FFFF. Level property (like killer wall in HCZ2 or avalanche in ICZ1). The high byte is set when an Act 1 signpost stops spinning, to signal the code that loads Act 2 into memory. This doesn't happen for AIZ and ICZ since they load Act 2 before the midboss.
$EEC8-$EEC9 Some sort of counter which counts up or down in multiples of $10.
$EECA-$EECB Some sort of counter which decreases by 1 whenever the value of $EEC8 increases or decreases by $10 and is set to various values whenever the value of $EEC8 is otherwise changed.
$EECC-$EECD Screen shaking flag. If zero, screen is not shaking. If negative, screen is shaking for an earthquake and will continue indefinitely. If positive, screen is shaking from a bomb impact or the like, and the value will be decremented each frame until it reaches zero, then shaking will stop.
$EECE-$EECF Screen shaking offset: the difference between the "true" camera Y positon and what appears on screen that frame. Most acts' screen events add this to $EE84 each frame. AIZ1, HCZ1, CNZ1, FBZ1, ICZ2, MHZ1 and DEZ ignore this value, so you'll need to edit the screen events if you want to add shaking effects in those acts. MHZ2 uses it as an X offset instead of a Y offset (when Robotnik hits the tree) so adds it to $EE80 instead of $EE84. ICZ1 uses it for both, depending on where in the level you are.
$EED0-$EED1 Stores the value that $EECE had during the previous frame.
$EED2-$EED3 Secondary screen event routine counter, used by some acts.
$EF00-$EF3F Seems to be unused, so if you need to find space for new variables somewhere, try here.
$EF49 Flag which determines whether the second player in a 2P versus game is player-controlled or just a "ghost" of the first player.
$EF6C-$EF6D Flag which is set to $FF00 when a Super Emerald special stage is newly completed. This stops the HPZS initalizer from repeating the "beam" effect that you see when you go to HPZ from a giant ring to pick the special stage in the first place.
$EF72-$EF73 Flag which is set to $FF00 if an ending is running. The only thing this seems to do is prevent the game from being able to pause.
$EF80 The number of rings inside the ring consumption table.
$EF82-$EFFF Ring consumption table. Contains the RAM addresses (inside the ring status table) of rings which are currently being consumed. Once consumed, the rings are deleted from this table.
$F000-$F07F Second underwater palette.
$F080-$F0FF Underwater palette.
$F100-$F57F Plane data buffer. During the normal level processing period, display update routines decide which tiles need to be updated and write the results here, and then in V-int a routine processes this and updates the planes accordingly. The first word of each entry in this buffer is the address in VRAM to write to - if this is 0, the buffer processing routine terminates. The second word is the number of 16x16 tiles to be written - 1, and the sign bit of this word being set indicates that the constituent 8x8 tiles are to be written column-by-column rather than row-by-row. Following this is the actual data to write.
$F580-$F5FF VRAM buffer. Used to temporarily hold data while it is being transferred from one VRAM location to another.
$F600 Master level trigger. Tells the game what it should be doing.

The MSB is a loading routine flag. It only matters for some game modes. It won't have any effect when changing modes because it's filtered out, but the corresponding routine does pay attention to it...

$F602 In-game Controller 1 held state. Same as F604, but it only updates during the main game loop, and not while paused, or a cutscene is running.
$F603 In-game Controller 1 pressed state. Same as F602, but only tells which buttons are being pressed newly this frame.
$F604 This bitfield tells which button(s) on Controller 1, if any, are currently 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

This is updated every frame.

$F605 Same as $F604, but only tells which buttons are being pressed newly this frame.
$F606 Same as $F604, but for Controller 2.
$F607 Same as $F606, but only tells which buttons are being pressed newly this frame for Controller 2.
$F614 Demo time left & Time until demo starts from title screen.
$F622 Teleport timer (leftover from Sonic 2)
$F623 Teleport active flag (leftover from Sonic 2)
$F628-$F629 Number of lag frames per level loop. Displayed in the place of the minutes counter in the debug HUD
$F636-$F639 RNG seed (used for pseudo-random number generation).
$F63A-$F63B Game paused flag.
$F646-$F647 Same as $F648.
$F648-$F649 Current water level. Should be a valid Y-axis value. Remember, the top of the level is $0000.
$F64A-$F64B Target water level. If this differs from $F648, the water level will move up or down $F64C lines per frame until they match.
$F64C The rate at which water rises or falls during a change in water level.
$F64E Set to 1 if water covers the entire visible screen; clear otherwise.
$F65C-$F65D Offset into the Super/Hyper color array, determines which set of colors we are currently on. Each palette entry is 2 bytes and there are 3 entries per set, so this is always a multiple of 6.
$F65E Number of frames remaining until the next set of Super/Hyper colors are loaded into the palette.
$F65F The current state of Super/Hyper palette rotation. 0 means disabled, 1 means the character is newly transforming to Super/Hyper, -1 ($FF) means the player is fully transformed, 2 means the character was Super/Hyper and is transforming back to normal.
$F667 Tails super flag, same as $FE19, just for Tails.
$F668 Same as $F65C, but for Tails. So this variable is used to control Tails' colors, and $F65C is used to control the Super Sonic flickies.
$F669 Same as $F65E, but for Tails. So this variable is used to control Tails' colors, and $F65E is used to control the Super Sonic flickies.
$F66A In-game Controller 2 held state. Same as $F602, but for controller 2
$F66B In-game Controller 2 pressed state. Same as $F66A, but only tells which buttons are being pressed newly this frame.
$F670-$F671 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.
$F680-$F6DF A buffer for pattern loading cues (requests). Each entry in this consists of one longword followed by one word, the longword being the location in ROM of the compressed art, and the word being the VRAM location to decompress to. Can store a maximum of 16 entries, but a coding error in the clearing routine means that storing a PLC in the last slot screws everything up, so effectively only 15 requests can be stored at one time.
$F6E0-$F6E3 The address in ROM of the decompression routine to be used for the art
$F6E4-$F6F7 Used by the PLC routines using decompression. No idea what their function is, although it seems they get passed in as parameters to the decompression routine, and are stored updated when the routine returns.
$F6F8-$F6F9 The total number of tiles left to be decompressed for the current piece of art
$F6FA-$F6FB The number of tiles left to be decompressed in the current frame
$F700-$F701 Seems to be set to $0001 when in a Sonic & Tails game. Set to $0000 when not a Sonic & Tails game.
$F702-$F703 Tails control counter. Counts how long until the CPU takes control.
$F704-$F705 Tails repawn counter.
$F708-$F709 Tails CPU routine.
$F70A-$F70B Tails CPU target X position. Tells Tails where Sonic's X position is so he can fly back to him.
$F70C-$F70D Tails CPU target Y position. Tells Tails where Sonic's Y position is so he can fly back to him.
$F70E-$F70F Tails interact ID. Object ID of last object Tails stood on.
$F710 Routine counter for the rings manager.
$F711 Level started flag. Set to 1 as soon as the player first gets control in the level.
$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
$F766 Sonic's current mapping frame number.
$F796-$F799 Pointer to solids for current collision layer. Is always the same as either $F7B4 or $F7B8.
$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.
$F7B4-$F7B7 Pointer to solids for default collision layer.
$F7B8-$F7BB Pointer to solids for alternate collision layer.
$F7C6 Reverse gravity flag. Only in Sonic & Knuckles.
$F7CA Controller lock for controller 1.
$F7CB Controller lock for controller 2.
$F7D0-$F7D1 Bonus counter. Increments upon destruction of a destroyable object, and is used to determine how many points the destruction should give. Resets when the player touches the ground.
$F7D2-$F7D3 Time bonus counter at the end of level result screen
$F7D4-$F7D5 Ring bonus counter at the end of level result screen
$F7DA-$F7DB Counts the number of times the camera has scrolled to the right by one full screen width from its previous position - initial value is $FF80 and then counts up like: $FF80,$0000,$0080,$0100,$0180,etc.
$F800-$FA7F Sprite attribute table buffer.
$FAA6-$FAA7 Signpost pointer, used between the falling signpost and the hidden monitors.
$FAA8 Flag which is set to $FF when a mid-boss or end boss is defeated, set back to zero when the results screen goes away.
$FAA9 Unknown flag which is something to do with control lock
$FAAA Flag which is set to $FF when a title card goes away, or when an Act 1 results screen goes away.
$FAAB Unknown flag which is only used by the LBZ1 boss
$FB00-$FBFB VDP command buffer. Stores up to 18 sets of queued up VDP commands to be issued later.
$FBFC-$FBFF VDP command buffer free slot. Stores the address of the first available empty place in the VDP command buffer.
$FC00-$FC7F Normal palette.
$FC80-$FCFF Second palette.
$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 incremented.
$FE02-$FE03 Level restart flag.
$FE04-$FE05 Level frame timer.
$FE06 Object currently selected in debug mode.
$FE08 Object placement mode routine counter.
$FE09 Object placement mode flag (0 - normal, 1 - object placement, 2 - frame cycling)
$FE0C-$FE0F Counts the number of times V-int has run
$FE10 The current Zone. This is the value assigned to the Zone, not its position in the level list.
$FE11 Act number
$FE12 Life Count
$FE18 Number of continues.
$FE19 Super/Hyper Sonic flag. 1 means Super and -1 ($FF) means Hyper. Setting this will load the Super/Hyper 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.
$FE1A Flag which is set when the player has a time over.
$FE1B This bitfield tells the game if the player has collected extra lives from rings. Seems to work differently in S3k than in S2.
$FE1C Flag determines if the lives counter needs to be updated
$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 Centiseconds. I don't know what'll happen if this goes out of range, but it's probably not good.
$FE26-$FE29 Score (divided by 10)
$FE2A Greatest reference number of passed star poles
$FE2B Starpole ID of the last starpole hit
$FE2C Zone in which the last starpole was hit
$FE2D Act in which the last starpole was hit
$FE2E-$FE2F X position of the last starpole hit
$FE30-$FE31 Y position of the last starpole hit
$FE32-$FE33 The number of the rings the player had when the last starpole was hit
$FE34-$FE37 Copy of the entire clock data when the last starpole was hit
$FE35 Minutes on the clock when the last starpole was hit
$FE36 Seconds on the clock when the last starpole was hit
$FE37 Centiseconds on the clock when the last starpole was hit
$FE38-$FE39 Starting art block of the main character when the last starpole was hit
$FE3A-$FE3B Main character's collision layers data when the last starpole was hit
$FE3C-$FE3D Camera's X position when the last starpole was hit
$FE3E-$FE3F Camera's Y position when the last starpole was hit
$FE40-$FE41 Water level when the last starpole was hit
$FE42 The state of the water movement flag when the last starpole was hit
$FE43 The state of the extra lives from rings bitfield when the last starpole was hit
$FE44-$FE45 Camera's current maximum Y position when the last starpole was hit
$FE46 DSR/DLE routine when the last starpole was hit
$FE48 Flag which is set upon special stage entry and cleared when the data saved on special stage entry is restored
$FE49 Starpole ID of the last starpole hit before the last special stage entry
$FE4A Zone from which the last special stage was entered
$FE4B Act from which the last special stage was entered
$FE50-$FE51 The number of rings the player had when the last special stage was entered
$FE52-$FE55 Copy of the entire clock data when the last special stage was entered
$FE53 Minutes on the clock when the last special stage was entered
$FE54 Seconds on the clock when the last special stage was entered
$FE55 Centiseconds on the clock when the last special stage was entered
$FE56-$FE57 Starting art block of the main character when the last special stage was entered
$FE58-$FE59 Main character's collision layers data when the last special stage was entered
$FE5A-$FE5B Camera's X position when the last special stage was entered
$FE5C-$FE5D Camera's Y position when the last special stage was entered
$FE5E-$FE5F Water level when the last special stage was entered
$FE60 The state of the water movement flag when the last special stage was entered
$FE61 The state of the extra lives from rings bitfield when the last special stage was entered
$FE62-$FE63 Camera's current maximum Y position when the last special stage was entered
$FE64 DSR/DLE routine when the last special stage was entered
$FE6E-$FEAF Oscillating numbers data
$FEB2 Rings animation counter.
$FEB3 Rings animation frame.
$FEB6 Spilling rings animation counter.
$FEB7 Spilling rings animation frame.
$FEC0-$FEC1 Tails' max speed
$FEC2-$FEC3 Tails' acceleration
$FEC4-$FEC5 Tails' deceleration
$FEC6 Tails' lives in 2P mode. Unused in S3K, but its there.
$FEC7 This bitfield tells the game if the player has collected extra lives from rings. Used for Tails in 2P mode. Unused in S3K, but its there.
$FEC8-$FEC9 Rings collected since level load. Resets if you enter Special/Bonus stage. Starts recounting from 0 when level is reentered. Unknown use.
$FF04-$FF05 Total rings remaining to be collected in a level. No perfect bonus is actually given for collecting all the rings, making this variable virtually useless.
$FF08-$FF09 Current character (00 - sonic & tails, 01 - sonic, 02 - tails, 03 - knuckles)
$FF0A-$FF0B Character selected in level select (00 - sonic & tails, 01 - sonic, 02 - tails, 03 - knuckles, 04 - blue knuckles)
$FF0E-$FF0F Number of kosinski compressed data pieces on the kosinski decompression queue ($FF40-$FF5F) waiting to be decompressed to RAM. The most significant bit of this being set signifies a decompression is in progress
$FF10-$FF37 Kosinski queue processing routine register backup. Registers d0-d6 and a0-a2 are backed up here in case the Kosinski queue processing routine is interrupted by V-Int. They're restored the next time the processing routine is called
$FF38-$FF39 Kosinski queue processing routine status register backup. In case the processing routine is interrupted by V-Int, the SR is stored here and restored the next time the routine is called
$FF3A-$FF3D Kosinski queue processing routine program counter backup. In the instance of the processing routine being interrupted by V-Int, when V-Int is ready to return, the processing does not resume. Instead, by means of the subroutine at $1BF0, program resumption is forced to occur at $1D0C, and the actual overwritten program counter value gets stored here. Next time the processing routine is called, the routine at $1CFC kicks in, pushing this value and the stored SR onto the stack and executing an RTE, causing both to get restored and the processing to resume.
$FF3E-$FF3F The Kosinski queue processing routine uses this to store words byteswapped. It's used by the processing routine the same way the stack is used by the normal Kosinski decompression routine
$FF40-$FF5F The Kosinski decompression queue. Each entry consists of two longwords:
  • $00 - the source Kosinski data location
  • $04 - the destination RAM address to decompress to

Since this is 32 bytes long, only 4 pieces can be stored on it at one time.

$FF60 Number of modules of KosinskiM compressed data waiting on the KosinskiM decompression and DMA queue ($FF64-$FF7B) to be decompressed to RAM and subsequently DMAed to VRAM. Bit 7 set to 1 indicates that the art has been already decompressed to the Kosinski art buffer ($D000), and is ready to be DMAed
$FF62-$FF63 The decompressed size of the last module of the KosinskiM data divided by 2. All other modules have a fixed decompressed size of $1000
$FF64-$FF7B The KosinskiM decompression and DMA queue. Each entry consists of a longword followed by a word:
  • $00 - the source Kosinski module location
  • $04 - the destination VRAM address to DMA the decompressed module to

Like the decompression queue, this can also only store 4 pieces at a time.

$FF90-$FF91 Used to store what music to resume after other music like the drowning music.
$FF96 State of the main character's secondary status bitfield when the last special stage was entered, used to restore any shield the character had when he entered the special stage and cleared once the shield is restored
$FF97 If set, the sprite and ring loaders will not clear the respawn table when the level loads. Used for returning from special and bonus stages.
$FF9A Apparent Zone in which the last starpole was hit (See $EE4E)
$FF9B Apparent Act in which the last starpole was hit (See $EE4B)
$FFA2-$FFA5 Map section IDs in Blue Sphere
$FFA6-$FFA9 Level number in Blue Sphere
$FFAE-$FFAF Zero if locked on to Sonic 3; nonzero otherwise.
$FFB0 Number of chaos emeralds
$FFB1 Number of super emeralds
$FFB2-$FFB8 Array of finished special stages. Each byte represents one stage:
  • 0 - special stage not completed
  • 1 - chaos emerald collected
  • 2 - super emerald present but grayed
  • 3 - super emerald present and activated
$FFBB If this is set to 0, Sonic 3 special stages will run. If it's 1, Sonic & Knuckles special stages will run.
$FFD2-$FFD3 Demo number
$FFD4 Blue Sphere flag
$FFDA Debug mode flag
$FFE2 The flag that determinate if holding A on level select enables debug mode in-game.
$FFE8 2P versus mode flag
$FFEA 2p mode player 1's character
$FFEB 2p mode player 2's character
$FFF0-$FFF1 Must be $4EF9 (68k opcode for long jump) as this address is the vertical interrupt vector
$FFF2-$FFF5 Pointer to the current vertical interrupt routine
$FFF6-$FFF7 Must be $4EF9 (68k opcode for long jump) as this address is the horizontal interrupt vector
$FFF8-$FFFB Pointer to the current horizontal interrupt routine
$FFFC-$FFFF Contains the ASCII string "SM&K" to indicate that the checksum is correct

Object Status Table Format

The starting offset in RAM for this list is $B000. The first object is always player 1, the second is always player 2. Each object is allocated a block of $4A bytes. 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-$03 Pointer to object code. Note that this pointer does not necessarily remain constant for a single object.
$04 Render 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.
  • Bits 3 and 4 are either unused, or their purpose is unknown.
  • Bit 5 is the static mappings flag. If set, this indicates that the mappings pointer for this object points directly to the pieces data for this frame, and implies that the object consists of only one sprite piece.
  • Bit 6 is the compound sprites flag. If set, this indicates that the current object's status table also contains information about other child sprites which need to be drawn using the current object's mappings:
    • Word $16 of the status table indicates the number of child sprites.
    • Following this word is the actual data for each sprite. The format is six bytes per sprite: the first word is the base X position, the next word is the base Y position, the next byte is ignored and the last byte is the mapping frame to display.
  • Bit 7 is the on-screen flag. It will be set if the object is on-screen, and clear otherwise.
$05 Routine number. This is always an even value (i.e. it goes in units of 2)
$06 Height of the object, in pixels.
$07 Width of the object, in pixels.
$08-$09 Sprite priority, in units of $80 (00 = front).
$0A-$0B The lower 11 bits of this represent the starting art block. This is an index into an array of cells; to get the actual address, multiply by $20. Bits 14 and 13 are used to specify the default palette line the sprite uses, and bit 15 is the priority flag - if this is set, the sprite will be given high priority.
$0C-$0F Object's mappings offset.
$10-$11 If the object is Sonic, Tails or Knuckles, 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 X screen coordinate.
$12-$13 If the object is Sonic, Tails or Knuckles, this is the X subpixel playfield coordinate. Otherwise, it's unused.
$14-$15 If the object is Sonic, Tails or Knuckles, 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 the Y screen coordinate.
$16-$17 If the object is Sonic, Tails or Knuckles, this is the Y subpixel playfield coordinate. Otherwise, it's unused.
$18-$19 X speed.
$1A-$1B Y speed.
$1C-$1D Potential speed (inertia).
$1E Height/2
$1F Width/2
$20 Animation number.
$21 Restart animation flag (when $21 is not equal to $20, animation restarts)
$22 Current animation frame to display.
$23 Current frame in animation script.
$24 Animation frame duration (time until next frame).
$25 Animation counter.
$26 Angle. $00 represents flat ground. $80 is the ceiling, $40 is a wall to the left of the object, $C0 is a wall to the right of the object. $20 is a 45 degree slope going down to the right, $E0 is a 45 degree slope going up to the right, and so on.
$27 Second angle (different axis).
$28 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 increments the routine counter, 10 is harm, and 11 seems to be a special thing for the starpole. SSSSSS is the size, lifted from a lookup table in the collision response routine.
$29 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.
$2A Status bitfield.

Counting from the least significant bit:

Bit Hex Description
0 $01 X Orientation. Clear is left and set is right.
1 $02 Y Orientation. Clear is right-side up, and set is upside-down
2 $04 RSS flag, set if the object should remember that it is destroyed. See offsets $3B and $3C below.
3 $08 Set if Sonic is standing on this object.
4 $10 Set if Tails is standing on this object.
5 $20 Set if Sonic is pushing on this object.
6 $40 Set if Tails is pushing on this object.
7 $80 Unknown or unused.
Note that these bits have different meanings for Sonic (see below).
$2B Object shield reaction bitfield.
Bit Hex Description
3 $08 Bounces off shield.
4 $10 Negated by fire shield.
5 $20 Negated by lightning shield.
6 $40 Negated by bubble shield.
$2C Object subtype. For example, the current monitor selected. Has a different meaning for Sonic, Tails and Knuckles.
$2E-2F Used as a timer/counter, upon completion the routine will jump to a pointer in $34.
$34-$37 Stores a code pointer branched to from various routines upon meeting certain conditions.
$3B If the RSS flag is set, this is the bit (0-7) to be cleared when the object is destroyed. See bit 2 of offset $2A above.
$3C-$3D If the RSS flag is set, this is the RAM address to be modified when the object is destroyed. See bit 2 of offset $2A above.
$46-$47 Used by child objects to point to their parent.
$48-$49 RAM location of the object's entry in the object respawn table.
Variables specific to Sonic, Tails and/or Knuckles
Offset Description
$25
  • If Sonic, it's unused.
  • If Tails, it's the number of flying frames remaining / 2.
  • If Knuckles, it's something gliding related.
$2A Status bitfield. Counting from the least significant bit:
Bit Hex Description
0 $01 Orientation. Clear is right and set is left.
1 $02 Set if in the air (jump counts).
2 $04 Set if jumping or rolling.
3 $08 Set if the character 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 bits 1 and 2 are used in the character object as a second routine counter.

$2B Secondary status 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 Fire shield flag.
5 $20 Lightning shield flag.
6 $40 Bubble shield flag.
7 $80 Sets infinite inertia. While the character 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).
$2C 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.
$2D Invert flipping flag.
$2E Object control flag. If bit 7 is not set, the character is under control of another object but can jump out (e.g. being carried by Tails), and if it is, the character is under control of another object and cannot jump out (e.g. LBZ tubes).
$2F Double jump flag. For Sonic:
  • 0 - on ground.
  • 1 - performing an instashield, fire dash, bubble bounce or lightning jump, or has performed the latter three.
  • 2 - has performed an instashield.

For Tails:

  • 0 - on ground.
  • 1 - gravity-affected flying.
  • Above 1 - gravity-less flying.

For Knuckles:

  • 0 - on ground.
  • 1 - gliding.
  • 2 - falling after a glide.
  • 3 - sliding across ground.
  • 4 - wall-climbing.
  • 5 - climbing over a wall and onto the ground.
$30 Number of flip revolutions remaining.
$31 Number of flip revolutions per frame divided by 256.
$32-$33 Horizontal control lock. Counts down to 0, left and right control on the ground is locked unless it's 0. Used for springs and bumpers and falling down slopes.
$34 Remaining invulnerability time. Starts at $78 after Sonic is hit, and is decremented every frame until it reaches $00.
$35 Remaining time of invincibility. Decremented once every eight frames.
$36 Remaining time of Speed Shoes. Decremented once every eight frames.
$37 Some sort of bitfield. If bit 7 of this is set, whenever the player is hit, even if he does not have a shield the game will act like he does and he will just recoil instead of losing rings. If he actually has a shield, however, he will lose it, as the shield check takes precedence over this bit check. Used, for example, by the spinning tops in MGZ.
$38 Character ID:
  • 0 - Sonic
  • 1 - Tails
  • 2 - Knuckles
$39 Character looking up/ducking counter. Starts off at 0 and is incremented each frame the character is looking up/ducking. When this reaches $78, the camera starts to scroll. Reset to 0 upon release of the up/down button.
$3A Angle on ground in front of sprite.
$3B Angle on ground under sprite.
$3C Stick to convex surfaces flag.
$3D Set if charging a Spin Dash.
$3E-$3F Spin Dash counter. Cleared when the Spin Dash 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.
$40 Set if jumping.
$42-43 RAM address of the last object Sonic stood on.
$44 Default height.
$45 Default width.
$46 The bit in the 16x16 entries in the 128x128 block mappings to check for top solidity. Is either $C (for the default collision layer), or $E (for the alternate collision layer).
$47 The bit in the 16x16 entries in the 128x128 block mappings to check for left/right/bottom solidity. Is either $D (for the default collision layer), or $F (for the alternate collision layer).
Variables specific to dynamically reloaded sprites, excluding Sonic, Tails and Knuckles
$34 Previous frame.
$38-$3B Pointer to uncompressed art.
$3C-$3F Pointer to dPLCs.
$40-$41 Address of art in VRAM (the same as starting art block * $20)


Sonic Community Hacking Guide
General
Sonic Music Hacking Guide | SonED2 Manual
Game-Specific
Sonic the Hedgehog (16-bit) | Sonic the Hedgehog (8-bit) | Sonic Eraser | Sonic CD (prototype 510) | Sonic CD | Sonic CD (PC) | Sonic 2 (Nick Arcade prototype) | Sonic 2 (Simon Wai prototype) | Sonic 2 (16-bit) | Sonic 2 (8-bit) | Sonic 2 & Knuckles | Dr. Robotnik's Mean Bean Machine | Sonic Triple Trouble | Sonic 3 | Sonic & Knuckles | Sonic 3 & Knuckles | Sonic & Knuckles Collection | Sonic Crackers | Sonic 3D: Flickies' Island | Chaotix | Sonic R PC | Sonic Jam 6 | Sonic Advance | Sonic Advance 2 | Sonic Advance 3 | Sonic Battle | 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 | Shadow the Hedgehog | Sonic Riders | Sonic the Hedgehog (2006) | Sonic & Sega All-Stars Racing | Sonic Unleashed (Xbox 360/PS3) | Sonic Generations
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 | Subroutine Equivalency List | 68000 Instruction Set | 68000 ASM-to-Hex Code Reference | VDP Documentation | Official Sega 32X Documentation | Official Mega-CD Documentation | Official Sega Mega Drive Documentation