From 21ff1d81ab4e68f31874894a1f4b7feb53d210df Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 29 Aug 2014 13:44:10 +0100 Subject: [PATCH] Improved explosion damage --- src/ChunkMap.cpp | 69 ++++++++++++++++-------------------------------- src/World.cpp | 9 ++++--- 2 files changed, 29 insertions(+), 49 deletions(-) diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index dd8be0631..8ca61e2cf 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1880,21 +1880,18 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ } else if ((m_World->GetTNTShrapnelLevel() > slNone) && (m_World->GetTickRandomNumber(100) < 20)) // 20% chance of flinging stuff around { - if (!cBlockInfo::FullyOccupiesVoxel(Block)) + if ( + ((m_World->GetTNTShrapnelLevel() == slAll) && cBlockInfo::FullyOccupiesVoxel(Block)) || + ((m_World->GetTNTShrapnelLevel() == slGravityAffectedOnly) && ((Block == E_BLOCK_SAND) || (Block == E_BLOCK_GRAVEL))) + ) { - break; + m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, Block, area.GetBlockMeta(bx + x, by + y, bz + z)); } - else if ((m_World->GetTNTShrapnelLevel() == slGravityAffectedOnly) && ((Block != E_BLOCK_SAND) && (Block != E_BLOCK_GRAVEL))) - { - break; - } - m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, Block, area.GetBlockMeta(bx + x, by + y, bz + z)); } area.SetBlockTypeMeta(bx + x, by + y, bz + z, E_BLOCK_AIR, 0); a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z)); - break; - + break; } } // switch (BlockType) } // for z @@ -1916,51 +1913,31 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ virtual bool Item(cEntity * a_Entity) override { - if (a_Entity->IsPickup()) + if (a_Entity->IsPickup() && (a_Entity->GetTicksAlive() < 20)) { - if (((cPickup *)a_Entity)->GetAge() < 20) // If pickup age is smaller than one second, it is invincible (so we don't kill pickups that were just spawned) + // If pickup age is smaller than one second, it is invincible (so we don't kill pickups that were just spawned) + return false; + } + + Vector3d DistanceFromExplosion = a_Entity->GetPosition() - m_ExplosionPos; + + if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible + { + cBoundingBox bbEntity(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight()); + + if (!m_bbTNT.IsInside(bbEntity)) // If bbEntity is inside bbTNT, not vice versa! { return false; } - } - Vector3d EntityPos = a_Entity->GetPosition(); - cBoundingBox bbEntity(EntityPos, a_Entity->GetWidth() / 2, a_Entity->GetHeight()); - - if (!m_bbTNT.IsInside(bbEntity)) // IsInside actually acts like DoesSurround - { - return false; - } - - Vector3d AbsoluteEntityPos(abs(EntityPos.x), abs(EntityPos.y), abs(EntityPos.z)); - - // Work out how far we are from the edge of the TNT's explosive effect - AbsoluteEntityPos -= m_ExplosionPos; - - // All to positive - AbsoluteEntityPos.x = abs(AbsoluteEntityPos.x); - AbsoluteEntityPos.y = abs(AbsoluteEntityPos.y); - AbsoluteEntityPos.z = abs(AbsoluteEntityPos.z); - - double FinalDamage = (((1 / AbsoluteEntityPos.x) + (1 / AbsoluteEntityPos.y) + (1 / AbsoluteEntityPos.z)) * 2) * m_ExplosionSize; - - // Clip damage values - FinalDamage = Clamp(FinalDamage, 0.0, (double)a_Entity->GetMaxHealth()); - - if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible - { - a_Entity->TakeDamage(dtExplosion, NULL, (int)FinalDamage, 0); + // Ensure that the damage dealt is inversely proportional to the distance to the TNT centre - the closer a player is, the harder they are hit + a_Entity->TakeDamage(dtExplosion, NULL, (int)((1 / DistanceFromExplosion.Length()) * 6 * m_ExplosionSize), 0); } // Apply force to entities around the explosion - code modified from World.cpp DoExplosionAt() - Vector3d distance_explosion = a_Entity->GetPosition() - m_ExplosionPos; - if (distance_explosion.SqrLength() < 4096.0) - { - distance_explosion.Normalize(); - distance_explosion *= m_ExplosionSize * m_ExplosionSize; - - a_Entity->AddSpeed(distance_explosion); - } + DistanceFromExplosion.Normalize(); + DistanceFromExplosion *= m_ExplosionSize * m_ExplosionSize; + a_Entity->AddSpeed(DistanceFromExplosion); return false; } diff --git a/src/World.cpp b/src/World.cpp index d2213d1e5..c850c50d3 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -1188,24 +1188,26 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo return; } - // TODO: Add damage to entities and implement block hardiness + // 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("random.explode", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.6f); + { cCSLock Lock(m_CSPlayers); for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { cClientHandle * ch = (*itr)->GetClientHandle(); - if ((ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed()) + if (ch == NULL) { continue; } + Vector3d distance_explosion = (*itr)->GetPosition() - explosion_pos; if (distance_explosion.SqrLength() < 4096.0) { - double real_distance = std::max(0.004, sqrt(distance_explosion.SqrLength())); + double real_distance = std::max(0.004, distance_explosion.Length()); double power = a_ExplosionSize / real_distance; if (power <= 1) { @@ -1217,6 +1219,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo } } } + cPluginManager::Get()->CallHookExploded(*this, a_ExplosionSize, a_CanCauseFire, a_BlockX, a_BlockY, a_BlockZ, a_Source, a_SourceData); }