diff options
Diffstat (limited to 'src/Entities')
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 |