1
0

Added extra awesomeness to TNT

+ TNT now has a chance of flinging FallingBlock entities around
* Improved TNT damage
* Improved TNT spawning visuals
* Possible fix for 'SetSwimState failure' messages in debug
This commit is contained in:
Tiger Wang 2014-03-05 22:12:48 +00:00
parent 7fb354e8f0
commit 53231bebd6
7 changed files with 236 additions and 213 deletions

View File

@ -1832,8 +1832,17 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
Handler->ConvertToPickups(Drops, area.GetBlockMeta(bx + x, by + y, bz + z)); // Stone becomes cobblestone, coal ore becomes coal, etc. Handler->ConvertToPickups(Drops, area.GetBlockMeta(bx + x, by + y, bz + z)); // Stone becomes cobblestone, coal ore becomes coal, etc.
m_World->SpawnItemPickups(Drops, bx + x, by + y, bz + z); m_World->SpawnItemPickups(Drops, bx + x, by + y, bz + z);
} }
else if (m_World->GetTickRandomNumber(100) < 20) // 20% chance of flinging stuff around
{
if (!cBlockInfo::FullyOccupiesVoxel(area.GetBlockType(bx + x, by + y, bz + z)))
{
break;
}
m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, area.GetBlockType(bx + x, by + y, bz + z), area.GetBlockMeta(bx + x, by + y, bz + z));
}
area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_AIR); area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_AIR);
a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z)); a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z));
break;
} }
} // switch (BlockType) } // switch (BlockType)
} // for z } // for z
@ -1846,11 +1855,10 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
public cEntityCallback public cEntityCallback
{ {
public: public:
cTNTDamageCallback(cBoundingBox & a_bbTNT, Vector3d a_ExplosionPos, int a_ExplosionSize, int a_ExplosionSizeSq) : cTNTDamageCallback(cBoundingBox & a_bbTNT, Vector3d a_ExplosionPos, int a_ExplosionSize) :
m_bbTNT(a_bbTNT), m_bbTNT(a_bbTNT),
m_ExplosionPos(a_ExplosionPos), m_ExplosionPos(a_ExplosionPos),
m_ExplosionSize(a_ExplosionSize), m_ExplosionSize(a_ExplosionSize)
m_ExplosionSizeSq(a_ExplosionSizeSq)
{ {
} }
@ -1873,14 +1881,16 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
} }
Vector3d AbsoluteEntityPos(abs(EntityPos.x), abs(EntityPos.y), abs(EntityPos.z)); Vector3d AbsoluteEntityPos(abs(EntityPos.x), abs(EntityPos.y), abs(EntityPos.z));
Vector3d MaxExplosionBoundary(m_ExplosionSizeSq, m_ExplosionSizeSq, m_ExplosionSizeSq);
// Work out how far we are from the edge of the TNT's explosive effect // Work out how far we are from the edge of the TNT's explosive effect
AbsoluteEntityPos -= m_ExplosionPos; AbsoluteEntityPos -= m_ExplosionPos;
AbsoluteEntityPos = MaxExplosionBoundary - AbsoluteEntityPos;
double FinalDamage = ((AbsoluteEntityPos.x + AbsoluteEntityPos.y + AbsoluteEntityPos.z) / 3) * m_ExplosionSize; // All to positive
FinalDamage = a_Entity->GetMaxHealth() - abs(FinalDamage); 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 // Clip damage values
if (FinalDamage > a_Entity->GetMaxHealth()) if (FinalDamage > a_Entity->GetMaxHealth())
@ -1888,7 +1898,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
else if (FinalDamage < 0) else if (FinalDamage < 0)
FinalDamage = 0; FinalDamage = 0;
if (!a_Entity->IsTNT()) // Don't apply damage to other TNT entities, they should be invincible if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities, they should be invincible
{ {
a_Entity->TakeDamage(dtExplosion, NULL, (int)FinalDamage, 0); a_Entity->TakeDamage(dtExplosion, NULL, (int)FinalDamage, 0);
} }
@ -1898,7 +1908,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
if (distance_explosion.SqrLength() < 4096.0) if (distance_explosion.SqrLength() < 4096.0)
{ {
distance_explosion.Normalize(); distance_explosion.Normalize();
distance_explosion *= m_ExplosionSizeSq; distance_explosion *= m_ExplosionSize * m_ExplosionSize;
a_Entity->AddSpeed(distance_explosion); a_Entity->AddSpeed(distance_explosion);
} }
@ -1910,14 +1920,13 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
cBoundingBox & m_bbTNT; cBoundingBox & m_bbTNT;
Vector3d m_ExplosionPos; Vector3d m_ExplosionPos;
int m_ExplosionSize; int m_ExplosionSize;
int m_ExplosionSizeSq;
}; };
cBoundingBox bbTNT(Vector3d(a_BlockX, a_BlockY, a_BlockZ), 0.5, 1); cBoundingBox bbTNT(Vector3d(a_BlockX, a_BlockY, a_BlockZ), 0.5, 1);
bbTNT.Expand(ExplosionSizeInt * 2, ExplosionSizeInt * 2, ExplosionSizeInt * 2); bbTNT.Expand(ExplosionSizeInt * 2, ExplosionSizeInt * 2, ExplosionSizeInt * 2);
cTNTDamageCallback TNTDamageCallback(bbTNT, Vector3d(a_BlockX, a_BlockY, a_BlockZ), ExplosionSizeInt, ExplosionSizeSq); cTNTDamageCallback TNTDamageCallback(bbTNT, Vector3d(a_BlockX, a_BlockY, a_BlockZ), ExplosionSizeInt);
ForEachEntity(TNTDamageCallback); ForEachEntity(TNTDamageCallback);
// Wake up all simulators for the area, so that water and lava flows and sand falls into the blasted holes (FS #391): // Wake up all simulators for the area, so that water and lava flows and sand falls into the blasted holes (FS #391):

View File

@ -521,28 +521,36 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
{ {
if (a_Chunk.IsValid()) if (a_Chunk.IsValid())
{ {
HandlePhysics(a_Dt, a_Chunk); cChunk * NextChunk = a_Chunk.GetNeighborChunk(POSX_TOINT, POSZ_TOINT);
}
} if ((NextChunk == NULL) || !NextChunk->IsValid())
if (a_Chunk.IsValid())
{ {
TickBurning(a_Chunk); return;
} }
if ((a_Chunk.IsValid()) && (GetPosY() < -46))
TickBurning(*NextChunk);
if (GetPosY() < VOID_BOUNDARY)
{ {
TickInVoid(a_Chunk); TickInVoid(*NextChunk);
} }
else else
{
m_TicksSinceLastVoidDamage = 0; m_TicksSinceLastVoidDamage = 0;
}
if (IsMob() || IsPlayer()) if (IsMob() || IsPlayer())
{ {
// Set swimming state // Set swimming state
SetSwimState(a_Chunk); SetSwimState(*NextChunk);
// Handle drowning // Handle drowning
HandleAir(); HandleAir();
} }
HandlePhysics(a_Dt, *NextChunk);
}
}
} }
@ -571,17 +579,14 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
NextPos += (NextSpeed * a_Dt); NextPos += (NextSpeed * a_Dt);
SetPosition(NextPos); SetPosition(NextPos);
} }
return; return;
} }
// Make sure we got the correct chunk and a valid one. No one ever knows... int RelBlockX = BlockX - (a_Chunk.GetPosX() * cChunkDef::Width);
cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); int RelBlockZ = BlockZ - (a_Chunk.GetPosZ() * cChunkDef::Width);
if (NextChunk != NULL) BLOCKTYPE BlockIn = a_Chunk.GetBlock( RelBlockX, BlockY, RelBlockZ );
{ BLOCKTYPE BlockBelow = (BlockY > 0) ? a_Chunk.GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width);
int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width);
BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ );
BLOCKTYPE BlockBelow = (BlockY > 0) ? NextChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
if (!cBlockInfo::IsSolid(BlockIn)) // Making sure we are not inside a solid block if (!cBlockInfo::IsSolid(BlockIn)) // Making sure we are not inside a solid block
{ {
if (m_bOnGround) // check if it's still on the ground if (m_bOnGround) // check if it's still on the ground
@ -611,7 +616,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
bool IsNoAirSurrounding = true; bool IsNoAirSurrounding = true;
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
{ {
if (!NextChunk->UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock)) if (!a_Chunk.UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock))
{ {
// The pickup is too close to an unloaded chunk, bail out of any physics handling // The pickup is too close to an unloaded chunk, bail out of any physics handling
return; return;
@ -761,9 +766,11 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
NextPos += (NextSpeed * a_Dt); NextPos += (NextSpeed * a_Dt);
} }
} }
BlockX = (int) floor(NextPos.x); BlockX = (int) floor(NextPos.x);
BlockZ = (int) floor(NextPos.z); BlockZ = (int) floor(NextPos.z);
NextChunk = NextChunk->GetNeighborChunk(BlockX,BlockZ);
cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
// See if we can commit our changes. If not, we will discard them. // See if we can commit our changes. If not, we will discard them.
if (NextChunk != NULL) if (NextChunk != NULL)
{ {
@ -775,7 +782,6 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z); if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z);
} }
} }
}
@ -815,14 +821,13 @@ void cEntity::TickBurning(cChunk & a_Chunk)
{ {
int RelX = x; int RelX = x;
int RelZ = z; int RelZ = z;
cChunk * CurChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelX, RelZ);
if (CurChunk == NULL)
{
continue;
}
for (int y = MinY; y <= MaxY; y++) for (int y = MinY; y <= MaxY; y++)
{ {
switch (CurChunk->GetBlock(RelX, y, RelZ)) BLOCKTYPE Block;
a_Chunk.UnboundedRelGetBlockType(RelX, y, RelZ, Block);
switch (Block)
{ {
case E_BLOCK_FIRE: case E_BLOCK_FIRE:
{ {
@ -922,7 +927,7 @@ void cEntity::TickInVoid(cChunk & a_Chunk)
void cEntity::SetSwimState(cChunk & a_Chunk) void cEntity::SetSwimState(cChunk & a_Chunk)
{ {
int RelY = (int)floor(m_LastPosY + 0.1); int RelY = (int)floor(GetPosY() + 0.1);
if ((RelY < 0) || (RelY >= cChunkDef::Height - 1)) if ((RelY < 0) || (RelY >= cChunkDef::Height - 1))
{ {
m_IsSwimming = false; m_IsSwimming = false;
@ -931,11 +936,10 @@ void cEntity::SetSwimState(cChunk & a_Chunk)
} }
BLOCKTYPE BlockIn; BLOCKTYPE BlockIn;
int RelX = (int)floor(m_LastPosX) - a_Chunk.GetPosX() * cChunkDef::Width; int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
int RelZ = (int)floor(m_LastPosZ) - a_Chunk.GetPosZ() * cChunkDef::Width; int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
// Check if the player is swimming: // Check if the player is swimming:
// Use Unbounded, because we're being called *after* processing super::Tick(), which could have changed our chunk
if (!a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockIn)) if (!a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockIn))
{ {
// This sometimes happens on Linux machines // This sometimes happens on Linux machines

View File

@ -119,6 +119,7 @@ public:
BURN_TICKS = 200, ///< How long to keep an entity burning after it has stood in lava / fire BURN_TICKS = 200, ///< How long to keep an entity burning after it has stood in lava / fire
MAX_AIR_LEVEL = 300, ///< Maximum air an entity can have MAX_AIR_LEVEL = 300, ///< Maximum air an entity can have
DROWNING_TICKS = 20, ///< Number of ticks per heart of damage DROWNING_TICKS = 20, ///< Number of ticks per heart of damage
VOID_BOUNDARY = -46 ///< At what position Y to begin applying void damage
} ; } ;
cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height); cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);

View File

@ -33,20 +33,16 @@ void cFallingBlock::SpawnOn(cClientHandle & a_ClientHandle)
void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk) void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
{ {
float MilliDt = a_Dt * 0.001f;
AddSpeedY(MilliDt * -9.8f);
AddPosY(GetSpeedY() * MilliDt);
// GetWorld()->BroadcastTeleportEntity(*this); // Test position // GetWorld()->BroadcastTeleportEntity(*this); // Test position
int BlockX = m_OriginalPosition.x; int BlockX = POSX_TOINT;
int BlockY = (int)(GetPosY() - 0.5); int BlockY = (int)(GetPosY() - 0.5);
int BlockZ = m_OriginalPosition.z; int BlockZ = POSZ_TOINT;
if (BlockY < 0) if (BlockY < 0)
{ {
// Fallen out of this world, just continue falling until out of sight, then destroy: // Fallen out of this world, just continue falling until out of sight, then destroy:
if (BlockY < 100) if (BlockY < VOID_BOUNDARY)
{ {
Destroy(true); Destroy(true);
} }
@ -86,6 +82,15 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
Destroy(true); Destroy(true);
return; return;
} }
float MilliDt = a_Dt * 0.001f;
AddSpeedY(MilliDt * -9.8f);
AddPosition(GetSpeed() * MilliDt);
if ((GetSpeedX() != 0) || (GetSpeedZ() != 0))
{
BroadcastMovementUpdate();
}
} }

View File

@ -34,8 +34,8 @@ public:
{ {
// Activate the TNT: // Activate the TNT:
a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f); a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f);
a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
a_World->SetBlock(a_BlockX,a_BlockY,a_BlockZ, E_BLOCK_AIR, 0); a_World->SetBlock(a_BlockX,a_BlockY,a_BlockZ, E_BLOCK_AIR, 0);
a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
break; break;
} }
default: default:

View File

@ -838,8 +838,8 @@ void cIncrementalRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_
if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
{ {
m_World.BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f); m_World.BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f);
m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
} }
} }

View File

@ -1696,7 +1696,11 @@ void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTim
UNUSED(a_InitialVelocityCoeff); UNUSED(a_InitialVelocityCoeff);
cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTimeInSec); cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTimeInSec);
TNT->Initialize(this); TNT->Initialize(this);
// TODO: Add a bit of speed in horiz and vert axes, based on the a_InitialVelocityCoeff TNT->SetSpeed(
a_InitialVelocityCoeff * (GetTickRandomNumber(2) - 1), /** -1, 0, 1 */
a_InitialVelocityCoeff * 2,
a_InitialVelocityCoeff * (GetTickRandomNumber(2) - 1)
);
} }