sourcegames/trek-adventure/TrekAdventure.xtl
1⍝# Trek adventure's rules, a library: trek-adventure.xtl (a scripted
2⍝# walkthrough), play.xtl (at the terminal) and the web page all use
3⍝# these. "Star Trek: Decaying Orbit": you wake alone on the Enterprise's
4⍝# bridge, its orbit decaying; find the toolkit and the engine coupler,
5⍝# prep the relay in engineering, install the coupler before the turns
6⍝# run out, and deal with the Klingon boarders on the way.
7⍝#
8⍝# The game is tables, not branches: every line of text is one row of a
9⍝# table, with a key (a room, an event, an ending) and a condition on the
10⍝# state; a room's description or a message is the rows whose key it is
11⍝# and whose condition holds, picked by one mask. The rooms' exits are a
12⍝# 9 by 9 table, the items' places a vector.
13⍝#
14⍝# The state is one vector: 1 room, 2 turns left, items held 3 phaser,
15⍝# 4 ID card, 5 toolkit, 6 coupler, 7 tribble (1 = carried), 8 relay
16⍝# prepped, 9 boarders aboard, 10 won, 11 dead, 12 the last event (the
17⍝# key of what to say).
18
19ˢ⁼u̲se< "State"
20ˣ⁼u̲se< "Text"
21
22⍝## The text
23⍝ :: Unit -> Box Char
24⍝# Every line the game prints, numbered as the rooms, items and events refer to them.
25ˡt̲ext ← { @ → (
26 "" ⍝ 300
27 "*** STAR TREK: DECAYING ORBIT ***" ⍝ 300
28 "" ⍝ 300
29 "YOU AWAKEN ALONE ON THE BRIDGE OF THE" ⍝ 300
30 "U.S.S. ENTERPRISE. RED LIGHTS FLASH." ⍝ 300
31 "THE SHIP SHUDDERS." ⍝ 300
32 "" ⍝ 300
33 "COMPUTER: WARNING - STABLE ORBIT LOST" ⍝ 300
34 "COMPUTER: ENGINES OFFLINE" ⍝ 300
35 "COMPUTER: ORBITAL DECAY IN PROGRESS" ⍝ 300
36 "" ⍝ 300
37 "RESTORE ENGINE POWER BEFORE THE SHIP" ⍝ 300
38 "BURNS UP. PICK 8 FOR HELP." ⍝ 300
39 "" ⍝ 300
40 "BRIDGE" ⍝ 1
41 "THE BRIDGE IS DESERTED. THE MAIN" ⍝ 1
42 "VIEWSCREEN SHOWS A PLANET GROWING" ⍝ 1
43 "LARGER. A DAMAGED CONSOLE SPARKS." ⍝ 1
44 "THE TURBOLIFT DOORS STAND OPEN." ⍝ 1
45 "A PHASER LIES UNDER THE CAPTAIN'S CHAIR." ⍝ 1 if 3=0
46 "EXITS: 2=TURBOLIFT" ⍝ 1
47 "TURBOLIFT" ⍝ 2
48 "THE TURBOLIFT HUMS ON EMERGENCY" ⍝ 2
49 "POWER. DECK BUTTONS GLOW DIMLY." ⍝ 2
50 "EXITS: 1=BRIDGE 3=CORRIDOR 6=ENGINEERING" ⍝ 2
51 "CORRIDOR" ⍝ 3
52 "A CORRIDOR STRETCHES FORE AND AFT." ⍝ 3
53 "EMERGENCY LIGHTS PULSE ALONG THE WALLS." ⍝ 3
54 "EXITS: 2=TURBOLIFT 4=QUARTERS" ⍝ 3
55 " 5=STORAGE 7=ARMORY" ⍝ 3
56 " 9=COMPUTER" ⍝ 3
57 "QUARTERS" ⍝ 4
58 "CREW QUARTERS ARE IN DISARRAY." ⍝ 4
59 "A LOCKER HANGS OPEN. PERSONAL EFFECTS" ⍝ 4
60 "FLOAT IN LOW GRAVITY." ⍝ 4
61 "A SECURITY ID CARD GLINTS UNDER A BUNK." ⍝ 4 if 4=0
62 "EXITS: 3=CORRIDOR" ⍝ 4
63 "STORAGE" ⍝ 5
64 "CARGO CONTAINERS ARE STRAPPED TO" ⍝ 5
65 "THE DECK." ⍝ 5
66 "A TOOLKIT LIES BY A MAINTENANCE CRATE." ⍝ 5 if 5=0
67 "AN ENGINE COUPLER RESTS ON A SHELF." ⍝ 5 if 6=0
68 "SOMETHING FURRY SQUEAKS - A TRIBBLE." ⍝ 5 if 7=0
69 "EXITS: 3=CORRIDOR 8=SHUTTLE" ⍝ 5
70 "ENGINEERING" ⍝ 6
71 "ENGINEERING IS HOT AND NOISY." ⍝ 6
72 "THE WARP SYSTEMS ARE OFFLINE." ⍝ 6
73 "A PLASMA RELAY PANEL HANGS OPEN." ⍝ 6 if 8=0
74 "THE RELAY PANEL IS PATCHED BUT NOT" ⍝ 6 if 8=1
75 "YET ACTIVATED." ⍝ 6 if 8=1
76 "EXITS: 2=TURBOLIFT" ⍝ 6
77 "ARMORY" ⍝ 7
78 "RACKS LINE THE WALLS. MOST WEAPONS" ⍝ 7
79 "ARE MISSING. A SPARE POWER CELL" ⍝ 7
80 "SITS IN A CRADLE." ⍝ 7
81 "EXITS: 3=CORRIDOR" ⍝ 7
82 "SHUTTLE BAY" ⍝ 8
83 "THE SHUTTLE BAY IS DARK AND COLD." ⍝ 8
84 "A SHUTTLE HANGS IN PLACE, BUT LAUNCH" ⍝ 8
85 "SYSTEMS ARE DEAD." ⍝ 8
86 "DISTANT METALLIC FOOTSTEPS ECHO." ⍝ 8 if 9=1
87 "EXITS: 5=STORAGE" ⍝ 8
88 "COMPUTER CORE" ⍝ 9
89 "BANKS OF PANELS FLICKER IN STANDBY." ⍝ 9
90 "A MONITOR SCROLLS SECURITY ALERTS." ⍝ 9
91 "EXITS: 3=CORRIDOR" ⍝ 9
92 "?WHAT" ⍝ 10
93 "YOU CAN'T GO THAT WAY." ⍝ 11
94 "ARMORY DOOR LOCKED - NEED ID CARD." ⍝ 12
95 " (NOTHING HERE TO TAKE)" ⍝ 20
96 "YOU DON'T SEE THAT HERE." ⍝ 21
97 "YOU ALREADY HAVE IT." ⍝ 22
98 "TAKEN: PHASER." ⍝ 23
99 "TAKEN: ID CARD." ⍝ 24
100 "TAKEN: TOOLKIT." ⍝ 25
101 "TAKEN: ENGINE COUPLER." ⍝ 26
102 "THE TRIBBLE PURRS SOFTLY. TAKEN." ⍝ 27
103 "NOTHING HAPPENS." ⍝ 30
104 "YOU DON'T HAVE A TOOLKIT." ⍝ 31
105 "YOU TIGHTEN FITTINGS BUT THE COUPLER" ⍝ 32
106 "IS STILL MISSING." ⍝ 32
107 "RELAY IS ALREADY PREPPED." ⍝ 33
108 "YOU REMOVE THE BURNT RELAY COVER" ⍝ 34
109 "AND PREP THE MOUNT." ⍝ 34
110 "YOU DON'T HAVE THE ENGINE COUPLER." ⍝ 35
111 "YOU NEED TOOLS TO INSTALL IT." ⍝ 36
112 "YOU MUST PREP THE RELAY PANEL FIRST." ⍝ 37
113 "YOU INSTALL THE ENGINE COUPLER AND" ⍝ 38
114 "LOCK IT DOWN." ⍝ 38
115 "MAIN IMPULSE POWER SURGES BACK ONLINE." ⍝ 38
116 "COMPUTER: ORBIT STABILIZED." ⍝ 38
117 "COMPUTER: SECURITY LOG..." ⍝ 39
118 " 'INTRUDER ALERT. BOARDING DETECTED.'" ⍝ 39
119 " 'CREW EVACUATED OR CAPTURED.'" ⍝ 39
120 " 'KLINGON SEARCH PARTIES EXPECTED.'" ⍝ 39
121 "A MAP HIGHLIGHTS STORAGE AND" ⍝ 39
122 "ENGINEERING AS PRIORITY SYSTEMS." ⍝ 39
123 "YOU DON'T HAVE A TRIBBLE." ⍝ 40
124 "NO TARGET. THE TRIBBLE SQUEAKS." ⍝ 41
125 "YOU HURL THE TRIBBLE." ⍝ 42
126 "THE KLINGONS FREEZE. ONE SHOUTS:" ⍝ 42
127 "'GET IT AWAY FROM ME!'" ⍝ 42
128 "IN THE CONFUSION, THEY RETREAT." ⍝ 42
129 "YOU DON'T HAVE A PHASER." ⍝ 50
130 "YOU FIRE AT NOTHING IN PARTICULAR." ⍝ 51
131 "YOU STUN ONE KLINGON - BUT ANOTHER" ⍝ 52
132 "RETURNS FIRE!" ⍝ 52
133 "YOU ARE CARRYING:" ⍝ 60
134 " PHASER" ⍝ 61 if 3=1
135 " ID CARD" ⍝ 61 if 4=1
136 " TOOLKIT" ⍝ 61 if 5=1
137 " ENGINE COUPLER" ⍝ 61 if 6=1
138 " TRIBBLE" ⍝ 61 if 7=1
139 " NOTHING" ⍝ 62 when nothing is carried
140 "" ⍝ 80
141 "COMMANDS (PICK A NUMBER):" ⍝ 80
142 " 1 LOOK - REDESCRIBE ROOM" ⍝ 80
143 " 2 INV - LIST INVENTORY" ⍝ 80
144 " 3 GO - THEN ENTER ROOM#" ⍝ 80
145 " 4 TAKE - THEN ENTER ITEM#" ⍝ 80
146 " 5 USE - THEN ENTER ITEM#" ⍝ 80
147 " 6 THROW - HURLS THE TRIBBLE" ⍝ 80
148 " 7 FIRE - FIRE THE PHASER" ⍝ 80
149 " 8 HELP - THIS HELP" ⍝ 80
150 " 0 QUIT - RESIGN COMMAND" ⍝ 80
151 "" ⍝ 80
152 "ROOM# IS THE NUMBER PRINTED NEXT TO" ⍝ 80
153 "EACH EXIT. GOAL: FIX ENGINES IN" ⍝ 80
154 "ENGINEERING BEFORE ORBIT DECAYS." ⍝ 80
155 "COMPUTER: INTERNAL SENSORS DETECT BOARDERS." ⍝ 101
156 "TWO KLINGONS EMERGE FROM THE SHADOWS!" ⍝ 102
157 "ONE RAISES A DISRUPTOR." ⍝ 102
158 "YOU HAVE ONLY MOMENTS TO ACT." ⍝ 102
159 "YOU HEAR KLINGON VOICES NEARBY." ⍝ 103
160 "" ⍝ 201
161 "THE DECK STEADIES BENEATH YOUR FEET." ⍝ 201
162 "ON THE VIEWSCREEN, THE PLANET SLOWLY" ⍝ 201
163 "RECEDES." ⍝ 201
164 "COMPUTER: ORBIT STABLE." ⍝ 201
165 "COMPUTER: EMERGENCY CONDITION ENDED." ⍝ 201
166 "" ⍝ 201
167 "*** YOU SAVED THE ENTERPRISE. ***" ⍝ 201
168 "" ⍝ 202
169 "A BURST OF DISRUPTOR FIRE SLAMS" ⍝ 202
170 "INTO THE BULKHEAD BESIDE YOU." ⍝ 202
171 "THE NEXT SHOT IS MORE ACCURATE." ⍝ 202
172 "" ⍝ 202
173 "*** YOU HAVE DIED. ***" ⍝ 202
174 "" ⍝ 203
175 "THE SHIP SHAKES VIOLENTLY." ⍝ 203
176 "FLAMES ERUPT FROM DEAD CONSOLES." ⍝ 203
177 "THE ENTERPRISE ENTERS THE UPPER" ⍝ 203
178 "ATMOSPHERE." ⍝ 203
179 "" ⍝ 203
180 "*** YOU WERE TOO LATE. ***" ⍝ 203
181 "" ⍝ 204
182 "*** COMMAND RESIGNED ***" ⍝ 204
183) }
184⍝ :: Num a => Unit -> a
185⍝# Each line's key: a room (1 to 9), an event (10 to 99), the clock (101
186⍝# to 103), an ending (201 to 204), the opening (300).
187ˡk̲eys ← { @ → (
188 300 300 300 300 300 300 300 300 300 300 300 300 300 300 1 1 1 1 1
189 1 1 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 5 5 5 5 5 5 5 6 6 6 6 6 6 6 7
190 7 7 7 7 8 8 8 8 8 8 9 9 9 9 10 11 12 20 21 22 23 24 25 26 27 30 31
191 32 32 33 34 34 35 36 37 38 38 38 38 39 39 39 39 39 39 40 41 42 42
192 42 42 50 51 52 52 60 61 61 61 61 61 62 80 80 80 80 80 80 80 80 80
193 80 80 80 80 80 80 101 102 102 102 103 201 201 201 201 201 201 201
194 201 202 202 202 202 202 202 203 203 203 203 203 203 203 204 204
195) }
196⍝ :: Num a => Unit -> a
197⍝# Each line's condition: shown only when this state item (0: always) ...
198ˡf̲lags ← { @ → (
199 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0
200 0 0 4 0 0 0 0 5 6 7 0 0 0 0 8 8 8 0 0 0 0 0 0 0 0 0 0 9 0 0 0 0 0
201 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
202 0 0 0 0 0 0 0 0 0 3 4 5 6 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
203 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
204) }
205⍝ :: Num a => Unit -> a
206⍝# ... has this value.
207ˡv̲alues ← { @ → (
208 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
209 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
210 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
211 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
212 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
213) }
214
215⍝ :: Num a => Unit -> a
216⍝# The table's three number columns as one 3-row matrix (key, condition
217⍝# item, condition value), as lib/Text reads it.
218ˡk̲fv ← { @ → (3 c̲at t̲ally ˡk̲eys @) r̲eshape (ˡk̲eys @) c̲at (ˡf̲lags @) c̲at ˡv̲alues @ }
219⍝ :: Num a => Int -> a -> Int
220⍝# The rows for keys k (one or many) in state s: the key matches, and the
221⍝# row's condition holds (lib/Text's l:h_olds).
222ˡl̲ines ← { s k → w̲here ((ˡk̲eys @) m̲ember? k) ∧ (ˡk̲fv @) ˣh̲olds s }
223⍝ :: (Num a, Num b) => Int -> a -> b
224⍝# Print the lines for keys k; how many were printed.
225ˡs̲ay ← { s k → ˣl̲ines (s ˡl̲ines k) s̲elect ˡt̲ext @ }
226
227⍝## The ship
228⍝ :: Num a => Unit -> a
229⍝# Exits: row r, column x is 1 when room x can be reached from room r.
230ˡe̲xits ← { @ → 9 9 r̲eshape (
231 0 1 0 0 0 0 0 0 0
232 1 0 1 0 0 1 0 0 0
233 0 1 0 1 1 0 1 0 1
234 0 0 1 0 0 0 0 0 0
235 0 0 1 0 0 0 0 1 0
236 0 1 0 0 0 0 0 0 0
237 0 0 1 0 0 0 0 0 0
238 0 0 0 0 1 0 0 0 0
239 0 0 1 0 0 0 0 0 0
240) }
241⍝ :: Unit -> Box Char
242⍝# The items, numbered as the TAKE menu numbers them, and where each lies.
243ˡi̲tems ← { @ → "PHASER" "CARD" "TOOLKIT" "COUPLER" "TRIBBLE" }
244⍝ :: Num a => Unit -> a
245⍝# Where each item lies at the start, by room.
246ˡh̲omes ← { @ → 1 4 5 5 5 }
247
248⍝## The state
249⍝ Where each thing is in the state vector, by name.
250⍝ :: Int
251⍝# Where the room is, in the state.
252ˡroom ← 1
253⍝ :: Int
254⍝# Where the turns left are, in the state.
255ˡturns ← 2
256⍝ :: Int
257⍝# Where the phaser's place is, in the state.
258ˡphaser ← 3
259⍝ :: Int
260⍝# Where the card's place is, in the state.
261ˡcard ← 4
262⍝ :: Int
263⍝# Where the toolkit's place is, in the state.
264ˡtoolkit ← 5
265⍝ :: Int
266⍝# Where the coupler's place is, in the state.
267ˡcoupler ← 6
268⍝ :: Int
269⍝# Where the tribble's place is, in the state.
270ˡtribble ← 7
271⍝ :: Int
272⍝# Whether the relay is fixed, its place in the state.
273ˡrelay ← 8
274⍝ :: Int
275⍝# Whether the boarders are aboard, its place in the state.
276ˡboarders ← 9
277⍝ :: Int
278⍝# Whether the game is won, its place in the state.
279ˡwon ← 10
280⍝ :: Int
281⍝# Whether the player is dead, its place in the state.
282ˡdead ← 11
283⍝ :: Int
284⍝# The last event, its place in the state.
285ˡevent ← 12
286
287⍝ :: (Any a, Num b) => a -> b
288⍝# A new game: in room 1 with 30 turns, nothing taken or done.
289ˡn̲ew ← { x → 1 30 0 0 0 0 0 0 0 0 0 0 }
290⍝ :: a -> a
291⍝# The room the player is in.
292ˡr̲oom ← { s → ˡroom s̲elect s }
293⍝ :: a -> a
294⍝# The turns left.
295ˡt̲urns ← { s → ˡturns s̲elect s }
296⍝ :: a -> a
297⍝# The last event (a code for the message).
298ˡe̲vent ← { s → ˡevent s̲elect s }
299⍝ :: (Num a, Truthy a) => a -> a
300⍝# 0 playing, 1 won, 2 dead, 3 out of time.
301ˡs̲tatus ← { s → (ˡwon s̲elect s) m̲ax (2 × ˡdead s̲elect s) m̲ax 3 × 0 ≥ ˡt̲urns s }
302⍝ :: Int -> Int -> Int
303⍝# Several items of s changed at once (lib/State): iv is index, value,
304⍝# index, value, ...
305ˡu̲pdate ← { s iv → s ˢu̲pdate iv }
306⍝ :: Int -> Int -> Int
307⍝# Just the event changed: what to say next.
308ˡs̲aying ← { s e → s ˡu̲pdate ˡevent c̲at e }
309⍝ :: Num a => a -> Int
310⍝# The items here, by number: in this room and not carried.
311ˡp̲resent ← { s → w̲here ((ˡh̲omes @) = ˡr̲oom s) ∧ 0 = 5 t̲ake 2 d̲rop s }
312⍝ :: (Truthy a, Num b) => a -> b -> b
313⍝# Of a row of checks that would refuse an action (1 where a check
314⍝# fails) and the event saying each, the first refusal: 0 when there is
315⍝# none.
316ˡr̲efusal ← { fails events → f̲irst (fails r̲eplicate events) c̲at 0 }
317
318⍝## A command
319⍝ :: Int -> Int -> Int
320⍝# cx is the command and its argument (a room or an item number, or 0):
321⍝# 1 look, 2 inventory, 3 go, 4 take, 5 use, 6 throw, 7 fire, 8 help.
322⍝# The result is the new state, its event the key of what to say.
323ˡm̲ove ← { s cx →
324 c ← f̲irst cx
325 x ← 2 s̲elect cx
326 c = 1 ? s ˡs̲aying 0
327 c = 2 ? s ˡs̲aying 60
328 c = 3 ? s ˡg̲o x
329 c = 4 ? s ˡt̲ake x
330 c = 5 ? s ˡu̲se x
331 c = 6 ? ˡt̲hrow s
332 c = 7 ? ˡf̲ire s
333 c = 8 ? s ˡs̲aying 80
334 s ˡs̲aying 10
335}
336⍝ :: Int -> Int -> Int
337⍝# Go to room x: there must be an exit (a 1 in the exits table), and the
338⍝# armory wants the ID card.
339ˡg̲o ← { s x →
340 (x < 1) ∨ x > 9 ? s ˡs̲aying 11
341 e ← ((0 = x s̲elect (ˡr̲oom s) s̲elect ˡe̲xits @) c̲at (x = 7) ∧ 0 = ˡcard s̲elect s) ˡr̲efusal 11 12
342 0 < e ? s ˡs̲aying e
343 s ˡu̲pdate ˡroom c̲at x c̲at ˡevent c̲at 0
344}
345⍝ :: Int -> Int -> Int
346⍝# Take item x: it must be here and not yet carried.
347ˡt̲ake ← { s x →
348 x = 0 ? s ˡs̲aying 20
349 (x < 1) ∨ x > 5 ? s ˡs̲aying 21
350 e ← (((ˡr̲oom s) ≠ x s̲elect ˡh̲omes @) c̲at 1 = (2 + x) s̲elect s) ˡr̲efusal 21 22
351 0 < e ? s ˡs̲aying e
352 s ˡu̲pdate (2 + x) c̲at 1 c̲at ˡevent c̲at 22 + x
353}
354⍝ :: Int -> Int -> Int
355⍝# Use item x: the toolkit and the coupler in engineering, the computer
356⍝# in its core; anything else does nothing.
357ˡu̲se ← { s x →
358 r ← ˡr̲oom s
359 (r = 6) ∧ x = 1 ? ˡt̲oolkit s
360 (r = 6) ∧ x = 2 ? ˡc̲oupler s
361 (r = 9) ∧ x = 3 ? s ˡs̲aying 39
362 s ˡs̲aying 30
363}
364⍝ :: Int -> Int
365⍝# The toolkit preps the relay: it needs the toolkit and the coupler, and
366⍝# the relay not yet prepped.
367ˡt̲oolkit ← { s →
368 e ← ((0 = ˡtoolkit s̲elect s) c̲at (0 = ˡcoupler s̲elect s) c̲at 1 = ˡrelay s̲elect s) ˡr̲efusal 31 32 33
369 0 < e ? s ˡs̲aying e
370 s ˡu̲pdate ˡrelay c̲at 1 c̲at ˡevent c̲at 34
371}
372⍝ :: Int -> Int
373⍝# The coupler, installed, wins: it needs the coupler, the toolkit and a
374⍝# prepped relay.
375ˡc̲oupler ← { s →
376 e ← ((0 = ˡcoupler s̲elect s) c̲at (0 = ˡtoolkit s̲elect s) c̲at 0 = ˡrelay s̲elect s) ˡr̲efusal 35 36 37
377 0 < e ? s ˡs̲aying e
378 s ˡu̲pdate ˡwon c̲at 1 c̲at ˡevent c̲at 38
379}
380⍝ :: Int -> Int
381⍝# Throwing the tribble makes the boarders retreat (it needs both).
382ˡt̲hrow ← { s →
383 e ← ((0 = ˡtribble s̲elect s) c̲at 0 = ˡboarders s̲elect s) ˡr̲efusal 40 41
384 0 < e ? s ˡs̲aying e
385 s ˡu̲pdate ˡboarders c̲at 0 c̲at ˡtribble c̲at 0 c̲at ˡevent c̲at 42
386}
387⍝ :: Int -> Int
388⍝# Firing the phaser at the boarders is fatal (it needs both).
389ˡf̲ire ← { s →
390 e ← ((0 = ˡphaser s̲elect s) c̲at 0 = ˡboarders s̲elect s) ˡr̲efusal 50 51
391 0 < e ? s ˡs̲aying e
392 s ˡu̲pdate ˡdead c̲at 1 c̲at ˡevent c̲at 52
393}
394⍝ :: Num a => a -> a
395⍝# The keys of what the last event says (the inventory adds what is
396⍝# carried, or "nothing").
397ˡs̲aid ← { s →
398 e ← ˡe̲vent s
399 e ≠ 60 ? e
400 60 61 c̲at (0 = '+ r̲/ 5 t̲ake 2 d̲rop s) r̲eplicate 62
401}
402
403⍝## The clock
404⍝ :: Int -> Int
405⍝# Each command takes a turn; at 21 turns left Klingons come aboard.
406ˡc̲lock ← { s →
407 t ← (ˡt̲urns s) − 1
408 s ˡu̲pdate ˡturns c̲at t c̲at ˡboarders c̲at (ˡboarders s̲elect s) m̲ax t = 21
409}
410⍝ :: (Num a, Truthy a, Num b) => a -> b
411⍝# What the clock says after a turn: the sensors (at 22), the Klingons in
412⍝# the shuttle bay, their voices in the corridor late in the game.
413ˡa̲larms ← { s →
414 t ← ˡt̲urns s
415 r ← ˡr̲oom s
416 b ← ˡboarders s̲elect s
417 ((t = 22) c̲at (b ∧ r = 8) c̲at b ∧ (r = 3) ∧ t < 15) r̲eplicate 101 102 103
418}