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