summaryrefslogblamecommitdiffstats
path: root/crawl-ref/source/mapdef.h
blob: a8a237650c99981782102d32dd8e772e9706d254 (plain) (tree)
1
2
3
4
5


                                                        

                                                         








                                                                          
                 
                 
 
                 
                 
                    
                   
                  
                     
                        
 





















                                                                             







                            
 
       
                               
                       
                            
              

       

                                                                              

                                
                                                                          
 
                 

                                         
 

                              
 

                       
 
                                                                 
 


                                        

                                                   
                                



                                 





                                                                            

  


                                                                       
                
 
                

       


                                                                                
 
                
 



                                                              
              

             
                     
 


                              
                 

       
                                                                       
       
                    


                                  
                                                




                                                               
                 

       
                                                                          


                                                                   



                     
                    



                            
 
                                                         







                                                             
                                                                        



                                                                     
                                 

       
                    
             
                             


                          

                                              
                                                           



                                                 

               

       

                                                                                                                   



                                      


                   
                    

                     
                   
               
              




                        
                     
 
       
                    
                       
 


                                        
                                                              

                                               
                                                          

                                                            
                                                


                                

  

























                                                                          
              
                         
                     

               

                



                                              
 
                                            
 
                                        
                                                  

                                                  
                                                   
                                                      
                         
 


                                                    
                                                    

      
                                                                       

                                                       
                                                                
 





                                                                                



                                               
                           
 
                                  
                                       
                                 
 
                                                
 
                                      
                                     







                                                          

                                                            

                                                      
 
                                             
                                                  
                                              
 
                                                      
                                          
 


                                                


                                          







                                                              
                                             


                                                                           
 






                                                                       





                                                                         
        
                                         








                                                                          
 
                                                     
                                                 
                             
                               
                                        
                                      





                                                                       


                                    
                         
                                       
                                                    


                                                          




                                                       

                                                                    
 
               
                                                                              
      
 








                                                                      
                            
                             
                              
                                 
                             
                           
 
        
                                      
                                   
 

                      
                                                                      
                                                                        


                      
                 
                       
                     
                        


                                               
 








                                                     
                  

                                                          

  

                   


                       
                       
                       
                          




                  
 

                                
                    




                      
                           
                   
 


                                                                      
                                                                             
                                                                 
                                                                   
                        













                                                
                                                



                                                                    


                                                                









                                                   
 



                                                         
                                                            








                                                               
               
 
        
             
                   
                                                                    
                               
                                                            
                                                                
                           

                        
                    
              
                

            

                             
 
                    
                        
                                   
 



                                      

                         
                                      
                                                  
                          
                                      
                                                                              


                                                                              

                                                                                
                                                    



     

               
       


                 
 


                                                                
                                     
                                                                
 
                                                              
                                                                      
                                                         
 

                                                                        

        
















                                                                    
 
        
                                                   
                                                   

                                                               
                                                            

                                                             
                                                     
                                                                       
                                                 
                                
                                                                      

        

                                       

  





















                                                                             
                                             

  

                
                                         

                
                 





                                                                    


                    
                           
 


                      
                          



                    


                                                                 


                                                         
                                                             
 

                                                            



                                              
 
                            


                                










                                                          

                                              






                               
              
                                                                                   
 
















                                                           

                                                                             
  
                                            
  

                                                                     
  





                                                                      
  








                                                                      
  

             


                         
                          

                            
                            

                                     
                            
                            

                                       
 

                                              

                         
                          
 





                                                    

                                       

                                              
                                                            
 

                                      

                              
                                              
                                          
 
                                          



                                                                      
                         
 





                                                             
       
              
                

                  
                
 
                                          

                                                                           
 

                                                       
                                                                
 

                                    
 

                             
 

                                        
 
                                             
                                               




                                                                 
                                      

                                                                



                                                           



                                
                          

                 
                                                 
 

                                                              




                                                    
 



                                               
                                          

                                         

                                                 

                                               
                                                      
                                                         
                                              
 

                                                         


                                           










                                                                








                                                                       
                                                 












                                                           
 
        
 

                                           
                                                                                
                                                                 
                                              

  

                              

                                                                   






                                                       
                                        

      
/*
 * mapdef.h:
 * Header for map structures used by the level compiler.
 * Created by: dshaligram on Wed Nov 22 08:41:20 2006 UTC
 *
 * NOTE: When we refer to map, this could be a full map, filling an entire
 * level or a minivault that occupies just a portion of the level.
 */

#ifndef __MAPDEF_H__
#define __MAPDEF_H__

#include <string>
#include <vector>
#include <cstdio>
#include <memory>

#include "dlua.h"
#include "enum.h"
#include "externs.h"
#include "matrix.h"
#include "fprop.h"
#include "makeitem.h"
#include "travel_defs.h"

// [dshaligram] Maps can be mirrored; for every orientation, there must be
// a suitable mirror.
enum map_section_type                  // see maps.cc and dungeon.cc {dlb}
{
    MAP_NONE  = -1,
    MAP_NORTH = 1,                     //    1
    MAP_SOUTH,
    MAP_EAST,
    MAP_WEST,
    MAP_NORTHWEST,                     //    5
    MAP_NORTHEAST,
    MAP_SOUTHWEST,
    MAP_SOUTHEAST,
    MAP_ENCOMPASS,

    // A "floating" vault is placed somewhat like a minivault, away from
    // the edges, although in other respects it behaves like a regular vault.
    MAP_FLOAT,

    MAP_NUM_SECTION_TYPES
};

struct raw_range
{
    branch_type branch;
    int shallowest, deepest;
    bool deny;
};

struct level_range
{
public:
    level_area_type level_type;
    branch_type branch;
    int shallowest, deepest;
    bool deny;

public:
    level_range(const raw_range &range);
    level_range(branch_type br = BRANCH_MAIN_DUNGEON, int s = -1, int d = -1);

    void set(int s, int d = -1);
    void set(const std::string &branch, int s, int d) throw (std::string);

    void reset();
    bool matches(const level_id &) const;
    bool matches(int depth) const;

    void write(writer&) const;
    void read(reader&);

    bool valid() const;
    int span() const;

    static level_range parse(std::string lr) throw (std::string);

    std::string describe() const;
    std::string str_depth_range() const;

    bool operator == (const level_range &lr) const;

    operator raw_range () const;
    operator std::string () const
    {
        return describe();
    }

private:
    static void parse_partial(level_range &lr, const std::string &s)
        throw (std::string);
    static void parse_depth_range(const std::string &s, int *low, int *high)
        throw (std::string);
};

typedef std::pair<int,int> glyph_weighted_replacement_t;
typedef std::vector<glyph_weighted_replacement_t> glyph_replacements_t;

class map_lines;

class subst_spec
{
public:
    subst_spec(std::string torepl, bool fix, const glyph_replacements_t &repls);
    subst_spec(int count, bool fix, const glyph_replacements_t &repls);
    subst_spec() : key(""), count(-1), fix(false), frozen_value(0), repl() { }

    int value();

public:
    std::string key;
    // If this is part of an nsubst spec, how many to replace.
    // -1 corresponds to all (i.e. '*')
    int count;

    bool fix;
    int frozen_value;

    glyph_replacements_t repl;
};

class nsubst_spec
{
public:
    nsubst_spec(std::string key, const std::vector<subst_spec> &specs);
public:
    std::string key;
    std::vector<subst_spec> specs;
};

typedef std::pair<int, int> map_weighted_colour;
class map_colour_list : public std::vector<map_weighted_colour>
{
public:
    bool parse(const std::string &s, int weight);
};
class colour_spec
{
public:
    colour_spec(std::string _key, bool _fix, const map_colour_list &clist)
        : key(_key), fix(_fix), fixed_colour(BLACK), colours(clist)
    {
    }

    int get_colour();

public:
    std::string key;
    bool fix;
    int fixed_colour;
    map_colour_list colours;
};

typedef std::pair<unsigned long, int> map_weighted_fprop;
class map_fprop_list : public std::vector<map_weighted_fprop>
{
public:
    bool parse(const std::string &fp, int weight);
};
class fprop_spec
{
public:
    fprop_spec(std::string _key, bool _fix, const map_fprop_list &flist)
        : key(_key), fix(_fix), fixed_prop(FPROP_NONE), fprops(flist)
    {
    }

    unsigned long get_property();

public:
    std::string key;
    bool fix;
    unsigned long fixed_prop;
    map_fprop_list fprops;
};

#ifdef USE_TILE
typedef std::pair<int, int> map_weighted_tile;
class map_tile_list : public std::vector<map_weighted_tile>
{
public:
    bool parse(const std::string &s, int weight);
};

class tile_spec
{
public:
    tile_spec(const std::string &_key, bool _fix, bool _rand, bool _floor, bool _feat, const map_tile_list &_tiles)
        : key(_key), fix(_fix), chose_fixed(false), no_random(_rand), floor(_floor), feat(_feat),
          fixed_tile(0), tiles(_tiles)
    {
    }

    int get_tile();

public:
    std::string key;
    bool fix;
    bool chose_fixed;
    bool no_random;
    bool floor;
    bool feat;
    int fixed_tile;
    map_tile_list tiles;
};
#endif

class map_marker_spec
{
public:
    std::string key;
    std::string marker;

    // Special handling for Lua markers:
    std::auto_ptr<lua_datum> lua_fn;

    map_marker_spec(std::string _key, const std::string &mark)
        : key(_key), marker(mark), lua_fn() { }

    map_marker_spec(std::string _key, const lua_datum &fn)
        : key(_key), marker(), lua_fn(new lua_datum(fn)) { }

    std::string apply_transform(map_lines &map);

private:
    map_marker *create_marker();
};

typedef std::pair<std::string, int> map_weighted_string;
class map_string_list : public std::vector<map_weighted_string>
{
public:
    bool parse(const std::string &fp, int weight);
};
class string_spec
{
public:
    string_spec(std::string _key, bool _fix, const map_string_list &slist)
        : key(_key), fix(_fix), fixed_str(""), strlist(slist)
    {
    }

    std::string get_property();

public:
    std::string key;
    bool fix;
    std::string fixed_str;
    map_string_list strlist;
};

template<class T>
std::string parse_weighted_str(const std::string &cspec, T &list);

class map_def;
class rectangle_iterator;
struct keyed_mapspec;
class map_lines
{
public:
    map_lines();
    map_lines(const map_lines &);
    ~map_lines();

    map_lines &operator = (const map_lines &);

    bool in_map(const coord_def &pos) const;

    void add_line(const std::string &s);
    std::string add_nsubst(const std::string &st);
    std::string add_subst(const std::string &st);
    std::string add_shuffle(const std::string &s);
    std::string add_colour(const std::string &col);
    std::string add_fproperty(const std::string &sub);
    void clear_markers();

#ifdef USE_TILE
    std::string add_floortile(const std::string &s);
    std::string add_rocktile(const std::string &s);
    std::string add_spec_tile(const std::string &s);
#endif

    std::vector<coord_def> find_glyph(const std::string &glyphs) const;
    std::vector<coord_def> find_glyph(int glyph) const;
    coord_def find_first_glyph(int glyph) const;
    coord_def find_first_glyph(const std::string &glyphs) const;

    // Find rectangular bounds (inclusive) for uses of the glyph in the map.
    // Returns false if glyph could not be found.
    bool find_bounds(int glyph, coord_def &tl, coord_def &br) const;
    // Same as above, but for any of the glyphs in glyph_str.
    bool find_bounds(const char *glyph_str, coord_def &tl, coord_def &br) const;

    void set_orientation(const std::string &s);

    int width() const;
    int height() const;
    coord_def size() const;

    int glyph(int x, int y) const;
    int glyph(const coord_def &) const;
    bool is_solid(int gly) const;

    bool solid_borders(map_section_type border);

    // Make all lines the same length.
    void normalise(char fillc = ' ');

    // Rotate 90 degrees either clockwise or anticlockwise
    void rotate(bool clockwise);
    void hmirror();
    void vmirror();

    void clear();

    void add_marker(map_marker *marker);
    std::string add_feature_marker(const std::string &desc);
    std::string add_lua_marker(const std::string &key,
                               const lua_datum &fn);

    void apply_markers(const coord_def &pos);
    void apply_grid_overlay(const coord_def &pos);
    void apply_overlays(const coord_def &pos);

    const std::vector<std::string> &get_lines() const;
    std::vector<std::string> &get_lines();

    rectangle_iterator get_iter() const;
    char operator () (const coord_def &c) const;
    char& operator () (const coord_def &c);
    char operator () (int x, int y) const;
    char& operator () (int x, int y);

    const keyed_mapspec *mapspec_at(const coord_def &c) const;
    keyed_mapspec *mapspec_at(const coord_def &c);

    std::string add_key_item(const std::string &s);
    std::string add_key_mons(const std::string &s);
    std::string add_key_feat(const std::string &s);
    std::string add_key_mask(const std::string &s);

    bool in_bounds(const coord_def &c) const;

    // Extend map dimensions with glyph 'fill' to minimum width and height.
    void extend(int min_width, int min_height, char fill);

    bool fill_zone(travel_distance_grid_t &tpd, const coord_def &start,
                   const coord_def &tl, const coord_def &br, int zone,
                   const char *wanted, const char *passable) const;

    int count_feature_in_box(const coord_def &tl, const coord_def &br,
                             const char *feat) const;

    void fill_mask_matrix(const std::string &glyphs, const coord_def &tl,
                          const coord_def &br, Matrix<bool> &flags);

    // Merge vault onto the tl/br subregion, where mask is true.
    void merge_subvault(const coord_def &tl, const coord_def &br,
                        const Matrix<bool> &mask, const map_def &vault);
private:
    void init_from(const map_lines &map);
    template <typename V> void clear_vector(V &vect);
    void vmirror_markers();
    void hmirror_markers();
    void rotate_markers(bool clock);
    void vmirror_marker(map_marker *, int par);
    void hmirror_marker(map_marker *, int par);
    void rotate_marker(map_marker *, int par);
    void translate_marker(void (map_lines::*xform)(map_marker *, int par),
                          int par = 0);

    void resolve_shuffle(const std::string &shuffle);
    void subst(std::string &s, subst_spec &spec);
    void subst(subst_spec &);
    void nsubst(nsubst_spec &);
    void overlay_colours(colour_spec &);
    void overlay_fprops(fprop_spec &);

    // Merge cell (vx, vy) from vault onto this map's (x, y) cell.
    typedef FixedVector<int, 256> keyspec_map;
    void merge_cell(int x, int y, const map_def &vault, int vx, int vy,
                    int keyspec_idx);

#ifdef USE_TILE
    void overlay_tiles(tile_spec &);
#endif
    void check_borders();
    std::string shuffle(std::string s);
    std::string block_shuffle(const std::string &s);
    std::string check_shuffle(std::string &s);
    std::string check_block_shuffle(const std::string &s);
    std::string clean_shuffle(std::string s);
    std::string parse_nsubst_spec(const std::string &s,
                                  subst_spec &spec);
    int apply_nsubst(std::vector<coord_def> &pos,
                     int start, int nsub,
                     subst_spec &spec);
    std::string parse_glyph_replacements(std::string s,
                                         glyph_replacements_t &gly);

#ifdef USE_TILE
    std::string add_tile(const std::string &sub, bool is_floor, bool is_feat);
#endif

    std::string add_key_field(
        const std::string &s,
        std::string (keyed_mapspec::*set_field)(
            const std::string &s, bool fixed),
        void (keyed_mapspec::*copy_field)(const keyed_mapspec &spec));

    const keyed_mapspec *mapspec_for_key(int key) const;
    keyed_mapspec *mapspec_for_key(int key);

    friend class subst_spec;
    friend class nsubst_spec;
    friend class shuffle_spec;
    friend class map_marker_spec;
    friend class colour_spec;
    friend class tile_spec;

private:
    std::vector<map_marker *> markers;
    std::vector<std::string> lines;

    struct overlay_def
    {
        overlay_def() : colour(0), rocktile(0), floortile(0), tile(0),
                        no_random(false), property(0), keyspec_idx(0) {}
        int colour;
        int rocktile;
        int floortile;
        int tile;
        bool no_random;
        int property;
        int keyspec_idx;
    };
    typedef Matrix<overlay_def> overlay_matrix;
    std::auto_ptr<overlay_matrix> overlay;

    typedef std::map<int, keyed_mapspec> keyed_specs;
    keyed_specs keyspecs;
    int next_keyspec_idx;

    enum
    {
        SUBVAULT_GLYPH = 1
    };

    int map_width;
    bool solid_north, solid_east, solid_south, solid_west;
    bool solid_checked;
};

enum item_spec_type
{
    ISPEC_GOOD    = -2,
    ISPEC_SUPERB  = -3,
    ISPEC_DAMAGED = -4,
    ISPEC_BAD     = -5,
    ISPEC_RANDART = -6,
    ISPEC_ACQUIREMENT = -9
};

struct item_spec
{
    int genweight;

    object_class_type base_type;
    int sub_type;
    int plus, plus2;
    int ego;
    int allow_uniques;
    int level;
    int race;
    int qty;
    int acquirement_source;
    level_id place;

    // Specifically for storing information about randart spell books.
    CrawlHashTable props;

    item_spec() : genweight(10), base_type(OBJ_RANDOM), sub_type(OBJ_RANDOM),
        plus(-1), plus2(-1), ego(0), allow_uniques(1), level(-1),
        race(MAKE_ITEM_RANDOM_RACE), qty(0), acquirement_source(0),
        place(), props()
    {
    }
};
typedef std::vector<item_spec> item_spec_list;

class item_list
{
public:
    item_list() : items() { }

    void clear();

    item_spec get_item(int index);
    size_t size() const { return items.size(); }
    bool empty() const { return items.empty(); }

    std::string add_item(const std::string &spec, bool fix = false);
    std::string set_item(int index, const std::string &spec);

    // Set this list to be a copy of the item_spec_slot in list.
    void set_from_slot(const item_list &list, int slot_index);

private:
    struct item_spec_slot
    {
        item_spec_list ilist;
        bool fix_slot;

        item_spec_slot() : ilist(), fix_slot(false)
        {
        }
    };

private:
    item_spec item_by_specifier(const std::string &spec);
    item_spec_slot parse_item_spec(std::string spec);
    item_spec parse_single_spec(std::string s);
    int parse_acquirement_source(const std::string &source);
    void parse_raw_name(std::string name, item_spec &spec);
    void parse_random_by_class(std::string c, item_spec &spec);
    item_spec pick_item(item_spec_slot &slot);

private:
    std::vector<item_spec_slot> items;
    std::string error;
};

class mons_spec
{
 public:
    int  mid;
    level_id place;
    monster_type monbase;     // Base monster for zombies and dracs.
    mon_attitude_type attitude;
    int  number;              // Head count for hydras, etc.
    int  quantity;            // Number of monsters (usually 1).
    int  genweight, mlevel;
    bool fix_mons;
    bool generate_awake;
    bool patrolling;
    bool band;
    int  colour;
    int  hd;
    int  hp;
    int  abjuration_duration;
    int  summon_type;

    item_list items;
    std::string monname;
    std::string non_actor_summoner;

    bool explicit_spells;
    monster_spells spells;
    unsigned long extra_monster_flags;

    CrawlHashTable props;

    mons_spec(int id = RANDOM_MONSTER,
              monster_type base = MONS_NO_MONSTER,
              int num = 0,
              int gw = 10, int ml = 0,
              bool _fixmons = false, bool awaken = false, bool patrol = false)
        : mid(id), place(), monbase(base), attitude(ATT_HOSTILE), number(num),
          quantity(1), genweight(gw), mlevel(ml), fix_mons(_fixmons),
          generate_awake(awaken), patrolling(false), band(false),
          colour(BLACK), hd(0), hp(0), abjuration_duration(0), summon_type(0),
          items(), monname(""), non_actor_summoner(""), explicit_spells(false), 
          spells(), extra_monster_flags(0L), props()
    {
    }
};

class mons_list
{
public:
    mons_list();

    void clear();

    // Set this list to be a copy of the mons_spec_slot in list.
    void set_from_slot(const mons_list &list, int slot_index);

    mons_spec get_monster(int index);
    mons_spec get_monster(int slot_index, int list_index) const;

    // Returns an error string if the monster is unrecognised.
    std::string add_mons(const std::string &s, bool fix_slot = false);
    std::string set_mons(int slot, const std::string &s);

    size_t size()              const { return mons.size(); }
    size_t slot_size(int slot) const { return mons[slot].mlist.size(); }

private:
    typedef std::vector<mons_spec> mons_spec_list;

    struct mons_spec_slot
    {
        mons_spec_list mlist;
        bool fix_slot;

        mons_spec_slot(const mons_spec_list &list, bool fix = false)
            : mlist(list), fix_slot(fix)
        {
        }

        mons_spec_slot()
            : mlist(), fix_slot(false)
        {
        }
    };

private:
    mons_spec mons_by_name(std::string name) const;
    mons_spec drac_monspec(std::string name) const;
    void get_zombie_type(std::string s, mons_spec &spec) const;
    mons_spec get_hydra_spec(const std::string &name) const;
    mons_spec get_slime_spec(const std::string &name) const;
    mons_spec get_zombified_monster(const std::string &name,
                                    monster_type zomb) const;
    mons_spec_slot parse_mons_spec(std::string spec);
    void parse_mons_spells(mons_spec &slot, const std::string &spells);
    mons_spec pick_monster(mons_spec_slot &slot);
    int fix_demon(int id) const;
    bool check_mimic(const std::string &s, int *mid, bool *fix) const;

private:
    std::vector< mons_spec_slot > mons;
    std::string error;
};

struct feature_spec
{
    int genweight;
    int feat;
    int shop;
    int trap;
    int glyph;

    feature_spec(int f, int wt = 10)
        : genweight(wt), feat(f), shop(-1),
          trap(-1), glyph(-1)
    { }
    feature_spec() : genweight(0), feat(0), shop(-1), trap(-1), glyph(-1) { }
};

typedef std::vector<feature_spec> feature_spec_list;
struct feature_slot
{
    feature_spec_list feats;
    bool fix_slot;

    feature_slot();
    feature_spec get_feat(int default_glyph);
};

struct map_flags
{
    unsigned long flags_set, flags_unset;

    map_flags();
    void clear();

    static map_flags parse(const std::string flag_list[],
                           const std::string &s) throw(std::string);
};


struct keyed_mapspec
{
public:
    int          key_glyph;

    feature_slot feat;
    item_list    item;
    mons_list    mons;
    map_flags    map_mask;

public:
    keyed_mapspec();

    // Parse the string and set the given entry.  If fix is true,
    // then whatever is selected for the first feature will be
    // permanently fixed.
    std::string set_feat(const std::string &s, bool fix);
    std::string set_mons(const std::string &s, bool fix);
    std::string set_item(const std::string &s, bool fix);
    std::string set_mask(const std::string &s, bool garbage);

    // Copy from the given mapspec.  If that entry is fixed,
    // it should be pre-selected prior to the copy.
    void copy_feat(const keyed_mapspec &spec);
    void copy_mons(const keyed_mapspec &spec);
    void copy_item(const keyed_mapspec &spec);
    void copy_mask(const keyed_mapspec &spec);

    feature_spec get_feat();
    mons_list   &get_monsters();
    item_list   &get_items();
    map_flags   &get_mask();

private:
    std::string err;

private:
    void parse_features(const std::string &);
    feature_spec_list parse_feature(const std::string &s);
    feature_spec parse_shop(std::string s, int weight);
    feature_spec parse_trap(std::string s, int weight);
};

typedef std::vector<level_range> depth_ranges;

class map_def;
struct dlua_set_map
{
    dlua_set_map(map_def *map);
    ~dlua_set_map();
};

class map_def;
dungeon_feature_type map_feature_at(map_def *map, const coord_def &c, int rawfeat);

struct map_file_place
{
    std::string filename;
    int lineno;

    map_file_place(const std::string &s = "", int line = 0)
        : filename(s), lineno(line)
    {
    }

    void clear()
    {
        filename.clear();
        lineno = 0;
    }
};

/////////////////////////////////////////////////////////////////////////////
// map_def: map definitions for maps loaded from .des files.
//
// Please read this before changing map_def.
//
// When adding Lua-visible fields to map_def, note that there are two
// kinds of fields:
//
// * Fields that determine placement of the map, or are unchanging,
//   such as "place", "depths" (determine placement), or "name" (does
//   not change between different evaluations of the map). Such fields
//   must be reset to their default values in map_def::init() if they
//   determine placement, or just initialised in the constructor if
//   they will not change.
//
// * Fields that do not determine placement and may change between
//   different uses of the map (such as "mons", "items",
//   "level_flags", etc.). Such fields must be reset to their default
//   values in map_def::reinit(), which is called before the map is
//   used.
//
// If you do not do this, maps will not work correctly, and will break
// in obscure, hard-to-find ways. The level-compiler will not (cannot)
// warn you.
//
class map_def
{
public:
    std::string     name;
    std::string     tags;
    level_id        place;

    depth_ranges     depths;
    map_section_type orient;

    int              chance_priority;
    int              chance;
    int              weight;
    int              weight_depth_mult;
    int              weight_depth_div;

    std::vector<std::string> welcome_messages;

    map_lines       map;
    mons_list       mons;
    item_list       items;

    static bool valid_item_array_glyph(int gly);
    static int item_array_glyph_to_slot(int gly);
    static bool valid_monster_array_glyph(int gly);
    static bool valid_monster_glyph(int gly);
    static int monster_array_glyph_to_slot(int gly);

    std::vector<mons_spec> random_mons;

    map_flags       level_flags, branch_flags;

    dlua_chunk      prelude, mapchunk, main, validate, veto;

    map_file_place  place_loaded_from;

    map_def         *original;

    unsigned char   rock_colour, floor_colour;
    int             rock_tile, floor_tile;

    dungeon_feature_type border_fill_type;
private:
    // This map has been loaded from an index, and not fully realised.
    bool            index_only;
    long            cache_offset;
    std::string     file;

    typedef Matrix<bool> subvault_mask;
    subvault_mask *svmask;

    // True if this map is in the process of being validated.
    bool validating_map_flag;

public:
    map_def();
    void init();
    void reinit();

    void load();

    bool in_map(const coord_def &p) const;

    coord_def size() const { return coord_def(map.width(), map.height()); }

    std::vector<coord_def> find_glyph(int glyph) const;
    coord_def find_first_glyph(int glyph) const;
    coord_def find_first_glyph(const std::string &glyphs) const;

    void write_index(writer&) const;
    void write_full(writer&);

    void read_index(reader&);
    void read_full(reader&);

    void set_file(const std::string &s);
    std::string run_lua(bool skip_main);

    // Returns true if the validation passed.
    bool test_lua_validate(bool croak = false);

    // Returns true if *not* vetoed, i.e., the map is good to go.
    bool test_lua_veto();

    std::string validate_map_def();
    std::string validate_temple_map();
    // Returns true if this map is in the middle of validation.
    bool is_validating() const { return (validating_map_flag); }

    void add_prelude_line(int line,  const std::string &s);
    void add_main_line(int line, const std::string &s);

    void hmirror();
    void vmirror();
    void rotate(bool clockwise);
    void normalise();
    std::string resolve();
    void fixup();

    bool is_usable_in(const level_id &lid) const;

    const keyed_mapspec *mapspec_at(const coord_def &c) const;
    keyed_mapspec *mapspec_at(const coord_def &c);

    bool has_depth() const;
    void add_depth(const level_range &depth);
    void add_depths(depth_ranges::const_iterator s,
                    depth_ranges::const_iterator e);

    bool can_dock(map_section_type) const;
    coord_def dock_pos(map_section_type) const;
    coord_def float_dock();
    coord_def float_place();
    coord_def float_aligned_place() const;
    coord_def float_random_place() const;

    std::vector<coord_def> anchor_points() const;

    bool is_minivault() const;
    bool has_tag(const std::string &tag) const;
    bool has_tag_prefix(const std::string &tag) const;
    bool has_tag_suffix(const std::string &suffix) const;
    std::vector<std::string> get_tags() const;

    std::vector<std::string> get_shuffle_strings() const;
    std::vector<std::string> get_subst_strings() const;

    int glyph_at(const coord_def &c) const;

    // Subvault functions.
    std::string subvault_from_tagstring(const std::string &s);
    bool is_subvault() const;
    void apply_subvault_mask();
    bool subvault_cell_valid(const coord_def &c) const;
    int subvault_width() const;
    int subvault_height() const;
    // Returns the number of cells in the subvault map that
    // will not get copied to parent vault at a given placement.
    int subvault_mismatch_count(const coord_def &place) const;

public:
    struct map_feature_finder
    {
        map_def &map;
        map_feature_finder(map_def &map_) : map(map_) { }
        // This may actually modify the underlying map by fixing KFEAT:
        // feature slots, but that's fine by us.
        dungeon_feature_type operator () (const coord_def &c) const
        {
            return (map_feature_at(&map, c, -1));
        }
    };

    struct map_bounds_check
    {
        map_def &map;
        map_bounds_check(map_def &map_) : map(map_) { }
        bool operator () (const coord_def &c) const
        {
            return (c.x >= 0 && c.x < map.map.width()
                    && c.y >= 0 && c.y < map.map.height());
        }
    };

private:

    void write_depth_ranges(writer&) const;
    void read_depth_ranges(reader&);
    bool test_lua_boolchunk(dlua_chunk &, bool def = false, bool croak = false);
    std::string rewrite_chunk_errors(const std::string &s) const;
    std::string apply_subvault(string_spec &);
};

const int CHANCE_ROLL = 10000;

std::string escape_string(std::string in, const std::string &toesc,
                          const std::string &escapewith);

std::string mapdef_split_key_item(const std::string &s,
                                  std::string *key,
                                  int *separator,
                                  std::string *arg,
                                  int key_max_len = 1);

const char *map_section_name(int msect);

#endif