TNT improvements
+ Added entity damage + Added entity propulsion * Fixed #67 and fixed #230
This commit is contained in:
parent
275035eb70
commit
e56d41175b
@ -801,6 +801,7 @@ enum eDamageType
|
|||||||
dtPotionOfHarming,
|
dtPotionOfHarming,
|
||||||
dtEnderPearl, // Thrown an ender pearl, teleported by it
|
dtEnderPearl, // Thrown an ender pearl, teleported by it
|
||||||
dtAdmin, // Damage applied by an admin command
|
dtAdmin, // Damage applied by an admin command
|
||||||
|
dtExplosion, // Damage applied by an explosion
|
||||||
|
|
||||||
// Some common synonyms:
|
// Some common synonyms:
|
||||||
dtPawnAttack = dtAttack,
|
dtPawnAttack = dtAttack,
|
||||||
|
152
src/ChunkMap.cpp
152
src/ChunkMap.cpp
@ -15,6 +15,9 @@
|
|||||||
#include "Blocks/BlockHandler.h"
|
#include "Blocks/BlockHandler.h"
|
||||||
#include "MobCensus.h"
|
#include "MobCensus.h"
|
||||||
#include "MobSpawner.h"
|
#include "MobSpawner.h"
|
||||||
|
#include "BoundingBox.h"
|
||||||
|
|
||||||
|
#include "Entities/Pickup.h"
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <cstdlib> // abs
|
#include <cstdlib> // abs
|
||||||
@ -1624,49 +1627,52 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ShouldDestroyBlocks = true;
|
||||||
|
|
||||||
// Don't explode if the explosion center is inside a liquid block:
|
// Don't explode if the explosion center is inside a liquid block:
|
||||||
switch (m_World->GetBlock((int)floor(a_BlockX), (int)floor(a_BlockY), (int)floor(a_BlockZ)))
|
if (IsBlockLiquid(m_World->GetBlock((int)floor(a_BlockX), (int)floor(a_BlockY), (int)floor(a_BlockZ))))
|
||||||
{
|
{
|
||||||
case E_BLOCK_WATER:
|
ShouldDestroyBlocks = false;
|
||||||
case E_BLOCK_STATIONARY_WATER:
|
|
||||||
case E_BLOCK_LAVA:
|
|
||||||
case E_BLOCK_STATIONARY_LAVA:
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cBlockArea area;
|
int ExplosionSizeInt = (int)ceil(a_ExplosionSize);
|
||||||
|
int ExplosionSizeSq = ExplosionSizeInt * ExplosionSizeInt;
|
||||||
|
|
||||||
int bx = (int)floor(a_BlockX);
|
int bx = (int)floor(a_BlockX);
|
||||||
int by = (int)floor(a_BlockY);
|
int by = (int)floor(a_BlockY);
|
||||||
int bz = (int)floor(a_BlockZ);
|
int bz = (int)floor(a_BlockZ);
|
||||||
int ExplosionSizeInt = (int) ceil(a_ExplosionSize);
|
|
||||||
int ExplosionSizeSq = ExplosionSizeInt * ExplosionSizeInt;
|
|
||||||
a_BlocksAffected.reserve(8 * ExplosionSizeInt * ExplosionSizeInt * ExplosionSizeInt);
|
|
||||||
int MinY = std::max((int)floor(a_BlockY - ExplosionSizeInt), 0);
|
int MinY = std::max((int)floor(a_BlockY - ExplosionSizeInt), 0);
|
||||||
int MaxY = std::min((int)ceil(a_BlockY + ExplosionSizeInt), cChunkDef::Height - 1);
|
int MaxY = std::min((int)ceil(a_BlockY + ExplosionSizeInt), cChunkDef::Height - 1);
|
||||||
area.Read(m_World, bx - ExplosionSizeInt, (int)ceil(a_BlockX + ExplosionSizeInt), MinY, MaxY, bz - ExplosionSizeInt, (int)ceil(a_BlockZ + ExplosionSizeInt));
|
|
||||||
for (int x = -ExplosionSizeInt; x < ExplosionSizeInt; x++)
|
if (ShouldDestroyBlocks)
|
||||||
{
|
{
|
||||||
for (int y = -ExplosionSizeInt; y < ExplosionSizeInt; y++)
|
cBlockArea area;
|
||||||
|
|
||||||
|
a_BlocksAffected.reserve(8 * ExplosionSizeInt * ExplosionSizeInt * ExplosionSizeInt);
|
||||||
|
|
||||||
|
area.Read(m_World, bx - ExplosionSizeInt, (int)ceil(a_BlockX + ExplosionSizeInt), MinY, MaxY, bz - ExplosionSizeInt, (int)ceil(a_BlockZ + ExplosionSizeInt));
|
||||||
|
for (int x = -ExplosionSizeInt; x < ExplosionSizeInt; x++)
|
||||||
{
|
{
|
||||||
if ((by + y >= cChunkDef::Height) || (by + y < 0))
|
for (int y = -ExplosionSizeInt; y < ExplosionSizeInt; y++)
|
||||||
{
|
{
|
||||||
// Outside of the world
|
if ((by + y >= cChunkDef::Height) || (by + y < 0))
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (int z = -ExplosionSizeInt; z < ExplosionSizeInt; z++)
|
|
||||||
{
|
|
||||||
if ((x * x + y * y + z * z) > ExplosionSizeSq)
|
|
||||||
{
|
{
|
||||||
// Too far away
|
// Outside of the world
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
for (int z = -ExplosionSizeInt; z < ExplosionSizeInt; z++)
|
||||||
BLOCKTYPE Block = area.GetBlockType(bx + x, by + y, bz + z);
|
|
||||||
switch (Block)
|
|
||||||
{
|
{
|
||||||
|
if ((x * x + y * y + z * z) > ExplosionSizeSq)
|
||||||
|
{
|
||||||
|
// Too far away
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLOCKTYPE Block = area.GetBlockType(bx + x, by + y, bz + z);
|
||||||
|
switch (Block)
|
||||||
|
{
|
||||||
case E_BLOCK_TNT:
|
case E_BLOCK_TNT:
|
||||||
{
|
{
|
||||||
// Activate the TNT, with a random fuse between 10 to 30 game ticks
|
// Activate the TNT, with a random fuse between 10 to 30 game ticks
|
||||||
@ -1691,20 +1697,20 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
|
|||||||
area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_WATER);
|
area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_WATER);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case E_BLOCK_STATIONARY_LAVA:
|
case E_BLOCK_STATIONARY_LAVA:
|
||||||
{
|
{
|
||||||
// Turn into simulated lava:
|
// Turn into simulated lava:
|
||||||
area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_LAVA);
|
area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_LAVA);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case E_BLOCK_AIR:
|
case E_BLOCK_AIR:
|
||||||
{
|
{
|
||||||
// No pickups for air
|
// No pickups for air
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
if (m_World->GetTickRandomNumber(100) <= 25) // 25% chance of pickups
|
if (m_World->GetTickRandomNumber(100) <= 25) // 25% chance of pickups
|
||||||
@ -1713,16 +1719,88 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
|
|||||||
cBlockHandler * Handler = BlockHandler(Block);
|
cBlockHandler * Handler = BlockHandler(Block);
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
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));
|
||||||
}
|
}
|
||||||
} // switch (BlockType)
|
} // switch (BlockType)
|
||||||
} // for z
|
} // for z
|
||||||
} // for y
|
} // for y
|
||||||
} // for x
|
} // for x
|
||||||
area.Write(m_World, bx - ExplosionSizeInt, MinY, bz - ExplosionSizeInt);
|
area.Write(m_World, bx - ExplosionSizeInt, MinY, bz - ExplosionSizeInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
class cTNTDamageCallback :
|
||||||
|
public cEntityCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cTNTDamageCallback(cBoundingBox & a_bbTNT, Vector3d a_ExplosionPos, int a_ExplosionSize, int a_ExplosionSizeSq) :
|
||||||
|
m_bbTNT(a_bbTNT),
|
||||||
|
m_ExplosionPos(a_ExplosionPos),
|
||||||
|
m_ExplosionSize(a_ExplosionSize),
|
||||||
|
m_ExplosionSizeSq(a_ExplosionSizeSq)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Item(cEntity * a_Entity) override
|
||||||
|
{
|
||||||
|
if (a_Entity->IsPickup())
|
||||||
|
{
|
||||||
|
if (((cPickup *)a_Entity)->GetAge() < 20) // If pickup age is smaller than one second, it is invincible
|
||||||
|
{
|
||||||
|
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
|
||||||
|
{
|
||||||
|
Vector3d AbsoluteEntityPos(abs(EntityPos.x), abs(EntityPos.y), abs(EntityPos.z));
|
||||||
|
Vector3d MaxExplosionBoundary(m_ExplosionSizeSq, m_ExplosionSizeSq, m_ExplosionSizeSq);
|
||||||
|
|
||||||
|
AbsoluteEntityPos -= m_ExplosionPos;
|
||||||
|
AbsoluteEntityPos = MaxExplosionBoundary - AbsoluteEntityPos;
|
||||||
|
|
||||||
|
double FinalDamage = ((AbsoluteEntityPos.x + AbsoluteEntityPos.y + AbsoluteEntityPos.z) / 3) * m_ExplosionSize;
|
||||||
|
FinalDamage = a_Entity->GetMaxHealth() - abs(FinalDamage);
|
||||||
|
if (FinalDamage > a_Entity->GetMaxHealth())
|
||||||
|
FinalDamage = a_Entity->GetMaxHealth();
|
||||||
|
else if (FinalDamage < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!a_Entity->IsTNT())
|
||||||
|
{
|
||||||
|
a_Entity->TakeDamage(dtExplosion, NULL, (int)FinalDamage, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3d distance_explosion = a_Entity->GetPosition() - m_ExplosionPos;
|
||||||
|
if (distance_explosion.SqrLength() < 4096.0)
|
||||||
|
{
|
||||||
|
distance_explosion.Normalize();
|
||||||
|
distance_explosion *= m_ExplosionSizeSq;
|
||||||
|
|
||||||
|
a_Entity->AddSpeed(distance_explosion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
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), a_ExplosionSize, ExplosionSizeSq);
|
||||||
|
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):
|
||||||
WakeUpSimulatorsInArea(
|
WakeUpSimulatorsInArea(
|
||||||
|
Loading…
Reference in New Issue
Block a user