diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp index 97e89359f..c4510fe6d 100644 --- a/src/BlockInfo.cpp +++ b/src/BlockInfo.cpp @@ -454,6 +454,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info) a_Info[E_BLOCK_DOUBLE_STONE_SLAB ].m_RequiresSpecialTool = true; a_Info[E_BLOCK_EMERALD_ORE ].m_RequiresSpecialTool = true; a_Info[E_BLOCK_END_STONE ].m_RequiresSpecialTool = true; + a_Info[E_BLOCK_VINES ].m_RequiresSpecialTool = true; a_Info[E_BLOCK_GOLD_BLOCK ].m_RequiresSpecialTool = true; a_Info[E_BLOCK_GOLD_ORE ].m_RequiresSpecialTool = true; a_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_RequiresSpecialTool = true; diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h index 797824506..18f336225 100644 --- a/src/Blocks/BlockLeaves.h +++ b/src/Blocks/BlockLeaves.h @@ -55,22 +55,6 @@ public: } } } - - - void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override - { - cBlockHandler::OnDestroyed(a_ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ); - - // 0.5% chance of dropping an apple, if the leaves' type is Apple Leaves: - NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - cFastRandom rand; - if (((Meta & 3) == E_META_LEAVES_APPLE) && (rand.NextInt(201) == 100)) - { - cItems Drops; - Drops.push_back(cItem(E_ITEM_RED_APPLE, 1, 0)); - a_WorldInterface.SpawnItemPickups(Drops, a_BlockX, a_BlockY, a_BlockZ); - } - } virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override diff --git a/src/Blocks/BlockTallGrass.h b/src/Blocks/BlockTallGrass.h index ba1f2e0f6..9c008f793 100644 --- a/src/Blocks/BlockTallGrass.h +++ b/src/Blocks/BlockTallGrass.h @@ -43,8 +43,9 @@ public: cItems Pickups; Pickups.Add(E_BLOCK_TALL_GRASS, 1, Meta); a_WorldInterface.SpawnItemPickups(Pickups, a_BlockX, a_BlockY, a_BlockZ); + + a_Player->UseEquippedItem(); } - a_Player->UseEquippedItem(); } diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h index 61092af3e..1e1f6d8d2 100644 --- a/src/Blocks/BlockVine.h +++ b/src/Blocks/BlockVine.h @@ -44,6 +44,13 @@ public: } + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + { + // Reset meta to 0 + a_Pickups.push_back(cItem(E_BLOCK_VINES, 1, 0)); + } + + static NIBBLETYPE DirectionToMetaData(char a_BlockFace) { switch (a_BlockFace) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index db0fd0fd6..6c3d7b40c 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -12,6 +12,7 @@ #include "../Bindings/PluginManager.h" #include "../Tracer.h" #include "Player.h" +#include "Items/ItemHandler.h" @@ -289,11 +290,6 @@ void cEntity::SetPitchFromSpeed(void) bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) { - if (cRoot::Get()->GetPluginManager()->CallHookTakeDamage(*this, a_TDI)) - { - return false; - } - if (m_Health <= 0) { // Can't take damage if already dead @@ -306,10 +302,17 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) return false; } + if (cRoot::Get()->GetPluginManager()->CallHookTakeDamage(*this, a_TDI)) + { + return false; + } + if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer())) { cPlayer * Player = (cPlayer *)a_TDI.Attacker; + Player->GetEquippedItem().GetHandler()->OnEntityAttack(Player, this); + // IsOnGround() only is false if the player is moving downwards // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain) if (!Player->IsOnGround()) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index fcc8eb9a0..afe5965aa 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1929,14 +1929,14 @@ cPlayer::StringList cPlayer::GetResolvedPermissions() -void cPlayer::UseEquippedItem(void) +void cPlayer::UseEquippedItem(int a_Amount) { if (IsGameModeCreative()) // No damage in creative { return; } - if (GetInventory().DamageEquippedItem()) + if (GetInventory().DamageEquippedItem(a_Amount)) { m_World->BroadcastSoundEffect("random.break", GetPosX(), GetPosY(), GetPosZ(), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); } diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 26db2050b..e89d9f48f 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -349,7 +349,7 @@ public: const AString & GetLoadedWorldName() { return m_LoadedWorldName; } - void UseEquippedItem(void); + void UseEquippedItem(int a_Amount = 1); void SendHealth(void); diff --git a/src/FastRandom.h b/src/FastRandom.h index 567198a31..2061a3958 100644 --- a/src/FastRandom.h +++ b/src/FastRandom.h @@ -44,6 +44,9 @@ public: /// Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M; a_Salt is additional source of randomness float NextFloat(float a_Range, int a_Salt); + /** Returns a random float between 0 and 1. */ + float NextFloat(void) { return NextFloat(1); }; + /** Returns a random int in the range [a_Begin .. a_End] */ int GenerateRandomInteger(int a_Begin, int a_End); diff --git a/src/Inventory.cpp b/src/Inventory.cpp index 0f9716d89..a34d51993 100644 --- a/src/Inventory.cpp +++ b/src/Inventory.cpp @@ -222,12 +222,6 @@ void cInventory::SetSlot(int a_SlotNum, const cItem & a_Item) return; } Grid->SetSlot(GridSlotNum, a_Item); - - // Broadcast the Equipped Item, if the Slot is changed. - if ((Grid == &m_HotbarSlots) && (m_EquippedSlotNum == (a_SlotNum - invHotbarOffset))) - { - m_Owner.GetWorld()->BroadcastEntityEquipment(m_Owner, 0, a_Item, m_Owner.GetClientHandle()); - } } @@ -393,6 +387,10 @@ bool cInventory::DamageItem(int a_SlotNum, short a_Amount) LOGWARNING("%s: requesting an invalid slot index: %d out of %d", __FUNCTION__, a_SlotNum, invNumSlots - 1); return false; } + if (a_Amount <= 0) + { + return false; + } int GridSlotNum = 0; cItemGrid * Grid = GetGridForSlotNum(a_SlotNum, GridSlotNum); @@ -713,6 +711,12 @@ void cInventory::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) m_ArmorSlots.GetSlot(a_SlotNum), m_Owner.GetClientHandle() ); } + + // Broadcast the Equipped Item, if the Slot is changed. + if ((a_ItemGrid == &m_HotbarSlots) && (m_EquippedSlotNum == a_SlotNum)) + { + m_Owner.GetWorld()->BroadcastEntityEquipment(m_Owner, 0, GetEquippedItem(), m_Owner.GetClientHandle()); + } // Convert the grid-local a_SlotNum to our global SlotNum: int Base = 0; diff --git a/src/Item.cpp b/src/Item.cpp index b44472e38..2c5deaddf 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -41,33 +41,33 @@ short cItem::GetMaxDamage(void) const switch (m_ItemType) { case E_ITEM_BOW: return 384; - case E_ITEM_DIAMOND_AXE: return 1563; - case E_ITEM_DIAMOND_HOE: return 1563; - case E_ITEM_DIAMOND_PICKAXE: return 1563; - case E_ITEM_DIAMOND_SHOVEL: return 1563; - case E_ITEM_DIAMOND_SWORD: return 1563; - case E_ITEM_FLINT_AND_STEEL: return 65; + case E_ITEM_DIAMOND_AXE: return 1561; + case E_ITEM_DIAMOND_HOE: return 1561; + case E_ITEM_DIAMOND_PICKAXE: return 1561; + case E_ITEM_DIAMOND_SHOVEL: return 1561; + case E_ITEM_DIAMOND_SWORD: return 1561; + case E_ITEM_FLINT_AND_STEEL: return 64; case E_ITEM_GOLD_AXE: return 32; case E_ITEM_GOLD_HOE: return 32; case E_ITEM_GOLD_PICKAXE: return 32; case E_ITEM_GOLD_SHOVEL: return 32; case E_ITEM_GOLD_SWORD: return 32; - case E_ITEM_IRON_AXE: return 251; - case E_ITEM_IRON_HOE: return 251; - case E_ITEM_IRON_PICKAXE: return 251; - case E_ITEM_IRON_SHOVEL: return 251; - case E_ITEM_IRON_SWORD: return 251; - case E_ITEM_SHEARS: return 251; - case E_ITEM_STONE_AXE: return 132; - case E_ITEM_STONE_HOE: return 132; - case E_ITEM_STONE_PICKAXE: return 132; - case E_ITEM_STONE_SHOVEL: return 132; - case E_ITEM_STONE_SWORD: return 132; - case E_ITEM_WOODEN_AXE: return 60; - case E_ITEM_WOODEN_HOE: return 60; - case E_ITEM_WOODEN_PICKAXE: return 60; - case E_ITEM_WOODEN_SHOVEL: return 60; - case E_ITEM_WOODEN_SWORD: return 60; + case E_ITEM_IRON_AXE: return 250; + case E_ITEM_IRON_HOE: return 250; + case E_ITEM_IRON_PICKAXE: return 250; + case E_ITEM_IRON_SHOVEL: return 250; + case E_ITEM_IRON_SWORD: return 250; + case E_ITEM_SHEARS: return 250; + case E_ITEM_STONE_AXE: return 131; + case E_ITEM_STONE_HOE: return 131; + case E_ITEM_STONE_PICKAXE: return 131; + case E_ITEM_STONE_SHOVEL: return 131; + case E_ITEM_STONE_SWORD: return 131; + case E_ITEM_WOODEN_AXE: return 59; + case E_ITEM_WOODEN_HOE: return 59; + case E_ITEM_WOODEN_PICKAXE: return 59; + case E_ITEM_WOODEN_SHOVEL: return 59; + case E_ITEM_WOODEN_SWORD: return 59; } return 0; } @@ -86,7 +86,7 @@ bool cItem::DamageItem(short a_Amount) } m_ItemDamage += a_Amount; - return (m_ItemDamage >= MaxDamage); + return (m_ItemDamage > MaxDamage); } diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index bf1d4e4cb..f0a91214d 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -335,8 +335,21 @@ void cItemHandler::OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const Handler->DropBlock(ChunkInterface, *a_World, PluginInterface, a_Player, a_BlockX, a_BlockY, a_BlockZ); } } - - a_Player->UseEquippedItem(); + + if (!cBlockInfo::IsOneHitDig(Block)) + { + a_Player->UseEquippedItem(GetDurabilityLostWithThatAction(dlaBreakBlock)); + } +} + + + + + +void cItemHandler::OnEntityAttack(cPlayer * a_Attacker, cEntity * a_AttackedEntity) +{ + UNUSED(a_AttackedEntity); + a_Attacker->UseEquippedItem(GetDurabilityLostWithThatAction(dlaAttackEntity)); } @@ -354,6 +367,20 @@ void cItemHandler::OnFoodEaten(cWorld * a_World, cPlayer * a_Player, cItem * a_I +short cItemHandler::GetDurabilityLostWithThatAction(eDurabilityLostAction a_Action) +{ + switch (a_Action) + { + case dlaAttackEntity: return 2; + case dlaBreakBlock: return 1; + } + return 0; +} + + + + + char cItemHandler::GetMaxStackSize(void) { if (m_ItemType < 256) @@ -505,6 +532,7 @@ bool cItemHandler::IsPlaceable(void) bool cItemHandler::CanRepairWithRawMaterial(short a_ItemType) { + UNUSED(a_ItemType); return false; } diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index c7362c5f4..28b1dd13b 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 */ @@ -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 GetDurabilityLostWithThatAction(eDurabilityLostAction a_Action); + /** Returns the maximum stack size for a given item */ virtual char GetMaxStackSize(void); diff --git a/src/Items/ItemHoe.h b/src/Items/ItemHoe.h index 29f7c83d5..6523b36d9 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 GetDurabilityLostWithThatAction(eDurabilityLostAction a_Action) override + { + return 0; + } } ; diff --git a/src/Items/ItemShears.h b/src/Items/ItemShears.h index 39d2776fa..f1b6cafc3 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); @@ -56,6 +61,24 @@ public: } // switch (a_BlockType) return false; } + + + virtual short GetDurabilityLostWithThatAction(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/ItemSword.h b/src/Items/ItemSword.h index 44feb2d83..8fd70bd7b 100644 --- a/src/Items/ItemSword.h +++ b/src/Items/ItemSword.h @@ -12,18 +12,20 @@ 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); } + virtual bool CanRepairWithRawMaterial(short a_ItemType) override { switch (m_ItemType) @@ -36,6 +38,17 @@ public: } return false; } + + + virtual short GetDurabilityLostWithThatAction(eDurabilityLostAction a_Action) override + { + switch (a_Action) + { + case dlaAttackEntity: return 1; + case dlaBreakBlock: return 2; + } + return 0; + } } ; diff --git a/src/Mobs/Sheep.cpp b/src/Mobs/Sheep.cpp index 7335848b7..9fb47201d 100644 --- a/src/Mobs/Sheep.cpp +++ b/src/Mobs/Sheep.cpp @@ -52,11 +52,7 @@ void cSheep::OnRightClicked(cPlayer & a_Player) { m_IsSheared = true; m_World->BroadcastEntityMetadata(*this); - - if (!a_Player.IsGameModeCreative()) - { - a_Player.UseEquippedItem(); - } + a_Player.UseEquippedItem(); cItems Drops; int NumDrops = m_World->GetTickRandomNumber(2) + 1;