1 /* $NetBSD: hack.dog.c,v 1.10 2009/06/07 18:30:39 dholland Exp $ */
4 * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * - Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * - Neither the name of the Stichting Centrum voor Wiskunde en
20 * Informatica, nor the names of its contributors may be used to endorse or
21 * promote products derived from this software without specific prior
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39 * All rights reserved.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. The name of the author may not be used to endorse or promote products
50 * derived from this software without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
55 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 #include <sys/cdefs.h>
66 __RCSID("$NetBSD: hack.dog.c,v 1.10 2009/06/07 18:30:39 dholland Exp $");
71 #include "hack.mfndpos.h"
73 #include "def.mkroom.h"
75 const struct permonst li_dog
=
76 {"little dog", 'd', 2, 18, 6, 1, 6, sizeof(struct edog
)};
77 const struct permonst dog
=
78 {"dog", 'd', 4, 16, 5, 1, 6, sizeof(struct edog
)};
79 const struct permonst la_dog
=
80 {"large dog", 'd', 6, 15, 4, 2, 4, sizeof(struct edog
)};
82 static void initedog(struct monst
*);
83 static int dogfood(struct obj
*);
88 struct monst
*mtmp
= makemon(&li_dog
, u
.ux
, u
.uy
);
90 return; /* dogs were genocided */
95 initedog(struct monst
*mtmp
)
97 mtmp
->mtame
= mtmp
->mpeaceful
= 1;
98 EDOG(mtmp
)->hungrytime
= 1000 + moves
;
99 EDOG(mtmp
)->eattime
= 0;
100 EDOG(mtmp
)->droptime
= 0;
101 EDOG(mtmp
)->dropdist
= 10000;
102 EDOG(mtmp
)->apport
= 10;
103 EDOG(mtmp
)->whistletime
= 0;
106 /* attach the monsters that went down (or up) together with @ */
107 struct monst
*mydogs
= 0;
108 struct monst
*fallen_down
= 0;/* monsters that fell through a trapdoor */
109 /* they will appear on the next level @ goes to, even if he goes up! */
115 while ((mtmp
= mydogs
) != NULL
) {
121 while ((mtmp
= fallen_down
) != NULL
) {
122 fallen_down
= mtmp
->nmon
;
133 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
)
134 if (dist(mtmp
->mx
, mtmp
->my
) < 3 && follower(mtmp
)
135 && !mtmp
->msleep
&& !mtmp
->mfroz
) {
140 keepdogs(); /* we destroyed the link, so use
142 return; /* (admittedly somewhat primitive) */
147 fall_down(struct monst
*mtmp
)
150 mtmp
->nmon
= fallen_down
;
156 /* return quality of food; the lower the better */
165 dogfood(struct obj
*obj
)
170 (obj
->otyp
== TRIPE_RATION
) ? DOGFOOD
:
171 (obj
->otyp
< CARROT
) ? ACCFOOD
:
172 (obj
->otyp
< CORPSE
) ? MANFOOD
:
173 (poisonous(obj
) || obj
->age
+ 50 <= moves
||
174 obj
->otyp
== DEAD_COCKATRICE
)
180 /* fall into next case */
188 /* return 0 (no move), 1 (move) or 2 (dead) */
190 dog_move(struct monst
*mtmp
, int after
)
192 int nx
, ny
, omx
, omy
, appr
, nearer
, j
;
193 int udist
, chi
= 0, i
, whappr
;
195 const struct permonst
*mdat
= mtmp
->data
;
196 struct edog
*edog
= EDOG(mtmp
);
199 xchar cnt
, chcnt
, nix
, niy
;
200 schar dogroom
, uroom
;
201 xchar gx
= 0, gy
= 0, gtyp
, otyp
; /* current goal */
204 #define GDIST(x,y) ((x-gx)*(x-gx) + (y-gy)*(y-gy))
205 #define DDIST(x,y) ((x-omx)*(x-omx) + (y-omy)*(y-omy))
207 if (moves
<= edog
->eattime
)
208 return (0); /* dog is still eating */
211 whappr
= (moves
- EDOG(mtmp
)->whistletime
< 5);
212 if (moves
> edog
->hungrytime
+ 500 && !mtmp
->mconf
) {
215 if (mtmp
->mhp
> mtmp
->mhpmax
)
216 mtmp
->mhp
= mtmp
->mhpmax
;
217 if (cansee(omx
, omy
))
218 pline("%s is confused from hunger.", Monnam(mtmp
));
220 pline("You feel worried about %s.", monnam(mtmp
));
221 } else if (moves
> edog
->hungrytime
+ 750 || mtmp
->mhp
< 1) {
222 if (cansee(omx
, omy
))
223 pline("%s dies from hunger.", Monnam(mtmp
));
225 pline("You have a sad feeling for a moment, then it passes.");
229 dogroom
= inroom(omx
, omy
);
230 uroom
= inroom(u
.ux
, u
.uy
);
231 udist
= dist(omx
, omy
);
233 /* maybe we tamed him while being swallowed --jgm */
237 /* if we are carrying sth then we drop it (perhaps near @) */
238 /* Note: if apport == 1 then our behaviour is independent of udist */
240 if (!rn2(udist
) || !rn2((int) edog
->apport
))
241 if ((unsigned) rn2(10) < edog
->apport
) {
242 relobj(mtmp
, (int) mtmp
->minvis
);
243 if (edog
->apport
> 1)
245 edog
->dropdist
= udist
; /* hpscdi!jon */
246 edog
->droptime
= moves
;
249 if ((obj
= o_at(omx
, omy
)) != NULL
)
250 if (!strchr("0_", obj
->olet
)) {
251 if ((otyp
= dogfood(obj
)) <= CADAVER
) {
256 if (obj
->owt
< 10 * mtmp
->data
->mlevel
)
257 if ((unsigned) rn2(20) < edog
->apport
+ 3)
258 if (rn2(udist
) || !rn2((int) edog
->apport
)) {
262 * if(levl[omx][omy].s
272 /* first we look for food */
273 gtyp
= UNDEF
; /* no goal as yet */
275 gx
= gy
= 0; /* suppress 'used before set' message */
277 for (obj
= fobj
; obj
; obj
= obj
->nobj
) {
279 if (otyp
> gtyp
|| otyp
== UNDEF
)
281 if (inroom(obj
->ox
, obj
->oy
) != dogroom
)
283 if (otyp
< MANFOOD
&&
284 (dogroom
>= 0 || DDIST(obj
->ox
, obj
->oy
) < 10)) {
285 if (otyp
< gtyp
|| (otyp
== gtyp
&&
286 DDIST(obj
->ox
, obj
->oy
) < DDIST(gx
, gy
))) {
291 } else if (gtyp
== UNDEF
&& dogroom
>= 0 &&
293 !mtmp
->minvent
&& edog
->apport
> (unsigned)rn2(8)) {
300 (gtyp
!= DOGFOOD
&& gtyp
!= APPORT
&& moves
< edog
->hungrytime
)) {
301 if (dogroom
< 0 || dogroom
== uroom
) {
306 int tmp
= rooms
[dogroom
].fdoor
;
307 cnt
= rooms
[dogroom
].doorct
;
309 gx
= gy
= FAR
; /* random, far away */
312 dist(doors
[tmp
].x
, doors
[tmp
].y
)) {
318 /* here gx == FAR e.g. when dog is in a vault */
319 if (gx
== FAR
|| (gx
== omx
&& gy
== omy
)) {
325 appr
= (udist
>= 9) ? 1 : (mtmp
->mflee
) ? -1 : 0;
326 if (after
&& udist
<= 4 && gx
== u
.ux
&& gy
== u
.uy
)
329 if (!IS_ROOM(levl
[u
.ux
][u
.uy
].typ
) || !rn2(4) ||
331 (mtmp
->minvent
&& rn2((int) edog
->apport
)))
334 /* if you have dog food he'll follow you more closely */
338 if (obj
->otyp
== TRIPE_RATION
) {
346 appr
= 1; /* gtyp != UNDEF */
350 if (gx
== u
.ux
&& gy
== u
.uy
&& (dogroom
!= uroom
|| dogroom
< 0)) {
352 cp
= gettrack(omx
, omy
);
360 cnt
= mfndpos(mtmp
, poss
, info
, ALLOW_M
| ALLOW_TRAPS
);
363 for (i
= 0; i
< cnt
; i
++) {
366 if (info
[i
] & ALLOW_M
) {
367 mtmp2
= m_at(nx
, ny
);
369 panic("error in dog_move");
370 if (mtmp2
->data
->mlevel
>= mdat
->mlevel
+ 2 ||
371 mtmp2
->data
->mlet
== 'c')
374 return (0); /* hit only once each move */
376 if (hitmm(mtmp
, mtmp2
) == 1 && rn2(4) &&
377 mtmp2
->mlstmv
!= moves
&&
378 hitmm(mtmp2
, mtmp
) == 2)
382 /* dog avoids traps */
383 /* but perhaps we have to pass a trap in order to follow @ */
384 if ((info
[i
] & ALLOW_TRAPS
) && (trap
= t_at(nx
, ny
))) {
385 if (!trap
->tseen
&& rn2(40))
390 /* dog eschewes cursed objects */
391 /* but likes dog food */
394 if (obj
->ox
!= nx
|| obj
->oy
!= ny
)
398 if (obj
->olet
== FOOD_SYM
&&
399 (otyp
= dogfood(obj
)) < MANFOOD
&&
400 (otyp
< ACCFOOD
|| edog
->hungrytime
<= moves
)) {
402 * Note: our dog likes the food so much that
403 * he might eat it even when it conceals a
411 moves
+ obj
->quan
* objects
[obj
->otyp
].oc_delay
;
412 if (edog
->hungrytime
< moves
)
413 edog
->hungrytime
= moves
;
415 5 * obj
->quan
* objects
[obj
->otyp
].nutrition
;
417 if (cansee(nix
, niy
))
418 pline("%s ate %s.", Monnam(mtmp
), doname(obj
));
419 /* perhaps this was a reward */
421 edog
->apport
+= 200 / (edog
->dropdist
+ moves
- edog
->droptime
);
429 for (j
= 0; j
< MTSZ
&& j
< cnt
- 1; j
++)
430 if (nx
== mtmp
->mtrack
[j
].x
&& ny
== mtmp
->mtrack
[j
].y
)
431 if (rn2(4 * (cnt
- j
)))
435 * Some stupid C compilers cannot compute the whole
436 * expression at once.
438 nearer
= GDIST(nx
, ny
);
439 nearer
-= GDIST(nix
, niy
);
441 if ((nearer
== 0 && !rn2(++chcnt
)) || nearer
< 0 ||
442 (nearer
> 0 && !whappr
&&
443 ((omx
== nix
&& omy
== niy
&& !rn2(3))
455 if (nix
!= omx
|| niy
!= omy
) {
456 if (info
[chi
] & ALLOW_U
) {
457 (void) hitu(mtmp
, d(mdat
->damn
, mdat
->damd
) + 1);
462 for (j
= MTSZ
- 1; j
> 0; j
--)
463 mtmp
->mtrack
[j
] = mtmp
->mtrack
[j
- 1];
464 mtmp
->mtrack
[0].x
= omx
;
465 mtmp
->mtrack
[0].y
= omy
;
467 if (mintrap(mtmp
) == 2) /* he died */
473 /* return roomnumber or -1 */
475 inroom(xchar x
, xchar y
)
478 struct mkroom
*croom
= &rooms
[0];
479 while (croom
->hx
>= 0) {
480 if (croom
->hx
>= x
- 1 && croom
->lx
<= x
+ 1 &&
481 croom
->hy
>= y
- 1 && croom
->ly
<= y
+ 1)
482 return (croom
- rooms
);
486 return (-1); /* not in room or on door */
490 tamedog(struct monst
*mtmp
, struct obj
*obj
)
494 if (flags
.moonphase
== FULL_MOON
&& night() && rn2(6))
497 /* If we cannot tame him, at least he's no longer afraid. */
500 if (mtmp
->mtame
|| mtmp
->mfroz
||
504 mtmp
->isshk
|| mtmp
->isgd
|| strchr(" &@12", mtmp
->data
->mlet
))
505 return (0); /* no tame long worms? */
507 if (dogfood(obj
) >= MANFOOD
)
509 if (cansee(mtmp
->mx
, mtmp
->my
)) {
510 pline("%s devours the %s.", Monnam(mtmp
),
511 objects
[obj
->otyp
].oc_name
);
513 obfree(obj
, (struct obj
*) 0);
515 mtmp2
= newmonst(sizeof(struct edog
) + mtmp
->mnamelth
);
517 mtmp2
->mxlth
= sizeof(struct edog
);
519 (void) strcpy(NAME(mtmp2
), NAME(mtmp
));
521 replmon(mtmp
, mtmp2
);