1(define (mk-ambush-gob x y w h msg) (list x y w h msg))
2(define (ambush-x gob) (list-ref gob 0))
3(define (ambush-y gob) (list-ref gob 1))
4(define (ambush-w gob) (list-ref gob 2))
5(define (ambush-h gob) (list-ref gob 3))
6(define (ambush-msg gob) (list-ref gob 4))
7
8;; ----------------------------------------------------------------------------
9;; mk-monster-generator-ifc -- make an interface for a monster generator in a
10;; town or dungeon
11;; ----------------------------------------------------------------------------
12(define (mk-monster-generator-ifc threshold max mk-monster is-monster?)
13  (define (roll-to-encounter)
14    (>= (modulo (random-next) 1000) threshold))
15  (define (not-too-many kobj)
16    (< (length (filter is-monster?
17                       (kern-place-get-beings (loc-place
18                                               (kern-obj-get-location kobj)))))
19       max))
20  (define (player-out-of-sight? gen)
21    (define (can-see? members)
22      (if (null? members)
23          #f
24          (or (kern-in-los? (kern-obj-get-location (car members))
25                            (kern-obj-get-location gen))
26              (can-see? (cdr members)))))
27    (not (can-see? (kern-party-get-members (kern-get-player)))))
28  (define (generate gen)
29    (if (and (roll-to-encounter)
30             (not-too-many gen)
31             (player-out-of-sight? gen)
32             (not (occupied? (kern-obj-get-location gen))))
33        (kern-obj-put-at (mk-monster)
34                         (kern-obj-get-location gen))))
35  (ifc '()
36       (method 'exec generate)))
37
38
39;; ----------------------------------------------------------------------------
40;; mk-wilderness-monster-generator -- make an object type for spawning random
41;; encounters
42;; ----------------------------------------------------------------------------
43(define (mk-wilderness-monster-generator tag threshold max party faction
44                                         vehicle)
45  (mk-obj-type tag                                  ;; tag
46               nil                                  ;; name
47               nil                                  ;; sprite
48               layer-none                           ;; layer
49               (mk-wilderness-monster-generator-ifc threshold  ;; ifc
50                                                    max
51                                                    party
52                                                    faction
53                                                    vehicle)))
54
55;; ----------------------------------------------------------------------------
56;; mk-wilderness-ambush-generator -- make an object type for spawning random
57;; ambush encounters
58;; ----------------------------------------------------------------------------
59(define (mk-wilderness-ambush-generator-type tag threshold party faction)
60  (mk-obj-type tag                ;; tag
61               nil                ;; name
62               nil                ;; sprite
63               layer-none         ;; layer
64               (mk-wilderness-ambush-generator-ifc threshold  ;; ifc
65                                                   max
66                                                   party
67                                                   faction)))
68
69;; ----------------------------------------------------------------------------
70;; mk-wilderness-ambush-generator -- make an instance of a wilderness ambush
71;; generator type which monitors the given rectangle
72;; ----------------------------------------------------------------------------
73(define (mk-wilderness-ambush-generator type x y w h msg)
74  (bind (kern-obj-set-visible (kern-mk-obj type 1) #f)
75        (mk-ambush-gob x y w h msg)))
76
77;;----------------------------------------------------------------------------
78;; mk-monster-generator -- make an instance of a town or dungeon monster
79;; generator
80;;----------------------------------------------------------------------------
81(define (mk-monster-generator tag threshold max mk-monster is-monster?)
82  (mk-obj-type tag                                  ;; tag
83               nil                                  ;; name
84               nil                                  ;; sprite
85               layer-none                           ;; layer
86               (mk-monster-generator-ifc threshold  ;; ifc
87                                         max
88                                         mk-monster
89                                         is-monster?)))
90
91;;----------------------------------------------------------------------------
92;; Newer, improveder monster generator
93;;----------------------------------------------------------------------------
94(define (mongen2-mk thresh max is-monster-tag mk-monster-tag mk-args
95                    out-of-sight-only? targ-loc)
96  (list thresh max is-monster-tag mk-monster-tag mk-args out-of-sight-only?
97        targ-loc))
98(define (mongen2-thresh gen) (car gen))
99(define (mongen2-max gen) (cadr gen))
100(define (mongen2-mk-monster gen)
101  (apply (eval (cadddr gen)) (list-ref gen 4)))
102(define (mongen2-out-of-sight-only? gen) (list-ref gen 5))
103(define (mongen2-targ-loc gen)
104  (let ((tag-loc (list-ref gen 6)))
105    (if (null? tag-loc)
106        nil
107        (eval-loc tag-loc))))
108
109(define (mongen2-exec kgen)
110  (let* ((gen (kobj-gob-data kgen))
111        (targ-loc (if (null? (mongen2-targ-loc gen))
112                      (kern-obj-get-location kgen)
113                      (mongen2-targ-loc gen)))
114        )
115    (define (roll-to-encounter)
116      (>= (modulo (random-next) 1000) (mongen2-thresh gen)))
117    (define (not-too-many?)
118      (< (length (filter (eval (caddr gen))
119                         (kern-place-get-beings (loc-place
120                                                 (kern-obj-get-location
121                                                  kgen)))))
122         (mongen2-max gen)))
123    (if (and (roll-to-encounter)
124             (not-too-many?)
125             (not (occupied? targ-loc))
126             (or (not (mongen2-out-of-sight-only? gen))
127                 (player-out-of-sight? kgen)))
128        (begin
129          (kern-obj-put-at (mongen2-mk-monster gen)
130                           (if (null? targ-loc)
131                               (kern-obj-get-location kgen)
132                               targ-loc))))))
133
134(define mongen2-ifc
135  (ifc nil
136       (method 'exec mongen2-exec)))
137
138(mk-obj-type 't_mongen2 nil nil layer-none mongen2-ifc)
139
140(define (mk-mongen2 thresh max is-monster? mk-monster mk-args)
141  (bind (kern-obj-set-visible (kern-mk-obj t_mongen2 1) #f)
142        (mongen2-mk thresh max is-monster? mk-monster mk-args #t nil)))
143
144;; same, only doesn't care if player is in sight
145(define (mk-edge-gen thresh max is-monster? mk-monster mk-args)
146  (bind (kern-obj-set-visible (kern-mk-obj t_mongen2 1) #f)
147        (mongen2-mk thresh max is-monster? mk-monster mk-args #f nil)))
148
149
150;;----------------------------------------------------------------------------
151;; Guard Generator
152;;
153;; Monitors a list of posts (x y) and guards. If a post is empty it creates
154;; a new guard and assigns it to that post.
155;;----------------------------------------------------------------------------
156(define (ggen-mk freq is-guard-tag? mk-guard-tag posts)
157  (list freq is-guard-tag? mk-guard-tag posts))
158(define (ggen-freq ggen) (car ggen))
159(define (ggen-get-is-guard-tag ggen) (cadr ggen))
160(define (ggen-get-mk-guard-tag ggen) (caddr ggen))
161(define (ggen-posts ggen) (cadddr ggen))
162
163(define (ggen-exec kgen)
164
165  ;;(display "ggen-exec")(newline)
166
167  (let ((ggen (kobj-gob-data kgen)))
168
169    (define (time-to-check?)
170      ;;(display "time-to-check")(newline)
171      (< (modulo (random-next)
172                 100)
173         (ggen-freq ggen)))
174
175    (define (fill-empty-posts)
176      ;;(display "fill-empty-posts")(newline)
177      (let ((guards (filter (eval (ggen-get-is-guard-tag ggen))
178                            (kern-place-get-beings (loc-place
179                                                    (kern-obj-get-location
180                                                     kgen))))))
181        ;;(display "guard:")(display guards)(newline)
182
183        (define (post-filled? post)
184          ;;(display "post-filled?:")(display post)(newline)
185          (foldr (lambda (a kguard)
186                   (or a
187                       (equal? post
188                               (guard-post (kobj-gob-data kguard)))))
189                 #f
190                 guards))
191
192        (define (fill-post post)
193          ;;(display "fill-post:")(display post)(newline)
194          (let ((kguard (post-guard (apply (eval (ggen-get-mk-guard-tag ggen))
195                                           nil)
196                                    (car post)
197                                    (cadr post)))
198                (loc (kern-obj-get-location kgen)))
199            (kern-obj-put-at kguard loc)))
200
201        (map (lambda (post)
202               (if (not (post-filled? post))
203                   (fill-post post)))
204             (ggen-posts ggen))))
205
206    (if (and (time-to-check?)
207             (player-out-of-sight? kgen)
208             (not (occupied? (kern-obj-get-location kgen))))
209        (fill-empty-posts))))
210
211(define ggen-ifc
212  (ifc nil
213       (method 'exec ggen-exec)))
214
215(mk-obj-type 't_ggen nil nil layer-none ggen-ifc)
216
217(define (mk-post x y) (list x y))
218
219(define (mk-ggen freq is-guard? mk-guard posts)
220  (bind (kern-obj-set-visible (kern-mk-obj t_ggen 1) #f)
221        (ggen-mk freq is-guard? mk-guard posts)))
222
223;;----------------------------------------------------------------------------
224;; Special generator which responds to the 'raise signal generated by a "Vas
225;; Uus Ylem" spell invocation on a wilderness location
226;;----------------------------------------------------------------------------
227(define (raise-mk proc-tag args) (list proc-tag args))
228(define (raise-proc-tag raise) (car raise))
229(define (raise-args raise) (cadr raise))
230
231(define (raise-exec kraise)
232  (display "raise-exec")(newline)
233  (let ((raise (kobj-gob-data kraise)))
234    (apply (eval (raise-proc-tag raise)) (raise-args raise))
235    (kern-obj-remove kraise)))
236
237(define raise-ifc
238  (ifc nil
239       (method 'raise raise-exec)))
240
241(mk-obj-type 't_raise_listener nil nil layer-none raise-ifc)
242
243(define (can-raise-vessel? kobj)
244  (eqv? (kern-obj-get-type kobj)
245        t_raise_listener))
246
247(define (mk-raise-listener proc-tag args)
248  (bind (kern-mk-obj t_raise_listener 1)
249        (raise-mk proc-tag args)))
250
251;;----------------------------------------------------------------------------
252;; Random treasure drops
253;;----------------------------------------------------------------------------
254(define (treasure-prob tr) (car tr))
255(define (treasure-type tr) (cadr tr))
256(define (treasure-quan tr) (caddr tr))
257
258(define treasure-list
259  (list
260   (list 32 't_gold_coins 5)
261   (list 32 't_arrow 5)
262   (list 32 't_bolt 5)
263   (list 32 't_food 1)
264   (list 8  't_heal_potion 1)
265   (list 8  't_mana_potion 1)
266   (list 4  't_cure_potion 1)
267   (list 4  't_torch 1)
268   (list 2  't_gem 1)
269   (list 4  't_picklock 1)
270   ))
271
272(define treasure-modulus
273  (foldr (lambda (n entry) (+ n (car entry)))
274         0
275         treasure-list))
276
277(define (treasure-lookup index)
278  (define (search n list)
279    (if (null? list)
280        (error "treasure-lookup not found")
281        (let ((next (+ n (treasure-prob (car list)))))
282          (if (<= index next)
283              (car list)
284              (search next (cdr list))))))
285  (search 0 treasure-list))
286
287;; pick-random-treasure -- returns a (quantity 'type) list
288(define (pick-random-treasure)
289  (let ((trsr (treasure-lookup (modulo (random-next) treasure-modulus))))
290    (list (+ 1 (modulo (random-next) (treasure-quan trsr)))
291          (treasure-type trsr)
292          )))
293
294;; eval-treasure-entry -- given a list of type (quantity 'type) it returns a
295;; list of type (quantity type)
296(define (eval-treasure-entry entry)
297  (list (car entry) (eval (cadr entry))))
298
299;; mk-random-treasure -- makes a treasure object
300(define (mk-random-treasure)
301  (let ((pair (eval-treasure-entry (pick-random-treasure))))
302    (kern-mk-obj (car pair)
303                 (+ 1 (modulo (random-next)
304                              (cadr pair))))))
305
306;; mk-treasure-heap -- creates a list of n treasure objects
307(define (mk-treasure-heap n)
308  (if (> n 0)
309      (cons (mk-random-treasure)
310            (mk-treasure-heap (- n 1)))))
311
312;; mk-quoted-treasure-list -- returns a list of n (quantity 'type) lists
313;; suitable in corpses and other gobs
314(define (mk-quoted-treasure-list n)
315  (if (> n 0)
316      (cons (pick-random-treasure)
317            (mk-quoted-treasure-list (- n 1)))))
318
319;;----------------------------------------------------------------------------
320;; spawn-pt -- generates a monster when triggered externally. The level of the
321;; monsters is calculated on-the-fly based on the player party level. The
322;; faction and npc type mix are determined by the "factory", which is passed to
323;; the spawn-pt constructor.
324(define (spawn-pt-mk npct-tag)
325  (list 'spawn-pt npct-tag))
326(define (spawn-pt-npct-tag sppt) (cadr sppt))
327
328(define (spawn-pt-exec ksppt)
329  (let* ((sppt (gob ksppt)))
330    (let ((npc (spawn-npc (spawn-pt-npct-tag sppt) (calc-level))))
331      (kern-obj-put-at npc (kern-obj-get-location ksppt))
332      npc)
333    ))
334
335(define spawn-pt-ifc
336  (ifc nil
337       (method 'on spawn-pt-exec)))
338
339(mk-obj-type 't_spawn_pt nil nil layer-none spawn-pt-ifc)
340
341(define (spawn-pt npct-tag)
342  (bind (kern-obj-set-visible (kern-mk-obj t_spawn_pt 1) #f)
343        (spawn-pt-mk npct-tag)))
344
345;;----------------------------------------------------------------------------
346;; guard-pt -- a spawn pt which creates an npc with a guard post
347(define (guard-pt-exec kgen)
348  (let ((kchar (spawn-pt-exec kgen)))
349    (npcg-set-post! (gob kchar)
350                    (cdr (kern-obj-get-location kgen)))
351    kchar))
352
353(define guard-pt-ifc
354  (ifc nil
355       (method 'on guard-pt-exec)))
356
357(mk-obj-type 't_guard_pt nil nil layer-none guard-pt-ifc)
358
359(define (guard-pt npct-tag)
360  (bind (kern-obj-set-visible (kern-mk-obj t_guard_pt 1) #f)
361        (spawn-pt-mk npct-tag)))
362
363;;----------------------------------------------------------------------------
364;; step-pt -- triggered when a kchar steps on it; spawns one or more npcs at
365;; different locations and prints some flavor text
366
367(define (step-pt-mk msg time sets)
368  (list 'step-pt msg time sets))
369(define (step-pt-msg sppt) (cadr sppt))
370(define (step-pt-time sppt) (caddr sppt))
371(define (step-pt-sets sppt) (cadddr sppt))
372(define (step-pt-set-time! sppt val) (set-car! (cddr sppt) val))
373
374(define (set-npct-tag set) (car set))
375(define (set-x set) (cadr set))
376(define (set-y set) (caddr set))
377
378(define (step-pt-exec ksppt kbeing)
379  (let ((sppt (gob ksppt))
380        (kplace (loc-place (kern-obj-get-location ksppt))))
381    (cond ((time-to-respawn? (step-pt-time sppt))
382           (kern-log-msg (step-pt-msg sppt))
383           (step-pt-set-time! sppt (kern-get-time))
384           (for-each (lambda (set)
385                       (kern-obj-put-at (spawn-npc (set-npct-tag set)
386                                                   (calc-level))
387                                        (mk-loc kplace
388                                                (set-x set)
389                                                (set-y set))))
390                     (step-pt-sets sppt)))
391    )))
392
393(define step-pt-ifc
394  (ifc nil
395       (method 'step step-pt-exec)))
396
397(mk-obj-type 't_step_pt nil nil layer-mechanism step-pt-ifc)
398
399(define (step-pt msg . sets)
400  (bind (kern-obj-set-visible (kern-mk-obj t_step_pt 1) #f)
401        (step-pt-mk msg
402                    (map - game-start-time
403                         (time-mk 0 0 0 1 1 1))
404                    sets)))
405
406
407;;----------------------------------------------------------------------------
408;; custom-pt -- a generic 'on trigger which is run by the respawn manager
409(define custom-pt-ifc
410  (ifc nil
411       (method 'on on-trig-exec)))
412
413(mk-obj-type 't_custom_pt nil nil layer-none custom-pt-ifc)
414
415(define (custom-pt proc-tag . args)
416  (bind (kern-obj-set-visible (kern-mk-obj t_custom_pt 1) #f)
417        (trig-mk proc-tag args)))
418
419;;----------------------------------------------------------------------------
420;; time-to-respawn? -- checks if an hour and a minute has passed
421(define (time-to-respawn? oldtime)
422  (let ((curtime (kern-get-time)))
423    (or (> (time-year curtime) (time-year oldtime))
424        (> (time-month curtime) (time-month oldtime))
425        (> (time-week curtime) (time-week oldtime))
426        (>= (- (time-day curtime) (time-day oldtime)) 2)
427        (and (> (time-day curtime) (time-day oldtime))
428             (>= (time-hour curtime) (time-hour oldtime))))))
429
430;;----------------------------------------------------------------------------
431;; monman -- monster manager object
432
433(define (monman-mk time)
434  (list 'monman time))
435(define (monman-time mm) (cadr mm))
436(define (monman-set-time! mm val) (set-car! (cdr mm) val))
437
438(define (monman-exec kmm)
439  (let ((mm (gob kmm))
440        (kplace (loc-place (kern-obj-get-location kmm))))
441    (define (cleanup-old-spawn)
442      (map kern-obj-remove
443           (filter (lambda (kbeing)
444                     (or (kbeing-was-spawned? kbeing)
445                         (char-is-gate-guard? kbeing)))
446                   (kern-place-get-beings kplace)))
447      )
448
449    (define (trigger-spawn-pt sppt)
450      (signal-kobj sppt 'on sppt nil))
451
452    (define (respawn)
453      (monman-set-time! mm (kern-get-time))
454      (map trigger-spawn-pt
455           (kplace-get-objects-of-type kplace t_spawn_pt))
456      (map trigger-spawn-pt
457           (kplace-get-objects-of-type kplace t_guard_pt))
458      (map trigger-spawn-pt
459           (kplace-get-objects-of-type kplace t_custom_pt))
460      )
461
462    (if (time-to-respawn? (monman-time mm))
463        (and (cleanup-old-spawn)
464             (respawn)))
465
466  ))
467
468(define monman-ifc
469  (ifc nil
470       (method 'on monman-exec)))
471
472(mk-obj-type 't_monman nil nil layer-none monman-ifc)
473
474(define (mk-monman)
475  (bind (kern-obj-set-visible (kern-mk-obj t_monman 1) #f)
476        (monman-mk (map - game-start-time
477                        (time-mk 0 0 0 1 1 1)))))
478