1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64: #include <sys/cdefs.h>
65: #ifndef lint
66: __RCSID("$NetBSD: hack.dog.c,v 1.6 2003/04/02 18:36:36 jsm Exp $");
67: #endif
68:
69: #include "hack.h"
70: #include "extern.h"
71: #include "hack.mfndpos.h"
72: #include "def.edog.h"
73: #include "def.mkroom.h"
74:
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)};
81:
82:
83: void
84: makedog()
85: {
86: struct monst *mtmp = makemon(&li_dog, u.ux, u.uy);
87: if (!mtmp)
88: return;
89: initedog(mtmp);
90: }
91:
92: void
93: initedog(mtmp)
94: struct monst *mtmp;
95: {
96: mtmp->mtame = mtmp->mpeaceful = 1;
97: EDOG(mtmp)->hungrytime = 1000 + moves;
98: EDOG(mtmp)->eattime = 0;
99: EDOG(mtmp)->droptime = 0;
100: EDOG(mtmp)->dropdist = 10000;
101: EDOG(mtmp)->apport = 10;
102: EDOG(mtmp)->whistletime = 0;
103: }
104:
105:
106: struct monst *mydogs = 0;
107: struct monst *fallen_down = 0;
108:
109:
110: void
111: losedogs()
112: {
113: struct monst *mtmp;
114: while ((mtmp = mydogs) != NULL) {
115: mydogs = mtmp->nmon;
116: mtmp->nmon = fmon;
117: fmon = mtmp;
118: mnexto(mtmp);
119: }
120: while ((mtmp = fallen_down) != NULL) {
121: fallen_down = mtmp->nmon;
122: mtmp->nmon = fmon;
123: fmon = mtmp;
124: rloc(mtmp);
125: }
126: }
127:
128: void
129: keepdogs()
130: {
131: struct monst *mtmp;
132: for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
133: if (dist(mtmp->mx, mtmp->my) < 3 && follower(mtmp)
134: && !mtmp->msleep && !mtmp->mfroz) {
135: relmon(mtmp);
136: mtmp->nmon = mydogs;
137: mydogs = mtmp;
138: unpmon(mtmp);
139: keepdogs();
140:
141: return;
142: }
143: }
144:
145: void
146: fall_down(mtmp)
147: struct monst *mtmp;
148: {
149: relmon(mtmp);
150: mtmp->nmon = fallen_down;
151: fallen_down = mtmp;
152: unpmon(mtmp);
153: mtmp->mtame = 0;
154: }
155:
156:
157: #define DOGFOOD 0
158: #define CADAVER 1
159: #define ACCFOOD 2
160: #define MANFOOD 3
161: #define APPORT 4
162: #define POISON 5
163: #define UNDEF 6
164: int
165: dogfood(obj)
166: struct obj *obj;
167: {
168: switch (obj->olet) {
169: case FOOD_SYM:
170: return (
171: (obj->otyp == TRIPE_RATION) ? DOGFOOD :
172: (obj->otyp < CARROT) ? ACCFOOD :
173: (obj->otyp < CORPSE) ? MANFOOD :
174: (poisonous(obj) || obj->age + 50 <= moves ||
175: obj->otyp == DEAD_COCKATRICE)
176: ? POISON : CADAVER
177: );
178: default:
179: if (!obj->cursed)
180: return (APPORT);
181:
182: case BALL_SYM:
183: case CHAIN_SYM:
184: case ROCK_SYM:
185: return (UNDEF);
186: }
187: }
188:
189:
190: int
191: dog_move(struct monst *mtmp, int after)
192: {
193: int nx, ny, omx, omy, appr, nearer, j;
194: int udist, chi = 0, i, whappr;
195: struct monst *mtmp2;
196: const struct permonst *mdat = mtmp->data;
197: struct edog *edog = EDOG(mtmp);
198: struct obj *obj;
199: struct trap *trap;
200: xchar cnt, chcnt, nix, niy;
201: schar dogroom, uroom;
202: xchar gx = 0, gy = 0, gtyp, otyp;
203: coord poss[9];
204: int info[9];
205: #define GDIST(x,y) ((x-gx)*(x-gx) + (y-gy)*(y-gy))
206: #define DDIST(x,y) ((x-omx)*(x-omx) + (y-omy)*(y-omy))
207:
208: if (moves <= edog->eattime)
209: return (0);
210: omx = mtmp->mx;
211: omy = mtmp->my;
212: whappr = (moves - EDOG(mtmp)->whistletime < 5);
213: if (moves > edog->hungrytime + 500 && !mtmp->mconf) {
214: mtmp->mconf = 1;
215: mtmp->mhpmax /= 3;
216: if (mtmp->mhp > mtmp->mhpmax)
217: mtmp->mhp = mtmp->mhpmax;
218: if (cansee(omx, omy))
219: pline("%s is confused from hunger.", Monnam(mtmp));
220: else
221: pline("You feel worried about %s.", monnam(mtmp));
222: } else if (moves > edog->hungrytime + 750 || mtmp->mhp < 1) {
223: if (cansee(omx, omy))
224: pline("%s dies from hunger.", Monnam(mtmp));
225: else
226: pline("You have a sad feeling for a moment, then it passes.");
227: mondied(mtmp);
228: return (2);
229: }
230: dogroom = inroom(omx, omy);
231: uroom = inroom(u.ux, u.uy);
232: udist = dist(omx, omy);
233:
234:
235: if (!udist)
236: return (0);
237:
238:
239:
240: if (mtmp->minvent) {
241: if (!rn2(udist) || !rn2((int) edog->apport))
242: if ((unsigned)rn2(10) < edog->apport) {
243: relobj(mtmp, (int) mtmp->minvis);
244: if (edog->apport > 1)
245: edog->apport--;
246: edog->dropdist = udist;
247: edog->droptime = moves;
248: }
249: } else {
250: if ((obj = o_at(omx, omy)) != NULL)
251: if (!strchr("0_", obj->olet)) {
252: if ((otyp = dogfood(obj)) <= CADAVER) {
253: nix = omx;
254: niy = omy;
255: goto eatobj;
256: }
257: if (obj->owt < 10 * mtmp->data->mlevel)
258: if ((unsigned)rn2(20) < edog->apport + 3)
259: if (rn2(udist) || !rn2((int) edog->apport)) {
260: freeobj(obj);
261: unpobj(obj);
262:
263:
264:
265:
266:
267:
268: mpickobj(mtmp, obj);
269: }
270: }
271: }
272:
273:
274: gtyp = UNDEF;
275: #ifdef LINT
276: gx = gy = 0;
277: #endif
278: for (obj = fobj; obj; obj = obj->nobj) {
279: otyp = dogfood(obj);
280: if (otyp > gtyp || otyp == UNDEF)
281: continue;
282: if (inroom(obj->ox, obj->oy) != dogroom)
283: continue;
284: if (otyp < MANFOOD &&
285: (dogroom >= 0 || DDIST(obj->ox, obj->oy) < 10)) {
286: if (otyp < gtyp || (otyp == gtyp &&
287: DDIST(obj->ox, obj->oy) < DDIST(gx, gy))) {
288: gx = obj->ox;
289: gy = obj->oy;
290: gtyp = otyp;
291: }
292: } else if (gtyp == UNDEF && dogroom >= 0 &&
293: uroom == dogroom &&
294: !mtmp->minvent && edog->apport > (unsigned)rn2(8)) {
295: gx = obj->ox;
296: gy = obj->oy;
297: gtyp = APPORT;
298: }
299: }
300: if (gtyp == UNDEF ||
301: (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)) {
302: if (dogroom < 0 || dogroom == uroom) {
303: gx = u.ux;
304: gy = u.uy;
305: #ifndef QUEST
306: } else {
307: int tmp = rooms[dogroom].fdoor;
308: cnt = rooms[dogroom].doorct;
309:
310: gx = gy = FAR;
311: while (cnt--) {
312: if (dist(gx, gy) >
313: dist(doors[tmp].x, doors[tmp].y)) {
314: gx = doors[tmp].x;
315: gy = doors[tmp].y;
316: }
317: tmp++;
318: }
319:
320: if (gx == FAR || (gx == omx && gy == omy)) {
321: gx = u.ux;
322: gy = u.uy;
323: }
324: #endif
325: }
326: appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
327: if (after && udist <= 4 && gx == u.ux && gy == u.uy)
328: return (0);
329: if (udist > 1) {
330: if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||
331: whappr ||
332: (mtmp->minvent && rn2((int) edog->apport)))
333: appr = 1;
334: }
335:
336: if (appr == 0) {
337: obj = invent;
338: while (obj) {
339: if (obj->otyp == TRIPE_RATION) {
340: appr = 1;
341: break;
342: }
343: obj = obj->nobj;
344: }
345: }
346: } else
347: appr = 1;
348: if (mtmp->mconf)
349: appr = 0;
350:
351: if (gx == u.ux && gy == u.uy && (dogroom != uroom || dogroom < 0)) {
352: coord *cp;
353: cp = gettrack(omx, omy);
354: if (cp) {
355: gx = cp->x;
356: gy = cp->y;
357: }
358: }
359: nix = omx;
360: niy = omy;
361: cnt = mfndpos(mtmp, poss, info, ALLOW_M | ALLOW_TRAPS);
362: chcnt = 0;
363: chi = -1;
364: for (i = 0; i < cnt; i++) {
365: nx = poss[i].x;
366: ny = poss[i].y;
367: if (info[i] & ALLOW_M) {
368: mtmp2 = m_at(nx, ny);
369: if (mtmp2->data->mlevel >= mdat->mlevel + 2 ||
370: mtmp2->data->mlet == 'c')
371: continue;
372: if (after)
373: return (0);
374:
375: if (hitmm(mtmp, mtmp2) == 1 && rn2(4) &&
376: mtmp2->mlstmv != moves &&
377: hitmm(mtmp2, mtmp) == 2)
378: return (2);
379: return (0);
380: }
381:
382:
383: if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx, ny))) {
384: if (!trap->tseen && rn2(40))
385: continue;
386: if (rn2(10))
387: continue;
388: }
389:
390:
391: obj = fobj;
392: while (obj) {
393: if (obj->ox != nx || obj->oy != ny)
394: goto nextobj;
395: if (obj->cursed)
396: goto nxti;
397: if (obj->olet == FOOD_SYM &&
398: (otyp = dogfood(obj)) < MANFOOD &&
399: (otyp < ACCFOOD || edog->hungrytime <= moves)) {
400:
401:
402:
403:
404:
405: nix = nx;
406: niy = ny;
407: chi = i;
408: eatobj:
409: edog->eattime =
410: moves + obj->quan * objects[obj->otyp].oc_delay;
411: if (edog->hungrytime < moves)
412: edog->hungrytime = moves;
413: edog->hungrytime +=
414: 5 * obj->quan * objects[obj->otyp].nutrition;
415: mtmp->mconf = 0;
416: if (cansee(nix, niy))
417: pline("%s ate %s.", Monnam(mtmp), doname(obj));
418:
419: if (otyp != CADAVER)
420: edog->apport += 200 / (edog->dropdist + moves - edog->droptime);
421: delobj(obj);
422: goto newdogpos;
423: }
424: nextobj:
425: obj = obj->nobj;
426: }
427:
428: for (j = 0; j < MTSZ && j < cnt - 1; j++)
429: if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
430: if (rn2(4 * (cnt - j)))
431: goto nxti;
432:
433:
434:
435:
436:
437: nearer = GDIST(nx, ny);
438: nearer -= GDIST(nix, niy);
439: nearer *= appr;
440: if ((nearer == 0 && !rn2(++chcnt)) || nearer < 0 ||
441: (nearer > 0 && !whappr &&
442: ((omx == nix && omy == niy && !rn2(3))
443: || !rn2(12))
444: )) {
445: nix = nx;
446: niy = ny;
447: if (nearer < 0)
448: chcnt = 0;
449: chi = i;
450: }
451: nxti: ;
452: }
453: newdogpos:
454: if (nix != omx || niy != omy) {
455: if (info[chi] & ALLOW_U) {
456: (void) hitu(mtmp, d(mdat->damn, mdat->damd) + 1);
457: return (0);
458: }
459: mtmp->mx = nix;
460: mtmp->my = niy;
461: for (j = MTSZ - 1; j > 0; j--)
462: mtmp->mtrack[j] = mtmp->mtrack[j - 1];
463: mtmp->mtrack[0].x = omx;
464: mtmp->mtrack[0].y = omy;
465: }
466: if (mintrap(mtmp) == 2)
467: return (2);
468: pmon(mtmp);
469: return (1);
470: }
471:
472:
473: int
474: inroom(x, y)
475: xchar x, y;
476: {
477: #ifndef QUEST
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);
483: croom++;
484: }
485: #endif
486: return (-1);
487: }
488:
489: int
490: tamedog(mtmp, obj)
491: struct monst *mtmp;
492: struct obj *obj;
493: {
494: struct monst *mtmp2;
495:
496: if (flags.moonphase == FULL_MOON && night() && rn2(6))
497: return (0);
498:
499:
500: mtmp->mflee = 0;
501: mtmp->mfleetim = 0;
502: if (mtmp->mtame || mtmp->mfroz ||
503: #ifndef NOWORM
504: mtmp->wormno ||
505: #endif
506: mtmp->isshk || mtmp->isgd || strchr(" &@12", mtmp->data->mlet))
507: return (0);
508: if (obj) {
509: if (dogfood(obj) >= MANFOOD)
510: return (0);
511: if (cansee(mtmp->mx, mtmp->my)) {
512: pline("%s devours the %s.", Monnam(mtmp),
513: objects[obj->