|
@@ -18,40 +18,54 @@
|
18
|
18
|
(in-package #:crypts-and-corpses)
|
19
|
19
|
|
20
|
20
|
(defstruct game-map
|
21
|
|
- (width 100 :type fixnum :read-only t)
|
22
|
|
- (height 40 :type fixnum :read-only t)
|
|
21
|
+ (width 99 :type fixnum :read-only t)
|
|
22
|
+ (height 39 :type fixnum :read-only t)
|
23
|
23
|
(mobiles (make-hash-table) :type hash-table :read-only t))
|
24
|
24
|
|
25
|
25
|
(defclass entity ()
|
26
|
26
|
((width :initarg :width :type fixnum :initform 1)
|
27
|
27
|
(height :initarg :height :type fixnum :initform 1)
|
28
|
|
- (location :initarg :location :initform 0 :type fixnum)))
|
|
28
|
+ (location :initarg :location :initform 0 :type fixnum)
|
|
29
|
+ (color :initarg :color :initform (color-from-name "white"))))
|
29
|
30
|
|
30
|
31
|
(defclass tile-entity (entity)
|
31
|
32
|
((codepoint :initarg :codepoint :initform #x3f :type fixnum)))
|
32
|
33
|
|
33
|
34
|
(defclass wall (tile-entity)
|
34
|
|
- ((codepoint :initarg :codepoint :initform #x23 :type fixnum)))
|
|
35
|
+ ((codepoint :initarg :codepoint :initform #x23 :type fixnum)
|
|
36
|
+ (color :initarg :color :initform (color-from-name "grey"))))
|
35
|
37
|
|
36
|
38
|
(defclass viewport (entity)
|
37
|
|
- ((width :initarg :width :type fixnum :initform 100)
|
|
39
|
+ ((width :initarg :width :type fixnum :initform 99)
|
38
|
40
|
(height :initarg :height :type fixnum :initform 40)
|
39
|
41
|
(location :initarg :location :type fixnum :initform 0)))
|
40
|
42
|
|
41
|
43
|
(defclass mobile (tile-entity)
|
42
|
|
- ((health :initarg :health :type fixnum)
|
43
|
|
- (mana :initarg :mana :type fixnum)
|
|
44
|
+ ((health :initarg :health :type fixnum :initform 10)
|
|
45
|
+ (mana :initarg :mana :type fixnum :initform 0)
|
|
46
|
+ (max-health :initarg :health :type fixnum :initform 10)
|
|
47
|
+ (max-mana :initarg :mana :type fixnum :initform 10)
|
44
|
48
|
(health-regen :initarg :health-regen :initform 0 :type fixnum)
|
45
|
49
|
(mana-regen :initarg :mana-regen :initform 0 :type fixnum)))
|
46
|
50
|
|
47
|
51
|
(defclass player-character (mobile)
|
48
|
|
- ((codepoint :initform #x263a)
|
|
52
|
+ ((health :initarg :health :type fixnum :initform 100)
|
|
53
|
+ (mana :initarg :mana :type fixnum :initform 10)
|
|
54
|
+ (codepoint :initform #x263a)
|
49
|
55
|
(ranged-attack-damage :initarg :ranged-attack-damage :initform 5 :type fixnum)
|
50
|
|
- (ranged-attack-cost :initarg :ranged-attack-cost :initform 5 :type fixnum)))
|
|
56
|
+ (melee-attack-damage :initarg :ranged-attack-damage :initform 2 :type fixnum)
|
|
57
|
+ (ranged-attack-cost :initarg :ranged-attack-cost :initform 5 :type fixnum)
|
|
58
|
+ (mana-regen :initarg :mana-regen :initform 3 :type fixnum)
|
|
59
|
+ (color :initarg :color :initform (color-from-name "green"))))
|
51
|
60
|
|
52
|
|
-(defclass enemy (mobile) ())
|
|
61
|
+(defclass enemy (mobile)
|
|
62
|
+ ((codepoint :initform #x263a)
|
|
63
|
+ (melee-attack-damage :initarg :ranged-attack-damage :initform 1 :type fixnum)
|
|
64
|
+ (health-regen :initarg :health-regen :initform 1 :type fixnum)
|
|
65
|
+ (color :initarg :color :initform (color-from-name "red"))))
|
53
|
66
|
|
54
|
|
-(defclass minion (mobile) ())
|
|
67
|
+(defclass minion (mobile)
|
|
68
|
+ ((color :initarg :color :initform (color-from-name "yellow"))))
|
55
|
69
|
|
56
|
70
|
(defun calc-coord (location map)
|
57
|
71
|
(values (mod location (game-map-width map)) (floor (/ location (game-map-width map)))))
|
|
@@ -66,12 +80,15 @@
|
66
|
80
|
(defmethod set-location ((object tile-entity) x y map)
|
67
|
81
|
(setf (slot-value object 'location) (calc-location x y map)))
|
68
|
82
|
|
69
|
|
-
|
70
|
83
|
(defgeneric end-of-turn (object))
|
71
|
84
|
|
72
|
85
|
(defmethod end-of-turn ((object mobile))
|
73
|
86
|
(incf (slot-value object 'health) (slot-value object 'health-regen))
|
74
|
|
- (incf (slot-value object 'mana) (slot-value object 'mana-regen)))
|
|
87
|
+ (incf (slot-value object 'mana) (slot-value object 'mana-regen))
|
|
88
|
+ (when (> (slot-value object 'health) (slot-value object 'max-health))
|
|
89
|
+ (setf (slot-value object 'health) (slot-value object 'max-health)))
|
|
90
|
+ (when (> (slot-value object 'mana) (slot-value object 'max-mana))
|
|
91
|
+ (setf (slot-value object 'mana) (slot-value object 'max-mana))))
|
75
|
92
|
|
76
|
93
|
(defgeneric move-left (object map))
|
77
|
94
|
(defgeneric move-right (object map))
|
|
@@ -99,11 +116,14 @@
|
99
|
116
|
(1- (slot-value object 'width))
|
100
|
117
|
(* (1- (slot-value object 'height)) (game-map-width map))))
|
101
|
118
|
|
|
119
|
+(defun collision-p (new-location map)
|
|
120
|
+ (gethash new-location (game-map-mobiles map)))
|
|
121
|
+
|
102
|
122
|
(defun bad-move-p (object map old-location new-location)
|
103
|
123
|
(let ((old-effective-location (calculate-effective-location object map old-location))
|
104
|
124
|
(new-effective-location (calculate-effective-location object map new-location)))
|
105
|
125
|
(or (out-of-bounds-p new-effective-location map)
|
106
|
|
- (out-of-bounds-p new-location map)
|
|
126
|
+ (collision-p new-effective-location map)
|
107
|
127
|
(overrun-p old-effective-location new-effective-location map))))
|
108
|
128
|
|
109
|
129
|
(defmethod update-location ((object entity) map old-location new-location)
|
|
@@ -136,21 +156,130 @@
|
136
|
156
|
(new-location (1+ (slot-value object 'location))))
|
137
|
157
|
(update-location object map old-location new-location)))
|
138
|
158
|
|
|
159
|
+(defun find-mobile-left (location map)
|
|
160
|
+ (let ((found-object nil))
|
|
161
|
+ (loop for i from (1- location) downto 0 do
|
|
162
|
+ (setf found-object (gethash i (game-map-mobiles map)))
|
|
163
|
+ (when (not (typep found-object 'mobile))
|
|
164
|
+ (setf found-object nil))
|
|
165
|
+ until found-object)
|
|
166
|
+ found-object))
|
|
167
|
+
|
|
168
|
+(defun find-mobile-right (location map)
|
|
169
|
+ (let ((found-object nil))
|
|
170
|
+ (loop for i from (1+ location) to (* (game-map-width map) (game-map-height map)) do
|
|
171
|
+ (setf found-object (gethash i (game-map-mobiles map)))
|
|
172
|
+ (when (not (typep found-object 'mobile))
|
|
173
|
+ (setf found-object nil))
|
|
174
|
+ until found-object)
|
|
175
|
+ found-object))
|
|
176
|
+
|
|
177
|
+(defun find-mobile-up (location map)
|
|
178
|
+ (let ((found-object nil))
|
|
179
|
+ (loop for i from (- location (game-map-width map)) downto 0 by (game-map-width map) do
|
|
180
|
+ (setf found-object (gethash i (game-map-mobiles map)))
|
|
181
|
+ (when (not (typep found-object 'mobile))
|
|
182
|
+ (setf found-object nil))
|
|
183
|
+ until found-object)
|
|
184
|
+ found-object))
|
|
185
|
+
|
|
186
|
+(defun find-mobile-down (location map)
|
|
187
|
+ (let ((found-object nil))
|
|
188
|
+ (loop for i from (+ location (game-map-width map)) to (* (game-map-width map) (game-map-height map)) by (game-map-width map) do
|
|
189
|
+ (setf found-object (gethash i (game-map-mobiles map)))
|
|
190
|
+ (when (not (typep found-object 'mobile))
|
|
191
|
+ (setf found-object nil))
|
|
192
|
+ until found-object)
|
|
193
|
+ found-object))
|
|
194
|
+
|
|
195
|
+(defgeneric shoot-left (object map))
|
|
196
|
+(defgeneric shoot-right (object map))
|
|
197
|
+(defgeneric shoot-up (object map))
|
|
198
|
+(defgeneric shoot-down (object map))
|
|
199
|
+
|
|
200
|
+(defmethod shoot-left ((object player-character) map)
|
|
201
|
+ (let ((target (find-mobile-left (slot-value object 'location) map)))
|
|
202
|
+ (when target
|
|
203
|
+ (decf (slot-value target 'health) (slot-value object 'ranged-attack-damage))
|
|
204
|
+ (decf (slot-value object 'mana) (slot-value object 'ranged-attack-cost)))))
|
|
205
|
+
|
|
206
|
+(defmethod shoot-right ((object player-character) map)
|
|
207
|
+ (let ((target (find-mobile-right (slot-value object 'location) map)))
|
|
208
|
+ (when target
|
|
209
|
+ (decf (slot-value target 'health) (slot-value object 'ranged-attack-damage))
|
|
210
|
+ (decf (slot-value object 'mana) (slot-value object 'ranged-attack-cost)))))
|
|
211
|
+
|
|
212
|
+(defmethod shoot-up ((object player-character) map)
|
|
213
|
+ (let ((target (find-mobile-up (slot-value object 'location) map)))
|
|
214
|
+ (when target
|
|
215
|
+ (decf (slot-value target 'health) (slot-value object 'ranged-attack-damage))
|
|
216
|
+ (decf (slot-value object 'mana) (slot-value object 'ranged-attack-cost)))))
|
|
217
|
+
|
|
218
|
+(defmethod shoot-down ((object player-character) map)
|
|
219
|
+ (let ((target (find-mobile-down (slot-value object 'location) map)))
|
|
220
|
+ (when target
|
|
221
|
+ (decf (slot-value target 'health) (slot-value object 'ranged-attack-damage))
|
|
222
|
+ (decf (slot-value object 'mana) (slot-value object 'ranged-attack-cost)))))
|
|
223
|
+
|
|
224
|
+(defgeneric bash-left (object map))
|
|
225
|
+(defgeneric bash-right (object map))
|
|
226
|
+(defgeneric bash-up (object map))
|
|
227
|
+(defgeneric bash-down (object map))
|
|
228
|
+
|
|
229
|
+(defmethod bash-left ((object player-character) map)
|
|
230
|
+ (let* ((location (1- (slot-value object 'location)))
|
|
231
|
+ (potential-target (gethash location (game-map-mobiles map)))
|
|
232
|
+ (target (and potential-target (typep potential-target 'mobile))))
|
|
233
|
+ (when target
|
|
234
|
+ (decf (slot-value target 'health) (slot-value object 'melee-attack-damage)))))
|
|
235
|
+
|
|
236
|
+(defmethod bash-right ((object player-character) map)
|
|
237
|
+ (let* ((location (1+ (slot-value object 'location)))
|
|
238
|
+ (potential-target (gethash location (game-map-mobiles map)))
|
|
239
|
+ (target (and potential-target (typep potential-target 'mobile))))
|
|
240
|
+ (when target
|
|
241
|
+ (decf (slot-value target 'health) (slot-value object 'melee-attack-damage)))))
|
|
242
|
+
|
|
243
|
+(defmethod bash-up ((object player-character) map)
|
|
244
|
+ (let* ((location (- (slot-value object 'location) (game-map-width map)))
|
|
245
|
+ (potential-target (gethash location (game-map-mobiles map)))
|
|
246
|
+ (target (and potential-target (typep potential-target 'mobile))))
|
|
247
|
+ (when target
|
|
248
|
+ (decf (slot-value target 'health) (slot-value object 'melee-attack-damage)))))
|
|
249
|
+
|
|
250
|
+(defmethod bash-down ((object player-character) map)
|
|
251
|
+ (let* ((location (+ (slot-value object 'location) (game-map-width map)))
|
|
252
|
+ (potential-target (gethash location (game-map-mobiles map)))
|
|
253
|
+ (target (and potential-target (typep potential-target 'mobile))))
|
|
254
|
+ (when target
|
|
255
|
+ (decf (slot-value target 'health) (slot-value object 'melee-attack-damage)))))
|
|
256
|
+
|
139
|
257
|
(defun intro-message ()
|
140
|
|
- (loop as key = (terminal-read) do
|
141
|
|
- (multiple-value-bind (win-width win-height) (get-window-size)
|
142
|
|
- (terminal-print (floor (- (/ win-width 2) 10)) (floor (1- (/ win-height 2))) "Crypts and Corpses")
|
143
|
|
- (terminal-print (floor (- (/ win-width 2) 11)) (floor (1+ (/ win-height 2))) "Press enter to start"))
|
144
|
|
- (terminal-refresh)
|
145
|
|
- until (= key bearlibterminal-ffi:+tk-enter+)))
|
|
258
|
+ (multiple-value-bind (win-width win-height) (get-window-size)
|
|
259
|
+ (terminal-print (floor (- (/ win-width 2) 10)) (floor (1- (/ win-height 2))) "Crypts and Corpses")
|
|
260
|
+ (terminal-print (floor (- (/ win-width 2) 11)) (floor (1+ (/ win-height 2))) "Press enter to start"))
|
|
261
|
+ (terminal-refresh))
|
146
|
262
|
|
147
|
263
|
(defun write-map-to-terminal (map viewport)
|
148
|
264
|
(labels ((write-cell (key tile)
|
149
|
265
|
(multiple-value-bind (x y) (calc-coord (- key (slot-value viewport 'location)) map)
|
|
266
|
+ (terminal-color (slot-value tile 'color))
|
150
|
267
|
(terminal-put x y (slot-value tile 'codepoint)))))
|
151
|
268
|
(maphash #'write-cell (game-map-mobiles map))))
|
152
|
269
|
|
153
|
|
-(defun fill-map-from-crawler (dungeon map)
|
|
270
|
+(defun nearest-open-tile (location map)
|
|
271
|
+ (let ((left (1- location))
|
|
272
|
+ (right (1+ location))
|
|
273
|
+ (up (- (game-map-width map) location))
|
|
274
|
+ (down (+ (game-map-width map) location))
|
|
275
|
+ (mobiles (game-map-mobiles map)))
|
|
276
|
+ (cond
|
|
277
|
+ ((eq :not-found (gethash left mobiles :not-found)) left)
|
|
278
|
+ ((eq :not-found (gethash up mobiles :not-found)) up)
|
|
279
|
+ ((eq :not-found (gethash right mobiles :not-found)) right)
|
|
280
|
+ ((eq :not-found (gethash down mobiles :not-found)) down))))
|
|
281
|
+
|
|
282
|
+(defun fill-map-from-crawler (dungeon map player)
|
154
|
283
|
(with-slots ((width crawler:width) (height crawler:height)) dungeon
|
155
|
284
|
(dotimes (x width)
|
156
|
285
|
(dotimes (y height)
|
|
@@ -158,24 +287,52 @@
|
158
|
287
|
(unless (crawler:walkablep tile)
|
159
|
288
|
(let ((wall (make-instance 'wall)))
|
160
|
289
|
(set-location wall x y map)
|
161
|
|
- (setf (gethash (calc-location x y map) (game-map-mobiles map)) wall))))))))
|
|
290
|
+ (setf (gethash (calc-location x y map) (game-map-mobiles map)) wall)))
|
|
291
|
+ (when (eq (crawler:map-feature tile) :stairs-up)
|
|
292
|
+ (set-location player x y map)
|
|
293
|
+ (setf (gethash (calc-location x y map) (game-map-mobiles map)) player)
|
|
294
|
+ (let* ((location (nearest-open-tile (calc-location x y map) map))
|
|
295
|
+ (enemy (make-instance 'enemy :location location)))
|
|
296
|
+ (setf (gethash location (game-map-mobiles map)) enemy))))))))
|
162
|
297
|
|
163
|
298
|
(defun initialize-map (map player)
|
164
|
299
|
(setf (gethash (slot-value player 'location) (game-map-mobiles map)) player)
|
165
|
|
- (fill-map-from-crawler (crawler:make-dungeon (1- (game-map-width map)) (1- (game-map-height map))) map)
|
|
300
|
+ (fill-map-from-crawler (crawler:make-dungeon (game-map-width map) (game-map-height map)) map player)
|
166
|
301
|
map)
|
167
|
302
|
|
168
|
|
-(defun handle-input (key map viewport player)
|
|
303
|
+(defun handle-input (key map viewport player prev-key)
|
169
|
304
|
(cond
|
170
|
|
- ((= key bearlibterminal-ffi:+tk-up+) (move-up player map))
|
171
|
|
- ((= key bearlibterminal-ffi:+tk-down+) (move-down player map))
|
172
|
|
- ((= key bearlibterminal-ffi:+tk-right+) (move-right player map))
|
173
|
|
- ((= key bearlibterminal-ffi:+tk-left+) (move-left player map))
|
174
|
|
- ((= key bearlibterminal-ffi:+tk-w+) (move-up viewport map))
|
175
|
|
- ((= key bearlibterminal-ffi:+tk-a+) (move-left viewport map))
|
176
|
|
- ((= key bearlibterminal-ffi:+tk-d+) (move-right viewport map))
|
177
|
|
- ((= key bearlibterminal-ffi:+tk-s+) (move-down viewport map))
|
178
|
|
- ((= key bearlibterminal-ffi:+tk-space+) (update-location viewport map (slot-value viewport 'location) (slot-value player 'location)))))
|
|
305
|
+ ;; Ranged attack
|
|
306
|
+ ((equal prev-key bearlibterminal-ffi:+tk-r+)
|
|
307
|
+ (cond
|
|
308
|
+ ((= key bearlibterminal-ffi:+tk-up+) (shoot-up player map))
|
|
309
|
+ ((= key bearlibterminal-ffi:+tk-down+) (shoot-down player map))
|
|
310
|
+ ((= key bearlibterminal-ffi:+tk-right+) (shoot-right player map))
|
|
311
|
+ ((= key bearlibterminal-ffi:+tk-left+) (shoot-left player map))
|
|
312
|
+ ((= key bearlibterminal-ffi:+tk-enter+) t))) ; cancel
|
|
313
|
+ ;; Melee attack
|
|
314
|
+ ((equal prev-key bearlibterminal-ffi:+tk-m+)
|
|
315
|
+ (cond
|
|
316
|
+ ((= key bearlibterminal-ffi:+tk-up+) (bash-up player map))
|
|
317
|
+ ((= key bearlibterminal-ffi:+tk-down+) (bash-down player map))
|
|
318
|
+ ((= key bearlibterminal-ffi:+tk-right+) (bash-right player map))
|
|
319
|
+ ((= key bearlibterminal-ffi:+tk-left+) (bash-left player map))
|
|
320
|
+ ((= key bearlibterminal-ffi:+tk-enter+) t))) ; cancel
|
|
321
|
+ ;; Not a stateful command
|
|
322
|
+ (:otherwise
|
|
323
|
+ (cond
|
|
324
|
+ ((= key bearlibterminal-ffi:+tk-r+) t) ; Prepare for ranged
|
|
325
|
+ ((= key bearlibterminal-ffi:+tk-m+) t) ; Prepare for melee
|
|
326
|
+ ((= key bearlibterminal-ffi:+tk-enter+) t) ; idle
|
|
327
|
+ ((= key bearlibterminal-ffi:+tk-up+) (move-up player map))
|
|
328
|
+ ((= key bearlibterminal-ffi:+tk-down+) (move-down player map))
|
|
329
|
+ ((= key bearlibterminal-ffi:+tk-right+) (move-right player map))
|
|
330
|
+ ((= key bearlibterminal-ffi:+tk-left+) (move-left player map))
|
|
331
|
+ ((= key bearlibterminal-ffi:+tk-w+) (move-up viewport map))
|
|
332
|
+ ((= key bearlibterminal-ffi:+tk-a+) (move-left viewport map))
|
|
333
|
+ ((= key bearlibterminal-ffi:+tk-d+) (move-right viewport map))
|
|
334
|
+ ((= key bearlibterminal-ffi:+tk-s+) (move-down viewport map))
|
|
335
|
+ ((= key bearlibterminal-ffi:+tk-space+) (update-location viewport map (slot-value viewport 'location) (slot-value player 'location)))))))
|
179
|
336
|
|
180
|
337
|
(defun create-viewport (map)
|
181
|
338
|
(multiple-value-bind (width height) (get-window-size)
|
|
@@ -185,23 +342,48 @@
|
185
|
342
|
(setf height (game-map-height map)))
|
186
|
343
|
(make-instance 'viewport :width width :height height)))
|
187
|
344
|
|
|
345
|
+(defun end-of-turn-tasks (player map)
|
|
346
|
+ (declare (ignore player))
|
|
347
|
+ (maphash (lambda (location object)
|
|
348
|
+ (when (typep object 'mobile)
|
|
349
|
+ (if (>= 0 (slot-value object 'health))
|
|
350
|
+ (progn
|
|
351
|
+ (format t "~S~%" (slot-value object 'health))
|
|
352
|
+ (setf (slot-value object 'location) nil)
|
|
353
|
+ (remhash location (game-map-mobiles map)))
|
|
354
|
+ (end-of-turn object)))) (game-map-mobiles map)))
|
|
355
|
+
|
|
356
|
+(defun write-status-to-terminal (player prev-key)
|
|
357
|
+ (declare (ignore prev-key))
|
|
358
|
+ (multiple-value-bind (width height) (get-window-size)
|
|
359
|
+ (declare (ignore width))
|
|
360
|
+ (terminal-color (color-from-name "white"))
|
|
361
|
+ (terminal-print 0 (1- height) (format nil "H: ~d M: ~d"
|
|
362
|
+ (slot-value player 'health)
|
|
363
|
+ (slot-value player 'mana)))))
|
|
364
|
+
|
188
|
365
|
(defun main-loop ()
|
189
|
|
- (let ((player (make-instance
|
190
|
|
- 'player-character
|
191
|
|
- :location 0)))
|
192
|
|
- (loop with map = (initialize-map (make-instance 'game-map) player)
|
193
|
|
- with viewport = (create-viewport map)
|
194
|
|
- as key = (terminal-read) do
|
195
|
|
- (handle-input key map viewport player)
|
|
366
|
+ (loop with player = (make-instance 'player-character)
|
|
367
|
+ with map = (initialize-map (make-instance 'game-map) player)
|
|
368
|
+ with viewport = (create-viewport map)
|
|
369
|
+ with prev-key = nil
|
|
370
|
+ as key = (terminal-read) do
|
|
371
|
+ (when (handle-input key map viewport player prev-key)
|
|
372
|
+ (setf prev-key key)
|
196
|
373
|
(terminal-clear)
|
|
374
|
+ (unless (or (= key bearlibterminal-ffi:+tk-r+)
|
|
375
|
+ (= key bearlibterminal-ffi:+tk-m+))
|
|
376
|
+ (end-of-turn-tasks player map))
|
197
|
377
|
(write-map-to-terminal map viewport)
|
198
|
|
- (terminal-refresh)
|
199
|
|
- until (or (= key bearlibterminal-ffi:+tk-close+)
|
200
|
|
- (= key bearlibterminal-ffi:+tk-escape+)))))
|
|
378
|
+ (write-status-to-terminal player prev-key)
|
|
379
|
+ (terminal-refresh))
|
|
380
|
+ until (or (= key bearlibterminal-ffi:+tk-close+)
|
|
381
|
+ (= key bearlibterminal-ffi:+tk-escape+)
|
|
382
|
+ (eq (slot-value player 'location) nil))))
|
201
|
383
|
|
202
|
384
|
(defun start ()
|
203
|
385
|
(terminal-open)
|
204
|
|
- (terminal-set "window: size=100x40, title='Crypts and Corpses'")
|
|
386
|
+ (terminal-set "window: size=99x40, title='Crypts and Corpses'")
|
205
|
387
|
(terminal-set "font: ./fonts/DejaVuSansMono.ttf, size=16")
|
206
|
388
|
(intro-message)
|
207
|
389
|
(main-loop)
|