OSDN Git Service

update year to 2018
[jnethack/source.git] / src / dogmove.c
1 /* NetHack 3.6  dogmove.c       $NHDT-Date: 1502753407 2017/08/14 23:30:07 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.63 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Robert Patrick Rankin, 2012. */
4 /* NetHack may be freely redistributed.  See license for details. */
5
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2018            */
9 /* JNetHack may be freely redistributed.  See license for details. */
10
11 #include "hack.h"
12
13 #include "mfndpos.h"
14
15 extern boolean notonhead;
16
17 STATIC_DCL boolean FDECL(dog_hunger, (struct monst *, struct edog *));
18 STATIC_DCL int FDECL(dog_invent, (struct monst *, struct edog *, int));
19 STATIC_DCL int FDECL(dog_goal, (struct monst *, struct edog *, int, int, int));
20 STATIC_DCL struct monst *FDECL(find_targ, (struct monst *, int, int, int));
21 STATIC_OVL int FDECL(find_friends, (struct monst *, struct monst *, int));
22 STATIC_DCL struct monst *FDECL(best_target, (struct monst *));
23 STATIC_DCL long FDECL(score_targ, (struct monst *, struct monst *));
24 STATIC_DCL boolean FDECL(can_reach_location, (struct monst *, XCHAR_P,
25                                               XCHAR_P, XCHAR_P, XCHAR_P));
26 STATIC_DCL boolean FDECL(could_reach_item, (struct monst *, XCHAR_P, XCHAR_P));
27 STATIC_DCL void FDECL(quickmimic, (struct monst *));
28
29 /* pick a carried item for pet to drop */
30 struct obj *
31 droppables(mon)
32 struct monst *mon;
33 {
34     struct obj *obj, *wep, dummy, *pickaxe, *unihorn, *key;
35
36     dummy = zeroobj;
37     dummy.otyp = GOLD_PIECE; /* not STRANGE_OBJECT or tools of interest */
38     dummy.oartifact = 1; /* so real artifact won't override "don't keep it" */
39     pickaxe = unihorn = key = (struct obj *) 0;
40     wep = MON_WEP(mon);
41
42     if (is_animal(mon->data) || mindless(mon->data)) {
43         /* won't hang on to any objects of these types */
44         pickaxe = unihorn = key = &dummy; /* act as if already have them */
45     } else {
46         /* don't hang on to pick-axe if can't use one or don't need one */
47         if (!tunnels(mon->data) || !needspick(mon->data))
48             pickaxe = &dummy;
49         /* don't hang on to key if can't open doors */
50         if (nohands(mon->data) || verysmall(mon->data))
51             key = &dummy;
52     }
53     if (wep) {
54         if (is_pick(wep))
55             pickaxe = wep;
56         if (wep->otyp == UNICORN_HORN)
57             unihorn = wep;
58         /* don't need any wielded check for keys... */
59     }
60
61     for (obj = mon->minvent; obj; obj = obj->nobj) {
62         switch (obj->otyp) {
63         case DWARVISH_MATTOCK:
64             /* reject mattock if couldn't wield it */
65             if (which_armor(mon, W_ARMS))
66                 break;
67             /* keep mattock in preference to pick unless pick is already
68                wielded or is an artifact and mattock isn't */
69             if (pickaxe && pickaxe->otyp == PICK_AXE && pickaxe != wep
70                 && (!pickaxe->oartifact || obj->oartifact))
71                 return pickaxe; /* drop the one we earlier decided to keep */
72         /*FALLTHRU*/
73         case PICK_AXE:
74             if (!pickaxe || (obj->oartifact && !pickaxe->oartifact)) {
75                 if (pickaxe)
76                     return pickaxe;
77                 pickaxe = obj; /* keep this digging tool */
78                 continue;
79             }
80             break;
81
82         case UNICORN_HORN:
83             /* reject cursed unicorn horns */
84             if (obj->cursed)
85                 break;
86             /* keep artifact unihorn in preference to ordinary one */
87             if (!unihorn || (obj->oartifact && !unihorn->oartifact)) {
88                 if (unihorn)
89                     return unihorn;
90                 unihorn = obj; /* keep this unicorn horn */
91                 continue;
92             }
93             break;
94
95         case SKELETON_KEY:
96             /* keep key in preference to lock-pick */
97             if (key && key->otyp == LOCK_PICK
98                 && (!key->oartifact || obj->oartifact))
99                 return key; /* drop the one we earlier decided to keep */
100         /*FALLTHRU*/
101         case LOCK_PICK:
102             /* keep lock-pick in preference to credit card */
103             if (key && key->otyp == CREDIT_CARD
104                 && (!key->oartifact || obj->oartifact))
105                 return key;
106         /*FALLTHRU*/
107         case CREDIT_CARD:
108             if (!key || (obj->oartifact && !key->oartifact)) {
109                 if (key)
110                     return key;
111                 key = obj; /* keep this unlocking tool */
112                 continue;
113             }
114             break;
115
116         default:
117             break;
118         }
119
120         if (!obj->owornmask && obj != wep)
121             return obj;
122     }
123
124     return (struct obj *) 0; /* don't drop anything */
125 }
126
127 static NEARDATA const char nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS,
128                                          0 };
129
130 STATIC_VAR xchar gtyp, gx, gy; /* type and position of dog's current goal */
131
132 STATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t));
133
134 boolean
135 cursed_object_at(x, y)
136 int x, y;
137 {
138     struct obj *otmp;
139
140     for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
141         if (otmp->cursed)
142             return TRUE;
143     return FALSE;
144 }
145
146 int
147 dog_nutrition(mtmp, obj)
148 struct monst *mtmp;
149 struct obj *obj;
150 {
151     int nutrit;
152
153     /*
154      * It is arbitrary that the pet takes the same length of time to eat
155      * as a human, but gets more nutritional value.
156      */
157     if (obj->oclass == FOOD_CLASS) {
158         if (obj->otyp == CORPSE) {
159             mtmp->meating = 3 + (mons[obj->corpsenm].cwt >> 6);
160             nutrit = mons[obj->corpsenm].cnutrit;
161         } else {
162             mtmp->meating = objects[obj->otyp].oc_delay;
163             nutrit = objects[obj->otyp].oc_nutrition;
164         }
165         switch (mtmp->data->msize) {
166         case MZ_TINY:
167             nutrit *= 8;
168             break;
169         case MZ_SMALL:
170             nutrit *= 6;
171             break;
172         default:
173         case MZ_MEDIUM:
174             nutrit *= 5;
175             break;
176         case MZ_LARGE:
177             nutrit *= 4;
178             break;
179         case MZ_HUGE:
180             nutrit *= 3;
181             break;
182         case MZ_GIGANTIC:
183             nutrit *= 2;
184             break;
185         }
186         if (obj->oeaten) {
187             mtmp->meating = eaten_stat(mtmp->meating, obj);
188             nutrit = eaten_stat(nutrit, obj);
189         }
190     } else if (obj->oclass == COIN_CLASS) {
191         mtmp->meating = (int) (obj->quan / 2000) + 1;
192         if (mtmp->meating < 0)
193             mtmp->meating = 1;
194         nutrit = (int) (obj->quan / 20);
195         if (nutrit < 0)
196             nutrit = 0;
197     } else {
198         /* Unusual pet such as gelatinous cube eating odd stuff.
199          * meating made consistent with wild monsters in mon.c.
200          * nutrit made consistent with polymorphed player nutrit in
201          * eat.c.  (This also applies to pets eating gold.)
202          */
203         mtmp->meating = obj->owt / 20 + 1;
204         nutrit = 5 * objects[obj->otyp].oc_nutrition;
205     }
206     return nutrit;
207 }
208
209 /* returns 2 if pet dies, otherwise 1 */
210 int
211 dog_eat(mtmp, obj, x, y, devour)
212 register struct monst *mtmp;
213 register struct obj *obj; /* if unpaid, then thrown or kicked by hero */
214 int x, y; /* dog's starting location, might be different from current */
215 boolean devour;
216 {
217     register struct edog *edog = EDOG(mtmp);
218     boolean poly, grow, heal, eyes, slimer, deadmimic;
219     int nutrit;
220     long oprice;
221     char objnambuf[BUFSZ];
222
223     objnambuf[0] = '\0';
224     if (edog->hungrytime < monstermoves)
225         edog->hungrytime = monstermoves;
226     nutrit = dog_nutrition(mtmp, obj);
227
228     deadmimic = (obj->otyp == CORPSE && (obj->corpsenm == PM_SMALL_MIMIC
229                                          || obj->corpsenm == PM_LARGE_MIMIC
230                                          || obj->corpsenm == PM_GIANT_MIMIC));
231     slimer = (obj->otyp == CORPSE && obj->corpsenm == PM_GREEN_SLIME);
232     poly = polyfodder(obj);
233     grow = mlevelgain(obj);
234     heal = mhealup(obj);
235     eyes = (obj->otyp == CARROT);
236
237     if (devour) {
238         if (mtmp->meating > 1)
239             mtmp->meating /= 2;
240         if (nutrit > 1)
241             nutrit = (nutrit * 3) / 4;
242     }
243     edog->hungrytime += nutrit;
244     mtmp->mconf = 0;
245     if (edog->mhpmax_penalty) {
246         /* no longer starving */
247         mtmp->mhpmax += edog->mhpmax_penalty;
248         edog->mhpmax_penalty = 0;
249     }
250     if (mtmp->mflee && mtmp->mfleetim > 1)
251         mtmp->mfleetim /= 2;
252     if (mtmp->mtame < 20)
253         mtmp->mtame++;
254     if (x != mtmp->mx || y != mtmp->my) { /* moved & ate on same turn */
255         newsym(x, y);
256         newsym(mtmp->mx, mtmp->my);
257     }
258
259     /* food items are eaten one at a time; entire stack for other stuff */
260     if (obj->quan > 1L && obj->oclass == FOOD_CLASS)
261         obj = splitobj(obj, 1L);
262     if (obj->unpaid)
263         iflags.suppress_price++;
264     if (is_pool(x, y) && !Underwater) {
265         /* Don't print obj */
266         /* TODO: Reveal presence of sea monster (especially sharks) */
267     } else {
268         /* food is at monster's current location, <mx,my>;
269            <x,y> was monster's location at start of this turn;
270            they might be the same but will be different when
271            the monster is moving+eating on same turn */
272         boolean seeobj = cansee(mtmp->mx, mtmp->my),
273                 sawpet = cansee(x, y) && mon_visible(mtmp);
274
275         /* Observe the action if either the food location or the pet
276            itself is in view.  When pet which was in view moves to an
277            unseen spot to eat the food there, avoid referring to that
278            pet as "it".  However, we want "it" if invisible/unsensed
279            pet eats visible food. */
280         if (sawpet || (seeobj && canspotmon(mtmp))) {
281             if (tunnels(mtmp->data))
282 /*JP
283                 pline("%s digs in.", noit_Monnam(mtmp));
284 */
285                 pline("%s\82Í\8c@\82Á\82Ä\82¢\82é\81D", noit_Monnam(mtmp));
286             else
287 #if 0 /*JP*/
288                 pline("%s %s %s.", noit_Monnam(mtmp),
289                       devour ? "devours" : "eats", distant_name(obj, doname));
290 #else
291                 pline("%s\82Í%s\82ð%s\82¢\82é\81D", noit_Monnam(mtmp),
292                       distant_name(obj, doname), devour ? "\88ù\82Ý\8d\9e\82ñ\82Å" : "\90H\82×\82Ä");
293 #endif
294         } else if (seeobj)
295 #if 0 /*JP*/
296             pline("It %s %s.", devour ? "devours" : "eats",
297                   distant_name(obj, doname));
298 #else
299             pline("\82»\82ê\82Í%s\82ð%s\82¢\82é\81D", distant_name(obj, doname),
300                   devour ? "\88ù\82Ý\8d\9e\82ñ\82Å" : "\90H\82×\82Ä");
301 #endif
302     }
303     if (obj->unpaid) {
304         Strcpy(objnambuf, xname(obj));
305         iflags.suppress_price--;
306     }
307     /* It's a reward if it's DOGFOOD and the player dropped/threw it.
308        We know the player had it if invlet is set. -dlc */
309     if (dogfood(mtmp, obj) == DOGFOOD && obj->invlet)
310 #ifdef LINT
311         edog->apport = 0;
312 #else
313         edog->apport += (int) (200L / ((long) edog->dropdist + monstermoves
314                                        - edog->droptime));
315 #endif
316     if (mtmp->data == &mons[PM_RUST_MONSTER] && obj->oerodeproof) {
317         /* The object's rustproofing is gone now */
318         if (obj->unpaid)
319             costly_alteration(obj, COST_DEGRD);
320         obj->oerodeproof = 0;
321         mtmp->mstun = 1;
322         if (canseemon(mtmp) && flags.verbose) {
323 #if 0 /*JP:T*/
324             pline("%s spits %s out in disgust!", Monnam(mtmp),
325                   distant_name(obj, doname));
326 #else
327             pline("%s\82Í%s\82ð\83y\83b\82Æ\93f\82«\8fo\82µ\82½\81I", Monnam(mtmp),
328                   distant_name(obj,doname));
329 #endif
330         }
331     } else if (obj == uball) {
332         unpunish();
333         delobj(obj); /* we assume this can't be unpaid */
334     } else if (obj == uchain) {
335         unpunish();
336     } else {
337         if (obj->unpaid) {
338             /* edible item owned by shop has been thrown or kicked
339                by hero and caught by tame or food-tameable monst */
340             oprice = unpaid_cost(obj, TRUE);
341 #if 0 /*JP*/
342             pline("That %s will cost you %ld %s.", objnambuf, oprice,
343                   currency(oprice));
344 #else
345             pline("\82 \82Ì%s\82Í%ld%s\82¾\81D", objnambuf, oprice,
346                   currency(oprice));
347 #endif
348             /* delobj->obfree will handle actual shop billing update */
349         }
350         delobj(obj);
351     }
352
353 #if 0 /* pet is eating, so slime recovery is not feasible... */
354     /* turning into slime might be cureable */
355     if (slimer && munslime(mtmp, FALSE)) {
356         /* but the cure (fire directed at self) might be fatal */
357         if (mtmp->mhp < 1)
358             return 2;
359         slimer = FALSE; /* sliming is avoided, skip polymorph */
360     }
361 #endif
362
363     if (poly || slimer) {
364         struct permonst *ptr = slimer ? &mons[PM_GREEN_SLIME] : 0;
365
366         (void) newcham(mtmp, ptr, FALSE, cansee(mtmp->mx, mtmp->my));
367     }
368
369     /* limit "instant" growth to prevent potential abuse */
370     if (grow && (int) mtmp->m_lev < (int) mtmp->data->mlevel + 15) {
371         if (!grow_up(mtmp, (struct monst *) 0))
372             return 2;
373     }
374     if (heal)
375         mtmp->mhp = mtmp->mhpmax;
376     if ((eyes || heal) && !mtmp->mcansee)
377         mcureblindness(mtmp, canseemon(mtmp));
378     if (deadmimic)
379         quickmimic(mtmp);
380     return 1;
381 }
382
383 /* hunger effects -- returns TRUE on starvation */
384 STATIC_OVL boolean
385 dog_hunger(mtmp, edog)
386 struct monst *mtmp;
387 struct edog *edog;
388 {
389     if (monstermoves > edog->hungrytime + 500) {
390         if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) {
391             edog->hungrytime = monstermoves + 500;
392             /* but not too high; it might polymorph */
393         } else if (!edog->mhpmax_penalty) {
394             /* starving pets are limited in healing */
395             int newmhpmax = mtmp->mhpmax / 3;
396             mtmp->mconf = 1;
397             edog->mhpmax_penalty = mtmp->mhpmax - newmhpmax;
398             mtmp->mhpmax = newmhpmax;
399             if (mtmp->mhp > mtmp->mhpmax)
400                 mtmp->mhp = mtmp->mhpmax;
401             if (mtmp->mhp < 1)
402                 goto dog_died;
403             if (cansee(mtmp->mx, mtmp->my))
404 /*JP
405                 pline("%s is confused from hunger.", Monnam(mtmp));
406 */
407                 pline("%s\82Í\8bó\95 \82Ì\82½\82ß\8d¬\97\90\82µ\82Ä\82¢\82é\81D", Monnam(mtmp));
408             else if (couldsee(mtmp->mx, mtmp->my))
409                 beg(mtmp);
410             else
411 /*JP
412                 You_feel("worried about %s.", y_monnam(mtmp));
413 */
414                 You("%s\82ª\90S\94z\82É\82È\82Á\82½\81D", y_monnam(mtmp));
415             stop_occupation();
416         } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) {
417         dog_died:
418             if (mtmp->mleashed && mtmp != u.usteed)
419 /*JP
420                 Your("leash goes slack.");
421 */
422                 Your("\95R\82Í\82½\82é\82ñ\82¾\81D");
423             else if (cansee(mtmp->mx, mtmp->my))
424 /*JP
425                 pline("%s starves.", Monnam(mtmp));
426 */
427                 pline("%s\82Í\8bQ\82¦\82Å\8e\80\82ñ\82¾\81D", Monnam(mtmp));
428             else
429 #if 0 /*JP*/
430                 You_feel("%s for a moment.",
431                          Hallucination ? "bummed" : "sad");
432 #else
433                 You("%s\8bC\95ª\82É\82¨\82»\82í\82ê\82½\81D",
434                     Hallucination ? "\82ª\82Á\82©\82è\82µ\82½" : "\94ß\82µ\82¢");
435 #endif
436             mondied(mtmp);
437             return  TRUE;
438         }
439     }
440     return FALSE;
441 }
442
443 /* do something with object (drop, pick up, eat) at current position
444  * returns 1 if object eaten (since that counts as dog's move), 2 if died
445  */
446 STATIC_OVL int
447 dog_invent(mtmp, edog, udist)
448 register struct monst *mtmp;
449 register struct edog *edog;
450 int udist;
451 {
452     register int omx, omy, carryamt = 0;
453     struct obj *obj, *otmp;
454
455     if (mtmp->msleeping || !mtmp->mcanmove)
456         return 0;
457
458     omx = mtmp->mx;
459     omy = mtmp->my;
460
461     /* If we are carrying something then we drop it (perhaps near @).
462      * Note: if apport == 1 then our behaviour is independent of udist.
463      * Use udist+1 so steed won't cause divide by zero.
464      */
465     if (droppables(mtmp)) {
466         if (!rn2(udist + 1) || !rn2(edog->apport))
467             if (rn2(10) < edog->apport) {
468                 relobj(mtmp, (int) mtmp->minvis, TRUE);
469                 if (edog->apport > 1)
470                     edog->apport--;
471                 edog->dropdist = udist; /* hpscdi!jon */
472                 edog->droptime = monstermoves;
473             }
474     } else {
475         if ((obj = level.objects[omx][omy]) != 0
476             && !index(nofetch, obj->oclass)
477 #ifdef MAIL
478             && obj->otyp != SCR_MAIL
479 #endif
480             ) {
481             int edible = dogfood(mtmp, obj);
482
483             if ((edible <= CADAVER
484                  /* starving pet is more aggressive about eating */
485                  || (edog->mhpmax_penalty && edible == ACCFOOD))
486                 && could_reach_item(mtmp, obj->ox, obj->oy))
487                 return dog_eat(mtmp, obj, omx, omy, FALSE);
488
489             carryamt = can_carry(mtmp, obj);
490             if (carryamt > 0 && !obj->cursed
491                 && could_reach_item(mtmp, obj->ox, obj->oy)) {
492                 if (rn2(20) < edog->apport + 3) {
493                     if (rn2(udist) || !rn2(edog->apport)) {
494                         otmp = obj;
495                         if (carryamt != obj->quan)
496                             otmp = splitobj(obj, carryamt);
497                         if (cansee(omx, omy) && flags.verbose)
498 #if 0 /*JP:T*/
499                             pline("%s picks up %s.", Monnam(mtmp),
500                                   distant_name(otmp, doname));
501 #else
502                             pline("%s\82Í%s\82ð\8fE\82Á\82½\81D", Monnam(mtmp),
503                                   distant_name(obj, doname));
504 #endif
505                         obj_extract_self(otmp);
506                         newsym(omx, omy);
507                         (void) mpickobj(mtmp, otmp);
508                         if (attacktype(mtmp->data, AT_WEAP)
509                             && mtmp->weapon_check == NEED_WEAPON) {
510                             mtmp->weapon_check = NEED_HTH_WEAPON;
511                             (void) mon_wield_item(mtmp);
512                         }
513                         m_dowear(mtmp, FALSE);
514                     }
515                 }
516             }
517         }
518     }
519     return 0;
520 }
521
522 /* set dog's goal -- gtyp, gx, gy;
523    returns -1/0/1 (dog's desire to approach player) or -2 (abort move) */
524 STATIC_OVL int
525 dog_goal(mtmp, edog, after, udist, whappr)
526 register struct monst *mtmp;
527 struct edog *edog;
528 int after, udist, whappr;
529 {
530     register int omx, omy;
531     boolean in_masters_sight, dog_has_minvent;
532     register struct obj *obj;
533     xchar otyp;
534     int appr;
535
536     /* Steeds don't move on their own will */
537     if (mtmp == u.usteed)
538         return -2;
539
540     omx = mtmp->mx;
541     omy = mtmp->my;
542
543     in_masters_sight = couldsee(omx, omy);
544     dog_has_minvent = (droppables(mtmp) != 0);
545
546     if (!edog || mtmp->mleashed) { /* he's not going anywhere... */
547         gtyp = APPORT;
548         gx = u.ux;
549         gy = u.uy;
550     } else {
551 #define DDIST(x, y) (dist2(x, y, omx, omy))
552 #define SQSRCHRADIUS 5
553         int min_x, max_x, min_y, max_y;
554         register int nx, ny;
555
556         gtyp = UNDEF; /* no goal as yet */
557         gx = gy = 0;  /* suppress 'used before set' message */
558
559         if ((min_x = omx - SQSRCHRADIUS) < 1)
560             min_x = 1;
561         if ((max_x = omx + SQSRCHRADIUS) >= COLNO)
562             max_x = COLNO - 1;
563         if ((min_y = omy - SQSRCHRADIUS) < 0)
564             min_y = 0;
565         if ((max_y = omy + SQSRCHRADIUS) >= ROWNO)
566             max_y = ROWNO - 1;
567
568         /* nearby food is the first choice, then other objects */
569         for (obj = fobj; obj; obj = obj->nobj) {
570             nx = obj->ox;
571             ny = obj->oy;
572             if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) {
573                 otyp = dogfood(mtmp, obj);
574                 /* skip inferior goals */
575                 if (otyp > gtyp || otyp == UNDEF)
576                     continue;
577                 /* avoid cursed items unless starving */
578                 if (cursed_object_at(nx, ny)
579                     && !(edog->mhpmax_penalty && otyp < MANFOOD))
580                     continue;
581                 /* skip completely unreachable goals */
582                 if (!could_reach_item(mtmp, nx, ny)
583                     || !can_reach_location(mtmp, mtmp->mx, mtmp->my, nx, ny))
584                     continue;
585                 if (otyp < MANFOOD) {
586                     if (otyp < gtyp || DDIST(nx, ny) < DDIST(gx, gy)) {
587                         gx = nx;
588                         gy = ny;
589                         gtyp = otyp;
590                     }
591                 } else if (gtyp == UNDEF && in_masters_sight
592                            && !dog_has_minvent
593                            && (!levl[omx][omy].lit || levl[u.ux][u.uy].lit)
594                            && (otyp == MANFOOD || m_cansee(mtmp, nx, ny))
595                            && edog->apport > rn2(8)
596                            && can_carry(mtmp, obj) > 0) {
597                     gx = nx;
598                     gy = ny;
599                     gtyp = APPORT;
600                 }
601             }
602         }
603     }
604
605     /* follow player if appropriate */
606     if (gtyp == UNDEF || (gtyp != DOGFOOD && gtyp != APPORT
607                           && monstermoves < edog->hungrytime)) {
608         gx = u.ux;
609         gy = u.uy;
610         if (after && udist <= 4 && gx == u.ux && gy == u.uy)
611             return -2;
612         appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
613         if (udist > 1) {
614             if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) || whappr
615                 || (dog_has_minvent && rn2(edog->apport)))
616                 appr = 1;
617         }
618         /* if you have dog food it'll follow you more closely */
619         if (appr == 0)
620             for (obj = invent; obj; obj = obj->nobj)
621                 if (dogfood(mtmp, obj) == DOGFOOD) {
622                     appr = 1;
623                     break;
624                 }
625     } else
626         appr = 1; /* gtyp != UNDEF */
627     if (mtmp->mconf)
628         appr = 0;
629
630 #define FARAWAY (COLNO + 2) /* position outside screen */
631     if (gx == u.ux && gy == u.uy && !in_masters_sight) {
632         register coord *cp;
633
634         cp = gettrack(omx, omy);
635         if (cp) {
636             gx = cp->x;
637             gy = cp->y;
638             if (edog)
639                 edog->ogoal.x = 0;
640         } else {
641             /* assume master hasn't moved far, and reuse previous goal */
642             if (edog && edog->ogoal.x
643                 && (edog->ogoal.x != omx || edog->ogoal.y != omy)) {
644                 gx = edog->ogoal.x;
645                 gy = edog->ogoal.y;
646                 edog->ogoal.x = 0;
647             } else {
648                 int fardist = FARAWAY * FARAWAY;
649                 gx = gy = FARAWAY; /* random */
650                 do_clear_area(omx, omy, 9, wantdoor, (genericptr_t) &fardist);
651
652                 /* here gx == FARAWAY e.g. when dog is in a vault */
653                 if (gx == FARAWAY || (gx == omx && gy == omy)) {
654                     gx = u.ux;
655                     gy = u.uy;
656                 } else if (edog) {
657                     edog->ogoal.x = gx;
658                     edog->ogoal.y = gy;
659                 }
660             }
661         }
662     } else if (edog) {
663         edog->ogoal.x = 0;
664     }
665     return appr;
666 }
667
668
669 STATIC_OVL struct monst *
670 find_targ(mtmp, dx, dy, maxdist)
671 register struct monst *mtmp;
672 int dx, dy;
673 int maxdist;
674 {
675     struct monst *targ = 0;
676     int curx = mtmp->mx, cury = mtmp->my;
677     int dist = 0;
678
679     /* Walk outwards */
680     for ( ; dist < maxdist; ++dist) {
681         curx += dx;
682         cury += dy;
683         if (!isok(curx, cury))
684             break;
685
686         /* FIXME: Check if we hit a wall/door/boulder to
687          *        short-circuit unnecessary subsequent checks
688          */
689
690         /* If we can't see up to here, forget it - will this
691          * mean pets in corridors don't breathe at monsters
692          * in rooms? If so, is that necessarily bad?
693          */
694         if (!m_cansee(mtmp, curx, cury))
695             break;
696
697         targ = m_at(curx, cury);
698
699         if (curx == mtmp->mux && cury == mtmp->muy)
700             return &youmonst;
701
702         if (targ) {
703             /* Is the monster visible to the pet? */
704             if ((!targ->minvis || perceives(mtmp->data)) &&
705                 !targ->mundetected)
706                 break;
707
708             /* If the pet can't see it, it assumes it aint there */
709             targ = 0;
710         }
711     }
712     return targ;
713 }
714
715 STATIC_OVL int
716 find_friends(mtmp, mtarg, maxdist)
717 struct monst *mtmp, *mtarg;
718 int    maxdist;
719 {
720     struct monst *pal;
721     int dx = sgn(mtarg->mx - mtmp->mx),
722         dy = sgn(mtarg->my - mtmp->my);
723     int curx = mtarg->mx, cury = mtarg->my;
724     int dist = distmin(mtarg->mx, mtarg->my, mtmp->mx, mtmp->my);
725
726     for ( ; dist <= maxdist; ++dist) {
727         curx += dx;
728         cury += dy;
729
730         if (!isok(curx, cury))
731             return 0;
732
733         /* If the pet can't see beyond this point, don't
734          * check any farther
735          */
736         if (!m_cansee(mtmp, curx, cury))
737             return 0;
738
739         /* Does pet think you're here? */
740         if (mtmp->mux == curx && mtmp->muy == cury)
741             return 1;
742
743         pal = m_at(curx, cury);
744
745         if (pal) {
746             if (pal->mtame) {
747                 /* Pet won't notice invisible pets */
748                 if (!pal->minvis || perceives(mtmp->data))
749                     return 1;
750             } else {
751                 /* Quest leaders and guardians are always seen */
752                 if (pal->data->msound == MS_LEADER
753                     || pal->data->msound == MS_GUARDIAN)
754                     return 1;
755             }
756         }
757     }
758     return 0;
759 }
760
761 STATIC_OVL long
762 score_targ(mtmp, mtarg)
763 struct monst *mtmp, *mtarg;
764 {
765     long score = 0L;
766
767     /* If the monster is confused, normal scoring is disrupted -
768      * anything may happen
769      */
770
771     /* Give 1 in 3 chance of safe breathing even if pet is confused or
772      * if you're on the quest start level */
773     if (!mtmp->mconf || !rn2(3) || Is_qstart(&u.uz)) {
774         aligntyp align1 = A_NONE, align2 = A_NONE; /* For priests, minions */
775         boolean faith1 = TRUE,  faith2 = TRUE;
776
777         if (mtmp->isminion)
778             align1 = EMIN(mtmp)->min_align;
779         else if (mtmp->ispriest)
780             align1 = EPRI(mtmp)->shralign;
781         else
782             faith1 = FALSE;
783         if (mtarg->isminion)
784             align2 = EMIN(mtarg)->min_align; /* MAR */
785         else if (mtarg->ispriest)
786             align2 = EPRI(mtarg)->shralign; /* MAR */
787         else
788             faith2 = FALSE;
789
790         /* Never target quest friendlies */
791         if (mtarg->data->msound == MS_LEADER
792             || mtarg->data->msound == MS_GUARDIAN)
793             return -5000L;
794         /* D: Fixed angelic beings using gaze attacks on coaligned priests */
795         if (faith1 && faith2 && align1 == align2 && mtarg->mpeaceful) {
796             score -= 5000L;
797             return score;
798         }
799         /* Is monster adjacent? */
800         if (distmin(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my) <= 1) {
801             score -= 3000L;
802             return score;
803         }
804         /* Is the monster peaceful or tame? */
805         if (/*mtarg->mpeaceful ||*/ mtarg->mtame || mtarg == &youmonst) {
806             /* Pets will never be targeted */
807             score -= 3000L;
808             return score;
809         }
810         /* Is master/pet behind monster? Check up to 15 squares beyond pet. */
811         if (find_friends(mtmp, mtarg, 15)) {
812             score -= 3000L;
813             return score;
814         }
815         /* Target hostile monsters in preference to peaceful ones */
816         if (!mtarg->mpeaceful)
817             score += 10;
818         /* Is the monster passive? Don't waste energy on it, if so */
819         if (mtarg->data->mattk[0].aatyp == AT_NONE)
820             score -= 1000;
821         /* Even weak pets with breath attacks shouldn't take on very
822            low-level monsters. Wasting breath on lichens is ridiculous. */
823         if ((mtarg->m_lev < 2 && mtmp->m_lev > 5)
824             || (mtmp->m_lev > 12 && mtarg->m_lev < mtmp->m_lev - 9
825                 && u.ulevel > 8 && mtarg->m_lev < u.ulevel - 7))
826             score -= 25;
827         /* And pets will hesitate to attack vastly stronger foes.
828            This penalty will be discarded if master's in trouble. */
829         if (mtarg->m_lev > mtmp->m_lev + 4L)
830             score -= (mtarg->m_lev - mtmp->m_lev) * 20L;
831         /* All things being the same, go for the beefiest monster. This
832            bonus should not be large enough to override the pet's aversion
833            to attacking much stronger monsters. */
834         score += mtarg->m_lev * 2 + mtarg->mhp / 3;
835     }
836     /* Fuzz factor to make things less predictable when very
837        similar targets are abundant. */
838     score += rnd(5);
839     /* Pet may decide not to use ranged attack when confused */
840     if (mtmp->mconf && !rn2(3))
841         score -= 1000;
842     return score;
843 }
844
845
846 STATIC_OVL struct monst *
847 best_target(mtmp)
848 struct monst *mtmp;   /* Pet */
849 {
850     int dx, dy;
851     long bestscore = -40000L, currscore;
852     struct monst *best_targ = 0, *temp_targ = 0;
853
854     /* Help! */
855     if (!mtmp)
856         return 0;
857
858     /* If the pet is blind, it's not going to see any target */
859     if (!mtmp->mcansee)
860         return 0;
861
862     /* Search for any monsters lined up with the pet, within an arbitrary
863      * distance from the pet (7 squares, even along diagonals). Monsters
864      * are assigned scores and the best score is chosen.
865      */
866     for (dy = -1; dy < 2; ++dy) {
867         for (dx = -1; dx < 2; ++dx) {
868             if (!dx && !dy)
869                 continue;
870             /* Traverse the line to find the first monster within 7
871              * squares. Invisible monsters are skipped (if the
872              * pet doesn't have see invisible).
873              */
874             temp_targ = find_targ(mtmp, dx, dy, 7);
875
876             /* Nothing in this line? */
877             if (!temp_targ)
878                 continue;
879
880             /* Decide how attractive the target is */
881             currscore = score_targ(mtmp, temp_targ);
882
883             if (currscore > bestscore) {
884                 bestscore = currscore;
885                 best_targ = temp_targ;
886             }
887         }
888     }
889
890     /* Filter out targets the pet doesn't like */
891     if (bestscore < 0L)
892         best_targ = 0;
893
894     return best_targ;
895 }
896
897
898 /* return 0 (no move), 1 (move) or 2 (dead) */
899 int
900 dog_move(mtmp, after)
901 register struct monst *mtmp;
902 int after; /* this is extra fast monster movement */
903 {
904     int omx, omy; /* original mtmp position */
905     int appr, whappr, udist;
906     int i, j, k;
907     register struct edog *edog = EDOG(mtmp);
908     struct obj *obj = (struct obj *) 0;
909     xchar otyp;
910     boolean has_edog, cursemsg[9], do_eat = FALSE;
911     boolean better_with_displacing = FALSE;
912     xchar nix, niy;      /* position mtmp is (considering) moving to */
913     register int nx, ny; /* temporary coordinates */
914     xchar cnt, uncursedcnt, chcnt;
915     int chi = -1, nidist, ndist;
916     coord poss[9];
917     long info[9], allowflags;
918 #define GDIST(x, y) (dist2(x, y, gx, gy))
919
920     /*
921      * Tame Angels have isminion set and an ispriest structure instead of
922      * an edog structure.  Fortunately, guardian Angels need not worry
923      * about mundane things like eating and fetching objects, and can
924      * spend all their energy defending the player.  (They are the only
925      * monsters with other structures that can be tame.)
926      */
927     has_edog = !mtmp->isminion;
928
929     omx = mtmp->mx;
930     omy = mtmp->my;
931     if (has_edog && dog_hunger(mtmp, edog))
932         return 2; /* starved */
933
934     udist = distu(omx, omy);
935     /* Let steeds eat and maybe throw rider during Conflict */
936     if (mtmp == u.usteed) {
937         if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
938             dismount_steed(DISMOUNT_THROWN);
939             return 1;
940         }
941         udist = 1;
942     } else if (!udist)
943         /* maybe we tamed him while being swallowed --jgm */
944         return 0;
945
946     nix = omx; /* set before newdogpos */
947     niy = omy;
948     cursemsg[0] = FALSE; /* lint suppression */
949     info[0] = 0;         /* ditto */
950
951     if (has_edog) {
952         j = dog_invent(mtmp, edog, udist);
953         if (j == 2)
954             return 2; /* died */
955         else if (j == 1)
956             goto newdogpos; /* eating something */
957
958         whappr = (monstermoves - edog->whistletime < 5);
959     } else
960         whappr = 0;
961
962     appr = dog_goal(mtmp, has_edog ? edog : (struct edog *) 0, after, udist,
963                     whappr);
964     if (appr == -2)
965         return 0;
966
967     allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT;
968     if (passes_walls(mtmp->data))
969         allowflags |= (ALLOW_ROCK | ALLOW_WALL);
970     if (passes_bars(mtmp->data))
971         allowflags |= ALLOW_BARS;
972     if (throws_rocks(mtmp->data))
973         allowflags |= ALLOW_ROCK;
974     if (is_displacer(mtmp->data))
975         allowflags |= ALLOW_MDISP;
976     if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
977         allowflags |= ALLOW_U;
978         if (!has_edog) {
979             /* Guardian angel refuses to be conflicted; rather,
980              * it disappears, angrily, and sends in some nasties
981              */
982             lose_guardian_angel(mtmp);
983             return 2; /* current monster is gone */
984         }
985     }
986 #if 0 /* [this is now handled in dochug()] */
987     if (!Conflict && !mtmp->mconf
988         && mtmp == u.ustuck && !sticks(youmonst.data)) {
989         unstuck(mtmp); /* swallowed case handled above */
990 /*JP
991         You("get released!");
992 */
993         You("\93®\82¯\82é\82æ\82¤\82É\82È\82Á\82½\81I");
994     }
995 #endif
996     if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
997         allowflags |= OPENDOOR;
998         if (monhaskey(mtmp, TRUE))
999             allowflags |= UNLOCKDOOR;
1000         /* note:  the Wizard and Riders can unlock doors without a key;
1001            they won't use that ability if someone manages to tame them */
1002     }
1003     if (is_giant(mtmp->data))
1004         allowflags |= BUSTDOOR;
1005     if (tunnels(mtmp->data)
1006         && !Is_rogue_level(&u.uz)) /* same restriction as m_move() */
1007         allowflags |= ALLOW_DIG;
1008     cnt = mfndpos(mtmp, poss, info, allowflags);
1009
1010     /* Normally dogs don't step on cursed items, but if they have no
1011      * other choice they will.  This requires checking ahead of time
1012      * to see how many uncursed item squares are around.
1013      */
1014     uncursedcnt = 0;
1015     for (i = 0; i < cnt; i++) {
1016         nx = poss[i].x;
1017         ny = poss[i].y;
1018         if (MON_AT(nx, ny) && !((info[i] & ALLOW_M) || info[i] & ALLOW_MDISP))
1019             continue;
1020         if (cursed_object_at(nx, ny))
1021             continue;
1022         uncursedcnt++;
1023     }
1024
1025     better_with_displacing = should_displace(mtmp, poss, info, cnt, gx, gy);
1026
1027     chcnt = 0;
1028     chi = -1;
1029     nidist = GDIST(nix, niy);
1030
1031     for (i = 0; i < cnt; i++) {
1032         nx = poss[i].x;
1033         ny = poss[i].y;
1034         cursemsg[i] = FALSE;
1035
1036         /* if leashed, we drag him along. */
1037         if (mtmp->mleashed && distu(nx, ny) > 4)
1038             continue;
1039
1040         /* if a guardian, try to stay close by choice */
1041         if (!has_edog && (j = distu(nx, ny)) > 16 && j >= udist)
1042             continue;
1043
1044         if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) {
1045             int mstatus;
1046             register struct monst *mtmp2 = m_at(nx, ny);
1047
1048             if ((int) mtmp2->m_lev >= (int) mtmp->m_lev + 2
1049                 || (mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10)
1050                     && mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee
1051                     && (perceives(mtmp->data) || !mtmp2->minvis))
1052                 || (mtmp2->data == &mons[PM_GELATINOUS_CUBE] && rn2(10))
1053                 || (max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp)
1054                 || ((mtmp->mhp * 4 < mtmp->mhpmax
1055                      || mtmp2->data->msound == MS_GUARDIAN
1056                      || mtmp2->data->msound == MS_LEADER) && mtmp2->mpeaceful
1057                     && !Conflict)
1058                 || (touch_petrifies(mtmp2->data) && !resists_ston(mtmp)))
1059                 continue;
1060
1061             if (after)
1062                 return 0; /* hit only once each move */
1063
1064             notonhead = 0;
1065             mstatus = mattackm(mtmp, mtmp2);
1066
1067             /* aggressor (pet) died */
1068             if (mstatus & MM_AGR_DIED)
1069                 return 2;
1070
1071             if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) && rn2(4)
1072                 && mtmp2->mlstmv != monstermoves
1073                 && !onscary(mtmp->mx, mtmp->my, mtmp2)
1074                 /* monnear check needed: long worms hit on tail */
1075                 && monnear(mtmp2, mtmp->mx, mtmp->my)) {
1076                 mstatus = mattackm(mtmp2, mtmp); /* return attack */
1077                 if (mstatus & MM_DEF_DIED)
1078                     return 2;
1079             }
1080             return 0;
1081         }
1082         if ((info[i] & ALLOW_MDISP) && MON_AT(nx, ny)
1083             && better_with_displacing && !undesirable_disp(mtmp, nx, ny)) {
1084             int mstatus;
1085             register struct monst *mtmp2 = m_at(nx, ny);
1086
1087             mstatus = mdisplacem(mtmp, mtmp2, FALSE); /* displace monster */
1088             if (mstatus & MM_DEF_DIED)
1089                 return 2;
1090             return 0;
1091         }
1092
1093         {
1094             /* Dog avoids harmful traps, but perhaps it has to pass one
1095              * in order to follow player.  (Non-harmful traps do not
1096              * have ALLOW_TRAPS in info[].)  The dog only avoids the
1097              * trap if you've seen it, unlike enemies who avoid traps
1098              * if they've seen some trap of that type sometime in the
1099              * past.  (Neither behavior is really realistic.)
1100              */
1101             struct trap *trap;
1102
1103             if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx, ny))) {
1104                 if (mtmp->mleashed) {
1105                     if (!Deaf)
1106                         whimper(mtmp);
1107                 } else {
1108                     /* 1/40 chance of stepping on it anyway, in case
1109                      * it has to pass one to follow the player...
1110                      */
1111                     if (trap->tseen && rn2(40))
1112                         continue;
1113                 }
1114             }
1115         }
1116
1117         /* dog eschews cursed objects, but likes dog food */
1118         /* (minion isn't interested; `cursemsg' stays FALSE) */
1119         if (has_edog)
1120             for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) {
1121                 if (obj->cursed) {
1122                     cursemsg[i] = TRUE;
1123                 } else if ((otyp = dogfood(mtmp, obj)) < MANFOOD
1124                          && (otyp < ACCFOOD
1125                              || edog->hungrytime <= monstermoves)) {
1126                     /* Note: our dog likes the food so much that he
1127                      * might eat it even when it conceals a cursed object */
1128                     nix = nx;
1129                     niy = ny;
1130                     chi = i;
1131                     do_eat = TRUE;
1132                     cursemsg[i] = FALSE; /* not reluctant */
1133                     goto newdogpos;
1134                 }
1135             }
1136         /* didn't find something to eat; if we saw a cursed item and
1137            aren't being forced to walk on it, usually keep looking */
1138         if (cursemsg[i] && !mtmp->mleashed && uncursedcnt > 0
1139             && rn2(13 * uncursedcnt))
1140             continue;
1141
1142         /* lessen the chance of backtracking to previous position(s) */
1143         /* This causes unintended issues for pets trying to follow
1144            the hero. Thus, only run it if not leashed and >5 tiles
1145            away. */
1146         if (!mtmp->mleashed &&
1147             distmin(mtmp->mx, mtmp->my, u.ux, u.uy) > 5) {
1148             k = has_edog ? uncursedcnt : cnt;
1149             for (j = 0; j < MTSZ && j < k - 1; j++)
1150                 if (nx == mtmp->mtrack[j].x &&
1151                     ny == mtmp->mtrack[j].y)
1152                     if (rn2(MTSZ * (k - j)))
1153                         goto nxti;
1154         }
1155
1156         j = ((ndist = GDIST(nx, ny)) - nidist) * appr;
1157         if ((j == 0 && !rn2(++chcnt)) || j < 0
1158             || (j > 0 && !whappr
1159                 && ((omx == nix && omy == niy && !rn2(3)) || !rn2(12)))) {
1160             nix = nx;
1161             niy = ny;
1162             nidist = ndist;
1163             if (j < 0)
1164                 chcnt = 0;
1165             chi = i;
1166         }
1167     nxti:
1168         ;
1169     }
1170
1171     /* Pet hasn't attacked anything but is considering moving -
1172      * now's the time for ranged attacks. Note that the pet can move
1173      * after it performs its ranged attack. Should this be changed?
1174      */
1175     {
1176         struct monst *mtarg;
1177         int hungry = 0;
1178
1179         /* How hungry is the pet? */
1180         if (!mtmp->isminion) {
1181             struct edog *dog = EDOG(mtmp);
1182             hungry = (monstermoves > (dog->hungrytime + 300));
1183         }
1184
1185         /* Identify the best target in a straight line from the pet;
1186          * if there is such a target, we'll let the pet attempt an
1187          * attack.
1188          */
1189         mtarg = best_target(mtmp);
1190
1191         /* Hungry pets are unlikely to use breath/spit attacks */
1192         if (mtarg && (!hungry || !rn2(5))) {
1193             int mstatus;
1194
1195             if (mtarg == &youmonst) {
1196                 if (mattacku(mtmp))
1197                     return 2;
1198             } else {
1199                 mstatus = mattackm(mtmp, mtarg);
1200
1201                 /* Shouldn't happen, really */
1202                 if (mstatus & MM_AGR_DIED)
1203                     return 2;
1204
1205                 /* Allow the targeted nasty to strike back - if
1206                  * the targeted beast doesn't have a ranged attack,
1207                  * nothing will happen.
1208                  */
1209                 if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED)
1210                     && rn2(4) && mtarg != &youmonst) {
1211
1212                     /* Can monster see? If it can, it can retaliate
1213                      * even if the pet is invisible, since it'll see
1214                      * the direction from which the ranged attack came;
1215                      * if it's blind or unseeing, it can't retaliate
1216                      */
1217                     if (mtarg->mcansee && haseyes(mtarg->data)) {
1218                         mstatus = mattackm(mtarg, mtmp);
1219                         if (mstatus & MM_DEF_DIED)
1220                             return 2;
1221                     }
1222                 }
1223             }
1224         }
1225     }
1226
1227 newdogpos:
1228     if (nix != omx || niy != omy) {
1229         boolean wasseen;
1230
1231         if (info[chi] & ALLOW_U) {
1232             if (mtmp->mleashed) { /* play it safe */
1233 #if 0 /*JP:T*/
1234                 pline("%s breaks loose of %s leash!", Monnam(mtmp),
1235                       mhis(mtmp));
1236 #else
1237                 pline("%s\82Í\8e©\95ª\82É\82Â\82¢\82Ä\82¢\82é\95R\82ð\82Í\82¸\82µ\82½\81I",
1238                       Monnam(mtmp));
1239 #endif
1240                 m_unleash(mtmp, FALSE);
1241             }
1242             (void) mattacku(mtmp);
1243             return 0;
1244         }
1245         if (!m_in_out_region(mtmp, nix, niy))
1246             return 1;
1247         if (m_digweapon_check(mtmp, nix,niy))
1248             return 0;
1249
1250         /* insert a worm_move() if worms ever begin to eat things */
1251         wasseen = canseemon(mtmp);
1252         remove_monster(omx, omy);
1253         place_monster(mtmp, nix, niy);
1254         if (cursemsg[chi] && (wasseen || canseemon(mtmp))) {
1255             /* describe top item of pile, not necessarily cursed item itself;
1256                don't use glyph_at() here--it would return the pet but we want
1257                to know whether an object is remembered at this map location */
1258             struct obj *o = (!Hallucination && level.flags.hero_memory
1259                              && glyph_is_object(levl[nix][niy].glyph))
1260                                ? vobj_at(nix, niy) : 0;
1261             const char *what = o ? distant_name(o, doname) : something;
1262
1263 #if 0 /*JP*/
1264             pline("%s %s reluctantly over %s.", noit_Monnam(mtmp),
1265                   vtense((char *) 0, locomotion(mtmp->data, "step")), what);
1266 #else
1267             pline("%s\82Í%s\82Ì\8fã\82É\82¢\82â\82¢\82â\93®\82¢\82½\81D", noit_Monnam(mtmp), what);
1268 #endif
1269         }
1270         for (j = MTSZ - 1; j > 0; j--)
1271             mtmp->mtrack[j] = mtmp->mtrack[j - 1];
1272         mtmp->mtrack[0].x = omx;
1273         mtmp->mtrack[0].y = omy;
1274         /* We have to know if the pet's going to do a combined eat and
1275          * move before moving it, but it can't eat until after being
1276          * moved.  Thus the do_eat flag.
1277          */
1278         if (do_eat) {
1279             if (dog_eat(mtmp, obj, omx, omy, FALSE) == 2)
1280                 return 2;
1281         }
1282     } else if (mtmp->mleashed && distu(omx, omy) > 4) {
1283         /* an incredible kludge, but the only way to keep pooch near
1284          * after it spends time eating or in a trap, etc.
1285          */
1286         coord cc;
1287
1288         nx = sgn(omx - u.ux);
1289         ny = sgn(omy - u.uy);
1290         cc.x = u.ux + nx;
1291         cc.y = u.uy + ny;
1292         if (goodpos(cc.x, cc.y, mtmp, 0))
1293             goto dognext;
1294
1295         i = xytod(nx, ny);
1296         for (j = (i + 7) % 8; j < (i + 1) % 8; j++) {
1297             dtoxy(&cc, j);
1298             if (goodpos(cc.x, cc.y, mtmp, 0))
1299                 goto dognext;
1300         }
1301         for (j = (i + 6) % 8; j < (i + 2) % 8; j++) {
1302             dtoxy(&cc, j);
1303             if (goodpos(cc.x, cc.y, mtmp, 0))
1304                 goto dognext;
1305         }
1306         cc.x = mtmp->mx;
1307         cc.y = mtmp->my;
1308     dognext:
1309         if (!m_in_out_region(mtmp, nix, niy))
1310             return 1;
1311         remove_monster(mtmp->mx, mtmp->my);
1312         place_monster(mtmp, cc.x, cc.y);
1313         newsym(cc.x, cc.y);
1314         set_apparxy(mtmp);
1315     }
1316     return 1;
1317 }
1318
1319 /* check if a monster could pick up objects from a location */
1320 STATIC_OVL boolean
1321 could_reach_item(mon, nx, ny)
1322 struct monst *mon;
1323 xchar nx, ny;
1324 {
1325     if ((!is_pool(nx, ny) || is_swimmer(mon->data))
1326         && (!is_lava(nx, ny) || likes_lava(mon->data))
1327         && (!sobj_at(BOULDER, nx, ny) || throws_rocks(mon->data)))
1328         return TRUE;
1329     return FALSE;
1330 }
1331
1332 /* Hack to prevent a dog from being endlessly stuck near an object that
1333  * it can't reach, such as caught in a teleport scroll niche.  It recursively
1334  * checks to see if the squares in between are good.  The checking could be
1335  * a little smarter; a full check would probably be useful in m_move() too.
1336  * Since the maximum food distance is 5, this should never be more than 5
1337  * calls deep.
1338  */
1339 STATIC_OVL boolean
1340 can_reach_location(mon, mx, my, fx, fy)
1341 struct monst *mon;
1342 xchar mx, my, fx, fy;
1343 {
1344     int i, j;
1345     int dist;
1346
1347     if (mx == fx && my == fy)
1348         return TRUE;
1349     if (!isok(mx, my))
1350         return FALSE; /* should not happen */
1351
1352     dist = dist2(mx, my, fx, fy);
1353     for (i = mx - 1; i <= mx + 1; i++) {
1354         for (j = my - 1; j <= my + 1; j++) {
1355             if (!isok(i, j))
1356                 continue;
1357             if (dist2(i, j, fx, fy) >= dist)
1358                 continue;
1359             if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data)
1360                 && (!may_dig(i, j) || !tunnels(mon->data)))
1361                 continue;
1362             if (IS_DOOR(levl[i][j].typ)
1363                 && (levl[i][j].doormask & (D_CLOSED | D_LOCKED)))
1364                 continue;
1365             if (!could_reach_item(mon, i, j))
1366                 continue;
1367             if (can_reach_location(mon, i, j, fx, fy))
1368                 return TRUE;
1369         }
1370     }
1371     return FALSE;
1372 }
1373
1374 /* do_clear_area client */
1375 STATIC_PTR void
1376 wantdoor(x, y, distance)
1377 int x, y;
1378 genericptr_t distance;
1379 {
1380     int ndist, *dist_ptr = (int *) distance;
1381
1382     if (*dist_ptr > (ndist = distu(x, y))) {
1383         gx = x;
1384         gy = y;
1385         *dist_ptr = ndist;
1386     }
1387 }
1388
1389 static struct qmchoices {
1390     int mndx;             /* type of pet, 0 means any  */
1391     char mlet;            /* symbol of pet, 0 means any */
1392     unsigned mappearance; /* mimic this */
1393     uchar m_ap_type;      /* what is the thing it is mimicing? */
1394 } qm[] = {
1395     /* Things that some pets might be thinking about at the time */
1396     { PM_LITTLE_DOG, 0, PM_KITTEN, M_AP_MONSTER },
1397     { PM_DOG, 0, PM_HOUSECAT, M_AP_MONSTER },
1398     { PM_LARGE_DOG, 0, PM_LARGE_CAT, M_AP_MONSTER },
1399     { PM_KITTEN, 0, PM_LITTLE_DOG, M_AP_MONSTER },
1400     { PM_HOUSECAT, 0, PM_DOG, M_AP_MONSTER },
1401     { PM_LARGE_CAT, 0, PM_LARGE_DOG, M_AP_MONSTER },
1402     { PM_HOUSECAT, 0, PM_GIANT_RAT, M_AP_MONSTER },
1403     { 0, S_DOG, SINK,
1404       M_AP_FURNITURE }, /* sorry, no fire hydrants in NetHack */
1405     { 0, 0, TRIPE_RATION, M_AP_OBJECT }, /* leave this at end */
1406 };
1407
1408 void
1409 finish_meating(mtmp)
1410 struct monst *mtmp;
1411 {
1412     mtmp->meating = 0;
1413     if (mtmp->m_ap_type && mtmp->mappearance && mtmp->cham == NON_PM) {
1414         /* was eating a mimic and now appearance needs resetting */
1415         mtmp->m_ap_type = 0;
1416         mtmp->mappearance = 0;
1417         newsym(mtmp->mx, mtmp->my);
1418     }
1419 }
1420
1421 STATIC_OVL void
1422 quickmimic(mtmp)
1423 struct monst *mtmp;
1424 {
1425     int idx = 0, trycnt = 5, spotted;
1426     char buf[BUFSZ];
1427
1428     if (Protection_from_shape_changers || !mtmp->meating)
1429         return;
1430
1431     do {
1432         idx = rn2(SIZE(qm));
1433         if (qm[idx].mndx != 0 && monsndx(mtmp->data) == qm[idx].mndx)
1434             break;
1435         if (qm[idx].mlet != 0 && mtmp->data->mlet == qm[idx].mlet)
1436             break;
1437         if (qm[idx].mndx == 0 && qm[idx].mlet == 0)
1438             break;
1439     } while (--trycnt > 0);
1440     if (trycnt == 0)
1441         idx = SIZE(qm) - 1;
1442
1443     Strcpy(buf, mon_nam(mtmp));
1444     spotted = canspotmon(mtmp);
1445
1446     mtmp->m_ap_type = qm[idx].m_ap_type;
1447     mtmp->mappearance = qm[idx].mappearance;
1448
1449     if (spotted || cansee(mtmp->mx, mtmp->my) || canspotmon(mtmp)) {
1450         /* this isn't quite right; if sensing a monster without being
1451            able to see its location, you really shouldn't be told you
1452            sense it becoming furniture or an object that you can't see
1453            (on the other hand, perhaps you're sensing a brief glimpse
1454            of its mind as it changes form) */
1455         newsym(mtmp->mx, mtmp->my);
1456 #if 0 /*JP*/
1457         You("%s %s %sappear%s where %s was!",
1458             cansee(mtmp->mx, mtmp->my) ? "see" : "sense that",
1459             (mtmp->m_ap_type == M_AP_FURNITURE)
1460                 ? an(defsyms[mtmp->mappearance].explanation)
1461                 : (mtmp->m_ap_type == M_AP_OBJECT
1462                    && OBJ_DESCR(objects[mtmp->mappearance]))
1463                       ? an(OBJ_DESCR(objects[mtmp->mappearance]))
1464                       : (mtmp->m_ap_type == M_AP_OBJECT
1465                          && OBJ_NAME(objects[mtmp->mappearance]))
1466                             ? an(OBJ_NAME(objects[mtmp->mappearance]))
1467                             : (mtmp->m_ap_type == M_AP_MONSTER)
1468                                   ? an(mons[mtmp->mappearance].mname)
1469                                   : something,
1470             cansee(mtmp->mx, mtmp->my) ? "" : "has ",
1471             cansee(mtmp->mx, mtmp->my) ? "" : "ed",
1472             buf);
1473 #else
1474         You("%s\82ª\82 \82Á\82½\82Æ\82±\82ë\82É%s\82ª\8c»\82ê\82½\82Ì%s\81I",
1475             buf,
1476             (mtmp->m_ap_type == M_AP_FURNITURE)
1477                 ? an(defsyms[mtmp->mappearance].explanation)
1478                 : (mtmp->m_ap_type == M_AP_OBJECT
1479                    && OBJ_DESCR(objects[mtmp->mappearance]))
1480                       ? an(OBJ_DESCR(objects[mtmp->mappearance]))
1481                       : (mtmp->m_ap_type == M_AP_OBJECT
1482                          && OBJ_NAME(objects[mtmp->mappearance]))
1483                             ? an(OBJ_NAME(objects[mtmp->mappearance]))
1484                             : (mtmp->m_ap_type == M_AP_MONSTER)
1485                                   ? an(mons[mtmp->mappearance].mname)
1486                                   : something,
1487             cansee(mtmp->mx, mtmp->my) ? "\82ð\8c©\82½" : "\82É\8bC\82Ã\82¢\82½");
1488 #endif
1489         display_nhwindow(WIN_MAP, TRUE);
1490     }
1491 }
1492
1493 /*dogmove.c*/