end of level generation do not isolate parts of the level that were not already isolated. This does not apply to weird level-types such as Labyrinths and the Abyss.
Added level veto stats to -mapstat output.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1831 c06c8d41-db1a-0410-9941-cceddc491573
2YSMM7QMFZOPD5NXAD2OAMDJEY5LOZO4NCYBC7UCQVANKINJRNBAC
HZK3YN3SAISTDS5JI4COBYFG7YB4ABDVENXWZZEYLFA2LDI232VAC
QFWQG7G6KTZX3GP52K3N4BDWLMNH7A3A5ILJLXDIK6PYYLF3KO3AC
OYTCBRC7LE44EUVRZVYTOOVKQWJ6P6YE3FXTOGUTNKEMLNWPHKSQC
C22455VGUQOSUX2OORA32LROFQ7NNYDMD2ZDTTUZSAQLXK4AD6QAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
6QWZDCP5HGYLTJO3WWYJJGRRT7QFY6IG64TC7TUB553Z7GAA2HIQC
SCWXQW5H65OXUP2MEJ2MEEAVPSRJDT3RQGKYCMKVTORS2334PQSQC
XAFFD52IHN6FWFR2TT5F2KCUS7HAVCBI5CWTFMKPQG77GGTGAHLAC
ZJLJGSB2XSBQU42OFQMXL3EG4CXAQGOYAU6YTV2SAWZEJIPFH2CAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
WLX2RQMMOMP2PYPAGJRM4VFD2WTLJTOAZZPPY3MV76FU2EGEJ54QC
KXUQB3WNWC5IFL6VFWADEPQMMU3VV3NDI5FLA666PGOEWFYUHCLQC
3XZOL3FFQZITUJIGDD6B6V6ZYMBN524JKNN6ZPJAXEC7RY433I3QC
4RFKVDJKTCRBZU6WPJ2E5OVI5IRPY3UTRPOBLC5QHY4CQJJTLZKQC
WWR4IDWLXP4XLBWDZBA5GFG7CRKUJQNRK7FFUFOISK6OJTMYQPFQC
TZ55IZNANEJO2WDTKYWVLY2W2VV6BR7WKIN7XLNISAMMFT6LG2WQC
ZVK4J5HTKFNOOIVCI62ZWEYGXEE5TYJ65DLYYZAZWTADFSXE62ZAC
ECJNCUSSE63BKED3EAYIXQCI62I76QGNHCSFO3CDWPRZF3JQP44QC
}
static inline bool dgn_grid_is_isolating(const dungeon_feature_type grid)
{
// Rock wall check is superfluous, but is the most common case.
return (grid == DNGN_ROCK_WALL
|| (grid_is_solid(grid) && grid != DNGN_CLOSED_DOOR
&& grid != DNGN_SECRET_DOOR));
}
// Counts the number of mutually unreachable areas in the map,
// excluding isolated zones within vaults (we assume the vault author
// knows what she's doing). This is an easy way to check whether a map
// has isolated parts of the level that were not formerly isolated.
//
// All squares within vaults are treated as non-reachable, to simplify
// life, because vaults may change the level layout and isolate
// different areas without changing the number of isolated areas.
// Here's a before and after example of such a vault that would cause
// problems if we considered floor in the vault as non-isolating (the
// vault is represented as V for walls and o for floor squares in the
// vault).
//
// Before:
//
// xxxxx xxxxx
// x<..x x.2.x
// x.1.x xxxxx 3 isolated zones
// x>..x x.3.x
// xxxxx xxxxx
//
// After:
//
// xxxxx xxxxx
// x<1.x x.2.x
// VVVVVVVVVVoooV 3 isolated zones, but the isolated zones are different.
// x>3.x x...x
// xxxxx xxxxx
//
static int dgn_count_disconnected_zones()
{
memset(travel_point_distance, 0, sizeof(travel_distance_grid_t));
int nzones = 0;
for (int y = 0; y < GYM; ++y)
{
for (int x = 0; x < GXM; ++x)
{
if (travel_point_distance[x][y] || dgn_map_mask[x][y])
continue;
if (dgn_grid_is_isolating(grd[x][y]))
continue;
dgn_fill_zone(coord_def(x, y), ++nzones);
}
}
return (nzones);
static void dgn_fill_zone(const coord_def &c, int zone)
{
// No bounds checks, assuming the level has at least one layer of
// rock border.
travel_point_distance[c.x][c.y] = zone;
for (int yi = -1; yi <= 1; ++yi)
{
for (int xi = -1; xi <= 1; ++xi)
{
if (!xi && !yi)
continue;
const coord_def cp(c.x + xi, c.y + yi);
if (travel_point_distance[cp.x][cp.y]
|| dgn_map_mask(cp)
|| dgn_grid_is_isolating(grd(cp)))
{
continue;
}
dgn_fill_zone(cp, zone);
}
}
}
static void dgn_verify_connectivity(unsigned nvaults)
{
// After placing vaults, make sure parts of the level have not been
// disconnected.
if (!dgn_level_vetoed && dgn_zones && nvaults != level_vaults.size())
{
const int newzones = dgn_count_disconnected_zones();
if (newzones > dgn_zones)
{
dgn_level_vetoed = true;
#ifdef DEBUG_DIAGNOSTICS
std::ostringstream vlist;
for (unsigned i = nvaults; i < level_vaults.size(); ++i)
{
if (i > nvaults)
vlist << ", ";
vlist << level_vaults[i].map.name;
}
mprf(MSGCH_DIAGNOSTICS,
"VETO: %s broken by [%s] (had %d zones, "
"now have %d zones.",
level_id::current().describe().c_str(),
vlist.str().c_str(), dgn_zones, newzones);
#endif
}
}
}
// Try to place minivaults that really badly want to be placed. Still
// no guarantees, seeing this is a minivault.
if (!player_in_branch(BRANCH_SHOALS))
place_special_minivaults(level_number, level_type);
const unsigned nvaults = level_vaults.size();
// Any further vaults must make sure not to disrupt level layout.
dgn_check_connectivity = true;
// Try to place minivaults that really badly want to be placed. Still
// no guarantees, seeing this is a minivault.
if (!player_in_branch(BRANCH_SHOALS))
place_special_minivaults(level_number, level_type);
place_branch_entrances( level_number, level_type );
place_extra_vaults();
dgn_verify_connectivity(nvaults);
if (dgn_level_vetoed)
return;
if (!player_in_branch( BRANCH_ECUMENICAL_TEMPLE ))
place_traps(level_number);
if (mg_vetoes)
{
fprintf(outf, "\n\nMost vetoed levels:\n");
std::multimap<int, level_id> sortedvetos;
for (std::map< level_id, std::pair<int, int> >::const_iterator
i = mapgen_map_builds.begin(); i != mapgen_map_builds.end();
++i)
{
if (!i->second.second)
continue;
sortedvetos.insert(
std::pair<int, level_id>( i->second.second, i->first ));
}
int count = 0;
for (std::multimap<int, level_id>::reverse_iterator
i = sortedvetos.rbegin(); i != sortedvetos.rend(); ++i)
{
const int vetoes = i->first;
const int tries = mapgen_map_builds[i->second].first;
fprintf(outf, "%3d) %s (%d of %d vetoed, %.2f%%)\n",
++count, i->second.describe().c_str(),
vetoes, tries, vetoes * 100.0 / tries);
}
}