diff options
Diffstat (limited to 'src/Entities')
-rw-r--r-- | src/Entities/Entity.cpp | 28 | ||||
-rw-r--r-- | src/Entities/Floater.cpp | 45 | ||||
-rw-r--r-- | src/Entities/LeashKnot.cpp | 61 | ||||
-rw-r--r-- | src/Entities/Minecart.cpp | 23 | ||||
-rw-r--r-- | src/Entities/Pawn.cpp | 68 | ||||
-rw-r--r-- | src/Entities/Pickup.cpp | 23 | ||||
-rw-r--r-- | src/Entities/Player.cpp | 73 | ||||
-rw-r--r-- | src/Entities/ProjectileEntity.cpp | 40 | ||||
-rw-r--r-- | src/Entities/SplashPotionEntity.cpp | 80 | ||||
-rw-r--r-- | src/Entities/ThrownEnderPearlEntity.cpp | 25 |
10 files changed, 323 insertions, 143 deletions
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 15e00871b..c31f05211 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -304,22 +304,38 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R void cEntity::TakeDamage(eDamageType a_DamageType, UInt32 a_AttackerID, int a_RawDamage, double a_KnockbackAmount) { - m_World->DoWithEntityByID(a_AttackerID, [=](cEntity & a_Attacker) + class cFindEntity : public cEntityCallback + { + public: + + cEntity * m_Entity; + eDamageType m_DamageType; + int m_RawDamage; + double m_KnockbackAmount; + + virtual bool Item(cEntity * a_Attacker) override { cPawn * Attacker; - if (a_Attacker.IsPawn()) + if (a_Attacker->IsPawn()) { - Attacker = static_cast<cPawn*>(&a_Attacker); + Attacker = static_cast<cPawn*>(a_Attacker); } else { Attacker = nullptr; } - TakeDamage(a_DamageType, Attacker, a_RawDamage, a_KnockbackAmount); + + m_Entity->TakeDamage(m_DamageType, Attacker, m_RawDamage, m_KnockbackAmount); return true; } - ); + } Callback; + + Callback.m_Entity = this; + Callback.m_DamageType = a_DamageType; + Callback.m_RawDamage = a_RawDamage; + Callback.m_KnockbackAmount = a_KnockbackAmount; + m_World->DoWithEntityByID(a_AttackerID, Callback); } @@ -650,7 +666,7 @@ bool cEntity::ArmorCoversAgainst(eDamageType a_DamageType) int cEntity::GetEnchantmentCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage) { - int TotalEPF = 0; + int TotalEPF = 0.0; const cItem ArmorItems[] = { GetEquippedHelmet(), GetEquippedChestplate(), GetEquippedLeggings(), GetEquippedBoots() }; for (size_t i = 0; i < ARRAYCOUNT(ArmorItems); i++) diff --git a/src/Entities/Floater.cpp b/src/Entities/Floater.cpp index de5824068..eeaa6cf3d 100644 --- a/src/Entities/Floater.cpp +++ b/src/Entities/Floater.cpp @@ -13,7 +13,8 @@ //////////////////////////////////////////////////////////////////////////////// // cFloaterEntityCollisionCallback -class cFloaterEntityCollisionCallback +class cFloaterEntityCollisionCallback : + public cEntityCallback { public: cFloaterEntityCollisionCallback(cFloater * a_Floater, const Vector3d & a_Pos, const Vector3d & a_NextPos) : @@ -24,14 +25,14 @@ public: m_HitEntity(nullptr) { } - bool operator () (cEntity & a_Entity) + virtual bool Item(cEntity * a_Entity) override { - if (!a_Entity.IsMob()) // Floaters can only pull mobs not other entities. + if (!a_Entity->IsMob()) // Floaters can only pull mobs not other entities. { return false; } - cBoundingBox EntBox(a_Entity.GetPosition(), a_Entity.GetWidth() / 2, a_Entity.GetHeight()); + cBoundingBox EntBox(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight()); double LineCoeff; eBlockFace Face; @@ -46,7 +47,7 @@ public: { // The entity is closer than anything we've stored so far, replace it as the potential victim m_MinCoeff = LineCoeff; - m_HitEntity = &a_Entity; + m_HitEntity = a_Entity; } // Don't break the enumeration, we want all the entities @@ -74,6 +75,32 @@ protected: +//////////////////////////////////////////////////////////////////////////////// +// cFloaterCheckEntityExist +class cFloaterCheckEntityExist : + public cEntityCallback +{ +public: + cFloaterCheckEntityExist(void) : + m_EntityExists(false) + { + } + + bool Item(cEntity * a_Entity) override + { + m_EntityExists = true; + return false; + } + + bool DoesExist(void) const { return m_EntityExists; } +protected: + bool m_EntityExists; +} ; + + + + + cFloater::cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, UInt32 a_PlayerID, int a_CountDownTime) : cEntity(etFloater, a_X, a_Y, a_Z, 0.2, 0.2), m_BitePos(Vector3d(a_X, a_Y, a_Z)), @@ -173,16 +200,18 @@ void cFloater::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) } } - if (!m_World->DoWithEntityByID(m_PlayerID, [](cEntity &) { return true; })) // The owner doesn't exist anymore. Destroy the floater entity. + cFloaterCheckEntityExist EntityCallback; + m_World->DoWithEntityByID(m_PlayerID, EntityCallback); + if (!EntityCallback.DoesExist()) // The owner doesn't exist anymore. Destroy the floater entity. { Destroy(true); } if (m_AttachedMobID != cEntity::INVALID_ID) { - if (!m_World->DoWithEntityByID(m_AttachedMobID, [](cEntity &) { return true; })) + m_World->DoWithEntityByID(m_AttachedMobID, EntityCallback); // The mob the floater was attached to doesn't exist anymore. + if (!EntityCallback.DoesExist()) { - // The mob the floater was attached to doesn't exist anymore. m_AttachedMobID = cEntity::INVALID_ID; } } diff --git a/src/Entities/LeashKnot.cpp b/src/Entities/LeashKnot.cpp index 51002531d..a86dc9d53 100644 --- a/src/Entities/LeashKnot.cpp +++ b/src/Entities/LeashKnot.cpp @@ -1,4 +1,4 @@ - + #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "LeashKnot.h" @@ -38,42 +38,58 @@ void cLeashKnot::OnRightClicked(cPlayer & a_Player) -void cLeashKnot::TiePlayersLeashedMobs(cPlayer & a_Player, bool a_ShouldBroadcast) +void cLeashKnot::TiePlayersLeashedMobs(cPlayer & a_Player, bool a_ShouldBroadCast) { // Check leashed nearby mobs to tie them to this knot - // taking world from player (instead from this) because this can be called before entity was initialized - a_Player.GetWorld()->ForEachEntityInBox(cBoundingBox(GetPosition(), 8, 8, -4), [&](cEntity & a_Entity) + class LookForLeasheds : public cEntityCallback + { + public: + cLeashKnot * m_Knot; + cPlayer * m_Player; + bool m_ShouldBroadcast; + + LookForLeasheds(cLeashKnot * a_Knot, cPlayer * a_PlayerLeashedTo, bool a_ShouldBroadcast) : + m_Knot(a_Knot), + m_Player(a_PlayerLeashedTo), + m_ShouldBroadcast(a_ShouldBroadcast) + { + } + + virtual bool Item(cEntity * a_Entity) override { // If the entity is not a monster skip it - if (a_Entity.GetEntityType() != cEntity::eEntityType::etMonster) + if (a_Entity->GetEntityType() != cEntity::eEntityType::etMonster) { return false; } - auto & PotentialLeashed = static_cast<cMonster&>(a_Entity); + cMonster * PotentialLeashed = static_cast<cMonster*>(a_Entity); // If can't be leashed skip it - if (!PotentialLeashed.CanBeLeashed()) + if (!PotentialLeashed->CanBeLeashed()) { return false; } // If it's not leashed to the player skip it if ( - !PotentialLeashed.IsLeashed() || - !PotentialLeashed.GetLeashedTo()->IsPlayer() || - (PotentialLeashed.GetLeashedTo()->GetUniqueID() != a_Player.GetUniqueID()) + !PotentialLeashed->IsLeashed() || + !PotentialLeashed->GetLeashedTo()->IsPlayer() || + (PotentialLeashed->GetLeashedTo()->GetUniqueID() != m_Player->GetUniqueID()) ) { return false; } // All conditions met, unleash from player and leash to fence - PotentialLeashed.Unleash(false, false); - PotentialLeashed.LeashTo(*this, a_ShouldBroadcast); + PotentialLeashed->Unleash(false, false); + PotentialLeashed->LeashTo(*m_Knot, m_ShouldBroadcast); return false; } - ); + } LookForLeashedsCallback(this, &a_Player, a_ShouldBroadCast); + + // taking world from player (instead from this) because this can be called before entity was initialized + a_Player.GetWorld()->ForEachEntityInBox(cBoundingBox(GetPosition(), 8, 8, -4), LookForLeashedsCallback); } @@ -142,19 +158,26 @@ void cLeashKnot::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) cLeashKnot * cLeashKnot::FindKnotAtPos(cWorldInterface & a_WorldInterface, Vector3i a_BlockPos) { - cLeashKnot * LeashKnot = nullptr; - a_WorldInterface.ForEachEntityInBox(cBoundingBox(a_BlockPos, 0.5, 1), [&](cEntity & a_Entity) + class LookForKnot : public cEntityCallback + { + public: + cLeashKnot * m_LeashKnot = nullptr; + + virtual bool Item(cEntity * a_Entity) override { - if (a_Entity.IsLeashKnot()) + if (a_Entity->IsLeashKnot()) { - LeashKnot = static_cast<cLeashKnot *>(&a_Entity); + m_LeashKnot = reinterpret_cast<cLeashKnot *>(a_Entity); return true; } return false; } - ); - return LeashKnot; + } CallbackFindKnot; + + a_WorldInterface.ForEachEntityInBox(cBoundingBox(a_BlockPos, 0.5, 1), CallbackFindKnot); + + return CallbackFindKnot.m_LeashKnot; } diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 8921f8894..7f32dc910 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -20,7 +20,8 @@ -class cMinecartCollisionCallback +class cMinecartCollisionCallback : + public cEntityCallback { public: cMinecartCollisionCallback(Vector3d a_Pos, double a_Height, double a_Width, UInt32 a_UniqueID, UInt32 a_AttacheeUniqueID) : @@ -34,31 +35,33 @@ public: { } - bool operator () (cEntity & a_Entity) + virtual bool Item(cEntity * a_Entity) override { + ASSERT(a_Entity != nullptr); + if ( ( - !a_Entity.IsPlayer() || - static_cast<cPlayer &>(a_Entity).IsGameModeSpectator() // Spectators doesn't collide with anything + !a_Entity->IsPlayer() || + reinterpret_cast<cPlayer *>(a_Entity)->IsGameModeSpectator() // Spectators doesn't collide with anything ) && - !a_Entity.IsMob() && - !a_Entity.IsMinecart() && - !a_Entity.IsBoat() + !a_Entity->IsMob() && + !a_Entity->IsMinecart() && + !a_Entity->IsBoat() ) { return false; } - else if ((a_Entity.GetUniqueID() == m_UniqueID) || (a_Entity.GetUniqueID() == m_AttacheeUniqueID)) + else if ((a_Entity->GetUniqueID() == m_UniqueID) || (a_Entity->GetUniqueID() == m_AttacheeUniqueID)) { return false; } - cBoundingBox bbEntity(a_Entity.GetPosition(), a_Entity.GetWidth() / 2, a_Entity.GetHeight()); + cBoundingBox bbEntity(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight()); cBoundingBox bbMinecart(Vector3d(m_Pos.x, floor(m_Pos.y), m_Pos.z), m_Width / 2, m_Height); if (bbEntity.DoesIntersect(bbMinecart)) { - m_CollidedEntityPos = a_Entity.GetPosition(); + m_CollidedEntityPos = a_Entity->GetPosition(); m_DoesIntersect = true; return true; } diff --git a/src/Entities/Pawn.cpp b/src/Entities/Pawn.cpp index a116f97e3..233cdfa85 100644 --- a/src/Entities/Pawn.cpp +++ b/src/Entities/Pawn.cpp @@ -1,4 +1,4 @@ - + #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Pawn.h" @@ -80,37 +80,49 @@ void cPawn::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) Effect->OnTick(*this); } - // Spectators cannot push entities around - if ((!IsPlayer()) || (!static_cast<cPlayer *>(this)->IsGameModeSpectator())) + class Pusher : public cEntityCallback { - m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), GetWidth(), GetHeight()), [=](cEntity & a_Entity) + public: + cEntity * m_Pusher; + + Pusher(cEntity * a_Pusher) : + m_Pusher(a_Pusher) + { + } + + virtual bool Item(cEntity * a_Entity) override + { + if (a_Entity->GetUniqueID() == m_Pusher->GetUniqueID()) + { + return false; + } + + // we only push other mobs, boats and minecarts + if ((a_Entity->GetEntityType() != etMonster) && (a_Entity->GetEntityType() != etMinecart) && (a_Entity->GetEntityType() != etBoat)) { - if (a_Entity.GetUniqueID() == GetUniqueID()) - { - return false; - } - - // we only push other mobs, boats and minecarts - if ((a_Entity.GetEntityType() != etMonster) && (a_Entity.GetEntityType() != etMinecart) && (a_Entity.GetEntityType() != etBoat)) - { - return false; - } - - // do not push a boat / minecart you're sitting in - if (IsAttachedTo(&a_Entity)) - { - return false; - } - - Vector3d v3Delta = a_Entity.GetPosition() - GetPosition(); - v3Delta.y = 0.0; // we only push sideways - v3Delta *= 1.0 / (v3Delta.Length() + 0.01); // we push harder if we're close - // QUESTION: is there an additional multiplier for this? current shoving seems a bit weak - - a_Entity.AddSpeed(v3Delta); return false; } - ); + + // do not push a boat / minecart you're sitting in + if (m_Pusher->IsAttachedTo(a_Entity)) + { + return false; + } + + Vector3d v3Delta = a_Entity->GetPosition() - m_Pusher->GetPosition(); + v3Delta.y = 0.0; // we only push sideways + v3Delta *= 1.0 / (v3Delta.Length() + 0.01); // we push harder if we're close + // QUESTION: is there an additional multiplier for this? current shoving seems a bit weak + + a_Entity->AddSpeed(v3Delta); + return false; + } + } Callback(this); + + // Spectators cannot push entities around + if ((!IsPlayer()) || (!reinterpret_cast<cPlayer *>(this)->IsGameModeSpectator())) + { + m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), GetWidth(), GetHeight()), Callback); } super::Tick(a_Dt, a_Chunk); diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp index fcae586f6..0c6c8feab 100644 --- a/src/Entities/Pickup.cpp +++ b/src/Entities/Pickup.cpp @@ -17,7 +17,8 @@ -class cPickupCombiningCallback +class cPickupCombiningCallback : + public cEntityCallback { public: cPickupCombiningCallback(Vector3d a_Position, cPickup * a_Pickup) : @@ -27,21 +28,21 @@ public: { } - bool operator () (cEntity & a_Entity) + virtual bool Item(cEntity * a_Entity) override { - ASSERT(a_Entity.IsTicking()); - if (!a_Entity.IsPickup() || (a_Entity.GetUniqueID() <= m_Pickup->GetUniqueID()) || !a_Entity.IsOnGround()) + ASSERT(a_Entity->IsTicking()); + if (!a_Entity->IsPickup() || (a_Entity->GetUniqueID() <= m_Pickup->GetUniqueID()) || !a_Entity->IsOnGround()) { return false; } - Vector3d EntityPos = a_Entity.GetPosition(); + Vector3d EntityPos = a_Entity->GetPosition(); double Distance = (EntityPos - m_Position).Length(); - auto & OtherPickup = static_cast<cPickup &>(a_Entity); - cItem & Item = OtherPickup.GetItem(); - if ((Distance < 1.2) && Item.IsEqual(m_Pickup->GetItem()) && OtherPickup.CanCombine()) + cPickup * OtherPickup = static_cast<cPickup *>(a_Entity); + cItem & Item = OtherPickup->GetItem(); + if ((Distance < 1.2) && Item.IsEqual(m_Pickup->GetItem()) && OtherPickup->CanCombine()) { short CombineCount = Item.m_ItemCount; if ((CombineCount + m_Pickup->GetItem().m_ItemCount) > Item.GetMaxStackSize()) @@ -63,16 +64,16 @@ public: int DiffX = FloorC(m_Pickup->GetPosX() * 32.0) - FloorC(EntityPos.x * 32.0); int DiffY = FloorC(m_Pickup->GetPosY() * 32.0) - FloorC(EntityPos.y * 32.0); int DiffZ = FloorC(m_Pickup->GetPosZ() * 32.0) - FloorC(EntityPos.z * 32.0); - a_Entity.GetWorld()->BroadcastEntityRelMove(a_Entity, static_cast<char>(DiffX), static_cast<char>(DiffY), static_cast<char>(DiffZ)); + a_Entity->GetWorld()->BroadcastEntityRelMove(*a_Entity, static_cast<char>(DiffX), static_cast<char>(DiffY), static_cast<char>(DiffZ)); /* End of experimental animation */ - a_Entity.Destroy(); + a_Entity->Destroy(); // Reset the timer m_Pickup->SetAge(0); } else { - a_Entity.GetWorld()->BroadcastEntityMetadata(a_Entity); + a_Entity->GetWorld()->BroadcastEntityMetadata(*a_Entity); } m_FoundMatchingPickup = true; } diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 93368f6fb..fb2274cad 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1005,21 +1005,36 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) void cPlayer::NotifyNearbyWolves(cPawn * a_Opponent, bool a_IsPlayerInvolved) { ASSERT(a_Opponent != nullptr); + class LookForWolves : public cEntityCallback + { + public: + cPlayer * m_Player; + cPawn * m_Attacker; + bool m_IsPlayerInvolved; + + LookForWolves(cPlayer * a_Me, cPawn * a_MyAttacker, bool a_PlayerInvolved) : + m_Player(a_Me), + m_Attacker(a_MyAttacker), + m_IsPlayerInvolved(a_PlayerInvolved) + { + } - m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), 16), [&] (cEntity & a_Entity) + virtual bool Item(cEntity * a_Entity) override { - if (a_Entity.IsMob()) + if (a_Entity->IsMob()) { - auto & Mob = static_cast<cMonster&>(a_Entity); - if (Mob.GetMobType() == mtWolf) + cMonster * Mob = static_cast<cMonster*>(a_Entity); + if (Mob->GetMobType() == mtWolf) { - auto & Wolf = static_cast<cWolf&>(Mob); - Wolf.ReceiveNearbyFightInfo(GetUUID(), a_Opponent, a_IsPlayerInvolved); + cWolf * Wolf = static_cast<cWolf*>(Mob); + Wolf->ReceiveNearbyFightInfo(m_Player->GetUUID(), m_Attacker, m_IsPlayerInvolved); } } return false; } - ); + } Callback(this, a_Opponent, a_IsPlayerInvolved); + + m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), 16), Callback); } @@ -2417,12 +2432,17 @@ void cPlayer::HandleFloater() { return; } - m_World->DoWithEntityByID(m_FloaterID, [](cEntity & a_Entity) + class cFloaterCallback : + public cEntityCallback + { + public: + virtual bool Item(cEntity * a_Entity) override { - a_Entity.Destroy(true); + a_Entity->Destroy(true); return true; } - ); + } Callback; + m_World->DoWithEntityByID(m_FloaterID, Callback); SetIsFishing(false); } @@ -2666,18 +2686,29 @@ bool cPlayer::DoesPlacingBlocksIntersectEntity(const sSetBlockVector & a_Blocks) cWorld * World = GetWorld(); // Check to see if any entity intersects any block being placed - return !World->ForEachEntityInBox(PlacingBounds, [&](cEntity & a_Entity) + class DoesIntersectBlock : public cEntityCallback + { + public: + const std::vector<cBoundingBox> & m_BoundingBoxes; + + // The distance inside the block the entity can still be. + const double EPSILON = 0.0005; + + DoesIntersectBlock(const std::vector<cBoundingBox> & a_BoundingBoxes) : + m_BoundingBoxes(a_BoundingBoxes) { - // The distance inside the block the entity can still be. - const double EPSILON = 0.0005; + } - if (!a_Entity.DoesPreventBlockPlacement()) + virtual bool Item(cEntity * a_Entity) override + { + if (!a_Entity->DoesPreventBlockPlacement()) { return false; } - cBoundingBox EntBox(a_Entity.GetPosition(), a_Entity.GetWidth() / 2, a_Entity.GetHeight()); - for (auto BlockBox : PlacementBoxes) + cBoundingBox EntBox(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight()); + for (auto BlockBox: m_BoundingBoxes) { + // Put in a little bit of wiggle room BlockBox.Expand(-EPSILON, -EPSILON, -EPSILON); if (EntBox.DoesIntersect(BlockBox)) @@ -2687,7 +2718,15 @@ bool cPlayer::DoesPlacingBlocksIntersectEntity(const sSetBlockVector & a_Blocks) } return false; } - ); + } Callback(PlacementBoxes); + + // See if any entities in that bounding box collide with anyone + if (!World->ForEachEntityInBox(PlacingBounds, Callback)) + { + return true; + } + + return false; } diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index 13ebe31bc..c2a1f782d 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -126,7 +126,8 @@ protected: //////////////////////////////////////////////////////////////////////////////// // cProjectileEntityCollisionCallback: -class cProjectileEntityCollisionCallback +class cProjectileEntityCollisionCallback : + public cEntityCallback { public: cProjectileEntityCollisionCallback(cProjectileEntity * a_Projectile, const Vector3d & a_Pos, const Vector3d & a_NextPos) : @@ -139,11 +140,11 @@ public: } - bool operator () (cEntity & a_Entity) + virtual bool Item(cEntity * a_Entity) override { if ( - (&a_Entity == m_Projectile) || // Do not check collisions with self - (a_Entity.GetUniqueID() == m_Projectile->GetCreatorUniqueID()) // Do not check whoever shot the projectile + (a_Entity == m_Projectile) || // Do not check collisions with self + (a_Entity->GetUniqueID() == m_Projectile->GetCreatorUniqueID()) // Do not check whoever shot the projectile ) { // Don't check creator only for the first 5 ticks so that projectiles can collide with the creator @@ -153,7 +154,7 @@ public: } } - cBoundingBox EntBox(a_Entity.GetPosition(), a_Entity.GetWidth() / 2, a_Entity.GetHeight()); + cBoundingBox EntBox(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight()); // Instead of colliding the bounding box with another bounding box in motion, we collide an enlarged bounding box with a hairline. // The results should be good enough for our purposes @@ -167,20 +168,20 @@ public: } if ( - !a_Entity.IsMob() && - !a_Entity.IsMinecart() && + !a_Entity->IsMob() && + !a_Entity->IsMinecart() && ( - !a_Entity.IsPlayer() || - static_cast<cPlayer &>(a_Entity).IsGameModeSpectator() + !a_Entity->IsPlayer() || + static_cast<cPlayer *>(a_Entity)->IsGameModeSpectator() ) && - !a_Entity.IsBoat() + !a_Entity->IsBoat() ) { // Not an entity that interacts with a projectile return false; } - if (cPluginManager::Get()->CallHookProjectileHitEntity(*m_Projectile, a_Entity)) + if (cPluginManager::Get()->CallHookProjectileHitEntity(*m_Projectile, *a_Entity)) { // A plugin disagreed. return false; @@ -190,7 +191,7 @@ public: { // The entity is closer than anything we've stored so far, replace it as the potential victim m_MinCoeff = LineCoeff; - m_HitEntity = &a_Entity; + m_HitEntity = a_Entity; } // Don't break the enumeration, we want all the entities @@ -326,13 +327,20 @@ void cProjectileEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_Hi // If we were created by a player and we hit a pawn, notify attacking player's wolves if (a_EntityHit.IsPawn() && (GetCreatorName() != "")) { - auto EntityHit = static_cast<cPawn *>(&a_EntityHit); - m_World->DoWithEntityByID(GetCreatorUniqueID(), [=](cEntity & a_Hitter) + class cNotifyWolves : public cEntityCallback + { + public: + cPawn * m_EntityHit; + + virtual bool Item(cEntity * a_Hitter) override { - static_cast<cPlayer&>(a_Hitter).NotifyNearbyWolves(EntityHit, true); + static_cast<cPlayer*>(a_Hitter)->NotifyNearbyWolves(m_EntityHit, true); return true; } - ); + } Callback; + + Callback.m_EntityHit = static_cast<cPawn*>(&a_EntityHit); + m_World->DoWithEntityByID(GetCreatorUniqueID(), Callback); } } diff --git a/src/Entities/SplashPotionEntity.cpp b/src/Entities/SplashPotionEntity.cpp index 35afe0fea..af4008e83 100644 --- a/src/Entities/SplashPotionEntity.cpp +++ b/src/Entities/SplashPotionEntity.cpp @@ -17,6 +17,60 @@ //////////////////////////////////////////////////////////////////////////////// +// 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); + + static_cast<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( @@ -65,30 +119,8 @@ void cSplashPotionEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_ void cSplashPotionEntity::Splash(const Vector3d & a_HitPos) { - m_World->ForEachEntity([=](cEntity & a_Entity) - { - if (!a_Entity.IsPawn()) - { - // Not an entity that can take effects - return false; - } - - double SplashDistance = (a_Entity.GetPosition() - a_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); - - static_cast<cPawn &>(a_Entity).AddEntityEffect(m_EntityEffectType, m_EntityEffect.GetDuration(), m_EntityEffect.GetIntensity(), Reduction); - return false; - } - ); + cSplashPotionCallback Callback(a_HitPos, m_EntityEffectType, m_EntityEffect); + m_World->ForEachEntity(Callback); m_World->BroadcastSoundParticleEffect( EffectID::PARTICLE_SPLASH_POTION, diff --git a/src/Entities/ThrownEnderPearlEntity.cpp b/src/Entities/ThrownEnderPearlEntity.cpp index cb0b3ada0..4b2e2f9ff 100644 --- a/src/Entities/ThrownEnderPearlEntity.cpp +++ b/src/Entities/ThrownEnderPearlEntity.cpp @@ -74,12 +74,29 @@ void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos) return; } - GetWorld()->FindAndDoWithPlayer(m_CreatorData.m_Name, [=](cPlayer & a_Entity) + class cProjectileCreatorCallbackForPlayers : public cPlayerListCallback + { + public: + cProjectileCreatorCallbackForPlayers(cEntity * a_Attacker, Vector3i a_CallbackHitPos) : + m_Attacker(a_Attacker), + m_HitPos(a_CallbackHitPos) + { + } + + virtual bool Item(cPlayer * a_Entity) override { // Teleport the creator here, make them take 5 damage: - a_Entity.TeleportToCoords(a_HitPos.x, a_HitPos.y + 0.2, a_HitPos.z); - a_Entity.TakeDamage(dtEnderPearl, this, 5, 0); + a_Entity->TeleportToCoords(m_HitPos.x, m_HitPos.y + 0.2, m_HitPos.z); + a_Entity->TakeDamage(dtEnderPearl, m_Attacker, 5, 0); return true; } - ); + + private: + + cEntity * m_Attacker; + Vector3i m_HitPos; + }; + + cProjectileCreatorCallbackForPlayers PCCFP(this, a_HitPos); + GetWorld()->FindAndDoWithPlayer(m_CreatorData.m_Name, PCCFP); } |