summaryrefslogtreecommitdiffstats
path: root/source/Entities
diff options
context:
space:
mode:
authormadmaxoft <github@xoft.cz>2013-08-30 14:32:07 +0200
committermadmaxoft <github@xoft.cz>2013-08-30 14:32:07 +0200
commitc28ccdc9d56497d42c2a97554a96de76e0d2ee68 (patch)
treef1a1f5629ae7e2565330580ab4e6fe76466acf6e /source/Entities
parentAdded the login sequence of a vanilla client to the docs. (diff)
parentShooting a bow kinda works. (diff)
downloadcuberite-c28ccdc9d56497d42c2a97554a96de76e0d2ee68.tar
cuberite-c28ccdc9d56497d42c2a97554a96de76e0d2ee68.tar.gz
cuberite-c28ccdc9d56497d42c2a97554a96de76e0d2ee68.tar.bz2
cuberite-c28ccdc9d56497d42c2a97554a96de76e0d2ee68.tar.lz
cuberite-c28ccdc9d56497d42c2a97554a96de76e0d2ee68.tar.xz
cuberite-c28ccdc9d56497d42c2a97554a96de76e0d2ee68.tar.zst
cuberite-c28ccdc9d56497d42c2a97554a96de76e0d2ee68.zip
Diffstat (limited to '')
-rw-r--r--source/Entities/Entity.cpp49
-rw-r--r--source/Entities/Entity.h5
-rw-r--r--source/Entities/FallingBlock.cpp14
-rw-r--r--source/Entities/FallingBlock.h1
-rw-r--r--source/Entities/Minecart.cpp14
-rw-r--r--source/Entities/Minecart.h1
-rw-r--r--source/Entities/Pickup.cpp14
-rw-r--r--source/Entities/Pickup.h2
-rw-r--r--source/Entities/Player.cpp44
-rw-r--r--source/Entities/Player.h15
-rw-r--r--source/Entities/ProjectileEntity.cpp296
-rw-r--r--source/Entities/ProjectileEntity.h102
-rw-r--r--source/Entities/TNTEntity.cpp14
-rw-r--r--source/Entities/TNTEntity.h1
14 files changed, 482 insertions, 90 deletions
diff --git a/source/Entities/Entity.cpp b/source/Entities/Entity.cpp
index 19a65ef4e..b936d8d73 100644
--- a/source/Entities/Entity.cpp
+++ b/source/Entities/Entity.cpp
@@ -144,6 +144,10 @@ bool cEntity::Initialize(cWorld * a_World)
m_World->AddEntity(this);
cPluginManager::Get()->CallHookSpawnedEntity(*a_World, *this);
+
+ // Spawn the entity on the clients:
+ a_World->BroadcastSpawnEntity(*this);
+
return true;
}
@@ -477,7 +481,7 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
// TODO Add collision detection with entities.
- a_Dt /= 1000;
+ a_Dt /= 1000; // Convert from msec to sec
Vector3d NextPos = Vector3d(GetPosX(),GetPosY(),GetPosZ());
Vector3d NextSpeed = Vector3d(GetSpeedX(),GetSpeedY(),GetSpeedZ());
int BlockX = (int) floor(NextPos.x);
@@ -493,7 +497,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
}
// Make sure we got the correct chunk and a valid one. No one ever knows...
- cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX,BlockZ);
+ cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
if (NextChunk != NULL)
{
int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width);
@@ -512,11 +516,12 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
}
else
{
- //Push out entity.
+ // Push out entity.
m_bOnGround = true;
NextPos.y += 0.2;
- LOGD("Entity #%d (%s) is inside a block at {%d,%d,%d}",
- m_UniqueID, GetClass(), BlockX, BlockY, BlockZ);
+ LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}",
+ m_UniqueID, GetClass(), BlockX, BlockY, BlockZ
+ );
}
if (!m_bOnGround)
@@ -524,34 +529,40 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
float fallspeed;
if (IsBlockWater(BlockIn))
{
- fallspeed = -3.0f * a_Dt; //Fall slower in water.
+ fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water.
}
else if (BlockIn == E_BLOCK_COBWEB)
{
- NextSpeed.y *= 0.05; //Reduce overall falling speed
- fallspeed = 0; //No falling.
+ NextSpeed.y *= 0.05; // Reduce overall falling speed
+ fallspeed = 0; // No falling.
}
else
{
- //Normal gravity
+ // Normal gravity
fallspeed = m_Gravity * a_Dt;
}
NextSpeed.y += fallspeed;
}
else
{
- //Friction
+ // Friction
if (NextSpeed.SqrLength() > 0.0004f)
{
- NextSpeed.x *= 0.7f/(1+a_Dt);
- if ( fabs(NextSpeed.x) < 0.05 ) NextSpeed.x = 0;
- NextSpeed.z *= 0.7f/(1+a_Dt);
- if ( fabs(NextSpeed.z) < 0.05 ) NextSpeed.z = 0;
+ NextSpeed.x *= 0.7f / (1 + a_Dt);
+ if (fabs(NextSpeed.x) < 0.05)
+ {
+ NextSpeed.x = 0;
+ }
+ NextSpeed.z *= 0.7f / (1 + a_Dt);
+ if (fabs(NextSpeed.z) < 0.05)
+ {
+ NextSpeed.z = 0;
+ }
}
}
- //Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we
- //might have different speed modifiers according to terrain.
+ // Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we
+ // might have different speed modifiers according to terrain.
if (BlockIn == E_BLOCK_COBWEB)
{
NextSpeed.x *= 0.25;
@@ -1028,9 +1039,9 @@ void cEntity::SetMass(double a_Mass)
}
else
{
- //Make sure that mass is not zero. 1g is the default because we
- //have to choose a number. It's perfectly legal to have a mass
- //less than 1g as long as is NOT equal or less than zero.
+ // Make sure that mass is not zero. 1g is the default because we
+ // have to choose a number. It's perfectly legal to have a mass
+ // less than 1g as long as is NOT equal or less than zero.
m_Mass = 0.001;
}
}
diff --git a/source/Entities/Entity.h b/source/Entities/Entity.h
index 7a070a5dd..f407cd2c1 100644
--- a/source/Entities/Entity.h
+++ b/source/Entities/Entity.h
@@ -90,12 +90,13 @@ public:
etPlayer,
etPickup,
etMonster,
- etMob = etMonster, // DEPRECATED, use etMonster instead!
etFallingBlock,
etMinecart,
etTNT,
+ etProjectile,
// DEPRECATED older constants, left over for compatibility reasons (plugins)
+ etMob = etMonster, // DEPRECATED, use etMonster instead!
eEntityType_Entity = etEntity,
eEntityType_Player = etPlayer,
eEntityType_Pickup = etPickup,
@@ -162,7 +163,7 @@ public:
void SetPosY (double a_PosY);
void SetPosZ (double a_PosZ);
void SetPosition(double a_PosX, double a_PosY, double a_PosZ);
- void SetPosition(const Vector3d & a_Pos) { SetPosition(a_Pos.x,a_Pos.y,a_Pos.z);}
+ void SetPosition(const Vector3d & a_Pos) { SetPosition(a_Pos.x, a_Pos.y, a_Pos.z); }
void SetRot (const Vector3f & a_Rot);
void SetRotation(double a_Rotation);
void SetPitch (double a_Pitch);
diff --git a/source/Entities/FallingBlock.cpp b/source/Entities/FallingBlock.cpp
index 237327975..9fcd9ac80 100644
--- a/source/Entities/FallingBlock.cpp
+++ b/source/Entities/FallingBlock.cpp
@@ -22,20 +22,6 @@ cFallingBlock::cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_Block
-bool cFallingBlock::Initialize(cWorld * a_World)
-{
- if (super::Initialize(a_World))
- {
- a_World->BroadcastSpawnEntity(*this);
- return true;
- }
- return false;
-}
-
-
-
-
-
void cFallingBlock::SpawnOn(cClientHandle & a_ClientHandle)
{
a_ClientHandle.SendSpawnFallingBlock(*this);
diff --git a/source/Entities/FallingBlock.h b/source/Entities/FallingBlock.h
index 13931f061..5ba9909bb 100644
--- a/source/Entities/FallingBlock.h
+++ b/source/Entities/FallingBlock.h
@@ -29,7 +29,6 @@ public:
NIBBLETYPE GetBlockMeta(void) const { return m_BlockMeta; }
// cEntity overrides:
- virtual bool Initialize(cWorld * a_World) override;
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
diff --git a/source/Entities/Minecart.cpp b/source/Entities/Minecart.cpp
index 3e6069237..808579582 100644
--- a/source/Entities/Minecart.cpp
+++ b/source/Entities/Minecart.cpp
@@ -22,20 +22,6 @@ cMinecart::cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z) :
-bool cMinecart::Initialize(cWorld * a_World)
-{
- if (super::Initialize(a_World))
- {
- a_World->BroadcastSpawnEntity(*this);
- return true;
- }
- return false;
-}
-
-
-
-
-
void cMinecart::SpawnOn(cClientHandle & a_ClientHandle)
{
char Type = 0;
diff --git a/source/Entities/Minecart.h b/source/Entities/Minecart.h
index 91336673d..c1a0e84a0 100644
--- a/source/Entities/Minecart.h
+++ b/source/Entities/Minecart.h
@@ -35,7 +35,6 @@ public:
} ;
// cEntity overrides:
- virtual bool Initialize(cWorld * a_World) override;
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
diff --git a/source/Entities/Pickup.cpp b/source/Entities/Pickup.cpp
index c8f36d503..9b388366a 100644
--- a/source/Entities/Pickup.cpp
+++ b/source/Entities/Pickup.cpp
@@ -40,20 +40,6 @@ cPickup::cPickup(int a_MicroPosX, int a_MicroPosY, int a_MicroPosZ, const cItem
-bool cPickup::Initialize(cWorld * a_World)
-{
- if (super::Initialize(a_World))
- {
- a_World->BroadcastSpawnEntity(*this);
- return true;
- }
- return false;
-}
-
-
-
-
-
void cPickup::SpawnOn(cClientHandle & a_Client)
{
a_Client.SendPickupSpawn(*this);
diff --git a/source/Entities/Pickup.h b/source/Entities/Pickup.h
index b0323dd92..af6eaf3bb 100644
--- a/source/Entities/Pickup.h
+++ b/source/Entities/Pickup.h
@@ -26,8 +26,6 @@ public:
cPickup(int a_MicroPosX, int a_MicroPosY, int a_MicroPosZ, const cItem & a_Item, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f); // tolua_export
- virtual bool Initialize(cWorld * a_World) override;
-
cItem & GetItem(void) {return m_Item; } // tolua_export
const cItem & GetItem(void) const {return m_Item; }
diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp
index 119afbafc..0cb047933 100644
--- a/source/Entities/Player.cpp
+++ b/source/Entities/Player.cpp
@@ -64,6 +64,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
, m_IsSwimming(false)
, m_IsSubmerged(false)
, m_EatingFinishTick(-1)
+ , m_IsChargingBow(false)
+ , m_BowCharge(0)
{
LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
a_PlayerName.c_str(), a_Client->GetIPString().c_str(),
@@ -213,6 +215,13 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
// Handle air drowning stuff
HandleAir();
+
+ // Handle charging the bow:
+ if (m_IsChargingBow)
+ {
+ m_BowCharge += 1;
+ LOGD("Player \"%s\" charging bow: %d", m_PlayerName.c_str(), m_BowCharge);
+ }
if (m_bDirtyPosition)
{
@@ -253,6 +262,41 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
+void cPlayer::StartChargingBow(void)
+{
+ LOGD("Player \"%s\" started charging their bow", m_PlayerName.c_str());
+ m_IsChargingBow = true;
+ m_BowCharge = 0;
+}
+
+
+
+
+
+int cPlayer::FinishChargingBow(void)
+{
+ LOGD("Player \"%s\" finished charging their bow at a charge of %d", m_PlayerName.c_str(), m_BowCharge);
+ int res = m_BowCharge;
+ m_IsChargingBow = false;
+ m_BowCharge = 0;
+ return res;
+}
+
+
+
+
+
+void cPlayer::CancelChargingBow(void)
+{
+ LOGD("Player \"%s\" cancelled charging their bow at a charge of %d", m_PlayerName.c_str(), m_BowCharge);
+ m_IsChargingBow = false;
+ m_BowCharge = 0;
+}
+
+
+
+
+
void cPlayer::SetTouchGround(bool a_bTouchGround)
{
// If just
diff --git a/source/Entities/Player.h b/source/Entities/Player.h
index 5dcce8421..4adf946db 100644
--- a/source/Entities/Player.h
+++ b/source/Entities/Player.h
@@ -62,6 +62,18 @@ public:
/// Returns the currently equipped boots; empty item if none
virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); }
+
+ /// Starts charging the equipped bow
+ void StartChargingBow(void);
+
+ /// Finishes charging the current bow. Returns the number of ticks for which the bow has been charged
+ int FinishChargingBow(void);
+
+ /// Cancels the current bow charging
+ void CancelChargingBow(void);
+
+ /// Returns true if the player is currently charging the bow
+ bool IsChargingBox(void) const { return m_IsChargingBow; }
void SetTouchGround( bool a_bTouchGround );
inline void SetStance( const double a_Stance ) { m_Stance = a_Stance; }
@@ -351,6 +363,9 @@ protected:
/// The world tick in which eating will be finished. -1 if not eating
Int64 m_EatingFinishTick;
+
+ bool m_IsChargingBow;
+ int m_BowCharge;
virtual void Destroyed(void);
diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp
new file mode 100644
index 000000000..f405e9aa4
--- /dev/null
+++ b/source/Entities/ProjectileEntity.cpp
@@ -0,0 +1,296 @@
+
+// ProjectileEntity.cpp
+
+// Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types
+
+#include "Globals.h"
+#include "ProjectileEntity.h"
+#include "../ClientHandle.h"
+#include "Player.h"
+#include "../LineBlockTracer.h"
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cProjectileTracerCallback:
+
+class cProjectileTracerCallback :
+ public cBlockTracer::cCallbacks
+{
+public:
+ cProjectileTracerCallback(cProjectileEntity * a_Projectile) :
+ m_Projectile(a_Projectile)
+ {
+ }
+
+protected:
+ cProjectileEntity * m_Projectile;
+
+ virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
+ {
+ if (g_BlockIsSolid[a_BlockType])
+ {
+ // The projectile hit a solid block
+ m_Projectile->OnHitSolidBlock(a_BlockX, a_BlockY, a_BlockZ, a_EntryFace);
+ return true;
+ }
+
+ // Convey some special effects from special blocks:
+ switch (a_BlockType)
+ {
+ case E_BLOCK_LAVA:
+ case E_BLOCK_STATIONARY_LAVA:
+ {
+ m_Projectile->StartBurning(30);
+ break;
+ }
+ case E_BLOCK_WATER:
+ case E_BLOCK_STATIONARY_WATER:
+ {
+ m_Projectile->StopBurning();
+ break;
+ }
+ } // switch (a_BlockType)
+
+ // Continue tracing
+ return false;
+ }
+} ;
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cProjectileEntity:
+
+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),
+ m_ProjectileKind(a_Kind),
+ m_Creator(a_Creator),
+ m_IsInGround(false)
+{
+}
+
+
+
+
+
+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),
+ m_ProjectileKind(a_Kind),
+ m_Creator(a_Creator),
+ m_IsInGround(false)
+{
+ SetSpeed(a_Speed);
+}
+
+
+
+
+
+cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed)
+{
+ Vector3d Speed;
+ if (a_Speed != NULL)
+ {
+ Speed = *a_Speed;
+ }
+
+ switch (a_Kind)
+ {
+ case pkArrow: return new cArrowEntity(a_Creator, a_X, a_Y, a_Z, Speed);
+ // TODO: the rest
+ }
+
+ LOGWARNING("%s: Unknown kind: %d", __FUNCTION__, a_Kind);
+ return NULL;
+}
+
+
+
+
+
+void cProjectileEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace)
+{
+ // 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;
+ }
+ 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
+ );
+
+ m_IsInGround = true;
+}
+
+
+
+
+
+AString cProjectileEntity::GetMCAClassName(void) const
+{
+ switch (m_ProjectileKind)
+ {
+ case pkArrow: return "Arrow";
+ case pkSnowball: return "Snowball";
+ case pkEgg: return "Egg";
+ case pkGhastFireball: return "Fireball";
+ case pkFireCharge: return "SmallFireball";
+ case pkEnderPearl: return "ThrownEnderPearl";
+ case pkExpBottle: return "ThrownExpBottle";
+ case pkSplashPotion: return "ThrownPotion";
+ case pkWitherSkull: return "WitherSkull";
+ case pkFishingFloat: return ""; // Unknown, perhaps MC doesn't save this?
+ }
+ ASSERT(!"Unhandled projectile entity kind!");
+ return "";
+}
+
+
+
+
+
+void cProjectileEntity::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+ BroadcastMovementUpdate();
+}
+
+
+
+
+
+void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
+{
+ if (m_IsInGround)
+ {
+ // Already-grounded projectiles don't move at all
+ return;
+ }
+
+ Vector3d PerTickSpeed = GetSpeed() / 20;
+ Vector3d Pos = GetPosition();
+
+ // 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))
+ {
+ // Nothing in the way, update the position
+ SetPosition(NextPos);
+ }
+
+ // Add gravity effect to the vertical speed component:
+ SetSpeedY(GetSpeedY() + m_Gravity / 20);
+
+ // DEBUG:
+ LOGD("Arrow %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}",
+ m_UniqueID,
+ GetPosX(), GetPosY(), GetPosZ(),
+ GetSpeedX(), GetSpeedY(), GetSpeedZ()
+ );
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cArrowEntity:
+
+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)
+{
+ SetSpeed(a_Speed);
+ SetMass(0.1);
+ LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f}",
+ m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ()
+ );
+}
+
+
+
+
+
+cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
+ super(pkArrow, &a_Player, PosFromPlayerPos(a_Player), SpeedFromPlayerLook(a_Player, a_Force), 0.5, 0.5),
+ m_PickupState(psInSurvivalOrCreative),
+ m_DamageCoeff(2)
+{
+}
+
+
+
+
+
+Vector3d cArrowEntity::PosFromPlayerPos(const cPlayer & a_Player)
+{
+ Vector3d res = a_Player.GetEyePosition();
+
+ // Adjust the position to be just outside the player's bounding box:
+ res.x += 0.16 * cos(a_Player.GetPitch());
+ res.y += -0.1;
+ res.z += 0.16 * sin(a_Player.GetPitch());
+
+ return res;
+}
+
+
+
+
+
+Vector3d cArrowEntity::SpeedFromPlayerLook(const cPlayer & a_Player, double a_Force)
+{
+ Vector3d res = a_Player.GetLookVector();
+ res.Normalize();
+
+ // TODO: Add a slight random change (+-0.0075 in each direction)
+
+ return res * a_Force * 1.5 * 20;
+}
+
+
+
+
+
+bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
+{
+ switch (m_PickupState)
+ {
+ case psNoPickup: return false;
+ case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative());
+ case psInCreative: return a_Player.IsGameModeCreative();
+ }
+ ASSERT(!"Unhandled pickup state");
+ return false;
+}
+
+
+
+
+
+void cArrowEntity::SpawnOn(cClientHandle & a_Client)
+{
+ a_Client.SendSpawnObject(*this, pkArrow, 0, 0, 0);
+}
+
+
+
+
diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h
index 2e050068b..1569ad035 100644
--- a/source/Entities/ProjectileEntity.h
+++ b/source/Entities/ProjectileEntity.h
@@ -1,7 +1,7 @@
// ProjectileEntity.h
-// Declares the cProjectileEntity class representing the common base class for projectiles
+// Declares the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types
@@ -29,8 +29,8 @@ public:
pkArrow = 60,
pkSnowball = 61,
pkEgg = 62,
- pkGhastFireball = 63, // TODO: Unverified TypeID, check this in ProtoProxy
- pkFireCharge = 64, // TODO: Unverified TypeID, check this in ProtoProxy
+ pkGhastFireball = 63,
+ pkFireCharge = 64,
pkEnderPearl = 65,
pkExpBottle = 75,
pkSplashPotion = 73,
@@ -38,17 +38,48 @@ public:
pkFishingFloat = 90,
} ;
+ // tolua_end
+
+ CLASS_PROTODEF(cProjectileEntity);
+
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height);
- /// Called by the physics blocktracer when the entity hits a solid block, the coords and the face hit is given
- virtual void OnHitSolidBlock(double a_BlockX, double a_BlockY, double a_BlockZ, char a_BlockFace) {};
+ 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);
+
+ // tolua_begin
+
+ /// Returns the kind of the projectile (fast class identification)
+ eKind GetProjectileKind(void) const { return m_ProjectileKind; }
+
+ /// Returns the entity who created this projectile; may be NULL
+ cEntity * GetCreator(void) { return m_Creator; }
+
+ /// Returns the string that is used as the entity type (class name) in MCA files
+ AString GetMCAClassName(void) const;
+
+ /// Returns true if the projectile has hit the ground and is stuck there
+ bool IsInGround(void) const { return m_IsInGround; }
protected:
- eKind m_Kind;
+ eKind m_ProjectileKind;
/// The entity who has created this projectile; may be NULL (e. g. for dispensers)
cEntity * m_Creator;
+
+ /// 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;
+
+ // tolua_begin
} ;
@@ -58,9 +89,64 @@ protected:
class cArrowEntity :
public cProjectileEntity
{
+ typedef cProjectileEntity super;
+
public:
- cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
- cArrowEntity(cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height);
+ /// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field
+ enum ePickupState
+ {
+ psNoPickup = 0,
+ psInSurvivalOrCreative = 1,
+ psInCreative = 2,
+ } ;
+
+ // tolua_end
+
+ CLASS_PROTODEF(cArrowEntity);
+
+ /// Creates a new arrow with psNoPickup state and default damage modifier coeff
+ cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d a_Speed);
+
+ /// Creates a new arrow as shot by a player, initializes it from the player object
+ cArrowEntity(cPlayer & a_Player, double a_Force);
+
+ // tolua_begin
+
+ /// Returns the initial arrow position, as defined by the player eye position + adjustment.
+ static Vector3d PosFromPlayerPos(const cPlayer & a_Player);
+
+ /// Returns the initial arrow speed, as defined by the player look vector and the force coefficient
+ static Vector3d SpeedFromPlayerLook(const cPlayer & a_Player, double a_Force);
+
+ /// Returns whether the arrow can be picked up by players
+ ePickupState GetPickupState(void) const { return m_PickupState; }
+
+ /// Sets a new pickup state
+ void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; }
+
+ /// Returns the damage modifier coeff.
+ double GetDamageCoeff(void) const { return m_DamageCoeff; }
+
+ /// Sets the damage modifier coeff
+ void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; }
+
+ /// Returns true if the specified player can pick the arrow up
+ bool CanPickup(const cPlayer & a_Player) const;
+
+ // tolua_end
+
+protected:
+
+ /// Determines when the arrow can be picked up by players
+ ePickupState m_PickupState;
+
+ /// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow
+ double m_DamageCoeff;
+
+ // cEntity overrides:
+ virtual void SpawnOn(cClientHandle & a_Client) override;
+
+ // tolua_begin
} ;
// tolua_end
diff --git a/source/Entities/TNTEntity.cpp b/source/Entities/TNTEntity.cpp
index 43a0dea09..ad3d9ae0c 100644
--- a/source/Entities/TNTEntity.cpp
+++ b/source/Entities/TNTEntity.cpp
@@ -29,20 +29,6 @@ cTNTEntity::cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec) :
-bool cTNTEntity::Initialize(cWorld * a_World)
-{
- if (super::Initialize(a_World))
- {
- a_World->BroadcastSpawnEntity(*this);
- return true;
- }
- return false;
-}
-
-
-
-
-
void cTNTEntity::SpawnOn(cClientHandle & a_ClientHandle)
{
a_ClientHandle.SendSpawnObject(*this, 50, 1, 0, 0); // 50 means TNT
diff --git a/source/Entities/TNTEntity.h b/source/Entities/TNTEntity.h
index ae6fc75e2..eb5040e8a 100644
--- a/source/Entities/TNTEntity.h
+++ b/source/Entities/TNTEntity.h
@@ -19,7 +19,6 @@ public:
cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec);
// cEntity overrides:
- virtual bool Initialize(cWorld * a_World) override;
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;