Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Amalgamation of research on Cave Story's file formats and important hacks for modding
-=~ Cave Story Research Compendium ~=-
-=~ A guide to Cave Story's file formats and important hacks for those who are interested ~=-
by F_Deity_Link, using research by others as well
Made it for myself to learn as well as because the file formats and important hacks weren't all 'published'
(actually they're in miza.chm, included with the Miza editor, but I hadn't realized this when I started),
and I figured a centralized document with all of it would be helpful
Last updated 2017-02-06
Note that some info might be incorrect - SP's guides are a bit old - feel free to tell me of anything that could be updated
-=~ Credits ~=-
Big thanks to all the people I got much of this research from!
- Carrotlord for TSC file format
- q3hardcore for (C)Pixel requirement removal
- S.P. Gardebiter for PXA values + EXE mapdata format + npc.tbl format
- dooey100 for flag setting, unsetting, and checking
- Noxid for Booster's Lab, which helped for seeing how edits affected the files, as well as getting newest info
- especially tilesets and sounds in npc.tbl
-=~ TSC File Format ~=-
Encoding char is the middle character in file: char at floor (file size / 2)
ex: size of 313 bytes, encode char is at 156th byte
Newlines are Windows-style newlines ("\r\n"): 0x0D + encode char val, then 0x0A + encode char val
- Because they're Windows-style newlines, open your files in binary mode, not text, otherwise the following transformations are done, which will end up corrupting the file
- "\r\n" --> '\n' for input
- '\n' --> "\r\n" for output
All characters in the file except for the encoding char itself (so other copies of the character are still encoded) have the value of the encoding char added to them when saved
ex: encoding char = [space]: only that instance of the [space] character will not be encoded, but the others will
When reading a TSC file, subtract the encoding character from each character (except the encoding char itself, as noted above) to properly decode the file
When writing a TSC file, add the encoding character to each character (except the encoding char itself, as noted above) to properly encode the file
-=~ Removing (C)Pixel Requirement ~=-
0x1136C: 0x74 --> 0xEB
0x8C4D8: 0x28 --> 0x00
Then in every .pbm, find the (C)Pixel at the end and change the '(' to the null character (0x00)
-=~ Allowing bitmaps ~=-
0x8C286 through 8 and 0x0008C30A through C: 0x70, 0x62, and 0x6D --> 0x62, 0x6D, and 0x70
0x8C32E and F: 0x70 and 0x62 --> 0x62 and 0x6D
0x8C330: 0x6D --> 0x70
-=~ npc.tbl Format ~=-
Cave Story has 361 entities (0x169) from 0 - 360
npc.tbl has 11 sets of data, the starting addresses of which are all multiples of 0x169:
0x0000: Flags - 2 Bytes
0x02D2: Health - 2 Bytes
0x05A4: Tileset Number - 1 Byte
0x070D: Death Sound - 1 Byte
0x0876: Hurt Sound - 1 Byte
0x09DF: Death Smoke - 1 Byte
0x0B48: Experience - 4 Bytes
0x10EC: Damage - 4 Bytes
0x1690: Collsion Bounding Box - 4 Bytes
0x1C34: Display Bounding Box - 4 Bytes
-=~ Flags ~=-
-=~ Byte 1 ~=-
0x01: Solid
0x02: No effect about Tile 44
0x04: Invulnerable (Blink Sound)
0x08: Ignore solid
0x10: Bouncing at top
0x20: Shootable
0x40: Special Solid
0x80: Rear and top no damage
-=~ Byte 2 ~=-
0x01: Call Event on Contact
0x02: Call Event on Death
0x04: Drop Hearts and EXP [Unused]
0x08: Visible if FlagID is set
0x10: Spawn with Alternate Direction
0x20: Call Event on Interaction
0x40: Invisible if FlagID is set
0x80: Show Damage Numbers ?"Interactable" in Booster's Lab
Setting Flags: Flag to set OR current flags
Unsetting Flags: (Flag to unset XOR 1111 1111) AND current flags
Checking Flags: Flag to check AND current flags - returns flag being checked if it is set, 0 if not set
-=~ Tilesets ~=-
0x00: title.pbm
0x01: '2004.12 Studio Pixel'
0x02: Current map tileset
0x03: [Unused]
0x04: [Unused]
0x05: [Unused]
0x06: Fade.pbm
0x07: [Unused]
0x08: ItemImage.pbm
0x09: Map System Buffer
0x0A: Screen Buffer
0x0B: Arms.pbm
0x0C: ArmsImage.pbm
0x0D: MNA Text Buffer
0x0E: StageImage.pbm
0x0F: Loading.pbm
0x10: MyChar.pbm
0x11: Bullet.pbm
0x12: [Unused]
0x13: Caret.pbm
0x14: Npc/NpcSym.pbm
0x15: Map NPC Set 1
0x16: Map NPC Set 2
0x17: Npc/NpcRegu.pbm
0x18: [Unused]
0x19: [Unused]
0x1A: TextBox.pbm
0x1B: Face.pbm
0x1C: Current Map BG
0x1D: Damage # Buffer
0x1E: Textbox Buffer 1
0x1F: Textbox Buffer 2
0x20: Textbox Buffer 3
0x21: [???]
0x22: [Unused]
0x23: Credits Buffer 1
0x24: Credits Buffer 2
0x25: Credits Buffer 3
0x26: [Unused]
0x27: [Unused]
-=~ Hurt / Death Sounds ~=-
0x00: [Nothing]
0x01: Blip
0x02: Message Typing
0x03: Bonk
0x04: Weapon Switching
0x05: Menu Prompt?
0x06: Critter hop
0x07: Silent?
0x08: Low charge sound
0x09: [Nothing?]
0x0A: [Nothing?]
0x0B: Door
0x0C: Block Destroy
0x0D: [Nothing?]
0x0E: Get EXP
0x0F: Quote Jump
0x10: Taking Damage
0x11: Death
0x12: [Menu?]
0x13: [Nothing?]
0x14: Health/Ammo Refill
0x15: Bubble
0x16: Chest open
0x17: Thud
0x18: Walking
0x19: Enemy killed?
0x1A: Quake
0x1B: Level up
0x1C: Shot hit
0x1D: Teleport
0x1E: Critter jump
0x1F: Ting
0x20: Polar Star lvl
0x21: Fireball
0x22: Fireball bounce
0x23: Explosion
0x24: [Nothing?]
0x25: No Ammo
0x26: Get item?
0x27: [*bvng*] Em fire? - taken from BL, what is em?
0x28: Water
0x29: Water
0x2A: Get Missile [Beep]
0x2B: Computer [Beep]
0x2C: Missile Hit
0x2D: EXP Bounce
0x2E: Ironhead Shot
0x2F: Explosion 2?
0x30: Bubble pop
0x31: Spur lvl 1
0x32: Sqeek!
0x33: Squeal!
0x34: Roar
0x35: Eyoww
0x36: Thud
0x37: Squeek
0x38: Splash
0x39: Little damage sound
0x3A: [*chik*]
0x3B: Spur Charge (lowest)
0x3C: Spur Charge (lower)
0x3D: Spur Charge (higher)
0x3E: Spur lvl 2
0x3F: Spur lvl 3
0x40: Spur MAX
0x41: Spur full?
0x42: [Nothing?]
0x43: [Nothing?]
0x44: [Nothing?]
0x45: [Nothing?]
0x46: Tiny Explosion
0x47: Medium Explosion
0x48: Large Explosion
0x49: [Nothing?]
0x4A: [Nothing?]
0x4B: [Nothing?]
0x4C: [Nothing?]
0x4D: [Nothing?]
0x4E: [Nothing?]
0x4F: [Nothing?]
0x50: [Nothing?]
0x51: [Nothing?]
0x52: [Nothing?]
0x53: [Nothing?]
0x54: [Nothing?]
0x55: [Nothing?]
0x56: [Nothing?]
0x57: [Nothing?]
0x58: [Nothing?]
0x59: [Nothing?]
0x5A: [Nothing?]
0x5B: [Nothing?]
0x5C: [Nothing?]
0x5D: [Nothing?]
0x5E: [Nothing?]
0x5F: [Nothing?]
0x60: [Nothing?]
0x61: [Nothing?]
0x62: [Nothing?]
0x63: [Nothing?]
0x64: Bubbler lvl 3
0x65: Lightning
0x66: Sandcroc Bite
0x67: Curly Charge
0x68: Hit Invisible Block
0x69: Puppy Bark
0x6A: Blade whoosh
0x6B: Block Move
0x6C: Power Critter Jump
0x6D: Critter Fly
0x6E: Power Critter Fly
0x6F: Thud
0x70: Bigger thud
0x71: [*pshew*] Helicopter?
0x72: Core hurt
0x73: Core thrust
0x74: Core super charge
0x75: Nemesis?
0x76: [Nothing?]
0x77: [Nothing?]
0x78: [Nothing?]
0x79: [Nothing?]
0x7A: [Nothing?]
0x7B: [Nothing?]
0x7C: [Nothing?]
0x7D: [Nothing?]
0x7E: [Nothing?]
0x7F: [Nothing?]
0x80: [Nothing?]
0x81: [Nothing?]
0x82: [Nothing?]
0x83: [Nothing?]
0x84: [Nothing?]
0x85: [Nothing?]
0x86: [Nothing?]
0x87: [Nothing?]
0x88: [Nothing?]
0x89: [Nothing?]
0x90: [Nothing?]
0x91: [Nothing?]
0x92: [Nothing?]
0x93: [Nothing?]
0x94: [Nothing?]
0x95: [Nothing?]
0x96: BASS01
0x97: SNARE01
0x98: HICLOSE
0x99: HIOPEN
0x9A: TOM01
0x9B: PER01
-=~ Smoke ~=-
0x01: None
0x02: Small amount
0x03: Medium amount
0x04: Large amount
-=~ Bounding Box Addresses ~=-
(from beginning of each portion)
0x00: Left
0x01: Top
0x02: Right
0x03: Bottom
-=~ Map Formats ~=-
-=~ Mapdata Addresses ~=-
(for freeware and stage.tbl(CS+))
(from the beginning of each map section)
0x00: Tileset name
0x20: Filename
0x40: Background Scrolling Type
0x44: Background Name
0x64: NPC Spritesheet 1
0x84: NPC Spritesheet 2
0xA4: Major Boss
0xA5: Mapname
-=~ Background Scrolling Types ~=-
0x00: No Scrolling
0x01: Slow Scrolling
0x02: Equal Scrolling
0x03: Water-Style
0x04: Null
0x05: Auto Scrolling
0x06: Cloud-Style [Gravity: Left]
0x07: Cloud-Style [Gravity: Normal]
-=~ Major Bosses are as follows ~=-
0x00: No Major Boss
0x01: Omega
0x02: Balfrog
0x03: Monster X
0x04: The Core
0x05: Iron Head
0x06: Dragon Sisters
0x07: Undead Core
0x08: Heavy Press
0x09: Ballos
WINDOWS IS LITTLE-ENDIAN AND ALL DATA (with the exception of PXM map tile and PXE entity count) TAKES UP TWO BYTES
ex: x coord of 256 (dec) is 0x0100, seen as 00 01 in hex editor
-=~ PXM File Data ~=-
maps must be minimum of 21x16
First three bytes are PXM, then 0x10
Then 0x_map_length - 2 bytes
Then 0x_map_height - 2 bytes
Then 0x_map_tile_from_tileset for the rest of the file (numbered from 0, and going left to right, top to bottom) - 1 byte
-=~ PXE File Data ~=-
First three bytes are PXE, then 0x00
Then 0x_entity_count - 4 bytes
Then each entity takes up 12 bytes, and they are in order based on their draw order (higher drawn on top) - lowest in file first:
0x_x_coord - 2 bytes
0x_y_coord - 2 bytes
0x_flag_num - 2 bytes
0x_event_num - 2 bytes
0x_entity_type - 2 bytes
0x_entity_flags - 2 bytes
-=~ Flags ~=-
Setting: Flag to set OR current flags
Unsetting: (Flag to unset XOR 1111 1111) AND current flags
Checking: Flag to check AND current flags - returns flag being checked if it is set, 0 if not set
-=~ PXA File Data ~=-
Format is tile type, corresponds to tileset directly - file has no header
Tilesets can be 16x16 tiles max, so PXA has 256 bytes, value of 0 for tiles not in tileset image
-=~ Tile Types ~=-
Flags:
0x01: Special
0x02: Special
0x04: Special
0x08: Special
0x10: Slope
0x20: Water
0x40: Foreground
0x80: Wind
0x00 (Null):
0x00: Null
0x01: Background Tile
0x02: Background Water
0x03: Background NPC-Blocker Tile [Unused]
0x04: Background NPC-Blocker Tile [Unused]
0x05: Background Shoot-Passer Tile [Unused]
0x06: Background Tile [Unused]
0x07: Background Tile [Unused]
0x08: Background Tile [Unused]
0x09: Background Tile [Unused]
0x0A: Background Tile [Unused]
0x0B: Background Tile [Unused]
0x0C: Background Tile [Unused]
0x0D: Background Tile [Unused]
0x0E: Background Tile [Unused]
0x0F: Background Tile [Unused]
0x10 (Slope):
0x10: Background Tile [Unused]
0x11: Background Tile [Unused]
0x12: Background Tile [Unused]
0x13: Background Tile [Unused]
0x14: Background Tile [Unused]
0x15: Background Tile [Unused]
0x16: Background Tile [Unused]
0x17: Background Tile [Unused]
0x18: Background Tile [Unused]
0x19: Background Tile [Unused]
0x1A: Background Tile [Unused]
0x1B: Background Tile [Unused]
0x1C: Background Tile [Unused]
0x1D: Background Tile [Unused]
0x1E: Background Tile [Unused]
0x1F: Background Tile [Unused]
0x20 (Water):
0x20: Null [Unused]
0x21: Null [Unused]
0x22: Null [Unused]
0x23: Null [Unused]
0x24: Null [Unused]
0x25: Null [Unused]
0x26: Null [Unused]
0x27: Null [Unused]
0x28: Null [Unused]
0x29: Null [Unused]
0x2A: Null [Unused]
0x2B: Null [Unused]
0x2C: Null [Unused]
0x2D: Null [Unused]
0x2E: Null [Unused]
0x2F: Null [Unused]
0x30 (Slope + Water):
0x30: Null [Unused]
0x31: Null [Unused]
0x32: Null [Unused]
0x33: Null [Unused]
0x34: Null [Unused]
0x35: Null [Unused]
0x36: Null [Unused]
0x37: Null [Unused]
0x38: Null [Unused]
0x39: Null [Unused]
0x3A: Null [Unused]
0x3B: Null [Unused]
0x3C: Null [Unused]
0x3D: Null [Unused]
0x3E: Null [Unused]
0x3F: Null [Unused]
0x40 (Foreground):
0x40: Foreground Tile
0x41: Solid Tile
0x42: 10 Damage Foreground Tile
0x43: Special Block Tile
0x44: Foreground NPC-Blocker Tile
0x45: Foreground Tile [Unused]
0x46: Character-Blocker Tile [Unused]
0x47: Foreground Tile [Unused]
0x48: Foreground Tile [Unused]
0x49: Foreground Tile [Unused]
0x4A: Foreground Tile [Unused]
0x4B: Foreground Tile [Unused]
0x4C: Foreground Tile [Unused]
0x4D: Foreground Tile [Unused]
0x4E: Foreground Tile [Unused]
0x4F: Foreground Tile [Unused]
0x50 (Foreground + Slope):
0x50: Slope Tile
0x51: Slope Tile
0x52: Slope Tile
0x53: Slope Tile
0x54: Slope Tile
0x55: Slope Tile
0x56: Slope Tile
0x57: Slope Tile
0x58: Foreground Tile [Unused]
0x59: Foreground Tile [Unused]
0x5A: Foreground Tile [Unused]
0x5B: Foreground Tile [Unused]
0x5C: Foreground Tile [Unused]
0x5D: Foreground Tile [Unused]
0x5E: Foreground Tile [Unused]
0x5F: Foreground Tile [Unused]
0x60 (Foreground + Water):
0x60: Foreground Water
0x61: Solid Tile [Unused]
0x62: 10 Damage Foreground Water Tile [Red]
0x63: Foreground Tile [Unused]
0x64: Foreground NPC-Blocker Tile [Unused]
0x65: Foreground Tile [Unused]
0x66: Foreground Tile [Unused]
0x67: Foreground Tile [Unused]
0x68: Foreground Tile [Unused]
0x69: Foreground Tile [Unused]
0x6A: Foreground Tile [Unused]
0x6B: Foreground Tile [Unused]
0x6C: Foreground Tile [Unused]
0x6D: Foreground Tile [Unused]
0x6E: Foreground Tile [Unused]
0x6F: Foreground Tile [Unused]
0x70 (Foreground + Slope + Water):
0x70: Slope Tile [Water]
0x71: Slope Tile [Water]
0x72: Slope Tile [Water]
0x73: Slope Tile [Water]
0x74: Slope Tile [Water]
0x75: Slope Tile [Water]
0x76: Slope Tile [Water]
0x77: Slope Tile [Water]
0x78: Foreground Tile [Unused]
0x79: Foreground Tile [Unused]
0x7A: Foreground Tile [Unused]
0x7B: Foreground Tile [Unused]
0x7C: Foreground Tile [Unused]
0x7D: Foreground Tile [Unused]
0x7E: Foreground Tile [Unused]
0x7F: Foreground Tile [Unused]
0x80 (Wind):
0x80: Wind [Left]
0x81: Wind [Up]
0x82: Wind [Right]
0x83: Wind [Down]
0x84: Null [Unused]
0x85: Null [Unused]
0x86: Null [Unused]
0x87: Null [Unused]
0x88: Null [Unused]
0x89: Null [Unused]
0x8A: Null [Unused]
0x8B: Null [Unused]
0x8C: Null [Unused]
0x8D: Null [Unused]
0x8E: Null [Unused]
0x8F: Null [Unused]
0x90 (Wind + Slope):
0x90: Null [Unused]
0x91: Null [Unused]
0x92: Null [Unused]
0x93: Null [Unused]
0x94: Null [Unused]
0x95: Null [Unused]
0x96: Null [Unused]
0x97: Null [Unused]
0x98: Null [Unused]
0x99: Null [Unused]
0x9A: Null [Unused]
0x9B: Null [Unused]
0x9C: Null [Unused]
0x9D: Null [Unused]
0x9E: Null [Unused]
0x9F: Null [Unused]
0xA0 (Wind + Water):
0xA0: Water Wind [Left]
0xA1: Water Wind [Up]
0xA2: Water Wind [Right]
0xA3: Water Wind [Down]
0xA4: Null [Unused]
0xA5: Null [Unused]
0xA6: Null [Unused]
0xA7: Null [Unused]
0xA8 :Null [Unused]
0xA9: Null [Unused]
0xAA: Null [Unused]
0xAB: Null [Unused]
0xAC: Null [Unused]
0xAD: Null [Unused]
0xAE: Null [Unused]
0xAF: Null [Unused]
0xB0 (Wind + Slope + Water):
0xB0: Null [Unused]
0xB1: Null [Unused]
0xB2: Null [Unused]
0xB3: Null [Unused]
0xB4: Null [Unused]
0xB5: Null [Unused]
0xB6: Null [Unused]
0xB7: Null [Unused]
0xB8: Null [Unused]
0xB9: Null [Unused]
0xBA: Null [Unused]
0xBB: Null [Unused]
0xBC: Null [Unused]
0xBD: Null [Unused]
0xBE: Null [Unused]
0xBF: Null [Unused]
0xC0 (Wind + Foreground):
0xC0: Null [Unused]
0xC1: Null [Unused]
0xC2: Null [Unused]
0xC3: Null [Unused]
0xC4: Null [Unused]
0xC5: Null [Unused]
0xC6: Null [Unused]
0xC7: Null [Unused]
0xC8: Null [Unused]
0xC9: Null [Unused]
0xCA: Null [Unused]
0xCB: Null [Unused]
0xCC: Null [Unused]
0xCD: Null [Unused]
0xCE: Null [Unused]
0xCF: Null [Unused]
0xD0 (Wind + Foreground + Slope):
0xD0: Null [Unused]
0xD1: Null [Unused]
0xD2: Null [Unused]
0xD3: Null [Unused]
0xD4: Null [Unused]
0xD5: Null [Unused]
0xD6: Null [Unused]
0xD7: Null [Unused]
0xD8: Null [Unused]
0xD9: Null [Unused]
0xDA: Null [Unused]
0xDB: Null [Unused]
0xDC: Null [Unused]
0xDD: Null [Unused]
0xDE: Null [Unused]
0xDF: Null [Unused]
0xE0 (Wind + Foreground + Water):
0xE0: Null [Unused]
0xE1: Null [Unused]
0xE2: Null [Unused]
0xE3: Null [Unused]
0xE4: Null [Unused]
0xE5: Null [Unused]
0xE6: Null [Unused]
0xE7: Null [Unused]
0xE8: Null [Unused]
0xE9: Null [Unused]
0xEA: Null [Unused]
0xEB: Null [Unused]
0xEC: Null [Unused]
0xED: Null [Unused]
0xEE: Null [Unused]
0xEF: Null [Unused]
0xF0 (Wind + Foreground + Slope + Water):
0xF0: Null [Unused]
0xF1: Null [Unused]
0xF2: Null [Unused]
0xF3: Null [Unused]
0xF4: Null [Unused]
0xF5: Null [Unused]
0xF6: Null [Unused]
0xF7: Null [Unused]
0xF8: Null [Unused]
0xF9: Null [Unused]
0xFA: Null [Unused]
0xFB: Null [Unused]
0xFC: Null [Unused]
0xFD: Null [Unused]
0xFE: Null [Unused]
0xFF: Null [Unused]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment