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.cpp1450
-rw-r--r--source/Entities/Entity.h445
-rw-r--r--source/Entities/FallingBlock.cpp93
-rw-r--r--source/Entities/FallingBlock.h43
-rw-r--r--source/Entities/Minecart.cpp541
-rw-r--r--source/Entities/Minecart.h169
-rw-r--r--source/Entities/Pawn.cpp19
-rw-r--r--source/Entities/Pawn.h28
-rw-r--r--source/Entities/Pickup.cpp166
-rw-r--r--source/Entities/Pickup.h64
-rw-r--r--source/Entities/Player.cpp1715
-rw-r--r--source/Entities/Player.h447
-rw-r--r--source/Entities/ProjectileEntity.cpp743
-rw-r--r--source/Entities/ProjectileEntity.h325
-rw-r--r--source/Entities/TNTEntity.cpp62
-rw-r--r--source/Entities/TNTEntity.h32
18 files changed, 0 insertions, 6466 deletions
diff --git a/source/Entities/Boat.cpp b/source/Entities/Boat.cpp
deleted file mode 100644
index 56e766dd4..000000000
--- a/source/Entities/Boat.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-
-// 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
deleted file mode 100644
index 8c51ab86c..000000000
--- a/source/Entities/Boat.h
+++ /dev/null
@@ -1,37 +0,0 @@
-
-// 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
deleted file mode 100644
index 3bea7bc01..000000000
--- a/source/Entities/Entity.cpp
+++ /dev/null
@@ -1,1450 +0,0 @@
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "Entity.h"
-#include "../World.h"
-#include "../Server.h"
-#include "../Root.h"
-#include "../Vector3d.h"
-#include "../Matrix4f.h"
-#include "../ReferenceManager.h"
-#include "../ClientHandle.h"
-#include "../Chunk.h"
-#include "../Simulator/FluidSimulator.h"
-#include "../PluginManager.h"
-#include "../Tracer.h"
-#include "Minecart.h"
-
-
-
-
-
-int cEntity::m_EntityCount = 0;
-cCriticalSection cEntity::m_CSCount;
-
-
-
-
-
-cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height)
- : m_UniqueID(0)
- , m_Health(1)
- , m_MaxHealth(1)
- , m_AttachedTo(NULL)
- , m_Attachee(NULL)
- , m_Referencers(new cReferenceManager(cReferenceManager::RFMNGR_REFERENCERS))
- , m_References(new cReferenceManager(cReferenceManager::RFMNGR_REFERENCES))
- , m_HeadYaw( 0.0 )
- , m_Rot(0.0, 0.0, 0.0)
- , m_Pos(a_X, a_Y, a_Z)
- , m_Mass (0.001) //Default 1g
- , m_bDirtyHead(true)
- , m_bDirtyOrientation(true)
- , m_bDirtyPosition(true)
- , m_bDirtySpeed(true)
- , m_bOnGround( false )
- , m_Gravity( -9.81f )
- , m_IsInitialized(false)
- , m_LastPosX( 0.0 )
- , m_LastPosY( 0.0 )
- , m_LastPosZ( 0.0 )
- , m_TimeLastTeleportPacket(0)
- , m_TimeLastMoveReltPacket(0)
- , m_TimeLastSpeedPacket(0)
- , m_EntityType(a_EntityType)
- , m_World(NULL)
- , m_TicksSinceLastBurnDamage(0)
- , m_TicksSinceLastLavaDamage(0)
- , m_TicksSinceLastFireDamage(0)
- , m_TicksSinceLastVoidDamage(0)
- , m_TicksLeftBurning(0)
- , m_WaterSpeed(0, 0, 0)
- , m_Width(a_Width)
- , m_Height(a_Height)
-{
- cCSLock Lock(m_CSCount);
- m_EntityCount++;
- m_UniqueID = m_EntityCount;
-}
-
-
-
-
-
-cEntity::~cEntity()
-{
- ASSERT(!m_World->HasEntity(m_UniqueID)); // Before deleting, the entity needs to have been removed from the world
-
- LOGD("Deleting entity %d at pos {%.2f, %.2f, %.2f} ~ [%d, %d]; ptr %p",
- m_UniqueID,
- m_Pos.x, m_Pos.y, m_Pos.z,
- (int)(m_Pos.x / cChunkDef::Width), (int)(m_Pos.z / cChunkDef::Width),
- this
- );
-
- if (m_AttachedTo != NULL)
- {
- Detach();
- }
- if (m_Attachee != NULL)
- {
- m_Attachee->Detach();
- }
-
- if (m_IsInitialized)
- {
- LOGWARNING("ERROR: Entity deallocated without being destroyed");
- ASSERT(!"Entity deallocated without being destroyed or unlinked");
- }
- delete m_Referencers;
- delete m_References;
-}
-
-
-
-
-
-const char * cEntity::GetClass(void) const
-{
- return "cEntity";
-}
-
-
-
-
-
-const char * cEntity::GetClassStatic(void)
-{
- return "cEntity";
-}
-
-
-
-
-
-const char * cEntity::GetParentClass(void) const
-{
- return "";
-}
-
-
-
-
-
-bool cEntity::Initialize(cWorld * a_World)
-{
- if (cPluginManager::Get()->CallHookSpawningEntity(*a_World, *this))
- {
- return false;
- }
-
- LOGD("Initializing entity #%d (%s) at {%.02f, %.02f, %.02f}",
- m_UniqueID, GetClass(), m_Pos.x, m_Pos.y, m_Pos.z
- );
- m_IsInitialized = true;
- m_World = a_World;
- m_World->AddEntity(this);
-
- cPluginManager::Get()->CallHookSpawnedEntity(*a_World, *this);
-
- // Spawn the entity on the clients:
- a_World->BroadcastSpawnEntity(*this);
-
- return true;
-}
-
-
-
-
-
-void cEntity::WrapHeadYaw(void)
-{
- while (m_HeadYaw > 180.f) m_HeadYaw -= 360.f; // Wrap it
- while (m_HeadYaw < -180.f) m_HeadYaw += 360.f;
-}
-
-
-
-
-
-void cEntity::WrapRotation(void)
-{
- while (m_Rot.x > 180.f) m_Rot.x -= 360.f; // Wrap it
- while (m_Rot.x < -180.f) m_Rot.x += 360.f;
- while (m_Rot.y > 180.f) m_Rot.y -= 360.f;
- while (m_Rot.y < -180.f) m_Rot.y += 360.f;
-}
-
-
-
-
-void cEntity::WrapSpeed(void)
-{
- // There shoudn't be a need for flipping the flag on because this function is called
- // after any update, so the flag is already turned on
- if (m_Speed.x > 78.0f) m_Speed.x = 78.0f;
- else if (m_Speed.x < -78.0f) m_Speed.x = -78.0f;
- if (m_Speed.y > 78.0f) m_Speed.y = 78.0f;
- else if (m_Speed.y < -78.0f) m_Speed.y = -78.0f;
- if (m_Speed.z > 78.0f) m_Speed.z = 78.0f;
- else if (m_Speed.z < -78.0f) m_Speed.z = -78.0f;
-}
-
-
-
-
-
-void cEntity::Destroy(bool a_ShouldBroadcast)
-{
- if (!m_IsInitialized)
- {
- return;
- }
-
- if (a_ShouldBroadcast)
- {
- m_World->BroadcastDestroyEntity(*this);
- }
-
- m_IsInitialized = false;
-
- Destroyed();
-}
-
-
-
-
-
-void cEntity::TakeDamage(cEntity & a_Attacker)
-{
- int RawDamage = a_Attacker.GetRawDamageAgainst(*this);
-
- TakeDamage(dtAttack, &a_Attacker, RawDamage, a_Attacker.GetKnockbackAmountAgainst(*this));
-}
-
-
-
-
-
-void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, double a_KnockbackAmount)
-{
- int FinalDamage = a_RawDamage - GetArmorCoverAgainst(a_Attacker, a_DamageType, a_RawDamage);
- cEntity::TakeDamage(a_DamageType, a_Attacker, a_RawDamage, FinalDamage, a_KnockbackAmount);
-}
-
-
-
-
-
-void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, int a_FinalDamage, double a_KnockbackAmount)
-{
- TakeDamageInfo TDI;
- TDI.DamageType = a_DamageType;
- TDI.Attacker = a_Attacker;
- TDI.RawDamage = a_RawDamage;
- TDI.FinalDamage = a_FinalDamage;
- Vector3d Heading;
- Heading.x = sin(GetRotation());
- Heading.y = 0.4; // TODO: adjust the amount of "up" knockback when testing
- Heading.z = cos(GetRotation());
- TDI.Knockback = Heading * a_KnockbackAmount;
- DoTakeDamage(TDI);
-}
-
-
-
-
-
-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))
- {
- return;
- }
-
- if (m_Health <= 0)
- {
- // Can't take damage if already dead
- return;
- }
-
- m_Health -= (short)a_TDI.FinalDamage;
-
- // TODO: Apply damage to armor
-
- if (m_Health < 0)
- {
- m_Health = 0;
- }
-
- m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT);
-
- if (m_Health <= 0)
- {
- KilledBy(a_TDI.Attacker);
- }
-}
-
-
-
-
-
-int cEntity::GetRawDamageAgainst(const cEntity & a_Receiver)
-{
- // Returns the hitpoints that this pawn can deal to a_Receiver using its equipped items
- // Ref: http://www.minecraftwiki.net/wiki/Damage#Dealing_damage as of 2012_12_20
- switch (this->GetEquippedWeapon().m_ItemType)
- {
- case E_ITEM_WOODEN_SWORD: return 4;
- case E_ITEM_GOLD_SWORD: return 4;
- case E_ITEM_STONE_SWORD: return 5;
- case E_ITEM_IRON_SWORD: return 6;
- case E_ITEM_DIAMOND_SWORD: return 7;
-
- case E_ITEM_WOODEN_AXE: return 3;
- case E_ITEM_GOLD_AXE: return 3;
- case E_ITEM_STONE_AXE: return 4;
- case E_ITEM_IRON_AXE: return 5;
- case E_ITEM_DIAMOND_AXE: return 6;
-
- case E_ITEM_WOODEN_PICKAXE: return 2;
- case E_ITEM_GOLD_PICKAXE: return 2;
- case E_ITEM_STONE_PICKAXE: return 3;
- case E_ITEM_IRON_PICKAXE: return 4;
- case E_ITEM_DIAMOND_PICKAXE: return 5;
-
- case E_ITEM_WOODEN_SHOVEL: return 1;
- case E_ITEM_GOLD_SHOVEL: return 1;
- case E_ITEM_STONE_SHOVEL: return 2;
- case E_ITEM_IRON_SHOVEL: return 3;
- case E_ITEM_DIAMOND_SHOVEL: return 4;
- }
- // All other equipped items give a damage of 1:
- return 1;
-}
-
-
-
-
-
-int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage)
-{
- // Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
-
- // Filter out damage types that are not protected by armor:
- // Ref.: http://www.minecraftwiki.net/wiki/Armor#Effects as of 2012_12_20
- switch (a_DamageType)
- {
- case dtOnFire:
- case dtSuffocating:
- case dtDrowning: // TODO: This one could be a special case - in various MC versions (PC vs XBox) it is and isn't armor-protected
- case dtStarving:
- case dtInVoid:
- case dtPoisoning:
- case dtPotionOfHarming:
- case dtFalling:
- case dtLightning:
- {
- return 0;
- }
- }
-
- // Add up all armor points:
- // Ref.: http://www.minecraftwiki.net/wiki/Armor#Defense_points as of 2012_12_20
- int ArmorValue = 0;
- switch (GetEquippedHelmet().m_ItemType)
- {
- case E_ITEM_LEATHER_CAP: ArmorValue += 1; break;
- case E_ITEM_GOLD_HELMET: ArmorValue += 2; break;
- case E_ITEM_CHAIN_HELMET: ArmorValue += 2; break;
- case E_ITEM_IRON_HELMET: ArmorValue += 2; break;
- case E_ITEM_DIAMOND_HELMET: ArmorValue += 3; break;
- }
- switch (GetEquippedChestplate().m_ItemType)
- {
- case E_ITEM_LEATHER_TUNIC: ArmorValue += 3; break;
- case E_ITEM_GOLD_CHESTPLATE: ArmorValue += 5; break;
- case E_ITEM_CHAIN_CHESTPLATE: ArmorValue += 5; break;
- case E_ITEM_IRON_CHESTPLATE: ArmorValue += 6; break;
- case E_ITEM_DIAMOND_CHESTPLATE: ArmorValue += 8; break;
- }
- switch (GetEquippedLeggings().m_ItemType)
- {
- case E_ITEM_LEATHER_PANTS: ArmorValue += 2; break;
- case E_ITEM_GOLD_LEGGINGS: ArmorValue += 3; break;
- case E_ITEM_CHAIN_LEGGINGS: ArmorValue += 4; break;
- case E_ITEM_IRON_LEGGINGS: ArmorValue += 5; break;
- case E_ITEM_DIAMOND_LEGGINGS: ArmorValue += 6; break;
- }
- switch (GetEquippedBoots().m_ItemType)
- {
- case E_ITEM_LEATHER_BOOTS: ArmorValue += 1; break;
- case E_ITEM_GOLD_BOOTS: ArmorValue += 1; break;
- case E_ITEM_CHAIN_BOOTS: ArmorValue += 1; break;
- case E_ITEM_IRON_BOOTS: ArmorValue += 2; break;
- case E_ITEM_DIAMOND_BOOTS: ArmorValue += 3; break;
- }
-
- // TODO: Special armor cases, such as wool, saddles, dog's collar
- // Ref.: http://www.minecraftwiki.net/wiki/Armor#Mob_armor as of 2012_12_20
-
- // Now ArmorValue is in [0, 20] range, which corresponds to [0, 80%] protection. Calculate the hitpoints from that:
- return a_Damage * (ArmorValue * 4) / 100;
-}
-
-
-
-
-
-double cEntity::GetKnockbackAmountAgainst(const cEntity & a_Receiver)
-{
- // Returns the knockback amount that the currently equipped items would cause to a_Receiver on a hit
-
- // TODO: Enchantments
- return 1;
-}
-
-
-
-
-
-void cEntity::KilledBy(cEntity * a_Killer)
-{
- m_Health = 0;
-
- cRoot::Get()->GetPluginManager()->CallHookKilling(*this, a_Killer);
-
- if (m_Health > 0)
- {
- // Plugin wants to 'unkill' the pawn. Abort
- return;
- }
-
- // Drop loot:
- cItems Drops;
- GetDrops(Drops, a_Killer);
- m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
-
- m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_DEAD);
-}
-
-
-
-
-
-void cEntity::Heal(int a_HitPoints)
-{
- m_Health += a_HitPoints;
- if (m_Health > m_MaxHealth)
- {
- m_Health = m_MaxHealth;
- }
-}
-
-
-
-
-
-void cEntity::SetHealth(int a_Health)
-{
- m_Health = std::max(0, std::min(m_MaxHealth, a_Health));
-}
-
-
-
-
-
-void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
-{
- if (m_AttachedTo != NULL)
- {
- if ((m_Pos - m_AttachedTo->GetPosition()).Length() > 0.5)
- {
- SetPosition(m_AttachedTo->GetPosition());
- }
- }
- else
- {
- if (a_Chunk.IsValid())
- {
- HandlePhysics(a_Dt, a_Chunk);
- }
- }
- if (a_Chunk.IsValid())
- {
- TickBurning(a_Chunk);
- }
- if ((a_Chunk.IsValid()) && (GetPosY() < -46))
- {
- TickInVoid(a_Chunk);
- }
- else { m_TicksSinceLastVoidDamage = 0; }
-}
-
-
-
-
-
-void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
-{
- // TODO Add collision detection with entities.
- 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);
- int BlockY = (int) floor(NextPos.y);
- int BlockZ = (int) floor(NextPos.z);
-
- if ((BlockY >= cChunkDef::Height) || (BlockY < 0))
- {
- // Outside 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;
- }
-
- // Make sure we got the correct chunk and a valid one. No one ever knows...
- cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
- if (NextChunk != NULL)
- {
- int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width);
- int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width);
- BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, 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
- {
- if (!g_BlockIsSolid[BlockBelow]) // Check if block below is air or water.
- {
- m_bOnGround = false;
- }
- }
- }
- 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;
-
- LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}",
- m_UniqueID, GetClass(), BlockX, BlockY, BlockZ
- );
- }
-
- if (!m_bOnGround)
- {
- float fallspeed;
- if (IsBlockWater(BlockIn))
- {
- 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
- fallspeed = 0; // No falling.
- }
- else
- {
- // Normal gravity
- fallspeed = m_Gravity * a_Dt;
- }
- NextSpeed.y += fallspeed;
- }
- else
- {
- if (IsMinecart())
- {
- 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.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.
- if (BlockIn == E_BLOCK_COBWEB)
- {
- NextSpeed.x *= 0.25;
- NextSpeed.z *= 0.25;
- }
-
- //Get water direction
- Direction WaterDir = m_World->GetWaterSimulator()->GetFlowingDirection(BlockX, BlockY, BlockZ);
-
- m_WaterSpeed *= 0.9f; //Reduce speed each tick
-
- switch(WaterDir)
- {
- case X_PLUS:
- m_WaterSpeed.x = 0.2f;
- m_bOnGround = false;
- break;
- case X_MINUS:
- m_WaterSpeed.x = -0.2f;
- m_bOnGround = false;
- break;
- case Z_PLUS:
- m_WaterSpeed.z = 0.2f;
- m_bOnGround = false;
- break;
- case Z_MINUS:
- m_WaterSpeed.z = -0.2f;
- m_bOnGround = false;
- break;
-
- default:
- break;
- }
-
- if (fabs(m_WaterSpeed.x) < 0.05)
- {
- m_WaterSpeed.x = 0;
- }
-
- if (fabs(m_WaterSpeed.z) < 0.05)
- {
- m_WaterSpeed.z = 0;
- }
-
- NextSpeed += m_WaterSpeed;
-
- if( NextSpeed.SqrLength() > 0.f )
- {
- cTracer Tracer( GetWorld() );
- int Ret = Tracer.Trace( NextPos, NextSpeed, 2 );
- if( Ret ) // Oh noez! we hit something
- {
- // Set to hit position
- if( (Tracer.RealHit - NextPos).SqrLength() <= ( NextSpeed * a_Dt ).SqrLength() )
- {
- 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;
-
- if( Tracer.HitNormal.y > 0 ) // means on ground
- {
- m_bOnGround = true;
- }
- }
- NextPos.Set(Tracer.RealHit.x,Tracer.RealHit.y,Tracer.RealHit.z);
- 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
- {
- // We didn't hit anything, so move =]
- NextPos += (NextSpeed * a_Dt);
- }
- }
- BlockX = (int) floor(NextPos.x);
- BlockZ = (int) floor(NextPos.z);
- NextChunk = NextChunk->GetNeighborChunk(BlockX,BlockZ);
- // See if we can commit our changes. If not, we will discard them.
- if (NextChunk != NULL)
- {
- if (NextPos.x != GetPosX()) SetPosX(NextPos.x);
- if (NextPos.y != GetPosY()) SetPosY(NextPos.y);
- if (NextPos.z != GetPosZ()) SetPosZ(NextPos.z);
- if (NextSpeed.x != GetSpeedX()) SetSpeedX(NextSpeed.x);
- if (NextSpeed.y != GetSpeedY()) SetSpeedY(NextSpeed.y);
- if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z);
- }
- }
-}
-
-
-
-
-
-void cEntity::TickBurning(cChunk & a_Chunk)
-{
- // Remember the current burning state:
- bool HasBeenBurning = (m_TicksLeftBurning > 0);
-
- // Do the burning damage:
- if (m_TicksLeftBurning > 0)
- {
- m_TicksSinceLastBurnDamage++;
- if (m_TicksSinceLastBurnDamage >= BURN_TICKS_PER_DAMAGE)
- {
- TakeDamage(dtOnFire, NULL, BURN_DAMAGE, 0);
- m_TicksSinceLastBurnDamage = 0;
- }
- m_TicksLeftBurning--;
- }
-
- // Update the burning times, based on surroundings:
- int MinRelX = (int)floor(GetPosX() - m_Width / 2) - a_Chunk.GetPosX() * cChunkDef::Width;
- int MaxRelX = (int)floor(GetPosX() + m_Width / 2) - a_Chunk.GetPosX() * cChunkDef::Width;
- int MinRelZ = (int)floor(GetPosZ() - m_Width / 2) - a_Chunk.GetPosZ() * cChunkDef::Width;
- int MaxRelZ = (int)floor(GetPosZ() + m_Width / 2) - a_Chunk.GetPosZ() * cChunkDef::Width;
- int MinY = std::max(0, std::min(cChunkDef::Height - 1, (int)floor(GetPosY())));
- int MaxY = std::max(0, std::min(cChunkDef::Height - 1, (int)ceil (GetPosY() + m_Height)));
- bool HasWater = false;
- bool HasLava = false;
- bool HasFire = false;
-
- for (int x = MinRelX; x <= MaxRelX; x++)
- {
- for (int z = MinRelZ; z <= MaxRelZ; z++)
- {
- int RelX = x;
- int RelZ = z;
- cChunk * CurChunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelX, RelZ);
- if (CurChunk == NULL)
- {
- continue;
- }
- for (int y = MinY; y <= MaxY; y++)
- {
- switch (CurChunk->GetBlock(RelX, y, RelZ))
- {
- case E_BLOCK_FIRE:
- {
- HasFire = true;
- break;
- }
- case E_BLOCK_LAVA:
- case E_BLOCK_STATIONARY_LAVA:
- {
- HasLava = true;
- break;
- }
- case E_BLOCK_STATIONARY_WATER:
- case E_BLOCK_WATER:
- {
- HasWater = true;
- break;
- }
- } // switch (BlockType)
- } // for y
- } // for z
- } // for x
-
- if (HasWater)
- {
- // Extinguish the fire
- m_TicksLeftBurning = 0;
- }
-
- if (HasLava)
- {
- // Burn:
- m_TicksLeftBurning = BURN_TICKS;
-
- // Periodically damage:
- m_TicksSinceLastLavaDamage++;
- if (m_TicksSinceLastLavaDamage >= LAVA_TICKS_PER_DAMAGE)
- {
- TakeDamage(dtLavaContact, NULL, LAVA_DAMAGE, 0);
- m_TicksSinceLastLavaDamage = 0;
- }
- }
- else
- {
- m_TicksSinceLastLavaDamage = 0;
- }
-
- if (HasFire)
- {
- // Burn:
- m_TicksLeftBurning = BURN_TICKS;
-
- // Periodically damage:
- m_TicksSinceLastFireDamage++;
- if (m_TicksSinceLastFireDamage >= FIRE_TICKS_PER_DAMAGE)
- {
- TakeDamage(dtFireContact, NULL, FIRE_DAMAGE, 0);
- m_TicksSinceLastFireDamage = 0;
- }
- }
- else
- {
- m_TicksSinceLastFireDamage = 0;
- }
-
- // If just started / finished burning, notify descendants:
- if ((m_TicksLeftBurning > 0) && !HasBeenBurning)
- {
- OnStartedBurning();
- }
- else if ((m_TicksLeftBurning <= 0) && HasBeenBurning)
- {
- OnFinishedBurning();
- }
-}
-
-
-
-
-
-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)
-{
- // Broadcast the change:
- m_World->BroadcastEntityMetadata(*this);
-}
-
-
-
-
-
-/// Called when the entity finishes burning
-void cEntity::OnFinishedBurning(void)
-{
- // Broadcast the change:
- m_World->BroadcastEntityMetadata(*this);
-}
-
-
-
-
-
-/// Sets the maximum value for the health
-void cEntity::SetMaxHealth(int a_MaxHealth)
-{
- m_MaxHealth = a_MaxHealth;
-
- // Reset health, if too high:
- if (m_Health > a_MaxHealth)
- {
- m_Health = a_MaxHealth;
- }
-}
-
-
-
-
-
-/// Puts the entity on fire for the specified amount of ticks
-void cEntity::StartBurning(int a_TicksLeftBurning)
-{
- if (m_TicksLeftBurning > 0)
- {
- // Already burning, top up the ticks left burning and bail out:
- m_TicksLeftBurning = std::max(m_TicksLeftBurning, a_TicksLeftBurning);
- return;
- }
-
- m_TicksLeftBurning = a_TicksLeftBurning;
- OnStartedBurning();
-}
-
-
-
-
-
-/// Stops the entity from burning, resets all burning timers
-void cEntity::StopBurning(void)
-{
- bool HasBeenBurning = (m_TicksLeftBurning > 0);
- m_TicksLeftBurning = 0;
- m_TicksSinceLastBurnDamage = 0;
- m_TicksSinceLastFireDamage = 0;
- m_TicksSinceLastLavaDamage = 0;
-
- // Notify if the entity has stopped burning
- if (HasBeenBurning)
- {
- OnFinishedBurning();
- }
-}
-
-
-
-
-
-void cEntity::TeleportToEntity(cEntity & a_Entity)
-{
- TeleportToCoords(a_Entity.GetPosX(), a_Entity.GetPosY(), a_Entity.GetPosZ());
-}
-
-
-
-
-
-void cEntity::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
-{
- SetPosition(a_PosX, a_PosY, a_PosZ);
- m_World->BroadcastTeleportEntity(*this);
-}
-
-
-
-
-
-void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
-{
- //We need to keep updating the clients when there is movement or if there was a change in speed and after 2 ticks
- if( (m_Speed.SqrLength() > 0.0004f || m_bDirtySpeed) && (m_World->GetWorldAge() - m_TimeLastSpeedPacket >= 2))
- {
- m_World->BroadcastEntityVelocity(*this,a_Exclude);
- m_bDirtySpeed = false;
- m_TimeLastSpeedPacket = m_World->GetWorldAge();
- }
-
- //Have to process position related packets this every two ticks
- if (m_World->GetWorldAge() % 2 == 0)
- {
- int DiffX = (int) (floor(GetPosX() * 32.0) - floor(m_LastPosX * 32.0));
- int DiffY = (int) (floor(GetPosY() * 32.0) - floor(m_LastPosY * 32.0));
- int DiffZ = (int) (floor(GetPosZ() * 32.0) - floor(m_LastPosZ * 32.0));
- Int64 DiffTeleportPacket = m_World->GetWorldAge() - m_TimeLastTeleportPacket;
- // 4 blocks is max Relative So if the Diff is greater than 127 or. Send an absolute position every 20 seconds
- if (DiffTeleportPacket >= 400 ||
- ((DiffX > 127) || (DiffX < -128) ||
- (DiffY > 127) || (DiffY < -128) ||
- (DiffZ > 127) || (DiffZ < -128)))
- {
- //
- m_World->BroadcastTeleportEntity(*this,a_Exclude);
- m_TimeLastTeleportPacket = m_World->GetWorldAge();
- m_TimeLastMoveReltPacket = m_TimeLastTeleportPacket; //Must synchronize.
- m_LastPosX = GetPosX();
- m_LastPosY = GetPosY();
- m_LastPosZ = GetPosZ();
- m_bDirtyPosition = false;
- m_bDirtyOrientation = false;
- }
- else
- {
- Int64 DiffMoveRelPacket = m_World->GetWorldAge() - m_TimeLastMoveReltPacket;
- //if the change is big enough.
- if ((abs(DiffX) >= 4 || abs(DiffY) >= 4 || abs(DiffZ) >= 4 || DiffMoveRelPacket >= 60) && m_bDirtyPosition)
- {
- if (m_bDirtyOrientation)
- {
- m_World->BroadcastEntityRelMoveLook(*this, (char)DiffX, (char)DiffY, (char)DiffZ,a_Exclude);
- m_bDirtyOrientation = false;
- }
- else
- {
- m_World->BroadcastEntityRelMove(*this, (char)DiffX, (char)DiffY, (char)DiffZ,a_Exclude);
- }
- m_LastPosX = GetPosX();
- m_LastPosY = GetPosY();
- m_LastPosZ = GetPosZ();
- m_bDirtyPosition = false;
- m_TimeLastMoveReltPacket = m_World->GetWorldAge();
- }
- else
- {
- if (m_bDirtyOrientation)
- {
- m_World->BroadcastEntityLook(*this,a_Exclude);
- m_bDirtyOrientation = false;
- }
- }
- }
- if (m_bDirtyHead)
- {
- m_World->BroadcastEntityHeadLook(*this,a_Exclude);
- m_bDirtyHead = false;
- }
- }
-}
-
-
-
-
-
-void cEntity::AttachTo(cEntity * a_AttachTo)
-{
- if (m_AttachedTo == a_AttachTo)
- {
- // Already attached to that entity, nothing to do here
- return;
- }
-
- // Detach from any previous entity:
- Detach();
-
- // Attach to the new entity:
- m_AttachedTo = a_AttachTo;
- a_AttachTo->m_Attachee = this;
- m_World->BroadcastAttachEntity(*this, a_AttachTo);
-}
-
-
-
-
-
-void cEntity::Detach(void)
-{
- if (m_AttachedTo == NULL)
- {
- // Attached to no entity, our work is done
- return;
- }
- m_AttachedTo->m_Attachee = NULL;
- m_AttachedTo = NULL;
- m_World->BroadcastAttachEntity(*this, NULL);
-}
-
-
-
-
-
-bool cEntity::IsA(const char * a_ClassName) const
-{
- return (strcmp(a_ClassName, "cEntity") == 0);
-}
-
-
-
-
-
-void cEntity::SetRot(const Vector3f & a_Rot)
-{
- m_Rot = a_Rot;
- m_bDirtyOrientation = true;
-}
-
-
-
-
-
-void cEntity::SetHeadYaw(double a_HeadYaw)
-{
- m_HeadYaw = a_HeadYaw;
- m_bDirtyHead = true;
- WrapHeadYaw();
-}
-
-
-
-
-
-void cEntity::SetHeight(double a_Height)
-{
- m_Height = a_Height;
-}
-
-
-
-
-
-void cEntity::SetMass(double a_Mass)
-{
- if (a_Mass > 0)
- {
- m_Mass = 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.
- m_Mass = 0.001;
- }
-}
-
-
-
-
-
-void cEntity::SetYaw(double a_Yaw)
-{
- m_Rot.x = a_Yaw;
- m_bDirtyOrientation = true;
- WrapRotation();
-}
-
-
-
-
-
-void cEntity::SetPitch(double a_Pitch)
-{
- m_Rot.y = a_Pitch;
- m_bDirtyOrientation = true;
- WrapRotation();
-}
-
-
-
-
-
-void cEntity::SetRoll(double a_Roll)
-{
- m_Rot.z = a_Roll;
- m_bDirtyOrientation = true;
-}
-
-
-
-
-
-void cEntity::SetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ)
-{
- m_Speed.Set(a_SpeedX, a_SpeedY, a_SpeedZ);
- m_bDirtySpeed = true;
- WrapSpeed();
-}
-
-
-
-
-void cEntity::SetSpeedX(double a_SpeedX)
-{
- m_Speed.x = a_SpeedX;
- m_bDirtySpeed = true;
- WrapSpeed();
-}
-
-
-
-
-void cEntity::SetSpeedY(double a_SpeedY)
-{
- m_Speed.y = a_SpeedY;
- m_bDirtySpeed = true;
- WrapSpeed();
-}
-
-
-
-
-void cEntity::SetSpeedZ(double a_SpeedZ)
-{
- m_Speed.z = a_SpeedZ;
- m_bDirtySpeed = true;
- WrapSpeed();
-}
-
-
-
-
-
-void cEntity::SetWidth(double a_Width)
-{
- m_Width = a_Width;
-}
-
-
-
-
-
-void cEntity::AddPosX(double a_AddPosX)
-{
- m_Pos.x += a_AddPosX;
- m_bDirtyPosition = true;
-}
-
-
-
-
-void cEntity::AddPosY(double a_AddPosY)
-{
- m_Pos.y += a_AddPosY;
- m_bDirtyPosition = true;
-}
-
-
-
-
-void cEntity::AddPosZ(double a_AddPosZ)
-{
- m_Pos.z += a_AddPosZ;
- m_bDirtyPosition = true;
-}
-
-
-
-
-void cEntity::AddPosition(double a_AddPosX, double a_AddPosY, double a_AddPosZ)
-{
- m_Pos.x += a_AddPosX;
- m_Pos.y += a_AddPosY;
- m_Pos.z += a_AddPosZ;
- m_bDirtyPosition = true;
-}
-
-
-
-
-void cEntity::AddSpeed(double a_AddSpeedX, double a_AddSpeedY, double a_AddSpeedZ)
-{
- m_Speed.x += a_AddSpeedX;
- m_Speed.y += a_AddSpeedY;
- m_Speed.z += a_AddSpeedZ;
- m_bDirtySpeed = true;
- WrapSpeed();
-}
-
-
-
-
-
-void cEntity::AddSpeedX(double a_AddSpeedX)
-{
- m_Speed.x += a_AddSpeedX;
- m_bDirtySpeed = true;
- WrapSpeed();
-}
-
-
-
-
-
-void cEntity::AddSpeedY(double a_AddSpeedY)
-{
- m_Speed.y += a_AddSpeedY;
- m_bDirtySpeed = true;
- WrapSpeed();
-}
-
-
-
-
-
-void cEntity::AddSpeedZ(double a_AddSpeedZ)
-{
- m_Speed.z += a_AddSpeedZ;
- m_bDirtySpeed = true;
- WrapSpeed();
-}
-
-
-
-
-
-void cEntity::SteerVehicle(float a_Forward, float a_Sideways)
-{
- if (m_AttachedTo == NULL)
- {
- return;
- }
- if ((a_Forward != 0) || (a_Sideways != 0))
- {
- Vector3d LookVector = GetLookVector();
- double AddSpeedX = LookVector.x * a_Forward + LookVector.z * a_Sideways;
- double AddSpeedZ = LookVector.z * a_Forward - LookVector.x * a_Sideways;
- m_AttachedTo->AddSpeed(AddSpeedX, 0, AddSpeedZ);
- }
-}
-
-
-
-
-
-//////////////////////////////////////////////////////////////////////////
-// Get look vector (this is NOT a rotation!)
-Vector3d cEntity::GetLookVector(void) const
-{
- Matrix4d m;
- m.Init(Vector3f(), 0, m_Rot.x, -m_Rot.y);
- Vector3d Look = m.Transform(Vector3d(0, 0, 1));
- return Look;
-}
-
-
-
-
-
-//////////////////////////////////////////////////////////////////////////
-// Set position
-void cEntity::SetPosition(double a_PosX, double a_PosY, double a_PosZ)
-{
- m_Pos.Set(a_PosX, a_PosY, a_PosZ);
- m_bDirtyPosition = true;
-}
-
-
-
-
-
-void cEntity::SetPosX(double a_PosX)
-{
- m_Pos.x = a_PosX;
- m_bDirtyPosition = true;
-}
-
-
-
-
-
-void cEntity::SetPosY(double a_PosY)
-{
- m_Pos.y = a_PosY;
- m_bDirtyPosition = true;
-}
-
-
-
-
-
-void cEntity::SetPosZ(double a_PosZ)
-{
- m_Pos.z = a_PosZ;
- m_bDirtyPosition = true;
-}
-
-
-
-
-
-//////////////////////////////////////////////////////////////////////////
-// Reference stuffs
-void cEntity::AddReference(cEntity * & a_EntityPtr)
-{
- m_References->AddReference(a_EntityPtr);
- a_EntityPtr->ReferencedBy(a_EntityPtr);
-}
-
-
-
-
-
-void cEntity::ReferencedBy(cEntity * & a_EntityPtr)
-{
- m_Referencers->AddReference(a_EntityPtr);
-}
-
-
-
-
-
-void cEntity::Dereference(cEntity * & a_EntityPtr)
-{
- m_Referencers->Dereference(a_EntityPtr);
-}
-
-
-
-
diff --git a/source/Entities/Entity.h b/source/Entities/Entity.h
deleted file mode 100644
index dafda7826..000000000
--- a/source/Entities/Entity.h
+++ /dev/null
@@ -1,445 +0,0 @@
-
-#pragma once
-
-#include "../Item.h"
-#include "../Vector3d.h"
-#include "../Vector3f.h"
-
-
-
-
-
-// Place this macro in the public section of each cEntity descendant class and you're done :)
-#define CLASS_PROTODEF(classname) \
- virtual bool IsA(const char * a_ClassName) const override\
- { \
- return ((strcmp(a_ClassName, #classname) == 0) || super::IsA(a_ClassName)); \
- } \
- virtual const char * GetClass(void) const override \
- { \
- return #classname; \
- } \
- static const char * GetClassStatic(void) \
- { \
- return #classname; \
- } \
- virtual const char * GetParentClass(void) const override \
- { \
- return super::GetClass(); \
- }
-
-
-
-
-
-class cWorld;
-class cReferenceManager;
-class cClientHandle;
-class cPlayer;
-class cChunk;
-
-
-
-
-
-// tolua_begin
-struct TakeDamageInfo
-{
- eDamageType DamageType; // Where does the damage come from? Being hit / on fire / contact with cactus / ...
- cEntity * Attacker; // The attacking entity; valid only for dtAttack
- int RawDamage; // What damage would the receiver get without any armor. Usually: attacker mob type + weapons
- int FinalDamage; // What actual damage will be received. Usually: m_RawDamage minus armor
- Vector3d Knockback; // The amount and direction of knockback received from the damage
- // TODO: Effects - list of effects that the hit is causing. Unknown representation yet
-} ;
-// tolua_end
-
-
-
-
-
-// tolua_begin
-class cEntity
-{
-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,
- ENTITY_STATUS_DEAD = 3,
- ENTITY_STATUS_WOLF_TAMING = 6,
- ENTITY_STATUS_WOLF_TAMED = 7,
- 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
- {
- FIRE_TICKS_PER_DAMAGE = 10, ///< How many ticks to wait between damaging an entity when it stands in fire
- FIRE_DAMAGE = 1, ///< How much damage to deal when standing in fire
- LAVA_TICKS_PER_DAMAGE = 10, ///< How many ticks to wait between damaging an entity when it stands in lava
- LAVA_DAMAGE = 5, ///< How much damage to deal when standing in lava
- BURN_TICKS_PER_DAMAGE = 20, ///< How many ticks to wait between damaging an entity when it is burning
- BURN_DAMAGE = 1, ///< How much damage to deal when the entity is burning
- BURN_TICKS = 200, ///< How long to keep an entity burning after it has stood in lava / fire
- } ;
-
- cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
- virtual ~cEntity();
-
- /// Spawns the entity in the world; returns true if spawned, false if not (plugin disallowed)
- virtual bool Initialize(cWorld * a_World);
-
- // tolua_begin
-
- 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 == 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;
-
- /// Returns the topmost class name for the object
- virtual const char * GetClass(void) const;
-
- // Returns the class name of this class
- static const char * GetClassStatic(void);
-
- /// Returns the topmost class's parent class name for the object. cEntity returns an empty string (no parent).
- virtual const char * GetParentClass(void) const;
-
- cWorld * GetWorld(void) const { return m_World; }
-
- double GetHeadYaw (void) const { return m_HeadYaw; }
- double GetHeight (void) const { return m_Height; }
- double GetMass (void) const { return m_Mass; }
- const Vector3d & GetPosition (void) const { return m_Pos; }
- double GetPosX (void) const { return m_Pos.x; }
- double GetPosY (void) const { return m_Pos.y; }
- double GetPosZ (void) const { return m_Pos.z; }
- const Vector3d & GetRot (void) const { return m_Rot; }
- double GetRotation (void) const { return m_Rot.x; } // OBSOLETE, use GetYaw() instead
- double GetYaw (void) const { return m_Rot.x; }
- double GetPitch (void) const { return m_Rot.y; }
- double GetRoll (void) const { return m_Rot.z; }
- Vector3d GetLookVector(void) const;
- const Vector3d & GetSpeed (void) const { return m_Speed; }
- double GetSpeedX (void) const { return m_Speed.x; }
- double GetSpeedY (void) const { return m_Speed.y; }
- double GetSpeedZ (void) const { return m_Speed.z; }
- double GetWidth (void) const { return m_Width; }
-
- int GetChunkX(void) const {return (int)floor(m_Pos.x / cChunkDef::Width); }
- int GetChunkZ(void) const {return (int)floor(m_Pos.z / cChunkDef::Width); }
-
- void SetHeadYaw (double a_HeadYaw);
- void SetHeight (double a_Height);
- void SetMass (double a_Mass);
- void SetPosX (double a_PosX);
- 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 SetRot (const Vector3f & a_Rot);
- void SetRotation(double a_Rotation) { SetYaw(a_Rotation); } // OBSOLETE, use SetYaw() instead
- void SetYaw (double a_Yaw);
- void SetPitch (double a_Pitch);
- void SetRoll (double a_Roll);
- void SetSpeed (double a_SpeedX, double a_SpeedY, double a_SpeedZ);
- void SetSpeed (const Vector3d & a_Speed) { SetSpeed(a_Speed.x, a_Speed.y, a_Speed.z); }
- void SetSpeedX (double a_SpeedX);
- void SetSpeedY (double a_SpeedY);
- void SetSpeedZ (double a_SpeedZ);
- void SetWidth (double a_Width);
-
- void AddPosX (double a_AddPosX);
- void AddPosY (double a_AddPosY);
- void AddPosZ (double a_AddPosZ);
- void AddPosition(double a_AddPosX, double a_AddPosY, double a_AddPosZ);
- void AddPosition(const Vector3d & a_AddPos) { AddPosition(a_AddPos.x,a_AddPos.y,a_AddPos.z);}
- void AddSpeed (double a_AddSpeedX, double a_AddSpeedY, double a_AddSpeedZ);
- void AddSpeed (const Vector3d & a_AddSpeed) { AddSpeed(a_AddSpeed.x,a_AddSpeed.y,a_AddSpeed.z);}
- void AddSpeedX (double a_AddSpeedX);
- void AddSpeedY (double a_AddSpeedY);
- void AddSpeedZ (double a_AddSpeedZ);
-
- void SteerVehicle(float a_Forward, float a_Sideways);
-
- inline int GetUniqueID(void) const { return m_UniqueID; }
- inline bool IsDestroyed(void) const { return !m_IsInitialized; }
-
- /// Schedules the entity for destroying; if a_ShouldBroadcast is set to true, broadcasts the DestroyEntity packet
- void Destroy(bool a_ShouldBroadcast = true);
-
- /// Makes this pawn take damage from an attack by a_Attacker. Damage values are calculated automatically and DoTakeDamage() called
- void TakeDamage(cEntity & a_Attacker);
-
- /// Makes this entity take the specified damage. The final damage is calculated using current armor, then DoTakeDamage() called
- void TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, double a_KnockbackAmount);
-
- /// 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
- virtual void DoTakeDamage(TakeDamageInfo & a_TDI);
-
- // tolua_begin
-
- /// Returns the hitpoints that this pawn can deal to a_Receiver using its equipped items
- virtual int GetRawDamageAgainst(const cEntity & a_Receiver);
-
- /// Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
- virtual int GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_RawDamage);
-
- /// Returns the knockback amount that the currently equipped items would cause to a_Receiver on a hit
- virtual double GetKnockbackAmountAgainst(const cEntity & a_Receiver);
-
- /// Returns the curently equipped weapon; empty item if none
- virtual cItem GetEquippedWeapon(void) const { return cItem(); }
-
- /// Returns the currently equipped helmet; empty item if none
- virtual cItem GetEquippedHelmet(void) const { return cItem(); }
-
- /// Returns the currently equipped chestplate; empty item if none
- virtual cItem GetEquippedChestplate(void) const { return cItem(); }
-
- /// Returns the currently equipped leggings; empty item if none
- virtual cItem GetEquippedLeggings(void) const { return cItem(); }
-
- /// 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)
- virtual void KilledBy(cEntity * a_Killer);
-
- /// Heals the specified amount of HPs
- void Heal(int a_HitPoints);
-
- /// Returns the health of this entity
- int GetHealth(void) const { return m_Health; }
-
- /// Sets the health of this entity; doesn't broadcast any hurt animation
- void SetHealth(int a_Health);
-
- // tolua_end
-
- virtual void Tick(float a_Dt, cChunk & a_Chunk);
-
- /// Handles the physics of the entity - updates position based on speed, updates speed based on environment
- virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk);
-
- /// 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);
-
- /// Called when the entity finishes burning
- virtual void OnFinishedBurning(void);
-
- // tolua_begin
-
- /// Sets the maximum value for the health
- void SetMaxHealth(int a_MaxHealth);
-
- int GetMaxHealth(void) const { return m_MaxHealth; }
-
- /// Puts the entity on fire for the specified amount of ticks
- void StartBurning(int a_TicksLeftBurning);
-
- /// Stops the entity from burning, resets all burning timers
- void StopBurning(void);
-
- // tolua_end
-
- /** Descendants override this function to send a command to the specified client to spawn the entity on the client.
- To spawn on all eligible clients, use cChunkMap::BroadcastSpawnEntity()
- */
- virtual void SpawnOn(cClientHandle & a_Client) = 0;
-
- // tolua_begin
-
- /// Teleports to the entity specified
- virtual void TeleportToEntity(cEntity & a_Entity);
-
- /// Teleports to the coordinates specified
- virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ);
-
- // tolua_end
-
- /// Updates clients of changes in the entity.
- virtual void BroadcastMovementUpdate(const cClientHandle * a_Exclude = NULL);
-
- /// Attaches to the specified entity; detaches from any previous one first
- void AttachTo(cEntity * a_AttachTo);
-
- /// Detaches from the currently attached entity, if any
- void Detach(void);
-
- /// Makes sure head yaw is not over the specified range.
- void WrapHeadYaw();
-
- /// Makes sure rotation is not over the specified range.
- void WrapRotation();
-
- /// Makes speed is not over 20. Max speed is 20 blocks / second
- void WrapSpeed();
-
- // tolua_begin
-
- // 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
-
- /// Called when the specified player right-clicks this entity
- virtual void OnRightClicked(cPlayer & a_Player) {};
-
- /// Returns the list of drops for this pawn when it is killed. May check a_Killer for special handling (sword of looting etc.). Called from KilledBy().
- virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) {}
-
-protected:
- static cCriticalSection m_CSCount;
- static int m_EntityCount;
-
- int m_UniqueID;
-
- int m_Health;
- int m_MaxHealth;
-
- /// The entity to which this entity is attached (vehicle), NULL if none
- cEntity * m_AttachedTo;
-
- /// The entity which is attached to this entity (rider), NULL if none
- cEntity * m_Attachee;
-
- cReferenceManager* m_Referencers;
- cReferenceManager* m_References;
-
- // Flags that signal that we haven't updated the clients with the latest.
- bool m_bDirtyHead;
- bool m_bDirtyOrientation;
- bool m_bDirtyPosition;
- bool m_bDirtySpeed;
-
- bool m_bOnGround;
- float m_Gravity;
-
- // Last Position.
- double m_LastPosX, m_LastPosY, m_LastPosZ;
-
- // This variables keep track of the last time a packet was sent
- Int64 m_TimeLastTeleportPacket,m_TimeLastMoveReltPacket,m_TimeLastSpeedPacket; // In ticks
-
- bool m_IsInitialized; // Is set to true when it's initialized, until it's destroyed (Initialize() till Destroy() )
-
- eEntityType m_EntityType;
-
- cWorld * m_World;
-
- /// Time, in ticks, since the last damage dealt by being on fire. Valid only if on fire (IsOnFire())
- int m_TicksSinceLastBurnDamage;
-
- /// Time, in ticks, since the last damage dealt by standing in lava. Reset to zero when moving out of lava.
- int m_TicksSinceLastLavaDamage;
-
- /// Time, in ticks, since the last damage dealt by standing in fire. Reset to zero when moving out of fire.
- int m_TicksSinceLastFireDamage;
-
- /// 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
-
- void SetWorld(cWorld * a_World) { m_World = a_World; }
-
- friend class cReferenceManager;
- void AddReference( cEntity*& a_EntityPtr );
- void ReferencedBy( cEntity*& a_EntityPtr );
- void Dereference( cEntity*& a_EntityPtr );
-
-private:
- // Measured in degrees (MAX 360°)
- double m_HeadYaw;
- // Measured in meter/second (m/s)
- Vector3d m_Speed;
- // Measured in degrees (MAX 360°)
- Vector3d m_Rot;
-
- /// Position of the entity's XZ center and Y bottom
- Vector3d m_Pos;
-
- // Measured in meter / second
- Vector3d m_WaterSpeed;
-
- // Measured in Kilograms (Kg)
- double m_Mass;
-
- /// Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter.
- double m_Width;
-
- /// Height of the entity (Y axis)
- double m_Height;
-} ; // tolua_export
-
-typedef std::list<cEntity *> cEntityList;
-
-
-
-
diff --git a/source/Entities/FallingBlock.cpp b/source/Entities/FallingBlock.cpp
deleted file mode 100644
index 9fcd9ac80..000000000
--- a/source/Entities/FallingBlock.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-#include "Globals.h"
-
-#include "FallingBlock.h"
-#include "../World.h"
-#include "../ClientHandle.h"
-#include "../Simulator/SandSimulator.h"
-#include "../Chunk.h"
-
-
-
-
-
-cFallingBlock::cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) :
- super(etFallingBlock, a_BlockPosition.x + 0.5f, a_BlockPosition.y + 0.5f, a_BlockPosition.z + 0.5f, 0.98, 0.98),
- m_BlockType(a_BlockType),
- m_BlockMeta(a_BlockMeta),
- m_OriginalPosition(a_BlockPosition)
-{
-}
-
-
-
-
-
-void cFallingBlock::SpawnOn(cClientHandle & a_ClientHandle)
-{
- a_ClientHandle.SendSpawnFallingBlock(*this);
-}
-
-
-
-
-
-void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
-{
- float MilliDt = a_Dt * 0.001f;
- AddSpeedY(MilliDt * -9.8f);
- AddPosY(GetSpeedY() * MilliDt);
-
- // GetWorld()->BroadcastTeleportEntity(*this); // Test position
-
- int BlockX = m_OriginalPosition.x;
- int BlockY = (int)(GetPosY() - 0.5);
- int BlockZ = m_OriginalPosition.z;
-
- if (BlockY < 0)
- {
- // Fallen out of this world, just continue falling until out of sight, then destroy:
- if (BlockY < 100)
- {
- Destroy(true);
- }
- return;
- }
-
- if (BlockY >= cChunkDef::Height)
- {
- // Above the world, just wait for it to fall back down
- return;
- }
-
- int idx = a_Chunk.MakeIndexNoCheck(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width);
- BLOCKTYPE BlockBelow = a_Chunk.GetBlock(idx);
- NIBBLETYPE BelowMeta = a_Chunk.GetMeta(idx);
- if (cSandSimulator::DoesBreakFallingThrough(BlockBelow, BelowMeta))
- {
- // Fallen onto a block that breaks this into pickups (e. g. half-slab)
- // Must finish the fall with coords one below the block:
- cSandSimulator::FinishFalling(m_World, BlockX, BlockY, BlockZ, m_BlockType, m_BlockMeta);
- Destroy(true);
- return;
- }
- else if (!cSandSimulator::CanContinueFallThrough(BlockBelow))
- {
- // Fallen onto a solid block
- /*
- LOGD(
- "Sand: Checked below at {%d, %d, %d} (rel {%d, %d, %d}), it's %s, finishing the fall.",
- BlockX, BlockY, BlockZ,
- BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width,
- ItemTypeToString(BlockBelow).c_str()
- );
- */
-
- cSandSimulator::FinishFalling(m_World, BlockX, BlockY + 1, BlockZ, m_BlockType, m_BlockMeta);
- Destroy(true);
- return;
- }
-}
-
-
-
-
diff --git a/source/Entities/FallingBlock.h b/source/Entities/FallingBlock.h
deleted file mode 100644
index 5ba9909bb..000000000
--- a/source/Entities/FallingBlock.h
+++ /dev/null
@@ -1,43 +0,0 @@
-
-#pragma once
-
-#include "Entity.h"
-
-
-
-
-class cPlayer;
-class cItem;
-
-
-
-
-
-
-class cFallingBlock :
- public cEntity
-{
- typedef cEntity super;
-
-public:
- CLASS_PROTODEF(cFallingBlock);
-
- /// Creates a new falling block. a_BlockPosition is expected in world coords
- cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
-
- BLOCKTYPE GetBlockType(void) const { return m_BlockType; }
- NIBBLETYPE GetBlockMeta(void) const { return m_BlockMeta; }
-
- // cEntity overrides:
- virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
- virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
-
-private:
- BLOCKTYPE m_BlockType;
- NIBBLETYPE m_BlockMeta;
- Vector3i m_OriginalPosition; // Position where the falling block has started, in world coords
-} ;
-
-
-
-
diff --git a/source/Entities/Minecart.cpp b/source/Entities/Minecart.cpp
deleted file mode 100644
index f75e23d8b..000000000
--- a/source/Entities/Minecart.cpp
+++ /dev/null
@@ -1,541 +0,0 @@
-
-// Minecart.cpp
-
-// Implements the cMinecart class representing a minecart in the world
-// Indiana Jones!
-
-#include "Globals.h"
-#include "Minecart.h"
-#include "../World.h"
-#include "../ClientHandle.h"
-#include "../Chunk.h"
-#include "Player.h"
-
-
-
-
-
-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_LastDamage(0)
-{
- SetMass(20.f);
- SetMaxHealth(6);
- SetHealth(6);
-}
-
-
-
-
-void cMinecart::SpawnOn(cClientHandle & a_ClientHandle)
-{
- char SubType = 0;
- switch (m_Payload)
- {
- case mpNone: SubType = 0; break;
- case mpChest: SubType = 1; break;
- case mpFurnace: SubType = 2; break;
- case mpTNT: SubType = 3; break;
- case mpHopper: SubType = 5; break;
- default:
- {
- ASSERT(!"Unknown payload, cannot spawn on client");
- return;
- }
- }
- a_ClientHandle.SendSpawnVehicle(*this, 10, SubType); // 10 = Minecarts, SubType = What type of Minecart
-}
-
-
-
-
-
-void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
-{
- int PosY = (int)floor(GetPosY());
- if ((PosY <= 0) || (PosY >= cChunkDef::Height))
- {
- // 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))
- {
- SetPosY(PosY + 1);
- HandleRailPhysics(a_Dt, *Chunk);
- }
- else
- {
- super::HandlePhysics(a_Dt, *Chunk);
- BroadcastMovementUpdate();
- }
- }
-}
-
-
-
-
-
-static const double MAX_SPEED = 8;
-static const double MAX_SPEED_NEGATIVE = (0 - MAX_SPEED);
-
-void cMinecart::HandleRailPhysics(float a_Dt, cChunk & a_Chunk)
-{
-
- super::HandlePhysics(a_Dt, a_Chunk); // Main physics handling
-
- /*
- NOTE: Please bear in mind that taking away from negatives make them even more negative,
- adding to negatives make them positive, etc.
- */
-
- // Get block meta below the cart
- 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)
- {
- case E_META_RAIL_ZM_ZP: // NORTHSOUTH
- {
- SetRotation(270);
- SpeedY = 0; // Don't move vertically as on ground
- SpeedX = 0; // Correct diagonal movement from curved rails
-
- if (SpeedZ != 0) // Don't do anything if cart is stationary
- {
- if (SpeedZ > 0)
- {
- // Going SOUTH, slow down
- SpeedZ = SpeedZ - 0.1;
- }
- else
- {
- // Going NORTH, slow down
- SpeedZ = SpeedZ + 0.1;
- }
- }
- break;
- }
-
- case E_META_RAIL_XM_XP: // EASTWEST
- {
- SetRotation(180);
- SpeedY = 0;
- SpeedZ = 0;
-
- if (SpeedX != 0)
- {
- if (SpeedX > 0)
- {
- SpeedX = SpeedX - 0.1;
- }
- else
- {
- SpeedX = SpeedX + 0.1;
- }
- }
- break;
- }
-
- case E_META_RAIL_ASCEND_ZM: // ASCEND NORTH
- {
- SetRotation(270);
- SetPosY(floor(GetPosY()) + 0.2); // It seems it doesn't work without levitation :/
- SpeedX = 0;
-
- if (SpeedZ >= 0)
- {
- // SpeedZ POSITIVE, going SOUTH
- if (SpeedZ <= MAX_SPEED) // Speed limit
- {
- SpeedZ = SpeedZ + 0.5; // Speed up
- SpeedY = (0 - SpeedZ); // Downward movement is negative (0 minus positive numbers is negative)
- }
- else
- {
- SpeedZ = MAX_SPEED; // Enforce speed limit
- SpeedY = (0 - SpeedZ);
- }
- }
- else
- {
- // SpeedZ NEGATIVE, going NORTH
- SpeedZ = SpeedZ + 0.4; // Slow down
- SpeedY = (0 - SpeedZ); // Upward movement is positive (0 minus negative number is positive number)
- }
- break;
- }
-
- case E_META_RAIL_ASCEND_ZP: // ASCEND SOUTH
- {
- SetRotation(270);
- SetPosY(floor(GetPosY()) + 0.2);
- SpeedX = 0;
-
- if (SpeedZ > 0)
- {
- // SpeedZ POSITIVE, going SOUTH
- SpeedZ = SpeedZ - 0.4; // Slow down
- SpeedY = SpeedZ; // Upward movement positive
- }
- else
- {
- if (SpeedZ >= MAX_SPEED_NEGATIVE) // Speed limit
- {
- // SpeedZ NEGATIVE, going NORTH
- SpeedZ = SpeedZ - 0.5; // Speed up
- SpeedY = SpeedZ; // Downward movement negative
- }
- else
- {
- SpeedZ = MAX_SPEED_NEGATIVE; // Enforce speed limit
- SpeedY = SpeedZ;
- }
- }
- break;
- }
-
- case E_META_RAIL_ASCEND_XM: // ASCEND EAST
- {
- SetRotation(180);
- SetPosY(floor(GetPosY()) + 0.2);
- SpeedZ = 0;
-
- if (SpeedX >= 0)
- {
- if (SpeedX <= MAX_SPEED)
- {
- SpeedX = SpeedX + 0.5;
- SpeedY = (0 - SpeedX);
- }
- else
- {
- SpeedX = MAX_SPEED;
- SpeedY = (0 - SpeedX);
- }
- }
- else
- {
- SpeedX = SpeedX + 0.4;
- SpeedY = (0 - SpeedX);
- }
- break;
- }
-
- case E_META_RAIL_ASCEND_XP: // ASCEND WEST
- {
- SetRotation(180);
- SetPosY(floor(GetPosY()) + 0.2);
- SpeedZ = 0;
-
- if (SpeedX > 0)
- {
- SpeedX = SpeedX - 0.4;
- SpeedY = SpeedX;
- }
- else
- {
- if (SpeedX >= MAX_SPEED_NEGATIVE)
- {
- SpeedX = SpeedX - 0.5;
- SpeedY = SpeedX;
- }
- else
- {
- SpeedX = MAX_SPEED_NEGATIVE;
- SpeedY = SpeedX;
- }
- }
- break;
- }
-
- case E_META_RAIL_CURVED_ZM_XM: // Ends pointing NORTH and WEST
- {
- SetRotation(315); // Set correct rotation server side
- SetPosY(floor(GetPosY()) + 0.2); // Levitate dat cart
-
- if (SpeedZ > 0) // Cart moving south
- {
- SpeedX = (0 - SpeedZ); // Diagonally move southwest (which will make cart hit a southwest rail)
- }
- else if (SpeedX > 0) // Cart moving east
- {
- SpeedZ = (0 - SpeedX); // Diagonally move northeast
- }
- break;
- }
-
- case E_META_RAIL_CURVED_ZM_XP: // Curved NORTH EAST
- {
- SetRotation(225);
- SetPosY(floor(GetPosY()) + 0.2);
-
- if (SpeedZ > 0)
- {
- SpeedX = SpeedZ;
- }
- else if (SpeedX < 0)
- {
- SpeedZ = SpeedX;
- }
- break;
- }
-
- case E_META_RAIL_CURVED_ZP_XM: // Curved SOUTH WEST
- {
- SetRotation(135);
- SetPosY(floor(GetPosY()) + 0.2);
-
- if (SpeedZ < 0)
- {
- SpeedX = SpeedZ;
- }
- else if (SpeedX > 0)
- {
- SpeedZ = SpeedX;
- }
- break;
- }
-
- case E_META_RAIL_CURVED_ZP_XP: // Curved SOUTH EAST
- {
- SetRotation(45);
- SetPosY(floor(GetPosY()) + 0.2);
-
- if (SpeedZ < 0)
- {
- SpeedX = (0 - SpeedZ);
- }
- else if (SpeedX < 0)
- {
- SpeedZ = (0 - SpeedX);
- }
- break;
- }
-
- default:
- {
- ASSERT(!"Unhandled rail meta!"); // Dun dun DUN!
- break;
- }
- }
-
- // Set speed to speed variables
- SetSpeedX(SpeedX);
- SetSpeedY(SpeedY);
- SetSpeedZ(SpeedZ);
-
-
- // Broadcast position to client
- BroadcastMovementUpdate();
-}
-
-
-
-
-
-void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
-{
- m_LastDamage = TDI.FinalDamage;
- super::DoTakeDamage(TDI);
-
- 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());
- }
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cEmptyMinecart:
-
-cEmptyMinecart::cEmptyMinecart(double a_X, double a_Y, double a_Z) :
- super(mpNone, a_X, a_Y, a_Z)
-{
-}
-
-
-
-
-
-void cEmptyMinecart::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 minecart now:
- m_Attachee->Detach();
- }
-
- // Attach the player to this minecart
- a_Player.AttachTo(this);
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cMinecartWithChest:
-
-cMinecartWithChest::cMinecartWithChest(double a_X, double a_Y, double a_Z) :
- super(mpChest, a_X, a_Y, a_Z)
-{
-}
-
-
-
-
-
-void cMinecartWithChest::SetSlot(int a_Idx, const cItem & a_Item)
-{
- ASSERT((a_Idx >= 0) && (a_Idx < ARRAYCOUNT(m_Items)));
-
- m_Items[a_Idx] = a_Item;
-}
-
-
-
-
-
-void cMinecartWithChest::OnRightClicked(cPlayer & a_Player)
-{
- // Show the chest UI window to the player
- // TODO
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cMinecartWithFurnace:
-
-cMinecartWithFurnace::cMinecartWithFurnace(double a_X, double a_Y, double a_Z) :
- super(mpFurnace, a_X, a_Y, a_Z),
- m_IsFueled(false)
-{
-}
-
-
-
-
-
-void cMinecartWithFurnace::OnRightClicked(cPlayer & a_Player)
-{
- if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_COAL)
- {
- if (!a_Player.IsGameModeCreative())
- {
- a_Player.GetInventory().RemoveOneEquippedItem();
- }
-
- m_IsFueled = true;
- m_World->BroadcastEntityMetadata(*this);
- }
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cMinecartWithTNT:
-
-cMinecartWithTNT::cMinecartWithTNT(double a_X, double a_Y, double a_Z) :
- super(mpTNT, a_X, a_Y, a_Z)
-{
-}
-
-// TODO: Make it activate when passing over activator rail
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cMinecartWithHopper:
-
-cMinecartWithHopper::cMinecartWithHopper(double a_X, double a_Y, double a_Z) :
- super(mpHopper, a_X, a_Y, a_Z)
-{
-}
-
-// TODO: Make it suck up blocks and travel further than any other cart and physics and put and take blocks
-// AND AVARYTHING!! \ No newline at end of file
diff --git a/source/Entities/Minecart.h b/source/Entities/Minecart.h
deleted file mode 100644
index b1b48be4e..000000000
--- a/source/Entities/Minecart.h
+++ /dev/null
@@ -1,169 +0,0 @@
-
-// Minecart.h
-
-// Declares the cMinecart class representing a minecart in the world
-
-
-
-
-
-#pragma once
-
-#include "Entity.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)
- ) ;
- }
-
-
-
-
-
-class cMinecart :
- public cEntity
-{
- typedef cEntity super;
-
-public:
- CLASS_PROTODEF(cMinecart);
-
- enum ePayload
- {
- mpNone, // Empty minecart, ridable by player or mobs
- mpChest, // Minecart-with-chest, can store a grid of 3*8 items
- mpFurnace, // Minecart-with-furnace, can be powered
- mpTNT, // Minecart-with-TNT, can be blown up with activator rail
- mpHopper, // Minecart-with-hopper, can be hopper
- // TODO: Spawner minecarts, (and possibly any block in a minecart with NBT editing)
- } ;
-
- // cEntity overrides:
- virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
- virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
- 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;
-
-} ;
-
-
-
-
-
-class cEmptyMinecart :
- public cMinecart
-{
- typedef cMinecart super;
-
-public:
- CLASS_PROTODEF(cEmptyMinecart);
-
- cEmptyMinecart(double a_X, double a_Y, double a_Z);
-
- // cEntity overrides:
- virtual void OnRightClicked(cPlayer & a_Player) override;
-} ;
-
-
-
-
-
-class cMinecartWithChest :
- public cMinecart
-{
- typedef cMinecart super;
-
-public:
- CLASS_PROTODEF(cMinecartWithChest);
-
- /// Number of item slots in the chest
- static const int NumSlots = 9 * 3;
-
- cMinecartWithChest(double a_X, double a_Y, double a_Z);
-
- const cItem & GetSlot(int a_Idx) const { return m_Items[a_Idx]; }
- cItem & GetSlot(int a_Idx) { return m_Items[a_Idx]; }
-
- void SetSlot(int a_Idx, const cItem & a_Item);
-
-protected:
-
- /// The chest contents:
- cItem m_Items[NumSlots];
-
- // cEntity overrides:
- virtual void OnRightClicked(cPlayer & a_Player) override;
-} ;
-
-
-
-
-
-class cMinecartWithFurnace :
- public cMinecart
-{
- typedef cMinecart super;
-
-public:
- CLASS_PROTODEF(cMinecartWithFurnace);
-
- cMinecartWithFurnace(double a_X, double a_Y, double a_Z);
-
- // cEntity overrides:
- virtual void OnRightClicked(cPlayer & a_Player) override;
- bool IsFueled (void) const { return m_IsFueled; }
-
-private:
-
- bool m_IsFueled;
-
-} ;
-
-
-
-
-
-class cMinecartWithTNT :
- public cMinecart
-{
- typedef cMinecart super;
-
-public:
- CLASS_PROTODEF(cMinecartWithTNT);
-
- cMinecartWithTNT(double a_X, double a_Y, double a_Z);
-} ;
-
-
-
-
-
-class cMinecartWithHopper :
- public cMinecart
-{
- typedef cMinecart super;
-
-public:
- CLASS_PROTODEF(cMinecartWithHopper);
-
- cMinecartWithHopper(double a_X, double a_Y, double a_Z);
-} ; \ No newline at end of file
diff --git a/source/Entities/Pawn.cpp b/source/Entities/Pawn.cpp
deleted file mode 100644
index fffefd538..000000000
--- a/source/Entities/Pawn.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "Pawn.h"
-
-
-
-
-
-cPawn::cPawn(eEntityType a_EntityType, double a_Width, double a_Height)
- : cEntity(a_EntityType, 0, 0, 0, a_Width, a_Height)
- , m_bBurnable(true)
-{
-}
-
-
-
-
-
diff --git a/source/Entities/Pawn.h b/source/Entities/Pawn.h
deleted file mode 100644
index e76337d86..000000000
--- a/source/Entities/Pawn.h
+++ /dev/null
@@ -1,28 +0,0 @@
-
-#pragma once
-
-#include "Entity.h"
-
-
-
-
-
-// tolua_begin
-class cPawn :
- public cEntity
-{
- // tolua_end
- typedef cEntity super;
-
-public:
- CLASS_PROTODEF(cPawn);
-
- cPawn(eEntityType a_EntityType, double a_Width, double a_Height);
-
-protected:
- bool m_bBurnable;
-} ; // tolua_export
-
-
-
-
diff --git a/source/Entities/Pickup.cpp b/source/Entities/Pickup.cpp
deleted file mode 100644
index f8aae9703..000000000
--- a/source/Entities/Pickup.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#ifndef _WIN32
-#include <cstdlib>
-#endif
-
-#include "Pickup.h"
-#include "../ClientHandle.h"
-#include "../Inventory.h"
-#include "../World.h"
-#include "../Simulator/FluidSimulator.h"
-#include "../Server.h"
-#include "Player.h"
-#include "../PluginManager.h"
-#include "../Item.h"
-#include "../Root.h"
-#include "../Chunk.h"
-
-#include "../Vector3d.h"
-#include "../Vector3f.h"
-
-
-
-
-
-cPickup::cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, float a_SpeedX /* = 0.f */, float a_SpeedY /* = 0.f */, float a_SpeedZ /* = 0.f */)
- : cEntity(etPickup, a_PosX, a_PosY, a_PosZ, 0.2, 0.2)
- , m_Timer( 0.f )
- , m_Item(a_Item)
- , m_bCollected( false )
- , m_bIsPlayerCreated( IsPlayerCreated )
-{
- SetGravity(-10.5f);
- SetMaxHealth(5);
- SetHealth(5);
- SetSpeed(a_SpeedX, a_SpeedY, a_SpeedZ);
-}
-
-
-
-
-
-void cPickup::SpawnOn(cClientHandle & a_Client)
-{
- a_Client.SendPickupSpawn(*this);
-}
-
-
-
-
-
-void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
-{
- super::Tick(a_Dt, a_Chunk);
- BroadcastMovementUpdate(); //Notify clients of position
-
- m_Timer += a_Dt;
-
- if (!m_bCollected)
- {
- int BlockY = (int) floor(GetPosY());
- if ((BlockY >= 0) && (BlockY < cChunkDef::Height)) // Don't do anything except for falling when outside the world
- {
- int BlockX = (int) floor(GetPosX());
- int BlockZ = (int) floor(GetPosZ());
- // Position might have changed due to physics. So we have to make sure we have the correct chunk.
- cChunk * CurrentChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
- if (CurrentChunk != NULL) // Make sure the chunk is loaded
- {
- int RelBlockX = BlockX - (CurrentChunk->GetPosX() * cChunkDef::Width);
- int RelBlockZ = BlockZ - (CurrentChunk->GetPosZ() * cChunkDef::Width);
-
- // If the pickup is on the bottommost block position, make it think the void is made of air: (#131)
- BLOCKTYPE BlockBelow = (BlockY > 0) ? CurrentChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
- BLOCKTYPE BlockIn = CurrentChunk->GetBlock(RelBlockX, BlockY, RelBlockZ);
-
- if (
- IsBlockLava(BlockBelow) || (BlockBelow == E_BLOCK_FIRE) ||
- IsBlockLava(BlockIn) || (BlockIn == E_BLOCK_FIRE)
- )
- {
- m_bCollected = true;
- m_Timer = 0; // We have to reset the timer.
- m_Timer += a_Dt; // In case we have to destroy the pickup in the same tick.
- if (m_Timer > 500.f)
- {
- Destroy(true);
- return;
- }
- }
- }
- }
- }
- else
- {
- if (m_Timer > 500.f) // 0.5 second
- {
- Destroy(true);
- return;
- }
- }
-
- if (m_Timer > 1000 * 60 * 5) // 5 minutes
- {
- Destroy(true);
- return;
- }
-
- if (GetPosY() < -8) // Out of this world and no more visible!
- {
- Destroy(true);
- return;
- }
-}
-
-
-
-
-
-bool cPickup::CollectedBy(cPlayer * a_Dest)
-{
- ASSERT(a_Dest != NULL);
-
- if (m_bCollected)
- {
- // LOG("Pickup %d cannot be collected by \"%s\", because it has already been collected.", m_UniqueID, a_Dest->GetName().c_str());
- return false; // It's already collected!
- }
-
- // Two seconds if player created the pickup (vomiting), half a second if anything else
- if (m_Timer < (m_bIsPlayerCreated ? 2000.f : 500.f))
- {
- // LOG("Pickup %d cannot be collected by \"%s\", because it is not old enough.", m_UniqueID, a_Dest->GetName().c_str());
- return false; // Not old enough
- }
-
- if (cRoot::Get()->GetPluginManager()->CallHookCollectingPickup(a_Dest, *this))
- {
- // LOG("Pickup %d cannot be collected by \"%s\", because a plugin has said no.", m_UniqueID, a_Dest->GetName().c_str());
- return false;
- }
-
- int NumAdded = a_Dest->GetInventory().AddItem(m_Item);
- if (NumAdded > 0)
- {
- m_Item.m_ItemCount -= NumAdded;
- m_World->BroadcastCollectPickup(*this, *a_Dest);
- // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
- m_World->BroadcastSoundEffect("random.pop",(int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
- if (m_Item.m_ItemCount == 0)
- {
- // All of the pickup has been collected, schedule the pickup for destroying
- m_bCollected = true;
- }
- m_Timer = 0;
- return true;
- }
-
- // LOG("Pickup %d cannot be collected by \"%s\", because there's no space in the inventory.", a_Dest->GetName().c_str(), m_UniqueID);
- return false;
-}
-
-
-
-
diff --git a/source/Entities/Pickup.h b/source/Entities/Pickup.h
deleted file mode 100644
index d39eda298..000000000
--- a/source/Entities/Pickup.h
+++ /dev/null
@@ -1,64 +0,0 @@
-
-#pragma once
-
-#include "Entity.h"
-#include "../Item.h"
-
-
-
-
-
-class cPlayer;
-
-
-
-
-
-// tolua_begin
-class cPickup :
- public cEntity
-{
- // tolua_end
- typedef cEntity super;
-
-public:
- CLASS_PROTODEF(cPickup);
-
- cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, 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; }
-
- virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
-
- bool CollectedBy(cPlayer * a_Dest); // tolua_export
-
- virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
-
- /// Returns the number of ticks that this entity has existed
- int GetAge(void) const { return (int)(m_Timer / 50); } // tolua_export
-
- /// Returns true if the pickup has already been collected
- bool IsCollected(void) const { return m_bCollected; } // tolua_export
-
- /// Returns true if created by player (i.e. vomiting), used for determining picking-up delay time
- bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export
-
-private:
- Vector3d m_ResultingSpeed; //Can be used to modify the resulting speed for the current tick ;)
-
- Vector3d m_WaterSpeed;
-
- /// The number of ticks that the entity has existed / timer between collect and destroy; in msec
- float m_Timer;
-
- cItem m_Item;
-
- bool m_bCollected;
-
- bool m_bIsPlayerCreated;
-}; // tolua_export
-
-
-
-
diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp
deleted file mode 100644
index 098417dc5..000000000
--- a/source/Entities/Player.cpp
+++ /dev/null
@@ -1,1715 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "Player.h"
-#include "../Server.h"
-#include "../ClientHandle.h"
-#include "../UI/Window.h"
-#include "../UI/WindowOwner.h"
-#include "../World.h"
-#include "Pickup.h"
-#include "../PluginManager.h"
-#include "../BlockEntities/BlockEntity.h"
-#include "../GroupManager.h"
-#include "../Group.h"
-#include "../ChatColor.h"
-#include "../Item.h"
-#include "../Tracer.h"
-#include "../Root.h"
-#include "../OSSupport/Timer.h"
-#include "../MersenneTwister.h"
-#include "../Chunk.h"
-#include "../Items/ItemHandler.h"
-
-#include "../Vector3d.h"
-#include "../Vector3f.h"
-
-#include "../../iniFile/iniFile.h"
-#include <json/json.h>
-
-#define float2int(x) ((x)<0 ? ((int)(x))-1 : (int)(x))
-
-
-
-
-
-
-cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
- : super(etPlayer, 0.6, 1.8)
- , m_GameMode(eGameMode_NotSet)
- , m_IP("")
- , m_LastBlockActionTime( 0 )
- , m_LastBlockActionCnt( 0 )
- , m_AirLevel( MAX_AIR_LEVEL )
- , m_AirTickTimer( DROWNING_TICKS )
- , m_bVisible( true )
- , m_LastGroundHeight( 0 )
- , m_bTouchGround( false )
- , m_Stance( 0.0 )
- , m_Inventory(*this)
- , m_CurrentWindow(NULL)
- , m_InventoryWindow(NULL)
- , m_TimeLastPickupCheck( 0.f )
- , m_Color('-')
- , m_ClientHandle( a_Client )
- , m_FoodLevel(MAX_FOOD_LEVEL)
- , m_FoodSaturationLevel(5)
- , m_FoodTickTimer(0)
- , m_FoodExhaustionLevel(0)
- , m_FoodPoisonedTicksRemaining(0)
- , m_NormalMaxSpeed(0.1)
- , m_SprintingMaxSpeed(0.13)
- , m_IsCrouched(false)
- , m_IsSprinting(false)
- , m_IsSwimming(false)
- , m_IsSubmerged(false)
- , m_EatingFinishTick(-1)
- , m_IsChargingBow(false)
- , m_BowCharge(0)
- , m_XpTotal(0)
-{
- LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
- a_PlayerName.c_str(), a_Client->GetIPString().c_str(),
- this, GetUniqueID()
- );
-
- m_InventoryWindow = new cInventoryWindow(*this);
- m_CurrentWindow = m_InventoryWindow;
- m_InventoryWindow->OpenedByPlayer(*this);
-
- SetMaxHealth(MAX_HEALTH);
- m_Health = MAX_HEALTH;
-
- cTimer t1;
- m_LastPlayerListTime = t1.GetNowTime();
-
- m_TimeLastTeleportPacket = 0;
- m_TimeLastPickupCheck = 0;
-
- m_PlayerName = a_PlayerName;
- m_bDirtyPosition = true; // So chunks are streamed to player at spawn
-
- if (!LoadFromDisk())
- {
- m_Inventory.Clear();
- SetPosX(cRoot::Get()->GetDefaultWorld()->GetSpawnX());
- SetPosY(cRoot::Get()->GetDefaultWorld()->GetSpawnY());
- SetPosZ(cRoot::Get()->GetDefaultWorld()->GetSpawnZ());
-
- LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}",
- a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ()
- );
- }
- m_LastJumpHeight = (float)(GetPosY());
- m_LastGroundHeight = (float)(GetPosY());
- m_Stance = GetPosY() + 1.62;
-
- cRoot::Get()->GetServer()->PlayerCreated(this);
-}
-
-
-
-
-
-cPlayer::~cPlayer(void)
-{
- LOGD("Deleting cPlayer \"%s\" at %p, ID %d", m_PlayerName.c_str(), this, GetUniqueID());
-
- // Notify the server that the player is being destroyed
- cRoot::Get()->GetServer()->PlayerDestroying(this);
-
- SaveToDisk();
-
- m_World->RemovePlayer( this );
-
- m_ClientHandle = NULL;
-
- delete m_InventoryWindow;
-
- LOGD("Player %p deleted", this);
-}
-
-
-
-
-
-bool cPlayer::Initialize(cWorld * a_World)
-{
- ASSERT(a_World != NULL);
-
- if (super::Initialize(a_World))
- {
- // Remove the client handle from the server, it will be ticked from this object from now on
- if (m_ClientHandle != NULL)
- {
- cRoot::Get()->GetServer()->ClientMovedToWorld(m_ClientHandle);
- }
-
- GetWorld()->AddPlayer(this);
- return true;
- }
- return false;
-}
-
-
-
-
-
-void cPlayer::Destroyed()
-{
- CloseWindow(false);
-
- m_ClientHandle = NULL;
-}
-
-
-
-
-
-void cPlayer::SpawnOn(cClientHandle & a_Client)
-{
- if (!m_bVisible || (m_ClientHandle == (&a_Client)))
- {
- return;
- }
- a_Client.SendPlayerSpawn(*this);
- a_Client.SendEntityHeadLook(*this);
- a_Client.SendEntityEquipment(*this, 0, m_Inventory.GetEquippedItem() );
- a_Client.SendEntityEquipment(*this, 1, m_Inventory.GetEquippedBoots() );
- a_Client.SendEntityEquipment(*this, 2, m_Inventory.GetEquippedLeggings() );
- a_Client.SendEntityEquipment(*this, 3, m_Inventory.GetEquippedChestplate() );
- a_Client.SendEntityEquipment(*this, 4, m_Inventory.GetEquippedHelmet() );
-}
-
-
-
-
-
-void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
-{
- if (m_ClientHandle != NULL)
- {
- if (m_ClientHandle->IsDestroyed())
- {
- // This should not happen, because destroying a client will remove it from the world, but just in case
- m_ClientHandle = NULL;
- return;
- }
-
- if (!m_ClientHandle->IsPlaying())
- {
- // We're not yet in the game, ignore everything
- return;
- }
- }
-
- if (!a_Chunk.IsValid())
- {
- // This may happen if the cPlayer is created before the chunks have the chance of being loaded / generated (#83)
- return;
- }
-
- super::Tick(a_Dt, a_Chunk);
-
- // Set player swimming state
- SetSwimState(a_Chunk);
-
- // Handle air drowning stuff
- HandleAir();
-
- // Handle charging the bow:
- if (m_IsChargingBow)
- {
- m_BowCharge += 1;
- }
-
- if (m_bDirtyPosition)
- {
- // Apply food exhaustion from movement:
- ApplyFoodExhaustionFromMovement();
-
- cRoot::Get()->GetPluginManager()->CallHookPlayerMoving(*this);
- BroadcastMovementUpdate(m_ClientHandle);
- m_ClientHandle->StreamChunks();
- }
- else
- {
- BroadcastMovementUpdate(m_ClientHandle);
- }
-
- if (m_Health > 0) // make sure player is alive
- {
- m_World->CollectPickupsByPlayer(this);
-
- if ((m_EatingFinishTick >= 0) && (m_EatingFinishTick <= m_World->GetWorldAge()))
- {
- FinishEating();
- }
-
- HandleFood();
- }
-
- // Send Player List (Once per m_LastPlayerListTime/1000 ms)
- cTimer t1;
- if (m_LastPlayerListTime + cPlayer::PLAYER_LIST_TIME_MS <= t1.GetNowTime())
- {
- m_World->SendPlayerList(this);
- m_LastPlayerListTime = t1.GetNowTime();
- }
-}
-
-
-
-
-
-int cPlayer::CalcLevelFromXp(int a_XpTotal)
-{
- //level 0 to 15
- if(a_XpTotal <= XP_TO_LEVEL15)
- {
- return a_XpTotal / XP_PER_LEVEL_TO15;
- }
-
- //level 30+
- if(a_XpTotal > XP_TO_LEVEL30)
- {
- return (int) (151.5 + sqrt( 22952.25 - (14 * (2220 - a_XpTotal)))) / 7;
- }
-
- //level 16 to 30
- return (int) ( 29.5 + sqrt( 870.25 - (6 * ( 360 - a_XpTotal )))) / 3;
-}
-
-
-
-
-
-int cPlayer::XpForLevel(int a_Level)
-{
- //level 0 to 15
- if(a_Level <= 15)
- {
- return a_Level * XP_PER_LEVEL_TO15;
- }
-
- //level 30+
- if(a_Level >= 31)
- {
- return (int) ( (3.5 * a_Level * a_Level) - (151.5 * a_Level) + 2220 );
- }
-
- //level 16 to 30
- return (int) ( (1.5 * a_Level * a_Level) - (29.5 * a_Level) + 360 );
-}
-
-
-
-
-
-int cPlayer::XpGetLevel()
-{
- return CalcLevelFromXp(m_XpTotal);
-}
-
-
-
-
-
-float cPlayer::XpGetPercentage()
-{
- int currentLevel = CalcLevelFromXp(m_XpTotal);
-
- return (float)m_XpTotal / (float)XpForLevel(1+currentLevel);
-}
-
-
-
-
-
-bool cPlayer::SetExperience(int a_XpTotal)
-{
- if(!(a_XpTotal >= 0) || (a_XpTotal > (INT_MAX - m_XpTotal)))
- {
- LOGWARNING("Tried to update experiece with an invalid Xp value: %d", a_XpTotal);
- return false; //oops, they gave us a dodgey number
- }
-
- m_XpTotal = a_XpTotal;
-
- return true;
-}
-
-
-
-
-
-int cPlayer::AddExperience(int a_Xp_delta)
-{
- if(a_Xp_delta < 0)
- {
- //value was negative, abort and report
- LOGWARNING("Attempt was made to increment Xp by %d, must be positive",
- a_Xp_delta);
- return -1; //should we instead just return the current Xp?
- }
-
- LOGD("Player \"%s\" earnt %d experience", m_PlayerName.c_str(), a_Xp_delta);
-
- m_XpTotal += a_Xp_delta;
-
- return m_XpTotal;
-}
-
-
-
-
-
-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)
-{
- m_bTouchGround = a_bTouchGround;
-
- if (!m_bTouchGround)
- {
- if (GetPosY() > m_LastJumpHeight)
- {
- m_LastJumpHeight = (float)GetPosY();
- }
- cWorld * World = GetWorld();
- if ((GetPosY() >= 0) && (GetPosY() < cChunkDef::Height))
- {
- BLOCKTYPE BlockType = World->GetBlock(float2int(GetPosX()), float2int(GetPosY()), float2int(GetPosZ()));
- if (BlockType != E_BLOCK_AIR)
- {
- m_bTouchGround = true;
- }
- if (
- (BlockType == E_BLOCK_WATER) ||
- (BlockType == E_BLOCK_STATIONARY_WATER) ||
- (BlockType == E_BLOCK_LADDER) ||
- (BlockType == E_BLOCK_VINES)
- )
- {
- m_LastGroundHeight = (float)GetPosY();
- }
- }
- }
- else
- {
- float Dist = (float)(m_LastGroundHeight - floor(GetPosY()));
- int Damage = (int)(Dist - 3.f);
- if (m_LastJumpHeight > m_LastGroundHeight) Damage++;
- m_LastJumpHeight = (float)GetPosY();
-
- if ((Damage > 0) && (!IsGameModeCreative()))
- {
- TakeDamage(dtFalling, NULL, Damage, Damage, 0);
- }
-
- m_LastGroundHeight = (float)GetPosY();
- }
-}
-
-
-
-
-
-void cPlayer::Heal(int a_Health)
-{
- super::Heal(a_Health);
- SendHealth();
-}
-
-
-
-
-
-void cPlayer::SetFoodLevel(int a_FoodLevel)
-{
- m_FoodLevel = std::max(0, std::min(a_FoodLevel, (int)MAX_FOOD_LEVEL));
- SendHealth();
-}
-
-
-
-
-
-void cPlayer::SetFoodSaturationLevel(double a_FoodSaturationLevel)
-{
- m_FoodSaturationLevel = std::max(0.0, std::min(a_FoodSaturationLevel, (double)m_FoodLevel));
-}
-
-
-
-
-
-void cPlayer::SetFoodTickTimer(int a_FoodTickTimer)
-{
- m_FoodTickTimer = a_FoodTickTimer;
-}
-
-
-
-
-
-void cPlayer::SetFoodExhaustionLevel(double a_FoodExhaustionLevel)
-{
- m_FoodExhaustionLevel = std::max(0.0, std::min(a_FoodExhaustionLevel, 4.0));
-}
-
-
-
-
-
-void cPlayer::SetFoodPoisonedTicksRemaining(int a_FoodPoisonedTicksRemaining)
-{
- m_FoodPoisonedTicksRemaining = a_FoodPoisonedTicksRemaining;
-}
-
-
-
-
-
-bool cPlayer::Feed(int a_Food, double a_Saturation)
-{
- if (m_FoodLevel >= MAX_FOOD_LEVEL)
- {
- return false;
- }
-
- m_FoodLevel = std::min(a_Food + m_FoodLevel, (int)MAX_FOOD_LEVEL);
- m_FoodSaturationLevel = std::min(m_FoodSaturationLevel + a_Saturation, (double)m_FoodLevel);
-
- SendHealth();
- return true;
-}
-
-
-
-
-
-void cPlayer::FoodPoison(int a_NumTicks)
-{
- bool HasBeenFoodPoisoned = (m_FoodPoisonedTicksRemaining > 0);
- m_FoodPoisonedTicksRemaining = std::max(m_FoodPoisonedTicksRemaining, a_NumTicks);
- if (!HasBeenFoodPoisoned)
- {
- // TODO: Send the poisoning indication to the client - how?
- SendHealth();
- }
-}
-
-
-
-
-
-void cPlayer::StartEating(void)
-{
- // Set the timer:
- m_EatingFinishTick = m_World->GetWorldAge() + EATING_TICKS;
-
- // Send the packets:
- m_World->BroadcastPlayerAnimation(*this, 5);
- m_World->BroadcastEntityMetadata(*this);
-}
-
-
-
-
-
-void cPlayer::FinishEating(void)
-{
- // Reset the timer:
- m_EatingFinishTick = -1;
-
- // Send the packets:
- m_ClientHandle->SendEntityStatus(*this, ENTITY_STATUS_EATING_ACCEPTED);
- m_World->BroadcastPlayerAnimation(*this, 0);
- m_World->BroadcastEntityMetadata(*this);
-
- // consume the item:
- cItem Item(GetEquippedItem());
- Item.m_ItemCount = 1;
- cItemHandler * ItemHandler = cItemHandler::GetItemHandler(Item.m_ItemType);
- if (!ItemHandler->EatItem(this, &Item))
- {
- return;
- }
- ItemHandler->OnFoodEaten(m_World, this, &Item);
-
- GetInventory().RemoveOneEquippedItem();
-
- //if the food is mushroom soup, return a bowl to the inventory
- if( Item.m_ItemType == E_ITEM_MUSHROOM_SOUP ) {
- cItem emptyBowl(E_ITEM_BOWL, 1, 0, "");
- GetInventory().AddItem(emptyBowl, true, true);
- }
-}
-
-
-
-
-
-void cPlayer::AbortEating(void)
-{
- m_EatingFinishTick = -1;
- m_World->BroadcastPlayerAnimation(*this, 0);
- m_World->BroadcastEntityMetadata(*this);
-}
-
-
-
-
-
-void cPlayer::SendHealth(void)
-{
- if (m_ClientHandle != NULL)
- {
- m_ClientHandle->SendHealth();
- }
-}
-
-
-
-
-
-void cPlayer::ClearInventoryPaintSlots(void)
-{
- // Clear the list of slots that are being inventory-painted. Used by cWindow only
- m_InventoryPaintSlots.clear();
-}
-
-
-
-
-
-void cPlayer::AddInventoryPaintSlot(int a_SlotNum)
-{
- // Add a slot to the list for inventory painting. Used by cWindow only
- m_InventoryPaintSlots.push_back(a_SlotNum);
-}
-
-
-
-
-
-const cSlotNums & cPlayer::GetInventoryPaintSlots(void) const
-{
- // Return the list of slots currently stored for inventory painting. Used by cWindow only
- return m_InventoryPaintSlots;
-}
-
-
-
-
-
-double cPlayer::GetMaxSpeed(void) const
-{
- return m_IsSprinting ? m_SprintingMaxSpeed : m_NormalMaxSpeed;
-}
-
-
-
-
-
-void cPlayer::SetNormalMaxSpeed(double a_Speed)
-{
- m_NormalMaxSpeed = a_Speed;
- if (!m_IsSprinting)
- {
- m_ClientHandle->SendPlayerMaxSpeed();
- }
-}
-
-
-
-
-
-void cPlayer::SetSprintingMaxSpeed(double a_Speed)
-{
- m_SprintingMaxSpeed = a_Speed;
- if (m_IsSprinting)
- {
- m_ClientHandle->SendPlayerMaxSpeed();
- }
-}
-
-
-
-
-
-void cPlayer::SetCrouch(bool a_IsCrouched)
-{
- // Set the crouch status, broadcast to all visible players
-
- if (a_IsCrouched == m_IsCrouched)
- {
- // No change
- return;
- }
- m_IsCrouched = a_IsCrouched;
- m_World->BroadcastEntityMetadata(*this);
-}
-
-
-
-
-
-void cPlayer::SetSprint(bool a_IsSprinting)
-{
- if (a_IsSprinting == m_IsSprinting)
- {
- // No change
- return;
- }
-
- m_IsSprinting = a_IsSprinting;
- m_ClientHandle->SendPlayerMaxSpeed();
-}
-
-
-
-
-
-void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
-{
- if (a_TDI.DamageType != dtInVoid)
- {
- if (IsGameModeCreative())
- {
- // No damage / health in creative mode
- return;
- }
- }
-
- super::DoTakeDamage(a_TDI);
-
- // Any kind of damage adds food exhaustion
- AddFoodExhaustion(0.3f);
-
- SendHealth();
-}
-
-
-
-
-
-void cPlayer::KilledBy(cEntity * a_Killer)
-{
- super::KilledBy(a_Killer);
-
- if (m_Health > 0)
- {
- return; // not dead yet =]
- }
-
- m_bVisible = false; // So new clients don't see the player
-
- // Puke out all the items
- cItems Pickups;
- m_Inventory.CopyToItems(Pickups);
- m_Inventory.Clear();
- m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10);
- SaveToDisk(); // Save it, yeah the world is a tough place !
-}
-
-
-
-
-
-void cPlayer::Respawn(void)
-{
- m_Health = GetMaxHealth();
-
- // Reset food level:
- m_FoodLevel = MAX_FOOD_LEVEL;
- m_FoodSaturationLevel = 5;
-
- m_ClientHandle->SendRespawn();
-
- // Extinguish the fire:
- StopBurning();
-
- TeleportToCoords(GetWorld()->GetSpawnX(), GetWorld()->GetSpawnY(), GetWorld()->GetSpawnZ());
-
- SetVisible(true);
-}
-
-
-
-
-
-double cPlayer::GetEyeHeight(void) const
-{
- return m_Stance;
-}
-
-
-
-
-Vector3d cPlayer::GetEyePosition(void) const
-{
- return Vector3d( GetPosX(), m_Stance, GetPosZ() );
-}
-
-
-
-
-
-bool cPlayer::IsGameModeCreative(void) const
-{
- return (m_GameMode == gmCreative) || // Either the player is explicitly in Creative
- ((m_GameMode == gmNotSet) && m_World->IsGameModeCreative()); // or they inherit from the world and the world is Creative
-}
-
-
-
-
-
-bool cPlayer::IsGameModeSurvival(void) const
-{
- return (m_GameMode == gmSurvival) || // Either the player is explicitly in Survival
- ((m_GameMode == gmNotSet) && m_World->IsGameModeSurvival()); // or they inherit from the world and the world is Survival
-}
-
-
-
-
-
-bool cPlayer::IsGameModeAdventure(void) const
-{
- return (m_GameMode == gmCreative) || // Either the player is explicitly in Adventure
- ((m_GameMode == gmNotSet) && m_World->IsGameModeCreative()); // or they inherit from the world and the world is Adventure
-}
-
-
-
-
-
-void cPlayer::OpenWindow(cWindow * a_Window)
-{
- if (a_Window != m_CurrentWindow)
- {
- CloseWindow(false);
- }
- a_Window->OpenedByPlayer(*this);
- m_CurrentWindow = a_Window;
- a_Window->SendWholeWindow(*GetClientHandle());
-}
-
-
-
-
-
-void cPlayer::CloseWindow(bool a_CanRefuse)
-{
- if (m_CurrentWindow == NULL)
- {
- m_CurrentWindow = m_InventoryWindow;
- return;
- }
-
- if (m_CurrentWindow->ClosedByPlayer(*this, a_CanRefuse) || !a_CanRefuse)
- {
- // Close accepted, go back to inventory window (the default):
- m_CurrentWindow = m_InventoryWindow;
- }
- else
- {
- // Re-open the window
- m_CurrentWindow->OpenedByPlayer(*this);
- m_CurrentWindow->SendWholeWindow(*GetClientHandle());
- }
-}
-
-
-
-
-
-void cPlayer::CloseWindowIfID(char a_WindowID, bool a_CanRefuse)
-{
- if ((m_CurrentWindow == NULL) || (m_CurrentWindow->GetWindowID() != a_WindowID))
- {
- return;
- }
- CloseWindow();
-}
-
-
-
-
-
-void cPlayer::SetLastBlockActionTime()
-{
- if (m_World != NULL)
- {
- m_LastBlockActionTime = m_World->GetWorldAge() / 20.0f;
- }
-}
-
-
-
-
-
-void cPlayer::SetLastBlockActionCnt( int a_LastBlockActionCnt )
-{
- m_LastBlockActionCnt = a_LastBlockActionCnt;
-}
-
-
-
-
-
-void cPlayer::SetGameMode(eGameMode a_GameMode)
-{
- if ((a_GameMode < gmMin) || (a_GameMode >= gmMax))
- {
- LOGWARNING("%s: Setting invalid gamemode: %d", GetName().c_str(), a_GameMode);
- return;
- }
-
- if (m_GameMode == a_GameMode)
- {
- // Gamemode already set
- return;
- }
-
- m_GameMode = a_GameMode;
- m_ClientHandle->SendGameMode(a_GameMode);
-}
-
-
-
-
-
-void cPlayer::LoginSetGameMode( eGameMode a_GameMode )
-{
- m_GameMode = a_GameMode;
-}
-
-
-
-
-
-void cPlayer::SetIP(const AString & a_IP)
-{
- m_IP = a_IP;
-}
-
-
-
-
-
-void cPlayer::SendMessage(const AString & a_Message)
-{
- m_ClientHandle->SendChat(a_Message);
-}
-
-
-
-
-
-void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
-{
- SetPosition( a_PosX, a_PosY, a_PosZ );
- m_LastGroundHeight = (float)a_PosY;
-
- m_World->BroadcastTeleportEntity(*this, GetClientHandle());
- m_ClientHandle->SendPlayerMoveLook();
-}
-
-
-
-
-
-Vector3d cPlayer::GetThrowStartPos(void) const
-{
- Vector3d res = GetEyePosition();
-
- // Adjust the position to be just outside the player's bounding box:
- res.x += 0.16 * cos(GetPitch());
- res.y += -0.1;
- res.z += 0.16 * sin(GetPitch());
-
- return res;
-}
-
-
-
-
-
-Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const
-{
- Vector3d res = GetLookVector();
- res.Normalize();
-
- // TODO: Add a slight random change (+-0.0075 in each direction)
-
- return res * a_SpeedCoeff;
-}
-
-
-
-
-
-void cPlayer::MoveTo( const Vector3d & a_NewPos )
-{
- if ((a_NewPos.y < -990) && (GetPosY() > -100))
- {
- // When attached to an entity, the client sends position packets with weird coords:
- // Y = -999 and X, Z = attempting to create speed, usually up to 0.03
- // We cannot test m_AttachedTo, because when deattaching, the server thinks the client is already deattached while
- // the client may still send more of these nonsensical packets.
- if (m_AttachedTo != NULL)
- {
- Vector3d AddSpeed(a_NewPos);
- AddSpeed.y = 0;
- m_AttachedTo->AddSpeed(AddSpeed);
- }
- return;
- }
-
- // TODO: should do some checks to see if player is not moving through terrain
- // TODO: Official server refuses position packets too far away from each other, kicking "hacked" clients; we should, too
-
- SetPosition( a_NewPos );
- SetStance(a_NewPos.y + 1.62);
-}
-
-
-
-
-
-void cPlayer::SetVisible(bool a_bVisible)
-{
- if (a_bVisible && !m_bVisible) // Make visible
- {
- m_bVisible = true;
- m_World->BroadcastSpawnEntity(*this);
- }
- if (!a_bVisible && m_bVisible)
- {
- m_bVisible = false;
- m_World->BroadcastDestroyEntity(*this, m_ClientHandle); // Destroy on all clients
- }
-}
-
-
-
-
-
-void cPlayer::AddToGroup( const AString & a_GroupName )
-{
- cGroup* Group = cRoot::Get()->GetGroupManager()->GetGroup( a_GroupName );
- m_Groups.push_back( Group );
- LOGD("Added %s to group %s", m_PlayerName.c_str(), a_GroupName.c_str() );
- ResolveGroups();
- ResolvePermissions();
-}
-
-
-
-
-
-void cPlayer::RemoveFromGroup( const AString & a_GroupName )
-{
- bool bRemoved = false;
- for( GroupList::iterator itr = m_Groups.begin(); itr != m_Groups.end(); ++itr )
- {
- if( (*itr)->GetName().compare(a_GroupName ) == 0 )
- {
- m_Groups.erase( itr );
- bRemoved = true;
- break;
- }
- }
-
- if( bRemoved )
- {
- LOGD("Removed %s from group %s", m_PlayerName.c_str(), a_GroupName.c_str() );
- ResolveGroups();
- ResolvePermissions();
- }
- else
- {
- LOGWARN("Tried to remove %s from group %s but was not in that group", m_PlayerName.c_str(), a_GroupName.c_str() );
- }
-}
-
-
-
-
-
-bool cPlayer::CanUseCommand( const AString & a_Command )
-{
- for( GroupList::iterator itr = m_Groups.begin(); itr != m_Groups.end(); ++itr )
- {
- if( (*itr)->HasCommand( a_Command ) ) return true;
- }
- return false;
-}
-
-
-
-
-
-bool cPlayer::HasPermission(const AString & a_Permission)
-{
- if (a_Permission.empty())
- {
- // Empty permission request is always granted
- return true;
- }
-
- AStringVector Split = StringSplit( a_Permission, "." );
- PermissionMap Possibilities = m_ResolvedPermissions;
- // Now search the namespaces
- while( Possibilities.begin() != Possibilities.end() )
- {
- PermissionMap::iterator itr = Possibilities.begin();
- if( itr->second )
- {
- AStringVector OtherSplit = StringSplit( itr->first, "." );
- if( OtherSplit.size() <= Split.size() )
- {
- unsigned int i;
- for( i = 0; i < OtherSplit.size(); ++i )
- {
- if( OtherSplit[i].compare( Split[i] ) != 0 )
- {
- if( OtherSplit[i].compare("*") == 0 ) return true; // WildCard man!! WildCard!
- break;
- }
- }
- if( i == Split.size() ) return true;
- }
- }
- Possibilities.erase( itr );
- }
-
- // Nothing that matched :(
- return false;
-}
-
-
-
-
-
-bool cPlayer::IsInGroup( const AString & a_Group )
-{
- for( GroupList::iterator itr = m_ResolvedGroups.begin(); itr != m_ResolvedGroups.end(); ++itr )
- {
- if( a_Group.compare( (*itr)->GetName().c_str() ) == 0 )
- return true;
- }
- return false;
-}
-
-
-
-
-
-void cPlayer::ResolvePermissions()
-{
- m_ResolvedPermissions.clear(); // Start with an empty map yo~
-
- // Copy all player specific permissions into the resolved permissions map
- for( PermissionMap::iterator itr = m_Permissions.begin(); itr != m_Permissions.end(); ++itr )
- {
- m_ResolvedPermissions[ itr->first ] = itr->second;
- }
-
- for( GroupList::iterator GroupItr = m_ResolvedGroups.begin(); GroupItr != m_ResolvedGroups.end(); ++GroupItr )
- {
- const cGroup::PermissionMap & Permissions = (*GroupItr)->GetPermissions();
- for( cGroup::PermissionMap::const_iterator itr = Permissions.begin(); itr != Permissions.end(); ++itr )
- {
- m_ResolvedPermissions[ itr->first ] = itr->second;
- }
- }
-}
-
-
-
-
-
-void cPlayer::ResolveGroups()
-{
- // Clear resolved groups first
- m_ResolvedGroups.clear();
-
- // Get a complete resolved list of all groups the player is in
- std::map< cGroup*, bool > AllGroups; // Use a map, because it's faster than iterating through a list to find duplicates
- GroupList ToIterate;
- for( GroupList::iterator GroupItr = m_Groups.begin(); GroupItr != m_Groups.end(); ++GroupItr )
- {
- ToIterate.push_back( *GroupItr );
- }
- while( ToIterate.begin() != ToIterate.end() )
- {
- cGroup* CurrentGroup = *ToIterate.begin();
- if( AllGroups.find( CurrentGroup ) != AllGroups.end() )
- {
- LOGWARNING("ERROR: Player \"%s\" is in the group multiple times (\"%s\"). Please fix your settings in users.ini!",
- m_PlayerName.c_str(), CurrentGroup->GetName().c_str()
- );
- }
- else
- {
- AllGroups[ CurrentGroup ] = true;
- m_ResolvedGroups.push_back( CurrentGroup ); // Add group to resolved list
- const cGroup::GroupList & Inherits = CurrentGroup->GetInherits();
- for( cGroup::GroupList::const_iterator itr = Inherits.begin(); itr != Inherits.end(); ++itr )
- {
- if( AllGroups.find( *itr ) != AllGroups.end() )
- {
- LOGERROR("ERROR: Player %s is in the same group multiple times due to inheritance (%s). FIX IT!", m_PlayerName.c_str(), (*itr)->GetName().c_str() );
- continue;
- }
- ToIterate.push_back( *itr );
- }
- }
- ToIterate.erase( ToIterate.begin() );
- }
-}
-
-
-
-
-
-AString cPlayer::GetColor(void) const
-{
- if ( m_Color != '-' )
- {
- return cChatColor::MakeColor( m_Color );
- }
-
- if ( m_Groups.size() < 1 )
- {
- return cChatColor::White;
- }
-
- return (*m_Groups.begin())->GetColor();
-}
-
-
-
-
-
-void cPlayer::TossItem(
- bool a_bDraggingItem,
- char a_Amount /* = 1 */,
- short a_CreateType /* = 0 */,
- short a_CreateHealth /* = 0 */
-)
-{
- cItems Drops;
- if (a_CreateType != 0)
- {
- // Just create item without touching the inventory (used in creative mode)
- Drops.push_back(cItem(a_CreateType, a_Amount, a_CreateHealth));
- }
- else
- {
- // Drop an item from the inventory:
- if (a_bDraggingItem)
- {
- cItem & Item = GetDraggingItem();
- if (!Item.IsEmpty())
- {
- char OriginalItemAmount = Item.m_ItemCount;
- Item.m_ItemCount = std::min(OriginalItemAmount, a_Amount);
- Drops.push_back(Item);
- if (OriginalItemAmount > a_Amount)
- {
- Item.m_ItemCount = OriginalItemAmount - (char)a_Amount;
- }
- else
- {
- Item.Empty();
- }
- }
- }
- else
- {
- // Else drop equipped item
- cItem DroppedItem(GetInventory().GetEquippedItem());
- if (!DroppedItem.IsEmpty())
- {
- if (GetInventory().RemoveOneEquippedItem())
- {
- DroppedItem.m_ItemCount = 1; // RemoveItem decreases the count, so set it to 1 again
- Drops.push_back(DroppedItem);
- }
- }
- }
- }
- 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 * 3, vY * 3, vZ * 3, true); // 'true' because created by player
-}
-
-
-
-
-
-bool cPlayer::MoveToWorld(const char * a_WorldName)
-{
- cWorld * World = cRoot::Get()->GetWorld(a_WorldName);
- if (World == NULL)
- {
- LOG("%s: Couldn't find world \"%s\".", __FUNCTION__, a_WorldName);
- return false;
- }
-
- eDimension OldDimension = m_World->GetDimension();
-
- // Remove all links to the old world
- m_World->RemovePlayer(this);
- m_ClientHandle->RemoveFromAllChunks();
- m_World->RemoveEntity(this);
-
- // If the dimension is different, we can send the respawn packet
- // http://wiki.vg/Protocol#0x09 says "don't send if dimension is the same" as of 2013_07_02
- m_ClientHandle->MoveToWorld(*World, (OldDimension != World->GetDimension()));
-
- // Add player to all the necessary parts of the new world
- SetWorld(World);
- World->AddEntity(this);
- World->AddPlayer(this);
-
- return true;
-}
-
-
-
-
-
-void cPlayer::LoadPermissionsFromDisk()
-{
- m_Groups.clear();
- m_Permissions.clear();
-
- cIniFile IniFile;
- if (IniFile.ReadFile("users.ini"))
- {
- std::string Groups = IniFile.GetValue(m_PlayerName, "Groups", "");
- if (!Groups.empty())
- {
- AStringVector Split = StringSplit( Groups, "," );
- for( unsigned int i = 0; i < Split.size(); i++ )
- {
- AddToGroup( Split[i].c_str() );
- }
- }
- else
- {
- AddToGroup("Default");
- }
-
- m_Color = IniFile.GetValue(m_PlayerName, "Color", "-")[0];
- }
- else
- {
- LOGWARN("Failed to read the users.ini file. The player will be added only to the Default group.");
- AddToGroup("Default");
- }
- ResolvePermissions();
-}
-
-
-
-
-bool cPlayer::LoadFromDisk()
-{
- LoadPermissionsFromDisk();
-
- // Log player permissions, cause it's what the cool kids do
- LOGINFO("Player %s has permissions:", m_PlayerName.c_str() );
- for( PermissionMap::iterator itr = m_ResolvedPermissions.begin(); itr != m_ResolvedPermissions.end(); ++itr )
- {
- if( itr->second ) LOGINFO("%s", itr->first.c_str() );
- }
-
- AString SourceFile;
- Printf(SourceFile, "players/%s.json", m_PlayerName.c_str() );
-
- cFile f;
- if (!f.Open(SourceFile, cFile::fmRead))
- {
- // This is a new player whom we haven't seen yet, bail out, let them have the defaults
- return false;
- }
-
- AString buffer;
- if (f.ReadRestOfFile(buffer) != f.GetSize())
- {
- LOGWARNING("Cannot read player data from file \"%s\"", SourceFile.c_str());
- return false;
- }
- f.Close(); //cool kids play nice
-
- Json::Value root;
- Json::Reader reader;
- if (!reader.parse(buffer, root, false))
- {
- LOGWARNING("Cannot parse player data in file \"%s\", player will be reset", SourceFile.c_str());
- }
-
- Json::Value & JSON_PlayerPosition = root["position"];
- if (JSON_PlayerPosition.size() == 3)
- {
- SetPosX(JSON_PlayerPosition[(unsigned int)0].asDouble());
- SetPosY(JSON_PlayerPosition[(unsigned int)1].asDouble());
- SetPosZ(JSON_PlayerPosition[(unsigned int)2].asDouble());
- m_LastPosX = GetPosX();
- m_LastPosY = GetPosY();
- m_LastPosZ = GetPosZ();
- m_LastFoodPos = GetPosition();
- }
-
- Json::Value & JSON_PlayerRotation = root["rotation"];
- if (JSON_PlayerRotation.size() == 3)
- {
- SetRotation ((float)JSON_PlayerRotation[(unsigned int)0].asDouble());
- SetPitch ((float)JSON_PlayerRotation[(unsigned int)1].asDouble());
- SetRoll ((float)JSON_PlayerRotation[(unsigned int)2].asDouble());
- }
-
- m_Health = root.get("health", 0).asInt();
- m_AirLevel = root.get("air", MAX_AIR_LEVEL).asInt();
- m_FoodLevel = root.get("food", MAX_FOOD_LEVEL).asInt();
- m_FoodSaturationLevel = root.get("foodSaturation", MAX_FOOD_LEVEL).asDouble();
- m_FoodTickTimer = root.get("foodTickTimer", 0).asInt();
- m_FoodExhaustionLevel = root.get("foodExhaustion", 0).asDouble();
-
- SetExperience(root.get("experience", 0).asInt());
-
- m_GameMode = (eGameMode) root.get("gamemode", eGameMode_NotSet).asInt();
-
- m_Inventory.LoadFromJson(root["inventory"]);
-
- m_LoadedWorldName = root.get("world", "world").asString();
-
- LOGD("Player \"%s\" was read from file, spawning at {%.2f, %.2f, %.2f} in world \"%s\"",
- m_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str()
- );
-
- return true;
-}
-
-
-
-
-
-bool cPlayer::SaveToDisk()
-{
- cFile::CreateFolder(FILE_IO_PREFIX + AString("players"));
-
- // create the JSON data
- Json::Value JSON_PlayerPosition;
- JSON_PlayerPosition.append(Json::Value(GetPosX()));
- JSON_PlayerPosition.append(Json::Value(GetPosY()));
- JSON_PlayerPosition.append(Json::Value(GetPosZ()));
-
- Json::Value JSON_PlayerRotation;
- JSON_PlayerRotation.append(Json::Value(GetRotation()));
- JSON_PlayerRotation.append(Json::Value(GetPitch()));
- JSON_PlayerRotation.append(Json::Value(GetRoll()));
-
- Json::Value JSON_Inventory;
- m_Inventory.SaveToJson(JSON_Inventory);
-
- Json::Value root;
- root["position"] = JSON_PlayerPosition;
- root["rotation"] = JSON_PlayerRotation;
- root["inventory"] = JSON_Inventory;
- root["health"] = m_Health;
- root["experience"] = m_XpTotal;
- root["air"] = m_AirLevel;
- root["food"] = m_FoodLevel;
- root["foodSaturation"] = m_FoodSaturationLevel;
- root["foodTickTimer"] = m_FoodTickTimer;
- root["foodExhaustion"] = m_FoodExhaustionLevel;
- root["world"] = GetWorld()->GetName();
-
- if (m_GameMode == GetWorld()->GetGameMode())
- {
- root["gamemode"] = (int) eGameMode_NotSet;
- }
- else
- {
- root["gamemode"] = (int) m_GameMode;
- }
-
- Json::StyledWriter writer;
- std::string JsonData = writer.write(root);
-
- AString SourceFile;
- Printf(SourceFile, "players/%s.json", m_PlayerName.c_str() );
-
- cFile f;
- if (!f.Open(SourceFile, cFile::fmWrite))
- {
- LOGERROR("ERROR WRITING PLAYER \"%s\" TO FILE \"%s\" - cannot open file", m_PlayerName.c_str(), SourceFile.c_str());
- return false;
- }
- if (f.Write(JsonData.c_str(), JsonData.size()) != (int)JsonData.size())
- {
- LOGERROR("ERROR WRITING PLAYER JSON TO FILE \"%s\"", SourceFile.c_str());
- return false;
- }
- return true;
-}
-
-
-
-
-
-cPlayer::StringList cPlayer::GetResolvedPermissions()
-{
- StringList Permissions;
-
- const PermissionMap& ResolvedPermissions = m_ResolvedPermissions;
- for( PermissionMap::const_iterator itr = ResolvedPermissions.begin(); itr != ResolvedPermissions.end(); ++itr )
- {
- if( itr->second ) Permissions.push_back( itr->first );
- }
-
- return Permissions;
-}
-
-
-
-
-
-void cPlayer::UseEquippedItem(void)
-{
- if (IsGameModeCreative()) // No damage in creative
- {
- return;
- }
-
- GetInventory().DamageEquippedItem();
-}
-
-
-
-
-
-void cPlayer::SetSwimState(cChunk & a_Chunk)
-{
- int RelY = (int)floor(m_LastPosY + 0.1);
- if ((RelY < 0) || (RelY >= cChunkDef::Height - 1))
- {
- m_IsSwimming = false;
- m_IsSubmerged = false;
- return;
- }
-
- BLOCKTYPE BlockIn;
- int RelX = (int)floor(m_LastPosX) - a_Chunk.GetPosX() * cChunkDef::Width;
- int RelZ = (int)floor(m_LastPosZ) - a_Chunk.GetPosZ() * cChunkDef::Width;
-
- // Check if the player is swimming:
- // Use Unbounded, because we're being called *after* processing super::Tick(), which could have changed our chunk
- 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:
- VERIFY(a_Chunk.UnboundedRelGetBlockType(RelX, RelY + 1, RelZ, BlockIn));
- m_IsSubmerged = IsBlockWater(BlockIn);
-}
-
-
-
-
-
-void cPlayer::HandleAir(void)
-{
- // Ref.: http://www.minecraftwiki.net/wiki/Chunk_format
- // see if the player is /submerged/ water (block above is water)
- // Get the type of block the player's standing in:
-
- if (IsSubmerged())
- {
- // either reduce air level or damage player
- if (m_AirLevel < 1)
- {
- if (m_AirTickTimer < 1)
- {
- // damage player
- TakeDamage(dtDrowning, NULL, 1, 1, 0);
- // reset timer
- m_AirTickTimer = DROWNING_TICKS;
- }
- else
- {
- m_AirTickTimer -= 1;
- }
- }
- else
- {
- // reduce air supply
- m_AirLevel -= 1;
- }
- }
- else
- {
- // set the air back to maximum
- m_AirLevel = MAX_AIR_LEVEL;
- m_AirTickTimer = DROWNING_TICKS;
- }
-}
-
-
-
-
-
-void cPlayer::HandleFood(void)
-{
- // Ref.: http://www.minecraftwiki.net/wiki/Hunger
-
- // Remember the food level before processing, for later comparison
- int LastFoodLevel = m_FoodLevel;
-
- // Heal or damage, based on the food level, using the m_FoodTickTimer:
- if ((m_FoodLevel > 17) || (m_FoodLevel <= 0))
- {
- m_FoodTickTimer++;
- if (m_FoodTickTimer >= 80)
- {
- m_FoodTickTimer = 0;
-
- if (m_FoodLevel >= 17)
- {
- // Regenerate health from food, incur 3 pts of food exhaustion:
- Heal(1);
- m_FoodExhaustionLevel += 3;
- }
- else if (m_FoodLevel <= 0)
- {
- // Damage from starving
- TakeDamage(dtStarving, NULL, 1, 1, 0);
- }
- }
- }
-
- // Apply food poisoning food exhaustion:
- if (m_FoodPoisonedTicksRemaining > 0)
- {
- m_FoodPoisonedTicksRemaining--;
- m_FoodExhaustionLevel += 0.025; // 0.5 per second = 0.025 per tick
- }
-
- // Apply food exhaustion that has accumulated:
- if (m_FoodExhaustionLevel >= 4)
- {
- m_FoodExhaustionLevel -= 4;
-
- if (m_FoodSaturationLevel >= 1)
- {
- m_FoodSaturationLevel -= 1;
- }
- else
- {
- m_FoodLevel = std::max(m_FoodLevel - 1, 0);
- }
- }
-
- if (m_FoodLevel != LastFoodLevel)
- {
- SendHealth();
- }
-}
-
-
-
-
-
-void cPlayer::ApplyFoodExhaustionFromMovement()
-{
- if (IsGameModeCreative())
- {
- return;
- }
-
- // Calculate the distance travelled, update the last pos:
- Vector3d Movement(GetPosition() - m_LastFoodPos);
- Movement.y = 0; // Only take XZ movement into account
- m_LastFoodPos = GetPosition();
-
- // If riding anything, apply no food exhaustion
- if (m_AttachedTo != NULL)
- {
- return;
- }
-
- // Apply the exhaustion based on distance travelled:
- double BaseExhaustion = Movement.Length();
- if (IsSprinting())
- {
- // 0.1 pt per meter sprinted
- BaseExhaustion = BaseExhaustion * 0.1;
- }
- else if (IsSwimming())
- {
- // 0.015 pt per meter swum
- BaseExhaustion = BaseExhaustion * 0.015;
- }
- else
- {
- // 0.01 pt per meter walked / sneaked
- BaseExhaustion = BaseExhaustion * 0.01;
- }
- m_FoodExhaustionLevel += BaseExhaustion;
-}
-
-
-
-
diff --git a/source/Entities/Player.h b/source/Entities/Player.h
deleted file mode 100644
index ab2f94d4c..000000000
--- a/source/Entities/Player.h
+++ /dev/null
@@ -1,447 +0,0 @@
-
-#pragma once
-
-#include "Pawn.h"
-#include "../Inventory.h"
-#include "../Defines.h"
-#include "../World.h"
-
-
-
-
-
-class cGroup;
-class cWindow;
-class cClientHandle;
-
-
-
-
-
-// tolua_begin
-class cPlayer :
- public cPawn
-{
- typedef cPawn super;
-
-public:
- enum
- {
- MAX_HEALTH = 20,
- MAX_FOOD_LEVEL = 20,
- EATING_TICKS = 30, ///< Number of ticks it takes to eat an item
- MAX_AIR_LEVEL = 300,
- DROWNING_TICKS = 10, //number of ticks per heart of damage
- } ;
- // tolua_end
-
- CLASS_PROTODEF(cPlayer)
-
-
- cPlayer(cClientHandle * a_Client, const AString & a_PlayerName);
- virtual ~cPlayer();
-
- virtual bool Initialize(cWorld * a_World) override;
-
- virtual void SpawnOn(cClientHandle & a_Client) override;
-
- virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
-
- virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override { };
-
- /// Returns the curently equipped weapon; empty item if none
- virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); }
-
- /// Returns the currently equipped helmet; empty item if nonte
- virtual cItem GetEquippedHelmet(void) const override { return m_Inventory.GetEquippedHelmet(); }
-
- /// Returns the currently equipped chestplate; empty item if none
- virtual cItem GetEquippedChestplate(void) const override { return m_Inventory.GetEquippedChestplate(); }
-
- /// Returns the currently equipped leggings; empty item if none
- virtual cItem GetEquippedLeggings(void) const override { return m_Inventory.GetEquippedLeggings(); }
-
- /// Returns the currently equipped boots; empty item if none
- virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); }
-
-
- // tolua_begin
-
- /** Sets the experience total
- Returns true on success
- "should" really only be called at init or player death, plugins excepted
- */
- bool SetExperience(int a_XpTotal);
-
- /* Adds Xp, "should" not inc more than MAX_EXPERIENCE_ORB_SIZE unless you're a plugin being funny, *cough* cheating
- Returns the new total experience, -1 on error
- */
- int AddExperience(int a_Xp_delta);
-
- /// Gets the experience total - XpTotal
- inline int XpGetTotal(void) { return m_XpTotal; }
-
- /// Gets the current level - XpLevel
- int XpGetLevel(void);
-
- /// Gets the experience bar percentage - XpP
- float XpGetPercentage(void);
-
- // tolua_end
-
- /// 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 IsChargingBow(void) const { return m_IsChargingBow; }
-
- void SetTouchGround( bool a_bTouchGround );
- inline void SetStance( const double a_Stance ) { m_Stance = a_Stance; }
- double GetEyeHeight(void) const; // tolua_export
- Vector3d GetEyePosition(void) const; // tolua_export
- inline bool IsOnGround(void) const {return m_bTouchGround; } // tolua_export
- inline const double GetStance(void) const { return GetPosY() + 1.62; } // tolua_export // TODO: Proper stance when crouching etc.
- inline cInventory & GetInventory(void) { return m_Inventory; } // tolua_export
- inline const cInventory & GetInventory(void) const { return m_Inventory; }
-
- inline const cItem & GetEquippedItem(void) const { return GetInventory().GetEquippedItem(); } // tolua_export
-
- virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) override;
-
- // tolua_begin
-
- /// Returns the position where projectiles thrown by this player should start, player eye position + adjustment
- Vector3d GetThrowStartPos(void) const;
-
- /// Returns the initial speed vector of a throw, with a 3D length of a_SpeedCoeff.
- Vector3d GetThrowSpeed(double a_SpeedCoeff) const;
-
- /// Returns the current gamemode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable
- eGameMode GetGameMode(void) const { return m_GameMode; }
-
- /// Returns the current effective gamemode (inherited gamemode is resolved before returning)
- eGameMode GetEffectiveGameMode(void) const { return (m_GameMode == gmNotSet) ? m_World->GetGameMode() : m_GameMode; }
-
- /** Sets the gamemode for the player.
- The gamemode may be gmNotSet, in that case the player inherits the world's gamemode.
- Updates the gamemode on the client (sends the packet)
- */
- void SetGameMode(eGameMode a_GameMode);
-
- /// Returns true if the player is in Creative mode, either explicitly, or by inheriting from current world
- bool IsGameModeCreative(void) const;
-
- /// Returns true if the player is in Survival mode, either explicitly, or by inheriting from current world
- bool IsGameModeSurvival(void) const;
-
- /// Returns true if the player is in Adventure mode, either explicitly, or by inheriting from current world
- bool IsGameModeAdventure(void) const;
-
- AString GetIP(void) const { return m_IP; } // tolua_export
-
- // tolua_end
-
- void SetIP(const AString & a_IP);
-
- float GetLastBlockActionTime() { return m_LastBlockActionTime; }
- int GetLastBlockActionCnt() { return m_LastBlockActionCnt; }
- void SetLastBlockActionCnt( int );
- void SetLastBlockActionTime();
-
- // Sets the current gamemode, doesn't check validity, doesn't send update packets to client
- void LoginSetGameMode(eGameMode a_GameMode);
-
- /// Tries to move to a new position, with attachment-related checks (y == -999)
- void MoveTo(const Vector3d & a_NewPos); // tolua_export
-
- cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export
- const cWindow * GetWindow(void) const { return m_CurrentWindow; }
-
- /// Opens the specified window; closes the current one first using CloseWindow()
- void OpenWindow(cWindow * a_Window); // Exported in ManualBindings.cpp
-
- // tolua_begin
-
- /// Closes the current window, resets current window to m_InventoryWindow. A plugin may refuse the closing if a_CanRefuse is true
- void CloseWindow(bool a_CanRefuse = true);
-
- /// Closes the current window if it matches the specified ID, resets current window to m_InventoryWindow
- void CloseWindowIfID(char a_WindowID, bool a_CanRefuse = true);
-
- cClientHandle * GetClientHandle(void) const { return m_ClientHandle; }
-
- void SendMessage(const AString & a_Message);
-
- const AString & GetName(void) const { return m_PlayerName; }
- void SetName(const AString & a_Name) { m_PlayerName = a_Name; }
-
- // tolua_end
-
- typedef std::list< cGroup* > GroupList;
- typedef std::list< std::string > StringList;
-
- /// Adds a player to existing group or creates a new group when it doesn't exist
- void AddToGroup( const AString & a_GroupName ); // tolua_export
-
- /// Removes a player from the group, resolves permissions and group inheritance (case sensitive)
- void RemoveFromGroup( const AString & a_GroupName ); // tolua_export
-
- bool CanUseCommand( const AString & a_Command ); // tolua_export
- bool HasPermission( const AString & a_Permission ); // tolua_export
- const GroupList & GetGroups() { return m_Groups; } // >> EXPORTED IN MANUALBINDINGS <<
- StringList GetResolvedPermissions(); // >> EXPORTED IN MANUALBINDINGS <<
- bool IsInGroup( const AString & a_Group ); // tolua_export
-
- // tolua_begin
-
- /// Returns the full color code to use for this player, based on their primary group or set in m_Color
- AString GetColor(void) const;
-
- void TossItem(bool a_bDraggingItem, char a_Amount = 1, short a_CreateType = 0, short a_CreateHealth = 0);
-
- /// Heals the player by the specified amount of HPs (positive only); sends health update
- void Heal(int a_Health);
-
- int GetFoodLevel (void) const { return m_FoodLevel; }
- double GetFoodSaturationLevel (void) const { return m_FoodSaturationLevel; }
- int GetFoodTickTimer (void) const { return m_FoodTickTimer; }
- double GetFoodExhaustionLevel (void) const { return m_FoodExhaustionLevel; }
- int GetFoodPoisonedTicksRemaining(void) const { return m_FoodPoisonedTicksRemaining; }
-
- int GetAirLevel (void) const { return m_AirLevel; }
-
- /// Returns true if the player is satiated, i. e. their foodlevel is at the max and they cannot eat anymore
- bool IsSatiated(void) const { return (m_FoodLevel >= MAX_FOOD_LEVEL); }
-
- void SetFoodLevel (int a_FoodLevel);
- void SetFoodSaturationLevel (double a_FoodSaturationLevel);
- void SetFoodTickTimer (int a_FoodTickTimer);
- void SetFoodExhaustionLevel (double a_FoodExhaustionLevel);
- void SetFoodPoisonedTicksRemaining(int a_FoodPoisonedTicksRemaining);
-
- /// Adds to FoodLevel and FoodSaturationLevel, returns true if any food has been consumed, false if player "full"
- bool Feed(int a_Food, double a_Saturation);
-
- /// Adds the specified exhaustion to m_FoodExhaustion. Expects only positive values.
- void AddFoodExhaustion(double a_Exhaustion)
- {
- m_FoodExhaustionLevel += a_Exhaustion;
- }
-
- /// Starts the food poisoning for the specified amount of ticks; if already foodpoisoned, sets FoodPoisonedTicksRemaining to the larger of the two
- void FoodPoison(int a_NumTicks);
-
- /// Returns true if the player is currently in the process of eating the currently equipped item
- bool IsEating(void) const { return (m_EatingFinishTick >= 0); }
-
- // tolua_end
-
- /// Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet
- void StartEating(void);
-
- /// Finishes eating the currently equipped item. Consumes the item, updates health and broadcasts the packets
- void FinishEating(void);
-
- /// Aborts the current eating operation
- void AbortEating(void);
-
- virtual void KilledBy(cEntity * a_Killer) override;
-
- void Respawn(void); // tolua_export
-
- void SetVisible( bool a_bVisible ); // tolua_export
- bool IsVisible(void) const { return m_bVisible; } // tolua_export
-
- bool MoveToWorld(const char * a_WorldName); // tolua_export
-
- bool SaveToDisk(void);
- bool LoadFromDisk(void);
- void LoadPermissionsFromDisk(void); // tolua_export
-
- const AString & GetLoadedWorldName() { return m_LoadedWorldName; }
-
- void UseEquippedItem(void);
-
- void SendHealth(void);
-
- // In UI windows, the item that the player is dragging:
- bool IsDraggingItem(void) const { return !m_DraggingItem.IsEmpty(); }
- cItem & GetDraggingItem(void) {return m_DraggingItem; }
-
- // In UI windows, when inventory-painting:
- /// Clears the list of slots that are being inventory-painted. To be used by cWindow only
- void ClearInventoryPaintSlots(void);
-
- /// Adds a slot to the list for inventory painting. To be used by cWindow only
- void AddInventoryPaintSlot(int a_SlotNum);
-
- /// Returns the list of slots currently stored for inventory painting. To be used by cWindow only
- const cSlotNums & GetInventoryPaintSlots(void) const;
-
- // tolua_begin
-
- /// Returns the current maximum speed, as reported in the 1.6.1+ protocol (takes current sprinting state into account)
- double GetMaxSpeed(void) const;
-
- /// Gets the normal maximum speed, as reported in the 1.6.1+ protocol, in the protocol units
- double GetNormalMaxSpeed(void) const { return m_NormalMaxSpeed; }
-
- /// Gets the sprinting maximum speed, as reported in the 1.6.1+ protocol, in the protocol units
- double GetSprintingMaxSpeed(void) const { return m_SprintingMaxSpeed; }
-
- /// Sets the normal maximum speed, as reported in the 1.6.1+ protocol. Sends the update to player, if needed.
- void SetNormalMaxSpeed(double a_Speed);
-
- /// Sets the sprinting maximum speed, as reported in the 1.6.1+ protocol. Sends the update to player, if needed.
- void SetSprintingMaxSpeed(double a_Speed);
-
- /// Sets the crouch status, broadcasts to all visible players
- void SetCrouch(bool a_IsCrouched);
-
- /// Starts or stops sprinting, sends the max speed update to the client, if needed
- void SetSprint(bool a_IsSprinting);
-
- /// Returns whether the player is swimming or not
- virtual bool IsSwimming(void) const{ return m_IsSwimming; }
-
- /// Return whether the player is under water or not
- virtual bool IsSubmerged(void) const{ return m_IsSubmerged; }
-
- // tolua_end
-
- // cEntity overrides:
- virtual bool IsCrouched (void) const { return m_IsCrouched; }
- virtual bool IsSprinting(void) const { return m_IsSprinting; }
- virtual bool IsRclking (void) const { return IsEating(); }
-
-
-
-protected:
- typedef std::map< std::string, bool > PermissionMap;
- PermissionMap m_ResolvedPermissions;
- PermissionMap m_Permissions;
-
- GroupList m_ResolvedGroups;
- GroupList m_Groups;
-
- std::string m_PlayerName;
- std::string m_LoadedWorldName;
-
- /// Xp Level stuff
- enum
- {
- XP_TO_LEVEL15 = 255,
- XP_PER_LEVEL_TO15 = 17,
- XP_TO_LEVEL30 = 825
- } ;
-
- /// Player's air level (for swimming)
- int m_AirLevel;
-
- /// used to time ticks between damage taken via drowning/suffocation
- int m_AirTickTimer;
-
- bool m_bVisible;
-
- // Food-related variables:
- /// Represents the food bar, one point equals half a "drumstick"
- int m_FoodLevel;
-
- /// "Overcharge" for the m_FoodLevel; is depleted before m_FoodLevel
- double m_FoodSaturationLevel;
-
- /// Count-up to the healing or damaging action, based on m_FoodLevel
- int m_FoodTickTimer;
-
- /// A "buffer" which adds up hunger before it is substracted from m_FoodSaturationLevel or m_FoodLevel. Each action adds a little
- double m_FoodExhaustionLevel;
-
- /// Number of ticks remaining for the foodpoisoning effect; zero if not foodpoisoned
- int m_FoodPoisonedTicksRemaining;
-
- /// Last position that has been recorded for food-related processing:
- Vector3d m_LastFoodPos;
-
- float m_LastJumpHeight;
- float m_LastGroundHeight;
- bool m_bTouchGround;
- double m_Stance;
- cInventory m_Inventory;
- cWindow * m_CurrentWindow;
- cWindow * m_InventoryWindow;
-
- float m_TimeLastPickupCheck;
-
- void ResolvePermissions();
-
- void ResolveGroups();
- char m_Color;
-
- float m_LastBlockActionTime;
- int m_LastBlockActionCnt;
- eGameMode m_GameMode;
- std::string m_IP;
-
- cItem m_DraggingItem;
-
- long long m_LastPlayerListTime;
- static const unsigned short PLAYER_LIST_TIME_MS = 1000; // 1000 = once per second
-
- cClientHandle * m_ClientHandle;
-
- cSlotNums m_InventoryPaintSlots;
-
- /// Max speed, in ENTITY_PROPERTIES packet's units, when the player is walking. 0.1 by default
- double m_NormalMaxSpeed;
-
- /// Max speed, in ENTITY_PROPERTIES packet's units, when the player is sprinting. 0.13 by default
- double m_SprintingMaxSpeed;
-
- bool m_IsCrouched;
- bool m_IsSprinting;
-
- bool m_IsSwimming;
- bool m_IsSubmerged;
-
- /// The world tick in which eating will be finished. -1 if not eating
- Int64 m_EatingFinishTick;
-
- /// Player Xp level
- int m_XpTotal;
-
- /// Caculates the Xp needed for a given level, ref: http://minecraft.gamepedia.com/XP
- static int XpForLevel(int a_Level);
-
- /// inverse of XpAtLevel, ref: http://minecraft.gamepedia.com/XP values are as per this with pre-calculations
- static int CalcLevelFromXp(int a_XpTotal);
-
- bool m_IsChargingBow;
- int m_BowCharge;
-
- virtual void Destroyed(void);
-
- /// Filters out damage for creative mode
- virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
-
- /// Called in each tick to handle food-related processing
- void HandleFood(void);
-
- /// Called in each tick to handle air-related processing i.e. drowning
- void HandleAir();
-
- /// Called once per tick to set IsSwimming and IsSubmerged
- void SetSwimState(cChunk & a_Chunk);
-
- /// Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block)
- void ApplyFoodExhaustionFromMovement();
-} ; // tolua_export
-
-
-
-
diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp
deleted file mode 100644
index c63b9523b..000000000
--- a/source/Entities/ProjectileEntity.cpp
+++ /dev/null
@@ -1,743 +0,0 @@
-
-// 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"
-#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)
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cProjectileTracerCallback:
-
-class cProjectileTracerCallback :
- public cBlockTracer::cCallbacks
-{
-public:
- cProjectileTracerCallback(cProjectileEntity * 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
- // 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:
- switch (a_BlockType)
- {
- case E_BLOCK_LAVA:
- 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)
-
- // Continue tracing
- return false;
- }
-} ;
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// 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:
-
-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);
- SetRotationFromSpeed();
- SetPitchFromSpeed();
-}
-
-
-
-
-
-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);
- 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
- }
-
- LOGWARNING("%s: Unknown projectile kind: %d", __FUNCTION__, a_Kind);
- return NULL;
-}
-
-
-
-
-
-void cProjectileEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
-{
- // 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,
- a_HitPos.x, a_HitPos.y, a_HitPos.z,
- a_HitFace
- );
-
- 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))
- {
- // 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:
- 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("Projectile %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}, rot {%.02f, %.02f}",
- m_UniqueID,
- GetPosX(), GetPosY(), GetPosZ(),
- GetSpeedX(), GetSpeedY(), GetSpeedZ(),
- GetRotation(), GetPitch()
- );
-}
-
-
-
-
-
-void cProjectileEntity::SpawnOn(cClientHandle & a_Client)
-{
- // Default spawning - use the projectile kind to spawn an object:
- a_Client.SendSpawnObject(*this, m_ProjectileKind, 12, ANGLE_TO_PROTO(GetRotation()), ANGLE_TO_PROTO(GetPitch()));
- a_Client.SendEntityMetadata(*this);
-}
-
-
-
-
-
-void cProjectileEntity::CollectedBy(cPlayer * a_Dest)
-{
- // Overriden in arrow
- UNUSED(a_Dest);
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// 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),
- m_IsCritical(false),
- m_Timer(0),
- m_bIsCollected(false),
- m_HitBlockPos(Vector3i(0, 0, 0))
-{
- SetSpeed(a_Speed);
- SetMass(0.1);
- SetRotationFromSpeed();
- SetPitchFromSpeed();
- LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}",
- m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(),
- GetRotation(), GetPitch()
- );
-}
-
-
-
-
-
-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_IsCritical((a_Force >= 1)),
- m_Timer(0),
- m_bIsCollected(false),
- m_HitBlockPos(0, 0, 0)
-{
-}
-
-
-
-
-
-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::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
-{
- if (a_HitFace == BLOCK_FACE_NONE)
- {
- return;
- }
-
- 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;
-
- if (a_HitFace != BLOCK_FACE_YP)
- {
- AddFaceDirection(a_X, a_Y, a_Z, a_HitFace);
- }
- else if (a_HitFace == BLOCK_FACE_YP) // These conditions because xoft got a little confused on block face directions, so AddFace works with all but YP & YM
- {
- a_Y--;
- }
- else
- {
- a_Y++;
- }
-
- m_HitBlockPos = Vector3i(a_X, a_Y, a_Z);
-
- // Broadcast arrow hit sound
- m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
-
- // 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() && !a_EntityHit.IsBoat())
- {
- // 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);
-
- // Broadcast successful hit sound
- m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
-
- Destroy();
-}
-
-
-
-
-
-void cArrowEntity::CollectedBy(cPlayer * a_Dest)
-{
- if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest)))
- {
- int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW);
- if (NumAdded > 0) // Only play effects if there was space in inventory
- {
- m_World->BroadcastCollectPickup((const cPickup &)*this, *a_Dest);
- // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
- m_World->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
- m_bIsCollected = true;
- }
- }
-}
-
-
-
-
-
-void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
-{
- super::Tick(a_Dt, a_Chunk);
- m_Timer += a_Dt;
-
- if (m_bIsCollected)
- {
- if (m_Timer > 500.f) // 0.5 seconds
- {
- Destroy();
- return;
- }
- }
- else if (m_Timer > 1000 * 60 * 5) // 5 minutes
- {
- Destroy();
- return;
- }
-
- if (m_IsInGround)
- {
- int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width;
- int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width;
- cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ);
-
- if (Chunk == NULL)
- {
- // Inside an unloaded chunk, abort
- return;
- }
-
- if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed?
- {
- m_IsInGround = false; // Yes, begin simulating physics again
- }
- }
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cThrownEggEntity:
-
-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)
-{
- SetSpeed(a_Speed);
-}
-
-
-
-
-
-void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
-{
- if (m_World->GetTickRandomNumber(7) == 1)
- {
- m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
- }
- else if (m_World->GetTickRandomNumber(32) == 1)
- {
- m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
- m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
- m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
- m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
- }
- Destroy();
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cThrownEnderPearlEntity :
-
-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)
-{
- SetSpeed(a_Speed);
-}
-
-
-
-
-
-void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
-{
- // 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();
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cThrownSnowballEntity :
-
-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)
-{
- SetSpeed(a_Speed);
-}
-
-
-
-
-
-void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace)
-{
- // TODO: Apply damage to certain mobs (blaze etc.) and anger all mobs
-
- Destroy();
-}
-
-
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// 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
-}
-
-
-
-
diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h
deleted file mode 100644
index 28dd76935..000000000
--- a/source/Entities/ProjectileEntity.h
+++ /dev/null
@@ -1,325 +0,0 @@
-
-// ProjectileEntity.h
-
-// Declares the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types
-
-
-
-
-
-#pragma once
-
-#include "Entity.h"
-
-
-
-
-
-// tolua_begin
-
-class cProjectileEntity :
- public cEntity
-{
- typedef cEntity super;
-
-public:
- /// The kind of the projectile. The numbers correspond to the network type ID used for spawning via the 0x17 packet.
- enum eKind
- {
- pkArrow = 60,
- pkSnowball = 61,
- pkEgg = 62,
- pkGhastFireball = 63,
- pkFireCharge = 64,
- pkEnderPearl = 65,
- pkExpBottle = 75,
- pkSplashPotion = 73,
- pkWitherSkull = 66,
- 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);
-
- 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 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) {}
-
- /// Called by Chunk when the projectile is eligible for player collection
- virtual void CollectedBy(cPlayer * a_Dest);
-
- // 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; }
-
- // 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;
-
- /// 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;
-
- // cEntity overrides:
- virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
- virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
- virtual void SpawnOn(cClientHandle & a_Client) override;
-
- // tolua_begin
-} ;
-
-
-
-
-
-class cArrowEntity :
- public cProjectileEntity
-{
- typedef cProjectileEntity super;
-
-public:
- /// 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 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;
-
- /// 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:
-
- /// 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;
-
- /// If true, the arrow deals more damage
- bool m_IsCritical;
-
- /// Timer for pickup collection animation or five minute timeout
- float m_Timer;
-
- /// If true, the arrow is in the process of being collected - don't go to anyone else
- bool m_bIsCollected;
-
- /// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air
- Vector3i m_HitBlockPos;
-
- // cProjectileEntity overrides:
- virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override;
- virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
- virtual void CollectedBy(cPlayer * a_Player) override;
- virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
-
- // tolua_begin
-} ;
-
-
-
-
-
-class cThrownEggEntity :
- public cProjectileEntity
-{
- typedef cProjectileEntity super;
-
-public:
-
- // tolua_end
-
- CLASS_PROTODEF(cThrownEggEntity);
-
- cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
-
-protected:
-
- // tolua_end
-
- // cProjectileEntity overrides:
- virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override;
-
- // tolua_begin
-
-} ;
-
-
-
-
-
-class cThrownEnderPearlEntity :
- public cProjectileEntity
-{
- typedef cProjectileEntity super;
-
-public:
-
- // tolua_end
-
- CLASS_PROTODEF(cThrownEnderPearlEntity);
-
- cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
-
-protected:
-
- // tolua_end
-
- // cProjectileEntity overrides:
- virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override;
-
- // tolua_begin
-
-} ;
-
-
-
-
-
-class cThrownSnowballEntity :
- public cProjectileEntity
-{
- typedef cProjectileEntity super;
-
-public:
-
- // tolua_end
-
- CLASS_PROTODEF(cThrownSnowballEntity);
-
- cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
-
-protected:
-
- // cProjectileEntity overrides:
- virtual void OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) override;
-
- // tolua_begin
-
-} ;
-
-
-
-
-
-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
-
-
-
diff --git a/source/Entities/TNTEntity.cpp b/source/Entities/TNTEntity.cpp
deleted file mode 100644
index 339107b2e..000000000
--- a/source/Entities/TNTEntity.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-#include "Globals.h"
-
-#include "TNTEntity.h"
-#include "../World.h"
-#include "../ClientHandle.h"
-
-
-
-
-
-cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec) :
- super(etTNT, a_X, a_Y, a_Z, 0.98, 0.98),
- m_Counter(0),
- m_MaxFuseTime(a_FuseTimeInSec)
-{
-}
-
-
-
-
-
-cTNTEntity::cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec) :
- super(etTNT, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98),
- m_Counter(0),
- m_MaxFuseTime(a_FuseTimeInSec)
-{
-}
-
-
-
-
-void cTNTEntity::SpawnOn(cClientHandle & a_ClientHandle)
-{
- a_ClientHandle.SendSpawnObject(*this, 50, 1, 0, 0); // 50 means TNT
- m_bDirtyPosition = false;
- m_bDirtySpeed = false;
- m_bDirtyOrientation = false;
- m_bDirtyHead = false;
-}
-
-
-
-
-
-void cTNTEntity::Tick(float a_Dt, cChunk & a_Chunk)
-{
- super::Tick(a_Dt, a_Chunk);
- BroadcastMovementUpdate();
- float delta_time = a_Dt / 1000; // Convert miliseconds to seconds
- m_Counter += delta_time;
- if (m_Counter > m_MaxFuseTime) // Check if we go KABOOOM
- {
- Destroy(true);
- LOGD("BOOM at {%f,%f,%f}", GetPosX(), GetPosY(), GetPosZ());
- m_World->DoExplosionAt(4.0, GetPosX() + 0.49, GetPosY() + 0.49, GetPosZ() + 0.49, true, esPrimedTNT, this);
- return;
- }
-}
-
-
-
-
diff --git a/source/Entities/TNTEntity.h b/source/Entities/TNTEntity.h
deleted file mode 100644
index eb5040e8a..000000000
--- a/source/Entities/TNTEntity.h
+++ /dev/null
@@ -1,32 +0,0 @@
-
-#pragma once
-
-#include "Entity.h"
-
-
-
-
-
-class cTNTEntity :
- public cEntity
-{
- typedef cEntity super;
-
-public:
- CLASS_PROTODEF(cTNTEntity);
-
- cTNTEntity(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec);
- cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec);
-
- // cEntity overrides:
- virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
- virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
-
-protected:
- double m_Counter; ///< How much time has elapsed since the object was created, in seconds
- double m_MaxFuseTime; ///< How long the fuse is, in seconds
-};
-
-
-
-