don't click here

ASM Spinball disassembly

Discussion in 'Engineering & Reverse Engineering' started by Andlabs, Oct 1, 2010.

  1. Scrambled Eggman

    Scrambled Eggman

    Worm Bagged Tech Member
    34
    179
    33
    Picking at Sonic Spinball Disassembly
    I now have logical game object data now rendering in the Spintool. Currently I am rendering them using arbitrarily coloured bounding boxes to represent the object type IDs (the bounding boxes accurately represent the collision data in the ROM). These reference the animation assets to determine the sprites to display. The animation asset format, and how it references sprite assets, is one of two remaining issues to solve before levels can be fully modded - the other being understanding the collision tiles, which atm I believe to be 128x128, but I have not quite figured out the format yet.

    • The addresses of these objects arrays are yet again hardcoded per-level. The number of objects is also defined in code, all very similar to how ring objects are defined.
    • Toxic caves appears to have an additional list of animated objects for the scenery such as the "drips" coming from the rocks, which is a separate hardcoded array reference.
    • There are numerous other instantiations that are hardcoded per level, but not all of them are immediately clear as to what or why.
    • Certain collision boxes that are flipped seem to be offset by 1 tile to the left. I'm reasonably sure that there is some code magic that offsets the collision boxes in those scenarios, but I'll need to figure out how that is specified in data, to accurately represent it in Spintool.
    I've attached renders of all levels to the post for reference.

    upload_2025-2-17_0-46-48.png

    spinball_level_0_combined.gif spinball_level_1_combined.gif spinball_level_2_combined.gif spinball_level_3_combined.gif
     
  2. Cooljerk

    Cooljerk

    Professional Electromancer Oldbie
    5,048
    693
    93
    playing spinball actually zoomed out like that with improved physics would be awesome. That's one of my problems with 90's video pinball games on consoles, they didn't let you zoom out the playfield like you could do on, for example, Epic Pinball. Today, when I play modern video pinball games, I always zoom out and show the whole playfield, like in Xenotilt or Demon's Tilt. Being able to see where I'm aiming far away on the board matters more than being upclose to the sonic sprite. I could see having everything zoomed out making the game a lot more fun to play.

    There are some details in that Toxic Caves map that I've never noticed before because I couldn't see the whole board at once, like how the pipes in the tubes on the bottom half of the board that take you to the two rooms in the wings actually curve into the background, instead of just shooting straight up into the rocks. That's a cool detail. It makes sense given how there's a little cave right above the tube that sonic can run through that logically would have had the tube cutting through if it wasn't bending into the background. You don't notice this when it's zoomed in, but they actually accounted for the tube going around the cave in the art. Really cool stuff.

    Just talking outloud here.
     
  3. Bobblen

    Bobblen

    Member
    464
    237
    43
    This is excellent work again, particularly working out that unknown compression scheme for titles! I assume because everything is hardcoded there are no interesting unused object types in those arrays?
     
  4. Scrambled Eggman

    Scrambled Eggman

    Worm Bagged Tech Member
    34
    179
    33
    Picking at Sonic Spinball Disassembly
    The objects defined in the data are not comprehensive as there are hardcoded instantiations of some things. The object types themselves I've not dug deep into yet, but these maps will help me to figure out a good portion of them simply through the context in which they're used.

    I have spotted a few unusual looking objects though, which could potentially be errors or objects with specific behaviours that may not necessarily be intuitive based on the bounding boxes alone. I haven't dug too thoroughly through these yet, but there are definitely interesting things to potentially discover:

    1) In the middle of the beginning play area of Toxic Caves, there is a second object near the central Worm that does not have an apparent purpose. It's coloured the same as the lids for the sewers, so quite possible this is tied to the Worm and so stops it spawning when the slime is drained.

    upload_2025-2-17_9-51-32.png

    2) 2 of the Power Chambers in The Machine have 4 objects dotted around them, yet the one to the right of the bottom play area does not.
    upload_2025-2-17_9-48-7.png upload_2025-2-17_9-48-13.png upload_2025-2-17_9-48-18.png

    3) There are 5 blocks in the data that block the central emerald in Showdown, but we only see 4 in-game:
    upload_2025-2-17_9-46-0.png upload_2025-2-17_9-46-10.png

    4) This unknown object to the right of Robotnik's ship in Showdown:
    upload_2025-2-17_9-44-3.png
     
  5. Bobblen

    Bobblen

    Member
    464
    237
    43
    I believe that last one is the bonus gate for multiball fwiw.

    EDIT - Middle of toxic caves too in fact. There's gates in the top left, top right and middle on that stage.
     
    • Informative Informative x 4
    • Like Like x 1
    • List
  6. Scrambled Eggman

    Scrambled Eggman

    Worm Bagged Tech Member
    34
    179
    33
    Picking at Sonic Spinball Disassembly
    Not been able to work on this as often as I'd like, but I wanted to share a bit of an update.

    Sprite and Animation tables
    I've managed to find the sprite tables for each of the main 4 levels, which defines the offsets for each level's unique sprites, a table for the player, and for a table of global sprites that are common to each level.

    The sprite asset tables locations are hardcoded in the level code. They have the following format:
    Code (Text):
    1. Number of sprites - ushort
    2. Unknown - ushort
    3. Jump table to access each sprite - ushort[Number of Sprites]
    4. Sprite data stored sequentially after this point
    They exist at the following address ranges:
    Code (Text):
    1. 0x000013DC -> 0x0000E479 - Player/Sonic sprites
    2. 0x0000E47A -> 0x00012BOB - Global sprites
    3. 0x00012B0C -> 0x0000665 - Toxic Caves sprites
    4. 0x00020666 -> 0x0002B7A3 - Lava Powerhouse sprites
    5. 0x0002B7A4 -> 0x000318ED - The Machine sprites
    6. 0x000318EE -> 0x0003909D - Showdown sprites
    (this precisely backs nicely onto the beginning of the animation ptr tables)

    Game objects themselves define the sprite table that they wish to reference as part of the object data. Each one has a ptr that references the current animation frame in ROM, and another ptr that references an animation definition which contains data that includes:
    Code (Text):
    1. - Sprite Table ptr
    2. - Starting Animation ptr
    3. - Palette Index
    4. - Frame Time / animation speed (as ticks per frame))
    5. + 2 more unknown bytes
    The level game object tables exist at the following locations. Note these do not include flippers or rings.
    Code (Text):
    1. 0x000C39B0 - Toxic Caves objects
    2. 0x000C1F02 - Lava Powerhouse objects
    3. 0x000C6298 - The Machine objects
    4. 0x000C39B0 - Showdown objects
    The animations are the authoritative source that defines what sprites any object should use. Within animations, typical frames will provide a word that references a sprite index, within the context of the sprite table already defined by the animation header/definition. These two things are not intrinsically linked, meaning that the same animation can be used whilst referencing a different sprite table. This could potentially offer a way to support multiple characters, for example.

    There exists a ptr array to level-specific arrays of animation ptrs. These tables are utilised by the PlayAnimation (0x000E1ABE) function to trigger animations from code.

    Code (Text):
    1. 0x000006FE => Player anim ptrs
    2. 0x00003909E => Toxic Caves anim ptrs
    3. 0x0007E55A => Lava Powerhouse anim ptrs
    4. 0x00098ECA => The Machine anim ptrs
    5. 0x0007ED68 => Showdown anim ptrs
    6.  
    7. 0x000C150C => Ptr array to level-specific arraysof animation ptrs.

    Animations
    This area is still work in progress, but I've begun to get some understanding of the format used here. Animation "frames" have a starting word that specifies the type of command, and the number of bytes that will follow. Normal frames set the first byte to 00, then the following byte is the sprite index within the associated sprite table (defined by the game object).

    Whilst I've identified a lot of the code that decodes the animation frames, I still have more work to do to get Spintool to render these all correctly. I've attached some examples of working animations coming from real data:
    spinbal_anims_2.gif spinbal_anims_3.gif

    Game Object manipulation
    In Sonic Spintool I am now inferring a lot of the sprite data using the animation definition headers in the ROM. Not all objects have a default sprite set (i.e. objects that are not visible by default), however I am able to now render a good portion of level objects with the correct sprites and palettes. I've attached a render of Toxic Caves with some manipulated emerald positions as an example:
    spinball_level_0_combined.gif

    This has however highlighted a major remaining issue, and that is the collision and object activation in Spinball. The visible object positions dictate where we see the object, however there is some secondary collision data that defines where the object collision should occur. This gets a bit screwy however as when the objects are not inside the viewport, the collision will not work even at the defined location - this means the visible object position is somehow associated with the collision test activation, yet is not responsible for actually handling the collisions. And to add to that, the real collision position is responsible for whether the visible object position is actually updated or not. in the screenshot below, you can see that only 2/3 emeralds are visible due to the left emerald being too far away to be considered as something that should update!
    upload_2025-2-28_22-56-16.png

    I have been aware of there being a visible object and a logical/collision object for some time, however the interdependency is a lot more intense than I thought!
    spinball_edits.gif
     
  7. Scrambled Eggman

    Scrambled Eggman

    Worm Bagged Tech Member
    34
    179
    33
    Picking at Sonic Spinball Disassembly
    Level editing
    It is now possible to edit collision and tiles using Sonic Spintool. I've linked some quick and dirty demonstration videos of this working:







    This is a huge personal milestone for me, as being able to edit levels was one of my major goals when I picked up this project. I hope to continue going on to expose more functionality and tools to make it easier to make new hacks and levels going forward!

    Collision & Object culling solved
    I've managed to solve the collision and culling systems for Sonic Spinball. Collisions in Spinball use splines, not pixel-based collision tiles. Shiny stuff first, detail after:

    upload_2025-3-9_0-58-43.png
    upload_2025-3-9_2-5-42.png
    upload_2025-3-9_2-6-13.png upload_2025-3-9_2-7-4.png

    Collision & Culling system detail

    Sonic Spinball uses 3 types of collision types, for general purposes:
    • Bounding Box collision - Generally only used for Emeralds and a few limited object types
    • Radial collision - Most enemies and bumpers opt to use radial collision. Radial collision is also used for level collision as a cheap way of creating a curved surfaces on the inside of a corner
    • Line/Spline collision - The majority of static collision is done using splines (see screenshots). Splines can supply flags to add behaviour such as being able to walk on it, triggering player animations, acting as generic triggers for code, death zones, and are even used as the collision detection for switches next to walls.
    Collision Data format
    There are 3 collision tables for each level (except Showdown, which only uses 2). Each of them has a common pattern whereby a jump table is defined for the offsets of the data for all of the possible sector indices. The data is referenced by calculating the current cell based on the position of the player (or object) and using the cell index to lookup the data offset.

    Spline collision sectors
    Dimensions: 128x128 cell size
    Cells: 256 (16 cells x 16 cells)


    Spline collision sectors contain a list of all of the collision geometry that needs to be polled when the player is within the cell. The splines can extend beyond the bounds of the cell, as to support scenarios where the player is positioned near the edges of the cell where there may be a continuous spline. This means that the same spline will be set multiple times in the whole table, depending on how many cells it intersects.

    Spline collision sectors define first a number of collision objects (ushort) following by that many of the following 12 bytes objects:
    Code (Text):
    1. ushort x_min
    2. ushort y_min
    3. ushort x_max
    4. ushort y_max
    5. ushort flags
    6. ushort additional data
    Splines support collision in 1 direction only. The orientation of the spline can be determined by a right-hand rule i.e. If a spline starts at 0,0 then finishes at 10,0 - it will have collision that faces downwards. If you flip that so it starts at 10,0 and finishes at 0,0 - it will have collision that faces upwards.

    There are flags on the spline data that can define other collision types, such as Radial collision and teleporters. This is something that I need to document further, however it is worth noting the following difference when dealing with an object flagged as a radial collision:
    Code (Text):
    1. ushort x_centre
    2. ushort y_centre
    3. ushort radius
    4. ushort unused
    5. ushort flags
    6. ushort additional data

    Game Object collision sectors

    Dimensions: 128x128 cell size
    Cells: 256 (16 cells x 16 cells)

    Game objects with collision can be defined to only be collidable when the player is within a specific cell. The table uses the same kind of format as the splines, with a jump table (256 entries) with only a ushort for an object count and a list of ushorts that represent the object IDs that should have active collision when within the cell.

    These objects use Bounding Box collision, whose bounds are defined by the anim object instance that is linked in the object definition in the level data.

    Sprite/Camera activation sectors
    Dimensions: 360x264 cell size
    Cells: 48 (6 cells x 8 cells)

    These are visually driven sectors for determining when to load, render or animate sprite objects. These sectors are considered active if any corner of the main viewport intersects with the cell. This effectively means that the animated object will be active in a bbox that is effectively (1000 * 744). If a sprite object is visible when the sector is considered deativated, it will persist on-screen until the player re-enters a sector that will trigger an update again.
    The format is identical to the previous table, however the jump offsets and the IDs only use single bytes, rather than 2-bytes per ids and jump offset.

    The following screenshots show examples of both obj collision sectors and sprite activation sectors for a couple of items in Toxic Caves:
    upload_2025-3-9_1-54-49.png upload_2025-3-9_1-55-14.png upload_2025-3-9_1-56-4.png
     
    Last edited: Mar 9, 2025
    • Like Like x 9
    • Informative Informative x 5
    • Useful Useful x 1
    • List
  8. Bobblen

    Bobblen

    Member
    464
    237
    43
    Amazing. Never thought I'd see the day that Spinball level hacks would be possible!
     
    • Like Like x 2
    • Agree Agree x 1
    • List
  9. Cooljerk

    Cooljerk

    Professional Electromancer Oldbie
    5,048
    693
    93
    Unbelievable stuff, that's one hell of an info dump
     
    • Like Like x 1
    • Agree Agree x 1
    • List
  10. TmEE

    TmEE

    Master of OPL3-SA2/3 Tech Member
    1,760
    35
    28
    Norway, Horten
    VFDgame
    That is super awesome ~
     
    • Like Like x 1
    • Agree Agree x 1
    • List
  11. TDRR

    TDRR

    Member
    The rate at which you're progressing on all these areas is also incredible. I hope to see some hacks soon. Ideally a performance improvement one for the base game first but I ain't complaining either way :p
     
  12. MarkeyJester

    MarkeyJester

    You smash your heart against the rocks Resident Jester
    2,273
    530
    93
    Japan
    This is absolutely crazy!
    Yeah no kidding, honestly, you're uncovering technical sides the community has never seen before. Spline based collision I honestly never would have expected...

    Sonic Spintool sounds a really interesting and exciting tool, can't wait to see a demonstration of its UI being used!
     
    • Agree Agree x 4
    • Like Like x 1
    • List