]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapgen/mapgen_valleys.cpp
Add 'ores' global mapgen flag (#10276)
[dragonfireclient.git] / src / mapgen / mapgen_valleys.cpp
1 /*
2 Minetest
3 Copyright (C) 2016-2019 Duane Robertson <duane@duanerobertson.com>
4 Copyright (C) 2016-2019 paramat
5
6 Based on Valleys Mapgen by Gael de Sailly
7 (https://forum.minetest.net/viewtopic.php?f=9&t=11430)
8 and mapgen_v7, mapgen_flat by kwolekr and paramat.
9
10 Licensing changed by permission of Gael de Sailly.
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU Lesser General Public License as published by
14 the Free Software Foundation; either version 2.1 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 GNU Lesser General Public License for more details.
21
22 You should have received a copy of the GNU Lesser General Public License along
23 with this program; if not, write to the Free Software Foundation, Inc.,
24 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
27
28 #include "mapgen.h"
29 #include "voxel.h"
30 #include "noise.h"
31 #include "mapblock.h"
32 #include "mapnode.h"
33 #include "map.h"
34 #include "nodedef.h"
35 #include "voxelalgorithms.h"
36 //#include "profiler.h" // For TimeTaker
37 #include "settings.h" // For g_settings
38 #include "emerge.h"
39 #include "dungeongen.h"
40 #include "mg_biome.h"
41 #include "mg_ore.h"
42 #include "mg_decoration.h"
43 #include "mapgen_valleys.h"
44 #include "cavegen.h"
45 #include <cmath>
46
47
48 FlagDesc flagdesc_mapgen_valleys[] = {
49         {"altitude_chill",   MGVALLEYS_ALT_CHILL},
50         {"humid_rivers",     MGVALLEYS_HUMID_RIVERS},
51         {"vary_river_depth", MGVALLEYS_VARY_RIVER_DEPTH},
52         {"altitude_dry",     MGVALLEYS_ALT_DRY},
53         {NULL,               0}
54 };
55
56
57 MapgenValleys::MapgenValleys(MapgenValleysParams *params, EmergeParams *emerge)
58         : MapgenBasic(MAPGEN_VALLEYS, params, emerge)
59 {
60         // NOTE: MapgenValleys has a hard dependency on BiomeGenOriginal
61         m_bgen = (BiomeGenOriginal *)biomegen;
62
63         spflags            = params->spflags;
64         altitude_chill     = params->altitude_chill;
65         river_depth_bed    = params->river_depth + 1.0f;
66         river_size_factor  = params->river_size / 100.0f;
67
68         cave_width         = params->cave_width;
69         large_cave_depth   = params->large_cave_depth;
70         small_cave_num_min = params->small_cave_num_min;
71         small_cave_num_max = params->small_cave_num_max;
72         large_cave_num_min = params->large_cave_num_min;
73         large_cave_num_max = params->large_cave_num_max;
74         large_cave_flooded = params->large_cave_flooded;
75         cavern_limit       = params->cavern_limit;
76         cavern_taper       = params->cavern_taper;
77         cavern_threshold   = params->cavern_threshold;
78         dungeon_ymin       = params->dungeon_ymin;
79         dungeon_ymax       = params->dungeon_ymax;
80
81         //// 2D Terrain noise
82         noise_filler_depth       = new Noise(&params->np_filler_depth,       seed, csize.X, csize.Z);
83         noise_inter_valley_slope = new Noise(&params->np_inter_valley_slope, seed, csize.X, csize.Z);
84         noise_rivers             = new Noise(&params->np_rivers,             seed, csize.X, csize.Z);
85         noise_terrain_height     = new Noise(&params->np_terrain_height,     seed, csize.X, csize.Z);
86         noise_valley_depth       = new Noise(&params->np_valley_depth,       seed, csize.X, csize.Z);
87         noise_valley_profile     = new Noise(&params->np_valley_profile,     seed, csize.X, csize.Z);
88
89         //// 3D Terrain noise
90         // 1-up 1-down overgeneration
91         noise_inter_valley_fill = new Noise(&params->np_inter_valley_fill,
92                 seed, csize.X, csize.Y + 2, csize.Z);
93         // 1-down overgeneraion
94         MapgenBasic::np_cave1    = params->np_cave1;
95         MapgenBasic::np_cave2    = params->np_cave2;
96         MapgenBasic::np_cavern   = params->np_cavern;
97         MapgenBasic::np_dungeons = params->np_dungeons;
98 }
99
100
101 MapgenValleys::~MapgenValleys()
102 {
103         delete noise_filler_depth;
104         delete noise_inter_valley_fill;
105         delete noise_inter_valley_slope;
106         delete noise_rivers;
107         delete noise_terrain_height;
108         delete noise_valley_depth;
109         delete noise_valley_profile;
110 }
111
112
113 MapgenValleysParams::MapgenValleysParams():
114         np_filler_depth       (0.0,   1.2,  v3f(256,  256,  256),  1605,  3, 0.5,  2.0),
115         np_inter_valley_fill  (0.0,   1.0,  v3f(256,  512,  256),  1993,  6, 0.8,  2.0),
116         np_inter_valley_slope (0.5,   0.5,  v3f(128,  128,  128),  746,   1, 1.0,  2.0),
117         np_rivers             (0.0,   1.0,  v3f(256,  256,  256),  -6050, 5, 0.6,  2.0),
118         np_terrain_height     (-10.0, 50.0, v3f(1024, 1024, 1024), 5202,  6, 0.4,  2.0),
119         np_valley_depth       (5.0,   4.0,  v3f(512,  512,  512),  -1914, 1, 1.0,  2.0),
120         np_valley_profile     (0.6,   0.50, v3f(512,  512,  512),  777,   1, 1.0,  2.0),
121         np_cave1              (0.0,   12.0, v3f(61,   61,   61),   52534, 3, 0.5,  2.0),
122         np_cave2              (0.0,   12.0, v3f(67,   67,   67),   10325, 3, 0.5,  2.0),
123         np_cavern             (0.0,   1.0,  v3f(768,  256,  768),  59033, 6, 0.63, 2.0),
124         np_dungeons           (0.9,   0.5,  v3f(500,  500,  500),  0,     2, 0.8,  2.0)
125 {
126 }
127
128
129 void MapgenValleysParams::readParams(const Settings *settings)
130 {
131         settings->getFlagStrNoEx("mgvalleys_spflags", spflags, flagdesc_mapgen_valleys);
132         settings->getU16NoEx("mgvalleys_altitude_chill",       altitude_chill);
133         settings->getS16NoEx("mgvalleys_large_cave_depth",     large_cave_depth);
134         settings->getU16NoEx("mgvalleys_small_cave_num_min",   small_cave_num_min);
135         settings->getU16NoEx("mgvalleys_small_cave_num_max",   small_cave_num_max);
136         settings->getU16NoEx("mgvalleys_large_cave_num_min",   large_cave_num_min);
137         settings->getU16NoEx("mgvalleys_large_cave_num_max",   large_cave_num_max);
138         settings->getFloatNoEx("mgvalleys_large_cave_flooded", large_cave_flooded);
139         settings->getU16NoEx("mgvalleys_river_depth",          river_depth);
140         settings->getU16NoEx("mgvalleys_river_size",           river_size);
141         settings->getFloatNoEx("mgvalleys_cave_width",         cave_width);
142         settings->getS16NoEx("mgvalleys_cavern_limit",         cavern_limit);
143         settings->getS16NoEx("mgvalleys_cavern_taper",         cavern_taper);
144         settings->getFloatNoEx("mgvalleys_cavern_threshold",   cavern_threshold);
145         settings->getS16NoEx("mgvalleys_dungeon_ymin",         dungeon_ymin);
146         settings->getS16NoEx("mgvalleys_dungeon_ymax",         dungeon_ymax);
147
148         settings->getNoiseParams("mgvalleys_np_filler_depth",       np_filler_depth);
149         settings->getNoiseParams("mgvalleys_np_inter_valley_fill",  np_inter_valley_fill);
150         settings->getNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
151         settings->getNoiseParams("mgvalleys_np_rivers",             np_rivers);
152         settings->getNoiseParams("mgvalleys_np_terrain_height",     np_terrain_height);
153         settings->getNoiseParams("mgvalleys_np_valley_depth",       np_valley_depth);
154         settings->getNoiseParams("mgvalleys_np_valley_profile",     np_valley_profile);
155
156         settings->getNoiseParams("mgvalleys_np_cave1",              np_cave1);
157         settings->getNoiseParams("mgvalleys_np_cave2",              np_cave2);
158         settings->getNoiseParams("mgvalleys_np_cavern",             np_cavern);
159         settings->getNoiseParams("mgvalleys_np_dungeons",           np_dungeons);
160 }
161
162
163 void MapgenValleysParams::writeParams(Settings *settings) const
164 {
165         settings->setFlagStr("mgvalleys_spflags", spflags, flagdesc_mapgen_valleys);
166         settings->setU16("mgvalleys_altitude_chill",       altitude_chill);
167         settings->setS16("mgvalleys_large_cave_depth",     large_cave_depth);
168         settings->setU16("mgvalleys_small_cave_num_min",   small_cave_num_min);
169         settings->setU16("mgvalleys_small_cave_num_max",   small_cave_num_max);
170         settings->setU16("mgvalleys_large_cave_num_min",   large_cave_num_min);
171         settings->setU16("mgvalleys_large_cave_num_max",   large_cave_num_max);
172         settings->setFloat("mgvalleys_large_cave_flooded", large_cave_flooded);
173         settings->setU16("mgvalleys_river_depth",          river_depth);
174         settings->setU16("mgvalleys_river_size",           river_size);
175         settings->setFloat("mgvalleys_cave_width",         cave_width);
176         settings->setS16("mgvalleys_cavern_limit",         cavern_limit);
177         settings->setS16("mgvalleys_cavern_taper",         cavern_taper);
178         settings->setFloat("mgvalleys_cavern_threshold",   cavern_threshold);
179         settings->setS16("mgvalleys_dungeon_ymin",         dungeon_ymin);
180         settings->setS16("mgvalleys_dungeon_ymax",         dungeon_ymax);
181
182         settings->setNoiseParams("mgvalleys_np_filler_depth",       np_filler_depth);
183         settings->setNoiseParams("mgvalleys_np_inter_valley_fill",  np_inter_valley_fill);
184         settings->setNoiseParams("mgvalleys_np_inter_valley_slope", np_inter_valley_slope);
185         settings->setNoiseParams("mgvalleys_np_rivers",             np_rivers);
186         settings->setNoiseParams("mgvalleys_np_terrain_height",     np_terrain_height);
187         settings->setNoiseParams("mgvalleys_np_valley_depth",       np_valley_depth);
188         settings->setNoiseParams("mgvalleys_np_valley_profile",     np_valley_profile);
189
190         settings->setNoiseParams("mgvalleys_np_cave1",              np_cave1);
191         settings->setNoiseParams("mgvalleys_np_cave2",              np_cave2);
192         settings->setNoiseParams("mgvalleys_np_cavern",             np_cavern);
193         settings->setNoiseParams("mgvalleys_np_dungeons",           np_dungeons);
194 }
195
196
197 void MapgenValleysParams::setDefaultSettings(Settings *settings)
198 {
199         settings->setDefault("mgvalleys_spflags", flagdesc_mapgen_valleys,
200                 MGVALLEYS_ALT_CHILL | MGVALLEYS_HUMID_RIVERS |
201                 MGVALLEYS_VARY_RIVER_DEPTH | MGVALLEYS_ALT_DRY);
202 }
203
204
205 /////////////////////////////////////////////////////////////////
206
207
208 void MapgenValleys::makeChunk(BlockMakeData *data)
209 {
210         // Pre-conditions
211         assert(data->vmanip);
212         assert(data->nodedef);
213         assert(data->blockpos_requested.X >= data->blockpos_min.X &&
214                 data->blockpos_requested.Y >= data->blockpos_min.Y &&
215                 data->blockpos_requested.Z >= data->blockpos_min.Z);
216         assert(data->blockpos_requested.X <= data->blockpos_max.X &&
217                 data->blockpos_requested.Y <= data->blockpos_max.Y &&
218                 data->blockpos_requested.Z <= data->blockpos_max.Z);
219
220         //TimeTaker t("makeChunk");
221
222         this->generating = true;
223         this->vm = data->vmanip;
224         this->ndef = data->nodedef;
225
226         v3s16 blockpos_min = data->blockpos_min;
227         v3s16 blockpos_max = data->blockpos_max;
228         node_min = blockpos_min * MAP_BLOCKSIZE;
229         node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
230         full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
231         full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
232
233         blockseed = getBlockSeed2(full_node_min, seed);
234
235         // Generate biome noises. Note this must be executed strictly before
236         // generateTerrain, because generateTerrain depends on intermediate
237         // biome-related noises.
238         m_bgen->calcBiomeNoise(node_min);
239
240         // Generate terrain
241         s16 stone_surface_max_y = generateTerrain();
242
243         // Create heightmap
244         updateHeightmap(node_min, node_max);
245
246         // Place biome-specific nodes and build biomemap
247         if (flags & MG_BIOMES) {
248                 generateBiomes();
249         }
250
251         // Generate tunnels, caverns and large randomwalk caves
252         if (flags & MG_CAVES) {
253                 // Generate tunnels first as caverns confuse them
254                 generateCavesNoiseIntersection(stone_surface_max_y);
255
256                 // Generate caverns
257                 bool near_cavern = generateCavernsNoise(stone_surface_max_y);
258
259                 // Generate large randomwalk caves
260                 if (near_cavern)
261                         // Disable large randomwalk caves in this mapchunk by setting
262                         // 'large cave depth' to world base. Avoids excessive liquid in
263                         // large caverns and floating blobs of overgenerated liquid.
264                         generateCavesRandomWalk(stone_surface_max_y,
265                                 -MAX_MAP_GENERATION_LIMIT);
266                 else
267                         generateCavesRandomWalk(stone_surface_max_y, large_cave_depth);
268         }
269
270         // Generate the registered ores
271         if (flags & MG_ORES)
272                 m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
273
274         // Dungeon creation
275         if (flags & MG_DUNGEONS)
276                 generateDungeons(stone_surface_max_y);
277
278         // Generate the registered decorations
279         if (flags & MG_DECORATIONS)
280                 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
281
282         // Sprinkle some dust on top after everything else was generated
283         if (flags & MG_BIOMES)
284                 dustTopNodes();
285
286         updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
287
288         if (flags & MG_LIGHT)
289                 calcLighting(node_min - v3s16(0, 1, 0), node_max + v3s16(0, 1, 0),
290                         full_node_min, full_node_max);
291
292         this->generating = false;
293
294         //printf("makeChunk: %lums\n", t.stop());
295 }
296
297
298 int MapgenValleys::getSpawnLevelAtPoint(v2s16 p)
299 {
300         // Check if in a river channel
301         float n_rivers = NoisePerlin2D(&noise_rivers->np, p.X, p.Y, seed);
302         if (std::fabs(n_rivers) <= river_size_factor)
303                 // Unsuitable spawn point
304                 return MAX_MAP_GENERATION_LIMIT;
305
306         float n_slope          = NoisePerlin2D(&noise_inter_valley_slope->np, p.X, p.Y, seed);
307         float n_terrain_height = NoisePerlin2D(&noise_terrain_height->np, p.X, p.Y, seed);
308         float n_valley         = NoisePerlin2D(&noise_valley_depth->np, p.X, p.Y, seed);
309         float n_valley_profile = NoisePerlin2D(&noise_valley_profile->np, p.X, p.Y, seed);
310
311         float valley_d = n_valley * n_valley;
312         float base = n_terrain_height + valley_d;
313         float river = std::fabs(n_rivers) - river_size_factor;
314         float tv = std::fmax(river / n_valley_profile, 0.0f);
315         float valley_h = valley_d * (1.0f - std::exp(-tv * tv));
316         float surface_y = base + valley_h;
317         float slope = n_slope * valley_h;
318         float river_y = base - 1.0f;
319
320         // Raising the maximum spawn level above 'water_level + 16' is necessary for custom
321         // parameters that set average terrain level much higher than water_level.
322         s16 max_spawn_y = std::fmax(
323                 noise_terrain_height->np.offset +
324                 noise_valley_depth->np.offset * noise_valley_depth->np.offset,
325                 water_level + 16);
326
327         // Starting spawn search at max_spawn_y + 128 ensures 128 nodes of open
328         // space above spawn position. Avoids spawning in possibly sealed voids.
329         for (s16 y = max_spawn_y + 128; y >= water_level; y--) {
330                 float n_fill = NoisePerlin3D(&noise_inter_valley_fill->np, p.X, y, p.Y, seed);
331                 float surface_delta = (float)y - surface_y;
332                 float density = slope * n_fill - surface_delta;
333
334                 if (density > 0.0f) {  // If solid
335                         // Sometimes surface level is below river water level in places that are not
336                         // river channels.
337                         if (y < water_level || y > max_spawn_y || y < (s16)river_y)
338                                 // Unsuitable spawn point
339                                 return MAX_MAP_GENERATION_LIMIT;
340
341                         // y + 2 because y is surface and due to biome 'dust' nodes.
342                         return y + 2;
343                 }
344         }
345         // Unsuitable spawn position, no ground found
346         return MAX_MAP_GENERATION_LIMIT;
347 }
348
349
350 int MapgenValleys::generateTerrain()
351 {
352         MapNode n_air(CONTENT_AIR);
353         MapNode n_river_water(c_river_water_source);
354         MapNode n_stone(c_stone);
355         MapNode n_water(c_water_source);
356
357         noise_inter_valley_slope->perlinMap2D(node_min.X, node_min.Z);
358         noise_rivers->perlinMap2D(node_min.X, node_min.Z);
359         noise_terrain_height->perlinMap2D(node_min.X, node_min.Z);
360         noise_valley_depth->perlinMap2D(node_min.X, node_min.Z);
361         noise_valley_profile->perlinMap2D(node_min.X, node_min.Z);
362
363         noise_inter_valley_fill->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z);
364
365         const v3s16 &em = vm->m_area.getExtent();
366         s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
367         u32 index_2d = 0;
368
369         for (s16 z = node_min.Z; z <= node_max.Z; z++)
370         for (s16 x = node_min.X; x <= node_max.X; x++, index_2d++) {
371                 float n_slope          = noise_inter_valley_slope->result[index_2d];
372                 float n_rivers         = noise_rivers->result[index_2d];
373                 float n_terrain_height = noise_terrain_height->result[index_2d];
374                 float n_valley         = noise_valley_depth->result[index_2d];
375                 float n_valley_profile = noise_valley_profile->result[index_2d];
376
377                 float valley_d = n_valley * n_valley;
378                 // 'base' represents the level of the river banks
379                 float base = n_terrain_height + valley_d;
380                 // 'river' represents the distance from the river edge
381                 float river = std::fabs(n_rivers) - river_size_factor;
382                 // Use the curve of the function 1-exp(-(x/a)^2) to model valleys.
383                 // 'valley_h' represents the height of the terrain, from the rivers.
384                 float tv = std::fmax(river / n_valley_profile, 0.0f);
385                 float valley_h = valley_d * (1.0f - std::exp(-tv * tv));
386                 // Approximate height of the terrain
387                 float surface_y = base + valley_h;
388                 float slope = n_slope * valley_h;
389                 // River water surface is 1 node below river banks
390                 float river_y = base - 1.0f;
391
392                 // Rivers are placed where 'river' is negative
393                 if (river < 0.0f) {
394                         // Use the function -sqrt(1-x^2) which models a circle
395                         float tr = river / river_size_factor + 1.0f;
396                         float depth = (river_depth_bed *
397                                 std::sqrt(std::fmax(0.0f, 1.0f - tr * tr)));
398                         // There is no logical equivalent to this using rangelim
399                         surface_y = std::fmin(
400                                 std::fmax(base - depth, (float)(water_level - 3)),
401                                 surface_y);
402                         slope = 0.0f;
403                 }
404
405                 // Optionally vary river depth according to heat and humidity
406                 if (spflags & MGVALLEYS_VARY_RIVER_DEPTH) {
407                         float t_heat = m_bgen->heatmap[index_2d];
408                         float heat = (spflags & MGVALLEYS_ALT_CHILL) ?
409                                 // Match heat value calculated below in
410                                 // 'Optionally decrease heat with altitude'.
411                                 // In rivers, 'ground height ignoring riverbeds' is 'base'.
412                                 // As this only affects river water we can assume y > water_level.
413                                 t_heat + 5.0f - (base - water_level) * 20.0f / altitude_chill :
414                                 t_heat;
415                         float delta = m_bgen->humidmap[index_2d] - 50.0f;
416                         if (delta < 0.0f) {
417                                 float t_evap = (heat - 32.0f) / 300.0f;
418                                 river_y += delta * std::fmax(t_evap, 0.08f);
419                         }
420                 }
421
422                 // Highest solid node in column
423                 s16 column_max_y = surface_y;
424                 u32 index_3d = (z - node_min.Z) * zstride_1u1d + (x - node_min.X);
425                 u32 index_data = vm->m_area.index(x, node_min.Y - 1, z);
426
427                 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
428                         if (vm->m_data[index_data].getContent() == CONTENT_IGNORE) {
429                                 float n_fill = noise_inter_valley_fill->result[index_3d];
430                                 float surface_delta = (float)y - surface_y;
431                                 // Density = density noise + density gradient
432                                 float density = slope * n_fill - surface_delta;
433
434                                 if (density > 0.0f) {
435                                         vm->m_data[index_data] = n_stone; // Stone
436                                         if (y > surface_max_y)
437                                                 surface_max_y = y;
438                                         if (y > column_max_y)
439                                                 column_max_y = y;
440                                 } else if (y <= water_level) {
441                                         vm->m_data[index_data] = n_water; // Water
442                                 } else if (y <= (s16)river_y) {
443                                         vm->m_data[index_data] = n_river_water; // River water
444                                 } else {
445                                         vm->m_data[index_data] = n_air; // Air
446                                 }
447                         }
448
449                         VoxelArea::add_y(em, index_data, 1);
450                         index_3d += ystride;
451                 }
452
453                 // Optionally increase humidity around rivers
454                 if (spflags & MGVALLEYS_HUMID_RIVERS) {
455                         // Compensate to avoid increasing average humidity
456                         m_bgen->humidmap[index_2d] *= 0.8f;
457                         // Ground height ignoring riverbeds
458                         float t_alt = std::fmax(base, (float)column_max_y);
459                         float water_depth = (t_alt - base) / 4.0f;
460                         m_bgen->humidmap[index_2d] *=
461                                 1.0f + std::pow(0.5f, std::fmax(water_depth, 1.0f));
462                 }
463
464                 // Optionally decrease humidity with altitude
465                 if (spflags & MGVALLEYS_ALT_DRY) {
466                         // Ground height ignoring riverbeds
467                         float t_alt = std::fmax(base, (float)column_max_y);
468                         // Only decrease above water_level
469                         if (t_alt > water_level)
470                                 m_bgen->humidmap[index_2d] -=
471                                         (t_alt - water_level) * 10.0f / altitude_chill;
472                 }
473
474                 // Optionally decrease heat with altitude
475                 if (spflags & MGVALLEYS_ALT_CHILL) {
476                         // Compensate to avoid reducing the average heat
477                         m_bgen->heatmap[index_2d] += 5.0f;
478                         // Ground height ignoring riverbeds
479                         float t_alt = std::fmax(base, (float)column_max_y);
480                         // Only decrease above water_level
481                         if (t_alt > water_level)
482                                 m_bgen->heatmap[index_2d] -=
483                                         (t_alt - water_level) * 20.0f / altitude_chill;
484                 }
485         }
486
487         return surface_max_y;
488 }