summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/dgn-proclayouts.cc
diff options
context:
space:
mode:
authorPete Hurst <pete@streamuniverse.tv>2013-03-05 06:18:37 +0000
committerPete Hurst <pete@streamuniverse.tv>2013-04-09 12:24:49 +0100
commit751b1299bb99bf548adb384fb3791bbe82a0afd9 (patch)
tree0ebf069135031f87d5e081534ec3efe5b92705da /crawl-ref/source/dgn-proclayouts.cc
parent7872dfe2f1dbb0966d738d918151614cfc2e8074 (diff)
downloadcrawl-ref-751b1299bb99bf548adb384fb3791bbe82a0afd9.tar.gz
crawl-ref-751b1299bb99bf548adb384fb3791bbe82a0afd9.zip
Large abyssal terrain layout
Diffstat (limited to 'crawl-ref/source/dgn-proclayouts.cc')
-rw-r--r--crawl-ref/source/dgn-proclayouts.cc294
1 files changed, 294 insertions, 0 deletions
diff --git a/crawl-ref/source/dgn-proclayouts.cc b/crawl-ref/source/dgn-proclayouts.cc
index c291c21a93..d354e3a4c2 100644
--- a/crawl-ref/source/dgn-proclayouts.cc
+++ b/crawl-ref/source/dgn-proclayouts.cc
@@ -305,3 +305,297 @@ CityLayout::operator()(const coord_def &p, const uint32_t offset) const
return ProceduralSample(p, DNGN_FLOOR, offset + 4096);
}
+
+ProceduralSample
+PlainsLayout::operator()(const coord_def &p, const uint32_t offset) const
+{
+ // Wetness gives us features like water, and optimal wetness is required for plants.
+ double wet_xoff = 3463.128;
+ double wet_yoff = -3737.987;
+ double wet_xmul = 0.5;
+ double wet_ymul = 0.5;
+ double wet_dmul = 3;
+ double wet_doff = 0;
+ double wet_oct = 2;
+
+ // Height
+ double height_xoff = 7.543;
+ double height_yoff = 2.123;
+ double height_xmul = 0.3; // 0.2; // Setting muls to 10 produces very dense terrain variation and looks cool
+ double height_ymul = 0.3;// 0.2;
+ double height_dmul = 1;
+ double height_doff = 0;
+ double height_oct = 4; // 4;
+
+ // Temperament. Plants struggle to grow in extreme temperatures, and we only see lava in hot places.
+ double hot_xoff = 111.612;
+ double hot_yoff = 11.243;
+ double hot_xmul = 0.1;
+ double hot_ymul = 0.1;
+ double hot_dmul = 2;
+ double hot_doff = 0;
+ double hot_oct = 1;
+
+ // Citification; areas with a high settle factor will tend to feature "man"-made architecture
+ double city_xoff = 2.732;
+ double city_yoff = 22.43;
+ double city_xmul = 0.2; // 0.4 , 0.4
+ double city_ymul = 0.2;
+ double city_dmul = 1;
+ double city_doff = 0;
+ double city_oct = 1;
+
+ // Gentrification; some cities are richer than others, for now this will just affect wall types
+ // but it could be interesting to make architecture more complex and regular in rich areas too,
+ // as well as influencing features like statues, fountains, plants, even monsters/loot
+ double rich_xoff = 9.543;
+ double rich_yoff = 5.543;
+ double rich_xmul = 0.05;
+ double rich_ymul = 0.05;
+ double rich_dmul = 1;
+ double rich_doff = 0;
+ double rich_oct = 1;
+
+ // to create lots of lines everywhere that can often be perpendicular to other features; for creating bridges, dividing walls
+ double lateral_xoff = 2000.543;
+ double lateral_yoff = 1414.823;
+ double lateral_xmul = 4;
+ double lateral_ymul = 4;
+ double lateral_dmul = 1;
+ double lateral_doff = 0;
+ double lateral_oct = 2;
+
+ // jitter needs to be completely random everywhere, so this can be used instead of normal random methods:
+ // if (jitter < (chance_in_1)) { ... }
+ double jitter_xoff = 1123.543;
+ double jitter_yoff = 2451.143;
+ double jitter_xmul = 10;
+ double jitter_ymul = 10;
+ double jitter_dmul = 0.5;
+ double jitter_doff = 0;
+ double jitter_oct = 5;
+
+ // Based on the various perlin layers, determine environmental parameters at the current spot
+ // printf ("Abyss: %d %d", p.x, p.y);
+ double wet = _perlin(p, offset, wet_xmul, wet_xoff, wet_ymul, wet_yoff, wet_dmul, wet_doff, wet_oct);
+ double height = _perlin(p, offset, height_xmul, height_xoff, height_ymul, height_yoff, height_dmul, height_doff, height_oct);
+
+ // Note: worley noise with x,y multiplied by something below 10 (maybe about 8) produces similar density to Perlin.
+ /*
+ worley::noise_datum n = worley::noise(hx, hy, hz);
+ double height = n.distance[0] - 1.0;
+ double other = n.distance[1] - 1.0;
+ */
+ //printf ("X: %d, Y: %d, HX: %f, HY: %f, HZ: %f, Height: %f, Other: %f\n", p.x, p.y, hx, hy, hz, height, other);
+ double hot = _perlin(p, offset, hot_xmul, hot_xoff, hot_ymul, hot_yoff, hot_dmul, hot_doff, hot_oct);
+ double city = _perlin(p, offset, city_xmul, city_xoff, city_ymul, city_yoff, city_dmul, city_doff, city_oct);
+ double rich = _perlin(p, offset, rich_xmul, rich_xoff, rich_ymul, rich_yoff, rich_dmul, rich_doff, rich_oct);
+ double lateral = _perlin(p, offset, lateral_xmul, lateral_xoff, lateral_ymul, lateral_yoff, lateral_dmul, lateral_doff, lateral_oct);
+ double jitter = _perlin(p, offset, jitter_xmul, jitter_xoff, jitter_ymul, jitter_yoff, jitter_dmul, jitter_doff, jitter_oct);
+
+ // TODO: The abyss doesn't support all of these yet but would be nice if:
+ // * Clusters of plants around water edge
+ // * Hot and wet areas are "tropical" with plants/trees/mangroves (and steam)
+ // * Extremely hot or cold areas should generate fire or ice clouds respectively. If an "ice" feature were ever created this would be a good place for it.
+ // * Wet cities have flooding, pools, fountains, aqueducts
+ // * City + water areas have lateral bridges
+ // * Pave areas within city
+ // * Borrow some easing functions from somewhere to better control how features vary across bounaries
+ // * Look at surrounding squares to determine gradients - will help with lateral features and also e.g. growing plants on sunlit mountainsides...
+
+ // TODO: Rather than basing all the factors purely on the perlin layers, we should combine some factors; e.g. cities thrive best at optimal combinations
+ // of wet, height and hot, so the city factor could be based on how close to optimum those three are...
+
+ // Factors controlling how the environment is mapped to terrain
+ /*
+ double dryness = ((1.0-wet)*0.5+0.5);
+ double water_depth = -0.8 * dryness;
+ double water_deep_depth = -0.9 * dryness;
+ */
+ double water_depth = 0.2 * wet; // 0.4,0.2
+ double water_deep_depth = 0.07 * wet;
+ // Good values for mountains: 0.75/0.95
+ double mountain_height = 0.8;
+ double mountain_top_height = 0.95;
+ // Default feature
+ dungeon_feature_type feat = DNGN_FLOOR;
+ // printf ("Height: %f, Wet: %f", height,wet);
+
+ // Lakes and rivers
+ /* height with a mul of 10 looked really nice with:
+ if (height<0.5)
+ feat = DNGN_SHALLOW_WATER;
+ if (height<0.3)
+ feat = DNGN_DEEP_WATER;
+ if (height>0.8)
+ feat = DNGN_ROCK_WALL; */
+ if (height < water_depth)
+ feat = DNGN_SHALLOW_WATER;
+ if (height < water_deep_depth)
+ feat = DNGN_DEEP_WATER;
+
+ if (height > mountain_height)
+ {
+ double dist_to_top = (height - mountain_height) / (mountain_top_height - mountain_height);
+ if (height > mountain_top_height
+ || lateral < dist_to_top)
+ {
+ if (hot > 0.7 && (dist_to_top>=1.0 || lateral/dist_to_top < 0.2))
+ feat = DNGN_LAVA;
+ else
+ feat = DNGN_ROCK_WALL;
+ }
+ }
+ /*
+ if (wet > 0.9)
+ {
+ feat = DNGN_DEEP_WATER;
+ if (hot > 0.7)
+ feat = DNGN_LAVA;
+ }
+ else if (wet > 0.88)
+ {
+ feat = DNGN_SHALLOW_WATER;
+ if (hot > 0.7)
+ feat = DNGN_DEEP_WATER;
+ }
+ */
+
+ // Forest
+ bool enable_forest = true;
+ // Forests fill an important gap in the middling height gap between water and mountainous regions
+ double forest_start_height = 0.4; // 0.3,0.7
+ double forest_end_height = 0.6;
+
+ if (enable_forest)
+ {
+ // A narrow river running through the middle of forresty heights at good wetness levels
+ // TODO: Use some lateral wetness to try and join mountain streams up to rivers...
+ bool is_river = (abs(height-0.5) < (wet/10.0));
+ if (is_river)
+ feat = DNGN_SHALLOW_WATER;
+ // if ( 0.4 < height < 0.6 && wet > 0.5)
+ /*
+ double forest = (height - forest_start_height) / (forest_end_height - forest_start_height);
+ forest = max(0.0,min(1.0,forest));
+ forest = 1.0 - 2.0 * abs(forest - 0.5);
+ */
+ // Forests are somewhat finnicky about their conditions now
+ double forest =
+ _optimum_range(height, forest_start_height, forest_end_height)
+ * _optimum_range(wet, 0.5, 0.8)
+ * _optimum_range(hot, 0.4, 0.6);
+
+ // TODO: Petrified trees and other fun stuff in extreme temperatures
+
+ // Forest should now be 1.0 in the center of the range, 0.0 at the end
+ if (jitter < (forest * 0.7))
+ {
+ if (is_river && jitter < forest / 2.0)
+ {
+ if (forest > 0.5 && wet > 0.5)
+ feat = DNGN_MANGROVE;
+ }
+ else
+ feat = DNGN_TREE;
+ }
+ }
+
+ // City
+ double city_outer_limit = 0.4;
+ double city_wall_limit = 0.65; // 0.6
+ double city_wall_width = 0.05;
+ double city_inner_wall_limit = 0.8; // 0.8
+ bool enable_city = true;
+
+ // Cities become less likely at extreme heights and depths
+ // double extreme_proximity = max(0.0,abs(height-0.5)-0.25) * 4.0;
+ double extreme_proximity = max(0.0,abs(height-0.5)-0.3) * 5.0;
+ city = city * (1.0 - extreme_proximity);
+
+ if (enable_city && city >= city_outer_limit) {
+ // feat = DNGN_FLOOR;
+
+ dungeon_feature_type city_wall = DNGN_ROCK_WALL;
+ if (rich > 0.5) city_wall = DNGN_STONE_WALL;
+ else if (rich > 0.75) city_wall = DNGN_METAL_WALL;
+ else if (rich > 0.9) city_wall = DNGN_GREEN_CRYSTAL_WALL;
+
+ // Doors and windows
+ if (jitter>0.5 && jitter<0.6) city_wall = DNGN_CLOSED_DOOR;
+ if (jitter>0.7 && jitter<0.75) city_wall = DNGN_CLEAR_STONE_WALL;
+
+ // Outer cloisters
+ /*
+ if (city < city_wall_limit) {
+ if ((lateral >= 0.3 && lateral < 0.4 || lateral >= 0.6 && lateral < 0.7)
+ || (lateral >= 0.4 && lateral < 0.6 && city < (city_outer_limit+city_wall_width)))
+ feat = city_wall;
+ else if (lateral >= 0.4 && lateral < 0.6)
+ feat = DNGN_FLOOR;
+ }*/
+ // Main outer wall
+ if (city >= city_wall_limit)
+ {
+ // Within outer wall reset all terrain to floor.
+ // TODO: We might sometimes want to modify the terrain based on what was here before the city.
+ // e.g. if the city was built on water then there should be fountains, with lava we get furnaces, etc.
+ feat = DNGN_FLOOR;
+
+ if (city < (city_wall_limit + city_wall_width))
+ feat = city_wall;
+ /*
+ else if (city <= 0.7) {
+ if (lateral > 0.0 && lateral < 0.1 || lateral > 0.5 || lateral < 0.6)
+ feat = city_wall;
+ }*/
+ // Wall of inner halls
+ else if (city >= city_inner_wall_limit)
+ {
+ if (city < (city_inner_wall_limit + city_wall_width))
+ feat = city_wall;
+ // Decide on what decor we want within the inner walls
+ // TODO: Make the decor more interesting, and choose fountain types based on wetness
+ else if (jitter > 0.9)
+ {
+ if (rich>0.8)
+ feat = DNGN_FOUNTAIN_BLUE;
+ else if (rich>0.5)
+ feat = DNGN_GRANITE_STATUE;
+ else if (rich>0.2)
+ feat = DNGN_GRATE;
+ else
+ feat = DNGN_STONE_ARCH;
+ }
+
+ // TOOD: Pave coords within wall limit
+ }
+ }
+ }
+
+ int delta = 100;
+
+ return ProceduralSample(p, feat, offset + delta);
+}
+
+double PlainsLayout::_perlin(const coord_def &p, const uint32_t offset, const double xmul, const double xoff, const double ymul,const double yoff, const double zmul,const double zoff, const int oct) const
+{
+ double hx = ((double)p.x / (double)10 + xoff) * xmul;
+ double hy = ((double)p.y / (double)10 + yoff) * ymul;
+ double hz = ((double)offset / (double)10000 + zoff) * zmul;
+ return perlin::fBM(hx, hy, hz, oct) / 2.0 + 0.5;
+}
+
+double PlainsLayout::_optimum_range(const double val, const double rstart, const double rend) const
+{
+ double mid = (rstart + rend) / 2.0;
+ return _optimum_range_mid(val, rstart, mid, mid, rend);
+}
+double PlainsLayout::_optimum_range_mid(const double val, const double rstart, const double rmax1, const double rmax2, const double rend) const
+{
+ if (rmax1 <= val <= rmax2) return 1.0;
+ if (val <= rstart || val >= rend) return 0.0;
+ if (val < rmax1)
+ return (val - rstart) / (rmax1-rstart);
+ return 1.0 - (val - rmax2)/(rend - rmax2);
+} \ No newline at end of file