display-name: "Games/Heroes of Might & Magic"
meta: {"Working": ["Packed file extraction", "Images", "Sprites", "Sounds"]}

palette: 
[0x00, 0xFF, 0xFF, 0xFF, 0x96, 0xFF, 0xFF, 0x64, 0xFF, 0xFF, 0x32, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0xB4, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xC9, 0xC9, 0xFF, 0xB9, 0xB9, 0xFF, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0xFC, 0xE8, 0xE8, 0xE8, 0xE0, 0xE0, 0xE0, 0xD0, 0xD0, 0xD0, 0xC8, 0xC8, 0xC8, 0xB8, 0xB8, 0xB8, 0xB0, 0xB0, 0xB0, 0x9C, 0x9C, 0x9C, 0x94, 0x94, 0x94, 0x84, 0x84, 0x84, 0x7C, 0x7C, 0x7C, 0x6C, 0x6C, 0x6C, 0x64, 0x64, 0x64, 0x54, 0x54, 0x54, 0x4C, 0x4C, 0x4C, 0x3C, 0x3C, 0x3C, 0x34, 0x34, 0x34, 0x20, 0x20, 0x20, 0x18, 0x18, 0x18, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0xFC, 0xE8, 0xDC, 0xF4, 0xDC, 0xD0, 0xEC, 0xCC, 0xB8, 0xE8, 0xC4, 0xAC, 0xDC, 0xB0, 0x94, 0xD8, 0xA8, 0x8C, 0xD0, 0x98, 0x78, 0xCC, 0x90, 0x6C, 0xC0, 0x84, 0x5C, 0xBC, 0x7C, 0x54, 0xB4, 0x70, 0x44, 0xAC, 0x6C, 0x40, 0x9C, 0x60, 0x34, 0x94, 0x5C, 0x30, 0x84, 0x50, 0x28, 0x7C, 0x4C, 0x24, 0x70, 0x44, 0x20, 0x68, 0x40, 0x1C, 0x58, 0x34, 0x14, 0x50, 0x30, 0x14, 0x40, 0x28, 0x0C, 0x3C, 0x24, 0x0C, 0xD8, 0xEC, 0xFC, 0xC4, 0xE4, 0xFC, 0xBC, 0xDC, 0xFC, 0xB4, 0xD8, 0xFC, 0xA8, 0xD0, 0xFC, 0xA0, 0xC4, 0xFC, 0x98, 0xBC, 0xFC, 0x8C, 0xB0, 0xFC, 0x84, 0xA4, 0xFC, 0x7C, 0x98, 0xFC, 0x70, 0x8C, 0xFC, 0x68, 0x7C, 0xFC, 0x60, 0x70, 0xFC, 0x54, 0x60, 0xF0, 0x48, 0x54, 0xE4, 0x3C, 0x48, 0xD4, 0x2C, 0x38, 0xC4, 0x24, 0x2C, 0xB4, 0x18, 0x20, 0xA8, 0x10, 0x14, 0x98, 0x08, 0x0C, 0x8C, 0x04, 0x08, 0x80, 0x00, 0x00, 0x70, 0x00, 0x00, 0x64, 0xC4, 0xFC, 0xB0, 0xB4, 0xF0, 0xA0, 0xA8, 0xE8, 0x94, 0x9C, 0xE0, 0x88, 0x90, 0xD8, 0x7C, 0x84, 0xD0, 0x70, 0x78, 0xC4, 0x64, 0x6C, 0xBC, 0x58, 0x60, 0xB4, 0x50, 0x58, 0xAC, 0x48, 0x4C, 0xA0, 0x3C, 0x44, 0x98, 0x34, 0x38, 0x90, 0x2C, 0x30, 0x88, 0x24, 0x28, 0x80, 0x20, 0x20, 0x74, 0x18, 0x18, 0x6C, 0x14, 0x14, 0x64, 0x0C, 0x0C, 0x5C, 0x08, 0x08, 0x50, 0x04, 0x04, 0x48, 0x04, 0x04, 0x40, 0x00, 0x00, 0x38, 0x00, 0x00, 0x30, 0x00, 0xFC, 0xFC, 0xE4, 0xFC, 0xFC, 0xC8, 0xFC, 0xFC, 0xB0, 0xF8, 0xF8, 0x94, 0xF8, 0xF8, 0x7C, 0xF8, 0xF8, 0x64, 0xF8, 0xF0, 0x48, 0xF4, 0xE8, 0x34, 0xF0, 0xE0, 0x24, 0xE8, 0xD4, 0x1C, 0xE0, 0xC8, 0x14, 0xD8, 0xB8, 0x10, 0xD0, 0xAC, 0x08, 0xC8, 0x9C, 0x04, 0xC0, 0x90, 0x00, 0xB8, 0x84, 0x00, 0xB0, 0x78, 0x00, 0xA4, 0x6C, 0x00, 0x98, 0x5C, 0x00, 0x88, 0x50, 0x00, 0x7C, 0x44, 0x00, 0x70, 0x38, 0x00, 0x64, 0x2C, 0x00, 0x58, 0x24, 0x00, 0xF0, 0xD8, 0xFC, 0xE8, 0xC8, 0xF8, 0xE0, 0xB8, 0xF8, 0xD8, 0xAC, 0xF4, 0xCC, 0x9C, 0xF4, 0xC4, 0x8C, 0xF4, 0xB8, 0x80, 0xF0, 0xB0, 0x70, 0xF0, 0xA4, 0x64, 0xF0, 0x98, 0x58, 0xE0, 0x8C, 0x4C, 0xD4, 0x80, 0x40, 0xC8, 0x78, 0x38, 0xBC, 0x6C, 0x2C, 0xB0, 0x64, 0x24, 0xA0, 0x58, 0x1C, 0x94, 0x50, 0x18, 0x88, 0x48, 0x10, 0x7C, 0x40, 0x0C, 0x70, 0x34, 0x08, 0x60, 0x2C, 0x04, 0x54, 0x24, 0x00, 0x48, 0x20, 0x00, 0x3C, 0x18, 0x00, 0x30, 0xBC, 0xF8, 0xFC, 0xB0, 0xEC, 0xF4, 0xA8, 0xE4, 0xE8, 0x9C, 0xDC, 0xE0, 0x94, 0xD4, 0xD8, 0x88, 0xC8, 0xD0, 0x80, 0xC0, 0xC8, 0x78, 0xB8, 0xC0, 0x70, 0xB0, 0xB8, 0x68, 0xA8, 0xB0, 0x60, 0xA0, 0xA8, 0x58, 0x94, 0xA0, 0x50, 0x8C, 0x98, 0x48, 0x84, 0x8C, 0x44, 0x7C, 0x84, 0x3C, 0x74, 0x7C, 0x38, 0x6C, 0x74, 0x30, 0x64, 0x6C, 0x2C, 0x5C, 0x64, 0x28, 0x54, 0x5C, 0x20, 0x4C, 0x54, 0x1C, 0x44, 0x4C, 0x18, 0x3C, 0x44, 0x14, 0x34, 0x3C, 0xFC, 0xE4, 0xE4, 0xFC, 0xD0, 0xD0, 0xFC, 0xC0, 0xC0, 0xFC, 0xB0, 0xB0, 0xFC, 0xA0, 0xA0, 0xFC, 0x90, 0x90, 0xFC, 0x80, 0x80, 0xFC, 0x70, 0x70, 0xFC, 0x60, 0x60, 0xF0, 0x54, 0x54, 0xE4, 0x48, 0x48, 0xD8, 0x40, 0x40, 0xCC, 0x34, 0x34, 0xC0, 0x2C, 0x2C, 0xB4, 0x24, 0x24, 0xA8, 0x20, 0x20, 0x9C, 0x18, 0x18, 0x90, 0x10, 0x10, 0x84, 0x0C, 0x0C, 0x78, 0x08, 0x08, 0x6C, 0x04, 0x04, 0x60, 0x00, 0x00, 0x54, 0x00, 0x00, 0x48, 0x00, 0x00, 0xFC, 0xE4, 0xA0, 0xFC, 0xD8, 0x90, 0xFC, 0xCC, 0x88, 0xFC, 0xC0, 0x7C, 0xFC, 0xB4, 0x70, 0xFC, 0xA4, 0x64, 0xFC, 0x98, 0x54, 0xF8, 0x8C, 0x40, 0xEC, 0x80, 0x28, 0xDC, 0x78, 0x20, 0xCC, 0x6C, 0x18, 0xB4, 0x60, 0x0C, 0x9C, 0x50, 0x00, 0x84, 0x44, 0x00, 0x6C, 0x38, 0x00, 0x64, 0x30, 0x00, 0xFC, 0x58, 0x0C, 0xDC, 0x34, 0x04, 0xC0, 0x14, 0x00, 0xA4, 0x00, 0x00, 0xFC, 0xFC, 0x00, 0xFC, 0xCC, 0x00, 0xC0, 0x8C, 0x00, 0x8C, 0x48, 0x00, 0xBC, 0xE8, 0x00, 0xAC, 0xD8, 0x00, 0xA0, 0xC8, 0x00, 0x94, 0xB8, 0x00, 0x84, 0xA8, 0x04, 0x78, 0x98, 0x04, 0x6C, 0x88, 0x04, 0x60, 0x7C, 0x04, 0x60, 0x68, 0xFC, 0x40, 0x58, 0xF0, 0x28, 0x50, 0xE4, 0x10, 0x48, 0xD8, 0x00, 0x48, 0xCC, 0xA8, 0xD0, 0xFC, 0x68, 0xB8, 0xFC, 0x84, 0xE0, 0xFC, 0x00, 0x98, 0xFC, 0x00, 0x50, 0xE4, 0x00, 0x00, 0xA4, 0x7C, 0x7C, 0xA8, 0x70, 0x70, 0x9C, 0x60, 0x60, 0x90, 0x58, 0x58, 0x88, 0xFC, 0xFC, 0xFC, 0xA9, 0xA9, 0xFF, 0x99, 0x99, 0xFF, 0x89, 0x89, 0xFF, 0x79, 0x79, 0xFF, 0x69, 0x69, 0xFF, 0x59, 0x59, 0xFF, 0x49, 0x49, 0xFF, 0x39, 0x39, 0xFF, 0x29, 0x29, 0xFF, 0x19, 0x19, 0xFF
]

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

	first-name-location: file.size - (15 * file-count)

	file-number: 0
	file [file-count]
	{
		data(2) unknown
		unsigned32 offset
		unsigned32 size
		unsigned32 size-again

		at first-name-location + (file-number * 15)
		{
			fixed-string(15) name
		}

		file-number = file-number + 1
	}
}

if (file.name like "*.82m")
{
	sound
	{
		channels: 1
		bits-per-sample: 8
		samples-per-second: 22050
		sound-signed: true
	}
}

if (file.name like ["*.bmp", "*.bkg"])
{
	data(2) unknown
	unsigned16 width
	unsigned16 height

	image
	{
		format: "I8"
		//palette: "kb.pal"
	}
}

if (file.name like ["*.std", "*.wlk", "*.icn", "*.atk", "*.wip", "*.xtl", "*.obj"])
{
	folder: "Sprites"

	unsigned16 sprite-count
	unsigned32 file-size

	loop (sprite-count): i
	//file[sprite-count]
	{
		signed16 x-offset
		signed16 y-offset

		unsigned16 width
		unsigned16 height

		unsigned32 data-offset
		at data-offset + 6
		{
			compression: "homm-sprite-compression"

			if ((file.name like "*.std" and i == 0) or (file.name like "*.std" and i > 8) or
			    (file.name like "*.wlk" and i > 5) or (file.name like "*.atk" and i > 8) or
			    (file.name like ["*font.icn", "shadow*.icn"]))
			{
				compression = "homm-sprite-compression-shadow"
			}
			compressed[file.size] compression
			{
				image
				{
					format: "I8"
					transparent-index: 255
				}
			}
		}
		//compressed compression

		//offset: data-offset
		//name: "sprite " + width + "x" + height
	}
}

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

	unsigned16 tile-count
	unsigned16 width
	unsigned16 height

	image
	{
		format: "I8"
		tiles-across: 10
	}
}

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

function homm-sprite-compression
{
	finished: false
	current-x: 0
	bytes-written: 0

	loop while ((file.remaining-bytes > 0) and (finished == false))
	{
		read unsigned8 token

		if (token == 0x80)
		{
			finished = true
		}
		else if (token == 0x00)
		{
			loop (width - current-x)
			{
				write unsigned8 255
			}
			bytes-written = bytes-written + (width - current-x)
			current-x = 0
		}
		else if (token <= 0x7F)
		{
			loop (token): i
			{
				read unsigned8 pixel
				write unsigned8 pixel
			}
			bytes-written = bytes-written + token
			current-x = current-x + token
		}
		else
		{
			loop (token - 0x80): i
			{
				write unsigned8 255
			}
			bytes-written = bytes-written + (token - 0x80)
			current-x = current-x + (token - 0x80)
		}
	}

	loop ((width * height) - bytes-written)
	{
		write unsigned8 255
	}
}

function homm-sprite-compression-shadow
{
	finished: false
	current-x: 0
	bytes-written: 0

	loop while ((file.remaining-bytes > 0) and (finished == false))
	{
		read unsigned8 token

		if (token == 0x80)
		{
			finished = true
		}
		else if (token == 0x00)
		{
			loop (width - current-x): i
			{
				write unsigned8 255
			}
			bytes-written = bytes-written + (width - current-x)
			current-x = 0
		}
		else if (token <= 0x7F)
		{
			loop (token): i
			{
				write unsigned8 10
			}
			bytes-written = bytes-written + token
			current-x = current-x + token
		}
		else
		{
			//start-offset: current-y * width + current-x
			loop (token - 0x80): i
			{
				write unsigned8 255
			}
			bytes-written = bytes-written + (token - 0x80)
			current-x = current-x + (token - 0x80)
		}
	}

	loop ((width * height) - bytes-written)
	{
		write unsigned8 255
	}
}