Initial commit.

This commit is contained in:
shru 2018-12-14 12:17:22 -05:00
parent c41cf626fe
commit 0094c34e51
7 changed files with 3852 additions and 1 deletions

View file

@ -1,2 +1,3 @@
# cave-story-randomizer
Cave Story Randomizer
=====================

666
docs/csresearch.txt Normal file
View file

@ -0,0 +1,666 @@
-=~ 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]

557
docs/tsc notes.txt Normal file
View file

@ -0,0 +1,557 @@
Doukutsu Monogatari - TSC notes (aka Cave Story)
by Kapow - 2006 April 24
additions by ShInInG PhAnToM - 2007 June 05
original: http://lotlot.net/misc/doukutsu/tsc.txt
updated: http://filespace.org/ShInInG_PhAnToM/TSC.TXT
THANKS:
caveoholic and upthorn from gameflaws forums
robert vandiver, for unused TSC commands
supergodantman
TSC COMMANDS (@ = available but unused commands found through disassembly - currently untested)
============
<AE+ Arms Energy + Refill ammo
<AM+x:y ArMs + Get weapon X, add Y to max ammo (just adds ammo if you have the weapon)
<AM-x ArMs - Lose weapon X
<AMJx:y ArMs Jump Jump to event Y if you have weapon X
<ANPx:y:z Animate NPc Animate npc X with method Y in direction Z [npc type determines Y values?]
<BOAx BOss Animate Animate boss
<BSLx Boss [Script Load?] Start a boss fight with npc X (npc flag 0200 must be set) (should work with anything that has HP)
<CAT [?] @ [same as SAT?]
<CIL Clear ILlustration Clear illustration during credits (used after SIL)
<CLO CLOse Close the text box (used after MSG/MS2/MS3)
<CLR CLeaR Clear the text box (used after MSG/MS2/MS3)
<CMPx:y:z Change Map [P?] Change map coords X:Y to tile Z
<CMUx Change MUsic Change music to song X
<CNPx:y:z Change NPc Change npc X to npc type Y with direction Z
<CPS Clear Prop. Sound Stop propeller sound (used after SPS) (from helicopter cutscene after final battles)
<CRE CREdits Roll credits
<CSS Clear Stream Sound Stop stream sound (used after SSS) (from River area)
<DNAx [?] [something to do with bosses]
<DNPx Delete NPc Npc X is removed completely
<ECJx:y [EC?] Jump @ Jump to event Y if any npc with ID X is present
<END END End scripted event
<EQ+x EQuip + Add X to equip flag bytes
<EQ-x EQuip - Subtract X from equip flag bytes
<ESC ESCape Quit to title screen
<EVEx EVEnt Jump to event X (non-conditional)
<FACx FACe Show face X in text box
<FAIx FAde In Fade in with direction X
<FAOx FAde Out Fade out with direction X
<FL+x FLag + Set flag X
<FL-x FLag - Clear flag X
<FLA FLAsh Flash the screen
<FLJx:y FLag Jump Jump to event Y if flag X is set
<FMU Fade MUsic Fade the music to a low volume (good to use before CMU)
<FOBx:y Focus On Boss [Focus view on boss X? why not use FON?], view movement takes Y ticks
<FOMx Focus On Me Focus view on you (normal view), view movement takes X ticks (WARNING: speed 0000 crashes)
<FONx:y Focus On Npc Focus view on npc X, view movement takes Y ticks
<FRE FREe Frees menu cursor [also used after ZAM for some reason?]
<GITx Graphic ITem Show weapon/item X icon above text box - add 1000 to X for items - GIT0000 to hide
<HMC Hide My Character Removes main character npc (use SMC after)
<INI INItialize Resets memory and starts game from the beginning
<INPx:y:z [I?] NPc @ Change npc X to npc type Y with direction Z with setting Flag 0x0100 [It seems that it setting the "No Player Damage" Flag and not the Costum 0x0100 Flag]
<IT+x ITem + Get item X
<IT-x ITem - Lose item X
<ITJx:y ITem Jump Jump to event Y if you have item X
<KEY KEYlock Hides status bars and locks out input to your character until END (used with MSG/MS2/MS3 and PRI)
<LDP LoaD Profile Loads profile.dat into memory and starts game from save
<LI+x LIfe + Restore X amount of health
<ML+x Max Life + Max health increased X amount
<MLP Map [LP?] Display map
<MM0 My Motion 0 Instantly halts your horizontal motion
<MNA [Map NAme?] Displays name of current map
<MNPx:y:z:w Move NPc Move npc X to coords Y:Z facing direction W
<MOVx:y MOVe Move you to coords X:Y
<MP+x [MaP ??] @ [map-related]
<MPJx [MaP Jump?] [Jump to event X if map exists for current area? the single instance of this seems to be dummied out]
<MS2 MeSsage 2 Open invisible text box at top of screen (text follows)
<MS3 MeSsage 3 Open normal text box at top of screen (text follows)
<MSG MeSsaGe 1 Open normal text box (text follows)
<MYBx MY Bump Knocks you back from direction X (0000 knocked right, 0002 knocked left, any other just hops in place)
<MYDx MY Direction Make you face direction X
<NCJx:y [NpC?] Jump Jump to event Y if any npc of type X is present
<NOD [Nod? Text box wait for button press (used after MSG/MS2/MS3)
<NUM0000 [Number?] Used to output Y from AM+ as text
<PRI [?] Hides status bars and freezes game action until KEY or END (used with MSG/MS2/MS3)
<PS+x:y [P? Slot?] Set teleporter slot X to location Y
<QUAx QUAke Shake the screen for X ticks
<RMU Restore MUsic Restore music playback [plays previous song? or only works with some songs?]
<SAT Speed-up All Text Instant text display on all messages until END (glitches scrolling text)
<SILx Show ILlustration Show illustration during credits (use CIL after)
<SK+x SKipflag + Set skipflag X (remains set until program exits, to avoid repeating cutscenes/dialogue after retrying)
<SK-x SKipflag -? @ Clear skipflag
<SKJx:y SKipflag Jump Jump to event Y if skipflag X is set
<SLP [Show? Location? P?] Teleporter location menu
<SMC Show My Character Restores main character npc (used after HMC)
<SMPx:y [?] [do something with npc X? - only used before and after the Omega fight]
<SNPx:y:z:w [Start?] NPc @ Create npc type X at coords Y:Z with direction W
<SOUx SOUnd Play sound effect X
<SPS Start Prop. Sound Start propeller sound (use CPS after) (from helicopter cutscene after final battles)
<SSSx Start Stream Sound Start stream sound at pitch X (use CSS after) (from River area - normal pitch is 0400)
<STC Save Time Counted Saves the current time to 290.rec
<SVP SaVe Profile Save game
<TAMx:y:z Trade ArMs Trade weapon X for weapon Y, set max ammo to Z (max ammo 0000 = no change) (GLITCH: first weapon 0000)
<TRAx:y:z:w TRAnsport Load map X, run event Y, transport you to coords Z:W
<TUR [?] Instant text display [until what? CLR?] (used after MSG/MS2/MS3)
<UNIx [?] [0000 normal / 0001 zero-g movement, facing direction is locked (disables focus commands) (from Stream boss) / 0002 movement is locked, can still fire]
<UNJx [?] Jump? [?]
<WAIx WAIt Pause script for X ticks
<WAS WAit until Standing Pause script until your character touches the ground
<XX1x [?] [shows distant view of island?]
<YNJx Yes/No Jump Ask yes or no, jump to event X if No
<ZAM Zero ArMs All weapons drop to level 1
Notes:
Invalid commands show an error message displaying the command before the game exits
The "jump if equipped" function is done with FLJ - an arbitrary flag is chosen, and every instance of EQ+/EQ- must also have the FL+/FL- command
The colon between parameters can be any character (it's ignored)
CREDITS FORMAT (credit.tsc)
==============
[T]X Text T with casts.pbm image X [on left?]
+X [?]
!X [?]
-X [line has height X?]
fX:Y Jump to location Y if flag X is set
jX Jump to location X
lX Location X
~ [switch to the left half of the screen?]
/ [end?]
<<< [comment?]
NPC FLAGS
==============
0x0001 - Solid
0x0002 - No effect about Tile 44
0x0004 - Invulnerable (Blink Sound)
0x0008 - Ignore solid
0x0010 - Bouncing at top
0x0020 - Shootable
0x0040 - Special Solid
0x0080 - Rear and top attack power 0
0x0100 - Costum
0x0200 - Boss Flag
0x0400 - ???
0x0800 - Is visible if FlagID is set
0x1000 - Costum
0x2000 - Call on Event
0x4000 - Is invisible if FlagID is set
0x8000 - Show Damage Numbers
COMMAND VALUES
==============
Maps (TRA) Profile.dat byte 0x008 - for position, 0x011-012: distance from left,
0x015-016: distance from top, 20h (32) per map tile (low byte first)
0000 0 Credits
0001 Pens1 Arthur's House - normal
0002 Eggs Egg Corridor
0003 EggX Egg No. 00 - normal
0004 Egg6 Egg No. 06
0005 EggR Egg Observation Room
0006 Weed Grasstown
0007 Santa Santa's House
0008 Chako Chaco's House
0009 MazeI Labyrinth I (vertical starting room)
0010 Sand Sand Zone - normal
0011 Mimi Mimiga Village
0012 Cave First Cave
0013 Start Start Point
0014 Barr Shack (Mimiga Village)
0015 Pool Reservoir
0016 Cemet Graveyard
0017 Plant Yamashita Farm
0018 Shelt Shelter (Grasstown)
0019 Comu Assembly Hall (Mimiga Village)
0020 MiBox Save Point (Mimiga Village)
0021 EgEnd1 Side Room (Egg Corridor)
0022 Cthu Cthulhu's Abode (Egg Corridor)
0023 Egg1 Egg No. 01
0024 Pens2 Arthur's House - Sue on computer
0025 Malco Power Room (Grasstown)
0026 WeedS Save Point (Grasstown)
0027 WeedD Execution Chamber (Grasstown)
0028 Frog Gum (Grasstown)
0029 Curly Sand Zone Residence
0030 WeedB Grasstown Hut
0031 Stream Main Artery (Waterway)
0032 CurlyS Small Room (Sand Zone)
0033 Jenka1 Jenka's House - normal
0034 Dark Deserted House (Sand Zone)
0035 Gard Sand Zone Storehouse
0036 Jenka2 Jenka's House - after Balrog attacks
0037 SandE Sand Zone - after boss fight
0038 MazeH Labyrinth H (sliding block room)
0039 MazeW Labyrinth W (main area w/shop, camp)
0040 MazeO Camp (Labyrinth)
0041 MazeD Clinic Ruins (Labyrinth)
0042 MazeA Labyrinth Shop
0043 MazeB Labyrinth B (booster)
0044 MazeS Boulder Chamber (Labyrinth)
0045 MazeM Labyrinth M (gaudi eggs)
0046 Drain Dark Place (Labyrinth)
0047 Almond Core (Labyrinth)
0048 River Waterway
0049 Eggs2 Egg Corridor?
0050 Cthu2 Cthulhu's Abode? (Egg Corridor?)
0051 EggR2 Egg Observation Room?
0052 EggX2 Egg No. 00 - hatched
0053 Oside Outer Wall
0054 EgEnd2 Side Room (Egg Corridor?)
0055 Itoh Storehouse (Outer Wall)
0056 Cent Plantation
0057 Jail1 Jail No. 1 (Plantation)
0058 Momo Hideout (Plantation)
0059 Lounge Rest Area (Plantation)
0060 CentW Teleporter (Plantation)
0061 Jail2 Jail No. 2 (Plantation)
0062 Blcny1 Balcony - normal
0063 Priso1 Last Cave
0064 Ring1 Throne Room (Balcony)
0065 Ring2 The King's Table (Balcony)
0066 Prefa1 Prefab House (Balcony) - normal
0067 Priso2 Last Cave Hidden
0068 Ring3 Black Space (Balcony)
0069 Little Little House (Outer Wall)
0070 Blcny2 Balcony - after boss fights
0071 Fall Ending
0072 Kings Intro
0073 Pixel Waterway Cabin
0074 e_Maze Credits - Labyrinth
0075 e_Jenk Credits - Jenka's House
0076 e_Malc Credits - Power Room
0077 e_Ceme Credits - Graveyard
0078 e_Sky Credits - Sky
0079 Prefa2 Prefab House (Balcony) - entrance to hell
0080 Hell1 Sacred Ground B1
0081 Hell2 Sacred Ground B2
0082 Hell3 Sacred Ground B3
0083 Mapi Storage (Graveyard)
0084 Hell4 Passage? - normal
0085 Hell42 Passage? - from Sacred Ground B3
0086 Statue Statue Chamber (Plantation/Sacred Grounds)
0087 Ballo1 Seal Chamber (Sacred Grounds) - normal
0088 Ostep Corridor (Sacred Grounds)
0089 e_Labo Credits - Laboratory
0090 Pole Hermit Gunsmith
0091 Island [map is totally blank - TSC is called right before good/best endings]
0092 Ballo2 Seal Chamber (Sacred Grounds) - after boss fight
0093 e_Blcn Credits - Balcony
0094 Clock Clock Room (Outer Wall)
Directions (FAI/FAO/MYD/MYB) Profile.dat bytes 0x018 (your direction)
0000 Left
0001 Up [FAI/FAO only?]
0002 Right
0003 Down
0004 Center [FAI/FAO only?]
NOTE: MYB is 0000 Right, 0002 Left (reversed)
Focus speed (FOB/FOM/FON)
0000 (CRASH - probably divide by zero error)
0001 Instant
0016 Fast
0032 Medium
0064 Slow
NOTE: Any value besides zero should work, these four are the only ones used normally
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)
0000 [nothing?]
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
Faces (FAC)
0000 [blank - does this set the text to normal width?]
0001 Sue (smile)
0002 Sue (frown)
0003 Sue (angry)
0004 Sue (hurt)
0005 Balrog (normal)
0006 Toroko (normal)
0007 King
0008 Toroko (angry)
0009 Jack
0010 Kazuma
0011 Toroko (rage)
0012 Igor
0013 Jenka
0014 Balrog (smile)
0015 Misery (normal)
0016 Misery (smile)
0017 Booster (hurt)
0018 Booster (normal)
0019 Curly (smile)
0020 Curly (frown)
0021 Doctor
0022 Momorin
0023 Balrog (hurt)
0024 Broken robot
0025 Curly (?)
0026 Misery (angry)
0027 Human Sue
0028 Itoh
0029 Ballos
Illustrations (SIL)
0001 riding Sky Dragon
0002 fighting Core
0003 fighting Misery
0004 Momorin's rocket
0005 Outer Wall
0006 fighting Ironhead
0007 fighting Balrog (with missiles)
0008 Clinic
0009 King fighting the Doctor
0010 Jenka with puppies
0011 Curly with Mimiga children
0012 riding Balrog
0014 Hell
0015 floating island (blue sky)
0016 floating island (orange sky)
0017 King, Jack, Sue
0018 Ballos
NOTE: any other values (including 0013) show 0001
Songs (CMU) Profile.dat byte 0x00C
0000 (none - silence)
0001 Mischievous Robot Egg Chamber
0002 Safety various homes
0003 (no title) game over
0004 Gravity boss battle
0005 On To Grasstown Grasstown
0006 Meltdown 2 Sand Zone
0007 Eyes of Flame major boss battle
0008 Gestation First Cave, various small rooms
0009 Mimiga Town Mimiga Village
0010 (no title) get item
0011 Balrog's Theme Balrog cutscenes
0012 Cemetary Graveyard
0013 Plant Yamashita Farm
0014 Pulse Egg No. 00, Waterway Cabin, Arthur's House after Waterway
0015 (no title) boss defeated
0016 (no title) get life capsule
0017 Tyrant Doctor cutscenes
0018 Run! Balcony areas after boss fights
0019 Jenka 1 Jenka's House, Labyrinth I & H (first two areas)
0020 Labyrinth Fight Labyrinth M (gaudi eggs)
0021 Access Shelter (Kazuma on computer)
0022 Oppression Core battle
0023 Geothermal Dark Place, Core, [Main Artery?]
0024 Cave Story title screen, Plantation
0025 Moonsong Outer Wall
0026 Hero's End bad ending
0027 Scorching Back Egg Corridor?
0028 Quiet Mimiga Village and homes after Waterway
0029 Final Cave Last Cave
0030 Balcony Balcony
0031 Charge Muscle Doctor battle
0032 Last Battle final battles
0033 The Way Back Home Credits
0034 Zombie before Undead Core battle, after Ballos battle
0035 Break Down Ending
0036 Running Hell Sacred Grounds
0037 Jenka 2 Labyrinth W (main area w/shop, camp)
0038 Living Waterway Waterway
0039 Seal Chamber before Ballos battle
0040 Toroko's Theme Title Screen - Toroko
0041 ["White"?] Title Screen - King
Sound Effects (SOU)
0000 <nothing>
0001 [blip]
0002 Message typing
0003 Bonk
0004 Weapon switch
0005 [?]
0006 [critter hop?]
0007 [nothing?]
0008 [nothing?]
0009 [nothing?]
0010 [nothing?]
0011 Door
0012 [*plsh* - map tile change?]
0013 [nothing?]
0014 Get weapon energy
0015 [click]
0016 Take damage
0017 Die
0018 [menu?]
0019 [nothing?]
0020 Health/ammo refill
0021 [bubble]
0022 Click (chest, life capsule, unlock door)
0023 [thud]
0024 [tap - walking?]
0025 [enemy killed?]
0026 [loud thud - balrog?]
0027 Level Up
0028 [thump]
0029 Teleport
0030 [jump]
0031 Invulnerable "ting"
0032 [shot - polar star?]
0033 [shot - fireball]
0034 [shot - fireball bounce?]
0035 [explosion (missiles?]
0036 [nothing?]
0037 [click]
0038 [get item?]
0039 [*bvng*]
0040 [water?]
0041 [water?]
0042 [beep]
0043 Computer beep (activate terminals, etc.)
0044 Blast (blow up door to Shelt)
0045 Weapon energy bounce
0046 [*ftt*]
0047 [?]
0048 [shot - bubble pop?]
0049 [shot - spur lv 1]
0050 [enemy squeak]
0051 [enemy take damage]
0052 [large enemy take damage (roar)]
0053 [enemy squeak-bblblbl]
0054 [object shot (thud)]
0055 [enemy squeak]
0056 [splash]
0057 [little damage sound]
0058 [*chlk*]
0059 [nothing?]
0060 [spur charge - lower]
0061 [spur charge - higher]
0062 Shot - Spur lv 2
0063 Shot - Spur lv 3
0064 Shot - Spur max
0065 Spur fully charged
0066 [nothing?]
0067 [nothing?]
0068 [nothing?]
0069 [nothing?]
0070 [Sue hitting you while you're unconscious in Jail1]
0071 [explosion]
0072 [explosion]
0073 [nothing?]
0074 [nothing?]
0075 [nothing?]
0076 [nothing?]
0077 [nothing?]
0078 [nothing?]
0079 [nothing?]
0080 [nothing?]
0081 [nothing?]
0082 [nothing?]
0083 [nothing?]
0084 [nothing?]
0085 [nothing?]
0086 [nothing?]
0087 [nothing?]
0088 [nothing?]
0089 [nothing?]
0090 [nothing?]
0091 [nothing?]
0092 [nothing?]
0093 [nothing?]
0094 [nothing?]
0095 [nothing?]
0096 [nothing?]
0097 [nothing?]
0098 [nothing?]
0099 [nothing?]
http://spgardebiter.sp.funpic.de/CaveStory/FAQ/TSC.txt

2250
src/lib/moses.lua Normal file

File diff suppressed because it is too large Load diff

124
src/lib/serpent.lua Normal file
View file

@ -0,0 +1,124 @@
local n, v = "serpent", 0.28 -- (C) 2012-15 Paul Kulchenko; MIT License
local c, d = "Paul Kulchenko", "Lua serializer and pretty printer"
local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'}
local badtype = {thread = true, userdata = true, cdata = true}
local keyword, globals, G = {}, {}, (_G or _ENV)
for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false',
'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat',
'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end
for k,v in pairs(G) do globals[v] = k end -- build func to name mapping
for _,g in ipairs({'coroutine', 'debug', 'io', 'math', 'string', 'table', 'os'}) do
for k,v in pairs(G[g] or {}) do globals[v] = g..'.'..k end end
local function s(t, opts)
local name, indent, fatal, maxnum = opts.name, opts.indent, opts.fatal, opts.maxnum
local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge
local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge)
local iname, comm = '_'..(name or ''), opts.comment and (tonumber(opts.comment) or math.huge)
local seen, sref, syms, symn = {}, {'local '..iname..'={}'}, {}, 0
local function gensym(val) return '_'..(tostring(tostring(val)):gsub("[^%w]",""):gsub("(%d%w+)",
-- tostring(val) is needed because __tostring may return a non-string value
function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return tostring(syms[s]) end)) end
local function safestr(s) return type(s) == "number" and tostring(huge and snum[tostring(s)] or s)
or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026
or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end
local function comment(s,l) return comm and (l or 0) < comm and ' --[['..tostring(s)..']]' or '' end
local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal
and safestr(select(2, pcall(tostring, s))) or error("Can't serialize "..tostring(s)) end
local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r']
local n = name == nil and '' or name
local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n]
local safe = plain and n or '['..safestr(n)..']'
return (path or '')..(plain and path and '.' or '')..safe, safe end
local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(k, o, n) -- k=keys, o=originaltable, n=padding
local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'}
local function padnum(d) return ("%0"..tostring(maxn).."d"):format(tonumber(d)) end
table.sort(k, function(a,b)
-- sort numeric keys first: k[key] is not nil for numerical keys
return (k[a] ~= nil and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum))
< (k[b] ~= nil and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end
local function val2str(t, name, indent, insref, path, plainindex, level)
local ttype, level, mt = type(t), (level or 0), getmetatable(t)
local spath, sname = safename(path, name)
local tag = plainindex and
((type(name) == "number") and '' or name..space..'='..space) or
(name ~= nil and sname..space..'='..space or '')
if seen[t] then -- already seen this element
sref[#sref+1] = spath..space..'='..space..seen[t]
return tag..'nil'..comment('ref', level) end
if type(mt) == 'table' and (mt.__serialize or mt.__tostring) then -- knows how to serialize itself
seen[t] = insref or spath
if mt.__serialize then t = mt.__serialize(t) else t = tostring(t) end
ttype = type(t) end -- new value falls through to be serialized
if ttype == "table" then
if level >= maxl then return tag..'{}'..comment('max', level) end
seen[t] = insref or spath
if next(t) == nil then return tag..'{}'..comment(t, level) end -- table empty
local maxn, o, out = math.min(#t, maxnum or #t), {}, {}
for key = 1, maxn do o[key] = key end
if not maxnum or #o < maxnum then
local n = #o -- n = n + 1; o[n] is much faster than o[#o+1] on large tables
for key in pairs(t) do if o[key] ~= key then n = n + 1; o[n] = key end end end
if maxnum and #o > maxnum then o[maxnum+1] = nil end
if opts.sortkeys and #o > maxn then alphanumsort(o, t, opts.sortkeys) end
local sparse = sparse and #o > maxn -- disable sparsness if only numeric keys (shorter output)
for n, key in ipairs(o) do
local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse
if opts.valignore and opts.valignore[value] -- skip ignored values; do nothing
or opts.keyallow and not opts.keyallow[key]
or opts.valtypeignore and opts.valtypeignore[type(value)] -- skipping ignored value types
or sparse and value == nil then -- skipping nils; do nothing
elseif ktype == 'table' or ktype == 'function' or badtype[ktype] then
if not seen[key] and not globals[key] then
sref[#sref+1] = 'placeholder'
local sname = safename(iname, gensym(key)) -- iname is table for local variables
sref[#sref] = val2str(key,sname,indent,sname,iname,true) end
sref[#sref+1] = 'placeholder'
local path = seen[t]..'['..tostring(seen[key] or globals[key] or gensym(key))..']'
sref[#sref] = path..space..'='..space..tostring(seen[value] or val2str(value,nil,indent,path))
else
out[#out+1] = val2str(value,key,indent,insref,seen[t],plainindex,level+1)
end
end
local prefix = string.rep(indent or '', level)
local head = indent and '{\n'..prefix..indent or '{'
local body = table.concat(out, ','..(indent and '\n'..prefix..indent or space))
local tail = indent and "\n"..prefix..'}' or '}'
return (custom and custom(tag,head,body,tail) or tag..head..body..tail)..comment(t, level)
elseif badtype[ttype] then
seen[t] = insref or spath
return tag..globerr(t, level)
elseif ttype == 'function' then
seen[t] = insref or spath
local ok, res = pcall(string.dump, t)
local func = ok and ((opts.nocode and "function() --[[..skipped..]] end" or
"((loadstring or load)("..safestr(res)..",'@serialized'))")..comment(t, level))
return tag..(func or globerr(t, level))
else return tag..safestr(t) end -- handle all other types
end
local sepr = indent and "\n" or ";"..space
local body = val2str(t, name, indent) -- this call also populates sref
local tail = #sref>1 and table.concat(sref, sepr)..sepr or ''
local warn = opts.comment and #sref>1 and space.."--[[incomplete output with shared/self-references skipped]]" or ''
return not name and body..warn or "do local "..body..sepr..tail.."return "..name..sepr.."end"
end
local function deserialize(data, opts)
local env = (opts and opts.safe == false) and G
or setmetatable({}, {
__index = function(t,k) return t end,
__call = function(t,...) error("cannot call functions") end
})
local f, res = (loadstring or load)('return '..data, nil, nil, env)
if not f then f, res = (loadstring or load)(data, nil, nil, env) end
if not f then return f, res end
if setfenv then setfenv(f, env) end
return pcall(f)
end
local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end
return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s,
load = deserialize,
dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end,
line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end,
block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = true}, opts)) end }

39
src/lib/strict.lua Normal file
View file

@ -0,0 +1,39 @@
-- strict.lua
-- checks uses of undeclared global variables
-- All global variables must be 'declared' through a regular assignment
-- (even assigning nil will do) in a main chunk before being used
-- anywhere or assigned to inside a function.
-- distributed under the Lua license: http://www.lua.org/license.html
local getinfo, error, rawset, rawget = debug.getinfo, error, rawset, rawget
local mt = getmetatable(_G)
if mt == nil then
mt = {}
setmetatable(_G, mt)
end
mt.__declared = {}
local function what ()
local d = getinfo(3, "S")
return d and d.what or "C"
end
mt.__newindex = function (t, n, v)
if not mt.__declared[n] then
local w = what()
if w ~= "main" and w ~= "C" then
error("assign to undeclared variable '"..n.."'", 2)
end
mt.__declared[n] = true
end
rawset(t, n, v)
end
mt.__index = function (t, n)
if not mt.__declared[n] and what() ~= "C" then
error("variable '"..n.."' is not declared", 2)
end
return rawget(t, n)
end

214
src/main.lua Normal file
View file

@ -0,0 +1,214 @@
io.stdout:setvbuf("no")
require 'lib.strict'
local _ = require 'lib.moses'
local Serpent = require 'lib.serpent'
local lf = love.filesystem
local MODE_READ_BINARY = 'rb'
local MODE_WRITE_BINARY = 'wb'
function readLittleEndian(file, bytes)
local string = file:read(2)
local bytes = string:byte()
-- print(string, type(bytes), bytes)
return bytes
end
-- https://gist.github.com/fdeitylink/3fded36e9187fe838eb18a412c712800
-- -=~ PXM File Data ~=-
-- maps must be minimum of 21x16
function readPXM(filename)
print('reading PXM: ' .. filename)
local file = assert(io.open(filename, MODE_READ_BINARY))
-- First three bytes are PXM, then 0x10.
assert(file:read(3) == "PXM")
assert(file:read(1):byte() == 0x10)
-- Then 0x_map_length - 2 bytes
-- Then 0x_map_height - 2 bytes
local length = readLittleEndian(file, 2)
local height = readLittleEndian(file, 2)
print('length:', length)
print('height:', height)
-- 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
local tiles = {}
for x = 1, length do
tiles[x] = {}
end
for y = 1, height do
for x = 1, length do
tiles[x][y] = file:read(1):byte()
end
end
-- Print result
local XXX = 3
for y = 1, height do
local line = ""
for x = 1, length do
local tile = tiles[x][y]
local len = string.len(tile)
line = line .. string.rep(' ', XXX - len) .. tile
end
print(line)
end
end
local ITEM_DATA = {
-- Weapons
wPolar = {
name = "Polar Star",
map = "Pole",
getText = "Got the =Polar Star=!",
command = "<AM+0002:0000",
displayCmd = "<GIT0002",
},
-- Items
iPanties = {
name = "Curly's Panties",
map = "CurlyS",
-- getText = "Found =Curly's Underwear=.",
getText = "Found =Curly's Panties=.",
command = "<IT+0035",
displayCmd = "<GIT1035",
},
}
function stringReplace(text, needle, replacement)
local i = text:find(needle, 1, true)
if i == nil then
return text
end
local len = needle:len()
local j = i + len - 1
assert((i % 1 == 0) and (i > 0) and (i <= j), tostring(i))
assert((j % 1 == 0), tostring(j))
local a = text:sub(1, i - 1)
local b = text:sub(j + 1)
return a .. replacement .. b
end
function readTSC(filename, decodedFilename)
print('reading TSC: ' .. filename)
local file = assert(io.open(filename, MODE_READ_BINARY))
local filesize = file:seek("end")
local encodingCharPosition = math.floor(filesize / 2)
file:seek("set", encodingCharPosition)
local encodingChar = file:read(1):byte()
print(" filesize", filesize)
print(" encoding char:", encodingChar)
print(" encoding char position:", encodingCharPosition)
-- Decode
local chars, len = {}, 0
file:seek("set")
for pos = 0, filesize - 1 do
local byte = file:read(1):byte()
if pos ~= encodingCharPosition then
-- print(pos, encodingCharPosition)
byte = (byte - encodingChar) % 256
-- byte = byte - encodingChar
end
len = len + 1
chars[len] = string.char(byte)
end
local decoded = table.concat(chars)
local t = {}
decoded:gsub(".",function(c) table.insert(t,c) end)
-- for i, c in ipairs(t) do
local near = 10
for i = 1270 - near, 1270 + near do
local c = t[i]
print (i, c, chars[i])
-- print(string.byte(chars[i]) == string.byte(c), string.byte(chars[i]), string.byte(c))
end
-- -- Replace
-- decoded = stringReplace(decoded, ITEM_DATA.wPolar.command, ITEM_DATA.iPanties.command)
-- decoded = stringReplace(decoded, ITEM_DATA.wPolar.getText, ITEM_DATA.iPanties.getText)
-- decoded = stringReplace(decoded, ITEM_DATA.wPolar.displayCmd, ITEM_DATA.iPanties.displayCmd)
-- Write
-- return decoded
local tmpFile, err = io.open(decodedFilename, MODE_WRITE_BINARY)
assert(err == nil, err)
tmpFile:write(decoded)
tmpFile:flush()
tmpFile:close()
end
function writeTSC(filename)
print('writing TSC: ' .. filename)
local file = assert(io.open(filename, MODE_READ_BINARY))
local filesize = file:seek("end")
local encodingCharPosition = math.floor(filesize / 2)
file:seek("set", encodingCharPosition)
local encodingChar = file:read(1):byte()
file:seek("set", encodingCharPosition)
print(file:read(1))
-- local encodingChar = 32
print(" filesize", filesize)
print(" encoding char:", encodingChar)
print(" encoding char position:", encodingCharPosition)
-- Encode
local chars, len = {}, 0
file:seek("set")
for pos = 0, filesize - 1 do
local byte = file:read(1):byte()
if pos ~= encodingCharPosition then
byte = (byte + encodingChar) % 255
end
len = len + 1
chars[len] = string.char(byte)
end
local decoded = table.concat(chars)
-- Write
local tmpFile, err = io.open('TestingEncoded.tsc', MODE_WRITE_BINARY)
assert(err == nil, err)
tmpFile:write(decoded)
tmpFile:flush()
tmpFile:close()
end
function love.load()
-- readPXM('Pole.pxm')
-- readTSC('Pole.tsc', 'Testing.tsc')
-- writeTSC('Testing.tsc')
-- readTSC('TestingEncoded.tsc', 'TestingDecoded.tsc')
end
function love.directorydropped(path)
local success = lf.mount(path, 'data')
assert(success)
local items = lf.getDirectoryItems('/data')
local containsStage = _.contains(items, 'Stage')
assert(containsStage)
local dirStage = '/data/Stage'
-- local items = lf.getDirectoryItems(dirStage)
-- print(Serpent.block(items))
end
function love.keypressed(key)
if key == 'escape' then
love.event.push('quit')
end
end
-- #0200
-- <KEY<FLJ1640:0201<FL+1640<SOU0022<CNP0200:0021:0000
-- <MSGOpened the chest.<NOD<GIT0002<AM+0002:0000<CLR
-- <CMU0010Got the =Polar Star=!<WAI0160<NOD<GIT0000<CLO<RMU
-- <MSG
-- From somewhere, a transmission...<FAO0004<NOD<TRA0018:0501:0002:0000
-- #0420
-- <KEY<DNP0420<MSG<GIT1035<IT+0035
-- Found Curly's Panties.<NOD<END