diff options
Diffstat (limited to 'src/BlockEntities')
-rw-r--r-- | src/BlockEntities/BeaconEntity.cpp | 116 | ||||
-rw-r--r-- | src/BlockEntities/BeaconEntity.h | 44 | ||||
-rw-r--r-- | src/BlockEntities/BlockEntity.cpp | 2 | ||||
-rw-r--r-- | src/BlockEntities/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/BlockEntities/CommandBlockEntity.cpp | 3 | ||||
-rw-r--r-- | src/BlockEntities/DispenserEntity.cpp | 97 | ||||
-rw-r--r-- | src/BlockEntities/DispenserEntity.h | 26 | ||||
-rw-r--r-- | src/BlockEntities/FurnaceEntity.cpp | 7 | ||||
-rw-r--r-- | src/BlockEntities/HopperEntity.cpp | 11 | ||||
-rw-r--r-- | src/BlockEntities/MobHeadEntity.cpp | 2 |
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("") { } |