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