From 53231bebd650b9398060cee1434ad4c44152d36e Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 5 Mar 2014 22:12:48 +0000 Subject: [PATCH] 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 --- src/ChunkMap.cpp | 31 +- src/Entities/Entity.cpp | 388 +++++++++--------- src/Entities/Entity.h | 1 + src/Entities/FallingBlock.cpp | 19 +- src/Items/ItemLighter.h | 2 +- .../IncrementalRedstoneSimulator.cpp | 2 +- src/World.cpp | 6 +- 7 files changed, 236 insertions(+), 213 deletions(-) diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index b5795fbaf..b13337b44 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -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. 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); a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z)); + break; } } // switch (BlockType) } // for z @@ -1846,11 +1855,10 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ public cEntityCallback { 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_ExplosionPos(a_ExplosionPos), - m_ExplosionSize(a_ExplosionSize), - m_ExplosionSizeSq(a_ExplosionSizeSq) + m_ExplosionSize(a_ExplosionSize) { } @@ -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 MaxExplosionBoundary(m_ExplosionSizeSq, m_ExplosionSizeSq, m_ExplosionSizeSq); // Work out how far we are from the edge of the TNT's explosive effect AbsoluteEntityPos -= m_ExplosionPos; - AbsoluteEntityPos = MaxExplosionBoundary - AbsoluteEntityPos; - double FinalDamage = ((AbsoluteEntityPos.x + AbsoluteEntityPos.y + AbsoluteEntityPos.z) / 3) * m_ExplosionSize; - FinalDamage = a_Entity->GetMaxHealth() - abs(FinalDamage); + // 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 if (FinalDamage > a_Entity->GetMaxHealth()) @@ -1888,7 +1898,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ else if (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); } @@ -1898,7 +1908,7 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ if (distance_explosion.SqrLength() < 4096.0) { distance_explosion.Normalize(); - distance_explosion *= m_ExplosionSizeSq; + distance_explosion *= m_ExplosionSize * m_ExplosionSize; a_Entity->AddSpeed(distance_explosion); } @@ -1910,14 +1920,13 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ cBoundingBox & m_bbTNT; Vector3d m_ExplosionPos; int m_ExplosionSize; - int m_ExplosionSizeSq; }; cBoundingBox bbTNT(Vector3d(a_BlockX, a_BlockY, a_BlockZ), 0.5, 1); 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); // Wake up all simulators for the area, so that water and lava flows and sand falls into the blasted holes (FS #391): diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 96e8c15a5..3eac0e2e8 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -521,28 +521,36 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk) { if (a_Chunk.IsValid()) { - HandlePhysics(a_Dt, a_Chunk); + cChunk * NextChunk = a_Chunk.GetNeighborChunk(POSX_TOINT, POSZ_TOINT); + + if ((NextChunk == NULL) || !NextChunk->IsValid()) + { + return; + } + + TickBurning(*NextChunk); + + if (GetPosY() < VOID_BOUNDARY) + { + TickInVoid(*NextChunk); + } + else + { + m_TicksSinceLastVoidDamage = 0; + } + + if (IsMob() || IsPlayer()) + { + // Set swimming state + SetSwimState(*NextChunk); + + // Handle drowning + HandleAir(); + } + + HandlePhysics(a_Dt, *NextChunk); } } - if (a_Chunk.IsValid()) - { - TickBurning(a_Chunk); - } - if ((a_Chunk.IsValid()) && (GetPosY() < -46)) - { - TickInVoid(a_Chunk); - } - else - m_TicksSinceLastVoidDamage = 0; - - if (IsMob() || IsPlayer()) - { - // Set swimming state - SetSwimState(a_Chunk); - - // Handle drowning - HandleAir(); - } } @@ -562,7 +570,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) if ((BlockY >= cChunkDef::Height) || (BlockY < 0)) { // Outside of the world - + cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); // See if we can commit our changes. If not, we will discard them. if (NextChunk != NULL) @@ -571,210 +579,208 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) NextPos += (NextSpeed * a_Dt); SetPosition(NextPos); } + return; } - // Make sure we got the correct chunk and a valid one. No one ever knows... - cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); - if (NextChunk != NULL) + int RelBlockX = BlockX - (a_Chunk.GetPosX() * cChunkDef::Width); + int RelBlockZ = BlockZ - (a_Chunk.GetPosZ() * cChunkDef::Width); + BLOCKTYPE BlockIn = a_Chunk.GetBlock( RelBlockX, BlockY, RelBlockZ ); + BLOCKTYPE BlockBelow = (BlockY > 0) ? a_Chunk.GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR; + if (!cBlockInfo::IsSolid(BlockIn)) // Making sure we are not inside a solid block { - 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 (m_bOnGround) // check if it's still on the ground { - if (m_bOnGround) // check if it's still on the ground + if (!cBlockInfo::IsSolid(BlockBelow)) // Check if block below is air or water. { - if (!cBlockInfo::IsSolid(BlockBelow)) // Check if block below is air or water. - { - m_bOnGround = false; - } + m_bOnGround = false; } } - else + } + else + { + // Push out entity. + BLOCKTYPE GotBlock; + + static const struct { - // Push out entity. - BLOCKTYPE GotBlock; + int x, y, z; + } gCrossCoords[] = + { + { 1, 0, 0}, + {-1, 0, 0}, + { 0, 0, 1}, + { 0, 0, -1}, + } ; - static const struct + bool IsNoAirSurrounding = true; + for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) + { + if (!a_Chunk.UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock)) { - int x, y, z; - } gCrossCoords[] = + // The pickup is too close to an unloaded chunk, bail out of any physics handling + return; + } + if (!cBlockInfo::IsSolid(GotBlock)) { - { 1, 0, 0}, - {-1, 0, 0}, - { 0, 0, 1}, - { 0, 0, -1}, - } ; - - bool IsNoAirSurrounding = true; - for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) - { - if (!NextChunk->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 - return; - } - if (!cBlockInfo::IsSolid(GotBlock)) - { - NextPos.x += gCrossCoords[i].x; - NextPos.z += gCrossCoords[i].z; - IsNoAirSurrounding = false; - break; - } - } // for i - gCrossCoords[] + NextPos.x += gCrossCoords[i].x; + NextPos.z += gCrossCoords[i].z; + IsNoAirSurrounding = false; + break; + } + } // for i - gCrossCoords[] - if (IsNoAirSurrounding) - { - NextPos.y += 0.5; - } - - m_bOnGround = true; - - /* - // DEBUG: - LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}", - m_UniqueID, GetClass(), BlockX, BlockY, BlockZ - ); - */ + if (IsNoAirSurrounding) + { + NextPos.y += 0.5; } - if (!m_bOnGround) + m_bOnGround = true; + + /* + // DEBUG: + LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}", + m_UniqueID, GetClass(), BlockX, BlockY, BlockZ + ); + */ + } + + if (!m_bOnGround) + { + float fallspeed; + if (IsBlockWater(BlockIn)) { - float fallspeed; - if (IsBlockWater(BlockIn)) - { - fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water. - } - else if (BlockIn == E_BLOCK_COBWEB) - { - NextSpeed.y *= 0.05; // Reduce overall falling speed - fallspeed = 0; // No falling. - } - else - { - // Normal gravity - fallspeed = m_Gravity * a_Dt; - } - NextSpeed.y += fallspeed; + fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water. + } + else if (BlockIn == E_BLOCK_COBWEB) + { + NextSpeed.y *= 0.05; // Reduce overall falling speed + fallspeed = 0; // No falling. } else { - // Friction - if (NextSpeed.SqrLength() > 0.0004f) + // Normal gravity + fallspeed = m_Gravity * a_Dt; + } + NextSpeed.y += fallspeed; + } + else + { + // Friction + if (NextSpeed.SqrLength() > 0.0004f) + { + NextSpeed.x *= 0.7f / (1 + a_Dt); + if (fabs(NextSpeed.x) < 0.05) { - NextSpeed.x *= 0.7f / (1 + a_Dt); - if (fabs(NextSpeed.x) < 0.05) - { - NextSpeed.x = 0; - } - NextSpeed.z *= 0.7f / (1 + a_Dt); - if (fabs(NextSpeed.z) < 0.05) - { - NextSpeed.z = 0; - } + NextSpeed.x = 0; + } + NextSpeed.z *= 0.7f / (1 + a_Dt); + if (fabs(NextSpeed.z) < 0.05) + { + NextSpeed.z = 0; } } + } - // Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we - // might have different speed modifiers according to terrain. - if (BlockIn == E_BLOCK_COBWEB) - { - NextSpeed.x *= 0.25; - NextSpeed.z *= 0.25; - } + // Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we + // might have different speed modifiers according to terrain. + if (BlockIn == E_BLOCK_COBWEB) + { + NextSpeed.x *= 0.25; + NextSpeed.z *= 0.25; + } - //Get water direction - Direction WaterDir = m_World->GetWaterSimulator()->GetFlowingDirection(BlockX, BlockY, BlockZ); + //Get water direction + Direction WaterDir = m_World->GetWaterSimulator()->GetFlowingDirection(BlockX, BlockY, BlockZ); - m_WaterSpeed *= 0.9f; //Reduce speed each tick + m_WaterSpeed *= 0.9f; //Reduce speed each tick - switch(WaterDir) - { - case X_PLUS: - m_WaterSpeed.x = 0.2f; - m_bOnGround = false; - break; - case X_MINUS: - m_WaterSpeed.x = -0.2f; - m_bOnGround = false; - break; - case Z_PLUS: - m_WaterSpeed.z = 0.2f; - m_bOnGround = false; - break; - case Z_MINUS: - m_WaterSpeed.z = -0.2f; - m_bOnGround = false; - break; - - default: + switch(WaterDir) + { + case X_PLUS: + m_WaterSpeed.x = 0.2f; + m_bOnGround = false; break; - } + case X_MINUS: + m_WaterSpeed.x = -0.2f; + m_bOnGround = false; + break; + case Z_PLUS: + m_WaterSpeed.z = 0.2f; + m_bOnGround = false; + break; + case Z_MINUS: + m_WaterSpeed.z = -0.2f; + m_bOnGround = false; + break; + + default: + break; + } - if (fabs(m_WaterSpeed.x) < 0.05) + if (fabs(m_WaterSpeed.x) < 0.05) + { + m_WaterSpeed.x = 0; + } + + if (fabs(m_WaterSpeed.z) < 0.05) + { + m_WaterSpeed.z = 0; + } + + NextSpeed += m_WaterSpeed; + + if( NextSpeed.SqrLength() > 0.f ) + { + cTracer Tracer( GetWorld() ); + int Ret = Tracer.Trace( NextPos, NextSpeed, 2 ); + if( Ret ) // Oh noez! we hit something { - m_WaterSpeed.x = 0; - } - - if (fabs(m_WaterSpeed.z) < 0.05) - { - m_WaterSpeed.z = 0; - } - - NextSpeed += m_WaterSpeed; - - if( NextSpeed.SqrLength() > 0.f ) - { - cTracer Tracer( GetWorld() ); - int Ret = Tracer.Trace( NextPos, NextSpeed, 2 ); - if( Ret ) // Oh noez! we hit something + // Set to hit position + if( (Tracer.RealHit - NextPos).SqrLength() <= ( NextSpeed * a_Dt ).SqrLength() ) { - // Set to hit position - if( (Tracer.RealHit - NextPos).SqrLength() <= ( NextSpeed * a_Dt ).SqrLength() ) + if( Ret == 1 ) { - if( Ret == 1 ) - { - if( Tracer.HitNormal.x != 0.f ) NextSpeed.x = 0.f; - if( Tracer.HitNormal.y != 0.f ) NextSpeed.y = 0.f; - if( Tracer.HitNormal.z != 0.f ) NextSpeed.z = 0.f; + if( Tracer.HitNormal.x != 0.f ) NextSpeed.x = 0.f; + if( Tracer.HitNormal.y != 0.f ) NextSpeed.y = 0.f; + if( Tracer.HitNormal.z != 0.f ) NextSpeed.z = 0.f; - if( Tracer.HitNormal.y > 0 ) // means on ground - { - m_bOnGround = true; - } + if( Tracer.HitNormal.y > 0 ) // means on ground + { + m_bOnGround = true; } - NextPos.Set(Tracer.RealHit.x,Tracer.RealHit.y,Tracer.RealHit.z); - NextPos.x += Tracer.HitNormal.x * 0.3f; - NextPos.y += Tracer.HitNormal.y * 0.05f; // Any larger produces entity vibration-upon-the-spot - NextPos.z += Tracer.HitNormal.z * 0.3f; - } - else - { - NextPos += (NextSpeed * a_Dt); } + NextPos.Set(Tracer.RealHit.x,Tracer.RealHit.y,Tracer.RealHit.z); + NextPos.x += Tracer.HitNormal.x * 0.3f; + NextPos.y += Tracer.HitNormal.y * 0.05f; // Any larger produces entity vibration-upon-the-spot + NextPos.z += Tracer.HitNormal.z * 0.3f; } else { - // We didn't hit anything, so move =] NextPos += (NextSpeed * a_Dt); } } - BlockX = (int) floor(NextPos.x); - BlockZ = (int) floor(NextPos.z); - NextChunk = NextChunk->GetNeighborChunk(BlockX,BlockZ); - // See if we can commit our changes. If not, we will discard them. - if (NextChunk != NULL) + else { - if (NextPos.x != GetPosX()) SetPosX(NextPos.x); - if (NextPos.y != GetPosY()) SetPosY(NextPos.y); - if (NextPos.z != GetPosZ()) SetPosZ(NextPos.z); - if (NextSpeed.x != GetSpeedX()) SetSpeedX(NextSpeed.x); - if (NextSpeed.y != GetSpeedY()) SetSpeedY(NextSpeed.y); - if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z); + // We didn't hit anything, so move =] + NextPos += (NextSpeed * a_Dt); } } + + BlockX = (int) floor(NextPos.x); + BlockZ = (int) floor(NextPos.z); + + cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); + // See if we can commit our changes. If not, we will discard them. + if (NextChunk != NULL) + { + if (NextPos.x != GetPosX()) SetPosX(NextPos.x); + if (NextPos.y != GetPosY()) SetPosY(NextPos.y); + if (NextPos.z != GetPosZ()) SetPosZ(NextPos.z); + if (NextSpeed.x != GetSpeedX()) SetSpeedX(NextSpeed.x); + if (NextSpeed.y != GetSpeedY()) SetSpeedY(NextSpeed.y); + if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z); + } } @@ -815,14 +821,13 @@ void cEntity::TickBurning(cChunk & a_Chunk) { int RelX = x; int RelZ = z; - cChunk * CurChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelX, RelZ); - if (CurChunk == NULL) - { - continue; - } + 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: { @@ -922,7 +927,7 @@ void cEntity::TickInVoid(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)) { m_IsSwimming = false; @@ -931,11 +936,10 @@ void cEntity::SetSwimState(cChunk & a_Chunk) } BLOCKTYPE BlockIn; - int RelX = (int)floor(m_LastPosX) - a_Chunk.GetPosX() * cChunkDef::Width; - int RelZ = (int)floor(m_LastPosZ) - a_Chunk.GetPosZ() * cChunkDef::Width; + int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width; + int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width; // 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)) { // This sometimes happens on Linux machines diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index b3b1cef83..ee3f25cd8 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -119,6 +119,7 @@ public: 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 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); diff --git a/src/Entities/FallingBlock.cpp b/src/Entities/FallingBlock.cpp index 9fcd9ac80..a66c7e4ae 100644 --- a/src/Entities/FallingBlock.cpp +++ b/src/Entities/FallingBlock.cpp @@ -33,20 +33,16 @@ void cFallingBlock::SpawnOn(cClientHandle & a_ClientHandle) 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 - int BlockX = m_OriginalPosition.x; + int BlockX = POSX_TOINT; int BlockY = (int)(GetPosY() - 0.5); - int BlockZ = m_OriginalPosition.z; + int BlockZ = POSZ_TOINT; if (BlockY < 0) { // Fallen out of this world, just continue falling until out of sight, then destroy: - if (BlockY < 100) + if (BlockY < VOID_BOUNDARY) { Destroy(true); } @@ -86,6 +82,15 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk) Destroy(true); return; } + + float MilliDt = a_Dt * 0.001f; + AddSpeedY(MilliDt * -9.8f); + AddPosition(GetSpeed() * MilliDt); + + if ((GetSpeedX() != 0) || (GetSpeedZ() != 0)) + { + BroadcastMovementUpdate(); + } } diff --git a/src/Items/ItemLighter.h b/src/Items/ItemLighter.h index cc7daeb08..a828cd4fa 100644 --- a/src/Items/ItemLighter.h +++ b/src/Items/ItemLighter.h @@ -34,8 +34,8 @@ public: { // Activate the TNT: 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->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom break; } default: diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index 0640227b0..c9305b8ff 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -838,8 +838,8 @@ void cIncrementalRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_ 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.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.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom } } diff --git a/src/World.cpp b/src/World.cpp index ffdae2a37..d6b88f187 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -1696,7 +1696,11 @@ void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTim UNUSED(a_InitialVelocityCoeff); cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTimeInSec); 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) + ); }