summaryrefslogtreecommitdiffstats
path: root/source/Entities
diff options
context:
space:
mode:
Diffstat (limited to 'source/Entities')
-rw-r--r--source/Entities/Boat.cpp87
-rw-r--r--source/Entities/Boat.h37
-rw-r--r--source/Entities/Entity.cpp132
-rw-r--r--source/Entities/Entity.h79
-rw-r--r--source/Entities/Minecart.cpp116
-rw-r--r--source/Entities/Minecart.h28
-rw-r--r--source/Entities/Pickup.cpp5
-rw-r--r--source/Entities/Pickup.h2
-rw-r--r--source/Entities/Player.cpp27
9 files changed, 415 insertions, 98 deletions
diff --git a/source/Entities/Boat.cpp b/source/Entities/Boat.cpp
new file mode 100644
index 000000000..56e766dd4
--- /dev/null
+++ b/source/Entities/Boat.cpp
@@ -0,0 +1,87 @@
+
+// Boat.cpp
+
+// Implements the cBoat class representing a boat in the world
+
+#include "Globals.h"
+#include "Boat.h"
+#include "../World.h"
+#include "../ClientHandle.h"
+#include "Player.h"
+
+
+
+
+
+cBoat::cBoat(double a_X, double a_Y, double a_Z) :
+ super(etBoat, a_X, a_Y, a_Z, 0.98, 0.7)
+{
+ SetMass(20.f);
+ SetMaxHealth(6);
+ SetHealth(6);
+}
+
+
+
+
+void cBoat::SpawnOn(cClientHandle & a_ClientHandle)
+{
+ a_ClientHandle.SendSpawnVehicle(*this, 1);
+}
+
+
+
+
+
+void cBoat::DoTakeDamage(TakeDamageInfo & TDI)
+{
+ super::DoTakeDamage(TDI);
+
+ if (GetHealth() == 0)
+ {
+ Destroy(true);
+ }
+}
+
+
+
+
+
+void cBoat::OnRightClicked(cPlayer & a_Player)
+{
+ if (m_Attachee != NULL)
+ {
+ if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID())
+ {
+ // This player is already sitting in, they want out.
+ a_Player.Detach();
+ return;
+ }
+
+ if (m_Attachee->IsPlayer())
+ {
+ // Another player is already sitting in here, cannot attach
+ return;
+ }
+
+ // Detach whatever is sitting in this boat now:
+ m_Attachee->Detach();
+ }
+
+ // Attach the player to this boat
+ a_Player.AttachTo(this);
+}
+
+
+
+
+
+void cBoat::HandlePhysics(float a_Dt, cChunk & a_Chunk)
+{
+ super::HandlePhysics(a_Dt, a_Chunk);
+ BroadcastMovementUpdate();
+}
+
+
+
+
diff --git a/source/Entities/Boat.h b/source/Entities/Boat.h
new file mode 100644
index 000000000..8c51ab86c
--- /dev/null
+++ b/source/Entities/Boat.h
@@ -0,0 +1,37 @@
+
+// Boat.h
+
+// Declares the cBoat class representing a boat in the world
+
+
+
+
+
+#pragma once
+
+#include "Entity.h"
+
+
+
+
+
+class cBoat :
+ public cEntity
+{
+ typedef cEntity super;
+
+public:
+ CLASS_PROTODEF(cBoat);
+
+ // cEntity overrides:
+ virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
+ virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
+ virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
+
+ cBoat(double a_X, double a_Y, double a_Z);
+} ;
+
+
+
+
diff --git a/source/Entities/Entity.cpp b/source/Entities/Entity.cpp
index 1a593b3d1..d465c75bd 100644
--- a/source/Entities/Entity.cpp
+++ b/source/Entities/Entity.cpp
@@ -1,4 +1,3 @@
-
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Entity.h"
@@ -13,6 +12,7 @@
#include "../Simulator/FluidSimulator.h"
#include "../PluginManager.h"
#include "../Tracer.h"
+#include "Minecart.h"
@@ -55,6 +55,7 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d
, m_TicksSinceLastBurnDamage(0)
, m_TicksSinceLastLavaDamage(0)
, m_TicksSinceLastFireDamage(0)
+ , m_TicksSinceLastVoidDamage(0)
, m_TicksLeftBurning(0)
, m_WaterSpeed(0, 0, 0)
, m_Width(a_Width)
@@ -505,6 +506,11 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
TickBurning(a_Chunk);
}
+ if ((a_Chunk.IsValid()) && (GetPosY() < -46))
+ {
+ TickInVoid(a_Chunk);
+ }
+ else { m_TicksSinceLastVoidDamage = 0; }
}
@@ -524,8 +530,15 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
if ((BlockY >= cChunkDef::Height) || (BlockY < 0))
{
// Outside of the world
- // TODO: Current speed should still be added to the entity position
- // Otherwise TNT explosions in the void will still effect the bottommost layers of the world
+
+ cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
+ // See if we can commit our changes. If not, we will discard them.
+ if (NextChunk != NULL)
+ {
+ SetSpeed(NextSpeed);
+ NextPos += (NextSpeed * a_Dt);
+ SetPosition(NextPos);
+ }
return;
}
@@ -536,12 +549,11 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width);
int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width);
BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ );
- BLOCKTYPE BlockBelow = NextChunk->GetBlock( RelBlockX, BlockY - 1, RelBlockZ );
+ BLOCKTYPE BlockBelow = (BlockY > 0) ? NextChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
if (!g_BlockIsSolid[BlockIn]) // Making sure we are not inside a solid block
{
if (m_bOnGround) // check if it's still on the ground
{
- BLOCKTYPE BlockBelow = NextChunk->GetBlock( RelBlockX, BlockY - 1, RelBlockZ );
if (!g_BlockIsSolid[BlockBelow]) // Check if block below is air or water.
{
m_bOnGround = false;
@@ -551,8 +563,43 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
else
{
// Push out entity.
+ BLOCKTYPE GotBlock;
+
+ static const struct
+ {
+ int x, y, z;
+ } gCrossCoords[] =
+ {
+ { 1, 0, 0},
+ {-1, 0, 0},
+ { 0, 0, 1},
+ { 0, 0, -1},
+ } ;
+
+ bool IsNoAirSurrounding = true;
+ for (int i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
+ {
+ if (!NextChunk->UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock))
+ {
+ // The pickup is too close to an unloaded chunk, bail out of any physics handling
+ return;
+ }
+ if (!g_BlockIsSolid[GotBlock])
+ {
+ NextPos.x += gCrossCoords[i].x;
+ NextPos.z += gCrossCoords[i].z;
+ IsNoAirSurrounding = false;
+ break;
+ }
+ } // for i - gCrossCoords[]
+
+ if (IsNoAirSurrounding)
+ {
+ NextPos.y += 0.5;
+ }
+
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
);
@@ -565,6 +612,11 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water.
}
+ else if (IsBlockRail(BlockBelow) && IsMinecart()) // Rails aren't solid, except for Minecarts
+ {
+ fallspeed = 0;
+ m_bOnGround = true;
+ }
else if (BlockIn == E_BLOCK_COBWEB)
{
NextSpeed.y *= 0.05; // Reduce overall falling speed
@@ -579,24 +631,37 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
}
else
{
- // TODO: This condition belongs to minecarts, without it, they derails too much.
- // But it shouldn't be here for other entities. We need a complete minecart physics overhaul.
- if (
- (BlockBelow != E_BLOCK_RAIL) &&
- (BlockBelow != E_BLOCK_DETECTOR_RAIL) &&
- (BlockBelow != E_BLOCK_POWERED_RAIL) &&
- (BlockBelow != E_BLOCK_ACTIVATOR_RAIL)
- )
+ if (IsMinecart())
{
- // Friction
+ if (!IsBlockRail(BlockBelow))
+ {
+ // Friction if minecart is off track, otherwise, Minecart.cpp handles this
+ 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;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Friction for non-minecarts
if (NextSpeed.SqrLength() > 0.0004f)
{
- NextSpeed.x *= 0.6666;
+ NextSpeed.x *= 0.7f / (1 + a_Dt);
if (fabs(NextSpeed.x) < 0.05)
{
NextSpeed.x = 0;
}
- NextSpeed.z *= 0.6666;
+ NextSpeed.z *= 0.7f / (1 + a_Dt);
if (fabs(NextSpeed.z) < 0.05)
{
NextSpeed.z = 0;
@@ -621,19 +686,19 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
switch(WaterDir)
{
case X_PLUS:
- m_WaterSpeed.x = 1.f;
+ m_WaterSpeed.x = 0.2f;
m_bOnGround = false;
break;
case X_MINUS:
- m_WaterSpeed.x = -1.f;
+ m_WaterSpeed.x = -0.2f;
m_bOnGround = false;
break;
case Z_PLUS:
- m_WaterSpeed.z = 1.f;
+ m_WaterSpeed.z = 0.2f;
m_bOnGround = false;
break;
case Z_MINUS:
- m_WaterSpeed.z = -1.f;
+ m_WaterSpeed.z = -0.2f;
m_bOnGround = false;
break;
@@ -664,7 +729,6 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
if( Ret == 1 )
{
-
if( Tracer.HitNormal.x != 0.f ) NextSpeed.x = 0.f;
if( Tracer.HitNormal.y != 0.f ) NextSpeed.y = 0.f;
if( Tracer.HitNormal.z != 0.f ) NextSpeed.z = 0.f;
@@ -675,11 +739,14 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
}
}
NextPos.Set(Tracer.RealHit.x,Tracer.RealHit.y,Tracer.RealHit.z);
- NextPos.x += Tracer.HitNormal.x * 0.5f;
- NextPos.z += Tracer.HitNormal.z * 0.5f;
+ NextPos.x += Tracer.HitNormal.x * 0.3f;
+ NextPos.y += Tracer.HitNormal.y * 0.05f; // Any larger produces entity vibration-upon-the-spot
+ NextPos.z += Tracer.HitNormal.z * 0.3f;
}
else
+ {
NextPos += (NextSpeed * a_Dt);
+ }
}
else
{
@@ -829,6 +896,23 @@ void cEntity::TickBurning(cChunk & a_Chunk)
+void cEntity::TickInVoid(cChunk & a_Chunk)
+{
+ if (m_TicksSinceLastVoidDamage == 20)
+ {
+ TakeDamage(dtInVoid, NULL, 2, 0);
+ m_TicksSinceLastVoidDamage = 0;
+ }
+ else
+ {
+ m_TicksSinceLastVoidDamage++;
+ }
+}
+
+
+
+
+
/// Called when the entity starts burning
void cEntity::OnStartedBurning(void)
{
diff --git a/source/Entities/Entity.h b/source/Entities/Entity.h
index b063838eb..c6b70a7fc 100644
--- a/source/Entities/Entity.h
+++ b/source/Entities/Entity.h
@@ -61,7 +61,26 @@ struct TakeDamageInfo
// tolua_begin
class cEntity
{
-public:
+public:
+
+ enum eEntityType
+ {
+ etEntity, // For all other types
+ etPlayer,
+ etPickup,
+ etMonster,
+ etFallingBlock,
+ etMinecart,
+ etBoat,
+ etTNT,
+ etProjectile,
+
+ // Common variations
+ etMob = etMonster, // DEPRECATED, use etMonster instead!
+ } ;
+
+ // tolua_end
+
enum
{
ENTITY_STATUS_HURT = 2,
@@ -71,6 +90,13 @@ public:
ENTITY_STATUS_WOLF_SHAKING = 8,
ENTITY_STATUS_EATING_ACCEPTED = 9,
ENTITY_STATUS_SHEEP_EATING = 10,
+ ENTITY_STATUS_GOLEM_ROSING = 11,
+ ENTITY_STATUS_VILLAGER_HEARTS = 12,
+ ENTITY_STATUS_VILLAGER_ANGRY = 13,
+ ENTITY_STATUS_VILLAGER_HAPPY = 14,
+ ENTITY_STATUS_WITCH_MAGICKING = 15,
+ // It seems 16 (zombie conversion) is now done with metadata
+ ENTITY_STATUS_FIREWORK_EXPLODE= 17,
} ;
enum
@@ -84,27 +110,6 @@ public:
BURN_TICKS = 200, ///< How long to keep an entity burning after it has stood in lava / fire
} ;
- enum eEntityType
- {
- etEntity, // For all other types
- etPlayer,
- etPickup,
- etMonster,
- 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,
- eEntityType_Mob = etMob,
- } ;
-
- // tolua_end
-
cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
virtual ~cEntity();
@@ -115,11 +120,14 @@ public:
eEntityType GetEntityType(void) const { return m_EntityType; }
- bool IsPlayer (void) const { return (m_EntityType == etPlayer); }
- bool IsPickup (void) const { return (m_EntityType == etPickup); }
- bool IsMob (void) const { return (m_EntityType == etMob); }
- bool IsMinecart(void) const { return (m_EntityType == etMinecart); }
- bool IsTNT (void) const { return (m_EntityType == etTNT); }
+ bool IsPlayer (void) const { return (m_EntityType == etPlayer); }
+ bool IsPickup (void) const { return (m_EntityType == etPickup); }
+ bool IsMob (void) const { return (m_EntityType == etMonster); }
+ bool IsFallingBlock(void) const { return (m_EntityType == etFallingBlock); }
+ bool IsMinecart (void) const { return (m_EntityType == etMinecart); }
+ bool IsBoat (void) const { return (m_EntityType == etBoat); }
+ bool IsTNT (void) const { return (m_EntityType == etTNT); }
+ bool IsProjectile (void) const { return (m_EntityType == etProjectile); }
/// Returns true if the entity is of the specified class or a subclass (cPawn's IsA("cEntity") returns true)
virtual bool IsA(const char * a_ClassName) const;
@@ -232,16 +240,16 @@ public:
/// Returns the curently equipped weapon; empty item if none
virtual cItem GetEquippedWeapon(void) const { return cItem(); }
- /// Returns the currently equipped helmet; empty item if nonte
+ /// Returns the currently equipped helmet; empty item if none
virtual cItem GetEquippedHelmet(void) const { return cItem(); }
- /// Returns the currently equipped chestplate; empty item if nonte
+ /// Returns the currently equipped chestplate; empty item if none
virtual cItem GetEquippedChestplate(void) const { return cItem(); }
- /// Returns the currently equipped leggings; empty item if nonte
+ /// Returns the currently equipped leggings; empty item if none
virtual cItem GetEquippedLeggings(void) const { return cItem(); }
- /// Returns the currently equipped boots; empty item if nonte
+ /// Returns the currently equipped boots; empty item if none
virtual cItem GetEquippedBoots(void) const { return cItem(); }
/// Called when the health drops below zero. a_Killer may be NULL (environmental damage)
@@ -265,6 +273,9 @@ public:
/// Updates the state related to this entity being on fire
virtual void TickBurning(cChunk & a_Chunk);
+
+ /// Handles when the entity is in the void
+ virtual void TickInVoid(cChunk & a_Chunk);
/// Called when the entity starts burning
virtual void OnStartedBurning(void);
@@ -322,12 +333,13 @@ public:
// tolua_begin
- // Metadata flags; descendants may override the defaults:
+ // COMMON metadata flags; descendants may override the defaults:
virtual bool IsOnFire (void) const {return (m_TicksLeftBurning > 0); }
virtual bool IsCrouched (void) const {return false; }
virtual bool IsRiding (void) const {return false; }
virtual bool IsSprinting(void) const {return false; }
virtual bool IsRclking (void) const {return false; }
+ virtual bool IsInvisible(void) const {return false; }
// tolua_end
@@ -387,6 +399,9 @@ protected:
/// Time, in ticks, until the entity extinguishes its fire
int m_TicksLeftBurning;
+
+ /// Time, in ticks, since the last damage dealt by the void. Reset to zero when moving out of the void.
+ int m_TicksSinceLastVoidDamage;
virtual void Destroyed(void) {} // Called after the entity has been destroyed
diff --git a/source/Entities/Minecart.cpp b/source/Entities/Minecart.cpp
index 0c0b7b58a..f75e23d8b 100644
--- a/source/Entities/Minecart.cpp
+++ b/source/Entities/Minecart.cpp
@@ -8,6 +8,7 @@
#include "Minecart.h"
#include "../World.h"
#include "../ClientHandle.h"
+#include "../Chunk.h"
#include "Player.h"
@@ -16,7 +17,8 @@
cMinecart::cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z) :
super(etMinecart, a_X, a_Y, a_Z, 0.98, 0.7),
- m_Payload(a_Payload)
+ m_Payload(a_Payload),
+ m_LastDamage(0)
{
SetMass(20.f);
SetMaxHealth(6);
@@ -51,30 +53,43 @@ void cMinecart::SpawnOn(cClientHandle & a_ClientHandle)
void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
- if ((GetPosY() > 0) && (GetPosY() < cChunkDef::Height))
+ int PosY = (int)floor(GetPosY());
+ if ((PosY <= 0) || (PosY >= cChunkDef::Height))
{
- BLOCKTYPE BelowType = GetWorld()->GetBlock(floor(GetPosX()), floor(GetPosY() -1 ), floor(GetPosZ()));
-
- if (
- (BelowType == E_BLOCK_RAIL) ||
- (BelowType == E_BLOCK_POWERED_RAIL) ||
- (BelowType == E_BLOCK_DETECTOR_RAIL) ||
- (BelowType == E_BLOCK_ACTIVATOR_RAIL)
- )
+ // Outside the world, just process normal falling physics
+ super::HandlePhysics(a_Dt, a_Chunk);
+ BroadcastMovementUpdate();
+ return;
+ }
+
+ int RelPosX = (int)floor(GetPosX()) - a_Chunk.GetPosX() * cChunkDef::Width;
+ int RelPosZ = (int)floor(GetPosZ()) - a_Chunk.GetPosZ() * cChunkDef::Width;
+ cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ);
+ if (Chunk == NULL)
+ {
+ // Inside an unloaded chunk, bail out all processing
+ return;
+ }
+ BLOCKTYPE BelowType = Chunk->GetBlock(RelPosX, PosY - 1, RelPosZ);
+ BLOCKTYPE InsideType = Chunk->GetBlock(RelPosX, PosY, RelPosZ);
+
+ if (IsBlockRail(BelowType))
+ {
+ HandleRailPhysics(a_Dt, *Chunk);
+ }
+ else
+ {
+ if (IsBlockRail(InsideType))
{
- HandleRailPhysics(a_Dt, a_Chunk);
+ SetPosY(PosY + 1);
+ HandleRailPhysics(a_Dt, *Chunk);
}
else
{
- super::HandlePhysics(a_Dt, a_Chunk);
+ super::HandlePhysics(a_Dt, *Chunk);
BroadcastMovementUpdate();
}
}
- else
- {
- super::HandlePhysics(a_Dt, a_Chunk);
- BroadcastMovementUpdate();
- }
}
@@ -83,6 +98,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
static const double MAX_SPEED = 8;
static const double MAX_SPEED_NEGATIVE = (0 - MAX_SPEED);
+
void cMinecart::HandleRailPhysics(float a_Dt, cChunk & a_Chunk)
{
@@ -94,7 +110,9 @@ void cMinecart::HandleRailPhysics(float a_Dt, cChunk & a_Chunk)
*/
// Get block meta below the cart
- NIBBLETYPE BelowMeta = GetWorld()->GetBlockMeta(floor(GetPosX()), floor(GetPosY() -1 ), floor(GetPosZ()));
+ int RelPosX = (int)floor(GetPosX()) - a_Chunk.GetPosX() * cChunkDef::Width;
+ int RelPosZ = (int)floor(GetPosZ()) - a_Chunk.GetPosZ() * cChunkDef::Width;
+ NIBBLETYPE BelowMeta = a_Chunk.GetMeta(RelPosX, (int)floor(GetPosY() - 1), RelPosZ);
double SpeedX = GetSpeedX(), SpeedY = GetSpeedY(), SpeedZ = GetSpeedZ(); // Get current speed
switch (BelowMeta)
@@ -105,9 +123,6 @@ void cMinecart::HandleRailPhysics(float a_Dt, cChunk & a_Chunk)
SpeedY = 0; // Don't move vertically as on ground
SpeedX = 0; // Correct diagonal movement from curved rails
- // Set Y as current Y rounded up to bypass friction
- SetPosY(floor(GetPosY()));
-
if (SpeedZ != 0) // Don't do anything if cart is stationary
{
if (SpeedZ > 0)
@@ -130,8 +145,6 @@ void cMinecart::HandleRailPhysics(float a_Dt, cChunk & a_Chunk)
SpeedY = 0;
SpeedZ = 0;
- SetPosY(floor(GetPosY()));
-
if (SpeedX != 0)
{
if (SpeedX > 0)
@@ -345,11 +358,51 @@ void cMinecart::HandleRailPhysics(float a_Dt, cChunk & a_Chunk)
void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
{
+ m_LastDamage = TDI.FinalDamage;
super::DoTakeDamage(TDI);
- if (GetHealth() == 0)
+ m_World->BroadcastEntityMetadata(*this);
+
+ if (GetHealth() <= 0)
{
Destroy(true);
+
+ cItems Drops;
+ switch (m_Payload)
+ {
+ case mpNone:
+ {
+ Drops.push_back(cItem(E_ITEM_MINECART, 1, 0));
+ break;
+ }
+ case mpChest:
+ {
+ Drops.push_back(cItem(E_ITEM_CHEST_MINECART, 1, 0));
+ break;
+ }
+ case mpFurnace:
+ {
+ Drops.push_back(cItem(E_ITEM_FURNACE_MINECART, 1, 0));
+ break;
+ }
+ case mpTNT:
+ {
+ Drops.push_back(cItem(E_ITEM_MINECART_WITH_TNT, 1, 0));
+ break;
+ }
+ case mpHopper:
+ {
+ Drops.push_back(cItem(E_ITEM_MINECART_WITH_HOPPER, 1, 0));
+ break;
+ }
+ default:
+ {
+ ASSERT(!"Unhandled minecart type when spawning pickup!");
+ return;
+ }
+ }
+
+ m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
}
}
@@ -435,7 +488,8 @@ void cMinecartWithChest::OnRightClicked(cPlayer & a_Player)
// cMinecartWithFurnace:
cMinecartWithFurnace::cMinecartWithFurnace(double a_X, double a_Y, double a_Z) :
- super(mpFurnace, a_X, a_Y, a_Z)
+ super(mpFurnace, a_X, a_Y, a_Z),
+ m_IsFueled(false)
{
}
@@ -445,8 +499,16 @@ cMinecartWithFurnace::cMinecartWithFurnace(double a_X, double a_Y, double a_Z) :
void cMinecartWithFurnace::OnRightClicked(cPlayer & a_Player)
{
- // Try to power the furnace with whatever the player is holding
- // TODO
+ if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_COAL)
+ {
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ }
+
+ m_IsFueled = true;
+ m_World->BroadcastEntityMetadata(*this);
+ }
}
diff --git a/source/Entities/Minecart.h b/source/Entities/Minecart.h
index f98b02bb5..b1b48be4e 100644
--- a/source/Entities/Minecart.h
+++ b/source/Entities/Minecart.h
@@ -10,7 +10,20 @@
#pragma once
#include "Entity.h"
-#include "../Item.h"
+
+
+
+
+
+inline bool IsBlockRail(BLOCKTYPE a_BlockType)
+ {
+ return (
+ (a_BlockType == E_BLOCK_RAIL) ||
+ (a_BlockType == E_BLOCK_ACTIVATOR_RAIL) ||
+ (a_BlockType == E_BLOCK_DETECTOR_RAIL) ||
+ (a_BlockType == E_BLOCK_POWERED_RAIL)
+ ) ;
+ }
@@ -37,16 +50,19 @@ public:
// cEntity overrides:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
- void HandleRailPhysics(float a_Dt, cChunk & a_Chunk);
virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
-
+ int LastDamage(void) const { return m_LastDamage; }
+ void HandleRailPhysics(float a_Dt, cChunk & a_Chunk);
ePayload GetPayload(void) const { return m_Payload; }
protected:
ePayload m_Payload;
cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z);
+
+ int m_LastDamage;
+
} ;
@@ -114,6 +130,12 @@ public:
// cEntity overrides:
virtual void OnRightClicked(cPlayer & a_Player) override;
+ bool IsFueled (void) const { return m_IsFueled; }
+
+private:
+
+ bool m_IsFueled;
+
} ;
diff --git a/source/Entities/Pickup.cpp b/source/Entities/Pickup.cpp
index 9b388366a..075f93449 100644
--- a/source/Entities/Pickup.cpp
+++ b/source/Entities/Pickup.cpp
@@ -24,8 +24,8 @@
-cPickup::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 */)
- : cEntity(etPickup, ((double)(a_MicroPosX)) / 32, ((double)(a_MicroPosY)) / 32, ((double)(a_MicroPosZ)) / 32, 0.2, 0.2)
+cPickup::cPickup(double a_X, double a_Y, double a_Z, const cItem & a_Item, float a_SpeedX /* = 0.f */, float a_SpeedY /* = 0.f */, float a_SpeedZ /* = 0.f */)
+ : cEntity(etPickup, a_X, a_Y, a_Z, 0.2, 0.2)
, m_Timer( 0.f )
, m_Item(a_Item)
, m_bCollected( false )
@@ -33,7 +33,6 @@ cPickup::cPickup(int a_MicroPosX, int a_MicroPosY, int a_MicroPosZ, const cItem
m_MaxHealth = 5;
m_Health = 5;
SetSpeed(a_SpeedX, a_SpeedY, a_SpeedZ);
- m_Gravity = -3.0;
}
diff --git a/source/Entities/Pickup.h b/source/Entities/Pickup.h
index af6eaf3bb..488f91fb2 100644
--- a/source/Entities/Pickup.h
+++ b/source/Entities/Pickup.h
@@ -24,7 +24,7 @@ class cPickup :
public:
CLASS_PROTODEF(cPickup);
- 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
+ cPickup(double a_X, double a_Y, double a_Z, const cItem & a_Item, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f); // tolua_export
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 0943f61ff..d93b45614 100644
--- a/source/Entities/Player.cpp
+++ b/source/Entities/Player.cpp
@@ -16,7 +16,6 @@
#include "../Item.h"
#include "../Tracer.h"
#include "../Root.h"
-#include "../OSSupport/MakeDir.h"
#include "../OSSupport/Timer.h"
#include "../MersenneTwister.h"
#include "../Chunk.h"
@@ -220,7 +219,6 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
if (m_IsChargingBow)
{
m_BowCharge += 1;
- LOGD("Player \"%s\" charging bow: %d", m_PlayerName.c_str(), m_BowCharge);
}
if (m_bDirtyPosition)
@@ -611,10 +609,13 @@ void cPlayer::SetSprint(bool a_IsSprinting)
void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
{
- if (m_GameMode == eGameMode_Creative)
+ if (a_TDI.DamageType != dtInVoid)
{
- // No damage / health in creative mode
- return;
+ if (IsGameModeCreative())
+ {
+ // No damage / health in creative mode
+ return;
+ }
}
super::DoTakeDamage(a_TDI);
@@ -1182,7 +1183,7 @@ void cPlayer::TossItem(
double vX = 0, vY = 0, vZ = 0;
EulerToVector(-GetRotation(), GetPitch(), vZ, vX, vY);
vY = -vY * 2 + 1.f;
- m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY() + 1.6f, GetPosZ(), vX * 2, vY * 2, vZ * 2);
+ m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY() + 1.6f, GetPosZ(), vX * 3, vY * 3, vZ * 3);
}
@@ -1338,7 +1339,7 @@ bool cPlayer::LoadFromDisk()
bool cPlayer::SaveToDisk()
{
- cMakeDir::MakeDir("players");
+ cFile::CreateFolder(FILE_IO_PREFIX + AString("players"));
// create the JSON data
Json::Value JSON_PlayerPosition;
@@ -1446,7 +1447,17 @@ void cPlayer::SetSwimState(cChunk & a_Chunk)
// Check if the player is swimming:
// Use Unbounded, because we're being called *after* processing super::Tick(), which could have changed our chunk
- VERIFY(a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockIn));
+ if (!a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockIn))
+ {
+ // This sometimes happens on Linux machines
+ // Ref.: http://forum.mc-server.org/showthread.php?tid=1244
+ LOGD("SetSwimState failure: RelX = %d, RelZ = %d, LastPos = {%.02f, %.02f}, Pos = %.02f, %.02f}",
+ RelX, RelY, m_LastPosX, m_LastPosZ, GetPosX(), GetPosZ()
+ );
+ m_IsSwimming = false;
+ m_IsSubmerged = false;
+ return;
+ }
m_IsSwimming = IsBlockWater(BlockIn);
// Check if the player is submerged: