OSDN Git Service

add gitignore
[nethackexpress/trunk.git] / src / worn.c
1 /*      SCCS Id: @(#)worn.c     3.4     2003/01/08      */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "hack.h"
6
7 STATIC_DCL void FDECL(m_lose_armor, (struct monst *,struct obj *));
8 STATIC_DCL void FDECL(m_dowear_type, (struct monst *,long, BOOLEAN_P, BOOLEAN_P));
9 STATIC_DCL int FDECL(extra_pref, (struct monst *, struct obj *));
10
11 const struct worn {
12         long w_mask;
13         struct obj **w_obj;
14 } worn[] = {
15         { W_ARM, &uarm },
16         { W_ARMC, &uarmc },
17         { W_ARMH, &uarmh },
18         { W_ARMS, &uarms },
19         { W_ARMG, &uarmg },
20         { W_ARMF, &uarmf },
21 #ifdef TOURIST
22         { W_ARMU, &uarmu },
23 #endif
24         { W_RINGL, &uleft },
25         { W_RINGR, &uright },
26         { W_WEP, &uwep },
27         { W_SWAPWEP, &uswapwep },
28         { W_QUIVER, &uquiver },
29         { W_AMUL, &uamul },
30         { W_TOOL, &ublindf },
31         { W_BALL, &uball },
32         { W_CHAIN, &uchain },
33         { 0, 0 }
34 };
35
36 /* This only allows for one blocking item per property */
37 #define w_blocks(o,m) \
38                 ((o->otyp == MUMMY_WRAPPING && ((m) & W_ARMC)) ? INVIS : \
39                  (o->otyp == CORNUTHAUM && ((m) & W_ARMH) && \
40                         !Role_if(PM_WIZARD)) ? CLAIRVOYANT : 0)
41                 /* note: monsters don't have clairvoyance, so your role
42                    has no significant effect on their use of w_blocks() */
43
44
45 /* Updated to use the extrinsic and blocked fields. */
46 void
47 setworn(obj, mask)
48 register struct obj *obj;
49 long mask;
50 {
51         register const struct worn *wp;
52         register struct obj *oobj;
53         register int p;
54
55         if ((mask & (W_ARM|I_SPECIAL)) == (W_ARM|I_SPECIAL)) {
56             /* restoring saved game; no properties are conferred via skin */
57             uskin = obj;
58          /* assert( !uarm ); */
59         } else {
60             for(wp = worn; wp->w_mask; wp++) if(wp->w_mask & mask) {
61                 oobj = *(wp->w_obj);
62                 if(oobj && !(oobj->owornmask & wp->w_mask))
63                         impossible("Setworn: mask = %ld.", wp->w_mask);
64                 if(oobj) {
65                     if (u.twoweap && (oobj->owornmask & (W_WEP|W_SWAPWEP)))
66                         u.twoweap = 0;
67                     oobj->owornmask &= ~wp->w_mask;
68                     if (wp->w_mask & ~(W_SWAPWEP|W_QUIVER)) {
69                         /* leave as "x = x <op> y", here and below, for broken
70                          * compilers */
71                         p = objects[oobj->otyp].oc_oprop;
72                         u.uprops[p].extrinsic =
73                                         u.uprops[p].extrinsic & ~wp->w_mask;
74                         if ((p = w_blocks(oobj,mask)) != 0)
75                             u.uprops[p].blocked &= ~wp->w_mask;
76                         if (oobj->oartifact)
77                             set_artifact_intrinsic(oobj, 0, mask);
78                     }
79                 }
80                 *(wp->w_obj) = obj;
81                 if(obj) {
82                     obj->owornmask |= wp->w_mask;
83                     /* Prevent getting/blocking intrinsics from wielding
84                      * potions, through the quiver, etc.
85                      * Allow weapon-tools, too.
86                      * wp_mask should be same as mask at this point.
87                      */
88                     if (wp->w_mask & ~(W_SWAPWEP|W_QUIVER)) {
89                         if (obj->oclass == WEAPON_CLASS || is_weptool(obj) ||
90                                             mask != W_WEP) {
91                             p = objects[obj->otyp].oc_oprop;
92                             u.uprops[p].extrinsic =
93                                         u.uprops[p].extrinsic | wp->w_mask;
94                             if ((p = w_blocks(obj, mask)) != 0)
95                                 u.uprops[p].blocked |= wp->w_mask;
96                         }
97                         if (obj->oartifact)
98                             set_artifact_intrinsic(obj, 1, mask);
99                     }
100                 }
101             }
102         }
103         update_inventory();
104 }
105
106 /* called e.g. when obj is destroyed */
107 /* Updated to use the extrinsic and blocked fields. */
108 void
109 setnotworn(obj)
110 register struct obj *obj;
111 {
112         register const struct worn *wp;
113         register int p;
114
115         if (!obj) return;
116         if (obj == uwep || obj == uswapwep) u.twoweap = 0;
117         for(wp = worn; wp->w_mask; wp++)
118             if(obj == *(wp->w_obj)) {
119                 *(wp->w_obj) = 0;
120                 p = objects[obj->otyp].oc_oprop;
121                 u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask;
122                 obj->owornmask &= ~wp->w_mask;
123                 if (obj->oartifact)
124                     set_artifact_intrinsic(obj, 0, wp->w_mask);
125                 if ((p = w_blocks(obj,wp->w_mask)) != 0)
126                     u.uprops[p].blocked &= ~wp->w_mask;
127             }
128         update_inventory();
129 }
130
131 void
132 mon_set_minvis(mon)
133 struct monst *mon;
134 {
135         mon->perminvis = 1;
136         if (!mon->invis_blkd) {
137             mon->minvis = 1;
138             newsym(mon->mx, mon->my);           /* make it disappear */
139             if (mon->wormno) see_wsegs(mon);    /* and any tail too */
140         }
141 }
142
143 void
144 mon_adjust_speed(mon, adjust, obj)
145 struct monst *mon;
146 int adjust;     /* positive => increase speed, negative => decrease */
147 struct obj *obj;        /* item to make known if effect can be seen */
148 {
149     struct obj *otmp;
150     boolean give_msg = !in_mklev, petrify = FALSE;
151     unsigned int oldspeed = mon->mspeed;
152
153     switch (adjust) {
154      case  2:
155         mon->permspeed = MFAST;
156         give_msg = FALSE;       /* special case monster creation */
157         break;
158      case  1:
159         if (mon->permspeed == MSLOW) mon->permspeed = 0;
160         else mon->permspeed = MFAST;
161         break;
162      case  0:                   /* just check for worn speed boots */
163         break;
164      case -1:
165         if (mon->permspeed == MFAST) mon->permspeed = 0;
166         else mon->permspeed = MSLOW;
167         break;
168      case -2:
169         mon->permspeed = MSLOW;
170         give_msg = FALSE;       /* (not currently used) */
171         break;
172      case -3:                   /* petrification */
173         /* take away intrinsic speed but don't reduce normal speed */
174         if (mon->permspeed == MFAST) mon->permspeed = 0;
175         petrify = TRUE;
176         break;
177     }
178
179     for (otmp = mon->minvent; otmp; otmp = otmp->nobj)
180         if (otmp->owornmask && objects[otmp->otyp].oc_oprop == FAST)
181             break;
182     if (otmp)           /* speed boots */
183         mon->mspeed = MFAST;
184     else
185         mon->mspeed = mon->permspeed;
186
187     if (give_msg && (mon->mspeed != oldspeed || petrify) && canseemon(mon)) {
188         /* fast to slow (skipping intermediate state) or vice versa */
189         const char *howmuch = (mon->mspeed + oldspeed == MFAST + MSLOW) ?
190                                 "much " : "";
191
192         if (petrify) {
193             /* mimic the player's petrification countdown; "slowing down"
194                even if fast movement rate retained via worn speed boots */
195             if (flags.verbose) pline("%s is slowing down.", Monnam(mon));
196         } else if (adjust > 0 || mon->mspeed == MFAST)
197             pline("%s is suddenly moving %sfaster.", Monnam(mon), howmuch);
198         else
199             pline("%s seems to be moving %sslower.", Monnam(mon), howmuch);
200
201         /* might discover an object if we see the speed change happen, but
202            avoid making possibly forgotten book known when casting its spell */
203         if (obj != 0 && obj->dknown &&
204                 objects[obj->otyp].oc_class != SPBOOK_CLASS)
205             makeknown(obj->otyp);
206     }
207 }
208
209 /* armor put on or taken off; might be magical variety */
210 void
211 update_mon_intrinsics(mon, obj, on, silently)
212 struct monst *mon;
213 struct obj *obj;
214 boolean on, silently;
215 {
216     int unseen;
217     uchar mask;
218     struct obj *otmp;
219     int which = (int) objects[obj->otyp].oc_oprop;
220
221     unseen = !canseemon(mon);
222     if (!which) goto maybe_blocks;
223
224     if (on) {
225         switch (which) {
226          case INVIS:
227             mon->minvis = !mon->invis_blkd;
228             break;
229          case FAST:
230           {
231             boolean save_in_mklev = in_mklev;
232             if (silently) in_mklev = TRUE;
233             mon_adjust_speed(mon, 0, obj);
234             in_mklev = save_in_mklev;
235             break;
236           }
237         /* properties handled elsewhere */
238          case ANTIMAGIC:
239          case REFLECTING:
240             break;
241         /* properties which have no effect for monsters */
242          case CLAIRVOYANT:
243          case STEALTH:
244          case TELEPAT:
245             break;
246         /* properties which should have an effect but aren't implemented */
247          case LEVITATION:
248          case WWALKING:
249             break;
250         /* properties which maybe should have an effect but don't */
251          case DISPLACED:
252          case FUMBLING:
253          case JUMPING:
254          case PROTECTION:
255             break;
256          default:
257             if (which <= 8) {   /* 1 thru 8 correspond to MR_xxx mask values */
258                 /* FIRE,COLD,SLEEP,DISINT,SHOCK,POISON,ACID,STONE */
259                 mask = (uchar) (1 << (which - 1));
260                 mon->mintrinsics |= (unsigned short) mask;
261             }
262             break;
263         }
264     } else {        /* off */
265         switch (which) {
266          case INVIS:
267             mon->minvis = mon->perminvis;
268             break;
269          case FAST:
270           {
271             boolean save_in_mklev = in_mklev;
272             if (silently) in_mklev = TRUE;
273             mon_adjust_speed(mon, 0, obj);
274             in_mklev = save_in_mklev;
275             break;
276           }
277          case FIRE_RES:
278          case COLD_RES:
279          case SLEEP_RES:
280          case DISINT_RES:
281          case SHOCK_RES:
282          case POISON_RES:
283          case ACID_RES:
284          case STONE_RES:
285             mask = (uchar) (1 << (which - 1));
286             /* If the monster doesn't have this resistance intrinsically,
287                check whether any other worn item confers it.  Note that
288                we don't currently check for anything conferred via simply
289                carrying an object. */
290             if (!(mon->data->mresists & mask)) {
291                 for (otmp = mon->minvent; otmp; otmp = otmp->nobj)
292                     if (otmp->owornmask &&
293                             (int) objects[otmp->otyp].oc_oprop == which)
294                         break;
295                 if (!otmp)
296                     mon->mintrinsics &= ~((unsigned short) mask);
297             }
298             break;
299          default:
300             break;
301         }
302     }
303
304  maybe_blocks:
305     /* obj->owornmask has been cleared by this point, so we can't use it.
306        However, since monsters don't wield armor, we don't have to guard
307        against that and can get away with a blanket worn-mask value. */
308     switch (w_blocks(obj,~0L)) {
309      case INVIS:
310         mon->invis_blkd = on ? 1 : 0;
311         mon->minvis = on ? 0 : mon->perminvis;
312         break;
313      default:
314         break;
315     }
316
317 #ifdef STEED
318         if (!on && mon == u.usteed && obj->otyp == SADDLE)
319             dismount_steed(DISMOUNT_FELL);
320 #endif
321
322     /* if couldn't see it but now can, or vice versa, update display */
323     if (!silently && (unseen ^ !canseemon(mon)))
324         newsym(mon->mx, mon->my);
325 }
326
327 int
328 find_mac(mon)
329 register struct monst *mon;
330 {
331         register struct obj *obj;
332         int base = mon->data->ac;
333         long mwflags = mon->misc_worn_check;
334
335         for (obj = mon->minvent; obj; obj = obj->nobj) {
336             if (obj->owornmask & mwflags)
337                 base -= ARM_BONUS(obj);
338                 /* since ARM_BONUS is positive, subtracting it increases AC */
339         }
340         return base;
341 }
342
343 /* weapons are handled separately; rings and eyewear aren't used by monsters */
344
345 /* Wear the best object of each type that the monster has.  During creation,
346  * the monster can put everything on at once; otherwise, wearing takes time.
347  * This doesn't affect monster searching for objects--a monster may very well
348  * search for objects it would not want to wear, because we don't want to
349  * check which_armor() each round.
350  *
351  * We'll let monsters put on shirts and/or suits under worn cloaks, but
352  * not shirts under worn suits.  This is somewhat arbitrary, but it's
353  * too tedious to have them remove and later replace outer garments,
354  * and preventing suits under cloaks makes it a little bit too easy for
355  * players to influence what gets worn.  Putting on a shirt underneath
356  * already worn body armor is too obviously buggy...
357  */
358 void
359 m_dowear(mon, creation)
360 register struct monst *mon;
361 boolean creation;
362 {
363 #define RACE_EXCEPTION TRUE
364         /* Note the restrictions here are the same as in dowear in do_wear.c
365          * except for the additional restriction on intelligence.  (Players
366          * are always intelligent, even if polymorphed).
367          */
368         if (verysmall(mon->data) || nohands(mon->data) || is_animal(mon->data))
369                 return;
370         /* give mummies a chance to wear their wrappings
371          * and let skeletons wear their initial armor */
372         if (mindless(mon->data) && (!creation ||
373             (mon->data->mlet != S_MUMMY && mon->data != &mons[PM_SKELETON])))
374                 return;
375
376         m_dowear_type(mon, W_AMUL, creation, FALSE);
377 #ifdef TOURIST
378         /* can't put on shirt if already wearing suit */
379         if (!cantweararm(mon->data) || (mon->misc_worn_check & W_ARM))
380             m_dowear_type(mon, W_ARMU, creation, FALSE);
381 #endif
382         /* treating small as a special case allows
383            hobbits, gnomes, and kobolds to wear cloaks */
384         if (!cantweararm(mon->data) || mon->data->msize == MZ_SMALL)
385             m_dowear_type(mon, W_ARMC, creation, FALSE);
386         m_dowear_type(mon, W_ARMH, creation, FALSE);
387         if (!MON_WEP(mon) || !bimanual(MON_WEP(mon)))
388             m_dowear_type(mon, W_ARMS, creation, FALSE);
389         m_dowear_type(mon, W_ARMG, creation, FALSE);
390         if (!slithy(mon->data) && mon->data->mlet != S_CENTAUR)
391             m_dowear_type(mon, W_ARMF, creation, FALSE);
392         if (!cantweararm(mon->data))
393             m_dowear_type(mon, W_ARM, creation, FALSE);
394         else
395             m_dowear_type(mon, W_ARM, creation, RACE_EXCEPTION);
396 }
397
398 STATIC_OVL void
399 m_dowear_type(mon, flag, creation, racialexception)
400 struct monst *mon;
401 long flag;
402 boolean creation;
403 boolean racialexception;
404 {
405         struct obj *old, *best, *obj;
406         int m_delay = 0;
407         int unseen = !canseemon(mon);
408         char nambuf[BUFSZ];
409
410         if (mon->mfrozen) return; /* probably putting previous item on */
411
412         /* Get a copy of monster's name before altering its visibility */
413         Strcpy(nambuf, See_invisible ? Monnam(mon) : mon_nam(mon));
414
415         old = which_armor(mon, flag);
416         if (old && old->cursed) return;
417         if (old && flag == W_AMUL) return; /* no such thing as better amulets */
418         best = old;
419
420         for(obj = mon->minvent; obj; obj = obj->nobj) {
421             switch(flag) {
422                 case W_AMUL:
423                     if (obj->oclass != AMULET_CLASS ||
424                             (obj->otyp != AMULET_OF_LIFE_SAVING &&
425                                 obj->otyp != AMULET_OF_REFLECTION))
426                         continue;
427                     best = obj;
428                     goto outer_break; /* no such thing as better amulets */
429 #ifdef TOURIST
430                 case W_ARMU:
431                     if (!is_shirt(obj)) continue;
432                     break;
433 #endif
434                 case W_ARMC:
435                     if (!is_cloak(obj)) continue;
436                     break;
437                 case W_ARMH:
438                     if (!is_helmet(obj)) continue;
439                     /* (flimsy exception matches polyself handling) */
440                     if (has_horns(mon->data) && !is_flimsy(obj)) continue;
441                     break;
442                 case W_ARMS:
443                     if (!is_shield(obj)) continue;
444                     break;
445                 case W_ARMG:
446                     if (!is_gloves(obj)) continue;
447                     break;
448                 case W_ARMF:
449                     if (!is_boots(obj)) continue;
450                     break;
451                 case W_ARM:
452                     if (!is_suit(obj)) continue;
453                     if (racialexception && (racial_exception(mon, obj) < 1)) continue;
454                     break;
455             }
456             if (obj->owornmask) continue;
457             /* I'd like to define a VISIBLE_ARM_BONUS which doesn't assume the
458              * monster knows obj->spe, but if I did that, a monster would keep
459              * switching forever between two -2 caps since when it took off one
460              * it would forget spe and once again think the object is better
461              * than what it already has.
462              */
463             if (best && (ARM_BONUS(best) + extra_pref(mon,best) >= ARM_BONUS(obj) + extra_pref(mon,obj)))
464                 continue;
465             best = obj;
466         }
467 outer_break:
468         if (!best || best == old) return;
469
470         /* if wearing a cloak, account for the time spent removing
471            and re-wearing it when putting on a suit or shirt */
472         if ((flag == W_ARM
473 #ifdef TOURIST
474           || flag == W_ARMU
475 #endif
476                           ) && (mon->misc_worn_check & W_ARMC))
477             m_delay += 2;
478         /* when upgrading a piece of armor, account for time spent
479            taking off current one */
480         if (old)
481             m_delay += objects[old->otyp].oc_delay;
482
483         if (old) /* do this first to avoid "(being worn)" */
484             old->owornmask = 0L;
485         if (!creation) {
486             if (canseemon(mon)) {
487                 char buf[BUFSZ];
488
489                 if (old)
490                     Sprintf(buf, " removes %s and", distant_name(old, doname));
491                 else
492                     buf[0] = '\0';
493                 pline("%s%s puts on %s.", Monnam(mon),
494                       buf, distant_name(best,doname));
495             } /* can see it */
496             m_delay += objects[best->otyp].oc_delay;
497             mon->mfrozen = m_delay;
498             if (mon->mfrozen) mon->mcanmove = 0;
499         }
500         if (old)
501             update_mon_intrinsics(mon, old, FALSE, creation);
502         mon->misc_worn_check |= flag;
503         best->owornmask |= flag;
504         update_mon_intrinsics(mon, best, TRUE, creation);
505         /* if couldn't see it but now can, or vice versa, */
506         if (!creation && (unseen ^ !canseemon(mon))) {
507                 if (mon->minvis && !See_invisible) {
508                         pline("Suddenly you cannot see %s.", nambuf);
509                         makeknown(best->otyp);
510                 } /* else if (!mon->minvis) pline("%s suddenly appears!", Amonnam(mon)); */
511         }
512 }
513 #undef RACE_EXCEPTION
514
515 struct obj *
516 which_armor(mon, flag)
517 struct monst *mon;
518 long flag;
519 {
520         register struct obj *obj;
521
522         for(obj = mon->minvent; obj; obj = obj->nobj)
523                 if (obj->owornmask & flag) return obj;
524         return((struct obj *)0);
525 }
526
527 /* remove an item of armor and then drop it */
528 STATIC_OVL void
529 m_lose_armor(mon, obj)
530 struct monst *mon;
531 struct obj *obj;
532 {
533         mon->misc_worn_check &= ~obj->owornmask;
534         if (obj->owornmask)
535             update_mon_intrinsics(mon, obj, FALSE, FALSE);
536         obj->owornmask = 0L;
537
538         obj_extract_self(obj);
539         place_object(obj, mon->mx, mon->my);
540         /* call stackobj() if we ever drop anything that can merge */
541         newsym(mon->mx, mon->my);
542 }
543
544 /* all objects with their bypass bit set should now be reset to normal */
545 void
546 clear_bypasses()
547 {
548         struct obj *otmp, *nobj;
549         struct monst *mtmp;
550
551         for (otmp = fobj; otmp; otmp = nobj) {
552             nobj = otmp->nobj;
553             if (otmp->bypass) {
554                 otmp->bypass = 0;
555                 /* bypass will have inhibited any stacking, but since it's
556                    used for polymorph handling, the objects here probably
557                    have been transformed and won't be stacked in the usual
558                    manner afterwards; so don't bother with this */
559 #if 0
560                 if (objects[otmp->otyp].oc_merge) {
561                     xchar ox, oy;
562
563                     (void) get_obj_location(otmp, &ox, &oy, 0);
564                     stack_object(otmp);
565                     newsym(ox, oy);
566                 }
567 #endif  /*0*/
568             }
569         }
570         /* invent and mydogs chains shouldn't matter here */
571         for (otmp = migrating_objs; otmp; otmp = otmp->nobj)
572             otmp->bypass = 0;
573         for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
574             if (DEADMONSTER(mtmp)) continue;
575             for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
576                 otmp->bypass = 0;
577         }
578         for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) {
579             for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
580                 otmp->bypass = 0;
581         }
582         flags.bypasses = FALSE;
583 }
584
585 void
586 bypass_obj(obj)
587 struct obj *obj;
588 {
589         obj->bypass = 1;
590         flags.bypasses = TRUE;
591 }
592
593 void
594 mon_break_armor(mon, polyspot)
595 struct monst *mon;
596 boolean polyspot;
597 {
598         register struct obj *otmp;
599         struct permonst *mdat = mon->data;
600         boolean vis = cansee(mon->mx, mon->my);
601         boolean handless_or_tiny = (nohands(mdat) || verysmall(mdat));
602         const char *pronoun = mhim(mon),
603                         *ppronoun = mhis(mon);
604
605         if (breakarm(mdat)) {
606             if ((otmp = which_armor(mon, W_ARM)) != 0) {
607                 if ((Is_dragon_scales(otmp) &&
608                         mdat == Dragon_scales_to_pm(otmp)) ||
609                     (Is_dragon_mail(otmp) && mdat == Dragon_mail_to_pm(otmp)))
610                     ;   /* no message here;
611                            "the dragon merges with his scaly armor" is odd
612                            and the monster's previous form is already gone */
613                 else if (vis)
614                     pline("%s breaks out of %s armor!", Monnam(mon), ppronoun);
615                 else
616                     You_hear("a cracking sound.");
617                 m_useup(mon, otmp);
618             }
619             if ((otmp = which_armor(mon, W_ARMC)) != 0) {
620                 if (otmp->oartifact) {
621                     if (vis)
622                         pline("%s %s falls off!", s_suffix(Monnam(mon)),
623                                 cloak_simple_name(otmp));
624                     if (polyspot) bypass_obj(otmp);
625                     m_lose_armor(mon, otmp);
626                 } else {
627                     if (vis)
628                         pline("%s %s tears apart!", s_suffix(Monnam(mon)),
629                                 cloak_simple_name(otmp));
630                     else
631                         You_hear("a ripping sound.");
632                     m_useup(mon, otmp);
633                 }
634             }
635 #ifdef TOURIST
636             if ((otmp = which_armor(mon, W_ARMU)) != 0) {
637                 if (vis)
638                     pline("%s shirt rips to shreds!", s_suffix(Monnam(mon)));
639                 else
640                     You_hear("a ripping sound.");
641                 m_useup(mon, otmp);
642             }
643 #endif
644         } else if (sliparm(mdat)) {
645             if ((otmp = which_armor(mon, W_ARM)) != 0) {
646                 if (vis)
647                     pline("%s armor falls around %s!",
648                                  s_suffix(Monnam(mon)), pronoun);
649                 else
650                     You_hear("a thud.");
651                 if (polyspot) bypass_obj(otmp);
652                 m_lose_armor(mon, otmp);
653             }
654             if ((otmp = which_armor(mon, W_ARMC)) != 0) {
655                 if (vis) {
656                     if (is_whirly(mon->data))
657                         pline("%s %s falls, unsupported!",
658                                      s_suffix(Monnam(mon)), cloak_simple_name(otmp));
659                     else
660                         pline("%s shrinks out of %s %s!", Monnam(mon),
661                                                 ppronoun, cloak_simple_name(otmp));
662                 }
663                 if (polyspot) bypass_obj(otmp);
664                 m_lose_armor(mon, otmp);
665             }
666 #ifdef TOURIST
667             if ((otmp = which_armor(mon, W_ARMU)) != 0) {
668                 if (vis) {
669                     if (sliparm(mon->data))
670                         pline("%s seeps right through %s shirt!",
671                                         Monnam(mon), ppronoun);
672                     else
673                         pline("%s becomes much too small for %s shirt!",
674                                         Monnam(mon), ppronoun);
675                 }
676                 if (polyspot) bypass_obj(otmp);
677                 m_lose_armor(mon, otmp);
678             }
679 #endif
680         }
681         if (handless_or_tiny) {
682             /* [caller needs to handle weapon checks] */
683             if ((otmp = which_armor(mon, W_ARMG)) != 0) {
684                 if (vis)
685                     pline("%s drops %s gloves%s!", Monnam(mon), ppronoun,
686                                         MON_WEP(mon) ? " and weapon" : "");
687                 if (polyspot) bypass_obj(otmp);
688                 m_lose_armor(mon, otmp);
689             }
690             if ((otmp = which_armor(mon, W_ARMS)) != 0) {
691                 if (vis)
692                     pline("%s can no longer hold %s shield!", Monnam(mon),
693                                                                 ppronoun);
694                 else
695                     You_hear("a clank.");
696                 if (polyspot) bypass_obj(otmp);
697                 m_lose_armor(mon, otmp);
698             }
699         }
700         if (handless_or_tiny || has_horns(mdat)) {
701             if ((otmp = which_armor(mon, W_ARMH)) != 0 &&
702                     /* flimsy test for horns matches polyself handling */
703                     (handless_or_tiny || !is_flimsy(otmp))) {
704                 if (vis)
705                     pline("%s helmet falls to the %s!",
706                           s_suffix(Monnam(mon)), surface(mon->mx, mon->my));
707                 else
708                     You_hear("a clank.");
709                 if (polyspot) bypass_obj(otmp);
710                 m_lose_armor(mon, otmp);
711             }
712         }
713         if (handless_or_tiny || slithy(mdat) || mdat->mlet == S_CENTAUR) {
714             if ((otmp = which_armor(mon, W_ARMF)) != 0) {
715                 if (vis) {
716                     if (is_whirly(mon->data))
717                         pline("%s boots fall away!",
718                                        s_suffix(Monnam(mon)));
719                     else pline("%s boots %s off %s feet!",
720                         s_suffix(Monnam(mon)),
721                         verysmall(mdat) ? "slide" : "are pushed", ppronoun);
722                 }
723                 if (polyspot) bypass_obj(otmp);
724                 m_lose_armor(mon, otmp);
725             }
726         }
727 #ifdef STEED
728         if (!can_saddle(mon)) {
729             if ((otmp = which_armor(mon, W_SADDLE)) != 0) {
730                 if (polyspot) bypass_obj(otmp);
731                 m_lose_armor(mon, otmp);
732                 if (vis)
733                     pline("%s saddle falls off.", s_suffix(Monnam(mon)));
734             }
735             if (mon == u.usteed)
736                 goto noride;
737         } else if (mon == u.usteed && !can_ride(mon)) {
738         noride:
739             You("can no longer ride %s.", mon_nam(mon));
740             if (touch_petrifies(u.usteed->data) &&
741                         !Stone_resistance && rnl(3)) {
742                 char buf[BUFSZ];
743
744                 You("touch %s.", mon_nam(u.usteed));
745                 Sprintf(buf, "falling off %s",
746                                 an(u.usteed->data->mname));
747                 instapetrify(buf);
748             }
749             dismount_steed(DISMOUNT_FELL);
750         }
751 #endif
752         return;
753 }
754
755 /* bias a monster's preferences towards armor that has special benefits. */
756 /* currently only does speed boots, but might be expanded if monsters get to
757    use more armor abilities */
758 static int
759 extra_pref(mon, obj)
760 struct monst *mon;
761 struct obj *obj;
762 {
763     if (obj) {
764         if (obj->otyp == SPEED_BOOTS && mon->permspeed != MFAST)
765             return 20;
766     }
767     return 0;
768 }
769
770 /*
771  * Exceptions to things based on race. Correctly checks polymorphed player race.
772  * Returns:
773  *       0 No exception, normal rules apply.
774  *       1 If the race/object combination is acceptable.
775  *      -1 If the race/object combination is unacceptable.
776  */
777 int
778 racial_exception(mon, obj)
779 struct monst *mon;
780 struct obj *obj;
781 {
782     const struct permonst *ptr = raceptr(mon);
783
784     /* Acceptable Exceptions: */
785     /* Allow hobbits to wear elven armor - LoTR */
786     if (ptr == &mons[PM_HOBBIT] && is_elven_armor(obj))
787         return 1;
788     /* Unacceptable Exceptions: */
789     /* Checks for object that certain races should never use go here */
790     /*  return -1; */
791
792     return 0;
793 }
794 /*worn.c*/