display-name: "Games/Duke Nukem 2"
meta: {"Working": ["Images, tiles, sprites", "Sounds", "Levels"],
"Issues": "Levels are not 100% correct", "Thanks to": ["Frenkel Smeijers", "Dave Bollinger"]}

if (file.name like "*.cmp")
{
	file
	{
		fixed-string(12) name
		unsigned32 offset
		unsigned32 size
	} while  (size > 0)
}

palette: "gamepal.pal"

if (file.name like "*.pal")
{
	compressed [48] "Duke2Pal"
	{
		palette
		{
			size: 16
			format: "R8G8B8"
		}
	}
}

if (file.name == "audiot.mni")
{
	from "audiohed.mni"
	{
		unsigned32[file.size / 4] offsets
	}

	file[offsets.length]: i
	{
		name: "audio " + i
		offset: offsets[i]

		skip-if (offset >= 6065) or (i >= 100)

		if (i < 34)
		{
			interpret-as "sound-PC-APOGEE-AUDIOT"
			name = "SFX\\sound " + i
		} 
		else
		{
			interpret-as "adlib-sound"
			name = "sfx-adlib\\sfx " + (i - 34)
		}		
	}
}

if (file.name like "czone*")
{
	folder: "Foreground Tiles"
	
	data(3600) unknown //tile attributes, I think
	
	image
	{
		format: "I4"
		bit-stride: 8
		width: 8
		height: 8
		tiles-across: 40
		data-size: 32000
	}

	image 
	{
		format: "A1I4"
		bit-stride: 8		
		width: 8
		height: 8
		tiles-across: 40
		data-size: 6400
		alpha-mask: 1
	}
}

if (file.size == 32000)
{
	folder: "Background Tiles"

	image
	{
		format: "I4"
		bit-stride: 8
		width: 8
		height: 8
		tiles-across: 40
		data-size: size
	}
}

if (file.name == "lcr.mni")
{
	folder: "Fullscreen Images"

	palette
	{
		size: 256
		format: "R6G6B6"
	}

	image
	{
		format: "I8"
		width: 320
		height: 200	
	}
}

if (file.size == 32048)
{
	folder: "Fullscreen Images"

	//hack to stop stack overflow.
	at (file.size - 48)
	{
		compressed [48] "Duke2Pal"
		{
			palette
			{
				size: 16
				format: "R8G8B8"
			}
		}
	}

	image
	{
		format: "I4"
		width: 320
		height: 200
		bit-stride: width * height	
	}
}

if (file.name == "actrinfo.mni")
{
	file-number: 1
	file
	{
		unsigned16 local-offset
		offset: local-offset * 2
		name: "sprite " + file-number
		interpret-as "duke2-sprite"
		file-number = file-number + 1
	} while  (file.position < first-offset)
}

//file-number, or filename or something here?
sprite-palettes: {

	278:		"story.mni",
	299:		"story.mni",
	279:		"story2.pal",
	280:		"story3.pal",
	["*"]:		"gamepal.pal"
}

file-format duke2-sprite
{
	unsigned16 frameCount
	unsigned16 unknown

	if (drawing-level-sprite == true)
	{
		frameCount = 1
	}

	image-layout-width: 320
	image-layout
	{
		loop (frameCount)
		{
			signed16 hotspotX
			signed16 hotspotY

			padding-left: 0
			padding-top: 0

			unsigned16 tiles-down
			unsigned16 tiles-across

			if (drawing-level-sprite == true)
			{
				padding-left = 128 + (hotspotX * 8)
				padding-top = 128 + (hotspotY * 8) - ((tiles-down - 1) * 8)
			}

			unsigned32 imageOffset
			unsigned32 unknown
		
			from "actors.mni" at imageOffset
			{
				image
				{
					format: "A1I4"
					width: 8
					height: 8				
					tile-count: tiles-across * tiles-down
					bit-stride: 8
					alpha-mask: 1
					palette: sprite-palettes[file-number] //I don't know.
				}
			}
		}
	}
}

if (file.name like ["l*.mni", "m*.mni", "n*.mni", "o*.mni"] and (file.size > 64999) and (file.size < 70000))
{
	folder: "Levels"

	unsigned16 data-offset     // offset within this file to levelwidth & start of level data
	fixed-string(13) graphicsFile   // name of czone tileset used for this level
	fixed-string(13) backdropFile   // name of backdrop image used for this level
	fixed-string(13) musicFile      // name of music file used for this level
	unsigned8 bFlags
	unsigned8 bAltBackdrop
	unsigned16 unknown
	unsigned16 actorSize

	actor-offset: file.position

	level
	{
		data(actorSize * 2) unknown

		unsigned16 level-width
		level-height: 32750 / level-width

		at file.position + (32750 * 2)
		{
			//unsigned16 foreTilesSCount
			unsigned16 supp-data-length
			compressed[supp-data-length] "Duke2-supplemental-level"
			{
				unsigned8[(level-width * level-height) / 4] foreTilesSS
			}
		}

		grid-x: 8
		grid-y: 8
		width: level-width
		height: level-height

		encrypted[32750 * 2] "DukeLevelBackTiles"
		{
			level-layer
			{
				data-type: "unsigned16"
				order: 0
				layer-image: graphicsFile
				name: "Background"
				ignore-tile: 0
			}
		}

		at data-offset + 2:

		encrypted[32750 * 2] "DukeLevelForeTiles"
		{
			//encrypted DukeLevelForeTilesCorrect[32750 * 2] (
				level-layer
				{
					data-type: "unsigned16"
					order: 1
					layer-image: graphicsFile
					name: "Foreground"
					ignore-tile: 0xDEAD
				}
			//)
		}

		at actor-offset:
		loop (actorSize / 3)
		{
			level-object
			{
				unsigned16 objectType
				unsigned16 xLocation-in-bytes
				unsigned16 yLocation-in-bytes

				offset-x: xLocation-in-bytes * 8 - 128
				offset-y: yLocation-in-bytes * 8 - 128

				sprite: "nukem2.cmp\\actrinfo.mni\\sprite " + (objectType + 1)			
			}
		}
	}
}

function DukeLevelBackTiles
{
	loop while (file.remaining-bytes > 0)
	{
		read unsigned16 tile
		if (tile < 8000)
		{
			write unsigned16 tile / 8
		}
		else
		{
			if ((tile & 0x8000) != 0)
			{
				write unsigned16 tile & 0x3FF
			}
			else
			{
				write unsigned16 0
			}
		}
	}
}

function DukeLevelForeTiles
{
	supp: 0
	loop while (file.remaining-bytes > 0)
	{
		read unsigned16 tile

		if ((tile >= 8000) and (tile < 0x8000))
		{
			write unsigned16 ((tile - 8000) / 40) + 1000
		}
		else 
		{
			if ((tile & 0x8000) != 0)
			{
				supp-data: foreTilesSS[supp / 4]
				supp-index: supp % 4

				if (supp-index == 0)
				{
					supp-data = (supp-data << 5) & 0x60
				}
				else if (supp-index == 1)
				{
					supp-data = (supp-data << 3) & 0x60
				}
				else if (supp-index == 2)
				{
					supp-data = (supp-data << 1) & 0x60
				}
				else if (supp-index == 3)
				{
					supp-data = (supp-data >> 1) & 0x60
				}

				write unsigned16 (supp-data + 1000 + ((tile >> 10) & 0x1F))
			}
			else
			{
				write unsigned16 0xDEAD
			}
		}

		supp = supp + 1
	}
}

function Duke2-supplemental-level
{
	loop while (file.remaining-bytes > 0)
	{
		read unsigned8 command
		if ((command & 0x80) != 0)
		{
			iCount: 0x100 - command
			loop (iCount)
			{
				read unsigned8 val
				write unsigned8 val
			}
		}
		else
		{
			read unsigned8 val
			loop(command)
			{
				write unsigned8 val
			}
		}
	}
}

function Duke2Pal
{
	loop (48)
	{
		read unsigned8 value
		if (value == 64)
		{
			write unsigned8 255
		}
		else
		{
			write unsigned8 ((value & 0x3F) << 2)
		}
	}
}

if (file.name like ["ordertxt.mni", "text.mni", "options.mni", "help.mni"])
{
	text

}

if (file.name like ["sb_*", "intro*"])
{
	interpret-as "sound-VOC"
}

if (file.size == 4000)
{
	b800-text
}

if (file.name like "*.imf")
{
	folder: "Music"
	interpret-as "music-imf-280"
}

if (file.name like "nukem2.f?")
{
	interpret-as "animation-flic"
}