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: }

Defined functions

dog_move defined in line 107; used 1 times
dogfood defined in line 85; used 4 times
initedog defined in line 24; used 2 times
keepdogs defined in line 55; used 3 times
losedogs defined in line 39; used 1 times
makedog defined in line 18; used 1 times
tamedog defined in line 380; used 2 times

Defined variables

dog defined in line 12; used 2 times
la_dog defined in line 14; used 1 times
li_dog defined in line 10; used 2 times
mydogs defined in line 35; used 4 times

Defined macros

ACCFOOD defined in line 80; used 2 times
APPORT defined in line 82; used 3 times
CADAVER defined in line 79; used 3 times
DDIST defined in line 121; used 3 times
DOGFOOD defined in line 78; used 2 times
GDIST defined in line 120; used 2 times
MANFOOD defined in line 81; used 4 times
POISON defined in line 83; used 1 times
  • in line 94
UNDEF defined in line 84; used 5 times
Last modified: 1985-10-01
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3749
Valid CSS Valid XHTML 1.0 Strict