From 01e72ddb6567531b16f92af2564b853878b6ef65 Mon Sep 17 00:00:00 2001 From: changyong guo Date: Mon, 23 Jul 2018 17:24:00 +0800 Subject: Rewrite explosion knock back (#4251) 1. Base knockback on an entity's bounding box intersection with the explosion 2. Armor blast protection reduces knockback 3. Don't apply knockback to players flying in creative mode Fixes #4139 --- src/Entities/Entity.cpp | 64 ++++++++++++++++++++++++++++++++++++++++++++++++- src/Entities/Entity.h | 11 ++++++++- src/Entities/Player.cpp | 28 ++++++++++++++++++++++ src/Entities/Player.h | 2 ++ 4 files changed, 103 insertions(+), 2 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index d1fdcfd39..4ecc5c4da 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -14,7 +14,7 @@ #include "Items/ItemHandler.h" #include "../FastRandom.h" #include "../NetherPortalScanner.h" - +#include "../BoundingBox.h" @@ -690,6 +690,33 @@ int cEntity::GetEnchantmentCoverAgainst(const cEntity * a_Attacker, eDamageType + +float cEntity::GetEnchantmentBlastKnockbackReduction() +{ + UInt32 MaxLevel = 0; + + const cItem ArmorItems[] = { GetEquippedHelmet(), GetEquippedChestplate(), GetEquippedLeggings(), GetEquippedBoots() }; + + for (auto & Item : ArmorItems) + { + UInt32 Level = Item.m_Enchantments.GetLevel(cEnchantments::enchBlastProtection); + if (Level > MaxLevel) + { + // Get max blast protection + MaxLevel = Level; + } + } + + // Max blast protect level is 4, each level provide 15% knock back reduction + MaxLevel = std::min(MaxLevel, 4); + return MaxLevel * 0.15f; +} + + + + + + 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 @@ -2241,3 +2268,38 @@ void cEntity::RemoveLeashedMob(cMonster * a_Monster) m_LeashedMobs.remove(a_Monster); } + + + + + + +float cEntity::GetExplosionExposureRate(Vector3d a_ExplosionPosition, float a_ExlosionPower) +{ + double EntitySize = m_Width * m_Width * m_Height; + if (EntitySize <= 0) + { + // Handle entity with invalid size + return 0; + } + + cBoundingBox EntityBox(GetPosition(), m_Width / 2, m_Height); + cBoundingBox ExplosionBox(a_ExplosionPosition, a_ExlosionPower * 2.0); + cBoundingBox IntersectionBox(EntityBox); + + bool Overlap = EntityBox.Intersect(ExplosionBox, IntersectionBox); + if (Overlap) + { + Vector3d Diff = IntersectionBox.GetMax() - IntersectionBox.GetMin(); + double OverlapSize = Diff.x * Diff.y * Diff.z; + + return static_cast(OverlapSize / EntitySize); + } + else + { + return 0; + } +} + + + diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 7ac12c95b..ae150b4e2 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -333,6 +333,10 @@ public: /** 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 explosion knock back reduction percent from blast protection level + @return knock back reduce percent */ + virtual float GetEnchantmentBlastKnockbackReduction(); + /** Returns the knockback amount that the currently equipped items would cause to a_Receiver on a hit */ virtual double GetKnockbackAmountAgainst(const cEntity & a_Receiver); @@ -545,6 +549,12 @@ public: /** Returs whether the entity has any mob leashed to */ bool HasAnyMobLeashed() const { return m_LeashedMobs.size() > 0; } + /** a lightweight calculation approach to get explosion exposure rate + @param a_ExplosionPosition explosion position + @param a_ExlosionPower explosion power + @return exposure rate */ + virtual float GetExplosionExposureRate(Vector3d a_ExplosionPosition, float a_ExlosionPower); + protected: /** Structure storing the portal delay timer and cooldown boolean */ struct sPortalCooldownData @@ -714,5 +724,4 @@ private: /** List of leashed mobs to this entity */ cMonsterList m_LeashedMobs; - } ; // tolua_export diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index d8bb22e2f..181a54870 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -3069,3 +3069,31 @@ float cPlayer::GetPlayerRelativeBlockHardness(BLOCKTYPE a_Block) // LOGD("blockHardness: %f, digSpeed: %f, canHarvestBlockDivisor: %f\n", blockHardness, digSpeed, canHarvestBlockDivisor); return (blockHardness < 0) ? 0 : ((digSpeed / blockHardness) / canHarvestBlockDivisor); } + + + + + + +float cPlayer::GetExplosionExposureRate(Vector3d a_ExplosionPosition, float a_ExlosionPower) +{ + if ( + IsGameModeSpectator() || + (IsGameModeCreative() && !IsOnGround()) + ) + { + return 0; // No impact from explosion + } + + return super::GetExplosionExposureRate(a_ExplosionPosition, a_ExlosionPower); +} + + + + + + + + + + diff --git a/src/Entities/Player.h b/src/Entities/Player.h index e710e8396..c9249b2f1 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -759,6 +759,8 @@ protected: This can be used both for online and offline UUIDs. */ AString GetUUIDFileName(const cUUID & a_UUID); + /** get player explosion exposure rate */ + virtual float GetExplosionExposureRate(Vector3d a_ExplosionPosition, float a_ExlosionPower) override; private: /** Pins the player to a_Location until Unfreeze() is called. -- cgit v1.2.3