summaryrefslogtreecommitdiffstats
path: root/src/Entities
diff options
context:
space:
mode:
Diffstat (limited to 'src/Entities')
-rw-r--r--src/Entities/CMakeLists.txt1
-rw-r--r--src/Entities/Entity.cpp98
-rw-r--r--src/Entities/Entity.h11
-rw-r--r--src/Entities/FallingBlock.cpp4
-rw-r--r--src/Entities/ProjectileEntity.cpp63
-rw-r--r--src/Entities/ProjectileEntity.h13
6 files changed, 167 insertions, 23 deletions
diff --git a/src/Entities/CMakeLists.txt b/src/Entities/CMakeLists.txt
index 85cc45494..c9ca44d38 100644
--- a/src/Entities/CMakeLists.txt
+++ b/src/Entities/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../")
file(GLOB SOURCE
"*.cpp"
+ "*.h"
)
add_library(Entities ${SOURCE})
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 56ef36ef8..7c8e18b51 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -45,6 +45,7 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d
, m_IsInitialized(false)
, m_EntityType(a_EntityType)
, m_World(NULL)
+ , m_IsFireproof(false)
, m_TicksSinceLastBurnDamage(0)
, m_TicksSinceLastLavaDamage(0)
, m_TicksSinceLastFireDamage(0)
@@ -325,9 +326,38 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
m_Health = 0;
}
- if (IsMob() || IsPlayer()) // Knockback for only players and mobs
+ if ((IsMob() || IsPlayer()) && (a_TDI.Attacker != NULL)) // Knockback for only players and mobs
{
- AddSpeed(a_TDI.Knockback * 2);
+ int KnockbackLevel = 0;
+ if (a_TDI.Attacker->GetEquippedWeapon().m_ItemType == E_ITEM_BOW)
+ {
+ 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);
+ 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;
+ }
+ }
+ AddSpeed(a_TDI.Knockback * additionalSpeed);
}
m_World->BroadcastEntityStatus(*this, esGenericHurt);
@@ -380,11 +410,8 @@ int cEntity::GetRawDamageAgainst(const cEntity & a_Receiver)
-int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage)
+bool cEntity::ArmorCoversAgainst(eDamageType a_DamageType)
{
- // Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
-
- // Filter out damage types that are not protected by armor:
// Ref.: http://www.minecraftwiki.net/wiki/Armor#Effects as of 2012_12_20
switch (a_DamageType)
{
@@ -399,9 +426,33 @@ int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_Dama
case dtLightning:
case dtPlugin:
{
- return 0;
+ return false;
+ }
+
+ case dtAttack:
+ case dtArrowAttack:
+ case dtCactusContact:
+ case dtLavaContact:
+ case dtFireContact:
+ case dtEnderPearl:
+ case dtExplosion:
+ {
+ return true;
}
}
+ ASSERT(!"Invalid damage type!");
+}
+
+
+
+
+
+int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage)
+{
+ // Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
+
+ // Filter out damage types that are not protected by armor:
+ if (!ArmorCoversAgainst(a_DamageType)) return 0;
// Add up all armor points:
// Ref.: http://www.minecraftwiki.net/wiki/Armor#Defense_points as of 2012_12_20
@@ -772,14 +823,12 @@ void cEntity::TickBurning(cChunk & a_Chunk)
// Remember the current burning state:
bool HasBeenBurning = (m_TicksLeftBurning > 0);
- if (GetWorld()->GetWeather() == eWeather_Rain)
+ if (m_World->IsWeatherWet())
{
- if (HasBeenBurning)
+ if (POSY_TOINT > m_World->GetHeight(POSX_TOINT, POSZ_TOINT))
{
m_TicksLeftBurning = 0;
- OnFinishedBurning();
- }
- return;
+ }
}
// Do the burning damage:
@@ -788,7 +837,10 @@ void cEntity::TickBurning(cChunk & a_Chunk)
m_TicksSinceLastBurnDamage++;
if (m_TicksSinceLastBurnDamage >= BURN_TICKS_PER_DAMAGE)
{
- TakeDamage(dtOnFire, NULL, BURN_DAMAGE, 0);
+ if (!m_IsFireproof)
+ {
+ TakeDamage(dtOnFire, NULL, BURN_DAMAGE, 0);
+ }
m_TicksSinceLastBurnDamage = 0;
}
m_TicksLeftBurning--;
@@ -856,7 +908,10 @@ void cEntity::TickBurning(cChunk & a_Chunk)
m_TicksSinceLastLavaDamage++;
if (m_TicksSinceLastLavaDamage >= LAVA_TICKS_PER_DAMAGE)
{
- TakeDamage(dtLavaContact, NULL, LAVA_DAMAGE, 0);
+ if (!m_IsFireproof)
+ {
+ TakeDamage(dtLavaContact, NULL, LAVA_DAMAGE, 0);
+ }
m_TicksSinceLastLavaDamage = 0;
}
}
@@ -874,7 +929,10 @@ void cEntity::TickBurning(cChunk & a_Chunk)
m_TicksSinceLastFireDamage++;
if (m_TicksSinceLastFireDamage >= FIRE_TICKS_PER_DAMAGE)
{
- TakeDamage(dtFireContact, NULL, FIRE_DAMAGE, 0);
+ if (!m_IsFireproof)
+ {
+ TakeDamage(dtFireContact, NULL, FIRE_DAMAGE, 0);
+ }
m_TicksSinceLastFireDamage = 0;
}
}
@@ -1033,6 +1091,16 @@ void cEntity::SetMaxHealth(int a_MaxHealth)
+/// Sets whether the entity is fireproof
+void cEntity::SetIsFireproof(bool a_IsFireproof)
+{
+ m_IsFireproof = a_IsFireproof;
+}
+
+
+
+
+
/// Puts the entity on fire for the specified amount of ticks
void cEntity::StartBurning(int a_TicksLeftBurning)
{
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index 8f3899e2f..9b8011b55 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -270,6 +270,9 @@ public:
/// Returns the hitpoints that this pawn can deal to a_Receiver using its equipped items
virtual int GetRawDamageAgainst(const cEntity & a_Receiver);
+ /** Returns whether armor will protect against the passed damage type **/
+ virtual bool ArmorCoversAgainst(eDamageType a_DamageType);
+
/// Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover
virtual int GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_RawDamage);
@@ -329,6 +332,11 @@ public:
int GetMaxHealth(void) const { return m_MaxHealth; }
+ /// Sets whether the entity is fireproof
+ void SetIsFireproof(bool a_IsFireproof);
+
+ bool IsFireproof(void) const { return m_IsFireproof; }
+
/// Puts the entity on fire for the specified amount of ticks
void StartBurning(int a_TicksLeftBurning);
@@ -435,6 +443,9 @@ protected:
cWorld * m_World;
+ /// 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;
diff --git a/src/Entities/FallingBlock.cpp b/src/Entities/FallingBlock.cpp
index a66c7e4ae..bcdac0291 100644
--- a/src/Entities/FallingBlock.cpp
+++ b/src/Entities/FallingBlock.cpp
@@ -87,7 +87,9 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
AddSpeedY(MilliDt * -9.8f);
AddPosition(GetSpeed() * MilliDt);
- if ((GetSpeedX() != 0) || (GetSpeedZ() != 0))
+ // If not static (One billionth precision) broadcast movement.
+ static const float epsilon = 0.000000001;
+ if ((fabs(GetSpeedX()) > epsilon) || (fabs(GetSpeedZ()) > epsilon))
{
BroadcastMovementUpdate();
}
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index 96db17ffd..fd3e80e5f 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -440,6 +440,7 @@ cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
m_IsCritical((a_Force >= 1)),
m_Timer(0),
m_HitGroundTimer(0),
+ m_HasTeleported(false),
m_bIsCollected(false),
m_HitBlockPos(0, 0, 0)
{
@@ -562,12 +563,12 @@ 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_HitGroundTimer != -1) // Sent a teleport already, don't do again
+ if (!m_HasTeleported) // Sent a teleport already, don't do again
{
if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case
{
m_World->BroadcastTeleportEntity(*this);
- m_HitGroundTimer = -1;
+ m_HasTeleported = true;
}
else
{
@@ -611,6 +612,32 @@ cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y,
void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
+ TrySpawnChicken(a_HitPos);
+
+ Destroy();
+}
+
+
+
+
+
+void cThrownEggEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
+{
+ int TotalDamage = 0;
+ // TODO: If entity is Ender Crystal, destroy it
+
+ TrySpawnChicken(a_HitPos);
+ a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
+
+ Destroy(true);
+}
+
+
+
+
+
+void cThrownEggEntity::TrySpawnChicken(const Vector3d & a_HitPos)
+{
if (m_World->GetTickRandomNumber(7) == 1)
{
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
@@ -622,7 +649,6 @@ void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_H
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
}
- Destroy();
}
@@ -644,15 +670,39 @@ cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X
void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
+ // TODO: Tweak a_HitPos based on block face.
+ TeleportCreator(a_HitPos);
+
+ Destroy();
+}
+
+
+
+
+
+void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
+{
+ int TotalDamage = 0;
+ // TODO: If entity is Ender Crystal, destroy it
+
+ TeleportCreator(a_HitPos);
+ a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
+
+ Destroy(true);
+}
+
+
+
+
+
+void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos)
+{
// Teleport the creator here, make them take 5 damage:
if (m_Creator != NULL)
{
- // TODO: The coords might need some tweaking based on the block face
m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5);
m_Creator->TakeDamage(dtEnderPearl, this, 5, 0);
}
-
- Destroy();
}
@@ -696,6 +746,7 @@ void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d &
TotalDamage = 1;
}
}
+ // TODO: If entity is Ender Crystal, destroy it
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
Destroy(true);
diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h
index efb7ae783..731dd060e 100644
--- a/src/Entities/ProjectileEntity.h
+++ b/src/Entities/ProjectileEntity.h
@@ -166,6 +166,9 @@ protected:
/// Timer for client arrow position confirmation via TeleportEntity
float m_HitGroundTimer;
+
+ // Whether the arrow has already been teleported into the proper position in the ground.
+ bool m_HasTeleported;
/// If true, the arrow is in the process of being collected - don't go to anyone else
bool m_bIsCollected;
@@ -205,7 +208,11 @@ 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;
+
+ // Randomly decides whether to spawn a chicken where the egg lands.
+ void TrySpawnChicken(const Vector3d & a_HitPos);
+
// tolua_begin
} ;
@@ -233,6 +240,10 @@ 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;
+
+ // Teleports the creator where the ender pearl lands.
+ void TeleportCreator(const Vector3d & a_HitPos);
// tolua_begin