|
|
1.1 ! root 1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ ! 2: /* hack.dog.c - version 1.0.3 */ ! 3: ! 4: #include "hack.h" ! 5: #include "hack.mfndpos.h" ! 6: extern struct monst *makemon(); ! 7: #include "def.edog.h" ! 8: #include "def.mkroom.h" ! 9: ! 10: struct permonst li_dog = ! 11: { "little dog", 'd',2,18,6,1,6,sizeof(struct edog) }; ! 12: struct permonst dog = ! 13: { "dog", 'd',4,16,5,1,6,sizeof(struct edog) }; ! 14: struct permonst la_dog = ! 15: { "large dog", 'd',6,15,4,2,4,sizeof(struct edog) }; ! 16: ! 17: ! 18: makedog(){ ! 19: register struct monst *mtmp = makemon(&li_dog,u.ux,u.uy); ! 20: if(!mtmp) return; /* dogs were genocided */ ! 21: initedog(mtmp); ! 22: } ! 23: ! 24: initedog(mtmp) register struct monst *mtmp; { ! 25: mtmp->mtame = mtmp->mpeaceful = 1; ! 26: EDOG(mtmp)->hungrytime = 1000 + moves; ! 27: EDOG(mtmp)->eattime = 0; ! 28: EDOG(mtmp)->droptime = 0; ! 29: EDOG(mtmp)->dropdist = 10000; ! 30: EDOG(mtmp)->apport = 10; ! 31: EDOG(mtmp)->whistletime = 0; ! 32: } ! 33: ! 34: /* attach the monsters that went down (or up) together with @ */ ! 35: struct monst *mydogs = 0; ! 36: struct monst *fallen_down = 0; /* monsters that fell through a trapdoor */ ! 37: /* they will appear on the next level @ goes to, even if he goes up! */ ! 38: ! 39: losedogs(){ ! 40: register struct monst *mtmp; ! 41: while(mtmp = mydogs){ ! 42: mydogs = mtmp->nmon; ! 43: mtmp->nmon = fmon; ! 44: fmon = mtmp; ! 45: mnexto(mtmp); ! 46: } ! 47: while(mtmp = fallen_down){ ! 48: fallen_down = mtmp->nmon; ! 49: mtmp->nmon = fmon; ! 50: fmon = mtmp; ! 51: rloc(mtmp); ! 52: } ! 53: } ! 54: ! 55: keepdogs(){ ! 56: register struct monst *mtmp; ! 57: for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) ! 58: if(dist(mtmp->mx,mtmp->my) < 3 && follower(mtmp) ! 59: && !mtmp->msleep && !mtmp->mfroz) { ! 60: relmon(mtmp); ! 61: mtmp->nmon = mydogs; ! 62: mydogs = mtmp; ! 63: unpmon(mtmp); ! 64: keepdogs(); /* we destroyed the link, so use recursion */ ! 65: return; /* (admittedly somewhat primitive) */ ! 66: } ! 67: } ! 68: ! 69: fall_down(mtmp) register struct monst *mtmp; { ! 70: relmon(mtmp); ! 71: mtmp->nmon = fallen_down; ! 72: fallen_down = mtmp; ! 73: unpmon(mtmp); ! 74: mtmp->mtame = 0; ! 75: } ! 76: ! 77: /* return quality of food; the lower the better */ ! 78: #define DOGFOOD 0 ! 79: #define CADAVER 1 ! 80: #define ACCFOOD 2 ! 81: #define MANFOOD 3 ! 82: #define APPORT 4 ! 83: #define POISON 5 ! 84: #define UNDEF 6 ! 85: dogfood(obj) register struct obj *obj; { ! 86: switch(obj->olet) { ! 87: case FOOD_SYM: ! 88: return( ! 89: (obj->otyp == TRIPE_RATION) ? DOGFOOD : ! 90: (obj->otyp < CARROT) ? ACCFOOD : ! 91: (obj->otyp < CORPSE) ? MANFOOD : ! 92: (poisonous(obj) || obj->age + 50 <= moves || ! 93: obj->otyp == DEAD_COCKATRICE) ! 94: ? POISON : CADAVER ! 95: ); ! 96: default: ! 97: if(!obj->cursed) return(APPORT); ! 98: /* fall into next case */ ! 99: case BALL_SYM: ! 100: case CHAIN_SYM: ! 101: case ROCK_SYM: ! 102: return(UNDEF); ! 103: } ! 104: } ! 105: ! 106: /* return 0 (no move), 1 (move) or 2 (dead) */ ! 107: dog_move(mtmp, after) register struct monst *mtmp; { ! 108: register int nx,ny,omx,omy,appr,nearer,j; ! 109: int udist,chi,i,whappr; ! 110: register struct monst *mtmp2; ! 111: register struct permonst *mdat = mtmp->data; ! 112: register struct edog *edog = EDOG(mtmp); ! 113: struct obj *obj; ! 114: struct trap *trap; ! 115: xchar cnt,chcnt,nix,niy; ! 116: schar dogroom,uroom; ! 117: xchar gx,gy,gtyp,otyp; /* current goal */ ! 118: coord poss[9]; ! 119: int info[9]; ! 120: #define GDIST(x,y) ((x-gx)*(x-gx) + (y-gy)*(y-gy)) ! 121: #define DDIST(x,y) ((x-omx)*(x-omx) + (y-omy)*(y-omy)) ! 122: ! 123: if(moves <= edog->eattime) return(0); /* dog is still eating */ ! 124: omx = mtmp->mx; ! 125: omy = mtmp->my; ! 126: whappr = (moves - EDOG(mtmp)->whistletime < 5); ! 127: if(moves > edog->hungrytime + 500 && !mtmp->mconf){ ! 128: mtmp->mconf = 1; ! 129: mtmp->mhpmax /= 3; ! 130: if(mtmp->mhp > mtmp->mhpmax) ! 131: mtmp->mhp = mtmp->mhpmax; ! 132: if(cansee(omx,omy)) ! 133: pline("%s is confused from hunger.", Monnam(mtmp)); ! 134: else pline("You feel worried about %s.", monnam(mtmp)); ! 135: } else ! 136: if(moves > edog->hungrytime + 750 || mtmp->mhp < 1){ ! 137: if(cansee(omx,omy)) ! 138: pline("%s dies from hunger.", Monnam(mtmp)); ! 139: else ! 140: pline("You have a sad feeling for a moment, then it passes."); ! 141: mondied(mtmp); ! 142: return(2); ! 143: } ! 144: dogroom = inroom(omx,omy); ! 145: uroom = inroom(u.ux,u.uy); ! 146: udist = dist(omx,omy); ! 147: ! 148: /* maybe we tamed him while being swallowed --jgm */ ! 149: if(!udist) return(0); ! 150: ! 151: /* if we are carrying sth then we drop it (perhaps near @) */ ! 152: /* Note: if apport == 1 then our behaviour is independent of udist */ ! 153: if(mtmp->minvent){ ! 154: if(!rn2(udist) || !rn2((int) edog->apport)) ! 155: if(rn2(10) < edog->apport){ ! 156: relobj(mtmp, (int) mtmp->minvis); ! 157: if(edog->apport > 1) edog->apport--; ! 158: edog->dropdist = udist; /* hpscdi!jon */ ! 159: edog->droptime = moves; ! 160: } ! 161: } else { ! 162: if(obj = o_at(omx,omy)) if(!index("0_", obj->olet)){ ! 163: if((otyp = dogfood(obj)) <= CADAVER){ ! 164: nix = omx; ! 165: niy = omy; ! 166: goto eatobj; ! 167: } ! 168: if(obj->owt < 10*mtmp->data->mlevel) ! 169: if(rn2(20) < edog->apport+3) ! 170: if(rn2(udist) || !rn2((int) edog->apport)){ ! 171: freeobj(obj); ! 172: unpobj(obj); ! 173: /* if(levl[omx][omy].scrsym == obj->olet) ! 174: newsym(omx,omy); */ ! 175: mpickobj(mtmp,obj); ! 176: } ! 177: } ! 178: } ! 179: ! 180: /* first we look for food */ ! 181: gtyp = UNDEF; /* no goal as yet */ ! 182: #ifdef LINT ! 183: gx = gy = 0; /* suppress 'used before set' message */ ! 184: #endif LINT ! 185: for(obj = fobj; obj; obj = obj->nobj) { ! 186: otyp = dogfood(obj); ! 187: if(otyp > gtyp || otyp == UNDEF) continue; ! 188: if(inroom(obj->ox,obj->oy) != dogroom) continue; ! 189: if(otyp < MANFOOD && ! 190: (dogroom >= 0 || DDIST(obj->ox,obj->oy) < 10)) { ! 191: if(otyp < gtyp || (otyp == gtyp && ! 192: DDIST(obj->ox,obj->oy) < DDIST(gx,gy))){ ! 193: gx = obj->ox; ! 194: gy = obj->oy; ! 195: gtyp = otyp; ! 196: } ! 197: } else ! 198: if(gtyp == UNDEF && dogroom >= 0 && ! 199: uroom == dogroom && ! 200: !mtmp->minvent && edog->apport > rn2(8)){ ! 201: gx = obj->ox; ! 202: gy = obj->oy; ! 203: gtyp = APPORT; ! 204: } ! 205: } ! 206: if(gtyp == UNDEF || ! 207: (gtyp != DOGFOOD && gtyp != APPORT && moves < edog->hungrytime)){ ! 208: if(dogroom < 0 || dogroom == uroom){ ! 209: gx = u.ux; ! 210: gy = u.uy; ! 211: #ifndef QUEST ! 212: } else { ! 213: int tmp = rooms[dogroom].fdoor; ! 214: cnt = rooms[dogroom].doorct; ! 215: ! 216: gx = gy = FAR; /* random, far away */ ! 217: while(cnt--){ ! 218: if(dist(gx,gy) > ! 219: dist(doors[tmp].x, doors[tmp].y)){ ! 220: gx = doors[tmp].x; ! 221: gy = doors[tmp].y; ! 222: } ! 223: tmp++; ! 224: } ! 225: /* here gx == FAR e.g. when dog is in a vault */ ! 226: if(gx == FAR || (gx == omx && gy == omy)){ ! 227: gx = u.ux; ! 228: gy = u.uy; ! 229: } ! 230: #endif QUEST ! 231: } ! 232: appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0; ! 233: if(after && udist <= 4 && gx == u.ux && gy == u.uy) ! 234: return(0); ! 235: if(udist > 1){ ! 236: if(!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) || ! 237: whappr || ! 238: (mtmp->minvent && rn2((int) edog->apport))) ! 239: appr = 1; ! 240: } ! 241: /* if you have dog food he'll follow you more closely */ ! 242: if(appr == 0){ ! 243: obj = invent; ! 244: while(obj){ ! 245: if(obj->otyp == TRIPE_RATION){ ! 246: appr = 1; ! 247: break; ! 248: } ! 249: obj = obj->nobj; ! 250: } ! 251: } ! 252: } else appr = 1; /* gtyp != UNDEF */ ! 253: if(mtmp->mconf) appr = 0; ! 254: ! 255: if(gx == u.ux && gy == u.uy && (dogroom != uroom || dogroom < 0)){ ! 256: extern coord *gettrack(); ! 257: register coord *cp; ! 258: cp = gettrack(omx,omy); ! 259: if(cp){ ! 260: gx = cp->x; ! 261: gy = cp->y; ! 262: } ! 263: } ! 264: ! 265: nix = omx; ! 266: niy = omy; ! 267: cnt = mfndpos(mtmp,poss,info,ALLOW_M | ALLOW_TRAPS); ! 268: chcnt = 0; ! 269: chi = -1; ! 270: for(i=0; i<cnt; i++){ ! 271: nx = poss[i].x; ! 272: ny = poss[i].y; ! 273: if(info[i] & ALLOW_M){ ! 274: mtmp2 = m_at(nx,ny); ! 275: if(mtmp2->data->mlevel >= mdat->mlevel+2 || ! 276: mtmp2->data->mlet == 'c') ! 277: continue; ! 278: if(after) return(0); /* hit only once each move */ ! 279: ! 280: if(hitmm(mtmp, mtmp2) == 1 && rn2(4) && ! 281: mtmp2->mlstmv != moves && ! 282: hitmm(mtmp2,mtmp) == 2) return(2); ! 283: return(0); ! 284: } ! 285: ! 286: /* dog avoids traps */ ! 287: /* but perhaps we have to pass a trap in order to follow @ */ ! 288: if((info[i] & ALLOW_TRAPS) && (trap = t_at(nx,ny))){ ! 289: if(!trap->tseen && rn2(40)) continue; ! 290: if(rn2(10)) continue; ! 291: } ! 292: ! 293: /* dog eschewes cursed objects */ ! 294: /* but likes dog food */ ! 295: obj = fobj; ! 296: while(obj){ ! 297: if(obj->ox != nx || obj->oy != ny) ! 298: goto nextobj; ! 299: if(obj->cursed) goto nxti; ! 300: if(obj->olet == FOOD_SYM && ! 301: (otyp = dogfood(obj)) < MANFOOD && ! 302: (otyp < ACCFOOD || edog->hungrytime <= moves)){ ! 303: /* Note: our dog likes the food so much that he ! 304: might eat it even when it conceals a cursed object */ ! 305: nix = nx; ! 306: niy = ny; ! 307: chi = i; ! 308: eatobj: ! 309: edog->eattime = ! 310: moves + obj->quan * objects[obj->otyp].oc_delay; ! 311: if(edog->hungrytime < moves) ! 312: edog->hungrytime = moves; ! 313: edog->hungrytime += ! 314: 5*obj->quan * objects[obj->otyp].nutrition; ! 315: mtmp->mconf = 0; ! 316: if(cansee(nix,niy)) ! 317: pline("%s ate %s.", Monnam(mtmp), doname(obj)); ! 318: /* perhaps this was a reward */ ! 319: if(otyp != CADAVER) ! 320: edog->apport += 200/(edog->dropdist+moves-edog->droptime); ! 321: delobj(obj); ! 322: goto newdogpos; ! 323: } ! 324: nextobj: ! 325: obj = obj->nobj; ! 326: } ! 327: ! 328: for(j=0; j<MTSZ && j<cnt-1; j++) ! 329: if(nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y) ! 330: if(rn2(4*(cnt-j))) goto nxti; ! 331: ! 332: /* Some stupid C compilers cannot compute the whole expression at once. */ ! 333: nearer = GDIST(nx,ny); ! 334: nearer -= GDIST(nix,niy); ! 335: nearer *= appr; ! 336: if((nearer == 0 && !rn2(++chcnt)) || nearer<0 || ! 337: (nearer > 0 && !whappr && ! 338: ((omx == nix && omy == niy && !rn2(3)) ! 339: || !rn2(12)) ! 340: )){ ! 341: nix = nx; ! 342: niy = ny; ! 343: if(nearer < 0) chcnt = 0; ! 344: chi = i; ! 345: } ! 346: nxti: ; ! 347: } ! 348: newdogpos: ! 349: if(nix != omx || niy != omy){ ! 350: if(info[chi] & ALLOW_U){ ! 351: (void) hitu(mtmp, d(mdat->damn, mdat->damd)+1); ! 352: return(0); ! 353: } ! 354: mtmp->mx = nix; ! 355: mtmp->my = niy; ! 356: for(j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1]; ! 357: mtmp->mtrack[0].x = omx; ! 358: mtmp->mtrack[0].y = omy; ! 359: } ! 360: if(mintrap(mtmp) == 2) /* he died */ ! 361: return(2); ! 362: pmon(mtmp); ! 363: return(1); ! 364: } ! 365: ! 366: /* return roomnumber or -1 */ ! 367: inroom(x,y) xchar x,y; { ! 368: #ifndef QUEST ! 369: register struct mkroom *croom = &rooms[0]; ! 370: while(croom->hx >= 0){ ! 371: if(croom->hx >= x-1 && croom->lx <= x+1 && ! 372: croom->hy >= y-1 && croom->ly <= y+1) ! 373: return(croom - rooms); ! 374: croom++; ! 375: } ! 376: #endif QUEST ! 377: return(-1); /* not in room or on door */ ! 378: } ! 379: ! 380: tamedog(mtmp, obj) ! 381: register struct monst *mtmp; ! 382: register struct obj *obj; ! 383: { ! 384: register struct monst *mtmp2; ! 385: ! 386: if(flags.moonphase == FULL_MOON && night() && rn2(6)) ! 387: return(0); ! 388: ! 389: /* If we cannot tame him, at least he's no longer afraid. */ ! 390: mtmp->mflee = 0; ! 391: mtmp->mfleetim = 0; ! 392: if(mtmp->mtame || mtmp->mfroz || ! 393: #ifndef NOWORM ! 394: mtmp->wormno || ! 395: #endif NOWORM ! 396: mtmp->isshk || mtmp->isgd || index(" &@12", mtmp->data->mlet)) ! 397: return(0); /* no tame long worms? */ ! 398: if(obj) { ! 399: if(dogfood(obj) >= MANFOOD) return(0); ! 400: if(cansee(mtmp->mx,mtmp->my)){ ! 401: pline("%s devours the %s.", Monnam(mtmp), ! 402: objects[obj->otyp].oc_name); ! 403: } ! 404: obfree(obj, (struct obj *) 0); ! 405: } ! 406: mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth); ! 407: *mtmp2 = *mtmp; ! 408: mtmp2->mxlth = sizeof(struct edog); ! 409: if(mtmp->mnamelth) (void) strcpy(NAME(mtmp2), NAME(mtmp)); ! 410: initedog(mtmp2); ! 411: replmon(mtmp,mtmp2); ! 412: return(1); ! 413: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.