OSDN Git Service

update year to 2020
[jnethack/source.git] / src / dogmove.c
1 /* NetHack 3.6  dogmove.c       $NHDT-Date: 1557094801 2019/05/05 22:20:01 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.74 $ */
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-2020            */
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:T*/
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:T*/
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:T*/
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 (DEADMONSTER(mtmp))
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 (DEADMONSTER(mtmp))
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
417                    || DEADMONSTER(mtmp)) {
418  dog_died:
419             if (mtmp->mleashed && mtmp != u.usteed)
420 /*JP
421                 Your("leash goes slack.");
422 */
423                 Your("\95R\82Í\82½\82é\82ñ\82¾\81D");
424             else if (cansee(mtmp->mx, mtmp->my))
425 /*JP
426                 pline("%s starves.", Monnam(mtmp));
427 */
428                 pline("%s\82Í\8bQ\82¦\82Å\8e\80\82ñ\82¾\81D", Monnam(mtmp));
429             else
430 #if 0 /*JP:T*/
431                 You_feel("%s for a moment.",
432                          Hallucination ? "bummed" : "sad");
433 #else
434                 You("%s\8bC\95ª\82É\82¨\82»\82í\82ê\82½\81D",
435                     Hallucination ? "\82ª\82Á\82©\82è\82µ\82½" : "\94ß\82µ\82¢");
436 #endif
437             mondied(mtmp);
438             return  TRUE;
439         }
440     }
441     return FALSE;
442 }
443
444 /* do something with object (drop, pick up, eat) at current position
445  * returns 1 if object eaten (since that counts as dog's move), 2 if died
446  */
447 STATIC_OVL int
448 dog_invent(mtmp, edog, udist)
449 register struct monst *mtmp;
450 register struct edog *edog;
451 int udist;
452 {
453     register int omx, omy, carryamt = 0;
454     struct obj *obj, *otmp;
455
456     if (mtmp->msleeping || !mtmp->mcanmove)
457         return 0;
458
459     omx = mtmp->mx;
460     omy = mtmp->my;
461
462     /* If we are carrying something then we drop it (perhaps near @).
463      * Note: if apport == 1 then our behaviour is independent of udist.
464      * Use udist+1 so steed won't cause divide by zero.
465      */
466     if (droppables(mtmp)) {
467         if (!rn2(udist + 1) || !rn2(edog->apport))
468             if (rn2(10) < edog->apport) {
469                 relobj(mtmp, (int) mtmp->minvis, TRUE);
470                 if (edog->apport > 1)
471                     edog->apport--;
472                 edog->dropdist = udist; /* hpscdi!jon */
473                 edog->droptime = monstermoves;
474             }
475     } else {
476         if ((obj = level.objects[omx][omy]) != 0
477             && !index(nofetch, obj->oclass)
478 #ifdef MAIL
479             && obj->otyp != SCR_MAIL
480 #endif
481             ) {
482             int edible = dogfood(mtmp, obj);
483
484             if ((edible <= CADAVER
485                  /* starving pet is more aggressive about eating */
486                  || (edog->mhpmax_penalty && edible == ACCFOOD))
487                 && could_reach_item(mtmp, obj->ox, obj->oy))
488                 return dog_eat(mtmp, obj, omx, omy, FALSE);
489
490             carryamt = can_carry(mtmp, obj);
491             if (carryamt > 0 && !obj->cursed
492                 && could_reach_item(mtmp, obj->ox, obj->oy)) {
493                 if (rn2(20) < edog->apport + 3) {
494                     if (rn2(udist) || !rn2(edog->apport)) {
495                         otmp = obj;
496                         if (carryamt != obj->quan)
497                             otmp = splitobj(obj, carryamt);
498                         if (cansee(omx, omy) && flags.verbose)
499 #if 0 /*JP:T*/
500                             pline("%s picks up %s.", Monnam(mtmp),
501                                   distant_name(otmp, doname));
502 #else
503                             pline("%s\82Í%s\82ð\8fE\82Á\82½\81D", Monnam(mtmp),
504                                   distant_name(obj, doname));
505 #endif
506                         obj_extract_self(otmp);
507                         newsym(omx, omy);
508                         (void) mpickobj(mtmp, otmp);
509                         if (attacktype(mtmp->data, AT_WEAP)
510                             && mtmp->weapon_check == NEED_WEAPON) {
511                             mtmp->weapon_check = NEED_HTH_WEAPON;
512                             (void) mon_wield_item(mtmp);
513                         }
514                         m_dowear(mtmp, FALSE);
515                     }
516                 }
517             }
518         }
519     }
520     return 0;
521 }
522
523 /* set dog's goal -- gtyp, gx, gy;
524    returns -1/0/1 (dog's desire to approach player) or -2 (abort move) */
525 STATIC_OVL int
526 dog_goal(mtmp, edog, after, udist, whappr)
527 register struct monst *mtmp;
528 struct edog *edog;
529 int after, udist, whappr;
530 {
531     register int omx, omy;
532     boolean in_masters_sight, dog_has_minvent;
533     register struct obj *obj;
534     xchar otyp;
535     int appr;
536
537     /* Steeds don't move on their own will */
538     if (mtmp == u.usteed)
539         return -2;
540
541     omx = mtmp->mx;
542     omy = mtmp->my;
543
544     in_masters_sight = couldsee(omx, omy);
545     dog_has_minvent = (droppables(mtmp) != 0);
546
547     if (!edog || mtmp->mleashed) { /* he's not going anywhere... */
548         gtyp = APPORT;
549         gx = u.ux;
550         gy = u.uy;
551     } else {
552 #define DDIST(x, y) (dist2(x, y, omx, omy))
553 #define SQSRCHRADIUS 5
554         int min_x, max_x, min_y, max_y;
555         register int nx, ny;
556
557         gtyp = UNDEF; /* no goal as yet */
558         gx = gy = 0;  /* suppress 'used before set' message */
559
560         if ((min_x = omx - SQSRCHRADIUS) < 1)
561             min_x = 1;
562         if ((max_x = omx + SQSRCHRADIUS) >= COLNO)
563             max_x = COLNO - 1;
564         if ((min_y = omy - SQSRCHRADIUS) < 0)
565             min_y = 0;
566         if ((max_y = omy + SQSRCHRADIUS) >= ROWNO)
567             max_y = ROWNO - 1;
568
569         /* nearby food is the first choice, then other objects */
570         for (obj = fobj; obj; obj = obj->nobj) {
571             nx = obj->ox;
572             ny = obj->oy;
573             if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) {
574                 otyp = dogfood(mtmp, obj);
575                 /* skip inferior goals */
576                 if (otyp > gtyp || otyp == UNDEF)
577                     continue;
578                 /* avoid cursed items unless starving */
579                 if (cursed_object_at(nx, ny)
580                     && !(edog->mhpmax_penalty && otyp < MANFOOD))
581                     continue;
582                 /* skip completely unreachable goals */
583                 if (!could_reach_item(mtmp, nx, ny)
584                     || !can_reach_location(mtmp, mtmp->mx, mtmp->my, nx, ny))
585                     continue;
586                 if (otyp < MANFOOD) {
587                     if (otyp < gtyp || DDIST(nx, ny) < DDIST(gx, gy)) {
588                         gx = nx;
589                         gy = ny;
590                         gtyp = otyp;
591                     }
592                 } else if (gtyp == UNDEF && in_masters_sight
593                            && !dog_has_minvent
594                            && (!levl[omx][omy].lit || levl[u.ux][u.uy].lit)
595                            && (otyp == MANFOOD || m_cansee(mtmp, nx, ny))
596                            && edog->apport > rn2(8)
597                            && can_carry(mtmp, obj) > 0) {
598                     gx = nx;
599                     gy = ny;
600                     gtyp = APPORT;
601                 }
602             }
603         }
604     }
605
606     /* follow player if appropriate */
607     if (gtyp == UNDEF || (gtyp != DOGFOOD && gtyp != APPORT
608                           && monstermoves < edog->hungrytime)) {
609         gx = u.ux;
610         gy = u.uy;
611         if (after && udist <= 4 && gx == u.ux && gy == u.uy)
612             return -2;
613         appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
614         if (udist > 1) {
615             if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) || whappr
616                 || (dog_has_minvent && rn2(edog->apport)))
617                 appr = 1;
618         }
619         /* if you have dog food it'll follow you more closely */
620         if (appr == 0)
621             for (obj = invent; obj; obj = obj->nobj)
622                 if (dogfood(mtmp, obj) == DOGFOOD) {
623                     appr = 1;
624                     break;
625                 }
626     } else
627         appr = 1; /* gtyp != UNDEF */
628     if (mtmp->mconf)
629         appr = 0;
630
631 #define FARAWAY (COLNO + 2) /* position outside screen */
632     if (gx == u.ux && gy == u.uy && !in_masters_sight) {
633         register coord *cp;
634
635         cp = gettrack(omx, omy);
636         if (cp) {
637             gx = cp->x;
638             gy = cp->y;
639             if (edog)
640                 edog->ogoal.x = 0;
641         } else {
642             /* assume master hasn't moved far, and reuse previous goal */
643             if (edog && edog->ogoal.x
644                 && (edog->ogoal.x != omx || edog->ogoal.y != omy)) {
645                 gx = edog->ogoal.x;
646                 gy = edog->ogoal.y;
647                 edog->ogoal.x = 0;
648             } else {
649                 int fardist = FARAWAY * FARAWAY;
650                 gx = gy = FARAWAY; /* random */
651                 do_clear_area(omx, omy, 9, wantdoor, (genericptr_t) &fardist);
652
653                 /* here gx == FARAWAY e.g. when dog is in a vault */
654                 if (gx == FARAWAY || (gx == omx && gy == omy)) {
655                     gx = u.ux;
656                     gy = u.uy;
657                 } else if (edog) {
658                     edog->ogoal.x = gx;
659                     edog->ogoal.y = gy;
660                 }
661             }
662         }
663     } else if (edog) {
664         edog->ogoal.x = 0;
665     }
666     return appr;
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         if (curx == mtmp->mux && cury == mtmp->muy)
698             return &youmonst;
699
700         if ((targ = m_at(curx, cury)) != 0) {
701             /* Is the monster visible to the pet? */
702             if ((!targ->minvis || perceives(mtmp->data))
703                 && !targ->mundetected)
704                 break;
705             /* If the pet can't see it, it assumes it aint there */
706             targ = 0;
707         }
708     }
709     return targ;
710 }
711
712 STATIC_OVL int
713 find_friends(mtmp, mtarg, maxdist)
714 struct monst *mtmp, *mtarg;
715 int    maxdist;
716 {
717     struct monst *pal;
718     int dx = sgn(mtarg->mx - mtmp->mx),
719         dy = sgn(mtarg->my - mtmp->my);
720     int curx = mtarg->mx, cury = mtarg->my;
721     int dist = distmin(mtarg->mx, mtarg->my, mtmp->mx, mtmp->my);
722
723     for ( ; dist <= maxdist; ++dist) {
724         curx += dx;
725         cury += dy;
726
727         if (!isok(curx, cury))
728             return 0;
729
730         /* If the pet can't see beyond this point, don't
731          * check any farther
732          */
733         if (!m_cansee(mtmp, curx, cury))
734             return 0;
735
736         /* Does pet think you're here? */
737         if (mtmp->mux == curx && mtmp->muy == cury)
738             return 1;
739
740         pal = m_at(curx, cury);
741
742         if (pal) {
743             if (pal->mtame) {
744                 /* Pet won't notice invisible pets */
745                 if (!pal->minvis || perceives(mtmp->data))
746                     return 1;
747             } else {
748                 /* Quest leaders and guardians are always seen */
749                 if (pal->data->msound == MS_LEADER
750                     || pal->data->msound == MS_GUARDIAN)
751                     return 1;
752             }
753         }
754     }
755     return 0;
756 }
757
758 STATIC_OVL long
759 score_targ(mtmp, mtarg)
760 struct monst *mtmp, *mtarg;
761 {
762     long score = 0L;
763
764     /* If the monster is confused, normal scoring is disrupted -
765      * anything may happen
766      */
767
768     /* Give 1 in 3 chance of safe breathing even if pet is confused or
769      * if you're on the quest start level */
770     if (!mtmp->mconf || !rn2(3) || Is_qstart(&u.uz)) {
771         int mtmp_lev;
772         aligntyp align1 = A_NONE, align2 = A_NONE; /* For priests, minions */
773         boolean faith1 = TRUE,  faith2 = TRUE;
774
775         if (mtmp->isminion)
776             align1 = EMIN(mtmp)->min_align;
777         else if (mtmp->ispriest)
778             align1 = EPRI(mtmp)->shralign;
779         else
780             faith1 = FALSE;
781         if (mtarg->isminion)
782             align2 = EMIN(mtarg)->min_align; /* MAR */
783         else if (mtarg->ispriest)
784             align2 = EPRI(mtarg)->shralign; /* MAR */
785         else
786             faith2 = FALSE;
787
788         /* Never target quest friendlies */
789         if (mtarg->data->msound == MS_LEADER
790             || mtarg->data->msound == MS_GUARDIAN)
791             return -5000L;
792         /* D: Fixed angelic beings using gaze attacks on coaligned priests */
793         if (faith1 && faith2 && align1 == align2 && mtarg->mpeaceful) {
794             score -= 5000L;
795             return score;
796         }
797         /* Is monster adjacent? */
798         if (distmin(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my) <= 1) {
799             score -= 3000L;
800             return score;
801         }
802         /* Is the monster peaceful or tame? */
803         if (/*mtarg->mpeaceful ||*/ mtarg->mtame || mtarg == &youmonst) {
804             /* Pets will never be targeted */
805             score -= 3000L;
806             return score;
807         }
808         /* Is master/pet behind monster? Check up to 15 squares beyond pet. */
809         if (find_friends(mtmp, mtarg, 15)) {
810             score -= 3000L;
811             return score;
812         }
813         /* Target hostile monsters in preference to peaceful ones */
814         if (!mtarg->mpeaceful)
815             score += 10;
816         /* Is the monster passive? Don't waste energy on it, if so */
817         if (mtarg->data->mattk[0].aatyp == AT_NONE)
818             score -= 1000;
819         /* Even weak pets with breath attacks shouldn't take on very
820            low-level monsters. Wasting breath on lichens is ridiculous. */
821         if ((mtarg->m_lev < 2 && mtmp->m_lev > 5)
822             || (mtmp->m_lev > 12 && mtarg->m_lev < mtmp->m_lev - 9
823                 && u.ulevel > 8 && mtarg->m_lev < u.ulevel - 7))
824             score -= 25;
825         /* for strength purposes, a vampshifter in weak form (vampire bat,
826            fog cloud, maybe wolf) will attack as if in vampire form;
827            otherwise if won't do much and usually wouldn't suffer enough
828            damage (from counterattacks) to switch back to vampire form;
829            make it be more aggressive by behaving as if stronger */
830         mtmp_lev = mtmp->m_lev;
831         if (is_vampshifter(mtmp) && mtmp->data->mlet != S_VAMPIRE) {
832             /* is_vampshifter() implies (mtmp->cham >= LOW_PM) */
833             mtmp_lev = mons[mtmp->cham].mlevel;
834             /* actual vampire level would range from 1.0*mlvl to 1.5*mlvl */
835             mtmp_lev += rn2(mtmp_lev / 2 + 1);
836             /* we don't expect actual level in weak form to exceed
837                base level of strong form, but handle that if it happens */
838             if (mtmp->m_lev > mtmp_lev)
839                 mtmp_lev = mtmp->m_lev;
840         }
841         /* And pets will hesitate to attack vastly stronger foes.
842            This penalty will be discarded if master's in trouble. */
843         if (mtarg->m_lev > mtmp_lev + 4L)
844             score -= (mtarg->m_lev - mtmp_lev) * 20L;
845         /* All things being the same, go for the beefiest monster. This
846            bonus should not be large enough to override the pet's aversion
847            to attacking much stronger monsters. */
848         score += mtarg->m_lev * 2 + mtarg->mhp / 3;
849     }
850     /* Fuzz factor to make things less predictable when very
851        similar targets are abundant. */
852     score += rnd(5);
853     /* Pet may decide not to use ranged attack when confused */
854     if (mtmp->mconf && !rn2(3))
855         score -= 1000;
856     return score;
857 }
858
859 STATIC_OVL struct monst *
860 best_target(mtmp)
861 struct monst *mtmp;   /* Pet */
862 {
863     int dx, dy;
864     long bestscore = -40000L, currscore;
865     struct monst *best_targ = 0, *temp_targ = 0;
866
867     /* Help! */
868     if (!mtmp)
869         return 0;
870
871     /* If the pet is blind, it's not going to see any target */
872     if (!mtmp->mcansee)
873         return 0;
874
875     /* Search for any monsters lined up with the pet, within an arbitrary
876      * distance from the pet (7 squares, even along diagonals). Monsters
877      * are assigned scores and the best score is chosen.
878      */
879     for (dy = -1; dy < 2; ++dy) {
880         for (dx = -1; dx < 2; ++dx) {
881             if (!dx && !dy)
882                 continue;
883             /* Traverse the line to find the first monster within 7
884              * squares. Invisible monsters are skipped (if the
885              * pet doesn't have see invisible).
886              */
887             temp_targ = find_targ(mtmp, dx, dy, 7);
888
889             /* Nothing in this line? */
890             if (!temp_targ)
891                 continue;
892
893             /* Decide how attractive the target is */
894             currscore = score_targ(mtmp, temp_targ);
895
896             if (currscore > bestscore) {
897                 bestscore = currscore;
898                 best_targ = temp_targ;
899             }
900         }
901     }
902
903     /* Filter out targets the pet doesn't like */
904     if (bestscore < 0L)
905         best_targ = 0;
906
907     return best_targ;
908 }
909
910 /* return 0 (no move), 1 (move) or 2 (dead) */
911 int
912 dog_move(mtmp, after)
913 register struct monst *mtmp;
914 int after; /* this is extra fast monster movement */
915 {
916     int omx, omy; /* original mtmp position */
917     int appr, whappr, udist;
918     int i, j, k;
919     register struct edog *edog = EDOG(mtmp);
920     struct obj *obj = (struct obj *) 0;
921     xchar otyp;
922     boolean has_edog, cursemsg[9], do_eat = FALSE;
923     boolean better_with_displacing = FALSE;
924     xchar nix, niy;      /* position mtmp is (considering) moving to */
925     register int nx, ny; /* temporary coordinates */
926     xchar cnt, uncursedcnt, chcnt;
927     int chi = -1, nidist, ndist;
928     coord poss[9];
929     long info[9], allowflags;
930 #define GDIST(x, y) (dist2(x, y, gx, gy))
931
932     /*
933      * Tame Angels have isminion set and an ispriest structure instead of
934      * an edog structure.  Fortunately, guardian Angels need not worry
935      * about mundane things like eating and fetching objects, and can
936      * spend all their energy defending the player.  (They are the only
937      * monsters with other structures that can be tame.)
938      */
939     has_edog = !mtmp->isminion;
940
941     omx = mtmp->mx;
942     omy = mtmp->my;
943     if (has_edog && dog_hunger(mtmp, edog))
944         return 2; /* starved */
945
946     udist = distu(omx, omy);
947     /* Let steeds eat and maybe throw rider during Conflict */
948     if (mtmp == u.usteed) {
949         if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
950             dismount_steed(DISMOUNT_THROWN);
951             return 1;
952         }
953         udist = 1;
954     } else if (!udist)
955         /* maybe we tamed him while being swallowed --jgm */
956         return 0;
957
958     nix = omx; /* set before newdogpos */
959     niy = omy;
960     cursemsg[0] = FALSE; /* lint suppression */
961     info[0] = 0;         /* ditto */
962
963     if (has_edog) {
964         j = dog_invent(mtmp, edog, udist);
965         if (j == 2)
966             return 2; /* died */
967         else if (j == 1)
968             goto newdogpos; /* eating something */
969
970         whappr = (monstermoves - edog->whistletime < 5);
971     } else
972         whappr = 0;
973
974     appr = dog_goal(mtmp, has_edog ? edog : (struct edog *) 0, after, udist,
975                     whappr);
976     if (appr == -2)
977         return 0;
978
979     allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT;
980     if (passes_walls(mtmp->data))
981         allowflags |= (ALLOW_ROCK | ALLOW_WALL);
982     if (passes_bars(mtmp->data))
983         allowflags |= ALLOW_BARS;
984     if (throws_rocks(mtmp->data))
985         allowflags |= ALLOW_ROCK;
986     if (is_displacer(mtmp->data))
987         allowflags |= ALLOW_MDISP;
988     if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
989         allowflags |= ALLOW_U;
990         if (!has_edog) {
991             /* Guardian angel refuses to be conflicted; rather,
992              * it disappears, angrily, and sends in some nasties
993              */
994             lose_guardian_angel(mtmp);
995             return 2; /* current monster is gone */
996         }
997     }
998 #if 0 /* [this is now handled in dochug()] */
999     if (!Conflict && !mtmp->mconf
1000         && mtmp == u.ustuck && !sticks(youmonst.data)) {
1001         unstuck(mtmp); /* swallowed case handled above */
1002 /*JP
1003         You("get released!");
1004 */
1005         You("\93®\82¯\82é\82æ\82¤\82É\82È\82Á\82½\81I");
1006     }
1007 #endif
1008     if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
1009         allowflags |= OPENDOOR;
1010         if (monhaskey(mtmp, TRUE))
1011             allowflags |= UNLOCKDOOR;
1012         /* note:  the Wizard and Riders can unlock doors without a key;
1013            they won't use that ability if someone manages to tame them */
1014     }
1015     if (is_giant(mtmp->data))
1016         allowflags |= BUSTDOOR;
1017     if (tunnels(mtmp->data)
1018         && !Is_rogue_level(&u.uz)) /* same restriction as m_move() */
1019         allowflags |= ALLOW_DIG;
1020     cnt = mfndpos(mtmp, poss, info, allowflags);
1021
1022     /* Normally dogs don't step on cursed items, but if they have no
1023      * other choice they will.  This requires checking ahead of time
1024      * to see how many uncursed item squares are around.
1025      */
1026     uncursedcnt = 0;
1027     for (i = 0; i < cnt; i++) {
1028         nx = poss[i].x;
1029         ny = poss[i].y;
1030         if (MON_AT(nx, ny) && !((info[i] & ALLOW_M) || info[i] & ALLOW_MDISP))
1031             continue;
1032         if (cursed_object_at(nx, ny))
1033             continue;
1034         uncursedcnt++;
1035     }
1036
1037     better_with_displacing = should_displace(mtmp, poss, info, cnt, gx, gy);
1038
1039     chcnt = 0;
1040     chi = -1;
1041     nidist = GDIST(nix, niy);
1042
1043     for (i = 0; i < cnt; i++) {
1044         nx = poss[i].x;
1045         ny = poss[i].y;
1046         cursemsg[i] = FALSE;
1047
1048         /* if leashed, we drag him along. */
1049         if (mtmp->mleashed && distu(nx, ny) > 4)
1050             continue;
1051
1052         /* if a guardian, try to stay close by choice */
1053         if (!has_edog && (j = distu(nx, ny)) > 16 && j >= udist)
1054             continue;
1055
1056         if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) {
1057             int mstatus;
1058             register struct monst *mtmp2 = m_at(nx, ny);
1059
1060             if ((int) mtmp2->m_lev >= (int) mtmp->m_lev + 2
1061                 || (mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10)
1062                     && mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee
1063                     && (perceives(mtmp->data) || !mtmp2->minvis))
1064                 || (mtmp2->data == &mons[PM_GELATINOUS_CUBE] && rn2(10))
1065                 || (max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp)
1066                 || ((mtmp->mhp * 4 < mtmp->mhpmax
1067                      || mtmp2->data->msound == MS_GUARDIAN
1068                      || mtmp2->data->msound == MS_LEADER) && mtmp2->mpeaceful
1069                     && !Conflict)
1070                 || (touch_petrifies(mtmp2->data) && !resists_ston(mtmp)))
1071                 continue;
1072
1073             if (after)
1074                 return 0; /* hit only once each move */
1075
1076             notonhead = 0;
1077             mstatus = mattackm(mtmp, mtmp2);
1078
1079             /* aggressor (pet) died */
1080             if (mstatus & MM_AGR_DIED)
1081                 return 2;
1082
1083             if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) && rn2(4)
1084                 && mtmp2->mlstmv != monstermoves
1085                 && !onscary(mtmp->mx, mtmp->my, mtmp2)
1086                 /* monnear check needed: long worms hit on tail */
1087                 && monnear(mtmp2, mtmp->mx, mtmp->my)) {
1088                 mstatus = mattackm(mtmp2, mtmp); /* return attack */
1089                 if (mstatus & MM_DEF_DIED)
1090                     return 2;
1091             }
1092             return 0;
1093         }
1094         if ((info[i] & ALLOW_MDISP) && MON_AT(nx, ny)
1095             && better_with_displacing && !undesirable_disp(mtmp, nx, ny)) {
1096             int mstatus;
1097             register struct monst *mtmp2 = m_at(nx, ny);
1098
1099             mstatus = mdisplacem(mtmp, mtmp2, FALSE); /* displace monster */
1100             if (mstatus & MM_DEF_DIED)
1101                 return 2;
1102             return 0;
1103         }
1104
1105         {
1106             /* Dog avoids harmful traps, but perhaps it has to pass one
1107              * in order to follow player.  (Non-harmful traps do not
1108              * have ALLOW_TRAPS in info[].)  The dog only avoids the
1109              * trap if you've seen it, unlike enemies who avoid traps
1110              * if they've seen some trap of that type sometime in the
1111              * past.  (Neither behavior is really realistic.)
1112              */
1113             struct trap *trap;
1114
1115             if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx, ny))) {
1116                 if (mtmp->mleashed) {
1117                     if (!Deaf)
1118                         whimper(mtmp);
1119                 } else {
1120                     /* 1/40 chance of stepping on it anyway, in case
1121                      * it has to pass one to follow the player...
1122                      */
1123                     if (trap->tseen && rn2(40))
1124                         continue;
1125                 }
1126             }
1127         }
1128
1129         /* dog eschews cursed objects, but likes dog food */
1130         /* (minion isn't interested; `cursemsg' stays FALSE) */
1131         if (has_edog)
1132             for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) {
1133                 if (obj->cursed) {
1134                     cursemsg[i] = TRUE;
1135                 } else if ((otyp = dogfood(mtmp, obj)) < MANFOOD
1136                          && (otyp < ACCFOOD
1137                              || edog->hungrytime <= monstermoves)) {
1138                     /* Note: our dog likes the food so much that he
1139                      * might eat it even when it conceals a cursed object */
1140                     nix = nx;
1141                     niy = ny;
1142                     chi = i;
1143                     do_eat = TRUE;
1144                     cursemsg[i] = FALSE; /* not reluctant */
1145                     goto newdogpos;
1146                 }
1147             }
1148         /* didn't find something to eat; if we saw a cursed item and
1149            aren't being forced to walk on it, usually keep looking */
1150         if (cursemsg[i] && !mtmp->mleashed && uncursedcnt > 0
1151             && rn2(13 * uncursedcnt))
1152             continue;
1153
1154         /* lessen the chance of backtracking to previous position(s) */
1155         /* This causes unintended issues for pets trying to follow
1156            the hero. Thus, only run it if not leashed and >5 tiles
1157            away. */
1158         if (!mtmp->mleashed && distmin(mtmp->mx, mtmp->my, u.ux, u.uy) > 5) {
1159             k = has_edog ? uncursedcnt : cnt;
1160             for (j = 0; j < MTSZ && j < k - 1; j++)
1161                 if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
1162                     if (rn2(MTSZ * (k - j)))
1163                         goto nxti;
1164         }
1165
1166         j = ((ndist = GDIST(nx, ny)) - nidist) * appr;
1167         if ((j == 0 && !rn2(++chcnt)) || j < 0
1168             || (j > 0 && !whappr
1169                 && ((omx == nix && omy == niy && !rn2(3)) || !rn2(12)))) {
1170             nix = nx;
1171             niy = ny;
1172             nidist = ndist;
1173             if (j < 0)
1174                 chcnt = 0;
1175             chi = i;
1176         }
1177  nxti:
1178         ;
1179     }
1180
1181     /* Pet hasn't attacked anything but is considering moving -
1182      * now's the time for ranged attacks. Note that the pet can move
1183      * after it performs its ranged attack. Should this be changed?
1184      */
1185     {
1186         struct monst *mtarg;
1187         int hungry = 0;
1188
1189         /* How hungry is the pet? */
1190         if (!mtmp->isminion) {
1191             struct edog *dog = EDOG(mtmp);
1192
1193             hungry = (monstermoves > (dog->hungrytime + 300));
1194         }
1195
1196         /* Identify the best target in a straight line from the pet;
1197          * if there is such a target, we'll let the pet attempt an
1198          * attack.
1199          */
1200         mtarg = best_target(mtmp);
1201
1202         /* Hungry pets are unlikely to use breath/spit attacks */
1203         if (mtarg && (!hungry || !rn2(5))) {
1204             int mstatus;
1205
1206             if (mtarg == &youmonst) {
1207                 if (mattacku(mtmp))
1208                     return 2;
1209             } else {
1210                 mstatus = mattackm(mtmp, mtarg);
1211
1212                 /* Shouldn't happen, really */
1213                 if (mstatus & MM_AGR_DIED)
1214                     return 2;
1215
1216                 /* Allow the targeted nasty to strike back - if
1217                  * the targeted beast doesn't have a ranged attack,
1218                  * nothing will happen.
1219                  */
1220                 if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED)
1221                     && rn2(4) && mtarg != &youmonst) {
1222
1223                     /* Can monster see? If it can, it can retaliate
1224                      * even if the pet is invisible, since it'll see
1225                      * the direction from which the ranged attack came;
1226                      * if it's blind or unseeing, it can't retaliate
1227                      */
1228                     if (mtarg->mcansee && haseyes(mtarg->data)) {
1229                         mstatus = mattackm(mtarg, mtmp);
1230                         if (mstatus & MM_DEF_DIED)
1231                             return 2;
1232                     }
1233                 }
1234             }
1235         }
1236     }
1237
1238  newdogpos:
1239     if (nix != omx || niy != omy) {
1240         boolean wasseen;
1241
1242         if (info[chi] & ALLOW_U) {
1243             if (mtmp->mleashed) { /* play it safe */
1244 #if 0 /*JP:T*/
1245                 pline("%s breaks loose of %s leash!", Monnam(mtmp),
1246                       mhis(mtmp));
1247 #else
1248                 pline("%s\82Í\8e©\95ª\82É\82Â\82¢\82Ä\82¢\82é\95R\82ð\82Í\82¸\82µ\82½\81I",
1249                       Monnam(mtmp));
1250 #endif
1251                 m_unleash(mtmp, FALSE);
1252             }
1253             (void) mattacku(mtmp);
1254             return 0;
1255         }
1256         if (!m_in_out_region(mtmp, nix, niy))
1257             return 1;
1258         if (m_digweapon_check(mtmp, nix,niy))
1259             return 0;
1260
1261         /* insert a worm_move() if worms ever begin to eat things */
1262         wasseen = canseemon(mtmp);
1263         remove_monster(omx, omy);
1264         place_monster(mtmp, nix, niy);
1265         if (cursemsg[chi] && (wasseen || canseemon(mtmp))) {
1266             /* describe top item of pile, not necessarily cursed item itself;
1267                don't use glyph_at() here--it would return the pet but we want
1268                to know whether an object is remembered at this map location */
1269             struct obj *o = (!Hallucination && level.flags.hero_memory
1270                              && glyph_is_object(levl[nix][niy].glyph))
1271                                ? vobj_at(nix, niy) : 0;
1272             const char *what = o ? distant_name(o, doname) : something;
1273
1274 #if 0 /*JP:T*/
1275             pline("%s %s reluctantly over %s.", noit_Monnam(mtmp),
1276                   vtense((char *) 0, locomotion(mtmp->data, "step")), what);
1277 #else
1278             pline("%s\82Í%s\82Ì\8fã\82É\82¢\82â\82¢\82â\93®\82¢\82½\81D", noit_Monnam(mtmp), what);
1279 #endif
1280         }
1281         for (j = MTSZ - 1; j > 0; j--)
1282             mtmp->mtrack[j] = mtmp->mtrack[j - 1];
1283         mtmp->mtrack[0].x = omx;
1284         mtmp->mtrack[0].y = omy;
1285         /* We have to know if the pet's going to do a combined eat and
1286          * move before moving it, but it can't eat until after being
1287          * moved.  Thus the do_eat flag.
1288          */
1289         if (do_eat) {
1290             if (dog_eat(mtmp, obj, omx, omy, FALSE) == 2)
1291                 return 2;
1292         }
1293     } else if (mtmp->mleashed && distu(omx, omy) > 4) {
1294         /* an incredible kludge, but the only way to keep pooch near
1295          * after it spends time eating or in a trap, etc.
1296          */
1297         coord cc;
1298
1299         nx = sgn(omx - u.ux);
1300         ny = sgn(omy - u.uy);
1301         cc.x = u.ux + nx;
1302         cc.y = u.uy + ny;
1303         if (goodpos(cc.x, cc.y, mtmp, 0))
1304             goto dognext;
1305
1306         i = xytod(nx, ny);
1307         for (j = (i + 7) % 8; j < (i + 1) % 8; j++) {
1308             dtoxy(&cc, j);
1309             if (goodpos(cc.x, cc.y, mtmp, 0))
1310                 goto dognext;
1311         }
1312         for (j = (i + 6) % 8; j < (i + 2) % 8; j++) {
1313             dtoxy(&cc, j);
1314             if (goodpos(cc.x, cc.y, mtmp, 0))
1315                 goto dognext;
1316         }
1317         cc.x = mtmp->mx;
1318         cc.y = mtmp->my;
1319  dognext:
1320         if (!m_in_out_region(mtmp, nix, niy))
1321             return 1;
1322         remove_monster(mtmp->mx, mtmp->my);
1323         place_monster(mtmp, cc.x, cc.y);
1324         newsym(cc.x, cc.y);
1325         set_apparxy(mtmp);
1326     }
1327     return 1;
1328 }
1329
1330 /* check if a monster could pick up objects from a location */
1331 STATIC_OVL boolean
1332 could_reach_item(mon, nx, ny)
1333 struct monst *mon;
1334 xchar nx, ny;
1335 {
1336     if ((!is_pool(nx, ny) || is_swimmer(mon->data))
1337         && (!is_lava(nx, ny) || likes_lava(mon->data))
1338         && (!sobj_at(BOULDER, nx, ny) || throws_rocks(mon->data)))
1339         return TRUE;
1340     return FALSE;
1341 }
1342
1343 /* Hack to prevent a dog from being endlessly stuck near an object that
1344  * it can't reach, such as caught in a teleport scroll niche.  It recursively
1345  * checks to see if the squares in between are good.  The checking could be
1346  * a little smarter; a full check would probably be useful in m_move() too.
1347  * Since the maximum food distance is 5, this should never be more than 5
1348  * calls deep.
1349  */
1350 STATIC_OVL boolean
1351 can_reach_location(mon, mx, my, fx, fy)
1352 struct monst *mon;
1353 xchar mx, my, fx, fy;
1354 {
1355     int i, j;
1356     int dist;
1357
1358     if (mx == fx && my == fy)
1359         return TRUE;
1360     if (!isok(mx, my))
1361         return FALSE; /* should not happen */
1362
1363     dist = dist2(mx, my, fx, fy);
1364     for (i = mx - 1; i <= mx + 1; i++) {
1365         for (j = my - 1; j <= my + 1; j++) {
1366             if (!isok(i, j))
1367                 continue;
1368             if (dist2(i, j, fx, fy) >= dist)
1369                 continue;
1370             if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data)
1371                 && (!may_dig(i, j) || !tunnels(mon->data)))
1372                 continue;
1373             if (IS_DOOR(levl[i][j].typ)
1374                 && (levl[i][j].doormask & (D_CLOSED | D_LOCKED)))
1375                 continue;
1376             if (!could_reach_item(mon, i, j))
1377                 continue;
1378             if (can_reach_location(mon, i, j, fx, fy))
1379                 return TRUE;
1380         }
1381     }
1382     return FALSE;
1383 }
1384
1385 /* do_clear_area client */
1386 STATIC_PTR void
1387 wantdoor(x, y, distance)
1388 int x, y;
1389 genericptr_t distance;
1390 {
1391     int ndist, *dist_ptr = (int *) distance;
1392
1393     if (*dist_ptr > (ndist = distu(x, y))) {
1394         gx = x;
1395         gy = y;
1396         *dist_ptr = ndist;
1397     }
1398 }
1399
1400 static struct qmchoices {
1401     int mndx;             /* type of pet, 0 means any  */
1402     char mlet;            /* symbol of pet, 0 means any */
1403     unsigned mappearance; /* mimic this */
1404     uchar m_ap_type;      /* what is the thing it is mimicing? */
1405 } qm[] = {
1406     /* Things that some pets might be thinking about at the time */
1407     { PM_LITTLE_DOG, 0, PM_KITTEN, M_AP_MONSTER },
1408     { PM_DOG, 0, PM_HOUSECAT, M_AP_MONSTER },
1409     { PM_LARGE_DOG, 0, PM_LARGE_CAT, M_AP_MONSTER },
1410     { PM_KITTEN, 0, PM_LITTLE_DOG, M_AP_MONSTER },
1411     { PM_HOUSECAT, 0, PM_DOG, M_AP_MONSTER },
1412     { PM_LARGE_CAT, 0, PM_LARGE_DOG, M_AP_MONSTER },
1413     { PM_HOUSECAT, 0, PM_GIANT_RAT, M_AP_MONSTER },
1414     { 0, S_DOG, SINK,
1415       M_AP_FURNITURE }, /* sorry, no fire hydrants in NetHack */
1416     { 0, 0, TRIPE_RATION, M_AP_OBJECT }, /* leave this at end */
1417 };
1418
1419 void
1420 finish_meating(mtmp)
1421 struct monst *mtmp;
1422 {
1423     mtmp->meating = 0;
1424     if (M_AP_TYPE(mtmp) && mtmp->mappearance && mtmp->cham == NON_PM) {
1425         /* was eating a mimic and now appearance needs resetting */
1426         mtmp->m_ap_type = 0;
1427         mtmp->mappearance = 0;
1428         newsym(mtmp->mx, mtmp->my);
1429     }
1430 }
1431
1432 STATIC_OVL void
1433 quickmimic(mtmp)
1434 struct monst *mtmp;
1435 {
1436     int idx = 0, trycnt = 5, spotted;
1437     char buf[BUFSZ];
1438
1439     if (Protection_from_shape_changers || !mtmp->meating)
1440         return;
1441
1442     /* with polymorph, the steed's equipment would be re-checked and its
1443        saddle would come off, triggering DISMOUNT_FELL, but mimicking
1444        doesn't impact monster's equipment; normally DISMOUNT_POLY is for
1445        rider taking on an unsuitable shape, but its message works fine
1446        for this and also avoids inflicting damage during forced dismount;
1447        do this before changing so that dismount refers to original shape */
1448     if (mtmp == u.usteed)
1449         dismount_steed(DISMOUNT_POLY);
1450
1451     do {
1452         idx = rn2(SIZE(qm));
1453         if (qm[idx].mndx != 0 && monsndx(mtmp->data) == qm[idx].mndx)
1454             break;
1455         if (qm[idx].mlet != 0 && mtmp->data->mlet == qm[idx].mlet)
1456             break;
1457         if (qm[idx].mndx == 0 && qm[idx].mlet == 0)
1458             break;
1459     } while (--trycnt > 0);
1460     if (trycnt == 0)
1461         idx = SIZE(qm) - 1;
1462
1463     Strcpy(buf, mon_nam(mtmp));
1464     spotted = canspotmon(mtmp);
1465
1466     mtmp->m_ap_type = qm[idx].m_ap_type;
1467     mtmp->mappearance = qm[idx].mappearance;
1468
1469     if (spotted || cansee(mtmp->mx, mtmp->my) || canspotmon(mtmp)) {
1470         /* this isn't quite right; if sensing a monster without being
1471            able to see its location, you really shouldn't be told you
1472            sense it becoming furniture or an object that you can't see
1473            (on the other hand, perhaps you're sensing a brief glimpse
1474            of its mind as it changes form) */
1475         newsym(mtmp->mx, mtmp->my);
1476 #if 0 /*JP:T*/
1477         You("%s %s %sappear%s where %s was!",
1478             cansee(mtmp->mx, mtmp->my) ? "see" : "sense that",
1479             (M_AP_TYPE(mtmp) == M_AP_FURNITURE)
1480                 ? an(defsyms[mtmp->mappearance].explanation)
1481                 : (M_AP_TYPE(mtmp) == M_AP_OBJECT
1482                    && OBJ_DESCR(objects[mtmp->mappearance]))
1483                       ? an(OBJ_DESCR(objects[mtmp->mappearance]))
1484                       : (M_AP_TYPE(mtmp) == M_AP_OBJECT
1485                          && OBJ_NAME(objects[mtmp->mappearance]))
1486                             ? an(OBJ_NAME(objects[mtmp->mappearance]))
1487                             : (M_AP_TYPE(mtmp) == M_AP_MONSTER)
1488                                   ? an(mons[mtmp->mappearance].mname)
1489                                   : something,
1490             cansee(mtmp->mx, mtmp->my) ? "" : "has ",
1491             cansee(mtmp->mx, mtmp->my) ? "" : "ed",
1492             buf);
1493 #else
1494         You("%s\82ª\82 \82Á\82½\82Æ\82±\82ë\82É%s\82ª\8c»\82ê\82½\82Ì%s\81I",
1495             buf,
1496             (mtmp->m_ap_type == M_AP_FURNITURE)
1497                 ? an(defsyms[mtmp->mappearance].explanation)
1498                 : (mtmp->m_ap_type == M_AP_OBJECT
1499                    && OBJ_DESCR(objects[mtmp->mappearance]))
1500                       ? an(OBJ_DESCR(objects[mtmp->mappearance]))
1501                       : (mtmp->m_ap_type == M_AP_OBJECT
1502                          && OBJ_NAME(objects[mtmp->mappearance]))
1503                             ? an(OBJ_NAME(objects[mtmp->mappearance]))
1504                             : (mtmp->m_ap_type == M_AP_MONSTER)
1505                                   ? an(mons[mtmp->mappearance].mname)
1506                                   : something,
1507             cansee(mtmp->mx, mtmp->my) ? "\82ð\8c©\82½" : "\82É\8bC\82Ã\82¢\82½");
1508 #endif
1509         display_nhwindow(WIN_MAP, TRUE);
1510     }
1511 }
1512
1513 /*dogmove.c*/