cavegen.cpp 21 KB

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