1 | /* SCCS Id: @(#)mon.c 3.3 2000/07/24 */ 2 | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3 | /* NetHack may be freely redistributed. See license for details. */ 4 | 5 | /* If you're using precompiled headers, you don't want this either */ 6 | #ifdef MICROPORT_BUG 7 | #define MKROOM_H 8 | #endif 9 | 10 | #include "hack.h" 11 | #include "mfndpos.h" 12 | #include "edog.h" 13 | #include <ctype.h> 14 | 15 | STATIC_DCL boolean FDECL(corpse_chance,(struct monst *)); 16 | STATIC_DCL boolean FDECL(restrap,(struct monst *)); 17 | STATIC_DCL long FDECL(mm_aggression, (struct monst *,struct monst *)); 18 | #ifdef OVL2 19 | STATIC_DCL int NDECL(pick_animal); 20 | STATIC_DCL int FDECL(select_newcham_form, (struct monst *)); 21 | STATIC_DCL void FDECL(kill_eggs, (struct obj *)); 22 | #endif 23 | 24 | #if 0 25 | /* part of the original warning code which was replaced in 3.3.1 */ 26 | #ifdef OVL1 27 | #define warnDelay 10 28 | long lastwarntime; 29 | int lastwarnlev; 30 | 31 | const char *warnings[] = { 32 | "white", "pink", "red", "ruby", "purple", "black" 33 | }; 34 | 35 | STATIC_DCL void NDECL(warn_effects); 36 | #endif /* OVL1 */ 37 | #endif /* 0 */ 38 | 39 | #ifndef OVLB 40 | STATIC_VAR short cham_to_pm[]; 41 | #else 42 | STATIC_DCL struct obj *FDECL(make_corpse,(struct monst *)); 43 | STATIC_DCL void FDECL(m_detach, (struct monst *, struct permonst *)); 44 | STATIC_DCL void FDECL(lifesaved_monster, (struct monst *)); 45 | 46 | /* convert the monster index of an undead to its living counterpart */ 47 | int 48 | undead_to_corpse(mndx) 49 | int mndx; 50 | { 51 | switch (mndx) { 52 | case PM_KOBOLD_ZOMBIE: 53 | case PM_KOBOLD_MUMMY: mndx = PM_KOBOLD; break; 54 | case PM_DWARF_ZOMBIE: 55 | case PM_DWARF_MUMMY: mndx = PM_DWARF; break; 56 | case PM_GNOME_ZOMBIE: 57 | case PM_GNOME_MUMMY: mndx = PM_GNOME; break; 58 | case PM_ORC_ZOMBIE: 59 | case PM_ORC_MUMMY: mndx = PM_ORC; break; 60 | case PM_ELF_ZOMBIE: 61 | case PM_ELF_MUMMY: mndx = PM_ELF; break; 62 | case PM_VAMPIRE: 63 | case PM_VAMPIRE_LORD: 64 | #if 0 /* DEFERRED */ 65 | case PM_VAMPIRE_MAGE: 66 | #endif 67 | case PM_HUMAN_ZOMBIE: 68 | case PM_HUMAN_MUMMY: mndx = PM_HUMAN; break; 69 | case PM_GIANT_ZOMBIE: 70 | case PM_GIANT_MUMMY: mndx = PM_GIANT; break; 71 | case PM_ETTIN_ZOMBIE: 72 | case PM_ETTIN_MUMMY: mndx = PM_ETTIN; break; 73 | default: break; 74 | } 75 | return mndx; 76 | } 77 | 78 | /* convert monster index to chameleon index */ 79 | int 80 | pm_to_cham(mndx) 81 | int mndx; 82 | { 83 | int mcham; 84 | 85 | switch (mndx) { 86 | case PM_CHAMELEON: mcham = CHAM_CHAMELEON; break; 87 | case PM_DOPPELGANGER: mcham = CHAM_DOPPELGANGER; break; 88 | case PM_SANDESTIN: mcham = CHAM_SANDESTIN; break; 89 | default: mcham = CHAM_ORDINARY; break; 90 | } 91 | return mcham; 92 | } 93 | 94 | /* convert chameleon index to monster index */ 95 | STATIC_VAR short cham_to_pm[] = { 96 | NON_PM, /* placeholder for CHAM_ORDINARY */ 97 | PM_CHAMELEON, 98 | PM_DOPPELGANGER, 99 | PM_SANDESTIN, 100 | }; 101 | 102 | /* return TRUE if the monster tends to revive */ 103 | #define REVIVER(ptr) (is_rider(ptr) || ptr->mlet == S_TROLL) 104 | 105 | #define KEEPTRAITS(mon) (mon->isshk || mon->mtame || \ 106 | (mon->data->geno & G_UNIQ) || REVIVER(mon->data)) 107 | 108 | /* Creates a monster corpse, a "special" corpse, or nothing if it doesn't 109 | * leave corpses. Monsters which leave "special" corpses should have 110 | * G_NOCORPSE set in order to prevent wishing for one, finding tins of one, 111 | * etc.... 112 | */ 113 | STATIC_OVL struct obj * 114 | make_corpse(mtmp) 115 | register struct monst *mtmp; 116 | { 117 | register struct permonst *mdat = mtmp->data; 118 | int num; 119 | struct obj *obj = (struct obj *)0; 120 | int x = mtmp->mx, y = mtmp->my; 121 | int mndx = monsndx(mdat); 122 | 123 | switch(mndx) { 124 | case PM_GRAY_DRAGON: 125 | case PM_SILVER_DRAGON: 126 | #if 0 /* DEFERRED */ 127 | case PM_SHIMMERING_DRAGON: 128 | #endif 129 | case PM_RED_DRAGON: 130 | case PM_ORANGE_DRAGON: 131 | case PM_WHITE_DRAGON: 132 | case PM_BLACK_DRAGON: 133 | case PM_BLUE_DRAGON: 134 | case PM_GREEN_DRAGON: 135 | case PM_YELLOW_DRAGON: 136 | /* Make dragon scales. This assumes that the order of the */ 137 | /* dragons is the same as the order of the scales. */ 138 | if (!rn2(mtmp->mrevived ? 20 : 3)) { 139 | obj = mksobj_at(GRAY_DRAGON_SCALES + 140 | monsndx(mdat)-PM_GRAY_DRAGON, x, y, FALSE); 141 | obj->spe = 0; 142 | obj->cursed = obj->blessed = FALSE; 143 | } 144 | goto default_1; 145 | 146 | case PM_WHITE_UNICORN: 147 | case PM_GRAY_UNICORN: 148 | case PM_BLACK_UNICORN: 149 | (void) mksobj_at(UNICORN_HORN, x, y, TRUE); 150 | goto default_1; 151 | case PM_LONG_WORM: 152 | (void) mksobj_at(WORM_TOOTH, x, y, TRUE); 153 | goto default_1; 154 | case PM_VAMPIRE: 155 | case PM_VAMPIRE_LORD: 156 | /* include mtmp in the mkcorpstat() call */ 157 | num = undead_to_corpse(mndx); 158 | obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, TRUE); 159 | obj->age -= 100; /* this is an *OLD* corpse */ 160 | break; 161 | case PM_KOBOLD_MUMMY: 162 | case PM_DWARF_MUMMY: 163 | case PM_GNOME_MUMMY: 164 | case PM_ORC_MUMMY: 165 | case PM_ELF_MUMMY: 166 | case PM_HUMAN_MUMMY: 167 | case PM_GIANT_MUMMY: 168 | case PM_ETTIN_MUMMY: 169 | case PM_KOBOLD_ZOMBIE: 170 | case PM_DWARF_ZOMBIE: 171 | case PM_GNOME_ZOMBIE: 172 | case PM_ORC_ZOMBIE: 173 | case PM_ELF_ZOMBIE: 174 | case PM_HUMAN_ZOMBIE: 175 | case PM_GIANT_ZOMBIE: 176 | case PM_ETTIN_ZOMBIE: 177 | num = undead_to_corpse(mndx); 178 | obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, TRUE); 179 | obj->age -= 100; /* this is an *OLD* corpse */ 180 | break; 181 | case PM_IRON_GOLEM: 182 | num = d(2,6); 183 | while (num--) 184 | obj = mksobj_at(IRON_CHAIN, x, y, TRUE); 185 | mtmp->mnamelth = 0; 186 | break; 187 | case PM_GLASS_GOLEM: 188 | num = d(2,4); /* very low chance of creating all glass gems */ 189 | while (num--) 190 | obj = mksobj_at((LAST_GEM + rnd(9)), x, y, TRUE); 191 | mtmp->mnamelth = 0; 192 | break; 193 | case PM_CLAY_GOLEM: 194 | obj = mksobj_at(ROCK, x, y, FALSE); 195 | obj->quan = (long)(rn2(20) + 50); 196 | obj->owt = weight(obj); 197 | mtmp->mnamelth = 0; 198 | break; 199 | case PM_STONE_GOLEM: 200 | obj = mkcorpstat(STATUE, (struct monst *)0, 201 | mdat, x, y, FALSE); 202 | break; 203 | case PM_WOOD_GOLEM: 204 | num = d(2,4); 205 | while(num--) { 206 | obj = mksobj_at(QUARTERSTAFF, x, y, TRUE); 207 | if (obj && obj->oartifact) { /* don't allow this */ 208 | artifact_exists(obj, ONAME(obj), FALSE); 209 | Strcpy(ONAME(obj), ""); obj->onamelth = 0; 210 | } 211 | } 212 | mtmp->mnamelth = 0; 213 | break; 214 | case PM_LEATHER_GOLEM: 215 | num = d(2,4); 216 | while(num--) 217 | obj = mksobj_at(LEATHER_ARMOR, x, y, TRUE); 218 | mtmp->mnamelth = 0; 219 | break; 220 | case PM_GOLD_GOLEM: 221 | /* Good luck gives more coins */ 222 | obj = mkgold((long)(200 - rnl(101)), x, y); 223 | mtmp->mnamelth = 0; 224 | break; 225 | case PM_PAPER_GOLEM: 226 | num = d(2,3); 227 | while (num--) 228 | obj = mksobj_at(SCR_BLANK_PAPER, x, y, TRUE); 229 | mtmp->mnamelth = 0; 230 | break; 231 | default_1: 232 | default: 233 | if (mvitals[mndx].mvflags & G_NOCORPSE) 234 | return (struct obj *)0; 235 | else /* preserve the unique traits of some creatures */ 236 | obj = mkcorpstat(CORPSE, KEEPTRAITS(mtmp) ? mtmp : 0, 237 | mdat, x, y, TRUE); 238 | break; 239 | } 240 | /* All special cases should precede the G_NOCORPSE check */ 241 | 242 | if (mtmp->mnamelth) 243 | obj = oname(obj, NAME(mtmp)); 244 | 245 | #ifdef INVISIBLE_OBJECTS 246 | /* Invisible monster ==> invisible corpse */ 247 | obj->oinvis = mtmp->minvis; 248 | #endif 249 | 250 | stackobj(obj); 251 | newsym(x, y); 252 | return obj; 253 | } 254 | 255 | #endif /* OVLB */ 256 | #ifdef OVL1 257 | 258 | #if 0 259 | /* part of the original warning code which was replaced in 3.3.1 */ 260 | STATIC_OVL void 261 | warn_effects() 262 | { 263 | if (warnlevel == 100) { 264 | if(!Blind && uwep && 265 | (warnlevel > lastwarnlev || moves > lastwarntime + warnDelay)) { 266 | Your("%s %s!", aobjnam(uwep, "glow"), 267 | hcolor(light_blue)); 268 | lastwarnlev = warnlevel; 269 | lastwarntime = moves; 270 | } 271 | warnlevel = 0; 272 | return; 273 | } 274 | 275 | if (warnlevel >= SIZE(warnings)) 276 | warnlevel = SIZE(warnings)-1; 277 | if (!Blind && 278 | (warnlevel > lastwarnlev || moves > lastwarntime + warnDelay)) { 279 | const char *which, *what, *how; 280 | long rings = (EWarning & (LEFT_RING|RIGHT_RING)); 281 | 282 | if (rings) { 283 | what = Hallucination ? "mood ring" : "ring"; 284 | how = "glows"; /* singular verb */ 285 | if (rings == LEFT_RING) { 286 | which = "left "; 287 | } else if (rings == RIGHT_RING) { 288 | which = "right "; 289 | } else { /* both */ 290 | which = ""; 291 | what = (const char *) makeplural(what); 292 | how = "glow"; /* plural verb */ 293 | } 294 | Your("%s%s %s %s!", which, what, how, hcolor(warnings[warnlevel])); 295 | } else { 296 | if (Hallucination) 297 | Your("spider-sense is tingling..."); 298 | else 299 | You_feel("apprehensive as you sense a %s flash.", 300 | warnings[warnlevel]); 301 | } 302 | 303 | lastwarntime = moves; 304 | lastwarnlev = warnlevel; 305 | } 306 | } 307 | #endif /* 0 */ 308 | 309 | /* check mtmp and water for compatibility, 0 (survived), 1 (drowned) */ 310 | int 311 | minwater(mtmp) 312 | register struct monst *mtmp; 313 | { 314 | boolean inpool, infountain; 315 | 316 | inpool = is_pool(mtmp->mx,mtmp->my) && 317 | !is_flyer(mtmp->data) && !is_floater(mtmp->data); 318 | infountain = IS_FOUNTAIN(levl[mtmp->mx][mtmp->my].typ); 319 | 320 | #ifdef STEED 321 | /* Flying and levitation keeps our steed out of the water */ 322 | /* (but not water-walking or swimming) */ 323 | if (mtmp == u.usteed && (Flying || Levitation)) 324 | return (0); 325 | #endif 326 | 327 | /* Gremlin multiplying won't go on forever since the hit points 328 | * keep going down, and when it gets to 1 hit point the clone 329 | * function will fail. 330 | */ 331 | if (mtmp->data == &mons[PM_GREMLIN] && (inpool || infountain) && rn2(3)) { 332 | if (split_mon(mtmp, (struct monst *)0)) 333 | dryup(mtmp->mx, mtmp->my, FALSE); 334 | if (inpool) water_damage(mtmp->minvent, FALSE, FALSE); 335 | return (0); 336 | } else if (mtmp->data == &mons[PM_IRON_GOLEM] && inpool && !rn2(5)) { 337 | int dam = d(2,6); 338 | if (cansee(mtmp->mx,mtmp->my)) 339 | pline("%s rusts.", Monnam(mtmp)); 340 | mtmp->mhp -= dam; 341 | if (mtmp->mhpmax > dam) mtmp->mhpmax -= dam; 342 | if (mtmp->mhp < 1) { 343 | mondead(mtmp); 344 | if (mtmp->mhp < 1) return (1); 345 | } 346 | water_damage(mtmp->minvent, FALSE, FALSE); 347 | return (0); 348 | } 349 | 350 | if (inpool) { 351 | /* Most monsters drown in pools. flooreffects() will take care of 352 | * water damage to dead monsters' inventory, but survivors need to 353 | * be handled here. Swimmers are able to protect their stuff... 354 | */ 355 | if (!is_clinger(mtmp->data) 356 | && !is_swimmer(mtmp->data) && !amphibious(mtmp->data)) { 357 | if (cansee(mtmp->mx,mtmp->my)) { 358 | pline("%s drowns.", Monnam(mtmp)); 359 | } 360 | mondead(mtmp); 361 | if (mtmp->mhp > 0) { 362 | rloc(mtmp); 363 | water_damage(mtmp->minvent, FALSE, FALSE); 364 | return 0; 365 | } 366 | return (1); 367 | } 368 | } else { 369 | /* but eels have a difficult time outside */ 370 | if (mtmp->data->mlet == S_EEL && !Is_waterlevel(&u.uz)) { 371 | if(mtmp->mhp > 1) mtmp->mhp--; 372 | mtmp->mflee = 1; 373 | mtmp->mfleetim += 2; 374 | } 375 | } 376 | return (0); 377 | } 378 | 379 | 380 | int 381 | mcalcmove(mon) 382 | struct monst *mon; 383 | { 384 | int mmove = mon->data->mmove; 385 | 386 | /* Note: MSLOW's `+ 1' prevents slowed speed 1 getting reduced to 0; 387 | * MFAST's `+ 2' prevents hasted speed 1 from becoming a no-op; 388 | * both adjustments have negligible effect on higher speeds. 389 | */ 390 | if (mon->mspeed == MSLOW) 391 | mmove = (2 * mmove + 1) / 3; 392 | else if (mon->mspeed == MFAST) 393 | mmove = (4 * mmove + 2) / 3; 394 | 395 | #ifdef STEED 396 | if (mon == u.usteed) { 397 | if (u.ugallop && flags.mv) { 398 | /* average movement is 1.50 times normal */ 399 | mmove = ((rn2(2) ? 4 : 5) * mmove) / 3; 400 | } 401 | } 402 | #endif 403 | 404 | return mmove; 405 | } 406 | 407 | /* actions that happen once per ``turn'', regardless of each 408 | individual monster's metabolism; some of these might need to 409 | be reclassified to occur more in proportion with movement rate */ 410 | void 411 | mcalcdistress() 412 | { 413 | struct monst *mtmp; 414 | 415 | for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { 416 | if (DEADMONSTER(mtmp)) continue; 417 | 418 | /* regenerate hit points */ 419 | mon_regen(mtmp, FALSE); 420 | 421 | /* possibly polymorph shapechangers and lycanthropes */ 422 | if (mtmp->cham && !rn2(6)) 423 | (void) newcham(mtmp, (struct permonst *)0); 424 | were_change(mtmp); 425 | 426 | /* gradually time out temporary problems */ 427 | if (mtmp->mblinded && !--mtmp->mblinded) 428 | mtmp->mcansee = 1; 429 | if (mtmp->mfrozen && !--mtmp->mfrozen) 430 | mtmp->mcanmove = 1; 431 | if (mtmp->mfleetim && !--mtmp->mfleetim) 432 | mtmp->mflee = 0; 433 | 434 | /* FIXME: mtmp->mlstmv ought to be updated here */ 435 | } 436 | } 437 | 438 | int 439 | movemon() 440 | { 441 | register struct monst *mtmp, *nmtmp; 442 | register boolean somebody_can_move = FALSE; 443 | #if 0 444 | /* part of the original warning code which was replaced in 3.3.1 */ 445 | warnlevel = 0; 446 | #endif 447 | 448 | /* 449 | Some of you may remember the former assertion here that 450 | because of deaths and other actions, a simple one-pass 451 | algorithm wasn't possible for movemon. Deaths are no longer 452 | removed to the separate list fdmon; they are simply left in 453 | the chain with hit points <= 0, to be cleaned up at the end 454 | of the pass. 455 | 456 | The only other actions which cause monsters to be removed from 457 | the chain are level migrations and losedogs(). I believe losedogs() 458 | is a cleanup routine not associated with monster movements, and 459 | monsters can only affect level migrations on themselves, not others 460 | (hence the fetching of nmon before moving the monster). Currently, 461 | monsters can jump into traps, read cursed scrolls of teleportation, 462 | and drink cursed potions of raise level to change levels. These are 463 | all reflexive at this point. Should one monster be able to level 464 | teleport another, this scheme would have problems. 465 | */ 466 | 467 | for(mtmp = fmon; mtmp; mtmp = nmtmp) { 468 | nmtmp = mtmp->nmon; 469 | 470 | /* Find a monster that we have not treated yet. */ 471 | if(DEADMONSTER(mtmp)) 472 | continue; 473 | if(mtmp->movement < NORMAL_SPEED) 474 | continue; 475 | 476 | mtmp->movement -= NORMAL_SPEED; 477 | if (mtmp->movement >= NORMAL_SPEED) 478 | somebody_can_move = TRUE; 479 | 480 | if (minwater(mtmp)) continue; 481 | 482 | if (is_hider(mtmp->data)) { 483 | /* unwatched mimics and piercers may hide again [MRS] */ 484 | if(restrap(mtmp)) continue; 485 | if(mtmp->m_ap_type == M_AP_FURNITURE || 486 | mtmp->m_ap_type == M_AP_OBJECT) 487 | continue; 488 | if(mtmp->mundetected) continue; 489 | } 490 | 491 | /* continue if the monster died fighting */ 492 | if (Conflict && !mtmp->iswiz && mtmp->mcansee) { 493 | /* Note: 494 | * Conflict does not take effect in the first round. 495 | * Therefore, A monster when stepping into the area will 496 | * get to swing at you. 497 | * 498 | * The call to fightm() must be _last_. The monster might 499 | * have died if it returns 1. 500 | */ 501 | if (couldsee(mtmp->mx,mtmp->my) && 502 | (distu(mtmp->mx,mtmp->my) <= BOLT_LIM*BOLT_LIM) && 503 | fightm(mtmp)) 504 | continue; /* mon might have died */ 505 | } 506 | if(dochugw(mtmp)) /* otherwise just move the monster */ 507 | continue; 508 | } 509 | #if 0 510 | /* part of the original warning code which was replaced in 3.3.1 */ 511 | if(warnlevel > 0) 512 | warn_effects(); 513 | #endif 514 | 515 | if (any_light_source()) 516 | vision_full_recalc = 1; /* in case a mon moved with a light source */ 517 | dmonsfree(); /* remove all dead monsters */ 518 | 519 | /* a monster may have levteleported player -dlc */ 520 | if (u.utotype) { 521 | deferred_goto(); 522 | /* changed levels, so these monsters are dormant */ 523 | somebody_can_move = FALSE; 524 | } 525 | 526 | return somebody_can_move; 527 | } 528 | 529 | #endif /* OVL1 */ 530 | #ifdef OVLB 531 | 532 | #define mstoning(obj) (ofood(obj) && \ 533 | (touch_petrifies(&mons[(obj)->corpsenm]) || \ 534 | (obj)->corpsenm == PM_MEDUSA)) 535 | 536 | /* 537 | * Maybe eat a metallic object (not just gold). 538 | * Return value: 0 => nothing happened, 1 => monster ate something, 539 | * 2 => monster died (it must have grown into a genocided form, but 540 | * that can't happen at present because nothing which eats objects 541 | * has young and old forms). 542 | */ 543 | int 544 | meatgold(mtmp) 545 | register struct monst *mtmp; 546 | { 547 | register struct obj *otmp; 548 | struct permonst *ptr; 549 | int poly, grow, heal, mstone; 550 | 551 | /* If a pet, eating is handled separately, in dog.c */ 552 | if (mtmp->mtame) return 0; 553 | 554 | /* Eats topmost metal object if it is there */ 555 | for (otmp = level.objects[mtmp->mx][mtmp->my]; 556 | otmp; otmp = otmp->nexthere) 557 | if (is_metallic(otmp) && !obj_resists(otmp, 5, 95) && 558 | touch_artifact(otmp,mtmp)) { 559 | if (mtmp->data == &mons[PM_RUST_MONSTER] && otmp->oerodeproof) { 560 | if (canseemon(mtmp) && flags.verbose) { 561 | pline("%s eats %s!", 562 | Monnam(mtmp), 563 | distant_name(otmp,doname)); 564 | } 565 | /* The object's rustproofing is gone now */ 566 | otmp->oerodeproof = 0; 567 | mtmp->mstun = 1; 568 | if (canseemon(mtmp) && flags.verbose) { 569 | pline("%s spits %s out in disgust!", 570 | Monnam(mtmp), distant_name(otmp,doname)); 571 | } 572 | /* KMH -- Don't eat undigestable/choking objects */ 573 | } else if (otmp->otyp != AMULET_OF_STRANGULATION && 574 | otmp->otyp != RIN_SLOW_DIGESTION) { 575 | if (cansee(mtmp->mx,mtmp->my) && flags.verbose) 576 | pline("%s eats %s!", Monnam(mtmp), 577 | distant_name(otmp,doname)); 578 | else if (flags.soundok && flags.verbose) 579 | You_hear("a crunching sound."); 580 | mtmp->meating = otmp->owt/2 + 1; 581 | /* Heal up to the object's weight in hp */ 582 | if (mtmp->mhp < mtmp->mhpmax) { 583 | mtmp->mhp += objects[otmp->otyp].oc_weight; 584 | if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; 585 | } 586 | if(otmp == uball) { 587 | unpunish(); 588 | delobj(otmp); 589 | } else if (otmp == uchain) { 590 | unpunish(); /* frees uchain */ 591 | } else { 592 | poly = polyfodder(otmp); 593 | grow = mlevelgain(otmp); 594 | heal = mhealup(otmp); 595 | mstone = mstoning(otmp); 596 | delobj(otmp); 597 | ptr = mtmp->data; 598 | if (poly) { 599 | if (newcham(mtmp, (struct permonst *)0)) 600 | ptr = mtmp->data; 601 | } else if (grow) { 602 | ptr = grow_up(mtmp, (struct monst *)0); 603 | } else if (mstone) { 604 | if (poly_when_stoned(ptr)) { 605 | mon_to_stone(mtmp); 606 | ptr = mtmp->data; 607 | } else if (!resists_ston(mtmp)) { 608 | if (canseemon(mtmp)) 609 | pline("%s turns to stone!", Monnam(mtmp)); 610 | monstone(mtmp); 611 | ptr = (struct permonst *)0; 612 | } 613 | } else if (heal) { 614 | mtmp->mhp = mtmp->mhpmax; 615 | } 616 | if (!ptr) return 2; /* it died */ 617 | } 618 | /* Left behind a pile? */ 619 | if(rnd(25) < 3) (void) mksobj_at(ROCK, mtmp->mx, mtmp->my, TRUE); 620 | newsym(mtmp->mx, mtmp->my); 621 | return 1; 622 | } 623 | } 624 | return 0; 625 | } 626 | 627 | int 628 | meatobj(mtmp) /* for gelatinous cubes */ 629 | register struct monst *mtmp; 630 | { 631 | register struct obj *otmp, *otmp2; 632 | struct permonst *ptr; 633 | int poly, grow, heal, count = 0, ecount = 0; 634 | char buf[BUFSZ]; 635 | 636 | buf[0] = '\0'; 637 | /* If a pet, eating is handled separately, in dog.c */ 638 | if (mtmp->mtame) return 0; 639 | 640 | /* Eats organic objects, including cloth and wood, if there */ 641 | /* Engulfs others, except huge rocks and metal attached to player */ 642 | for (otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { 643 | otmp2 = otmp->nexthere; 644 | if (is_organic(otmp) && !obj_resists(otmp, 5, 95) && 645 | touch_artifact(otmp,mtmp)) { 646 | if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && 647 | !resists_ston(mtmp)) 648 | continue; 649 | if (otmp->otyp == AMULET_OF_STRANGULATION || 650 | otmp->otyp == RIN_SLOW_DIGESTION) 651 | continue; 652 | ++count; 653 | if (cansee(mtmp->mx,mtmp->my) && flags.verbose) 654 | pline("%s eats %s!", Monnam(mtmp), 655 | distant_name(otmp, doname)); 656 | else if (flags.soundok && flags.verbose) 657 | You_hear("a slurping sound."); 658 | /* Heal up to the object's weight in hp */ 659 | if (mtmp->mhp < mtmp->mhpmax) { 660 | mtmp->mhp += objects[otmp->otyp].oc_weight; 661 | if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; 662 | } 663 | if (Has_contents(otmp)) { 664 | register struct obj *otmp3; 665 | /* contents of eaten containers become engulfed; this 666 | is arbitrary, but otherwise g.cubes are too powerful */ 667 | while ((otmp3 = otmp->cobj) != 0) { 668 | obj_extract_self(otmp3); 669 | if (otmp->otyp == ICE_BOX && otmp3->otyp == CORPSE) { 670 | otmp3->age = monstermoves - otmp3->age; 671 | start_corpse_timeout(otmp3); 672 | } 673 | (void) mpickobj(mtmp, otmp3); 674 | } 675 | } 676 | poly = polyfodder(otmp); 677 | grow = mlevelgain(otmp); 678 | heal = mhealup(otmp); 679 | delobj(otmp); /* munch */ 680 | ptr = mtmp->data; 681 | if (poly) { 682 | if (newcham(mtmp, (struct permonst *)0)) ptr = mtmp->data; 683 | } else if (grow) { 684 | ptr = grow_up(mtmp, (struct monst *)0); 685 | } else if (heal) { 686 | mtmp->mhp = mtmp->mhpmax; 687 | } 688 | /* in case it polymorphed or died */ 689 | if (ptr != &mons[PM_GELATINOUS_CUBE]) 690 | return !ptr ? 2 : 1; 691 | } else if (otmp->oclass != ROCK_CLASS && 692 | otmp != uball && otmp != uchain) { 693 | ++ecount; 694 | if (ecount == 1) { 695 | Sprintf(buf, "%s engulfs %s.", Monnam(mtmp), 696 | distant_name(otmp,doname)); 697 | } else if (ecount == 2) 698 | Sprintf(buf, "%s engulfs several objects.", Monnam(mtmp)); 699 | obj_extract_self(otmp); 700 | (void) mpickobj(mtmp, otmp); /* slurp */ 701 | } 702 | /* Engulf & devour is instant, so don't set meating */ 703 | if (mtmp->minvis) newsym(mtmp->mx, mtmp->my); 704 | } 705 | if (ecount > 0) { 706 | if (cansee(mtmp->mx, mtmp->my) && flags.verbose && buf[0]) 707 | pline("%s", buf); 708 | else if (flags.soundok && flags.verbose) 709 | You_hear("%s slurping sound%s.", 710 | ecount == 1 ? "a" : "several", 711 | ecount == 1 ? "" : "s"); 712 | } 713 | return ((count > 0) || (ecount > 0)) ? 1 : 0; 714 | } 715 | 716 | void 717 | mpickgold(mtmp) 718 | register struct monst *mtmp; 719 | { 720 | register struct obj *gold; 721 | 722 | if ((gold = g_at(mtmp->mx, mtmp->my)) != 0) { 723 | mtmp->mgold += gold->quan; 724 | delobj(gold); 725 | if (cansee(mtmp->mx, mtmp->my) ) { 726 | if (flags.verbose && !mtmp->isgd) 727 | pline("%s picks up some gold.", Monnam(mtmp)); 728 | newsym(mtmp->mx, mtmp->my); 729 | } 730 | } 731 | } 732 | #endif /* OVLB */ 733 | #ifdef OVL2 734 | 735 | boolean 736 | mpickstuff(mtmp, str) 737 | register struct monst *mtmp; 738 | register const char *str; 739 | { 740 | register struct obj *otmp, *otmp2; 741 | 742 | /* prevent shopkeepers from leaving the door of their shop */ 743 | if(mtmp->isshk && inhishop(mtmp)) return FALSE; 744 | 745 | for(otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { 746 | otmp2 = otmp->nexthere; 747 | /* Nymphs take everything. Most monsters don't pick up corpses. */ 748 | if (!str ? searches_for_item(mtmp,otmp) : 749 | !!(index(str, otmp->oclass))) { 750 | if (otmp->otyp == CORPSE && ( 751 | is_rider(&mons[otmp->corpsenm]) || 752 | (touch_petrifies(&mons[otmp->corpsenm]) 753 | && !(mtmp->misc_worn_check & W_ARMG)) || 754 | (mtmp->data->mlet != S_NYMPH 755 | && !touch_petrifies(&mons[otmp->corpsenm]) 756 | && otmp->corpsenm != PM_LIZARD 757 | && !acidic(&mons[otmp->corpsenm])) 758 | )) 759 | continue; 760 | if (!touch_artifact(otmp,mtmp)) continue; 761 | if (!can_carry(mtmp,otmp)) continue; 762 | if (is_pool(mtmp->mx,mtmp->my)) continue; 763 | #ifdef INVISIBLE_OBJECTS 764 | if (otmp->oinvis && !perceives(mtmp->data)) continue; 765 | #endif 766 | if (cansee(mtmp->mx,mtmp->my) && flags.verbose) 767 | pline("%s picks up %s.", Monnam(mtmp), 768 | (distu(mtmp->my, mtmp->my) <= 5) ? 769 | doname(otmp) : distant_name(otmp, doname)); 770 | obj_extract_self(otmp); 771 | /* unblock point after extract, before pickup */ 772 | if (otmp->otyp == BOULDER) 773 | unblock_point(otmp->ox,otmp->oy); /* vision */ 774 | (void) mpickobj(mtmp, otmp); /* may merge and free otmp */ 775 | m_dowear(mtmp, FALSE); 776 | newsym(mtmp->mx, mtmp->my); 777 | return TRUE; /* pick only one object */ 778 | } 779 | } 780 | return FALSE; 781 | } 782 | 783 | #endif /* OVL2 */ 784 | #ifdef OVL0 785 | 786 | int 787 | curr_mon_load(mtmp) 788 | register struct monst *mtmp; 789 | { 790 | register int curload = 0; 791 | register struct obj *obj; 792 | 793 | for(obj = mtmp->minvent; obj; obj = obj->nobj) { 794 | if(obj->otyp != BOULDER || !throws_rocks(mtmp->data)) 795 | curload += obj->owt; 796 | } 797 | 798 | return curload; 799 | } 800 | 801 | int 802 | max_mon_load(mtmp) 803 | register struct monst *mtmp; 804 | { 805 | register long maxload; 806 | 807 | /* Base monster carrying capacity is equal to human maximum 808 | * carrying capacity, or half human maximum if not strong. 809 | * (for a polymorphed player, the value used would be the 810 | * non-polymorphed carrying capacity instead of max/half max). 811 | * This is then modified by the ratio between the monster weights 812 | * and human weights. Corpseless monsters are given a capacity 813 | * proportional to their size instead of weight. 814 | */ 815 | if (!mtmp->data->cwt) 816 | maxload = (MAX_CARR_CAP * (long)mtmp->data->msize) / MZ_HUMAN; 817 | else if (!strongmonst(mtmp->data) 818 | || (strongmonst(mtmp->data) && (mtmp->data->cwt > WT_HUMAN))) 819 | maxload = (MAX_CARR_CAP * (long)mtmp->data->cwt) / WT_HUMAN; 820 | else maxload = MAX_CARR_CAP; /*strong monsters w/cwt <= WT_HUMAN*/ 821 | 822 | if (!strongmonst(mtmp->data)) maxload /= 2; 823 | 824 | if (maxload < 1) maxload = 1; 825 | 826 | return (int) maxload; 827 | } 828 | 829 | /* for restricting monsters' object-pickup */ 830 | boolean 831 | can_carry(mtmp,otmp) 832 | struct monst *mtmp; 833 | struct obj *otmp; 834 | { 835 | int otyp = otmp->otyp, newload = otmp->owt; 836 | struct permonst *mdat = mtmp->data; 837 | 838 | if (notake(mdat)) return FALSE; /* can't carry anything */ 839 | 840 | if (otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && 841 | !(mtmp->misc_worn_check & W_ARMG) && !resists_ston(mtmp)) 842 | return FALSE; 843 | if (objects[otyp].oc_material == SILVER && hates_silver(mdat) && 844 | (otyp != BELL_OF_OPENING || !is_covetous(mdat))) 845 | return FALSE; 846 | 847 | #ifdef STEED 848 | /* Steeds don't pick up stuff (to avoid shop abuse) */ 849 | if (mtmp == u.usteed) return (FALSE); 850 | #endif 851 | if (mtmp->isshk) return(TRUE); /* no limit */ 852 | if (mtmp->mpeaceful && !mtmp->mtame) return(FALSE); 853 | /* otherwise players might find themselves obligated to violate 854 | * their alignment if the monster takes something they need 855 | */ 856 | 857 | /* special--boulder throwers carry unlimited amounts of boulders */ 858 | if (throws_rocks(mdat) && otyp == BOULDER) 859 | return(TRUE); 860 | 861 | /* nymphs deal in stolen merchandise, but not boulders or statues */ 862 | if (mdat->mlet == S_NYMPH) 863 | return (boolean)(otmp->oclass != ROCK_CLASS); 864 | 865 | if (curr_mon_load(mtmp) + newload > max_mon_load(mtmp)) return FALSE; 866 | 867 | return(TRUE); 868 | } 869 | 870 | /* return number of acceptable neighbour positions */ 871 | int 872 | mfndpos(mon, poss, info, flag) 873 | register struct monst *mon; 874 | coord *poss; /* coord poss[9] */ 875 | long *info; /* long info[9] */ 876 | long flag; 877 | { 878 | struct permonst *mdat = mon->data; 879 | register xchar x,y,nx,ny; 880 | register int cnt = 0; 881 | register uchar ntyp; 882 | uchar nowtyp; 883 | boolean wantpool,poolok,lavaok,nodiag; 884 | int maxx, maxy; 885 | 886 | x = mon->mx; 887 | y = mon->my; 888 | nowtyp = levl[x][y].typ; 889 | 890 | nodiag = (mdat == &mons[PM_GRID_BUG]); 891 | wantpool = mdat->mlet == S_EEL; 892 | poolok = is_flyer(mdat) || is_clinger(mdat) || 893 | (is_swimmer(mdat) && !wantpool); 894 | lavaok = is_flyer(mdat) || is_clinger(mdat) || likes_lava(mdat); 895 | 896 | nexttry: /* eels prefer the water, but if there is no water nearby, 897 | they will crawl over land */ 898 | if(mon->mconf) { 899 | flag |= ALLOW_ALL; 900 | flag &= ~NOTONL; 901 | } 902 | if(!mon->mcansee) 903 | flag |= ALLOW_SSM; 904 | maxx = min(x+1,COLNO-1); 905 | maxy = min(y+1,ROWNO-1); 906 | for(nx = max(1,x-1); nx <= maxx; nx++) 907 | for(ny = max(0,y-1); ny <= maxy; ny++) { 908 | if(nx == x && ny == y) continue; 909 | if(IS_ROCK(ntyp = levl[nx][ny].typ) && 910 | !((flag & ALLOW_WALL) && may_passwall(nx,ny)) && 911 | !((flag & ALLOW_DIG) && may_dig(nx,ny))) continue; 912 | /* KMH -- Added iron bars */ 913 | if (ntyp == IRONBARS && 914 | !((flag & ALLOW_WALL) && may_passwall(nx,ny))) continue; 915 | if(IS_DOOR(ntyp) && !amorphous(mdat) && 916 | ((levl[nx][ny].doormask & D_CLOSED && !(flag & OPENDOOR)) || 917 | (levl[nx][ny].doormask & D_LOCKED && !(flag & UNLOCKDOOR)) 918 | ) && !(flag & (ALLOW_WALL|ALLOW_DIG|BUSTDOOR))) continue; 919 | if(nx != x && ny != y && (nodiag || 920 | #ifdef REINCARNATION 921 | ((IS_DOOR(nowtyp) && 922 | ((levl[x][y].doormask & ~D_BROKEN) || Is_rogue_level(&u.uz))) || 923 | (IS_DOOR(ntyp) && 924 | ((levl[nx][ny].doormask & ~D_BROKEN) || Is_rogue_level(&u.uz)))) 925 | #else 926 | ((IS_DOOR(nowtyp) && (levl[x][y].doormask & ~D_BROKEN)) || 927 | (IS_DOOR(ntyp) && (levl[nx][ny].doormask & ~D_BROKEN))) 928 | #endif 929 | )) 930 | continue; 931 | if((is_pool(nx,ny) == wantpool || poolok) && 932 | (lavaok || !is_lava(nx,ny))) { 933 | int dispx, dispy; 934 | boolean monseeu = (mon->mcansee && (!Invis || perceives(mdat))); 935 | boolean checkobj = OBJ_AT(nx,ny); 936 | 937 | /* Displacement also displaces the Elbereth/scare monster, 938 | * as long as you are visible. 939 | */ 940 | if(Displaced && monseeu && (mon->mux==nx) && (mon->muy==ny)) { 941 | dispx = u.ux; 942 | dispy = u.uy; 943 | } else { 944 | dispx = nx; 945 | dispy = ny; 946 | } 947 | 948 | info[cnt] = 0; 949 | if ((checkobj || Displaced) && onscary(dispx, dispy, mon)) { 950 | if(!(flag & ALLOW_SSM)) continue; 951 | info[cnt] |= ALLOW_SSM; 952 | } 953 | if((nx == u.ux && ny == u.uy) || 954 | (nx == mon->mux && ny == mon->muy)) { 955 | if (nx == u.ux && ny == u.uy) { 956 | /* If it's right next to you, it found you, 957 | * displaced or no. We must set mux and muy 958 | * right now, so when we return we can tell 959 | * that the ALLOW_U means to attack _you_ and 960 | * not the image. 961 | */ 962 | mon->mux = u.ux; 963 | mon->muy = u.uy; 964 | } 965 | if(!(flag & ALLOW_U)) continue; 966 | info[cnt] |= ALLOW_U; 967 | } else { 968 | if(MON_AT(nx, ny)) { 969 | struct monst *mtmp2 = m_at(nx, ny); 970 | long mmflag = flag | mm_aggression(mon, mtmp2); 971 | 972 | if (!(mmflag & ALLOW_M)) continue; 973 | info[cnt] |= ALLOW_M; 974 | if (mtmp2->mtame) { 975 | if (!(mmflag & ALLOW_TM)) continue; 976 | info[cnt] |= ALLOW_TM; 977 | } 978 | } 979 | /* Note: ALLOW_SANCT only prevents movement, not */ 980 | /* attack, into a temple. */ 981 | if(level.flags.has_temple && 982 | *in_rooms(nx, ny, TEMPLE) && 983 | !*in_rooms(x, y, TEMPLE) && 984 | in_your_sanctuary((struct monst *)0, nx, ny)) { 985 | if(!(flag & ALLOW_SANCT)) continue; 986 | info[cnt] |= ALLOW_SANCT; 987 | } 988 | } 989 | if(checkobj && sobj_at(CLOVE_OF_GARLIC, nx, ny)) { 990 | if(flag & NOGARLIC) continue; 991 | info[cnt] |= NOGARLIC; 992 | } 993 | if(checkobj && sobj_at(BOULDER, nx, ny)) { 994 | if(!(flag & ALLOW_ROCK)) continue; 995 | info[cnt] |= ALLOW_ROCK; 996 | } 997 | if (monseeu && onlineu(nx,ny)) { 998 | if(flag & NOTONL) continue; 999 | info[cnt] |= NOTONL; 1000 | } 1001 | if (nx != x && ny != y && bad_rock(mdat, x, ny) 1002 | && bad_rock(mdat, nx, y) 1003 | && (bigmonst(mdat) || (curr_mon_load(mon) > 600))) 1004 | continue; 1005 | /* The monster avoids a particular type of trap if it's familiar 1006 | * with the trap type. Pets get ALLOW_TRAPS and checking is 1007 | * done in dogmove.c. In either case, "harmless" traps are 1008 | * neither avoided nor marked in info[]. 1009 | */ 1010 | { register struct trap *ttmp = t_at(nx, ny); 1011 | if(ttmp) { 1012 | if(ttmp->ttyp >= TRAPNUM || ttmp->ttyp == 0) { 1013 | impossible("A monster looked at a very strange trap of type %d.", ttmp->ttyp); 1014 | continue; 1015 | } 1016 | if ((ttmp->ttyp != RUST_TRAP 1017 | || mdat == &mons[PM_IRON_GOLEM]) 1018 | && ttmp->ttyp != STATUE_TRAP 1019 | && ((ttmp->ttyp != PIT 1020 | && ttmp->ttyp != SPIKED_PIT 1021 | && ttmp->ttyp != TRAPDOOR 1022 | && ttmp->ttyp != HOLE) 1023 | || (!is_flyer(mdat) 1024 | && !is_floater(mdat) 1025 | && !is_clinger(mdat)) 1026 | || In_sokoban(&u.uz)) 1027 | && (ttmp->ttyp != SLP_GAS_TRAP || 1028 | !resists_sleep(mon)) 1029 | && (ttmp->ttyp != BEAR_TRAP || 1030 | (mdat->msize > MZ_SMALL && 1031 | !amorphous(mdat) && !is_flyer(mdat))) 1032 | && (ttmp->ttyp != FIRE_TRAP || 1033 | !resists_fire(mon)) 1034 | && (ttmp->ttyp != SQKY_BOARD || !is_flyer(mdat)) 1035 | && (ttmp->ttyp != WEB || (!amorphous(mdat) && 1036 | !webmaker(mdat))) 1037 | ) { 1038 | if (!(flag & ALLOW_TRAPS)) { 1039 | if (mon->mtrapseen & (1L << (ttmp->ttyp - 1))) 1040 | continue; 1041 | } 1042 | info[cnt] |= ALLOW_TRAPS; 1043 | } 1044 | } 1045 | } 1046 | poss[cnt].x = nx; 1047 | poss[cnt].y = ny; 1048 | cnt++; 1049 | } 1050 | } 1051 | if(!cnt && wantpool && !is_pool(x,y)) { 1052 | wantpool = FALSE; 1053 | goto nexttry; 1054 | } 1055 | return(cnt); 1056 | } 1057 | 1058 | #endif /* OVL0 */ 1059 | #ifdef OVL1 1060 | 1061 | /* Monster against monster special attacks; for the specified monster 1062 | combinations, this allows one monster to attack another adjacent one 1063 | in the absence of Conflict. There is no provision for targetting 1064 | other monsters; just hand to hand fighting when they happen to be 1065 | next to each other. */ 1066 | STATIC_OVL long 1067 | mm_aggression(magr, mdef) 1068 | struct monst *magr, /* monster that is currently deciding where to move */ 1069 | *mdef; /* another monster which is next to it */ 1070 | { 1071 | /* supposedly purple worms are attracted to shrieking because they 1072 | like to eat shriekers, so attack the latter when feasible */ 1073 | if (magr->data == &mons[PM_PURPLE_WORM] && 1074 | mdef->data == &mons[PM_SHRIEKER]) 1075 | return ALLOW_M|ALLOW_TM; 1076 | /* Various other combinations such as dog vs cat, cat vs rat, and 1077 | elf vs orc have been suggested. For the time being we don't 1078 | support those. */ 1079 | return 0L; 1080 | } 1081 | 1082 | boolean 1083 | monnear(mon, x, y) 1084 | register struct monst *mon; 1085 | register int x,y; 1086 | /* Is the square close enough for the monster to move or attack into? */ 1087 | { 1088 | register int distance = dist2(mon->mx, mon->my, x, y); 1089 | if (distance==2 && mon->data==&mons[PM_GRID_BUG]) return 0; 1090 | return((boolean)(distance < 3)); 1091 | } 1092 | 1093 | /* really free dead monsters */ 1094 | void 1095 | dmonsfree() 1096 | { 1097 | struct monst **mtmp; 1098 | int count = 0; 1099 | 1100 | for (mtmp = &fmon; *mtmp;) { 1101 | if ((*mtmp)->mhp <= 0) { 1102 | struct monst *freetmp = *mtmp; 1103 | *mtmp = (*mtmp)->nmon; 1104 | dealloc_monst(freetmp); 1105 | count++; 1106 | } else 1107 | mtmp = &(*mtmp)->nmon; 1108 | } 1109 | 1110 | if (count != iflags.purge_monsters) 1111 | impossible("dmonsfree: %d removed doesn't match %d pending", 1112 | count, iflags.purge_monsters); 1113 | iflags.purge_monsters = 0; 1114 | } 1115 | 1116 | #endif /* OVL1 */ 1117 | #ifdef OVLB 1118 | 1119 | /* called when monster is moved to larger structure */ 1120 | void 1121 | replmon(mtmp, mtmp2) 1122 | register struct monst *mtmp, *mtmp2; 1123 | { 1124 | struct obj *otmp; 1125 | 1126 | /* transfer the monster's inventory */ 1127 | for (otmp = mtmp2->minvent; otmp; otmp = otmp->nobj) { 1128 | #ifdef DEBUG 1129 | if (otmp->where != OBJ_MINVENT || otmp->ocarry != mtmp) 1130 | panic("replmon: minvent inconsistency"); 1131 | #endif 1132 | otmp->ocarry = mtmp2; 1133 | } 1134 | mtmp->minvent = 0; 1135 | 1136 | /* remove the old monster from the map and from `fmon' list */ 1137 | relmon(mtmp); 1138 | 1139 | /* finish adding its replacement */ 1140 | #ifdef STEED 1141 | if (mtmp == u.usteed) ; else /* don't place steed onto the map */ 1142 | #endif 1143 | place_monster(mtmp2, mtmp2->mx, mtmp2->my); 1144 | if (mtmp2->wormno) /* update level.monsters[wseg->wx][wseg->wy] */ 1145 | place_wsegs(mtmp2); /* locations to mtmp2 not mtmp. */ 1146 | if (emits_light(mtmp2->data)) { 1147 | /* since this is so rare, we don't have any `mon_move_light_source' */ 1148 | new_light_source(mtmp2->mx, mtmp2->my, 1149 | emits_light(mtmp2->data), 1150 | LS_MONSTER, (genericptr_t)mtmp2); 1151 | /* here we rely on the fact that `mtmp' hasn't actually been deleted */ 1152 | del_light_source(LS_MONSTER, (genericptr_t)mtmp); 1153 | } 1154 | mtmp2->nmon = fmon; 1155 | fmon = mtmp2; 1156 | if (u.ustuck == mtmp) u.ustuck = mtmp2; 1157 | #ifdef STEED 1158 | if (u.usteed == mtmp) u.usteed = mtmp2; 1159 | #endif 1160 | if (mtmp2->isshk) replshk(mtmp,mtmp2); 1161 | 1162 | /* discard the old monster */ 1163 | dealloc_monst(mtmp); 1164 | } 1165 | 1166 | /* release mon from display and monster list */ 1167 | void 1168 | relmon(mon) 1169 | register struct monst *mon; 1170 | { 1171 | register struct monst *mtmp; 1172 | 1173 | if (fmon == (struct monst *)0) panic ("relmon: no fmon available."); 1174 | 1175 | remove_monster(mon->mx, mon->my); 1176 | 1177 | if(mon == fmon) fmon = fmon->nmon; 1178 | else { 1179 | for(mtmp = fmon; mtmp && mtmp->nmon != mon; mtmp = mtmp->nmon) ; 1180 | if(mtmp) mtmp->nmon = mon->nmon; 1181 | else panic("relmon: mon not in list."); 1182 | } 1183 | } 1184 | 1185 | /* remove effects of mtmp from other data structures */ 1186 | STATIC_OVL void 1187 | m_detach(mtmp, mptr) 1188 | struct monst *mtmp; 1189 | struct permonst *mptr; /* reflects mtmp->data _prior_ to mtmp's death */ 1190 | { 1191 | if(mtmp->mleashed) m_unleash(mtmp); 1192 | /* to prevent an infinite relobj-flooreffects-hmon-killed loop */ 1193 | mtmp->mtrapped = 0; 1194 | mtmp->mhp = 0; /* simplify some tests: force mhp to 0 */ 1195 | relobj(mtmp, 0, FALSE); 1196 | remove_monster(mtmp->mx, mtmp->my); 1197 | if (emits_light(mptr)) 1198 | del_light_source(LS_MONSTER, (genericptr_t)mtmp); 1199 | newsym(mtmp->mx,mtmp->my); 1200 | unstuck(mtmp); 1201 | fill_pit(mtmp->mx, mtmp->my); 1202 | 1203 | if(mtmp->isshk) shkgone(mtmp); 1204 | if(mtmp->wormno) wormgone(mtmp); 1205 | iflags.purge_monsters++; 1206 | } 1207 | 1208 | /* find the worn amulet of life saving which will save a monster */ 1209 | struct obj * 1210 | mlifesaver(mon) 1211 | struct monst *mon; 1212 | { 1213 | if (!nonliving(mon->data)) { 1214 | struct obj *otmp = which_armor(mon, W_AMUL); 1215 | 1216 | if (otmp && otmp->otyp == AMULET_OF_LIFE_SAVING) 1217 | return otmp; 1218 | } 1219 | return (struct obj *)0; 1220 | } 1221 | 1222 | STATIC_OVL void 1223 | lifesaved_monster(mtmp) 1224 | struct monst *mtmp; 1225 | { 1226 | struct obj *lifesave = mlifesaver(mtmp); 1227 | 1228 | if (lifesave) { 1229 | /* not canseemon; amulets are on the head, so you don't want */ 1230 | /* to show this for a long worm with only a tail visible. */ 1231 | /* Nor do you check invisibility, because glowing and disinte- */ 1232 | /* grating amulets are always visible. */ 1233 | if (cansee(mtmp->mx, mtmp->my)) { 1234 | pline("But wait..."); 1235 | pline("%s medallion begins to glow!", 1236 | s_suffix(Monnam(mtmp))); 1237 | makeknown(AMULET_OF_LIFE_SAVING); 1238 | pline("%s looks much better!", Monnam(mtmp)); 1239 | pline_The("medallion crumbles to dust!"); 1240 | } 1241 | m_useup(mtmp, lifesave); 1242 | mtmp->mcanmove = 1; 1243 | mtmp->mfrozen = 0; 1244 | if (mtmp->mtame && !mtmp->isminion) { 1245 | struct edog *edog = EDOG(mtmp); 1246 | if (edog->hungrytime < moves+500) 1247 | edog->hungrytime = moves+500; 1248 | if (edog->mhpmax_penalty) { 1249 | /* was starving */ 1250 | mtmp->mhpmax += edog->mhpmax_penalty; 1251 | edog->mhpmax_penalty = 0; 1252 | } 1253 | wary_dog(mtmp, FALSE); 1254 | } 1255 | if (mtmp->mhpmax <= 0) mtmp->mhpmax = 10; 1256 | mtmp->mhp = mtmp->mhpmax; 1257 | if (mvitals[monsndx(mtmp->data)].mvflags & G_GENOD) { 1258 | if (cansee(mtmp->mx, mtmp->my)) 1259 | pline("Unfortunately %s is still genocided...", 1260 | mon_nam(mtmp)); 1261 | } else 1262 | return; 1263 | } 1264 | mtmp->mhp = 0; 1265 | } 1266 | 1267 | void 1268 | mondead(mtmp) 1269 | register struct monst *mtmp; 1270 | { 1271 | struct permonst *mptr; 1272 | int tmp; 1273 | 1274 | if(mtmp->isgd) { 1275 | /* if we're going to abort the death, it *must* be before 1276 | * the m_detach or there will be relmon problems later */ 1277 | if(!grddead(mtmp)) return; 1278 | } 1279 | lifesaved_monster(mtmp); 1280 | if (mtmp->mhp > 0) return; 1281 | 1282 | #ifdef STEED 1283 | /* Player is thrown from his steed when it dies */ 1284 | if (mtmp == u.usteed) 1285 | dismount_steed(DISMOUNT_GENERIC); 1286 | #endif 1287 | 1288 | mptr = mtmp->data; /* save this for m_detach() */ 1289 | /* restore chameleon, lycanthropes to true form at death */ 1290 | if (mtmp->cham) 1291 | set_mon_data(mtmp, &mons[cham_to_pm[mtmp->cham]], -1); 1292 | else if (mtmp->data == &mons[PM_WEREJACKAL]) 1293 | set_mon_data(mtmp, &mons[PM_HUMAN_WEREJACKAL], -1); 1294 | else if (mtmp->data == &mons[PM_WEREWOLF]) 1295 | set_mon_data(mtmp, &mons[PM_HUMAN_WEREWOLF], -1); 1296 | else if (mtmp->data == &mons[PM_WERERAT]) 1297 | set_mon_data(mtmp, &mons[PM_HUMAN_WERERAT], -1); 1298 | 1299 | /* if MAXMONNO monsters of a given type have died, and it 1300 | * can be done, extinguish that monster. 1301 | * 1302 | * mvitals[].died does double duty as total number of dead monsters 1303 | * and as experience factor for the player killing more monsters. 1304 | * this means that a dragon dying by other means reduces the 1305 | * experience the player gets for killing a dragon directly; this 1306 | * is probably not too bad, since the player likely finagled the 1307 | * first dead dragon via ring of conflict or pets, and extinguishing 1308 | * based on only player kills probably opens more avenues of abuse 1309 | * for rings of conflict and such. 1310 | */ 1311 | tmp = monsndx(mtmp->data); 1312 | if (mvitals[tmp].died < 255) mvitals[tmp].died++; 1313 | #ifdef MAIL 1314 | /* if the mail daemon dies, no more mail delivery. -3. */ 1315 | if (tmp == PM_MAIL_DAEMON) mvitals[tmp].mvflags |= G_GENOD; 1316 | #endif 1317 | 1318 | #ifdef KOPS 1319 | if (mtmp->data->mlet == S_KOP) { 1320 | /* Dead Kops may come back. */ 1321 | switch(rnd(5)) { 1322 | case 1: /* returns near the stairs */ 1323 | (void) makemon(mtmp->data,xdnstair,ydnstair,NO_MM_FLAGS); 1324 | break; 1325 | case 2: /* randomly */ 1326 | (void) makemon(mtmp->data,0,0,NO_MM_FLAGS); 1327 | break; 1328 | default: 1329 | break; 1330 | } 1331 | } 1332 | #endif 1333 | if(mtmp->iswiz) wizdead(); 1334 | if(mtmp->data->msound == MS_NEMESIS) nemdead(); 1335 | if(glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) 1336 | unmap_object(mtmp->mx, mtmp->my); 1337 | m_detach(mtmp, mptr); 1338 | } 1339 | 1340 | STATIC_OVL boolean 1341 | corpse_chance(mon) 1342 | struct monst *mon; 1343 | { 1344 | struct permonst *mdat = mon->data; 1345 | int i, tmp; 1346 | 1347 | 1348 | if (mdat == &mons[PM_VLAD_THE_IMPALER] || mdat->mlet == S_LICH) { 1349 | if (cansee(mon->mx, mon->my)) 1350 | pline("%s body crumbles into dust.", 1351 | s_suffix(Monnam(mon))); 1352 | return FALSE; 1353 | } 1354 | 1355 | /* Gas spores always explode upon death */ 1356 | for(i = 0; i < NATTK; i++) { 1357 | if (mdat->mattk[i].aatyp == AT_BOOM) { 1358 | if (mdat->mattk[i].damn) 1359 | tmp = d((int)mdat->mattk[i].damn, 1360 | (int)mdat->mattk[i].damd); 1361 | else if(mdat->mattk[i].damd) 1362 | tmp = d((int)mdat->mlevel+1, (int)mdat->mattk[i].damd); 1363 | else tmp = 0; 1364 | Sprintf(killer_buf, "%s explosion", s_suffix(mdat->mname)); 1365 | killer = killer_buf; 1366 | killer_format = KILLED_BY_AN; 1367 | explode(mon->mx, mon->my, -1, tmp, MON_EXPLODE); 1368 | return (FALSE); 1369 | } 1370 | } 1371 | 1372 | /* must duplicate this below check in xkilled() since it results in 1373 | * creating no objects as well as no corpse 1374 | */ 1375 | if ( 1376 | #ifdef REINCARNATION 1377 | Is_rogue_level(&u.uz) || 1378 | #endif 1379 | (level.flags.graveyard && is_undead(mdat) && rn2(3))) 1380 | return FALSE; 1381 | 1382 | if (bigmonst(mdat) || mdat == &mons[PM_LIZARD] 1383 | || is_golem(mdat) 1384 | || is_mplayer(mdat) 1385 | || is_rider(mdat)) 1386 | return TRUE; 1387 | return (boolean) (!rn2((int) 1388 | (2 + ((int)(mdat->geno & G_FREQ)<2) + verysmall(mdat)))); 1389 | } 1390 | 1391 | /* drop (perhaps) a cadaver and remove monster */ 1392 | void 1393 | mondied(mdef) 1394 | register struct monst *mdef; 1395 | { 1396 | mondead(mdef); 1397 | if (mdef->mhp > 0) return; /* lifesaved */ 1398 | 1399 | if (corpse_chance(mdef)) 1400 | (void) make_corpse(mdef); 1401 | } 1402 | 1403 | /* monster disappears, not dies */ 1404 | void 1405 | mongone(mdef) 1406 | register struct monst *mdef; 1407 | { 1408 | #ifdef STEED 1409 | /* Player is thrown from his steed when it disappears */ 1410 | if (mdef == u.usteed) 1411 | dismount_steed(DISMOUNT_GENERIC); 1412 | #endif 1413 | 1414 | discard_minvent(mdef); /* release monster's inventory */ 1415 | mdef->mgold = 0L; 1416 | m_detach(mdef, mdef->data); 1417 | } 1418 | 1419 | /* drop a statue or rock and remove monster */ 1420 | void 1421 | monstone(mdef) 1422 | register struct monst *mdef; 1423 | { 1424 | struct obj *otmp, *obj; 1425 | xchar x = mdef->mx, y = mdef->my; 1426 | 1427 | /* we have to make the statue before calling mondead, to be able to 1428 | * put inventory in it, and we have to check for lifesaving before 1429 | * making the statue.... 1430 | */ 1431 | lifesaved_monster(mdef); 1432 | if (mdef->mhp > 0) return; 1433 | 1434 | mdef->mtrapped = 0; /* (see m_detach) */ 1435 | 1436 | if ((int)mdef->data->msize > MZ_TINY || 1437 | !rn2(2 + ((int) (mdef->data->geno & G_FREQ) > 2))) { 1438 | otmp = mkcorpstat(STATUE, KEEPTRAITS(mdef) ? mdef : 0, 1439 | mdef->data, x, y, FALSE); 1440 | if (mdef->mnamelth) otmp = oname(otmp, NAME(mdef)); 1441 | /* some objects may end up outside the statue */ 1442 | while ((obj = mdef->minvent) != 0) { 1443 | obj_extract_self(obj); 1444 | obj->owornmask = 0L; 1445 | if (obj->otyp == BOULDER || 1446 | #if 0 /* monsters don't carry statues */ 1447 | (obj->otyp == STATUE && mons[obj->corpsenm].msize >= mdef->data->msize) || 1448 | #endif 1449 | obj_resists(obj, 0, 0)) { 1450 | if (flooreffects(obj, x, y, "fall")) continue; 1451 | place_object(obj, x, y); 1452 | } else { 1453 | if (obj->lamplit) end_burn(obj, TRUE); 1454 | add_to_container(otmp, obj); 1455 | } 1456 | } 1457 | if (mdef->mgold) { 1458 | struct obj *au; 1459 | au = mksobj(GOLD_PIECE, FALSE, FALSE); 1460 | au->quan = mdef->mgold; 1461 | au->owt = weight(au); 1462 | add_to_container(otmp, au); 1463 | mdef->mgold = 0; 1464 | } 1465 | /* Archeologists should not break unique statues */ 1466 | if (mdef->data->geno & G_UNIQ) 1467 | otmp->spe = 1; 1468 | otmp->owt = weight(otmp); 1469 | } else 1470 | otmp = mksobj_at(ROCK, x, y, TRUE); 1471 | 1472 | stackobj(otmp); 1473 | /* mondead() already does this, but we must do it before the newsym */ 1474 | if(glyph_is_invisible(levl[x][y].glyph)) 1475 | unmap_object(x, y); 1476 | if (cansee(x, y)) newsym(x,y); 1477 | mondead(mdef); 1478 | } 1479 | 1480 | /* another monster has killed the monster mdef */ 1481 | void 1482 | monkilled(mdef, fltxt, how) 1483 | register struct monst *mdef; 1484 | const char *fltxt; 1485 | int how; 1486 | { 1487 | boolean be_sad = FALSE; /* true if unseen pet is killed */ 1488 | 1489 | if ((mdef->wormno ? worm_known(mdef) : cansee(mdef->mx, mdef->my)) 1490 | && fltxt) 1491 | pline("%s is %s%s%s!", Monnam(mdef), 1492 | nonliving(mdef->data) ? "destroyed" : "killed", 1493 | *fltxt ? " by the " : "", 1494 | fltxt 1495 | ); 1496 | else 1497 | be_sad = (mdef->mtame != 0); 1498 | 1499 | /* no corpses if digested or disintegrated */ 1500 | if(how == AD_DGST || how == -AD_RBRE) 1501 | mondead(mdef); 1502 | else 1503 | mondied(mdef); 1504 | 1505 | if (be_sad && mdef->mhp <= 0) 1506 | You("have a sad feeling for a moment, then it passes."); 1507 | } 1508 | 1509 | void 1510 | unstuck(mtmp) 1511 | register struct monst *mtmp; 1512 | { 1513 | if(u.ustuck == mtmp) { 1514 | if(u.uswallow){ 1515 | u.ux = mtmp->mx; 1516 | u.uy = mtmp->my; 1517 | u.uswallow = 0; 1518 | u.uswldtim = 0; 1519 | if (Punished) placebc(); 1520 | vision_full_recalc = 1; 1521 | docrt(); 1522 | } 1523 | u.ustuck = 0; 1524 | } 1525 | } 1526 | 1527 | void 1528 | killed(mtmp) 1529 | register struct monst *mtmp; 1530 | { 1531 | xkilled(mtmp, 1); 1532 | } 1533 | 1534 | /* the player has killed the monster mtmp */ 1535 | void 1536 | xkilled(mtmp, dest) 1537 | register struct monst *mtmp; 1538 | /* 1539 | * Dest=1, normal; dest=0, don't print message; dest=2, don't drop corpse 1540 | * either; dest=3, message but no corpse 1541 | */ 1542 | int dest; 1543 | { 1544 | register int tmp, x = mtmp->mx, y = mtmp->my; 1545 | register struct permonst *mdat; 1546 | int mndx; 1547 | register struct obj *otmp; 1548 | register struct trap *t; 1549 | boolean redisp = FALSE; 1550 | boolean wasinside = u.uswallow && (u.ustuck == mtmp); 1551 | 1552 | 1553 | /* KMH, conduct */ 1554 | u.uconduct.killer++; 1555 | 1556 | if (dest & 1) { 1557 | if(!wasinside && !canspotmon(mtmp)) 1558 | You("destroy it!"); 1559 | else { 1560 | You("destroy %s!", 1561 | mtmp->mtame 1562 | ? x_monnam(mtmp, ARTICLE_THE, "poor", 1563 | mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE) 1564 | : mon_nam(mtmp)); 1565 | } 1566 | } 1567 | 1568 | if (mtmp->mtrapped && 1569 | ((t = t_at(x, y)) && (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) && 1570 | sobj_at(BOULDER, x, y)) 1571 | dest ^= 2; /* 1572 | * Prevent corpses/treasure being created "on top" 1573 | * of the boulder that is about to fall in. This is 1574 | * out of order, but cannot be helped unless this 1575 | * whole routine is rearranged. 1576 | */ 1577 | 1578 | /* your pet knows who just killed it...watch out */ 1579 | if (mtmp->mtame && !mtmp->isminion) EDOG(mtmp)->killed_by_u = 1; 1580 | 1581 | /* dispose of monster and make cadaver */ 1582 | if(stoned) monstone(mtmp); 1583 | else mondead(mtmp); 1584 | 1585 | if (mtmp->mhp > 0) { /* monster lifesaved */ 1586 | /* Cannot put the non-visible lifesaving message in 1587 | * lifesaved_monster() since the message appears only when you 1588 | * kill it (as opposed to visible lifesaving which always 1589 | * appears). 1590 | */ 1591 | stoned = FALSE; 1592 | if (!cansee(x,y)) pline("Maybe not..."); 1593 | return; 1594 | } 1595 | 1596 | mdat = mtmp->data; /* note: mondead can change mtmp->data */ 1597 | mndx = monsndx(mdat); 1598 | 1599 | if (stoned) { 1600 | stoned = FALSE; 1601 | goto cleanup; 1602 | } 1603 | 1604 | if((dest & 2) 1605 | #ifdef REINCARNATION 1606 | || Is_rogue_level(&u.uz) 1607 | #endif 1608 | || (level.flags.graveyard && is_undead(mdat) && rn2(3))) 1609 | goto cleanup; 1610 | 1611 | #ifdef MAIL 1612 | if(mdat == &mons[PM_MAIL_DAEMON]) { 1613 | stackobj(mksobj_at(SCR_MAIL, x, y, FALSE)); 1614 | redisp = TRUE; 1615 | } 1616 | #endif 1617 | if(!accessible(x, y) && !is_pool(x, y)) { 1618 | /* might be mimic in wall or corpse in lava */ 1619 | redisp = TRUE; 1620 | if(wasinside) spoteffects(TRUE); 1621 | } else if(x != u.ux || y != u.uy) { 1622 | /* might be here after swallowed */ 1623 | if (!rn2(6) && !(mvitals[mndx].mvflags & G_NOCORPSE) 1624 | #ifdef KOPS 1625 | && mdat->mlet != S_KOP 1626 | #endif 1627 | ) { 1628 | int typ; 1629 | 1630 | otmp = mkobj_at(RANDOM_CLASS, x, y, TRUE); 1631 | /* Don't create large objects from small monsters */ 1632 | typ = otmp->otyp; 1633 | if (mdat->msize < MZ_HUMAN && typ != FOOD_RATION 1634 | && typ != LEASH 1635 | && typ != FIGURINE 1636 | && (otmp->owt > 3 || 1637 | objects[typ].oc_big /*oc_bimanual/oc_bulky*/ || 1638 | is_spear(otmp) || is_pole(otmp) || 1639 | typ == MORNING_STAR)) { 1640 | delobj(otmp); 1641 | } else redisp = TRUE; 1642 | } 1643 | /* Whether or not it always makes a corpse is, in theory, 1644 | * different from whether or not the corpse is "special"; 1645 | * if we want both, we have to specify it explicitly. 1646 | */ 1647 | if (corpse_chance(mtmp)) 1648 | (void) make_corpse(mtmp); 1649 | } 1650 | if(redisp) newsym(x,y); 1651 | cleanup: 1652 | /* punish bad behaviour */ 1653 | if(is_human(mdat) && (!always_hostile(mdat) && mtmp->malign <= 0) && 1654 | (mndx < PM_ARCHEOLOGIST || mndx > PM_WIZARD) && 1655 | u.ualign.type != A_CHAOTIC) { 1656 | HTelepat &= ~INTRINSIC; 1657 | change_luck(-2); 1658 | You("murderer!"); 1659 | if (Blind && !Blind_telepat) 1660 | see_monsters(); /* Can't sense monsters any more. */ 1661 | } 1662 | if((mtmp->mpeaceful && !rn2(2)) || mtmp->mtame) change_luck(-1); 1663 | if (is_unicorn(mdat) && 1664 | sgn(u.ualign.type) == sgn(mdat->maligntyp)) { 1665 | change_luck(-5); 1666 | You_feel("guilty..."); 1667 | } 1668 | 1669 | /* give experience points */ 1670 | tmp = experience(mtmp, (int)mvitals[mndx].died + 1); 1671 | more_experienced(tmp, 0); 1672 | newexplevel(); /* will decide if you go up */ 1673 | 1674 | /* adjust alignment points */ 1675 | if (mdat->msound == MS_LEADER) { /* REAL BAD! */ 1676 | adjalign(-(u.ualign.record+(int)ALIGNLIM/2)); 1677 | pline("That was %sa bad idea...", 1678 | u.uevent.qcompleted ? "probably " : ""); 1679 | } else if (mdat->msound == MS_NEMESIS) /* Real good! */ 1680 | adjalign((int)(ALIGNLIM/4)); 1681 | else if (mdat->msound == MS_GUARDIAN) { /* Bad */ 1682 | adjalign(-(int)(ALIGNLIM/8)); 1683 | if (!Hallucination) pline("That was probably a bad idea..."); 1684 | else pline("Whoopsie-daisy!"); 1685 | }else if (mtmp->ispriest) { 1686 | adjalign((p_coaligned(mtmp)) ? -2 : 2); 1687 | /* cancel divine protection for killing your priest */ 1688 | if (p_coaligned(mtmp)) u.ublessed = 0; 1689 | if (mdat->maligntyp == A_NONE) 1690 | adjalign((int)(ALIGNLIM / 4)); /* BIG bonus */ 1691 | } else if (mtmp->mtame) { 1692 | adjalign(-15); /* bad!! */ 1693 | /* your god is mighty displeased... */ 1694 | if (!Hallucination) You_hear("the rumble of distant thunder..."); 1695 | else You_hear("the studio audience applaud!"); 1696 | } else if (mtmp->mpeaceful) 1697 | adjalign(-5); 1698 | 1699 | /* malign was already adjusted for u.ualign.type and randomization */ 1700 | adjalign(mtmp->malign); 1701 | } 1702 | 1703 | /* changes the monster into a stone monster of the same type */ 1704 | /* this should only be called when poly_when_stoned() is true */ 1705 | void 1706 | mon_to_stone(mtmp) 1707 | register struct monst *mtmp; 1708 | { 1709 | if(mtmp->data->mlet == S_GOLEM) { 1710 | /* it's a golem, and not a stone golem */ 1711 | if(canseemon(mtmp)) 1712 | pline("%s solidifies...", Monnam(mtmp)); 1713 | if (newcham(mtmp, &mons[PM_STONE_GOLEM])) { 1714 | if(canseemon(mtmp)) 1715 | pline("Now it's %s.", an(mtmp->data->mname)); 1716 | } else { 1717 | if(canseemon(mtmp)) 1718 | pline("... and returns to normal."); 1719 | } 1720 | } else 1721 | impossible("Can't polystone %s!", a_monnam(mtmp)); 1722 | } 1723 | 1724 | void 1725 | mnexto(mtmp) /* Make monster mtmp next to you (if possible) */ 1726 | struct monst *mtmp; 1727 | { 1728 | coord mm; 1729 | 1730 | #ifdef STEED 1731 | if (mtmp == u.usteed) { 1732 | /* Keep your steed in sync with you instead */ 1733 | mtmp->mx = u.ux; 1734 | mtmp->my = u.uy; 1735 | return; 1736 | } 1737 | #endif 1738 | 1739 | if(!enexto(&mm, u.ux, u.uy, mtmp->data)) return; 1740 | rloc_to(mtmp, mm.x, mm.y); 1741 | return; 1742 | } 1743 | 1744 | /* mnearto() 1745 | * Put monster near (or at) location if possible. 1746 | * Returns: 1747 | * 1 - if a monster was moved from x, y to put mtmp at x, y. 1748 | * 0 - in most cases. 1749 | */ 1750 | boolean 1751 | mnearto(mtmp,x,y,move_other) 1752 | register struct monst *mtmp; 1753 | xchar x, y; 1754 | boolean move_other; /* make sure mtmp gets to x, y! so move m_at(x, y) */ 1755 | { 1756 | struct monst *othermon = (struct monst *)0; 1757 | xchar newx, newy; 1758 | coord mm; 1759 | 1760 | if ((mtmp->mx == x) && (mtmp->my == y)) return(FALSE); 1761 | 1762 | if (move_other && (othermon = m_at(x, y))) { 1763 | if (othermon->wormno) 1764 | remove_worm(othermon); 1765 | else 1766 | remove_monster(x, y); 1767 | } 1768 | 1769 | newx = x; 1770 | newy = y; 1771 | 1772 | if (!goodpos(newx, newy, mtmp)) { 1773 | /* actually we have real problems if enexto ever fails. 1774 | * migrating_mons that need to be placed will cause 1775 | * no end of trouble. 1776 | */ 1777 | if (!enexto(&mm, newx, newy, mtmp->data)) return(FALSE); 1778 | newx = mm.x; newy = mm.y; 1779 | } 1780 | 1781 | rloc_to(mtmp, newx, newy); 1782 | 1783 | if (move_other && othermon) { 1784 | othermon->mx = othermon->my = 0; 1785 | (void) mnearto(othermon, x, y, FALSE); 1786 | if ((othermon->mx != x) || (othermon->my != y)) 1787 | return(TRUE); 1788 | } 1789 | 1790 | return(FALSE); 1791 | } 1792 | 1793 | 1794 | static const char *poiseff[] = { 1795 | 1796 | " feel weaker", "r brain is on fire", 1797 | "r judgement is impaired", "r muscles won't obey you", 1798 | " feel very sick", " break out in hives" 1799 | }; 1800 | 1801 | void 1802 | poisontell(typ) 1803 | 1804 | int typ; 1805 | { 1806 | pline("You%s.", poiseff[typ]); 1807 | } 1808 | 1809 | void 1810 | poisoned(string, typ, pname, fatal) 1811 | register const char *string, *pname; 1812 | register int typ, fatal; 1813 | { 1814 | register int i, plural; 1815 | boolean thrown_weapon = !strncmp(string, "poison", 6); 1816 | /* admittedly a kludge... */ 1817 | 1818 | if(strcmp(string, "blast") && !thrown_weapon) { 1819 | /* 'blast' has already given a 'poison gas' message */ 1820 | /* so have "poison arrow", "poison dart", etc... */ 1821 | plural = (string[strlen(string) - 1] == 's')? 1 : 0; 1822 | /* avoid "The" Orcus's sting was poisoned... */ 1823 | pline("%s%s %s poisoned!", isupper(*string) ? "" : "The ", 1824 | string, plural ? "were" : "was"); 1825 | } 1826 | 1827 | if(Poison_resistance) { 1828 | if(!strcmp(string, "blast")) shieldeff(u.ux, u.uy); 1829 | pline_The("poison doesn't seem to affect you."); 1830 | return; 1831 | } 1832 | i = rn2(fatal + 20*thrown_weapon); 1833 | if(i == 0 && typ != A_CHA) { 1834 | u.uhp = -1; 1835 | pline_The("poison was deadly..."); 1836 | } else if(i <= 5) { 1837 | /* Check that a stat change was made */ 1838 | if (adjattrib(typ, thrown_weapon ? -1 : -rn1(3,3), 1)) 1839 | pline("You%s!", poiseff[typ]); 1840 | } else { 1841 | i = thrown_weapon ? rnd(6) : rn1(10,6); 1842 | if(Half_physical_damage) i = (i+1) / 2; 1843 | losehp(i, pname, KILLED_BY_AN); 1844 | } 1845 | if(u.uhp < 1) { 1846 | killer_format = KILLED_BY_AN; 1847 | killer = pname; 1848 | /* "Poisoned by a poisoned ___" is redundant */ 1849 | done(thrown_weapon ? DIED : POISONING); 1850 | } 1851 | (void) encumber_msg(); 1852 | } 1853 | 1854 | /* monster responds to player action; not the same as a passive attack */ 1855 | /* assumes reason for response has been tested, and response _must_ be made */ 1856 | void 1857 | m_respond(mtmp) 1858 | register struct monst *mtmp; 1859 | { 1860 | if(mtmp->data->msound == MS_SHRIEK) { 1861 | if(flags.soundok) { 1862 | pline("%s shrieks.", Monnam(mtmp)); 1863 | stop_occupation(); 1864 | } 1865 | if (!rn2(10)) { 1866 | if (!rn2(13)) 1867 | (void) makemon(&mons[PM_PURPLE_WORM], 0, 0, NO_MM_FLAGS); 1868 | else 1869 | (void) makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS); 1870 | 1871 | } 1872 | aggravate(); 1873 | } 1874 | if(mtmp->data == &mons[PM_MEDUSA] && !mtmp->mcan) { 1875 | register int i; 1876 | for(i = 0; i < NATTK; i++) 1877 | if(mtmp->data->mattk[i].aatyp == AT_GAZE) { 1878 | (void) gazemu(mtmp, &mtmp->data->mattk[i]); 1879 | break; 1880 | } 1881 | } 1882 | } 1883 | 1884 | #endif /* OVLB */ 1885 | #ifdef OVL2 1886 | 1887 | void 1888 | setmangry(mtmp) 1889 | register struct monst *mtmp; 1890 | { 1891 | mtmp->mstrategy &= ~STRAT_WAITMASK; 1892 | if(!mtmp->mpeaceful) return; 1893 | if(mtmp->mtame) return; 1894 | mtmp->mpeaceful = 0; 1895 | if(mtmp->ispriest) { 1896 | if(p_coaligned(mtmp)) adjalign(-5); /* very bad */ 1897 | else adjalign(2); 1898 | } else 1899 | adjalign(-1); /* attacking peaceful monsters is bad */ 1900 | if (couldsee(mtmp->mx, mtmp->my)) { 1901 | if (humanoid(mtmp->data) || mtmp->isshk || mtmp->isgd) 1902 | pline("%s gets angry!", Monnam(mtmp)); 1903 | else if (flags.verbose && flags.soundok) growl(mtmp); 1904 | } 1905 | 1906 | /* attacking your own quest leader will anger his or her guardians */ 1907 | if (!flags.mon_moving && /* should always be the case here */ 1908 | mtmp->data == &mons[quest_info(MS_LEADER)]) { 1909 | struct monst *mon; 1910 | struct permonst *q_guardian = &mons[quest_info(MS_GUARDIAN)]; 1911 | int got_mad = 0; 1912 | 1913 | /* guardians will sense this attack even if they can't see it */ 1914 | for (mon = fmon; mon; mon = mon->nmon) 1915 | if (!DEADMONSTER(mon) && mon->data == q_guardian && mon->mpeaceful) { 1916 | mon->mpeaceful = 0; 1917 | if (canseemon(mon)) ++got_mad; 1918 | } 1919 | if (got_mad && !Hallucination) 1920 | pline_The("%s appear%s to be angry too...", 1921 | got_mad == 1 ? q_guardian->mname : 1922 | makeplural(q_guardian->mname), 1923 | got_mad == 1 ? "s" : ""); 1924 | } 1925 | } 1926 | 1927 | void 1928 | wakeup(mtmp) 1929 | register struct monst *mtmp; 1930 | { 1931 | mtmp->msleeping = 0; 1932 | mtmp->meating = 0; /* assume there's no salvagable food left */ 1933 | setmangry(mtmp); 1934 | if(mtmp->m_ap_type) seemimic(mtmp); 1935 | } 1936 | 1937 | /* Wake up nearby monsters. */ 1938 | void 1939 | wake_nearby() 1940 | { 1941 | register struct monst *mtmp; 1942 | 1943 | for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { 1944 | if (!DEADMONSTER(mtmp) && distu(mtmp->mx,mtmp->my) < u.ulevel*20) { 1945 | mtmp->msleeping = 0; 1946 | if (mtmp->mtame && !mtmp->isminion) 1947 | EDOG(mtmp)->whistletime = moves; 1948 | } 1949 | } 1950 | } 1951 | 1952 | /* Wake up monsters near some particular location. */ 1953 | void 1954 | wake_nearto(x, y, distance) 1955 | register int x, y, distance; 1956 | { 1957 | register struct monst *mtmp; 1958 | 1959 | for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { 1960 | if (!DEADMONSTER(mtmp) && mtmp->msleeping && (distance == 0 || 1961 | dist2(mtmp->mx, mtmp->my, x, y) < distance)) 1962 | mtmp->msleeping = 0; 1963 | } 1964 | } 1965 | 1966 | /* NOTE: we must check for mimicry before calling this routine */ 1967 | void 1968 | seemimic(mtmp) 1969 | register struct monst *mtmp; 1970 | { 1971 | /* 1972 | * Discovered mimics don't block light. 1973 | */ 1974 | if ((mtmp->m_ap_type == M_AP_FURNITURE && 1975 | (mtmp->mappearance==S_hcdoor || mtmp->mappearance==S_vcdoor))|| 1976 | (mtmp->m_ap_type == M_AP_OBJECT && mtmp->mappearance == BOULDER)) 1977 | unblock_point(mtmp->mx,mtmp->my); 1978 | 1979 | mtmp->m_ap_type = M_AP_NOTHING; 1980 | mtmp->mappearance = 0; 1981 | newsym(mtmp->mx,mtmp->my); 1982 | } 1983 | 1984 | /* force all chameleons to become normal */ 1985 | void 1986 | rescham() 1987 | { 1988 | register struct monst *mtmp; 1989 | int mcham; 1990 | 1991 | for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { 1992 | if (DEADMONSTER(mtmp)) continue; 1993 | mcham = (int) mtmp->cham; 1994 | if (mcham) { 1995 | mtmp->cham = CHAM_ORDINARY; 1996 | (void) newcham(mtmp, &mons[cham_to_pm[mcham]]); 1997 | } 1998 | if(is_were(mtmp->data) && mtmp->data->mlet != S_HUMAN) 1999 | new_were(mtmp); 2000 | if(mtmp->m_ap_type && cansee(mtmp->mx, mtmp->my)) { 2001 | seemimic(mtmp); 2002 | /* we pretend that the mimic doesn't */ 2003 | /* know that it has been unmasked. */ 2004 | mtmp->msleeping = 1; 2005 | } 2006 | } 2007 | } 2008 | 2009 | /* Let the chameleons change again -dgk */ 2010 | void 2011 | restartcham() 2012 | { 2013 | register struct monst *mtmp; 2014 | 2015 | for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { 2016 | if (DEADMONSTER(mtmp)) continue; 2017 | mtmp->cham = pm_to_cham(monsndx(mtmp->data)); 2018 | if (mtmp->data->mlet == S_MIMIC && mtmp->msleeping && 2019 | cansee(mtmp->mx, mtmp->my)) { 2020 | set_mimic_sym(mtmp); 2021 | newsym(mtmp->mx,mtmp->my); 2022 | } 2023 | } 2024 | } 2025 | 2026 | /* called when restoring a monster from a saved level; protection 2027 | against shape-changing might be different now than it was at the 2028 | time the level was saved. */ 2029 | void 2030 | restore_cham(mon) 2031 | struct monst *mon; 2032 | { 2033 | int mcham; 2034 | 2035 | if (Protection_from_shape_changers) { 2036 | mcham = (int) mon->cham; 2037 | if (mcham) { 2038 | mon->cham = CHAM_ORDINARY; 2039 | (void) newcham(mon, &mons[cham_to_pm[mcham]]); 2040 | } else if (is_were(mon->data) && !is_human(mon->data)) { 2041 | new_were(mon); 2042 | } 2043 | } else { 2044 | mon->cham = pm_to_cham(monsndx(mon->data)); 2045 | } 2046 | } 2047 | 2048 | /* unwatched hiders may hide again; if so, a 1 is returned. */ 2049 | STATIC_OVL boolean 2050 | restrap(mtmp) 2051 | register struct monst *mtmp; 2052 | { 2053 | if(mtmp->cham || mtmp->mcan || mtmp->m_ap_type || 2054 | cansee(mtmp->mx, mtmp->my) || rn2(3) || (mtmp == u.ustuck)) 2055 | return(FALSE); 2056 | 2057 | if(mtmp->data->mlet == S_MIMIC) { 2058 | set_mimic_sym(mtmp); 2059 | return(TRUE); 2060 | } else 2061 | if(levl[mtmp->mx][mtmp->my].typ == ROOM) { 2062 | mtmp->mundetected = 1; 2063 | return(TRUE); 2064 | } 2065 | 2066 | return(FALSE); 2067 | } 2068 | 2069 | short *animal_list = 0; /* list of PM values for animal monsters */ 2070 | int animal_list_count; 2071 | 2072 | void 2073 | mon_animal_list(construct) 2074 | boolean construct; 2075 | { 2076 | if (construct) { 2077 | short animal_temp[SPECIAL_PM]; 2078 | int i, n; 2079 | 2080 | /* if (animal_list) impossible("animal_list already exists"); */ 2081 | 2082 | for (n = 0, i = LOW_PM; i < SPECIAL_PM; i++) 2083 | if (is_animal(&mons[i])) animal_temp[n++] = i; 2084 | /* if (n == 0) animal_temp[n++] = NON_PM; */ 2085 | 2086 | animal_list = (short *)alloc(n * sizeof *animal_list); 2087 | (void) memcpy((genericptr_t)animal_list, 2088 | (genericptr_t)animal_temp, 2089 | n * sizeof *animal_list); 2090 | animal_list_count = n; 2091 | } else { /* release */ 2092 | if (animal_list) free((genericptr_t)animal_list), animal_list = 0; 2093 | animal_list_count = 0; 2094 | } 2095 | } 2096 | 2097 | STATIC_OVL int 2098 | pick_animal() 2099 | { 2100 | if (!animal_list) mon_animal_list(TRUE); 2101 | 2102 | return animal_list[rn2(animal_list_count)]; 2103 | } 2104 | 2105 | STATIC_OVL int 2106 | select_newcham_form(mon) 2107 | struct monst *mon; 2108 | { 2109 | int mndx = NON_PM; 2110 | 2111 | switch (mon->cham) { 2112 | case CHAM_SANDESTIN: 2113 | if (rn2(7)) mndx = pick_nasty(); 2114 | break; 2115 | case CHAM_DOPPELGANGER: 2116 | if (!rn2(7)) mndx = pick_nasty(); 2117 | else if (rn2(3)) mndx = rn1(PM_WIZARD - PM_ARCHEOLOGIST + 1, 2118 | PM_ARCHEOLOGIST); 2119 | break; 2120 | case CHAM_CHAMELEON: 2121 | if (!rn2(3)) mndx = pick_animal(); 2122 | break; 2123 | case CHAM_ORDINARY: 2124 | break; 2125 | } 2126 | if (mndx == NON_PM) mndx = rn1(SPECIAL_PM - LOW_PM, LOW_PM); 2127 | return mndx; 2128 | } 2129 | 2130 | /* make a chameleon look like a new monster; returns 1 if it actually changed */ 2131 | int 2132 | newcham(mtmp, mdat) 2133 | struct monst *mtmp; 2134 | struct permonst *mdat; 2135 | { 2136 | int mhp, hpn, hpd; 2137 | int mndx, tryct; 2138 | struct permonst *olddata = mtmp->data; 2139 | 2140 | /* mdat = 0 -> caller wants a random monster shape */ 2141 | tryct = 0; 2142 | if (mdat == 0) { 2143 | while (++tryct <= 100) { 2144 | mndx = select_newcham_form(mtmp); 2145 | mdat = &mons[mndx]; 2146 | if ((mvitals[mndx].mvflags & G_GENOD) != 0 || 2147 | is_placeholder(mdat)) continue; 2148 | /* polyok rules out all M2_PNAME and M2_WERE's; 2149 | select_newcham_form might deliberately pick a player 2150 | character type, so we can't arbitrarily rule out all 2151 | human forms any more */ 2152 | if (is_mplayer(mdat) || (!is_human(mdat) && polyok(mdat))) 2153 | break; 2154 | } 2155 | if (tryct > 100) return 0; /* Should never happen */ 2156 | } else if (mvitals[monsndx(mdat)].mvflags & G_GENOD) 2157 | return(0); /* passed in mdat is genocided */ 2158 | 2159 | if(is_male(mdat)) { 2160 | if(mtmp->female) mtmp->female = FALSE; 2161 | } else if (is_female(mdat)) { 2162 | if(!mtmp->female) mtmp->female = TRUE; 2163 | } else if (!is_neuter(mdat)) { 2164 | if(!rn2(10)) mtmp->female = !mtmp->female; 2165 | } 2166 | 2167 | if (In_endgame(&u.uz) && is_mplayer(olddata)) { 2168 | /* mplayers start out as "Foo the Bar", but some of the 2169 | * titles are inappropriate when polymorphed, particularly 2170 | * into the opposite sex. players don't use ranks when 2171 | * polymorphed, so dropping the rank for mplayers seems 2172 | * reasonable. 2173 | */ 2174 | char *p = index(NAME(mtmp), ' '); 2175 | if (p) { 2176 | *p = '\0'; 2177 | mtmp->mnamelth = p - NAME(mtmp) + 1; 2178 | } 2179 | } 2180 | 2181 | if(mdat == mtmp->data) return(0); /* still the same monster */ 2182 | 2183 | if(mtmp->wormno) { /* throw tail away */ 2184 | wormgone(mtmp); 2185 | place_monster(mtmp, mtmp->mx, mtmp->my); 2186 | } 2187 | 2188 | hpn = mtmp->mhp; 2189 | hpd = (mtmp->m_lev < 50) ? ((int)mtmp->m_lev)*8 : mdat->mlevel; 2190 | if(!hpd) hpd = 4; 2191 | 2192 | mtmp->m_lev = adj_lev(mdat); /* new monster level */ 2193 | 2194 | mhp = (mtmp->m_lev < 50) ? ((int)mtmp->m_lev)*8 : mdat->mlevel; 2195 | if(!mhp) mhp = 4; 2196 | 2197 | /* new hp: same fraction of max as before */ 2198 | #ifndef LINT 2199 | mtmp->mhp = (int)(((long)hpn*(long)mhp)/(long)hpd); 2200 | #endif 2201 | if(mtmp->mhp < 0) mtmp->mhp = hpn; /* overflow */ 2202 | /* Unlikely but not impossible; a 1HD creature with 1HP that changes into a 2203 | 0HD creature will require this statement */ 2204 | if (!mtmp->mhp) mtmp->mhp = 1; 2205 | 2206 | /* and the same for maximum hit points */ 2207 | hpn = mtmp->mhpmax; 2208 | #ifndef LINT 2209 | mtmp->mhpmax = (int)(((long)hpn*(long)mhp)/(long)hpd); 2210 | #endif 2211 | if(mtmp->mhpmax < 0) mtmp->mhpmax = hpn; /* overflow */ 2212 | if (!mtmp->mhpmax) mtmp->mhpmax = 1; 2213 | 2214 | /* take on the new form... */ 2215 | set_mon_data(mtmp, mdat, 0); 2216 | 2217 | if (emits_light(olddata) != emits_light(mtmp->data)) { 2218 | /* used to give light, now doesn't, or vice versa, 2219 | or light's range has changed */ 2220 | if (emits_light(olddata)) 2221 | del_light_source(LS_MONSTER, (genericptr_t)mtmp); 2222 | if (emits_light(mtmp->data)) 2223 | new_light_source(mtmp->mx, mtmp->my, emits_light(mtmp->data), 2224 | LS_MONSTER, (genericptr_t)mtmp); 2225 | } 2226 | mtmp->perminvis = pm_invisible(mdat); 2227 | mtmp->minvis = mtmp->invis_blkd ? 0 : mtmp->perminvis; 2228 | if (!(hides_under(mdat) && OBJ_AT(mtmp->mx, mtmp->my)) && 2229 | !(mdat->mlet == S_EEL && is_pool(mtmp->mx, mtmp->my))) 2230 | mtmp->mundetected = 0; 2231 | if (u.ustuck == mtmp) { 2232 | if(u.uswallow) { 2233 | if(!attacktype(mdat,AT_ENGL)) { 2234 | /* Does mdat care? */ 2235 | if (!noncorporeal(mdat) && !amorphous(mdat) && 2236 | !is_whirly(mdat) && 2237 | (mdat != &mons[PM_YELLOW_LIGHT])) { 2238 | You("break out of %s%s!", mon_nam(mtmp), 2239 | (is_animal(mdat)? 2240 | "'s stomach" : "")); 2241 | mtmp->mhp = 1; /* almost dead */ 2242 | } 2243 | expels(mtmp, olddata, FALSE); 2244 | } 2245 | } else if (!sticks(mdat) && !sticks(youmonst.data)) 2246 | unstuck(mtmp); 2247 | } 2248 | 2249 | #ifndef DCC30_BUG 2250 | if (mdat == &mons[PM_LONG_WORM] && (mtmp->wormno = get_wormno()) != 0) { 2251 | #else 2252 | /* DICE 3.0 doesn't like assigning and comparing mtmp->wormno in the 2253 | * same expression. 2254 | */ 2255 | if (mdat == &mons[PM_LONG_WORM] && 2256 | (mtmp->wormno = get_wormno(), mtmp->wormno != 0)) { 2257 | #endif 2258 | /* we can now create worms with tails - 11/91 */ 2259 | initworm(mtmp, rn2(5)); 2260 | if (count_wsegs(mtmp)) 2261 | place_worm_tail_randomly(mtmp, mtmp->mx, mtmp->my); 2262 | } 2263 | 2264 | newsym(mtmp->mx,mtmp->my); 2265 | 2266 | mon_break_armor(mtmp); 2267 | if (!(mtmp->misc_worn_check & W_ARMG)) 2268 | mselftouch(mtmp, "No longer petrify-resistant, ", 2269 | !flags.mon_moving); 2270 | possibly_unwield(mtmp); 2271 | m_dowear(mtmp, FALSE); 2272 | 2273 | /* This ought to re-test can_carry() on each item in the inventory 2274 | * rather than just checking ex-giants & boulders, but that'd be 2275 | * pretty expensive to perform. If implemented, then perhaps 2276 | * minvent should be sorted in order to drop heaviest items first. 2277 | */ 2278 | /* former giants can't continue carrying boulders */ 2279 | if (mtmp->minvent && !throws_rocks(mdat)) { 2280 | register struct obj *otmp, *otmp2; 2281 | 2282 | for (otmp = mtmp->minvent; otmp; otmp = otmp2) { 2283 | otmp2 = otmp->nobj; 2284 | if (otmp->otyp == BOULDER) { 2285 | obj_extract_self(otmp); 2286 | /* probably ought to give some "drop" message here */ 2287 | if (flooreffects(otmp, mtmp->mx, mtmp->my, "")) continue; 2288 | place_object(otmp, mtmp->mx, mtmp->my); 2289 | } 2290 | } 2291 | } 2292 | 2293 | return(1); 2294 | } 2295 | 2296 | /* sometimes an egg will be special */ 2297 | #define BREEDER_EGG (!rn2(77)) 2298 | 2299 | /* 2300 | * Determine if the given monster number can be hatched from an egg. 2301 | * Return the monster number to use as the egg's corpsenm. Return 2302 | * NON_PM if the given monster can't be hatched. 2303 | */ 2304 | int 2305 | can_be_hatched(mnum) 2306 | int mnum; 2307 | { 2308 | mnum = little_to_big(mnum); 2309 | /* 2310 | * Queen bees lay killer bee eggs (usually), but killer bees don't 2311 | * grow into queen bees. Ditto for [winged-]gargoyles. 2312 | */ 2313 | if (mnum == PM_KILLER_BEE || mnum == PM_GARGOYLE || 2314 | (lays_eggs(&mons[mnum]) && (BREEDER_EGG || 2315 | (mnum != PM_QUEEN_BEE && mnum != PM_WINGED_GARGOYLE)))) 2316 | return mnum; 2317 | return NON_PM; 2318 | } 2319 | 2320 | /* type of egg laid by #sit; usually matches parent */ 2321 | int 2322 | egg_type_from_parent(mnum, force_ordinary) 2323 | int mnum; /* parent monster; caller must handle lays_eggs() check */ 2324 | boolean force_ordinary; 2325 | { 2326 | if (force_ordinary || !BREEDER_EGG) { 2327 | if (mnum == PM_QUEEN_BEE) mnum = PM_KILLER_BEE; 2328 | else if (mnum == PM_WINGED_GARGOYLE) mnum = PM_GARGOYLE; 2329 | } 2330 | return mnum; 2331 | } 2332 | 2333 | /* decide whether an egg of the indicated monster type is viable; */ 2334 | /* also used to determine whether an egg or tin can be created... */ 2335 | boolean 2336 | dead_species(m_idx, egg) 2337 | int m_idx; 2338 | boolean egg; 2339 | { 2340 | /* 2341 | * For monsters with both baby and adult forms, genociding either 2342 | * form kills all eggs of that monster. Monsters with more than 2343 | * two forms (small->large->giant mimics) are more or less ignored; 2344 | * fortunately, none of them have eggs. Species extinction due to 2345 | * overpopulation does not kill eggs. 2346 | */ 2347 | return (boolean) 2348 | (m_idx >= LOW_PM && 2349 | ((mvitals[m_idx].mvflags & G_GENOD) != 0 || 2350 | (egg && 2351 | (mvitals[big_to_little(m_idx)].mvflags & G_GENOD) != 0))); 2352 | } 2353 | 2354 | /* kill off any eggs of genocided monsters */ 2355 | STATIC_OVL void 2356 | kill_eggs(obj_list) 2357 | struct obj *obj_list; 2358 | { 2359 | struct obj *otmp; 2360 | 2361 | for (otmp = obj_list; otmp; otmp = otmp->nobj) 2362 | if (otmp->otyp == EGG) { 2363 | if (dead_species(otmp->corpsenm, TRUE)) { 2364 | /* 2365 | * It seems we could also just catch this when 2366 | * it attempted to hatch, so we wouldn't have to 2367 | * search all of the objlists.. or stop all 2368 | * hatch timers based on a corpsenm. 2369 | */ 2370 | kill_egg(otmp); 2371 | } 2372 | #if 0 /* not used */ 2373 | } else if (otmp->otyp == TIN) { 2374 | if (dead_species(otmp->corpsenm, FALSE)) 2375 | otmp->corpsenm = NON_PM; /* empty tin */ 2376 | } else if (otmp->otyp == CORPSE) { 2377 | if (dead_species(otmp->corpsenm, FALSE)) 2378 | ; /* not yet implemented... */ 2379 | #endif 2380 | } else if (Has_contents(otmp)) { 2381 | kill_eggs(otmp->cobj); 2382 | } 2383 | } 2384 | 2385 | /* kill all members of genocided species */ 2386 | void 2387 | kill_genocided_monsters() 2388 | { 2389 | struct monst *mtmp, *mtmp2; 2390 | boolean kill_cham[CHAM_MAX_INDX+1]; 2391 | int mndx; 2392 | 2393 | kill_cham[CHAM_ORDINARY] = FALSE; /* (this is mndx==0) */ 2394 | for (mndx = 1; mndx <= CHAM_MAX_INDX; mndx++) 2395 | kill_cham[mndx] = (mvitals[cham_to_pm[mndx]].mvflags & G_GENOD) != 0; 2396 | /* 2397 | * Called during genocide, and again upon level change. The latter 2398 | * catches up with any migrating monsters as they finally arrive at 2399 | * their intended destinations, so possessions get deposited there. 2400 | * 2401 | * Chameleon handling: 2402 | * 1) if chameleons have been genocided, destroy them 2403 | * regardless of current form; 2404 | * 2) otherwise, force every chameleon which is imitating 2405 | * any genocided species to take on a new form. 2406 | */ 2407 | for (mtmp = fmon; mtmp; mtmp = mtmp2) { 2408 | mtmp2 = mtmp->nmon; 2409 | if (DEADMONSTER(mtmp)) continue; 2410 | mndx = monsndx(mtmp->data); 2411 | if ((mvitals[mndx].mvflags & G_GENOD) || kill_cham[mtmp->cham]) { 2412 | if (mtmp->cham && !kill_cham[mtmp->cham]) 2413 | (void) newcham(mtmp, (struct permonst *)0); 2414 | else 2415 | mondead(mtmp); 2416 | } 2417 | if (mtmp->minvent) kill_eggs(mtmp->minvent); 2418 | } 2419 | 2420 | kill_eggs(invent); 2421 | kill_eggs(fobj); 2422 | kill_eggs(level.buriedobjlist); 2423 | } 2424 | 2425 | #endif /* OVL2 */ 2426 | #ifdef OVLB 2427 | 2428 | void 2429 | golemeffects(mon, damtype, dam) 2430 | register struct monst *mon; 2431 | int damtype, dam; 2432 | { 2433 | int heal = 0, slow = 0; 2434 | 2435 | if (mon->data == &mons[PM_FLESH_GOLEM]) { 2436 | if (damtype == AD_ELEC) heal = dam / 6; 2437 | else if (damtype == AD_FIRE || damtype == AD_COLD) slow = 1; 2438 | } else if (mon->data == &mons[PM_IRON_GOLEM]) { 2439 | if (damtype == AD_ELEC) slow = 1; 2440 | else if (damtype == AD_FIRE) heal = dam; 2441 | } else { 2442 | return; 2443 | } 2444 | if (slow) { 2445 | if (mon->mspeed != MSLOW) { 2446 | unsigned int oldspeed = mon->mspeed; 2447 | 2448 | mon_adjust_speed(mon, -1); 2449 | if (mon->mspeed != oldspeed && cansee(mon->mx, mon->my)) 2450 | pline("%s seems to be moving slower.", Monnam(mon)); 2451 | } 2452 | } 2453 | if (heal) { 2454 | if (mon->mhp < mon->mhpmax) { 2455 | mon->mhp += dam; 2456 | if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; 2457 | if (cansee(mon->mx, mon->my)) 2458 | pline("%s seems healthier.", Monnam(mon)); 2459 | } 2460 | } 2461 | } 2462 | 2463 | boolean 2464 | angry_guards(silent) 2465 | register boolean silent; 2466 | { 2467 | register struct monst *mtmp; 2468 | register int ct = 0, nct = 0, sct = 0, slct = 0; 2469 | 2470 | for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { 2471 | if (DEADMONSTER(mtmp)) continue; 2472 | if((mtmp->data == &mons[PM_WATCHMAN] || 2473 | mtmp->data == &mons[PM_WATCH_CAPTAIN]) 2474 | && mtmp->mpeaceful) { 2475 | ct++; 2476 | if(cansee(mtmp->mx, mtmp->my) && mtmp->mcanmove) { 2477 | if (distu(mtmp->mx, mtmp->my) == 2) nct++; 2478 | else sct++; 2479 | } 2480 | if (mtmp->msleeping || mtmp->mfrozen) { 2481 | slct++; 2482 | mtmp->msleeping = mtmp->mfrozen = 0; 2483 | } 2484 | mtmp->mpeaceful = 0; 2485 | } 2486 | } 2487 | if(ct) { 2488 | if(!silent) { /* do we want pline msgs? */ 2489 | if(slct) pline_The("guard%s wake%s up!", 2490 | slct > 1 ? "s" : "", slct == 1 ? "s" : ""); 2491 | if(nct || sct) { 2492 | if(nct) pline_The("guard%s get%s angry!", 2493 | nct == 1 ? "" : "s", nct == 1 ? "s" : ""); 2494 | else if(!Blind) 2495 | You("see %sangry guard%s approaching!", 2496 | sct == 1 ? "an " : "", sct > 1 ? "s" : ""); 2497 | } else if(flags.soundok) 2498 | You_hear("the shrill sound of a guard's whistle."); 2499 | } 2500 | return(TRUE); 2501 | } 2502 | return(FALSE); 2503 | } 2504 | 2505 | void 2506 | pacify_guards() 2507 | { 2508 | register struct monst *mtmp; 2509 | 2510 | for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { 2511 | if (DEADMONSTER(mtmp)) continue; 2512 | if (mtmp->data == &mons[PM_WATCHMAN] || 2513 | mtmp->data == &mons[PM_WATCH_CAPTAIN]) 2514 | mtmp->mpeaceful = 1; 2515 | } 2516 | } 2517 | #endif /* OVLB */ 2518 | 2519 | /*mon.c*/