Actions

SCHG

Sonic the Hedgehog 2 (16-bit)/RAM Editing

From Sonic Retro

(Redirected from SCHG:Sonic 2/RAM Editing)
Sonic Community Hacking Guide
Sonic the Hedgehog 2 (16-bit)
Art
Objects
Levels
Text
Music
RAM
Miscellaneous

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 Git label Description
$0000 - $7FFF Chunk_Table Metablock table
$8000 - $8FFF Level_Layout Level layout
$9000 - $A9FF Block_Table Block table
$AA00 - $A?FF Decomp_Buffer Decompression buffer
$AC00 - $AFFF Sprite_Table_Input Sprite table input. Intermediate storage for sprite attribute table data destined for $DD00 or $F800.
$B000 - $D5FF Object_RAM Object attribute table
$D600 - $D8FF Primary_Collision Primary collision index
$D900 - $DBFF Secondary_Collision Secondary collision index
$DC00 - $DCFB VDP_Command_Buffer VDP command buffer. Stores up to 18 sets of queued up VDP commands to be issued later.
$DCFC - $DCFF VDP_Command_Buffer_Slot VDP command buffer free slot. Stores the address of the first available empty place in the VDP command buffer.
$DD00 - $DF7F Sprite_Table_2 Sprite attribute table buffer for the bottom split screen in 2-player mode.
$E000 - $E3FF Horiz_Scroll_Buf Horizontal scroll buffer
$E400 - $E4FF Sonic_Stat_Record_Buf Sonic's statistic recording buffer, used by Tails' AI.
$E500 - $E5FF Sonic_Pos_Record_Buf Sonic's invincibility star position table
$E600 - $E6FF Tails_Pos_Record_Buf Tails' invincibility star position table
$E800 - $EDFF Ring_Positions Ring Layout
$EE00-$EE01 Camera_X_pos Camera's X position, as measured from the top left corner of the Act.
$EE04-$EE05 Camera_Y_pos Camera's Y position from the same point.
$EE06-$EE0B Unknown
$EE0C-$EE0D Camera_BG_Y_pos Variable used by the software scroll managers. Its exact purpose is not known.
$EE0E-$EEC5 Unknown
$EE20-$EE21 Camera_X_pos_P2 Camera's X position, as measured from the top left corner of the Act, for player 2.
$EE24-$EE25 Camera_Y_pos_P2 Camera's Y position from the same point, for player 2.
$EEC6-$EEC7 Camera_Max_Y_pos Screen Y end location for Sonic; the maximum value for camera Y position.
$EEC8-$EEC9 Camera_Min_X_pos Screen X start location for Sonic; minimum value for camera X position. Should be 0.
$EECA-$EECB Camera_Max_X_pos Screen X end location for Sonic; should be at least $30 less than the end of the level, otherwise, Sonic will fall off the screen.
$EECC-$EECD Camera_Min_Y_pos 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 Camera_Max_Y_pos_now Screen Y end location for Sonic; the maximum value for camera Y position. Like $EEC6, but changes slowly instead of instantly when the level Y boundary changes.
$EED2-$EED3 Sonic_Pos_Record_Index Index into Sonic's statistics recording buffer and invincibility star position table.
$EED6-$EED7 Tails_Pos_Record_Index Index into Tails' invincibility star position table.
$EED8 Camera_Y_pos_bias Camera Y position bias.
$EEDA Camera_Y_pos_bias_P2 Camera Y position bias for Tails.
$EEDF Dynamic_Resize_Routine Routine counter for Dynamic Screen Resizing. (Dynamic Level Events)
$EEF8-$EEF9 Tails_Min_X_pos Screen X start location for Tails; minimum value for camera X position. Should be 0.
$EEFA-$EEFB Tails_Max_X_pos Screen X end location for Tails; should be at least $30 less than the end of the level, otherwise, Tails will fall off the screen.
$EEFE-$EEFF Tails_Max_Y_pos Screen Y end location for Tails; the maximum value for camera Y position.
$F000-$F07F Underwater_target_palette Underwater target palette.
$F080-$F0FF Underwater_palette Underwater palette.
$F100-$F5FF Unused
$F600 Game_Mode Master level trigger. Tells the game what it should be doing. Values:
  • $00 - GameModeID_SegaScreen - Sega logo
  • $04 - GameModeID_TitleScreen - Title screen
  • $08 - GameModeID_Demo - Demo (return to title screen at 27 seconds)
  • $0C - GameModeID_Level - Normal level (Level loop, when it has been loaded)
  • $10 - GameModeID_SpecialStage - Special stage
  • $14 - GameModeID_ContinueScreen - Continue screen
  • $18 - GameModeID_2PResults - 2P vs. result
  • $1C - GameModeID_2PLevelSelect - 2P vs. level select
  • $20 - GameModeID_EndingSequence - Game end sequence
  • $24 - GameModeID_OptionsMenu - Options menu
  • $28 - GameModeID_LevelSelect - Level select

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 Ctrl_1_Held_Logical 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 Ctrl_1_Press_Logical In-game Controller 1 pressed state. Same as F602, but only tells which buttons are being pressed newly this frame.
$F604 Ctrl_1_Held 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 Ctrl_1_Press Same as $F604, but only tells which buttons are being pressed newly this frame.
$F606 Ctrl_2_Held Same as $F604, but for Controller 2.
$F607 Ctrl_2_Press Same as $F606, but only tells which buttons are being pressed newly this frame for Controller 2.
$F614 Demo_Time_left Demo time left & Time until demo starts from title screen.
$F624-$F625 Hint_counter_reserve Always contains a VDP command consisting of a write to register $0A (H-Int register). This controls which line H-Int occurs on, and is executed every V-Int.
$F62A Vint_routine V-Int routine to run. Goes in units of 2, like most other routine counters.
$F636 RNG_seed RNG seed (used for pseudo-random number generation).
$F63A-$F63B Game_paused Game paused flag.
$F640 DMA_data_thunk DMA data thunk: every final DMA command word gets written here and copied back out, as required by the Megadrive hardware.
$F648-$F649 Water_Level_2 Current water level. Should be a valid Y-axis value. Remember, the top of the level is $0000.
$F64C Water_on Water on: seems to be a copy of $F730.
$F64D Water_routine Water routine counter
$F64E Water_fullscreen_flag Flag which is set when Sonic is fully submerged in water and the underwater palette has to be displayed throughout the entire screen
$F64F Do_Updates_in_H_int Flag which is set when H-Int is set to occur at a line above line $5C. The only effect this has is that DemoTime is called from inside H-Int instead of from inside V-Int
$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 Palette_timer Super Sonic palette counter. Decremented with every frame. How it works, exactly, is not known.
$F65F Super_Sonic_palette Sets the rotating palette for Super Sonic.
$F66A Ctrl_2_Held_Logical In-game Controller 2 held state. Same as $F602, but for controller 2
$F66B Ctrl_2_Press_Logical In-game Controller 2 pressed state. Same as $F66A, but only tells which buttons are being pressed newly this frame.
$F66C-$F66D Sonic_Look_delay_counter Sonic looking up/ducking counter. Starts off at 0 and is incremented each frame Sonic is looking up/ducking. When this reaches $78, the camera starts to scroll. Reset to 0 upon release of the up/down button.
$F66E-$F66F Tails_Look_delay_counter Same as above, only for player 2.
$F670-$F671 Super_Sonic_frame_count Super Sonic ring drain counter. This is set to 60 ($3C). After each frame, the code subtracts 1. One ring is removed when this counter reaches zero; in other words, each second.
$F680-$F6DF Plc_Buffer 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 Plc_Buffer_Only_End The address in ROM of the decompression routine to be used for the art
$F6E4-$F6F7 Plc_Buffer_Reg4 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 Plc_Buffer_Reg18 The total number of tiles left to be decompressed for the current piece of art
$F6FA-$F6FB Plc_Buffer_Reg1A 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 Tails control counter. Counts how long until the CPU takes control.
$F704-$F705 Tails_respawn_counter Tails respawn counter.
$F708-$F709 Tails_CPU_routine Tails CPU routine.
$F70A-$F70B Tails_CPU_target_x 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 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 Tails interact ID. Object ID of last object Tails stood on.
$F710 Rings_manager_routine Routine counter for the rings manager.
$F711 Level_started_flag Level started flag. Set to 1 as soon as the player first gets control in the level.
$F712 Ring_start_addr Address (inside the ring layout table) of the first ring whose X position is greater than or equal to the current camera X value.
$F714 Ring_end_addr Address (inside the ring layout table) of the first ring whose X position is greater than or equal to the current camera X value + $150
$F716 Ring_start_addr_P2 $F712 for Player 2.
$F718 Ring_end_addr_P2 $F714 for Player 2.
$F72C Dirty_flag Dirty flag. Setting this causes the whole screen to redraw (once) instead of only the part that's scrolling into the screen.
$F730 Water_flag 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.
$F732-$F733 Demo_button_index_2P Demo button index for Player 2.
$F734 Demo_press_counter_2P Frames remaining until next button press in a demo for Player 2.
$F760-$F761 Sonic_top_speed Sonic's top speed
$F762-$F763 Sonic_acceleration Sonic's acceleration
$F764-$F765 Sonic_deceleration Sonic's deceleration
$F766 Sonic_LastLoadedDPLC Sonic's current mapping frame number.
$F76C Obj_placement_routine Object placement function's subroutine counter
$F76E-$F76F Camera_X_pos_last Unknown
$F770-$F773
$F774-$F777
$F778-$F77B
$F77C-$F77F
Obj_load_addr_right Sprite loading addresses. Tells the game where in the ROM to get sprite info.
$F780-??? unk_F780 Something
$F78C-$F78D Camera_X_pos_last_P2 Unknown
$F790-$F791 Demo_button_index Demo button index for Player 1.
$F792 Demo_press_counter Frames remaining until next button press in a demo for Player 1.
$F796-$F799 Collision_addr Pointer to primary collision data in RAM.
$F7A7 Boss_defeated_flag Boss defeated flag. Set to $1 once boss is defeated.
$F7AA Current_Boss_ID Seems to be clear during normal play, but set to some value during a boss fight.
$F7CC Control_Locked Controller lock. Normally the player object overwrites $F602 with the actual controller state, but setting this flag will prevent that. Used when the game will supply its own movement script.
$F7D0-$F7D1 Chain_Bonus_counter 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 Bonus_Countdown_1 Time bonus counter at the end of level result screen/Player 1 ring bonus counter at the end of special stage result screen
$F7D4-$F7D5 Bonus_Countdown_2 Ring bonus counter at the end of level result screen/Player 2 ring bonus counter at the end of special stage result screen
$F7D6 Update_Bonus_score Flag determines if the bonus counters need to be updated.
$F7DA-$F7DB Camera_X_pos_coarse 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_Table Sprite attribute table buffer.
$FA80-$FAFF Unused (although due to the way Sonic 2's BuildSprites is designed, it is possible for the sprite attribute table buffer to spill over into this area)
$FB00-$FB7F Normal_palette Palette.
$FB80-$FBFF Target_palette Target palette.
$FC00 - $FCFF Object_Respawn_Table Object respawn table
$FE00 System_Stack 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_Inactive_flag Level restart flag.
$FE04-$FE05 Timer_frames Level frame timer.
$FE06 Debug_object Object currently selected in debug mode.
$FE08-$FE09 Debug_placement_mode Object placement mode flag.
$FE10 Current_Zone The current Zone. This is the value assigned to the Zone, not its position in the level list.
$FE11 Current_Act Act number
$FE12 Life_count Number of lives.
$FE16 Current_Special_Stage Current special stage.
$FE17 Current_Special_Act Current segment in special stage.
$FE18 Continue_count Number of continues.
$FE19 Super_Sonic_flag 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 Time_Over_flag Flag which is set when Player 1 has a time over
$FE1B Extra_life_flags This bitfield tells the game if the player has collected extra lives from rings.
  • Bit 0 - 100 rings life collected
  • Bit 1 - 200 rings life collected
  • Bit 2 - Unused
  • Bit 3 - Unused
  • Bit 4 - Unused
  • Bit 5 - Unused
  • Bit 6 - Unused
  • Bit 7 - Unused
$FE1C Update_HUD_lives Flag determines if the lives counter needs to be updated
$FE1D Update_HUD_rings Flag determines if the rings counter needs to be updated
$FE1E Update_HUD_timer Flag determines if the timer needs to be updated
$FE1F Update_HUD_score Flag determines if the score counter needs to be updated
$FE20-$FE21 Ring_count Ring count. This is also applied in Special Stages.
$FE23 Timer_minute Minutes on clock. Should not go above $09, or the clock will look like shit.
$FE24 Timer_second Seconds. This one shouldn't go above $3B, for the same reason.
$FE25 Timer_frame Frames. I don't know what'll happen if this goes out of range, but it's probably not good.
$FE26-$FE29 Score Score (divided by 10)
$FE30 Last_star_pole_hit Greatest reference number of passed star poles
$FEA0 Logspike_anim_counter Log-spike animation counter.
$FEA1 Logspike_anim_frame Log-spike animation frame.
$FEA2 Rings_anim_counter Rings animation counter.
$FEA3 Rings_anim_frame Rings animation frame.
$FEA6 Ring_spill_anim_counter Spilling rings animation counter.
$FEA7 Ring_spill_anim_frame Spilling rings animation frame.
$FEC0-$FEC1 Tails_top_speed Tails' max speed
$FEC2-$FEC3 Tails_acceleration Tails' acceleration
$FEC4-$FEC5 Tails_deceleration Tails' deceleration
$FEC6 Life_count_2P Tails' lives in 2P mode
$FEC7 Extra_life_flags_2P This bitfield tells the game if the player has collected extra lives from rings. Used for Tails in 2P mode.
  • Bit 0 - 100 rings life collected
  • Bit 1 - 200 rings life collected
  • Bit 2 - Unused
  • Bit 3 - Unused
  • Bit 4 - Unused
  • Bit 5 - Unused
  • Bit 6 - Unused
  • Bit 7 - Unused
$FEC8 Update_HUD_lives_2P Flag determines if the lives counter needs to be updated. Used for Tails in 2P mode.
$FEC9 Update_HUD_rings_2P Flag determines if the rings counter needs to be updated. Used for Tails in 2P mode.
$FECA Update_HUD_timer_2P Flag determines if the timer needs to be updated. Used for Tails in 2P mode.
$FECC Time_Over_flag_2P Flag which is set when Player 2 has a time over.
$FED0 Ring_count_2P Tails' rings in 2P mode.
$FED3 Timer_minute_2P Minutes on clock for Player 2. Should not go above $09, or the clock will look like shit.
$FED4 Timer_second_2P Seconds for Player 2. This one shouldn't go above $3B, for the same reason.
$FED5 Timer_frame_2P Frames for Player 2. I don't know what'll happen if this goes out of range, but it's probably not good.
$FED6-$FED9 Score_2P Score for Player 2 (divided by 10).
$FEF0-$FEF1 Rings_Collected Rings collected since level load. Resets if you enter a Special stage. Starts recounting from 0 when level is reentered. Unknown use.
$FEF8 Loser_Time_Left Seconds remaining for level completion in 2P versus mode.
$FEF9 Centiseconds remaining for level completion in 2P versus mode.
$FF10 Results_Screen_2P The type of 2P versus results screen being displayed:
  • 0 is end of act results screen
  • 1 is end of zone results screen
  • 2 is end of game results screen (that is when all the zones are completed)
  • 3 is end of special stage results screen
  • 4 is end of all three special stages results screen
$FF20-$FF39 Results_Data_2P 2P results array. The format is 6 bytes per zone (2 per act, the 3rd act is the special stage). The first byte for each act is the number of "wins" for Player 1, while the second byte is the number of "wins" for Player 2. The special stage uses 2 extra bytes: the first is the number of special stages won by Player 1, the second is the number of special stages won by Player 2.
$FF40-$FF41 Perfect_rings_left Number of rings to collect before a perfect is scored
$FF70-$FF71 Player_mode Player in game (at the start of the game, $FF72 is copied over to $FF70, so they're mostly identical)
$FF72-$FF73 Player_option Player option (Sonic and Tails - 0, Sonic alone - 1, Tails alone - 2)
$FF74-$FF75 Two_player_items 2P mode items (all kinds items - 0, teleport only - 1)
$FF80-$FF81 LevSel_HoldTimer Timer which regulates the speed at which the level select selection changes if up or down is held down. The timer is initialized to $B, and 1 is subtracted from it every frame. If the timer is positive, and the up or down button is being held down, the level select screen selection will not be changed. Only when the timer reaches $FFFF (i.e. -1) is the selection changed. The timer is reset to $B in case of it becoming negative or if up/down is released and pressed again.
$FF82-$FF83 Level_select_zone Item in level select menu that's selected (set to 16 to see the HPZ picture)
$FF84-$FF85 Sound_test_sound Sound currently selected in sound test; value retained when options menu is exited
$FF86 Title_screen_option Selection on Title Screen
$FF88 Current_Zone_2P Selection on 2 Player Level Select Menu
$FF89 Current_Act_2P Act number in 2P versus mode
$FF8A-$FF8B Two_player_mode_copy Copy of $FFD8 (no idea why there are 2 copies)
$FF8C Options_menu_box Box slected in options menu
$FF8E-$FF8F Total_Bonus_Countdown Total bonus counter at the end of level result screen/emerald bonus counter at the end of special stage result screen
$FF90-$FF91 Level_Music Zone music currently playing. Used for quick access when switching music.
$FF92-$FF93 Bonus_Countdown_3 Perfect bonus counter at the end of level result screen
$FF98-$FF99 Game_Over_2P 2P versus mode restart game flag. Set when a game over occurs in 2P versus mode, causes 2P versus results for the current session (from $FF20 to $FF37, last two bytes of result data are skipped) to be wiped, resetting the entire session.
$FFB0 Got_Emerald Special stage completed flag
$FFB1 Emerald_count Number of emeralds collected so far
$FFB2-$FFB8 Got_Emeralds_array Array of finished special stages. Each byte represents one stage.
$FFC0-$FFC3 Next_Extra_life_score Next score at which an extra life will be awarded to Player 1.
$FFC4-$FFC7 Next_Extra_life_score_2P Next score at which an extra life will be awarded to Player 2.
$FFC8-$FFC9 Level_Has_Signpost Level signpost flag.
$FFD0 Level_select_flag Level select flag
$FFD1 Slow_motion_flag Slow motion flag
$FFD4-$FFD5 Correct_cheat_entries Number of correct sounds that have been played for the level select or debug codes
$FFD6-$FFD7 Correct_cheat_entries_2 Same as $FFD4, except it's for the 14 continues or 7 emeralds codes
$FFD8-$FFD9 Two_player_mode 2P mode flag
$FFE1 SFX_to_play Play specified sound effect. Not sure how it works.
$FFE4 Music_to_play_2 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 Demo mode flag
$FFFA Debug_mode_flag Debug mode flag
$FFFC-$FFFF Checksum_fourcc Set to 'init' (69 6E 69 74) once the checksum routine has run.

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. The next few slots are reserved for certain special objects (e.g. title cards), and the slots available for general use start from $B400. Each object is allocated a block of $40 bytes. The beginning of a block is used 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 Git label Description
$00 id Object number. See the IDs at the object pointer list. Writing an ID over an empty object's memory requests that object to be loaded.
$01 render_flags 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.
  • Bits 2 and 3 are the coordinate system flags. If both bits are clear, the object will be positioned by absolute screen coordinates. This is used for things like the HUD and menu options. If either bit is set, the object will be positioned by the playfield coordinates, i.e. where it is in a level.
  • Bit 4 is the assume pixel height flag. If clear, the pixel height of each object is assumed to be 32 pixels, otherwise the y-radius of the object (byte $16 of its status table) is also taken to be its pixel height.
  • 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, and also signifies that certain bytes of its status table have different meanings:
    • Byte $B is the mapping frame to display.
    • Byte $E is the pixel width of the object.
    • Byte $14 is the pixel height of the object.
    • Byte $F is the number of child sprites to draw.
    • From byte $10 onwards is the actual data for each child 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.
$02-$03 art_tile 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.
$04-$07 mappings Object's mappings offset
$08-$09 x_pos, x_pixel 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 X screen coordinate.
$0A-$0B x_sub, y_pixel If the object is Sonic or Tails, this is the X subpixel playfield coordinate. Otherwise:
  • If in playfield positioning mode, it is unused.
  • If in screen positioning mode, it's the Y screen coordinate.
$0C-$0D y_pos 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 y_pixel If the object is Sonic or Tails, this is the Y subpixel playfield coordinate. Otherwise:
  • It's unused.
$10-$11 x_vel X speed
$12-$13 y_vel Y speed
$14-$15 inertia Potential speed (inertia).
$16 y_radius Height/2
$17 x_radius Width/2
$18 priority Sprite priority (00 = front).
$19 width_pixels Width of the object, in pixels
$1A mapping_frame Current animation frame to display.
$1B anim_frame Current frame in animation script.
$1C anim Animation number.
$1D next_anim Restart animation flag (when $1D is not equal to $1C, animation restarts)
$1E anim_frame_duration Animation frame duration (time until next frame).
$20 collision_flags 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 sets the routine counter to $4, 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.
$21 collision_property 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 status 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 Unknown or unused.
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).
$23 respawn_index 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 Routine counter.
$25 routine_secondary Second routine counter. This is used for some of the more complicated objects.
$26 angle Angle.
$27 flip_angle Second angle (different axis).
$28 subtype Object subtype. For example, the current monitor selected. See the Object List above for values. Has a different meaning for Sonic and Tails.
$3E-$3F parent Parent. Address of the object that spawned this one. Has a different meaning for orphans like Sonic and Tails.
Sonic and Tails-specific variables
Offset Hg label Description
$22 status Special bitfield. Counting from the least significant bit:
Bit Hex Description
0 $01 Orientation. Clear is right and set is left.
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 bits 1 and 2 are used in the character object as a second routine counter.

$28 air_left 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.
$29 flip_turned Invert flipping flag.
$2A obj_control Object control flag. Set to 1 if Sonic is under control of another object but can jump out (e.g. flippers), and set to $81 if Sonic is under control of another object and cannot jump out (e.g. CPZ tubes).
$2B status_secondary 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).
$2C flips_remaining Number of flip revolutions remaining.
$2D flip_speed Number of flip revolutions per frame divided by 256.
$2E-$2F move_lock 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.
$30-$31 invulnerable_time Remaining invunerability time. Starts at $0078 after Sonic is hit, and seems to decrement every frame until it reaches $0000.
$32-$33 invincibility_time Remaining time of invincibility.
$34-$35 speedshoes_time Remaining time of Speed Shoes.
$36 next_tilt Angle on ground in front of sprite.
$37 tilt Angle on ground under sprite.
$38 stick_to_convex Stick to convex surfaces flag (unused in Sonic 2 but fully functional).
$39 spindash_flag Set if charging a Spin Dash.
$3A-$3B spindash_counter 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.
$3C jumping Set if jumping.
$3D interact RAM address of the last object Sonic stood on, minus $B000 and divided by $40.
$3E top_solid_bit 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).
$3F lrb_solid_bit 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).


References


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