display-name: "Games/Dune 2"
meta: {"Working": ["Packed file extraction", "All graphics", "Text", "Sound"],
"Thanks to": ["Vladan Bato", "Siberian_GRemlin"]}

if (file.name like "*.pak")
{
	file 
	{
		unsigned32 offset
		skip-if (offset == 0)
	
		string name
	} while (offset > 0)
}

if (file.name like "*.pal")
{
	palette
	{
		size: 256
		format: "R6G6B6"
	}
}

if (file.name == "icon.icn")
{
	folder: "Tiles"
	interpret-as-internally "iff"

	palette: "dune.pak\\ibm.pal"

	from "icon\\rtbl"
	{
		image-amount: file.size
	}

	loop (3): ol {

	image-layout-width: 16 * 10
	image-layout
	{
		loop (image-amount): i
		{
			from "icon\\rtbl" at i
			{
				unsigned8 rtbl-lookup
			}

			any-remapped: false

			from "icon\\rpal" at rtbl-lookup * 16
			{
				unsigned8[16] rpal-lookup

				loop (16):r {
					if ((rpal-lookup[r] >= (9 * 16)) and (rpal-lookup[r] <= (9 * 16 + 7))) {
						rpal-lookup[r] = rpal-lookup[r] + (ol * 16)
						any-remapped = true
					}
				}
			}

			if ((ol == 0) or (any-remapped == true))
			{

			from "icon\\sset" at (i * 128) + 8
			{
				compressed[128] "dune2-tile"
				{
					image
					{
						format: "I8"
						width: 16
						height: 16
					}
				}
			}
			}
		}
	}
	}
}

function dune2-tile
{
	loop (file.size)
	{
		read unsigned8 comp
		write unsigned8 rpal-lookup[comp >> 4]
		write unsigned8 rpal-lookup[comp & 0xF]
	}
}

if (file.name like ["*.cps", "misc.???", "and.???", "title.???", "herald.???"])
{
	folder: "Fullscreen Images"

	unsigned16 shortSize  // File size
	unsigned16 unknown  //  Always 0004h
	unsigned32 decompressed-size  // Size of uncompressed image (always FA00h)
	unsigned16 paletteSize // 768 or 0

	if (paletteSize == 768)
	{
		palette
		{
			size: 256
			format: "R6G6B6"
		}
	}
	else
	{
		if (file.name == "mentatm.cps")
		{
			palette: "bene.pal"
		}
		else
		{
			palette: "dune.pak\\ibm.pal"
		}
	}

	compressed [file.remaining-bytes] "Westwood80"
	{
		image
		{
			format: "I8"
			width: 320
			height: 200
		}
	}
}

if (file.name like "mentat?.???")
{
	original-name: file.name
	interpret-as-internally "iff"

	from "MENT\\NAME"
	{
		loop while (file.remaining-bytes > 0)
		{
			unsigned8 data-size
			unsigned32be desc-offset
			fixed-string(data-size - 7) this-name

			text
			{
				string-data: this-name
			}

			from original-name at desc-offset
			{
				compressed[file.remaining-bytes] "Dune2Text-single"
				{
				compressed[file.remaining-bytes] "Dune2TextLoc"
				{
					string desc
					text
					{
						string-data: desc
					}
				}
				}
			}

			text
			{
				string-data: "\r\n"
			}

			unsigned16 mission-start
		}
	}
}

if (file.name like "*.emc")
{
	interpret-as "iff"
}

if (file.name like ["*.shp", "choam.???", "bttn.???", "mentat.???"])
{
	folder: "Sprites"
	unsigned16 frame-count
	//frame-count = frame-count - 1

	at 0x4
	{
		unsigned16 version-test
	}

	if (version-test == 0)
	{
		unsigned32[frame-count] frame-offsets
		loop(frame-count): i
		{
			frame-offsets[i] = frame-offsets[i] + 2
		}
	}
	else
	{
		unsigned16[frame-count] frame-offsets
	}

	image-layout-width: 460

	outer-loop-count: 1
	if (file.name like "units*.shp")
	{
		outer-loop-count = 6
	}

	loop (outer-loop-count): ol
	{

	image-layout
	{
		loop (frame-count): i
		{
			at frame-offsets[i]:

			unsigned16 flags

			unsigned8 slices
			unsigned16 width
			unsigned8 height

			unsigned16 frame-size
			unsigned16 zero-compressed-size

			if ((flags & 0x4) != 0)
			{
				unsigned8 remap-size
			}
			else
			{
				remap-size: 16
			}

			any-remapped: false

			if ((flags & 0x1) != 0)
			{
				unsigned8[remap-size] remap
				loop (remap-size):r {
					if ((remap[r] >= (9 * 16)) and (remap[r] <= (9 * 16 + 7))) {
						remap[r] = remap[r] + (ol * 16)
						any-remapped = true
					}
				}
			}

			if ((ol == 0) or (any-remapped == true)) 
			{

			if (file.name == "menshpm.shp")
			{
				palette: "bene.pal"
			}
			else
			{
				palette: "dune.pak\\ibm.pal"
			}

			if ((flags & 0x2) != 0)
			{
				//No LCW
				compressed[frame-size - (file.position - frame-offsets[i])] "dune2-sprites"
				{
					image
					{
						format: "I8"
						transparent-index: 0
					}
				}
			}
			else
			{
				decompressed-size: zero-compressed-size
				compressed[frame-size - (file.position - frame-offsets[i])] "Westwood80"
				{
					compressed[zero-compressed-size] "dune2-sprites"
					{
						image
						{
							format: "I8"
							transparent-index: 0
						}
					}
				}
			}
			}
		}
	}
	}
}

previous-animation:
{
	"hfinalc.wsa": "hfinalb.wsa",
	"ofinalb.wsa": "ofinala.wsa",
	"ofinalc.wsa": "ofinalb.wsa",
	"intro7b.wsa": "intro7a.wsa",
	"intro8b.wsa": "intro8a.wsa",
	"intro8c.wsa": "intro8b.wsa"
}

if (file.name like "*.wsa")
{
	folder: "Animations"

	unsigned16 frame-count
	unsigned16 width
	unsigned16 height

	unsigned32 delta //frames/sec = delta / 1024

	unsigned32[frame-count + 1] offsets
	
	current-frame: 0

	if (file.name == "westwood.wsa")
	{
		palette: "westwood.pal"
	}
	else if (file.name like "intro*.wsa")
	{
		palette: "intro.pal"
	}
	else
	{
		palette: "dune.pak\\ibm.pal"
	}

	decompressed-size: width * height

	base: [](decompressed-size)

	loop (frame-count)
	{
		if (offsets[current-frame] != 0) {
			at offsets[current-frame]:

			compressed [offsets[current-frame + 1] - offsets[current-frame]] "Westwood80"
			{
				compressed [file.size] "Westwood40"
				{
					image
					{
						format: "I8"
					}

					at 0:
					unsigned8[decompressed-size] decompressed-data
					base = decompressed-data
				}
			}
		}
		else
		{
			previous-WSA-name: previous-animation[file.name]
			compressed[0] "previous-WSA"
			{
				unsigned8[decompressed-size] decompressed-data-pre
				base = decompressed-data-pre
			}
		}

		current-frame = current-frame + 1
	}
}

function previous-WSA
{
	base: [](decompressed-size)

	from previous-WSA-name
	{
		unsigned16 frame-count-pre
		unsigned16 width-pre
		unsigned16 height-pre

		unsigned32 delta-pre //frames/sec = delta / 1024

		unsigned32[frame-count-pre + 1] offsets-pre

		current-frame-pre: 0
		loop (frame-count-pre)
		{
			if (offsets-pre[current-frame-pre] != 0)
			{
				at offsets-pre[current-frame-pre]:

				compressed [offsets-pre[current-frame-pre + 1] - offsets-pre[current-frame-pre]] "Westwood80"
				{
					compressed [file.size] "Westwood40"
					{
						unsigned8[decompressed-size] decompressed-data-pre
						base = decompressed-data-pre
					}
				}
			}
			else
			{
				previous-WSA-name-2: previous-animation[previous-WSA-name]
				compressed[0] "previous-WSA-2"
				{
					unsigned8[decompressed-size] decompressed-data-pre
					base = decompressed-data-pre
				}
			}

			current-frame-pre = current-frame-pre + 1
		}
	}

	write unsigned8 base
}

function previous-WSA-2
{
	base: [](decompressed-size)

	from previous-WSA-name-2
	{
		unsigned16 frame-count-pre-2
		unsigned16 width-pre-2
		unsigned16 height-pre-2

		unsigned32 delta-pre-2 //frames/sec = delta / 1024

		unsigned32[frame-count-pre-2 + 1] offsets-pre-2

		current-frame-pre-2: 0
		loop (frame-count-pre-2)
		{
			at offsets-pre-2[current-frame-pre-2]:

			compressed [offsets-pre-2[current-frame-pre-2 + 1] - offsets-pre-2[current-frame-pre-2]] "Westwood80"
			{
				compressed [file.size] "Westwood40"
				{
					unsigned8[decompressed-size] decompressed-data-pre-2
					base = decompressed-data-pre-2
				}
			}

			current-frame-pre-2 = current-frame-pre-2 + 1
		}
	}

	write unsigned8 base
}

if (file.name like "*.voc")
{
	interpret-as "sound-VOC"
}

if (file.name like "*.ini")
{
	folder: "Scenarios"

	text
}

if (file.name like "credits.???")
{
	text

	text
	{
		string-data: "\r\n"
	}
}

if (file.name like "desc")
{
	compressed "Dune2Text"
	compressed "Dune2TextLoc"
}

if (file.name like ["*.eng", "*.ger", "*.fre"] and !(file.name like "mentat?.???"))
{
	unsigned16 firstOffset

	//other offsets are here, TODO: correct way

	at firstOffset:

	loop while (file.remaining-bytes > 0)
	{
		thisOffset: file.position
		string compressedString
		stringSize: file.position - thisOffset

		at thisOffset: 
 
		compressed [stringSize] "Dune2Text"
		{
		compressed [file.remaining-bytes] "Dune2TextLoc"
		{
			text

			text
			{
				string-data: "\r\n"
			}
		}
		}
	}
}

if (file.name like "*.dip")
{
	unsigned16 firstOffset

	//other offsets are here, TODO: correct way

	at firstOffset + 1:

	loop while (file.remaining-bytes > 0)
	{
		string this-string
		text
		{
			string-data: this-string
		}
		text
		{
			string-data: "\r\n"
		}
	}
}

function dune2-sprites
{
	loop while (file.remaining-bytes > 0)
	{
		read unsigned8 pixel
		if (pixel == 0)
		{
			read unsigned8 count
			loop (count)
			{
				write unsigned8 0
			}
		}
		else
		{
			if ((flags & 0x1) != 0)
			{
				write unsigned8 remap[pixel]
			}
			else
			{
				write unsigned8 pixel
			}
		}
	}
}