1 /* NetHack 3.6 dogmove.c $NHDT-Date: 1463704424 2016/05/20 00:33:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.60 $ */
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
struct monst
*FDECL(find_targ
, (struct monst
*, int, int, int));
15 STATIC_OVL
int FDECL(find_friends
, (struct monst
*, struct monst
*, int));
16 STATIC_DCL
struct monst
*FDECL(best_target
, (struct monst
*));
17 STATIC_DCL
long FDECL(score_targ
, (struct monst
*, struct monst
*));
18 STATIC_DCL boolean
FDECL(can_reach_location
, (struct monst
*, XCHAR_P
,
19 XCHAR_P
, XCHAR_P
, XCHAR_P
));
20 STATIC_DCL boolean
FDECL(could_reach_item
, (struct monst
*, XCHAR_P
, XCHAR_P
));
21 STATIC_DCL
void FDECL(quickmimic
, (struct monst
*));
23 /* pick a carried item for pet to drop */
28 struct obj
*obj
, *wep
, dummy
, *pickaxe
, *unihorn
, *key
;
31 dummy
.otyp
= GOLD_PIECE
; /* not STRANGE_OBJECT or tools of interest */
32 dummy
.oartifact
= 1; /* so real artifact won't override "don't keep it" */
33 pickaxe
= unihorn
= key
= (struct obj
*) 0;
36 if (is_animal(mon
->data
) || mindless(mon
->data
)) {
37 /* won't hang on to any objects of these types */
38 pickaxe
= unihorn
= key
= &dummy
; /* act as if already have them */
40 /* don't hang on to pick-axe if can't use one or don't need one */
41 if (!tunnels(mon
->data
) || !needspick(mon
->data
))
43 /* don't hang on to key if can't open doors */
44 if (nohands(mon
->data
) || verysmall(mon
->data
))
50 if (wep
->otyp
== UNICORN_HORN
)
52 /* don't need any wielded check for keys... */
55 for (obj
= mon
->minvent
; obj
; obj
= obj
->nobj
) {
57 case DWARVISH_MATTOCK
:
58 /* reject mattock if couldn't wield it */
59 if (which_armor(mon
, W_ARMS
))
61 /* keep mattock in preference to pick unless pick is already
62 wielded or is an artifact and mattock isn't */
63 if (pickaxe
&& pickaxe
->otyp
== PICK_AXE
&& pickaxe
!= wep
64 && (!pickaxe
->oartifact
|| obj
->oartifact
))
65 return pickaxe
; /* drop the one we earlier decided to keep */
68 if (!pickaxe
|| (obj
->oartifact
&& !pickaxe
->oartifact
)) {
71 pickaxe
= obj
; /* keep this digging tool */
77 /* reject cursed unicorn horns */
80 /* keep artifact unihorn in preference to ordinary one */
81 if (!unihorn
|| (obj
->oartifact
&& !unihorn
->oartifact
)) {
84 unihorn
= obj
; /* keep this unicorn horn */
90 /* keep key in preference to lock-pick */
91 if (key
&& key
->otyp
== LOCK_PICK
92 && (!key
->oartifact
|| obj
->oartifact
))
93 return key
; /* drop the one we earlier decided to keep */
96 /* keep lock-pick in preference to credit card */
97 if (key
&& key
->otyp
== CREDIT_CARD
98 && (!key
->oartifact
|| obj
->oartifact
))
102 if (!key
|| (obj
->oartifact
&& !key
->oartifact
)) {
105 key
= obj
; /* keep this unlocking tool */
114 if (!obj
->owornmask
&& obj
!= wep
)
118 return (struct obj
*) 0; /* don't drop anything */
121 static NEARDATA
const char nofetch
[] = { BALL_CLASS
, CHAIN_CLASS
, ROCK_CLASS
,
124 STATIC_VAR xchar gtyp
, gx
, gy
; /* type and position of dog's current goal */
126 STATIC_PTR
void FDECL(wantdoor
, (int, int, genericptr_t
));
129 cursed_object_at(x
, y
)
134 for (otmp
= level
.objects
[x
][y
]; otmp
; otmp
= otmp
->nexthere
)
141 dog_nutrition(mtmp
, obj
)
148 * It is arbitrary that the pet takes the same length of time to eat
149 * as a human, but gets more nutritional value.
151 if (obj
->oclass
== FOOD_CLASS
) {
152 if (obj
->otyp
== CORPSE
) {
153 mtmp
->meating
= 3 + (mons
[obj
->corpsenm
].cwt
>> 6);
154 nutrit
= mons
[obj
->corpsenm
].cnutrit
;
156 mtmp
->meating
= objects
[obj
->otyp
].oc_delay
;
157 nutrit
= objects
[obj
->otyp
].oc_nutrition
;
159 switch (mtmp
->data
->msize
) {
181 mtmp
->meating
= eaten_stat(mtmp
->meating
, obj
);
182 nutrit
= eaten_stat(nutrit
, obj
);
184 } else if (obj
->oclass
== COIN_CLASS
) {
185 mtmp
->meating
= (int) (obj
->quan
/ 2000) + 1;
186 if (mtmp
->meating
< 0)
188 nutrit
= (int) (obj
->quan
/ 20);
192 /* Unusual pet such as gelatinous cube eating odd stuff.
193 * meating made consistent with wild monsters in mon.c.
194 * nutrit made consistent with polymorphed player nutrit in
195 * eat.c. (This also applies to pets eating gold.)
197 mtmp
->meating
= obj
->owt
/ 20 + 1;
198 nutrit
= 5 * objects
[obj
->otyp
].oc_nutrition
;
203 /* returns 2 if pet dies, otherwise 1 */
205 dog_eat(mtmp
, obj
, x
, y
, devour
)
206 register struct monst
*mtmp
;
207 register struct obj
*obj
; /* if unpaid, then thrown or kicked by hero */
208 int x
, y
; /* dog's starting location, might be different from current */
211 register struct edog
*edog
= EDOG(mtmp
);
212 boolean poly
, grow
, heal
, slimer
, deadmimic
;
215 char objnambuf
[BUFSZ
];
218 if (edog
->hungrytime
< monstermoves
)
219 edog
->hungrytime
= monstermoves
;
220 nutrit
= dog_nutrition(mtmp
, obj
);
222 deadmimic
= (obj
->otyp
== CORPSE
&& (obj
->corpsenm
== PM_SMALL_MIMIC
223 || obj
->corpsenm
== PM_LARGE_MIMIC
224 || obj
->corpsenm
== PM_GIANT_MIMIC
));
225 slimer
= (obj
->otyp
== CORPSE
&& obj
->corpsenm
== PM_GREEN_SLIME
);
226 poly
= polyfodder(obj
);
227 grow
= mlevelgain(obj
);
231 if (mtmp
->meating
> 1)
234 nutrit
= (nutrit
* 3) / 4;
236 edog
->hungrytime
+= nutrit
;
238 if (edog
->mhpmax_penalty
) {
239 /* no longer starving */
240 mtmp
->mhpmax
+= edog
->mhpmax_penalty
;
241 edog
->mhpmax_penalty
= 0;
243 if (mtmp
->mflee
&& mtmp
->mfleetim
> 1)
245 if (mtmp
->mtame
< 20)
247 if (x
!= mtmp
->mx
|| y
!= mtmp
->my
) { /* moved & ate on same turn */
249 newsym(mtmp
->mx
, mtmp
->my
);
252 /* food items are eaten one at a time; entire stack for other stuff */
253 if (obj
->quan
> 1L && obj
->oclass
== FOOD_CLASS
)
254 obj
= splitobj(obj
, 1L);
256 iflags
.suppress_price
++;
257 if (is_pool(x
, y
) && !Underwater
) {
258 /* Don't print obj */
259 /* TODO: Reveal presence of sea monster (especially sharks) */
261 /* food is at monster's current location, <mx,my>;
262 <x,y> was monster's location at start of this turn;
263 they might be the same but will be different when
264 the monster is moving+eating on same turn */
265 boolean seeobj
= cansee(mtmp
->mx
, mtmp
->my
),
266 sawpet
= cansee(x
, y
) && mon_visible(mtmp
);
268 /* Observe the action if either the food location or the pet
269 itself is in view. When pet which was in view moves to an
270 unseen spot to eat the food there, avoid referring to that
271 pet as "it". However, we want "it" if invisible/unsensed
272 pet eats visible food. */
273 if (sawpet
|| (seeobj
&& canspotmon(mtmp
))) {
274 if (tunnels(mtmp
->data
))
275 pline("%s digs in.", noit_Monnam(mtmp
));
277 pline("%s %s %s.", noit_Monnam(mtmp
),
278 devour
? "devours" : "eats", distant_name(obj
, doname
));
280 pline("It %s %s.", devour
? "devours" : "eats",
281 distant_name(obj
, doname
));
284 Strcpy(objnambuf
, xname(obj
));
285 iflags
.suppress_price
--;
287 /* It's a reward if it's DOGFOOD and the player dropped/threw it.
288 We know the player had it if invlet is set. -dlc */
289 if (dogfood(mtmp
, obj
) == DOGFOOD
&& obj
->invlet
)
293 edog
->apport
+= (int) (200L / ((long) edog
->dropdist
+ monstermoves
296 if (mtmp
->data
== &mons
[PM_RUST_MONSTER
] && obj
->oerodeproof
) {
297 /* The object's rustproofing is gone now */
299 costly_alteration(obj
, COST_DEGRD
);
300 obj
->oerodeproof
= 0;
302 if (canseemon(mtmp
) && flags
.verbose
) {
303 pline("%s spits %s out in disgust!", Monnam(mtmp
),
304 distant_name(obj
, doname
));
306 } else if (obj
== uball
) {
308 delobj(obj
); /* we assume this can't be unpaid */
309 } else if (obj
== uchain
) {
313 /* edible item owned by shop has been thrown or kicked
314 by hero and caught by tame or food-tameable monst */
315 oprice
= unpaid_cost(obj
, TRUE
);
316 pline("That %s will cost you %ld %s.", objnambuf
, oprice
,
318 /* delobj->obfree will handle actual shop billing update */
323 #if 0 /* pet is eating, so slime recovery is not feasible... */
324 /* turning into slime might be cureable */
325 if (slimer
&& munslime(mtmp
, FALSE
)) {
326 /* but the cure (fire directed at self) might be fatal */
329 slimer
= FALSE
; /* sliming is avoided, skip polymorph */
333 if (poly
|| slimer
) {
334 struct permonst
*ptr
= slimer
? &mons
[PM_GREEN_SLIME
] : 0;
336 (void) newcham(mtmp
, ptr
, FALSE
, cansee(mtmp
->mx
, mtmp
->my
));
339 /* limit "instant" growth to prevent potential abuse */
340 if (grow
&& (int) mtmp
->m_lev
< (int) mtmp
->data
->mlevel
+ 15) {
341 if (!grow_up(mtmp
, (struct monst
*) 0))
345 mtmp
->mhp
= mtmp
->mhpmax
;
351 /* hunger effects -- returns TRUE on starvation */
353 dog_hunger(mtmp
, edog
)
357 if (monstermoves
> edog
->hungrytime
+ 500) {
358 if (!carnivorous(mtmp
->data
) && !herbivorous(mtmp
->data
)) {
359 edog
->hungrytime
= monstermoves
+ 500;
360 /* but not too high; it might polymorph */
361 } else if (!edog
->mhpmax_penalty
) {
362 /* starving pets are limited in healing */
363 int newmhpmax
= mtmp
->mhpmax
/ 3;
365 edog
->mhpmax_penalty
= mtmp
->mhpmax
- newmhpmax
;
366 mtmp
->mhpmax
= newmhpmax
;
367 if (mtmp
->mhp
> mtmp
->mhpmax
)
368 mtmp
->mhp
= mtmp
->mhpmax
;
371 if (cansee(mtmp
->mx
, mtmp
->my
))
372 pline("%s is confused from hunger.", Monnam(mtmp
));
373 else if (couldsee(mtmp
->mx
, mtmp
->my
))
376 You_feel("worried about %s.", y_monnam(mtmp
));
378 } else if (monstermoves
> edog
->hungrytime
+ 750 || mtmp
->mhp
< 1) {
380 if (mtmp
->mleashed
&& mtmp
!= u
.usteed
)
381 Your("leash goes slack.");
382 else if (cansee(mtmp
->mx
, mtmp
->my
))
383 pline("%s starves.", Monnam(mtmp
));
385 You_feel("%s for a moment.",
386 Hallucination
? "bummed" : "sad");
394 /* do something with object (drop, pick up, eat) at current position
395 * returns 1 if object eaten (since that counts as dog's move), 2 if died
398 dog_invent(mtmp
, edog
, udist
)
399 register struct monst
*mtmp
;
400 register struct edog
*edog
;
403 register int omx
, omy
, carryamt
= 0;
404 struct obj
*obj
, *otmp
;
406 if (mtmp
->msleeping
|| !mtmp
->mcanmove
)
412 /* If we are carrying something then we drop it (perhaps near @).
413 * Note: if apport == 1 then our behaviour is independent of udist.
414 * Use udist+1 so steed won't cause divide by zero.
416 if (droppables(mtmp
)) {
417 if (!rn2(udist
+ 1) || !rn2(edog
->apport
))
418 if (rn2(10) < edog
->apport
) {
419 relobj(mtmp
, (int) mtmp
->minvis
, TRUE
);
420 if (edog
->apport
> 1)
422 edog
->dropdist
= udist
; /* hpscdi!jon */
423 edog
->droptime
= monstermoves
;
426 if ((obj
= level
.objects
[omx
][omy
]) != 0
427 && !index(nofetch
, obj
->oclass
)
429 && obj
->otyp
!= SCR_MAIL
432 int edible
= dogfood(mtmp
, obj
);
434 if ((edible
<= CADAVER
435 /* starving pet is more aggressive about eating */
436 || (edog
->mhpmax_penalty
&& edible
== ACCFOOD
))
437 && could_reach_item(mtmp
, obj
->ox
, obj
->oy
))
438 return dog_eat(mtmp
, obj
, omx
, omy
, FALSE
);
440 carryamt
= can_carry(mtmp
, obj
);
441 if (carryamt
> 0 && !obj
->cursed
442 && could_reach_item(mtmp
, obj
->ox
, obj
->oy
)) {
443 if (rn2(20) < edog
->apport
+ 3) {
444 if (rn2(udist
) || !rn2(edog
->apport
)) {
446 if (carryamt
!= obj
->quan
)
447 otmp
= splitobj(obj
, carryamt
);
448 if (cansee(omx
, omy
) && flags
.verbose
)
449 pline("%s picks up %s.", Monnam(mtmp
),
450 distant_name(otmp
, doname
));
451 obj_extract_self(otmp
);
453 (void) mpickobj(mtmp
, otmp
);
454 if (attacktype(mtmp
->data
, AT_WEAP
)
455 && mtmp
->weapon_check
== NEED_WEAPON
) {
456 mtmp
->weapon_check
= NEED_HTH_WEAPON
;
457 (void) mon_wield_item(mtmp
);
459 m_dowear(mtmp
, FALSE
);
468 /* set dog's goal -- gtyp, gx, gy;
469 returns -1/0/1 (dog's desire to approach player) or -2 (abort move) */
471 dog_goal(mtmp
, edog
, after
, udist
, whappr
)
472 register struct monst
*mtmp
;
474 int after
, udist
, whappr
;
476 register int omx
, omy
;
477 boolean in_masters_sight
, dog_has_minvent
;
478 register struct obj
*obj
;
482 /* Steeds don't move on their own will */
483 if (mtmp
== u
.usteed
)
489 in_masters_sight
= couldsee(omx
, omy
);
490 dog_has_minvent
= (droppables(mtmp
) != 0);
492 if (!edog
|| mtmp
->mleashed
) { /* he's not going anywhere... */
497 #define DDIST(x, y) (dist2(x, y, omx, omy))
498 #define SQSRCHRADIUS 5
499 int min_x
, max_x
, min_y
, max_y
;
502 gtyp
= UNDEF
; /* no goal as yet */
503 gx
= gy
= 0; /* suppress 'used before set' message */
505 if ((min_x
= omx
- SQSRCHRADIUS
) < 1)
507 if ((max_x
= omx
+ SQSRCHRADIUS
) >= COLNO
)
509 if ((min_y
= omy
- SQSRCHRADIUS
) < 0)
511 if ((max_y
= omy
+ SQSRCHRADIUS
) >= ROWNO
)
514 /* nearby food is the first choice, then other objects */
515 for (obj
= fobj
; obj
; obj
= obj
->nobj
) {
518 if (nx
>= min_x
&& nx
<= max_x
&& ny
>= min_y
&& ny
<= max_y
) {
519 otyp
= dogfood(mtmp
, obj
);
520 /* skip inferior goals */
521 if (otyp
> gtyp
|| otyp
== UNDEF
)
523 /* avoid cursed items unless starving */
524 if (cursed_object_at(nx
, ny
)
525 && !(edog
->mhpmax_penalty
&& otyp
< MANFOOD
))
527 /* skip completely unreachable goals */
528 if (!could_reach_item(mtmp
, nx
, ny
)
529 || !can_reach_location(mtmp
, mtmp
->mx
, mtmp
->my
, nx
, ny
))
531 if (otyp
< MANFOOD
) {
532 if (otyp
< gtyp
|| DDIST(nx
, ny
) < DDIST(gx
, gy
)) {
537 } else if (gtyp
== UNDEF
&& in_masters_sight
539 && (!levl
[omx
][omy
].lit
|| levl
[u
.ux
][u
.uy
].lit
)
540 && (otyp
== MANFOOD
|| m_cansee(mtmp
, nx
, ny
))
541 && edog
->apport
> rn2(8)
542 && can_carry(mtmp
, obj
) > 0) {
551 /* follow player if appropriate */
552 if (gtyp
== UNDEF
|| (gtyp
!= DOGFOOD
&& gtyp
!= APPORT
553 && monstermoves
< edog
->hungrytime
)) {
556 if (after
&& udist
<= 4 && gx
== u
.ux
&& gy
== u
.uy
)
558 appr
= (udist
>= 9) ? 1 : (mtmp
->mflee
) ? -1 : 0;
560 if (!IS_ROOM(levl
[u
.ux
][u
.uy
].typ
) || !rn2(4) || whappr
561 || (dog_has_minvent
&& rn2(edog
->apport
)))
564 /* if you have dog food it'll follow you more closely */
566 for (obj
= invent
; obj
; obj
= obj
->nobj
)
567 if (dogfood(mtmp
, obj
) == DOGFOOD
) {
572 appr
= 1; /* gtyp != UNDEF */
576 #define FARAWAY (COLNO + 2) /* position outside screen */
577 if (gx
== u
.ux
&& gy
== u
.uy
&& !in_masters_sight
) {
580 cp
= gettrack(omx
, omy
);
587 /* assume master hasn't moved far, and reuse previous goal */
588 if (edog
&& edog
->ogoal
.x
589 && (edog
->ogoal
.x
!= omx
|| edog
->ogoal
.y
!= omy
)) {
594 int fardist
= FARAWAY
* FARAWAY
;
595 gx
= gy
= FARAWAY
; /* random */
596 do_clear_area(omx
, omy
, 9, wantdoor
, (genericptr_t
) &fardist
);
598 /* here gx == FARAWAY e.g. when dog is in a vault */
599 if (gx
== FARAWAY
|| (gx
== omx
&& gy
== omy
)) {
615 STATIC_OVL
struct monst
*
616 find_targ(mtmp
, dx
, dy
, maxdist
)
617 register struct monst
*mtmp
;
621 struct monst
*targ
= 0;
622 int curx
= mtmp
->mx
, cury
= mtmp
->my
;
626 for ( ; dist
< maxdist
; ++dist
) {
629 if (!isok(curx
, cury
))
632 /* FIXME: Check if we hit a wall/door/boulder to
633 * short-circuit unnecessary subsequent checks
636 /* If we can't see up to here, forget it - will this
637 * mean pets in corridors don't breathe at monsters
638 * in rooms? If so, is that necessarily bad?
640 if (!m_cansee(mtmp
, curx
, cury
))
643 targ
= m_at(curx
, cury
);
645 if (curx
== mtmp
->mux
&& cury
== mtmp
->muy
)
649 /* Is the monster visible to the pet? */
650 if ((!targ
->minvis
|| perceives(mtmp
->data
)) &&
654 /* If the pet can't see it, it assumes it aint there */
662 find_friends(mtmp
, mtarg
, maxdist
)
663 struct monst
*mtmp
, *mtarg
;
667 int dx
= sgn(mtarg
->mx
- mtmp
->mx
),
668 dy
= sgn(mtarg
->my
- mtmp
->my
);
669 int curx
= mtarg
->mx
, cury
= mtarg
->my
;
670 int dist
= distmin(mtarg
->mx
, mtarg
->my
, mtmp
->mx
, mtmp
->my
);
672 for ( ; dist
<= maxdist
; ++dist
) {
676 if (!isok(curx
, cury
))
679 /* If the pet can't see beyond this point, don't
682 if (!m_cansee(mtmp
, curx
, cury
))
685 /* Does pet think you're here? */
686 if (mtmp
->mux
== curx
&& mtmp
->muy
== cury
)
689 pal
= m_at(curx
, cury
);
693 /* Pet won't notice invisible pets */
694 if (!pal
->minvis
|| perceives(mtmp
->data
))
697 /* Quest leaders and guardians are always seen */
698 if (pal
->data
->msound
== MS_LEADER
699 || pal
->data
->msound
== MS_GUARDIAN
)
708 score_targ(mtmp
, mtarg
)
709 struct monst
*mtmp
, *mtarg
;
713 /* If the monster is confused, normal scoring is disrupted -
714 * anything may happen
717 /* Give 1 in 3 chance of safe breathing even if pet is confused or
718 * if you're on the quest start level */
719 if (!mtmp
->mconf
|| !rn2(3) || Is_qstart(&u
.uz
)) {
720 aligntyp align1
= A_NONE
, align2
= A_NONE
; /* For priests, minions */
721 boolean faith1
= TRUE
, faith2
= TRUE
;
724 align1
= EMIN(mtmp
)->min_align
;
725 else if (mtmp
->ispriest
)
726 align1
= EPRI(mtmp
)->shralign
;
730 align2
= EMIN(mtarg
)->min_align
; /* MAR */
731 else if (mtarg
->ispriest
)
732 align2
= EPRI(mtarg
)->shralign
; /* MAR */
736 /* Never target quest friendlies */
737 if (mtarg
->data
->msound
== MS_LEADER
738 || mtarg
->data
->msound
== MS_GUARDIAN
)
740 /* D: Fixed angelic beings using gaze attacks on coaligned priests */
741 if (faith1
&& faith2
&& align1
== align2
&& mtarg
->mpeaceful
) {
745 /* Is monster adjacent? */
746 if (distmin(mtmp
->mx
, mtmp
->my
, mtarg
->mx
, mtarg
->my
) <= 1) {
750 /* Is the monster peaceful or tame? */
751 if (/*mtarg->mpeaceful ||*/ mtarg
->mtame
|| mtarg
== &youmonst
) {
752 /* Pets will never be targeted */
756 /* Is master/pet behind monster? Check up to 15 squares beyond pet. */
757 if (find_friends(mtmp
, mtarg
, 15)) {
761 /* Target hostile monsters in preference to peaceful ones */
762 if (!mtarg
->mpeaceful
)
764 /* Is the monster passive? Don't waste energy on it, if so */
765 if (mtarg
->data
->mattk
[0].aatyp
== AT_NONE
)
767 /* Even weak pets with breath attacks shouldn't take on very
768 low-level monsters. Wasting breath on lichens is ridiculous. */
769 if ((mtarg
->m_lev
< 2 && mtmp
->m_lev
> 5)
770 || (mtmp
->m_lev
> 12 && mtarg
->m_lev
< mtmp
->m_lev
- 9
771 && u
.ulevel
> 8 && mtarg
->m_lev
< u
.ulevel
- 7))
773 /* And pets will hesitate to attack vastly stronger foes.
774 This penalty will be discarded if master's in trouble. */
775 if (mtarg
->m_lev
> mtmp
->m_lev
+ 4L)
776 score
-= (mtarg
->m_lev
- mtmp
->m_lev
) * 20L;
777 /* All things being the same, go for the beefiest monster. This
778 bonus should not be large enough to override the pet's aversion
779 to attacking much stronger monsters. */
780 score
+= mtarg
->m_lev
* 2 + mtarg
->mhp
/ 3;
782 /* Fuzz factor to make things less predictable when very
783 similar targets are abundant. */
785 /* Pet may decide not to use ranged attack when confused */
786 if (mtmp
->mconf
&& !rn2(3))
792 STATIC_OVL
struct monst
*
794 struct monst
*mtmp
; /* Pet */
797 long bestscore
= -40000L, currscore
;
798 struct monst
*best_targ
= 0, *temp_targ
= 0;
804 /* If the pet is blind, it's not going to see any target */
808 /* Search for any monsters lined up with the pet, within an arbitrary
809 * distance from the pet (7 squares, even along diagonals). Monsters
810 * are assigned scores and the best score is chosen.
812 for (dy
= -1; dy
< 2; ++dy
) {
813 for (dx
= -1; dx
< 2; ++dx
) {
816 /* Traverse the line to find the first monster within 7
817 * squares. Invisible monsters are skipped (if the
818 * pet doesn't have see invisible).
820 temp_targ
= find_targ(mtmp
, dx
, dy
, 7);
822 /* Nothing in this line? */
826 /* Decide how attractive the target is */
827 currscore
= score_targ(mtmp
, temp_targ
);
829 if (currscore
> bestscore
) {
830 bestscore
= currscore
;
831 best_targ
= temp_targ
;
836 /* Filter out targets the pet doesn't like */
844 /* return 0 (no move), 1 (move) or 2 (dead) */
846 dog_move(mtmp
, after
)
847 register struct monst
*mtmp
;
848 int after
; /* this is extra fast monster movement */
850 int omx
, omy
; /* original mtmp position */
851 int appr
, whappr
, udist
;
853 register struct edog
*edog
= EDOG(mtmp
);
854 struct obj
*obj
= (struct obj
*) 0;
856 boolean has_edog
, cursemsg
[9], do_eat
= FALSE
;
857 boolean better_with_displacing
= FALSE
;
858 xchar nix
, niy
; /* position mtmp is (considering) moving to */
859 register int nx
, ny
; /* temporary coordinates */
860 xchar cnt
, uncursedcnt
, chcnt
;
861 int chi
= -1, nidist
, ndist
;
863 long info
[9], allowflags
;
864 #define GDIST(x, y) (dist2(x, y, gx, gy))
867 * Tame Angels have isminion set and an ispriest structure instead of
868 * an edog structure. Fortunately, guardian Angels need not worry
869 * about mundane things like eating and fetching objects, and can
870 * spend all their energy defending the player. (They are the only
871 * monsters with other structures that can be tame.)
873 has_edog
= !mtmp
->isminion
;
877 if (has_edog
&& dog_hunger(mtmp
, edog
))
878 return 2; /* starved */
880 udist
= distu(omx
, omy
);
881 /* Let steeds eat and maybe throw rider during Conflict */
882 if (mtmp
== u
.usteed
) {
883 if (Conflict
&& !resist(mtmp
, RING_CLASS
, 0, 0)) {
884 dismount_steed(DISMOUNT_THROWN
);
889 /* maybe we tamed him while being swallowed --jgm */
892 nix
= omx
; /* set before newdogpos */
894 cursemsg
[0] = FALSE
; /* lint suppression */
895 info
[0] = 0; /* ditto */
898 j
= dog_invent(mtmp
, edog
, udist
);
902 goto newdogpos
; /* eating something */
904 whappr
= (monstermoves
- edog
->whistletime
< 5);
908 appr
= dog_goal(mtmp
, has_edog
? edog
: (struct edog
*) 0, after
, udist
,
913 allowflags
= ALLOW_M
| ALLOW_TRAPS
| ALLOW_SSM
| ALLOW_SANCT
;
914 if (passes_walls(mtmp
->data
))
915 allowflags
|= (ALLOW_ROCK
| ALLOW_WALL
);
916 if (passes_bars(mtmp
->data
))
917 allowflags
|= ALLOW_BARS
;
918 if (throws_rocks(mtmp
->data
))
919 allowflags
|= ALLOW_ROCK
;
920 if (is_displacer(mtmp
->data
))
921 allowflags
|= ALLOW_MDISP
;
922 if (Conflict
&& !resist(mtmp
, RING_CLASS
, 0, 0)) {
923 allowflags
|= ALLOW_U
;
925 /* Guardian angel refuses to be conflicted; rather,
926 * it disappears, angrily, and sends in some nasties
928 lose_guardian_angel(mtmp
);
929 return 2; /* current monster is gone */
932 #if 0 /* [this is now handled in dochug()] */
933 if (!Conflict
&& !mtmp
->mconf
934 && mtmp
== u
.ustuck
&& !sticks(youmonst
.data
)) {
935 unstuck(mtmp
); /* swallowed case handled above */
936 You("get released!");
939 if (!nohands(mtmp
->data
) && !verysmall(mtmp
->data
)) {
940 allowflags
|= OPENDOOR
;
941 if (monhaskey(mtmp
, TRUE
))
942 allowflags
|= UNLOCKDOOR
;
943 /* note: the Wizard and Riders can unlock doors without a key;
944 they won't use that ability if someone manages to tame them */
946 if (is_giant(mtmp
->data
))
947 allowflags
|= BUSTDOOR
;
948 if (tunnels(mtmp
->data
)
949 && !Is_rogue_level(&u
.uz
)) /* same restriction as m_move() */
950 allowflags
|= ALLOW_DIG
;
951 cnt
= mfndpos(mtmp
, poss
, info
, allowflags
);
953 /* Normally dogs don't step on cursed items, but if they have no
954 * other choice they will. This requires checking ahead of time
955 * to see how many uncursed item squares are around.
958 for (i
= 0; i
< cnt
; i
++) {
961 if (MON_AT(nx
, ny
) && !((info
[i
] & ALLOW_M
) || info
[i
] & ALLOW_MDISP
))
963 if (cursed_object_at(nx
, ny
))
968 better_with_displacing
= should_displace(mtmp
, poss
, info
, cnt
, gx
, gy
);
972 nidist
= GDIST(nix
, niy
);
974 for (i
= 0; i
< cnt
; i
++) {
979 /* if leashed, we drag him along. */
980 if (mtmp
->mleashed
&& distu(nx
, ny
) > 4)
983 /* if a guardian, try to stay close by choice */
984 if (!has_edog
&& (j
= distu(nx
, ny
)) > 16 && j
>= udist
)
987 if ((info
[i
] & ALLOW_M
) && MON_AT(nx
, ny
)) {
989 register struct monst
*mtmp2
= m_at(nx
, ny
);
991 if ((int) mtmp2
->m_lev
>= (int) mtmp
->m_lev
+ 2
992 || (mtmp2
->data
== &mons
[PM_FLOATING_EYE
] && rn2(10)
993 && mtmp
->mcansee
&& haseyes(mtmp
->data
) && mtmp2
->mcansee
994 && (perceives(mtmp
->data
) || !mtmp2
->minvis
))
995 || (mtmp2
->data
== &mons
[PM_GELATINOUS_CUBE
] && rn2(10))
996 || (max_passive_dmg(mtmp2
, mtmp
) >= mtmp
->mhp
)
997 || ((mtmp
->mhp
* 4 < mtmp
->mhpmax
998 || mtmp2
->data
->msound
== MS_GUARDIAN
999 || mtmp2
->data
->msound
== MS_LEADER
) && mtmp2
->mpeaceful
1001 || (touch_petrifies(mtmp2
->data
) && !resists_ston(mtmp
)))
1005 return 0; /* hit only once each move */
1008 mstatus
= mattackm(mtmp
, mtmp2
);
1010 /* aggressor (pet) died */
1011 if (mstatus
& MM_AGR_DIED
)
1014 if ((mstatus
& MM_HIT
) && !(mstatus
& MM_DEF_DIED
) && rn2(4)
1015 && mtmp2
->mlstmv
!= monstermoves
1016 && !onscary(mtmp
->mx
, mtmp
->my
, mtmp2
)
1017 /* monnear check needed: long worms hit on tail */
1018 && monnear(mtmp2
, mtmp
->mx
, mtmp
->my
)) {
1019 mstatus
= mattackm(mtmp2
, mtmp
); /* return attack */
1020 if (mstatus
& MM_DEF_DIED
)
1025 if ((info
[i
] & ALLOW_MDISP
) && MON_AT(nx
, ny
)
1026 && better_with_displacing
&& !undesirable_disp(mtmp
, nx
, ny
)) {
1028 register struct monst
*mtmp2
= m_at(nx
, ny
);
1030 mstatus
= mdisplacem(mtmp
, mtmp2
, FALSE
); /* displace monster */
1031 if (mstatus
& MM_DEF_DIED
)
1037 /* Dog avoids harmful traps, but perhaps it has to pass one
1038 * in order to follow player. (Non-harmful traps do not
1039 * have ALLOW_TRAPS in info[].) The dog only avoids the
1040 * trap if you've seen it, unlike enemies who avoid traps
1041 * if they've seen some trap of that type sometime in the
1042 * past. (Neither behavior is really realistic.)
1046 if ((info
[i
] & ALLOW_TRAPS
) && (trap
= t_at(nx
, ny
))) {
1047 if (mtmp
->mleashed
) {
1051 /* 1/40 chance of stepping on it anyway, in case
1052 * it has to pass one to follow the player...
1054 if (trap
->tseen
&& rn2(40))
1060 /* dog eschews cursed objects, but likes dog food */
1061 /* (minion isn't interested; `cursemsg' stays FALSE) */
1063 for (obj
= level
.objects
[nx
][ny
]; obj
; obj
= obj
->nexthere
) {
1066 } else if ((otyp
= dogfood(mtmp
, obj
)) < MANFOOD
1068 || edog
->hungrytime
<= monstermoves
)) {
1069 /* Note: our dog likes the food so much that he
1070 * might eat it even when it conceals a cursed object */
1075 cursemsg
[i
] = FALSE
; /* not reluctant */
1079 /* didn't find something to eat; if we saw a cursed item and
1080 aren't being forced to walk on it, usually keep looking */
1081 if (cursemsg
[i
] && !mtmp
->mleashed
&& uncursedcnt
> 0
1082 && rn2(13 * uncursedcnt
))
1085 /* lessen the chance of backtracking to previous position(s) */
1086 k
= has_edog
? uncursedcnt
: cnt
;
1087 for (j
= 0; j
< MTSZ
&& j
< k
- 1; j
++)
1088 if (nx
== mtmp
->mtrack
[j
].x
&& ny
== mtmp
->mtrack
[j
].y
)
1089 if (rn2(MTSZ
* (k
- j
)))
1092 j
= ((ndist
= GDIST(nx
, ny
)) - nidist
) * appr
;
1093 if ((j
== 0 && !rn2(++chcnt
)) || j
< 0
1094 || (j
> 0 && !whappr
1095 && ((omx
== nix
&& omy
== niy
&& !rn2(3)) || !rn2(12)))) {
1107 /* Pet hasn't attacked anything but is considering moving -
1108 * now's the time for ranged attacks. Note that the pet can move
1109 * after it performs its ranged attack. Should this be changed?
1112 struct monst
*mtarg
;
1115 /* How hungry is the pet? */
1116 if (!mtmp
->isminion
) {
1117 struct edog
*dog
= EDOG(mtmp
);
1118 hungry
= (monstermoves
> (dog
->hungrytime
+ 300));
1121 /* Identify the best target in a straight line from the pet;
1122 * if there is such a target, we'll let the pet attempt an
1125 mtarg
= best_target(mtmp
);
1127 /* Hungry pets are unlikely to use breath/spit attacks */
1128 if (mtarg
&& (!hungry
|| !rn2(5))) {
1131 if (mtarg
== &youmonst
) {
1135 mstatus
= mattackm(mtmp
, mtarg
);
1137 /* Shouldn't happen, really */
1138 if (mstatus
& MM_AGR_DIED
)
1141 /* Allow the targeted nasty to strike back - if
1142 * the targeted beast doesn't have a ranged attack,
1143 * nothing will happen.
1145 if ((mstatus
& MM_HIT
) && !(mstatus
& MM_DEF_DIED
)
1146 && rn2(4) && mtarg
!= &youmonst
) {
1148 /* Can monster see? If it can, it can retaliate
1149 * even if the pet is invisible, since it'll see
1150 * the direction from which the ranged attack came;
1151 * if it's blind or unseeing, it can't retaliate
1153 if (mtarg
->mcansee
&& haseyes(mtarg
->data
)) {
1154 mstatus
= mattackm(mtarg
, mtmp
);
1155 if (mstatus
& MM_DEF_DIED
)
1164 if (nix
!= omx
|| niy
!= omy
) {
1167 if (info
[chi
] & ALLOW_U
) {
1168 if (mtmp
->mleashed
) { /* play it safe */
1169 pline("%s breaks loose of %s leash!", Monnam(mtmp
),
1171 m_unleash(mtmp
, FALSE
);
1173 (void) mattacku(mtmp
);
1176 if (!m_in_out_region(mtmp
, nix
, niy
))
1178 if (m_digweapon_check(mtmp
, nix
,niy
))
1181 /* insert a worm_move() if worms ever begin to eat things */
1182 wasseen
= canseemon(mtmp
);
1183 remove_monster(omx
, omy
);
1184 place_monster(mtmp
, nix
, niy
);
1185 if (cursemsg
[chi
] && (wasseen
|| canseemon(mtmp
))) {
1186 /* describe top item of pile, not necessarily cursed item itself;
1187 don't use glyph_at() here--it would return the pet but we want
1188 to know whether an object is remembered at this map location */
1189 struct obj
*o
= (!Hallucination
&& level
.flags
.hero_memory
1190 && glyph_is_object(levl
[nix
][niy
].glyph
))
1191 ? vobj_at(nix
, niy
) : 0;
1192 const char *what
= o
? distant_name(o
, doname
) : something
;
1194 pline("%s %s reluctantly over %s.", noit_Monnam(mtmp
),
1195 vtense((char *) 0, locomotion(mtmp
->data
, "step")), what
);
1197 for (j
= MTSZ
- 1; j
> 0; j
--)
1198 mtmp
->mtrack
[j
] = mtmp
->mtrack
[j
- 1];
1199 mtmp
->mtrack
[0].x
= omx
;
1200 mtmp
->mtrack
[0].y
= omy
;
1201 /* We have to know if the pet's going to do a combined eat and
1202 * move before moving it, but it can't eat until after being
1203 * moved. Thus the do_eat flag.
1206 if (dog_eat(mtmp
, obj
, omx
, omy
, FALSE
) == 2)
1209 } else if (mtmp
->mleashed
&& distu(omx
, omy
) > 4) {
1210 /* an incredible kludge, but the only way to keep pooch near
1211 * after it spends time eating or in a trap, etc.
1215 nx
= sgn(omx
- u
.ux
);
1216 ny
= sgn(omy
- u
.uy
);
1219 if (goodpos(cc
.x
, cc
.y
, mtmp
, 0))
1223 for (j
= (i
+ 7) % 8; j
< (i
+ 1) % 8; j
++) {
1225 if (goodpos(cc
.x
, cc
.y
, mtmp
, 0))
1228 for (j
= (i
+ 6) % 8; j
< (i
+ 2) % 8; j
++) {
1230 if (goodpos(cc
.x
, cc
.y
, mtmp
, 0))
1236 if (!m_in_out_region(mtmp
, nix
, niy
))
1238 remove_monster(mtmp
->mx
, mtmp
->my
);
1239 place_monster(mtmp
, cc
.x
, cc
.y
);
1246 /* check if a monster could pick up objects from a location */
1248 could_reach_item(mon
, nx
, ny
)
1252 if ((!is_pool(nx
, ny
) || is_swimmer(mon
->data
))
1253 && (!is_lava(nx
, ny
) || likes_lava(mon
->data
))
1254 && (!sobj_at(BOULDER
, nx
, ny
) || throws_rocks(mon
->data
)))
1259 /* Hack to prevent a dog from being endlessly stuck near an object that
1260 * it can't reach, such as caught in a teleport scroll niche. It recursively
1261 * checks to see if the squares in between are good. The checking could be
1262 * a little smarter; a full check would probably be useful in m_move() too.
1263 * Since the maximum food distance is 5, this should never be more than 5
1267 can_reach_location(mon
, mx
, my
, fx
, fy
)
1269 xchar mx
, my
, fx
, fy
;
1274 if (mx
== fx
&& my
== fy
)
1277 return FALSE
; /* should not happen */
1279 dist
= dist2(mx
, my
, fx
, fy
);
1280 for (i
= mx
- 1; i
<= mx
+ 1; i
++) {
1281 for (j
= my
- 1; j
<= my
+ 1; j
++) {
1284 if (dist2(i
, j
, fx
, fy
) >= dist
)
1286 if (IS_ROCK(levl
[i
][j
].typ
) && !passes_walls(mon
->data
)
1287 && (!may_dig(i
, j
) || !tunnels(mon
->data
)))
1289 if (IS_DOOR(levl
[i
][j
].typ
)
1290 && (levl
[i
][j
].doormask
& (D_CLOSED
| D_LOCKED
)))
1292 if (!could_reach_item(mon
, i
, j
))
1294 if (can_reach_location(mon
, i
, j
, fx
, fy
))
1301 /* do_clear_area client */
1303 wantdoor(x
, y
, distance
)
1305 genericptr_t distance
;
1307 int ndist
, *dist_ptr
= (int *) distance
;
1309 if (*dist_ptr
> (ndist
= distu(x
, y
))) {
1316 static struct qmchoices
{
1317 int mndx
; /* type of pet, 0 means any */
1318 char mlet
; /* symbol of pet, 0 means any */
1319 unsigned mappearance
; /* mimic this */
1320 uchar m_ap_type
; /* what is the thing it is mimicing? */
1322 /* Things that some pets might be thinking about at the time */
1323 { PM_LITTLE_DOG
, 0, PM_KITTEN
, M_AP_MONSTER
},
1324 { PM_DOG
, 0, PM_HOUSECAT
, M_AP_MONSTER
},
1325 { PM_LARGE_DOG
, 0, PM_LARGE_CAT
, M_AP_MONSTER
},
1326 { PM_KITTEN
, 0, PM_LITTLE_DOG
, M_AP_MONSTER
},
1327 { PM_HOUSECAT
, 0, PM_DOG
, M_AP_MONSTER
},
1328 { PM_LARGE_CAT
, 0, PM_LARGE_DOG
, M_AP_MONSTER
},
1329 { PM_HOUSECAT
, 0, PM_GIANT_RAT
, M_AP_MONSTER
},
1331 M_AP_FURNITURE
}, /* sorry, no fire hydrants in NetHack */
1332 { 0, 0, TRIPE_RATION
, M_AP_OBJECT
}, /* leave this at end */
1336 finish_meating(mtmp
)
1340 if (mtmp
->m_ap_type
&& mtmp
->mappearance
&& mtmp
->cham
== NON_PM
) {
1341 /* was eating a mimic and now appearance needs resetting */
1342 mtmp
->m_ap_type
= 0;
1343 mtmp
->mappearance
= 0;
1344 newsym(mtmp
->mx
, mtmp
->my
);
1352 int idx
= 0, trycnt
= 5, spotted
;
1355 if (Protection_from_shape_changers
|| !mtmp
->meating
)
1359 idx
= rn2(SIZE(qm
));
1360 if (qm
[idx
].mndx
!= 0 && monsndx(mtmp
->data
) == qm
[idx
].mndx
)
1362 if (qm
[idx
].mlet
!= 0 && mtmp
->data
->mlet
== qm
[idx
].mlet
)
1364 if (qm
[idx
].mndx
== 0 && qm
[idx
].mlet
== 0)
1366 } while (--trycnt
> 0);
1370 Strcpy(buf
, mon_nam(mtmp
));
1371 spotted
= canspotmon(mtmp
);
1373 mtmp
->m_ap_type
= qm
[idx
].m_ap_type
;
1374 mtmp
->mappearance
= qm
[idx
].mappearance
;
1376 if (spotted
|| cansee(mtmp
->mx
, mtmp
->my
) || canspotmon(mtmp
)) {
1377 /* this isn't quite right; if sensing a monster without being
1378 able to see its location, you really shouldn't be told you
1379 sense it becoming furniture or an object that you can't see
1380 (on the other hand, perhaps you're sensing a brief glimpse
1381 of its mind as it changes form) */
1382 newsym(mtmp
->mx
, mtmp
->my
);
1383 You("%s %s %sappear%s where %s was!",
1384 cansee(mtmp
->mx
, mtmp
->my
) ? "see" : "sense that",
1385 (mtmp
->m_ap_type
== M_AP_FURNITURE
)
1386 ? an(defsyms
[mtmp
->mappearance
].explanation
)
1387 : (mtmp
->m_ap_type
== M_AP_OBJECT
1388 && OBJ_DESCR(objects
[mtmp
->mappearance
]))
1389 ? an(OBJ_DESCR(objects
[mtmp
->mappearance
]))
1390 : (mtmp
->m_ap_type
== M_AP_OBJECT
1391 && OBJ_NAME(objects
[mtmp
->mappearance
]))
1392 ? an(OBJ_NAME(objects
[mtmp
->mappearance
]))
1393 : (mtmp
->m_ap_type
== M_AP_MONSTER
)
1394 ? an(mons
[mtmp
->mappearance
].mname
)
1396 cansee(mtmp
->mx
, mtmp
->my
) ? "" : "has ",
1397 cansee(mtmp
->mx
, mtmp
->my
) ? "" : "ed",
1399 display_nhwindow(WIN_MAP
, TRUE
);