1 /* SCCS Id: @(#)mhitm.c 3.4 2003/01/02 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 #include "hack.h"
6 #include "artifact.h"
7 #include "edog.h"
8
9 extern boolean notonhead;
10
11 #ifdef OVLB
12
13 static NEARDATA boolean vis, far_noise;
14 static NEARDATA long noisetime;
15 static NEARDATA struct obj *otmp;
16
17 static const char brief_feeling[] =
18 "have a %s feeling for a moment, then it passes.";
19
20 STATIC_DCL char *FDECL(mon_nam_too, (char *,struct monst *,struct monst *));
21 STATIC_DCL void FDECL(mrustm, (struct monst *, struct monst *, struct obj *));
22 STATIC_DCL int FDECL(hitmm, (struct monst *,struct monst *,struct attack *));
23 STATIC_DCL int FDECL(gazemm, (struct monst *,struct monst *,struct attack *));
24 STATIC_DCL int FDECL(gulpmm, (struct monst *,struct monst *,struct attack *));
25 STATIC_DCL int FDECL(explmm, (struct monst *,struct monst *,struct attack *));
26 STATIC_DCL int FDECL(mdamagem, (struct monst *,struct monst *,struct attack *));
27 #ifdef WEBB_DISINT
28 STATIC_DCL int FDECL(defdisintagr, (struct monst *,struct monst *,struct attack *));
29 #endif
30 STATIC_DCL void FDECL(mswingsm, (struct monst *, struct monst *, struct obj *));
31 STATIC_DCL void FDECL(noises,(struct monst *,struct attack *));
32 STATIC_DCL void FDECL(missmm,(struct monst *,struct monst *,struct attack *));
33 STATIC_DCL int FDECL(passivemm, (struct monst *, struct monst *, BOOLEAN_P, int));
34
35 /* Needed for the special case of monsters wielding vorpal blades (rare).
36 * If we use this a lot it should probably be a parameter to mdamagem()
37 * instead of a global variable.
38 */
39 static int dieroll;
40
41 /* returns mon_nam(mon) relative to other_mon; normal name unless they're
42 the same, in which case the reference is to {him|her|it} self */
43 STATIC_OVL char *
mon_nam_too(outbuf,mon,other_mon)44 mon_nam_too(outbuf, mon, other_mon)
45 char *outbuf;
46 struct monst *mon, *other_mon;
47 {
48 Strcpy(outbuf, mon_nam(mon));
49 if (mon == other_mon)
50 switch (pronoun_gender(mon)) {
51 case 0: Strcpy(outbuf, "himself"); break;
52 case 1: Strcpy(outbuf, "herself"); break;
53 default: Strcpy(outbuf, "itself"); break;
54 }
55 return outbuf;
56 }
57
58 STATIC_OVL void
noises(magr,mattk)59 noises(magr, mattk)
60 register struct monst *magr;
61 register struct attack *mattk;
62 {
63 boolean farq = (distu(magr->mx, magr->my) > 15);
64
65 if(flags.soundok && (farq != far_noise || moves-noisetime > 10)) {
66 far_noise = farq;
67 noisetime = moves;
68 You_hear("%s%s.",
69 (mattk->aatyp == AT_EXPL) ? "an explosion" : "some noises",
70 farq ? " in the distance" : "");
71 }
72 }
73
74 STATIC_OVL
75 void
missmm(magr,mdef,mattk)76 missmm(magr, mdef, mattk)
77 register struct monst *magr, *mdef;
78 struct attack *mattk;
79 {
80 const char *fmt;
81 char buf[BUFSZ], mdef_name[BUFSZ];
82
83 if (vis) {
84 if (!canspotmon(magr))
85 map_invisible(magr->mx, magr->my);
86 if (!canspotmon(mdef))
87 map_invisible(mdef->mx, mdef->my);
88 if (mdef->m_ap_type) seemimic(mdef);
89 if (magr->m_ap_type) seemimic(magr);
90 fmt = (could_seduce(magr,mdef,mattk) && !magr->mcan) ?
91 "%s pretends to be friendly to" : "%s misses";
92 Sprintf(buf, fmt, Monnam(magr));
93 pline("%s %s.", buf, mon_nam_too(mdef_name, mdef, magr));
94 } else noises(magr, mattk);
95 }
96
97 /*
98 * fightm() -- fight some other monster
99 *
100 * Returns:
101 * 0 - Monster did nothing.
102 * 1 - If the monster made an attack. The monster might have died.
103 *
104 * There is an exception to the above. If mtmp has the hero swallowed,
105 * then we report that the monster did nothing so it will continue to
106 * digest the hero.
107 */
108 int
fightm(mtmp)109 fightm(mtmp) /* have monsters fight each other */
110 register struct monst *mtmp;
111 {
112 register struct monst *mon, *nmon;
113 int result, has_u_swallowed;
114 #ifdef LINT
115 nmon = 0;
116 #endif
117 /* perhaps the monster will resist Conflict */
118 if(resist(mtmp, RING_CLASS, 0, 0))
119 return(0);
120
121 if(u.ustuck == mtmp) {
122 /* perhaps we're holding it... */
123 if(itsstuck(mtmp))
124 return(0);
125 }
126 has_u_swallowed = (u.uswallow && (mtmp == u.ustuck));
127
128 for(mon = fmon; mon; mon = nmon) {
129 nmon = mon->nmon;
130 if(nmon == mtmp) nmon = mtmp->nmon;
131 /* Be careful to ignore monsters that are already dead, since we
132 * might be calling this before we've cleaned them up. This can
133 * happen if the monster attacked a cockatrice bare-handedly, for
134 * instance.
135 */
136 if(mon != mtmp && !DEADMONSTER(mon)) {
137 if(monnear(mtmp,mon->mx,mon->my)) {
138 if(!u.uswallow && (mtmp == u.ustuck)) {
139 if(!rn2(4)) {
140 pline("%s releases you!", Monnam(mtmp));
141 u.ustuck = 0;
142 } else
143 break;
144 }
145
146 /* mtmp can be killed */
147 bhitpos.x = mon->mx;
148 bhitpos.y = mon->my;
149 notonhead = 0;
150 result = mattackm(mtmp,mon);
151
152 if (result & MM_AGR_DIED) return 1; /* mtmp died */
153 /*
154 * If mtmp has the hero swallowed, lie and say there
155 * was no attack (this allows mtmp to digest the hero).
156 */
157 if (has_u_swallowed) return 0;
158
159 /* Allow attacked monsters a chance to hit back. Primarily
160 * to allow monsters that resist conflict to respond.
161 */
162 if ((result & MM_HIT) && !(result & MM_DEF_DIED) &&
163 rn2(4) && mon->movement >= NORMAL_SPEED) {
164 mon->movement -= NORMAL_SPEED;
165 notonhead = 0;
166 (void) mattackm(mon, mtmp); /* return attack */
167 }
168
169 return ((result & MM_HIT) ? 1 : 0);
170 }
171 }
172 }
173 return 0;
174 }
175
176 /*
177 * mattackm() -- a monster attacks another monster.
178 *
179 * This function returns a result bitfield:
180 *
181 * --------- aggressor died
182 * / ------- defender died
183 * / / ----- defender was hit
184 * / / /
185 * x x x
186 *
187 * 0x4 MM_AGR_DIED
188 * 0x2 MM_DEF_DIED
189 * 0x1 MM_HIT
190 * 0x0 MM_MISS
191 *
192 * Each successive attack has a lower probability of hitting. Some rely on the
193 * success of previous attacks. ** this doen't seem to be implemented -dl **
194 *
195 * In the case of exploding monsters, the monster dies as well.
196 */
197 int
mattackm(magr,mdef)198 mattackm(magr, mdef)
199 register struct monst *magr,*mdef;
200 {
201 int i, /* loop counter */
202 tmp, /* amour class difference */
203 strike, /* hit this attack */
204 attk, /* attack attempted this time */
205 struck = 0, /* hit at least once */
206 res[NATTK]; /* results of all attacks */
207 struct attack *mattk, alt_attk;
208 struct permonst *pa, *pd;
209
210 if (!magr || !mdef) return(MM_MISS); /* mike@genat */
211 if (!magr->mcanmove || magr->msleeping) return(MM_MISS);
212 pa = magr->data; pd = mdef->data;
213
214 /* Grid bugs cannot attack at an angle. */
215 if (pa == &mons[PM_GRID_BUG] && magr->mx != mdef->mx
216 && magr->my != mdef->my)
217 return(MM_MISS);
218
219 /* Calculate the armour class differential. */
220 tmp = find_mac(mdef) + magr->m_lev;
221 if (mdef->mconf || !mdef->mcanmove || mdef->msleeping) {
222 tmp += 4;
223 mdef->msleeping = 0;
224 }
225
226 /* undetect monsters become un-hidden if they are attacked */
227 if (mdef->mundetected) {
228 mdef->mundetected = 0;
229 newsym(mdef->mx, mdef->my);
230 if(canseemon(mdef) && !sensemon(mdef)) {
231 if (u.usleep) You("dream of %s.",
232 (mdef->data->geno & G_UNIQ) ?
233 a_monnam(mdef) : makeplural(m_monnam(mdef)));
234 else pline("Suddenly, you notice %s.", a_monnam(mdef));
235 }
236 }
237
238 /* Elves hate orcs. */
239 if (is_elf(pa) && is_orc(pd)) tmp++;
240
241
242 /* Set up the visibility of action */
243 vis = (cansee(magr->mx,magr->my) && cansee(mdef->mx,mdef->my) && (canspotmon(magr) || canspotmon(mdef)));
244
245 /* Set flag indicating monster has moved this turn. Necessary since a
246 * monster might get an attack out of sequence (i.e. before its move) in
247 * some cases, in which case this still counts as its move for the round
248 * and it shouldn't move again.
249 */
250 magr->mlstmv = monstermoves;
251
252 /* Now perform all attacks for the monster. */
253 for (i = 0; i < NATTK; i++) {
254 res[i] = MM_MISS;
255 mattk = getmattk(pa, i, res, &alt_attk);
256 otmp = (struct obj *)0;
257 attk = 1;
258 switch (mattk->aatyp) {
259 case AT_WEAP: /* "hand to hand" attacks */
260 if (magr->weapon_check == NEED_WEAPON || !MON_WEP(magr)) {
261 magr->weapon_check = NEED_HTH_WEAPON;
262 if (mon_wield_item(magr) != 0) return 0;
263 }
264 possibly_unwield(magr, FALSE);
265 otmp = MON_WEP(magr);
266
267 if (otmp) {
268 if (vis) mswingsm(magr, mdef, otmp);
269 tmp += hitval(otmp, mdef);
270 }
271 /* fall through */
272 case AT_CLAW:
273 case AT_KICK:
274 case AT_BITE:
275 case AT_STNG:
276 case AT_TUCH:
277 case AT_BUTT:
278 case AT_TENT:
279 /* Nymph that teleported away on first attack? */
280 if (distmin(magr->mx,magr->my,mdef->mx,mdef->my) > 1)
281 return MM_MISS;
282 /* Monsters won't attack cockatrices physically if they
283 * have a weapon instead. This instinct doesn't work for
284 * players, or under conflict or confusion.
285 */
286 if (!magr->mconf && !Conflict && otmp && (
287 #ifdef WEBB_DISINT
288 (touch_disintegrates(mdef->data) &&
289 (mattk->aatyp == AT_WEAP || !(resists_disint(magr))) ) ||
290 #endif
291 (mattk->aatyp != AT_WEAP && touch_petrifies(mdef->data)))) {
292 strike = 0;
293 break;
294 }
295 dieroll = rnd(20 + i);
296 strike = (tmp > dieroll);
297 /* KMH -- don't accumulate to-hit bonuses */
298 if (otmp)
299 tmp -= hitval(otmp, mdef);
300 if (strike) {
301 res[i] = hitmm(magr, mdef, mattk);
302 if((mdef->data == &mons[PM_BLACK_PUDDING] || mdef->data == &mons[PM_BROWN_PUDDING])
303 && otmp && objects[otmp->otyp].oc_material == IRON
304 && mdef->mhp > 1 && !mdef->mcan)
305 {
306 if (clone_mon(mdef, 0, 0)) {
307 if (vis) {
308 char buf[BUFSZ];
309
310 Strcpy(buf, Monnam(mdef));
311 pline("%s divides as %s hits it!", buf, mon_nam(magr));
312 }
313 }
314 }
315 } else
316 missmm(magr, mdef, mattk);
317 break;
318
319 case AT_HUGS: /* automatic if prev two attacks succeed */
320 strike = (i >= 2 && res[i-1] == MM_HIT && res[i-2] == MM_HIT);
321 if (strike)
322 res[i] = hitmm(magr, mdef, mattk);
323
324 break;
325
326 case AT_GAZE:
327 strike = 0; /* will not wake up a sleeper */
328 res[i] = gazemm(magr, mdef, mattk);
329 break;
330
331 case AT_EXPL:
332 res[i] = explmm(magr, mdef, mattk);
333 if (res[i] == MM_MISS) { /* cancelled--no attack */
334 strike = 0;
335 attk = 0;
336 } else
337 strike = 1; /* automatic hit */
338 break;
339
340 case AT_ENGL:
341 #ifdef STEED
342 if (u.usteed && (mdef == u.usteed)) {
343 strike = 0;
344 break;
345 }
346 #endif
347 /* Engulfing attacks are directed at the hero if
348 * possible. -dlc
349 */
350 if (u.uswallow && magr == u.ustuck)
351 strike = 0;
352 else {
353 if ((strike = (tmp > rnd(20+i))))
354 res[i] = gulpmm(magr, mdef, mattk);
355 else
356 missmm(magr, mdef, mattk);
357 }
358 break;
359
360 default: /* no attack */
361 strike = 0;
362 attk = 0;
363 break;
364 }
365
366 if (attk && !(res[i] & MM_AGR_DIED))
367 res[i] = passivemm(magr, mdef, strike, res[i] & MM_DEF_DIED);
368
369 if (res[i] & MM_DEF_DIED) return res[i];
370
371 /*
372 * Wake up the defender. NOTE: this must follow the check
373 * to see if the defender died. We don't want to modify
374 * unallocated monsters!
375 */
376 if (strike) mdef->msleeping = 0;
377
378 if (res[i] & MM_AGR_DIED) return res[i];
379 /* return if aggressor can no longer attack */
380 if (!magr->mcanmove || magr->msleeping) return res[i];
381 if (res[i] & MM_HIT) struck = 1; /* at least one hit */
382 }
383
384 return(struck ? MM_HIT : MM_MISS);
385 }
386
387 /* Returns the result of mdamagem(). */
388 STATIC_OVL int
hitmm(magr,mdef,mattk)389 hitmm(magr, mdef, mattk)
390 register struct monst *magr,*mdef;
391 struct attack *mattk;
392 {
393 if(vis){
394 int compat;
395 char buf[BUFSZ], mdef_name[BUFSZ];
396
397 if (!canspotmon(magr))
398 map_invisible(magr->mx, magr->my);
399 if (!canspotmon(mdef))
400 map_invisible(mdef->mx, mdef->my);
401 if(mdef->m_ap_type) seemimic(mdef);
402 if(magr->m_ap_type) seemimic(magr);
403 if((compat = could_seduce(magr,mdef,mattk)) && !magr->mcan) {
404 Sprintf(buf, "%s %s", Monnam(magr),
405 mdef->mcansee ? "smiles at" : "talks to");
406 pline("%s %s %s.", buf, mon_nam(mdef),
407 compat == 2 ?
408 "engagingly" : "seductively");
409 } else {
410 char magr_name[BUFSZ];
411
412 Strcpy(magr_name, Monnam(magr));
413 switch (mattk->aatyp) {
414 case AT_BITE:
415 Sprintf(buf,"%s bites", magr_name);
416 break;
417 case AT_STNG:
418 Sprintf(buf,"%s stings", magr_name);
419 break;
420 case AT_BUTT:
421 Sprintf(buf,"%s butts", magr_name);
422 break;
423 case AT_TUCH:
424 Sprintf(buf,"%s touches", magr_name);
425 break;
426 case AT_TENT:
427 Sprintf(buf, "%s tentacles suck",
428 s_suffix(magr_name));
429 break;
430 case AT_HUGS:
431 if (magr != u.ustuck) {
432 Sprintf(buf,"%s squeezes", magr_name);
433 break;
434 }
435 default:
436 Sprintf(buf,"%s hits", magr_name);
437 }
438 pline("%s %s.", buf, mon_nam_too(mdef_name, mdef, magr));
439 }
440 } else noises(magr, mattk);
441 return(mdamagem(magr, mdef, mattk));
442 }
443
444 /* Returns the same values as mdamagem(). */
445 STATIC_OVL int
gazemm(magr,mdef,mattk)446 gazemm(magr, mdef, mattk)
447 register struct monst *magr, *mdef;
448 struct attack *mattk;
449 {
450 char buf[BUFSZ];
451
452 if(vis) {
453 Sprintf(buf,"%s gazes at", Monnam(magr));
454 pline("%s %s...", buf, mon_nam(mdef));
455 }
456
457 if (magr->mcan || !magr->mcansee ||
458 (magr->minvis && !perceives(mdef->data)) ||
459 !mdef->mcansee || mdef->msleeping) {
460 if(vis) pline("but nothing happens.");
461 return(MM_MISS);
462 }
463 /* call mon_reflects 2x, first test, then, if visible, print message */
464 if (magr->data == &mons[PM_MEDUSA] && mon_reflects(mdef, (char *)0)) {
465 if (canseemon(mdef))
466 (void) mon_reflects(mdef,
467 "The gaze is reflected away by %s %s.");
468 if (mdef->mcansee) {
469 if (mon_reflects(magr, (char *)0)) {
470 if (canseemon(magr))
471 (void) mon_reflects(magr,
472 "The gaze is reflected away by %s %s.");
473 return (MM_MISS);
474 }
475 if (mdef->minvis && !perceives(magr->data)) {
476 if (canseemon(magr)) {
477 pline("%s doesn't seem to notice that %s gaze was reflected.",
478 Monnam(magr), mhis(magr));
479 }
480 return (MM_MISS);
481 }
482 if (canseemon(magr))
483 pline("%s is turned to stone!", Monnam(magr));
484 monstone(magr);
485 if (magr->mhp > 0) return (MM_MISS);
486 return (MM_AGR_DIED);
487 }
488 }
489
490 return(mdamagem(magr, mdef, mattk));
491 }
492
493 /* Returns the same values as mattackm(). */
494 STATIC_OVL int
gulpmm(magr,mdef,mattk)495 gulpmm(magr, mdef, mattk)
496 register struct monst *magr, *mdef;
497 register struct attack *mattk;
498 {
499 xchar ax, ay, dx, dy;
500 int status;
501 char buf[BUFSZ];
502 struct obj *obj;
503
504 if (mdef->data->msize >= MZ_HUGE) return MM_MISS;
505
506 if (vis) {
507 Sprintf(buf,"%s swallows", Monnam(magr));
508 pline("%s %s.", buf, mon_nam(mdef));
509 }
510 for (obj = mdef->minvent; obj; obj = obj->nobj)
511 (void) snuff_lit(obj);
512
513 /*
514 * All of this maniuplation is needed to keep the display correct.
515 * There is a flush at the next pline().
516 */
517 ax = magr->mx;
518 ay = magr->my;
519 dx = mdef->mx;
520 dy = mdef->my;
521 /*
522 * Leave the defender in the monster chain at it's current position,
523 * but don't leave it on the screen. Move the agressor to the def-
524 * ender's position.
525 */
526 remove_monster(ax, ay);
527 place_monster(magr, dx, dy);
528 newsym(ax,ay); /* erase old position */
529 newsym(dx,dy); /* update new position */
530
531 status = mdamagem(magr, mdef, mattk);
532
533 if ((status & MM_AGR_DIED) && (status & MM_DEF_DIED)) {
534 ; /* both died -- do nothing */
535 }
536 else if (status & MM_DEF_DIED) { /* defender died */
537 /*
538 * Note: remove_monster() was called in relmon(), wiping out
539 * magr from level.monsters[mdef->mx][mdef->my]. We need to
540 * put it back and display it. -kd
541 */
542 place_monster(magr, dx, dy);
543 newsym(dx, dy);
544 }
545 else if (status & MM_AGR_DIED) { /* agressor died */
546 place_monster(mdef, dx, dy);
547 newsym(dx, dy);
548 }
549 else { /* both alive, put them back */
550 if (cansee(dx, dy))
551 pline("%s is regurgitated!", Monnam(mdef));
552
553 place_monster(magr, ax, ay);
554 place_monster(mdef, dx, dy);
555 newsym(ax, ay);
556 newsym(dx, dy);
557 }
558
559 return status;
560 }
561
562 STATIC_OVL int
explmm(magr,mdef,mattk)563 explmm(magr, mdef, mattk)
564 register struct monst *magr, *mdef;
565 register struct attack *mattk;
566 {
567 int result;
568
569 if (magr->mcan)
570 return MM_MISS;
571
572 if(cansee(magr->mx, magr->my))
573 pline("%s explodes!", Monnam(magr));
574 else noises(magr, mattk);
575
576 result = mdamagem(magr, mdef, mattk);
577
578 /* Kill off agressor if it didn't die. */
579 if (!(result & MM_AGR_DIED)) {
580 mondead(magr);
581 if (magr->mhp > 0) return result; /* life saved */
582 result |= MM_AGR_DIED;
583 }
584 if (magr->mtame) /* give this one even if it was visible */
585 You(brief_feeling, "melancholy");
586
587 return result;
588 }
589
590 #ifdef WEBB_DISINT
591 STATIC_OVL int
defdisintagr(magr,mdef,mattk)592 defdisintagr(magr, mdef, mattk)
593 register struct monst *magr, *mdef;
594 register struct attack *mattk;
595 {
596 int tmp=-1; /* -1 a miss,
597 -MM_AGR_DIED aggre died,
598 -2 do nothing,
599 >=0 store as tmp. */
600
601 if (mdef->mhp>6 && !mdef->mcan) {
602 int touched = 0;
603 int mass = 0;
604 struct obj * otch = 0;
605 switch (attk_protection((int)mattk->aatyp)) {
606 /* this is in dire need of optimization */
607 case (W_ARMC|W_ARMG):
608 if ((otch = which_armor(magr, W_ARMG))) {
609 if (!oresist_disintegration(otch)) {
610 if (canseemon(magr))
611 pline("%s %s disintegrates!",
612 s_suffix(Monnam(magr)), distant_name(otch, xname));
613 mass += otch->owt;
614 m_useup(magr,otch);
615 otch = 0;
616 touched = 1;
617 }
618 } else touched = 1;
619 if ((otch = which_armor(magr, W_ARMC))) {
620 if (!oresist_disintegration(otch)) {
621 if (canseemon(magr))
622 pline("%s %s disintegrates!",
623 s_suffix(Monnam(magr)), distant_name(otch, xname));
624 mass += otch->owt;
625 m_useup(magr,otch);
626 touched = 1;
627 }
628 } else touched = 1;
629 if (!(magr->misc_worn_check & W_ARMC) &&
630 (otch = which_armor(magr,W_ARM)) &&
631 (!oresist_disintegration(otch))) {
632 if (canseemon(magr))
633 pline("%s %s disintegrates!",
634 s_suffix(Monnam(magr)), distant_name(otch, xname));
635 mass += otch->owt;
636 m_useup(magr,otch);
637 }
638 #ifdef TOURIST
639 if (!(magr->misc_worn_check & (W_ARMC|W_ARM)) &&
640 (otch = which_armor(magr,W_ARMU)) &&
641 (!oresist_disintegration(otch))) {
642 if (canseemon(magr))
643 pline("%s %s disintegrates!",
644 s_suffix(Monnam(magr)), distant_name(otch, xname));
645 mass += otch->owt;
646 m_useup(magr,otch);
647 }
648 #endif
649 break;
650 case (W_ARMG):
651 if (otmp) {
652 if (!oresist_disintegration(otmp)) {
653 if (canseemon(magr))
654 pline("%s %s disintegrates!",
655 s_suffix(Monnam(magr)), distant_name(otmp, xname));
656 mass += otmp->owt;
657 m_useup(magr,otmp);
658 tmp = 0;
659 }
660 } else if ((otch = which_armor(magr,W_ARMG))) {
661 if (!oresist_disintegration(otch)) {
662 if (canseemon(magr))
663 pline("%s %s disintegrates!",
664 s_suffix(Monnam(magr)), distant_name(otch, xname));
665 mass += otch->owt;
666 m_useup(magr,otch);
667 touched = 1;
668 }
669 } else touched = 1;
670 break;
671 case (W_ARMH):
672 if ((otch = which_armor(magr,W_ARMH))) {
673 if (!oresist_disintegration(otch)) {
674 if (canseemon(magr))
675 pline("%s %s disintegrates!",
676 s_suffix(Monnam(magr)), distant_name(otch, xname));
677 mass += otch->owt;
678 m_useup(magr,otch);
679 touched = 1;
680 }
681 } else touched = 1;
682 break;
683 case (W_ARMF):
684 if ((otch = which_armor(magr,W_ARMF))) {
685 if (!oresist_disintegration(otch)) {
686 if (canseemon(magr))
687 pline("%s %s disintegrates!",
688 s_suffix(Monnam(magr)), distant_name(otch, xname));
689 mass += otch->owt;
690 m_useup(magr,otch);
691 touched = 1;
692 }
693 } else touched = 1;
694 break;
695 case (0L):
696 touched = 1;
697 break;
698 default:
699 break;
700 }
701 if (!touched || resists_disint(magr)) {
702 if (mass)
703 weight_dmg(mass);
704 tmp = mass;
705 } else {
706 struct obj * lifesave = mlifesaver(magr);
707 mass += magr->data->cwt;
708 weight_dmg(mass);
709 if (mass)
710 mdef->mhp -= mass ;
711 if (vis) pline("%s disintegrates!", Monnam(magr));
712 mondead_helper(magr,mattk->adtyp);
713 if (magr->mhp > 0) return -1;
714 else if (magr->mtame && !vis)
715 You(brief_feeling, "peculiarly sad");
716 return -MM_AGR_DIED;
717 }
718 }
719 return tmp;
720 }
721 #endif
722
723 /*
724 * See comment at top of mattackm(), for return values.
725 */
726 STATIC_OVL int
mdamagem(magr,mdef,mattk)727 mdamagem(magr, mdef, mattk)
728 register struct monst *magr, *mdef;
729 register struct attack *mattk;
730 {
731 struct obj *obj;
732 char buf[BUFSZ];
733 struct permonst *pa = magr->data, *pd = mdef->data;
734 int armpro, num, tmp = d((int)mattk->damn, (int)mattk->damd);
735 boolean cancelled;
736
737 #ifdef WEBB_DISINT
738 int def_disintegrated;
739 if (touch_disintegrates(pd) &&
740 (def_disintegrated = defdisintagr(magr, mdef, mattk)) != -2 )
741 switch (def_disintegrated) {
742 case -MM_AGR_DIED:
743 return MM_AGR_DIED;
744 break;
745 case -1:
746 return 0;
747 break;
748 default:
749 tmp = def_disintegrated;
750 break;
751 }
752 #endif
753 if (touch_petrifies(pd) && !resists_ston(magr)) {
754 long protector = attk_protection((int)mattk->aatyp),
755 wornitems = magr->misc_worn_check;
756
757 /* wielded weapon gives same protection as gloves here */
758 if (otmp != 0) wornitems |= W_ARMG;
759
760 if (protector == 0L ||
761 (protector != ~0L && (wornitems & protector) != protector)) {
762 if (poly_when_stoned(pa)) {
763 mon_to_stone(magr);
764 return MM_HIT; /* no damage during the polymorph */
765 }
766 if (vis) pline("%s turns to stone!", Monnam(magr));
767 monstone(magr);
768 if (magr->mhp > 0) return 0;
769 else if (magr->mtame && !vis)
770 You(brief_feeling, "peculiarly sad");
771 return MM_AGR_DIED;
772 }
773 }
774
775 /* cancellation factor is the same as when attacking the hero */
776 armpro = magic_negation(mdef);
777 cancelled = magr->mcan || !((rn2(3) >= armpro) || !rn2(50));
778
779 switch(mattk->adtyp) {
780 case AD_DGST:
781 /* eating a Rider or its corpse is fatal */
782 if (is_rider(mdef->data)) {
783 if (vis)
784 pline("%s %s!", Monnam(magr),
785 mdef->data == &mons[PM_FAMINE] ?
786 "belches feebly, shrivels up and dies" :
787 mdef->data == &mons[PM_PESTILENCE] ?
788 "coughs spasmodically and collapses" :
789 "vomits violently and drops dead");
790 mondied(magr);
791 if (magr->mhp > 0) return 0; /* lifesaved */
792 else if (magr->mtame && !vis)
793 You(brief_feeling, "queasy");
794 return MM_AGR_DIED;
795 }
796 if(flags.verbose && flags.soundok) verbalize("Burrrrp!");
797 tmp = mdef->mhp;
798 /* Use up amulet of life saving */
799 if (!!(obj = mlifesaver(mdef))) m_useup(mdef, obj);
800
801 /* Is a corpse for nutrition possible? It may kill magr */
802 if (!corpse_chance(mdef, magr, TRUE) || magr->mhp < 1)
803 break;
804
805 /* Pets get nutrition from swallowing monster whole.
806 * No nutrition from G_NOCORPSE monster, eg, undead.
807 * DGST monsters don't die from undead corpses
808 */
809 num = monsndx(mdef->data);
810 if (magr->mtame && !magr->isminion &&
811 !(mvitals[num].mvflags & G_NOCORPSE)) {
812 struct obj *virtualcorpse = mksobj(CORPSE, FALSE, FALSE);
813 int nutrit;
814
815 virtualcorpse->corpsenm = num;
816 virtualcorpse->owt = weight(virtualcorpse);
817 nutrit = dog_nutrition(magr, virtualcorpse);
818 dealloc_obj(virtualcorpse);
819
820 /* only 50% nutrition, 25% of normal eating time */
821 if (magr->meating > 1) magr->meating = (magr->meating+3)/4;
822 if (nutrit > 1) nutrit /= 2;
823 EDOG(magr)->hungrytime += nutrit;
824 }
825 break;
826 case AD_STUN:
827 if (magr->mcan) break;
828 if (canseemon(mdef))
829 pline("%s %s for a moment.", Monnam(mdef),
830 makeplural(stagger(mdef->data, "stagger")));
831 mdef->mstun = 1;
832 goto physical;
833 case AD_LEGS:
834 if (magr->mcan) {
835 tmp = 0;
836 break;
837 }
838 goto physical;
839 case AD_HEAD:
840 if ((!rn2(40) || mdef->data->mlet == S_JABBERWOCK) && !magr->mcan) {
841 Strcpy(buf, Monnam(magr));
842 if (!has_head(mdef->data)) {
843 pline("Somehow, %s misses %s wildly.", buf, mon_nam(mdef));
844 tmp = 0;
845 break;
846 }
847 if (noncorporeal(mdef->data) || amorphous(mdef->data)) {
848 pline("%s slices through %s %s.",
849 buf, s_suffix(mon_nam(mdef)),
850 mbodypart(mdef,NECK));
851 goto physical;
852 }
853 pline("%s %ss %s!", buf,
854 rn2(2) ? "behead" : "decapitate", mon_nam(mdef));
855 mondied(mdef);
856 if (mdef->mhp > 0) return 0;
857 return (MM_DEF_DIED | (grow_up(magr,mdef) ?
858 0 : MM_AGR_DIED));
859 }
860 case AD_WERE:
861 case AD_HEAL:
862 case AD_PHYS:
863 physical:
864 if (mattk->aatyp == AT_KICK && thick_skinned(pd)) {
865 tmp = 0;
866 } else if(mattk->aatyp == AT_WEAP) {
867 if(otmp) {
868 if (otmp->otyp == CORPSE &&
869 touch_petrifies(&mons[otmp->corpsenm]))
870 goto do_stone;
871 tmp += dmgval(otmp, mdef);
872 if (otmp->oartifact) {
873 (void)artifact_hit(magr,mdef, otmp, &tmp, dieroll);
874 if (mdef->mhp <= 0)
875 return (MM_DEF_DIED |
876 (grow_up(magr,mdef) ? 0 : MM_AGR_DIED));
877 }
878 if (tmp)
879 mrustm(magr, mdef, otmp);
880 }
881 } else if (magr->data == &mons[PM_PURPLE_WORM] &&
882 mdef->data == &mons[PM_SHRIEKER]) {
883 /* hack to enhance mm_aggression(); we don't want purple
884 worm's bite attack to kill a shrieker because then it
885 won't swallow the corpse; but if the target survives,
886 the subsequent engulf attack should accomplish that */
887 if (tmp >= mdef->mhp) tmp = mdef->mhp - 1;
888 }
889 break;
890 case AD_FIRE:
891 if (cancelled) {
892 tmp = 0;
893 break;
894 }
895 if (vis)
896 pline("%s is %s!", Monnam(mdef),
897 on_fire(mdef->data, mattk));
898 if (pd == &mons[PM_STRAW_GOLEM] ||
899 pd == &mons[PM_PAPER_GOLEM]) {
900 if (vis) pline("%s burns completely!", Monnam(mdef));
901 mondied(mdef);
902 if (mdef->mhp > 0) return 0;
903 else if (mdef->mtame && !vis)
904 pline("May %s roast in peace.", mon_nam(mdef));
905 return (MM_DEF_DIED | (grow_up(magr,mdef) ?
906 0 : MM_AGR_DIED));
907 }
908 tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
909 tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
910 if (resists_fire(mdef)) {
911 if (vis)
912 pline_The("fire doesn't seem to burn %s!",
913 mon_nam(mdef));
914 shieldeff(mdef->mx, mdef->my);
915 golemeffects(mdef, AD_FIRE, tmp);
916 tmp = 0;
917 }
918 /* only potions damage resistant players in destroy_item */
919 tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
920 break;
921 case AD_COLD:
922 if (cancelled) {
923 tmp = 0;
924 break;
925 }
926 if (vis) pline("%s is covered in frost!", Monnam(mdef));
927 if (resists_cold(mdef)) {
928 if (vis)
929 pline_The("frost doesn't seem to chill %s!",
930 mon_nam(mdef));
931 shieldeff(mdef->mx, mdef->my);
932 golemeffects(mdef, AD_COLD, tmp);
933 tmp = 0;
934 }
935 tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
936 break;
937 case AD_ELEC:
938 if (cancelled) {
939 tmp = 0;
940 break;
941 }
942 if (vis) pline("%s gets zapped!", Monnam(mdef));
943 tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
944 if (resists_elec(mdef)) {
945 if (vis) pline_The("zap doesn't shock %s!", mon_nam(mdef));
946 shieldeff(mdef->mx, mdef->my);
947 golemeffects(mdef, AD_ELEC, tmp);
948 tmp = 0;
949 }
950 /* only rings damage resistant players in destroy_item */
951 tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
952 break;
953 case AD_ACID:
954 if (magr->mcan) {
955 tmp = 0;
956 break;
957 }
958 if (resists_acid(mdef)) {
959 if (vis)
960 pline("%s is covered in acid, but it seems harmless.",
961 Monnam(mdef));
962 tmp = 0;
963 } else if (vis) {
964 pline("%s is covered in acid!", Monnam(mdef));
965 pline("It burns %s!", mon_nam(mdef));
966 }
967 if (!rn2(30)) erode_armor(mdef, TRUE);
968 if (!rn2(6)) erode_obj(MON_WEP(mdef), TRUE, TRUE);
969 break;
970 case AD_RUST:
971 if (magr->mcan) break;
972 if (pd == &mons[PM_IRON_GOLEM]) {
973 if (vis) pline("%s falls to pieces!", Monnam(mdef));
974 mondied(mdef);
975 if (mdef->mhp > 0) return 0;
976 else if (mdef->mtame && !vis)
977 pline("May %s rust in peace.", mon_nam(mdef));
978 return (MM_DEF_DIED | (grow_up(magr,mdef) ?
979 0 : MM_AGR_DIED));
980 }
981 hurtmarmor(mdef, AD_RUST);
982 mdef->mstrategy &= ~STRAT_WAITFORU;
983 tmp = 0;
984 break;
985 case AD_CORR:
986 if (magr->mcan) break;
987 hurtmarmor(mdef, AD_CORR);
988 mdef->mstrategy &= ~STRAT_WAITFORU;
989 tmp = 0;
990 break;
991 case AD_DCAY:
992 if (magr->mcan) break;
993 if (pd == &mons[PM_WOOD_GOLEM] ||
994 pd == &mons[PM_LEATHER_GOLEM]) {
995 if (vis) pline("%s falls to pieces!", Monnam(mdef));
996 mondied(mdef);
997 if (mdef->mhp > 0) return 0;
998 else if (mdef->mtame && !vis)
999 pline("May %s rot in peace.", mon_nam(mdef));
1000 return (MM_DEF_DIED | (grow_up(magr,mdef) ?
1001 0 : MM_AGR_DIED));
1002 }
1003 hurtmarmor(mdef, AD_DCAY);
1004 mdef->mstrategy &= ~STRAT_WAITFORU;
1005 tmp = 0;
1006 break;
1007 case AD_STON:
1008 if (magr->mcan) break;
1009 do_stone:
1010 /* may die from the acid if it eats a stone-curing corpse */
1011 if (munstone(mdef, FALSE)) goto post_stone;
1012 if (poly_when_stoned(pd)) {
1013 mon_to_stone(mdef);
1014 tmp = 0;
1015 break;
1016 }
1017 if (!resists_ston(mdef)) {
1018 if (vis) pline("%s turns to stone!", Monnam(mdef));
1019 monstone(mdef);
1020 post_stone: if (mdef->mhp > 0) return 0;
1021 else if (mdef->mtame && !vis)
1022 You(brief_feeling, "peculiarly sad");
1023 return (MM_DEF_DIED | (grow_up(magr,mdef) ?
1024 0 : MM_AGR_DIED));
1025 }
1026 tmp = (mattk->adtyp == AD_STON ? 0 : 1);
1027 break;
1028 case AD_TLPT:
1029 if (!cancelled && tmp < mdef->mhp && !tele_restrict(mdef)) {
1030 char mdef_Monnam[BUFSZ];
1031 /* save the name before monster teleports, otherwise
1032 we'll get "it" in the suddenly disappears message */
1033 if (vis) Strcpy(mdef_Monnam, Monnam(mdef));
1034 mdef->mstrategy &= ~STRAT_WAITFORU;
1035 (void) rloc(mdef, FALSE);
1036 if (vis && !canspotmon(mdef)
1037 #ifdef STEED
1038 && mdef != u.usteed
1039 #endif
1040 )
1041 pline("%s suddenly disappears!", mdef_Monnam);
1042 }
1043 break;
1044 case AD_SLEE:
1045 if (!cancelled && !mdef->msleeping &&
1046 sleep_monst(mdef, rnd(10), -1)) {
1047 if (vis) {
1048 Strcpy(buf, Monnam(mdef));
1049 pline("%s is put to sleep by %s.", buf, mon_nam(magr));
1050 }
1051 mdef->mstrategy &= ~STRAT_WAITFORU;
1052 slept_monst(mdef);
1053 }
1054 break;
1055 case AD_PLYS:
1056 if(!cancelled && mdef->mcanmove) {
1057 if (vis) {
1058 Strcpy(buf, Monnam(mdef));
1059 pline("%s is frozen by %s.", buf, mon_nam(magr));
1060 }
1061 mdef->mcanmove = 0;
1062 mdef->mfrozen = rnd(10);
1063 mdef->mstrategy &= ~STRAT_WAITFORU;
1064 }
1065 break;
1066 case AD_SLOW:
1067 if (!cancelled && mdef->mspeed != MSLOW) {
1068 unsigned int oldspeed = mdef->mspeed;
1069
1070 mon_adjust_speed(mdef, -1, (struct obj *)0);
1071 mdef->mstrategy &= ~STRAT_WAITFORU;
1072 if (mdef->mspeed != oldspeed && vis)
1073 pline("%s slows down.", Monnam(mdef));
1074 }
1075 break;
1076 case AD_CONF:
1077 /* Since confusing another monster doesn't have a real time
1078 * limit, setting spec_used would not really be right (though
1079 * we still should check for it).
1080 */
1081 if (!magr->mcan && !mdef->mconf && !magr->mspec_used) {
1082 if (vis) pline("%s looks confused.", Monnam(mdef));
1083 mdef->mconf = 1;
1084 mdef->mstrategy &= ~STRAT_WAITFORU;
1085 }
1086 break;
1087 case AD_BLND:
1088 if (can_blnd(magr, mdef, mattk->aatyp, (struct obj*)0)) {
1089 register unsigned rnd_tmp;
1090
1091 if (vis && mdef->mcansee)
1092 pline("%s is blinded.", Monnam(mdef));
1093 rnd_tmp = d((int)mattk->damn, (int)mattk->damd);
1094 if ((rnd_tmp += mdef->mblinded) > 127) rnd_tmp = 127;
1095 mdef->mblinded = rnd_tmp;
1096 mdef->mcansee = 0;
1097 mdef->mstrategy &= ~STRAT_WAITFORU;
1098 }
1099 tmp = 0;
1100 break;
1101 case AD_HALU:
1102 if (!magr->mcan && haseyes(pd) && mdef->mcansee) {
1103 if (vis) pline("%s looks %sconfused.",
1104 Monnam(mdef), mdef->mconf ? "more " : "");
1105 mdef->mconf = 1;
1106 mdef->mstrategy &= ~STRAT_WAITFORU;
1107 }
1108 tmp = 0;
1109 break;
1110 case AD_CURS:
1111 if (!night() && (pa == &mons[PM_GREMLIN])) break;
1112 if (!magr->mcan && !rn2(10)) {
1113 mdef->mcan = 1; /* cancelled regardless of lifesave */
1114 mdef->mstrategy &= ~STRAT_WAITFORU;
1115 if (is_were(pd) && pd->mlet != S_HUMAN)
1116 were_change(mdef);
1117 if (pd == &mons[PM_CLAY_GOLEM]) {
1118 if (vis) {
1119 pline("Some writing vanishes from %s head!",
1120 s_suffix(mon_nam(mdef)));
1121 pline("%s is destroyed!", Monnam(mdef));
1122 }
1123 mondied(mdef);
1124 if (mdef->mhp > 0) return 0;
1125 else if (mdef->mtame && !vis)
1126 You(brief_feeling, "strangely sad");
1127 return (MM_DEF_DIED | (grow_up(magr,mdef) ?
1128 0 : MM_AGR_DIED));
1129 }
1130 if (flags.soundok) {
1131 if (!vis) You_hear("laughter.");
1132 else pline("%s chuckles.", Monnam(magr));
1133 }
1134 }
1135 break;
1136 case AD_SGLD:
1137 tmp = 0;
1138 #ifndef GOLDOBJ
1139 if (magr->mcan || !mdef->mgold) break;
1140 /* technically incorrect; no check for stealing gold from
1141 * between mdef's feet...
1142 */
1143 magr->mgold += mdef->mgold;
1144 mdef->mgold = 0;
1145 #else
1146 if (magr->mcan) break;
1147 /* technically incorrect; no check for stealing gold from
1148 * between mdef's feet...
1149 */
1150 {
1151 struct obj *gold = findgold(mdef->minvent);
1152 if (!gold) break;
1153 obj_extract_self(gold);
1154 add_to_minv(magr, gold);
1155 }
1156 #endif
1157 mdef->mstrategy &= ~STRAT_WAITFORU;
1158 if (vis) {
1159 Strcpy(buf, Monnam(magr));
1160 pline("%s steals some gold from %s.", buf, mon_nam(mdef));
1161 }
1162 if (!tele_restrict(magr)) {
1163 (void) rloc(magr, FALSE);
1164 if (vis && !canspotmon(magr))
1165 pline("%s suddenly disappears!", buf);
1166 }
1167 break;
1168 case AD_DRLI:
1169 if (!cancelled && magr->mtame && !magr->isminion &&
1170 is_vampire(pa) && mattk->aatyp == AT_BITE &&
1171 has_blood(pd))
1172 EDOG(magr)->hungrytime += ((int)((mdef->data)->cnutrit / 20) + 1);
1173
1174 if (!cancelled && !rn2(3) && !resists_drli(mdef)) {
1175 tmp = d(2,6);
1176 if (vis)
1177 pline("%s suddenly seems weaker!", Monnam(mdef));
1178 mdef->mhpmax -= tmp;
1179 if (mdef->m_lev == 0)
1180 tmp = mdef->mhp;
1181 else mdef->m_lev--;
1182 /* Automatic kill if drained past level 0 */
1183 }
1184 break;
1185 #ifdef SEDUCE
1186 case AD_SSEX:
1187 #endif
1188 case AD_SITM: /* for now these are the same */
1189 case AD_SEDU:
1190 if (magr->mcan) break;
1191 /* find an object to steal, non-cursed if magr is tame */
1192 for (obj = mdef->minvent; obj; obj = obj->nobj)
1193 if (!magr->mtame || !obj->cursed)
1194 break;
1195
1196 if (obj) {
1197 char onambuf[BUFSZ], mdefnambuf[BUFSZ];
1198
1199 /* make a special x_monnam() call that never omits
1200 the saddle, and save it for later messages */
1201 Strcpy(mdefnambuf, x_monnam(mdef, ARTICLE_THE, (char *)0, 0, FALSE));
1202
1203 otmp = obj;
1204 #ifdef STEED
1205 if (u.usteed == mdef &&
1206 otmp == which_armor(mdef, W_SADDLE))
1207 /* "You can no longer ride <steed>." */
1208 dismount_steed(DISMOUNT_POLY);
1209 #endif
1210 obj_extract_self(otmp);
1211 if (otmp->owornmask) {
1212 mdef->misc_worn_check &= ~otmp->owornmask;
1213 if (otmp->owornmask & W_WEP)
1214 setmnotwielded(mdef,otmp);
1215 otmp->owornmask = 0L;
1216 update_mon_intrinsics(mdef, otmp, FALSE, FALSE);
1217 }
1218 /* add_to_minv() might free otmp [if it merges] */
1219 if (vis)
1220 Strcpy(onambuf, doname(otmp));
1221 (void) add_to_minv(magr, otmp);
1222 if (vis) {
1223 Strcpy(buf, Monnam(magr));
1224 pline("%s steals %s from %s!", buf,
1225 onambuf, mdefnambuf);
1226 }
1227 possibly_unwield(mdef, FALSE);
1228 mdef->mstrategy &= ~STRAT_WAITFORU;
1229 mselftouch(mdef, (const char *)0, FALSE);
1230 if (mdef->mhp <= 0)
1231 return (MM_DEF_DIED | (grow_up(magr,mdef) ?
1232 0 : MM_AGR_DIED));
1233 if (magr->data->mlet == S_NYMPH &&
1234 !tele_restrict(magr)) {
1235 (void) rloc(magr, FALSE);
1236 if (vis && !canspotmon(magr))
1237 pline("%s suddenly disappears!", buf);
1238 }
1239 }
1240 tmp = 0;
1241 break;
1242 case AD_DRST:
1243 case AD_DRDX:
1244 case AD_DRCO:
1245 if (!cancelled && !rn2(8)) {
1246 if (vis)
1247 pline("%s %s was poisoned!", s_suffix(Monnam(magr)),
1248 mpoisons_subj(magr, mattk));
1249 if (resists_poison(mdef)) {
1250 if (vis)
1251 pline_The("poison doesn't seem to affect %s.",
1252 mon_nam(mdef));
1253 } else {
1254 if (rn2(10)) tmp += rn1(10,6);
1255 else {
1256 if (vis) pline_The("poison was deadly...");
1257 tmp = mdef->mhp;
1258 }
1259 }
1260 }
1261 break;
1262 case AD_DRIN:
1263 if (notonhead || !has_head(pd)) {
1264 if (vis) pline("%s doesn't seem harmed.", Monnam(mdef));
1265 /* Not clear what to do for green slimes */
1266 tmp = 0;
1267 break;
1268 }
1269 if ((mdef->misc_worn_check & W_ARMH) && rn2(8)) {
1270 if (vis) {
1271 Strcpy(buf, s_suffix(Monnam(mdef)));
1272 pline("%s helmet blocks %s attack to %s head.",
1273 buf, s_suffix(mon_nam(magr)),
1274 mhis(mdef));
1275 }
1276 break;
1277 }
1278 if (vis) pline("%s brain is eaten!", s_suffix(Monnam(mdef)));
1279 if (mindless(pd)) {
1280 if (vis) pline("%s doesn't notice.", Monnam(mdef));
1281 break;
1282 }
1283 tmp += rnd(10); /* fakery, since monsters lack INT scores */
1284 if (magr->mtame && !magr->isminion) {
1285 EDOG(magr)->hungrytime += rnd(60);
1286 magr->mconf = 0;
1287 }
1288 if (tmp >= mdef->mhp && vis)
1289 pline("%s last thought fades away...",
1290 s_suffix(Monnam(mdef)));
1291 break;
1292 case AD_SLIM:
1293 if (cancelled) break; /* physical damage only */
1294 if (!rn2(4) && !flaming(mdef->data) &&
1295 mdef->data != &mons[PM_GREEN_SLIME]) {
1296 (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, vis);
1297 mdef->mstrategy &= ~STRAT_WAITFORU;
1298 tmp = 0;
1299 }
1300 break;
1301 case AD_STCK:
1302 if (cancelled) tmp = 0;
1303 break;
1304 case AD_WRAP: /* monsters cannot grab one another, it's too hard */
1305 if (magr->mcan) tmp = 0;
1306 break;
1307 case AD_ENCH:
1308 /* there's no msomearmor() function, so just do damage */
1309 /* if (cancelled) break; */
1310 break;
1311 #ifdef WEBB_DISINT
1312 case AD_DISN: /* only hit torso aromor */
1313 if (!magr->mcan && magr->mhp > 6) {
1314 struct obj * otch = 0;
1315 int recip_dam = 0;
1316 if ((otch = which_armor(mdef, W_ARMS))) {
1317 if (oresist_disintegration(otch))
1318 otch = 0;
1319 } else if ((otch = which_armor(mdef, W_ARMC))) {
1320 if (oresist_disintegration(otch))
1321 otch = 0;
1322 } else if ((otch = which_armor(mdef, W_ARM))) {
1323 if (oresist_disintegration(otch))
1324 otch = 0;
1325 #ifdef TOURIST
1326 } else if ((otch = which_armor(mdef, W_ARMU))) {
1327 if (oresist_disintegration(otch))
1328 otch = 0;
1329 #endif
1330 } else {
1331 recip_dam = minstadisintegrate(mdef);
1332 }
1333 if (recip_dam) {
1334 tmp = 0;
1335 } else if (otch) {
1336 recip_dam = otch->owt;
1337 weight_dmg(recip_dam);
1338 if(canseemon(mdef))
1339 pline("%s %s disintegrates!",
1340 s_suffix(Monnam(mdef)), distant_name(otch, xname));
1341 m_useup(mdef,otch);
1342 tmp = 0;
1343 }
1344 magr->mhp -= recip_dam;
1345 if (!mdef->mhp)
1346 return (MM_DEF_DIED |
1347 (grow_up(magr,mdef) ? 0 : MM_AGR_DIED));
1348 }
1349 break;
1350 #endif
1351 default: tmp = 0;
1352 break;
1353 }
1354 if(!tmp) return(MM_MISS);
1355
1356 if((mdef->mhp -= tmp) < 1) {
1357 if (m_at(mdef->mx, mdef->my) == magr) { /* see gulpmm() */
1358 remove_monster(mdef->mx, mdef->my);
1359 mdef->mhp = 1; /* otherwise place_monster will complain */
1360 place_monster(mdef, mdef->mx, mdef->my);
1361 mdef->mhp = 0;
1362 }
1363 monkilled(mdef, "", (int)mattk->adtyp);
1364 if (mdef->mhp > 0) return 0; /* mdef lifesaved */
1365
1366 if (mattk->adtyp == AD_DGST) {
1367 /* various checks similar to dog_eat and meatobj.
1368 * after monkilled() to provide better message ordering */
1369 if (mdef->cham != CHAM_ORDINARY) {
1370 (void) newcham(magr, (struct permonst *)0, FALSE, TRUE);
1371 } else if (mdef->data == &mons[PM_GREEN_SLIME]) {
1372 (void) newcham(magr, &mons[PM_GREEN_SLIME], FALSE, TRUE);
1373 } else if (mdef->data == &mons[PM_WRAITH]) {
1374 (void) grow_up(magr, (struct monst *)0);
1375 /* don't grow up twice */
1376 return (MM_DEF_DIED | (magr->mhp > 0 ? 0 : MM_AGR_DIED));
1377 } else if (mdef->data == &mons[PM_NURSE]) {
1378 magr->mhp = magr->mhpmax;
1379 }
1380 }
1381
1382 return (MM_DEF_DIED | (grow_up(magr,mdef) ? 0 : MM_AGR_DIED));
1383 }
1384 return(MM_HIT);
1385 }
1386
1387 #endif /* OVLB */
1388
1389
1390 #ifdef OVL0
1391
1392 int
noattacks(ptr)1393 noattacks(ptr) /* returns 1 if monster doesn't attack */
1394 struct permonst *ptr;
1395 {
1396 int i;
1397
1398 for(i = 0; i < NATTK; i++)
1399 if(ptr->mattk[i].aatyp) return(0);
1400
1401 return(1);
1402 }
1403
1404 /* `mon' is hit by a sleep attack; return 1 if it's affected, 0 otherwise */
1405 int
sleep_monst(mon,amt,how)1406 sleep_monst(mon, amt, how)
1407 struct monst *mon;
1408 int amt, how;
1409 {
1410 if (resists_sleep(mon) ||
1411 (how >= 0 && resist(mon, (char)how, 0, NOTELL))) {
1412 shieldeff(mon->mx, mon->my);
1413 } else if (mon->mcanmove) {
1414 amt += (int) mon->mfrozen;
1415 if (amt > 0) { /* sleep for N turns */
1416 mon->mcanmove = 0;
1417 mon->mfrozen = min(amt, 127);
1418 } else { /* sleep until awakened */
1419 mon->msleeping = 1;
1420 }
1421 return 1;
1422 }
1423 return 0;
1424 }
1425
1426 /* sleeping grabber releases, engulfer doesn't; don't use for paralysis! */
1427 void
slept_monst(mon)1428 slept_monst(mon)
1429 struct monst *mon;
1430 {
1431 if ((mon->msleeping || !mon->mcanmove) && mon == u.ustuck &&
1432 !sticks(youmonst.data) && !u.uswallow) {
1433 pline("%s grip relaxes.", s_suffix(Monnam(mon)));
1434 unstuck(mon);
1435 }
1436 }
1437
1438 #endif /* OVL0 */
1439 #ifdef OVLB
1440
1441 STATIC_OVL void
mrustm(magr,mdef,obj)1442 mrustm(magr, mdef, obj)
1443 register struct monst *magr, *mdef;
1444 register struct obj *obj;
1445 {
1446 boolean is_acid;
1447
1448 if (!magr || !mdef || !obj) return; /* just in case */
1449
1450 if (dmgtype(mdef->data, AD_CORR))
1451 is_acid = TRUE;
1452 else if (dmgtype(mdef->data, AD_RUST))
1453 is_acid = FALSE;
1454 else
1455 return;
1456
1457 if (!mdef->mcan &&
1458 (is_acid ? is_corrodeable(obj) : is_rustprone(obj)) &&
1459 (is_acid ? obj->oeroded2 : obj->oeroded) < MAX_ERODE) {
1460 if (obj->greased || obj->oerodeproof || (obj->blessed && rn2(3))) {
1461 if (cansee(mdef->mx, mdef->my) && flags.verbose)
1462 pline("%s weapon is not affected.",
1463 s_suffix(Monnam(magr)));
1464 if (obj->greased && !rn2(2)) obj->greased = 0;
1465 } else {
1466 if (cansee(mdef->mx, mdef->my)) {
1467 pline("%s %s%s!", s_suffix(Monnam(magr)),
1468 aobjnam(obj, (is_acid ? "corrode" : "rust")),
1469 (is_acid ? obj->oeroded2 : obj->oeroded)
1470 ? " further" : "");
1471 }
1472 if (is_acid) obj->oeroded2++;
1473 else obj->oeroded++;
1474 }
1475 }
1476 }
1477
1478 STATIC_OVL void
mswingsm(magr,mdef,otemp)1479 mswingsm(magr, mdef, otemp)
1480 register struct monst *magr, *mdef;
1481 register struct obj *otemp;
1482 {
1483 char buf[BUFSZ];
1484 if (!flags.verbose || Blind || !mon_visible(magr)) return;
1485 Strcpy(buf, mon_nam(mdef));
1486 pline("%s %s %s %s at %s.", Monnam(magr),
1487 (objects[otemp->otyp].oc_dir & PIERCE) ? "thrusts" : "swings",
1488 mhis(magr), singular(otemp, xname), buf);
1489 }
1490
1491 /*
1492 * Passive responses by defenders. Does not replicate responses already
1493 * handled above. Returns same values as mattackm.
1494 */
1495 STATIC_OVL int
passivemm(magr,mdef,mhit,mdead)1496 passivemm(magr,mdef,mhit,mdead)
1497 register struct monst *magr, *mdef;
1498 boolean mhit;
1499 int mdead;
1500 {
1501 register struct permonst *mddat = mdef->data;
1502 register struct permonst *madat = magr->data;
1503 char buf[BUFSZ];
1504 int i, tmp;
1505
1506 for(i = 0; ; i++) {
1507 if(i >= NATTK) return (mdead | mhit); /* no passive attacks */
1508 if(mddat->mattk[i].aatyp == AT_NONE) break;
1509 }
1510 if (mddat->mattk[i].damn)
1511 tmp = d((int)mddat->mattk[i].damn,
1512 (int)mddat->mattk[i].damd);
1513 else if(mddat->mattk[i].damd)
1514 tmp = d((int)mddat->mlevel+1, (int)mddat->mattk[i].damd);
1515 else
1516 tmp = 0;
1517
1518 /* These affect the enemy even if defender killed */
1519 switch(mddat->mattk[i].adtyp) {
1520 case AD_ACID:
1521 if (mhit && !rn2(2)) {
1522 Strcpy(buf, Monnam(magr));
1523 if(canseemon(magr))
1524 pline("%s is splashed by %s acid!",
1525 buf, s_suffix(mon_nam(mdef)));
1526 if (resists_acid(magr)) {
1527 if(canseemon(magr))
1528 pline("%s is not affected.", Monnam(magr));
1529 tmp = 0;
1530 }
1531 } else tmp = 0;
1532 goto assess_dmg;
1533 case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
1534 if (mhit && !mdef->mcan && otmp) {
1535 (void) drain_item(otmp);
1536 /* No message */
1537 }
1538 break;
1539 default:
1540 break;
1541 }
1542 if (mdead || mdef->mcan) return (mdead|mhit);
1543
1544 /* These affect the enemy only if defender is still alive */
1545 if (rn2(3)) switch(mddat->mattk[i].adtyp) {
1546 case AD_PLYS: /* Floating eye */
1547 if (tmp > 127) tmp = 127;
1548 if (mddat == &mons[PM_FLOATING_EYE]) {
1549 if (!rn2(4)) tmp = 127;
1550 if (magr->mcansee && haseyes(madat) && mdef->mcansee &&
1551 (perceives(madat) || !mdef->minvis)) {
1552 Sprintf(buf, "%s gaze is reflected by %%s %%s.",
1553 s_suffix(mon_nam(mdef)));
1554 if (mon_reflects(magr,
1555 canseemon(magr) ? buf : (char *)0))
1556 return(mdead|mhit);
1557 Strcpy(buf, Monnam(magr));
1558 if(canseemon(magr))
1559 pline("%s is frozen by %s gaze!",
1560 buf, s_suffix(mon_nam(mdef)));
1561 magr->mcanmove = 0;
1562 magr->mfrozen = tmp;
1563 return (mdead|mhit);
1564 }
1565 } else { /* gelatinous cube */
1566 Strcpy(buf, Monnam(magr));
1567 if(canseemon(magr))
1568 pline("%s is frozen by %s.", buf, mon_nam(mdef));
1569 magr->mcanmove = 0;
1570 magr->mfrozen = tmp;
1571 return (mdead|mhit);
1572 }
1573 return 1;
1574 case AD_COLD:
1575 if (resists_cold(magr)) {
1576 if (canseemon(magr)) {
1577 pline("%s is mildly chilly.", Monnam(magr));
1578 golemeffects(magr, AD_COLD, tmp);
1579 }
1580 tmp = 0;
1581 break;
1582 }
1583 if(canseemon(magr))
1584 pline("%s is suddenly very cold!", Monnam(magr));
1585 mdef->mhp += tmp / 2;
1586 if (mdef->mhpmax < mdef->mhp) mdef->mhpmax = mdef->mhp;
1587 if (mdef->mhpmax > ((int) (mdef->m_lev+1) * 8))
1588 (void)split_mon(mdef, magr);
1589 break;
1590 case AD_STUN:
1591 if (!magr->mstun) {
1592 magr->mstun = 1;
1593 if (canseemon(magr))
1594 pline("%s %s...", Monnam(magr),
1595 makeplural(stagger(magr->data, "stagger")));
1596 }
1597 tmp = 0;
1598 break;
1599 case AD_FIRE:
1600 if (resists_fire(magr)) {
1601 if (canseemon(magr)) {
1602 pline("%s is mildly warmed.", Monnam(magr));
1603 golemeffects(magr, AD_FIRE, tmp);
1604 }
1605 tmp = 0;
1606 break;
1607 }
1608 if(canseemon(magr))
1609 pline("%s is suddenly very hot!", Monnam(magr));
1610 break;
1611 case AD_ELEC:
1612 if (resists_elec(magr)) {
1613 if (canseemon(magr)) {
1614 pline("%s is mildly tingled.", Monnam(magr));
1615 golemeffects(magr, AD_ELEC, tmp);
1616 }
1617 tmp = 0;
1618 break;
1619 }
1620 if(canseemon(magr))
1621 pline("%s is jolted with electricity!", Monnam(magr));
1622 break;
1623 default: tmp = 0;
1624 break;
1625 }
1626 else tmp = 0;
1627
1628 assess_dmg:
1629 if((magr->mhp -= tmp) <= 0) {
1630 monkilled(magr, "", (int)mddat->mattk[i].adtyp);
1631 return (mdead | mhit | MM_AGR_DIED);
1632 }
1633 return (mdead | mhit);
1634 }
1635
1636 /* "aggressive defense"; what type of armor prevents specified attack
1637 from touching its target? */
1638 long
attk_protection(aatyp)1639 attk_protection(aatyp)
1640 int aatyp;
1641 {
1642 long w_mask = 0L;
1643
1644 switch (aatyp) {
1645 case AT_NONE:
1646 case AT_SPIT:
1647 case AT_EXPL:
1648 case AT_BOOM:
1649 case AT_GAZE:
1650 case AT_BREA:
1651 case AT_MAGC:
1652 w_mask = ~0L; /* special case; no defense needed */
1653 break;
1654 case AT_CLAW:
1655 case AT_TUCH:
1656 case AT_WEAP:
1657 w_mask = W_ARMG; /* caller needs to check for weapon */
1658 break;
1659 case AT_KICK:
1660 w_mask = W_ARMF;
1661 break;
1662 case AT_BUTT:
1663 w_mask = W_ARMH;
1664 break;
1665 case AT_HUGS:
1666 w_mask = (W_ARMC|W_ARMG); /* attacker needs both to be protected */
1667 break;
1668 case AT_BITE:
1669 case AT_STNG:
1670 case AT_ENGL:
1671 case AT_TENT:
1672 default:
1673 w_mask = 0L; /* no defense available */
1674 break;
1675 }
1676 return w_mask;
1677 }
1678
1679 #endif /* OVLB */
1680
1681 /*mhitm.c*/
1682
1683