Technical appendix · Home · Français
The game is two programs sharing one DOS session.
MAUPITI1.EXE is the game; maup.exe is
its engine.
MAUPITI1.EXE |
maup.exe |
|
|---|---|---|
| Written in | Borland Pascal | Turbo C and assembly |
| Role | Decides what happens | Does what touches the hardware or the data files |
| Handles | Commands, time, schedules, conversations, puzzles, the quiz, sympathy; which layers make up a scene and which line to say | Files and archives, image and text decoding, video, palettes and fades, music, speech playback, mouse, saves |
| Data | Interprets the game tables in record 0x2A and the state
from SAUP.MAU, once loaded |
Loads all files: .CON archives, MUS.HUF,
SND.HUF, .MAU |
How they run together:
MAUPITI.BAT starts MAUPITI1.EXE, which
goes resident and returns to DOS without playing anything.maup.exe, which installs its
services on INT 0FEh, probes the sound card and runs the
intro.maup.exe calls back into MAUPITI1.EXE,
whose main loop then runs the game until the end.MAUPITI1.EXE is in control and calls
maup.exe through 51 INT 0FEh services.So MAUPITI1.EXE loads first and maup.exe is
the process that stays running, but MAUPITI1.EXE drives the
game. For example, to say a line, MAUPITI1.EXE picks the
phrase and the character, and maup.exe builds and plays the
sound.
The details and evidence follow.
| File | Size | Notes |
|---|---|---|
maup.exe |
56,577 B | 16-bit MZ, Turbo C 1988 runtime. Owns files, video, sound and mouse. |
MAUPITI1.EXE |
76,544 B | Borland Pascal game logic with 51 INT 0FEh client stubs, run first
by MAUPITI.BAT. |
MAUPITI1.olz |
32,717 B | LZEXE LZ91 packing of the same program: it unpacks to
an identical 70,912-byte image. |
INSTALLE.EXE |
12,684 B | Turbo C installer; contains md c:maupiti,
copy *.* c:maupiti and INSERT DISK No %d. |
MAUPITI.BAT: echo off,
maupiti1, maup %1.
maup.exe layout
(verified)e_cparhdr = 0x80, so the image starts at file
0x800 = EA 0x10000. CS:IP =
0000:0000, SS:SP = 11C4:00E6, 444
relocations.dseg is image paragraph 0xA42 (EA
0x1A420); the stack is paragraph 0x11C4 (EA
0x21C40).0, 53, 84, 159, 2DB, 493, 5FA, 6F0, 742, 7AB, 805, 8E8, 968, 96C, 97F, 9DF, 9E3, 9E9, A1A, A2F, A31, A34, A3B, A3E.
They are ordinary multi-segment program segments. Nothing in the file
shows an overlay manager or overlay data.The X Web, - www.lankhor.net.push bp / mov bp,sp: 160 raw
55 8B EC matches.INT 21h: 67 CD 21 sites (verified). The
per-AH breakdown from earlier work is unverified.0x10102: C startup calls main at
0x53:0 = _main EA 0x10530, which
calls 0x53:6 = Game_Main EA
0x10536.Game_Main first probes ports
0x210-0x260 for a Sound Blaster with
Snd_ProbeSbDsp EA 0x107FC (reset at base+6,
expects 0xAA at base+0xA). It then stores the result in
bSoundCard (DS:F6).0x105C0-0x105F2: stores
ds:0xDA = 0x5000, then makes six far init calls. The last
is 0x6F0:4 = Font_LoadCharset EA
0x16F04, which runs the intro.0x105F7: publishes maup.exe's DS at
0000:03C4.0x10603-0x10617: sets
IVT[0xFE] to 0x53:0xF8 with direct stores.
Segment 0x53 is relocated.0x10618: loads DS from
0000:03C6 and jumps to 0x84:0x3CB = EA
0x10C0B, which does call far [0000:03C8] into
MAUPITI1.The handler is in maup.exe at 0x53:0xF8 =
EA 0x10628, just after a
push bp / mov bp,sp at 0x10625.
0000:03C4, sets
bInInt0FE, and jumps to
0x10653 + (AX-1)*8.call far target / jmp common_exit.
Exit at 0x107E8, then iret at
0x107FB.| Svc | Target EA | Name | Svc | Target EA | Name |
|---|---|---|---|---|---|
| 02 | 0x15A38 |
Vid_DrawTextLines |
1A | 0x123F9 |
Con_LoadRec22Images |
| 09 | 0x157C3 |
Txt_DrawIndexed |
1C | 0x1135D |
Vid_ArenaAlloc |
| 0A | 0x11A20 |
Ui_DrawWidget |
23 | 0x11F39 |
Save_WriteGame |
| 0B | 0x11E12 |
Save_LoadGame |
28 | 0x141D9 |
Mau_LoadFiles |
| 17 | 0x1428C |
Ui_CaptureSpriteSheet |
2B | 0x148BC |
Demo_Init |
| 19 | 0x123D4 |
Con_LoadRecordPlus1E |
others | see symbols.tsv |
SvcNN if unidentified |
The main groups read from their code:
| Services | Names | What they do |
|---|---|---|
| 03, 04, 05 | Mem_PeekByte, Mem_PeekBE16,
Mem_PeekBE32 |
read through a far pointer, swapping from big-endian |
| 1F, 20, 21 | Mem_PokeByte, Mem_PokeBE16,
Mem_PokeBE32 |
the same for writes |
| 01, 06 | Mem_SumBytes, Mem_SumBE16 |
sum a table's first N entries |
| 26 | Table_EntrySize |
difference of two adjacent big-endian words |
| 0F | Table_GetEntry |
table lookup; MAUPITI1 uses it on the rec
0x2A buffer |
| 15 | Rand_Range |
value between two bounds, from counter DS:63F |
| 0D, 0E, 1D, 27 | Vid_ClearRect, Img_Draw,
Vid_CopyRect, Vid_DrawLine |
drawing (the rectangle and line roles are inferred) |
| 18, 1A, 1B | Con_LoadRoom, Con_LoadRec22Images,
Con_LoadRec23 |
load a room, a portrait, the map and small portraits |
| 1E | Speech_Say |
compiles and plays a spoken line: see Speech |
| 14 | Svc14 |
magnifying glass: redraws an area at double size with sprite
0x27 sub 7 (inferred) |
| 22 | Svc22 |
recolours the frame for the room, with table 0xC9
(inferred) |
| 2C, 2D | Snd_PlayMusic, Snd_Stop |
music (Snd_Stop is inferred) |
| 31, 33 | Time_DelayShort, Time_Delay |
delay loops |
Con_LoadRoom is service 0x18.
Pal_TimeOfDayB (service 0x2A) picks a room
palette by hour; File formats, scenes and
palettes has the whole palette system. Pal_TimeOfDayA
(service 0x29) has the same hour test.
So MAUPITI1, a little-endian Pascal program, reads the
game's big-endian data through these services.
maup.exe
calling itself through INT 0FEhCD FE occurs seven times, but 0x13B8F is
the operand of the jmp at 0x13B8E. The six
real sites:
| EA | Service | Block size |
|---|---|---|
0x12194 |
0x24 |
0x1C |
0x121A9 |
0x0A |
0x18 |
0x12269 |
0x09 |
0x38 |
0x12363 |
0x08 |
0x10 |
0x1238A |
0x1D |
0x10 |
0x123CB |
0x24 |
0x1C |
| Slot | Writer | Contents |
|---|---|---|
0000:03C4 |
maup.exe |
maup.exe DS |
0000:03C6/03C8/03CA |
MAUPITI1 EA 0x20B80 |
its DS, then return IP+9 and CS |
0000:03F8/03FA |
maup.exe |
IVT[0xFE] |
MAUPITI1.EXE
(verified with ndisasm)EA = file + 0xEA00; header 0x1600 B; 1,378 relocations;
entry EA 0x1EF37. Segments: 0 (main code),
0xF21 (one Keep routine), 0xF23 (library and
service stubs), 0x10B8, 0x10F1 (Borland
runtime), 0x114C (data).
Main EA 0x1EF37 initialises the runtime,
then calls Mailbox_Publish EA 0x20B80. That
stores its DS, return IP + 9 and CS at
0000:03C6-03CB.Dos_Keep(3) at EA
0x1F210 (INT 21h AH=31h). The program stays
resident and the batch file starts maup.exe.maup.exe sets its services up, then does
call far [0000:03C8]. Return IP + 9 is EA
0x1EF4D, the instruction after Dos_Keep, so
Main carries on inside maup.exe's
process.Main computes buffer pointers, then calls
Game_LoadAssets EA 0x12722 and
Game_InitOnce EA 0x186D9, then repeats
Game_MainLoop EA 0x1EBC8 until
DS:131 is non-zero.So MAUPITI1.EXE holds the game logic and calls
maup.exe for files, video, sound and input.
mov ax,N / mov cx,bp / add cx,6 / int 0FEh, numbered 1..51.
The other five CD FE hits are displacements of
mov [bp+di-0x133],ax, starting at 0x17D6E.
Call counts per service are in symbols-maupiti1.tsv;
the IDA name Maup_Svc13 (7 callers) is decimal, so service
0x0D.INT 21h: 21 sites. One is Keep; the
rest are in the Borland runtime segment. Its vector calls target
00h, 23h, 24h and
3Fh, so none set vector 0FEh.0x20F10, 0x20FE8,
0x21154, 0x2116D, 0x21189 and
0x211A4. The file INT 21h code at
0x2136E and up has no far caller, so game code doesn't use
it. All game file access goes through services.in, out, INT 10h or
INT 33h, and one iret at 0x20FD5.
Its three in/ins hits and the
CD 33 bytes are misaligned decodes or operands. The two
rep movsb sites are runtime code, so nothing copies a
handler.G3.CON.Service 7 returns a far pointer to MAUPITI1's
DS:166, the base of a 0x99B-byte state block.
Game_MainLoop EA 0x1EBC8 fills it from
SAUP.MAU (service 0x28), and restores from a
save with service 0x0B. So SAUP.MAU is
the starting game state, followed by 8 more bytes.
| DS: | SAUP.MAU offset |
Start value | Role |
|---|---|---|---|
166 |
0 | 26 | current room number; its .CON record is this minus
1 |
168 |
2 | 20 | time in half-hours, so 10:00: the palette code uses it as hours (File formats, scenes and palettes) |
16A |
4 | 0 | passed with the time; high word or day count (inferred) |
16C |
6 | 79 | condition, 0-99; 20-point steps choose "Lessivé" to "La pêche" |
16E |
8 | 50 | hidden sympathy score, lowered by Game_AddSympathy (see
Game logic) |
Game_MainLoop loads the state and calls
Room_Enter EA 0x141CB, then runs
Game_Turn EA 0x1E220 until DS:132
or DS:134 is set. If DS:134 was set, it runs a
closing sequence that draws a class 6 string. Main_Body
repeats Game_MainLoop until DS:131 is set.
Game_LoadAssets EA 0x12722Con_LoadRecord EA 0x20691 calls service
0x19 with record - 0x1E:
| Record | Sub | Pointer (DS:) | Size used in layout |
|---|---|---|---|
0x28 |
0 | A8 |
banks 1-7 of string sizes, 3,178 B |
0x29 |
0 | A4 |
banks 1-7 of text, 45,410 B |
0x2A |
0 | AC |
0xA39E = 41,886 B |
0x27 |
0 | E4 |
|
0x27 |
7, 8 | F8, 104 |
|
0x27 |
5, 1 | BC |
loaded for further processing |
0x27 |
6 | 100 |