Cuberite
A lightweight, fast and extensible game server for Minecraft
MineShafts.cpp
Go to the documentation of this file.
1 
2 // MineShafts.cpp
3 
4 // Implements the cStructGenMineShafts class representing the structure generator for abandoned mineshafts
5 
6 /*
7 Algorithm:
8 The cStructGenMineShafts::cMineShaftSystem class is the main controller, which knows what mineshaft
9 classes there are and their random weights. It gets asked to produce a new class everytime a connection is to be made.
10 The cMineShaft class is a base class for each mineshaft structure.
11 Each cMineShaft descendant knows how large it is, how to imprint itself into the chunk data and where to connect to
12 other descendants. Its PivotPoint is always a walkable column. Its Direction determines in which direction the structure
13 is facing.
14 
15 The generation starts with the central dirt room, from there corridors, crossings and staircases are added
16 in a depth-first processing. Each of the descendants will branch randomly, if not beyond the allowed recursion level
17 */
18 
19 #include "Globals.h"
20 #include "MineShafts.h"
21 #include "../Cuboid.h"
22 #include "../BlockEntities/ChestEntity.h"
23 #include "../BlockEntities/MobSpawnerEntity.h"
24 
25 
26 
27 
28 
29 class cMineShaft abstract
30 {
31 public:
32  enum eKind
33  {
34  mskDirtRoom,
35  mskCorridor,
36  mskCrossing,
37  mskStaircase,
38  } ;
39 
40 
41  enum eDirection
42  {
43  dirXP,
44  dirZP,
45  dirXM,
46  dirZM,
47  } ;
48 
49 
51  eKind m_Kind;
52  cCuboid m_BoundingBox;
53 
54 
55  cMineShaft(cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, eKind a_Kind) :
56  m_ParentSystem(a_ParentSystem),
57  m_Kind(a_Kind)
58  {
59  }
60 
61  cMineShaft(cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, eKind a_Kind, const cCuboid & a_BoundingBox) :
62  m_ParentSystem(a_ParentSystem),
63  m_Kind(a_Kind),
64  m_BoundingBox(a_BoundingBox)
65  {
66  }
67 
68  virtual ~cMineShaft() {}
69 
71  bool DoesIntersect(const cCuboid & a_Other)
72  {
73  return m_BoundingBox.DoesIntersect(a_Other);
74  }
75 
78  virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) = 0;
79 
81  virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) = 0;
82 } ;
83 
84 using cMineShafts = std::vector<cMineShaft *>;
85 
86 
87 
88 
89 
91  public cMineShaft
92 {
93  using Super = cMineShaft;
94 
95 public:
96 
98 
99  // cMineShaft overrides:
100  virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) override;
101  virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) override;
102 } ;
103 
104 
105 
106 
107 
109  public cMineShaft
110 {
111  using Super = cMineShaft;
112 
113 public:
114 
118  static cMineShaft * CreateAndFit(
120  int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction,
121  cNoise & a_Noise
122  );
123 
124 protected:
125  static const int MAX_SEGMENTS = 5;
126 
128  eDirection m_Direction;
132  bool m_HasTracks;
133 
136  const cCuboid & a_BoundingBox, int a_NumSegments, eDirection a_Direction,
137  cNoise & a_Noise
138  );
139 
140  // cMineShaft overrides:
141  virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) override;
142  virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) override;
143 
145  void PlaceChest(cChunkDesc & a_ChunkDesc);
146 
148  void PlaceTracks(cChunkDesc & a_ChunkDesc);
149 
151  void PlaceSpawner(cChunkDesc & a_ChunkDesc);
152 
154  void PlaceTorches(cChunkDesc & a_ChunkDesc);
155 } ;
156 
157 
158 
159 
160 
162  public cMineShaft
163 {
164  using Super = cMineShaft;
165 
166 public:
167 
171  static cMineShaft * CreateAndFit(
173  int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction,
174  cNoise & a_Noise
175  );
176 
177 protected:
178  cMineShaftCrossing(cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, const cCuboid & a_BoundingBox);
179 
180  // cMineShaft overrides:
181  virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) override;
182  virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) override;
183 } ;
184 
185 
186 
187 
188 
190  public cMineShaft
191 {
192  using Super = cMineShaft;
193 
194 public:
195 
196  enum eSlope
197  {
200  } ;
201 
206  static cMineShaft * CreateAndFit(
208  int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction,
209  cNoise & a_Noise
210  );
211 
212 protected:
213  eDirection m_Direction;
215 
216 
219  const cCuboid & a_BoundingBox,
220  eDirection a_Direction,
221  eSlope a_Slope
222  );
223 
224  // cMineShaft overrides:
225  virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) override;
226  virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) override;
227 } ;
228 
229 
230 
231 
232 
235 {
237 
238 public:
239 
250 
251 
254  int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ,
255  int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise,
256  int a_ProbLevelCorridor, int a_ProbLevelCrossing, int a_ProbLevelStaircase
257  );
258 
259  virtual ~cMineShaftSystem() override;
260 
264  void AppendBranch(
265  int a_BlockX, int a_BlockY, int a_BlockZ,
266  cMineShaft::eDirection a_Direction, cNoise & a_Noise,
267  int a_RecursionLevel
268  );
269 
271  bool CanAppend(const cCuboid & a_BoundingBox);
272 
273  // cGridStructGen::cStructure overrides:
274  virtual void DrawIntoChunk(cChunkDesc & a_Chunk) override;
275 } ;
276 
277 
278 
279 
280 
282 // cStructGenMineShafts::cMineShaftSystem:
283 
285  int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ,
286  int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise,
287  int a_ProbLevelCorridor, int a_ProbLevelCrossing, int a_ProbLevelStaircase
288 ) :
289  Super(a_GridX, a_GridZ, a_OriginX, a_OriginZ),
290  m_GridSize(a_GridSize),
291  m_MaxRecursion(8), // TODO: settable
292  m_ProbLevelCorridor(a_ProbLevelCorridor),
293  m_ProbLevelCrossing(a_ProbLevelCrossing),
294  m_ProbLevelStaircase(a_ProbLevelStaircase + 1),
295  m_ChanceChest(12), // TODO: settable
296  m_ChanceSpawner(12), // TODO: settable
297  m_ChanceTorch(1000) // TODO: settable
298 {
299  m_MineShafts.reserve(100);
300 
301  cMineShaft * Start = new cMineShaftDirtRoom(*this, a_Noise);
302  m_MineShafts.push_back(Start);
303 
305  {Start->m_BoundingBox.p1.x - a_MaxSystemSize / 2, 2, Start->m_BoundingBox.p1.z - a_MaxSystemSize / 2},
306  {Start->m_BoundingBox.p2.x + a_MaxSystemSize / 2, 50, Start->m_BoundingBox.p2.z + a_MaxSystemSize / 2}
307  );
308 
309  Start->AppendBranches(0, a_Noise);
310 
311  for (cMineShafts::const_iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr)
312  {
313  ASSERT((*itr)->m_BoundingBox.IsSorted());
314  } // for itr - m_MineShafts[]
315 }
316 
317 
318 
319 
320 
322 {
323  for (cMineShafts::iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr)
324  {
325  delete *itr;
326  } // for itr - m_MineShafts[]
327  m_MineShafts.clear();
328 }
329 
330 
331 
332 
333 
335 {
336  for (cMineShafts::const_iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr)
337  {
338  (*itr)->ProcessChunk(a_Chunk);
339  } // for itr - m_MineShafts[]
340 }
341 
342 
343 
344 
345 
347  int a_PivotX, int a_PivotY, int a_PivotZ,
348  cMineShaft::eDirection a_Direction, cNoise & a_Noise,
349  int a_RecursionLevel
350 )
351 {
352  if (a_RecursionLevel > m_MaxRecursion)
353  {
354  return;
355  }
356 
357  cMineShaft * Next = nullptr;
358  int rnd = (a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_RecursionLevel * 16, a_PivotZ) / 13) % m_ProbLevelStaircase;
359  if (rnd < m_ProbLevelCorridor)
360  {
361  Next = cMineShaftCorridor::CreateAndFit(*this, a_PivotX, a_PivotY, a_PivotZ, a_Direction, a_Noise);
362  }
363  else if (rnd < m_ProbLevelCrossing)
364  {
365  Next = cMineShaftCrossing::CreateAndFit(*this, a_PivotX, a_PivotY, a_PivotZ, a_Direction, a_Noise);
366  }
367  else
368  {
369  Next = cMineShaftStaircase::CreateAndFit(*this, a_PivotX, a_PivotY, a_PivotZ, a_Direction, a_Noise);
370  }
371  if (Next == nullptr)
372  {
373  return;
374  }
375  m_MineShafts.push_back(Next);
376  Next->AppendBranches(a_RecursionLevel + 1, a_Noise);
377 }
378 
379 
380 
381 
382 
384 {
385  if (!a_BoundingBox.IsCompletelyInside(m_BoundingBox))
386  {
387  // Too far away, or too low / too high
388  return false;
389  }
390 
391  // Check intersections:
392  for (cMineShafts::const_iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr)
393  {
394  if ((*itr)->DoesIntersect(a_BoundingBox))
395  {
396  return false;
397  }
398  } // for itr - m_MineShafts[]
399  return true;
400 }
401 
402 
403 
404 
405 
407 // cMineShaftDirtRoom:
408 
410  Super(a_Parent, mskDirtRoom)
411 {
412  // Make the room of random size, min 10 x 4 x 10; max 18 x 12 x 18:
413  int rnd = a_Noise.IntNoise3DInt(a_Parent.m_OriginX, 0, a_Parent.m_OriginZ) / 7;
414  int OfsX = (rnd % a_Parent.m_GridSize) - a_Parent.m_GridSize / 2;
415  rnd >>= 12;
416  int OfsZ = (rnd % a_Parent.m_GridSize) - a_Parent.m_GridSize / 2;
417  rnd = a_Noise.IntNoise3DInt(a_Parent.m_OriginX, 1000, a_Parent.m_OriginZ) / 11;
418  m_BoundingBox.p1.x = a_Parent.m_OriginX + OfsX;
419  m_BoundingBox.p2.x = m_BoundingBox.p1.x + 10 + (rnd % 8);
420  rnd >>= 4;
421  m_BoundingBox.p1.z = a_Parent.m_OriginZ + OfsZ;
422  m_BoundingBox.p2.z = m_BoundingBox.p1.z + 10 + (rnd % 8);
423  rnd >>= 4;
424  m_BoundingBox.p1.y = 20;
425  m_BoundingBox.p2.y = 24 + rnd % 8;
426 }
427 
428 
429 
430 
431 
432 void cMineShaftDirtRoom::AppendBranches(int a_RecursionLevel, cNoise & a_Noise)
433 {
434  int Height = m_BoundingBox.DifY() - 3;
435  for (int x = m_BoundingBox.p1.x + 1; x < m_BoundingBox.p2.x; x += 4)
436  {
437  int rnd = a_Noise.IntNoise3DInt(x, a_RecursionLevel, m_BoundingBox.p1.z) / 7;
438  m_ParentSystem.AppendBranch(x, m_BoundingBox.p1.y + (rnd % Height), m_BoundingBox.p1.z - 1, dirZM, a_Noise, a_RecursionLevel);
439  rnd >>= 4;
440  m_ParentSystem.AppendBranch(x, m_BoundingBox.p1.y + (rnd % Height), m_BoundingBox.p2.z + 1, dirZP, a_Noise, a_RecursionLevel);
441  }
442 
443  for (int z = m_BoundingBox.p1.z + 1; z < m_BoundingBox.p2.z; z += 4)
444  {
445  int rnd = a_Noise.IntNoise3DInt(m_BoundingBox.p1.x, a_RecursionLevel, z) / 13;
446  m_ParentSystem.AppendBranch(m_BoundingBox.p1.x - 1, m_BoundingBox.p1.y + (rnd % Height), z, dirXM, a_Noise, a_RecursionLevel);
447  rnd >>= 4;
448  m_ParentSystem.AppendBranch(m_BoundingBox.p2.x + 1, m_BoundingBox.p1.y + (rnd % Height), z, dirXP, a_Noise, a_RecursionLevel);
449  }
450 }
451 
452 
453 
454 
455 
457 {
458  int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
459  int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
460  if (
461  (m_BoundingBox.p1.x > BlockX + cChunkDef::Width) ||
462  (m_BoundingBox.p1.z > BlockZ + cChunkDef::Width) ||
463  (m_BoundingBox.p2.x < BlockX) ||
464  (m_BoundingBox.p2.z < BlockZ)
465  )
466  {
467  // Early bailout - cannot intersect this chunk
468  return;
469  }
470 
471  // Chunk-relative coords of the boundaries:
472  int MinX = std::max(BlockX, m_BoundingBox.p1.x) - BlockX;
473  int MaxX = std::min(BlockX + cChunkDef::Width, m_BoundingBox.p2.x + 1) - BlockX;
474  int MinZ = std::max(BlockZ, m_BoundingBox.p1.z) - BlockZ;
475  int MaxZ = std::min(BlockZ + cChunkDef::Width, m_BoundingBox.p2.z + 1) - BlockZ;
476 
477  // Carve the room out:
478  for (int z = MinZ; z < MaxZ; z++)
479  {
480  for (int x = MinX; x < MaxX; x++)
481  {
482  for (int y = m_BoundingBox.p1.y + 1; y < m_BoundingBox.p2.y; y++)
483  {
484  a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_AIR);
485  }
486  if (a_ChunkDesc.GetBlockType(x, m_BoundingBox.p1.y, z) != E_BLOCK_AIR)
487  {
488  a_ChunkDesc.SetBlockType(x, m_BoundingBox.p1.y, z, E_BLOCK_DIRT);
489  }
490  } // for x
491  } // for z
492 }
493 
494 
495 
496 
497 
499 // cMineShaftCorridor:
500 
503  const cCuboid & a_BoundingBox, int a_NumSegments, eDirection a_Direction,
504  cNoise & a_Noise
505 ) :
506  Super(a_ParentSystem, mskCorridor, a_BoundingBox),
507  m_NumSegments(a_NumSegments),
508  m_Direction(a_Direction),
509  m_ChestPosition(-1),
510  m_SpawnerPosition(-1)
511 {
512  int rnd = a_Noise.IntNoise3DInt(a_BoundingBox.p1.x, a_BoundingBox.p1.y, a_BoundingBox.p1.z) / 7;
513  for (int i = 0; i < a_NumSegments; i++)
514  {
515  m_HasFullBeam[i] = (rnd % 4) < 3; // 75 % chance of full beam
516  rnd >>= 2;
517  }
518  m_HasTracks = ((rnd % 4) < 2); // 50 % chance of tracks
519 
520  rnd = a_Noise.IntNoise3DInt(a_BoundingBox.p1.z, a_BoundingBox.p1.x, a_BoundingBox.p1.y) / 7;
521  int ChestCheck = rnd % 250;
522  rnd >>= 8;
523  int SpawnerCheck = rnd % 250;
524  rnd >>= 8;
525  if (ChestCheck < a_ParentSystem.m_ChanceChest)
526  {
527  m_ChestPosition = rnd % (a_NumSegments * 5);
528  }
529  if ((a_NumSegments < 4) && (SpawnerCheck < a_ParentSystem.m_ChanceSpawner))
530  {
531  m_SpawnerPosition = rnd % (a_NumSegments * 5);
532  }
533 }
534 
535 
536 
537 
538 
541  int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction,
542  cNoise & a_Noise
543 )
544 {
545  cCuboid BoundingBox(a_PivotX, a_PivotY - 1, a_PivotZ);
546  BoundingBox.p2.y += 3;
547  int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + static_cast<int>(a_ParentSystem.m_MineShafts.size()), a_PivotZ) / 7;
548  int NumSegments = 2 + (rnd) % (MAX_SEGMENTS - 1); // 2 .. MAX_SEGMENTS
549  switch (a_Direction)
550  {
551  case dirXP: BoundingBox.p2.x += NumSegments * 5 - 1; BoundingBox.p1.z -= 1; BoundingBox.p2.z += 1; break;
552  case dirXM: BoundingBox.p1.x -= NumSegments * 5 - 1; BoundingBox.p1.z -= 1; BoundingBox.p2.z += 1; break;
553  case dirZP: BoundingBox.p2.z += NumSegments * 5 - 1; BoundingBox.p1.x -= 1; BoundingBox.p2.x += 1; break;
554  case dirZM: BoundingBox.p1.z -= NumSegments * 5 - 1; BoundingBox.p1.x -= 1; BoundingBox.p2.x += 1; break;
555  }
556  if (!a_ParentSystem.CanAppend(BoundingBox))
557  {
558  return nullptr;
559  }
560  return new cMineShaftCorridor(a_ParentSystem, BoundingBox, NumSegments, a_Direction, a_Noise);
561 }
562 
563 
564 
565 
566 
567 void cMineShaftCorridor::AppendBranches(int a_RecursionLevel, cNoise & a_Noise)
568 {
569  int Outerrnd = a_Noise.IntNoise3DInt(m_BoundingBox.p1.x, m_BoundingBox.p1.y + a_RecursionLevel, m_BoundingBox.p1.z) / 7;
570  // Prefer the same height, but allow for up to one block height displacement:
571  int OuterHeight = m_BoundingBox.p1.y + ((Outerrnd % 4) + ((Outerrnd >> 3) % 3)) / 2;
572  switch (m_Direction)
573  {
574  case dirXM:
575  {
576  m_ParentSystem.AppendBranch(m_BoundingBox.p1.x - 1, OuterHeight, m_BoundingBox.p1.z + 1, dirXM, a_Noise, a_RecursionLevel);
577  for (int i = m_NumSegments; i >= 0; i--)
578  {
579  int rnd = a_Noise.IntNoise3DInt(m_BoundingBox.p1.x + i + 10, m_BoundingBox.p1.y + a_RecursionLevel, m_BoundingBox.p1.z) / 11;
580  int Height = m_BoundingBox.p1.y + ((rnd % 4) + ((rnd >> 3) % 3)) / 2;
581  rnd >>= 6;
582  int Ofs = 1 + rnd % (m_NumSegments * 5 - 2);
583  m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + Ofs, Height, m_BoundingBox.p1.z - 1, dirZM, a_Noise, a_RecursionLevel);
584  m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + Ofs, Height, m_BoundingBox.p2.z + 1, dirZP, a_Noise, a_RecursionLevel);
585  }
586  break;
587  }
588 
589  case dirXP:
590  {
591  m_ParentSystem.AppendBranch(m_BoundingBox.p2.x + 1, OuterHeight, m_BoundingBox.p1.z + 1, dirXP, a_Noise, a_RecursionLevel);
592  for (int i = m_NumSegments; i >= 0; i--)
593  {
594  int rnd = a_Noise.IntNoise3DInt(m_BoundingBox.p1.x + i + 10, m_BoundingBox.p1.y + a_RecursionLevel, m_BoundingBox.p1.z) / 11;
595  int Height = m_BoundingBox.p1.y + ((rnd % 4) + ((rnd >> 3) % 3)) / 2;
596  rnd >>= 6;
597  int Ofs = 1 + rnd % (m_NumSegments * 5 - 2);
598  m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + Ofs, Height, m_BoundingBox.p1.z - 1, dirZM, a_Noise, a_RecursionLevel);
599  m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + Ofs, Height, m_BoundingBox.p2.z + 1, dirZP, a_Noise, a_RecursionLevel);
600  }
601  break;
602  }
603 
604  case dirZM:
605  {
606  m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + 1, OuterHeight, m_BoundingBox.p1.z - 1, dirZM, a_Noise, a_RecursionLevel);
607  for (int i = m_NumSegments; i >= 0; i--)
608  {
609  int rnd = a_Noise.IntNoise3DInt(m_BoundingBox.p1.x + i + 10, m_BoundingBox.p1.y + a_RecursionLevel, m_BoundingBox.p1.z) / 11;
610  int Height = m_BoundingBox.p1.y + ((rnd % 4) + ((rnd >> 3) % 3)) / 2;
611  rnd >>= 6;
612  int Ofs = 1 + rnd % (m_NumSegments * 5 - 2);
613  m_ParentSystem.AppendBranch(m_BoundingBox.p1.x - 1, Height, m_BoundingBox.p1.z + Ofs, dirXM, a_Noise, a_RecursionLevel);
614  m_ParentSystem.AppendBranch(m_BoundingBox.p2.x + 1, Height, m_BoundingBox.p1.z + Ofs, dirXP, a_Noise, a_RecursionLevel);
615  }
616  break;
617  }
618 
619  case dirZP:
620  {
621  m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + 1, OuterHeight, m_BoundingBox.p2.z + 1, dirZP, a_Noise, a_RecursionLevel);
622  for (int i = m_NumSegments; i >= 0; i--)
623  {
624  int rnd = a_Noise.IntNoise3DInt(m_BoundingBox.p1.x + i + 10, m_BoundingBox.p1.y + a_RecursionLevel, m_BoundingBox.p1.z) / 11;
625  int Height = m_BoundingBox.p1.y + ((rnd % 4) + ((rnd >> 3) % 3)) / 2;
626  rnd >>= 6;
627  int Ofs = 1 + rnd % (m_NumSegments * 5 - 2);
628  m_ParentSystem.AppendBranch(m_BoundingBox.p1.x - 1, Height, m_BoundingBox.p1.z + Ofs, dirXM, a_Noise, a_RecursionLevel);
629  m_ParentSystem.AppendBranch(m_BoundingBox.p2.x + 1, Height, m_BoundingBox.p1.z + Ofs, dirXP, a_Noise, a_RecursionLevel);
630  }
631  break;
632  }
633  } // switch (m_Direction)
634 }
635 
636 
637 
638 
639 
641 {
642  int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
643  int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
644  cCuboid RelBoundingBox(m_BoundingBox);
645  RelBoundingBox.Move({-BlockX, 0, -BlockZ});
646  RelBoundingBox.p1.y += 1;
647  RelBoundingBox.p2.y -= 1;
648  cCuboid Top(RelBoundingBox);
649  Top.p2.y += 1;
650  Top.p1.y = Top.p2.y;
651  a_ChunkDesc.FillRelCuboid(RelBoundingBox, E_BLOCK_AIR, 0);
652  a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_AIR, 0, (BlockX ^ (BlockZ + BlockX)), 8000);
653  if (m_SpawnerPosition >= 0)
654  {
655  // Cobwebs around the spider spawner
656  a_ChunkDesc.RandomFillRelCuboid(RelBoundingBox, E_BLOCK_COBWEB, 0, (BlockX ^ (BlockZ + BlockZ)), 8000);
657  a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_COBWEB, 0, (BlockX ^ (BlockZ + BlockX)), 5000);
658  }
659  a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_COBWEB, 0, (BlockX ^ (BlockZ + BlockX + 10)), 500);
660  RelBoundingBox.p1.y = m_BoundingBox.p1.y;
661  RelBoundingBox.p2.y = m_BoundingBox.p1.y;
662  a_ChunkDesc.FloorRelCuboid(RelBoundingBox, E_BLOCK_PLANKS, 0);
663  switch (m_Direction)
664  {
665  case dirXM:
666  case dirXP:
667  {
668  int y1 = m_BoundingBox.p1.y + 1;
669  int y2 = m_BoundingBox.p1.y + 2;
670  int y3 = m_BoundingBox.p1.y + 3;
671  int z1 = m_BoundingBox.p1.z - BlockZ;
672  int z2 = m_BoundingBox.p2.z - BlockZ;
673  for (int i = 0; i < m_NumSegments; i++)
674  {
675  int x = m_BoundingBox.p1.x + i * 5 + 2 - BlockX;
676  if ((x < 0) || (x >= cChunkDef::Width))
677  {
678  continue;
679  }
680  if ((z1 >= 0) && (z1 < cChunkDef::Width))
681  {
682  a_ChunkDesc.SetBlockTypeMeta(x, y1, z1, E_BLOCK_FENCE, 0);
683  a_ChunkDesc.SetBlockTypeMeta(x, y2, z1, E_BLOCK_FENCE, 0);
684  a_ChunkDesc.SetBlockTypeMeta(x, y3, z1, E_BLOCK_PLANKS, 0);
685  }
686  if ((z2 >= 0) && (z2 < cChunkDef::Width))
687  {
688  a_ChunkDesc.SetBlockTypeMeta(x, y1, z2, E_BLOCK_FENCE, 0);
689  a_ChunkDesc.SetBlockTypeMeta(x, y2, z2, E_BLOCK_FENCE, 0);
690  a_ChunkDesc.SetBlockTypeMeta(x, y3, z2, E_BLOCK_PLANKS, 0);
691  }
692  if ((z1 >= -1) && (z1 < cChunkDef::Width - 1) && m_HasFullBeam[i])
693  {
694  a_ChunkDesc.SetBlockTypeMeta(x, y3, z1 + 1, E_BLOCK_PLANKS, 0);
695  }
696  } // for i - NumSegments
697  break;
698  }
699 
700  case dirZM:
701  case dirZP:
702  {
703  int y1 = m_BoundingBox.p1.y + 1;
704  int y2 = m_BoundingBox.p1.y + 2;
705  int y3 = m_BoundingBox.p1.y + 3;
706  int x1 = m_BoundingBox.p1.x - BlockX;
707  int x2 = m_BoundingBox.p2.x - BlockX;
708  for (int i = 0; i < m_NumSegments; i++)
709  {
710  int z = m_BoundingBox.p1.z + i * 5 + 2 - BlockZ;
711  if ((z < 0) || (z >= cChunkDef::Width))
712  {
713  continue;
714  }
715  if ((x1 >= 0) && (x1 < cChunkDef::Width))
716  {
717  a_ChunkDesc.SetBlockTypeMeta(x1, y1, z, E_BLOCK_FENCE, 0);
718  a_ChunkDesc.SetBlockTypeMeta(x1, y2, z, E_BLOCK_FENCE, 0);
719  a_ChunkDesc.SetBlockTypeMeta(x1, y3, z, E_BLOCK_PLANKS, 0);
720  }
721  if ((x2 >= 0) && (x2 < cChunkDef::Width))
722  {
723  a_ChunkDesc.SetBlockTypeMeta(x2, y1, z, E_BLOCK_FENCE, 0);
724  a_ChunkDesc.SetBlockTypeMeta(x2, y2, z, E_BLOCK_FENCE, 0);
725  a_ChunkDesc.SetBlockTypeMeta(x2, y3, z, E_BLOCK_PLANKS, 0);
726  }
727  if ((x1 >= -1) && (x1 < cChunkDef::Width - 1) && m_HasFullBeam[i])
728  {
729  a_ChunkDesc.SetBlockTypeMeta(x1 + 1, y3, z, E_BLOCK_PLANKS, 0);
730  }
731  } // for i - NumSegments
732  break;
733  } // case dirZ?
734  } // for i
735 
736  PlaceChest(a_ChunkDesc);
737  PlaceTracks(a_ChunkDesc);
738  PlaceSpawner(a_ChunkDesc); // (must be after Tracks!)
739  PlaceTorches(a_ChunkDesc);
740 }
741 
742 
743 
744 
745 
747 {
748  static const cLootProbab LootProbab[] =
749  {
750  // Item, MinAmount, MaxAmount, Weight
751  { cItem(E_ITEM_IRON), 1, 5, 10 },
752  { cItem(E_ITEM_GOLD), 1, 3, 5 },
753  { cItem(E_ITEM_REDSTONE_DUST), 4, 9, 5 },
754  { cItem(E_ITEM_DIAMOND), 1, 2, 3 },
755  { cItem(E_ITEM_DYE, 1, 4), 4, 9, 5 }, // lapis lazuli dye
756  { cItem(E_ITEM_COAL), 3, 8, 10 },
757  { cItem(E_ITEM_BREAD), 1, 3, 15 },
758  { cItem(E_ITEM_IRON_PICKAXE), 1, 1, 1 },
759  { cItem(E_BLOCK_MINECART_TRACKS), 4, 8, 1 },
760  { cItem(E_ITEM_MELON_SEEDS), 2, 4, 10 },
761  { cItem(E_ITEM_PUMPKIN_SEEDS), 2, 4, 10 },
762  } ;
763 
764  if (m_ChestPosition < 0)
765  {
766  return;
767  }
768 
769  int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
770  int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
771  int x, z;
772  NIBBLETYPE Meta = 0;
773  [&]
774  {
775  switch (m_Direction)
776  {
777  case dirXM:
778  case dirXP:
779  {
780  x = m_BoundingBox.p1.x + m_ChestPosition - BlockX;
781  z = m_BoundingBox.p1.z - BlockZ;
782  Meta = E_META_CHEST_FACING_ZP;
783  return;
784  }
785 
786  case dirZM:
787  case dirZP:
788  {
789  x = m_BoundingBox.p1.x - BlockX;
790  z = m_BoundingBox.p1.z + m_ChestPosition - BlockZ;
791  Meta = E_META_CHEST_FACING_XP;
792  return;
793  }
794  } // switch (Dir)
795  UNREACHABLE("Unsupported corridor direction");
796  }();
797 
798  if (
799  (x >= 0) && (x < cChunkDef::Width) &&
800  (z >= 0) && (z < cChunkDef::Width)
801  )
802  {
803  a_ChunkDesc.SetBlockTypeMeta(x, m_BoundingBox.p1.y + 1, z, E_BLOCK_CHEST, Meta);
804  cChestEntity * ChestEntity = static_cast<cChestEntity *>(a_ChunkDesc.GetBlockEntity(x, m_BoundingBox.p1.y + 1, z));
805  ASSERT((ChestEntity != nullptr) && (ChestEntity->GetBlockType() == E_BLOCK_CHEST));
806  cNoise Noise(a_ChunkDesc.GetChunkX() ^ a_ChunkDesc.GetChunkZ());
807  int NumSlots = 3 + ((Noise.IntNoise3DInt(x, m_BoundingBox.p1.y, z) / 11) % 4);
808  int Seed = Noise.IntNoise2DInt(x, z);
809  ChestEntity->GetContents().GenerateRandomLootWithBooks(LootProbab, ARRAYCOUNT(LootProbab), NumSlots, Seed);
810  }
811 }
812 
813 
814 
815 
816 
818 {
819  if (!m_HasTracks)
820  {
821  return;
822  }
823  cCuboid Box(m_BoundingBox);
824  Box.Move({-a_ChunkDesc.GetChunkX() * cChunkDef::Width, 1, -a_ChunkDesc.GetChunkZ() * cChunkDef::Width});
825  Box.p2.y = Box.p1.y;
826  Box.p1.x += 1;
827  Box.p2.x -= 1;
828  Box.p1.z += 1;
829  Box.p2.z -= 1;
830  NIBBLETYPE Meta = 0;
831  switch (m_Direction)
832  {
833  case dirXM:
834  case dirXP:
835  {
836  Meta = E_META_TRACKS_X;
837  break;
838  }
839 
840  case dirZM:
841  case dirZP:
842  {
843  Meta = E_META_TRACKS_Z;
844  break;
845  }
846  } // switch (direction)
847  a_ChunkDesc.RandomFillRelCuboid(Box, E_BLOCK_MINECART_TRACKS, Meta, a_ChunkDesc.GetChunkX() + a_ChunkDesc.GetChunkZ(), 6000);
848 }
849 
850 
851 
852 
853 
855 {
856  if (m_SpawnerPosition < 0)
857  {
858  // No spawner in this corridor
859  return;
860  }
861  int SpawnerRelX = m_BoundingBox.p1.x + 1 - a_ChunkDesc.GetChunkX() * cChunkDef::Width;
862  int SpawnerRelZ = m_BoundingBox.p1.z + 1 - a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
863  switch (m_Direction)
864  {
865  case dirXM:
866  case dirXP:
867  {
868  SpawnerRelX += m_SpawnerPosition - 1;
869  break;
870  }
871  case dirZM:
872  case dirZP:
873  {
874  SpawnerRelZ += m_SpawnerPosition - 1;
875  break;
876  }
877  }
878  if (
879  (SpawnerRelX >= 0) && (SpawnerRelX < cChunkDef::Width) &&
880  (SpawnerRelZ >= 0) && (SpawnerRelZ < cChunkDef::Width)
881  )
882  {
883  a_ChunkDesc.SetBlockTypeMeta(SpawnerRelX, m_BoundingBox.p1.y + 1, SpawnerRelZ, E_BLOCK_MOB_SPAWNER, 0);
884  cMobSpawnerEntity * MobSpawner = static_cast<cMobSpawnerEntity *>(a_ChunkDesc.GetBlockEntity(SpawnerRelX, m_BoundingBox.p1.y + 1, SpawnerRelZ));
885  ASSERT((MobSpawner != nullptr) && (MobSpawner->GetBlockType() == E_BLOCK_MOB_SPAWNER));
886  MobSpawner->SetEntity(mtCaveSpider);
887  }
888 }
889 
890 
891 
892 
893 
895 {
896  cNoise Noise(m_BoundingBox.p1.x);
897  switch (m_Direction)
898  {
899  case dirXM:
900  case dirXP:
901  {
902  int z = m_BoundingBox.p1.z + 1 - a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
903  if ((z < 0) || (z >= cChunkDef::Width))
904  {
905  return;
906  }
907  int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
908  for (int i = 0; i < m_NumSegments; i++)
909  {
910  if (!m_HasFullBeam[i])
911  {
912  continue;
913  }
914  int x = m_BoundingBox.p1.x + i * 5 + 1 - BlockX;
915  if ((x >= 0) && (x < cChunkDef::Width))
916  {
917  if (((Noise.IntNoise2DInt(x, z) / 7) % 10000) < m_ParentSystem.m_ChanceTorch)
918  {
919  a_ChunkDesc.SetBlockTypeMeta(x, m_BoundingBox.p2.y, z, E_BLOCK_TORCH, E_META_TORCH_XP);
920  }
921  }
922  x += 2;
923  if ((x >= 0) && (x < cChunkDef::Width))
924  {
925  if (((Noise.IntNoise2DInt(x, z) / 7) % 10000) < m_ParentSystem.m_ChanceTorch)
926  {
927  a_ChunkDesc.SetBlockTypeMeta(x, m_BoundingBox.p2.y, z, E_BLOCK_TORCH, E_META_TORCH_XM);
928  }
929  }
930  } // for i
931  break;
932  }
933 
934  case dirZM:
935  case dirZP:
936  {
937  int x = m_BoundingBox.p1.x + 1 - a_ChunkDesc.GetChunkX() * cChunkDef::Width;
938  if ((x < 0) || (x >= cChunkDef::Width))
939  {
940  return;
941  }
942  int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
943  for (int i = 0; i < m_NumSegments; i++)
944  {
945  if (!m_HasFullBeam[i])
946  {
947  continue;
948  }
949  int z = m_BoundingBox.p1.z + i * 5 + 1 - BlockZ;
950  if ((z >= 0) && (z < cChunkDef::Width))
951  {
952  if (((Noise.IntNoise2DInt(x, z) / 7) % 10000) < m_ParentSystem.m_ChanceTorch)
953  {
954  a_ChunkDesc.SetBlockTypeMeta(x, m_BoundingBox.p2.y, z, E_BLOCK_TORCH, E_META_TORCH_ZP);
955  }
956  }
957  z += 2;
958  if ((z >= 0) && (z < cChunkDef::Width))
959  {
960  if (((Noise.IntNoise2DInt(x, z) / 7) % 10000) < m_ParentSystem.m_ChanceTorch)
961  {
962  a_ChunkDesc.SetBlockTypeMeta(x, m_BoundingBox.p2.y, z, E_BLOCK_TORCH, E_META_TORCH_ZM);
963  }
964  }
965  } // for i
966  break;
967  }
968  } // switch (direction)
969 }
970 
971 
972 
973 
974 
976 // cMineShaftCrossing:
977 
979  Super(a_ParentSystem, mskCrossing, a_BoundingBox)
980 {
981 }
982 
983 
984 
985 
986 
989  int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction,
990  cNoise & a_Noise
991 )
992 {
993  cCuboid BoundingBox(a_PivotX, a_PivotY - 1, a_PivotZ);
994  int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + static_cast<int>(a_ParentSystem.m_MineShafts.size()), a_PivotZ) / 7;
995  BoundingBox.p2.y += 3;
996  if ((rnd % 4) < 2)
997  {
998  // 2-level crossing:
999  BoundingBox.p2.y += 4;
1000  rnd >>= 2;
1001  if ((rnd % 4) < 2)
1002  {
1003  // This is the higher level:
1004  BoundingBox.p1.y -= 4;
1005  BoundingBox.p2.y -= 4;
1006  }
1007  }
1008  switch (a_Direction)
1009  {
1010  case dirXP: BoundingBox.p2.x += 4; BoundingBox.p1.z -= 2; BoundingBox.p2.z += 2; break;
1011  case dirXM: BoundingBox.p1.x -= 4; BoundingBox.p1.z -= 2; BoundingBox.p2.z += 2; break;
1012  case dirZP: BoundingBox.p2.z += 4; BoundingBox.p1.x -= 2; BoundingBox.p2.x += 2; break;
1013  case dirZM: BoundingBox.p1.z -= 4; BoundingBox.p1.x -= 2; BoundingBox.p2.x += 2; break;
1014  }
1015  if (!a_ParentSystem.CanAppend(BoundingBox))
1016  {
1017  return nullptr;
1018  }
1019  return new cMineShaftCrossing(a_ParentSystem, BoundingBox);
1020 }
1021 
1022 
1023 
1024 
1025 
1026 void cMineShaftCrossing::AppendBranches(int a_RecursionLevel, cNoise & a_Noise)
1027 {
1028  struct
1029  {
1030  int x, y, z;
1031  eDirection dir;
1032  } Exits[] =
1033  {
1034  // Bottom level:
1035  {-1, 1, 2, dirXM},
1036  { 2, 1, -1, dirZM},
1037  { 5, 1, 2, dirXP},
1038  { 2, 1, 5, dirZP},
1039  // Top level:
1040  {-1, 5, 2, dirXM},
1041  { 2, 5, -1, dirZM},
1042  { 5, 5, 2, dirXP},
1043  { 2, 5, 5, dirZP},
1044  } ;
1045  for (size_t i = 0; i < ARRAYCOUNT(Exits); i++)
1046  {
1047  if (m_BoundingBox.p1.y + Exits[i].y >= m_BoundingBox.p2.y)
1048  {
1049  // This exit is not available (two-level exit on a one-level crossing)
1050  continue;
1051  }
1052 
1053  int Height = m_BoundingBox.p1.y + Exits[i].y;
1054  m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + Exits[i].x, Height, m_BoundingBox.p1.z + Exits[i].z, Exits[i].dir, a_Noise, a_RecursionLevel);
1055  } // for i
1056 }
1057 
1058 
1059 
1060 
1061 
1063 {
1064  int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
1065  int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
1066  cCuboid box(m_BoundingBox);
1067  box.Move({-BlockX, 0, -BlockZ});
1068  if ((box.p2.x < 0) || (box.p2.z < 0) || (box.p1.x >= cChunkDef::Width) || (box.p1.z > cChunkDef::Width))
1069  {
1070  // Does not intersect this chunk
1071  return;
1072  }
1073  int Floor = box.p1.y + 1;
1074  int Ceil = box.p2.y;
1075 
1076  // The supports:
1077  a_ChunkDesc.FillRelCuboid(box.p1.x + 1, box.p1.x + 1, Floor, Ceil, box.p1.z + 1, box.p1.z + 1, E_BLOCK_PLANKS, 0);
1078  a_ChunkDesc.FillRelCuboid(box.p2.x - 1, box.p2.x - 1, Floor, Ceil, box.p1.z + 1, box.p1.z + 1, E_BLOCK_PLANKS, 0);
1079  a_ChunkDesc.FillRelCuboid(box.p1.x + 1, box.p1.x + 1, Floor, Ceil, box.p2.z - 1, box.p2.z - 1, E_BLOCK_PLANKS, 0);
1080  a_ChunkDesc.FillRelCuboid(box.p2.x - 1, box.p2.x - 1, Floor, Ceil, box.p2.z - 1, box.p2.z - 1, E_BLOCK_PLANKS, 0);
1081 
1082  // The air in between:
1083  a_ChunkDesc.FillRelCuboid(box.p1.x + 2, box.p1.x + 2, Floor, Ceil, box.p1.z + 1, box.p2.z - 1, E_BLOCK_AIR, 0);
1084  a_ChunkDesc.FillRelCuboid(box.p1.x + 1, box.p2.x - 1, Floor, Ceil, box.p1.z + 2, box.p1.z + 2, E_BLOCK_AIR, 0);
1085 
1086  // The air on the edges:
1087  int Mid = Floor + 2;
1088  a_ChunkDesc.FillRelCuboid(box.p1.x, box.p1.x, Floor, Mid, box.p1.z + 1, box.p2.z - 1, E_BLOCK_AIR, 0);
1089  a_ChunkDesc.FillRelCuboid(box.p2.x, box.p2.x, Floor, Mid, box.p1.z + 1, box.p2.z - 1, E_BLOCK_AIR, 0);
1090  a_ChunkDesc.FillRelCuboid(box.p1.x + 1, box.p2.x - 1, Floor, Mid, box.p1.z, box.p1.z, E_BLOCK_AIR, 0);
1091  a_ChunkDesc.FillRelCuboid(box.p1.x + 1, box.p2.x - 1, Floor, Mid, box.p2.z, box.p2.z, E_BLOCK_AIR, 0);
1092  Mid += 2;
1093  if (Mid < Ceil)
1094  {
1095  a_ChunkDesc.FillRelCuboid(box.p1.x, box.p1.x, Mid, Ceil, box.p1.z + 1, box.p2.z - 1, E_BLOCK_AIR, 0);
1096  a_ChunkDesc.FillRelCuboid(box.p2.x, box.p2.x, Mid, Ceil, box.p1.z + 1, box.p2.z - 1, E_BLOCK_AIR, 0);
1097  a_ChunkDesc.FillRelCuboid(box.p1.x + 1, box.p2.x - 1, Mid, Ceil, box.p1.z, box.p1.z, E_BLOCK_AIR, 0);
1098  a_ChunkDesc.FillRelCuboid(box.p1.x + 1, box.p2.x - 1, Mid, Ceil, box.p2.z, box.p2.z, E_BLOCK_AIR, 0);
1099  }
1100 
1101  // The floor, if needed:
1102  box.p2.y = box.p1.y;
1103  a_ChunkDesc.FloorRelCuboid(box, E_BLOCK_PLANKS, 0);
1104 }
1105 
1106 
1107 
1108 
1109 
1111 // cMineShaftStaircase:
1112 
1114  cStructGenMineShafts::cMineShaftSystem & a_ParentSystem,
1115  const cCuboid & a_BoundingBox,
1116  eDirection a_Direction,
1117  eSlope a_Slope
1118 ) :
1119  Super(a_ParentSystem, mskStaircase, a_BoundingBox),
1120  m_Direction(a_Direction),
1121  m_Slope(a_Slope)
1122 {
1123 }
1124 
1125 
1126 
1127 
1128 
1130  cStructGenMineShafts::cMineShaftSystem & a_ParentSystem,
1131  int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction,
1132  cNoise & a_Noise
1133 )
1134 {
1135  int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + static_cast<int>(a_ParentSystem.m_MineShafts.size()), a_PivotZ) / 7;
1136  cCuboid Box;
1137  switch (a_Direction)
1138  {
1139  case dirXM:
1140  {
1141  Box.Assign({a_PivotX - 7, a_PivotY - 1, a_PivotZ - 1}, {a_PivotX, a_PivotY + 6, a_PivotZ + 1});
1142  break;
1143  }
1144  case dirXP:
1145  {
1146  Box.Assign({a_PivotX, a_PivotY - 1, a_PivotZ - 1}, {a_PivotX + 7, a_PivotY + 6, a_PivotZ + 1});
1147  break;
1148  }
1149  case dirZM:
1150  {
1151  Box.Assign({a_PivotX - 1, a_PivotY - 1, a_PivotZ - 7}, {a_PivotX + 1, a_PivotY + 6, a_PivotZ});
1152  break;
1153  }
1154  case dirZP:
1155  {
1156  Box.Assign({a_PivotX - 1, a_PivotY - 1, a_PivotZ}, {a_PivotX + 1, a_PivotY + 6, a_PivotZ + 7});
1157  break;
1158  }
1159  }
1160  eSlope Slope = sUp;
1161  if ((rnd % 4) < 2) // 50 %
1162  {
1163  Slope = sDown;
1164  Box.Move({0, -4, 0});
1165  }
1166  if (!a_ParentSystem.CanAppend(Box))
1167  {
1168  return nullptr;
1169  }
1170  return new cMineShaftStaircase(a_ParentSystem, Box, a_Direction, Slope);
1171 }
1172 
1173 
1174 
1175 
1176 
1177 void cMineShaftStaircase::AppendBranches(int a_RecursionLevel, cNoise & a_Noise)
1178 {
1179  int Height = m_BoundingBox.p1.y + ((m_Slope == sDown) ? 1 : 5);
1180  switch (m_Direction)
1181  {
1182  case dirXM: m_ParentSystem.AppendBranch(m_BoundingBox.p1.x - 1, Height, m_BoundingBox.p1.z + 1, dirXM, a_Noise, a_RecursionLevel); break;
1183  case dirXP: m_ParentSystem.AppendBranch(m_BoundingBox.p2.x + 1, Height, m_BoundingBox.p1.z + 1, dirXP, a_Noise, a_RecursionLevel); break;
1184  case dirZM: m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + 1, Height, m_BoundingBox.p1.z - 1, dirZM, a_Noise, a_RecursionLevel); break;
1185  case dirZP: m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + 1, Height, m_BoundingBox.p2.z + 1, dirZP, a_Noise, a_RecursionLevel); break;
1186  }
1187 }
1188 
1189 
1190 
1191 
1192 
1194 {
1195  int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
1196  int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
1197  cCuboid RelB(m_BoundingBox);
1198  RelB.Move({-BlockX, 0, -BlockZ});
1199  if (
1200  (RelB.p1.x >= cChunkDef::Width) ||
1201  (RelB.p1.z >= cChunkDef::Width) ||
1202  (RelB.p2.x < 0) ||
1203  (RelB.p2.z < 0)
1204  )
1205  {
1206  // No intersection between this staircase and this chunk
1207  return;
1208  }
1209 
1210  int SFloor = RelB.p1.y + ((m_Slope == sDown) ? 5 : 1);
1211  int DFloor = RelB.p1.y + ((m_Slope == sDown) ? 1 : 5);
1212  int Add = (m_Slope == sDown) ? -1 : 1;
1213  int InitAdd = (m_Slope == sDown) ? -1 : 0;
1214  cCuboid Box;
1215  switch (m_Direction)
1216  {
1217  case dirXM:
1218  {
1219  a_ChunkDesc.FillRelCuboid (RelB.p2.x - 1, RelB.p2.x, SFloor, SFloor + 2, RelB.p1.z, RelB.p2.z, E_BLOCK_AIR, 0);
1220  a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p1.x + 1, DFloor, DFloor + 2, RelB.p1.z, RelB.p2.z, E_BLOCK_AIR, 0);
1221  a_ChunkDesc.FloorRelCuboid(RelB.p2.x - 1, RelB.p2.x, SFloor - 1, SFloor - 1, RelB.p1.z, RelB.p2.z, E_BLOCK_PLANKS, 0);
1222  a_ChunkDesc.FloorRelCuboid(RelB.p1.x, RelB.p1.x + 1, DFloor - 1, DFloor - 1, RelB.p1.z, RelB.p2.z, E_BLOCK_PLANKS, 0);
1223  Box.Assign({RelB.p2.x - 2, SFloor + InitAdd, RelB.p1.z}, {RelB.p2.x - 2, SFloor + 3 + InitAdd, RelB.p2.z});
1224  for (int i = 0; i < 4; i++)
1225  {
1226  a_ChunkDesc.FillRelCuboid(Box, E_BLOCK_AIR, 0);
1227  a_ChunkDesc.FloorRelCuboid(Box.p1.x, Box.p2.x, Box.p1.y - 1, Box.p1.y - 1, Box.p1.z, Box.p2.z, E_BLOCK_PLANKS, 0);
1228  Box.Move({-1, Add, 0});
1229  }
1230  break;
1231  }
1232 
1233  case dirXP:
1234  {
1235  a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p1.x + 1, SFloor, SFloor + 2, RelB.p1.z, RelB.p2.z, E_BLOCK_AIR, 0);
1236  a_ChunkDesc.FillRelCuboid (RelB.p2.x - 1, RelB.p2.x, DFloor, DFloor + 2, RelB.p1.z, RelB.p2.z, E_BLOCK_AIR, 0);
1237  a_ChunkDesc.FloorRelCuboid(RelB.p1.x, RelB.p1.x + 1, SFloor - 1, SFloor - 1, RelB.p1.z, RelB.p2.z, E_BLOCK_PLANKS, 0);
1238  a_ChunkDesc.FloorRelCuboid(RelB.p2.x - 1, RelB.p2.x, DFloor - 1, DFloor - 1, RelB.p1.z, RelB.p2.z, E_BLOCK_PLANKS, 0);
1239  Box.Assign({RelB.p1.x + 2, SFloor + InitAdd, RelB.p1.z}, {RelB.p1.x + 2, SFloor + 3 + InitAdd, RelB.p2.z});
1240  for (int i = 0; i < 4; i++)
1241  {
1242  a_ChunkDesc.FillRelCuboid(Box, E_BLOCK_AIR, 0);
1243  a_ChunkDesc.FloorRelCuboid(Box.p1.x, Box.p2.x, Box.p1.y - 1, Box.p1.y - 1, Box.p1.z, Box.p2.z, E_BLOCK_PLANKS, 0);
1244  Box.Move({1, Add, 0});
1245  }
1246  break;
1247  }
1248 
1249  case dirZM:
1250  {
1251  a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p2.x, SFloor, SFloor + 2, RelB.p2.z - 1, RelB.p2.z, E_BLOCK_AIR, 0);
1252  a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p2.x, DFloor, DFloor + 2, RelB.p1.z, RelB.p1.z + 1, E_BLOCK_AIR, 0);
1253  a_ChunkDesc.FloorRelCuboid(RelB.p1.x, RelB.p2.x, SFloor - 1, SFloor - 1, RelB.p2.z - 1, RelB.p2.z, E_BLOCK_PLANKS, 0);
1254  a_ChunkDesc.FloorRelCuboid(RelB.p1.x, RelB.p2.x, DFloor - 1, DFloor - 1, RelB.p1.z, RelB.p1.z + 1, E_BLOCK_PLANKS, 0);
1255  Box.Assign({RelB.p1.x, SFloor + InitAdd, RelB.p2.z - 2}, {RelB.p2.x, SFloor + 3 + InitAdd, RelB.p2.z - 2});
1256  for (int i = 0; i < 4; i++)
1257  {
1258  a_ChunkDesc.FillRelCuboid(Box, E_BLOCK_AIR, 0);
1259  a_ChunkDesc.FloorRelCuboid(Box.p1.x, Box.p2.x, Box.p1.y - 1, Box.p1.y - 1, Box.p1.z, Box.p2.z, E_BLOCK_PLANKS, 0);
1260  Box.Move({0, Add, -1});
1261  }
1262  break;
1263  }
1264 
1265  case dirZP:
1266  {
1267  a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p2.x, SFloor, SFloor + 2, RelB.p1.z, RelB.p1.z + 1, E_BLOCK_AIR, 0);
1268  a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p2.x, DFloor, DFloor + 2, RelB.p2.z - 1, RelB.p2.z, E_BLOCK_AIR, 0);
1269  a_ChunkDesc.FloorRelCuboid(RelB.p1.x, RelB.p2.x, SFloor - 1, SFloor - 1, RelB.p1.z, RelB.p1.z + 1, E_BLOCK_PLANKS, 0);
1270  a_ChunkDesc.FloorRelCuboid(RelB.p1.x, RelB.p2.x, DFloor - 1, DFloor - 1, RelB.p2.z - 1, RelB.p2.z, E_BLOCK_PLANKS, 0);
1271  Box.Assign({RelB.p1.x, SFloor + InitAdd, RelB.p1.z + 2}, {RelB.p2.x, SFloor + 3 + InitAdd, RelB.p1.z + 2});
1272  for (int i = 0; i < 4; i++)
1273  {
1274  a_ChunkDesc.FillRelCuboid(Box, E_BLOCK_AIR, 0);
1275  a_ChunkDesc.FloorRelCuboid(Box.p1.x, Box.p2.x, Box.p1.y - 1, Box.p1.y - 1, Box.p1.z, Box.p2.z, E_BLOCK_PLANKS, 0);
1276  Box.Move({0, Add, 1});
1277  }
1278  break;
1279  }
1280 
1281  } // switch (m_Direction)
1282 }
1283 
1284 
1285 
1286 
1287 
1289 // cStructGenMineShafts:
1290 
1292  int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxSystemSize,
1293  int a_ChanceCorridor, int a_ChanceCrossing, int a_ChanceStaircase
1294 ) :
1295  Super(a_Seed, a_GridSize, a_GridSize, a_MaxOffset, a_MaxOffset, a_MaxSystemSize, a_MaxSystemSize, 100),
1296  m_GridSize(a_GridSize),
1297  m_MaxSystemSize(a_MaxSystemSize),
1298  m_ProbLevelCorridor(std::max(0, a_ChanceCorridor)),
1299  m_ProbLevelCrossing(std::max(0, a_ChanceCorridor + a_ChanceCrossing)),
1300  m_ProbLevelStaircase(std::max(0, a_ChanceCorridor + a_ChanceCrossing + a_ChanceStaircase))
1301 {
1302 }
1303 
1304 
1305 
1306 
1307 
1308 cGridStructGen::cStructurePtr cStructGenMineShafts::CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ)
1309 {
1311 }
1312 
1313 
1314 
1315 
@ E_META_CHEST_FACING_XP
Definition: BlockType.h:600
@ E_META_TORCH_ZP
Definition: BlockType.h:944
@ E_META_TORCH_XP
Definition: BlockType.h:942
@ E_META_TORCH_ZM
Definition: BlockType.h:943
@ E_META_TORCH_XM
Definition: BlockType.h:941
@ E_META_CHEST_FACING_ZP
Definition: BlockType.h:598
@ E_BLOCK_AIR
Definition: BlockType.h:10
@ E_BLOCK_CHEST
Definition: BlockType.h:64
@ E_BLOCK_COBWEB
Definition: BlockType.h:40
@ E_BLOCK_FENCE
Definition: BlockType.h:100
@ E_BLOCK_MINECART_TRACKS
Definition: BlockType.h:80
@ E_BLOCK_PLANKS
Definition: BlockType.h:15
@ E_BLOCK_TORCH
Definition: BlockType.h:60
@ E_BLOCK_DIRT
Definition: BlockType.h:13
@ E_BLOCK_MOB_SPAWNER
Definition: BlockType.h:62
@ E_ITEM_IRON
Definition: BlockType.h:309
@ E_ITEM_GOLD
Definition: BlockType.h:310
@ E_ITEM_COAL
Definition: BlockType.h:307
@ E_ITEM_DYE
Definition: BlockType.h:396
@ E_ITEM_REDSTONE_DUST
Definition: BlockType.h:375
@ E_ITEM_IRON_PICKAXE
Definition: BlockType.h:301
@ E_ITEM_DIAMOND
Definition: BlockType.h:308
@ E_ITEM_MELON_SEEDS
Definition: BlockType.h:407
@ E_ITEM_BREAD
Definition: BlockType.h:341
@ E_ITEM_PUMPKIN_SEEDS
Definition: BlockType.h:406
@ E_META_TRACKS_Z
Definition: BlockType.h:1086
@ E_META_TRACKS_X
Definition: BlockType.h:1085
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:44
std::vector< cMineShaft * > cMineShafts
Definition: MineShafts.cpp:84
#define UNREACHABLE(x)
Definition: Globals.h:288
#define ARRAYCOUNT(X)
Evaluates to the number of elements in an array (compile-time!)
Definition: Globals.h:231
#define ASSERT(x)
Definition: Globals.h:276
@ mtCaveSpider
Definition: MonsterTypes.h:17
Definition: FastNBT.h:132
BLOCKTYPE GetBlockType() const
Definition: BlockEntity.h:97
cItemGrid & GetContents(void)
Returns the ItemGrid used for storing the contents.
void SetEntity(eMonsterType a_EntityType)
static const int Width
Definition: ChunkDef.h:124
Definition: Cuboid.h:10
Vector3i p2
Definition: Cuboid.h:13
void Assign(Vector3i a_Point1, Vector3i a_Point2)
Definition: Cuboid.cpp:13
void Move(Vector3i a_Offset)
Moves the cuboid by the specified offset.
Definition: Cuboid.cpp:74
int DifY(void) const
Definition: Cuboid.h:34
Vector3i p1
Definition: Cuboid.h:13
bool IsCompletelyInside(const cCuboid &a_Outer) const
Returns true if this cuboid is completely inside the specified cuboid (in all 6 coords).
Definition: Cuboid.cpp:55
bool DoesIntersect(const cCuboid &a_Other) const
Returns true if the cuboids have at least one voxel in common.
Definition: Cuboid.h:44
cBlockEntity * GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ)
Returns the block entity at the specified coords.
Definition: ChunkDesc.cpp:573
void SetBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType)
Definition: ChunkDesc.cpp:81
void RandomFillRelCuboid(int a_MinX, int a_MaxX, int a_MinY, int a_MaxY, int a_MinZ, int a_MaxZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_RandomSeed, int a_ChanceOutOf10k)
Fills the relative cuboid with specified block with a random chance; allows cuboid out of range of th...
Definition: ChunkDesc.cpp:537
void FillRelCuboid(int a_MinX, int a_MaxX, int a_MinY, int a_MaxY, int a_MinZ, int a_MaxZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Fills the relative cuboid with specified block; allows cuboid out of range of this chunk.
Definition: ChunkDesc.cpp:431
int GetChunkX() const
Definition: ChunkDesc.h:49
void SetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
Definition: ChunkDesc.cpp:63
void FloorRelCuboid(int a_MinX, int a_MaxX, int a_MinY, int a_MaxY, int a_MinZ, int a_MaxZ, BLOCKTYPE a_DstType, NIBBLETYPE a_DstMeta)
Replaces the blocks in the cuboid by the dst blocks if they are considered non-floor (air,...
Definition: ChunkDesc.cpp:498
BLOCKTYPE GetBlockType(int a_RelX, int a_RelY, int a_RelZ) const
Definition: ChunkDesc.cpp:90
int GetChunkZ() const
Definition: ChunkDesc.h:50
Generates structures in a semi-random grid.
Definition: GridStructGen.h:46
std::shared_ptr< cStructure > cStructurePtr
Definition: GridStructGen.h:77
cNoise m_Noise
The noise used for generating grid offsets.
Represents a single structure that occupies the grid point.
Definition: GridStructGen.h:50
int m_OriginX
The origin (the coords for which the structure is generated)
Definition: GridStructGen.h:56
virtual void AppendBranches(int a_RecursionLevel, cNoise &a_Noise) override
Definition: MineShafts.cpp:432
cMineShaft Super
Definition: MineShafts.cpp:93
cMineShaftDirtRoom(cStructGenMineShafts::cMineShaftSystem &a_Parent, cNoise &a_Noise)
Definition: MineShafts.cpp:409
virtual void ProcessChunk(cChunkDesc &a_ChunkDesc) override
Definition: MineShafts.cpp:456
bool m_HasFullBeam[MAX_SEGMENTS]
If true, segment at that index has a full beam support (planks in the top center block)
Definition: MineShafts.cpp:129
int m_ChestPosition
If <0, no chest; otherwise an offset from m_BoundingBox's p1.x or p1.z, depenging on m_Direction.
Definition: MineShafts.cpp:130
eDirection m_Direction
Definition: MineShafts.cpp:128
void PlaceSpawner(cChunkDesc &a_ChunkDesc)
If this corridor has a spawner, places the spawner.
Definition: MineShafts.cpp:854
cMineShaftCorridor(cStructGenMineShafts::cMineShaftSystem &a_ParentSystem, const cCuboid &a_BoundingBox, int a_NumSegments, eDirection a_Direction, cNoise &a_Noise)
Definition: MineShafts.cpp:501
bool m_HasTracks
If true, random tracks will be placed on the floor.
Definition: MineShafts.cpp:132
void PlaceTorches(cChunkDesc &a_ChunkDesc)
Randomly places torches around the central beam block.
Definition: MineShafts.cpp:894
virtual void AppendBranches(int a_RecursionLevel, cNoise &a_Noise) override
Definition: MineShafts.cpp:567
void PlaceTracks(cChunkDesc &a_ChunkDesc)
If this corridor has tracks, places them randomly.
Definition: MineShafts.cpp:817
static cMineShaft * CreateAndFit(cStructGenMineShafts::cMineShaftSystem &a_ParentSystem, int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction, cNoise &a_Noise)
Creates a new Corridor attached to the specified pivot point and direction.
Definition: MineShafts.cpp:539
void PlaceChest(cChunkDesc &a_ChunkDesc)
Places a chest, if the corridor has one.
Definition: MineShafts.cpp:746
int m_SpawnerPosition
If <0, no spawner; otherwise an offset from m_BoundingBox's p1.x or p1.z, depenging on m_Direction.
Definition: MineShafts.cpp:131
virtual void ProcessChunk(cChunkDesc &a_ChunkDesc) override
Definition: MineShafts.cpp:640
static const int MAX_SEGMENTS
Definition: MineShafts.cpp:125
static cMineShaft * CreateAndFit(cStructGenMineShafts::cMineShaftSystem &a_ParentSystem, int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction, cNoise &a_Noise)
Creates a new Crossing attached to the specified pivot point and direction.
Definition: MineShafts.cpp:987
virtual void AppendBranches(int a_RecursionLevel, cNoise &a_Noise) override
cMineShaftCrossing(cStructGenMineShafts::cMineShaftSystem &a_ParentSystem, const cCuboid &a_BoundingBox)
Definition: MineShafts.cpp:978
virtual void ProcessChunk(cChunkDesc &a_ChunkDesc) override
eDirection m_Direction
Definition: MineShafts.cpp:213
static cMineShaft * CreateAndFit(cStructGenMineShafts::cMineShaftSystem &a_ParentSystem, int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction, cNoise &a_Noise)
Creates a new Staircase attached to the specified pivot point and direction.
virtual void AppendBranches(int a_RecursionLevel, cNoise &a_Noise) override
virtual void ProcessChunk(cChunkDesc &a_ChunkDesc) override
cMineShaftStaircase(cStructGenMineShafts::cMineShaftSystem &a_ParentSystem, const cCuboid &a_BoundingBox, eDirection a_Direction, eSlope a_Slope)
int m_ProbLevelCorridor
Probability level of a branch object being the corridor.
Definition: MineShafts.cpp:242
virtual void DrawIntoChunk(cChunkDesc &a_Chunk) override
Draws self into the specified chunk.
Definition: MineShafts.cpp:334
cMineShaftSystem(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ, int a_GridSize, int a_MaxSystemSize, cNoise &a_Noise, int a_ProbLevelCorridor, int a_ProbLevelCrossing, int a_ProbLevelStaircase)
Creates and generates the entire system.
Definition: MineShafts.cpp:284
int m_ChanceTorch
Chance [0 .. 10k] for a torch appearing attached to a corridor's beam.
Definition: MineShafts.cpp:247
int m_ChanceChest
Chance [0 .. 250] that a corridor has a chest in it.
Definition: MineShafts.cpp:245
void AppendBranch(int a_BlockX, int a_BlockY, int a_BlockZ, cMineShaft::eDirection a_Direction, cNoise &a_Noise, int a_RecursionLevel)
Creates new cMineShaft descendant connected at the specified point, heading the specified direction,...
Definition: MineShafts.cpp:346
int m_ChanceSpawner
Chance [0 .. 250] that a corridor has a spawner in it.
Definition: MineShafts.cpp:246
bool CanAppend(const cCuboid &a_BoundingBox)
Returns true if none of the objects in m_MineShafts intersect with the specified bounding box and the...
Definition: MineShafts.cpp:383
cCuboid m_BoundingBox
Bounding box into which all of the components need to fit.
Definition: MineShafts.cpp:249
cMineShafts m_MineShafts
List of cMineShaft descendants that comprise this system.
Definition: MineShafts.cpp:248
int m_GridSize
Maximum offset of the dirtroom from grid center, * 2, in each direction.
Definition: MineShafts.cpp:240
int m_MaxRecursion
Maximum recursion level (initialized from cStructGenMineShafts::m_MaxRecursion)
Definition: MineShafts.cpp:241
int m_ProbLevelStaircase
Probability level of a branch object being the staircase, minus Crossing.
Definition: MineShafts.cpp:244
int m_ProbLevelCrossing
Probability level of a branch object being the crossing, minus Corridor.
Definition: MineShafts.cpp:243
int m_ProbLevelCrossing
Probability level of a branch object being the crossing, minus Corridor.
Definition: MineShafts.h:40
friend class cMineShaft
Definition: MineShafts.h:30
int m_ProbLevelStaircase
Probability level of a branch object being the staircase, minus Crossing.
Definition: MineShafts.h:41
int m_GridSize
Average spacing of the systems.
Definition: MineShafts.h:35
friend class cMineShaftDirtRoom
Definition: MineShafts.h:31
int m_ProbLevelCorridor
Probability level of a branch object being the corridor.
Definition: MineShafts.h:39
int m_MaxSystemSize
Maximum blcok size of a mineshaft system.
Definition: MineShafts.h:38
virtual cStructurePtr CreateStructure(int a_GridX, int a_GridZ, int a_OriginX, int a_OriginZ) override
Create a new structure at the specified gridpoint.
cStructGenMineShafts(int a_Seed, int a_GridSize, int a_MaxOffset, int a_MaxSystemSize, int a_ChanceCorridor, int a_ChanceCrossing, int a_ChanceStaircase)
Definition: Item.h:37
Used to store loot probability tables.
Definition: Item.h:260
void GenerateRandomLootWithBooks(const cLootProbab *a_LootProbabs, size_t a_CountLootProbabs, int a_NumSlots, int a_Seed)
Generates random loot from the specified loot probability table, with a chance of enchanted books add...
Definition: ItemGrid.cpp:752
Definition: Noise.h:20
int IntNoise3DInt(int a_X, int a_Y, int a_Z) const
Definition: Noise.h:254
int IntNoise2DInt(int a_X, int a_Y) const
Definition: Noise.h:243
T x
Definition: Vector3.h:17
T y
Definition: Vector3.h:17
T z
Definition: Vector3.h:17