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,
|
||||
dtEnderPearl, // Thrown an ender pearl, teleported by it
|
||||
dtAdmin, // Damage applied by an admin command
|
||||
dtExplosion, // Damage applied by an explosion
|
||||
|
||||
// Some common synonyms:
|
||||
dtPawnAttack = dtAttack,
|
||||
|
152
src/ChunkMap.cpp
152
src/ChunkMap.cpp
@ -15,6 +15,9 @@
|
||||
#include "Blocks/BlockHandler.h"
|
||||
#include "MobCensus.h"
|
||||
#include "MobSpawner.h"
|
||||
#include "BoundingBox.h"
|
||||
|
||||
#include "Entities/Pickup.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <cstdlib> // abs
|
||||
@ -1624,49 +1627,52 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool ShouldDestroyBlocks = true;
|
||||
|
||||
// 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:
|
||||
case E_BLOCK_STATIONARY_WATER:
|
||||
case E_BLOCK_LAVA:
|
||||
case E_BLOCK_STATIONARY_LAVA:
|
||||
{
|
||||
return;
|
||||
}
|
||||
ShouldDestroyBlocks = false;
|
||||
}
|
||||
|
||||
cBlockArea area;
|
||||
|
||||
int ExplosionSizeInt = (int)ceil(a_ExplosionSize);
|
||||
int ExplosionSizeSq = ExplosionSizeInt * ExplosionSizeInt;
|
||||
|
||||
int bx = (int)floor(a_BlockX);
|
||||
int by = (int)floor(a_BlockY);
|
||||
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 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
|
||||
continue;
|
||||
}
|
||||
for (int z = -ExplosionSizeInt; z < ExplosionSizeInt; z++)
|
||||
{
|
||||
if ((x * x + y * y + z * z) > ExplosionSizeSq)
|
||||
if ((by + y >= cChunkDef::Height) || (by + y < 0))
|
||||
{
|
||||
// Too far away
|
||||
// Outside of the world
|
||||
continue;
|
||||
}
|
||||
|
||||
BLOCKTYPE Block = area.GetBlockType(bx + x, by + y, bz + z);
|
||||
switch (Block)
|
||||
for (int z = -ExplosionSizeInt; z < ExplosionSizeInt; z++)
|
||||
{
|
||||
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:
|
||||
{
|
||||
// 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);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case E_BLOCK_STATIONARY_LAVA:
|
||||
{
|
||||
// Turn into simulated lava:
|
||||
area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_LAVA);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case E_BLOCK_AIR:
|
||||
{
|
||||
// No pickups for air
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
{
|
||||
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);
|
||||
|
||||
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);
|
||||
a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z));
|
||||
}
|
||||
} // switch (BlockType)
|
||||
} // for z
|
||||
} // for y
|
||||
} // for x
|
||||
area.Write(m_World, bx - ExplosionSizeInt, MinY, bz - ExplosionSizeInt);
|
||||
} // switch (BlockType)
|
||||
} // for z
|
||||
} // for y
|
||||
} // for x
|
||||
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):
|
||||
WakeUpSimulatorsInArea(
|
||||
|
Loading…
Reference in New Issue
Block a user