mirror of
https://github.com/cave-story-randomizer/cave-story-randomizer
synced 2024-11-10 00:45:15 +00:00
20 KiB
20 KiB
Cave Story Research Compendium
A guide to Cave Story's file formats and important hacks
by fdeitylink
Last updated 2019-10-23
Rationale
- Learning more about Cave Story for my own edification
- File formats & important hacks weren't all published and collected
- Actually, they are included with Miza, but I hadn't realized this when beginning
Notes
- Some information may be incorrect - S.P. Gardebiter's guides are a bit old. Feel free to tell me of any information that is incorrect or in need of an update.
- Cave Story was made for Windows and x86 architecture, which leads to some nuances to look out for
- Newlines are encoded as
\r\n
(affects TSC) - Multibyte data is encoded in little endian format
- Newlines are encoded as
Credits
Big thanks to all of the following people for much of the following information!
- Carrotlord for the TSC file format
- q3hardcore for the (C)Pixel requirement removal hack
- S.P. Gardebiter for the PXA file format values, the executable mapdata format, and the
npc.tbl
format - Noxid for Booster's Lab
- Used to determine how particular edits affected the files
- Provided newest information, especially tileset and sound values for
npc.tbl
WIthout further ado, let's begin!
Flags
Setting Flags
Bitwise OR the current flags with the flag to set
flags |= flag
Unsetting Flags
Bitwise XOR the flag to set with 0b1111_1111
Bitwise AND the current flags with that result
flags &= (flag ^ 0xFF)
Checking Flags
Bitwise AND the current flags with the flag to check
Returns flag if it is set, 0
otherwise
is_set = (flags & flag)
TSC File Format
- The encoding character is the middle character in the file (i.e. the character at
floor(file_size / 2)
.- For example, if the file size is 313 bytes, the encoding character is at the 156th byte.
- During encoding, all characters in the file, except for the encoding character itself, have the value of the encoding character added to them.
- To be clear, the encoding character itself, at the middle of the file, is not encoding, but other instances of it can be. If the encoding character was
a
, that one instance ofa
would not be encoded, but others would be.
- To be clear, the encoding character itself, at the middle of the file, is not encoding, but other instances of it can be. If the encoding character was
- To encode a TSC file, add the value of the encoding character to all characters except for the encoding character.
- To be clear, do not encode the middle byte of the file
- It then follows that to decode a TSC file, subtract the value of the encoding character from each character
- Also note that newlines in TSC files are Windows-style (
"\r\n"
), so they take up two bytes that should each be treated as independent characters when encoding and decoding.
Removing the (C)Pixel
Requirement
Offset | Old Value | New Value |
---|---|---|
0x1136C |
0x74 |
0xEB |
0x8C4D8 |
0x28 |
0x00 |
In every .pbm
file, find the (C)Pixel
at the end and replace the (
with the null character (0x00
)
Enabling bitmaps
Offset | Old Value | New Value |
---|---|---|
0x8C286 , 0x8C30A , 0x8C32E |
0x70 |
0x62 |
0x8C287 , 0x8C30B , 0x8C32F |
0x62 |
0x6D |
0x8C288 , 0x8C30C , 0x8C330 |
0x6D |
0x70 |
npc.tbl
Format
- Cave Story has 361 (
0x169
) entities numbered from 0 to 360 npc.tbl
contains 11 sets of data. The starting address of each set is a multiple of0x169
.- Each set of data contains the corresponding value for each entity, in order.
- For example: At offset
0x02D2
is the Health data for entity 0. At offset0x02D4
is the Health data for entity 1.
- For example: At offset
Offset | Description | Size per Entity (bytes) |
---|---|---|
0x0000 |
Flags | 2 |
0x02D2 |
Health | 2 |
0x05A4 |
Tileset Number | 1 |
0x070D |
Death Sound | 1 |
0x0876 |
Hurt Sound | 1 |
0x09DF |
Death Smoke | 1 |
0x0B48 |
Experience | 4 |
0x10EC |
Damage | 4 |
0x1690 |
Collision Bounding Box | 4 |
0x1C34 |
Display Bounding Box | 4 |
Flags
Byte 1
0x01
: Solid0x02
: No effect about Tile 440x04
: Invulnerable (Blink Sound)0x08
: Ignore solid0x10
: Bouncing at top0x20
: Shootable0x40
: Special Solid0x80
: Rear and top no damage
Byte 2
0x01
: Call Event on Contact0x02
: Call Event on Death0x04
: Drop Hearts and EXP [Unused]0x08
: Visible if FlagID is set0x10
: Spawn with Alternate Direction0x20
: Call Event on Interaction0x40
: Invisible if FlagID is set0x80
: Show Damage Numbers ? ("Interactable" in Booster's Lab)
Tilesets
0x00
: title.pbm0x01
: '2004.12 Studio Pixel'0x02
: Current map tileset0x03
: [Unused]0x04
: [Unused]0x05
: [Unused]0x06
: Fade.pbm0x07
: [Unused]0x08
: ItemImage.pbm0x09
: Map System Buffer0x0A
: Screen Buffer0x0B
: Arms.pbm0x0C
: ArmsImage.pbm0x0D
: MNA Text Buffer0x0E
: StageImage.pbm0x0F
: Loading.pbm0x10
: MyChar.pbm0x11
: Bullet.pbm0x12
: [Unused]0x13
: Caret.pbm0x14
: Npc/NpcSym.pbm0x15
: Map NPC Set 10x16
: Map NPC Set 20x17
: Npc/NpcRegu.pbm0x18
: [Unused]0x19
: [Unused]0x1A
: TextBox.pbm0x1B
: Face.pbm0x1C
: Current Map BG0x1D
: Damage # Buffer0x1E
: Textbox Buffer 10x1F
: Textbox Buffer 20x20
: Textbox Buffer 30x21
: [???]0x22
: [Unused]0x23
: Credits Buffer 10x24
: Credits Buffer 20x25
: Credits Buffer 30x26
: [Unused]0x27
: [Unused]
Hurt / Death Sounds
0x00
: [Nothing]0x01
: Blip0x02
: Message Typing0x03
: Bonk0x04
: Weapon Switching0x05
: Menu Prompt?0x06
: Critter hop0x07
: Silent?0x08
: Low charge sound0x09
: [Nothing?]0x0A
: [Nothing?]0x0B
: Door0x0C
: Block Destroy0x0D
: [Nothing?]0x0E
: Get EXP0x0F
: Quote Jump0x10
: Taking Damage0x11
: Death0x12
: [Menu?]0x13
: [Nothing?]0x14
: Health/Ammo Refill0x15
: Bubble0x16
: Chest open0x17
: Thud0x18
: Walking0x19
: Enemy killed?0x1A
: Quake0x1B
: Level up0x1C
: Shot hit0x1D
: Teleport0x1E
: Critter jump0x1F
: Ting0x20
: Polar Star lvl0x21
: Fireball0x22
: Fireball bounce0x23
: Explosion0x24
: [Nothing?]0x25
: No Ammo0x26
: Get item?0x27
: [bvng] Em fire? - taken from BL, what is em?0x28
: Water0x29
: Water0x2A
: Get Missile [Beep]0x2B
: Computer [Beep]0x2C
: Missile Hit0x2D
: EXP Bounce0x2E
: Ironhead Shot0x2F
: Explosion 2?0x30
: Bubble pop0x31
: Spur lvl 10x32
: Sqeek!0x33
: Squeal!0x34
: Roar0x35
: Eyoww0x36
: Thud0x37
: Squeek0x38
: Splash0x39
: Little damage sound0x3A
: [chik]0x3B
: Spur Charge (lowest)0x3C
: Spur Charge (lower)0x3D
: Spur Charge (higher)0x3E
: Spur lvl 20x3F
: Spur lvl 30x40
: Spur MAX0x41
: Spur full?0x42
: [Nothing?]0x43
: [Nothing?]0x44
: [Nothing?]0x45
: [Nothing?]0x46
: Tiny Explosion0x47
: Medium Explosion0x48
: Large Explosion0x49
: [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 30x65
: Lightning0x66
: Sandcroc Bite0x67
: Curly Charge0x68
: Hit Invisible Block0x69
: Puppy Bark0x6A
: Blade whoosh0x6B
: Block Move0x6C
: Power Critter Jump0x6D
: Critter Fly0x6E
: Power Critter Fly0x6F
: Thud0x70
: Bigger thud0x71
: [pshew] Helicopter?0x72
: Core hurt0x73
: Core thrust0x74
: Core super charge0x75
: 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
: BASS010x97
: SNARE010x98
: HICLOSE0x99
: HIOPEN0x9A
: TOM010x9B
: PER01
Smoke
0x01
: None0x02
: Small amount0x03
: Medium amount0x04
: Large amount
Bounding Box Addresses
From the beginning of each entity's section
0x00
: Left0x01
: Top0x02
: Right0x03
: Bottom
Map Formats
Map Metadata
- Applies to freeware executable and CS+
stage.tbl
file - Begins at offset
0x937B0
in freeware executable
Offset (from beginning of each map section) | Description | Size (bytes) |
---|---|---|
0x00 |
Tileset name | 32 |
0x20 |
Filename | 32 |
0x40 |
Background Scrolling Type | 4 |
0x44 |
Background Name | 32 |
0x64 |
NPC Spritesheet 1 | 32 |
0x84 |
NPC Spritesheet 2 | 32 |
0xA4 |
Major Boss | 1 |
0xA5 |
Map Name | 35 |
Background Scrolling Types
0x00
: No Scrolling0x01
: Slow Scrolling0x02
: Equal Scrolling0x03
: Water-Style0x04
: Null0x05
: Auto Scrolling0x06
: Cloud-Style [Gravity: Left]0x07
: Cloud-Style [Gravity: Normal]
Major Bosses
0x00
: No Major Boss0x01
: Omega0x02
: Balfrog0x03
: Monster X0x04
: The Core0x05
: Iron Head0x06
: Dragon Sisters0x07
: Undead Core0x08
: Heavy Press0x09
: Ballos
PXM File Format
Note: Maps must have a minimum size of 21x16
Offset | Description | Size (bytes) |
---|---|---|
0x00 |
"PXM" |
3 |
0x03 |
0x10 |
1 |
0x04 |
Map length | 2 |
0x06 |
Map height | 2 |
Rest of the file | Tile index (left to right then top to bottom) | 1 |
PXE File Format
Offset | Description | Size (bytes) |
---|---|---|
0x00 |
"PXE" |
3 |
0x03 |
0x00 |
1 |
0x04 |
Entity count | 4 |
Rest of the file | Entity | 12 |
Entity Format
Offset (from beginning of each entity section) | Description | Size (bytes) |
---|---|---|
0x00 |
x coordinate | 2 |
0x02 |
y coordinate | 2 |
0x06 |
flag number | 2 |
0x08 |
event number | 2 |
0x0A |
type | 2 |
0x0C |
flags | 2 |
PXA File Format
- No header
- Array of tile types corresponding to tiles in a tileset (left to right then top to bottom)
- Tilesets have up to 16x16 tiles, so PXA files are always 256 bytes - fill in
0x00
for tiles not in the tileset
Flags
0x01
: Special0x02
: Special0x04
: Special0x08
: Special0x10
: Slope0x20
: Water0x40
: Foreground0x80
: Wind
Null (0x00
)
0x00
: Null0x01
: Background Tile0x02
: Background Water0x03
: 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]
Slope (0x10
)
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]
Water (0x20
)
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]
Slope + Water (0x30
)
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]
Foreground (0x40
)
0x40
: Foreground Tile0x41
: Solid Tile0x42
: 10 Damage Foreground Tile0x43
: Special Block Tile0x44
: Foreground NPC-Blocker Tile0x45
: 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]
Foreground + Slope (0x50
)
0x50
: Slope Tile0x51
: Slope Tile0x52
: Slope Tile0x53
: Slope Tile0x54
: Slope Tile0x55
: Slope Tile0x56
: Slope Tile0x57
: Slope Tile0x58
: 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]
Foreground + Water (0x60
)
0x60
: Foreground Water0x61
: 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]
Foreground + Slope + Water (0x70
)
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]
Wind (0x80
)
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]
Wind + Slope (0x90
)
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]
Wind + Water (0xA0
)
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]
Wind + Slope + Water (0xB0
)
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]
Wind + Foreground (0xC0
)
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]
Wind + Foreground + Slope (0xD0
)
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]
Wind + Foreground + Water (0xE0
)
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]
Wind + Foreground + Slope + Water (0xF0
)
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]