diff options
-rw-r--r-- | src/Entities/Entity.h | 2 | ||||
-rw-r--r-- | src/Entities/ItemFrame.cpp | 124 | ||||
-rw-r--r-- | src/Entities/ItemFrame.h | 42 | ||||
-rw-r--r-- | src/Items/ItemHandler.cpp | 3 | ||||
-rw-r--r-- | src/Items/ItemItemFrame.h | 53 | ||||
-rw-r--r-- | src/Protocol/Protocol17x.cpp | 14 | ||||
-rw-r--r-- | src/WorldStorage/NBTChunkSerializer.cpp | 1 |
7 files changed, 237 insertions, 2 deletions
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 29ffd949d..b3b1cef83 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -81,6 +81,7 @@ public: etProjectile, etExpOrb, etFloater, + etItemFrame, etPainting, // Common variations @@ -140,6 +141,7 @@ public: bool IsProjectile (void) const { return (m_EntityType == etProjectile); } bool IsExpOrb (void) const { return (m_EntityType == etExpOrb); } bool IsFloater (void) const { return (m_EntityType == etFloater); } + bool IsItemFrame (void) const { return (m_EntityType == etItemFrame); } bool IsPainting (void) const { return (m_EntityType == etPainting); } /// Returns true if the entity is of the specified class or a subclass (cPawn's IsA("cEntity") returns true) diff --git a/src/Entities/ItemFrame.cpp b/src/Entities/ItemFrame.cpp new file mode 100644 index 000000000..8cfa5e18d --- /dev/null +++ b/src/Entities/ItemFrame.cpp @@ -0,0 +1,124 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "ItemFrame.h" +#include "ClientHandle.h" +#include "Player.h" + + + + + +cItemFrame::cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z) + : cEntity(etItemFrame, a_X, a_Y, a_Z, 0.8, 0.8), + m_BlockFace(a_BlockFace), + m_Item(E_BLOCK_AIR), + m_Rotation(0) +{ + SetMaxHealth(1); + SetHealth(1); +} + + + + + +void cItemFrame::SpawnOn(cClientHandle & a_ClientHandle) +{ + int Dir = 0; + + // The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces + switch (m_BlockFace) + { + case BLOCK_FACE_ZP: break; // Initialised to zero + case BLOCK_FACE_ZM: Dir = 2; break; + case BLOCK_FACE_XM: Dir = 1; break; + case BLOCK_FACE_XP: Dir = 3; break; + default: ASSERT(!"Unhandled block face when trying to spawn item frame!"); return; + } + + if ((Dir == 0) || (Dir == 2)) // Probably a client bug, but two directions are flipped and contrary to the norm, so we do -180 + { + SetYaw((Dir * 90) - 180); + } + else + { + SetYaw(Dir * 90); + } + + a_ClientHandle.SendSpawnObject(*this, 71, Dir, (Byte)GetYaw(), (Byte)GetPitch()); +} + + + + + +void cItemFrame::OnRightClicked(cPlayer & a_Player) +{ + if (!m_Item.IsEmpty()) + { + // Item not empty, rotate, clipping values to zero to three inclusive + m_Rotation++; + if (m_Rotation >= 4) + { + m_Rotation = 0; + } + } + else if (!a_Player.GetEquippedItem().IsEmpty()) + { + // Item empty, and player held item not empty - add this item to self + m_Item = a_Player.GetEquippedItem(); + m_Item.m_ItemCount = 1; + + if (!a_Player.IsGameModeCreative()) + { + a_Player.GetInventory().RemoveOneEquippedItem(); + } + } + + GetWorld()->BroadcastEntityMetadata(*this); // Update clients +} + + + + + + +void cItemFrame::KilledBy(cEntity * a_Killer) +{ + if (m_Item.IsEmpty()) + { + super::KilledBy(a_Killer); + Destroy(); + return; + } + + if ((a_Killer != NULL) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative()) + { + cItems Item; + Item.push_back(m_Item); + + GetWorld()->SpawnItemPickups(Item, GetPosX(), GetPosY(), GetPosZ()); + } + + SetHealth(GetMaxHealth()); + m_Item.Clear(); + m_Rotation = 0; + GetWorld()->BroadcastEntityMetadata(*this); +} + + + + + +void cItemFrame::GetDrops(cItems & a_Items, cEntity * a_Killer) +{ + if ((a_Killer != NULL) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative()) + { + a_Items.push_back(cItem(E_ITEM_ITEM_FRAME)); + } +} + + + + diff --git a/src/Entities/ItemFrame.h b/src/Entities/ItemFrame.h new file mode 100644 index 000000000..43915e3f9 --- /dev/null +++ b/src/Entities/ItemFrame.h @@ -0,0 +1,42 @@ + +#pragma once + +#include "Entity.h" + + + + + +// tolua_begin +class cItemFrame : + public cEntity +{ + // tolua_end + typedef cEntity super; + +public: + + CLASS_PROTODEF(cItemFrame); + + cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z); + + const cItem & GetItem(void) { return m_Item; } + Byte GetRotation(void) const { return m_Rotation; } + +private: + + virtual void SpawnOn(cClientHandle & a_ClientHandle) override; + virtual void OnRightClicked(cPlayer & a_Player) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override {}; + virtual void KilledBy(cEntity * a_Killer) override; + virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override; + + eBlockFace m_BlockFace; + cItem m_Item; + Byte m_Rotation; + +}; // tolua_export + + + + diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index 5ff74fc2c..945f84b9c 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -21,6 +21,7 @@ #include "ItemFishingRod.h" #include "ItemFlowerPot.h" #include "ItemFood.h" +#include "ItemItemFrame.h" #include "ItemHoe.h" #include "ItemLeaves.h" #include "ItemLighter.h" @@ -106,6 +107,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType); case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType); case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType); + case E_ITEM_ITEM_FRAME: return new cItemItemFrameHandler(a_ItemType); case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType); case E_ITEM_PAINTING: return new cItemPaintingHandler(a_ItemType); case E_ITEM_REDSTONE_DUST: return new cItemRedstoneDustHandler(a_ItemType); @@ -344,6 +346,7 @@ char cItemHandler::GetMaxStackSize(void) case E_ITEM_GUNPOWDER: return 64; case E_ITEM_HEAD: return 64; case E_ITEM_IRON: return 64; + case E_ITEM_ITEM_FRAME: return 64; case E_ITEM_LEATHER: return 64; case E_ITEM_MAGMA_CREAM: return 64; case E_ITEM_MAP: return 64; diff --git a/src/Items/ItemItemFrame.h b/src/Items/ItemItemFrame.h new file mode 100644 index 000000000..74e987445 --- /dev/null +++ b/src/Items/ItemItemFrame.h @@ -0,0 +1,53 @@ + +#pragma once + +#include "ItemHandler.h" +#include "Entities/ItemFrame.h" +#include "../Entities/Player.h" + + + + + +class cItemItemFrameHandler : + public cItemHandler +{ +public: + cItemItemFrameHandler(int a_ItemType) + : cItemHandler(a_ItemType) + { + + } + + virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override + { + if ((a_Dir == BLOCK_FACE_NONE) || (a_Dir == BLOCK_FACE_YP) || (a_Dir == BLOCK_FACE_YM)) + { + // Client sends this if clicked on top or bottom face + return false; + } + + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir); // Make sure block that will be occupied is free + BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir, true); // We want the clicked block, so go back again + + if (Block == E_BLOCK_AIR) + { + cItemFrame * ItemFrame = new cItemFrame(a_Dir, a_BlockX, a_BlockY, a_BlockZ); + ItemFrame->Initialize(a_World); + + if (!a_Player->IsGameModeCreative()) + { + a_Player->GetInventory().RemoveOneEquippedItem(); + } + + return true; + + } + return false; + } +}; + + + + diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 7da19a14b..0c569c07c 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -24,6 +24,7 @@ Implements the 1.7.x protocol classes: #include "../Entities/Painting.h" #include "../Entities/Pickup.h" #include "../Entities/Player.h" +#include "../Entities/ItemFrame.h" #include "../Mobs/IncludeAllMonsters.h" #include "../UI/Window.h" #include "../BlockEntities/CommandBlockEntity.h" @@ -938,8 +939,8 @@ void cProtocol172::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, Pkt.WriteFPInt(a_Entity.GetPosX()); Pkt.WriteFPInt(a_Entity.GetPosY()); Pkt.WriteFPInt(a_Entity.GetPosZ()); - Pkt.WriteByteAngle(a_Entity.GetYaw()); Pkt.WriteByteAngle(a_Entity.GetPitch()); + Pkt.WriteByteAngle(a_Entity.GetYaw()); Pkt.WriteInt(a_ObjectData); if (a_ObjectData != 0) { @@ -961,8 +962,8 @@ void cProtocol172::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp Pkt.WriteFPInt(a_Vehicle.GetPosX()); Pkt.WriteFPInt(a_Vehicle.GetPosY()); Pkt.WriteFPInt(a_Vehicle.GetPosZ()); - Pkt.WriteByteAngle(a_Vehicle.GetYaw()); Pkt.WriteByteAngle(a_Vehicle.GetPitch()); + Pkt.WriteByteAngle(a_Vehicle.GetYaw()); Pkt.WriteInt(a_VehicleSubType); if (a_VehicleSubType != 0) { @@ -2406,6 +2407,15 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) WriteMobMetadata((const cMonster &)a_Entity); break; } + case cEntity::etItemFrame: + { + cItemFrame & Frame = (cItemFrame &)a_Entity; + WriteByte(0xA2); + WriteItem(Frame.GetItem()); + WriteByte(0x3); + WriteByte(Frame.GetRotation()); + break; + } } } diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 8419bd646..c7aaa2633 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -627,6 +627,7 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity) case cEntity::etProjectile: AddProjectileEntity ((cProjectileEntity *)a_Entity); break; case cEntity::etTNT: /* TODO */ break; case cEntity::etExpOrb: /* TODO */ break; + case cEntity::etItemFrame: /* TODO */ break; case cEntity::etPainting: /* TODO */ break; case cEntity::etPlayer: return; // Players aren't saved into the world default: |