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