OSDN Git Service

patch src/
[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             pline("That %s will cost you %ld %s.", objnambuf, oprice,
336                   currency(oprice));
337             /* delobj->obfree will handle actual shop billing update */
338         }
339         delobj(obj);
340     }
341
342 #if 0 /* pet is eating, so slime recovery is not feasible... */
343     /* turning into slime might be cureable */
344     if (slimer && munslime(mtmp, FALSE)) {
345         /* but the cure (fire directed at self) might be fatal */
346         if (mtmp->mhp < 1)
347             return 2;
348         slimer = FALSE; /* sliming is avoided, skip polymorph */
349     }
350 #endif
351
352     if (poly || slimer) {
353         struct permonst *ptr = slimer ? &mons[PM_GREEN_SLIME] : 0;
354
355         (void) newcham(mtmp, ptr, FALSE, cansee(mtmp->mx, mtmp->my));
356     }
357
358     /* limit "instant" growth to prevent potential abuse */
359     if (grow && (int) mtmp->m_lev < (int) mtmp->data->mlevel + 15) {
360         if (!grow_up(mtmp, (struct monst *) 0))
361             return 2;
362     }
363     if (heal)
364         mtmp->mhp = mtmp->mhpmax;
365     if (deadmimic)
366         quickmimic(mtmp);
367     return 1;
368 }
369
370 /* hunger effects -- returns TRUE on starvation */
371 STATIC_OVL boolean
372 dog_hunger(mtmp, edog)
373 register struct monst *mtmp;
374 register struct edog *edog;
375 {
376     if (monstermoves > edog->hungrytime + 500) {
377         if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) {
378             edog->hungrytime = monstermoves + 500;
379             /* but not too high; it might polymorph */
380         } else if (!edog->mhpmax_penalty) {
381             /* starving pets are limited in healing */
382             int newmhpmax = mtmp->mhpmax / 3;
383             mtmp->mconf = 1;
384             edog->mhpmax_penalty = mtmp->mhpmax - newmhpmax;
385             mtmp->mhpmax = newmhpmax;
386             if (mtmp->mhp > mtmp->mhpmax)
387                 mtmp->mhp = mtmp->mhpmax;
388             if (mtmp->mhp < 1)
389                 goto dog_died;
390             if (cansee(mtmp->mx, mtmp->my))
391 /*JP
392                 pline("%s is confused from hunger.", Monnam(mtmp));
393 */
394                 pline("%s\82Í\8bó\95 \82Ì\82½\82ß\8d¬\97\90\82µ\82Ä\82¢\82é\81D", Monnam(mtmp));
395             else if (couldsee(mtmp->mx, mtmp->my))
396                 beg(mtmp);
397             else
398 /*JP
399                 You_feel("worried about %s.", y_monnam(mtmp));
400 */
401                 You("%s\82ª\90S\94z\82É\82È\82Á\82½\81D", y_monnam(mtmp));
402             stop_occupation();
403         } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) {
404         dog_died:
405             if (mtmp->mleashed && mtmp != u.usteed)
406 /*JP
407                 Your("leash goes slack.");
408 */
409                 Your("\95R\82Í\82½\82é\82ñ\82¾\81D");
410             else if (cansee(mtmp->mx, mtmp->my))
411 /*JP
412                 pline("%s starves.", Monnam(mtmp));
413 */
414                 pline("%s\82Í\8bQ\82¦\82Å\8e\80\82ñ\82¾\81D", Monnam(mtmp));
415             else
416 #if 0 /*JP*/
417                 You_feel("%s for a moment.",
418                          Hallucination ? "bummed" : "sad");
419 #else
420                 You("%s\8bC\95ª\82É\82¨\82»\82í\82ê\82½\81D",
421                     Hallucination ? "\82ª\82Á\82©\82è\82µ\82½" : "\94ß\82µ\82¢");
422 #endif
423             mondied(mtmp);
424             return  TRUE;
425         }
426     }
427     return FALSE;
428 }
429
430 /* do something with object (drop, pick up, eat) at current position
431  * returns 1 if object eaten (since that counts as dog's move), 2 if died
432  */
433 STATIC_OVL int
434 dog_invent(mtmp, edog, udist)
435 register struct monst *mtmp;
436 register struct edog *edog;
437 int udist;
438 {
439     register int omx, omy, carryamt = 0;
440     struct obj *obj, *otmp;
441
442     if (mtmp->msleeping || !mtmp->mcanmove)
443         return 0;
444
445     omx = mtmp->mx;
446     omy = mtmp->my;
447
448     /* if we are carrying something then we drop it (perhaps near @) */
449     /* Note: if apport == 1 then our behaviour is independent of udist */
450     /* Use udist+1 so steed won't cause divide by zero */
451     if (droppables(mtmp)) {
452         if (!rn2(udist + 1) || !rn2(edog->apport))
453             if (rn2(10) < edog->apport) {
454                 relobj(mtmp, (int) mtmp->minvis, TRUE);
455                 if (edog->apport > 1)
456                     edog->apport--;
457                 edog->dropdist = udist; /* hpscdi!jon */
458                 edog->droptime = monstermoves;
459             }
460     } else {
461         if ((obj = level.objects[omx][omy]) && !index(nofetch, obj->oclass)
462 #ifdef MAIL
463             && obj->otyp != SCR_MAIL
464 #endif
465             ) {
466             int edible = dogfood(mtmp, obj);
467
468             if ((edible <= CADAVER
469                  /* starving pet is more aggressive about eating */
470                  || (edog->mhpmax_penalty && edible == ACCFOOD))
471                 && could_reach_item(mtmp, obj->ox, obj->oy))
472                 return dog_eat(mtmp, obj, omx, omy, FALSE);
473
474             carryamt = can_carry(mtmp, obj);
475             if (carryamt > 0 && !obj->cursed
476                 && could_reach_item(mtmp, obj->ox, obj->oy)) {
477                 if (rn2(20) < edog->apport + 3) {
478                     if (rn2(udist) || !rn2(edog->apport)) {
479                         otmp = obj;
480                         if (carryamt != obj->quan)
481                             otmp = splitobj(obj, carryamt);
482                         if (cansee(omx, omy) && flags.verbose)
483 #if 0 /*JP:T*/
484                             pline("%s picks up %s.", Monnam(mtmp),
485                                   distant_name(otmp, doname));
486 #else
487                             pline("%s\82Í%s\82ð\8fE\82Á\82½\81D", Monnam(mtmp),
488                                   distant_name(obj, doname));
489 #endif
490                         obj_extract_self(otmp);
491                         newsym(omx, omy);
492                         (void) mpickobj(mtmp, otmp);
493                         if (attacktype(mtmp->data, AT_WEAP)
494                             && mtmp->weapon_check == NEED_WEAPON) {
495                             mtmp->weapon_check = NEED_HTH_WEAPON;
496                             (void) mon_wield_item(mtmp);
497                         }
498                         m_dowear(mtmp, FALSE);
499                     }
500                 }
501             }
502         }
503     }
504     return 0;
505 }
506
507 /* set dog's goal -- gtyp, gx, gy
508    returns -1/0/1 (dog's desire to approach player) or -2 (abort move) */
509 STATIC_OVL int
510 dog_goal(mtmp, edog, after, udist, whappr)
511 register struct monst *mtmp;
512 struct edog *edog;
513 int after, udist, whappr;
514 {
515     register int omx, omy;
516     boolean in_masters_sight, dog_has_minvent;
517     register struct obj *obj;
518     xchar otyp;
519     int appr;
520
521     /* Steeds don't move on their own will */
522     if (mtmp == u.usteed)
523         return -2;
524
525     omx = mtmp->mx;
526     omy = mtmp->my;
527
528     in_masters_sight = couldsee(omx, omy);
529     dog_has_minvent = (droppables(mtmp) != 0);
530
531     if (!edog || mtmp->mleashed) { /* he's not going anywhere... */
532         gtyp = APPORT;
533         gx = u.ux;
534         gy = u.uy;
535     } else {
536 #define DDIST(x, y) (dist2(x, y, omx, omy))
537 #define SQSRCHRADIUS 5
538         int min_x, max_x, min_y, max_y;
539         register int nx, ny;
540
541         gtyp = UNDEF; /* no goal as yet */
542         gx = gy = 0;  /* suppress 'used before set' message */
543
544         if ((min_x = omx - SQSRCHRADIUS) < 1)
545             min_x = 1;
546         if ((max_x = omx + SQSRCHRADIUS) >= COLNO)
547             max_x = COLNO - 1;
548         if ((min_y = omy - SQSRCHRADIUS) < 0)
549             min_y = 0;
550         if ((max_y = omy + SQSRCHRADIUS) >= ROWNO)
551             max_y = ROWNO - 1;
552
553         /* nearby food is the first choice, then other objects */
554         for (obj = fobj; obj; obj = obj->nobj) {
555             nx = obj->ox;
556             ny = obj->oy;
557             if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) {
558                 otyp = dogfood(mtmp, obj);
559                 /* skip inferior goals */
560                 if (otyp > gtyp || otyp == UNDEF)
561                     continue;
562                 /* avoid cursed items unless starving */
563                 if (cursed_object_at(nx, ny)
564                     && !(edog->mhpmax_penalty && otyp < MANFOOD))
565                     continue;
566                 /* skip completely unreachable goals */
567                 if (!could_reach_item(mtmp, nx, ny)
568                     || !can_reach_location(mtmp, mtmp->mx, mtmp->my, nx, ny))
569                     continue;
570                 if (otyp < MANFOOD) {
571                     if (otyp < gtyp || DDIST(nx, ny) < DDIST(gx, gy)) {
572                         gx = nx;
573                         gy = ny;
574                         gtyp = otyp;
575                     }
576                 } else if (gtyp == UNDEF && in_masters_sight
577                            && !dog_has_minvent
578                            && (!levl[omx][omy].lit || levl[u.ux][u.uy].lit)
579                            && (otyp == MANFOOD || m_cansee(mtmp, nx, ny))
580                            && edog->apport > rn2(8)
581                            && can_carry(mtmp, obj) > 0) {
582                     gx = nx;
583                     gy = ny;
584                     gtyp = APPORT;
585                 }
586             }
587         }
588     }
589
590     /* follow player if appropriate */
591     if (gtyp == UNDEF || (gtyp != DOGFOOD && gtyp != APPORT
592                           && monstermoves < edog->hungrytime)) {
593         gx = u.ux;
594         gy = u.uy;
595         if (after && udist <= 4 && gx == u.ux && gy == u.uy)
596             return -2;
597         appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
598         if (udist > 1) {
599             if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) || whappr
600                 || (dog_has_minvent && rn2(edog->apport)))
601                 appr = 1;
602         }
603         /* if you have dog food it'll follow you more closely */
604         if (appr == 0) {
605             obj = invent;
606             while (obj) {
607                 if (dogfood(mtmp, obj) == DOGFOOD) {
608                     appr = 1;
609                     break;
610                 }
611                 obj = obj->nobj;
612             }
613         }
614     } else
615         appr = 1; /* gtyp != UNDEF */
616     if (mtmp->mconf)
617         appr = 0;
618
619 #define FARAWAY (COLNO + 2) /* position outside screen */
620     if (gx == u.ux && gy == u.uy && !in_masters_sight) {
621         register coord *cp;
622
623         cp = gettrack(omx, omy);
624         if (cp) {
625             gx = cp->x;
626             gy = cp->y;
627             if (edog)
628                 edog->ogoal.x = 0;
629         } else {
630             /* assume master hasn't moved far, and reuse previous goal */
631             if (edog && edog->ogoal.x
632                 && ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) {
633                 gx = edog->ogoal.x;
634                 gy = edog->ogoal.y;
635                 edog->ogoal.x = 0;
636             } else {
637                 int fardist = FARAWAY * FARAWAY;
638                 gx = gy = FARAWAY; /* random */
639                 do_clear_area(omx, omy, 9, wantdoor, (genericptr_t) &fardist);
640
641                 /* here gx == FARAWAY e.g. when dog is in a vault */
642                 if (gx == FARAWAY || (gx == omx && gy == omy)) {
643                     gx = u.ux;
644                     gy = u.uy;
645                 } else if (edog) {
646                     edog->ogoal.x = gx;
647                     edog->ogoal.y = gy;
648                 }
649             }
650         }
651     } else if (edog) {
652         edog->ogoal.x = 0;
653     }
654     return appr;
655 }
656
657 /* return 0 (no move), 1 (move) or 2 (dead) */
658 int
659 dog_move(mtmp, after)
660 register struct monst *mtmp;
661 register int after; /* this is extra fast monster movement */
662 {
663     int omx, omy; /* original mtmp position */
664     int appr, whappr, udist;
665     int i, j, k;
666     register struct edog *edog = EDOG(mtmp);
667     struct obj *obj = (struct obj *) 0;
668     xchar otyp;
669     boolean has_edog, cursemsg[9], do_eat = FALSE;
670     boolean better_with_displacing = FALSE;
671     xchar nix, niy;      /* position mtmp is (considering) moving to */
672     register int nx, ny; /* temporary coordinates */
673     xchar cnt, uncursedcnt, chcnt;
674     int chi = -1, nidist, ndist;
675     coord poss[9];
676     long info[9], allowflags;
677 #define GDIST(x, y) (dist2(x, y, gx, gy))
678
679     /*
680      * Tame Angels have isminion set and an ispriest structure instead of
681      * an edog structure.  Fortunately, guardian Angels need not worry
682      * about mundane things like eating and fetching objects, and can
683      * spend all their energy defending the player.  (They are the only
684      * monsters with other structures that can be tame.)
685      */
686     has_edog = !mtmp->isminion;
687
688     omx = mtmp->mx;
689     omy = mtmp->my;
690     if (has_edog && dog_hunger(mtmp, edog))
691         return 2; /* starved */
692
693     udist = distu(omx, omy);
694     /* Let steeds eat and maybe throw rider during Conflict */
695     if (mtmp == u.usteed) {
696         if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
697             dismount_steed(DISMOUNT_THROWN);
698             return 1;
699         }
700         udist = 1;
701     } else if (!udist)
702         /* maybe we tamed him while being swallowed --jgm */
703         return 0;
704
705     nix = omx; /* set before newdogpos */
706     niy = omy;
707     cursemsg[0] = FALSE; /* lint suppression */
708     info[0] = 0;         /* ditto */
709
710     if (has_edog) {
711         j = dog_invent(mtmp, edog, udist);
712         if (j == 2)
713             return 2; /* died */
714         else if (j == 1)
715             goto newdogpos; /* eating something */
716
717         whappr = (monstermoves - edog->whistletime < 5);
718     } else
719         whappr = 0;
720
721     appr = dog_goal(mtmp, has_edog ? edog : (struct edog *) 0, after, udist,
722                     whappr);
723     if (appr == -2)
724         return 0;
725
726     allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT;
727     if (passes_walls(mtmp->data))
728         allowflags |= (ALLOW_ROCK | ALLOW_WALL);
729     if (passes_bars(mtmp->data))
730         allowflags |= ALLOW_BARS;
731     if (throws_rocks(mtmp->data))
732         allowflags |= ALLOW_ROCK;
733     if (is_displacer(mtmp->data))
734         allowflags |= ALLOW_MDISP;
735     if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
736         allowflags |= ALLOW_U;
737         if (!has_edog) {
738             /* Guardian angel refuses to be conflicted; rather,
739              * it disappears, angrily, and sends in some nasties
740              */
741             lose_guardian_angel(mtmp);
742             return 2; /* current monster is gone */
743         }
744     }
745 #if 0 /* [this is now handled in dochug()] */
746     if (!Conflict && !mtmp->mconf
747         && mtmp == u.ustuck && !sticks(youmonst.data)) {
748         unstuck(mtmp); /* swallowed case handled above */
749 /*JP
750         You("get released!");
751 */
752         You("\93®\82¯\82é\82æ\82¤\82É\82È\82Á\82½\81I");
753     }
754 #endif
755     if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
756         allowflags |= OPENDOOR;
757         if (monhaskey(mtmp, TRUE))
758             allowflags |= UNLOCKDOOR;
759         /* note:  the Wizard and Riders can unlock doors without a key;
760            they won't use that ability if someone manages to tame them */
761     }
762     if (is_giant(mtmp->data))
763         allowflags |= BUSTDOOR;
764     if (tunnels(mtmp->data)
765         && !Is_rogue_level(&u.uz)) /* same restriction as m_move() */
766         allowflags |= ALLOW_DIG;
767     cnt = mfndpos(mtmp, poss, info, allowflags);
768
769     /* Normally dogs don't step on cursed items, but if they have no
770      * other choice they will.  This requires checking ahead of time
771      * to see how many uncursed item squares are around.
772      */
773     uncursedcnt = 0;
774     for (i = 0; i < cnt; i++) {
775         nx = poss[i].x;
776         ny = poss[i].y;
777         if (MON_AT(nx, ny) && !((info[i] & ALLOW_M) || info[i] & ALLOW_MDISP))
778             continue;
779         if (cursed_object_at(nx, ny))
780             continue;
781         uncursedcnt++;
782     }
783
784     better_with_displacing = should_displace(mtmp, poss, info, cnt, gx, gy);
785
786     chcnt = 0;
787     chi = -1;
788     nidist = GDIST(nix, niy);
789
790     for (i = 0; i < cnt; i++) {
791         nx = poss[i].x;
792         ny = poss[i].y;
793         cursemsg[i] = FALSE;
794
795         /* if leashed, we drag him along. */
796         if (mtmp->mleashed && distu(nx, ny) > 4)
797             continue;
798
799         /* if a guardian, try to stay close by choice */
800         if (!has_edog && (j = distu(nx, ny)) > 16 && j >= udist)
801             continue;
802
803         if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) {
804             int mstatus;
805             register struct monst *mtmp2 = m_at(nx, ny);
806
807             if ((int) mtmp2->m_lev >= (int) mtmp->m_lev + 2
808                 || (mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10)
809                     && mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee
810                     && (perceives(mtmp->data) || !mtmp2->minvis))
811                 || (mtmp2->data == &mons[PM_GELATINOUS_CUBE] && rn2(10))
812                 || (max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp)
813                 || ((mtmp->mhp * 4 < mtmp->mhpmax
814                      || mtmp2->data->msound == MS_GUARDIAN
815                      || mtmp2->data->msound == MS_LEADER) && mtmp2->mpeaceful
816                     && !Conflict)
817                 || (touch_petrifies(mtmp2->data) && !resists_ston(mtmp)))
818                 continue;
819
820             if (after)
821                 return 0; /* hit only once each move */
822
823             notonhead = 0;
824             mstatus = mattackm(mtmp, mtmp2);
825
826             /* aggressor (pet) died */
827             if (mstatus & MM_AGR_DIED)
828                 return 2;
829
830             if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) && rn2(4)
831                 && mtmp2->mlstmv != monstermoves
832                 && !onscary(mtmp->mx, mtmp->my, mtmp2)
833                 /* monnear check needed: long worms hit on tail */
834                 && monnear(mtmp2, mtmp->mx, mtmp->my)) {
835                 mstatus = mattackm(mtmp2, mtmp); /* return attack */
836                 if (mstatus & MM_DEF_DIED)
837                     return 2;
838             }
839             return 0;
840         }
841         if ((info[i] & ALLOW_MDISP) && MON_AT(nx, ny)
842             && better_with_displacing && !undesirable_disp(mtmp, nx, ny)) {
843             int mstatus;
844             register struct monst *mtmp2 = m_at(nx, ny);
845             mstatus = mdisplacem(mtmp, mtmp2, FALSE); /* displace monster */
846             if (mstatus & MM_DEF_DIED)
847                 return 2;
848             return 0;
849         }
850
851         {
852             /* Dog avoids harmful traps, but perhaps it has to pass one
853              * in order to follow player.  (Non-harmful traps do not
854              * have ALLOW_TRAPS in info[].)  The dog only avoids the
855              * trap if you've seen it, unlike enemies who avoid traps
856              * if they've seen some trap of that type sometime in the
857              * past.  (Neither behavior is really realistic.)
858              */
859             struct trap *trap;
860
861             if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx, ny))) {
862                 if (mtmp->mleashed) {
863                     if (!Deaf)
864                         whimper(mtmp);
865                 } else
866                     /* 1/40 chance of stepping on it anyway, in case
867                      * it has to pass one to follow the player...
868                      */
869                     if (trap->tseen && rn2(40))
870                     continue;
871             }
872         }
873
874         /* dog eschews cursed objects, but likes dog food */
875         /* (minion isn't interested; `cursemsg' stays FALSE) */
876         if (has_edog)
877             for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) {
878                 if (obj->cursed)
879                     cursemsg[i] = TRUE;
880                 else if ((otyp = dogfood(mtmp, obj)) < MANFOOD
881                          && (otyp < ACCFOOD
882                              || edog->hungrytime <= monstermoves)) {
883                     /* Note: our dog likes the food so much that he
884                      * might eat it even when it conceals a cursed object */
885                     nix = nx;
886                     niy = ny;
887                     chi = i;
888                     do_eat = TRUE;
889                     cursemsg[i] = FALSE; /* not reluctant */
890                     goto newdogpos;
891                 }
892             }
893         /* didn't find something to eat; if we saw a cursed item and
894            aren't being forced to walk on it, usually keep looking */
895         if (cursemsg[i] && !mtmp->mleashed && uncursedcnt > 0
896             && rn2(13 * uncursedcnt))
897             continue;
898
899         /* lessen the chance of backtracking to previous position(s) */
900         k = has_edog ? uncursedcnt : cnt;
901         for (j = 0; j < MTSZ && j < k - 1; j++)
902             if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
903                 if (rn2(MTSZ * (k - j)))
904                     goto nxti;
905
906         j = ((ndist = GDIST(nx, ny)) - nidist) * appr;
907         if ((j == 0 && !rn2(++chcnt)) || j < 0
908             || (j > 0 && !whappr
909                 && ((omx == nix && omy == niy && !rn2(3)) || !rn2(12)))) {
910             nix = nx;
911             niy = ny;
912             nidist = ndist;
913             if (j < 0)
914                 chcnt = 0;
915             chi = i;
916         }
917     nxti:
918         ;
919     }
920 newdogpos:
921     if (nix != omx || niy != omy) {
922         struct obj *mw_tmp;
923         boolean wasseen;
924
925         if (info[chi] & ALLOW_U) {
926             if (mtmp->mleashed) { /* play it safe */
927 #if 0 /*JP:T*/
928                 pline("%s breaks loose of %s leash!", Monnam(mtmp),
929                       mhis(mtmp));
930 #else
931                 pline("%s\82Í\8e©\95ª\82É\82Â\82¢\82Ä\82¢\82é\95R\82ð\82Í\82¸\82µ\82½\81I",
932                       Monnam(mtmp));
933 #endif
934                 m_unleash(mtmp, FALSE);
935             }
936             (void) mattacku(mtmp);
937             return 0;
938         }
939         if (!m_in_out_region(mtmp, nix, niy))
940             return 1;
941         if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix, niy))
942              || closed_door(nix, niy))
943             && mtmp->weapon_check != NO_WEAPON_WANTED
944             && tunnels(mtmp->data) && needspick(mtmp->data)) {
945             if (closed_door(nix, niy)) {
946                 if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)
947                     || !is_axe(mw_tmp))
948                     mtmp->weapon_check = NEED_PICK_OR_AXE;
949             } else if (IS_TREE(levl[nix][niy].typ)) {
950                 if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp))
951                     mtmp->weapon_check = NEED_AXE;
952             } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) {
953                 mtmp->weapon_check = NEED_PICK_AXE;
954             }
955             if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp))
956                 return 0;
957         }
958         /* insert a worm_move() if worms ever begin to eat things */
959         wasseen = canseemon(mtmp);
960         remove_monster(omx, omy);
961         place_monster(mtmp, nix, niy);
962         if (cursemsg[chi] && (wasseen || canseemon(mtmp)))
963 /*JP
964             pline("%s moves only reluctantly.", noit_Monnam(mtmp));
965 */
966             pline("%s\82Í\82¢\82â\82¢\82â\93®\82¢\82½\81D", Monnam(mtmp));
967         for (j = MTSZ - 1; j > 0; j--)
968             mtmp->mtrack[j] = mtmp->mtrack[j - 1];
969         mtmp->mtrack[0].x = omx;
970         mtmp->mtrack[0].y = omy;
971         /* We have to know if the pet's gonna do a combined eat and
972          * move before moving it, but it can't eat until after being
973          * moved.  Thus the do_eat flag.
974          */
975         if (do_eat) {
976             if (dog_eat(mtmp, obj, omx, omy, FALSE) == 2)
977                 return 2;
978         }
979     } else if (mtmp->mleashed && distu(omx, omy) > 4) {
980         /* an incredible kludge, but the only way to keep pooch near
981          * after it spends time eating or in a trap, etc.
982          */
983         coord cc;
984
985         nx = sgn(omx - u.ux);
986         ny = sgn(omy - u.uy);
987         cc.x = u.ux + nx;
988         cc.y = u.uy + ny;
989         if (goodpos(cc.x, cc.y, mtmp, 0))
990             goto dognext;
991
992         i = xytod(nx, ny);
993         for (j = (i + 7) % 8; j < (i + 1) % 8; j++) {
994             dtoxy(&cc, j);
995             if (goodpos(cc.x, cc.y, mtmp, 0))
996                 goto dognext;
997         }
998         for (j = (i + 6) % 8; j < (i + 2) % 8; j++) {
999             dtoxy(&cc, j);
1000             if (goodpos(cc.x, cc.y, mtmp, 0))
1001                 goto dognext;
1002         }
1003         cc.x = mtmp->mx;
1004         cc.y = mtmp->my;
1005     dognext:
1006         if (!m_in_out_region(mtmp, nix, niy))
1007             return 1;
1008         remove_monster(mtmp->mx, mtmp->my);
1009         place_monster(mtmp, cc.x, cc.y);
1010         newsym(cc.x, cc.y);
1011         set_apparxy(mtmp);
1012     }
1013     return 1;
1014 }
1015
1016 /* check if a monster could pick up objects from a location */
1017 STATIC_OVL boolean
1018 could_reach_item(mon, nx, ny)
1019 struct monst *mon;
1020 xchar nx, ny;
1021 {
1022     if ((!is_pool(nx, ny) || is_swimmer(mon->data))
1023         && (!is_lava(nx, ny) || likes_lava(mon->data))
1024         && (!sobj_at(BOULDER, nx, ny) || throws_rocks(mon->data)))
1025         return TRUE;
1026     return FALSE;
1027 }
1028
1029 /* Hack to prevent a dog from being endlessly stuck near an object that
1030  * it can't reach, such as caught in a teleport scroll niche.  It recursively
1031  * checks to see if the squares in between are good.  The checking could be
1032  * a little smarter; a full check would probably be useful in m_move() too.
1033  * Since the maximum food distance is 5, this should never be more than 5
1034  * calls deep.
1035  */
1036 STATIC_OVL boolean
1037 can_reach_location(mon, mx, my, fx, fy)
1038 struct monst *mon;
1039 xchar mx, my, fx, fy;
1040 {
1041     int i, j;
1042     int dist;
1043
1044     if (mx == fx && my == fy)
1045         return TRUE;
1046     if (!isok(mx, my))
1047         return FALSE; /* should not happen */
1048
1049     dist = dist2(mx, my, fx, fy);
1050     for (i = mx - 1; i <= mx + 1; i++) {
1051         for (j = my - 1; j <= my + 1; j++) {
1052             if (!isok(i, j))
1053                 continue;
1054             if (dist2(i, j, fx, fy) >= dist)
1055                 continue;
1056             if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data)
1057                 && (!may_dig(i, j) || !tunnels(mon->data)))
1058                 continue;
1059             if (IS_DOOR(levl[i][j].typ)
1060                 && (levl[i][j].doormask & (D_CLOSED | D_LOCKED)))
1061                 continue;
1062             if (!could_reach_item(mon, i, j))
1063                 continue;
1064             if (can_reach_location(mon, i, j, fx, fy))
1065                 return TRUE;
1066         }
1067     }
1068     return FALSE;
1069 }
1070
1071 /*ARGSUSED*/ /* do_clear_area client */
1072 STATIC_PTR void
1073 wantdoor(x, y, distance)
1074 int x, y;
1075 genericptr_t distance;
1076 {
1077     int ndist;
1078
1079     if (*(int *) distance > (ndist = distu(x, y))) {
1080         gx = x;
1081         gy = y;
1082         *(int *) distance = ndist;
1083     }
1084 }
1085
1086 static struct qmchoices {
1087     int mndx;             /* type of pet, 0 means any  */
1088     char mlet;            /* symbol of pet, 0 means any */
1089     unsigned mappearance; /* mimic this */
1090     uchar m_ap_type;      /* what is the thing it is mimicing? */
1091 } qm[] = {
1092     /* Things that some pets might be thinking about at the time */
1093     { PM_LITTLE_DOG, 0, PM_KITTEN, M_AP_MONSTER },
1094     { PM_DOG, 0, PM_HOUSECAT, M_AP_MONSTER },
1095     { PM_LARGE_DOG, 0, PM_LARGE_CAT, M_AP_MONSTER },
1096     { PM_KITTEN, 0, PM_LITTLE_DOG, M_AP_MONSTER },
1097     { PM_HOUSECAT, 0, PM_DOG, M_AP_MONSTER },
1098     { PM_LARGE_CAT, 0, PM_LARGE_DOG, M_AP_MONSTER },
1099     { PM_HOUSECAT, 0, PM_GIANT_RAT, M_AP_MONSTER },
1100     { 0, S_DOG, SINK,
1101       M_AP_FURNITURE }, /* sorry, no fire hydrants in NetHack */
1102     { 0, 0, TRIPE_RATION, M_AP_OBJECT }, /* leave this at end */
1103 };
1104
1105 void
1106 finish_meating(mtmp)
1107 struct monst *mtmp;
1108 {
1109     mtmp->meating = 0;
1110     if (mtmp->m_ap_type && mtmp->mappearance && mtmp->cham == NON_PM) {
1111         /* was eating a mimic and now appearance needs resetting */
1112         mtmp->m_ap_type = 0;
1113         mtmp->mappearance = 0;
1114         newsym(mtmp->mx, mtmp->my);
1115     }
1116 }
1117
1118 STATIC_OVL void
1119 quickmimic(mtmp)
1120 struct monst *mtmp;
1121 {
1122     int idx = 0, trycnt = 5, spotted;
1123     char buf[BUFSZ];
1124
1125     if (Protection_from_shape_changers || !mtmp->meating)
1126         return;
1127
1128     do {
1129         idx = rn2(SIZE(qm));
1130         if (qm[idx].mndx != 0 && monsndx(mtmp->data) == qm[idx].mndx)
1131             break;
1132         if (qm[idx].mlet != 0 && mtmp->data->mlet == qm[idx].mlet)
1133             break;
1134         if (qm[idx].mndx == 0 && qm[idx].mlet == 0)
1135             break;
1136     } while (--trycnt > 0);
1137     if (trycnt == 0)
1138         idx = SIZE(qm) - 1;
1139
1140     Strcpy(buf, mon_nam(mtmp));
1141     spotted = canspotmon(mtmp);
1142
1143     mtmp->m_ap_type = qm[idx].m_ap_type;
1144     mtmp->mappearance = qm[idx].mappearance;
1145
1146     if (spotted || cansee(mtmp->mx, mtmp->my) || canspotmon(mtmp)) {
1147         /* this isn't quite right; if sensing a monster without being
1148            able to see its location, you really shouldn't be told you
1149            sense it becoming furniture or an object that you can't see
1150            (on the other hand, perhaps you're sensing a brief glimpse
1151            of its mind as it changes form) */
1152         newsym(mtmp->mx, mtmp->my);
1153         You("%s %s appear where %s was!",
1154             cansee(mtmp->mx, mtmp->my) ? "see" : "sense",
1155             (mtmp->m_ap_type == M_AP_FURNITURE)
1156                 ? an(defsyms[mtmp->mappearance].explanation)
1157                 : (mtmp->m_ap_type == M_AP_OBJECT
1158                    && OBJ_DESCR(objects[mtmp->mappearance]))
1159                       ? an(OBJ_DESCR(objects[mtmp->mappearance]))
1160                       : (mtmp->m_ap_type == M_AP_OBJECT
1161                          && OBJ_NAME(objects[mtmp->mappearance]))
1162                             ? an(OBJ_NAME(objects[mtmp->mappearance]))
1163                             : (mtmp->m_ap_type == M_AP_MONSTER)
1164                                   ? an(mons[mtmp->mappearance].mname)
1165                                   : something,
1166             buf);
1167         display_nhwindow(WIN_MAP, TRUE);
1168     }
1169 }
1170
1171 /*dogmove.c*/