Technical appendix · Home · Français
| File | Size (B) | Format | Payloads |
|---|---|---|---|
G1.CON |
295,406 | .CON |
60 (20 records) |
G2.CON |
70,513 | .CON |
15 (5 records) |
G3.CON |
114,229 | .CON |
18 (4 records) |
G4.CON |
180,769 | .CON |
53 (5 records) |
G5.CON |
54,978 | .CON |
93 (2 records) |
G6.CON |
63,860 | .CON |
16 (4 records) |
MUS.HUF |
31,782 | stream file | 29 |
SND.HUF |
4,478 | stream file | 28 |
SAUP.MAU |
2,467 | raw | 1 |
DEMOFR.MAU |
895 | raw | 1 |
HNF.HUF |
4,717 | not game data | see section 4 |
That is 40 .CON records, 255 .CON payloads
and 57 .HUF streams (312 together, 952,709 B), plus the two
.MAU files.
Files named by maup.exe:
G1-G6.CON, SAUP.MAU,
DEMOFR.MAU, MUS.HUF, SND.HUF,
SAUVEMAU.00n, and conditionally
G7.CON (below).
.CONCon_ReadRecord EA 0x13F9F (verified)Arguments, pushed first to last: record, sub-index, destination segment, destination offset.
Con_OpenArchive EA 0x140EC.wConArchiveSentinels EA 0x1AE64: six
0xFFFF-terminated groups of record numbers. The group
number selects ConOfs_Disk1-6 (EA
0x1ADAC, 0x1AE00, 0x1AE18,
0x1AE2C, 0x1AE44, 0x1AE50); the
position in the group selects a dword in that table.base + 4*sub, then reads 8 bytes into
ConRecIndexBuf EA 0x1AEC0.base + start, and reads
next - start bytes (low words) to the caller's buffer.The groups are:
0,1,2,4,5,6,8,9,B,C,D,E,12,13,14,17,18,1A,1C,1E /
7,A,10,15,1B / 27,28,29,2A /
21,22,23,2B,2C / 20,1F /
3,F,19,1D.
Con_OpenArchive (verified)wConRecordToArchive[record] EA
0x1AD52: slot (n-1)*7 of
aConNames EA 0x1AEC8. The open is
AX=3D80h.bConDiskLayoutVariant EA 0x1AA92 is set by
Sys_DetectMedia EA 0x10842 from
INT 21h AH=1Bh: media byte F9h gives 1,
F8h (hard disk) gives 2, anything else gives 0.bConRecordDiskMap0/1 EA 0x1ACF8 /
0x1AD25; on a mismatch Con_PromptDisk EA
0x128F7 runs with AX = 8, 0x306
or 6.G7.CON: with variant 0, record
0x20, current disk 2 and a sub-index outside 4..9, the
digit of the G5.CON name is patched to 7 at
0x14185. No G7.CON is in this folder. It
presumably belongs to a low-density floppy set
(inferred), and a hard-disk install never takes this
path.0x141CF).4-byte entries, N = first entry / 4,
payload[k] = blob[base + start[k] : base + start[k+1]]. All
archives tile exactly (selftest); 39 payloads are empty,
always the last slot of a record.
| Record | Contents | Evidence |
|---|---|---|
0x27 sub 2 |
full-screen picture | verified: renders as a sailboat at sunset |
0x27 subs 9, 10 |
codec streams, music-like | verified codec; loaded by Huf_LoadRec27Music EA
0x1781C |
0x27 subs 0, 1, 3-8 |
frame parts and interface sprites, such as the title and the magnifying glass; exact roles not established | verified load |
0x28 sub 0 |
1,589 big-endian u16 string sizes, in 7 banks | verified |
0x29 sub 0 |
5-bit packed game text, in 7 banks | verified: see Text and fonts |
0x2A sub 0 |
516-entry table of game-logic data, below | verified structure |
0x00-0x1E subs 0, 1 |
rooms: sub 0 is the background, below | verified for sub 0 |
0x22 |
conversation background and the nine character portraits, loaded by
Con_LoadRec22Images |
verified |
0x2B sub 0 |
speech samples: 644 big-endian offsets, then 4-bit delta audio. See Speech | verified |
0x2C sub 0 |
speech phrases: 460 big-endian offsets (450 used), then 16-bit phoneme words. See Speech | verified |
Img_Decode EA 0x14930 (verified
structure)Far arguments: source segment, source offset, destination segment, x, y.
u8 kind; u8 tileCount
if kind == 0: 16 big-endian palette words, 0RGB with 3 bits per channel; no transparency
else: u8 transparent colour; u8 unused
each tile: be16 lenA, lenB, x, y, flags, w-1, h-1, then its data
flags high byte is the scan mode, dispatched at
0x14B91 + 3*mode, 0..18.lenA) and a run-length nibble list (lenB) in
a work area at destination segment +0xFA0, just past the
64,000-byte page.flags bits 0 and 1 mark those lists as themselves
run-length packed.rec27_sub02 has a 16-colour palette and four tiles that
cover 320×200 exactly:

tools/decode_image.py
ports all 19 modes. Run in an emulator, the game's own routine produces
the same page for all 439 images in the game (tools/verify_image.py).
Other image records:
| Record | Contents |
|---|---|
0x1F |
object icons, in the object list's order |
0x20 |
timed scene overlays (below) |
0x21 |
book, newspaper, calendar and scroll pages, with their backgrounds; subs 6 and 7 are the two halves of the pirate inscription |
0x22 |
conversation background and character portraits; the palette appears
to be the one in record 0x23
(inferred) |
0x23 |
island map and small portraits |
0x27 |
title, frame parts and interface sprites |
0x18 Con_LoadRoom EA
0x12640 (verified)The record number is the room number minus 1:
MAUPITI1 passes DS:166 - 1, and the
screenshots confirm it (room 26, the cabin, is record
0x19). Sub 0 holds two 16-word palettes at +0
and +0x20, then a normal image at +0x40 with
its own palette at +0x42, drawn at (0,0). Header sizes tile
exactly: for record 0x1A, 21 tiles fill the remaining
11,418 bytes. Six rooms by day:

A scene is drawn in layers by Room_Enter
MAUPITI1 EA 0x141CB; tools/render_scene.py
ports it, and scenes/ has every
room. On all four screenshots, only the mouse pointer differs in the
picture area (49-61 pixels each). On the left, the screenshots; on the
right, the renderer:

0x129 (count per room)
and 0x12A (zone). State DS:92F + 11 * room + i
picks the open image (sizes in 0x12B) or the closed one
(0x12C). A zone is skipped if its flag in
DS:7B5 is clear, unless Zone_Alias EA
0x1079F maps it to another zone.0xC0 and
0xC1. State DS:8AE + 2 * index picks the
image: zero uses table 0x132, otherwise 0x133.
Room 30 pairs its bénitiers, and also draws entries of size 0.Scene_DrawTimedOverlays EA 0x10479: tables
0x11C (count per room), 0x11D and
0x11E (first and last time), 0x11F (sub of
record 0x20). These draw the bassin's tides and reflection,
the bodies on the beach and the jetty, and the changes to rooms 6 and
8.Sub 1 holds those images in order, each a normal
image: sizes from 0x12B, 0x12C,
0x132, 0x133, 0x134, then 51
bytes used only by the non-VGA paths. This adds up exactly on the rooms
checked (for example 3,146 + 51 = 3,197 for record 0x19).
Table 0x134 holds images used when an object is taken.
Record 0x1E, which the ending loads as "room 31", is a
sunset over the island with no room data of its own.
Palette words are 0RGB, 3 bits per channel. They never
reach the VGA directly. tools/decode_image.py
implements this, and it reproduces the 16 colours in screenshots/ exactly, on all
four.
Step 1: which palette. EA 0x145D4
stores three in DS:79E, 7BE, 7DE,
and Pal_TimeOfDayB EA 0x147C3 picks by
hour = (time / 2) mod 24:
| Hours | Palette | Record offset | DS: |
|---|---|---|---|
| 8-17 | day | +0x42 |
79E |
| 6-7, 18-19 | dawn and dusk | +0 |
7BE |
| 20-5 | night | +0x20 |
7DE |
Step 2: channel tables. EA 0x143F0
converts each channel through a table at DS:676 to a 6-bit
DAC value. The tables differ per channel, and 6 and 7 are the same:
| Value | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
|---|---|---|---|---|---|---|---|---|
Red, DS:676 |
0 | 3 | 17 | 31 | 44 | 58 | 63 | 63 |
Green, DS:67E |
0 | 7 | 18 | 30 | 43 | 54 | 63 | 63 |
Blue, DS:686 |
0 | 4 | 13 | 29 | 41 | 60 | 63 | 63 |
Step 3: register order. Palette entry k is
written to DAC register DS:68E[k], which reverses the four
bits: 0 8 4 12 2 10 6 14 1 9 5 13 3 11 7 15. So
pixel value i shows palette word
reversed(i).
Step 4: fade. Colours are written at one site, EA
0x1453E. Each step blends
(from * a + to * b) >> 6 per channel, with
a falling from 63 and b rising from 1, over 63
steps. "From" or "to" can be cleared to black (DS:647 = 1
or 2).
| Part | Checked by |
|---|---|
| Day palette, channel tables, register order | All four screenshots, exact |
| Dawn, dusk and night palettes | Code only: the screenshots are all at 10:00 |
| Fade | Code only |
Other video modes (DS:492 not 5) |
Not used by this path; not studied |
DOSBox shows a 6-bit value v as
(v << 2) | (v >> 4). That's in screenshots/' colours, and isn't
part of the game.
0x2A: the game data table (verified structure)Table_GetEntry EA 0x15354 (service
0x0F) treats the record as big-endian sizes. The first
word, 1,032, is the table's own size, so 516 entries. On first use, EA
0x153BD makes them cumulative in place. The sizes total
41,895, 10 bytes more than the record, so the final entry runs past its
end.
Entries are small arrays of bytes and big-endian words, read with the
Mem_Peek services. Almost none are images. Entries 199 and
200 are 32-byte palettes, and requesting them has a side effect at
0x153E4/0x15405 that also copies palette data.
rec2a-entries.tsv
lists every entry, with its callers where the index is a constant (115
entries; others are computed). Game logic
explains the tables behind dialogue, actions, objects and the ending;
others are still unidentified.
.HUFHufStreamTab EA 0x1CC60 holds the
cumulative u32 offsets; there is no directory in the files.
MUS: 30 boundaries, 29 streams
SND: 29 boundaries, 28 streams
Huf_LoadFile EA 0x1761D opens the files
with AX=3D80h. When bSoundCard
(DS:F6, EA 0x1A516) is zero,
the selector is first replaced by HufStreamRemap[selector]
(word table at EA 0x1CD5A): identity up to
0x14, then 0x15→0x17, 0x16→0x14,
0x17→0x17.
Each stream starts with a u32 length and uses the codec in The compression codec. All decode byte-exactly.
SND:
{u16 ver; u16 count; u16 dataOfs = 6+9*count; count × 9-byte name; count × 56-byte record};
25 distinct instrument names.MUS: 28 event scripts with a 70-byte header
(u16 0x04F0 at +0x24, u32 body length at
+0x2A); stream 28 is an Amiga IFF 8SVX sample..MAU:
Mau_LoadFiles EA 0x141D9 (verified)SAUP.MAU: reads 0x9A3 bytes to the
caller's buffer. The last 8 bytes are copied to DS:2835. It
is the starting game state: see The two
programs, and Game logic for the
fields in use.DEMOFR.MAU: reads 0x37F bytes to
DS:AE6 (EA 0x1AF06).DEMOFR.MAU is u8 + 149 six-byte records.
Demo_Init EA 0x148BC multiplies byte 0 by 18;
the consumer at 0x137FC steps by 6. The records hold
mouse-style data read near 0x135BB (x and y words at +2 and
+4). The reading as a mouse path is inferred.
HNF.HUF: not game
datamaup.exe never names it. Its header is ROT-13 text:
Jeu telecharge sur : The X Web
Webmaster : Fred
E-mail du webmaster : fred@lankhor.net
URL : http://www.lankhor.net
The rest resembles SND.HUF but isn't a copy: the shared
suffix is 216 B. This looks like release-group metadata, like the
trailer on maup.exe.
Previous: Game logic · Next: The compression codec · Technical appendix · Home