Use cell_is_solid where appropriate.
[crawl:crawl.git] / crawl-ref / source / dungeon.cc
1 /**
2  * @file
3  * @brief Functions used when building new levels.
4 **/
5
6 #include "AppHdr.h"
7
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <time.h>
11 #include <list>
12 #include <map>
13 #include <set>
14 #include <sstream>
15 #include <algorithm>
16 #include <cmath>
17
18 #include "abyss.h"
19 #include "acquire.h"
20 #include "artefact.h"
21 #include "branch.h"
22 #include "chardump.h"
23 #include "coordit.h"
24 #include "defines.h"
25 #include "describe.h"
26 #include "dgn-delve.h"
27 #include "dgn-height.h"
28 #include "dgn-shoals.h"
29 #include "dgn-swamp.h"
30 #include "dgn-labyrinth.h"
31 #include "dgn-layouts.h"
32 #include "effects.h"
33 #include "env.h"
34 #include "enum.h"
35 #include "map_knowledge.h"
36 #include "flood_find.h"
37 #include "fprop.h"
38 #include "externs.h"
39 #include "dbg-maps.h"
40 #include "dbg-scan.h"
41 #include "directn.h"
42 #include "dungeon.h"
43 #include "files.h"
44 #include "ghost.h"
45 #include "itemname.h"
46 #include "itemprop.h"
47 #include "items.h"
48 #include "l_defs.h"
49 #include "lev-pand.h"
50 #include "libutil.h"
51 #include "makeitem.h"
52 #include "mapdef.h"
53 #include "mapmark.h"
54 #include "maps.h"
55 #include "message.h"
56 #include "misc.h"
57 #include "mon-chimera.h"
58 #include "mon-util.h"
59 #include "mon-pick-data.h"
60 #include "mon-place.h"
61 #include "mgen_data.h"
62 #include "mon-pathfind.h"
63 #include "notes.h"
64 #include "place.h"
65 #include "player.h"
66 #include "random.h"
67 #include "religion.h"
68 #include "spl-book.h"
69 #include "spl-transloc.h"
70 #include "spl-util.h"
71 #include "state.h"
72 #include "stuff.h"
73 #include "tags.h"
74 #include "terrain.h"
75 #include "tiledef-dngn.h"
76 #include "tilepick.h"
77 #include "tileview.h"
78 #include "traps.h"
79 #include "travel.h"
80 #include "zotdef.h"
81 #include "hints.h"
82
83 #ifdef DEBUG_DIAGNOSTICS
84 #define DEBUG_TEMPLES
85 #endif
86
87 #ifdef WIZARD
88 #include "cio.h" // for cancellable_get_line()
89 #endif
90
91 // DUNGEON BUILDERS
92 static bool _build_level_vetoable(bool enable_random_maps,
93                                   dungeon_feature_type dest_stairs_type);
94 static void _build_dungeon_level(dungeon_feature_type dest_stairs_type);
95 static bool _valid_dungeon_level();
96
97 static bool _builder_by_type();
98 static bool _builder_normal();
99 static void _builder_items();
100 static void _builder_monsters();
101 static coord_def _place_specific_feature(dungeon_feature_type feat);
102 static void _place_spec_shop(const coord_def& where,
103                              shop_spec* spec, bool representative = false);
104 static bool _place_specific_trap(const coord_def& where, trap_spec* spec,
105                                  int charges = 0);
106 static void _place_branch_entrances(bool use_vaults);
107 static void _place_extra_vaults();
108 static void _place_chance_vaults();
109 static void _place_minivaults(void);
110 static int _place_uniques();
111 static void _place_traps();
112 static void _prepare_water();
113 static void _check_doors();
114
115 static void _add_plant_clumps(int frequency = 10, int clump_density = 12,
116                               int clump_radius = 4);
117
118 static void _pick_float_exits(vault_placement &place,
119                               vector<coord_def> &targets);
120 static bool _feat_is_wall_floor_liquid(dungeon_feature_type);
121 static bool _connect_spotty(const coord_def& from,
122                             bool (*overwriteable)(dungeon_feature_type) = NULL);
123 static bool _connect_vault_exit(const coord_def& exit);
124
125 // ITEM & SHOP FUNCTIONS
126 static object_class_type _item_in_shop(shop_type shop_type);
127
128 // VAULT FUNCTIONS
129 static const vault_placement *
130 _build_secondary_vault(const map_def *vault,
131                        bool check_collisions = true,
132                        bool make_no_exits = false,
133                        const coord_def &where = coord_def(-1, -1));
134
135 static const vault_placement *_build_primary_vault(const map_def *vault);
136
137 static void _build_postvault_level(vault_placement &place);
138 static const vault_placement *
139 _build_vault_impl(const map_def *vault,
140                   bool build_only = false,
141                   bool check_collisions = false,
142                   bool make_no_exits = false,
143                   const coord_def &where = coord_def(-1, -1));
144
145 static void _vault_grid(vault_placement &,
146                         int vgrid,
147                         const coord_def& where,
148                         keyed_mapspec *mapsp);
149 static void _vault_grid_mons(vault_placement &,
150                         int vgrid,
151                         const coord_def& where,
152                         keyed_mapspec *mapsp);
153 static void _vault_grid_glyph(vault_placement &place, const coord_def& where,
154                               int vgrid);
155 static void _vault_grid_mapspec(vault_placement &place, const coord_def& where,
156                                 keyed_mapspec& mapsp);
157 static dungeon_feature_type _vault_inspect(vault_placement &place,
158                                            int vgrid, keyed_mapspec *mapsp);
159 static dungeon_feature_type _vault_inspect_mapspec(vault_placement &place,
160                                                    keyed_mapspec& mapsp);
161 static dungeon_feature_type _vault_inspect_glyph(vault_placement &place,
162                                                  int vgrid);
163
164 static const map_def *_dgn_random_map_for_place(bool minivault);
165 static void _dgn_load_colour_grid();
166 static void _dgn_map_colour_fixup();
167
168 static void _dgn_unregister_vault(const map_def &map);
169 static void _remember_vault_placement(const vault_placement &place, bool extra);
170
171 // Returns true if the given square is okay for use by any character,
172 // but always false for squares in non-transparent vaults.
173 static bool _dgn_square_is_passable(const coord_def &c);
174
175 static coord_def _dgn_random_point_in_bounds(
176     dungeon_feature_type searchfeat,
177     uint32_t mapmask = MMT_VAULT,
178     dungeon_feature_type adjacent = DNGN_UNSEEN,
179     bool monster_free = false,
180     int tries = 1500);
181
182 // ALTAR FUNCTIONS
183 static int                  _setup_temple_altars(CrawlHashTable &temple);
184 static dungeon_feature_type _pick_temple_altar(vault_placement &place);
185 static dungeon_feature_type _pick_an_altar();
186
187 static vector<god_type> _temple_altar_list;
188 static CrawlHashTable*       _current_temple_hash = NULL; // XXX: hack!
189
190 // MISC FUNCTIONS
191 static void _dgn_set_floor_colours();
192 static bool _fixup_interlevel_connectivity();
193 static void _slime_connectivity_fixup();
194
195 static void _dgn_postprocess_level();
196 static void _calc_density();
197 static void _mark_solid_squares();
198
199 //////////////////////////////////////////////////////////////////////////
200 // Static data
201
202 // A mask of vaults and vault-specific flags.
203 vector<vault_placement> Temp_Vaults;
204 static FixedBitVector<NUM_MONSTERS> temp_unique_creatures;
205 static FixedVector<unique_item_status_type, MAX_UNRANDARTS> temp_unique_items;
206
207 const map_bitmask *Vault_Placement_Mask = NULL;
208
209 static bool use_random_maps = true;
210 static bool dgn_check_connectivity = false;
211 static int  dgn_zones = 0;
212
213 static vector<string> _you_vault_list;
214
215 class dgn_veto_exception : public exception
216 {
217 public:
218     dgn_veto_exception(const string& _msg) : msg(_msg) { }
219     ~dgn_veto_exception() throw () { }
220     const char *what() const throw ()
221     {
222         return msg.c_str();
223     }
224 private:
225     string msg;
226 };
227
228 struct coloured_feature
229 {
230     dungeon_feature_type feature;
231     int                  colour;
232
233     coloured_feature() : feature(DNGN_UNSEEN), colour(BLACK) { }
234     coloured_feature(dungeon_feature_type f, int c)
235         : feature(f), colour(c)
236     {
237     }
238 };
239
240 struct dgn_colour_override_manager
241 {
242     dgn_colour_override_manager()
243     {
244         _dgn_load_colour_grid();
245     }
246
247     ~dgn_colour_override_manager()
248     {
249         _dgn_map_colour_fixup();
250     }
251 };
252
253 typedef FixedArray< coloured_feature, GXM, GYM > dungeon_colour_grid;
254 static unique_ptr<dungeon_colour_grid> dgn_colour_grid;
255
256 static string branch_epilogues[NUM_BRANCHES];
257
258 /**********************************************************************
259  * builder() - kickoff for the dungeon generator.
260  *********************************************************************/
261 bool builder(bool enable_random_maps, dungeon_feature_type dest_stairs_type)
262 {
263     // Re-check whether we're in a valid place, it leads to obscure errors
264     // otherwise.
265     ASSERT_RANGE(you.where_are_you, 0, NUM_BRANCHES);
266     ASSERT_RANGE(you.depth, 0 + 1, brdepth[you.where_are_you] + 1);
267
268     const set<string> uniq_tags  = you.uniq_map_tags;
269     const set<string> uniq_names = you.uniq_map_names;
270
271     // Save a copy of unique creatures for vetoes.
272     temp_unique_creatures = you.unique_creatures;
273     // And unrands
274     temp_unique_items = you.unique_items;
275
276     unwind_bool levelgen(crawl_state.generating_level, true);
277
278     // N tries to build the level, after which we bail with a capital B.
279     int tries = 50;
280     while (tries-- > 0)
281     {
282         // If we're getting low on available retries, disable random vaults
283         // and minivaults (special levels will still be placed).
284         if (tries < 5)
285             enable_random_maps = false;
286
287         try
288         {
289             if (_build_level_vetoable(enable_random_maps, dest_stairs_type))
290                 return true;
291         }
292         catch (map_load_exception &mload)
293         {
294             mprf(MSGCH_ERROR, "Failed to load map %s, reloading all maps",
295                  mload.what());
296             reread_maps();
297         }
298
299         you.uniq_map_tags  = uniq_tags;
300         you.uniq_map_names = uniq_names;
301     }
302
303     if (!crawl_state.map_stat_gen)
304     {
305         // Failed to build level, bail out.
306         if (crawl_state.need_save)
307         {
308             save_game(true,
309                   make_stringf("Unable to generate level for '%s'!",
310                                level_id::current().describe().c_str()).c_str());
311         }
312         else
313         {
314             die("Unable to generate level for '%s'!",
315                 level_id::current().describe().c_str());
316         }
317     }
318
319     env.level_layout_types.clear();
320     return false;
321 }
322
323 static bool _build_level_vetoable(bool enable_random_maps,
324                                   dungeon_feature_type dest_stairs_type)
325 {
326 #ifdef DEBUG_DIAGNOSTICS
327     mapgen_report_map_build_start();
328 #endif
329
330     dgn_reset_level(enable_random_maps);
331
332     if (player_in_branch(BRANCH_ECUMENICAL_TEMPLE))
333         _setup_temple_altars(you.props);
334
335     try
336     {
337         _build_dungeon_level(dest_stairs_type);
338     }
339     catch (dgn_veto_exception& e)
340     {
341         dprf("<white>VETO</white>: %s: %s", level_id::current().describe().c_str(), e.what());
342 #ifdef DEBUG_DIAGNOSTICS
343         mapgen_report_map_veto();
344 #endif
345         return false;
346     }
347
348     _dgn_set_floor_colours();
349
350     if (crawl_state.game_standard_levelgen()
351         && !_valid_dungeon_level())
352     {
353         return false;
354     }
355
356 #ifdef DEBUG_MONS_SCAN
357     // If debug_mons_scan() finds a problem while crawl_state.generating_level is
358     // still true then it will announce that a problem was caused
359     // during level generation.
360     debug_mons_scan();
361 #endif
362
363     if (!env.level_build_method.empty()
364         && env.level_build_method[0] == ' ')
365     {
366         env.level_build_method = env.level_build_method.substr(1);
367     }
368
369     string level_layout_type = comma_separated_line(
370         env.level_layout_types.begin(),
371         env.level_layout_types.end(), ", ");
372
373     // Save information in the level's properties hash table
374     // so we can include it in crash reports.
375     env.properties[BUILD_METHOD_KEY] = env.level_build_method;
376     env.properties[LAYOUT_TYPE_KEY]  = level_layout_type;
377
378     _dgn_postprocess_level();
379
380     env.level_layout_types.clear();
381     env.level_uniq_maps.clear();
382     env.level_uniq_map_tags.clear();
383     _dgn_map_colour_fixup();
384
385     // Call the branch epilogue, if any.
386     if (!branch_epilogues[you.where_are_you].empty())
387         if (!dlua.callfn(branch_epilogues[you.where_are_you].c_str(), 0, 0))
388         {
389             mprf(MSGCH_ERROR, "branch epilogue for %s failed: %s",
390                               level_id::current().describe().c_str(),
391                               dlua.error.c_str());
392             return false;
393         }
394
395     // Discard any Lua chunks we loaded.
396     strip_all_maps();
397
398     check_map_validity();
399
400     if (!_you_vault_list.empty())
401     {
402         vector<string> &vec(you.vault_list[level_id::current()]);
403         vec.insert(vec.end(), _you_vault_list.begin(), _you_vault_list.end());
404     }
405
406     return true;
407 }
408
409 // Things that are bugs where we want to assert rather than to sweep it under
410 // the rug with a veto.
411 static void _builder_assertions()
412 {
413 #ifdef ASSERTS
414     for (rectangle_iterator ri(0); ri; ++ri)
415         if (!in_bounds(*ri))
416             if (!is_valid_border_feat(grd(*ri)))
417             {
418                 die("invalid map border at (%d,%d): %s", ri->x, ri->y,
419                     dungeon_feature_name(grd(*ri)));
420             }
421 #endif
422 }
423
424 // Should be called after a level is constructed to perform any final
425 // fixups.
426 static void _dgn_postprocess_level()
427 {
428     shoals_postprocess_level();
429     _builder_assertions();
430     _calc_density();
431     _mark_solid_squares();
432 }
433
434 void dgn_clear_vault_placements(vault_placement_refv &vps)
435 {
436     for (vault_placement_refv::const_iterator i = vps.begin();
437          i != vps.end(); ++i)
438     {
439         delete *i;
440     }
441     vps.clear();
442 }
443
444 // Removes vaults that are not referenced in the map index mask from
445 // the level_vaults array.
446 void dgn_erase_unused_vault_placements()
447 {
448     set<int> referenced_vault_indexes;
449     for (rectangle_iterator ri(MAPGEN_BORDER); ri; ++ri)
450     {
451         const int map_index = env.level_map_ids(*ri);
452         if (map_index != INVALID_MAP_INDEX)
453             referenced_vault_indexes.insert(map_index);
454     }
455
456     // Walk backwards and toss unused vaults.
457     map<int, int> new_vault_index_map;
458     const int nvaults = env.level_vaults.size();
459     for (int i = nvaults - 1; i >= 0; --i)
460     {
461         if (referenced_vault_indexes.find(i) == referenced_vault_indexes.end())
462         {
463             vault_placement *vp = env.level_vaults[i];
464             // Unreferenced vault, blow it away
465             dprf("Removing references to unused map #%d) '%s' (%d,%d) (%d,%d)",
466                  i, vp->map.name.c_str(), vp->pos.x, vp->pos.y,
467                  vp->size.x, vp->size.y);
468
469             if (!vp->seen)
470             {
471                 dprf("Unregistering unseen vault: %s", vp->map.name.c_str());
472                 _dgn_unregister_vault(vp->map);
473             }
474
475             delete vp;
476             env.level_vaults.erase(env.level_vaults.begin() + i);
477
478             // Fix new indexes for all higher indexed vaults that are
479             // still referenced.
480             for (int j = i + 1; j < nvaults; ++j)
481             {
482                 map<int, int>::iterator imap = new_vault_index_map.find(j);
483                 if (imap != new_vault_index_map.end())
484                     --imap->second;
485             }
486         }
487         else
488         {
489             // Vault is still referenced, make a note of this index.
490             new_vault_index_map[i] = i;
491         }
492     }
493
494     // Finally, update the index map.
495     for (rectangle_iterator ri(MAPGEN_BORDER); ri; ++ri)
496     {
497         const int map_index = env.level_map_ids(*ri);
498         if (map_index != INVALID_MAP_INDEX)
499         {
500             map<int, int>::iterator imap = new_vault_index_map.find(map_index);
501             if (imap != new_vault_index_map.end())
502                 env.level_map_ids(*ri) = imap->second;
503         }
504     }
505
506 #ifdef DEBUG_ABYSS
507     dprf("Extant vaults on level: %d", (int) env.level_vaults.size());
508     for (int i = 0, size = env.level_vaults.size(); i < size; ++i)
509     {
510         const vault_placement &vp(*env.level_vaults[i]);
511         dprf("%d) %s (%d,%d) size (%d,%d)",
512              i, vp.map.name.c_str(), vp.pos.x, vp.pos.y,
513              vp.size.x, vp.size.y);
514     }
515 #endif
516 }
517
518 void level_clear_vault_memory()
519 {
520     dgn_clear_vault_placements(env.level_vaults);
521     Temp_Vaults.clear();
522     env.level_map_mask.init(0);
523     env.level_map_ids.init(INVALID_MAP_INDEX);
524 }
525
526 void dgn_flush_map_memory()
527 {
528     you.uniq_map_tags.clear();
529     you.uniq_map_names.clear();
530 }
531
532 static void _dgn_load_colour_grid()
533 {
534     dgn_colour_grid.reset(new dungeon_colour_grid);
535     dungeon_colour_grid &dcgrid(*dgn_colour_grid);
536     for (int y = Y_BOUND_1; y <= Y_BOUND_2; ++y)
537         for (int x = X_BOUND_1; x <= X_BOUND_2; ++x)
538             if (env.grid_colours[x][y] != BLACK)
539             {
540                 dcgrid[x][y]
541                     = coloured_feature(grd[x][y], env.grid_colours[x][y]);
542             }
543 }
544
545 static void _dgn_map_colour_fixup()
546 {
547     if (!dgn_colour_grid.get())
548         return;
549
550     // If the original coloured feature has been changed, reset the colour.
551     const dungeon_colour_grid &dcgrid(*dgn_colour_grid);
552     for (int y = Y_BOUND_1; y <= Y_BOUND_2; ++y)
553         for (int x = X_BOUND_1; x <= X_BOUND_2; ++x)
554             if (dcgrid[x][y].colour != BLACK
555                 && grd[x][y] != dcgrid[x][y].feature
556                 && (grd[x][y] != DNGN_UNDISCOVERED_TRAP
557                     || dcgrid[x][y].feature != DNGN_FLOOR))
558             {
559                 env.grid_colours[x][y] = BLACK;
560             }
561
562     dgn_colour_grid.reset(NULL);
563 }
564
565 bool set_level_flags(uint32_t flags, bool silent)
566 {
567     bool could_control = allow_control_teleport(true);
568     bool could_map     = is_map_persistent();
569
570     uint32_t old_flags = env.level_flags;
571     env.level_flags |= flags;
572
573     bool can_control = allow_control_teleport(true);
574     bool can_map     = is_map_persistent();
575
576     if (could_control && !can_control && !silent)
577     {
578         mpr("You sense the appearance of a powerful magical force "
579             "which warps space.", MSGCH_WARN);
580     }
581
582     if (could_map && !can_map && !silent)
583     {
584         mpr("A powerful force appears that prevents you from "
585             "remembering where you've been.", MSGCH_WARN);
586     }
587
588     return old_flags != env.level_flags;
589 }
590
591 bool unset_level_flags(uint32_t flags, bool silent)
592 {
593     bool could_control = allow_control_teleport(true);
594     bool could_map     = is_map_persistent();
595
596     iflags_t old_flags = env.level_flags;
597     env.level_flags &= ~flags;
598
599     bool can_control = allow_control_teleport(true);
600     bool can_map     = is_map_persistent();
601
602     if (!could_control && can_control && !silent)
603     {
604         // Isn't really a "recovery", but I couldn't think of where
605         // else to send it.
606         mpr("You sense the disappearance of a powerful magical force "
607             "which warped space.", MSGCH_RECOVERY);
608     }
609
610     if (!could_map && can_map && !silent)
611     {
612         // Isn't really a "recovery", but I couldn't think of where
613         // else to send it.
614         mpr("You sense the disappearance of the force that prevented you "
615             "from remembering where you've been.", MSGCH_RECOVERY);
616     }
617
618     return old_flags != env.level_flags;
619 }
620
621 void dgn_set_grid_colour_at(const coord_def &c, int colour)
622 {
623     if (colour != BLACK)
624     {
625         env.grid_colours(c) = colour;
626         if (!dgn_colour_grid.get())
627             dgn_colour_grid.reset(new dungeon_colour_grid);
628
629         (*dgn_colour_grid)(c) = coloured_feature(grd(c), colour);
630     }
631 }
632
633 static void _set_grd(const coord_def &c, dungeon_feature_type feat)
634 {
635     // It might be good to clear some pgrid flags as well.
636     env.tile_flv(c).feat    = 0;
637     env.tile_flv(c).special = 0;
638     env.grid_colours(c) = 0;
639     grd(c) = feat;
640 }
641
642 static void _dgn_register_vault(const string name, const string spaced_tags)
643 {
644     if (spaced_tags.find(" allow_dup ") == string::npos)
645         you.uniq_map_names.insert(name);
646
647     if (spaced_tags.find(" luniq ") != string::npos)
648         env.level_uniq_maps.insert(name);
649
650     vector<string> tags = split_string(" ", spaced_tags);
651     for (int t = 0, ntags = tags.size(); t < ntags; ++t)
652     {
653         const string &tag = tags[t];
654         if (tag.find("uniq_") == 0)
655             you.uniq_map_tags.insert(tag);
656         else if (tag.find("luniq_") == 0)
657             env.level_uniq_map_tags.insert(tag);
658     }
659 }
660
661 static void _dgn_unregister_vault(const map_def &map)
662 {
663     you.uniq_map_names.erase(map.name);
664     env.level_uniq_maps.erase(map.name);
665
666     vector<string> tags = split_string(" ", map.tags);
667     for (int t = 0, ntags = tags.size(); t < ntags; ++t)
668     {
669         const string &tag = tags[t];
670         if (tag.find("uniq_") == 0)
671             you.uniq_map_tags.erase(tag);
672         else if (tag.find("luniq_") == 0)
673             env.level_uniq_map_tags.erase(tag);
674     }
675
676     for (unsigned int j = 0; j < map.subvault_places.size(); ++j)
677         _dgn_unregister_vault(*map.subvault_places[j].subvault);
678 }
679
680 bool dgn_square_travel_ok(const coord_def &c)
681 {
682     const dungeon_feature_type feat = grd(c);
683     if (feat_is_trap(feat))
684     {
685         const trap_def * const trap = find_trap(c);
686         return !(trap && trap->type == TRAP_TELEPORT);
687     }
688     else
689         return feat_is_traversable(feat);
690 }
691
692 static bool _dgn_square_is_passable(const coord_def &c)
693 {
694     // [enne] Why does this function check MMT_OPAQUE?
695     //
696     // Don't peek inside MMT_OPAQUE vaults (all vaults are opaque by
697     // default) because vaults may choose to create isolated regions,
698     // or otherwise cause connectivity issues even if the map terrain
699     // is travel-passable.
700     return !(env.level_map_mask(c) & MMT_OPAQUE) && dgn_square_travel_ok(c);
701 }
702
703 static inline void _dgn_point_record_stub(const coord_def &) { }
704
705 template <class point_record>
706 static bool _dgn_fill_zone(
707     const coord_def &start, int zone,
708     point_record &record_point,
709     bool (*passable)(const coord_def &) = _dgn_square_is_passable,
710     bool (*iswanted)(const coord_def &) = NULL)
711 {
712     bool ret = false;
713     list<coord_def> points[2];
714     int cur = 0;
715
716     // No bounds checks, assuming the level has at least one layer of
717     // rock border.
718
719     for (points[cur].push_back(start); !points[cur].empty();)
720     {
721         for (list<coord_def>::const_iterator i = points[cur].begin();
722              i != points[cur].end(); ++i)
723         {
724             const coord_def &c(*i);
725
726             travel_point_distance[c.x][c.y] = zone;
727
728             if (iswanted && iswanted(c))
729                 ret = true;
730
731             for (adjacent_iterator ai(c); ai; ++ai)
732             {
733                 const coord_def& cp = *ai;
734                 if (!map_bounds(cp)
735                     || travel_point_distance[cp.x][cp.y] || !passable(cp))
736                 {
737                     continue;
738                 }
739
740                 travel_point_distance[cp.x][cp.y] = zone;
741                 record_point(cp);
742                 points[!cur].push_back(cp);
743             }
744         }
745
746         points[cur].clear();
747         cur = !cur;
748     }
749     return ret;
750 }
751
752 static bool _is_perm_down_stair(const coord_def &c)
753 {
754     switch (grd(c))
755     {
756     case DNGN_STONE_STAIRS_DOWN_I:
757     case DNGN_STONE_STAIRS_DOWN_II:
758     case DNGN_STONE_STAIRS_DOWN_III:
759     case DNGN_EXIT_HELL:
760     case DNGN_EXIT_PANDEMONIUM:
761     case DNGN_TRANSIT_PANDEMONIUM:
762     case DNGN_EXIT_ABYSS:
763     case DNGN_ABYSSAL_STAIR:
764         return true;
765     default:
766         return false;
767     }
768 }
769
770 static bool _is_upwards_exit_stair(const coord_def &c)
771 {
772     // Is this a valid upwards or exit stair out of a branch? In general,
773     // ensure that each region has a stone stair up.
774
775     if (feature_mimic_at(c))
776         return false;
777
778     switch (grd(c))
779     {
780     case DNGN_STONE_STAIRS_UP_I:
781     case DNGN_STONE_STAIRS_UP_II:
782     case DNGN_STONE_STAIRS_UP_III:
783     case DNGN_EXIT_HELL:
784 #if TAG_MAJOR_VERSION == 34
785     case DNGN_RETURN_FROM_DWARVEN_HALL:
786 #endif
787     case DNGN_RETURN_FROM_ORCISH_MINES:
788     case DNGN_RETURN_FROM_LAIR:
789     case DNGN_RETURN_FROM_SLIME_PITS:
790     case DNGN_RETURN_FROM_VAULTS:
791     case DNGN_RETURN_FROM_CRYPT:
792     case DNGN_RETURN_FROM_HALL_OF_BLADES:
793     case DNGN_RETURN_FROM_ZOT:
794     case DNGN_RETURN_FROM_TEMPLE:
795     case DNGN_RETURN_FROM_SNAKE_PIT:
796     case DNGN_RETURN_FROM_ELVEN_HALLS:
797     case DNGN_RETURN_FROM_TOMB:
798     case DNGN_RETURN_FROM_SWAMP:
799     case DNGN_RETURN_FROM_SHOALS:
800     case DNGN_RETURN_FROM_SPIDER_NEST:
801     case DNGN_RETURN_FROM_FOREST:
802     case DNGN_EXIT_PANDEMONIUM:
803     case DNGN_TRANSIT_PANDEMONIUM:
804     case DNGN_EXIT_ABYSS:
805         return true;
806     default:
807         return false;
808     }
809 }
810
811 static bool _is_exit_stair(const coord_def &c)
812 {
813     if (feature_mimic_at(c))
814         return false;
815
816     // Branch entries, portals, and abyss entries are not considered exit
817     // stairs here, as they do not provide an exit (in a transitive sense) from
818     // the current level.
819     switch (grd(c))
820     {
821     case DNGN_STONE_STAIRS_DOWN_I:
822     case DNGN_STONE_STAIRS_DOWN_II:
823     case DNGN_STONE_STAIRS_DOWN_III:
824     case DNGN_ESCAPE_HATCH_DOWN:
825     case DNGN_STONE_STAIRS_UP_I:
826     case DNGN_STONE_STAIRS_UP_II:
827     case DNGN_STONE_STAIRS_UP_III:
828     case DNGN_ESCAPE_HATCH_UP:
829     case DNGN_EXIT_HELL:
830 #if TAG_MAJOR_VERSION == 34
831     case DNGN_RETURN_FROM_DWARVEN_HALL:
832 #endif
833     case DNGN_RETURN_FROM_ORCISH_MINES:
834     case DNGN_RETURN_FROM_LAIR:
835     case DNGN_RETURN_FROM_SLIME_PITS:
836     case DNGN_RETURN_FROM_VAULTS:
837     case DNGN_RETURN_FROM_CRYPT:
838     case DNGN_RETURN_FROM_HALL_OF_BLADES:
839     case DNGN_RETURN_FROM_ZOT:
840     case DNGN_RETURN_FROM_TEMPLE:
841     case DNGN_RETURN_FROM_SNAKE_PIT:
842     case DNGN_RETURN_FROM_ELVEN_HALLS:
843     case DNGN_RETURN_FROM_TOMB:
844     case DNGN_RETURN_FROM_SWAMP:
845     case DNGN_RETURN_FROM_SHOALS:
846     case DNGN_RETURN_FROM_SPIDER_NEST:
847     case DNGN_RETURN_FROM_FOREST:
848     case DNGN_EXIT_PANDEMONIUM:
849     case DNGN_TRANSIT_PANDEMONIUM:
850     case DNGN_EXIT_ABYSS:
851         return true;
852     default:
853         return false;
854     }
855 }
856
857 // Counts the number of mutually unreachable areas in the map,
858 // excluding isolated zones within vaults (we assume the vault author
859 // knows what she's doing). This is an easy way to check whether a map
860 // has isolated parts of the level that were not formerly isolated.
861 //
862 // All squares within vaults are treated as non-reachable, to simplify
863 // life, because vaults may change the level layout and isolate
864 // different areas without changing the number of isolated areas.
865 // Here's a before and after example of such a vault that would cause
866 // problems if we considered floor in the vault as non-isolating (the
867 // vault is represented as V for walls and o for floor squares in the
868 // vault).
869 //
870 // Before:
871 //
872 //   xxxxx    xxxxx
873 //   x<..x    x.2.x
874 //   x.1.x    xxxxx  3 isolated zones
875 //   x>..x    x.3.x
876 //   xxxxx    xxxxx
877 //
878 // After:
879 //
880 //   xxxxx    xxxxx
881 //   x<1.x    x.2.x
882 //   VVVVVVVVVVoooV  3 isolated zones, but the isolated zones are different.
883 //   x>3.x    x...x
884 //   xxxxx    xxxxx
885 //
886 // If count_stairless is true, returns the number of regions that have no
887 // stairs in them.
888 //
889 // If fill is non-zero, it fills any disconnected regions with fill.
890 //
891 static int _process_disconnected_zones(int x1, int y1, int x2, int y2,
892                                        bool choose_stairless,
893                                        dungeon_feature_type fill)
894 {
895     memset(travel_point_distance, 0, sizeof(travel_distance_grid_t));
896     int nzones = 0;
897     int ngood = 0;
898     for (int y = y1; y <= y2 ; ++y)
899     {
900         for (int x = x1; x <= x2; ++x)
901         {
902             if (!map_bounds(x, y)
903                 || travel_point_distance[x][y]
904                 || !_dgn_square_is_passable(coord_def(x, y)))
905             {
906                 continue;
907             }
908
909             const bool found_exit_stair =
910                 _dgn_fill_zone(coord_def(x, y), ++nzones,
911                                _dgn_point_record_stub,
912                                _dgn_square_is_passable,
913                                choose_stairless ? (at_branch_bottom() ?
914                                                    _is_upwards_exit_stair :
915                                                    _is_exit_stair) : NULL);
916
917             // If we want only stairless zones, screen out zones that did
918             // have stairs.
919             if (choose_stairless && found_exit_stair)
920                 ++ngood;
921             else if (fill)
922             {
923                 // Don't fill in areas connected to vaults.
924                 // We want vaults to be accessible; if the area is disconneted
925                 // from the rest of the level, this will cause the level to be
926                 // vetoed later on.
927                 bool veto = false;
928                 vector<coord_def> coords;
929                 for (int fy = y1; fy <= y2 ; ++fy)
930                 {
931                     for (int fx = x1; fx <= x2; ++fx)
932                     {
933                         if (travel_point_distance[fx][fy] == nzones)
934                         {
935                             if (map_masked(coord_def(fx, fy), MMT_VAULT))
936                             {
937                                 veto = true;
938                                 break;
939                             }
940                             else
941                                 coords.push_back(coord_def(fx, fy));
942                         }
943                     }
944                     if (veto)
945                         break;
946                 }
947                 if (!veto)
948                     for (vector<coord_def>::iterator it = coords.begin();
949                          it != coords.end(); it++)
950                     {
951                         _set_grd(*it, fill);
952                     }
953             }
954         }
955     }
956
957     return nzones - ngood;
958 }
959
960 int dgn_count_disconnected_zones(bool choose_stairless,
961                                  dungeon_feature_type fill)
962 {
963     return _process_disconnected_zones(0, 0, GXM-1, GYM-1, choose_stairless,
964                                        fill);
965 }
966
967 static void _fixup_hell_stairs()
968 {
969     for (rectangle_iterator ri(1); ri; ++ri)
970     {
971         if (grd(*ri) >= DNGN_STONE_STAIRS_UP_I
972             && grd(*ri) <= DNGN_ESCAPE_HATCH_UP)
973         {
974             _set_grd(*ri, DNGN_ENTER_HELL);
975         }
976     }
977 }
978
979 static void _fixup_pandemonium_stairs()
980 {
981     for (rectangle_iterator ri(1); ri; ++ri)
982     {
983         if (grd(*ri) >= DNGN_STONE_STAIRS_UP_I
984             && grd(*ri) <= DNGN_ESCAPE_HATCH_UP)
985         {
986             _set_grd(*ri, DNGN_TRANSIT_PANDEMONIUM);
987         }
988     }
989 }
990
991 static void _mask_vault(const vault_placement &place, unsigned mask)
992 {
993     for (vault_place_iterator vi(place); vi; ++vi)
994         env.level_map_mask(*vi) |= mask;
995 }
996
997 static void _dgn_apply_map_index(const vault_placement &place, int map_index)
998 {
999     for (vault_place_iterator vi(place); vi; ++vi)
1000         env.level_map_ids(*vi) = map_index;
1001 }
1002
1003 const vault_placement *
1004 dgn_register_place(const vault_placement &place, bool register_vault)
1005 {
1006     const int  map_index    = env.level_vaults.size();
1007     const bool overwritable = place.map.is_overwritable_layout();
1008     const bool transparent  = place.map.has_tag("transparent");
1009
1010     if (register_vault)
1011     {
1012         _dgn_register_vault(place.map.name, place.map.tags);
1013         for (int i = env.new_subvault_names.size() - 1; i >= 0; i--)
1014         {
1015             _dgn_register_vault(env.new_subvault_names[i],
1016                                 env.new_subvault_tags[i]);
1017         }
1018         clear_subvault_stack();
1019
1020         // Identify each square in the map with its map_index.
1021         if (!overwritable)
1022             _dgn_apply_map_index(place, map_index);
1023     }
1024
1025     if (!overwritable)
1026     {
1027         if (place.map.orient == MAP_ENCOMPASS)
1028         {
1029             for (rectangle_iterator ri(0); ri; ++ri)
1030                 env.level_map_mask(*ri) |= MMT_VAULT;
1031         }
1032         else
1033             _mask_vault(place, MMT_VAULT);
1034
1035         if (!transparent)
1036             _mask_vault(place, MMT_OPAQUE);
1037     }
1038
1039     // Find tags matching properties.
1040     vector<string> tags = place.map.get_tags();
1041
1042     for (vector<string>::const_iterator i = tags.begin(); i != tags.end(); ++i)
1043     {
1044         const feature_property_type prop = str_to_fprop(*i);
1045         if (prop == FPROP_NONE)
1046             continue;
1047
1048         for (vault_place_iterator vi(place); vi; ++vi)
1049             env.pgrid(*vi) |= prop;
1050
1051     }
1052
1053     if (place.map.has_tag("no_monster_gen"))
1054         _mask_vault(place, MMT_NO_MONS);
1055
1056     if (place.map.has_tag("no_item_gen"))
1057         _mask_vault(place, MMT_NO_ITEM);
1058
1059     if (place.map.has_tag("no_pool_fixup"))
1060         _mask_vault(place, MMT_NO_POOL);
1061
1062     if (place.map.has_tag("no_wall_fixup"))
1063         _mask_vault(place, MMT_NO_WALL);
1064
1065     if (place.map.has_tag("no_trap_gen"))
1066         _mask_vault(place, MMT_NO_TRAP);
1067
1068     // Now do per-square by-symbol masking.
1069     for (vault_place_iterator vi(place); vi; ++vi)
1070     {
1071         const keyed_mapspec *spec = place.map.mapspec_at(*vi - place.pos);
1072
1073         if (spec != NULL)
1074         {
1075             env.level_map_mask(*vi) |= (short)spec->map_mask.flags_set;
1076             env.level_map_mask(*vi) &= ~((short)spec->map_mask.flags_unset);
1077         }
1078     }
1079
1080     set_level_flags(place.map.level_flags.flags_set, true);
1081     unset_level_flags(place.map.level_flags.flags_unset, true);
1082
1083     if (place.map.floor_colour != BLACK)
1084         env.floor_colour = place.map.floor_colour;
1085
1086     if (place.map.rock_colour != BLACK)
1087         env.rock_colour = place.map.rock_colour;
1088
1089     if (!place.map.rock_tile.empty())
1090     {
1091         tileidx_t rock;
1092         if (tile_dngn_index(place.map.rock_tile.c_str(), &rock))
1093         {
1094             env.tile_default.wall_idx =
1095                 store_tilename_get_index(place.map.rock_tile);
1096
1097             env.tile_default.wall = rock;
1098         }
1099     }
1100
1101     if (!place.map.floor_tile.empty())
1102     {
1103         tileidx_t floor;
1104         if (tile_dngn_index(place.map.floor_tile.c_str(), &floor))
1105         {
1106             env.tile_default.floor_idx =
1107                 store_tilename_get_index(place.map.floor_tile);
1108
1109             env.tile_default.floor = floor;
1110         }
1111     }
1112
1113     vault_placement *new_vault_place = new vault_placement(place);
1114     env.level_vaults.push_back(new_vault_place);
1115     if (register_vault)
1116         _remember_vault_placement(place, place.map.has_tag("extra"));
1117     return new_vault_place;
1118 }
1119
1120 static bool _dgn_ensure_vault_placed(bool vault_success,
1121                                      bool disable_further_vaults)
1122 {
1123     if (!vault_success)
1124         throw dgn_veto_exception("Vault placement failure.");
1125     else if (disable_further_vaults)
1126         use_random_maps = false;
1127     return vault_success;
1128 }
1129
1130 static bool _ensure_vault_placed_ex(bool vault_success, const map_def *vault)
1131 {
1132     return _dgn_ensure_vault_placed(vault_success,
1133                                     (!vault->has_tag("extra")
1134                                      && vault->orient == MAP_ENCOMPASS));
1135 }
1136
1137 static coord_def _find_level_feature(int feat)
1138 {
1139     for (rectangle_iterator ri(1); ri; ++ri)
1140     {
1141         if (grd(*ri) == feat)
1142             return *ri;
1143     }
1144
1145     return coord_def(0, 0);
1146 }
1147
1148 static bool _has_connected_stone_stairs_from(const coord_def &c)
1149 {
1150     flood_find<feature_grid, coord_predicate> ff(env.grid, in_bounds);
1151     ff.add_feat(DNGN_STONE_STAIRS_DOWN_I);
1152     ff.add_feat(DNGN_STONE_STAIRS_DOWN_II);
1153     ff.add_feat(DNGN_STONE_STAIRS_DOWN_III);
1154     ff.add_feat(DNGN_STONE_STAIRS_UP_I);
1155     ff.add_feat(DNGN_STONE_STAIRS_UP_II);
1156     ff.add_feat(DNGN_STONE_STAIRS_UP_III);
1157
1158     coord_def where = ff.find_first_from(c, env.level_map_mask);
1159     return where.x || !ff.did_leave_vault();
1160 }
1161
1162 static bool _has_connected_downstairs_from(const coord_def &c)
1163 {
1164     flood_find<feature_grid, coord_predicate> ff(env.grid, in_bounds);
1165     ff.add_feat(DNGN_STONE_STAIRS_DOWN_I);
1166     ff.add_feat(DNGN_STONE_STAIRS_DOWN_II);
1167     ff.add_feat(DNGN_STONE_STAIRS_DOWN_III);
1168     ff.add_feat(DNGN_ESCAPE_HATCH_DOWN);
1169
1170     coord_def where = ff.find_first_from(c, env.level_map_mask);
1171     return where.x || !ff.did_leave_vault();
1172 }
1173
1174 static bool _is_level_stair_connected(dungeon_feature_type feat)
1175 {
1176     coord_def up = _find_level_feature(feat);
1177     if (up.x && up.y)
1178         return _has_connected_downstairs_from(up);
1179
1180     return false;
1181 }
1182
1183 static bool _valid_dungeon_level()
1184 {
1185     // D:1 only.
1186     // Also, what's the point of this check?  Regular connectivity should
1187     // do that already.
1188     if (player_in_branch(BRANCH_MAIN_DUNGEON) && you.depth == 1)
1189         return _is_level_stair_connected(branches[BRANCH_MAIN_DUNGEON].exit_stairs);
1190
1191     return true;
1192 }
1193
1194 void dgn_reset_level(bool enable_random_maps)
1195 {
1196     env.level_uniq_maps.clear();
1197     env.level_uniq_map_tags.clear();
1198     clear_subvault_stack();
1199
1200     you.unique_creatures = temp_unique_creatures;
1201     you.unique_items = temp_unique_items;
1202
1203     _you_vault_list.clear();
1204     env.level_build_method.clear();
1205     env.level_layout_types.clear();
1206     level_clear_vault_memory();
1207     dgn_colour_grid.reset(NULL);
1208
1209     use_random_maps = enable_random_maps;
1210     dgn_check_connectivity = false;
1211     dgn_zones        = 0;
1212
1213     _temple_altar_list.clear();
1214     _current_temple_hash = NULL;
1215
1216     // Forget level properties.
1217     env.properties.clear();
1218     env.heightmap.reset(NULL);
1219
1220     env.absdepth0 = absdungeon_depth(you.where_are_you, you.depth);
1221
1222     if (!crawl_state.test)
1223         dprf("absdepth0 = %d", env.absdepth0);
1224
1225     // Blank level with DNGN_ROCK_WALL.
1226     env.grid.init(DNGN_ROCK_WALL);
1227     env.pgrid.init(0);
1228     env.grid_colours.init(BLACK);
1229     env.map_knowledge.init(map_cell());
1230     env.map_forgotten.reset();
1231
1232     // Delete all traps.
1233     for (int i = 0; i < MAX_TRAPS; i++)
1234         env.trap[i].type = TRAP_UNASSIGNED;
1235
1236     // Initialise all items.
1237     for (int i = 0; i < MAX_ITEMS; i++)
1238         init_item(i);
1239
1240     // Reset all monsters.
1241     reset_all_monsters();
1242     init_anon();
1243
1244     // ... and Pan/regular spawn lists.
1245     env.mons_alloc.init(MONS_NO_MONSTER);
1246     setup_vault_mon_list();
1247
1248     // Zap clouds
1249     env.cgrid.init(EMPTY_CLOUD);
1250
1251     const cloud_struct empty;
1252     env.cloud.init(empty);
1253     env.cloud_no = 0;
1254
1255     mgrd.init(NON_MONSTER);
1256     igrd.init(NON_ITEM);
1257     env.tgrid.init(NON_ENTITY);
1258
1259     // Reset all shops.
1260     for (int shcount = 0; shcount < MAX_SHOPS; shcount++)
1261         env.shop[shcount].type = SHOP_UNASSIGNED;
1262
1263     // Clear all markers.
1264     env.markers.clear();
1265
1266     // Lose all listeners.
1267     dungeon_events.clear();
1268
1269     // Set default level flags.
1270     env.level_flags = branches[you.where_are_you].default_level_flags;
1271
1272     // Set default random monster generation rate (smaller is more often,
1273     // except that 0 == no random monsters).
1274     if (player_in_branch(BRANCH_ECUMENICAL_TEMPLE)
1275         && you.char_direction == GDT_DESCENDING // except for the Orb run
1276         || crawl_state.game_is_tutorial())
1277     {
1278         // No random monsters in tutorial or ecu temple
1279         env.spawn_random_rate = 0;
1280     }
1281     else if (player_in_connected_branch())
1282         env.spawn_random_rate = 240;
1283     else if (player_in_branch(BRANCH_ABYSS)
1284              || player_in_branch(BRANCH_PANDEMONIUM))
1285     {
1286         // Abyss spawn rate is set for those characters that start out in the
1287         // Abyss; otherwise the number is ignored in the Abyss.
1288         env.spawn_random_rate = 50;
1289     }
1290     else
1291         // No random monsters in Labyrinths and portal vaults.
1292         env.spawn_random_rate = 0;
1293     env.density = 0;
1294     env.forest_awoken_until = 0;
1295     env.sunlight.clear();
1296
1297     env.floor_colour = BLACK;
1298     env.rock_colour  = BLACK;
1299
1300     // Clear exclusions
1301     clear_excludes();
1302
1303     // Clear custom tile settings from vaults
1304     tile_init_default_flavour();
1305     tile_clear_flavour();
1306     env.tile_names.clear();
1307 }
1308
1309 static int _num_items_wanted(int absdepth0)
1310 {
1311     if (branches[you.where_are_you].branch_flags & BFLAG_NO_ITEMS)
1312         return 0;
1313     else if (absdepth0 > 5 && one_chance_in(500 - 5 * absdepth0))
1314         return 10 + random2avg(90, 2); // rich level!
1315     else
1316         return 3 + roll_dice(3, 11);
1317 }
1318
1319 static int _num_mons_wanted()
1320 {
1321     if (player_in_branch(BRANCH_ABYSS))
1322         return 0;
1323
1324     if (player_in_branch(BRANCH_PANDEMONIUM))
1325         return random2avg(28, 3);
1326
1327     // Except for Abyss and Pan, no other portal gets random monsters.
1328     if (!player_in_connected_branch())
1329         return 0;
1330
1331     if (!branch_has_monsters(you.where_are_you))
1332         return 0;
1333
1334     if (player_in_branch(BRANCH_CRYPT))
1335         return roll_dice(3, 8);
1336
1337     int mon_wanted = roll_dice(3, 10);
1338
1339     if (player_in_hell())
1340         mon_wanted += roll_dice(3, 8);
1341
1342     if (mon_wanted > 60)
1343         mon_wanted = 60;
1344
1345     return mon_wanted;
1346 }
1347
1348 static void _fixup_walls()
1349 {
1350     // If level part of Dis -> all walls metal.
1351     // If Vaults:$ -> all walls metal or crystal.
1352     // If part of crypt -> all walls stone.
1353
1354     dungeon_feature_type wall_type = DNGN_ROCK_WALL;
1355
1356     if (!player_in_connected_branch())
1357         return;
1358
1359     switch (you.where_are_you)
1360     {
1361     case BRANCH_DIS:
1362         wall_type = DNGN_METAL_WALL;
1363         break;
1364
1365     case BRANCH_VAULTS:
1366     {
1367         // Everything but the branch end is handled in Lua.
1368         if (you.depth == branches[BRANCH_VAULTS].numlevels)
1369         {
1370             wall_type = random_choose_weighted(1, DNGN_GREEN_CRYSTAL_WALL,
1371                                                9, DNGN_METAL_WALL,
1372                                                0);
1373         }
1374         break;
1375     }
1376
1377     case BRANCH_CRYPT:
1378         wall_type = DNGN_STONE_WALL;
1379         break;
1380
1381     case BRANCH_SLIME_PITS:
1382         wall_type = DNGN_SLIMY_WALL;
1383         break;
1384
1385     default:
1386         return;
1387     }
1388
1389     dgn_replace_area(0, 0, GXM-1, GYM-1, DNGN_ROCK_WALL, wall_type,
1390                      MMT_NO_WALL);
1391 }
1392
1393 // Remove any items that are on squares that items should not be on.
1394 // link_items() must be called after this function.
1395 void fixup_misplaced_items()
1396 {
1397     for (int i = 0; i < MAX_ITEMS; i++)
1398     {
1399         item_def& item(mitm[i]);
1400         if (!item.defined() || (item.pos.x == 0)
1401             || item.held_by_monster())
1402         {
1403             continue;
1404         }
1405
1406         if (in_bounds(item.pos))
1407         {
1408             dungeon_feature_type feat = grd(item.pos);
1409             if (feat >= DNGN_MINITEM)
1410                 continue;
1411
1412             // We accept items in deep water in the Abyss---they are likely to
1413             // be revealed eventually by morphing, and having deep water push
1414             // items away leads to strange results.
1415             if (feat == DNGN_DEEP_WATER && you.where_are_you == BRANCH_ABYSS)
1416                 continue;
1417
1418             mprf(MSGCH_ERROR, "Item %s buggily placed in feature %s at (%d, %d).",
1419                  item.name(DESC_PLAIN).c_str(),
1420                  feature_description_at(item.pos, false, DESC_PLAIN,
1421                                      false, false).c_str(),
1422                  item.pos.x, item.pos.y);
1423         }
1424         else
1425         {
1426             mprf(MSGCH_ERROR, "Item buggily placed out of bounds at (%d, %d).",
1427                  item.pos.x, item.pos.y);
1428         }
1429
1430         // Can't just unlink item because it might not have been linked yet.
1431         item.base_type = OBJ_UNASSIGNED;
1432         item.quantity = 0;
1433         item.pos.reset();
1434     }
1435 }
1436
1437 // count_root is present to allow the root branch to keep placing three
1438 // stairs (ZotDef, entry vaults placing multiple stairs).
1439 static bool _at_top_of_branch()
1440 {
1441     return your_branch().exit_stairs != NUM_FEATURES
1442            && you.depth == 1
1443            && player_in_connected_branch();
1444 }
1445
1446 static void _fixup_branch_stairs()
1447 {
1448     // Top level of branch levels - replaces up stairs with stairs back to
1449     // dungeon or wherever:
1450     if (_at_top_of_branch())
1451     {
1452 #ifdef DEBUG_DIAGNOSTICS
1453         int count = 0;
1454 #endif
1455         // Just in case we somehow get here with more than one stair placed.
1456         // Prefer stairs that are placed in vaults for picking an exit at
1457         // random.
1458         vector<coord_def> vault_stairs, normal_stairs;
1459         dungeon_feature_type exit = your_branch().exit_stairs;
1460         if (you.where_are_you == root_branch) // ZotDef
1461             exit = DNGN_EXIT_DUNGEON;
1462         for (rectangle_iterator ri(1); ri; ++ri)
1463         {
1464             if (grd(*ri) == DNGN_ESCAPE_HATCH_UP)
1465                 _set_grd(*ri, DNGN_FLOOR);
1466             else if (grd(*ri) >= DNGN_STONE_STAIRS_UP_I
1467                      && grd(*ri) <= DNGN_STONE_STAIRS_UP_III)
1468             {
1469 #ifdef DEBUG_DIAGNOSTICS
1470                 if (count++ && you.where_are_you != root_branch)
1471                 {
1472                     mprf(MSGCH_ERROR, "Multiple branch exits on %s",
1473                          level_id::current().describe().c_str());
1474                 }
1475 #endif
1476                 if (you.where_are_you == root_branch)
1477                 {
1478                     env.markers.add(new map_feature_marker(*ri, grd(*ri)));
1479                     _set_grd(*ri, exit);
1480                 }
1481                 else
1482                 {
1483                     if (map_masked(*ri, MMT_VAULT))
1484                         vault_stairs.push_back(*ri);
1485                     else
1486                         normal_stairs.push_back(*ri);
1487                 }
1488             }
1489         }
1490         if (you.where_are_you != root_branch)
1491         {
1492             vector<coord_def> stairs;
1493             if (!vault_stairs.empty())
1494                 stairs = vault_stairs;
1495             else
1496                 stairs = normal_stairs;
1497
1498             if (!stairs.empty())
1499             {
1500                 shuffle_array(stairs);
1501                 coord_def coord = *(stairs.begin());
1502                 env.markers.add(new map_feature_marker(coord, grd(coord)));
1503                 _set_grd(coord, exit);
1504                 for (vector<coord_def>::iterator it = stairs.begin() + 1;
1505                      it != stairs.end(); it++)
1506                 {
1507                     _set_grd(*it, DNGN_FLOOR);
1508                 }
1509             }
1510         }
1511     }
1512
1513     // Bottom level of branch - wipes out down stairs and hatches
1514     dungeon_feature_type feat = DNGN_FLOOR;
1515
1516     if (at_branch_bottom())
1517     {
1518         for (rectangle_iterator ri(1); ri; ++ri)
1519         {
1520             if (grd(*ri) >= DNGN_STONE_STAIRS_DOWN_I
1521                 && grd(*ri) <= DNGN_ESCAPE_HATCH_DOWN)
1522             {
1523                 _set_grd(*ri, feat);
1524             }
1525         }
1526     }
1527 }
1528
1529 static bool _fixup_stone_stairs(bool preserve_vault_stairs)
1530 {
1531     // This function ensures that there is exactly one each up and down
1532     // stone stairs I, II, and III.  More than three stairs will result in
1533     // turning additional stairs into escape hatches (with an attempt to keep
1534     // level connectivity).  Fewer than three stone stairs will result in
1535     // random placement of new stairs.
1536
1537     const unsigned int max_stairs = 20;
1538     FixedVector<coord_def, max_stairs> up_stairs;
1539     FixedVector<coord_def, max_stairs> down_stairs;
1540     unsigned int num_up_stairs   = 0;
1541     unsigned int num_down_stairs = 0;
1542
1543     for (rectangle_iterator ri(1); ri; ++ri)
1544     {
1545         const coord_def& c = *ri;
1546         if (feature_mimic_at(c))
1547             continue;
1548
1549         if (grd(c) >= DNGN_STONE_STAIRS_DOWN_I
1550             && grd(c) <= DNGN_STONE_STAIRS_DOWN_III
1551             && num_down_stairs < max_stairs)
1552         {
1553             down_stairs[num_down_stairs++] = c;
1554         }
1555         else if (grd(c) >= DNGN_STONE_STAIRS_UP_I
1556                  && grd(c) <= DNGN_STONE_STAIRS_UP_III
1557                  && num_up_stairs < max_stairs)
1558         {
1559             up_stairs[num_up_stairs++] = c;
1560         }
1561     }
1562
1563     bool success = true;
1564
1565     for (unsigned int i = 0; i < 2; i++)
1566     {
1567         FixedVector<coord_def, max_stairs>& stair_list = (i == 0 ? up_stairs
1568                                                                  : down_stairs);
1569
1570         unsigned int num_stairs, needed_stairs;
1571         dungeon_feature_type base;
1572         dungeon_feature_type replace;
1573         if (i == 0)
1574         {
1575             num_stairs = num_up_stairs;
1576             replace = DNGN_FLOOR;
1577             base = DNGN_STONE_STAIRS_UP_I;
1578             needed_stairs = _at_top_of_branch() ? 1 : 3;
1579         }
1580         else
1581         {
1582             num_stairs = num_down_stairs;
1583             replace = DNGN_FLOOR;
1584             base = DNGN_STONE_STAIRS_DOWN_I;
1585
1586             if (at_branch_bottom())
1587                 needed_stairs = 0;
1588             else
1589                 needed_stairs = 3;
1590         }
1591
1592         // In Zot, don't create extra escape hatches, in order to force
1593         // the player through vaults that use all three down stone stairs.
1594         if (player_in_branch(BRANCH_HALL_OF_ZOT))
1595             replace = DNGN_GRANITE_STATUE;
1596
1597         dprf("Before culling: %d/%d %s stairs", num_stairs, needed_stairs,
1598              i ? "down" : "up");
1599
1600         if (num_stairs > needed_stairs)
1601         {
1602             // Find pairwise stairs that are connected and turn one of them
1603             // into an escape hatch of the appropriate type.
1604             for (unsigned int s1 = 0; s1 < num_stairs; s1++)
1605             {
1606                 if (num_stairs <= needed_stairs)
1607                     break;
1608
1609                 for (unsigned int s2 = s1 + 1; s2 < num_stairs; s2++)
1610                 {
1611                     if (num_stairs <= needed_stairs)
1612                         break;
1613
1614                     if (preserve_vault_stairs
1615                         && map_masked(stair_list[s2], MMT_VAULT))
1616                     {
1617                         continue;
1618                     }
1619
1620                     flood_find<feature_grid, coord_predicate> ff(env.grid,
1621                                                                  in_bounds);
1622
1623                     ff.add_feat(grd(stair_list[s2]));
1624
1625                     // Ensure we're not searching for the feature at s1.
1626                     dungeon_feature_type save = grd(stair_list[s1]);
1627                     grd(stair_list[s1]) = DNGN_FLOOR;
1628
1629                     const coord_def where =
1630                         ff.find_first_from(stair_list[s1],
1631                                            env.level_map_mask);
1632                     if (where.x)
1633                     {
1634                         dprf("Too many stairs -- removing one of a connected pair.");
1635                         grd(stair_list[s2]) = replace;
1636                         num_stairs--;
1637                         stair_list[s2] = stair_list[num_stairs];
1638                         s2--;
1639                     }
1640
1641                     grd(stair_list[s1]) = save;
1642                 }
1643             }
1644
1645             // If that doesn't work, remove random stairs.
1646             while (num_stairs > needed_stairs)
1647             {
1648                 int remove = random2(num_stairs);
1649                 if (preserve_vault_stairs)
1650                 {
1651                     int tries;
1652                     for (tries = num_stairs; tries > 0; tries--)
1653                     {
1654                         if (!map_masked(stair_list[remove], MMT_VAULT))
1655                             break;
1656                         remove = (remove + 1) % num_stairs;
1657                     }
1658
1659                     // If we looped through all possibilities, then it
1660                     // means that there are more than 3 stairs in vaults and
1661                     // we can't preserve vault stairs.
1662                     if (!tries)
1663                     {
1664                         dprf("Too many stairs inside vaults!");
1665                         break;
1666                     }
1667                 }
1668                 dprf("Too many stairs -- removing one blindly.");
1669                 _set_grd(stair_list[remove], replace);
1670
1671                 stair_list[remove] = stair_list[--num_stairs];
1672             }
1673         }
1674
1675         // FIXME: stairs that generate inside random vaults are still
1676         // protected, resulting in superfluoes ones.
1677         dprf("After culling: %d/%d %s stairs", num_stairs, needed_stairs,
1678              i ? "down" : "up");
1679
1680         if (num_stairs > needed_stairs && preserve_vault_stairs
1681             && (i || you.depth != 1 || you.where_are_you != root_branch))
1682         {
1683             success = false;
1684             continue;
1685         }
1686
1687         // If there are no stairs, it's either a branch entrance or exit.
1688         // If we somehow have ended up in a catastrophic "no stairs" state,
1689         // the level will not be validated, so we do not need to catch it here.
1690         if (num_stairs == 0)
1691             continue;
1692
1693         // Add extra stairs to get to exactly three.
1694         for (unsigned int s = num_stairs; s < needed_stairs; s++)
1695         {
1696             const uint32_t mask = preserve_vault_stairs ? MMT_VAULT : 0;
1697             coord_def gc = _dgn_random_point_in_bounds(DNGN_FLOOR, mask, DNGN_UNSEEN);
1698
1699             if (!gc.origin())
1700             {
1701                 dprf("Adding stair %d at (%d,%d)", s, gc.x, gc.y);
1702                 // base gets fixed up to be the right stone stair below...
1703                 _set_grd(gc, base);
1704                 stair_list[num_stairs++] = gc;
1705             }
1706             else
1707                 success = false;
1708         }
1709
1710         // If we only need one stone stair, make sure it's _I.
1711         if (i == 0 && needed_stairs == 1)
1712         {
1713             ASSERT(num_stairs == 1 || you.where_are_you == root_branch);
1714             if (num_stairs == 1)
1715             {
1716                 grd(stair_list[0]) = DNGN_STONE_STAIRS_UP_I;
1717                 continue;
1718             }
1719         }
1720
1721         // Ensure uniqueness of three stairs.
1722         for (int s = 0; s < 4; s++)
1723         {
1724             int s1 = s % num_stairs;
1725             int s2 = (s1 + 1) % num_stairs;
1726             ASSERT(grd(stair_list[s2]) >= base
1727                    && grd(stair_list[s2]) < base + 3);
1728
1729             if (grd(stair_list[s1]) == grd(stair_list[s2]))
1730             {
1731                 _set_grd(stair_list[s2], (dungeon_feature_type)
1732                     (base + (grd(stair_list[s2])-base+1) % 3));
1733             }
1734         }
1735     }
1736
1737     return success;
1738 }
1739
1740 static bool _add_feat_if_missing(bool (*iswanted)(const coord_def &),
1741                                  dungeon_feature_type feat)
1742 {
1743     memset(travel_point_distance, 0, sizeof(travel_distance_grid_t));
1744     int nzones = 0;
1745     for (int y = 0; y < GYM; ++y)
1746         for (int x = 0; x < GXM; ++x)
1747         {
1748             // [ds] Use dgn_square_is_passable instead of
1749             // dgn_square_travel_ok here, for we'll otherwise
1750             // fail on floorless isolated pocket in vaults (like the
1751             // altar surrounded by deep water), and trigger the assert
1752             // downstairs.
1753             const coord_def gc(x, y);
1754             if (!map_bounds(x, y)
1755                 || travel_point_distance[x][y] // already covered previously
1756                 || !_dgn_square_is_passable(gc))
1757             {
1758                 continue;
1759             }
1760
1761             if (_dgn_fill_zone(gc, ++nzones, _dgn_point_record_stub,
1762                                _dgn_square_is_passable, iswanted))
1763             {
1764                 continue;
1765             }
1766
1767             bool found_feature = false;
1768             for (rectangle_iterator ri(0); ri; ++ri)
1769             {
1770                 if (grd(*ri) == feat
1771                     && travel_point_distance[ri->x][ri->y] == nzones)
1772                 {
1773                     found_feature = true;
1774                     break;
1775                 }
1776             }
1777
1778             if (found_feature)
1779                 continue;
1780
1781             int i = 0;
1782             while (i++ < 2000)
1783             {
1784                 coord_def rnd(random2(GXM), random2(GYM));
1785                 if (grd(rnd) != DNGN_FLOOR)
1786                     continue;
1787
1788                 if (travel_point_distance[rnd.x][rnd.y] != nzones)
1789                     continue;
1790
1791                 _set_grd(rnd, feat);
1792                 found_feature = true;
1793                 break;
1794             }
1795
1796             if (found_feature)
1797                 continue;
1798
1799             for (rectangle_iterator ri(0); ri; ++ri)
1800             {
1801                 if (grd(*ri) != DNGN_FLOOR)
1802                     continue;
1803
1804                 if (travel_point_distance[ri->x][ri->y] != nzones)
1805                     continue;
1806
1807                 _set_grd(*ri, feat);
1808                 found_feature = true;
1809                 break;
1810             }
1811
1812             if (found_feature)
1813                 continue;
1814
1815 #ifdef DEBUG_DIAGNOSTICS
1816             dump_map("debug.map", true, true);
1817 #endif
1818             // [ds] Too many normal cases trigger this ASSERT, including
1819             // rivers that surround a stair with deep water.
1820             // die("Couldn't find region.");
1821             return false;
1822         }
1823
1824     return true;
1825 }
1826
1827 static bool _add_connecting_escape_hatches()
1828 {
1829     // For any regions without a down stone stair case, add an
1830     // escape hatch.  This will always allow (downward) progress.
1831
1832     if (branches[you.where_are_you].branch_flags & BFLAG_ISLANDED)
1833         return true;
1834
1835     // Veto D:1 or Pan if there are disconnected areas.
1836     if (player_in_branch(BRANCH_PANDEMONIUM)
1837         || (player_in_branch(BRANCH_MAIN_DUNGEON) && you.depth == 1))
1838     {
1839         // Allow == 0 in case the entire level is one opaque vault.
1840         return dgn_count_disconnected_zones(false) <= 1;
1841     }
1842
1843     if (!player_in_connected_branch())
1844         return true;
1845
1846     if (at_branch_bottom())
1847         return dgn_count_disconnected_zones(true) == 0;
1848
1849     if (!_add_feat_if_missing(_is_perm_down_stair, DNGN_ESCAPE_HATCH_DOWN))
1850         return false;
1851
1852     // FIXME: shouldn't depend on branch.
1853     if (!player_in_branch(BRANCH_ORCISH_MINES))
1854         return true;
1855
1856     return _add_feat_if_missing(_is_upwards_exit_stair, DNGN_ESCAPE_HATCH_UP);
1857 }
1858
1859 static bool _branch_entrances_are_connected()
1860 {
1861     // Returns true if all branch entrances on the level are connected to
1862     // stone stairs.
1863     for (rectangle_iterator ri(0); ri; ++ri)
1864     {
1865         if (!feat_is_branch_stairs(grd(*ri)))
1866             continue;
1867         if (!_has_connected_stone_stairs_from(*ri))
1868             return false;
1869     }
1870
1871     return true;
1872 }
1873
1874 static bool _branch_needs_stairs()
1875 {
1876     // Irrelevant for branches with a single level and all encompass maps.
1877     return you.where_are_you != BRANCH_ZIGGURAT;
1878 }
1879
1880 static void _dgn_verify_connectivity(unsigned nvaults)
1881 {
1882     // After placing vaults, make sure parts of the level have not been
1883     // disconnected.
1884     if (dgn_zones && nvaults != env.level_vaults.size())
1885     {
1886         const int newzones = dgn_count_disconnected_zones(false);
1887
1888 #ifdef DEBUG_DIAGNOSTICS
1889         ostringstream vlist;
1890         for (unsigned i = nvaults; i < env.level_vaults.size(); ++i)
1891         {
1892             if (i > nvaults)
1893                 vlist << ", ";
1894             vlist << env.level_vaults[i]->map.name;
1895         }
1896         mprf(MSGCH_DIAGNOSTICS, "Dungeon has %d zones after placing %s.",
1897              newzones, vlist.str().c_str());
1898 #endif
1899         if (newzones > dgn_zones)
1900         {
1901             throw dgn_veto_exception(make_stringf(
1902                  "Had %d zones, now has %d%s%s.", dgn_zones, newzones,
1903 #ifdef DEBUG_DIAGNOSTICS
1904                  "; broken by ", vlist.str().c_str()
1905 #else
1906                  "", ""
1907 #endif
1908             ));
1909         }
1910     }
1911
1912     // Also check for isolated regions that have no stairs.
1913     if (player_in_connected_branch()
1914         && !(branches[you.where_are_you].branch_flags & BFLAG_ISLANDED)
1915         && dgn_count_disconnected_zones(true) > 0)
1916     {
1917         throw dgn_veto_exception("Isolated areas with no stairs.");
1918     }
1919
1920     if (_branch_needs_stairs() && !_fixup_stone_stairs(true))
1921     {
1922         dprf("Warning: failed to preserve vault stairs.");
1923         if (!_fixup_stone_stairs(false))
1924             throw dgn_veto_exception("Failed to fix stone stairs.");
1925     }
1926
1927     if (!_branch_entrances_are_connected())
1928         throw dgn_veto_exception("A disconnected branch entrance.");
1929
1930     if (!_add_connecting_escape_hatches())
1931         throw dgn_veto_exception("Failed to add connecting escape hatches.");
1932
1933     // XXX: Interlevel connectivity fixup relies on being the last
1934     //      point at which a level may be vetoed.
1935     if (!_fixup_interlevel_connectivity())
1936         throw dgn_veto_exception("Failed to ensure interlevel connectivity.");
1937 }
1938
1939 // Structure of OVERFLOW_TEMPLES:
1940 //
1941 // * A vector, with one cell per dungeon level (unset if there's no
1942 //   overflow temples on that level).
1943 //
1944 // * The cell of the previous vector is a vector, with one overflow
1945 //   temple definition per cell.
1946 //
1947 // * The cell of the previous vector is a hash table, containing the
1948 //   list of gods for the overflow temple and (optionally) the name of
1949 //   the vault to use for the temple.  If no map name is supplied,
1950 //   it will randomly pick from vaults tagged "temple_overflow_num",
1951 //   where "num" is the number of gods in the temple.  Gods are listed
1952 //   in the order their altars are placed.
1953 static void _build_overflow_temples()
1954 {
1955     // Levels built while in testing mode.
1956     if (!you.props.exists(OVERFLOW_TEMPLES_KEY))
1957         return;
1958
1959     CrawlVector &levels = you.props[OVERFLOW_TEMPLES_KEY].get_vector();
1960
1961     // Are we deeper than the last overflow temple?
1962     if (you.depth >= levels.size() + 1)
1963         return;
1964
1965     CrawlStoreValue &val = levels[you.depth - 1];
1966
1967     // Does this level have an overflow temple?
1968     if (val.get_flags() & SFLAG_UNSET)
1969         return;
1970
1971     CrawlVector &temples = val.get_vector();
1972
1973     if (temples.empty())
1974         return;
1975
1976     for (unsigned int i = 0; i < temples.size(); i++)
1977     {
1978         CrawlHashTable &temple = temples[i].get_table();
1979
1980         const int num_gods = _setup_temple_altars(temple);
1981
1982         const map_def *vault = NULL;
1983         string vault_tag = "";
1984         string name = "";
1985
1986         if (temple.exists(TEMPLE_MAP_KEY))
1987         {
1988             name = temple[TEMPLE_MAP_KEY].get_string();
1989
1990             vault = find_map_by_name(name);
1991             if (vault == NULL)
1992             {
1993                 mprf(MSGCH_ERROR,
1994                      "Couldn't find overflow temple map '%s'!",
1995                      name.c_str());
1996             }
1997         }
1998         else
1999         {
2000             // First try to find a temple specialized for this combination of
2001             // gods.
2002             if (num_gods > 1 || coinflip())
2003             {
2004                 vault_tag = make_stringf("temple_overflow_%d", num_gods);
2005
2006                 CrawlVector &god_vec = temple[TEMPLE_GODS_KEY];
2007
2008                 for (int j = 0; j < num_gods; j++)
2009                 {
2010                     god_type god = (god_type) god_vec[j].get_byte();
2011
2012                     name = god_name(god);
2013                     name = replace_all(name, " ", "_");
2014                     lowercase(name);
2015
2016                     vault_tag = vault_tag + " temple_overflow_" + name;
2017                 }
2018
2019                 if (num_gods == 1
2020                     && you.uniq_map_tags.find("uniq_altar_" + name)
2021                        != you.uniq_map_tags.end())
2022                 {
2023                     // We've already placed a specialized temple for this
2024                     // god, so do nothing.
2025 #ifdef DEBUG_TEMPLES
2026                     mprf(MSGCH_DIAGNOSTICS, "Already placed specialized "
2027                          "single-altar temple for %s", name.c_str());
2028 #endif
2029                     continue;
2030                 }
2031
2032                 vault = random_map_for_tag(vault_tag, true);
2033 #ifdef DEBUG_TEMPLES
2034                 if (vault == NULL)
2035                     mprf(MSGCH_DIAGNOSTICS, "Couldn't find overflow temple "
2036                          "for combination of tags %s", vault_tag.c_str());
2037 #endif
2038             }
2039
2040             if (vault == NULL)
2041             {
2042                 vault_tag = make_stringf("temple_overflow_generic_%d",
2043                                          num_gods);
2044
2045                 vault = random_map_for_tag(vault_tag, true);
2046                 if (vault == NULL)
2047                 {
2048                     mprf(MSGCH_ERROR,
2049                          "Couldn't find overflow temple tag '%s'!",
2050                          vault_tag.c_str());
2051                 }
2052             }
2053         }
2054
2055         if (vault == NULL)
2056             // Might as well build the rest of the level if we couldn't
2057             // find the overflow temple map, so don't veto the level.
2058             return;
2059
2060         {
2061             dgn_map_parameters mp(vault_tag);
2062             if (!_dgn_ensure_vault_placed(
2063                     _build_secondary_vault(vault),
2064                     false))
2065             {
2066 #ifdef DEBUG_TEMPLES
2067                 mprf(MSGCH_DIAGNOSTICS, "Couldn't place overflow temple '%s', "
2068                      "vetoing level.", vault->name.c_str());
2069 #endif
2070                 return;
2071             }
2072         }
2073 #ifdef DEBUG_TEMPLES
2074         mprf(MSGCH_DIAGNOSTICS, "Placed overflow temple %s",
2075              vault->name.c_str());
2076 #endif
2077     }
2078     _current_temple_hash = NULL; // XXX: hack!
2079 }
2080
2081 struct coord_feat
2082 {
2083     coord_def pos;
2084     dungeon_feature_type feat;
2085     terrain_property_t prop;
2086     unsigned int mask;
2087
2088     coord_feat(const coord_def &c, dungeon_feature_type f)
2089         : pos(c), feat(f), prop(0), mask(0)
2090     {
2091     }
2092
2093     void set_from(const coord_def &c)
2094     {
2095         feat = grd(c);
2096         // Don't copy mimic-ness.
2097         mask = env.level_map_mask(c) & ~(MMT_MIMIC);
2098         // Only copy "static" properties.
2099         prop = env.pgrid(c) & (FPROP_NO_CLOUD_GEN | FPROP_NO_TELE_INTO
2100                                | FPROP_NO_TIDE | FPROP_NO_SUBMERGE);
2101     }
2102 };
2103
2104 template <typename Iterator>
2105 static void _ruin_level(Iterator iter,
2106                         unsigned vault_mask = MMT_VAULT,
2107                         int ruination = 10,
2108                         int plant_density = 5,
2109                         int iterations = 1)
2110 {
2111     vector<coord_def> replaced;
2112
2113     for (int i = 0; i < iterations; ++i)
2114     {
2115         typedef vector<coord_feat> coord_feats;
2116         coord_feats to_replace;
2117         for (Iterator ri = iter; ri; ++ri)
2118         {
2119             // don't alter map boundary
2120             if (!in_bounds(*ri))
2121                 continue;
2122
2123             // only try to replace wall and door tiles
2124             if (!feat_is_wall(grd(*ri)) && !feat_is_door(grd(*ri)))
2125                 continue;
2126
2127             // don't mess with permarock
2128             if (grd(*ri) == DNGN_PERMAROCK_WALL)
2129                 continue;
2130
2131             // or vaults
2132             if (map_masked(*ri, vault_mask))
2133                 continue;
2134
2135             // Pick a random adjacent non-wall, non-door, non-statue
2136             // feature, and count the number of such features.
2137             coord_feat replacement(*ri, DNGN_UNSEEN);
2138             int floor_count = 0;
2139             for (adjacent_iterator ai(*ri); ai; ++ai)
2140             {
2141                 if (!feat_is_wall(grd(*ai)) && !feat_is_door(grd(*ai))
2142                     && !feat_is_statue_or_idol(grd(*ai))
2143                     // Shouldn't happen, but just in case.
2144                     && grd(*ai) != DNGN_MALIGN_GATEWAY)
2145                 {
2146                     if (one_chance_in(++floor_count))
2147                         replacement.set_from(*ai);
2148                 }
2149             }
2150
2151             // chance of removing the tile is dependent on the number of adjacent
2152             // floor(ish) tiles
2153             if (x_chance_in_y(floor_count, ruination))
2154                 to_replace.push_back(replacement);
2155         }
2156
2157         for (coord_feats::const_iterator it = to_replace.begin();
2158             it != to_replace.end();
2159             ++it)
2160         {
2161             const coord_def &p(it->pos);
2162             replaced.push_back(p);
2163             dungeon_feature_type replacement = it->feat;
2164             ASSERT(replacement != DNGN_UNSEEN);
2165
2166             // Don't replace doors with impassable features.
2167             if (feat_is_door(grd(p)))
2168             {
2169                 if (feat_is_water(replacement))
2170                     replacement = DNGN_SHALLOW_WATER;
2171                 else
2172                     replacement = DNGN_FLOOR;
2173             }
2174             else if (feat_has_solid_floor(replacement)
2175                     && replacement != DNGN_SHALLOW_WATER)
2176             {
2177                 // Exclude traps, shops, stairs, portals, altars, fountains.
2178                 // The first four, especially, are a big deal.
2179                 replacement = DNGN_FLOOR;
2180             }
2181
2182             // only remove some doors, to preserve tactical options
2183             if (feat_is_wall(grd(p)) || coinflip() && feat_is_door(grd(p)))
2184             {
2185                 // Copy the mask and properties too, so that we don't make an
2186                 // isolated transparent or rtele_into square.
2187                 env.level_map_mask(p) |= it->mask;
2188                 env.pgrid(p) |= it->prop;
2189                 _set_grd(p, replacement);
2190             }
2191
2192             // but remove doors if we've removed all adjacent walls
2193             for (adjacent_iterator wai(p); wai; ++wai)
2194             {
2195                 if (feat_is_door(grd(*wai)))
2196                 {
2197                     bool remove = true;
2198                     for (adjacent_iterator dai(*wai); dai; ++dai)
2199                     {
2200                         if (feat_is_wall(grd(*dai)))
2201                             remove = false;
2202                     }
2203                     // It's always safe to replace a door with floor.
2204                     if (remove)
2205                     {
2206                         env.level_map_mask(p) |= it->mask;
2207                         env.pgrid(p) |= it->prop;
2208                         _set_grd(*wai, DNGN_FLOOR);
2209                     }
2210                 }
2211             }
2212         }
2213     }
2214
2215
2216     for (vector<coord_def>::const_iterator it = replaced.begin();
2217          it != replaced.end();
2218          ++it)
2219     {
2220         const coord_def &p(*it);
2221
2222         // replace some ruined walls with plants/fungi/bushes
2223         if (plant_density && one_chance_in(plant_density)
2224             && feat_has_solid_floor(grd(p))
2225             && !plant_forbidden_at(p))
2226         {
2227             mgen_data mg;
2228             mg.cls = one_chance_in(20) ? MONS_BUSH  :
2229                      coinflip()        ? MONS_PLANT :
2230                      MONS_FUNGUS;
2231             mg.pos = p;
2232             mg.flags = MG_FORCE_PLACE;
2233             mons_place(mgen_data(mg));
2234         }
2235     }
2236 }
2237
2238 static bool _mimic_at_level()
2239 {
2240     return (!player_in_branch(BRANCH_MAIN_DUNGEON) || you.depth > 1)
2241            && !player_in_branch(BRANCH_ECUMENICAL_TEMPLE)
2242            && !player_in_branch(BRANCH_VESTIBULE_OF_HELL)
2243            && !player_in_branch(BRANCH_SLIME_PITS)
2244            && !player_in_branch(BRANCH_TOMB)
2245            && !player_in_branch(BRANCH_PANDEMONIUM)
2246            && !player_in_hell();
2247 }
2248
2249 static void _place_feature_mimics(dungeon_feature_type dest_stairs_type)
2250 {
2251     for (rectangle_iterator ri(1); ri; ++ri)
2252     {
2253         const coord_def pos = *ri;
2254         const dungeon_feature_type feat = grd(pos);
2255
2256         // Vault tag prevents mimic.
2257         if (map_masked(pos, MMT_NO_MIMIC))
2258             continue;
2259
2260         // Only features valid for mimicing.
2261         if (!is_valid_mimic_feat(feat))
2262             continue;
2263
2264         // Reduce the number of stairs and door mimics since those features
2265         // are very common.
2266         if ((feat_is_stone_stair(feat) || feat_is_escape_hatch(feat)
2267              || feat_is_door(feat)) && !one_chance_in(4))
2268         {
2269             continue;
2270         }
2271
2272         // Don't mimic the stairs the player is going to be placed on.
2273         if (feat == dest_stairs_type)
2274             continue;
2275
2276         // Don't mimic vetoed doors.
2277         if (door_vetoed(pos))
2278             continue;
2279
2280         // Don't mimic staircases in vaults to avoid trapping the player or
2281         // breaking vault layouts.
2282         if (map_masked(pos, MMT_VAULT)
2283             && (feat_is_escape_hatch(feat) || feat_is_stone_stair(feat)))
2284         {
2285             continue;
2286         }
2287
2288         // If this is the real branch entry, don't mimic it.
2289         if (feat_is_branch_stairs(feat)
2290             && you.depth == startdepth[get_branch_at(pos)])
2291         {
2292             continue;
2293         }
2294
2295         // If it is a branch entry, it's been put there for mimicing.
2296         if (feat_is_branch_stairs(feat) || one_chance_in(FEATURE_MIMIC_CHANCE))
2297         {
2298             // For normal stairs, there is a chance to create another mimics
2299             // elsewhere instead of turning this one. That way, when the 3
2300             // stairs are grouped and there is another isolated one, any of
2301             // the 4 staircase can be the mimic.
2302             if (feat_is_stone_stair(feat) && one_chance_in(4))
2303             {
2304                 const coord_def new_pos = _place_specific_feature(feat);
2305                 dprf("Placed %s mimic at (%d,%d).",
2306                      feat_type_name(feat), new_pos.x, new_pos.y);
2307                 env.level_map_mask(new_pos) |= MMT_MIMIC;
2308                 continue;
2309             }
2310
2311             dprf("Placed %s mimic at (%d,%d).",
2312                  feat_type_name(feat), ri->x, ri->y);
2313             env.level_map_mask(*ri) |= MMT_MIMIC;
2314
2315             // If we're mimicing a unique portal vault, give a chance for
2316             // another one to spawn.
2317             string dst = env.markers.property_at(pos, MAT_ANY, "dstname");
2318             if (dst.empty())
2319                 dst = env.markers.property_at(pos, MAT_ANY, "dst");
2320             if (!dst.empty())
2321             {
2322                 const string tag = "uniq_" + lowercase_string(dst);
2323                 if (you.uniq_map_tags.find(tag) != you.uniq_map_tags.end())
2324                     you.uniq_map_tags.erase(tag);
2325             }
2326         }
2327     }
2328 }
2329
2330 static void _place_item_mimics()
2331 {
2332     // No mimics on D:1
2333     if (!env.absdepth0)
2334         return;
2335
2336     for (int i = 0; i < MAX_ITEMS; i++)
2337     {
2338         item_def& item(mitm[i]);
2339         if (!item.defined() || !in_bounds(item.pos)
2340             || item.flags & ISFLAG_NO_MIMIC
2341             || !is_valid_mimic_item(item.base_type)
2342             || mimic_at(item.pos))
2343         {
2344             continue;
2345         }
2346
2347         if (one_chance_in(ITEM_MIMIC_CHANCE))
2348         {
2349             item.flags |= ISFLAG_MIMIC;
2350             dprf("Placed a %s mimic at (%d,%d).",
2351                  item.name(DESC_BASENAME).c_str(), item.pos.x, item.pos.y);
2352         }
2353     }
2354
2355 }
2356
2357 // Apply modifications (ruination, plant clumps) that should happen
2358 // regardless of game mode.
2359 static void _post_vault_build()
2360 {
2361     if (player_in_branch(BRANCH_LAIR))
2362     {
2363         int depth = you.depth + 1;
2364         _ruin_level(rectangle_iterator(1), MMT_VAULT,
2365                     20 - depth, depth / 2 + 4, 1 + (depth / 3));
2366         do
2367         {
2368             _add_plant_clumps(12 - depth, 18 - depth / 4, depth / 4 + 2);
2369             depth -= 3;
2370         } while (depth > 0);
2371     }
2372
2373     if (player_in_branch(BRANCH_FOREST))
2374         _add_plant_clumps(2);
2375 }
2376
2377 static void _build_dungeon_level(dungeon_feature_type dest_stairs_type)
2378 {
2379     bool place_vaults = _builder_by_type();
2380
2381     if (player_in_branch(BRANCH_LABYRINTH))
2382         return;
2383
2384     if (player_in_branch(BRANCH_SLIME_PITS))
2385         _slime_connectivity_fixup();
2386
2387     // Now place items, mons, gates, etc.
2388     // Stairs must exist by this point (except in Shoals where they are
2389     // yet to be placed). Some items and monsters already exist.
2390
2391     _check_doors();
2392
2393     const unsigned nvaults = env.level_vaults.size();
2394
2395     // Any further vaults must make sure not to disrupt level layout.
2396     dgn_check_connectivity = true;
2397
2398     if (player_in_branch(BRANCH_MAIN_DUNGEON)
2399         && !crawl_state.game_is_tutorial())
2400     {
2401         _build_overflow_temples();
2402     }
2403
2404     // Try to place minivaults that really badly want to be placed. Still
2405     // no guarantees, seeing this is a minivault.
2406     if (crawl_state.game_standard_levelgen())
2407     {
2408         if (place_vaults)
2409         {
2410             // Moved branch entries to place first so there's a good
2411             // chance of having room for a vault
2412             _place_branch_entrances(true);
2413             _place_chance_vaults();
2414             _place_minivaults();
2415             _place_extra_vaults();
2416         }
2417         else
2418         {
2419             // Place any branch entries vaultlessly
2420             _place_branch_entrances(false);
2421             // Still place chance vaults - important things like Abyss,
2422             // Hell, Pan entries are placed this way
2423             _place_chance_vaults();
2424         }
2425
2426         // Ruination and plant clumps.
2427         _post_vault_build();
2428
2429         // XXX: Moved this here from builder_monsters so that
2430         //      connectivity can be ensured
2431         _place_uniques();
2432
2433         if (_mimic_at_level())
2434             _place_feature_mimics(dest_stairs_type);
2435
2436         // Any vault-placement activity must happen before this check.
2437         _dgn_verify_connectivity(nvaults);
2438
2439         _place_traps();
2440
2441         // Place monsters.
2442         if (!crawl_state.game_is_zotdef())
2443             _builder_monsters();
2444
2445         // Place items.
2446         _builder_items();
2447
2448         _fixup_walls();
2449     }
2450     else
2451     {
2452         // Do ruination and plant clumps even in funny game modes, if
2453         // they happen to have the relevant branch.
2454         _post_vault_build();
2455     }
2456
2457     _fixup_branch_stairs();
2458     fixup_misplaced_items();
2459
2460     link_items();
2461     if (_mimic_at_level())
2462         _place_item_mimics();
2463
2464     if (!player_in_branch(BRANCH_COCYTUS)
2465         && !player_in_branch(BRANCH_SWAMP)
2466         && !player_in_branch(BRANCH_SHOALS))
2467     {
2468         _prepare_water();
2469     }
2470
2471     // Translate stairs for pandemonium levels.
2472     if (player_in_branch(BRANCH_PANDEMONIUM))
2473         _fixup_pandemonium_stairs();
2474
2475     if (player_in_hell())
2476         _fixup_hell_stairs();
2477 }
2478
2479 static void _dgn_set_floor_colours()
2480 {
2481     colour_t old_floor_colour = env.floor_colour;
2482     colour_t old_rock_colour  = env.rock_colour;
2483
2484     const int youbranch = you.where_are_you;
2485     env.floor_colour    = branches[youbranch].floor_colour;
2486     env.rock_colour     = branches[youbranch].rock_colour;
2487
2488     if (old_floor_colour != BLACK)
2489         env.floor_colour = old_floor_colour;
2490     if (old_rock_colour != BLACK)
2491         env.rock_colour = old_rock_colour;
2492
2493     if (env.floor_colour == BLACK)
2494         env.floor_colour = LIGHTGREY;
2495     if (env.rock_colour == BLACK)
2496         env.rock_colour  = BROWN;
2497 }
2498
2499 static void _check_doors()
2500 {
2501     for (rectangle_iterator ri(1); ri; ++ri)
2502     {
2503         if (!feat_is_closed_door(grd(*ri)))
2504             continue;
2505
2506         int solid_count = 0;
2507
2508         for (orth_adjacent_iterator rai(*ri); rai; ++rai)
2509             if (cell_is_solid(*rai))
2510                 solid_count++;
2511
2512         if (solid_count < 2)
2513             _set_grd(*ri, DNGN_FLOOR);
2514     }
2515 }
2516
2517 int count_feature_in_box(int x0, int y0, int x1, int y1,
2518                          dungeon_feature_type feat)
2519 {
2520     int result = 0;
2521     for (int i = x0; i < x1; ++i)
2522         for (int j = y0; j < y1; ++j)
2523         {
2524             if (grd[i][j] == feat)
2525                 ++result;
2526         }
2527
2528     return result;
2529 }
2530
2531 // Count how many neighbours of grd[x][y] are the feature feat.
2532 int count_neighbours(int x, int y, dungeon_feature_type feat)
2533 {
2534     return count_feature_in_box(x-1, y-1, x+2, y+2, feat);
2535 }
2536
2537 // Gives water which is next to ground/shallow water a chance of being
2538 // shallow. Checks each water space.
2539 static void _prepare_water()
2540 {
2541     dungeon_feature_type which_grid;   // code compaction {dlb}
2542     int absdepth0 = env.absdepth0;
2543
2544     for (rectangle_iterator ri(1); ri; ++ri)
2545     {
2546         if (map_masked(*ri, MMT_NO_POOL))
2547             continue;
2548
2549         if (grd(*ri) == DNGN_DEEP_WATER)
2550         {
2551             for (adjacent_iterator ai(*ri); ai; ++ai)
2552             {
2553                 which_grid = grd(*ai);
2554
2555                 // must come first {dlb}
2556                 if (which_grid == DNGN_SHALLOW_WATER
2557                     && one_chance_in(8 + absdepth0))
2558                 {
2559                     grd(*ri) = DNGN_SHALLOW_WATER;
2560                 }
2561                 else if (feat_has_dry_floor(which_grid)
2562                          && x_chance_in_y(80 - absdepth0 * 4,
2563                                           100))
2564                 {
2565                     _set_grd(*ri, DNGN_SHALLOW_WATER);
2566                 }
2567             }
2568         }
2569     }
2570 }
2571
2572 static bool _vault_can_use_layout(const map_def *vault, const map_def *layout)
2573 {
2574     if (!vault->has_tag_prefix("layout_"))
2575         return true;
2576
2577     ASSERT(layout->has_tag_prefix("layout_type_"));
2578
2579     vector<string> tags = layout->get_tags();
2580
2581     for (unsigned int i = 0; i < tags.size(); i++)
2582     {
2583         if (starts_with(tags[i], "layout_type_"))
2584         {
2585             string type = strip_tag_prefix(tags[i], "layout_type_");
2586             if (vault->has_tag("layout_" + type))
2587                 return true;
2588         }
2589     }
2590
2591     return false;
2592 }
2593
2594 static const map_def *_pick_layout(const map_def *vault)
2595 {
2596     const map_def *layout = NULL;
2597
2598     // This is intended for use with primary vaults, so...
2599     ASSERT(vault);
2600
2601     // For centred maps, try to pick a central-type layout first.
2602     if (vault->orient == MAP_CENTRE)
2603         layout = random_map_for_tag("central", true, true);
2604
2605     int tries = 100;
2606
2607     if (!layout)
2608     {
2609         do
2610         {
2611             if (!tries--)
2612             {
2613                 die("Couldn't find a layout for %s",
2614                     level_id::current().describe().c_str());
2615             }
2616             layout = random_map_for_tag("layout", true, true);
2617         }
2618         while (layout->has_tag("no_primary_vault")
2619                || (tries > 10 && !_vault_can_use_layout(vault, layout)));
2620     }
2621
2622     return layout;
2623 }
2624
2625 static bool _pan_level()
2626 {
2627     const char *pandemon_level_names[] =
2628         { "mnoleg", "lom_lobon", "cerebov", "gloorx_vloq", };
2629     int which_demon = -1;
2630     PlaceInfo &place_info = you.get_place_info();
2631     bool all_demons_generated = true;
2632
2633     if (you.props.exists("force_map"))
2634     {
2635         const map_def *vault =
2636             find_map_by_name(you.props["force_map"].get_string());
2637         ASSERT(vault);
2638
2639         _dgn_ensure_vault_placed(_build_primary_vault(vault), true);
2640         return vault->orient != MAP_ENCOMPASS;
2641     }
2642
2643     for (int i = 0; i < 4; i++)
2644     {
2645         if (!you.uniq_map_tags.count(string("uniq_") + pandemon_level_names[i]))
2646         {
2647             all_demons_generated = false;
2648             break;
2649         }
2650     }
2651
2652     // Unique pan lords become more common as you travel through pandemonium.
2653     // On average it takes 27 levels to see all four, and you're likely to see
2654     // your first one after about 10 levels.
2655     if (x_chance_in_y(1 + place_info.levels_seen, 65 + place_info.levels_seen * 2)
2656         && !all_demons_generated)
2657     {
2658         do
2659             which_demon = random2(4);
2660         while (you.uniq_map_tags.count(string("uniq_")
2661                                        + pandemon_level_names[which_demon]));
2662     }
2663
2664     if (which_demon >= 0)
2665     {
2666         const map_def *vault =
2667             random_map_for_tag(pandemon_level_names[which_demon], false);
2668
2669         ASSERT(vault);
2670
2671         _dgn_ensure_vault_placed(_build_primary_vault(vault), true);
2672         return vault->orient != MAP_ENCOMPASS;
2673     }
2674     else
2675     {
2676         const map_def *vault = random_map_for_tag("pan", true);
2677         ASSERT(vault);
2678
2679         if (vault->orient == MAP_ENCOMPASS)
2680         {
2681             _dgn_ensure_vault_placed(_build_primary_vault(vault), true);
2682             return false;
2683         }
2684         else
2685         {
2686             const map_def *layout = _pick_layout(vault);
2687
2688             {
2689                 dgn_map_parameters mp(vault->orient == MAP_CENTRE
2690                                       ? "central" : "layout");
2691                 _dgn_ensure_vault_placed(_build_primary_vault(layout), true);
2692             }
2693
2694             dgn_check_connectivity = true;
2695             _build_secondary_vault(vault);
2696             return true;
2697         }
2698     }
2699 }
2700
2701 // Returns true if we want the dungeon builder
2702 // to place more vaults after this
2703 static bool _builder_by_type()
2704 {
2705     if (player_in_branch(BRANCH_LABYRINTH))
2706     {
2707         dgn_build_labyrinth_level();
2708         // Labs placed their minivaults already
2709         return false;
2710     }
2711     else if (player_in_branch(BRANCH_ABYSS))
2712     {
2713         generate_abyss();
2714         // Should place some vaults in abyss because
2715         // there's never an encompass vault
2716         return true;
2717     }
2718     else if (player_in_branch(BRANCH_PANDEMONIUM))
2719     {
2720         // Generate a random monster table for Pan.
2721         init_pandemonium();
2722         setup_vault_mon_list();
2723         return _pan_level();
2724     }
2725     else
2726         return _builder_normal();
2727 }
2728
2729 static const map_def *_dgn_random_map_for_place(bool minivault)
2730 {
2731     if (!minivault && player_in_branch(BRANCH_ECUMENICAL_TEMPLE))
2732     {
2733         // Temple vault determined at new game time.
2734         const string name = you.props[TEMPLE_MAP_KEY];
2735
2736         // Tolerate this for a little while, for old games.
2737         if (!name.empty())
2738         {
2739             const map_def *vault = find_map_by_name(name);
2740
2741             if (vault)
2742                 return vault;
2743
2744             mprf(MSGCH_ERROR, "Unable to find Temple vault '%s'",
2745                  name.c_str());
2746
2747             // Fall through and use a different Temple map instead.
2748         }
2749     }
2750
2751     const level_id lid = level_id::current();
2752
2753     const map_def *vault = 0;
2754
2755     if (you.props.exists("force_map"))
2756         vault = find_map_by_name(you.props["force_map"].get_string());
2757     else if (lid.branch == root_branch && lid.depth == 1
2758         && (crawl_state.game_is_sprint()
2759             || crawl_state.game_is_zotdef()
2760             || crawl_state.game_is_tutorial()))
2761     {
2762         vault = find_map_by_name(crawl_state.map);
2763         if (vault == NULL)
2764         {
2765             end(1, false, "Couldn't find selected map '%s'.",
2766                 crawl_state.map.c_str());
2767         }
2768     }
2769
2770     if (!vault)
2771         // Pick a normal map
2772         vault = random_map_for_place(lid, minivault);
2773
2774     if (!vault && lid.branch == root_branch && lid.depth == 1)
2775         vault = random_map_for_tag("entry");
2776
2777     return vault;
2778 }
2779
2780 static int _setup_temple_altars(CrawlHashTable &temple)
2781 {
2782     _current_temple_hash = &temple; // XXX: hack!
2783
2784     CrawlVector god_list = temple[TEMPLE_GODS_KEY].get_vector();
2785
2786     _temple_altar_list.clear();
2787
2788     for (unsigned int i = 0; i < god_list.size(); i++)
2789         _temple_altar_list.push_back((god_type) god_list[i].get_byte());
2790
2791     return (int)god_list.size();
2792 }
2793
2794 struct map_component
2795 {
2796     int label;
2797
2798     map_component()
2799     {
2800         min_equivalent = NULL;
2801     }
2802     map_component * min_equivalent;
2803
2804
2805     coord_def min_coord;
2806     coord_def max_coord;
2807
2808     coord_def seed_position;
2809
2810     void start_component(const coord_def & pos, int in_label)
2811     {
2812         seed_position = pos;
2813         min_coord = pos;
2814         max_coord = pos;
2815
2816         label = in_label;
2817         min_equivalent = NULL;
2818     }
2819
2820     void add_coord(const coord_def & pos)
2821     {
2822         if (pos.x < min_coord.x)
2823             min_coord.x = pos.x;
2824         if (pos.x > max_coord.x)
2825             max_coord.x = pos.x;
2826         if (pos.y < min_coord.y)
2827             min_coord.y = pos.y;
2828         if (pos.y > max_coord.y)
2829             max_coord.y = pos.y;
2830     }
2831
2832     void merge_region(const map_component & existing)
2833     {
2834         add_coord(existing.min_coord);
2835         add_coord(existing.max_coord);
2836     }
2837 };
2838
2839 static int _min_transitive_label(map_component & component)
2840 {
2841     map_component * current = &component;
2842
2843     int label;
2844     do
2845     {
2846         label = current->label;
2847
2848         current = current->min_equivalent;
2849     } while (current);
2850
2851     return label;
2852 }
2853
2854 // 8-way connected component analysis on the current level map.
2855 template<typename comp>
2856 static void _ccomps_8(FixedArray<int, GXM, GYM > & connectivity_map,
2857                       vector<map_component> & components, comp & connected)
2858 {
2859     map<int, map_component> intermediate_components;
2860
2861     connectivity_map.init(0);
2862     components.clear();
2863
2864     unsigned adjacent_size = 4;
2865     coord_def offsets[4] = {coord_def(-1, 0), coord_def(-1, -1), coord_def(0, -1), coord_def(1, -1)};
2866
2867     int next_label = 1;
2868
2869
2870     // Pass 1, for each point, check the upper/left adjacent squares for labels
2871     // if a labels are found, use the min connected label, else assign a new
2872     // label and start a new component
2873     for (rectangle_iterator pos(1); pos; ++pos)
2874     {
2875         if (connected(*pos))
2876         {
2877             int absolute_min_label = INT_MAX;
2878             set<int> neighbor_labels;
2879             for (unsigned i = 0; i < adjacent_size; i++)
2880             {
2881                 coord_def test = *pos + offsets[i];
2882                 if (in_bounds(test) && connectivity_map(test) != 0)
2883                 {
2884                     int neighbor_label = connectivity_map(test);
2885                     if (neighbor_labels.insert(neighbor_label).second)
2886                     {
2887                         int trans = _min_transitive_label(intermediate_components[neighbor_label]);
2888
2889                         if (trans < absolute_min_label)
2890                             absolute_min_label = trans;
2891                     }
2892                 }
2893             }
2894
2895             int label;
2896             if (neighbor_labels.empty())
2897             {
2898                 intermediate_components[next_label].start_component(*pos, next_label);
2899                 label = next_label;
2900                 next_label++;
2901             }
2902             else
2903             {
2904                 label = absolute_min_label;
2905                 map_component * absolute_min = &intermediate_components[absolute_min_label];
2906
2907                 absolute_min->add_coord(*pos);
2908                 for (set<int>::iterator i = neighbor_labels.begin();
2909                      i != neighbor_labels.end();i++)
2910                 {
2911                     map_component * current = &intermediate_components[*i];
2912
2913                     while (current && current != absolute_min)
2914                     {
2915                         absolute_min->merge_region(*current);
2916                         map_component * next = current->min_equivalent;
2917                         current->min_equivalent = absolute_min;
2918                         current = next;
2919                     }
2920                 }
2921             }
2922             connectivity_map(*pos) = label;
2923         }
2924     }
2925
2926     int reindexed_label = 1;
2927     // Reindex root labels, and move them to output
2928     for (map<int, map_component>::iterator i = intermediate_components.begin();
2929          i != intermediate_components.end(); ++i)
2930     {
2931         if (i->second.min_equivalent == NULL)
2932         {
2933             i->second.label = reindexed_label++;
2934             components.push_back(i->second);
2935         }
2936     }
2937
2938     // Pass 2, mark new labels on the grid
2939     for (rectangle_iterator pos(1); pos; ++pos)
2940     {
2941         int label = connectivity_map(*pos);
2942         if (label  != 0)
2943             connectivity_map(*pos) = _min_transitive_label(intermediate_components[label]);
2944     }
2945 }
2946
2947 // Is this square a wall, or does it belong to a vault? both are considered to
2948 // block connectivity.
2949 static bool _passable_square(const coord_def & pos)
2950 {
2951     return !feat_is_wall(env.grid(pos)) && !(env.level_map_mask(pos) & MMT_VAULT);