Note: I called this method of encoding/compression Dizio-Encoding because it's a sort of text substitution based on a fixed dictionary table. Isn't really a compressor because the efficiency is minimal (at best from 1 char we obtain 2 chars), but is good to obfuscate text. This method is also used in other Westwood games (and the table is always the same) like Kyrandia2.

We have two alphabetic tables (can be found into main .exe file of the game), the MainTable of 16 chars, and a SubTable that is an array of 16 strings made of 8 chars each.


MainTable = " etainosrlhcdupm"
SubTable = (
"tasio wb",
" rnsdalm",
"h ieoras",
"nrtlc sy",
"nstcloer",
" dtgesio",
"nr ufmsw",
" tep.ica",
"e oiadur",
" laeiyod",
"eia otru",
"etoakhlr",
" eiu,.oa",
"nsrctlai",
"leoiratp",
"eaoip bm"
)


To decode the text, we take a byte at time in the original string.
If bit 7 is set, we must decode the char to obtain two chars, else if the byte value is < 32 the next byte is an "high" char (usually international letters like accent chars and similar) else we have a normal char.
The spec for the encoded char is the following:

+---+---+---+---+---+---+---+---+
| 1 |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+
    \_______________/\__________/
            |             |
       FirstIndex     SecondIndex

Bits 6,5,4,3 (4bit) are the first index, while 2,1,0 (3bit) are second index.
Now, FirstIndex index the char in the MainTable and give the first char, SecondIndex index the char in the string of the SubTable, but the string is indexed by the FirstIndex.
Example:

Original String (hex value): 52 6F CA A9 21
52, bit 7 is not set, so we have a letter, in this case R
6F, bit 7 is not set, so we have a letter, in this case o
CA, bit 7 is set, so we must decode:
CA in binary is 11001010, so the FirstIndex is 1001=9 and SecondIndex is 010=2.
From MainTable we get the first char that is l From SubTable we get the string index by FirstIndex that is " laeiyod", then we get the second char using the SecondIndex value and we get a.
So, from the byte CA we get the chars la.
A9, bit 7 is set, so we must decode:
FirstIndex is 0101=5 and SecondIndex is 001=1, so the first char is n and the second char is d (getting from " dtgesio"), the two chars are "nd" 21, bit 7 is not set, so we have a letter, in this case !

At end of the decoding process we obtain the final string: Roland!

When there is an "high char" to decode (byte value < 32), we have the possibility:
- byte value is 27, so the next byte is the "high char" and we must add 127 to get the real value.
- byte value is 13, we have a "carriage return" (\r) value
- other values are unknown to me

Decompression routine (in Pascal):
const
  MainTable = ' etainosrlhcdupm';
  SubTable: array[0..15] of string[8] = (
    'tasio wb', ' rnsdalm', 'h ieoras', 'nrtlc sy', 'nstcloer', ' dtgesio',
    'nr ufmsw', ' tep.ica', 'e oiadur', ' laeiyod', 'eia otru', 'etoakhlr',
    ' eiu,.oa', 'nsrctlai', 'leoiratp', 'eaoip bm');
var i: Integer;
  c, c1, c2: byte;
  ch1, ch2: char;
begin
  Result := ''; //result is a string variable - default return value of a function
  i := 1;
  while (i <= length(s)) do
  begin
    c := byte(s[i]);
    if (c and $80) > 0 then //bit 7 set
    begin
      c1 := ((c shr 3) and $0F); //c1 = bit 6,5,4,3
      ch1 := MainTable[c1 + 1]; //c1+1 because pascal string start from 1 not 0
      c2 := (c and $07); //c2 = bit 2,1,0
      ch2 := SubTable[c1][c2 + 1]; //c2+1 because pascal string start from 1 not 0
      Result := Result + ch1 + ch2;
    end else if (c < 32) then
    begin
      if (c = 27) then
      begin
        inc(i);
        c1 := byte(s[i]);
        ch1 := char(127 + c1);
        Result := Result + ch1;
      end else if (c = 13) then Result := Result + '\r'
      else Result := Result + '§'; //unknown value
    end
    else Result := Result + s[i];
    inc(i);
  end; //while
end;

Here's the complete Decoding/Encoding routine in Pascal: