summaryrefslogtreecommitdiffstats
path: root/src/Blocks
diff options
context:
space:
mode:
Diffstat (limited to 'src/Blocks')
-rw-r--r--src/Blocks/BlockDoor.cpp2
-rw-r--r--src/Blocks/BlockDoor.h104
-rw-r--r--src/Blocks/BlockDropSpenser.h4
-rw-r--r--src/Blocks/BlockFurnace.h4
-rw-r--r--src/Blocks/BlockMobHead.h28
-rw-r--r--src/Blocks/BlockPiston.cpp177
-rw-r--r--src/Blocks/BlockPiston.h134
7 files changed, 411 insertions, 42 deletions
diff --git a/src/Blocks/BlockDoor.cpp b/src/Blocks/BlockDoor.cpp
index 479c68153..fb2d6f2dc 100644
--- a/src/Blocks/BlockDoor.cpp
+++ b/src/Blocks/BlockDoor.cpp
@@ -62,7 +62,7 @@ void cBlockDoorHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, c
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
- if (Meta & 8)
+ if (Meta & 0x8)
{
// Current block is top of the door
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY - 1, a_BlockZ, a_Player);
diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h
index 797fe484c..bc59051c3 100644
--- a/src/Blocks/BlockDoor.h
+++ b/src/Blocks/BlockDoor.h
@@ -20,12 +20,12 @@ public:
virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override;
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override;
virtual const char * GetStepSound(void) override;
-
+
virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override;
virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override;
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override;
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override;
-
+
virtual bool GetPlacementBlockTypeMeta(
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
@@ -52,7 +52,7 @@ public:
return true;
}
-
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem((m_BlockType == E_BLOCK_WOODEN_DOOR) ? E_ITEM_WOODEN_DOOR : E_ITEM_IRON_DOOR, 1, 0));
@@ -77,8 +77,8 @@ public:
{
return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR));
}
-
-
+
+
bool CanReplaceBlock(BLOCKTYPE a_BlockType)
{
switch (a_BlockType)
@@ -99,7 +99,7 @@ public:
}
- /// Converts the player's yaw to placed door's blockmeta
+ /** Converts the player's yaw to placed door's blockmeta */
inline static NIBBLETYPE PlayerYawToMetaData(double a_Yaw)
{
ASSERT((a_Yaw >= -180) && (a_Yaw < 180));
@@ -111,67 +111,109 @@ public:
}
if ((a_Yaw >= 0) && (a_Yaw < 90))
{
- return 0x0;
+ return 0x00;
}
else if ((a_Yaw >= 180) && (a_Yaw < 270))
{
- return 0x2;
+ return 0x02;
}
else if ((a_Yaw >= 90) && (a_Yaw < 180))
{
- return 0x1;
+ return 0x01;
}
else
{
- return 0x3;
+ return 0x03;
}
}
- /// Returns true if the specified blocktype is any kind of door
+ /** Returns true if the specified blocktype is any kind of door */
inline static bool IsDoor(BLOCKTYPE a_Block)
{
return (a_Block == E_BLOCK_WOODEN_DOOR) || (a_Block == E_BLOCK_IRON_DOOR);
}
- /// Returns the metadata for the opposite door state (open vs closed)
- static NIBBLETYPE ChangeStateMetaData(NIBBLETYPE a_MetaData)
+ static NIBBLETYPE IsOpen(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
{
- return a_MetaData ^ 4;
+ NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
+ return ((Meta & 0x04) != 0);
}
- /// Changes the door at the specified coords from open to close or vice versa
- static void ChangeDoor(cChunkInterface & a_ChunkInterface, int a_X, int a_Y, int a_Z)
+ /** Returns the complete meta composed from the both parts of the door as (TopMeta << 4) | BottomMeta
+ The coords may point to either part of the door.
+ The returned value has bit 3 (0x08) set iff the coords point to the top part of the door.
+ Fails gracefully for (invalid) doors on the world's top and bottom. */
+ static NIBBLETYPE GetCompleteDoorMeta(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
{
- NIBBLETYPE OldMetaData = a_ChunkInterface.GetBlockMeta(a_X, a_Y, a_Z);
-
- a_ChunkInterface.SetBlockMeta(a_X, a_Y, a_Z, ChangeStateMetaData(OldMetaData));
+ NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
- if (OldMetaData & 8)
+ if ((Meta & 0x08) != 0)
{
- // Current block is top of the door
- BLOCKTYPE BottomBlock = a_ChunkInterface.GetBlock(a_X, a_Y - 1, a_Z);
- NIBBLETYPE BottomMeta = a_ChunkInterface.GetBlockMeta(a_X, a_Y - 1, a_Z);
-
- if (IsDoor(BottomBlock) && !(BottomMeta & 8))
+ // The coords are pointing at the top part of the door
+ if (a_BlockX > 0)
{
- a_ChunkInterface.SetBlockMeta(a_X, a_Y - 1, a_Z, ChangeStateMetaData(BottomMeta));
+ NIBBLETYPE DownMeta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ);
+ return (DownMeta & 0x07) | 0x08 | (Meta << 4);
}
+ // This is the top part of the door at the bottommost layer of the world, there's no bottom:
+ return 0x08 | (Meta << 4);
}
else
{
- // Current block is bottom of the door
- BLOCKTYPE TopBlock = a_ChunkInterface.GetBlock(a_X, a_Y + 1, a_Z);
- NIBBLETYPE TopMeta = a_ChunkInterface.GetBlockMeta(a_X, a_Y + 1, a_Z);
+ // The coords are pointing at the bottom part of the door
+ if (a_BlockY < cChunkDef::Height - 1)
+ {
+ NIBBLETYPE UpMeta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY + 1, a_BlockZ);
+ return Meta | (UpMeta << 4);
+ }
+ // This is the bottom part of the door at the topmost layer of the world, there's no top:
+ return Meta;
+ }
+ }
- if (IsDoor(TopBlock) && (TopMeta & 8))
+
+ /** Sets the door to the specified state. If the door is already in that state, does nothing. */
+ static void SetOpen(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Open)
+ {
+ BLOCKTYPE Block = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ if (!IsDoor(Block))
+ {
+ return;
+ }
+
+ NIBBLETYPE Meta = GetCompleteDoorMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
+ bool IsOpened = ((Meta & 0x04) != 0);
+ if (IsOpened == a_Open)
+ {
+ return;
+ }
+
+ // Change the door
+ NIBBLETYPE NewMeta = (Meta & 0x07) ^ 0x04; // Flip the "IsOpen" bit (0x04)
+ if ((Meta & 0x08) == 0)
+ {
+ // The block is the bottom part of the door
+ a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, NewMeta);
+ }
+ else
+ {
+ // The block is the top part of the door, set the meta to the corresponding top part
+ if (a_BlockY > 0)
{
- a_ChunkInterface.SetBlockMeta(a_X, a_Y + 1, a_Z, ChangeStateMetaData(TopMeta));
+ a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ, NewMeta);
}
}
}
+
+
+ /** Changes the door at the specified coords from open to close or vice versa */
+ static void ChangeDoor(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
+ {
+ SetOpen(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, !IsOpen(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ));
+ }
} ;
diff --git a/src/Blocks/BlockDropSpenser.h b/src/Blocks/BlockDropSpenser.h
index 88b61a418..e2b3039fd 100644
--- a/src/Blocks/BlockDropSpenser.h
+++ b/src/Blocks/BlockDropSpenser.h
@@ -5,7 +5,7 @@
#pragma once
-#include "../Piston.h"
+#include "../Blocks/BlockPiston.h"
#include "MetaRotator.h"
@@ -32,7 +32,7 @@ public:
a_BlockType = m_BlockType;
// FIXME: Do not use cPiston class for dispenser placement!
- a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
+ a_BlockMeta = cBlockPistonHandler::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
return true;
}
diff --git a/src/Blocks/BlockFurnace.h b/src/Blocks/BlockFurnace.h
index a7a807957..74582c3b3 100644
--- a/src/Blocks/BlockFurnace.h
+++ b/src/Blocks/BlockFurnace.h
@@ -3,7 +3,7 @@
#include "BlockEntity.h"
#include "../World.h"
-#include "../Piston.h"
+#include "../Blocks/BlockPiston.h"
#include "MetaRotator.h"
@@ -35,7 +35,7 @@ public:
a_BlockType = m_BlockType;
// FIXME: Do not use cPiston class for furnace placement!
- a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), 0);
+ a_BlockMeta = cBlockPistonHandler::RotationPitchToMetaData(a_Player->GetYaw(), 0);
return true;
}
diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h
index acd1c88fb..9855574ad 100644
--- a/src/Blocks/BlockMobHead.h
+++ b/src/Blocks/BlockMobHead.h
@@ -46,8 +46,30 @@ public:
bool IsWither(void) const { return m_IsWither; }
void Reset(void) { m_IsWither = false; }
+
} CallbackA, CallbackB;
+ class cPlayerCallback : public cPlayerListCallback
+ {
+ Vector3f m_Pos;
+
+ virtual bool Item(cPlayer * a_Player)
+ {
+ // TODO 2014-05-21 xdot: Vanilla minecraft uses an AABB check instead of a radius one
+ double Dist = (a_Player->GetPosition() - m_Pos).Length();
+ if (Dist < 50.0)
+ {
+ // If player is close, award achievement
+ a_Player->AwardAchievement(achSpawnWither);
+ }
+ return false;
+ }
+
+ public:
+ cPlayerCallback(const Vector3f & a_Pos) : m_Pos(a_Pos) {}
+
+ } PlayerCallback(Vector3f((float)a_BlockX, (float)a_BlockY, (float)a_BlockZ));
+
a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, CallbackA);
if (!CallbackA.IsWither())
@@ -86,6 +108,9 @@ public:
// Spawn the wither:
a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither);
+ // Award Achievement
+ a_World->ForEachPlayer(PlayerCallback);
+
return true;
}
@@ -113,6 +138,9 @@ public:
// Spawn the wither:
a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither);
+ // Award Achievement
+ a_World->ForEachPlayer(PlayerCallback);
+
return true;
}
diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp
index 542eb33b5..faf639312 100644
--- a/src/Blocks/BlockPiston.cpp
+++ b/src/Blocks/BlockPiston.cpp
@@ -4,14 +4,14 @@
#include "../Item.h"
#include "../World.h"
#include "../Entities/Player.h"
-#include "../Piston.h"
+#include "BlockInServerPluginInterface.h"
#define AddPistonDir(x, y, z, dir, amount) \
- switch (dir) \
+ switch (dir & 0x07) \
{ \
case 0: (y) -= (amount); break; \
case 1: (y) += (amount); break; \
@@ -19,8 +19,16 @@
case 3: (z) += (amount); break; \
case 4: (x) -= (amount); break; \
case 5: (x) += (amount); break; \
+ default: \
+ { \
+ LOGWARNING("%s: invalid direction %d, ignoring", __FUNCTION__, dir & 0x07); \
+ break; \
+ } \
}
+#define PISTON_TICK_DELAY 1
+#define PISTON_MAX_PUSH_DISTANCE 12
+
@@ -40,7 +48,7 @@ void cBlockPistonHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorld
int newX = a_BlockX;
int newY = a_BlockY;
int newZ = a_BlockZ;
- AddPistonDir(newX, newY, newZ, OldMeta & ~(8), 1);
+ AddPistonDir(newX, newY, newZ, OldMeta, 1);
if (a_ChunkInterface.GetBlock(newX, newY, newZ) == E_BLOCK_PISTON_EXTENSION)
{
@@ -60,7 +68,7 @@ bool cBlockPistonHandler::GetPlacementBlockTypeMeta(
)
{
a_BlockType = m_BlockType;
- a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
+ a_BlockMeta = RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
return true;
}
@@ -68,6 +76,165 @@ bool cBlockPistonHandler::GetPlacementBlockTypeMeta(
+int cBlockPistonHandler::FirstPassthroughBlock(int a_PistonX, int a_PistonY, int a_PistonZ, NIBBLETYPE pistonmeta, cWorld * a_World)
+{
+ // Examine each of the 12 blocks ahead of the piston:
+ for (int ret = 0; ret < PISTON_MAX_PUSH_DISTANCE; ret++)
+ {
+ BLOCKTYPE currBlock;
+ NIBBLETYPE currMeta;
+ AddPistonDir(a_PistonX, a_PistonY, a_PistonZ, pistonmeta, 1);
+ a_World->GetBlockTypeMeta(a_PistonX, a_PistonY, a_PistonZ, currBlock, currMeta);
+ if (CanBreakPush(currBlock))
+ {
+ // This block breaks when pushed, extend up to here
+ return ret;
+ }
+ if (!CanPush(currBlock, currMeta))
+ {
+ // This block cannot be pushed at all, the piston can't extend
+ return -1;
+ }
+ }
+ // There is no space for the blocks to move, piston can't extend
+ return -1;
+}
+
+
+
+
+
+void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World)
+{
+ BLOCKTYPE pistonBlock;
+ NIBBLETYPE pistonMeta;
+ a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta);
+
+ if (IsExtended(pistonMeta))
+ {
+ // Already extended, bail out
+ return;
+ }
+
+ int dist = FirstPassthroughBlock(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, a_World);
+ if (dist < 0)
+ {
+ // FirstPassthroughBlock says piston can't push anything, bail out
+ return;
+ }
+
+ a_World->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, 0, pistonMeta, pistonBlock);
+ a_World->BroadcastSoundEffect("tile.piston.out", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.7f);
+
+ // Drop the breakable block in the line, if appropriate:
+ AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, dist + 1); // "a_Block" now at the breakable / empty block
+ BLOCKTYPE currBlock;
+ NIBBLETYPE currMeta;
+ a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, currBlock, currMeta);
+ if (currBlock != E_BLOCK_AIR)
+ {
+ cBlockHandler * Handler = BlockHandler(currBlock);
+ if (Handler->DoesDropOnUnsuitable())
+ {
+ cChunkInterface ChunkInterface(a_World->GetChunkMap());
+ cBlockInServerPluginInterface PluginInterface(*a_World);
+ Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, NULL, a_BlockX, a_BlockY, a_BlockZ);
+ }
+ }
+
+ // Push blocks, from the furthest to the nearest:
+ int oldx = a_BlockX, oldy = a_BlockY, oldz = a_BlockZ;
+ NIBBLETYPE currBlockMeta;
+ std::vector<Vector3i> ScheduledBlocks;
+ ScheduledBlocks.reserve(PISTON_MAX_PUSH_DISTANCE);
+
+ for (int i = dist + 1; i > 1; i--)
+ {
+ AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1);
+ a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, currBlock, currBlockMeta);
+ a_World->SetBlock(oldx, oldy, oldz, currBlock, currBlockMeta, false);
+ ScheduledBlocks.push_back(Vector3i(oldx, oldy, oldz));
+ oldx = a_BlockX;
+ oldy = a_BlockY;
+ oldz = a_BlockZ;
+ }
+
+ int extx = a_BlockX;
+ int exty = a_BlockY;
+ int extz = a_BlockZ;
+ ScheduledBlocks.push_back(Vector3i(extx, exty, extz));
+ AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1);
+ // "a_Block" now at piston body, "ext" at future extension
+
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta | 0x8);
+ a_World->SetBlock(extx, exty, extz, E_BLOCK_PISTON_EXTENSION, pistonMeta | (IsSticky(pistonBlock) ? 8 : 0), false);
+ a_World->ScheduleTask(PISTON_TICK_DELAY, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks));
+}
+
+
+
+
+
+void cBlockPistonHandler::RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World)
+{
+ BLOCKTYPE pistonBlock;
+ NIBBLETYPE pistonMeta;
+ a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta);
+
+ if (!IsExtended(pistonMeta))
+ {
+ // Already retracted, bail out
+ return;
+ }
+
+ // Check the extension:
+ AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, 1);
+ if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) != E_BLOCK_PISTON_EXTENSION)
+ {
+ LOGD("%s: Piston without an extension - still extending, or just in an invalid state?", __FUNCTION__);
+ return;
+ }
+
+ AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1);
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta & ~(8));
+ a_World->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, 1, pistonMeta & ~(8), pistonBlock);
+ a_World->BroadcastSoundEffect("tile.piston.in", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.7f);
+ AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, 1);
+
+ // Retract the extension, pull block if appropriate
+ if (IsSticky(pistonBlock))
+ {
+ int tempx = a_BlockX, tempy = a_BlockY, tempz = a_BlockZ;
+ AddPistonDir(tempx, tempy, tempz, pistonMeta, 1);
+ BLOCKTYPE tempBlock;
+ NIBBLETYPE tempMeta;
+ a_World->GetBlockTypeMeta(tempx, tempy, tempz, tempBlock, tempMeta);
+ if (CanPull(tempBlock, tempMeta))
+ {
+ // Pull the block
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, tempBlock, tempMeta, false);
+ a_World->SetBlock(tempx, tempy, tempz, E_BLOCK_AIR, 0, false);
+
+ std::vector<Vector3i> ScheduledBlocks;
+ ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ));
+ ScheduledBlocks.push_back(Vector3i(tempx, tempy, tempz));
+ a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks));
+ return;
+ }
+ }
+
+ // Retract without pulling
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0, false);
+
+ std::vector<Vector3i> ScheduledBlocks;
+ ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ));
+ a_World->ScheduleTask(PISTON_TICK_DELAY + 1, new cWorld::cTaskSendBlockToAllPlayers(ScheduledBlocks));
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cBlockPistonHeadHandler:
@@ -87,7 +254,7 @@ void cBlockPistonHeadHandler::OnDestroyedByPlayer(cChunkInterface & a_ChunkInter
int newX = a_BlockX;
int newY = a_BlockY;
int newZ = a_BlockZ;
- AddPistonDir(newX, newY, newZ, OldMeta & ~(8), -1);
+ AddPistonDir(newX, newY, newZ, OldMeta, -1);
BLOCKTYPE Block = a_ChunkInterface.GetBlock(newX, newY, newZ);
if ((Block == E_BLOCK_STICKY_PISTON) || (Block == E_BLOCK_PISTON))
diff --git a/src/Blocks/BlockPiston.h b/src/Blocks/BlockPiston.h
index 7632b5e5a..e6fa48e54 100644
--- a/src/Blocks/BlockPiston.h
+++ b/src/Blocks/BlockPiston.h
@@ -21,6 +21,138 @@ public:
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override;
+
+ static NIBBLETYPE RotationPitchToMetaData(double a_Rotation, double a_Pitch)
+ {
+ if (a_Pitch >= 50)
+ {
+ return 0x1;
+ }
+ else if (a_Pitch <= -50)
+ {
+ return 0x0;
+ }
+ else
+ {
+ a_Rotation += 90 + 45; // So its not aligned with axis
+
+ if (a_Rotation > 360)
+ {
+ a_Rotation -= 360;
+ }
+ if ((a_Rotation >= 0) && (a_Rotation < 90))
+ {
+ return 0x4;
+ }
+ else if ((a_Rotation >= 180) && (a_Rotation < 270))
+ {
+ return 0x5;
+ }
+ else if ((a_Rotation >= 90) && (a_Rotation < 180))
+ {
+ return 0x2;
+ }
+ else
+ {
+ return 0x3;
+ }
+ }
+ }
+
+ static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData)
+ {
+ switch (a_MetaData)
+ {
+ case 0x0: return BLOCK_FACE_YM;
+ case 0x1: return BLOCK_FACE_YP;
+ case 0x2: return BLOCK_FACE_ZM;
+ case 0x3: return BLOCK_FACE_ZP;
+ case 0x4: return BLOCK_FACE_XM;
+ case 0x5: return BLOCK_FACE_XP;
+ default:
+ {
+ ASSERT(!"Invalid Metadata");
+ return BLOCK_FACE_NONE;
+ }
+ }
+ }
+
+ static void ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
+ static void RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
+
+private:
+
+ /// Returns true if the piston (specified by blocktype) is a sticky piston
+ static inline bool IsSticky(BLOCKTYPE a_BlockType) { return (a_BlockType == E_BLOCK_STICKY_PISTON); }
+
+ /// Returns true if the piston (with the specified meta) is extended
+ static inline bool IsExtended(NIBBLETYPE a_PistonMeta) { return ((a_PistonMeta & 0x8) != 0x0); }
+
+ /// Returns true if the specified block can be pushed by a piston (and left intact)
+ static inline bool CanPush(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
+ {
+ switch (a_BlockType)
+ {
+ case E_BLOCK_ANVIL:
+ case E_BLOCK_BED:
+ case E_BLOCK_BEDROCK:
+ case E_BLOCK_BREWING_STAND:
+ case E_BLOCK_CHEST:
+ case E_BLOCK_COMMAND_BLOCK:
+ case E_BLOCK_DISPENSER:
+ case E_BLOCK_DROPPER:
+ case E_BLOCK_ENCHANTMENT_TABLE:
+ case E_BLOCK_END_PORTAL:
+ case E_BLOCK_END_PORTAL_FRAME:
+ case E_BLOCK_FURNACE:
+ case E_BLOCK_LIT_FURNACE:
+ case E_BLOCK_HOPPER:
+ case E_BLOCK_JUKEBOX:
+ case E_BLOCK_MOB_SPAWNER:
+ case E_BLOCK_NETHER_PORTAL:
+ case E_BLOCK_NOTE_BLOCK:
+ case E_BLOCK_OBSIDIAN:
+ case E_BLOCK_PISTON_EXTENSION:
+ {
+ return false;
+ }
+ case E_BLOCK_STICKY_PISTON:
+ case E_BLOCK_PISTON:
+ {
+ // A piston can only be pushed if retracted:
+ return !IsExtended(a_BlockMeta);
+ }
+ }
+ return true;
+ }
+
+ /// Returns true if the specified block can be pushed by a piston and broken / replaced
+ static inline bool CanBreakPush(BLOCKTYPE a_BlockType) { return cBlockInfo::IsPistonBreakable(a_BlockType); }
+
+ /// Returns true if the specified block can be pulled by a sticky piston
+ static inline bool CanPull(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
+ {
+ switch (a_BlockType)
+ {
+ case E_BLOCK_LAVA:
+ case E_BLOCK_STATIONARY_LAVA:
+ case E_BLOCK_STATIONARY_WATER:
+ case E_BLOCK_WATER:
+ {
+ return false;
+ }
+ }
+
+ if (CanBreakPush(a_BlockType))
+ {
+ return false; // CanBreakPush returns true, but we need false to prevent pulling
+ }
+
+ return CanPush(a_BlockType, a_BlockMeta);
+ }
+
+ /// Returns how many blocks the piston has to push (where the first free space is); < 0 when unpushable
+ static int FirstPassthroughBlock(int a_PistonX, int a_PistonY, int a_PistonZ, NIBBLETYPE a_PistonMeta, cWorld * a_World);
} ;
@@ -40,7 +172,7 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// No pickups
- // Also with 1.7, the item forms of these tecnical blocks have been removed, so giving someone this will crash their client...
+ // Also with 1.7, the item forms of these technical blocks have been removed, so giving someone this will crash their client...
}
} ;