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