summaryrefslogtreecommitdiffstats
path: root/src/Entities
diff options
context:
space:
mode:
Diffstat (limited to 'src/Entities')
-rw-r--r--src/Entities/ArrowEntity.cpp16
-rw-r--r--src/Entities/ArrowEntity.h2
-rw-r--r--src/Entities/Boat.cpp4
-rw-r--r--src/Entities/CMakeLists.txt65
-rw-r--r--src/Entities/Effects.h30
-rw-r--r--src/Entities/EnderCrystal.cpp4
-rw-r--r--src/Entities/EnderCrystal.h2
-rw-r--r--src/Entities/Entity.cpp127
-rw-r--r--src/Entities/Entity.h17
-rw-r--r--src/Entities/EntityEffect.cpp287
-rw-r--r--src/Entities/EntityEffect.h476
-rw-r--r--src/Entities/ExpBottleEntity.h2
-rw-r--r--src/Entities/ExpOrb.cpp10
-rw-r--r--src/Entities/FireChargeEntity.h2
-rw-r--r--src/Entities/FireworkEntity.h2
-rw-r--r--src/Entities/Floater.cpp18
-rw-r--r--src/Entities/Floater.h4
-rw-r--r--src/Entities/GhastFireballEntity.h2
-rw-r--r--src/Entities/HangingEntity.cpp6
-rw-r--r--src/Entities/ItemFrame.cpp10
-rw-r--r--src/Entities/ItemFrame.h2
-rw-r--r--src/Entities/Minecart.cpp114
-rw-r--r--src/Entities/Minecart.h13
-rw-r--r--src/Entities/Painting.h8
-rw-r--r--src/Entities/Pawn.cpp100
-rw-r--r--src/Entities/Pawn.h28
-rw-r--r--src/Entities/Pickup.cpp16
-rw-r--r--src/Entities/Pickup.h6
-rw-r--r--src/Entities/Player.cpp271
-rw-r--r--src/Entities/Player.h53
-rw-r--r--src/Entities/ProjectileEntity.cpp18
-rw-r--r--src/Entities/ProjectileEntity.h6
-rw-r--r--src/Entities/SplashPotionEntity.cpp133
-rw-r--r--src/Entities/SplashPotionEntity.h81
-rw-r--r--src/Entities/TNTEntity.cpp2
-rw-r--r--src/Entities/TNTEntity.h2
-rw-r--r--src/Entities/ThrownEggEntity.h2
-rw-r--r--src/Entities/ThrownEnderPearlEntity.h2
-rw-r--r--src/Entities/ThrownSnowballEntity.h2
-rw-r--r--src/Entities/WitherSkullEntity.cpp49
-rw-r--r--src/Entities/WitherSkullEntity.h35
41 files changed, 1606 insertions, 423 deletions
diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp
index a3a1667e4..913519c4c 100644
--- a/src/Entities/ArrowEntity.cpp
+++ b/src/Entities/ArrowEntity.cpp
@@ -72,15 +72,15 @@ bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
-{
+{
if (GetSpeed().EqualsEps(Vector3d(0, 0, 0), 0.0000001))
{
- SetSpeed(GetLookVector().NormalizeCopy() * 0.1); // Ensure that no division by zero happens later
+ SetSpeed(GetLookVector().NormalizeCopy() * 0.1); // Ensure that no division by zero happens later
}
Vector3d Hit = a_HitPos;
Vector3d SinkMovement = (GetSpeed() / 1000);
- Hit += SinkMovement * (0.0005 / SinkMovement.Length()); // Make arrow sink into block a centimetre so it lodges (but not to far so it goes black clientside)
+ Hit += SinkMovement * (0.0005 / SinkMovement.Length()); // Make arrow sink into block a centimetre so it lodges (but not to far so it goes black clientside)
super::OnHitSolidBlock(Hit, a_HitFace);
Vector3i BlockHit = Hit.Floor();
@@ -97,7 +97,7 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFa
void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
-{
+{
int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5);
if (m_IsCritical)
{
@@ -166,9 +166,9 @@ void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
// We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync
// Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position
- if (!m_HasTeleported) // Sent a teleport already, don't do again
+ if (!m_HasTeleported) // Sent a teleport already, don't do again
{
- if (m_HitGroundTimer > 500.f) // Send after half a second, could be less, but just in case
+ if (m_HitGroundTimer > 500.f) // Send after half a second, could be less, but just in case
{
m_World->BroadcastTeleportEntity(*this);
m_HasTeleported = true;
@@ -189,9 +189,9 @@ void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
return;
}
- if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed?
+ if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed?
{
- m_IsInGround = false; // Yes, begin simulating physics again
+ m_IsInGround = false; // Yes, begin simulating physics again
}
}
}
diff --git a/src/Entities/ArrowEntity.h b/src/Entities/ArrowEntity.h
index 76cb24449..ad93dba6c 100644
--- a/src/Entities/ArrowEntity.h
+++ b/src/Entities/ArrowEntity.h
@@ -99,4 +99,4 @@ protected:
virtual void CollectedBy(cPlayer * a_Player) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
-}; // tolua_export
+}; // tolua_export
diff --git a/src/Entities/Boat.cpp b/src/Entities/Boat.cpp
index 31bfe3dc3..8ff8866a1 100644
--- a/src/Entities/Boat.cpp
+++ b/src/Entities/Boat.cpp
@@ -94,7 +94,7 @@ void cBoat::Tick(float a_Dt, cChunk & a_Chunk)
super::Tick(a_Dt, a_Chunk);
BroadcastMovementUpdate();
- SetSpeed(GetSpeed() * 0.97); // Slowly decrease the speed
+ SetSpeed(GetSpeed() * 0.97); // Slowly decrease the speed
if ((POSY_TOINT < 0) || (POSY_TOINT > cChunkDef::Height))
{
@@ -104,7 +104,7 @@ void cBoat::Tick(float a_Dt, cChunk & a_Chunk)
if (IsBlockWater(m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT)))
{
if (GetSpeedY() < 2)
- {
+ {
AddSpeedY(0.2);
}
}
diff --git a/src/Entities/CMakeLists.txt b/src/Entities/CMakeLists.txt
index 205cb2cca..5d10e1680 100644
--- a/src/Entities/CMakeLists.txt
+++ b/src/Entities/CMakeLists.txt
@@ -4,11 +4,64 @@ project (MCServer)
include_directories ("${PROJECT_SOURCE_DIR}/../")
-file(GLOB SOURCE
- "*.cpp"
- "*.h"
-)
+SET (SRCS
+ ArrowEntity.cpp
+ Boat.cpp
+ EnderCrystal.cpp
+ Entity.cpp
+ EntityEffect.cpp
+ ExpBottleEntity.cpp
+ ExpOrb.cpp
+ FallingBlock.cpp
+ FireChargeEntity.cpp
+ FireworkEntity.cpp
+ Floater.cpp
+ GhastFireballEntity.cpp
+ HangingEntity.cpp
+ ItemFrame.cpp
+ Minecart.cpp
+ Painting.cpp
+ Pawn.cpp
+ Pickup.cpp
+ Player.cpp
+ ProjectileEntity.cpp
+ SplashPotionEntity.cpp
+ TNTEntity.cpp
+ ThrownEggEntity.cpp
+ ThrownEnderPearlEntity.cpp
+ ThrownSnowballEntity.cpp
+ WitherSkullEntity.cpp)
-add_library(Entities ${SOURCE})
+SET (HDRS
+ ArrowEntity.h
+ Boat.h
+ EnderCrystal.h
+ Entity.h
+ EntityEffect.h
+ ExpBottleEntity.h
+ ExpOrb.h
+ FallingBlock.h
+ FireChargeEntity.h
+ FireworkEntity.h
+ Floater.h
+ GhastFireballEntity.h
+ HangingEntity.h
+ ItemFrame.h
+ Minecart.h
+ Painting.h
+ Pawn.h
+ Pickup.h
+ Player.h
+ ProjectileEntity.h
+ SplashPotionEntity.h
+ TNTEntity.h
+ ThrownEggEntity.h
+ ThrownEnderPearlEntity.h
+ ThrownSnowballEntity.h
+ WitherSkullEntity.h)
-target_link_libraries(Entities WorldStorage)
+if(NOT MSVC)
+ add_library(Entities ${SRCS} ${HDRS})
+
+ target_link_libraries(Entities WorldStorage)
+endif()
diff --git a/src/Entities/Effects.h b/src/Entities/Effects.h
deleted file mode 100644
index baf3302fb..000000000
--- a/src/Entities/Effects.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#pragma once
-
-// tolua_begin
-enum ENUM_ENTITY_EFFECT
-{
- E_EFFECT_SPEED = 1,
- E_EFFECT_SLOWNESS = 2,
- E_EFFECT_HASTE = 3,
- E_EFFECT_MINING_FATIGUE = 4,
- E_EFFECT_STENGTH = 5,
- E_EFFECT_INSTANT_HEALTH = 6,
- E_EFFECT_INSTANT_DAMAGE = 7,
- E_EFFECT_JUMP_BOOST = 8,
- E_EFFECT_NAUSEA = 9,
- E_EFFECT_REGENERATION = 10,
- E_EFFECT_RESISTANCE = 11,
- E_EFFECT_FIRE_RESISTANCE = 12,
- E_EFFECT_WATER_BREATHING = 13,
- E_EFFECT_INVISIBILITY = 14,
- E_EFFECT_BLINDNESS = 15,
- E_EFFECT_NIGHT_VISION = 16,
- E_EFFECT_HUNGER = 17,
- E_EFFECT_WEAKNESS = 18,
- E_EFFECT_POISON = 19,
- E_EFFECT_WITHER = 20,
- E_EFFECT_HEALTH_BOOST = 21,
- E_EFFECT_ABSORPTION = 22,
- E_EFFECT_SATURATION = 23,
-} ;
-// tolua_end
diff --git a/src/Entities/EnderCrystal.cpp b/src/Entities/EnderCrystal.cpp
index a640b236c..bf86a6c42 100644
--- a/src/Entities/EnderCrystal.cpp
+++ b/src/Entities/EnderCrystal.cpp
@@ -42,9 +42,9 @@ void cEnderCrystal::Tick(float a_Dt, cChunk & a_Chunk)
-void cEnderCrystal::KilledBy(cEntity * a_Killer)
+void cEnderCrystal::KilledBy(TakeDamageInfo & a_TDI)
{
- super::KilledBy(a_Killer);
+ super::KilledBy(a_TDI);
m_World->DoExplosionAt(6.0, GetPosX(), GetPosY(), GetPosZ(), true, esEnderCrystal, this);
diff --git a/src/Entities/EnderCrystal.h b/src/Entities/EnderCrystal.h
index 5b86df987..30211de13 100644
--- a/src/Entities/EnderCrystal.h
+++ b/src/Entities/EnderCrystal.h
@@ -24,7 +24,7 @@ private:
// cEntity overrides:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
- virtual void KilledBy(cEntity * a_Killer) override;
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override;
}; // tolua_export
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 26823924f..db0fd0fd6 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -49,6 +49,7 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d
, m_IsSubmerged(false)
, m_AirLevel(0)
, m_AirTickTimer(0)
+ , m_TicksAlive(0)
, m_HeadYaw(0.0)
, m_Rot(0.0, 0.0, 0.0)
, m_Pos(a_X, a_Y, a_Z)
@@ -74,7 +75,7 @@ cEntity::~cEntity()
/*
// DEBUG:
- LOGD("Deleting entity %d at pos {%.2f, %.2f, %.2f} ~ [%d, %d]; ptr %p",
+ 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),
@@ -272,7 +273,7 @@ void cEntity::SetYawFromSpeed(void)
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
+ 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
@@ -310,10 +311,14 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
cPlayer * Player = (cPlayer *)a_TDI.Attacker;
// IsOnGround() only is false if the player is moving downwards
- if (!Player->IsOnGround()) // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain)
+ // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain)
+ if (!Player->IsOnGround())
{
- a_TDI.FinalDamage += 2;
- m_World->BroadcastEntityAnimation(*this, 4); // Critical hit
+ if ((a_TDI.DamageType == dtAttack) || (a_TDI.DamageType == dtArrowAttack))
+ {
+ a_TDI.FinalDamage += 2;
+ m_World->BroadcastEntityAnimation(*this, 4); // Critical hit
+ }
}
Player->GetStatManager().AddValue(statDamageDealt, (StatValue)floor(a_TDI.FinalDamage * 10 + 0.5));
@@ -323,43 +328,25 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
// TODO: Apply damage to armor
- if (m_Health < 0)
- {
- m_Health = 0;
- }
+ m_Health = std::max(m_Health, 0);
- if ((IsMob() || IsPlayer()) && (a_TDI.Attacker != NULL)) // Knockback for only players and mobs
+ if ((IsMob() || IsPlayer()) && (a_TDI.Attacker != NULL)) // Knockback for only players and mobs
{
- int KnockbackLevel = 0;
- if (a_TDI.Attacker->GetEquippedWeapon().m_ItemType == E_ITEM_BOW)
+ int KnockbackLevel = a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchKnockback); // More common enchantment
+ if (KnockbackLevel < 1)
{
+ // We support punch on swords and vice versa! :)
KnockbackLevel = a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchPunch);
}
- else
- {
- KnockbackLevel = a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchKnockback);
- }
- Vector3d additionalSpeed(0, 0, 0);
+ Vector3d AdditionalSpeed(0, 0, 0);
switch (KnockbackLevel)
{
- case 1:
- {
- additionalSpeed.Set(5, .3, 5);
- break;
- }
- case 2:
- {
- additionalSpeed.Set(8, .3, 8);
- break;
- }
- default:
- {
- additionalSpeed.Set(2, .3, 2);
- break;
- }
+ case 1: AdditionalSpeed.Set(5, 0.3, 5); break;
+ case 2: AdditionalSpeed.Set(8, 0.3, 8); break;
+ default: break;
}
- AddSpeed(a_TDI.Knockback * additionalSpeed);
+ AddSpeed(a_TDI.Knockback + AdditionalSpeed);
}
m_World->BroadcastEntityStatus(*this, esGenericHurt);
@@ -368,7 +355,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
if (m_Health <= 0)
{
- KilledBy(a_TDI.Attacker);
+ KilledBy(a_TDI);
if (a_TDI.Attacker != NULL)
{
@@ -431,6 +418,7 @@ bool cEntity::ArmorCoversAgainst(eDamageType a_DamageType)
case dtStarving:
case dtInVoid:
case dtPoisoning:
+ case dtWithering:
case dtPotionOfHarming:
case dtFalling:
case dtLightning:
@@ -524,11 +512,11 @@ double cEntity::GetKnockbackAmountAgainst(const cEntity & a_Receiver)
-void cEntity::KilledBy(cEntity * a_Killer)
+void cEntity::KilledBy(TakeDamageInfo & a_TDI)
{
m_Health = 0;
- cRoot::Get()->GetPluginManager()->CallHookKilling(*this, a_Killer);
+ cRoot::Get()->GetPluginManager()->CallHookKilling(*this, a_TDI.Attacker, a_TDI);
if (m_Health > 0)
{
@@ -538,7 +526,7 @@ void cEntity::KilledBy(cEntity * a_Killer)
// Drop loot:
cItems Drops;
- GetDrops(Drops, a_Killer);
+ GetDrops(Drops, a_TDI.Attacker);
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
m_World->BroadcastEntityStatus(*this, esGenericDead);
@@ -572,6 +560,8 @@ void cEntity::SetHealth(int a_Health)
void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
+ m_TicksAlive++;
+
if (m_InvulnerableTicks > 0)
{
m_InvulnerableTicks--;
@@ -650,7 +640,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
if ((BlockY >= cChunkDef::Height) || (BlockY < 0))
{
- // Outside of the world
+ // Outside of the world
AddSpeedY(m_Gravity * a_Dt);
AddPosition(GetSpeed() * a_Dt);
return;
@@ -658,7 +648,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width);
int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width);
- BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ );
+ BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ);
BLOCKTYPE BlockBelow = (BlockY > 0) ? NextChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
if (!cBlockInfo::IsSolid(BlockIn)) // Making sure we are not inside a solid block
{
@@ -762,13 +752,13 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
NextSpeed.x *= 0.25;
NextSpeed.z *= 0.25;
}
-
- //Get water direction
+
+ // Get water direction
Direction WaterDir = m_World->GetWaterSimulator()->GetFlowingDirection(BlockX, BlockY, BlockZ);
- m_WaterSpeed *= 0.9f; //Reduce speed each tick
+ m_WaterSpeed *= 0.9f; // Reduce speed each tick
- switch(WaterDir)
+ switch (WaterDir)
{
case X_PLUS:
m_WaterSpeed.x = 0.2f;
@@ -823,7 +813,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
if (Tracer.HitNormal.y != 0.f) NextSpeed.y = 0.f;
if (Tracer.HitNormal.z != 0.f) NextSpeed.z = 0.f;
- if (Tracer.HitNormal.y == 1) // Hit BLOCK_FACE_YP, we are on the ground
+ if (Tracer.HitNormal.y == 1) // Hit BLOCK_FACE_YP, we are on the ground
{
m_bOnGround = true;
}
@@ -868,7 +858,7 @@ void cEntity::TickBurning(cChunk & a_Chunk)
if (POSY_TOINT > m_World->GetHeight(POSX_TOINT, POSZ_TOINT))
{
m_TicksLeftBurning = 0;
- }
+ }
}
// Do the burning damage:
@@ -1090,9 +1080,9 @@ void cEntity::HandleAir(void)
if (IsSubmerged())
{
- if (!IsPlayer()) // Players control themselves
+ if (!IsPlayer()) // Players control themselves
{
- SetSpeedY(1); // Float in the water
+ SetSpeedY(1); // Float in the water
}
// Either reduce air level or damage player
@@ -1100,7 +1090,7 @@ void cEntity::HandleAir(void)
{
if (m_AirTickTimer < 1)
{
- // Damage player
+ // Damage player
TakeDamage(dtDrowning, NULL, 1, 1, 0);
// Reset timer
m_AirTickTimer = DROWNING_TICKS;
@@ -1156,10 +1146,7 @@ void cEntity::SetMaxHealth(int a_MaxHealth)
m_MaxHealth = a_MaxHealth;
// Reset health, if too high:
- if (m_Health > a_MaxHealth)
- {
- m_Health = a_MaxHealth;
- }
+ m_Health = std::min(m_Health, a_MaxHealth);
}
@@ -1261,9 +1248,9 @@ void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
int DiffY = (int)(floor(GetPosY() * 32.0) - floor(m_LastPos.y * 32.0));
int DiffZ = (int)(floor(GetPosZ() * 32.0) - floor(m_LastPos.z * 32.0));
- if ((DiffX != 0) || (DiffY != 0) || (DiffZ != 0)) // Have we moved?
+ if ((DiffX != 0) || (DiffY != 0) || (DiffZ != 0)) // Have we moved?
{
- if ((abs(DiffX) <= 127) && (abs(DiffY) <= 127) && (abs(DiffZ) <= 127)) // Limitations of a Byte
+ if ((abs(DiffX) <= 127) && (abs(DiffY) <= 127) && (abs(DiffZ) <= 127)) // Limitations of a Byte
{
// Difference within Byte limitations, use a relative move packet
if (m_bDirtyOrientation)
@@ -1283,7 +1270,7 @@ void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
{
// Too big a movement, do a teleport
m_World->BroadcastTeleportEntity(*this, a_Exclude);
- m_LastPos = GetPosition(); // See above
+ m_LastPos = GetPosition(); // See above
m_bDirtyOrientation = false;
}
}
@@ -1392,8 +1379,8 @@ void cEntity::SetMass(double a_Mass)
}
else
{
- // Make sure that mass is not zero. 1g is the default because we
- // have to choose a number. It's perfectly legal to have a mass
+ // 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;
}
@@ -1479,7 +1466,7 @@ void cEntity::SetWidth(double a_Width)
void cEntity::AddPosX(double a_AddPosX)
{
- m_Pos.x += a_AddPosX;
+ m_Pos.x += a_AddPosX;
}
@@ -1487,7 +1474,7 @@ void cEntity::AddPosX(double a_AddPosX)
void cEntity::AddPosY(double a_AddPosY)
{
- m_Pos.y += a_AddPosY;
+ m_Pos.y += a_AddPosY;
}
@@ -1495,7 +1482,7 @@ void cEntity::AddPosY(double a_AddPosY)
void cEntity::AddPosZ(double a_AddPosZ)
{
- m_Pos.z += a_AddPosZ;
+ m_Pos.z += a_AddPosZ;
}
@@ -1505,7 +1492,7 @@ 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_Pos.z += a_AddPosZ;
}
@@ -1515,7 +1502,7 @@ void cEntity::AddSpeed(double a_AddSpeedX, double a_AddSpeedY, double a_AddSpeed
{
m_Speed.x += a_AddSpeedX;
m_Speed.y += a_AddSpeedY;
- m_Speed.z += a_AddSpeedZ;
+ m_Speed.z += a_AddSpeedZ;
WrapSpeed();
}
@@ -1525,7 +1512,7 @@ void cEntity::AddSpeed(double a_AddSpeedX, double a_AddSpeedY, double a_AddSpeed
void cEntity::AddSpeedX(double a_AddSpeedX)
{
- m_Speed.x += a_AddSpeedX;
+ m_Speed.x += a_AddSpeedX;
WrapSpeed();
}
@@ -1535,7 +1522,7 @@ void cEntity::AddSpeedX(double a_AddSpeedX)
void cEntity::AddSpeedY(double a_AddSpeedY)
{
- m_Speed.y += a_AddSpeedY;
+ m_Speed.y += a_AddSpeedY;
WrapSpeed();
}
@@ -1545,7 +1532,7 @@ void cEntity::AddSpeedY(double a_AddSpeedY)
void cEntity::AddSpeedZ(double a_AddSpeedZ)
{
- m_Speed.z += a_AddSpeedZ;
+ m_Speed.z += a_AddSpeedZ;
WrapSpeed();
}
@@ -1582,7 +1569,7 @@ void cEntity::SteerVehicle(float a_Forward, float a_Sideways)
-//////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
// Get look vector (this is NOT a rotation!)
Vector3d cEntity::GetLookVector(void) const
{
@@ -1596,11 +1583,11 @@ Vector3d cEntity::GetLookVector(void) const
-//////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
// Set position
void cEntity::SetPosition(double a_PosX, double a_PosY, double a_PosZ)
{
- m_Pos.Set(a_PosX, a_PosY, a_PosZ);
+ m_Pos.Set(a_PosX, a_PosY, a_PosZ);
}
@@ -1609,7 +1596,7 @@ void cEntity::SetPosition(double a_PosX, double a_PosY, double a_PosZ)
void cEntity::SetPosX(double a_PosX)
{
- m_Pos.x = a_PosX;
+ m_Pos.x = a_PosX;
}
@@ -1618,7 +1605,7 @@ void cEntity::SetPosX(double a_PosX)
void cEntity::SetPosY(double a_PosY)
{
- m_Pos.y = a_PosY;
+ m_Pos.y = a_PosY;
}
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index f4080f8aa..83fe76e7e 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -158,6 +158,7 @@ public:
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 IsPawn (void) const { return (IsMob() || IsPlayer()); }
bool IsFallingBlock(void) const { return (m_EntityType == etFallingBlock); }
bool IsMinecart (void) const { return (m_EntityType == etMinecart); }
bool IsBoat (void) const { return (m_EntityType == etBoat); }
@@ -309,13 +310,13 @@ public:
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);
+ virtual void KilledBy(TakeDamageInfo & a_TDI);
/// Called when the entity kills another entity
virtual void Killed(cEntity * a_Victim) {}
/// Heals the specified amount of HPs
- void Heal(int a_HitPoints);
+ virtual void Heal(int a_HitPoints);
/// Returns the health of this entity
int GetHealth(void) const { return m_Health; }
@@ -415,6 +416,9 @@ public:
/** Gets remaining air of a monster */
int GetAirLevel(void) const { return m_AirLevel; }
+ /** Gets number of ticks this entity has existed for */
+ long int GetTicksAlive(void) const { return m_TicksAlive; }
+
/** Gets the invulnerable ticks from the entity */
int GetInvulnerableTicks(void) const { return m_InvulnerableTicks; }
@@ -427,7 +431,7 @@ public:
virtual void OnRightClicked(cPlayer &) {};
/// 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)
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL)
{
UNUSED(a_Drops);
UNUSED(a_Killer);
@@ -484,7 +488,7 @@ protected:
/// Whether the entity is capable of taking fire or lava damage.
bool m_IsFireproof;
-
+
/// Time, in ticks, since the last damage dealt by being on fire. Valid only if on fire (IsOnFire())
int m_TicksSinceLastBurnDamage;
@@ -505,7 +509,7 @@ protected:
overrides can provide further processing, such as forcing players to move at the given speed. */
virtual void DoSetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ);
- virtual void Destroyed(void) {} // Called after the entity has been destroyed
+ virtual void Destroyed(void) {} // Called after the entity has been destroyed
/** Called in each tick to handle air-related processing i.e. drowning */
virtual void HandleAir(void);
@@ -520,6 +524,9 @@ protected:
int m_AirLevel;
int m_AirTickTimer;
+ /** The number of ticks this entity has been alive for */
+ long int m_TicksAlive;
+
private:
/** Measured in degrees, [-180, +180) */
double m_HeadYaw;
diff --git a/src/Entities/EntityEffect.cpp b/src/Entities/EntityEffect.cpp
new file mode 100644
index 000000000..6c4b13a58
--- /dev/null
+++ b/src/Entities/EntityEffect.cpp
@@ -0,0 +1,287 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "EntityEffect.h"
+#include "../Mobs/Monster.h"
+#include "Player.h"
+
+
+
+
+cEntityEffect::cEntityEffect():
+ m_Ticks(0),
+ m_Duration(0),
+ m_Intensity(0),
+ m_DistanceModifier(1)
+{
+
+}
+
+
+
+
+
+cEntityEffect::cEntityEffect(int a_Duration, short a_Intensity, double a_DistanceModifier):
+ m_Ticks(0),
+ m_Duration(a_Duration),
+ m_Intensity(a_Intensity),
+ m_DistanceModifier(a_DistanceModifier)
+{
+
+}
+
+
+
+
+
+cEntityEffect::cEntityEffect(const cEntityEffect & a_OtherEffect):
+ m_Ticks(a_OtherEffect.m_Ticks),
+ m_Duration(a_OtherEffect.m_Duration),
+ m_Intensity(a_OtherEffect.m_Intensity),
+ m_DistanceModifier(a_OtherEffect.m_DistanceModifier)
+{
+
+}
+
+
+
+
+
+cEntityEffect & cEntityEffect::operator=(cEntityEffect a_OtherEffect)
+{
+ std::swap(m_Ticks, a_OtherEffect.m_Ticks);
+ std::swap(m_Duration, a_OtherEffect.m_Duration);
+ std::swap(m_Intensity, a_OtherEffect.m_Intensity);
+ std::swap(m_DistanceModifier, a_OtherEffect.m_DistanceModifier);
+ return *this;
+}
+
+
+
+
+
+cEntityEffect * cEntityEffect::CreateEntityEffect(cEntityEffect::eType a_EffectType, int a_Duration, short a_Intensity, double a_DistanceModifier)
+{
+ switch (a_EffectType)
+ {
+ case cEntityEffect::effNoEffect: return new cEntityEffect (a_Duration, a_Intensity, a_DistanceModifier);
+
+ case cEntityEffect::effAbsorption: return new cEntityEffectAbsorption (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effBlindness: return new cEntityEffectBlindness (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effFireResistance: return new cEntityEffectFireResistance(a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effHaste: return new cEntityEffectHaste (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effHealthBoost: return new cEntityEffectHealthBoost (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effHunger: return new cEntityEffectHunger (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effInstantDamage: return new cEntityEffectInstantDamage (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effInstantHealth: return new cEntityEffectInstantHealth (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effInvisibility: return new cEntityEffectInvisibility (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effJumpBoost: return new cEntityEffectJumpBoost (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effMiningFatigue: return new cEntityEffectMiningFatigue (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effNausea: return new cEntityEffectNausea (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effNightVision: return new cEntityEffectNightVision (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effPoison: return new cEntityEffectPoison (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effRegeneration: return new cEntityEffectRegeneration (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effResistance: return new cEntityEffectResistance (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effSaturation: return new cEntityEffectSaturation (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effSlowness: return new cEntityEffectSlowness (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effSpeed: return new cEntityEffectSpeed (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effStrength: return new cEntityEffectStrength (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effWaterBreathing: return new cEntityEffectWaterBreathing(a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effWeakness: return new cEntityEffectWeakness (a_Duration, a_Intensity, a_DistanceModifier);
+ case cEntityEffect::effWither: return new cEntityEffectWither (a_Duration, a_Intensity, a_DistanceModifier);
+ }
+
+ ASSERT(!"Unhandled entity effect type!");
+ return NULL;
+}
+
+
+
+
+
+void cEntityEffect::OnTick(cPawn & a_Target)
+{
+ // Reduce the effect's duration
+ ++m_Ticks;
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cEntityEffectInstantHealth:
+
+void cEntityEffectInstantHealth::OnActivate(cPawn & a_Target)
+{
+ // Base amount = 6, doubles for every increase in intensity
+ int amount = (int)(6 * (1 << m_Intensity) * m_DistanceModifier);
+
+ if (a_Target.IsMob() && ((cMonster &) a_Target).IsUndead())
+ {
+ a_Target.TakeDamage(dtPotionOfHarming, NULL, amount, 0); // TODO: Store attacker in a pointer-safe way, pass to TakeDamage
+ return;
+ }
+ a_Target.Heal(amount);
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cEntityEffectInstantDamage:
+
+void cEntityEffectInstantDamage::OnActivate(cPawn & a_Target)
+{
+ // Base amount = 6, doubles for every increase in intensity
+ int amount = (int)(6 * (1 << m_Intensity) * m_DistanceModifier);
+
+ if (a_Target.IsMob() && ((cMonster &) a_Target).IsUndead())
+ {
+ a_Target.Heal(amount);
+ return;
+ }
+ a_Target.TakeDamage(dtPotionOfHarming, NULL, amount, 0); // TODO: Store attacker in a pointer-safe way, pass to TakeDamage
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cEntityEffectRegeneration:
+
+void cEntityEffectRegeneration::OnTick(cPawn & a_Target)
+{
+ super::OnTick(a_Target);
+
+ if (a_Target.IsMob() && ((cMonster &) a_Target).IsUndead())
+ {
+ return;
+ }
+
+ // Regen frequency = 50 ticks, divided by potion level (Regen II = 25 ticks)
+ int frequency = (int) std::floor(50.0 / (double)(m_Intensity + 1));
+
+ if ((m_Ticks % frequency) != 0)
+ {
+ return;
+ }
+
+ a_Target.Heal(1);
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cEntityEffectHunger:
+
+void cEntityEffectHunger::OnTick(cPawn & a_Target)
+{
+ super::OnTick(a_Target);
+
+ if (a_Target.IsPlayer())
+ {
+ cPlayer & Target = (cPlayer &) a_Target;
+ Target.SetFoodExhaustionLevel(Target.GetFoodExhaustionLevel() + 0.025); // 0.5 per second = 0.025 per tick
+ }
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cEntityEffectWeakness:
+
+void cEntityEffectWeakness::OnTick(cPawn & a_Target)
+{
+ super::OnTick(a_Target);
+
+ // Damage reduction = 0.5 damage, multiplied by potion level (Weakness II = 1 damage)
+ // double dmg_reduc = 0.5 * (a_Effect.GetIntensity() + 1);
+
+ // TODO: Implement me!
+ // TODO: Weakened villager zombies can be turned back to villagers with the god apple
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cEntityEffectPoison:
+
+void cEntityEffectPoison::OnTick(cPawn & a_Target)
+{
+ super::OnTick(a_Target);
+
+ if (a_Target.IsMob())
+ {
+ cMonster & Target = (cMonster &) a_Target;
+
+ // Doesn't effect undead mobs, spiders
+ if (
+ Target.IsUndead() ||
+ (Target.GetMobType() == cMonster::mtSpider) ||
+ (Target.GetMobType() == cMonster::mtCaveSpider)
+ )
+ {
+ return;
+ }
+ }
+
+ // Poison frequency = 25 ticks, divided by potion level (Poison II = 12 ticks)
+ int frequency = (int) std::floor(25.0 / (double)(m_Intensity + 1));
+
+ if ((m_Ticks % frequency) == 0)
+ {
+ // Cannot take poison damage when health is at 1
+ if (a_Target.GetHealth() > 1)
+ {
+ a_Target.TakeDamage(dtPoisoning, NULL, 1, 0);
+ }
+ }
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cEntityEffectWither:
+
+void cEntityEffectWither::OnTick(cPawn & a_Target)
+{
+ super::OnTick(a_Target);
+
+ // Damage frequency = 40 ticks, divided by effect level (Wither II = 20 ticks)
+ int frequency = (int) std::floor(25.0 / (double)(m_Intensity + 1));
+
+ if ((m_Ticks % frequency) == 0)
+ {
+ a_Target.TakeDamage(dtWither, NULL, 1, 0);
+ }
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cEntityEffectSaturation:
+
+void cEntityEffectSaturation::OnTick(cPawn & a_Target)
+{
+ if (a_Target.IsPlayer())
+ {
+ cPlayer & Target = (cPlayer &) a_Target;
+ Target.SetFoodSaturationLevel(Target.GetFoodSaturationLevel() + (1 + m_Intensity)); // Increase saturation 1 per tick, adds 1 for every increase in level
+ }
+}
+
+
+
+
diff --git a/src/Entities/EntityEffect.h b/src/Entities/EntityEffect.h
new file mode 100644
index 000000000..ebd611ff0
--- /dev/null
+++ b/src/Entities/EntityEffect.h
@@ -0,0 +1,476 @@
+#pragma once
+
+class cPawn;
+
+// tolua_begin
+class cEntityEffect
+{
+public:
+
+ /** All types of entity effects (numbers correspond to protocol / storage types) */
+ enum eType
+ {
+ effNoEffect = 0,
+ effSpeed = 1,
+ effSlowness = 2,
+ effHaste = 3,
+ effMiningFatigue = 4,
+ effStrength = 5,
+ effInstantHealth = 6,
+ effInstantDamage = 7,
+ effJumpBoost = 8,
+ effNausea = 9,
+ effRegeneration = 10,
+ effResistance = 11,
+ effFireResistance = 12,
+ effWaterBreathing = 13,
+ effInvisibility = 14,
+ effBlindness = 15,
+ effNightVision = 16,
+ effHunger = 17,
+ effWeakness = 18,
+ effPoison = 19,
+ effWither = 20,
+ effHealthBoost = 21,
+ effAbsorption = 22,
+ effSaturation = 23,
+ } ;
+
+ // tolua_end
+
+ /** Creates an empty entity effect */
+ cEntityEffect(void);
+
+ /** Creates an entity effect of the specified type
+ @param a_Duration How long this effect will last, in ticks
+ @param a_Intensity How strong the effect will be applied
+ @param a_DistanceModifier The distance modifier for affecting potency, defaults to 1 */
+ cEntityEffect(int a_Duration, short a_Intensity, double a_DistanceModifier = 1);
+
+ /** Creates an entity effect by copying another
+ @param a_OtherEffect The other effect to copy */
+ cEntityEffect(const cEntityEffect & a_OtherEffect);
+
+ /** Creates an entity effect by copying another
+ @param a_OtherEffect The other effect to copy */
+ cEntityEffect & operator=(cEntityEffect a_OtherEffect);
+
+ virtual ~cEntityEffect(void) {};
+
+ /** Creates a pointer to the proper entity effect from the effect type
+ @warning This function creates raw pointers that must be manually managed.
+ @param a_EffectType The effect type to create the effect from
+ @param a_Duration How long this effect will last, in ticks
+ @param a_Intensity How strong the effect will be applied
+ @param a_DistanceModifier The distance modifier for affecting potency, defaults to 1 */
+ static cEntityEffect * CreateEntityEffect(cEntityEffect::eType a_EffectType, int a_Duration, short a_Intensity, double a_DistanceModifier);
+
+ /** Returns how many ticks this effect has been active for */
+ int GetTicks(void) const { return m_Ticks; }
+
+ /** Returns the duration of the effect */
+ int GetDuration(void) const { return m_Duration; }
+
+ /** Returns how strong the effect will be applied */
+ short GetIntensity(void) const { return m_Intensity; }
+
+ /** Returns the distance modifier for affecting potency */
+ double GetDistanceModifier(void) const { return m_DistanceModifier; }
+
+ void SetTicks(int a_Ticks) { m_Ticks = a_Ticks; }
+ void SetDuration(int a_Duration) { m_Duration = a_Duration; }
+ void SetIntensity(short a_Intensity) { m_Intensity = a_Intensity; }
+ void SetDistanceModifier(double a_DistanceModifier) { m_DistanceModifier = a_DistanceModifier; }
+
+ /** Called on each tick.
+ By default increases the m_Ticks, descendants may override to provide additional processing. */
+ virtual void OnTick(cPawn & a_Target);
+
+ /** Called when the effect is first added to an entity */
+ virtual void OnActivate(cPawn & a_Target) { }
+
+ /** Called when the effect is removed from an entity */
+ virtual void OnDeactivate(cPawn & a_Target) { }
+
+protected:
+ /** How many ticks this effect has been active for */
+ int m_Ticks;
+
+ /** How long this effect will last, in ticks */
+ int m_Duration;
+
+ /** How strong the effect will be applied */
+ short m_Intensity;
+
+ /** The distance modifier for affecting potency */
+ double m_DistanceModifier;
+}; // tolua_export
+
+
+
+
+
+class cEntityEffectSpeed:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectSpeed(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+};
+
+
+
+
+
+class cEntityEffectSlowness:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectSlowness(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+};
+
+
+
+
+
+class cEntityEffectHaste:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectHaste(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+};
+
+
+
+
+
+class cEntityEffectMiningFatigue:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectMiningFatigue(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+};
+
+
+
+
+
+class cEntityEffectStrength:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectStrength(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+};
+
+
+
+
+
+class cEntityEffectInstantHealth:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectInstantHealth(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+
+ virtual void OnActivate(cPawn & a_Target) override;
+};
+
+
+
+
+
+class cEntityEffectInstantDamage:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectInstantDamage(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+
+ virtual void OnActivate(cPawn & a_Target) override;
+};
+
+
+
+
+
+class cEntityEffectJumpBoost:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectJumpBoost(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+};
+
+
+
+
+
+class cEntityEffectNausea:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectNausea(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+};
+
+
+
+
+
+class cEntityEffectRegeneration:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectRegeneration(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+
+ virtual void OnTick(cPawn & a_Target) override;
+};
+
+
+
+
+
+class cEntityEffectResistance:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectResistance(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+};
+
+
+
+
+
+class cEntityEffectFireResistance:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectFireResistance(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+};
+
+
+
+
+
+class cEntityEffectWaterBreathing:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectWaterBreathing(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+};
+
+
+
+
+
+class cEntityEffectInvisibility:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectInvisibility(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+};
+
+
+
+
+
+class cEntityEffectBlindness:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectBlindness(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+};
+
+
+
+
+
+class cEntityEffectNightVision:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectNightVision(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+};
+
+
+
+
+
+class cEntityEffectHunger:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectHunger(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+
+ // cEntityEffect overrides:
+ virtual void OnTick(cPawn & a_Target) override;
+};
+
+
+
+
+
+class cEntityEffectWeakness:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectWeakness(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+
+ // cEntityEffect overrides:
+ virtual void OnTick(cPawn & a_Target) override;
+};
+
+
+
+
+
+class cEntityEffectPoison:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectPoison(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+
+ // cEntityEffect overrides:
+ virtual void OnTick(cPawn & a_Target) override;
+};
+
+
+
+
+
+class cEntityEffectWither:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectWither(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+
+ // cEntityEffect overrides:
+ virtual void OnTick(cPawn & a_Target) override;
+};
+
+
+
+
+
+class cEntityEffectHealthBoost:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectHealthBoost(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+};
+
+
+
+
+
+class cEntityEffectAbsorption:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectAbsorption(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+};
+
+
+
+
+
+class cEntityEffectSaturation:
+ public cEntityEffect
+{
+ typedef cEntityEffect super;
+public:
+ cEntityEffectSaturation(int a_Duration, short a_Intensity, double a_DistanceModifier = 1):
+ super(a_Duration, a_Intensity, a_DistanceModifier)
+ {
+ }
+
+ virtual void OnTick(cPawn & a_Target) override;
+};
+
+
+
+
diff --git a/src/Entities/ExpBottleEntity.h b/src/Entities/ExpBottleEntity.h
index b2043d8f1..e9536452c 100644
--- a/src/Entities/ExpBottleEntity.h
+++ b/src/Entities/ExpBottleEntity.h
@@ -30,4 +30,4 @@ protected:
// cProjectileEntity overrides:
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
-}; // tolua_export
+}; // tolua_export
diff --git a/src/Entities/ExpOrb.cpp b/src/Entities/ExpOrb.cpp
index e437c24ef..73d5cbfed 100644
--- a/src/Entities/ExpOrb.cpp
+++ b/src/Entities/ExpOrb.cpp
@@ -6,7 +6,7 @@
cExpOrb::cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward)
- : cEntity(etExpOrb, a_X, a_Y, a_Z, 0.98, 0.98)
+ : cEntity(etExpOrb, a_X, a_Y, a_Z, 0.98, 0.98)
, m_Reward(a_Reward)
, m_Timer(0.f)
{
@@ -19,7 +19,7 @@ cExpOrb::cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward)
cExpOrb::cExpOrb(const Vector3d & a_Pos, int a_Reward)
- : cEntity(etExpOrb, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98)
+ : cEntity(etExpOrb, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98)
, m_Reward(a_Reward)
, m_Timer(0.f)
{
@@ -62,9 +62,9 @@ void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk)
}
a_Distance.Normalize();
a_Distance *= ((float) (5.5 - Distance));
- SetSpeedX( a_Distance.x );
- SetSpeedY( a_Distance.y );
- SetSpeedZ( a_Distance.z );
+ SetSpeedX( a_Distance.x);
+ SetSpeedY( a_Distance.y);
+ SetSpeedZ( a_Distance.z);
BroadcastMovementUpdate();
}
HandlePhysics(a_Dt, a_Chunk);
diff --git a/src/Entities/FireChargeEntity.h b/src/Entities/FireChargeEntity.h
index 3924c337c..42ecc7d74 100644
--- a/src/Entities/FireChargeEntity.h
+++ b/src/Entities/FireChargeEntity.h
@@ -33,4 +33,4 @@ protected:
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
-} ; // tolua_export
+} ; // tolua_export
diff --git a/src/Entities/FireworkEntity.h b/src/Entities/FireworkEntity.h
index c62ca9402..7dbdc49e1 100644
--- a/src/Entities/FireworkEntity.h
+++ b/src/Entities/FireworkEntity.h
@@ -37,4 +37,4 @@ private:
int m_ExplodeTimer;
cItem m_FireworkItem;
-}; // tolua_export
+}; // tolua_export
diff --git a/src/Entities/Floater.cpp b/src/Entities/Floater.cpp
index d49893020..159429147 100644
--- a/src/Entities/Floater.cpp
+++ b/src/Entities/Floater.cpp
@@ -11,7 +11,7 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
// cFloaterEntityCollisionCallback
class cFloaterEntityCollisionCallback :
public cEntityCallback
@@ -75,7 +75,7 @@ protected:
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
// cFloaterCheckEntityExist
class cFloaterCheckEntityExist :
public cEntityCallback
@@ -130,7 +130,7 @@ void cFloater::Tick(float a_Dt, cChunk & a_Chunk)
HandlePhysics(a_Dt, a_Chunk);
if (IsBlockWater(m_World->GetBlock((int) GetPosX(), (int) GetPosY(), (int) GetPosZ())) && m_World->GetBlockMeta((int) GetPosX(), (int) GetPosY(), (int) GetPosZ()) == 0)
{
- if ((!m_CanPickupItem) && (m_AttachedMobID == -1)) // Check if you can't already pickup a fish and if the floater isn't attached to a mob.
+ if ((!m_CanPickupItem) && (m_AttachedMobID == -1)) // Check if you can't already pickup a fish and if the floater isn't attached to a mob.
{
if (m_CountDownTime <= 0)
{
@@ -141,7 +141,7 @@ void cFloater::Tick(float a_Dt, cChunk & a_Chunk)
m_CountDownTime = 100 + m_World->GetTickRandomNumber(800);
LOGD("Floater %i can be picked up", GetUniqueID());
}
- else if (m_CountDownTime == 20) // Calculate the position where the particles should spawn and start producing them.
+ else if (m_CountDownTime == 20) // Calculate the position where the particles should spawn and start producing them.
{
LOGD("Started producing particles for floater %i", GetUniqueID());
m_ParticlePos.Set(GetPosX() + (-4 + m_World->GetTickRandomNumber(8)), GetPosY(), GetPosZ() + (-4 + m_World->GetTickRandomNumber(8)));
@@ -156,12 +156,12 @@ void cFloater::Tick(float a_Dt, cChunk & a_Chunk)
m_CountDownTime--;
if (m_World->GetHeight((int) GetPosX(), (int) GetPosZ()) == (int) GetPosY())
{
- if (m_World->IsWeatherWet() && m_World->GetTickRandomNumber(3) == 0) // 25% chance of an extra countdown when being rained on.
+ if (m_World->IsWeatherWet() && m_World->GetTickRandomNumber(3) == 0) // 25% chance of an extra countdown when being rained on.
{
m_CountDownTime--;
}
}
- else // if the floater is underground it has a 50% chance of not decreasing the countdown.
+ else // if the floater is underground it has a 50% chance of not decreasing the countdown.
{
if (m_World->GetTickRandomNumber(1) == 0)
{
@@ -190,21 +190,21 @@ void cFloater::Tick(float a_Dt, cChunk & a_Chunk)
if (Callback.HasHit())
{
AttachTo(Callback.GetHitEntity());
- Callback.GetHitEntity()->TakeDamage(*this); // TODO: the player attacked the mob not the floater.
+ Callback.GetHitEntity()->TakeDamage(*this); // TODO: the player attacked the mob not the floater.
m_AttachedMobID = Callback.GetHitEntity()->GetUniqueID();
}
}
cFloaterCheckEntityExist EntityCallback;
m_World->DoWithEntityByID(m_PlayerID, EntityCallback);
- if (!EntityCallback.DoesExist()) // The owner doesn't exist anymore. Destroy the floater entity.
+ if (!EntityCallback.DoesExist()) // The owner doesn't exist anymore. Destroy the floater entity.
{
Destroy(true);
}
if (m_AttachedMobID != -1)
{
- m_World->DoWithEntityByID(m_AttachedMobID, EntityCallback); // The mob the floater was attached to doesn't exist anymore.
+ m_World->DoWithEntityByID(m_AttachedMobID, EntityCallback); // The mob the floater was attached to doesn't exist anymore.
if (!EntityCallback.DoesExist())
{
m_AttachedMobID = -1;
diff --git a/src/Entities/Floater.h b/src/Entities/Floater.h
index 547d503f1..5d2720b6a 100644
--- a/src/Entities/Floater.h
+++ b/src/Entities/Floater.h
@@ -14,7 +14,7 @@ class cFloater :
typedef cEntity super;
public:
- //tolua_end
+ // tolua_end
CLASS_PROTODEF(cFloater);
@@ -43,4 +43,4 @@ protected:
// Entity IDs
int m_PlayerID;
int m_AttachedMobID;
-} ; // tolua_export
+} ; // tolua_export
diff --git a/src/Entities/GhastFireballEntity.h b/src/Entities/GhastFireballEntity.h
index 9e4572c78..fa59fa642 100644
--- a/src/Entities/GhastFireballEntity.h
+++ b/src/Entities/GhastFireballEntity.h
@@ -35,4 +35,4 @@ protected:
// TODO: Deflecting the fireballs by arrow- or sword- hits
-} ; // tolua_export
+} ; // tolua_export
diff --git a/src/Entities/HangingEntity.cpp b/src/Entities/HangingEntity.cpp
index 41ac86268..32d2b226d 100644
--- a/src/Entities/HangingEntity.cpp
+++ b/src/Entities/HangingEntity.cpp
@@ -10,7 +10,7 @@
cHangingEntity::cHangingEntity(eEntityType a_EntityType, eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z)
- : cEntity(a_EntityType, a_X, a_Y, a_Z, 0.8, 0.8)
+ : cEntity(a_EntityType, a_X, a_Y, a_Z, 0.8, 0.8)
, m_BlockFace(a_BlockFace)
{
SetMaxHealth(1);
@@ -28,14 +28,14 @@ void cHangingEntity::SpawnOn(cClientHandle & a_ClientHandle)
// The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces
switch (m_BlockFace)
{
- case BLOCK_FACE_ZP: break; // Initialised to zero
+ case BLOCK_FACE_ZP: break; // Initialised to zero
case BLOCK_FACE_ZM: Dir = 2; break;
case BLOCK_FACE_XM: Dir = 1; break;
case BLOCK_FACE_XP: Dir = 3; break;
default: ASSERT(!"Unhandled block face when trying to spawn item frame!"); return;
}
- if ((Dir == 0) || (Dir == 2)) // Probably a client bug, but two directions are flipped and contrary to the norm, so we do -180
+ if ((Dir == 0) || (Dir == 2)) // Probably a client bug, but two directions are flipped and contrary to the norm, so we do -180
{
SetYaw((Dir * 90) - 180);
}
diff --git a/src/Entities/ItemFrame.cpp b/src/Entities/ItemFrame.cpp
index 7bc7bda8d..f0b0c8c65 100644
--- a/src/Entities/ItemFrame.cpp
+++ b/src/Entities/ItemFrame.cpp
@@ -10,7 +10,7 @@
cItemFrame::cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z)
- : cHangingEntity(etItemFrame, a_BlockFace, a_X, a_Y, a_Z)
+ : cHangingEntity(etItemFrame, a_BlockFace, a_X, a_Y, a_Z)
, m_Item(E_BLOCK_AIR)
, m_Rotation(0)
{
@@ -43,7 +43,7 @@ void cItemFrame::OnRightClicked(cPlayer & a_Player)
}
}
- GetWorld()->BroadcastEntityMetadata(*this); // Update clients
+ GetWorld()->BroadcastEntityMetadata(*this); // Update clients
}
@@ -51,17 +51,17 @@ void cItemFrame::OnRightClicked(cPlayer & a_Player)
-void cItemFrame::KilledBy(cEntity * a_Killer)
+void cItemFrame::KilledBy(TakeDamageInfo & a_TDI)
{
if (m_Item.IsEmpty())
{
SetHealth(0);
- super::KilledBy(a_Killer);
+ super::KilledBy(a_TDI);
Destroy();
return;
}
- if ((a_Killer != NULL) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative())
+ if ((a_TDI.Attacker != NULL) && a_TDI.Attacker->IsPlayer() && !((cPlayer *)a_TDI.Attacker)->IsGameModeCreative())
{
cItems Item;
Item.push_back(m_Item);
diff --git a/src/Entities/ItemFrame.h b/src/Entities/ItemFrame.h
index 6577e7d94..9261e52cc 100644
--- a/src/Entities/ItemFrame.h
+++ b/src/Entities/ItemFrame.h
@@ -35,7 +35,7 @@ public:
private:
virtual void OnRightClicked(cPlayer & a_Player) override;
- virtual void KilledBy(cEntity * a_Killer) override;
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override;
virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
cItem m_Item;
diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp
index 7bd440d6d..d4eadc5d5 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -103,21 +103,7 @@ cMinecart::cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z) :
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
+ a_ClientHandle.SendSpawnVehicle(*this, 10, (char)m_Payload); // 10 = Minecarts
a_ClientHandle.SendEntityMetadata(*this);
}
@@ -127,7 +113,7 @@ void cMinecart::SpawnOn(cClientHandle & a_ClientHandle)
void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
- if (IsDestroyed()) // Mainly to stop detector rails triggering again after minecart is dead
+ if (IsDestroyed()) // Mainly to stop detector rails triggering again after minecart is dead
{
return;
}
@@ -156,8 +142,8 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
if (!IsBlockRail(InsideType))
{
- Chunk->GetBlockTypeMeta(RelPosX, PosY + 1, RelPosZ, InsideType, InsideMeta); // When an descending minecart hits a flat rail, it goes through the ground; check for this
- if (IsBlockRail(InsideType)) AddPosY(1); // Push cart upwards
+ Chunk->GetBlockTypeMeta(RelPosX, PosY + 1, RelPosZ, InsideType, InsideMeta); // When an descending minecart hits a flat rail, it goes through the ground; check for this
+ if (IsBlockRail(InsideType)) AddPosY(1); // Push cart upwards
}
bool WasDetectorRail = false;
@@ -186,12 +172,12 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
default: VERIFY(!"Unhandled rail type despite checking if block was rail!"); break;
}
- AddPosition(GetSpeed() * (a_Dt / 1000)); // Commit changes; as we use our own engine when on rails, this needs to be done, whereas it is normally in Entity.cpp
+ AddPosition(GetSpeed() * (a_Dt / 1000)); // Commit changes; as we use our own engine when on rails, this needs to be done, whereas it is normally in Entity.cpp
}
else
{
// Not on rail, default physics
- SetPosY(floor(GetPosY()) + 0.35); // HandlePhysics overrides this if minecart can fall, else, it is to stop ground clipping minecart bottom when off-rail
+ SetPosY(floor(GetPosY()) + 0.35); // HandlePhysics overrides this if minecart can fall, else, it is to stop ground clipping minecart bottom when off-rail
super::HandlePhysics(a_Dt, *Chunk);
}
@@ -223,18 +209,18 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
switch (a_RailMeta)
{
- case E_META_RAIL_ZM_ZP: // NORTHSOUTH
+ case E_META_RAIL_ZM_ZP: // NORTHSOUTH
{
SetYaw(270);
SetPosY(floor(GetPosY()) + 0.55);
- SetSpeedY(0); // Don't move vertically as on ground
- SetSpeedX(0); // Correct diagonal movement from curved rails
+ SetSpeedY(0); // Don't move vertically as on ground
+ SetSpeedX(0); // Correct diagonal movement from curved rails
// Execute both the entity and block collision checks
bool BlckCol = TestBlockCollision(a_RailMeta), EntCol = TestEntityCollision(a_RailMeta);
if (EntCol || BlckCol) return;
- if (GetSpeedZ() != 0) // Don't do anything if cart is stationary
+ if (GetSpeedZ() != 0) // Don't do anything if cart is stationary
{
if (GetSpeedZ() > 0)
{
@@ -249,7 +235,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
break;
}
- case E_META_RAIL_XM_XP: // EASTWEST
+ case E_META_RAIL_XM_XP: // EASTWEST
{
SetYaw(180);
SetPosY(floor(GetPosY()) + 0.55);
@@ -272,7 +258,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
break;
}
- case E_META_RAIL_ASCEND_ZM: // ASCEND NORTH
+ case E_META_RAIL_ASCEND_ZM: // ASCEND NORTH
{
SetYaw(270);
SetSpeedX(0);
@@ -280,21 +266,21 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
if (GetSpeedZ() >= 0)
{
// SpeedZ POSITIVE, going SOUTH
- if (GetSpeedZ() <= MAX_SPEED) // Speed limit
+ if (GetSpeedZ() <= MAX_SPEED) // Speed limit
{
- AddSpeedZ(0.5); // Speed up
- SetSpeedY(-GetSpeedZ()); // Downward movement is negative (0 minus positive numbers is negative)
+ AddSpeedZ(0.5); // Speed up
+ SetSpeedY(-GetSpeedZ()); // Downward movement is negative (0 minus positive numbers is negative)
}
}
else
{
// SpeedZ NEGATIVE, going NORTH
- AddSpeedZ(1); // Slow down
- SetSpeedY(-GetSpeedZ()); // Upward movement is positive (0 minus negative number is positive number)
+ AddSpeedZ(1); // Slow down
+ SetSpeedY(-GetSpeedZ()); // Upward movement is positive (0 minus negative number is positive number)
}
break;
}
- case E_META_RAIL_ASCEND_ZP: // ASCEND SOUTH
+ case E_META_RAIL_ASCEND_ZP: // ASCEND SOUTH
{
SetYaw(270);
SetSpeedX(0);
@@ -302,21 +288,21 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
if (GetSpeedZ() > 0)
{
// SpeedZ POSITIVE, going SOUTH
- AddSpeedZ(-1); // Slow down
- SetSpeedY(GetSpeedZ()); // Upward movement positive
+ AddSpeedZ(-1); // Slow down
+ SetSpeedY(GetSpeedZ()); // Upward movement positive
}
else
{
- if (GetSpeedZ() >= MAX_SPEED_NEGATIVE) // Speed limit
+ if (GetSpeedZ() >= MAX_SPEED_NEGATIVE) // Speed limit
{
// SpeedZ NEGATIVE, going NORTH
- AddSpeedZ(-0.5); // Speed up
- SetSpeedY(GetSpeedZ()); // Downward movement negative
+ AddSpeedZ(-0.5); // Speed up
+ SetSpeedY(GetSpeedZ()); // Downward movement negative
}
}
break;
}
- case E_META_RAIL_ASCEND_XM: // ASCEND EAST
+ case E_META_RAIL_ASCEND_XM: // ASCEND EAST
{
SetYaw(180);
SetSpeedZ(0);
@@ -336,7 +322,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
break;
}
- case E_META_RAIL_ASCEND_XP: // ASCEND WEST
+ case E_META_RAIL_ASCEND_XP: // ASCEND WEST
{
SetYaw(180);
SetSpeedZ(0);
@@ -356,10 +342,10 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
break;
}
- case E_META_RAIL_CURVED_ZM_XM: // Ends pointing NORTH and WEST
+ case E_META_RAIL_CURVED_ZM_XM: // Ends pointing NORTH and WEST
{
- SetYaw(315); // Set correct rotation server side
- SetPosY(floor(GetPosY()) + 0.55); // Levitate dat cart
+ SetYaw(315); // Set correct rotation server side
+ SetPosY(floor(GetPosY()) + 0.55); // Levitate dat cart
SetSpeedY(0);
TestBlockCollision(a_RailMeta);
@@ -369,7 +355,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
break;
}
- case E_META_RAIL_CURVED_ZM_XP: // Curved NORTH EAST
+ case E_META_RAIL_CURVED_ZM_XP: // Curved NORTH EAST
{
SetYaw(225);
SetPosY(floor(GetPosY()) + 0.55);
@@ -380,7 +366,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
break;
}
- case E_META_RAIL_CURVED_ZP_XM: // Curved SOUTH WEST
+ case E_META_RAIL_CURVED_ZP_XM: // Curved SOUTH WEST
{
SetYaw(135);
SetPosY(floor(GetPosY()) + 0.55);
@@ -391,7 +377,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
break;
}
- case E_META_RAIL_CURVED_ZP_XP: // Curved SOUTH EAST
+ case E_META_RAIL_CURVED_ZP_XP: // Curved SOUTH EAST
{
SetYaw(45);
SetPosY(floor(GetPosY()) + 0.55);
@@ -404,7 +390,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
}
default:
{
- ASSERT(!"Unhandled rail meta!"); // Dun dun DUN!
+ ASSERT(!"Unhandled rail meta!"); // Dun dun DUN!
break;
}
}
@@ -428,7 +414,7 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
switch (a_RailMeta & 0x07)
{
- case E_META_RAIL_ZM_ZP: // NORTHSOUTH
+ case E_META_RAIL_ZM_ZP: // NORTHSOUTH
{
SetYaw(270);
SetPosY(floor(GetPosY()) + 0.55);
@@ -451,7 +437,7 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
}
break;
}
- case E_META_RAIL_XM_XP: // EASTWEST
+ case E_META_RAIL_XM_XP: // EASTWEST
{
SetYaw(180);
SetPosY(floor(GetPosY()) + 0.55);
@@ -474,7 +460,7 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
}
break;
}
- case E_META_RAIL_ASCEND_XM: // ASCEND EAST
+ case E_META_RAIL_ASCEND_XM: // ASCEND EAST
{
SetYaw(180);
SetSpeedZ(0);
@@ -493,8 +479,8 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
SetSpeedY(-GetSpeedX());
}
break;
- }
- case E_META_RAIL_ASCEND_XP: // ASCEND WEST
+ }
+ case E_META_RAIL_ASCEND_XP: // ASCEND WEST
{
SetYaw(180);
SetSpeedZ(0);
@@ -513,8 +499,8 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
}
}
break;
- }
- case E_META_RAIL_ASCEND_ZM: // ASCEND NORTH
+ }
+ case E_META_RAIL_ASCEND_ZM: // ASCEND NORTH
{
SetYaw(270);
SetSpeedX(0);
@@ -534,7 +520,7 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
}
break;
}
- case E_META_RAIL_ASCEND_ZP: // ASCEND SOUTH
+ case E_META_RAIL_ASCEND_ZP: // ASCEND SOUTH
{
SetYaw(270);
SetSpeedX(0);
@@ -787,7 +773,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
}
}
break;
- }
+ }
case E_META_RAIL_CURVED_ZM_XM:
case E_META_RAIL_CURVED_ZM_XP:
case E_META_RAIL_CURVED_ZP_XM:
@@ -883,7 +869,7 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta)
}
}
return true;
- }
+ }
case E_META_RAIL_CURVED_ZM_XM:
case E_META_RAIL_CURVED_ZM_XP:
case E_META_RAIL_CURVED_ZP_XM:
@@ -907,7 +893,7 @@ bool cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
if ((TDI.Attacker != NULL) && TDI.Attacker->IsPlayer() && ((cPlayer *)TDI.Attacker)->IsGameModeCreative())
{
Destroy();
- TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative
+ TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative
SetInvulnerableTicks(0);
return super::DoTakeDamage(TDI); // No drops for creative
}
@@ -980,7 +966,7 @@ void cMinecart::Destroyed()
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
// cRideableMinecart:
cRideableMinecart::cRideableMinecart(double a_X, double a_Y, double a_Z, const cItem & a_Content, int a_Height) :
@@ -1023,7 +1009,7 @@ void cRideableMinecart::OnRightClicked(cPlayer & a_Player)
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
// cMinecartWithChest:
cMinecartWithChest::cMinecartWithChest(double a_X, double a_Y, double a_Z) :
@@ -1056,7 +1042,7 @@ void cMinecartWithChest::OnRightClicked(cPlayer & a_Player)
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
// cMinecartWithFurnace:
cMinecartWithFurnace::cMinecartWithFurnace(double a_X, double a_Y, double a_Z) :
@@ -1078,12 +1064,12 @@ void cMinecartWithFurnace::OnRightClicked(cPlayer & a_Player)
{
a_Player.GetInventory().RemoveOneEquippedItem();
}
- if (!m_IsFueled) // We don't want to change the direction by right clicking it.
+ if (!m_IsFueled) // We don't want to change the direction by right clicking it.
{
AddSpeed(a_Player.GetLookVector().x, 0, a_Player.GetLookVector().z);
}
m_IsFueled = true;
- m_FueledTimeLeft = m_FueledTimeLeft + 600; // The minecart will be active 600 more ticks.
+ m_FueledTimeLeft = m_FueledTimeLeft + 600; // The minecart will be active 600 more ticks.
m_World->BroadcastEntityMetadata(*this);
}
}
@@ -1118,7 +1104,7 @@ void cMinecartWithFurnace::Tick(float a_Dt, cChunk & a_Chunk)
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
// cMinecartWithTNT:
cMinecartWithTNT::cMinecartWithTNT(double a_X, double a_Y, double a_Z) :
@@ -1132,7 +1118,7 @@ cMinecartWithTNT::cMinecartWithTNT(double a_X, double a_Y, double a_Z) :
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
// cMinecartWithHopper:
cMinecartWithHopper::cMinecartWithHopper(double a_X, double a_Y, double a_Z) :
diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h
index 1e60f091c..c585cfab0 100644
--- a/src/Entities/Minecart.h
+++ b/src/Entities/Minecart.h
@@ -23,13 +23,14 @@ class cMinecart :
public:
CLASS_PROTODEF(cMinecart);
+ /** Minecart payload, values correspond to packet subtype */
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
+ mpNone = 0, // Empty minecart, ridable by player or mobs
+ mpChest = 1, // Minecart-with-chest, can store a grid of 3*8 items
+ mpFurnace = 2, // Minecart-with-furnace, can be powered
+ mpTNT = 3, // Minecart-with-TNT, can be blown up with activator rail
+ mpHopper = 5, // Minecart-with-hopper, can be hopper
// TODO: Spawner minecarts, (and possibly any block in a minecart with NBT editing)
} ;
@@ -99,7 +100,7 @@ public:
protected:
cItem m_Content;
- int m_Height;
+ int m_Height;
} ;
diff --git a/src/Entities/Painting.h b/src/Entities/Painting.h
index c1024bd1b..ce7c6f3de 100644
--- a/src/Entities/Painting.h
+++ b/src/Entities/Painting.h
@@ -18,17 +18,17 @@ public:
CLASS_PROTODEF(cPainting);
cPainting(const AString & a_Name, int a_Direction, double a_X, double a_Y, double a_Z);
- const AString & GetName(void) const { return m_Name; } // tolua_export
- int GetDirection(void) const { return m_Direction; } // tolua_export
+ const AString & GetName(void) const { return m_Name; } // tolua_export
+ int GetDirection(void) const { return m_Direction; } // tolua_export
private:
virtual void SpawnOn(cClientHandle & a_Client) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
- virtual void KilledBy(cEntity * a_Killer) override
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override
{
- super::KilledBy(a_Killer);
+ super::KilledBy(a_TDI);
Destroy();
}
diff --git a/src/Entities/Pawn.cpp b/src/Entities/Pawn.cpp
index fffefd538..fe6c24a7a 100644
--- a/src/Entities/Pawn.cpp
+++ b/src/Entities/Pawn.cpp
@@ -2,14 +2,16 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Pawn.h"
+#include "../World.h"
+#include "../Bindings/PluginManager.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)
+cPawn::cPawn(eEntityType a_EntityType, double a_Width, double a_Height):
+ super(a_EntityType, 0, 0, 0, a_Width, a_Height),
+ m_EntityEffects(tEffectMap())
{
}
@@ -17,3 +19,95 @@ cPawn::cPawn(eEntityType a_EntityType, double a_Width, double a_Height)
+void cPawn::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ // Iterate through this entity's applied effects
+ for (tEffectMap::iterator iter = m_EntityEffects.begin(); iter != m_EntityEffects.end();)
+ {
+ // Copies values to prevent pesky wrong accesses and erasures
+ cEntityEffect::eType EffectType = iter->first;
+ cEntityEffect * Effect = iter->second;
+
+ Effect->OnTick(*this);
+
+ // Iterates (must be called before any possible erasure)
+ ++iter;
+
+ // Remove effect if duration has elapsed
+ if (Effect->GetDuration() - Effect->GetTicks() <= 0)
+ {
+ RemoveEntityEffect(EffectType);
+ }
+
+ // TODO: Check for discrepancies between client and server effect values
+ }
+
+ super::Tick(a_Dt, a_Chunk);
+}
+
+
+
+
+
+void cPawn::KilledBy(TakeDamageInfo & a_TDI)
+{
+ ClearEntityEffects();
+ super::KilledBy(a_TDI);
+}
+
+
+
+
+
+void cPawn::AddEntityEffect(cEntityEffect::eType a_EffectType, int a_Duration, short a_Intensity, double a_DistanceModifier)
+{
+ // Check if the plugins allow the addition:
+ if (cPluginManager::Get()->CallHookEntityAddEffect(*this, a_EffectType, a_Duration, a_Intensity, a_DistanceModifier))
+ {
+ // A plugin disallows the addition, bail out.
+ return;
+ }
+
+ // No need to add empty effects:
+ if (a_EffectType == cEntityEffect::effNoEffect)
+ {
+ return;
+ }
+ a_Duration = (int)(a_Duration * a_DistanceModifier);
+
+ m_EntityEffects[a_EffectType] = cEntityEffect::CreateEntityEffect(a_EffectType, a_Duration, a_Intensity, a_DistanceModifier);
+ m_World->BroadcastEntityEffect(*this, a_EffectType, a_Intensity, a_Duration);
+ m_EntityEffects[a_EffectType]->OnActivate(*this);
+}
+
+
+
+
+
+void cPawn::RemoveEntityEffect(cEntityEffect::eType a_EffectType)
+{
+ m_World->BroadcastRemoveEntityEffect(*this, a_EffectType);
+ m_EntityEffects[a_EffectType]->OnDeactivate(*this);
+ delete m_EntityEffects[a_EffectType];
+ m_EntityEffects.erase(a_EffectType);
+}
+
+
+
+
+
+void cPawn::ClearEntityEffects()
+{
+ // Iterate through this entity's applied effects
+ for (tEffectMap::iterator iter = m_EntityEffects.begin(); iter != m_EntityEffects.end();)
+ {
+ // Copy values to prevent pesky wrong erasures
+ cEntityEffect::eType EffectType = iter->first;
+
+ // Iterates (must be called before any possible erasure)
+ ++iter;
+
+ // Remove effect
+ RemoveEntityEffect(EffectType);
+ }
+}
diff --git a/src/Entities/Pawn.h b/src/Entities/Pawn.h
index e76337d86..63c7cfbb6 100644
--- a/src/Entities/Pawn.h
+++ b/src/Entities/Pawn.h
@@ -2,6 +2,7 @@
#pragma once
#include "Entity.h"
+#include "EntityEffect.h"
@@ -18,9 +19,34 @@ public:
CLASS_PROTODEF(cPawn);
cPawn(eEntityType a_EntityType, double a_Width, double a_Height);
+
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override;
+
+ // tolua_begin
+
+ /** Applies an entity effect
+ Checks with plugins if they allow the addition.
+ @param a_EffectType The entity effect to apply
+ @param a_EffectDurationTicks The duration of the effect
+ @param a_EffectIntensity The level of the effect (0 = Potion I, 1 = Potion II, etc)
+ @param a_DistanceModifier The scalar multiplied to the potion duration, only applies to splash potions)
+ */
+ void AddEntityEffect(cEntityEffect::eType a_EffectType, int a_EffectDurationTicks, short a_EffectIntensity, double a_DistanceModifier = 1);
+
+ /** Removes a currently applied entity effect
+ @param a_EffectType The entity effect to remove
+ */
+ void RemoveEntityEffect(cEntityEffect::eType a_EffectType);
+
+ /** Removes all currently applied entity effects (used when drinking milk) */
+ void ClearEntityEffects(void);
+
+ // tolua_end
protected:
- bool m_bBurnable;
+ typedef std::map<cEntityEffect::eType, cEntityEffect *> tEffectMap;
+ tEffectMap m_EntityEffects;
} ; // tolua_export
diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp
index bae1485d4..aab534f41 100644
--- a/src/Entities/Pickup.cpp
+++ b/src/Entities/Pickup.cpp
@@ -85,7 +85,7 @@ protected:
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)
+ : cEntity(etPickup, a_PosX, a_PosY, a_PosZ, 0.2, 0.2)
, m_Timer(0.f)
, m_Item(a_Item)
, m_bCollected(false)
@@ -113,7 +113,7 @@ void cPickup::SpawnOn(cClientHandle & a_Client)
void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
- BroadcastMovementUpdate(); //Notify clients of position
+ BroadcastMovementUpdate(); // Notify clients of position
m_Timer += a_Dt;
@@ -143,17 +143,17 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
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)
+ if (m_Timer > 500.f)
{
Destroy(true);
return;
}
}
- if (!IsDestroyed() && (m_Item.m_ItemCount < m_Item.GetMaxStackSize())) // Don't combine into an already full pickup
+ if (!IsDestroyed() && (m_Item.m_ItemCount < m_Item.GetMaxStackSize())) // Don't combine into an already full pickup
{
cPickupCombiningCallback PickupCombiningCallback(GetPosition(), this);
- m_World->ForEachEntity(PickupCombiningCallback); // Not ForEachEntityInChunk, otherwise pickups don't combine across chunk boundaries
+ m_World->ForEachEntity(PickupCombiningCallback); // Not ForEachEntityInChunk, otherwise pickups don't combine across chunk boundaries
if (PickupCombiningCallback.FoundMatchingPickup())
{
m_World->BroadcastEntityMetadata(*this);
@@ -176,7 +176,7 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
return;
}
- if (GetPosY() < VOID_BOUNDARY) // Out of this world and no more visible!
+ if (GetPosY() < VOID_BOUNDARY) // Out of this world and no more visible!
{
Destroy(true);
return;
@@ -194,14 +194,14 @@ bool cPickup::CollectedBy(cPlayer * a_Dest)
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!
+ 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
+ return false; // Not old enough
}
if (cRoot::Get()->GetPluginManager()->CallHookCollectingPickup(a_Dest, *this))
diff --git a/src/Entities/Pickup.h b/src/Entities/Pickup.h
index 2dcbecaaf..d7c5d2b26 100644
--- a/src/Entities/Pickup.h
+++ b/src/Entities/Pickup.h
@@ -27,12 +27,12 @@ public:
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);
- cItem & GetItem(void) {return m_Item; } // 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
+ bool CollectedBy(cPlayer * a_Dest); // tolua_export
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
@@ -46,7 +46,7 @@ public:
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
+ bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export
private:
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index b1b7fc74e..fcc8eb9a0 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -2,6 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Player.h"
+#include "../ChatColor.h"
#include "../Server.h"
#include "../UI/Window.h"
#include "../UI/WindowOwner.h"
@@ -41,7 +42,6 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) :
m_FoodSaturationLevel(5.0),
m_FoodTickTimer(0),
m_FoodExhaustionLevel(0.0),
- m_FoodPoisonedTicksRemaining(0),
m_LastJumpHeight(0),
m_LastGroundHeight(0),
m_bTouchGround(false),
@@ -130,7 +130,7 @@ cPlayer::~cPlayer(void)
if (!cRoot::Get()->GetPluginManager()->CallHookPlayerDestroyed(*this))
{
cRoot::Get()->BroadcastChatLeave(Printf("%s has left the game", GetName().c_str()));
- LOGINFO("Player %s has left the game.", GetName().c_str());
+ LOGINFO("Player %s has left the game", GetName().c_str());
}
LOGD("Deleting cPlayer \"%s\" at %p, ID %d", GetName().c_str(), this, GetUniqueID());
@@ -140,7 +140,7 @@ cPlayer::~cPlayer(void)
SaveToDisk();
- m_World->RemovePlayer( this );
+ m_World->RemovePlayer( this);
m_ClientHandle = NULL;
@@ -173,11 +173,11 @@ void cPlayer::SpawnOn(cClientHandle & a_Client)
}
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() );
+ 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());
}
@@ -224,7 +224,7 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
SendExperience();
}
- if (!GetPosition().EqualsEps(m_LastPos, 0.01)) // Non negligible change in position from last tick?
+ if (!GetPosition().EqualsEps(m_LastPos, 0.01)) // Non negligible change in position from last tick?
{
// Apply food exhaustion from movement:
ApplyFoodExhaustionFromMovement();
@@ -285,20 +285,20 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
short cPlayer::CalcLevelFromXp(short a_XpTotal)
{
- //level 0 to 15
- if(a_XpTotal <= XP_TO_LEVEL15)
+ // 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)
+ // level 30+
+ if (a_XpTotal > XP_TO_LEVEL30)
{
return (short) (151.5 + sqrt( 22952.25 - (14 * (2220 - a_XpTotal)))) / 7;
}
- //level 16 to 30
- return (short) ( 29.5 + sqrt( 870.25 - (6 * ( 360 - a_XpTotal )))) / 3;
+ // level 16 to 30
+ return (short) ( 29.5 + sqrt( 870.25 - (6 * ( 360 - a_XpTotal)))) / 3;
}
@@ -307,20 +307,20 @@ short cPlayer::CalcLevelFromXp(short a_XpTotal)
short cPlayer::XpForLevel(short a_Level)
{
- //level 0 to 15
- if(a_Level <= 15)
+ // level 0 to 15
+ if (a_Level <= 15)
{
return a_Level * XP_PER_LEVEL_TO15;
}
- //level 30+
- if(a_Level >= 31)
+ // level 30+
+ if (a_Level >= 31)
{
- return (short) ( (3.5 * a_Level * a_Level) - (151.5 * a_Level) + 2220 );
+ return (short) ( (3.5 * a_Level * a_Level) - (151.5 * a_Level) + 2220);
}
- //level 16 to 30
- return (short) ( (1.5 * a_Level * a_Level) - (29.5 * a_Level) + 360 );
+ // level 16 to 30
+ return (short) ( (1.5 * a_Level * a_Level) - (29.5 * a_Level) + 360);
}
@@ -341,7 +341,7 @@ float cPlayer::GetXpPercentage()
short int currentLevel = CalcLevelFromXp(m_CurrentXp);
short int currentLevel_XpBase = XpForLevel(currentLevel);
- return (float)(m_CurrentXp - currentLevel_XpBase) /
+ return (float)(m_CurrentXp - currentLevel_XpBase) /
(float)(XpForLevel(1+currentLevel) - currentLevel_XpBase);
}
@@ -351,10 +351,10 @@ float cPlayer::GetXpPercentage()
bool cPlayer::SetCurrentExperience(short int a_CurrentXp)
{
- if(!(a_CurrentXp >= 0) || (a_CurrentXp > (SHRT_MAX - m_LifetimeTotalXp)))
+ if (!(a_CurrentXp >= 0) || (a_CurrentXp > (SHRT_MAX - m_LifetimeTotalXp)))
{
LOGWARNING("Tried to update experiece with an invalid Xp value: %d", a_CurrentXp);
- return false; //oops, they gave us a dodgey number
+ return false; // oops, they gave us a dodgey number
}
m_CurrentXp = a_CurrentXp;
@@ -376,16 +376,13 @@ short cPlayer::DeltaExperience(short a_Xp_delta)
// Value was bad, abort and report
LOGWARNING("Attempt was made to increment Xp by %d, which overflowed the short datatype. Ignoring.",
a_Xp_delta);
- return -1; // Should we instead just return the current Xp?
+ return -1; // Should we instead just return the current Xp?
}
m_CurrentXp += a_Xp_delta;
// Make sure they didn't subtract too much
- if (m_CurrentXp < 0)
- {
- m_CurrentXp = 0;
- }
+ m_CurrentXp = std::max<short int>(m_CurrentXp, 0);
// Update total for score calculation
if (a_Xp_delta > 0)
@@ -393,7 +390,7 @@ short cPlayer::DeltaExperience(short a_Xp_delta)
m_LifetimeTotalXp += a_Xp_delta;
}
- LOGD("Player \"%s\" gained/lost %d experience, total is now: %d",
+ LOGD("Player \"%s\" gained/lost %d experience, total is now: %d",
GetName().c_str(), a_Xp_delta, m_CurrentXp);
// Set experience to be updated
@@ -478,7 +475,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
{
float Dist = (float)(m_LastGroundHeight - floor(GetPosY()));
- if (Dist >= 2.0) // At least two blocks - TODO: Use m_LastJumpHeight instead of m_LastGroundHeight above
+ if (Dist >= 2.0) // At least two blocks - TODO: Use m_LastJumpHeight instead of m_LastGroundHeight above
{
// Increment statistic
m_Stats.AddValue(statDistFallen, (StatValue)floor(Dist * 100 + 0.5));
@@ -498,7 +495,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
// Fall particles
GetWorld()->BroadcastSoundParticleEffect(2006, POSX_TOINT, (int)GetPosY() - 1, POSZ_TOINT, Damage /* Used as particle effect speed modifier */);
- }
+ }
m_LastGroundHeight = (float)GetPosY();
}
@@ -563,18 +560,9 @@ void cPlayer::SetFoodExhaustionLevel(double a_FoodExhaustionLevel)
-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)
+ if (IsSatiated())
{
return false;
}
@@ -590,17 +578,7 @@ bool cPlayer::Feed(int a_Food, double a_Saturation)
void cPlayer::FoodPoison(int a_NumTicks)
{
- bool HasBeenFoodPoisoned = (m_FoodPoisonedTicksRemaining > 0);
- m_FoodPoisonedTicksRemaining = std::max(m_FoodPoisonedTicksRemaining, a_NumTicks);
- if (!HasBeenFoodPoisoned)
- {
- m_World->BroadcastRemoveEntityEffect(*this, E_EFFECT_HUNGER);
- SendHealth();
- }
- else
- {
- m_World->BroadcastEntityEffect(*this, E_EFFECT_HUNGER, 0, 400); // Give the player the "Hunger" effect for 20 seconds.
- }
+ AddEntityEffect(cEntityEffect::effHunger, a_NumTicks, 0, 1);
}
@@ -643,8 +621,9 @@ void cPlayer::FinishEating(void)
GetInventory().RemoveOneEquippedItem();
- //if the food is mushroom soup, return a bowl to the inventory
- if( Item.m_ItemType == E_ITEM_MUSHROOM_SOUP ) {
+ // 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);
}
@@ -885,16 +864,16 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
-void cPlayer::KilledBy(cEntity * a_Killer)
+void cPlayer::KilledBy(TakeDamageInfo & a_TDI)
{
- super::KilledBy(a_Killer);
+ super::KilledBy(a_TDI);
if (m_Health > 0)
{
- return; // not dead yet =]
+ return; // not dead yet =]
}
- m_bVisible = false; // So new clients don't see the player
+ m_bVisible = false; // So new clients don't see the player
// Puke out all the items
cItems Pickups;
@@ -911,20 +890,42 @@ void cPlayer::KilledBy(cEntity * a_Killer)
m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10);
SaveToDisk(); // Save it, yeah the world is a tough place !
- if (a_Killer == NULL)
+ if (a_TDI.Attacker == NULL)
{
- GetWorld()->BroadcastChatDeath(Printf("%s was killed by environmental damage", GetName().c_str()));
+ AString DamageText;
+ switch (a_TDI.DamageType)
+ {
+ case dtRangedAttack: DamageText = "was shot"; break;
+ case dtLightning: DamageText = "was plasmified by lightining"; break;
+ case dtFalling: DamageText = (GetWorld()->GetTickRandomNumber(10) % 2 == 0) ? "fell to death" : "hit the ground too hard"; break;
+ case dtDrowning: DamageText = "drowned"; break;
+ case dtSuffocating: DamageText = (GetWorld()->GetTickRandomNumber(10) % 2 == 0) ? "git merge'd into a block" : "fused with a block"; break;
+ case dtStarving: DamageText = "forgot the importance of food"; break;
+ case dtCactusContact: DamageText = "was impaled on a cactus"; break;
+ case dtLavaContact: DamageText = "was melted by lava"; break;
+ case dtPoisoning: DamageText = "died from septicaemia"; break;
+ case dtWithering: DamageText = "is a husk of their former selves"; break;
+ case dtOnFire: DamageText = "forgot to stop, drop, and roll"; break;
+ case dtFireContact: DamageText = "burnt themselves to death"; break;
+ case dtInVoid: DamageText = "somehow fell out of the world"; break;
+ case dtPotionOfHarming: DamageText = "was magicked to death"; break;
+ case dtEnderPearl: DamageText = "misused an ender pearl"; break;
+ case dtAdmin: DamageText = "was administrator'd"; break;
+ case dtExplosion: DamageText = "blew up"; break;
+ default: DamageText = "died, somehow; we've no idea how though"; break;
+ }
+ GetWorld()->BroadcastChatDeath(Printf("%s %s", GetName().c_str(), DamageText.c_str()));
}
- else if (a_Killer->IsPlayer())
+ else if (a_TDI.Attacker->IsPlayer())
{
- cPlayer * Killer = (cPlayer *)a_Killer;
+ cPlayer * Killer = (cPlayer *)a_TDI.Attacker;
GetWorld()->BroadcastChatDeath(Printf("%s was killed by %s", GetName().c_str(), Killer->GetName().c_str()));
}
else
{
- AString KillerClass = a_Killer->GetClass();
- KillerClass.erase(KillerClass.begin()); // Erase the 'c' of the class (e.g. "cWitch" -> "Witch")
+ AString KillerClass = a_TDI.Attacker->GetClass();
+ KillerClass.erase(KillerClass.begin()); // Erase the 'c' of the class (e.g. "cWitch" -> "Witch")
GetWorld()->BroadcastChatDeath(Printf("%s was killed by a %s", GetName().c_str(), KillerClass.c_str()));
}
@@ -1006,7 +1007,7 @@ double cPlayer::GetEyeHeight(void) const
Vector3d cPlayer::GetEyePosition(void) const
{
- return Vector3d( GetPosX(), m_Stance, GetPosZ() );
+ return Vector3d( GetPosX(), m_Stance, GetPosZ());
}
@@ -1168,7 +1169,7 @@ void cPlayer::SetGameMode(eGameMode a_GameMode)
-void cPlayer::LoginSetGameMode( eGameMode a_GameMode )
+void cPlayer::LoginSetGameMode( eGameMode a_GameMode)
{
m_GameMode = a_GameMode;
}
@@ -1277,7 +1278,7 @@ Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const
// TODO: Add a slight random change (+-0.0075 in each direction)
return res * a_SpeedCoeff;
-}
+}
@@ -1304,13 +1305,13 @@ void cPlayer::DoSetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ)
-void cPlayer::MoveTo( const Vector3d & a_NewPos )
+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
+ // 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)
{
@@ -1327,7 +1328,7 @@ void cPlayer::MoveTo( const Vector3d & a_NewPos )
Vector3d DeltaPos = a_NewPos - GetPosition();
UpdateMovementStats(DeltaPos);
- SetPosition( a_NewPos );
+ SetPosition( a_NewPos);
SetStance(a_NewPos.y + 1.62);
}
@@ -1337,7 +1338,7 @@ void cPlayer::MoveTo( const Vector3d & a_NewPos )
void cPlayer::SetVisible(bool a_bVisible)
{
- if (a_bVisible && !m_bVisible) // Make visible
+ if (a_bVisible && !m_bVisible) // Make visible
{
m_bVisible = true;
m_World->BroadcastSpawnEntity(*this);
@@ -1345,7 +1346,7 @@ void cPlayer::SetVisible(bool a_bVisible)
if (!a_bVisible && m_bVisible)
{
m_bVisible = false;
- m_World->BroadcastDestroyEntity(*this, m_ClientHandle); // Destroy on all clients
+ m_World->BroadcastDestroyEntity(*this, m_ClientHandle); // Destroy on all clients
}
}
@@ -1353,11 +1354,11 @@ void cPlayer::SetVisible(bool a_bVisible)
-void cPlayer::AddToGroup( const AString & a_GroupName )
+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", GetName().c_str(), a_GroupName.c_str() );
+ cGroup* Group = cRoot::Get()->GetGroupManager()->GetGroup( a_GroupName);
+ m_Groups.push_back( Group);
+ LOGD("Added %s to group %s", GetName().c_str(), a_GroupName.c_str());
ResolveGroups();
ResolvePermissions();
}
@@ -1366,28 +1367,28 @@ void cPlayer::AddToGroup( const AString & a_GroupName )
-void cPlayer::RemoveFromGroup( const AString & a_GroupName )
+void cPlayer::RemoveFromGroup( const AString & a_GroupName)
{
bool bRemoved = false;
- for( GroupList::iterator itr = m_Groups.begin(); itr != m_Groups.end(); ++itr )
+ for (GroupList::iterator itr = m_Groups.begin(); itr != m_Groups.end(); ++itr)
{
- if( (*itr)->GetName().compare(a_GroupName ) == 0 )
+ if ((*itr)->GetName().compare(a_GroupName) == 0)
{
- m_Groups.erase( itr );
+ m_Groups.erase( itr);
bRemoved = true;
break;
}
}
- if( bRemoved )
+ if (bRemoved)
{
- LOGD("Removed %s from group %s", GetName().c_str(), a_GroupName.c_str() );
+ LOGD("Removed %s from group %s", GetName().c_str(), a_GroupName.c_str());
ResolveGroups();
ResolvePermissions();
}
else
{
- LOGWARN("Tried to remove %s from group %s but was not in that group", GetName().c_str(), a_GroupName.c_str() );
+ LOGWARN("Tried to remove %s from group %s but was not in that group", GetName().c_str(), a_GroupName.c_str());
}
}
@@ -1403,30 +1404,30 @@ bool cPlayer::HasPermission(const AString & a_Permission)
return true;
}
- AStringVector Split = StringSplit( a_Permission, "." );
+ AStringVector Split = StringSplit( a_Permission, ".");
PermissionMap Possibilities = m_ResolvedPermissions;
// Now search the namespaces
- while( Possibilities.begin() != Possibilities.end() )
+ while (Possibilities.begin() != Possibilities.end())
{
PermissionMap::iterator itr = Possibilities.begin();
- if( itr->second )
+ if (itr->second)
{
- AStringVector OtherSplit = StringSplit( itr->first, "." );
- if( OtherSplit.size() <= Split.size() )
+ AStringVector OtherSplit = StringSplit( itr->first, ".");
+ if (OtherSplit.size() <= Split.size())
{
unsigned int i;
- for( i = 0; i < OtherSplit.size(); ++i )
+ for (i = 0; i < OtherSplit.size(); ++i)
{
- if( OtherSplit[i].compare( Split[i] ) != 0 )
+ if (OtherSplit[i].compare( Split[i]) != 0)
{
- if( OtherSplit[i].compare("*") == 0 ) return true; // WildCard man!! WildCard!
+ if (OtherSplit[i].compare("*") == 0) return true; // WildCard man!! WildCard!
break;
}
}
- if( i == Split.size() ) return true;
+ if (i == Split.size()) return true;
}
}
- Possibilities.erase( itr );
+ Possibilities.erase( itr);
}
// Nothing that matched :(
@@ -1437,11 +1438,11 @@ bool cPlayer::HasPermission(const AString & a_Permission)
-bool cPlayer::IsInGroup( const AString & a_Group )
+bool cPlayer::IsInGroup( const AString & a_Group)
{
- for( GroupList::iterator itr = m_ResolvedGroups.begin(); itr != m_ResolvedGroups.end(); ++itr )
+ for (GroupList::iterator itr = m_ResolvedGroups.begin(); itr != m_ResolvedGroups.end(); ++itr)
{
- if( a_Group.compare( (*itr)->GetName().c_str() ) == 0 )
+ if (a_Group.compare( (*itr)->GetName().c_str()) == 0)
return true;
}
return false;
@@ -1453,18 +1454,18 @@ bool cPlayer::IsInGroup( const AString & a_Group )
void cPlayer::ResolvePermissions()
{
- m_ResolvedPermissions.clear(); // Start with an empty map yo~
+ m_ResolvedPermissions.clear(); // Start with an empty map
// Copy all player specific permissions into the resolved permissions map
- for( PermissionMap::iterator itr = m_Permissions.begin(); itr != m_Permissions.end(); ++itr )
+ 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 )
+ 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 )
+ for (cGroup::PermissionMap::const_iterator itr = Permissions.begin(); itr != Permissions.end(); ++itr)
{
m_ResolvedPermissions[ itr->first ] = itr->second;
}
@@ -1481,16 +1482,16 @@ void cPlayer::ResolveGroups()
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
+ 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 )
+ for (GroupList::iterator GroupItr = m_Groups.begin(); GroupItr != m_Groups.end(); ++GroupItr)
{
- ToIterate.push_back( *GroupItr );
+ ToIterate.push_back( *GroupItr);
}
- while( ToIterate.begin() != ToIterate.end() )
+ while (ToIterate.begin() != ToIterate.end())
{
cGroup* CurrentGroup = *ToIterate.begin();
- if( AllGroups.find( CurrentGroup ) != AllGroups.end() )
+ if (AllGroups.find( CurrentGroup) != AllGroups.end())
{
LOGWARNING("ERROR: Player \"%s\" is in the group multiple times (\"%s\"). Please fix your settings in users.ini!",
GetName().c_str(), CurrentGroup->GetName().c_str()
@@ -1499,19 +1500,19 @@ void cPlayer::ResolveGroups()
else
{
AllGroups[ CurrentGroup ] = true;
- m_ResolvedGroups.push_back( CurrentGroup ); // Add group to resolved list
+ 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 )
+ for (cGroup::GroupList::const_iterator itr = Inherits.begin(); itr != Inherits.end(); ++itr)
{
- if( AllGroups.find( *itr ) != AllGroups.end() )
+ if (AllGroups.find( *itr) != AllGroups.end())
{
- LOGERROR("ERROR: Player %s is in the same group multiple times due to inheritance (%s). FIX IT!", GetName().c_str(), (*itr)->GetName().c_str() );
+ LOGERROR("ERROR: Player %s is in the same group multiple times due to inheritance (%s). FIX IT!", GetName().c_str(), (*itr)->GetName().c_str());
continue;
}
- ToIterate.push_back( *itr );
+ ToIterate.push_back( *itr);
}
}
- ToIterate.erase( ToIterate.begin() );
+ ToIterate.erase( ToIterate.begin());
}
}
@@ -1521,12 +1522,12 @@ void cPlayer::ResolveGroups()
AString cPlayer::GetColor(void) const
{
- if ( m_Color != '-' )
+ if (m_Color != '-')
{
- return cChatColor::Color + m_Color;
+ return cChatColor::Delimiter + m_Color;
}
- if ( m_Groups.size() < 1 )
+ if (m_Groups.size() < 1)
{
return cChatColor::White;
}
@@ -1547,7 +1548,7 @@ void cPlayer::TossEquippedItem(char a_Amount)
char NewAmount = a_Amount;
if (NewAmount > GetInventory().GetEquippedItem().m_ItemCount)
{
- NewAmount = GetInventory().GetEquippedItem().m_ItemCount; // Drop only what's there
+ NewAmount = GetInventory().GetEquippedItem().m_ItemCount; // Drop only what's there
}
GetInventory().GetHotbarGrid().ChangeSlotCount(GetInventory().GetEquippedSlotNum() /* Returns hotbar subslot, which HotbarGrid takes */, -a_Amount);
@@ -1609,7 +1610,7 @@ void cPlayer::TossItems(const cItems & a_Items)
double vX = 0, vY = 0, vZ = 0;
EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY);
vY = -vY * 2 + 1.f;
- m_World->SpawnItemPickups(a_Items, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player
+ m_World->SpawnItemPickups(a_Items, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player
}
@@ -1804,7 +1805,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName)
cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats);
StatSerializer.Load();
- LOGD("Player \"%s\" was read from file \"%s\", spawning at {%.2f, %.2f, %.2f} in world \"%s\"",
+ LOGD("Player %s was read from file \"%s\", spawning at {%.2f, %.2f, %.2f} in world \"%s\"",
GetName().c_str(), a_FileName.c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str()
);
@@ -1888,7 +1889,7 @@ bool cPlayer::SaveToDisk()
{
LOGWARNING("Error writing player \"%s\" to file \"%s\" - cannot save data. Player will lose their progress. ",
GetName().c_str(), SourceFile.c_str()
- );
+ );
return false;
}
@@ -1913,11 +1914,11 @@ cPlayer::StringList cPlayer::GetResolvedPermissions()
StringList Permissions;
const PermissionMap& ResolvedPermissions = m_ResolvedPermissions;
- for( PermissionMap::const_iterator itr = ResolvedPermissions.begin(); itr != ResolvedPermissions.end(); ++itr )
+ for (PermissionMap::const_iterator itr = ResolvedPermissions.begin(); itr != ResolvedPermissions.end(); ++itr)
{
if (itr->second)
{
- Permissions.push_back( itr->first );
+ Permissions.push_back( itr->first);
}
}
@@ -1930,7 +1931,7 @@ cPlayer::StringList cPlayer::GetResolvedPermissions()
void cPlayer::UseEquippedItem(void)
{
- if (IsGameModeCreative()) // No damage in creative
+ if (IsGameModeCreative()) // No damage in creative
{
return;
}
@@ -1994,17 +1995,6 @@ void cPlayer::HandleFood(void)
}
}
- // Apply food poisoning food exhaustion:
- if (m_FoodPoisonedTicksRemaining > 0)
- {
- m_FoodPoisonedTicksRemaining--;
- m_FoodExhaustionLevel += 0.025; // 0.5 per second = 0.025 per tick
- }
- else
- {
- m_World->BroadcastRemoveEntityEffect(*this, E_EFFECT_HUNGER); // Remove the "Hunger" effect.
- }
-
// Apply food exhaustion that has accumulated:
if (m_FoodExhaustionLevel >= 4.0)
{
@@ -2084,7 +2074,7 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos)
{
if (IsClimbing())
{
- if (a_DeltaPos.y > 0.0) // Going up
+ if (a_DeltaPos.y > 0.0) // Going up
{
m_Stats.AddValue(statDistClimbed, (StatValue)floor(a_DeltaPos.y * 100 + 0.5));
}
@@ -2103,7 +2093,7 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos)
}
else
{
- if (Value >= 25) // Ignore small/slow movement
+ if (Value >= 25) // Ignore small/slow movement
{
m_Stats.AddValue(statDistFlown, Value);
}
@@ -2141,6 +2131,8 @@ void cPlayer::ApplyFoodExhaustionFromMovement()
{
return;
}
+
+ // If we have just teleported, apply no exhaustion
if (m_bIsTeleporting)
{
m_bIsTeleporting = false;
@@ -2152,6 +2144,13 @@ void cPlayer::ApplyFoodExhaustionFromMovement()
{
return;
}
+
+ // Process exhaustion every two ticks as that is how frequently m_LastPos is updated
+ // Otherwise, we apply exhaustion for a 'movement' every tick, one of which is an already processed value
+ if (GetWorld()->GetWorldAge() % 2 != 0)
+ {
+ return;
+ }
// Calculate the distance travelled, update the last pos:
Vector3d Movement(GetPosition() - m_LastPos);
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 8f9b46e0f..26db2050b 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -117,13 +117,13 @@ public:
/** 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
+ 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 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 cInventory & GetInventory(void) { return m_Inventory; } // tolua_export
inline const cInventory & GetInventory(void) const { return m_Inventory; }
/** Gets the contents of the player's associated enderchest */
@@ -174,7 +174,7 @@ public:
AString GetIP(void) const { return m_IP; } // tolua_export
/** Returns the associated team, NULL if none */
- cTeam * GetTeam(void) { return m_Team; } // tolua_export
+ cTeam * GetTeam(void) { return m_Team; } // tolua_export
/** Sets the player team, NULL if none */
void SetTeam(cTeam * a_Team);
@@ -198,9 +198,9 @@ public:
// Sets the current gamemode, doesn't check validity, doesn't send update packets to client
void LoginSetGameMode(eGameMode a_GameMode);
- /** Forces the player to move in the given direction.
+ /** Forces the player to move in the given direction.
@deprecated Use SetSpeed instead. */
- void ForceSetSpeed(const Vector3d & a_Speed); // tolua_export
+ void ForceSetSpeed(const Vector3d & a_Speed); // tolua_export
/** Tries to move to a new position, with attachment-related checks (y == -999) */
void MoveTo(const Vector3d & a_NewPos); // tolua_export
@@ -239,15 +239,15 @@ public:
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
+ 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
+ void RemoveFromGroup( const AString & a_GroupName); // 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
+ 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
@@ -265,13 +265,12 @@ public:
void TossPickup(const cItem & a_Item);
/** Heals the player by the specified amount of HPs (positive only); sends health update */
- void Heal(int a_Health);
+ virtual void Heal(int a_Health) override;
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; }
/** 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); }
@@ -280,7 +279,6 @@ public:
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);
@@ -291,7 +289,7 @@ public:
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 */
+ /** Starts the food poisoning for the specified amount of ticks */
void FoodPoison(int a_NumTicks);
/** Returns true if the player is currently in the process of eating the currently equipped item */
@@ -324,14 +322,14 @@ public:
/** Aborts the current eating operation */
void AbortEating(void);
- virtual void KilledBy(cEntity * a_Killer) override;
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override;
virtual void Killed(cEntity * a_Victim) override;
- void Respawn(void); // tolua_export
+ void Respawn(void); // tolua_export
- void SetVisible( bool a_bVisible ); // tolua_export
- bool IsVisible(void) const { return m_bVisible; } // tolua_export
+ void SetVisible( bool a_bVisible); // tolua_export
+ bool IsVisible(void) const { return m_bVisible; } // tolua_export
/** Moves the player to the specified world.
Returns true if successful, false on failure (world not found). */
@@ -347,7 +345,7 @@ public:
Returns true on success, false on failure. */
bool LoadFromFile(const AString & a_FileName);
- void LoadPermissionsFromDisk(void); // tolua_export
+ void LoadPermissionsFromDisk(void); // tolua_export
const AString & GetLoadedWorldName() { return m_LoadedWorldName; }
@@ -432,7 +430,7 @@ protected:
AString m_LoadedWorldName;
/** Xp Level stuff */
- enum
+ enum
{
XP_TO_LEVEL15 = 255,
XP_PER_LEVEL_TO15 = 17,
@@ -449,14 +447,11 @@ protected:
double m_FoodSaturationLevel;
/** Count-up to the healing or damaging action, based on m_FoodLevel */
- int m_FoodTickTimer;
+ 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;
-
float m_LastJumpHeight;
float m_LastGroundHeight;
bool m_bTouchGround;
@@ -575,7 +570,7 @@ protected:
/** Returns the filename for the player data based on the UUID given.
This can be used both for online and offline UUIDs. */
AString GetUUIDFileName(const AString & a_UUID);
-} ; // tolua_export
+} ; // tolua_export
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index b5ef5c90a..b5e81bc0c 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -21,6 +21,7 @@
#include "FireChargeEntity.h"
#include "FireworkEntity.h"
#include "GhastFireballEntity.h"
+#include "WitherSkullEntity.h"
#include "Player.h"
@@ -34,7 +35,7 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
// cProjectileTracerCallback:
class cProjectileTracerCallback :
@@ -121,7 +122,7 @@ protected:
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
// cProjectileEntityCollisionCallback:
class cProjectileEntityCollisionCallback :
@@ -145,9 +146,11 @@ public:
(a_Entity->GetUniqueID() == m_Projectile->GetCreatorUniqueID()) // 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;
+ // Don't check creator only for the first 5 ticks so that projectiles can collide with the creator
+ if (m_Projectile->GetTicksAlive() <= 5)
+ {
+ return false;
+ }
}
cBoundingBox EntBox(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight());
@@ -210,7 +213,7 @@ protected:
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
// cProjectileEntity:
cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height) :
@@ -260,6 +263,7 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator,
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);
case pkExpBottle: return new cExpBottleEntity (a_Creator, a_X, a_Y, a_Z, Speed);
+ case pkWitherSkull: return new cWitherSkullEntity (a_Creator, a_X, a_Y, a_Z, Speed);
case pkFirework:
{
ASSERT(a_Item != NULL);
@@ -311,7 +315,7 @@ AString cProjectileEntity::GetMCAClassName(void) const
case pkFireCharge: return "SmallFireball";
case pkEnderPearl: return "ThrownEnderpearl";
case pkExpBottle: return "ThrownExpBottle";
- case pkSplashPotion: return "ThrownPotion";
+ case pkSplashPotion: return "SplashPotion";
case pkWitherSkull: return "WitherSkull";
case pkFirework: return "Firework";
case pkFishingFloat: return ""; // Unknown, perhaps MC doesn't save this?
diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h
index 14cee1272..e6b05714e 100644
--- a/src/Entities/ProjectileEntity.h
+++ b/src/Entities/ProjectileEntity.h
@@ -52,7 +52,7 @@ public:
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace);
/// Called by the physics blocktracer when the entity hits another entity
- virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
+ virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
{
UNUSED(a_EntityHit);
UNUSED(a_HitPos);
@@ -89,7 +89,7 @@ public:
protected:
- /** A structure that stores the Entity ID and Playername of the projectile's creator
+ /** A structure that stores the Entity ID and Playername of the projectile's creator
Used to migitate invalid pointers caused by the creator being destroyed
*/
struct CreatorData
@@ -120,4 +120,4 @@ protected:
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
virtual void SpawnOn(cClientHandle & a_Client) override;
-} ; // tolua_export
+} ; // tolua_export
diff --git a/src/Entities/SplashPotionEntity.cpp b/src/Entities/SplashPotionEntity.cpp
new file mode 100644
index 000000000..6d874e957
--- /dev/null
+++ b/src/Entities/SplashPotionEntity.cpp
@@ -0,0 +1,133 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "SplashPotionEntity.h"
+#include "Pawn.h"
+#include "../ClientHandle.h"
+
+
+
+
+
+/// Converts an angle in radians into a byte representation used by the network protocol
+#define ANGLE_TO_PROTO(X) (Byte)(X * 255 / 360)
+
+////////////////////////////////////////////////////////////////////////////////
+// cSplashPotionEntityCallback:
+
+/** Used to distribute the splashed potion effect among nearby entities */
+class cSplashPotionCallback :
+ public cEntityCallback
+{
+public:
+ /** Creates the callback.
+ @param a_HitPos The position where the splash potion has splashed
+ @param a_EntityEffectType The effect type of the potion
+ @param a_EntityEffect The effect description */
+ cSplashPotionCallback(const Vector3d & a_HitPos, cEntityEffect::eType a_EntityEffectType, const cEntityEffect & a_EntityEffect) :
+ m_HitPos(a_HitPos),
+ m_EntityEffectType(a_EntityEffectType),
+ m_EntityEffect(a_EntityEffect)
+ {
+ }
+
+ /** Called by cWorld::ForEachEntity(), adds the stored entity effect to the entity, if it is close enough. */
+ virtual bool Item(cEntity * a_Entity) override
+ {
+ if (!a_Entity->IsPawn())
+ {
+ // Not an entity that can take effects
+ return false;
+ }
+
+ double SplashDistance = (a_Entity->GetPosition() - m_HitPos).Length();
+ if (SplashDistance >= 20)
+ {
+ // Too far away
+ return false;
+ }
+
+ // y = -0.25x + 1, where x is the distance from the player. Approximation for potion splash.
+ // TODO: better equation
+ double Reduction = -0.25 * SplashDistance + 1.0;
+ Reduction = std::max(Reduction, 0.0);
+
+ ((cPawn *) a_Entity)->AddEntityEffect(m_EntityEffectType, m_EntityEffect.GetDuration(), m_EntityEffect.GetIntensity(), Reduction);
+ return false;
+ }
+
+private:
+ const Vector3d & m_HitPos;
+ cEntityEffect::eType m_EntityEffectType;
+ const cEntityEffect & m_EntityEffect;
+};
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cSplashPotionEntity:
+
+cSplashPotionEntity::cSplashPotionEntity(
+ cEntity * a_Creator,
+ double a_X, double a_Y, double a_Z,
+ const Vector3d & a_Speed,
+ cEntityEffect::eType a_EntityEffectType,
+ cEntityEffect a_EntityEffect,
+ int a_PotionColor
+) :
+ super(pkSplashPotion, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
+ m_EntityEffectType(a_EntityEffectType),
+ m_EntityEffect(a_EntityEffect),
+ m_PotionColor(a_PotionColor),
+ m_DestroyTimer(-1)
+{
+ SetSpeed(a_Speed);
+}
+
+
+
+
+
+void cSplashPotionEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
+{
+ Splash(a_HitPos);
+ m_DestroyTimer = 2;
+}
+
+
+
+
+
+void cSplashPotionEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
+{
+ a_EntityHit.TakeDamage(dtRangedAttack, this, 0, 1);
+ Splash(a_HitPos);
+ m_DestroyTimer = 5;
+}
+
+
+
+
+
+void cSplashPotionEntity::Splash(const Vector3d & a_HitPos)
+{
+ cSplashPotionCallback Callback(a_HitPos, m_EntityEffectType, m_EntityEffect);
+ m_World->ForEachEntity(Callback);
+
+ m_World->BroadcastSoundParticleEffect(2002, (int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z), m_PotionColor);
+}
+
+
+
+
+
+void cSplashPotionEntity::SpawnOn(cClientHandle & a_Client)
+{
+ a_Client.SendSpawnObject(*this, 73, m_PotionColor, ANGLE_TO_PROTO(GetYaw()), ANGLE_TO_PROTO(GetPitch()));
+ a_Client.SendEntityMetadata(*this);
+}
+
+
+
+
diff --git a/src/Entities/SplashPotionEntity.h b/src/Entities/SplashPotionEntity.h
new file mode 100644
index 000000000..290dd81d4
--- /dev/null
+++ b/src/Entities/SplashPotionEntity.h
@@ -0,0 +1,81 @@
+//
+// SplashPotionEntity.h
+//
+
+#pragma once
+
+#include "ProjectileEntity.h"
+#include "EntityEffect.h"
+#include "../World.h"
+#include "Entity.h"
+
+
+
+
+// tolua_begin
+
+class cSplashPotionEntity :
+ public cProjectileEntity
+{
+ typedef cProjectileEntity super;
+
+public:
+
+ // tolua_end
+
+ CLASS_PROTODEF(cSplashPotionEntity);
+
+ cSplashPotionEntity(
+ cEntity * a_Creator,
+ double a_X, double a_Y, double a_Z,
+ const Vector3d & a_Speed,
+ cEntityEffect::eType a_EntityEffectType,
+ cEntityEffect a_EntityEffect,
+ int a_PotionColor
+ );
+
+ cEntityEffect::eType GetEntityEffectType(void) const { return m_EntityEffectType; }
+ cEntityEffect GetEntityEffect(void) const { return m_EntityEffect; }
+ int GetPotionColor(void) const { return m_PotionColor; }
+
+ void SetEntityEffectType(cEntityEffect::eType a_EntityEffectType) { m_EntityEffectType = a_EntityEffectType; }
+ void SetEntityEffect(cEntityEffect a_EntityEffect) { m_EntityEffect = a_EntityEffect; }
+ void SetPotionColor(int a_PotionColor) { m_PotionColor = a_PotionColor; }
+
+protected:
+
+ cEntityEffect::eType m_EntityEffectType;
+ cEntityEffect m_EntityEffect;
+ int m_PotionColor;
+
+
+ // cProjectileEntity overrides:
+ virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
+ virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
+ virtual void Tick (float a_Dt, cChunk & a_Chunk) override
+ {
+ if (m_DestroyTimer > 0)
+ {
+ m_DestroyTimer--;
+ if (m_DestroyTimer == 0)
+ {
+ Destroy();
+ return;
+ }
+ }
+ else
+ {
+ super::Tick(a_Dt, a_Chunk);
+ }
+ }
+
+ /** Splashes the potion, fires its particle effects and sounds
+ @param a_HitPos The position where the potion will splash */
+ void Splash(const Vector3d & a_HitPos);
+
+ virtual void SpawnOn(cClientHandle & a_Client) override;
+
+private:
+ /** Time in ticks to wait for the hit animation to begin before destroying */
+ int m_DestroyTimer;
+} ; // tolua_export
diff --git a/src/Entities/TNTEntity.cpp b/src/Entities/TNTEntity.cpp
index fd9a4e7ac..53af446cc 100644
--- a/src/Entities/TNTEntity.cpp
+++ b/src/Entities/TNTEntity.cpp
@@ -42,7 +42,7 @@ void cTNTEntity::Explode(void)
{
m_FuseTicks = 0;
Destroy(true);
- LOGD("BOOM at {%f,%f,%f}", GetPosX(), GetPosY(), GetPosZ());
+ 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);
}
diff --git a/src/Entities/TNTEntity.h b/src/Entities/TNTEntity.h
index 116f5a8cb..df61b14f5 100644
--- a/src/Entities/TNTEntity.h
+++ b/src/Entities/TNTEntity.h
@@ -38,7 +38,7 @@ public:
protected:
int m_FuseTicks; ///< How much ticks is left, while the tnt will explode
-}; // tolua_export
+}; // tolua_export
diff --git a/src/Entities/ThrownEggEntity.h b/src/Entities/ThrownEggEntity.h
index dc72c279f..f93731256 100644
--- a/src/Entities/ThrownEggEntity.h
+++ b/src/Entities/ThrownEggEntity.h
@@ -55,4 +55,4 @@ private:
/** Time in ticks to wait for the hit animation to begin before destroying */
int m_DestroyTimer;
-} ; // tolua_export
+} ; // tolua_export
diff --git a/src/Entities/ThrownEnderPearlEntity.h b/src/Entities/ThrownEnderPearlEntity.h
index 1cea5f7d9..549d8a3eb 100644
--- a/src/Entities/ThrownEnderPearlEntity.h
+++ b/src/Entities/ThrownEnderPearlEntity.h
@@ -55,4 +55,4 @@ private:
/** Time in ticks to wait for the hit animation to begin before destroying */
int m_DestroyTimer;
-} ; // tolua_export
+} ; // tolua_export
diff --git a/src/Entities/ThrownSnowballEntity.h b/src/Entities/ThrownSnowballEntity.h
index 9a8770379..6f3efdd7e 100644
--- a/src/Entities/ThrownSnowballEntity.h
+++ b/src/Entities/ThrownSnowballEntity.h
@@ -52,4 +52,4 @@ private:
/** Time in ticks to wait for the hit animation to begin before destroying */
int m_DestroyTimer;
-} ; // tolua_export
+} ; // tolua_export
diff --git a/src/Entities/WitherSkullEntity.cpp b/src/Entities/WitherSkullEntity.cpp
new file mode 100644
index 000000000..a7e774bba
--- /dev/null
+++ b/src/Entities/WitherSkullEntity.cpp
@@ -0,0 +1,49 @@
+
+// WitherSkullEntity.cpp
+
+// Implements the cWitherSkullEntity class representing the entity used by both blue and black wither skulls
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "WitherSkullEntity.h"
+#include "../World.h"
+
+
+
+
+
+cWitherSkullEntity::cWitherSkullEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
+ super(pkWitherSkull, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
+{
+ SetSpeed(a_Speed);
+}
+
+
+
+
+
+void cWitherSkullEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
+{
+ // TODO: Explode
+ // TODO: Apply wither effect to entities nearby
+ Destroy();
+}
+
+
+
+
+
+void cWitherSkullEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
+{
+ // TODO: If entity is Ender Crystal, destroy it
+ a_EntityHit.TakeDamage(dtRangedAttack, this, 0, 1);
+
+ // TODO: Explode
+ // TODO: Apply wither effect to entity and others nearby
+
+ Destroy(true);
+}
+
+
+
+
diff --git a/src/Entities/WitherSkullEntity.h b/src/Entities/WitherSkullEntity.h
new file mode 100644
index 000000000..ebc1550e3
--- /dev/null
+++ b/src/Entities/WitherSkullEntity.h
@@ -0,0 +1,35 @@
+
+// WitherSkullEntity.h
+
+// Declares the cWitherSkullEntity class representing the entity used by both blue and black wither skulls
+
+#pragma once
+
+#include "ProjectileEntity.h"
+
+
+
+
+
+// tolua_begin
+
+class cWitherSkullEntity :
+public cProjectileEntity
+{
+ typedef cProjectileEntity super;
+
+public:
+
+ // tolua_end
+
+ CLASS_PROTODEF(cWitherSkullEntity);
+
+ cWitherSkullEntity(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, eBlockFace a_HitFace) override;
+ virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
+
+} ; // tolua_export