/** * Standard "find me a location" function, now with all legal outputs! * * Obtains a legal location within the given distance of the initial * location, and with "los()" from the source to destination location. * * This function is often called from inside a loop which searches for * locations while increasing the "d" distance. * * need_los determines whether line of sight is needed */ void scatter(struct chunk *c, int *yp, int *xp, int y, int x, int d, bool need_los) { int nx, ny; int tries = 0; /* Pick a location, try many times */ while (tries < 1000) { /* Pick a new location */ ny = rand_spread(y, d); nx = rand_spread(x, d); tries++; /* Ignore annoying locations */ if (!square_in_bounds_fully(c, ny, nx)) continue; /* Ignore "excessively distant" locations */ if ((d > 1) && (distance(y, x, ny, nx) > d)) continue; /* Require "line of sight" if set */ if (need_los && !los(c, y, x, ny, nx)) continue; /* Set the location and return */ (*yp) = ny; (*xp) = nx; return; } }
/** * Standard "find me a location" function * * Obtains a legal location within the given distance of the initial * location, and with "los()" from the source to destination location. * * This function is often called from inside a loop which searches for * locations while increasing the "d" distance. * * need_los determines whether line of sight is needed */ void scatter(struct chunk *c, int *yp, int *xp, int y, int x, int d, bool need_los) { int nx, ny; /* Pick a location */ while (true) { /* Pick a new location */ ny = rand_spread(y, d); nx = rand_spread(x, d); /* Ignore annoying locations */ if (!square_in_bounds_fully(c, ny, nx)) continue; /* Ignore "excessively distant" locations */ if ((d > 1) && (distance(y, x, ny, nx) > d)) continue; /* Don't need los */ if (!need_los) break; /* Require "line of sight" if set */ if (need_los && (los(c, y, x, ny, nx))) break; } /* Save the location */ (*yp) = ny; (*xp) = nx; }
/** * Light or Darken the town */ void cave_illuminate(struct chunk *c, bool daytime) { int y, x, i; /* Apply light or darkness */ for (y = 0; y < c->height; y++) for (x = 0; x < c->width; x++) { int d; bool light = FALSE; feature_type *f_ptr = &f_info[c->squares[y][x].feat]; /* Skip grids with no surrounding floors or stairs */ for (d = 0; d < 9; d++) { /* Extract adjacent (legal) location */ int yy = y + ddy_ddd[d]; int xx = x + ddx_ddd[d]; /* Paranoia */ if (!square_in_bounds_fully(c, yy, xx)) continue; /* Test */ if (square_isfloor(c, yy, xx) || square_isstairs(c, yy, xx)) light = TRUE; } if (!light) continue; /* Only interesting grids at night */ if (daytime || !tf_has(f_ptr->flags, TF_FLOOR)) { sqinfo_on(c->squares[y][x].info, SQUARE_GLOW); sqinfo_on(c->squares[y][x].info, SQUARE_MARK); } else { sqinfo_off(c->squares[y][x].info, SQUARE_GLOW); sqinfo_off(c->squares[y][x].info, SQUARE_MARK); } } /* Light shop doorways */ for (y = 0; y < c->height; y++) { for (x = 0; x < c->width; x++) { if (!square_isshop(c, y, x)) continue; for (i = 0; i < 8; i++) { int yy = y + ddy_ddd[i]; int xx = x + ddx_ddd[i]; sqinfo_on(c->squares[yy][xx].info, SQUARE_GLOW); sqinfo_on(c->squares[yy][xx].info, SQUARE_MARK); } } } /* Fully update the visuals */ player->upkeep->update |= (PU_FORGET_VIEW | PU_UPDATE_VIEW | PU_MONSTERS); /* Redraw map, monster list */ player->upkeep->redraw |= (PR_MAP | PR_MONLIST | PR_ITEMLIST); }
/** * Checks if a square is at the (inner) edge of a trap detect area */ bool square_dtrap_edge(struct chunk *c, int y, int x) { /* Check if the square is a dtrap in the first place */ if (!square_isdtrap(c, y, x)) return FALSE; /* Check for non-dtrap adjacent grids */ if (square_in_bounds_fully(c, y + 1, x) && (!square_isdtrap(c, y + 1, x))) return TRUE; if (square_in_bounds_fully(c, y, x + 1) && (!square_isdtrap(c, y, x + 1))) return TRUE; if (square_in_bounds_fully(c, y - 1, x) && (!square_isdtrap(c, y - 1, x))) return TRUE; if (square_in_bounds_fully(c, y, x - 1) && (!square_isdtrap(c, y, x - 1))) return TRUE; return FALSE; }
/** * Choose a good hiding place near a monster for it to run toward. * * Pack monsters will use this to "ambush" the player and lure him out * of corridors into open space so they can swarm him. * * Return true if a good location is available. */ static bool get_move_find_hiding(struct chunk *c, struct monster *mon) { struct loc mon_grid = loc(mon->fx, mon->fy); struct loc player_grid = loc(player->px, player->py); int i, y, x, dy, dx, d, dis; int gy = 0, gx = 0, gdis = 999, min; const int *y_offsets, *x_offsets; /* Closest distance to get */ min = distance(player_grid, mon_grid) * 3 / 4 + 2; /* Start with adjacent locations, spread further */ for (d = 1; d < 10; d++) { /* Get the lists of points with a distance d from monster */ y_offsets = dist_offsets_y[d]; x_offsets = dist_offsets_x[d]; /* Check the locations */ for (i = 0, dx = x_offsets[0], dy = y_offsets[0]; dx != 0 || dy != 0; i++, dx = x_offsets[i], dy = y_offsets[i]) { y = mon_grid.y + dy; x = mon_grid.x + dx; /* Skip illegal locations */ if (!square_in_bounds_fully(c, y, x)) continue; /* Skip occupied locations */ if (!square_isempty(c, y, x)) continue; /* Check for hidden, available grid */ if (!square_isview(c, y, x) && projectable(c, mon_grid.y, mon_grid.x, y, x, PROJECT_STOP)) { /* Calculate distance from player */ dis = distance(loc(x, y), player_grid); /* Remember if closer than previous */ if (dis < gdis && dis >= min) { gy = y; gx = x; gdis = dis; } } } /* Check for success */ if (gdis < 999) { /* Good location */ mon->target.grid = loc(gx, gy); return (true); } } /* No good place */ return (false); }
/** * Light up the dungeon using "claravoyance" * * This function "illuminates" every grid in the dungeon, memorizes all * "objects" (or notes the existence of an object "if" full is true), * and memorizes all grids as with magic mapping. */ void wiz_light(struct chunk *c, struct player *p, bool full) { int i, y, x; /* Scan all grids */ for (y = 1; y < c->height - 1; y++) { for (x = 1; x < c->width - 1; x++) { /* Process all non-walls */ if (!square_seemslikewall(c, y, x)) { if (!square_in_bounds_fully(c, y, x)) continue; /* Scan all neighbors */ for (i = 0; i < 9; i++) { int yy = y + ddy_ddd[i]; int xx = x + ddx_ddd[i]; /* Perma-light the grid */ sqinfo_on(c->squares[yy][xx].info, SQUARE_GLOW); /* Memorize normal features */ if (!square_isfloor(c, yy, xx) || square_isvisibletrap(c, yy, xx)) { square_memorize(c, yy, xx); square_mark(c, yy, xx); } } } /* Memorize objects */ if (full) { square_know_pile(c, y, x); } else { square_sense_pile(c, y, x); } /* Forget unprocessed, unknown grids in the mapping area */ if (!square_ismark(c, y, x) && square_isnotknown(c, y, x)) square_forget(c, y, x); } } /* Unmark grids */ for (y = 1; y < c->height - 1; y++) { for (x = 1; x < c->width - 1; x++) { if (!square_in_bounds(c, y, x)) continue; square_unmark(c, y, x); } } /* Fully update the visuals */ p->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Redraw whole map, monster list */ p->upkeep->redraw |= (PR_MAP | PR_MONLIST | PR_ITEMLIST); }
/** * Set the target to a location */ void target_set_location(int y, int x) { /* Legal target */ if (square_in_bounds_fully(cave, y, x)) { /* Save target info */ target_set = true; target_who = NULL; target_y = y; target_x = x; return; } /* Reset target info */ target_set = false; target_who = 0; target_y = 0; target_x = 0; }
/** * Return a target set of target_able monsters. */ struct point_set *target_get_monsters(int mode, monster_predicate pred) { int y, x; int min_y, min_x, max_y, max_x; struct point_set *targets = point_set_new(TS_INITIAL_SIZE); /* Get the current panel */ get_panel(&min_y, &min_x, &max_y, &max_x); /* Scan for targets */ for (y = min_y; y < max_y; y++) { for (x = min_x; x < max_x; x++) { struct loc grid = loc(x, y); /* Check bounds */ if (!square_in_bounds_fully(cave, grid)) continue; /* Require "interesting" contents */ if (!target_accept(y, x)) continue; /* Special mode */ if (mode & (TARGET_KILL)) { struct monster *mon = square_monster(cave, grid); /* Must contain a monster */ if (mon == NULL) continue; /* Must be a targettable monster */ if (!target_able(mon)) continue; /* Must be the right sort of monster */ if (pred && !pred(mon)) continue; } /* Save the location */ add_to_point_set(targets, grid); } } sort(targets->pts, point_set_size(targets), sizeof(*(targets->pts)), cmp_distance); return targets; }
/** * Set the target to a location */ void target_set_location(int y, int x) { struct loc grid = loc(x, y); /* Legal target */ if (square_in_bounds_fully(cave, grid)) { /* Save target info */ target_set = true; target.midx = 0; target.grid = grid; return; } /* Reset target info */ target_set = false; target.midx = 0; target.grid.y = 0; target.grid.x = 0; }
/* From Will Asher in DJA: * Find whether a monster is near a permanent wall * this decides whether PASS_WALL & KILL_WALL monsters * use the monster flow code */ static bool near_permwall(const struct monster *mon, struct chunk *c) { int y, x; int my = mon->fy; int mx = mon->fx; /* if PC is in LOS, there's no need to go around walls */ if (projectable(cave, my, mx, player->py, player->px, PROJECT_NONE)) return false; /* PASS_WALL & KILL_WALL monsters occasionally flow for a turn anyway */ if (randint0(99) < 5) return true; /* Search the nearby grids, which are always in bounds */ for (y = (my - 2); y <= (my + 2); y++) { for (x = (mx - 2); x <= (mx + 2); x++) { if (!square_in_bounds_fully(c, y, x)) continue; if (square_isperm(c, y, x)) return true; } } return false; }
/** * Set the target to a location */ void target_set_location(int y, int x) { /* Legal target */ if (square_in_bounds_fully(cave, y, x)) { struct monster *mon = square_monster(cave, y, x); /* Save target info */ target_set = TRUE; target_who = NULL; if (mon && target_able(mon)) target_who = mon; target_y = y; target_x = x; return; } /* Reset target info */ target_set = FALSE; target_who = 0; target_y = 0; target_x = 0; }
/** * Return the number of doors/traps around (or under) the character. */ int count_feats(int *y, int *x, bool (*test)(struct chunk *c, int y, int x), bool under) { int d; int xx, yy; int count = 0; /* Count how many matches */ /* Check around (and under) the character */ for (d = 0; d < 9; d++) { /* if not searching under player continue */ if ((d == 8) && !under) continue; /* Extract adjacent (legal) location */ yy = player->py + ddy_ddd[d]; xx = player->px + ddx_ddd[d]; /* Paranoia */ if (!square_in_bounds_fully(cave, yy, xx)) continue; /* Must have knowledge */ if (!square_isknown(cave, yy, xx)) continue; /* Not looking for this feature */ if (!((*test)(cave, yy, xx))) continue; /* Count it */ ++count; /* Remember the location of the last door found */ if (x && y) { *y = yy; *x = xx; } } /* All done */ return count; }
/** * Place the player at a random starting location. * \param c current chunk * \param p the player */ void new_player_spot(struct chunk *c, struct player *p) { int y, x; /* Try to find a good place to put the player */ if (OPT(p, birth_levels_persist) && square_in_bounds_fully(c, p->py, p->px) && square_isstairs(c, p->py, p->px)) { y = p->py; x = p->px; } else if (!find_start(c, &y, &x)) { quit("Failed to place player!"); } /* Create stairs the player came down if allowed and necessary */ if (!OPT(p, birth_connect_stairs)) ; else if (p->upkeep->create_down_stair) square_set_feat(c, y, x, FEAT_MORE); else if (p->upkeep->create_up_stair) square_set_feat(c, y, x, FEAT_LESS); player_place(c, p, y, x); }
/** * Return a target set of target_able monsters. */ struct point_set *target_get_monsters(int mode) { int y, x; int min_y, min_x, max_y, max_x; struct point_set *targets = point_set_new(TS_INITIAL_SIZE); /* Get the current panel */ get_panel(&min_y, &min_x, &max_y, &max_x); /* Scan for targets */ for (y = min_y; y < max_y; y++) { for (x = min_x; x < max_x; x++) { /* Check bounds */ if (!square_in_bounds_fully(cave, y, x)) continue; /* Require "interesting" contents */ if (!target_accept(y, x)) continue; /* Special mode */ if (mode & (TARGET_KILL)) { /* Must contain a monster */ if (!(cave->squares[y][x].mon > 0)) continue; /* Must be a targettable monster */ if (!target_able(square_monster(cave, y, x))) continue; } /* Save the location */ add_to_point_set(targets, y, x); } } sort(targets->pts, point_set_size(targets), sizeof(*(targets->pts)), cmp_distance); return targets; }
/** * Choose a "safe" location near a monster for it to run toward. * * A location is "safe" if it can be reached quickly and the player * is not able to fire into it (it isn't a "clean shot"). So, this will * cause monsters to "duck" behind walls. Hopefully, monsters will also * try to run towards corridor openings if they are in a room. * * This function may take lots of CPU time if lots of monsters are fleeing. * * Return true if a safe location is available. */ static bool get_move_find_safety(struct chunk *c, struct monster *mon) { int fy = mon->fy; int fx = mon->fx; int py = player->py; int px = player->px; int i, y, x, dy, dx, d, dis; int gy = 0, gx = 0, gdis = 0; const int *y_offsets; const int *x_offsets; /* Start with adjacent locations, spread further */ for (d = 1; d < 10; d++) { /* Get the lists of points with a distance d from (fx, fy) */ y_offsets = dist_offsets_y[d]; x_offsets = dist_offsets_x[d]; /* Check the locations */ for (i = 0, dx = x_offsets[0], dy = y_offsets[0]; dx != 0 || dy != 0; i++, dx = x_offsets[i], dy = y_offsets[i]) { y = fy + dy; x = fx + dx; /* Skip illegal locations */ if (!square_in_bounds_fully(c, y, x)) continue; /* Skip locations in a wall */ if (!square_ispassable(c, y, x)) continue; /* Ignore too-distant grids */ if (c->noise.grids[y][x] > c->noise.grids[fy][fx] + 2 * d) continue; /* Ignore damaging terrain if they can't handle it */ if (square_isdamaging(c, y, x) && !rf_has(mon->race->flags, square_feat(c, y, x)->resist_flag)) continue; /* Check for absence of shot (more or less) */ if (!square_isview(c, y, x)) { /* Calculate distance from player */ dis = distance(loc(x, y), loc(px, py)); /* Remember if further than previous */ if (dis > gdis) { gy = y; gx = x; gdis = dis; } } } /* Check for success */ if (gdis > 0) { /* Good location */ mon->target.grid = loc(gx, gy); return (true); } } /* No safe place */ return (false); }
void square_add_trap(struct chunk *c, int y, int x) { assert(square_in_bounds_fully(c, y, x)); place_trap(c, y, x, -1, c->depth); }
/** * Let an object fall to the ground at or near a location. * * The initial location is assumed to be "square_in_bounds_fully(cave, )". * * This function takes a parameter "chance". This is the percentage * chance that the item will "disappear" instead of drop. If the object * has been thrown, then this is the chance of disappearance on contact. * * This function will produce a description of a drop event under the player * when "verbose" is true. * * We check several locations to see if we can find a location at which * the object can combine, stack, or be placed. Artifacts will try very * hard to be placed, including "teleporting" to a useful grid if needed. * * Objects which fail to be carried by the floor are deleted. This function * attempts to add successfully dropped objects to, and to remove failures * from, the object list (as dropped items may or may not be already listed). */ void drop_near(struct chunk *c, struct object *dropped, int chance, int y, int x, bool verbose) { int i, k, n, d, s; int bs, bn; int by, bx; int dy, dx; int ty, tx; struct object *obj; char o_name[80]; bool flag = false; /* Only called in the current level */ assert(c == cave); /* Describe object */ object_desc(o_name, sizeof(o_name), dropped, ODESC_BASE); /* Handle normal "breakage" */ if (!dropped->artifact && (randint0(100) < chance)) { /* Message */ msg("The %s %s.", o_name, VERB_AGREEMENT(dropped->number, "breaks", "break")); /* Failure */ if (dropped->known) { delist_object(cave_k, dropped->known); object_delete(&dropped->known); } delist_object(c, dropped); object_delete(&dropped); return; } /* Score */ bs = -1; /* Picker */ bn = 0; /* Default */ by = y; bx = x; /* Scan local grids */ for (dy = -3; dy <= 3; dy++) { for (dx = -3; dx <= 3; dx++) { bool comb = false; /* Calculate actual distance */ d = (dy * dy) + (dx * dx); /* Ignore distant grids */ if (d > 10) continue; /* Location */ ty = y + dy; tx = x + dx; /* Skip illegal grids */ if (!square_in_bounds_fully(c, ty, tx)) continue; /* Require line of sight */ if (!los(c, y, x, ty, tx)) continue; /* Require floor space */ if (!square_isfloor(c, ty, tx)) continue; /* Require no trap or rune */ if (square_isplayertrap(c, ty, tx) || square_iswarded(c, ty, tx)) continue; /* No objects */ k = 0; n = 0; /* Scan objects in that grid */ for (obj = square_object(c, ty, tx); obj; obj = obj->next) { /* Check for possible combination */ if (object_similar(obj, dropped, OSTACK_FLOOR)) comb = true; /* Count objects */ if (!ignore_item_ok(obj)) k++; else n++; } /* Add new object */ if (!comb) k++; /* Option -- disallow stacking */ if (OPT(birth_no_stacking) && (k > 1)) continue; /* Paranoia? */ if ((k + n) > z_info->floor_size && !floor_get_oldest_ignored(ty, tx)) continue; /* Calculate score */ s = 1000 - (d + k * 5); /* Skip bad values */ if (s < bs) continue; /* New best value */ if (s > bs) bn = 0; /* Apply the randomizer to equivalent values */ if ((++bn >= 2) && (randint0(bn) != 0)) continue; /* Keep score */ bs = s; /* Track it */ by = ty; bx = tx; /* Okay */ flag = true; } } /* Handle lack of space */ if (!flag && !dropped->artifact) { /* Message */ msg("The %s %s.", o_name, VERB_AGREEMENT(dropped->number, "disappears", "disappear")); /* Debug */ if (player->wizard) msg("Breakage (no floor space)."); /* Failure */ if (dropped->known) { delist_object(cave_k, dropped->known); object_delete(&dropped->known); } delist_object(c, dropped); object_delete(&dropped); return; } /* Find a grid */ for (i = 0; !flag; i++) { /* Bounce around */ if (i < 1000) { ty = rand_spread(by, 1); tx = rand_spread(bx, 1); } else { /* Random locations */ ty = randint0(c->height); tx = randint0(c->width); } /* Require floor space */ if (!square_canputitem(c, ty, tx)) continue; /* Bounce to that location */ by = ty; bx = tx; /* Okay */ flag = true; } /* Give it to the floor */ if (!floor_carry(c, by, bx, dropped, false)) { /* Message */ msg("The %s %s.", o_name, VERB_AGREEMENT(dropped->number, "disappears", "disappear")); /* Debug */ if (player->wizard) msg("Breakage (too many objects)."); if (dropped->artifact) dropped->artifact->created = false; /* Failure */ if (dropped->known) { delist_object(cave_k, dropped->known); object_delete(&dropped->known); } delist_object(c, dropped); object_delete(&dropped); return; } /* Sound */ sound(MSG_DROP); /* Message when an object falls under the player */ if (verbose && (c->squares[by][bx].mon < 0)) /* Check the item still exists and isn't ignored */ if (c->objects[dropped->oidx] && !ignore_item_ok(dropped)) msg("You feel something roll beneath your feet."); }
/** * Choose a good hiding place near a monster for it to run toward. * * Pack monsters will use this to "ambush" the player and lure him out * of corridors into open space so they can swarm him. * * Return true if a good location is available. */ static bool find_hiding(struct chunk *c, struct monster *mon) { int fy = mon->fy; int fx = mon->fx; int py = player->py; int px = player->px; int i, y, x, dy, dx, d, dis; int gy = 0, gx = 0, gdis = 999, min; const int *y_offsets, *x_offsets; /* Closest distance to get */ min = distance(py, px, fy, fx) * 3 / 4 + 2; /* Start with adjacent locations, spread further */ for (d = 1; d < 10; d++) { /* Get the lists of points with a distance d from (fx, fy) */ y_offsets = dist_offsets_y[d]; x_offsets = dist_offsets_x[d]; /* Check the locations */ for (i = 0, dx = x_offsets[0], dy = y_offsets[0]; dx != 0 || dy != 0; i++, dx = x_offsets[i], dy = y_offsets[i]) { y = fy + dy; x = fx + dx; /* Skip illegal locations */ if (!square_in_bounds_fully(c, y, x)) continue; /* Skip occupied locations */ if (!square_isempty(c, y, x)) continue; /* Check for hidden, available grid */ if (!square_isview(c, y, x) && projectable(c, fy, fx, y, x, PROJECT_STOP)) { /* Calculate distance from player */ dis = distance(y, x, py, px); /* Remember if closer than previous */ if (dis < gdis && dis >= min) { gy = y; gx = x; gdis = dis; } } } /* Check for success */ if (gdis < 999) { /* Good location */ mon->ty = gy; mon->tx = gx; /* Found good place */ return (true); } } /* No good place */ return (false); }
/** * Choose a "safe" location near a monster for it to run toward. * * A location is "safe" if it can be reached quickly and the player * is not able to fire into it (it isn't a "clean shot"). So, this will * cause monsters to "duck" behind walls. Hopefully, monsters will also * try to run towards corridor openings if they are in a room. * * This function may take lots of CPU time if lots of monsters are fleeing. * * Return true if a safe location is available. */ static bool find_safety(struct chunk *c, struct monster *mon) { int fy = mon->fy; int fx = mon->fx; int py = player->py; int px = player->px; int i, y, x, dy, dx, d, dis; int gy = 0, gx = 0, gdis = 0; const int *y_offsets; const int *x_offsets; /* Start with adjacent locations, spread further */ for (d = 1; d < 10; d++) { /* Get the lists of points with a distance d from (fx, fy) */ y_offsets = dist_offsets_y[d]; x_offsets = dist_offsets_x[d]; /* Check the locations */ for (i = 0, dx = x_offsets[0], dy = y_offsets[0]; dx != 0 || dy != 0; i++, dx = x_offsets[i], dy = y_offsets[i]) { y = fy + dy; x = fx + dx; /* Skip illegal locations */ if (!square_in_bounds_fully(c, y, x)) continue; /* Skip locations in a wall */ if (!square_ispassable(c, y, x)) continue; /* Ignore grids very far from the player */ if (c->squares[y][x].scent < c->squares[py][px].scent) continue; /* Ignore too-distant grids */ if (c->squares[y][x].noise > c->squares[fy][fx].noise + 2 * d) continue; /* Ignore lava if they can't handle the heat */ if (square_isfiery(c, y, x) && !rf_has(mon->race->flags, RF_IM_FIRE)) continue; /* Check for absence of shot (more or less) */ if (!square_isview(c, y, x)) { /* Calculate distance from player */ dis = distance(y, x, py, px); /* Remember if further than previous */ if (dis > gdis) { gy = y; gx = x; gdis = dis; } } } /* Check for success */ if (gdis > 0) { /* Good location */ mon->ty = gy; mon->tx = gx; /* Found safe place */ return (true); } } /* No safe place */ return (false); }
/* * Choose a "safe" location near a monster for it to run toward. * * A location is "safe" if it can be reached quickly and the player * is not able to fire into it (it isn't a "clean shot"). So, this will * cause monsters to "duck" behind walls. Hopefully, monsters will also * try to run towards corridor openings if they are in a room. * * This function may take lots of CPU time if lots of monsters are fleeing. * * Return TRUE if a safe location is available. */ static bool find_safety(struct chunk *c, struct monster *m_ptr) { int fy = m_ptr->fy; int fx = m_ptr->fx; int py = player->py; int px = player->px; int i, y, x, dy, dx, d, dis; int gy = 0, gx = 0, gdis = 0; const int *y_offsets; const int *x_offsets; /* Start with adjacent locations, spread further */ for (d = 1; d < 10; d++) { /* Get the lists of points with a distance d from (fx, fy) */ y_offsets = dist_offsets_y[d]; x_offsets = dist_offsets_x[d]; /* Check the locations */ for (i = 0, dx = x_offsets[0], dy = y_offsets[0]; dx != 0 || dy != 0; i++, dx = x_offsets[i], dy = y_offsets[i]) { y = fy + dy; x = fx + dx; /* Skip illegal locations */ if (!square_in_bounds_fully(cave, y, x)) continue; /* Skip locations in a wall */ if (!square_ispassable(cave, y, x)) continue; /* Ignore grids very far from the player */ if (c->squares[y][x].when < c->squares[py][px].when) continue; /* Ignore too-distant grids */ if (c->squares[y][x].cost > c->squares[fy][fx].cost + 2 * d) continue; /* Check for absence of shot (more or less) */ if (!player_has_los_bold(y,x)) { /* Calculate distance from player */ dis = distance(y, x, py, px); /* Remember if further than previous */ if (dis > gdis) { gy = y; gx = x; gdis = dis; } } } /* Check for success */ if (gdis > 0) { /* Good location */ m_ptr->ty = gy; m_ptr->tx = gx; /* Found safe place */ return (TRUE); } } /* No safe place */ return (FALSE); }
void calc_cave_distances(int **cave_dist) { int dist, i; int oy, ox, ty, tx, d; /* Squares with distance from player of n - 1 */ int d_x_old[DIST_MAX]; int d_y_old[DIST_MAX]; int d_old_max; /* Squares with distance from player of n */ int d_x_new[DIST_MAX]; int d_y_new[DIST_MAX]; int d_new_max; /* Get player location */ oy = d_y_old[0] = player->py; ox = d_x_old[0] = player->px; d_old_max = 1; /* Distance from player starts at 0 */ dist = 0; /* Assign the distance value to the first square (player) */ cave_dist[oy][ox] = dist; do { d_new_max = 0; dist++; /* Loop over all visited squares of the previous iteration */ for (i = 0; i < d_old_max; i++){ /* Get the square we want to look at */ oy = d_y_old[i]; ox = d_x_old[i]; /* debug msg("x: %d y: %d dist: %d %d ",ox,oy,dist-1,i); */ /* Get all adjacent squares */ for (d = 0; d < 8; d++) { /* Adjacent square location */ ty = oy + ddy_ddd[d]; tx = ox + ddx_ddd[d]; if (!(square_in_bounds_fully(cave, ty, tx))) continue; /* Have we been here before? */ if (cave_dist[ty][tx] >= 0) continue; /* Is it a wall? */ if (square_iswall(cave, ty, tx)) continue; /* Add the new location */ d_y_new[d_new_max] = ty; d_x_new[d_new_max] = tx; /* Assign the distance to that spot */ cave_dist[ty][tx] = dist; d_new_max++; /* debug msg("x: %d y: %d dist: %d ",tx,ty,dist); */ } } /* Copy the new distance list to the old one */ for (i = 0; i < d_new_max; i++) { d_y_old[i] = d_y_new[i]; d_x_old[i] = d_x_new[i]; } d_old_max = d_new_max; } while ((d_old_max > 0) || dist == DIST_MAX); }
/** * Find a grid near the given one for an object to fall on * * We check several locations to see if we can find a location at which * the object can combine, stack, or be placed. Artifacts will try very * hard to be placed, including "teleporting" to a useful grid if needed. * * If no appropriate grid is found, the given grid is unchanged */ static void drop_find_grid(struct object *drop, int *y, int *x) { int best_score = -1; int best_y = *y; int best_x = *x; int i, dy, dx; struct object *obj; /* Scan local grids */ for (dy = -3; dy <= 3; dy++) { for (dx = -3; dx <= 3; dx++) { bool combine = false; int dist = (dy * dy) + (dx * dx); int ty = *y + dy; int tx = *x + dx; int num_shown = 0; int num_ignored = 0; int score; /* Lots of reasons to say no */ if ((dist > 10) || !square_in_bounds_fully(cave, ty, tx) || !los(cave, *y, *x, ty, tx) || !square_isfloor(cave, ty, tx) || square_isplayertrap(cave, ty, tx) || square_iswarded(cave, ty, tx)) continue; /* Analyse the grid for carrying the new object */ for (obj = square_object(cave, ty, tx); obj; obj = obj->next) { /* Check for possible combination */ if (object_similar(obj, drop, OSTACK_FLOOR)) combine = true; /* Count objects */ if (!ignore_item_ok(obj)) num_shown++; else num_ignored++; } if (!combine) num_shown++; /* Disallow if the stack size is too big */ if ((OPT(player, birth_stacking) && (num_shown > 1)) || ((num_shown + num_ignored) > z_info->floor_size && !floor_get_oldest_ignored(ty, tx))) continue; /* Score the location based on how close and how full the grid is */ score = 1000 - (dist + num_shown * 5); if ((score < best_score) || ((score == best_score) && one_in_(2))) continue; best_score = score; best_y = ty; best_x = tx; } } /* Return if we have a score, otherwise fail or try harder for artifacts */ if (best_score >= 0) { *y = best_y; *x = best_x; return; } else if (!drop->artifact) { return; } for (i = 0; i < 2000; i++) { /* Start bouncing from grid to grid, stopping if we find an empty one */ if (i < 1000) { best_y = rand_spread(best_y, 1); best_x = rand_spread(best_x, 1); } else { /* Now go to purely random locations */ best_y = randint0(cave->height); best_x = randint0(cave->width); } if (square_canputitem(cave, best_y, best_x)) { *y = best_y; *x = best_x; return; } } }