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