1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2 /* hack.dog.c - version 1.0.3 */
3 /* $FreeBSD: src/games/hack/hack.dog.c,v 1.3 1999/11/16 02:57:03 billf Exp $ */
6 #include "hack.mfndpos.h"
9 struct permonst li_dog
=
10 { "little dog", 'd', 2, 18, 6, 1, 6, sizeof(struct edog
) };
12 { "dog", 'd', 4, 16, 5, 1, 6, sizeof(struct edog
) };
13 struct permonst la_dog
=
14 { "large dog", 'd', 6, 15, 4, 2, 4, sizeof(struct edog
) };
16 static void initedog(struct monst
*);
17 static xchar
dogfood(struct obj
*);
22 struct monst
*mtmp
= makemon(&li_dog
, u
.ux
, u
.uy
);
25 return; /* dogs were genocided */
30 initedog(struct monst
*mtmp
)
32 mtmp
->mtame
= mtmp
->mpeaceful
= 1;
33 EDOG(mtmp
)->hungrytime
= 1000 + moves
;
34 EDOG(mtmp
)->eattime
= 0;
35 EDOG(mtmp
)->droptime
= 0;
36 EDOG(mtmp
)->dropdist
= 10000;
37 EDOG(mtmp
)->apport
= 10;
38 EDOG(mtmp
)->whistletime
= 0;
41 /* attach the monsters that went down (or up) together with @ */
42 struct monst
*mydogs
= NULL
;
43 struct monst
*fallen_down
= NULL
; /* monsters that fell through a trapdoor */
44 /* they will appear on the next level @ goes to, even if he goes up! */
51 while ((mtmp
= mydogs
)) {
57 while ((mtmp
= fallen_down
)) {
58 fallen_down
= mtmp
->nmon
;
70 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
)
71 if (dist(mtmp
->mx
, mtmp
->my
) < 3 && follower(mtmp
)
72 && !mtmp
->msleep
&& !mtmp
->mfroz
) {
77 keepdogs(); /* we destroyed the link, so use recursion */
78 return; /* (admittedly somewhat primitive) */
83 fall_down(struct monst
*mtmp
)
86 mtmp
->nmon
= fallen_down
;
92 /* return quality of food; the lower the better */
102 dogfood(struct obj
*obj
)
107 (obj
->otyp
== TRIPE_RATION
) ? DOGFOOD
:
108 (obj
->otyp
< CARROT
) ? ACCFOOD
:
109 (obj
->otyp
< CORPSE
) ? MANFOOD
:
110 (poisonous(obj
) || obj
->age
+ 50 <= moves
||
111 obj
->otyp
== DEAD_COCKATRICE
)
125 /* return 0 (no move), 1 (move) or 2 (dead) */
127 dog_move(struct monst
*mtmp
, int after
)
129 int nx
, ny
, omx
, omy
, appr
, nearer
, j
;
130 int udist
, chi
= 0, i
, whappr
;
132 struct permonst
*mdat
= mtmp
->data
;
133 struct edog
*edog
= EDOG(mtmp
);
136 xchar cnt
, chcnt
, nix
, niy
;
137 schar dogroom
, uroom
;
138 xchar gx
, gy
, gtyp
, otyp
; /* current goal */
141 #define GDIST(x, y) ((x - gx) * (x - gx) + (y - gy) * (y - gy))
142 #define DDIST(x, y) ((x - omx) * (x - omx) + (y - omy) * (y - omy))
144 if (moves
<= edog
->eattime
) /* dog is still eating */
148 whappr
= (moves
- EDOG(mtmp
)->whistletime
< 5);
149 if (moves
> edog
->hungrytime
+ 500 && !mtmp
->mconf
) {
152 if (mtmp
->mhp
> mtmp
->mhpmax
)
153 mtmp
->mhp
= mtmp
->mhpmax
;
154 if (cansee(omx
, omy
))
155 pline("%s is confused from hunger.", Monnam(mtmp
));
157 pline("You feel worried about %s.", monnam(mtmp
));
158 } else if (moves
> edog
->hungrytime
+ 750 || mtmp
->mhp
< 1) {
159 if (cansee(omx
, omy
))
160 pline("%s dies from hunger.", Monnam(mtmp
));
162 pline("You have a sad feeling for a moment, then it passes.");
166 dogroom
= inroom(omx
, omy
);
167 uroom
= inroom(u
.ux
, u
.uy
);
168 udist
= dist(omx
, omy
);
170 /* maybe we tamed him while being swallowed --jgm */
174 /* if we are carrying sth then we drop it (perhaps near @) */
175 /* Note: if apport == 1 then our behaviour is independent of udist */
177 if (!rn2(udist
) || !rn2((int)edog
->apport
))
178 if (rn2(10) < (int)edog
->apport
) {
179 relobj(mtmp
, (int)mtmp
->minvis
);
180 if (edog
->apport
> 1)
182 edog
->dropdist
= udist
; /* hpscdi!jon */
183 edog
->droptime
= moves
;
185 } else if ((obj
= o_at(omx
, omy
))) {
186 if (!strchr("0_", obj
->olet
)) {
187 if ((otyp
= dogfood(obj
)) <= CADAVER
) {
192 if (obj
->owt
< 10 * mtmp
->data
->mlevel
) {
193 if (rn2(20) < (int)edog
->apport
+ 3) {
195 !rn2((int)edog
->apport
)) {
198 /* if (levl[omx][omy].scrsym == obj->olet)
199 * newsym(omx, omy); */
207 /* first we look for food */
208 gtyp
= UNDEF
; /* no goal as yet */
209 gx
= gy
= 0; /* suppress 'used before set' message */
210 for (obj
= fobj
; obj
; obj
= obj
->nobj
) {
212 if (otyp
> gtyp
|| otyp
== UNDEF
)
214 if (inroom(obj
->ox
, obj
->oy
) != dogroom
)
216 if (otyp
< MANFOOD
&&
217 (dogroom
>= 0 || DDIST(obj
->ox
, obj
->oy
) < 10)) {
218 if (otyp
< gtyp
|| (otyp
== gtyp
&&
219 DDIST(obj
->ox
, obj
->oy
) < DDIST(gx
, gy
))) {
224 } else if (gtyp
== UNDEF
&& dogroom
>= 0 &&
226 !mtmp
->minvent
&& (int)edog
->apport
> rn2(8)) {
233 (gtyp
!= DOGFOOD
&& gtyp
!= APPORT
&& moves
< edog
->hungrytime
)) {
234 if (dogroom
< 0 || dogroom
== uroom
) {
239 int tmp
= rooms
[dogroom
].fdoor
;
240 cnt
= rooms
[dogroom
].doorct
;
242 gx
= gy
= FAR
; /* random, far away */
245 dist(doors
[tmp
].x
, doors
[tmp
].y
)) {
251 /* here gx == FAR e.g. when dog is in a vault */
252 if (gx
== FAR
|| (gx
== omx
&& gy
== omy
)) {
258 appr
= (udist
>= 9) ? 1 : (mtmp
->mflee
) ? -1 : 0;
259 if (after
&& udist
<= 4 && gx
== u
.ux
&& gy
== u
.uy
)
262 if (!IS_ROOM(levl
[u
.ux
][u
.uy
].typ
) || !rn2(4) ||
264 (mtmp
->minvent
&& rn2((int)edog
->apport
)))
267 /* if you have dog food he'll follow you more closely */
271 if (obj
->otyp
== TRIPE_RATION
) {
278 } else /* gtyp != UNDEF */
283 if (gx
== u
.ux
&& gy
== u
.uy
&& (dogroom
!= uroom
|| dogroom
< 0)) {
285 cp
= gettrack(omx
, omy
);
294 cnt
= mfndpos(mtmp
, poss
, info
, ALLOW_M
| ALLOW_TRAPS
);
297 for (i
= 0; i
< cnt
; i
++) {
300 if (info
[i
] & ALLOW_M
) {
301 mtmp2
= m_at(nx
, ny
);
302 if (mtmp2
->data
->mlevel
>= mdat
->mlevel
+ 2 ||
303 mtmp2
->data
->mlet
== 'c')
305 if (after
) /* hit only once each move */
308 if (hitmm(mtmp
, mtmp2
) == 1 && rn2(4) &&
309 mtmp2
->mlstmv
!= moves
&&
310 hitmm(mtmp2
, mtmp
) == 2)
315 /* dog avoids traps */
316 /* but perhaps we have to pass a trap in order to follow @ */
317 if ((info
[i
] & ALLOW_TRAPS
) && (trap
= t_at(nx
, ny
))) {
318 if (!trap
->tseen
&& rn2(40))
324 /* dog eschewes cursed objects */
325 /* but likes dog food */
328 if (obj
->ox
!= nx
|| obj
->oy
!= ny
)
332 if (obj
->olet
== FOOD_SYM
&&
333 (otyp
= dogfood(obj
)) < MANFOOD
&&
334 (otyp
< ACCFOOD
|| edog
->hungrytime
<= moves
)) {
336 * Note: our dog likes the food so much that
337 * he might eat it even when it conceals a
346 objects
[obj
->otyp
].oc_delay
;
347 if (edog
->hungrytime
< moves
)
348 edog
->hungrytime
= moves
;
351 objects
[obj
->otyp
].nutrition
;
353 if (cansee(nix
, niy
))
354 pline("%s ate %s.", Monnam(
356 /* perhaps this was a reward */
358 edog
->apport
+= 200 /
360 moves
- edog
->droptime
);
368 for (j
= 0; j
< MTSZ
&& j
< cnt
- 1; j
++)
369 if (nx
== mtmp
->mtrack
[j
].x
&& ny
== mtmp
->mtrack
[j
].y
)
370 if (rn2(4 * (cnt
- j
)))
373 /* Some stupid C compilers cannot compute the whole expression at once. */
374 nearer
= GDIST(nx
, ny
);
375 nearer
-= GDIST(nix
, niy
);
377 if ((nearer
== 0 && !rn2(++chcnt
)) || nearer
< 0 ||
378 (nearer
> 0 && !whappr
&&
379 ((omx
== nix
&& omy
== niy
&& !rn2(3))
391 if (nix
!= omx
|| niy
!= omy
) {
392 if (info
[chi
] & ALLOW_U
) {
393 hitu(mtmp
, d(mdat
->damn
, mdat
->damd
) + 1);
398 for (j
= MTSZ
- 1; j
> 0; j
--)
399 mtmp
->mtrack
[j
] = mtmp
->mtrack
[j
- 1];
400 mtmp
->mtrack
[0].x
= omx
;
401 mtmp
->mtrack
[0].y
= omy
;
403 if (mintrap(mtmp
) == 2) /* he died */
409 /* return roomnumber or -1 */
411 inroom(xchar x
, xchar y
)
414 struct mkroom
*croom
= &rooms
[0];
416 while (croom
->hx
>= 0) {
417 if (croom
->hx
>= x
- 1 && croom
->lx
<= x
+ 1 &&
418 croom
->hy
>= y
- 1 && croom
->ly
<= y
+ 1)
419 return (croom
- rooms
);
423 return (-1); /* not in room or on door */
427 tamedog(struct monst
*mtmp
, struct obj
*obj
)
431 if (flags
.moonphase
== FULL_MOON
&& night() && rn2(6))
434 /* If we cannot tame him, at least he's no longer afraid. */
437 if (mtmp
->mtame
|| mtmp
->mfroz
||
441 mtmp
->isshk
|| mtmp
->isgd
|| strchr(" &@12", mtmp
->data
->mlet
))
442 return (0); /* no tame long worms? */
444 if (dogfood(obj
) >= MANFOOD
)
446 if (cansee(mtmp
->mx
, mtmp
->my
))
447 pline("%s devours the %s.", Monnam(mtmp
),
448 objects
[obj
->otyp
].oc_name
);
451 mtmp2
= newmonst(sizeof(struct edog
) + mtmp
->mnamelth
);
453 mtmp2
->mxlth
= sizeof(struct edog
);
455 strcpy(NAME(mtmp2
), NAME(mtmp
));
457 replmon(mtmp
, mtmp2
);