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