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. */
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. */
14 extern boolean notonhead;
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 *));
24 /* pick a carried item for pet to drop */
29 struct obj *obj, *wep, dummy, *pickaxe, *unihorn, *key;
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;
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 */
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))
44 /* don't hang on to key if can't open doors */
45 if (nohands(mon->data) || verysmall(mon->data))
51 if (wep->otyp == UNICORN_HORN)
53 /* don't need any wielded check for keys... */
56 for (obj = mon->minvent; obj; obj = obj->nobj) {
58 case DWARVISH_MATTOCK:
59 /* reject mattock if couldn't wield it */
60 if (which_armor(mon, W_ARMS))
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 */
69 if (!pickaxe || (obj->oartifact && !pickaxe->oartifact)) {
72 pickaxe = obj; /* keep this digging tool */
78 /* reject cursed unicorn horns */
81 /* keep artifact unihorn in preference to ordinary one */
82 if (!unihorn || (obj->oartifact && !unihorn->oartifact)) {
85 unihorn = obj; /* keep this unicorn horn */
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 */
97 /* keep lock-pick in preference to credit card */
98 if (key && key->otyp == CREDIT_CARD
99 && (!key->oartifact || obj->oartifact))
103 if (!key || (obj->oartifact && !key->oartifact)) {
106 key = obj; /* keep this unlocking tool */
115 if (!obj->owornmask && obj != wep)
119 return (struct obj *) 0; /* don't drop anything */
122 static NEARDATA const char nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS,
125 STATIC_VAR xchar gtyp, gx, gy; /* type and position of dog's current goal */
127 STATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t));
130 cursed_object_at(x, y)
135 for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
142 dog_nutrition(mtmp, obj)
149 * It is arbitrary that the pet takes the same length of time to eat
150 * as a human, but gets more nutritional value.
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;
157 mtmp->meating = objects[obj->otyp].oc_delay;
158 nutrit = objects[obj->otyp].oc_nutrition;
160 switch (mtmp->data->msize) {
182 mtmp->meating = eaten_stat(mtmp->meating, obj);
183 nutrit = eaten_stat(nutrit, obj);
185 } else if (obj->oclass == COIN_CLASS) {
186 mtmp->meating = (int) (obj->quan / 2000) + 1;
187 if (mtmp->meating < 0)
189 nutrit = (int) (obj->quan / 20);
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.)
198 mtmp->meating = obj->owt / 20 + 1;
199 nutrit = 5 * objects[obj->otyp].oc_nutrition;
204 /* returns 2 if pet dies, otherwise 1 */
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 */
212 register struct edog *edog = EDOG(mtmp);
213 boolean poly, grow, heal, slimer, deadmimic;
216 char objnambuf[BUFSZ];
219 if (edog->hungrytime < monstermoves)
220 edog->hungrytime = monstermoves;
221 nutrit = dog_nutrition(mtmp, obj);
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);
232 if (mtmp->meating > 1)
235 nutrit = (nutrit * 3) / 4;
237 edog->hungrytime += nutrit;
239 if (edog->mhpmax_penalty) {
240 /* no longer starving */
241 mtmp->mhpmax += edog->mhpmax_penalty;
242 edog->mhpmax_penalty = 0;
244 if (mtmp->mflee && mtmp->mfleetim > 1)
246 if (mtmp->mtame < 20)
248 if (x != mtmp->mx || y != mtmp->my) { /* moved & ate on same turn */
250 newsym(mtmp->mx, mtmp->my);
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);
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) */
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);
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))
277 pline("%s digs in.", noit_Monnam(mtmp));
279 pline("%s
\82Í
\8c@
\82Á
\82Ä
\82¢
\82é
\81D", noit_Monnam(mtmp));
282 pline("%s %s %s.", noit_Monnam(mtmp),
283 devour ? "devours" : "eats", distant_name(obj, doname));
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Ä");
290 pline("It %s %s.", devour ? "devours" : "eats",
291 distant_name(obj, doname));
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Ä");
298 Strcpy(objnambuf, xname(obj));
299 iflags.suppress_price--;
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)
307 edog->apport += (int) (200L / ((long) edog->dropdist + monstermoves
310 if (mtmp->data == &mons[PM_RUST_MONSTER] && obj->oerodeproof) {
311 /* The object's rustproofing is gone now */
313 costly_alteration(obj, COST_DEGRD);
314 obj->oerodeproof = 0;
316 if (canseemon(mtmp) && flags.verbose) {
318 pline("%s spits %s out in disgust!", Monnam(mtmp),
319 distant_name(obj, doname));
321 pline("%s
\82Í%s
\82ð
\83y
\83b
\82Æ
\93f
\82«
\8fo
\82µ
\82½
\81I", Monnam(mtmp),
322 distant_name(obj,doname));
325 } else if (obj == uball) {
327 delobj(obj); /* we assume this can't be unpaid */
328 } else if (obj == uchain) {
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);
336 pline("That %s will cost you %ld %s.", objnambuf, oprice,
339 pline("
\82 \82Ì%s
\82Í%ld%s
\82¾
\81D", objnambuf, oprice,
342 /* delobj->obfree will handle actual shop billing update */
347 #if 0 /* pet is eating, so slime recovery is not feasible... */
348 /* turning into slime might be cureable */
349 if (slimer && munslime(mtmp, FALSE)) {
350 /* but the cure (fire directed at self) might be fatal */
353 slimer = FALSE; /* sliming is avoided, skip polymorph */
357 if (poly || slimer) {
358 struct permonst *ptr = slimer ? &mons[PM_GREEN_SLIME] : 0;
360 (void) newcham(mtmp, ptr, FALSE, cansee(mtmp->mx, mtmp->my));
363 /* limit "instant" growth to prevent potential abuse */
364 if (grow && (int) mtmp->m_lev < (int) mtmp->data->mlevel + 15) {
365 if (!grow_up(mtmp, (struct monst *) 0))
369 mtmp->mhp = mtmp->mhpmax;
375 /* hunger effects -- returns TRUE on starvation */
377 dog_hunger(mtmp, edog)
378 register struct monst *mtmp;
379 register struct edog *edog;
381 if (monstermoves > edog->hungrytime + 500) {
382 if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) {
383 edog->hungrytime = monstermoves + 500;
384 /* but not too high; it might polymorph */
385 } else if (!edog->mhpmax_penalty) {
386 /* starving pets are limited in healing */
387 int newmhpmax = mtmp->mhpmax / 3;
389 edog->mhpmax_penalty = mtmp->mhpmax - newmhpmax;
390 mtmp->mhpmax = newmhpmax;
391 if (mtmp->mhp > mtmp->mhpmax)
392 mtmp->mhp = mtmp->mhpmax;
395 if (cansee(mtmp->mx, mtmp->my))
397 pline("%s is confused from hunger.", Monnam(mtmp));
399 pline("%s
\82Í
\8bó
\95 \82Ì
\82½
\82ß
\8d¬
\97\90\82µ
\82Ä
\82¢
\82é
\81D", Monnam(mtmp));
400 else if (couldsee(mtmp->mx, mtmp->my))
404 You_feel("worried about %s.", y_monnam(mtmp));
406 You("%s
\82ª
\90S
\94z
\82É
\82È
\82Á
\82½
\81D", y_monnam(mtmp));
408 } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) {
410 if (mtmp->mleashed && mtmp != u.usteed)
412 Your("leash goes slack.");
414 Your("
\95R
\82Í
\82½
\82é
\82ñ
\82¾
\81D");
415 else if (cansee(mtmp->mx, mtmp->my))
417 pline("%s starves.", Monnam(mtmp));
419 pline("%s
\82Í
\8bQ
\82¦
\82Å
\8e\80\82ñ
\82¾
\81D", Monnam(mtmp));
422 You_feel("%s for a moment.",
423 Hallucination ? "bummed" : "sad");
425 You("%s
\8bC
\95ª
\82É
\82¨
\82»
\82í
\82ê
\82½
\81D",
426 Hallucination ? "
\82ª
\82Á
\82©
\82è
\82µ
\82½" : "
\94ß
\82µ
\82¢");
435 /* do something with object (drop, pick up, eat) at current position
436 * returns 1 if object eaten (since that counts as dog's move), 2 if died
439 dog_invent(mtmp, edog, udist)
440 register struct monst *mtmp;
441 register struct edog *edog;
444 register int omx, omy, carryamt = 0;
445 struct obj *obj, *otmp;
447 if (mtmp->msleeping || !mtmp->mcanmove)
453 /* if we are carrying something then we drop it (perhaps near @) */
454 /* Note: if apport == 1 then our behaviour is independent of udist */
455 /* Use udist+1 so steed won't cause divide by zero */
456 if (droppables(mtmp)) {
457 if (!rn2(udist + 1) || !rn2(edog->apport))
458 if (rn2(10) < edog->apport) {
459 relobj(mtmp, (int) mtmp->minvis, TRUE);
460 if (edog->apport > 1)
462 edog->dropdist = udist; /* hpscdi!jon */
463 edog->droptime = monstermoves;
466 if ((obj = level.objects[omx][omy]) && !index(nofetch, obj->oclass)
468 && obj->otyp != SCR_MAIL
471 int edible = dogfood(mtmp, obj);
473 if ((edible <= CADAVER
474 /* starving pet is more aggressive about eating */
475 || (edog->mhpmax_penalty && edible == ACCFOOD))
476 && could_reach_item(mtmp, obj->ox, obj->oy))
477 return dog_eat(mtmp, obj, omx, omy, FALSE);
479 carryamt = can_carry(mtmp, obj);
480 if (carryamt > 0 && !obj->cursed
481 && could_reach_item(mtmp, obj->ox, obj->oy)) {
482 if (rn2(20) < edog->apport + 3) {
483 if (rn2(udist) || !rn2(edog->apport)) {
485 if (carryamt != obj->quan)
486 otmp = splitobj(obj, carryamt);
487 if (cansee(omx, omy) && flags.verbose)
489 pline("%s picks up %s.", Monnam(mtmp),
490 distant_name(otmp, doname));
492 pline("%s
\82Í%s
\82ð
\8fE
\82Á
\82½
\81D", Monnam(mtmp),
493 distant_name(obj, doname));
495 obj_extract_self(otmp);
497 (void) mpickobj(mtmp, otmp);
498 if (attacktype(mtmp->data, AT_WEAP)
499 && mtmp->weapon_check == NEED_WEAPON) {
500 mtmp->weapon_check = NEED_HTH_WEAPON;
501 (void) mon_wield_item(mtmp);
503 m_dowear(mtmp, FALSE);
512 /* set dog's goal -- gtyp, gx, gy
513 returns -1/0/1 (dog's desire to approach player) or -2 (abort move) */
515 dog_goal(mtmp, edog, after, udist, whappr)
516 register struct monst *mtmp;
518 int after, udist, whappr;
520 register int omx, omy;
521 boolean in_masters_sight, dog_has_minvent;
522 register struct obj *obj;
526 /* Steeds don't move on their own will */
527 if (mtmp == u.usteed)
533 in_masters_sight = couldsee(omx, omy);
534 dog_has_minvent = (droppables(mtmp) != 0);
536 if (!edog || mtmp->mleashed) { /* he's not going anywhere... */
541 #define DDIST(x, y) (dist2(x, y, omx, omy))
542 #define SQSRCHRADIUS 5
543 int min_x, max_x, min_y, max_y;
546 gtyp = UNDEF; /* no goal as yet */
547 gx = gy = 0; /* suppress 'used before set' message */
549 if ((min_x = omx - SQSRCHRADIUS) < 1)
551 if ((max_x = omx + SQSRCHRADIUS) >= COLNO)
553 if ((min_y = omy - SQSRCHRADIUS) < 0)
555 if ((max_y = omy + SQSRCHRADIUS) >= ROWNO)
558 /* nearby food is the first choice, then other objects */
559 for (obj = fobj; obj; obj = obj->nobj) {
562 if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) {
563 otyp = dogfood(mtmp, obj);
564 /* skip inferior goals */
565 if (otyp > gtyp || otyp == UNDEF)
567 /* avoid cursed items unless starving */
568 if (cursed_object_at(nx, ny)
569 && !(edog->mhpmax_penalty && otyp < MANFOOD))
571 /* skip completely unreachable goals */
572 if (!could_reach_item(mtmp, nx, ny)
573 || !can_reach_location(mtmp, mtmp->mx, mtmp->my, nx, ny))
575 if (otyp < MANFOOD) {
576 if (otyp < gtyp || DDIST(nx, ny) < DDIST(gx, gy)) {
581 } else if (gtyp == UNDEF && in_masters_sight
583 && (!levl[omx][omy].lit || levl[u.ux][u.uy].lit)
584 && (otyp == MANFOOD || m_cansee(mtmp, nx, ny))
585 && edog->apport > rn2(8)
586 && can_carry(mtmp, obj) > 0) {
595 /* follow player if appropriate */
596 if (gtyp == UNDEF || (gtyp != DOGFOOD && gtyp != APPORT
597 && monstermoves < edog->hungrytime)) {
600 if (after && udist <= 4 && gx == u.ux && gy == u.uy)
602 appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
604 if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) || whappr
605 || (dog_has_minvent && rn2(edog->apport)))
608 /* if you have dog food it'll follow you more closely */
612 if (dogfood(mtmp, obj) == DOGFOOD) {
620 appr = 1; /* gtyp != UNDEF */
624 #define FARAWAY (COLNO + 2) /* position outside screen */
625 if (gx == u.ux && gy == u.uy && !in_masters_sight) {
628 cp = gettrack(omx, omy);
635 /* assume master hasn't moved far, and reuse previous goal */
636 if (edog && edog->ogoal.x
637 && ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) {
642 int fardist = FARAWAY * FARAWAY;
643 gx = gy = FARAWAY; /* random */
644 do_clear_area(omx, omy, 9, wantdoor, (genericptr_t) &fardist);
646 /* here gx == FARAWAY e.g. when dog is in a vault */
647 if (gx == FARAWAY || (gx == omx && gy == omy)) {
662 /* return 0 (no move), 1 (move) or 2 (dead) */
664 dog_move(mtmp, after)
665 register struct monst *mtmp;
666 register int after; /* this is extra fast monster movement */
668 int omx, omy; /* original mtmp position */
669 int appr, whappr, udist;
671 register struct edog *edog = EDOG(mtmp);
672 struct obj *obj = (struct obj *) 0;
674 boolean has_edog, cursemsg[9], do_eat = FALSE;
675 boolean better_with_displacing = FALSE;
676 xchar nix, niy; /* position mtmp is (considering) moving to */
677 register int nx, ny; /* temporary coordinates */
678 xchar cnt, uncursedcnt, chcnt;
679 int chi = -1, nidist, ndist;
681 long info[9], allowflags;
682 #define GDIST(x, y) (dist2(x, y, gx, gy))
685 * Tame Angels have isminion set and an ispriest structure instead of
686 * an edog structure. Fortunately, guardian Angels need not worry
687 * about mundane things like eating and fetching objects, and can
688 * spend all their energy defending the player. (They are the only
689 * monsters with other structures that can be tame.)
691 has_edog = !mtmp->isminion;
695 if (has_edog && dog_hunger(mtmp, edog))
696 return 2; /* starved */
698 udist = distu(omx, omy);
699 /* Let steeds eat and maybe throw rider during Conflict */
700 if (mtmp == u.usteed) {
701 if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
702 dismount_steed(DISMOUNT_THROWN);
707 /* maybe we tamed him while being swallowed --jgm */
710 nix = omx; /* set before newdogpos */
712 cursemsg[0] = FALSE; /* lint suppression */
713 info[0] = 0; /* ditto */
716 j = dog_invent(mtmp, edog, udist);
720 goto newdogpos; /* eating something */
722 whappr = (monstermoves - edog->whistletime < 5);
726 appr = dog_goal(mtmp, has_edog ? edog : (struct edog *) 0, after, udist,
731 allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT;
732 if (passes_walls(mtmp->data))
733 allowflags |= (ALLOW_ROCK | ALLOW_WALL);
734 if (passes_bars(mtmp->data))
735 allowflags |= ALLOW_BARS;
736 if (throws_rocks(mtmp->data))
737 allowflags |= ALLOW_ROCK;
738 if (is_displacer(mtmp->data))
739 allowflags |= ALLOW_MDISP;
740 if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
741 allowflags |= ALLOW_U;
743 /* Guardian angel refuses to be conflicted; rather,
744 * it disappears, angrily, and sends in some nasties
746 lose_guardian_angel(mtmp);
747 return 2; /* current monster is gone */
750 #if 0 /* [this is now handled in dochug()] */
751 if (!Conflict && !mtmp->mconf
752 && mtmp == u.ustuck && !sticks(youmonst.data)) {
753 unstuck(mtmp); /* swallowed case handled above */
755 You("get released!");
757 You("
\93®
\82¯
\82é
\82æ
\82¤
\82É
\82È
\82Á
\82½
\81I");
760 if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
761 allowflags |= OPENDOOR;
762 if (monhaskey(mtmp, TRUE))
763 allowflags |= UNLOCKDOOR;
764 /* note: the Wizard and Riders can unlock doors without a key;
765 they won't use that ability if someone manages to tame them */
767 if (is_giant(mtmp->data))
768 allowflags |= BUSTDOOR;
769 if (tunnels(mtmp->data)
770 && !Is_rogue_level(&u.uz)) /* same restriction as m_move() */
771 allowflags |= ALLOW_DIG;
772 cnt = mfndpos(mtmp, poss, info, allowflags);
774 /* Normally dogs don't step on cursed items, but if they have no
775 * other choice they will. This requires checking ahead of time
776 * to see how many uncursed item squares are around.
779 for (i = 0; i < cnt; i++) {
782 if (MON_AT(nx, ny) && !((info[i] & ALLOW_M) || info[i] & ALLOW_MDISP))
784 if (cursed_object_at(nx, ny))
789 better_with_displacing = should_displace(mtmp, poss, info, cnt, gx, gy);
793 nidist = GDIST(nix, niy);
795 for (i = 0; i < cnt; i++) {
800 /* if leashed, we drag him along. */
801 if (mtmp->mleashed && distu(nx, ny) > 4)
804 /* if a guardian, try to stay close by choice */
805 if (!has_edog && (j = distu(nx, ny)) > 16 && j >= udist)
808 if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) {
810 register struct monst *mtmp2 = m_at(nx, ny);
812 if ((int) mtmp2->m_lev >= (int) mtmp->m_lev + 2
813 || (mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10)
814 && mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee
815 && (perceives(mtmp->data) || !mtmp2->minvis))
816 || (mtmp2->data == &mons[PM_GELATINOUS_CUBE] && rn2(10))
817 || (max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp)
818 || ((mtmp->mhp * 4 < mtmp->mhpmax
819 || mtmp2->data->msound == MS_GUARDIAN
820 || mtmp2->data->msound == MS_LEADER) && mtmp2->mpeaceful
822 || (touch_petrifies(mtmp2->data) && !resists_ston(mtmp)))
826 return 0; /* hit only once each move */
829 mstatus = mattackm(mtmp, mtmp2);
831 /* aggressor (pet) died */
832 if (mstatus & MM_AGR_DIED)
835 if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) && rn2(4)
836 && mtmp2->mlstmv != monstermoves
837 && !onscary(mtmp->mx, mtmp->my, mtmp2)
838 /* monnear check needed: long worms hit on tail */
839 && monnear(mtmp2, mtmp->mx, mtmp->my)) {
840 mstatus = mattackm(mtmp2, mtmp); /* return attack */
841 if (mstatus & MM_DEF_DIED)
846 if ((info[i] & ALLOW_MDISP) && MON_AT(nx, ny)
847 && better_with_displacing && !undesirable_disp(mtmp, nx, ny)) {
849 register struct monst *mtmp2 = m_at(nx, ny);
850 mstatus = mdisplacem(mtmp, mtmp2, FALSE); /* displace monster */
851 if (mstatus & MM_DEF_DIED)
857 /* Dog avoids harmful traps, but perhaps it has to pass one
858 * in order to follow player. (Non-harmful traps do not
859 * have ALLOW_TRAPS in info[].) The dog only avoids the
860 * trap if you've seen it, unlike enemies who avoid traps
861 * if they've seen some trap of that type sometime in the
862 * past. (Neither behavior is really realistic.)
866 if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx, ny))) {
867 if (mtmp->mleashed) {
871 /* 1/40 chance of stepping on it anyway, in case
872 * it has to pass one to follow the player...
874 if (trap->tseen && rn2(40))
879 /* dog eschews cursed objects, but likes dog food */
880 /* (minion isn't interested; `cursemsg' stays FALSE) */
882 for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) {
885 else if ((otyp = dogfood(mtmp, obj)) < MANFOOD
887 || edog->hungrytime <= monstermoves)) {
888 /* Note: our dog likes the food so much that he
889 * might eat it even when it conceals a cursed object */
894 cursemsg[i] = FALSE; /* not reluctant */
898 /* didn't find something to eat; if we saw a cursed item and
899 aren't being forced to walk on it, usually keep looking */
900 if (cursemsg[i] && !mtmp->mleashed && uncursedcnt > 0
901 && rn2(13 * uncursedcnt))
904 /* lessen the chance of backtracking to previous position(s) */
905 k = has_edog ? uncursedcnt : cnt;
906 for (j = 0; j < MTSZ && j < k - 1; j++)
907 if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
908 if (rn2(MTSZ * (k - j)))
911 j = ((ndist = GDIST(nx, ny)) - nidist) * appr;
912 if ((j == 0 && !rn2(++chcnt)) || j < 0
914 && ((omx == nix && omy == niy && !rn2(3)) || !rn2(12)))) {
926 if (nix != omx || niy != omy) {
930 if (info[chi] & ALLOW_U) {
931 if (mtmp->mleashed) { /* play it safe */
933 pline("%s breaks loose of %s leash!", Monnam(mtmp),
936 pline("%s
\82Í
\8e©
\95ª
\82É
\82Â
\82¢
\82Ä
\82¢
\82é
\95R
\82ð
\82Í
\82¸
\82µ
\82½
\81I",
939 m_unleash(mtmp, FALSE);
941 (void) mattacku(mtmp);
944 if (!m_in_out_region(mtmp, nix, niy))
946 if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix, niy))
947 || closed_door(nix, niy))
948 && mtmp->weapon_check != NO_WEAPON_WANTED
949 && tunnels(mtmp->data) && needspick(mtmp->data)) {
950 if (closed_door(nix, niy)) {
951 if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)
953 mtmp->weapon_check = NEED_PICK_OR_AXE;
954 } else if (IS_TREE(levl[nix][niy].typ)) {
955 if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp))
956 mtmp->weapon_check = NEED_AXE;
957 } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) {
958 mtmp->weapon_check = NEED_PICK_AXE;
960 if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp))
963 /* insert a worm_move() if worms ever begin to eat things */
964 wasseen = canseemon(mtmp);
965 remove_monster(omx, omy);
966 place_monster(mtmp, nix, niy);
967 if (cursemsg[chi] && (wasseen || canseemon(mtmp)))
969 pline("%s moves only reluctantly.", noit_Monnam(mtmp));
971 pline("%s
\82Í
\82¢
\82â
\82¢
\82â
\93®
\82¢
\82½
\81D", Monnam(mtmp));
972 for (j = MTSZ - 1; j > 0; j--)
973 mtmp->mtrack[j] = mtmp->mtrack[j - 1];
974 mtmp->mtrack[0].x = omx;
975 mtmp->mtrack[0].y = omy;
976 /* We have to know if the pet's gonna do a combined eat and
977 * move before moving it, but it can't eat until after being
978 * moved. Thus the do_eat flag.
981 if (dog_eat(mtmp, obj, omx, omy, FALSE) == 2)
984 } else if (mtmp->mleashed && distu(omx, omy) > 4) {
985 /* an incredible kludge, but the only way to keep pooch near
986 * after it spends time eating or in a trap, etc.
990 nx = sgn(omx - u.ux);
991 ny = sgn(omy - u.uy);
994 if (goodpos(cc.x, cc.y, mtmp, 0))
998 for (j = (i + 7) % 8; j < (i + 1) % 8; j++) {
1000 if (goodpos(cc.x, cc.y, mtmp, 0))
1003 for (j = (i + 6) % 8; j < (i + 2) % 8; j++) {
1005 if (goodpos(cc.x, cc.y, mtmp, 0))
1011 if (!m_in_out_region(mtmp, nix, niy))
1013 remove_monster(mtmp->mx, mtmp->my);
1014 place_monster(mtmp, cc.x, cc.y);
1021 /* check if a monster could pick up objects from a location */
1023 could_reach_item(mon, nx, ny)
1027 if ((!is_pool(nx, ny) || is_swimmer(mon->data))
1028 && (!is_lava(nx, ny) || likes_lava(mon->data))
1029 && (!sobj_at(BOULDER, nx, ny) || throws_rocks(mon->data)))
1034 /* Hack to prevent a dog from being endlessly stuck near an object that
1035 * it can't reach, such as caught in a teleport scroll niche. It recursively
1036 * checks to see if the squares in between are good. The checking could be
1037 * a little smarter; a full check would probably be useful in m_move() too.
1038 * Since the maximum food distance is 5, this should never be more than 5
1042 can_reach_location(mon, mx, my, fx, fy)
1044 xchar mx, my, fx, fy;
1049 if (mx == fx && my == fy)
1052 return FALSE; /* should not happen */
1054 dist = dist2(mx, my, fx, fy);
1055 for (i = mx - 1; i <= mx + 1; i++) {
1056 for (j = my - 1; j <= my + 1; j++) {
1059 if (dist2(i, j, fx, fy) >= dist)
1061 if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data)
1062 && (!may_dig(i, j) || !tunnels(mon->data)))
1064 if (IS_DOOR(levl[i][j].typ)
1065 && (levl[i][j].doormask & (D_CLOSED | D_LOCKED)))
1067 if (!could_reach_item(mon, i, j))
1069 if (can_reach_location(mon, i, j, fx, fy))
1076 /*ARGSUSED*/ /* do_clear_area client */
1078 wantdoor(x, y, distance)
1080 genericptr_t distance;
1084 if (*(int *) distance > (ndist = distu(x, y))) {
1087 *(int *) distance = ndist;
1091 static struct qmchoices {
1092 int mndx; /* type of pet, 0 means any */
1093 char mlet; /* symbol of pet, 0 means any */
1094 unsigned mappearance; /* mimic this */
1095 uchar m_ap_type; /* what is the thing it is mimicing? */
1097 /* Things that some pets might be thinking about at the time */
1098 { PM_LITTLE_DOG, 0, PM_KITTEN, M_AP_MONSTER },
1099 { PM_DOG, 0, PM_HOUSECAT, M_AP_MONSTER },
1100 { PM_LARGE_DOG, 0, PM_LARGE_CAT, M_AP_MONSTER },
1101 { PM_KITTEN, 0, PM_LITTLE_DOG, M_AP_MONSTER },
1102 { PM_HOUSECAT, 0, PM_DOG, M_AP_MONSTER },
1103 { PM_LARGE_CAT, 0, PM_LARGE_DOG, M_AP_MONSTER },
1104 { PM_HOUSECAT, 0, PM_GIANT_RAT, M_AP_MONSTER },
1106 M_AP_FURNITURE }, /* sorry, no fire hydrants in NetHack */
1107 { 0, 0, TRIPE_RATION, M_AP_OBJECT }, /* leave this at end */
1111 finish_meating(mtmp)
1115 if (mtmp->m_ap_type && mtmp->mappearance && mtmp->cham == NON_PM) {
1116 /* was eating a mimic and now appearance needs resetting */
1117 mtmp->m_ap_type = 0;
1118 mtmp->mappearance = 0;
1119 newsym(mtmp->mx, mtmp->my);
1127 int idx = 0, trycnt = 5, spotted;
1130 if (Protection_from_shape_changers || !mtmp->meating)
1134 idx = rn2(SIZE(qm));
1135 if (qm[idx].mndx != 0 && monsndx(mtmp->data) == qm[idx].mndx)
1137 if (qm[idx].mlet != 0 && mtmp->data->mlet == qm[idx].mlet)
1139 if (qm[idx].mndx == 0 && qm[idx].mlet == 0)
1141 } while (--trycnt > 0);
1145 Strcpy(buf, mon_nam(mtmp));
1146 spotted = canspotmon(mtmp);
1148 mtmp->m_ap_type = qm[idx].m_ap_type;
1149 mtmp->mappearance = qm[idx].mappearance;
1151 if (spotted || cansee(mtmp->mx, mtmp->my) || canspotmon(mtmp)) {
1152 /* this isn't quite right; if sensing a monster without being
1153 able to see its location, you really shouldn't be told you
1154 sense it becoming furniture or an object that you can't see
1155 (on the other hand, perhaps you're sensing a brief glimpse
1156 of its mind as it changes form) */
1157 newsym(mtmp->mx, mtmp->my);
1159 You("%s %s appear where %s was!",
1160 cansee(mtmp->mx, mtmp->my) ? "see" : "sense",
1161 (mtmp->m_ap_type == M_AP_FURNITURE)
1162 ? an(defsyms[mtmp->mappearance].explanation)
1163 : (mtmp->m_ap_type == M_AP_OBJECT
1164 && OBJ_DESCR(objects[mtmp->mappearance]))
1165 ? an(OBJ_DESCR(objects[mtmp->mappearance]))
1166 : (mtmp->m_ap_type == M_AP_OBJECT
1167 && OBJ_NAME(objects[mtmp->mappearance]))
1168 ? an(OBJ_NAME(objects[mtmp->mappearance]))
1169 : (mtmp->m_ap_type == M_AP_MONSTER)
1170 ? an(mons[mtmp->mappearance].mname)
1174 You("%s
\82ª
\82 \82Á
\82½
\82Æ
\82±
\82ë
\82É%s
\82ª
\8c»
\82ê
\82½
\82Ì%s
\81I",
1176 (mtmp->m_ap_type == M_AP_FURNITURE)
1177 ? an(defsyms[mtmp->mappearance].explanation)
1178 : (mtmp->m_ap_type == M_AP_OBJECT
1179 && OBJ_DESCR(objects[mtmp->mappearance]))
1180 ? an(OBJ_DESCR(objects[mtmp->mappearance]))
1181 : (mtmp->m_ap_type == M_AP_OBJECT
1182 && OBJ_NAME(objects[mtmp->mappearance]))
1183 ? an(OBJ_NAME(objects[mtmp->mappearance]))
1184 : (mtmp->m_ap_type == M_AP_MONSTER)
1185 ? an(mons[mtmp->mappearance].mname)
1187 cansee(mtmp->mx, mtmp->my) ? "
\82ð
\8c©
\82½" : "
\82É
\8bC
\82Ã
\82¢
\82½");
1189 display_nhwindow(WIN_MAP, TRUE);