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
This commit is contained in:
parent
7b0db672d1
commit
01e72ddb65
@ -3231,6 +3231,16 @@ local Hash = cCryptoHash.sha1HexString("DataToHash")
|
||||
},
|
||||
Notes = "Returns the entity classname that this class implements. Each descendant overrides this function.",
|
||||
},
|
||||
GetEnchantmentBlastKnockbackReduction =
|
||||
{
|
||||
Returns =
|
||||
{
|
||||
{
|
||||
Type = "number",
|
||||
},
|
||||
},
|
||||
Notes = "Returns explosion knock back reduction percent from blast protection level.",
|
||||
},
|
||||
GetEnchantmentCoverAgainst =
|
||||
{
|
||||
Params =
|
||||
|
@ -1814,10 +1814,21 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
|
||||
a_Entity.TakeDamage(dtExplosion, nullptr, static_cast<int>((1 / DistanceFromExplosion.Length()) * 6 * ExplosionSizeInt), 0);
|
||||
}
|
||||
|
||||
// Apply force to entities around the explosion - code modified from World.cpp DoExplosionAt()
|
||||
DistanceFromExplosion.Normalize();
|
||||
DistanceFromExplosion *= ExplosionSizeInt * ExplosionSizeInt;
|
||||
a_Entity.AddSpeed(DistanceFromExplosion);
|
||||
double Length = DistanceFromExplosion.Length();
|
||||
if (Length <= ExplosionSizeInt) // Entity is impacted by explosion
|
||||
{
|
||||
float EntityExposure = a_Entity.GetExplosionExposureRate(ExplosionPos, ExplosionSizeInt);
|
||||
|
||||
// Exposure reduced by armor
|
||||
EntityExposure = EntityExposure * (1.0f - a_Entity.GetEnchantmentBlastKnockbackReduction());
|
||||
|
||||
double Impact = (1 - ((Length / ExplosionSizeInt) / 2)) * EntityExposure;
|
||||
|
||||
DistanceFromExplosion.Normalize();
|
||||
DistanceFromExplosion *= Impact;
|
||||
|
||||
a_Entity.AddSpeed(DistanceFromExplosion);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -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<UInt32>(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<float>(OverlapSize / EntitySize);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
@ -1430,7 +1430,6 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo
|
||||
}
|
||||
|
||||
// TODO: Implement block hardiness
|
||||
Vector3d explosion_pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ);
|
||||
cVector3iArray BlocksAffected;
|
||||
m_ChunkMap->DoExplosionAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, BlocksAffected);
|
||||
BroadcastSoundEffect("entity.generic.explode", Vector3d(a_BlockX, a_BlockY, a_BlockZ), 1.0f, 0.6f);
|
||||
@ -1445,19 +1444,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector3d distance_explosion = (*itr)->GetPosition() - explosion_pos;
|
||||
if (distance_explosion.SqrLength() < 4096.0)
|
||||
{
|
||||
double real_distance = std::max(0.004, distance_explosion.Length());
|
||||
double power = a_ExplosionSize / real_distance;
|
||||
if (power <= 1)
|
||||
{
|
||||
power = 0;
|
||||
}
|
||||
distance_explosion.Normalize();
|
||||
distance_explosion *= power;
|
||||
ch->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, static_cast<float>(a_ExplosionSize), BlocksAffected, distance_explosion);
|
||||
}
|
||||
ch->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, static_cast<float>(a_ExplosionSize), BlocksAffected, (*itr)->GetSpeed());
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user