1 /* SCCS Id: @(#)mhitu.c 3.3 2000/04/19 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 #include "hack.h"
6 #include "artifact.h"
7
8 STATIC_VAR NEARDATA struct obj *otmp;
9
10 STATIC_DCL void FDECL(urustm, (struct monst *, struct obj *));
11 # ifdef OVL1
12 STATIC_DCL boolean FDECL(u_slip_free, (struct monst *,struct attack *));
13 STATIC_DCL int FDECL(passiveum, (struct permonst *,struct monst *,struct attack *));
14 # endif /* OVL1 */
15
16 #ifdef OVLB
17 # ifdef SEDUCE
18 STATIC_DCL void FDECL(mayberem, (struct obj *, const char *));
19 # endif
20 #endif /* OVLB */
21
22 STATIC_DCL boolean FDECL(diseasemu, (struct permonst *));
23 STATIC_DCL int FDECL(hitmu, (struct monst *,struct attack *));
24 STATIC_DCL int FDECL(gulpmu, (struct monst *,struct attack *));
25 STATIC_DCL int FDECL(explmu, (struct monst *,struct attack *,BOOLEAN_P));
26 STATIC_DCL void FDECL(missmu,(struct monst *,BOOLEAN_P,struct attack *));
27 STATIC_DCL void FDECL(mswings,(struct monst *,struct obj *));
28 STATIC_DCL void FDECL(wildmiss, (struct monst *,struct attack *));
29
30 STATIC_DCL void FDECL(hurtarmor,(int));
31 STATIC_DCL void FDECL(hitmsg,(struct monst *,struct attack *));
32
33 /* See comment in mhitm.c. If we use this a lot it probably should be */
34 /* changed to a parameter to mhitu. */
35 static int dieroll;
36
37 #ifdef OVL1
38
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))
50 && !mtmp->mcan && !mtmp->mspec_used) {
51 pline("%s %s you %s.", Monnam(mtmp),
52 Blind ? "talks to" : "smiles at",
53 compat == 2 ? "engagingly" : "seductively");
54 } else
55 switch (mattk->aatyp) {
56 case AT_BITE:
57 pline("%s bites!", Monnam(mtmp));
58 break;
59 case AT_KICK:
60 pline("%s kicks%c", Monnam(mtmp),
61 thick_skinned(youmonst.data) ? '.' : '!');
62 break;
63 case AT_STNG:
64 pline("%s stings!", Monnam(mtmp));
65 break;
66 case AT_BUTT:
67 pline("%s butts!", Monnam(mtmp));
68 break;
69 case AT_TUCH:
70 pline("%s touches you!", Monnam(mtmp));
71 break;
72 case AT_TENT:
73 pline("%s tentacles suck you!",
74 s_suffix(Monnam(mtmp)));
75 break;
76 case AT_EXPL:
77 case AT_BOOM:
78 pline("%s explodes!", Monnam(mtmp));
79 break;
80 default:
81 pline("%s hits!", Monnam(mtmp));
82 }
83 }
84
85 STATIC_OVL void
missmu(mtmp,nearmiss,mattk)86 missmu(mtmp, nearmiss, mattk) /* monster missed you */
87 register struct monst *mtmp;
88 register boolean nearmiss;
89 register struct attack *mattk;
90 {
91 if (!canspotmon(mtmp))
92 map_invisible(mtmp->mx, mtmp->my);
93
94 if(could_seduce(mtmp, &youmonst, mattk) && !mtmp->mcan)
95 pline("%s pretends to be friendly.", Monnam(mtmp));
96 else {
97 if (!flags.verbose || !nearmiss)
98 pline("%s misses.", Monnam(mtmp));
99 else
100 pline("%s just misses!", Monnam(mtmp));
101 }
102 }
103
104 STATIC_OVL void
mswings(mtmp,otemp)105 mswings(mtmp, otemp) /* monster swings obj */
106 register struct monst *mtmp;
107 register struct obj *otemp;
108 {
109 if (!flags.verbose || Blind || !mon_visible(mtmp))
110 return;
111 pline("%s %s %s %s.", Monnam(mtmp),
112 (objects[otemp->otyp].oc_dir & PIERCE) ? "thrusts" : "swings",
113 his[pronoun_gender(mtmp)], xname(otemp));
114 }
115
116 /* return how a poison attack was delivered */
117 const char *
mpoisons_subj(mtmp,mattk)118 mpoisons_subj(mtmp, mattk)
119 struct monst *mtmp;
120 struct attack *mattk;
121 {
122 if (mattk->aatyp == AT_WEAP) {
123 struct obj *mwep = (mtmp == &youmonst) ? uwep : MON_WEP(mtmp);
124 /* "Foo's attack was poisoned." is pretty lame, but at least
125 it's better than "sting" when not a stinging attack... */
126 return (!mwep || !mwep->opoisoned) ? "attack" : "weapon";
127 } else {
128 return (mattk->aatyp == AT_TUCH) ? "contact" :
129 (mattk->aatyp == AT_GAZE) ? "gaze" :
130 (mattk->aatyp == AT_BITE) ? "bite" : "sting";
131 }
132 }
133
134 /* called when your intrinsic speed is taken away */
135 void
u_slow_down()136 u_slow_down()
137 {
138 HFast = 0L;
139 if (!Fast)
140 You("slow down.");
141 else /* speed boots */
142 Your("quickness feels less natural.");
143 exercise(A_DEX, FALSE);
144 }
145
146 #endif /* OVL1 */
147 #ifdef OVLB
148
149 STATIC_OVL void
wildmiss(mtmp,mattk)150 wildmiss(mtmp, mattk) /* monster attacked your displaced image */
151 register struct monst *mtmp;
152 register struct attack *mattk;
153 {
154 int compat;
155
156 /* no map_invisible() -- no way to tell where _this_ is coming from */
157
158 if (!flags.verbose) return;
159 if (!cansee(mtmp->mx, mtmp->my)) return;
160 /* maybe it's attacking an image around the corner? */
161
162 compat = (mattk->adtyp == AD_SEDU || mattk->adtyp == AD_SSEX) &&
163 could_seduce(mtmp, &youmonst, (struct attack *)0);
164
165 if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) {
166 const char *swings =
167 mattk->aatyp == AT_BITE ? "snaps" :
168 mattk->aatyp == AT_KICK ? "kicks" :
169 (mattk->aatyp == AT_STNG ||
170 mattk->aatyp == AT_BUTT ||
171 nolimbs(mtmp->data)) ? "lunges" : "swings";
172
173 if (compat)
174 pline("%s tries to touch you and misses!", Monnam(mtmp));
175 else
176 switch(rn2(3)) {
177 case 0: pline("%s %s wildly and misses!", Monnam(mtmp),
178 swings);
179 break;
180 case 1: pline("%s attacks a spot beside you.", Monnam(mtmp));
181 break;
182 case 2: pline("%s strikes at %s!", Monnam(mtmp),
183 levl[mtmp->mux][mtmp->muy].typ == WATER
184 ? "empty water" : "thin air");
185 break;
186 default:pline("%s %s wildly!", Monnam(mtmp), swings);
187 break;
188 }
189
190 } else if (Displaced) {
191 if (compat)
192 pline("%s smiles %s at your %sdisplaced image...",
193 Monnam(mtmp),
194 compat == 2 ? "engagingly" : "seductively",
195 Invis ? "invisible " : "");
196 else
197 pline("%s strikes at your %sdisplaced image and misses you!",
198 /* Note: if you're both invisible and displaced,
199 * only monsters which see invisible will attack your
200 * displaced image, since the displaced image is also
201 * invisible.
202 */
203 Monnam(mtmp),
204 Invis ? "invisible " : "");
205
206 } else if (Underwater) {
207 /* monsters may miss especially on water level where
208 bubbles shake the player here and there */
209 if (compat)
210 pline("%s reaches towards your distorted image.",Monnam(mtmp));
211 else
212 pline("%s is fooled by water reflections and misses!",Monnam(mtmp));
213
214 } else impossible("%s attacks you without knowing your location?",
215 Monnam(mtmp));
216 }
217
218 void
expels(mtmp,mdat,message)219 expels(mtmp, mdat, message)
220 register struct monst *mtmp;
221 register struct permonst *mdat; /* if mtmp is polymorphed, mdat != mtmp->data */
222 boolean message;
223 {
224 if (message) {
225 if (is_animal(mdat))
226 You("get regurgitated!");
227 else {
228 char blast[40];
229 register int i;
230
231 blast[0] = '\0';
232 for(i = 0; i < NATTK; i++)
233 if(mdat->mattk[i].aatyp == AT_ENGL)
234 break;
235 if (mdat->mattk[i].aatyp != AT_ENGL)
236 impossible("Swallower has no engulfing attack?");
237 else {
238 if (is_whirly(mdat)) {
239 switch (mdat->mattk[i].adtyp) {
240 case AD_ELEC:
241 Strcpy(blast,
242 " in a shower of sparks");
243 break;
244 case AD_COLD:
245 Strcpy(blast,
246 " in a blast of frost");
247 break;
248 }
249 } else
250 Strcpy(blast, " with a squelch");
251 You("get expelled from %s%s!",
252 mon_nam(mtmp), blast);
253 }
254 }
255 }
256 unstuck(mtmp); /* ball&chain returned in unstuck() */
257 mnexto(mtmp);
258 newsym(u.ux,u.uy);
259 spoteffects(TRUE);
260 /* to cover for a case where mtmp is not in a next square */
261 if(um_dist(mtmp->mx,mtmp->my,1))
262 pline("Brrooaa... You land hard at some distance.");
263 }
264
265 #endif /* OVLB */
266 #ifdef OVL0
267
268 /*
269 * mattacku: monster attacks you
270 * returns 1 if monster dies (e.g. "yellow light"), 0 otherwise
271 * Note: if you're displaced or invisible the monster might attack the
272 * wrong position...
273 * Assumption: it's attacking you or an empty square; if there's another
274 * monster which it attacks by mistake, the caller had better
275 * take care of it...
276 */
277 int
mattacku(mtmp)278 mattacku(mtmp)
279 register struct monst *mtmp;
280 {
281 struct attack *mattk;
282 int i, j, tmp, sum[NATTK];
283 struct permonst *mdat = mtmp->data;
284 boolean ranged = (distu(mtmp->mx, mtmp->my) > 3);
285 /* Is it near you? Affects your actions */
286 boolean range2 = !monnear(mtmp, mtmp->mux, mtmp->muy);
287 /* Does it think it's near you? Affects its actions */
288 boolean foundyou = (mtmp->mux==u.ux && mtmp->muy==u.uy);
289 /* Is it attacking you or your image? */
290 boolean youseeit = canseemon(mtmp);
291 /* Might be attacking your image around the corner, or
292 * invisible, or you might be blind....
293 */
294
295 if(!ranged) nomul(0);
296 if(mtmp->mhp <= 0 || (Underwater && !is_swimmer(mtmp->data)))
297 return(0);
298
299 /* If swallowed, can only be affected by u.ustuck */
300 if(u.uswallow) {
301 if(mtmp != u.ustuck)
302 return(0);
303 u.ustuck->mux = u.ux;
304 u.ustuck->muy = u.uy;
305 range2 = 0;
306 foundyou = 1;
307 if(u.uinvulnerable) return (0); /* stomachs can't hurt you! */
308 }
309
310 #ifdef STEED
311 else if (u.usteed) {
312 if (mtmp == u.usteed)
313 /* Your steed won't attack you */
314 return (0);
315 /* Orcs like to steal and eat horses and the like */
316 if (!rn2(is_orc(mtmp->data) ? 2 : 4) &&
317 distu(mtmp->mx, mtmp->my) <= 2) {
318 /* Attack your steed instead */
319 i = mattackm(mtmp, u.usteed);
320 if ((i & MM_AGR_DIED))
321 return (1);
322 if (i & MM_DEF_DIED || u.ux != u.ux0 || u.uy != u.uy0)
323 return (0);
324 /* Let your steed retaliate */
325 return (!!(mattackm(u.usteed, mtmp) & MM_DEF_DIED));
326 }
327 }
328 #endif
329
330 if (u.uundetected && !range2 && foundyou && !u.uswallow) {
331 u.uundetected = 0;
332 if (is_hider(youmonst.data)) {
333 coord cc; /* maybe we need a unexto() function? */
334
335 You("fall from the %s!", ceiling(u.ux,u.uy));
336 if (enexto(&cc, u.ux, u.uy, youmonst.data)) {
337 remove_monster(mtmp->mx, mtmp->my);
338 newsym(mtmp->mx,mtmp->my);
339 place_monster(mtmp, u.ux, u.uy);
340 if(mtmp->wormno) worm_move(mtmp);
341 teleds(cc.x, cc.y);
342 set_apparxy(mtmp);
343 newsym(u.ux,u.uy);
344 } else {
345 pline("%s is killed by a falling %s (you)!",
346 Monnam(mtmp), youmonst.data->mname);
347 killed(mtmp);
348 newsym(u.ux,u.uy);
349 if (mtmp->mhp > 0) return 0;
350 else return 1;
351 }
352 if (youmonst.data->mlet != S_PIERCER)
353 return(0); /* trappers don't attack */
354
355 if (which_armor(mtmp, WORN_HELMET)) {
356 Your("blow glances off %s helmet.",
357 s_suffix(mon_nam(mtmp)));
358 } else {
359 if (3 + find_mac(mtmp) <= rnd(20)) {
360 pline("%s is hit by a falling piercer (you)!",
361 Monnam(mtmp));
362 if ((mtmp->mhp -= d(3,6)) < 1)
363 killed(mtmp);
364 } else
365 pline("%s is almost hit by a falling piercer (you)!",
366 Monnam(mtmp));
367 }
368 } else {
369 if (!youseeit)
370 pline("It tries to move where you are hiding.");
371 else {
372 /* Ugly kludge for eggs. The message is phrased so as
373 * to be directed at the monster, not the player,
374 * which makes "laid by you" wrong. For the
375 * parallelism to work, we can't rephrase it, so we
376 * zap the "laid by you" momentarily instead.
377 */
378 struct obj *obj = level.objects[u.ux][u.uy];
379
380 if (obj ||
381 (youmonst.data->mlet == S_EEL && is_pool(u.ux, u.uy))) {
382 int save_spe = 0; /* suppress warning */
383 if (obj) {
384 save_spe = obj->spe;
385 if (obj->otyp == EGG) obj->spe = 0;
386 }
387 if (youmonst.data->mlet == S_EEL)
388 pline("Wait, %s! There's a hidden %s named %s there!",
389 m_monnam(mtmp), youmonst.data->mname, plname);
390 else
391 pline("Wait, %s! There's a %s named %s hiding under %s!",
392 m_monnam(mtmp), youmonst.data->mname, plname,
393 doname(level.objects[u.ux][u.uy]));
394 if (obj) obj->spe = save_spe;
395 } else
396 impossible("hiding under nothing?");
397 }
398 newsym(u.ux,u.uy);
399 }
400 return(0);
401 }
402 if (youmonst.data->mlet == S_MIMIC && youmonst.m_ap_type && !range2 && foundyou && !u.uswallow) {
403 if (!youseeit) pline("It gets stuck on you.");
404 else pline("Wait, %s! That's a %s named %s!",
405 m_monnam(mtmp), youmonst.data->mname, plname);
406 u.ustuck = mtmp;
407 youmonst.m_ap_type = M_AP_NOTHING;
408 youmonst.mappearance = 0;
409 newsym(u.ux,u.uy);
410 return(0);
411 }
412
413 /* player might be mimicking gold */
414 if (youmonst.m_ap_type == M_AP_OBJECT
415 && youmonst.mappearance == GOLD_PIECE
416 && !range2 && foundyou && !u.uswallow) {
417 if (!youseeit)
418 pline("%s %s!", Something, likes_gold(mtmp->data) ?
419 "tries to pick you up" : "disturbs you");
420 else pline("Wait, %s! That gold is really %s named %s!",
421 m_monnam(mtmp),
422 an(mons[u.umonnum].mname),
423 plname);
424 if (multi < 0) { /* this should always be the case */
425 char buf[BUFSZ];
426 Sprintf(buf, "You appear to be %s again.",
427 Upolyd ? (const char *) an(youmonst.data->mname) :
428 (const char *) "yourself");
429 unmul(buf); /* immediately stop mimicking gold */
430 }
431 return 0;
432 }
433
434 /* Work out the armor class differential */
435 tmp = AC_VALUE(u.uac) + 10; /* tmp ~= 0 - 20 */
436 tmp += mtmp->m_lev;
437 if(multi < 0) tmp += 4;
438 if((Invis && !perceives(mdat)) || !mtmp->mcansee)
439 tmp -= 2;
440 if(mtmp->mtrapped) tmp -= 2;
441 if(tmp <= 0) tmp = 1;
442
443 /* make eels visible the moment they hit/miss us */
444 if(mdat->mlet == S_EEL && mtmp->minvis && cansee(mtmp->mx,mtmp->my)) {
445 mtmp->minvis = 0;
446 newsym(mtmp->mx,mtmp->my);
447 }
448
449 /* Special demon handling code */
450 if(!mtmp->cham && is_demon(mdat) && !range2
451 && mtmp->data != &mons[PM_BALROG]
452 && mtmp->data != &mons[PM_SUCCUBUS]
453 && mtmp->data != &mons[PM_INCUBUS])
454 if(!mtmp->mcan && !rn2(13)) msummon(mdat);
455
456 /* Special lycanthrope handling code */
457 if(!mtmp->cham && is_were(mdat) && !range2) {
458
459 if(is_human(mdat)) {
460 if(!rn2(5 - (night() * 2)) && !mtmp->mcan) new_were(mtmp);
461 } else if(!rn2(30) && !mtmp->mcan) new_were(mtmp);
462 mdat = mtmp->data;
463
464 if(!rn2(10) && !mtmp->mcan) {
465 if(youseeit) {
466 pline("%s summons help!", Monnam(mtmp));
467 } else
468 You_feel("hemmed in.");
469 /* Technically wrong; we really should check if you can see the
470 * help, but close enough...
471 */
472 if (!were_summon(mdat,FALSE) && youseeit)
473 pline("But none comes.");
474 }
475 }
476
477 if(u.uinvulnerable) {
478 /* monster's won't attack you */
479 if(mtmp == u.ustuck)
480 pline("%s loosens its grip slightly.", Monnam(mtmp));
481 else if(!range2) {
482 if(youseeit)
483 pline("%s starts to attack you, but pulls back.",
484 Monnam(mtmp));
485 else
486 You_feel("%s move nearby.", something);
487 }
488 return (0);
489 }
490
491 /* Unlike defensive stuff, don't let them use item _and_ attack. */
492 if(find_offensive(mtmp)) {
493 int foo = use_offensive(mtmp);
494
495 if (foo != 0) return(foo==1);
496 }
497
498 for(i = 0; i < NATTK; i++) {
499
500 sum[i] = 0;
501 mattk = &(mdat->mattk[i]);
502 if (u.uswallow && (mattk->aatyp != AT_ENGL))
503 continue;
504 switch(mattk->aatyp) {
505 case AT_CLAW: /* "hand to hand" attacks */
506 case AT_KICK:
507 case AT_BITE:
508 case AT_STNG:
509 case AT_TUCH:
510 case AT_BUTT:
511 case AT_TENT:
512 if(!range2 && (!MON_WEP(mtmp) || mtmp->mconf || Conflict ||
513 !touch_petrifies(youmonst.data))) {
514 if (foundyou) {
515 if(tmp > (j = rnd(20+i))) {
516 if (mattk->aatyp != AT_KICK ||
517 !thick_skinned(youmonst.data))
518 sum[i] = hitmu(mtmp, mattk);
519 } else
520 missmu(mtmp, (tmp == j), mattk);
521 } else
522 wildmiss(mtmp, mattk);
523 }
524 break;
525
526 case AT_HUGS: /* automatic if prev two attacks succeed */
527 /* Note: if displaced, prev attacks never succeeded */
528 if((!range2 && i>=2 && sum[i-1] && sum[i-2])
529 || mtmp == u.ustuck)
530 sum[i]= hitmu(mtmp, mattk);
531 break;
532
533 case AT_GAZE: /* can affect you either ranged or not */
534 /* Medusa gaze already operated through m_respond in
535 * dochug(); don't gaze more than once per round.
536 */
537 if (mdat != &mons[PM_MEDUSA])
538 sum[i] = gazemu(mtmp, mattk);
539 break;
540
541 case AT_EXPL: /* automatic hit if next to, and aimed at you */
542 if(!range2) sum[i] = explmu(mtmp, mattk, foundyou);
543 break;
544
545 case AT_ENGL:
546 if (!range2) {
547 if(foundyou) {
548 if(u.uswallow || tmp > (j = rnd(20+i))) {
549 /* Force swallowing monster to be
550 * displayed even when player is
551 * moving away */
552 flush_screen(1);
553 sum[i] = gulpmu(mtmp, mattk);
554 } else {
555 missmu(mtmp, (tmp == j), mattk);
556 }
557 } else if (is_animal(mtmp->data))
558 pline("%s gulps some air!", youseeit ?
559 Monnam(mtmp) : "It");
560 else
561 if (youseeit)
562 pline("%s lunges forward and recoils!",
563 Monnam(mtmp));
564 else
565 You_hear("a %s nearby.",
566 is_whirly(mtmp->data)?
567 "rushing noise" :
568 "splat");
569 }
570 break;
571 case AT_BREA:
572 if(range2) sum[i] = breamu(mtmp, mattk);
573 /* Note: breamu takes care of displacement */
574 break;
575 case AT_SPIT:
576 if(range2) sum[i] = spitmu(mtmp, mattk);
577 /* Note: spitmu takes care of displacement */
578 break;
579 case AT_WEAP:
580 if(range2) {
581 #ifdef REINCARNATION
582 if (!Is_rogue_level(&u.uz))
583 #endif
584 thrwmu(mtmp);
585 } else {
586 int hittmp = 0;
587
588 /* Rare but not impossible. Normally the monster
589 * wields when 2 spaces away, but it can be
590 * teleported or whatever....
591 */
592 if (mtmp->weapon_check == NEED_WEAPON ||
593 !MON_WEP(mtmp)) {
594 mtmp->weapon_check = NEED_HTH_WEAPON;
595 /* mon_wield_item resets weapon_check as
596 * appropriate */
597 if (mon_wield_item(mtmp) != 0) break;
598 }
599 if (foundyou) {
600 possibly_unwield(mtmp);
601 otmp = MON_WEP(mtmp);
602 if(otmp) {
603 hittmp = hitval(otmp, &youmonst);
604 tmp += hittmp;
605 mswings(mtmp, otmp);
606 }
607 if(tmp > (j = dieroll = rnd(20+i)))
608 sum[i] = hitmu(mtmp, mattk);
609 else
610 missmu(mtmp, (tmp == j), mattk);
611 /* KMH -- Don't accumulate to-hit bonuses */
612 if (otmp)
613 tmp -= hittmp;
614 } else
615 wildmiss(mtmp, mattk);
616 }
617 break;
618 case AT_MAGC:
619 if (range2)
620 sum[i] = buzzmu(mtmp, mattk);
621 else
622 if (foundyou)
623 sum[i] = castmu(mtmp, mattk);
624 else
625 pline("%s casts a spell at %s!",
626 youseeit ? Monnam(mtmp) : "It",
627 levl[mtmp->mux][mtmp->muy].typ == WATER
628 ? "empty water" : "thin air");
629 /* FIXME: castmu includes spells that are not
630 * cast at the player and thus should be
631 * possible whether the monster knows your
632 * location or not.
633 * --KAA
634 */
635 break;
636
637 default: /* no attack */
638 break;
639 }
640 if(flags.botl) bot();
641 /* give player a chance of waking up before dying -kaa */
642 if(sum[i] == 1) { /* successful attack */
643 if (u.usleep && u.usleep < monstermoves && !rn2(10)) {
644 multi = -1;
645 nomovemsg = "The combat suddenly awakens you.";
646 }
647 }
648 if(sum[i] == 2) return 1; /* attacker dead */
649 if(sum[i] == 3) break; /* attacker teleported, no more attacks */
650 /* sum[i] == 0: unsuccessful attack */
651 }
652 return(0);
653 }
654
655 #endif /* OVL0 */
656 #ifdef OVLB
657
658 /*
659 * helper function for some compilers that have trouble with hitmu
660 */
661
662 STATIC_OVL void
hurtarmor(attk)663 hurtarmor(attk)
664 int attk;
665 {
666 int hurt;
667
668 switch(attk) {
669 /* 0 is burning, which we should never be called with */
670 case AD_RUST: hurt = 1; break;
671 case AD_CORRODE: hurt = 3; break;
672 default: hurt = 2; break;
673 }
674
675 /* What the following code does: it keeps looping until it
676 * finds a target for the rust monster.
677 * Head, feet, etc... not covered by metal, or covered by
678 * rusty metal, are not targets. However, your body always
679 * is, no matter what covers it.
680 */
681 while (1) {
682 switch(rn2(5)) {
683 case 0:
684 if (!uarmh || !rust_dmg(uarmh, xname(uarmh), hurt, FALSE, &youmonst))
685 continue;
686 break;
687 case 1:
688 if (uarmc) {
689 (void)rust_dmg(uarmc, xname(uarmc), hurt, TRUE, &youmonst);
690 break;
691 }
692 /* Note the difference between break and continue;
693 * break means it was hit and didn't rust; continue
694 * means it wasn't a target and though it didn't rust
695 * something else did.
696 */
697 if (uarm)
698 (void)rust_dmg(uarm, xname(uarm), hurt, TRUE, &youmonst);
699 #ifdef TOURIST
700 else if (uarmu)
701 (void)rust_dmg(uarmu, xname(uarmu), hurt, TRUE, &youmonst);
702 #endif
703 break;
704 case 2:
705 if (!uarms || !rust_dmg(uarms, xname(uarms), hurt, FALSE, &youmonst))
706 continue;
707 break;
708 case 3:
709 if (!uarmg || !rust_dmg(uarmg, xname(uarmg), hurt, FALSE, &youmonst))
710 continue;
711 break;
712 case 4:
713 if (!uarmf || !rust_dmg(uarmf, xname(uarmf), hurt, FALSE, &youmonst))
714 continue;
715 break;
716 }
717 break; /* Out of while loop */
718 }
719 }
720
721 #endif /* OVLB */
722 #ifdef OVL1
723
724 STATIC_OVL boolean
diseasemu(mdat)725 diseasemu(mdat)
726 struct permonst *mdat;
727 {
728 if (Sick_resistance) {
729 You_feel("a slight illness.");
730 return FALSE;
731 } else {
732 make_sick(Sick ? Sick/3L + 1L : (long)rn1(ACURR(A_CON), 20),
733 mdat->mname, TRUE, SICK_NONVOMITABLE);
734 return TRUE;
735 }
736 }
737
738 /* check whether slippery clothing protects from hug or wrap attack */
739 STATIC_OVL boolean
u_slip_free(mtmp,mattk)740 u_slip_free(mtmp, mattk)
741 struct monst *mtmp;
742 struct attack *mattk;
743 {
744 struct obj *obj = (uarmc ? uarmc : uarm);
745
746 #ifdef TOURIST
747 if (!obj) obj = uarmu;
748 #endif
749 if (mattk->adtyp == AD_DRIN) obj = uarmh;
750
751 /* if your cloak/armor is greased, monster slips off; this
752 protection might fail (33% chance) when the armor is cursed */
753 if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK) &&
754 (!obj->cursed || rn2(3))) {
755 pline("%s %s your %s %s!",
756 Monnam(mtmp),
757 (mattk->adtyp == AD_WRAP) ?
758 "slips off of" : "grabs you, but cannot hold onto",
759 obj->greased ? "greased" : "slippery",
760 /* avoid "slippery slippery cloak"
761 for undiscovered oilskin cloak */
762 (obj->greased || objects[obj->otyp].oc_name_known) ?
763 xname(obj) : "cloak");
764
765 if (obj->greased && !rn2(2)) {
766 pline_The("grease wears off.");
767 obj->greased = 0;
768 }
769 return TRUE;
770 }
771 return FALSE;
772 }
773
774 /*
775 * hitmu: monster hits you
776 * returns 2 if monster dies (e.g. "yellow light"), 1 otherwise
777 * 3 if the monster lives but teleported/paralyzed, so it can't keep
778 * attacking you
779 */
780 STATIC_OVL int
hitmu(mtmp,mattk)781 hitmu(mtmp, mattk)
782 register struct monst *mtmp;
783 register struct attack *mattk;
784 {
785 register struct permonst *mdat = mtmp->data;
786 register int uncancelled, ptmp;
787 int dmg, armpro;
788 char buf[BUFSZ];
789 struct permonst *olduasmon = youmonst.data;
790 int res;
791
792 if (!canspotmon(mtmp))
793 map_invisible(mtmp->mx, mtmp->my);
794
795 /* If the monster is undetected & hits you, you should know where
796 * the attack came from.
797 */
798 if(mtmp->mundetected && (hides_under(mdat) || mdat->mlet == S_EEL)) {
799 mtmp->mundetected = 0;
800 if (!(Blind ? Blind_telepat : Unblind_telepat)) {
801 struct obj *obj;
802 const char *what;
803
804 if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0) {
805 if (Blind && !obj->dknown)
806 what = something;
807 else if (is_pool(mtmp->mx, mtmp->my) && !Underwater)
808 what = "the water";
809 else
810 what = doname(obj);
811
812 pline("%s was hidden under %s!", Amonnam(mtmp), what);
813 }
814 newsym(mtmp->mx, mtmp->my);
815 }
816 }
817
818 /* First determine the base damage done */
819 dmg = d((int)mattk->damn, (int)mattk->damd);
820 if(is_undead(mdat) && midnight())
821 dmg += d((int)mattk->damn, (int)mattk->damd); /* extra damage */
822
823 /* Next a cancellation factor */
824 /* Use uncancelled when the cancellation factor takes into account certain
825 * armor's special magic protection. Otherwise just use !mtmp->mcan.
826 */
827 armpro = 0;
828 if (uarm && armpro < objects[uarm->otyp].a_can)
829 armpro = objects[uarm->otyp].a_can;
830 if (uarmc && armpro < objects[uarmc->otyp].a_can)
831 armpro = objects[uarmc->otyp].a_can;
832 if (uarmh && armpro < objects[uarmh->otyp].a_can)
833 armpro = objects[uarmh->otyp].a_can;
834 uncancelled = !mtmp->mcan && ((rn2(3) >= armpro) || !rn2(50));
835
836 /* Now, adjust damages via resistances or specific attacks */
837 switch(mattk->adtyp) {
838 case AD_PHYS:
839 if (mattk->aatyp == AT_HUGS && !sticks(youmonst.data)) {
840 if(!u.ustuck && rn2(2)) {
841 if (u_slip_free(mtmp, mattk)) {
842 dmg = 0;
843 } else {
844 u.ustuck = mtmp;
845 pline("%s grabs you!", Monnam(mtmp));
846 }
847 } else if(u.ustuck == mtmp) {
848 exercise(A_STR, FALSE);
849 You("are being %s.",
850 (mtmp->data == &mons[PM_ROPE_GOLEM])
851 ? "choked" : "crushed");
852 }
853 } else { /* hand to hand weapon */
854 if(mattk->aatyp == AT_WEAP && otmp) {
855 if (otmp->otyp == CORPSE
856 && touch_petrifies(&mons[otmp->corpsenm])) {
857 dmg = 1;
858 pline("%s hits you with the %s corpse.",
859 Monnam(mtmp), mons[otmp->corpsenm].mname);
860 if (!Stoned)
861 goto do_stone;
862 }
863 dmg += dmgval(otmp, &youmonst);
864 if (dmg <= 0) dmg = 1;
865 if (!(otmp->oartifact &&
866 artifact_hit(mtmp, &youmonst, otmp, &dmg,dieroll)))
867 hitmsg(mtmp, mattk);
868 if (!dmg) break;
869 if (u.mh > 1 && u.mh > ((u.uac>0) ? dmg : dmg+u.uac) &&
870 (u.umonnum==PM_BLACK_PUDDING
871 || u.umonnum==PM_BROWN_PUDDING)) {
872 /* This redundancy necessary because you have to
873 * take the damage _before_ being cloned.
874 */
875 if (u.uac < 0) dmg += u.uac;
876 if (dmg < 1) dmg = 1;
877 if (dmg > 1) exercise(A_STR, FALSE);
878 u.mh -= dmg;
879 flags.botl = 1;
880 dmg = 0;
881 if(cloneu())
882 You("divide as %s hits you!",mon_nam(mtmp));
883 }
884 urustm(mtmp, otmp);
885 } else if (mattk->aatyp != AT_TUCH || dmg != 0 ||
886 mtmp != u.ustuck)
887 hitmsg(mtmp, mattk);
888 }
889 break;
890 case AD_DISE:
891 hitmsg(mtmp, mattk);
892 if (!diseasemu(mdat)) dmg = 0;
893 break;
894 case AD_FIRE:
895 hitmsg(mtmp, mattk);
896 if (uncancelled) {
897 pline("You're %s!",
898 mattk->aatyp == AT_HUGS ? "being roasted" :
899 "on fire");
900 if (youmonst.data == &mons[PM_STRAW_GOLEM] ||
901 youmonst.data == &mons[PM_PAPER_GOLEM]) {
902 You("roast!");
903 /* KMH -- this is okay with unchanging */
904 rehumanize();
905 break;
906 } else if (Fire_resistance) {
907 pline_The("fire doesn't feel hot!");
908 dmg = 0;
909 }
910 if((int) mtmp->m_lev > rn2(20))
911 destroy_item(SCROLL_CLASS, AD_FIRE);
912 if((int) mtmp->m_lev > rn2(20))
913 destroy_item(POTION_CLASS, AD_FIRE);
914 if((int) mtmp->m_lev > rn2(25))
915 destroy_item(SPBOOK_CLASS, AD_FIRE);
916 burn_away_slime();
917 } else dmg = 0;
918 break;
919 case AD_COLD:
920 hitmsg(mtmp, mattk);
921 if (uncancelled) {
922 pline("You're covered in frost!");
923 if (Cold_resistance) {
924 pline_The("frost doesn't seem cold!");
925 dmg = 0;
926 }
927 if((int) mtmp->m_lev > rn2(20))
928 destroy_item(POTION_CLASS, AD_COLD);
929 } else dmg = 0;
930 break;
931 case AD_ELEC:
932 hitmsg(mtmp, mattk);
933 if (uncancelled) {
934 You("get zapped!");
935 if (Shock_resistance) {
936 pline_The("zap doesn't shock you!");
937 dmg = 0;
938 }
939 if((int) mtmp->m_lev > rn2(20))
940 destroy_item(WAND_CLASS, AD_ELEC);
941 if((int) mtmp->m_lev > rn2(20))
942 destroy_item(RING_CLASS, AD_ELEC);
943 } else dmg = 0;
944 break;
945 case AD_SLEE:
946 hitmsg(mtmp, mattk);
947 if (uncancelled && multi >= 0 && !rn2(5)) {
948 if (Sleep_resistance) break;
949 fall_asleep(-rnd(10), TRUE);
950 if (Blind) You("are put to sleep!");
951 else You("are put to sleep by %s!", mon_nam(mtmp));
952 }
953 break;
954 case AD_BLND:
955 if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj*)0)) {
956 if (!Blind) pline("%s blinds you!", Monnam(mtmp));
957 make_blinded(Blinded+(long)dmg,FALSE);
958 }
959 dmg = 0;
960 break;
961 case AD_DRST:
962 ptmp = A_STR;
963 goto dopois;
964 case AD_DRDX:
965 ptmp = A_DEX;
966 goto dopois;
967 case AD_DRCO:
968 ptmp = A_CON;
969 dopois:
970 hitmsg(mtmp, mattk);
971 if (uncancelled && !rn2(8)) {
972 Sprintf(buf, "%s %s",
973 !canspotmon(mtmp) ? "Its" :
974 Hallucination ? s_suffix(rndmonnam()) :
975 s_suffix(mdat->mname),
976 mpoisons_subj(mtmp, mattk));
977 poisoned(buf, ptmp, mdat->mname, 30);
978 }
979 break;
980 case AD_DRIN:
981 hitmsg(mtmp, mattk);
982 if (defends(AD_DRIN, uwep) || !has_head(youmonst.data)) {
983 You("don't seem harmed.");
984 break;
985 }
986 if (u_slip_free(mtmp,mattk)) break;
987
988 if (uarmh && rn2(8)) {
989 /* not body_part(HEAD) */
990 Your("helmet blocks the attack to your head.");
991 break;
992 }
993 if (Half_physical_damage) dmg = (dmg+1) / 2;
994 mdamageu(mtmp, dmg);
995
996 if (!uarmh || uarmh->otyp != DUNCE_CAP) {
997 Your("brain is eaten!");
998 /* No such thing as mindless players... */
999 if (ABASE(A_INT) <= ATTRMIN(A_INT)) {
1000 int lifesaved = 0;
1001 struct obj *wore_amulet = uamul;
1002
1003 while(1) {
1004 /* avoid looping on "die(y/n)?" */
1005 if (lifesaved && (discover || wizard)) {
1006 if (wore_amulet && !uamul) {
1007 /* used up AMULET_OF_LIFE_SAVING; still
1008 subject to dying from brainlessness */
1009 wore_amulet = 0;
1010 } else {
1011 /* explicitly chose not to die;
1012 arbitrarily boost intelligence */
1013 ABASE(A_INT) = ATTRMIN(A_INT) + 2;
1014 You_feel("like a scarecrow.");
1015 break;
1016 }
1017 }
1018
1019 if (lifesaved)
1020 pline("Unfortunately your brain is still gone.");
1021 else
1022 Your("last thought fades away.");
1023 killer = "brainlessness";
1024 killer_format = KILLED_BY;
1025 done(DIED);
1026 lifesaved++;
1027 }
1028 }
1029 }
1030 /* adjattrib gives dunce cap message when appropriate */
1031 (void) adjattrib(A_INT, -rnd(2), FALSE);
1032 forget_levels(25); /* lose memory of 25% of levels */
1033 forget_objects(25); /* lose memory of 25% of objects */
1034 exercise(A_WIS, FALSE);
1035 break;
1036 case AD_PLYS:
1037 hitmsg(mtmp, mattk);
1038 if (uncancelled && multi >= 0 && !rn2(3)) {
1039 if (Free_action) You("momentarily stiffen.");
1040 else {
1041 if (Blind) You("are frozen!");
1042 else You("are frozen by %s!", mon_nam(mtmp));
1043 nomovemsg = 0; /* default: "you can move again" */
1044 nomul(-rnd(10));
1045 exercise(A_DEX, FALSE);
1046 }
1047 }
1048 break;
1049 case AD_DRLI:
1050 hitmsg(mtmp, mattk);
1051 if (uncancelled && !rn2(3) && !Drain_resistance) {
1052 losexp("life drainage");
1053 }
1054 break;
1055 case AD_LEGS:
1056 { register long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE;
1057 const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left";
1058
1059 /* This case is too obvious to ignore, but Nethack is not in
1060 * general very good at considering height--most short monsters
1061 * still _can_ attack you when you're flying or mounted.
1062 */
1063 if (
1064 #ifdef STEED
1065 u.usteed ||
1066 #endif
1067 Levitation || Flying) {
1068 pline("%s tries to reach your %s %s!", Monnam(mtmp),
1069 sidestr, body_part(LEG));
1070 } else if (mtmp->mcan) {
1071 pline("%s nuzzles against your %s %s!", Monnam(mtmp),
1072 sidestr, body_part(LEG));
1073 } else {
1074 if (uarmf) {
1075 if (rn2(2) && (uarmf->otyp == LOW_BOOTS ||
1076 uarmf->otyp == IRON_SHOES))
1077 pline("%s pricks the exposed part of your %s %s!",
1078 Monnam(mtmp), sidestr, body_part(LEG));
1079 else if (!rn2(5))
1080 pline("%s pricks through your %s boot!",
1081 Monnam(mtmp), sidestr);
1082 else {
1083 pline("%s scratches your %s boot!", Monnam(mtmp),
1084 sidestr);
1085 break;
1086 }
1087 } else pline("%s pricks your %s %s!", Monnam(mtmp),
1088 sidestr, body_part(LEG));
1089 set_wounded_legs(side, rnd(60-ACURR(A_DEX)));
1090 exercise(A_STR, FALSE);
1091 exercise(A_DEX, FALSE);
1092 }
1093 break;
1094 }
1095 case AD_STON: /* cockatrice */
1096 hitmsg(mtmp, mattk);
1097 if(!rn2(3) && !Stoned) {
1098 if (mtmp->mcan) {
1099 if (flags.soundok)
1100 You_hear("a cough from %s!", mon_nam(mtmp));
1101 } else {
1102 if (flags.soundok)
1103 You_hear("%s hissing!", s_suffix(mon_nam(mtmp)));
1104 if(!rn2(10) ||
1105 (flags.moonphase == NEW_MOON && !have_lizard())) {
1106 do_stone:
1107 if (!Stone_resistance
1108 && !(poly_when_stoned(youmonst.data) &&
1109 polymon(PM_STONE_GOLEM))) {
1110 Stoned = 5;
1111 killer_format = KILLED_BY_AN;
1112 delayed_killer = mtmp->data->mname;
1113 return(1);
1114 /* You("turn to stone..."); */
1115 /* done_in_by(mtmp); */
1116 }
1117 }
1118 }
1119 }
1120 break;
1121 case AD_STCK:
1122 hitmsg(mtmp, mattk);
1123 if (uncancelled && !u.ustuck && !sticks(youmonst.data))
1124 u.ustuck = mtmp;
1125 break;
1126 case AD_WRAP:
1127 if ((!mtmp->mcan || u.ustuck == mtmp) && !sticks(youmonst.data)) {
1128 if (!u.ustuck && !rn2(10)) {
1129 if (u_slip_free(mtmp, mattk)) {
1130 dmg = 0;
1131 } else {
1132 pline("%s swings itself around you!",
1133 Monnam(mtmp));
1134 u.ustuck = mtmp;
1135 }
1136 } else if(u.ustuck == mtmp) {
1137 if (is_pool(mtmp->mx,mtmp->my) && !Swimming
1138 && !Amphibious) {
1139 boolean moat = (levl[u.ux][u.uy].typ != POOL) &&
1140 (levl[u.ux][u.uy].typ != WATER) &&
1141 !Is_medusa_level(&u.uz) &&
1142 !Is_waterlevel(&u.uz);
1143
1144 pline("%s drowns you...", Monnam(mtmp));
1145 killer_format = KILLED_BY_AN;
1146 Sprintf(buf, "%s by %s",
1147 moat ? "moat" : "pool of water",
1148 a_monnam(mtmp));
1149 killer = buf;
1150 done(DROWNING);
1151 } else if(mattk->aatyp == AT_HUGS)
1152 You("are being crushed.");
1153 } else {
1154 dmg = 0;
1155 if(flags.verbose)
1156 pline("%s brushes against your %s.", Monnam(mtmp),
1157 body_part(LEG));
1158 }
1159 } else dmg = 0;
1160 break;
1161 case AD_WERE:
1162 hitmsg(mtmp, mattk);
1163 if (uncancelled && !rn2(4) && u.ulycn == NON_PM &&
1164 !Protection_from_shape_changers &&
1165 !defends(AD_WERE,uwep)) {
1166 You_feel("feverish.");
1167 exercise(A_CON, FALSE);
1168 u.ulycn = monsndx(mdat);
1169 }
1170 break;
1171 case AD_SGLD:
1172 hitmsg(mtmp, mattk);
1173 if (youmonst.data->mlet == mdat->mlet) break;
1174 if(!mtmp->mcan) stealgold(mtmp);
1175 break;
1176
1177 case AD_SITM: /* for now these are the same */
1178 case AD_SEDU:
1179 if (is_animal(mtmp->data)) {
1180 hitmsg(mtmp, mattk);
1181 if (mtmp->mcan) break;
1182 /* Continue below */
1183 } else if (dmgtype(youmonst.data, AD_SEDU)
1184 #ifdef SEDUCE
1185 || dmgtype(youmonst.data, AD_SSEX)
1186 #endif
1187 ) {
1188 pline("%s %s.", Monnam(mtmp), mtmp->minvent ?
1189 "brags about the goods some dungeon explorer provided" :
1190 "makes some remarks about how difficult theft is lately");
1191 if (!tele_restrict(mtmp)) rloc(mtmp);
1192 return 3;
1193 } else if (mtmp->mcan) {
1194 if (!Blind) {
1195 pline("%s tries to %s you, but you seem %s.",
1196 Adjmonnam(mtmp, "plain"),
1197 flags.female ? "charm" : "seduce",
1198 flags.female ? "unaffected" : "uninterested");
1199 }
1200 if(rn2(3)) {
1201 if (!tele_restrict(mtmp)) rloc(mtmp);
1202 return 3;
1203 }
1204 break;
1205 }
1206 switch (steal(mtmp)) {
1207 case -1:
1208 return 2;
1209 case 0:
1210 break;
1211 default:
1212 if (!is_animal(mtmp->data) && !tele_restrict(mtmp))
1213 rloc(mtmp);
1214 mtmp->mflee = 1;
1215 return 3;
1216 }
1217 break;
1218 #ifdef SEDUCE
1219 case AD_SSEX:
1220 if(could_seduce(mtmp, &youmonst, mattk) == 1
1221 && !mtmp->mcan)
1222 if (doseduce(mtmp))
1223 return 3;
1224 break;
1225 #endif
1226 case AD_SAMU:
1227 hitmsg(mtmp, mattk);
1228 /* when the Wiz hits, 1/20 steals the amulet */
1229 if (u.uhave.amulet ||
1230 u.uhave.bell || u.uhave.book || u.uhave.menorah
1231 || u.uhave.questart) /* carrying the Quest Artifact */
1232 if (!rn2(20)) stealamulet(mtmp);
1233 break;
1234
1235 case AD_TLPT:
1236 hitmsg(mtmp, mattk);
1237 if (uncancelled) {
1238 if(flags.verbose)
1239 Your("position suddenly seems very uncertain!");
1240 tele();
1241 }
1242 break;
1243 case AD_RUST:
1244 hitmsg(mtmp, mattk);
1245 if (mtmp->mcan) break;
1246 if (u.umonnum == PM_IRON_GOLEM) {
1247 You("rust!");
1248 /* KMH -- this is okay with unchanging */
1249 rehumanize();
1250 break;
1251 }
1252 hurtarmor(AD_RUST);
1253 break;
1254 case AD_CORRODE:
1255 hitmsg(mtmp, mattk);
1256 if (mtmp->mcan) break;
1257 hurtarmor(AD_CORRODE);
1258 break;
1259 case AD_DCAY:
1260 hitmsg(mtmp, mattk);
1261 if (mtmp->mcan) break;
1262 if (u.umonnum == PM_WOOD_GOLEM ||
1263 u.umonnum == PM_LEATHER_GOLEM) {
1264 You("rot!");
1265 /* KMH -- this is okay with unchanging */
1266 rehumanize();
1267 break;
1268 }
1269 hurtarmor(AD_DCAY);
1270 break;
1271 case AD_HEAL:
1272 if(!uwep
1273 #ifdef TOURIST
1274 && !uarmu
1275 #endif
1276 && !uarm && !uarmh && !uarms && !uarmg && !uarmc && !uarmf) {
1277 boolean goaway = FALSE;
1278 pline("%s hits! (I hope you don't mind.)", Monnam(mtmp));
1279 if (Upolyd) {
1280 u.mh += rnd(7);
1281 if (!rn2(7)) {
1282 /* no upper limit necessary; effect is temporary */
1283 u.mhmax++;
1284 if (!rn2(13)) goaway = TRUE;
1285 }
1286 if (u.mh > u.mhmax) u.mh = u.mhmax;
1287 } else {
1288 u.uhp += rnd(7);
1289 if (!rn2(7)) {
1290 /* hard upper limit via nurse care: 25 * ulevel */
1291 if (u.uhpmax < 5 * u.ulevel + d(2 * u.ulevel, 10))
1292 u.uhpmax++;
1293 if (!rn2(13)) goaway = TRUE;
1294 }
1295 if (u.uhp > u.uhpmax) u.uhp = u.uhpmax;
1296 }
1297 if (!rn2(3)) exercise(A_STR, TRUE);
1298 if (!rn2(3)) exercise(A_CON, TRUE);
1299 if (Sick) make_sick(0L, (char *) 0, FALSE, SICK_ALL);
1300 flags.botl = 1;
1301 if (goaway) {
1302 mongone(mtmp);
1303 return 2;
1304 } else if (!rn2(33)) {
1305 if (!tele_restrict(mtmp)) rloc(mtmp);
1306 if (!mtmp->mflee) {
1307 mtmp->mflee = 1;
1308 mtmp->mfleetim = d(3,6);
1309 }
1310 return 3;
1311 }
1312 dmg = 0;
1313 } else {
1314 if (Role_if(PM_HEALER)) {
1315 if (flags.soundok && !(moves % 5))
1316 verbalize("Doc, I can't help you unless you cooperate.");
1317 dmg = 0;
1318 } else hitmsg(mtmp, mattk);
1319 }
1320 break;
1321 case AD_CURS:
1322 hitmsg(mtmp, mattk);
1323 if(!night() && mdat == &mons[PM_GREMLIN]) break;
1324 if(!mtmp->mcan && !rn2(10)) {
1325 if (flags.soundok) {
1326 if (Blind) You_hear("laughter.");
1327 else pline("%s chuckles.", Monnam(mtmp));
1328 }
1329 if (u.umonnum == PM_CLAY_GOLEM) {
1330 pline("Some writing vanishes from your head!");
1331 /* KMH -- this is okay with unchanging */
1332 rehumanize();
1333 break;
1334 }
1335 attrcurse();
1336 }
1337 break;
1338 case AD_STUN:
1339 hitmsg(mtmp, mattk);
1340 if(!mtmp->mcan && !rn2(4)) {
1341 make_stunned(HStun + dmg, TRUE);
1342 dmg /= 2;
1343 }
1344 break;
1345 case AD_ACID:
1346 hitmsg(mtmp, mattk);
1347 if (!mtmp->mcan && !rn2(3))
1348 if (Acid_resistance) {
1349 pline("You're covered in acid, but it seems harmless.");
1350 dmg = 0;
1351 } else {
1352 pline("You're covered in acid! It burns!");
1353 exercise(A_STR, FALSE);
1354 }
1355 else dmg = 0;
1356 break;
1357 case AD_SLOW:
1358 hitmsg(mtmp, mattk);
1359 if (uncancelled && HFast &&
1360 !defends(AD_SLOW, uwep) && !rn2(4))
1361 u_slow_down();
1362 break;
1363 case AD_DREN:
1364 hitmsg(mtmp, mattk);
1365 if (uncancelled && !rn2(4))
1366 drain_en(dmg);
1367 dmg = 0;
1368 break;
1369 case AD_CONF:
1370 hitmsg(mtmp, mattk);
1371 if(!mtmp->mcan && !rn2(4) && !mtmp->mspec_used) {
1372 mtmp->mspec_used = mtmp->mspec_used + (dmg + rn2(6));
1373 if(Confusion)
1374 You("are getting even more confused.");
1375 else You("are getting confused.");
1376 make_confused(HConfusion + dmg, FALSE);
1377 }
1378 /* fall through to next case */
1379 case AD_DETH:
1380 pline("%s reaches out with its deadly touch.", Monnam(mtmp));
1381 if (is_undead(youmonst.data)) {
1382 /* Still does normal damage */
1383 pline("Was that the touch of death?");
1384 break;
1385 }
1386 if(!Antimagic && rn2(20) > 16) {
1387 killer_format = KILLED_BY_AN;
1388 killer = "touch of death";
1389 done(DIED);
1390 } else {
1391 if(!rn2(5)) {
1392 if(Antimagic) shieldeff(u.ux, u.uy);
1393 pline("Lucky for you, it didn't work!");
1394 dmg = 0;
1395 } else You_feel("your life force draining away...");
1396 }
1397 break;
1398 case AD_PEST:
1399 pline("%s reaches out, and you feel fever and chills.",
1400 Monnam(mtmp));
1401 (void) diseasemu(mdat); /* plus the normal damage */
1402 break;
1403 case AD_FAMN:
1404 pline("%s reaches out, and your body shrivels.",
1405 Monnam(mtmp));
1406 exercise(A_CON, FALSE);
1407 if (!is_fainted()) morehungry(rn1(40,40));
1408 /* plus the normal damage */
1409 break;
1410 case AD_SLIM:
1411 hitmsg(mtmp, mattk);
1412 if (!uncancelled) break;
1413 if (youmonst.data == &mons[PM_FIRE_VORTEX] ||
1414 youmonst.data == &mons[PM_FIRE_ELEMENTAL]) {
1415 pline_The("slime burns away!");
1416 dmg = 0;
1417 } else if (Unchanging ||
1418 youmonst.data == &mons[PM_GREEN_SLIME]) {
1419 You("are unaffected.");
1420 dmg = 0;
1421 } else if (!Slimed) {
1422 You("don't feel very well.");
1423 Slimed = 10L;
1424 killer_format = KILLED_BY_AN;
1425 delayed_killer = mtmp->data->mname;
1426 } else
1427 pline("Yuck!");
1428 break;
1429 case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
1430 hitmsg(mtmp, mattk);
1431 /* uncancelled is sufficient enough; please
1432 don't make this attack less frequent */
1433 if (uncancelled) {
1434 struct obj *obj = some_armor(&youmonst);
1435
1436 if (drain_item(obj)) {
1437 Your("%s less effective.", aobjnam(obj, "seem"));
1438 }
1439 }
1440 break;
1441 default: dmg = 0;
1442 break;
1443 }
1444 if(u.uhp < 1) done_in_by(mtmp);
1445
1446 /* Negative armor class reduces damage done instead of fully protecting
1447 * against hits.
1448 */
1449 if (dmg && u.uac < 0) {
1450 dmg -= rnd(-u.uac);
1451 if (dmg < 1) dmg = 1;
1452 }
1453
1454 if(dmg) {
1455 if (Half_physical_damage
1456 /* Mitre of Holiness */
1457 || (Role_if(PM_PRIEST) && uarmh && is_quest_artifact(uarmh) &&
1458 (is_undead(mtmp->data) || is_demon(mtmp->data))))
1459 dmg = (dmg+1) / 2;
1460 mdamageu(mtmp, dmg);
1461 }
1462
1463 if (dmg) {
1464 res = passiveum(olduasmon, mtmp, mattk);
1465 stop_occupation();
1466 return res;
1467 } else
1468 return 1;
1469 }
1470
1471 #endif /* OVL1 */
1472 #ifdef OVLB
1473
1474 STATIC_OVL int
gulpmu(mtmp,mattk)1475 gulpmu(mtmp, mattk) /* monster swallows you, or damage if u.uswallow */
1476 register struct monst *mtmp;
1477 register struct attack *mattk;
1478 {
1479 struct trap *t = t_at(u.ux, u.uy);
1480 int tmp = d((int)mattk->damn, (int)mattk->damd);
1481 int tim_tmp;
1482 register struct obj *otmp2;
1483 int i;
1484
1485 if (!u.uswallow) { /* swallows you */
1486 if (youmonst.data->msize >= MZ_HUGE) return(0);
1487 if ((t && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT))) &&
1488 sobj_at(BOULDER, u.ux, u.uy))
1489 return(0);
1490
1491 if (Punished) unplacebc(); /* ball&chain go away */
1492 remove_monster(mtmp->mx, mtmp->my);
1493 mtmp->mtrapped = 0; /* no longer on old trap */
1494 place_monster(mtmp, u.ux, u.uy);
1495 u.ustuck = mtmp;
1496 newsym(mtmp->mx,mtmp->my);
1497 #ifdef STEED
1498 if (is_animal(mtmp->data) && u.usteed) {
1499 char buf[BUFSZ];
1500 /* Too many quirks presently if hero and steed
1501 * are swallowed. Pretend purple worms don't
1502 * like horses for now :-)
1503 */
1504 Strcpy(buf, mon_nam(u.usteed));
1505 pline ("%s lunges forward and plucks you off %s!",
1506 Monnam(mtmp), buf);
1507 dismount_steed(DISMOUNT_ENGULFED);
1508 } else
1509 #endif
1510 pline("%s engulfs you!", Monnam(mtmp));
1511 stop_occupation();
1512 reset_occupations(); /* behave as if you had moved */
1513
1514 if (u.utrap) {
1515 You("are released from the %s!",
1516 u.utraptype==TT_WEB ? "web" : "trap");
1517 u.utrap = 0;
1518 }
1519
1520 i = number_leashed();
1521 if (i > 0) {
1522 pline_The("leash%s snap%s loose.",
1523 (i > 1) ? "es" : "",
1524 (i > 1) ? "" : "s");
1525 unleash_all();
1526 }
1527
1528 if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) {
1529 minstapetrify(mtmp, TRUE);
1530 if (mtmp->mhp > 0) return 0;
1531 else return 2;
1532 }
1533
1534 display_nhwindow(WIN_MESSAGE, FALSE);
1535 vision_recalc(2); /* hero can't see anything */
1536 u.uswallow = 1;
1537 /* u.uswldtim always set > 1 */
1538 tim_tmp = 25 - (int)mtmp->m_lev;
1539 if (tim_tmp > 0) tim_tmp = rnd(tim_tmp) / 2;
1540 else if (tim_tmp < 0) tim_tmp = -(rnd(-tim_tmp) / 2);
1541 tim_tmp += -u.uac + 10;
1542 u.uswldtim = (unsigned)((tim_tmp < 2) ? 2 : tim_tmp);
1543 swallowed(1);
1544 for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj)
1545 (void) snuff_lit(otmp2);
1546 }
1547
1548 if (mtmp != u.ustuck) return(0);
1549 if (u.uswldtim > 0) u.uswldtim -= 1;
1550
1551 switch(mattk->adtyp) {
1552
1553 case AD_DGST:
1554 if (Slow_digestion) {
1555 /* Messages are handled below */
1556 u.uswldtim = 0;
1557 tmp = 0;
1558 } else if (u.uswldtim == 0) {
1559 pline("%s totally digests you!", Monnam(mtmp));
1560 tmp = u.uhp;
1561 if (Half_physical_damage) tmp *= 2; /* sorry */
1562 } else {
1563 pline("%s%s digests you!", Monnam(mtmp),
1564 (u.uswldtim == 2) ? " thoroughly" :
1565 (u.uswldtim == 1) ? " utterly" : "");
1566 exercise(A_STR, FALSE);
1567 }
1568 break;
1569 case AD_PHYS:
1570 You("are pummeled with debris!");
1571 exercise(A_STR, FALSE);
1572 break;
1573 case AD_ACID:
1574 if (Acid_resistance) {
1575 You("are covered with a seemingly harmless goo.");
1576 tmp = 0;
1577 } else {
1578 if (Hallucination) pline("Ouch! You've been slimed!");
1579 else You("are covered in slime! It burns!");
1580 exercise(A_STR, FALSE);
1581 }
1582 break;
1583 case AD_BLND:
1584 if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj*)0)) {
1585 if(!Blind) {
1586 You_cant("see in here!");
1587 make_blinded((long)tmp,FALSE);
1588 } else
1589 /* keep him blind until disgorged */
1590 make_blinded(Blinded+1,FALSE);
1591 }
1592 tmp = 0;
1593 break;
1594 case AD_ELEC:
1595 if(!mtmp->mcan && rn2(2)) {
1596 pline_The("air around you crackles with electricity.");
1597 if (Shock_resistance) {
1598 shieldeff(u.ux, u.uy);
1599 You("seem unhurt.");
1600 ugolemeffects(AD_ELEC,tmp);
1601 tmp = 0;
1602 }
1603 } else tmp = 0;
1604 break;
1605 case AD_COLD:
1606 if(!mtmp->mcan && rn2(2)) {
1607 if (Cold_resistance) {
1608 shieldeff(u.ux, u.uy);
1609 You_feel("mildly chilly.");
1610 ugolemeffects(AD_COLD,tmp);
1611 tmp = 0;
1612 } else You("are freezing to death!");
1613 } else tmp = 0;
1614 break;
1615 case AD_FIRE:
1616 if(!mtmp->mcan && rn2(2)) {
1617 if (Fire_resistance) {
1618 shieldeff(u.ux, u.uy);
1619 You_feel("mildly hot.");
1620 ugolemeffects(AD_FIRE,tmp);
1621 tmp = 0;
1622 } else You("are burning to a crisp!");
1623 burn_away_slime();
1624 } else tmp = 0;
1625 break;
1626 case AD_DISE:
1627 if (!diseasemu(mtmp->data)) tmp = 0;
1628 break;
1629 default:
1630 tmp = 0;
1631 break;
1632 }
1633
1634 if (Half_physical_damage) tmp = (tmp+1) / 2;
1635
1636 mdamageu(mtmp, tmp);
1637 if (tmp) stop_occupation();
1638
1639 if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) {
1640 pline("%s very hurriedly %s you!", Monnam(mtmp),
1641 is_animal(mtmp->data)? "regurgitates" : "expels");
1642 expels(mtmp, mtmp->data, FALSE);
1643 } else if (!u.uswldtim || youmonst.data->msize >= MZ_HUGE) {
1644 You("get %s!", is_animal(mtmp->data)? "regurgitated" : "expelled");
1645 if (flags.verbose && (is_animal(mtmp->data) ||
1646 (dmgtype(mtmp->data, AD_DGST) && Slow_digestion)))
1647 pline("Obviously %s doesn't like your taste.", mon_nam(mtmp));
1648 expels(mtmp, mtmp->data, FALSE);
1649 }
1650 return(1);
1651 }
1652
1653 STATIC_OVL int
explmu(mtmp,mattk,ufound)1654 explmu(mtmp, mattk, ufound) /* monster explodes in your face */
1655 register struct monst *mtmp;
1656 register struct attack *mattk;
1657 boolean ufound;
1658 {
1659 if (mtmp->mcan) return(0);
1660
1661 if (!ufound)
1662 pline("%s explodes at a spot in %s!",
1663 canseemon(mtmp) ? Monnam(mtmp) : "It",
1664 levl[mtmp->mux][mtmp->muy].typ == WATER
1665 ? "empty water" : "thin air");
1666 else {
1667 register int tmp = d((int)mattk->damn, (int)mattk->damd);
1668 register boolean not_affected = defends((int)mattk->adtyp, uwep);
1669
1670 hitmsg(mtmp, mattk);
1671
1672 switch (mattk->adtyp) {
1673 case AD_COLD:
1674 not_affected |= Cold_resistance;
1675 goto common;
1676 case AD_FIRE:
1677 not_affected |= Fire_resistance;
1678 goto common;
1679 case AD_ELEC:
1680 not_affected |= Shock_resistance;
1681 common:
1682
1683 if (!not_affected) {
1684 if (ACURR(A_DEX) > rnd(20)) {
1685 You("duck some of the blast.");
1686 tmp = (tmp+1) / 2;
1687 } else {
1688 if (flags.verbose) You("get blasted!");
1689 }
1690 if (mattk->adtyp == AD_FIRE) burn_away_slime();
1691 if (Half_physical_damage) tmp = (tmp+1) / 2;
1692 mdamageu(mtmp, tmp);
1693 }
1694 break;
1695
1696 case AD_BLND:
1697 not_affected = resists_blnd(&youmonst);
1698 if (!not_affected) {
1699 /* sometimes you're affected even if it's invisible */
1700 if (mon_visible(mtmp) || (rnd(tmp /= 2) > u.ulevel)) {
1701 You("are blinded by a blast of light!");
1702 make_blinded((long)tmp, FALSE);
1703 } else if (flags.verbose)
1704 You("get the impression it was not terribly bright.");
1705 }
1706 break;
1707
1708 case AD_HALU:
1709 not_affected |= Blind ||
1710 (u.umonnum == PM_BLACK_LIGHT ||
1711 u.umonnum == PM_VIOLET_FUNGUS ||
1712 dmgtype(youmonst.data, AD_STUN));
1713 if (!not_affected) {
1714 if (!Hallucination)
1715 You("are freaked by a blast of kaleidoscopic light!");
1716 make_hallucinated(HHallucination + (long)tmp,FALSE,0L);
1717 }
1718 break;
1719
1720 default:
1721 break;
1722 }
1723 if (not_affected) {
1724 You("seem unaffected by it.");
1725 ugolemeffects((int)mattk->adtyp, tmp);
1726 }
1727 }
1728 mondead(mtmp);
1729 if (mtmp->mhp > 0) return(0);
1730 return(2); /* it dies */
1731 }
1732
1733 int
gazemu(mtmp,mattk)1734 gazemu(mtmp, mattk) /* monster gazes at you */
1735 register struct monst *mtmp;
1736 register struct attack *mattk;
1737 {
1738 switch(mattk->adtyp) {
1739 case AD_STON:
1740 if (mtmp->mcan) {
1741 if (mtmp->data == &mons[PM_MEDUSA] && canseemon(mtmp))
1742 pline("%s doesn't look all that ugly.", Monnam(mtmp));
1743 break;
1744 }
1745 if(Reflecting && mtmp->mcansee &&
1746 !mtmp->mcan && mtmp->data == &mons[PM_MEDUSA]) {
1747 if(!Blind) {
1748 (void) ureflects("%s gaze is reflected by your %s.",
1749 s_suffix(Monnam(mtmp)));
1750 if (mon_reflects(mtmp,
1751 "The gaze is reflected away by %s %s!"))
1752 break;
1753 if (!m_canseeu(mtmp)) { /* probably you're invisible */
1754 pline("%s doesn't seem to notice that %s gaze was reflected.",
1755 Monnam(mtmp),
1756 his[pronoun_gender(mtmp)]);
1757 break;
1758 }
1759 pline("%s is turned to stone!", Monnam(mtmp));
1760 }
1761 stoned = TRUE;
1762 killed(mtmp);
1763
1764 if (mtmp->mhp > 0) break;
1765 return 2;
1766 }
1767 if (canseemon(mtmp) && !Stone_resistance) {
1768 You("meet %s gaze.", s_suffix(mon_nam(mtmp)));
1769 if(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
1770 break;
1771 You("turn to stone...");
1772 killer_format = KILLED_BY;
1773 killer = mons[PM_MEDUSA].mname;
1774 done(STONING);
1775 }
1776 break;
1777 case AD_CONF:
1778 if(!mtmp->mcan && canseemon(mtmp) && mtmp->mcansee &&
1779 !mtmp->mspec_used && rn2(5)) {
1780 int conf = d(3,4);
1781
1782 mtmp->mspec_used = mtmp->mspec_used + (conf + rn2(6));
1783 if(!Confusion)
1784 pline("%s gaze confuses you!",
1785 s_suffix(Monnam(mtmp)));
1786 else
1787 You("are getting more and more confused.");
1788 make_confused(HConfusion + conf, FALSE);
1789 }
1790 break;
1791 case AD_STUN:
1792 if(!mtmp->mcan && canseemon(mtmp) && mtmp->mcansee &&
1793 !mtmp->mspec_used && rn2(5)) {
1794 int stun = d(2,6);
1795
1796 mtmp->mspec_used = mtmp->mspec_used + (stun + rn2(6));
1797 make_stunned(HStun + stun, TRUE);
1798 pline("%s stares piercingly at you!", Monnam(mtmp));
1799 }
1800 break;
1801 case AD_BLND:
1802 if (!mtmp->mcan && canseemon(mtmp) && !resists_blnd(&youmonst)
1803 && distu(mtmp->mx,mtmp->my) <= BOLT_LIM*BOLT_LIM) {
1804 int blnd = d((int)mattk->damn, (int)mattk->damd);
1805 make_blinded((long)blnd,FALSE);
1806 make_stunned((long)d(1,3),TRUE);
1807 You("are blinded by %s radiance!",
1808 s_suffix(mon_nam(mtmp)));
1809 }
1810 break;
1811 case AD_FIRE:
1812 if(!mtmp->mcan && canseemon(mtmp) && mtmp->mcansee &&
1813 !mtmp->mspec_used && rn2(5)) {
1814 int dmg = d(2,6);
1815 pline("%s attacks you with a fiery gaze!",
1816 Monnam(mtmp));
1817 if (Fire_resistance) {
1818 pline_The("fire doesn't feel hot!");
1819 dmg = 0;
1820 }
1821 burn_away_slime();
1822 if((int) mtmp->m_lev > rn2(20))
1823 destroy_item(SCROLL_CLASS, AD_FIRE);
1824 if((int) mtmp->m_lev > rn2(20))
1825 destroy_item(POTION_CLASS, AD_FIRE);
1826 if((int) mtmp->m_lev > rn2(25))
1827 destroy_item(SPBOOK_CLASS, AD_FIRE);
1828 if (dmg) mdamageu(mtmp, dmg);
1829 }
1830 break;
1831 #ifdef PM_BEHOLDER /* work in progress */
1832 case AD_SLEE:
1833 if(!mtmp->mcan && canseemon(mtmp) && mtmp->mcansee &&
1834 multi >= 0 && !rn2(5) && !Sleep_resistance) {
1835 fall_asleep(-rnd(10), TRUE);
1836 pline("%s gaze makes you very sleepy...",
1837 s_suffix(Monnam(mtmp)));
1838 }
1839 break;
1840 case AD_SLOW:
1841 if(!mtmp->mcan && canseemon(mtmp) && mtmp->mcansee &&
1842 (HFast & (INTRINSIC|TIMEOUT)) &&
1843 !defends(AD_SLOW, uwep) && !rn2(4))
1844 u_slow_down();
1845 break;
1846 #endif
1847 default: impossible("Gaze attack %d?", mattk->adtyp);
1848 break;
1849 }
1850 return(0);
1851 }
1852
1853 #endif /* OVLB */
1854 #ifdef OVL1
1855
1856 void
mdamageu(mtmp,n)1857 mdamageu(mtmp, n) /* mtmp hits you for n points damage */
1858 register struct monst *mtmp;
1859 register int n;
1860 {
1861 flags.botl = 1;
1862 if (Upolyd) {
1863 u.mh -= n;
1864 if (u.mh < 1) rehumanize();
1865 } else {
1866 u.uhp -= n;
1867 if(u.uhp < 1) done_in_by(mtmp);
1868 }
1869 }
1870
1871 #endif /* OVL1 */
1872 #ifdef OVLB
1873
1874 STATIC_OVL void
urustm(mon,obj)1875 urustm(mon, obj)
1876 register struct monst *mon;
1877 register struct obj *obj;
1878 {
1879 boolean vis;
1880 boolean is_acid;
1881
1882 if (!mon || !obj) return; /* just in case */
1883 if (dmgtype(youmonst.data, AD_CORRODE))
1884 is_acid = TRUE;
1885 else if (dmgtype(youmonst.data, AD_RUST))
1886 is_acid = FALSE;
1887 else
1888 return;
1889
1890 vis = cansee(mon->mx, mon->my);
1891
1892 if ((is_acid ? is_corrodeable(obj) : is_rustprone(obj)) &&
1893 (is_acid ? obj->oeroded2 : obj->oeroded) < MAX_ERODE) {
1894 if (obj->greased || obj->oerodeproof || (obj->blessed && rn2(3))) {
1895 if (vis)
1896 pline("Somehow, %s weapon is not affected.",
1897 s_suffix(mon_nam(mon)));
1898 if (obj->greased && !rn2(2)) obj->greased = 0;
1899 } else {
1900 if (vis)
1901 pline("%s %s%s!",
1902 s_suffix(Monnam(mon)),
1903 aobjnam(obj, (is_acid ? "corrode" : "rust")),
1904 (is_acid ? obj->oeroded2 : obj->oeroded)
1905 ? " further" : "");
1906 if (is_acid) obj->oeroded2++;
1907 else obj->oeroded++;
1908 }
1909 }
1910 }
1911
1912 #endif /* OVLB */
1913 #ifdef OVL1
1914
1915 int
could_seduce(magr,mdef,mattk)1916 could_seduce(magr,mdef,mattk)
1917 struct monst *magr, *mdef;
1918 struct attack *mattk;
1919 /* returns 0 if seduction impossible,
1920 * 1 if fine,
1921 * 2 if wrong gender for nymph */
1922 {
1923 register struct permonst *pagr;
1924 boolean agrinvis, defperc;
1925 xchar genagr, gendef;
1926
1927 if (is_animal(magr->data)) return (0);
1928 if(magr == &youmonst) {
1929 pagr = youmonst.data;
1930 agrinvis = (Invis != 0);
1931 genagr = poly_gender();
1932 } else {
1933 pagr = magr->data;
1934 agrinvis = magr->minvis;
1935 genagr = gender(magr);
1936 }
1937 if(mdef == &youmonst) {
1938 defperc = (See_invisible != 0);
1939 gendef = poly_gender();
1940 } else {
1941 defperc = perceives(mdef->data);
1942 gendef = gender(mdef);
1943 }
1944
1945 if(agrinvis && !defperc
1946 #ifdef SEDUCE
1947 && mattk && mattk->adtyp != AD_SSEX
1948 #endif
1949 )
1950 return 0;
1951
1952 if(pagr->mlet != S_NYMPH
1953 && ((pagr != &mons[PM_INCUBUS] && pagr != &mons[PM_SUCCUBUS])
1954 #ifdef SEDUCE
1955 || (mattk && mattk->adtyp != AD_SSEX)
1956 #endif
1957 ))
1958 return 0;
1959
1960 if(genagr == 1 - gendef)
1961 return 1;
1962 else
1963 return (pagr->mlet == S_NYMPH) ? 2 : 0;
1964 }
1965
1966 #endif /* OVL1 */
1967 #ifdef OVLB
1968
1969 #ifdef SEDUCE
1970 /* Returns 1 if monster teleported */
1971 int
doseduce(mon)1972 doseduce(mon)
1973 register struct monst *mon;
1974 {
1975 register struct obj *ring, *nring;
1976 boolean fem = (mon->data == &mons[PM_SUCCUBUS]); /* otherwise incubus */
1977 char qbuf[QBUFSZ];
1978
1979 if (mon->mcan || mon->mspec_used) {
1980 pline("%s acts as though %s has got a %sheadache.",
1981 Monnam(mon), he[pronoun_gender(mon)],
1982 mon->mcan ? "severe " : "");
1983 return 0;
1984 }
1985
1986 if (unconscious()) {
1987 pline("%s seems dismayed at your lack of response.",
1988 Monnam(mon));
1989 return 0;
1990 }
1991
1992 if (Blind) pline("It caresses you...");
1993 else You_feel("very attracted to %s.", mon_nam(mon));
1994
1995 for(ring = invent; ring; ring = nring) {
1996 nring = ring->nobj;
1997 if (ring->otyp != RIN_ADORNMENT) continue;
1998 if (fem) {
1999 if (rn2(20) < ACURR(A_CHA)) {
2000 Sprintf(qbuf, "\"That %s looks pretty. May I have it?\"",
2001 xname(ring));
2002 makeknown(RIN_ADORNMENT);
2003 if (yn(qbuf) == 'n') continue;
2004 } else pline("%s decides she'd like your %s, and takes it.",
2005 Blind ? "She" : Monnam(mon), xname(ring));
2006 makeknown(RIN_ADORNMENT);
2007 if (ring==uleft || ring==uright) Ring_gone(ring);
2008 if (ring==uwep) setuwep((struct obj *)0);
2009 if (ring==uswapwep) setuswapwep((struct obj *)0);
2010 if (ring==uquiver) setuqwep((struct obj *)0);
2011 freeinv(ring);
2012 (void) mpickobj(mon,ring);
2013 } else {
2014 char buf[BUFSZ];
2015
2016 if (uleft && uright && uleft->otyp == RIN_ADORNMENT
2017 && uright->otyp==RIN_ADORNMENT)
2018 break;
2019 if (ring==uleft || ring==uright) continue;
2020 if (rn2(20) < ACURR(A_CHA)) {
2021 Sprintf(qbuf,"\"That %s looks pretty. Would you wear it for me?\"",
2022 xname(ring));
2023 makeknown(RIN_ADORNMENT);
2024 if (yn(qbuf) == 'n') continue;
2025 } else {
2026 pline("%s decides you'd look prettier wearing your %s,",
2027 Blind ? "He" : Monnam(mon), xname(ring));
2028 pline("and puts it on your finger.");
2029 }
2030 makeknown(RIN_ADORNMENT);
2031 if (!uright) {
2032 pline("%s puts %s on your right %s.",
2033 Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND));
2034 setworn(ring, RIGHT_RING);
2035 } else if (!uleft) {
2036 pline("%s puts %s on your left %s.",
2037 Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND));
2038 setworn(ring, LEFT_RING);
2039 } else if (uright && uright->otyp != RIN_ADORNMENT) {
2040 Strcpy(buf, xname(uright));
2041 pline("%s replaces your %s with your %s.",
2042 Blind ? "He" : Monnam(mon), buf, xname(ring));
2043 Ring_gone(uright);
2044 setworn(ring, RIGHT_RING);
2045 } else if (uleft && uleft->otyp != RIN_ADORNMENT) {
2046 Strcpy(buf, xname(uleft));
2047 pline("%s replaces your %s with your %s.",
2048 Blind ? "He" : Monnam(mon), buf, xname(ring));
2049 Ring_gone(uleft);
2050 setworn(ring, LEFT_RING);
2051 } else impossible("ring replacement");
2052 Ring_on(ring);
2053 prinv((char *)0, ring, 0L);
2054 }
2055 }
2056
2057 if (!uarmc && !uarmf && !uarmg && !uarms && !uarmh
2058 #ifdef TOURIST
2059 && !uarmu
2060 #endif
2061 )
2062 pline("%s murmurs sweet nothings into your ear.",
2063 Blind ? (fem ? "She" : "He") : Monnam(mon));
2064 else
2065 pline("%s murmurs in your ear, while helping you undress.",
2066 Blind ? (fem ? "She" : "He") : Monnam(mon));
2067 mayberem(uarmc, "cloak");
2068 if(!uarmc)
2069 mayberem(uarm, "suit");
2070 mayberem(uarmf, "boots");
2071 if(!uwep || !welded(uwep))
2072 mayberem(uarmg, "gloves");
2073 mayberem(uarms, "shield");
2074 mayberem(uarmh, "helmet");
2075 #ifdef TOURIST
2076 if(!uarmc && !uarm)
2077 mayberem(uarmu, "shirt");
2078 #endif
2079
2080 if (uarm || uarmc) {
2081 verbalize("You're such a %s; I wish...",
2082 flags.female ? "sweet lady" : "nice guy");
2083 if (!tele_restrict(mon)) rloc(mon);
2084 return 1;
2085 }
2086 if (u.ualign.type == A_CHAOTIC)
2087 adjalign(1);
2088
2089 /* by this point you have discovered mon's identity, blind or not... */
2090 pline("Time stands still while you and %s lie in each other's arms...",
2091 mon_nam(mon));
2092 if (rn2(35) > ACURR(A_CHA) + ACURR(A_INT)) {
2093 /* Don't bother with mspec_used here... it didn't get tired! */
2094 pline("%s seems to have enjoyed it more than you...",
2095 Monnam(mon));
2096 switch (rn2(5)) {
2097 case 0: You_feel("drained of energy.");
2098 u.uen = 0;
2099 u.uenmax -= rnd(Half_physical_damage ? 5 : 10);
2100 exercise(A_CON, FALSE);
2101 if (u.uenmax < 0) u.uenmax = 0;
2102 break;
2103 case 1: You("are down in the dumps.");
2104 (void) adjattrib(A_CON, -1, TRUE);
2105 exercise(A_CON, FALSE);
2106 flags.botl = 1;
2107 break;
2108 case 2: Your("senses are dulled.");
2109 (void) adjattrib(A_WIS, -1, TRUE);
2110 exercise(A_WIS, FALSE);
2111 flags.botl = 1;
2112 break;
2113 case 3:
2114 if (!resists_drli(&youmonst)) {
2115 You_feel("out of shape.");
2116 losexp("overexertion");
2117 } else {
2118 You("have a curious feeling...");
2119 }
2120 break;
2121 case 4: {
2122 int tmp;
2123 You_feel("exhausted.");
2124 exercise(A_STR, FALSE);
2125 tmp = rn1(10, 6);
2126 if(Half_physical_damage) tmp = (tmp+1) / 2;
2127 losehp(tmp, "exhaustion", KILLED_BY);
2128 break;
2129 }
2130 }
2131 } else {
2132 mon->mspec_used = rnd(100); /* monster is worn out */
2133 You("seem to have enjoyed it more than %s...", mon_nam(mon));
2134 switch (rn2(5)) {
2135 case 0: You_feel("raised to your full potential.");
2136 exercise(A_CON, TRUE);
2137 u.uen = (u.uenmax += rnd(5));
2138 break;
2139 case 1: You_feel("good enough to do it again.");
2140 (void) adjattrib(A_CON, 1, TRUE);
2141 exercise(A_CON, TRUE);
2142 flags.botl = 1;
2143 break;
2144 case 2: You("will always remember %s...", mon_nam(mon));
2145 (void) adjattrib(A_WIS, 1, TRUE);
2146 exercise(A_WIS, TRUE);
2147 flags.botl = 1;
2148 break;
2149 case 3: pline("That was a very educational experience.");
2150 pluslvl(FALSE);
2151 exercise(A_WIS, TRUE);
2152 break;
2153 case 4: You_feel("restored to health!");
2154 u.uhp = u.uhpmax;
2155 if (Upolyd) u.mh = u.mhmax;
2156 exercise(A_STR, TRUE);
2157 flags.botl = 1;
2158 break;
2159 }
2160 }
2161
2162 if (mon->mtame) /* don't charge */ ;
2163 else if (rn2(20) < ACURR(A_CHA)) {
2164 pline("%s demands that you pay %s, but you refuse...",
2165 Monnam(mon), him[fem]);
2166 } else if (u.umonnum == PM_LEPRECHAUN)
2167 pline("%s tries to take your money, but fails...",
2168 Monnam(mon));
2169 else {
2170 long cost;
2171
2172 if (u.ugold > (long)LARGEST_INT - 10L)
2173 cost = (long) rnd(LARGEST_INT) + 500L;
2174 else
2175 cost = (long) rnd((int)u.ugold + 10) + 500L;
2176 if (mon->mpeaceful) {
2177 cost /= 5L;
2178 if (!cost) cost = 1L;
2179 }
2180 if (cost > u.ugold) cost = u.ugold;
2181 if (!cost) verbalize("It's on the house!");
2182 else {
2183 pline("%s takes %ld zorkmid%s for services rendered!",
2184 Monnam(mon), cost, plur(cost));
2185 u.ugold -= cost;
2186 mon->mgold += cost;
2187 flags.botl = 1;
2188 }
2189 }
2190 if (!rn2(25)) mon->mcan = 1; /* monster is worn out */
2191 if (!tele_restrict(mon)) rloc(mon);
2192 return 1;
2193 }
2194
2195 STATIC_OVL void
mayberem(obj,str)2196 mayberem(obj, str)
2197 register struct obj *obj;
2198 const char *str;
2199 {
2200 char qbuf[QBUFSZ];
2201
2202 if (!obj || !obj->owornmask) return;
2203
2204 if (rn2(20) < ACURR(A_CHA)) {
2205 Sprintf(qbuf,"\"Shall I remove your %s, %s?\"",
2206 str,
2207 (!rn2(2) ? "lover" : !rn2(2) ? "dear" : "sweetheart"));
2208 if (yn(qbuf) == 'n') return;
2209 } else {
2210 char hairbuf[BUFSZ];
2211
2212 Sprintf(hairbuf, "let me run my fingers through your %s",
2213 body_part(HAIR));
2214 verbalize("Take off your %s; %s.", str,
2215 (obj == uarm) ? "let's get a little closer" :
2216 (obj == uarmc || obj == uarms) ? "it's in the way" :
2217 (obj == uarmf) ? "let me rub your feet" :
2218 (obj == uarmg) ? "they're too clumsy" :
2219 #ifdef TOURIST
2220 (obj == uarmu) ? "let me massage you" :
2221 #endif
2222 /* obj == uarmh */
2223 hairbuf);
2224 }
2225 remove_worn_item(obj);
2226 }
2227 #endif /* SEDUCE */
2228
2229 #endif /* OVLB */
2230
2231 #ifdef OVL1
2232
2233 STATIC_OVL int
passiveum(olduasmon,mtmp,mattk)2234 passiveum(olduasmon,mtmp,mattk)
2235 struct permonst *olduasmon;
2236 register struct monst *mtmp;
2237 register struct attack *mattk;
2238 {
2239 int i, tmp;
2240
2241 for (i = 0; ; i++) {
2242 if (i >= NATTK) return 1;
2243 if (olduasmon->mattk[i].aatyp == AT_NONE ||
2244 olduasmon->mattk[i].aatyp == AT_BOOM) break;
2245 }
2246 if (olduasmon->mattk[i].damn)
2247 tmp = d((int)olduasmon->mattk[i].damn,
2248 (int)olduasmon->mattk[i].damd);
2249 else if(olduasmon->mattk[i].damd)
2250 tmp = d((int)olduasmon->mlevel+1, (int)olduasmon->mattk[i].damd);
2251 else
2252 tmp = 0;
2253
2254 /* These affect the enemy even if you were "killed" (rehumanized) */
2255 switch(olduasmon->mattk[i].adtyp) {
2256 case AD_ACID:
2257 if (!rn2(2)) {
2258 pline("%s is splashed by your acid!", Monnam(mtmp));
2259 if (resists_acid(mtmp)) {
2260 pline("%s is not affected.", Monnam(mtmp));
2261 tmp = 0;
2262 }
2263 } else tmp = 0;
2264 if (!rn2(30)) erode_armor(mtmp, TRUE);
2265 if (!rn2(6)) erode_weapon(MON_WEP(mtmp), TRUE);
2266 goto assess_dmg;
2267 case AD_STON: /* cockatrice */
2268 if (!resists_ston(mtmp) &&
2269 (mattk->aatyp != AT_WEAP || !MON_WEP(mtmp)) &&
2270 mattk->aatyp != AT_GAZE && mattk->aatyp != AT_EXPL &&
2271 mattk->aatyp != AT_MAGC &&
2272 !(mtmp->misc_worn_check & W_ARMG)) {
2273 if(poly_when_stoned(mtmp->data)) {
2274 mon_to_stone(mtmp);
2275 return (1);
2276 }
2277 pline("%s turns to stone!", Monnam(mtmp));
2278 stoned = 1;
2279 xkilled(mtmp, 0);
2280 if (mtmp->mhp > 0) return 1;
2281 return 2;
2282 }
2283 return 1;
2284 case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
2285 if (otmp) {
2286 (void) drain_item(otmp);
2287 /* No message */
2288 }
2289 return (1);
2290 default:
2291 break;
2292 }
2293 if (!Upolyd) return 1;
2294
2295 /* These affect the enemy only if you are still a monster */
2296 if (rn2(3)) switch(youmonst.data->mattk[i].adtyp) {
2297 case AD_PHYS:
2298 if (youmonst.data->mattk[i].aatyp == AT_BOOM) {
2299 You("explode!");
2300 /* KMH, balance patch -- this is okay with unchanging */
2301 rehumanize();
2302 goto assess_dmg;
2303 }
2304 break;
2305 case AD_PLYS: /* Floating eye */
2306 if (tmp > 127) tmp = 127;
2307 if (u.umonnum == PM_FLOATING_EYE) {
2308 if (!rn2(4)) tmp = 127;
2309 if (mtmp->mcansee && haseyes(mtmp->data) && rn2(3) &&
2310 (perceives(mtmp->data) || !Invis)) {
2311 if (Blind)
2312 pline("As a blind %s, you cannot defend yourself.",
2313 youmonst.data->mname);
2314 else {
2315 if (mon_reflects(mtmp,
2316 "Your gaze is reflected by %s %s."))
2317 return 1;
2318 pline("%s is frozen by your gaze!", Monnam(mtmp));
2319 mtmp->mcanmove = 0;
2320 mtmp->mfrozen = tmp;
2321 return 3;
2322 }
2323 }
2324 } else { /* gelatinous cube */
2325 pline("%s is frozen by you.", Monnam(mtmp));
2326 mtmp->mcanmove = 0;
2327 mtmp->mfrozen = tmp;
2328 return 3;
2329 }
2330 return 1;
2331 case AD_COLD: /* Brown mold or blue jelly */
2332 if (resists_cold(mtmp)) {
2333 shieldeff(mtmp->mx, mtmp->my);
2334 pline("%s is mildly chilly.", Monnam(mtmp));
2335 golemeffects(mtmp, AD_COLD, tmp);
2336 tmp = 0;
2337 break;
2338 }
2339 pline("%s is suddenly very cold!", Monnam(mtmp));
2340 u.mh += tmp / 2;
2341 if (u.mhmax < u.mh) u.mhmax = u.mh;
2342 if (u.mhmax > ((youmonst.data->mlevel+1) * 8))
2343 (void)split_mon(&youmonst, mtmp);
2344 break;
2345 case AD_STUN: /* Yellow mold */
2346 if (!mtmp->mstun) {
2347 mtmp->mstun = 1;
2348 pline("%s staggers.", Monnam(mtmp));
2349 }
2350 tmp = 0;
2351 break;
2352 case AD_FIRE: /* Red mold */
2353 if (resists_fire(mtmp)) {
2354 shieldeff(mtmp->mx, mtmp->my);
2355 pline("%s is mildly warm.", Monnam(mtmp));
2356 golemeffects(mtmp, AD_FIRE, tmp);
2357 tmp = 0;
2358 break;
2359 }
2360 pline("%s is suddenly very hot!", Monnam(mtmp));
2361 break;
2362 case AD_ELEC:
2363 if (resists_elec(mtmp)) {
2364 shieldeff(mtmp->mx, mtmp->my);
2365 pline("%s is slightly tingled.", Monnam(mtmp));
2366 golemeffects(mtmp, AD_ELEC, tmp);
2367 tmp = 0;
2368 break;
2369 }
2370 pline("%s is jolted with your electricity!", Monnam(mtmp));
2371 break;
2372 default: tmp = 0;
2373 break;
2374 }
2375 else tmp = 0;
2376
2377 assess_dmg:
2378 if((mtmp->mhp -= tmp) <= 0) {
2379 pline("%s dies!", Monnam(mtmp));
2380 xkilled(mtmp,0);
2381 if (mtmp->mhp > 0) return 1;
2382 return 2;
2383 }
2384 return 1;
2385 }
2386
2387 #endif /* OVL1 */
2388 #ifdef OVLB
2389
2390 #include "edog.h"
2391 struct monst *
cloneu()2392 cloneu()
2393 {
2394 register struct monst *mon;
2395 int mndx = monsndx(youmonst.data);
2396
2397 if (u.mh <= 1) return(struct monst *)0;
2398 if (mvitals[mndx].mvflags & G_EXTINCT) return(struct monst *)0;
2399 mon = makemon(youmonst.data, u.ux, u.uy, NO_MINVENT|MM_EDOG);
2400 mon = christen_monst(mon, plname);
2401 initedog(mon);
2402 mon->m_lev = youmonst.data->mlevel;
2403 mon->mhpmax = u.mhmax;
2404 mon->mhp = u.mh / 2;
2405 u.mh -= mon->mhp;
2406 flags.botl = 1;
2407 return(mon);
2408 }
2409
2410 #endif /* OVLB */
2411
2412 /*mhitu.c*/
2413