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 $ */
4 /* $DragonFly: src/games/hack/hack.dog.c,v 1.4 2006/08/21 19:45:32 pavalos Exp $ */
7 #include "hack.mfndpos.h"
10 struct permonst li_dog =
11 { "little dog", 'd', 2, 18, 6, 1, 6, sizeof(struct edog) };
13 { "dog", 'd', 4, 16, 5, 1, 6, sizeof(struct edog) };
14 struct permonst la_dog =
15 { "large dog", 'd', 6, 15, 4, 2, 4, sizeof(struct edog) };
17 static void initedog(struct monst *);
18 static xchar dogfood(struct obj *);
23 struct monst *mtmp = makemon(&li_dog, u.ux, u.uy);
26 return; /* dogs were genocided */
31 initedog(struct monst *mtmp)
33 mtmp->mtame = mtmp->mpeaceful = 1;
34 EDOG(mtmp)->hungrytime = 1000 + moves;
35 EDOG(mtmp)->eattime = 0;
36 EDOG(mtmp)->droptime = 0;
37 EDOG(mtmp)->dropdist = 10000;
38 EDOG(mtmp)->apport = 10;
39 EDOG(mtmp)->whistletime = 0;
42 /* attach the monsters that went down (or up) together with @ */
43 struct monst *mydogs = 0;
44 struct monst *fallen_down = 0; /* monsters that fell through a trapdoor */
45 /* they will appear on the next level @ goes to, even if he goes up! */
52 while ((mtmp = mydogs)) {
58 while ((mtmp = fallen_down)) {
59 fallen_down = mtmp->nmon;
71 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
72 if (dist(mtmp->mx, mtmp->my) < 3 && follower(mtmp)
73 && !mtmp->msleep && !mtmp->mfroz) {
78 keepdogs(); /* we destroyed the link, so use recursion */
79 return; /* (admittedly somewhat primitive) */
84 fall_down(struct monst *mtmp)
87 mtmp->nmon = fallen_down;
93 /* return quality of food; the lower the better */
103 dogfood(struct obj *obj)
108 (obj->otyp == TRIPE_RATION) ? DOGFOOD :
109 (obj->otyp < CARROT) ? ACCFOOD :
110 (obj->otyp < CORPSE) ? MANFOOD :
111 (poisonous(obj) || obj->age + 50 <= moves ||
112 obj->otyp == DEAD_COCKATRICE)
118 /* fall into next case */
126 /* return 0 (no move), 1 (move) or 2 (dead) */
128 dog_move(struct monst *mtmp, int after)
130 int nx, ny, omx, omy, appr, nearer, j;
131 int udist, chi = 0, i, whappr;
133 struct permonst *mdat = mtmp->data;
134 struct edog *edog = EDOG(mtmp);
137 xchar cnt, chcnt, nix, niy;
138 schar dogroom, uroom;
139 xchar gx, gy, gtyp, otyp; /* current goal */
142 #define GDIST(x, y) ((x - gx) * (x - gx) + (y - gy) * (y - gy))
143 #define DDIST(x, y) ((x - omx) * (x - omx) + (y - omy) * (y - omy))
145 if (moves <= edog->eattime) /* dog is still eating */
149 whappr = (moves - EDOG(mtmp)->whistletime < 5);
150 if (moves > edog->hungrytime + 500 && !mtmp->mconf) {
153 if (mtmp->mhp > mtmp->mhpmax)
154 mtmp->mhp = mtmp->mhpmax;
155 if (cansee(omx, omy))
156 pline("%s is confused from hunger.", Monnam(mtmp));
158 pline("You feel worried about %s.", monnam(mtmp));
159 } else if (moves > edog->hungrytime + 750 || mtmp->mhp < 1) {
160 if (cansee(omx, omy))
161 pline("%s dies from hunger.", Monnam(mtmp));
163 pline("You have a sad feeling for a moment, then it passes.");
167 dogroom = inroom(omx, omy);
168 uroom = inroom(u.ux, u.uy);
169 udist = dist(omx, omy);
171 /* maybe we tamed him while being swallowed --jgm */
175 /* if we are carrying sth then we drop it (perhaps near @) */
176 /* Note: if apport == 1 then our behaviour is independent of udist */
178 if (!rn2(udist) || !rn2((int)edog->apport))
179 if (rn2(10) < (int)edog->apport) {
180 relobj(mtmp, (int)mtmp->minvis);
181 if (edog->apport > 1)
183 edog->dropdist = udist; /* hpscdi!jon */
184 edog->droptime = moves;
186 } else if ((obj = o_at(omx, omy))) {
187 if (!strchr("0_", obj->olet)) {
188 if ((otyp = dogfood(obj)) <= CADAVER) {
193 if (obj->owt < 10 * mtmp->data->mlevel) {
194 if (rn2(20) < (int)edog->apport + 3) {
196 !rn2((int)edog->apport)) {
199 /* if (levl[omx][omy].scrsym == obj->olet)
200 * newsym(omx, omy); */
208 /* first we look for food */
209 gtyp = UNDEF; /* no goal as yet */
210 gx = gy = 0; /* suppress 'used before set' message */
211 for (obj = fobj; obj; obj = obj->nobj) {
213 if (otyp > gtyp || otyp == UNDEF)
215 if (inroom(obj->ox, obj->oy) != dogroom)
217 if (otyp < MANFOOD &&
218 (dogroom >= 0 || DDIST(obj->ox, obj->oy) < 10)) {
219 if (otyp < gtyp || (otyp == gtyp &&
220 DDIST(obj->ox, obj->oy) < DDIST(gx, gy))) {
225 } else if (gtyp == UNDEF && dogroom >= 0 &&
227 !mtmp->minvent && (int)edog->apport > rn2(8)) {
234 (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)) {
235 if (dogroom < 0 || dogroom == uroom) {
240 int tmp = rooms[dogroom].fdoor;
241 cnt = rooms[dogroom].doorct;
243 gx = gy = FAR; /* random, far away */
246 dist(doors[tmp].x, doors[tmp].y)) {
252 /* here gx == FAR e.g. when dog is in a vault */
253 if (gx == FAR || (gx == omx && gy == omy)) {
259 appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
260 if (after && udist <= 4 && gx == u.ux && gy == u.uy)
263 if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||
265 (mtmp->minvent && rn2((int)edog->apport)))
268 /* if you have dog food he'll follow you more closely */
272 if (obj->otyp == TRIPE_RATION) {
279 } else /* gtyp != UNDEF */
284 if (gx == u.ux && gy == u.uy && (dogroom != uroom || dogroom < 0)) {
286 cp = gettrack(omx, omy);
295 cnt = mfndpos(mtmp, poss, info, ALLOW_M | ALLOW_TRAPS);
298 for (i = 0; i < cnt; i++) {
301 if (info[i] & ALLOW_M) {
302 mtmp2 = m_at(nx, ny);
303 if (mtmp2->data->mlevel >= mdat->mlevel + 2 ||
304 mtmp2->data->mlet == 'c')
306 if (after) /* hit only once each move */
309 if (hitmm(mtmp, mtmp2) == 1 && rn2(4) &&
310 mtmp2->mlstmv != moves &&
311 hitmm(mtmp2, mtmp) == 2)
316 /* dog avoids traps */
317 /* but perhaps we have to pass a trap in order to follow @ */
318 if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx, ny))) {
319 if (!trap->tseen && rn2(40))
325 /* dog eschewes cursed objects */
326 /* but likes dog food */
329 if (obj->ox != nx || obj->oy != ny)
333 if (obj->olet == FOOD_SYM &&
334 (otyp = dogfood(obj)) < MANFOOD &&
335 (otyp < ACCFOOD || edog->hungrytime <= moves)) {
337 * Note: our dog likes the food so much that
338 * he might eat it even when it conceals a
347 objects[obj->otyp].oc_delay;
348 if (edog->hungrytime < moves)
349 edog->hungrytime = moves;
352 objects[obj->otyp].nutrition;
354 if (cansee(nix, niy))
355 pline("%s ate %s.", Monnam(
357 /* perhaps this was a reward */
359 edog->apport += 200 /
361 moves - edog->droptime);
369 for (j = 0; j < MTSZ && j < cnt - 1; j++)
370 if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
371 if (rn2(4 * (cnt - j)))
374 /* Some stupid C compilers cannot compute the whole expression at once. */
375 nearer = GDIST(nx, ny);
376 nearer -= GDIST(nix, niy);
378 if ((nearer == 0 && !rn2(++chcnt)) || nearer < 0 ||
379 (nearer > 0 && !whappr &&
380 ((omx == nix && omy == niy && !rn2(3))
392 if (nix != omx || niy != omy) {
393 if (info[chi] & ALLOW_U) {
394 hitu(mtmp, d(mdat->damn, mdat->damd) + 1);
399 for (j = MTSZ - 1; j > 0; j--)
400 mtmp->mtrack[j] = mtmp->mtrack[j - 1];
401 mtmp->mtrack[0].x = omx;
402 mtmp->mtrack[0].y = omy;
404 if (mintrap(mtmp) == 2) /* he died */
410 /* return roomnumber or -1 */
412 inroom(xchar x, xchar y)
415 struct mkroom *croom = &rooms[0];
417 while (croom->hx >= 0) {
418 if (croom->hx >= x - 1 && croom->lx <= x + 1 &&
419 croom->hy >= y - 1 && croom->ly <= y + 1)
420 return (croom - rooms);
424 return (-1); /* not in room or on door */
428 tamedog(struct monst *mtmp, struct obj *obj)
432 if (flags.moonphase == FULL_MOON && night() && rn2(6))
435 /* If we cannot tame him, at least he's no longer afraid. */
438 if (mtmp->mtame || mtmp->mfroz ||
442 mtmp->isshk || mtmp->isgd || strchr(" &@12", mtmp->data->mlet))
443 return (0); /* no tame long worms? */
445 if (dogfood(obj) >= MANFOOD)
447 if (cansee(mtmp->mx, mtmp->my))
448 pline("%s devours the %s.", Monnam(mtmp),
449 objects[obj->otyp].oc_name);
452 mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth);
454 mtmp2->mxlth = sizeof(struct edog);
456 strcpy(NAME(mtmp2), NAME(mtmp));
458 replmon(mtmp, mtmp2);