after map transforms are applied.
Fixed conflicts in bison grammar.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1669 c06c8d41-db1a-0410-9941-cceddc491573
OYTCBRC7LE44EUVRZVYTOOVKQWJ6P6YE3FXTOGUTNKEMLNWPHKSQC
XEZ76QETN2I5KWNSGQPNNPH2K55DPRAXDYZ6UGHOPI3E5V2OCOUAC
PM2AFCUMNJD4UBWQ4GQPETHSE4T2C75JB5B4RHN3DBD6KTX3VBLQC
NTFA3ZSJFTVLTTKI6ONJE33PGGDW36IVGWMO6GXRA4ZG57TOWNFAC
Y67JTRJI2257JT6OAZGAOREMVPR6JNAQNAFKKS4ZME5VYGORBPIAC
RRADDS444JWSL4KOJKNZFAIMWMZRLFR4KZPC2MJBCJPEPINC5CPQC
EIZC76IFTDKBNDJOX6YPFBOAOVAY6RSXH3JUWFLLGCZ3PYJMW3GQC
6JGTYQKIAHVHQIBZ6RKSLIRIQHE3EJZUEY4IOXU5TTN654JV7KHAC
JDPJS5SNW6ZTY5DYV5QUBG2WVJ45FJ4CAOK6KDJKPEI2HLIHVLRQC
RGHXFBNIULRVRYLBGG5JZDMYVM2E2JJ2Y5KQPMU6PUS3V26G6ZXQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
JDM27QE4HR52AYFSQE763BFF57ANOTF5MXKMO377PP5EXMN7SAOAC
W52PCSHX72WAMWKG6L4BPUBVMO6E72KYYBNKAA7554KNOTY6V7WQC
KXUQB3WNWC5IFL6VFWADEPQMMU3VV3NDI5FLA666PGOEWFYUHCLQC
34C4U6EQWERY75GZJKUCM5KVGU2OUICETS5LGZF6RMKMZT4R5SQAC
JTTHP2BEYEPBQMSDM7IKANTMKRPY6ACGL2JN4D3OBZ7HFXKAYEGQC
WW6THKR7JN447YC23YYHYYNH7ABMCFFSECNUFTIJBZX6JHX6W7TAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
RC6L3CIBLJEH4GWRFD7UQNGI6PZT74FRUVOYHSAN2XCC74NZUASQC
SCWXQW5H65OXUP2MEJ2MEEAVPSRJDT3RQGKYCMKVTORS2334PQSQC
TAHSTXR7ROOMDFUSBUU4ZAIEWQLAS5CIRCTARLD4Q2BGNLSL7E5QC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
KZNUAHJQUBM6MEVUSSWG734AXZ3NZYMRJ2XFQLRGXJ3MSTBV7ELQC
A3CO4KBFTFU3ZSHWRY2OPPX3MMTFV7OUCZGL7Q4Y2FU7JO4AP7MAC
ZJLJGSB2XSBQU42OFQMXL3EG4CXAQGOYAU6YTV2SAWZEJIPFH2CAC
NCDWWDJQLAU5ORSAQGZKJJ5E22VTDGGPJMVVBWQFHQ2B3U3UFHDQC
KFJEFN377VIZ7OH2XCYOGCELNEGO4CIOOP7DNXEMX3LFKIKWXVTAC
B3SRWSFITQMJRVEBHGQQJARETYPSSDV6XKMQSSUTXEHTXRZKIQJQC
AUXHSGS4EFOPZ6TVZYWNVOUDO7NYKUKE3HBKGQQWTALSVFOE3HAAC
ILOED4VB4I6VPAUTR75ZWX6MXDYXB5DO2EDK2UH67O3HNKWV23RQC
Z3RI4XAN7J2GUABAQ5G6YIOQYMBOAEQFFGRBWHMUEB2A2QYXO5MQC
XY77S75KH5KV54MZVAPMUC64TVRE2QM2KVJAAGJGCIBGQEC5GUTQC
XAFFD52IHN6FWFR2TT5F2KCUS7HAVCBI5CWTFMKPQG77GGTGAHLAC
MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC
EEPNZ3SHGXQ4NKLSWHI7X2WK3LU3AR2EDZZFFDGOXQQBK5LO5OYAC
Q2FZIIGQECGP2FKKWLGDBBQVGCFZ4JTY53PFPJP6X7YKC23AQGFQC
AVSMB4Y6F6ZMMNNPOAQQZ34OWC6N5JOURTEWFTUKDWMIIMLWWJUAC
KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC
int glyph_at(const coord_def &c) const;
public:
struct map_feature_finder
{
map_def ↦
map_feature_finder(map_def &map_) : map(map_) { }
// This may actually modify the underlying map by fixing KFEAT:
// feature slots, but that's fine by us.
dungeon_feature_type operator () (const coord_def &c) const
{
return (map_feature(&map, c, -1));
}
};
struct map_bounds_check
{
map_def ↦
map_bounds_check(map_def &map_) : map(map_) { }
bool operator () (const coord_def &c) const
{
return (c.x >= 0 && c.x < map.map.width()
&& c.y >= 0 && c.y < map.map.height());
}
};
std::vector<coord_def> map_def::find_glyph(int glyph) const
{
std::vector<coord_def> points;
for (int y = map.height() - 1; y >= 0; --y)
{
for (int x = map.width() - 1; x >= 0; --x)
{
const coord_def c(x, y);
if (map(c) == glyph)
points.push_back(c);
}
}
return (points);
}
coord_def map_def::find_first_glyph(int glyph) const
{
for (int y = 0, height = map.height(); y < height; ++y)
{
for (int x = 0, width = map.width(); x < width; ++x)
{
const coord_def c(x, y);
if (map(c) == glyph)
return (c);
}
}
return coord_def(-1, -1);
}
static int dgn_points_connected(lua_State *ls)
{
MAP(ls, 1, map);
const int nargs = lua_gettop(ls);
if (nargs < 5)
return luaL_error(ls,
"Not enough points to test connectedness "
"(need at least two)");
map_def::map_feature_finder feat_finder(*map);
map_def::map_bounds_check bounds_checker(*map);
flood_find<map_def::map_feature_finder, map_def::map_bounds_check>
finder(feat_finder, bounds_checker);
for (int i = 4; i < nargs; i += 2)
{
const coord_def c(luaL_checkint(ls, i),
luaL_checkint(ls, i + 1));
finder.add_point(c);
}
const coord_def pos(luaL_checkint(ls, 2), luaL_checkint(ls, 3));
const bool connected = finder.points_connected_from(pos);
PLUARET(boolean, connected);
}
static void dlua_push_coord(lua_State *ls, const coord_def &c)
{
lua_pushnumber(ls, c.x);
lua_pushnumber(ls, c.y);
}
static int dgn_gly_point(lua_State *ls)
{
MAP(ls, 1, map);
coord_def c = map->find_first_glyph(*luaL_checkstring(ls, 2));
if (c.x != -1 && c.y != -1)
{
dlua_push_coord(ls, c);
return (2);
}
return (0);
}
static int dgn_gly_points(lua_State *ls)
{
MAP(ls, 1, map);
std::vector<coord_def> cs = map->find_glyph(*luaL_checkstring(ls, 2));
for (int i = 0, size = cs.size(); i < size; ++i)
dlua_push_coord(ls, cs[i]);
return (cs.size() * 2);
}
static int dgn_original_map(lua_State *ls)
{
MAP(ls, 1, map);
if (map->original)
clua_push_map(ls, map->original);
else
lua_pushnil(ls);
return (1);
}
void place_spec_shop(int level_number, unsigned char shop_x,
unsigned char shop_y, unsigned char force_s_type,
bool representative = false );
//////////////////////////////////////////////////////////////////////////
template <typename fgrd, typename bound_check>
class flood_find : public travel_pathfind
{
public:
flood_find(const fgrd &f, const bound_check &bc);
bool unforbidden(const coord_def &c, const dgn_region_list &forbidden);
void add_feat(int feat);
void add_point(const coord_def &pos);
coord_def find_first_from(const coord_def &c, const dgn_region_list &vlts);
bool points_connected_from(const coord_def &start);
bool did_leave_vault() const { return left_vault; }
protected:
bool path_flood(const coord_def &c, const coord_def &dc);
protected:
bool point_hunt;
bool needed_features[NUM_FEATURES];
std::vector<coord_def> needed_points;
bool left_vault;
dgn_region_list vaults;
const fgrd &fgrid;
const bound_check &bcheck;
};
template <typename fgrd, typename bound_check>
flood_find<fgrd, bound_check>::flood_find(const fgrd &f, const bound_check &bc)
: travel_pathfind(), point_hunt(false), needed_features(),
needed_points(), left_vault(true), vaults(),
fgrid(f), bcheck(bc)
{
memset(needed_features, false, sizeof needed_features);
}
template <typename fgrd, typename bound_check>
void flood_find<fgrd, bound_check>::add_feat(int feat)
{
if (feat >= 0 && feat < NUM_FEATURES)
needed_features[feat] = true;
}
template <typename fgrd, typename bound_check>
coord_def
flood_find<fgrd, bound_check>::find_first_from(
const coord_def &c,
const dgn_region_list &vlts)
{
set_floodseed(c);
vaults = vlts;
return pathfind(RMODE_EXPLORE);
}
template <typename fgrd, typename bound_check>
void flood_find<fgrd, bound_check>::add_point(const coord_def &c)
{
needed_points.push_back(c);
}
template <typename fgrd, typename bound_check>
bool flood_find<fgrd, bound_check>::points_connected_from(
const coord_def &sp)
{
if (needed_points.empty())
return (true);
set_floodseed(sp);
pathfind(RMODE_EXPLORE);
return (needed_points.empty());
}
template <typename fgrd, typename bound_check>
bool flood_find<fgrd, bound_check>::path_flood(
const coord_def &c,
const coord_def &dc)
{
if (!bcheck(dc))
return (false);
if (!needed_points.empty())
{
std::vector<coord_def>::iterator i =
std::find(needed_points.begin(), needed_points.end(), dc);
if (i != needed_points.end())
{
needed_points.erase(i);
if (needed_points.empty())
return (true);
}
}
const dungeon_feature_type grid = fgrid(dc);
if (needed_features[ grid ])
{
unexplored_place = dc;
unexplored_dist = traveled_distance;
return (true);
}
if (!is_traversable(grid)
&& grid != DNGN_SECRET_DOOR
&& !grid_is_trap(grid))
{
return (false);
}
if (!left_vault && unforbidden(dc, vaults))
left_vault = true;
good_square(dc);
return (false);
}
//////////////////////////////////////////////////////////////////////////
class feature_find : public travel_pathfind
{
public:
feature_find();
void add_feat(int feat);
coord_def find_first_from(const coord_def &c);
bool did_leave_vault() const { return left_vault; }
protected:
bool path_flood(const coord_def &c, const coord_def &dc);
protected:
bool needed_features[NUM_FEATURES];
bool left_vault;
dgn_region_list vaults;
};
feature_find::feature_find()
: travel_pathfind(), needed_features(), left_vault(true), vaults()
{
memset(needed_features, false, sizeof needed_features);
}
void feature_find::add_feat(int feat)
{
if (feat >= 0 && feat < NUM_FEATURES)
needed_features[feat] = true;
}
coord_def feature_find::find_first_from(const coord_def &c)
{
set_floodseed(c);
for (int i = 0, size = level_vaults.size(); i < size; ++i)
{
const vault_placement &p = level_vaults[i];
vaults.push_back( dgn_region(p.x, p.y, p.width, p.height) );
}
return pathfind(RMODE_EXPLORE);
}
bool feature_find::path_flood(const coord_def &c, const coord_def &dc)
{
if (!in_bounds(dc))
return (false);
const dungeon_feature_type grid = grd(dc);
if (needed_features[ grid ])
{
unexplored_place = dc;
unexplored_dist = traveled_distance;
return (true);
}
if (!is_travelsafe_square(dc.x, dc.y, false, true)
&& grid != DNGN_SECRET_DOOR
&& !grid_is_trap(grid))
{
return (false);
}
if (!left_vault && unforbidden(dc, vaults))
left_vault = true;
good_square(dc);
return (false);
}
}
// Grr, keep this in sync with vault_grid.
dungeon_feature_type map_feature(map_def *map, const coord_def &c, int rawfeat)
{
if (rawfeat == -1)
rawfeat = map->glyph_at(c);
keyed_mapspec *mapsp = map? map->mapspec_for_key(rawfeat) : NULL;
if (mapsp)
{
const feature_spec f = mapsp->get_feat();
if (f.feat >= 0)
return static_cast<dungeon_feature_type>(f.feat);
else if (f.glyph >= 0)
return map_feature(NULL, c, rawfeat);
else if (f.shop >= 0)
return (DNGN_ENTER_SHOP);
else if (f.trap >= 0)
return (DNGN_UNDISCOVERED_TRAP);
return (DNGN_FLOOR);
}
return ((rawfeat == 'x') ? DNGN_ROCK_WALL :
(rawfeat == 'X') ? DNGN_PERMAROCK_WALL :
(rawfeat == 'c') ? DNGN_STONE_WALL :
(rawfeat == 'v') ? DNGN_METAL_WALL :
(rawfeat == 'b') ? DNGN_GREEN_CRYSTAL_WALL :
(rawfeat == 'a') ? DNGN_WAX_WALL :
(rawfeat == '+') ? DNGN_CLOSED_DOOR :
(rawfeat == '=') ? DNGN_SECRET_DOOR :
(rawfeat == 'w') ? DNGN_DEEP_WATER :
(rawfeat == 'W') ? DNGN_SHALLOW_WATER :
(rawfeat == 'l') ? DNGN_LAVA :
(rawfeat == '>') ? DNGN_ROCK_STAIRS_DOWN :
(rawfeat == '<') ? DNGN_ROCK_STAIRS_UP :
(rawfeat == '}') ? DNGN_STONE_STAIRS_DOWN_I :
(rawfeat == '{') ? DNGN_STONE_STAIRS_UP_I :
(rawfeat == ')') ? DNGN_STONE_STAIRS_DOWN_II :
(rawfeat == '(') ? DNGN_STONE_STAIRS_UP_II :
(rawfeat == ']') ? DNGN_STONE_STAIRS_DOWN_III :
(rawfeat == '[') ? DNGN_STONE_STAIRS_UP_III :
(rawfeat == 'A') ? DNGN_STONE_ARCH :
(rawfeat == 'B') ? DNGN_ALTAR_ZIN :
(rawfeat == 'C') ? pick_an_altar() : // f(x) elsewhere {dlb}
(rawfeat == 'F') ? DNGN_GRANITE_STATUE :
(rawfeat == 'I') ? DNGN_ORCISH_IDOL :
(rawfeat == 'S') ? DNGN_SILVER_STATUE :
(rawfeat == 'G') ? DNGN_GRANITE_STATUE :
(rawfeat == 'H') ? DNGN_ORANGE_CRYSTAL_STATUE :
(rawfeat == 'T') ? DNGN_BLUE_FOUNTAIN :
(rawfeat == 'U') ? DNGN_SPARKLING_FOUNTAIN :
(rawfeat == 'V') ? DNGN_PERMADRY_FOUNTAIN :
(rawfeat == '\0')? DNGN_ROCK_WALL :
DNGN_FLOOR); // includes everything else
end
end
--------------------------------------------------------------------
function dgn.places_connected(map, map_glyph, test_connect, ...)
local points = { }
for _, glyph in ipairs( { ... } ) do
local x, y = map_glyph(map, glyph)
if x and y then
table.insert(points, x)
table.insert(points, y)
else
error("Can't find coords for '" .. glyph .. "'")
end
end
return test_connect(map, unpack(points))
end
function dgn.glyphs_connected(map, ...)
return dgn.places_connected(map, dgn.gly_point, dgn.points_connected, ...)
end
function dgn.orig_glyphs_connected(map, ...)
return dgn.places_connected(map, dgn.orig_gly_point,
dgn.points_connected, ...)
end
function dgn.orig_fn(map, fnx, ...)
local original = dgn.original_map(map)
if not original then
error("Can't find original map for map '" .. dgn.name(map) .. "'")