Table of Contents

Mozaïc

Some game distributed with lottery tickets from Loto-Québec

Download: https://archive.org/details/mozaic_202207 (also hacked to bypass ticket validity checks)

See also: https://www.youtube.com/watch?v=YygmFM3qP8w

Install on Wine

This game makes heavy use of Indeo 5 and other DirectShow codecs so make sure to install it. Use a 32-bit prefix, and ideally pretend you're Windows XP and enable windowed mode.

# mount the ISO
# the game won't run without it
sudo mount MOZAIC.iso /mnt/cdrom
 
# create a new 32-bit prefix
# it currently won't work in a 64-bit prefix due to the codecs
# also make sure the CD-ROM is detected as such
export WINEARCH=win32
export WINEPREFIX=~/.wine32
winecfg
 
# install the codecs
winetricks -q allcodecs
 
# install and run the game (also make sure $WINEPREFIX is set)
wine /mnt/cdrom/Mozaic.exe

The installation may fail because you have an ï in the install path, you may remove it and put a normal i instead.

PAK file format

Data is in little-endian.

NomTypeOffsetSizeNotes
magicstring04 bytes“PACK”
sizeu3244 bytesNumber of entries
??? 832 bytesSeems unused, can be used as a comment field
filelistFile40size * (12 + name)

File

NomTypeOffsetSizeNotes
filesizeu3204 bytes
offsetu3244 bytesByte offset from the beginning of the file
???u3284 bytesUnknown, the game crashes right away if it's not what it expected
nameNull-terminated string12 File path and name

ImHex pattern

import std.string;
 
struct File {
    u32 filesize;
    u32 offset;
    u32 unknown;
    std::string::NullString name;
    char data[filesize] @ offset;
};
 
char magic[4] @ 0;
u32 size @ 4;
char unknown[32] @ 8;
File filelist[size] @ 40;

Tools

Node.js pak extractor

extractpak.js
const fs = require('node:fs');
const path = require('node:path');
 
if(process.argv.length < 3)
{
    console.log("error: no input file");
    process.exit(1);
}
 
var f = fs.readFileSync(process.argv[2]);
 
var magic = f.toString('hex', 0, 4);
if(magic != "5041434b")
{
    console.log("error: invalid file");
    process.exit(1);
}
 
var size = f.readUInt32LE(4);
var offset = 40;
 
for(var i = 0; i < size; i++)
{
    var filesize = f.readUint32LE(offset); offset+=4;
    var fileoffset = f.readUint32LE(offset); offset+=4;
    var mystery = f.readUint32LE(offset); offset+=4;
    var next = f.indexOf(0, offset, 'ascii');
    var name = f.toString('ascii', offset, next).replaceAll("\\", "/");
    offset = next+1;
    console.log("%s; %s", name, mystery);
 
    fs.mkdirSync(path.dirname(name), { recursive: true });
    var data = fs.createWriteStream(name, 'binary');
    data.end(f.slice(fileoffset, fileoffset+filesize));
}

mpar - extractor and archiver