diff options
Diffstat (limited to 'src/BlockEntities/DropSpenserEntity.cpp')
-rw-r--r-- | src/BlockEntities/DropSpenserEntity.cpp | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/src/BlockEntities/DropSpenserEntity.cpp b/src/BlockEntities/DropSpenserEntity.cpp new file mode 100644 index 000000000..7c9a40ce6 --- /dev/null +++ b/src/BlockEntities/DropSpenserEntity.cpp @@ -0,0 +1,267 @@ + +// 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" +#include "json/json.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); +} + + + + |