From 2431b077cd2d99c7bf1fde4d3c93f937acef0cce Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Fri, 13 Jul 2018 00:10:15 +0200 Subject: Add unbreaking for armor (#4220) Ref: minecraft.gamepedia.com/Enchanting#Unbreaking #915 --- src/Entities/Player.cpp | 55 +++++++++++++++++++++++++++++-------------------- src/Entities/Player.h | 4 ++++ 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index c674f4620..e984534a5 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -934,17 +934,14 @@ void cPlayer::SetFlying(bool a_IsFlying) -void cPlayer::ApplyArmorDamage(int DamageBlocked) +void cPlayer::ApplyArmorDamage(int a_DamageBlocked) { - short ArmorDamage = static_cast(DamageBlocked / 4); - if (ArmorDamage == 0) + short ArmorDamage = static_cast(std::max(a_DamageBlocked / 4, 1)); + + for (int i = 0; i < 4; i++) { - ArmorDamage = 1; + UseItem(cInventory::invArmorOffset + i, ArmorDamage); } - m_Inventory.DamageItem(cInventory::invArmorOffset + 0, ArmorDamage); - m_Inventory.DamageItem(cInventory::invArmorOffset + 1, ArmorDamage); - m_Inventory.DamageItem(cInventory::invArmorOffset + 2, ArmorDamage); - m_Inventory.DamageItem(cInventory::invArmorOffset + 3, ArmorDamage); } @@ -2334,20 +2331,7 @@ void cPlayer::UseEquippedItem(short a_Damage) return; } - // If the item has an unbreaking enchantment, give it a chance of escaping damage: - // Ref: https://minecraft.gamepedia.com/Enchanting#Unbreaking - cItem Item = GetEquippedItem(); - int UnbreakingLevel = static_cast(Item.m_Enchantments.GetLevel(cEnchantments::enchUnbreaking)); - double chance = 1 - (1.0 / (UnbreakingLevel + 1)); - if (GetRandomProvider().RandBool(chance)) - { - return; - } - - if (GetInventory().DamageEquippedItem(a_Damage)) - { - m_World->BroadcastSoundEffect("entity.item.break", GetPosition(), 0.5f, static_cast(0.75 + (static_cast((GetUniqueID() * 23) % 32)) / 64)); - } + UseItem(cInventory::invHotbarOffset + m_Inventory.GetEquippedSlotNum(), a_Damage); } @@ -2369,6 +2353,33 @@ void cPlayer::UseEquippedItem(cItemHandler::eDurabilityLostAction a_Action) +void cPlayer::UseItem(int a_SlotNumber, short a_Damage) +{ + const cItem & Item = m_Inventory.GetSlot(a_SlotNumber); + if (Item.IsEmpty()) + { + return; + } + + // Ref: https://minecraft.gamepedia.com/Enchanting#Unbreaking + unsigned int UnbreakingLevel = Item.m_Enchantments.GetLevel(cEnchantments::enchUnbreaking); + double chance = ItemCategory::IsArmor(Item.m_ItemType) + ? (0.6 + (0.4 / (UnbreakingLevel + 1))) : (1.0 / (UnbreakingLevel + 1)); + + // When durability is reduced by multiple points + // Unbreaking is applied for each point of reduction. + std::binomial_distribution Dist(a_Damage, chance); + short ReducedDamage = Dist(GetRandomProvider().Engine()); + if (m_Inventory.DamageItem(a_SlotNumber, ReducedDamage)) + { + m_World->BroadcastSoundEffect("entity.item.break", GetPosition(), 0.5f, static_cast(0.75 + (static_cast((GetUniqueID() * 23) % 32)) / 64)); + } +} + + + + + void cPlayer::HandleFood(void) { // Ref.: https://minecraft.gamepedia.com/Hunger diff --git a/src/Entities/Player.h b/src/Entities/Player.h index f04f90a2b..8fa463c5a 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -425,6 +425,10 @@ public: is damaged by when used for a_Action */ void UseEquippedItem(cItemHandler::eDurabilityLostAction a_Action); + /** Damage the item in a_SlotNumber by a_Damage, possibly less if the + equipped item is enchanted. */ + void UseItem(int a_SlotNumber, short a_Damage = 1); + void SendHealth(void); void SendExperience(void); -- cgit v1.2.3