summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/BlockID.h4
-rw-r--r--src/Blocks/BlockHandler.cpp2
-rw-r--r--src/Blocks/BlockSponge.h157
3 files changed, 163 insertions, 0 deletions
diff --git a/src/BlockID.h b/src/BlockID.h
index d7b362c41..733155a50 100644
--- a/src/BlockID.h
+++ b/src/BlockID.h
@@ -806,6 +806,10 @@ enum ENUM_BLOCK_META : NIBBLETYPE
E_META_SNOW_LAYER_SEVEN = 6,
E_META_SNOW_LAYER_EIGHT = 7,
+ // E_BLOCK_SPONGE metas:
+ E_META_SPONGE_DRY = 0,
+ E_META_SPONGE_WET = 1,
+
// E_BLOCK_STAINED_CLAY metas:
E_META_STAINED_CLAY_WHITE = 0,
E_META_STAINED_CLAY_ORANGE = 1,
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index 923d02a80..61427cae6 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -77,6 +77,7 @@
#include "BlockSlab.h"
#include "BlockSlime.h"
#include "BlockSnow.h"
+#include "BlockSponge.h"
#include "BlockStairs.h"
#include "BlockStems.h"
#include "BlockStone.h"
@@ -317,6 +318,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_SIGN_POST: return new cBlockSignPostHandler (a_BlockType);
case E_BLOCK_SNOW: return new cBlockSnowHandler (a_BlockType);
case E_BLOCK_SLIME_BLOCK: return new cBlockSlimeHandler (a_BlockType);
+ case E_BLOCK_SPONGE: return new cBlockSpongeHandler (a_BlockType);
case E_BLOCK_SPRUCE_DOOR: return new cBlockDoorHandler (a_BlockType);
case E_BLOCK_SPRUCE_FENCE: return new cBlockFenceHandler (a_BlockType);
case E_BLOCK_SPRUCE_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType);
diff --git a/src/Blocks/BlockSponge.h b/src/Blocks/BlockSponge.h
new file mode 100644
index 000000000..24bc25388
--- /dev/null
+++ b/src/Blocks/BlockSponge.h
@@ -0,0 +1,157 @@
+
+#pragma once
+
+#include "BlockHandler.h"
+
+
+
+
+
+class cBlockSpongeHandler :
+ public cBlockHandler
+{
+public:
+ cBlockSpongeHandler(BLOCKTYPE a_BlockType):
+ cBlockHandler(a_BlockType)
+ {
+ }
+
+
+
+
+
+ virtual void Check(cChunkInterface & a_ChunkInterface, cBlockPluginInterface & a_PluginInterface, int a_RelX, int a_RelY, int a_RelZ, cChunk & a_Chunk) override
+ {
+ if (GetSoaked(Vector3i(a_RelX, a_RelY, a_RelZ), a_Chunk))
+ {
+ return;
+ }
+ cBlockHandler::Check(a_ChunkInterface, a_PluginInterface, a_RelX, a_RelY, a_RelZ, a_Chunk);
+ }
+
+
+
+
+
+ /** Check blocks around the sponge to see if they are water.
+ If a dry sponge is touching water, soak up up to 65 blocks of water,
+ with a taxicab distance of 7, and turn the sponge into a wet sponge.
+ Returns TRUE if the block was changed. */
+ bool GetSoaked(Vector3i a_Rel, cChunk & a_Chunk)
+ {
+ static const std::array<Vector3i, 6> WaterCheck
+ {
+ {
+ { 1, 0, 0},
+ {-1, 0, 0},
+ { 0, 0, 1},
+ { 0, 0, -1},
+ { 0, 1, 0},
+ { 0, -1, 0},
+ }
+ };
+ struct sSeed
+ {
+ sSeed(Vector3i pos, int d)
+ {
+ m_Pos = pos;
+ m_Depth = d;
+ }
+ Vector3i m_Pos;
+ int m_Depth;
+ };
+
+
+ // Check if this is a dry sponge next to a water block.
+ NIBBLETYPE TargetMeta = a_Chunk.GetMeta(a_Rel.x, a_Rel.y, a_Rel.z);
+ if (TargetMeta != E_META_SPONGE_DRY)
+ {
+ return false;
+ }
+
+ bool ShouldSoak = std::any_of(WaterCheck.cbegin(), WaterCheck.cend(), [a_Rel, & a_Chunk](Vector3i a_Offset)
+ {
+ return IsWet(a_Rel + a_Offset, a_Chunk);
+ }
+ );
+
+ // Early return if the sponge isn't touching any water.
+ if (! ShouldSoak)
+ {
+ return false;
+ }
+
+
+ // Use a queue to hold blocks that we want to check, so our search is breadth-first.
+ std::queue<sSeed> Seeds;
+ int count = 0;
+ // Only go 7 blocks away from the center block.
+ const int maxDepth = 7;
+ // Start with the 6 blocks around the sponge.
+ for (unsigned int i = 0; i < 6; i++)
+ {
+ Seeds.emplace(a_Rel + WaterCheck[i], maxDepth - 1);
+ }
+
+
+ // Keep checking blocks that are touching water blocks, or until 65 have been soaked up.
+ while (!Seeds.empty() && count < 65)
+ {
+ sSeed seed = Seeds.front();
+ Vector3i checkRel = seed.m_Pos;
+ if (IsWet(checkRel, a_Chunk))
+ {
+ count++;
+ DryUp(checkRel, a_Chunk);
+ if (seed.m_Depth > 0)
+ {
+ // If this block was water, and we haven't yet gone too far away,
+ // add itÅ› neighbors to the queue to check.
+ for (unsigned int i = 0; i < 6; i++)
+ {
+ Seeds.emplace(checkRel + WaterCheck[i], seed.m_Depth - 1);
+ }
+ }
+ }
+ Seeds.pop();
+ }
+ a_Chunk.SetBlock(a_Rel.x, a_Rel.y, a_Rel.z, E_BLOCK_SPONGE, E_META_SPONGE_WET);
+ return true;
+ }
+
+
+
+
+
+ static void DryUp(Vector3i a_Rel, cChunk & a_Chunk)
+ {
+ // TODO: support evaporating waterlogged blocks.
+ a_Chunk.UnboundedRelSetBlock(a_Rel.x, a_Rel.y, a_Rel.z, E_BLOCK_AIR, 0);
+ }
+
+
+
+
+
+ static bool IsWet(Vector3i a_Rel, cChunk & a_Chunk)
+ {
+ // TODO: support detecting waterlogged blocks.
+ BLOCKTYPE Type;
+ return(a_Chunk.UnboundedRelGetBlockType(a_Rel.x, a_Rel.y, a_Rel.z, Type) && IsBlockWater(Type));
+ }
+
+
+
+
+
+ virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override
+ {
+ UNUSED(a_Meta);
+ return 18;
+ }
+
+
+
+
+
+};