1 /* NetHack 3.6	worn.c	$NHDT-Date: 1550524569 2019/02/18 21:16:09 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.56 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2013. */
4 /* NetHack may be freely redistributed.  See license for details. */
5 
6 #include "hack.h"
7 
8 STATIC_DCL void FDECL(m_lose_armor, (struct monst *, struct obj *));
9 STATIC_DCL void FDECL(m_dowear_type,
10                       (struct monst *, long, BOOLEAN_P, BOOLEAN_P));
11 STATIC_DCL int FDECL(extra_pref, (struct monst *, struct obj *));
12 
13 const struct worn {
14     long w_mask;
15     struct obj **w_obj;
16 } worn[] = { { W_ARM, &uarm },
17              { W_ARMC, &uarmc },
18              { W_ARMH, &uarmh },
19              { W_ARMS, &uarms },
20              { W_ARMG, &uarmg },
21              { W_ARMF, &uarmf },
22              { W_ARMU, &uarmu },
23              { W_RINGL, &uleft },
24              { W_RINGR, &uright },
25              { W_WEP, &uwep },
26              { W_SWAPWEP, &uswapwep },
27              { W_QUIVER, &uquiver },
28              { W_AMUL, &uamul },
29              { W_TOOL, &ublindf },
30              { W_BALL, &uball },
31              { W_CHAIN, &uchain },
32              { 0, 0 }
33 };
34 
35 /* This only allows for one blocking item per property */
36 #define w_blocks(o, m) \
37     ((o->otyp == MUMMY_WRAPPING && ((m) & W_ARMC))                          \
38          ? INVIS                                                            \
39          : (o->otyp == CORNUTHAUM && ((m) & W_ARMH) && !Role_if(PM_WIZARD)) \
40                ? CLAIRVOYANT                                                \
41                : 0)
42 /* note: monsters don't have clairvoyance, so your role
43    has no significant effect on their use of w_blocks() */
44 
45 /* Updated to use the extrinsic and blocked fields. */
46 void
setworn(obj,mask)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         if ((mask & W_ARMOR))
61             u.uroleplay.nudist = FALSE;
62         for (wp = worn; wp->w_mask; wp++)
63             if (wp->w_mask & mask) {
64                 oobj = *(wp->w_obj);
65                 if (oobj && !(oobj->owornmask & wp->w_mask))
66                     impossible("Setworn: mask = %ld.", wp->w_mask);
67                 if (oobj) {
68                     if (u.twoweap && (oobj->owornmask & (W_WEP | W_SWAPWEP)))
69                         u.twoweap = 0;
70                     oobj->owornmask &= ~wp->w_mask;
71                     if (wp->w_mask & ~(W_SWAPWEP | W_QUIVER)) {
72                         /* leave as "x = x <op> y", here and below, for broken
73                          * compilers */
74                         p = objects[oobj->otyp].oc_oprop;
75                         u.uprops[p].extrinsic =
76                             u.uprops[p].extrinsic & ~wp->w_mask;
77                         if ((p = w_blocks(oobj, mask)) != 0)
78                             u.uprops[p].blocked &= ~wp->w_mask;
79                         if (oobj->oartifact)
80                             set_artifact_intrinsic(oobj, 0, mask);
81                     }
82                     /* in case wearing or removal is in progress or removal
83                        is pending (via 'A' command for multiple items) */
84                     cancel_doff(oobj, wp->w_mask);
85                 }
86                 *(wp->w_obj) = obj;
87                 if (obj) {
88                     obj->owornmask |= wp->w_mask;
89                     /* Prevent getting/blocking intrinsics from wielding
90                      * potions, through the quiver, etc.
91                      * Allow weapon-tools, too.
92                      * wp_mask should be same as mask at this point.
93                      */
94                     if (wp->w_mask & ~(W_SWAPWEP | W_QUIVER)) {
95                         if (obj->oclass == WEAPON_CLASS || is_weptool(obj)
96                             || mask != W_WEP) {
97                             p = objects[obj->otyp].oc_oprop;
98                             u.uprops[p].extrinsic =
99                                 u.uprops[p].extrinsic | wp->w_mask;
100                             if ((p = w_blocks(obj, mask)) != 0)
101                                 u.uprops[p].blocked |= wp->w_mask;
102                         }
103                         if (obj->oartifact)
104                             set_artifact_intrinsic(obj, 1, mask);
105                     }
106                 }
107             }
108     }
109     update_inventory();
110 }
111 
112 /* called e.g. when obj is destroyed */
113 /* Updated to use the extrinsic and blocked fields. */
114 void
setnotworn(obj)115 setnotworn(obj)
116 register struct obj *obj;
117 {
118     register const struct worn *wp;
119     register int p;
120 
121     if (!obj)
122         return;
123     if (obj == uwep || obj == uswapwep)
124         u.twoweap = 0;
125     for (wp = worn; wp->w_mask; wp++)
126         if (obj == *(wp->w_obj)) {
127             /* in case wearing or removal is in progress or removal
128                is pending (via 'A' command for multiple items) */
129             cancel_doff(obj, wp->w_mask);
130 
131             *(wp->w_obj) = 0;
132             p = objects[obj->otyp].oc_oprop;
133             u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask;
134             obj->owornmask &= ~wp->w_mask;
135             if (obj->oartifact)
136                 set_artifact_intrinsic(obj, 0, wp->w_mask);
137             if ((p = w_blocks(obj, wp->w_mask)) != 0)
138                 u.uprops[p].blocked &= ~wp->w_mask;
139         }
140     update_inventory();
141 }
142 
143 /* return item worn in slot indiciated by wornmask; needed by poly_obj() */
144 struct obj *
wearmask_to_obj(wornmask)145 wearmask_to_obj(wornmask)
146 long wornmask;
147 {
148     const struct worn *wp;
149 
150     for (wp = worn; wp->w_mask; wp++)
151         if (wp->w_mask & wornmask)
152             return *wp->w_obj;
153     return (struct obj *) 0;
154 }
155 
156 /* return a bitmask of the equipment slot(s) a given item might be worn in */
157 long
wearslot(obj)158 wearslot(obj)
159 struct obj *obj;
160 {
161     int otyp = obj->otyp;
162     /* practically any item can be wielded or quivered; it's up to
163        our caller to handle such things--we assume "normal" usage */
164     long res = 0L; /* default: can't be worn anywhere */
165 
166     switch (obj->oclass) {
167     case AMULET_CLASS:
168         res = W_AMUL; /* WORN_AMUL */
169         break;
170     case RING_CLASS:
171         res = W_RINGL | W_RINGR; /* W_RING, BOTH_SIDES */
172         break;
173     case ARMOR_CLASS:
174         switch (objects[otyp].oc_armcat) {
175         case ARM_SUIT:
176             res = W_ARM;
177             break; /* WORN_ARMOR */
178         case ARM_SHIELD:
179             res = W_ARMS;
180             break; /* WORN_SHIELD */
181         case ARM_HELM:
182             res = W_ARMH;
183             break; /* WORN_HELMET */
184         case ARM_GLOVES:
185             res = W_ARMG;
186             break; /* WORN_GLOVES */
187         case ARM_BOOTS:
188             res = W_ARMF;
189             break; /* WORN_BOOTS */
190         case ARM_CLOAK:
191             res = W_ARMC;
192             break; /* WORN_CLOAK */
193         case ARM_SHIRT:
194             res = W_ARMU;
195             break; /* WORN_SHIRT */
196         }
197         break;
198     case WEAPON_CLASS:
199         res = W_WEP | W_SWAPWEP;
200         if (objects[otyp].oc_merge)
201             res |= W_QUIVER;
202         break;
203     case TOOL_CLASS:
204         if (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)
205             res = W_TOOL; /* WORN_BLINDF */
206         else if (is_weptool(obj) || otyp == TIN_OPENER)
207             res = W_WEP | W_SWAPWEP;
208         else if (otyp == SADDLE)
209             res = W_SADDLE;
210         break;
211     case FOOD_CLASS:
212         if (obj->otyp == MEAT_RING)
213             res = W_RINGL | W_RINGR;
214         break;
215     case GEM_CLASS:
216         res = W_QUIVER;
217         break;
218     case BALL_CLASS:
219         res = W_BALL;
220         break;
221     case CHAIN_CLASS:
222         res = W_CHAIN;
223         break;
224     default:
225         break;
226     }
227     return res;
228 }
229 
230 void
mon_set_minvis(mon)231 mon_set_minvis(mon)
232 struct monst *mon;
233 {
234     mon->perminvis = 1;
235     if (!mon->invis_blkd) {
236         mon->minvis = 1;
237         newsym(mon->mx, mon->my); /* make it disappear */
238         if (mon->wormno)
239             see_wsegs(mon); /* and any tail too */
240     }
241 }
242 
243 void
mon_adjust_speed(mon,adjust,obj)244 mon_adjust_speed(mon, adjust, obj)
245 struct monst *mon;
246 int adjust;      /* positive => increase speed, negative => decrease */
247 struct obj *obj; /* item to make known if effect can be seen */
248 {
249     struct obj *otmp;
250     boolean give_msg = !in_mklev, petrify = FALSE;
251     unsigned int oldspeed = mon->mspeed;
252 
253     switch (adjust) {
254     case 2:
255         mon->permspeed = MFAST;
256         give_msg = FALSE; /* special case monster creation */
257         break;
258     case 1:
259         if (mon->permspeed == MSLOW)
260             mon->permspeed = 0;
261         else
262             mon->permspeed = MFAST;
263         break;
264     case 0: /* just check for worn speed boots */
265         break;
266     case -1:
267         if (mon->permspeed == MFAST)
268             mon->permspeed = 0;
269         else
270             mon->permspeed = MSLOW;
271         break;
272     case -2:
273         mon->permspeed = MSLOW;
274         give_msg = FALSE; /* (not currently used) */
275         break;
276     case -3: /* petrification */
277         /* take away intrinsic speed but don't reduce normal speed */
278         if (mon->permspeed == MFAST)
279             mon->permspeed = 0;
280         petrify = TRUE;
281         break;
282     case -4: /* green slime */
283         if (mon->permspeed == MFAST)
284             mon->permspeed = 0;
285         give_msg = FALSE;
286         break;
287     }
288 
289     for (otmp = mon->minvent; otmp; otmp = otmp->nobj)
290         if (otmp->owornmask && objects[otmp->otyp].oc_oprop == FAST)
291             break;
292     if (otmp) /* speed boots */
293         mon->mspeed = MFAST;
294     else
295         mon->mspeed = mon->permspeed;
296 
297     /* no message if monster is immobile (temp or perm) or unseen */
298     if (give_msg && (mon->mspeed != oldspeed || petrify) && mon->data->mmove
299         && !(mon->mfrozen || mon->msleeping) && canseemon(mon)) {
300         /* fast to slow (skipping intermediate state) or vice versa */
301         const char *howmuch =
302             (mon->mspeed + oldspeed == MFAST + MSLOW) ? "much " : "";
303 
304         if (petrify) {
305             /* mimic the player's petrification countdown; "slowing down"
306                even if fast movement rate retained via worn speed boots */
307             if (flags.verbose)
308                 pline("%s is slowing down.", Monnam(mon));
309         } else if (adjust > 0 || mon->mspeed == MFAST)
310             pline("%s is suddenly moving %sfaster.", Monnam(mon), howmuch);
311         else
312             pline("%s seems to be moving %sslower.", Monnam(mon), howmuch);
313 
314         /* might discover an object if we see the speed change happen */
315         if (obj != 0)
316             learnwand(obj);
317     }
318 }
319 
320 /* armor put on or taken off; might be magical variety
321    [TODO: rename to 'update_mon_extrinsics()' and change all callers...] */
322 void
update_mon_intrinsics(mon,obj,on,silently)323 update_mon_intrinsics(mon, obj, on, silently)
324 struct monst *mon;
325 struct obj *obj;
326 boolean on, silently;
327 {
328     int unseen;
329     uchar mask;
330     struct obj *otmp;
331     int which = (int) objects[obj->otyp].oc_oprop;
332 
333     unseen = !canseemon(mon);
334     if (!which)
335         goto maybe_blocks;
336 
337     if (on) {
338         switch (which) {
339         case INVIS:
340             mon->minvis = !mon->invis_blkd;
341             break;
342         case FAST: {
343             boolean save_in_mklev = in_mklev;
344             if (silently)
345                 in_mklev = TRUE;
346             mon_adjust_speed(mon, 0, obj);
347             in_mklev = save_in_mklev;
348             break;
349         }
350         /* properties handled elsewhere */
351         case ANTIMAGIC:
352         case REFLECTING:
353             break;
354         /* properties which have no effect for monsters */
355         case CLAIRVOYANT:
356         case STEALTH:
357         case TELEPAT:
358             break;
359         /* properties which should have an effect but aren't implemented */
360         case LEVITATION:
361         case WWALKING:
362             break;
363         /* properties which maybe should have an effect but don't */
364         case DISPLACED:
365         case FUMBLING:
366         case JUMPING:
367         case PROTECTION:
368             break;
369         default:
370             if (which <= 8) { /* 1 thru 8 correspond to MR_xxx mask values */
371                 /* FIRE,COLD,SLEEP,DISINT,SHOCK,POISON,ACID,STONE */
372                 mask = (uchar) (1 << (which - 1));
373                 mon->mextrinsics |= (unsigned short) mask;
374             }
375             break;
376         }
377     } else { /* off */
378         switch (which) {
379         case INVIS:
380             mon->minvis = mon->perminvis;
381             break;
382         case FAST: {
383             boolean save_in_mklev = in_mklev;
384             if (silently)
385                 in_mklev = TRUE;
386             mon_adjust_speed(mon, 0, obj);
387             in_mklev = save_in_mklev;
388             break;
389         }
390         case FIRE_RES:
391         case COLD_RES:
392         case SLEEP_RES:
393         case DISINT_RES:
394         case SHOCK_RES:
395         case POISON_RES:
396         case ACID_RES:
397         case STONE_RES:
398             mask = (uchar) (1 << (which - 1));
399             /* update monster's extrinsics (for worn objects only;
400                'obj' itself might still be worn or already unworn) */
401             for (otmp = mon->minvent; otmp; otmp = otmp->nobj)
402                 if (otmp != obj
403                     && otmp->owornmask
404                     && (int) objects[otmp->otyp].oc_oprop == which)
405                     break;
406             if (!otmp)
407                 mon->mextrinsics &= ~((unsigned short) mask);
408             break;
409         default:
410             break;
411         }
412     }
413 
414  maybe_blocks:
415     /* obj->owornmask has been cleared by this point, so we can't use it.
416        However, since monsters don't wield armor, we don't have to guard
417        against that and can get away with a blanket worn-mask value. */
418     switch (w_blocks(obj, ~0L)) {
419     case INVIS:
420         mon->invis_blkd = on ? 1 : 0;
421         mon->minvis = on ? 0 : mon->perminvis;
422         break;
423     default:
424         break;
425     }
426 
427     if (!on && mon == u.usteed && obj->otyp == SADDLE)
428         dismount_steed(DISMOUNT_FELL);
429 
430     /* if couldn't see it but now can, or vice versa, update display */
431     if (!silently && (unseen ^ !canseemon(mon)))
432         newsym(mon->mx, mon->my);
433 }
434 
435 int
find_mac(mon)436 find_mac(mon)
437 register struct monst *mon;
438 {
439     register struct obj *obj;
440     int base = mon->data->ac;
441     long mwflags = mon->misc_worn_check;
442 
443     for (obj = mon->minvent; obj; obj = obj->nobj) {
444         if (obj->owornmask & mwflags)
445             base -= ARM_BONUS(obj);
446         /* since ARM_BONUS is positive, subtracting it increases AC */
447     }
448     return base;
449 }
450 
451 /*
452  * weapons are handled separately;
453  * rings and eyewear aren't used by monsters
454  */
455 
456 /* Wear the best object of each type that the monster has.  During creation,
457  * the monster can put everything on at once; otherwise, wearing takes time.
458  * This doesn't affect monster searching for objects--a monster may very well
459  * search for objects it would not want to wear, because we don't want to
460  * check which_armor() each round.
461  *
462  * We'll let monsters put on shirts and/or suits under worn cloaks, but
463  * not shirts under worn suits.  This is somewhat arbitrary, but it's
464  * too tedious to have them remove and later replace outer garments,
465  * and preventing suits under cloaks makes it a little bit too easy for
466  * players to influence what gets worn.  Putting on a shirt underneath
467  * already worn body armor is too obviously buggy...
468  */
469 void
m_dowear(mon,creation)470 m_dowear(mon, creation)
471 register struct monst *mon;
472 boolean creation;
473 {
474 #define RACE_EXCEPTION TRUE
475     /* Note the restrictions here are the same as in dowear in do_wear.c
476      * except for the additional restriction on intelligence.  (Players
477      * are always intelligent, even if polymorphed).
478      */
479     if (verysmall(mon->data) || nohands(mon->data) || is_animal(mon->data))
480         return;
481     /* give mummies a chance to wear their wrappings
482      * and let skeletons wear their initial armor */
483     if (mindless(mon->data)
484         && (!creation || (mon->data->mlet != S_MUMMY
485                           && mon->data != &mons[PM_SKELETON])))
486         return;
487 
488     m_dowear_type(mon, W_AMUL, creation, FALSE);
489     /* can't put on shirt if already wearing suit */
490     if (!cantweararm(mon->data) && !(mon->misc_worn_check & W_ARM))
491         m_dowear_type(mon, W_ARMU, creation, FALSE);
492     /* treating small as a special case allows
493        hobbits, gnomes, and kobolds to wear cloaks */
494     if (!cantweararm(mon->data) || mon->data->msize == MZ_SMALL)
495         m_dowear_type(mon, W_ARMC, creation, FALSE);
496     m_dowear_type(mon, W_ARMH, creation, FALSE);
497     if (!MON_WEP(mon) || !bimanual(MON_WEP(mon)))
498         m_dowear_type(mon, W_ARMS, creation, FALSE);
499     m_dowear_type(mon, W_ARMG, creation, FALSE);
500     if (!slithy(mon->data) && mon->data->mlet != S_CENTAUR)
501         m_dowear_type(mon, W_ARMF, creation, FALSE);
502     if (!cantweararm(mon->data))
503         m_dowear_type(mon, W_ARM, creation, FALSE);
504     else
505         m_dowear_type(mon, W_ARM, creation, RACE_EXCEPTION);
506 }
507 
508 STATIC_OVL void
m_dowear_type(mon,flag,creation,racialexception)509 m_dowear_type(mon, flag, creation, racialexception)
510 struct monst *mon;
511 long flag;
512 boolean creation;
513 boolean racialexception;
514 {
515     struct obj *old, *best, *obj;
516     int m_delay = 0;
517     int unseen = !canseemon(mon);
518     boolean autocurse;
519     char nambuf[BUFSZ];
520 
521     if (mon->mfrozen)
522         return; /* probably putting previous item on */
523 
524     /* Get a copy of monster's name before altering its visibility */
525     Strcpy(nambuf, See_invisible ? Monnam(mon) : mon_nam(mon));
526 
527     old = which_armor(mon, flag);
528     if (old && old->cursed)
529         return;
530     if (old && flag == W_AMUL)
531         return; /* no such thing as better amulets */
532     best = old;
533 
534     for (obj = mon->minvent; obj; obj = obj->nobj) {
535         switch (flag) {
536         case W_AMUL:
537             if (obj->oclass != AMULET_CLASS
538                 || (obj->otyp != AMULET_OF_LIFE_SAVING
539                     && obj->otyp != AMULET_OF_REFLECTION))
540                 continue;
541             best = obj;
542             goto outer_break; /* no such thing as better amulets */
543         case W_ARMU:
544             if (!is_shirt(obj))
545                 continue;
546             break;
547         case W_ARMC:
548             if (!is_cloak(obj))
549                 continue;
550             break;
551         case W_ARMH:
552             if (!is_helmet(obj))
553                 continue;
554             /* changing alignment is not implemented for monsters;
555                priests and minions could change alignment but wouldn't
556                want to, so they reject helms of opposite alignment */
557             if (obj->otyp == HELM_OF_OPPOSITE_ALIGNMENT
558                 && (mon->ispriest || mon->isminion))
559                 continue;
560             /* (flimsy exception matches polyself handling) */
561             if (has_horns(mon->data) && !is_flimsy(obj))
562                 continue;
563             break;
564         case W_ARMS:
565             if (!is_shield(obj))
566                 continue;
567             break;
568         case W_ARMG:
569             if (!is_gloves(obj))
570                 continue;
571             break;
572         case W_ARMF:
573             if (!is_boots(obj))
574                 continue;
575             break;
576         case W_ARM:
577             if (!is_suit(obj))
578                 continue;
579             if (racialexception && (racial_exception(mon, obj) < 1))
580                 continue;
581             break;
582         }
583         if (obj->owornmask)
584             continue;
585         /* I'd like to define a VISIBLE_ARM_BONUS which doesn't assume the
586          * monster knows obj->spe, but if I did that, a monster would keep
587          * switching forever between two -2 caps since when it took off one
588          * it would forget spe and once again think the object is better
589          * than what it already has.
590          */
591         if (best && (ARM_BONUS(best) + extra_pref(mon, best)
592                      >= ARM_BONUS(obj) + extra_pref(mon, obj)))
593             continue;
594         best = obj;
595     }
596 outer_break:
597     if (!best || best == old)
598         return;
599 
600     /* same auto-cursing behavior as for hero */
601     autocurse = ((best->otyp == HELM_OF_OPPOSITE_ALIGNMENT
602                   || best->otyp == DUNCE_CAP) && !best->cursed);
603     /* if wearing a cloak, account for the time spent removing
604        and re-wearing it when putting on a suit or shirt */
605     if ((flag == W_ARM || flag == W_ARMU) && (mon->misc_worn_check & W_ARMC))
606         m_delay += 2;
607     /* when upgrading a piece of armor, account for time spent
608        taking off current one */
609     if (old)
610         m_delay += objects[old->otyp].oc_delay;
611 
612     if (old) /* do this first to avoid "(being worn)" */
613         old->owornmask = 0L;
614     if (!creation) {
615         if (canseemon(mon)) {
616             char buf[BUFSZ];
617 
618             if (old)
619                 Sprintf(buf, " removes %s and", distant_name(old, doname));
620             else
621                 buf[0] = '\0';
622             pline("%s%s puts on %s.", Monnam(mon), buf,
623                   distant_name(best, doname));
624             if (autocurse)
625                 pline("%s %s %s %s for a moment.", s_suffix(Monnam(mon)),
626                       simpleonames(best), otense(best, "glow"),
627                       hcolor(NH_BLACK));
628         } /* can see it */
629         m_delay += objects[best->otyp].oc_delay;
630         mon->mfrozen = m_delay;
631         if (mon->mfrozen)
632             mon->mcanmove = 0;
633     }
634     if (old)
635         update_mon_intrinsics(mon, old, FALSE, creation);
636     mon->misc_worn_check |= flag;
637     best->owornmask |= flag;
638     if (autocurse)
639         curse(best);
640     update_mon_intrinsics(mon, best, TRUE, creation);
641     /* if couldn't see it but now can, or vice versa, */
642     if (!creation && (unseen ^ !canseemon(mon))) {
643         if (mon->minvis && !See_invisible) {
644             pline("Suddenly you cannot see %s.", nambuf);
645             makeknown(best->otyp);
646         } /* else if (!mon->minvis) pline("%s suddenly appears!",
647              Amonnam(mon)); */
648     }
649 }
650 #undef RACE_EXCEPTION
651 
652 struct obj *
which_armor(mon,flag)653 which_armor(mon, flag)
654 struct monst *mon;
655 long flag;
656 {
657     if (mon == &youmonst) {
658         switch (flag) {
659         case W_ARM:
660             return uarm;
661         case W_ARMC:
662             return uarmc;
663         case W_ARMH:
664             return uarmh;
665         case W_ARMS:
666             return uarms;
667         case W_ARMG:
668             return uarmg;
669         case W_ARMF:
670             return uarmf;
671         case W_ARMU:
672             return uarmu;
673         default:
674             impossible("bad flag in which_armor");
675             return 0;
676         }
677     } else {
678         register struct obj *obj;
679 
680         for (obj = mon->minvent; obj; obj = obj->nobj)
681             if (obj->owornmask & flag)
682                 return obj;
683         return (struct obj *) 0;
684     }
685 }
686 
687 /* remove an item of armor and then drop it */
688 STATIC_OVL void
m_lose_armor(mon,obj)689 m_lose_armor(mon, obj)
690 struct monst *mon;
691 struct obj *obj;
692 {
693     mon->misc_worn_check &= ~obj->owornmask;
694     if (obj->owornmask)
695         update_mon_intrinsics(mon, obj, FALSE, FALSE);
696     obj->owornmask = 0L;
697 
698     obj_extract_self(obj);
699     place_object(obj, mon->mx, mon->my);
700     /* call stackobj() if we ever drop anything that can merge */
701     newsym(mon->mx, mon->my);
702 }
703 
704 /* all objects with their bypass bit set should now be reset to normal */
705 void
clear_bypasses()706 clear_bypasses()
707 {
708     struct obj *otmp, *nobj;
709     struct monst *mtmp;
710 
711     /*
712      * 'Object' bypass is also used for one monster function:
713      * polymorph control of long worms.  Activated via setting
714      * context.bypasses even if no specific object has been
715      * bypassed.
716      */
717 
718     for (otmp = fobj; otmp; otmp = nobj) {
719         nobj = otmp->nobj;
720         if (otmp->bypass) {
721             otmp->bypass = 0;
722 
723             /* bypass will have inhibited any stacking, but since it's
724              * used for polymorph handling, the objects here probably
725              * have been transformed and won't be stacked in the usual
726              * manner afterwards; so don't bother with this.
727              * [Changing the fobj chain mid-traversal would also be risky.]
728              */
729 #if 0
730             if (objects[otmp->otyp].oc_merge) {
731                 xchar ox, oy;
732 
733                 (void) get_obj_location(otmp, &ox, &oy, 0);
734                 stack_object(otmp);
735                 newsym(ox, oy);
736             }
737 #endif /*0*/
738         }
739     }
740     for (otmp = invent; otmp; otmp = otmp->nobj)
741         otmp->bypass = 0;
742     for (otmp = migrating_objs; otmp; otmp = otmp->nobj)
743         otmp->bypass = 0;
744     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
745         if (DEADMONSTER(mtmp))
746             continue;
747         for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
748             otmp->bypass = 0;
749         /* long worm created by polymorph has mon->mextra->mcorpsenm set
750            to PM_LONG_WORM to flag it as not being subject to further
751            polymorph (so polymorph zap won't hit monster to transform it
752            into a long worm, then hit that worm's tail and transform it
753            again on same zap); clearing mcorpsenm reverts worm to normal */
754         if (mtmp->data == &mons[PM_LONG_WORM] && has_mcorpsenm(mtmp))
755             MCORPSENM(mtmp) = NON_PM;
756     }
757     for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) {
758         for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
759             otmp->bypass = 0;
760         /* no MCORPSENM(mtmp)==PM_LONG_WORM check here; long worms can't
761            be just created by polymorph and migrating at the same time */
762     }
763     /* billobjs and mydogs chains don't matter here */
764     context.bypasses = FALSE;
765 }
766 
767 void
bypass_obj(obj)768 bypass_obj(obj)
769 struct obj *obj;
770 {
771     obj->bypass = 1;
772     context.bypasses = TRUE;
773 }
774 
775 /* set or clear the bypass bit in a list of objects */
776 void
bypass_objlist(objchain,on)777 bypass_objlist(objchain, on)
778 struct obj *objchain;
779 boolean on; /* TRUE => set, FALSE => clear */
780 {
781     if (on && objchain)
782         context.bypasses = TRUE;
783     while (objchain) {
784         objchain->bypass = on ? 1 : 0;
785         objchain = objchain->nobj;
786     }
787 }
788 
789 /* return the first object without its bypass bit set; set that bit
790    before returning so that successive calls will find further objects */
791 struct obj *
nxt_unbypassed_obj(objchain)792 nxt_unbypassed_obj(objchain)
793 struct obj *objchain;
794 {
795     while (objchain) {
796         if (!objchain->bypass) {
797             bypass_obj(objchain);
798             break;
799         }
800         objchain = objchain->nobj;
801     }
802     return objchain;
803 }
804 
805 /* like nxt_unbypassed_obj() but operates on sortloot_item array rather
806    than an object linked list; the array contains obj==Null terminator;
807    there's an added complication that the array may have stale pointers
808    for deleted objects (see Multiple-Drop case in askchain(invent.c)) */
809 struct obj *
nxt_unbypassed_loot(lootarray,listhead)810 nxt_unbypassed_loot(lootarray, listhead)
811 Loot *lootarray;
812 struct obj *listhead;
813 {
814     struct obj *o, *obj;
815 
816     while ((obj = lootarray->obj) != 0) {
817         for (o = listhead; o; o = o->nobj)
818             if (o == obj)
819                 break;
820         if (o && !obj->bypass) {
821             bypass_obj(obj);
822             break;
823         }
824         ++lootarray;
825     }
826     return obj;
827 }
828 
829 void
mon_break_armor(mon,polyspot)830 mon_break_armor(mon, polyspot)
831 struct monst *mon;
832 boolean polyspot;
833 {
834     register struct obj *otmp;
835     struct permonst *mdat = mon->data;
836     boolean vis = cansee(mon->mx, mon->my);
837     boolean handless_or_tiny = (nohands(mdat) || verysmall(mdat));
838     const char *pronoun = mhim(mon), *ppronoun = mhis(mon);
839 
840     if (breakarm(mdat)) {
841         if ((otmp = which_armor(mon, W_ARM)) != 0) {
842             if ((Is_dragon_scales(otmp) && mdat == Dragon_scales_to_pm(otmp))
843                 || (Is_dragon_mail(otmp) && mdat == Dragon_mail_to_pm(otmp)))
844                 ; /* no message here;
845                      "the dragon merges with his scaly armor" is odd
846                      and the monster's previous form is already gone */
847             else if (vis)
848                 pline("%s breaks out of %s armor!", Monnam(mon), ppronoun);
849             else
850                 You_hear("a cracking sound.");
851             m_useup(mon, otmp);
852         }
853         if ((otmp = which_armor(mon, W_ARMC)) != 0) {
854             if (otmp->oartifact) {
855                 if (vis)
856                     pline("%s %s falls off!", s_suffix(Monnam(mon)),
857                           cloak_simple_name(otmp));
858                 if (polyspot)
859                     bypass_obj(otmp);
860                 m_lose_armor(mon, otmp);
861             } else {
862                 if (vis)
863                     pline("%s %s tears apart!", s_suffix(Monnam(mon)),
864                           cloak_simple_name(otmp));
865                 else
866                     You_hear("a ripping sound.");
867                 m_useup(mon, otmp);
868             }
869         }
870         if ((otmp = which_armor(mon, W_ARMU)) != 0) {
871             if (vis)
872                 pline("%s shirt rips to shreds!", s_suffix(Monnam(mon)));
873             else
874                 You_hear("a ripping sound.");
875             m_useup(mon, otmp);
876         }
877     } else if (sliparm(mdat)) {
878         if ((otmp = which_armor(mon, W_ARM)) != 0) {
879             if (vis)
880                 pline("%s armor falls around %s!", s_suffix(Monnam(mon)),
881                       pronoun);
882             else
883                 You_hear("a thud.");
884             if (polyspot)
885                 bypass_obj(otmp);
886             m_lose_armor(mon, otmp);
887         }
888         if ((otmp = which_armor(mon, W_ARMC)) != 0) {
889             if (vis) {
890                 if (is_whirly(mon->data))
891                     pline("%s %s falls, unsupported!", s_suffix(Monnam(mon)),
892                           cloak_simple_name(otmp));
893                 else
894                     pline("%s shrinks out of %s %s!", Monnam(mon), ppronoun,
895                           cloak_simple_name(otmp));
896             }
897             if (polyspot)
898                 bypass_obj(otmp);
899             m_lose_armor(mon, otmp);
900         }
901         if ((otmp = which_armor(mon, W_ARMU)) != 0) {
902             if (vis) {
903                 if (sliparm(mon->data))
904                     pline("%s seeps right through %s shirt!", Monnam(mon),
905                           ppronoun);
906                 else
907                     pline("%s becomes much too small for %s shirt!",
908                           Monnam(mon), ppronoun);
909             }
910             if (polyspot)
911                 bypass_obj(otmp);
912             m_lose_armor(mon, otmp);
913         }
914     }
915     if (handless_or_tiny) {
916         /* [caller needs to handle weapon checks] */
917         if ((otmp = which_armor(mon, W_ARMG)) != 0) {
918             if (vis)
919                 pline("%s drops %s gloves%s!", Monnam(mon), ppronoun,
920                       MON_WEP(mon) ? " and weapon" : "");
921             if (polyspot)
922                 bypass_obj(otmp);
923             m_lose_armor(mon, otmp);
924         }
925         if ((otmp = which_armor(mon, W_ARMS)) != 0) {
926             if (vis)
927                 pline("%s can no longer hold %s shield!", Monnam(mon),
928                       ppronoun);
929             else
930                 You_hear("a clank.");
931             if (polyspot)
932                 bypass_obj(otmp);
933             m_lose_armor(mon, otmp);
934         }
935     }
936     if (handless_or_tiny || has_horns(mdat)) {
937         if ((otmp = which_armor(mon, W_ARMH)) != 0
938             /* flimsy test for horns matches polyself handling */
939             && (handless_or_tiny || !is_flimsy(otmp))) {
940             if (vis)
941                 pline("%s helmet falls to the %s!", s_suffix(Monnam(mon)),
942                       surface(mon->mx, mon->my));
943             else
944                 You_hear("a clank.");
945             if (polyspot)
946                 bypass_obj(otmp);
947             m_lose_armor(mon, otmp);
948         }
949     }
950     if (handless_or_tiny || slithy(mdat) || mdat->mlet == S_CENTAUR) {
951         if ((otmp = which_armor(mon, W_ARMF)) != 0) {
952             if (vis) {
953                 if (is_whirly(mon->data))
954                     pline("%s boots fall away!", s_suffix(Monnam(mon)));
955                 else
956                     pline("%s boots %s off %s feet!", s_suffix(Monnam(mon)),
957                           verysmall(mdat) ? "slide" : "are pushed", ppronoun);
958             }
959             if (polyspot)
960                 bypass_obj(otmp);
961             m_lose_armor(mon, otmp);
962         }
963     }
964     if (!can_saddle(mon)) {
965         if ((otmp = which_armor(mon, W_SADDLE)) != 0) {
966             if (polyspot)
967                 bypass_obj(otmp);
968             m_lose_armor(mon, otmp);
969             if (vis)
970                 pline("%s saddle falls off.", s_suffix(Monnam(mon)));
971         }
972         if (mon == u.usteed)
973             goto noride;
974     } else if (mon == u.usteed && !can_ride(mon)) {
975     noride:
976         You("can no longer ride %s.", mon_nam(mon));
977         if (touch_petrifies(u.usteed->data) && !Stone_resistance && rnl(3)) {
978             char buf[BUFSZ];
979 
980             You("touch %s.", mon_nam(u.usteed));
981             Sprintf(buf, "falling off %s", an(u.usteed->data->mname));
982             instapetrify(buf);
983         }
984         dismount_steed(DISMOUNT_FELL);
985     }
986     return;
987 }
988 
989 /* bias a monster's preferences towards armor that has special benefits. */
990 STATIC_OVL int
extra_pref(mon,obj)991 extra_pref(mon, obj)
992 struct monst *mon;
993 struct obj *obj;
994 {
995     /* currently only does speed boots, but might be expanded if monsters
996      * get to use more armor abilities
997      */
998     if (obj) {
999         if (obj->otyp == SPEED_BOOTS && mon->permspeed != MFAST)
1000             return 20;
1001     }
1002     return 0;
1003 }
1004 
1005 /*
1006  * Exceptions to things based on race.
1007  * Correctly checks polymorphed player race.
1008  * Returns:
1009  *       0 No exception, normal rules apply.
1010  *       1 If the race/object combination is acceptable.
1011  *      -1 If the race/object combination is unacceptable.
1012  */
1013 int
racial_exception(mon,obj)1014 racial_exception(mon, obj)
1015 struct monst *mon;
1016 struct obj *obj;
1017 {
1018     const struct permonst *ptr = raceptr(mon);
1019 
1020     /* Acceptable Exceptions: */
1021     /* Allow hobbits to wear elven armor - LoTR */
1022     if (ptr == &mons[PM_HOBBIT] && is_elven_armor(obj))
1023         return 1;
1024     /* Unacceptable Exceptions: */
1025     /* Checks for object that certain races should never use go here */
1026     /*  return -1; */
1027 
1028     return 0;
1029 }
1030 /*worn.c*/
1031