Merge pull request #1135 from mc-server/fixes
Fixes to projectiles and the undead
This commit is contained in:
commit
372dbbb994
@ -73,25 +73,23 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
|
|||||||
|
|
||||||
void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||||
{
|
{
|
||||||
if (a_HitFace == BLOCK_FACE_NONE) { return; }
|
if (GetSpeed().EqualsEps(Vector3d(0, 0, 0), 0.0000001))
|
||||||
|
|
||||||
super::OnHitSolidBlock(a_HitPos, a_HitFace);
|
|
||||||
int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z;
|
|
||||||
|
|
||||||
switch (a_HitFace)
|
|
||||||
{
|
{
|
||||||
case BLOCK_FACE_XM: // Strangely, bounding boxes / block tracers return the actual block for these two directions, so AddFace not needed
|
SetSpeed(GetLookVector().NormalizeCopy() * 0.1); // Ensure that no division by zero happens later
|
||||||
case BLOCK_FACE_YM:
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: AddFaceDirection(a_X, a_Y, a_Z, a_HitFace, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_HitBlockPos = Vector3i(a_X, a_Y, a_Z);
|
Vector3d Hit = a_HitPos;
|
||||||
|
Vector3d SinkMovement = (GetSpeed() / 800);
|
||||||
|
Hit += (SinkMovement * 0.01) / SinkMovement.Length(); // Make arrow sink into block a centimetre so it lodges (but not to far so it goes black clientside)
|
||||||
|
|
||||||
|
super::OnHitSolidBlock(Hit, a_HitFace);
|
||||||
|
Vector3i BlockHit = Hit.Floor();
|
||||||
|
|
||||||
|
int X = BlockHit.x, Y = BlockHit.y, Z = BlockHit.z;
|
||||||
|
m_HitBlockPos = Vector3i(X, Y, Z);
|
||||||
|
|
||||||
// Broadcast arrow hit sound
|
// Broadcast arrow hit sound
|
||||||
m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
m_World->BroadcastSoundEffect("random.bowhit", X * 8, Y * 8, Z * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -100,12 +98,6 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFa
|
|||||||
|
|
||||||
void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||||
{
|
{
|
||||||
if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer() && !a_EntityHit.IsBoat())
|
|
||||||
{
|
|
||||||
// Not an entity that interacts with an arrow
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5);
|
int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5);
|
||||||
if (m_IsCritical)
|
if (m_IsCritical)
|
||||||
{
|
{
|
||||||
@ -194,7 +186,7 @@ void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
|||||||
|
|
||||||
if (!m_HasTeleported) // Sent a teleport already, don't do again
|
if (!m_HasTeleported) // Sent a teleport already, don't do again
|
||||||
{
|
{
|
||||||
if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case
|
if (m_HitGroundTimer > 500.f) // Send after half a second, could be less, but just in case
|
||||||
{
|
{
|
||||||
m_World->BroadcastTeleportEntity(*this);
|
m_World->BroadcastTeleportEntity(*this);
|
||||||
m_HasTeleported = true;
|
m_HasTeleported = true;
|
||||||
|
@ -59,8 +59,14 @@ public:
|
|||||||
/// Sets the IsCritical flag
|
/// Sets the IsCritical flag
|
||||||
void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; }
|
void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; }
|
||||||
|
|
||||||
|
/** Gets the block arrow is in */
|
||||||
|
Vector3i GetBlockHit(void) const { return m_HitBlockPos; }
|
||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
|
/** Sets the block arrow is in. To be used by the MCA loader only! */
|
||||||
|
void SetBlockHit(const Vector3i & a_BlockHit) { m_HitBlockPos = a_BlockHit; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/// Determines when the arrow can be picked up by players
|
/// Determines when the arrow can be picked up by players
|
||||||
|
@ -1480,7 +1480,6 @@ void cEntity::SetWidth(double a_Width)
|
|||||||
void cEntity::AddPosX(double a_AddPosX)
|
void cEntity::AddPosX(double a_AddPosX)
|
||||||
{
|
{
|
||||||
m_Pos.x += a_AddPosX;
|
m_Pos.x += a_AddPosX;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1489,7 +1488,6 @@ void cEntity::AddPosX(double a_AddPosX)
|
|||||||
void cEntity::AddPosY(double a_AddPosY)
|
void cEntity::AddPosY(double a_AddPosY)
|
||||||
{
|
{
|
||||||
m_Pos.y += a_AddPosY;
|
m_Pos.y += a_AddPosY;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1498,7 +1496,6 @@ void cEntity::AddPosY(double a_AddPosY)
|
|||||||
void cEntity::AddPosZ(double a_AddPosZ)
|
void cEntity::AddPosZ(double a_AddPosZ)
|
||||||
{
|
{
|
||||||
m_Pos.z += a_AddPosZ;
|
m_Pos.z += a_AddPosZ;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1509,7 +1506,6 @@ void cEntity::AddPosition(double a_AddPosX, double a_AddPosY, double a_AddPosZ)
|
|||||||
m_Pos.x += a_AddPosX;
|
m_Pos.x += a_AddPosX;
|
||||||
m_Pos.y += a_AddPosY;
|
m_Pos.y += a_AddPosY;
|
||||||
m_Pos.z += a_AddPosZ;
|
m_Pos.z += a_AddPosZ;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "FireChargeEntity.h"
|
#include "FireChargeEntity.h"
|
||||||
#include "FireworkEntity.h"
|
#include "FireworkEntity.h"
|
||||||
#include "GhastFireballEntity.h"
|
#include "GhastFireballEntity.h"
|
||||||
|
#include "Player.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -67,16 +68,17 @@ protected:
|
|||||||
|
|
||||||
if (cBlockInfo::IsSolid(a_BlockType))
|
if (cBlockInfo::IsSolid(a_BlockType))
|
||||||
{
|
{
|
||||||
// The projectile hit a solid block
|
// The projectile hit a solid block, calculate the exact hit coords:
|
||||||
// Calculate the exact hit coords:
|
cBoundingBox bb(a_BlockX, a_BlockX + 1, a_BlockY, a_BlockY + 1, a_BlockZ, a_BlockZ + 1); // Bounding box of the block hit
|
||||||
cBoundingBox bb(a_BlockX, a_BlockX + 1, a_BlockY, a_BlockY + 1, a_BlockZ, a_BlockZ + 1);
|
const Vector3d LineStart = m_Projectile->GetPosition(); // Start point for the imaginary line that goes through the block hit
|
||||||
Vector3d Line1 = m_Projectile->GetPosition();
|
const Vector3d LineEnd = LineStart + m_Projectile->GetSpeed(); // End point for the imaginary line that goes through the block hit
|
||||||
Vector3d Line2 = Line1 + m_Projectile->GetSpeed();
|
double LineCoeff = 0; // Used to calculate where along the line an intersection with the bounding box occurs
|
||||||
double LineCoeff = 0;
|
eBlockFace Face; // Face hit
|
||||||
eBlockFace Face;
|
|
||||||
if (bb.CalcLineIntersection(Line1, Line2, LineCoeff, Face))
|
if (bb.CalcLineIntersection(LineStart, LineEnd, LineCoeff, Face))
|
||||||
{
|
{
|
||||||
Vector3d Intersection = Line1 + m_Projectile->GetSpeed() * LineCoeff;
|
Vector3d Intersection = LineStart + m_Projectile->GetSpeed() * LineCoeff; // Point where projectile goes into the hit block
|
||||||
|
|
||||||
if (cPluginManager::Get()->CallHookProjectileHitBlock(*m_Projectile, a_BlockX, a_BlockY, a_BlockZ, Face, &Intersection))
|
if (cPluginManager::Get()->CallHookProjectileHitBlock(*m_Projectile, a_BlockX, a_BlockY, a_BlockZ, Face, &Intersection))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -140,7 +142,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (
|
if (
|
||||||
(a_Entity == m_Projectile) || // Do not check collisions with self
|
(a_Entity == m_Projectile) || // Do not check collisions with self
|
||||||
(a_Entity == m_Projectile->GetCreator()) // Do not check whoever shot the projectile
|
(a_Entity->GetUniqueID() == m_Projectile->GetCreatorUniqueID()) // Do not check whoever shot the projectile
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// TODO: Don't check creator only for the first 5 ticks
|
// TODO: Don't check creator only for the first 5 ticks
|
||||||
@ -161,7 +163,12 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Some entities don't interact with the projectiles (pickups, falling blocks)
|
if (!a_Entity->IsMob() && !a_Entity->IsMinecart() && !a_Entity->IsPlayer() && !a_Entity->IsBoat())
|
||||||
|
{
|
||||||
|
// Not an entity that interacts with a projectile
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (cPluginManager::Get()->CallHookProjectileHitEntity(*m_Projectile, *a_Entity))
|
if (cPluginManager::Get()->CallHookProjectileHitEntity(*m_Projectile, *a_Entity))
|
||||||
{
|
{
|
||||||
// A plugin disagreed.
|
// A plugin disagreed.
|
||||||
@ -209,7 +216,10 @@ protected:
|
|||||||
cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height) :
|
cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height) :
|
||||||
super(etProjectile, a_X, a_Y, a_Z, a_Width, a_Height),
|
super(etProjectile, a_X, a_Y, a_Z, a_Width, a_Height),
|
||||||
m_ProjectileKind(a_Kind),
|
m_ProjectileKind(a_Kind),
|
||||||
m_Creator(a_Creator),
|
m_CreatorData(
|
||||||
|
((a_Creator != NULL) ? a_Creator->GetUniqueID() : -1),
|
||||||
|
((a_Creator != NULL) ? (a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : "") : "")
|
||||||
|
),
|
||||||
m_IsInGround(false)
|
m_IsInGround(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -221,7 +231,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a
|
|||||||
cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height) :
|
cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height) :
|
||||||
super(etProjectile, a_Pos.x, a_Pos.y, a_Pos.z, a_Width, a_Height),
|
super(etProjectile, a_Pos.x, a_Pos.y, a_Pos.z, a_Width, a_Height),
|
||||||
m_ProjectileKind(a_Kind),
|
m_ProjectileKind(a_Kind),
|
||||||
m_Creator(a_Creator),
|
m_CreatorData(a_Creator->GetUniqueID(), a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : ""),
|
||||||
m_IsInGround(false)
|
m_IsInGround(false)
|
||||||
{
|
{
|
||||||
SetSpeed(a_Speed);
|
SetSpeed(a_Speed);
|
||||||
@ -298,7 +308,7 @@ AString cProjectileEntity::GetMCAClassName(void) const
|
|||||||
case pkEgg: return "Egg";
|
case pkEgg: return "Egg";
|
||||||
case pkGhastFireball: return "Fireball";
|
case pkGhastFireball: return "Fireball";
|
||||||
case pkFireCharge: return "SmallFireball";
|
case pkFireCharge: return "SmallFireball";
|
||||||
case pkEnderPearl: return "ThrownEnderPearl";
|
case pkEnderPearl: return "ThrownEnderpearl";
|
||||||
case pkExpBottle: return "ThrownExpBottle";
|
case pkExpBottle: return "ThrownExpBottle";
|
||||||
case pkSplashPotion: return "ThrownPotion";
|
case pkSplashPotion: return "ThrownPotion";
|
||||||
case pkWitherSkull: return "WitherSkull";
|
case pkWitherSkull: return "WitherSkull";
|
||||||
@ -317,7 +327,8 @@ void cProjectileEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
|||||||
{
|
{
|
||||||
super::Tick(a_Dt, a_Chunk);
|
super::Tick(a_Dt, a_Chunk);
|
||||||
|
|
||||||
if (GetProjectileKind() != pkArrow) // See cArrow::Tick
|
// TODO: see BroadcastMovementUpdate; RelativeMove packet jerkiness affects projectiles too (cause of sympton described in cArrowEntity::Tick())
|
||||||
|
if (GetProjectileKind() != pkArrow)
|
||||||
{
|
{
|
||||||
BroadcastMovementUpdate();
|
BroadcastMovementUpdate();
|
||||||
}
|
}
|
||||||
@ -335,18 +346,9 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3d PerTickSpeed = GetSpeed() / 20;
|
const Vector3d PerTickSpeed = GetSpeed() / 20;
|
||||||
Vector3d Pos = GetPosition();
|
const Vector3d Pos = GetPosition();
|
||||||
|
const Vector3d NextPos = Pos + PerTickSpeed;
|
||||||
// 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))
|
|
||||||
{
|
|
||||||
// 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
|
|
||||||
|
|
||||||
// Test for entity collisions:
|
// Test for entity collisions:
|
||||||
cProjectileEntityCollisionCallback EntityCollisionCallback(this, Pos, NextPos);
|
cProjectileEntityCollisionCallback EntityCollisionCallback(this, Pos, NextPos);
|
||||||
@ -369,6 +371,15 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
|||||||
}
|
}
|
||||||
// TODO: Test the entities in the neighboring chunks, too
|
// TODO: Test the entities in the neighboring chunks, too
|
||||||
|
|
||||||
|
// Trace the tick's worth of movement as a line:
|
||||||
|
cProjectileTracerCallback TracerCallback(this);
|
||||||
|
if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, 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
|
||||||
|
|
||||||
// Update the position:
|
// Update the position:
|
||||||
SetPosition(NextPos);
|
SetPosition(NextPos);
|
||||||
|
|
||||||
|
@ -66,8 +66,15 @@ public:
|
|||||||
/// Returns the kind of the projectile (fast class identification)
|
/// Returns the kind of the projectile (fast class identification)
|
||||||
eKind GetProjectileKind(void) const { return m_ProjectileKind; }
|
eKind GetProjectileKind(void) const { return m_ProjectileKind; }
|
||||||
|
|
||||||
/// Returns the entity who created this projectile; may be NULL
|
/** Returns the unique ID of the entity who created this projectile
|
||||||
cEntity * GetCreator(void) { return m_Creator; }
|
May return an ID <0
|
||||||
|
*/
|
||||||
|
int GetCreatorUniqueID(void) { return m_CreatorData.m_UniqueID; }
|
||||||
|
|
||||||
|
/** Returns the name of the player that created the projectile
|
||||||
|
Will be empty for non-player creators
|
||||||
|
*/
|
||||||
|
AString GetCreatorName(void) const { return m_CreatorData.m_Name; }
|
||||||
|
|
||||||
/// Returns the string that is used as the entity type (class name) in MCA files
|
/// Returns the string that is used as the entity type (class name) in MCA files
|
||||||
AString GetMCAClassName(void) const;
|
AString GetMCAClassName(void) const;
|
||||||
@ -81,10 +88,29 @@ public:
|
|||||||
void SetIsInGround(bool a_IsInGround) { m_IsInGround = a_IsInGround; }
|
void SetIsInGround(bool a_IsInGround) { m_IsInGround = a_IsInGround; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
/** A structure that stores the Entity ID and Playername of the projectile's creator
|
||||||
|
Used to migitate invalid pointers caused by the creator being destroyed
|
||||||
|
*/
|
||||||
|
struct CreatorData
|
||||||
|
{
|
||||||
|
CreatorData(int a_UniqueID, const AString & a_Name) :
|
||||||
|
m_UniqueID(a_UniqueID),
|
||||||
|
m_Name(a_Name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const int m_UniqueID;
|
||||||
|
AString m_Name;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** The type of projectile I am */
|
||||||
eKind m_ProjectileKind;
|
eKind m_ProjectileKind;
|
||||||
|
|
||||||
/// The entity who has created this projectile; may be NULL (e. g. for dispensers)
|
/** The structure for containing the entity ID and name who has created this projectile
|
||||||
cEntity * m_Creator;
|
The ID and/or name may be NULL (e.g. for dispensers/mobs)
|
||||||
|
*/
|
||||||
|
CreatorData m_CreatorData;
|
||||||
|
|
||||||
/// True if the projectile has hit the ground and is stuck there
|
/// True if the projectile has hit the ground and is stuck there
|
||||||
bool m_IsInGround;
|
bool m_IsInGround;
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
|
|
||||||
|
|
||||||
cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||||
super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
|
||||||
|
m_DestroyTimer(-1)
|
||||||
{
|
{
|
||||||
SetSpeed(a_Speed);
|
SetSpeed(a_Speed);
|
||||||
}
|
}
|
||||||
@ -21,7 +22,7 @@ void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_H
|
|||||||
{
|
{
|
||||||
TrySpawnChicken(a_HitPos);
|
TrySpawnChicken(a_HitPos);
|
||||||
|
|
||||||
Destroy();
|
m_DestroyTimer = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ void cThrownEggEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_Hit
|
|||||||
TrySpawnChicken(a_HitPos);
|
TrySpawnChicken(a_HitPos);
|
||||||
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
||||||
|
|
||||||
Destroy(true);
|
m_DestroyTimer = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,8 +30,29 @@ protected:
|
|||||||
// cProjectileEntity overrides:
|
// cProjectileEntity overrides:
|
||||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||||
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||||
|
virtual void Tick (float a_Dt, cChunk & a_Chunk) override
|
||||||
|
{
|
||||||
|
if (m_DestroyTimer > 0)
|
||||||
|
{
|
||||||
|
m_DestroyTimer--;
|
||||||
|
if (m_DestroyTimer == 0)
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
super::Tick(a_Dt, a_Chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Randomly decides whether to spawn a chicken where the egg lands.
|
// Randomly decides whether to spawn a chicken where the egg lands.
|
||||||
void TrySpawnChicken(const Vector3d & a_HitPos);
|
void TrySpawnChicken(const Vector3d & a_HitPos);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** Time in ticks to wait for the hit animation to begin before destroying */
|
||||||
|
int m_DestroyTimer;
|
||||||
|
|
||||||
} ; // tolua_export
|
} ; // tolua_export
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
#include "ThrownEnderPearlEntity.h"
|
#include "ThrownEnderPearlEntity.h"
|
||||||
|
#include "Player.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||||
super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
|
||||||
|
m_DestroyTimer(-1)
|
||||||
{
|
{
|
||||||
SetSpeed(a_Speed);
|
SetSpeed(a_Speed);
|
||||||
}
|
}
|
||||||
@ -21,7 +23,7 @@ void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockF
|
|||||||
// TODO: Tweak a_HitPos based on block face.
|
// TODO: Tweak a_HitPos based on block face.
|
||||||
TeleportCreator(a_HitPos);
|
TeleportCreator(a_HitPos);
|
||||||
|
|
||||||
Destroy();
|
m_DestroyTimer = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -36,7 +38,7 @@ void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d
|
|||||||
TeleportCreator(a_HitPos);
|
TeleportCreator(a_HitPos);
|
||||||
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
||||||
|
|
||||||
Destroy(true);
|
m_DestroyTimer = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -45,10 +47,34 @@ void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d
|
|||||||
|
|
||||||
void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos)
|
void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos)
|
||||||
{
|
{
|
||||||
// Teleport the creator here, make them take 5 damage:
|
if (m_CreatorData.m_Name.empty())
|
||||||
if (m_Creator != NULL)
|
|
||||||
{
|
{
|
||||||
m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5);
|
return;
|
||||||
m_Creator->TakeDamage(dtEnderPearl, this, 5, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class cProjectileCreatorCallbackForPlayers : public cPlayerListCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cProjectileCreatorCallbackForPlayers(cEntity * a_Attacker, Vector3i a_HitPos) :
|
||||||
|
m_Attacker(a_Attacker),
|
||||||
|
m_HitPos(a_HitPos)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Item(cPlayer * a_Entity) override
|
||||||
|
{
|
||||||
|
// Teleport the creator here, make them take 5 damage:
|
||||||
|
a_Entity->TeleportToCoords(m_HitPos.x, m_HitPos.y + 0.2, m_HitPos.z);
|
||||||
|
a_Entity->TakeDamage(dtEnderPearl, m_Attacker, 5, 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
cEntity * m_Attacker;
|
||||||
|
Vector3i m_HitPos;
|
||||||
|
};
|
||||||
|
|
||||||
|
cProjectileCreatorCallbackForPlayers PCCFP(this, a_HitPos);
|
||||||
|
GetWorld()->FindAndDoWithPlayer(m_CreatorData.m_Name, PCCFP);
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,29 @@ protected:
|
|||||||
// cProjectileEntity overrides:
|
// cProjectileEntity overrides:
|
||||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||||
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||||
|
virtual void Tick (float a_Dt, cChunk & a_Chunk) override
|
||||||
|
{
|
||||||
|
if (m_DestroyTimer > 0)
|
||||||
|
{
|
||||||
|
m_DestroyTimer--;
|
||||||
|
if (m_DestroyTimer == 0)
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
super::Tick(a_Dt, a_Chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Teleports the creator where the ender pearl lands.
|
/** Teleports the creator where the ender pearl lands */
|
||||||
void TeleportCreator(const Vector3d & a_HitPos);
|
void TeleportCreator(const Vector3d & a_HitPos);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** Time in ticks to wait for the hit animation to begin before destroying */
|
||||||
|
int m_DestroyTimer;
|
||||||
|
|
||||||
} ; // tolua_export
|
} ; // tolua_export
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
|
|
||||||
|
|
||||||
cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||||
super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
|
||||||
|
m_DestroyTimer(-1)
|
||||||
{
|
{
|
||||||
SetSpeed(a_Speed);
|
SetSpeed(a_Speed);
|
||||||
}
|
}
|
||||||
@ -19,7 +20,7 @@ cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, do
|
|||||||
|
|
||||||
void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||||
{
|
{
|
||||||
Destroy();
|
m_DestroyTimer = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -40,5 +41,5 @@ void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d &
|
|||||||
// TODO: If entity is Ender Crystal, destroy it
|
// TODO: If entity is Ender Crystal, destroy it
|
||||||
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
||||||
|
|
||||||
Destroy(true);
|
m_DestroyTimer = 5;
|
||||||
}
|
}
|
||||||
|
@ -30,5 +30,26 @@ protected:
|
|||||||
// cProjectileEntity overrides:
|
// cProjectileEntity overrides:
|
||||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||||
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||||
|
virtual void Tick (float a_Dt, cChunk & a_Chunk) override
|
||||||
|
{
|
||||||
|
if (m_DestroyTimer > 0)
|
||||||
|
{
|
||||||
|
m_DestroyTimer--;
|
||||||
|
if (m_DestroyTimer == 0)
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
super::Tick(a_Dt, a_Chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** Time in ticks to wait for the hit animation to begin before destroying */
|
||||||
|
int m_DestroyTimer;
|
||||||
|
|
||||||
} ; // tolua_export
|
} ; // tolua_export
|
||||||
|
@ -67,9 +67,27 @@ void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer)
|
|||||||
}
|
}
|
||||||
AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_GUNPOWDER);
|
AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_GUNPOWDER);
|
||||||
|
|
||||||
if ((a_Killer != NULL) && (a_Killer->IsProjectile()))
|
if ((a_Killer != NULL) && a_Killer->IsProjectile() && (((cProjectileEntity *)a_Killer)->GetCreatorUniqueID() >= 0))
|
||||||
{
|
{
|
||||||
if (((cMonster *)((cProjectileEntity *)a_Killer)->GetCreator())->GetMobType() == mtSkeleton)
|
class cProjectileCreatorCallback : public cEntityCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cProjectileCreatorCallback(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Item(cEntity * a_Entity) override
|
||||||
|
{
|
||||||
|
if (a_Entity->IsMob() && ((cMonster *)a_Entity)->GetMobType() == mtSkeleton)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
cProjectileCreatorCallback PCC;
|
||||||
|
if (GetWorld()->DoWithEntityByID(((cProjectileEntity *)a_Killer)->GetCreatorUniqueID(), PCC))
|
||||||
{
|
{
|
||||||
// 12 music discs. TickRand starts from 0 to 11. Disk IDs start at 2256, so add that. There.
|
// 12 music discs. TickRand starts from 0 to 11. Disk IDs start at 2256, so add that. There.
|
||||||
AddRandomDropItem(a_Drops, 1, 1, (short)m_World->GetTickRandomNumber(11) + 2256);
|
AddRandomDropItem(a_Drops, 1, 1, (short)m_World->GetTickRandomNumber(11) + 2256);
|
||||||
|
@ -49,11 +49,10 @@ void cSkeleton::GetDrops(cItems & a_Drops, cEntity * a_Killer)
|
|||||||
|
|
||||||
void cSkeleton::MoveToPosition(const Vector3f & a_Position)
|
void cSkeleton::MoveToPosition(const Vector3f & a_Position)
|
||||||
{
|
{
|
||||||
// If the destination is in the sun and if it is not night AND the skeleton isn't on fire then block the movement.
|
// If the destination is sufficiently skylight challenged AND the skeleton isn't on fire then block the movement
|
||||||
if (
|
if (
|
||||||
!IsOnFire() &&
|
!IsOnFire() &&
|
||||||
(m_World->GetTimeOfDay() < 13187) &&
|
(m_World->GetBlockSkyLight((int)floor(a_Position.x), (int)floor(a_Position.y), (int)floor(a_Position.z)) - m_World->GetSkyDarkness() > 8)
|
||||||
(m_World->GetBlockSkyLight((int) a_Position.x, (int) a_Position.y, (int) a_Position.z) == 15)
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
m_bMovingToDestination = false;
|
m_bMovingToDestination = false;
|
||||||
|
@ -44,11 +44,10 @@ void cZombie::GetDrops(cItems & a_Drops, cEntity * a_Killer)
|
|||||||
|
|
||||||
void cZombie::MoveToPosition(const Vector3f & a_Position)
|
void cZombie::MoveToPosition(const Vector3f & a_Position)
|
||||||
{
|
{
|
||||||
// If the destination is in the sun and if it is not night AND the zombie isn't on fire then block the movement.
|
// If the destination is sufficiently skylight challenged AND the skeleton isn't on fire then block the movement
|
||||||
if (
|
if (
|
||||||
!IsOnFire() &&
|
!IsOnFire() &&
|
||||||
(m_World->GetTimeOfDay() < 13187) &&
|
(m_World->GetBlockSkyLight((int)floor(a_Position.x), (int)floor(a_Position.y), (int)floor(a_Position.z)) - m_World->GetSkyDarkness() > 8)
|
||||||
(m_World->GetBlockSkyLight((int)a_Position.x, (int)a_Position.y, (int)a_Position.z) == 15)
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
m_bMovingToDestination = false;
|
m_bMovingToDestination = false;
|
||||||
|
@ -2333,7 +2333,7 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
|
|||||||
|
|
||||||
for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings
|
for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings
|
||||||
{
|
{
|
||||||
AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a newline, used internally by MCS to display a new line in the client; don't forget to c_str ;)
|
AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a grave accent/backtick, used internally by MCS to display a new line in the client; don't forget to c_str ;)
|
||||||
}
|
}
|
||||||
|
|
||||||
a_Item.m_Lore = Lore;
|
a_Item.m_Lore = Lore;
|
||||||
|
@ -134,6 +134,16 @@ public:
|
|||||||
z += a_Diff.z;
|
z += a_Diff.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Runs each value of the vector through std::floor() */
|
||||||
|
inline Vector3<int> Floor(void) const
|
||||||
|
{
|
||||||
|
return Vector3<int>(
|
||||||
|
(int)floor(x),
|
||||||
|
(int)floor(y),
|
||||||
|
(int)floor(z)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
inline bool operator != (const Vector3<T> & a_Rhs) const
|
inline bool operator != (const Vector3<T> & a_Rhs) const
|
||||||
@ -146,6 +156,16 @@ public:
|
|||||||
return Equals(a_Rhs);
|
return Equals(a_Rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool operator > (const Vector3<T> & a_Rhs) const
|
||||||
|
{
|
||||||
|
return (SqrLength() > a_Rhs.SqrLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator < (const Vector3<T> & a_Rhs) const
|
||||||
|
{
|
||||||
|
return (SqrLength() < a_Rhs.SqrLength());
|
||||||
|
}
|
||||||
|
|
||||||
inline void operator += (const Vector3<T> & a_Rhs)
|
inline void operator += (const Vector3<T> & a_Rhs)
|
||||||
{
|
{
|
||||||
x += a_Rhs.x;
|
x += a_Rhs.x;
|
||||||
@ -288,6 +308,7 @@ protected:
|
|||||||
{
|
{
|
||||||
return (a_Value < 0) ? -a_Value : a_Value;
|
return (a_Value < 0) ? -a_Value : a_Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
|
@ -589,20 +589,19 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
|
|||||||
m_Writer.BeginCompound("");
|
m_Writer.BeginCompound("");
|
||||||
AddBasicEntity(a_Projectile, a_Projectile->GetMCAClassName());
|
AddBasicEntity(a_Projectile, a_Projectile->GetMCAClassName());
|
||||||
Vector3d Pos = a_Projectile->GetPosition();
|
Vector3d Pos = a_Projectile->GetPosition();
|
||||||
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
|
|
||||||
m_Writer.AddShort("shake", 0); // TODO: Any shake?
|
|
||||||
m_Writer.AddByte("inGround", a_Projectile->IsInGround() ? 1 : 0);
|
m_Writer.AddByte("inGround", a_Projectile->IsInGround() ? 1 : 0);
|
||||||
|
|
||||||
switch (a_Projectile->GetProjectileKind())
|
switch (a_Projectile->GetProjectileKind())
|
||||||
{
|
{
|
||||||
case cProjectileEntity::pkArrow:
|
case cProjectileEntity::pkArrow:
|
||||||
{
|
{
|
||||||
m_Writer.AddByte("inData", 0); // TODO: Query the block meta (is it needed?)
|
cArrowEntity * Arrow = (cArrowEntity *)a_Projectile;
|
||||||
m_Writer.AddByte("pickup", ((cArrowEntity *)a_Projectile)->GetPickupState());
|
|
||||||
m_Writer.AddDouble("damage", ((cArrowEntity *)a_Projectile)->GetDamageCoeff());
|
m_Writer.AddInt("xTile", (Int16)Arrow->GetBlockHit().x);
|
||||||
|
m_Writer.AddInt("yTile", (Int16)Arrow->GetBlockHit().y);
|
||||||
|
m_Writer.AddInt("zTile", (Int16)Arrow->GetBlockHit().z);
|
||||||
|
m_Writer.AddByte("pickup", Arrow->GetPickupState());
|
||||||
|
m_Writer.AddDouble("damage", Arrow->GetDamageCoeff());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case cProjectileEntity::pkGhastFireball:
|
case cProjectileEntity::pkGhastFireball:
|
||||||
@ -621,13 +620,10 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
|
|||||||
ASSERT(!"Unsaved projectile entity!");
|
ASSERT(!"Unsaved projectile entity!");
|
||||||
}
|
}
|
||||||
} // switch (ProjectileKind)
|
} // switch (ProjectileKind)
|
||||||
cEntity * Creator = a_Projectile->GetCreator();
|
|
||||||
if (Creator != NULL)
|
if (!a_Projectile->GetCreatorName().empty())
|
||||||
{
|
{
|
||||||
if (Creator->GetEntityType() == cEntity::etPlayer)
|
m_Writer.AddString("ownerName", a_Projectile->GetCreatorName());
|
||||||
{
|
|
||||||
m_Writer.AddString("ownerName", ((cPlayer *)Creator)->GetName());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
m_Writer.EndCompound();
|
m_Writer.EndCompound();
|
||||||
}
|
}
|
||||||
|
@ -1642,6 +1642,15 @@ void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
|
|||||||
Arrow->SetDamageCoeff(a_NBT.GetDouble(DamageIdx));
|
Arrow->SetDamageCoeff(a_NBT.GetDouble(DamageIdx));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load block hit:
|
||||||
|
int InBlockXIdx = a_NBT.FindChildByName(a_TagIdx, "xTile");
|
||||||
|
int InBlockYIdx = a_NBT.FindChildByName(a_TagIdx, "yTile");
|
||||||
|
int InBlockZIdx = a_NBT.FindChildByName(a_TagIdx, "zTile");
|
||||||
|
if ((InBlockXIdx > 0) && (InBlockYIdx > 0) && (InBlockZIdx > 0))
|
||||||
|
{
|
||||||
|
Arrow->SetBlockHit(Vector3i(a_NBT.GetInt(InBlockXIdx), a_NBT.GetInt(InBlockYIdx), a_NBT.GetInt(InBlockZIdx)));
|
||||||
|
}
|
||||||
|
|
||||||
// Store the new arrow in the entities list:
|
// Store the new arrow in the entities list:
|
||||||
a_Entities.push_back(Arrow.release());
|
a_Entities.push_back(Arrow.release());
|
||||||
}
|
}
|
||||||
@ -2474,8 +2483,6 @@ bool cWSSAnvil::LoadProjectileBaseFromNBT(cProjectileEntity & a_Entity, const cP
|
|||||||
}
|
}
|
||||||
a_Entity.SetIsInGround(IsInGround);
|
a_Entity.SetIsInGround(IsInGround);
|
||||||
|
|
||||||
// TODO: Load inTile, TileCoords
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user