chiark / gitweb /
hack
[dnd] / dice.lisp
1 ;;;
2
3 (defun d (n &optional (k 1) &key (bias 0) best worst)
4   (let ((rolls (sort (loop repeat k
5                            collect (1+ (max 0 (min (1- n)
6                                                    (+ (random n) bias)))))
7                      #'<)))
8     (reduce #'+ (cond (best (subseq rolls (- k best)))
9                       (worst (subseq rolls 0 worst))
10                       (t rolls)))))
11
12 (defvar *dnd-alist* nil)
13
14 (defun do-lookup (name default defaultp)
15   (let ((item (assoc name *dnd-alist*)))
16     (cond (item (cdr item))
17           (defaultp default)
18           (t (error "Missing required item ~S." name)))))
19
20 (defun lookup-list (name &optional (default nil defaultp))
21   (do-lookup name default defaultp))
22
23 (defun lookup (name &optional (default nil defaultp))
24   (car (do-lookup name (list default) defaultp)))
25
26 (defun hp-from-hd (&optional (hd (lookup-list :hit-dice)))
27   (destructuring-bind (dice &key (plus 0) (stars 0)) hd
28     (declare (ignore stars))
29     (+ (cond ((zerop dice) 0)
30              ((= dice 1/8) 1)
31              ((= dice 1/4) (d 2))
32              ((= dice 1/2) (d 4))
33              ((and (integerp dice) (plusp dice)) (d 8 dice))
34              (t (error "Bad hit dice ~S." hd)))
35        plus)))
36
37 (defun hd-table-lookup (hd table)
38   (flet ((hd<= (a b)
39            (let ((aa (if (consp a) (car a) a))
40                  (bb (if (consp b) (car b) b)))
41              (or (< aa bb)
42                  (and (= aa bb)
43                       (or (consp a)
44                           (not (consp b))))))))
45     (loop for ((lo . hi) . rest) in table
46           when (and (hd<= lo hd)
47                     (hd<= hd hi))
48           return rest
49           finally (return nil))))
50
51 (let ((xp-table '(((  0    . (0 +))    5     1)
52                   ((  1    .  1)      10     3)
53                   ((( 1 +) . (1 +))   15     4)
54                   ((  2    .  2)      20     5)
55                   ((( 2 +) . (2 +))   25    10)
56                   ((  3    .  3)      30    15)
57                   ((( 3 +) . (3 +))   50    25)
58                   ((  4    .  4)      75    50)
59                   ((( 4 +) . (4 +))  125    75)
60                   ((  5    .  5)     175   125)
61                   ((( 5 +) . (5 +))  225   175)
62                   ((  6    .  6)     275   225)
63                   ((( 6 +) . (6 +))  350   300)
64                   ((  7    .  7)     450   400)
65                   ((( 7 +) . (7 +))  550   475)
66                   ((  8    .  8)     650   550)
67                   ((( 8 +) . (8 +))  775   625)
68                   ((  9    .  9)     900   700)
69                   ((( 9 +) . 10)    1000   750)
70                   (((10 +) . 11)    1100   800)
71                   (((11 +) . 12)    1250   875)
72                   (((12 +) . 13)    1350   950)
73                   (((13 +) . 14)    1500  1000)
74                   (((14 +) . 15)    1650  1050)
75                   (((15 +) . 16)    1850  1100)
76                   (((16 +) . 17)    2000  1150)
77                   (((17 +) . 18)    2125  1350)
78                   (((18 +) . 19)    2250  1550)
79                   (((19 +) . 20)    2375  1800)
80                   (((20 +) . 21)    2500  2000))))
81   (defun xp-from-hd (&optional (hd (lookup-list :hit-dice)))
82     (destructuring-bind (dice &key (plus 0) (stars 0)) hd
83       (multiple-value-bind (hd-base hd-plus)
84           (cond ((zerop plus) (values dice 0))
85                 ((plusp plus) (values dice 1))
86                 ((minusp plus) (values (1- dice) 1)))
87         (let ((result (hd-table-lookup (if (zerop hd-plus)
88                                            hd-base
89                                            (list hd-base '+))
90                                      xp-table)))
91           (if result
92               (destructuring-bind (base bonus) result
93                 (+ base (* stars bonus)))
94               (let ((steps (+ hd-base -21 hd-plus)))
95                 (+ 2500
96                    (* 250 steps)
97                    (* (+ 2000 (* 250 steps)) stars)))))))))
98
99 (let ((thac0-table '(((  0      .   1) . 19)
100                      ((( 1 . +) .   2) . 18)
101                      ((( 2 . +) .   3) . 17)
102                      ((( 3 . +) .   4) . 16)
103                      ((( 4 . +) .   5) . 15)
104                      ((( 5 . +) .   6) . 14)
105                      ((( 6 . +) .   7) . 13)
106                      ((( 7 . +) .   8) . 12)
107                      ((( 8 . +) .   9) . 11)
108                      ((( 9 . +) .  11) . 10)
109                      (((11 . +) .  13) .  9)
110                      (((13 . +) .  15) .  8)
111                      (((15 . +) .  17) .  7)
112                      (((17 . +) .  19) .  6)
113                      (((19 . +) .  21) .  5)
114                      (((21 . +) .  23) .  4)
115                      (((23 . +) .  25) .  3)
116                      (((25 . +) .  27) .  2)
117                      (((27 . +) .  29) .  1)
118                      (((29 . +) .  31) .  0)
119                      (((31 . +) .  33) . -1)
120                      (((33 . +) .  35) . -2))))
121   (defun thac0-from-hd (&optional (hd (lookup-list :hit-dice)))
122     (destructuring-bind (dice &key (plus 0) (stars 0)) hd
123       (declare (ignore stars))
124       (multiple-value-bind (hd-base hd-plus)
125           (cond ((zerop plus) (values dice 0))
126                 ((plusp plus) (values dice 1))
127                 ((minusp plus) (values (1- dice) 1)))
128         (or (hd-table-lookup (if (zerop hd-plus)
129                                  hd-base
130                                  (list hd-base '+))
131                              thac0-table)
132             -3)))))
133
134 (defparameter monster-template
135   `((:hit-dice :required)
136     (:thac0 :list ,#'thac0-from-hd)
137     (:hit-points :list ,#'hp-from-hd)
138     (:experience-points :list ,#'xp-from-hd)))
139
140 (defun apply-template (def tpl)
141   (flet ((run (tag func)
142            (unless (assoc tag *dnd-alist*)
143              (push (cons tag (funcall func)) *dnd-alist*))))
144     (loop with *dnd-alist* = def
145           for (tag key . tail) in tpl do
146           (case key
147             (:required (lookup-list tag))
148             (:eval (run tag (car tail)))
149             (:list (run tag (lambda () (list (funcall (car tail))))))
150             (t (run tag key)))
151           finally (return *dnd-alist*))))
152
153 (defun percentp (pc) (< (random 100) pc))
154
155 (defun bag (&rest things)
156   (loop for i in things
157         when i collect i))
158
159 (defun tagged-bag (tag &rest things)
160   (let ((bag (apply #'bag things)))
161     (and bag (cons tag bag))))
162
163 (defun choose (&rest things)
164   (let ((n 0)
165         (it nil))
166     (do ((things things (cddr things)))
167         ((null things) it)
168       (let ((k (car things)))
169         (incf n k)
170         (when (and (plusp n) (< (random n) k))
171           (setf it (cadr things)))))))
172
173 (defun choose-uniformly (&rest things)
174   (let ((n 0) (it nil))
175     (do ((things things (cdr things)))
176         ((null things) it)
177         (incf n)
178         (when (< (random n) 1)
179           (setf it (car things))))))
180
181 (defmacro pick (&rest clauses)
182   `(funcall (choose ,@(loop for (n . clause) in clauses
183                            collect n
184                            collect `(lambda () ,@clause)))))
185
186 (defconstant druid-spells
187   #((detect-danger faerie-fire locate predict-weather)
188     (heat-metal obscure produce-fire warp-wood)
189     (call-lightning hold-animal protection-from-poison water-breathing)
190     (control-temperature-10-ft-radius plant-door protection-from-lightning
191      summon-animals)
192     (anti-plant-shell control-winds dissolve pass-plant)
193     (anti-animal-shell summon-weather transport-through-plants turn-wood)
194     (creeping-doom metal-to-wood summon-elemental weather-control)))
195
196 (defconstant cleric-spells
197   #((cure-light-wounds detect-evil detect-magic light protection-from-evil
198      purify-food-and-water remove-fear resist-cold)
199     (bless find-traps hold-person resist-fire silence-15-ft-radius
200      slow-poison snake-charm speak-with-animal)
201     (continual-light cure-blindness cure-disease growth-of-animals
202      locate-object remove-curse speak-with-the-dead striking)
203     (animate-dead create-water cure-serious-wounds dispel-magic
204      neutralize-poison protection-from-evil-10-ft-radius speak-with-plants
205      sticks-to-snakes)
206     (commune create-food cure-critical-wounds dispel-evil insect-plague quest
207      raise-dead truesight)
208     (aerial-servant animate-objects barrier create-normal-animals cureall
209      find-the-path speak-with-monsters word-of-recall)
210     (earthquake holy-word raise-dead-fully restore survival travel wish
211      wizardry)))
212
213 (defconstant magic-user-spells
214   #((analyse charm-person detect-magic floating-disc hold-portal light
215      magic-missile protection-from-evil read-languages read-magic shield
216      sleep ventriloquism)
217     (continual-light detect-evil detect-invisible entangle esp invisibility
218      knock levitate locate-object mirror-image phantasmal-force web
219      wizard-lock)
220     (clairvoyance create-air dispel-magic fire-ball fly haste hold-person
221      infravision invisibility-10-ft-radius lightning-bolt
222      protection-from-evil-10-ft-radius protection-from-normal-missiles
223      water-breathing)
224     (charm-monster clothform confusion dimension-door growth-of-plants
225      hallucinatory-terrain ice-storm/wall massmorph polymorph-others
226      polymorph-self remove-curse wall-of-fire wizard-eye)
227     (animate-dead cloudkill conjure-elemental contact-outer-plane dissolve
228      feeblemind hold-monster magic-jar pass-wall telekinesis teleport
229      wall-of-stone woodform)
230     (anti-magic-shell death-spell disintegrate geas invisible-stalker
231      lower-water move-earth projected-image reincarnation stone-to-flesh
232      stoneform wall-of-iron weather-control)
233     (charm-plant create-normal-monsters delayed-blast-fire-ball ironform lore
234      magic-door mass-invisibility power-word-stun reverse-gravity statue
235      summon-object sword teleport-any-object)
236     (clone create-magical-monsters dance explosive-cloud force-field
237      mass-charm mind-barrier permanence polymorph-any-object power-word-blind
238      steelform symbol travel)
239     (contingency create-any-monster gate heal immunity maze meteor-swarm
240      power-word-kill prismatic-wall shapechange survival timestop wish)))
241
242 (defun spell-caster-type ()
243   (choose 25 :cleric 5 :druid 70 :magic-user))
244
245 (defun random-spell (&optional (caster (spell-caster-type))
246                                (level (ecase caster
247                                         ((:magic-user) (choose 28 1
248                                                                21 2
249                                                                15 3
250                                                                11 4
251                                                                 9 5
252                                                                 7 6
253                                                                 5 7
254                                                                 3 8
255                                                                 1 9))
256                                         ((:cleric :druid) (choose 34 1
257                                                                   24 2
258                                                                   18 3
259                                                                   12 4
260                                                                    7 5
261                                                                    4 6
262                                                                    1 7)))))
263   (let ((list (aref (ecase caster
264                       ((:magic-user) magic-user-spells)
265                       ((:cleric) cleric-spells)
266                       ((:druid) druid-spells))
267                     level)))
268     (values (elt list (random (length list)))
269             caster
270             level)))
271
272 (defun symbol-match-p (form sym)
273   (cond ((eq form t) t)
274         ((eq form nil) nil)
275         ((eq form sym) t)
276         ((atom form) nil)
277         (t (ecase (car form)
278              ((and) (every (lambda (f) (symbol-match-p f sym)) (cdr form)))
279              ((or) (some (lambda (f) (symbol-match-p f sym)) (cdr form)))
280              ((not) (not (symbol-match-p (cadr form) sym)))))))
281
282 (defun choose-distinct-items (n seq)
283   (let* ((copy (subseq (coerce seq 'vector) 0))
284          (len (length copy))
285          (list nil))
286     (dotimes (i n (sort list #'string<))
287       (let ((j (random len)))
288         (push (aref copy j) list)
289         (decf len)
290         (setf (aref copy j) (aref copy len))))))
291
292 (defun magic-item (form)
293   (labels ((potion (&key recursivep)
294              (pick (2 `(:potion agility))
295                    (1 `(:potion animal-control))
296                    (3 `(:potion antidote))
297                    (2 `(:potion blending))
298                    (2 `(:potion bug-repellent))
299                    (2 `(:potion clairaudience))
300                    (2 `(:potion clairvoyance))
301                    (2 `(:potion climbing))
302                    (2 `(:potion defence :bonus ,(choose 3 1
303                                                          2 2
304                                                          2 3
305                                                          2 4
306                                                          1 5)))
307                    ((if recursivep 0 4)
308                     `(:potion delusion
309                       :fakes ,@(cdr (potion :recursivep t))))
310                    (2 `(:potion diminution))
311                    (1 `(:potion ,(choose 35 'white-dragon-control
312                                          15 'crystal-dragon-control
313                                          35 'black-dragon-control
314                                          15 'onyx-dragon-control
315                                          28 'green-dragon-control
316                                          12 'jade-dragon-control
317                                          21 'blue-dragon-control
318                                           9 'sapphire-dragon-control
319                                          14 'red-dragon-control
320                                           6 'ruby-dragon-control
321                                           7 'gold-dragon-control
322                                           3 'amber-dragon-control)))
323                    (2 `(:potion dreamspeech))
324                    (1 `(:potion elasicity))
325                    (2 `(:potion ,(choose-uniformly 'air-form
326                                                    'water-form
327                                                    'earth-form
328                                                    'fire-form)))
329                    (2 `(:potion esp))
330                    (1 `(:potion ethereality))
331                    (3 `(:potion fire-resistance))
332                    (3 `(:potion flying))
333                    (2 `(:potion fortitude))
334                    (1 `(:potion freedom))
335                    (3 `(:potion gaseous-form))
336                    (1 `(:potion ,(choose 5 'hill-giant-control
337                                          5 'stone-giant-control
338                                          4 'frost-giant-control
339                                          2 'fire-giant-control
340                                          1 'mountain-giant-control
341                                          1 'sea-giant-control
342                                          1 'cloud-giant-control
343                                          1 'storm-giant-control)))
344                    (3 `(:potion giant-strength))
345                    (2 `(:potion growth))
346                    (6 `(:potion healing))
347                    (3 `(:potion heroism))
348                    (1 `(:potion human-control))
349                    (3 `(:potion invisibility))
350                    (2 `(:potion invulnerability))
351                    (2 `(:potion levitation))
352                    (2 `(:potion longevity))
353                    (1 `(:potion luck))
354                    (1 `(:potion merging))
355                    (2 `(:potion plant-control))
356                    (3 `(:potion poison))
357                    (3 `(:potion polymorph-self))
358                    (2 `(:potion sight))
359                    (2 `(:potion speech))
360                    (4 `(:potion speed))
361                    (2 `(:potion strength))
362                    (3 `(:potion super-healing))
363                    (3 `(:potion swimming))
364                    (1 `(:potion treasure-finding))
365                    (1 `(:potion undead-control))
366                    (2 `(:potion water-breathing))))
367            (scroll ()
368              (pick (3 `(:scroll communication))
369                    (2 `(:scroll creation))
370                    (8 `(:scroll curse))
371                    (1 (multiple-value-bind
372                           (spell caster level)
373                           (random-spell)
374                         (declare (ignore level))
375                         `(:scroll delay :caster ,caster :spells (,spell))))
376                    (3 `(:scroll equipment
377                         :items ,(choose-distinct-items 6
378                                                        '(grappling-hook
379                                                          hammer
380                                                          iron-spikes
381                                                          lantern
382                                                          mirror
383                                                          wooden-pole
384                                                          rope
385                                                          saddle
386                                                          backpack
387                                                          saddle-bags
388                                                          stakes-and-mallet
389                                                          wolfsbane))))
390                    (2 `(:scroll illumination))
391                    (2 `(:scroll mages))
392                    (4 `(:map normal-treasure))
393                    (3 `(:map magical-treasure))
394                    (2 `(:map combined-treasure))
395                    (1 `(:map special-treasure))
396                    (3 `(:scroll mapping))
397                    (2 `(:scroll portals))
398                    (6 `(:scroll protection-from-elementals))
399                    (8 `(:scroll protection-from-lycanthropes))
400                    (4 `(:scroll protection-from-magic))
401                    (7 `(:scroll protection-from-undead))
402                    (2 `(:scroll questioning))
403                    (1 (multiple-value-bind
404                           (spell caster level)
405                           (random-spell)
406                         `(:scroll repetition
407                           :caster ,caster
408                           :level ,level
409                           :spells (,spell))))
410                    (2 `(:scroll seeing))
411                    (2 `(:scroll shelter))
412                    (3 `(:scroll spell-catching :max-level ,(choose 4 1
413                                                                    3 2
414                                                                    2 3
415                                                                    1 8)))
416                    (25 (let ((caster (spell-caster-type))
417                              (spells (choose 50 1  33 2  17 3)))
418                          `(:scroll spell
419                            :caster ,caster
420                            :spells ,(loop repeat spells
421                                           collect (random-spell caster)))))
422                    (2 `(:scroll trapping))
423                    (2 `(:scroll truth))))
424            (wand-charges () (d 10 3))
425            (staff-charges () (d 20 2))
426            (wandlike ()
427              (pick (5 `(:wand cold :charges ,(wand-charges)))
428                    (5 `(:wand enemy-detection :charges ,(wand-charges)))
429                    (4 `(:wand fear :charges ,(wand-charges)))
430                    (5 `(:wand fireballs :charges ,(wand-charges)))
431                    (4 `(:wand illusion :charges ,(wand-charges)))
432                    (5 `(:wand lightning-bolts :charges ,(wand-charges)))
433                    (5 `(:wand magic-detection :charges ,(wand-charges)))
434                    (5 `(:wand metal-detection :charges ,(wand-charges)))
435                    (4 `(:wand negation :charges ,(wand-charges)))
436                    (5 `(:wand paralysation :charges ,(wand-charges)))
437                    (5 `(:wand polymorphing :charges ,(wand-charges)))
438                    (4 `(:wand secret-door-detection
439                         :charges ,(wand-charges)))
440                    (4 `(:wand trap-detection :charges ,(wand-charges)))
441                    (1 `(:staff commanding :charges nil))
442                    (2 `(:staff dispelling :charges ,(staff-charges)))
443                    (3 `(:staff druids :charges ,(staff-charges)))
444                    (3 `(:staff ,(choose 19 'air
445                                         19 'earth
446                                         19 'fire
447                                         19 'water
448                                          6 'air-and-water
449                                          6 'earth-and-fire
450                                          2 'elemental-power)
451                         :charges ,(staff-charges)))
452                    (2 `(:staff harming :charges ,(staff-charges)))
453                    (7 `(:staff healing :charges ,(staff-charges)))
454                    (1 `(:staff power :charges ,(staff-charges)))
455                    (3 `(:staff snake :charges ,(staff-charges)))
456                    (3 `(:staff striking :charges ,(staff-charges)))
457                    (2 `(:staff withering :charges ,(staff-charges)))
458                    (1 `(:staff wizardry :charges ,(staff-charges)))
459                    (2 `(:rod cancellation))
460                    (1 `(:rod dominion))
461                    (1 `(:rod health))
462                    (2 `(:rod inertia))
463                    (1 `(:rod parrying))
464                    (1 `(:rod victory))
465                    (3 `(:rod weaponry))
466                    (1 `(:rod wyrm :colour ,(choose 5 'gold
467                                                    3 'blue
468                                                    2 'black)))))
469            (ring ()
470              (pick (2 `(:ring animal-control))
471                    (6 `(:ring delusion))
472                    (1 `(:ring djinni-summoning))
473                    (4 `(:ring ear))
474                    (4 `(:ring ,(choose 19 'air-adaptation
475                                        19 'earth-adaptation
476                                        19 'fire-adaptation
477                                        19 'water-adaptation
478                                         6 'air-and-water-adaptation
479                                         6 'earth-and-fire-adaptation
480                                         2 'elemental-adaptation)))
481                    (6 `(:ring fire-resistance))
482                    (3 `(:ring holiness))
483                    (1 `(:ring human-control))
484                    (5 `(:ring invisibility))
485                    (3 `(:ring life-protection :charges ,(d 6)))
486                    (3 `(:ring memory))
487                    (2 `(:ring plant-control))
488                    (1 `(:ring protection :bonus 1 :radius 5))
489                    (10 `(:ring protection :bonus ,(choose 4 1
490                                                           3 2
491                                                           2 3
492                                                           1 4)))
493                    (4 `(:ring quickness))
494                    (1 `(:ring regeneration))
495                    (3 `(:ring remedies))
496                    (2 `(:ring safety :charges ,(d 4)))
497                    (3 `(:ring seeing))
498                    (3 `(:ring spell-eating))
499                    (2 (let* ((caster (spell-caster-type))
500                              (spells (loop repeat (d 6)
501                                            collect (random-spell caster))))
502                         `(:ring spell-storing
503                           :caster ,caster
504                           :spells ,(remove-duplicates (sort spells
505                                                             #'string<)))))
506                    (2 `(:ring spell-turning))
507                    (4 `(:ring survival :charges ,(+ 100 (d 100))))
508                    (2 `(:ring telekinesis))
509                    (4 `(:ring truth))
510                    (3 `(:ring truthfulness))
511                    (2 `(:ring truthlessness))
512                    (5 `(:ring water-walking))
513                    (5 `(:ring weakness))
514                    (2 `(:ring wishes :charges ,(choose 4 1
515                                                        3 2
516                                                        2 3
517                                                        1 4)))
518                    (2 `(:ring x-ray-vision))))
519            (misc-item ()
520              (pick (2 `(:amulet protection-from-crystal-balls-and-esp))
521                    (2 `(:bag devouring))
522                    (5 `(:bag holding))
523                    (3 `(:boat undersea))
524                    (2 `(:boots levitation))
525                    (3 `(:boots speed))
526                    (2 `(:boots travelling-and-leaping))
527                    (1 `(:bowl commanding-water-elementals))
528                    (1 `(:brazier commanding-fire-elementals))
529                    (2 `(:broom flying))
530                    (1 `(:censer controlling-air-elementals))
531                    (3 `(:chime time))
532                    (2 `(:crystal-ball normal))
533                    (1 `(:crystal-ball clairaudience))
534                    (1 `(:crystal-ball esp))
535                    (2 `(:cloak displacer))
536                    (1 `(:drums panic))
537                    (1 `(:bottle efreeti))
538                    (3 `(:egg ,(choose-uniformly 'rock-baboon
539                                                 'giant-bat
540                                                 'black-bear
541                                                 'grizzly-bear
542                                                 'boar
543                                                 'mountain-lion
544                                                 'panther
545                                                 'giant-ferret
546                                                 'gecko
547                                                 'draco
548                                                 'racer-snake
549                                                 'wolf)))
550                    (2 `(:boots elven))
551                    (2 `(:cloak elven))
552                    (1 `(:carpet flying))
553                    (2 `(:gauntlets ogre-power))
554                    (2 `(:girdle giant-strength))
555                    (2 `(:helm ,(choose-uniformly 'lawful-alignment
556                                                  'neutral-alignment
557                                                  'chaotic-alignment)))
558                    (2 `(:helm reading))
559                    (1 `(:helm telepathy))
560                    (1 `(:helm teleportation))
561                    (1 `(:horn blasting))
562                    (2 `(:lamp hurricane))
563                    (3 `(:lamp long-burning))
564                    (2 `(:medallion esp-30-ft-range))
565                    (1 `(:medallion esp-90-ft-range))
566                    (1 `(:mirror life-trapping)) ;;; fixme include contents
567                    (3 `(:muzzle training))
568                    (2 `(:nail finger))
569                    (3 `(:nail pointing))
570                    (5 `(:ointment ,(choose-uniformly 'blessing
571                                                      'healing
572                                                      'poison
573                                                      'scarring
574                                                      'soothing
575                                                      'tanning)))
576                    (3 `(:pouch security))
577                    (3 `(:quill copying))
578                    (4 `(:rope climbing))
579                    (2 `(:scarab protection :charges ,(d 6 2)))
580                    (3 `(:slate identification))
581                    (1 `(:stone controlling-earth-elementals))
582                    (2 `(:talisman ,(choose-uniformly 'air-travel
583                                                      'earth-travel
584                                                      'fire-travel
585                                                      'water-travel
586                                                      'elemental-travel)))
587                    (3 `(:wheel floating))
588                    (1 `(:wheel fortune))
589                    (2 `(:wheel square))))
590            (weapon-bonus (class)
591              (loop for bonus from 1
592                    for roll = (random 100) then (- roll item)
593                    for item in (ecase class
594                                  ((a) '(40 27 17 10 6))
595                                  ((b) '(50 24 14 8 4))
596                                  ((c) '(60 21 11 6 2))
597                                  ((d) '(70 18 8 3 1)))
598                    when (< roll item) return bonus))
599            (armour-size ()
600              (choose 68 'human
601                      13 'dwarf
602                      10 'elf
603                       7 'halfling
604                       2 'giant))
605            (armour-piece (class)
606              (let* ((bonus (weapon-bonus class))
607                     (power (and (percentp (* 5 (1+ bonus)))
608                                 (pick (7 `(absorption))
609                                       (10 `(charm))
610                                       (15 `(cure-wounds))
611                                       (10 `(electricity))
612                                       (5 `(energy-drain))
613                                       (3 `(ethereality))
614                                       (10 `(fly))
615                                       (6 `(gaseous-form))
616                                       (9 `(haste))
617                                       (10 `(invisibility))
618                                       (8 `(reflection))
619                                       (7 `(remove-curse :charges ,(d 3))))))
620                     (cursedp (if (and power (eq (car power) 'remove-curse))
621                                  nil
622                                  (zerop (random 8)))))
623                `(:bonus ,bonus
624                  ,@(and power (cons :power power))
625                  :size ,(armour-size)
626                  ,@(and cursedp `(:cursed t)))))
627            (armour ()
628              (pick (10 `((:leather ,@(armour-piece 'd))))
629                    ( 7 `((:scale-mail ,@(armour-piece 'd))))
630                    (13 `((:chain-mail ,@(armour-piece 'c))))
631                    ( 9 `((:banded-mail ,@(armour-piece 'd))))
632                    (11 `((:plate-mail ,@(armour-piece 'b))))
633                    ( 5 `((:suit-armour ,@(armour-piece 'b))))
634                    (20 `((:shield ,@(armour-piece 'a))))
635                    ( 2 `((:scale-mail ,@(armour-piece 'd))
636                          (:shield ,@(armour-piece 'a))))
637                    ( 8 `((:chain-mail ,@(armour-piece 'c))
638                          (:shield ,@(armour-piece 'a))))
639                    ( 5 `((:banded-mail ,@(armour-piece 'd))
640                          (:shield ,@(armour-piece 'a))))
641                    (10 `((:plate-mail ,@(armour-piece 'b))
642                          (:shield ,@(armour-piece 'a))))))
643            (opponent ()
644              (choose 6 'bugs
645                      3 'constructs
646                      6 'dragonkind
647                      9 'enchanted-monsters
648                      12 'giantkind
649                      12 'lycanthropes
650                      4 'planar-monsters
651                      6 'regenerating-monsters
652                      9 'reptiles-and-dinosaurs
653                      3 'spell-immune-monsters
654                      6 'spellcasters
655                      12 'undead
656                      6 'water-breathing-monsters
657                      6 'weapon-using-monsters))
658            (weapon-talent (&key missilep)
659              (pick (5 `(breathing))
660                    (7 `(charming))
661                    (4 `(deceiving))
662                    ((if missilep 0 7) `(defending))
663                    (2 `(deflecting))
664                    (2 `(draining :charges ,(+ 4 (d 4))))
665                    (5 `(extinguishing))
666                    (6 `(finding))
667                    (5 `(flaming))
668                    (3 `(flying))
669                    (8 `(healing))
670                    (5 `(hiding))
671                    (6 `(holding))
672                    (8 `(lightning))
673                    (6 `(silencing))
674                    (2 `(slicing))
675                    (4 `(slowing))
676                    (4 `(speeding))
677                    (5 `(translating))
678                    (5 `(watching))
679                    (1 `(wishing :charges ,(d 3)))))
680            (weapon-modifier (bonus &rest keys &key &allow-other-keys)
681              (and (percentp (aref #(40 30 20 15 10) (1- bonus)))
682                   (pick (33 `(:extra (,(+ bonus 1) :against ,(opponent))))
683                         (24 `(:extra (,(+ bonus 2) :against ,(opponent))))
684                         (16 `(:extra (,(+ bonus 3) :against ,(opponent))))
685                         (9 `(:extra (,(+ bonus 4) :against ,(opponent))))
686                         (3 `(:extra (,(+ bonus 5) :against ,(opponent))))
687                         (15 `(:talent ,@(apply #'weapon-talent keys))))))
688            (sword-modifier (bonus &rest keys &key &allow-other-keys)
689              (and (percentp (aref #(40 30 25 20 15) (1- bonus)))
690                   (pick (29 `(:extra (,(+ bonus 1) :against ,(opponent))))
691                         (21 `(:extra (,(+ bonus 2) :against ,(opponent))))
692                         (14 `(:extra (,(+ bonus 3) :against ,(opponent))))
693                         (8 `(:extra (,(+ bonus 4) :against ,(opponent))))
694                         (3 `(:extra (,(+ bonus 5) :against ,(opponent))))
695                         (25 `(:talent ,@(apply #'weapon-talent keys))))))
696            (missile ()
697              (multiple-value-bind
698                  (item class)
699                  (pick (37 (values :arrow 'a))
700                        (22 (values :quarrel 'a))
701                        (11 (values :sling-stone 'a))
702                        (2 (values :blowgun 'd))
703                        (8 (values :long-bow 'd))
704                        (5 (values :short-bow 'd))
705                        (2 (values :heavy-crossbow 'd))
706                        (5 (values :light-crossbow 'd))
707                        (8 (values :sling 'd)))
708                (ecase class
709                  ((a) (let* ((bonus (weapon-bonus 'a))
710                              (cursedp (zerop (random 10)))
711                              (talent (and (percentp (* 5 (- 7 bonus)))
712                                           (choose 4 'biting
713                                                   5 'blinking
714                                                   5 'charming
715                                                   7 'climbing
716                                                   10 'curing
717                                                   3 'disarming
718                                                   4 'dispelling
719                                                   7 'flying
720                                                   7 'lightning
721                                                   5 'penetrating
722                                                   4 'refilling
723                                                   6 'screaming
724                                                   5 'seeking
725                                                   4 'sinking
726                                                   2 'slaying
727                                                   7 'speaking
728                                                   4 'stunning
729                                                   2 'teleporting
730                                                   5 'transporting
731                                                   4 'wounding)))
732                              (number (ecase bonus
733                                        ((1) (d 10 2))
734                                        ((2) (d 8 2))
735                                        ((3) (d 6 2))
736                                        ((4) (d 4 2))
737                                        ((5) (+ (d 4) 1)))))
738                         `(,item :bonus ,bonus
739                           ,@(and talent `(:talent ,talent))
740                           :number ,number
741                           ,@(and cursedp `(:cursed t)))))
742                  ((d) (let* ((bonus (weapon-bonus 'd))
743                              (cursedp (zerop (random 10)))
744                              (modifier (weapon-modifier bonus :missilep t))
745                              (range (ecase (+ bonus (d 4))
746                                       ((2 3 4) nil)
747                                       ((5 6 7) 1.5)
748                                       ((8 9) 2))))
749                         `(,item :bonus ,bonus ,@modifier
750                           ,@(and range `(:range ,range))
751                           ,@(and cursedp `(:cursed t))))))))
752            (weapon-intelligence ()
753              (multiple-value-bind
754                  (int langs prim read-magic-p extra)
755                  (pick (79 (values nil 0 0 nil 0))
756                        (6 (values 7 0 1 nil 0))
757                        (5 (values 8 0 2 nil 0))
758                        (4 (values 9 0 3 nil 0))
759                        (3 (values 10 (d 3) 3 nil 0))
760                        (2 (values 11 (d 6) 3 t 0))
761                        (1 (values 12 (d 4 2) 3 t 1)))
762                (and int
763                     (let ((powers nil)
764                           (healing nil)
765                           (damage nil)
766                           (checklist nil))
767                       (macrolet ((power-check (&rest forms)
768                                    `(pick ,@(loop for (tag n . form) in forms
769                                                   if tag
770                                                   collect
771                                                   `((if (member ',tag
772                                                                 checklist)
773                                                         0
774                                                         ,n)
775                                                     (push ',tag checklist)
776                                                     ,@(or form
777                                                           `((push ',tag
778                                                              powers))))
779                                                   else
780                                                   collect `(,n ,@form)))))
781                         (labels ((primary-power ()
782                                    (power-check
783                                     (detect-evil 10)
784                                     (detect-gems 5)
785                                     (detect-magic 10)
786                                     (detect-metal 10)
787                                     (detect-shifting-walls-and-rooms 15)
788                                     (detect-sloping-passages 15)
789                                     (find-secret-doors 10)
790                                     (find-traps 10)
791                                     (see-invisible 10)
792                                     (:one-extra 4
793                                       (extraordinary-power))
794                                     (:two-primary 1
795                                       (primary-power)
796                                       (primary-power))))
797                                  (extraordinary-power ()
798                                    (power-check
799                                     (clairaudience 10)
800                                     (clairvoyance 10)
801                                     (esp 10)
802                                     (nil 5
803                                       (setf damage (if damage
804                                                        (1+ damage)
805                                                        5)))
806                                     (flying 5)
807                                     (nil 5
808                                       (setf healing (+ (or healing 0) 6)))
809                                     (illusion 9)
810                                     (levitation 5)
811                                     (telekinesis 10)
812                                     (telepathy 10)
813                                     (teleportation 9)
814                                     (x-ray-vision 9)
815                                     (:two-three-extra 2
816                                       (extraordinary-power)
817                                       (extraordinary-power))
818                                     (:two-three-extra 1
819                                       (extraordinary-power)
820                                       (extraordinary-power)
821                                       (extraordinary-power)))))
822                           (dotimes (i prim) (primary-power))
823                           (dotimes (i extra) (extraordinary-power))))
824                       (when damage
825                         (push `(extra-damage ,damage) powers))
826                       (when healing
827                         (push `(healing ,healing) powers))
828                       `(:intelligence ,int
829                         :ego ,(d 12)
830                         :languages ,langs
831                         ,@(and read-magic-p `(:read-magic t))
832                         :powers ,powers)))))
833            (sword ()
834              (multiple-value-bind
835                  (type class)
836                  (pick (65 (values :normal-sword 'c))
837                        (19 (values :short-sword 'c))
838                        (8 (values :two-handed-sword 'd))
839                        (8 (values :bastard-sword 'd)))
840                (let* ((bonus (weapon-bonus class))
841                       (cursedp (zerop (random 10)))
842                       (modifier (sword-modifier bonus))
843                       (intel (weapon-intelligence)))
844                  `(,type :bonus ,bonus
845                    ,@modifier
846                    ,@intel
847                    ,@(and cursedp `(:cursed t))))))
848            (weapon ()
849              (multiple-value-bind
850                  (type returnsp class)
851                  (pick (7 (values :battle-axe nil 'd))
852                        (8 (values :hand-axe (choose 3 nil 1 t) 'b))
853                        (3 (values :blackjack nil 'c))
854                        (3 (values :bola (choose 2 nil 1 t) 'b))
855                        (5 (values :club nil 'c))
856                        (14 (values :dagger (choose 11 nil 3 t) 'b))
857                        (4 (values :one-handed-flail nil 'c))
858                        (2 (values :two-handed-flail nil 'd))
859                        (3 (values :halberd nil 'd))
860                        (8 (values :war-hammer nil 'c))
861                        (4 (values :javelin (choose 3 nil 1 t) 'b))
862                        (4 (values :lance nil 'd))
863                        (7 (values :mace nil 'c))
864                        (5 (values :morning-star nil 'c))
865                        (3 (values :net (choose 2 nil 1 t) 'b))
866                        (3 (values :pike nil 'd))
867                        (2 (values :pole-axe nil 'd))
868                        (12 (values :spear (choose 3 nil 1 t) 'b))
869                        (3 (values :whip nil 'c)))
870                (let* ((bonus (weapon-bonus class))
871                       (cursedp (zerop (random 10)))
872                       (modifier (sword-modifier bonus))
873                       (intel (and (percentp 40)
874                                   (weapon-intelligence))))
875                  `(,type
876                    ,@(and returnsp `(:returning t))
877                    :bonus ,bonus
878                    ,@modifier
879                    ,@intel
880                    ,@(and cursedp `(:cursed t)))))))
881     (pick ((if (symbol-match-p form :potion) 25 0) (list (potion)))
882           ((if (symbol-match-p form :scroll) 12 0) (list (scroll)))
883           ((if (symbol-match-p form :wandlike) 9 0) (list (wandlike)))
884           ((if (symbol-match-p form :ring) 6 0) (list (ring)))
885           ((if (symbol-match-p form :misc) 10 0) (list (misc-item)))
886           ((if (symbol-match-p form :armour) 10 0) (armour))
887           ((if (symbol-match-p form :missile) 11 0) (list (missile)))
888           ((if (symbol-match-p form :sword) 9 0) (list (sword)))
889           ((if (symbol-match-p form :weapon) 8 0) (list (weapon))))))
890
891 (defun treasure-type (type-code)
892   (labels ((common-fur-type ()
893              (choose-uniformly 'beaver
894                                'fox
895                                'marten
896                                'seal))
897            (rare-fur-type ()
898              (choose-uniformly 'ermine
899                                'mink
900                                'sable))
901            (special (n)
902              (tagged-bag
903               :special
904               (loop repeat n
905                     collect
906                     (pick (10 `(:kind book
907                                 :value ,(* 10 (d 100))
908                                 :encumbrance ,(d 100)))
909                           (2 `(:kind pelt
910                                :animal ,(common-fur-type)
911                                :value ,(d 4)
912                                :encumbrance ,(* 10 (d 6))))
913                           (5 `(:kind cape
914                                :animal ,(common-fur-type)
915                                :value ,(* 100 (d 6))
916                                :encumbrance ,(* 10 (+ 4 (d 8)))))
917                           (3 `(:kind coat
918                                :animal ,(common-fur-type)
919                                :value ,(* 100 (d 4 3))
920                                :encumbrance ,(* 10 (+ 8 (d 6 2)))))
921                           (2 `(:kind pelt
922                                :animal ,(rare-fur-type)
923                                :value ,(d 6 2)
924                                :encumbrance ,(* 10 (d 6))))
925                           (5 `(:kind cape
926                                :animal ,(rare-fur-type)
927                                :value ,(* 100 (d 6 4))
928                                :encumbrance ,(* 10 (+ 4 (d 8)))))
929                           (3 `(:kind coat
930                                :animal ,(rare-fur-type)
931                                :value ,(* 1000 (d 4))
932                                :encumbrance ,(* 10 (+ 8 (d 6 2)))))
933                           (5 `(:kind incense
934                                :value ,(d 6 5)
935                                :encumbrance 1
936                                :quantity ,(d 4 2)))
937                           (5 `(:kind perfume
938                                :value ,(* 10 (+ 5 (d 10)))
939                                :encumbrance 1
940                                :quantity ,(d 3 2)))
941                           (5 (let ((w (d 6)) (h (d 2)))
942                                `(:kind ,(choose-uniformly 'rug
943                                                           'tapestry)
944                                  :value ,(* w h (d 10 2))
945                                  :encumbrance ,(* 100 w h (d 6))
946                                  :size (* ,w ,h))))
947                           (10 (let ((w (d 8)) (h (d 2)))
948                                 `(:kind silk
949                                   :value ,(* w h (d 8))
950                                   :encumbrance ,(* 10 w h (d 6))
951                                   :size (* ,w ,h))))
952                           (10 `(:kind animal-skin
953                                 :value ,(d 10)
954                                 :encumbrance ,(* 10 (d 4 5))))
955                           (10 `(:kind monster-skin
956                                 :value ,(* 100 (d 10))
957                                 :encumbrance ,(* 50 (d 100))))
958                           (5 (let ((enc (d 100)))
959                                `(:kind spice
960                                  :value ,(* enc (d 4 4))
961                                  :encumbrance ,enc)))
962                           (5 `(:kind statuette
963                                :value ,(* 100 (d 10))
964                                :encumbrance ,(d 100)))
965                           (5 `(:wine
966                                :value ,(d 6)
967                                :encumbrance ,(* 10 (+ 3 (d 6)))
968                                :bottles ,(d 12)))))))
969            (gem-type (&key (min-value 0) recursivep)
970              (pick ((if (<= min-value 10) 3 0)
971                     (values 10 (choose-uniformly 'agate
972                                                  'quartz
973                                                  'turquoise)))
974                    ((if (<= min-value 50) 7 0)
975                     (values 50 (choose-uniformly 'crystal
976                                                  'jasper
977                                                  'onyx)))
978                    ((if (<= min-value 100) 15 0)
979                     (values 100 (choose-uniformly 'amber
980                                                   'amethyst
981                                                   'coral
982                                                   'garnet
983                                                   'jade)))
984                    ((if (<= min-value 500) 21 0)
985                     (values 500 (choose-uniformly 'aquamarine
986                                                   'pearl
987                                                   'topaz)))
988                    ((if (<= min-value 1000) 25 0)
989                     (values 1000 (choose-uniformly 'carbuncle
990                                                    'opal)))
991                    ((if (<= min-value 5000) 19 0)
992                     (values 5000 (choose-uniformly 'emerald
993                                                    'ruby
994                                                    'sapphire)))
995                    ((if (<= min-value 10000) 7 0)
996                     (values 10000 'diamond 'jacinth))
997                    ((if (<= min-value 1000) 1 0)
998                     (values (* 1000 (d 100))
999                             'tristal))
1000                    ((if (and (not recursivep)
1001                              (<= min-value 2000)) 2 0)
1002                     (multiple-value-bind
1003                         (value kind)
1004                         (gem-type :min-value (max 1000
1005                                                   (ceiling min-value 2))
1006                                   :recursivep t)
1007                       (values (* 2 value)
1008                               (intern (format nil "STAR-~A"
1009                                               (string kind))))))))
1010            (gems (n)
1011              (tagged-bag
1012               :gems
1013               (loop while (plusp n)
1014                     for i = (min n (d 5))
1015                     do (decf n i)
1016                     collect
1017                     (let ((mods (choose 4 :size 4 :qual 2 :both))
1018                           (mod-list nil))
1019                       (multiple-value-bind
1020                           (value kind)
1021                           (gem-type)
1022                         (when (or (eq mods :size)
1023                                   (eq mods :both))
1024                           (multiple-value-bind
1025                               (mod mult)
1026                               (pick (1 (values 'very-small 1/8))
1027                                     (2 (values 'small 1/4))
1028                                     (2 (values 'fairly-small 1/2))
1029                                     (2 (values 'fairly-large 2))
1030                                     (2 (values 'large 4))
1031                                     (1 (values 'very-small 8)))
1032                             (setf mod-list
1033                                   (append `(:size ,mod) mod-list))
1034                             (setf value (* value mult))))
1035                         (when (or (eq mods :qual)
1036                                   (eq mods :both))
1037                           (multiple-value-bind
1038                               (mod mult)
1039                               (pick (1 (values 'very-poor 1/8))
1040                                     (2 (values 'poor 1/4))
1041                                     (2 (values 'fairly-poor 1/2))
1042                                     (2 (values 'fairly-good 2))
1043                                     (2 (values 'good 4))
1044                                     (1 (values 'very-good 8)))
1045                             (setf mod-list
1046                                   (append `(:size ,mod) mod-list))
1047                             (setf value (* value mult))))
1048                       `(:kind ,kind
1049                         :value ,(max 1 (round value))
1050                         ,@mod-list
1051                         ,@(and (> i 1) `(:quantity ,i))))))))
1052            (jewellery (n)
1053              (tagged-bag
1054               :jewellery
1055               (loop while (plusp n)
1056                     for i = (min n (d 5))
1057                     do (decf n i)
1058                     collect
1059                     (multiple-value-bind
1060                         (value enc class)
1061                         (pick ( 1 (values   100 10 'a))
1062                               ( 2 (values   500 10 'a))
1063                               ( 3 (values  1000 10 'a))
1064                               ( 4 (values  1500 10 'a))
1065                               ( 5 (values  2000 10 'a))
1066                               ( 8 (values  2500 10 'a))
1067                               (10 (values  3000 25 'a))
1068                               (11 (values  4000 25 'b))
1069                               (13 (values  5000 25 'b))
1070                               (11 (values  7500 25 'b))
1071                               ( 9 (values 10000 25 'b))
1072                               ( 7 (values 15000 25 'c))
1073                               ( 5 (values 20000 50 'c))
1074                               ( 4 (values 25000 50 'c))
1075                               ( 3 (values 30000 50 'c))
1076                               ( 2 (values 40000 50 'c))
1077                               ( 1 (values 50000 50 'c)))
1078                       (let ((kind (ecase class
1079                                     ((a) (choose-uniformly 'anklet
1080                                                            'beads
1081                                                            'bracelet
1082                                                            'brooch
1083                                                            'buckle
1084                                                            'cameo
1085                                                            'chain
1086                                                            'clasp
1087                                                            'locket
1088                                                            'pin))
1089                                     ((b) (choose-uniformly 'armband
1090                                                            'belt
1091                                                            'collar
1092                                                            'earring
1093                                                            'four-leaf-clover
1094                                                            'heart
1095                                                            'leaf
1096                                                            'necklace
1097                                                            'pendant
1098                                                            'rabbit-foot))
1099                                     ((c) (choose-uniformly 'amulet
1100                                                            'crown
1101                                                            'diadem
1102                                                            'medallion
1103                                                            'orb
1104                                                            'ring
1105                                                            'scarab
1106                                                            'sceptre
1107                                                            'talisman
1108                                                            'tiara)))))
1109                         `(:kind ,kind
1110                           :value ,value
1111                           :encumbrance ,enc
1112                           ,@(and (> i 1) `(:quantity ,i))))))))
1113            (magic (&rest forms)
1114              (tagged-bag :magic
1115                          (loop with list = nil
1116                                for (form n) on forms by #'cddr do
1117                                (loop repeat n do
1118                                      (dolist (item (magic-item form))
1119                                        (push item list)))
1120                                finally (return list)))))
1121     (ecase type-code
1122
1123       ;; treasure in lair
1124       ((a) (bag (tagged-bag :coins
1125                             (and (percentp 25) `(:cp ,(* 1000 (d 6))))
1126                             (and (percentp 30) `(:sp ,(* 1000 (d 6))))
1127                             (and (percentp 20) `(:ep ,(* 1000 (d 4))))
1128                             (and (percentp 35) `(:gp ,(* 1000 (d 6 2))))
1129                             (and (percentp 25) `(:pp ,(* 1000 (d 2)))))
1130                 (and (percentp 50) (gems (d 6 6)))
1131                 (and (percentp 50) (jewellery (d 6 6)))
1132                 (and (percentp 10) (special (d 2)))
1133                 (and (percentp 30) (magic t 3))))
1134       ((b) (bag (tagged-bag :coins
1135                             (and (percentp 50) `(:cp ,(* 1000 (d 8))))
1136                             (and (percentp 25) `(:sp ,(* 1000 (d 6))))
1137                             (and (percentp 25) `(:ep ,(* 1000 (d 4))))
1138                             (and (percentp 35) `(:gp ,(* 1000 (d 3)))))
1139                 (and (percentp 25) (gems (d 6)))
1140                 (and (percentp 25) (jewellery (d 6)))
1141                 (and (percentp 10)
1142                      (magic '(or :armour :missile :sword :weapon) 1))))
1143       ((c) (bag (tagged-bag :coins
1144                             (and (percentp 20) `(:cp ,(* 1000 (d 12))))
1145                             (and (percentp 30) `(:sp ,(* 1000 (d 4))))
1146                             (and (percentp 10) `(:ep ,(* 1000 (d 4)))))
1147                 (and (percentp 50) (gems (d 6 6)))
1148                 (and (percentp 50) (jewellery (d 6 6)))
1149                 (and (percentp 5) (special (d 2)))
1150                 (and (percentp 10) (magic t 2))))
1151       ((d) (bag (tagged-bag :coins
1152                             (and (percentp 10) `(:cp ,(* 1000 (d 8))))
1153                             (and (percentp 15) `(:sp ,(* 1000 (d 12))))
1154                             (and (percentp 60) `(:gp ,(* 1000 (d 6)))))
1155                 (and (percentp 30) (gems (d 8)))
1156                 (and (percentp 30) (jewellery (d 8)))
1157                 (and (percentp 10) (special (d 2)))
1158                 (and (percentp 10) (magic t 1 :potion 1))))
1159       ((e) (bag (tagged-bag :coins
1160                             (and (percentp 5) `(:cp ,(* 1000 (d 10))))
1161                             (and (percentp 30) `(:sp ,(* 1000 (d 12))))
1162                             (and (percentp 25) `(:ep ,(* 1000 (d 4))))
1163                             (and (percentp 25) `(:gp ,(* 1000 (d 8)))))
1164                 (and (percentp 10) (gems (d 10)))
1165                 (and (percentp 10) (jewellery (d 10)))
1166                 (and (percentp 15) (special (d 2)))
1167                 (and (percentp 25) (magic t 3 :scroll 1))))
1168       ((f) (bag (tagged-bag :coins
1169                             (and (percentp 30) `(:sp ,(* 1000 (d 10 2))))
1170                             (and (percentp 20) `(:ep ,(* 1000 (d 8))))
1171                             (and (percentp 45) `(:gp ,(* 1000 (d 12))))
1172                             (and (percentp 30) `(:pp ,(* 1000 (d 3)))))
1173                 (and (percentp 20) (gems (d 12 2)))
1174                 (and (percentp 10) (jewellery (d 12)))
1175                 (and (percentp 20) (special (d 3)))
1176                 (and (percentp 30) (magic :potion 1 :scroll 1
1177                                           '(not :armour :missile
1178                                             :sword :weapon) 3))))
1179       ((g) (bag (tagged-bag :coins
1180                             (and (percentp 50) `(:gp ,(* 10000 (d 4))))
1181                             (and (percentp 50) `(:pp ,(* 1000 (d 6)))))
1182                 (and (percentp 25) (gems (d 6 3)))
1183                 (and (percentp 25) (jewellery (d 10)))
1184                 (and (percentp 30) (special (d 3)))
1185                 (and (percentp 35) (magic t 4 :scroll 1))))
1186       ((h) (bag (tagged-bag :coins
1187                             (and (percentp 25) `(:cp ,(* 1000 (d 8 3))))
1188                             (and (percentp 50) `(:sp ,(* 1000 (d 100))))
1189                             (and (percentp 50) `(:ep ,(* 10000 (d 4))))
1190                             (and (percentp 50) `(:gp ,(* 10000 (d 6))))
1191                             (and (percentp 25) `(:pp ,(* 1000 (d 4 5)))))
1192                 (and (percentp 50) (gems (d 100)))
1193                 (and (percentp 50) (jewellery (* 10 (d 4))))
1194                 (and (percentp 10) (special (d 2)))
1195                 (and (percentp 15) (magic t 4 :potion 1 :scroll 1))))
1196       ((i) (bag (tagged-bag :coins
1197                             (and (percentp 30) `(:pp ,(* 1000 (d 8)))))
1198                 (and (percentp 50) (gems (d 6 2)))
1199                 (and (percentp 50) (jewellery (d 6 2)))
1200                 (and (percentp 5) (special (d 2)))
1201                 (and (percentp 15) (magic t 1))))
1202       ((j) (bag (tagged-bag :coins
1203                             (and (percentp 25) `(:cp ,(* 1000 (d 4))))
1204                             (and (percentp 10) `(:sp ,(* 1000 (d 3)))))))
1205       ((k) (bag (tagged-bag :coins
1206                             (and (percentp 30) `(:sp ,(* 1000 (d 6))))
1207                             (and (percentp 10) `(:ep ,(* 1000 (d 2)))))))
1208       ((l) (bag (and (percentp 50) (gems (d 4)))))
1209       ((m) (bag (and (percentp 55) (gems (d 4)))
1210                 (and (percentp 45) (jewellery (d 6 2)))))
1211       ((n) (bag (and (percentp 10) (special (d 2)))
1212                 (and (percentp 40) (magic :potion (d 4 2)))))
1213       ((o) (bag (and (percentp 10) (special (d 3)))
1214                 (and (percentp 50) (magic :scroll (d 4)))))
1215
1216       ;; treasure carried
1217       ((p) (bag (tagged-bag :coins `(:cp ,(d 8 3)))))
1218       ((q) (bag (tagged-bag :coins `(:sp ,(d 6 3)))))
1219       ((r) (bag (tagged-bag :coins `(:ep ,(d 6 2)))))
1220       ((s) (bag (tagged-bag :coins `(:gp ,(d 4 2)))
1221                 (and (percentp 5) (gems 1))))
1222       ((t) (bag (tagged-bag :coins `(:pp ,(d 6 1)))
1223                 (and (percentp 5) (gems 1))))
1224       ((u) (bag (tagged-bag :coins
1225                             (and (percentp 10) `(:cp ,(d 100)))
1226                             (and (percentp 10) `(:sp ,(d 100)))
1227                             (and (percentp 5) `(:gp ,(d 100))))
1228                 (and (percentp 5) (gems (d 2)))
1229                 (and (percentp 5) (gems (d 4)))
1230                 (and (percentp 2) (special 1))
1231                 (and (percentp 2) (magic t 1))))
1232       ((v) (bag (tagged-bag :coins
1233                             (and (percentp 10) `(:sp ,(d 100)))
1234                             (and (percentp 5) `(:ep ,(d 100)))
1235                             (and (percentp 5) `(:gp ,(d 100)))
1236                             (and (percentp 5) `(:pp ,(d 100))))
1237                 (and (percentp 10) (gems (d 2)))
1238                 (and (percentp 10) (gems (d 4)))
1239                 (and (percentp 5) (special 1))
1240                 (and (percentp 5) (magic t 1))))
1241
1242       ;; unguarded treasures
1243       ((unguarded-1)
1244        (bag (tagged-bag :coins
1245                         `(:sp ,(* 100 (d 6)))
1246                         (and (percentp 50) `(:gp ,(* 10 (d 6)))))
1247             (and (percentp 5) (gems (d 6)))
1248             (and (percentp 2) (jewellery (d 6)))
1249             (and (percentp 2) (magic t 1))))
1250       ((unguarded-2 unguarded-3)
1251        (bag (tagged-bag :coins
1252                         `(:sp ,(* 100 (d 12)))
1253                         (and (percentp 50) `(:gp ,(* 100 (d 6)))))
1254             (and (percentp 10) (gems (d 6)))
1255             (and (percentp 5) (jewellery (d 6)))
1256             (and (percentp 8) (magic t 1))))
1257       ((unguarded-4 unguarded-5)
1258        (bag (tagged-bag :coins
1259                         `(:sp ,(* 1000 (d 6)))
1260                         `(:gp ,(* 200 (d 6))))
1261             (and (percentp 20) (gems (d 8)))
1262             (and (percentp 10) (jewellery (d 8)))
1263             (and (percentp 10) (magic t 1))))
1264       ((unguarded-6 unguarded-7)
1265        (bag (tagged-bag :coins
1266                         `(:sp ,(* 2000 (d 6)))
1267                         `(:gp ,(* 500 (d 6))))
1268             (and (percentp 30) (gems (d 10)))
1269             (and (percentp 15) (jewellery (d 10)))
1270             (and (percentp 15) (magic t 1))))
1271       ((unguarded-8 unguarded-9)
1272        (bag (tagged-bag :coins
1273                         `(:sp ,(* 5000 (d 6)))
1274                         `(:gp ,(* 1000 (d 6))))
1275             (and (percentp 40) (gems (d 12)))
1276             (and (percentp 20) (jewellery (d 12)))
1277             (and (percentp 20) (magic t 1)))))))