Merged branch 'Projectiles'.
This commit is contained in:
commit
d31142811d
@ -1,6 +1,5 @@
|
||||
-- Global variables
|
||||
PLUGIN = {}; -- Reference to own plugin object
|
||||
|
||||
-- Global variables
|
||||
g_DropSpensersToActivate = {}; -- A list of dispensers and droppers (as {World, X, Y Z} quadruplets) that are to be activated every tick
|
||||
g_HungerReportTick = 10;
|
||||
g_ShowFoodStats = false; -- When true, each player's food stats are sent to them every 10 ticks
|
||||
@ -11,8 +10,6 @@ g_ShowFoodStats = false; -- When true, each player's food stats are sent to the
|
||||
|
||||
|
||||
function Initialize(Plugin)
|
||||
PLUGIN = Plugin
|
||||
|
||||
Plugin:SetName("Debuggers")
|
||||
Plugin:SetVersion(1)
|
||||
|
||||
@ -46,6 +43,7 @@ function Initialize(Plugin)
|
||||
PluginManager:BindCommand("/ench", "debuggers", HandleEnchCmd, "- Provides an instant dummy enchantment window");
|
||||
PluginManager:BindCommand("/fs", "debuggers", HandleFoodStatsCmd, "- Turns regular foodstats message on or off");
|
||||
PluginManager:BindCommand("/arr", "debuggers", HandleArrowCmd, "- Creates an arrow going away from the player");
|
||||
PluginManager:BindCommand("/fb", "debuggers", HandleFireballCmd, "- Creates a ghast fireball as if shot by the player");
|
||||
|
||||
-- Enable the following line for BlockArea / Generator interface testing:
|
||||
-- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED);
|
||||
@ -480,6 +478,7 @@ end
|
||||
|
||||
|
||||
function OnWorldTick(a_World, a_Dt)
|
||||
-- Report food stats, if switched on:
|
||||
local Tick = a_World:GetWorldAge();
|
||||
if (not(g_ShowFoodStats) or (math.mod(Tick, 10) ~= 0)) then
|
||||
return false;
|
||||
@ -825,3 +824,18 @@ end
|
||||
|
||||
|
||||
|
||||
|
||||
function HandleFireballCmd(a_Split, a_Player)
|
||||
local World = a_Player:GetWorld();
|
||||
local Pos = a_Player:GetEyePosition();
|
||||
local Speed = a_Player:GetLookVector();
|
||||
Speed:Normalize();
|
||||
Pos = Pos + Speed * 2;
|
||||
|
||||
World:CreateProjectile(Pos.x, Pos.y, Pos.z, cProjectileEntity.pkGhastFireball, a_Player, Speed * 10);
|
||||
return true;
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
2
Tools/AnvilStats/.gitignore
vendored
2
Tools/AnvilStats/.gitignore
vendored
@ -6,4 +6,4 @@ Release/
|
||||
Profiling
|
||||
*.png
|
||||
world/
|
||||
*.html
|
||||
*.html
|
||||
|
@ -232,6 +232,18 @@ enum
|
||||
|
||||
|
||||
|
||||
AString PrintableAbsIntTriplet(int a_X, int a_Y, int a_Z, double a_Divisor = 32)
|
||||
{
|
||||
return Printf("<%d, %d, %d> ~ {%.02f, %.02f, %.02f}",
|
||||
a_X, a_Y, a_Z,
|
||||
(double)a_X / a_Divisor, (double)a_Y / a_Divisor, (double)a_Z / a_Divisor
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cConnection:
|
||||
|
||||
@ -1481,7 +1493,7 @@ bool cConnection::HandleServerEntityRelativeMove(void)
|
||||
HANDLE_SERVER_PACKET_READ(ReadByte, Byte, dz);
|
||||
Log("Received a PACKET_ENTITY_RELATIVE_MOVE from the server:");
|
||||
Log(" EntityID = %d", EntityID);
|
||||
Log(" RelMove = <%d, %d, %d>", dx, dy, dz);
|
||||
Log(" RelMove = %s", PrintableAbsIntTriplet(dx, dy, dz).c_str());
|
||||
COPY_TO_CLIENT();
|
||||
return true;
|
||||
}
|
||||
@ -1500,7 +1512,7 @@ bool cConnection::HandleServerEntityRelativeMoveLook(void)
|
||||
HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch);
|
||||
Log("Received a PACKET_ENTITY_RELATIVE_MOVE_LOOK from the server:");
|
||||
Log(" EntityID = %d", EntityID);
|
||||
Log(" RelMove = <%d, %d, %d>", dx, dy, dz);
|
||||
Log(" RelMove = %s", PrintableAbsIntTriplet(dx, dy, dz).c_str());
|
||||
Log(" Yaw = %d", Yaw);
|
||||
Log(" Pitch = %d", Pitch);
|
||||
COPY_TO_CLIENT();
|
||||
@ -1529,14 +1541,14 @@ bool cConnection::HandleServerEntityStatus(void)
|
||||
bool cConnection::HandleServerEntityTeleport(void)
|
||||
{
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, EntityID);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockX);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockY);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, BlockZ);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, AbsX);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, AbsY);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, AbsZ);
|
||||
HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw);
|
||||
HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Pitch);
|
||||
Log("Received a PACKET_ENTITY_TELEPORT from the server:");
|
||||
Log(" EntityID = %d", EntityID);
|
||||
Log(" Pos = {%d, %d, %d}", BlockX, BlockY, BlockZ);
|
||||
Log(" Pos = (%d, %d, %d) ~ {%.02f, %.02f, %.02f}", AbsX, AbsY, AbsZ, (double)AbsX / 32, (double)AbsY / 32, (double)AbsZ / 32);
|
||||
Log(" Yaw = %d", Yaw);
|
||||
Log(" Pitch = %d", Pitch);
|
||||
COPY_TO_CLIENT();
|
||||
@ -1555,7 +1567,7 @@ bool cConnection::HandleServerEntityVelocity(void)
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, VelocityZ);
|
||||
Log("Received a PACKET_ENTITY_VELOCITY from the server:");
|
||||
Log(" EntityID = %d", EntityID);
|
||||
Log(" Velocity = <%d, %d, %d>", VelocityX, VelocityY, VelocityZ);
|
||||
Log(" Velocity = %s", PrintableAbsIntTriplet(VelocityX, VelocityY, VelocityZ, 8000).c_str());
|
||||
COPY_TO_CLIENT();
|
||||
return true;
|
||||
}
|
||||
@ -1996,9 +2008,9 @@ bool cConnection::HandleServerSpawnMob(void)
|
||||
Log("Received a PACKET_SPAWN_MOB from the server:");
|
||||
Log(" EntityID = %d", EntityID);
|
||||
Log(" MobType = %d", MobType);
|
||||
Log(" Pos = <%d, %d, %d> ~ {%d, %d, %d}", PosX, PosY, PosZ, PosX / 32, PosY / 32, PosZ / 32);
|
||||
Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str());
|
||||
Log(" Angles = [%d, %d, %d]", Yaw, Pitch, HeadYaw);
|
||||
Log(" Velocity = <%d, %d, %d>", VelocityX, VelocityY, VelocityZ);
|
||||
Log(" Velocity = %s", PrintableAbsIntTriplet(VelocityX, VelocityY, VelocityZ, 8000).c_str());
|
||||
Log(" Metadata, length = %d (0x%x):\n%s", Metadata.length(), Metadata.length(), HexDump.c_str());
|
||||
LogMetadata(Metadata, 4);
|
||||
COPY_TO_CLIENT();
|
||||
@ -2029,7 +2041,7 @@ bool cConnection::HandleServerSpawnNamedEntity(void)
|
||||
Log("Received a PACKET_SPAWN_NAMED_ENTITY from the server:");
|
||||
Log(" EntityID = %d (0x%x)", EntityID, EntityID);
|
||||
Log(" Name = %s", EntityName.c_str());
|
||||
Log(" Pos = <%d, %d, %d> ~ {%d, %d, %d}", PosX, PosY, PosZ, PosX / 32, PosY / 32, PosZ / 32);
|
||||
Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str());
|
||||
Log(" Rotation = <yaw %d, pitch %d>", Yaw, Pitch);
|
||||
Log(" CurrentItem = %d", CurrentItem);
|
||||
Log(" Metadata, length = %d (0x%x):\n%s", Metadata.length(), Metadata.length(), HexDump.c_str());
|
||||
@ -2102,12 +2114,12 @@ bool cConnection::HandleServerSpawnObjectVehicle(void)
|
||||
Log("Received a PACKET_SPAWN_OBJECT_VEHICLE from the server:");
|
||||
Log(" EntityID = %d (0x%x)", EntityID, EntityID);
|
||||
Log(" ObjType = %d (0x%x)", ObjType, ObjType);
|
||||
Log(" Pos = <%d, %d, %d> ~ {%d, %d, %d}", PosX, PosY, PosZ, PosX / 32, PosY / 32, PosZ / 32);
|
||||
Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str());
|
||||
Log(" Rotation = <yaw %d, pitch %d>", Yaw, Pitch);
|
||||
Log(" DataIndicator = %d (0x%x)", DataIndicator, DataIndicator);
|
||||
if (DataIndicator != 0)
|
||||
{
|
||||
Log(" Velocity = <%d, %d, %d>", VelocityX, VelocityY, VelocityZ);
|
||||
Log(" Velocity = %s", PrintableAbsIntTriplet(VelocityX, VelocityY, VelocityZ, 8000).c_str());
|
||||
DataLog(ExtraData.data(), ExtraData.size(), " ExtraData size = %d:", ExtraData.size());
|
||||
}
|
||||
COPY_TO_CLIENT();
|
||||
@ -2129,7 +2141,7 @@ bool cConnection::HandleServerSpawnPainting(void)
|
||||
Log("Received a PACKET_SPAWN_PAINTING from the server:");
|
||||
Log(" EntityID = %d", EntityID);
|
||||
Log(" ImageName = \"%s\"", ImageName.c_str());
|
||||
Log(" Pos = <%d, %d, %d> ~ {%d, %d, %d}", PosX, PosY, PosZ, PosX / 32, PosY / 32, PosZ / 32);
|
||||
Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str());
|
||||
Log(" Direction = %d", Direction);
|
||||
COPY_TO_CLIENT();
|
||||
return true;
|
||||
@ -2156,7 +2168,7 @@ bool cConnection::HandleServerSpawnPickup(void)
|
||||
Log("Received a PACKET_SPAWN_PICKUP from the server:");
|
||||
Log(" EntityID = %d", EntityID);
|
||||
Log(" Item = %s", ItemDesc.c_str());
|
||||
Log(" Pos = <%d, %d, %d> ~ {%d, %d, %d}", PosX, PosY, PosZ, PosX / 32, PosY / 32, PosZ / 32);
|
||||
Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str());
|
||||
Log(" Angles = [%d, %d, %d]", Rotation, Pitch, Roll);
|
||||
COPY_TO_CLIENT();
|
||||
return true;
|
||||
|
@ -386,6 +386,14 @@
|
||||
RelativePath="..\source\BlockTracer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\BoundingBox.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\BoundingBox.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\ByteBuffer.cpp"
|
||||
>
|
||||
|
@ -53,6 +53,7 @@ $cfile "Vector3d.h"
|
||||
$cfile "Vector3i.h"
|
||||
$cfile "Matrix4f.h"
|
||||
$cfile "Cuboid.h"
|
||||
$cfile "BoundingBox.h"
|
||||
$cfile "Tracer.h"
|
||||
$cfile "Group.h"
|
||||
$cfile "BlockArea.h"
|
||||
|
1227
source/Bindings.cpp
1227
source/Bindings.cpp
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
** Lua binding: AllToLua
|
||||
** Generated automatically by tolua++-1.0.92 on 09/01/13 14:42:05.
|
||||
** Generated automatically by tolua++-1.0.92 on 09/07/13 22:05:19.
|
||||
*/
|
||||
|
||||
/* Exported function */
|
||||
|
@ -419,6 +419,7 @@ AString DamageTypeToString(eDamageType a_DamageType)
|
||||
switch (a_DamageType)
|
||||
{
|
||||
case dtAttack: return "dtAttack";
|
||||
case dtRangedAttack: return "dtRangedAttack";
|
||||
case dtLightning: return "dtLightning";
|
||||
case dtFalling: return "dtFalling";
|
||||
case dtDrowning: return "dtDrowning";
|
||||
@ -463,6 +464,7 @@ eDamageType StringToDamageType(const AString & a_DamageTypeString)
|
||||
{
|
||||
// Cannonical names:
|
||||
{ dtAttack, "dtAttack"},
|
||||
{ dtRangedAttack, "dtRangedAttack"},
|
||||
{ dtLightning, "dtLightning"},
|
||||
{ dtFalling, "dtFalling"},
|
||||
{ dtDrowning, "dtDrowning"},
|
||||
@ -478,23 +480,26 @@ eDamageType StringToDamageType(const AString & a_DamageTypeString)
|
||||
{ dtAdmin, "dtAdmin"},
|
||||
|
||||
// Common synonyms:
|
||||
{ dtPawnAttack, "dtAttack"},
|
||||
{ dtEntityAttack, "dtAttack"},
|
||||
{ dtMob, "dtAttack"},
|
||||
{ dtMobAttack, "dtAttack"},
|
||||
{ dtFall, "dtFalling"},
|
||||
{ dtDrown, "dtDrowning"},
|
||||
{ dtSuffocation, "dtSuffocating"},
|
||||
{ dtStarvation, "dtStarving"},
|
||||
{ dtHunger, "dtStarving"},
|
||||
{ dtCactus, "dtCactusContact"},
|
||||
{ dtCactuses, "dtCactusContact"},
|
||||
{ dtCacti, "dtCactusContact"},
|
||||
{ dtLava, "dtLavaContact"},
|
||||
{ dtPoison, "dtPoisoning"},
|
||||
{ dtBurning, "dtOnFire"},
|
||||
{ dtInFire, "dtFireContact"},
|
||||
{ dtPlugin, "dtAdmin"},
|
||||
{ dtAttack, "dtPawnAttack"},
|
||||
{ dtAttack, "dtEntityAttack"},
|
||||
{ dtAttack, "dtMob"},
|
||||
{ dtAttack, "dtMobAttack"},
|
||||
{ dtRangedAttack, "dtArrowAttack"},
|
||||
{ dtRangedAttack, "dtArrow"},
|
||||
{ dtRangedAttack, "dtProjectile"},
|
||||
{ dtFalling, "dtFall"},
|
||||
{ dtDrowning, "dtDrown"},
|
||||
{ dtSuffocating, "dtSuffocation"},
|
||||
{ dtStarving, "dtStarvation"},
|
||||
{ dtStarving, "dtHunger"},
|
||||
{ dtCactusContact, "dtCactus"},
|
||||
{ dtCactusContact, "dtCactuses"},
|
||||
{ dtCactusContact, "dtCacti"},
|
||||
{ dtLavaContact, "dtLava"},
|
||||
{ dtPoisoning, "dtPoison"},
|
||||
{ dtOnFire, "dtBurning"},
|
||||
{ dtFireContact, "dtInFire"},
|
||||
{ dtAdmin, "dtPlugin"},
|
||||
} ;
|
||||
for (int i = 0; i < ARRAYCOUNT(DamageTypeMap); i++)
|
||||
{
|
||||
|
@ -659,6 +659,7 @@ enum eDamageType
|
||||
{
|
||||
// Canonical names for the types (as documented in the plugin wiki):
|
||||
dtAttack, // Being attacked by a mob
|
||||
dtRangedAttack, // Being attacked by a projectile, possibly from a mob
|
||||
dtLightning, // Hit by a lightning strike
|
||||
dtFalling, // Falling down; dealt when hitting the ground
|
||||
dtDrowning, // Drowning in water / lava
|
||||
@ -671,6 +672,7 @@ enum eDamageType
|
||||
dtFireContact, // Standing inside a fire block
|
||||
dtInVoid, // Falling into the Void (Y < 0)
|
||||
dtPotionOfHarming,
|
||||
dtEnderPearl, // Thrown an ender pearl, teleported by it
|
||||
dtAdmin, // Damage applied by an admin command
|
||||
|
||||
// Some common synonyms:
|
||||
@ -678,6 +680,9 @@ enum eDamageType
|
||||
dtEntityAttack = dtAttack,
|
||||
dtMob = dtAttack,
|
||||
dtMobAttack = dtAttack,
|
||||
dtArrowAttack = dtRangedAttack,
|
||||
dtArrow = dtRangedAttack,
|
||||
dtProjectile = dtRangedAttack,
|
||||
dtFall = dtFalling,
|
||||
dtDrown = dtDrowning,
|
||||
dtSuffocation = dtSuffocating,
|
||||
|
@ -56,7 +56,7 @@ void cBlockBedHandler::OnUse(cWorld *a_World, cPlayer *a_Player, int a_BlockX, i
|
||||
if (a_World->GetDimension() != dimOverworld)
|
||||
{
|
||||
Vector3i Coords(a_BlockX, a_BlockY, a_BlockZ);
|
||||
a_World->DoExplosiontAt(5, a_BlockX, a_BlockY, a_BlockZ, true, esBed, &Coords);
|
||||
a_World->DoExplosionAt(5, a_BlockX, a_BlockY, a_BlockZ, true, esBed, &Coords);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
331
source/BoundingBox.cpp
Normal file
331
source/BoundingBox.cpp
Normal file
@ -0,0 +1,331 @@
|
||||
|
||||
// BoundingBox.cpp
|
||||
|
||||
// Implements the cBoundingBox class representing an axis-aligned bounding box with floatingpoint coords
|
||||
|
||||
#include "Globals.h"
|
||||
#include "BoundingBox.h"
|
||||
#include "Defines.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
/// A simple self-test that is executed on program start, used to verify bbox functionality
|
||||
class SelfTest
|
||||
{
|
||||
public:
|
||||
SelfTest(void)
|
||||
{
|
||||
Vector3d Min(1, 1, 1);
|
||||
Vector3d Max(2, 2, 2);
|
||||
Vector3d LineDefs[] =
|
||||
{
|
||||
Vector3d(1.5, 4, 1.5), Vector3d(1.5, 3, 1.5), // Should intersect at 2, face 1 (YP)
|
||||
Vector3d(1.5, 0, 1.5), Vector3d(1.5, 4, 1.5), // Should intersect at 0.25, face 0 (YM)
|
||||
Vector3d(0, 0, 0), Vector3d(2, 2, 2), // Should intersect at 0.5, face 0, 3 or 5 (anyM)
|
||||
Vector3d(0.999, 0, 1.5), Vector3d(0.999, 4, 1.5), // Should not intersect
|
||||
Vector3d(1.999, 0, 1.5), Vector3d(1.999, 4, 1.5), // Should intersect at 0.25, face 0 (YM)
|
||||
Vector3d(2.001, 0, 1.5), Vector3d(2.001, 4, 1.5), // Should not intersect
|
||||
} ;
|
||||
for (int i = 0; i < ARRAYCOUNT(LineDefs) / 2; i++)
|
||||
{
|
||||
double LineCoeff;
|
||||
char Face;
|
||||
Vector3d Line1 = LineDefs[2 * i];
|
||||
Vector3d Line2 = LineDefs[2 * i + 1];
|
||||
bool res = cBoundingBox::CalcLineIntersection(Min, Max, Line1, Line2, LineCoeff, Face);
|
||||
printf("LineIntersection({%.02f, %.02f, %.02f}, {%.02f, %.02f, %.02f}) -> %d, %.05f, %d\n",
|
||||
Line1.x, Line1.y, Line1.z,
|
||||
Line2.x, Line2.y, Line2.z,
|
||||
res ? 1 : 0, LineCoeff, Face
|
||||
);
|
||||
} // for i - LineDefs[]
|
||||
printf("BoundingBox selftest complete.");
|
||||
}
|
||||
} Test;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cBoundingBox::cBoundingBox(double a_MinX, double a_MaxX, double a_MinY, double a_MaxY, double a_MinZ, double a_MaxZ) :
|
||||
m_Min(a_MinX, a_MinY, a_MinZ),
|
||||
m_Max(a_MaxX, a_MaxY, a_MaxZ)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cBoundingBox::cBoundingBox(const Vector3d & a_Min, const Vector3d & a_Max) :
|
||||
m_Min(a_Min),
|
||||
m_Max(a_Max)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cBoundingBox::cBoundingBox(const Vector3d & a_Pos, double a_Radius, double a_Height) :
|
||||
m_Min(a_Pos.x - a_Radius, a_Pos.y, a_Pos.z - a_Radius),
|
||||
m_Max(a_Pos.x + a_Radius, a_Pos.y + a_Height, a_Pos.z + a_Radius)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cBoundingBox::cBoundingBox(const cBoundingBox & a_Orig) :
|
||||
m_Min(a_Orig.m_Min),
|
||||
m_Max(a_Orig.m_Max)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cBoundingBox::Move(double a_OffX, double a_OffY, double a_OffZ)
|
||||
{
|
||||
m_Min.x += a_OffX;
|
||||
m_Min.y += a_OffY;
|
||||
m_Min.z += a_OffZ;
|
||||
m_Max.x += a_OffX;
|
||||
m_Max.y += a_OffY;
|
||||
m_Max.z += a_OffZ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cBoundingBox::Move(const Vector3d & a_Off)
|
||||
{
|
||||
m_Min.x += a_Off.x;
|
||||
m_Min.y += a_Off.y;
|
||||
m_Min.z += a_Off.z;
|
||||
m_Max.x += a_Off.x;
|
||||
m_Max.y += a_Off.y;
|
||||
m_Max.z += a_Off.z;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cBoundingBox::Expand(double a_ExpandX, double a_ExpandY, double a_ExpandZ)
|
||||
{
|
||||
m_Min.x -= a_ExpandX;
|
||||
m_Min.y -= a_ExpandY;
|
||||
m_Min.z -= a_ExpandZ;
|
||||
m_Max.x += a_ExpandX;
|
||||
m_Max.y += a_ExpandY;
|
||||
m_Max.z += a_ExpandZ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBoundingBox::DoesIntersect(const cBoundingBox & a_Other)
|
||||
{
|
||||
return (
|
||||
((a_Other.m_Min.x <= m_Max.x) && (a_Other.m_Max.x >= m_Min.x)) && // X coords intersect
|
||||
((a_Other.m_Min.y <= m_Max.y) && (a_Other.m_Max.y >= m_Min.y)) && // Y coords intersect
|
||||
((a_Other.m_Min.z <= m_Max.z) && (a_Other.m_Max.z >= m_Min.z)) // Z coords intersect
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cBoundingBox cBoundingBox::Union(const cBoundingBox & a_Other)
|
||||
{
|
||||
return cBoundingBox(
|
||||
std::min(m_Min.x, a_Other.m_Min.x),
|
||||
std::min(m_Min.y, a_Other.m_Min.y),
|
||||
std::min(m_Min.z, a_Other.m_Min.z),
|
||||
std::max(m_Max.x, a_Other.m_Max.x),
|
||||
std::max(m_Max.y, a_Other.m_Max.y),
|
||||
std::max(m_Max.z, a_Other.m_Max.z)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBoundingBox::IsInside(const Vector3d & a_Point)
|
||||
{
|
||||
return IsInside(m_Min, m_Max, a_Point);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBoundingBox::IsInside(double a_X, double a_Y,double a_Z)
|
||||
{
|
||||
return IsInside(m_Min, m_Max, a_X, a_Y, a_Z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBoundingBox::IsInside(cBoundingBox & a_Other)
|
||||
{
|
||||
// If both a_Other's coords are inside this, then the entire a_Other is inside
|
||||
return (IsInside(a_Other.m_Min) && IsInside(a_Other.m_Max));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max)
|
||||
{
|
||||
// If both coords are inside this, then the entire a_Other is inside
|
||||
return (IsInside(a_Min) && IsInside(a_Max));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Point)
|
||||
{
|
||||
return (
|
||||
((a_Point.x >= a_Min.x) && (a_Point.x <= a_Max.x)) &&
|
||||
((a_Point.y >= a_Min.y) && (a_Point.y <= a_Max.y)) &&
|
||||
((a_Point.z >= a_Min.z) && (a_Point.z <= a_Max.z))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBoundingBox::IsInside(const Vector3d & a_Min, const Vector3d & a_Max, double a_X, double a_Y, double a_Z)
|
||||
{
|
||||
return (
|
||||
((a_X >= a_Min.x) && (a_X <= a_Max.x)) &&
|
||||
((a_Y >= a_Min.y) && (a_Y <= a_Max.y)) &&
|
||||
((a_Z >= a_Min.z) && (a_Z <= a_Max.z))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, char & a_Face)
|
||||
{
|
||||
return CalcLineIntersection(m_Min, m_Max, a_Line1, a_Line2, a_LineCoeff, a_Face);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, char & a_Face)
|
||||
{
|
||||
if (IsInside(a_Min, a_Max, a_Line1))
|
||||
{
|
||||
// The starting point is inside the bounding box.
|
||||
a_LineCoeff = 0;
|
||||
a_Face = BLOCK_FACE_YM; // Make it look as the top face was hit, although none really are.
|
||||
return true;
|
||||
}
|
||||
|
||||
char Face = 0;
|
||||
double Coeff = Vector3d::NO_INTERSECTION;
|
||||
|
||||
// Check each individual bbox face for intersection with the line, remember the one with the lowest coeff
|
||||
double c = a_Line1.LineCoeffToXYPlane(a_Line2, a_Min.z);
|
||||
if ((c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c))
|
||||
{
|
||||
Face = (a_Line1.z > a_Line2.z) ? BLOCK_FACE_ZP : BLOCK_FACE_ZM;
|
||||
Coeff = c;
|
||||
}
|
||||
c = a_Line1.LineCoeffToXYPlane(a_Line2, a_Max.z);
|
||||
if ((c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c))
|
||||
{
|
||||
Face = (a_Line1.z > a_Line2.z) ? BLOCK_FACE_ZP : BLOCK_FACE_ZM;
|
||||
Coeff = c;
|
||||
}
|
||||
c = a_Line1.LineCoeffToXZPlane(a_Line2, a_Min.y);
|
||||
if ((c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c))
|
||||
{
|
||||
Face = (a_Line1.y > a_Line2.y) ? BLOCK_FACE_YP : BLOCK_FACE_YM;
|
||||
Coeff = c;
|
||||
}
|
||||
c = a_Line1.LineCoeffToXZPlane(a_Line2, a_Max.y);
|
||||
if ((c >= 0) && (c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c))
|
||||
{
|
||||
Face = (a_Line1.y > a_Line2.y) ? BLOCK_FACE_YP : BLOCK_FACE_YM;
|
||||
Coeff = c;
|
||||
}
|
||||
c = a_Line1.LineCoeffToYZPlane(a_Line2, a_Min.x);
|
||||
if ((c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c))
|
||||
{
|
||||
Face = (a_Line1.x > a_Line2.x) ? BLOCK_FACE_XP : BLOCK_FACE_XM;
|
||||
Coeff = c;
|
||||
}
|
||||
c = a_Line1.LineCoeffToYZPlane(a_Line2, a_Max.x);
|
||||
if ((c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c))
|
||||
{
|
||||
Face = (a_Line1.x > a_Line2.x) ? BLOCK_FACE_XP : BLOCK_FACE_XM;
|
||||
Coeff = c;
|
||||
}
|
||||
|
||||
if (Coeff >= Vector3d::NO_INTERSECTION)
|
||||
{
|
||||
// There has been no intersection
|
||||
return false;
|
||||
}
|
||||
|
||||
a_LineCoeff = Coeff;
|
||||
a_Face = Face;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cBoundingBox::Intersect(const cBoundingBox & a_Other, cBoundingBox & a_Intersection)
|
||||
{
|
||||
a_Intersection.m_Min.x = std::max(m_Min.x, a_Other.m_Min.x);
|
||||
a_Intersection.m_Max.x = std::min(m_Max.x, a_Other.m_Max.x);
|
||||
if (a_Intersection.m_Min.x >= a_Intersection.m_Max.x)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
a_Intersection.m_Min.y = std::max(m_Min.y, a_Other.m_Min.y);
|
||||
a_Intersection.m_Max.y = std::min(m_Max.y, a_Other.m_Max.y);
|
||||
if (a_Intersection.m_Min.y >= a_Intersection.m_Max.y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
a_Intersection.m_Min.z = std::max(m_Min.z, a_Other.m_Min.z);
|
||||
a_Intersection.m_Max.z = std::min(m_Max.z, a_Other.m_Max.z);
|
||||
if (a_Intersection.m_Min.z >= a_Intersection.m_Max.z)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
90
source/BoundingBox.h
Normal file
90
source/BoundingBox.h
Normal file
@ -0,0 +1,90 @@
|
||||
|
||||
// BoundingBox.h
|
||||
|
||||
// Declares the cBoundingBox class representing an axis-aligned bounding box with floatingpoint coords
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Vector3d.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
/** Represents two sets of coords, minimum and maximum for each direction.
|
||||
All the coords within those limits (inclusive the edges) are considered "inside" the box.
|
||||
For intersection purposes, though, if the intersection is "sharp" in any coord (i. e. zero volume),
|
||||
the boxes are considered non-intersecting.
|
||||
*/
|
||||
class cBoundingBox
|
||||
{
|
||||
public:
|
||||
cBoundingBox(double a_MinX, double a_MaxX, double a_MinY, double a_MaxY, double a_MinZ, double a_MaxZ);
|
||||
cBoundingBox(const Vector3d & a_Min, const Vector3d & a_Max);
|
||||
cBoundingBox(const Vector3d & a_Pos, double a_Radius, double a_Height);
|
||||
cBoundingBox(const cBoundingBox & a_Orig);
|
||||
|
||||
/// Moves the entire boundingbox by the specified offset
|
||||
void Move(double a_OffX, double a_OffY, double a_OffZ);
|
||||
|
||||
/// Moves the entire boundingbox by the specified offset
|
||||
void Move(const Vector3d & a_Off);
|
||||
|
||||
/// Expands the bounding box by the specified amount in each direction (so the box becomes larger by 2 * Expand in each direction)
|
||||
void Expand(double a_ExpandX, double a_ExpandY, double a_ExpandZ);
|
||||
|
||||
/// Returns true if the two bounding boxes intersect
|
||||
bool DoesIntersect(const cBoundingBox & a_Other);
|
||||
|
||||
/// Returns the union of the two bounding boxes
|
||||
cBoundingBox Union(const cBoundingBox & a_Other);
|
||||
|
||||
/// Returns true if the point is inside the bounding box
|
||||
bool IsInside(const Vector3d & a_Point);
|
||||
|
||||
/// Returns true if the point is inside the bounding box
|
||||
bool IsInside(double a_X, double a_Y,double a_Z);
|
||||
|
||||
/// Returns true if a_Other is inside this bounding box
|
||||
bool IsInside(cBoundingBox & a_Other);
|
||||
|
||||
/// Returns true if a boundingbox specified by a_Min and a_Max is inside this bounding box
|
||||
bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max);
|
||||
|
||||
/// Returns true if the specified point is inside the bounding box specified by its min/max corners
|
||||
static bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Point);
|
||||
|
||||
/// Returns true if the specified point is inside the bounding box specified by its min/max corners
|
||||
static bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max, double a_X, double a_Y, double a_Z);
|
||||
|
||||
/** Returns true if this bounding box is intersected by the line specified by its two points
|
||||
Also calculates the distance along the line in which the intersection occurs (0 .. 1)
|
||||
Only forward collisions (a_LineCoeff >= 0) are returned.
|
||||
*/
|
||||
bool CalcLineIntersection(const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, char & a_Face);
|
||||
|
||||
/** Returns true if the specified bounding box is intersected by the line specified by its two points
|
||||
Also calculates the distance along the line in which the intersection occurs (0 .. 1) and the face hit (BLOCK_FACE_ constants)
|
||||
Only forward collisions (a_LineCoeff >= 0) are returned.
|
||||
*/
|
||||
static bool CalcLineIntersection(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, char & a_Face);
|
||||
|
||||
// tolua_end
|
||||
|
||||
/// Calculates the intersection of the two bounding boxes; returns true if nonempty
|
||||
bool Intersect(const cBoundingBox & a_Other, cBoundingBox & a_Intersection);
|
||||
|
||||
protected:
|
||||
Vector3d m_Min;
|
||||
Vector3d m_Max;
|
||||
|
||||
} ; // tolua_export
|
||||
|
||||
|
||||
|
||||
|
@ -1562,7 +1562,7 @@ bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback
|
||||
|
||||
|
||||
|
||||
void cChunkMap::DoExplosiontAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlocksAffected)
|
||||
void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlocksAffected)
|
||||
{
|
||||
// Don't explode if outside of Y range (prevents the following test running into unallocated memory):
|
||||
if ((a_BlockY < 0) || (a_BlockY > cChunkDef::Height - 1))
|
||||
|
@ -184,7 +184,7 @@ public:
|
||||
bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Lua-accessible
|
||||
|
||||
/// Destroys and returns a list of blocks destroyed in the explosion at the specified coordinates
|
||||
void DoExplosiontAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlockAffected);
|
||||
void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlockAffected);
|
||||
|
||||
/// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false.
|
||||
bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Lua-accessible
|
||||
|
@ -43,16 +43,24 @@ extern bool g_BlockIsSolid[256];
|
||||
|
||||
|
||||
|
||||
/// Block face constants, used in PlayerDigging and PlayerBlockPlacement packets
|
||||
enum
|
||||
/// Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc
|
||||
enum eBlockFace
|
||||
{
|
||||
BLOCK_FACE_NONE = -1, // Interacting with no block face - swinging the item in the air
|
||||
BLOCK_FACE_BOTTOM = 0, // Interacting with the bottom face of the block (YM)
|
||||
BLOCK_FACE_TOP = 1, // Interacting with the top face of the block (YP)
|
||||
BLOCK_FACE_NORTH = 2, // Interacting with the northern face of the block (ZP)
|
||||
BLOCK_FACE_SOUTH = 3, // Interacting with the southern face of the block (ZM)
|
||||
BLOCK_FACE_WEST = 4, // Interacting with the western face of the block (XP)
|
||||
BLOCK_FACE_EAST = 5, // Interacting with the eastern face of the block (XM)
|
||||
BLOCK_FACE_NONE = -1, // Interacting with no block face - swinging the item in the air
|
||||
BLOCK_FACE_XM = 5, // Interacting with the X- face of the block
|
||||
BLOCK_FACE_XP = 4, // Interacting with the X+ face of the block
|
||||
BLOCK_FACE_YM = 0, // Interacting with the Y- face of the block
|
||||
BLOCK_FACE_YP = 1, // Interacting with the Y+ face of the block
|
||||
BLOCK_FACE_ZM = 3, // Interacting with the Z- face of the block
|
||||
BLOCK_FACE_ZP = 2, // Interacting with the Z+ face of the block
|
||||
|
||||
// Synonyms using the (deprecated) world directions:
|
||||
BLOCK_FACE_BOTTOM = BLOCK_FACE_YM, // Interacting with the bottom face of the block
|
||||
BLOCK_FACE_TOP = BLOCK_FACE_YP, // Interacting with the top face of the block
|
||||
BLOCK_FACE_NORTH = BLOCK_FACE_ZP, // Interacting with the northern face of the block
|
||||
BLOCK_FACE_SOUTH = BLOCK_FACE_ZM, // Interacting with the southern face of the block
|
||||
BLOCK_FACE_WEST = BLOCK_FACE_XP, // Interacting with the western face of the block
|
||||
BLOCK_FACE_EAST = BLOCK_FACE_XM, // Interacting with the eastern face of the block
|
||||
} ;
|
||||
|
||||
|
||||
@ -345,8 +353,7 @@ inline void AddFaceDirection(int & a_BlockX, unsigned char & a_BlockY, int & a_B
|
||||
|
||||
|
||||
|
||||
#include <math.h>
|
||||
#define PI 3.14159265358979323846264338327950288419716939937510582097494459072381640628620899862803482534211706798f
|
||||
#define PI 3.14159265358979323846264338327950288419716939937510582097494459072381640628620899862803482534211706798f
|
||||
|
||||
inline void EulerToVector(double a_Pan, double a_Pitch, double & a_X, double & a_Y, double & a_Z)
|
||||
{
|
||||
|
@ -253,6 +253,39 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R
|
||||
|
||||
|
||||
|
||||
void cEntity::SetRotationFromSpeed(void)
|
||||
{
|
||||
const double EPS = 0.0000001;
|
||||
if ((abs(m_Speed.x) < EPS) && (abs(m_Speed.z) < EPS))
|
||||
{
|
||||
// atan2() may overflow or is undefined, pick any number
|
||||
SetRotation(0);
|
||||
return;
|
||||
}
|
||||
SetRotation(atan2(m_Speed.x, m_Speed.z) * 180 / PI);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::SetPitchFromSpeed(void)
|
||||
{
|
||||
const double EPS = 0.0000001;
|
||||
double xz = sqrt(m_Speed.x * m_Speed.x + m_Speed.z * m_Speed.z); // Speed XZ-plane component
|
||||
if ((abs(xz) < EPS) && (abs(m_Speed.y) < EPS))
|
||||
{
|
||||
// atan2() may overflow or is undefined, pick any number
|
||||
SetPitch(0);
|
||||
return;
|
||||
}
|
||||
SetPitch(atan2(m_Speed.y, xz) * 180 / PI);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
if (cRoot::Get()->GetPluginManager()->CallHookTakeDamage(*this, a_TDI))
|
||||
|
@ -203,6 +203,16 @@ public:
|
||||
/// Makes this entity take the specified damage. The values are packed into a TDI, knockback calculated, then sent through DoTakeDamage()
|
||||
void TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, int a_FinalDamage, double a_KnockbackAmount);
|
||||
|
||||
float GetGravity(void) const { return m_Gravity; }
|
||||
|
||||
void SetGravity(float a_Gravity) { m_Gravity = a_Gravity; }
|
||||
|
||||
/// Sets the rotation to match the speed vector (entity goes "face-forward")
|
||||
void SetRotationFromSpeed(void);
|
||||
|
||||
/// Sets the pitch to match the speed vector (entity gies "face-forward")
|
||||
void SetPitchFromSpeed(void);
|
||||
|
||||
// tolua_end
|
||||
|
||||
/// Makes this entity take damage specified in the a_TDI. The TDI is sent through plugins first, then applied
|
||||
|
@ -8,6 +8,16 @@
|
||||
#include "../ClientHandle.h"
|
||||
#include "Player.h"
|
||||
#include "../LineBlockTracer.h"
|
||||
#include "../BoundingBox.h"
|
||||
#include "../ChunkMap.h"
|
||||
#include "../Chunk.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Converts an angle in radians into a byte representation used by the network protocol
|
||||
#define ANGLE_TO_PROTO(X) (Byte)(X * 255 / 360)
|
||||
|
||||
|
||||
|
||||
@ -21,20 +31,49 @@ class cProjectileTracerCallback :
|
||||
{
|
||||
public:
|
||||
cProjectileTracerCallback(cProjectileEntity * a_Projectile) :
|
||||
m_Projectile(a_Projectile)
|
||||
m_Projectile(a_Projectile),
|
||||
m_SlowdownCoeff(0.99) // Default slowdown when not in water
|
||||
{
|
||||
}
|
||||
|
||||
double GetSlowdownCoeff(void) const { return m_SlowdownCoeff; }
|
||||
|
||||
protected:
|
||||
cProjectileEntity * m_Projectile;
|
||||
double m_SlowdownCoeff;
|
||||
|
||||
// cCallbacks overrides:
|
||||
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
|
||||
{
|
||||
/*
|
||||
// DEBUG:
|
||||
LOGD("Hit block %d:%d at {%d, %d, %d} face %d, %s (%s)",
|
||||
a_BlockType, a_BlockMeta,
|
||||
a_BlockX, a_BlockY, a_BlockZ, a_EntryFace,
|
||||
g_BlockIsSolid[a_BlockType] ? "solid" : "non-solid",
|
||||
ItemToString(cItem(a_BlockType, 1, a_BlockMeta)).c_str()
|
||||
);
|
||||
*/
|
||||
|
||||
if (g_BlockIsSolid[a_BlockType])
|
||||
{
|
||||
// The projectile hit a solid block
|
||||
m_Projectile->OnHitSolidBlock(a_BlockX, a_BlockY, a_BlockZ, a_EntryFace);
|
||||
return true;
|
||||
// Calculate the exact hit coords:
|
||||
cBoundingBox bb(a_BlockX, a_BlockX + 1, a_BlockY, a_BlockY + 1, a_BlockZ, a_BlockZ + 1);
|
||||
Vector3d Line1 = m_Projectile->GetPosition();
|
||||
Vector3d Line2 = Line1 + m_Projectile->GetSpeed();
|
||||
double LineCoeff = 0;
|
||||
char Face;
|
||||
if (bb.CalcLineIntersection(Line1, Line2, LineCoeff, Face))
|
||||
{
|
||||
Vector3d Intersection = Line1 + m_Projectile->GetSpeed() * LineCoeff;
|
||||
m_Projectile->OnHitSolidBlock(Intersection, Face);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGD("WEIRD! block tracer reports a hit, but BBox tracer doesn't. Ignoring the hit.");
|
||||
}
|
||||
}
|
||||
|
||||
// Convey some special effects from special blocks:
|
||||
@ -44,12 +83,14 @@ protected:
|
||||
case E_BLOCK_STATIONARY_LAVA:
|
||||
{
|
||||
m_Projectile->StartBurning(30);
|
||||
m_SlowdownCoeff = std::min(m_SlowdownCoeff, 0.9); // Slow down to 0.9* the speed each tick when moving through lava
|
||||
break;
|
||||
}
|
||||
case E_BLOCK_WATER:
|
||||
case E_BLOCK_STATIONARY_WATER:
|
||||
{
|
||||
m_Projectile->StopBurning();
|
||||
m_SlowdownCoeff = std::min(m_SlowdownCoeff, 0.8); // Slow down to 0.8* the speed each tick when moving through water
|
||||
break;
|
||||
}
|
||||
} // switch (a_BlockType)
|
||||
@ -63,6 +104,86 @@ protected:
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cProjectileEntityCollisionCallback:
|
||||
|
||||
class cProjectileEntityCollisionCallback :
|
||||
public cEntityCallback
|
||||
{
|
||||
public:
|
||||
cProjectileEntityCollisionCallback(cProjectileEntity * a_Projectile, const Vector3d & a_Pos, const Vector3d & a_NextPos) :
|
||||
m_Projectile(a_Projectile),
|
||||
m_Pos(a_Pos),
|
||||
m_NextPos(a_NextPos),
|
||||
m_MinCoeff(1),
|
||||
m_HitEntity(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual bool Item(cEntity * a_Entity) override
|
||||
{
|
||||
if (
|
||||
(a_Entity == m_Projectile) || // Do not check collisions with self
|
||||
(a_Entity == m_Projectile->GetCreator()) // Do not check whoever shot the projectile
|
||||
)
|
||||
{
|
||||
// TODO: Don't check creator only for the first 5 ticks
|
||||
// so that arrows stuck in ground and dug up can hurt the player
|
||||
return false;
|
||||
}
|
||||
|
||||
cBoundingBox EntBox(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight());
|
||||
|
||||
// Instead of colliding the bounding box with another bounding box in motion, we collide an enlarged bounding box with a hairline.
|
||||
// The results should be good enough for our purposes
|
||||
double LineCoeff;
|
||||
char Face;
|
||||
EntBox.Expand(m_Projectile->GetWidth() / 2, m_Projectile->GetHeight() / 2, m_Projectile->GetWidth() / 2);
|
||||
if (!EntBox.CalcLineIntersection(m_Pos, m_NextPos, LineCoeff, Face))
|
||||
{
|
||||
// No intersection whatsoever
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Some entities don't interact with the projectiles (pickups, falling blocks)
|
||||
// TODO: Allow plugins to interfere about which entities can be hit
|
||||
|
||||
if (LineCoeff < m_MinCoeff)
|
||||
{
|
||||
// The entity is closer than anything we've stored so far, replace it as the potential victim
|
||||
m_MinCoeff = LineCoeff;
|
||||
m_HitEntity = a_Entity;
|
||||
}
|
||||
|
||||
// Don't break the enumeration, we want all the entities
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Returns the nearest entity that was hit, after the enumeration has been completed
|
||||
cEntity * GetHitEntity(void) const { return m_HitEntity; }
|
||||
|
||||
/// Returns the line coeff where the hit was encountered, after the enumeration has been completed
|
||||
double GetMinCoeff(void) const { return m_MinCoeff; }
|
||||
|
||||
/// Returns true if the callback has encountered a true hit
|
||||
bool HasHit(void) const { return (m_MinCoeff < 1); }
|
||||
|
||||
protected:
|
||||
cProjectileEntity * m_Projectile;
|
||||
const Vector3d & m_Pos;
|
||||
const Vector3d & m_NextPos;
|
||||
double m_MinCoeff; // The coefficient of the nearest hit on the Pos line
|
||||
|
||||
// Although it's bad(tm) to store entity ptrs from a callback, we can afford it here, because the entire callback
|
||||
// is processed inside the tick thread, so the entities won't be removed in between the calls and the final processing
|
||||
cEntity * m_HitEntity; // The nearest hit entity
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cProjectileEntity:
|
||||
|
||||
@ -85,6 +206,8 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve
|
||||
m_IsInGround(false)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
SetRotationFromSpeed();
|
||||
SetPitchFromSpeed();
|
||||
}
|
||||
|
||||
|
||||
@ -101,10 +224,12 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator,
|
||||
|
||||
switch (a_Kind)
|
||||
{
|
||||
case pkArrow: return new cArrowEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkEgg: return new cThrownEggEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkEnderPearl: return new cThrownEnderPearlEntity(a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkSnowball: return new cThrownSnowballEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkArrow: return new cArrowEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkEgg: return new cThrownEggEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkEnderPearl: return new cThrownEnderPearlEntity(a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkSnowball: return new cThrownSnowballEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkGhastFireball: return new cGhastFireballEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkFireCharge: return new cFireChargeEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
// TODO: the rest
|
||||
}
|
||||
|
||||
@ -116,26 +241,17 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator,
|
||||
|
||||
|
||||
|
||||
void cProjectileEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace)
|
||||
void cProjectileEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
|
||||
{
|
||||
// TODO: Set proper position based on what face was hit
|
||||
switch (a_BlockFace)
|
||||
{
|
||||
case BLOCK_FACE_TOP: SetPosition(0.5 + a_BlockX, 1.0 + a_BlockY, 0.5 + a_BlockZ); break;
|
||||
case BLOCK_FACE_BOTTOM: SetPosition(0.5 + a_BlockX, a_BlockY, 0.5 + a_BlockZ); break;
|
||||
case BLOCK_FACE_EAST: SetPosition( a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break;
|
||||
case BLOCK_FACE_WEST: SetPosition(1.0 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break;
|
||||
case BLOCK_FACE_NORTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 1.0 + a_BlockZ); break;
|
||||
case BLOCK_FACE_SOUTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, a_BlockZ); break;
|
||||
case BLOCK_FACE_NONE: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break;
|
||||
}
|
||||
// Set the position based on what face was hit:
|
||||
SetPosition(a_HitPos);
|
||||
SetSpeed(0, 0, 0);
|
||||
|
||||
// DEBUG:
|
||||
LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, hit solid block at face %d",
|
||||
m_UniqueID,
|
||||
GetPosX(), GetPosY(), GetPosZ(),
|
||||
a_BlockFace
|
||||
a_HitPos.x, a_HitPos.y, a_HitPos.z,
|
||||
a_HitFace
|
||||
);
|
||||
|
||||
m_IsInGround = true;
|
||||
@ -192,20 +308,51 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
// Trace the tick's worth of movement as a line:
|
||||
Vector3d NextPos = Pos + PerTickSpeed;
|
||||
cProjectileTracerCallback TracerCallback(this);
|
||||
if (cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos))
|
||||
if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos))
|
||||
{
|
||||
// Nothing in the way, update the position
|
||||
SetPosition(NextPos);
|
||||
// Something has been hit, abort all other processing
|
||||
return;
|
||||
}
|
||||
// The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff
|
||||
|
||||
// Add gravity effect to the vertical speed component:
|
||||
SetSpeedY(GetSpeedY() + m_Gravity / 20);
|
||||
// Test for entity collisions:
|
||||
cProjectileEntityCollisionCallback EntityCollisionCallback(this, Pos, NextPos);
|
||||
a_Chunk.ForEachEntity(EntityCollisionCallback);
|
||||
if (EntityCollisionCallback.HasHit())
|
||||
{
|
||||
// An entity was hit:
|
||||
Vector3d HitPos = Pos + (NextPos - Pos) * EntityCollisionCallback.GetMinCoeff();
|
||||
|
||||
// DEBUG:
|
||||
LOGD("Projectile %d has hit an entity %d (%s) at {%.02f, %.02f, %.02f} (coeff %.03f)",
|
||||
m_UniqueID,
|
||||
EntityCollisionCallback.GetHitEntity()->GetUniqueID(),
|
||||
EntityCollisionCallback.GetHitEntity()->GetClass(),
|
||||
HitPos.x, HitPos.y, HitPos.z,
|
||||
EntityCollisionCallback.GetMinCoeff()
|
||||
);
|
||||
|
||||
OnHitEntity(*(EntityCollisionCallback.GetHitEntity()), HitPos);
|
||||
}
|
||||
// TODO: Test the entities in the neighboring chunks, too
|
||||
|
||||
// Update the position:
|
||||
SetPosition(NextPos);
|
||||
|
||||
// Add slowdown and gravity effect to the speed:
|
||||
Vector3d NewSpeed(GetSpeed());
|
||||
NewSpeed.y += m_Gravity / 20;
|
||||
NewSpeed *= TracerCallback.GetSlowdownCoeff();
|
||||
SetSpeed(NewSpeed);
|
||||
SetRotationFromSpeed();
|
||||
SetPitchFromSpeed();
|
||||
|
||||
// DEBUG:
|
||||
LOGD("Arrow %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}",
|
||||
LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}, rot {%.02f, %.02f}",
|
||||
m_UniqueID,
|
||||
GetPosX(), GetPosY(), GetPosZ(),
|
||||
GetSpeedX(), GetSpeedY(), GetSpeedZ()
|
||||
GetSpeedX(), GetSpeedY(), GetSpeedZ(),
|
||||
GetRotation(), GetPitch()
|
||||
);
|
||||
}
|
||||
|
||||
@ -216,7 +363,8 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
void cProjectileEntity::SpawnOn(cClientHandle & a_Client)
|
||||
{
|
||||
// Default spawning - use the projectile kind to spawn an object:
|
||||
a_Client.SendSpawnObject(*this, m_ProjectileKind, 0, 0, 0);
|
||||
a_Client.SendSpawnObject(*this, m_ProjectileKind, 12, ANGLE_TO_PROTO(GetRotation()), ANGLE_TO_PROTO(GetPitch()));
|
||||
a_Client.SendEntityMetadata(*this);
|
||||
}
|
||||
|
||||
|
||||
@ -229,12 +377,16 @@ void cProjectileEntity::SpawnOn(cClientHandle & a_Client)
|
||||
cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5),
|
||||
m_PickupState(psNoPickup),
|
||||
m_DamageCoeff(2)
|
||||
m_DamageCoeff(2),
|
||||
m_IsCritical(false)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
SetMass(0.1);
|
||||
LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f}",
|
||||
m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ()
|
||||
SetRotationFromSpeed();
|
||||
SetPitchFromSpeed();
|
||||
LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}",
|
||||
m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(),
|
||||
GetRotation(), GetPitch()
|
||||
);
|
||||
}
|
||||
|
||||
@ -245,7 +397,8 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a
|
||||
cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
|
||||
super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5),
|
||||
m_PickupState(psInSurvivalOrCreative),
|
||||
m_DamageCoeff(2)
|
||||
m_DamageCoeff(2),
|
||||
m_IsCritical((a_Force >= 1))
|
||||
{
|
||||
}
|
||||
|
||||
@ -269,14 +422,43 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
|
||||
|
||||
|
||||
|
||||
void cArrowEntity::SpawnOn(cClientHandle & a_Client)
|
||||
void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
|
||||
{
|
||||
a_Client.SendSpawnObject(*this, pkArrow, 0, 0, 0);
|
||||
super::OnHitSolidBlock(a_HitPos, a_HitFace);
|
||||
|
||||
// Broadcast the position and speed packets before teleporting:
|
||||
BroadcastMovementUpdate();
|
||||
|
||||
// Teleport the entity to the exact hit coords:
|
||||
m_World->BroadcastTeleportEntity(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer())
|
||||
{
|
||||
// Not an entity that interacts with an arrow
|
||||
return;
|
||||
}
|
||||
|
||||
int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5);
|
||||
if (m_IsCritical)
|
||||
{
|
||||
Damage += m_World->GetTickRandomNumber(Damage / 2 + 2);
|
||||
}
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cThrownEggEntity:
|
||||
|
||||
@ -290,7 +472,7 @@ cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y,
|
||||
|
||||
|
||||
|
||||
void cThrownEggEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace)
|
||||
void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
|
||||
{
|
||||
// TODO: Random-spawn a chicken or four
|
||||
|
||||
@ -314,9 +496,15 @@ cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X
|
||||
|
||||
|
||||
|
||||
void cThrownEnderPearlEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace)
|
||||
void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
|
||||
{
|
||||
// TODO: Teleport the creator here, make them take 5 damage
|
||||
// Teleport the creator here, make them take 5 damage:
|
||||
if (m_Creator != NULL)
|
||||
{
|
||||
// TODO: The coords might need some tweaking based on the block face
|
||||
m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5);
|
||||
m_Creator->TakeDamage(dtEnderPearl, this, 5, 0);
|
||||
}
|
||||
|
||||
Destroy();
|
||||
}
|
||||
@ -338,7 +526,7 @@ cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, do
|
||||
|
||||
|
||||
|
||||
void cThrownSnowballEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace)
|
||||
void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
|
||||
{
|
||||
// TODO: Apply damage to certain mobs (blaze etc.) and anger all mobs
|
||||
|
||||
@ -349,3 +537,94 @@ void cThrownSnowballEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_Bl
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cGhastFireballEntity :
|
||||
|
||||
cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkGhastFireball, a_Creator, a_X, a_Y, a_Z, 1, 1)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
SetGravity(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cGhastFireballEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
m_World->DoExplosionAt(1, a_BlockX, a_BlockY, a_BlockZ, true, esGhastFireball, this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cGhastFireballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
|
||||
{
|
||||
Destroy();
|
||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cGhastFireballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
Destroy();
|
||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cFireChargeEntity :
|
||||
|
||||
cFireChargeEntity::cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||
super(pkFireCharge, a_Creator, a_X, a_Y, a_Z, 0.3125, 0.3125)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
SetGravity(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireChargeEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
if (m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
|
||||
{
|
||||
m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireChargeEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
|
||||
{
|
||||
Destroy();
|
||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFireChargeEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
Destroy();
|
||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||
|
||||
// TODO: Some entities are immune to hits
|
||||
a_EntityHit.StartBurning(5 * 20); // 5 seconds of burning
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -47,8 +47,11 @@ public:
|
||||
|
||||
static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed = NULL);
|
||||
|
||||
/// Called by the physics blocktracer when the entity hits a solid block, the block's coords and the face hit is given
|
||||
virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace);
|
||||
/// Called by the physics blocktracer when the entity hits a solid block, the hit position and the face hit (BLOCK_FACE_) is given
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace);
|
||||
|
||||
/// Called by the physics blocktracer when the entity hits another entity
|
||||
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) {}
|
||||
|
||||
// tolua_begin
|
||||
|
||||
@ -64,6 +67,11 @@ public:
|
||||
/// Returns true if the projectile has hit the ground and is stuck there
|
||||
bool IsInGround(void) const { return m_IsInGround; }
|
||||
|
||||
// tolua_end
|
||||
|
||||
/// Sets the internal InGround flag. To be used by MCA loader only!
|
||||
void SetIsInGround(bool a_IsInGround) { m_IsInGround = a_IsInGround; }
|
||||
|
||||
protected:
|
||||
eKind m_ProjectileKind;
|
||||
|
||||
@ -73,8 +81,6 @@ protected:
|
||||
/// True if the projectile has hit the ground and is stuck there
|
||||
bool m_IsInGround;
|
||||
|
||||
// tolua_end
|
||||
|
||||
// cEntity overrides:
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
|
||||
@ -128,6 +134,12 @@ public:
|
||||
/// Returns true if the specified player can pick the arrow up
|
||||
bool CanPickup(const cPlayer & a_Player) const;
|
||||
|
||||
/// Returns true if the arrow is set as critical
|
||||
bool IsCritical(void) const { return m_IsCritical; }
|
||||
|
||||
/// Sets the IsCritical flag
|
||||
void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; }
|
||||
|
||||
// tolua_end
|
||||
|
||||
protected:
|
||||
@ -137,9 +149,13 @@ protected:
|
||||
|
||||
/// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow
|
||||
double m_DamageCoeff;
|
||||
|
||||
/// If true, the arrow deals more damage
|
||||
bool m_IsCritical;
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void SpawnOn(cClientHandle & a_Client) override;
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override;
|
||||
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
// tolua_begin
|
||||
} ;
|
||||
@ -166,7 +182,7 @@ protected:
|
||||
// tolua_end
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override;
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override;
|
||||
|
||||
// tolua_begin
|
||||
|
||||
@ -194,7 +210,7 @@ protected:
|
||||
// tolua_end
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override;
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override;
|
||||
|
||||
// tolua_begin
|
||||
|
||||
@ -218,11 +234,9 @@ public:
|
||||
cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
// tolua_end
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override;
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override;
|
||||
|
||||
// tolua_begin
|
||||
|
||||
@ -232,6 +246,65 @@ protected:
|
||||
|
||||
|
||||
|
||||
class cGhastFireballEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cGhastFireballEntity);
|
||||
|
||||
cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
void Explode(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override;
|
||||
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
// TODO: Deflecting the fireballs by arrow- or sword- hits
|
||||
|
||||
// tolua_begin
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cFireChargeEntity :
|
||||
public cProjectileEntity
|
||||
{
|
||||
typedef cProjectileEntity super;
|
||||
|
||||
public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
CLASS_PROTODEF(cFireChargeEntity);
|
||||
|
||||
cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||
|
||||
protected:
|
||||
|
||||
void Explode(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
|
||||
// cProjectileEntity overrides:
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override;
|
||||
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||
|
||||
// tolua_begin
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_end
|
||||
|
||||
|
||||
|
@ -52,7 +52,7 @@ void cTNTEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
Destroy(true);
|
||||
LOGD("BOOM at {%f,%f,%f}", GetPosX(), GetPosY(), GetPosZ());
|
||||
m_World->DoExplosiontAt(4.0, GetPosX() + 0.49, GetPosY() + 0.49, GetPosZ() + 0.49, true, esPrimedTNT, this);
|
||||
m_World->DoExplosionAt(4.0, GetPosX() + 0.49, GetPosY() + 0.49, GetPosZ() + 0.49, true, esPrimedTNT, this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -8,16 +8,70 @@
|
||||
|
||||
|
||||
|
||||
Vector3d::Vector3d(const Vector3f & v )
|
||||
: x( v.x )
|
||||
, y( v.y )
|
||||
, z( v.z )
|
||||
const double Vector3d::EPS = 0.000001; ///< The max difference between two coords for which the coords are assumed equal
|
||||
const double Vector3d::NO_INTERSECTION = 1e70; ///< Return value of LineCoeffToPlane() if the line is parallel to the plane
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Vector3d::Vector3d(const Vector3f & v) :
|
||||
x(v.x),
|
||||
y(v.y),
|
||||
z(v.z)
|
||||
{
|
||||
}
|
||||
|
||||
Vector3d::Vector3d(const Vector3f * v )
|
||||
: x( v->x )
|
||||
, y( v->y )
|
||||
, z( v->z )
|
||||
|
||||
|
||||
|
||||
|
||||
Vector3d::Vector3d(const Vector3f * v) :
|
||||
x(v->x),
|
||||
y(v->y),
|
||||
z(v->z)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
double Vector3d::LineCoeffToXYPlane(const Vector3d & a_OtherEnd, double a_Z) const
|
||||
{
|
||||
if (abs(z - a_OtherEnd.z) < EPS)
|
||||
{
|
||||
return NO_INTERSECTION;
|
||||
}
|
||||
return (a_Z - z) / (a_OtherEnd.z - z);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
double Vector3d::LineCoeffToXZPlane(const Vector3d & a_OtherEnd, double a_Y) const
|
||||
{
|
||||
if (abs(y - a_OtherEnd.y) < EPS)
|
||||
{
|
||||
return NO_INTERSECTION;
|
||||
}
|
||||
return (a_Y - y) / (a_OtherEnd.y - y);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
double Vector3d::LineCoeffToYZPlane(const Vector3d & a_OtherEnd, double a_X) const
|
||||
{
|
||||
if (abs(x - a_OtherEnd.x) < EPS)
|
||||
{
|
||||
return NO_INTERSECTION;
|
||||
}
|
||||
return (a_X - x) / (a_OtherEnd.x - x);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -3,26 +3,54 @@
|
||||
#include <math.h>
|
||||
|
||||
class Vector3f;
|
||||
class Vector3d // tolua_export
|
||||
{ // tolua_export
|
||||
public: // tolua_export
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class Vector3d
|
||||
{
|
||||
public:
|
||||
// convert from float
|
||||
Vector3d(const Vector3f & v ); // tolua_export
|
||||
Vector3d(const Vector3f * v ); // tolua_export
|
||||
Vector3d(const Vector3f & v);
|
||||
Vector3d(const Vector3f * v);
|
||||
|
||||
Vector3d() : x(0), y(0), z(0) {} // tolua_export
|
||||
Vector3d(double a_x, double a_y, double a_z) : x(a_x), y(a_y), z(a_z) {} // tolua_export
|
||||
Vector3d() : x(0), y(0), z(0) {}
|
||||
Vector3d(double a_x, double a_y, double a_z) : x(a_x), y(a_y), z(a_z) {}
|
||||
|
||||
inline void Set(double a_x, double a_y, double a_z) { x = a_x, y = a_y, z = a_z; } // tolua_export
|
||||
inline void Normalize() { double l = 1.0f / Length(); x *= l; y *= l; z *= l; } // tolua_export
|
||||
inline Vector3d NormalizeCopy() { double l = 1.0f / Length(); return Vector3d( x * l, y * l, z * l ); } // tolua_export
|
||||
inline void NormalizeCopy(Vector3d & a_V) { double l = 1.0f / Length(); a_V.Set(x*l, y*l, z*l ); } // tolua_export
|
||||
inline double Length() const { return (double)sqrt( x * x + y * y + z * z ); } // tolua_export
|
||||
inline double SqrLength() const { return x * x + y * y + z * z; } // tolua_export
|
||||
inline double Dot( const Vector3d & a_V ) const { return x * a_V.x + y * a_V.y + z * a_V.z; } // tolua_export
|
||||
inline Vector3d Cross( const Vector3d & v ) const { return Vector3d( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x ); } // tolua_export
|
||||
inline void Set(double a_x, double a_y, double a_z) { x = a_x, y = a_y, z = a_z; }
|
||||
inline void Normalize() { double l = 1.0f / Length(); x *= l; y *= l; z *= l; }
|
||||
inline Vector3d NormalizeCopy() { double l = 1.0f / Length(); return Vector3d( x * l, y * l, z * l ); }
|
||||
inline void NormalizeCopy(Vector3d & a_V) { double l = 1.0f / Length(); a_V.Set(x*l, y*l, z*l ); }
|
||||
inline double Length() const { return (double)sqrt( x * x + y * y + z * z ); }
|
||||
inline double SqrLength() const { return x * x + y * y + z * z; }
|
||||
inline double Dot( const Vector3d & a_V ) const { return x * a_V.x + y * a_V.y + z * a_V.z; }
|
||||
inline Vector3d Cross( const Vector3d & v ) const { return Vector3d( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x ); }
|
||||
|
||||
/** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified Z coord
|
||||
The result satisfies the following equation:
|
||||
(*this + Result * (a_OtherEnd - *this)).z = a_Z
|
||||
If the line is too close to being parallel, this function returns NO_INTERSECTION
|
||||
*/
|
||||
double LineCoeffToXYPlane(const Vector3d & a_OtherEnd, double a_Z) const;
|
||||
|
||||
inline bool Equals( const Vector3d & v ) const { return (x == v.x && y == v.y && z == v.z ); } // tolua_export
|
||||
/** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified Y coord
|
||||
The result satisfies the following equation:
|
||||
(*this + Result * (a_OtherEnd - *this)).y = a_Y
|
||||
If the line is too close to being parallel, this function returns NO_INTERSECTION
|
||||
*/
|
||||
double LineCoeffToXZPlane(const Vector3d & a_OtherEnd, double a_Y) const;
|
||||
|
||||
/** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified X coord
|
||||
The result satisfies the following equation:
|
||||
(*this + Result * (a_OtherEnd - *this)).x = a_X
|
||||
If the line is too close to being parallel, this function returns NO_INTERSECTION
|
||||
*/
|
||||
double LineCoeffToYZPlane(const Vector3d & a_OtherEnd, double a_X) const;
|
||||
|
||||
inline bool Equals(const Vector3d & v) const { return ((x == v.x) && (y == v.y) && (z == v.z)); }
|
||||
|
||||
// tolua_end
|
||||
|
||||
void operator += ( const Vector3d& a_V ) { x += a_V.x; y += a_V.y; z += a_V.z; }
|
||||
void operator += ( Vector3d* a_V ) { x += a_V->x; y += a_V->y; z += a_V->z; }
|
||||
@ -30,14 +58,24 @@ public: // tolua_export
|
||||
void operator -= ( Vector3d* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; }
|
||||
void operator *= ( double a_f ) { x *= a_f; y *= a_f; z *= a_f; }
|
||||
|
||||
Vector3d operator + (const Vector3d & v2) const { return Vector3d(x + v2.x, y + v2.y, z + v2.z ); } // tolua_export
|
||||
Vector3d operator + (const Vector3d * v2) const { return Vector3d(x + v2->x, y + v2->y, z + v2->z ); } // tolua_export
|
||||
Vector3d operator - (const Vector3d & v2) const { return Vector3d(x - v2.x, y - v2.y, z - v2.z ); } // tolua_export
|
||||
Vector3d operator - (const Vector3d * v2) const { return Vector3d(x - v2->x, y - v2->y, z - v2->z ); } // tolua_export
|
||||
Vector3d operator * (const double f) const { return Vector3d(x * f, y * f, z * f ); } // tolua_export
|
||||
Vector3d operator * (const Vector3d & v2) const { return Vector3d(x * v2.x, y * v2.y, z * v2.z ); } // tolua_export
|
||||
Vector3d operator / (const double f) const { return Vector3d(x / f, y / f, z / f ); } // tolua_export
|
||||
// tolua_begin
|
||||
|
||||
Vector3d operator + (const Vector3d & v2) const { return Vector3d(x + v2.x, y + v2.y, z + v2.z ); }
|
||||
Vector3d operator + (const Vector3d * v2) const { return Vector3d(x + v2->x, y + v2->y, z + v2->z ); }
|
||||
Vector3d operator - (const Vector3d & v2) const { return Vector3d(x - v2.x, y - v2.y, z - v2.z ); }
|
||||
Vector3d operator - (const Vector3d * v2) const { return Vector3d(x - v2->x, y - v2->y, z - v2->z ); }
|
||||
Vector3d operator * (const double f) const { return Vector3d(x * f, y * f, z * f ); }
|
||||
Vector3d operator * (const Vector3d & v2) const { return Vector3d(x * v2.x, y * v2.y, z * v2.z ); }
|
||||
Vector3d operator / (const double f) const { return Vector3d(x / f, y / f, z / f ); }
|
||||
|
||||
double x, y, z;
|
||||
|
||||
static const double EPS; ///< The max difference between two coords for which the coords are assumed equal
|
||||
static const double NO_INTERSECTION; ///< Return value of LineCoeffToPlane() if the line is parallel to the plane
|
||||
} ;
|
||||
|
||||
// tolua_end
|
||||
|
||||
|
||||
|
||||
double x, y, z; // tolua_export
|
||||
|
||||
};// tolua_export
|
||||
|
@ -969,7 +969,7 @@ bool cWorld::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback
|
||||
|
||||
|
||||
|
||||
void cWorld::DoExplosiontAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData)
|
||||
void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData)
|
||||
{
|
||||
if (cPluginManager::Get()->CallHookExploding(*this, a_ExplosionSize, a_CanCauseFire, a_BlockX, a_BlockY, a_BlockZ, a_Source, a_SourceData) || (a_ExplosionSize <= 0))
|
||||
{
|
||||
@ -979,7 +979,7 @@ void cWorld::DoExplosiontAt(double a_ExplosionSize, double a_BlockX, double a_Bl
|
||||
// TODO: Add damage to entities, add support for pickups, and implement block hardiness
|
||||
Vector3d explosion_pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ);
|
||||
cVector3iArray BlocksAffected;
|
||||
m_ChunkMap->DoExplosiontAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, BlocksAffected);
|
||||
m_ChunkMap->DoExplosionAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, BlocksAffected);
|
||||
BroadcastSoundEffect("random.explode", (int)floor(a_BlockX * 8), (int)floor(a_BlockY * 8), (int)floor(a_BlockZ * 8), 1.0f, 0.6f);
|
||||
{
|
||||
cCSLock Lock(m_CSPlayers);
|
||||
|
@ -414,13 +414,13 @@ public:
|
||||
| esCreeper | cCreeper * |
|
||||
| esBed | cVector3i * |
|
||||
| esEnderCrystal | Vector3i * |
|
||||
| esGhastFireball | TBD |
|
||||
| esGhastFireball | cGhastFireball * |
|
||||
| esWitherSkullBlack | TBD |
|
||||
| esWitherSkullBlue | TBD |
|
||||
| esWitherBirth | TBD |
|
||||
| esPlugin | void * |
|
||||
*/
|
||||
void DoExplosiontAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export
|
||||
void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export
|
||||
|
||||
/// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found
|
||||
bool DoWithChestAt (int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp
|
||||
|
@ -340,7 +340,7 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
|
||||
m_Writer.AddShort("xTile", (Int16)floor(Pos.x));
|
||||
m_Writer.AddShort("yTile", (Int16)floor(Pos.y));
|
||||
m_Writer.AddShort("zTile", (Int16)floor(Pos.z));
|
||||
m_Writer.AddShort("inTile", 0); // TODO: Query the block type (is it needed?)
|
||||
m_Writer.AddShort("inTile", 0); // TODO: Query the block type
|
||||
m_Writer.AddShort("shake", 0); // TODO: Any shake?
|
||||
m_Writer.AddByte ("inGround", a_Projectile->IsInGround() ? 1 : 0);
|
||||
|
||||
|
@ -952,14 +952,34 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
|
||||
{
|
||||
LoadMinecartHFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||
}
|
||||
if (strncmp(a_IDTag, "Item", a_IDTagLength) == 0)
|
||||
else if (strncmp(a_IDTag, "Item", a_IDTagLength) == 0)
|
||||
{
|
||||
LoadPickupFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||
}
|
||||
if (strncmp(a_IDTag, "Arrow", a_IDTagLength) == 0)
|
||||
else if (strncmp(a_IDTag, "Arrow", a_IDTagLength) == 0)
|
||||
{
|
||||
LoadArrowFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||
}
|
||||
else if (strncmp(a_IDTag, "Snowball", a_IDTagLength) == 0)
|
||||
{
|
||||
LoadSnowballFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||
}
|
||||
else if (strncmp(a_IDTag, "Egg", a_IDTagLength) == 0)
|
||||
{
|
||||
LoadEggFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||
}
|
||||
else if (strncmp(a_IDTag, "Fireball", a_IDTagLength) == 0)
|
||||
{
|
||||
LoadFireballFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||
}
|
||||
else if (strncmp(a_IDTag, "SmallFireball", a_IDTagLength) == 0)
|
||||
{
|
||||
LoadFireChargeFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||
}
|
||||
else if (strncmp(a_IDTag, "ThrownEnderpearl", a_IDTagLength) == 0)
|
||||
{
|
||||
LoadThrownEnderpearlFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
|
||||
}
|
||||
// TODO: other entities
|
||||
}
|
||||
|
||||
@ -1100,7 +1120,7 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
|
||||
void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
std::auto_ptr<cArrowEntity> Arrow(new cArrowEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0)));
|
||||
if (!LoadEntityBaseFromNBT(*Arrow.get(), a_NBT, a_TagIdx))
|
||||
if (!LoadProjectileBaseFromNBT(*Arrow.get(), a_NBT, a_TagIdx))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -1136,6 +1156,86 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadSnowballFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
std::auto_ptr<cThrownSnowballEntity> Snowball(new cThrownSnowballEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0)));
|
||||
if (!LoadProjectileBaseFromNBT(*Snowball.get(), a_NBT, a_TagIdx))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the new snowball in the entities list:
|
||||
a_Entities.push_back(Snowball.release());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadEggFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
std::auto_ptr<cThrownEggEntity> Egg(new cThrownEggEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0)));
|
||||
if (!LoadProjectileBaseFromNBT(*Egg.get(), a_NBT, a_TagIdx))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the new egg in the entities list:
|
||||
a_Entities.push_back(Egg.release());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadFireballFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
std::auto_ptr<cGhastFireballEntity> Fireball(new cGhastFireballEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0)));
|
||||
if (!LoadProjectileBaseFromNBT(*Fireball.get(), a_NBT, a_TagIdx))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the new fireball in the entities list:
|
||||
a_Entities.push_back(Fireball.release());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadFireChargeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
std::auto_ptr<cFireChargeEntity> FireCharge(new cFireChargeEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0)));
|
||||
if (!LoadProjectileBaseFromNBT(*FireCharge.get(), a_NBT, a_TagIdx))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the new FireCharge in the entities list:
|
||||
a_Entities.push_back(FireCharge.release());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
std::auto_ptr<cThrownEnderPearlEntity> Enderpearl(new cThrownEnderPearlEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0)));
|
||||
if (!LoadProjectileBaseFromNBT(*Enderpearl.get(), a_NBT, a_TagIdx))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the new enderpearl in the entities list:
|
||||
a_Entities.push_back(Enderpearl.release());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
double Pos[3];
|
||||
@ -1167,6 +1267,30 @@ bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_N
|
||||
|
||||
|
||||
|
||||
bool cWSSAnvil::LoadProjectileBaseFromNBT(cProjectileEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
if (!LoadEntityBaseFromNBT(a_Entity, a_NBT, a_TagIdx))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsInGround = false;
|
||||
int InGroundIdx = a_NBT.FindChildByName(a_TagIdx, "inGround");
|
||||
if (InGroundIdx > 0)
|
||||
{
|
||||
IsInGround = (a_NBT.GetByte(InGroundIdx) != 0);
|
||||
}
|
||||
a_Entity.SetIsInGround(IsInGround);
|
||||
|
||||
// TODO: Load inTile, TileCoords
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWSSAnvil::LoadDoublesListFromNBT(double * a_Doubles, int a_NumDoubles, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_List) || (a_NBT.GetChildrenType(a_TagIdx) != TAG_Double))
|
||||
|
@ -18,6 +18,8 @@
|
||||
// fwd: ItemGrid.h
|
||||
class cItemGrid;
|
||||
|
||||
class cProjectileEntity;
|
||||
|
||||
|
||||
|
||||
|
||||
@ -138,18 +140,26 @@ protected:
|
||||
|
||||
void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength);
|
||||
|
||||
void LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadMinecartRFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadMinecartCFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadMinecartFFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadMinecartTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadMinecartHFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadArrowFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadFallingBlockFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadMinecartRFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadMinecartCFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadMinecartFFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadMinecartTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadMinecartHFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadArrowFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadSnowballFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadEggFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadFireballFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadFireChargeFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadThrownEnderpearlFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
|
||||
/// Loads entity common data from the NBT compound; returns true if successful
|
||||
bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
|
||||
/// Loads projectile common data from the NBT compound; returns true if successful
|
||||
bool LoadProjectileBaseFromNBT(cProjectileEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIx);
|
||||
|
||||
/// Loads an array of doubles of the specified length from the specified NBT list tag a_TagIdx; returns true if successful
|
||||
bool LoadDoublesListFromNBT(double * a_Doubles, int a_NumDoubles, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user