From f4ef35e877a1a7e23b61e166e1a5a34690536ce5 Mon Sep 17 00:00:00 2001 From: Robert Vollmert Date: Mon, 2 Nov 2009 11:11:45 +0100 Subject: Move random_near_space into new teleport.cc. --- crawl-ref/source/teleport.cc | 130 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 crawl-ref/source/teleport.cc (limited to 'crawl-ref/source/teleport.cc') diff --git a/crawl-ref/source/teleport.cc b/crawl-ref/source/teleport.cc new file mode 100644 index 0000000000..5db62261b2 --- /dev/null +++ b/crawl-ref/source/teleport.cc @@ -0,0 +1,130 @@ +/* + * File: teleport.cc + * Summary: Functions related to teleportation and blinking. + */ + +#include "AppHdr.h" + +#include "teleport.h" + +#include "cloud.h" +#include "coord.h" +#include "los.h" +#include "player.h" +#include "random.h" +#include "state.h" +#include "terrain.h" +#include "view.h" + +bool random_near_space(const coord_def& origin, coord_def& target, + bool allow_adjacent, bool restrict_los, + bool forbid_dangerous, bool forbid_sanctuary) +{ + // This might involve ray tracing (via num_feats_between()), so + // cache results to avoid duplicating ray traces. +#define RNS_OFFSET 6 +#define RNS_WIDTH (2*RNS_OFFSET + 1) + FixedArray tried; + const coord_def tried_o = coord_def(RNS_OFFSET, RNS_OFFSET); + tried.init(false); + + // Is the monster on the other side of a transparent wall? + const bool trans_wall_block = trans_wall_blocking(origin); + const bool origin_is_player = (you.pos() == origin); + int min_walls_between = 0; + + // Skip ray tracing if possible. + if (trans_wall_block && !crawl_state.arena) + { + // XXX: you.pos() is invalid in the arena. + min_walls_between = num_feats_between(origin, you.pos(), + DNGN_CLEAR_ROCK_WALL, + DNGN_CLEAR_PERMAROCK_WALL); + } + + for (int tries = 0; tries < 150; tries++) + { + coord_def p = coord_def(random2(RNS_WIDTH), random2(RNS_WIDTH)); + if (tried(p)) + continue; + else + tried(p) = true; + + target = origin + (p - tried_o); + + // Origin is not 'near'. + if (target == origin) + continue; + + if (!in_bounds(target) + || restrict_los && !see_cell(target) + || grd(target) < DNGN_SHALLOW_WATER + || actor_at(target) + || !allow_adjacent && distance(origin, target) <= 2 + || forbid_sanctuary && is_sanctuary(target)) + { + continue; + } + + // Don't pick grids that contain a dangerous cloud. + if (forbid_dangerous) + { + const int cloud = env.cgrid(target); + + if (cloud != EMPTY_CLOUD + && is_damaging_cloud(env.cloud[cloud].type, true)) + { + continue; + } + } + + if (!trans_wall_block && !origin_is_player) + return (true); + + // If the monster is on a visible square which is on the other + // side of one or more translucent walls from the player, then it + // can only blink through translucent walls if the end point + // is either not visible to the player, or there are at least + // as many translucent walls between the player and the end + // point as between the player and the start point. However, + // monsters can still blink through translucent walls to get + // away from the player, since in the absence of translucent + // walls monsters can blink to places which are not in either + // the monster's nor the player's LOS. + if (!origin_is_player && !see_cell(target)) + return (true); + + // Player can't randomly pass through translucent walls. + if (origin_is_player) + { + if (see_cell_no_trans(target)) + return (true); + + continue; + } + + int walls_passed = num_feats_between(target, origin, + DNGN_CLEAR_ROCK_WALL, + DNGN_CLEAR_PERMAROCK_WALL, + true, true); + if (walls_passed == 0) + return (true); + + // Player can't randomly pass through translucent walls. + if (origin_is_player) + continue; + + int walls_between = 0; + if (!crawl_state.arena) + walls_between = num_feats_between(target, you.pos(), + DNGN_CLEAR_ROCK_WALL, + DNGN_CLEAR_PERMAROCK_WALL); + + if (walls_between >= min_walls_between) + return (true); + } + + return (false); +} + + -- cgit v1.2.3-54-g00ecf