display-name: "Games/Tyrian"
meta: {"Working": ["Tiles, most images and sprites", "Sounds", "Some text"]}

pal-off: 0

if (file.name like "*.snd")
{
	unsigned16 count

	file-number: 0

	file[count]
	{
		unsigned32 offset
		name: "" + file-number + ".wav"
		file-number = file-number + 1
		interpret-as "tyrian-sound"
	}
}

file-format tyrian-sound
{
	sound
	{
		channels: 1
		sound-signed: 1
        samples-per-second: 11025
        bits-per-sample: 8
        volume: 255
	}
}

if (file.name == "palette.dat")
{
	palette
	{
		size: 256
		format: "R6G6B6"
	}
}

if (file.name == "tyrian.pic")
{
	unsigned16 image-count

	file[image-count]: i
	{
		name: "Image " + (i + 1)
		unsigned32 offset
		image-index: i
		interpret-as "tyrian-fsimage"
	}
}

pal-remap: [0, 7, 5, 8, 10, 5, 18, 19, 19, 20, 21, 22, 5, 23 ]

file-format tyrian-fsimage
{
	//Get palette
	from "palette.dat" at (pal-remap[image-index] * 768)
	{
		palette
		{
			size: 256
			format: "R6G6B6"
		}
	}

	width: 320
	height: 200
	totalBytesPerRow: width
	compressed[file.size] "PCXRLE"
	{
		image
		{
			format: "I8"
		}
	}
}

width: 24
height: 28

if (file.name like "s*.dat")
{
	folder: "Tiles"

	tiles-drawn: 0

	image-layout-width: 240
	image-layout
	{
		loop while (tiles-drawn < 1120)
		{
			blank-tile-count: 0

			loop
			{
				unsigned8 read-byte
				blank-tile-count = blank-tile-count + 1
				tiles-drawn = tiles-drawn + 1
			} while (read-byte != 0 and tiles-drawn < 1120)

			loop (blank-tile-count - 1)
			{
				image
				{
					format: "blank"
				}					
			}

			if (file.remaining-bytes > 518)
			{
				tiles-drawn = tiles-drawn + 1

				image
				{
					format: "I8"
					palette: "palette.dat"
				}
			}
		}
	}

	//other data here...tile attribs? 518 bytes of something
	data(518) unknown
}

if (file.name like ["tyrian.shp", "tyrianc.shp"])
{
	unsigned16 shp-count

	file[shp-count]: i
	{
		name: "Shape " + i
		unsigned32 offset

		if (i == 3)
		{
			//Planets
			interpret-as "tyrian-shape-planets"
		}
		else if (i == 4)
		{
			//Faces
			interpret-as "tyrian-shape-faces"
		}
		else if (i <= 6)
		{
			pal-off: 0
			interpret-as "tyrian-shape-0"
		}
		else
		{
			interpret-as "tyrian-sprite2"
		}
	}
}

file-format tyrian-shape-planets
{
	unsigned16 count

	loop (count): i
	{
		unsigned8 unknown
		unsigned16 width
		unsigned16 height
		unsigned16 size

		if ((i == 151) or (i == 146))
		{
			pal-off: 8
		}
		else
		{
			pal-off: 17
		}

		decomp-width: width

		compressed[size] "tyrian-rle"
		{
			image
			{
				format: "I8"
				from "palette.dat" at (pal-off * 768)
				{
					palette
					{
						size: 256
						format: "R6G6B6"
					}
				}
				transparent-index: 0xFF
			}
		}
	}
}

face-palettes: [1, 2, 3, 4, 6, 9, 11, 12, 16, 13, 14, 15, 0, 0, 0, 0, 0, 0]

file-format tyrian-shape-faces
{
	unsigned16 count

	loop (count): i
	{
		unsigned8 unknown
		unsigned16 width
		unsigned16 height
		unsigned16 size

		pal-off: face-palettes[i]

		decomp-width: width

		compressed[size] "tyrian-rle"
		{
			image
			{
				format: "I8"
				from "palette.dat" at (pal-off * 768)
				{
					palette
					{
						size: 256
						format: "R6G6B6"
					}
				}
				transparent-index: 0xFF
			}
		}
	}
}

file-format tyrian-shape-0
{
	unsigned16 count

	loop (count): i
	{
		unsigned8 unknown
		unsigned16 width
		unsigned16 height
		unsigned16 size

		decomp-width: width

		compressed[size] "tyrian-rle"
		{
			image
			{
				format: "I8"
				//palette: "palette.dat"
				from "palette.dat" at (pal-off * 768)
				{
					palette
					{
						size: 256
						format: "R6G6B6"
					}
				}
				transparent-index: 0xFF
			}
		}
	}
}

if (file.name == "estsc.shp")
{
	interpret-as "tyrian-shape-0"
}


if (file.name like "newsh?.shp")
{
	folder: "Sprites"
	interpret-as "tyrian-sprite2"
}

file-format tyrian-sprite2
{
	unsigned16 first-offset

	at 0:

	image-layout-width: 228
	image-layout
	{
		loop while (file.position < first-offset): i
		{
			unsigned16 offset

			at offset
			{
				compressed[file.remaining-bytes] "tyrian-rle2"
				{
					
					image
					{
						format: "I8"
						width: 12
						height: 12
						transparent-index: 0
						palette: "palette.dat"
					}
				}
			}
		}
	}
}

function tyrian-rle2
{
	written: 0
	loop while (written < (12 * 12))
	{
		read unsigned8 opcode

		if (opcode == 0x0F)
		{
			loop ((12 * 12) - written)
			{
				write unsigned8 0
			}

			written = 12 * 12
		}
		else
		{
			trans-count: opcode & 0xF

			loop (trans-count)
			{
				write unsigned8 0
			}

			loop (opcode >> 4)
			{
				read unsigned8 pixel
				write unsigned8 pixel
			}

			written = written + trans-count + (opcode >> 4)
		}
	}
}

function tyrian-rle
{
	current-x: 0

	loop while (file.remaining-bytes > 0)
	{
		read unsigned8 opcode
		if (opcode == 0xFF)
		{
			read unsigned8 num-trans
			loop (num-trans)
			{
				write unsigned8 0xFF
			}
			current-x = current-x + num-trans
		}
		else if (opcode == 0xFE)
		{
			loop (decomp-width - current-x)
			{
				write unsigned8 0xFF
			}
			current-x = decomp-width
		}
		else if (opcode == 0xFD)
		{
			write unsigned8 0xFF
			current-x = current-x + 1
		}
		else
		{
			write unsigned8 opcode
			current-x = current-x + 1
		}

		if (current-x >= decomp-width)
		{
			current-x = 0
		}
	}
}

if (file.name like "*.pcx")
{
	interpret-as "image-PCX"
}

if (file.name like ["cubetxt?.dat", "tyrian.cdt"])
{
	encrypted [file.size] "tyrian-xor" 
	{
		text
	}
}

if (file.name like "levels?.dat")
{
	folder: "Levels"

	encrypted [file.size] "tyrian-xor" 
	{
		text
	}
}

function tyrian-xor
{
	XORData: [0xCC, 0x81, 0x3F, 0xFF, 0x47, 0x13, 0x19, 0x3E, 0x01, 0x63]

	loop while (file.remaining-bytes > 0)
	{
		counter: 0

		read unsigned8 count

		oldVal: 0
		loop (count)
		{
        		read unsigned8 encrypted-byte
        		write unsigned8 encrypted-byte ^ oldVal ^ XORData[counter % 10]
        		oldVal = encrypted-byte
			counter = counter + 1
		}

		write unsigned8 0x0D
		write unsigned8 0x0A
	}
}

if (file.name like "tyrian*.lvl")
{
	folder: "Levels"
	unsigned16 section-count

	file[section-count]: i
	{
		name: "Section " + i
		unsigned32 offset	
	}
}