diff options
author | Pete Hurst <pete@streamuniverse.tv> | 2013-03-05 06:18:37 +0000 |
---|---|---|
committer | Pete Hurst <pete@streamuniverse.tv> | 2013-04-09 12:24:49 +0100 |
commit | 751b1299bb99bf548adb384fb3791bbe82a0afd9 (patch) | |
tree | 0ebf069135031f87d5e081534ec3efe5b92705da /crawl-ref/source/dgn-proclayouts.cc | |
parent | 7872dfe2f1dbb0966d738d918151614cfc2e8074 (diff) | |
download | crawl-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.cc | 294 |
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 |