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);
335 pline("That %s will cost you %ld %s.", objnambuf, oprice,
337 /* delobj->obfree will handle actual shop billing update */
342 #if 0 /* pet is eating, so slime recovery is not feasible... */
343 /* turning into slime might be cureable */
344 if (slimer && munslime(mtmp, FALSE)) {
345 /* but the cure (fire directed at self) might be fatal */
348 slimer = FALSE; /* sliming is avoided, skip polymorph */
352 if (poly || slimer) {
353 struct permonst *ptr = slimer ? &mons[PM_GREEN_SLIME] : 0;
355 (void) newcham(mtmp, ptr, FALSE, cansee(mtmp->mx, mtmp->my));
358 /* limit "instant" growth to prevent potential abuse */
359 if (grow && (int) mtmp->m_lev < (int) mtmp->data->mlevel + 15) {
360 if (!grow_up(mtmp, (struct monst *) 0))
364 mtmp->mhp = mtmp->mhpmax;
370 /* hunger effects -- returns TRUE on starvation */
372 dog_hunger(mtmp, edog)
373 register struct monst *mtmp;
374 register struct edog *edog;
376 if (monstermoves > edog->hungrytime + 500) {
377 if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) {
378 edog->hungrytime = monstermoves + 500;
379 /* but not too high; it might polymorph */
380 } else if (!edog->mhpmax_penalty) {
381 /* starving pets are limited in healing */
382 int newmhpmax = mtmp->mhpmax / 3;
384 edog->mhpmax_penalty = mtmp->mhpmax - newmhpmax;
385 mtmp->mhpmax = newmhpmax;
386 if (mtmp->mhp > mtmp->mhpmax)
387 mtmp->mhp = mtmp->mhpmax;
390 if (cansee(mtmp->mx, mtmp->my))
392 pline("%s is confused from hunger.", Monnam(mtmp));
394 pline("%s
\82Í
\8bó
\95 \82Ì
\82½
\82ß
\8d¬
\97\90\82µ
\82Ä
\82¢
\82é
\81D", Monnam(mtmp));
395 else if (couldsee(mtmp->mx, mtmp->my))
399 You_feel("worried about %s.", y_monnam(mtmp));
401 You("%s
\82ª
\90S
\94z
\82É
\82È
\82Á
\82½
\81D", y_monnam(mtmp));
403 } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) {
405 if (mtmp->mleashed && mtmp != u.usteed)
407 Your("leash goes slack.");
409 Your("
\95R
\82Í
\82½
\82é
\82ñ
\82¾
\81D");
410 else if (cansee(mtmp->mx, mtmp->my))
412 pline("%s starves.", Monnam(mtmp));
414 pline("%s
\82Í
\8bQ
\82¦
\82Å
\8e\80\82ñ
\82¾
\81D", Monnam(mtmp));
417 You_feel("%s for a moment.",
418 Hallucination ? "bummed" : "sad");
420 You("%s
\8bC
\95ª
\82É
\82¨
\82»
\82í
\82ê
\82½
\81D",
421 Hallucination ? "
\82ª
\82Á
\82©
\82è
\82µ
\82½" : "
\94ß
\82µ
\82¢");
430 /* do something with object (drop, pick up, eat) at current position
431 * returns 1 if object eaten (since that counts as dog's move), 2 if died
434 dog_invent(mtmp, edog, udist)
435 register struct monst *mtmp;
436 register struct edog *edog;
439 register int omx, omy, carryamt = 0;
440 struct obj *obj, *otmp;
442 if (mtmp->msleeping || !mtmp->mcanmove)
448 /* if we are carrying something then we drop it (perhaps near @) */
449 /* Note: if apport == 1 then our behaviour is independent of udist */
450 /* Use udist+1 so steed won't cause divide by zero */
451 if (droppables(mtmp)) {
452 if (!rn2(udist + 1) || !rn2(edog->apport))
453 if (rn2(10) < edog->apport) {
454 relobj(mtmp, (int) mtmp->minvis, TRUE);
455 if (edog->apport > 1)
457 edog->dropdist = udist; /* hpscdi!jon */
458 edog->droptime = monstermoves;
461 if ((obj = level.objects[omx][omy]) && !index(nofetch, obj->oclass)
463 && obj->otyp != SCR_MAIL
466 int edible = dogfood(mtmp, obj);
468 if ((edible <= CADAVER
469 /* starving pet is more aggressive about eating */
470 || (edog->mhpmax_penalty && edible == ACCFOOD))
471 && could_reach_item(mtmp, obj->ox, obj->oy))
472 return dog_eat(mtmp, obj, omx, omy, FALSE);
474 carryamt = can_carry(mtmp, obj);
475 if (carryamt > 0 && !obj->cursed
476 && could_reach_item(mtmp, obj->ox, obj->oy)) {
477 if (rn2(20) < edog->apport + 3) {
478 if (rn2(udist) || !rn2(edog->apport)) {
480 if (carryamt != obj->quan)
481 otmp = splitobj(obj, carryamt);
482 if (cansee(omx, omy) && flags.verbose)
484 pline("%s picks up %s.", Monnam(mtmp),
485 distant_name(otmp, doname));
487 pline("%s
\82Í%s
\82ð
\8fE
\82Á
\82½
\81D", Monnam(mtmp),
488 distant_name(obj, doname));
490 obj_extract_self(otmp);
492 (void) mpickobj(mtmp, otmp);
493 if (attacktype(mtmp->data, AT_WEAP)
494 && mtmp->weapon_check == NEED_WEAPON) {
495 mtmp->weapon_check = NEED_HTH_WEAPON;
496 (void) mon_wield_item(mtmp);
498 m_dowear(mtmp, FALSE);
507 /* set dog's goal -- gtyp, gx, gy
508 returns -1/0/1 (dog's desire to approach player) or -2 (abort move) */
510 dog_goal(mtmp, edog, after, udist, whappr)
511 register struct monst *mtmp;
513 int after, udist, whappr;
515 register int omx, omy;
516 boolean in_masters_sight, dog_has_minvent;
517 register struct obj *obj;
521 /* Steeds don't move on their own will */
522 if (mtmp == u.usteed)
528 in_masters_sight = couldsee(omx, omy);
529 dog_has_minvent = (droppables(mtmp) != 0);
531 if (!edog || mtmp->mleashed) { /* he's not going anywhere... */
536 #define DDIST(x, y) (dist2(x, y, omx, omy))
537 #define SQSRCHRADIUS 5
538 int min_x, max_x, min_y, max_y;
541 gtyp = UNDEF; /* no goal as yet */
542 gx = gy = 0; /* suppress 'used before set' message */
544 if ((min_x = omx - SQSRCHRADIUS) < 1)
546 if ((max_x = omx + SQSRCHRADIUS) >= COLNO)
548 if ((min_y = omy - SQSRCHRADIUS) < 0)
550 if ((max_y = omy + SQSRCHRADIUS) >= ROWNO)
553 /* nearby food is the first choice, then other objects */
554 for (obj = fobj; obj; obj = obj->nobj) {
557 if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) {
558 otyp = dogfood(mtmp, obj);
559 /* skip inferior goals */
560 if (otyp > gtyp || otyp == UNDEF)
562 /* avoid cursed items unless starving */
563 if (cursed_object_at(nx, ny)
564 && !(edog->mhpmax_penalty && otyp < MANFOOD))
566 /* skip completely unreachable goals */
567 if (!could_reach_item(mtmp, nx, ny)
568 || !can_reach_location(mtmp, mtmp->mx, mtmp->my, nx, ny))
570 if (otyp < MANFOOD) {
571 if (otyp < gtyp || DDIST(nx, ny) < DDIST(gx, gy)) {
576 } else if (gtyp == UNDEF && in_masters_sight
578 && (!levl[omx][omy].lit || levl[u.ux][u.uy].lit)
579 && (otyp == MANFOOD || m_cansee(mtmp, nx, ny))
580 && edog->apport > rn2(8)
581 && can_carry(mtmp, obj) > 0) {
590 /* follow player if appropriate */
591 if (gtyp == UNDEF || (gtyp != DOGFOOD && gtyp != APPORT
592 && monstermoves < edog->hungrytime)) {
595 if (after && udist <= 4 && gx == u.ux && gy == u.uy)
597 appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
599 if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) || whappr
600 || (dog_has_minvent && rn2(edog->apport)))
603 /* if you have dog food it'll follow you more closely */
607 if (dogfood(mtmp, obj) == DOGFOOD) {
615 appr = 1; /* gtyp != UNDEF */
619 #define FARAWAY (COLNO + 2) /* position outside screen */
620 if (gx == u.ux && gy == u.uy && !in_masters_sight) {
623 cp = gettrack(omx, omy);
630 /* assume master hasn't moved far, and reuse previous goal */
631 if (edog && edog->ogoal.x
632 && ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) {
637 int fardist = FARAWAY * FARAWAY;
638 gx = gy = FARAWAY; /* random */
639 do_clear_area(omx, omy, 9, wantdoor, (genericptr_t) &fardist);
641 /* here gx == FARAWAY e.g. when dog is in a vault */
642 if (gx == FARAWAY || (gx == omx && gy == omy)) {
657 /* return 0 (no move), 1 (move) or 2 (dead) */
659 dog_move(mtmp, after)
660 register struct monst *mtmp;
661 register int after; /* this is extra fast monster movement */
663 int omx, omy; /* original mtmp position */
664 int appr, whappr, udist;
666 register struct edog *edog = EDOG(mtmp);
667 struct obj *obj = (struct obj *) 0;
669 boolean has_edog, cursemsg[9], do_eat = FALSE;
670 boolean better_with_displacing = FALSE;
671 xchar nix, niy; /* position mtmp is (considering) moving to */
672 register int nx, ny; /* temporary coordinates */
673 xchar cnt, uncursedcnt, chcnt;
674 int chi = -1, nidist, ndist;
676 long info[9], allowflags;
677 #define GDIST(x, y) (dist2(x, y, gx, gy))
680 * Tame Angels have isminion set and an ispriest structure instead of
681 * an edog structure. Fortunately, guardian Angels need not worry
682 * about mundane things like eating and fetching objects, and can
683 * spend all their energy defending the player. (They are the only
684 * monsters with other structures that can be tame.)
686 has_edog = !mtmp->isminion;
690 if (has_edog && dog_hunger(mtmp, edog))
691 return 2; /* starved */
693 udist = distu(omx, omy);
694 /* Let steeds eat and maybe throw rider during Conflict */
695 if (mtmp == u.usteed) {
696 if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
697 dismount_steed(DISMOUNT_THROWN);
702 /* maybe we tamed him while being swallowed --jgm */
705 nix = omx; /* set before newdogpos */
707 cursemsg[0] = FALSE; /* lint suppression */
708 info[0] = 0; /* ditto */
711 j = dog_invent(mtmp, edog, udist);
715 goto newdogpos; /* eating something */
717 whappr = (monstermoves - edog->whistletime < 5);
721 appr = dog_goal(mtmp, has_edog ? edog : (struct edog *) 0, after, udist,
726 allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT;
727 if (passes_walls(mtmp->data))
728 allowflags |= (ALLOW_ROCK | ALLOW_WALL);
729 if (passes_bars(mtmp->data))
730 allowflags |= ALLOW_BARS;
731 if (throws_rocks(mtmp->data))
732 allowflags |= ALLOW_ROCK;
733 if (is_displacer(mtmp->data))
734 allowflags |= ALLOW_MDISP;
735 if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) {
736 allowflags |= ALLOW_U;
738 /* Guardian angel refuses to be conflicted; rather,
739 * it disappears, angrily, and sends in some nasties
741 lose_guardian_angel(mtmp);
742 return 2; /* current monster is gone */
745 #if 0 /* [this is now handled in dochug()] */
746 if (!Conflict && !mtmp->mconf
747 && mtmp == u.ustuck && !sticks(youmonst.data)) {
748 unstuck(mtmp); /* swallowed case handled above */
750 You("get released!");
752 You("
\93®
\82¯
\82é
\82æ
\82¤
\82É
\82È
\82Á
\82½
\81I");
755 if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
756 allowflags |= OPENDOOR;
757 if (monhaskey(mtmp, TRUE))
758 allowflags |= UNLOCKDOOR;
759 /* note: the Wizard and Riders can unlock doors without a key;
760 they won't use that ability if someone manages to tame them */
762 if (is_giant(mtmp->data))
763 allowflags |= BUSTDOOR;
764 if (tunnels(mtmp->data)
765 && !Is_rogue_level(&u.uz)) /* same restriction as m_move() */
766 allowflags |= ALLOW_DIG;
767 cnt = mfndpos(mtmp, poss, info, allowflags);
769 /* Normally dogs don't step on cursed items, but if they have no
770 * other choice they will. This requires checking ahead of time
771 * to see how many uncursed item squares are around.
774 for (i = 0; i < cnt; i++) {
777 if (MON_AT(nx, ny) && !((info[i] & ALLOW_M) || info[i] & ALLOW_MDISP))
779 if (cursed_object_at(nx, ny))
784 better_with_displacing = should_displace(mtmp, poss, info, cnt, gx, gy);
788 nidist = GDIST(nix, niy);
790 for (i = 0; i < cnt; i++) {
795 /* if leashed, we drag him along. */
796 if (mtmp->mleashed && distu(nx, ny) > 4)
799 /* if a guardian, try to stay close by choice */
800 if (!has_edog && (j = distu(nx, ny)) > 16 && j >= udist)
803 if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) {
805 register struct monst *mtmp2 = m_at(nx, ny);
807 if ((int) mtmp2->m_lev >= (int) mtmp->m_lev + 2
808 || (mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10)
809 && mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee
810 && (perceives(mtmp->data) || !mtmp2->minvis))
811 || (mtmp2->data == &mons[PM_GELATINOUS_CUBE] && rn2(10))
812 || (max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp)
813 || ((mtmp->mhp * 4 < mtmp->mhpmax
814 || mtmp2->data->msound == MS_GUARDIAN
815 || mtmp2->data->msound == MS_LEADER) && mtmp2->mpeaceful
817 || (touch_petrifies(mtmp2->data) && !resists_ston(mtmp)))
821 return 0; /* hit only once each move */
824 mstatus = mattackm(mtmp, mtmp2);
826 /* aggressor (pet) died */
827 if (mstatus & MM_AGR_DIED)
830 if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) && rn2(4)
831 && mtmp2->mlstmv != monstermoves
832 && !onscary(mtmp->mx, mtmp->my, mtmp2)
833 /* monnear check needed: long worms hit on tail */
834 && monnear(mtmp2, mtmp->mx, mtmp->my)) {
835 mstatus = mattackm(mtmp2, mtmp); /* return attack */
836 if (mstatus & MM_DEF_DIED)
841 if ((info[i] & ALLOW_MDISP) && MON_AT(nx, ny)
842 && better_with_displacing && !undesirable_disp(mtmp, nx, ny)) {
844 register struct monst *mtmp2 = m_at(nx, ny);
845 mstatus = mdisplacem(mtmp, mtmp2, FALSE); /* displace monster */
846 if (mstatus & MM_DEF_DIED)
852 /* Dog avoids harmful traps, but perhaps it has to pass one
853 * in order to follow player. (Non-harmful traps do not
854 * have ALLOW_TRAPS in info[].) The dog only avoids the
855 * trap if you've seen it, unlike enemies who avoid traps
856 * if they've seen some trap of that type sometime in the
857 * past. (Neither behavior is really realistic.)
861 if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx, ny))) {
862 if (mtmp->mleashed) {
866 /* 1/40 chance of stepping on it anyway, in case
867 * it has to pass one to follow the player...
869 if (trap->tseen && rn2(40))
874 /* dog eschews cursed objects, but likes dog food */
875 /* (minion isn't interested; `cursemsg' stays FALSE) */
877 for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) {
880 else if ((otyp = dogfood(mtmp, obj)) < MANFOOD
882 || edog->hungrytime <= monstermoves)) {
883 /* Note: our dog likes the food so much that he
884 * might eat it even when it conceals a cursed object */
889 cursemsg[i] = FALSE; /* not reluctant */
893 /* didn't find something to eat; if we saw a cursed item and
894 aren't being forced to walk on it, usually keep looking */
895 if (cursemsg[i] && !mtmp->mleashed && uncursedcnt > 0
896 && rn2(13 * uncursedcnt))
899 /* lessen the chance of backtracking to previous position(s) */
900 k = has_edog ? uncursedcnt : cnt;
901 for (j = 0; j < MTSZ && j < k - 1; j++)
902 if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
903 if (rn2(MTSZ * (k - j)))
906 j = ((ndist = GDIST(nx, ny)) - nidist) * appr;
907 if ((j == 0 && !rn2(++chcnt)) || j < 0
909 && ((omx == nix && omy == niy && !rn2(3)) || !rn2(12)))) {
921 if (nix != omx || niy != omy) {
925 if (info[chi] & ALLOW_U) {
926 if (mtmp->mleashed) { /* play it safe */
928 pline("%s breaks loose of %s leash!", Monnam(mtmp),
931 pline("%s
\82Í
\8e©
\95ª
\82É
\82Â
\82¢
\82Ä
\82¢
\82é
\95R
\82ð
\82Í
\82¸
\82µ
\82½
\81I",
934 m_unleash(mtmp, FALSE);
936 (void) mattacku(mtmp);
939 if (!m_in_out_region(mtmp, nix, niy))
941 if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix, niy))
942 || closed_door(nix, niy))
943 && mtmp->weapon_check != NO_WEAPON_WANTED
944 && tunnels(mtmp->data) && needspick(mtmp->data)) {
945 if (closed_door(nix, niy)) {
946 if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)
948 mtmp->weapon_check = NEED_PICK_OR_AXE;
949 } else if (IS_TREE(levl[nix][niy].typ)) {
950 if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp))
951 mtmp->weapon_check = NEED_AXE;
952 } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) {
953 mtmp->weapon_check = NEED_PICK_AXE;
955 if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp))
958 /* insert a worm_move() if worms ever begin to eat things */
959 wasseen = canseemon(mtmp);
960 remove_monster(omx, omy);
961 place_monster(mtmp, nix, niy);
962 if (cursemsg[chi] && (wasseen || canseemon(mtmp)))
964 pline("%s moves only reluctantly.", noit_Monnam(mtmp));
966 pline("%s
\82Í
\82¢
\82â
\82¢
\82â
\93®
\82¢
\82½
\81D", Monnam(mtmp));
967 for (j = MTSZ - 1; j > 0; j--)
968 mtmp->mtrack[j] = mtmp->mtrack[j - 1];
969 mtmp->mtrack[0].x = omx;
970 mtmp->mtrack[0].y = omy;
971 /* We have to know if the pet's gonna do a combined eat and
972 * move before moving it, but it can't eat until after being
973 * moved. Thus the do_eat flag.
976 if (dog_eat(mtmp, obj, omx, omy, FALSE) == 2)
979 } else if (mtmp->mleashed && distu(omx, omy) > 4) {
980 /* an incredible kludge, but the only way to keep pooch near
981 * after it spends time eating or in a trap, etc.
985 nx = sgn(omx - u.ux);
986 ny = sgn(omy - u.uy);
989 if (goodpos(cc.x, cc.y, mtmp, 0))
993 for (j = (i + 7) % 8; j < (i + 1) % 8; j++) {
995 if (goodpos(cc.x, cc.y, mtmp, 0))
998 for (j = (i + 6) % 8; j < (i + 2) % 8; j++) {
1000 if (goodpos(cc.x, cc.y, mtmp, 0))
1006 if (!m_in_out_region(mtmp, nix, niy))
1008 remove_monster(mtmp->mx, mtmp->my);
1009 place_monster(mtmp, cc.x, cc.y);
1016 /* check if a monster could pick up objects from a location */
1018 could_reach_item(mon, nx, ny)
1022 if ((!is_pool(nx, ny) || is_swimmer(mon->data))
1023 && (!is_lava(nx, ny) || likes_lava(mon->data))
1024 && (!sobj_at(BOULDER, nx, ny) || throws_rocks(mon->data)))
1029 /* Hack to prevent a dog from being endlessly stuck near an object that
1030 * it can't reach, such as caught in a teleport scroll niche. It recursively
1031 * checks to see if the squares in between are good. The checking could be
1032 * a little smarter; a full check would probably be useful in m_move() too.
1033 * Since the maximum food distance is 5, this should never be more than 5
1037 can_reach_location(mon, mx, my, fx, fy)
1039 xchar mx, my, fx, fy;
1044 if (mx == fx && my == fy)
1047 return FALSE; /* should not happen */
1049 dist = dist2(mx, my, fx, fy);
1050 for (i = mx - 1; i <= mx + 1; i++) {
1051 for (j = my - 1; j <= my + 1; j++) {
1054 if (dist2(i, j, fx, fy) >= dist)
1056 if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data)
1057 && (!may_dig(i, j) || !tunnels(mon->data)))
1059 if (IS_DOOR(levl[i][j].typ)
1060 && (levl[i][j].doormask & (D_CLOSED | D_LOCKED)))
1062 if (!could_reach_item(mon, i, j))
1064 if (can_reach_location(mon, i, j, fx, fy))
1071 /*ARGSUSED*/ /* do_clear_area client */
1073 wantdoor(x, y, distance)
1075 genericptr_t distance;
1079 if (*(int *) distance > (ndist = distu(x, y))) {
1082 *(int *) distance = ndist;
1086 static struct qmchoices {
1087 int mndx; /* type of pet, 0 means any */
1088 char mlet; /* symbol of pet, 0 means any */
1089 unsigned mappearance; /* mimic this */
1090 uchar m_ap_type; /* what is the thing it is mimicing? */
1092 /* Things that some pets might be thinking about at the time */
1093 { PM_LITTLE_DOG, 0, PM_KITTEN, M_AP_MONSTER },
1094 { PM_DOG, 0, PM_HOUSECAT, M_AP_MONSTER },
1095 { PM_LARGE_DOG, 0, PM_LARGE_CAT, M_AP_MONSTER },
1096 { PM_KITTEN, 0, PM_LITTLE_DOG, M_AP_MONSTER },
1097 { PM_HOUSECAT, 0, PM_DOG, M_AP_MONSTER },
1098 { PM_LARGE_CAT, 0, PM_LARGE_DOG, M_AP_MONSTER },
1099 { PM_HOUSECAT, 0, PM_GIANT_RAT, M_AP_MONSTER },
1101 M_AP_FURNITURE }, /* sorry, no fire hydrants in NetHack */
1102 { 0, 0, TRIPE_RATION, M_AP_OBJECT }, /* leave this at end */
1106 finish_meating(mtmp)
1110 if (mtmp->m_ap_type && mtmp->mappearance && mtmp->cham == NON_PM) {
1111 /* was eating a mimic and now appearance needs resetting */
1112 mtmp->m_ap_type = 0;
1113 mtmp->mappearance = 0;
1114 newsym(mtmp->mx, mtmp->my);
1122 int idx = 0, trycnt = 5, spotted;
1125 if (Protection_from_shape_changers || !mtmp->meating)
1129 idx = rn2(SIZE(qm));
1130 if (qm[idx].mndx != 0 && monsndx(mtmp->data) == qm[idx].mndx)
1132 if (qm[idx].mlet != 0 && mtmp->data->mlet == qm[idx].mlet)
1134 if (qm[idx].mndx == 0 && qm[idx].mlet == 0)
1136 } while (--trycnt > 0);
1140 Strcpy(buf, mon_nam(mtmp));
1141 spotted = canspotmon(mtmp);
1143 mtmp->m_ap_type = qm[idx].m_ap_type;
1144 mtmp->mappearance = qm[idx].mappearance;
1146 if (spotted || cansee(mtmp->mx, mtmp->my) || canspotmon(mtmp)) {
1147 /* this isn't quite right; if sensing a monster without being
1148 able to see its location, you really shouldn't be told you
1149 sense it becoming furniture or an object that you can't see
1150 (on the other hand, perhaps you're sensing a brief glimpse
1151 of its mind as it changes form) */
1152 newsym(mtmp->mx, mtmp->my);
1153 You("%s %s appear where %s was!",
1154 cansee(mtmp->mx, mtmp->my) ? "see" : "sense",
1155 (mtmp->m_ap_type == M_AP_FURNITURE)
1156 ? an(defsyms[mtmp->mappearance].explanation)
1157 : (mtmp->m_ap_type == M_AP_OBJECT
1158 && OBJ_DESCR(objects[mtmp->mappearance]))
1159 ? an(OBJ_DESCR(objects[mtmp->mappearance]))
1160 : (mtmp->m_ap_type == M_AP_OBJECT
1161 && OBJ_NAME(objects[mtmp->mappearance]))
1162 ? an(OBJ_NAME(objects[mtmp->mappearance]))
1163 : (mtmp->m_ap_type == M_AP_MONSTER)
1164 ? an(mons[mtmp->mappearance].mname)
1167 display_nhwindow(WIN_MAP, TRUE);