diff options
Diffstat (limited to 'src/Items')
30 files changed, 2219 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..3fbb7603d --- /dev/null +++ b/src/Items/ItemComparator.h @@ -0,0 +1,40 @@ + +#pragma once + +#include "ItemHandler.h" +#include "../Blocks/BlockRedstoneRepeater.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 = cBlockRedstoneRepeaterHandler::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..92ba94999 --- /dev/null +++ b/src/Items/ItemHandler.cpp @@ -0,0 +1,511 @@ + +#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_BOTTLE_O_ENCHANTING: return new cItemBottleOEnchantingHandler(); + 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_FIREWORK_ROCKET: return new cItemFireworkHandler(); + 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..f69f24eb8 --- /dev/null +++ b/src/Items/ItemRedstoneRepeater.h @@ -0,0 +1,40 @@ + +#pragma once + +#include "ItemHandler.h" +#include "../Blocks/BlockRedstoneRepeater.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 = cBlockRedstoneRepeaterHandler::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..fc24e775a --- /dev/null +++ b/src/Items/ItemThrowable.h @@ -0,0 +1,140 @@ + +// 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) + { + } +} ; + + + + + +class cItemBottleOEnchantingHandler : + public cItemThrowableHandler +{ + typedef cItemThrowableHandler super; +public: + cItemBottleOEnchantingHandler(void) : + super(E_ITEM_BOTTLE_O_ENCHANTING, cProjectileEntity::pkExpBottle, 10) + { + } +}; + + + + + +class cItemFireworkHandler : + public cItemThrowableHandler +{ + typedef cItemThrowableHandler super; +public: + cItemFireworkHandler(void) : + super(E_ITEM_FIREWORK_ROCKET, cProjectileEntity::pkFirework, 0) + { + } + + 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_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) + { + return false; + } + + if (!a_Player->IsGameModeCreative()) + { + a_Player->GetInventory().RemoveOneEquippedItem(); + } + + a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, 0); + + return true; + } + +};
\ No newline at end of file |