-=~ 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] Weapons (AM+/AM-/AMJ/GIT/TAM) Profile.dat bytes 0x038-098 (every 4 bytes: weapon, level (1-3), energy, max ammo (0 = infinite), current ammo) (every 20 bytes) 0000 [nothing?] 0001 Snake 0002 Polar Star 0003 Fireball 0004 Machine Gun 0005 Missile Launcher 0006 Missiles (GIT only) 0007 Bubbler 0008 [nothing?] 0009 Blade 0010 Super Missile Launcher 0011 Super Missiles (GIT only) 0012 Nemesis 0013 Spur Items (GIT/IT+/IT-/ITJ) Profile.dat bytes 0x0D8-14C (every 4 bytes) [Add 1000 to GIT?] 0000 [Blank - Clears box in GIT] 0001 Arthur's Key 0002 Map System 0003 Santa's Key 0004 Silver Locket 0005 Beast Fang 0006 Life Capsule (GIT only) 0007 ID Card 0008 Jellyfish Juice 0009 Rusty Key 0010 Gum Key 0011 Gum Base 0012 Charcoal 0013 Explosive 0014 Puppy 0015 Life Pot 0016 Cure-All 0017 Clinic Key 0018 Booster 0.8 0019 Arms Barrier 0020 Turbocharge 0021 Curly's Air Tank 0022 Nikumaru Counter 0023 Booster v2.0 0024 Mimiga Mask 0025 Teleporter Room Key 0026 Sue's Letter 0027 Controller 0028 Broken Sprinkler 0029 Sprinkler 0030 Tow Rope 0031 Clay Figure Medal 0032 Little Man 0033 Mushroom Badge 0034 Ma Pignon 0035 Curly's Underwear 0036 Alien Medal 0037 Chaco's Lipstick 0038 Whimsical Star 0039 Iron Bond Equip (EQ+/EQ-) Profile.dat bytes 0x02C-02D (low byte first) 0001 Booster v0.8 (ignored if v2.0 on) 0002 Map System 0004 Arms Barrier 0008 Turbocharge 0016 Curly's Air Tank 0032 Booster v2.0 0064 Mimiga Mask 0128 Whimsical Star 0256 Nikumaru Counter NOTE: these are bitwise flags, the final value is the sum of the equipped items