SCHG:Sonic the Hedgehog 3 & Knuckles/RAM Editing
From Sonic Retro
SCHG: Sonic the Hedgehog 3 & Knuckles |
---|
Main Article |
Art Editing |
Editing Art |
Object Editing |
Editing Objects |
Level Editing |
Editing Levels |
Music Editing |
Editing Music |
RAM Editing |
Editing RAM |
Sonic & Knuckles Collection |
Sonic & Knuckles Collection |
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. |
$E500-$E5FF | Position table for player 1 |
$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 spindash 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 spindash 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 |
$EEC6 | Level property (like killer wall in HCZ2 or avalanche in ICZ1) |
$EF49 | Flag which determines whether the second player in a 2P versus game is player-controlled or just a "ghost" of the first player. |
$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:
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. |
$F648-$F649 | Current water level. Should be a valid Y-axis value. Remember, the top of the level is $0000. |
$F64C | Water on: seems to be a copy of $F730. |
$F65E | Super Sonic palette counter. Decremented with every frame. How it works, exactly, is not known. |
$F65F | Sets the rotating palette for Super Sonic. |
$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. |
$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. |
$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. |
$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 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. |
$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's max speed |
$FEC2-$FEC3 | Tails's acceleration |
$FEC4-$FEC5 | Tails's deceleration |
$FEC6 | Tails's 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 | Perfect counter (leftover from S2). No perfect bonus is 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) |
$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:
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:
Like the decompression queue, this can also only store 4 pieces at a time. |
$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 |
$FFB0 | Number of chaos emeralds |
$FFB1 | Number of super emeralds |
$FFB2-$FFB8 | Array of finished special stages. Each byte represents one stage:
|
$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 |
$FFDA | Debug mode flag |
$FFE8 | 2P versus mode flag |
$FFEA | 2p mode player 1's character |
$FFEB | 2p mode player 2's character |
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:
| |||||||||||||||||||||||||||
$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:
| |||||||||||||||||||||||||||
$12-$13 | If the object is Sonic, Tails or Knuckles, this is the X subpixel playfield coordinate. Otherwise:
| |||||||||||||||||||||||||||
$14-$15 | If the object is Sonic, Tails or Knuckles, this is the Y playfield coordinate. Otherwise:
| |||||||||||||||||||||||||||
$16-$17 | If the object is Sonic, Tails or Knuckles, this is the Y subpixel playfield coordinate. Otherwise:
| |||||||||||||||||||||||||||
$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. | |||||||||||||||||||||||||||
$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:
| |||||||||||||||||||||||||||
$2B | Object shield reaction bitfield.
| |||||||||||||||||||||||||||
$2C | Object subtype. For example, the current monitor selected. Has a different meaning for Sonic, Tails and Knuckles. | |||||||||||||||||||||||||||
$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 |
| |||||||||||||||||||||||||||
$2A | Status bitfield. Counting from the least significant bit:
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.
| |||||||||||||||||||||||||||
$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:
For Tails:
For Knuckles:
| |||||||||||||||||||||||||||
$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:
| |||||||||||||||||||||||||||
$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 spindash. | |||||||||||||||||||||||||||
$3E-$3F | 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. | |||||||||||||||||||||||||||
$40 | Set if jumping. | |||||||||||||||||||||||||||
$42-43 | RAM address of the last object Sonic stood on. | |||||||||||||||||||||||||||
$44 | Default height. | |||||||||||||||||||||||||||
$45 | Default width. | |||||||||||||||||||||||||||
$46 | Current collision plane/layer, seems to always be $C or $E. | |||||||||||||||||||||||||||
$47 | Unknown, seems to always be objstatus($46)+1, affects collision. | |||||||||||||||||||||||||||
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) |