s3k-disasm-guide

star 6

This skill provides guidance on finding, identifying, and interpreting items in the Sonic 3 & Knuckles disassembly (`docs/skdisasm/`).

jamesj999 By jamesj999 schedule Updated 2/23/2026

title: s3k-disasm Navigation Guide description: Reference for navigating the Sonic 3 and Knuckles disassembly, choosing S&K-side addresses, and using RomOffsetFinder with S3K data.

s3k-disasm Navigation Guide

This skill provides guidance on finding, identifying, and interpreting items in the Sonic 3 & Knuckles disassembly (docs/skdisasm/).

S&K vs S3 ROM Halves — Address Selection Rule

The locked-on ROM ("Sonic and Knuckles & Sonic 3") contains two halves:

  • S&K half (0x000000–0x1FFFFF): The primary S&K code and data — this is what the engine runs
  • S3 half (0x200000–0x3FFFFF): The Sonic 3 standalone code and data

Many shared assets (art, mappings, palettes) exist in both halves with identical binary content. **Always use S&K-side addresses (< 0x200000)** for all ROM constants. The S3 copies at >= 0x200000 are not referenced by the S3KL code path.

When RomOffsetFinder returns multiple results for the same label — one from sonic3k.asm (S&K) and one from s3.asm (S3) — always use the sonic3k.asm result. Similarly, when reading disassembly source, prefer sonic3k.asm over s3.asm for object code, as the S3KL versions may contain zone-specific overrides (e.g., FBZ art tile) absent from the S3 version.

Directory Structure

S3K is organized very differently from S1/S2 — per-zone directories under Levels/:

Directory Contents Notes
Levels/{ZONE}/ Per-zone data AIZ, HCZ, MGZ, CNZ, FBZ, ICZ, LBZ, MHZ, SOZ, LRZ, HPZ, SSZ, DEZ, DDZ
Levels/{ZONE}/KosinskiM Art/ Kosinski Moduled compressed art Primary art compression type
Levels/{ZONE}/Nemesis Art/ Nemesis compressed art Secondary art compression
Levels/{ZONE}/Tiles/ Raw tile patterns Uncompressed tile data
Levels/{ZONE}/Blocks/ 16x16 block mappings Per-zone chunk definitions
Levels/{ZONE}/Chunks/ 128x128 chunk mappings Per-zone block definitions
Levels/{ZONE}/Layout/ Level layouts 1.bin, 2.bin per act
Levels/{ZONE}/Object Pos/ Object placement Per-act object positions
Levels/{ZONE}/Ring Pos/ Ring placement Per-act ring positions
Levels/{ZONE}/Palettes/ Zone palettes Zone-specific color data
Levels/{ZONE}/Collision/ Collision data Zone collision indices
Levels/{ZONE}/Misc Object Data/ Zone-specific object maps/anims Map - Name.asm, Anim - Name.asm
General/Sprites/{NAME}/ Shared sprite data Art/, Map, DPLC, Anim files
Sound/ Z80 sound driver SMPS audio data

Key Source Files

File Contents
sonic3k.asm Main assembly source (~203K lines, all object code inline)
sonic3k.constants.asm RAM addresses, object field names
sonic3k.macros.asm Assembly macros
s3.asm Sonic 3 standalone variant

Compression Types

Type Directory/Label Suffix Tool Flag Description
Kosinski Moduled KosinskiM Art/, _KosM suffix kosm Primary art compression (dominant in S3K)
Nemesis Nemesis Art/, ArtNem_ prefix nem Secondary art compression
Kosinski ArtKos_ prefix kos Used for some shared data
Uncompressed Various .bin bin Raw tile data, palettes

Note: S3K encodes compression type in the label suffix (e.g., AIZ1_8x8_Primary_KosM) rather than the file extension. The RomOffsetFinder tool auto-infers the correct type from the label when the file extension is .bin.

Finding Items with RomOffsetFinder

Important: All RomOffsetFinder commands for Sonic 3 & Knuckles require the --game s3k flag.

Search Command (Most Common)

# Search by partial name
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k search AIZ" -q

# Search for zone-specific items
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k search MHZ" -q

# Search for palettes
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k search Pal_" -q

# Search for specific object art
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k search ArtKosM_" -q

List Command

# List all Nemesis-compressed items
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k list nem" -q

# List all Kosinski Moduled items
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k list kosm" -q

# List all compression types
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k list" -q

Verify and Export

# Verify a single offset
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k verify ArtNem_TitleScreenText" -q

# Batch verify all Nemesis items
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k verify-batch nem" -q

# Export as Java constants
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k export nem ART_" -q

Search ROM Binary

Use search-rom to find inline assembly data (pointer tables, animation scripts, AniPLC tables, dc.w/dc.b directives) that have no binary file — the search and find commands only work with binclude items. This is especially useful for S3K where many data structures are inline.

# Search for known hex byte pattern (spaces optional)
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k search-rom \"0002 FF2A 2940 5CC0\"" -q

# Restrict search to a specific ROM range
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k search-rom \"0002\" 0x28000 0x29000" -q

Label Naming Conventions

S3K uses different label prefixes from S1 and S2:

S3K Prefix Meaning Example
ArtKosM_ Kosinski Moduled art ArtKosM_AIZEndBoss
ArtNem_ Nemesis art ArtNem_TitleScreenText
ArtKos_ Kosinski art ArtKos_LevelResults
Pal_ Palette Pal_AIZ1, Pal_Sonic
AnPal_ Animated palette AnPal_AIZ1
Obj_ Object code Obj_AIZEndBoss
Map_ / Map - Sprite mappings In General/Sprites/ or Misc Object Data/
DPLC_ Dynamic Pattern Load Cue In General/Sprites/
Anim_ / Anim - Animation scripts In General/Sprites/ or Misc Object Data/
PLC_ Pattern Load Cue PLC_AIZ

Comparison with S1 and S2

S3K Prefix S2 Equivalent S1 Equivalent
ArtKosM_ (no equivalent) (no equivalent)
ArtNem_ ArtNem_ Nem_
ArtKos_ ArtKos_ Kos_
Pal_ Pal_ Pal_
AnPal_ (inline cycling) (inline cycling)
Obj_ Obj_ ObjXX / Obj_
Map_ MapUnc_ Map_
DPLC_ (inline) DPLC_

Zone Abbreviations

Abbrev Full Name Zone ID
AIZ Angel Island Zone 0x00
HCZ Hydrocity Zone 0x01
MGZ Marble Garden Zone 0x02
CNZ Carnival Night Zone 0x03
FBZ Flying Battery Zone 0x04
ICZ Icecap Zone 0x05
LBZ Launch Base Zone 0x06
MHZ Mushroom Hill Zone 0x07
SOZ Sandopolis Zone 0x08
LRZ Lava Reef Zone 0x09
SSZ Sky Sanctuary Zone 0x0A
DEZ Death Egg Zone 0x0B
DDZ Doomsday Zone 0x0C
HPZ Hidden Palace Zone 0x0D

Bonus/Special Zones

Abbrev Full Name Notes
Gumball Gumball Machine Bonus stage
Pachinko Pachinko Bonus stage
Slots Slot Machine Bonus stage
CGZ Chrome Gadget Zone S3-only
BPZ Balloon Park Zone S3-only
DPZ Desert Palace Zone S3-only
EMZ Endless Mine Zone S3-only
ALZ Azure Lake Zone S3-only competition

Dual Object Pointer Tables (Zone-Set System)

S3K uses two separate object pointer tables that remap many IDs depending on the zone:

Set Disasm Name Engine Name Zones File
SK Set 1 Sprite_Listing3 S3KL (S3K-Level Object Set) 0-6 (AIZ through LBZ) Levels/Misc/Object pointers - SK Set 1.asm (256 entries)
SK Set 2 Sprite_ListingK SKL (SK-Level Object Set) 7-13 (MHZ through DDZ) Levels/Misc/Object pointers - SK Set 2.asm (185 entries)

Selection logic (sonic3k.asm line ~37411): Purely zone-based, NOT game-mode-based. Zones 0-6 use S3KL, zones 7+ use SKL.

The same numeric object ID can map to completely different objects:

  • 0x03: AIZHollowTree (S3KL) vs MHZTwistedVine (SKL)
  • 0x8F: CaterKillerJr (S3KL) vs Butterdroid (SKL)
  • 0x9C: Spiker (S3KL) vs LRZRockCrusher (SKL)

Many IDs are shared between both sets (Ring, Monitor, PathSwap, Spring, Spikes, etc.).

Engine support: S3kZoneSet enum (S3KL/SKL), Sonic3kObjectRegistry.getPrimaryName(id, zoneSet), and Sonic3kObjectProfile with per-level name/badnik/boss resolution.

Object Code Organization

Unlike S1 (separate files per object) and S2 (inline in s2.asm), S3K objects are:

  • Inline in sonic3k.asm as Obj_ routines
  • Zone-specific objects appear near their zone's code section
  • Shared sprites have data in General/Sprites/{Name}/ (Art, Map, DPLC, Anim)
  • Zone-specific maps/anims are in Levels/{ZONE}/Misc Object Data/

Finding Object Code

# Search for object by name in the main ASM
grep -n "Obj_AIZEndBoss" docs/skdisasm/sonic3k.asm

# Search for all objects in a zone
grep -n "Obj_AIZ" docs/skdisasm/sonic3k.asm

# Find object sprite data
ls docs/skdisasm/General/Sprites/
ls "docs/skdisasm/Levels/AIZ/Misc Object Data/"

Object File Locations

Data Type Location Example
Object code sonic3k.asm (inline) Obj_AIZEndBoss:
Shared sprite art General/Sprites/{Name}/Art/ General/Sprites/Rhinobot/Art/
Shared sprite maps General/Sprites/{Name}/Map General/Sprites/Rhinobot/Map - Rhinobot.asm
Shared sprite DPLC General/Sprites/{Name}/DPLC General/Sprites/Rhinobot/DPLC - Rhinobot.asm
Shared sprite anim General/Sprites/{Name}/Anim General/Sprites/Rhinobot/Anim - Rhinobot.asm
Zone-specific maps Levels/{ZONE}/Misc Object Data/ Levels/AIZ/Misc Object Data/Map - Zipline.asm
Zone-specific anim Levels/{ZONE}/Misc Object Data/ Levels/AIZ/Misc Object Data/Anim - Zipline.asm

Object System Reference

Object Status Table Offsets

S3K uses S2-style field names (same as S2, different from S1):

Field Offset Size Description
code 0x00 long Object code pointer
render_flags 0x04 byte Render flags
routine 0x05 byte Current routine
height_pixels 0x06 byte Sprite height
width_pixels 0x07 byte Sprite width
x_pos 0x10 word/long X position
y_pos 0x14 word/long Y position
x_vel 0x18 word X velocity
y_vel 0x1A word Y velocity
mapping_frame 0x22 byte Current frame
routine 0x24 byte Current routine (alternate ref)
collision_flags 0x28 byte TT SSSSSS (type + size)
collision_property 0x29 byte Hit count for bosses
shield_reaction 0x2B byte Shield-specific reactions (S3K-only)
subtype 0x2C byte Object subtype
routine_secondary 0x3C byte Secondary routine
parent 0x42 word Parent object address

Object size: $4A bytes (same as S2).

S3K-Specific Features

Shield reactions (shield_reaction at offset 0x2B):

Bit Shield Effect
3 Bounce Bounce shield attack reaction
4 Fire Fire shield immunity/reaction
5 Lightning Lightning shield reaction
6 Bubble Bubble shield negation

Child sprite system via mainspr_childsprites at offset +$16:

  • Up to 8 inline child sprites per object
  • Children share the parent object's RAM slot
  • Used for multi-piece visual objects (e.g., boss segments)

Character ID (character_id field):

Value Character
0 Sonic
1 Tails
2 Knuckles

Object Routine Pattern

Obj_Example:
    moveq   #0,d0
    move.b  routine(a0),d0
    move.w  Obj_Example_Index(pc,d0.w),d1
    jmp     Obj_Example_Index(pc,d1.w)

Obj_Example_Index:
    dc.w Obj_Example_Init - Obj_Example_Index   ; routine 0
    dc.w Obj_Example_Main - Obj_Example_Index   ; routine 2

Sprite Mappings Format (S2/S3K Format)

S3K uses the same 6-byte per piece format as S2 (not S1's 5-byte):

Frame header:
  dc.w  <piece_count>              ; Word header (same as S2)

Per piece (6 bytes):
  dc.b  <y_offset>                 ; Signed byte
  dc.b  <size>                     ; bits 0-1: width-1, bits 2-3: height-1
  dc.w  <pattern>                  ; Pattern index + flags (priority, palette, flip)
  dc.w  <x_offset>                 ; Signed word (S1 uses byte)

Size byte encoding (same as S1/S2):

  • 0x00 = 1x1 (8x8 pixels)
  • 0x05 = 2x2 (16x16 pixels)
  • 0x0F = 4x4 (32x32 pixels)

Common Search Patterns

Finding Badnik Art

# Search for specific badnik
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k search Rhinobot" -q

# Find all Kosinski Moduled art
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k search ArtKosM_" -q

# Find all Nemesis art
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k search ArtNem_" -q

Finding Zone Data

# All AIZ resources
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k search AIZ" -q

# Zone palette
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k search Pal_AIZ" -q

# Animated palette
mvn exec:java -Dexec.mainClass="com.openggf.tools.disasm.RomOffsetFinder" -Dexec.args="--game s3k search AnPal_AIZ" -q

Finding Object Code

# Search for object in main ASM
grep -n "Obj_Rhinobot" docs/skdisasm/sonic3k.asm

# Find all boss objects
grep -n "Obj_.*Boss" docs/skdisasm/sonic3k.asm

# Find sprite data directory
ls "docs/skdisasm/General/Sprites/Rhinobot/"

RAM Address Reference

Key RAM addresses from sonic3k.constants.asm:

Address Name Description
(dynamic) Object_RAM Object status table (dynamically allocated)
Current_zone Current zone Current zone ID
Current_zone_and_act Zone and act Combined zone/act value
Camera_X_pos Camera X Camera X position
Camera_Y_pos Camera Y Camera Y position
Ring_count Rings Current ring count

Zone-specific variables exist for special mechanics:

  • AIZ1_palette_cycle_flag - AIZ fire palette cycling
  • SOZ_darkness_level - SOZ Act 2 darkness
  • MHZ_pollen_counter - MHZ pollen effect

Quick Reference Card

Search:  --game s3k search <pattern>      Find items by name
List:    --game s3k list [type]           List items (nem/kos/kosm/bin)
Test:    --game s3k test <offset> <type>  Test decompression
Verify:  --game s3k verify <label>        Check calculated offset
Export:  --game s3k export <type> [prefix] Generate Java constants

Troubleshooting

Address Verification

Like S1, addresses derived from skdisasm labels may not always match the compiled ROM binary exactly. Use verify to check calculated offsets against the actual ROM data.

"Item not found"

  • Check spelling and case sensitivity
  • Try partial names (e.g., "Rhino" instead of "Rhinobot")
  • S3K labels use ArtKosM_ for Kosinski Moduled, ArtNem_ for Nemesis
  • Compression type is encoded in the label suffix for some items
  • Use list command to see all items of a type

Compression Detection

  • S3K primarily uses Kosinski Moduled (kosm) rather than regular Kosinski
  • Label suffix _KosM indicates Kosinski Moduled compression
  • ArtNem_ prefix indicates Nemesis compression
  • ArtKos_ prefix indicates regular Kosinski compression
  • When the file extension is .bin, the tool infers compression from the label
Install via CLI
npx skills add https://github.com/jamesj999/OpenGGF --skill s3k-disasm-guide
Repository Details
star Stars 6
call_split Forks 1
navigation Branch main
article Path SKILL.md
More from Creator