summaryrefslogtreecommitdiffstats
path: root/src/Physics/Explodinator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Physics/Explodinator.cpp')
-rw-r--r--src/Physics/Explodinator.cpp775
1 files changed, 446 insertions, 329 deletions
diff --git a/src/Physics/Explodinator.cpp b/src/Physics/Explodinator.cpp
index af1d1da34..835fb589a 100644
--- a/src/Physics/Explodinator.cpp
+++ b/src/Physics/Explodinator.cpp
@@ -16,198 +16,215 @@
namespace Explodinator
{
- static const auto StepUnit = 0.3f;
- static const auto KnockbackFactor = 25U;
- static const auto StepAttenuation = 0.225f;
- static const auto TraceCubeSideLength = 16U;
- static const auto BoundingBoxStepUnit = 0.5;
-
- /** Converts an absolute floating-point Position into a Chunk-relative one. */
- static Vector3f AbsoluteToRelative(const Vector3f a_Position, const cChunkCoords a_ChunkPosition)
- {
- return { a_Position.x - a_ChunkPosition.m_ChunkX * cChunkDef::Width, a_Position.y, a_Position.z - a_ChunkPosition.m_ChunkZ * cChunkDef::Width };
- }
+static const auto StepUnit = 0.3f;
+static const auto KnockbackFactor = 25U;
+static const auto StepAttenuation = 0.225f;
+static const auto TraceCubeSideLength = 16U;
+static const auto BoundingBoxStepUnit = 0.5;
+
+/** Converts an absolute floating-point Position into a Chunk-relative one. */
+static Vector3f AbsoluteToRelative(const Vector3f a_Position, const cChunkCoords a_ChunkPosition)
+{
+ return {
+ a_Position.x - a_ChunkPosition.m_ChunkX * cChunkDef::Width,
+ a_Position.y,
+ a_Position.z - a_ChunkPosition.m_ChunkZ * cChunkDef::Width
+ };
+}
+
+/** Make a From Chunk-relative Position into a To Chunk-relative position. */
+static Vector3f RebaseRelativePosition(const cChunkCoords a_From, const cChunkCoords a_To, const Vector3f a_Position)
+{
+ return {
+ a_Position.x + (a_From.m_ChunkX - a_To.m_ChunkX) * cChunkDef::Width,
+ a_Position.y,
+ a_Position.z + (a_From.m_ChunkZ - a_To.m_ChunkZ) * cChunkDef::Width
+ };
+}
- /** Make a From Chunk-relative Position into a To Chunk-relative position. */
- static Vector3f RebaseRelativePosition(const cChunkCoords a_From, const cChunkCoords a_To, const Vector3f a_Position)
+/** Returns how much of an explosion Destruction Lazor's (tm) intensity the given block attenuates.
+Values are scaled as 0.3 * (0.3 + Wiki) since some compilers miss the constant folding optimisation.
+Wiki values are https://minecraft.wiki/w/Explosion#Blast_resistance as of 2021-02-06. */
+static float GetExplosionAbsorption(const BLOCKTYPE Block)
+{
+ switch (Block)
{
- return
- {
- a_Position.x + (a_From.m_ChunkX - a_To.m_ChunkX) * cChunkDef::Width,
- a_Position.y,
- a_Position.z + (a_From.m_ChunkZ - a_To.m_ChunkZ) * cChunkDef::Width
- };
+ case E_BLOCK_BEDROCK:
+ case E_BLOCK_COMMAND_BLOCK:
+ case E_BLOCK_END_GATEWAY:
+ case E_BLOCK_END_PORTAL:
+ case E_BLOCK_END_PORTAL_FRAME: return 1080000.09f;
+ case E_BLOCK_ANVIL:
+ case E_BLOCK_ENCHANTMENT_TABLE:
+ case E_BLOCK_OBSIDIAN: return 360.09f;
+ case E_BLOCK_ENDER_CHEST: return 180.09f;
+ case E_BLOCK_LAVA:
+ case E_BLOCK_STATIONARY_LAVA:
+ case E_BLOCK_WATER:
+ case E_BLOCK_STATIONARY_WATER: return 30.09f;
+ case E_BLOCK_DRAGON_EGG:
+ case E_BLOCK_END_STONE:
+ case E_BLOCK_END_BRICKS: return 2.79f;
+ case E_BLOCK_STONE:
+ case E_BLOCK_BLOCK_OF_COAL:
+ case E_BLOCK_DIAMOND_BLOCK:
+ case E_BLOCK_EMERALD_BLOCK:
+ case E_BLOCK_GOLD_BLOCK:
+ case E_BLOCK_IRON_BLOCK:
+ case E_BLOCK_BLOCK_OF_REDSTONE:
+ case E_BLOCK_BRICK:
+ case E_BLOCK_BRICK_STAIRS:
+ case E_BLOCK_COBBLESTONE:
+ case E_BLOCK_COBBLESTONE_STAIRS:
+ case E_BLOCK_IRON_BARS:
+ case E_BLOCK_JUKEBOX:
+ case E_BLOCK_MOSSY_COBBLESTONE:
+ case E_BLOCK_NETHER_BRICK:
+ case E_BLOCK_NETHER_BRICK_FENCE:
+ case E_BLOCK_NETHER_BRICK_STAIRS:
+ case E_BLOCK_PRISMARINE_BLOCK:
+ case E_BLOCK_STONE_BRICKS:
+ case E_BLOCK_STONE_BRICK_STAIRS:
+ case E_BLOCK_COBBLESTONE_WALL: return 1.89f;
+ case E_BLOCK_IRON_DOOR:
+ case E_BLOCK_IRON_TRAPDOOR:
+ case E_BLOCK_MOB_SPAWNER: return 1.59f;
+ case E_BLOCK_HOPPER: return 1.53f;
+ case E_BLOCK_TERRACOTTA: return 1.35f;
+ case E_BLOCK_COBWEB: return 1.29f;
+ case E_BLOCK_DISPENSER:
+ case E_BLOCK_DROPPER:
+ case E_BLOCK_FURNACE:
+ case E_BLOCK_OBSERVER: return 1.14f;
+ case E_BLOCK_BEACON:
+ case E_BLOCK_COAL_ORE:
+ case E_BLOCK_COCOA_POD:
+ case E_BLOCK_DIAMOND_ORE:
+ case E_BLOCK_EMERALD_ORE:
+ case E_BLOCK_GOLD_ORE:
+ case E_BLOCK_IRON_ORE:
+ case E_BLOCK_LAPIS_BLOCK:
+ case E_BLOCK_LAPIS_ORE:
+ case E_BLOCK_NETHER_QUARTZ_ORE:
+ case E_BLOCK_PLANKS:
+ case E_BLOCK_REDSTONE_ORE:
+ case E_BLOCK_FENCE:
+ case E_BLOCK_FENCE_GATE:
+ case E_BLOCK_WOODEN_DOOR:
+ case E_BLOCK_WOODEN_SLAB:
+ case E_BLOCK_WOODEN_STAIRS:
+ case E_BLOCK_TRAPDOOR: return 0.99f;
+ case E_BLOCK_CHEST:
+ case E_BLOCK_WORKBENCH:
+ case E_BLOCK_TRAPPED_CHEST: return 0.84f;
+ case E_BLOCK_BONE_BLOCK:
+ case E_BLOCK_CAULDRON:
+ case E_BLOCK_LOG: return 0.69f; // nIcE
+ case E_BLOCK_CONCRETE: return 0.63f;
+ case E_BLOCK_BOOKCASE: return 0.54f;
+ case E_BLOCK_STANDING_BANNER:
+ case E_BLOCK_WALL_BANNER:
+ case E_BLOCK_JACK_O_LANTERN:
+ case E_BLOCK_MELON:
+ case E_BLOCK_HEAD:
+ case E_BLOCK_NETHER_WART_BLOCK:
+ case E_BLOCK_PUMPKIN:
+ case E_BLOCK_SIGN_POST:
+ case E_BLOCK_WALLSIGN: return 0.39f;
+ case E_BLOCK_QUARTZ_BLOCK:
+ case E_BLOCK_QUARTZ_STAIRS:
+ case E_BLOCK_RED_SANDSTONE:
+ case E_BLOCK_RED_SANDSTONE_STAIRS:
+ case E_BLOCK_SANDSTONE:
+ case E_BLOCK_SANDSTONE_STAIRS:
+ case E_BLOCK_WOOL: return 0.33f;
+ case E_BLOCK_SILVERFISH_EGG: return 0.315f;
+ case E_BLOCK_ACTIVATOR_RAIL:
+ case E_BLOCK_DETECTOR_RAIL:
+ case E_BLOCK_POWERED_RAIL:
+ case E_BLOCK_RAIL: return 0.3f;
+ case E_BLOCK_GRASS_PATH:
+ case E_BLOCK_CLAY:
+ case E_BLOCK_FARMLAND:
+ case E_BLOCK_GRASS:
+ case E_BLOCK_GRAVEL:
+ case E_BLOCK_SPONGE: return 0.27f;
+ case E_BLOCK_BREWING_STAND:
+ case E_BLOCK_STONE_BUTTON:
+ case E_BLOCK_WOODEN_BUTTON:
+ case E_BLOCK_CAKE:
+ case E_BLOCK_CONCRETE_POWDER:
+ case E_BLOCK_DIRT:
+ case E_BLOCK_FROSTED_ICE:
+ case E_BLOCK_HAY_BALE:
+ case E_BLOCK_ICE: return 0.24f;
+ default: return 0.09f;
}
+}
- /** Returns how much of an explosion Destruction Lazor's (tm) intensity the given block attenuates.
- Values are scaled as 0.3 * (0.3 + Wiki) since some compilers miss the constant folding optimisation.
- Wiki values are https://minecraft.wiki/w/Explosion#Blast_resistance as of 2021-02-06. */
- static float GetExplosionAbsorption(const BLOCKTYPE Block)
+/** Calculates the approximate percentage of an Entity's bounding box that is exposed to an explosion centred at
+ * Position. */
+static float CalculateEntityExposure(
+ const cChunk & a_Chunk,
+ const cEntity & a_Entity,
+ const Vector3f a_Position,
+ const int a_SquareRadius
+)
+{
+ class LineOfSightCallbacks final : public cLineBlockTracer::cCallbacks
{
- switch (Block)
+ virtual bool OnNextBlock(
+ Vector3i a_BlockPos,
+ BLOCKTYPE a_BlockType,
+ NIBBLETYPE a_BlockMeta,
+ eBlockFace a_EntryFace
+ ) override
{
- case E_BLOCK_BEDROCK:
- case E_BLOCK_COMMAND_BLOCK:
- case E_BLOCK_END_GATEWAY:
- case E_BLOCK_END_PORTAL:
- case E_BLOCK_END_PORTAL_FRAME: return 1080000.09f;
- case E_BLOCK_ANVIL:
- case E_BLOCK_ENCHANTMENT_TABLE:
- case E_BLOCK_OBSIDIAN: return 360.09f;
- case E_BLOCK_ENDER_CHEST: return 180.09f;
- case E_BLOCK_LAVA:
- case E_BLOCK_STATIONARY_LAVA:
- case E_BLOCK_WATER:
- case E_BLOCK_STATIONARY_WATER: return 30.09f;
- case E_BLOCK_DRAGON_EGG:
- case E_BLOCK_END_STONE:
- case E_BLOCK_END_BRICKS: return 2.79f;
- case E_BLOCK_STONE:
- case E_BLOCK_BLOCK_OF_COAL:
- case E_BLOCK_DIAMOND_BLOCK:
- case E_BLOCK_EMERALD_BLOCK:
- case E_BLOCK_GOLD_BLOCK:
- case E_BLOCK_IRON_BLOCK:
- case E_BLOCK_BLOCK_OF_REDSTONE:
- case E_BLOCK_BRICK:
- case E_BLOCK_BRICK_STAIRS:
- case E_BLOCK_COBBLESTONE:
- case E_BLOCK_COBBLESTONE_STAIRS:
- case E_BLOCK_IRON_BARS:
- case E_BLOCK_JUKEBOX:
- case E_BLOCK_MOSSY_COBBLESTONE:
- case E_BLOCK_NETHER_BRICK:
- case E_BLOCK_NETHER_BRICK_FENCE:
- case E_BLOCK_NETHER_BRICK_STAIRS:
- case E_BLOCK_PRISMARINE_BLOCK:
- case E_BLOCK_STONE_BRICKS:
- case E_BLOCK_STONE_BRICK_STAIRS:
- case E_BLOCK_COBBLESTONE_WALL: return 1.89f;
- case E_BLOCK_IRON_DOOR:
- case E_BLOCK_IRON_TRAPDOOR:
- case E_BLOCK_MOB_SPAWNER: return 1.59f;
- case E_BLOCK_HOPPER: return 1.53f;
- case E_BLOCK_TERRACOTTA: return 1.35f;
- case E_BLOCK_COBWEB: return 1.29f;
- case E_BLOCK_DISPENSER:
- case E_BLOCK_DROPPER:
- case E_BLOCK_FURNACE:
- case E_BLOCK_OBSERVER: return 1.14f;
- case E_BLOCK_BEACON:
- case E_BLOCK_COAL_ORE:
- case E_BLOCK_COCOA_POD:
- case E_BLOCK_DIAMOND_ORE:
- case E_BLOCK_EMERALD_ORE:
- case E_BLOCK_GOLD_ORE:
- case E_BLOCK_IRON_ORE:
- case E_BLOCK_LAPIS_BLOCK:
- case E_BLOCK_LAPIS_ORE:
- case E_BLOCK_NETHER_QUARTZ_ORE:
- case E_BLOCK_PLANKS:
- case E_BLOCK_REDSTONE_ORE:
- case E_BLOCK_FENCE:
- case E_BLOCK_FENCE_GATE:
- case E_BLOCK_WOODEN_DOOR:
- case E_BLOCK_WOODEN_SLAB:
- case E_BLOCK_WOODEN_STAIRS:
- case E_BLOCK_TRAPDOOR: return 0.99f;
- case E_BLOCK_CHEST:
- case E_BLOCK_WORKBENCH:
- case E_BLOCK_TRAPPED_CHEST: return 0.84f;
- case E_BLOCK_BONE_BLOCK:
- case E_BLOCK_CAULDRON:
- case E_BLOCK_LOG: return 0.69f; // nIcE
- case E_BLOCK_CONCRETE: return 0.63f;
- case E_BLOCK_BOOKCASE: return 0.54f;
- case E_BLOCK_STANDING_BANNER:
- case E_BLOCK_WALL_BANNER:
- case E_BLOCK_JACK_O_LANTERN:
- case E_BLOCK_MELON:
- case E_BLOCK_HEAD:
- case E_BLOCK_NETHER_WART_BLOCK:
- case E_BLOCK_PUMPKIN:
- case E_BLOCK_SIGN_POST:
- case E_BLOCK_WALLSIGN: return 0.39f;
- case E_BLOCK_QUARTZ_BLOCK:
- case E_BLOCK_QUARTZ_STAIRS:
- case E_BLOCK_RED_SANDSTONE:
- case E_BLOCK_RED_SANDSTONE_STAIRS:
- case E_BLOCK_SANDSTONE:
- case E_BLOCK_SANDSTONE_STAIRS:
- case E_BLOCK_WOOL: return 0.33f;
- case E_BLOCK_SILVERFISH_EGG: return 0.315f;
- case E_BLOCK_ACTIVATOR_RAIL:
- case E_BLOCK_DETECTOR_RAIL:
- case E_BLOCK_POWERED_RAIL:
- case E_BLOCK_RAIL: return 0.3f;
- case E_BLOCK_GRASS_PATH:
- case E_BLOCK_CLAY:
- case E_BLOCK_FARMLAND:
- case E_BLOCK_GRASS:
- case E_BLOCK_GRAVEL:
- case E_BLOCK_SPONGE: return 0.27f;
- case E_BLOCK_BREWING_STAND:
- case E_BLOCK_STONE_BUTTON:
- case E_BLOCK_WOODEN_BUTTON:
- case E_BLOCK_CAKE:
- case E_BLOCK_CONCRETE_POWDER:
- case E_BLOCK_DIRT:
- case E_BLOCK_FROSTED_ICE:
- case E_BLOCK_HAY_BALE:
- case E_BLOCK_ICE: return 0.24f;
- default: return 0.09f;
+ return a_BlockType != E_BLOCK_AIR;
}
- }
+ } Callback;
+
+ const Vector3d Position = a_Position;
+ unsigned Unobstructed = 0, Total = 0;
+ const auto Box = a_Entity.GetBoundingBox();
+ cLineBlockTracer Tracer(*a_Chunk.GetWorld(), Callback);
- /** Calculates the approximate percentage of an Entity's bounding box that is exposed to an explosion centred at Position. */
- static float CalculateEntityExposure(const cChunk & a_Chunk, const cEntity & a_Entity, const Vector3f a_Position, const int a_SquareRadius)
+ for (double X = Box.GetMinX(); X < Box.GetMaxX(); X += BoundingBoxStepUnit)
{
- class LineOfSightCallbacks final : public cLineBlockTracer::cCallbacks
+ for (double Y = Box.GetMinY(); Y < Box.GetMaxY(); Y += BoundingBoxStepUnit)
{
- virtual bool OnNextBlock(Vector3i a_BlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, eBlockFace a_EntryFace) override
+ for (double Z = Box.GetMinZ(); Z < Box.GetMaxZ(); Z += BoundingBoxStepUnit)
{
- return a_BlockType != E_BLOCK_AIR;
- }
- } Callback;
-
- const Vector3d Position = a_Position;
- unsigned Unobstructed = 0, Total = 0;
- const auto Box = a_Entity.GetBoundingBox();
- cLineBlockTracer Tracer(*a_Chunk.GetWorld(), Callback);
+ const Vector3d Destination {X, Y, Z};
+ if ((Destination - Position).SqrLength() > a_SquareRadius)
+ {
+ // Don't bother with points outside our designated area-of-effect
+ // This is, surprisingly, a massive amount of work saved (~3m to detonate a sphere of 37k TNT
+ // before, ~1m after):
+ continue;
+ }
- for (double X = Box.GetMinX(); X < Box.GetMaxX(); X += BoundingBoxStepUnit)
- {
- for (double Y = Box.GetMinY(); Y < Box.GetMaxY(); Y += BoundingBoxStepUnit)
- {
- for (double Z = Box.GetMinZ(); Z < Box.GetMaxZ(); Z += BoundingBoxStepUnit)
+ if (Tracer.Trace(a_Position, Destination))
{
- const Vector3d Destination{X, Y, Z};
- if ((Destination - Position).SqrLength() > a_SquareRadius)
- {
- // Don't bother with points outside our designated area-of-effect
- // This is, surprisingly, a massive amount of work saved (~3m to detonate a sphere of 37k TNT before, ~1m after):
- continue;
- }
-
- if (Tracer.Trace(a_Position, Destination))
- {
- Unobstructed++;
- }
- Total++;
+ Unobstructed++;
}
+ Total++;
}
}
-
- return (Total == 0) ? 0 : (static_cast<float>(Unobstructed) / Total);
}
- /** Applies distance-based damage and knockback to all entities within the explosion's effect range. */
- static void DamageEntities(const cChunk & a_Chunk, const Vector3f a_Position, const int a_Power)
- {
- const auto Radius = a_Power * 2;
- const auto SquareRadius = Radius * Radius;
+ return (Total == 0) ? 0 : (static_cast<float>(Unobstructed) / Total);
+}
+
+/** Applies distance-based damage and knockback to all entities within the explosion's effect range. */
+static void DamageEntities(const cChunk & a_Chunk, const Vector3f a_Position, const int a_Power)
+{
+ const auto Radius = a_Power * 2;
+ const auto SquareRadius = Radius * Radius;
- a_Chunk.GetWorld()->ForEachEntityInBox({ a_Position, Radius * 2.f }, [&a_Chunk, a_Position, a_Power, Radius, SquareRadius](cEntity & Entity)
+ a_Chunk.GetWorld()->ForEachEntityInBox(
+ {a_Position, Radius * 2.f},
+ [&a_Chunk, a_Position, a_Power, Radius, SquareRadius](cEntity & Entity)
{
// Percentage of rays unobstructed.
const auto Exposure = CalculateEntityExposure(a_Chunk, Entity, a_Position, SquareRadius);
@@ -234,210 +251,310 @@ namespace Explodinator
// Continue iteration:
return false;
- });
+ }
+ );
+}
+
+/** Returns true if block should always drop when exploded.
+Currently missing conduits from 1.13 */
+static bool BlockAlwaysDrops(const BLOCKTYPE a_Block)
+{
+ if (IsBlockShulkerBox(a_Block))
+ {
+ return true;
}
- /** Returns true if block should always drop when exploded.
- Currently missing conduits from 1.13 */
- static bool BlockAlwaysDrops(const BLOCKTYPE a_Block)
+ switch (a_Block)
{
- if (IsBlockShulkerBox(a_Block))
- {
- return true;
- }
+ case E_BLOCK_DRAGON_EGG:
+ case E_BLOCK_BEACON:
+ case E_BLOCK_HEAD: return true;
+ }
- switch (a_Block)
- {
- case E_BLOCK_DRAGON_EGG:
- case E_BLOCK_BEACON:
- case E_BLOCK_HEAD: return true;
- }
+ return false;
+}
- return false;
- }
+/** Sets the block at the given position, updating surroundings. */
+static void SetBlock(
+ cWorld & a_World,
+ cChunk & a_Chunk,
+ const Vector3i a_AbsolutePosition,
+ const Vector3i a_RelativePosition,
+ const BLOCKTYPE a_DestroyedBlock,
+ const BLOCKTYPE a_NewBlock,
+ const cEntity * const a_ExplodingEntity
+)
+{
+ const auto DestroyedMeta = a_Chunk.GetMeta(a_RelativePosition);
- /** Sets the block at the given position, updating surroundings. */
- static void SetBlock(cWorld & a_World, cChunk & a_Chunk, const Vector3i a_AbsolutePosition, const Vector3i a_RelativePosition, const BLOCKTYPE a_DestroyedBlock, const BLOCKTYPE a_NewBlock, const cEntity * const a_ExplodingEntity)
- {
- const auto DestroyedMeta = a_Chunk.GetMeta(a_RelativePosition);
+ // SetBlock wakes up all simulators for the area, so that water and lava flows and sand falls into the blasted holes
+ // It also is responsible for calling cBlockHandler::OnNeighborChanged to pop off blocks that fail CanBeAt
+ // An explicit call to cBlockHandler::OnBroken handles the destruction of multiblock structures
+ // References at (FS #391, GH #4418):
+ a_Chunk.SetBlock(a_RelativePosition, a_NewBlock, 0);
- // SetBlock wakes up all simulators for the area, so that water and lava flows and sand falls into the blasted holes
- // It also is responsible for calling cBlockHandler::OnNeighborChanged to pop off blocks that fail CanBeAt
- // An explicit call to cBlockHandler::OnBroken handles the destruction of multiblock structures
- // References at (FS #391, GH #4418):
- a_Chunk.SetBlock(a_RelativePosition, a_NewBlock, 0);
+ cChunkInterface Interface(a_World.GetChunkMap());
+ cBlockHandler::For(a_DestroyedBlock)
+ .OnBroken(Interface, a_World, a_AbsolutePosition, a_DestroyedBlock, DestroyedMeta, a_ExplodingEntity);
+}
- cChunkInterface Interface(a_World.GetChunkMap());
- cBlockHandler::For(a_DestroyedBlock).OnBroken(Interface, a_World, a_AbsolutePosition, a_DestroyedBlock, DestroyedMeta, a_ExplodingEntity);
+/** Work out what should happen when an explosion destroys the given block.
+Tasks include lighting TNT, dropping pickups, setting fire and flinging shrapnel according to Minecraft rules.
+OK, _mostly_ Minecraft rules. */
+static void DestroyBlock(
+ cChunk & a_Chunk,
+ const Vector3i a_Position,
+ const int a_Power,
+ const bool a_Fiery,
+ const cEntity * const a_ExplodingEntity
+)
+{
+ const auto DestroyedBlock = a_Chunk.GetBlock(a_Position);
+ if (DestroyedBlock == E_BLOCK_AIR)
+ {
+ // There's nothing left for us here, but a barren and empty land
+ // Let's go.
+ return;
}
- /** Work out what should happen when an explosion destroys the given block.
- Tasks include lighting TNT, dropping pickups, setting fire and flinging shrapnel according to Minecraft rules.
- OK, _mostly_ Minecraft rules. */
- static void DestroyBlock(cChunk & a_Chunk, const Vector3i a_Position, const int a_Power, const bool a_Fiery, const cEntity * const a_ExplodingEntity)
- {
- const auto DestroyedBlock = a_Chunk.GetBlock(a_Position);
- if (DestroyedBlock == E_BLOCK_AIR)
- {
- // There's nothing left for us here, but a barren and empty land
- // Let's go.
- return;
- }
+ auto & World = *a_Chunk.GetWorld();
+ auto & Random = GetRandomProvider();
+ const auto Absolute = cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos());
- auto & World = *a_Chunk.GetWorld();
- auto & Random = GetRandomProvider();
- const auto Absolute = cChunkDef::RelativeToAbsolute(a_Position, a_Chunk.GetPos());
+ if (DestroyedBlock == E_BLOCK_TNT) // If the block is TNT we should set it off
+ {
+ // Random fuse between 10 to 30 game ticks.
+ const int FuseTime = Random.RandInt(10, 30);
- if (DestroyedBlock == E_BLOCK_TNT) // If the block is TNT we should set it off
+ // Activate the TNT, with initial velocity and no fuse sound:
+ World.SpawnPrimedTNT(Vector3d(0.5, 0, 0.5) + Absolute, FuseTime, 1, false);
+ }
+ else if ((a_ExplodingEntity != nullptr) &&
+ (a_ExplodingEntity->IsTNT() || BlockAlwaysDrops(DestroyedBlock) || Random.RandBool(1.f / a_Power)
+ )) // For TNT explosions, destroying a block that always drops, or if RandBool, drop pickups
+ {
+ const auto DestroyedMeta = a_Chunk.GetMeta(a_Position);
+ a_Chunk.GetWorld()->SpawnItemPickups(
+ cBlockHandler::For(DestroyedBlock).ConvertToPickups(DestroyedMeta),
+ Absolute
+ );
+ }
+ else if (a_Fiery && Random.RandBool(1 / 3.0)) // 33% chance of starting fires if it can start fires
+ {
+ const auto Below = a_Position.addedY(-1);
+ if ((Below.y >= 0) && cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(Below)))
{
- // Random fuse between 10 to 30 game ticks.
- const int FuseTime = Random.RandInt(10, 30);
-
- // Activate the TNT, with initial velocity and no fuse sound:
- World.SpawnPrimedTNT(Vector3d(0.5, 0, 0.5) + Absolute, FuseTime, 1, false);
+ // Start a fire:
+ SetBlock(World, a_Chunk, Absolute, a_Position, DestroyedBlock, E_BLOCK_FIRE, a_ExplodingEntity);
+ return;
}
- else if ((a_ExplodingEntity != nullptr) && (a_ExplodingEntity->IsTNT() || BlockAlwaysDrops(DestroyedBlock) || Random.RandBool(1.f / a_Power))) // For TNT explosions, destroying a block that always drops, or if RandBool, drop pickups
+ }
+ else if (const auto Shrapnel = World.GetTNTShrapnelLevel();
+ (Shrapnel > slNone) && Random.RandBool(0)) // Currently 0% chance of flinging stuff around
+ {
+ // If the block is shrapnel-able, make a falling block entity out of it:
+ if (((Shrapnel == slAll) && cBlockInfo::FullyOccupiesVoxel(DestroyedBlock)) ||
+ ((Shrapnel == slGravityAffectedOnly) && cSandSimulator::IsAllowedBlock(DestroyedBlock)))
{
const auto DestroyedMeta = a_Chunk.GetMeta(a_Position);
- a_Chunk.GetWorld()->SpawnItemPickups(cBlockHandler::For(DestroyedBlock).ConvertToPickups(DestroyedMeta), Absolute);
+ auto FallingBlock =
+ std::make_unique<cFallingBlock>(Vector3d(0.5, 0, 0.5) + Absolute, DestroyedBlock, DestroyedMeta);
+ // TODO: correct velocity FallingBlock->SetSpeedY(40);
+ FallingBlock->Initialize(std::move(FallingBlock), World);
}
- else if (a_Fiery && Random.RandBool(1 / 3.0)) // 33% chance of starting fires if it can start fires
- {
- const auto Below = a_Position.addedY(-1);
- if ((Below.y >= 0) && cBlockInfo::FullyOccupiesVoxel(a_Chunk.GetBlock(Below)))
- {
- // Start a fire:
- SetBlock(World, a_Chunk, Absolute, a_Position, DestroyedBlock, E_BLOCK_FIRE, a_ExplodingEntity);
- return;
- }
- }
- else if (const auto Shrapnel = World.GetTNTShrapnelLevel(); (Shrapnel > slNone) && Random.RandBool(0)) // Currently 0% chance of flinging stuff around
- {
- // If the block is shrapnel-able, make a falling block entity out of it:
- if (
- ((Shrapnel == slAll) && cBlockInfo::FullyOccupiesVoxel(DestroyedBlock)) ||
- ((Shrapnel == slGravityAffectedOnly) && cSandSimulator::IsAllowedBlock(DestroyedBlock))
- )
- {
- const auto DestroyedMeta = a_Chunk.GetMeta(a_Position);
- auto FallingBlock = std::make_unique<cFallingBlock>(Vector3d(0.5, 0, 0.5) + Absolute, DestroyedBlock, DestroyedMeta);
- // TODO: correct velocity FallingBlock->SetSpeedY(40);
- FallingBlock->Initialize(std::move(FallingBlock), World);
- }
- }
-
- SetBlock(World, a_Chunk, Absolute, a_Position, DestroyedBlock, E_BLOCK_AIR, a_ExplodingEntity);
}
- /** Traces the path taken by one Explosion Lazor (tm) with given direction and intensity, that will destroy blocks until it is exhausted. */
- static void DestructionTrace(cChunk * a_Chunk, Vector3f a_Origin, const Vector3f a_Direction, const int a_Power, const bool a_Fiery, float a_Intensity, const cEntity * const a_ExplodingEntity)
- {
- // The current position the ray is at.
- auto Checkpoint = a_Origin;
+ SetBlock(World, a_Chunk, Absolute, a_Position, DestroyedBlock, E_BLOCK_AIR, a_ExplodingEntity);
+}
- // The displacement that the ray in one iteration step should travel.
- const auto Step = a_Direction.NormalizeCopy() * StepUnit;
+/** Traces the path taken by one Explosion Lazor (tm) with given direction and intensity, that will destroy blocks until
+ * it is exhausted. */
+static void DestructionTrace(
+ cChunk * a_Chunk,
+ Vector3f a_Origin,
+ const Vector3f a_Direction,
+ const int a_Power,
+ const bool a_Fiery,
+ float a_Intensity,
+ const cEntity * const a_ExplodingEntity
+)
+{
+ // The current position the ray is at.
+ auto Checkpoint = a_Origin;
+
+ // The displacement that the ray in one iteration step should travel.
+ const auto Step = a_Direction.NormalizeCopy() * StepUnit;
- // Loop until intensity runs out:
- while (a_Intensity > 0)
+ // Loop until intensity runs out:
+ while (a_Intensity > 0)
+ {
+ auto Position = Checkpoint.Floor();
+ if (!cChunkDef::IsValidHeight(Position))
{
- auto Position = Checkpoint.Floor();
- if (!cChunkDef::IsValidHeight(Position))
- {
- break;
- }
+ break;
+ }
- const auto Neighbour = a_Chunk->GetRelNeighborChunkAdjustCoords(Position);
- if ((Neighbour == nullptr) || !Neighbour->IsValid())
- {
- break;
- }
+ const auto Neighbour = a_Chunk->GetRelNeighborChunkAdjustCoords(Position);
+ if ((Neighbour == nullptr) || !Neighbour->IsValid())
+ {
+ break;
+ }
- a_Intensity -= GetExplosionAbsorption(Neighbour->GetBlock(Position));
- if (a_Intensity <= 0)
- {
- // The ray is exhausted:
- break;
- }
+ a_Intensity -= GetExplosionAbsorption(Neighbour->GetBlock(Position));
+ if (a_Intensity <= 0)
+ {
+ // The ray is exhausted:
+ break;
+ }
- DestroyBlock(*Neighbour, Position, a_Power, a_Fiery, a_ExplodingEntity);
+ DestroyBlock(*Neighbour, Position, a_Power, a_Fiery, a_ExplodingEntity);
- // Adjust coordinates to be relative to the neighbour chunk:
- Checkpoint = RebaseRelativePosition(a_Chunk->GetPos(), Neighbour->GetPos(), Checkpoint);
- a_Origin = RebaseRelativePosition(a_Chunk->GetPos(), Neighbour->GetPos(), a_Origin);
- a_Chunk = Neighbour;
+ // Adjust coordinates to be relative to the neighbour chunk:
+ Checkpoint = RebaseRelativePosition(a_Chunk->GetPos(), Neighbour->GetPos(), Checkpoint);
+ a_Origin = RebaseRelativePosition(a_Chunk->GetPos(), Neighbour->GetPos(), a_Origin);
+ a_Chunk = Neighbour;
- // Increment the simulation, weaken the ray:
- Checkpoint += Step;
- a_Intensity -= StepAttenuation;
- }
- }
-
- /** Returns a random intensity for an Explosion Lazor (tm) as a function of the explosion's power. */
- static float RandomIntensity(MTRand & a_Random, const int a_Power)
- {
- return a_Power * (0.7f + a_Random.RandReal(0.6f));
+ // Increment the simulation, weaken the ray:
+ Checkpoint += Step;
+ a_Intensity -= StepAttenuation;
}
+}
- /** Sends out Explosion Lazors (tm) originating from the given position that destroy blocks. */
- static void DamageBlocks(cChunk & a_Chunk, const Vector3f a_Position, const int a_Power, const bool a_Fiery, const cEntity * const a_ExplodingEntity)
- {
- // Oh boy... Better hope you have a hot cache, 'cos this little manoeuvre's gonna cost us 1352 raytraces in one tick...
- const int HalfSide = TraceCubeSideLength / 2;
- auto & Random = GetRandomProvider();
+/** Returns a random intensity for an Explosion Lazor (tm) as a function of the explosion's power. */
+static float RandomIntensity(MTRand & a_Random, const int a_Power)
+{
+ return a_Power * (0.7f + a_Random.RandReal(0.6f));
+}
- // The following loops implement the tracing algorithm described in http://minecraft.wiki/w/Explosion
+/** Sends out Explosion Lazors (tm) originating from the given position that destroy blocks. */
+static void DamageBlocks(
+ cChunk & a_Chunk,
+ const Vector3f a_Position,
+ const int a_Power,
+ const bool a_Fiery,
+ const cEntity * const a_ExplodingEntity
+)
+{
+ // Oh boy... Better hope you have a hot cache, 'cos this little manoeuvre's gonna cost us 1352 raytraces in one
+ // tick...
+ const int HalfSide = TraceCubeSideLength / 2;
+ auto & Random = GetRandomProvider();
- // Trace rays from the explosion centre to all points in a square of area TraceCubeSideLength * TraceCubeSideLength
- // for the top and bottom sides:
- for (float OffsetX = -HalfSide; OffsetX < HalfSide; OffsetX++)
- {
- for (float OffsetZ = -HalfSide; OffsetZ < HalfSide; OffsetZ++)
- {
- DestructionTrace(&a_Chunk, a_Position, Vector3f(OffsetX, +HalfSide, OffsetZ), a_Power, a_Fiery, RandomIntensity(Random, a_Power), a_ExplodingEntity);
- DestructionTrace(&a_Chunk, a_Position, Vector3f(OffsetX, -HalfSide, OffsetZ), a_Power, a_Fiery, RandomIntensity(Random, a_Power), a_ExplodingEntity);
- }
- }
+ // The following loops implement the tracing algorithm described in http://minecraft.wiki/w/Explosion
- // Left and right sides, avoid duplicates at top and bottom edges:
- for (float OffsetX = -HalfSide; OffsetX < HalfSide; OffsetX++)
+ // Trace rays from the explosion centre to all points in a square of area TraceCubeSideLength * TraceCubeSideLength
+ // for the top and bottom sides:
+ for (float OffsetX = -HalfSide; OffsetX < HalfSide; OffsetX++)
+ {
+ for (float OffsetZ = -HalfSide; OffsetZ < HalfSide; OffsetZ++)
{
- for (float OffsetY = -HalfSide + 1; OffsetY < HalfSide - 1; OffsetY++)
- {
- DestructionTrace(&a_Chunk, a_Position, Vector3f(OffsetX, OffsetY, +HalfSide), a_Power, a_Fiery, RandomIntensity(Random, a_Power), a_ExplodingEntity);
- DestructionTrace(&a_Chunk, a_Position, Vector3f(OffsetX, OffsetY, -HalfSide), a_Power, a_Fiery, RandomIntensity(Random, a_Power), a_ExplodingEntity);
- }
+ DestructionTrace(
+ &a_Chunk,
+ a_Position,
+ Vector3f(OffsetX, +HalfSide, OffsetZ),
+ a_Power,
+ a_Fiery,
+ RandomIntensity(Random, a_Power),
+ a_ExplodingEntity
+ );
+ DestructionTrace(
+ &a_Chunk,
+ a_Position,
+ Vector3f(OffsetX, -HalfSide, OffsetZ),
+ a_Power,
+ a_Fiery,
+ RandomIntensity(Random, a_Power),
+ a_ExplodingEntity
+ );
}
+ }
- // Front and back sides, avoid all edges:
- for (float OffsetZ = -HalfSide + 1; OffsetZ < HalfSide - 1; OffsetZ++)
+ // Left and right sides, avoid duplicates at top and bottom edges:
+ for (float OffsetX = -HalfSide; OffsetX < HalfSide; OffsetX++)
+ {
+ for (float OffsetY = -HalfSide + 1; OffsetY < HalfSide - 1; OffsetY++)
{
- for (float OffsetY = -HalfSide + 1; OffsetY < HalfSide - 1; OffsetY++)
- {
- DestructionTrace(&a_Chunk, a_Position, Vector3f(+HalfSide, OffsetY, OffsetZ), a_Power, a_Fiery, RandomIntensity(Random, a_Power), a_ExplodingEntity);
- DestructionTrace(&a_Chunk, a_Position, Vector3f(-HalfSide, OffsetY, OffsetZ), a_Power, a_Fiery, RandomIntensity(Random, a_Power), a_ExplodingEntity);
- }
+ DestructionTrace(
+ &a_Chunk,
+ a_Position,
+ Vector3f(OffsetX, OffsetY, +HalfSide),
+ a_Power,
+ a_Fiery,
+ RandomIntensity(Random, a_Power),
+ a_ExplodingEntity
+ );
+ DestructionTrace(
+ &a_Chunk,
+ a_Position,
+ Vector3f(OffsetX, OffsetY, -HalfSide),
+ a_Power,
+ a_Fiery,
+ RandomIntensity(Random, a_Power),
+ a_ExplodingEntity
+ );
}
}
- /** Sends an explosion packet to all clients in the given chunk. */
- static void LagTheClient(cChunk & a_Chunk, const Vector3f a_Position, const int a_Power)
+ // Front and back sides, avoid all edges:
+ for (float OffsetZ = -HalfSide + 1; OffsetZ < HalfSide - 1; OffsetZ++)
{
- for (const auto Client : a_Chunk.GetAllClients())
+ for (float OffsetY = -HalfSide + 1; OffsetY < HalfSide - 1; OffsetY++)
{
- Client->SendExplosion(a_Position, static_cast<float>(a_Power));
+ DestructionTrace(
+ &a_Chunk,
+ a_Position,
+ Vector3f(+HalfSide, OffsetY, OffsetZ),
+ a_Power,
+ a_Fiery,
+ RandomIntensity(Random, a_Power),
+ a_ExplodingEntity
+ );
+ DestructionTrace(
+ &a_Chunk,
+ a_Position,
+ Vector3f(-HalfSide, OffsetY, OffsetZ),
+ a_Power,
+ a_Fiery,
+ RandomIntensity(Random, a_Power),
+ a_ExplodingEntity
+ );
}
}
+}
- void Kaboom(cWorld & a_World, const Vector3f a_Position, const int a_Power, const bool a_Fiery, const cEntity * const a_ExplodingEntity)
+/** Sends an explosion packet to all clients in the given chunk. */
+static void LagTheClient(cChunk & a_Chunk, const Vector3f a_Position, const int a_Power)
+{
+ for (const auto Client : a_Chunk.GetAllClients())
{
- a_World.DoWithChunkAt(a_Position.Floor(), [a_Position, a_Power, a_Fiery, a_ExplodingEntity](cChunk & a_Chunk)
+ Client->SendExplosion(a_Position, static_cast<float>(a_Power));
+ }
+}
+
+void Kaboom(
+ cWorld & a_World,
+ const Vector3f a_Position,
+ const int a_Power,
+ const bool a_Fiery,
+ const cEntity * const a_ExplodingEntity
+)
+{
+ a_World.DoWithChunkAt(
+ a_Position.Floor(),
+ [a_Position, a_Power, a_Fiery, a_ExplodingEntity](cChunk & a_Chunk)
{
LagTheClient(a_Chunk, a_Position, a_Power);
DamageEntities(a_Chunk, a_Position, a_Power);
- DamageBlocks(a_Chunk, AbsoluteToRelative(a_Position, a_Chunk.GetPos()), a_Power, a_Fiery, a_ExplodingEntity);
+ DamageBlocks(
+ a_Chunk,
+ AbsoluteToRelative(a_Position, a_Chunk.GetPos()),
+ a_Power,
+ a_Fiery,
+ a_ExplodingEntity
+ );
return false;
- });
- }
+ }
+ );
}
+} // namespace Explodinator