@@ -20,18 +20,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
20
20
#include " util/numeric.h"
21
21
#include " map.h"
22
22
#include " mapgen.h"
23
+ #include " mapgen_v6.h"
24
+ #include " mapgen_v7.h"
23
25
#include " cavegen.h"
24
26
25
27
26
- CaveV6::CaveV6 (Mapgen *mg, PseudoRandom *ps, PseudoRandom *ps2,
27
- bool is_large_cave, content_t c_water, content_t c_lava) {
28
- this ->vm = mg->vm ;
28
+ CaveV6::CaveV6 (MapgenV6 *mg, PseudoRandom *ps, PseudoRandom *ps2, bool is_large_cave) {
29
+ this ->mg = mg;
30
+ this ->vm = mg->vm ;
31
+ this ->ndef = mg->ndef ;
29
32
this ->water_level = mg->water_level ;
30
33
this ->large_cave = is_large_cave;
31
34
this ->ps = ps;
32
35
this ->ps2 = ps2;
33
- this ->c_water_source = c_water ;
34
- this ->c_lava_source = c_lava ;
36
+ this ->c_water_source = mg-> c_water_source ;
37
+ this ->c_lava_source = mg-> c_lava_source ;
35
38
36
39
min_tunnel_diameter = 2 ;
37
40
max_tunnel_diameter = ps->range (2 , 6 );
@@ -152,13 +155,6 @@ void CaveV6::makeTunnel(bool dirswitch) {
152
155
);
153
156
}
154
157
155
- /* if(large_cave){
156
- v3f p = orp + vec;
157
- s16 h = find_ground_level_clever(vmanip, v2s16(p.X, p.Z), ndef);
158
- route_y_min = h - rs/3;
159
- route_y_max = h + rs;
160
- }*/
161
-
162
158
vec += main_direction;
163
159
164
160
v3f rp = orp + vec;
@@ -181,7 +177,7 @@ void CaveV6::makeTunnel(bool dirswitch) {
181
177
182
178
float veclen = vec.getLength ();
183
179
// As odd as it sounds, veclen is *exactly* 0.0 sometimes, causing a FPE
184
- if (veclen == 0.0 )
180
+ if (veclen < 0.05 )
185
181
veclen = 1.0 ;
186
182
187
183
// Every second section is rough
@@ -220,11 +216,7 @@ void CaveV6::carveRoute(v3f vec, float f, bool randomize_xz) {
220
216
for (s16 x0 = -si - ps->range (0 ,1 ); x0 <= si - 1 + ps->range (0 ,1 ); x0++) {
221
217
s16 maxabsxz = MYMAX (abs (x0), abs (z0));
222
218
s16 si2 = rs / 2 - MYMAX (0 , maxabsxz - rs / 7 - 1 );
223
- for (s16 y0 = -si2; y0 <= si2; y0 ++) {
224
- // Make better floors in small caves
225
- // if(y0 <= -rs/2 && rs<=7)
226
- // continue;
227
-
219
+ for (s16 y0 = -si2; y0 <= si2; y0 ++) {
228
220
if (large_cave_is_flat) {
229
221
// Make large caves not so tall
230
222
if (rs > 7 && abs (y0 ) >= rs / 3 )
@@ -242,7 +234,7 @@ void CaveV6::carveRoute(v3f vec, float f, bool randomize_xz) {
242
234
if (large_cave) {
243
235
int full_ymin = node_min.Y - MAP_BLOCKSIZE;
244
236
int full_ymax = node_max.Y + MAP_BLOCKSIZE;
245
-
237
+
246
238
if (flooded && full_ymin < water_level && full_ymax > water_level) {
247
239
vm->m_data [i] = (p.Y <= water_level) ? waternode : airnode;
248
240
} else if (flooded && full_ymax < water_level) {
@@ -264,3 +256,278 @@ void CaveV6::carveRoute(v3f vec, float f, bool randomize_xz) {
264
256
}
265
257
}
266
258
}
259
+
260
+
261
+ // /////////////////////////////////////// Caves V7
262
+
263
+ CaveV7::CaveV7 (MapgenV7 *mg, PseudoRandom *ps, bool is_large_cave) {
264
+ this ->mg = mg;
265
+ this ->vm = mg->vm ;
266
+ this ->ndef = mg->ndef ;
267
+ this ->water_level = mg->water_level ;
268
+ this ->large_cave = is_large_cave;
269
+ this ->ps = ps;
270
+ this ->c_water_source = mg->c_water_source ;
271
+ this ->c_lava_source = mg->c_lava_source ;
272
+
273
+ dswitchint = ps->range (1 , 14 );
274
+ flooded = ps->range (1 , 2 ) == 2 ;
275
+
276
+ if (large_cave) {
277
+ part_max_length_rs = ps->range (2 , 4 );
278
+ tunnel_routepoints = ps->range (5 , ps->range (15 , 30 ));
279
+ min_tunnel_diameter = 5 ;
280
+ max_tunnel_diameter = ps->range (7 , ps->range (8 , 24 ));
281
+ } else {
282
+ part_max_length_rs = ps->range (2 , 9 );
283
+ tunnel_routepoints = ps->range (10 , ps->range (15 , 30 ));
284
+ min_tunnel_diameter = 2 ;
285
+ max_tunnel_diameter = ps->range (2 , 6 );
286
+ }
287
+
288
+ large_cave_is_flat = (ps->range (0 , 1 ) == 0 );
289
+ }
290
+
291
+
292
+ void CaveV7::makeCave (v3s16 nmin, v3s16 nmax, int max_stone_height) {
293
+ node_min = nmin;
294
+ node_max = nmax;
295
+ max_stone_y = max_stone_height;
296
+ main_direction = v3f (0 , 0 , 0 );
297
+
298
+ // Allowed route area size in nodes
299
+ ar = node_max - node_min + v3s16 (1 , 1 , 1 );
300
+ // Area starting point in nodes
301
+ of = node_min;
302
+
303
+ // Allow a bit more
304
+ // (this should be more than the maximum radius of the tunnel)
305
+ s16 insure = 10 ;
306
+ s16 more = MAP_BLOCKSIZE - max_tunnel_diameter / 2 - insure;
307
+ ar += v3s16 (1 ,0 ,1 ) * more * 2 ;
308
+ of -= v3s16 (1 ,0 ,1 ) * more;
309
+
310
+ route_y_min = 0 ;
311
+ // Allow half a diameter + 7 over stone surface
312
+ route_y_max = -of.Y + max_stone_y + max_tunnel_diameter / 2 + 7 ;
313
+
314
+ // Limit maximum to area
315
+ route_y_max = rangelim (route_y_max, 0 , ar.Y - 1 );
316
+
317
+ if (large_cave) {
318
+ s16 min = 0 ;
319
+ if (node_min.Y < water_level && node_max.Y > water_level) {
320
+ min = water_level - max_tunnel_diameter/3 - of.Y ;
321
+ route_y_max = water_level + max_tunnel_diameter/3 - of.Y ;
322
+ }
323
+ route_y_min = ps->range (min, min + max_tunnel_diameter);
324
+ route_y_min = rangelim (route_y_min, 0 , route_y_max);
325
+ }
326
+
327
+ s16 route_start_y_min = route_y_min;
328
+ s16 route_start_y_max = route_y_max;
329
+
330
+ route_start_y_min = rangelim (route_start_y_min, 0 , ar.Y - 1 );
331
+ route_start_y_max = rangelim (route_start_y_max, route_start_y_min, ar.Y - 1 );
332
+
333
+ // Randomize starting position
334
+ orp = v3f (
335
+ (float )(ps->next () % ar.X ) + 0.5 ,
336
+ (float )(ps->range (route_start_y_min, route_start_y_max)) + 0.5 ,
337
+ (float )(ps->next () % ar.Z ) + 0.5
338
+ );
339
+
340
+ // Generate some tunnel starting from orp
341
+ for (u16 j = 0 ; j < tunnel_routepoints; j++)
342
+ makeTunnel (j % dswitchint == 0 );
343
+ }
344
+
345
+
346
+ void CaveV7::makeTunnel (bool dirswitch) {
347
+ if (dirswitch && !large_cave) {
348
+ main_direction = v3f (
349
+ ((float )(ps->next () % 20 ) - (float )10 ) / 10 ,
350
+ ((float )(ps->next () % 20 ) - (float )10 ) / 30 ,
351
+ ((float )(ps->next () % 20 ) - (float )10 ) / 10
352
+ );
353
+ main_direction *= (float )ps->range (0 , 10 ) / 10 ;
354
+ }
355
+
356
+ // Randomize size
357
+ s16 min_d = min_tunnel_diameter;
358
+ s16 max_d = max_tunnel_diameter;
359
+ rs = ps->range (min_d, max_d);
360
+
361
+ v3s16 maxlen;
362
+ if (large_cave) {
363
+ maxlen = v3s16 (
364
+ rs * part_max_length_rs,
365
+ rs * part_max_length_rs / 2 ,
366
+ rs * part_max_length_rs
367
+ );
368
+ } else {
369
+ maxlen = v3s16 (
370
+ rs * part_max_length_rs,
371
+ ps->range (1 , rs * part_max_length_rs),
372
+ rs * part_max_length_rs
373
+ );
374
+ }
375
+
376
+ v3f vec;
377
+ // Jump downward sometimes
378
+ if (!large_cave && ps->range (0 , 12 ) == 0 ) {
379
+ vec = v3f (
380
+ (float )(ps->next () % (maxlen.X * 1 )) - (float )maxlen.X / 2 ,
381
+ (float )(ps->next () % (maxlen.Y * 2 )) - (float )maxlen.Y ,
382
+ (float )(ps->next () % (maxlen.Z * 1 )) - (float )maxlen.Z / 2
383
+ );
384
+ } else {
385
+ vec = v3f (
386
+ (float )(ps->next () % (maxlen.X * 1 )) - (float )maxlen.X / 2 ,
387
+ (float )(ps->next () % (maxlen.Y * 1 )) - (float )maxlen.Y / 2 ,
388
+ (float )(ps->next () % (maxlen.Z * 1 )) - (float )maxlen.Z / 2
389
+ );
390
+ }
391
+
392
+ // Do not make large caves that are above ground.
393
+ // It is only necessary to check the startpoint and endpoint.
394
+ if (large_cave) {
395
+ v3s16 orpi (orp.X , orp.Y , orp.Z );
396
+ v3s16 veci (vec.X , vec.Y , vec.Z );
397
+ v3s16 p;
398
+
399
+ p = orpi + veci + of + rs / 2 ;
400
+ if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
401
+ p.X >= node_min.X && p.X <= node_max.X ) {
402
+ u32 index = (p.Z - node_min.Z ) * mg->ystride + (p.X - node_min.X );
403
+ s16 h = mg->ridge_heightmap [index ];
404
+ if (h < p.Y )
405
+ return ;
406
+ } else if (p.Y > water_level) {
407
+ return ; // If it's not in our heightmap, use a simple heuristic
408
+ }
409
+
410
+ p = orpi + of + rs / 2 ;
411
+ if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
412
+ p.X >= node_min.X && p.X <= node_max.X ) {
413
+ u32 index = (p.Z - node_min.Z ) * mg->ystride + (p.X - node_min.X );
414
+ s16 h = mg->ridge_heightmap [index ];
415
+ if (h < p.Y )
416
+ return ;
417
+ } else if (p.Y > water_level) {
418
+ return ;
419
+ }
420
+ }
421
+
422
+ vec += main_direction;
423
+
424
+ v3f rp = orp + vec;
425
+ if (rp.X < 0 )
426
+ rp.X = 0 ;
427
+ else if (rp.X >= ar.X )
428
+ rp.X = ar.X - 1 ;
429
+
430
+ if (rp.Y < route_y_min)
431
+ rp.Y = route_y_min;
432
+ else if (rp.Y >= route_y_max)
433
+ rp.Y = route_y_max - 1 ;
434
+
435
+ if (rp.Z < 0 )
436
+ rp.Z = 0 ;
437
+ else if (rp.Z >= ar.Z )
438
+ rp.Z = ar.Z - 1 ;
439
+
440
+ vec = rp - orp;
441
+
442
+ float veclen = vec.getLength ();
443
+ if (veclen < 0.05 )
444
+ veclen = 1.0 ;
445
+
446
+ // Every second section is rough
447
+ bool randomize_xz = (ps->range (1 , 2 ) == 1 );
448
+
449
+ // Make a ravine every once in a while if it's long enough
450
+ float xylen = vec.X * vec.X + vec.Z * vec.Z ;
451
+ bool is_ravine = (xylen > 500.0 ) && !large_cave && (ps->range (1 , 8 ) == 1 );
452
+
453
+ // Carve routes
454
+ for (float f = 0 ; f < 1.0 ; f += 1.0 / veclen)
455
+ carveRoute (vec, f, randomize_xz, is_ravine);
456
+
457
+ orp = rp;
458
+ }
459
+
460
+
461
+ void CaveV7::carveRoute (v3f vec, float f, bool randomize_xz, bool is_ravine) {
462
+ MapNode airnode (CONTENT_AIR);
463
+ MapNode waternode (c_water_source);
464
+ MapNode lavanode (c_lava_source);
465
+ MapNode liquidnode = ps->range (0 , 4 ) ? lavanode : waternode;
466
+
467
+ v3s16 startp (orp.X , orp.Y , orp.Z );
468
+ startp += of;
469
+
470
+ v3f fp = orp + vec * f;
471
+ fp.X += 0.1 * ps->range (-10 , 10 );
472
+ fp.Z += 0.1 * ps->range (-10 , 10 );
473
+ v3s16 cp (fp.X , fp.Y , fp.Z );
474
+
475
+ s16 d0 = -rs/2 ;
476
+ s16 d1 = d0 + rs;
477
+ if (randomize_xz) {
478
+ d0 += ps->range (-1 , 1 );
479
+ d1 += ps->range (-1 , 1 );
480
+ }
481
+
482
+ bool flat_cave_floor = !large_cave && ps->range (0 , 2 ) == 2 ;
483
+
484
+ for (s16 z0 = d0; z0 <= d1; z0++) {
485
+ s16 si = rs / 2 - MYMAX (0 , abs (z0) - rs / 7 - 1 );
486
+ for (s16 x0 = -si - ps->range (0 ,1 ); x0 <= si - 1 + ps->range (0 ,1 ); x0++) {
487
+ s16 maxabsxz = MYMAX (abs (x0), abs (z0));
488
+
489
+ s16 si2 = is_ravine ? MYMIN (ps->range (25 , 26 ), ar.Y ) :
490
+ rs / 2 - MYMAX (0 , maxabsxz - rs / 7 - 1 );
491
+
492
+ for (s16 y0 = -si2; y0 <= si2; y0 ++) {
493
+ // Make better floors in small caves
494
+ if (flat_cave_floor && y0 <= -rs/2 && rs<=7 )
495
+ continue ;
496
+
497
+ if (large_cave_is_flat) {
498
+ // Make large caves not so tall
499
+ if (rs > 7 && abs (y0 ) >= rs / 3 )
500
+ continue ;
501
+ }
502
+
503
+ v3s16 p (cp.X + x0, cp.Y + y0 , cp.Z + z0);
504
+ p += of;
505
+
506
+ if (vm->m_area .contains (p) == false )
507
+ continue ;
508
+
509
+ u32 i = vm->m_area .index (p);
510
+
511
+ // Don't replace air or water or lava
512
+ content_t c = vm->m_data [i].getContent ();
513
+ if (c == CONTENT_AIR || c == c_water_source || c == c_lava_source)
514
+ continue ;
515
+
516
+ if (large_cave) {
517
+ int full_ymin = node_min.Y - MAP_BLOCKSIZE;
518
+ int full_ymax = node_max.Y + MAP_BLOCKSIZE;
519
+
520
+ if (flooded && full_ymin < water_level && full_ymax > water_level)
521
+ vm->m_data [i] = (p.Y <= water_level) ? waternode : airnode;
522
+ else if (flooded && full_ymax < water_level)
523
+ vm->m_data [i] = (p.Y < startp.Y - 4 ) ? liquidnode : airnode;
524
+ else
525
+ vm->m_data [i] = airnode;
526
+ } else {
527
+ vm->m_data [i] = airnode;
528
+ vm->m_flags [i] |= VMANIP_FLAG_CAVE;
529
+ }
530
+ }
531
+ }
532
+ }
533
+ }
0 commit comments