1 /* SCCS Id: @(#)mhitm.c 3.3 2000/07/29 */
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 STATIC_DCL void FDECL(mswingsm, (struct monst *, struct monst *, struct obj *));
28 STATIC_DCL void FDECL(noises,(struct monst *,struct attack *));
29 STATIC_DCL void FDECL(missmm,(struct monst *,struct monst *,struct attack *));
30 STATIC_DCL int FDECL(passivemm, (struct monst *, struct monst *, BOOLEAN_P, int));
31
32 /* Needed for the special case of monsters wielding vorpal blades (rare).
33 * If we use this a lot it should probably be a parameter to mdamagem()
34 * instead of a global variable.
35 */
36 static int dieroll;
37
38 /* returns mon_nam(mon) relative to other_mon; normal name unless they're
39 the same, in which case the reference is to {him|her|it} self */
40 STATIC_OVL char *
mon_nam_too(outbuf,mon,other_mon)41 mon_nam_too(outbuf, mon, other_mon)
42 char *outbuf;
43 struct monst *mon, *other_mon;
44 {
45 Strcpy(outbuf, mon_nam(mon));
46 if (mon == other_mon)
47 switch (pronoun_gender(mon)) {
48 case 0: Strcpy(outbuf, "himself"); break;
49 case 1: Strcpy(outbuf, "herself"); break;
50 default: Strcpy(outbuf, "itself"); break;
51 }
52 return outbuf;
53 }
54
55 STATIC_OVL void
noises(magr,mattk)56 noises(magr, mattk)
57 register struct monst *magr;
58 register struct attack *mattk;
59 {
60 boolean farq = (distu(magr->mx, magr->my) > 15);
61
62 if(flags.soundok && (farq != far_noise || moves-noisetime > 10)) {
63 far_noise = farq;
64 noisetime = moves;
65 You_hear("%s%s.",
66 (mattk->aatyp == AT_EXPL) ? "an explosion" : "some noises",
67 farq ? " in the distance" : "");
68 }
69 }
70
71 STATIC_OVL
72 void
missmm(magr,mdef,mattk)73 missmm(magr, mdef, mattk)
74 register struct monst *magr, *mdef;
75 struct attack *mattk;
76 {
77 const char *fmt;
78 char buf[BUFSZ], mdef_name[BUFSZ];
79
80 if (vis) {
81 if (!canspotmon(mdef))
82 map_invisible(mdef->mx, mdef->my);
83 if (mdef->m_ap_type) seemimic(mdef);
84 if (magr->m_ap_type) seemimic(magr);
85 fmt = (could_seduce(magr,mdef,mattk) && !magr->mcan) ?
86 "%s pretends to be friendly to" : "%s misses";
87 Sprintf(buf, fmt, Monnam(magr));
88 pline("%s %s.", buf, mon_nam_too(mdef_name, mdef, magr));
89 } else noises(magr, mattk);
90 }
91
92 /*
93 * fightm() -- fight some other monster
94 *
95 * Returns:
96 * 0 - Monster did nothing.
97 * 1 - If the monster made an attack. The monster might have died.
98 *
99 * There is an exception to the above. If mtmp has the hero swallowed,
100 * then we report that the monster did nothing so it will continue to
101 * digest the hero.
102 */
103 int
fightm(mtmp)104 fightm(mtmp) /* have monsters fight each other */
105 register struct monst *mtmp;
106 {
107 register struct monst *mon, *nmon;
108 int result, has_u_swallowed;
109 #ifdef LINT
110 nmon = 0;
111 #endif
112 /* perhaps the monster will resist Conflict */
113 if(resist(mtmp, RING_CLASS, 0, 0))
114 return(0);
115
116 if(u.ustuck == mtmp) {
117 /* perhaps we're holding it... */
118 if(itsstuck(mtmp))
119 return(0);
120 }
121 has_u_swallowed = (u.uswallow && (mtmp == u.ustuck));
122
123 for(mon = fmon; mon; mon = nmon) {
124 nmon = mon->nmon;
125 if(nmon == mtmp) nmon = mtmp->nmon;
126 /* Be careful to ignore monsters that are already dead, since we
127 * might be calling this before we've cleaned them up. This can
128 * happen if the monster attacked a cockatrice bare-handedly, for
129 * instance.
130 */
131 if(mon != mtmp && !DEADMONSTER(mon)) {
132 if(monnear(mtmp,mon->mx,mon->my)) {
133 if(!u.uswallow && (mtmp == u.ustuck)) {
134 if(!rn2(4)) {
135 pline("%s releases you!", Monnam(mtmp));
136 u.ustuck = 0;
137 } else
138 break;
139 }
140
141 /* mtmp can be killed */
142 bhitpos.x = mon->mx;
143 bhitpos.y = mon->my;
144 notonhead = 0;
145 result = mattackm(mtmp,mon);
146
147 if (result & MM_AGR_DIED) return 1; /* mtmp died */
148 /*
149 * If mtmp has the hero swallowed, lie and say there
150 * was no attack (this allows mtmp to digest the hero).
151 */
152 if (has_u_swallowed) return 0;
153
154 return ((result & MM_HIT) ? 1 : 0);
155 }
156 }
157 }
158 return 0;
159 }
160
161 /*
162 * mattackm() -- a monster attacks another monster.
163 *
164 * This function returns a result bitfield:
165 *
166 * --------- aggressor died
167 * / ------- defender died
168 * / / ----- defender was hit
169 * / / /
170 * x x x
171 *
172 * 0x4 MM_AGR_DIED
173 * 0x2 MM_DEF_DIED
174 * 0x1 MM_HIT
175 * 0x0 MM_MISS
176 *
177 * Each successive attack has a lower probability of hitting. Some rely on the
178 * success of previous attacks. ** this doen't seem to be implemented -dl **
179 *
180 * In the case of exploding monsters, the monster dies as well.
181 */
182 int
mattackm(magr,mdef)183 mattackm(magr, mdef)
184 register struct monst *magr,*mdef;
185 {
186 int i, /* loop counter */
187 tmp, /* amour class difference */
188 strike, /* hit this attack */
189 attk, /* attack attempted this time */
190 struck = 0, /* hit at least once */
191 res[NATTK]; /* results of all attacks */
192 struct attack *mattk;
193 struct permonst *pa, *pd;
194
195 if (!magr || !mdef) return(MM_MISS); /* mike@genat */
196 if (!magr->mcanmove) return(MM_MISS); /* riv05!a3 */
197 pa = magr->data; pd = mdef->data;
198
199 /* Grid bugs cannot attack at an angle. */
200 if (pa == &mons[PM_GRID_BUG] && magr->mx != mdef->mx
201 && magr->my != mdef->my)
202 return(MM_MISS);
203
204 /* Calculate the armour class differential. */
205 tmp = find_mac(mdef) + magr->m_lev;
206 if (mdef->mconf || !mdef->mcanmove || mdef->msleeping) {
207 tmp += 4;
208 mdef->msleeping = 0;
209 }
210
211 /* undetect monsters become un-hidden if they are attacked */
212 if (mdef->mundetected) {
213 mdef->mundetected = 0;
214 newsym(mdef->mx, mdef->my);
215 if(canseemon(mdef) && !sensemon(mdef))
216 pline("Suddenly, you notice %s.", a_monnam(mdef));
217 }
218
219 /* Elves hate orcs. */
220 if (is_elf(pa) && is_orc(pd)) tmp++;
221
222
223 /* Set up the visibility of action */
224 vis = (cansee(magr->mx,magr->my) && cansee(mdef->mx,mdef->my));
225
226 /* Set flag indicating monster has moved this turn. Necessary since a
227 * monster might get an attack out of sequence (i.e. before its move) in
228 * some cases, in which case this still counts as its move for the round
229 * and it shouldn't move again.
230 */
231 magr->mlstmv = monstermoves;
232
233 /* Now perform all attacks for the monster. */
234 for (i = 0; i < NATTK; i++) {
235 res[i] = MM_MISS;
236 mattk = &(pa->mattk[i]);
237 otmp = (struct obj *)0;
238 attk = 1;
239 switch (mattk->aatyp) {
240 case AT_WEAP: /* "hand to hand" attacks */
241 if (magr->weapon_check == NEED_WEAPON || !MON_WEP(magr)) {
242 magr->weapon_check = NEED_HTH_WEAPON;
243 if (mon_wield_item(magr) != 0) return 0;
244 }
245 possibly_unwield(magr);
246 otmp = MON_WEP(magr);
247
248 if (otmp) {
249 if (vis) mswingsm(magr, mdef, otmp);
250 tmp += hitval(otmp, mdef);
251 }
252 /* fall through */
253 case AT_CLAW:
254 case AT_KICK:
255 case AT_BITE:
256 case AT_STNG:
257 case AT_TUCH:
258 case AT_BUTT:
259 case AT_TENT:
260 /* Nymph that teleported away on first attack? */
261 if (distmin(magr->mx,magr->my,mdef->mx,mdef->my) > 1)
262 return MM_MISS;
263 /* Monsters won't attack cockatrices physically if they
264 * have a weapon instead. This instinct doesn't work for
265 * players, or under conflict or confusion.
266 */
267 if (!magr->mconf && !Conflict && otmp &&
268 mattk->aatyp != AT_WEAP && touch_petrifies(mdef->data)) {
269 strike = 0;
270 break;
271 }
272 dieroll = rnd(20 + i);
273 strike = (tmp > dieroll);
274 /* KMH -- don't accumulate to-hit bonuses */
275 if (otmp)
276 tmp -= hitval(otmp, mdef);
277 if (strike)
278 res[i] = hitmm(magr, mdef, mattk);
279 else
280 missmm(magr, mdef, mattk);
281 break;
282
283 case AT_HUGS: /* automatic if prev two attacks succeed */
284 strike = (i >= 2 && res[i-1] == MM_HIT && res[i-2] == MM_HIT);
285 if (strike)
286 res[i] = hitmm(magr, mdef, mattk);
287
288 break;
289
290 case AT_GAZE:
291 strike = 0; /* will not wake up a sleeper */
292 res[i] = gazemm(magr, mdef, mattk);
293 break;
294
295 case AT_EXPL:
296 strike = 1; /* automatic hit */
297 res[i] = explmm(magr, mdef, mattk);
298 break;
299
300 case AT_ENGL:
301 #ifdef STEED
302 if (u.usteed && (mdef == u.usteed)) {
303 strike = 0;
304 break;
305 }
306 #endif
307 /* Engulfing attacks are directed at the hero if
308 * possible. -dlc
309 */
310 if (u.uswallow && magr == u.ustuck)
311 strike = 0;
312 else {
313 if ((strike = (tmp > rnd(20+i))))
314 res[i] = gulpmm(magr, mdef, mattk);
315 else
316 missmm(magr, mdef, mattk);
317 }
318 break;
319
320 default: /* no attack */
321 strike = 0;
322 attk = 0;
323 break;
324 }
325
326 if (attk && !(res[i] & MM_AGR_DIED))
327 res[i] = passivemm(magr, mdef, strike, res[i] & MM_DEF_DIED);
328
329 if (res[i] & MM_DEF_DIED) return res[i];
330
331 /*
332 * Wake up the defender. NOTE: this must follow the check
333 * to see if the defender died. We don't want to modify
334 * unallocated monsters!
335 */
336 if (strike) mdef->msleeping = 0;
337
338 if (res[i] & MM_AGR_DIED) return res[i];
339 /* return if aggressor can no longer attack */
340 if (!magr->mcanmove || magr->msleeping) return res[i];
341 if (res[i] & MM_HIT) struck = 1; /* at least one hit */
342 }
343
344 return(struck ? MM_HIT : MM_MISS);
345 }
346
347 /* Returns the result of mdamagem(). */
348 STATIC_OVL int
hitmm(magr,mdef,mattk)349 hitmm(magr, mdef, mattk)
350 register struct monst *magr,*mdef;
351 struct attack *mattk;
352 {
353 if(vis){
354 int compat;
355 char buf[BUFSZ], mdef_name[BUFSZ];
356
357 if (!canspotmon(mdef))
358 map_invisible(mdef->mx, mdef->my);
359 if(mdef->m_ap_type) seemimic(mdef);
360 if(magr->m_ap_type) seemimic(magr);
361 if((compat = could_seduce(magr,mdef,mattk)) && !magr->mcan) {
362 Sprintf(buf, "%s %s", Monnam(magr),
363 mdef->mcansee ? "smiles at" : "talks to");
364 pline("%s %s %s.", buf, mon_nam(mdef),
365 compat == 2 ?
366 "engagingly" : "seductively");
367 } else {
368 char magr_name[BUFSZ];
369
370 Strcpy(magr_name, Monnam(magr));
371 switch (mattk->aatyp) {
372 case AT_BITE:
373 Sprintf(buf,"%s bites", magr_name);
374 break;
375 case AT_STNG:
376 Sprintf(buf,"%s stings", magr_name);
377 break;
378 case AT_BUTT:
379 Sprintf(buf,"%s butts", magr_name);
380 break;
381 case AT_TUCH:
382 Sprintf(buf,"%s touches", magr_name);
383 break;
384 case AT_TENT:
385 Sprintf(buf, "%s tentacles suck",
386 s_suffix(magr_name));
387 break;
388 case AT_HUGS:
389 if (magr != u.ustuck) {
390 Sprintf(buf,"%s squeezes", magr_name);
391 break;
392 }
393 default:
394 Sprintf(buf,"%s hits", magr_name);
395 }
396 }
397 pline("%s %s.", buf, mon_nam_too(mdef_name, mdef, magr));
398 } else noises(magr, mattk);
399 return(mdamagem(magr, mdef, mattk));
400 }
401
402 /* Returns the same values as mdamagem(). */
403 STATIC_OVL int
gazemm(magr,mdef,mattk)404 gazemm(magr, mdef, mattk)
405 register struct monst *magr, *mdef;
406 struct attack *mattk;
407 {
408 char buf[BUFSZ];
409
410 if(vis) {
411 Sprintf(buf,"%s gazes at", Monnam(magr));
412 pline("%s %s...", buf, mon_nam(mdef));
413 }
414
415 if (!mdef->mcansee || mdef->msleeping) {
416 if(vis) pline("but nothing happens.");
417 return(MM_MISS);
418 }
419
420 return(mdamagem(magr, mdef, mattk));
421 }
422
423 /* Returns the same values as mattackm(). */
424 STATIC_OVL int
gulpmm(magr,mdef,mattk)425 gulpmm(magr, mdef, mattk)
426 register struct monst *magr, *mdef;
427 register struct attack *mattk;
428 {
429 xchar ax, ay, dx, dy;
430 int status;
431 char buf[BUFSZ];
432 struct obj *obj;
433
434 if (mdef->data->msize >= MZ_HUGE) return MM_MISS;
435
436 if (vis) {
437 Sprintf(buf,"%s swallows", Monnam(magr));
438 pline("%s %s.", buf, mon_nam(mdef));
439 }
440 for (obj = mdef->minvent; obj; obj = obj->nobj)
441 (void) snuff_lit(obj);
442
443 /*
444 * All of this maniuplation is needed to keep the display correct.
445 * There is a flush at the next pline().
446 */
447 ax = magr->mx;
448 ay = magr->my;
449 dx = mdef->mx;
450 dy = mdef->my;
451 /*
452 * Leave the defender in the monster chain at it's current position,
453 * but don't leave it on the screen. Move the agressor to the def-
454 * ender's position.
455 */
456 remove_monster(ax, ay);
457 place_monster(magr, dx, dy);
458 newsym(ax,ay); /* erase old position */
459 newsym(dx,dy); /* update new position */
460
461 status = mdamagem(magr, mdef, mattk);
462
463 if ((status & MM_AGR_DIED) && (status & MM_DEF_DIED)) {
464 ; /* both died -- do nothing */
465 }
466 else if (status & MM_DEF_DIED) { /* defender died */
467 /*
468 * Note: remove_monster() was called in relmon(), wiping out
469 * magr from level.monsters[mdef->mx][mdef->my]. We need to
470 * put it back and display it. -kd
471 */
472 place_monster(magr, dx, dy);
473 newsym(dx, dy);
474 }
475 else if (status & MM_AGR_DIED) { /* agressor died */
476 place_monster(mdef, dx, dy);
477 newsym(dx, dy);
478 }
479 else { /* both alive, put them back */
480 if (cansee(dx, dy))
481 pline("%s is regurgitated!", Monnam(mdef));
482
483 place_monster(magr, ax, ay);
484 place_monster(mdef, dx, dy);
485 newsym(ax, ay);
486 newsym(dx, dy);
487 }
488
489 return status;
490 }
491
492 STATIC_OVL int
explmm(magr,mdef,mattk)493 explmm(magr, mdef, mattk)
494 register struct monst *magr, *mdef;
495 register struct attack *mattk;
496 {
497 int result;
498
499 if(cansee(magr->mx, magr->my))
500 pline("%s explodes!", Monnam(magr));
501 else noises(magr, mattk);
502
503 result = mdamagem(magr, mdef, mattk);
504
505 /* Kill off agressor if it didn't die. */
506 if (!(result & MM_AGR_DIED)) {
507 mondead(magr);
508 if (magr->mhp > 0) return result; /* life saved */
509 result |= MM_AGR_DIED;
510 }
511 if (magr->mtame) /* give this one even if it was visible */
512 You(brief_feeling, "melancholy");
513
514 return result;
515 }
516
517 /*
518 * See comment at top of mattackm(), for return values.
519 */
520 STATIC_OVL int
mdamagem(magr,mdef,mattk)521 mdamagem(magr, mdef, mattk)
522 register struct monst *magr, *mdef;
523 register struct attack *mattk;
524 {
525 struct permonst *pa = magr->data, *pd = mdef->data;
526 int tmp = d((int)mattk->damn,(int)mattk->damd);
527 struct obj *obj;
528 char buf[BUFSZ];
529
530 if (touch_petrifies(pd) && !resists_ston(magr) &&
531 (mattk->aatyp != AT_WEAP || !otmp) &&
532 (mattk->aatyp != AT_GAZE && mattk->aatyp != AT_EXPL) &&
533 !(magr->misc_worn_check & W_ARMG)) {
534 if (poly_when_stoned(pa)) {
535 mon_to_stone(magr);
536 return MM_HIT; /* no damage during the polymorph */
537 }
538 if (vis) pline("%s turns to stone!", Monnam(magr));
539 monstone(magr);
540 if (magr->mhp > 0) return 0;
541 else if (magr->mtame && !vis)
542 You(brief_feeling, "peculiarly sad");
543 return MM_AGR_DIED;
544 }
545
546 switch(mattk->adtyp) {
547 case AD_DGST:
548 /* eating a Rider or its corpse is fatal */
549 if (is_rider(mdef->data)) {
550 if (vis)
551 pline("%s %s!", Monnam(magr),
552 mdef->data == &mons[PM_FAMINE] ?
553 "belches feebly, shrivels up and dies" :
554 mdef->data == &mons[PM_PESTILENCE] ?
555 "coughs spasmodically and collapses" :
556 "vomits violently and drops dead");
557 mondied(magr);
558 if (magr->mhp > 0) return 0; /* lifesaved */
559 else if (magr->mtame && !vis)
560 You(brief_feeling, "queasy");
561 return MM_AGR_DIED;
562 }
563 if(flags.verbose && flags.soundok) verbalize("Burrrrp!");
564 tmp = mdef->mhp;
565 /* Use up amulet of life saving */
566 if (!!(obj = mlifesaver(mdef))) m_useup(mdef, obj);
567 break;
568 case AD_STUN:
569 if (magr->mcan) break;
570 if(vis) pline("%s staggers for a moment.", Monnam(mdef));
571 mdef->mstun = 1;
572 /* fall through */
573 case AD_WERE:
574 case AD_HEAL:
575 case AD_LEGS:
576 case AD_PHYS:
577 if (mattk->aatyp == AT_KICK && thick_skinned(pd))
578 tmp = 0;
579 else if(mattk->aatyp == AT_WEAP) {
580 if(otmp) {
581 if (otmp->otyp == CORPSE &&
582 touch_petrifies(&mons[otmp->corpsenm]))
583 goto do_stone_goto_label;
584 tmp += dmgval(otmp, mdef);
585 if (otmp->oartifact) {
586 (void)artifact_hit(magr,mdef, otmp, &tmp, dieroll);
587 if (mdef->mhp <= 0)
588 return (MM_DEF_DIED |
589 (grow_up(magr,mdef) ? 0 : MM_AGR_DIED));
590 }
591 if (tmp)
592 mrustm(magr, mdef, otmp);
593 }
594 } else if (magr->data == &mons[PM_PURPLE_WORM] &&
595 mdef->data == &mons[PM_SHRIEKER]) {
596 /* hack to enhance mm_aggression(); we don't want purple
597 worm's bite attack to kill a shrieker because then it
598 won't swallow the corpse; but if the target survives,
599 the subsequent engulf attack should accomplish that */
600 if (tmp >= mdef->mhp) tmp = mdef->mhp - 1;
601 }
602 break;
603 case AD_FIRE:
604 if (magr->mcan) {
605 tmp = 0;
606 break;
607 }
608 if (vis)
609 pline("%s is %s!", Monnam(mdef),
610 mattk->aatyp == AT_HUGS ?
611 "being roasted" : "on fire");
612 if (pd == &mons[PM_STRAW_GOLEM] ||
613 pd == &mons[PM_PAPER_GOLEM]) {
614 if (vis) pline("%s burns completely!", Monnam(mdef));
615 mondied(mdef);
616 if (mdef->mhp > 0) return 0;
617 else if (mdef->mtame && !vis)
618 pline("May %s roast in peace.", mon_nam(mdef));
619 return (MM_DEF_DIED | (grow_up(magr,mdef) ?
620 0 : MM_AGR_DIED));
621 }
622 tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
623 tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
624 if (resists_fire(mdef)) {
625 if (vis)
626 pline_The("fire doesn't seem to burn %s!",
627 mon_nam(mdef));
628 shieldeff(mdef->mx, mdef->my);
629 golemeffects(mdef, AD_FIRE, tmp);
630 tmp = 0;
631 }
632 /* only potions damage resistant players in destroy_item */
633 tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
634 break;
635 case AD_COLD:
636 if (magr->mcan) {
637 tmp = 0;
638 break;
639 }
640 if (vis) pline("%s is covered in frost!", Monnam(mdef));
641 if (resists_cold(mdef)) {
642 if (vis)
643 pline_The("frost doesn't seem to chill %s!",
644 mon_nam(mdef));
645 shieldeff(mdef->mx, mdef->my);
646 golemeffects(mdef, AD_COLD, tmp);
647 tmp = 0;
648 }
649 tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
650 break;
651 case AD_ELEC:
652 if (magr->mcan) {
653 tmp = 0;
654 break;
655 }
656 if (vis) pline("%s gets zapped!", Monnam(mdef));
657 tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
658 if (resists_elec(mdef)) {
659 if (vis) pline_The("zap doesn't shock %s!", mon_nam(mdef));
660 shieldeff(mdef->mx, mdef->my);
661 golemeffects(mdef, AD_ELEC, tmp);
662 tmp = 0;
663 }
664 /* only rings damage resistant players in destroy_item */
665 tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
666 break;
667 case AD_ACID:
668 if (magr->mcan) {
669 tmp = 0;
670 break;
671 }
672 if (resists_acid(mdef)) {
673 if (vis)
674 pline("%s is covered in acid, but it seems harmless.",
675 Monnam(mdef));
676 tmp = 0;
677 } else if (vis) {
678 pline("%s is covered in acid!", Monnam(mdef));
679 pline("It burns %s!", mon_nam(mdef));
680 }
681 if (!rn2(30)) erode_armor(mdef, TRUE);
682 if (!rn2(6)) erode_weapon(MON_WEP(mdef), TRUE);
683 break;
684 case AD_RUST:
685 if (!magr->mcan && pd == &mons[PM_IRON_GOLEM]) {
686 if (vis) pline("%s falls to pieces!", Monnam(mdef));
687 mondied(mdef);
688 if (mdef->mhp > 0) return 0;
689 else if (mdef->mtame && !vis)
690 pline("May %s rust in peace.", mon_nam(mdef));
691 return (MM_DEF_DIED | (grow_up(magr,mdef) ?
692 0 : MM_AGR_DIED));
693 }
694 hurtmarmor(mdef, AD_RUST);
695 tmp = 0;
696 break;
697 case AD_CORRODE:
698 hurtmarmor(mdef, AD_CORRODE);
699 tmp = 0;
700 break;
701 case AD_DCAY:
702 if (!magr->mcan && (pd == &mons[PM_WOOD_GOLEM] ||
703 pd == &mons[PM_LEATHER_GOLEM])) {
704 if (vis) pline("%s falls to pieces!", Monnam(mdef));
705 mondied(mdef);
706 if (mdef->mhp > 0) return 0;
707 else if (mdef->mtame && !vis)
708 pline("May %s rot in peace.", mon_nam(mdef));
709 return (MM_DEF_DIED | (grow_up(magr,mdef) ?
710 0 : MM_AGR_DIED));
711 }
712 hurtmarmor(mdef, AD_DCAY);
713 tmp = 0;
714 break;
715 case AD_STON:
716 do_stone_goto_label:
717 /* may die from the acid if it eats a stone-curing corpse */
718 if (munstone(mdef, FALSE)) goto label2;
719 if (poly_when_stoned(pd)) {
720 mon_to_stone(mdef);
721 tmp = 0;
722 break;
723 }
724 if (!resists_ston(mdef)) {
725 if (vis) pline("%s turns to stone!", Monnam(mdef));
726 monstone(mdef);
727 label2: if (mdef->mhp > 0) return 0;
728 else if (mdef->mtame && !vis)
729 You(brief_feeling, "peculiarly sad");
730 return (MM_DEF_DIED | (grow_up(magr,mdef) ?
731 0 : MM_AGR_DIED));
732 }
733 tmp = (mattk->adtyp == AD_STON ? 0 : 1);
734 break;
735 case AD_TLPT:
736 if (!magr->mcan && tmp < mdef->mhp && !tele_restrict(mdef)) {
737 char mdef_Monnam[BUFSZ];
738 /* save the name before monster teleports, otherwise
739 we'll get "it" in the suddenly disappears message */
740 if (vis) Strcpy(mdef_Monnam, Monnam(mdef));
741 rloc(mdef);
742 if (vis && !canspotmon(mdef)
743 #ifdef STEED
744 && mdef != u.usteed
745 #endif
746 )
747 pline("%s suddenly disappears!", mdef_Monnam);
748 }
749 break;
750 case AD_SLEE:
751 if (!magr->mcan && !mdef->msleeping &&
752 sleep_monst(mdef, rnd(10), -1)) {
753 if (vis) {
754 Strcpy(buf, Monnam(mdef));
755 pline("%s is put to sleep by %s.", buf, mon_nam(magr));
756 }
757 slept_monst(mdef);
758 }
759 break;
760 case AD_PLYS:
761 if(!magr->mcan && mdef->mcanmove) {
762 if (vis) {
763 Strcpy(buf, Monnam(mdef));
764 pline("%s is frozen by %s.", buf, mon_nam(magr));
765 }
766 mdef->mcanmove = 0;
767 mdef->mfrozen = rnd(10);
768 }
769 break;
770 case AD_SLOW:
771 if (!magr->mcan && vis && mdef->mspeed != MSLOW) {
772 unsigned int oldspeed = mdef->mspeed;
773
774 mon_adjust_speed(mdef, -1);
775 if (mdef->mspeed != oldspeed && vis)
776 pline("%s slows down.", Monnam(mdef));
777 }
778 break;
779 case AD_CONF:
780 /* Since confusing another monster doesn't have a real time
781 * limit, setting spec_used would not really be right (though
782 * we still should check for it).
783 */
784 if (!magr->mcan && !mdef->mconf && !magr->mspec_used) {
785 if (vis) pline("%s looks confused.", Monnam(mdef));
786 mdef->mconf = 1;
787 }
788 break;
789 case AD_BLND:
790 if (can_blnd(magr, mdef, mattk->aatyp, (struct obj*)0)) {
791 register unsigned rnd_tmp;
792
793 if (vis && mdef->mcansee)
794 pline("%s is blinded.", Monnam(mdef));
795 rnd_tmp = d((int)mattk->damn, (int)mattk->damd);
796 if ((rnd_tmp += mdef->mblinded) > 127) rnd_tmp = 127;
797 mdef->mblinded = rnd_tmp;
798 mdef->mcansee = 0;
799 }
800 tmp = 0;
801 break;
802 case AD_HALU:
803 if (!magr->mcan && haseyes(pd) && mdef->mcansee) {
804 if (vis) pline("%s looks %sconfused.",
805 Monnam(mdef), mdef->mconf ? "more " : "");
806 mdef->mconf = 1;
807 }
808 tmp = 0;
809 break;
810 case AD_CURS:
811 if (!night() && (pa == &mons[PM_GREMLIN])) break;
812 if (!magr->mcan && !rn2(10)) {
813 mdef->mcan = 1; /* cancelled regardless of lifesave */
814 if (is_were(pd) && pd->mlet != S_HUMAN)
815 were_change(mdef);
816 if (pd == &mons[PM_CLAY_GOLEM]) {
817 if (vis) {
818 pline("Some writing vanishes from %s head!",
819 s_suffix(mon_nam(mdef)));
820 pline("%s is destroyed!", Monnam(mdef));
821 }
822 mondied(mdef);
823 if (mdef->mhp > 0) return 0;
824 else if (mdef->mtame && !vis)
825 You(brief_feeling, "strangely sad");
826 return (MM_DEF_DIED | (grow_up(magr,mdef) ?
827 0 : MM_AGR_DIED));
828 }
829 if (flags.soundok) {
830 if (!vis) You_hear("laughter.");
831 else pline("%s chuckles.", Monnam(magr));
832 }
833 }
834 break;
835 case AD_SGLD:
836 tmp = 0;
837 if (magr->mcan || !mdef->mgold) break;
838 /* technically incorrect; no check for stealing gold from
839 * between mdef's feet...
840 */
841 magr->mgold += mdef->mgold;
842 mdef->mgold = 0;
843 if (vis) {
844 Strcpy(buf, Monnam(magr));
845 pline("%s steals some gold from %s.", buf, mon_nam(mdef));
846 }
847 if (!tele_restrict(magr)) {
848 rloc(magr);
849 if (vis && !canspotmon(magr))
850 pline("%s suddenly disappears!", buf);
851 }
852 break;
853 case AD_DRLI:
854 if (rn2(2) && !resists_drli(mdef)) {
855 tmp = d(2,6);
856 if (vis)
857 pline("%s suddenly seems weaker!", Monnam(mdef));
858 mdef->mhpmax -= tmp;
859 if (mdef->m_lev == 0)
860 tmp = mdef->mhp;
861 else mdef->m_lev--;
862 /* Automatic kill if drained past level 0 */
863 }
864 break;
865 #ifdef SEDUCE
866 case AD_SSEX:
867 #endif
868 case AD_SITM: /* for now these are the same */
869 case AD_SEDU:
870 if (!magr->mcan && mdef->minvent) {
871 char onambuf[BUFSZ], mdefnambuf[BUFSZ];
872
873 /* make a special x_monnam() call that never omits
874 the saddle, and save it for later messages */
875 Strcpy(mdefnambuf, x_monnam(mdef, ARTICLE_THE, (char *)0, 0, FALSE));
876
877 otmp = mdef->minvent;
878 #ifdef STEED
879 if (u.usteed == mdef &&
880 otmp == which_armor(mdef, W_SADDLE))
881 /* "You can no longer ride <steed>." */
882 dismount_steed(DISMOUNT_POLY);
883 #endif
884 obj_extract_self(otmp);
885 if (otmp->owornmask) {
886 mdef->misc_worn_check &= ~otmp->owornmask;
887 otmp->owornmask = 0L;
888 update_mon_intrinsics(mdef, otmp, FALSE);
889 }
890 /* add_to_minv() might free otmp [if it merges] */
891 if (vis)
892 Strcpy(onambuf, doname(otmp));
893 (void) add_to_minv(magr, otmp);
894 if (vis) {
895 Strcpy(buf, Monnam(magr));
896 pline("%s steals %s from %s!", buf,
897 onambuf, mdefnambuf);
898 }
899 possibly_unwield(mdef);
900 mselftouch(mdef, (const char *)0, FALSE);
901 if (mdef->mhp <= 0)
902 return (MM_DEF_DIED | (grow_up(magr,mdef) ?
903 0 : MM_AGR_DIED));
904 if (magr->data->mlet == S_NYMPH &&
905 !tele_restrict(magr)) {
906 rloc(magr);
907 if (vis && !canspotmon(magr))
908 pline("%s suddenly disappears!", buf);
909 }
910 }
911 tmp = 0;
912 break;
913 case AD_DRST:
914 case AD_DRDX:
915 case AD_DRCO:
916 if (!magr->mcan && !rn2(8)) {
917 if (vis)
918 pline("%s %s was poisoned!", s_suffix(Monnam(magr)),
919 mpoisons_subj(magr, mattk));
920 if (resists_poison(mdef)) {
921 if (vis)
922 pline_The("poison doesn't seem to affect %s.",
923 mon_nam(mdef));
924 } else {
925 if (rn2(10)) tmp += rn1(10,6);
926 else {
927 if (vis) pline_The("poison was deadly...");
928 tmp = mdef->mhp;
929 }
930 }
931 }
932 break;
933 case AD_DRIN:
934 if (notonhead || !has_head(pd)) {
935 if (vis) pline("%s doesn't seem harmed.", Monnam(mdef));
936 tmp = 0;
937 break;
938 }
939 if ((mdef->misc_worn_check & W_ARMH) && rn2(8)) {
940 if (vis) {
941 Strcpy(buf, s_suffix(Monnam(mdef)));
942 pline("%s helmet blocks %s attack to %s head.",
943 buf, s_suffix(mon_nam(magr)),
944 his[pronoun_gender(mdef)]);
945 }
946 break;
947 }
948 if (vis) pline("%s brain is eaten!", s_suffix(Monnam(mdef)));
949 if (mindless(pd)) {
950 if (vis) pline("%s doesn't notice.", Monnam(mdef));
951 break;
952 }
953 tmp += rnd(10); /* fakery, since monsters lack INT scores */
954 if (magr->mtame && !magr->isminion) {
955 EDOG(magr)->hungrytime += rnd(60);
956 magr->mconf = 0;
957 }
958 if (tmp >= mdef->mhp && vis)
959 pline("%s last thought fades away...",
960 s_suffix(Monnam(mdef)));
961 break;
962 case AD_SLIM:
963 if (!rn2(4) && mdef->data != &mons[PM_FIRE_VORTEX] &&
964 mdef->data != &mons[PM_FIRE_ELEMENTAL] &&
965 mdef->data != &mons[PM_GREEN_SLIME]) {
966 if (vis) pline("%s turns into slime.", Monnam(mdef));
967 (void) newcham(mdef, &mons[PM_GREEN_SLIME]);
968 tmp = 0;
969 }
970 break;
971 case AD_STCK:
972 case AD_WRAP: /* monsters cannot grab one another, it's too hard */
973 case AD_ENCH: /* There's no msomearmor() function, so just do damage */
974 break;
975 default: tmp = 0;
976 break;
977 }
978 if(!tmp) return(MM_MISS);
979
980 if((mdef->mhp -= tmp) < 1) {
981 if (m_at(mdef->mx, mdef->my) == magr) { /* see gulpmm() */
982 remove_monster(mdef->mx, mdef->my);
983 mdef->mhp = 1; /* otherwise place_monster will complain */
984 place_monster(mdef, mdef->mx, mdef->my);
985 mdef->mhp = 0;
986 }
987 monkilled(mdef, "", (int)mattk->adtyp);
988 if (mdef->mhp > 0) return 0; /* mdef lifesaved */
989 return (MM_DEF_DIED | (grow_up(magr,mdef) ? 0 : MM_AGR_DIED));
990 }
991 return(MM_HIT);
992 }
993
994 #endif /* OVLB */
995
996
997 #ifdef OVL0
998
999 int
noattacks(ptr)1000 noattacks(ptr) /* returns 1 if monster doesn't attack */
1001 struct permonst *ptr;
1002 {
1003 int i;
1004
1005 for(i = 0; i < NATTK; i++)
1006 if(ptr->mattk[i].aatyp) return(0);
1007
1008 return(1);
1009 }
1010
1011 /* `mon' is hit by a sleep attack; return 1 if it's affected, 0 otherwise */
1012 int
sleep_monst(mon,amt,how)1013 sleep_monst(mon, amt, how)
1014 struct monst *mon;
1015 int amt, how;
1016 {
1017 if (resists_sleep(mon) ||
1018 (how >= 0 && resist(mon, (char)how, 0, NOTELL))) {
1019 shieldeff(mon->mx, mon->my);
1020 } else if (mon->mcanmove) {
1021 amt += (int) mon->mfrozen;
1022 if (amt > 0) { /* sleep for N turns */
1023 mon->mcanmove = 0;
1024 mon->mfrozen = min(amt, 127);
1025 } else { /* sleep until awakened */
1026 mon->msleeping = 1;
1027 }
1028 return 1;
1029 }
1030 return 0;
1031 }
1032
1033 /* sleeping grabber releases, engulfer doesn't; don't use for paralysis! */
1034 void
slept_monst(mon)1035 slept_monst(mon)
1036 struct monst *mon;
1037 {
1038 if ((mon->msleeping || !mon->mcanmove) && mon == u.ustuck &&
1039 !sticks(youmonst.data) && !u.uswallow) {
1040 pline("%s grip relaxes.", s_suffix(Monnam(mon)));
1041 unstuck(mon);
1042 }
1043 }
1044
1045 #endif /* OVL0 */
1046 #ifdef OVLB
1047
1048 STATIC_OVL void
mrustm(magr,mdef,obj)1049 mrustm(magr, mdef, obj)
1050 register struct monst *magr, *mdef;
1051 register struct obj *obj;
1052 {
1053 boolean is_acid;
1054
1055 if (!magr || !mdef || !obj) return; /* just in case */
1056
1057 if (dmgtype(mdef->data, AD_CORRODE))
1058 is_acid = TRUE;
1059 else if (dmgtype(mdef->data, AD_RUST))
1060 is_acid = FALSE;
1061 else
1062 return;
1063
1064 if (!mdef->mcan &&
1065 (is_acid ? is_corrodeable(obj) : is_rustprone(obj)) &&
1066 (is_acid ? obj->oeroded2 : obj->oeroded) < MAX_ERODE) {
1067 if (obj->greased || obj->oerodeproof || (obj->blessed && rn2(3))) {
1068 if (cansee(mdef->mx, mdef->my) && flags.verbose)
1069 pline("%s weapon is not affected.",
1070 s_suffix(Monnam(magr)));
1071 if (obj->greased && !rn2(2)) obj->greased = 0;
1072 } else {
1073 if (cansee(mdef->mx, mdef->my)) {
1074 pline("%s %s%s!", s_suffix(Monnam(magr)),
1075 aobjnam(obj, (is_acid ? "corrode" : "rust")),
1076 (is_acid ? obj->oeroded2 : obj->oeroded)
1077 ? " further" : "");
1078 }
1079 if (is_acid) obj->oeroded2++;
1080 else obj->oeroded++;
1081 }
1082 }
1083 }
1084
1085 STATIC_OVL void
mswingsm(magr,mdef,otemp)1086 mswingsm(magr, mdef, otemp)
1087 register struct monst *magr, *mdef;
1088 register struct obj *otemp;
1089 {
1090 char buf[BUFSZ];
1091 Strcpy(buf, mon_nam(mdef));
1092 if (!flags.verbose || Blind) return;
1093 pline("%s %s %s %s at %s.", Monnam(magr),
1094 (objects[otemp->otyp].oc_dir & PIERCE) ? "thrusts" : "swings",
1095 his[pronoun_gender(magr)], xname(otemp), buf);
1096 }
1097
1098 /*
1099 * Passive responses by defenders. Does not replicate responses already
1100 * handled above. Returns same values as mattackm.
1101 */
1102 STATIC_OVL int
passivemm(magr,mdef,mhit,mdead)1103 passivemm(magr,mdef,mhit,mdead)
1104 register struct monst *magr, *mdef;
1105 boolean mhit;
1106 int mdead;
1107 {
1108 register struct permonst *mddat = mdef->data;
1109 register struct permonst *madat = magr->data;
1110 char buf[BUFSZ];
1111 int i, tmp;
1112
1113 for(i = 0; ; i++) {
1114 if(i >= NATTK) return (mdead | mhit); /* no passive attacks */
1115 if(mddat->mattk[i].aatyp == AT_NONE) break;
1116 }
1117 if (mddat->mattk[i].damn)
1118 tmp = d((int)mddat->mattk[i].damn,
1119 (int)mddat->mattk[i].damd);
1120 else if(mddat->mattk[i].damd)
1121 tmp = d((int)mddat->mlevel+1, (int)mddat->mattk[i].damd);
1122 else
1123 tmp = 0;
1124
1125 /* These affect the enemy even if defender killed */
1126 switch(mddat->mattk[i].adtyp) {
1127 case AD_ACID:
1128 if (mhit && !rn2(2)) {
1129 Strcpy(buf, Monnam(magr));
1130 if(canseemon(magr))
1131 pline("%s is splashed by %s acid!",
1132 buf, s_suffix(mon_nam(mdef)));
1133 if (resists_acid(magr)) {
1134 if(canseemon(magr))
1135 pline("%s is not affected.", Monnam(magr));
1136 tmp = 0;
1137 }
1138 } else tmp = 0;
1139 goto assess_dmg;
1140 case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
1141 if (mhit && !mdef->mcan && otmp) {
1142 (void) drain_item(otmp);
1143 /* No message */
1144 }
1145 break;
1146 default:
1147 break;
1148 }
1149 if (mdead || mdef->mcan) return (mdead|mhit);
1150
1151 /* These affect the enemy only if defender is still alive */
1152 if (rn2(3)) switch(mddat->mattk[i].adtyp) {
1153 case AD_PLYS: /* Floating eye */
1154 if (tmp > 127) tmp = 127;
1155 if (mddat == &mons[PM_FLOATING_EYE]) {
1156 if (!rn2(4)) tmp = 127;
1157 if (magr->mcansee && haseyes(madat) && mdef->mcansee &&
1158 (perceives(madat) || !mdef->minvis)) {
1159 Sprintf(buf, "%s gaze is reflected by %%s %%s.",
1160 s_suffix(mon_nam(mdef)));
1161 if (mon_reflects(magr,
1162 canseemon(magr) ? buf : (char *)0))
1163 return(mdead|mhit);
1164 Strcpy(buf, Monnam(magr));
1165 if(canseemon(magr))
1166 pline("%s is frozen by %s gaze!",
1167 buf, s_suffix(mon_nam(mdef)));
1168 magr->mcanmove = 0;
1169 magr->mfrozen = tmp;
1170 return (mdead|mhit);
1171 }
1172 } else { /* gelatinous cube */
1173 Strcpy(buf, Monnam(magr));
1174 if(canseemon(magr))
1175 pline("%s is frozen by %s.", buf, mon_nam(mdef));
1176 magr->mcanmove = 0;
1177 magr->mfrozen = tmp;
1178 return (mdead|mhit);
1179 }
1180 return 1;
1181 case AD_COLD:
1182 if (resists_cold(magr)) {
1183 if (canseemon(magr)) {
1184 pline("%s is mildly chilly.", Monnam(magr));
1185 golemeffects(magr, AD_COLD, tmp);
1186 }
1187 tmp = 0;
1188 break;
1189 }
1190 if(canseemon(magr))
1191 pline("%s is suddenly very cold!", Monnam(magr));
1192 mdef->mhp += tmp / 2;
1193 if (mdef->mhpmax < mdef->mhp) mdef->mhpmax = mdef->mhp;
1194 if (mdef->mhpmax > ((int) (mdef->m_lev+1) * 8))
1195 (void)split_mon(mdef, magr);
1196 break;
1197 case AD_STUN:
1198 if (!magr->mstun) {
1199 magr->mstun = 1;
1200 if (canseemon(magr))
1201 pline("%s staggers...", Monnam(magr));
1202 }
1203 tmp = 0;
1204 break;
1205 case AD_FIRE:
1206 if (resists_fire(magr)) {
1207 if (canseemon(magr)) {
1208 pline("%s is mildly warmed.", Monnam(magr));
1209 golemeffects(magr, AD_FIRE, tmp);
1210 }
1211 tmp = 0;
1212 break;
1213 }
1214 if(canseemon(magr))
1215 pline("%s is suddenly very hot!", Monnam(magr));
1216 break;
1217 case AD_ELEC:
1218 if (resists_elec(magr)) {
1219 if (canseemon(magr)) {
1220 pline("%s is mildly tingled.", Monnam(magr));
1221 golemeffects(magr, AD_ELEC, tmp);
1222 }
1223 tmp = 0;
1224 break;
1225 }
1226 if(canseemon(magr))
1227 pline("%s is jolted with electricity!", Monnam(magr));
1228 break;
1229 default: tmp = 0;
1230 break;
1231 }
1232 else tmp = 0;
1233
1234 assess_dmg:
1235 if((magr->mhp -= tmp) <= 0) {
1236 monkilled(magr, "", (int)mddat->mattk[i].adtyp);
1237 return (mdead | mhit | MM_AGR_DIED);
1238 }
1239 return (mdead | mhit);
1240 }
1241
1242 #endif /* OVLB */
1243
1244 /*mhitm.c*/
1245
1246