Game logic

Technical appendix · Home · Français

How the player acts on the game, and what decides which sentence appears. Most of the game's content is data in G3.CON record 0x2A, so the lists are generated into logic/ by tools/game_logic.py.

File Contents
logic/dialogue.md Every answer for each character and question, with what changes it
logic/actions.md Per room and zone: each verb's reply, objects, containers
logic/unlocks.md What unlocks each conversation topic
logic/events.md Messages and scene changes by time
logic/schedule.tsv Where each character is, every half-hour
logic/rooms.md Room exits and travel costs
logic/quiz.md The final questionnaire, with its answers
logic/documents.md Every readable object with its pages, the newspapers, and the piano's tunes

Coverage. The tables are extracted exactly as the code reads them. Reactions written directly in code are only partly listed (see "Scripted reactions"), so a sentence missing from logic/ isn't proof that it never appears. Room names are matched from exit labels and string order, and aren't stored in a table.

The player's commands

Game_Turn EA 0x1E220 waits for a choice, then Cmd_Dispatch EA 0x1D9D8 runs it.

Menu (DS:40) Label Choices
0 Fic (inferred label) 9 characters: if present, Accoster (talk) or Suivre (follow). Item 10 opens another screen (0x119B8), not yet read
1 Dep up to 6 exits for the room, from tables 6, 7 and 8
2 Invent select a carried object (up to 5 slots at DS:7A0, in hand at DS:7AA)
3 Action appuyer, attendre, dormir, fermer, fouiller, lire, manger, mettre, observer, ouvrir, prendre, regarder, sentir, sonder, soulever, tourner
4 Self se cacher, déposer, se fouiller, lire

After choosing a verb that needs a target, the player clicks the scene. Ui_PickPoint EA 0x19660 converts the click to 8×8 cells and looks up two zone sets, per room: tables 0x111 (scene zones, DS:78) and 0x112 (detail zones, DS:7A). A zone with an entry in Flag_ZoneIndex EA 0x1FCC8 exists only while its flag is set. The cell is ((x - 4) / 8, (y - 12) / 8) on the 320 × 200 screen. Each table gives, per room, a record 0x2A entry with the number of rectangles per zone (first byte: zones - 1), and the next entry holds, zone by zone, the rectangles' x0, x1 pairs then their y0, y1 pairs, in cells (Zone_Find EA 0x206ED).

Fixed behaviour of some verbs:

  • attendre: adds one half-hour.
  • dormir: only in room 26 (your cabin); adds 6 condition and advances time twice.
  • manger: only in room 2, and only when the hour (DS:68, set from the time by EA 0x1F924) is 9, 13 or 20, otherwise a refusal. Breakfast at 9 adds 7 condition and one half-hour; lunch at 13 and dinner at 20 add 14 and take an hour (EA 0x1A58C).
  • fouiller: lowers DS:16E by 1 if DS:7C is set, and by 3 if DS:137 is set; see "State".
  • se cacher: sets DS:138 where the zone allows it. While it is set, the owner of the room doesn't confront you.

Time and movement

Game_AdvanceTime EA 0x138DE advances the clock and runs what depends on it. Time starts at 20 (10:00 on the 31st), and the character tables run for 74 half-hours from there.

  • Characters follow logic/schedule.tsv exactly: table 0, room = T0[(time - 20) * 9 + character]. The player can only talk to those in the current room.

  • Travel adds table 8's value to DS:6C. The code adjusts it by (condition / 20 - 2) * 25 / 100, but that integer division gives 0 for every condition value, so the adjustment has no effect.

  • Exits: values from 100 trigger a special event. "Pick on screen" exits (255) lead through a door zone (tables 0x113, 0x114, 0x116, listed at the end of logic/rooms.md).

  • Exits shown: the word at DS:A79 + 2 × (room - 1) is how many of the room's exits the Dep menu shows (Game_Turn EA 0x1E258). Scripts raise it: the rope put on the well (room 10, zone 17) sets 6 and adds dans le puits; opening Maguy's trapdoor sets 4 and adds the passage; in the well (room 16), appuyer on detail zone 6 ("Signes des temps") switches 1 and 2, adding dans le passage, but only while the stone #23 sits in the well's rock (room 10, zone 15, flag DS:7F0). Climbing back out sets it to 1 again.

  • Locks: Tbl_LockCheck EA 0x152A2 refuses a door (table 0x1B2) or a zone that opens (table 0x1B8) between two times unless one of the five carried objects matches. Lucie's room (door 4 in front of Maguy's house) is always locked without key

    15, Juste's house is locked 18:30-19:00 and from 21:30 on the 31st without key #76, and Maguy's trapdoor needs key #17.

    All are listed in logic/rooms.md.

  • Timed messages, scene changes and objects moved by the clock are in logic/events.md, such as the well flooding at 16:30, the wig in Juste's stove at 18:30, the médaillon in the fish trap at 01:30 and the decoded sheet in Roy's cabin at 02:00. Each object move runs once (flag DS:924+i). A removal that finds nothing in the container means you carry the object, and kills you.

Conversations

Dlg_Talk EA 0x1ADD4 offers a topic list. Characters are numbered 0-8: Maguy, Sue, Anita, Bruce, Roy, Chris, Bob, Anton, Juste. Marie and Lucie can be asked about but aren't in the schedule.

Which answer you get

Question Table Lookup, c = character Change key (type)
Votre emploi du temps... 1 T[slot * 9 + c] c * 40 + slot (1)
Qu'avez-vous remarqué... 2 T[slot * 9 + c] c * 40 + slot (2)
Que faites-vous là? 3 T[(time - 20) * 9 + c] c * 74 + time - 20 (3)
opinion of a person, 0-8 4 T[c * 9 + person] c * 9 + person (4)
Marie, Lucie, or one of 20 topics 5 T[row * 9 + c] c * 22 + row (5)

Values are 1-based class 5 strings (storage bank 7). A value of 0 gives a random evasive line: one of class 5 strings 141-143 for "Que faites-vous là?", and three others for "Qu'avez-vous remarqué".

An answer changed earlier takes priority: Dlg_GetOverride EA 0x18784 looks in the saved array at DS:2D2.

Which topics are available

The three lists are gated by flags in the state block. Showing certain strings or taking certain objects sets them, as listed in logic/unlocks.md.

Topics Flags Names
people and the four standard questions DS:842+i table 0x105
20 subjects DS:851+i table 0x106
time slots DS:864+i-1; the first two are always on table 0x107

A time slot appears once it is over. At each time step, Time_UnlockSlots EA 0x1F924 sets DS:864+i for i = 1 to day × 24 + hour - 10, so "6 à 7 h PM" can be asked about from 19:00. The menu reads slot k (k ≥ 2) at DS:864+k-1.

Topics are unlocked in four ways, all listed in logic/unlocks.md and run by Tbl_UnlockTopic EA 0x103B4: an answer (table 0x1BE), a message (0x1C6), reading or taking an object (0x1C2), and clicking a scene zone with any verb (0x1CB, from Ui_PickPoint). The last one is how "La chambre fermée à clef" appears: click the locked door in front of Maguy's house. The bassin's statue, the sealed crate and Marie's forced bookcase work the same way.

What changes an answer

Dlg_Answer EA 0x18A43 shows an answer with seven buttons (table 0xFE):

Button Effect
Mémoriser stores the answer: who, question and string, at DS:170-1A6
opposer confronts the character with a stored answer: 8 points if it's the statement this level expects
se souvenir shows a stored answer
donner gives the object in hand; if the character wants it (tables 0x130/0x131), +4 pressure
montrer shows the object in hand: reply from table 0x87, T[object * 9 + c]; costs 2 of DS:16E
soudoyer offers money: accepted if the amount exceeds table 10's price by 3 per refusal, +2 pressure
tabasser lowers DS:16E by 10 or 40. Won if condition is at least the character's strength (30,20,40,60,60,90,90,80,40) plus the attempt number: +1 pressure, -10 condition. Losing costs condition by the gap, at least 15

Dlg_Pressure EA 0x163A3 applies the change, using tables F = 0xCA, 0xCE, 0xD6, 0xDC, 0xE4 by question type and G = 0x1EA, 0x1EB, 0x1EE, 0x1F0, 0x1F3. A question listed in F+1 has up to three levels, and each level says which answer comes next (table F+3+2×level). To advance:

  • Opposing must match the expected type, question and string (F+2+2×level, F+3+2×level). A string of 600 in the data can never match, so those levels advance only by pressure. Otherwise it adds 8 points.
  • Pressure works on any listed question: asking adds the current pressure (DS:88), which then falls by 1.
  • The level advances when the question's points (word at DS:216+2i) plus this attempt's amount reach its threshold (G+level). Only then are the points kept, the level byte (DS:1B8+i) raised and the new answer stored at DS:2D2. A failed attempt leaves no points, and the thresholds count from the points already kept.
  • So opposer with the expected statement (amount 8, EA 0x19047) works at the first try whenever the earlier levels were also passed by opposing: no threshold in the game is above 8 × (level + 1). Opposing with anything else never helps. The "pressure >= N" in logic/dialogue.md is this threshold: pressure (DS:88) is the amount for a plain question, and it only matters for the levels marked 600, which can't be opposed.

logic/dialogue.md shows these under each answer, as → condition: new answer. Reaching a given sentence means meeting all of: the character is present at that time, the topic is unlocked, and any → condition on it is met. Sentences that aren't in a character's grid come from → lines or code.

Following (Dlg_Follow EA 0x1C5CD) tracks the character's schedule, and can fail with "Vous l'avez perdu de vue!".

Actions on the scene

Each verb has a reply table family, listed in logic/actions.md: T zones per room, T+1 zone ids, T+2 the default, T+3 the strings (Tbl_ZoneLookup EA 0x1FF5C).

Reply used When
table reply the zone is listed for this verb
default no entry; for Tbl_ZoneReply EA 0x1294C, also when the zone is already open
"not open yet" reply Tbl_StateReply EA 0x12C58, for fermer, fouiller, ouvrir, mettre

Other mechanisms:

  • Open zones: ouvrir, fermer, soulever, tourner and appuyer toggle state at DS:92F + 11 × (room - 1) + zone, redrawing the zone. Table 0x1B8 can block them by time or carried object.
  • Flag writes: tables 0x185-0x1A9, one per verb, set and clear scene flags on success (Tbl_ApplyFlags EA 0x11584).
  • Objects: prendre uses tables 0xC0-0xC3. Containers hold up to 5 objects, in the saved arrays at DS:368 and DS:5FC; fouiller shows them. Object names are table 0xC6.
  • Clues: the first time certain strings appear or objects are taken, points go to DS:88E (tables 0x1D0-0x1D5), the basis of "Vous devriez avoir remarqué x pour cent des indices".

State

DS: Meaning
166 room
168 time, in half-hours
16C condition, 0-99; below 0 triggers an event
16E hidden sympathy score, starts at 50; see "Sympathy"
7A0, 7AA carried objects, object in hand
7B5 scene and story flags; includes topic flags at 842, 851, 864
88C money
88E clue points
8AE zone and object state words

Sympathy

DS:16E is a hidden score, starting at 50. "Sympathy" is the name an online source gives it; the game's text never names it. Only three instructions touch it: the add and store in Game_AddSympathy EA 0x1F9B1, and the test in Game_AdvanceTime. It has 18 call sites, all with fixed negative amounts, so it can only fall. It isn't displayed and changes nothing else, including dialogue.

At the next time step after it goes below 0 (51 points lost), the game ends with one of two failure texts, class 6 strings 62 or 63: Maguy has you taken to Mahé, or the men lock you in your cabin.

Action Loss Condition Site
tabasser 40 anyone else is in the room 0x1939B
tabasser 10 only the two of you (DS:7C = 1) 0x19390
fouiller 3 the room's owner is there (DS:137) 0x1A1A8
fouiller 1 someone else is there 0x1A19D
montrer 2 each time 0x191C9
soudoyer 1 each offer, accepted or not 0x19236
suivre 2 the person notices you, and turns on you 0x1CE55
suivre 2 you tail the same person again ("Encore vous?") 0x1AFAE
being in someone's own room with them 1 "Vous vouliez me voir?" 0x1B00B
the same 2 if it's the last person you tailed ("Toujours dans mes pattes!") 0x1AFF6
the same, from 23:00 to 08:00 1 or 2 "Ce n'est pas une heure pour déranger." 0x1AF5C, 0x1AF47
leaving something open 2 per item someone has been in the room since you left; they close it 0x19CCD
taking money from an object list 1 0x160D8
taking an object with your hands full 2 from a close-up 0x160B5
dropping an object 1 away from its own place 0x1D64B

Owners' rooms come from the array in Dlg_Talk: Maguy 3, Sue 5, Anita 7, Bruce 20, Roy 19, Chris 21, Bob 25, Anton 27, Juste 8. The room check runs from the turn loop, so staying can cost more than once (how often wasn't counted). Hiding avoids the confrontation, but not the fouiller penalty.

The losses are applied before the outcome, so a beating costs the same whether you win or lose. Plain accosting, questions, opposer, donner and Mémoriser cost nothing.

Two more call sites, 0x1AFCD (3) and 0x1B038 (2), need Dlg_Talk to be called for a room's owner with DS:137 clear. The only such call site checks that it is set, so they look unreachable.

Tolerance, for reference: one beating with a witness leaves 10, and a second one ends the game. Beating people alone, you can do it five times and sit at 0; the sixth ends it.

The ending

Tourner on zone 31 of room 30 starts the check in Script_Hook EA 0x1767F. It needs the 5 bénitier on the first plate and the 3 bénitier on the second, each holding 2 volumes (DS:AF7 = 0xA6, DS:AF9 = 0xA8, DS:AF1 = 2, DS:AF3 = 2). Zone 31 exists once the opened médaillon is in the ring.

Quiz_Run EA 0x15450 then asks 7 chains of questions from table 0x1F9. Questions in 0x1FB go on to 0x1FC if right. Any wrong answer clears the success flag, so the percentage in class 7 string 126 is only shown on failure, and play continues. Success plays class 6 string 102 and sets DS:132. The winning path is worth exactly 100 points. See Walkthrough.

Scripted reactions

Script_Hook receives (event, room, zone, item), with these events:

Event From Event From
1 ouvrir 9 appuyer, scene zone
2, 3 tourner, detail and scene zones 0xA lire
4 fermer 0xB time passing during travel
5, 6, 7 mettre: success, attempt, special 0xC an exit
8 appuyer, detail zone 0xD, 0xE, 0xF déposer, sonder, prendre

Cases read so far:

  • Room 30 puzzle: a water-jug puzzle with bénitiers of 5, 3 and 8 volumes, which start full; sonder reads a level, tourner empties, mettre pours.

  • The piano (room 2). tourner on its detail zone 14 once the ashtray is in place sets DS:139 and opens the compartment (container 24). Putting a one-cent coin in the slot (zone 16, event 6 with object kind 14 from table 0xC4) shows the 15 tunes of table 0xF1 (logic/documents.md). If DS:139 is set, the chosen tune leaves a sheet in the compartment (DS:456 is its fifth slot) and DS:139 is cleared (EA 0x17D37):

    • from 12:00 to 17:00 on the 31st, tune 13 ("Requiem") leaves the real message, sheet #139; tunes 0-12 and 14 leave

      174-#187. A timer starts (DS:88A, ending at about 15:00); when it runs out, if you are alone in the salon you are

      killed, otherwise it waits.

    • from 07:00 on the 1st, tune 4 ("Ham and eggs") leaves the second message, sheet #162; the others leave #188-#201. Marie's hidden list (sheet #158) starts with "Requiem: Kyrie eleison", then "Ham and eggs". At 17:30 on the 31st the clock puts #139 in the compartment anyway, and takes it away at 23:00.

  • Inscriptions: lire on the bassin's zone 5 (with the binoculars, at low tide) shows record 0x21 sub 7, and lire on detail zone 1 of the passage under Maguy's trapdoor (room 17) shows sub 6. Each is half of a mirrored Spanish text; see Walkthrough.

  • Touch puzzles: Item_TouchPuzzle EA 0x14D04 turns an object into another when its stones are clicked in order. Header T: byte 2 is the last stone index, byte 3 the last step index, byte 4 the new object; T+1 and T+2 are the stones' x and y, T+3 the order. The écrin #40 (T = 0x1E0) has 5 stones and needs 4, 5, 3, 3, 5, 2, and becomes #163, whose lid shows zodiac signs. The médaillon #49 (T = 0x1E5) has 7 stones and needs 3, 4, 6, 5, 2, and becomes #153 with its key.

  • Hidden caches: appuyer on the painting in Maguy's room (zone 1, table 0x12D) opens the cache with key #15 and 10 dollars. tourner on zone 14 there opens the drawer with key #17 (zone 30), and soulever on zone 15 shows the trapdoor (zone 21). In Roy's cabin, tourner on zone 31 ("Un déclic") opens the cache, zone 33, where the decoded sheet

    25 arrives at 02:00 on the 1st.

  • Room 11, zone 5 (event 10): readable only at times 32-33, 56-57 and 80-81, while carrying object 42 (the binoculars). Otherwise "Vous êtes trop loin...".

  • Well, room 10 to 16 (event 12): outside those same times, leaving triggers special event 0x40.

  • Sounds and small flag changes in rooms 1, 3, 10, 12, 16, 20, 26 and 28.

Documents and the coded sheets

Item_Read EA 0x12E52 looks the object up in three families, listed in logic/documents.md: single pages (tables 0x137-0x13A), books (0x13B-0x13E) and newspapers (0x13F-0x145). For a single page it passes the string number to service 9 with table 0x13A's value in the high word. Txt_DrawIndexed in maup.exe (EA 0x157C3) keeps that value at DS:CE, and Vid_DrawStringEx (EA 0x1188C) uses it to highlight some letters in another colour:

  • positive k (sheets #25, #139, #162, #48): string k is decoded too, and grid letters are highlighted when they match the next letter of string k. The highlighted letters are string k itself, so this mode only marks letters. Confirmed in the game: the darker letters of #139 spell class 6 string 2.
  • negative k (the decoy sheets #174-#201): letters are highlighted at intervals read from a byte table at maup.exe DS:k-1 (each byte is an offset to a list of gaps, ending with 0xFF). In the file, DS:0 holds the C runtime's copyright, and the game does read it: in the game, #174 (k = -1) darkens the first four characters and then one on the third row, and #175 (k = -2) the first three and then one a place earlier, as the bytes 0, 0, 0, 0 and "T" (84) predict. The decoys show noise.

The five readable grids as the game shows them, read in the game from a test start state (the pointer is the mouse):

Sheet Screen
#139, the real message ("Requiem") #139
#25, Roy's copy #25
#162, the second message ("Ham and eggs") #162
#48, the paper in the garden #48
#174, a decoy ("Sweet Emily") #174

Decoding. The 64 highlighted letters are a chessboard, a1 first then rank by rank. Reading the destination square of each move of a game in 'Les échecs', white and black in turn, gives the message: game n°4 (pages 4 and 90 of bank 4) on #139 or #25 gives "we wait the boat", and game n°5 (pages 40 and 96) on #162 gives "tribes need guns! the Wind!". No game decodes #48. The method was first found by the Adventurers' Guild blog for the first message.

Not yet read in full: parts of Script_Hook, Act_Regarder's close-ups (including the médaillon), Act_Observer, 0x119B8, and what happens when you're caught.

Previous: The two programs · Next: File formats, scenes and palettes · Technical appendix · Home