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