inet6: require RTF_ANNOUNCE to proxy NS
[dragonfly.git] / games / hack / hack.dog.c
blobd70be0b35c2ae87b9f4eaf5c172072e189bd3e31
1 /* $NetBSD: hack.dog.c,v 1.12 2011/08/07 06:03:45 dholland Exp $ */
3 /*
4 * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5 * Amsterdam
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
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
22 * written permission.
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
43 * are met:
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 "hack.h"
65 #include "extern.h"
66 #include "hack.mfndpos.h"
67 #include "def.edog.h"
68 #include "def.mkroom.h"
70 const struct permonst li_dog =
71 {"little dog", 'd', 2, 18, 6, 1, 6, sizeof(struct edog)};
72 const struct permonst dog =
73 {"dog", 'd', 4, 16, 5, 1, 6, sizeof(struct edog)};
74 const struct permonst la_dog =
75 {"large dog", 'd', 6, 15, 4, 2, 4, sizeof(struct edog)};
77 static void initedog(struct monst *);
78 static int dogfood(struct obj *);
80 void
81 makedog(void)
83 struct monst *mtmp = makemon(&li_dog, u.ux, u.uy);
84 if (!mtmp)
85 return; /* dogs were genocided */
86 initedog(mtmp);
89 static void
90 initedog(struct monst *mtmp)
92 mtmp->mtame = mtmp->mpeaceful = 1;
93 EDOG(mtmp)->hungrytime = 1000 + moves;
94 EDOG(mtmp)->eattime = 0;
95 EDOG(mtmp)->droptime = 0;
96 EDOG(mtmp)->dropdist = 10000;
97 EDOG(mtmp)->apport = 10;
98 EDOG(mtmp)->whistletime = 0;
101 /* attach the monsters that went down (or up) together with @ */
102 struct monst *mydogs = 0;
103 struct monst *fallen_down = 0;/* monsters that fell through a trapdoor */
104 /* they will appear on the next level @ goes to, even if he goes up! */
106 void
107 losedogs(void)
109 struct monst *mtmp;
110 while ((mtmp = mydogs) != NULL) {
111 mydogs = mtmp->nmon;
112 mtmp->nmon = fmon;
113 fmon = mtmp;
114 mnexto(mtmp);
116 while ((mtmp = fallen_down) != NULL) {
117 fallen_down = mtmp->nmon;
118 mtmp->nmon = fmon;
119 fmon = mtmp;
120 rloc(mtmp);
124 void
125 keepdogs(void)
127 struct monst *mtmp;
128 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
129 if (dist(mtmp->mx, mtmp->my) < 3 && follower(mtmp)
130 && !mtmp->msleep && !mtmp->mfroz) {
131 relmon(mtmp);
132 mtmp->nmon = mydogs;
133 mydogs = mtmp;
134 unpmon(mtmp);
135 keepdogs(); /* we destroyed the link, so use
136 * recursion */
137 return; /* (admittedly somewhat primitive) */
141 void
142 fall_down(struct monst *mtmp)
144 relmon(mtmp);
145 mtmp->nmon = fallen_down;
146 fallen_down = mtmp;
147 unpmon(mtmp);
148 mtmp->mtame = 0;
151 /* return quality of food; the lower the better */
152 #define DOGFOOD 0
153 #define CADAVER 1
154 #define ACCFOOD 2
155 #define MANFOOD 3
156 #define APPORT 4
157 #define POISON 5
158 #define UNDEF 6
159 static int
160 dogfood(struct obj *obj)
162 switch (obj->olet) {
163 case FOOD_SYM:
164 return (
165 (obj->otyp == TRIPE_RATION) ? DOGFOOD :
166 (obj->otyp < CARROT) ? ACCFOOD :
167 (obj->otyp < CORPSE) ? MANFOOD :
168 (poisonous(obj) || obj->age + 50 <= moves ||
169 obj->otyp == DEAD_COCKATRICE)
170 ? POISON : CADAVER
172 default:
173 if (!obj->cursed)
174 return (APPORT);
175 /* FALLTHROUGH */
176 case BALL_SYM:
177 case CHAIN_SYM:
178 case ROCK_SYM:
179 return (UNDEF);
183 /* return 0 (no move), 1 (move) or 2 (dead) */
185 dog_move(struct monst *mtmp, int after)
187 int nx, ny, omx, omy, appr, nearer, j;
188 int udist, chi = 0, i, whappr;
189 struct monst *mtmp2;
190 const struct permonst *mdat = mtmp->data;
191 struct edog *edog = EDOG(mtmp);
192 struct obj *obj;
193 struct trap *trap;
194 xchar cnt, chcnt, nix, niy;
195 schar dogroom, uroom;
196 xchar gx = 0, gy = 0, gtyp, otyp; /* current goal */
197 coord poss[9];
198 int info[9];
199 #define GDIST(x,y) ((x-gx)*(x-gx) + (y-gy)*(y-gy))
200 #define DDIST(x,y) ((x-omx)*(x-omx) + (y-omy)*(y-omy))
202 if (moves <= edog->eattime)
203 return (0); /* dog is still eating */
204 omx = mtmp->mx;
205 omy = mtmp->my;
206 whappr = (moves - EDOG(mtmp)->whistletime < 5);
207 if (moves > edog->hungrytime + 500 && !mtmp->mconf) {
208 mtmp->mconf = 1;
209 mtmp->mhpmax /= 3;
210 if (mtmp->mhp > mtmp->mhpmax)
211 mtmp->mhp = mtmp->mhpmax;
212 if (cansee(omx, omy))
213 pline("%s is confused from hunger.", Monnam(mtmp));
214 else
215 pline("You feel worried about %s.", monnam(mtmp));
216 } else if (moves > edog->hungrytime + 750 || mtmp->mhp < 1) {
217 if (cansee(omx, omy))
218 pline("%s dies from hunger.", Monnam(mtmp));
219 else
220 pline("You have a sad feeling for a moment, then it passes.");
221 mondied(mtmp);
222 return (2);
224 dogroom = inroom(omx, omy);
225 uroom = inroom(u.ux, u.uy);
226 udist = dist(omx, omy);
228 /* maybe we tamed him while being swallowed --jgm */
229 if (!udist)
230 return (0);
232 /* if we are carrying sth then we drop it (perhaps near @) */
233 /* Note: if apport == 1 then our behaviour is independent of udist */
234 if (mtmp->minvent) {
235 if (!rn2(udist) || !rn2((int) edog->apport))
236 if ((unsigned) rn2(10) < edog->apport) {
237 relobj(mtmp, (int) mtmp->minvis);
238 if (edog->apport > 1)
239 edog->apport--;
240 edog->dropdist = udist; /* hpscdi!jon */
241 edog->droptime = moves;
243 } else {
244 if ((obj = o_at(omx, omy)) != NULL)
245 if (!strchr("0_", obj->olet)) {
246 if ((otyp = dogfood(obj)) <= CADAVER) {
247 nix = omx;
248 niy = omy;
249 goto eatobj;
251 if (obj->owt < 10 * mtmp->data->mlevel)
252 if ((unsigned) rn2(20) < edog->apport + 3)
253 if (rn2(udist) || !rn2((int) edog->apport)) {
254 freeobj(obj);
255 unpobj(obj);
257 * if(levl[omx][omy].s
258 * crsym ==
259 * obj->olet)
260 * newsym(omx,omy);
262 mpickobj(mtmp, obj);
267 /* first we look for food */
268 gtyp = UNDEF; /* no goal as yet */
269 #ifdef LINT
270 gx = gy = 0; /* suppress 'used before set' message */
271 #endif /* LINT */
272 for (obj = fobj; obj; obj = obj->nobj) {
273 otyp = dogfood(obj);
274 if (otyp > gtyp || otyp == UNDEF)
275 continue;
276 if (inroom(obj->ox, obj->oy) != dogroom)
277 continue;
278 if (otyp < MANFOOD &&
279 (dogroom >= 0 || DDIST(obj->ox, obj->oy) < 10)) {
280 if (otyp < gtyp || (otyp == gtyp &&
281 DDIST(obj->ox, obj->oy) < DDIST(gx, gy))) {
282 gx = obj->ox;
283 gy = obj->oy;
284 gtyp = otyp;
286 } else if (gtyp == UNDEF && dogroom >= 0 &&
287 uroom == dogroom &&
288 !mtmp->minvent && edog->apport > (unsigned)rn2(8)) {
289 gx = obj->ox;
290 gy = obj->oy;
291 gtyp = APPORT;
294 if (gtyp == UNDEF ||
295 (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)) {
296 if (dogroom < 0 || dogroom == uroom) {
297 gx = u.ux;
298 gy = u.uy;
299 #ifndef QUEST
300 } else {
301 int tmp = rooms[dogroom].fdoor;
302 cnt = rooms[dogroom].doorct;
304 gx = gy = FAR; /* random, far away */
305 while (cnt--) {
306 if (dist(gx, gy) >
307 dist(doors[tmp].x, doors[tmp].y)) {
308 gx = doors[tmp].x;
309 gy = doors[tmp].y;
311 tmp++;
313 /* here gx == FAR e.g. when dog is in a vault */
314 if (gx == FAR || (gx == omx && gy == omy)) {
315 gx = u.ux;
316 gy = u.uy;
318 #endif /* QUEST */
320 appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
321 if (after && udist <= 4 && gx == u.ux && gy == u.uy)
322 return (0);
323 if (udist > 1) {
324 if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||
325 whappr ||
326 (mtmp->minvent && rn2((int) edog->apport)))
327 appr = 1;
329 /* if you have dog food he'll follow you more closely */
330 if (appr == 0) {
331 obj = invent;
332 while (obj) {
333 if (obj->otyp == TRIPE_RATION) {
334 appr = 1;
335 break;
337 obj = obj->nobj;
340 } else
341 appr = 1; /* gtyp != UNDEF */
342 if (mtmp->mconf)
343 appr = 0;
345 if (gx == u.ux && gy == u.uy && (dogroom != uroom || dogroom < 0)) {
346 coord *cp;
347 cp = gettrack(omx, omy);
348 if (cp) {
349 gx = cp->x;
350 gy = cp->y;
353 nix = omx;
354 niy = omy;
355 cnt = mfndpos(mtmp, poss, info, ALLOW_M | ALLOW_TRAPS);
356 chcnt = 0;
357 chi = -1;
358 for (i = 0; i < cnt; i++) {
359 nx = poss[i].x;
360 ny = poss[i].y;
361 if (info[i] & ALLOW_M) {
362 mtmp2 = m_at(nx, ny);
363 if (mtmp2 == NULL)
364 panic("error in dog_move");
365 if (mtmp2->data->mlevel >= mdat->mlevel + 2 ||
366 mtmp2->data->mlet == 'c')
367 continue;
368 if (after)
369 return (0); /* hit only once each move */
371 if (hitmm(mtmp, mtmp2) == 1 && rn2(4) &&
372 mtmp2->mlstmv != moves &&
373 hitmm(mtmp2, mtmp) == 2)
374 return (2);
375 return (0);
377 /* dog avoids traps */
378 /* but perhaps we have to pass a trap in order to follow @ */
379 if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx, ny))) {
380 if (!trap->tseen && rn2(40))
381 continue;
382 if (rn2(10))
383 continue;
385 /* dog eschewes cursed objects */
386 /* but likes dog food */
387 obj = fobj;
388 while (obj) {
389 if (obj->ox != nx || obj->oy != ny)
390 goto nextobj;
391 if (obj->cursed)
392 goto nxti;
393 if (obj->olet == FOOD_SYM &&
394 (otyp = dogfood(obj)) < MANFOOD &&
395 (otyp < ACCFOOD || edog->hungrytime <= moves)) {
397 * Note: our dog likes the food so much that
398 * he might eat it even when it conceals a
399 * cursed object
401 nix = nx;
402 niy = ny;
403 chi = i;
404 eatobj:
405 edog->eattime =
406 moves + obj->quan * objects[obj->otyp].oc_delay;
407 if (edog->hungrytime < moves)
408 edog->hungrytime = moves;
409 edog->hungrytime +=
410 5 * obj->quan * objects[obj->otyp].nutrition;
411 mtmp->mconf = 0;
412 if (cansee(nix, niy))
413 pline("%s ate %s.", Monnam(mtmp), doname(obj));
414 /* perhaps this was a reward */
415 if (otyp != CADAVER)
416 edog->apport += 200 / (edog->dropdist + moves - edog->droptime);
417 delobj(obj);
418 goto newdogpos;
420 nextobj:
421 obj = obj->nobj;
424 for (j = 0; j < MTSZ && j < cnt - 1; j++)
425 if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
426 if (rn2(4 * (cnt - j)))
427 goto nxti;
430 * Some stupid C compilers cannot compute the whole
431 * expression at once.
433 nearer = GDIST(nx, ny);
434 nearer -= GDIST(nix, niy);
435 nearer *= appr;
436 if ((nearer == 0 && !rn2(++chcnt)) || nearer < 0 ||
437 (nearer > 0 && !whappr &&
438 ((omx == nix && omy == niy && !rn2(3))
439 || !rn2(12))
440 )) {
441 nix = nx;
442 niy = ny;
443 if (nearer < 0)
444 chcnt = 0;
445 chi = i;
447 nxti: ;
449 newdogpos:
450 if (nix != omx || niy != omy) {
451 if (info[chi] & ALLOW_U) {
452 (void) hitu(mtmp, d(mdat->damn, mdat->damd) + 1);
453 return (0);
455 mtmp->mx = nix;
456 mtmp->my = niy;
457 for (j = MTSZ - 1; j > 0; j--)
458 mtmp->mtrack[j] = mtmp->mtrack[j - 1];
459 mtmp->mtrack[0].x = omx;
460 mtmp->mtrack[0].y = omy;
462 if (mintrap(mtmp) == 2) /* he died */
463 return (2);
464 pmon(mtmp);
465 return (1);
468 /* return roomnumber or -1 */
470 inroom(xchar x, xchar y)
472 #ifndef QUEST
473 int pos = 0;
475 while (rooms[pos].hx >= 0) {
476 if (rooms[pos].hx >= x - 1 && rooms[pos].lx <= x + 1 &&
477 rooms[pos].hy >= y - 1 && rooms[pos].ly <= y + 1)
478 return pos;
479 pos++;
481 #endif /* QUEST */
482 return (-1); /* not in room or on door */
486 tamedog(struct monst *mtmp, struct obj *obj)
488 struct monst *mtmp2;
490 if (flags.moonphase == FULL_MOON && night() && rn2(6))
491 return (0);
493 /* If we cannot tame him, at least he's no longer afraid. */
494 mtmp->mflee = 0;
495 mtmp->mfleetim = 0;
496 if (mtmp->mtame || mtmp->mfroz ||
497 #ifndef NOWORM
498 mtmp->wormno ||
499 #endif /* NOWORM */
500 mtmp->isshk || mtmp->isgd || strchr(" &@12", mtmp->data->mlet))
501 return (0); /* no tame long worms? */
502 if (obj) {
503 if (dogfood(obj) >= MANFOOD)
504 return (0);
505 if (cansee(mtmp->mx, mtmp->my)) {
506 pline("%s devours the %s.", Monnam(mtmp),
507 objects[obj->otyp].oc_name);
509 obfree(obj, (struct obj *) 0);
511 mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth);
512 *mtmp2 = *mtmp;
513 mtmp2->mxlth = sizeof(struct edog);
514 if (mtmp->mnamelth)
515 (void) strcpy(NAME(mtmp2), NAME(mtmp));
516 initedog(mtmp2);
517 replmon(mtmp, mtmp2);
518 return (1);