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