1 ;;--------------------------------------------------------------
2 ;; This stuff needs to be somewhere more generic
3 ;;--------------------------------------------------------------
5 (define pi (* 2 (acos 0)))
7 (define (xy->angle x y)
9 (cond ((> y 0) (atan 999999))
10 ((< y 0) (atan -999999))
16 (define (cone-in-range x y range)
17 (< (+ (* x x) (* y y)) (* range range)))
19 (define (angle-wrap angle)
20 (cond ((< angle 0) (angle-wrap (+ angle (* 2 pi))))
21 ((> angle (* 2 pi)) (angle-wrap (- angle (* 2 pi))))
24 (define (angle-diff baseangle testangle)
25 (- (angle-wrap (- testangle baseangle pi)) pi))
27 (define (cone-in-angle x y minangle maxangle)
28 (let ((tangle (xy->angle x y)))
29 (if (< (angle-diff minangle maxangle) 0)
30 (or (>= (angle-diff minangle tangle) 0)
31 (<= (angle-diff maxangle tangle) 0))
32 (and (>= (angle-diff minangle tangle) 0)
33 (<= (angle-diff maxangle tangle) 0))
36 (define (cone-get-edge x y inlist)
38 (cons (list x y) inlist)))
40 (define (cone-get-initial n inlist)
41 (cone-get-edge (- 0 n) 0
42 (cone-get-edge n 0 inlist)))
44 (define (cone-get-sides n m inlist)
46 (cone-get-sides n (+ m 1)
48 (cone-get-edge (- 0 n) m
49 (cone-get-edge n (- 0 m)
50 (cone-get-edge (- 0 n) (- 0 m) inlist))))
54 (define (cone-get-corners n inlist)
56 (cons (list (- 0 n) (- 0 n) )
57 (cone-get-edge (- 0 n) n inlist))))
59 (define (cone-get-box n)
62 (cone-get-initial n nil))))
64 (define (cone-check-cell origin minangle maxangle range proc cell)
67 (loc (list (car origin) (+ (cadr origin) x) (+ y (caddr origin)))))
68 (if (and (cone-in-range x y range)
69 (cone-in-angle x y minangle maxangle)
70 (kern-is-valid-location? loc)
76 (define (cone-handle-box origin minangle maxangle range proc list)
77 (if (not (null? list))
79 (cone-check-cell origin minangle maxangle range proc (car list))
80 (cone-handle-box origin minangle maxangle range proc (cdr list))
84 (define (cone-area-slice n origin minangle maxangle range proc)
87 (cone-handle-box origin minangle maxangle range proc
89 (cone-area-slice (+ n 1) origin minangle maxangle range proc)
92 (define (cone-area-effect origin angle range width proc)
93 (let ((minangle (angle-wrap (- angle (/ width 2))))
94 (maxangle (angle-wrap (+ angle (/ width 2)))))
95 (cone-area-slice 1 origin minangle maxangle range proc)
98 (define (cone-do-simple caster target range proc)
99 (let* ((origin (kern-obj-get-location caster))
100 (x (- (cadr target) (cadr origin)))
101 (y (- (caddr target) (caddr origin))))
102 (cone-area-effect origin (xy->angle x y) range (/ pi 2) proc)
105 (define (cone-simple caster range proc)
106 (let ((origin (kern-obj-get-location caster))
107 (target (get-target-loc caster range)))
110 (let ((x (- (cadr target) (cadr origin)))
111 (y (- (caddr target) (caddr origin))))
112 (cone-area-effect origin (xy->angle x y) range (/ pi 2) proc))
115 (define (powers-field-generic loc f_type duration proc)
116 (let* ((finduration (if (< duration 1) 1 duration))
117 (afield (kern-mk-field f_type finduration)))
118 (if (can-be-dropped? afield loc cant)
120 (kern-obj-put-at afield loc)
122 (if (not (null? proc))
123 (for-each proc (kern-get-objects-at loc))
125 ;; remove fields on semi-bad locations
126 (if (or (< duration 1)
127 (not (can-be-dropped? afield loc no-drop)))
128 (kern-obj-remove afield)
134 (define (mk-basic-cone-proc origin objfx field-type leaveproc)
135 (define (dropfield loc)
136 (if (kern-obj-put-at (kern-mk-obj field-type 1) loc)))
137 (define (is-my-field? kobj) (eqv? field-type (kern-obj-get-type kobj)))
138 (define (cleanfields loc)
139 (let ((fields (filter is-my-field? (kern-get-objects-at loc)))
140 (duration (leaveproc)))
141 (cond ((null? fields) nil)
143 (kern-obj-remove (car fields))))
144 (if (and (terrain-ok-for-field? loc)
146 (kern-obj-put-at (kern-mk-field field-type duration) loc))
149 (if (kern-in-los? origin loc)
150 (if (null? field-type)
151 (if (not (null? objfx))
152 (map objfx (kern-get-objects-at loc))
154 (powers-field-generic loc field-type (leaveproc) objfx)
158 (define (mk-cone-proc-sfx origin objfx sfx field-type leaveproc)
159 (define (dropfield loc)
160 (if (kern-obj-put-at (kern-mk-obj field-type 1) loc)))
161 (define (is-my-field? kobj) (eqv? field-type (kern-obj-get-type kobj)))
162 (define (cleanfields loc)
163 (let ((fields (filter is-my-field? (kern-get-objects-at loc)))
164 (duration (leaveproc)))
165 (cond ((null? fields) nil)
167 (kern-obj-remove (car fields))))
168 (if (and (terrain-ok-for-field? loc)
170 (kern-obj-put-at (kern-mk-field field-type duration) loc))
173 (kern-sound-play-at sfx origin)
174 (if (kern-in-los? origin loc)
175 (if (null? field-type)
176 (if (not (null? objfx))
177 (map objfx (kern-get-objects-at loc))
179 (powers-field-generic loc field-type (leaveproc) objfx)
183 ;; todo- inc these in line-cell to simplify?
184 (define (line-do-proc proc location)
185 (if (kern-is-valid-location? location)
190 (define (line-diag place x y dx dy proc)
191 (let* ((curx (floor x))
193 (newx (floor (+ x (/ dx 2))))
194 (newy (floor (+ y (/ dy 2))))
195 (location (loc-mk place newx newy)))
196 (if (or (not (equal? newx curx))
197 (not (equal? newy cury)))
198 (if (kern-is-valid-location? location)
206 (define (line-cell place x y dx dy endx endy proc)
207 (let ((curx (floor x))
210 (if (equal? (abs dx) 1) (line-diag place x y 0 (* dy 1.0000001) proc) (line-diag place x y (* dx 1.0000001) 0 proc))
211 (line-do-proc proc (loc-mk place curx cury))
212 (not (and (equal? curx endx) (equal? cury endy)))
213 (if (equal? (abs dx) 1) (line-diag place (+ x dx) (+ y dy) 0 (* dy -0.9999999) proc) (line-diag place (+ x dx) (+ y dy) (* dx -0.9999999) 0 proc))
215 (line-cell place (+ x dx) (+ y dy) dx dy endx endy proc))
218 ;; todo will fail on looping maps
219 (define (line-draw place startx starty stopx stopy proc)
220 (if (and (equal? startx stopx)
221 (equal? starty stopy))
222 (line-do-proc proc (loc-mk place startx starty))
223 (let* ((xdif (- stopx startx))
224 (ydif (- stopy starty))
225 (div (if (> (abs xdif) (abs ydif)) (abs xdif) (abs ydif)))
228 (line-cell place (+ startx 0.5) (+ starty 0.5) dx dy stopx stopy proc)
231 (define (cast-missile-proc kchar ktarg ktype)
232 (kern-fire-missile ktype
233 (kern-obj-get-location kchar)
234 (kern-obj-get-location ktarg)))
236 ;;--------------------------------------------------------------
238 ;;--------------------------------------------------------------
240 (define (contest-of-skill offense defense)
241 (let ((oprob (+ offense 1))
242 (tprob (number->string (+ offense defense 2))))
243 (println "oprob=" oprob " tprob=" tprob " offense=" offense " defense=" defense)
244 (if (< (kern-dice-roll (string-append "1d" tprob))
251 ;;--------------------------------------------------------------
253 ;;--------------------------------------------------------------
256 ;todo add area effect for high powered users?
257 (define (powers-awaken caster ktarg power)
258 (kern-obj-remove-effect ktarg ef_sleep)
259 (kern-char-set-sleep ktarg #f)
262 (define (powers-blink-range power)
265 (define (powers-blink caster ktarg power)
266 (if (kern-place-is-passable ktarg caster)
267 (kern-obj-relocate caster ktarg nil)
268 (kern-log-msg "Blink Failed: Impassable terrain")
272 (define (powers-blink-party-range power)
273 (cond ((< power 20) (* power 0.75))
276 (define (powers-blink-party caster ktarg power)
277 (if (kern-place-is-passable ktarg (kern-char-get-party caster))
278 (kern-obj-relocate (kern-char-get-party caster) ktarg nil)
279 (kern-log-msg "Blink Failed: Impassable terrain")
283 (define (powers-charm-range power)
286 ; (Only) failed charm pisses off target
287 (define (powers-charm caster target power)
289 ((has-charm-immunity? target)
290 (msg-log-visible (kern-obj-get-location target) (kern-obj-get-name target) " immune to charm")
294 (occ-ability-magicdef target))
295 (let ((tloc (kern-obj-get-location target)))
296 (kern-obj-add-effect target
298 (charm-mk (kern-being-get-current-faction caster)))
299 (kern-map-flash-sprite s_heart (loc-x tloc) (loc-y tloc))
300 (msg-log-visible tloc (kern-obj-get-name target) " is charmed")
304 (msg-log-visible (kern-obj-get-location target) (kern-obj-get-name target) " resists charm")
305 (kern-harm-relations target caster)
311 ;; Weaker than charm, this turns the target's alignment to be that of
312 ;; monsters. The monster faction is hostile to most others, so the player can
313 ;; use it against outlaws, cave goblins, etc.
314 (define (powers-beastly-illusion caster target power)
315 (cond ((has-charm-immunity? target)
316 (msg-log-visible (kern-obj-get-location target) (kern-obj-get-name target) " resists illusion")
318 ((contest-of-skill (+ power 1) (occ-ability-magicdef target))
319 (let ((tloc (kern-obj-get-location target)))
320 (kern-obj-add-effect target ef_charm (charm-mk faction-monster))
321 (kern-map-flash-sprite s_heart (loc-x tloc) (loc-y tloc))
322 (msg-log-visible tloc (kern-obj-get-name target) " is deluded")
324 (else (msg-log-visible (kern-obj-get-location target) (kern-obj-get-name target) " resists illusion"))
326 (kern-harm-relations target caster)
330 (define (powers-clone-range power)
333 (define (powers-clone caster target power)
334 (let* ((clone (kern-obj-clone target))
335 (loc (pick-loc (kern-obj-get-location target) clone)))
336 (kern-being-set-base-faction clone (kern-being-get-current-faction caster))
337 ;; clone has equipment of original
339 (kern-obj-add-to-inventory clone ktype 1))
340 (kern-char-get-arms target)
342 (kern-char-arm-self clone)
343 ;; clone level based on of weaker of caster or original
344 (if (> (kern-char-get-level target) (kern-char-get-level caster))
345 (kern-char-set-level clone (+ 1 (* (kern-char-get-level caster) 0.75)))
346 (kern-char-set-level clone (+ 1 (* (kern-char-get-level target) 0.75)))
348 ;; clone may not have more hp/mana than original
349 (if (> (kern-char-get-hp clone) (kern-char-get-hp target))
350 (kern-char-set-hp clone (kern-char-get-hp target)))
351 (if (> (kern-char-get-mana clone) (kern-char-get-mana target))
352 (kern-char-set-mana clone (kern-char-get-mana target)))
353 ;;(kern-char-set-ai clone 'spell-sword-ai)
354 (kern-obj-put-at clone loc)
358 (define (powers-cone-flamespray caster ktarg power)
359 (let ((damage (mkdice 2 (min (floor (+ 2 (/ power 2))) 10))))
360 (define (flambe-all kobj)
361 (if (and (is-being? kobj)
362 (not (has-fire-immunity? kobj)))
363 (kern-obj-inflict-damage kobj "burning" (kern-dice-roll damage) caster)
365 (cone-do-simple caster ktarg 3.3
366 (mk-basic-cone-proc (kern-obj-get-location caster) flambe-all F_fire (lambda () 0))
370 (define (powers-cone-basic-leaveproc balance width)
372 (- (kern-dice-roll (mkdice 1 width)) balance)))
374 ;; this may need to be limited...
375 (define (powers-cone-basic-range power)
378 (define (powers-cone-fire-range power)
381 (define (powers-cone-energy caster ktarg power)
382 (let ((damage (mkdice (floor (/ power 2)) 3)))
383 (define (energize-all kobj)
385 (kern-obj-inflict-damage kobj "shocked" (kern-dice-roll damage) caster)
387 (cone-do-simple caster ktarg (powers-cone-basic-range power)
388 (mk-basic-cone-proc (kern-obj-get-location caster) energize-all F_energy
389 (powers-cone-basic-leaveproc 40 (+ 30 (* 4 power)))
393 ;; check for: no unintended victims
394 ;; at least 2 fire vulnerable targets
395 (define (powers-cone-fire-test caster targloc power)
396 ;;(println "test cone fire")
397 (let ((viable-targets (list 0))
399 (define (checktarg kobj)
401 ;; test for hostility and known (ie permanent) fire resistance
402 (if (is-hostile? kobj caster)
403 (if (not (has-effect? kobj ef_fire_immunity))
404 (set-car! viable-targets (+ (car viable-targets) 1))
406 (set-car! shot-ok #f)
410 (cone-do-simple caster targloc (powers-cone-fire-range power)
411 (mk-basic-cone-proc (kern-obj-get-location caster) checktarg nil nil)
413 ;;(println "tested cone fire " (car shot-ok) " " (car viable-targets))
415 (> (car viable-targets )1))
418 (define (powers-cone-fire caster targloc power)
419 (let ((damage (mkdice (floor (/ power 2)) 3)))
420 (define (burn-all kobj)
421 (if (and (is-being? kobj)
422 (not (has-fire-immunity? kobj)))
424 (kern-obj-inflict-damage kobj "burning" (kern-dice-roll damage) caster)
425 (kern-harm-relations kobj caster)
428 (cone-do-simple caster targloc (powers-cone-fire-range power)
429 (mk-cone-proc-sfx (kern-obj-get-location caster) burn-all sound-fireblast F_fire
430 (powers-cone-basic-leaveproc 30 (+ 20 (* 5 power)))
436 (define (powers-cone-poison caster ktarg power)
437 (let ((damage (mkdice 1 (floor (/ power 4)))))
438 (define (poison-all kobj)
442 (if (is-poisoned? kobj)
444 (kern-harm-relations kobj caster)
445 (kern-harm-relations kobj caster)
446 (kern-harm-relations kobj caster)
447 (kern-harm-relations kobj caster)
448 (kern-obj-inflict-damage kobj "poison" (kern-dice-roll damage) caster)
451 (cone-do-simple caster ktarg (powers-cone-basic-range power)
452 (mk-basic-cone-proc (kern-obj-get-location caster) poison-all F_poison
453 (powers-cone-basic-leaveproc 60 (+ 40 (* 3 power)))
457 (define (powers-cone-sleep caster ktarg power)
458 (let ((damage (mkdice 1 (floor (/ power 4)))))
459 (define (sleep-all kobj)
462 (kern-harm-relations kobj caster)
463 (if (contest-of-skill
465 (occ-ability-magicdef kobj))
468 (cone-do-simple caster ktarg (powers-cone-basic-range power)
469 (mk-basic-cone-proc (kern-obj-get-location caster) sleep-all F_sleep
470 (powers-cone-basic-leaveproc 40 (+ 30 (* 4 power)))
474 ;todo limit to some range?
475 (define (powers-confuse caster unused power)
476 (define (confuse kchar)
477 (if (contest-of-skill
479 (+ (occ-ability-magicdef kchar) 2))
480 (kern-being-set-base-faction kchar (random-faction))
482 (map confuse (all-hostiles caster))
485 (define (powers-cure-poison caster ktarg power)
486 (kern-obj-remove-effect ktarg ef_poison)
487 (if (< (kern-dice-roll "1d25") power)
488 (kern-obj-remove-effect ktarg ef_disease))
491 ;todo currently only checks topmost item
492 (define (powers-detect-traps caster ktarg power)
493 (let ((traps (ifccall ktarg 'get-traps)))
495 (kern-log-msg (kern-obj-get-name caster)
496 " does not detect any traps")
500 (trap-set-detected! trap #t)
501 (kern-log-msg (kern-obj-get-name caster)
502 " detects a " (trap-name trap) " trap!")
508 ;again, a bit of range for powerful users?
509 (define (powers-dispel-field caster ktarg power)
510 (kern-print "Dispelled field!\n")
511 (kern-obj-remove ktarg)
515 ;; todo saving throw vs caster power for different effects?
516 (define (powers-dispel-magic caster ktarg power)
517 (effects-dispel-magic ktarg)
520 (define (powers-disarm-traps kchar ktarg power)
522 (traps (filter (lambda (trap)
523 (and (trap-detected? trap)
524 (not (trap-tripped? trap))))
525 (ifccall ktarg 'get-traps)))
527 ;; Check if any unprocessed traps remaining
531 ((not (handles? ktarg 'rm-traps))
532 (kern-log-msg "Traps can't be removed!")
539 (dc (trap-avoid-dc trap))
540 (roll (kern-dice-roll "1d20"))
541 (bonus (kern-dice-roll (string-append "1d" (number->string power))))
545 (> (+ roll bonus) dc)
547 ;; Success - disarm the trap
548 (kern-log-msg (kern-obj-get-name kchar) " ^c+gdisarms^c- a " (trap-name trap) " trap!")
549 (trap-set-tripped! trap #t)
553 ;; Failure - trip the trap (kchar will get another roll
554 ;; to avoid the damage)
555 (trap-trigger trap ktarg kchar)
561 (define (powers-fear caster unused power)
562 (define (repel kchar)
563 (msg-log-visible (kern-obj-get-location kchar) (kern-obj-get-name kchar) " flees in terror!")
564 (kern-map-flash-sprite s_magicflash (loc-x tloc) (loc-y tloc))
565 (kern-char-set-fleeing kchar #t)
567 (define (try-repel kchar)
568 (if (contest-of-skill
570 (occ-ability-magicdef kchar))
572 (map try-repel (all-hostiles caster))
576 ; fields would be a lot more useful if a wall was created instead of one square
577 ; (length based on caster strength of course)
578 ; I need a 'line' utility anyway, perhaps a ui along the lines of (select center point) (select end point)
579 ; -> draw line from centre to end and opposite side
580 (define (powers-field-range power)
586 (define (powers-field-length power)
589 (define (powers-field-wall start stop f_type duration leng proc)
590 (let ((lengremaining (list leng)))
591 (define (put-field location delta)
592 (powers-field-generic location f_type duration proc)
593 (set-car! lengremaining (- (car lengremaining) delta))
594 (> (car lengremaining) 0)
596 (line-draw (loc-place start) (loc-x start) (loc-y start) (loc-x stop) (loc-y stop) put-field)
599 (define (powers-field-fire-wall caster start stop power)
600 (define (do-burn kobj)
601 (if (and (kern-obj-is-char? kobj)
602 (not (has-fire-immunity? kobj)))
603 (kern-obj-inflict-damage kobj "burning" (kern-dice-roll "2d3+2") caster)
605 (powers-field-wall start stop F_fire (+ 20 (kern-dice-roll (mkdice 1 power))) (powers-field-length power) do-burn)
608 (define (powers-field-energy-wall caster start stop power)
609 (define (do-burn kobj)
610 (if (kern-obj-is-char? kobj)
611 (kern-obj-inflict-damage kobj "shocked" (kern-dice-roll "2d8") caster)
613 (powers-field-wall start stop F_energy (+ 20 (kern-dice-roll (mkdice 2 power))) (powers-field-length power) do-burn)
616 (define (powers-field-poison-wall caster start stop power)
617 (define (do-burn kobj)
618 (if (and (kern-obj-is-char? kobj)
619 (not (has-poison-immunity? kobj)))
622 (kern-harm-relations kobj caster)
623 (kern-harm-relations kobj caster)
626 (powers-field-wall start stop F_poison (+ 10 (kern-dice-roll (mkdice 1 power))) (powers-field-length power) do-burn)
629 (define (powers-field-sleep-wall caster start stop power)
630 (define (do-burn kobj)
631 (if (and (kern-obj-is-char? kobj)
632 (not (has-sleep-immunity? kobj)))
634 (kern-harm-relations kobj caster)
638 (powers-field-wall start stop F_sleep (+ 15 (kern-dice-roll (mkdice 1 power))) (powers-field-length power) do-burn)
641 (define (powers-field-energy caster ktarg power)
642 (kern-obj-put-at (kern-mk-field F_energy (+ 20 (kern-dice-roll (mkdice 2 power)))) ktarg)
645 (define (powers-field-fire caster ktarg power)
646 (kern-obj-put-at (kern-mk-field F_fire (+ 20 (kern-dice-roll (mkdice 1 power)))) ktarg)
649 (define (powers-field-poison caster ktarg power)
650 (kern-obj-put-at (kern-mk-field F_poison (+ 10 (kern-dice-roll (mkdice 1 power)))) ktarg)
653 (define (powers-field-sleep caster ktarg power)
654 (kern-obj-put-at (kern-mk-field F_sleep (+ 15 (kern-dice-roll (mkdice 1 power)))) ktarg)
657 (define (powers-field-energy-weak caster ktarg power)
658 (powers-field-generic ktarg F_energy (+ 5 (kern-dice-roll (mkdice 1 (ceiling (/ power 2))))) apply-lightning)
661 (define (powers-field-fire-weak caster ktarg power)
662 (powers-field-generic ktarg F_fire (+ 5 (kern-dice-roll (mkdice 1 (ceiling (/ power 3))))) burn)
665 (define (powers-field-poison-weak caster ktarg power)
666 (powers-field-generic ktarg F_poison (+ 3 (kern-dice-roll (mkdice 1 (ceiling (/ power 3))))) apply-poison)
669 (define (powers-field-sleep-weak caster ktarg power)
670 (powers-field-generic ktarg F_sleep (+ 4 (kern-dice-roll (mkdice 1 (ceiling (/ power 3))))) apply-sleep)
673 (define (powers-fireball-range power)
676 ;; returns true if the location is ok
677 (define (powers-fireball-collateral-check caster targloc apower)
678 ;;(println "fireball check")
679 (let ((place (loc-place targloc))
682 (define (checkloc kloc)
686 (and (kern-obj-is-char? kobj)
687 (not (is-hostile? kobj caster))
690 (kern-get-objects-at kloc)
693 (define (checkoff xoff yoff)
694 (let ((kloc (mk-loc place (+ x xoff) (+ y yoff))))
695 (if (kern-is-valid-location? kloc)
716 (define (powers-fireball caster ktarg apower)
717 ;;(println "fireball")
718 (define (fireball-damage-dice power)
719 (if (> power 3) (string-append (number->string (floor (/ power 2))) "d3")
721 (define (is-my-field? kobj) (eqv? F_fire (kern-obj-get-type kobj)))
722 (define (cleanfields kplace x y)
723 (let ((kloc (mk-loc kplace x y)))
724 (if (kern-is-valid-location? kloc)
725 (let ((fields (filter is-my-field? (kern-get-objects-at kloc))))
726 (cond ((null? fields) nil)
728 (kern-obj-remove (car fields))))))))
729 (define (do-fireball-hit kplace x y damdf damdi)
730 (define (fire-damage kobj)
731 (if (kern-obj-is-char? kobj)
733 (kern-log-msg "Burning!")
734 (if (not (has-fire-immunity? kobj))
735 (kern-obj-inflict-damage kobj "burning" (kern-dice-roll damdf) caster)
736 (if (not (null? damdi))
737 (kern-obj-inflict-damage kobj "impact" (kern-dice-roll damdi) caster))
739 ;;(kern-obj-apply-damage kobj "burning" (kern-dice-roll damdf))
741 (let ((kloc (mk-loc kplace x y)))
742 (if (kern-is-valid-location? kloc)
744 (kern-obj-put-at (kern-mk-obj F_fire 1) kloc)
746 (for-each fire-damage
747 (kern-get-objects-at kloc))
749 (let* ((targchar (get-being-at ktarg))
750 (damf (fireball-damage-dice apower))
751 (dami (if (> apower 5) (fireball-damage-dice (/ apower 3)) nil)))
752 (define (do-fireball-effect kplace x y)
753 (kern-sound-play-at sound-explode (mk-loc kplace x y))
754 (do-fireball-hit kplace x y damf dami)
755 (if (> apower 10) (let ((apower (- apower 5))
756 (damf (fireball-damage-dice apower))
757 (dami (if (> apower 5) (fireball-damage-dice (/ apower 3)) nil)))
758 (do-fireball-hit kplace (+ x 1) y damf dami)
759 (do-fireball-hit kplace (- x 1) y damf dami)
760 (do-fireball-hit kplace x (+ y 1) damf dami)
761 (do-fireball-hit kplace x (- y 1) damf dami)
762 (if (> apower 10) (let ((apower (- apower 5))
763 (damf (fireball-damage-dice apower))
764 (dami (if (> apower 5) (fireball-damage-dice (/ apower 3)) nil)))
765 (do-fireball-hit kplace (+ x 1) (+ y 1) damf dami)
766 (do-fireball-hit kplace (- x 1) (+ y 1) damf dami)
767 (do-fireball-hit kplace (+ x 1) (- y 1) damf dami)
768 (do-fireball-hit kplace (- x 1) (- y 1) damf dami)
769 (cleanfields kplace (+ x 1) (+ y 1))
770 (cleanfields kplace (- x 1) (+ y 1))
771 (cleanfields kplace (+ x 1) (- y 1))
772 (cleanfields kplace (- x 1) (- y 1))
774 (cleanfields kplace (+ x 1) y)
775 (cleanfields kplace (- x 1) y)
776 (cleanfields kplace x (+ y 1))
777 (cleanfields kplace x (- y 1))
779 (cleanfields kplace x y)
782 (kern-log-msg (kern-obj-get-name caster)
784 (kern-log-msg (kern-obj-get-name caster)
785 " hurls a fireball at "
786 (kern-obj-get-name targchar)))
788 (lambda (kmissile kuser ktarget kplace x y)
789 (do-fireball-effect kplace x y)
792 (kern-sound-play-at sound-missile (kern-obj-get-location caster))
793 (kern-sound-play-at sound-missile ktarg)
794 (kern-fire-missile t_mfireball
795 (kern-obj-get-location caster)
799 ;todo high power should go to user specified gate
800 (define (powers-gate-travel caster ktarg power)
801 ;; Fix for bug 1738251, which involved summoning gates over magically locked
802 ;; doors: check passability. Use the passability of the caster as a
803 ;; reasonable estimate for the passability of the gate.
804 (if (not (kern-place-is-passable ktarg caster))
806 (let ((gate (summon-moongate 'ord)))
807 (kern-obj-put-at gate ktarg)
811 (define (powers-great-light caster ktarg power)
815 (light-apply-new ktarg (+ 6000 (* 50 power))))
818 ;todo should the messages be in the ui part?
819 (define (powers-great-heal kchar ktarg power)
820 (kern-log-msg (kern-obj-get-name kchar)
821 " casts a great healing spell on "
822 (if (eqv? kchar ktarg)
824 (kern-obj-get-name ktarg)))
826 (+ 10 power (kern-dice-roll "2d20")
827 (kern-dice-roll (mkdice 4 power))))
830 ;todo should the messages be in the ui part?
831 (define (powers-heal kchar ktarg power)
832 (kern-log-msg (kern-obj-get-name kchar)
833 " casts a healing spell on "
834 (if (eqv? kchar ktarg)
836 (kern-obj-get-name ktarg)))
838 (+ 2 (kern-dice-roll "1d10")
839 (kern-dice-roll (mkdice 2 power))))
842 ;todo vary duration with power
843 (define (powers-invisibility kchar ktarg power)
844 (kern-obj-add-effect ktarg ef_invisibility nil)
847 ;todo hack in something for xp & hostility
848 (define (powers-kill kchar ktarg)
849 (kern-log-msg (kern-obj-get-name kchar)
851 (kern-obj-get-name ktarg))
852 (kern-sound-play-at sound-missile (kern-obj-get-location kchar))
853 (kern-sound-play-at sound-missile (kern-obj-get-location ktarg))
854 (cast-missile-proc kchar ktarg t_deathball)
857 (define (powers-light caster ktarg power)
861 (light-apply-new ktarg (+ 400 (* 5 power))))
864 (define (powers-lightning-range power)
867 ;; todo will fail on looping maps
868 (define (powers-lightning-collateral-check caster targloc apower)
869 ;;(println "checkzap")
870 (let* ((range (powers-lightning-range apower))
871 (casterloc (kern-obj-get-location caster))
872 (targrange (+ 1 (kern-get-distance targloc casterloc)))
873 (rangemult (if (> targrange 0) (ceiling (/ range targrange)) 0))
874 (dx (* rangemult (- (loc-x targloc) (loc-x casterloc))))
875 (dy (* rangemult (- (loc-y targloc) (loc-y casterloc))))
876 (endx (+ (loc-x casterloc) dx))
877 (endy (+ (loc-y casterloc) dy))
879 (range-ok (> range targrange))
881 (define (check-loc location delta)
882 (cond ((equal? location casterloc) #t)
883 ((> (kern-get-distance location casterloc) range) #f)
886 (and (kern-obj-is-char? kobj)
887 (not (is-hostile? kobj caster))
890 (kern-get-objects-at location)
894 (else (set-car! shot-ok #f) #f)
896 (if (and range-ok (> rangemult 0))
898 (line-draw (loc-place targloc) (loc-x casterloc) (loc-y casterloc) endx endy check-loc)
905 (define (powers-lightning caster targloc apower)
907 (let ((targets (list nil))
908 (dam (mkdice (floor (+ 1 (/ apower 3))) 4))
911 (lambda (kmissile kuser ktarget kplace x y unused)
913 (targchar (get-being-at (mk-loc kplace x y)))
915 (if (not (null? targchar))
916 (set-car! targets (cons targchar (car targets)))
920 (kern-sound-play sound-lightning)
921 (kern-fire-missile-to-max t_lightning_bolt (powers-lightning-range apower)
922 (kern-obj-get-location caster)
925 (if (not (null? (car targets)))
928 (kern-log-msg (kern-obj-get-name zappee) " shocked!")
929 (kern-obj-inflict-damage zappee "shocked" (kern-dice-roll dam) caster)
936 (define (powers-lock caster ktarg power)
937 ((kobj-ifc ktarg) 'lock ktarg caster)
940 (define (powers-lock-magic caster ktarg power)
941 ((kobj-ifc ktarg) 'magic-lock ktarg caster)
944 (define (powers-locate caster ktarg power)
945 (let ((loc (kern-obj-get-location caster)))
946 (kern-log-msg "You are in " (kern-place-get-name (car loc))
947 " at [x=" (cadr loc) " y=" (caddr loc) "]"))
950 (define (powers-magic-missile-range power)
954 (define (powers-magic-missile kchar ktarg power)
955 (kern-sound-play-at sound-missile (kern-obj-get-location kchar))
956 (kern-sound-play-at sound-missile (kern-obj-get-location ktarg))
957 (kern-log-msg (kern-obj-get-name kchar)
958 " fires magic missile at "
959 (kern-obj-get-name ktarg))
960 (if (cast-missile-proc kchar ktarg t_magicarrow_p)
965 (/ (occ-ability-magicdef ktarg) 10)
967 (damagedice (string-append
968 (number->string (if (> apower 0) apower 1))
970 (kern-obj-inflict-damage ktarg
971 "magic" (kern-dice-roll damagedice) kchar)))
974 (define (powers-negate-magic caster ktarg power)
975 (kern-add-magic-negated (kern-dice-roll
976 (mkdice 3 (floor (+ (/ power 3) 1)))))
979 (define (powers-paralyse caster ktarg power)
980 (if (and (can-paralyze? ktarg)
983 (occ-ability-magicdef ktarg)))
984 (kern-obj-add-effect ktarg ef_paralyze nil))
987 (define (powers-poison-range power)
990 ;todo contest to resist? to-hit roll required? power based initial damage?
991 ;note instant hostility - you cant just cause someone to slowly die and say
993 (define (powers-poison-effect caster ktarg power)
994 (if (and (kern-obj-is-char? ktarg)
997 (if (contest-of-skill
999 (occ-ability-dexdefend ktarg))
1000 (apply-poison ktarg)
1001 (kern-log-msg (kern-obj-get-name ktarg) " avoids poison!")
1005 (define (powers-poison caster ktarg power)
1006 (define (do-poison-effect kmissile kuser ktarget kplace x y dam)
1007 (on-hit-target ktarget dam
1008 (lambda (obj) (powers-poison-effect kuser obj (+ power 10))))
1009 (on-hit-nontarget ktarget (loc-mk kplace x y) dam
1010 (lambda (obj) (powers-poison-effect kuser obj power)))
1012 (temp-ifc-set do-poison-effect)
1013 (kern-log-msg (kern-obj-get-name caster)
1014 " hurls poison missile at "
1015 (kern-obj-get-name ktarg))
1016 (kern-harm-relations ktarg caster)
1017 (kern-harm-relations ktarg caster)
1018 (kern-harm-relations ktarg caster)
1019 (kern-harm-relations ktarg caster)
1020 (kern-sound-play-at sound-missile (kern-obj-get-location caster))
1021 (kern-sound-play-at sound-missile (kern-obj-get-location ktarg))
1022 (cast-missile-proc caster ktarg t_mpoison_bolt)
1025 ;todo duration based on power?
1026 (define (powers-protect caster ktarg power)
1027 (let ((party (kern-char-get-party caster)))
1029 (kern-obj-add-effect caster ef_protection nil)
1030 (kern-obj-add-effect party ef_protection nil)
1035 ;todo duration based on power?
1036 (define (powers-protect-vs-fire caster ktarg power)
1037 (kern-obj-add-effect ktarg ef_temporary_fire_immunity nil)
1040 ;todo duration based on power?
1041 (define (powers-protect-vs-poison caster ktarg power)
1042 (kern-obj-add-effect ktarg ef_temporary_poison_immunity nil)
1045 ;todo duration based on power?
1046 (define (powers-protect-vs-poison-all caster ktarg power)
1047 (let ((party (kern-char-get-party caster)))
1049 (kern-obj-add-effect caster ef_temporary_poison_immunity nil)
1050 (kern-obj-add-effect party ef_temporary_poison_immunity nil)
1055 (define (powers-quickness caster dir power)
1056 (kern-add-quicken (kern-dice-roll
1057 (mkdice 3 (floor (+ (/ power 3) 1)))))
1060 ;note is different scenarios, could have other uses
1061 (define (powers-raise-lost-area caster loc power)
1062 (let ((kobjs (filter can-raise-vessel?
1063 (kern-get-objects-at loc))))
1064 (if (not (null? kobjs))
1065 (let ((kgen (car kobjs)))
1066 (signal-kobj kgen 'raise kgen caster)
1070 ;resurrect should have side effects, diminishing with power
1071 (define (powers-resurrect caster ktarg power)
1072 (cond ((is-dead? ktarg)
1073 (kern-char-resurrect ktarg)
1080 (define (powers-reveal caster ktarg power)
1081 (kern-add-reveal (* power 4))
1085 (define (powers-sleep-target-range power)
1088 (define (powers-sleep-apply target power)
1089 (if (contest-of-skill power (occ-ability-magicdef target))
1091 (msg-log-visible (kern-obj-get-location target) (kern-obj-get-name target) " slept")
1092 (apply-sleep target))
1094 (msg-log-visible (kern-obj-get-location target) (kern-obj-get-name target) " resists sleep"))
1097 (define (powers-sleep-target caster ktarg power)
1098 (powers-sleep-apply ktarg (+ power 6))
1099 (kern-harm-relations ktarg caster)
1102 ;todo limit to some range?
1103 (define (powers-sleep-area caster ktarg power)
1104 (let ((hostiles (all-hostiles caster)))
1105 (define (trysleep target)
1106 (powers-sleep-apply target (+ power 3))
1108 (cond ((null? hostiles) result-ok)
1110 (map trysleep hostiles)
1113 (define (powers-smoke-range power)
1116 (define (powers-smoke-field caster ktarg apower)
1117 (fields-smoke-apply (loc-place ktarg) (loc-x ktarg) (loc-y ktarg) apower)
1121 ;todo duration based on power?
1122 (define (powers-spider-calm caster ktarg power)
1123 (kern-obj-add-effect ktarg ef_spider_calm nil)
1126 (define (powers-summon targetloc quantity typegen levelgen faction)
1127 (define (run-loop count done)
1128 (if (<= count 0) done
1129 (let* ((knpc (spawn-npc (typegen) (levelgen)))
1130 (loc (pick-loc targetloc knpc)))
1133 (kern-obj-dec-ref knpc)
1136 (kern-being-set-base-faction knpc faction)
1137 (kern-obj-set-temporary knpc #t)
1138 (kern-obj-put-at knpc loc)
1139 (run-loop (- count 1) 1)
1141 (run-loop quantity 0))
1143 (define (powers-summon-simple-levelgen power)
1145 (+ (floor (+ (* power 0.2) 1
1147 (mkdice 3 (floor (+ (* power 0.2) 1))))
1150 (define (powers-summon-single-type type)
1155 ;todo enable remote summoning for high power?
1156 (define (powers-summon-medium-size caster ktarg power type-tag)
1157 (let ((spower (floor (+ (/ power 4) 1))))
1158 (powers-summon (kern-obj-get-location caster)
1159 (kern-dice-roll (mkdice 1 spower))
1160 (powers-summon-single-type type-tag)
1161 (powers-summon-simple-levelgen power)
1162 (kern-being-get-base-faction caster))
1165 ;todo enable remote summoning for high power?
1166 (define (powers-summon-snake caster ktarg power)
1167 (powers-summon-medium-size caster ktarg power 'snake)
1170 ;todo enable remote summoning for high power?
1171 (define (powers-summon-spider caster ktarg power)
1172 (powers-summon-medium-size caster ktarg power 'giant-spider)
1175 ;todo enable remote summoning for high power?
1176 (define (powers-summon-wolf caster ktarg power)
1177 (powers-summon-medium-size caster ktarg power 'wolf)
1180 ;todo enable remote summoning for high power?
1181 (define (powers-summon-small caster ktarg power type-tag)
1182 (let ((spower (floor (+ (/ power 4) 1))))
1183 (powers-summon (kern-obj-get-location caster)
1184 (kern-dice-roll (mkdice 2 spower))
1185 (powers-summon-single-type type-tag)
1186 (powers-summon-simple-levelgen power)
1187 (kern-being-get-base-faction caster))
1190 ;todo enable remote summoning for high power?
1191 (define (powers-summon-insect caster ktarg power)
1192 (powers-summon-small caster ktarg power 'insect)
1195 ;todo enable remote summoning for high power?
1196 (define (powers-summon-rat caster ktarg power)
1197 (powers-summon-small caster ktarg power 'rat)
1200 ;todo enable remote summoning for high power?
1201 (define (powers-summon-bat caster ktarg power)
1202 (powers-summon-small caster ktarg power 'bat)
1205 ;todo enable remote summoning for high power?
1206 (define (powers-summon-undead caster ktarg power)
1207 (let ((spower (floor (+ (/ power 4) 1))))
1208 (powers-summon (kern-obj-get-location caster)
1209 (kern-dice-roll (mkdice 1 spower))
1211 (random-select (list 'skeletal-warrior 'skeletal-spear-thrower 'ghast)))
1212 (powers-summon-simple-levelgen power)
1213 (kern-being-get-base-faction caster))
1217 (define (powers-summon-slime caster ktarg power)
1218 (let ((spower (floor (+ (/ power 4) 1))))
1219 (powers-summon (kern-obj-get-location caster)
1220 (kern-dice-roll (mkdice 1 spower))
1221 (powers-summon-single-type 'green-slime)
1222 (powers-summon-simple-levelgen power)
1223 (kern-being-get-base-faction caster))
1228 (define (powers-telekinesis-range power)
1231 ;todo damage/knock away critters?
1232 ;should fail on no handler squares rather than aborting?
1233 (define (powers-telekinesis caster ktarg power)
1234 ((kobj-ifc ktarg) 'handle ktarg caster)
1237 (define (powers-timestop caster dir power)
1238 (kern-add-time-stop (kern-dice-roll
1239 (mkdice 3 (floor (+ (/ power 3) 1)))))
1242 ; a few things needed here:
1243 ; check for visibility before messages
1244 ; no player specific messages
1245 ; only hits hostiles
1246 ; area of effect based on power
1247 ; 'turned' as an effect? [so it shows on description] or maybe fleeing should show...
1248 (define (powers-turn-undead caster unused power)
1249 (define (is-undead-char? kobj)
1250 (and (obj-is-char? kobj)
1251 (species-is-undead? (kern-char-get-species kobj)))
1253 (define (repel kchar)
1254 (if (contest-of-skill
1256 (occ-ability-magicdef kchar))
1257 (let ((tloc (kern-obj-get-location kchar)))
1258 (kern-map-flash-sprite s_magicflash (loc-x tloc) (loc-y tloc))
1259 (msg-log-visible tloc (kern-obj-get-name kchar) " turned")
1260 (kern-char-set-fleeing kchar #t)
1263 (msg-log-visible (kern-obj-get-location kchar) (kern-obj-get-name kchar) " resists")
1267 (let* ((all-kobjs (all-hostiles caster))
1268 (all-undead-combatants (filter is-undead-char? all-kobjs)))
1269 (map repel all-undead-combatants)
1273 ;todo limit to some (large) range?
1274 (define (powers-tremor caster unused power)
1275 (let ((damdice (mkdice 1 power))
1276 (foes (all-hostiles caster)))
1277 (define (tremor kchar)
1278 (cond ((kern-char-is-asleep? kchar) (kern-char-set-sleep kchar #f))
1279 ((> (kern-dice-roll "1d4") 1)
1280 (kern-map-set-jitter #t)
1282 (kern-char-set-sleep kchar #t)
1283 (kern-obj-inflict-damage kchar "knocked down" (kern-dice-roll damdice) caster))
1285 (define (loop n kchar)
1289 (loop (- n 1) kchar))))
1290 (define (wakeup kchar) (kern-char-set-sleep kchar #f))
1291 (kern-log-enable #f)
1292 (map kern-obj-inc-ref foes)
1294 (loop (+ 1 (floor (/ power 4))) foes)
1297 (map kern-obj-dec-ref foes)
1298 (map wakeup (kern-place-get-beings (loc-place (kern-obj-get-location caster))))
1299 (kern-log-enable #t)
1303 (define (powers-unlock caster ktarg power)
1304 (println "power:" power)
1305 (let ((dc ((kobj-ifc ktarg) 'get-unlock-dc ktarg caster)))
1309 (let ((roll (kern-dice-roll "1d20"))
1310 (bonus (kern-dice-roll (string-append "1d" (number->string power)))))
1311 (println "roll:" roll)
1312 (println "bonus:" bonus)
1313 (cond ((or (= roll 20)
1314 (> (+ roll bonus ) dc))
1315 (if ((kobj-ifc ktarg) 'unlock ktarg caster)
1318 (else result-failed))))))
1320 (define (powers-unlock-magic caster ktarg power)
1321 (if ((kobj-ifc ktarg) 'magic-unlock ktarg caster)
1325 (define (powers-view caster ktarg power)
1326 (kern-map-center-camera (kern-obj-get-location caster))
1327 (kern-map-set-peering #t)
1329 (kern-print "Hit a key when done gazing...\n")
1331 (kern-map-set-peering #f)
1335 (define (powers-web-range power)
1338 ;note defense is dodge, not magicdef
1339 (define (powers-web caster target power)
1340 (define (do-web-effect kplace x y)
1341 (let* ((loc (mk-loc kplace x y))
1342 (targchar (get-being-at loc)))
1343 (if (not (null? targchar))
1345 (if (contest-of-skill
1347 (occ-ability-dexdefend targchar))
1349 (kern-harm-relations kobj caster)))
1350 (if (and (< (kern-dice-roll "1d20") power)
1351 (terrain-ok-for-field? loc))
1352 (kern-obj-put-at (kern-mk-obj web-type 1) loc))
1354 (let ((targchar (get-being-at target)))
1355 (if (null? targchar)
1356 (kern-log-msg (kern-obj-get-name caster)
1358 (kern-log-msg (kern-obj-get-name caster)
1360 (kern-obj-get-name targchar)))
1362 (lambda (kmissile kplace x y)
1363 (do-web-effect kplace x y)
1365 (kern-sound-play-at sound-missile (kern-obj-get-location caster))
1366 (kern-sound-play-at sound-missile target)
1367 (kern-fire-missile t_mweb
1368 (kern-obj-get-location caster)
1373 (define (powers-wind-change caster dir power)
1374 (kern-set-wind dir (+ 10 (kern-dice-roll (mkdice (* 2 power) 6))))
1377 (define (powers-xray caster dir power)
1378 (kern-add-xray-vision (kern-dice-roll
1379 (mkdice 10 (floor (+ (/ power 3) 1)))))
1382 ;; vttjo - "Vectors to tiles jumped over"
1383 (define (powers-jump-vttjo dx dy)
1385 (cond ((= dy -1) (list (cons 1 0) (cons 1 -1)))
1386 ((= dy 0) (list (cons 1 0)))
1387 ((= dy 1) (list (cons 1 0) (cons 1 1)))
1390 (cond ((= dy -2) (list (cons 0 -1) (cons 1 -1)))
1391 ((= dy 2) (list (cons 0 1) (cons 1 1)))
1394 (cond ((= dy -2) (list (cons 0 -1)))
1395 ((= dy 2) (list (cons 0 1)))
1398 (cond ((= dy -2) (list (cons 0 -1) (cons -1 -1)))
1399 ((= dy 2) (list (cons 0 1) (cons -1 1)))
1402 (cond ((= dy -1) (list (cons -1 0) (cons -1 -1)))
1403 ((= dy 0) (list (cons -1 0)))
1404 ((= dy 1) (list (cons -1 0) (cons -1 1)))
1408 (define (powers-jump caster ktarg power)
1409 (let ((cloc (kern-obj-get-location caster)))
1411 ;; special case: when jumping 1 (or fewer tiles) use normal movement mode
1413 (cond ((not (kern-place-move-is-passable? cloc ktarg caster))
1414 (kern-log-msg "Jump failed: blocked!")
1417 (kern-obj-relocate caster ktarg nil)
1420 (cond ((not (kern-place-is-passable ktarg caster))
1421 (kern-log-msg "Jump Failed: Impassable terrain")
1424 (let* ((vect (loc-diff cloc ktarg))
1427 (kplace (loc-place (kern-obj-get-location caster))))
1428 (cond ((and (<= (abs dx) 1) (<= (abs dy) 1))
1431 ;; normal case: jump of more than 1 tile
1432 (kern-obj-set-mmode caster mmode-jump)
1433 (let* ((vttjo (powers-jump-vttjo dx dy))
1435 (cond ((foldr (lambda (val vtt)
1437 (not (kern-place-is-passable
1439 (+ (car vtt) (loc-x cloc))
1440 (+ (cdr vtt) (loc-y cloc)))
1443 (kern-log-msg "Jump failed: blocked!")
1446 (kern-obj-relocate caster ktarg nil)
1447 (kern-obj-add-effect caster ef_fatigue nil)
1449 (kern-obj-set-mmode caster nil)
1452 (define (powers-sprint caster ktarg power)
1453 ;; hokay... first let's get the path from here to there
1454 (let* ((origin (kern-obj-get-location caster))
1455 (kplace (loc-place origin))
1456 (path (line (loc-x origin) (loc-y origin)
1457 (loc-x ktarg) (loc-y ktarg)))
1459 ;; and now, for each point on the path, let's move the dude there and apply
1460 ;; any terrain/field effects. The way should be passable (unless we do
1461 ;; something weird like along the way trigger a mech which throws up a
1462 ;; wall, in which case I guess that's an advantage of having the sprint
1463 ;; skill ;) Note that the dude may die along the way due to tile effects,
1464 ;; so keep a ref count just to be safe and check for death in the move-dude
1466 (define (move-dude ok xy)
1468 (let ((loc (loc-mk kplace (car xy) (cdr xy))))
1469 (cond ((or (not (passable? loc caster))
1471 (println loc " impassable")
1474 ((not (kern-char-is-dead? caster))
1475 (kern-obj-relocate caster loc nil)
1477 (kern-place-apply-tile-effects kplace caster)
1481 (kern-obj-inc-ref caster)
1482 (foldr move-dude #t (cdr path))
1483 (kern-obj-dec-ref caster)
1485 (kern-obj-add-effect caster ef_fatigue nil)
1488 ;; Roll to even make the attempt, then roll to see if you get stuck.
1489 (define (powers-wriggle caster ktarg power)
1490 (kern-obj-set-mmode caster mmode-wriggle)
1491 (cond ((not (kern-place-move-is-passable? (kern-obj-get-location caster)
1493 (kern-log-msg "Wriggle failed: blocked!")
1494 (kern-obj-set-mmode caster nil)
1497 (kern-obj-relocate caster ktarg nil)
1498 (kern-obj-set-mmode caster nil)
1499 (cond ((passable? (kern-obj-get-location caster) caster)
1500 (kern-log-msg "(Was that really necessary?)")
1503 ((not (check-roll dc-avoid-stuck (occ-thief-dice-roll caster)))
1504 (kern-obj-add-effect caster ef_stuck nil)
1511 (define (powers-butcher caster ktarg power)
1512 (if ((kobj-ifc ktarg) 'butcher ktarg caster)
1516 (define (powers-pickpocket kactor ktarg power)
1517 (cond ((contest-of-skill power (occ-ability-thief ktarg))
1518 (let ((ktype (kern-ui-select-item ktarg)))
1519 (cond ((null? ktype) result-no-effect)
1521 (kern-obj-remove-from-inventory ktarg ktype 1)
1522 (if (ktype-can? ktype 'receive)
1523 ((kern-type-get-gifc ktype) 'receive ktype kactor)
1525 (kern-obj-add-to-inventory kactor ktype 1)
1529 (harm-relations kactor ktarg)