Starting a thread to capture all information currently known about file formats for the Lemmings Revolution game, in the same vein as what we documented (http://www6.camanis.net.ipv4.sixxs.org/lemmings/tools.php) for a few other Lemmings games in the series. Interest in Revolution may be low, but then again so are games like L3, but we currently know more about that game's file formats than Revolution. That should change at some point in the future. (http://www.lemmingsforums.com/Smileys/lemmings/wink.gif)
Information given on this thread are not guaranteed 100% accurate, but should be pretty good, and will be updated with corrections if any are reported.
We start off with the BOX file format, which is just a way to package a set of files in a directory tree into a single file, without any compression. Yeah, not sure why they did that, but they did. (http://www.lemmingsforums.com/Smileys/lemmings/undecided.gif) Attached text file is same info as below, just for convenience.
Code: [Select] (//http://javascript:void(0);)Lemmings Revolution (PC) BOX format
documented by ccexplore
For some reason, Lemmings Revolution packs most of its data files into a single
large BOX file, instead of simply letting them live as individual files in
individual directories. There isn't even any compression going on inside BOX
files. Go figure.
The format is really simple though.
Sidenote: the "Dragon unPACKer" program (as of version 5.6.2 [build 268]) has
major bugs in its extraction code for BOX files. It produces the correct
directory listing, but does not correctly associate each file entry with the
correct set of bytes in the BOX file, at least when I tried it on the files on
my game CD.
----------------
BOX format
----------------
[NOTE: per Intel convention, all integers are little-endian, meaning that
a 4-byte hexadecimal integer 0xdeadbeef is stored in bytes as
0xef, 0xbe, 0xad, 0xde.]
Header Info (14 bytes)
0x0000-0x0005: "LEMBOX"
0x0006-0x0009: 4-byte integer, number of files N
0x000A-0x000D: 4-byte integer, offset from first byte after the header to File
Locations table
File Directory (variable size)
0x000E: N filename entries (variable size), each entry as follows:
0x00-0x03: 4-byte integer, length L of text string following
0x04: L bytes in 8-bit ASCII, name of file (including path), no
0-termination
File Locations table (variable size)
0x00-0x03: 4-byte integer, number of table entries N' (should be equal
to N)
0x04: N' table entries
each entry is a 4-byte integer, offset from start of BOX file to
first byte of contents of the file
File Lengths table (variable size)
0x00-0x03: 4-byte integer, number of table entries N" (should be equal
to N)
0x04: N" table entries
each entry is a 4-byte integer, length of file (in bytes)
remainder of BOX file are the bytes for the individual files contained within
----------------
Example
----------------
Suppose we want to capture the following files in the directory tree below into
a BOX file:
AFILE.EXT (file contents: 0x42)
DIR1\FILE1.ZZZ (file contents: 0xde 0xad 0xbe 0xef 0xde 0xad 0xbe 0xef)
DIR1\2ND.MMM (file contents: 0xab 0xcd 0xef)
D2\SD3\Y.CD (file contents: 0xac 0xdc)
Below is one possible encoding. "One possible" because the ordering of files
can be anything--files under the same subdirectory do not have to come up
in consecutive table entries in the BOX file, as demonstrated in the example
encoding below.
Similarly, the contents of each file may not necessarily come in the same order
as the file ordering in the tables, because the File Locations table provides
direct offsets into the BOX file for each file's contents, theoretically allow
you to place the contents of each file in any order consistent with the offsets
and lengths given in the tables. That said, in the BOX files from the game, I
think the file contents do come in the same order as the files do in the tables.
Resulting BOX file, viewed in hex editor:
4C 45 4D 42 4F 58 04 00 00 00 3E 00 00 00 0E 00
00 00 44 49 52 31 5C 46 49 4C 45 31 2E 5A 5A 5A
09 00 00 00 41 46 49 4C 45 2E 45 58 54 0C 00 00
00 44 49 52 31 5C 32 4E 44 2E 4D 4D 4D 0B 00 00
00 44 32 5C 53 44 33 5C 59 2E 43 44 04 00 00 00
74 00 00 00 7C 00 00 00 7D 00 00 00 80 00 00 00
04 00 00 00 08 00 00 00 01 00 00 00 03 00 00 00
02 00 00 00 DE AD BE EF DE AD BE EF 42 AB CD EF
AC DC
Below is the breakdown:
4C 45 4D 42 4F 58: "LEMBOX"
04 00 00 00: 0x00000004=4 files
3E 00 00 00: offset to File Locations table=0xE (header length) + 0x0000003E
=0x0000004C from start of BOX file (counting from zero).
File Directory, which we know has 4 entries for 4 files
0E 00 00 00 44 49 52 31 5C 46 49 4C 45 31 2E 5A 5A 5A:
"DIR1\FILE1.ZZZ", string length 0x0000000E=14 bytes
09 00 00 00 41 46 49 4C 45 2E 45 58 54:
"AFILE.EXT", string length 0x00000009=9 bytes
0C 00 00 00 44 49 52 31 5C 32 4E 44 2E 4D 4D 4D:
"DIR1\2ND.MMM", string length 0x0000000C=12 bytes
0B 00 00 00 44 32 5C 53 44 33 5C 59 2E 43 44:
"D2\SD3\Y.CD", string length 0x0000000B=11 bytes
File Locations table
04 00 00 00: 0x00000004=4 files, as expected
74 00 00 00: location in BOX file for the 1st file's contents, which according
to File Directory is the file DIR1\FILE1.ZZZ
so contents of DIR\FILE1.ZZZ starts at 0x00000074 from
start of BOX file
7C 00 00 00: AFILE.EXT's contents starts at 0x0000007C from start of BOX file
7D 00 00 00: DIR1\2ND.MMM's contents @ 0x0000007D from start of BOX file
80 00 00 00: D2\SD3\Y.CD's contents @ 0x00000080 from start of BOX file
File Lengths table
04 00 00 00: 0x00000004=4 files, as expected
08 00 00 00: DIR1\FILE1.ZZZ's length is 0x00000008=8 bytes
01 00 00 00: AFILE.EXT's length is 0x00000001=1 byte
03 00 00 00: DIR1\2ND.MMM's length is 0x00000003=3 bytes
02 00 00 00: D2\SD3\Y.CD's length is 0x00000002=2 bytes
DE AD BE EF DE AD BE EF: these 8 bytes are DIR1\FILE1.ZZZ's file contents
located at offset 0x00000074 as specified earlier
42: this 1 byte is AFILE.EXT's file contents
located at offset 0x0000007C as specified earlier
AB CD EF: these 3 bytes are DIR1\2ND.MMM's file contents
located at offset 0x0000007D as specified earlier
AC DC: these 2 bytes are D2\SD3\Y.CD's file contents
located at offset 0x00000080 as specified earlier
There are apparently some programs already available that can extract from BOX files, but they may be buggy and not extract every file inside the BOX correctly, or mix up contents of one file with another. My documentation here should be more accurate than such programs, sadly. (http://www.lemmingsforums.com/Smileys/lemmings/undecided.gif)
Mod Edit: Restored attachments.
While GuyPerfect is sorting out the bmp compression in a portable manner, here are some tools one can use on Windows at the moment to try to extract and decompress files from the BOX. They are not user friendly at all since both my time and general demand is pretty low. If you never used this thing called a "command prompt", then wait for someone else to extract some files for you instead.

example usage:
unbox c:\foo\bar\lemmings.box c:\output
Unpack everytyhing in c:\foo\bar\lemmings.box into c:\output folder, preserving the folder structure stored in lemmings.box. No file decompression is done.
lrdecomp c:\output\textures\main_logo.bmp c:\output\textures\main_logo-D.bmp
Decompresses c:\output\textures\main_logo.bmp and save decompressed data to c:\output\textures\main_logo-D.bmp.
Invalid/incorrect parameters just result in nothing happening. Only works on compressed files, anything else will just crash program. AFAIK any files with .BMP extension in BOX are compressed (and decompresses to the MS BMP bitmap file format), everything else aren't.
While GuyPerfect is sorting out the bmp compression in a portable manner
Done! Also, where is your source code, mister? D-:<
__________
I'll have a write-up of the bitmap compression algorithm in this thread at some point tomorrow, but for now here's a fully-functional decompressor.
A compiled EXE of this is attached to this post, and the format is the same as ccexplore's utility:
lrz <infile> <outfile>
Where
infile is a compressed .bmp from the Lemmings Revolution BOX file and
outfile is the desired name of the uncompressed file.
The source code is as follows, subject to improvements later on:
lrz.h
#ifndef __LRZ_LEMMINGS__
#define __LRZ_LEMMINGS__
// API error constants
#define LRZ_SUCCESS 0
#define LRZ_BADPARAMS -1
#define LRZ_BADDATA -2
// Function prototypes
int lrzDecode(unsigned char *, int, unsigned char *, int);
int lrzGetSize(unsigned char *, int);
#endif // __LRZ_LEMMINGS__
lrz.c
#include <stdio.h>
#include <stdlib.h>
#include "lrz.h"
// Node type constants
#define NODE_UNKNOWN 0
#define NODE_BRANCHING 1
#define NODE_VALUE 2
// Decoder state constants
#define STATE_RAW 0
#define STATE_COPY 1
// Linked list data structure for binary tree nodes
typedef struct LRZ_NODE LRZ_NODE;
struct LRZ_NODE {
int type, value, done;
LRZ_NODE *parent, *child[2];
};
// Atomic data processing unit for file chunks
typedef struct {
// Input/output properties
unsigned char *src, *dst;
int srclen, dstlen, srcoff, dstoff;
// Binary trees
LRZ_NODE *rawtree, *lentree, *disttree;
// Bit processing properties
int bitsleft, reg, subbits, state;
} LRZ_CHUNK;
////////////////////////////////////////////////////////////////////////////////
// Decoder Functions //
////////////////////////////////////////////////////////////////////////////////
// This macro is used in lrzdFreeTree() to handle deletion of individual nodes
#define DeleteNode() { \
if (node == node->parent->child[0]) node->parent->child[0] = NULL; \
if (node == node->parent->child[1]) node->parent->child[1] = NULL; \
temp = node->parent; free(node); node = temp; continue; \
}
// Deletes memory allocated for a binary tree object
static void lrzdFreeTree(LRZ_NODE *root) {
LRZ_NODE *temp, *node = root;
// Exit now if the tree wasn't initialized
if (root == NULL) return;
// Traverse the tree until all child nodes are deleted
while (1) {
// Terminal nodes are deleted outright
if (node->type != NODE_BRANCHING) DeleteNode();
// Delete a branching node if both its children are gone
if (node->child[0] == NULL && node->child[1] == NULL) {
if (node == root) break; // Root has no parent, so exit here
DeleteNode();
}
// Select the next non-deleted child node
if (node->child[0] != NULL)
node = node->child[0];
else node = node->child[1];
}
// Delete root and return
free(root);
return;
}
// Deletes memory allocated for a chunk object
static void lrzdFreeChunk(LRZ_CHUNK *chunk) {
lrzdFreeTree(chunk->rawtree);
lrzdFreeTree(chunk->lentree);
lrzdFreeTree(chunk->disttree);
return;
}
// Decodes a binary tree from a chunk header
static int lrzdGetTree(LRZ_CHUNK *chunk, LRZ_NODE **out) {
int nibnum, x, nodenum = 3, donenum = 0, level = 1;
unsigned char nibs[17], curbyte;
LRZ_NODE *root, *node;
// Error checking
if (chunk->srcoff >= chunk->srclen) return 1;
// Get the number of nibbles for this tree
curbyte = chunk->src[chunk->srcoff++];
nibnum = (curbyte & 0x0F) + 2;
if (nibnum == 2) return 0; // No nibbles for this tree
if (chunk->srcoff + (nibnum >> 1) >= chunk->srclen)
return 1; // Not enough bytes for this tree's definition
// Process all of the nibbles for this tree
for (x = 0; x < nibnum; x++) {
if (x & 1) curbyte = chunk->src[chunk->srcoff++];
else curbyte >>= 4;
nibs- = curbyte & 0x0F;
}
// Initialize the tree
root = *out = calloc(sizeof(LRZ_NODE), 1);
node = root->child[0] = calloc(sizeof(LRZ_NODE), 1);
root->child[1] = calloc(sizeof(LRZ_NODE), 1);
root->type = NODE_BRANCHING;
root->child[0]->parent = root;
root->child[1]->parent = root;
// Construct the remainder of the tree
while (!root->done) {
// Check if this node needs further processing
if (node->done) {
node = node->parent;
level--;
continue;
}
// If a branching node, step down into the tree a level
if (node->type == NODE_BRANCHING) {
// Check if both child nodes are finished
if (node->child[0]->done && node->child[1]->done) {
node->done = 1;
donenum++;
continue;
}
// Step into the next unfinished child node
if (node->child[0]->type == NODE_UNKNOWN)
node = node->child[0];
else node = node->child[1];
level++;
continue;
}
// If all the nibbles are less than the current level, return error
for (x = 0; x < nibnum; x++)
if (nibs - >= level) break;
if (x == nibnum) return 1;
// Try to find a value for this node
for (x = 0; x < nibnum; x++)
if (nibs - == level) break;
// A value was found for this node
if (x < nibnum) {
nibs - = 0;
node->type = NODE_VALUE;
node->value = x;
node->done = 1;
donenum++;
continue;
}
// No value could be found for this node; make it a branching node
node->type = NODE_BRANCHING;
node->child[0] = calloc(sizeof(LRZ_NODE), 1);
node->child[1] = calloc(sizeof(LRZ_NODE), 1);
node->child[0]->parent = node;
node->child[1]->parent = node;
nodenum += 2;
}
// If not all the nodes created were finalized, return error
if (donenum != nodenum) return 1;
// Return success
return 0;
}
// Returns the value of the specified number of bits from the input stream
static int lrzdGetBits(LRZ_CHUNK *chunk, int count) {
int ret;
// Error checking
if (chunk->bitsleft < count || count > 15) return -1;
chunk->bitsleft -= count;
// Load the bits from the stream into the register
while (count > chunk->subbits) {
chunk->reg <<= chunk->subbits;
if (chunk->srcoff < chunk->srclen)
chunk->reg |= (int) chunk->src[chunk->srcoff++];
count -= chunk->subbits;
chunk->subbits = 8;
}
chunk->reg <<= count;
chunk->subbits -= count;
// Process the bits from the register
ret = (chunk->reg & 0x00FFFF00) >> 8;
chunk->reg &= 0x000000FF;
return ret;
}
// Loads a number from input data encoded as a normal value
static int lrzdParse(LRZ_CHUNK *chunk) {
int x = 1, count = 0;
// Read (and count) bits until a 0 is encountered
while (x) {
x = lrzdGetBits(chunk, 1);
if (x < 0) return -1; // Error reading bit
count += x;
}
// Read that many additional bits from the input
x = lrzdGetBits(chunk, count);
if (x < 0) return -1; // Error reading bits
// Return the composited value
return (1 << count) - 1 + x;
}
// Loads a number from input data by traversing a binary tree
static int lrzdTraverse(LRZ_CHUNK *chunk, LRZ_NODE *node) {
int x, ret;
// Traverse the tree to a terminal node
while (node->type == NODE_BRANCHING) {
x = lrzdGetBits(chunk, 1);
if (x < 0) return -1; // Error reading bit
node = node->child - ;
}
// Return the number as a literal
x = node->value;
if (x < 2) return x;
// Read additional bits from the data
ret = 1 << --x;
x = lrzdGetBits(chunk, x);
if (x < 0) return -1; // Error reading bits
return ret | x;
}
// This macro is used by lrzdChunk() to load a number from the input stream
#define GetNumber(var, tree) { \
if (tree != NULL) \
var = lrzdTraverse(chunk, tree); \
else var = lrzdParse(chunk); \
}
// Processes a file chunk
static int lrzdChunk(LRZ_CHUNK *chunk) {
int x, dist, len;
// Initialize input/output variables
chunk->srcoff = 0;
chunk->dstoff = 0;
// Process binary trees
chunk->rawtree = chunk->lentree = chunk->disttree = NULL;
if (lrzdGetTree(chunk, &chunk->rawtree)) return 1;
if (lrzdGetTree(chunk, &chunk->lentree)) return 1;
if (lrzdGetTree(chunk, &chunk->disttree)) return 1;
// Initialize bit processing variables
chunk->bitsleft = (chunk->srclen - chunk->srcoff) * 8;
if (!chunk->bitsleft) return 1; // Insufficient data
chunk->reg = (int) chunk->src[chunk->srcoff++];
chunk->subbits = 8;
// Process input data until all output data is written
chunk->state = STATE_RAW;
while (chunk->dstoff < chunk->dstlen) {
// Read raw bytes from the input
if (chunk->state == STATE_RAW) {
// Read the number of bytes to copy
GetNumber(x, chunk->rawtree);
if (x < 0 || chunk->dstoff + x > chunk->dstlen)
return LRZ_BADDATA;
// Copy that many bytes
for (len = x; len > 0; len--) {
x = lrzdGetBits(chunk, 8);
if (x < 0) return LRZ_BADDATA;
chunk->dst[chunk->dstoff++] =
(unsigned char) x;
}
}
// Copy data with a distance/length pair
else {
// Read the length and distance values
GetNumber(len, chunk->lentree);
GetNumber(dist, chunk->disttree);
if (len < 0 || dist < 0) return LRZ_BADDATA;
len += 2; dist++; // Implicit processing
if (chunk->dstoff + len > chunk->dstlen ||
chunk->dstoff - dist < 0)
return LRZ_BADDATA;
// Copy the bytes from earlier in the output
for (x = chunk->dstoff - dist; len > 0; len--)
chunk->dst[chunk->dstoff++] = chunk->dst[x++];
}
// Alternate processing states
chunk->state = 1 - chunk->state;
}
// Return success
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// API Functions //
////////////////////////////////////////////////////////////////////////////////
// Decompresses a compressed buffer
int lrzDecode(unsigned char *src, int srclen, unsigned char *dst, int dstlen) {
int chunks, packed, unpacked, srcoff = 1, dstoff = 0, x;
LRZ_CHUNK chunk;
// Error checking
if (src == NULL || dst == NULL || srclen < 1 || dstlen < 1)
return LRZ_BADPARAMS;
// Read the chunk count and check input size
chunks = (int) src[0];
if (!chunks || chunks * 5 + 1 > srclen) return LRZ_BADDATA;
// Process all chunks
for (; chunks > 0; chunks--, srcoff += packed, dstoff += unpacked) {
// Process the chunk header
packed = ((int) src[srcoff + 1] << 8) | (int) src[srcoff];
if (srcoff + packed > srclen) return LRZ_BADDATA;
unpacked = ((int) src[srcoff + 3] << 8) | (int) src[srcoff + 2];
if (dstoff + unpacked > dstlen) return LRZ_BADDATA;
// Construct and process a chunk object
chunk.src = &src[srcoff + 5]; chunk.dst = &dst[dstoff];
chunk.srclen = packed - 5; chunk.dstlen = unpacked;
x = lrzdChunk(&chunk); lrzdFreeChunk(&chunk);
if (x) return LRZ_BADDATA;
}
// Return success
return LRZ_SUCCESS;
}
// Examines a compressed buffer to determine its decompressed size
int lrzGetSize(unsigned char *data, int len) {
int chunks, packed, unpacked = 0, off = 1;
// Error checking
if (data == NULL || len < 1) return LRZ_BADPARAMS;
// Read the chunk count and check input size
chunks = (int) data[0];
if (!chunks || chunks * 5 + 1 > len) return LRZ_BADDATA;
// Check each chunk's packed size
for (; chunks > 0; chunks--, off += packed) {
packed = ((int) data[off + 1] << 8) | (int) data[off];
if (off + packed > len) return LRZ_BADDATA;
unpacked += (((int) data[off + 3] << 8) | (int) data[off + 2]);
}
// Return the accumulated unpacked size
return unpacked;
}
lrz_main.c
#include <stdio.h>
#include <stdlib.h>
#include "lrz.h"
// Program entry point
int main(int argc, char **argv) {
unsigned char *src, *dst;
int srclen, dstlen, x;
FILE *fPtr;
// Check the command line arguments
if (argc != 3)
{ printf("Usage: %s <infile> <outfile>\n", argv[0]); return 0; }
// Get the size of the file
fPtr = fopen(argv[1], "rb");
if (fPtr == NULL)
{ printf("Could not open %s\n", argv[1]); return 1; }
fseek(fPtr, 0, SEEK_END);
srclen = ftell(fPtr);
// Check the file size for errors
if (!srclen) {
fclose(fPtr);
printf("%s contains no data\n", argv[1]);
return 1;
}
// Load the file data
fseek(fPtr, 0, SEEK_SET);
src = malloc(srclen);
x = fread(src, 1, srclen, fPtr);
close(fPtr);
if (x != srclen) { printf("Error reading %s\n", argv[1]); return 1; }
// Get the uncompressed size of the file
dstlen = lrzGetSize(src, srclen);
if (dstlen < 1) {
free(src);
printf("%s contains errors\n", argv[1]);
return 1;
}
// Decode the file
dst = malloc(dstlen);
x = lrzDecode(src, srclen, dst, dstlen);
if (x != LRZ_SUCCESS) {
free(dst); free(src);
printf("%s contains errors\n", argv[1]);
return 1;
}
// Save the decoded output to disk
fPtr = fopen(argv[2], "wb");
if (fPtr == NULL) {
free(dst); free(src);
printf("Cannot write to %s\n", argv[2]);
return 1;
}
fwrite(dst, 1, dstlen, fPtr);
fclose(fPtr);
// User output
printf("Wrote to %s\n", argv[2]);
// Clean up and exit
free(dst);
free(src);
return 0;
}
EDIT:
Fixed a bug with the error checking, where I was using a value that wasn't being helpful. (-:
If I did my job correctly, this should now be error-proof, so use any files you want and it won't crash.
The image files in Lemmings Revolution are somewhat misleadingly named ".bmp", since the files themselves are not actual Windows Bitmap files. However, the Lemmings files
do represent Windows Bitmap files through a layer of compression.
The File FormatThe file format is as follows:
File
=============================================================================
ChunkNum UInt8 The number of chunks in the file
Chunks Chunk[] The data chunks
=============================================================================
Chunk
=============================================================================
Header ChunkHeader Describes how the chunk is encoded
Data Byte[] The compressed input data
=============================================================================
ChunkHeader
=============================================================================
PackedSize UInt16 The total size of this chunk, including the header
UnpackedSize UInt16 The size of the data this chunk represents
(Unknown) UInt8 Value of unknown significance; usually (always?) 4
RawTree BinTree Binary tree for raw byte counts
LengthTree BinTree Binary tree for distance/length lengths
DistanceTree BinTree Binary tree for distance/length distances
=============================================================================
BinTree
=============================================================================
The lower 4 bits of the first byte indicates how many additional values need
to be read from the input. If the value is 0, no additional input is needed
as the binary tree will not be used. If it's greater than 0, then add 2 to it
and read that many more values.
The values themselves are in 4-bit increments starting with the high bits of
the byte that contained the count, followed by however many bytes are
necessary to encode the remaining 4-bit values. For each byte, the lower 4
bits are read first, followed by the higher 4 bits.
The last byte may have 4 bits of padding so that the next data begins on a
byte boundary.
=============================================================================
Since the compression algorithm's implementation was designed for 16-bit systems, chunks are limited to an unpacked size of 64 KB. For files larger than this, additional chunks are present and they are simply concatenated to form the decompressed file.
Binary TreesUPDATE: Apparently the means by which these trees are stored in the file is called
canonical Huffman code.
Each chunk header can define up to 3 binary trees that are used to more concisely encode numbers into the input data. Rather, the trees are stored in the data for decoding those concise numbers. The first tree is used when reading raw byte counts, the second for when reading distance/length lengths, and the third for when reading distance/length distances. More on those later.
Note: For the uninitiated, you can mask out the lower 4 bits of a value by performing a
bitwise AND with the number 15.
The lower 4 bits of the first byte read for a binary tree indicates how many values are to be added to the tree, and those values describe how to construct that tree. These values are all 4 bits, and can be decoded with the following algorithm:
- Read a byte from the input into CURBYTE
- Copy the lower 4 bits of CURBYTE into COUNT
- If COUNT is 0
- This binary tree will not be used
- Otherwise
- Add 2 to COUNT
- Create an array NIBBLES that contains COUNT elements, with the first element being at index 0 in the list
- LOOP: Iterate X from 0 to COUNT - 1
- If X is even, divide CURBYTE by 16 (or shift CURBYTE right by 4)
- If X is odd, read the next byte from the input into CURBYTE
- Copy the lower 4 bits of CURBYTE into NIBBLES[X]
For example, the byte string 22 31 03 will yield 4 nibbles: 2, 1, 3, 3 and the 0 is just padding.
The final structure of the binary tree is not known until all of the nibbles are processed. Note that any given node in a binary tree can either be a
terminal node with a value, or a
branching node that has two child nodes. These are the only two types of nodes that can exist in a binary tree, and the topmost node that connects everything else is called the
root node.
Initially, the root node is set to be a branching node and its child nodes are of unknown type (in regards to terminal or branching). The root node is at the top of the tree, meaning it has no "depth" into the tree. For this documentation, I'll refer to this as having a "depth level" of 0. The two child nodes of the root node have a depth level of 1. If they have child nodes, their children will be at depth level 2 and so-on.
The initial tree looks like this:
Level 0 root
0/ \1
Level 1 ? ?
To determine the significance of these nodes, the list of nibbles is searched in order to find one where the nibble
value is equal to the depth level of the node in question.
IMPORTANT: The order in which the nodes are considered is determined by the
preorder traversal algorithm, where "left" corresponds with the 0 side (not the 1 side).
Consider the list of nibbles from earlier:
Nibble Value: 2 1 3 3
Nibble Index: 0 1 2 3
In this case, the first node of unknown significance is the root node's 0 child (according to preorder traversal), which is in depth level 1. Therefore, a nibble with a
value of 1 is sought. There is one, so the nibble's
index becomes the
node's value--in this case also a 1--and the nibble is processed in such a way so that it will not be considered in future searches: it is effectively "crossed out."
At this point, the tree looks like this:
Level 0 root
0/ \1
Level 1 (1) ?
Nibble Value: 2 x 3 3
Nibble Index: 0 1 2 3
Note that the value of the nibble at index 1 has been crossed out.
When the list of nibbles is searched again for another nibble with a
value of 1 (for the current depth level), none can be found because the only remaining nibbles contain 2, 3 and 3. In this situation, the node becomes a branching node and that node's 0 child is the next to be considered (according to the preorder traversal algorithm):
Level 0 root
0/ \1
Level 1 (1) @
0/ \1
Level 2 ? ?
Nibble Value: 2 x 3 3
Nibble Index: 0 1 2 3
The remainder of the nibbles and nodes are processed in the same manner--again, according to preorder traversal--and the remaining steps look like this:
=Step 3= =Step 4= =Step 5= =Step 6=
Level 0 root Level 0 root Level 0 root Level 0 root
0/ \1 0/ \1 0/ \1 0/ \1
Level 1 (1) @ Level 1 (1) @ Level 1 (1) @ Level 1 (1) @
0/ \1 0/ \1 0/ \1 0/ \1
Level 2 (0) ? Level 2 (0) @ Level 2 (0) @ Level 2 (0) @
0/ \1 0/ \1 0/ \1
Level 3 ? ? Level 3 (2) ? Level 3 (2) (3)
Nibble Value: x x 3 3 Nibble Value: x x 3 3 Nibble Value: x x x 3 Nibble Value: x x x x
Nibble Index: 0 1 2 3 Nibble Index: 0 1 2 3 Nibble Index: 0 1 2 3 Nibble Index: 0 1 2 3
Note: Nibbles need not define any values for a particular depth level. In fact, in most situations, level 1 will not contain any definitions and thus both of the child nodes of the root node themselves become branching nodes. It's important to stick to the preorder traversal algorithm and attempt to use the nibbles to assign values at each node, one step at a time.
Note: If a given nibble index doesn't need to appear in the binary tree as a node value, the nibble value at that index can be 0. Since a nibble specifying depth level 0 will never be searched for, this will effectively force that index to be skipped. For the same reason, nibbles can be "crossed out" by setting their values to 0.
Note: Data errors can easily make the tree impossible to construct. If, when searching, all of the nibbles have a value less than the current depth level, the process should be aborted before an endless loop and a memory leak occur.
Note: The process ordinarily terminates when there are no further nodes of unknown significance. In the event there are still remaining, "unused" nibbles, they are simply ignored.
The Compression AlgorithmThe compression algorithm itself is a type of
ROLZ that, in addition to encoding repeating strings of bytes in distance/length references (which is the technique used by
LZ77), is able to reduce the size of literal numbers in the data by using a binary tree, presumably constructed with the
Huffman technique. This particular implementation, however, is quite restrictive and will lose out over conventional compression algorithms for larger files. For the small data in Lemmings Revolution, however, this variant of ROLZ will generally out-perform
DEFLATE, the algorithm used in ZIP files, for total compression ratio.
The general decompression algorithm looks like this:
- Initialize the decoder to the RAW state
- LOOP: Begin decoding until all output data is processed or an error occurs
- If the current decoder state is RAW
- Read a number from the input
- Read that number of bytes (8 bit values) from the input to the output
- If the current decoder state is COPY
- Read a number from the input for LENGTH and add 2
- Read a number from the input for DISTANCE and add 1
- From the current position in the output buffer, start reading from DISTANCE bytes earlier and copy LENGTH bytes to the end of the output
- Alternate decoder states: if it's RAW, switch to COPY and vice-versa
Note: It's totally valid for LENGTH to be greater than DISTANCE. All that means is that it will copy bytes that have already been copied during the current operation. When repeating a single byte many times, DISTANCE can just be 1 and LENGTH can be however many copies you want.
Reading BitsFor the purpose of reading bits from the input data, the first bit is the highest bit (2^7) of the first byte of the input data. The second bit is 2^6 and so-forth. The ninth bit will be the highest bit of the second byte, and this continues through the input data. For example:
- Input data (as hex): 9A 36 E3
- Input data (as bits): 10011010 00110110 11101011
- To read 3 bits will return 100
- To read another 4 bits will return 1101
- To read another 10 bits will return 0001101101
Reading NumbersTo "read a number from the input," as the algorithm above indicates, follows a particular convention. Numbers can be read in one of two ways, depending on whether or not there is a binary tree present for the purpose of the number being read (raw, length or distance). This is determined by the number of nibbles read for the tree: if the number was 0, then the tree is not present.
If no tree is present for the current purpose, then numbers are read entirely from the input and conform to a "normal" format.
If a tree
is present for the current purpose, then the contents of that tree will dictate what bits are read from the input and what the value of the number will be.
The Normal Number FormatThe Normal format for numbers is as follows:
- Initialize COUNT to 0
- LOOP: Begin reading bits from the input until the bit read is a 0
- If the bit is a 1, increment COUNT
- Read an additional COUNT bits from the input into BITS
- The value of the number is 2 ^ COUNT - 1 + BITS
Note: If COUNT reaches 16 (perhaps 17?), then the data contains an error and the loop should be aborted. This isn't a violation of the format, per sé, but it
will cause the 16-bit Lemmings Revolution implementation to overflow.
The Tree Number FormatThe Tree format for numbers is as follows:
- Initialize NODE to the root node of the appropriate binary tree
- LOOP: Read 1 bit at a time from the input until NODE is a terminal node
- If the bit is a 0, set NODE to its 0 child node
- If the bit is a 1, set NODE to its 1 child node
- Copy the value of NODE into PARAM
- If PARAM is less than 2
- The value of the number is PARAM
- Otherwise
- Subtract 1 from PARAM
- Read PARAM bits from the input into BITS
- The value of the number is 2 ^ PARAM + BITS
Holy low-hanging fruit, Batman!
The .ALF file format... isn't really a format. It's just a layer of an image stored separately from the other layer. In detail, the .BMP images contain the RGB channels, and if there is a corresponding .ALF file with the same filename in the same directory, it will specify the alpha channel.
Pixels in an ALF file are stored left-to-right, top-to-bottom. This contrasts the Windows Bitmap, which stores pixels left-to-right, bottom-to-top. Each byte in the .ALF file represents a whole pixel, where the alpha value ranges from 0 (fully transparent) to 255 (fully opaque). As such, the total necessary size of any given .ALF file is the product of the pixel dimensions of its corresponding .BMP file (width * height * 1 byte per pixel).

__________
There's a naming convention in place where bitmap files that need to be processed with blending of some sort have a character stuck in front:
- ^ indicates there is a .ALF file present
- + is the same as ^? There's only one of these and it has a .ALF
- $ indicates any pixel with color value #404040 is transparent
- _ indicates any pixel with color value #000000 is transparent
- ~ indicates that the image uses additive blending
All other images are drawn without blending, or could be interpreted as images where every pixel has full opacity.

(Note that you can't create an alpha mask for additive blending. The above image is an approximation)
LEVELMAP.DAT file format:
File
========================================================================
Levels Level[125] Meta data for all levels
========================================================================
Level
========================================================================
IDSize UInt32 Size of ID string
ID String IDSize bytes, ASCII, not null-terminated
NameSize UInt32 Size of name string
Name String NameSize bytes, ASCII, not terminated
Time UInt32 Number of seconds for this level
Save UInt32 Number of Lemmings to save
Lemmings UInt32 Total number of Lemmings
========================================================================
Here's some processed output of the data:
Level 0
ID = MM_CLIMB_002
Name = Just Climb
Time = 5:00
Save = 1
Lemmings = 10
Level 1
ID = MM_FLOAT
Name = Just Float
Time = 5:00
Save = 1
Lemmings = 10
Level 2
ID = MM_BOMB
Name = Just Bomb
Time = 5:00
Save = 10
Lemmings = 20
Level 3
ID = MM_BLOCK_001_A
Name = Just Block
Time = 5:00
Save = 15
Lemmings = 30
Level 4
ID = MM_BUILD
Name = Just Build
Time = 5:00
Save = 10
Lemmings = 20
Level 5
ID = MM_MINE
Name = Just Mine
Time = 5:00
Save = 10
Lemmings = 20
Level 6
ID = MM_BASH_002
Name = Just Bash
Time = 5:00
Save = 10
Lemmings = 10
Level 7
ID = MM_DIG_000
Name = Just Dig
Time = 5:00
Save = 10
Lemmings = 20
Level 8
ID = MM_W_012
Name = Introducing - Water Lemmings
Time = 5:00
Save = 10
Lemmings = 20
Level 9
ID = MM_Block_Bomb_A
Name = Block And Bomb
Time = 10:00
Save = 10
Lemmings = 20
Level 10
ID = MM_BASH_MINE_WLR1
Name = Bash and Mine
Time = 10:00
Save = 10
Lemmings = 20
Level 11
ID = MM_BASH_DIG_001_A
Name = Bash and Dig
Time = 5:00
Save = 10
Lemmings = 20
Level 12
ID = MM_FLOAT_CLIMB2
Name = Float and Climb
Time = 10:00
Save = 6
Lemmings = 10
Level 13
ID = MM_BUILD_BLOCK_A
Name = Build and Block
Time = 5:00
Save = 10
Lemmings = 20
Level 14
ID = MM_BLOCK_BUILD_BASH
Name = Seafood Sarnie
Time = 10:00
Save = 20
Lemmings = 25
Level 15
ID = MM_E4_4_SKILLS
Name = A Long and Lonely Road
Time = 10:00
Save = 20
Lemmings = 30
Level 16
ID = MM_E1_3_SKILLS
Name = Lems at Loggerheads
Time = 10:00
Save = 5
Lemmings = 10
Level 17
ID = MM_E2_4SKILLS
Name = The Abyss
Time = 10:00
Save = 10
Lemmings = 15
Level 18
ID = E19_KF_2
Name = Kriss Kross
Time = 5:00
Save = 20
Lemmings = 30
Level 19
ID = MM_E1_4SKILLS
Name = Seargeant Bash
Time = 10:00
Save = 10
Lemmings = 20
Level 20
ID = E20_mg_1
Name = The Crowded House
Time = 10:00
Save = 5
Lemmings = 10
Level 21
ID = MM_ALL_8_001
Name = One Way Ticket
Time = 8:00
Save = 40
Lemmings = 50
Level 22
ID = MM_E1_5_Skills
Name = Swings Both Ways
Time = 10:00
Save = 16
Lemmings = 20
Level 23
ID = MM_ALL_8_002
Name = Wandering Free
Time = 10:00
Save = 10
Lemmings = 20
Level 24
ID = MM_ALL_8_003
Name = The Iron Curtain
Time = 10:00
Save = 20
Lemmings = 30
Level 25
ID = E18_KF_2
Name = Make Mine a Large One
Time = 5:00
Save = 25
Lemmings = 30
Level 26
ID = E22_KF_1
Name = Now you're stalking
Time = 6:00
Save = 49
Lemmings = 50
Level 27
ID = E11_KF_1
Name = Escape to victory
Time = 8:00
Save = 40
Lemmings = 45
Level 28
ID = M08_KF_1
Name = 2 sides to every story
Time = 10:00
Save = 40
Lemmings = 50
Level 29
ID = E16_KF_1
Name = Wood you believe it?
Time = 5:00
Save = 45
Lemmings = 50
Level 30
ID = M08_mg_1
Name = Wheelbarrows of Doom
Time = 4:00
Save = 98
Lemmings = 100
Level 31
ID = M11_KF_1
Name = Designed with love
Time = 10:00
Save = 85
Lemmings = 99
Level 32
ID = M04_KF_1
Name = Penelope Lem Stop
Time = 6:00
Save = 32
Lemmings = 32
Level 33
ID = H02_JC_1
Name = How do we get up there!
Time = 4:00
Save = 50
Lemmings = 50
Level 34
ID = E07_JC_1
Name = There`s only one way down!
Time = 5:00
Save = 10
Lemmings = 25
Level 35
ID = M02_MG_1
Name = What a Fantastic Pair of Birds
Time = 5:00
Save = 20
Lemmings = 20
Level 36
ID = MM_TELE_003
Name = The Lone Ranger
Time = 10:00
Save = 90
Lemmings = 100
Level 37
ID = M03_mg_1
Name = Swarthy Seadogs!
Time = 10:00
Save = 99
Lemmings = 100
Level 38
ID = E17_KF_1
Name = Build 'em up ....then bring em down
Time = 10:00
Save = 45
Lemmings = 50
Level 39
ID = M01_KF_1
Name = Love train boogie
Time = 10:00
Save = 25
Lemmings = 25
Level 40
ID = M10_JC_1
Name = Bounce around the world!
Time = 5:00
Save = 46
Lemmings = 50
Level 41
ID = M16_mg_1
Name = Lock In
Time = 10:00
Save = 11
Lemmings = 14
Level 42
ID = M17_MT_1
Name = Under and Up.
Time = 5:00
Save = 48
Lemmings = 60
Level 43
ID = VH04_JC1
Name = Nice shootin tex!
Time = 4:00
Save = 42
Lemmings = 50
Level 44
ID = M03_MT_1
Name = Quick as you can!
Time = 4:00
Save = 96
Lemmings = 101
Level 45
ID = M18_MT_1
Name = Watch Out! Evil about!
Time = 6:00
Save = 45
Lemmings = 50
Level 46
ID = Show_MT3
Name = Take Her to Warp Speed, Captain
Time = 8:00
Save = 12
Lemmings = 25
Level 47
ID = M20_MT_1
Name = Bridges
Time = 3:30
Save = 48
Lemmings = 53
Level 48
ID = M21_KF_1
Name = Walk the plank or join the crew?
Time = 15:00
Save = 75
Lemmings = 100
Level 49
ID = M19_MT_1
Name = Bamboo Maze
Time = 5:00
Save = 48
Lemmings = 50
Level 50
ID = H01_KF_1
Name = Can't Get There From Here
Time = 6:00
Save = 49
Lemmings = 50
Level 51
ID = H03_KF_1
Name = Lemmings Four the Drop
Time = 5:00
Save = 4
Lemmings = 4
Level 52
ID = M12_MT_1
Name = Booby trap.
Time = 8:00
Save = 46
Lemmings = 50
Level 53
ID = H17_mg_1
Name = Hit 'n' Run
Time = 10:00
Save = 10
Lemmings = 11
Level 54
ID = H05_KF_1
Name = Battle o' Lemmuckburn
Time = 10:00
Save = 43
Lemmings = 50
Level 55
ID = H06_MT_1
Name = Feeling Gravity's Pull
Time = 6:00
Save = 50
Lemmings = 66
Level 56
ID = VH02_JC1
Name = It's a hard life
Time = 7:00
Save = 45
Lemmings = 50
Level 57
ID = H08_KF_1
Name = Waste not...want not.part1
Time = 10:00
Save = 10
Lemmings = 10
Level 58
ID = H09_KF_1
Name = Ouch me head.
Time = 5:00
Save = 50
Lemmings = 50
Level 59
ID = M07_mg_1
Name = Topsy Turvy
Time = 10:00
Save = 98
Lemmings = 100
Level 60
ID = M15_mg_1
Name = The Legend of Smelly Belly
Time = 10:00
Save = 15
Lemmings = 15
Level 61
ID = H12_mg_1
Name = Where's Carol Vorderlem?
Time = 20:00
Save = 4
Lemmings = 10
Level 62
ID = H13_MT_1
Name = Use the Force Lem...
Time = 3:45
Save = 99
Lemmings = 100
Level 63
ID = H10_MT_1
Name = Scale that wall....
Time = 5:00
Save = 46
Lemmings = 50
Level 64
ID = H15_MT_1
Name = Rocket Science.
Time = 5:30
Save = 30
Lemmings = 50
Level 65
ID = E23_JC_1
Name = Time is of the essence!
Time = 3:20
Save = 48
Lemmings = 50
Level 66
ID = H16_MT_1
Name = Odd Jobs.
Time = 6:00
Save = 99
Lemmings = 100
Level 67
ID = H18_mg_1
Name = Reduce and Simmer
Time = 10:00
Save = 16
Lemmings = 20
Level 68
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 69
ID = H20_KF_1
Name = Waste not...want not.part2
Time = 10:00
Save = 10
Lemmings = 10
Level 70
ID = E25_JC_1
Name = Touch the ground turn around.
Time = 1:35
Save = 19
Lemmings = 20
Level 71
ID = H22_MT_1
Name = Which Switch is Which?
Time = 4:00
Save = 48
Lemmings = 50
Level 72
ID = H23_mg_1
Name = When Two Tribes go to War
Time = 10:00
Save = 18
Lemmings = 20
Level 73
ID = H24_KF_1
Name = Bash Street Kids
Time = 10:00
Save = 64
Lemmings = 70
Level 74
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 75
ID = VH01_JC1
Name = Something Fishy!
Time = 5:00
Save = 49
Lemmings = 50
Level 76
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 77
ID = H08_MT_1
Name = T is for Teamwork.
Time = 10:00
Save = 2
Lemmings = 2
Level 78
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 79
ID = VH05_JC1
Name = Don`t Let them out!
Time = 5:00
Save = 40
Lemmings = 50
Level 80
ID = VH06_MT
Name = Speedy Gonzalez
Time = 4:00
Save = 52
Lemmings = 53
Level 81
ID = VH07_MT
Name = Goonies
Time = 3:45
Save = 48
Lemmings = 50
Level 82
ID = VH08_MT
Name = Lemming be thy name...
Time = 5:00
Save = 51
Lemmings = 60
Level 83
ID = VH09_MT
Name = 'Tanks' a Lot
Time = 4:00
Save = 76
Lemmings = 76
Level 84
ID = VH10_MT
Name = Two Laps Finale
Time = 6:15
Save = 50
Lemmings = 50
Level 85
ID = VH11_MT
Name = The Diving Board
Time = 5:00
Save = 98
Lemmings = 100
Level 86
ID = VH12_KF1
Name = Green with Envy
Time = 10:00
Save = 15
Lemmings = 15
Level 87
ID = VH13_KF_1
Name = Anger, Love, Hate
Time = 5:00
Save = 40
Lemmings = 50
Level 88
ID = VH13_MT
Name = All in..
Time = 5:00
Save = 51
Lemmings = 51
Level 89
ID = VH15_KF_1
Name = No clues ...hee hee hee hee!
Time = 10:00
Save = 40
Lemmings = 50
Level 90
ID = VH16_MT
Name = Last one to the top.....
Time = 5:00
Save = 29
Lemmings = 30
Level 91
ID = M02_JC
Name = The Long and Winding Road
Time = 5:00
Save = 5
Lemmings = 20
Level 92
ID = VH18_JC
Name = Just you wait
Time = 4:10
Save = 98
Lemmings = 100
Level 93
ID = VH19_JC
Name = Turn on! Tune in! Switch on!
Time = 3:45
Save = 94
Lemmings = 100
Level 94
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 95
ID = VH21_JC
Name = My friend the end.
Time = 3:30
Save = 49
Lemmings = 50
Level 96
ID = VH22_KF1
Name = My finest moment
Time = 3:00
Save = 49
Lemmings = 50
Level 97
ID = MM_H_001
Name = Mission Impossible
Time = 2:00
Save = 20
Lemmings = 20
Level 98
ID = MM_H_002
Name = Race Against Time
Time = 3:00
Save = 45
Lemmings = 45
Level 99
ID = MM_H_003
Name = It's Going to Take Time
Time = 10:00
Save = 99
Lemmings = 100
Level 100
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 101
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 102
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 103
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 104
ID = m06_kf_1
Name = Sometimes up..sometimes down.
Time = 3:00
Save = 50
Lemmings = 100
Level 105
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 106
ID = show_kf3
Name = Water way to go.
Time = 10:00
Save = 25
Lemmings = 30
Level 107
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 108
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 109
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 110
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 111
ID = vh22_jc
Name = Going in all directions
Time = 3:15
Save = 44
Lemmings = 50
Level 112
ID = e06_kf_1
Name = Lets play 'catch'.
Time = 5:00
Save = 5
Lemmings = 10
Level 113
ID = e10_kf_1
Name = LEMTRIS
Time = 3:00
Save = 50
Lemmings = 50
Level 114
ID = e10_kf_2
Name = Lets get those fingers moving
Time = 5:00
Save = 12
Lemmings = 15
Level 115
ID = e14_kf_1
Name = The high dive
Time = 5:00
Save = 20
Lemmings = 40
Level 116
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 117
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 118
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 119
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 120
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 121
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 122
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 123
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Level 124
ID = blank
Name = blank
Time = 1:00
Save = 0
Lemmings = 100
Note that these levels are not in the order they appear on the level select screen. This is just defining the levels as-is. Also note that "The high dive" is the last level defined, which may somewhat explain why that's the
only level that crashes the game after a Typical install. (Note to guests: you can fix the crash by copying lemmings.box from the CD yourself after the installer does it wrong)
The ID strings are arbitrary and assigned by the developers, but we can glean some insights by looking at them. Some parts appear to be level numbers, some appear to be difficulty descriptors, and some appear to be creator initials. Not that it really matters, but might be interesting to look through.
__________
LEVELS.MAP file format:
File
===========================================================================
Unk1 UInt16 Unknown value
Unk2 UInt16 Unknown value
Slots Slot[125] Matches levels with map slots
===========================================================================
Slot
===========================================================================
Unk1 UInt8 If not 1, Unk1a is present
Unk1a UInt16 Unknown value
Unk2 UInt8 If 0, Unk2aSize and Unk2a are present
Unk2aSize UInt16 Size of unknown string
Unk2a String Unk2aSize bytes, ASCII, not null-terminated
IDSize UInt16 Size of level ID string
ID String ID string, ASCII, not terminated
Unk3 UInt32 Unknown value
Unk4 UInt32 Unknown value
Unk5 UInt32 Unknown value
===========================================================================
Once again, the processed output:
(Unk1) = 0x0019
(Unk2) = 0xFFFF
Slot 0
(Unk1) = 0x01
(Unk2) = 0x00
(Unk2a) = CLevelSlot
ID = MM_CLIMB_002
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 1
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_FLOAT
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 2
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_BOMB
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 3
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_BLOCK_001_A
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 4
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_BUILD
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 5
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_MINE
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 6
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_BASH_002
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 7
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_DIG_000
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 8
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_W_012
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 9
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_Block_Bomb_A
(Unk3) = 1
(Unk4) = 1
(Unk5) = 0
Slot 10
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_BASH_MINE_WLR1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 11
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_BASH_DIG_001_A
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 12
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_FLOAT_CLIMB2
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 13
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_BUILD_BLOCK_A
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 14
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_BLOCK_BUILD_BASH
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 15
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_E4_4_SKILLS
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 16
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_E1_3_SKILLS
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 17
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_E2_4SKILLS
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 18
(Unk1) = 0x01
(Unk2) = 0x80
ID = E19_KF_2
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 19
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_E1_4SKILLS
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 20
(Unk1) = 0x01
(Unk2) = 0x80
ID = E20_mg_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 21
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_ALL_8_001
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 22
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_E1_5_Skills
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 23
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_ALL_8_002
(Unk3) = 1
(Unk4) = 1
(Unk5) = 0
Slot 24
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_ALL_8_003
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 25
(Unk1) = 0x19
(Unk1a) = 256
(Unk2) = 0x80
ID = E18_KF_2
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 26
(Unk1) = 0x01
(Unk2) = 0x80
ID = E22_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 27
(Unk1) = 0x01
(Unk2) = 0x80
ID = E11_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 28
(Unk1) = 0x01
(Unk2) = 0x80
ID = M08_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 29
(Unk1) = 0x01
(Unk2) = 0x80
ID = E16_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 30
(Unk1) = 0x01
(Unk2) = 0x80
ID = M08_mg_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 31
(Unk1) = 0x01
(Unk2) = 0x80
ID = M11_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 32
(Unk1) = 0x01
(Unk2) = 0x80
ID = M04_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 33
(Unk1) = 0x01
(Unk2) = 0x80
ID = H02_JC_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 34
(Unk1) = 0x01
(Unk2) = 0x80
ID = E07_JC_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 35
(Unk1) = 0x01
(Unk2) = 0x80
ID = M02_MG_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 36
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_TELE_003
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 37
(Unk1) = 0x01
(Unk2) = 0x80
ID = M03_mg_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 38
(Unk1) = 0x01
(Unk2) = 0x80
ID = E17_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 39
(Unk1) = 0x01
(Unk2) = 0x80
ID = M01_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 40
(Unk1) = 0x01
(Unk2) = 0x80
ID = M10_JC_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 41
(Unk1) = 0x01
(Unk2) = 0x80
ID = M16_mg_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 42
(Unk1) = 0x01
(Unk2) = 0x80
ID = M17_MT_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 43
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH04_JC1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 44
(Unk1) = 0x01
(Unk2) = 0x80
ID = M03_MT_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 45
(Unk1) = 0x01
(Unk2) = 0x80
ID = M18_MT_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 46
(Unk1) = 0x01
(Unk2) = 0x80
ID = Show_MT3
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 47
(Unk1) = 0x01
(Unk2) = 0x80
ID = M20_MT_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 48
(Unk1) = 0x01
(Unk2) = 0x80
ID = M21_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 49
(Unk1) = 0x01
(Unk2) = 0x80
ID = M19_MT_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 50
(Unk1) = 0x19
(Unk1a) = 256
(Unk2) = 0x80
ID = H01_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 51
(Unk1) = 0x01
(Unk2) = 0x80
ID = H03_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 52
(Unk1) = 0x01
(Unk2) = 0x80
ID = M12_MT_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 53
(Unk1) = 0x01
(Unk2) = 0x80
ID = H17_mg_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 54
(Unk1) = 0x01
(Unk2) = 0x80
ID = H05_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 55
(Unk1) = 0x01
(Unk2) = 0x80
ID = H06_MT_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 56
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH02_JC1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 57
(Unk1) = 0x01
(Unk2) = 0x80
ID = H08_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 58
(Unk1) = 0x01
(Unk2) = 0x80
ID = H09_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 59
(Unk1) = 0x01
(Unk2) = 0x80
ID = M07_mg_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 60
(Unk1) = 0x01
(Unk2) = 0x80
ID = M15_mg_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 61
(Unk1) = 0x01
(Unk2) = 0x80
ID = H12_mg_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 62
(Unk1) = 0x01
(Unk2) = 0x80
ID = H13_MT_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 63
(Unk1) = 0x01
(Unk2) = 0x80
ID = H10_MT_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 64
(Unk1) = 0x01
(Unk2) = 0x80
ID = H15_MT_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 65
(Unk1) = 0x01
(Unk2) = 0x80
ID = E23_JC_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 66
(Unk1) = 0x01
(Unk2) = 0x80
ID = H16_MT_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 67
(Unk1) = 0x01
(Unk2) = 0x80
ID = H18_mg_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 68
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 69
(Unk1) = 0x01
(Unk2) = 0x80
ID = H20_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 70
(Unk1) = 0x01
(Unk2) = 0x80
ID = E25_JC_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 71
(Unk1) = 0x01
(Unk2) = 0x80
ID = H22_MT_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 72
(Unk1) = 0x01
(Unk2) = 0x80
ID = H23_mg_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 73
(Unk1) = 0x01
(Unk2) = 0x80
ID = H24_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 74
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 75
(Unk1) = 0x19
(Unk1a) = 256
(Unk2) = 0x80
ID = VH01_JC1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 76
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 77
(Unk1) = 0x01
(Unk2) = 0x80
ID = H08_MT_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 78
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 79
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH05_JC1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 80
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH06_MT
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 81
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH07_MT
(Unk3) = 1
(Unk4) = 1
(Unk5) = 0
Slot 82
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH08_MT
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 83
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH09_MT
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 84
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH10_MT
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 85
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH11_MT
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 86
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH12_KF1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 87
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH13_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 88
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH13_MT
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 89
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH15_KF_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 90
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH16_MT
(Unk3) = 1
(Unk4) = 1
(Unk5) = 0
Slot 91
(Unk1) = 0x01
(Unk2) = 0x80
ID = M02_JC
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 92
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH18_JC
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 93
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH19_JC
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 94
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 95
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH21_JC
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 96
(Unk1) = 0x01
(Unk2) = 0x80
ID = VH22_KF1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 97
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_H_001
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 98
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_H_002
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 99
(Unk1) = 0x01
(Unk2) = 0x80
ID = MM_H_003
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 100
(Unk1) = 0x19
(Unk1a) = 256
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 101
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 102
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 103
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 104
(Unk1) = 0x01
(Unk2) = 0x80
ID = m06_kf_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 105
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 106
(Unk1) = 0x01
(Unk2) = 0x80
ID = show_kf3
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 107
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 108
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 109
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 110
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 111
(Unk1) = 0x01
(Unk2) = 0x80
ID = vh22_jc
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 112
(Unk1) = 0x01
(Unk2) = 0x80
ID = e06_kf_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 113
(Unk1) = 0x01
(Unk2) = 0x80
ID = e10_kf_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 114
(Unk1) = 0x01
(Unk2) = 0x80
ID = e10_kf_2
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 115
(Unk1) = 0x01
(Unk2) = 0x80
ID = e14_kf_1
(Unk3) = 1
(Unk4) = 0
(Unk5) = 0
Slot 116
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 117
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 118
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 119
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 120
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 121
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 122
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 123
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
Slot 124
(Unk1) = 0x01
(Unk2) = 0x80
ID = blank
(Unk3) = 0
(Unk4) = 0
(Unk5) = 0
I'll have to revise this later, because the order in the file doesn't line up precisely with the level select screen using any apparent uniform algorithm. The values of Unk3 and Unk4 might assist in placing these slots on the map.
__________
RELEASERATE.PC file format:
File
=============================================
Rates Rate[99] Release rates
=============================================
Rate
=============================================
Unk1 UInt3 Unknown value
Unk2 Float Unknown value
=============================================
I don't really know what precisely these values represent, but it's apparent from the game and the number of entries that they affect the time delay between Lemming entry for various release rate settings.
The floats are encoded as
32-bit IEEE-754 values.
Whatever the case, we don't need to mess with this file when producing a level editor.
Egads, I've proven myself wrong. The .WAV files, while ordinary Microsoft Wave files, are in fact
uncompressed PCM. Further details are in the file headers, though I suspect they all match the title music, which is 22050 hz, mono, 16-bit signed.
Isn't it odd there's a bunch of "blank" levels in there. In between real ones no less. I wonder if these were levels they made and couldn't fit into the game

.
Or (morel likely) They're probably just blank level templates they made for all the levels before they started designing each individual level. If that's the case, that may give you good insight into how the levels themselves are made.
anyway, great work so far!
Next up is the .LTX file:
File
===========================================================================
Count UInt32 Number of strings in this file
Offsets UInt32[] Count starts of string data
Strings Byte[] Remainder of file--CP-1252, null-terminated
===========================================================================
Strings are stored in
Windows Code Page 1252, which was the default character set on Windows 95. The lower 128 values are identical to ASCII, though the higher 128 values are used for western European ideographs and diacritical marks.
There are six such files, one for English, French, German, Italian, Polish and Spanish. All of them have the same number of entries, suggesting that the entries in each are parallel to each other--effectively allowing translation between multiple languages.
Processed output:
130 strings in UK.LTX
130 strings in GERMAN.LTX
130 strings in SPAIN.LTX
130 strings in FRANCE.LTX
130 strings in ITALY.LTX
130 strings in POLISH.LTX
String 0
EN =
DE =
ES =
FR =
IT =
PL =
String 1
EN = Press X button
DE = Weiter mit X-Taste
ES = Presionar el botón X para continuar
FR = Appuyez sur le bouton X
IT = Premi il tasto X per continuare
PL = Wciœnij klawisz X
String 2
EN = Start
DE = Start
ES = Comenzar
FR = Commencer
IT = Avvio
PL = Start
String 3
EN = Options
DE = Optionen
ES = Opciones
FR = Options
IT = Opzioni
PL = Opcje
String 4
EN = Game Options
DE = Spiel-Optionen
ES = Opciones Del Juego
FR = Options du jeu
IT = Opzioni Di Gioco
PL = Opcje Gry
String 5
EN = Controls
DE = Steuerung
ES = Controles
FR = Contrôles
IT = Comandi
PL = Sterowanie
String 6
EN = Audio
DE = Audio
ES = Sonido
FR = Audio
IT = Audio
PL = Audio
String 7
EN = Video
DE = Bildschirm
ES = Video
FR = Vidéo
IT = Video
PL = Wideo
String 8
EN = Load Game
DE = Spiel Laden
ES = Cargar Partida
FR = Charger partie
IT = Carica Partita
PL = Wczytaj Grê
String 9
EN = View Credits
DE = Credits
ES = Ver Créditos
FR = Voir crédits
IT = Visualizza Autori
PL = Autorzy
String 10
EN = English
DE = Deutsch
ES = Español
FR = Français
IT = Italiano
PL = Polski
String 11
EN = Music
DE = Musik
ES = Música
FR = Musique
IT = Musica
PL = Muzyka
String 12
EN = SFX
DE = SFX
ES = Efectos de sonido
FR = Effets sonores
IT = SFX
PL = Efekty dŸwiêkowe
String 13
EN = Mono
DE = Mono
ES = Mono
FR = Mono
IT = Mono
PL = Mono
String 14
EN = Stereo
DE = Stereo
ES = Estéreo
FR = Stéréo
IT = Stereo
PL = Stereo
String 15
EN = Select
DE = Auswählen
ES = Selección
FR = Sélectionner
IT = Seleziona
PL = Wybierz
String 16
EN = Return
DE = Zurück
ES = Volver
FR = Retour
IT = Invio
PL = Powrót
String 17
EN = Climb
DE = Klettern
ES = Trepar
FR = Grimper
IT = Scala
PL = Wspinanie
String 18
EN = Reset Controls
DE = Standard-Steuerung?
ES = ¿Restablecer controles?
FR = Rétablir contrôles
IT = Ripristina comandi?
PL = Zresetuj ustawienia sterowania
String 19
EN = Reset Screen
DE = Standard-Anzeige
ES = Restablecer pantalla
FR = Rétablir écran
IT = Ripristina videata
PL = Zresetuj ekran
String 20
EN = Reset
DE = Reset
ES = Reiniciar
FR = Rétablir
IT = Reset
PL = Zresetuj
String 21
EN = Yes
DE = Ja
ES = Sí
FR = Oui
IT = Sì
PL = Tak
String 22
EN = No
DE = Nein
ES = No
FR = Non
IT = No
PL = Nie
String 23
EN = Start Stage
DE = Anfangslevel
ES = Iniciar etapa
FR = Commencer scène
IT = Inizio livello
PL = Rozpocznij Etap
String 24
EN = Accept Changes And Exit
DE = Annehmen Und Schließen?
ES = Guardar Cambios Y Salir?
FR = Accepter les modifications et quitter
IT = Accetti Le Modifiche Ed Esci?
PL = ZatwierdŸ zmiany i opuœæ
String 25
EN = Press appropriate button
DE = Bitte Taste Wählen!
ES = ¡Presiona el botón correcto!
FR = Appuyer sur la bonne touche !
IT = Premi il tasto appropriato!
PL = Wciœnij odpowiedni klawisz
String 26
EN = Save Game?
DE = Speichern?
ES = ¿Guardar Juego?
FR = Enregistrer la partie ?
IT = Salvare La Partita?
PL = Zachowaæ grê?
String 27
EN = Lemmings
DE = Lemmings
ES = Lemmings
FR = Lemmings
IT = Lemmings
PL = Lemmings
String 28
EN = YOU WILL BE UNABLE TO SAVE GAMES
DE = Sie können nicht speichern
ES = No se pueden guardar los juegos.
FR = VOUS NE POURREZ PAS ENREGISTRER LES PARTIES
IT = Impossibile salvare le partite
PL = NIE BÊDZIESZ MÓG£ ZACHOWYWAÆ GIER
String 29
EN = Empty
DE = Leer
ES = Vacío
FR = Vide
IT = Vuoto
PL = Pusty
String 30
EN = Player
DE = Spieler
ES = Jugador
FR = Joueur
IT = Giocatore
PL = Gracz
String 31
EN = Difficulty Level
DE = Schwierigkeitsgrad
ES = Nivel De Dificultad
FR = Niveau de difficulté
IT = Livello Di Difficoltà
PL = Poziom Gry
String 32
EN = Easy
DE = Leicht
ES = Fácil
FR = Facile
IT = Facile
PL = £atwy
String 33
EN = Hard
DE = Schwer
ES = Difícil
FR = Difficile
IT = Difficile
PL = Trudny
String 34
EN = Medium
DE = Mittel
ES = Intermedio
FR = Moyen
IT = Intermedio
PL = Œredni
String 35
EN = Nightmare
DE = Alptraum
ES = Pesadilla
FR = Cauchemar
IT = Incubo
PL = Koszmarny
String 36
EN = Loading
DE = Ladevorgang
ES = Cargando
FR = Chargement en cours
IT = Caricamento
PL = Wczytywanie
String 37
EN = Select Option
DE = Option wählen
ES = Seleccionar opción
FR = Sélectionner une option
IT = Seleziona opzione
PL = Wybierz Opcjê
String 38
EN = Save Game
DE = Gespeicherte Spiele
ES = Guardar Partida
FR = Enregistrer la partie
IT = Salva Partita
PL = Zachowaj Grê
String 39
EN = Credits
DE = Info
ES = Créditos
FR = Crédits
IT = Autori
PL = Autorzy
String 40
EN = Well Done - Now try it on Hard difficulty.
DE = Gut gemacht - versuch' jetzt den schweren Schwierigkeitsgrad.
ES = Bien hecho - Ahora inténtalo con el nivel Difícil.
FR = Bien joué ! Essayez à présent en mode Difficile.
IT = Bel lavoro! Adesso prova il livello Difficile.
PL = Dobrze - a teraz spróbuj na poziomie Trudnym
String 41
EN = Well Done - Now try it on Medium difficulty.
DE = Gut gemacht - versuch' jetzt den mittleren Schwierigkeitsgrad.
ES = Bien hecho - Ahora inténtalo con el nivel Intermedio.
FR = Bien joué ! Essayez à présent en mode Moyen.
IT = Bel lavoro! Adesso prova il livello Intermedio.
PL = Dobrze - a teraz spróbuj na poziomie Œrednim
String 42
EN = Well Done - Now try it on Nightmare difficulty.
DE = Gut gemacht - versuch' jetzt den Alptraum-Modus.
ES = Bien hecho - Ahora inténtalo con el nivel Pesadilla
FR = Bien joué ! Essayez à présent en mode Cauchemar.
IT = Bel lavoro! Adesso prova il livello Incubo.
PL = Dobrze - a teraz spróbuj na poziomie Koszmarnym
String 43
EN = Quit
DE = Beenden
ES = Abandonar
FR = Quitter
IT = Esci
PL = OpuϾ
String 44
EN = Resume
DE = Wiederaufnehmen
ES = Reanudar
FR = Reprendre
IT = Riprendi
PL = Wznów grê
String 45
EN = Very Hard
DE = Vieben Harden
ES = Mucho Hardez
FR = Très difficile
IT = Mucho Hardo
PL = Bardzo Trudny
String 46
EN = Special
DE = Speziell
ES = Especial
FR = Spécial
IT = Speciale
PL = Specjalny
String 47
EN = Continue
DE = Weiter
ES = Continuar
FR = Continuer
IT = Continua
PL = Kontynuuj
String 48
EN = Try Again
DE = Nochmals versuchen
ES = Volver a intentarlo
FR = Recommencer
IT = Riprova
PL = Spróbuj jeszcze raz
String 49
EN = You Failed To Rescue Enough Lemmings! Please try again!
DE = Du hast nicht genug Lemminge gerettet! Versuch es nochmals!
ES = ¡No has conseguido rescatar suficientes Lemmings! Vuelve a intentarlo.
FR = Vous n'avez pas sauvé assez de Lemmings ! Recommencez S.V.P. !
IT = Non è stato salvato un numero sufficiente di Lemming. Riprovare
PL = Nie uda³o ci siê uratowaæ doœæ Lemmingów! Spróbuj jeszcze raz!
String 50
EN = You Totally Stormed That Level!
DE = Du hast diesen Level im Sturm genommen!!
ES = ¡Has arrasado el nivel!
FR = Vous avez remporté de niveau haut la main !
IT = Avete proprio sfondato in quel livello!
PL = Totalnie rozgromi³eœ ten poziom!
String 51
EN = Fast Rotate
DE = Schnelle Umdrehung
ES = Rápido Rote
FR = Rotation rapide
IT = Veloce Ruotare
PL = Szybki obrót
String 52
EN = Flip
DE = Leichter Schlag
ES = Tirón
FR = Retourner
IT = Vibrazione
PL = Flip
String 53
EN = Rotate Cylinder
DE = Drehen Sie Zylinder
ES = Rote El Cilindro
FR = Rotation cylindre
IT = Ruotare Il Cilindro
PL = Rotate Cylinder
String 54
EN = Select Skill
DE = Wählen Sie Fähigkeit Aus
ES = Seleccione La Habilidad
FR = Sélectionner capacité
IT = Selezionare L' Abilità
PL = Wybierz poziom umiejêtnoœci
String 55
EN = Play Level
DE = Level spielen
ES = Jugar nivel
FR = Jouer niveau
IT = Gioca livello
PL = Rozegraj poziom
String 56
EN = Tutorial
DE = Lektion
ES = Guía
FR = Didacticiel
IT = Lezione Privata
PL = Przewodnik
String 57
EN = Record Demo
DE =
ES =
FR = Enregistrer démo
IT =
PL = Nagraj demo
String 58
EN = Recorder off
DE =
ES =
FR = Enregistrement désactivé
IT =
PL = Wy³¹cz nagrywanie
String 59
EN = Playback Demo
DE =
ES =
FR = Lire démo
IT =
PL = Odtwórz demo
String 60
EN = Cursor Reversed
DE = Cursor Aufgehoben
ES = Cursor Invertido
FR = Curseur inversé
IT = Cursore Invertito
PL = Kursor odwrócony
String 61
EN = Cursor Not Reversed
DE = Cursor Nicht Aufgehoben
ES = Cursor No Invertido
FR = Curseur non inversé
IT = Cursore Non Invertito
PL = Kursor nie odwrócony
String 62
EN = Fixed Cursor
DE = Örtlich Festgelegter Cursor
ES = Fijo Cursor
FR = Curseur fixe
IT = Fisso Cursore
PL = Kursor sta³y
String 63
EN = Dead zone cursor
DE = Toter Zone Cursor
ES = Cursor muerto de la zona
FR = Curseur zone morte
IT = Cursore guasto di zona
PL = Martwa strefa kursora
String 64
EN = Free Floating Cursor
DE = Freier Schwimmen Cursor
ES = Cursor Libre De La Flotación
FR = Curseur flottant
IT = Cursore Libero Di Galleggiante
PL = Kursor swobodny
String 65
EN = Toggle Fullscreen
DE = Schalten Sie Vollen Bildschirm
ES = Cambie Completa La Pantalla
FR = Basculer plein écran
IT = Passare Pieno Lo Schermo
PL = Pe³ny ekran
String 66
EN = Choose Video Device Driver
DE = Wählen Sie VideoEinheit
ES = Elija Video El Dispositivo
FR = Choisir pilote d'affichage
IT = Scegliere Il Video Dispositivo
PL = Wybierz sterownik graficzny
String 67
EN = Time Remaining
DE = Verbleibende Zeit
ES = Tiempo restante
FR = Temps restant
IT = Tempo residuo
PL = Pozosta³y czas
String 68
EN = Out
DE = Aus
ES = Fuera
FR = Sortie
IT = Fuori
PL = Out
String 69
EN = Saved
DE = Gerettet
ES = Salvados
FR = Sauvés
IT = Salvati
PL = Zachowano
String 70
EN = Loading
DE = Ladevorgang
ES = Cargando
FR = Chargement en cours
IT = Caricamento
PL = Wczytywanie
String 71
EN = Let's Go!
DE = Los geht's!
ES = ¡Adelante!
FR = Allons-y !
IT = Avanti!
PL = Ruszamy!
String 72
EN = Min
DE = Min
ES = Min
FR = Min
IT = Min.
PL = Min.
String 73
EN = Sec
DE = Sek
ES = Seg.
FR = Sec
IT = Sec
PL = Sek.
String 74
EN = Climber
DE = Kletterer
ES = Trepador
FR = Grimpeur
IT = Scalatore
PL = Wspinacz
String 75
EN = Floater
DE = Springer
ES = Paracaidista
FR = Flotteur
IT = Galleggiatore
PL = Fruwacz
String 76
EN = Bomber
DE = Bombe
ES = Bombardero
FR = Lemming à explosion
IT = Bomba
PL = Bomber
String 77
EN = Blocker
DE = Blocker
ES = Bloque
FR = Intercepteur
IT = Bloccatore
PL = Bloker
String 78
EN = Builder
DE = Brückenbauer
ES = Constructor
FR = Constructeur
IT = Costruttore
PL = Budowniczy
String 79
EN = Basher
DE = Horizontalbuddler
ES = Golpe
FR = Cogneur
IT = Sfondatore
PL = Rozbijacz
String 80
EN = Miner
DE = Diagonalgräber
ES = Minero
FR = Mineur
IT = Minatore
PL = Miner
String 81
EN = Digger
DE = Vertikalwühler
ES = Cavador
FR = Creuseur
IT = Scavatore
PL = Kopacz
String 82
EN = Speed Up
DE = Tempo
ES = Acelerar
FR = Accélérer
IT = Accelera
PL = Przyspieszenie
String 83
EN = Nuke!
DE = Feuer!
ES = ¡Bombardea!
FR = Annihiler !
IT = Annienta!
PL = Nuke!
String 84
EN = Paused
DE = Unterbrochen
ES = Pausa
FR = Interrompu
IT = Interrotto
PL = Pauza
String 85
EN = Skill Names Enabled
DE = Fähigkeit Namen Sind Sichtbar
ES = Nombres De La Habilidad Son Visibles
FR = Noms des capacités activés
IT = I Nomi Di Abilità Sono Visibile
PL = Nazwy umiejêtnoœci w³¹czone
String 86
EN = Skill Names Disabled
DE = Fähigkeit Namen Sind Nicht Sichtbar
ES = Nombres De La Habilidad No Son Visibles
FR = Noms des capacités désactivés
IT = I Nomi Di Abilità Non Sono Visibile
PL = Nazwy umiejêtnoœci wy³¹czone
String 87
EN = You must save the Lemmings!
DE = Sie müssen den Lemmings retten!
ES = Usted debe rescatar el Lemmings!
FR = Vous devez sauver les Lemmings !
IT = Dovete salvare il Lemmings!
PL = Musisz uratowaæ Lemmingi!
String 88
EN = Help them to reach their balloon
DE = Helfen Sie ihnen, zu ihrem Ballon zu entgehen
ES = Ayude al Lemmings para alcanzar su globo
FR = Aidez-les à atteindre leur montgolfière
IT = Aiutare il Lemmings per raggiungere il loro aerostato
PL = Pomó¿ im dotrzeæ do balonu
String 89
EN = Click and hold RIGHT MOUSE BUTTON to rotate
DE = Klicken Sie an und halten Sie die RECHTE^MAUSTASTE nieder sich drehen
ES = BOTÓN de RATÓN DERECHO del tecleo y del considerar a rotar
FR = Cliquez sur le BOUTON DROIT DE LA SOURIS et maintenez-le enfoncé pour pivoter
IT = TASTO di MOUSE DI DESTRA della stretta^e di scatto da ruotare
PL = Aby obróciæ, kliknij i przytrzymaj lewy klawisz myszy
String 90
EN = For a closer look press SPACE BAR
DE = Für eine genauere Blickpresse-cLeertaste
ES = Para mirar más cercana prensa SPACEBAR
FR = Pour voir les choses de plus près, appuyez sur la BARRE D'ESPACE
IT = Premere la BARRA di SPAZIO per osservare^più molto attentamente
PL = Aby przyjrzeæ siê bli¿ej, wciœnij SPACJÊ
String 91
EN = Press SPACE BAR again to zoom out
DE = Betätigen Sie ' LEERTASTE ' wieder Zoom aus
ES = Presione la BARRA de ESPACIO otra vez para enfocar fuera de
FR = Appuyez à nouveau sur la BARRE D'ESPACE pour effectuer un zoom arrière
IT = Premere ancora la BARRA di SPAZIO per zumare verso l'esterno
PL = Aby siê odsun¹æ, ponownie wciœnij SPACJÊ
String 92
EN = You can give the Lemmings SKILLS^LEFT CLICK on the SKILL ICON
DE = Sie konnen die FAHIGKEITEN Lemmings geban^KLICKEN VERLIESS auf der FÄHIGKEIT IKONE
ES = Usted puede dar las HABILIDADES al Lemmings^TECLEO IZQUIERDO mientras que el cursor está concluído el ICONO de la HABILIDAD
FR = Vous pouvez donner des CAPACITÉS aux Lemmings^CLIQUEZ SUR L'ICÔNE D'UNE CAPACITÉ à l'aide du BOUTON GAUCHE DE LA SOURIS
IT = Potete dare le ABILITÀ al Lemmings^DI SINISTRA SCATTARE sopra l' ICONA di ABILITÀ
PL = Mo¿esz nadaæ Lemmingom UMIEJÊTNOŒÆ^KLIKNIJ LEWYM IKONÊ UMIEJÊTNOŒCI
String 93
EN = Now move the cursor over a Lemming^LEFT CLICK to activate the skill
DE = Verschieben Sie jetzt den CURSOR über einem Lemming ^und einem LEFT-CLICK wieder
ES = Ahora mueva el cursor concluído un Lemming^TECLEO IZQUIERDO para activar la habilidad
FR = Amenez à présent le curseur au-dessus d'un Lemming^CLIQUEZ À L'AIDE DU BOUTON GAUCHE DE LA SOURIS pour activer la capacité
IT = Ora spostare il cursore sopra un Lemming^SCATTO DI SINISTRA per attivare l' abilità
PL = Teraz przesuñ kursor nad Lemminga^KLIKNIJ LEWYM, aby uaktywniæ umiejêtnoœæ
String 94
EN = Here we've made a BLOCKER Lemming
DE = Hier haben wir GEBLOCKT einen Lemming
ES = Aquí hemos hecho un BLOQUE Lemming
FR = Nous venons de créer un Lemming BLOQUEUR
IT = Qui abbiamo fatto uno BLOCCATORE Lemming
PL = Tutaj mamy Lemminga BLOKERA
String 95
EN = All Lemmings will turn around when they meet him
DE = Alles Lemmings dreht sich herum^wenn sie treffen ihn
ES = Todo el Lemmings dará vuelta alrededor cuando lo satisfacen
FR = Tous les Lemmings feront demi-tour lorsqu'ils le rencontreront
IT = Tutto il Lemmings girerà intorno quando lo vengono a contatto di
PL = Wszystkie Lemmingi odwróc¹ siê, kiedy na niego trafi¹
String 96
EN = To get over the wall we need CLIMBERS
DE = Über der Wand müssen wir erhalten BERGSTEIGER
ES = Para conseguir concluído la pared necesitamos a TREPADORES
FR = Pour passer au-dessus du mur, nous avons besoin de GRIMPEURS
IT = Per ottenere sopra la parete abbiamo bisogno dei SCALATORE
PL = Aby przedostaæ siê przez mur, potrzebujemy WSPINACZY
String 97
EN = LEFT CLICK on the Icon^LEFT CLICK on the Lemming
DE = LEFT-CLICK auf der Ikone^LEFT-CLICK auf dem Lemming
ES = IZQUIERDO HAGA CLIC encendido el icono^IZQUIERDO HAGA CLIC encendido el Lemming
FR = Pour choisir un Lemming qui va vers la GAUCHE^Maintenez la TOUCHE PORTANT UNE FLÈCHE VERS LA GAUCHE enfoncée
IT = DI SINISTRA SCATTARE sopra l' icona^DI SINISTRA SCATTARE sopra il Lemming
PL = KLIKNIJ LEWYM ikonê^KLIKNIJ LEWYM Lemminga
String 98
EN = To choose a Lemming moving LEFT^Hold down the LEFT ARROW KEY
DE = um ein Lemming zu wählen, das sich NACH LINKS bewegt^halten Sie die LINKE PFEILTASTE nach unten^und wenden Sie die Fähigkeit an
ES = Para elegir una IZQUIERDA móvil de Lemming^mantenga IZQUIERDO el CLAVE de FLECHA
FR = Pour choisir un Lemming qui va vers la DROITE^Maintenez la TOUCHE PORTANT UNE FLÈCHE VERS LA DROITE enfoncée
IT = Per scegliere una PARTE DI SINISTRA commovente^di Lemming mantenere DI SINISTRA il TASTO di FRECCIA
PL = Jeœli chcesz, ¿eby Lemming poszed³ W LEWO^Wciœnij LEWY KURSOR
String 99
EN = To choose a Lemming moving RIGHT^Hold down the RIGHT ARROW KEY
DE = um ein Lemming zu wählen, das sich NACH RECHTS bewegt^halten Sie die TASTE "CCursor NACH RECHTS" nach unten^und wenden Sie die Fähigkeit an
ES = Para elegir una DERECHA móvil de Lemming^mantenga DERECHO el CLAVE de FLECHA
FR = Pour donner une COMPÉTENCE à un Lemming^qui se déplace vers la DROITE^maintenez la TOUCHE DE DÉPLACEMENT DU CURSEUR DROITE
IT = Per scegliere una DESTRA commovente di Lemming^mantenere il TASTO della FRECCIA A DESTRA
PL = Jeœli chcesz, ¿eby Lemming poszed³ W PRAWO^Wciœnij PRAWY KURSOR
String 100
EN = Look out for the drop!
DE = Schauen Sie heraus nach dem Tropfen!
ES = Guárdese de la gota!
FR = Attention à la chute !
IT = Guardarsi dalla goccia!
PL = Wypatruj kropli!
String 101
EN = Ooops
DE = Ooops
ES = Ooops
FR = Oups !
IT = Ooops
PL = £aaa
String 102
EN = Give them the FLOATER skill^to fall safely from a great height
DE = Geben Sie ihnen die FALLSCHIRM-Fähigkeit^zum Fall sicher von einer großen Höhe
ES = Déles la habilidad del PARACAIDISTA a la caída^con seguridad de una gran altura
FR = Donnez-leur la capacité de FLOTTEUR^pour leur permettre de tomber de haut en toute sécurité
IT = Dare loro la caduta di skill^to del FLOATER sicuro grande da un' altezza
PL = Nadaj im umiejêtnoœæ FRUWACZA^aby mog³y opaœæ bezpiecznie z du¿ej wysokoœci
String 103
EN = Look out for the water!^These Lemmings will drown
DE = Schauen Sie heraus nach dem water!^ Diese Lemmings ertrinkt
ES = Guárdese del agua!^Este Lemmings se ahogará
FR = Attention à l'eau !^Ces Lemmings vont se noyer
IT = Guardarsi dall' acqua!^Questo Lemmings si annegherà
PL = Wypatruj wody!^Te Lemmingi siê utopi¹.
String 104
EN = We need a BUILDER to reach the other side
DE = Wir benötigen einen HORIZONTALBUDDLER,^das andere seitliche zu erreichen
ES = Necesitamos a un CONSTRUCTOR alcanzar el otro lateral
FR = Nous aurons besoin d'un CONSTRUCTEUR pour atteindre l'autre côté
IT = Abbiamo bisogno d'un COSTRUTTORE^di raggiungere l' altro laterale
PL = Aby dostaæ siê na drug¹ stronê, potrzebujemy BUDOWNICZEGO
String 105
EN = Now let's use a MINER
DE = Verwenden Sie jetzt ein BERGMANN
ES = Ahora utilicemos a un MINERO
FR = Utilisons maintenant un MINEUR
IT = Ora usiamo un MINATORE
PL = A teraz u¿yjmy MINERA
String 106
EN = A MINER cannot mine through metal^Try again on softer ground
DE = Ein BERGMANN kann nicht durch Metall gewinnen^Versuchen noch einmal auf weicherem Boden
ES = Un MINERO no puede minar con metal^Try otra vez en más lisa tierra
FR = Le MINEUR ne peut pas creuser le métal^Essayez de nouveau sur un sol plus tendre
IT = Un MINATORE non può estrarre attraverso metallo^Prova ancora più molle su terra
PL = MINER nie mo¿e siê wkopaæ w metal^Spróbuj znaleŸæ miêkkie pod³o¿e
String 107
EN = This is also true for DIGGERS and BASHERS
DE = Dies gilt auch für GRÄBERS und HORIZONTALBUDDLERS
ES = Esto es también verdad para los CAVADORES y BASHERS
FR = C'est également le cas des CREUSEURS et des COGNEURS
IT = Ciò è egualmente allineare per gli SCAVATORI e SFONDATORE
PL = Dotyczy to tak¿e KOPACZY i ROZBIJACZY
String 108
EN = Almost there!
DE = Wir haben fast beendet!
ES = Casi hemos acabado!
FR = Vous y êtes presque !
IT = Quasi abbiamo rifinito!
PL = No prawie!
String 109
EN = A DIGGER can now escape^But don't forget the others!
DE = Ein VERTIKALWÜHLER kann jetzt entgehen^Aber vergessen Sie nicht die anderen!
ES = Un CAVADOR puede ahora ser free^But usted no puede olvidarse del otros!
FR = Un CREUSEUR peut à présent s'échapper^Mais n'oubliez pas les autres !
IT = Uno SCAVATORE può ora fuoriuscire^Ma non dimenticare l' altri!
PL = KOPACZ mo¿e teraz uciec^Ale nie zapomnij o innych!
String 110
EN = A BASHER can free them^The BASHER must be next to the wall
DE = Ein HORIZONTALBUDDLER kann sie^Ein HORIZONTALBUDDLER freigeben muß nahe bei der Sperre
ES = Un GOLPE puede liberar them^The GOLPE debe estar al lado de la pared
FR = Un COGNEUR peut les libérer^Il doit se trouver à proximité du mur
IT = Un SFONDATORE può liberare them^The SFONDATORE deve essere vicino alla parete
PL = ROZBIJACZ mo¿e je uwolniæ^ROZBIJACZ musi staæ obok muru
String 111
EN = A BOMBER Lemming will explode
DE = Ein BOMBE Lemming explodiert
ES = Un BOMBARDERO Lemming estallará
FR = Un Lemming À EXPLOSION va exploser
IT = Un BOMBA Lemming esploderà
PL = Lemming BOMBER wybuchnie
String 112
EN = Click and hold on the balloon^to speed up time
DE = Klicken Sie und halten Sie auf dem Ballon an,^um Zeit zu beschleunigen
ES = Haga clic y sostenga en el globo para^acelerar tiempo
FR = Cliquez sur la montgolfière et maintenez le bouton enfoncé pour accélérer l'horloge
IT = Aerostato del sull del tenere di Scattarsi^e ' per il tempo del il del accelerare
PL = Kliknij i przytrzymaj balon^aby przyspieszyæ up³yw czasu
String 113
EN = If things go wrong^NUKE the level with a DOUBLE CLICK
DE = Wenn Sachen gegangenes wrong^NUKE die Stufe mit einem DOPPELTEN Mäuse-cKlicken
ES = Si van las cosas mal^NUKE el nivel con un DOBLE HACEN CLIC
FR = Si la situation se gâte^un DOUBLE CLIC vous permet d'ANNIHILER le niveau
IT = Se le cose vanno wrong^NUKE il livello con un DOPPIO SI SCATTANO
PL = Jeœli sprawy potocz¹ siê Ÿle^NUKNIJ poziom PODWÓJNYM KLIKNIÊCIEM
String 114
EN = Now it's your turn....
DE = Jetzt ist es Ihre Umdrehung
ES = Ahora es su vuelta
FR = À vous de jouer...
IT = Ora è la vostra girata
PL = Teraz twoja kolej...
String 115
EN = English
DE = English
ES = English
FR = English
IT = English
PL = English
String 116
EN = Français
DE = Français
ES = Français
FR = Français
IT = Français
PL = Français
String 117
EN = Deutsch
DE = Deutsch
ES = Deutsch
FR = Deutsch
IT = Deutsch
PL = Deutsch
String 118
EN = Italiano
DE = Italiano
ES = Italiano
FR = Italiano
IT = Italiano
PL = Italiano
String 119
EN = Español
DE = Español
ES = Español
FR = Español
IT = Español
PL = Español
String 120
EN = Language Selection
DE = Sprachenwahl
ES = Selección de idioma
FR = Sélection de la langue
IT = Selezione lingua
PL = Wybór jêzyka
String 121
EN = You Needed
DE = Benötigt:
ES = Necesitabas
FR = Il vous en fallait
IT = Occorreva
PL = Potrzebnych
String 122
EN = You Saved
DE = Gerettet:
ES = Salvaste
FR = Vous en avez sauvé
IT = Sono stati salvati
PL = Uratowanych
String 123
EN = Save
DE = Rettung
ES = Rescate
FR = Enregistrer
IT = Salvataggio
PL = Zachowaj
String 124
EN = Self-playing tutorial: Press P to pause
DE = Lektion: P, um zu pausieren
ES = Guía: Presione P para detenerse brevemente
FR = Didacticiel automatique : Appuyez sur P pour interrompre
IT = Lezione Privata: P per fare una pausa
PL = Przewodnik: Aby w³¹czyæ pauzê, wciœnij klawisz P
String 125
EN = Start New Game
DE = Neues Spiel starten
ES = Comenzar partida nueva
FR = Commencer nouvelle partie
IT = Inizia nuova partita
PL = Rozpocznij now¹ grê
String 126
EN = Play Current Game
DE = Aktuelles Spiel spielen
ES = Jugar partida en curso
FR = Jouer partie actuelle
IT = Gioca partita in corso
PL = Rozegraj aktualn¹ grê
String 127
EN = Back to Main Menu
DE = Zurück zum Hauptmenü
ES = Volver al menú principal
FR = Retour au menu principal
IT = Indietro al menu principale
PL = Powrót do menu g³ównego
String 128
EN = Polski
DE = Polski
ES = Polski
FR = Polski
IT = Polski
PL = Polski
String 129
EN = Continue?
DE = Weiter?
ES = Continuar?
FR = Continuer?
IT = Continua?
PL = Kontynuuj?
According to this, uh... there's a self-playing tutorial? O-: How do you access it?
And now for the .SPR file format:
File
==================================================================
AnimCount UInt32 Number of animations in this file
Animations Animation[] Animation definitions
(Unk1) UInt32 Unknown value--if 0, is EoF
(Unk2) UInt32 Unknown value
(UnkList) UnkItem[] Unknown list--remainder of file
==================================================================
Animation
==================================================================
FrameCount UInt32 Number of frames in this animation
Frames Frame[] Frame definitions
IDSize UInt32 Size of animation ID string
ID UInt32 Animation ID string
(Unk1) UInt32 Unknown value
(Unk2) Float Unknown value
==================================================================
Frame
==================================================================
AngleCount UInt32 Number of angles for this frame
Angles Angle[] Angle definitions
==================================================================
Angle
==================================================================
(Unk1) UInt32 Unknown value
(Unk2) UInt32 Unknown value
(Unk3) UInt32 Unknown value
(Unk4) UInt32 Unknown value
(Unk5) UInt32 Unknown value
(Unk6) Float Unknown value
(Unk7) UInt32 Unknown value
(Unk8) Float Unknown value
(Unk9) Float Unknown value (may be UInt32)
(Unk10) Float Unknown value
(Unk11) Float Unknown value (may be UInt32)
(Unk12) Float Unknown value
(Unk13) UInt32 Unknown value
(Unk14) UInt32 Unknown value
(Unk15) UInt32 Unknown value
(Unk16) UInt32 Unknown value
TextureSize UInt32 Size of texture name string
Texture String Texture name string
==================================================================
UnkItem -- The total number of these is not apparent in the data
==================================================================
(Unk1) UInt32 Unknown value
(Unk2) Float Unknown value
==================================================================
Obviously, I haven't investigated this too thoroughly. Most of the values in the file have unknown significance, but I wanted to get the file structure documented.
Nothing appears to be vanilla ST texture coordinates, but besides that and timing information there can't be much in there. Maybe if someone's bored they can look through it a little closer.
Sample output from SPRITES\FIRE.SPR:
Animations = 1
Animation 0
Frames = 16
Frame 0
Angles = 1
Angle 0
(Unk1) = 57
(Unk2) = 32
(Unk3) = 15
(Unk4) = 34
(Unk5) = 0xD1BC2503
(Unk6) = 1.796687f
(Unk7) = 0x0F6BF3AA
(Unk8) = 1.692771f
(Unk9) = 0.000000f
(Unk10) = 1.484375f
(Unk11) = 0.000000f
(Unk12) = 1.632813f
(Unk13) = 9
(Unk14) = 0
(Unk15) = 19
(Unk16) = 25
Texture = Sheets\_Fire0
Frame 1
Angles = 1
Angle 0
(Unk1) = 59
(Unk2) = 31
(Unk3) = 71
(Unk4) = 90
(Unk5) = 0x9A3784A0
(Unk6) = 1.802711f
(Unk7) = 0x46F0940C
(Unk8) = 1.686747f
(Unk9) = 0.000000f
(Unk10) = 1.763672f
(Unk11) = 0.000000f
(Unk12) = 1.800781f
(Unk13) = 9
(Unk14) = 0
(Unk15) = 19
(Unk16) = 28
Texture = Sheets\_Fire0
Frame 2
Angles = 1
Angle 0
(Unk1) = 83
(Unk2) = 59
(Unk3) = 37
(Unk4) = 56
(Unk5) = 0x00000000
(Unk6) = 1.875000f
(Unk7) = 0x9A3784A0
(Unk8) = 1.802711f
(Unk9) = 0.000000f
(Unk10) = 1.644531f
(Unk11) = 0.000000f
(Unk12) = 1.718750f
(Unk13) = 9
(Unk14) = 0
(Unk15) = 19
(Unk16) = 24
Texture = Sheets\_Fire0
Frame 3
Angles = 1
Angle 0
(Unk1) = 58
(Unk2) = 32
(Unk3) = 34
(Unk4) = 53
(Unk5) = 0xB5F9D4D2
(Unk6) = 1.799699f
(Unk7) = 0x0F6BF3AA
(Unk8) = 1.692771f
(Unk9) = 0.000000f
(Unk10) = 1.632813f
(Unk11) = 0.000000f
(Unk12) = 1.707031f
(Unk13) = 9
(Unk14) = 0
(Unk15) = 19
(Unk16) = 26
Texture = Sheets\_Fire0
Frame 4
Angles = 1
Angle 0
(Unk1) = 58
(Unk2) = 29
(Unk3) = 108
(Unk4) = 127
(Unk5) = 0xB5F9D4D2
(Unk6) = 1.799699f
(Unk7) = 0xB5F9D4D2
(Unk8) = 1.674699f
(Unk9) = 0.000000f
(Unk10) = 1.835938f
(Unk11) = 0.000000f
(Unk12) = 1.873047f
(Unk13) = 9
(Unk14) = 0
(Unk15) = 19
(Unk16) = 29
Texture = Sheets\_Fire0
Frame 5
Angles = 1
Angle 0
(Unk1) = 60
(Unk2) = 31
(Unk3) = 90
(Unk4) = 108
(Unk5) = 0x7E75346F
(Unk6) = 1.805723f
(Unk7) = 0x46F0940C
(Unk8) = 1.686747f
(Unk9) = 0.000000f
(Unk10) = 1.800781f
(Unk11) = 0.000000f
(Unk12) = 1.835938f
(Unk13) = 8
(Unk14) = 0
(Unk15) = 18
(Unk16) = 29
Texture = Sheets\_Fire0
Frame 6
Angles = 1
Angle 0
(Unk1) = 28
(Unk2) = 0
(Unk3) = 111
(Unk4) = 128
(Unk5) = 0xED7E7534
(Unk6) = 1.668675f
(Unk7) = 0x00000000
(Unk8) = 0.000000f
(Unk9) = 0.000000f
(Unk10) = 1.841797f
(Unk11) = 0.000000f
(Unk12) = 1.875000f
(Unk13) = 7
(Unk14) = 0
(Unk15) = 17
(Unk16) = 28
Texture = Sheets\_Fire0
Frame 7
Angles = 1
Angle 0
(Unk1) = 29
(Unk2) = 0
(Unk3) = 92
(Unk4) = 111
(Unk5) = 0xB5F9D4D2
(Unk6) = 1.674699f
(Unk7) = 0x00000000
(Unk8) = 0.000000f
(Unk9) = 0.000000f
(Unk10) = 1.804688f
(Unk11) = 0.000000f
(Unk12) = 1.841797f
(Unk13) = 8
(Unk14) = 0
(Unk15) = 19
(Unk16) = 29
Texture = Sheets\_Fire0
Frame 8
Angles = 1
Angle 0
(Unk1) = 31
(Unk2) = 0
(Unk3) = 56
(Unk4) = 75
(Unk5) = 0x46F0940C
(Unk6) = 1.686747f
(Unk7) = 0x00000000
(Unk8) = 0.000000f
(Unk9) = 0.000000f
(Unk10) = 1.718750f
(Unk11) = 0.000000f
(Unk12) = 1.771484f
(Unk13) = 8
(Unk14) = 0
(Unk15) = 19
(Unk16) = 31
Texture = Sheets\_Fire0
Frame 9
Angles = 1
Angle 0
(Unk1) = 32
(Unk2) = 0
(Unk3) = 19
(Unk4) = 38
(Unk5) = 0x0F6BF3AA
(Unk6) = 1.692771f
(Unk7) = 0x00000000
(Unk8) = 0.000000f
(Unk9) = 0.000000f
(Unk10) = 1.523438f
(Unk11) = 0.000000f
(Unk12) = 1.648438f
(Unk13) = 8
(Unk14) = 0
(Unk15) = 19
(Unk16) = 32
Texture = Sheets\_Fire0
Frame 10
Angles = 1
Angle 0
(Unk1) = 32
(Unk2) = 0
(Unk3) = 38
(Unk4) = 56
(Unk5) = 0x0F6BF3AA
(Unk6) = 1.692771f
(Unk7) = 0x00000000
(Unk8) = 0.000000f
(Unk9) = 0.000000f
(Unk10) = 1.648438f
(Unk11) = 0.000000f
(Unk12) = 1.718750f
(Unk13) = 8
(Unk14) = 0
(Unk15) = 18
(Unk16) = 32
Texture = Sheets\_Fire0
Frame 11
Angles = 1
Angle 0
(Unk1) = 32
(Unk2) = 0
(Unk3) = 0
(Unk4) = 19
(Unk5) = 0x0F6BF3AA
(Unk6) = 1.692771f
(Unk7) = 0x00000000
(Unk8) = 0.000000f
(Unk9) = 0.000000f
(Unk10) = 0.000000f
(Unk11) = 0.000000f
(Unk12) = 1.523438f
(Unk13) = 8
(Unk14) = 0
(Unk15) = 19
(Unk16) = 32
Texture = Sheets\_Fire0
Frame 12
Angles = 1
Angle 0
(Unk1) = 31
(Unk2) = 0
(Unk3) = 75
(Unk4) = 92
(Unk5) = 0x46F0940C
(Unk6) = 1.686747f
(Unk7) = 0x00000000
(Unk8) = 0.000000f
(Unk9) = 0.000000f
(Unk10) = 1.771484f
(Unk11) = 0.000000f
(Unk12) = 1.804688f
(Unk13) = 8
(Unk14) = 0
(Unk15) = 17
(Unk16) = 31
Texture = Sheets\_Fire0
Frame 13
Angles = 1
Angle 0
(Unk1) = 59
(Unk2) = 32
(Unk3) = 53
(Unk4) = 71
(Unk5) = 0x9A3784A0
(Unk6) = 1.802711f
(Unk7) = 0x0F6BF3AA
(Unk8) = 1.692771f
(Unk9) = 0.000000f
(Unk10) = 1.707031f
(Unk11) = 0.000000f
(Unk12) = 1.763672f
(Unk13) = 8
(Unk14) = 0
(Unk15) = 18
(Unk16) = 27
Texture = Sheets\_Fire0
Frame 14
Angles = 1
Angle 0
(Unk1) = 82
(Unk2) = 57
(Unk3) = 0
(Unk4) = 18
(Unk5) = 0x1BC25031
(Unk6) = 1.871988f
(Unk7) = 0xD1BC2503
(Unk8) = 1.796687f
(Unk9) = 0.000000f
(Unk10) = 0.000000f
(Unk11) = 0.000000f
(Unk12) = 1.515625f
(Unk13) = 8
(Unk14) = 1
(Unk15) = 18
(Unk16) = 25
Texture = Sheets\_Fire0
Frame 15
Angles = 1
Angle 0
(Unk1) = 82
(Unk2) = 58
(Unk3) = 18
(Unk4) = 37
(Unk5) = 0x1BC25031
(Unk6) = 1.871988f
(Unk7) = 0xB5F9D4D2
(Unk8) = 1.799699f
(Unk9) = 0.000000f
(Unk10) = 1.515625f
(Unk11) = 0.000000f
(Unk12) = 1.644531f
(Unk13) = 9
(Unk14) = 0
(Unk15) = 19
(Unk16) = 24
Texture = Sheets\_Fire0
ID = fire
(Unk1) = 0
(Unk2) = 1.875000f
(Unk1) = 0
And for the curious, here are the animation IDs for SPRITES\LEMMINGSHI.SPR:
Animations = 15
Animation 0: ID = bash
Animation 1: ID = block
Animation 2: ID = build
Animation 3: ID = climb
Animation 4: ID = dig
Animation 5: ID = drown
Animation 6: ID = explode
Animation 7: ID = fall
Animation 8: ID = flip
Animation 9: ID = mine
Animation 10: ID = shrug
Animation 11: ID = float
Animation 12: ID = umbopen
Animation 13: ID = walk
Animation 14: ID = cartwheel
Sorry to leave you guys hanging, but I wanted to get through all the
other file formats first before looking into the .LVL format. And this post documents the last of those, the .JBF file.
There's only one of these: TEXTURES\SHEETS\PSPBRWSE.JBF
Turns out this isn't actually a Lemmings Revolution file. Have you ever been browsing a ZIP file or something that you made and noticed
that mysterious thumbs.db file that seems to have come out of nowhere? Well, this is almost exactly the same thing. The .JBF files are, or at one point were, produced by
Paint Shop Pro to accelerate file browsing. They include thumbnails for images in a directory and presumably some other information on the file such as their dimensions and formats. I didn't look into it since I didn't really care--I was too anxious to rip it open and see if we could get a candid glimpse of some pre-release material that they never intended for the end user to see.
Well... not so much. The file appears to be recent as of the time the game was packaged for release--it contains thumbnails for all the final image files in TEXTURES\SHEETS\ and nothing more. Ah well. I'll take what I can get. Kinda funny that we have it, though. Somebody forgot to exclude it from the CD (or rather, from the .BOX file).
File
=========================================================================
Identifier String*16 ASCII "JASC BROWS FILE" (null-terminated)
Junk Byte[0x03F0] Appears to be arbitrary, overwritten data
Files CachedFile[] Remainder of file
=========================================================================
CachedFile
=========================================================================
FilenameSize UInt32 Size of filename
Filename String Filename--ASCII, not null-terminated
AppData Byte[0x2C] Unknown data--used by PaintShopPro
ThumbnailSize UInt32 Size of thumbnail
Thumbnail JPEG Thumbnail data--expresses a JPEG file
=========================================================================
That "junk" region really does appear to just be 1008 bytes of nothing in particular. It's got some string remnants floating about, though:
- D:\lrpc\Textures\Sheets\
- 168)
- down the SHIFT key to add to the selection, or the CTRL key to remove from the selection.
- Magic Wand
- chase the li
- nsed vrsion. You are on day 7 of your 30 day evaluation period.
- DRIVE 2l: 256 x 255 x 256 - (67
And the thumbnails aren't even all that good-looking. They're JPEGs with some pretty terrible compression going on:
So the guy I was working with on the compression algorithm was able to locate a name for the way the binary trees are stored as lists of numbers:
canonical Huffman code. The article even uses the list 2, 1, 3, 3 as its example. (-:
Attached to this post is a new version of the LRZ utility with a working compressor, but it's slow. It's doing about the least efficient search possible for dictionary matches and while it's a well-traveled road speeding that up, it's not one I'm terribly familiar with. Fortunately, there's just one little function in the program that's imposing a bottleneck, so making that more efficient will make the entire program run faster.
The encoder does not make use of the binary trees. I'm not prepared to implement an algorithm that uses them; not without weeks of studying it.
It also occurs to me after examining the multi-language text strings that this game was at one point likely to have been in development for the Sony Playstation. I remember reading about how there was a PC demo for the game and Sony made the decision that the game would not see a PC release... well, enter Talonsoft to do the publishing work. I think that self-playing tutorial really existed, but nowadays there's no triangle button to exit out of it.
LEVELMAP.DAT file format:
"String 112
EN = Click and hold on the balloon^to speed up time"

this possibly explains something I've been wondering about (I thought it was a glitch)...
if you hover over the balloon notice the cursor changes. And If you try to scroll with right mouse button when your over the balloon, it doesn't work and your mouse moves like when your on top of the entrance (and you change the RR instead of scrolling)
[it makes a little more sense after reading that they apparently changed quite a bit before the game's release especially if they were gonna make it for the playstation] but clicking on the
balloon to speed up? I'm glad they changed that.
I would
love to see that self playing tutorial

in the instruction booklet (which I have since lost...) there's a complete walkthrough for the level "Now Your stalking"
While I'm at it, the .BOX format (with some revisions since the time ccexplore documented it):
File
==============================================================================
Identifier String*6 ASCII "LEMBOX"
NameCount UInt32 Number of filename strings *
NamesSize UInt32 Size of filename data
Names Filename[] NameCount elements within NamesSize bytes
OffsetCount UInt32 Number of file offsets *
Offsets UInt32[] Offsets of files from the beginning of the BOX
SizeCount UInt32 Number of file sizes *
Sizes UInt32[] Lengths of packed files
Data Byte[] Remainder of file--packed file data
==============================================================================
* NameCount, OffsetCount and SizeCount must all match
Filename
==============================================================================
NameSize UInt32 Size of the filename string
Filename String NameSize bytes--ASCII, not null-terminated
==============================================================================
It's worth noting that there is no implied directory structure within the .BOX file. All filenames have their full paths prepended, which is rather inefficient use of storage space...
And last but not least, I've compiled a set of documents for all file formats up to this point in the thread, as well as information on the .BMP compression algorithm and naming convention.
The .LVL files are going to be the most complex, so I'll be starting another thread for those to work out the details. This thread should be reserved for merely documenting the format once it's figured out.
Attached to this post is a ZIP file containing the documents in question.
[edit: here, I updated two punctuations in my reply above, may be that better portraits my confusion after reading your post. If that's still "trolling" then whatever]
Sure. I didn't for a minute think that you wasted my time
on purpose. All I was expressing was that time was wasted when I tried in vain to figure out what subtle errors need to be addressed in the original post. This is why it was only a

response and not a

response. I mistakenly thought something needs to be fixed in my original post when you mentioned you have revisions. Clearly this wastes your time too so sorry about that.
While exporting all of the .BMP files to, well, real .bmp files, one of them came back with an error: TEXTURES\MODELS\TELEPORT_FX\~SHAFT.BMP
Upon investigation, I found that it had a 3 for that mysterious value in the chunk header, unlike all the other files which had a 4. When it was 3, the chunk was uncompressed, meaning the chunk data in total was 5 bytes larger than the data it was representing.
No other values appeared in that field across all the .BMP files in the game. Additionally, all of the .BMP files are encoded in the chunked format; none of them are already Windows Bitmap files.
Here is the new document to reflect this:
Lemmings Revolution .BMP File format
-Decompressed data represents a Windows Bitmap file
File
=============================================================================
ChunkNum UInt8 The number of chunks in the file
Chunks Chunk[] The data chunks
=============================================================================
Chunk
=============================================================================
Header ChunkHeader Describes how the chunk is encoded
RawData Byte[] Only if Compression = 3 -- UnpackedSize bytes
Stream ROLZStream Only if Compression = 4
=============================================================================
ChunkHeader
=============================================================================
PackedSize UInt16 The total size of this chunk, including the header
UnpackedSize UInt16 The size of the data that this chunk represents
Compression UInt8 Compression type: 3 = none, 4 = ROLZ, else = bad
=============================================================================
ROLZStream
=============================================================================
RawTree BinTree Binary tree for raw byte counts
LengthTree BinTree Binary tree for distance/length lengths
DistanceTree BinTree Binary tree for distance/length distances
BitStream Byte[] Remainder of chunk
=============================================================================
BinTree
=============================================================================
The lower 4 bits of the first byte indicates how many additional values need
to be read from the input. If the value is 0, no additional input is needed
as the binary tree will not be used. If it's greater than 0, then add 2 to it
and read that many more values.
The values themselves are in 4-bit increments starting with the high bits of
the byte that contained the count, followed by however many bytes are
necessary to encode the remaining 4-bit values. For each byte, the lower 4
bits are read first, followed by the higher 4 bits.
The last byte may have 4 bits of padding so that the next data begins on a
byte boundary.
=============================================================================
I went looking in that old demo of undisclosed origin, where the default language is German and only has one level: Feeling Gravity's Pull. The "email.box" file there has the Playstation button icons, the fully-translated .LTX files that made it into the final game and, get this: the LEVELMAP.DAT file is identical to the one in the final game. All level names are there--
all 103 of them. This was the oldest build of the game I've come across--it doesn't have any music even--and at that point in time apparently all of the levels were already done.
There's no telling how this all happened. They obviously had a lot of work done on it before even submitting a build as a
demo. I expect it went something like this:
- Sony/Psygnosis commissions a new 3D-graphics Lemmings game for Playstation.
- Take-Two Interactive takes the job, or possibly pitched the publisher the idea. One or the other.
- Lemmings Revolution is completed or nearly completed as a Playstation title.
- Sony, being scumbags as they are, decides the game isn't worth publishing. I mean, it's not exactly exceptional.
- Take-Two reworks the game for Microsoft Windows 95.
- Sony/Psygnosis releases a demo on their web site to see what kind of appeal the game has.
- Sony decides the game still isn't worth publishing, even for Windows.
- Take-Two Interactive contacts Talonsoft to publish it instead.
interesting. Except I read on lemmings encyclopedia that Talonsoft was a company that was bought out by Take Two during the production. In any case, I'm glad the game ended up on the PC and not Play Station for my sake.
I really don't understand why the game had so much trouble getting published and why it still has so little appeal. I guess we're just different in liking it so much.