1 /* SCCS Id: @(#)worn.c 3.4 2003/01/08 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
7 STATIC_DCL void FDECL(m_lose_armor, (struct monst *,struct obj *));
8 STATIC_DCL void FDECL(m_dowear_type, (struct monst *,long, BOOLEAN_P, BOOLEAN_P));
9 STATIC_DCL int FDECL(extra_pref, (struct monst *, struct obj *));
27 { W_SWAPWEP, &uswapwep },
28 { W_QUIVER, &uquiver },
36 /* This only allows for one blocking item per property */
37 #define w_blocks(o,m) \
38 ((o->otyp == MUMMY_WRAPPING && ((m) & W_ARMC)) ? INVIS : \
39 (o->otyp == CORNUTHAUM && ((m) & W_ARMH) && \
40 !Role_if(PM_WIZARD)) ? CLAIRVOYANT : 0)
41 /* note: monsters don't have clairvoyance, so your role
42 has no significant effect on their use of w_blocks() */
45 /* Updated to use the extrinsic and blocked fields. */
48 register struct obj *obj;
51 register const struct worn *wp;
52 register struct obj *oobj;
55 if ((mask & (W_ARM|I_SPECIAL)) == (W_ARM|I_SPECIAL)) {
56 /* restoring saved game; no properties are conferred via skin */
58 /* assert( !uarm ); */
60 for(wp = worn; wp->w_mask; wp++) if(wp->w_mask & mask) {
62 if(oobj && !(oobj->owornmask & wp->w_mask))
63 impossible("Setworn: mask = %ld.", wp->w_mask);
65 if (u.twoweap && (oobj->owornmask & (W_WEP|W_SWAPWEP)))
67 oobj->owornmask &= ~wp->w_mask;
68 if (wp->w_mask & ~(W_SWAPWEP|W_QUIVER)) {
69 /* leave as "x = x <op> y", here and below, for broken
71 p = objects[oobj->otyp].oc_oprop;
72 u.uprops[p].extrinsic =
73 u.uprops[p].extrinsic & ~wp->w_mask;
74 if ((p = w_blocks(oobj,mask)) != 0)
75 u.uprops[p].blocked &= ~wp->w_mask;
77 set_artifact_intrinsic(oobj, 0, mask);
82 obj->owornmask |= wp->w_mask;
83 /* Prevent getting/blocking intrinsics from wielding
84 * potions, through the quiver, etc.
85 * Allow weapon-tools, too.
86 * wp_mask should be same as mask at this point.
88 if (wp->w_mask & ~(W_SWAPWEP|W_QUIVER)) {
89 if (obj->oclass == WEAPON_CLASS || is_weptool(obj) ||
91 p = objects[obj->otyp].oc_oprop;
92 u.uprops[p].extrinsic =
93 u.uprops[p].extrinsic | wp->w_mask;
94 if ((p = w_blocks(obj, mask)) != 0)
95 u.uprops[p].blocked |= wp->w_mask;
98 set_artifact_intrinsic(obj, 1, mask);
106 /* called e.g. when obj is destroyed */
107 /* Updated to use the extrinsic and blocked fields. */
110 register struct obj *obj;
112 register const struct worn *wp;
116 if (obj == uwep || obj == uswapwep) u.twoweap = 0;
117 for(wp = worn; wp->w_mask; wp++)
118 if(obj == *(wp->w_obj)) {
120 p = objects[obj->otyp].oc_oprop;
121 u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask;
122 obj->owornmask &= ~wp->w_mask;
124 set_artifact_intrinsic(obj, 0, wp->w_mask);
125 if ((p = w_blocks(obj,wp->w_mask)) != 0)
126 u.uprops[p].blocked &= ~wp->w_mask;
136 if (!mon->invis_blkd) {
138 newsym(mon->mx, mon->my); /* make it disappear */
139 if (mon->wormno) see_wsegs(mon); /* and any tail too */
144 mon_adjust_speed(mon, adjust, obj)
146 int adjust; /* positive => increase speed, negative => decrease */
147 struct obj *obj; /* item to make known if effect can be seen */
150 boolean give_msg = !in_mklev, petrify = FALSE;
151 unsigned int oldspeed = mon->mspeed;
155 mon->permspeed = MFAST;
156 give_msg = FALSE; /* special case monster creation */
159 if (mon->permspeed == MSLOW) mon->permspeed = 0;
160 else mon->permspeed = MFAST;
162 case 0: /* just check for worn speed boots */
165 if (mon->permspeed == MFAST) mon->permspeed = 0;
166 else mon->permspeed = MSLOW;
169 mon->permspeed = MSLOW;
170 give_msg = FALSE; /* (not currently used) */
172 case -3: /* petrification */
173 /* take away intrinsic speed but don't reduce normal speed */
174 if (mon->permspeed == MFAST) mon->permspeed = 0;
179 for (otmp = mon->minvent; otmp; otmp = otmp->nobj)
180 if (otmp->owornmask && objects[otmp->otyp].oc_oprop == FAST)
182 if (otmp) /* speed boots */
185 mon->mspeed = mon->permspeed;
187 if (give_msg && (mon->mspeed != oldspeed || petrify) && canseemon(mon)) {
188 /* fast to slow (skipping intermediate state) or vice versa */
189 const char *howmuch = (mon->mspeed + oldspeed == MFAST + MSLOW) ?
193 /* mimic the player's petrification countdown; "slowing down"
194 even if fast movement rate retained via worn speed boots */
195 if (flags.verbose) pline("%s is slowing down.", Monnam(mon));
196 } else if (adjust > 0 || mon->mspeed == MFAST)
197 pline("%s is suddenly moving %sfaster.", Monnam(mon), howmuch);
199 pline("%s seems to be moving %sslower.", Monnam(mon), howmuch);
201 /* might discover an object if we see the speed change happen, but
202 avoid making possibly forgotten book known when casting its spell */
203 if (obj != 0 && obj->dknown &&
204 objects[obj->otyp].oc_class != SPBOOK_CLASS)
205 makeknown(obj->otyp);
209 /* armor put on or taken off; might be magical variety */
211 update_mon_intrinsics(mon, obj, on, silently)
214 boolean on, silently;
219 int which = (int) objects[obj->otyp].oc_oprop;
221 unseen = !canseemon(mon);
222 if (!which) goto maybe_blocks;
227 mon->minvis = !mon->invis_blkd;
231 boolean save_in_mklev = in_mklev;
232 if (silently) in_mklev = TRUE;
233 mon_adjust_speed(mon, 0, obj);
234 in_mklev = save_in_mklev;
237 /* properties handled elsewhere */
241 /* properties which have no effect for monsters */
246 /* properties which should have an effect but aren't implemented */
250 /* properties which maybe should have an effect but don't */
257 if (which <= 8) { /* 1 thru 8 correspond to MR_xxx mask values */
258 /* FIRE,COLD,SLEEP,DISINT,SHOCK,POISON,ACID,STONE */
259 mask = (uchar) (1 << (which - 1));
260 mon->mintrinsics |= (unsigned short) mask;
267 mon->minvis = mon->perminvis;
271 boolean save_in_mklev = in_mklev;
272 if (silently) in_mklev = TRUE;
273 mon_adjust_speed(mon, 0, obj);
274 in_mklev = save_in_mklev;
285 mask = (uchar) (1 << (which - 1));
286 /* If the monster doesn't have this resistance intrinsically,
287 check whether any other worn item confers it. Note that
288 we don't currently check for anything conferred via simply
289 carrying an object. */
290 if (!(mon->data->mresists & mask)) {
291 for (otmp = mon->minvent; otmp; otmp = otmp->nobj)
292 if (otmp->owornmask &&
293 (int) objects[otmp->otyp].oc_oprop == which)
296 mon->mintrinsics &= ~((unsigned short) mask);
305 /* obj->owornmask has been cleared by this point, so we can't use it.
306 However, since monsters don't wield armor, we don't have to guard
307 against that and can get away with a blanket worn-mask value. */
308 switch (w_blocks(obj,~0L)) {
310 mon->invis_blkd = on ? 1 : 0;
311 mon->minvis = on ? 0 : mon->perminvis;
318 if (!on && mon == u.usteed && obj->otyp == SADDLE)
319 dismount_steed(DISMOUNT_FELL);
322 /* if couldn't see it but now can, or vice versa, update display */
323 if (!silently && (unseen ^ !canseemon(mon)))
324 newsym(mon->mx, mon->my);
329 register struct monst *mon;
331 register struct obj *obj;
332 int base = mon->data->ac;
333 long mwflags = mon->misc_worn_check;
335 for (obj = mon->minvent; obj; obj = obj->nobj) {
336 if (obj->owornmask & mwflags)
337 base -= ARM_BONUS(obj);
338 /* since ARM_BONUS is positive, subtracting it increases AC */
343 /* weapons are handled separately; rings and eyewear aren't used by monsters */
345 /* Wear the best object of each type that the monster has. During creation,
346 * the monster can put everything on at once; otherwise, wearing takes time.
347 * This doesn't affect monster searching for objects--a monster may very well
348 * search for objects it would not want to wear, because we don't want to
349 * check which_armor() each round.
351 * We'll let monsters put on shirts and/or suits under worn cloaks, but
352 * not shirts under worn suits. This is somewhat arbitrary, but it's
353 * too tedious to have them remove and later replace outer garments,
354 * and preventing suits under cloaks makes it a little bit too easy for
355 * players to influence what gets worn. Putting on a shirt underneath
356 * already worn body armor is too obviously buggy...
359 m_dowear(mon, creation)
360 register struct monst *mon;
363 #define RACE_EXCEPTION TRUE
364 /* Note the restrictions here are the same as in dowear in do_wear.c
365 * except for the additional restriction on intelligence. (Players
366 * are always intelligent, even if polymorphed).
368 if (verysmall(mon->data) || nohands(mon->data) || is_animal(mon->data))
370 /* give mummies a chance to wear their wrappings
371 * and let skeletons wear their initial armor */
372 if (mindless(mon->data) && (!creation ||
373 (mon->data->mlet != S_MUMMY && mon->data != &mons[PM_SKELETON])))
376 m_dowear_type(mon, W_AMUL, creation, FALSE);
378 /* can't put on shirt if already wearing suit */
379 if (!cantweararm(mon->data) || (mon->misc_worn_check & W_ARM))
380 m_dowear_type(mon, W_ARMU, creation, FALSE);
382 /* treating small as a special case allows
383 hobbits, gnomes, and kobolds to wear cloaks */
384 if (!cantweararm(mon->data) || mon->data->msize == MZ_SMALL)
385 m_dowear_type(mon, W_ARMC, creation, FALSE);
386 m_dowear_type(mon, W_ARMH, creation, FALSE);
387 if (!MON_WEP(mon) || !bimanual(MON_WEP(mon)))
388 m_dowear_type(mon, W_ARMS, creation, FALSE);
389 m_dowear_type(mon, W_ARMG, creation, FALSE);
390 if (!slithy(mon->data) && mon->data->mlet != S_CENTAUR)
391 m_dowear_type(mon, W_ARMF, creation, FALSE);
392 if (!cantweararm(mon->data))
393 m_dowear_type(mon, W_ARM, creation, FALSE);
395 m_dowear_type(mon, W_ARM, creation, RACE_EXCEPTION);
399 m_dowear_type(mon, flag, creation, racialexception)
403 boolean racialexception;
405 struct obj *old, *best, *obj;
407 int unseen = !canseemon(mon);
410 if (mon->mfrozen) return; /* probably putting previous item on */
412 /* Get a copy of monster's name before altering its visibility */
413 Strcpy(nambuf, See_invisible ? Monnam(mon) : mon_nam(mon));
415 old = which_armor(mon, flag);
416 if (old && old->cursed) return;
417 if (old && flag == W_AMUL) return; /* no such thing as better amulets */
420 for(obj = mon->minvent; obj; obj = obj->nobj) {
423 if (obj->oclass != AMULET_CLASS ||
424 (obj->otyp != AMULET_OF_LIFE_SAVING &&
425 obj->otyp != AMULET_OF_REFLECTION))
428 goto outer_break; /* no such thing as better amulets */
431 if (!is_shirt(obj)) continue;
435 if (!is_cloak(obj)) continue;
438 if (!is_helmet(obj)) continue;
439 /* (flimsy exception matches polyself handling) */
440 if (has_horns(mon->data) && !is_flimsy(obj)) continue;
443 if (!is_shield(obj)) continue;
446 if (!is_gloves(obj)) continue;
449 if (!is_boots(obj)) continue;
452 if (!is_suit(obj)) continue;
453 if (racialexception && (racial_exception(mon, obj) < 1)) continue;
456 if (obj->owornmask) continue;
457 /* I'd like to define a VISIBLE_ARM_BONUS which doesn't assume the
458 * monster knows obj->spe, but if I did that, a monster would keep
459 * switching forever between two -2 caps since when it took off one
460 * it would forget spe and once again think the object is better
461 * than what it already has.
463 if (best && (ARM_BONUS(best) + extra_pref(mon,best) >= ARM_BONUS(obj) + extra_pref(mon,obj)))
468 if (!best || best == old) return;
470 /* if wearing a cloak, account for the time spent removing
471 and re-wearing it when putting on a suit or shirt */
476 ) && (mon->misc_worn_check & W_ARMC))
478 /* when upgrading a piece of armor, account for time spent
479 taking off current one */
481 m_delay += objects[old->otyp].oc_delay;
483 if (old) /* do this first to avoid "(being worn)" */
486 if (canseemon(mon)) {
490 Sprintf(buf, " removes %s and", distant_name(old, doname));
493 pline("%s%s puts on %s.", Monnam(mon),
494 buf, distant_name(best,doname));
496 m_delay += objects[best->otyp].oc_delay;
497 mon->mfrozen = m_delay;
498 if (mon->mfrozen) mon->mcanmove = 0;
501 update_mon_intrinsics(mon, old, FALSE, creation);
502 mon->misc_worn_check |= flag;
503 best->owornmask |= flag;
504 update_mon_intrinsics(mon, best, TRUE, creation);
505 /* if couldn't see it but now can, or vice versa, */
506 if (!creation && (unseen ^ !canseemon(mon))) {
507 if (mon->minvis && !See_invisible) {
508 pline("Suddenly you cannot see %s.", nambuf);
509 makeknown(best->otyp);
510 } /* else if (!mon->minvis) pline("%s suddenly appears!", Amonnam(mon)); */
513 #undef RACE_EXCEPTION
516 which_armor(mon, flag)
520 register struct obj *obj;
522 for(obj = mon->minvent; obj; obj = obj->nobj)
523 if (obj->owornmask & flag) return obj;
524 return((struct obj *)0);
527 /* remove an item of armor and then drop it */
529 m_lose_armor(mon, obj)
533 mon->misc_worn_check &= ~obj->owornmask;
535 update_mon_intrinsics(mon, obj, FALSE, FALSE);
538 obj_extract_self(obj);
539 place_object(obj, mon->mx, mon->my);
540 /* call stackobj() if we ever drop anything that can merge */
541 newsym(mon->mx, mon->my);
544 /* all objects with their bypass bit set should now be reset to normal */
548 struct obj *otmp, *nobj;
551 for (otmp = fobj; otmp; otmp = nobj) {
555 /* bypass will have inhibited any stacking, but since it's
556 used for polymorph handling, the objects here probably
557 have been transformed and won't be stacked in the usual
558 manner afterwards; so don't bother with this */
560 if (objects[otmp->otyp].oc_merge) {
563 (void) get_obj_location(otmp, &ox, &oy, 0);
570 /* invent and mydogs chains shouldn't matter here */
571 for (otmp = migrating_objs; otmp; otmp = otmp->nobj)
573 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
574 if (DEADMONSTER(mtmp)) continue;
575 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
578 for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) {
579 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
582 flags.bypasses = FALSE;
590 flags.bypasses = TRUE;
594 mon_break_armor(mon, polyspot)
598 register struct obj *otmp;
599 struct permonst *mdat = mon->data;
600 boolean vis = cansee(mon->mx, mon->my);
601 boolean handless_or_tiny = (nohands(mdat) || verysmall(mdat));
602 const char *pronoun = mhim(mon),
603 *ppronoun = mhis(mon);
605 if (breakarm(mdat)) {
606 if ((otmp = which_armor(mon, W_ARM)) != 0) {
607 if ((Is_dragon_scales(otmp) &&
608 mdat == Dragon_scales_to_pm(otmp)) ||
609 (Is_dragon_mail(otmp) && mdat == Dragon_mail_to_pm(otmp)))
610 ; /* no message here;
611 "the dragon merges with his scaly armor" is odd
612 and the monster's previous form is already gone */
614 pline("%s breaks out of %s armor!", Monnam(mon), ppronoun);
616 You_hear("a cracking sound.");
619 if ((otmp = which_armor(mon, W_ARMC)) != 0) {
620 if (otmp->oartifact) {
622 pline("%s %s falls off!", s_suffix(Monnam(mon)),
623 cloak_simple_name(otmp));
624 if (polyspot) bypass_obj(otmp);
625 m_lose_armor(mon, otmp);
628 pline("%s %s tears apart!", s_suffix(Monnam(mon)),
629 cloak_simple_name(otmp));
631 You_hear("a ripping sound.");
636 if ((otmp = which_armor(mon, W_ARMU)) != 0) {
638 pline("%s shirt rips to shreds!", s_suffix(Monnam(mon)));
640 You_hear("a ripping sound.");
644 } else if (sliparm(mdat)) {
645 if ((otmp = which_armor(mon, W_ARM)) != 0) {
647 pline("%s armor falls around %s!",
648 s_suffix(Monnam(mon)), pronoun);
651 if (polyspot) bypass_obj(otmp);
652 m_lose_armor(mon, otmp);
654 if ((otmp = which_armor(mon, W_ARMC)) != 0) {
656 if (is_whirly(mon->data))
657 pline("%s %s falls, unsupported!",
658 s_suffix(Monnam(mon)), cloak_simple_name(otmp));
660 pline("%s shrinks out of %s %s!", Monnam(mon),
661 ppronoun, cloak_simple_name(otmp));
663 if (polyspot) bypass_obj(otmp);
664 m_lose_armor(mon, otmp);
667 if ((otmp = which_armor(mon, W_ARMU)) != 0) {
669 if (sliparm(mon->data))
670 pline("%s seeps right through %s shirt!",
671 Monnam(mon), ppronoun);
673 pline("%s becomes much too small for %s shirt!",
674 Monnam(mon), ppronoun);
676 if (polyspot) bypass_obj(otmp);
677 m_lose_armor(mon, otmp);
681 if (handless_or_tiny) {
682 /* [caller needs to handle weapon checks] */
683 if ((otmp = which_armor(mon, W_ARMG)) != 0) {
685 pline("%s drops %s gloves%s!", Monnam(mon), ppronoun,
686 MON_WEP(mon) ? " and weapon" : "");
687 if (polyspot) bypass_obj(otmp);
688 m_lose_armor(mon, otmp);
690 if ((otmp = which_armor(mon, W_ARMS)) != 0) {
692 pline("%s can no longer hold %s shield!", Monnam(mon),
695 You_hear("a clank.");
696 if (polyspot) bypass_obj(otmp);
697 m_lose_armor(mon, otmp);
700 if (handless_or_tiny || has_horns(mdat)) {
701 if ((otmp = which_armor(mon, W_ARMH)) != 0 &&
702 /* flimsy test for horns matches polyself handling */
703 (handless_or_tiny || !is_flimsy(otmp))) {
705 pline("%s helmet falls to the %s!",
706 s_suffix(Monnam(mon)), surface(mon->mx, mon->my));
708 You_hear("a clank.");
709 if (polyspot) bypass_obj(otmp);
710 m_lose_armor(mon, otmp);
713 if (handless_or_tiny || slithy(mdat) || mdat->mlet == S_CENTAUR) {
714 if ((otmp = which_armor(mon, W_ARMF)) != 0) {
716 if (is_whirly(mon->data))
717 pline("%s boots fall away!",
718 s_suffix(Monnam(mon)));
719 else pline("%s boots %s off %s feet!",
720 s_suffix(Monnam(mon)),
721 verysmall(mdat) ? "slide" : "are pushed", ppronoun);
723 if (polyspot) bypass_obj(otmp);
724 m_lose_armor(mon, otmp);
728 if (!can_saddle(mon)) {
729 if ((otmp = which_armor(mon, W_SADDLE)) != 0) {
730 if (polyspot) bypass_obj(otmp);
731 m_lose_armor(mon, otmp);
733 pline("%s saddle falls off.", s_suffix(Monnam(mon)));
737 } else if (mon == u.usteed && !can_ride(mon)) {
739 You("can no longer ride %s.", mon_nam(mon));
740 if (touch_petrifies(u.usteed->data) &&
741 !Stone_resistance && rnl(3)) {
744 You("touch %s.", mon_nam(u.usteed));
745 Sprintf(buf, "falling off %s",
746 an(u.usteed->data->mname));
749 dismount_steed(DISMOUNT_FELL);
755 /* bias a monster's preferences towards armor that has special benefits. */
756 /* currently only does speed boots, but might be expanded if monsters get to
757 use more armor abilities */
764 if (obj->otyp == SPEED_BOOTS && mon->permspeed != MFAST)
771 * Exceptions to things based on race. Correctly checks polymorphed player race.
773 * 0 No exception, normal rules apply.
774 * 1 If the race/object combination is acceptable.
775 * -1 If the race/object combination is unacceptable.
778 racial_exception(mon, obj)
782 const struct permonst *ptr = raceptr(mon);
784 /* Acceptable Exceptions: */
785 /* Allow hobbits to wear elven armor - LoTR */
786 if (ptr == &mons[PM_HOBBIT] && is_elven_armor(obj))
788 /* Unacceptable Exceptions: */
789 /* Checks for object that certain races should never use go here */