1 /*	SCCS Id: @(#)worn.c	3.3	2000/02/19	*/
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 #include "hack.h"
6 
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));
9 
10 const struct worn {
11 	long w_mask;
12 	struct obj **w_obj;
13 } worn[] = {
14 	{ W_ARM, &uarm },
15 	{ W_ARMC, &uarmc },
16 	{ W_ARMH, &uarmh },
17 	{ W_ARMS, &uarms },
18 	{ W_ARMG, &uarmg },
19 	{ W_ARMF, &uarmf },
20 #ifdef TOURIST
21 	{ W_ARMU, &uarmu },
22 #endif
23 	{ W_RINGL, &uleft },
24 	{ W_RINGR, &uright },
25 	{ W_WEP, &uwep },
26 	{ W_SWAPWEP, &uswapwep },
27 	{ W_QUIVER, &uquiver },
28 	{ W_AMUL, &uamul },
29 	{ W_TOOL, &ublindf },
30 	{ W_BALL, &uball },
31 	{ W_CHAIN, &uchain },
32 	{ 0, 0 }
33 };
34 
35 /* This only allows for one blocking item per property */
36 #define w_blocks(o,m) \
37 		((o->otyp == MUMMY_WRAPPING && ((m) & W_ARMC)) ? INVIS : \
38 		 (o->otyp == CORNUTHAUM && ((m) & W_ARMH) && \
39 			!Role_if(PM_WIZARD)) ? CLAIRVOYANT : 0)
40 		/* note: monsters don't have clairvoyance, so your role
41 		   has no significant effect on their use of w_blocks() */
42 
43 
44 /* Updated to use the extrinsic and blocked fields. */
45 void
setworn(obj,mask)46 setworn(obj, mask)
47 register struct obj *obj;
48 long mask;
49 {
50 	register const struct worn *wp;
51 	register struct obj *oobj;
52 	register int p;
53 
54 	if ((mask & (W_ARM|I_SPECIAL)) == (W_ARM|I_SPECIAL)) {
55 	    /* restoring saved game; no properties are conferred via skin */
56 	    uskin = obj;
57 	 /* assert( !uarm ); */
58 	} else {
59 	    for(wp = worn; wp->w_mask; wp++) if(wp->w_mask & mask) {
60 		oobj = *(wp->w_obj);
61 		if(oobj && !(oobj->owornmask & wp->w_mask))
62 			impossible("Setworn: mask = %ld.", wp->w_mask);
63 		if(oobj) {
64 		    if (u.twoweap && (oobj->owornmask & (W_WEP|W_SWAPWEP)))
65 			u.twoweap = 0;
66 		    oobj->owornmask &= ~wp->w_mask;
67 		    if (wp->w_mask & ~(W_SWAPWEP|W_QUIVER)) {
68 			/* leave as "x = x <op> y", here and below, for broken
69 			 * compilers */
70 			p = objects[oobj->otyp].oc_oprop;
71 			u.uprops[p].extrinsic =
72 					u.uprops[p].extrinsic & ~wp->w_mask;
73 			if ((p = w_blocks(oobj,mask)) != 0)
74 			    u.uprops[p].blocked &= ~wp->w_mask;
75 			if (oobj->oartifact)
76 			    set_artifact_intrinsic(oobj, 0, mask);
77 		    }
78 		}
79 		*(wp->w_obj) = obj;
80 		if(obj) {
81 		    obj->owornmask |= wp->w_mask;
82 		    /* Prevent getting/blocking intrinsics from wielding
83 		     * potions, through the quiver, etc.
84 		     * Allow weapon-tools, too.
85 		     * wp_mask should be same as mask at this point.
86 		     */
87 		    if (wp->w_mask & ~(W_SWAPWEP|W_QUIVER)) {
88 			if (obj->oclass == WEAPON_CLASS || is_weptool(obj) ||
89 					    mask != W_WEP) {
90 			    p = objects[obj->otyp].oc_oprop;
91 			    u.uprops[p].extrinsic =
92 					u.uprops[p].extrinsic | wp->w_mask;
93 			    if ((p = w_blocks(obj, mask)) != 0)
94 				u.uprops[p].blocked |= wp->w_mask;
95 			}
96 			if (obj->oartifact)
97 			    set_artifact_intrinsic(obj, 1, mask);
98 		    }
99 		}
100 	    }
101 	}
102 	update_inventory();
103 }
104 
105 /* called e.g. when obj is destroyed */
106 /* Updated to use the extrinsic and blocked fields. */
107 void
setnotworn(obj)108 setnotworn(obj)
109 register struct obj *obj;
110 {
111 	register const struct worn *wp;
112 	register int p;
113 
114 	if (!obj) return;
115 	if (obj == uwep || obj == uswapwep) u.twoweap = 0;
116 	for(wp = worn; wp->w_mask; wp++)
117 		if(obj == *(wp->w_obj)) {
118 			*(wp->w_obj) = 0;
119 			p = objects[obj->otyp].oc_oprop;
120 			u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask;
121 			obj->owornmask &= ~wp->w_mask;
122 			if (obj->oartifact)
123 			    set_artifact_intrinsic(obj, 0, wp->w_mask);
124 			if ((p = w_blocks(obj,wp->w_mask)) != 0)
125 			    u.uprops[p].blocked &= ~wp->w_mask;
126 		}
127 	update_inventory();
128 }
129 
130 void
mon_set_minvis(mon)131 mon_set_minvis(mon)
132 struct monst *mon;
133 {
134 	mon->perminvis = 1;
135 	if (!mon->invis_blkd) {
136 	    mon->minvis = 1;
137 	    newsym(mon->mx, mon->my);		/* make it disappear */
138 	    if (mon->wormno) see_wsegs(mon);	/* and any tail too */
139 	}
140 }
141 
142 void
mon_adjust_speed(mon,adjust)143 mon_adjust_speed(mon, adjust)
144 struct monst *mon;
145 int adjust;	/* positive => increase speed, negative => decrease */
146 {
147     struct obj *otmp;
148 
149     switch (adjust) {
150      case  2:
151 	mon->permspeed = MFAST;
152 	break;
153      case  1:
154 	if (mon->permspeed == MSLOW) mon->permspeed = 0;
155 	else mon->permspeed = MFAST;
156 	break;
157      case  0:			/* just check for worn speed boots */
158 	break;
159      case -1:
160 	if (mon->permspeed == MFAST) mon->permspeed = 0;
161 	else mon->permspeed = MSLOW;
162 	break;
163      case -2:
164 	mon->permspeed = MSLOW;
165 	break;
166     }
167 
168     for (otmp = mon->minvent; otmp; otmp = otmp->nobj)
169 	if (otmp->owornmask && objects[otmp->otyp].oc_oprop == FAST)
170 	    break;
171     if (otmp)		/* speed boots */
172 	mon->mspeed = MFAST;
173     else
174 	mon->mspeed = mon->permspeed;
175 }
176 
177 /* armor put on or taken off; might be magical variety */
178 void
update_mon_intrinsics(mon,obj,on)179 update_mon_intrinsics(mon, obj, on)
180 struct monst *mon;
181 struct obj *obj;
182 boolean on;
183 {
184     int unseen;
185     uchar mask;
186     struct obj *otmp;
187     int which = (int) objects[obj->otyp].oc_oprop;
188 
189     unseen = !canseemon(mon);
190     if (!which) goto maybe_blocks;
191 
192     if (on) {
193 	switch (which) {
194 	 case INVIS:
195 	    mon->minvis = !mon->invis_blkd;
196 	    break;
197 	 case FAST:
198 	    mon_adjust_speed(mon, 0);
199 	    break;
200 	/* properties handled elsewhere */
201 	 case ANTIMAGIC:
202 	 case REFLECTING:
203 	    break;
204 	/* properties which have no effect for monsters */
205 	 case CLAIRVOYANT:
206 	 case STEALTH:
207 	 case TELEPAT:
208 	    break;
209 	/* properties which should have an effect but aren't implemented */
210 	 case LEVITATION:
211 	 case WWALKING:
212 	    break;
213 	/* properties which maybe should have an effect but don't */
214 	 case DISPLACED:
215 	 case FUMBLING:
216 	 case JUMPING:
217 	 case PROTECTION:
218 	    break;
219 	 default:
220 	    if (which <= 8) {	/* 1 thru 8 correspond to MR_xxx mask values */
221 		/* FIRE,COLD,SLEEP,DISINT,SHOCK,POISON,ACID,STONE */
222 		mask = (uchar) (1 << (which - 1));
223 		mon->mintrinsics |= (unsigned short) mask;
224 	    }
225 	    break;
226 	}
227     } else {	    /* off */
228 	switch (which) {
229 	 case INVIS:
230 	    mon->minvis = mon->perminvis;
231 	    break;
232 	 case FAST:
233 	    mon_adjust_speed(mon, 0);
234 	    break;
235 	 case FIRE_RES:
236 	 case COLD_RES:
237 	 case SLEEP_RES:
238 	 case DISINT_RES:
239 	 case SHOCK_RES:
240 	 case POISON_RES:
241 	 case ACID_RES:
242 	 case STONE_RES:
243 	    mask = (uchar) (1 << (which - 1));
244 	    /* If the monster doesn't have this resistance intrinsically,
245 	       check whether any other worn item confers it.  Note that
246 	       we don't currently check for anything conferred via simply
247 	       carrying an object. */
248 	    if (!(mon->data->mresists & mask)) {
249 		for (otmp = mon->minvent; otmp; otmp = otmp->nobj)
250 		    if (otmp->owornmask &&
251 			    (int) objects[otmp->otyp].oc_oprop == which)
252 			break;
253 		if (!otmp)
254 		    mon->mintrinsics &= ~((unsigned short) mask);
255 	    }
256 	    break;
257 	 default:
258 	    break;
259 	}
260     }
261 
262  maybe_blocks:
263     /* obj->owornmask has been cleared by this point, so we can't use it.
264        However, since monsters don't wield armor, we don't have to guard
265        against that and can get away with a blanket worn-mask value. */
266     switch (w_blocks(obj,~0L)) {
267      case INVIS:
268 	mon->invis_blkd = on ? 1 : 0;
269 	mon->minvis = on ? 0 : mon->perminvis;
270 	break;
271      default:
272 	break;
273     }
274 
275 #ifdef STEED
276 	if (!on && mon == u.usteed && obj->otyp == SADDLE)
277 	    dismount_steed(DISMOUNT_FELL);
278 #endif
279 
280     /* if couldn't see it but now can, or vice versa, update display */
281     if (unseen ^ !canseemon(mon))
282 	newsym(mon->mx, mon->my);
283 }
284 
285 int
find_mac(mon)286 find_mac(mon)
287 register struct monst *mon;
288 {
289 	register struct obj *obj;
290 	int base = mon->data->ac;
291 	long mwflags = mon->misc_worn_check;
292 
293 	for (obj = mon->minvent; obj; obj = obj->nobj) {
294 	    if (obj->owornmask & mwflags)
295 		base -= ARM_BONUS(obj);
296 		/* since ARM_BONUS is positive, subtracting it increases AC */
297 	}
298 	return base;
299 }
300 
301 /* weapons are handled separately; rings and eyewear aren't used by monsters */
302 
303 /* Wear the best object of each type that the monster has.  During creation,
304  * the monster can put everything on at once; otherwise, wearing takes time.
305  * This doesn't affect monster searching for objects--a monster may very well
306  * search for objects it would not want to wear, because we don't want to
307  * check which_armor() each round.
308  *
309  * We'll let monsters put on shirts and/or suits under worn cloaks, but
310  * not shirts under worn suits.  This is somewhat arbitrary, but it's
311  * too tedious to have them remove and later replace outer garments,
312  * and preventing suits under cloaks makes it a little bit too easy for
313  * players to influence what gets worn.  Putting on a shirt underneath
314  * already worn body armor is too obviously buggy...
315  */
316 void
m_dowear(mon,creation)317 m_dowear(mon, creation)
318 register struct monst *mon;
319 boolean creation;
320 {
321 	/* Note the restrictions here are the same as in dowear in do_wear.c
322 	 * except for the additional restriction on intelligence.  (Players
323 	 * are always intelligent, even if polymorphed).
324 	 */
325 	if (verysmall(mon->data) || nohands(mon->data) || is_animal(mon->data))
326 		return;
327 	/* give mummies a chance to wear their wrappings */
328 	if (mindless(mon->data) && (mon->data->mlet != S_MUMMY || !creation))
329 		return;
330 
331 	m_dowear_type(mon, W_AMUL, creation);
332 #ifdef TOURIST
333 	/* can't put on shirt if already wearing suit */
334 	if (!cantweararm(mon->data) || (mon->misc_worn_check & W_ARM))
335 	    m_dowear_type(mon, W_ARMU, creation);
336 #endif
337 	/* treating small as a special case allows
338 	   hobbits, gnomes, and kobolds to wear cloaks */
339 	if (!cantweararm(mon->data) || mon->data->msize == MZ_SMALL)
340 	    m_dowear_type(mon, W_ARMC, creation);
341 	m_dowear_type(mon, W_ARMH, creation);
342 	if (!MON_WEP(mon) || !bimanual(MON_WEP(mon)))
343 	    m_dowear_type(mon, W_ARMS, creation);
344 	m_dowear_type(mon, W_ARMG, creation);
345 	if (!slithy(mon->data) && mon->data->mlet != S_CENTAUR)
346 	    m_dowear_type(mon, W_ARMF, creation);
347 	if (!cantweararm(mon->data))
348 	    m_dowear_type(mon, W_ARM, creation);
349 }
350 
351 STATIC_OVL void
m_dowear_type(mon,flag,creation)352 m_dowear_type(mon, flag, creation)
353 struct monst *mon;
354 long flag;
355 boolean creation;
356 {
357 	struct obj *old, *best, *obj;
358 	int m_delay = 0;
359 
360 	if (mon->mfrozen) return; /* probably putting previous item on */
361 
362 	old = which_armor(mon, flag);
363 	if (old && old->cursed) return;
364 	if (old && flag == W_AMUL) return; /* no such thing as better amulets */
365 	best = old;
366 
367 	for(obj = mon->minvent; obj; obj = obj->nobj) {
368 	    switch(flag) {
369 		case W_AMUL:
370 		    if (obj->oclass != AMULET_CLASS ||
371 			    (obj->otyp != AMULET_OF_LIFE_SAVING &&
372 				obj->otyp != AMULET_OF_REFLECTION))
373 			continue;
374 		    best = obj;
375 		    goto outer_break; /* no such thing as better amulets */
376 #ifdef TOURIST
377 		case W_ARMU:
378 		    if (!is_shirt(obj)) continue;
379 		    break;
380 #endif
381 		case W_ARMC:
382 		    if (!is_cloak(obj)) continue;
383 		    break;
384 		case W_ARMH:
385 		    if (!is_helmet(obj)) continue;
386 		    break;
387 		case W_ARMS:
388 		    if (!is_shield(obj)) continue;
389 		    break;
390 		case W_ARMG:
391 		    if (!is_gloves(obj)) continue;
392 		    break;
393 		case W_ARMF:
394 		    if (!is_boots(obj)) continue;
395 		    break;
396 		case W_ARM:
397 		    if (!is_suit(obj)) continue;
398 		    break;
399 	    }
400 	    if (obj->owornmask) continue;
401 	    /* I'd like to define a VISIBLE_ARM_BONUS which doesn't assume the
402 	     * monster knows obj->spe, but if I did that, a monster would keep
403 	     * switching forever between two -2 caps since when it took off one
404 	     * it would forget spe and once again think the object is better
405 	     * than what it already has.
406 	     */
407 	    if (best && (ARM_BONUS(best) >= ARM_BONUS(obj))) continue;
408 	    best = obj;
409 	}
410 outer_break:
411 	if (!best || best == old) return;
412 
413 	/* if wearing a cloak, account for the time spent removing
414 	   and re-wearing it when putting on a suit or shirt */
415 	if ((flag == W_ARM
416 #ifdef TOURIST
417 	  || flag == W_ARMU
418 #endif
419 			  ) && (mon->misc_worn_check & W_ARMC))
420 	    m_delay += 2;
421 	/* when upgrading a piece of armor, account for time spent
422 	   taking off current one */
423 	if (old)
424 	    m_delay += objects[old->otyp].oc_delay;
425 
426 	if (old) /* do this first to avoid "(being worn)" */
427 	    old->owornmask = 0L;
428 	if (!creation) {
429 	    if (canseemon(mon)) {
430 		char buf[BUFSZ];
431 
432 		if (old)
433 		    Sprintf(buf, " removes %s and", distant_name(old, doname));
434 		else
435 		    buf[0] = '\0';
436 		pline("%s%s puts on %s.", Monnam(mon),
437 		      buf, distant_name(best,doname));
438 	    } /* can see it */
439 	    m_delay += objects[best->otyp].oc_delay;
440 	    mon->mfrozen = m_delay;
441 	    if (mon->mfrozen) mon->mcanmove = 0;
442 	}
443 	if (old)
444 	    update_mon_intrinsics(mon, old, FALSE);
445 	mon->misc_worn_check |= flag;
446 	best->owornmask |= flag;
447 	update_mon_intrinsics(mon, best, TRUE);
448 }
449 
450 struct obj *
which_armor(mon,flag)451 which_armor(mon, flag)
452 struct monst *mon;
453 long flag;
454 {
455 	register struct obj *obj;
456 
457 	for(obj = mon->minvent; obj; obj = obj->nobj)
458 		if (obj->owornmask & flag) return obj;
459 	return((struct obj *)0);
460 }
461 
462 /* remove an item of armor and then drop it */
463 STATIC_OVL void
m_lose_armor(mon,obj)464 m_lose_armor(mon, obj)
465 struct monst *mon;
466 struct obj *obj;
467 {
468 	mon->misc_worn_check &= ~obj->owornmask;
469 	obj->owornmask = 0L;
470 	update_mon_intrinsics(mon, obj, FALSE);
471 
472 	obj_extract_self(obj);
473 	place_object(obj, mon->mx, mon->my);
474 	/* call stackobj() if we ever drop anything that can merge */
475 	newsym(mon->mx, mon->my);
476 }
477 
478 void
mon_break_armor(mon)479 mon_break_armor(mon)
480 struct monst *mon;
481 {
482 	register struct obj *otmp;
483 	struct permonst *mdat = mon->data;
484 	boolean vis = cansee(mon->mx, mon->my);
485 	const char *pronoun = him[pronoun_gender(mon)],
486 			*ppronoun = his[pronoun_gender(mon)];
487 
488 	if (breakarm(mdat)) {
489 	    if ((otmp = which_armor(mon, W_ARM)) != 0) {
490 		if (vis)
491 		    pline("%s breaks out of %s armor!", Monnam(mon), ppronoun);
492 		else
493 		    You_hear("a cracking sound.");
494 		m_useup(mon, otmp);
495 	    }
496 	    if ((otmp = which_armor(mon, W_ARMC)) != 0) {
497 		if (otmp->oartifact) {
498 		    if (vis)
499 			pline("%s cloak falls off!", s_suffix(Monnam(mon)));
500 		    m_lose_armor(mon, otmp);
501 		} else {
502 		    if (vis)
503 			pline("%s cloak tears apart!", s_suffix(Monnam(mon)));
504 		    else
505 			You_hear("a ripping sound.");
506 		    m_useup(mon, otmp);
507 		}
508 	    }
509 #ifdef TOURIST
510 	    if ((otmp = which_armor(mon, W_ARMU)) != 0) {
511 		if (vis)
512 		    pline("%s shirt rips to shreds!", s_suffix(Monnam(mon)));
513 		else
514 		    You_hear("a ripping sound.");
515 		m_useup(mon, otmp);
516 	    }
517 #endif
518 	} else if (sliparm(mdat)) {
519 	    if ((otmp = which_armor(mon, W_ARM)) != 0) {
520 		if (vis)
521 		    pline("%s armor falls around %s!",
522 				 s_suffix(Monnam(mon)), pronoun);
523 		else
524 		    You_hear("a thud.");
525 		m_lose_armor(mon, otmp);
526 	    }
527 	    if ((otmp = which_armor(mon, W_ARMC)) != 0) {
528 		if (vis) {
529 		    if (is_whirly(mon->data))
530 			pline("%s cloak falls, unsupported!",
531 				     s_suffix(Monnam(mon)));
532 		    else
533 			pline("%s shrinks out of %s cloak!", Monnam(mon),
534 								ppronoun);
535 		}
536 		m_lose_armor(mon, otmp);
537 	    }
538 #ifdef TOURIST
539 	    if ((otmp = which_armor(mon, W_ARMU)) != 0) {
540 		if (vis) {
541 		    if (sliparm(mon->data))
542 			pline("%s seeps right through %s shirt!",
543 					Monnam(mon), ppronoun);
544 		    else
545 			pline("%s becomes much too small for %s shirt!",
546 					Monnam(mon), ppronoun);
547 		}
548 		m_lose_armor(mon, otmp);
549 	    }
550 #endif
551 	}
552 	if (nohands(mdat) || verysmall(mdat)) {
553 	    if ((otmp = which_armor(mon, W_ARMG)) != 0) {
554 		if (vis)
555 		    pline("%s drops %s gloves%s!", Monnam(mon), ppronoun,
556 					MON_WEP(mon) ? " and weapon" : "");
557 		possibly_unwield(mon);
558 		m_lose_armor(mon, otmp);
559 	    }
560 	    if ((otmp = which_armor(mon, W_ARMS)) != 0) {
561 		if (vis)
562 		    pline("%s can no longer hold %s shield!", Monnam(mon),
563 								ppronoun);
564 		else
565 		    You_hear("a clank.");
566 		m_lose_armor(mon, otmp);
567 	    }
568 	    if ((otmp = which_armor(mon, W_ARMH)) != 0) {
569 		if (vis)
570 		    pline("%s helmet falls to the %s!",
571 			  s_suffix(Monnam(mon)), surface(mon->mx, mon->my));
572 		else
573 		    You_hear("a clank.");
574 		m_lose_armor(mon, otmp);
575 	    }
576 	}
577 	if (nohands(mdat) || verysmall(mdat) || slithy(mdat) ||
578 	    mdat->mlet == S_CENTAUR) {
579 	    if ((otmp = which_armor(mon, W_ARMF)) != 0) {
580 		if (vis) {
581 		    if (is_whirly(mon->data))
582 			pline("%s boots fall away!",
583 				       s_suffix(Monnam(mon)));
584 		    else pline("%s boots %s off %s feet!",
585 			s_suffix(Monnam(mon)),
586 			verysmall(mdat) ? "slide" : "are pushed", ppronoun);
587 		}
588 		m_lose_armor(mon, otmp);
589 	    }
590 	}
591 #ifdef STEED
592 	if (!can_saddle(mon)) {
593 	    if ((otmp = which_armor(mon, W_SADDLE)) != 0) {
594 		m_lose_armor(mon, otmp);
595 		if (vis)
596 		    pline("%s saddle falls off.", s_suffix(Monnam(mon)));
597 	    }
598 	    if (mon == u.usteed)
599 		goto noride;
600 	} else if (mon == u.usteed && !can_ride(mon)) {
601 	noride:
602 	    You("can no longer ride %s.", mon_nam(mon));
603 	    if (touch_petrifies(u.usteed->data) &&
604 			!Stone_resistance && rnl(3)) {
605 		char buf[BUFSZ];
606 
607 		You("touch %s.", mon_nam(u.usteed));
608 		Sprintf(buf, "falling off %s",
609 				an(u.usteed->data->mname));
610 		instapetrify(buf);
611 	    }
612 	    dismount_steed(DISMOUNT_FELL);
613 	}
614 #endif
615 	return;
616 }
617 
618 /*worn.c*/
619