OSDN Git Service

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