home *** CD-ROM | disk | FTP | other *** search
- /* SCCS Id: @(#)monmove.c 3.1 92/12/06 */
- /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
- /* NetHack may be freely redistributed. See license for details. */
-
- #include "hack.h"
- #include "mfndpos.h"
- #include "artifact.h"
-
- #ifdef OVL0
-
- static int FDECL(disturb,(struct monst *));
- static void FDECL(distfleeck,(struct monst *,int *,int *,int *));
-
- #endif /* OVL0 */
- #ifdef OVL1
-
- STATIC_OVL boolean FDECL(mdig_tunnel,(struct monst *));
-
- #endif /* OVL1 */
- #ifdef OVLB
-
- boolean /* TRUE : mtmp died */
- mb_trapped(mtmp)
- register struct monst *mtmp;
- {
- if (flags.verbose) {
- if (cansee(mtmp->mx, mtmp->my))
- pline("KABOOM!! You see a door explode.");
- else if (flags.soundok)
- You("hear a distant explosion.");
- }
- mtmp->mstun = 1;
- mtmp->mhp -= rnd(15);
- if(mtmp->mhp <= 0) {
- mondied(mtmp);
- return(TRUE);
- }
- return(FALSE);
- }
-
- #endif /* OVLB */
- #ifdef OVL1
-
- /* Return TRUE if monster died, FALSE otherwise. */
- STATIC_OVL boolean
- mdig_tunnel(mtmp)
- register struct monst *mtmp;
- {
- register struct rm *here;
- register int pile;
-
- here = &levl[mtmp->mx][mtmp->my];
- if (here->typ == SDOOR) here->typ = DOOR;
-
- /* Eats away door if present & closed or locked */
- if(closed_door(mtmp->mx, mtmp->my)) {
- if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE))
- add_damage(mtmp->mx, mtmp->my, 0L);
- unblock_point(mtmp->mx,mtmp->my); /* vision */
- if(here->doormask & D_TRAPPED) {
- here->doormask = D_NODOOR;
- if(mb_trapped(mtmp)) { /* mtmp is killed */
- newsym(mtmp->mx,mtmp->my);
- return TRUE;
- }
- } else {
- if(!rn2(3) && flags.verbose) /* not too often.. */
- You("feel an unexpected draft of air.");
- here->doormask = D_BROKEN;
- }
- newsym(mtmp->mx,mtmp->my);
- return FALSE;
- } else
- if (!IS_ROCK(here->typ)) /* no dig */
- return(FALSE);
-
- /* Only rock and walls fall through to this point. */
- if ((here->diggable & W_NONDIGGABLE)) {
- impossible("mdig_tunnel: %s at (%d,%d) is undiggable",
- (IS_WALL(here->typ) ? "wall" : "stone"),
- (int) mtmp->mx, (int) mtmp->my);
- return FALSE; /* still alive */
- }
-
- if(IS_WALL(here->typ)) {
- if(flags.soundok && flags.verbose && !rn2(5))
- You("hear the sound of crashing rock.");
- if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE))
- add_damage(mtmp->mx, mtmp->my, 0L);
- if (level.flags.is_maze_lev) {
- here->typ = ROOM;
- } else if (level.flags.is_cavernous_lev) {
- here->typ = CORR;
- } else {
- here->typ = DOOR;
- here->doormask = D_NODOOR;
- }
- } else
- here->typ = CORR;
-
- pile = rnd(12);
- if(pile < 5) /* leave behind some rocks? */
- (void) mksobj_at((pile == 1)? BOULDER : ROCK,
- mtmp->mx, mtmp->my, TRUE);
- newsym(mtmp->mx,mtmp->my);
- if(sobj_at(BOULDER, mtmp->mx, mtmp->my) == (struct obj *)0)
- unblock_point(mtmp->mx,mtmp->my); /* vision */
- return FALSE ;
- }
-
- int
- dochugw(mtmp)
- register struct monst *mtmp;
- {
- register int x = mtmp->mx;
- register int y = mtmp->my;
- register int rd = dochug(mtmp);
- register int dd;
-
- if(Warning && !rd && !mtmp->mpeaceful &&
- (dd = distu(mtmp->mx,mtmp->my)) < distu(x,y) &&
- dd < 100 && !canseemon(mtmp)) {
- /* Note: this assumes we only want to warn against the monster to
- * which the weapon does extra damage, as there is no "monster
- * which the weapon warns against" field.
- */
- if(spec_ability(uwep,SPFX_WARN) && spec_dbon(uwep,mtmp->data,1))
- warnlevel = 100;
- else if ((int) (mtmp->m_lev / 4) > warnlevel)
- warnlevel = (mtmp->m_lev / 4);
- }
- /* check whether hero notices monster and stops current activity */
- if (occupation && !rd && !Confusion &&
- (!mtmp->mpeaceful || Hallucination) &&
- canseemon(mtmp) && !cansee(x,y) &&
- distu(mtmp->mx,mtmp->my) <= (BOLT_LIM+1)*(BOLT_LIM+1))
- stop_occupation();
-
- return(rd);
- }
-
- #endif /* OVL1 */
- #ifdef OVL2
-
- boolean
- onscary(x, y, mtmp)
- int x, y;
- struct monst *mtmp;
- {
- if (mtmp->isshk || mtmp->isgd || mtmp->iswiz || !mtmp->mcansee ||
- is_lminion(mtmp->data) || is_rider(mtmp->data) ||
- mtmp->data->mlet == S_HUMAN || mtmp->mpeaceful ||
- mtmp->data == &mons[PM_MINOTAUR])
- return(FALSE);
- return(
- #ifdef ELBERETH
- sengr_at("Elbereth", x, y) ||
- #endif
- sobj_at(SCR_SCARE_MONSTER, x, y) != (struct obj *)0);
- }
-
- #endif /* OVL2 */
- #ifdef OVL0
-
- /*
- * Possibly awaken the given monster. Return a 1 if the monster has been
- * jolted awake.
- */
- static int
- disturb(mtmp)
- register struct monst *mtmp;
- {
- /*
- * + Ettins are hard to surprise.
- * + Nymphs, jabberwocks, and leprechauns do not easily wake up.
- *
- * Wake up if:
- * in direct LOS AND
- * within 10 squares AND
- * not stealthy or (mon is an ettin and 9/10) AND
- * (mon is not a nymph, jabberwock, or leprechaun) or 1/50 AND
- * Aggravate or mon is (dog or human) or
- * (1/7 and mon is not mimicing furniture or object)
- */
- if(couldsee(mtmp->mx,mtmp->my) &&
- distu(mtmp->mx,mtmp->my) <= 100 &&
- (!Stealth || (mtmp->data == &mons[PM_ETTIN] && rn2(10))) &&
- (!(mtmp->data->mlet == S_NYMPH
- || mtmp->data == &mons[PM_JABBERWOCK]
- || mtmp->data->mlet == S_LEPRECHAUN) || !rn2(50)) &&
- (Aggravate_monster
- || (mtmp->data->mlet == S_DOG ||
- mtmp->data->mlet == S_HUMAN)
- || (!rn2(7) && mtmp->m_ap_type != M_AP_FURNITURE &&
- mtmp->m_ap_type != M_AP_OBJECT) )) {
-
- mtmp->msleep = 0;
- return(1);
- }
- return(0);
- }
-
- static void
- distfleeck(mtmp,inrange,nearby,scared)
- register struct monst *mtmp;
- int *inrange, *nearby, *scared;
- {
- int seescaryx, seescaryy;
-
- *inrange = (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <=
- (BOLT_LIM * BOLT_LIM));
- *nearby = *inrange && monnear(mtmp, mtmp->mux, mtmp->muy);
-
- /* Note: if your image is displaced, the monster sees the Elbereth
- * at your displaced position, thus never attacking your displaced
- * position, but possibly attacking you by accident. If you are
- * invisible, it sees the Elbereth at your real position, thus never
- * running into you by accident but possibly attacking the spot
- * where it guesses you are.
- */
- if (Invis && !perceives(mtmp->data)) {
- seescaryx = mtmp->mux;
- seescaryy = mtmp->muy;
- } else {
- seescaryx = u.ux;
- seescaryy = u.uy;
- }
- *scared = (*nearby && (onscary(seescaryx, seescaryy, mtmp) ||
- (!mtmp->mpeaceful &&
- in_your_sanctuary(mtmp->mx, mtmp->my))));
-
- if(*scared && !mtmp->mflee) {
- #ifdef POLYSELF
- if (!sticks(uasmon))
- #endif
- unstuck(mtmp); /* monster lets go when fleeing */
- mtmp->mflee = 1;
- #ifdef STUPID
- if (rn2(7))
- mtmp->mfleetim = rnd(10);
- else
- mtmp->mfleetim = rnd(100);
- #else
- mtmp->mfleetim = rnd(rn2(7) ? 10 : 100);
- #endif
- }
-
- }
-
- /* returns 1 if monster died moving, 0 otherwise */
- /* The whole dochugw/m_move/distfleeck/mfndpos section is serious spaghetti
- * code. --KAA
- */
- int
- dochug(mtmp)
- register struct monst *mtmp;
- {
- register struct permonst *mdat = mtmp->data;
- register int tmp=0;
- int inrange, nearby, scared;
-
- /* Pre-movement adjustments */
-
- if(mtmp->cham && !rn2(6)) /* polymorph chameleons */
- (void) newcham(mtmp, (struct permonst *)0);
-
- /* regenerate monsters */
- if (mtmp->mhp < mtmp->mhpmax && (!(moves%20) || regenerates(mdat)))
- mtmp->mhp++;
- if(mtmp->mspec_used) mtmp->mspec_used--;
-
- /* polymorph lycanthropes */
- were_change(mtmp);
-
- /* check for waitmask status change */
- if((mtmp->data->mflags3 & M3_WAITFORU) &&
- (m_canseeu(mtmp) || mtmp->mhp < mtmp->mhpmax))
- mtmp->data->mflags3 &= ~M3_WAITFORU;
-
- #ifdef MULDGN
- /* update quest status flags */
- quest_stat_check(mtmp);
- #endif
-
- if(!mtmp->mcanmove || (mtmp->data->mflags3 & M3_WAITMASK)) {
- if (Hallucination) newsym(mtmp->mx,mtmp->my);
- #ifdef MULDGN
- if(mtmp->mcanmove && (mtmp->data->mflags3 & M3_CLOSE) &&
- !mtmp->msleep && monnear(mtmp, u.ux, u.uy))
- quest_talk(mtmp); /* give the leaders a chance to speak */
- #endif
- return(0); /* other frozen monsters can't do anything */
- }
-
- /* there is a chance we will wake it */
- if(mtmp->msleep && !disturb(mtmp)) {
- if (Hallucination) newsym(mtmp->mx,mtmp->my);
- return(0);
- }
-
- /* not frozen or sleeping: wipe out texts written in the dust */
- wipe_engr_at(mtmp->mx, mtmp->my, 1);
-
- /* confused monsters get unconfused with small probability */
- if(mtmp->mconf && !rn2(50)) mtmp->mconf = 0;
-
- /* stunned monsters get un-stunned with larger probability */
- if(mtmp->mstun && !rn2(10)) mtmp->mstun = 0;
-
- /* some monsters teleport */
- if(mtmp->mflee && !rn2(40) && can_teleport(mdat) && !mtmp->iswiz) {
- rloc(mtmp);
- return(0);
- }
- if(mdat->msound == MS_SHRIEK && !um_dist(mtmp->mx, mtmp->my, 1))
- m_respond(mtmp);
- if(mdat->mmove < rnd(6)) return(0);
-
- /* fleeing monsters might regain courage */
- if(mtmp->mflee && !mtmp->mfleetim
- && mtmp->mhp == mtmp->mhpmax && !rn2(25)) mtmp->mflee = 0;
-
- set_apparxy(mtmp);
- /* Must be done after you move and before the monster does. The
- * set_apparxy() call in m_move() doesn't suffice since the variables
- * inrange, etc. all depend on stuff set by set_apparxy().
- */
-
- /* Monsters that want to acquire things */
- /* may teleport, so do it before inrange is set */
- if(is_covetous(mtmp->data)) (void) tactics(mtmp);
-
- /* check distance and scariness of attacks */
- distfleeck(mtmp,&inrange,&nearby,&scared);
-
- #ifdef MUSE
- if(find_defensive(mtmp)) {
- if (use_defensive(mtmp) != 0)
- return 1;
- } else if(find_misc(mtmp)) {
- if (use_misc(mtmp) != 0)
- return 1;
- }
- #endif
-
- /* Demonic Blackmail! */
- if(nearby && mdat->msound == MS_BRIBE &&
- mtmp->mpeaceful && !mtmp->mtame) {
- if (mtmp->mux != u.ux || mtmp->muy != u.uy) {
- pline("%s whispers something to thin air.",
- cansee(mtmp->mux, mtmp->muy) ? Monnam(mtmp) : "It");
- #ifdef POLYSELF
- if (is_demon(uasmon)) rloc(mtmp);
- /* "Good hunting, brother" */
- else {
- #endif
- mtmp->minvis = 0;
- /* Why? For the same reason in real demon talk */
- pline("%s gets angry.", Amonnam(mtmp));
- mtmp->mpeaceful = 0;
- /* since no way is an image going to pay it off */
- #ifdef POLYSELF
- }
- #endif
- } else if(demon_talk(mtmp)) return(1); /* you paid it off */
- }
-
- if (mdat == &mons[PM_MIND_FLAYER] && !rn2(20)) {
- struct monst *m2, *nmon = (struct monst *)0;
-
- if (canseemon(mtmp))
- pline("%s concentrates.", Monnam(mtmp));
- if (distu(mtmp->mx, mtmp->my) > BOLT_LIM * BOLT_LIM) {
- You("sense a faint wave of psychic energy.");
- goto toofar;
- }
- You("sense a wave of psychic energy pouring over you!");
- if (mtmp->mpeaceful &&
- (!Conflict || resist(mtmp, RING_CLASS, 0, 0)))
- pline("It seems quite soothing.");
- else {
- register boolean m_sen = sensemon(mtmp);
-
- if (m_sen || (Telepat && rn2(2)) || !rn2(10)) {
- int dmg;
- pline("It locks in on your %s!",
- m_sen ? "telepathy" :
- Telepat ? "latent telepathy" : "mind");
- dmg = rnd(15);
- if (Half_spell_damage) dmg = (dmg+1) / 2;
- losehp(dmg, "psychic blast", KILLED_BY_AN);
- }
- }
- for(m2=fmon; m2; m2 = nmon) {
- nmon = m2->nmon;
- if (m2->mpeaceful != mtmp->mpeaceful) continue;
- if (mindless(m2->data)) continue;
- if (m2 == mtmp) continue;
- if ((telepathic(m2->data) &&
- (rn2(2) || m2->mblinded)) || !rn2(10)) {
- if (cansee(m2->mx, m2->my))
- pline("It locks in on %s.", mon_nam(m2));
- m2->mhp -= rnd(15);
- if (m2->mhp <= 0)
- monkilled(m2, "", AD_DRIN);
- }
- }
- }
- toofar:
- #ifdef MUSE
- /* If monster is nearby you, and has to wield a weapon, do so. This
- * costs the monster a move, of course.
- */
- if((!mtmp->mpeaceful || Conflict) && inrange &&
- dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 8
- && attacktype(mdat, AT_WEAP)) {
- if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
- mtmp->weapon_check = NEED_HTH_WEAPON;
- if (mon_wield_item(mtmp) != 0) return(0);
- }
- }
- #endif
- /* Now the actual movement phase */
-
- if(!nearby || mtmp->mflee || scared ||
- mtmp->mconf || mtmp->mstun || (mtmp->minvis && !rn2(3)) ||
- (mdat->mlet == S_LEPRECHAUN && !u.ugold && (mtmp->mgold || rn2(2))) ||
- (is_wanderer(mdat) && !rn2(4)) || (Conflict && !mtmp->iswiz) ||
- (!mtmp->mcansee && !rn2(4)) || mtmp->mpeaceful) {
-
- tmp = m_move(mtmp, 0);
- distfleeck(mtmp,&inrange,&nearby,&scared); /* recalc */
-
- switch (tmp) {
-
- case 0: /* no movement, but it can still attack you */
- case 3: /* absolutely no movement */
- /* for pets, case 0 and 3 are equivalent */
- /* During hallucination, monster appearance should
- * still change - even if it doesn't move.
- */
- if(Hallucination) newsym(mtmp->mx,mtmp->my);
- break;
- case 1: /* monster moved */
- /* Maybe it stepped on a trap and fell asleep... */
- if(mtmp->msleep || !mtmp->mcanmove) return(0);
- if(!nearby && ranged_attk(mdat)) break;
- else if(mdat->mmove <= 12) {
- /* a monster that's digesting you can move at the
- * same time -dlc
- */
- if(u.uswallow && mtmp == u.ustuck)
- return(mattacku(mtmp));
- return(0);
- }
- break;
- case 2: /* monster died */
- return(1);
- }
- }
-
- /* Now, attack the player if possible - one attack set per monst */
-
- if (!mtmp->mpeaceful ||
- (Conflict && !resist(mtmp, RING_CLASS, 0, 0))) {
- if(inrange && !noattacks(mdat) && u.uhp > 0 && !scared && tmp != 3)
- if(mattacku(mtmp)) return(1); /* monster died (e.g. exploded) */
-
- if(mtmp->wormno) wormhitu(mtmp);
- }
- #ifdef MULDGN
- /* special speeches for quest monsters */
- if(!mtmp->msleep && mtmp->mcanmove && nearby)
- quest_talk(mtmp);
- else
- #endif
- /* extra emotional attack for vile monsters */
- if(inrange && mtmp->data->msound == MS_CUSS && !mtmp->mpeaceful &&
- couldsee(mtmp->mx, mtmp->my) && !mtmp->minvis && !rn2(5))
- cuss(mtmp);
-
- /* extra movement for fast monsters */
- if(mdat->mmove-12 > rnd(12)) tmp = m_move(mtmp, 1);
- return(tmp == 2);
- }
-
- static const char NEARDATA practical[] = { WEAPON_CLASS, ARMOR_CLASS, GEM_CLASS, FOOD_CLASS, 0 };
- static const char NEARDATA magical[] = {
- AMULET_CLASS, POTION_CLASS, SCROLL_CLASS, WAND_CLASS, RING_CLASS,
- SPBOOK_CLASS, 0 };
- static const char NEARDATA indigestion[] = { BALL_CLASS, ROCK_CLASS, 0 };
-
- #ifdef POLYSELF
- boolean
- itsstuck(mtmp)
- register struct monst *mtmp;
- {
- if (sticks(uasmon) && mtmp==u.ustuck && !u.uswallow) {
- pline("%s cannot escape from you!", Monnam(mtmp));
- return(TRUE);
- }
- return(FALSE);
- }
- #endif
-
- int
- m_move(mtmp, after)
- register struct monst *mtmp;
- register int after;
- {
- register int appr;
- xchar gx,gy,nix,niy,chcnt;
- int chi; /* could be schar except for stupid Sun-2 compiler */
- boolean likegold=0, likegems=0, likeobjs=0, likemagic=0, conceals=0;
- boolean likerock=0, can_tunnel=0;
- boolean can_open=0, can_unlock=0, doorbuster=0;
- #ifdef MUSE
- boolean uses_items=0;
- #endif
- struct permonst *ptr;
- schar mmoved = 0; /* not strictly nec.: chi >= 0 will do */
- long info[9];
- long flag;
- int omx = mtmp->mx, omy = mtmp->my;
- #ifdef MUSE
- struct obj *mw_tmp;
- #endif
-
- if(mtmp->mtrapped) {
- int i = mintrap(mtmp);
- if(i >= 2) { newsym(mtmp->mx,mtmp->my); return(2); }/* it died */
- if(i == 1) return(0); /* still in trap, so didn't move */
- }
- ptr = mtmp->data; /* mintrap() can change mtmp->data -dlc */
- if(hides_under(ptr) && OBJ_AT(mtmp->mx, mtmp->my) && rn2(10))
- return(0); /* do not leave hiding place */
- if(mtmp->meating) {
- mtmp->meating--;
- return(3); /* still eating */
- }
-
- set_apparxy(mtmp);
- /* where does mtmp think you are? */
- /* Not necessary if m_move called from this file, but necessary in
- * other calls of m_move (ex. leprechauns dodging)
- */
- can_tunnel = tunnels(ptr) &&
- #ifdef REINCARNATION
- !Is_rogue_level(&u.uz) &&
- #endif
- #ifdef MUSE
- (!needspick(ptr) ||
- (m_carrying(mtmp, PICK_AXE) &&
- (mtmp->weapon_check != NO_WEAPON_WANTED ||
- !(mw_tmp = MON_WEP(mtmp)) || mw_tmp->otyp == PICK_AXE)));
- #else
- (!needspick(ptr) || m_carrying(mtmp, PICK_AXE));
- #endif
- can_open = !(nohands(ptr) || verysmall(ptr));
- can_unlock = ((can_open && m_carrying(mtmp, SKELETON_KEY)) || mtmp->iswiz);
- doorbuster = is_giant(ptr);
- if(mtmp->wormno) goto not_special;
- /* my dog gets special treatment */
- if(mtmp->mtame) {
- mmoved = dog_move(mtmp, after);
- goto postmov;
- }
-
- /* likewise for shopkeeper */
- if(mtmp->isshk) {
- mmoved = shk_move(mtmp);
- if(mmoved == -2) return(2);
- if(mmoved >= 0) goto postmov;
- mmoved = 0; /* follow player outside shop */
- }
-
- /* and for the guard */
- if(mtmp->isgd) {
- mmoved = gd_move(mtmp);
- if(mmoved == -2) return(2);
- if(mmoved >= 0) goto postmov;
- mmoved = 0;
- }
-
- /* and the acquisitive monsters get special treatment */
- if(is_covetous(ptr)) {
- xchar tx = (xchar)((mtmp->mstrategy >> 16) & 0xff),
- ty = (xchar)((mtmp->mstrategy >> 8) & 0xff);
- struct monst *intruder = m_at(tx, ty);
- /*
- * if there's a monster on the object or in possesion of it,
- * attack it.
- */
- if((dist2(mtmp->mx, mtmp->my, tx, ty) < 2) &&
- intruder && (intruder != mtmp)) {
-
- if(mattackm(mtmp, intruder) == 2) return(2);
- mmoved = 1;
- } else mmoved = 0;
- goto postmov;
- }
-
- /* and for the priest */
- if(mtmp->ispriest) {
- mmoved = pri_move(mtmp);
- if(mmoved == -2) return(2);
- if(mmoved >= 0) goto postmov;
- mmoved = 0;
- }
-
- #ifdef MAIL
- if(ptr == &mons[PM_MAIL_DAEMON]) {
- if(flags.soundok && canseemon(mtmp))
- verbalize("I'm late!");
- mongone(mtmp);
- return(2);
- }
- #endif
-
- /* teleport if that lies in our nature */
- if(ptr == &mons[PM_TENGU] && !rn2(5) && !mtmp->mcan) {
- if(mtmp->mhp < 7 || mtmp->mpeaceful || rn2(2))
- rloc(mtmp);
- else
- mnexto(mtmp);
- mmoved = 1;
- goto postmov;
- }
- not_special:
- if(u.uswallow && !mtmp->mflee && u.ustuck != mtmp) return(1);
- appr = 1;
- omx = mtmp->mx;
- omy = mtmp->my;
- gx = mtmp->mux;
- gy = mtmp->muy;
- if(mtmp->mflee) appr = -1;
- if (mtmp->mconf || (u.uswallow && mtmp == u.ustuck))
- appr = 0;
- else {
- boolean should_see = (couldsee(omx, omy) &&
- (levl[gx][gy].lit ||
- !levl[omx][omy].lit) &&
- (dist2(omx, omy, gx, gy) <= 36));
-
- if (!mtmp->mcansee ||
- (should_see && Invis && !perceives(ptr)) ||
- #ifdef POLYSELF
- (u.usym == S_MIMIC_DEF) || u.uundetected ||
- #endif
- (mtmp->mpeaceful && !mtmp->isshk) || /* allow shks to follow */
- ((ptr->mlet == S_STALKER || ptr->mlet == S_BAT ||
- ptr->mlet == S_LIGHT) && !rn2(3)))
- appr = 0;
-
- if(monsndx(ptr) == PM_LEPRECHAUN && (appr == 1) &&
- (mtmp->mgold > u.ugold))
- appr = -1;
-
- if (!should_see && can_track(ptr)) {
- register coord *cp;
-
- cp = gettrack(omx,omy);
- if (cp) {
- gx = cp->x;
- gy = cp->y;
- }
- }
- }
-
- #ifdef REINCARNATION
- if (!Is_rogue_level(&u.uz))
- #endif
- {
- register int pctload = (curr_mon_load(mtmp) * 100) /
- max_mon_load(mtmp);
-
- /* look for gold or jewels nearby */
- likegold = (likes_gold(ptr) && pctload < 95);
- likegems = (likes_gems(ptr) && pctload < 85);
- #ifdef MUSE
- uses_items = (!mindless(ptr) && !is_animal(ptr)
- && pctload < 75);
- #endif
- likeobjs = (likes_objs(ptr) && pctload < 75);
- likemagic = (likes_magic(ptr) && pctload < 85);
- likerock = (throws_rocks(ptr) && pctload < 50);
- conceals = hides_under(ptr);
- }
-
- #define SQSRCHRADIUS 5
-
- { register int minr = SQSRCHRADIUS; /* not too far away */
- register struct obj *otmp;
- register int xx, yy;
- int oomx, oomy, lmx, lmy;
-
- /* cut down the search radius if it thinks character is closer. */
- if(distmin(mtmp->mux, mtmp->muy, omx, omy) < SQSRCHRADIUS &&
- !mtmp->mpeaceful) minr--;
- /* guards shouldn't get too distracted */
- if(!mtmp->mpeaceful && is_mercenary(ptr)) minr = 1;
-
- if((likegold || likegems || likeobjs || likemagic || likerock || conceals)
- && (!*in_rooms(omx, omy, SHOPBASE) || (!rn2(25) && !mtmp->isshk))) {
- look_for_obj:
- oomx = min(COLNO-1, omx+minr);
- oomy = min(ROWNO-1, omy+minr);
- lmx = max(1, omx-minr);
- lmy = max(0, omy-minr);
- for(otmp = fobj; otmp; otmp = otmp->nobj) {
- xx = otmp->ox;
- yy = otmp->oy;
- if(xx >= lmx && xx <= oomx && yy >= lmy && yy <= oomy) {
- if(((likegold && otmp->otyp == GOLD_PIECE) ||
- (likeobjs && index(practical, otmp->oclass)) ||
- (likemagic && index(magical, otmp->oclass)) ||
- #ifdef MUSE
- (uses_items && searches_for_item(mtmp, otmp)) ||
- #endif
- (likerock && otmp->otyp == BOULDER) ||
- (likegems && otmp->oclass == GEM_CLASS &&
- objects[otmp->otyp].oc_material != MINERAL) ||
- (conceals && !cansee(otmp->ox,otmp->oy)) ||
- (ptr == &mons[PM_GELATINOUS_CUBE] &&
- !index(indigestion, otmp->oclass) &&
- !(otmp->otyp == CORPSE &&
- otmp->corpsenm == PM_COCKATRICE))
- ) && touch_artifact(otmp,mtmp)) {
- if(can_carry(mtmp,otmp) &&
- (throws_rocks(ptr) ||
- !sobj_at(BOULDER,xx,yy)) &&
- (ptr->mlet != S_UNICORN ||
- objects[otmp->otyp].oc_material == GEMSTONE)) {
- minr = distmin(omx,omy,xx,yy);
- oomx = min(COLNO-1, omx+minr);
- oomy = min(ROWNO-1, omy+minr);
- lmx = max(1, omx-minr);
- lmy = max(0, omy-minr);
- gx = otmp->ox;
- gy = otmp->oy;
- }
- }
- }
- }
- } else if(likegold) {
- /* don't try to pick up anything else, but use the same loop */
- #ifdef MUSE
- uses_items =
- #endif
- likegems = likeobjs = likemagic = likerock = conceals = 0;
- goto look_for_obj;
- }
-
- if(minr < SQSRCHRADIUS && appr == -1) {
- if(distmin(omx,omy,mtmp->mux,mtmp->muy) <= 3) {
- gx = mtmp->mux;
- gy = mtmp->muy;
- } else
- appr = 1;
- }
- }
- nix = omx;
- niy = omy;
- flag = ALLOW_TRAPS;
- if (mtmp->mpeaceful && (!Conflict || resist(mtmp, RING_CLASS, 0, 0)))
- flag |= (ALLOW_SANCT | ALLOW_SSM);
- else flag |= ALLOW_U;
- if (ptr->mlet == S_UNICORN) flag |= NOTONL;
- if (passes_walls(ptr)) flag |= (ALLOW_WALL | ALLOW_ROCK);
- if (can_tunnel) flag |= ALLOW_DIG;
- if (is_human(ptr) || ptr == &mons[PM_MINOTAUR]) flag |= ALLOW_SSM;
- if (is_undead(ptr)) flag |= NOGARLIC;
- if (throws_rocks(ptr)) flag |= ALLOW_ROCK;
- if (can_open) flag |= OPENDOOR;
- if (can_unlock) flag |= UNLOCKDOOR;
- if (doorbuster) flag |= BUSTDOOR;
- {
- register int i, j, nx, ny, nearer;
- int jcnt, cnt;
- int ndist, nidist;
- register coord *mtrk;
- coord poss[9];
-
- cnt = mfndpos(mtmp, poss, info, flag);
- chcnt = 0;
- jcnt = min(MTSZ, cnt-1);
- chi = -1;
- nidist = dist2(nix,niy,gx,gy);
- /* allow monsters be shortsighted on some levels for balance */
- if(!mtmp->mpeaceful && level.flags.shortsighted &&
- nidist > (couldsee(nix,niy) ? 144 : 36) && appr == 1) appr = 0;
-
- for(i=0; i < cnt; i++) {
- nx = poss[i].x;
- ny = poss[i].y;
-
- if (appr != 0) {
- mtrk = &mtmp->mtrack[0];
- for(j=0; j < jcnt; mtrk++, j++)
- if(nx == mtrk->x && ny == mtrk->y)
- if(rn2(4*(cnt-j)))
- goto nxti;
- }
-
- nearer = ((ndist = dist2(nx,ny,gx,gy)) < nidist);
-
- if((appr == 1 && nearer) || (appr == -1 && !nearer) ||
- (!appr && !rn2(++chcnt)) || !mmoved) {
- nix = nx;
- niy = ny;
- nidist = ndist;
- chi = i;
- mmoved = 1;
- }
- nxti: ;
- }
- }
-
- if(mmoved) {
- register int j;
- #ifdef POLYSELF
- if (mmoved==1 && (u.ux != nix || u.uy != niy) && itsstuck(mtmp))
- return(3);
- #endif
- #ifdef MUSE
- if (mmoved==1 && can_tunnel && needspick(ptr) &&
- (!(mw_tmp = MON_WEP(mtmp)) || mw_tmp->otyp != PICK_AXE)) {
- mtmp->weapon_check = NEED_PICK_AXE;
- (void)mon_wield_item(mtmp);
- }
- #endif
- /* If ALLOW_U is set, either it's trying to attack you, or it
- * thinks it is. In either case, attack this spot in preference to
- * all others.
- */
- if(info[chi] & ALLOW_U) {
- nix = mtmp->mux;
- niy = mtmp->muy;
- }
- if (nix == u.ux && niy == u.uy) {
- mtmp->mux = u.ux;
- mtmp->muy = u.uy;
- return(0);
- }
- /* The monster may attack another based on 1 of 2 conditions:
- * 1 - It may be confused.
- * 2 - It may mistake the monster for your (displaced) image.
- * Pets get taken care of above and shouldn't reach this code.
- * Conflict gets handled even farther away (movemon()).
- */
- if((info[chi] & ALLOW_M) ||
- (nix == mtmp->mux && niy == mtmp->muy)) {
- struct monst *mtmp2;
- int stat;
- mtmp2 = m_at(nix,niy);
-
- stat = mattackm(mtmp, mtmp2);
-
- if (stat & MM_AGR_DIED) /* aggressor died */
- return 2;
-
- if ((stat & MM_HIT) && !(stat & MM_DEF_DIED) &&
- rn2(4) && mtmp2->mlstmv != monstermoves) {
- stat = mattackm(mtmp2, mtmp); /* return attack */
- if (stat & MM_DEF_DIED)
- return 2;
- }
- return 3;
- }
-
- remove_monster(omx, omy);
- place_monster(mtmp, nix, niy);
- for(j = MTSZ-1; j > 0; j--)
- mtmp->mtrack[j] = mtmp->mtrack[j-1];
- mtmp->mtrack[0].x = omx;
- mtmp->mtrack[0].y = omy;
- /* Place a segment at the old position. */
- if (mtmp->wormno) worm_move(mtmp);
- } else {
- if(ptr->mlet == S_UNICORN && rn2(2)) {
- rloc(mtmp);
- return(1);
- }
- if(mtmp->wormno) worm_nomove(mtmp);
- }
- postmov:
- if(mmoved == 1) {
- boolean canseeit = cansee(mtmp->mx, mtmp->my);
- boolean abstain = (mtmp->mpeaceful && !mtmp->mtame);
-
- newsym(omx,omy); /* update the old position */
- if (mintrap(mtmp) >= 2) {
- if(mtmp->mx) newsym(mtmp->mx,mtmp->my);
- return(2); /* it died */
- }
- ptr = mtmp->data;
-
- /* open a door, or crash through it, if you can */
- if(IS_DOOR(levl[mtmp->mx][mtmp->my].typ)
- && !passes_walls(ptr) /* doesn't need to open doors */
- && !can_tunnel /* taken care of below */
- ) {
- struct rm *here = &levl[mtmp->mx][mtmp->my];
- boolean btrapped = (here->doormask & D_TRAPPED);
-
- if(here->doormask & (D_LOCKED|D_CLOSED) && amorphous(ptr)) {
- if (flags.verbose && canseeit)
- pline("%s %ss under the door.", Monnam(mtmp),
- (ptr == &mons[PM_FOG_CLOUD] ||
- ptr == &mons[PM_YELLOW_LIGHT])
- ? "flow" : "ooze");
- } else if(here->doormask & D_LOCKED && can_unlock) {
- if(btrapped) {
- here->doormask = D_NODOOR;
- newsym(mtmp->mx, mtmp->my);
- unblock_point(mtmp->mx,mtmp->my); /* vision */
- if(mb_trapped(mtmp)) return(2);
- } else {
- if (flags.verbose) {
- if (canseeit)
- You("see a door being unlocked and opened.");
- else if (flags.soundok)
- You("hear a door being unlocked and opened.");
- }
- here->doormask = D_ISOPEN;
- /* newsym(mtmp->mx, mtmp->my); */
- unblock_point(mtmp->mx,mtmp->my); /* vision */
- }
- } else if (here->doormask == D_CLOSED && can_open) {
- if(btrapped) {
- here->doormask = D_NODOOR;
- newsym(mtmp->mx, mtmp->my);
- unblock_point(mtmp->mx,mtmp->my); /* vision */
- if(mb_trapped(mtmp)) return(2);
- } else {
- if (flags.verbose) {
- if (canseeit)
- You("see a door being opened.");
- else if (flags.soundok)
- You("hear the sound of a door opening.");
- }
- here->doormask = D_ISOPEN;
- /* newsym(mtmp->mx, mtmp->my); */ /* done below */
- unblock_point(mtmp->mx,mtmp->my); /* vision */
- }
- } else if (here->doormask & (D_LOCKED|D_CLOSED)) {
- /* mfndpos guarantees this must be a doorbuster */
- if(btrapped) {
- here->doormask = D_NODOOR;
- newsym(mtmp->mx, mtmp->my);
- unblock_point(mtmp->mx,mtmp->my); /* vision */
- if(mb_trapped(mtmp)) return(2);
- } else {
- if (flags.verbose) {
- if (canseeit)
- You("see a door crash open.");
- else if (flags.soundok)
- You("hear the sound of a door crashing open.");
- }
- if (here->doormask & D_LOCKED && !rn2(2))
- here->doormask = D_NODOOR;
- else here->doormask = D_BROKEN;
- /* newsym(mtmp->mx, mtmp->my); */ /* done below */
- unblock_point(mtmp->mx,mtmp->my); /* vision */
- }
- }
- }
-
- /* possibly dig */
- if (can_tunnel && mdig_tunnel(mtmp))
- return(2); /* mon died (position already updated) */
-
- /* set also in domove(), hack.c */
- if (u.uswallow && mtmp == u.ustuck &&
- (mtmp->mx != omx || mtmp->my != omy)) {
- /* If the monster moved, then update */
- u.ux0 = u.ux;
- u.uy0 = u.uy;
- u.ux = mtmp->mx;
- u.uy = mtmp->my;
- swallowed(0);
- } else
- newsym(mtmp->mx,mtmp->my);
-
- if(OBJ_AT(mtmp->mx, mtmp->my) && mtmp->mcanmove) {
- /* Maybe a rock mole just ate some metal object */
- if(metallivorous(ptr)) meatgold(mtmp);
-
- if(g_at(mtmp->mx,mtmp->my) && likegold &&
- (!abstain || !rn2(10))) mpickgold(mtmp);
-
- /* Maybe a cube ate just about anything */
- if(ptr == &mons[PM_GELATINOUS_CUBE]) meatobj(mtmp);
-
- if((!abstain || !rn2(10)) &&
- (!*in_rooms(mtmp->mx, mtmp->my, SHOPBASE) || !rn2(25))) {
- if(likeobjs) mpickstuff(mtmp, practical);
- if(likemagic) mpickstuff(mtmp, magical);
- if(likerock || likegems) mpickgems(mtmp);
- #ifdef MUSE
- if(uses_items) mpickstuff(mtmp, (char *)0);
- #endif
- }
-
- if(mtmp->minvis) {
- newsym(mtmp->mx, mtmp->my);
- if (mtmp->wormno) see_wsegs(mtmp);
- }
- }
-
- if(hides_under(ptr)) {
- mtmp->mundetected = OBJ_AT(mtmp->mx, mtmp->my);
- newsym(mtmp->mx, mtmp->my);
- }
- }
- return(mmoved);
- }
-
- #endif /* OVL0 */
- #ifdef OVL2
-
- boolean
- closed_door(x, y)
- register int x, y;
- {
- return(IS_DOOR(levl[x][y].typ) &&
- (levl[x][y].doormask & (D_LOCKED | D_CLOSED)));
- }
-
- boolean
- accessible(x, y)
- register int x, y;
- {
- return(ACCESSIBLE(levl[x][y].typ) && !closed_door(x, y));
- }
-
- #endif /* OVL2 */
- #ifdef OVL0
-
- void
- set_apparxy(mtmp) /* where does mtmp think you are standing? */
- register struct monst *mtmp;
- {
- #define notseen (Invis && !perceives(mtmp->data))
- /* add cases as required. eg. Displacement ... */
- register int disp = (Underwater ? 3 : notseen ? 1 : Displaced ? 2 : 0);
-
- /* without something like the following, invis. and displ. are too */
- /* powerful. */
- register boolean gotu =
- (notseen ? !rn2(3) : Displaced ? !rn2(4) : FALSE);
-
- /* Monsters which know where you are don't suddenly forget, if you
- didn't move away. */
- if (mtmp->mux==u.ux && mtmp->muy==u.uy) gotu = 1;
-
- /* your dog follows your smell */
- if(!disp || mtmp->mtame || gotu ||
- /* Monsters touching you know where you are */
- mtmp == u.ustuck ||
- /* If invisible but not displaced, staying around gets you 'discovered' */
- (!Displaced && u.dx == 0 && u.dy == 0)) {
- mtmp->mux = u.ux;
- mtmp->muy = u.uy;
- }
- else do {
- mtmp->mux = u.ux - disp + rn2(2*disp+1);
- mtmp->muy = u.uy - disp + rn2(2*disp+1);
- } while((mtmp->mux != u.ux || mtmp->muy != u.uy) &&
- ( (!passes_walls(mtmp->data) &&
- (!ACCESSIBLE(levl[mtmp->mux][mtmp->muy].typ) ||
- (closed_door(mtmp->mux, mtmp->muy) &&
- !amorphous(mtmp->data)
- )
- )
- ) ||
- (disp==1 && mtmp->mux == mtmp->mx && mtmp->muy == mtmp->my)
- )
- );
- }
-
- #endif /* OVL0 */
-
- /*monmove.c*/
-