summaryrefslogtreecommitdiffstats
path: root/src/BlockEntities
diff options
context:
space:
mode:
Diffstat (limited to 'src/BlockEntities')
-rw-r--r--src/BlockEntities/BeaconEntity.cpp116
-rw-r--r--src/BlockEntities/BeaconEntity.h44
-rw-r--r--src/BlockEntities/BlockEntity.cpp2
-rw-r--r--src/BlockEntities/CMakeLists.txt1
-rw-r--r--src/BlockEntities/CommandBlockEntity.cpp3
-rw-r--r--src/BlockEntities/DispenserEntity.cpp97
-rw-r--r--src/BlockEntities/DispenserEntity.h26
-rw-r--r--src/BlockEntities/FurnaceEntity.cpp7
-rw-r--r--src/BlockEntities/HopperEntity.cpp11
-rw-r--r--src/BlockEntities/MobHeadEntity.cpp2
10 files changed, 276 insertions, 33 deletions
diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp
new file mode 100644
index 000000000..0914353eb
--- /dev/null
+++ b/src/BlockEntities/BeaconEntity.cpp
@@ -0,0 +1,116 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "BeaconEntity.h"
+#include "../BlockArea.h"
+
+
+
+
+
+cBeaconEntity::cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
+ super(E_BLOCK_BEACON, a_BlockX, a_BlockY, a_BlockZ, a_World)
+{
+}
+
+
+
+
+
+int cBeaconEntity::GetPyramidLevel(void)
+{
+ cBlockArea Area;
+ int MinY = GetPosY() - 4;
+ if (MinY < 0)
+ {
+ MinY = 0;
+ }
+ int MaxY = GetPosY() - 1;
+ if (MaxY < 0)
+ {
+ MaxY = 0;
+ }
+
+ Area.Read(
+ m_World,
+ GetPosX() - 4, GetPosX() + 4,
+ MinY, MaxY,
+ GetPosZ() - 4, GetPosZ() + 4,
+ cBlockArea::baTypes
+ );
+
+ int Layer = 1;
+ int MiddleXZ = 4;
+
+ for (int Y = Area.GetSizeY() - 1; Y > 0; Y--)
+ {
+ for (int X = MiddleXZ - Layer; X <= (MiddleXZ + Layer); X++)
+ {
+ for (int Z = MiddleXZ - Layer; Z <= (MiddleXZ + Layer); Z++)
+ {
+ if (!IsMineralBlock(Area.GetRelBlockType(X, Y, Z)))
+ {
+ return Layer - 1;
+ }
+ }
+ }
+ Layer++;
+ }
+
+ return Layer - 1;
+}
+
+
+
+
+
+bool cBeaconEntity::IsMineralBlock(BLOCKTYPE a_BlockType)
+{
+ switch(a_BlockType)
+ {
+ case E_BLOCK_DIAMOND_BLOCK:
+ case E_BLOCK_GOLD_BLOCK:
+ case E_BLOCK_IRON_BLOCK:
+ case E_BLOCK_EMERALD_BLOCK:
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
+bool cBeaconEntity::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ return false;
+}
+
+
+
+
+
+void cBeaconEntity::SaveToJson(Json::Value& a_Value)
+{
+}
+
+
+
+
+void cBeaconEntity::SendTo(cClientHandle & a_Client)
+{
+}
+
+
+
+
+
+void cBeaconEntity::UsedBy(cPlayer * a_Player)
+{
+}
+
+
+
+
diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h
new file mode 100644
index 000000000..b1df68bc4
--- /dev/null
+++ b/src/BlockEntities/BeaconEntity.h
@@ -0,0 +1,44 @@
+
+#pragma once
+
+#include "BlockEntity.h"
+
+
+
+
+
+namespace Json
+{
+ class Value;
+}
+
+
+
+
+
+class cBeaconEntity :
+ public cBlockEntity
+{
+ typedef cBlockEntity super;
+
+public:
+
+ /** The initial constructor */
+ cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
+
+ /** Returns the amount of layers the pyramid below the beacon has. */
+ int GetPyramidLevel(void);
+
+ /** Returns true if the block is a diamond block, a golden block, an iron block or an emerald block. */
+ static bool IsMineralBlock(BLOCKTYPE a_BlockType);
+
+ // cBlockEntity overrides:
+ virtual void SaveToJson(Json::Value& a_Value ) override;
+ virtual void SendTo(cClientHandle & a_Client) override;
+ virtual void UsedBy(cPlayer * a_Player) override;
+ virtual bool Tick(float a_Dt, cChunk & /* a_Chunk */) override;
+} ;
+
+
+
+
diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp
index b42318c2f..430f04551 100644
--- a/src/BlockEntities/BlockEntity.cpp
+++ b/src/BlockEntities/BlockEntity.cpp
@@ -4,6 +4,7 @@
// Implements the cBlockEntity class that is the common ancestor for all block entities
#include "Globals.h"
+#include "BeaconEntity.h"
#include "BlockEntity.h"
#include "ChestEntity.h"
#include "CommandBlockEntity.h"
@@ -26,6 +27,7 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
{
switch (a_BlockType)
{
+ case E_BLOCK_BEACON: return new cBeaconEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_COMMAND_BLOCK: return new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
diff --git a/src/BlockEntities/CMakeLists.txt b/src/BlockEntities/CMakeLists.txt
index 920767f5c..3e3d17f86 100644
--- a/src/BlockEntities/CMakeLists.txt
+++ b/src/BlockEntities/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(BlockEntities ${SOURCE})
diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp
index 96ca0ac37..146ad915b 100644
--- a/src/BlockEntities/CommandBlockEntity.cpp
+++ b/src/BlockEntities/CommandBlockEntity.cpp
@@ -21,7 +21,8 @@
cCommandBlockEntity::cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World) :
super(E_BLOCK_COMMAND_BLOCK, a_X, a_Y, a_Z, a_World),
m_ShouldExecute(false),
- m_IsPowered(false)
+ m_IsPowered(false),
+ m_Result(0)
{}
diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp
index e03bf776d..c02c68afa 100644
--- a/src/BlockEntities/DispenserEntity.cpp
+++ b/src/BlockEntities/DispenserEntity.cpp
@@ -6,6 +6,10 @@
#include "../Simulator/FluidSimulator.h"
#include "../Chunk.h"
+#include "../World.h"
+#include "../Entities/ArrowEntity.h"
+#include "../Entities/FireChargeEntity.h"
+#include "../Entities/ProjectileEntity.h"
@@ -33,7 +37,10 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
// Would dispense into / interact with a non-loaded chunk, ignore the tick
return;
}
+
BLOCKTYPE DispBlock = DispChunk->GetBlock(DispX, DispY, DispZ);
+ int BlockX = (DispX + DispChunk->GetPosX() * cChunkDef::Width);
+ int BlockZ = (DispZ + DispChunk->GetPosZ() * cChunkDef::Width);
// Dispense the item:
switch (m_Contents.GetSlot(a_SlotNum).m_ItemType)
@@ -69,7 +76,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
}
break;
} // E_ITEM_BUCKET
-
+
case E_ITEM_WATER_BUCKET:
{
LOGD("Dispensing water bucket in slot %d; DispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(DispBlock).c_str(), DispBlock);
@@ -83,7 +90,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
}
break;
}
-
+
case E_ITEM_LAVA_BUCKET:
{
LOGD("Dispensing lava bucket in slot %d; DispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(DispBlock).c_str(), DispBlock);
@@ -97,7 +104,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
}
break;
}
-
+
case E_ITEM_SPAWN_EGG:
{
double MobX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width);
@@ -108,7 +115,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
}
break;
}
-
+
case E_BLOCK_TNT:
{
// Spawn a primed TNT entity, if space allows:
@@ -128,22 +135,51 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
if (DispChunk->GetBlock(DispX, DispY, DispZ) == E_BLOCK_AIR)
{
DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_FIRE, 0);
- m_Contents.SetSlot(a_SlotNum, m_Contents.GetSlot(a_SlotNum).m_ItemType, m_Contents.GetSlot(a_SlotNum).m_ItemCount, m_Contents.GetSlot(a_SlotNum).m_ItemDamage + 1);
- // If the durability has run out destroy the item.
- if (m_Contents.GetSlot(a_SlotNum).m_ItemDamage > 64)
- {
+
+ bool ItemBroke = m_Contents.DamageItem(a_SlotNum, 1);
+
+ if (ItemBroke)
+ {
m_Contents.ChangeSlotCount(a_SlotNum, -1);
}
}
break;
}
-
+
case E_ITEM_FIRE_CHARGE:
{
- // TODO: Spawn fireball entity
+ SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkFireCharge, GetShootVector(Meta) * 20);
+ m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ break;
+ }
+
+ case E_ITEM_ARROW:
+ {
+ SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkArrow, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0));
+ m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ break;
+ }
+
+ case E_ITEM_SNOWBALL:
+ {
+ SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkSnowball, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0));
+ m_Contents.ChangeSlotCount(a_SlotNum, -1);
+ break;
+ }
+
+ case E_ITEM_EGG:
+ {
+ SpawnProjectileFromDispenser(BlockX, DispY, BlockZ, cProjectileEntity::pkEgg, GetShootVector(Meta) * 20 + Vector3d(0, 1, 0));
+ m_Contents.ChangeSlotCount(a_SlotNum, -1);
break;
}
-
+
+ case E_ITEM_FIREWORK_ROCKET:
+ {
+ // TODO: Add the fireworks entity
+ break;
+ }
+
default:
{
DropFromSlot(a_Chunk, a_SlotNum);
@@ -156,6 +192,34 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
+void cDispenserEntity::SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & a_ShootVector)
+{
+ m_World->CreateProjectile((double)a_BlockX + 0.5, (double)a_BlockY + 0.5, (double)a_BlockZ + 0.5, a_Kind, NULL, NULL, &a_ShootVector);
+}
+
+
+
+
+
+Vector3d cDispenserEntity::GetShootVector(NIBBLETYPE a_Meta)
+{
+ switch (a_Meta)
+ {
+ case E_META_DROPSPENSER_FACING_YP: return Vector3d( 0, 1, 0);
+ case E_META_DROPSPENSER_FACING_YM: return Vector3d( 0, -1, 0);
+ case E_META_DROPSPENSER_FACING_XM: return Vector3d(-1, 0, 0);
+ case E_META_DROPSPENSER_FACING_XP: return Vector3d( 1, 0, 0);
+ case E_META_DROPSPENSER_FACING_ZM: return Vector3d( 0, 0, -1);
+ case E_META_DROPSPENSER_FACING_ZP: return Vector3d( 0, 0, 1);
+ }
+ LOGWARNING("Unhandled dispenser meta: %d", a_Meta);
+ ASSERT(!"Unhandled dispenser facing");
+ return Vector3d(0, 1, 0);
+}
+
+
+
+
bool cDispenserEntity::ScoopUpLiquid(int a_SlotNum, short a_BucketItemType)
{
@@ -166,14 +230,14 @@ bool cDispenserEntity::ScoopUpLiquid(int a_SlotNum, short a_BucketItemType)
m_Contents.SetSlot(a_SlotNum, LiquidBucket);
return true;
}
-
+
// There are stacked buckets at the selected slot, see if a full bucket will fit somewhere else
if (m_Contents.HowManyCanFit(LiquidBucket) < 1)
{
// Cannot fit into m_Contents
return false;
}
-
+
m_Contents.ChangeSlotCount(a_SlotNum, -1);
m_Contents.AddItem(LiquidBucket);
return true;
@@ -194,7 +258,7 @@ bool cDispenserEntity::EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum
// Not a suitable block in front
return false;
}
-
+
cItem EmptyBucket(E_ITEM_BUCKET, 1);
if (m_Contents.GetSlot(a_SlotNum).m_ItemCount == 1)
{
@@ -202,14 +266,14 @@ bool cDispenserEntity::EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum
m_Contents.SetSlot(a_SlotNum, EmptyBucket);
return true;
}
-
+
// There are full buckets stacked at this slot, check if we can fit in the empty bucket
if (m_Contents.HowManyCanFit(EmptyBucket) < 1)
{
// The empty bucket wouldn't fit into m_Contents
return false;
}
-
+
// The empty bucket fits in, remove one full bucket and add the empty one
m_Contents.ChangeSlotCount(a_SlotNum, -1);
m_Contents.AddItem(EmptyBucket);
@@ -218,4 +282,3 @@ bool cDispenserEntity::EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum
-
diff --git a/src/BlockEntities/DispenserEntity.h b/src/BlockEntities/DispenserEntity.h
index fdfe4e5b4..b33d08342 100644
--- a/src/BlockEntities/DispenserEntity.h
+++ b/src/BlockEntities/DispenserEntity.h
@@ -12,27 +12,37 @@ class cDispenserEntity :
public cDropSpenserEntity
{
typedef cDropSpenserEntity super;
-
+
public:
// tolua_end
-
- /// Constructor used for normal operation
+
+ /** Constructor used for normal operation */
cDispenserEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
static const char * GetClassStatic(void) { return "cDispenserEntity"; }
+ // tolua_begin
+
+ /** Spawns a projectile of the given kind in front of the dispenser with the specified speed. */
+ void SpawnProjectileFromDispenser(int a_BlockX, int a_BlockY, int a_BlockZ, cProjectileEntity::eKind a_Kind, const Vector3d & a_Speed);
+
+ /** Returns a unit vector in the cardinal direction of where the dispenser is facing. */
+ Vector3d GetShootVector(NIBBLETYPE a_Meta);
+
+ // tolua_end
+
private:
// cDropSpenser overrides:
virtual void DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) override;
-
- /// If such a bucket can fit, adds it to m_Contents and returns true
+
+ /** If such a bucket can fit, adds it to m_Contents and returns true */
bool ScoopUpLiquid(int a_SlotNum, short a_BucketItemType);
-
- /// If the a_BlockInFront is liquidable and the empty bucket can fit, does the m_Contents processing and returns true
+
+ /** If the a_BlockInFront can be washed away by liquid and the empty bucket can fit,
+ does the m_Contents processing and returns true. Returns false otherwise. */
bool EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum);
} ; // tolua_export
-
diff --git a/src/BlockEntities/FurnaceEntity.cpp b/src/BlockEntities/FurnaceEntity.cpp
index 7d6d1f89e..1b1741713 100644
--- a/src/BlockEntities/FurnaceEntity.cpp
+++ b/src/BlockEntities/FurnaceEntity.cpp
@@ -413,19 +413,20 @@ bool cFurnaceEntity::CanCookInputToOutput(void) const
return false;
}
- if (m_Contents.GetSlot(fsOutput).IsEmpty())
+ const cItem & Slot = m_Contents.GetSlot(fsOutput);
+ if (Slot.IsEmpty())
{
// The output is empty, can cook
return true;
}
- if (!m_Contents.GetSlot(fsOutput).IsEqual(*m_CurrentRecipe->Out))
+ if (!Slot.IsEqual(*m_CurrentRecipe->Out))
{
// The output slot is blocked with something that cannot be stacked with the recipe's output
return false;
}
- if (m_Contents.GetSlot(fsOutput).IsFullStack())
+ if (Slot.IsFullStack())
{
// Cannot add any more items to the output slot
return false;
diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp
index 41fb9f811..7f001c739 100644
--- a/src/BlockEntities/HopperEntity.cpp
+++ b/src/BlockEntities/HopperEntity.cpp
@@ -234,24 +234,27 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
bool TrySuckPickupIn(cPickup * a_Pickup)
{
+ cItem & Item = a_Pickup->GetItem();
+
for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
{
if (m_Contents.IsSlotEmpty(i))
{
m_bFoundPickupsAbove = true;
- m_Contents.SetSlot(i, a_Pickup->GetItem());
+ m_Contents.SetSlot(i, Item);
a_Pickup->Destroy(); // Kill pickup
return true;
}
- else if (m_Contents.GetSlot(i).IsEqual(a_Pickup->GetItem()) && !m_Contents.GetSlot(i).IsFullStack())
+ else if (m_Contents.GetSlot(i).IsEqual(Item) && !m_Contents.GetSlot(i).IsFullStack())
{
m_bFoundPickupsAbove = true;
int PreviousCount = m_Contents.GetSlot(i).m_ItemCount;
- a_Pickup->GetItem().m_ItemCount -= m_Contents.ChangeSlotCount(i, a_Pickup->GetItem().m_ItemCount) - PreviousCount; // Set count to however many items were added
- if (a_Pickup->GetItem().IsEmpty())
+ Item.m_ItemCount -= m_Contents.ChangeSlotCount(i, Item.m_ItemCount) - PreviousCount; // Set count to however many items were added
+
+ if (Item.IsEmpty())
{
a_Pickup->Destroy(); // Kill pickup if all items were added
}
diff --git a/src/BlockEntities/MobHeadEntity.cpp b/src/BlockEntities/MobHeadEntity.cpp
index c0a1781f6..dc9c18d58 100644
--- a/src/BlockEntities/MobHeadEntity.cpp
+++ b/src/BlockEntities/MobHeadEntity.cpp
@@ -14,6 +14,8 @@
cMobHeadEntity::cMobHeadEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
super(E_BLOCK_HEAD, a_BlockX, a_BlockY, a_BlockZ, a_World),
+ m_Type(SKULL_TYPE_SKELETON),
+ m_Rotation(SKULL_ROTATION_NORTH),
m_Owner("")
{
}