LCOV - code coverage report
Current view: top level - src - cavegen.cpp (source / functions) Hit Total Coverage
Test: report Lines: 2 508 0.4 %
Date: 2015-07-11 18:23:49 Functions: 2 14 14.3 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
       4             : 
       5             : This program is free software; you can redistribute it and/or modify
       6             : it under the terms of the GNU Lesser General Public License as published by
       7             : the Free Software Foundation; either version 2.1 of the License, or
       8             : (at your option) any later version.
       9             : 
      10             : This program is distributed in the hope that it will be useful,
      11             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             : GNU Lesser General Public License for more details.
      14             : 
      15             : You should have received a copy of the GNU Lesser General Public License along
      16             : with this program; if not, write to the Free Software Foundation, Inc.,
      17             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             : */
      19             : 
      20             : #include "util/numeric.h"
      21             : #include "map.h"
      22             : #include "mapgen.h"
      23             : #include "mapgen_v5.h"
      24             : #include "mapgen_v6.h"
      25             : #include "mapgen_v7.h"
      26             : #include "cavegen.h"
      27             : 
      28           1 : NoiseParams nparams_caveliquids(0, 1, v3f(150.0, 150.0, 150.0), 776, 3, 0.6, 2.0);
      29             : 
      30             : 
      31             : ///////////////////////////////////////// Caves V5
      32             : 
      33             : 
      34           0 : CaveV5::CaveV5(MapgenV5 *mg, PseudoRandom *ps) {
      35           0 :         this->mg   = mg;
      36           0 :         this->vm   = mg->vm;
      37           0 :         this->ndef = mg->ndef;
      38           0 :         this->water_level = mg->water_level;
      39           0 :         this->ps = ps;
      40           0 :         this->c_water_source = mg->c_water_source;
      41           0 :         this->c_lava_source  = mg->c_lava_source;
      42           0 :         this->c_ice          = mg->c_ice;
      43           0 :         this->np_caveliquids = &nparams_caveliquids;
      44             : 
      45           0 :         dswitchint = ps->range(1, 14);
      46           0 :         flooded    = ps->range(1, 2) == 2;
      47             : 
      48           0 :         part_max_length_rs = ps->range(2, 4);
      49           0 :         tunnel_routepoints = ps->range(5, ps->range(15, 30));
      50           0 :         min_tunnel_diameter = 5;
      51           0 :         max_tunnel_diameter = ps->range(7, ps->range(8, 24));
      52             : 
      53           0 :         large_cave_is_flat = (ps->range(0, 1) == 0);
      54           0 : }
      55             : 
      56             : 
      57           0 : void CaveV5::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
      58           0 :         node_min = nmin;
      59           0 :         node_max = nmax;
      60           0 :         main_direction = v3f(0, 0, 0);
      61             : 
      62             :         // Allowed route area size in nodes
      63           0 :         ar = node_max - node_min + v3s16(1, 1, 1);
      64             :         // Area starting point in nodes
      65           0 :         of = node_min;
      66             : 
      67             :         // Allow a bit more
      68             :         //(this should be more than the maximum radius of the tunnel)
      69           0 :         s16 insure = 10;
      70           0 :         s16 more = MYMAX(MAP_BLOCKSIZE - max_tunnel_diameter / 2 - insure, 1);
      71           0 :         ar += v3s16(1,0,1) * more * 2;
      72           0 :         of -= v3s16(1,0,1) * more;
      73             : 
      74           0 :         route_y_min = 0;
      75             :         // Allow half a diameter + 7 over stone surface
      76           0 :         route_y_max = -of.Y + max_stone_y + max_tunnel_diameter / 2 + 7;
      77             : 
      78             :         // Limit maximum to area
      79           0 :         route_y_max = rangelim(route_y_max, 0, ar.Y - 1);
      80             : 
      81           0 :         s16 min = 0;
      82           0 :                 if (node_min.Y < water_level && node_max.Y > water_level) {
      83           0 :                         min = water_level - max_tunnel_diameter/3 - of.Y;
      84           0 :                         route_y_max = water_level + max_tunnel_diameter/3 - of.Y;
      85             :                 }
      86           0 :         route_y_min = ps->range(min, min + max_tunnel_diameter);
      87           0 :         route_y_min = rangelim(route_y_min, 0, route_y_max);
      88             : 
      89           0 :         s16 route_start_y_min = route_y_min;
      90           0 :         s16 route_start_y_max = route_y_max;
      91             : 
      92           0 :         route_start_y_min = rangelim(route_start_y_min, 0, ar.Y - 1);
      93           0 :         route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y - 1);
      94             : 
      95             :         // Randomize starting position
      96           0 :         orp = v3f(
      97           0 :                 (float)(ps->next() % ar.X) + 0.5,
      98           0 :                 (float)(ps->range(route_start_y_min, route_start_y_max)) + 0.5,
      99           0 :                 (float)(ps->next() % ar.Z) + 0.5
     100           0 :         );
     101             : 
     102             :         // Add generation notify begin event
     103           0 :         v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
     104           0 :         GenNotifyType notifytype = GENNOTIFY_LARGECAVE_BEGIN;
     105           0 :         mg->gennotify.addEvent(notifytype, abs_pos);
     106             : 
     107             :         // Generate some tunnel starting from orp
     108           0 :         for (u16 j = 0; j < tunnel_routepoints; j++)
     109           0 :                 makeTunnel(j % dswitchint == 0);
     110             : 
     111             :         // Add generation notify end event
     112           0 :         abs_pos = v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
     113           0 :         notifytype = GENNOTIFY_LARGECAVE_END;
     114           0 :         mg->gennotify.addEvent(notifytype, abs_pos);
     115           0 : }
     116             : 
     117             : 
     118           0 : void CaveV5::makeTunnel(bool dirswitch) {
     119             : 
     120             :         // Randomize size
     121           0 :         s16 min_d = min_tunnel_diameter;
     122           0 :         s16 max_d = max_tunnel_diameter;
     123           0 :         rs = ps->range(min_d, max_d);
     124           0 :         s16 rs_part_max_length_rs = rs * part_max_length_rs;
     125             : 
     126           0 :         v3s16 maxlen;
     127           0 :         maxlen = v3s16(
     128             :                 rs_part_max_length_rs,
     129             :                 rs_part_max_length_rs / 2,
     130             :                 rs_part_max_length_rs
     131           0 :         );
     132             : 
     133           0 :         v3f vec;
     134             :         // Jump downward sometimes
     135           0 :         vec = v3f(
     136           0 :                 (float)(ps->next() % maxlen.X) - (float)maxlen.X / 2,
     137           0 :                 (float)(ps->next() % maxlen.Y) - (float)maxlen.Y / 2,
     138           0 :                 (float)(ps->next() % maxlen.Z) - (float)maxlen.Z / 2
     139           0 :         );
     140             : 
     141             :         // Do not make large caves that are above ground.
     142             :         // It is only necessary to check the startpoint and endpoint.
     143           0 :         v3s16 orpi(orp.X, orp.Y, orp.Z);
     144           0 :         v3s16 veci(vec.X, vec.Y, vec.Z);
     145           0 :         v3s16 p;
     146             : 
     147           0 :         p = orpi + veci + of + rs / 2;
     148           0 :         if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
     149           0 :                         p.X >= node_min.X && p.X <= node_max.X) {
     150           0 :                 u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
     151           0 :                 s16 h = mg->heightmap[index];
     152           0 :                 if (h < p.Y)
     153           0 :                         return;
     154           0 :         } else if (p.Y > water_level) {
     155           0 :                 return; // If it's not in our heightmap, use a simple heuristic
     156             :         }
     157             : 
     158           0 :         p = orpi + of + rs / 2;
     159           0 :         if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
     160           0 :                 p.X >= node_min.X && p.X <= node_max.X) {
     161           0 :                 u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
     162           0 :                 s16 h = mg->heightmap[index];
     163           0 :                 if (h < p.Y)
     164           0 :                         return;
     165           0 :         } else if (p.Y > water_level) {
     166           0 :                 return;
     167             :         }
     168             : 
     169           0 :         vec += main_direction;
     170             : 
     171           0 :         v3f rp = orp + vec;
     172           0 :         if (rp.X < 0)
     173           0 :                 rp.X = 0;
     174           0 :         else if (rp.X >= ar.X)
     175           0 :                 rp.X = ar.X - 1;
     176             : 
     177           0 :         if (rp.Y < route_y_min)
     178           0 :                 rp.Y = route_y_min;
     179           0 :         else if (rp.Y >= route_y_max)
     180           0 :                 rp.Y = route_y_max - 1;
     181             : 
     182           0 :         if (rp.Z < 0)
     183           0 :                 rp.Z = 0;
     184           0 :         else if (rp.Z >= ar.Z)
     185           0 :                 rp.Z = ar.Z - 1;
     186             : 
     187           0 :         vec = rp - orp;
     188             : 
     189           0 :         float veclen = vec.getLength();
     190           0 :         if (veclen < 0.05)
     191           0 :                 veclen = 1.0;
     192             : 
     193             :         // Every second section is rough
     194           0 :         bool randomize_xz = (ps->range(1, 2) == 1);
     195             : 
     196             :         // Make a ravine every once in a while if it's long enough
     197             :         //float xylen = vec.X * vec.X + vec.Z * vec.Z;
     198             :         //disable ravines for now
     199           0 :         bool is_ravine = false; //(xylen > 500.0) && !large_cave && (ps->range(1, 8) == 1);
     200             : 
     201             :         // Carve routes
     202           0 :         for (float f = 0; f < 1.0; f += 1.0 / veclen)
     203           0 :                 carveRoute(vec, f, randomize_xz, is_ravine);
     204             : 
     205           0 :         orp = rp;
     206             : }
     207             : 
     208             : 
     209           0 : void CaveV5::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
     210           0 :         MapNode airnode(CONTENT_AIR);
     211           0 :         MapNode waternode(c_water_source);
     212           0 :         MapNode lavanode(c_lava_source);
     213             : 
     214           0 :         v3s16 startp(orp.X, orp.Y, orp.Z);
     215           0 :         startp += of;
     216             : 
     217           0 :         float nval = NoisePerlin3D(np_caveliquids, startp.X,
     218           0 :                                                         startp.Y, startp.Z, mg->seed);
     219           0 :         MapNode liquidnode = nval < 0.40 ? lavanode : waternode;
     220             : 
     221           0 :         v3f fp = orp + vec * f;
     222           0 :         fp.X += 0.1 * ps->range(-10, 10);
     223           0 :         fp.Z += 0.1 * ps->range(-10, 10);
     224           0 :         v3s16 cp(fp.X, fp.Y, fp.Z);
     225             : 
     226           0 :         s16 d0 = -rs/2;
     227           0 :         s16 d1 = d0 + rs;
     228           0 :         if (randomize_xz) {
     229           0 :                 d0 += ps->range(-1, 1);
     230           0 :                 d1 += ps->range(-1, 1);
     231             :         }
     232             : 
     233           0 :         bool should_make_cave_hole = ps->range(1, 10) == 1;
     234             : 
     235           0 :         for (s16 z0 = d0; z0 <= d1; z0++) {
     236           0 :                 s16 si = rs / 2 - MYMAX(0, abs(z0) - rs / 7 - 1);
     237           0 :                 for (s16 x0 = -si - ps->range(0,1); x0 <= si - 1 + ps->range(0,1); x0++) {
     238           0 :                         s16 maxabsxz = MYMAX(abs(x0), abs(z0));
     239             : 
     240           0 :                         s16 si2 = is_ravine ? MYMIN(ps->range(25, 26), ar.Y) :
     241           0 :                                                                  rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);
     242             : 
     243           0 :                         for (s16 y0 = -si2; y0 <= si2; y0++) {
     244           0 :                                 if (large_cave_is_flat) {
     245             :                                         // Make large caves not so tall
     246           0 :                                         if (rs > 7 && abs(y0) >= rs / 3)
     247           0 :                                                 continue;
     248             :                                 }
     249             : 
     250           0 :                                 v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
     251           0 :                                 p += of;
     252             : 
     253           0 :                                 if (!is_ravine && mg->heightmap && should_make_cave_hole &&
     254           0 :                                         p.X <= node_max.X && p.Z <= node_max.Z) {
     255           0 :                                         int maplen = node_max.X - node_min.X + 1;
     256           0 :                                         int idx = (p.Z - node_min.Z) * maplen + (p.X - node_min.X);
     257           0 :                                         if (p.Y >= mg->heightmap[idx] - 2)
     258           0 :                                                 continue;
     259             :                                 }
     260             : 
     261           0 :                                 if (vm->m_area.contains(p) == false)
     262           0 :                                         continue;
     263             : 
     264           0 :                                 u32 i = vm->m_area.index(p);
     265           0 :                                 content_t c = vm->m_data[i].getContent();
     266           0 :                                 if (!ndef->get(c).is_ground_content)
     267           0 :                                         continue;
     268             : 
     269           0 :                                 int full_ymin = node_min.Y - MAP_BLOCKSIZE;
     270           0 :                                 int full_ymax = node_max.Y + MAP_BLOCKSIZE;
     271             : 
     272           0 :                                 if (flooded && full_ymin < water_level && full_ymax > water_level)
     273           0 :                                         vm->m_data[i] = (p.Y <= water_level) ? waternode : airnode;
     274           0 :                                 else if (flooded && full_ymax < water_level)
     275           0 :                                         vm->m_data[i] = (p.Y < startp.Y - 4) ? liquidnode : airnode;
     276             :                                 else
     277           0 :                                         vm->m_data[i] = airnode;
     278             :                         }
     279             :                 }
     280             :         }
     281           0 : }
     282             : 
     283             : 
     284             : ///////////////////////////////////////// Caves V6
     285             : 
     286             : 
     287           0 : CaveV6::CaveV6(MapgenV6 *mg, PseudoRandom *ps, PseudoRandom *ps2, bool is_large_cave) {
     288           0 :         this->mg   = mg;
     289           0 :         this->vm   = mg->vm;
     290           0 :         this->ndef = mg->ndef;
     291           0 :         this->water_level = mg->water_level;
     292           0 :         this->large_cave = is_large_cave;
     293           0 :         this->ps  = ps;
     294           0 :         this->ps2 = ps2;
     295           0 :         this->c_water_source = mg->c_water_source;
     296           0 :         this->c_lava_source  = mg->c_lava_source;
     297             : 
     298           0 :         min_tunnel_diameter = 2;
     299           0 :         max_tunnel_diameter = ps->range(2, 6);
     300           0 :         dswitchint = ps->range(1, 14);
     301           0 :         flooded = true;
     302             : 
     303           0 :         if (large_cave) {
     304           0 :                 part_max_length_rs = ps->range(2,4);
     305           0 :                 tunnel_routepoints = ps->range(5, ps->range(15,30));
     306           0 :                 min_tunnel_diameter = 5;
     307           0 :                 max_tunnel_diameter = ps->range(7, ps->range(8,24));
     308             :         } else {
     309           0 :                 part_max_length_rs = ps->range(2,9);
     310           0 :                 tunnel_routepoints = ps->range(10, ps->range(15,30));
     311             :         }
     312             : 
     313           0 :         large_cave_is_flat = (ps->range(0,1) == 0);
     314           0 : }
     315             : 
     316             : 
     317           0 : void CaveV6::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
     318           0 :         node_min = nmin;
     319           0 :         node_max = nmax;
     320           0 :         max_stone_y = max_stone_height;
     321           0 :         main_direction = v3f(0, 0, 0);
     322             : 
     323             :         // Allowed route area size in nodes
     324           0 :         ar = node_max - node_min + v3s16(1, 1, 1);
     325             :         // Area starting point in nodes
     326           0 :         of = node_min;
     327             : 
     328             :         // Allow a bit more
     329             :         //(this should be more than the maximum radius of the tunnel)
     330           0 :         const s16 max_spread_amount = MAP_BLOCKSIZE;
     331           0 :         s16 insure = 10;
     332           0 :         s16 more = MYMAX(max_spread_amount - max_tunnel_diameter / 2 - insure, 1);
     333           0 :         ar += v3s16(1,0,1) * more * 2;
     334           0 :         of -= v3s16(1,0,1) * more;
     335             : 
     336           0 :         route_y_min = 0;
     337             :         // Allow half a diameter + 7 over stone surface
     338           0 :         route_y_max = -of.Y + max_stone_y + max_tunnel_diameter / 2 + 7;
     339             : 
     340             :         // Limit maximum to area
     341           0 :         route_y_max = rangelim(route_y_max, 0, ar.Y - 1);
     342             : 
     343           0 :         if (large_cave) {
     344           0 :                 s16 min = 0;
     345           0 :                 if (node_min.Y < water_level && node_max.Y > water_level) {
     346           0 :                         min = water_level - max_tunnel_diameter/3 - of.Y;
     347           0 :                         route_y_max = water_level + max_tunnel_diameter/3 - of.Y;
     348             :                 }
     349           0 :                 route_y_min = ps->range(min, min + max_tunnel_diameter);
     350           0 :                 route_y_min = rangelim(route_y_min, 0, route_y_max);
     351             :         }
     352             : 
     353           0 :         s16 route_start_y_min = route_y_min;
     354           0 :         s16 route_start_y_max = route_y_max;
     355             : 
     356           0 :         route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
     357           0 :         route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
     358             : 
     359             :         // Randomize starting position
     360           0 :         orp = v3f(
     361           0 :                 (float)(ps->next() % ar.X) + 0.5,
     362           0 :                 (float)(ps->range(route_start_y_min, route_start_y_max)) + 0.5,
     363           0 :                 (float)(ps->next() % ar.Z) + 0.5
     364           0 :         );
     365             : 
     366             :         // Add generation notify begin event
     367           0 :         v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
     368           0 :         GenNotifyType notifytype = large_cave ?
     369           0 :                 GENNOTIFY_LARGECAVE_BEGIN : GENNOTIFY_CAVE_BEGIN;
     370           0 :         mg->gennotify.addEvent(notifytype, abs_pos);
     371             : 
     372             :         // Generate some tunnel starting from orp
     373           0 :         for (u16 j = 0; j < tunnel_routepoints; j++)
     374           0 :                 makeTunnel(j % dswitchint == 0);
     375             : 
     376             :         // Add generation notify end event
     377           0 :         abs_pos = v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
     378           0 :         notifytype = large_cave ?
     379           0 :                 GENNOTIFY_LARGECAVE_END : GENNOTIFY_CAVE_END;
     380           0 :         mg->gennotify.addEvent(notifytype, abs_pos);
     381           0 : }
     382             : 
     383             : 
     384           0 : void CaveV6::makeTunnel(bool dirswitch) {
     385           0 :         if (dirswitch && !large_cave) {
     386           0 :                 main_direction = v3f(
     387           0 :                         ((float)(ps->next() % 20) - (float)10) / 10,
     388           0 :                         ((float)(ps->next() % 20) - (float)10) / 30,
     389           0 :                         ((float)(ps->next() % 20) - (float)10) / 10
     390           0 :                 );
     391           0 :                 main_direction *= (float)ps->range(0, 10) / 10;
     392             :         }
     393             : 
     394             :         // Randomize size
     395           0 :         s16 min_d = min_tunnel_diameter;
     396           0 :         s16 max_d = max_tunnel_diameter;
     397           0 :         rs = ps->range(min_d, max_d);
     398           0 :         s16 rs_part_max_length_rs = rs * part_max_length_rs;
     399             : 
     400           0 :         v3s16 maxlen;
     401           0 :         if (large_cave) {
     402           0 :                 maxlen = v3s16(
     403             :                         rs_part_max_length_rs,
     404             :                         rs_part_max_length_rs / 2,
     405             :                         rs_part_max_length_rs
     406           0 :                 );
     407             :         } else {
     408           0 :                 maxlen = v3s16(
     409             :                         rs_part_max_length_rs,
     410           0 :                         ps->range(1, rs_part_max_length_rs),
     411             :                         rs_part_max_length_rs
     412           0 :                 );
     413             :         }
     414             : 
     415             :         v3f vec(
     416           0 :                 (float)(ps->next() % maxlen.X) - (float)maxlen.X / 2,
     417           0 :                 (float)(ps->next() % maxlen.Y) - (float)maxlen.Y / 2,
     418           0 :                 (float)(ps->next() % maxlen.Z) - (float)maxlen.Z / 2
     419           0 :         );
     420             : 
     421             :         // Jump downward sometimes
     422           0 :         if (!large_cave && ps->range(0, 12) == 0) {
     423           0 :                 vec = v3f(
     424           0 :                         (float)(ps->next() % maxlen.X) - (float)maxlen.X / 2,
     425           0 :                         (float)(ps->next() % (maxlen.Y * 2)) - (float)maxlen.Y,
     426           0 :                         (float)(ps->next() % maxlen.Z) - (float)maxlen.Z / 2
     427           0 :                 );
     428             :         }
     429             : 
     430             :         // Do not make large caves that are entirely above ground.
     431             :         // It is only necessary to check the startpoint and endpoint.
     432           0 :         if (large_cave) {
     433           0 :                 v3s16 orpi(orp.X, orp.Y, orp.Z);
     434           0 :                 v3s16 veci(vec.X, vec.Y, vec.Z);
     435             :                 s16 h1;
     436             :                 s16 h2;
     437             : 
     438           0 :                 v3s16 p1 = orpi + veci + of + rs / 2;
     439           0 :                 if (p1.Z >= node_min.Z && p1.Z <= node_max.Z &&
     440           0 :                                 p1.X >= node_min.X && p1.X <= node_max.X) {
     441           0 :                         u32 index1 = (p1.Z - node_min.Z) * mg->ystride + (p1.X - node_min.X);
     442           0 :                         h1 = mg->heightmap[index1];
     443             :                 } else {
     444           0 :                         h1 = water_level; // If not in heightmap
     445             :                 }
     446             : 
     447           0 :                 v3s16 p2 = orpi + of + rs / 2;
     448           0 :                 if (p2.Z >= node_min.Z && p2.Z <= node_max.Z &&
     449           0 :                                 p2.X >= node_min.X && p2.X <= node_max.X) {
     450           0 :                         u32 index2 = (p2.Z - node_min.Z) * mg->ystride + (p2.X - node_min.X);
     451           0 :                         h2 = mg->heightmap[index2];
     452             :                 } else {
     453           0 :                         h2 = water_level;
     454             :                 }
     455             : 
     456           0 :                 if (p1.Y > h1 && p2.Y > h2) // If startpoint and endpoint are above ground
     457           0 :                         return;
     458             :         }
     459             : 
     460           0 :         vec += main_direction;
     461             : 
     462           0 :         v3f rp = orp + vec;
     463           0 :         if (rp.X < 0)
     464           0 :                 rp.X = 0;
     465           0 :         else if (rp.X >= ar.X)
     466           0 :                 rp.X = ar.X - 1;
     467             : 
     468           0 :         if (rp.Y < route_y_min)
     469           0 :                 rp.Y = route_y_min;
     470           0 :         else if (rp.Y >= route_y_max)
     471           0 :                 rp.Y = route_y_max - 1;
     472             : 
     473           0 :         if (rp.Z < 0)
     474           0 :                 rp.Z = 0;
     475           0 :         else if (rp.Z >= ar.Z)
     476           0 :                 rp.Z = ar.Z - 1;
     477             : 
     478           0 :         vec = rp - orp;
     479             : 
     480           0 :         float veclen = vec.getLength();
     481             :         // As odd as it sounds, veclen is *exactly* 0.0 sometimes, causing a FPE
     482           0 :         if (veclen < 0.05)
     483           0 :                 veclen = 1.0;
     484             : 
     485             :         // Every second section is rough
     486           0 :         bool randomize_xz = (ps2->range(1, 2) == 1);
     487             : 
     488             :         // Carve routes
     489           0 :         for (float f = 0; f < 1.0; f += 1.0 / veclen)
     490           0 :                 carveRoute(vec, f, randomize_xz);
     491             : 
     492           0 :         orp = rp;
     493             : }
     494             : 
     495             : 
     496           0 : void CaveV6::carveRoute(v3f vec, float f, bool randomize_xz) {
     497           0 :         MapNode airnode(CONTENT_AIR);
     498           0 :         MapNode waternode(c_water_source);
     499           0 :         MapNode lavanode(c_lava_source);
     500             : 
     501           0 :         v3s16 startp(orp.X, orp.Y, orp.Z);
     502           0 :         startp += of;
     503             : 
     504           0 :         v3f fp = orp + vec * f;
     505           0 :         fp.X += 0.1 * ps->range(-10, 10);
     506           0 :         fp.Z += 0.1 * ps->range(-10, 10);
     507           0 :         v3s16 cp(fp.X, fp.Y, fp.Z);
     508             : 
     509           0 :         s16 d0 = -rs/2;
     510           0 :         s16 d1 = d0 + rs;
     511           0 :         if (randomize_xz) {
     512           0 :                 d0 += ps->range(-1, 1);
     513           0 :                 d1 += ps->range(-1, 1);
     514             :         }
     515             : 
     516           0 :         for (s16 z0 = d0; z0 <= d1; z0++) {
     517           0 :                 s16 si = rs / 2 - MYMAX(0, abs(z0) - rs / 7 - 1);
     518           0 :                 for (s16 x0 = -si - ps->range(0,1); x0 <= si - 1 + ps->range(0,1); x0++) {
     519           0 :                         s16 maxabsxz = MYMAX(abs(x0), abs(z0));
     520           0 :                         s16 si2 = rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);
     521           0 :                         for (s16 y0 = -si2; y0 <= si2; y0++) {
     522           0 :                                 if (large_cave_is_flat) {
     523             :                                         // Make large caves not so tall
     524           0 :                                         if (rs > 7 && abs(y0) >= rs / 3)
     525           0 :                                                 continue;
     526             :                                 }
     527             : 
     528           0 :                                 v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
     529           0 :                                 p += of;
     530             : 
     531           0 :                                 if (vm->m_area.contains(p) == false)
     532           0 :                                         continue;
     533             : 
     534           0 :                                 u32 i = vm->m_area.index(p);
     535           0 :                                 content_t c = vm->m_data[i].getContent();
     536           0 :                                 if (!ndef->get(c).is_ground_content)
     537           0 :                                         continue;
     538             : 
     539           0 :                                 if (large_cave) {
     540           0 :                                         int full_ymin = node_min.Y - MAP_BLOCKSIZE;
     541           0 :                                         int full_ymax = node_max.Y + MAP_BLOCKSIZE;
     542             : 
     543           0 :                                         if (flooded && full_ymin < water_level && full_ymax > water_level) {
     544           0 :                                                 vm->m_data[i] = (p.Y <= water_level) ? waternode : airnode;
     545           0 :                                         } else if (flooded && full_ymax < water_level) {
     546           0 :                                                 vm->m_data[i] = (p.Y < startp.Y - 2) ? lavanode : airnode;
     547             :                                         } else {
     548           0 :                                                 vm->m_data[i] = airnode;
     549             :                                         }
     550             :                                 } else {
     551           0 :                                         if (c == CONTENT_IGNORE || c == CONTENT_AIR)
     552           0 :                                                 continue;
     553             : 
     554           0 :                                         vm->m_data[i] = airnode;
     555           0 :                                         vm->m_flags[i] |= VMANIP_FLAG_CAVE;
     556             :                                 }
     557             :                         }
     558             :                 }
     559             :         }
     560           0 : }
     561             : 
     562             : 
     563             : ///////////////////////////////////////// Caves V7
     564             : 
     565             : 
     566           0 : CaveV7::CaveV7(MapgenV7 *mg, PseudoRandom *ps) {
     567           0 :         this->mg   = mg;
     568           0 :         this->vm   = mg->vm;
     569           0 :         this->ndef = mg->ndef;
     570           0 :         this->water_level = mg->water_level;
     571           0 :         this->ps = ps;
     572           0 :         this->c_water_source = mg->c_water_source;
     573           0 :         this->c_lava_source  = mg->c_lava_source;
     574           0 :         this->c_ice          = mg->c_ice;
     575           0 :         this->np_caveliquids = &nparams_caveliquids;
     576             : 
     577           0 :         dswitchint = ps->range(1, 14);
     578           0 :         flooded    = ps->range(1, 2) == 2;
     579             : 
     580           0 :         part_max_length_rs = ps->range(2, 4);
     581           0 :         tunnel_routepoints = ps->range(5, ps->range(15, 30));
     582           0 :         min_tunnel_diameter = 5;
     583           0 :         max_tunnel_diameter = ps->range(7, ps->range(8, 24));
     584             : 
     585           0 :         large_cave_is_flat = (ps->range(0, 1) == 0);
     586           0 : }
     587             : 
     588             : 
     589           0 : void CaveV7::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
     590           0 :         node_min = nmin;
     591           0 :         node_max = nmax;
     592           0 :         max_stone_y = max_stone_height;
     593           0 :         main_direction = v3f(0, 0, 0);
     594             : 
     595             :         // Allowed route area size in nodes
     596           0 :         ar = node_max - node_min + v3s16(1, 1, 1);
     597             :         // Area starting point in nodes
     598           0 :         of = node_min;
     599             : 
     600             :         // Allow a bit more
     601             :         //(this should be more than the maximum radius of the tunnel)
     602           0 :         s16 insure = 10;
     603           0 :         s16 more = MYMAX(MAP_BLOCKSIZE - max_tunnel_diameter / 2 - insure, 1);
     604           0 :         ar += v3s16(1,0,1) * more * 2;
     605           0 :         of -= v3s16(1,0,1) * more;
     606             : 
     607           0 :         route_y_min = 0;
     608             :         // Allow half a diameter + 7 over stone surface
     609           0 :         route_y_max = -of.Y + max_stone_y + max_tunnel_diameter / 2 + 7;
     610             : 
     611             :         // Limit maximum to area
     612           0 :         route_y_max = rangelim(route_y_max, 0, ar.Y - 1);
     613             : 
     614           0 :         s16 min = 0;
     615           0 :         if (node_min.Y < water_level && node_max.Y > water_level) {
     616           0 :                 min = water_level - max_tunnel_diameter/3 - of.Y;
     617           0 :                 route_y_max = water_level + max_tunnel_diameter/3 - of.Y;
     618             :         }
     619           0 :         route_y_min = ps->range(min, min + max_tunnel_diameter);
     620           0 :         route_y_min = rangelim(route_y_min, 0, route_y_max);
     621             : 
     622           0 :         s16 route_start_y_min = route_y_min;
     623           0 :         s16 route_start_y_max = route_y_max;
     624             : 
     625           0 :         route_start_y_min = rangelim(route_start_y_min, 0, ar.Y - 1);
     626           0 :         route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y - 1);
     627             : 
     628             :         // Randomize starting position
     629           0 :         orp = v3f(
     630           0 :                 (float)(ps->next() % ar.X) + 0.5,
     631           0 :                 (float)(ps->range(route_start_y_min, route_start_y_max)) + 0.5,
     632           0 :                 (float)(ps->next() % ar.Z) + 0.5
     633           0 :         );
     634             : 
     635             :         // Add generation notify begin event
     636           0 :         v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
     637           0 :         GenNotifyType notifytype = GENNOTIFY_LARGECAVE_BEGIN;
     638           0 :         mg->gennotify.addEvent(notifytype, abs_pos);
     639             : 
     640             :         // Generate some tunnel starting from orp
     641           0 :         for (u16 j = 0; j < tunnel_routepoints; j++)
     642           0 :                 makeTunnel(j % dswitchint == 0);
     643             : 
     644             :         // Add generation notify end event
     645           0 :         abs_pos = v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
     646           0 :         notifytype = GENNOTIFY_LARGECAVE_END;
     647           0 :         mg->gennotify.addEvent(notifytype, abs_pos);
     648           0 : }
     649             : 
     650             : 
     651           0 : void CaveV7::makeTunnel(bool dirswitch) {
     652             : 
     653             :         // Randomize size
     654           0 :         s16 min_d = min_tunnel_diameter;
     655           0 :         s16 max_d = max_tunnel_diameter;
     656           0 :         rs = ps->range(min_d, max_d);
     657           0 :         s16 rs_part_max_length_rs = rs * part_max_length_rs;
     658             : 
     659           0 :         v3s16 maxlen;
     660           0 :         maxlen = v3s16(
     661             :                 rs_part_max_length_rs,
     662             :                 rs_part_max_length_rs / 2,
     663             :                 rs_part_max_length_rs
     664           0 :         );
     665             : 
     666           0 :         v3f vec;
     667             :         // Jump downward sometimes
     668           0 :         vec = v3f(
     669           0 :                 (float)(ps->next() % maxlen.X) - (float)maxlen.X / 2,
     670           0 :                 (float)(ps->next() % maxlen.Y) - (float)maxlen.Y / 2,
     671           0 :                 (float)(ps->next() % maxlen.Z) - (float)maxlen.Z / 2
     672           0 :         );
     673             : 
     674             :         // Do not make large caves that are above ground.
     675             :         // It is only necessary to check the startpoint and endpoint.
     676           0 :         v3s16 orpi(orp.X, orp.Y, orp.Z);
     677           0 :         v3s16 veci(vec.X, vec.Y, vec.Z);
     678           0 :         v3s16 p;
     679             : 
     680           0 :         p = orpi + veci + of + rs / 2;
     681           0 :         if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
     682           0 :                         p.X >= node_min.X && p.X <= node_max.X) {
     683           0 :                 u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
     684           0 :                 s16 h = mg->ridge_heightmap[index];
     685           0 :                 if (h < p.Y)
     686           0 :                         return;
     687           0 :         } else if (p.Y > water_level) {
     688           0 :                 return; // If it's not in our heightmap, use a simple heuristic
     689             :         }
     690             : 
     691           0 :         p = orpi + of + rs / 2;
     692           0 :         if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
     693           0 :                         p.X >= node_min.X && p.X <= node_max.X) {
     694           0 :                 u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
     695           0 :                 s16 h = mg->ridge_heightmap[index];
     696           0 :                 if (h < p.Y)
     697           0 :                         return;
     698           0 :         } else if (p.Y > water_level) {
     699           0 :                 return;
     700             :         }
     701             : 
     702           0 :         vec += main_direction;
     703             : 
     704           0 :         v3f rp = orp + vec;
     705           0 :         if (rp.X < 0)
     706           0 :                 rp.X = 0;
     707           0 :         else if (rp.X >= ar.X)
     708           0 :                 rp.X = ar.X - 1;
     709             : 
     710           0 :         if (rp.Y < route_y_min)
     711           0 :                 rp.Y = route_y_min;
     712           0 :         else if (rp.Y >= route_y_max)
     713           0 :                 rp.Y = route_y_max - 1;
     714             : 
     715           0 :         if (rp.Z < 0)
     716           0 :                 rp.Z = 0;
     717           0 :         else if (rp.Z >= ar.Z)
     718           0 :                 rp.Z = ar.Z - 1;
     719             : 
     720           0 :         vec = rp - orp;
     721             : 
     722           0 :         float veclen = vec.getLength();
     723           0 :         if (veclen < 0.05)
     724           0 :                 veclen = 1.0;
     725             : 
     726             :         // Every second section is rough
     727           0 :         bool randomize_xz = (ps->range(1, 2) == 1);
     728             : 
     729             :         // Make a ravine every once in a while if it's long enough
     730             :         //float xylen = vec.X * vec.X + vec.Z * vec.Z;
     731             :         //disable ravines for now
     732           0 :         bool is_ravine = false; //(xylen > 500.0) && !large_cave && (ps->range(1, 8) == 1);
     733             : 
     734             :         // Carve routes
     735           0 :         for (float f = 0; f < 1.0; f += 1.0 / veclen)
     736           0 :                 carveRoute(vec, f, randomize_xz, is_ravine);
     737             : 
     738           0 :         orp = rp;
     739             : }
     740             : 
     741             : 
     742           0 : void CaveV7::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
     743           0 :         MapNode airnode(CONTENT_AIR);
     744           0 :         MapNode waternode(c_water_source);
     745           0 :         MapNode lavanode(c_lava_source);
     746             : 
     747           0 :         v3s16 startp(orp.X, orp.Y, orp.Z);
     748           0 :         startp += of;
     749             : 
     750           0 :         float nval = NoisePerlin3D(np_caveliquids, startp.X,
     751           0 :                                                         startp.Y, startp.Z, mg->seed);
     752           0 :         MapNode liquidnode = (nval < 0.40 && node_max.Y < -256) ? lavanode : waternode;
     753             : 
     754           0 :         v3f fp = orp + vec * f;
     755           0 :         fp.X += 0.1 * ps->range(-10, 10);
     756           0 :         fp.Z += 0.1 * ps->range(-10, 10);
     757           0 :         v3s16 cp(fp.X, fp.Y, fp.Z);
     758             : 
     759           0 :         s16 d0 = -rs/2;
     760           0 :         s16 d1 = d0 + rs;
     761           0 :         if (randomize_xz) {
     762           0 :                 d0 += ps->range(-1, 1);
     763           0 :                 d1 += ps->range(-1, 1);
     764             :         }
     765             : 
     766           0 :         bool should_make_cave_hole = ps->range(1, 10) == 1;
     767             : 
     768           0 :         for (s16 z0 = d0; z0 <= d1; z0++) {
     769           0 :                 s16 si = rs / 2 - MYMAX(0, abs(z0) - rs / 7 - 1);
     770           0 :                 for (s16 x0 = -si - ps->range(0,1); x0 <= si - 1 + ps->range(0,1); x0++) {
     771           0 :                         s16 maxabsxz = MYMAX(abs(x0), abs(z0));
     772             : 
     773           0 :                         s16 si2 = is_ravine ? MYMIN(ps->range(25, 26), ar.Y) :
     774           0 :                                                                  rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);
     775             : 
     776           0 :                         for (s16 y0 = -si2; y0 <= si2; y0++) {
     777           0 :                                 if (large_cave_is_flat) {
     778             :                                         // Make large caves not so tall
     779           0 :                                         if (rs > 7 && abs(y0) >= rs / 3)
     780           0 :                                                 continue;
     781             :                                 }
     782             : 
     783           0 :                                 v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
     784           0 :                                 p += of;
     785             : 
     786           0 :                                 if (!is_ravine && mg->heightmap && should_make_cave_hole &&
     787           0 :                                         p.X <= node_max.X && p.Z <= node_max.Z) {
     788           0 :                                         int maplen = node_max.X - node_min.X + 1;
     789           0 :                                         int idx = (p.Z - node_min.Z) * maplen + (p.X - node_min.X);
     790           0 :                                         if (p.Y >= mg->heightmap[idx] - 2)
     791           0 :                                                 continue;
     792             :                                 }
     793             : 
     794           0 :                                 if (vm->m_area.contains(p) == false)
     795           0 :                                         continue;
     796             : 
     797           0 :                                 u32 i = vm->m_area.index(p);
     798           0 :                                 content_t c = vm->m_data[i].getContent();
     799           0 :                                 if (!ndef->get(c).is_ground_content)
     800           0 :                                         continue;
     801             : 
     802           0 :                                 int full_ymin = node_min.Y - MAP_BLOCKSIZE;
     803           0 :                                 int full_ymax = node_max.Y + MAP_BLOCKSIZE;
     804             : 
     805           0 :                                 if (flooded && full_ymin < water_level && full_ymax > water_level)
     806           0 :                                         vm->m_data[i] = (p.Y <= water_level) ? waternode : airnode;
     807           0 :                                 else if (flooded && full_ymax < water_level)
     808           0 :                                         vm->m_data[i] = (p.Y < startp.Y - 4) ? liquidnode : airnode;
     809             :                                 else
     810           0 :                                         vm->m_data[i] = airnode;
     811             :                         }
     812             :                 }
     813             :         }
     814           3 : }
     815             : 

Generated by: LCOV version 1.11