This is dogmove.c in view mode; [Download] [Up]
/* SCCS Id: @(#)dogmove.c 3.0 88/04/15 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "mfndpos.h" #include "edog.h" #ifdef OVL0 static const char nofetch[] = { BALL_SYM, CHAIN_SYM, ROCK_SYM, 0 }; #endif /* OVL0 */ OSTATIC void FDECL(dog_eat, (struct monst *, struct obj *, XCHAR_P, int, int)); #ifdef OVLB XSTATIC void dog_eat(mtmp, obj, otyp, x, y) register struct monst *mtmp; register struct obj * obj; xchar otyp; int x, y; { register struct edog *edog = EDOG(mtmp); int nutrit; if(edog->hungrytime < moves) edog->hungrytime = moves; /* Note: to get the correct percentage-eaten in case oeaten is set, * use "obj->owt / obj->quan / base-weight". It so happens that here * we want to multiply by obj->quan, which thus cancels out. * It is arbitrary that the pet takes the same length of time to eat * as a human, but gets 5X as much nutrition. */ if(obj->otyp == CORPSE) { mtmp->meating = 3 + (mons[obj->corpsenm].cwt >> 2); nutrit = 5 * mons[obj->corpsenm].cnutrit; } else { mtmp->meating = objects[obj->otyp].oc_delay; nutrit = 5 * objects[obj->otyp].nutrition; } if(obj->oeaten) { mtmp->meating = eaten_stat(mtmp->meating, obj); nutrit = eaten_stat(nutrit, obj); } edog->hungrytime += nutrit; mtmp->mconf = 0; if (mtmp->mtame < 20) mtmp->mtame++; if(cansee(x,y)) pline("%s eats %s.", Monnam(mtmp), doname(obj)); /* perhaps this was a reward */ if(otyp != CADAVER) #ifdef LINT edog->apport = 0; #else edog->apport += (unsigned)(200L/ ((long)edog->dropdist+moves-edog->droptime)); #endif delobj(obj); } #endif /* OVLB */ #ifdef OVL0 /* return 0 (no move), 1 (move) or 2 (dead) */ int dog_move(mtmp, after) register struct monst *mtmp; register int after; { register int nx,ny,omx,omy,appr,nearer,j; int udist,chi,i,whappr; /* XLINT register struct permonst *mdat = mtmp->data; */ register 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]; long info[9]; long allowflags; #define GDIST(x,y) (dist2(x,y,gx,gy)) #define DDIST(x,y) (dist2(x,y,omx,omy)) #ifdef __GNULINT__ chi = -1; /* gcc warning from 'goto newdogpos' */ #endif omx = mtmp->mx; omy = mtmp->my; whappr = (moves - edog->whistletime < 5); if(moves > edog->hungrytime + 500) { if(!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) { edog->hungrytime = moves + 500; /* but not too high; it might polymorph */ } else if (!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 You("feel worried about %s.", mon_nam(mtmp)); } else if(moves > edog->hungrytime + 750 || mtmp->mhp < 1) { #ifdef WALKIES if(mtmp->mleashed) Your("leash goes slack."); #endif if(cansee(omx,omy)) pline("%s dies%s.", Monnam(mtmp), (mtmp->mhp >= 1) ? "" : " from hunger"); else 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) < edog->apport){ if (cansee(omx,omy) && flags.verbose) pline("%s drops %s.", Monnam(mtmp), distant_name(mtmp->minvent, doname)); relobj(mtmp, (int) mtmp->minvis); if(edog->apport > 1) edog->apport--; edog->dropdist = udist; /* hpscdi!jon */ edog->droptime = moves; } } else { if((obj=level.objects[omx][omy]) && !index(nofetch,obj->olet)){ if((otyp = dogfood(mtmp, obj)) <= CADAVER){ nix = omx; niy = omy; dog_eat(mtmp, obj, otyp, nix, niy); goto newdogpos; } if(can_carry(mtmp, obj)) if(!obj->cursed) if(rn2(20) < edog->apport+3) if(rn2(udist) || !rn2((int) edog->apport)){ if (cansee(omx, omy) && flags.verbose) pline("%s picks up %s.", Monnam(mtmp), distant_name(obj, doname)); freeobj(obj); unpobj(obj); /* if(levl[omx][omy].scrsym == obj->olet) newsym(omx,omy); */ mpickobj(mtmp,obj); } } } gtyp = UNDEF; /* no goal as yet */ gx = gy = 0; /* suppress 'used before set' message */ #ifdef WALKIES /* If he's on a leash, he's not going anywhere. */ if(mtmp->mleashed) { gtyp = APPORT; gx = u.ux; gy = u.uy; } else #endif /* first we look for food, then objects */ for(obj = fobj; obj; obj = obj->nobj) { otyp = dogfood(mtmp, 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 && edog->apport > rn2(8) && can_carry(mtmp,obj)){ 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; } 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; } } 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 it'll follow you more closely */ if(appr == 0){ obj = invent; while(obj){ if(dogfood(mtmp, obj) == DOGFOOD) { appr = 1; break; } obj = obj->nobj; } } } else appr = 1; /* gtyp != UNDEF */ if(mtmp->mconf) appr = 0; if(gx == u.ux && gy == u.uy && (dogroom != uroom || dogroom < 0)) { register coord *cp; cp = gettrack(omx,omy); if(cp){ gx = cp->x; gy = cp->y; } } nix = omx; niy = omy; allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT; if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK|ALLOW_WALL); if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK; if (!nohands(mtmp->data) && !verysmall(mtmp->data)) { allowflags |= OPENDOOR; if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR; } if (is_giant(mtmp->data)) allowflags |= BUSTDOOR; if (tunnels(mtmp->data) && !needspick(mtmp->data)) allowflags |= ALLOW_DIG; cnt = mfndpos(mtmp, poss, info, allowflags); if (allowflags & ALLOW_DIG) if(!mdig_tunnel(mtmp)) return(2); chcnt = 0; chi = -1; for(i=0; i<cnt; i++){ nx = poss[i].x; ny = poss[i].y; #ifdef WALKIES /* if leashed, we drag him along. */ if(dist(nx, ny) > 4 && mtmp->mleashed) continue; #endif if(info[i] & ALLOW_M) { if(MON_AT(nx, ny)) { int stat; register struct monst *mtmp2 = m_at(nx,ny); if(mtmp2->m_lev >= mtmp->m_lev+2 || (mtmp2->data->mlet == S_COCKATRICE && !resists_ston(mtmp->data))) continue; if(after) return(0); /* hit only once each move */ if((stat = mattackm(mtmp, mtmp2)) == 1 && rn2(4) && mtmp2->mlstmv != moves && mattackm(mtmp2, mtmp) == 2) return(2); if(stat == -1) 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))){ #ifdef WALKIES if(!mtmp->mleashed) { #endif if(!trap->tseen && rn2(40)) continue; if(rn2(10)) continue; #ifdef WALKIES } # ifdef SOUNDS else if(flags.soundok) whimper(mtmp); # endif #endif } /* dog eschews cursed objects */ /* but likes dog food */ for(obj = level.objects[nx][ny]; obj; obj = obj->nexthere) { if(obj->cursed && !mtmp->mleashed) goto nxti; if(obj->olet == FOOD_SYM && (otyp = dogfood(mtmp, 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; dog_eat(mtmp, obj, otyp, nix, niy); goto newdogpos; } } 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; nearer = (GDIST(nx,ny) - GDIST(nix,niy)) * 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) { #ifdef WALKIES if(mtmp->mleashed) { /* play it safe */ pline("%s breaks loose of %s leash!", is_female(mtmp) ? "her" : is_human(mtmp->data) ? "his" : "its", Monnam(mtmp)); m_unleash(mtmp); } #endif (void) mattacku(mtmp); return(0); } remove_monster(omx, omy); place_monster(mtmp, nix, 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; } #ifdef WALKIES /* an incredible kluge, but the only way to keep pooch near * after he spends time eating or in a trap, etc... */ else if(mtmp->mleashed && dist(omx, omy) > 4) { coord cc; nx = sgn(omx - u.ux); ny = sgn(omy - u.uy); if(goodpos((cc.x = u.ux+nx), (cc.y = u.uy+ny), mtmp->data)) goto dognext; i = xytod(nx, ny); for(j = (i + 7)%8; j < (i + 1)%8; j++) { dtoxy(&cc, j); if(goodpos(cc.x, cc.y, mtmp->data)) goto dognext; } for(j = (i + 6)%8; j < (i + 2)%8; j++) { dtoxy(&cc, j); if(goodpos(cc.x, cc.y, mtmp->data)) goto dognext; } cc.x = mtmp->mx; cc.y = mtmp->my; dognext: remove_monster(mtmp->mx, mtmp->my); place_monster(mtmp, cc.x, cc.y); pmon(mtmp); set_apparxy(mtmp); } #endif return(1); } #endif /* OVL0 */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.