1 /** 2 * @file 3 * @brief Procedurally generated dungeon layouts. 4 **/ 5 6 #pragma once 7 8 #include <vector> 9 10 #include "dungeon.h" 11 #include "enum.h" 12 #include "fixedvector.h" 13 #include "worley.h" 14 15 using std::vector; 16 17 dungeon_feature_type sanitize_feature(dungeon_feature_type feature, 18 bool strict = false); 19 20 class ProceduralSample 21 { 22 public: 23 ProceduralSample(const coord_def _c, const dungeon_feature_type _ft, 24 const uint32_t _cp, map_mask_type _m = MMT_NONE) c(_c)25 : c(_c), ft(_ft), cp(_cp), m(_m) 26 { 27 ASSERT_RANGE(ft, DNGN_UNSEEN + 1, NUM_FEATURES); 28 } coord()29 coord_def coord() const { return c; } feat()30 dungeon_feature_type feat() const { return ft; } changepoint()31 uint32_t changepoint() const { return cp; } mask()32 map_mask_type mask() const { return m; } 33 private: 34 coord_def c; 35 dungeon_feature_type ft; 36 // A lower bound estimate of when this feat can change in terms of 37 // absolute abyss depth. If you say that a feature might change by 38 // depth 1000, it will get checked at depth 1000. Then it will get 39 // pushed back into the terrain queue with the new depth estimate. 40 // If you overestimate the time between shifts, this will introduce 41 // bad behaviour when a game is loaded. [bh] 42 uint32_t cp; 43 map_mask_type m; 44 }; 45 46 class ProceduralSamplePQCompare 47 { 48 public: operator()49 bool operator() (const ProceduralSample &lhs, 50 const ProceduralSample &rhs) 51 { 52 return lhs.changepoint() > rhs.changepoint(); 53 } 54 }; 55 56 class ProceduralLayout 57 { 58 public: 59 virtual ProceduralSample operator()(const coord_def &p, 60 const uint32_t offset = 0) const = 0; ~ProceduralLayout()61 virtual ~ProceduralLayout() { } 62 }; 63 64 // Geometric layout that generates columns with width cw, col spacing cs, row width rw, and row spacing rs. 65 // cw is the only required parameter and will generate uniform columns. 66 class ColumnLayout : public ProceduralLayout 67 { 68 public: 69 ColumnLayout(int cw, int cs = -1, int rw = -1, int rs = -1) 70 { 71 cs = (cs < 0 ? cw : cs); 72 _col_width = cw; 73 _col_space = cs; 74 _row_width = (rw < 0 ? cw : rw); 75 _row_space = (rs < 0 ? cs : rs); 76 } 77 78 ProceduralSample operator()(const coord_def &p, 79 const uint32_t offset = 0) const override; 80 private: 81 int _col_width, _col_space, _row_width, _row_space; 82 }; 83 84 class DiamondLayout : public ProceduralLayout 85 { 86 public: DiamondLayout(int _w,int _s)87 DiamondLayout(int _w, int _s) : w(_w) , s(_s) { } 88 ProceduralSample operator()(const coord_def &p, 89 const uint32_t offset = 0) const override; 90 private: 91 uint32_t w, s; 92 }; 93 94 // A worley noise layout that selects between other layouts. 95 class WorleyLayout : public ProceduralLayout 96 { 97 public: 98 WorleyLayout(uint32_t _seed, 99 vector<const ProceduralLayout*> _layouts, 100 const float _scale = 2.0) : seed(_seed)101 seed(_seed), layouts(_layouts), scale(_scale) {} 102 ProceduralSample operator()(const coord_def &p, 103 const uint32_t offset = 0) const override; 104 private: 105 const uint32_t seed; 106 const vector<const ProceduralLayout*> layouts; 107 const float scale; 108 }; 109 110 // A pseudo-random layout with variable density. 111 // By default, 45% of the area is wall. Densities in excess of 50% (500) 112 // are very likely to create isolated bubbles. 113 // See http://en.wikipedia.org/wiki/Percolation_theory for additional 114 // information. 115 // This layout is depth invariant. 116 class ChaosLayout : public ProceduralLayout 117 { 118 public: 119 ChaosLayout(uint32_t _seed, uint32_t _density = 450) : seed(_seed)120 seed(_seed), baseDensity(_density) {} 121 ProceduralSample operator()(const coord_def &p, 122 const uint32_t offset = 0) const override; 123 private: 124 const uint32_t seed; 125 const uint32_t baseDensity; 126 }; 127 128 // Similar to ChaosLayout, but changes relatively quickly with depth. 129 class RoilingChaosLayout : public ProceduralLayout 130 { 131 public: 132 RoilingChaosLayout(uint32_t _seed, uint32_t _density = 450) : seed(_seed)133 seed(_seed), density(_density) {} 134 ProceduralSample operator()(const coord_def &p, 135 const uint32_t offset = 0) const override; 136 private: 137 const uint32_t seed; 138 const uint32_t density; 139 }; 140 141 // A mostly empty layout. 142 class WastesLayout : public ProceduralLayout 143 { 144 public: WastesLayout()145 WastesLayout() { }; 146 ProceduralSample operator()(const coord_def &p, 147 const uint32_t offset = 0) const override; 148 }; 149 150 class RiverLayout : public ProceduralLayout 151 { 152 public: RiverLayout(uint32_t _seed,const ProceduralLayout & _layout)153 RiverLayout(uint32_t _seed, const ProceduralLayout &_layout) : 154 seed(_seed), layout(_layout) {} 155 ProceduralSample operator()(const coord_def &p, 156 const uint32_t offset = 0) const override; 157 private: 158 const uint32_t seed; 159 const ProceduralLayout &layout; 160 }; 161 162 // A reimagining of the beloved newabyss layout. 163 class NewAbyssLayout : public ProceduralLayout 164 { 165 public: NewAbyssLayout(uint32_t _seed)166 NewAbyssLayout(uint32_t _seed) : seed(_seed) {} 167 ProceduralSample operator()(const coord_def &p, 168 const uint32_t offset = 0) const override; 169 private: 170 const uint32_t seed; 171 }; 172 173 // This layout takes chunks of a single level the player has seen, corrupts them 174 // and uses them to build the level. 175 class LevelLayout : public ProceduralLayout 176 { 177 public: 178 LevelLayout(level_id id, uint32_t _seed, 179 const ProceduralLayout &_layout); 180 ProceduralSample operator()(const coord_def &p, 181 const uint32_t offset = 0) const override; 182 private: 183 feature_grid grid; 184 uint32_t seed; 185 const ProceduralLayout &layout; 186 }; 187 188 // Clamps another layout so that it changes no more frequently than specified 189 // by the clamp parameter. This is useful if you can't find a good analytic 190 // bound on how rapidly your layout changes. If you provide a high valued clamp 191 // to a fast changing layout, aliasing will occur. 192 // If bursty is true, changes will be not be distributed uniformly over the 193 // clamp period. 194 class ClampLayout : public ProceduralLayout 195 { 196 public: ClampLayout(const ProceduralLayout & _layout,int _clamp,bool _bursty)197 ClampLayout(const ProceduralLayout &_layout, int _clamp, bool _bursty) : 198 layout(_layout), clamp(_clamp), bursty(_bursty) {} 199 ProceduralSample operator()(const coord_def &p, 200 const uint32_t offset = 0) const override; 201 private: 202 const ProceduralLayout &layout; 203 const int clamp; 204 const bool bursty; 205 }; 206 207 // Base class is only needed for a couple of support functions 208 // TODO: Refactor those functions into ProceduralFunctions 209 210 class NoiseLayout : public ProceduralLayout 211 { 212 public: NoiseLayout()213 NoiseLayout() { }; 214 ProceduralSample operator()(const coord_def &p, const uint32_t offset = 0) const override; 215 216 protected: 217 double _optimum_range(const double val, const double rstart, const double rend) const; 218 double _optimum_range_mid(const double val, const double rstart, const double rmax1, const double rmax2, const double rend) const; 219 }; 220 221 class ForestLayout : public NoiseLayout 222 { 223 public: ForestLayout()224 ForestLayout() { }; 225 ProceduralSample operator()(const coord_def &p, const uint32_t offset = 0) const override; 226 }; 227 228 class UnderworldLayout : public NoiseLayout 229 { 230 public: UnderworldLayout()231 UnderworldLayout() { }; 232 ProceduralSample operator()(const coord_def &p, const uint32_t offset = 0) const override; 233 }; 234 235 // ProceduralFunctions abstract a noise calculation for x,y,z coordinates (which could 236 // include distortion by domain transformation) 237 238 class ProceduralFunction 239 { 240 public: 241 // Not virtual! 242 double operator()(const coord_def &p, const uint32_t offset) const; 243 double operator()(double x, double y, double z) const; 244 }; 245 246 class SimplexFunction : public ProceduralFunction 247 { 248 public: 249 SimplexFunction(double _scale_x, double _scale_y, double _scale_z, 250 double _seed_x, double _seed_y, double _seed_z = 0, 251 int _octaves = 1) scale_x(_scale_x)252 : scale_x(_scale_x), scale_y(_scale_y), scale_z(_scale_z), 253 seed_x(_seed_x), seed_y(_seed_y), seed_z(_seed_z), 254 octaves(_octaves) { }; 255 256 double operator()(const coord_def &p, const uint32_t offset) const; 257 double operator()(double x, double y, double z) const; 258 259 private: 260 const double scale_x; 261 const double scale_y; 262 const double scale_z; 263 const double seed_x; 264 const double seed_y; 265 const double seed_z; 266 const int octaves; 267 }; 268 269 class WorleyFunction : public ProceduralFunction 270 { 271 public: 272 WorleyFunction(double _scale_x, double _scale_y, double _scale_z, 273 double _seed_x, double _seed_y, double _seed_z = 0) scale_x(_scale_x)274 : scale_x(_scale_x), scale_y(_scale_y), scale_z(_scale_z), 275 seed_x(_seed_x), seed_y(_seed_y), seed_z(_seed_z) { }; 276 double operator()(const coord_def &p, const uint32_t offset) const; 277 double operator()(double x, double y, double z) const; 278 worley::noise_datum datum(double x, double y, double z) const; 279 280 private: 281 const double scale_x; 282 const double scale_y; 283 const double scale_z; 284 const double seed_x; 285 const double seed_y; 286 const double seed_z; 287 }; 288 289 class DistortFunction : public ProceduralFunction 290 { 291 public: DistortFunction(const ProceduralFunction & _base,const ProceduralFunction & _offx,double _scalex,const ProceduralFunction & _offy,double _scaley)292 DistortFunction(const ProceduralFunction &_base, 293 const ProceduralFunction &_offx, double _scalex, 294 const ProceduralFunction &_offy, double _scaley) 295 : base(_base), off_x(_offx), scale_x(_scalex), 296 off_y(_offy), scale_y(_scaley) { }; 297 double operator()(double x, double y, double z) const; 298 299 protected: 300 const ProceduralFunction &base; 301 const ProceduralFunction &off_x; 302 const double scale_x; 303 const ProceduralFunction &off_y; 304 const double scale_y; 305 }; 306 307 class WorleyDistortFunction : public DistortFunction 308 { 309 public: WorleyDistortFunction(const WorleyFunction & _base,const ProceduralFunction & _offx,double _scalex,const ProceduralFunction & _offy,double _scaley)310 WorleyDistortFunction(const WorleyFunction &_base, 311 const ProceduralFunction &_offx, double _scalex, 312 const ProceduralFunction &_offy, double _scaley) 313 : DistortFunction(_base,_offx,_scalex,_offy,_scaley), wbase(_base) { }; 314 worley::noise_datum datum(double x, double y, double z) const; 315 316 private: 317 const WorleyFunction &wbase; 318 }; 319