summaryrefslogtreecommitdiffstats
path: root/source/BlockEntities
diff options
context:
space:
mode:
Diffstat (limited to 'source/BlockEntities')
-rw-r--r--source/BlockEntities/BlockEntity.cpp44
-rw-r--r--source/BlockEntities/BlockEntity.h106
-rw-r--r--source/BlockEntities/BlockEntityWithItems.h86
-rw-r--r--source/BlockEntities/ChestEntity.cpp172
-rw-r--r--source/BlockEntities/ChestEntity.h59
-rw-r--r--source/BlockEntities/DispenserEntity.cpp215
-rw-r--r--source/BlockEntities/DispenserEntity.h38
-rw-r--r--source/BlockEntities/DropSpenserEntity.cpp266
-rw-r--r--source/BlockEntities/DropSpenserEntity.h89
-rw-r--r--source/BlockEntities/DropperEntity.cpp32
-rw-r--r--source/BlockEntities/DropperEntity.h46
-rw-r--r--source/BlockEntities/FurnaceEntity.cpp479
-rw-r--r--source/BlockEntities/FurnaceEntity.h164
-rw-r--r--source/BlockEntities/HopperEntity.cpp566
-rw-r--r--source/BlockEntities/HopperEntity.h96
-rw-r--r--source/BlockEntities/JukeboxEntity.cpp125
-rw-r--r--source/BlockEntities/JukeboxEntity.h56
-rw-r--r--source/BlockEntities/NoteEntity.cpp154
-rw-r--r--source/BlockEntities/NoteEntity.h63
-rw-r--r--source/BlockEntities/SignEntity.cpp115
-rw-r--r--source/BlockEntities/SignEntity.h67
21 files changed, 0 insertions, 3038 deletions
diff --git a/source/BlockEntities/BlockEntity.cpp b/source/BlockEntities/BlockEntity.cpp
deleted file mode 100644
index 41a488717..000000000
--- a/source/BlockEntities/BlockEntity.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-
-// BlockEntity.cpp
-
-// Implements the cBlockEntity class that is the common ancestor for all block entities
-
-#include "Globals.h"
-#include "BlockEntity.h"
-#include "ChestEntity.h"
-#include "DispenserEntity.h"
-#include "DropperEntity.h"
-#include "FurnaceEntity.h"
-#include "HopperEntity.h"
-#include "JukeboxEntity.h"
-#include "NoteEntity.h"
-#include "SignEntity.h"
-
-
-
-
-
-cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World)
-{
- switch (a_BlockType)
- {
- case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
- case E_BLOCK_DISPENSER: return new cDispenserEntity(a_BlockX, a_BlockY, a_BlockZ, a_World);
- case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
- case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
- case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
- case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
- case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);
- case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);
- case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
- case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
- }
- LOGD("%s: Requesting creation of an unknown block entity - block type %d (%s)",
- __FUNCTION__, a_BlockType, ItemTypeToString(a_BlockType).c_str()
- );
- return NULL;
-}
-
-
-
-
diff --git a/source/BlockEntities/BlockEntity.h b/source/BlockEntities/BlockEntity.h
deleted file mode 100644
index 0d358b556..000000000
--- a/source/BlockEntities/BlockEntity.h
+++ /dev/null
@@ -1,106 +0,0 @@
-
-#pragma once
-
-#include "../ClientHandle.h"
-#include "../World.h"
-
-
-
-
-
-namespace Json
-{
- class Value;
-};
-
-class cPlayer;
-class cPacket;
-
-
-
-
-
-// tolua_begin
-class cBlockEntity
-{
-protected:
- cBlockEntity(BLOCKTYPE a_BlockType, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
- m_PosX(a_BlockX),
- m_PosY(a_BlockY),
- m_PosZ(a_BlockZ),
- m_RelX(a_BlockX - cChunkDef::Width * FAST_FLOOR_DIV(a_BlockX, cChunkDef::Width)),
- m_RelZ(a_BlockZ - cChunkDef::Width * FAST_FLOOR_DIV(a_BlockZ, cChunkDef::Width)),
- m_BlockType(a_BlockType),
- m_World(a_World)
- {
- }
-
-public:
- // tolua_end
-
- virtual ~cBlockEntity() {}; // force a virtual destructor in all descendants
-
- virtual void Destroy(void) {};
-
- void SetWorld(cWorld * a_World)
- {
- m_World = a_World;
- }
-
- /// Creates a new block entity for the specified block type
- /// If a_World is valid, then the entity is created bound to that world
- /// Returns NULL for unknown block types
- static cBlockEntity * CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World = NULL);
-
- static const char * GetClassStatic(void) // Needed for ManualBindings's ForEach templates
- {
- return "cBlockEntity";
- }
-
- // tolua_begin
-
- // Position, in absolute block coordinates:
- int GetPosX(void) const { return m_PosX; }
- int GetPosY(void) const { return m_PosY; }
- int GetPosZ(void) const { return m_PosZ; }
-
- BLOCKTYPE GetBlockType(void) const { return m_BlockType; }
-
- cWorld * GetWorld(void) const {return m_World; }
-
- int GetChunkX(void) const { return FAST_FLOOR_DIV(m_PosX, cChunkDef::Width); }
- int GetChunkZ(void) const { return FAST_FLOOR_DIV(m_PosZ, cChunkDef::Width); }
-
- int GetRelX(void) const { return m_RelX; }
- int GetRelZ(void) const { return m_RelZ; }
-
- // tolua_end
-
- virtual void SaveToJson (Json::Value & a_Value) = 0;
-
- /// Called when a player uses this entity; should open the UI window
- virtual void UsedBy( cPlayer * a_Player ) = 0;
-
- /** Sends the packet defining the block entity to the client specified.
- To send to all eligible clients, use cWorld::BroadcastBlockEntity()
- */
- virtual void SendTo(cClientHandle & a_Client) = 0;
-
- /// Ticks the entity; returns true if the chunk should be marked as dirty as a result of this ticking. By default does nothing.
- virtual bool Tick(float a_Dt, cChunk & a_Chunk) { return false; }
-
-protected:
- /// Position in absolute block coordinates
- int m_PosX, m_PosY, m_PosZ;
-
- /// Position relative to the chunk, used to speed up ticking
- int m_RelX, m_RelZ;
-
- BLOCKTYPE m_BlockType;
-
- cWorld * m_World;
-} ; // tolua_export
-
-
-
-
diff --git a/source/BlockEntities/BlockEntityWithItems.h b/source/BlockEntities/BlockEntityWithItems.h
deleted file mode 100644
index 0846ae17e..000000000
--- a/source/BlockEntities/BlockEntityWithItems.h
+++ /dev/null
@@ -1,86 +0,0 @@
-
-// BlockEntityWithItems.h
-
-// Declares the cBlockEntityWithItems class representing a common ancestor for all block entities that have an ItemGrid
-
-
-
-
-
-#pragma once
-
-#include "BlockEntity.h"
-#include "../ItemGrid.h"
-
-
-
-
-
-// tolua_begin
-class cBlockEntityWithItems :
- public cBlockEntity
- // tolua_end
- // tolua doesn't seem to support multiple inheritance?
- , public cItemGrid::cListener
- // tolua_begin
-{
- typedef cBlockEntity super;
-
-public:
- // tolua_end
-
- cBlockEntityWithItems(
- BLOCKTYPE a_BlockType, // Type of the block that the entity represents
- int a_BlockX, int a_BlockY, int a_BlockZ, // Position of the block entity
- int a_ItemGridWidth, int a_ItemGridHeight, // Dimensions of the ItemGrid
- cWorld * a_World // Optional world to assign to the entity
- ) :
- super(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World),
- m_Contents(a_ItemGridWidth, a_ItemGridHeight)
- {
- m_Contents.AddListener(*this);
- }
-
- virtual void Destroy(void) override
- {
- // Drop the contents as pickups:
- ASSERT(m_World != NULL);
- cItems Pickups;
- m_Contents.CopyToItems(Pickups);
- m_Contents.Clear();
- m_World->SpawnItemPickups(Pickups, m_PosX, m_PosY, m_PosZ);
- }
-
- // tolua_begin
-
- const cItem & GetSlot(int a_SlotNum) const { return m_Contents.GetSlot(a_SlotNum); }
- const cItem & GetSlot(int a_X, int a_Y) const { return m_Contents.GetSlot(a_X, a_Y); }
-
- void SetSlot(int a_SlotNum, const cItem & a_Item) { m_Contents.SetSlot(a_SlotNum, a_Item); }
- void SetSlot(int a_X, int a_Y, const cItem & a_Item) { m_Contents.SetSlot(a_X, a_Y, a_Item); }
-
- /// Returns the ItemGrid used for storing the contents
- cItemGrid & GetContents(void) { return m_Contents; }
-
- // tolua_end
-
- /// Const version of the GetContents() function for C++ type-safety
- const cItemGrid & GetContents(void) const { return m_Contents; }
-
-protected:
- cItemGrid m_Contents;
-
- // cItemGrid::cListener overrides:
- virtual void OnSlotChanged(cItemGrid * a_Grid, int a_SlotNum)
- {
- ASSERT(a_Grid == &m_Contents);
- if (m_World != NULL)
- {
- m_World->MarkChunkDirty(GetChunkX(), GetChunkZ());
- }
- }
-} ; // tolua_export
-
-
-
-
diff --git a/source/BlockEntities/ChestEntity.cpp b/source/BlockEntities/ChestEntity.cpp
deleted file mode 100644
index ca2626bc9..000000000
--- a/source/BlockEntities/ChestEntity.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "ChestEntity.h"
-#include "../Item.h"
-#include "../Entities/Player.h"
-#include "../UI/Window.h"
-#include <json/json.h>
-
-
-
-
-
-cChestEntity::cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
- super(E_BLOCK_CHEST, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World)
-{
- cBlockEntityWindowOwner::SetBlockEntity(this);
-}
-
-
-
-
-
-cChestEntity::~cChestEntity()
-{
- cWindow * Window = GetWindow();
- if (Window != NULL)
- {
- Window->OwnerDestroyed();
- }
-}
-
-
-
-
-
-bool cChestEntity::LoadFromJson(const Json::Value & a_Value)
-{
- m_PosX = a_Value.get("x", 0).asInt();
- m_PosY = a_Value.get("y", 0).asInt();
- m_PosZ = a_Value.get("z", 0).asInt();
-
- Json::Value AllSlots = a_Value.get("Slots", 0);
- int SlotIdx = 0;
- for (Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr)
- {
- cItem Item;
- Item.FromJson(*itr);
- SetSlot(SlotIdx, Item);
- SlotIdx++;
- }
- return true;
-}
-
-
-
-
-
-void cChestEntity::SaveToJson(Json::Value & a_Value)
-{
- a_Value["x"] = m_PosX;
- a_Value["y"] = m_PosY;
- a_Value["z"] = m_PosZ;
-
- Json::Value AllSlots;
- for (int i = m_Contents.GetNumSlots() - 1; i >= 0; i--)
- {
- Json::Value Slot;
- m_Contents.GetSlot(i).GetJson(Slot);
- AllSlots.append(Slot);
- }
- a_Value["Slots"] = AllSlots;
-}
-
-
-
-
-
-void cChestEntity::SendTo(cClientHandle & a_Client)
-{
- // The chest entity doesn't need anything sent to the client when it's created / gets in the viewdistance
- // All the actual handling is in the cWindow UI code that gets called when the chest is rclked
-
- UNUSED(a_Client);
-}
-
-
-
-
-
-void cChestEntity::UsedBy(cPlayer * a_Player)
-{
- // If the window is not created, open it anew:
- cWindow * Window = GetWindow();
- if (Window == NULL)
- {
- OpenNewWindow();
- Window = GetWindow();
- }
-
- // Open the window for the player:
- if (Window != NULL)
- {
- if (a_Player->GetWindow() != Window)
- {
- a_Player->OpenWindow(Window);
- }
- }
-
- // This is rather a hack
- // Instead of marking the chunk as dirty upon chest contents change, we mark it dirty now
- // We cannot properly detect contents change, but such a change doesn't happen without a player opening the chest first.
- // The few false positives aren't much to worry about
- int ChunkX, ChunkZ;
- cChunkDef::BlockToChunk(m_PosX, m_PosZ, ChunkX, ChunkZ);
- m_World->MarkChunkDirty(ChunkX, ChunkZ);
-}
-
-
-
-
-
-void cChestEntity::OpenNewWindow(void)
-{
- // Callback for opening together with neighbor chest:
- class cOpenDouble :
- public cChestCallback
- {
- cChestEntity * m_ThisChest;
- public:
- cOpenDouble(cChestEntity * a_ThisChest) :
- m_ThisChest(a_ThisChest)
- {
- }
-
- virtual bool Item(cChestEntity * a_Chest) override
- {
- // The primary chest should eb the one with lesser X or Z coord:
- cChestEntity * Primary = a_Chest;
- cChestEntity * Secondary = m_ThisChest;
- if (
- (Primary->GetPosX() > Secondary->GetPosX()) ||
- (Primary->GetPosZ() > Secondary->GetPosZ())
- )
- {
- std::swap(Primary, Secondary);
- }
- m_ThisChest->OpenWindow(new cChestWindow(Primary, Secondary));
- return false;
- }
- } ;
-
- // Scan neighbors for adjacent chests:
- cOpenDouble OpenDbl(this);
- if (
- m_World->DoWithChestAt(m_PosX - 1, m_PosY, m_PosZ, OpenDbl) ||
- m_World->DoWithChestAt(m_PosX + 1, m_PosY, m_PosZ, OpenDbl) ||
- m_World->DoWithChestAt(m_PosX , m_PosY, m_PosZ - 1, OpenDbl) ||
- m_World->DoWithChestAt(m_PosX , m_PosY, m_PosZ + 1, OpenDbl)
- )
- {
- // The double-chest window has been opened in the callback
- return;
- }
-
- // There is no chest neighbor, open a single-chest window:
- OpenWindow(new cChestWindow(this));
-}
-
-
-
-
diff --git a/source/BlockEntities/ChestEntity.h b/source/BlockEntities/ChestEntity.h
deleted file mode 100644
index 4f2c21e91..000000000
--- a/source/BlockEntities/ChestEntity.h
+++ /dev/null
@@ -1,59 +0,0 @@
-
-#pragma once
-
-#include "BlockEntityWithItems.h"
-#include "../UI/WindowOwner.h"
-
-
-
-
-
-namespace Json
-{
- class Value;
-};
-
-class cClientHandle;
-class cServer;
-class cNBTData;
-
-
-
-
-
-class cChestEntity : // tolua_export
- public cBlockEntityWindowOwner,
- // tolua_begin
- public cBlockEntityWithItems
-{
- typedef cBlockEntityWithItems super;
-
-public:
- enum {
- ContentsHeight = 3,
- ContentsWidth = 9,
- } ;
-
- // tolua_end
-
- /// Constructor used for normal operation
- cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
-
- virtual ~cChestEntity();
-
- static const char * GetClassStatic(void) { return "cChestEntity"; }
-
- bool LoadFromJson(const Json::Value & a_Value);
-
- // cBlockEntity overrides:
- virtual void SaveToJson(Json::Value & a_Value) override;
- virtual void SendTo(cClientHandle & a_Client) override;
- virtual void UsedBy(cPlayer * a_Player) override;
-
- /// Opens a new chest window for this chest. Scans for neighbors to open a double chest window, if appropriate.
- void OpenNewWindow(void);
-} ; // tolua_export
-
-
-
-
diff --git a/source/BlockEntities/DispenserEntity.cpp b/source/BlockEntities/DispenserEntity.cpp
deleted file mode 100644
index 374f3d6e3..000000000
--- a/source/BlockEntities/DispenserEntity.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "DispenserEntity.h"
-#include "../Entities/Player.h"
-#include "../Simulator/FluidSimulator.h"
-#include "../Chunk.h"
-
-
-
-
-
-cDispenserEntity::cDispenserEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
- super(E_BLOCK_DISPENSER, a_BlockX, a_BlockY, a_BlockZ, a_World)
-{
- SetBlockEntity(this); // cBlockEntityWindowOwner
-}
-
-
-
-
-
-void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
-{
- int DispX = m_RelX;
- int DispY = m_PosY;
- int DispZ = m_RelZ;
- NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ);
- AddDropSpenserDir(DispX, DispY, DispZ, Meta);
- cChunk * DispChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(DispX, DispZ);
- if (DispChunk == NULL)
- {
- // Would dispense into / interact with a non-loaded chunk, ignore the tick
- return;
- }
- BLOCKTYPE DispBlock = DispChunk->GetBlock(DispX, DispY, DispZ);
-
- // Dispense the item:
- switch (m_Contents.GetSlot(a_SlotNum).m_ItemType)
- {
- case E_ITEM_BUCKET:
- {
- LOGD("Dispensing empty bucket in slot %d; DispBlock is \"%s\" (%d).", a_SlotNum, ItemTypeToString(DispBlock).c_str(), DispBlock);
- switch (DispBlock)
- {
- case E_BLOCK_STATIONARY_WATER:
- case E_BLOCK_WATER:
- {
- if (ScoopUpLiquid(a_SlotNum, E_ITEM_WATER_BUCKET))
- {
- DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_AIR, 0);
- }
- break;
- }
- case E_BLOCK_STATIONARY_LAVA:
- case E_BLOCK_LAVA:
- {
- if (ScoopUpLiquid(a_SlotNum, E_ITEM_LAVA_BUCKET))
- {
- DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_AIR, 0);
- }
- break;
- }
- default:
- {
- DropFromSlot(a_Chunk, a_SlotNum);
- break;
- }
- }
- 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);
- if (EmptyLiquidBucket(DispBlock, a_SlotNum))
- {
- DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_WATER, 0);
- }
- else
- {
- DropFromSlot(a_Chunk, 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);
- if (EmptyLiquidBucket(DispBlock, a_SlotNum))
- {
- DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_LAVA, 0);
- }
- else
- {
- DropFromSlot(a_Chunk, a_SlotNum);
- }
- break;
- }
-
- case E_ITEM_SPAWN_EGG:
- {
- double MobX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width);
- double MobZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width);
- if (m_World->SpawnMob(MobX, DispY, MobZ, (cMonster::eType)m_Contents.GetSlot(a_SlotNum).m_ItemDamage) >= 0)
- {
- m_Contents.ChangeSlotCount(a_SlotNum, -1);
- }
- break;
- }
-
- case E_BLOCK_TNT:
- {
- // Spawn a primed TNT entity, if space allows:
- if (DispChunk->GetBlock(DispX, DispY, DispZ) == E_BLOCK_AIR)
- {
- double TNTX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width);
- double TNTZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width);
- m_World->SpawnPrimedTNT(TNTX, DispY + 0.5, TNTZ, 4, 0); // 4 seconds fuse, no initial velocity
- m_Contents.ChangeSlotCount(a_SlotNum, -1);
- }
- break;
- }
-
- case E_ITEM_FLINT_AND_STEEL:
- {
- // Spawn fire if the block in front is air.
- 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)
- {
- m_Contents.ChangeSlotCount(a_SlotNum, -1);
- }
- }
- break;
- }
-
- default:
- {
- DropFromSlot(a_Chunk, a_SlotNum);
- break;
- }
- } // switch (ItemType)
-}
-
-
-
-
-
-
-bool cDispenserEntity::ScoopUpLiquid(int a_SlotNum, short a_BucketItemType)
-{
- cItem LiquidBucket(a_BucketItemType, 1);
- if (m_Contents.GetSlot(a_SlotNum).m_ItemCount == 1)
- {
- // Special case: replacing one empty bucket with one full bucket
- 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;
-}
-
-
-
-
-
-bool cDispenserEntity::EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum)
-{
- if (
- (a_BlockInFront != E_BLOCK_AIR) &&
- !IsBlockLiquid(a_BlockInFront) &&
- !cFluidSimulator::CanWashAway(a_BlockInFront)
- )
- {
- // Not a suitable block in front
- return false;
- }
-
- cItem EmptyBucket(E_ITEM_BUCKET, 1);
- if (m_Contents.GetSlot(a_SlotNum).m_ItemCount == 1)
- {
- // Change the single full bucket present into a single empty bucket
- 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);
- return true;
-}
-
-
-
-
diff --git a/source/BlockEntities/DispenserEntity.h b/source/BlockEntities/DispenserEntity.h
deleted file mode 100644
index fdfe4e5b4..000000000
--- a/source/BlockEntities/DispenserEntity.h
+++ /dev/null
@@ -1,38 +0,0 @@
-
-#pragma once
-
-#include "DropSpenserEntity.h"
-
-
-
-
-
-// tolua_begin
-class cDispenserEntity :
- public cDropSpenserEntity
-{
- typedef cDropSpenserEntity super;
-
-public:
-
- // tolua_end
-
- /// 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"; }
-
-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
- 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
- bool EmptyLiquidBucket(BLOCKTYPE a_BlockInFront, int a_SlotNum);
-} ; // tolua_export
-
-
-
-
diff --git a/source/BlockEntities/DropSpenserEntity.cpp b/source/BlockEntities/DropSpenserEntity.cpp
deleted file mode 100644
index 823ed598f..000000000
--- a/source/BlockEntities/DropSpenserEntity.cpp
+++ /dev/null
@@ -1,266 +0,0 @@
-
-// DropSpenserEntity.cpp
-
-// Declares the cDropSpenserEntity class representing a common ancestor to the cDispenserEntity and cDropperEntity
-// The dropper and dispenser only needs to override the DropSpenseFromSlot() function to provide the specific item behavior
-
-#include "Globals.h"
-#include "DropSpenserEntity.h"
-#include "../Entities/Player.h"
-#include "../Chunk.h"
-
-
-
-
-
-cDropSpenserEntity::cDropSpenserEntity(BLOCKTYPE a_BlockType, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
- super(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World),
- m_ShouldDropSpense(false),
- m_IsPowered(false)
-{
- SetBlockEntity(this); // cBlockEntityWindowOwner
-}
-
-
-
-
-
-cDropSpenserEntity::~cDropSpenserEntity()
-{
- // Tell window its owner is destroyed
- cWindow * Window = GetWindow();
- if (Window != NULL)
- {
- Window->OwnerDestroyed();
- }
-}
-
-
-
-
-
-void cDropSpenserEntity::AddDropSpenserDir(int & a_BlockX, int & a_BlockY, int & a_BlockZ, NIBBLETYPE a_Direction)
-{
- switch (a_Direction)
- {
- case E_META_DROPSPENSER_FACING_YM: a_BlockY--; return;
- case E_META_DROPSPENSER_FACING_YP: a_BlockY++; return;
- case E_META_DROPSPENSER_FACING_ZM: a_BlockZ--; return;
- case E_META_DROPSPENSER_FACING_ZP: a_BlockZ++; return;
- case E_META_DROPSPENSER_FACING_XM: a_BlockX--; return;
- case E_META_DROPSPENSER_FACING_XP: a_BlockX++; return;
- }
- LOGWARNING("%s: Unhandled direction: %d", __FUNCTION__, a_Direction);
- return;
-}
-
-
-
-
-
-void cDropSpenserEntity::DropSpense(cChunk & a_Chunk)
-{
- // Pick one of the occupied slots:
- int OccupiedSlots[9];
- int SlotsCnt = 0;
- for (int i = m_Contents.GetNumSlots() - 1; i >= 0; i--)
- {
- if (!m_Contents.GetSlot(i).IsEmpty())
- {
- OccupiedSlots[SlotsCnt] = i;
- SlotsCnt++;
- }
- } // for i - m_Contents[]
-
- if (SlotsCnt == 0)
- {
- // Nothing in the dropspenser, play the click sound
- m_World->BroadcastSoundEffect("random.click", m_PosX * 8, m_PosY * 8, m_PosZ * 8, 1.0f, 1.2f);
- return;
- }
-
- int RandomSlot = m_World->GetTickRandomNumber(SlotsCnt - 1);
-
- // DropSpense the item, using the specialized behavior in the subclasses:
- DropSpenseFromSlot(a_Chunk, OccupiedSlots[RandomSlot]);
-
- // Broadcast a smoke and click effects:
- NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ);
- int SmokeDir = 0;
- switch (Meta)
- {
- case E_META_DROPSPENSER_FACING_YP: SmokeDir = 4; break; // YP & YM don't have associated smoke dirs, just do 4 (centre of block)
- case E_META_DROPSPENSER_FACING_YM: SmokeDir = 4; break;
- case E_META_DROPSPENSER_FACING_XM: SmokeDir = 3; break;
- case E_META_DROPSPENSER_FACING_XP: SmokeDir = 5; break;
- case E_META_DROPSPENSER_FACING_ZM: SmokeDir = 1; break;
- case E_META_DROPSPENSER_FACING_ZP: SmokeDir = 7; break;
- }
- m_World->BroadcastSoundParticleEffect(2000, m_PosX, m_PosY, m_PosZ, SmokeDir);
- m_World->BroadcastSoundEffect("random.click", m_PosX * 8, m_PosY * 8, m_PosZ * 8, 1.0f, 1.0f);
-
- // Update the UI window, if open:
- cWindow * Window = GetWindow();
- if (Window != NULL)
- {
- Window->BroadcastWholeWindow();
- }
-}
-
-
-
-
-
-void cDropSpenserEntity::Activate(void)
-{
- m_ShouldDropSpense = true;
-}
-
-
-
-
-
-void cDropSpenserEntity::SetRedstonePower(bool a_IsPowered)
-{
- if (a_IsPowered && !m_IsPowered)
- {
- Activate();
- }
- m_IsPowered = a_IsPowered;
-}
-
-
-
-
-
-bool cDropSpenserEntity::Tick(float a_Dt, cChunk & a_Chunk)
-{
- if (!m_ShouldDropSpense)
- {
- return false;
- }
-
- m_ShouldDropSpense = false;
- DropSpense(a_Chunk);
- return true;
-}
-
-
-
-
-
-bool cDropSpenserEntity::LoadFromJson(const Json::Value & a_Value)
-{
- m_PosX = a_Value.get("x", 0).asInt();
- m_PosY = a_Value.get("y", 0).asInt();
- m_PosZ = a_Value.get("z", 0).asInt();
-
- Json::Value AllSlots = a_Value.get("Slots", 0);
- int SlotIdx = 0;
- for (Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr)
- {
- cItem Contents;
- Contents.FromJson(*itr);
- m_Contents.SetSlot(SlotIdx, Contents);
- SlotIdx++;
- if (SlotIdx >= m_Contents.GetNumSlots())
- {
- return true;
- }
- }
-
- return true;
-}
-
-
-
-
-
-void cDropSpenserEntity::SaveToJson(Json::Value & a_Value)
-{
- a_Value["x"] = m_PosX;
- a_Value["y"] = m_PosY;
- a_Value["z"] = m_PosZ;
-
- Json::Value AllSlots;
- int NumSlots = m_Contents.GetNumSlots();
- for (int i = 0; i < NumSlots; i++)
- {
- Json::Value Slot;
- m_Contents.GetSlot(i).GetJson(Slot);
- AllSlots.append(Slot);
- }
- a_Value["Slots"] = AllSlots;
-}
-
-
-
-
-
-void cDropSpenserEntity::SendTo(cClientHandle & a_Client)
-{
- // Nothing needs to be sent
- UNUSED(a_Client);
-}
-
-
-
-
-
-void cDropSpenserEntity::UsedBy(cPlayer * a_Player)
-{
- cWindow * Window = GetWindow();
- if (Window == NULL)
- {
- OpenWindow(new cDropSpenserWindow(m_PosX, m_PosY, m_PosZ, this));
- Window = GetWindow();
- }
-
- if (Window != NULL)
- {
- if (a_Player->GetWindow() != Window)
- {
- a_Player->OpenWindow(Window);
- }
- }
-}
-
-
-
-
-
-void cDropSpenserEntity::DropFromSlot(cChunk & a_Chunk, int a_SlotNum)
-{
- int DispX = m_PosX;
- int DispY = m_PosY;
- int DispZ = m_PosZ;
- NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ);
- AddDropSpenserDir(DispX, DispY, DispZ, Meta);
-
- cItems Pickups;
- Pickups.push_back(m_Contents.RemoveOneItem(a_SlotNum));
-
- const int PickupSpeed = m_World->GetTickRandomNumber(4) + 2; // At least 2, at most 6
- int PickupSpeedX = 0, PickupSpeedY = 0, PickupSpeedZ = 0;
- switch (Meta)
- {
- case E_META_DROPSPENSER_FACING_YP: PickupSpeedY = PickupSpeed; break;
- case E_META_DROPSPENSER_FACING_YM: PickupSpeedY = -PickupSpeed; break;
- case E_META_DROPSPENSER_FACING_XM: PickupSpeedX = -PickupSpeed; break;
- case E_META_DROPSPENSER_FACING_XP: PickupSpeedX = PickupSpeed; break;
- case E_META_DROPSPENSER_FACING_ZM: PickupSpeedZ = -PickupSpeed; break;
- case E_META_DROPSPENSER_FACING_ZP: PickupSpeedZ = PickupSpeed; break;
- }
-
- double MicroX, MicroY, MicroZ;
- MicroX = DispX + 0.5;
- MicroY = DispY + 0.4; // Slightly less than half, to accomodate actual texture hole on DropSpenser
- MicroZ = DispZ + 0.5;
-
-
- m_World->SpawnItemPickups(Pickups, MicroX, MicroY, MicroZ, PickupSpeedX, PickupSpeedY, PickupSpeedZ);
-}
-
-
-
-
diff --git a/source/BlockEntities/DropSpenserEntity.h b/source/BlockEntities/DropSpenserEntity.h
deleted file mode 100644
index 0e9039915..000000000
--- a/source/BlockEntities/DropSpenserEntity.h
+++ /dev/null
@@ -1,89 +0,0 @@
-
-// DropSpenser.h
-
-// Declares the cDropSpenser class representing a common ancestor to the cDispenserEntity and cDropperEntity
-// The dropper and dispenser only needs to override the DropSpenseFromSlot() function to provide the specific item behavior
-
-
-
-
-
-#pragma once
-
-#include "BlockEntityWithItems.h"
-#include "../UI/WindowOwner.h"
-
-
-
-
-
-namespace Json
-{
- class Value;
-}
-
-class cClientHandle;
-class cServer;
-
-
-
-
-
-class cDropSpenserEntity : // tolua_export
- public cBlockEntityWindowOwner,
- // tolua_begin
- public cBlockEntityWithItems
-{
- typedef cBlockEntityWithItems super;
-
-public:
- enum {
- ContentsHeight = 3,
- ContentsWidth = 3,
- } ;
-
- // tolua_end
-
- cDropSpenserEntity(BLOCKTYPE a_BlockType, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
- virtual ~cDropSpenserEntity();
-
- static const char * GetClassStatic(void) { return "cDropSpenserEntity"; }
-
- bool LoadFromJson(const Json::Value & a_Value);
-
- // cBlockEntity overrides:
- virtual void SaveToJson(Json::Value & a_Value) override;
- virtual bool Tick(float a_Dt, cChunk & a_Chunk) override;
- virtual void SendTo(cClientHandle & a_Client) override;
- virtual void UsedBy(cPlayer * a_Player) override;
-
- // tolua_begin
-
- /// Modifies the block coords to match the dropspenser direction given (where the dropspensed pickups should materialize)
- void AddDropSpenserDir(int & a_BlockX, int & a_BlockY, int & a_BlockZ, NIBBLETYPE a_Direction);
-
- /// Sets the dropspenser to dropspense an item in the next tick
- void Activate(void);
-
- /// Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate
- void SetRedstonePower(bool a_IsPowered);
-
- // tolua_end
-
-protected:
- bool m_ShouldDropSpense; ///< If true, the dropspenser will dropspense an item in the next tick
- bool m_IsPowered; ///< Set to true when the dropspenser receives redstone power.
-
- /// Does the actual work on dropspensing an item. Chooses the slot, calls DropSpenseFromSlot() and handles smoke / sound effects
- void DropSpense(cChunk & a_Chunk);
-
- /// Override this function to provide the specific behavior for item dropspensing (drop / shoot / pour / ...)
- virtual void DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) = 0;
-
- /// Helper function, drops one item from the specified slot (like a dropper)
- void DropFromSlot(cChunk & a_Chunk, int a_SlotNum);
-} ; // tolua_export
-
-
-
-
diff --git a/source/BlockEntities/DropperEntity.cpp b/source/BlockEntities/DropperEntity.cpp
deleted file mode 100644
index 5d4a8ad97..000000000
--- a/source/BlockEntities/DropperEntity.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-
-// DropperEntity.cpp
-
-// Implements the cRtopperEntity class representing a Dropper block entity
-
-#include "Globals.h"
-#include "DropperEntity.h"
-#include "../Entities/Player.h"
-#include "../Simulator/FluidSimulator.h"
-
-
-
-
-
-cDropperEntity::cDropperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
- super(E_BLOCK_DROPPER, a_BlockX, a_BlockY, a_BlockZ, a_World)
-{
- SetBlockEntity(this); // cBlockEntityWindowOwner
-}
-
-
-
-
-
-void cDropperEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
-{
- DropFromSlot(a_Chunk, a_SlotNum);
-}
-
-
-
-
diff --git a/source/BlockEntities/DropperEntity.h b/source/BlockEntities/DropperEntity.h
deleted file mode 100644
index 8e07bc6f8..000000000
--- a/source/BlockEntities/DropperEntity.h
+++ /dev/null
@@ -1,46 +0,0 @@
-
-// DropperEntity.h
-
-// Declares the cDropperEntity class representing a dropper block entity
-
-
-
-
-
-#pragma once
-
-#include "DropSpenserEntity.h"
-
-
-
-
-
-// tolua_begin
-class cDropperEntity :
- public cDropSpenserEntity
-{
- typedef cDropSpenserEntity super;
-
-public:
-
- // tolua_end
-
- /// Constructor used for normal operation
- cDropperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
-
- static const char * GetClassStatic(void) { return "cDropperEntity"; }
-
-protected:
- // cDropSpenserEntity overrides:
- virtual void DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) override;
-
- /** Takes an item from slot a_SlotNum and puts it into the container in front of the dropper.
- Called when there's a container directly in front of the dropper,
- so the dropper should store items there, rather than dropping.
- */
- void PutIntoContainer(cChunk & a_Chunk, int a_SlotNum, BLOCKTYPE a_ContainerBlock, int a_ContainerX, int a_ContainerY, int a_ContainerZ);
-} ; // tolua_export
-
-
-
-
diff --git a/source/BlockEntities/FurnaceEntity.cpp b/source/BlockEntities/FurnaceEntity.cpp
deleted file mode 100644
index ec5ebe8b9..000000000
--- a/source/BlockEntities/FurnaceEntity.cpp
+++ /dev/null
@@ -1,479 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "FurnaceEntity.h"
-#include "../UI/Window.h"
-#include "../Entities/Player.h"
-#include "../Root.h"
-#include "../Chunk.h"
-#include <json/json.h>
-
-
-
-
-
-
-enum
-{
- PROGRESSBAR_SMELTING = 0,
- PROGRESSBAR_FUEL = 1,
-} ;
-
-
-
-
-
-cFurnaceEntity::cFurnaceEntity(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cWorld * a_World) :
- super(E_BLOCK_FURNACE, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World),
- m_BlockType(a_BlockType),
- m_BlockMeta(a_BlockMeta),
- m_CurrentRecipe(NULL),
- m_IsCooking((a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_LIT_FURNACE)),
- m_NeedCookTime(0),
- m_TimeCooked(0),
- m_FuelBurnTime(0),
- m_TimeBurned(0),
- m_LastProgressFuel(0),
- m_LastProgressCook(0)
-{
- cBlockEntityWindowOwner::SetBlockEntity(this);
- m_Contents.AddListener(*this);
-}
-
-
-
-
-
-cFurnaceEntity::~cFurnaceEntity()
-{
- // Tell window its owner is destroyed
- cWindow * Window = GetWindow();
- if (Window != NULL)
- {
- Window->OwnerDestroyed();
- }
-}
-
-
-
-
-
-void cFurnaceEntity::UsedBy(cPlayer * a_Player)
-{
- if (GetWindow() == NULL)
- {
- OpenWindow(new cFurnaceWindow(m_PosX, m_PosY, m_PosZ, this));
- }
- cWindow * Window = GetWindow();
- if (Window != NULL)
- {
- if (a_Player->GetWindow() != Window)
- {
- a_Player->OpenWindow(Window);
- BroadcastProgress(PROGRESSBAR_FUEL, m_LastProgressFuel);
- BroadcastProgress(PROGRESSBAR_SMELTING, m_LastProgressCook);
- }
- }
-}
-
-
-
-
-
-/// Restarts cooking. Used after the furnace is loaded from storage to set up the internal variables so that cooking continues, if it was active. Returns true if cooking.
-bool cFurnaceEntity::ContinueCooking(void)
-{
- UpdateInput();
- UpdateFuel();
- return m_IsCooking;
-}
-
-
-
-
-
-bool cFurnaceEntity::Tick(float a_Dt, cChunk & a_Chunk)
-{
- if (m_FuelBurnTime <= 0)
- {
- // No fuel is burning, reset progressbars and bail out
- if ((m_LastProgressCook > 0) || (m_LastProgressFuel > 0))
- {
- UpdateProgressBars();
- }
- return false;
- }
-
- if (m_IsCooking)
- {
- m_TimeCooked++;
- if (m_TimeCooked >= m_NeedCookTime)
- {
- // Finished smelting one item
- FinishOne(a_Chunk);
- }
- }
-
- m_TimeBurned++;
- if (m_TimeBurned >= m_FuelBurnTime)
- {
- // The current fuel has been exhausted, use another one, if possible
- BurnNewFuel();
- }
-
- UpdateProgressBars();
-
- return true;
-}
-
-
-
-
-
-bool cFurnaceEntity::LoadFromJson(const Json::Value & a_Value)
-{
- m_PosX = a_Value.get("x", 0).asInt();
- m_PosY = a_Value.get("y", 0).asInt();
- m_PosZ = a_Value.get("z", 0).asInt();
-
- Json::Value AllSlots = a_Value.get("Slots", 0);
- int SlotIdx = 0;
- for (Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr)
- {
- cItem Item;
- Item.FromJson(*itr);
- SetSlot(SlotIdx, Item);
- SlotIdx++;
- }
-
- m_NeedCookTime = (int)(a_Value.get("CookTime", 0).asDouble() / 50);
- m_TimeCooked = (int)(a_Value.get("TimeCooked", 0).asDouble() / 50);
- m_FuelBurnTime = (int)(a_Value.get("BurnTime", 0).asDouble() / 50);
- m_TimeBurned = (int)(a_Value.get("TimeBurned", 0).asDouble() / 50);
-
- return true;
-}
-
-
-
-
-
-void cFurnaceEntity::SaveToJson( Json::Value& a_Value )
-{
- a_Value["x"] = m_PosX;
- a_Value["y"] = m_PosY;
- a_Value["z"] = m_PosZ;
-
- Json::Value AllSlots;
- int NumSlots = m_Contents.GetNumSlots();
- for (int i = 0; i < NumSlots; i++)
- {
- Json::Value Slot;
- m_Contents.GetSlot(i).GetJson(Slot);
- AllSlots.append(Slot);
- }
- a_Value["Slots"] = AllSlots;
-
- a_Value["CookTime"] = m_NeedCookTime * 50;
- a_Value["TimeCooked"] = m_TimeCooked * 50;
- a_Value["BurnTime"] = m_FuelBurnTime * 50;
- a_Value["TimeBurned"] = m_TimeBurned * 50;
-}
-
-
-
-
-
-void cFurnaceEntity::SendTo(cClientHandle & a_Client)
-{
- // Nothing needs to be sent
- UNUSED(a_Client);
-}
-
-
-
-
-
-void cFurnaceEntity::BroadcastProgress(int a_ProgressbarID, short a_Value)
-{
- cWindow * Window = GetWindow();
- if (Window != NULL)
- {
- Window->BroadcastProgress(a_ProgressbarID, a_Value);
- }
-}
-
-
-
-
-
-/// One item finished cooking
-void cFurnaceEntity::FinishOne(cChunk & a_Chunk)
-{
- m_TimeCooked = 0;
-
- if (m_Contents.GetSlot(fsOutput).IsEmpty())
- {
- m_Contents.SetSlot(fsOutput, *m_CurrentRecipe->Out);
- }
- else
- {
- m_Contents.ChangeSlotCount(fsOutput, m_CurrentRecipe->Out->m_ItemCount);
- }
- m_Contents.ChangeSlotCount(fsInput, -m_CurrentRecipe->In->m_ItemCount);
-
- UpdateIsCooking();
-}
-
-
-
-
-
-void cFurnaceEntity::BurnNewFuel(void)
-{
- cFurnaceRecipe * FR = cRoot::Get()->GetFurnaceRecipe();
- int NewTime = FR->GetBurnTime(m_Contents.GetSlot(fsFuel));
- if (NewTime == 0)
- {
- // The item in the fuel slot is not suitable
- m_FuelBurnTime = 0;
- m_TimeBurned = 0;
- SetIsCooking(false);
- return;
- }
-
- // Is the input and output ready for cooking?
- if (!CanCookInputToOutput())
- {
- return;
- }
-
- // Burn one new fuel:
- m_FuelBurnTime = NewTime;
- m_TimeBurned = 0;
- SetIsCooking(true);
- if (m_Contents.GetSlot(fsFuel).m_ItemType == E_ITEM_LAVA_BUCKET)
- {
- m_Contents.SetSlot(fsFuel, cItem(E_ITEM_BUCKET));
- }
- else
- {
- m_Contents.ChangeSlotCount(fsFuel, -1);
- }
-}
-
-
-
-
-
-void cFurnaceEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
-{
- super::OnSlotChanged(a_ItemGrid, a_SlotNum);
-
- if (m_World == NULL)
- {
- // The furnace isn't initialized yet, do no processing
- return;
- }
-
- ASSERT(a_ItemGrid == &m_Contents);
- switch (a_SlotNum)
- {
- case fsInput:
- {
- UpdateInput();
- break;
- }
-
- case fsFuel:
- {
- UpdateFuel();
- break;
- }
-
- case fsOutput:
- {
- UpdateOutput();
- break;
- }
- }
-}
-
-
-
-
-
-
-/// Updates the current recipe, based on the current input
-void cFurnaceEntity::UpdateInput(void)
-{
- if (!m_Contents.GetSlot(fsInput).IsStackableWith(m_LastInput))
- {
- // The input is different from what we had before, reset the cooking time
- m_TimeCooked = 0;
- }
- m_LastInput = m_Contents.GetSlot(fsInput);
-
- cFurnaceRecipe * FR = cRoot::Get()->GetFurnaceRecipe();
- m_CurrentRecipe = FR->GetRecipeFrom(m_Contents.GetSlot(fsInput));
- if (!CanCookInputToOutput())
- {
- // This input cannot be cooked
- m_NeedCookTime = 0;
- SetIsCooking(false);
- }
- else
- {
- m_NeedCookTime = m_CurrentRecipe->CookTime;
- SetIsCooking(true);
-
- // Start burning new fuel if there's no flame now:
- if (GetFuelBurnTimeLeft() <= 0)
- {
- BurnNewFuel();
- }
- }
-}
-
-
-
-
-
-/// Called when the fuel slot changes or when the fuel is spent, burns another piece of fuel if appropriate
-void cFurnaceEntity::UpdateFuel(void)
-{
- if (m_FuelBurnTime > m_TimeBurned)
- {
- // The current fuel is still burning, don't modify anything:
- return;
- }
-
- // The current fuel is spent, try to burn some more:
- BurnNewFuel();
-}
-
-
-
-
-
-/// Called when the output slot changes; starts burning if space became available
-void cFurnaceEntity::UpdateOutput(void)
-{
- if (!CanCookInputToOutput())
- {
- // Cannot cook anymore:
- m_TimeCooked = 0;
- m_NeedCookTime = 0;
- SetIsCooking(false);
- return;
- }
-
- // No need to burn new fuel, the Tick() function will take care of that
-
- // Can cook, start cooking if not already underway:
- m_NeedCookTime = m_CurrentRecipe->CookTime;
- SetIsCooking(m_FuelBurnTime > 0);
-}
-
-
-
-
-
-/// Updates the m_IsCooking, based on the input slot, output slot and m_FuelBurnTime / m_TimeBurned
-void cFurnaceEntity::UpdateIsCooking(void)
-{
- if (
- !CanCookInputToOutput() || // Cannot cook this
- (m_FuelBurnTime <= 0) || // No fuel
- (m_TimeBurned >= m_FuelBurnTime) // Fuel burnt out
- )
- {
- // Reset everything
- SetIsCooking(false);
- m_TimeCooked = 0;
- m_NeedCookTime = 0;
- return;
- }
-
- SetIsCooking(true);
-}
-
-
-
-
-
-/// Returns true if the input can be cooked into output and the item counts allow for another cooking operation
-bool cFurnaceEntity::CanCookInputToOutput(void) const
-{
- if (m_CurrentRecipe == NULL)
- {
- // This input cannot be cooked
- return false;
- }
-
- if (m_Contents.GetSlot(fsOutput).IsEmpty())
- {
- // The output is empty, can cook
- return true;
- }
-
- if (!m_Contents.GetSlot(fsOutput).IsStackableWith(*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())
- {
- // Cannot add any more items to the output slot
- return false;
- }
-
- return true;
-}
-
-
-
-
-
-/// Broadcasts progressbar updates, if needed
-void cFurnaceEntity::UpdateProgressBars(void)
-{
- // In order to preserve bandwidth, an update is sent only every 10th tick
- // That's why the comparisons use the division by eight
-
- int CurFuel = (m_FuelBurnTime > 0) ? (200 - 200 * m_TimeBurned / m_FuelBurnTime) : 0;
- if ((CurFuel / 8) != (m_LastProgressFuel / 8))
- {
- BroadcastProgress(PROGRESSBAR_FUEL, CurFuel);
- m_LastProgressFuel = CurFuel;
- }
-
- int CurCook = (m_NeedCookTime > 0) ? (200 * m_TimeCooked / m_NeedCookTime) : 0;
- if ((CurCook / 8) != (m_LastProgressCook / 8))
- {
- BroadcastProgress(PROGRESSBAR_SMELTING, CurCook);
- m_LastProgressCook = CurCook;
- }
-}
-
-
-
-
-
-void cFurnaceEntity::SetIsCooking(bool a_IsCooking)
-{
- if (a_IsCooking == m_IsCooking)
- {
- return;
- }
-
- m_IsCooking = a_IsCooking;
-
- // Light or extinguish the furnace:
- m_World->FastSetBlock(m_PosX, m_PosY, m_PosZ, m_IsCooking ? E_BLOCK_LIT_FURNACE : E_BLOCK_FURNACE, m_BlockMeta);
-}
-
-
-
-
diff --git a/source/BlockEntities/FurnaceEntity.h b/source/BlockEntities/FurnaceEntity.h
deleted file mode 100644
index 9464fd175..000000000
--- a/source/BlockEntities/FurnaceEntity.h
+++ /dev/null
@@ -1,164 +0,0 @@
-
-#pragma once
-
-#include "BlockEntityWithItems.h"
-#include "../UI/WindowOwner.h"
-#include "../FurnaceRecipe.h"
-
-
-
-
-
-namespace Json
-{
- class Value;
-}
-
-class cClientHandle;
-class cServer;
-
-
-
-
-
-class cFurnaceEntity : // tolua_export
- public cBlockEntityWindowOwner,
- // tolua_begin
- public cBlockEntityWithItems
-{
- typedef cBlockEntityWithItems super;
-
-public:
- enum
- {
- fsInput = 0, // Input slot number
- fsFuel = 1, // Fuel slot number
- fsOutput = 2, // Output slot number
-
- ContentsWidth = 3,
- ContentsHeight = 1,
- };
-
- // tolua_end
-
- /// Constructor used for normal operation
- cFurnaceEntity(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cWorld * a_World);
-
- virtual ~cFurnaceEntity();
-
- static const char * GetClassStatic() { return "cFurnaceEntity"; }
-
- bool LoadFromJson(const Json::Value & a_Value);
-
- // cBlockEntity overrides:
- virtual void SaveToJson(Json::Value & a_Value) override;
- virtual void SendTo(cClientHandle & a_Client) override;
- virtual bool Tick(float a_Dt, cChunk & a_Chunk) override;
- virtual void UsedBy(cPlayer * a_Player) override;
-
- /// Restarts cooking. Used after the furnace is loaded from storage to set up the internal variables so that cooking continues, if it was active. Returns true if cooking.
- bool ContinueCooking(void);
-
- void ResetCookTimer();
-
- // tolua_begin
-
- /// Returns the item in the input slot
- const cItem & GetInputSlot(void) const { return GetSlot(fsInput); }
-
- /// Returns the item in the fuel slot
- const cItem & GetFuelSlot(void) const { return GetSlot(fsFuel); }
-
- /// Returns the item in the output slot
- const cItem & GetOutputSlot(void) const { return GetSlot(fsOutput); }
-
- /// Sets the item in the input slot
- void SetInputSlot(const cItem & a_Item) { SetSlot(fsInput, a_Item); }
-
- /// Sets the item in the fuel slot
- void SetFuelSlot(const cItem & a_Item) { SetSlot(fsFuel, a_Item); }
-
- /// Sets the item in the output slot
- void SetOutputSlot(const cItem & a_Item) { SetSlot(fsOutput, a_Item); }
-
- /// Returns the time that the current item has been cooking, in ticks
- int GetTimeCooked(void) const {return m_TimeCooked; }
-
- /// Returns the time until the current item finishes cooking, in ticks
- int GetCookTimeLeft(void) const { return m_NeedCookTime - m_TimeCooked; }
-
- /// Returns the time until the current fuel is depleted, in ticks
- int GetFuelBurnTimeLeft(void) const {return m_FuelBurnTime - m_TimeBurned; }
-
- /// Returns true if there's time left before the current fuel is depleted
- bool HasFuelTimeLeft(void) const { return (GetFuelBurnTimeLeft() > 0); }
-
- // tolua_end
-
- void SetBurnTimes(int a_FuelBurnTime, int a_TimeBurned) {m_FuelBurnTime = a_FuelBurnTime; m_TimeBurned = 0; }
- void SetCookTimes(int a_NeedCookTime, int a_TimeCooked) {m_NeedCookTime = a_NeedCookTime; m_TimeCooked = a_TimeCooked; }
-
-protected:
-
- /// Block type of the block currently represented by this entity (changes when furnace lights up)
- BLOCKTYPE m_BlockType;
-
- /// Block meta of the block currently represented by this entity
- NIBBLETYPE m_BlockMeta;
-
- /// The recipe for the current input slot
- const cFurnaceRecipe::Recipe * m_CurrentRecipe;
-
- /// The item that is being smelted
- cItem m_LastInput;
-
- bool m_IsCooking; ///< Set to true if the furnace is cooking an item
-
- // All timers are in ticks
- int m_NeedCookTime; ///< Amount of time needed to fully cook current item
- int m_TimeCooked; ///< Amount of time that the current item has been cooking
- int m_FuelBurnTime; ///< Amount of time that the current fuel can burn (in total); zero if no fuel burning
- int m_TimeBurned; ///< Amount of time that the current fuel has been burning
-
- int m_LastProgressFuel; ///< Last value sent as the progress for the fuel
- int m_LastProgressCook; ///< Last value sent as the progress for the cooking
-
-
- /// Sends the specified progressbar value to all clients of the window
- void BroadcastProgress(int a_ProgressbarID, short a_Value);
-
- /// One item finished cooking
- void FinishOne(cChunk & a_Chunk);
-
- /// Starts burning a new fuel, if possible
- void BurnNewFuel(void);
-
- /// Updates the recipe, based on the current input
- void UpdateInput(void);
-
- /// Called when the fuel slot changes or when the fuel is spent, burns another piece of fuel if appropriate
- void UpdateFuel(void);
-
- /// Called when the output slot changes
- void UpdateOutput(void);
-
- /// Updates the m_IsCooking, based on the input slot, output slot and m_FuelBurnTime / m_TimeBurned
- void UpdateIsCooking(void);
-
- /// Returns true if the input can be cooked into output and the item counts allow for another cooking operation
- bool CanCookInputToOutput(void) const;
-
- /// Broadcasts progressbar updates, if needed
- void UpdateProgressBars(void);
-
- /// Sets the m_IsCooking variable, updates the furnace block type based on the value
- void SetIsCooking(bool a_IsCooking);
-
- // cItemGrid::cListener overrides:
- virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override;
-
-} ; // tolua_export
-
-
-
-
diff --git a/source/BlockEntities/HopperEntity.cpp b/source/BlockEntities/HopperEntity.cpp
deleted file mode 100644
index 41849b1b3..000000000
--- a/source/BlockEntities/HopperEntity.cpp
+++ /dev/null
@@ -1,566 +0,0 @@
-
-// HopperEntity.cpp
-
-// Implements the cHopperEntity representing a hopper block entity
-
-#include "Globals.h"
-#include "HopperEntity.h"
-#include "../Chunk.h"
-#include "../Entities/Player.h"
-#include "../PluginManager.h"
-#include "ChestEntity.h"
-#include "DropSpenserEntity.h"
-#include "FurnaceEntity.h"
-
-
-
-
-
-cHopperEntity::cHopperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
- super(E_BLOCK_HOPPER, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World),
- m_LastMoveItemsInTick(0),
- m_LastMoveItemsOutTick(0)
-{
-}
-
-
-
-
-
-/** Returns the block coords of the block receiving the output items, based on the meta
-Returns false if unattached
-*/
-bool cHopperEntity::GetOutputBlockPos(NIBBLETYPE a_BlockMeta, int & a_OutputX, int & a_OutputY, int & a_OutputZ)
-{
- a_OutputX = m_PosX;
- a_OutputY = m_PosY;
- a_OutputZ = m_PosZ;
- switch (a_BlockMeta)
- {
- case E_META_HOPPER_FACING_XM: a_OutputX--; return true;
- case E_META_HOPPER_FACING_XP: a_OutputX++; return true;
- case E_META_HOPPER_FACING_YM: a_OutputY--; return true;
- case E_META_HOPPER_FACING_ZM: a_OutputZ--; return true;
- case E_META_HOPPER_FACING_ZP: a_OutputZ++; return true;
- default:
- {
- // Not attached
- return false;
- }
- }
-}
-
-
-
-
-
-bool cHopperEntity::Tick(float a_Dt, cChunk & a_Chunk)
-{
- Int64 CurrentTick = a_Chunk.GetWorld()->GetWorldAge();
-
- bool res = false;
- res = MoveItemsIn (a_Chunk, CurrentTick) || res;
- res = MovePickupsIn(a_Chunk, CurrentTick) || res;
- res = MoveItemsOut (a_Chunk, CurrentTick) || res;
- return res;
-}
-
-
-
-
-
-void cHopperEntity::SaveToJson(Json::Value & a_Value)
-{
- // TODO
- LOGWARNING("%s: Not implemented yet", __FUNCTION__);
-}
-
-
-
-
-
-void cHopperEntity::SendTo(cClientHandle & a_Client)
-{
- // The hopper entity doesn't need anything sent to the client when it's created / gets in the viewdistance
- // All the actual handling is in the cWindow UI code that gets called when the hopper is rclked
-
- UNUSED(a_Client);
-}
-
-
-
-
-
-void cHopperEntity::UsedBy(cPlayer * a_Player)
-{
- // If the window is not created, open it anew:
- cWindow * Window = GetWindow();
- if (Window == NULL)
- {
- OpenNewWindow();
- Window = GetWindow();
- }
-
- // Open the window for the player:
- if (Window != NULL)
- {
- if (a_Player->GetWindow() != Window)
- {
- a_Player->OpenWindow(Window);
- }
- }
-
- // This is rather a hack
- // Instead of marking the chunk as dirty upon chest contents change, we mark it dirty now
- // We cannot properly detect contents change, but such a change doesn't happen without a player opening the chest first.
- // The few false positives aren't much to worry about
- int ChunkX, ChunkZ;
- cChunkDef::BlockToChunk(m_PosX, m_PosZ, ChunkX, ChunkZ);
- m_World->MarkChunkDirty(ChunkX, ChunkZ);
-}
-
-
-
-
-
-/// Opens a new window UI for this hopper
-void cHopperEntity::OpenNewWindow(void)
-{
- OpenWindow(new cHopperWindow(m_PosX, m_PosY, m_PosZ, this));
-}
-
-
-
-
-
-/// Moves items from the container above it into this hopper. Returns true if the contents have changed.
-bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
-{
- if (m_PosY >= cChunkDef::Height)
- {
- // This hopper is at the top of the world, no more blocks above
- return false;
- }
-
- if (a_CurrentTick - m_LastMoveItemsInTick < TICKS_PER_TRANSFER)
- {
- // Too early after the previous transfer
- return false;
- }
-
- // Try moving an item in:
- bool res = false;
- switch (a_Chunk.GetBlock(m_RelX, m_PosY + 1, m_RelZ))
- {
- case E_BLOCK_CHEST:
- {
- // Chests have special handling because of double-chests
- res = MoveItemsFromChest(a_Chunk);
- break;
- }
- case E_BLOCK_LIT_FURNACE:
- case E_BLOCK_FURNACE:
- {
- // Furnaces have special handling because only the output and leftover fuel buckets shall be moved
- res = MoveItemsFromFurnace(a_Chunk);
- break;
- }
- case E_BLOCK_DISPENSER:
- case E_BLOCK_DROPPER:
- case E_BLOCK_HOPPER:
- {
- res = MoveItemsFromGrid(*(cBlockEntityWithItems *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ));
- break;
- }
- }
-
- // If the item has been moved, reset the last tick:
- if (res)
- {
- m_LastMoveItemsInTick = a_CurrentTick;
- }
-
- return res;
-}
-
-
-
-
-
-/// Moves pickups from above this hopper into it. Returns true if the contents have changed.
-bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
-{
- // TODO
- return false;
-}
-
-
-
-
-
-/// Moves items out from this hopper into the destination. Returns true if the contents have changed.
-bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
-{
- if (a_CurrentTick - m_LastMoveItemsOutTick < TICKS_PER_TRANSFER)
- {
- // Too early after the previous transfer
- return false;
- }
-
- int bx, by, bz;
- NIBBLETYPE Meta = a_Chunk.GetMeta(m_RelX, m_PosY, m_RelZ);
- if (!GetOutputBlockPos(Meta, bx, by, bz))
- {
- // Not attached to another container
- return false;
- }
- if (by < 0)
- {
- // Cannot output below the zero-th block level
- return false;
- }
-
- // Convert coords to relative:
- int rx = bx - a_Chunk.GetPosX() * cChunkDef::Width;
- int rz = bz - a_Chunk.GetPosZ() * cChunkDef::Width;
- cChunk * DestChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(rx, rz);
- if (DestChunk == NULL)
- {
- // The destination chunk has been unloaded, don't tick
- return false;
- }
-
- // Call proper moving function, based on the blocktype present at the coords:
- bool res = false;
- switch (DestChunk->GetBlock(rx, by, rz))
- {
- case E_BLOCK_CHEST:
- {
- // Chests have special handling because of double-chests
- res = MoveItemsToChest(*DestChunk, bx, by, bz);
- break;
- }
- case E_BLOCK_LIT_FURNACE:
- case E_BLOCK_FURNACE:
- {
- // Furnaces have special handling because of the direction-to-slot relation
- res = MoveItemsToFurnace(*DestChunk, bx, by, bz, Meta);
- break;
- }
- case E_BLOCK_DISPENSER:
- case E_BLOCK_DROPPER:
- case E_BLOCK_HOPPER:
- {
- res = MoveItemsToGrid(*(cBlockEntityWithItems *)DestChunk->GetBlockEntity(bx, by, bz));
- break;
- }
- }
-
- // If the item has been moved, reset the last tick:
- if (res)
- {
- m_LastMoveItemsOutTick = a_CurrentTick;
- }
-
- return res;
-}
-
-
-
-
-
-/// Moves items from a chest (dblchest) above the hopper into this hopper. Returns true if contents have changed.
-bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
-{
- if (MoveItemsFromGrid(*(cChestEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ)))
- {
- // Moved the item from the chest directly above the hopper
- return true;
- }
-
- // Check if the chest is a double-chest, if so, try to move from there:
- static const struct
- {
- int x, z;
- }
- Coords [] =
- {
- {1, 0},
- {-1, 0},
- {0, 1},
- {0, -1},
- } ;
- for (int i = 0; i < ARRAYCOUNT(Coords); i++)
- {
- int x = m_RelX + Coords[i].x;
- int z = m_RelZ + Coords[i].z;
- cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z);
- if (
- (Neighbor == NULL) ||
- (Neighbor->GetBlock(x, m_PosY + 1, z) != E_BLOCK_CHEST)
- )
- {
- continue;
- }
- if (MoveItemsFromGrid(*(cChestEntity *)Neighbor->GetBlockEntity(x, m_PosY, z)))
- {
- return true;
- }
- return false;
- }
-
- // The chest was single and nothing could be moved
- return false;
-}
-
-
-
-
-
-/// Moves items from a furnace above the hopper into this hopper. Returns true if contents have changed.
-bool cHopperEntity::MoveItemsFromFurnace(cChunk & a_Chunk)
-{
- cFurnaceEntity * Furnace = (cFurnaceEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ);
- ASSERT(Furnace != NULL);
-
- // Try move from the output slot:
- if (MoveItemsFromSlot(*Furnace, cFurnaceEntity::fsOutput, true))
- {
- cItem NewOutput(Furnace->GetOutputSlot());
- Furnace->SetOutputSlot(NewOutput.AddCount(-1));
- return true;
- }
-
- // No output moved, check if we can move an empty bucket out of the fuel slot:
- if (Furnace->GetFuelSlot().m_ItemType == E_ITEM_BUCKET)
- {
- if (MoveItemsFromSlot(*Furnace, cFurnaceEntity::fsFuel, true))
- {
- Furnace->SetFuelSlot(cItem());
- return true;
- }
- }
-
- // Nothing can be moved
- return false;
-}
-
-
-
-
-
-bool cHopperEntity::MoveItemsFromGrid(cBlockEntityWithItems & a_Entity)
-{
- cItemGrid & Grid = a_Entity.GetContents();
- int NumSlots = Grid.GetNumSlots();
-
- // First try adding items of types already in the hopper:
- for (int i = 0; i < NumSlots; i++)
- {
- if (Grid.IsSlotEmpty(i))
- {
- continue;
- }
- if (MoveItemsFromSlot(a_Entity, i, false))
- {
- Grid.ChangeSlotCount(i, -1);
- return true;
- }
- }
-
- // No already existing stack can be topped up, try again with allowing new stacks:
- for (int i = 0; i < NumSlots; i++)
- {
- if (Grid.IsSlotEmpty(i))
- {
- continue;
- }
- if (MoveItemsFromSlot(a_Entity, i, true))
- {
- Grid.ChangeSlotCount(i, -1);
- return true;
- }
- }
- return false;
-}
-
-
-
-
-
-/// Moves one piece of the specified a_Entity's slot itemstack into this hopper. Returns true if contents have changed. Doesn't change the itemstack.
-bool cHopperEntity::MoveItemsFromSlot(cBlockEntityWithItems & a_Entity, int a_SlotNum, bool a_AllowNewStacks)
-{
- cItem One(a_Entity.GetSlot(a_SlotNum).CopyOne());
- for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
- {
- if (m_Contents.IsSlotEmpty(i))
- {
- if (a_AllowNewStacks)
- {
- if (cPluginManager::Get()->CallHookHopperPullingItem(*m_World, *this, i, a_Entity, a_SlotNum))
- {
- // Plugin disagrees with the move
- continue;
- }
- }
- m_Contents.SetSlot(i, One);
- return true;
- }
- else if (m_Contents.GetSlot(i).IsStackableWith(One))
- {
- if (cPluginManager::Get()->CallHookHopperPullingItem(*m_World, *this, i, a_Entity, a_SlotNum))
- {
- // Plugin disagrees with the move
- continue;
- }
-
- m_Contents.ChangeSlotCount(i, 1);
- return true;
- }
- }
- return false;
-}
-
-
-
-
-
-/// Moves items to the chest at the specified coords. Returns true if contents have changed
-bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_BlockY, int a_BlockZ)
-{
- // Try the chest directly connected to the hopper:
- if (MoveItemsToGrid(*(cChestEntity *)a_Chunk.GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ)))
- {
- return true;
- }
-
- // Check if the chest is a double-chest, if so, try to move into the other half:
- static const struct
- {
- int x, z;
- }
- Coords [] =
- {
- {1, 0},
- {-1, 0},
- {0, 1},
- {0, -1},
- } ;
- for (int i = 0; i < ARRAYCOUNT(Coords); i++)
- {
- int x = m_RelX + Coords[i].x;
- int z = m_RelZ + Coords[i].z;
- cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z);
- if (
- (Neighbor == NULL) ||
- (Neighbor->GetBlock(x, m_PosY + 1, z) != E_BLOCK_CHEST)
- )
- {
- continue;
- }
- if (MoveItemsToGrid(*(cChestEntity *)Neighbor->GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ)))
- {
- return true;
- }
- return false;
- }
-
- // The chest was single and nothing could be moved
- return false;
-}
-
-
-
-
-
-/// Moves items to the furnace at the specified coords. Returns true if contents have changed
-bool cHopperEntity::MoveItemsToFurnace(cChunk & a_Chunk, int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_HopperMeta)
-{
- cFurnaceEntity * Furnace = (cFurnaceEntity *)a_Chunk.GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ);
- if (a_HopperMeta == E_META_HOPPER_FACING_YM)
- {
- // Feed the input slot of the furnace
- return MoveItemsToSlot(*Furnace, cFurnaceEntity::fsInput);
- }
- else
- {
- // Feed the fuel slot of the furnace
- return MoveItemsToSlot(*Furnace, cFurnaceEntity::fsFuel);
- }
- return false;
-}
-
-
-
-
-
-bool cHopperEntity::MoveItemsToGrid(cBlockEntityWithItems & a_Entity)
-{
- // Iterate through our slots, try to move from each one:
- int NumSlots = a_Entity.GetContents().GetNumSlots();
- for (int i = 0; i < NumSlots; i++)
- {
- if (MoveItemsToSlot(a_Entity, i))
- {
- return true;
- }
- }
- return false;
-}
-
-
-
-
-
-bool cHopperEntity::MoveItemsToSlot(cBlockEntityWithItems & a_Entity, int a_DstSlotNum)
-{
- cItemGrid & Grid = a_Entity.GetContents();
- if (Grid.IsSlotEmpty(a_DstSlotNum))
- {
- // The slot is empty, move the first non-empty slot from our contents:
- for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
- {
- if (!m_Contents.IsSlotEmpty(i))
- {
- if (cPluginManager::Get()->CallHookHopperPushingItem(*m_World, *this, i, a_Entity, a_DstSlotNum))
- {
- // A plugin disagrees with the move
- continue;
- }
- Grid.SetSlot(a_DstSlotNum, m_Contents.GetSlot(i).CopyOne());
- m_Contents.ChangeSlotCount(i, -1);
- return true;
- }
- }
- return false;
- }
- else
- {
- // The slot is taken, try to top it up:
- const cItem & DestSlot = Grid.GetSlot(a_DstSlotNum);
- if (DestSlot.IsFullStack())
- {
- return false;
- }
- for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
- {
- if (m_Contents.GetSlot(i).IsStackableWith(DestSlot))
- {
- if (cPluginManager::Get()->CallHookHopperPushingItem(*m_World, *this, i, a_Entity, a_DstSlotNum))
- {
- // A plugin disagrees with the move
- continue;
- }
- Grid.ChangeSlotCount(a_DstSlotNum, 1);
- m_Contents.ChangeSlotCount(i, -1);
- return true;
- }
- }
- return false;
- }
-}
-
-
-
-
diff --git a/source/BlockEntities/HopperEntity.h b/source/BlockEntities/HopperEntity.h
deleted file mode 100644
index 3eaa05b7c..000000000
--- a/source/BlockEntities/HopperEntity.h
+++ /dev/null
@@ -1,96 +0,0 @@
-
-// HopperEntity.h
-
-// Declares the cHopperEntity representing a hopper block entity
-
-
-
-
-
-#pragma once
-
-#include "BlockEntityWithItems.h"
-#include "../UI/WindowOwner.h"
-
-
-
-
-
-class cHopperEntity : // tolua_export
- public cBlockEntityWindowOwner,
- // tolua_begin
- public cBlockEntityWithItems
-{
- typedef cBlockEntityWithItems super;
-
-public:
- enum {
- ContentsHeight = 1,
- ContentsWidth = 5,
- TICKS_PER_TRANSFER = 8, ///< How many ticks at minimum between two item transfers to or from the hopper
- } ;
-
- // tolua_end
-
- /// Constructor used for normal operation
- cHopperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
-
- /** Returns the block coords of the block receiving the output items, based on the meta
- Returns false if unattached.
- Exported in ManualBindings.cpp
- */
- bool GetOutputBlockPos(NIBBLETYPE a_BlockMeta, int & a_OutputX, int & a_OutputY, int & a_OutputZ);
-
- static const char * GetClassStatic(void) { return "cHopperEntity"; }
-
-protected:
-
- Int64 m_LastMoveItemsInTick;
- Int64 m_LastMoveItemsOutTick;
-
- // cBlockEntity overrides:
- virtual bool Tick(float a_Dt, cChunk & a_Chunk) override;
- virtual void SaveToJson(Json::Value & a_Value) override;
- virtual void SendTo(cClientHandle & a_Client) override;
- virtual void UsedBy(cPlayer * a_Player) override;
-
- /// Opens a new chest window for this chest. Scans for neighbors to open a double chest window, if appropriate.
- void OpenNewWindow(void);
-
- /// Moves items from the container above it into this hopper. Returns true if the contents have changed.
- bool MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick);
-
- /// Moves pickups from above this hopper into it. Returns true if the contents have changed.
- bool MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick);
-
- /// Moves items out from this hopper into the destination. Returns true if the contents have changed.
- bool MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick);
-
- /// Moves items from a chest (dblchest) above the hopper into this hopper. Returns true if contents have changed.
- bool MoveItemsFromChest(cChunk & a_Chunk);
-
- /// Moves items from a furnace above the hopper into this hopper. Returns true if contents have changed.
- bool MoveItemsFromFurnace(cChunk & a_Chunk);
-
- /// Moves items from the specified a_Entity's Contents into this hopper. Returns true if contents have changed.
- bool MoveItemsFromGrid(cBlockEntityWithItems & a_Entity);
-
- /// Moves one piece from the specified itemstack into this hopper. Returns true if contents have changed. Doesn't change the itemstack.
- bool MoveItemsFromSlot(cBlockEntityWithItems & a_Entity, int a_SrcSlotNum, bool a_AllowNewStacks);
-
- /// Moves items to the chest at the specified coords. Returns true if contents have changed
- bool MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_BlockY, int a_BlockZ);
-
- /// Moves items to the furnace at the specified coords. Returns true if contents have changed
- bool MoveItemsToFurnace(cChunk & a_Chunk, int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_HopperMeta);
-
- /// Moves items to the specified ItemGrid. Returns true if contents have changed
- bool MoveItemsToGrid(cBlockEntityWithItems & a_Entity);
-
- /// Moves one piece to the specified entity's contents' slot. Returns true if contents have changed.
- bool MoveItemsToSlot(cBlockEntityWithItems & a_Entity, int a_DstSlotNum);
-} ; // tolua_export
-
-
-
-
diff --git a/source/BlockEntities/JukeboxEntity.cpp b/source/BlockEntities/JukeboxEntity.cpp
deleted file mode 100644
index aca376dd3..000000000
--- a/source/BlockEntities/JukeboxEntity.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "JukeboxEntity.h"
-#include "../World.h"
-#include <json/json.h>
-
-
-
-
-
-cJukeboxEntity::cJukeboxEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
- super(E_BLOCK_JUKEBOX, a_BlockX, a_BlockY, a_BlockZ, a_World),
- m_Record(0)
-{
-}
-
-
-
-
-
-cJukeboxEntity::~cJukeboxEntity()
-{
- EjectRecord();
-}
-
-
-
-
-
-void cJukeboxEntity::UsedBy(cPlayer * a_Player)
-{
- if (m_Record == 0)
- {
- const cItem & HeldItem = a_Player->GetEquippedItem();
- if (HeldItem.m_ItemType >= 2256 && HeldItem.m_ItemType <= 2267)
- {
- m_Record = HeldItem.m_ItemType;
- a_Player->GetInventory().RemoveOneEquippedItem();
- PlayRecord();
- }
- }
- else
- {
- EjectRecord();
- }
-}
-
-
-
-
-
-void cJukeboxEntity::PlayRecord(void)
-{
- m_World->BroadcastSoundParticleEffect(1005, m_PosX, m_PosY, m_PosZ, m_Record);
-}
-
-
-
-
-
-void cJukeboxEntity::EjectRecord(void)
-{
- if ((m_Record < E_ITEM_FIRST_DISC) || (m_Record > E_ITEM_LAST_DISC))
- {
- // There's no record here
- return;
- }
-
- cItems Drops;
- Drops.push_back(cItem(m_Record, 1, 0));
- m_World->SpawnItemPickups(Drops, m_PosX + 0.5, m_PosY + 1, m_PosZ + 0.5, 8);
- m_World->BroadcastSoundParticleEffect(1005, m_PosX, m_PosY, m_PosZ, 0);
- m_Record = 0;
-}
-
-
-
-
-
-int cJukeboxEntity::GetRecord(void)
-{
- return m_Record;
-}
-
-
-
-
-
-void cJukeboxEntity::SetRecord(int a_Record)
-{
- m_Record = a_Record;
-}
-
-
-
-
-
-bool cJukeboxEntity::LoadFromJson(const Json::Value & a_Value)
-{
- m_PosX = a_Value.get("x", 0).asInt();
- m_PosY = a_Value.get("y", 0).asInt();
- m_PosZ = a_Value.get("z", 0).asInt();
-
- m_Record = a_Value.get("Record", 0).asInt();
-
- return true;
-}
-
-
-
-
-
-void cJukeboxEntity::SaveToJson(Json::Value & a_Value)
-{
- a_Value["x"] = m_PosX;
- a_Value["y"] = m_PosY;
- a_Value["z"] = m_PosZ;
-
- a_Value["Record"] = m_Record;
-}
-
-
-
-
diff --git a/source/BlockEntities/JukeboxEntity.h b/source/BlockEntities/JukeboxEntity.h
deleted file mode 100644
index fcafdc479..000000000
--- a/source/BlockEntities/JukeboxEntity.h
+++ /dev/null
@@ -1,56 +0,0 @@
-
-#pragma once
-
-#include "BlockEntity.h"
-#include "../Entities/Player.h"
-
-
-
-
-
-namespace Json
-{
- class Value;
-}
-
-
-
-
-
-// tolua_begin
-
-class cJukeboxEntity :
- public cBlockEntity
-{
- typedef cBlockEntity super;
-public:
-
- // tolua_end
-
- cJukeboxEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
- virtual ~cJukeboxEntity();
-
- bool LoadFromJson(const Json::Value & a_Value);
- virtual void SaveToJson(Json::Value & a_Value) override;
-
- // tolua_begin
-
- int GetRecord(void);
- void SetRecord(int a_Record);
- void PlayRecord(void);
-
- /// Ejects the currently held record as a pickup. Does nothing when no record inserted.
- void EjectRecord(void);
-
- // tolua_end
-
- virtual void UsedBy(cPlayer * a_Player) override;
- virtual void SendTo(cClientHandle & a_Client) override { };
-
-private:
- int m_Record;
-} ; // tolua_end
-
-
-
-
diff --git a/source/BlockEntities/NoteEntity.cpp b/source/BlockEntities/NoteEntity.cpp
deleted file mode 100644
index 1b0620299..000000000
--- a/source/BlockEntities/NoteEntity.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "NoteEntity.h"
-#include "../World.h"
-#include <json/json.h>
-
-
-
-
-
-cNoteEntity::cNoteEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
- super(E_BLOCK_NOTE_BLOCK, a_BlockX, a_BlockY, a_BlockZ, a_World),
- m_Pitch(0)
-{
-}
-
-
-
-
-
-void cNoteEntity::UsedBy(cPlayer * a_Player)
-{
- IncrementPitch();
- MakeSound();
-}
-
-
-
-
-
-void cNoteEntity::MakeSound(void)
-{
- char instrument;
- AString sampleName;
-
- switch (m_World->GetBlock(m_PosX, m_PosY - 1, m_PosZ))
- {
- case E_BLOCK_PLANKS:
- case E_BLOCK_LOG:
- case E_BLOCK_NOTE_BLOCK:
- {
- // TODO: add other wood-based blocks if needed
- instrument = E_INST_DOUBLE_BASS;
- sampleName = "note.db";
- break;
- }
-
- case E_BLOCK_SAND:
- case E_BLOCK_GRAVEL:
- case E_BLOCK_SOULSAND:
- {
- instrument = E_INST_SNARE_DRUM;
- sampleName = "note.snare";
- break;
- }
-
- case E_BLOCK_GLASS:
- case E_BLOCK_GLASS_PANE:
- case E_BLOCK_GLOWSTONE:
- {
- instrument = E_INST_CLICKS;
- sampleName = "note.hat";
- break;
- }
-
- case E_BLOCK_STONE:
- case E_BLOCK_STONE_BRICKS:
- case E_BLOCK_COBBLESTONE:
- case E_BLOCK_OBSIDIAN:
- case E_BLOCK_NETHERRACK:
- case E_BLOCK_BRICK:
- case E_BLOCK_NETHER_BRICK:
- {
- // TODO: add other stone-based blocks if needed
- instrument = E_INST_BASS_DRUM;
- sampleName = "note.bassattack";
- break;
- }
-
- default:
- {
- instrument = E_INST_HARP_PIANO;
- sampleName = "note.harp";
- break;
- }
- }
-
- m_World->BroadcastBlockAction(m_PosX, m_PosY, m_PosZ, instrument, m_Pitch, E_BLOCK_NOTE_BLOCK);
-
- // TODO: instead of calculating the power function over and over, make a precalculated table - there's only 24 pitches after all
- float calcPitch = pow(2.0f, ((float)m_Pitch - 12.0f) / 12.0f);
- m_World->BroadcastSoundEffect(sampleName, m_PosX * 8, m_PosY * 8, m_PosZ * 8, 3.0f, calcPitch);
-}
-
-
-
-
-
-char cNoteEntity::GetPitch(void)
-{
- return m_Pitch;
-}
-
-
-
-
-
-void cNoteEntity::SetPitch(char a_Pitch)
-{
- m_Pitch = a_Pitch % 25;
-}
-
-
-
-
-
-void cNoteEntity::IncrementPitch(void)
-{
- SetPitch(m_Pitch + 1);
-}
-
-
-
-
-
-bool cNoteEntity::LoadFromJson(const Json::Value & a_Value)
-{
-
- m_PosX = a_Value.get("x", 0).asInt();
- m_PosY = a_Value.get("y", 0).asInt();
- m_PosZ = a_Value.get("z", 0).asInt();
-
- m_Pitch = (char)a_Value.get("p", 0).asInt();
-
- return true;
-}
-
-
-
-
-
-void cNoteEntity::SaveToJson(Json::Value & a_Value)
-{
- a_Value["x"] = m_PosX;
- a_Value["y"] = m_PosY;
- a_Value["z"] = m_PosZ;
-
- a_Value["p"] = m_Pitch;
-}
-
-
-
-
diff --git a/source/BlockEntities/NoteEntity.h b/source/BlockEntities/NoteEntity.h
deleted file mode 100644
index e2d088f44..000000000
--- a/source/BlockEntities/NoteEntity.h
+++ /dev/null
@@ -1,63 +0,0 @@
-
-#pragma once
-
-#include "BlockEntity.h"
-
-
-namespace Json
-{
- class Value;
-}
-
-
-
-
-
-enum ENUM_NOTE_INSTRUMENTS
-{
- E_INST_HARP_PIANO = 0,
- E_INST_DOUBLE_BASS = 1,
- E_INST_SNARE_DRUM = 2,
- E_INST_CLICKS = 3,
- E_INST_BASS_DRUM = 4
-};
-
-
-
-
-
-// tolua_begin
-
-class cNoteEntity :
- public cBlockEntity
-{
- typedef cBlockEntity super;
-public:
-
- // tolua_end
-
- /// Creates a new note entity. a_World may be NULL
- cNoteEntity(int a_X, int a_Y, int a_Z, cWorld * a_World);
-
- bool LoadFromJson(const Json::Value & a_Value);
- virtual void SaveToJson(Json::Value & a_Value) override;
-
- // tolua_begin
-
- char GetPitch(void);
- void SetPitch(char a_Pitch);
- void IncrementPitch(void);
- void MakeSound(void);
-
- // tolua_end
-
- virtual void UsedBy(cPlayer * a_Player) override;
- virtual void SendTo(cClientHandle & a_Client) override { };
-
-private:
- char m_Pitch;
-} ; // tolua_export
-
-
-
-
diff --git a/source/BlockEntities/SignEntity.cpp b/source/BlockEntities/SignEntity.cpp
deleted file mode 100644
index 81f6f6d77..000000000
--- a/source/BlockEntities/SignEntity.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-
-// SignEntity.cpp
-
-// Implements the cSignEntity class representing a single sign in the world
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-#include <json/json.h>
-#include "SignEntity.h"
-#include "../Entities/Player.h"
-
-
-
-
-
-cSignEntity::cSignEntity(BLOCKTYPE a_BlockType, int a_X, int a_Y, int a_Z, cWorld * a_World) :
- super(a_BlockType, a_X, a_Y, a_Z, a_World)
-{
-}
-
-
-
-
-
-// It don't do anything when 'used'
-void cSignEntity::UsedBy(cPlayer * a_Player)
-{
- UNUSED(a_Player);
-}
-
-
-
-
-
-void cSignEntity::SetLines(const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4)
-{
- m_Line[0] = a_Line1;
- m_Line[1] = a_Line2;
- m_Line[2] = a_Line3;
- m_Line[3] = a_Line4;
-}
-
-
-
-
-
-void cSignEntity::SetLine(int a_Index, const AString & a_Line)
-{
- if ((a_Index < 0) || (a_Index >= ARRAYCOUNT(m_Line)))
- {
- LOGWARNING("%s: setting a non-existent line %d (value \"%s\"", __FUNCTION__, a_Index, a_Line.c_str());
- return;
- }
- m_Line[a_Index] = a_Line;
-}
-
-
-
-
-
-AString cSignEntity::GetLine(int a_Index) const
-{
- if ((a_Index < 0) || (a_Index >= ARRAYCOUNT(m_Line)))
- {
- LOGWARNING("%s: requesting a non-existent line %d", __FUNCTION__, a_Index);
- return "";
- }
- return m_Line[a_Index];
-}
-
-
-
-
-
-void cSignEntity::SendTo(cClientHandle & a_Client)
-{
- a_Client.SendUpdateSign(m_PosX, m_PosY, m_PosZ, m_Line[0], m_Line[1], m_Line[2], m_Line[3]);
-}
-
-
-
-
-
-bool cSignEntity::LoadFromJson(const Json::Value & a_Value)
-{
- m_PosX = a_Value.get("x", 0).asInt();
- m_PosY = a_Value.get("y", 0).asInt();
- m_PosZ = a_Value.get("z", 0).asInt();
-
- m_Line[0] = a_Value.get("Line1", "").asString();
- m_Line[1] = a_Value.get("Line2", "").asString();
- m_Line[2] = a_Value.get("Line3", "").asString();
- m_Line[3] = a_Value.get("Line4", "").asString();
-
- return true;
-}
-
-
-
-
-
-void cSignEntity::SaveToJson(Json::Value & a_Value)
-{
- a_Value["x"] = m_PosX;
- a_Value["y"] = m_PosY;
- a_Value["z"] = m_PosZ;
-
- a_Value["Line1"] = m_Line[0];
- a_Value["Line2"] = m_Line[1];
- a_Value["Line3"] = m_Line[2];
- a_Value["Line4"] = m_Line[3];
-}
-
-
-
-
diff --git a/source/BlockEntities/SignEntity.h b/source/BlockEntities/SignEntity.h
deleted file mode 100644
index d998ff1e8..000000000
--- a/source/BlockEntities/SignEntity.h
+++ /dev/null
@@ -1,67 +0,0 @@
-
-// SignEntity.h
-
-// Declares the cSignEntity class representing a single sign in the world
-
-
-
-
-
-#pragma once
-
-#include "BlockEntity.h"
-
-
-
-
-
-namespace Json
-{
- class Value;
-}
-
-
-
-
-
-// tolua_begin
-
-class cSignEntity :
- public cBlockEntity
-{
- typedef cBlockEntity super;
-
-public:
-
- // tolua_end
-
- /// Creates a new empty sign entity at the specified block coords and block type (wall or standing). a_World may be NULL
- cSignEntity(BLOCKTYPE a_BlockType, int a_X, int a_Y, int a_Z, cWorld * a_World);
-
- bool LoadFromJson( const Json::Value& a_Value );
- virtual void SaveToJson(Json::Value& a_Value ) override;
-
- // tolua_begin
-
- /// Sets all the sign's lines
- void SetLines(const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4);
-
- /// Sets individual line (zero-based index)
- void SetLine(int a_Index, const AString & a_Line);
-
- /// Retrieves individual line (zero-based index)
- AString GetLine(int a_Index) const;
-
- // tolua_end
-
- virtual void UsedBy(cPlayer * a_Player) override;
- virtual void SendTo(cClientHandle & a_Client) override;
-
-private:
-
- AString m_Line[4];
-} ; // tolua_export
-
-
-
-