1/* SCCS Id: @(#)monmove.c 3.4 2002/04/06 */ 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 "mfndpos.h" 7#include "artifact.h" 8#include "epri.h" 9 10extern boolean notonhead; 11 12#ifdef OVL0 13 14STATIC_DCL int FDECL(disturb,(struct monst *)); 15STATIC_DCL void FDECL(distfleeck,(struct monst *,int *,int *,int *)); 16STATIC_DCL int FDECL(m_arrival, (struct monst *)); 17STATIC_DCL void FDECL(watch_on_duty,(struct monst *)); 18 19#endif /* OVL0 */ 20#ifdef OVLB 21 22boolean /* TRUE : mtmp died */ 23mb_trapped(mtmp) 24register struct monst *mtmp; 25{ 26 if (flags.verbose) { 27 if (cansee(mtmp->mx, mtmp->my)) 28 pline("KABOOM!! You see a door explode."); 29 else if (flags.soundok) 30 You_hear("a distant explosion."); 31 } 32 wake_nearto(mtmp->mx, mtmp->my, 7*7); 33 mtmp->mstun = 1; 34 mtmp->mhp -= rnd(15); 35 if(mtmp->mhp <= 0) { 36 mondied(mtmp); 37 if (mtmp->mhp > 0) /* lifesaved */ 38 return(FALSE); 39 else 40 return(TRUE); 41 } 42 return(FALSE); 43} 44 45#endif /* OVLB */ 46#ifdef OVL0 47 48STATIC_OVL void 49watch_on_duty(mtmp) 50register struct monst *mtmp; 51{ 52 int x, y; 53 54 if(mtmp->mpeaceful && in_town(u.ux+u.dx, u.uy+u.dy) && 55 mtmp->mcansee && m_canseeu(mtmp) && !rn2(3)) { 56 57 if(picking_lock(&x, &y) && IS_DOOR(levl[x][y].typ) && 58 (levl[x][y].doormask & D_LOCKED)) { 59 60 if(couldsee(mtmp->mx, mtmp->my)) { 61 62 pline("%s yells:", Amonnam(mtmp)); 63 if(levl[x][y].looted & D_WARNED) { 64 verbalize("Halt, thief! You're under arrest!"); 65 (void) angry_guards(!(flags.soundok)); 66 } else { 67 verbalize("Hey, stop picking that lock!"); 68 levl[x][y].looted |= D_WARNED; 69 } 70 stop_occupation(); 71 } 72 } else if (is_digging()) { 73 /* chewing, wand/spell of digging are checked elsewhere */ 74 watch_dig(mtmp, digging.pos.x, digging.pos.y, FALSE); 75 } 76 } 77} 78 79#endif /* OVL0 */ 80#ifdef OVL1 81 82int 83dochugw(mtmp) 84 register struct monst *mtmp; 85{ 86 register int x = mtmp->mx, y = mtmp->my; 87 boolean already_saw_mon = !occupation ? 0 : canspotmon(mtmp); 88 int rd = dochug(mtmp); 89#if 0 90 /* part of the original warning code which was replaced in 3.3.1 */ 91 int dd; 92 93 if(Warning && !rd && !mtmp->mpeaceful && 94 (dd = distu(mtmp->mx,mtmp->my)) < distu(x,y) && 95 dd < 100 && !canseemon(mtmp)) { 96 /* Note: this assumes we only want to warn against the monster to 97 * which the weapon does extra damage, as there is no "monster 98 * which the weapon warns against" field. 99 */ 100 if (spec_ability(uwep, SPFX_WARN) && spec_dbon(uwep, mtmp, 1)) 101 warnlevel = 100; 102 else if ((int) (mtmp->m_lev / 4) > warnlevel) 103 warnlevel = (mtmp->m_lev / 4); 104 } 105#endif /* 0 */ 106 107 /* a similar check is in monster_nearby() in hack.c */ 108 /* check whether hero notices monster and stops current activity */ 109 if (occupation && !rd && !Confusion && 110 (!mtmp->mpeaceful || Hallucination) && 111 /* it's close enough to be a threat */ 112 distu(mtmp->mx,mtmp->my) <= (BOLT_LIM+1)*(BOLT_LIM+1) && 113 /* and either couldn't see it before, or it was too far away */ 114 (!already_saw_mon || !couldsee(x,y) || 115 distu(x,y) > (BOLT_LIM+1)*(BOLT_LIM+1)) && 116 /* can see it now, or sense it and would normally see it */ 117 (canseemon(mtmp) || 118 (sensemon(mtmp) && couldsee(mtmp->mx,mtmp->my))) && 119 mtmp->mcanmove && 120 !noattacks(mtmp->data) && !onscary(u.ux, u.uy, mtmp)) 121 stop_occupation(); 122 123 return(rd); 124} 125 126#endif /* OVL1 */ 127#ifdef OVL2 128 129boolean 130onscary(x, y, mtmp) 131int x, y; 132struct monst *mtmp; 133{ 134 if (mtmp->isshk || mtmp->isgd || mtmp->iswiz || !mtmp->mcansee || 135 mtmp->mpeaceful || mtmp->data->mlet == S_HUMAN || 136 is_lminion(mtmp) || mtmp->data == &mons[PM_ANGEL] || 137 is_rider(mtmp->data) || mtmp->data == &mons[PM_MINOTAUR]) 138 return(FALSE); 139 140 return (boolean)(sobj_at(SCR_SCARE_MONSTER, x, y) 141#ifdef ELBERETH 142 || sengr_at("Elbereth", x, y) 143#endif 144 || (mtmp->data->mlet == S_VAMPIRE 145 && IS_ALTAR(levl[x][y].typ))); 146} 147 148#endif /* OVL2 */ 149#ifdef OVL0 150 151/* regenerate lost hit points */ 152void 153mon_regen(mon, digest_meal) 154struct monst *mon; 155boolean digest_meal; 156{ 157 if (mon->mhp < mon->mhpmax && 158 (moves % 20 == 0 || regenerates(mon->data))) mon->mhp++; 159 if (mon->mspec_used) mon->mspec_used--; 160 if (digest_meal) { 161 if (mon->meating) mon->meating--; 162 } 163} 164 165/* 166 * Possibly awaken the given monster. Return a 1 if the monster has been 167 * jolted awake. 168 */ 169STATIC_OVL int 170disturb(mtmp) 171 register struct monst *mtmp; 172{ 173 /* 174 * + Ettins are hard to surprise. 175 * + Nymphs, jabberwocks, and leprechauns do not easily wake up. 176 * 177 * Wake up if: 178 * in direct LOS AND 179 * within 10 squares AND 180 * not stealthy or (mon is an ettin and 9/10) AND 181 * (mon is not a nymph, jabberwock, or leprechaun) or 1/50 AND 182 * Aggravate or mon is (dog or human) or 183 * (1/7 and mon is not mimicing furniture or object) 184 */ 185 if(couldsee(mtmp->mx,mtmp->my) && 186 distu(mtmp->mx,mtmp->my) <= 100 && 187 (!Stealth || (mtmp->data == &mons[PM_ETTIN] && rn2(10))) && 188 (!(mtmp->data->mlet == S_NYMPH 189 || mtmp->data == &mons[PM_JABBERWOCK] 190#if 0 /* DEFERRED */ 191 || mtmp->data == &mons[PM_VORPAL_JABBERWOCK] 192#endif 193 || mtmp->data->mlet == S_LEPRECHAUN) || !rn2(50)) && 194 (Aggravate_monster 195 || (mtmp->data->mlet == S_DOG || 196 mtmp->data->mlet == S_HUMAN) 197 || (!rn2(7) && mtmp->m_ap_type != M_AP_FURNITURE && 198 mtmp->m_ap_type != M_AP_OBJECT) )) { 199 mtmp->msleeping = 0; 200 return(1); 201 } 202 return(0); 203} 204 205/* monster begins fleeing for the specified time, 0 means untimed flee 206 * if first, only adds fleetime if monster isn't already fleeing 207 * if fleemsg, prints a message about new flight, otherwise, caller should */ 208void 209monflee(mtmp, fleetime, first, fleemsg) 210struct monst *mtmp; 211int fleetime; 212boolean first; 213boolean fleemsg; 214{ 215 if (u.ustuck == mtmp) { 216 if (u.uswallow) 217 expels(mtmp, mtmp->data, TRUE); 218 else if (!sticks(youmonst.data)) { 219 unstuck(mtmp); /* monster lets go when fleeing */ 220 You("get released!"); 221 } 222 } 223 224 if (!first || !mtmp->mflee) { 225 /* don't lose untimed scare */ 226 if (!fleetime) 227 mtmp->mfleetim = 0; 228 else if (!mtmp->mflee || mtmp->mfleetim) { 229 fleetime += mtmp->mfleetim; 230 /* ensure monster flees long enough to visibly stop fighting */ 231 if (fleetime == 1) fleetime++; 232 mtmp->mfleetim = min(fleetime, 127); 233 } 234 if (!mtmp->mflee && fleemsg && canseemon(mtmp) && !mtmp->mfrozen) 235 pline("%s turns to flee!", (Monnam(mtmp))); 236 mtmp->mflee = 1; 237 } 238} 239 240STATIC_OVL void 241distfleeck(mtmp,inrange,nearby,scared) 242register struct monst *mtmp; 243int *inrange, *nearby, *scared; 244{ 245 int seescaryx, seescaryy; 246 247 *inrange = (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 248 (BOLT_LIM * BOLT_LIM)); 249 *nearby = *inrange && monnear(mtmp, mtmp->mux, mtmp->muy); 250 251 /* Note: if your image is displaced, the monster sees the Elbereth 252 * at your displaced position, thus never attacking your displaced 253 * position, but possibly attacking you by accident. If you are 254 * invisible, it sees the Elbereth at your real position, thus never 255 * running into you by accident but possibly attacking the spot 256 * where it guesses you are. 257 */ 258 if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) { 259 seescaryx = mtmp->mux; 260 seescaryy = mtmp->muy; 261 } else { 262 seescaryx = u.ux; 263 seescaryy = u.uy; 264 } 265 *scared = (*nearby && (onscary(seescaryx, seescaryy, mtmp) || 266 (!mtmp->mpeaceful && 267 in_your_sanctuary(mtmp, 0, 0)))); 268 269 if(*scared) { 270 if (rn2(7)) 271 monflee(mtmp, rnd(10), TRUE, TRUE); 272 else 273 monflee(mtmp, rnd(100), TRUE, TRUE); 274 } 275 276} 277 278/* perform a special one-time action for a monster; returns -1 if nothing 279 special happened, 0 if monster uses up its turn, 1 if monster is killed */ 280STATIC_OVL int 281m_arrival(mon) 282struct monst *mon; 283{ 284 mon->mstrategy &= ~STRAT_ARRIVE; /* always reset */ 285 286 return -1; 287} 288 289/* returns 1 if monster died moving, 0 otherwise */ 290/* The whole dochugw/m_move/distfleeck/mfndpos section is serious spaghetti 291 * code. --KAA 292 */ 293int 294dochug(mtmp) 295register struct monst *mtmp; 296{ 297 register struct permonst *mdat; 298 register int tmp=0; 299 int inrange, nearby, scared; 300#ifdef GOLDOBJ 301 struct obj *ygold = 0, *lepgold = 0; 302#endif 303 304/* Pre-movement adjustments */ 305 306 mdat = mtmp->data; 307 308 if (mtmp->mstrategy & STRAT_ARRIVE) { 309 int res = m_arrival(mtmp); 310 if (res >= 0) return res; 311 } 312 313 /* check for waitmask status change */ 314 if ((mtmp->mstrategy & STRAT_WAITFORU) && 315 (m_canseeu(mtmp) || mtmp->mhp < mtmp->mhpmax)) 316 mtmp->mstrategy &= ~STRAT_WAITFORU; 317 318 /* update quest status flags */ 319 quest_stat_check(mtmp); 320 321 if (!mtmp->mcanmove || (mtmp->mstrategy & STRAT_WAITMASK)) { 322 if (Hallucination) newsym(mtmp->mx,mtmp->my); 323 if (mtmp->mcanmove && (mtmp->mstrategy & STRAT_CLOSE) && 324 !mtmp->msleeping && monnear(mtmp, u.ux, u.uy)) 325 quest_talk(mtmp); /* give the leaders a chance to speak */ 326 return(0); /* other frozen monsters can't do anything */ 327 } 328 329 /* there is a chance we will wake it */ 330 if (mtmp->msleeping && !disturb(mtmp)) { 331 if (Hallucination) newsym(mtmp->mx,mtmp->my); 332 return(0); 333 } 334 335 /* not frozen or sleeping: wipe out texts written in the dust */ 336 wipe_engr_at(mtmp->mx, mtmp->my, 1); 337 338 /* confused monsters get unconfused with small probability */ 339 if (mtmp->mconf && !rn2(50)) mtmp->mconf = 0; 340 341 /* stunned monsters get un-stunned with larger probability */ 342 if (mtmp->mstun && !rn2(10)) mtmp->mstun = 0; 343 344 /* some monsters teleport */ 345 if (mtmp->mflee && !rn2(40) && can_teleport(mdat) && !mtmp->iswiz && 346 !level.flags.noteleport) { 347 (void) rloc(mtmp, FALSE); 348 return(0); 349 } 350 if (mdat->msound == MS_SHRIEK && !um_dist(mtmp->mx, mtmp->my, 1)) 351 m_respond(mtmp); 352 if (mdat == &mons[PM_MEDUSA] && couldsee(mtmp->mx, mtmp->my)) 353 m_respond(mtmp); 354 if (mtmp->mhp <= 0) return(1); /* m_respond gaze can kill medusa */ 355 356 /* fleeing monsters might regain courage */ 357 if (mtmp->mflee && !mtmp->mfleetim 358 && mtmp->mhp == mtmp->mhpmax && !rn2(25)) mtmp->mflee = 0; 359 360 set_apparxy(mtmp); 361 /* Must be done after you move and before the monster does. The 362 * set_apparxy() call in m_move() doesn't suffice since the variables 363 * inrange, etc. all depend on stuff set by set_apparxy(). 364 */ 365 366 /* Monsters that want to acquire things */ 367 /* may teleport, so do it before inrange is set */ 368 if(is_covetous(mdat)) (void) tactics(mtmp); 369 370 /* check distance and scariness of attacks */ 371 distfleeck(mtmp,&inrange,&nearby,&scared); 372 373 if(find_defensive(mtmp)) { 374 if (use_defensive(mtmp) != 0) 375 return 1; 376 } else if(find_misc(mtmp)) { 377 if (use_misc(mtmp) != 0) 378 return 1; 379 } 380 381 /* Demonic Blackmail! */ 382 if(nearby && mdat->msound == MS_BRIBE && 383 mtmp->mpeaceful && !mtmp->mtame && !u.uswallow) { 384 if (mtmp->mux != u.ux || mtmp->muy != u.uy) { 385 pline("%s whispers at thin air.", 386 cansee(mtmp->mux, mtmp->muy) ? Monnam(mtmp) : "It"); 387 388 if (is_demon(youmonst.data)) { 389 /* "Good hunting, brother" */ 390 if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE); 391 } else { 392 mtmp->minvis = mtmp->perminvis = 0; 393 /* Why? For the same reason in real demon talk */ 394 pline("%s gets angry!", Amonnam(mtmp)); 395 mtmp->mpeaceful = 0; 396 /* since no way is an image going to pay it off */ 397 } 398 } else if(demon_talk(mtmp)) return(1); /* you paid it off */ 399 } 400 401 /* the watch will look around and see if you are up to no good :-) */ 402 if (mdat == &mons[PM_WATCHMAN] || mdat == &mons[PM_WATCH_CAPTAIN]) 403 watch_on_duty(mtmp); 404 405 else if (is_mind_flayer(mdat) && !rn2(20)) { 406 struct monst *m2, *nmon = (struct monst *)0; 407 408 if (canseemon(mtmp)) 409 pline("%s concentrates.", Monnam(mtmp)); 410 if (distu(mtmp->mx, mtmp->my) > BOLT_LIM * BOLT_LIM) { 411 You("sense a faint wave of psychic energy."); 412 goto toofar; 413 } 414 pline("A wave of psychic energy pours over you!"); 415 if (mtmp->mpeaceful && 416 (!Conflict || resist(mtmp, RING_CLASS, 0, 0))) 417 pline("It feels quite soothing."); 418 else { 419 register boolean m_sen = sensemon(mtmp); 420 421 if (m_sen || (Blind_telepat && rn2(2)) || !rn2(10)) { 422 int dmg; 423 pline("It locks on to your %s!", 424 m_sen ? "telepathy" : 425 Blind_telepat ? "latent telepathy" : "mind"); 426 dmg = rnd(15); 427 if (Half_spell_damage) dmg = (dmg+1) / 2; 428 losehp(dmg, "psychic blast", KILLED_BY_AN); 429 } 430 } 431 for(m2=fmon; m2; m2 = nmon) { 432 nmon = m2->nmon; 433 if (DEADMONSTER(m2)) continue; 434 if (m2->mpeaceful == mtmp->mpeaceful) continue; 435 if (mindless(m2->data)) continue; 436 if (m2 == mtmp) continue; 437 if ((telepathic(m2->data) && 438 (rn2(2) || m2->mblinded)) || !rn2(10)) { 439 if (cansee(m2->mx, m2->my)) 440 pline("It locks on to %s.", mon_nam(m2)); 441 m2->mhp -= rnd(15); 442 if (m2->mhp <= 0) 443 monkilled(m2, "", AD_DRIN); 444 else 445 m2->msleeping = 0; 446 } 447 } 448 } 449toofar: 450 451 /* If monster is nearby you, and has to wield a weapon, do so. This 452 * costs the monster a move, of course. 453 */ 454 if((!mtmp->mpeaceful || Conflict) && inrange && 455 dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 8 456 && attacktype(mdat, AT_WEAP)) { 457 struct obj *mw_tmp; 458 459 /* The scared check is necessary. Otherwise a monster that is 460 * one square near the player but fleeing into a wall would keep 461 * switching between pick-axe and weapon. If monster is stuck 462 * in a trap, prefer ranged weapon (wielding is done in thrwmu). 463 * This may cost the monster an attack, but keeps the monster 464 * from switching back and forth if carrying both. 465 */ 466 mw_tmp = MON_WEP(mtmp); 467 if (!(scared && mw_tmp && is_pick(mw_tmp)) && 468 mtmp->weapon_check == NEED_WEAPON && 469 !(mtmp->mtrapped && !nearby && select_rwep(mtmp))) { 470 mtmp->weapon_check = NEED_HTH_WEAPON; 471 if (mon_wield_item(mtmp) != 0) return(0); 472 } 473 } 474 475/* Now the actual movement phase */ 476 477#ifndef GOLDOBJ 478 if(!nearby || mtmp->mflee || scared || 479 mtmp->mconf || mtmp->mstun || (mtmp->minvis && !rn2(3)) || 480 (mdat->mlet == S_LEPRECHAUN && !u.ugold && (mtmp->mgold || rn2(2))) || 481#else 482 if (mdat->mlet == S_LEPRECHAUN) { 483 ygold = findgold(invent); 484 lepgold = findgold(mtmp->minvent); 485 } 486 487 if(!nearby || mtmp->mflee || scared || 488 mtmp->mconf || mtmp->mstun || (mtmp->minvis && !rn2(3)) || 489 (mdat->mlet == S_LEPRECHAUN && !ygold && (lepgold || rn2(2))) || 490#endif 491 (is_wanderer(mdat) && !rn2(4)) || (Conflict && !mtmp->iswiz) || 492 (!mtmp->mcansee && !rn2(4)) || mtmp->mpeaceful) { 493 /* Possibly cast an undirected spell if not attacking you */ 494 /* note that most of the time castmu() will pick a directed 495 spell and do nothing, so the monster moves normally */ 496 /* arbitrary distance restriction to keep monster far away 497 from you from having cast dozens of sticks-to-snakes 498 or similar spells by the time you reach it */ 499 if (dist2(mtmp->mx, mtmp->my, u.ux, u.uy) <= 49 && !mtmp->mspec_used) { 500 struct attack *a; 501 502 for (a = &mdat->mattk[0]; a < &mdat->mattk[NATTK]; a++) { 503 if (a->aatyp == AT_MAGC && (a->adtyp == AD_SPEL || a->adtyp == AD_CLRC)) { 504 if (castmu(mtmp, a, FALSE, FALSE)) { 505 tmp = 3; 506 break; 507 } 508 } 509 } 510 } 511 512 tmp = m_move(mtmp, 0); 513 distfleeck(mtmp,&inrange,&nearby,&scared); /* recalc */ 514 515 switch (tmp) { 516 case 0: /* no movement, but it can still attack you */ 517 case 3: /* absolutely no movement */ 518 /* for pets, case 0 and 3 are equivalent */ 519 /* vault guard might have vanished */ 520 if (mtmp->isgd && (mtmp->mhp < 1 || 521 (mtmp->mx == 0 && mtmp->my == 0))) 522 return 1; /* behave as if it died */ 523 /* During hallucination, monster appearance should 524 * still change - even if it doesn't move. 525 */ 526 if(Hallucination) newsym(mtmp->mx,mtmp->my); 527 break; 528 case 1: /* monster moved */ 529 /* Maybe it stepped on a trap and fell asleep... */ 530 if (mtmp->msleeping || !mtmp->mcanmove) return(0); 531 if(!nearby && 532 (ranged_attk(mdat) || find_offensive(mtmp))) 533 break; 534 else if(u.uswallow && mtmp == u.ustuck) { 535 /* a monster that's digesting you can move at the 536 * same time -dlc 537 */ 538 return(mattacku(mtmp)); 539 } else 540 return(0); 541 /*NOTREACHED*/ 542 break; 543 case 2: /* monster died */ 544 return(1); 545 } 546 } 547 548/* Now, attack the player if possible - one attack set per monst */ 549 550 if (!mtmp->mpeaceful || 551 (Conflict && !resist(mtmp, RING_CLASS, 0, 0))) { 552 if(inrange && !noattacks(mdat) && u.uhp > 0 && !scared && tmp != 3) 553 if(mattacku(mtmp)) return(1); /* monster died (e.g. exploded) */ 554 555 if(mtmp->wormno) wormhitu(mtmp); 556 } 557 /* special speeches for quest monsters */ 558 if (!mtmp->msleeping && mtmp->mcanmove && nearby) 559 quest_talk(mtmp); 560 /* extra emotional attack for vile monsters */ 561 if (inrange && mtmp->data->msound == MS_CUSS && !mtmp->mpeaceful && 562 couldsee(mtmp->mx, mtmp->my) && !mtmp->minvis && !rn2(5)) 563 cuss(mtmp); 564 565 return(tmp == 2); 566} 567 568static NEARDATA const char practical[] = { WEAPON_CLASS, ARMOR_CLASS, GEM_CLASS, FOOD_CLASS, 0 }; 569static NEARDATA const char magical[] = { 570 AMULET_CLASS, POTION_CLASS, SCROLL_CLASS, WAND_CLASS, RING_CLASS, 571 SPBOOK_CLASS, 0 }; 572static NEARDATA const char indigestion[] = { BALL_CLASS, ROCK_CLASS, 0 }; 573static NEARDATA const char boulder_class[] = { ROCK_CLASS, 0 }; 574static NEARDATA const char gem_class[] = { GEM_CLASS, 0 }; 575 576boolean 577itsstuck(mtmp) 578register struct monst *mtmp; 579{ 580 if (sticks(youmonst.data) && mtmp==u.ustuck && !u.uswallow) { 581 pline("%s cannot escape from you!", Monnam(mtmp)); 582 return(TRUE); 583 } 584 return(FALSE); 585} 586 587/* Return values: 588 * 0: did not move, but can still attack and do other stuff. 589 * 1: moved, possibly can attack. 590 * 2: monster died. 591 * 3: did not move, and can't do anything else either. 592 */ 593int 594m_move(mtmp, after) 595register struct monst *mtmp; 596register int after; 597{ 598 register int appr; 599 xchar gx,gy,nix,niy,chcnt; 600 int chi; /* could be schar except for stupid Sun-2 compiler */ 601 boolean likegold=0, likegems=0, likeobjs=0, likemagic=0, conceals=0; 602 boolean likerock=0, can_tunnel=0; 603 boolean can_open=0, can_unlock=0, doorbuster=0; 604 boolean uses_items=0, setlikes=0; 605 boolean avoid=FALSE; 606 struct permonst *ptr; 607 struct monst *mtoo; 608 schar mmoved = 0; /* not strictly nec.: chi >= 0 will do */ 609 long info[9]; 610 long flag; 611 int omx = mtmp->mx, omy = mtmp->my; 612 struct obj *mw_tmp; 613 614 if(mtmp->mtrapped) { 615 int i = mintrap(mtmp); 616 if(i >= 2) { newsym(mtmp->mx,mtmp->my); return(2); }/* it died */ 617 if(i == 1) return(0); /* still in trap, so didn't move */ 618 } 619 ptr = mtmp->data; /* mintrap() can change mtmp->data -dlc */ 620 621 if (mtmp->meating) { 622 mtmp->meating--; 623 return 3; /* still eating */ 624 } 625 if (hides_under(ptr) && OBJ_AT(mtmp->mx, mtmp->my) && rn2(10)) 626 return 0; /* do not leave hiding place */ 627 628 set_apparxy(mtmp); 629 /* where does mtmp think you are? */ 630 /* Not necessary if m_move called from this file, but necessary in 631 * other calls of m_move (ex. leprechauns dodging) 632 */ 633#ifdef REINCARNATION 634 if (!Is_rogue_level(&u.uz)) 635#endif 636 can_tunnel = tunnels(ptr); 637 can_open = !(nohands(ptr) || verysmall(ptr)); 638 can_unlock = ((can_open && m_carrying(mtmp, SKELETON_KEY)) || 639 mtmp->iswiz || is_rider(ptr)); 640 doorbuster = is_giant(ptr); 641 if(mtmp->wormno) goto not_special; 642 /* my dog gets special treatment */ 643 if(mtmp->mtame) { 644 mmoved = dog_move(mtmp, after); 645 goto postmov; 646 } 647 648 /* likewise for shopkeeper */ 649 if(mtmp->isshk) { 650 mmoved = shk_move(mtmp); 651 if(mmoved == -2) return(2); 652 if(mmoved >= 0) goto postmov; 653 mmoved = 0; /* follow player outside shop */ 654 } 655 656 /* and for the guard */ 657 if(mtmp->isgd) { 658 mmoved = gd_move(mtmp); 659 if(mmoved == -2) return(2); 660 if(mmoved >= 0) goto postmov; 661 mmoved = 0; 662 } 663 664 /* and the acquisitive monsters get special treatment */ 665 if(is_covetous(ptr)) { 666 xchar tx = STRAT_GOALX(mtmp->mstrategy), 667 ty = STRAT_GOALY(mtmp->mstrategy); 668 struct monst *intruder = m_at(tx, ty); 669 /* 670 * if there's a monster on the object or in possesion of it, 671 * attack it. 672 */ 673 if((dist2(mtmp->mx, mtmp->my, tx, ty) < 2) && 674 intruder && (intruder != mtmp)) { 675 676 notonhead = (intruder->mx != tx || intruder->my != ty); 677 if(mattackm(mtmp, intruder) == 2) return(2); 678 mmoved = 1; 679 } else mmoved = 0; 680 goto postmov; 681 } 682 683 /* and for the priest */ 684 if(mtmp->ispriest) { 685 mmoved = pri_move(mtmp); 686 if(mmoved == -2) return(2); 687 if(mmoved >= 0) goto postmov; 688 mmoved = 0; 689 } 690 691#ifdef MAIL 692 if(ptr == &mons[PM_MAIL_DAEMON]) { 693 if(flags.soundok && canseemon(mtmp)) 694 verbalize("I'm late!"); 695 mongone(mtmp); 696 return(2); 697 } 698#endif 699 700 /* teleport if that lies in our nature */ 701 if(ptr == &mons[PM_TENGU] && !rn2(5) && !mtmp->mcan && 702 !tele_restrict(mtmp)) { 703 if(mtmp->mhp < 7 || mtmp->mpeaceful || rn2(2)) 704 (void) rloc(mtmp, FALSE); 705 else 706 mnexto(mtmp); 707 mmoved = 1; 708 goto postmov; 709 } 710not_special: 711 if(u.uswallow && !mtmp->mflee && u.ustuck != mtmp) return(1); 712 omx = mtmp->mx; 713 omy = mtmp->my; 714 gx = mtmp->mux; 715 gy = mtmp->muy; 716 appr = mtmp->mflee ? -1 : 1; 717 if (mtmp->mconf || (u.uswallow && mtmp == u.ustuck)) 718 appr = 0; 719 else { 720#ifdef GOLDOBJ 721 struct obj *lepgold, *ygold; 722#endif 723 boolean should_see = (couldsee(omx, omy) && 724 (levl[gx][gy].lit || 725 !levl[omx][omy].lit) && 726 (dist2(omx, omy, gx, gy) <= 36)); 727 728 if (!mtmp->mcansee || 729 (should_see && Invis && !perceives(ptr) && rn2(11)) || 730 (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance == STRANGE_OBJECT) || u.uundetected || 731 (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance == GOLD_PIECE && !likes_gold(ptr)) || 732 (mtmp->mpeaceful && !mtmp->isshk) || /* allow shks to follow */ 733 ((monsndx(ptr) == PM_STALKER || ptr->mlet == S_BAT || 734 ptr->mlet == S_LIGHT) && !rn2(3))) 735 appr = 0; 736 737 if(monsndx(ptr) == PM_LEPRECHAUN && (appr == 1) && 738#ifndef GOLDOBJ 739 (mtmp->mgold > u.ugold)) 740#else 741 ( (lepgold = findgold(mtmp->minvent)) && 742 (lepgold->quan > ((ygold = findgold(invent)) ? ygold->quan : 0L)) )) 743#endif 744 appr = -1; 745 746 if (!should_see && can_track(ptr)) { 747 register coord *cp; 748 749 cp = gettrack(omx,omy); 750 if (cp) { 751 gx = cp->x; 752 gy = cp->y; 753 } 754 } 755 } 756 757 if ((!mtmp->mpeaceful || !rn2(10)) 758#ifdef REINCARNATION 759 && (!Is_rogue_level(&u.uz)) 760#endif 761 ) { 762 boolean in_line = lined_up(mtmp) && 763 (distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 764 (throws_rocks(youmonst.data) ? 20 : ACURRSTR/2+1) 765 ); 766 767 if (appr != 1 || !in_line) { 768 /* Monsters in combat won't pick stuff up, avoiding the 769 * situation where you toss arrows at it and it has nothing 770 * better to do than pick the arrows up. 771 */ 772 register int pctload = (curr_mon_load(mtmp) * 100) / 773 max_mon_load(mtmp); 774 775 /* look for gold or jewels nearby */ 776 likegold = (likes_gold(ptr) && pctload < 95); 777 likegems = (likes_gems(ptr) && pctload < 85); 778 uses_items = (!mindless(ptr) && !is_animal(ptr) 779 && pctload < 75); 780 likeobjs = (likes_objs(ptr) && pctload < 75); 781 likemagic = (likes_magic(ptr) && pctload < 85); 782 likerock = (throws_rocks(ptr) && pctload < 50 && !In_sokoban(&u.uz)); 783 conceals = hides_under(ptr); 784 setlikes = TRUE; 785 } 786 } 787 788#define SQSRCHRADIUS 5 789 790 { register int minr = SQSRCHRADIUS; /* not too far away */ 791 register struct obj *otmp; 792 register int xx, yy; 793 int oomx, oomy, lmx, lmy; 794 795 /* cut down the search radius if it thinks character is closer. */ 796 if(distmin(mtmp->mux, mtmp->muy, omx, omy) < SQSRCHRADIUS && 797 !mtmp->mpeaceful) minr--; 798 /* guards shouldn't get too distracted */ 799 if(!mtmp->mpeaceful && is_mercenary(ptr)) minr = 1; 800 801 if((likegold || likegems || likeobjs || likemagic || likerock || conceals) 802 && (!*in_rooms(omx, omy, SHOPBASE) || (!rn2(25) && !mtmp->isshk))) { 803 look_for_obj: 804 oomx = min(COLNO-1, omx+minr); 805 oomy = min(ROWNO-1, omy+minr); 806 lmx = max(1, omx-minr); 807 lmy = max(0, omy-minr); 808 for(otmp = fobj; otmp; otmp = otmp->nobj) { 809 /* monsters may pick rocks up, but won't go out of their way 810 to grab them; this might hamper sling wielders, but it cuts 811 down on move overhead by filtering out most common item */ 812 if (otmp->otyp == ROCK) continue; 813 xx = otmp->ox; 814 yy = otmp->oy; 815 /* Nymphs take everything. Most other creatures should not 816 * pick up corpses except as a special case like in 817 * searches_for_item(). We need to do this check in 818 * mpickstuff() as well. 819 */ 820 if(xx >= lmx && xx <= oomx && yy >= lmy && yy <= oomy) { 821 /* don't get stuck circling around an object that's underneath 822 an immobile or hidden monster; paralysis victims excluded */ 823 if ((mtoo = m_at(xx,yy)) != 0 && 824 (mtoo->msleeping || mtoo->mundetected || 825 (mtoo->mappearance && !mtoo->iswiz) || 826 !mtoo->data->mmove)) continue; 827 828 if(((likegold && otmp->oclass == COIN_CLASS) || 829 (likeobjs && index(practical, otmp->oclass) && 830 (otmp->otyp != CORPSE || (ptr->mlet == S_NYMPH 831 && !is_rider(&mons[otmp->corpsenm])))) || 832 (likemagic && index(magical, otmp->oclass)) || 833 (uses_items && searches_for_item(mtmp, otmp)) || 834 (likerock && otmp->otyp == BOULDER) || 835 (likegems && otmp->oclass == GEM_CLASS && 836 objects[otmp->otyp].oc_material != MINERAL) || 837 (conceals && !cansee(otmp->ox,otmp->oy)) || 838 (ptr == &mons[PM_GELATINOUS_CUBE] && 839 !index(indigestion, otmp->oclass) && 840 !(otmp->otyp == CORPSE && 841 touch_petrifies(&mons[otmp->corpsenm]))) 842 ) && touch_artifact(otmp,mtmp)) { 843 if(can_carry(mtmp,otmp) && 844 (throws_rocks(ptr) || 845 !sobj_at(BOULDER,xx,yy)) && 846 (!is_unicorn(ptr) || 847 objects[otmp->otyp].oc_material == GEMSTONE) && 848 /* Don't get stuck circling an Elbereth */ 849 !(onscary(xx, yy, mtmp))) { 850 minr = distmin(omx,omy,xx,yy); 851 oomx = min(COLNO-1, omx+minr); 852 oomy = min(ROWNO-1, omy+minr); 853 lmx = max(1, omx-minr); 854 lmy = max(0, omy-minr); 855 gx = otmp->ox; 856 gy = otmp->oy; 857 if (gx == omx && gy == omy) { 858 mmoved = 3; /* actually unnecessary */ 859 goto postmov; 860 } 861 } 862 } 863 } 864 } 865 } else if(likegold) { 866 /* don't try to pick up anything else, but use the same loop */ 867 uses_items = 0; 868 likegems = likeobjs = likemagic = likerock = conceals = 0; 869 goto look_for_obj; 870 } 871 872 if(minr < SQSRCHRADIUS && appr == -1) { 873 if(distmin(omx,omy,mtmp->mux,mtmp->muy) <= 3) { 874 gx = mtmp->mux; 875 gy = mtmp->muy; 876 } else 877 appr = 1; 878 } 879 } 880 881 /* don't tunnel if hostile and close enough to prefer a weapon */ 882 if (can_tunnel && needspick(ptr) && 883 ((!mtmp->mpeaceful || Conflict) && 884 dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 8)) 885 can_tunnel = FALSE; 886 887 nix = omx; 888 niy = omy; 889 flag = 0L; 890 if (mtmp->mpeaceful && (!Conflict || resist(mtmp, RING_CLASS, 0, 0))) 891 flag |= (ALLOW_SANCT | ALLOW_SSM); 892 else flag |= ALLOW_U; 893 if (is_minion(ptr) || is_rider(ptr)) flag |= ALLOW_SANCT; 894 /* unicorn may not be able to avoid hero on a noteleport level */ 895 if (is_unicorn(ptr) && !level.flags.noteleport) flag |= NOTONL; 896 if (passes_walls(ptr)) flag |= (ALLOW_WALL | ALLOW_ROCK); 897 if (passes_bars(ptr)) flag |= ALLOW_BARS; 898 if (can_tunnel) flag |= ALLOW_DIG; 899 if (is_human(ptr) || ptr == &mons[PM_MINOTAUR]) flag |= ALLOW_SSM; 900 if (is_undead(ptr) && ptr->mlet != S_GHOST) flag |= NOGARLIC; 901 if (throws_rocks(ptr)) flag |= ALLOW_ROCK; 902 if (can_open) flag |= OPENDOOR; 903 if (can_unlock) flag |= UNLOCKDOOR; 904 if (doorbuster) flag |= BUSTDOOR; 905 { 906 register int i, j, nx, ny, nearer; 907 int jcnt, cnt; 908 int ndist, nidist; 909 register coord *mtrk; 910 coord poss[9]; 911 912 cnt = mfndpos(mtmp, poss, info, flag); 913 chcnt = 0; 914 jcnt = min(MTSZ, cnt-1); 915 chi = -1; 916 nidist = dist2(nix,niy,gx,gy); 917 /* allow monsters be shortsighted on some levels for balance */ 918 if(!mtmp->mpeaceful && level.flags.shortsighted && 919 nidist > (couldsee(nix,niy) ? 144 : 36) && appr == 1) appr = 0; 920 if (is_unicorn(ptr) && level.flags.noteleport) { 921 /* on noteleport levels, perhaps we cannot avoid hero */ 922 for(i = 0; i < cnt; i++) 923 if(!(info[i] & NOTONL)) avoid=TRUE; 924 } 925 926 for(i=0; i < cnt; i++) { 927 if (avoid && (info[i] & NOTONL)) continue; 928 nx = poss[i].x; 929 ny = poss[i].y; 930 931 if (appr != 0) { 932 mtrk = &mtmp->mtrack[0]; 933 for(j=0; j < jcnt; mtrk++, j++) 934 if(nx == mtrk->x && ny == mtrk->y) 935 if(rn2(4*(cnt-j))) 936 goto nxti; 937 } 938 939 nearer = ((ndist = dist2(nx,ny,gx,gy)) < nidist); 940 941 if((appr == 1 && nearer) || (appr == -1 && !nearer) || 942 (!appr && !rn2(++chcnt)) || !mmoved) { 943 nix = nx; 944 niy = ny; 945 nidist = ndist; 946 chi = i; 947 mmoved = 1; 948 } 949 nxti: ; 950 } 951 } 952 953 if(mmoved) { 954 register int j; 955 956 if (mmoved==1 && (u.ux != nix || u.uy != niy) && itsstuck(mtmp)) 957 return(3); 958 959 if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy)) || 960 closed_door(nix, niy)) && 961 mmoved==1 && can_tunnel && needspick(ptr)) { 962 if (closed_door(nix, niy)) { 963 if (!(mw_tmp = MON_WEP(mtmp)) || 964 !is_pick(mw_tmp) || !is_axe(mw_tmp)) 965 mtmp->weapon_check = NEED_PICK_OR_AXE; 966 } else if (IS_TREE(levl[nix][niy].typ)) { 967 if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp)) 968 mtmp->weapon_check = NEED_AXE; 969 } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) { 970 mtmp->weapon_check = NEED_PICK_AXE; 971 } 972 if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp)) 973 return(3); 974 } 975 /* If ALLOW_U is set, either it's trying to attack you, or it 976 * thinks it is. In either case, attack this spot in preference to 977 * all others. 978 */ 979 /* Actually, this whole section of code doesn't work as you'd expect. 980 * Most attacks are handled in dochug(). It calls distfleeck(), which 981 * among other things sets nearby if the monster is near you--and if 982 * nearby is set, we never call m_move unless it is a special case 983 * (confused, stun, etc.) The effect is that this ALLOW_U (and 984 * mfndpos) has no effect for normal attacks, though it lets a confused 985 * monster attack you by accident. 986 */ 987 if(info[chi] & ALLOW_U) { 988 nix = mtmp->mux; 989 niy = mtmp->muy; 990 } 991 if (nix == u.ux && niy == u.uy) { 992 mtmp->mux = u.ux; 993 mtmp->muy = u.uy; 994 return(0); 995 } 996 /* The monster may attack another based on 1 of 2 conditions: 997 * 1 - It may be confused. 998 * 2 - It may mistake the monster for your (displaced) image. 999 * Pets get taken care of above and shouldn't reach this code. 1000 * Conflict gets handled even farther away (movemon()). 1001 */ 1002 if((info[chi] & ALLOW_M) || 1003 (nix == mtmp->mux && niy == mtmp->muy)) { 1004 struct monst *mtmp2; 1005 int mstatus; 1006 mtmp2 = m_at(nix,niy); 1007 1008 notonhead = mtmp2 && (nix != mtmp2->mx || niy != mtmp2->my); 1009 /* note: mstatus returns 0 if mtmp2 is nonexistent */ 1010 mstatus = mattackm(mtmp, mtmp2); 1011 1012 if (mstatus & MM_AGR_DIED) /* aggressor died */ 1013 return 2; 1014 1015 if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) && 1016 rn2(4) && mtmp2->movement >= NORMAL_SPEED) { 1017 mtmp2->movement -= NORMAL_SPEED; 1018 notonhead = 0; 1019 mstatus = mattackm(mtmp2, mtmp); /* return attack */ 1020 if (mstatus & MM_DEF_DIED) 1021 return 2; 1022 } 1023 return 3; 1024 } 1025 1026 if (!m_in_out_region(mtmp,nix,niy)) 1027 return 3; 1028 remove_monster(omx, omy); 1029 place_monster(mtmp, nix, niy); 1030 for(j = MTSZ-1; j > 0; j--) 1031 mtmp->mtrack[j] = mtmp->mtrack[j-1]; 1032 mtmp->mtrack[0].x = omx; 1033 mtmp->mtrack[0].y = omy; 1034 /* Place a segment at the old position. */ 1035 if (mtmp->wormno) worm_move(mtmp); 1036 } else { 1037 if(is_unicorn(ptr) && rn2(2) && !tele_restrict(mtmp)) { 1038 (void) rloc(mtmp, FALSE); 1039 return(1); 1040 } 1041 if(mtmp->wormno) worm_nomove(mtmp); 1042 } 1043postmov: 1044 if(mmoved == 1 || mmoved == 3) { 1045 boolean canseeit = cansee(mtmp->mx, mtmp->my); 1046 1047 if(mmoved == 1) { 1048 newsym(omx,omy); /* update the old position */ 1049 if (mintrap(mtmp) >= 2) { 1050 if(mtmp->mx) newsym(mtmp->mx,mtmp->my); 1051 return(2); /* it died */ 1052 } 1053 ptr = mtmp->data; 1054 1055 /* open a door, or crash through it, if you can */ 1056 if(IS_DOOR(levl[mtmp->mx][mtmp->my].typ) 1057 && !passes_walls(ptr) /* doesn't need to open doors */ 1058 && !can_tunnel /* taken care of below */ 1059 ) { 1060 struct rm *here = &levl[mtmp->mx][mtmp->my]; 1061 boolean btrapped = (here->doormask & D_TRAPPED); 1062 1063 if(here->doormask & (D_LOCKED|D_CLOSED) && amorphous(ptr)) { 1064 if (flags.verbose && canseemon(mtmp)) 1065 pline("%s %s under the door.", Monnam(mtmp), 1066 (ptr == &mons[PM_FOG_CLOUD] || 1067 ptr == &mons[PM_YELLOW_LIGHT]) 1068 ? "flows" : "oozes"); 1069 } else if(here->doormask & D_LOCKED && can_unlock) { 1070 if(btrapped) { 1071 here->doormask = D_NODOOR; 1072 newsym(mtmp->mx, mtmp->my); 1073 unblock_point(mtmp->mx,mtmp->my); /* vision */ 1074 if(mb_trapped(mtmp)) return(2); 1075 } else { 1076 if (flags.verbose) { 1077 if (canseeit) 1078 You("see a door unlock and open."); 1079 else if (flags.soundok) 1080 You_hear("a door unlock and open."); 1081 } 1082 here->doormask = D_ISOPEN; 1083 /* newsym(mtmp->mx, mtmp->my); */ 1084 unblock_point(mtmp->mx,mtmp->my); /* vision */ 1085 } 1086 } else if (here->doormask == D_CLOSED && can_open) { 1087 if(btrapped) { 1088 here->doormask = D_NODOOR; 1089 newsym(mtmp->mx, mtmp->my); 1090 unblock_point(mtmp->mx,mtmp->my); /* vision */ 1091 if(mb_trapped(mtmp)) return(2); 1092 } else { 1093 if (flags.verbose) { 1094 if (canseeit) 1095 You("see a door open."); 1096 else if (flags.soundok) 1097 You_hear("a door open."); 1098 } 1099 here->doormask = D_ISOPEN; 1100 /* newsym(mtmp->mx, mtmp->my); */ /* done below */ 1101 unblock_point(mtmp->mx,mtmp->my); /* vision */ 1102 } 1103 } else if (here->doormask & (D_LOCKED|D_CLOSED)) { 1104 /* mfndpos guarantees this must be a doorbuster */ 1105 if(btrapped) { 1106 here->doormask = D_NODOOR; 1107 newsym(mtmp->mx, mtmp->my); 1108 unblock_point(mtmp->mx,mtmp->my); /* vision */ 1109 if(mb_trapped(mtmp)) return(2); 1110 } else { 1111 if (flags.verbose) { 1112 if (canseeit) 1113 You("see a door crash open."); 1114 else if (flags.soundok) 1115 You_hear("a door crash open."); 1116 } 1117 if (here->doormask & D_LOCKED && !rn2(2)) 1118 here->doormask = D_NODOOR; 1119 else here->doormask = D_BROKEN; 1120 /* newsym(mtmp->mx, mtmp->my); */ /* done below */ 1121 unblock_point(mtmp->mx,mtmp->my); /* vision */ 1122 } 1123 /* if it's a shop door, schedule repair */ 1124 if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE)) 1125 add_damage(mtmp->mx, mtmp->my, 0L); 1126 } 1127 } else if (levl[mtmp->mx][mtmp->my].typ == IRONBARS) { 1128 if (flags.verbose && canseemon(mtmp)) 1129 Norep("%s %s %s the iron bars.", Monnam(mtmp), 1130 /* pluralization fakes verb conjugation */ 1131 makeplural(locomotion(ptr, "pass")), 1132 passes_walls(ptr) ? "through" : "between"); 1133 } 1134 1135 /* possibly dig */ 1136 if (can_tunnel && mdig_tunnel(mtmp)) 1137 return(2); /* mon died (position already updated) */ 1138 1139 /* set also in domove(), hack.c */ 1140 if (u.uswallow && mtmp == u.ustuck && 1141 (mtmp->mx != omx || mtmp->my != omy)) { 1142 /* If the monster moved, then update */ 1143 u.ux0 = u.ux; 1144 u.uy0 = u.uy; 1145 u.ux = mtmp->mx; 1146 u.uy = mtmp->my; 1147 swallowed(0); 1148 } else 1149 newsym(mtmp->mx,mtmp->my); 1150 } 1151 if(OBJ_AT(mtmp->mx, mtmp->my) && mtmp->mcanmove) { 1152 /* recompute the likes tests, in case we polymorphed 1153 * or if the "likegold" case got taken above */ 1154 if (setlikes) { 1155 register int pctload = (curr_mon_load(mtmp) * 100) / 1156 max_mon_load(mtmp); 1157 1158 /* look for gold or jewels nearby */ 1159 likegold = (likes_gold(ptr) && pctload < 95); 1160 likegems = (likes_gems(ptr) && pctload < 85); 1161 uses_items = (!mindless(ptr) && !is_animal(ptr) 1162 && pctload < 75); 1163 likeobjs = (likes_objs(ptr) && pctload < 75); 1164 likemagic = (likes_magic(ptr) && pctload < 85); 1165 likerock = (throws_rocks(ptr) && pctload < 50 && 1166 !In_sokoban(&u.uz)); 1167 conceals = hides_under(ptr); 1168 } 1169 1170 /* Maybe a rock mole just ate some metal object */ 1171 if (metallivorous(ptr)) { 1172 if (meatmetal(mtmp) == 2) return 2; /* it died */ 1173 } 1174 1175 if(g_at(mtmp->mx,mtmp->my) && likegold) mpickgold(mtmp); 1176 1177 /* Maybe a cube ate just about anything */ 1178 if (ptr == &mons[PM_GELATINOUS_CUBE]) { 1179 if (meatobj(mtmp) == 2) return 2; /* it died */ 1180 } 1181 1182 if(!*in_rooms(mtmp->mx, mtmp->my, SHOPBASE) || !rn2(25)) { 1183 boolean picked = FALSE; 1184 1185 if(likeobjs) picked |= mpickstuff(mtmp, practical); 1186 if(likemagic) picked |= mpickstuff(mtmp, magical); 1187 if(likerock) picked |= mpickstuff(mtmp, boulder_class); 1188 if(likegems) picked |= mpickstuff(mtmp, gem_class); 1189 if(uses_items) picked |= mpickstuff(mtmp, (char *)0); 1190 if(picked) mmoved = 3; 1191 } 1192 1193 if(mtmp->minvis) { 1194 newsym(mtmp->mx, mtmp->my); 1195 if (mtmp->wormno) see_wsegs(mtmp); 1196 } 1197 } 1198 1199 if(hides_under(ptr) || ptr->mlet == S_EEL) { 1200 /* Always set--or reset--mundetected if it's already hidden 1201 (just in case the object it was hiding under went away); 1202 usually set mundetected unless monster can't move. */ 1203 if (mtmp->mundetected || 1204 (mtmp->mcanmove && !mtmp->msleeping && rn2(5))) 1205 mtmp->mundetected = (ptr->mlet != S_EEL) ? 1206 OBJ_AT(mtmp->mx, mtmp->my) : 1207 (is_pool(mtmp->mx, mtmp->my) && !Is_waterlevel(&u.uz)); 1208 newsym(mtmp->mx, mtmp->my); 1209 } 1210 if (mtmp->isshk) { 1211 after_shk_move(mtmp); 1212 } 1213 } 1214 return(mmoved); 1215} 1216 1217#endif /* OVL0 */ 1218#ifdef OVL2 1219 1220boolean 1221closed_door(x, y) 1222register int x, y; 1223{ 1224 return((boolean)(IS_DOOR(levl[x][y].typ) && 1225 (levl[x][y].doormask & (D_LOCKED | D_CLOSED)))); 1226} 1227 1228boolean 1229accessible(x, y) 1230register int x, y; 1231{ 1232 return((boolean)(ACCESSIBLE(levl[x][y].typ) && !closed_door(x, y))); 1233} 1234 1235#endif /* OVL2 */ 1236#ifdef OVL0 1237 1238/* decide where the monster thinks you are standing */ 1239void 1240set_apparxy(mtmp) 1241register struct monst *mtmp; 1242{ 1243 boolean notseen, gotu; 1244 register int disp, mx = mtmp->mux, my = mtmp->muy; 1245#ifdef GOLDOBJ 1246 long umoney = money_cnt(invent); 1247#endif 1248 1249 /* 1250 * do cheapest and/or most likely tests first 1251 */ 1252 1253 /* pet knows your smell; grabber still has hold of you */ 1254 if (mtmp->mtame || mtmp == u.ustuck) goto found_you; 1255 1256 /* monsters which know where you are don't suddenly forget, 1257 if you haven't moved away */ 1258 if (mx == u.ux && my == u.uy) goto found_you; 1259 1260 notseen = (!mtmp->mcansee || (Invis && !perceives(mtmp->data))); 1261 /* add cases as required. eg. Displacement ... */ 1262 if (notseen || Underwater) { 1263 /* Xorns can smell valuable metal like gold, treat as seen */ 1264 if ((mtmp->data == &mons[PM_XORN]) && 1265#ifndef GOLDOBJ 1266 u.ugold 1267#else 1268 umoney 1269#endif 1270 && !Underwater) 1271 disp = 0; 1272 else 1273 disp = 1; 1274 } else if (Displaced) { 1275 disp = couldsee(mx, my) ? 2 : 1; 1276 } else disp = 0; 1277 if (!disp) goto found_you; 1278 1279 /* without something like the following, invis. and displ. 1280 are too powerful */ 1281 gotu = notseen ? !rn2(3) : Displaced ? !rn2(4) : FALSE; 1282 1283#if 0 /* this never worked as intended & isn't needed anyway */ 1284 /* If invis but not displaced, staying around gets you 'discovered' */ 1285 gotu |= (!Displaced && u.dx == 0 && u.dy == 0); 1286#endif 1287 1288 if (!gotu) { 1289 register int try_cnt = 0; 1290 do { 1291 if (++try_cnt > 200) goto found_you; /* punt */ 1292 mx = u.ux - disp + rn2(2*disp+1); 1293 my = u.uy - disp + rn2(2*disp+1); 1294 } while (!isok(mx,my) 1295 || (disp != 2 && mx == mtmp->mx && my == mtmp->my) 1296 || ((mx != u.ux || my != u.uy) && 1297 !passes_walls(mtmp->data) && 1298 (!ACCESSIBLE(levl[mx][my].typ) || 1299 (closed_door(mx, my) && !can_ooze(mtmp)))) 1300 || !couldsee(mx, my)); 1301 } else { 1302found_you: 1303 mx = u.ux; 1304 my = u.uy; 1305 } 1306 1307 mtmp->mux = mx; 1308 mtmp->muy = my; 1309} 1310 1311boolean 1312can_ooze(mtmp) 1313struct monst *mtmp; 1314{ 1315 struct obj *chain, *obj; 1316 1317 if (!amorphous(mtmp->data)) return FALSE; 1318 if (mtmp == &youmonst) { 1319#ifndef GOLDOBJ 1320 if (u.ugold > 100L) return FALSE; 1321#endif 1322 chain = invent; 1323 } else { 1324#ifndef GOLDOBJ 1325 if (mtmp->mgold > 100L) return FALSE; 1326#endif 1327 chain = mtmp->minvent; 1328 } 1329 for (obj = chain; obj; obj = obj->nobj) { 1330 int typ = obj->otyp; 1331 1332#ifdef GOLDOBJ 1333 if (typ == COIN_CLASS && obj->quan > 100L) return FALSE; 1334#endif 1335 if (obj->oclass != GEM_CLASS && 1336 !(typ >= ARROW && typ <= BOOMERANG) && 1337 !(typ >= DAGGER && typ <= CRYSKNIFE) && 1338 typ != SLING && 1339 !is_cloak(obj) && typ != FEDORA && 1340 !is_gloves(obj) && typ != LEATHER_JACKET && 1341#ifdef TOURIST 1342 typ != CREDIT_CARD && !is_shirt(obj) && 1343#endif 1344 !(typ == CORPSE && verysmall(&mons[obj->corpsenm])) && 1345 typ != FORTUNE_COOKIE && typ != CANDY_BAR && 1346 typ != PANCAKE && typ != LEMBAS_WAFER && 1347 typ != LUMP_OF_ROYAL_JELLY && 1348 obj->oclass != AMULET_CLASS && 1349 obj->oclass != RING_CLASS && 1350#ifdef WIZARD 1351 obj->oclass != VENOM_CLASS && 1352#endif 1353 typ != SACK && typ != BAG_OF_HOLDING && 1354 typ != BAG_OF_TRICKS && !Is_candle(obj) && 1355 typ != OILSKIN_SACK && typ != LEASH && 1356 typ != STETHOSCOPE && typ != BLINDFOLD && typ != TOWEL && 1357 typ != TIN_WHISTLE && typ != MAGIC_WHISTLE && 1358 typ != MAGIC_MARKER && typ != TIN_OPENER && 1359 typ != SKELETON_KEY && typ != LOCK_PICK 1360 ) return FALSE; 1361 if (Is_container(obj) && obj->cobj) return FALSE; 1362 1363 } 1364 return TRUE; 1365} 1366 1367#endif /* OVL0 */ 1368 1369/*monmove.c*/ 1370