OSDN Git Service

rearrange main dungeon
[nethackexpress/trunk.git] / src / monmove.c
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
10 extern boolean notonhead;
11
12 #ifdef OVL0
13
14 STATIC_DCL int FDECL(disturb,(struct monst *));
15 STATIC_DCL void FDECL(distfleeck,(struct monst *,int *,int *,int *));
16 STATIC_DCL int FDECL(m_arrival, (struct monst *));
17 STATIC_DCL void FDECL(watch_on_duty,(struct monst *));
18
19 #endif /* OVL0 */
20 #ifdef OVLB
21
22 boolean /* TRUE : mtmp died */
23 mb_trapped(mtmp)
24 register 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
48 STATIC_OVL void
49 watch_on_duty(mtmp)
50 register 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
82 int
83 dochugw(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
129 boolean
130 onscary(x, y, mtmp)
131 int x, y;
132 struct 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 */
152 void
153 mon_regen(mon, digest_meal)
154 struct monst *mon;
155 boolean 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  */
169 STATIC_OVL int
170 disturb(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 */
208 void
209 monflee(mtmp, fleetime, first, fleemsg)
210 struct monst *mtmp;
211 int fleetime;
212 boolean first;
213 boolean 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
240 STATIC_OVL void
241 distfleeck(mtmp,inrange,nearby,scared)
242 register struct monst *mtmp;
243 int *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 */
280 STATIC_OVL int
281 m_arrival(mon)
282 struct 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  */
293 int
294 dochug(mtmp)
295 register 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         }
449 toofar:
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
568 static NEARDATA const char practical[] = { WEAPON_CLASS, ARMOR_CLASS, GEM_CLASS, FOOD_CLASS, 0 };
569 static NEARDATA const char magical[] = {
570         AMULET_CLASS, POTION_CLASS, SCROLL_CLASS, WAND_CLASS, RING_CLASS,
571         SPBOOK_CLASS, 0 };
572 static NEARDATA const char indigestion[] = { BALL_CLASS, ROCK_CLASS, 0 };
573 static NEARDATA const char boulder_class[] = { ROCK_CLASS, 0 };
574 static NEARDATA const char gem_class[] = { GEM_CLASS, 0 };
575
576 boolean
577 itsstuck(mtmp)
578 register 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  */
593 int
594 m_move(mtmp, after)
595 register struct monst *mtmp;
596 register 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         }
710 not_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         }
1043 postmov:
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
1220 boolean
1221 closed_door(x, y)
1222 register int x, y;
1223 {
1224         return((boolean)(IS_DOOR(levl[x][y].typ) &&
1225                         (levl[x][y].doormask & (D_LOCKED | D_CLOSED))));
1226 }
1227
1228 boolean
1229 accessible(x, y)
1230 register 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 */
1239 void
1240 set_apparxy(mtmp)
1241 register 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 {
1302 found_you:
1303             mx = u.ux;
1304             my = u.uy;
1305         }
1306
1307         mtmp->mux = mx;
1308         mtmp->muy = my;
1309 }
1310
1311 boolean
1312 can_ooze(mtmp)
1313 struct 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*/