git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@8169 c06c8d41-db1a-0410-9941-cceddc491573
OMAUFQNBWGX4FDABHQCVPGDYRVKMDASGQJVRH7AOPPEMHAP2LQSQC
2ZWSJ2ZV5VI4MYCBS4TNOE43VPKIMSLPWLVNFGRCGDQPD2PS6EXAC
UQZESUMXKG6SRYSP52RYO6EUX7TRLHRALAOX2S3HUGZMR2C5NDCQC
BSU7KFO5UGBSWPF2W7MWUWG42JJZ556H7PQG3BEZOZ53YPPLTZAAC
7DLDFEEB5IHCPN5VL2BBI7JM6SJB6M6FTYM2DMM6R6QV33COOA6QC
JQKRFPNPLYBHUWMVQLPX5UB5RRP5PKY6NQ5LRHJRIOY6IKN2AH6AC
XIFNWKKXBHUZG52JL2PICXF4C3I5HDGFAEU2CHHVBXNT75WQE5NAC
SIDH2P7NBIG5KEOE27XHD3ZT2NQ2OJZFN6VZXWNWYFFY5YVXSSVQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC
B7DNCNY7SXL5WAW5B3XZP5KIQSBWOJ3N2YW46WOUQKTRBRRZ7YOQC
AO3KHGKGSX2ZR24KJVIOTUY7EHYHMMI5W4HN3CAG4YGQHBOHLGDQC
KIDHPMZSLUVK3TF4565MH7SJ57C45SORJXR274VJTOULNOTGHQ4AC
VTJOYDSSNQZOK23N65C64NUGDTGPL6QZWGCALRQHQDQXAPYBRKMAC
BW6QCGQDWZ6G2UGDD4EXI5VVDZHM5S53MJIC5CKG3Q3VQ4IDQ2VQC
ZVK4J5HTKFNOOIVCI62ZWEYGXEE5TYJ65DLYYZAZWTADFSXE62ZAC
MT3256427VMCV4JUFWCN7ULY4KXSND5ZL5THDKYNWWYOXXR5DLIQC
IVVTHLTTLOP5TSULXJWUSSXHOKYWVU3OWKYVK45A7RIB6V34MYQAC
ZJLJGSB2XSBQU42OFQMXL3EG4CXAQGOYAU6YTV2SAWZEJIPFH2CAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
JR4ZZK4HOXQIG3WXBGTPZAPPNF7HHBCUZ3TE7RBCS64NHCOX7B2QC
KTRWLM6WDL4GAAJZNLQEEA3TGY2OKYZZUAAT4TCAVKRTR2NQBWUQC
CREW3VTGN2BV622ZXHCPHUEZWBAGEQMNUELDLTHLEKG4VBXGMRPQC
KCHX2F3JFEWOZT3WMJVZAAQUU2QSZ5Q7RDCD7WUJ7VE65J52JFUQC
PISXY4NKSKL5KDJWAHD7CTXWTQDH3NFWQSFAHUAI3VVATWKXRODQC
FSD7GIK3YLZXWLEH37BU6KV3IUCFGXPQL6IZ7H65YWNRBEKDBX5AC
NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC
ILOED4VB4I6VPAUTR75ZWX6MXDYXB5DO2EDK2UH67O3HNKWV23RQC
FQ7XALBL6NZAGBKKYIFHYQ7MUWIHR4TEU4TCS33EG4I3JTND5SQAC
KSCU43RIVSEIHTN6BRAKXENI66L3IRDZQHUBT5VS4NJBBCQQPHUQC
SM6YRPYZS6LMDQA6X3VAOK2PGMUFKPD7JMWJISOQSMX2CBR4ISPAC
AUXHSGS4EFOPZ6TVZYWNVOUDO7NYKUKE3HBKGQQWTALSVFOE3HAAC
NKONHW4JNY6HP2M63MNPM3H64ZWSUNUT5FX2STW4KTS4AMXJXXVQC
4N5PW5S3OV25HFN634NNWMMYX26NA2TB6TVFG4UMYSZ2VBJWKE4QC
B7MSPF6X2RLGWN4M6ZZF3WSOPKGYPTTD7LIJVST7DXN27DG6JHNAC
HZK3YN3SAISTDS5JI4COBYFG7YB4ABDVENXWZZEYLFA2LDI232VAC
AOLWOUIFBQDQTCMSVB7N7GAKFUY5J5LH7CJZAY3HEY3WEUSLADZAC
45EMD3KLQPMERNMIKU5G76H6556XOMIW352TSBP7VLWJX2YYGS7AC
SH6NU4H5TG4O7CRXRHZ7MDHABZLWWXQ77NJDBHI7KCVHXHQYK46QC
GQL5SIGBHLU3FMCE54XVGLRY5AZHRM6DUEB722REA2DPLGJSN6EQC
EJ4GIPFSSQCQASUMRF4CR2WPUQOTEHFRGLOYEZ7BH6YEMIR6DN4QC
AYAQKTO6HOZJ44NDH5UIP6WFNB54Z5EZ4UMUISIQ67ZOIDB6OIQAC
ANBVGN4RZOMY5LI4QSHOV2477FN55H353ZYLSVCPTXC7AWWSQZBAC
6QWZDCP5HGYLTJO3WWYJJGRRT7QFY6IG64TC7TUB553Z7GAA2HIQC
KXUQB3WNWC5IFL6VFWADEPQMMU3VV3NDI5FLA666PGOEWFYUHCLQC
FIYBXLWALQINNQTHG2KNDUUTAQAZRDDLXW2XOVSKDKBADJ3XCJ4AC
KKNUX66ORZWWQH4ARKCHPHNDOYCI65STE3A27LKA3FWUKIX7MAXQC
34C4U6EQWERY75GZJKUCM5KVGU2OUICETS5LGZF6RMKMZT4R5SQAC
43NBC6HJOFQQTASUMC5W7MWLS355ASIUS7SEFRO6PJWQDY7MRZZQC
FKRLQJYHK3GB6HHSNNFQ7L57ZAR52LSTBG5B6SNJBYZ2LQ36P67AC
3UKFCWWS5BLFQWZRB5FUA46CE2XGX5VRCEWC3K3XH5RCGQK64N2AC
56C44YMFHZ62GXAAOLYSLLGBVGRWXB53W2VI37Q26ZECEK2XG5SQC
UOW2X5KTUHYCM73SWNOSJPHUKWVLF3OJTNSISSSENEURBX2XWHVQC
ZJU5Z2WDMI7HN4XJ3NVTVRHIZO2CGFUQ2FSKIRJVTQG47XHNCZFQC
C22455VGUQOSUX2OORA32LROFQ7NNYDMD2ZDTTUZSAQLXK4AD6QAC
4RFKVDJKTCRBZU6WPJ2E5OVI5IRPY3UTRPOBLC5QHY4CQJJTLZKQC
CUNNC574MESEMTTONZ6YB6CJ2S5P6VA3V7Z3OODESWAK37GYOBPAC
W45PMU4HNPSAMMEBJ4XH4MTHLPVIASZT4FXTBPID5LFXKIMNUBKAC
UEI5JAVCMN7Y2SACTEZPZSNFJWOJTC55G24Q6LKQCT4XNDH5ZQIAC
AF7VAKCSGEYCXRTITS2WAW7VTM3OEQOECMNXR6YMOQLBCVZZFAVQC
2YSMM7QMFZOPD5NXAD2OAMDJEY5LOZO4NCYBC7UCQVANKINJRNBAC
6CHNAAPWNROCQNX6EWPLXZOWX5HHKL5ZOHO24XRMNQTQF3CWB3VQC
SCWXQW5H65OXUP2MEJ2MEEAVPSRJDT3RQGKYCMKVTORS2334PQSQC
A3CO4KBFTFU3ZSHWRY2OPPX3MMTFV7OUCZGL7Q4Y2FU7JO4AP7MAC
ECJNCUSSE63BKED3EAYIXQCI62I76QGNHCSFO3CDWPRZF3JQP44QC
CPBVQFT7NWEYLYD34D5VYZIEOZ32YADXYTSFMS635YNXX4OFIZVAC
JT672SIJK4BOIUAGL2WQ6NR2NF4PSWP3BT6Q4HMNRF25UN6JQ2MAC
K6ELQ4HEZYDROC7CJFLPJS64AAJQ4G6RVLL4GBRUG6FJMKSBDDIQC
L6O4LGZRKBURVWEY7XRVCSQLJ5RULNBEWMQJ6I2UYVWWB66FM3MQC
J7GPW2YXLT6FGSKJ24FGQ24GTRZ6A2BDYM6CIXV4R6YBEHP6BGPAC
6ZQY6HMQHBIQP6RPQZTK4KJ6YGCW2SJJUYHGI6UVATES5GKJRP7QC
XAFFD52IHN6FWFR2TT5F2KCUS7HAVCBI5CWTFMKPQG77GGTGAHLAC
OY7KHQPESOUHPBXRZ2JSNUKPAC7DCDY73TAUHCSJG5V6TPAHBVYQC
IHV7JHD4E67NEGLZEO3FPQGJPJF3IAV6QV5A63FPG4SU2VRFV47QC
X7MFMKQTNZ2IWBFVGS6WQV7NRNKJ3DWQAW2X7IQMFQQXW24AHPZQC
PKXXBHS3LWLPZI2QVRX22MSQ4R2626IXRSNHFFYHXYTLJJQU54LQC
TLA5UN6LZPXGKERI27EFY4HKIIU3VU5Y7ZU54WXL6ANBUV2VOTMQC
ILN2K6ASDZSMEHOPJ22IZLZJUO6DDGZTKAKXM3YXG6JZZHJNLX4AC
R6XS2HO5QX2FJUGL5UQQRNETKCMYWTUFPHPPS5SYWK3OQA4UDUQQC
BPPMLLPJLP6W2LZSPAMOMYA7YWCIFJTNNL3XBWU2MRHAQBZ5M4XAC
ZTDYCQQQQSLWGFJOUB3HKGHMJLNY6UHF4OOC2XVVHXSZTTZK5A5AC
MXOCLQAUGWLOS7AOTYZ46JZDMRL4EVRK5YN4JJUQ76GLKBOBHEVAC
// Return value of zero forces dungeon.cc to regenerate the level, except
// for branch entry vaults where dungeon.cc just rejects the vault and
// places a vanilla entry.
// Return value of MAP_NONE forces dungeon.cc to regenerate the
// level, except for branch entry vaults where dungeon.cc just
// rejects the vault and places a vanilla entry.
}
// Determines if the region specified by (x, y, x + width - 1, y + height - 1)
// is a bad place to build a vault.
static bool bad_map_place(const map_def &map, const coord_def &c,
const coord_def &size)
{
const std::vector<std::string> &lines = map.map.get_lines();
for (rectangle_iterator r(c, c + size - 1); r; ++r)
{
const coord_def &p(*r);
const coord_def dp = p - c;
if (lines[dp.y][dp.x] == ' ')
continue;
if (dgn_Map_Mask[p.x][p.y])
return (true);
if (igrd(p) != NON_ITEM || mgrd(p) != NON_MONSTER)
return (true);
const dungeon_feature_type grid = grd(p);
if (!grid_is_opaque(grid)
&& grid != DNGN_FLOOR
&& grid != DNGN_SHALLOW_WATER
&& grid != DNGN_CLOSED_DOOR
&& grid != DNGN_OPEN_DOOR
&& grid != DNGN_SECRET_DOOR)
{
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS,
"Rejecting place because of %s at (%d,%d)",
dungeon_feature_name(grid), p.x, p.y);
#endif
return (true);
}
}
return (false);
}
// Used for placement of vaults.
static bool _may_overwrite_feature(const dungeon_feature_type grid,
bool water_ok, bool wall_ok = true)
{
// Deep water grids may be overwritten if water_ok == true.
if (grid == DNGN_DEEP_WATER)
return (water_ok);
// Handle all other non-LOS blocking grids here.
if (!grid_is_opaque(grid)
&& grid != DNGN_FLOOR
&& grid != DNGN_SHALLOW_WATER
&& grid != DNGN_CLOSED_DOOR
&& grid != DNGN_OPEN_DOOR
&& grid != DNGN_SECRET_DOOR)
{
return (false);
}
if (grid_is_wall(grid))
return (wall_ok);
// Otherwise, feel free to clobber this feature.
return (true);
}
static bool _safe_vault_place(const map_def &map,
const coord_def &c,
const coord_def &size)
{
if (size.zero())
return (true);
const bool water_ok = map.has_tag("water_ok");
const std::vector<std::string> &lines = map.map.get_lines();
for (rectangle_iterator ri(c, c + size - 1); ri; ++ri)
{
const coord_def &cp(*ri);
const coord_def &dp(cp - c);
if (lines[dp.y][dp.x] == ' ')
continue;
if (dgn_Map_Mask[cp.x][cp.y])
return (false);
const dungeon_feature_type dfeat = grd(cp);
// Don't overwrite features other than floor, rock wall, doors,
// nor water, if !water_ok.
if (!_may_overwrite_feature(dfeat, water_ok))
return (false);
// Don't overwrite items or monsters, either!
if (igrd(cp) != NON_ITEM || mgrd(cp) != NON_MONSTER)
return (false);
}
return (true);
}
static bool _connected_minivault_place(const coord_def &c,
const vault_placement &place)
{
if (place.size.zero())
return (true);
// Must not be completely isolated.
const bool water_ok = place.map.has_tag("water_ok");
const std::vector<std::string> &lines = place.map.map.get_lines();
for (rectangle_iterator ri(c, c + place.size - 1); ri; ++ri)
{
const coord_def &ci(*ri);
if (lines[ci.y - c.y][ci.x - c.x] == ' ')
continue;
if (_may_overwrite_feature(grd(ci), water_ok, false))
return (true);
}
return (false);
}
static coord_def _find_minivault_place(
const vault_placement &place,
bool check_place)
{
// [ds] The margin around the edges of the map where the minivault
// won't be placed. Purely arbitrary as far as I can see.
const int margin = MAPGEN_BORDER * 2;
// Find a target area which can be safely overwritten.
for (int tries = 0; tries < 600; ++tries)
{
coord_def v1(random_range( margin, GXM - margin - place.size.x ),
random_range( margin, GYM - margin - place.size.y ));
if (check_place && !map_place_valid(place.map, v1, place.size))
continue;
if (_connected_minivault_place(v1, place))
return (v1);
}
return (coord_def(-1, -1));
static bool _build_minivaults(int level_number,
const map_def *vault,
bool clobber = false,
bool make_no_exits = false,
const coord_def &where = coord_def() );
const map_def *vault = random_map_for_tag("shoal_rune", true);
_build_minivaults( level_number, vault, false, false,
centres[1] );
const map_def *vault = random_map_for_tag("shoal_rune");
_build_secondary_vault(level_number, vault, -1, false, false,
centres[1]);
}
int chance = you.your_level == 0? 50 : 100;
while (chance && x_chance_in_y(chance, 100) || nvaults-- > 0)
{
const map_def *vault = _dgn_random_map_for_place(true);
if (!vault)
break;
_build_minivaults(you.your_level, vault);
chance /= 4;
// ORIENT: encompass maps are unsuitable as secondary vaults.
if (vault && vault->orient == MAP_ENCOMPASS)
vault = NULL;
// Used for placement of vaults.
static bool _may_overwrite_feature(const dungeon_feature_type grid,
bool water_ok, bool rock_ok = true)
{
// Floor, and closed/secret doors may always be overwritten.
if (grid == DNGN_FLOOR
|| grid == DNGN_CLOSED_DOOR || grid == DNGN_SECRET_DOOR)
{
return (true);
}
if (grid == DNGN_ROCK_WALL)
return (rock_ok);
// Watery grids may be overwritten if water_ok == true.
if (grid == DNGN_DEEP_WATER || grid == DNGN_SHALLOW_WATER)
return (water_ok);
// Otherwise, don't overwrite this feature.
return (false);
}
static bool _safe_minivault_place(int v1x, int v1y,
const vault_placement &place,
bool clobber)
{
if (clobber)
return (true);
const bool water_ok = place.map.has_tag("water_ok");
const std::vector<std::string> &lines = place.map.map.get_lines();
for (int vx = v1x; vx < v1x + place.size.x; vx++)
for (int vy = v1y; vy < v1y + place.size.y; vy++)
{
if (lines[vy - v1y][vx - v1x] == ' ')
continue;
if (dgn_Map_Mask[vx][vy])
return (false);
const dungeon_feature_type dfeat = grd[vx][vy];
// Don't overwrite features other than floor, rock wall, doors,
// nor water, if !water_ok.
if (!_may_overwrite_feature(dfeat, water_ok))
return (false);
// Don't overwrite items or monsters, either!
if (igrd[vx][vy] != NON_ITEM || mgrd[vx][vy] != NON_MONSTER)
return (false);
}
return (true);
}
static bool _connected_minivault_place(int v1x, int v1y,
const vault_placement &place)
{
// Must not be completely isolated.
const bool water_ok = place.map.has_tag("water_ok");
const std::vector<std::string> &lines = place.map.map.get_lines();
for (int vx = v1x; vx < v1x + place.size.x; vx++)
for (int vy = v1y; vy < v1y + place.size.y; vy++)
{
if (lines[vy - v1y][vx - v1x] == ' ')
continue;
// Overwrite floor, doors or water, but not rock walls.
if (_may_overwrite_feature(grd[vx][vy], water_ok, false))
return (true);
}
return (false);
}
static bool _find_minivault_place(const vault_placement &place,
coord_def& v1, bool clobber)
{
// [ds] The margin around the edges of the map where the minivault
// won't be placed. Purely arbitrary as far as I can see.
const int margin = MAPGEN_BORDER * 2;
// Find a target area which can be safely overwritten.
for (int tries = 0; tries < 600; ++tries)
{
v1.x = random_range( margin, GXM - margin - place.size.x );
v1.y = random_range( margin, GYM - margin - place.size.y );
if (!_safe_minivault_place( v1.x, v1.y, place, clobber ))
continue;
if (_connected_minivault_place(v1.x, v1.y, place))
return (true);
}
return (false);
}
static bool _build_minivaults(int level_number, const map_def *vault,
bool clobber, bool make_no_exits,
const coord_def &where)
{
if (dgn_check_connectivity && !dgn_zones)
dgn_zones = _dgn_count_disconnected_zones(false);
vault_placement place;
place.level_number = level_number;
vault_main(place, vault);
coord_def v1;
// Not map_bounds, minivaults should never touch edge.
if (in_bounds(where))
{
coord_def tl(where - place.size / 2);
fit_region_into_map_bounds(tl, place.size, 1);
v1 = tl;
}
else if (!_find_minivault_place(place, v1, clobber))
return (false);
place.pos = v1;
Level_Vaults.push_back(place);
#ifdef DEBUG_DIAGNOSTICS
if (crawl_state.map_stat_gen)
mapgen_report_map_use(place.map);
#endif
dgn_register_place(place, true);
place.apply_grid();
if (!make_no_exits)
{
// This is a throwaway.
std::vector<coord_def> &target_connections = place.exits;
if (target_connections.empty() && place.map.has_tag("mini_float"))
_pick_float_exits(place, target_connections);
if (!target_connections.empty())
_connect_vault(place);
}
return (true);
} // end build_minivaults()
if (mdef->is_minivault())
{
did_map = _build_minivaults(you.your_level, mdef, clobber,
make_no_exits, where);
}
else
{
dungeon_feature_type rune_subst = DNGN_FLOOR;
if (mdef->has_tag_suffix("_entry"))
rune_subst = _dgn_find_rune_subst_tags(mdef->tags);
did_map = _build_secondary_vault(you.your_level, mdef, rune_subst,
clobber, make_no_exits, where);
}
dungeon_feature_type rune_subst = DNGN_FLOOR;
if (mdef->has_tag_suffix("_entry"))
rune_subst = _dgn_find_rune_subst_tags(mdef->tags);
did_map = _build_secondary_vault(you.your_level, mdef, rune_subst,
clobber, make_no_exits, where);
Minivaults are distinguished from normal vaults solely by the absence of an
ORIENT: declaration. Any map without a specified ORIENT: is a minivault.
1. Floating vaults may be placed before the rest of the level layout
is generated, and the rest of the level may be built around the floating
vault. This is never the case for minivaults.
2. Floating vaults may be placed anywhere in the map, including places
completely separated from the rest of the level by rock. The
dungeon builder will then connect the exits from the floating vault
to the rest of the level, usually producing obvious "passages" from
the floating vault to the main body of the level.
In contrast, minivaults are placed such that at least one square of
the minivault overlaps with an existing part of the level, and are
thus more likely to look like part of the level. Unlike floating
vaults, the dungeon builder assumes that any one square of overlap
is enough to connect the minivault to the rest of the level and
makes no effort to connect exits from the minivault to the level.
You can ask the dungeon builder to connect exits from your
minivault with the "mini_float" tag.