diff options
Diffstat (limited to 'src/Items')
40 files changed, 687 insertions, 185 deletions
diff --git a/src/Items/CMakeLists.txt b/src/Items/CMakeLists.txt index a6fe6ea70..12a467672 100644 --- a/src/Items/CMakeLists.txt +++ b/src/Items/CMakeLists.txt @@ -4,9 +4,53 @@ project (MCServer) include_directories ("${PROJECT_SOURCE_DIR}/../") -file(GLOB SOURCE - "*.cpp" - "*.h" -) +SET (SRCS + ItemHandler.cpp) -add_library(Items ${SOURCE}) +SET (HDRS + ItemArmor.h + ItemBed.h + ItemBoat.h + ItemBow.h + ItemBrewingStand.h + ItemBucket.h + ItemCake.h + ItemCauldron.h + ItemCloth.h + ItemComparator.h + ItemDoor.h + ItemDye.h + ItemEmptyMap.h + ItemFishingRod.h + ItemFlowerPot.h + ItemFood.h + ItemHandler.h + ItemHoe.h + ItemItemFrame.h + ItemLeaves.h + ItemLighter.h + ItemLilypad.h + ItemMap.h + ItemMilk.h + ItemMinecart.h + ItemMobHead.h + ItemNetherWart.h + ItemPainting.h + ItemPickaxe.h + ItemPotion.h + ItemRedstoneDust.h + ItemRedstoneRepeater.h + ItemSapling.h + ItemSeeds.h + ItemShears.h + ItemShovel.h + ItemSign.h + ItemSpawnEgg.h + ItemString.h + ItemSugarcane.h + ItemSword.h + ItemThrowable.h) + +if(NOT MSVC) + add_library(Items ${SRCS} ${HDRS}) +endif() diff --git a/src/Items/ItemArmor.h b/src/Items/ItemArmor.h index 08cddb1ad..2436df5bd 100644 --- a/src/Items/ItemArmor.h +++ b/src/Items/ItemArmor.h @@ -60,6 +60,49 @@ public: return true; } + virtual bool CanRepairWithRawMaterial(short a_ItemType) override + { + switch (m_ItemType) + { + case E_ITEM_CHAIN_BOOTS: + case E_ITEM_CHAIN_CHESTPLATE: + case E_ITEM_CHAIN_HELMET: + case E_ITEM_CHAIN_LEGGINGS: + { + return (a_ItemType == E_ITEM_IRON); + } + case E_ITEM_DIAMOND_BOOTS: + case E_ITEM_DIAMOND_CHESTPLATE: + case E_ITEM_DIAMOND_HELMET: + case E_ITEM_DIAMOND_LEGGINGS: + { + return (a_ItemType == E_ITEM_DIAMOND); + } + case E_ITEM_IRON_BOOTS: + case E_ITEM_IRON_CHESTPLATE: + case E_ITEM_IRON_HELMET: + case E_ITEM_IRON_LEGGINGS: + { + return (a_ItemType == E_ITEM_IRON); + } + case E_ITEM_GOLD_BOOTS: + case E_ITEM_GOLD_CHESTPLATE: + case E_ITEM_GOLD_HELMET: + case E_ITEM_GOLD_LEGGINGS: + { + return (a_ItemType == E_ITEM_GOLD); + } + case E_ITEM_LEATHER_BOOTS: + case E_ITEM_LEATHER_CAP: + case E_ITEM_LEATHER_PANTS: + case E_ITEM_LEATHER_TUNIC: + { + return (a_ItemType == E_ITEM_LEATHER); + } + } + return false; + } + } ; diff --git a/src/Items/ItemBed.h b/src/Items/ItemBed.h index f23d69731..94a14cf16 100644 --- a/src/Items/ItemBed.h +++ b/src/Items/ItemBed.h @@ -26,7 +26,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemBoat.h b/src/Items/ItemBoat.h index 42f4ffc8f..7faac1e32 100644 --- a/src/Items/ItemBoat.h +++ b/src/Items/ItemBoat.h @@ -75,7 +75,7 @@ public: double z = Callbacks.m_Pos.z; cBoat * Boat = new cBoat(x + 0.5, y + 1, z + 0.5); - Boat->Initialize(a_World); + Boat->Initialize(*a_World); return true; } diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h index 8c0b3a0a3..e7a77dcbc 100644 --- a/src/Items/ItemBow.h +++ b/src/Items/ItemBow.h @@ -46,34 +46,31 @@ public: { // 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 + double Force = (double)BowCharge / 20.0; + Force = (Force * Force + 2.0 * Force) / 3.0; // 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; - } - + Force = std::min(Force, 1.0); + // Create the arrow entity: cArrowEntity * Arrow = new cArrowEntity(*a_Player, Force * 2); if (Arrow == NULL) { return; } - if (!Arrow->Initialize(a_Player->GetWorld())) + if (!Arrow->Initialize(*a_Player->GetWorld())) { delete Arrow; + Arrow = NULL; 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); + a_Player->GetWorld()->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY(), a_Player->GetPosZ(), 0.5, (float)Force); if (!a_Player->IsGameModeCreative()) { a_Player->UseEquippedItem(); diff --git a/src/Items/ItemBrewingStand.h b/src/Items/ItemBrewingStand.h index d5eefb855..7be57763c 100644 --- a/src/Items/ItemBrewingStand.h +++ b/src/Items/ItemBrewingStand.h @@ -25,7 +25,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemBucket.h b/src/Items/ItemBucket.h index 68c89dd85..a17c4838b 100644 --- a/src/Items/ItemBucket.h +++ b/src/Items/ItemBucket.h @@ -41,7 +41,7 @@ public: 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) + if (a_BlockFace != BLOCK_FACE_NONE) { return false; } @@ -49,7 +49,7 @@ public: Vector3i BlockPos; if (!GetBlockFromTrace(a_World, a_Player, BlockPos)) { - return false; // Nothing in range. + return false; // Nothing in range. } if (a_World->GetBlockMeta(BlockPos.x, BlockPos.y, BlockPos.z) != 0) @@ -94,30 +94,16 @@ public: bool PlaceFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_FluidBlock) - { - if (a_BlockFace < 0) + { + if (a_BlockFace != BLOCK_FACE_NONE) { return false; } - BLOCKTYPE CurrentBlock = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - bool CanWashAway = cFluidSimulator::CanWashAway(CurrentBlock); - if (!CanWashAway) + BLOCKTYPE CurrentBlock; + Vector3i BlockPos; + if (!GetPlacementCoordsFromTrace(a_World, a_Player, BlockPos, CurrentBlock)) { - // 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; } @@ -131,14 +117,14 @@ public: return false; } cItem Item(E_ITEM_BUCKET, 1); - if (!a_Player->GetInventory().AddItem(Item,true,true)) + if (!a_Player->GetInventory().AddItem(Item, true, true)) { return false; } } // Wash away anything that was there prior to placing: - if (CanWashAway) + if (cFluidSimulator::CanWashAway(CurrentBlock)) { cBlockHandler * Handler = BlockHandler(CurrentBlock); if (Handler->DoesDropOnUnsuitable()) @@ -149,13 +135,13 @@ public: } } - a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_FluidBlock, 0); + a_World->SetBlock(BlockPos.x, BlockPos.y, BlockPos.z, a_FluidBlock, 0); return true; } - bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & BlockPos) + bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos) { class cCallbacks : public cBlockTracer::cCallbacks @@ -174,7 +160,7 @@ public: { if (IsBlockWater(a_BlockType) || IsBlockLava(a_BlockType)) { - if (a_BlockMeta != 0) // GetBlockFromTrace is called for scooping up fluids; the hit block should be a source + if (a_BlockMeta != 0) // GetBlockFromTrace is called for scooping up fluids; the hit block should be a source { return false; } @@ -198,8 +184,49 @@ public: } - BlockPos.Set(Callbacks.m_Pos.x, Callbacks.m_Pos.y, Callbacks.m_Pos.z); + a_BlockPos = Callbacks.m_Pos; return true; } + + + bool GetPlacementCoordsFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos, BLOCKTYPE & a_BlockType) + { + class cCallbacks : + public cBlockTracer::cCallbacks + { + public: + Vector3i m_Pos; + BLOCKTYPE m_ReplacedBlock; + + virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override + { + if (a_BlockType != E_BLOCK_AIR) + { + m_ReplacedBlock = a_BlockType; + if (!cFluidSimulator::CanWashAway(a_BlockType) && !IsBlockLiquid(a_BlockType)) + { + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, (eBlockFace)a_EntryFace); // Was an unwashawayable block, can't overwrite it! + } + m_Pos.Set(a_BlockX, a_BlockY, a_BlockZ); // (Block could be washed away, replace it) + return true; // Abort tracing + } + return false; + } + } Callbacks; + cLineBlockTracer Tracer(*a_World, Callbacks); + Vector3d Start(a_Player->GetEyePosition()); + Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5); + + // cTracer::Trace returns true when whole line was traversed. By returning true when we hit something, we ensure that this never happens if liquid could be placed + // Use this to judge whether the position is valid + if (!Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z)) + { + a_BlockPos = Callbacks.m_Pos; + a_BlockType = Callbacks.m_ReplacedBlock; + return true; + } + + return false; + } }; diff --git a/src/Items/ItemCake.h b/src/Items/ItemCake.h index 48e23ed59..d1cb091b6 100644 --- a/src/Items/ItemCake.h +++ b/src/Items/ItemCake.h @@ -25,7 +25,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemCauldron.h b/src/Items/ItemCauldron.h index 07ae12660..9617c30ef 100644 --- a/src/Items/ItemCauldron.h +++ b/src/Items/ItemCauldron.h @@ -25,7 +25,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemComparator.h b/src/Items/ItemComparator.h index 60d9c3648..fc843c186 100644 --- a/src/Items/ItemComparator.h +++ b/src/Items/ItemComparator.h @@ -24,7 +24,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemDoor.h b/src/Items/ItemDoor.h index f3677c28c..c1b439024 100644 --- a/src/Items/ItemDoor.h +++ b/src/Items/ItemDoor.h @@ -25,7 +25,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override @@ -33,8 +33,8 @@ public: a_BlockType = (m_ItemType == E_ITEM_WOODEN_DOOR) ? E_BLOCK_WOODEN_DOOR : E_BLOCK_IRON_DOOR; cChunkInterface ChunkInterface(a_World->GetChunkMap()); bool Meta = BlockHandler(a_BlockType)->GetPlacementBlockTypeMeta( - ChunkInterface, a_Player, - a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, + ChunkInterface, 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/ItemFishingRod.h b/src/Items/ItemFishingRod.h index 0431b88b7..6350a38ba 100644 --- a/src/Items/ItemFishingRod.h +++ b/src/Items/ItemFishingRod.h @@ -17,13 +17,15 @@ -///////////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// // cFloaterCallback class cFloaterCallback : public cEntityCallback { public: - cFloaterCallback(void) : + cFloaterCallback(void) : m_CanPickup(false), m_AttachedMobID(-1) { @@ -49,14 +51,19 @@ protected: Vector3d m_Pos; } ; -//////////////////////////////////////////////////////////////////////////// -// cSweepEntityCallback + + + + +//////////////////////////////////////////////////////////////////////////////// +// cSweepEntityCallback: + class cSweepEntityCallback : public cEntityCallback { public: cSweepEntityCallback(Vector3d a_PlayerPos) : - m_PlayerPos(a_PlayerPos) + m_PlayerPos(a_PlayerPos) { } @@ -73,6 +80,8 @@ protected: + + class cItemFishingRodHandler : public cItemHandler { @@ -106,19 +115,19 @@ public: { cItems Drops; int ItemCategory = a_World->GetTickRandomNumber(99); - if (ItemCategory <= 4) // Treasures 5% + if (ItemCategory <= 4) // Treasures 5% { int Treasure = a_World->GetTickRandomNumber(5); switch (Treasure) { case 0: { - Drops.Add(cItem(E_ITEM_BOW)); // TODO: Enchantments + Drops.Add(cItem(E_ITEM_BOW)); // TODO: Enchantments break; } case 1: { - Drops.Add(cItem(E_ITEM_BOOK)); // TODO: Enchanted book + Drops.Add(cItem(E_ITEM_BOOK)); // TODO: Enchanted book break; } case 2: @@ -142,6 +151,8 @@ public: break; } } + + a_Player->GetStatManager().AddValue(statTreasureFished, 1); } else if (ItemCategory <= 14) // Junk 10% { @@ -190,6 +201,8 @@ public: { Drops.Add(cItem(E_BLOCK_TRIPWIRE_HOOK)); } + + a_Player->GetStatManager().AddValue(statJunkFished, 1); } else // Fish { @@ -197,7 +210,7 @@ public: if (FishType <= 1) // Clownfish has a 2% chance of spawning { Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_CLOWNFISH)); - } + } else if (FishType <= 12) // Pufferfish has a 13% chance of spawning { Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_CLOWNFISH)); @@ -210,6 +223,8 @@ public: { Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_FISH)); } + + a_Player->GetStatManager().AddValue(statFishCaught, 1); } if (cRoot::Get()->GetPluginManager()->CallHookPlayerFishing(*a_Player, Drops)) @@ -225,9 +240,13 @@ public: else { cFloater * Floater = new cFloater(a_Player->GetPosX(), a_Player->GetStance(), a_Player->GetPosZ(), a_Player->GetLookVector() * 15, a_Player->GetUniqueID(), 100 + a_World->GetTickRandomNumber(800) - (a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchLure) * 100)); - Floater->Initialize(a_World); + Floater->Initialize(*a_World); a_Player->SetIsFishing(true, Floater->GetUniqueID()); } return true; } } ; + + + + diff --git a/src/Items/ItemFlowerPot.h b/src/Items/ItemFlowerPot.h index 60bf87985..320dce997 100644 --- a/src/Items/ItemFlowerPot.h +++ b/src/Items/ItemFlowerPot.h @@ -25,7 +25,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemFood.h b/src/Items/ItemFood.h index 961cf482d..ff1d7991b 100644 --- a/src/Items/ItemFood.h +++ b/src/Items/ItemFood.h @@ -26,7 +26,7 @@ public: virtual FoodInfo GetFoodInfo(void) override { - switch(m_ItemType) + switch (m_ItemType) { // Please keep alpha-sorted. case E_ITEM_BAKED_POTATO: return FoodInfo(6, 7.2); diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index ce9593a70..d36b5d663 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -19,6 +19,7 @@ #include "ItemCloth.h" #include "ItemComparator.h" #include "ItemDoor.h" +#include "ItemMilk.h" #include "ItemDye.h" #include "ItemEmptyMap.h" #include "ItemFishingRod.h" @@ -34,6 +35,7 @@ #include "ItemNetherWart.h" #include "ItemPainting.h" #include "ItemPickaxe.h" +#include "ItemPotion.h" #include "ItemThrowable.h" #include "ItemRedstoneDust.h" #include "ItemRedstoneRepeater.h" @@ -44,6 +46,7 @@ #include "ItemSign.h" #include "ItemMobHead.h" #include "ItemSpawnEgg.h" +#include "ItemString.h" #include "ItemSugarcane.h" #include "ItemSword.h" @@ -62,7 +65,7 @@ cItemHandler * cItemHandler::m_ItemHandler[2268]; cItemHandler * cItemHandler::GetItemHandler(int a_ItemType) { - if (a_ItemType < 0) + if ((a_ItemType < 0) || ((unsigned long)a_ItemType >= ARRAYCOUNT(m_ItemHandler))) { // Either nothing (-1), or bad value, both cases should return the air handler if (a_ItemType < -1) @@ -91,7 +94,7 @@ cItemHandler * cItemHandler::GetItemHandler(int a_ItemType) cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) { - switch(a_ItemType) + switch (a_ItemType) { default: return new cItemHandler(a_ItemType); @@ -119,9 +122,11 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType); case E_BLOCK_LILY_PAD: return new cItemLilypadHandler(a_ItemType); case E_ITEM_MAP: return new cItemMapHandler(); + case E_ITEM_MILK: return new cItemMilkHandler(); case E_ITEM_ITEM_FRAME: return new cItemItemFrameHandler(a_ItemType); case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType); case E_ITEM_PAINTING: return new cItemPaintingHandler(a_ItemType); + case E_ITEM_POTIONS: return new cItemPotionHandler(); 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); @@ -129,6 +134,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_ITEM_HEAD: return new cItemMobHeadHandler(a_ItemType); case E_ITEM_SNOWBALL: return new cItemSnowballHandler(); case E_ITEM_SPAWN_EGG: return new cItemSpawnEggHandler(a_ItemType); + case E_ITEM_STRING: return new cItemStringHandler(a_ItemType); case E_ITEM_SUGARCANE: return new cItemSugarcaneHandler(a_ItemType); case E_ITEM_WOODEN_HOE: @@ -257,9 +263,10 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) void cItemHandler::Deinit() { - for(int i = 0; i < 2267; i++) + for (int i = 0; i < 2267; i++) { delete m_ItemHandler[i]; + m_ItemHandler[i] = NULL; } memset(m_ItemHandler, 0, sizeof(m_ItemHandler)); // Don't leave any dangling pointers around, just in case m_HandlerInitialized = false; @@ -321,15 +328,25 @@ void cItemHandler::OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const if (a_Player->IsGameModeSurvival()) { - if (!BlockRequiresSpecialTool(Block) || CanHarvestBlock(Block)) - { - cChunkInterface ChunkInterface(a_World->GetChunkMap()); - cBlockInServerPluginInterface PluginInterface(*a_World); - Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ); - } + cChunkInterface ChunkInterface(a_World->GetChunkMap()); + cBlockInServerPluginInterface PluginInterface(*a_World); + Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ, CanHarvestBlock(Block), a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0); } - - a_Player->UseEquippedItem(); + + if (!cBlockInfo::IsOneHitDig(Block)) + { + a_Player->UseEquippedItem(GetDurabilityLossByAction(dlaBreakBlock)); + } +} + + + + + +void cItemHandler::OnEntityAttack(cPlayer * a_Attacker, cEntity * a_AttackedEntity) +{ + UNUSED(a_AttackedEntity); + a_Attacker->UseEquippedItem(GetDurabilityLossByAction(dlaAttackEntity)); } @@ -347,6 +364,20 @@ void cItemHandler::OnFoodEaten(cWorld * a_World, cPlayer * a_Player, cItem * a_I +short cItemHandler::GetDurabilityLossByAction(eDurabilityLostAction a_Action) +{ + switch ((int)a_Action) + { + case dlaAttackEntity: return 2; + case dlaBreakBlock: return 1; + } + return 0; +} + + + + + char cItemHandler::GetMaxStackSize(void) { if (m_ItemType < 256) @@ -355,7 +386,7 @@ char cItemHandler::GetMaxStackSize(void) return 64; } - switch (m_ItemType) //sorted by id + switch (m_ItemType) { case E_ITEM_ARROW: return 64; case E_ITEM_BAKED_POTATO: return 64; @@ -451,14 +482,14 @@ char cItemHandler::GetMaxStackSize(void) 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 == 325) - || (m_ItemType == 346); + 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 == 325) || + (m_ItemType == 346); } @@ -467,33 +498,17 @@ bool cItemHandler::IsTool() 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::IsDrinkable(short a_ItemDamage) +{ + UNUSED(a_ItemDamage); + return false; } @@ -511,10 +526,10 @@ bool cItemHandler::IsPlaceable(void) -bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType) + +bool cItemHandler::CanRepairWithRawMaterial(short a_ItemType) { - UNUSED(a_BlockType); - + UNUSED(a_ItemType); return false; } @@ -522,9 +537,61 @@ bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType) +bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType) +{ + switch (a_BlockType) + { + case E_BLOCK_ANVIL: + case E_BLOCK_ENCHANTMENT_TABLE: + case E_BLOCK_FURNACE: + case E_BLOCK_LIT_FURNACE: + 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_COBBLESTONE_WALL: + case E_BLOCK_STONE_BRICK_STAIRS: + case E_BLOCK_NETHER_BRICK_STAIRS: + case E_BLOCK_CAULDRON: + case E_BLOCK_OBSIDIAN: + 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: + case E_BLOCK_IRON_BLOCK: + case E_BLOCK_IRON_ORE: + case E_BLOCK_LAPIS_ORE: + case E_BLOCK_LAPIS_BLOCK: + case E_BLOCK_SNOW: + case E_BLOCK_VINES: + { + return false; + } + default: return true; + } +} + + + + + bool cItemHandler::GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) @@ -541,7 +608,7 @@ bool cItemHandler::GetPlacementBlockTypeMeta( cChunkInterface ChunkInterface(a_World->GetChunkMap()); return BlockH->GetPlacementBlockTypeMeta( ChunkInterface, a_Player, - a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, + a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta ); @@ -567,7 +634,7 @@ bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item) cFastRandom r1; if ((r1.NextInt(100, a_Player->GetUniqueID()) - Info.PoisonChance) <= 0) { - a_Player->FoodPoison(300); + a_Player->FoodPoison(600); // Give the player food poisoning for 30 seconds. } } diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index 4993eac85..1d5f59f3e 100644 --- a/src/Items/ItemHandler.h +++ b/src/Items/ItemHandler.h @@ -19,6 +19,13 @@ class cPlayer; class cItemHandler { public: + + enum eDurabilityLostAction + { + dlaBreakBlock, + dlaAttackEntity, + }; + cItemHandler(int a_ItemType); /** Force virtual destructor */ @@ -28,7 +35,7 @@ public: virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir); /** Called when the client sends the SHOOT status in the lclk packet */ - virtual void OnItemShoot(cPlayer *, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) + virtual void OnItemShoot(cPlayer *, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) { UNUSED(a_BlockX); UNUSED(a_BlockY); @@ -48,11 +55,17 @@ public: virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace 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); + virtual void OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ); + + /** Called when a player attacks a other entity. */ + virtual void OnEntityAttack(cPlayer * a_Attacker, cEntity * a_AttackedEntity); /** Called after the player has eaten this item. */ virtual void OnFoodEaten(cWorld *a_World, cPlayer *a_Player, cItem *a_Item); - + + /** Get the durability lost which the item will get, when a specified action was performed. */ + virtual short GetDurabilityLossByAction(eDurabilityLostAction a_Action); + /** Returns the maximum stack size for a given item */ virtual char GetMaxStackSize(void); @@ -60,7 +73,7 @@ public: { double Saturation; int FoodLevel; - int PoisonChance; // 0 - 100, in percent. 0 = no chance of poisoning, 100 = sure poisoning + 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) : Saturation(a_Saturation), @@ -82,21 +95,27 @@ public: /** Indicates if this item is food */ virtual bool IsFood(void); + /** Indicates if this item is drinkable */ + virtual bool IsDrinkable(short a_ItemDamage); + /** Blocks simply get placed */ virtual bool IsPlaceable(void); - /** Called before a block is placed into a world. + /** Can the anvil repair this item, when a_Item is the second input? */ + virtual bool CanRepairWithRawMaterial(short a_ItemType); + + /** 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, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace 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 */ + /** 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); @@ -106,11 +125,11 @@ public: protected: int m_ItemType; - static cItemHandler *CreateItemHandler(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 + static bool m_HandlerInitialized; // used to detect if the itemhandlers are initialized }; -//Short function +// 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 index 29f7c83d5..8d0b71478 100644 --- a/src/Items/ItemHoe.h +++ b/src/Items/ItemHoe.h @@ -16,7 +16,6 @@ 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, eBlockFace a_Dir) override @@ -26,13 +25,18 @@ public: 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; } + + + virtual short GetDurabilityLossByAction(eDurabilityLostAction a_Action) override + { + return 0; + } } ; diff --git a/src/Items/ItemItemFrame.h b/src/Items/ItemItemFrame.h index 27e7dba35..87e20ecf0 100644 --- a/src/Items/ItemItemFrame.h +++ b/src/Items/ItemItemFrame.h @@ -27,16 +27,17 @@ public: return false; } - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir); // Make sure block that will be occupied is free + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir); // Make sure block that will be occupied is free BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir, true); // We want the clicked block, so go back again + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir, true); // We want the clicked block, so go back again if (Block == E_BLOCK_AIR) { cItemFrame * ItemFrame = new cItemFrame(a_Dir, a_BlockX, a_BlockY, a_BlockZ); - if (!ItemFrame->Initialize(a_World)) + if (!ItemFrame->Initialize(*a_World)) { delete ItemFrame; + ItemFrame = NULL; return false; } diff --git a/src/Items/ItemLeaves.h b/src/Items/ItemLeaves.h index 12cb45d1c..f48126dc5 100644 --- a/src/Items/ItemLeaves.h +++ b/src/Items/ItemLeaves.h @@ -20,7 +20,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override @@ -31,7 +31,7 @@ public: 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 + 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 index 32f49cab6..9f98bf85f 100644 --- a/src/Items/ItemLighter.h +++ b/src/Items/ItemLighter.h @@ -52,8 +52,8 @@ public: case E_BLOCK_TNT: { // Activate the TNT: - a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 1.0f); - a_World->SetBlock(a_BlockX,a_BlockY,a_BlockZ, E_BLOCK_AIR, 0); + a_World->BroadcastSoundEffect("game.tnt.primed", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 1.0f); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom break; } @@ -68,7 +68,7 @@ public: 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); - a_World->BroadcastSoundEffect("fire.ignite", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0F, 1.04F); + a_World->BroadcastSoundEffect("fire.ignite", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0F, 1.04F); break; } } diff --git a/src/Items/ItemLilypad.h b/src/Items/ItemLilypad.h index 8fc1d8543..b9d837384 100644 --- a/src/Items/ItemLilypad.h +++ b/src/Items/ItemLilypad.h @@ -25,7 +25,7 @@ public: virtual bool IsPlaceable(void) override { - return false; // Set as not placeable so OnItemUse is called + return false; // Set as not placeable so OnItemUse is called } @@ -47,9 +47,9 @@ public: public cBlockTracer::cCallbacks { public: - cCallbacks(cWorld * a_CBWorld) : - m_HasHitFluid(false), - m_World(a_CBWorld) + + cCallbacks(void) : + m_HasHitFluid(false) { } @@ -57,15 +57,14 @@ public: { if (IsBlockWater(a_CBBlockType)) { - if ((a_CBBlockMeta != 0) || (a_CBEntryFace == BLOCK_FACE_NONE)) // The hit block should be a source. The FACE_NONE check is clicking whilst submerged + if ((a_CBBlockMeta != 0) || (a_CBEntryFace == BLOCK_FACE_NONE)) // The hit block should be a source. The FACE_NONE check is clicking whilst submerged { return false; } AddFaceDirection(a_CBBlockX, a_CBBlockY, a_CBBlockZ, BLOCK_FACE_YP); // Always place pad at top of water block - BLOCKTYPE Block = m_World->GetBlock(a_CBBlockX, a_CBBlockY, a_CBBlockZ); if ( - !IsBlockWater(Block) && - cBlockInfo::FullyOccupiesVoxel(Block) + !IsBlockWater(a_CBBlockType) && + cBlockInfo::FullyOccupiesVoxel(a_CBBlockType) ) { // Can't place lilypad on air/in another block! @@ -80,11 +79,10 @@ public: Vector3i m_Pos; bool m_HasHitFluid; - cWorld * m_World; }; - cCallbacks Callbacks(a_World); + cCallbacks Callbacks; cLineBlockTracer Tracer(*a_Player->GetWorld(), Callbacks); Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector()); Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5); diff --git a/src/Items/ItemMilk.h b/src/Items/ItemMilk.h new file mode 100644 index 000000000..db7bc13be --- /dev/null +++ b/src/Items/ItemMilk.h @@ -0,0 +1,28 @@ + +#pragma once + +class cItemMilkHandler: + public cItemHandler +{ + typedef cItemHandler super; +public: + cItemMilkHandler(): + super(E_ITEM_MILK) + { + } + + virtual bool IsDrinkable(short a_ItemDamage) override + { + UNUSED(a_ItemDamage); + return true; + } + + virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override + { + UNUSED(a_Item); + a_Player->ClearEntityEffects(); + a_Player->GetInventory().RemoveOneEquippedItem(); + a_Player->GetInventory().AddItem(E_ITEM_BUCKET); + return true; + } +}; diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h index 25500aeb9..63038de51 100644 --- a/src/Items/ItemMinecart.h +++ b/src/Items/ItemMinecart.h @@ -70,7 +70,7 @@ public: return false; } } // switch (m_ItemType) - Minecart->Initialize(a_World); + Minecart->Initialize(*a_World); if (!a_Player->IsGameModeCreative()) { @@ -78,7 +78,7 @@ public: } return true; } - + } ; diff --git a/src/Items/ItemMobHead.h b/src/Items/ItemMobHead.h index 5ae040282..4c36fe8d8 100644 --- a/src/Items/ItemMobHead.h +++ b/src/Items/ItemMobHead.h @@ -26,7 +26,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemNetherWart.h b/src/Items/ItemNetherWart.h index a6a9a286a..10a0864b5 100644 --- a/src/Items/ItemNetherWart.h +++ b/src/Items/ItemNetherWart.h @@ -25,7 +25,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemPainting.h b/src/Items/ItemPainting.h index b85098221..a2a77ce21 100644 --- a/src/Items/ItemPainting.h +++ b/src/Items/ItemPainting.h @@ -27,9 +27,9 @@ public: return false; } - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir); // Make sure block that will be occupied is free + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir); // Make sure block that will be occupied is free BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir, true); // We want the clicked block, so go back again + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_Dir, true); // We want the clicked block, so go back again if (Block == E_BLOCK_AIR) { @@ -38,14 +38,14 @@ public: // The client uses different values for painting directions and block faces. Our constants are for the block faces, so we convert them here to painting faces switch (a_Dir) { - case BLOCK_FACE_ZP: break; // Initialised to zero + case BLOCK_FACE_ZP: break; // Initialised to zero case BLOCK_FACE_ZM: Dir = 2; break; case BLOCK_FACE_XM: Dir = 1; break; case BLOCK_FACE_XP: Dir = 3; break; default: ASSERT(!"Unhandled block face when trying spawn painting!"); return false; } - static const struct // Define all the possible painting titles + static const struct // Define all the possible painting titles { AString Title; } gPaintingTitlesList[] = @@ -79,7 +79,7 @@ public: }; cPainting * Painting = new cPainting(gPaintingTitlesList[a_World->GetTickRandomNumber(ARRAYCOUNT(gPaintingTitlesList) - 1)].Title, Dir, a_BlockX, a_BlockY, a_BlockZ); - Painting->Initialize(a_World); + Painting->Initialize(*a_World); if (!a_Player->IsGameModeCreative()) { diff --git a/src/Items/ItemPickaxe.h b/src/Items/ItemPickaxe.h index 2a8e40daa..17fd96822 100644 --- a/src/Items/ItemPickaxe.h +++ b/src/Items/ItemPickaxe.h @@ -8,6 +8,7 @@ class cItemPickaxeHandler : public cItemHandler { + typedef cItemHandler super; public: cItemPickaxeHandler(int a_ItemType) : cItemHandler(a_ItemType) @@ -17,7 +18,7 @@ public: char PickaxeLevel() { - switch(m_ItemType) + switch (m_ItemType) { case E_ITEM_WOODEN_PICKAXE: return 1; case E_ITEM_GOLD_PICKAXE: return 1; @@ -31,7 +32,7 @@ public: virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType) override { - switch(a_BlockType) + switch (a_BlockType) { case E_BLOCK_OBSIDIAN: { @@ -76,6 +77,7 @@ public: case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_BRICK: case E_BLOCK_COBBLESTONE_STAIRS: + case E_BLOCK_COBBLESTONE_WALL: case E_BLOCK_STONE_BRICK_STAIRS: case E_BLOCK_NETHER_BRICK_STAIRS: case E_BLOCK_CAULDRON: @@ -83,6 +85,19 @@ public: return PickaxeLevel() >= 1; } } + return super::CanHarvestBlock(a_BlockType); + } + + virtual bool CanRepairWithRawMaterial(short a_ItemType) override + { + switch (m_ItemType) + { + case E_ITEM_WOODEN_PICKAXE: return (a_ItemType == E_BLOCK_PLANKS); + case E_ITEM_STONE_PICKAXE: return (a_ItemType == E_BLOCK_COBBLESTONE); + case E_ITEM_IRON_PICKAXE: return (a_ItemType == E_ITEM_IRON); + case E_ITEM_GOLD_PICKAXE: return (a_ItemType == E_ITEM_GOLD); + case E_ITEM_DIAMOND_PICKAXE: return (a_ItemType == E_ITEM_DIAMOND); + } return false; } } ; diff --git a/src/Items/ItemPotion.h b/src/Items/ItemPotion.h new file mode 100644 index 000000000..24614cd8a --- /dev/null +++ b/src/Items/ItemPotion.h @@ -0,0 +1,79 @@ + +#pragma once + +#include "../Entities/EntityEffect.h" +#include "../Entities/SplashPotionEntity.h" + +class cItemPotionHandler: + public cItemHandler +{ + typedef cItemHandler super; + +public: + + cItemPotionHandler(): + super(E_ITEM_POTION) + { + } + + + // cItemHandler overrides: + virtual bool IsDrinkable(short a_ItemDamage) override + { + // Drinkable potion if 13th lowest bit is set + // Ref.: http://minecraft.gamepedia.com/Potions#Data_value_table + return cEntityEffect::IsPotionDrinkable(a_ItemDamage); + } + + + virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override + { + short PotionDamage = a_Item.m_ItemDamage; + + // Do not throw non-splash potions: + if (cEntityEffect::IsPotionDrinkable(PotionDamage)) + { + return false; + } + + Vector3d Pos = a_Player->GetThrowStartPos(); + Vector3d Speed = a_Player->GetLookVector() * 7; + + if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, cProjectileEntity::pkSplashPotion, a_Player, &a_Player->GetEquippedItem(), &Speed) < 0) + { + return false; + } + + if (!a_Player->IsGameModeCreative()) + { + a_Player->GetInventory().RemoveOneEquippedItem(); + } + + return true; + } + + + virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override + { + short PotionDamage = a_Item->m_ItemDamage; + + // Do not drink undrinkable potions: + if (!cEntityEffect::IsPotionDrinkable(a_Item->m_ItemDamage)) + { + return false; + } + + a_Player->AddEntityEffect( + cEntityEffect::GetPotionEffectType(PotionDamage), + cEntityEffect::GetPotionEffectDuration(PotionDamage), + cEntityEffect::GetPotionEffectIntensity(PotionDamage) + ); + a_Player->GetInventory().RemoveOneEquippedItem(); + a_Player->GetInventory().AddItem(E_ITEM_GLASS_BOTTLE); + return true; + } +}; + + + + diff --git a/src/Items/ItemRedstoneDust.h b/src/Items/ItemRedstoneDust.h index 274d905a5..a2289239c 100644 --- a/src/Items/ItemRedstoneDust.h +++ b/src/Items/ItemRedstoneDust.h @@ -22,12 +22,12 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { - if (!cBlockInfo::FullyOccupiesVoxel(a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))) // Some solid blocks, such as cocoa beans, are not suitable for dust + if (!cBlockInfo::FullyOccupiesVoxel(a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))) // Some solid blocks, such as cocoa beans, are not suitable for dust { return false; } diff --git a/src/Items/ItemRedstoneRepeater.h b/src/Items/ItemRedstoneRepeater.h index c5fb5d566..13a797d00 100644 --- a/src/Items/ItemRedstoneRepeater.h +++ b/src/Items/ItemRedstoneRepeater.h @@ -24,7 +24,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemSapling.h b/src/Items/ItemSapling.h index 61b1a32be..dbcb12be5 100644 --- a/src/Items/ItemSapling.h +++ b/src/Items/ItemSapling.h @@ -20,7 +20,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemSeeds.h b/src/Items/ItemSeeds.h index 7283edcee..54a1183d7 100644 --- a/src/Items/ItemSeeds.h +++ b/src/Items/ItemSeeds.h @@ -25,12 +25,12 @@ public: virtual bool IsFood(void) override { - switch (m_ItemType) // Special cases, both a seed and food + switch (m_ItemType) // Special cases, both a seed and food { case E_ITEM_CARROT: case E_ITEM_POTATO: return true; default: return false; - } + } } virtual FoodInfo GetFoodInfo(void) override @@ -40,12 +40,12 @@ public: case E_ITEM_CARROT: return FoodInfo(4, 4.8); case E_ITEM_POTATO: return FoodInfo(1, 0.6); default: return FoodInfo(0, 0); - } + } } virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemShears.h b/src/Items/ItemShears.h index 39d2776fa..fa2794df2 100644 --- a/src/Items/ItemShears.h +++ b/src/Items/ItemShears.h @@ -12,6 +12,7 @@ class cItemShearsHandler : public cItemHandler { + typedef cItemHandler super; public: cItemShearsHandler(int a_ItemType) : cItemHandler(a_ItemType) @@ -30,8 +31,12 @@ public: BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); if ((Block == E_BLOCK_LEAVES) || (Block == E_BLOCK_NEW_LEAVES)) { + NIBBLETYPE Meta = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + cBlockHandler * Handler = cBlockInfo::GetHandler(Block); + cItems Drops; - Drops.push_back(cItem(Block, 1, a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x03)); + Handler->ConvertToPickups(Drops, Meta); + Drops.push_back(cItem(Block, 1, Meta & 3)); a_World->SpawnItemPickups(Drops, a_BlockX, a_BlockY, a_BlockZ); a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); @@ -54,7 +59,25 @@ public: return true; } } // switch (a_BlockType) - return false; + return super::CanHarvestBlock(a_BlockType); + } + + + virtual short GetDurabilityLossByAction(eDurabilityLostAction a_Action) override + { + return 0; + } + + + virtual void OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ) override + { + super::OnBlockDestroyed(a_World, a_Player, a_Item, a_BlockX, a_BlockY, a_BlockZ); + + BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ); + if ((Block == E_BLOCK_TRIPWIRE) || (Block == E_BLOCK_VINES)) + { + a_Player->UseEquippedItem(); + } } } ; diff --git a/src/Items/ItemShovel.h b/src/Items/ItemShovel.h index 873d5ae25..7d5760fa9 100644 --- a/src/Items/ItemShovel.h +++ b/src/Items/ItemShovel.h @@ -14,6 +14,7 @@ class cItemShovelHandler : public cItemHandler { + typedef cItemHandler super; public: cItemShovelHandler(int a_ItemType) : cItemHandler(a_ItemType) @@ -28,7 +29,7 @@ public: { cChunkInterface ChunkInterface(a_World->GetChunkMap()); cBlockInServerPluginInterface PluginInterface(*a_World); - BlockHandler(Block)->DropBlock(ChunkInterface,*a_World, PluginInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ); + BlockHandler(Block)->DropBlock(ChunkInterface, *a_World, PluginInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ); a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); a_Player->UseEquippedItem(); @@ -39,6 +40,24 @@ public: virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType) override { - return (a_BlockType == E_BLOCK_SNOW); + if (a_BlockType == E_BLOCK_SNOW) + { + return true; + } + return super::CanHarvestBlock(a_BlockType); + } + + virtual bool CanRepairWithRawMaterial(short a_ItemType) override + { + switch (m_ItemType) + { + case E_ITEM_WOODEN_SHOVEL: return (a_ItemType == E_BLOCK_PLANKS); + case E_ITEM_STONE_SHOVEL: return (a_ItemType == E_BLOCK_COBBLESTONE); + case E_ITEM_IRON_SHOVEL: return (a_ItemType == E_ITEM_IRON); + case E_ITEM_GOLD_SHOVEL: return (a_ItemType == E_ITEM_GOLD); + case E_ITEM_DIAMOND_SHOVEL: return (a_ItemType == E_ITEM_DIAMOND); + } + return false; } + }; diff --git a/src/Items/ItemSign.h b/src/Items/ItemSign.h index 60cf0f5f8..0fa0fa0be 100644 --- a/src/Items/ItemSign.h +++ b/src/Items/ItemSign.h @@ -3,7 +3,8 @@ #include "ItemHandler.h" #include "../World.h" -#include "../Blocks/BlockSign.h" +#include "../Blocks/BlockSignPost.h" +#include "../Blocks/BlockWallSign.h" @@ -27,19 +28,19 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace 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->GetYaw()); + a_BlockMeta = cBlockSignPostHandler::RotationToMetaData(a_Player->GetYaw()); a_BlockType = E_BLOCK_SIGN_POST; } else { - a_BlockMeta = cBlockSignHandler::DirectionToMetaData(a_BlockFace); + a_BlockMeta = cBlockWallSignHandler::DirectionToMetaData(a_BlockFace); a_BlockType = E_BLOCK_WALLSIGN; } return true; diff --git a/src/Items/ItemSpawnEgg.h b/src/Items/ItemSpawnEgg.h index 0d6019398..bba97afa1 100644 --- a/src/Items/ItemSpawnEgg.h +++ b/src/Items/ItemSpawnEgg.h @@ -33,7 +33,10 @@ public: a_BlockY--; } - if (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, (cMonster::eType)(a_Item.m_ItemDamage)) >= 0) + cMonster::eType MonsterType = ItemDamageToMonsterType(a_Item.m_ItemDamage); + if ( + (MonsterType != cMonster::mtInvalidType) && // Valid monster type + (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, MonsterType) >= 0)) // Spawning succeeded { if (!a_Player->IsGameModeCreative()) { @@ -45,6 +48,41 @@ public: return false; } + + + /** Converts the Spawn egg item damage to the monster type to spawn. + Returns mtInvalidType for invalid damage values. */ + static cMonster::eType ItemDamageToMonsterType(short a_ItemDamage) + { + switch (a_ItemDamage) + { + case E_META_SPAWN_EGG_BAT: return cMonster::mtBat; + case E_META_SPAWN_EGG_BLAZE: return cMonster::mtBlaze; + case E_META_SPAWN_EGG_CAVE_SPIDER: return cMonster::mtCaveSpider; + case E_META_SPAWN_EGG_CHICKEN: return cMonster::mtChicken; + case E_META_SPAWN_EGG_COW: return cMonster::mtCow; + case E_META_SPAWN_EGG_CREEPER: return cMonster::mtCreeper; + case E_META_SPAWN_EGG_ENDERMAN: return cMonster::mtEnderman; + case E_META_SPAWN_EGG_GHAST: return cMonster::mtGhast; + case E_META_SPAWN_EGG_HORSE: return cMonster::mtHorse; + case E_META_SPAWN_EGG_MAGMA_CUBE: return cMonster::mtMagmaCube; + case E_META_SPAWN_EGG_MOOSHROOM: return cMonster::mtMooshroom; + case E_META_SPAWN_EGG_OCELOT: return cMonster::mtOcelot; + case E_META_SPAWN_EGG_PIG: return cMonster::mtPig; + case E_META_SPAWN_EGG_SHEEP: return cMonster::mtSheep; + case E_META_SPAWN_EGG_SILVERFISH: return cMonster::mtSilverfish; + case E_META_SPAWN_EGG_SKELETON: return cMonster::mtSkeleton; + case E_META_SPAWN_EGG_SLIME: return cMonster::mtSlime; + case E_META_SPAWN_EGG_SPIDER: return cMonster::mtSpider; + case E_META_SPAWN_EGG_SQUID: return cMonster::mtSquid; + case E_META_SPAWN_EGG_VILLAGER: return cMonster::mtVillager; + case E_META_SPAWN_EGG_WITCH: return cMonster::mtWitch; + case E_META_SPAWN_EGG_WOLF: return cMonster::mtWolf; + case E_META_SPAWN_EGG_ZOMBIE: return cMonster::mtZombie; + case E_META_SPAWN_EGG_ZOMBIE_PIGMAN: return cMonster::mtZombiePigman; + } + return cMonster::mtInvalidType; + } } ; diff --git a/src/Items/ItemString.h b/src/Items/ItemString.h new file mode 100644 index 000000000..a97fbe0ce --- /dev/null +++ b/src/Items/ItemString.h @@ -0,0 +1,39 @@ + +#pragma once + +#include "ItemHandler.h" + + + + + +class cItemStringHandler : + public cItemHandler +{ +public: + cItemStringHandler(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, eBlockFace a_BlockFace, + int a_CursorX, int a_CursorY, int a_CursorZ, + BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta + ) override + { + a_BlockType = E_BLOCK_TRIPWIRE; + a_BlockMeta = 0; + return true; + } +}; + + + + diff --git a/src/Items/ItemSugarcane.h b/src/Items/ItemSugarcane.h index e891cc367..dd2e2ece3 100644 --- a/src/Items/ItemSugarcane.h +++ b/src/Items/ItemSugarcane.h @@ -23,7 +23,7 @@ public: virtual bool GetPlacementBlockTypeMeta( cWorld * a_World, cPlayer * a_Player, - int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override diff --git a/src/Items/ItemSword.h b/src/Items/ItemSword.h index a7c1d2432..2b2dbfc0d 100644 --- a/src/Items/ItemSword.h +++ b/src/Items/ItemSword.h @@ -12,16 +12,46 @@ class cItemSwordHandler : public cItemHandler { + typedef cItemHandler super; public: cItemSwordHandler(int a_ItemType) : cItemHandler(a_ItemType) { - } - + + virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType) override { - return (a_BlockType == E_BLOCK_COBWEB); + if (a_BlockType == E_BLOCK_COBWEB) + { + return true; + } + return super::CanHarvestBlock(a_BlockType); + } + + + virtual bool CanRepairWithRawMaterial(short a_ItemType) override + { + switch (m_ItemType) + { + case E_ITEM_WOODEN_SWORD: return (a_ItemType == E_BLOCK_PLANKS); + case E_ITEM_STONE_SWORD: return (a_ItemType == E_BLOCK_COBBLESTONE); + case E_ITEM_IRON_SWORD: return (a_ItemType == E_ITEM_IRON); + case E_ITEM_GOLD_SWORD: return (a_ItemType == E_ITEM_GOLD); + case E_ITEM_DIAMOND_SWORD: return (a_ItemType == E_ITEM_DIAMOND); + } + return false; + } + + + virtual short GetDurabilityLossByAction(eDurabilityLostAction a_Action) override + { + switch ((int)a_Action) + { + case dlaAttackEntity: return 1; + case dlaBreakBlock: return 2; + } + return 0; } } ; diff --git a/src/Items/ItemThrowable.h b/src/Items/ItemThrowable.h index c6a4e714e..c151c5d3a 100644 --- a/src/Items/ItemThrowable.h +++ b/src/Items/ItemThrowable.h @@ -28,15 +28,23 @@ public: virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override { + Vector3d Pos = a_Player->GetThrowStartPos(); + Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff; + + // Play sound + cFastRandom Random; + a_World->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY() - a_Player->GetHeight(), a_Player->GetPosZ(), 0.5f, 0.4f / (Random.NextFloat(1.0f) * 0.4f + 0.8f)); + + if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem(), &Speed) < 0) + { + return false; + } + 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, a_Player->GetEquippedItem(), &Speed); - return true; } @@ -127,7 +135,10 @@ public: return false; } - a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, a_Player->GetEquippedItem()); + if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem()) < 0) + { + return false; + } if (!a_Player->IsGameModeCreative()) { |