summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLane Kolbly <lane@rscheme.org>2017-07-23 11:46:38 +0200
committerTiger Wang <ziwei.tiger@outlook.com>2017-07-23 11:46:38 +0200
commit87af95b67cb45b72bffd77f7744dc1a10cb3f25a (patch)
tree516a9c969936fc0d42a251f4462a5d1f92781230
parentCreepers explode when burned by flint and steel (#3865) (diff)
downloadcuberite-87af95b67cb45b72bffd77f7744dc1a10cb3f25a.tar
cuberite-87af95b67cb45b72bffd77f7744dc1a10cb3f25a.tar.gz
cuberite-87af95b67cb45b72bffd77f7744dc1a10cb3f25a.tar.bz2
cuberite-87af95b67cb45b72bffd77f7744dc1a10cb3f25a.tar.lz
cuberite-87af95b67cb45b72bffd77f7744dc1a10cb3f25a.tar.xz
cuberite-87af95b67cb45b72bffd77f7744dc1a10cb3f25a.tar.zst
cuberite-87af95b67cb45b72bffd77f7744dc1a10cb3f25a.zip
-rw-r--r--Server/Plugins/APIDump/APIDesc.lua36
-rw-r--r--src/Entities/Entity.cpp195
-rw-r--r--src/Entities/Entity.h10
-rw-r--r--src/Entities/Player.cpp27
-rw-r--r--src/Entities/Player.h1
5 files changed, 134 insertions, 135 deletions
diff --git a/Server/Plugins/APIDump/APIDesc.lua b/Server/Plugins/APIDump/APIDesc.lua
index 58a79fb66..288466303 100644
--- a/Server/Plugins/APIDump/APIDesc.lua
+++ b/Server/Plugins/APIDump/APIDesc.lua
@@ -3019,6 +3019,17 @@ local Hash = cCryptoHash.sha1HexString("DataToHash")
},
Notes = "Adds the specified amount of speed in the Z axis direction.",
},
+ ApplyArmorDamage =
+ {
+ Params =
+ {
+ {
+ Name = "DamageBlocked",
+ Type = "number",
+ },
+ },
+ Notes = "Lowers armor durability, as if the armor blocked the given amount of damage.",
+ },
ArmorCoversAgainst =
{
Params =
@@ -3124,6 +3135,31 @@ local Hash = cCryptoHash.sha1HexString("DataToHash")
},
Notes = "Returns the entity classname that this class implements. Each descendant overrides this function.",
},
+ GetEnchantmentCoverAgainst =
+ {
+ Params =
+ {
+ {
+ Name = "AttackerEntity",
+ Type = "cEntity",
+ },
+ {
+ Name = "DamageType",
+ Type = "eDamageType",
+ },
+ {
+ Name = "RawDamage",
+ Type = "number",
+ },
+ },
+ Returns =
+ {
+ {
+ Type = "number",
+ },
+ },
+ Notes = "Returns the number of hitpoints out of RawDamage that the enchantments on the currently equipped armor would cover. See {{TakeDamageInfo}} for more information on attack damage.",
+ },
GetEntityType =
{
Returns =
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index f2836de9b..b596bc93d 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -268,7 +268,16 @@ void cEntity::TakeDamage(cEntity & a_Attacker)
void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, double a_KnockbackAmount)
{
- int FinalDamage = a_RawDamage - GetArmorCoverAgainst(a_Attacker, a_DamageType, a_RawDamage);
+ int ArmorCover = GetArmorCoverAgainst(a_Attacker, a_DamageType, a_RawDamage);
+ int EnchantmentCover = GetEnchantmentCoverAgainst(a_Attacker, a_DamageType, a_RawDamage);
+ int FinalDamage = a_RawDamage - ArmorCover - EnchantmentCover;
+ if ((FinalDamage == 0) && (a_RawDamage > 0))
+ {
+ // Nobody's invincible
+ FinalDamage = 1;
+ }
+ ApplyArmorDamage(ArmorCover);
+
cEntity::TakeDamage(a_DamageType, a_Attacker, a_RawDamage, FinalDamage, a_KnockbackAmount);
}
@@ -278,7 +287,7 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R
void cEntity::TakeDamage(eDamageType a_DamageType, UInt32 a_AttackerID, int a_RawDamage, double a_KnockbackAmount)
{
- class cNotifyWolves : public cEntityCallback
+ class cFindEntity : public cEntityCallback
{
public:
@@ -300,8 +309,7 @@ void cEntity::TakeDamage(eDamageType a_DamageType, UInt32 a_AttackerID, int a_Ra
}
- int FinalDamage = m_RawDamage - m_Entity->GetArmorCoverAgainst(Attacker, m_DamageType, m_RawDamage);
- m_Entity->TakeDamage(m_DamageType, Attacker, m_RawDamage, FinalDamage, m_KnockbackAmount);
+ m_Entity->TakeDamage(m_DamageType, Attacker, m_RawDamage, m_KnockbackAmount);
return true;
}
} Callback;
@@ -517,118 +525,8 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
Player->GetStatManager().AddValue(statDamageDealt, static_cast<StatValue>(floor(a_TDI.FinalDamage * 10 + 0.5)));
}
- if (IsPlayer())
- {
- double TotalEPF = 0.0;
- double EPFProtection = 0.00;
- double EPFFireProtection = 0.00;
- double EPFBlastProtection = 0.00;
- double EPFProjectileProtection = 0.00;
- double EPFFeatherFalling = 0.00;
-
- const cItem ArmorItems[] = { GetEquippedHelmet(), GetEquippedChestplate(), GetEquippedLeggings(), GetEquippedBoots() };
- for (size_t i = 0; i < ARRAYCOUNT(ArmorItems); i++)
- {
- const cItem & Item = ArmorItems[i];
- int Level = static_cast<int>(Item.m_Enchantments.GetLevel(cEnchantments::enchProtection));
- if (Level > 0)
- {
- EPFProtection += (6 + Level * Level) * 0.75 / 3;
- }
-
- Level = static_cast<int>(Item.m_Enchantments.GetLevel(cEnchantments::enchFireProtection));
- if (Level > 0)
- {
- EPFFireProtection += (6 + Level * Level) * 1.25 / 3;
- }
-
- Level = static_cast<int>(Item.m_Enchantments.GetLevel(cEnchantments::enchFeatherFalling));
- if (Level > 0)
- {
- EPFFeatherFalling += (6 + Level * Level) * 2.5 / 3;
- }
-
- Level = static_cast<int>(Item.m_Enchantments.GetLevel(cEnchantments::enchBlastProtection));
- if (Level > 0)
- {
- EPFBlastProtection += (6 + Level * Level) * 1.5 / 3;
- }
-
- Level = static_cast<int>(Item.m_Enchantments.GetLevel(cEnchantments::enchProjectileProtection));
- if (Level > 0)
- {
- EPFProjectileProtection += (6 + Level * Level) * 1.5 / 3;
- }
-
- }
-
- TotalEPF = EPFProtection + EPFFireProtection + EPFFeatherFalling + EPFBlastProtection + EPFProjectileProtection;
-
- EPFProtection = EPFProtection / TotalEPF;
- EPFFireProtection = EPFFireProtection / TotalEPF;
- EPFFeatherFalling = EPFFeatherFalling / TotalEPF;
- EPFBlastProtection = EPFBlastProtection / TotalEPF;
- EPFProjectileProtection = EPFProjectileProtection / TotalEPF;
-
- if (TotalEPF > 25)
- {
- TotalEPF = 25;
- }
-
- float RandomValue = GetRandomProvider().RandReal(0.5f, 1.0f);
-
- TotalEPF = ceil(TotalEPF * RandomValue);
-
- if (TotalEPF > 20)
- {
- TotalEPF = 20;
- }
-
- EPFProtection = TotalEPF * EPFProtection;
- EPFFireProtection = TotalEPF * EPFFireProtection;
- EPFFeatherFalling = TotalEPF * EPFFeatherFalling;
- EPFBlastProtection = TotalEPF * EPFBlastProtection;
- EPFProjectileProtection = TotalEPF * EPFProjectileProtection;
-
- int RemovedDamage = 0;
-
- if ((a_TDI.DamageType != dtInVoid) && (a_TDI.DamageType != dtAdmin))
- {
- RemovedDamage += CeilC(EPFProtection * 0.04 * a_TDI.FinalDamage);
- }
-
- if ((a_TDI.DamageType == dtFalling) || (a_TDI.DamageType == dtEnderPearl))
- {
- RemovedDamage += CeilC(EPFFeatherFalling * 0.04 * a_TDI.FinalDamage);
- }
-
- if (a_TDI.DamageType == dtBurning)
- {
- RemovedDamage += CeilC(EPFFireProtection * 0.04 * a_TDI.FinalDamage);
- }
-
- if (a_TDI.DamageType == dtExplosion)
- {
- RemovedDamage += CeilC(EPFBlastProtection * 0.04 * a_TDI.FinalDamage);
- }
-
- if (a_TDI.DamageType == dtProjectile)
- {
- RemovedDamage += CeilC(EPFBlastProtection * 0.04 * a_TDI.FinalDamage);
- }
-
- if (a_TDI.FinalDamage < RemovedDamage)
- {
- RemovedDamage = 0;
- }
-
- a_TDI.FinalDamage -= RemovedDamage;
- }
-
m_Health -= static_cast<short>(a_TDI.FinalDamage);
- // TODO: Apply damage to armor
-
m_Health = std::max(m_Health, 0);
// Add knockback:
@@ -708,6 +606,15 @@ int cEntity::GetRawDamageAgainst(const cEntity & a_Receiver)
+void cEntity::ApplyArmorDamage(int DamageBlocked)
+{
+ // cEntities don't necessarily have armor to damage.
+ return;
+}
+
+
+
+
bool cEntity::ArmorCoversAgainst(eDamageType a_DamageType)
{
@@ -717,6 +624,7 @@ bool cEntity::ArmorCoversAgainst(eDamageType a_DamageType)
case dtOnFire:
case dtSuffocating:
case dtDrowning: // TODO: This one could be a special case - in various MC versions (PC vs XBox) it is and isn't armor-protected
+ case dtEnderPearl:
case dtStarving:
case dtInVoid:
case dtPoisoning:
@@ -734,7 +642,6 @@ bool cEntity::ArmorCoversAgainst(eDamageType a_DamageType)
case dtCactusContact:
case dtLavaContact:
case dtFireContact:
- case dtEnderPearl:
case dtExplosion:
{
return true;
@@ -750,6 +657,49 @@ bool cEntity::ArmorCoversAgainst(eDamageType a_DamageType)
+int cEntity::GetEnchantmentCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage)
+{
+ int TotalEPF = 0.0;
+
+ const cItem ArmorItems[] = { GetEquippedHelmet(), GetEquippedChestplate(), GetEquippedLeggings(), GetEquippedBoots() };
+ for (size_t i = 0; i < ARRAYCOUNT(ArmorItems); i++)
+ {
+ const cItem & Item = ArmorItems[i];
+
+ if ((a_DamageType != dtInVoid) && (a_DamageType != dtAdmin) && (a_DamageType != dtStarving))
+ {
+ TotalEPF += static_cast<int>(Item.m_Enchantments.GetLevel(cEnchantments::enchProtection)) * 1;
+ }
+
+ if ((a_DamageType == dtBurning) || (a_DamageType == dtFireContact) || (a_DamageType == dtLavaContact))
+ {
+ TotalEPF += static_cast<int>(Item.m_Enchantments.GetLevel(cEnchantments::enchFireProtection)) * 2;
+ }
+
+ if ((a_DamageType == dtFalling) || (a_DamageType == dtEnderPearl))
+ {
+ TotalEPF += static_cast<int>(Item.m_Enchantments.GetLevel(cEnchantments::enchFeatherFalling)) * 3;
+ }
+
+ if (a_DamageType == dtExplosion)
+ {
+ TotalEPF += static_cast<int>(Item.m_Enchantments.GetLevel(cEnchantments::enchBlastProtection)) * 2;
+ }
+
+ // Note: Also blocks against fire charges, etc.
+ if (a_DamageType == dtProjectile)
+ {
+ TotalEPF += static_cast<int>(Item.m_Enchantments.GetLevel(cEnchantments::enchProjectileProtection)) * 2;
+ }
+ }
+ int CappedEPF = std::min(20, TotalEPF);
+ return static_cast<int>(a_Damage * CappedEPF / 25.0);
+}
+
+
+
+
+
int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage)
{
// Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
@@ -761,15 +711,16 @@ int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_Dama
}
// Add up all armor points:
- // Ref.: http://minecraft.gamepedia.com/Armor#Defense_points as of 2012_12_20
+ // Ref.: http://minecraft.gamepedia.com/Armor#Defense_points
int ArmorValue = 0;
+ int Toughness = 0;
switch (GetEquippedHelmet().m_ItemType)
{
case E_ITEM_LEATHER_CAP: ArmorValue += 1; break;
case E_ITEM_GOLD_HELMET: ArmorValue += 2; break;
case E_ITEM_CHAIN_HELMET: ArmorValue += 2; break;
case E_ITEM_IRON_HELMET: ArmorValue += 2; break;
- case E_ITEM_DIAMOND_HELMET: ArmorValue += 3; break;
+ case E_ITEM_DIAMOND_HELMET: ArmorValue += 3; Toughness += 2; break;
}
switch (GetEquippedChestplate().m_ItemType)
{
@@ -777,7 +728,7 @@ int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_Dama
case E_ITEM_GOLD_CHESTPLATE: ArmorValue += 5; break;
case E_ITEM_CHAIN_CHESTPLATE: ArmorValue += 5; break;
case E_ITEM_IRON_CHESTPLATE: ArmorValue += 6; break;
- case E_ITEM_DIAMOND_CHESTPLATE: ArmorValue += 8; break;
+ case E_ITEM_DIAMOND_CHESTPLATE: ArmorValue += 8; Toughness += 2; break;
}
switch (GetEquippedLeggings().m_ItemType)
{
@@ -785,7 +736,7 @@ int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_Dama
case E_ITEM_GOLD_LEGGINGS: ArmorValue += 3; break;
case E_ITEM_CHAIN_LEGGINGS: ArmorValue += 4; break;
case E_ITEM_IRON_LEGGINGS: ArmorValue += 5; break;
- case E_ITEM_DIAMOND_LEGGINGS: ArmorValue += 6; break;
+ case E_ITEM_DIAMOND_LEGGINGS: ArmorValue += 6; Toughness += 2; break;
}
switch (GetEquippedBoots().m_ItemType)
{
@@ -793,14 +744,14 @@ int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_Dama
case E_ITEM_GOLD_BOOTS: ArmorValue += 1; break;
case E_ITEM_CHAIN_BOOTS: ArmorValue += 1; break;
case E_ITEM_IRON_BOOTS: ArmorValue += 2; break;
- case E_ITEM_DIAMOND_BOOTS: ArmorValue += 3; break;
+ case E_ITEM_DIAMOND_BOOTS: ArmorValue += 3; Toughness += 2; break;
}
// TODO: Special armor cases, such as wool, saddles, dog's collar
// Ref.: http://minecraft.gamepedia.com/Armor#Mob_armor as of 2012_12_20
- // Now ArmorValue is in [0, 20] range, which corresponds to [0, 80%] protection. Calculate the hitpoints from that:
- return a_Damage * (ArmorValue * 4) / 100;
+ double Reduction = std::max(ArmorValue / 5.0, ArmorValue - a_Damage / (2 + Toughness / 4.0));
+ return static_cast<int>(a_Damage * std::min(20.0, Reduction) / 25.0);
}
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index 4310b1567..d55955b0c 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -141,12 +141,12 @@ public:
static const int BURN_TICKS_PER_DAMAGE = 20; ///< Ticks to wait between damaging an entity when it is burning
static const int BURN_DAMAGE = 1; ///< Damage to deal when the entity is burning
- static const int BURN_TICKS = 200; ///< Ticks to keep an entity burning after it has stood in lava / fire
+ static const int BURN_TICKS = 160; ///< Ticks to keep an entity burning after it has stood in lava / fire
static const int MAX_AIR_LEVEL = 300; ///< Maximum air an entity can have
static const int DROWNING_TICKS = 20; ///< Number of ticks per heart of damage
- static const int VOID_BOUNDARY = -46; ///< Y position to begin applying void damage
+ static const int VOID_BOUNDARY = -64; ///< Y position to begin applying void damage
static const int FALL_DAMAGE_HEIGHT = 4; ///< Y difference after which fall damage is applied
/** Special ID that is considered an "invalid value", signifying no entity. */
@@ -320,6 +320,9 @@ public:
/** Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover */
virtual int GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_RawDamage);
+ /** Returns the hitpoints that the currently equipped armor's enchantments would cover */
+ virtual int GetEnchantmentCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage);
+
/** Returns the knockback amount that the currently equipped items would cause to a_Receiver on a hit */
virtual double GetKnockbackAmountAgainst(const cEntity & a_Receiver);
@@ -338,6 +341,9 @@ public:
/** Returns the currently equipped boots; empty item if none */
virtual cItem GetEquippedBoots(void) const { return cItem(); }
+ /** Applies damage to the armor after the armor blocked the given amount */
+ virtual void ApplyArmorDamage(int DamageBlocked);
+
// tolua_end
/** Called when the health drops below zero. a_TDI's Attacker may be nullptr (environmental damage) */
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index e4192140a..77ce378da 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -940,6 +940,22 @@ void cPlayer::SetFlying(bool a_IsFlying)
+void cPlayer::ApplyArmorDamage(int DamageBlocked)
+{
+ short ArmorDamage = static_cast<short>(DamageBlocked / 4);
+ if (ArmorDamage == 0)
+ {
+ ArmorDamage = 1;
+ }
+ 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);
+}
+
+
+
+
bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
{
@@ -976,17 +992,6 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
AddFoodExhaustion(0.3f);
SendHealth();
- // Damage armor
- short ArmorDamage = static_cast<short>(a_TDI.RawDamage / 4);
- if (ArmorDamage == 0)
- {
- ArmorDamage = 1;
- }
- 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);
-
// Tell the wolves
if (a_TDI.Attacker != nullptr)
{
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 95b21ec9a..8ad803998 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -68,6 +68,7 @@ public:
/** Returns the currently equipped boots; empty item if none */
virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); }
+ virtual void ApplyArmorDamage(int DamageBlocked) override;
// tolua_begin