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. */
9 extern boolean notonhead;
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 *));
19 /* pick a carried item for pet to drop */
24 struct obj *obj, *wep, dummy, *pickaxe, *unihorn, *key;
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;
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 */
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))
39 /* don't hang on to key if can't open doors */
40 if (nohands(mon->data) || verysmall(mon->data))
46 if (wep->otyp == UNICORN_HORN)
48 /* don't need any wielded check for keys... */
51 for (obj = mon->minvent; obj; obj = obj->nobj) {
53 case DWARVISH_MATTOCK:
54 /* reject mattock if couldn't wield it */
55 if (which_armor(mon, W_ARMS))
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 */
64 if (!pickaxe || (obj->oartifact && !pickaxe->oartifact)) {
67 pickaxe = obj; /* keep this digging tool */
73 /* reject cursed unicorn horns */
76 /* keep artifact unihorn in preference to ordinary one */
77 if (!unihorn || (obj->oartifact && !unihorn->oartifact)) {
80 unihorn = obj; /* keep this unicorn horn */
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 */
92 /* keep lock-pick in preference to credit card */
93 if (key && key->otyp == CREDIT_CARD
94 && (!key->oartifact || obj->oartifact))
98 if (!key || (obj->oartifact && !key->oartifact)) {
101 key = obj; /* keep this unlocking tool */
110 if (!obj->owornmask && obj != wep)
114 return (struct obj *) 0; /* don't drop anything */
117 static NEARDATA const char nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS,
120 STATIC_VAR xchar gtyp, gx, gy; /* type and position of dog's current goal */
122 STATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t));
125 cursed_object_at(x, y)
130 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
137 dog_nutrition(mtmp, obj)
144 * It is arbitrary that the pet takes the same length of time to eat
145 * as a human, but gets more nutritional value.
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;
152 mtmp->meating = objects[obj->otyp].oc_delay;
153 nutrit = objects[obj->otyp].oc_nutrition;
155 switch (mtmp->data->msize) {
177 mtmp->meating = eaten_stat(mtmp->meating, obj);
178 nutrit = eaten_stat(nutrit, obj);
180 } else if (obj->oclass == COIN_CLASS) {
181 mtmp->meating = (int) (obj->quan / 2000) + 1;
182 if (mtmp->meating < 0)
184 nutrit = (int) (obj->quan / 20);
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.)
193 mtmp->meating = obj->owt / 20 + 1;
194 nutrit = 5 * objects[obj->otyp].oc_nutrition;
199 /* returns 2 if pet dies, otherwise 1 */
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 */
207 register struct edog *edog = EDOG(mtmp);
208 boolean poly, grow, heal, slimer, deadmimic;
211 char objnambuf[BUFSZ];
214 if (edog->hungrytime < monstermoves)
215 edog->hungrytime = monstermoves;
216 nutrit = dog_nutrition(mtmp, obj);
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);
227 if (mtmp->meating > 1)
230 nutrit = (nutrit * 3) / 4;
232 edog->hungrytime += nutrit;
234 if (edog->mhpmax_penalty) {
235 /* no longer starving */
236 mtmp->mhpmax += edog->mhpmax_penalty;
237 edog->mhpmax_penalty = 0;
239 if (mtmp->mflee && mtmp->mfleetim > 1)
241 if (mtmp->mtame < 20)
243 if (x != mtmp->mx || y != mtmp->my) { /* moved & ate on same turn */
245 newsym(mtmp->mx, mtmp->my);
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);
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) */
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);
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));
273 pline("%s %s %s.", noit_Monnam(mtmp),
274 devour ? "devours" : "eats", distant_name(obj, doname));
276 pline("It %s %s.", devour ? "devours" : "eats",
277 distant_name(obj, doname));
280 Strcpy(objnambuf, xname(obj));
281 iflags.suppress_price--;
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)
289 edog->apport += (int) (200L / ((long) edog->dropdist + monstermoves
292 if (mtmp->data == &mons[PM_RUST_MONSTER] && obj->oerodeproof) {
293 /* The object's rustproofing is gone now */
295 costly_alteration(obj, COST_DEGRD);
296 obj->oerodeproof = 0;
298 if (canseemon(mtmp) && flags.verbose) {
299 pline("%s spits %s out in disgust!", Monnam(mtmp),
300 distant_name(obj, doname));
302 } else if (obj == uball) {
304 delobj(obj); /* we assume this can't be unpaid */
305 } else if (obj == uchain) {
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,
314 /* delobj->obfree will handle actual shop billing update */
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 */
325 slimer = FALSE; /* sliming is avoided, skip polymorph */
329 if (poly || slimer) {
330 struct permonst *ptr = slimer ? &mons[PM_GREEN_SLIME] : 0;
332 (void) newcham(mtmp, ptr, FALSE, cansee(mtmp->mx, mtmp->my));
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))
341 mtmp->mhp = mtmp->mhpmax;
347 /* hunger effects -- returns TRUE on starvation */
349 dog_hunger(mtmp, edog)
350 register struct monst *mtmp;
351 register struct edog *edog;
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;
361 edog->mhpmax_penalty = mtmp->mhpmax - newmhpmax;
362 mtmp->mhpmax = newmhpmax;
363 if (mtmp->mhp > mtmp->mhpmax)
364 mtmp->mhp = mtmp->mhpmax;
367 if (cansee(mtmp->mx, mtmp->my))
368 pline("%s is confused from hunger.", Monnam(mtmp));
369 else if (couldsee(mtmp->mx, mtmp->my))
372 You_feel("worried about %s.", y_monnam(mtmp));
374 } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) {
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));
381 You_feel("%s for a moment.",
382 Hallucination ? "bummed" : "sad");
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
394 dog_invent(mtmp, edog, udist)
395 register struct monst *mtmp;
396 register struct edog *edog;
399 register int omx, omy, carryamt = 0;
400 struct obj *obj, *otmp;
402 if (mtmp->msleeping || !mtmp->mcanmove)
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)
417 edog->dropdist = udist; /* hpscdi!jon */
418 edog->droptime = monstermoves;
421 if ((obj = level.objects[omx][omy]) && !index(nofetch, obj->oclass)
423 && obj->otyp != SCR_MAIL
426 int edible = dogfood(mtmp, obj);
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);
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)) {
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);
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);
453 m_dowear(mtmp, FALSE);
462 /* set dog's goal -- gtyp, gx, gy
463 returns -1/0/1 (dog's desire to approach player) or -2 (abort move) */
465 dog_goal(mtmp, edog, after, udist, whappr)
466 register struct monst *mtmp;
468 int after, udist, whappr;
470 register int omx, omy;
471 boolean in_masters_sight, dog_has_minvent;
472 register struct obj *obj;
476 /* Steeds don't move on their own will */
477 if (mtmp == u.usteed)
483 in_masters_sight = couldsee(omx, omy);
484 dog_has_minvent = (droppables(mtmp) != 0);
486 if (!edog || mtmp->mleashed) { /* he's not going anywhere... */
491 #define DDIST(x, y) (dist2(x, y, omx, omy))
492 #define SQSRCHRADIUS 5
493 int min_x, max_x, min_y, max_y;
496 gtyp = UNDEF; /* no goal as yet */
497 gx = gy = 0; /* suppress 'used before set' message */
499 if ((min_x = omx - SQSRCHRADIUS) < 1)
501 if ((max_x = omx + SQSRCHRADIUS) >= COLNO)
503 if ((min_y = omy - SQSRCHRADIUS) < 0)
505 if ((max_y = omy + SQSRCHRADIUS) >= ROWNO)
508 /* nearby food is the first choice, then other objects */
509 for (obj = fobj; obj; obj = obj->nobj) {
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)
517 /* avoid cursed items unless starving */
518 if (cursed_object_at(nx, ny)
519 && !(edog->mhpmax_penalty && otyp < MANFOOD))
521 /* skip completely unreachable goals */
522 if (!could_reach_item(mtmp, nx, ny)
523 || !can_reach_location(mtmp, mtmp->mx, mtmp->my, nx, ny))
525 if (otyp < MANFOOD) {
526 if (otyp < gtyp || DDIST(nx, ny) < DDIST(gx, gy)) {
531 } else if (gtyp == UNDEF && in_masters_sight
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) {
545 /* follow player if appropriate */
546 if (gtyp == UNDEF || (gtyp != DOGFOOD && gtyp != APPORT
547 && monstermoves < edog->hungrytime)) {
550 if (after && udist <= 4 && gx == u.ux && gy == u.uy)
552 appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
554 if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) || whappr
555 || (dog_has_minvent && rn2(edog->apport)))
558 /* if you have dog food it'll follow you more closely */
562 if (dogfood(mtmp, obj) == DOGFOOD) {
570 appr = 1; /* gtyp != UNDEF */
574 #define FARAWAY (COLNO + 2) /* position outside screen */
575 if (gx == u.ux && gy == u.uy && !in_masters_sight) {
578 cp = gettrack(omx, omy);
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))) {
592 int fardist = FARAWAY * FARAWAY;
593 gx = gy = FARAWAY; /* random */
594 do_clear_area(omx, omy, 9, wantdoor, (genericptr_t) &fardist);
596 /* here gx == FARAWAY e.g. when dog is in a vault */
597 if (gx == FARAWAY || (gx == omx && gy == omy)) {
612 /* return 0 (no move), 1 (move) or 2 (dead) */
614 dog_move(mtmp, after)
615 register struct monst *mtmp;
616 register int after; /* this is extra fast monster movement */
618 int omx, omy; /* original mtmp position */
619 int appr, whappr, udist;
621 register struct edog *edog = EDOG(mtmp);
622 struct obj *obj = (struct obj *) 0;
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;
631 long info[9], allowflags;
632 #define GDIST(x, y) (dist2(x, y, gx, gy))
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.)
641 has_edog = !mtmp->isminion;
645 if (has_edog && dog_hunger(mtmp, edog))
646 return 2; /* starved */
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);
657 /* maybe we tamed him while being swallowed --jgm */
660 nix = omx; /* set before newdogpos */
662 cursemsg[0] = FALSE; /* lint suppression */
663 info[0] = 0; /* ditto */
666 j = dog_invent(mtmp, edog, udist);
670 goto newdogpos; /* eating something */
672 whappr = (monstermoves - edog->whistletime < 5);
676 appr = dog_goal(mtmp, has_edog ? edog : (struct edog *) 0, after, udist,
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;
693 /* Guardian angel refuses to be conflicted; rather,
694 * it disappears, angrily, and sends in some nasties
696 lose_guardian_angel(mtmp);
697 return 2; /* current monster is gone */
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!");
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 */
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);
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.
726 for (i = 0; i < cnt; i++) {
729 if (MON_AT(nx, ny) && !((info[i] & ALLOW_M) || info[i] & ALLOW_MDISP))
731 if (cursed_object_at(nx, ny))
736 better_with_displacing = should_displace(mtmp, poss, info, cnt, gx, gy);
740 nidist = GDIST(nix, niy);
742 for (i = 0; i < cnt; i++) {
747 /* if leashed, we drag him along. */
748 if (mtmp->mleashed && distu(nx, ny) > 4)
751 /* if a guardian, try to stay close by choice */
752 if (!has_edog && (j = distu(nx, ny)) > 16 && j >= udist)
755 if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) {
757 register struct monst *mtmp2 = m_at(nx, ny);
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
769 || (touch_petrifies(mtmp2->data) && !resists_ston(mtmp)))
773 return 0; /* hit only once each move */
776 mstatus = mattackm(mtmp, mtmp2);
778 /* aggressor (pet) died */
779 if (mstatus & MM_AGR_DIED)
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)
793 if ((info[i] & ALLOW_MDISP) && MON_AT(nx, ny)
794 && better_with_displacing && !undesirable_disp(mtmp, nx, ny)) {
796 register struct monst *mtmp2 = m_at(nx, ny);
797 mstatus = mdisplacem(mtmp, mtmp2, FALSE); /* displace monster */
798 if (mstatus & MM_DEF_DIED)
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.)
813 if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx, ny))) {
814 if (mtmp->mleashed) {
818 /* 1/40 chance of stepping on it anyway, in case
819 * it has to pass one to follow the player...
821 if (trap->tseen && rn2(40))
826 /* dog eschews cursed objects, but likes dog food */
827 /* (minion isn't interested; `cursemsg' stays FALSE) */
829 for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) {
832 else if ((otyp = dogfood(mtmp, obj)) < MANFOOD
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 */
841 cursemsg[i] = FALSE; /* not reluctant */
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))
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)))
858 j = ((ndist = GDIST(nx, ny)) - nidist) * appr;
859 if ((j == 0 && !rn2(++chcnt)) || j < 0
861 && ((omx == nix && omy == niy && !rn2(3)) || !rn2(12)))) {
873 if (nix != omx || niy != omy) {
877 if (info[chi] & ALLOW_U) {
878 if (mtmp->mleashed) { /* play it safe */
879 pline("%s breaks loose of %s leash!", Monnam(mtmp),
881 m_unleash(mtmp, FALSE);
883 (void) mattacku(mtmp);
886 if (!m_in_out_region(mtmp, nix, niy))
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)
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;
902 if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp))
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.
920 if (dog_eat(mtmp, obj, omx, omy, FALSE) == 2)
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.
929 nx = sgn(omx - u.ux);
930 ny = sgn(omy - u.uy);
933 if (goodpos(cc.x, cc.y, mtmp, 0))
937 for (j = (i + 7) % 8; j < (i + 1) % 8; j++) {
939 if (goodpos(cc.x, cc.y, mtmp, 0))
942 for (j = (i + 6) % 8; j < (i + 2) % 8; j++) {
944 if (goodpos(cc.x, cc.y, mtmp, 0))
950 if (!m_in_out_region(mtmp, nix, niy))
952 remove_monster(mtmp->mx, mtmp->my);
953 place_monster(mtmp, cc.x, cc.y);
960 /* check if a monster could pick up objects from a location */
962 could_reach_item(mon, nx, ny)
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)))
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
981 can_reach_location(mon, mx, my, fx, fy)
983 xchar mx, my, fx, fy;
988 if (mx == fx && my == fy)
991 return FALSE; /* should not happen */
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++) {
998 if (dist2(i, j, fx, fy) >= dist)
1000 if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data)
1001 && (!may_dig(i, j) || !tunnels(mon->data)))
1003 if (IS_DOOR(levl[i][j].typ)
1004 && (levl[i][j].doormask & (D_CLOSED | D_LOCKED)))
1006 if (!could_reach_item(mon, i, j))
1008 if (can_reach_location(mon, i, j, fx, fy))
1015 /*ARGSUSED*/ /* do_clear_area client */
1017 wantdoor(x, y, distance)
1019 genericptr_t distance;
1023 if (*(int *) distance > (ndist = distu(x, y))) {
1026 *(int *) distance = ndist;
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? */
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 },
1045 M_AP_FURNITURE }, /* sorry, no fire hydrants in NetHack */
1046 { 0, 0, TRIPE_RATION, M_AP_OBJECT }, /* leave this at end */
1050 finish_meating(mtmp)
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);
1066 int idx = 0, trycnt = 5, spotted;
1069 if (Protection_from_shape_changers || !mtmp->meating)
1073 idx = rn2(SIZE(qm));
1074 if (qm[idx].mndx != 0 && monsndx(mtmp->data) == qm[idx].mndx)
1076 if (qm[idx].mlet != 0 && mtmp->data->mlet == qm[idx].mlet)
1078 if (qm[idx].mndx == 0 && qm[idx].mlet == 0)
1080 } while (--trycnt > 0);
1084 Strcpy(buf, mon_nam(mtmp));
1085 spotted = canspotmon(mtmp);
1087 mtmp->m_ap_type = qm[idx].m_ap_type;
1088 mtmp->mappearance = qm[idx].mappearance;
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)
1111 display_nhwindow(WIN_MAP, TRUE);