diff options
author | B. Watson <yalhcru@gmail.com> | 2015-05-07 16:32:32 -0400 |
---|---|---|
committer | B. Watson <yalhcru@gmail.com> | 2015-05-07 16:32:32 -0400 |
commit | 013ac7742311556022304e8b30ca170d48b3a016 (patch) | |
tree | 53faa33e75991363f1a6dcc7edc83a66b70e6995 /hack/hack.dog.c | |
download | bsd-games-extra-013ac7742311556022304e8b30ca170d48b3a016.tar.gz |
initial commit
Diffstat (limited to 'hack/hack.dog.c')
-rw-r--r-- | hack/hack.dog.c | 459 |
1 files changed, 459 insertions, 0 deletions
diff --git a/hack/hack.dog.c b/hack/hack.dog.c new file mode 100644 index 0000000..531a3a4 --- /dev/null +++ b/hack/hack.dog.c @@ -0,0 +1,459 @@ +/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ +/* hack.dog.c - version 1.0.3 */ +/* $FreeBSD: src/games/hack/hack.dog.c,v 1.3 1999/11/16 02:57:03 billf Exp $ */ + +#include "hack.h" +#include "hack.mfndpos.h" +#include "def.edog.h" + +struct permonst li_dog = + { "little dog", 'd', 2, 18, 6, 1, 6, sizeof(struct edog) }; +struct permonst dog = + { "dog", 'd', 4, 16, 5, 1, 6, sizeof(struct edog) }; +struct permonst la_dog = + { "large dog", 'd', 6, 15, 4, 2, 4, sizeof(struct edog) }; + +static void initedog(struct monst *); +static xchar dogfood(struct obj *); + +void +makedog(void) +{ + struct monst *mtmp = makemon(&li_dog, u.ux, u.uy); + + if (!mtmp) + return; /* dogs were genocided */ + initedog(mtmp); +} + +static void +initedog(struct monst *mtmp) +{ + mtmp->mtame = mtmp->mpeaceful = 1; + EDOG(mtmp)->hungrytime = 1000 + moves; + EDOG(mtmp)->eattime = 0; + EDOG(mtmp)->droptime = 0; + EDOG(mtmp)->dropdist = 10000; + EDOG(mtmp)->apport = 10; + EDOG(mtmp)->whistletime = 0; +} + +/* attach the monsters that went down (or up) together with @ */ +struct monst *mydogs = NULL; +struct monst *fallen_down = NULL; /* monsters that fell through a trapdoor */ +/* they will appear on the next level @ goes to, even if he goes up! */ + +void +losedogs(void) +{ + struct monst *mtmp; + + while ((mtmp = mydogs)) { + mydogs = mtmp->nmon; + mtmp->nmon = fmon; + fmon = mtmp; + mnexto(mtmp); + } + while ((mtmp = fallen_down)) { + fallen_down = mtmp->nmon; + mtmp->nmon = fmon; + fmon = mtmp; + rloc(mtmp); + } +} + +void +keepdogs(void) +{ + struct monst *mtmp; + + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) + if (dist(mtmp->mx, mtmp->my) < 3 && follower(mtmp) + && !mtmp->msleep && !mtmp->mfroz) { + relmon(mtmp); + mtmp->nmon = mydogs; + mydogs = mtmp; + unpmon(mtmp); + keepdogs(); /* we destroyed the link, so use recursion */ + return; /* (admittedly somewhat primitive) */ + } +} + +void +fall_down(struct monst *mtmp) +{ + relmon(mtmp); + mtmp->nmon = fallen_down; + fallen_down = mtmp; + unpmon(mtmp); + mtmp->mtame = 0; +} + +/* return quality of food; the lower the better */ +#define DOGFOOD 0 +#define CADAVER 1 +#define ACCFOOD 2 +#define MANFOOD 3 +#define APPORT 4 +#define POISON 5 +#define UNDEF 6 + +static xchar +dogfood(struct obj *obj) +{ + switch (obj->olet) { + case FOOD_SYM: + return ( + (obj->otyp == TRIPE_RATION) ? DOGFOOD : + (obj->otyp < CARROT) ? ACCFOOD : + (obj->otyp < CORPSE) ? MANFOOD : + (poisonous(obj) || obj->age + 50 <= moves || + obj->otyp == DEAD_COCKATRICE) + ? POISON : CADAVER + ); + default: + if (!obj->cursed) + return (APPORT); + /* fall into next case */ + case BALL_SYM: + case CHAIN_SYM: + case ROCK_SYM: + return (UNDEF); + } +} + +/* return 0 (no move), 1 (move) or 2 (dead) */ +int +dog_move(struct monst *mtmp, int after) +{ + int nx, ny, omx, omy, appr, nearer, j; + int udist, chi = 0, i, whappr; + struct monst *mtmp2; + struct permonst *mdat = mtmp->data; + struct edog *edog = EDOG(mtmp); + struct obj *obj; + struct trap *trap; + xchar cnt, chcnt, nix, niy; + schar dogroom, uroom; + xchar gx, gy, gtyp, otyp; /* current goal */ + coord poss[9]; + int info[9]; +#define GDIST(x, y) ((x - gx) * (x - gx) + (y - gy) * (y - gy)) +#define DDIST(x, y) ((x - omx) * (x - omx) + (y - omy) * (y - omy)) + + if (moves <= edog->eattime) /* dog is still eating */ + return (0); + omx = mtmp->mx; + omy = mtmp->my; + whappr = (moves - EDOG(mtmp)->whistletime < 5); + if (moves > edog->hungrytime + 500 && !mtmp->mconf) { + mtmp->mconf = 1; + mtmp->mhpmax /= 3; + if (mtmp->mhp > mtmp->mhpmax) + mtmp->mhp = mtmp->mhpmax; + if (cansee(omx, omy)) + pline("%s is confused from hunger.", Monnam(mtmp)); + else + pline("You feel worried about %s.", monnam(mtmp)); + } else if (moves > edog->hungrytime + 750 || mtmp->mhp < 1) { + if (cansee(omx, omy)) + pline("%s dies from hunger.", Monnam(mtmp)); + else + pline("You have a sad feeling for a moment, then it passes."); + mondied(mtmp); + return (2); + } + dogroom = inroom(omx, omy); + uroom = inroom(u.ux, u.uy); + udist = dist(omx, omy); + + /* maybe we tamed him while being swallowed --jgm */ + if (!udist) + return (0); + + /* if we are carrying sth then we drop it (perhaps near @) */ + /* Note: if apport == 1 then our behaviour is independent of udist */ + if (mtmp->minvent) { + if (!rn2(udist) || !rn2((int)edog->apport)) + if (rn2(10) < (int)edog->apport) { + relobj(mtmp, (int)mtmp->minvis); + if (edog->apport > 1) + edog->apport--; + edog->dropdist = udist; /* hpscdi!jon */ + edog->droptime = moves; + } + } else if ((obj = o_at(omx, omy))) { + if (!strchr("0_", obj->olet)) { + if ((otyp = dogfood(obj)) <= CADAVER) { + nix = omx; + niy = omy; + goto eatobj; + } + if (obj->owt < 10 * mtmp->data->mlevel) { + if (rn2(20) < (int)edog->apport + 3) { + if (rn2(udist) || + !rn2((int)edog->apport)) { + freeobj(obj); + unpobj(obj); + /* if (levl[omx][omy].scrsym == obj->olet) + * newsym(omx, omy); */ + mpickobj(mtmp, obj); + } + } + } + } + } + + /* first we look for food */ + gtyp = UNDEF; /* no goal as yet */ + gx = gy = 0; /* suppress 'used before set' message */ + for (obj = fobj; obj; obj = obj->nobj) { + otyp = dogfood(obj); + if (otyp > gtyp || otyp == UNDEF) + continue; + if (inroom(obj->ox, obj->oy) != dogroom) + continue; + if (otyp < MANFOOD && + (dogroom >= 0 || DDIST(obj->ox, obj->oy) < 10)) { + if (otyp < gtyp || (otyp == gtyp && + DDIST(obj->ox, obj->oy) < DDIST(gx, gy))) { + gx = obj->ox; + gy = obj->oy; + gtyp = otyp; + } + } else if (gtyp == UNDEF && dogroom >= 0 && + uroom == dogroom && + !mtmp->minvent && (int)edog->apport > rn2(8)) { + gx = obj->ox; + gy = obj->oy; + gtyp = APPORT; + } + } + if (gtyp == UNDEF || + (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)) { + if (dogroom < 0 || dogroom == uroom) { + gx = u.ux; + gy = u.uy; +#ifndef QUEST + } else { + int tmp = rooms[dogroom].fdoor; + cnt = rooms[dogroom].doorct; + + gx = gy = FAR; /* random, far away */ + while (cnt--) { + if (dist(gx, gy) > + dist(doors[tmp].x, doors[tmp].y)) { + gx = doors[tmp].x; + gy = doors[tmp].y; + } + tmp++; + } + /* here gx == FAR e.g. when dog is in a vault */ + if (gx == FAR || (gx == omx && gy == omy)) { + gx = u.ux; + gy = u.uy; + } +#endif /* QUEST */ + } + appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0; + if (after && udist <= 4 && gx == u.ux && gy == u.uy) + return (0); + if (udist > 1) { + if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) || + whappr || + (mtmp->minvent && rn2((int)edog->apport))) + appr = 1; + } + /* if you have dog food he'll follow you more closely */ + if (appr == 0) { + obj = invent; + while (obj) { + if (obj->otyp == TRIPE_RATION) { + appr = 1; + break; + } + obj = obj->nobj; + } + } + } else /* gtyp != UNDEF */ + appr = 1; + if (mtmp->mconf) + appr = 0; + + if (gx == u.ux && gy == u.uy && (dogroom != uroom || dogroom < 0)) { + coord *cp; + cp = gettrack(omx, omy); + if (cp) { + gx = cp->x; + gy = cp->y; + } + } + + nix = omx; + niy = omy; + cnt = mfndpos(mtmp, poss, info, ALLOW_M | ALLOW_TRAPS); + chcnt = 0; + chi = -1; + for (i = 0; i < cnt; i++) { + nx = poss[i].x; + ny = poss[i].y; + if (info[i] & ALLOW_M) { + mtmp2 = m_at(nx, ny); + if (mtmp2->data->mlevel >= mdat->mlevel + 2 || + mtmp2->data->mlet == 'c') + continue; + if (after) /* hit only once each move */ + return (0); + + if (hitmm(mtmp, mtmp2) == 1 && rn2(4) && + mtmp2->mlstmv != moves && + hitmm(mtmp2, mtmp) == 2) + return (2); + return (0); + } + + /* dog avoids traps */ + /* but perhaps we have to pass a trap in order to follow @ */ + if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx, ny))) { + if (!trap->tseen && rn2(40)) + continue; + if (rn2(10)) + continue; + } + + /* dog eschewes cursed objects */ + /* but likes dog food */ + obj = fobj; + while (obj) { + if (obj->ox != nx || obj->oy != ny) + goto nextobj; + if (obj->cursed) + goto nxti; + if (obj->olet == FOOD_SYM && + (otyp = dogfood(obj)) < MANFOOD && + (otyp < ACCFOOD || edog->hungrytime <= moves)) { + /* + * Note: our dog likes the food so much that + * he might eat it even when it conceals a + * cursed object + */ + nix = nx; + niy = ny; + chi = i; +eatobj: + edog->eattime = + moves + obj->quan * + objects[obj->otyp].oc_delay; + if (edog->hungrytime < moves) + edog->hungrytime = moves; + edog->hungrytime += + 5 * obj->quan * + objects[obj->otyp].nutrition; + mtmp->mconf = 0; + if (cansee(nix, niy)) + pline("%s ate %s.", Monnam( + mtmp), doname(obj)); + /* perhaps this was a reward */ + if (otyp != CADAVER) + edog->apport += 200 / + (edog->dropdist + + moves - edog->droptime); + delobj(obj); + goto newdogpos; + } +nextobj: + obj = obj->nobj; + } + + for (j = 0; j < MTSZ && j < cnt - 1; j++) + if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y) + if (rn2(4 * (cnt - j))) + goto nxti; + +/* Some stupid C compilers cannot compute the whole expression at once. */ + nearer = GDIST(nx, ny); + nearer -= GDIST(nix, niy); + nearer *= appr; + if ((nearer == 0 && !rn2(++chcnt)) || nearer < 0 || + (nearer > 0 && !whappr && + ((omx == nix && omy == niy && !rn2(3)) + || !rn2(12)) + )) { + nix = nx; + niy = ny; + if (nearer < 0) + chcnt = 0; + chi = i; + } +nxti:; + } +newdogpos: + if (nix != omx || niy != omy) { + if (info[chi] & ALLOW_U) { + hitu(mtmp, d(mdat->damn, mdat->damd) + 1); + return (0); + } + mtmp->mx = nix; + mtmp->my = niy; + for (j = MTSZ - 1; j > 0; j--) + mtmp->mtrack[j] = mtmp->mtrack[j - 1]; + mtmp->mtrack[0].x = omx; + mtmp->mtrack[0].y = omy; + } + if (mintrap(mtmp) == 2) /* he died */ + return (2); + pmon(mtmp); + return (1); +} + +/* return roomnumber or -1 */ +int +inroom(xchar x, xchar y) +{ +#ifndef QUEST + struct mkroom *croom = &rooms[0]; + + while (croom->hx >= 0) { + if (croom->hx >= x - 1 && croom->lx <= x + 1 && + croom->hy >= y - 1 && croom->ly <= y + 1) + return (croom - rooms); + croom++; + } +#endif /* QUEST */ + return (-1); /* not in room or on door */ +} + +bool +tamedog(struct monst *mtmp, struct obj *obj) +{ + struct monst *mtmp2; + + if (flags.moonphase == FULL_MOON && night() && rn2(6)) + return (0); + + /* If we cannot tame him, at least he's no longer afraid. */ + mtmp->mflee = 0; + mtmp->mfleetim = 0; + if (mtmp->mtame || mtmp->mfroz || +#ifndef NOWORM + mtmp->wormno || +#endif /* NOWORM */ + mtmp->isshk || mtmp->isgd || strchr(" &@12", mtmp->data->mlet)) + return (0); /* no tame long worms? */ + if (obj) { + if (dogfood(obj) >= MANFOOD) + return (0); + if (cansee(mtmp->mx, mtmp->my)) + pline("%s devours the %s.", Monnam(mtmp), + objects[obj->otyp].oc_name); + obfree(obj, NULL); + } + mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth); + *mtmp2 = *mtmp; + mtmp2->mxlth = sizeof(struct edog); + if (mtmp->mnamelth) + strcpy(NAME(mtmp2), NAME(mtmp)); + initedog(mtmp2); + replmon(mtmp, mtmp2); + return (1); +} |