summaryrefslogtreecommitdiffstats
path: root/src/Items
diff options
context:
space:
mode:
authorAlexander Harkness <bearbin@gmail.com>2013-11-24 15:19:41 +0100
committerAlexander Harkness <bearbin@gmail.com>2013-11-24 15:19:41 +0100
commit675b4aa878f16291ce33fced48a2bc7425f635ae (patch)
tree409914df27a98f65adf866da669429c4de141b6f /src/Items
parentLineBlockTracer: Using the coord-based block faces. (diff)
downloadcuberite-675b4aa878f16291ce33fced48a2bc7425f635ae.tar
cuberite-675b4aa878f16291ce33fced48a2bc7425f635ae.tar.gz
cuberite-675b4aa878f16291ce33fced48a2bc7425f635ae.tar.bz2
cuberite-675b4aa878f16291ce33fced48a2bc7425f635ae.tar.lz
cuberite-675b4aa878f16291ce33fced48a2bc7425f635ae.tar.xz
cuberite-675b4aa878f16291ce33fced48a2bc7425f635ae.tar.zst
cuberite-675b4aa878f16291ce33fced48a2bc7425f635ae.zip
Diffstat (limited to 'src/Items')
-rw-r--r--src/Items/ItemBed.h56
-rw-r--r--src/Items/ItemBoat.h54
-rw-r--r--src/Items/ItemBow.h87
-rw-r--r--src/Items/ItemBrewingStand.h41
-rw-r--r--src/Items/ItemBucket.h160
-rw-r--r--src/Items/ItemCauldron.h41
-rw-r--r--src/Items/ItemCloth.h23
-rw-r--r--src/Items/ItemComparator.h40
-rw-r--r--src/Items/ItemDoor.h45
-rw-r--r--src/Items/ItemDye.h44
-rw-r--r--src/Items/ItemFlowerPot.h41
-rw-r--r--src/Items/ItemFood.h63
-rw-r--r--src/Items/ItemHandler.cpp509
-rw-r--r--src/Items/ItemHandler.h99
-rw-r--r--src/Items/ItemHoe.h40
-rw-r--r--src/Items/ItemLeaves.h41
-rw-r--r--src/Items/ItemLighter.h59
-rw-r--r--src/Items/ItemMinecart.h82
-rw-r--r--src/Items/ItemPickaxe.h92
-rw-r--r--src/Items/ItemRedstoneDust.h38
-rw-r--r--src/Items/ItemRedstoneRepeater.h40
-rw-r--r--src/Items/ItemSapling.h42
-rw-r--r--src/Items/ItemSeeds.h65
-rw-r--r--src/Items/ItemShears.h62
-rw-r--r--src/Items/ItemShovel.h41
-rw-r--r--src/Items/ItemSign.h51
-rw-r--r--src/Items/ItemSpawnEgg.h52
-rw-r--r--src/Items/ItemSugarcane.h39
-rw-r--r--src/Items/ItemSword.h30
-rw-r--r--src/Items/ItemThrowable.h96
30 files changed, 2173 insertions, 0 deletions
diff --git a/src/Items/ItemBed.h b/src/Items/ItemBed.h
new file mode 100644
index 000000000..ab4182eea
--- /dev/null
+++ b/src/Items/ItemBed.h
@@ -0,0 +1,56 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+#include "../Blocks/BlockBed.h"
+
+
+
+
+
+class cItemBedHandler :
+ public cItemHandler
+{
+public:
+ cItemBedHandler(int a_ItemType) :
+ cItemHandler(a_ItemType)
+ {
+ }
+
+
+ virtual bool IsPlaceable(void) override
+ {
+ return true;
+ }
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ if (a_BlockFace != BLOCK_FACE_TOP)
+ {
+ // Can only be placed on the floor
+ return false;
+ }
+
+ a_BlockMeta = cBlockBedHandler::RotationToMetaData(a_Player->GetRotation());
+
+ // Check if there is empty space for the foot section:
+ Vector3i Direction = cBlockBedHandler::MetaDataToDirection(a_BlockMeta);
+ if (a_World->GetBlock(a_BlockX + Direction.x, a_BlockY, a_BlockZ + Direction.z) != E_BLOCK_AIR)
+ {
+ return false;
+ }
+
+ a_BlockType = E_BLOCK_BED;
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemBoat.h b/src/Items/ItemBoat.h
new file mode 100644
index 000000000..6e3395f1d
--- /dev/null
+++ b/src/Items/ItemBoat.h
@@ -0,0 +1,54 @@
+
+// ItemBoat.h
+
+// Declares the various boat ItemHandlers
+
+
+
+
+
+#pragma once
+
+#include "../Entities/Boat.h"
+
+
+
+
+
+class cItemBoatHandler :
+ public cItemHandler
+{
+ typedef cItemHandler super;
+
+public:
+ cItemBoatHandler(int a_ItemType) :
+ super(a_ItemType)
+ {
+ }
+
+
+
+ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override
+ {
+ if (a_Dir < 0)
+ {
+ return false;
+ }
+
+ double x = (double)a_BlockX + 0.5;
+ double y = (double)a_BlockY + 0.5;
+ double z = (double)a_BlockZ + 0.5;
+
+ cBoat * Boat = NULL;
+
+ Boat = new cBoat (x, y, z);
+ Boat->Initialize(a_World);
+
+ return true;
+ }
+
+} ;
+
+
+
+
diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h
new file mode 100644
index 000000000..d533c21fd
--- /dev/null
+++ b/src/Items/ItemBow.h
@@ -0,0 +1,87 @@
+
+// ItemBow.h
+
+// Declares the cItemBowHandler class representing the itemhandler for bows
+
+
+
+
+
+#pragma once
+
+#include "../Entities/ProjectileEntity.h"
+
+
+
+
+
+class cItemBowHandler :
+ public cItemHandler
+{
+ typedef cItemHandler super;
+
+public:
+ cItemBowHandler(void) :
+ super(E_ITEM_BOW)
+ {
+ }
+
+
+ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override
+ {
+ ASSERT(a_Player != NULL);
+
+ // Check if the player has an arrow in the inventory, or is in Creative:
+ if (!(a_Player->IsGameModeCreative() || a_Player->GetInventory().HasItems(cItem(E_ITEM_ARROW))))
+ {
+ return false;
+ }
+
+ a_Player->StartChargingBow();
+ return true;
+ }
+
+
+ virtual void OnItemShoot(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override
+ {
+ // Actual shot - produce the arrow with speed based on the ticks that the bow was charged
+ ASSERT(a_Player != NULL);
+
+ int BowCharge = a_Player->FinishChargingBow();
+ double Force = (double)BowCharge / 20;
+ Force = (Force * Force + 2 * Force) / 3; // This formula is used by the 1.6.2 client
+ if (Force < 0.1)
+ {
+ // Too little force, ignore the shot
+ return;
+ }
+ if (Force > 1)
+ {
+ Force = 1;
+ }
+
+ // Create the arrow entity:
+ cArrowEntity * Arrow = new cArrowEntity(*a_Player, Force * 2);
+ if (Arrow == NULL)
+ {
+ return;
+ }
+ if (!Arrow->Initialize(a_Player->GetWorld()))
+ {
+ delete Arrow;
+ return;
+ }
+ a_Player->GetWorld()->BroadcastSpawnEntity(*Arrow);
+ a_Player->GetWorld()->BroadcastSoundEffect("random.bow", (int)a_Player->GetPosX() * 8, (int)a_Player->GetPosY() * 8, (int)a_Player->GetPosZ() * 8, 0.5, (float)Force);
+
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->UseEquippedItem();
+ }
+ }
+} ;
+
+
+
+
+
diff --git a/src/Items/ItemBrewingStand.h b/src/Items/ItemBrewingStand.h
new file mode 100644
index 000000000..4ff14d4b4
--- /dev/null
+++ b/src/Items/ItemBrewingStand.h
@@ -0,0 +1,41 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+
+
+
+
+
+class cItemBrewingStandHandler :
+ public cItemHandler
+{
+public:
+ cItemBrewingStandHandler(int a_ItemType) :
+ cItemHandler(a_ItemType)
+ {
+ }
+
+
+ virtual bool IsPlaceable(void) override
+ {
+ return true;
+ }
+
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ a_BlockType = E_BLOCK_BREWING_STAND;
+ a_BlockMeta = 0;
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemBucket.h b/src/Items/ItemBucket.h
new file mode 100644
index 000000000..fa3d48da1
--- /dev/null
+++ b/src/Items/ItemBucket.h
@@ -0,0 +1,160 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+#include "../Simulator/FluidSimulator.h"
+#include "../Blocks/BlockHandler.h"
+
+
+
+
+
+class cItemBucketHandler :
+ public cItemHandler
+{
+public:
+ cItemBucketHandler(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, char a_Dir) override
+ {
+ switch (m_ItemType)
+ {
+ case E_ITEM_BUCKET: return ScoopUpFluid(a_World, a_Player, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_Dir);
+ case E_ITEM_LAVA_BUCKET: return PlaceFluid (a_World, a_Player, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_Dir, E_BLOCK_LAVA);
+ case E_ITEM_WATER_BUCKET: return PlaceFluid (a_World, a_Player, a_Item, a_BlockX, a_BlockY, a_BlockZ, a_Dir, E_BLOCK_WATER);
+ default:
+ {
+ ASSERT(!"Unhandled ItemType");
+ return false;
+ }
+ }
+ }
+
+
+
+ bool ScoopUpFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace)
+ {
+ if (a_BlockFace < 0)
+ {
+ return false;
+ }
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+ BLOCKTYPE ClickedBlock;
+ NIBBLETYPE ClickedMeta;
+ a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedMeta);
+ LOGD("Bucket Clicked BlockType %d, meta %d", ClickedBlock, ClickedMeta);
+ if (ClickedMeta != 0)
+ {
+ // Not a source block
+ return false;
+ }
+
+ if (a_Player->GetGameMode() == gmCreative)
+ {
+ // In creative mode don't modify the inventory, just remove the fluid:
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ return true;
+ }
+
+ ENUM_ITEM_ID NewItem = E_ITEM_EMPTY;
+ switch (ClickedBlock)
+ {
+ case E_BLOCK_WATER:
+ case E_BLOCK_STATIONARY_WATER:
+ {
+ NewItem = E_ITEM_WATER_BUCKET;
+ break;
+ }
+ case E_BLOCK_LAVA:
+ case E_BLOCK_STATIONARY_LAVA:
+ {
+ NewItem = E_ITEM_LAVA_BUCKET;
+ break;
+ }
+
+ default: return false;
+ }
+
+ // Remove the bucket from the inventory
+ if (!a_Player->GetInventory().RemoveOneEquippedItem())
+ {
+ LOG("Clicked with an empty bucket, but cannot remove one from the inventory? WTF?");
+ ASSERT(!"Inventory bucket mismatch");
+ return true;
+ }
+
+ // Give new bucket, filled with fluid:
+ cItem Item(NewItem, 1);
+ a_Player->GetInventory().AddItem(Item, true, true);
+
+ // Remove water / lava block
+ a_Player->GetWorld()->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ return true;
+ }
+
+
+ bool PlaceFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_FluidBlock)
+ {
+ if (a_BlockFace < 0)
+ {
+ return false;
+ }
+
+ BLOCKTYPE CurrentBlock = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ bool CanWashAway = cFluidSimulator::CanWashAway(CurrentBlock);
+ if (!CanWashAway)
+ {
+ // The block pointed at cannot be washed away, so put fluid on top of it / on its sides
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+ CurrentBlock = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ }
+ if (
+ !CanWashAway &&
+ (CurrentBlock != E_BLOCK_AIR) &&
+ (CurrentBlock != E_BLOCK_WATER) &&
+ (CurrentBlock != E_BLOCK_STATIONARY_WATER) &&
+ (CurrentBlock != E_BLOCK_LAVA) &&
+ (CurrentBlock != E_BLOCK_STATIONARY_LAVA)
+ )
+ {
+ // Cannot place water here
+ return false;
+ }
+
+ if (a_Player->GetGameMode() != gmCreative)
+ {
+ // Remove fluid bucket, add empty bucket:
+ if (!a_Player->GetInventory().RemoveOneEquippedItem())
+ {
+ LOG("Clicked with a full bucket, but cannot remove one from the inventory? WTF?");
+ ASSERT(!"Inventory bucket mismatch");
+ return false;
+ }
+ cItem Item(E_ITEM_BUCKET, 1);
+ if (!a_Player->GetInventory().AddItem(Item,true,true))
+ {
+ return false;
+ }
+ }
+
+ // Wash away anything that was there prior to placing:
+ if (CanWashAway)
+ {
+ cBlockHandler * Handler = BlockHandler(CurrentBlock);
+ if (Handler->DoesDropOnUnsuitable())
+ {
+ Handler->DropBlock(a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ);
+ }
+ }
+
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_FluidBlock, 0);
+
+ return true;
+ }
+
+};
diff --git a/src/Items/ItemCauldron.h b/src/Items/ItemCauldron.h
new file mode 100644
index 000000000..8b2ddc29f
--- /dev/null
+++ b/src/Items/ItemCauldron.h
@@ -0,0 +1,41 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+
+
+
+
+
+class cItemCauldronHandler :
+ public cItemHandler
+{
+public:
+ cItemCauldronHandler(int a_ItemType) :
+ cItemHandler(a_ItemType)
+ {
+ }
+
+
+ virtual bool IsPlaceable(void) override
+ {
+ return true;
+ }
+
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ a_BlockType = E_BLOCK_CAULDRON;
+ a_BlockMeta = 0;
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemCloth.h b/src/Items/ItemCloth.h
new file mode 100644
index 000000000..aca27a299
--- /dev/null
+++ b/src/Items/ItemCloth.h
@@ -0,0 +1,23 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+
+
+
+
+
+class cItemClothHandler :
+ public cItemHandler
+{
+public:
+ cItemClothHandler(int a_ItemType)
+ : cItemHandler(a_ItemType)
+ {
+
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemComparator.h b/src/Items/ItemComparator.h
new file mode 100644
index 000000000..53dbd020d
--- /dev/null
+++ b/src/Items/ItemComparator.h
@@ -0,0 +1,40 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../Simulator/RedstoneSimulator.h"
+
+
+
+
+
+class cItemComparatorHandler :
+ public cItemHandler
+{
+public:
+ cItemComparatorHandler(int a_ItemType) :
+ cItemHandler(a_ItemType)
+ {
+ }
+
+ virtual bool IsPlaceable(void) override
+ {
+ return true;
+ }
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ a_BlockType = E_BLOCK_INACTIVE_COMPARATOR;
+ a_BlockMeta = cRedstoneSimulator::RepeaterRotationToMetaData(a_Player->GetRotation());
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemDoor.h b/src/Items/ItemDoor.h
new file mode 100644
index 000000000..72ea0beed
--- /dev/null
+++ b/src/Items/ItemDoor.h
@@ -0,0 +1,45 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+
+
+
+
+
+class cItemDoorHandler :
+ public cItemHandler
+{
+public:
+ cItemDoorHandler(int a_ItemType) :
+ cItemHandler(a_ItemType)
+ {
+
+ }
+
+ virtual bool IsPlaceable(void) override
+ {
+ return true;
+ }
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ a_BlockType = (m_ItemType == E_ITEM_WOODEN_DOOR) ? E_BLOCK_WOODEN_DOOR : E_BLOCK_IRON_DOOR;
+ return BlockHandler(a_BlockType)->GetPlacementBlockTypeMeta(
+ a_World, a_Player,
+ a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
+ a_CursorX, a_CursorY, a_CursorZ,
+ a_BlockType, a_BlockMeta
+ );
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemDye.h b/src/Items/ItemDye.h
new file mode 100644
index 000000000..99b8d2543
--- /dev/null
+++ b/src/Items/ItemDye.h
@@ -0,0 +1,44 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+class cItemDyeHandler :
+ public cItemHandler
+{
+public:
+ cItemDyeHandler(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, char a_Dir) override
+ {
+ // TODO: Handle coloring the sheep, too (OnItemUseOnEntity maybe)
+
+ // Handle growing the plants:
+ if (a_Item.m_ItemDamage == E_META_DYE_WHITE)
+ {
+ if (a_World->GrowRipePlant(a_BlockX, a_BlockY, a_BlockZ, true))
+ {
+ if (a_Player->GetGameMode() != gmCreative)
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemFlowerPot.h b/src/Items/ItemFlowerPot.h
new file mode 100644
index 000000000..befa2ff21
--- /dev/null
+++ b/src/Items/ItemFlowerPot.h
@@ -0,0 +1,41 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+
+
+
+
+
+class cItemFlowerPotHandler :
+ public cItemHandler
+{
+public:
+ cItemFlowerPotHandler(int a_ItemType) :
+ cItemHandler(a_ItemType)
+ {
+ }
+
+
+ virtual bool IsPlaceable(void) override
+ {
+ return true;
+ }
+
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ a_BlockType = E_BLOCK_FLOWER_POT;
+ a_BlockMeta = 0;
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemFood.h b/src/Items/ItemFood.h
new file mode 100644
index 000000000..2ae572331
--- /dev/null
+++ b/src/Items/ItemFood.h
@@ -0,0 +1,63 @@
+#pragma once
+
+#include "ItemHandler.h"
+
+
+
+
+
+class cItemFoodHandler :
+ public cItemHandler
+{
+ typedef cItemHandler super;
+
+public:
+ cItemFoodHandler(int a_ItemType)
+ : super(a_ItemType)
+ {
+ }
+
+
+ virtual bool IsFood(void) override
+ {
+ return true;
+ }
+
+
+ virtual FoodInfo GetFoodInfo(void) override
+ {
+ switch(m_ItemType)
+ {
+ // Please keep alpha-sorted.
+ case E_ITEM_BAKED_POTATO: return FoodInfo(6, 7.2);
+ case E_ITEM_BREAD: return FoodInfo(5, 6);
+ case E_ITEM_CARROT: return FoodInfo(4, 4.8);
+ case E_ITEM_COOKED_CHICKEN: return FoodInfo(6, 7.2);
+ case E_ITEM_COOKED_FISH: return FoodInfo(5, 6);
+ case E_ITEM_COOKED_PORKCHOP: return FoodInfo(8, 12.8);
+ case E_ITEM_COOKIE: return FoodInfo(2, 0.4);
+ case E_ITEM_GOLDEN_APPLE: return FoodInfo(4, 9.6);
+ case E_ITEM_GOLDEN_CARROT: return FoodInfo(6, 14.4);
+ case E_ITEM_MELON_SLICE: return FoodInfo(2, 1.2);
+ case E_ITEM_POISONOUS_POTATO: return FoodInfo(2, 1.2, 60);
+ case E_ITEM_POTATO: return FoodInfo(1, 0.6);
+ case E_ITEM_PUMPKIN_PIE: return FoodInfo(8, 4.8);
+ case E_ITEM_RAW_BEEF: return FoodInfo(3, 1.8);
+ case E_ITEM_RAW_CHICKEN: return FoodInfo(2, 1.2, 30);
+ case E_ITEM_RAW_FISH: return FoodInfo(2, 1.2);
+ case E_ITEM_RAW_PORKCHOP: return FoodInfo(3, 1.8);
+ case E_ITEM_RED_APPLE: return FoodInfo(4, 2.4);
+ case E_ITEM_ROTTEN_FLESH: return FoodInfo(4, 0.8, 80);
+ case E_ITEM_SPIDER_EYE: return FoodInfo(2, 3.2, 100);
+ case E_ITEM_STEAK: return FoodInfo(8, 12.8);
+ case E_ITEM_MUSHROOM_SOUP: return FoodInfo(6, 7.2);
+ }
+ LOGWARNING("%s: Unknown food item (%d), returning zero nutrition", __FUNCTION__, m_ItemType);
+ return FoodInfo(0, 0.f);
+ }
+
+};
+
+
+
+
diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp
new file mode 100644
index 000000000..13f5293b9
--- /dev/null
+++ b/src/Items/ItemHandler.cpp
@@ -0,0 +1,509 @@
+
+#include "Globals.h"
+#include "ItemHandler.h"
+#include "../Item.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+#include "../FastRandom.h"
+
+// Handlers:
+#include "ItemBed.h"
+#include "ItemBoat.h"
+#include "ItemBow.h"
+#include "ItemBrewingStand.h"
+#include "ItemBucket.h"
+#include "ItemCauldron.h"
+#include "ItemCloth.h"
+#include "ItemComparator.h"
+#include "ItemDoor.h"
+#include "ItemDye.h"
+#include "ItemFlowerPot.h"
+#include "ItemFood.h"
+#include "ItemHoe.h"
+#include "ItemLeaves.h"
+#include "ItemLighter.h"
+#include "ItemMinecart.h"
+#include "ItemPickaxe.h"
+#include "ItemThrowable.h"
+#include "ItemRedstoneDust.h"
+#include "ItemRedstoneRepeater.h"
+#include "ItemSapling.h"
+#include "ItemSeeds.h"
+#include "ItemShears.h"
+#include "ItemShovel.h"
+#include "ItemSign.h"
+#include "ItemSpawnEgg.h"
+#include "ItemSugarcane.h"
+#include "ItemSword.h"
+
+#include "../Blocks/BlockHandler.h"
+
+
+
+
+
+bool cItemHandler::m_HandlerInitialized = false;
+cItemHandler * cItemHandler::m_ItemHandler[2268];
+
+
+
+
+
+cItemHandler * cItemHandler::GetItemHandler(int a_ItemType)
+{
+ if (a_ItemType < 0)
+ {
+ // Either nothing (-1), or bad value, both cases should return the air handler
+ if (a_ItemType < -1)
+ {
+ ASSERT(!"Bad item type");
+ }
+ a_ItemType = 0;
+ }
+
+ if (!m_HandlerInitialized)
+ {
+ // We need to initialize
+ memset(m_ItemHandler, 0, sizeof(m_ItemHandler));
+ m_HandlerInitialized = true;
+ }
+ if (m_ItemHandler[a_ItemType] == NULL)
+ {
+ m_ItemHandler[a_ItemType] = CreateItemHandler(a_ItemType);
+ }
+ return m_ItemHandler[a_ItemType];
+}
+
+
+
+
+
+cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
+{
+ switch(a_ItemType)
+ {
+ default: return new cItemHandler(a_ItemType);
+
+ // Single item per handler, alphabetically sorted:
+ case E_BLOCK_LEAVES: return new cItemLeavesHandler(a_ItemType);
+ case E_BLOCK_SAPLING: return new cItemSaplingHandler(a_ItemType);
+ case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType);
+ case E_ITEM_BED: return new cItemBedHandler(a_ItemType);
+ case E_ITEM_BOAT: return new cItemBoatHandler(a_ItemType);
+ case E_ITEM_BOW: return new cItemBowHandler;
+ case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType);
+ case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType);
+ case E_ITEM_COMPARATOR: return new cItemComparatorHandler(a_ItemType);
+ case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType);
+ case E_ITEM_EGG: return new cItemEggHandler();
+ case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler();
+ case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType);
+ case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType);
+ case E_ITEM_REDSTONE_DUST: return new cItemRedstoneDustHandler(a_ItemType);
+ case E_ITEM_REDSTONE_REPEATER: return new cItemRedstoneRepeaterHandler(a_ItemType);
+ case E_ITEM_SHEARS: return new cItemShearsHandler(a_ItemType);
+ case E_ITEM_SIGN: return new cItemSignHandler(a_ItemType);
+ case E_ITEM_SNOWBALL: return new cItemSnowballHandler();
+ case E_ITEM_SPAWN_EGG: return new cItemSpawnEggHandler(a_ItemType);
+ case E_ITEM_SUGARCANE: return new cItemSugarcaneHandler(a_ItemType);
+
+ case E_ITEM_WOODEN_HOE:
+ case E_ITEM_STONE_HOE:
+ case E_ITEM_IRON_HOE:
+ case E_ITEM_GOLD_HOE:
+ case E_ITEM_DIAMOND_HOE:
+ {
+ return new cItemHoeHandler(a_ItemType);
+ }
+
+ case E_ITEM_WOODEN_PICKAXE:
+ case E_ITEM_STONE_PICKAXE:
+ case E_ITEM_IRON_PICKAXE:
+ case E_ITEM_GOLD_PICKAXE:
+ case E_ITEM_DIAMOND_PICKAXE:
+ {
+ return new cItemPickaxeHandler(a_ItemType);
+ }
+
+ case E_ITEM_WOODEN_SHOVEL:
+ case E_ITEM_STONE_SHOVEL:
+ case E_ITEM_IRON_SHOVEL:
+ case E_ITEM_GOLD_SHOVEL:
+ case E_ITEM_DIAMOND_SHOVEL:
+ {
+ return new cItemShovelHandler(a_ItemType);
+ }
+
+ case E_ITEM_WOODEN_SWORD:
+ case E_ITEM_STONE_SWORD:
+ case E_ITEM_IRON_SWORD:
+ case E_ITEM_GOLD_SWORD:
+ case E_ITEM_DIAMOND_SWORD:
+ {
+ return new cItemSwordHandler(a_ItemType);
+ }
+
+ case E_ITEM_BUCKET:
+ case E_ITEM_WATER_BUCKET:
+ case E_ITEM_LAVA_BUCKET:
+ {
+ return new cItemBucketHandler(a_ItemType);
+ }
+
+ case E_ITEM_CARROT:
+ case E_ITEM_MELON_SEEDS:
+ case E_ITEM_POTATO:
+ case E_ITEM_PUMPKIN_SEEDS:
+ case E_ITEM_SEEDS:
+ {
+ return new cItemSeedsHandler(a_ItemType);
+ }
+
+ case E_ITEM_IRON_DOOR:
+ case E_ITEM_WOODEN_DOOR:
+ {
+ return new cItemDoorHandler(a_ItemType);
+ }
+
+ case E_ITEM_MINECART:
+ case E_ITEM_CHEST_MINECART:
+ case E_ITEM_FURNACE_MINECART:
+ case E_ITEM_MINECART_WITH_TNT:
+ case E_ITEM_MINECART_WITH_HOPPER:
+ {
+ return new cItemMinecartHandler(a_ItemType);
+ }
+
+ // Food:
+ case E_ITEM_BREAD:
+ case E_ITEM_COOKIE:
+ case E_ITEM_MELON_SLICE:
+ case E_ITEM_RAW_CHICKEN:
+ case E_ITEM_COOKED_CHICKEN:
+ case E_ITEM_RAW_BEEF:
+ case E_ITEM_RAW_PORKCHOP:
+ case E_ITEM_STEAK:
+ case E_ITEM_COOKED_PORKCHOP:
+ case E_ITEM_RAW_FISH:
+ case E_ITEM_COOKED_FISH:
+ case E_ITEM_RED_APPLE:
+ case E_ITEM_GOLDEN_APPLE:
+ case E_ITEM_ROTTEN_FLESH:
+ case E_ITEM_MUSHROOM_SOUP:
+ case E_ITEM_SPIDER_EYE:
+ {
+ return new cItemFoodHandler(a_ItemType);
+ }
+ }
+}
+
+
+
+
+
+void cItemHandler::Deinit()
+{
+ for(int i = 0; i < 2267; i++)
+ {
+ delete m_ItemHandler[i];
+ }
+ memset(m_ItemHandler, 0, sizeof(m_ItemHandler)); // Don't leave any dangling pointers around, just in case
+ m_HandlerInitialized = false;
+}
+
+
+
+
+
+cItemHandler::cItemHandler(int a_ItemType)
+{
+ m_ItemType = a_ItemType;
+}
+
+
+
+
+
+bool cItemHandler::OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir)
+{
+ return false;
+}
+
+
+
+
+
+bool cItemHandler::OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir)
+{
+ return false;
+}
+
+
+
+
+
+void cItemHandler::OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ cBlockHandler * Handler = cBlockHandler::GetBlockHandler(Block);
+
+ if (a_Player->IsGameModeSurvival())
+ {
+ if (!BlockRequiresSpecialTool(Block) || CanHarvestBlock(Block))
+ {
+ Handler->DropBlock(a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ);
+ }
+ }
+
+ a_Player->UseEquippedItem();
+}
+
+
+
+
+
+void cItemHandler::OnFoodEaten(cWorld * a_World, cPlayer * a_Player, cItem * a_Item)
+{
+
+}
+
+
+
+
+
+char cItemHandler::GetMaxStackSize(void)
+{
+ if (m_ItemType < 256)
+ {
+ // All blocks can stack up to 64
+ return 64;
+ }
+
+ switch (m_ItemType) //sorted by id
+ {
+ case E_ITEM_ARROW: return 64;
+ case E_ITEM_BAKED_POTATO: return 64;
+ case E_ITEM_BLAZE_POWDER: return 64;
+ case E_ITEM_BLAZE_ROD: return 64;
+ case E_ITEM_BONE: return 64;
+ case E_ITEM_BOOK: return 64;
+ case E_ITEM_BOTTLE_O_ENCHANTING: return 64;
+ case E_ITEM_BOWL: return 64;
+ case E_ITEM_BREAD: return 64;
+ case E_ITEM_BREWING_STAND: return 64;
+ case E_ITEM_BUCKET: return 1; // TODO: change this to 16 when turning compatibility to 1.3
+ case E_ITEM_CARROT: return 64;
+ case E_ITEM_CAULDRON: return 64;
+ case E_ITEM_CLAY: return 64;
+ case E_ITEM_CLAY_BRICK: return 64;
+ case E_ITEM_CLOCK: return 64;
+ case E_ITEM_COAL: return 64;
+ case E_ITEM_COMPARATOR: return 64;
+ case E_ITEM_COMPASS: return 64;
+ case E_ITEM_COOKED_CHICKEN: return 64;
+ case E_ITEM_COOKED_FISH: return 64;
+ case E_ITEM_COOKED_PORKCHOP: return 64;
+ case E_ITEM_COOKIE: return 64;
+ case E_ITEM_DIAMOND: return 64;
+ case E_ITEM_DYE: return 64;
+ case E_ITEM_EGG: return 16;
+ case E_ITEM_EMERALD: return 64;
+ case E_ITEM_ENDER_PEARL: return 16;
+ case E_ITEM_EYE_OF_ENDER: return 64;
+ case E_ITEM_FEATHER: return 64;
+ case E_ITEM_FERMENTED_SPIDER_EYE: return 64;
+ case E_ITEM_FIRE_CHARGE: return 64;
+ case E_ITEM_FIREWORK_ROCKET: return 64;
+ case E_ITEM_FIREWORK_STAR: return 64;
+ case E_ITEM_FLINT: return 64;
+ case E_ITEM_FLOWER_POT: return 64;
+ case E_ITEM_GHAST_TEAR: return 64;
+ case E_ITEM_GLASS_BOTTLE: return 64;
+ case E_ITEM_GLISTERING_MELON: return 64;
+ case E_ITEM_GLOWSTONE_DUST: return 64;
+ case E_ITEM_GOLD: return 64;
+ case E_ITEM_GOLDEN_APPLE: return 64;
+ case E_ITEM_GOLDEN_CARROT: return 64;
+ case E_ITEM_GOLD_NUGGET: return 64;
+ case E_ITEM_GUNPOWDER: return 64;
+ case E_ITEM_HEAD: return 64;
+ case E_ITEM_IRON: return 64;
+ case E_ITEM_LEATHER: return 64;
+ case E_ITEM_MAGMA_CREAM: return 64;
+ case E_ITEM_MAP: return 64;
+ case E_ITEM_MELON_SEEDS: return 64;
+ case E_ITEM_MELON_SLICE: return 64;
+ case E_ITEM_NETHER_BRICK: return 64;
+ case E_ITEM_NETHER_WART: return 64;
+ case E_ITEM_PAINTINGS: return 64;
+ case E_ITEM_PAPER: return 64;
+ case E_ITEM_POISONOUS_POTATO: return 64;
+ case E_ITEM_POTATO: return 64;
+ case E_ITEM_PUMPKIN_PIE: return 64;
+ case E_ITEM_PUMPKIN_SEEDS: return 64;
+ case E_ITEM_RAW_BEEF: return 64;
+ case E_ITEM_RAW_CHICKEN: return 64;
+ case E_ITEM_RAW_FISH: return 64;
+ case E_ITEM_RAW_PORKCHOP: return 64;
+ case E_ITEM_RED_APPLE: return 64;
+ case E_ITEM_REDSTONE_DUST: return 64;
+ case E_ITEM_REDSTONE_REPEATER: return 64;
+ case E_ITEM_ROTTEN_FLESH: return 64;
+ case E_ITEM_SEEDS: return 64;
+ case E_ITEM_SIGN: return 16;
+ case E_ITEM_SLIMEBALL: return 64;
+ case E_ITEM_SNOWBALL: return 16;
+ case E_ITEM_SPAWN_EGG: return 64;
+ case E_ITEM_SPIDER_EYE: return 64;
+ case E_ITEM_STEAK: return 64;
+ case E_ITEM_STICK: return 64;
+ case E_ITEM_STRING: return 64;
+ case E_ITEM_SUGAR: return 64;
+ case E_ITEM_SUGAR_CANE: return 64;
+ case E_ITEM_WHEAT: return 64;
+ }
+ // By default items don't stack:
+ return 1;
+}
+
+
+
+
+
+bool cItemHandler::IsTool()
+{
+ // TODO: Rewrite this to list all tools specifically
+ return
+ (m_ItemType >= 256 && m_ItemType <= 259)
+ || (m_ItemType == 261)
+ || (m_ItemType >= 267 && m_ItemType <= 279)
+ || (m_ItemType >= 283 && m_ItemType <= 286)
+ || (m_ItemType >= 290 && m_ItemType <= 294)
+ || (m_ItemType >= 256 && m_ItemType <= 259)
+ || (m_ItemType == 325)
+ || (m_ItemType == 346);
+}
+
+
+
+
+
+bool cItemHandler::IsFood(void)
+{
+ switch (m_ItemType)
+ {
+ case E_ITEM_RED_APPLE:
+ case E_ITEM_GOLDEN_APPLE:
+ case E_ITEM_MUSHROOM_SOUP:
+ case E_ITEM_BREAD:
+ case E_ITEM_RAW_PORKCHOP:
+ case E_ITEM_COOKED_PORKCHOP:
+ case E_ITEM_MILK:
+ case E_ITEM_RAW_FISH:
+ case E_ITEM_COOKED_FISH:
+ case E_ITEM_COOKIE:
+ case E_ITEM_MELON_SLICE:
+ case E_ITEM_RAW_BEEF:
+ case E_ITEM_STEAK:
+ case E_ITEM_RAW_CHICKEN:
+ case E_ITEM_COOKED_CHICKEN:
+ case E_ITEM_ROTTEN_FLESH:
+ case E_ITEM_SPIDER_EYE:
+ case E_ITEM_CARROT:
+ case E_ITEM_POTATO:
+ case E_ITEM_BAKED_POTATO:
+ case E_ITEM_POISONOUS_POTATO:
+ {
+ return true;
+ }
+ } // switch (m_ItemType)
+ return false;
+}
+
+
+
+
+
+bool cItemHandler::IsPlaceable(void)
+{
+ // We can place any block that has a corresponding E_BLOCK_TYPE:
+ return (m_ItemType >= 1) && (m_ItemType <= E_BLOCK_MAX_TYPE_ID);
+}
+
+
+
+
+
+bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType)
+{
+ return false;
+}
+
+
+
+
+
+bool cItemHandler::GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+)
+{
+ ASSERT(m_ItemType < 256); // Items with IDs above 255 should all be handled by specific handlers
+
+ if (m_ItemType > 256)
+ {
+ LOGERROR("%s: Item %d has no valid block!", __FUNCTION__, m_ItemType);
+ return false;
+ }
+
+ cBlockHandler * BlockH = BlockHandler(m_ItemType);
+ return BlockH->GetPlacementBlockTypeMeta(
+ a_World, a_Player,
+ a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
+ a_CursorX, a_CursorY, a_CursorZ,
+ a_BlockType, a_BlockMeta
+ );
+}
+
+
+
+
+
+bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item)
+{
+ FoodInfo Info = GetFoodInfo();
+
+ if ((Info.FoodLevel > 0) || (Info.Saturation > 0.f))
+ {
+ bool Success = a_Player->Feed(Info.FoodLevel, Info.Saturation);
+
+ // If consumed and there's chance of foodpoisoning, do it:
+ if (Success && (Info.PoisonChance > 0))
+ {
+ cFastRandom r1;
+ if ((r1.NextInt(100, a_Player->GetUniqueID()) - Info.PoisonChance) <= 0)
+ {
+ a_Player->FoodPoison(300);
+ }
+ }
+
+ return Success;
+ }
+
+ return false;
+}
+
+
+
+
+
+cItemHandler::FoodInfo cItemHandler::GetFoodInfo()
+{
+ return FoodInfo(0, 0.f);
+}
+
+
+
+
diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h
new file mode 100644
index 000000000..e39bb054b
--- /dev/null
+++ b/src/Items/ItemHandler.h
@@ -0,0 +1,99 @@
+
+#pragma once
+
+#include "../Defines.h"
+#include "../Item.h"
+
+
+
+
+
+// fwd:
+class cWorld;
+class cPlayer;
+
+
+
+
+
+class cItemHandler
+{
+public:
+ cItemHandler(int a_ItemType);
+
+ /// Called when the player tries to use the item (right mouse button). Return false to make the item unusable. DEFAULT: False
+ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir);
+
+ /// Called when the client sends the SHOOT status in the lclk packet
+ virtual void OnItemShoot(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) {}
+
+ /// Called while the player diggs a block using this item
+ virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace);
+
+ /// Called when the player destroys a block using this item. This also calls the drop function for the destroyed block
+ virtual void OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_X, int a_Y, int a_Z);
+
+ /// Called after the player has eaten this item.
+ virtual void OnFoodEaten(cWorld *a_World, cPlayer *a_Player, cItem *a_Item);
+
+ /// Returns the maximum stack size for a given item
+ virtual char GetMaxStackSize(void);
+
+ struct FoodInfo
+ {
+ int FoodLevel;
+ double Saturation;
+ int PoisonChance; // 0 - 100, in percent. 0 = no chance of poisoning, 100 = sure poisoning
+
+ FoodInfo(int a_FoodLevel, double a_Saturation, int a_PoisonChance = 0) :
+ FoodLevel(a_FoodLevel),
+ Saturation(a_Saturation),
+ PoisonChance(a_PoisonChance)
+ {
+ }
+ } ;
+
+ /// Returns the FoodInfo for this item. (FoodRecovery, Saturation and PoisionChance)
+ virtual FoodInfo GetFoodInfo();
+
+ /// Lets the player eat a selected item. Returns true if the player ate the item
+ virtual bool EatItem(cPlayer *a_Player, cItem *a_Item);
+
+ /// Indicates if this item is a tool
+ virtual bool IsTool(void);
+
+ /// Indicates if this item is food
+ virtual bool IsFood(void);
+
+ /// Blocks simply get placed
+ virtual bool IsPlaceable(void);
+
+ /** Called before a block is placed into a world.
+ The handler should return true to allow placement, false to refuse.
+ Also, the handler should set a_BlockType and a_BlockMeta to correct values for the newly placed block.
+ */
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ );
+
+ /// Returns whether this tool/item can harvest a specific block (e.g. wooden pickaxe can harvest stone, but wood canīt) DEFAULT: False
+ virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType);
+
+ static cItemHandler * GetItemHandler(int a_ItemType);
+ static cItemHandler * GetItemHandler(const cItem & a_Item) { return GetItemHandler(a_Item.m_ItemType); }
+
+ static void Deinit();
+
+protected:
+ int m_ItemType;
+ static cItemHandler *CreateItemHandler(int m_ItemType);
+
+ static cItemHandler * m_ItemHandler[E_ITEM_LAST + 1];
+ static bool m_HandlerInitialized; //used to detect if the itemhandlers are initialized
+};
+
+//Short function
+inline cItemHandler *ItemHandler(int a_ItemType) { return cItemHandler::GetItemHandler(a_ItemType); }
diff --git a/src/Items/ItemHoe.h b/src/Items/ItemHoe.h
new file mode 100644
index 000000000..7b6b3e6ac
--- /dev/null
+++ b/src/Items/ItemHoe.h
@@ -0,0 +1,40 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+class cItemHoeHandler :
+ public cItemHandler
+{
+public:
+ cItemHoeHandler(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, char a_Dir) override
+ {
+ BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+
+ if ((Block == E_BLOCK_DIRT) || (Block == E_BLOCK_GRASS))
+ {
+ a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FARMLAND, 0);
+
+ a_Player->UseEquippedItem();
+ return true;
+
+ }
+ return false;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemLeaves.h b/src/Items/ItemLeaves.h
new file mode 100644
index 000000000..60222eaa9
--- /dev/null
+++ b/src/Items/ItemLeaves.h
@@ -0,0 +1,41 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+
+
+
+
+
+class cItemLeavesHandler :
+ public cItemHandler
+{
+ typedef cItemHandler super;
+
+public:
+ cItemLeavesHandler(int a_ItemType)
+ : cItemHandler(a_ItemType)
+ {
+ }
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ bool res = super::GetPlacementBlockTypeMeta(
+ a_World, a_Player,
+ a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
+ a_CursorX, a_CursorY, a_CursorZ,
+ a_BlockType, a_BlockMeta
+ );
+ a_BlockMeta = a_BlockMeta | 0x4; //0x4 bit set means this is a player-placed leaves block, not to be decayed
+ return res;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemLighter.h b/src/Items/ItemLighter.h
new file mode 100644
index 000000000..4281a2d0c
--- /dev/null
+++ b/src/Items/ItemLighter.h
@@ -0,0 +1,59 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+#include "../Entities/TNTEntity.h"
+
+
+
+
+
+class cItemLighterHandler :
+ public cItemHandler
+{
+public:
+ cItemLighterHandler(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, char a_BlockFace) override
+ {
+ if (a_BlockFace < 0)
+ {
+ return false;
+ }
+
+ a_Player->UseEquippedItem();
+
+ switch (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ))
+ {
+ case E_BLOCK_TNT:
+ {
+ // Activate the TNT:
+ a_World->BroadcastSoundEffect("random.fuse", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f);
+ a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
+ a_World->SetBlock(a_BlockX,a_BlockY,a_BlockZ, E_BLOCK_AIR, 0);
+ break;
+ }
+ default:
+ {
+ // Light a fire next to/on top of the block if air:
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+ if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
+ {
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 0);
+ break;
+ }
+ }
+ }
+
+ return false;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h
new file mode 100644
index 000000000..f8eb31a49
--- /dev/null
+++ b/src/Items/ItemMinecart.h
@@ -0,0 +1,82 @@
+
+// ItemMinecart.h
+
+// Declares the various minecart ItemHandlers
+
+
+
+
+
+#pragma once
+
+#include "../Entities/Minecart.h"
+
+
+
+
+
+class cItemMinecartHandler :
+ public cItemHandler
+{
+ typedef cItemHandler super;
+
+public:
+ cItemMinecartHandler(int a_ItemType) :
+ super(a_ItemType)
+ {
+ }
+
+
+
+ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override
+ {
+ if (a_Dir < 0)
+ {
+ return false;
+ }
+
+ // Check that there's rail in there:
+ BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ switch (Block)
+ {
+ case E_BLOCK_MINECART_TRACKS:
+ case E_BLOCK_POWERED_RAIL:
+ case E_BLOCK_DETECTOR_RAIL:
+ case E_BLOCK_ACTIVATOR_RAIL:
+ {
+ // These are allowed
+ break;
+ }
+ default:
+ {
+ LOGD("Used minecart on an unsuitable block %d (%s)", Block, ItemTypeToString(Block).c_str());
+ return false;
+ }
+ }
+
+ double x = (double)a_BlockX + 0.5;
+ double y = (double)a_BlockY + 0.5;
+ double z = (double)a_BlockZ + 0.5;
+ cMinecart * Minecart = NULL;
+ switch (m_ItemType)
+ {
+ case E_ITEM_MINECART: Minecart = new cEmptyMinecart (x, y, z); break;
+ case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (x, y, z); break;
+ case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (x, y, z); break;
+ case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (x, y, z); break;
+ case E_ITEM_MINECART_WITH_HOPPER: Minecart = new cMinecartWithHopper (x, y, z); break;
+ default:
+ {
+ ASSERT(!"Unhandled minecart item");
+ return false;
+ }
+ } // switch (m_ItemType)
+ Minecart->Initialize(a_World);
+ return true;
+ }
+
+} ;
+
+
+
+
diff --git a/src/Items/ItemPickaxe.h b/src/Items/ItemPickaxe.h
new file mode 100644
index 000000000..bde7f0905
--- /dev/null
+++ b/src/Items/ItemPickaxe.h
@@ -0,0 +1,92 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+
+class cItemPickaxeHandler :
+ public cItemHandler
+{
+public:
+ cItemPickaxeHandler(int a_ItemType)
+ : cItemHandler(a_ItemType)
+ {
+
+ }
+
+ char PickaxeLevel()
+ {
+ switch(m_ItemType)
+ {
+ case E_ITEM_WOODEN_PICKAXE:
+ case E_ITEM_GOLD_PICKAXE:
+ return 1;
+ case E_ITEM_STONE_PICKAXE:
+ return 2;
+ case E_ITEM_IRON_PICKAXE:
+ return 3;
+ case E_ITEM_DIAMOND_PICKAXE:
+ return 4;
+ default:
+ return 0;
+ }
+ }
+
+ virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType) override
+ {
+ switch(a_BlockType)
+ {
+ case E_BLOCK_OBSIDIAN:
+ {
+ return PickaxeLevel() >= 4;
+ }
+
+ case E_BLOCK_DIAMOND_BLOCK:
+ case E_BLOCK_DIAMOND_ORE:
+ case E_BLOCK_GOLD_BLOCK:
+ case E_BLOCK_GOLD_ORE:
+ case E_BLOCK_REDSTONE_ORE:
+ case E_BLOCK_REDSTONE_ORE_GLOWING:
+ case E_BLOCK_EMERALD_ORE:
+ {
+ return PickaxeLevel() >= 3;
+ }
+
+ case E_BLOCK_IRON_BLOCK:
+ case E_BLOCK_IRON_ORE:
+ case E_BLOCK_LAPIS_ORE:
+ case E_BLOCK_LAPIS_BLOCK:
+ {
+ return PickaxeLevel() >= 2;
+ }
+
+ case E_BLOCK_COAL_ORE:
+ case E_BLOCK_STONE:
+ case E_BLOCK_COBBLESTONE:
+ case E_BLOCK_END_STONE:
+ case E_BLOCK_MOSSY_COBBLESTONE:
+ case E_BLOCK_SANDSTONE_STAIRS:
+ case E_BLOCK_SANDSTONE:
+ case E_BLOCK_STONE_BRICKS:
+ case E_BLOCK_NETHER_BRICK:
+ case E_BLOCK_NETHERRACK:
+ case E_BLOCK_STONE_SLAB:
+ case E_BLOCK_DOUBLE_STONE_SLAB:
+ case E_BLOCK_STONE_PRESSURE_PLATE:
+ case E_BLOCK_BRICK:
+ case E_BLOCK_COBBLESTONE_STAIRS:
+ case E_BLOCK_STONE_BRICK_STAIRS:
+ case E_BLOCK_NETHER_BRICK_STAIRS:
+ case E_BLOCK_CAULDRON:
+ {
+ return PickaxeLevel() >= 1;
+ }
+ }
+ return false;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemRedstoneDust.h b/src/Items/ItemRedstoneDust.h
new file mode 100644
index 000000000..b7860b187
--- /dev/null
+++ b/src/Items/ItemRedstoneDust.h
@@ -0,0 +1,38 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+
+
+
+
+
+class cItemRedstoneDustHandler : public cItemHandler
+{
+public:
+ cItemRedstoneDustHandler(int a_ItemType)
+ : cItemHandler(a_ItemType)
+ {
+ }
+
+ virtual bool IsPlaceable(void) override
+ {
+ return true;
+ }
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ a_BlockType = E_BLOCK_REDSTONE_WIRE;
+ a_BlockMeta = 0;
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemRedstoneRepeater.h b/src/Items/ItemRedstoneRepeater.h
new file mode 100644
index 000000000..459070579
--- /dev/null
+++ b/src/Items/ItemRedstoneRepeater.h
@@ -0,0 +1,40 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../Simulator/RedstoneSimulator.h"
+
+
+
+
+
+class cItemRedstoneRepeaterHandler :
+ public cItemHandler
+{
+public:
+ cItemRedstoneRepeaterHandler(int a_ItemType)
+ : cItemHandler(a_ItemType)
+ {
+ }
+
+ virtual bool IsPlaceable() override
+ {
+ return true;
+ }
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ a_BlockType = E_BLOCK_REDSTONE_REPEATER_OFF;
+ a_BlockMeta = cRedstoneSimulator::RepeaterRotationToMetaData(a_Player->GetRotation());
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemSapling.h b/src/Items/ItemSapling.h
new file mode 100644
index 000000000..dc0810a45
--- /dev/null
+++ b/src/Items/ItemSapling.h
@@ -0,0 +1,42 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+
+
+
+
+
+class cItemSaplingHandler : public cItemHandler
+{
+ typedef cItemHandler super;
+
+public:
+ cItemSaplingHandler(int a_ItemType)
+ : cItemHandler(a_ItemType)
+ {
+
+ }
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ bool res = super::GetPlacementBlockTypeMeta(
+ a_World, a_Player,
+ a_BlockX, a_BlockY, a_BlockZ, a_BlockFace,
+ a_CursorX, a_CursorY, a_CursorZ,
+ a_BlockType, a_BlockMeta
+ );
+ // Only the lowest 3 bits are important
+ a_BlockMeta = a_BlockMeta & 0x7;
+ return res;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemSeeds.h b/src/Items/ItemSeeds.h
new file mode 100644
index 000000000..8ca86663f
--- /dev/null
+++ b/src/Items/ItemSeeds.h
@@ -0,0 +1,65 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+
+
+
+
+
+class cItemSeedsHandler :
+ public cItemHandler
+{
+public:
+ cItemSeedsHandler(int a_ItemType) :
+ cItemHandler(a_ItemType)
+ {
+
+ }
+
+ virtual bool IsPlaceable(void) override
+ {
+ return true;
+ }
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ if (a_BlockFace != BLOCK_FACE_TOP)
+ {
+ // Only allow planting seeds from the top side of the block
+ return false;
+ }
+
+ // Only allow placement on farmland
+ int X = a_BlockX;
+ int Y = a_BlockY;
+ int Z = a_BlockZ;
+ AddFaceDirection(X, Y, Z, a_BlockFace, true);
+ if (a_World->GetBlock(X, Y, Z) != E_BLOCK_FARMLAND)
+ {
+ return false;
+ }
+
+ a_BlockMeta = 0;
+ switch (m_ItemType)
+ {
+ case E_ITEM_CARROT: a_BlockType = E_BLOCK_CARROTS; return true;
+ case E_ITEM_MELON_SEEDS: a_BlockType = E_BLOCK_MELON_STEM; return true;
+ case E_ITEM_POTATO: a_BlockType = E_BLOCK_POTATOES; return true;
+ case E_ITEM_PUMPKIN_SEEDS: a_BlockType = E_BLOCK_PUMPKIN_STEM; return true;
+ case E_ITEM_SEEDS: a_BlockType = E_BLOCK_CROPS; return true;
+ default: a_BlockType = E_BLOCK_AIR; return true;
+ }
+ return false;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemShears.h b/src/Items/ItemShears.h
new file mode 100644
index 000000000..6a17607ee
--- /dev/null
+++ b/src/Items/ItemShears.h
@@ -0,0 +1,62 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+class cItemShearsHandler :
+ public cItemHandler
+{
+public:
+ cItemShearsHandler(int a_ItemType) :
+ cItemHandler(a_ItemType)
+ {
+ }
+
+
+ virtual bool IsTool(void) override
+ {
+ return true;
+ }
+
+
+ virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override
+ {
+ BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ if (Block == E_BLOCK_LEAVES)
+ {
+ cItems Drops;
+ Drops.push_back(cItem(E_BLOCK_LEAVES, 1, a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x03));
+ a_World->SpawnItemPickups(Drops, a_BlockX, a_BlockY, a_BlockZ);
+
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_Player->UseEquippedItem();
+ return true;
+ }
+ return false;
+ }
+
+
+ virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType) override
+ {
+ switch (a_BlockType)
+ {
+ case E_BLOCK_COBWEB:
+ case E_BLOCK_VINES:
+ case E_BLOCK_LEAVES:
+ {
+ return true;
+ }
+ } // switch (a_BlockType)
+ return false;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemShovel.h b/src/Items/ItemShovel.h
new file mode 100644
index 000000000..d0625ef1c
--- /dev/null
+++ b/src/Items/ItemShovel.h
@@ -0,0 +1,41 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+
+#include "../Blocks/BlockHandler.h"
+
+
+
+
+
+class cItemShovelHandler : public cItemHandler
+{
+public:
+ cItemShovelHandler(int a_ItemType)
+ : cItemHandler(a_ItemType)
+ {
+
+ }
+
+ virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override
+ {
+ BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ if (Block == E_BLOCK_SNOW)
+ {
+ BlockHandler(Block)->DropBlock(a_World, a_Player, a_BlockX, a_BlockY, a_BlockZ);
+
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ a_Player->UseEquippedItem();
+ return true;
+ }
+ return false;
+ }
+
+ virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType) override
+ {
+ return (a_BlockType == E_BLOCK_SNOW);
+ }
+}; \ No newline at end of file
diff --git a/src/Items/ItemSign.h b/src/Items/ItemSign.h
new file mode 100644
index 000000000..5ccd79e29
--- /dev/null
+++ b/src/Items/ItemSign.h
@@ -0,0 +1,51 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+#include "../Blocks/BlockSign.h"
+
+
+
+
+
+class cItemSignHandler :
+ public cItemHandler
+{
+public:
+ cItemSignHandler(int a_ItemType) :
+ cItemHandler(a_ItemType)
+ {
+ }
+
+
+ virtual bool IsPlaceable(void) override
+ {
+ return true;
+ }
+
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ if (a_BlockFace == BLOCK_FACE_TOP)
+ {
+ a_BlockMeta = cBlockSignHandler::RotationToMetaData(a_Player->GetRotation());
+ a_BlockType = E_BLOCK_SIGN_POST;
+ }
+ else
+ {
+ a_BlockMeta = cBlockSignHandler::DirectionToMetaData(a_BlockFace);
+ a_BlockType = E_BLOCK_WALLSIGN;
+ }
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemSpawnEgg.h b/src/Items/ItemSpawnEgg.h
new file mode 100644
index 000000000..26dd15b7d
--- /dev/null
+++ b/src/Items/ItemSpawnEgg.h
@@ -0,0 +1,52 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+class cItemSpawnEggHandler : public cItemHandler
+{
+public:
+ cItemSpawnEggHandler(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, char a_BlockFace) override
+ {
+ if (a_BlockFace < 0)
+ {
+ return false;
+ }
+
+ AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+
+ if (a_BlockFace == BLOCK_FACE_BOTTOM)
+ {
+ a_BlockY--;
+ }
+
+ if (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, (cMonster::eType)(a_Item.m_ItemDamage)) >= 0)
+ {
+ if (a_Player->GetGameMode() != 1)
+ {
+ // The mob was spawned, "use" the item:
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
+ return true;
+ }
+
+ return false;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemSugarcane.h b/src/Items/ItemSugarcane.h
new file mode 100644
index 000000000..ce93aa3e5
--- /dev/null
+++ b/src/Items/ItemSugarcane.h
@@ -0,0 +1,39 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+
+
+
+
+
+class cItemSugarcaneHandler :
+ public cItemHandler
+{
+public:
+ cItemSugarcaneHandler(int a_ItemType) :
+ cItemHandler(a_ItemType)
+ {
+ }
+
+ virtual bool IsPlaceable(void) override
+ {
+ return true;
+ }
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ a_BlockType = E_BLOCK_SUGARCANE;
+ a_BlockMeta = 0;
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemSword.h b/src/Items/ItemSword.h
new file mode 100644
index 000000000..a7c1d2432
--- /dev/null
+++ b/src/Items/ItemSword.h
@@ -0,0 +1,30 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+class cItemSwordHandler :
+ public cItemHandler
+{
+public:
+ cItemSwordHandler(int a_ItemType)
+ : cItemHandler(a_ItemType)
+ {
+
+ }
+
+ virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType) override
+ {
+ return (a_BlockType == E_BLOCK_COBWEB);
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemThrowable.h b/src/Items/ItemThrowable.h
new file mode 100644
index 000000000..85579daf2
--- /dev/null
+++ b/src/Items/ItemThrowable.h
@@ -0,0 +1,96 @@
+
+// ItemThrowable.h
+
+// Declares the itemhandlers for throwable items: eggs, snowballs and ender pearls
+
+
+
+
+
+#pragma once
+
+
+
+
+
+class cItemThrowableHandler :
+ public cItemHandler
+{
+ typedef cItemHandler super;
+public:
+ cItemThrowableHandler(int a_ItemType, cProjectileEntity::eKind a_ProjectileKind, double a_SpeedCoeff) :
+ super(a_ItemType),
+ m_ProjectileKind(a_ProjectileKind),
+ m_SpeedCoeff(a_SpeedCoeff)
+ {
+ }
+
+
+ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override
+ {
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
+
+ Vector3d Pos = a_Player->GetThrowStartPos();
+ Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff;
+ a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &Speed);
+
+ return true;
+ }
+
+protected:
+ cProjectileEntity::eKind m_ProjectileKind;
+ double m_SpeedCoeff;
+} ;
+
+
+
+
+
+class cItemEggHandler :
+ public cItemThrowableHandler
+{
+ typedef cItemThrowableHandler super;
+public:
+ cItemEggHandler(void) :
+ super(E_ITEM_EGG, cProjectileEntity::pkEgg, 30)
+ {
+ }
+} ;
+
+
+
+
+class cItemSnowballHandler :
+ public cItemThrowableHandler
+{
+ typedef cItemThrowableHandler super;
+
+public:
+ cItemSnowballHandler(void) :
+ super(E_ITEM_SNOWBALL, cProjectileEntity::pkSnowball, 30)
+ {
+ }
+} ;
+
+
+
+
+
+class cItemEnderPearlHandler :
+ public cItemThrowableHandler
+{
+ typedef cItemThrowableHandler super;
+
+public:
+ cItemEnderPearlHandler(void) :
+ super(E_ITEM_ENDER_PEARL, cProjectileEntity::pkEnderPearl, 30)
+ {
+ }
+} ;
+
+
+
+