summaryrefslogtreecommitdiffstats
path: root/src/Generating/MineShafts.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Generating/MineShafts.cpp')
-rw-r--r--src/Generating/MineShafts.cpp1424
1 files changed, 1424 insertions, 0 deletions
diff --git a/src/Generating/MineShafts.cpp b/src/Generating/MineShafts.cpp
new file mode 100644
index 000000000..f42240e55
--- /dev/null
+++ b/src/Generating/MineShafts.cpp
@@ -0,0 +1,1424 @@
+
+// MineShafts.cpp
+
+// Implements the cStructGenMineShafts class representing the structure generator for abandoned mineshafts
+
+/*
+Algorithm:
+The cStructGenMineShafts::cMineShaftSystem class is the main controller, which knows what mineshaft
+classes there are and their random weights. It gets asked to produce a new class everytime a connection is to be made.
+The cMineShaft class is a base class for each mineshaft structure.
+Each cMineShaft descendant knows how large it is, how to imprint itself into the chunk data and where to connect to
+other descendants. Its PivotPoint is always a walkable column. Its Direction determines in which direction the structure
+is facing.
+
+The generation starts with the central dirt room, from there corridors, crossings and staircases are added
+in a depth-first processing. Each of the descendants will branch randomly, if not beyond the allowed recursion level
+*/
+
+#include "Globals.h"
+#include "MineShafts.h"
+#include "../Cuboid.h"
+#include "../BlockEntities/ChestEntity.h"
+
+
+
+
+
+static const int NEIGHBORHOOD_SIZE = 3;
+
+
+
+
+
+class cMineShaft abstract
+{
+public:
+ enum eKind
+ {
+ mskDirtRoom,
+ mskCorridor,
+ mskCrossing,
+ mskStaircase,
+ } ;
+
+
+ enum eDirection
+ {
+ dirXP,
+ dirZP,
+ dirXM,
+ dirZM,
+ } ;
+
+
+ cStructGenMineShafts::cMineShaftSystem & m_ParentSystem;
+ eKind m_Kind;
+ cCuboid m_BoundingBox;
+
+
+ cMineShaft(cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, eKind a_Kind) :
+ m_ParentSystem(a_ParentSystem),
+ m_Kind(a_Kind)
+ {
+ }
+
+ cMineShaft(cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, eKind a_Kind, const cCuboid & a_BoundingBox) :
+ m_ParentSystem(a_ParentSystem),
+ m_Kind(a_Kind),
+ m_BoundingBox(a_BoundingBox)
+ {
+ }
+
+ /// Returns true if this mineshaft intersects the specified cuboid
+ bool DoesIntersect(const cCuboid & a_Other)
+ {
+ return m_BoundingBox.DoesIntersect(a_Other);
+ }
+
+ /** If recursion level is not too large, appends more branches to the parent system,
+ using exit points specific to this class.
+ */
+ virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) = 0;
+
+ /// Imprints this shape into the specified chunk's data
+ virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) = 0;
+} ;
+
+typedef std::vector<cMineShaft *> cMineShafts;
+
+
+
+
+
+class cMineShaftDirtRoom :
+ public cMineShaft
+{
+ typedef cMineShaft super;
+
+public:
+ cMineShaftDirtRoom(cStructGenMineShafts::cMineShaftSystem & a_Parent, cNoise & a_Noise);
+
+ // cMineShaft overrides:
+ virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) override;
+ virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) override;
+} ;
+
+
+
+
+
+class cMineShaftCorridor :
+ public cMineShaft
+{
+ typedef cMineShaft super;
+
+public:
+ /** Creates a new Corridor attached to the specified pivot point and direction.
+ Checks all ParentSystem's objects and disallows intersecting. Initializes the new object to fit.
+ May return NULL if cannot fit.
+ */
+ static cMineShaft * CreateAndFit(
+ cStructGenMineShafts::cMineShaftSystem & a_ParentSystem,
+ int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction,
+ cNoise & a_Noise
+ );
+
+protected:
+ static const int MAX_SEGMENTS = 5;
+
+ int m_NumSegments;
+ eDirection m_Direction;
+ bool m_HasFullBeam[MAX_SEGMENTS]; ///< If true, segment at that index has a full beam support (planks in the top center block)
+ int m_ChestPosition; ///< If <0, no chest; otherwise an offset from m_BoundingBox's p1.x or p1.z, depenging on m_Direction
+ int m_SpawnerPosition; ///< If <0, no spawner; otherwise an offset from m_BoundingBox's p1.x or p1.z, depenging on m_Direction
+ bool m_HasTracks; ///< If true, random tracks will be placed on the floor
+
+ cMineShaftCorridor(
+ cStructGenMineShafts::cMineShaftSystem & a_ParentSystem,
+ const cCuboid & a_BoundingBox, int a_NumSegments, eDirection a_Direction,
+ cNoise & a_Noise
+ );
+
+ // cMineShaft overrides:
+ virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) override;
+ virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) override;
+
+ /// Places a chest, if the corridor has one
+ void PlaceChest(cChunkDesc & a_ChunkDesc);
+
+ /// If this corridor has tracks, places them randomly
+ void PlaceTracks(cChunkDesc & a_ChunkDesc);
+
+ /// If this corridor has a spawner, places the spawner
+ void PlaceSpawner(cChunkDesc & a_ChunkDesc);
+
+ /// Randomly places torches around the central beam block
+ void PlaceTorches(cChunkDesc & a_ChunkDesc);
+} ;
+
+
+
+
+
+class cMineShaftCrossing :
+ public cMineShaft
+{
+ typedef cMineShaft super;
+
+public:
+ /** Creates a new Crossing attached to the specified pivot point and direction.
+ Checks all ParentSystem's objects and disallows intersecting. Initializes the new object to fit.
+ May return NULL if cannot fit.
+ */
+ static cMineShaft * CreateAndFit(
+ cStructGenMineShafts::cMineShaftSystem & a_ParentSystem,
+ int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction,
+ cNoise & a_Noise
+ );
+
+protected:
+ cMineShaftCrossing(cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, const cCuboid & a_BoundingBox);
+
+ // cMineShaft overrides:
+ virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) override;
+ virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) override;
+} ;
+
+
+
+
+
+class cMineShaftStaircase :
+ public cMineShaft
+{
+ typedef cMineShaft super;
+
+public:
+ enum eSlope
+ {
+ sUp,
+ sDown,
+ } ;
+
+ /** Creates a new Staircase attached to the specified pivot point and direction.
+ Checks all ParentSystem's objects and disallows intersecting. Initializes the new object to fit.
+ May return NULL if cannot fit.
+ */
+ static cMineShaft * CreateAndFit(
+ cStructGenMineShafts::cMineShaftSystem & a_ParentSystem,
+ int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction,
+ cNoise & a_Noise
+ );
+
+protected:
+ eDirection m_Direction;
+ eSlope m_Slope;
+
+
+ cMineShaftStaircase(
+ cStructGenMineShafts::cMineShaftSystem & a_ParentSystem,
+ const cCuboid & a_BoundingBox,
+ eDirection a_Direction,
+ eSlope a_Slope
+ );
+
+ // cMineShaft overrides:
+ virtual void AppendBranches(int a_RecursionLevel, cNoise & a_Noise) override;
+ virtual void ProcessChunk(cChunkDesc & a_ChunkDesc) override;
+} ;
+
+
+
+
+
+class cStructGenMineShafts::cMineShaftSystem
+{
+public:
+ int m_BlockX, m_BlockZ; ///< The pivot point on which the system is generated
+ int m_GridSize; ///< Maximum offset of the dirtroom from grid center, * 2, in each direction
+ int m_MaxRecursion; ///< Maximum recursion level (initialized from cStructGenMineShafts::m_MaxRecursion)
+ int m_ProbLevelCorridor; ///< Probability level of a branch object being the corridor
+ int m_ProbLevelCrossing; ///< Probability level of a branch object being the crossing, minus Corridor
+ int m_ProbLevelStaircase; ///< Probability level of a branch object being the staircase, minus Crossing
+ int m_ChanceChest; ///< Chance [0 .. 250] that a corridor has a chest in it
+ int m_ChanceSpawner; ///< Chance [0 .. 250] that a corridor has a spawner in it
+ int m_ChanceTorch; ///< Chance [0 .. 10k] for a torch appearing attached to a corridor's beam
+ cMineShafts m_MineShafts; ///< List of cMineShaft descendants that comprise this system
+ cCuboid m_BoundingBox; ///< Bounding box into which all of the components need to fit
+
+ /// Creates and generates the entire system
+ cMineShaftSystem(
+ int a_BlockX, int a_BlockZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise,
+ int a_ProbLevelCorridor, int a_ProbLevelCrossing, int a_ProbLevelStaircase
+ );
+
+ ~cMineShaftSystem();
+
+ /// Carves the system into the chunk data
+ void ProcessChunk(cChunkDesc & a_Chunk);
+
+ /** Creates new cMineShaft descendant connected at the specified point, heading the specified direction,
+ if it fits, appends it to the list and calls its AppendBranches()
+ */
+ void AppendBranch(
+ int a_BlockX, int a_BlockY, int a_BlockZ,
+ cMineShaft::eDirection a_Direction, cNoise & a_Noise,
+ int a_RecursionLevel
+ );
+
+ /// Returns true if none of the objects in m_MineShafts intersect with the specified bounding box and the bounding box is valid
+ bool CanAppend(const cCuboid & a_BoundingBox);
+} ;
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cStructGenMineShafts::cMineShaftSystem:
+
+cStructGenMineShafts::cMineShaftSystem::cMineShaftSystem(
+ int a_BlockX, int a_BlockZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise,
+ int a_ProbLevelCorridor, int a_ProbLevelCrossing, int a_ProbLevelStaircase
+) :
+ m_BlockX(a_BlockX),
+ m_BlockZ(a_BlockZ),
+ m_GridSize(a_GridSize),
+ m_MaxRecursion(8), // TODO: settable
+ m_ProbLevelCorridor(a_ProbLevelCorridor),
+ m_ProbLevelCrossing(a_ProbLevelCrossing),
+ m_ProbLevelStaircase(a_ProbLevelStaircase + 1),
+ m_ChanceChest(12), // TODO: settable
+ m_ChanceSpawner(12), // TODO: settable
+ m_ChanceTorch(1000) // TODO: settable
+{
+ m_MineShafts.reserve(100);
+
+ cMineShaft * Start = new cMineShaftDirtRoom(*this, a_Noise);
+ m_MineShafts.push_back(Start);
+
+ m_BoundingBox.Assign(
+ Start->m_BoundingBox.p1.x - a_MaxSystemSize / 2, 2, Start->m_BoundingBox.p1.z - a_MaxSystemSize / 2,
+ Start->m_BoundingBox.p2.x + a_MaxSystemSize / 2, 50, Start->m_BoundingBox.p2.z + a_MaxSystemSize / 2
+ );
+
+ Start->AppendBranches(0, a_Noise);
+
+ for (cMineShafts::const_iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr)
+ {
+ ASSERT((*itr)->m_BoundingBox.IsSorted());
+ } // for itr - m_MineShafts[]
+}
+
+
+
+
+
+cStructGenMineShafts::cMineShaftSystem::~cMineShaftSystem()
+{
+ for (cMineShafts::iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ } // for itr - m_MineShafts[]
+ m_MineShafts.clear();
+}
+
+
+
+
+
+void cStructGenMineShafts::cMineShaftSystem::ProcessChunk(cChunkDesc & a_Chunk)
+{
+ for (cMineShafts::const_iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr)
+ {
+ (*itr)->ProcessChunk(a_Chunk);
+ } // for itr - m_MineShafts[]
+}
+
+
+
+
+
+void cStructGenMineShafts::cMineShaftSystem::AppendBranch(
+ int a_PivotX, int a_PivotY, int a_PivotZ,
+ cMineShaft::eDirection a_Direction, cNoise & a_Noise,
+ int a_RecursionLevel
+)
+{
+ if (a_RecursionLevel > m_MaxRecursion)
+ {
+ return;
+ }
+
+ cMineShaft * Next = NULL;
+ int rnd = (a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_RecursionLevel * 16, a_PivotZ) / 13) % m_ProbLevelStaircase;
+ if (rnd < m_ProbLevelCorridor)
+ {
+ Next = cMineShaftCorridor::CreateAndFit(*this, a_PivotX, a_PivotY, a_PivotZ, a_Direction, a_Noise);
+ }
+ else if (rnd < m_ProbLevelCrossing)
+ {
+ Next = cMineShaftCrossing::CreateAndFit(*this, a_PivotX, a_PivotY, a_PivotZ, a_Direction, a_Noise);
+ }
+ else
+ {
+ Next = cMineShaftStaircase::CreateAndFit(*this, a_PivotX, a_PivotY, a_PivotZ, a_Direction, a_Noise);
+ }
+ if (Next == NULL)
+ {
+ return;
+ }
+ m_MineShafts.push_back(Next);
+ Next->AppendBranches(a_RecursionLevel + 1, a_Noise);
+}
+
+
+
+
+
+bool cStructGenMineShafts::cMineShaftSystem::CanAppend(const cCuboid & a_BoundingBox)
+{
+ if (!a_BoundingBox.IsCompletelyInside(m_BoundingBox))
+ {
+ // Too far away, or too low / too high
+ return false;
+ }
+
+ // Check intersections:
+ for (cMineShafts::const_iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr)
+ {
+ if ((*itr)->DoesIntersect(a_BoundingBox))
+ {
+ return false;
+ }
+ } // for itr - m_MineShafts[]
+ return true;
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cMineShaftDirtRoom:
+
+cMineShaftDirtRoom::cMineShaftDirtRoom(cStructGenMineShafts::cMineShaftSystem & a_Parent, cNoise & a_Noise) :
+ super(a_Parent, mskDirtRoom)
+{
+ // Make the room of random size, min 10 x 4 x 10; max 18 x 12 x 18:
+ int rnd = a_Noise.IntNoise3DInt(a_Parent.m_BlockX, 0, a_Parent.m_BlockZ) / 7;
+ int OfsX = (rnd % a_Parent.m_GridSize) - a_Parent.m_GridSize / 2;
+ rnd >>= 12;
+ int OfsZ = (rnd % a_Parent.m_GridSize) - a_Parent.m_GridSize / 2;
+ rnd = a_Noise.IntNoise3DInt(a_Parent.m_BlockX, 1000, a_Parent.m_BlockZ) / 11;
+ m_BoundingBox.p1.x = a_Parent.m_BlockX + OfsX;
+ m_BoundingBox.p2.x = m_BoundingBox.p1.x + 10 + (rnd % 8);
+ rnd >>= 4;
+ m_BoundingBox.p1.z = a_Parent.m_BlockZ + OfsZ;
+ m_BoundingBox.p2.z = m_BoundingBox.p1.z + 10 + (rnd % 8);
+ rnd >>= 4;
+ m_BoundingBox.p1.y = 20;
+ m_BoundingBox.p2.y = 24 + rnd % 8;
+}
+
+
+
+
+
+void cMineShaftDirtRoom::AppendBranches(int a_RecursionLevel, cNoise & a_Noise)
+{
+ int Height = m_BoundingBox.DifY() - 3;
+ for (int x = m_BoundingBox.p1.x + 1; x < m_BoundingBox.p2.x; x += 4)
+ {
+ int rnd = a_Noise.IntNoise3DInt(x, a_RecursionLevel, m_BoundingBox.p1.z) / 7;
+ m_ParentSystem.AppendBranch(x, m_BoundingBox.p1.y + (rnd % Height), m_BoundingBox.p1.z - 1, dirZM, a_Noise, a_RecursionLevel);
+ rnd >>= 4;
+ m_ParentSystem.AppendBranch(x, m_BoundingBox.p1.y + (rnd % Height), m_BoundingBox.p2.z + 1, dirZP, a_Noise, a_RecursionLevel);
+ }
+
+ for (int z = m_BoundingBox.p1.z + 1; z < m_BoundingBox.p2.z; z += 4)
+ {
+ int rnd = a_Noise.IntNoise3DInt(m_BoundingBox.p1.x, a_RecursionLevel, z) / 13;
+ m_ParentSystem.AppendBranch(m_BoundingBox.p1.x - 1, m_BoundingBox.p1.y + (rnd % Height), z, dirXM, a_Noise, a_RecursionLevel);
+ rnd >>= 4;
+ m_ParentSystem.AppendBranch(m_BoundingBox.p2.x + 1, m_BoundingBox.p1.y + (rnd % Height), z, dirXP, a_Noise, a_RecursionLevel);
+ }
+}
+
+
+
+
+
+void cMineShaftDirtRoom::ProcessChunk(cChunkDesc & a_ChunkDesc)
+{
+ int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
+ if (
+ (m_BoundingBox.p1.x > BlockX + cChunkDef::Width) ||
+ (m_BoundingBox.p1.z > BlockZ + cChunkDef::Width) ||
+ (m_BoundingBox.p2.x < BlockX) ||
+ (m_BoundingBox.p2.z < BlockZ)
+ )
+ {
+ // Early bailout - cannot intersect this chunk
+ return;
+ }
+
+ // Chunk-relative coords of the boundaries:
+ int MinX = std::max(BlockX, m_BoundingBox.p1.x) - BlockX;
+ int MaxX = std::min(BlockX + cChunkDef::Width, m_BoundingBox.p2.x + 1) - BlockX;
+ int MinZ = std::max(BlockZ, m_BoundingBox.p1.z) - BlockZ;
+ int MaxZ = std::min(BlockZ + cChunkDef::Width, m_BoundingBox.p2.z + 1) - BlockZ;
+
+ // Carve the room out:
+ for (int z = MinZ; z < MaxZ; z++)
+ {
+ for (int x = MinX; x < MaxX; x++)
+ {
+ for (int y = m_BoundingBox.p1.y + 1; y < m_BoundingBox.p2.y; y++)
+ {
+ a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_AIR);
+ }
+ if (a_ChunkDesc.GetBlockType(x, m_BoundingBox.p1.y, z) != E_BLOCK_AIR)
+ {
+ a_ChunkDesc.SetBlockType(x, m_BoundingBox.p1.y, z, E_BLOCK_DIRT);
+ }
+ } // for x
+ } // for z
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cMineShaftCorridor:
+
+cMineShaftCorridor::cMineShaftCorridor(
+ cStructGenMineShafts::cMineShaftSystem & a_ParentSystem,
+ const cCuboid & a_BoundingBox, int a_NumSegments, eDirection a_Direction,
+ cNoise & a_Noise
+) :
+ super(a_ParentSystem, mskCorridor, a_BoundingBox),
+ m_NumSegments(a_NumSegments),
+ m_Direction(a_Direction),
+ m_ChestPosition(-1),
+ m_SpawnerPosition(-1)
+{
+ int rnd = a_Noise.IntNoise3DInt(a_BoundingBox.p1.x, a_BoundingBox.p1.y, a_BoundingBox.p1.z) / 7;
+ for (int i = 0; i < a_NumSegments; i++)
+ {
+ m_HasFullBeam[i] = (rnd % 4) < 3; // 75 % chance of full beam
+ rnd >>= 2;
+ }
+ m_HasTracks = ((rnd % 4) < 2); // 50 % chance of tracks
+
+ rnd = a_Noise.IntNoise3DInt(a_BoundingBox.p1.z, a_BoundingBox.p1.x, a_BoundingBox.p1.y) / 7;
+ int ChestCheck = rnd % 250;
+ rnd >>= 8;
+ int SpawnerCheck = rnd % 250;
+ rnd >>= 8;
+ if (ChestCheck < a_ParentSystem.m_ChanceChest)
+ {
+ m_ChestPosition = rnd % (a_NumSegments * 5);
+ }
+ if ((a_NumSegments < 4) && (SpawnerCheck < a_ParentSystem.m_ChanceSpawner))
+ {
+ m_SpawnerPosition = rnd % (a_NumSegments * 5);
+ }
+}
+
+
+
+
+
+cMineShaft * cMineShaftCorridor::CreateAndFit(
+ cStructGenMineShafts::cMineShaftSystem & a_ParentSystem,
+ int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction,
+ cNoise & a_Noise
+)
+{
+ cCuboid BoundingBox(a_PivotX, a_PivotY - 1, a_PivotZ);
+ BoundingBox.p2.y += 3;
+ int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7;
+ int NumSegments = 2 + (rnd) % (MAX_SEGMENTS - 1); // 2 .. MAX_SEGMENTS
+ switch (a_Direction)
+ {
+ case dirXP: BoundingBox.p2.x += NumSegments * 5 - 1; BoundingBox.p1.z -= 1; BoundingBox.p2.z += 1; break;
+ case dirXM: BoundingBox.p1.x -= NumSegments * 5 - 1; BoundingBox.p1.z -= 1; BoundingBox.p2.z += 1; break;
+ case dirZP: BoundingBox.p2.z += NumSegments * 5 - 1; BoundingBox.p1.x -= 1; BoundingBox.p2.x += 1; break;
+ case dirZM: BoundingBox.p1.z -= NumSegments * 5 - 1; BoundingBox.p1.x -= 1; BoundingBox.p2.x += 1; break;
+ }
+ if (!a_ParentSystem.CanAppend(BoundingBox))
+ {
+ return NULL;
+ }
+ return new cMineShaftCorridor(a_ParentSystem, BoundingBox, NumSegments, a_Direction, a_Noise);
+}
+
+
+
+
+
+void cMineShaftCorridor::AppendBranches(int a_RecursionLevel, cNoise & a_Noise)
+{
+ int rnd = a_Noise.IntNoise3DInt(m_BoundingBox.p1.x, m_BoundingBox.p1.y + a_RecursionLevel, m_BoundingBox.p1.z) / 7;
+ // Prefer the same height, but allow for up to one block height displacement:
+ int Height = m_BoundingBox.p1.y + ((rnd % 4) + ((rnd >> 3) % 3)) / 2;
+ switch (m_Direction)
+ {
+ case dirXM:
+ {
+ m_ParentSystem.AppendBranch(m_BoundingBox.p1.x - 1, Height, m_BoundingBox.p1.z + 1, dirXM, a_Noise, a_RecursionLevel);
+ for (int i = m_NumSegments; i >= 0; i--)
+ {
+ int rnd = a_Noise.IntNoise3DInt(m_BoundingBox.p1.x + i + 10, m_BoundingBox.p1.y + a_RecursionLevel, m_BoundingBox.p1.z) / 11;
+ int Height = m_BoundingBox.p1.y + ((rnd % 4) + ((rnd >> 3) % 3)) / 2;
+ rnd >>= 6;
+ int Ofs = 1 + rnd % (m_NumSegments * 5 - 2);
+ m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + Ofs, Height, m_BoundingBox.p1.z - 1, dirZM, a_Noise, a_RecursionLevel);
+ m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + Ofs, Height, m_BoundingBox.p2.z + 1, dirZP, a_Noise, a_RecursionLevel);
+ }
+ break;
+ }
+
+ case dirXP:
+ {
+ m_ParentSystem.AppendBranch(m_BoundingBox.p2.x + 1, Height, m_BoundingBox.p1.z + 1, dirXP, a_Noise, a_RecursionLevel);
+ for (int i = m_NumSegments; i >= 0; i--)
+ {
+ int rnd = a_Noise.IntNoise3DInt(m_BoundingBox.p1.x + i + 10, m_BoundingBox.p1.y + a_RecursionLevel, m_BoundingBox.p1.z) / 11;
+ int Height = m_BoundingBox.p1.y + ((rnd % 4) + ((rnd >> 3) % 3)) / 2;
+ rnd >>= 6;
+ int Ofs = 1 + rnd % (m_NumSegments * 5 - 2);
+ m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + Ofs, Height, m_BoundingBox.p1.z - 1, dirZM, a_Noise, a_RecursionLevel);
+ m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + Ofs, Height, m_BoundingBox.p2.z + 1, dirZP, a_Noise, a_RecursionLevel);
+ }
+ break;
+ }
+
+ case dirZM:
+ {
+ m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + 1, Height, m_BoundingBox.p1.z - 1, dirZM, a_Noise, a_RecursionLevel);
+ for (int i = m_NumSegments; i >= 0; i--)
+ {
+ int rnd = a_Noise.IntNoise3DInt(m_BoundingBox.p1.x + i + 10, m_BoundingBox.p1.y + a_RecursionLevel, m_BoundingBox.p1.z) / 11;
+ int Height = m_BoundingBox.p1.y + ((rnd % 4) + ((rnd >> 3) % 3)) / 2;
+ rnd >>= 6;
+ int Ofs = 1 + rnd % (m_NumSegments * 5 - 2);
+ m_ParentSystem.AppendBranch(m_BoundingBox.p1.x - 1, Height, m_BoundingBox.p1.z + Ofs, dirXM, a_Noise, a_RecursionLevel);
+ m_ParentSystem.AppendBranch(m_BoundingBox.p2.x + 1, Height, m_BoundingBox.p1.z + Ofs, dirXP, a_Noise, a_RecursionLevel);
+ }
+ break;
+ }
+
+ case dirZP:
+ {
+ m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + 1, Height, m_BoundingBox.p2.z + 1, dirZP, a_Noise, a_RecursionLevel);
+ for (int i = m_NumSegments; i >= 0; i--)
+ {
+ int rnd = a_Noise.IntNoise3DInt(m_BoundingBox.p1.x + i + 10, m_BoundingBox.p1.y + a_RecursionLevel, m_BoundingBox.p1.z) / 11;
+ int Height = m_BoundingBox.p1.y + ((rnd % 4) + ((rnd >> 3) % 3)) / 2;
+ rnd >>= 6;
+ int Ofs = 1 + rnd % (m_NumSegments * 5 - 2);
+ m_ParentSystem.AppendBranch(m_BoundingBox.p1.x - 1, Height, m_BoundingBox.p1.z + Ofs, dirXM, a_Noise, a_RecursionLevel);
+ m_ParentSystem.AppendBranch(m_BoundingBox.p2.x + 1, Height, m_BoundingBox.p1.z + Ofs, dirXP, a_Noise, a_RecursionLevel);
+ }
+ break;
+ }
+ } // switch (m_Direction)
+}
+
+
+
+
+
+void cMineShaftCorridor::ProcessChunk(cChunkDesc & a_ChunkDesc)
+{
+ int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
+ cCuboid RelBoundingBox(m_BoundingBox);
+ RelBoundingBox.Move(-BlockX, 0, -BlockZ);
+ RelBoundingBox.p1.y += 1;
+ RelBoundingBox.p2.y -= 1;
+ cCuboid Top(RelBoundingBox);
+ Top.p2.y += 1;
+ Top.p1.y = Top.p2.y;
+ a_ChunkDesc.FillRelCuboid(RelBoundingBox, E_BLOCK_AIR, 0);
+ a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_AIR, 0, (BlockX ^ (BlockZ + BlockX)), 8000);
+ if (m_SpawnerPosition >= 0)
+ {
+ // Cobwebs around the spider spawner
+ a_ChunkDesc.RandomFillRelCuboid(RelBoundingBox, E_BLOCK_COBWEB, 0, (BlockX ^ (BlockZ + BlockZ)), 8000);
+ a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_COBWEB, 0, (BlockX ^ (BlockZ + BlockX)), 5000);
+ }
+ a_ChunkDesc.RandomFillRelCuboid(Top, E_BLOCK_COBWEB, 0, (BlockX ^ (BlockZ + BlockX + 10)), 500);
+ RelBoundingBox.p1.y = m_BoundingBox.p1.y;
+ RelBoundingBox.p2.y = m_BoundingBox.p1.y;
+ a_ChunkDesc.FloorRelCuboid(RelBoundingBox, E_BLOCK_PLANKS, 0);
+ switch (m_Direction)
+ {
+ case dirXM:
+ case dirXP:
+ {
+ int y1 = m_BoundingBox.p1.y + 1;
+ int y2 = m_BoundingBox.p1.y + 2;
+ int y3 = m_BoundingBox.p1.y + 3;
+ int z1 = m_BoundingBox.p1.z - BlockZ;
+ int z2 = m_BoundingBox.p2.z - BlockZ;
+ for (int i = 0; i < m_NumSegments; i++)
+ {
+ int x = m_BoundingBox.p1.x + i * 5 + 2 - BlockX;
+ if ((x < 0) || (x >= cChunkDef::Width))
+ {
+ continue;
+ }
+ if ((z1 >= 0) && (z1 < cChunkDef::Width))
+ {
+ a_ChunkDesc.SetBlockTypeMeta(x, y1, z1, E_BLOCK_FENCE, 0);
+ a_ChunkDesc.SetBlockTypeMeta(x, y2, z1, E_BLOCK_FENCE, 0);
+ a_ChunkDesc.SetBlockTypeMeta(x, y3, z1, E_BLOCK_PLANKS, 0);
+ }
+ if ((z2 >= 0) && (z2 < cChunkDef::Width))
+ {
+ a_ChunkDesc.SetBlockTypeMeta(x, y1, z2, E_BLOCK_FENCE, 0);
+ a_ChunkDesc.SetBlockTypeMeta(x, y2, z2, E_BLOCK_FENCE, 0);
+ a_ChunkDesc.SetBlockTypeMeta(x, y3, z2, E_BLOCK_PLANKS, 0);
+ }
+ if ((z1 >= -1) && (z1 < cChunkDef::Width - 1) && m_HasFullBeam[i])
+ {
+ a_ChunkDesc.SetBlockTypeMeta(x, y3, z1 + 1, E_BLOCK_PLANKS, 0);
+ }
+ } // for i - NumSegments
+ break;
+ }
+
+ case dirZM:
+ case dirZP:
+ {
+ int y1 = m_BoundingBox.p1.y + 1;
+ int y2 = m_BoundingBox.p1.y + 2;
+ int y3 = m_BoundingBox.p1.y + 3;
+ int x1 = m_BoundingBox.p1.x - BlockX;
+ int x2 = m_BoundingBox.p2.x - BlockX;
+ for (int i = 0; i < m_NumSegments; i++)
+ {
+ int z = m_BoundingBox.p1.z + i * 5 + 2 - BlockZ;
+ if ((z < 0) || (z >= cChunkDef::Width))
+ {
+ continue;
+ }
+ if ((x1 >= 0) && (x1 < cChunkDef::Width))
+ {
+ a_ChunkDesc.SetBlockTypeMeta(x1, y1, z, E_BLOCK_FENCE, 0);
+ a_ChunkDesc.SetBlockTypeMeta(x1, y2, z, E_BLOCK_FENCE, 0);
+ a_ChunkDesc.SetBlockTypeMeta(x1, y3, z, E_BLOCK_PLANKS, 0);
+ }
+ if ((x2 >= 0) && (x2 < cChunkDef::Width))
+ {
+ a_ChunkDesc.SetBlockTypeMeta(x2, y1, z, E_BLOCK_FENCE, 0);
+ a_ChunkDesc.SetBlockTypeMeta(x2, y2, z, E_BLOCK_FENCE, 0);
+ a_ChunkDesc.SetBlockTypeMeta(x2, y3, z, E_BLOCK_PLANKS, 0);
+ }
+ if ((x1 >= -1) && (x1 < cChunkDef::Width - 1) && m_HasFullBeam[i])
+ {
+ a_ChunkDesc.SetBlockTypeMeta(x1 + 1, y3, z, E_BLOCK_PLANKS, 0);
+ }
+ } // for i - NumSegments
+ break;
+ } // case dirZ?
+ } // for i
+
+ PlaceChest(a_ChunkDesc);
+ PlaceTracks(a_ChunkDesc);
+ PlaceSpawner(a_ChunkDesc); // (must be after Tracks!)
+ PlaceTorches(a_ChunkDesc);
+}
+
+
+
+
+
+void cMineShaftCorridor::PlaceChest(cChunkDesc & a_ChunkDesc)
+{
+ static const cLootProbab LootProbab[] =
+ {
+ // Item, MinAmount, MaxAmount, Weight
+ { cItem(E_ITEM_IRON), 1, 5, 10 },
+ { cItem(E_ITEM_GOLD), 1, 3, 5 },
+ { cItem(E_ITEM_REDSTONE_DUST), 4, 9, 5 },
+ { cItem(E_ITEM_DIAMOND), 1, 2, 3 },
+ { cItem(E_ITEM_DYE, 1, 4), 4, 9, 5 }, // lapis lazuli dye
+ { cItem(E_ITEM_COAL), 3, 8, 10 },
+ { cItem(E_ITEM_BREAD), 1, 3, 15 },
+ { cItem(E_ITEM_IRON_PICKAXE), 1, 1, 1 },
+ { cItem(E_BLOCK_MINECART_TRACKS), 4, 8, 1 },
+ { cItem(E_ITEM_MELON_SEEDS), 2, 4, 10 },
+ { cItem(E_ITEM_PUMPKIN_SEEDS), 2, 4, 10 },
+ } ;
+
+ if (m_ChestPosition < 0)
+ {
+ return;
+ }
+
+ int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
+ int x, z;
+ NIBBLETYPE Meta = 0;
+ switch (m_Direction)
+ {
+ case dirXM:
+ case dirXP:
+ {
+ x = m_BoundingBox.p1.x + m_ChestPosition - BlockX;
+ z = m_BoundingBox.p1.z - BlockZ;
+ Meta = E_META_CHEST_FACING_ZP;
+ break;
+ }
+
+ case dirZM:
+ case dirZP:
+ default:
+ {
+ x = m_BoundingBox.p1.x - BlockX;
+ z = m_BoundingBox.p1.z + m_ChestPosition - BlockZ;
+ Meta = E_META_CHEST_FACING_XP;
+ break;
+ }
+ } // switch (Dir)
+
+ if (
+ (x >= 0) && (x < cChunkDef::Width) &&
+ (z >= 0) && (z < cChunkDef::Width)
+ )
+ {
+ a_ChunkDesc.SetBlockTypeMeta(x, m_BoundingBox.p1.y + 1, z, E_BLOCK_CHEST, Meta);
+ cChestEntity * ChestEntity = (cChestEntity *)a_ChunkDesc.GetBlockEntity(x, m_BoundingBox.p1.y + 1, z);
+ ASSERT((ChestEntity != NULL) && (ChestEntity->GetBlockType() == E_BLOCK_CHEST));
+ cNoise Noise(a_ChunkDesc.GetChunkX() ^ a_ChunkDesc.GetChunkZ());
+ int NumSlots = 3 + ((Noise.IntNoise3DInt(x, m_BoundingBox.p1.y, z) / 11) % 4);
+ int Seed = Noise.IntNoise2DInt(x, z);
+ ChestEntity->GetContents().GenerateRandomLootWithBooks(LootProbab, ARRAYCOUNT(LootProbab), NumSlots, Seed);
+ }
+}
+
+
+
+
+
+void cMineShaftCorridor::PlaceTracks(cChunkDesc & a_ChunkDesc)
+{
+ if (!m_HasTracks)
+ {
+ return;
+ }
+ cCuboid Box(m_BoundingBox);
+ Box.Move(-a_ChunkDesc.GetChunkX() * cChunkDef::Width, 1, -a_ChunkDesc.GetChunkZ() * cChunkDef::Width);
+ Box.p2.y = Box.p1.y;
+ Box.p1.x += 1;
+ Box.p2.x -= 1;
+ Box.p1.z += 1;
+ Box.p2.z -= 1;
+ NIBBLETYPE Meta = 0;
+ switch (m_Direction)
+ {
+ case dirXM:
+ case dirXP:
+ {
+ Meta = E_META_TRACKS_X;
+ break;
+ }
+
+ case dirZM:
+ case dirZP:
+ {
+ Meta = E_META_TRACKS_Z;
+ break;
+ }
+ } // switch (direction)
+ a_ChunkDesc.RandomFillRelCuboid(Box, E_BLOCK_MINECART_TRACKS, Meta, a_ChunkDesc.GetChunkX() + a_ChunkDesc.GetChunkZ(), 6000);
+}
+
+
+
+
+
+void cMineShaftCorridor::PlaceSpawner(cChunkDesc & a_ChunkDesc)
+{
+ if (m_SpawnerPosition < 0)
+ {
+ // No spawner in this corridor
+ return;
+ }
+ int SpawnerRelX = m_BoundingBox.p1.x + 1 - a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ int SpawnerRelZ = m_BoundingBox.p1.z + 1 - a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
+ switch (m_Direction)
+ {
+ case dirXM:
+ case dirXP:
+ {
+ SpawnerRelX += m_SpawnerPosition - 1;
+ break;
+ }
+ case dirZM:
+ case dirZP:
+ {
+ SpawnerRelZ += m_SpawnerPosition - 1;
+ break;
+ }
+ }
+ if (
+ (SpawnerRelX >= 0) && (SpawnerRelX < cChunkDef::Width) &&
+ (SpawnerRelZ >= 0) && (SpawnerRelZ < cChunkDef::Width)
+ )
+ {
+ a_ChunkDesc.SetBlockTypeMeta(SpawnerRelX, m_BoundingBox.p1.y + 1, SpawnerRelZ, E_BLOCK_MOB_SPAWNER, 0);
+ // TODO: The spawner needs its accompanying cMobSpawnerEntity, when implemented
+ }
+}
+
+
+
+
+
+void cMineShaftCorridor::PlaceTorches(cChunkDesc & a_ChunkDesc)
+{
+ cNoise Noise(m_BoundingBox.p1.x);
+ switch (m_Direction)
+ {
+ case dirXM:
+ case dirXP:
+ {
+ int z = m_BoundingBox.p1.z + 1 - a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
+ if ((z < 0) || (z >= cChunkDef::Width))
+ {
+ return;
+ }
+ int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ for (int i = 0; i < m_NumSegments; i++)
+ {
+ if (!m_HasFullBeam[i])
+ {
+ continue;
+ }
+ int x = m_BoundingBox.p1.x + i * 5 + 1 - BlockX;
+ if ((x >= 0) && (x < cChunkDef::Width))
+ {
+ if (((Noise.IntNoise2DInt(x, z) / 7) % 10000) < m_ParentSystem.m_ChanceTorch)
+ {
+ a_ChunkDesc.SetBlockTypeMeta(x, m_BoundingBox.p2.y, z, E_BLOCK_TORCH, E_META_TORCH_XP);
+ }
+ }
+ x += 2;
+ if ((x >= 0) && (x < cChunkDef::Width))
+ {
+ if (((Noise.IntNoise2DInt(x, z) / 7) % 10000) < m_ParentSystem.m_ChanceTorch)
+ {
+ a_ChunkDesc.SetBlockTypeMeta(x, m_BoundingBox.p2.y, z, E_BLOCK_TORCH, E_META_TORCH_XM);
+ }
+ }
+ } // for i
+ break;
+ }
+
+ case dirZM:
+ case dirZP:
+ {
+ int x = m_BoundingBox.p1.x + 1 - a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ if ((x < 0) || (x >= cChunkDef::Width))
+ {
+ return;
+ }
+ int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
+ for (int i = 0; i < m_NumSegments; i++)
+ {
+ if (!m_HasFullBeam[i])
+ {
+ continue;
+ }
+ int z = m_BoundingBox.p1.z + i * 5 + 1 - BlockZ;
+ if ((z >= 0) && (z < cChunkDef::Width))
+ {
+ if (((Noise.IntNoise2DInt(x, z) / 7) % 10000) < m_ParentSystem.m_ChanceTorch)
+ {
+ a_ChunkDesc.SetBlockTypeMeta(x, m_BoundingBox.p2.y, z, E_BLOCK_TORCH, E_META_TORCH_ZP);
+ }
+ }
+ z += 2;
+ if ((z >= 0) && (z < cChunkDef::Width))
+ {
+ if (((Noise.IntNoise2DInt(x, z) / 7) % 10000) < m_ParentSystem.m_ChanceTorch)
+ {
+ a_ChunkDesc.SetBlockTypeMeta(x, m_BoundingBox.p2.y, z, E_BLOCK_TORCH, E_META_TORCH_ZM);
+ }
+ }
+ } // for i
+ break;
+ }
+ } // switch (direction)
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cMineShaftCrossing:
+
+cMineShaftCrossing::cMineShaftCrossing(cStructGenMineShafts::cMineShaftSystem & a_ParentSystem, const cCuboid & a_BoundingBox) :
+ super(a_ParentSystem, mskCrossing, a_BoundingBox)
+{
+}
+
+
+
+
+
+cMineShaft * cMineShaftCrossing::CreateAndFit(
+ cStructGenMineShafts::cMineShaftSystem & a_ParentSystem,
+ int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction,
+ cNoise & a_Noise
+)
+{
+ cCuboid BoundingBox(a_PivotX, a_PivotY - 1, a_PivotZ);
+ int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7;
+ BoundingBox.p2.y += 3;
+ if ((rnd % 4) < 2)
+ {
+ // 2-level crossing:
+ BoundingBox.p2.y += 4;
+ rnd >>= 2;
+ if ((rnd % 4) < 2)
+ {
+ // This is the higher level:
+ BoundingBox.p1.y -= 4;
+ BoundingBox.p2.y -= 4;
+ }
+ }
+ rnd >>= 2;
+ switch (a_Direction)
+ {
+ case dirXP: BoundingBox.p2.x += 4; BoundingBox.p1.z -= 2; BoundingBox.p2.z += 2; break;
+ case dirXM: BoundingBox.p1.x -= 4; BoundingBox.p1.z -= 2; BoundingBox.p2.z += 2; break;
+ case dirZP: BoundingBox.p2.z += 4; BoundingBox.p1.x -= 2; BoundingBox.p2.x += 2; break;
+ case dirZM: BoundingBox.p1.z -= 4; BoundingBox.p1.x -= 2; BoundingBox.p2.x += 2; break;
+ }
+ if (!a_ParentSystem.CanAppend(BoundingBox))
+ {
+ return NULL;
+ }
+ return new cMineShaftCrossing(a_ParentSystem, BoundingBox);
+}
+
+
+
+
+
+void cMineShaftCrossing::AppendBranches(int a_RecursionLevel, cNoise & a_Noise)
+{
+ struct
+ {
+ int x, y, z;
+ eDirection dir;
+ } Exits[] =
+ {
+ // Bottom level:
+ {-1, 1, 2, dirXM},
+ { 2, 1, -1, dirZM},
+ { 5, 1, 2, dirXP},
+ { 2, 1, 5, dirZP},
+ // Top level:
+ {-1, 5, 2, dirXM},
+ { 2, 5, -1, dirZM},
+ { 5, 5, 2, dirXP},
+ { 2, 5, 5, dirZP},
+ } ;
+ for (unsigned int i = 0; i < ARRAYCOUNT(Exits); i++)
+ {
+ if (m_BoundingBox.p1.y + Exits[i].y >= m_BoundingBox.p2.y)
+ {
+ // This exit is not available (two-level exit on a one-level crossing)
+ continue;
+ }
+
+ int Height = m_BoundingBox.p1.y + Exits[i].y;
+ 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);
+ } // for i
+}
+
+
+
+
+
+void cMineShaftCrossing::ProcessChunk(cChunkDesc & a_ChunkDesc)
+{
+ int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
+ cCuboid box(m_BoundingBox);
+ box.Move(-BlockX, 0, -BlockZ);
+ if ((box.p2.x < 0) || (box.p2.z < 0) || (box.p1.x >= cChunkDef::Width) || (box.p1.z > cChunkDef::Width))
+ {
+ // Does not intersect this chunk
+ return;
+ }
+ int Floor = box.p1.y + 1;
+ int Ceil = box.p2.y;
+
+ // The supports:
+ 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);
+ 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);
+ 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);
+ 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);
+
+ // The air in between:
+ 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);
+ 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);
+
+ // The air on the edges:
+ int Mid = Floor + 2;
+ a_ChunkDesc.FillRelCuboid(box.p1.x, box.p1.x, Floor, Mid, box.p1.z + 1, box.p2.z - 1, E_BLOCK_AIR, 0);
+ a_ChunkDesc.FillRelCuboid(box.p2.x, box.p2.x, Floor, Mid, box.p1.z + 1, box.p2.z - 1, E_BLOCK_AIR, 0);
+ a_ChunkDesc.FillRelCuboid(box.p1.x + 1, box.p2.x - 1, Floor, Mid, box.p1.z, box.p1.z, E_BLOCK_AIR, 0);
+ a_ChunkDesc.FillRelCuboid(box.p1.x + 1, box.p2.x - 1, Floor, Mid, box.p2.z, box.p2.z, E_BLOCK_AIR, 0);
+ Mid += 2;
+ if (Mid < Ceil)
+ {
+ a_ChunkDesc.FillRelCuboid(box.p1.x, box.p1.x, Mid, Ceil, box.p1.z + 1, box.p2.z - 1, E_BLOCK_AIR, 0);
+ a_ChunkDesc.FillRelCuboid(box.p2.x, box.p2.x, Mid, Ceil, box.p1.z + 1, box.p2.z - 1, E_BLOCK_AIR, 0);
+ a_ChunkDesc.FillRelCuboid(box.p1.x + 1, box.p2.x - 1, Mid, Ceil, box.p1.z, box.p1.z, E_BLOCK_AIR, 0);
+ a_ChunkDesc.FillRelCuboid(box.p1.x + 1, box.p2.x - 1, Mid, Ceil, box.p2.z, box.p2.z, E_BLOCK_AIR, 0);
+ }
+
+ // The floor, if needed:
+ box.p2.y = box.p1.y;
+ a_ChunkDesc.FloorRelCuboid(box, E_BLOCK_PLANKS, 0);
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cMineShaftStaircase:
+
+cMineShaftStaircase::cMineShaftStaircase(
+ cStructGenMineShafts::cMineShaftSystem & a_ParentSystem,
+ const cCuboid & a_BoundingBox,
+ eDirection a_Direction,
+ eSlope a_Slope
+) :
+ super(a_ParentSystem, mskStaircase, a_BoundingBox),
+ m_Direction(a_Direction),
+ m_Slope(a_Slope)
+{
+}
+
+
+
+
+
+cMineShaft * cMineShaftStaircase::CreateAndFit(
+ cStructGenMineShafts::cMineShaftSystem & a_ParentSystem,
+ int a_PivotX, int a_PivotY, int a_PivotZ, eDirection a_Direction,
+ cNoise & a_Noise
+)
+{
+ int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7;
+ cCuboid Box;
+ switch (a_Direction)
+ {
+ case dirXM:
+ {
+ Box.Assign(a_PivotX - 7, a_PivotY - 1, a_PivotZ - 1, a_PivotX, a_PivotY + 6, a_PivotZ + 1);
+ break;
+ }
+ case dirXP:
+ {
+ Box.Assign(a_PivotX, a_PivotY - 1, a_PivotZ - 1, a_PivotX + 7, a_PivotY + 6, a_PivotZ + 1);
+ break;
+ }
+ case dirZM:
+ {
+ Box.Assign(a_PivotX - 1, a_PivotY - 1, a_PivotZ - 7, a_PivotX + 1, a_PivotY + 6, a_PivotZ);
+ break;
+ }
+ case dirZP:
+ {
+ Box.Assign(a_PivotX - 1, a_PivotY - 1, a_PivotZ, a_PivotX + 1, a_PivotY + 6, a_PivotZ + 7);
+ break;
+ }
+ }
+ eSlope Slope = sUp;
+ if ((rnd % 4) < 2) // 50 %
+ {
+ Slope = sDown;
+ Box.Move(0, -4, 0);
+ }
+ if (!a_ParentSystem.CanAppend(Box))
+ {
+ return NULL;
+ }
+ return new cMineShaftStaircase(a_ParentSystem, Box, a_Direction, Slope);
+}
+
+
+
+
+
+void cMineShaftStaircase::AppendBranches(int a_RecursionLevel, cNoise & a_Noise)
+{
+ int Height = m_BoundingBox.p1.y + ((m_Slope == sDown) ? 1 : 5);
+ switch (m_Direction)
+ {
+ case dirXM: m_ParentSystem.AppendBranch(m_BoundingBox.p1.x - 1, Height, m_BoundingBox.p1.z + 1, dirXM, a_Noise, a_RecursionLevel); break;
+ case dirXP: m_ParentSystem.AppendBranch(m_BoundingBox.p2.x + 1, Height, m_BoundingBox.p1.z + 1, dirXP, a_Noise, a_RecursionLevel); break;
+ case dirZM: m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + 1, Height, m_BoundingBox.p1.z - 1, dirZM, a_Noise, a_RecursionLevel); break;
+ case dirZP: m_ParentSystem.AppendBranch(m_BoundingBox.p1.x + 1, Height, m_BoundingBox.p2.z + 1, dirZP, a_Noise, a_RecursionLevel); break;
+ }
+}
+
+
+
+
+
+void cMineShaftStaircase::ProcessChunk(cChunkDesc & a_ChunkDesc)
+{
+ int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
+ cCuboid RelB(m_BoundingBox);
+ RelB.Move(-BlockX, 0, -BlockZ);
+ if (
+ (RelB.p1.x >= cChunkDef::Width) ||
+ (RelB.p1.z >= cChunkDef::Width) ||
+ (RelB.p2.x < 0) ||
+ (RelB.p2.z < 0)
+ )
+ {
+ // No intersection between this staircase and this chunk
+ return;
+ }
+
+ int SFloor = RelB.p1.y + ((m_Slope == sDown) ? 5 : 1);
+ int DFloor = RelB.p1.y + ((m_Slope == sDown) ? 1 : 5);
+ int Add = (m_Slope == sDown) ? -1 : 1;
+ int InitAdd = (m_Slope == sDown) ? -1 : 0;
+ cCuboid Box;
+ switch (m_Direction)
+ {
+ case dirXM:
+ {
+ a_ChunkDesc.FillRelCuboid (RelB.p2.x - 1, RelB.p2.x, SFloor, SFloor + 2, RelB.p1.z, RelB.p2.z, E_BLOCK_AIR, 0);
+ a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p1.x + 1, DFloor, DFloor + 2, RelB.p1.z, RelB.p2.z, E_BLOCK_AIR, 0);
+ a_ChunkDesc.FloorRelCuboid(RelB.p2.x - 1, RelB.p2.x, SFloor - 1, SFloor - 1, RelB.p1.z, RelB.p2.z, E_BLOCK_PLANKS, 0);
+ a_ChunkDesc.FloorRelCuboid(RelB.p1.x, RelB.p1.x + 1, DFloor - 1, DFloor - 1, RelB.p1.z, RelB.p2.z, E_BLOCK_PLANKS, 0);
+ Box.Assign(RelB.p2.x - 2, SFloor + InitAdd, RelB.p1.z, RelB.p2.x - 2, SFloor + 3 + InitAdd, RelB.p2.z);
+ for (int i = 0; i < 4; i++)
+ {
+ a_ChunkDesc.FillRelCuboid(Box, E_BLOCK_AIR, 0);
+ 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);
+ Box.Move(-1, Add, 0);
+ }
+ break;
+ }
+
+ case dirXP:
+ {
+ a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p1.x + 1, SFloor, SFloor + 2, RelB.p1.z, RelB.p2.z, E_BLOCK_AIR, 0);
+ a_ChunkDesc.FillRelCuboid (RelB.p2.x - 1, RelB.p2.x, DFloor, DFloor + 2, RelB.p1.z, RelB.p2.z, E_BLOCK_AIR, 0);
+ a_ChunkDesc.FloorRelCuboid(RelB.p1.x, RelB.p1.x + 1, SFloor - 1, SFloor - 1, RelB.p1.z, RelB.p2.z, E_BLOCK_PLANKS, 0);
+ a_ChunkDesc.FloorRelCuboid(RelB.p2.x - 1, RelB.p2.x, DFloor - 1, DFloor - 1, RelB.p1.z, RelB.p2.z, E_BLOCK_PLANKS, 0);
+ Box.Assign(RelB.p1.x + 2, SFloor + InitAdd, RelB.p1.z, RelB.p1.x + 2, SFloor + 3 + InitAdd, RelB.p2.z);
+ for (int i = 0; i < 4; i++)
+ {
+ a_ChunkDesc.FillRelCuboid(Box, E_BLOCK_AIR, 0);
+ 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);
+ Box.Move(1, Add, 0);
+ }
+ break;
+ }
+
+ case dirZM:
+ {
+ a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p2.x, SFloor, SFloor + 2, RelB.p2.z - 1, RelB.p2.z, E_BLOCK_AIR, 0);
+ a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p2.x, DFloor, DFloor + 2, RelB.p1.z, RelB.p1.z + 1, E_BLOCK_AIR, 0);
+ a_ChunkDesc.FloorRelCuboid(RelB.p1.x, RelB.p2.x, SFloor - 1, SFloor - 1, RelB.p2.z - 1, RelB.p2.z, E_BLOCK_PLANKS, 0);
+ a_ChunkDesc.FloorRelCuboid(RelB.p1.x, RelB.p2.x, DFloor - 1, DFloor - 1, RelB.p1.z, RelB.p1.z + 1, E_BLOCK_PLANKS, 0);
+ Box.Assign(RelB.p1.x, SFloor + InitAdd, RelB.p2.z - 2, RelB.p2.x, SFloor + 3 + InitAdd, RelB.p2.z - 2);
+ for (int i = 0; i < 4; i++)
+ {
+ a_ChunkDesc.FillRelCuboid(Box, E_BLOCK_AIR, 0);
+ 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);
+ Box.Move(0, Add, -1);
+ }
+ break;
+ }
+
+ case dirZP:
+ {
+ a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p2.x, SFloor, SFloor + 2, RelB.p1.z, RelB.p1.z + 1, E_BLOCK_AIR, 0);
+ a_ChunkDesc.FillRelCuboid (RelB.p1.x, RelB.p2.x, DFloor, DFloor + 2, RelB.p2.z - 1, RelB.p2.z, E_BLOCK_AIR, 0);
+ a_ChunkDesc.FloorRelCuboid(RelB.p1.x, RelB.p2.x, SFloor - 1, SFloor - 1, RelB.p1.z, RelB.p1.z + 1, E_BLOCK_PLANKS, 0);
+ a_ChunkDesc.FloorRelCuboid(RelB.p1.x, RelB.p2.x, DFloor - 1, DFloor - 1, RelB.p2.z - 1, RelB.p2.z, E_BLOCK_PLANKS, 0);
+ Box.Assign(RelB.p1.x, SFloor + InitAdd, RelB.p1.z + 2, RelB.p2.x, SFloor + 3 + InitAdd, RelB.p1.z + 2);
+ for (int i = 0; i < 4; i++)
+ {
+ a_ChunkDesc.FillRelCuboid(Box, E_BLOCK_AIR, 0);
+ 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);
+ Box.Move(0, Add, 1);
+ }
+ break;
+ }
+
+ } // switch (m_Direction)
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cStructGenMineShafts:
+
+cStructGenMineShafts::cStructGenMineShafts(
+ int a_Seed, int a_GridSize, int a_MaxSystemSize,
+ int a_ChanceCorridor, int a_ChanceCrossing, int a_ChanceStaircase
+) :
+ m_Noise(a_Seed),
+ m_GridSize(a_GridSize),
+ m_MaxSystemSize(a_MaxSystemSize),
+ m_ProbLevelCorridor(std::max(0, a_ChanceCorridor)),
+ m_ProbLevelCrossing(std::max(0, a_ChanceCorridor + a_ChanceCrossing)),
+ m_ProbLevelStaircase(std::max(0, a_ChanceCorridor + a_ChanceCrossing + a_ChanceStaircase))
+{
+}
+
+
+
+
+
+cStructGenMineShafts::~cStructGenMineShafts()
+{
+ ClearCache();
+}
+
+
+
+
+
+void cStructGenMineShafts::ClearCache(void)
+{
+ for (cMineShaftSystems::const_iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ } // for itr - m_Cache[]
+ m_Cache.clear();
+}
+
+
+
+
+
+void cStructGenMineShafts::GetMineShaftSystemsForChunk(
+ int a_ChunkX, int a_ChunkZ,
+ cStructGenMineShafts::cMineShaftSystems & a_MineShafts
+)
+{
+ int BaseX = a_ChunkX * cChunkDef::Width / m_GridSize;
+ int BaseZ = a_ChunkZ * cChunkDef::Width / m_GridSize;
+ if (BaseX < 0)
+ {
+ --BaseX;
+ }
+ if (BaseZ < 0)
+ {
+ --BaseZ;
+ }
+ BaseX -= NEIGHBORHOOD_SIZE / 2;
+ BaseZ -= NEIGHBORHOOD_SIZE / 2;
+
+ // Walk the cache, move each cave system that we want into a_Caves:
+ int StartX = BaseX * m_GridSize;
+ int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_GridSize;
+ int StartZ = BaseZ * m_GridSize;
+ int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_GridSize;
+ for (cMineShaftSystems::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;)
+ {
+ if (
+ ((*itr)->m_BlockX >= StartX) && ((*itr)->m_BlockX < EndX) &&
+ ((*itr)->m_BlockZ >= StartZ) && ((*itr)->m_BlockZ < EndZ)
+ )
+ {
+ // want
+ a_MineShafts.push_back(*itr);
+ itr = m_Cache.erase(itr);
+ }
+ else
+ {
+ // don't want
+ ++itr;
+ }
+ } // for itr - m_Cache[]
+
+ for (int x = 0; x < NEIGHBORHOOD_SIZE; x++)
+ {
+ int RealX = (BaseX + x) * m_GridSize;
+ for (int z = 0; z < NEIGHBORHOOD_SIZE; z++)
+ {
+ int RealZ = (BaseZ + z) * m_GridSize;
+ bool Found = false;
+ for (cMineShaftSystems::const_iterator itr = a_MineShafts.begin(), end = a_MineShafts.end(); itr != end; ++itr)
+ {
+ if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ))
+ {
+ Found = true;
+ break;
+ }
+ } // for itr - a_Mineshafts
+ if (!Found)
+ {
+ a_MineShafts.push_back(new cMineShaftSystem(RealX, RealZ, m_GridSize, m_MaxSystemSize, m_Noise, m_ProbLevelCorridor, m_ProbLevelCrossing, m_ProbLevelStaircase));
+ }
+ } // for z
+ } // for x
+
+ // Copy a_MineShafts into m_Cache to the beginning:
+ cMineShaftSystems MineShaftsCopy(a_MineShafts);
+ m_Cache.splice(m_Cache.begin(), MineShaftsCopy, MineShaftsCopy.begin(), MineShaftsCopy.end());
+
+ // Trim the cache if it's too long:
+ if (m_Cache.size() > 100)
+ {
+ cMineShaftSystems::iterator itr = m_Cache.begin();
+ std::advance(itr, 100);
+ for (cMineShaftSystems::iterator end = m_Cache.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ }
+ itr = m_Cache.begin();
+ std::advance(itr, 100);
+ m_Cache.erase(itr, m_Cache.end());
+ }
+}
+
+
+
+
+
+
+void cStructGenMineShafts::GenStructures(cChunkDesc & a_ChunkDesc)
+{
+ int ChunkX = a_ChunkDesc.GetChunkX();
+ int ChunkZ = a_ChunkDesc.GetChunkZ();
+ cMineShaftSystems MineShafts;
+ GetMineShaftSystemsForChunk(ChunkX, ChunkZ, MineShafts);
+ for (cMineShaftSystems::const_iterator itr = MineShafts.begin(); itr != MineShafts.end(); ++itr)
+ {
+ (*itr)->ProcessChunk(a_ChunkDesc);
+ } // for itr - MineShafts[]
+}
+
+
+
+