Sweep-fix comparing pointers with 0 (and assigning 0 to pointers).
[dragonfly.git] / games / hack / hack.dog.c
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
5 #include "hack.h"
6 #include "hack.mfndpos.h"
7 #include "def.edog.h"
8
9 struct permonst li_dog =
10         { "little dog", 'd', 2, 18, 6, 1, 6, sizeof(struct edog) };
11 struct permonst dog =
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) };
15
16 static void initedog(struct monst *);
17 static xchar dogfood(struct obj *);
18
19 void
20 makedog(void)
21 {
22         struct monst *mtmp = makemon(&li_dog, u.ux, u.uy);
23
24         if (!mtmp)
25                 return;         /* dogs were genocided */
26         initedog(mtmp);
27 }
28
29 static void
30 initedog(struct monst *mtmp)
31 {
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;
39 }
40
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! */
45
46 void
47 losedogs(void)
48 {
49         struct monst *mtmp;
50
51         while ((mtmp = mydogs)) {
52                 mydogs = mtmp->nmon;
53                 mtmp->nmon = fmon;
54                 fmon = mtmp;
55                 mnexto(mtmp);
56         }
57         while ((mtmp = fallen_down)) {
58                 fallen_down = mtmp->nmon;
59                 mtmp->nmon = fmon;
60                 fmon = mtmp;
61                 rloc(mtmp);
62         }
63 }
64
65 void
66 keepdogs(void)
67 {
68         struct monst *mtmp;
69
70         for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
71                 if (dist(mtmp->mx, mtmp->my) < 3 && follower(mtmp)
72                     && !mtmp->msleep && !mtmp->mfroz) {
73                         relmon(mtmp);
74                         mtmp->nmon = mydogs;
75                         mydogs = mtmp;
76                         unpmon(mtmp);
77                         keepdogs();     /* we destroyed the link, so use recursion */
78                         return;         /* (admittedly somewhat primitive) */
79                 }
80 }
81
82 void
83 fall_down(struct monst *mtmp)
84 {
85         relmon(mtmp);
86         mtmp->nmon = fallen_down;
87         fallen_down = mtmp;
88         unpmon(mtmp);
89         mtmp->mtame = 0;
90 }
91
92 /* return quality of food; the lower the better */
93 #define DOGFOOD 0
94 #define CADAVER 1
95 #define ACCFOOD 2
96 #define MANFOOD 3
97 #define APPORT  4
98 #define POISON  5
99 #define UNDEF   6
100
101 static xchar
102 dogfood(struct obj *obj)
103 {
104         switch (obj->olet) {
105         case FOOD_SYM:
106                 return (
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)
112                     ? POISON : CADAVER
113                     );
114         default:
115                 if (!obj->cursed)
116                         return (APPORT);
117         /* fall into next case */
118         case BALL_SYM:
119         case CHAIN_SYM:
120         case ROCK_SYM:
121                 return (UNDEF);
122         }
123 }
124
125 /* return 0 (no move), 1 (move) or 2 (dead) */
126 int
127 dog_move(struct monst *mtmp, int after)
128 {
129         int nx, ny, omx, omy, appr, nearer, j;
130         int udist, chi = 0, i, whappr;
131         struct monst *mtmp2;
132         struct permonst *mdat = mtmp->data;
133         struct edog *edog = EDOG(mtmp);
134         struct obj *obj;
135         struct trap *trap;
136         xchar cnt, chcnt, nix, niy;
137         schar dogroom, uroom;
138         xchar gx, gy, gtyp, otyp;       /* current goal */
139         coord poss[9];
140         int info[9];
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))
143
144         if (moves <= edog->eattime)     /* dog is still eating */
145                 return (0);
146         omx = mtmp->mx;
147         omy = mtmp->my;
148         whappr = (moves - EDOG(mtmp)->whistletime < 5);
149         if (moves > edog->hungrytime + 500 && !mtmp->mconf) {
150                 mtmp->mconf = 1;
151                 mtmp->mhpmax /= 3;
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));
156                 else
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));
161                 else
162                         pline("You have a sad feeling for a moment, then it passes.");
163                 mondied(mtmp);
164                 return (2);
165         }
166         dogroom = inroom(omx, omy);
167         uroom = inroom(u.ux, u.uy);
168         udist = dist(omx, omy);
169
170         /* maybe we tamed him while being swallowed --jgm */
171         if (!udist)
172                 return (0);
173
174         /* if we are carrying sth then we drop it (perhaps near @) */
175         /* Note: if apport == 1 then our behaviour is independent of udist */
176         if (mtmp->minvent) {
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)
181                                         edog->apport--;
182                                 edog->dropdist = udist; /* hpscdi!jon */
183                                 edog->droptime = moves;
184                         }
185         } else if ((obj = o_at(omx, omy))) {
186                 if (!strchr("0_", obj->olet)) {
187                         if ((otyp = dogfood(obj)) <= CADAVER) {
188                                 nix = omx;
189                                 niy = omy;
190                                 goto eatobj;
191                         }
192                         if (obj->owt < 10 * mtmp->data->mlevel) {
193                                 if (rn2(20) < (int)edog->apport + 3) {
194                                         if (rn2(udist) ||
195                                             !rn2((int)edog->apport)) {
196                                                 freeobj(obj);
197                                                 unpobj(obj);
198                                                 /* if (levl[omx][omy].scrsym == obj->olet)
199                                                  *      newsym(omx, omy); */
200                                                 mpickobj(mtmp, obj);
201                                         }
202                                 }
203                         }
204                 }
205         }
206
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) {
211                 otyp = dogfood(obj);
212                 if (otyp > gtyp || otyp == UNDEF)
213                         continue;
214                 if (inroom(obj->ox, obj->oy) != dogroom)
215                         continue;
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))) {
220                                 gx = obj->ox;
221                                 gy = obj->oy;
222                                 gtyp = otyp;
223                         }
224                 } else if (gtyp == UNDEF && dogroom >= 0 &&
225                     uroom == dogroom &&
226                     !mtmp->minvent && (int)edog->apport > rn2(8)) {
227                         gx = obj->ox;
228                         gy = obj->oy;
229                         gtyp = APPORT;
230                 }
231         }
232         if (gtyp == UNDEF ||
233             (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)) {
234                 if (dogroom < 0 || dogroom == uroom) {
235                         gx = u.ux;
236                         gy = u.uy;
237 #ifndef QUEST
238                 } else {
239                         int tmp = rooms[dogroom].fdoor;
240                         cnt = rooms[dogroom].doorct;
241
242                         gx = gy = FAR;  /* random, far away */
243                         while (cnt--) {
244                                 if (dist(gx, gy) >
245                                     dist(doors[tmp].x, doors[tmp].y)) {
246                                         gx = doors[tmp].x;
247                                         gy = doors[tmp].y;
248                                 }
249                                 tmp++;
250                         }
251                         /* here gx == FAR e.g. when dog is in a vault */
252                         if (gx == FAR || (gx == omx && gy == omy)) {
253                                 gx = u.ux;
254                                 gy = u.uy;
255                         }
256 #endif /* QUEST */
257                 }
258                 appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
259                 if (after && udist <= 4 && gx == u.ux && gy == u.uy)
260                         return (0);
261                 if (udist > 1) {
262                         if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||
263                             whappr ||
264                             (mtmp->minvent && rn2((int)edog->apport)))
265                                 appr = 1;
266                 }
267                 /* if you have dog food he'll follow you more closely */
268                 if (appr == 0) {
269                         obj = invent;
270                         while (obj) {
271                                 if (obj->otyp == TRIPE_RATION) {
272                                         appr = 1;
273                                         break;
274                                 }
275                                 obj = obj->nobj;
276                         }
277                 }
278         } else          /* gtyp != UNDEF */
279                 appr = 1;
280         if (mtmp->mconf)
281                 appr = 0;
282
283         if (gx == u.ux && gy == u.uy && (dogroom != uroom || dogroom < 0)) {
284                 coord *cp;
285                 cp = gettrack(omx, omy);
286                 if (cp) {
287                         gx = cp->x;
288                         gy = cp->y;
289                 }
290         }
291
292         nix = omx;
293         niy = omy;
294         cnt = mfndpos(mtmp, poss, info, ALLOW_M | ALLOW_TRAPS);
295         chcnt = 0;
296         chi = -1;
297         for (i = 0; i < cnt; i++) {
298                 nx = poss[i].x;
299                 ny = poss[i].y;
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')
304                                 continue;
305                         if (after)              /* hit only once each move */
306                                 return (0);
307
308                         if (hitmm(mtmp, mtmp2) == 1 && rn2(4) &&
309                             mtmp2->mlstmv != moves &&
310                             hitmm(mtmp2, mtmp) == 2)
311                                 return (2);
312                         return (0);
313                 }
314
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))
319                                 continue;
320                         if (rn2(10))
321                                 continue;
322                 }
323
324                 /* dog eschewes cursed objects */
325                 /* but likes dog food */
326                 obj = fobj;
327                 while (obj) {
328                         if (obj->ox != nx || obj->oy != ny)
329                                 goto nextobj;
330                         if (obj->cursed)
331                                 goto nxti;
332                         if (obj->olet == FOOD_SYM &&
333                             (otyp = dogfood(obj)) < MANFOOD &&
334                             (otyp < ACCFOOD || edog->hungrytime <= moves)) {
335                                 /*
336                                  * Note: our dog likes the food so much that
337                                  * he might eat it even when it conceals a
338                                  * cursed object
339                                  */
340                                 nix = nx;
341                                 niy = ny;
342                                 chi = i;
343 eatobj:
344                                 edog->eattime =
345                                         moves + obj->quan *
346                                         objects[obj->otyp].oc_delay;
347                                 if (edog->hungrytime < moves)
348                                         edog->hungrytime = moves;
349                                 edog->hungrytime +=
350                                         5 * obj->quan *
351                                         objects[obj->otyp].nutrition;
352                                 mtmp->mconf = 0;
353                                 if (cansee(nix, niy))
354                                         pline("%s ate %s.", Monnam(
355                                                       mtmp), doname(obj));
356                                 /* perhaps this was a reward */
357                                 if (otyp != CADAVER)
358                                         edog->apport += 200 /
359                                                         (edog->dropdist +
360                                                          moves - edog->droptime);
361                                 delobj(obj);
362                                 goto newdogpos;
363                         }
364 nextobj:
365                         obj = obj->nobj;
366                 }
367
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)))
371                                         goto nxti;
372
373 /* Some stupid C compilers cannot compute the whole expression at once. */
374                 nearer = GDIST(nx, ny);
375                 nearer -= GDIST(nix, niy);
376                 nearer *= appr;
377                 if ((nearer == 0 && !rn2(++chcnt)) || nearer < 0 ||
378                     (nearer > 0 && !whappr &&
379                      ((omx == nix && omy == niy && !rn2(3))
380                       || !rn2(12))
381                     )) {
382                         nix = nx;
383                         niy = ny;
384                         if (nearer < 0)
385                                 chcnt = 0;
386                         chi = i;
387                 }
388 nxti:;
389         }
390 newdogpos:
391         if (nix != omx || niy != omy) {
392                 if (info[chi] & ALLOW_U) {
393                         hitu(mtmp, d(mdat->damn, mdat->damd) + 1);
394                         return (0);
395                 }
396                 mtmp->mx = nix;
397                 mtmp->my = niy;
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;
402         }
403         if (mintrap(mtmp) == 2) /* he died */
404                 return (2);
405         pmon(mtmp);
406         return (1);
407 }
408
409 /* return roomnumber or -1 */
410 int
411 inroom(xchar x, xchar y)
412 {
413 #ifndef QUEST
414         struct mkroom *croom = &rooms[0];
415
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);
420                 croom++;
421         }
422 #endif /* QUEST */
423         return (-1);            /* not in room or on door */
424 }
425
426 bool
427 tamedog(struct monst *mtmp, struct obj *obj)
428 {
429         struct monst *mtmp2;
430
431         if (flags.moonphase == FULL_MOON && night() && rn2(6))
432                 return (0);
433
434         /* If we cannot tame him, at least he's no longer afraid. */
435         mtmp->mflee = 0;
436         mtmp->mfleetim = 0;
437         if (mtmp->mtame || mtmp->mfroz ||
438 #ifndef NOWORM
439             mtmp->wormno ||
440 #endif /* NOWORM */
441             mtmp->isshk || mtmp->isgd || strchr(" &@12", mtmp->data->mlet))
442                 return (0);     /* no tame long worms? */
443         if (obj) {
444                 if (dogfood(obj) >= MANFOOD)
445                         return (0);
446                 if (cansee(mtmp->mx, mtmp->my))
447                         pline("%s devours the %s.", Monnam(mtmp),
448                               objects[obj->otyp].oc_name);
449                 obfree(obj, NULL);
450         }
451         mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth);
452         *mtmp2 = *mtmp;
453         mtmp2->mxlth = sizeof(struct edog);
454         if (mtmp->mnamelth)
455                 strcpy(NAME(mtmp2), NAME(mtmp));
456         initedog(mtmp2);
457         replmon(mtmp, mtmp2);
458         return (1);
459 }