void ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b) { int i, j; unsigned int dmin[256], dmax; int r0, g0, b0; int r1, g1, b1; int rc, gc, bc; unsigned int d[BOXVOLUME]; UINT8 c[BOXVOLUME]; /* Get box boundaries for the given (r,g,b)-triplet. Each box covers eight cache slots (32 colour values, that is). */ r0 = r & 0xe0; r1 = r0 + 0x1f; rc = (r0 + r1) / 2; g0 = g & 0xe0; g1 = g0 + 0x1f; gc = (g0 + g1) / 2; b0 = b & 0xe0; b1 = b0 + 0x1f; bc = (b0 + b1) / 2; /* Step 1 -- Select relevant palette entries (after Heckbert) */ /* For each palette entry, calculate the min and max distances to * any position in the box given by the colour we're looking for. */ dmax = (unsigned int) ~0; for (i = 0; i < 256; i++) { int r, g, b; unsigned int tmin, tmax; /* Find min and max distances to any point in the box */ r = palette->palette[i*4+0]; tmin = (r < r0) ? RDIST(r, r1) : (r > r1) ? RDIST(r, r0) : 0; tmax = (r <= rc) ? RDIST(r, r1) : RDIST(r, r0); g = palette->palette[i*4+1]; tmin += (g < g0) ? GDIST(g, g1) : (g > g1) ? GDIST(g, g0) : 0; tmax += (g <= gc) ? GDIST(g, g1) : GDIST(g, g0); b = palette->palette[i*4+2]; tmin += (b < b0) ? BDIST(b, b1) : (b > b1) ? BDIST(b, b0) : 0; tmax += (b <= bc) ? BDIST(b, b1) : BDIST(b, b0); dmin[i] = tmin; if (tmax < dmax) dmax = tmax; /* keep the smallest max distance only */ } /* Step 2 -- Incrementally update cache slot (after Thomas) */ /* Find the box containing the nearest palette entry, and update * all slots in that box. We only check boxes for which the min * distance is less than or equal the smallest max distance */ for (i = 0; i < BOXVOLUME; i++) d[i] = (unsigned int) ~0; for (i = 0; i < 256; i++) if (dmin[i] <= dmax) { int rd, gd, bd; int ri, gi, bi; int rx, gx, bx; ri = (r0 - palette->palette[i*4+0]) * RSCALE; gi = (g0 - palette->palette[i*4+1]) * GSCALE; bi = (b0 - palette->palette[i*4+2]) * BSCALE; rd = ri*ri + gi*gi + bi*bi; ri = ri * (2 * RSTEP) + RSTEP * RSTEP; gi = gi * (2 * GSTEP) + GSTEP * GSTEP; bi = bi * (2 * BSTEP) + BSTEP * BSTEP; rx = ri; for (r = j = 0; r < BOX; r++) { gd = rd; gx = gi; for (g = 0; g < BOX; g++) { bd = gd; bx = bi; for (b = 0; b < BOX; b++) { if ((unsigned int) bd < d[j]) { d[j] = bd; c[j] = (UINT8) i; } bd += bx; bx += 2 * BSTEP * BSTEP; j++; } gd += gx; gx += 2 * GSTEP * GSTEP; } rd += rx; rx += 2 * RSTEP * RSTEP; } } /* Step 3 -- Update cache */ /* The c array now contains the closest match for each * cache slot in the box. Update the cache. */ j = 0; for (r = r0; r < r1; r+=4) for (g = g0; g < g1; g+=4) for (b = b0; b < b1; b+=4) ImagingPaletteCache(palette, r, g, b) = c[j++]; }
/* 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, 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) return(0); /* dog is still eating */ 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) < 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) < 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; 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 && 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[(int)dogroom].fdoor; cnt = rooms[(int)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[(int)u.ux][(int)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 appr = 1; /* gtyp != UNDEF */ 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) return(0); /* hit only once each move */ 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){ (void) 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); }
/* * shk_move: return 1: he moved 0: he didnt -1: let m_move do it */ int shk_move(struct monst *shkp) { struct monst *mtmp; struct permonst *mdat = shkp->data; xchar gx, gy, omx, omy, nx, ny, nix, niy; schar appr, i; int udist; int z; schar shkroom, chi, chcnt, cnt; boolean uondoor = 0, satdoor, avoid = 0, badinv; coord poss[9]; int info[9]; struct obj *ib = NULL; omx = shkp->mx; omy = shkp->my; if ((udist = dist(omx, omy)) < 3) { if (ANGRY(shkp)) { hitu(shkp, d(mdat->damn, mdat->damd) + 1); return (0); } if (ESHK(shkp)->following) { if (strncmp(ESHK(shkp)->customer, plname, PL_NSIZ)) { pline("Hello %s! I was looking for %s.", plname, ESHK(shkp)->customer); ESHK(shkp)->following = 0; return (0); } if (!ESHK(shkp)->robbed) { /* impossible? */ ESHK(shkp)->following = 0; return (0); } if (moves > followmsg + 4) { pline("Hello %s! Didn't you forget to pay?", plname); followmsg = moves; } if (udist < 2) return (0); } } shkroom = inroom(omx, omy); appr = 1; gx = ESHK(shkp)->shk.x; gy = ESHK(shkp)->shk.y; satdoor = (gx == omx && gy == omy); if (ESHK(shkp)->following || ((z = holetime()) >= 0 && z * z <= udist)) { gx = u.ux; gy = u.uy; if (shkroom < 0 || shkroom != inroom(u.ux, u.uy)) if (udist > 4) return (-1); /* leave it to m_move */ } else if (ANGRY(shkp)) { long saveBlind = Blind; Blind = 0; if (shkp->mcansee && !Invis && cansee(omx, omy)) { gx = u.ux; gy = u.uy; } Blind = saveBlind; avoid = FALSE; } else { #define GDIST(x, y) ((x - gx) * (x - gx) + (y - gy) * (y - gy)) if (Invis) avoid = FALSE; else { uondoor = (u.ux == ESHK(shkp)->shd.x && u.uy == ESHK(shkp)->shd.y); if (uondoor) { if (ESHK(shkp)->billct) pline("Hello %s! Will you please pay before leaving?", plname); badinv = (carrying(PICK_AXE) || carrying(ICE_BOX)); if (satdoor && badinv) return (0); avoid = !badinv; } else { avoid = (u.uinshop && dist(gx, gy) > 8); badinv = FALSE; } if (((!ESHK(shkp)->robbed && !ESHK(shkp)->billct) || avoid) && GDIST(omx, omy) < 3) { if (!badinv && !online(omx, omy)) return (0); if (satdoor) appr = gx = gy = 0; } } } if (omx == gx && omy == gy) return (0); if (shkp->mconf) { avoid = FALSE; appr = 0; } nix = omx; niy = omy; cnt = mfndpos(shkp, poss, info, ALLOW_SSM); if (avoid && uondoor) { /* perhaps we cannot avoid him */ for (i = 0; i < cnt; i++) if (!(info[i] & NOTONL)) goto notonl_ok; avoid = FALSE; notonl_ok: ; } chi = -1; chcnt = 0; for (i = 0; i < cnt; i++) { nx = poss[i].x; ny = poss[i].y; if (levl[nx][ny].typ == ROOM || shkroom != ESHK(shkp)->shoproom || ESHK(shkp)->following) { #ifdef STUPID /* cater for stupid compilers */ int zz; #endif /* STUPID */ if (uondoor && (ib = sobj_at(ICE_BOX, nx, ny))) { nix = nx; niy = ny; chi = i; break; } if (avoid && (info[i] & NOTONL)) continue; if ((!appr && !rn2(++chcnt)) || #ifdef STUPID (appr && (zz = GDIST(nix, niy)) && zz > GDIST(nx, ny)) #else (appr && GDIST(nx, ny) < GDIST(nix, niy)) #endif /* STUPID */ ) { nix = nx; niy = ny; chi = i; } } } if (nix != omx || niy != omy) { if (info[chi] & ALLOW_M) { mtmp = m_at(nix, niy); if (hitmm(shkp, mtmp) == 1 && rn2(3) && hitmm(mtmp, shkp) == 2) return (2); return (0); } else if (info[chi] & ALLOW_U) { hitu(shkp, d(mdat->damn, mdat->damd) + 1); return (0); } shkp->mx = nix; shkp->my = niy; pmon(shkp); if (ib) { freeobj(ib); mpickobj(shkp, ib); } return (1); } return (0); }
/* * Move for priests and shopkeepers. Called from shk_move() and pri_move(). * Valid returns are 1: moved 0: didn't -1: let m_move do it -2: died. */ int move_special(struct monst *mtmp, boolean in_his_shop, schar appr, boolean uondoor, boolean avoid, xchar omx, xchar omy, xchar gx, xchar gy) { xchar nx, ny, nix, niy; schar i; schar chcnt, cnt; coord poss[9]; long info[9]; long allowflags; struct obj *ib = NULL; if (omx == gx && omy == gy) return 0; if (mtmp->mconf) { avoid = FALSE; appr = 0; } nix = omx; niy = omy; if (mtmp->isshk) allowflags = ALLOW_SSM; else allowflags = ALLOW_SSM | ALLOW_SANCT; if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK | ALLOW_WALL); if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK; if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG; if (!nohands(mtmp->data) && !verysmall(mtmp->data)) { allowflags |= OPENDOOR; if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR; } if (is_giant(mtmp->data)) allowflags |= BUSTDOOR; cnt = mfndpos(mtmp, poss, info, allowflags); if (mtmp->isshk && avoid && uondoor) { /* perhaps we cannot avoid him */ for (i = 0; i < cnt; i++) if (!(info[i] & NOTONL)) goto pick_move; avoid = FALSE; } #define GDIST(x,y) (dist2(x,y,gx,gy)) pick_move: chcnt = 0; for (i = 0; i < cnt; i++) { nx = poss[i].x; ny = poss[i].y; if (IS_ROOM(level->locations[nx][ny].typ) || (mtmp->isshk && (!in_his_shop || ESHK(mtmp)->following))) { if (avoid && (info[i] & NOTONL)) continue; if ((!appr && !rn2(++chcnt)) || (appr && GDIST(nx, ny) < GDIST(nix, niy))) { nix = nx; niy = ny; } } } if (mtmp->ispriest && avoid && nix == omx && niy == omy && onlineu(omx, omy)) { /* might as well move closer as long it's going to stay lined up */ avoid = FALSE; goto pick_move; } if (nix != omx || niy != omy) { remove_monster(level, omx, omy); place_monster(mtmp, nix, niy); newsym(nix, niy); if (mtmp->isshk && !in_his_shop && inhishop(mtmp)) check_special_room(FALSE); if (ib) { if (cansee(mtmp->mx, mtmp->my)) pline("%s picks up %s.", Monnam(mtmp), distant_name(ib, doname)); obj_extract_self(ib); mpickobj(mtmp, ib); } return 1; } return 0; }
/* * shk_move: return 1: he moved 0: he didnt -1: let m_move do it * (what about "return 2" ??? */ Short shk_move(monst_t *shkp) { monst_t *mtmp; permonst_t *mdat = shkp->data; UChar gx,gy,omx,omy,nx,ny,nix,niy; Int8 appr,i; Short udist; Short z; Int8 shkroom,chi,chcnt,cnt; Boolean uondoor=false, satdoor, avoid=false, badinv; coord poss[9]; Short info[9]; obj_t *ib = NULL; omx = shkp->mx; omy = shkp->my; if ((udist = dist(omx,omy)) < 3) { if (ANGRY(shkp)) { hit_you(shkp, dice(mdat->damn, mdat->damd)+1); return 0; } if (ESHK(shkp)->following) { if (StrNCompare(ESHK(shkp)->customer, plname, PL_NSIZ)) { StrPrintF(ScratchBuffer, "Hello %s! I was looking for %s.", plname, ESHK(shkp)->customer); message(ScratchBuffer); ESHK(shkp)->following = false; return 0; } if (!ESHK(shkp)->robbed) { /* impossible? */ ESHK(shkp)->following = false; return 0; } if (moves > followmsg+4) { StrPrintF(ScratchBuffer, "Hello %s! Didn't you forget to pay?", plname); message(ScratchBuffer); followmsg = moves; } if (udist < 2) return 0; } } shkroom = inroom(omx,omy); appr = 1; gx = ESHK(shkp)->shk.x; gy = ESHK(shkp)->shk.y; satdoor = (gx == omx && gy == omy); if (ESHK(shkp)->following || ((z = holetime()) >= 0 && z*z <= udist)){ gx = you.ux; gy = you.uy; if (shkroom < 0 || shkroom != inroom(you.ux,you.uy)) if (udist > 4) return -1; /* leave it to m_move */ } else if (ANGRY(shkp)) { Long saveBlind = Blind; Blind = 0; if ((shkp->mcansee_and_blinded & M_CAN_SEE) && !Invis && cansee(omx,omy)) { gx = you.ux; gy = you.uy; } Blind = saveBlind; avoid = false; } else { #define GDIST(x,y) ((x-gx)*(x-gx)+(y-gy)*(y-gy)) if (Invis) avoid = false; else { uondoor = (you.ux == ESHK(shkp)->shd.x && you.uy == ESHK(shkp)->shd.y); if (uondoor) { if (ESHK(shkp)->billct) { StrPrintF(ScratchBuffer, "Hello %s! Will you please pay before leaving?", plname); message(ScratchBuffer); } badinv = (carrying(PICK_AXE) || carrying(ICE_BOX)); if (satdoor && badinv) return 0; avoid = !badinv; } else { avoid = (you.uinshop && dist(gx,gy) > 8); badinv = false; } if (((!ESHK(shkp)->robbed && !ESHK(shkp)->billct) || avoid) && GDIST(omx,omy) < 3) { if (!badinv && !online(omx,omy)) return 0; if (satdoor) appr = gx = gy = 0; } } } if (omx == gx && omy == gy) return 0; if (shkp->bitflags & M_IS_CONFUSED) { avoid = false; appr = 0; } nix = omx; niy = omy; cnt = mfindpos(shkp,poss,info,ALLOW_SSM); if (avoid && uondoor) { /* perhaps we cannot avoid him */ for (i=0; i<cnt; i++) if (!(info[i] & NOTONL)) goto notonl_ok; avoid = false; notonl_ok: ; } chi = -1; chcnt = 0; for (i = 0 ; i < cnt ; i++) { nx = poss[i].x; ny = poss[i].y; if (get_cell_type(floor_info[nx][ny]) == ROOM || shkroom != ESHK(shkp)->shoproom || ESHK(shkp)->following) { #ifdef STUPID /* cater for stupid compilers */ Short zz; #endif STUPID if (uondoor && (ib = sobj_at(ICE_BOX, nx, ny))) { nix = nx; niy = ny; chi = i; break; } if (avoid && (info[i] & NOTONL)) continue; if ((!appr && !rund(++chcnt)) || #ifdef STUPID (appr && (zz = GDIST(nix,niy)) && zz > GDIST(nx,ny)) #else (appr && GDIST(nx,ny) < GDIST(nix,niy)) #endif STUPID ) { nix = nx; niy = ny; chi = i; } } } if (nix != omx || niy != omy) { if (info[chi] & ALLOW_M){ mtmp = mon_at(nix,niy); if (hitmm(shkp,mtmp) == 1 && rund(3) && hitmm(mtmp,shkp) == 2) return 2; return 0; } else if (info[chi] & ALLOW_U){ hit_you(shkp, dice(mdat->damn, mdat->damd)+1); return 0; } shkp->mx = nix; shkp->my = niy; pmon(shkp); if (ib) { unlink_obj(ib);//freeobj mpickobj(shkp, ib); } return 1; } return 0; }