@@ -29,6 +29,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
29
29
#include " settings.h" // For g_settings
30
30
#include " main.h" // For g_profiler
31
31
32
+ // #define DGEN_USE_TORCHES
33
+
32
34
NoiseParams nparams_dungeon_rarity =
33
35
{0.0 , 1.0 , v3f (500.0 , 500.0 , 500.0 ), 0 , 2 , 0.8 };
34
36
NoiseParams nparams_dungeon_wetness =
@@ -40,42 +42,49 @@ NoiseParams nparams_dungeon_density =
40
42
// /////////////////////////////////////////////////////////////////////////////
41
43
42
44
43
- DungeonGen::DungeonGen (INodeDefManager *ndef, u64 seed, s16 waterlevel) {
45
+ DungeonGen::DungeonGen (INodeDefManager *ndef, u64 seed, s16 waterlevel,
46
+ DungeonParams *dparams) {
44
47
this ->ndef = ndef;
45
48
this ->mapseed = seed;
46
49
this ->water_level = waterlevel;
50
+
51
+ #ifdef DGEN_USE_TORCHES
52
+ c_torch = ndef->getId (" default:torch" );
53
+ #endif
47
54
48
- np_rarity = &nparams_dungeon_rarity;
49
- np_wetness = &nparams_dungeon_wetness;
50
- np_density = &nparams_dungeon_density;
51
- /*
52
- cid_water_source = ndef->getId("mapgen_water_source");
53
- cid_cobble = ndef->getId("mapgen_cobble");
54
- cid_mossycobble = ndef->getId("mapgen_mossycobble");
55
- cid_torch = ndef->getId("default:torch");
56
- */
55
+ if (dparams) {
56
+ memcpy (&dp, dparams, sizeof (dp));
57
+ } else {
58
+ dp.c_water = ndef->getId (" mapgen_water_source" );
59
+ dp.c_cobble = ndef->getId (" mapgen_cobble" );
60
+ dp.c_moss = ndef->getId (" mapgen_mossycobble" );
61
+ dp.c_stair = ndef->getId (" mapgen_stair_cobble" );
62
+
63
+ dp.diagonal_dirs = false ;
64
+ dp.mossratio = 3.0 ;
65
+ dp.holesize = v3s16 (1 , 2 , 1 );
66
+ dp.roomsize = v3s16 (0 ,0 ,0 );
67
+
68
+ dp.np_rarity = nparams_dungeon_rarity;
69
+ dp.np_wetness = nparams_dungeon_wetness;
70
+ dp.np_density = nparams_dungeon_density;
71
+ }
57
72
}
58
73
59
74
60
75
void DungeonGen::generate (ManualMapVoxelManipulator *vm, u32 bseed,
61
- v3s16 nmin, v3s16 nmax) {
76
+ v3s16 nmin, v3s16 nmax) {
62
77
// TimeTaker t("gen dungeons");
63
78
int approx_groundlevel = 10 + water_level;
64
79
65
80
if ((nmin.Y + nmax.Y ) / 2 >= approx_groundlevel ||
66
- NoisePerlin3D (np_rarity, nmin.X , nmin.Y , nmin.Z , mapseed) < 0.2 )
81
+ NoisePerlin3D (&dp. np_rarity , nmin.X , nmin.Y , nmin.Z , mapseed) < 0.2 )
67
82
return ;
68
83
69
84
this ->vmanip = vm;
70
85
this ->blockseed = bseed;
71
86
random .seed (bseed + 2 );
72
87
73
- cid_water_source = ndef->getId (" mapgen_water_source" );
74
- cid_cobble = ndef->getId (" mapgen_cobble" );
75
- cid_mossycobble = ndef->getId (" mapgen_mossycobble" );
76
- // cid_torch = ndef->getId("default:torch");
77
- cid_cobblestair = ndef->getId (" mapgen_stair_cobble" );
78
-
79
88
// Dungeon generator doesn't modify places which have this set
80
89
vmanip->clearFlag (VMANIP_FLAG_DUNGEON_INSIDE | VMANIP_FLAG_DUNGEON_PRESERVE);
81
90
@@ -86,7 +95,7 @@ void DungeonGen::generate(ManualMapVoxelManipulator *vm, u32 bseed,
86
95
u32 i = vmanip->m_area .index (nmin.X , y, z);
87
96
for (s16 x = nmin.X ; x <= nmax.X ; x++) {
88
97
content_t c = vmanip->m_data [i].getContent ();
89
- if (c == CONTENT_AIR || c == cid_water_source )
98
+ if (c == CONTENT_AIR || c == dp. c_water )
90
99
vmanip->m_flags [i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
91
100
i++;
92
101
}
@@ -95,17 +104,18 @@ void DungeonGen::generate(ManualMapVoxelManipulator *vm, u32 bseed,
95
104
96
105
// Add it
97
106
makeDungeon (v3s16 (1 ,1 ,1 ) * MAP_BLOCKSIZE);
98
-
107
+
99
108
// Convert some cobble to mossy cobble
100
- for (s16 z = nmin.Z ; z <= nmax.Z ; z++) {
109
+ if (dp.mossratio != 0.0 ) {
110
+ for (s16 z = nmin.Z ; z <= nmax.Z ; z++)
101
111
for (s16 y = nmin.Y ; y <= nmax.Y ; y++) {
102
112
u32 i = vmanip->m_area .index (nmin.X , y, z);
103
113
for (s16 x = nmin.X ; x <= nmax.X ; x++) {
104
- if (vmanip->m_data [i].getContent () == cid_cobble ) {
105
- float wetness = NoisePerlin3D (np_wetness, x, y, z, mapseed);
106
- float density = NoisePerlin3D (np_density, x, y, z, blockseed);
107
- if (density < wetness / 3.0 )
108
- vmanip->m_data [i].setContent (cid_mossycobble );
114
+ if (vmanip->m_data [i].getContent () == dp. c_cobble ) {
115
+ float wetness = NoisePerlin3D (&dp. np_wetness , x, y, z, mapseed);
116
+ float density = NoisePerlin3D (&dp. np_density , x, y, z, blockseed);
117
+ if (density < wetness / dp. mossratio )
118
+ vmanip->m_data [i].setContent (dp. c_moss );
109
119
}
110
120
i++;
111
121
}
@@ -132,7 +142,8 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
132
142
roomsize = is_large_room ?
133
143
v3s16 (random .range (8 , 16 ),random .range (8 , 16 ),random .range (8 , 16 )) :
134
144
v3s16 (random .range (4 , 8 ),random .range (4 , 6 ),random .range (4 , 8 ));
135
-
145
+ roomsize += dp.roomsize ;
146
+
136
147
// start_padding is used to disallow starting the generation of
137
148
// a dungeon in a neighboring generation chunk
138
149
roomplace = vmanip->m_area .MinEdge + start_padding + v3s16 (
@@ -184,8 +195,10 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
184
195
185
196
v3s16 room_center = roomplace + v3s16 (roomsize.X / 2 , 1 , roomsize.Z / 2 );
186
197
198
+ #ifdef DGEN_USE_TORCHES
187
199
// Place torch at room center (for testing)
188
- // vmanip->m_data[vmanip->m_area.index(room_center)] = MapNode(cid_torch);
200
+ vmanip->m_data [vmanip->m_area .index (room_center)] = MapNode (c_torch);
201
+ #endif
189
202
190
203
// Quit if last room
191
204
if (i == room_count - 1 )
@@ -231,6 +244,8 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
231
244
232
245
// Find a place for a random sized room
233
246
roomsize = v3s16 (random .range (4 ,8 ),random .range (4 ,6 ),random .range (4 ,8 ));
247
+ roomsize += dp.roomsize ;
248
+
234
249
m_pos = corridor_end;
235
250
m_dir = corridor_end_dir;
236
251
r = findPlaceForRoomDoor (roomsize, doorplace, doordir, roomplace);
@@ -250,7 +265,7 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
250
265
251
266
void DungeonGen::makeRoom (v3s16 roomsize, v3s16 roomplace)
252
267
{
253
- MapNode n_cobble (cid_cobble );
268
+ MapNode n_cobble (dp. c_cobble );
254
269
MapNode n_air (CONTENT_AIR);
255
270
256
271
// Make +-X walls
@@ -361,16 +376,19 @@ void DungeonGen::makeFill(v3s16 place, v3s16 size,
361
376
362
377
void DungeonGen::makeHole (v3s16 place)
363
378
{
364
- makeFill (place, v3s16 ( 1 , 2 , 1 ), 0 , MapNode (CONTENT_AIR) ,
365
- VMANIP_FLAG_DUNGEON_INSIDE);
379
+ makeFill (place, dp. holesize , 0 ,
380
+ MapNode (CONTENT_AIR), VMANIP_FLAG_DUNGEON_INSIDE);
366
381
}
367
382
368
383
369
384
void DungeonGen::makeDoor (v3s16 doorplace, v3s16 doordir)
370
385
{
371
386
makeHole (doorplace);
387
+
388
+ #ifdef DGEN_USE_TORCHES
372
389
// Place torch (for testing)
373
- // vmanip->m_data[vmanip->m_area.index(doorplace)] = MapNode(cid_torch);
390
+ vmanip->m_data [vmanip->m_area .index (doorplace)] = MapNode (c_torch);
391
+ #endif
374
392
}
375
393
376
394
@@ -401,30 +419,32 @@ void DungeonGen::makeCorridor(v3s16 doorplace,
401
419
if (vmanip->m_area .contains (p) == true &&
402
420
vmanip->m_area .contains (p + v3s16 (0 , 1 , 0 )) == true ) {
403
421
if (make_stairs) {
404
- makeFill (p + v3s16 (-1 , -1 , -1 ), v3s16 (3 , 5 , 3 ),
405
- VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode (cid_cobble ), 0 );
422
+ makeFill (p + v3s16 (-1 , -1 , -1 ), dp. holesize + v3s16 (2 , 3 , 2 ),
423
+ VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode (dp. c_cobble ), 0 );
406
424
makeHole (p);
407
425
makeHole (p - dir);
408
426
409
427
// TODO: fix stairs code so it works 100% (quite difficult)
410
428
411
429
// exclude stairs from the bottom step
412
- if (((make_stairs == 1 ) && i != 0 ) ||
413
- ((make_stairs == -1 ) && i != length - 1 )) {
430
+ // exclude stairs from diagonal steps
431
+ if (((dir.X ^ dir.Z ) & 1 ) &&
432
+ (((make_stairs == 1 ) && i != 0 ) ||
433
+ ((make_stairs == -1 ) && i != length - 1 ))) {
414
434
// rotate face 180 deg if making stairs backwards
415
435
int facedir = dir_to_facedir (dir * make_stairs);
416
436
417
437
u32 vi = vmanip->m_area .index (p.X - dir.X , p.Y - 1 , p.Z - dir.Z );
418
- if (vmanip->m_data [vi].getContent () == cid_cobble )
419
- vmanip->m_data [vi] = MapNode (cid_cobblestair , 0 , facedir);
438
+ if (vmanip->m_data [vi].getContent () == dp. c_cobble )
439
+ vmanip->m_data [vi] = MapNode (dp. c_stair , 0 , facedir);
420
440
421
441
vi = vmanip->m_area .index (p.X , p.Y , p.Z );
422
- if (vmanip->m_data [vi].getContent () == cid_cobble )
423
- vmanip->m_data [vi] = MapNode (cid_cobblestair , 0 , facedir);
442
+ if (vmanip->m_data [vi].getContent () == dp. c_cobble )
443
+ vmanip->m_data [vi] = MapNode (dp. c_stair , 0 , facedir);
424
444
}
425
445
} else {
426
- makeFill (p + v3s16 (-1 , -1 , -1 ), v3s16 (3 , 4 , 3 ),
427
- VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode (cid_cobble ), 0 );
446
+ makeFill (p + v3s16 (-1 , -1 , -1 ), dp. holesize + v3s16 (2 , 2 , 2 ),
447
+ VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode (dp. c_cobble ), 0 );
428
448
makeHole (p);
429
449
}
430
450
@@ -469,8 +489,8 @@ bool DungeonGen::findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
469
489
randomizeDir ();
470
490
continue ;
471
491
}
472
- if (vmanip->getNodeNoExNoEmerge (p).getContent () == cid_cobble
473
- && vmanip->getNodeNoExNoEmerge (p1).getContent () == cid_cobble )
492
+ if (vmanip->getNodeNoExNoEmerge (p).getContent () == dp. c_cobble
493
+ && vmanip->getNodeNoExNoEmerge (p1).getContent () == dp. c_cobble )
474
494
{
475
495
// Found wall, this is a good place!
476
496
result_place = p;
@@ -483,12 +503,12 @@ bool DungeonGen::findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
483
503
Determine where to move next
484
504
*/
485
505
// Jump one up if the actual space is there
486
- if (vmanip->getNodeNoExNoEmerge (p+v3s16 (0 ,0 ,0 )).getContent () == cid_cobble
506
+ if (vmanip->getNodeNoExNoEmerge (p+v3s16 (0 ,0 ,0 )).getContent () == dp. c_cobble
487
507
&& vmanip->getNodeNoExNoEmerge (p+v3s16 (0 ,1 ,0 )).getContent () == CONTENT_AIR
488
508
&& vmanip->getNodeNoExNoEmerge (p+v3s16 (0 ,2 ,0 )).getContent () == CONTENT_AIR)
489
509
p += v3s16 (0 ,1 ,0 );
490
510
// Jump one down if the actual space is there
491
- if (vmanip->getNodeNoExNoEmerge (p+v3s16 (0 ,1 ,0 )).getContent () == cid_cobble
511
+ if (vmanip->getNodeNoExNoEmerge (p+v3s16 (0 ,1 ,0 )).getContent () == dp. c_cobble
492
512
&& vmanip->getNodeNoExNoEmerge (p+v3s16 (0 ,0 ,0 )).getContent () == CONTENT_AIR
493
513
&& vmanip->getNodeNoExNoEmerge (p+v3s16 (0 ,-1 ,0 )).getContent () == CONTENT_AIR)
494
514
p += v3s16 (0 ,-1 ,0 );
@@ -577,12 +597,25 @@ bool DungeonGen::findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
577
597
}
578
598
579
599
580
- v3s16 rand_ortho_dir (PseudoRandom &random)
600
+ v3s16 rand_ortho_dir (PseudoRandom &random, bool diagonal_dirs )
581
601
{
582
- if (random .next () % 2 == 0 )
583
- return random .next () % 2 ? v3s16 (-1 , 0 , 0 ) : v3s16 (1 , 0 , 0 );
584
- else
585
- return random .next () % 2 ? v3s16 (0 , 0 , -1 ) : v3s16 (0 , 0 , 1 );
602
+ // Make diagonal directions somewhat rare
603
+ if (diagonal_dirs && (random .next () % 4 == 0 )) {
604
+ v3s16 dir;
605
+ int trycount = 0 ;
606
+
607
+ do {
608
+ trycount++;
609
+ dir = v3s16 (random .next () % 3 - 1 , 0 , random .next () % 3 - 1 );
610
+ } while ((dir.X == 0 && dir.Z == 0 ) && trycount < 10 );
611
+
612
+ return dir;
613
+ } else {
614
+ if (random .next () % 2 == 0 )
615
+ return random .next () % 2 ? v3s16 (-1 , 0 , 0 ) : v3s16 (1 , 0 , 0 );
616
+ else
617
+ return random .next () % 2 ? v3s16 (0 , 0 , -1 ) : v3s16 (0 , 0 , 1 );
618
+ }
586
619
}
587
620
588
621
0 commit comments