1 /* SCCS Id: @(#)mhitu.c 3.4 2003/11/26 */
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 STATIC_VAR NEARDATA struct obj *otmp;
10
11 STATIC_DCL void FDECL(urustm, (struct monst *, struct obj *));
12 # ifdef OVL1
13 STATIC_DCL boolean FDECL(u_slip_free, (struct monst *,struct attack *));
14 STATIC_DCL int FDECL(passiveum, (struct permonst *,struct monst *,struct attack *));
15 # endif /* OVL1 */
16
17 #ifdef OVLB
18 # ifdef SEDUCE
19 STATIC_DCL void FDECL(mayberem, (struct obj *, const char *));
20 # endif
21 #endif /* OVLB */
22
23 STATIC_DCL boolean FDECL(diseasemu, (struct permonst *));
24 STATIC_DCL int FDECL(hitmu, (struct monst *,struct attack *));
25 STATIC_DCL int FDECL(gulpmu, (struct monst *,struct attack *));
26 STATIC_DCL int FDECL(explmu, (struct monst *,struct attack *,BOOLEAN_P));
27 STATIC_DCL void FDECL(missmu,(struct monst *,int,int,struct attack *));
28 STATIC_DCL void FDECL(mswings,(struct monst *,struct obj *));
29 STATIC_DCL void FDECL(wildmiss, (struct monst *,struct attack *));
30
31 STATIC_DCL void FDECL(hurtarmor,(int));
32 STATIC_DCL void FDECL(hitmsg,(struct monst *,struct attack *));
33
34 /* See comment in mhitm.c. If we use this a lot it probably should be */
35 /* changed to a parameter to mhitu. */
36 static int dieroll;
37
38 #ifdef OVL1
39
40 STATIC_OVL void
hitmsg(mtmp,mattk)41 hitmsg(mtmp, mattk)
42 register struct monst *mtmp;
43 register struct attack *mattk;
44 {
45 int compat;
46
47 /* Note: if opposite gender, "seductively" */
48 /* If same gender, "engagingly" for nymph, normal msg for others */
49 if((compat = could_seduce(mtmp, &youmonst, mattk)) && !mtmp->mcan &&
50 !mtmp->mspec_used) {
51 pline("%s %s you %s.", Monnam(mtmp), Blind ? "talks to" :
52 "smiles at", compat == 2 ? "engagingly" :
53 "seductively");
54 } else switch (mattk->aatyp) {
55 case AT_CLAW:
56 pline("%s claws you!", Monnam(mtmp));
57 break;
58 case AT_BITE:
59 pline("%s bites!", Monnam(mtmp));
60 break;
61 case AT_KICK:
62 pline("%s kicks%c", Monnam(mtmp),
63 thick_skinned(youmonst.data) ? '.' : '!');
64 break;
65 case AT_STNG:
66 pline("%s stings!", Monnam(mtmp));
67 break;
68 case AT_BUTT:
69 pline("%s butts!", Monnam(mtmp));
70 break;
71 case AT_TUCH:
72 pline("%s touches you!", Monnam(mtmp));
73 break;
74 case AT_TENT:
75 pline("%s tentacles suck you!",
76 s_suffix(Monnam(mtmp)));
77 break;
78 case AT_EXPL:
79 case AT_BOOM:
80 pline("%s explodes!", Monnam(mtmp));
81 break;
82 case AT_MULTIPLY:
83 /* No message. */
84 break;
85 default:
86 pline("%s hits!", Monnam(mtmp));
87 }
88 }
89
90
91 STATIC_OVL void
missmu(mtmp,target,roll,mattk)92 missmu(mtmp, target, roll, mattk) /* monster missed you */
93 register struct monst *mtmp;
94 register int target;
95 register int roll;
96 register struct attack *mattk;
97 {
98 register boolean nearmiss = (target == roll);
99 register struct obj *blocker = (struct obj *)0;
100 /* 3 values for blocker
101 * No blocker: (struct obj *) 0
102 * Piece of armour: object
103 * magical: &zeroobj
104 */
105
106 if (target < roll) {
107 /* get object responsible
108 * Work from the closest to the skin outwards
109 */
110 #ifdef TOURIST
111 /* Try undershirt if tourist */
112 if (uarmu && target <= roll) {
113 target += ARM_BONUS(uarmu);
114 if (target > roll) blocker = uarmu;
115 }
116 #endif
117 /* Try body armour */
118 if (uarm && target <= roll) {
119 target += ARM_BONUS(uarm);
120 if (target > roll) blocker = uarm;
121 }
122
123 if (uarmg && !rn2(10)) {
124 /* Try gloves */
125 target += ARM_BONUS(uarmg);
126 if (target > roll) blocker = uarmg;
127 }
128 if (uarmf && !rn2(10)) {
129 /* Try boots */
130 target += ARM_BONUS(uarmf);
131 if (target > roll) blocker = uarmf;
132 }
133 if (uarmh && !rn2(5)) {
134 /* Try helm */
135 target += ARM_BONUS(uarmh);
136 if (target > roll) blocker = uarmh;
137 }
138 if (uarmc && target <= roll) {
139 /* Try cloak */
140 target += ARM_BONUS(uarmc);
141 if (target > roll) blocker = uarmc;
142 }
143 if (uarms && target <= roll) {
144 /* Try shield */
145 target += ARM_BONUS(uarms);
146 if (target > roll) blocker = uarms;
147 }
148 if (target <= roll) {
149 /* Try spell protection */
150 target += u.uspellprot;
151 if (target > roll) blocker = &zeroobj;
152 }
153 }
154
155 if (!canspotmon(mtmp))
156 map_invisible(mtmp->mx, mtmp->my);
157
158 if(could_seduce(mtmp, &youmonst, mattk) && !mtmp->mcan)
159 pline("%s pretends to be friendly.", Monnam(mtmp));
160 else {
161 if (!flags.verbose || !nearmiss && !blocker)
162 pline("%s misses.", Monnam(mtmp));
163 else if (!blocker)
164 pline("%s just misses!", Monnam(mtmp));
165 else if (blocker == &zeroobj)
166 pline("%s is stopped by the golden haze.", Monnam(mtmp));
167 else
168 Your("%s %s%s %s attack.",
169 simple_typename(blocker->otyp),
170 rn2(2) ? "block" : "deflect",
171 (blocker == uarmg || blocker == uarmf) ? "" : "s",
172 s_suffix(mon_nam(mtmp)));
173
174 if (MON_WEP(mtmp)) {
175 struct obj *obj = MON_WEP(mtmp);
176 obj->owornmask &= ~W_WEP;
177 if (rnd(100) < (obj->oeroded * 5 / 2)) {
178 if (obj->spe > -5) {
179 obj->spe--;
180 pline("%s %s is damaged further!",
181 s_suffix(Monnam(mtmp)), xname(obj));
182 } else
183 pline("%s %s is badly battered!",
184 s_suffix(Monnam(mtmp)), xname(obj));
185 }
186 }
187 }
188 stop_occupation();
189 }
190
191 STATIC_OVL void
mswings(mtmp,otemp)192 mswings(mtmp, otemp) /* monster swings obj */
193 register struct monst *mtmp;
194 register struct obj *otemp;
195 {
196 if (!flags.verbose || Blind || !mon_visible(mtmp)) return;
197 pline("%s %s %s %s.", Monnam(mtmp),
198 (objects[otemp->otyp].oc_dir & PIERCE) ? "thrusts" : "swings",
199 mhis(mtmp), singular(otemp, xname));
200 }
201
202 /* return how a poison attack was delivered */
203 const char *
mpoisons_subj(mtmp,mattk)204 mpoisons_subj(mtmp, mattk)
205 struct monst *mtmp;
206 struct attack *mattk;
207 {
208 if (mattk->aatyp == AT_WEAP) {
209 struct obj *mwep = (mtmp == &youmonst) ? uwep : MON_WEP(mtmp);
210 /* "Foo's attack was poisoned." is pretty lame, but at least
211 it's better than "sting" when not a stinging attack... */
212 return (!mwep || !mwep->opoisoned) ? "attack" : "weapon";
213 } else {
214 return (mattk->aatyp == AT_TUCH) ? "contact" :
215 (mattk->aatyp == AT_GAZE) ? "gaze" :
216 (mattk->aatyp == AT_BITE) ? "bite" : "sting";
217 }
218 }
219
220 /* called when your intrinsic speed is taken away */
221 void
u_slow_down()222 u_slow_down()
223 {
224 HFast = 0L;
225 if (!Fast) You("slow down.");
226 /* speed boots */
227 else Your("quickness feels less natural.");
228 exercise(A_DEX, FALSE);
229 }
230
231 #endif /* OVL1 */
232 #ifdef OVLB
233
234 STATIC_OVL void
wildmiss(mtmp,mattk)235 wildmiss(mtmp, mattk) /* monster attacked your displaced image */
236 register struct monst *mtmp;
237 register struct attack *mattk;
238 {
239 int compat;
240
241 /* no map_invisible() -- no way to tell where _this_ is coming from */
242
243 if (!flags.verbose) return;
244 if (!cansee(mtmp->mx, mtmp->my)) return;
245 /* maybe it's attacking an image around the corner? */
246
247 compat = (mattk->adtyp == AD_SEDU || mattk->adtyp == AD_SSEX) &&
248 could_seduce(mtmp, &youmonst, (struct attack *)0);
249
250 if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) {
251 const char *swings =
252 mattk->aatyp == AT_BITE ? "snaps" :
253 mattk->aatyp == AT_KICK ? "kicks" :
254 (mattk->aatyp == AT_STNG ||
255 mattk->aatyp == AT_BUTT ||
256 nolimbs(mtmp->data)) ? "lunges" : "swings";
257
258 if (compat)
259 pline("%s tries to touch you and misses!", Monnam(mtmp));
260 else
261 switch(rn2(3)) {
262 case 0: pline("%s %s wildly and misses!", Monnam(mtmp),
263 swings);
264 break;
265 case 1: pline("%s attacks a spot beside you.", Monnam(mtmp));
266 break;
267 case 2: pline("%s strikes at %s!", Monnam(mtmp),
268 levl[mtmp->mux][mtmp->muy].typ == WATER
269 ? "empty water" : "thin air");
270 break;
271 default:pline("%s %s wildly!", Monnam(mtmp), swings);
272 break;
273 }
274 } else if (Displaced) {
275 if (compat)
276 pline("%s smiles %s at your %sdisplaced image...",
277 Monnam(mtmp),
278 compat == 2 ? "engagingly" : "seductively",
279 Invis ? "invisible " : "");
280 else
281 pline("%s strikes at your %sdisplaced image and misses you!",
282 /* Note: if you're both invisible and displaced,
283 * only monsters which see invisible will attack your
284 * displaced image, since the displaced image is also
285 * invisible.
286 */
287 Monnam(mtmp),Invis ? "invisible " : "");
288
289 } else if (Underwater) {
290 /* monsters may miss especially on water level where
291 bubbles shake the player here and there */
292 if (compat)
293 pline("%s reaches towards your distorted image.",Monnam(mtmp));
294 else
295 pline("%s is fooled by water reflections and misses!",Monnam(mtmp));
296
297 } else impossible("%s attacks you without knowing your location?",
298 Monnam(mtmp));
299 }
300
301 void
expels(mtmp,mdat,message)302 expels(mtmp, mdat, message)
303 register struct monst *mtmp;
304 register struct permonst *mdat; /* if mtmp is polymorphed, mdat != mtmp->data */
305 boolean message;
306 {
307 if (message) {
308 if (is_animal(mdat))
309 You("get regurgitated!");
310 else {
311 char blast[40];
312 register int i;
313
314 blast[0] = '\0';
315 for(i = 0; i < NATTK; i++)
316 if(mdat->mattk[i].aatyp == AT_ENGL)
317 break;
318 if (mdat->mattk[i].aatyp != AT_ENGL)
319 impossible("Swallower has no engulfing attack?");
320 else {
321 if (is_whirly(mdat)) {
322 switch (mdat->mattk[i].adtyp) {
323 case AD_ELEC:
324 Strcpy(blast,
325 " in a shower of sparks");
326 break;
327 case AD_COLD:
328 Strcpy(blast,
329 " in a blast of frost");
330 break;
331 }
332 } else
333 Strcpy(blast, " with a squelch");
334 You("get expelled from %s%s!",mon_nam(mtmp), blast);
335 }
336 }
337 }
338 unstuck(mtmp); /* ball&chain returned in unstuck() */
339 mnexto(mtmp);
340 newsym(u.ux,u.uy);
341 spoteffects(TRUE);
342 /* to cover for a case where mtmp is not in a next square */
343 if(um_dist(mtmp->mx,mtmp->my,1))
344 pline("Brrooaa... You land hard at some distance.");
345 }
346
347 #endif /* OVLB */
348 #ifdef OVL0
349
350 /* select a monster's next attack, possibly substituting for its usual one */
351 struct attack *
getmattk(mptr,indx,prev_result,alt_attk_buf)352 getmattk(mptr, indx, prev_result, alt_attk_buf)
353 struct permonst *mptr;
354 int indx, prev_result[];
355 struct attack *alt_attk_buf;
356 {
357 struct attack *attk = &mptr->mattk[indx];
358
359 /* prevent a monster with two consecutive disease or hunger attacks
360 from hitting with both of them on the same turn; if the first has
361 already hit, switch to a stun attack for the second */
362 if (indx > 0 && prev_result[indx - 1] > 0 &&
363 (attk->adtyp == AD_DISE ||
364 attk->adtyp == AD_PEST ||
365 attk->adtyp == AD_FAMN) &&
366 attk->adtyp == mptr->mattk[indx - 1].adtyp) {
367 *alt_attk_buf = *attk;
368 attk = alt_attk_buf;
369 attk->adtyp = AD_STUN;
370 }
371 return attk;
372 }
373
374 /* Intelligent monsters try and avoid "blue on blue" incidents.
375 */
376 STATIC_OVL int
blue_on_blue(mtmp)377 blue_on_blue(mtmp)
378 struct monst *mtmp;
379 {
380 int x, y;
381 struct monst *mon;
382 if (!mtmp->mconf && !Conflict && !mtmp->mflee && !mindless(mtmp->data)) {
383 if (!lined_up(mtmp))
384 return FALSE; /* Irrelevant; monster won't attack anyway */
385 x = mtmp->mx + sgn(tbx);
386 y = mtmp->my + sgn(tby);
387 while(x != mtmp->mux || y != mtmp->muy) {
388 mon = m_at(x, y);
389 if (mon && m_cansee(mtmp, x, y) && !mon->mundetected &&
390 (!mon->minvis || perceives(mtmp->data)))
391 return TRUE;
392 x += sgn(tbx);
393 y += sgn(tby);
394 }
395 }
396 return FALSE;
397 }
398
399 /*
400 * mattacku: monster attacks you
401 * returns 1 if monster dies (e.g. "yellow light"), 0 otherwise
402 * Note: if you're displaced or invisible the monster might attack the
403 * wrong position...
404 * Assumption: it's attacking you or an empty square; if there's another
405 * monster which it attacks by mistake, the caller had better
406 * take care of it...
407 */
408 int
mattacku(mtmp)409 mattacku(mtmp)
410 register struct monst *mtmp;
411 {
412 struct attack *mattk, alt_attk;
413 int i, j, tmp, sum[NATTK];
414 struct permonst *mdat = mtmp->data;
415 boolean ranged = (distu(mtmp->mx, mtmp->my) > 3);
416 /* Is it near you? Affects your actions */
417 boolean range2 = !monnear(mtmp, mtmp->mux, mtmp->muy);
418 /* Does it think it's near you? Affects its actions */
419 boolean foundyou = (mtmp->mux==u.ux && mtmp->muy==u.uy);
420 /* Is it attacking you or your image? */
421 boolean youseeit = canseemon(mtmp);
422 /* Might be attacking your image around the corner, or
423 * invisible, or you might be blind....
424 */
425
426 if(!ranged) nomul(0);
427 if(mtmp->mhp <= 0 || (Underwater && !is_swimmer(mtmp->data)))
428 return(0);
429
430 /* If swallowed, can only be affected by u.ustuck */
431 if(u.uswallow) {
432 if(mtmp != u.ustuck) return(0);
433 u.ustuck->mux = u.ux;
434 u.ustuck->muy = u.uy;
435 range2 = 0;
436 foundyou = 1;
437 if(u.uinvulnerable) return (0); /* stomachs can't hurt you! */
438 }
439
440 #ifdef STEED
441 else if (u.usteed) {
442 if (mtmp == u.usteed)
443 /* Your steed won't attack you */
444 return (0);
445 /* Orcs like to steal and eat horses and the like */
446 if (!rn2(is_orc(mtmp->data) ? 2 : 4) &&
447 distu(mtmp->mx, mtmp->my) <= 2) {
448 /* Attack your steed instead */
449 i = mattackm(mtmp, u.usteed);
450 if ((i & MM_AGR_DIED))
451 return (1);
452 if (i & MM_DEF_DIED || u.umoved)
453 return (0);
454 /* Let your steed retaliate */
455 return (!!(mattackm(u.usteed, mtmp) & MM_DEF_DIED));
456 }
457 }
458 #endif
459
460 if (u.uundetected && !range2 && foundyou && !u.uswallow) {
461 u.uundetected = 0;
462 if (is_hider(youmonst.data)) {
463 coord cc; /* maybe we need a unexto() function? */
464 struct obj *obj;
465
466 You("fall from the %s!", ceiling(u.ux,u.uy));
467 if (enexto(&cc, u.ux, u.uy, youmonst.data)) {
468 remove_monster(mtmp->mx, mtmp->my);
469 newsym(mtmp->mx,mtmp->my);
470 place_monster(mtmp, u.ux, u.uy);
471 if(mtmp->wormno) worm_move(mtmp);
472 teleds(cc.x, cc.y, TRUE);
473 set_apparxy(mtmp);
474 newsym(u.ux,u.uy);
475 } else {
476 pline("%s is killed by a falling %s (you)!",
477 Monnam(mtmp), youmonst.data->mname);
478 killed(mtmp);
479 newsym(u.ux,u.uy);
480 if (mtmp->mhp > 0) return 0;
481 else return 1;
482 }
483 if (youmonst.data->mlet != S_PIERCER)
484 return(0); /* trappers don't attack */
485
486 obj = which_armor(mtmp, WORN_HELMET);
487 if (obj && is_metallic(obj)) {
488 Your("blow glances off %s helmet.",
489 s_suffix(mon_nam(mtmp)));
490 } else {
491 if (3 + find_mac(mtmp) <= rnd(20)) {
492 pline("%s is hit by a falling piercer (you)!",
493 Monnam(mtmp));
494 if ((mtmp->mhp -= d(3,6)) < 1)
495 killed(mtmp);
496 } else
497 pline("%s is almost hit by a falling piercer (you)!",
498 Monnam(mtmp));
499 }
500 } else {
501 if (!youseeit)
502 pline("It tries to move where you are hiding.");
503 else {
504 /* Ugly kludge for eggs. The message is phrased so as
505 * to be directed at the monster, not the player,
506 * which makes "laid by you" wrong. For the
507 * parallelism to work, we can't rephrase it, so we
508 * zap the "laid by you" momentarily instead.
509 */
510 struct obj *obj = level.objects[u.ux][u.uy];
511
512 if (obj ||
513 (youmonst.data->mlet == S_EEL && is_pool(u.ux, u.uy))) {
514 int save_spe = 0; /* suppress warning */
515 if (obj) {
516 save_spe = obj->spe;
517 if (obj->otyp == EGG) obj->spe = 0;
518 }
519 if (youmonst.data->mlet == S_EEL)
520 pline("Wait, %s! There's a hidden %s named %s there!",
521 m_monnam(mtmp), youmonst.data->mname, plname);
522 else
523 pline("Wait, %s! There's a %s named %s hiding under %s!",
524 m_monnam(mtmp), youmonst.data->mname, plname,
525 doname(level.objects[u.ux][u.uy]));
526 if (obj) obj->spe = save_spe;
527 } else
528 impossible("hiding under nothing?");
529 }
530 newsym(u.ux,u.uy);
531 }
532 return(0);
533 }
534 if (youmonst.data->mlet == S_MIMIC && youmonst.m_ap_type &&
535 !range2 && foundyou && !u.uswallow) {
536 if (!youseeit) pline("It gets stuck on you.");
537 else pline("Wait, %s! That's a %s named %s!",
538 m_monnam(mtmp), youmonst.data->mname, plname);
539 setustuck(mtmp);
540 youmonst.m_ap_type = M_AP_NOTHING;
541 youmonst.mappearance = 0;
542 newsym(u.ux,u.uy);
543 return(0);
544 }
545
546 /* player might be mimicking an object */
547 if (youmonst.m_ap_type == M_AP_OBJECT && !range2 && foundyou && !u.uswallow) {
548 if (!youseeit)
549 pline("%s %s!", Something,
550 (likes_gold(mtmp->data) && youmonst.mappearance == GOLD_PIECE) ?
551 "tries to pick you up" : "disturbs you");
552 else pline("Wait, %s! That %s is really %s named %s!",
553 m_monnam(mtmp),
554 mimic_obj_name(&youmonst),
555 an(mons[u.umonnum].mname),
556 plname);
557 if (multi < 0) { /* this should always be the case */
558 char buf[BUFSZ];
559 Sprintf(buf, "You appear to be %s again.",
560 Upolyd ? (const char *) an(youmonst.data->mname) :
561 (const char *) "yourself");
562 unmul(buf); /* immediately stop mimicking */
563 }
564 return 0;
565 }
566
567 /* Work out the armor class differential */
568 tmp = AC_VALUE(u.uac) + 10; /* tmp ~= 0 - 20 */
569 tmp += mtmp->m_lev;
570 if(multi < 0) tmp += 4;
571 if((Invis && !perceives(mdat)) || !mtmp->mcansee) tmp -= 2;
572 if(mtmp->mtrapped) tmp -= 2;
573 if(tmp <= 0) tmp = 1;
574
575 /* make eels visible the moment they hit/miss us */
576 if(mdat->mlet == S_EEL && mtmp->minvis && cansee(mtmp->mx,mtmp->my)) {
577 mtmp->minvis = 0;
578 newsym(mtmp->mx,mtmp->my);
579 }
580
581 /* Make Star Vampires visible the moment they hit/miss us */
582 if(mtmp->data == &mons[PM_STAR_VAMPIRE] && mtmp->minvis
583 && cansee(mtmp->mx, mtmp->my)) {
584 mtmp->minvis = 0;
585 newsym(mtmp->mx, mtmp->my);
586 }
587
588 /* Special demon handling code */
589 if(!mtmp->cham && is_demon(mdat) && !range2
590 && mtmp->data != &mons[PM_BALROG]
591 && mtmp->data != &mons[PM_SUCCUBUS]
592 && mtmp->data != &mons[PM_INCUBUS])
593 if(!mtmp->mcan && !rn2(13)) msummon(mtmp);
594
595 /* Special lycanthrope handling code */
596 if(!mtmp->cham && is_were(mdat) && !range2) {
597 if(is_human(mdat)) {
598 if(!rn2(5 - (night() * 2)) && !mtmp->mcan) new_were(mtmp);
599 } else if(!rn2(30) && !mtmp->mcan) new_were(mtmp);
600 mdat = mtmp->data;
601
602 if(!rn2(4) && !mtmp->mcan) {
603 int numseen, numhelp;
604 char buf[BUFSZ], genericwere[BUFSZ];
605
606 Strcpy(genericwere, "creature");
607 numhelp = were_summon(mdat, FALSE, &numseen, genericwere);
608 if (youseeit) {
609 pline("%s summons help!", Monnam(mtmp));
610 if (numhelp > 0) {
611 if (numseen == 0)
612 You_feel("hemmed in.");
613 } else pline("But none comes.");
614 } else {
615 const char *from_nowhere;
616
617 if (flags.soundok) {
618 pline("%s %s!", Something,
619 makeplural(growl_sound(mtmp)));
620 from_nowhere = "";
621 } else from_nowhere = " from nowhere";
622 if (numhelp > 0) {
623 if (numseen < 1) You_feel("hemmed in.");
624 else {
625 if (numseen == 1)
626 Sprintf(buf, "%s appears",
627 an(genericwere));
628 else
629 Sprintf(buf, "%s appear",
630 makeplural(genericwere));
631 pline("%s%s!", upstart(buf), from_nowhere);
632 }
633 } /* else no help came; but you didn't know it tried */
634 }
635 }
636 }
637
638 if(u.uinvulnerable) {
639 /* monsters won't attack you */
640 if(mtmp == u.ustuck)
641 pline("%s loosens its grip slightly.", Monnam(mtmp));
642 else if(!range2) {
643 if (youseeit || sensemon(mtmp))
644 pline("%s starts to attack you, but pulls back.",
645 Monnam(mtmp));
646 else
647 You_feel("%s move nearby.", something);
648 }
649 return (0);
650 }
651
652 /* Unlike defensive stuff, don't let them use item _and_ attack. */
653 if(!blue_on_blue(mtmp) && find_offensive(mtmp)) {
654 int foo = use_offensive(mtmp);
655
656 if (foo != 0) return(foo==1);
657 }
658
659 for(i = 0; i < NATTK; i++) {
660
661 sum[i] = 0;
662 mattk = getmattk(mdat, i, sum, &alt_attk);
663 if (u.uswallow && (mattk->aatyp != AT_ENGL))
664 continue;
665 switch(mattk->aatyp) {
666 case AT_CLAW: /* "hand to hand" attacks */
667 case AT_KICK:
668 case AT_BITE:
669 case AT_STNG:
670 case AT_TUCH:
671 case AT_BUTT:
672 case AT_TENT:
673 if(!range2 && (!MON_WEP(mtmp) || mtmp->mconf || Conflict ||
674 !touch_petrifies(youmonst.data))) {
675 if (foundyou) {
676 if(tmp > (j = rnd(20+i))) {
677 if (mattk->aatyp != AT_KICK ||
678 !thick_skinned(youmonst.data))
679 sum[i] = hitmu(mtmp, mattk);
680 } else
681 missmu(mtmp, tmp, j, mattk);
682 } else wildmiss(mtmp, mattk);
683 }
684 break;
685 case AT_HUGS: /* automatic if prev two attacks succeed */
686 /* Note: if displaced, prev attacks never succeeded */
687 if((!range2 && i>=2 && sum[i-1] && sum[i-2]) || mtmp == u.ustuck)
688 sum[i]= hitmu(mtmp, mattk);
689 break;
690 case AT_GAZE: /* can affect you either ranged or not */
691 /* Medusa gaze already operated through m_respond in
692 * dochug(); don't gaze more than once per round.
693 */
694 if (mdat != &mons[PM_MEDUSA])
695 sum[i] = gazemu(mtmp, mattk);
696 break;
697 case AT_EXPL: /* automatic hit if next to, and aimed at you */
698 if(!range2) sum[i] = explmu(mtmp, mattk, foundyou);
699 break;
700 case AT_ENGL:
701 if (!range2) {
702 if(foundyou) {
703 if(u.uswallow || tmp > (j = rnd(20+i))) {
704 /* Force swallowing monster to be
705 * displayed even when player is
706 * moving away */
707 flush_screen(1);
708 sum[i] = gulpmu(mtmp, mattk);
709 } else {
710 missmu(mtmp, tmp, j, mattk);
711 }
712 } else if (is_animal(mtmp->data)) {
713 pline("%s gulps some air!", Monnam(mtmp));
714 } else {
715 if (youseeit)
716 pline("%s lunges forward and recoils!",
717 Monnam(mtmp));
718 else
719 You_hear("a %s nearby.",
720 is_whirly(mtmp->data) ?
721 "rushing noise" : "splat");
722 }
723 }
724 break;
725 case AT_BREA:
726 if (range2 && !blue_on_blue(mtmp))
727 sum[i] = breamu(mtmp, mattk);
728 /* Note: breamu takes care of displacement */
729 break;
730 case AT_SPIT:
731 if (range2 && !blue_on_blue(mtmp))
732 sum[i] = spitmu(mtmp, mattk);
733 /* Note: spitmu takes care of displacement */
734 break;
735 case AT_MULTIPLY:
736 /*
737 * Monster multiplying is an AT_ for the following
738 * reasons:
739 * 1. Monsters will only multiply when they're close
740 * to you. The whole level will not become clogged
741 * up with giant lice from monsters multiplying
742 * where you can't see them.
743 * 2. Tame monsters won't multiply. Too bad! (unless
744 * they are conflicted or confused from hunger.
745 * A bit of a "tactic" -- but then you'll have to
746 * let them bite you, and anyway who really wants
747 * a dozen pet fleas to feed?)
748 * 3. Monsters have to be next to you to multiply.
749 * This makes the inevitable altar abuse a little
750 * harder.
751 * 4. Elbereth will stop monsters multiplying.
752 * Otherwise a ring of conflict would crowd out a
753 * whole level in no time.
754 * 5. It is a hack. (Shrug)
755 *
756 * Multiplying monsters must be low-level and
757 * low-frequency, so as to minimise altar/experience
758 * abuse. Any multiplying monsters above about
759 * level 5 should be G_NOCORPSE.
760 *
761 * RJ
762 */
763 if (!range2)
764 clone_mon(mtmp, 0, 0);
765 break;
766 case AT_WEAP:
767 if(range2) {
768 #ifdef REINCARNATION
769 if (!Is_rogue_level(&u.uz))
770 #endif
771 if (!blue_on_blue(mtmp))
772 thrwmu(mtmp);
773 } else {
774 int hittmp = 0;
775
776 /* Rare but not impossible. Normally the monster
777 * wields when 2 spaces away, but it can be
778 * teleported or whatever....
779 */
780 if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
781 mtmp->weapon_check = NEED_HTH_WEAPON;
782 /* mon_wield_item resets weapon_check as
783 * appropriate */
784 if (mon_wield_item(mtmp) != 0) break;
785 }
786 if (foundyou) {
787 otmp = MON_WEP(mtmp);
788 if (otmp) {
789 hittmp = hitval(otmp, &youmonst);
790 tmp += hittmp;
791 mswings(mtmp, otmp);
792 }
793 if(tmp > (j = dieroll = rnd(20+i)))
794 sum[i] = hitmu(mtmp, mattk);
795 else
796 missmu(mtmp, tmp , j, mattk);
797 /* KMH -- Don't accumulate to-hit bonuses */
798 if (otmp)
799 tmp -= hittmp;
800 } else wildmiss(mtmp, mattk);
801 }
802 break;
803 case AT_MAGC:
804 if (range2) {
805 if (!blue_on_blue(mtmp))
806 sum[i] = buzzmu(mtmp, mattk);
807 } else {
808 if (foundyou)
809 sum[i] = castmu(mtmp, mattk, TRUE, TRUE);
810 else
811 sum[i] = castmu(mtmp, mattk, TRUE, FALSE);
812 }
813 break;
814
815 default: /* no attack */
816 break;
817 }
818 if(flags.botl) bot();
819 /* give player a chance of waking up before dying -kaa */
820 if(sum[i] == 1) { /* successful attack */
821 if (u.usleep && u.usleep < monstermoves && !rn2(10)) {
822 multi = -1;
823 nomovemsg = "The combat suddenly awakens you.";
824 }
825 }
826 if(sum[i] == 2) return 1; /* attacker dead */
827 if(sum[i] == 3) break; /* attacker teleported, no more attacks */
828 /* sum[i] == 0: unsuccessful attack */
829 }
830 return(0);
831 }
832
833 #endif /* OVL0 */
834 #ifdef OVLB
835
836 /*
837 * helper function for some compilers that have trouble with hitmu
838 */
839
840 STATIC_OVL void
hurtarmor(attk)841 hurtarmor(attk)
842 int attk;
843 {
844 int hurt;
845
846 switch(attk) {
847 /* 0 is burning, which we should never be called with */
848 case AD_RUST: hurt = 1; break;
849 case AD_CORR: hurt = 3; break;
850 default: hurt = 2; break;
851 }
852
853 /* What the following code does: it keeps looping until it
854 * finds a target for the rust monster.
855 * Head, feet, etc... not covered by metal, or covered by
856 * rusty metal, are not targets. However, your body always
857 * is, no matter what covers it.
858 *
859 * WAC fixed code so that it keeps looping until it either hits
860 * your body or finds a rustable item
861 * changed the last parm of !rust_dmg for non-body targets to FALSE
862 */
863 while (1) {
864 switch(rn2(5)) {
865 case 0:
866 if (!uarmh || !rust_dmg(uarmh, xname(uarmh), hurt, FALSE, &youmonst))
867 continue;
868 break;
869 case 1:
870 if (uarmc) {
871 (void)rust_dmg(uarmc, xname(uarmc), hurt, TRUE, &youmonst);
872 break;
873 }
874 /* Note the difference between break and continue;
875 * break means it was hit and didn't rust; continue
876 * means it wasn't a target and though it didn't rust
877 * something else did.
878 */
879 if (uarm)
880 (void)rust_dmg(uarm, xname(uarm), hurt, TRUE, &youmonst);
881 #ifdef TOURIST
882 else if (uarmu)
883 (void)rust_dmg(uarmu, xname(uarmu), hurt, TRUE, &youmonst);
884 #endif
885 break;
886 case 2:
887 if (!uarms || !rust_dmg(uarms, xname(uarms), hurt, FALSE, &youmonst))
888 continue;
889 break;
890 case 3:
891 if (!uarmg || !rust_dmg(uarmg, xname(uarmg), hurt, FALSE, &youmonst))
892 continue;
893 break;
894 case 4:
895 if (!uarmf || !rust_dmg(uarmf, xname(uarmf), hurt, FALSE, &youmonst))
896 continue;
897 break;
898 }
899
900 break; /* Out of while loop */
901 }
902 }
903
904 #endif /* OVLB */
905 #ifdef OVL1
906
907 STATIC_OVL boolean
diseasemu(mdat)908 diseasemu(mdat)
909 struct permonst *mdat;
910 {
911 if (Sick_resistance) {
912 You_feel("a slight illness.");
913 return FALSE;
914 } else {
915 make_sick(Sick ? Sick/3L + 1L : (long)rn1(ACURR(A_CON), 20),
916 mdat->mname, TRUE, SICK_NONVOMITABLE);
917 return TRUE;
918 }
919 }
920
921 /* check whether slippery clothing protects from hug or wrap attack */
922 STATIC_OVL boolean
u_slip_free(mtmp,mattk)923 u_slip_free(mtmp, mattk)
924 struct monst *mtmp;
925 struct attack *mattk;
926 {
927 struct obj *obj = (uarmc ? uarmc : uarm);
928
929 #ifdef TOURIST
930 if (!obj) obj = uarmu;
931 #endif
932 if (mattk->adtyp == AD_DRIN) obj = uarmh;
933
934 /* if your cloak/armor is greased, monster slips off; this
935 protection might fail (33% chance) when the armor is cursed */
936 if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK) &&
937 (!obj->cursed || rn2(3))) {
938 pline("%s %s your %s %s!",
939 Monnam(mtmp),
940 (mattk->adtyp == AD_WRAP) ?
941 "slips off of" : "grabs you, but cannot hold onto",
942 obj->greased ? "greased" : "slippery",
943 /* avoid "slippery slippery cloak"
944 for undiscovered oilskin cloak */
945 (obj->greased || objects[obj->otyp].oc_name_known) ?
946 xname(obj) : cloak_simple_name(obj));
947
948 if (obj->greased && !rn2(2)) {
949 pline_The("grease wears off.");
950 obj->greased = 0;
951 update_inventory();
952 }
953 return TRUE;
954 /* 50% chance (with a luck bonus) of slipping free with free action */
955 } else if (Free_action && (rnl(10) < 5)) {
956 pline("%s %s you, but you quickly free yourself!",
957 Monnam(mtmp),
958 (mattk->adtyp == AD_WRAP) ?
959 "swings itself around of" : "grabs");
960 return TRUE;
961 }
962 return FALSE;
963 }
964
965 /* armor that sufficiently covers the body might be able to block magic */
966 int
magic_negation(mon)967 magic_negation(mon)
968 struct monst *mon;
969 {
970 struct obj *armor;
971 int armpro = 0;
972
973 armor = (mon == &youmonst) ? uarm : which_armor(mon, W_ARM);
974 if (armor && armpro < objects[armor->otyp].a_can)
975 armpro = objects[armor->otyp].a_can;
976 armor = (mon == &youmonst) ? uarmc : which_armor(mon, W_ARMC);
977 if (armor && armpro < objects[armor->otyp].a_can)
978 armpro = objects[armor->otyp].a_can;
979 armor = (mon == &youmonst) ? uarmh : which_armor(mon, W_ARMH);
980 if (armor && armpro < objects[armor->otyp].a_can)
981 armpro = objects[armor->otyp].a_can;
982
983 /* armor types for shirt, gloves, shoes, and shield don't currently
984 provide any magic cancellation but we might as well be complete */
985 #ifdef TOURIST
986 armor = (mon == &youmonst) ? uarmu : which_armor(mon, W_ARMU);
987 if (armor && armpro < objects[armor->otyp].a_can)
988 armpro = objects[armor->otyp].a_can;
989 #endif
990 armor = (mon == &youmonst) ? uarmg : which_armor(mon, W_ARMG);
991 if (armor && armpro < objects[armor->otyp].a_can)
992 armpro = objects[armor->otyp].a_can;
993 armor = (mon == &youmonst) ? uarmf : which_armor(mon, W_ARMF);
994 if (armor && armpro < objects[armor->otyp].a_can)
995 armpro = objects[armor->otyp].a_can;
996 armor = (mon == &youmonst) ? uarms : which_armor(mon, W_ARMS);
997 if (armor && armpro < objects[armor->otyp].a_can)
998 armpro = objects[armor->otyp].a_can;
999
1000 #ifdef STEED
1001 /* this one is really a stretch... */
1002 armor = (mon == &youmonst) ? 0 : which_armor(mon, W_SADDLE);
1003 if (armor && armpro < objects[armor->otyp].a_can)
1004 armpro = objects[armor->otyp].a_can;
1005 #endif
1006
1007 return armpro;
1008 }
1009
1010 /*
1011 * hitmu: monster hits you
1012 * returns 2 if monster dies (e.g. "yellow light"), 1 otherwise
1013 * 3 if the monster lives but teleported/paralyzed, so it can't keep
1014 * attacking you
1015 */
1016 STATIC_OVL int
hitmu(mtmp,mattk)1017 hitmu(mtmp, mattk)
1018 register struct monst *mtmp;
1019 register struct attack *mattk;
1020 {
1021 register struct permonst *mdat = mtmp->data;
1022 register int uncancelled, ptmp;
1023 int dmg, armpro, permdmg;
1024 char buf[BUFSZ];
1025 struct permonst *olduasmon = youmonst.data;
1026 int res;
1027 boolean burnmsg = FALSE;
1028
1029 if (!canspotmon(mtmp))
1030 map_invisible(mtmp->mx, mtmp->my);
1031
1032 /* If the monster is undetected & hits you, you should know where
1033 * the attack came from.
1034 */
1035 if(mtmp->mundetected && (hides_under(mdat) || mdat->mlet == S_EEL)) {
1036 mtmp->mundetected = 0;
1037 if (!(Blind ? Blind_telepat : Unblind_telepat)) {
1038 struct obj *obj;
1039 const char *what;
1040
1041 if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0) {
1042 if (Blind && !obj->dknown)
1043 what = something;
1044 else if (is_pool(mtmp->mx, mtmp->my) && !Underwater)
1045 what = "the water";
1046 else
1047 what = doname(obj);
1048
1049 pline("%s was hidden under %s!", Amonnam(mtmp), what);
1050 }
1051 newsym(mtmp->mx, mtmp->my);
1052 }
1053 }
1054
1055 /* First determine the base damage done */
1056 dmg = d((int)mattk->damn, (int)mattk->damd);
1057 if(is_undead(mdat) && midnight())
1058 dmg += d((int)mattk->damn, (int)mattk->damd); /* extra damage */
1059 /* Next a cancellation factor */
1060
1061 /* Use uncancelled when the cancellation factor takes into account certain
1062 * armor's special magic protection. Otherwise just use !mtmp->mcan.
1063 */
1064 armpro = magic_negation(&youmonst);
1065 uncancelled = !mtmp->mcan && ((rn2(3) >= armpro) || !rn2(50));
1066
1067 permdmg = 0;
1068 /* Now, adjust damages via resistances or specific attacks */
1069 switch(mattk->adtyp) {
1070 case AD_PHYS:
1071 if (mattk->aatyp == AT_HUGS && !sticks(youmonst.data)) {
1072 if(!u.ustuck && rn2(2)) {
1073 if (u_slip_free(mtmp, mattk)) {
1074 dmg = 0;
1075 } else {
1076 setustuck(mtmp);
1077 pline("%s grabs you!", Monnam(mtmp));
1078 }
1079 } else if(u.ustuck == mtmp) {
1080 exercise(A_STR, FALSE);
1081 if (mtmp->data == &mons[PM_ROPE_GOLEM] && Breathless) {
1082 You("are being strangled.");
1083 dmg = (dmg+1) / 2;
1084 } else
1085 You("are being %s.",
1086 (mtmp->data == &mons[PM_ROPE_GOLEM])
1087 ? "choked" : "crushed");
1088 }
1089 } else { /* hand to hand weapon */
1090 if(mattk->aatyp == AT_WEAP && otmp) {
1091 int nopoison = (10 - (otmp->owt/10));
1092 if (otmp->otyp == CORPSE &&
1093 touch_petrifies(&mons[otmp->corpsenm])) {
1094 dmg = 1;
1095 pline("%s hits you with the %s corpse.",
1096 Monnam(mtmp), mons[otmp->corpsenm].mname);
1097 if (!Stoned) goto do_stone;
1098 }
1099
1100 /* MRKR: If hit with a burning torch, */
1101 /* then do an extra point of damage */
1102 /* but save the message till after */
1103 /* the hitmsg() */
1104
1105 if (otmp->otyp == TORCH && otmp->lamplit &&
1106 !Fire_resistance) {
1107 burnmsg = TRUE;
1108 dmg++;
1109 }
1110
1111 /* WAC -- Real weapon?
1112 * Could be stuck with a cursed bow/polearm it wielded
1113 */
1114 if (/* if you strike with a bow... */
1115 is_launcher(otmp) ||
1116 /* or strike with a missile in your hand... */
1117 (is_missile(otmp) || is_ammo(otmp)) ||
1118 #ifdef LIGHTSABERS
1119 /* lightsaber that isn't lit ;) */
1120 (is_lightsaber(otmp) && !otmp->lamplit) ||
1121 #endif
1122 /* WAC -- or using a pole at short range... */
1123 (is_pole(otmp))) {
1124 /* then do only 1-2 points of damage */
1125 if (u.umonnum == PM_SHADE && otmp->otyp != SILVER_ARROW)
1126 dmg = 0;
1127 else
1128 dmg = rnd(2);
1129
1130 #if 0 /* Monsters don't wield boomerangs */
1131 if (otmp->otyp == BOOMERANG /* && !rnl(3) */) {
1132 pline("As %s hits you, %s breaks into splinters.",
1133 mon_nam(mtmp), the(xname(otmp)));
1134 useup(otmp);
1135 otmp = (struct obj *) 0;
1136 possibly_unwield(mtmp);
1137 if (u.umonnum != PM_SHADE)
1138 dmg++;
1139 }
1140 #endif
1141 } else dmg += dmgval(otmp, &youmonst);
1142
1143 if (objects[otmp->otyp].oc_material == SILVER &&
1144 hates_silver(youmonst.data)) {
1145 pline("The silver sears your flesh!");
1146 }
1147 /* Stakes do extra dmg agains vamps */
1148 if (otmp->otyp == WOODEN_STAKE &&
1149 is_vampire(youmonst.data)) {
1150 if (otmp->oartifact == ART_STAKE_OF_VAN_HELSING) {
1151 if (!rn2(10)) {
1152 pline("%s plunges the stake into your heart.",
1153 Monnam(mtmp));
1154 killer = "a wooden stake in the heart.";
1155 killer_format = KILLED_BY_AN;
1156 u.ugrave_arise = NON_PM; /* No corpse */
1157 done(DIED);
1158 } else {
1159 pline("%s drives the stake into you.",
1160 Monnam(mtmp));
1161 dmg += rnd(6) + 2;
1162 }
1163 } else {
1164 pline("%s drives the stake into you.",
1165 Monnam(mtmp));
1166 dmg += rnd(6);
1167 }
1168 }
1169
1170 if (otmp->opoisoned) {
1171 poisoned(simple_typename(otmp->otyp), A_STR,
1172 killer_xname(otmp), 10);
1173 if (nopoison < 2) nopoison = 2;
1174 if (!rn2(nopoison)) {
1175 otmp->opoisoned = FALSE;
1176 pline("%s %s no longer poisoned.",
1177 s_suffix(Monnam(mtmp)),
1178 aobjnam(otmp, "are"));
1179 }
1180 }
1181 if (dmg <= 0) dmg = 1;
1182 if (!otmp->oartifact || !artifact_hit(mtmp, &youmonst,
1183 otmp, &dmg, dieroll))
1184 hitmsg(mtmp, mattk);
1185
1186 if (burnmsg) {
1187 boolean plural = (Blind ? FALSE : otmp->quan > 1L);
1188 boolean water = (youmonst.data ==
1189 &mons[PM_WATER_ELEMENTAL]);
1190
1191 pline("%s %s%s %syou!",
1192 (Blind ? "It" : Yname2(otmp)),
1193 (water ? "vaporize" : "burn"),
1194 (plural ? "" : "s"),
1195 (water ? "part of " : ""));
1196
1197 if (!rn2(2) && burnarmor(&youmonst)) {
1198 dmg++;
1199
1200 /* Torch flame is not hot enough to guarantee */
1201 /* burning away slime */
1202
1203 if (!rn2(4)) burn_away_slime();
1204 if (!rn2(3))
1205 (void)destroy_item(POTION_CLASS, AD_FIRE);
1206 if (!rn2(3))
1207 (void)destroy_item(SCROLL_CLASS, AD_FIRE);
1208 if (!rn2(5))
1209 (void)destroy_item(SPBOOK_CLASS, AD_FIRE);
1210 }
1211 burn_faster(otmp, 1);
1212 }
1213
1214 if (!dmg) break;
1215 if (u.mh > 1 && u.mh > ((u.uac>0) ? dmg : dmg+u.uac) &&
1216 objects[otmp->otyp].oc_material == IRON &&
1217 (u.umonnum==PM_BLACK_PUDDING
1218 || u.umonnum==PM_BROWN_PUDDING)) {
1219 /* This redundancy necessary because you have to
1220 * take the damage _before_ being cloned.
1221 */
1222 if (u.uac < 0) dmg += u.uac;
1223 if (dmg < 1) dmg = 1;
1224 if (dmg > 1) exercise(A_STR, FALSE);
1225 u.mh -= dmg;
1226 flags.botl = 1;
1227 dmg = 0;
1228 if(cloneu())
1229 You("divide as %s hits you!",mon_nam(mtmp));
1230 }
1231 urustm(mtmp, otmp);
1232 } else if (mattk->aatyp != AT_TUCH || dmg != 0 ||
1233 mtmp != u.ustuck)
1234 hitmsg(mtmp, mattk);
1235 }
1236 break;
1237 case AD_DISE:
1238 hitmsg(mtmp, mattk);
1239 if (!diseasemu(mdat) || Invulnerable) dmg = 0;
1240 break;
1241 case AD_FIRE:
1242 hitmsg(mtmp, mattk);
1243 if (uncancelled) {
1244 pline("You're %s!", on_fire(youmonst.data, mattk));
1245 if (youmonst.data == &mons[PM_STRAW_GOLEM] ||
1246 youmonst.data == &mons[PM_PAPER_GOLEM]) {
1247 You("roast!");
1248 /* KMH -- this is okay with unchanging */
1249 rehumanize();
1250 break;
1251 } else if (Fire_resistance) {
1252 pline_The("fire doesn't feel hot!");
1253 dmg = 0;
1254 } else if (u.umonnum == PM_STRAW_GOLEM ||
1255 u.umonnum == PM_PAPER_GOLEM ||
1256 u.umonnum == PM_WAX_GOLEM) {
1257 /* This code ASSUMES that you are polymorphed
1258 * Code will need to be changed if we ever implement
1259 * Golems as a class.
1260 */
1261 You("burn up!");
1262 u.uhp -= mons[u.umonnum].mlevel;
1263 u.uhpmax -= mons[u.umonnum].mlevel;
1264 if (u.uhpmax < 1) u.uhpmax = 1;
1265 /* KMH, balance patch -- this is okay with unchanging */
1266 u.mh = 0; /* Kill monster form */
1267 rehumanize();
1268 break;
1269 }
1270 if((int) mtmp->m_lev > rn2(20))
1271 destroy_item(SCROLL_CLASS, AD_FIRE);
1272 if((int) mtmp->m_lev > rn2(20))
1273 destroy_item(POTION_CLASS, AD_FIRE);
1274 if((int) mtmp->m_lev > rn2(25))
1275 destroy_item(SPBOOK_CLASS, AD_FIRE);
1276 burn_away_slime();
1277 } else dmg = 0;
1278 break;
1279 case AD_COLD:
1280 hitmsg(mtmp, mattk);
1281 if (uncancelled) {
1282 pline("You're covered in frost!");
1283 if (Cold_resistance) {
1284 pline_The("frost doesn't seem cold!");
1285 dmg = 0;
1286 }
1287 if((int) mtmp->m_lev > rn2(20))
1288 destroy_item(POTION_CLASS, AD_COLD);
1289 } else dmg = 0;
1290 break;
1291 case AD_ELEC:
1292 hitmsg(mtmp, mattk);
1293 if (uncancelled) {
1294 You("get zapped!");
1295 if (Shock_resistance) {
1296 pline_The("zap doesn't shock you!");
1297 dmg = 0;
1298 }
1299 if((int) mtmp->m_lev > rn2(20))
1300 destroy_item(WAND_CLASS, AD_ELEC);
1301 if((int) mtmp->m_lev > rn2(20))
1302 destroy_item(RING_CLASS, AD_ELEC);
1303 } else dmg = 0;
1304 break;
1305 case AD_SLEE:
1306 hitmsg(mtmp, mattk);
1307 if (uncancelled && multi >= 0 && !rn2(5)) {
1308 if (Sleep_resistance) break;
1309 fall_asleep(-rnd(10), TRUE);
1310 if (Blind) You("are put to sleep!");
1311 else You("are put to sleep by %s!", mon_nam(mtmp));
1312 }
1313 break;
1314 case AD_BLND:
1315 if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj*)0)) {
1316 if (!Blind) pline("%s blinds you!", Monnam(mtmp));
1317 make_blinded(Blinded+(long)dmg,FALSE);
1318 if (!Blind) Your(vision_clears);
1319 }
1320 dmg = 0;
1321 break;
1322 case AD_DRST:
1323 ptmp = A_STR;
1324 goto dopois;
1325 case AD_DRDX:
1326 ptmp = A_DEX;
1327 goto dopois;
1328 case AD_DRCO:
1329 ptmp = A_CON;
1330 dopois:
1331 hitmsg(mtmp, mattk);
1332 if (uncancelled && !rn2(8)) {
1333 Sprintf(buf, "%s %s",
1334 s_suffix(Monnam(mtmp)), mpoisons_subj(mtmp, mattk));
1335 poisoned(buf, ptmp, mdat->mname, 30);
1336 }
1337 break;
1338 case AD_DRIN:
1339 hitmsg(mtmp, mattk);
1340 if (defends(AD_DRIN, uwep) || !has_head(youmonst.data)) {
1341 You("don't seem harmed.");
1342 /* Not clear what to do for green slimes */
1343 break;
1344 }
1345 if (u_slip_free(mtmp,mattk)) break;
1346
1347 if (uarmh && rn2(8)) {
1348 /* not body_part(HEAD) */
1349 Your("helmet blocks the attack to your head.");
1350 break;
1351 }
1352
1353 /* conflicted dog, perhaps? */
1354 if (mtmp->mtame && !mtmp->isminion) {
1355 EDOG(mtmp)->hungrytime += rnd(60);
1356 mtmp->mconf = 0;
1357 }
1358
1359 if (Half_physical_damage) dmg = (dmg+1) / 2;
1360 mdamageu(mtmp, dmg);
1361
1362 if (!uarmh || uarmh->otyp != DUNCE_CAP) {
1363 Your("brain is eaten!");
1364 /* No such thing as mindless players... */
1365 if (ABASE(A_INT) <= ATTRMIN(A_INT)) {
1366 int lifesaved = 0;
1367 struct obj *wore_amulet = uamul;
1368
1369 while(1) {
1370 /* avoid looping on "die(y/n)?" */
1371 if (lifesaved && (discover || wizard)) {
1372 if (wore_amulet && !uamul) {
1373 /* used up AMULET_OF_LIFE_SAVING; still
1374 subject to dying from brainlessness */
1375 wore_amulet = 0;
1376 } else {
1377 /* explicitly chose not to die;
1378 arbitrarily boost intelligence */
1379 ABASE(A_INT) = ATTRMIN(A_INT) + 2;
1380 You_feel("like a scarecrow.");
1381 break;
1382 }
1383 }
1384
1385 if (lifesaved)
1386 pline("Unfortunately your brain is still gone.");
1387 else
1388 Your("last thought fades away.");
1389 killer = "brainlessness";
1390 killer_format = KILLED_BY;
1391 done(DIED);
1392 lifesaved++;
1393 }
1394 }
1395 }
1396 /* adjattrib gives dunce cap message when appropriate */
1397 (void) adjattrib(A_INT, -rnd(2), FALSE);
1398 forget_levels(25); /* lose memory of 25% of levels */
1399 forget_objects(25); /* lose memory of 25% of objects */
1400 exercise(A_WIS, FALSE);
1401 break;
1402 case AD_PLYS:
1403 hitmsg(mtmp, mattk);
1404 if (uncancelled && multi >= 0 && !rn2(3)) {
1405 if (Free_action) {
1406 You("momentarily stiffen.");
1407 } else {
1408 if (Blind) You("are frozen!");
1409 else You("are frozen by %s!", mon_nam(mtmp));
1410 nomovemsg = 0; /* default: "you can move again" */
1411 nomul(-rnd(10));
1412 exercise(A_DEX, FALSE);
1413 }
1414 }
1415 break;
1416 case AD_TCKL:
1417 hitmsg(mtmp, mattk);
1418 if (uncancelled && multi >= 0 && !rn2(3)) {
1419 if (Free_action)
1420 You_feel("horrible tentacles probing your flesh!");
1421 else {
1422 if (Blind) You("are mercilessly tickled!");
1423 else You("are mercilessly tickled by %s!", mon_nam(mtmp));
1424 nomovemsg = 0; /* default: "you can move again" */
1425 nomul(-rnd(10));
1426 exercise(A_DEX, FALSE);
1427 exercise(A_CON, FALSE);
1428 }
1429 }
1430 break;
1431 case AD_DRLI:
1432 hitmsg(mtmp, mattk);
1433 /* if vampire biting (and also a pet) */
1434 if (is_vampire(mtmp->data) && mattk->aatyp == AT_BITE &&
1435 has_blood(youmonst.data)) {
1436 Your("blood is being drained!");
1437 /* Get 1/20th of full corpse value
1438 * Therefore 4 bites == 1 drink
1439 */
1440 if (mtmp->mtame && !mtmp->isminion)
1441 EDOG(mtmp)->hungrytime += ((int)((youmonst.data)->cnutrit / 20) + 1);
1442 }
1443
1444 if (uncancelled && !rn2(3) && !Drain_resistance) {
1445 losexp("life drainage", FALSE);
1446 }
1447 break;
1448 case AD_LEGS:
1449 { register long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE;
1450 const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left";
1451
1452 /* This case is too obvious to ignore, but Nethack is not in
1453 * general very good at considering height--most short monsters
1454 * still _can_ attack you when you're flying or mounted.
1455 * [FIXME: why can't a flying attacker overcome this?]
1456 */
1457 if (
1458 #ifdef STEED
1459 u.usteed ||
1460 #endif
1461 Levitation || Flying) {
1462 pline("%s tries to reach your %s %s!", Monnam(mtmp),
1463 sidestr, body_part(LEG));
1464 dmg = 0;
1465 } else if (mtmp->mcan) {
1466 pline("%s nuzzles against your %s %s!", Monnam(mtmp),
1467 sidestr, body_part(LEG));
1468 dmg = 0;
1469 } else {
1470 if (uarmf) {
1471 if (rn2(2) && (uarmf->otyp == LOW_BOOTS ||
1472 uarmf->otyp == IRON_SHOES))
1473 pline("%s pricks the exposed part of your %s %s!",
1474 Monnam(mtmp), sidestr, body_part(LEG));
1475 else if (!rn2(5))
1476 pline("%s pricks through your %s boot!",
1477 Monnam(mtmp), sidestr);
1478 else {
1479 pline("%s scratches your %s boot!", Monnam(mtmp),
1480 sidestr);
1481 dmg = 0;
1482 break;
1483 }
1484 } else pline("%s pricks your %s %s!", Monnam(mtmp),
1485 sidestr, body_part(LEG));
1486 set_wounded_legs(side, rnd(60-ACURR(A_DEX)));
1487 exercise(A_STR, FALSE);
1488 exercise(A_DEX, FALSE);
1489 }
1490 break;
1491 }
1492 case AD_STON: /* cockatrice */
1493 hitmsg(mtmp, mattk);
1494 if(!rn2(3)) {
1495 if (mtmp->mcan) {
1496 if (flags.soundok)
1497 You_hear("a cough from %s!", mon_nam(mtmp));
1498 } else {
1499 if (flags.soundok)
1500 You_hear("%s hissing!", s_suffix(mon_nam(mtmp)));
1501 if(!rn2(10) ||
1502 (flags.moonphase == NEW_MOON && !have_lizard())) {
1503 do_stone:
1504 if (!Stoned && !Stone_resistance
1505 && !(poly_when_stoned(youmonst.data) &&
1506 polymon(PM_STONE_GOLEM))) {
1507 Stoned = 5;
1508 delayed_killer = mtmp->data->mname;
1509 if (mtmp->data->geno & G_UNIQ) {
1510 if (!type_is_pname(mtmp->data)) {
1511 static char kbuf[BUFSZ];
1512
1513 /* "the" buffer may be reallocated */
1514 Strcpy(kbuf, the(delayed_killer));
1515 delayed_killer = kbuf;
1516 }
1517 killer_format = KILLED_BY;
1518 } else killer_format = KILLED_BY_AN;
1519 return(1);
1520 /* You("turn to stone..."); */
1521 /* done_in_by(mtmp); */
1522 }
1523 }
1524 }
1525 }
1526 break;
1527 case AD_STCK:
1528 hitmsg(mtmp, mattk);
1529 if (uncancelled && !u.ustuck && !sticks(youmonst.data))
1530 setustuck(mtmp);
1531 break;
1532 case AD_WRAP:
1533 if ((!mtmp->mcan || u.ustuck == mtmp) && !sticks(youmonst.data)) {
1534 if (!u.ustuck && !rn2(10)) {
1535 if (u_slip_free(mtmp, mattk)) {
1536 dmg = 0;
1537 } else {
1538 pline("%s swings itself around you!",
1539 Monnam(mtmp));
1540 setustuck(mtmp);
1541 }
1542 } else if(u.ustuck == mtmp) {
1543 if (is_pool(mtmp->mx,mtmp->my) && !Swimming
1544 && !Amphibious) {
1545 boolean moat =
1546 (levl[mtmp->mx][mtmp->my].typ != POOL) &&
1547 (levl[mtmp->mx][mtmp->my].typ != WATER) &&
1548 !Is_medusa_level(&u.uz) &&
1549 !Is_waterlevel(&u.uz);
1550
1551 pline("%s drowns you...", Monnam(mtmp));
1552 killer_format = KILLED_BY_AN;
1553 Sprintf(buf, "%s by %s",
1554 moat ? "moat" : "pool of water",
1555 an(mtmp->data->mname));
1556 killer = buf;
1557 done(DROWNING);
1558 } else if(mattk->aatyp == AT_HUGS)
1559 You("are being crushed.");
1560 } else {
1561 dmg = 0;
1562 if(flags.verbose)
1563 pline("%s brushes against your %s.", Monnam(mtmp),
1564 body_part(LEG));
1565 }
1566 } else dmg = 0;
1567 break;
1568 case AD_WERE:
1569 hitmsg(mtmp, mattk);
1570 if (uncancelled && !rn2(4) && u.ulycn == NON_PM &&
1571 !Protection_from_shape_changers &&
1572 !is_were(youmonst.data) &&
1573 !defends(AD_WERE,uwep)) {
1574 You_feel("feverish.");
1575 exercise(A_CON, FALSE);
1576 u.ulycn = monsndx(mdat);
1577 upermonst.mflags2 |= (M2_WERE);
1578 }
1579 break;
1580 case AD_SGLD:
1581 hitmsg(mtmp, mattk);
1582 if (youmonst.data->mlet == mdat->mlet) break;
1583 if(!mtmp->mcan) stealgold(mtmp);
1584 break;
1585
1586 case AD_SITM: /* for now these are the same */
1587 case AD_SEDU:
1588 if (is_animal(mtmp->data)) {
1589 hitmsg(mtmp, mattk);
1590 if (mtmp->mcan) break;
1591 /* Continue below */
1592 } else if (dmgtype(youmonst.data, AD_SEDU)
1593 #ifdef SEDUCE
1594 || dmgtype(youmonst.data, AD_SSEX)
1595 #endif
1596 ) {
1597 pline("%s %s.", Monnam(mtmp), mtmp->minvent ?
1598 "brags about the goods some dungeon explorer provided" :
1599 "makes some remarks about how difficult theft is lately");
1600 if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
1601 return 3;
1602 } else if (mtmp->mcan) {
1603 if (!Blind) {
1604 /*
1605 * We use flags.female here on the basis that the
1606 * monster chooses whether to charm or to seduce
1607 * based on your visible gender. --ALI
1608 */
1609 int do_charm = is_neuter(mdat) || \
1610 flags.female == mtmp->female;
1611 pline("%s tries to %s you, but you seem %s.",
1612 Adjmonnam(mtmp, "plain"),
1613 do_charm ? "charm" : "seduce",
1614 do_charm ? "unaffected" : "uninterested");
1615 }
1616 if(rn2(3)) {
1617 if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
1618 return 3;
1619 }
1620 break;
1621 }
1622 buf[0] = '\0';
1623 switch (steal(mtmp, buf)) {
1624 case -1:
1625 return 2;
1626 case 0:
1627 break;
1628 default:
1629 if (!is_animal(mtmp->data) && !tele_restrict(mtmp))
1630 (void) rloc(mtmp, FALSE);
1631 if (is_animal(mtmp->data) && *buf) {
1632 if (canseemon(mtmp))
1633 pline("%s tries to %s away with %s.",
1634 Monnam(mtmp),
1635 locomotion(mtmp->data, "run"),
1636 buf);
1637 }
1638 monflee(mtmp, 0, FALSE, FALSE);
1639 return 3;
1640 }
1641 break;
1642 #ifdef SEDUCE
1643 case AD_SSEX:
1644 if(could_seduce(mtmp, &youmonst, mattk) == 1
1645 && !mtmp->mcan)
1646 if (doseduce(mtmp))
1647 return 3;
1648 break;
1649 #endif
1650 case AD_SAMU:
1651 hitmsg(mtmp, mattk);
1652 /* when the Wiz hits, 1/20 steals the amulet */
1653 if (u.uhave.amulet ||
1654 u.uhave.bell || u.uhave.book || u.uhave.menorah
1655 || u.uhave.questart) /* carrying the Quest Artifact */
1656 if (!rn2(20)) stealamulet(mtmp);
1657 break;
1658
1659 case AD_TLPT:
1660 hitmsg(mtmp, mattk);
1661 if (uncancelled) {
1662 if(flags.verbose)
1663 Your("position suddenly seems very uncertain!");
1664 tele();
1665 }
1666 break;
1667 case AD_RUST:
1668 hitmsg(mtmp, mattk);
1669 if (mtmp->mcan) break;
1670 if (u.umonnum == PM_IRON_GOLEM) {
1671 You("rust!");
1672 u.uhp -= mons[u.umonnum].mlevel;
1673 u.uhpmax -= mons[u.umonnum].mlevel;
1674 if (u.uhpmax < 1) u.uhpmax = 1;
1675 /* KMH, balance patch -- this is okay with unchanging */
1676 u.mh = 0;
1677 rehumanize();
1678 break;
1679 }
1680 hurtarmor(AD_RUST);
1681 break;
1682 case AD_CORR:
1683 hitmsg(mtmp, mattk);
1684 if (mtmp->mcan) break;
1685 hurtarmor(AD_CORR);
1686 break;
1687 case AD_DCAY:
1688 hitmsg(mtmp, mattk);
1689 if (mtmp->mcan) break;
1690 if (u.umonnum == PM_WOOD_GOLEM ||
1691 u.umonnum == PM_LEATHER_GOLEM) {
1692 You("rot!");
1693 u.uhp -= mons[u.umonnum].mlevel;
1694 u.uhpmax -= mons[u.umonnum].mlevel;
1695 if (u.uhpmax < 1) u.uhpmax = 1;
1696 u.mh = 0;
1697 /* KMH, balance patch -- this is okay with unchanging */
1698 rehumanize();
1699 break;
1700 }
1701 hurtarmor(AD_DCAY);
1702 break;
1703 case AD_HEAL:
1704 /* a cancelled nurse is just an ordinary monster */
1705 if (mtmp->mcan) {
1706 hitmsg(mtmp, mattk);
1707 break;
1708 }
1709 if(!uwep
1710 #ifdef TOURIST
1711 && !uarmu
1712 #endif
1713 && !uarm && !uarmh && !uarms && !uarmg && !uarmc && !uarmf) {
1714 boolean goaway = FALSE;
1715 pline("%s hits! (I hope you don't mind.)", Monnam(mtmp));
1716 if (Upolyd) {
1717 u.mh += rnd(7);
1718 /* STEPHEN WHITE'S NEW CODE */
1719 if (!rn2(7)) {
1720 /* no upper limit necessary; effect is temporary */
1721 u.mhmax++;
1722 if (!rn2(13)) goaway = TRUE;
1723 }
1724 if (u.mh > u.mhmax) u.mh = u.mhmax;
1725 } else {
1726 u.uhp += rnd(7);
1727 if (!rn2(7)) {
1728 /* hard upper limit via nurse care: 25 * ulevel */
1729 if (u.uhpmax < 5 * u.ulevel + d(2 * u.ulevel, 10)) {
1730 u.uhpmax++;
1731 }
1732 if (!rn2(13)) goaway = TRUE;
1733 }
1734 if (u.uhp > u.uhpmax) u.uhp = u.uhpmax;
1735 }
1736 if (!rn2(3)) exercise(A_STR, TRUE);
1737 if (!rn2(3)) exercise(A_CON, TRUE);
1738 if (Sick) make_sick(0L, (char *) 0, FALSE, SICK_ALL);
1739 flags.botl = 1;
1740 if (goaway) {
1741 mongone(mtmp);
1742 return 2;
1743 } else if (!rn2(33)) {
1744 if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE);
1745 monflee(mtmp, d(3, 6), TRUE, FALSE);
1746 return 3;
1747 }
1748 dmg = 0;
1749 } else {
1750 if (Role_if(PM_HEALER)) {
1751 if (flags.soundok && !(moves % 5))
1752 verbalize("Doc, I can't help you unless you cooperate.");
1753 dmg = 0;
1754 } else hitmsg(mtmp, mattk);
1755 }
1756 break;
1757 case AD_CURS:
1758 hitmsg(mtmp, mattk);
1759 if(!night() && mdat == &mons[PM_GREMLIN]) break;
1760 if(!mtmp->mcan && !rn2(10)) {
1761 if (flags.soundok) {
1762 if (Blind) You_hear("laughter.");
1763 else pline("%s chuckles.", Monnam(mtmp));
1764 }
1765 if (u.umonnum == PM_CLAY_GOLEM) {
1766 pline("Some writing vanishes from your head!");
1767 u.uhp -= mons[u.umonnum].mlevel;
1768 u.uhpmax -= mons[u.umonnum].mlevel;
1769 if (u.uhpmax < 1) u.uhpmax = 1;
1770 /* KMH, balance patch -- this is okay with unchanging */
1771 u.mh = 0;
1772 rehumanize();
1773 break;
1774 }
1775 attrcurse();
1776 }
1777 break;
1778 case AD_STUN:
1779 hitmsg(mtmp, mattk);
1780 if(!mtmp->mcan && !rn2(4)) {
1781 make_stunned(HStun + dmg, TRUE);
1782 dmg /= 2;
1783 }
1784 break;
1785 case AD_ACID:
1786 hitmsg(mtmp, mattk);
1787 if(!mtmp->mcan && !rn2(3)) {
1788 if (Acid_resistance) {
1789 pline("You're covered in acid, but it seems harmless.");
1790 dmg = 0;
1791 } else {
1792 pline("You're covered in acid! It burns!");
1793 exercise(A_STR, FALSE);
1794 }
1795 } else dmg = 0;
1796 break;
1797 case AD_SLOW:
1798 hitmsg(mtmp, mattk);
1799 if (uncancelled && HFast &&
1800 !defends(AD_SLOW, uwep) && !rn2(4))
1801 u_slow_down();
1802 break;
1803 case AD_DREN:
1804 hitmsg(mtmp, mattk);
1805 if (uncancelled && !rn2(4))
1806 drain_en(dmg);
1807 dmg = 0;
1808 break;
1809 case AD_CONF:
1810 hitmsg(mtmp, mattk);
1811 if(!mtmp->mcan && !rn2(4) && !mtmp->mspec_used) {
1812 mtmp->mspec_used = mtmp->mspec_used + (dmg + rn2(6));
1813 if(Confusion)
1814 You("are getting even more confused.");
1815 else You("are getting confused.");
1816 make_confused(HConfusion + dmg, FALSE);
1817 }
1818 dmg = 0;
1819 break;
1820 case AD_DETH:
1821 pline("%s reaches out with its deadly touch.", Monnam(mtmp));
1822 if (is_undead(youmonst.data)) {
1823 /* Still does normal damage */
1824 pline("Was that the touch of death?");
1825 break;
1826 }
1827 switch (rn2(20)) {
1828 case 19: case 18: case 17:
1829 if (!Antimagic) {
1830 killer_format = KILLED_BY_AN;
1831 killer = "touch of death";
1832 done(DIED);
1833 dmg = 0;
1834 break;
1835 } /* else FALLTHRU */
1836 default: /* case 16: ... case 5: */
1837 You_feel("your life force draining away...");
1838 permdmg = 1; /* actual damage done below */
1839 break;
1840 case 4: case 3: case 2: case 1: case 0:
1841 if (Antimagic) shieldeff(u.ux, u.uy);
1842 pline("Lucky for you, it didn't work!");
1843 dmg = 0;
1844 break;
1845 }
1846 break;
1847 case AD_PEST:
1848 pline("%s reaches out, and you feel fever and chills.",
1849 Monnam(mtmp));
1850 (void) diseasemu(mdat); /* plus the normal damage */
1851 /* No damage if invulnerable; setting dmg zero prevents
1852 * "You are unharmed!" after a sickness inducing attack */
1853 if (Invulnerable) dmg = 0;
1854 break;
1855 case AD_FAMN:
1856 pline("%s reaches out, and your body shrivels.",
1857 Monnam(mtmp));
1858 exercise(A_CON, FALSE);
1859 if (!is_fainted()) morehungry(rn1(40,40));
1860 /* plus the normal damage */
1861 break;
1862 case AD_CALM: /* KMH -- koala attack */
1863 hitmsg(mtmp, mattk);
1864 if (uncancelled)
1865 docalm();
1866 break;
1867 case AD_POLY:
1868 hitmsg(mtmp, mattk);
1869 if (uncancelled && !Unchanging && !Antimagic) {
1870 if (flags.verbose)
1871 You("undergo a freakish metamorphosis!");
1872 polyself(FALSE);
1873 }
1874 break;
1875 case AD_SLIM:
1876 hitmsg(mtmp, mattk);
1877 if (!uncancelled) break;
1878 if (flaming(youmonst.data)) {
1879 pline_The("slime burns away!");
1880 dmg = 0;
1881 } else if (Unchanging ||
1882 youmonst.data == &mons[PM_GREEN_SLIME]) {
1883 You("are unaffected.");
1884 dmg = 0;
1885 } else if (!Slimed) {
1886 You("don't feel very well.");
1887 Slimed = 10L;
1888 flags.botl = 1;
1889 killer_format = KILLED_BY_AN;
1890 delayed_killer = mtmp->data->mname;
1891 } else
1892 pline("Yuck!");
1893 break;
1894 case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
1895 hitmsg(mtmp, mattk);
1896 /* uncancelled is sufficient enough; please
1897 don't make this attack less frequent */
1898 if (uncancelled) {
1899 struct obj *obj = some_armor(&youmonst);
1900
1901 if (drain_item(obj)) {
1902 Your("%s less effective.", aobjnam(obj, "seem"));
1903 }
1904 }
1905 break;
1906 default: dmg = 0;
1907 break;
1908 }
1909 if(u.uhp < 1) done_in_by(mtmp);
1910
1911 /* Negative armor class reduces damage done instead of fully protecting
1912 * against hits.
1913 */
1914 if (dmg && u.uac < -10) {
1915 int tempval;
1916 tempval = rnd(-(10 + u.uac)/5+1);
1917 if (tempval < 1) tempval = 1;
1918 if (tempval > 10) tempval = 10;
1919 dmg -= tempval;
1920 if (dmg < 1) dmg = 1;
1921 }
1922
1923 if(dmg) {
1924 if (Half_physical_damage
1925 /* Mitre of Holiness */
1926 || (Role_if(PM_PRIEST) && uarmh && is_quest_artifact(uarmh) &&
1927 (is_undead(mtmp->data) || is_demon(mtmp->data))))
1928 dmg = (dmg+1) / 2;
1929
1930 if (permdmg) { /* Death's life force drain */
1931 int lowerlimit, *hpmax_p;
1932 /*
1933 * Apply some of the damage to permanent hit points:
1934 * polymorphed 100% against poly'd hpmax
1935 * hpmax > 25*lvl 100% against normal hpmax
1936 * hpmax > 10*lvl 50..100%
1937 * hpmax > 5*lvl 25..75%
1938 * otherwise 0..50%
1939 * Never reduces hpmax below 1 hit point per level.
1940 */
1941 permdmg = rn2(dmg / 2 + 1);
1942 if (Upolyd || u.uhpmax > 25 * u.ulevel) permdmg = dmg;
1943 else if (u.uhpmax > 10 * u.ulevel) permdmg += dmg / 2;
1944 else if (u.uhpmax > 5 * u.ulevel) permdmg += dmg / 4;
1945
1946 if (Upolyd) {
1947 hpmax_p = &u.mhmax;
1948 /* [can't use youmonst.m_lev] */
1949 lowerlimit = min((int)youmonst.data->mlevel, u.ulevel);
1950 } else {
1951 hpmax_p = &u.uhpmax;
1952 lowerlimit = u.ulevel;
1953 }
1954 if (*hpmax_p - permdmg > lowerlimit)
1955 *hpmax_p -= permdmg;
1956 else if (*hpmax_p > lowerlimit)
1957 *hpmax_p = lowerlimit;
1958 else /* unlikely... */
1959 ; /* already at or below minimum threshold; do nothing */
1960 flags.botl = 1;
1961 }
1962
1963 mdamageu(mtmp, dmg);
1964 }
1965
1966 if (DEADMONSTER(mtmp))
1967 res = 2;
1968 else if (dmg)
1969 res = passiveum(olduasmon, mtmp, mattk);
1970 else
1971 res = 1;
1972 stop_occupation();
1973 return res;
1974 }
1975
1976 #endif /* OVL1 */
1977 #ifdef OVLB
1978
1979 STATIC_OVL int
gulpmu(mtmp,mattk)1980 gulpmu(mtmp, mattk) /* monster swallows you, or damage if u.uswallow */
1981 register struct monst *mtmp;
1982 register struct attack *mattk;
1983 {
1984 struct trap *t = t_at(u.ux, u.uy);
1985 int tmp = d((int)mattk->damn, (int)mattk->damd);
1986 int tim_tmp;
1987 register struct obj *otmp2;
1988 int i;
1989
1990 if (!u.uswallow) { /* swallows you */
1991 if (youmonst.data->msize >= MZ_HUGE) return(0);
1992 if ((t && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT))) &&
1993 sobj_at(BOULDER, u.ux, u.uy))
1994 return(0);
1995
1996 if (Punished) unplacebc(); /* ball&chain go away */
1997 remove_monster(mtmp->mx, mtmp->my);
1998 mtmp->mtrapped = 0; /* no longer on old trap */
1999 place_monster(mtmp, u.ux, u.uy);
2000 newsym(mtmp->mx,mtmp->my);
2001 #ifdef STEED
2002 if (is_animal(mtmp->data) && u.usteed) {
2003 char buf[BUFSZ];
2004 /* Too many quirks presently if hero and steed
2005 * are swallowed. Pretend purple worms don't
2006 * like horses for now :-)
2007 */
2008 Strcpy(buf, mon_nam(u.usteed));
2009 pline ("%s lunges forward and plucks you off %s!",
2010 Monnam(mtmp), buf);
2011 dismount_steed(DISMOUNT_ENGULFED);
2012 } else
2013 #endif
2014 pline("%s engulfs you!", Monnam(mtmp));
2015 stop_occupation();
2016 reset_occupations(); /* behave as if you had moved */
2017
2018 if (u.utrap) {
2019 You("are released from the %s!",
2020 u.utraptype==TT_WEB ? "web" : "trap");
2021 u.utrap = 0;
2022 }
2023
2024 i = number_leashed();
2025 if (i > 0) {
2026 const char *s = (i > 1) ? "leashes" : "leash";
2027 pline_The("%s %s loose.", s, vtense(s, "snap"));
2028 unleash_all();
2029 }
2030
2031 if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) {
2032 minstapetrify(mtmp, TRUE);
2033 if (mtmp->mhp > 0) return 0;
2034 else return 2;
2035 }
2036
2037 display_nhwindow(WIN_MESSAGE, FALSE);
2038 vision_recalc(2); /* hero can't see anything */
2039 u.uswallow = 1;
2040 setustuck(mtmp);
2041 /* u.uswldtim always set > 1 */
2042 tim_tmp = 25 - (int)mtmp->m_lev;
2043 if (tim_tmp > 0) tim_tmp = rnd(tim_tmp) / 2;
2044 else if (tim_tmp < 0) tim_tmp = -(rnd(-tim_tmp) / 2);
2045 tim_tmp += -u.uac + 10;
2046 u.uswldtim = (unsigned)((tim_tmp < 2) ? 2 : tim_tmp);
2047 swallowed(1);
2048 for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj)
2049 (void) snuff_lit(otmp2);
2050 }
2051
2052 if (mtmp != u.ustuck) return(0);
2053 if (u.uswldtim > 0) u.uswldtim -= 1;
2054
2055 switch(mattk->adtyp) {
2056
2057 case AD_DGST:
2058 if (Slow_digestion) {
2059 /* Messages are handled below */
2060 u.uswldtim = 0;
2061 tmp = 0;
2062 } else if (u.uswldtim == 0) {
2063 pline("%s totally digests you!", Monnam(mtmp));
2064 tmp = u.uhp;
2065 if (Half_physical_damage) tmp *= 2; /* sorry */
2066 } else {
2067 pline("%s%s digests you!", Monnam(mtmp),
2068 (u.uswldtim == 2) ? " thoroughly" :
2069 (u.uswldtim == 1) ? " utterly" : "");
2070 exercise(A_STR, FALSE);
2071 }
2072 break;
2073 case AD_PHYS:
2074 if (mtmp->data == &mons[PM_FOG_CLOUD]) {
2075 You("are laden with moisture and %s",
2076 flaming(youmonst.data) ? "are smoldering out!" :
2077 Breathless ? "find it mildly uncomfortable." :
2078 amphibious(youmonst.data) ? "feel comforted." :
2079 "can barely breathe!");
2080 /* NB: Amphibious includes Breathless */
2081 if (Amphibious && !flaming(youmonst.data)) tmp = 0;
2082 } else {
2083 You("are pummeled with debris!");
2084 exercise(A_STR, FALSE);
2085 }
2086 break;
2087 case AD_ACID:
2088 if (Acid_resistance) {
2089 You("are covered with a seemingly harmless goo.");
2090 tmp = 0;
2091 } else {
2092 if (Hallucination) pline("Ouch! You've been slimed!");
2093 else You("are covered in slime! It burns!");
2094 exercise(A_STR, FALSE);
2095 }
2096 /* Mik: Go corrode a few things... */
2097 if (mtmp->data == &mons[PM_SHOGGOTH]
2098 || mtmp->data == &mons[PM_GIANT_SHOGGOTH]) {
2099 for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj)
2100 if (is_corrodeable(otmp2))
2101 (void) rust_dmg(otmp2, xname(otmp2), 3, FALSE,
2102 &youmonst);
2103 } else {
2104 for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj)
2105 if (is_corrodeable(otmp2) && !rn2(9))
2106 (void) rust_dmg(otmp2, xname(otmp2), 3, FALSE,
2107 &youmonst);
2108 }
2109 break;
2110 case AD_BLND:
2111 if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj*)0)) {
2112 if(!Blind) {
2113 You_cant("see in here!");
2114 make_blinded((long)tmp,FALSE);
2115 if (!Blind) Your(vision_clears);
2116 } else
2117 /* keep him blind until disgorged */
2118 make_blinded(Blinded+1,FALSE);
2119 }
2120 tmp = 0;
2121 break;
2122 case AD_ELEC:
2123 if(!mtmp->mcan && rn2(2)) {
2124 pline_The("air around you crackles with electricity.");
2125 if (Shock_resistance) {
2126 shieldeff(u.ux, u.uy);
2127 You("seem unhurt.");
2128 ugolemeffects(AD_ELEC,tmp);
2129 tmp = 0;
2130 }
2131 } else tmp = 0;
2132 break;
2133 case AD_COLD:
2134 if(!mtmp->mcan && rn2(2)) {
2135 if (Cold_resistance) {
2136 shieldeff(u.ux, u.uy);
2137 You_feel("mildly chilly.");
2138 ugolemeffects(AD_COLD,tmp);
2139 tmp = 0;
2140 } else You("are freezing to death!");
2141 } else tmp = 0;
2142 break;
2143 case AD_FIRE:
2144 if(!mtmp->mcan && rn2(2)) {
2145 if (Fire_resistance) {
2146 shieldeff(u.ux, u.uy);
2147 You_feel("mildly hot.");
2148 ugolemeffects(AD_FIRE,tmp);
2149 tmp = 0;
2150 } else You("are burning to a crisp!");
2151 burn_away_slime();
2152 } else tmp = 0;
2153 break;
2154 case AD_DISE:
2155 if (!diseasemu(mtmp->data)) tmp = 0;
2156 break;
2157 default:
2158 tmp = 0;
2159 break;
2160 }
2161
2162 if (Half_physical_damage) tmp = (tmp+1) / 2;
2163
2164 mdamageu(mtmp, tmp);
2165 if (tmp) stop_occupation();
2166
2167 if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) {
2168 pline("%s very hurriedly %s you!", Monnam(mtmp),
2169 is_animal(mtmp->data)? "regurgitates" : "expels");
2170 expels(mtmp, mtmp->data, FALSE);
2171 } else if (!u.uswldtim || youmonst.data->msize >= MZ_HUGE) {
2172 You("get %s!", is_animal(mtmp->data)? "regurgitated" : "expelled");
2173 if (flags.verbose && (is_animal(mtmp->data) ||
2174 (dmgtype(mtmp->data, AD_DGST) && Slow_digestion)))
2175 pline("Obviously %s doesn't like your taste.", mon_nam(mtmp));
2176 expels(mtmp, mtmp->data, FALSE);
2177 }
2178 return(1);
2179 }
2180
2181 STATIC_OVL int
explmu(mtmp,mattk,ufound)2182 explmu(mtmp, mattk, ufound) /* monster explodes in your face */
2183 register struct monst *mtmp;
2184 register struct attack *mattk;
2185 boolean ufound;
2186 {
2187 if (mtmp->mcan) return(0);
2188
2189 if (!ufound)
2190 pline("%s explodes at a spot in %s!",
2191 canseemon(mtmp) ? Monnam(mtmp) : "It",
2192 levl[mtmp->mux][mtmp->muy].typ == WATER
2193 ? "empty water" : "thin air");
2194 else {
2195 register int tmp = d((int)mattk->damn, (int)mattk->damd);
2196 register boolean not_affected = defends((int)mattk->adtyp, uwep);
2197
2198 hitmsg(mtmp, mattk);
2199
2200 switch (mattk->adtyp) {
2201 case AD_COLD:
2202 not_affected |= Cold_resistance;
2203 goto common;
2204 case AD_FIRE:
2205 not_affected |= Fire_resistance;
2206 goto common;
2207 case AD_ELEC:
2208 not_affected |= Shock_resistance;
2209 common:
2210
2211 if (!not_affected) {
2212 if (ACURR(A_DEX) > rnd(20)) {
2213 You("duck some of the blast.");
2214 tmp = (tmp+1) / 2;
2215 } else {
2216 if (flags.verbose) You("get blasted!");
2217 }
2218 if (mattk->adtyp == AD_FIRE) burn_away_slime();
2219 if (Half_physical_damage) tmp = (tmp+1) / 2;
2220 mdamageu(mtmp, tmp);
2221 }
2222 break;
2223
2224 case AD_BLND:
2225 not_affected = resists_blnd(&youmonst);
2226 if (!not_affected) {
2227 /* sometimes you're affected even if it's invisible */
2228 if (mon_visible(mtmp) || (rnd(tmp /= 2) > u.ulevel)) {
2229 You("are blinded by a blast of light!");
2230 make_blinded((long)tmp, FALSE);
2231 if (!Blind) Your(vision_clears);
2232 } else if (flags.verbose)
2233 You("get the impression it was not terribly bright.");
2234 }
2235 break;
2236
2237 case AD_HALU:
2238 not_affected |= Blind ||
2239 (u.umonnum == PM_BLACK_LIGHT ||
2240 u.umonnum == PM_VIOLET_FUNGUS ||
2241 dmgtype(youmonst.data, AD_STUN));
2242 if (!not_affected) {
2243 boolean chg;
2244 if (!Hallucination)
2245 You("are caught in a blast of kaleidoscopic light!");
2246 chg = make_hallucinated(HHallucination + (long)tmp,FALSE,0L);
2247 You("%s.", chg ? "are freaked out" : "seem unaffected");
2248 }
2249 break;
2250
2251 default:
2252 break;
2253 }
2254 if (not_affected) {
2255 You("seem unaffected by it.");
2256 ugolemeffects((int)mattk->adtyp, tmp);
2257 }
2258 }
2259 mondead(mtmp);
2260 wake_nearto(mtmp->mx, mtmp->my, 7*7);
2261 if (mtmp->mhp > 0) return(0);
2262 return(2); /* it dies */
2263 }
2264
2265 int
gazemu(mtmp,mattk)2266 gazemu(mtmp, mattk) /* monster gazes at you */
2267 register struct monst *mtmp;
2268 register struct attack *mattk;
2269 {
2270 switch(mattk->adtyp) {
2271 case AD_STON:
2272 if (mtmp->mcan || !mtmp->mcansee) {
2273 if (!canseemon(mtmp)) break; /* silently */
2274 pline("%s %s.", Monnam(mtmp),
2275 (mtmp->data == &mons[PM_MEDUSA] && mtmp->mcan) ?
2276 "doesn't look all that ugly" :
2277 "gazes ineffectually");
2278 break;
2279 }
2280 if (Reflecting && couldsee(mtmp->mx, mtmp->my) &&
2281 mtmp->data == &mons[PM_MEDUSA]) {
2282 /* hero has line of sight to Medusa and she's not blind */
2283 boolean useeit = canseemon(mtmp);
2284
2285 if (useeit)
2286 (void) ureflects("%s gaze is reflected by your %s.",
2287 s_suffix(Monnam(mtmp)));
2288 if (mon_reflects(mtmp, !useeit ? (char *)0 :
2289 "The gaze is reflected away by %s %s!"))
2290 break;
2291 if (!m_canseeu(mtmp)) { /* probably you're invisible */
2292 if (useeit)
2293 pline(
2294 "%s doesn't seem to notice that %s gaze was reflected.",
2295 Monnam(mtmp), mhis(mtmp));
2296 break;
2297 }
2298 if (useeit)
2299 pline("%s is turned to stone!", Monnam(mtmp));
2300 stoned = TRUE;
2301 killed(mtmp);
2302
2303 if (mtmp->mhp > 0) break;
2304 return 2;
2305 }
2306 if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) &&
2307 !Stone_resistance) {
2308 You("meet %s gaze.", s_suffix(mon_nam(mtmp)));
2309 stop_occupation();
2310 if(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
2311 break;
2312 You("turn to stone...");
2313 killer_format = KILLED_BY;
2314 killer = mtmp->data->mname;
2315 done(STONING);
2316 }
2317 break;
2318 case AD_CONF:
2319 if(!mtmp->mcan && canseemon(mtmp) &&
2320 couldsee(mtmp->mx, mtmp->my) &&
2321 mtmp->mcansee && !mtmp->mspec_used && rn2(5)) {
2322 int conf = d(3,4);
2323
2324 mtmp->mspec_used = mtmp->mspec_used + (conf + rn2(6));
2325 if(!Confusion)
2326 pline("%s gaze confuses you!",
2327 s_suffix(Monnam(mtmp)));
2328 else
2329 You("are getting more and more confused.");
2330 make_confused(HConfusion + conf, FALSE);
2331 stop_occupation();
2332 }
2333 break;
2334 case AD_STUN:
2335 if(!mtmp->mcan && canseemon(mtmp) &&
2336 couldsee(mtmp->mx, mtmp->my) &&
2337 mtmp->mcansee && !mtmp->mspec_used && rn2(5)) {
2338 int stun = d(2,6);
2339
2340 mtmp->mspec_used = mtmp->mspec_used + (stun + rn2(6));
2341 pline("%s stares piercingly at you!", Monnam(mtmp));
2342 make_stunned(HStun + stun, TRUE);
2343 stop_occupation();
2344 }
2345 break;
2346 case AD_BLND:
2347 if (!mtmp->mcan && canseemon(mtmp) && !resists_blnd(&youmonst)
2348 && distu(mtmp->mx,mtmp->my) <= BOLT_LIM*BOLT_LIM) {
2349 int blnd = d((int)mattk->damn, (int)mattk->damd);
2350
2351 You("are blinded by %s radiance!",
2352 s_suffix(mon_nam(mtmp)));
2353 make_blinded((long)blnd,FALSE);
2354 stop_occupation();
2355 /* not blind at this point implies you're wearing
2356 the Eyes of the Overworld; make them block this
2357 particular stun attack too */
2358 if (!Blind) Your(vision_clears);
2359 else make_stunned((long)d(1,3),TRUE);
2360 }
2361 break;
2362 case AD_FIRE:
2363 if (!mtmp->mcan && canseemon(mtmp) &&
2364 couldsee(mtmp->mx, mtmp->my) &&
2365 mtmp->mcansee && !mtmp->mspec_used && rn2(5)) {
2366 int dmg = d(2,6);
2367
2368 pline("%s attacks you with a fiery gaze!", Monnam(mtmp));
2369 stop_occupation();
2370 if (Fire_resistance) {
2371 pline_The("fire doesn't feel hot!");
2372 dmg = 0;
2373 }
2374 burn_away_slime();
2375 if ((int) mtmp->m_lev > rn2(20))
2376 destroy_item(SCROLL_CLASS, AD_FIRE);
2377 if ((int) mtmp->m_lev > rn2(20))
2378 destroy_item(POTION_CLASS, AD_FIRE);
2379 if ((int) mtmp->m_lev > rn2(25))
2380 destroy_item(SPBOOK_CLASS, AD_FIRE);
2381 if (dmg) mdamageu(mtmp, dmg);
2382 }
2383 break;
2384 #ifdef PM_BEHOLDER /* work in progress */
2385 #if 0
2386 case AD_SLEE:
2387 if(!mtmp->mcan && canseemon(mtmp) &&
2388 couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee &&
2389 multi >= 0 && !rn2(5) && !Sleep_resistance) {
2390
2391 fall_asleep(-rnd(10), TRUE);
2392 pline("%s gaze makes you very sleepy...",
2393 s_suffix(Monnam(mtmp)));
2394 }
2395 break;
2396 #endif
2397 case AD_SLOW:
2398 if(!mtmp->mcan && canseemon(mtmp) && mtmp->mcansee &&
2399 (HFast & (INTRINSIC|TIMEOUT)) &&
2400 !defends(AD_SLOW, uwep) && !rn2(4))
2401
2402 u_slow_down();
2403 stop_occupation();
2404 break;
2405 #endif
2406 case AD_SLEE:
2407 if(!mtmp->mcan && canseemon(mtmp) &&
2408 mtmp->mcansee && !mtmp->mspec_used && rn2(3)) {
2409 if (Displaced && rn2(3)) {
2410 if (!Blind) pline("%s gazes at your displaced image!",Monnam(mtmp));
2411 break;
2412 }
2413 if ((Invisible && rn2(3)) || rn2(4)) {
2414 if (!Blind) pline("%s gazes around, but misses you!",Monnam(mtmp));
2415 break;
2416 }
2417 if (!Blind) pline("%s gazes directly at you!",Monnam(mtmp));
2418 if(Reflecting && m_canseeu(mtmp) && !mtmp->mcan) {
2419 if(!Blind) {
2420 (void) ureflects("%s gaze is reflected by your %s.",
2421 s_suffix(Monnam(mtmp)));
2422 if (mon_reflects(mtmp,
2423 "The gaze is reflected away by %s %s!"))
2424 break;
2425 }
2426 if (sleep_monst(mtmp, rnd(10), -1) && !Blind)
2427 pline("%s is put to sleep!", Monnam(mtmp));
2428 break;
2429 } else if (Sleep_resistance) {
2430 pline("You yawn.");
2431 } else {
2432 nomul(-rnd(10));
2433 u.usleep = 1;
2434 nomovemsg = "You wake up.";
2435 if (Blind) You("are put to sleep!");
2436 else You("are put to sleep by %s!",mon_nam(mtmp));
2437 }
2438 }
2439 break;
2440 case AD_DETH:
2441 if(!mtmp->mcan && canseemon(mtmp) && mtmp->mcansee && !mtmp->mspec_used && rn2(4)) {
2442 if (Displaced && rn2(3)) {
2443 if (!Blind) pline("%s gazes at your displaced image!",Monnam(mtmp));
2444 break;
2445 }
2446 if ((Invisible && rn2(3)) || rn2(4)) {
2447 if (!Blind) pline("%s gazes around, but misses you!",Monnam(mtmp));
2448 break;
2449 }
2450 if (!Blind) pline("%s gazes directly at you!",Monnam(mtmp));
2451 if(Reflecting && m_canseeu(mtmp) && !mtmp->mcan) {
2452 if(!Blind) {
2453 (void) ureflects("%s gaze is reflected by your %s.",
2454 s_suffix(Monnam(mtmp)));
2455 if (mon_reflects(mtmp,
2456 "The gaze is reflected away by %s %s!"))
2457 break;
2458 pline("%s is killed by its own gaze of death!",
2459 Monnam(mtmp));
2460 }
2461 killed(mtmp);
2462 if (mtmp->mhp > 0) break;
2463 return 2;
2464 } else if (is_undead(youmonst.data)) {
2465 /* Still does normal damage */
2466 pline("Was that the gaze of death?");
2467 break;
2468 } else if (Antimagic) {
2469 You("shudder momentarily...");
2470 } else {
2471 You("die...");
2472 killer_format = KILLED_BY_AN;
2473 killer = "gaze of death";
2474 done(DIED);
2475 }
2476 }
2477 break;
2478 case AD_PHYS:
2479 if(!mtmp->mcan && canseemon(mtmp) && mtmp->mcansee && !mtmp->mspec_used && rn2(3)) {
2480 if (Displaced && rn2(3)) {
2481 if (!Blind) pline("%s gazes at your displaced image!",Monnam(mtmp));
2482 break;
2483 }
2484 if ((Invisible && rn2(3)) || rn2(4)) {
2485 if (!Blind) pline("%s gazes around, but misses you!",Monnam(mtmp));
2486 break;
2487 }
2488 if (!Blind) pline("%s gazes directly at you!",Monnam(mtmp));
2489 pline("You are wracked with pains!");
2490 mdamageu(mtmp, d(3,8));
2491 }
2492 break;
2493 case AD_DRST:
2494 if(!mtmp->mcan && canseemon(mtmp) && mtmp->mcansee && !mtmp->mspec_used && rn2(5)) {
2495 pline("%s stares into your eyes...", Monnam(mtmp));
2496 poisoned("The gaze", A_STR, mtmp->data->mname, 30);
2497 }
2498 break;
2499 case AD_PLYS:
2500 if(!mtmp->mcan && multi >= 0 && canseemon(mtmp) && mtmp->mcansee && !mtmp->mspec_used && rn2(5)) {
2501 pline("%s stares at you!", Monnam(mtmp));
2502 if (Free_action) You("stiffen momentarily.");
2503 else {
2504 You("are frozen by %s!", mon_nam(mtmp));
2505 nomovemsg = 0;
2506 nomul(-rnd(4));
2507 exercise(A_DEX, FALSE);
2508 }
2509 }
2510 break;
2511 case AD_TLPT:
2512 if(!mtmp->mcan && canseemon(mtmp) && mtmp->mcansee && !mtmp->mspec_used && rn2(5)) {
2513 pline("%s stares blinkingly at you!", Monnam(mtmp));
2514 if(flags.verbose)
2515 Your("position suddenly seems very uncertain!");
2516 tele();
2517 }
2518 break;
2519 default: impossible("Gaze attack %d?", mattk->adtyp);
2520 break;
2521 }
2522 return(0);
2523 }
2524
2525 #endif /* OVLB */
2526 #ifdef OVL1
2527
2528 void
mdamageu(mtmp,n)2529 mdamageu(mtmp, n) /* mtmp hits you for n points damage */
2530 register struct monst *mtmp;
2531 register int n;
2532 {
2533
2534 if (Invulnerable) n=0;
2535 if (n == 0) {
2536 pline("You are unharmed.");
2537 return;
2538 }
2539
2540 /* WAC For consistency...DO be careful using techniques ;B */
2541 if (mtmp->mtame != 0 && tech_inuse(T_PRIMAL_ROAR)) {
2542 n *= 2; /* Double Damage! */
2543 }
2544
2545 #ifdef SHOW_DMG
2546 if (flags.showdmg) pline("[%d pts.]", n);
2547 #endif
2548 flags.botl = 1; /* This needs to be AFTER the pline for botl to be
2549 * updated correctly -- Kelly Bailey
2550 */
2551
2552 if (Upolyd) {
2553 u.mh -= n;
2554 if (u.mh < 1) {
2555 if (Polymorph_control || !rn2(3)) {
2556 u.uhp -= mons[u.umonnum].mlevel;
2557 u.uhpmax -= mons[u.umonnum].mlevel;
2558 if (u.uhpmax < 1) u.uhpmax = 1;
2559 }
2560 rehumanize();
2561 }
2562 } else {
2563 u.uhp -= n;
2564 if(u.uhp < 1) done_in_by(mtmp);
2565 }
2566 }
2567
2568 #endif /* OVL1 */
2569 #ifdef OVLB
2570
2571 STATIC_OVL void
urustm(mon,obj)2572 urustm(mon, obj)
2573 register struct monst *mon;
2574 register struct obj *obj;
2575 {
2576 boolean vis;
2577 boolean is_acid;
2578
2579 if (!mon || !obj) return; /* just in case */
2580 if (dmgtype(youmonst.data, AD_CORR))
2581 is_acid = TRUE;
2582 else if (dmgtype(youmonst.data, AD_RUST))
2583 is_acid = FALSE;
2584 else
2585 return;
2586
2587 vis = cansee(mon->mx, mon->my);
2588
2589 if ((is_acid ? is_corrodeable(obj) : is_rustprone(obj)) &&
2590 (is_acid ? obj->oeroded2 : obj->oeroded) < MAX_ERODE) {
2591 if (obj->greased || obj->oerodeproof || (obj->blessed && rn2(3))) {
2592 if (vis) pline("Somehow, %s weapon is not affected.",
2593 s_suffix(mon_nam(mon)));
2594 if (obj->greased && !rn2(2)) obj->greased = 0;
2595 } else {
2596 if (vis) pline("%s %s%s!",
2597 s_suffix(Monnam(mon)),
2598 aobjnam(obj, (is_acid ? "corrode" : "rust")),
2599 (is_acid ? obj->oeroded2 : obj->oeroded)
2600 ? " further" : "");
2601 if (is_acid) obj->oeroded2++;
2602 else obj->oeroded++;
2603 }
2604 }
2605 }
2606
2607 #endif /* OVLB */
2608 #ifdef OVL1
2609
2610 int
could_seduce(magr,mdef,mattk)2611 could_seduce(magr,mdef,mattk)
2612 struct monst *magr, *mdef;
2613 struct attack *mattk;
2614 /* returns 0 if seduction impossible,
2615 * 1 if fine,
2616 * 2 if wrong gender for nymph */
2617 {
2618 register struct permonst *pagr;
2619 boolean agrinvis, defperc;
2620 xchar genagr, gendef;
2621
2622 if (is_animal(magr->data)) return (0);
2623 if(magr == &youmonst) {
2624 pagr = youmonst.data;
2625 agrinvis = (Invis != 0);
2626 genagr = poly_gender();
2627 } else {
2628 pagr = magr->data;
2629 agrinvis = magr->minvis;
2630 genagr = gender(magr);
2631 }
2632 if(mdef == &youmonst) {
2633 defperc = (See_invisible != 0);
2634 gendef = poly_gender();
2635 } else {
2636 defperc = perceives(mdef->data);
2637 gendef = gender(mdef);
2638 }
2639
2640 if(agrinvis && !defperc
2641 #ifdef SEDUCE
2642 && mattk && mattk->adtyp != AD_SSEX
2643 #endif
2644 )
2645 return 0;
2646
2647 if(pagr->mlet != S_NYMPH
2648 && ((pagr != &mons[PM_INCUBUS] && pagr != &mons[PM_SUCCUBUS])
2649 #ifdef SEDUCE
2650 || (mattk && mattk->adtyp != AD_SSEX)
2651 #endif
2652 ))
2653 return 0;
2654
2655 if(genagr == 1 - gendef)
2656 return 1;
2657 else
2658 return (pagr->mlet == S_NYMPH) ? 2 : 0;
2659 }
2660
2661 #endif /* OVL1 */
2662 #ifdef OVLB
2663
2664 #ifdef SEDUCE
2665 /* Returns 1 if monster teleported */
2666 int
doseduce(mon)2667 doseduce(mon)
2668 register struct monst *mon;
2669 {
2670 register struct obj *ring, *nring;
2671 boolean fem = (mon->data == &mons[PM_SUCCUBUS]); /* otherwise incubus */
2672 char qbuf[QBUFSZ];
2673
2674 if (mon->mcan || mon->mspec_used) {
2675 pline("%s acts as though %s has got a %sheadache.",
2676 Monnam(mon), mhe(mon),
2677 mon->mcan ? "severe " : "");
2678 return 0;
2679 }
2680
2681 if (unconscious()) {
2682 pline("%s seems dismayed at your lack of response.",
2683 Monnam(mon));
2684 return 0;
2685 }
2686
2687 if (Blind) pline("It caresses you...");
2688 else You_feel("very attracted to %s.", mon_nam(mon));
2689
2690 for(ring = invent; ring; ring = nring) {
2691 nring = ring->nobj;
2692 if (ring->otyp != RIN_ADORNMENT) continue;
2693 if (fem) {
2694 if (rn2(20) < ACURR(A_CHA)) {
2695 Sprintf(qbuf, "\"That %s looks pretty. May I have it?\"",
2696 safe_qbuf("",sizeof("\"That looks pretty. May I have it?\""),
2697 xname(ring), simple_typename(ring->otyp), "ring"));
2698 makeknown(RIN_ADORNMENT);
2699 if (yn(qbuf) == 'n') continue;
2700 } else pline("%s decides she'd like your %s, and takes it.",
2701 Blind ? "She" : Monnam(mon), xname(ring));
2702 makeknown(RIN_ADORNMENT);
2703 if (ring==uleft || ring==uright) Ring_gone(ring);
2704 if (ring==uwep) setuwep((struct obj *)0, FALSE);
2705 if (ring==uswapwep) setuswapwep((struct obj *)0, FALSE);
2706 if (ring==uquiver) setuqwep((struct obj *)0);
2707 freeinv(ring);
2708 (void) mpickobj(mon,ring);
2709 } else {
2710 char buf[BUFSZ];
2711
2712 if (uleft && uright && uleft->otyp == RIN_ADORNMENT
2713 && uright->otyp==RIN_ADORNMENT)
2714 break;
2715 if (ring==uleft || ring==uright) continue;
2716 if (rn2(20) < ACURR(A_CHA)) {
2717 Sprintf(qbuf,"\"That %s looks pretty. Would you wear it for me?\"",
2718 safe_qbuf("",
2719 sizeof("\"That looks pretty. Would you wear it for me?\""),
2720 xname(ring), simple_typename(ring->otyp), "ring"));
2721 makeknown(RIN_ADORNMENT);
2722 if (yn(qbuf) == 'n') continue;
2723 } else {
2724 pline("%s decides you'd look prettier wearing your %s,",
2725 Blind ? "He" : Monnam(mon), xname(ring));
2726 pline("and puts it on your finger.");
2727 }
2728 makeknown(RIN_ADORNMENT);
2729 if (!uright) {
2730 pline("%s puts %s on your right %s.",
2731 Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND));
2732 setworn(ring, RIGHT_RING);
2733 } else if (!uleft) {
2734 pline("%s puts %s on your left %s.",
2735 Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND));
2736 setworn(ring, LEFT_RING);
2737 } else if (uright && uright->otyp != RIN_ADORNMENT) {
2738 Strcpy(buf, xname(uright));
2739 pline("%s replaces your %s with your %s.",
2740 Blind ? "He" : Monnam(mon), buf, xname(ring));
2741 Ring_gone(uright);
2742 setworn(ring, RIGHT_RING);
2743 } else if (uleft && uleft->otyp != RIN_ADORNMENT) {
2744 Strcpy(buf, xname(uleft));
2745 pline("%s replaces your %s with your %s.",
2746 Blind ? "He" : Monnam(mon), buf, xname(ring));
2747 Ring_gone(uleft);
2748 setworn(ring, LEFT_RING);
2749 } else impossible("ring replacement");
2750 Ring_on(ring);
2751 prinv((char *)0, ring, 0L);
2752 }
2753 }
2754
2755 if (!uarmc && !uarmf && !uarmg && !uarms && !uarmh
2756 #ifdef TOURIST
2757 && !uarmu
2758 #endif
2759 )
2760 pline("%s murmurs sweet nothings into your ear.",
2761 Blind ? (fem ? "She" : "He") : Monnam(mon));
2762 else
2763 pline("%s murmurs in your ear, while helping you undress.",
2764 Blind ? (fem ? "She" : "He") : Monnam(mon));
2765 mayberem(uarmc, cloak_simple_name(uarmc));
2766 if(!uarmc)
2767 mayberem(uarm, "suit");
2768 mayberem(uarmf, "boots");
2769 if(!uwep || !welded(uwep))
2770 mayberem(uarmg, "gloves");
2771 /*
2772 * STEPHEN WHITE'S NEW CODE
2773 *
2774 * This will cause a game crash should the if statment be removed.
2775 * It will try to de-referance a pointer that doesn't exist should
2776 * the player not have a shield
2777 */
2778
2779 if (uarms) mayberem(uarms, "shield");
2780 mayberem(uarmh, "helmet");
2781 #ifdef TOURIST
2782 if(!uarmc && !uarm)
2783 mayberem(uarmu, "shirt");
2784 #endif
2785
2786 if (uarm || uarmc) {
2787 verbalize("You're such a %s; I wish...",
2788 flags.female ? "sweet lady" : "nice guy");
2789 if (!tele_restrict(mon)) (void) rloc(mon, FALSE);
2790 return 1;
2791 }
2792 if (u.ualign.type == A_CHAOTIC)
2793 adjalign(1);
2794
2795 /* by this point you have discovered mon's identity, blind or not... */
2796 pline("Time stands still while you and %s lie in each other's arms...",
2797 noit_mon_nam(mon));
2798 /* Well, IT happened ... */
2799 u.uconduct.celibacy++;
2800
2801 if (rn2(35) > ACURR(A_CHA) + ACURR(A_INT)) {
2802 /* Don't bother with mspec_used here... it didn't get tired! */
2803 pline("%s seems to have enjoyed it more than you...",
2804 noit_Monnam(mon));
2805 switch (rn2(5)) {
2806 case 0: You_feel("drained of energy.");
2807 u.uen = 0;
2808 u.uenmax -= rnd(Half_physical_damage ? 5 : 10);
2809 exercise(A_CON, FALSE);
2810 if (u.uenmax < 0) u.uenmax = 0;
2811 break;
2812 case 1: You("are down in the dumps.");
2813 (void) adjattrib(A_CON, -1, TRUE);
2814 exercise(A_CON, FALSE);
2815 flags.botl = 1;
2816 break;
2817 case 2: Your("senses are dulled.");
2818 (void) adjattrib(A_WIS, -1, TRUE);
2819 exercise(A_WIS, FALSE);
2820 flags.botl = 1;
2821 break;
2822 case 3:
2823 if (!Drain_resistance) {
2824 You_feel("out of shape.");
2825 losexp("overexertion", FALSE);
2826 } else {
2827 You("have a curious feeling...");
2828 }
2829 break;
2830 case 4: {
2831 int tmp;
2832 You_feel("exhausted.");
2833 exercise(A_STR, FALSE);
2834 tmp = rn1(10, 6);
2835 if(Half_physical_damage) tmp = (tmp+1) / 2;
2836 losehp(tmp, "exhaustion", KILLED_BY);
2837 break;
2838 }
2839 }
2840 } else {
2841 mon->mspec_used = rnd(100); /* monster is worn out */
2842 You("seem to have enjoyed it more than %s...",
2843 noit_mon_nam(mon));
2844 switch (rn2(5)) {
2845 case 0: You_feel("raised to your full potential.");
2846 exercise(A_CON, TRUE);
2847 u.uen = (u.uenmax += rnd(5));
2848 break;
2849 case 1: You_feel("good enough to do it again.");
2850 (void) adjattrib(A_CON, 1, TRUE);
2851 exercise(A_CON, TRUE);
2852 flags.botl = 1;
2853 break;
2854 case 2: You("will always remember %s...", noit_mon_nam(mon));
2855 (void) adjattrib(A_WIS, 1, TRUE);
2856 exercise(A_WIS, TRUE);
2857 flags.botl = 1;
2858 break;
2859 case 3: pline("That was a very educational experience.");
2860 pluslvl(FALSE);
2861 exercise(A_WIS, TRUE);
2862 break;
2863 case 4: You_feel("restored to health!");
2864 u.uhp = u.uhpmax;
2865 if (Upolyd) u.mh = u.mhmax;
2866 exercise(A_STR, TRUE);
2867 flags.botl = 1;
2868 break;
2869 }
2870 }
2871
2872 if (mon->mtame) /* don't charge */ ;
2873 else if (rn2(20) < ACURR(A_CHA)) {
2874 pline("%s demands that you pay %s, but you refuse...",
2875 noit_Monnam(mon),
2876 Blind ? (fem ? "her" : "him") : mhim(mon));
2877 } else if (u.umonnum == PM_LEPRECHAUN)
2878 pline("%s tries to take your money, but fails...",
2879 noit_Monnam(mon));
2880 else {
2881 #ifndef GOLDOBJ
2882 long cost;
2883
2884 if (u.ugold > (long)LARGEST_INT - 10L)
2885 cost = (long) rnd(LARGEST_INT) + 500L;
2886 else
2887 cost = (long) rnd((int)u.ugold + 10) + 500L;
2888 if (mon->mpeaceful) {
2889 cost /= 5L;
2890 if (!cost) cost = 1L;
2891 }
2892 if (cost > u.ugold) cost = u.ugold;
2893 if (!cost) verbalize("It's on the house!");
2894 else {
2895 pline("%s takes %ld %s for services rendered!",
2896 noit_Monnam(mon), cost, currency(cost));
2897 u.ugold -= cost;
2898 mon->mgold += cost;
2899 flags.botl = 1;
2900 }
2901 #else
2902 long cost;
2903 long umoney = money_cnt(invent);
2904
2905 if (umoney > (long)LARGEST_INT - 10L)
2906 cost = (long) rnd(LARGEST_INT) + 500L;
2907 else
2908 cost = (long) rnd((int)umoney + 10) + 500L;
2909 if (mon->mpeaceful) {
2910 cost /= 5L;
2911 if (!cost) cost = 1L;
2912 }
2913 if (cost > umoney) cost = umoney;
2914 if (!cost) verbalize("It's on the house!");
2915 else {
2916 pline("%s takes %ld %s for services rendered!",
2917 noit_Monnam(mon), cost, currency(cost));
2918 money2mon(mon, cost);
2919 flags.botl = 1;
2920 }
2921 #endif
2922 }
2923 if (!rn2(25)) mon->mcan = 1; /* monster is worn out */
2924 if (!tele_restrict(mon)) (void) rloc(mon, FALSE);
2925 return 1;
2926 }
2927
2928 STATIC_OVL void
mayberem(obj,str)2929 mayberem(obj, str)
2930 register struct obj *obj;
2931 const char *str;
2932 {
2933 char qbuf[QBUFSZ];
2934
2935 if (!obj || !obj->owornmask) return;
2936
2937 if (rn2(20) < ACURR(A_CHA)) {
2938 Sprintf(qbuf,"\"Shall I remove your %s, %s?\"",
2939 str,
2940 (!rn2(2) ? "lover" : !rn2(2) ? "dear" : "sweetheart"));
2941 if (yn(qbuf) == 'n') return;
2942 } else {
2943 char hairbuf[BUFSZ];
2944
2945 Sprintf(hairbuf, "let me run my fingers through your %s",
2946 body_part(HAIR));
2947 verbalize("Take off your %s; %s.", str,
2948 (obj == uarm) ? "let's get a little closer" :
2949 (obj == uarmc || obj == uarms) ? "it's in the way" :
2950 (obj == uarmf) ? "let me rub your feet" :
2951 (obj == uarmg) ? "they're too clumsy" :
2952 #ifdef TOURIST
2953 (obj == uarmu) ? "let me massage you" :
2954 #endif
2955 /* obj == uarmh */
2956 hairbuf);
2957 }
2958 remove_worn_item(obj, TRUE);
2959 }
2960 #endif /* SEDUCE */
2961
2962 #endif /* OVLB */
2963
2964 #ifdef OVL1
2965
2966 STATIC_OVL int
passiveum(olduasmon,mtmp,mattk)2967 passiveum(olduasmon,mtmp,mattk)
2968 struct permonst *olduasmon;
2969 register struct monst *mtmp;
2970 register struct attack *mattk;
2971 {
2972 int i, tmp;
2973
2974 for(i = 0; ; i++) {
2975 if(i >= NATTK) return 1;
2976 if (olduasmon->mattk[i].aatyp == AT_NONE ||
2977 olduasmon->mattk[i].aatyp == AT_BOOM) break;
2978 }
2979 if (olduasmon->mattk[i].damn)
2980 tmp = d((int)olduasmon->mattk[i].damn,
2981 (int)olduasmon->mattk[i].damd);
2982 else if(olduasmon->mattk[i].damd)
2983 tmp = d((int)olduasmon->mlevel+1, (int)olduasmon->mattk[i].damd);
2984 else
2985 tmp = 0;
2986
2987 /* These affect the enemy even if you were "killed" (rehumanized) */
2988 switch(olduasmon->mattk[i].adtyp) {
2989 case AD_ACID:
2990 if (!rn2(2)) {
2991 pline("%s is splashed by your acid!", Monnam(mtmp));
2992 if (resists_acid(mtmp)) {
2993 pline("%s is not affected.", Monnam(mtmp));
2994 tmp = 0;
2995 }
2996 } else tmp = 0;
2997 if (!rn2(30)) erode_armor(mtmp, TRUE);
2998 if (!rn2(6)) erode_obj(MON_WEP(mtmp), TRUE, TRUE);
2999 goto assess_dmg;
3000 case AD_STON: /* cockatrice */
3001 {
3002 long protector = attk_protection((int)mattk->aatyp),
3003 wornitems = mtmp->misc_worn_check;
3004
3005 /* wielded weapon gives same protection as gloves here */
3006 if (MON_WEP(mtmp) != 0) wornitems |= W_ARMG;
3007
3008 if (!resists_ston(mtmp) && (protector == 0L ||
3009 (protector != ~0L &&
3010 (wornitems & protector) != protector))) {
3011 if (poly_when_stoned(mtmp->data)) {
3012 mon_to_stone(mtmp);
3013 return (1);
3014 }
3015 pline("%s turns to stone!", Monnam(mtmp));
3016 stoned = 1;
3017 xkilled(mtmp, 0);
3018 if (mtmp->mhp > 0) return 1;
3019 return 2;
3020 }
3021 return 1;
3022 }
3023 case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
3024 if (otmp) {
3025 (void) drain_item(otmp);
3026 /* No message */
3027 }
3028 return (1);
3029 default:
3030 break;
3031 }
3032 if (!Upolyd) return 1;
3033
3034 /* These affect the enemy only if you are still a monster */
3035 if (rn2(3)) switch(youmonst.data->mattk[i].adtyp) {
3036 case AD_PHYS:
3037 if (youmonst.data->mattk[i].aatyp == AT_BOOM) {
3038 You("explode!");
3039 /* KMH, balance patch -- this is okay with unchanging */
3040 rehumanize();
3041 goto assess_dmg;
3042 }
3043 break;
3044 case AD_PLYS: /* Floating eye */
3045 if (tmp > 127) tmp = 127;
3046 if (u.umonnum == PM_FLOATING_EYE) {
3047 if (!rn2(4)) tmp = 127;
3048 if (mtmp->mcansee && haseyes(mtmp->data) && rn2(3) &&
3049 (perceives(mtmp->data) || !Invis)) {
3050 if (Blind)
3051 pline("As a blind %s, you cannot defend yourself.",
3052 youmonst.data->mname);
3053 else {
3054 if (mon_reflects(mtmp,
3055 "Your gaze is reflected by %s %s."))
3056 return 1;
3057 pline("%s is frozen by your gaze!", Monnam(mtmp));
3058 mtmp->mcanmove = 0;
3059 mtmp->mfrozen = tmp;
3060 return 3;
3061 }
3062 }
3063 } else { /* gelatinous cube */
3064 pline("%s is frozen by you.", Monnam(mtmp));
3065 mtmp->mcanmove = 0;
3066 mtmp->mfrozen = tmp;
3067 return 3;
3068 }
3069 return 1;
3070 case AD_COLD: /* Brown mold or blue jelly */
3071 if (resists_cold(mtmp)) {
3072 shieldeff(mtmp->mx, mtmp->my);
3073 pline("%s is mildly chilly.", Monnam(mtmp));
3074 golemeffects(mtmp, AD_COLD, tmp);
3075 tmp = 0;
3076 break;
3077 }
3078 pline("%s is suddenly very cold!", Monnam(mtmp));
3079 u.mh += tmp / 2;
3080 if (u.mhmax < u.mh) u.mhmax = u.mh;
3081 if (u.mhmax > ((youmonst.data->mlevel+1) * 8))
3082 (void)split_mon(&youmonst, mtmp);
3083 break;
3084 case AD_STUN: /* Yellow mold */
3085 if (!mtmp->mstun) {
3086 mtmp->mstun = 1;
3087 pline("%s %s.", Monnam(mtmp),
3088 makeplural(stagger(mtmp->data, "stagger")));
3089 }
3090 tmp = 0;
3091 break;
3092 case AD_FIRE: /* Red mold */
3093 if (resists_fire(mtmp)) {
3094 shieldeff(mtmp->mx, mtmp->my);
3095 pline("%s is mildly warm.", Monnam(mtmp));
3096 golemeffects(mtmp, AD_FIRE, tmp);
3097 tmp = 0;
3098 break;
3099 }
3100 pline("%s is suddenly very hot!", Monnam(mtmp));
3101 break;
3102 case AD_ELEC:
3103 if (resists_elec(mtmp)) {
3104 shieldeff(mtmp->mx, mtmp->my);
3105 pline("%s is slightly tingled.", Monnam(mtmp));
3106 golemeffects(mtmp, AD_ELEC, tmp);
3107 tmp = 0;
3108 break;
3109 }
3110 pline("%s is jolted with your electricity!", Monnam(mtmp));
3111 break;
3112 default: tmp = 0;
3113 break;
3114 }
3115 else tmp = 0;
3116
3117 assess_dmg:
3118 if((mtmp->mhp -= tmp) <= 0) {
3119 pline("%s dies!", Monnam(mtmp));
3120 xkilled(mtmp,0);
3121 if (mtmp->mhp > 0) return 1;
3122 return 2;
3123 }
3124 return 1;
3125 }
3126
3127 #endif /* OVL1 */
3128 #ifdef OVLB
3129
3130 #include "edog.h"
3131 struct monst *
cloneu()3132 cloneu()
3133 {
3134 register struct monst *mon;
3135 int mndx = monsndx(youmonst.data);
3136
3137 if (u.mh <= 1) return(struct monst *)0;
3138 if (mvitals[mndx].mvflags & G_EXTINCT) return(struct monst *)0;
3139 mon = makemon(youmonst.data, u.ux, u.uy, NO_MINVENT|MM_EDOG);
3140 mon = christen_monst(mon, plname);
3141 initedog(mon);
3142 mon->m_lev = youmonst.data->mlevel;
3143 mon->mhpmax = u.mhmax;
3144 mon->mhp = u.mh / 2;
3145 u.mh -= mon->mhp;
3146 flags.botl = 1;
3147 return(mon);
3148 }
3149
3150 #endif /* OVLB */
3151
3152 /*mhitu.c*/
3153