We just moved to a different server. Please be patient until all files and pages are restored and the MediaWiki software has been updated. Thank you

Toonstruck

From REWiki
Jump to: navigation, search

Toonstruck is a classic point'n'click adventure.

It seems to reuse large parts of the Kyrandia engines, as already implemented in SCUMMVM. But there seem to be some differences, which I want to record here...


File Formats

CPS-File, Mode SPCN

Fileheader:

4 Bytes Magic "SPCN"
4 Bytes Filessize - 4
2 Bytes Compression Mode (0x0004 -> Format80)
4 Bytes Filesize uncompressed
2 Bytes Size of palette -> N
N Bytes palette data
1 Byte unknown
Rest is compressed data

The palette data is only 5 bits wide per color and has to be streched to 8 bits in order to produce the correct results:

for (int i = 0; i < palette.Length; i++)
    palette[i] = (byte)Math.Round((((float)(palette[i] & 0x3F)) * 255 / 63));

The image data is compressed with a specialized variant of the Format80 algorithm (this one also supports large images beyond 64k). The following snippet of code demonstrates this method:

protected byte[] UncompressFormat80 (byte[] src, long length) {
    byte[] dst = new byte[length];
    long csrc = 0;
    long cdst = 0;
    while (csrc < src.LongLength) {
        byte code = src[csrc++];
        if ((code & 0xFF) == 0xFF) {
            long len = ((src[csrc + 1] << 8) | src[csrc]);
            long pos = ((src[csrc + 3] << 8) | src[csrc + 2]);
            csrc += 4;
            pos = cdst - pos;
            while (len-- > 0)
                dst[cdst++] = dst[pos++];
        } else if ((code & 0xFE) == 0xFE) {
            long len = ((src[csrc + 1] << 8) | src[csrc]);
            byte val = src[csrc + 2];
            csrc += 3;
            while (len-- > 0)
                dst[cdst++] = val;
        } else if ((code & 0xC0) == 0xC0) {
            long len = (code & 0x3F) + 3;
            long pos = ((src[csrc + 1] << 8) | src[csrc]);
            csrc += 2;
            pos = cdst - pos;
            while (len-- > 0)
                dst[cdst++] = dst[pos++];
        } else if ((code & 0x80) == 0x80) {
            long len = (code & 0x3F);
            if (len == 0)
                break;
            while (len-- > 0)
                dst[cdst++] = src[csrc++];
        } else {
            long len = ((code & 0x70) >> 4) + 3;
            long pos = ((code & 0x0F) << 8) | src[csrc];
            csrc++;
            if (pos == 1) {
                pos = cdst - 1;
                while (len-- > 0)
                    dst[cdst++] = dst[pos];
            } else {
                pos = cdst - pos;
                while (len-- > 0)
                    dst[cdst++] = dst[pos++];
            }
        }
    }
    return dst;
}


CPS-File, Mode LZSS

Fileheader:

4 Bytes Magic "LZSS"
4 Bytes Filesize uncompressed
Rest seems compressed data
Personal tools