xref: /netbsd-src/games/hack/hack.dog.c (revision d5b021c7edb8313eee3804ec3819b28abef1d1a0)
1*d5b021c7Sdholland /*	$NetBSD: hack.dog.c,v 1.12 2011/08/07 06:03:45 dholland Exp $	*/
23ea4a95cSchristos 
302ded532Smycroft /*
41c7f94e5Sjsm  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
51c7f94e5Sjsm  * Amsterdam
61c7f94e5Sjsm  * All rights reserved.
71c7f94e5Sjsm  *
81c7f94e5Sjsm  * Redistribution and use in source and binary forms, with or without
91c7f94e5Sjsm  * modification, are permitted provided that the following conditions are
101c7f94e5Sjsm  * met:
111c7f94e5Sjsm  *
121c7f94e5Sjsm  * - Redistributions of source code must retain the above copyright notice,
131c7f94e5Sjsm  * this list of conditions and the following disclaimer.
141c7f94e5Sjsm  *
151c7f94e5Sjsm  * - Redistributions in binary form must reproduce the above copyright
161c7f94e5Sjsm  * notice, this list of conditions and the following disclaimer in the
171c7f94e5Sjsm  * documentation and/or other materials provided with the distribution.
181c7f94e5Sjsm  *
191c7f94e5Sjsm  * - Neither the name of the Stichting Centrum voor Wiskunde en
201c7f94e5Sjsm  * Informatica, nor the names of its contributors may be used to endorse or
211c7f94e5Sjsm  * promote products derived from this software without specific prior
221c7f94e5Sjsm  * written permission.
231c7f94e5Sjsm  *
241c7f94e5Sjsm  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
251c7f94e5Sjsm  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
261c7f94e5Sjsm  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
271c7f94e5Sjsm  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
281c7f94e5Sjsm  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
291c7f94e5Sjsm  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
301c7f94e5Sjsm  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
311c7f94e5Sjsm  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
321c7f94e5Sjsm  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
331c7f94e5Sjsm  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
341c7f94e5Sjsm  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
351c7f94e5Sjsm  */
361c7f94e5Sjsm 
371c7f94e5Sjsm /*
381c7f94e5Sjsm  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
391c7f94e5Sjsm  * All rights reserved.
401c7f94e5Sjsm  *
411c7f94e5Sjsm  * Redistribution and use in source and binary forms, with or without
421c7f94e5Sjsm  * modification, are permitted provided that the following conditions
431c7f94e5Sjsm  * are met:
441c7f94e5Sjsm  * 1. Redistributions of source code must retain the above copyright
451c7f94e5Sjsm  *    notice, this list of conditions and the following disclaimer.
461c7f94e5Sjsm  * 2. Redistributions in binary form must reproduce the above copyright
471c7f94e5Sjsm  *    notice, this list of conditions and the following disclaimer in the
481c7f94e5Sjsm  *    documentation and/or other materials provided with the distribution.
491c7f94e5Sjsm  * 3. The name of the author may not be used to endorse or promote products
501c7f94e5Sjsm  *    derived from this software without specific prior written permission.
511c7f94e5Sjsm  *
521c7f94e5Sjsm  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
531c7f94e5Sjsm  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
541c7f94e5Sjsm  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
551c7f94e5Sjsm  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
561c7f94e5Sjsm  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
571c7f94e5Sjsm  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
581c7f94e5Sjsm  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
591c7f94e5Sjsm  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
601c7f94e5Sjsm  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
611c7f94e5Sjsm  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6202ded532Smycroft  */
6302ded532Smycroft 
643ea4a95cSchristos #include <sys/cdefs.h>
6502ded532Smycroft #ifndef lint
66*d5b021c7Sdholland __RCSID("$NetBSD: hack.dog.c,v 1.12 2011/08/07 06:03:45 dholland Exp $");
6702ded532Smycroft #endif				/* not lint */
6861f28255Scgd 
6961f28255Scgd #include "hack.h"
703ea4a95cSchristos #include "extern.h"
7161f28255Scgd #include "hack.mfndpos.h"
7261f28255Scgd #include "def.edog.h"
7361f28255Scgd #include "def.mkroom.h"
7461f28255Scgd 
75ab8b6343Sjsm const struct permonst li_dog =
7661f28255Scgd {"little dog", 'd', 2, 18, 6, 1, 6, sizeof(struct edog)};
77ab8b6343Sjsm const struct permonst dog =
7861f28255Scgd {"dog", 'd', 4, 16, 5, 1, 6, sizeof(struct edog)};
79ab8b6343Sjsm const struct permonst la_dog =
8061f28255Scgd {"large dog", 'd', 6, 15, 4, 2, 4, sizeof(struct edog)};
8161f28255Scgd 
829b92b189Sdholland static void initedog(struct monst *);
839b92b189Sdholland static int dogfood(struct obj *);
8461f28255Scgd 
853ea4a95cSchristos void
makedog(void)861fa8a9a6Sdholland makedog(void)
873ea4a95cSchristos {
883ea4a95cSchristos 	struct monst   *mtmp = makemon(&li_dog, u.ux, u.uy);
893ea4a95cSchristos 	if (!mtmp)
903ea4a95cSchristos 		return;		/* dogs were genocided */
9161f28255Scgd 	initedog(mtmp);
9261f28255Scgd }
9361f28255Scgd 
949b92b189Sdholland static void
initedog(struct monst * mtmp)951fa8a9a6Sdholland initedog(struct monst *mtmp)
963ea4a95cSchristos {
9761f28255Scgd 	mtmp->mtame = mtmp->mpeaceful = 1;
9861f28255Scgd 	EDOG(mtmp)->hungrytime = 1000 + moves;
9961f28255Scgd 	EDOG(mtmp)->eattime = 0;
10061f28255Scgd 	EDOG(mtmp)->droptime = 0;
10161f28255Scgd 	EDOG(mtmp)->dropdist = 10000;
10261f28255Scgd 	EDOG(mtmp)->apport = 10;
10361f28255Scgd 	EDOG(mtmp)->whistletime = 0;
10461f28255Scgd }
10561f28255Scgd 
10661f28255Scgd /* attach the monsters that went down (or up) together with @ */
10761f28255Scgd struct monst   *mydogs = 0;
10861f28255Scgd struct monst   *fallen_down = 0;/* monsters that fell through a trapdoor */
10961f28255Scgd /* they will appear on the next level @ goes to, even if he goes up! */
11061f28255Scgd 
1113ea4a95cSchristos void
losedogs(void)1121fa8a9a6Sdholland losedogs(void)
1133ea4a95cSchristos {
1143ea4a95cSchristos 	struct monst   *mtmp;
1153ea4a95cSchristos 	while ((mtmp = mydogs) != NULL) {
11661f28255Scgd 		mydogs = mtmp->nmon;
11761f28255Scgd 		mtmp->nmon = fmon;
11861f28255Scgd 		fmon = mtmp;
11961f28255Scgd 		mnexto(mtmp);
12061f28255Scgd 	}
1213ea4a95cSchristos 	while ((mtmp = fallen_down) != NULL) {
12261f28255Scgd 		fallen_down = mtmp->nmon;
12361f28255Scgd 		mtmp->nmon = fmon;
12461f28255Scgd 		fmon = mtmp;
12561f28255Scgd 		rloc(mtmp);
12661f28255Scgd 	}
12761f28255Scgd }
12861f28255Scgd 
1293ea4a95cSchristos void
keepdogs(void)1301fa8a9a6Sdholland keepdogs(void)
1313ea4a95cSchristos {
1323ea4a95cSchristos 	struct monst   *mtmp;
13361f28255Scgd 	for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
13461f28255Scgd 		if (dist(mtmp->mx, mtmp->my) < 3 && follower(mtmp)
13561f28255Scgd 		    && !mtmp->msleep && !mtmp->mfroz) {
13661f28255Scgd 			relmon(mtmp);
13761f28255Scgd 			mtmp->nmon = mydogs;
13861f28255Scgd 			mydogs = mtmp;
13961f28255Scgd 			unpmon(mtmp);
1403ea4a95cSchristos 			keepdogs();	/* we destroyed the link, so use
1413ea4a95cSchristos 					 * recursion */
14261f28255Scgd 			return;	/* (admittedly somewhat primitive) */
14361f28255Scgd 		}
14461f28255Scgd }
14561f28255Scgd 
1463ea4a95cSchristos void
fall_down(struct monst * mtmp)1471fa8a9a6Sdholland fall_down(struct monst *mtmp)
1483ea4a95cSchristos {
14961f28255Scgd 	relmon(mtmp);
15061f28255Scgd 	mtmp->nmon = fallen_down;
15161f28255Scgd 	fallen_down = mtmp;
15261f28255Scgd 	unpmon(mtmp);
15361f28255Scgd 	mtmp->mtame = 0;
15461f28255Scgd }
15561f28255Scgd 
15661f28255Scgd /* return quality of food; the lower the better */
15761f28255Scgd #define	DOGFOOD	0
15861f28255Scgd #define	CADAVER	1
15961f28255Scgd #define	ACCFOOD	2
16061f28255Scgd #define	MANFOOD	3
16161f28255Scgd #define	APPORT	4
16261f28255Scgd #define	POISON	5
16361f28255Scgd #define	UNDEF	6
1649b92b189Sdholland static int
dogfood(struct obj * obj)1651fa8a9a6Sdholland dogfood(struct obj *obj)
1663ea4a95cSchristos {
16761f28255Scgd 	switch (obj->olet) {
16861f28255Scgd 	case FOOD_SYM:
16961f28255Scgd 		return (
17061f28255Scgd 			(obj->otyp == TRIPE_RATION) ? DOGFOOD :
17161f28255Scgd 			(obj->otyp < CARROT) ? ACCFOOD :
17261f28255Scgd 			(obj->otyp < CORPSE) ? MANFOOD :
17361f28255Scgd 			(poisonous(obj) || obj->age + 50 <= moves ||
17461f28255Scgd 			 obj->otyp == DEAD_COCKATRICE)
17561f28255Scgd 			? POISON : CADAVER
17661f28255Scgd 			);
17761f28255Scgd 	default:
1783ea4a95cSchristos 		if (!obj->cursed)
1793ea4a95cSchristos 			return (APPORT);
180*d5b021c7Sdholland 		/* FALLTHROUGH */
18161f28255Scgd 	case BALL_SYM:
18261f28255Scgd 	case CHAIN_SYM:
18361f28255Scgd 	case ROCK_SYM:
18461f28255Scgd 		return (UNDEF);
18561f28255Scgd 	}
18661f28255Scgd }
18761f28255Scgd 
18861f28255Scgd /* return 0 (no move), 1 (move) or 2 (dead) */
1893ea4a95cSchristos int
dog_move(struct monst * mtmp,int after)190ab8b6343Sjsm dog_move(struct monst *mtmp, int after)
1913ea4a95cSchristos {
1923ea4a95cSchristos 	int             nx, ny, omx, omy, appr, nearer, j;
1933ea4a95cSchristos 	int             udist, chi = 0, i, whappr;
1943ea4a95cSchristos 	struct monst   *mtmp2;
195ab8b6343Sjsm 	const struct permonst *mdat = mtmp->data;
1963ea4a95cSchristos 	struct edog    *edog = EDOG(mtmp);
19761f28255Scgd 	struct obj     *obj;
19861f28255Scgd 	struct trap    *trap;
19961f28255Scgd 	xchar           cnt, chcnt, nix, niy;
20061f28255Scgd 	schar           dogroom, uroom;
2013ea4a95cSchristos 	xchar           gx = 0, gy = 0, gtyp, otyp;	/* current goal */
20261f28255Scgd 	coord           poss[9];
20361f28255Scgd 	int             info[9];
20461f28255Scgd #define GDIST(x,y) ((x-gx)*(x-gx) + (y-gy)*(y-gy))
20561f28255Scgd #define DDIST(x,y) ((x-omx)*(x-omx) + (y-omy)*(y-omy))
20661f28255Scgd 
2073ea4a95cSchristos 	if (moves <= edog->eattime)
2083ea4a95cSchristos 		return (0);	/* dog is still eating */
20961f28255Scgd 	omx = mtmp->mx;
21061f28255Scgd 	omy = mtmp->my;
21161f28255Scgd 	whappr = (moves - EDOG(mtmp)->whistletime < 5);
21261f28255Scgd 	if (moves > edog->hungrytime + 500 && !mtmp->mconf) {
21361f28255Scgd 		mtmp->mconf = 1;
21461f28255Scgd 		mtmp->mhpmax /= 3;
21561f28255Scgd 		if (mtmp->mhp > mtmp->mhpmax)
21661f28255Scgd 			mtmp->mhp = mtmp->mhpmax;
21761f28255Scgd 		if (cansee(omx, omy))
21861f28255Scgd 			pline("%s is confused from hunger.", Monnam(mtmp));
2193ea4a95cSchristos 		else
2203ea4a95cSchristos 			pline("You feel worried about %s.", monnam(mtmp));
2213ea4a95cSchristos 	} else if (moves > edog->hungrytime + 750 || mtmp->mhp < 1) {
22261f28255Scgd 		if (cansee(omx, omy))
22361f28255Scgd 			pline("%s dies from hunger.", Monnam(mtmp));
22461f28255Scgd 		else
22561f28255Scgd 			pline("You have a sad feeling for a moment, then it passes.");
22661f28255Scgd 		mondied(mtmp);
22761f28255Scgd 		return (2);
22861f28255Scgd 	}
22961f28255Scgd 	dogroom = inroom(omx, omy);
23061f28255Scgd 	uroom = inroom(u.ux, u.uy);
23161f28255Scgd 	udist = dist(omx, omy);
23261f28255Scgd 
23361f28255Scgd 	/* maybe we tamed him while being swallowed --jgm */
2343ea4a95cSchristos 	if (!udist)
2353ea4a95cSchristos 		return (0);
23661f28255Scgd 
23761f28255Scgd 	/* if we are carrying sth then we drop it (perhaps near @) */
23861f28255Scgd 	/* Note: if apport == 1 then our behaviour is independent of udist */
23961f28255Scgd 	if (mtmp->minvent) {
24061f28255Scgd 		if (!rn2(udist) || !rn2((int) edog->apport))
2413c439f43Sdholland 			if ((unsigned) rn2(10) < edog->apport) {
24261f28255Scgd 				relobj(mtmp, (int) mtmp->minvis);
2433ea4a95cSchristos 				if (edog->apport > 1)
2443ea4a95cSchristos 					edog->apport--;
24561f28255Scgd 				edog->dropdist = udist;	/* hpscdi!jon */
24661f28255Scgd 				edog->droptime = moves;
24761f28255Scgd 			}
24861f28255Scgd 	} else {
2493ea4a95cSchristos 		if ((obj = o_at(omx, omy)) != NULL)
2503ea4a95cSchristos 			if (!strchr("0_", obj->olet)) {
25161f28255Scgd 				if ((otyp = dogfood(obj)) <= CADAVER) {
25261f28255Scgd 					nix = omx;
25361f28255Scgd 					niy = omy;
25461f28255Scgd 					goto eatobj;
25561f28255Scgd 				}
25661f28255Scgd 				if (obj->owt < 10 * mtmp->data->mlevel)
2573c439f43Sdholland 					if ((unsigned) rn2(20) < edog->apport + 3)
25861f28255Scgd 						if (rn2(udist) || !rn2((int) edog->apport)) {
25961f28255Scgd 							freeobj(obj);
26061f28255Scgd 							unpobj(obj);
2613ea4a95cSchristos 							/*
2623ea4a95cSchristos 							 * if(levl[omx][omy].s
2633ea4a95cSchristos 							 * crsym ==
2643ea4a95cSchristos 							 * obj->olet)
2653ea4a95cSchristos 							 * newsym(omx,omy);
2663ea4a95cSchristos 							 */
26761f28255Scgd 							mpickobj(mtmp, obj);
26861f28255Scgd 						}
26961f28255Scgd 			}
27061f28255Scgd 	}
27161f28255Scgd 
27261f28255Scgd 	/* first we look for food */
27361f28255Scgd 	gtyp = UNDEF;		/* no goal as yet */
27461f28255Scgd #ifdef LINT
27561f28255Scgd 	gx = gy = 0;		/* suppress 'used before set' message */
2763ea4a95cSchristos #endif	/* LINT */
27761f28255Scgd 	for (obj = fobj; obj; obj = obj->nobj) {
27861f28255Scgd 		otyp = dogfood(obj);
2793ea4a95cSchristos 		if (otyp > gtyp || otyp == UNDEF)
2803ea4a95cSchristos 			continue;
2813ea4a95cSchristos 		if (inroom(obj->ox, obj->oy) != dogroom)
2823ea4a95cSchristos 			continue;
28361f28255Scgd 		if (otyp < MANFOOD &&
28461f28255Scgd 		    (dogroom >= 0 || DDIST(obj->ox, obj->oy) < 10)) {
28561f28255Scgd 			if (otyp < gtyp || (otyp == gtyp &&
28661f28255Scgd 				 DDIST(obj->ox, obj->oy) < DDIST(gx, gy))) {
28761f28255Scgd 				gx = obj->ox;
28861f28255Scgd 				gy = obj->oy;
28961f28255Scgd 				gtyp = otyp;
29061f28255Scgd 			}
2913ea4a95cSchristos 		} else if (gtyp == UNDEF && dogroom >= 0 &&
29261f28255Scgd 			   uroom == dogroom &&
2933c439f43Sdholland 			   !mtmp->minvent && edog->apport > (unsigned)rn2(8)) {
29461f28255Scgd 			gx = obj->ox;
29561f28255Scgd 			gy = obj->oy;
29661f28255Scgd 			gtyp = APPORT;
29761f28255Scgd 		}
29861f28255Scgd 	}
29961f28255Scgd 	if (gtyp == UNDEF ||
30061f28255Scgd 	  (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)) {
30161f28255Scgd 		if (dogroom < 0 || dogroom == uroom) {
30261f28255Scgd 			gx = u.ux;
30361f28255Scgd 			gy = u.uy;
30461f28255Scgd #ifndef QUEST
30561f28255Scgd 		} else {
30661f28255Scgd 			int             tmp = rooms[dogroom].fdoor;
30761f28255Scgd 			cnt = rooms[dogroom].doorct;
30861f28255Scgd 
30961f28255Scgd 			gx = gy = FAR;	/* random, far away */
31061f28255Scgd 			while (cnt--) {
31161f28255Scgd 				if (dist(gx, gy) >
31261f28255Scgd 				    dist(doors[tmp].x, doors[tmp].y)) {
31361f28255Scgd 					gx = doors[tmp].x;
31461f28255Scgd 					gy = doors[tmp].y;
31561f28255Scgd 				}
31661f28255Scgd 				tmp++;
31761f28255Scgd 			}
31861f28255Scgd 			/* here gx == FAR e.g. when dog is in a vault */
31961f28255Scgd 			if (gx == FAR || (gx == omx && gy == omy)) {
32061f28255Scgd 				gx = u.ux;
32161f28255Scgd 				gy = u.uy;
32261f28255Scgd 			}
3233ea4a95cSchristos #endif	/* QUEST */
32461f28255Scgd 		}
32561f28255Scgd 		appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0;
32661f28255Scgd 		if (after && udist <= 4 && gx == u.ux && gy == u.uy)
32761f28255Scgd 			return (0);
32861f28255Scgd 		if (udist > 1) {
32961f28255Scgd 			if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) ||
33061f28255Scgd 			    whappr ||
33161f28255Scgd 			    (mtmp->minvent && rn2((int) edog->apport)))
33261f28255Scgd 				appr = 1;
33361f28255Scgd 		}
33461f28255Scgd 		/* if you have dog food he'll follow you more closely */
33561f28255Scgd 		if (appr == 0) {
33661f28255Scgd 			obj = invent;
33761f28255Scgd 			while (obj) {
33861f28255Scgd 				if (obj->otyp == TRIPE_RATION) {
33961f28255Scgd 					appr = 1;
34061f28255Scgd 					break;
34161f28255Scgd 				}
34261f28255Scgd 				obj = obj->nobj;
34361f28255Scgd 			}
34461f28255Scgd 		}
3453ea4a95cSchristos 	} else
3463ea4a95cSchristos 		appr = 1;	/* gtyp != UNDEF */
3473ea4a95cSchristos 	if (mtmp->mconf)
3483ea4a95cSchristos 		appr = 0;
34961f28255Scgd 
35061f28255Scgd 	if (gx == u.ux && gy == u.uy && (dogroom != uroom || dogroom < 0)) {
3513ea4a95cSchristos 		coord          *cp;
35261f28255Scgd 		cp = gettrack(omx, omy);
35361f28255Scgd 		if (cp) {
35461f28255Scgd 			gx = cp->x;
35561f28255Scgd 			gy = cp->y;
35661f28255Scgd 		}
35761f28255Scgd 	}
35861f28255Scgd 	nix = omx;
35961f28255Scgd 	niy = omy;
36061f28255Scgd 	cnt = mfndpos(mtmp, poss, info, ALLOW_M | ALLOW_TRAPS);
36161f28255Scgd 	chcnt = 0;
36261f28255Scgd 	chi = -1;
36361f28255Scgd 	for (i = 0; i < cnt; i++) {
36461f28255Scgd 		nx = poss[i].x;
36561f28255Scgd 		ny = poss[i].y;
36661f28255Scgd 		if (info[i] & ALLOW_M) {
36761f28255Scgd 			mtmp2 = m_at(nx, ny);
368a3fb5aa7Sjnemeth 			if (mtmp2 == NULL)
369f413c2baSjnemeth 				panic("error in dog_move");
37061f28255Scgd 			if (mtmp2->data->mlevel >= mdat->mlevel + 2 ||
37161f28255Scgd 			    mtmp2->data->mlet == 'c')
37261f28255Scgd 				continue;
3733ea4a95cSchristos 			if (after)
3743ea4a95cSchristos 				return (0);	/* hit only once each move */
37561f28255Scgd 
37661f28255Scgd 			if (hitmm(mtmp, mtmp2) == 1 && rn2(4) &&
37761f28255Scgd 			    mtmp2->mlstmv != moves &&
3783ea4a95cSchristos 			    hitmm(mtmp2, mtmp) == 2)
3793ea4a95cSchristos 				return (2);
38061f28255Scgd 			return (0);
38161f28255Scgd 		}
38261f28255Scgd 		/* dog avoids traps */
38361f28255Scgd 		/* but perhaps we have to pass a trap in order to follow @ */
38461f28255Scgd 		if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx, ny))) {
3853ea4a95cSchristos 			if (!trap->tseen && rn2(40))
3863ea4a95cSchristos 				continue;
3873ea4a95cSchristos 			if (rn2(10))
3883ea4a95cSchristos 				continue;
38961f28255Scgd 		}
39061f28255Scgd 		/* dog eschewes cursed objects */
39161f28255Scgd 		/* but likes dog food */
39261f28255Scgd 		obj = fobj;
39361f28255Scgd 		while (obj) {
39461f28255Scgd 			if (obj->ox != nx || obj->oy != ny)
39561f28255Scgd 				goto nextobj;
3963ea4a95cSchristos 			if (obj->cursed)
3973ea4a95cSchristos 				goto nxti;
39861f28255Scgd 			if (obj->olet == FOOD_SYM &&
39961f28255Scgd 			    (otyp = dogfood(obj)) < MANFOOD &&
40061f28255Scgd 			    (otyp < ACCFOOD || edog->hungrytime <= moves)) {
4013ea4a95cSchristos 				/*
4023ea4a95cSchristos 				 * Note: our dog likes the food so much that
4033ea4a95cSchristos 				 * he might eat it even when it conceals a
4043ea4a95cSchristos 				 * cursed object
4053ea4a95cSchristos 				 */
40661f28255Scgd 				nix = nx;
40761f28255Scgd 				niy = ny;
40861f28255Scgd 				chi = i;
40961f28255Scgd 		eatobj:
41061f28255Scgd 				edog->eattime =
41161f28255Scgd 					moves + obj->quan * objects[obj->otyp].oc_delay;
41261f28255Scgd 				if (edog->hungrytime < moves)
41361f28255Scgd 					edog->hungrytime = moves;
41461f28255Scgd 				edog->hungrytime +=
41561f28255Scgd 					5 * obj->quan * objects[obj->otyp].nutrition;
41661f28255Scgd 				mtmp->mconf = 0;
41761f28255Scgd 				if (cansee(nix, niy))
41861f28255Scgd 					pline("%s ate %s.", Monnam(mtmp), doname(obj));
41961f28255Scgd 				/* perhaps this was a reward */
42061f28255Scgd 				if (otyp != CADAVER)
42161f28255Scgd 					edog->apport += 200 / (edog->dropdist + moves - edog->droptime);
42261f28255Scgd 				delobj(obj);
42361f28255Scgd 				goto newdogpos;
42461f28255Scgd 			}
42561f28255Scgd 	nextobj:
42661f28255Scgd 			obj = obj->nobj;
42761f28255Scgd 		}
42861f28255Scgd 
42961f28255Scgd 		for (j = 0; j < MTSZ && j < cnt - 1; j++)
43061f28255Scgd 			if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y)
4313ea4a95cSchristos 				if (rn2(4 * (cnt - j)))
4323ea4a95cSchristos 					goto nxti;
43361f28255Scgd 
4343ea4a95cSchristos 		/*
4353ea4a95cSchristos 		 * Some stupid C compilers cannot compute the whole
4363ea4a95cSchristos 		 * expression at once.
4373ea4a95cSchristos 		 */
43861f28255Scgd 		nearer = GDIST(nx, ny);
43961f28255Scgd 		nearer -= GDIST(nix, niy);
44061f28255Scgd 		nearer *= appr;
44161f28255Scgd 		if ((nearer == 0 && !rn2(++chcnt)) || nearer < 0 ||
44261f28255Scgd 		    (nearer > 0 && !whappr &&
44361f28255Scgd 		     ((omx == nix && omy == niy && !rn2(3))
44461f28255Scgd 		      || !rn2(12))
44561f28255Scgd 		     )) {
44661f28255Scgd 			nix = nx;
44761f28255Scgd 			niy = ny;
4483ea4a95cSchristos 			if (nearer < 0)
4493ea4a95cSchristos 				chcnt = 0;
45061f28255Scgd 			chi = i;
45161f28255Scgd 		}
45261f28255Scgd nxti:		;
45361f28255Scgd 	}
45461f28255Scgd newdogpos:
45561f28255Scgd 	if (nix != omx || niy != omy) {
45661f28255Scgd 		if (info[chi] & ALLOW_U) {
45761f28255Scgd 			(void) hitu(mtmp, d(mdat->damn, mdat->damd) + 1);
45861f28255Scgd 			return (0);
45961f28255Scgd 		}
46061f28255Scgd 		mtmp->mx = nix;
46161f28255Scgd 		mtmp->my = niy;
4623ea4a95cSchristos 		for (j = MTSZ - 1; j > 0; j--)
4633ea4a95cSchristos 			mtmp->mtrack[j] = mtmp->mtrack[j - 1];
46461f28255Scgd 		mtmp->mtrack[0].x = omx;
46561f28255Scgd 		mtmp->mtrack[0].y = omy;
46661f28255Scgd 	}
46761f28255Scgd 	if (mintrap(mtmp) == 2)	/* he died */
46861f28255Scgd 		return (2);
46961f28255Scgd 	pmon(mtmp);
47061f28255Scgd 	return (1);
47161f28255Scgd }
47261f28255Scgd 
47361f28255Scgd /* return roomnumber or -1 */
4743ea4a95cSchristos int
inroom(xchar x,xchar y)4751fa8a9a6Sdholland inroom(xchar x, xchar y)
4763ea4a95cSchristos {
47761f28255Scgd #ifndef QUEST
478*d5b021c7Sdholland 	int pos = 0;
479*d5b021c7Sdholland 
480*d5b021c7Sdholland 	while (rooms[pos].hx >= 0) {
481*d5b021c7Sdholland 		if (rooms[pos].hx >= x - 1 && rooms[pos].lx <= x + 1 &&
482*d5b021c7Sdholland 		    rooms[pos].hy >= y - 1 && rooms[pos].ly <= y + 1)
483*d5b021c7Sdholland 			return pos;
484*d5b021c7Sdholland 		pos++;
48561f28255Scgd 	}
4863ea4a95cSchristos #endif	/* QUEST */
48761f28255Scgd 	return (-1);		/* not in room or on door */
48861f28255Scgd }
48961f28255Scgd 
4903ea4a95cSchristos int
tamedog(struct monst * mtmp,struct obj * obj)4911fa8a9a6Sdholland tamedog(struct monst *mtmp, struct obj *obj)
49261f28255Scgd {
4933ea4a95cSchristos 	struct monst   *mtmp2;
49461f28255Scgd 
49561f28255Scgd 	if (flags.moonphase == FULL_MOON && night() && rn2(6))
49661f28255Scgd 		return (0);
49761f28255Scgd 
49861f28255Scgd 	/* If we cannot tame him, at least he's no longer afraid. */
49961f28255Scgd 	mtmp->mflee = 0;
50061f28255Scgd 	mtmp->mfleetim = 0;
50161f28255Scgd 	if (mtmp->mtame || mtmp->mfroz ||
50261f28255Scgd #ifndef NOWORM
50361f28255Scgd 	    mtmp->wormno ||
5043ea4a95cSchristos #endif	/* NOWORM */
5053ea4a95cSchristos 	    mtmp->isshk || mtmp->isgd || strchr(" &@12", mtmp->data->mlet))
50661f28255Scgd 		return (0);	/* no tame long worms? */
50761f28255Scgd 	if (obj) {
5083ea4a95cSchristos 		if (dogfood(obj) >= MANFOOD)
5093ea4a95cSchristos 			return (0);
51061f28255Scgd 		if (cansee(mtmp->mx, mtmp->my)) {
51161f28255Scgd 			pline("%s devours the %s.", Monnam(mtmp),
51261f28255Scgd 			      objects[obj->otyp].oc_name);
51361f28255Scgd 		}
51461f28255Scgd 		obfree(obj, (struct obj *) 0);
51561f28255Scgd 	}
51661f28255Scgd 	mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth);
51761f28255Scgd 	*mtmp2 = *mtmp;
51861f28255Scgd 	mtmp2->mxlth = sizeof(struct edog);
5193ea4a95cSchristos 	if (mtmp->mnamelth)
5203ea4a95cSchristos 		(void) strcpy(NAME(mtmp2), NAME(mtmp));
52161f28255Scgd 	initedog(mtmp2);
52261f28255Scgd 	replmon(mtmp, mtmp2);
52361f28255Scgd 	return (1);
52461f28255Scgd }
525