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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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*/