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. */ 4 5#include "hack.h" 6 7STATIC_DCL void FDECL(m_lose_armor, (struct monst *,struct obj *)); 8STATIC_DCL void FDECL(m_dowear_type, (struct monst *,long, BOOLEAN_P, BOOLEAN_P)); 9STATIC_DCL int FDECL(extra_pref, (struct monst *, struct obj *)); 10 11const struct worn { 12 long w_mask; 13 struct obj **w_obj; 14} worn[] = { 15 { W_ARM, &uarm }, 16 { W_ARMC, &uarmc }, 17 { W_ARMH, &uarmh }, 18 { W_ARMS, &uarms }, 19 { W_ARMG, &uarmg }, 20 { W_ARMF, &uarmf }, 21#ifdef TOURIST 22 { W_ARMU, &uarmu }, 23#endif 24 { W_RINGL, &uleft }, 25 { W_RINGR, &uright }, 26 { W_WEP, &uwep }, 27 { W_SWAPWEP, &uswapwep }, 28 { W_QUIVER, &uquiver }, 29 { W_AMUL, &uamul }, 30 { W_TOOL, &ublindf }, 31 { W_BALL, &uball }, 32 { W_CHAIN, &uchain }, 33 { 0, 0 } 34}; 35 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() */ 43 44 45/* Updated to use the extrinsic and blocked fields. */ 46void 47setworn(obj, mask) 48register struct obj *obj; 49long mask; 50{ 51 register const struct worn *wp; 52 register struct obj *oobj; 53 register int p; 54 55 if ((mask & (W_ARM|I_SPECIAL)) == (W_ARM|I_SPECIAL)) { 56 /* restoring saved game; no properties are conferred via skin */ 57 uskin = obj; 58 /* assert( !uarm ); */ 59 } else { 60 for(wp = worn; wp->w_mask; wp++) if(wp->w_mask & mask) { 61 oobj = *(wp->w_obj); 62 if(oobj && !(oobj->owornmask & wp->w_mask)) 63 impossible("Setworn: mask = %ld.", wp->w_mask); 64 if(oobj) { 65 if (u.twoweap && (oobj->owornmask & (W_WEP|W_SWAPWEP))) 66 u.twoweap = 0; 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 70 * compilers */ 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; 76 if (oobj->oartifact) 77 set_artifact_intrinsic(oobj, 0, mask); 78 } 79 } 80 *(wp->w_obj) = obj; 81 if(obj) { 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. 87 */ 88 if (wp->w_mask & ~(W_SWAPWEP|W_QUIVER)) { 89 if (obj->oclass == WEAPON_CLASS || is_weptool(obj) || 90 mask != W_WEP) { 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; 96 } 97 if (obj->oartifact) 98 set_artifact_intrinsic(obj, 1, mask); 99 } 100 } 101 } 102 } 103 update_inventory(); 104} 105 106/* called e.g. when obj is destroyed */ 107/* Updated to use the extrinsic and blocked fields. */ 108void 109setnotworn(obj) 110register struct obj *obj; 111{ 112 register const struct worn *wp; 113 register int p; 114 115 if (!obj) return; 116 if (obj == uwep || obj == uswapwep) u.twoweap = 0; 117 for(wp = worn; wp->w_mask; wp++) 118 if(obj == *(wp->w_obj)) { 119 *(wp->w_obj) = 0; 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; 123 if (obj->oartifact) 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; 127 } 128 update_inventory(); 129} 130 131void 132mon_set_minvis(mon) 133struct monst *mon; 134{ 135 mon->perminvis = 1; 136 if (!mon->invis_blkd) { 137 mon->minvis = 1; 138 newsym(mon->mx, mon->my); /* make it disappear */ 139 if (mon->wormno) see_wsegs(mon); /* and any tail too */ 140 } 141} 142 143void 144mon_adjust_speed(mon, adjust, obj) 145struct monst *mon; 146int adjust; /* positive => increase speed, negative => decrease */ 147struct obj *obj; /* item to make known if effect can be seen */ 148{ 149 struct obj *otmp; 150 boolean give_msg = !in_mklev, petrify = FALSE; 151 unsigned int oldspeed = mon->mspeed; 152 153 switch (adjust) { 154 case 2: 155 mon->permspeed = MFAST; 156 give_msg = FALSE; /* special case monster creation */ 157 break; 158 case 1: 159 if (mon->permspeed == MSLOW) mon->permspeed = 0; 160 else mon->permspeed = MFAST; 161 break; 162 case 0: /* just check for worn speed boots */ 163 break; 164 case -1: 165 if (mon->permspeed == MFAST) mon->permspeed = 0; 166 else mon->permspeed = MSLOW; 167 break; 168 case -2: 169 mon->permspeed = MSLOW; 170 give_msg = FALSE; /* (not currently used) */ 171 break; 172 case -3: /* petrification */ 173 /* take away intrinsic speed but don't reduce normal speed */ 174 if (mon->permspeed == MFAST) mon->permspeed = 0; 175 petrify = TRUE; 176 break; 177 } 178 179 for (otmp = mon->minvent; otmp; otmp = otmp->nobj) 180 if (otmp->owornmask && objects[otmp->otyp].oc_oprop == FAST) 181 break; 182 if (otmp) /* speed boots */ 183 mon->mspeed = MFAST; 184 else 185 mon->mspeed = mon->permspeed; 186 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) ? 190 "much " : ""; 191 192 if (petrify) { 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); 198 else 199 pline("%s seems to be moving %sslower.", Monnam(mon), howmuch); 200 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); 206 } 207} 208 209/* armor put on or taken off; might be magical variety */ 210void 211update_mon_intrinsics(mon, obj, on, silently) 212struct monst *mon; 213struct obj *obj; 214boolean on, silently; 215{ 216 int unseen; 217 uchar mask; 218 struct obj *otmp; 219 int which = (int) objects[obj->otyp].oc_oprop; 220 221 unseen = !canseemon(mon); 222 if (!which) goto maybe_blocks; 223 224 if (on) { 225 switch (which) { 226 case INVIS: 227 mon->minvis = !mon->invis_blkd; 228 break; 229 case FAST: 230 { 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; 235 break; 236 } 237 /* properties handled elsewhere */ 238 case ANTIMAGIC: 239 case REFLECTING: 240 break; 241 /* properties which have no effect for monsters */ 242 case CLAIRVOYANT: 243 case STEALTH: 244 case TELEPAT: 245 break; 246 /* properties which should have an effect but aren't implemented */ 247 case LEVITATION: 248 case WWALKING: 249 break; 250 /* properties which maybe should have an effect but don't */ 251 case DISPLACED: 252 case FUMBLING: 253 case JUMPING: 254 case PROTECTION: 255 break; 256 default: 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; 261 } 262 break; 263 } 264 } else { /* off */ 265 switch (which) { 266 case INVIS: 267 mon->minvis = mon->perminvis; 268 break; 269 case FAST: 270 { 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; 275 break; 276 } 277 case FIRE_RES: 278 case COLD_RES: 279 case SLEEP_RES: 280 case DISINT_RES: 281 case SHOCK_RES: 282 case POISON_RES: 283 case ACID_RES: 284 case STONE_RES: 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) 294 break; 295 if (!otmp) 296 mon->mintrinsics &= ~((unsigned short) mask); 297 } 298 break; 299 default: 300 break; 301 } 302 } 303 304 maybe_blocks: 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)) { 309 case INVIS: 310 mon->invis_blkd = on ? 1 : 0; 311 mon->minvis = on ? 0 : mon->perminvis; 312 break; 313 default: 314 break; 315 } 316 317#ifdef STEED 318 if (!on && mon == u.usteed && obj->otyp == SADDLE) 319 dismount_steed(DISMOUNT_FELL); 320#endif 321 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); 325} 326 327int 328find_mac(mon) 329register struct monst *mon; 330{ 331 register struct obj *obj; 332 int base = mon->data->ac; 333 long mwflags = mon->misc_worn_check; 334 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 */ 339 } 340 return base; 341} 342 343/* weapons are handled separately; rings and eyewear aren't used by monsters */ 344 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. 350 * 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... 357 */ 358void 359m_dowear(mon, creation) 360register struct monst *mon; 361boolean creation; 362{ 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). 367 */ 368 if (verysmall(mon->data) || nohands(mon->data) || is_animal(mon->data)) 369 return; 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]))) 374 return; 375 376 m_dowear_type(mon, W_AMUL, creation, FALSE); 377#ifdef TOURIST 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); 381#endif 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); 394 else 395 m_dowear_type(mon, W_ARM, creation, RACE_EXCEPTION); 396} 397 398STATIC_OVL void 399m_dowear_type(mon, flag, creation, racialexception) 400struct monst *mon; 401long flag; 402boolean creation; 403boolean racialexception; 404{ 405 struct obj *old, *best, *obj; 406 int m_delay = 0; 407 int unseen = !canseemon(mon); 408 char nambuf[BUFSZ]; 409 410 if (mon->mfrozen) return; /* probably putting previous item on */ 411 412 /* Get a copy of monster's name before altering its visibility */ 413 Strcpy(nambuf, See_invisible ? Monnam(mon) : mon_nam(mon)); 414 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 */ 418 best = old; 419 420 for(obj = mon->minvent; obj; obj = obj->nobj) { 421 switch(flag) { 422 case W_AMUL: 423 if (obj->oclass != AMULET_CLASS || 424 (obj->otyp != AMULET_OF_LIFE_SAVING && 425 obj->otyp != AMULET_OF_REFLECTION)) 426 continue; 427 best = obj; 428 goto outer_break; /* no such thing as better amulets */ 429#ifdef TOURIST 430 case W_ARMU: 431 if (!is_shirt(obj)) continue; 432 break; 433#endif 434 case W_ARMC: 435 if (!is_cloak(obj)) continue; 436 break; 437 case W_ARMH: 438 if (!is_helmet(obj)) continue; 439 /* (flimsy exception matches polyself handling) */ 440 if (has_horns(mon->data) && !is_flimsy(obj)) continue; 441 break; 442 case W_ARMS: 443 if (!is_shield(obj)) continue; 444 break; 445 case W_ARMG: 446 if (!is_gloves(obj)) continue; 447 break; 448 case W_ARMF: 449 if (!is_boots(obj)) continue; 450 break; 451 case W_ARM: 452 if (!is_suit(obj)) continue; 453 if (racialexception && (racial_exception(mon, obj) < 1)) continue; 454 break; 455 } 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. 462 */ 463 if (best && (ARM_BONUS(best) + extra_pref(mon,best) >= ARM_BONUS(obj) + extra_pref(mon,obj))) 464 continue; 465 best = obj; 466 } 467outer_break: 468 if (!best || best == old) return; 469 470 /* if wearing a cloak, account for the time spent removing 471 and re-wearing it when putting on a suit or shirt */ 472 if ((flag == W_ARM 473#ifdef TOURIST 474 || flag == W_ARMU 475#endif 476 ) && (mon->misc_worn_check & W_ARMC)) 477 m_delay += 2; 478 /* when upgrading a piece of armor, account for time spent 479 taking off current one */ 480 if (old) 481 m_delay += objects[old->otyp].oc_delay; 482 483 if (old) /* do this first to avoid "(being worn)" */ 484 old->owornmask = 0L; 485 if (!creation) { 486 if (canseemon(mon)) { 487 char buf[BUFSZ]; 488 489 if (old) 490 Sprintf(buf, " removes %s and", distant_name(old, doname)); 491 else 492 buf[0] = '\0'; 493 pline("%s%s puts on %s.", Monnam(mon), 494 buf, distant_name(best,doname)); 495 } /* can see it */ 496 m_delay += objects[best->otyp].oc_delay; 497 mon->mfrozen = m_delay; 498 if (mon->mfrozen) mon->mcanmove = 0; 499 } 500 if (old) 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)); */ 511 } 512} 513#undef RACE_EXCEPTION 514 515struct obj * 516which_armor(mon, flag) 517struct monst *mon; 518long flag; 519{ 520 register struct obj *obj; 521 522 for(obj = mon->minvent; obj; obj = obj->nobj) 523 if (obj->owornmask & flag) return obj; 524 return((struct obj *)0); 525} 526 527/* remove an item of armor and then drop it */ 528STATIC_OVL void 529m_lose_armor(mon, obj) 530struct monst *mon; 531struct obj *obj; 532{ 533 mon->misc_worn_check &= ~obj->owornmask; 534 if (obj->owornmask) 535 update_mon_intrinsics(mon, obj, FALSE, FALSE); 536 obj->owornmask = 0L; 537 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); 542} 543 544/* all objects with their bypass bit set should now be reset to normal */ 545void 546clear_bypasses() 547{ 548 struct obj *otmp, *nobj; 549 struct monst *mtmp; 550 551 for (otmp = fobj; otmp; otmp = nobj) { 552 nobj = otmp->nobj; 553 if (otmp->bypass) { 554 otmp->bypass = 0; 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 */ 559#if 0 560 if (objects[otmp->otyp].oc_merge) { 561 xchar ox, oy; 562 563 (void) get_obj_location(otmp, &ox, &oy, 0); 564 stack_object(otmp); 565 newsym(ox, oy); 566 } 567#endif /*0*/ 568 } 569 } 570 /* invent and mydogs chains shouldn't matter here */ 571 for (otmp = migrating_objs; otmp; otmp = otmp->nobj) 572 otmp->bypass = 0; 573 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { 574 if (DEADMONSTER(mtmp)) continue; 575 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) 576 otmp->bypass = 0; 577 } 578 for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) { 579 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) 580 otmp->bypass = 0; 581 } 582 flags.bypasses = FALSE; 583} 584 585void 586bypass_obj(obj) 587struct obj *obj; 588{ 589 obj->bypass = 1; 590 flags.bypasses = TRUE; 591} 592 593void 594mon_break_armor(mon, polyspot) 595struct monst *mon; 596boolean polyspot; 597{ 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); 604 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 */ 613 else if (vis) 614 pline("%s breaks out of %s armor!", Monnam(mon), ppronoun); 615 else 616 You_hear("a cracking sound."); 617 m_useup(mon, otmp); 618 } 619 if ((otmp = which_armor(mon, W_ARMC)) != 0) { 620 if (otmp->oartifact) { 621 if (vis) 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); 626 } else { 627 if (vis) 628 pline("%s %s tears apart!", s_suffix(Monnam(mon)), 629 cloak_simple_name(otmp)); 630 else 631 You_hear("a ripping sound."); 632 m_useup(mon, otmp); 633 } 634 } 635#ifdef TOURIST 636 if ((otmp = which_armor(mon, W_ARMU)) != 0) { 637 if (vis) 638 pline("%s shirt rips to shreds!", s_suffix(Monnam(mon))); 639 else 640 You_hear("a ripping sound."); 641 m_useup(mon, otmp); 642 } 643#endif 644 } else if (sliparm(mdat)) { 645 if ((otmp = which_armor(mon, W_ARM)) != 0) { 646 if (vis) 647 pline("%s armor falls around %s!", 648 s_suffix(Monnam(mon)), pronoun); 649 else 650 You_hear("a thud."); 651 if (polyspot) bypass_obj(otmp); 652 m_lose_armor(mon, otmp); 653 } 654 if ((otmp = which_armor(mon, W_ARMC)) != 0) { 655 if (vis) { 656 if (is_whirly(mon->data)) 657 pline("%s %s falls, unsupported!", 658 s_suffix(Monnam(mon)), cloak_simple_name(otmp)); 659 else 660 pline("%s shrinks out of %s %s!", Monnam(mon), 661 ppronoun, cloak_simple_name(otmp)); 662 } 663 if (polyspot) bypass_obj(otmp); 664 m_lose_armor(mon, otmp); 665 } 666#ifdef TOURIST 667 if ((otmp = which_armor(mon, W_ARMU)) != 0) { 668 if (vis) { 669 if (sliparm(mon->data)) 670 pline("%s seeps right through %s shirt!", 671 Monnam(mon), ppronoun); 672 else 673 pline("%s becomes much too small for %s shirt!", 674 Monnam(mon), ppronoun); 675 } 676 if (polyspot) bypass_obj(otmp); 677 m_lose_armor(mon, otmp); 678 } 679#endif 680 } 681 if (handless_or_tiny) { 682 /* [caller needs to handle weapon checks] */ 683 if ((otmp = which_armor(mon, W_ARMG)) != 0) { 684 if (vis) 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); 689 } 690 if ((otmp = which_armor(mon, W_ARMS)) != 0) { 691 if (vis) 692 pline("%s can no longer hold %s shield!", Monnam(mon), 693 ppronoun); 694 else 695 You_hear("a clank."); 696 if (polyspot) bypass_obj(otmp); 697 m_lose_armor(mon, otmp); 698 } 699 } 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))) { 704 if (vis) 705 pline("%s helmet falls to the %s!", 706 s_suffix(Monnam(mon)), surface(mon->mx, mon->my)); 707 else 708 You_hear("a clank."); 709 if (polyspot) bypass_obj(otmp); 710 m_lose_armor(mon, otmp); 711 } 712 } 713 if (handless_or_tiny || slithy(mdat) || mdat->mlet == S_CENTAUR) { 714 if ((otmp = which_armor(mon, W_ARMF)) != 0) { 715 if (vis) { 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); 722 } 723 if (polyspot) bypass_obj(otmp); 724 m_lose_armor(mon, otmp); 725 } 726 } 727#ifdef STEED 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); 732 if (vis) 733 pline("%s saddle falls off.", s_suffix(Monnam(mon))); 734 } 735 if (mon == u.usteed) 736 goto noride; 737 } else if (mon == u.usteed && !can_ride(mon)) { 738 noride: 739 You("can no longer ride %s.", mon_nam(mon)); 740 if (touch_petrifies(u.usteed->data) && 741 !Stone_resistance && rnl(3)) { 742 char buf[BUFSZ]; 743 744 You("touch %s.", mon_nam(u.usteed)); 745 Sprintf(buf, "falling off %s", 746 an(u.usteed->data->mname)); 747 instapetrify(buf); 748 } 749 dismount_steed(DISMOUNT_FELL); 750 } 751#endif 752 return; 753} 754 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 */ 758static int 759extra_pref(mon, obj) 760struct monst *mon; 761struct obj *obj; 762{ 763 if (obj) { 764 if (obj->otyp == SPEED_BOOTS && mon->permspeed != MFAST) 765 return 20; 766 } 767 return 0; 768} 769 770/* 771 * Exceptions to things based on race. Correctly checks polymorphed player race. 772 * Returns: 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. 776 */ 777int 778racial_exception(mon, obj) 779struct monst *mon; 780struct obj *obj; 781{ 782 const struct permonst *ptr = raceptr(mon); 783 784 /* Acceptable Exceptions: */ 785 /* Allow hobbits to wear elven armor - LoTR */ 786 if (ptr == &mons[PM_HOBBIT] && is_elven_armor(obj)) 787 return 1; 788 /* Unacceptable Exceptions: */ 789 /* Checks for object that certain races should never use go here */ 790 /* return -1; */ 791 792 return 0; 793} 794/*worn.c*/ 795