/* return TRUE if successful, FALSE if not */ boolean rloc(struct monst *mtmp, /* mx==COLNO implies migrating monster arrival */ boolean suppress_impossible) { int x, y, trycount; int relaxed_goodpos; if (mtmp == u.usteed) { tele(); return TRUE; } if (mtmp->iswiz && mtmp->mx != COLNO) { /* Wizard, not just arriving */ if (!In_W_tower(u.ux, u.uy, &u.uz)) x = level->upstair.sx, y = level->upstair.sy; else if (!isok(level->dnladder.sx, level->dnladder.sy)) x = level->upladder.sx, y = level->upladder.sy;/* bottom of tower */ else x = level->dnladder.sx, y = level->dnladder.sy; /* if the wiz teleports away to heal, try the up staircase, to block the player's escaping before he's healed (deliberately use `goodpos' rather than `rloc_pos_ok' here) */ if (goodpos(level, x, y, mtmp, 0)) goto found_xy; } for (relaxed_goodpos = -1; relaxed_goodpos < 2; relaxed_goodpos++) { /* If this is a monster that blinks, try to do that first. */ if (relaxed_goodpos < 0) { if ((isok(mtmp->mx, mtmp->my)) && mtmp->data->mflags3 & M3_BLINKAWAY) { /* We're going to do a polar-to-rectangular conversion here, because it's a convenient way to select positions at the correct distance from where we're starting. We'll try with the maximum radius then back it off. */ int maxradius = 2 * mtmp->data->mlevel; int minradius = 2; int theta[24] = { 0, 15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240, 255, 270, 285, 300, 315, 330, 345 }; int angle, fineangle, swi, sw; coord rectcoord; if (maxradius < minradius + 3) maxradius = minradius + 3; /* Shuffle the order of the angles so we don't always get the same one tried first. */ for (angle = 0; angle < 24; angle++) { swi = rn2(24); sw = theta[swi]; theta[swi] = theta[angle]; theta[angle] = sw; } for (trycount = maxradius; trycount >= minradius; trycount--) { for (angle = 0; angle < 24; angle++) for (fineangle = 0; fineangle < 15; fineangle += 3) { /* theta is shuffled so that the angle isn't the same all the time, but it isn't necessary to shuffle over a hundred different angles; we use fineangle to allow positions that don't line up to the 15-degree increments, but the randomness of the blink direction doesn't need that much precision. */ rectcoord = polartorect(trycount, theta[angle] + fineangle); x = mtmp->mx + rectcoord.x; y = mtmp->my + rectcoord.y; if (isok(x,y) && !m_at(level,x,y) && /* TODO: evaluate whether goodpos() should be * used here */ (level->locations[x][y].typ >= CORR) && /* Blinking only works with line-of-sight, but for now I am not requiring the monster to actually _see_ the tile, so e.g. blinking into the dark works ok. */ clear_path(mtmp->mx, mtmp->my, x, y, viz_array) ) { goto found_xy; } } } } continue; } /* first try sensible terrain; if none exists, ignore water, doors and boulders */ int gpflags = relaxed_goodpos ? MM_IGNOREWATER | MM_IGNOREDOORS : 0; /* try several pairs of positions; try the more restrictive rloc_pos_ok before we use the less restrictive goodpos */ trycount = 0; do { x = rn2(COLNO); y = rn2(ROWNO); if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp) : goodpos(level, x, y, mtmp, gpflags)) goto found_xy; } while (++trycount < 1000); /* try every square on the level as a fallback */ for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (goodpos(level, x, y, mtmp, gpflags)) goto found_xy; } /* level either full of monsters or somehow faulty */ if (!suppress_impossible) impossible("rloc(): couldn't relocate monster"); return FALSE; found_xy: rloc_to(mtmp, x, y); return TRUE; }
/* functions defined and used internally */ void eiktam (float xs, float zs, int nz, float dz, float fz, int nx, float dx, float fx, float **vel, float **time, float **angle, float **sig, float **bet) /***************************************************************************** eiktam - Compute traveltimes t(x,z) and propagation angle a(x,z) via eikonal equation, and ray_theoretic_sigma sig(x,z), incident angle bet(x,z) via Crank-Nicolson Method ****************************************************************************** Input: xs x coordinate of source (must be within x samples) zs z coordinate of source (must be within z samples) nz number of z samples dz z sampling interval fz first z sample nx number of x samples dx x sampling interval fx first x sample vel array[nx][nz] containing velocities Output: time array[nx][nz] containing first-arrival times angle array[nx][nz] containing propagation angles sig array[nx][nz] containing ray_theoretic_sigmas bet array[nx][nz] containing ray_theoretic_betas ****************************************************************************** Notes: The actual computation of times and ray_theoretic_sigmas is done in polar coordinates, with bilinear interpolation used to map to/from rectangular coordinates. ****************************************************************************** Revisor: Zhenyue Liu, Colorado School of Mines, 7/8/92 ******************************************************************************/ { int ix,iz,ia,ir,na,nr; float ss,a,r,da,dr,fa,fr,ex,ez,ea,rmax,rmaxs, **s,**sp,**tp,**up,**wp,**ap; /* shift coordinates so source is at (x=0,z=0) */ fx -= xs; fz -= zs; ex = fx+(nx-1)*dx; ez = fz+(nz-1)*dz; /* determine polar coordinate sampling */ rmaxs = fx*fx+fz*fz; rmaxs = MAX(rmaxs,fx*fx+ez*ez); rmaxs = MAX(rmaxs,ex*ex+ez*ez); rmaxs = MAX(rmaxs,ex*ex+fz*fz); rmax = sqrt(rmaxs); dr = MIN(ABS(dx),ABS(dz)); nr = 1+NINT(rmax/dr); dr = rmax/(nr-1); fr = 0.0; if (fx==0.0 && fz==0.0) { fa = 0.0; ea = PI/2.0; } else if (fx<0.0 && fz==0.0) { fa = -PI/2.0; ea = PI/2.0; } else if (fx==0.0 && fz<0.0) { fa = 0.0; ea = PI; } else { fa = -PI; ea = PI; } da = dr/rmax; na = 1+NINT((ea-fa)/da); da = (ea-fa)/(na-1); if (fa==-PI && ea==PI) na = na-1; /* allocate space */ s = alloc2float(nz,nx); sp = alloc2float(na,nr); tp = alloc2float(na,nr); up = alloc2float(na,nr); wp = alloc2float(na,nr); ap = alloc2float(na,nr); /* compute slownesses */ for (ix=0; ix<nx; ++ix) for (iz=0; iz<nz; ++iz) s[ix][iz] = 1.0/vel[ix][iz]; /* convert from rectangular to polar coordinates */ recttopolar(nz,dz,fz,nx,dx,fx,s,na,da,fa,nr,dr,fr,sp); /* average the slownesses in source region */ for (ir=0,ss=0.0; ir<2; ++ir) for (ia=0; ia<na; ++ia) ss += sp[ir][ia]; ss /= 2*na; /* compute traveltimes and derivatives in source region */ for (ir=0,r=0; ir<2; ++ir,r+=dr) { for (ia=0; ia<na; ++ia) { up[ir][ia] = ss; wp[ir][ia] = 0.0; tp[ir][ia] = r*ss; } } /* tt=cpusec(); */ /* solve eikonal equation for remaining times and derivatives */ for (ir=1,r=dr; ir<nr-1; ++ir,r+=dr) { eikpex(na,da,r,dr, sp[ir],up[ir],wp[ir],tp[ir], sp[ir+1],up[ir+1],wp[ir+1],tp[ir+1]); } /* convert times from polar to rectangular coordinates */ polartorect(na,da,fa,nr,dr,fr,tp,nz,dz,fz,nx,dx,fx,time); /* fprintf(stderr,"\t CPU time for traveltimes= %f \n",cpusec()-tt); tt=cpusec(); */ /* compute propagation angles in polar and convert */ for (ia=0,a=fa; ia<na; ++ia,a+=da) ap[0][ia] = a; for (ir=1,r=fr+dr; ir<nr; ++ir,r+=dr) for (ia=0,a=fa; ia<na; ++ia,a+=da){ ap[ir][ia] = a+asin(wp[ir][ia]/(sp[ir][ia]*r)); } polartorect(na,da,fa,nr,dr,fr,ap,nz,dz,fz,nx,dx,fx,angle); /* fprintf(stderr,"\t CPU time for propagation angles= %f\n", cpusec()-tt); tt=cpusec(); */ /* compute ray_theoretic_sigmas for initial values */ for (ir=0,r=0; ir<2; ++ir,r+=dr) for (ia=0; ia<na; ++ia) tp[ir][ia] = r/ss; /* solve diffrence equation for remaining ray_theoretic_sigmas */ for (ir=1,r=dr; ir<nr-1; ++ir,r+=dr) ray_theoretic_sigma(na,da,r,dr,up[ir],wp[ir],tp[ir], up[ir+1],wp[ir+1],tp[ir+1]); polartorect(na,da,fa,nr,dr,fr,tp,nz,dz,fz,nx,dx,fx,sig); /* fprintf(stderr,"\t CPU time for sigmas= %f \n",cpusec()-tt); tt=cpusec(); */ /* compute ray_theoretic_betas for initial values */ for (ir=0; ir<2; ++ir) for (ia=0,a=fa; ia<na; ++ia,a+=da) tp[ir][ia] = a; /* solve diffrence equation for remaining ray_theoretic_betas */ for (ir=1,r=dr; ir<nr-1; ++ir,r+=dr) ray_theoretic_beta(na,da,r,dr,up[ir],wp[ir],tp[ir], up[ir+1],wp[ir+1],tp[ir+1]); polartorect(na,da,fa,nr,dr,fr,tp,nz,dz,fz,nx,dx,fx,bet); /* fprintf(stderr,"\t CPU time for incident angles= %f \n", cpusec()-tt); */ /* free space */ free2float(s); free2float(sp); free2float(tp); free2float(up); free2float(wp); free2float(ap); }