OSDN Git Service

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