diff options
-rw-r--r-- | Server/monsters.ini | 2 | ||||
-rw-r--r-- | src/BoundingBox.cpp | 20 | ||||
-rw-r--r-- | src/BoundingBox.h | 39 | ||||
-rw-r--r-- | src/ClientHandle.cpp | 2 | ||||
-rw-r--r-- | src/Entities/ArrowEntity.cpp | 2 | ||||
-rw-r--r-- | src/Entities/Entity.cpp | 41 | ||||
-rw-r--r-- | src/Entities/Entity.h | 3 | ||||
-rw-r--r-- | src/Entities/Player.cpp | 16 | ||||
-rw-r--r-- | src/Entities/Player.h | 7 | ||||
-rw-r--r-- | src/Entities/ProjectileEntity.cpp | 18 | ||||
-rw-r--r-- | src/Entities/ThrownSnowballEntity.cpp | 2 | ||||
-rw-r--r-- | src/Mobs/Wolf.cpp | 128 | ||||
-rw-r--r-- | src/Mobs/Wolf.h | 17 |
13 files changed, 214 insertions, 83 deletions
diff --git a/Server/monsters.ini b/Server/monsters.ini index f327a38bc..2c8950a0c 100644 --- a/Server/monsters.ini +++ b/Server/monsters.ini @@ -191,7 +191,7 @@ MaxHealth=26 SightDistance=25.0 [Wolf] -AttackDamage=4.0 +AttackDamage=8.0 AttackRange=2.0 AttackRate=1 MaxHealth=20 diff --git a/src/BoundingBox.cpp b/src/BoundingBox.cpp index 64e3c02d2..8e3bb29a9 100644 --- a/src/BoundingBox.cpp +++ b/src/BoundingBox.cpp @@ -37,7 +37,7 @@ public: } ; bool Results[] = {true, true, true, false, true, false}; double LineCoeffs[] = {2, 0.25, 0.5, 0, 0.25, 0}; - + for (size_t i = 0; i < ARRAYCOUNT(LineDefs) / 2; i++) { double LineCoeff; @@ -106,6 +106,16 @@ cBoundingBox::cBoundingBox(const Vector3d & a_Pos, double a_Radius, double a_Hei +cBoundingBox::cBoundingBox(const Vector3d & a_Pos, double a_CubeLength) : + m_Min(a_Pos.x - a_CubeLength / 2, a_Pos.y - a_CubeLength / 2, a_Pos.z - a_CubeLength / 2), + m_Max(a_Pos.x + a_CubeLength / 2, a_Pos.y + a_CubeLength / 2, a_Pos.z + a_CubeLength / 2) +{ +} + + + + + cBoundingBox::cBoundingBox(const cBoundingBox & a_Orig) : m_Min(a_Orig.m_Min), m_Max(a_Orig.m_Max) @@ -269,10 +279,10 @@ bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Min, const Vector3d & a_Face = BLOCK_FACE_NONE; // No faces hit return true; } - + eBlockFace Face = BLOCK_FACE_NONE; double Coeff = Vector3d::NO_INTERSECTION; - + // Check each individual bbox face for intersection with the line, remember the one with the lowest coeff double c = a_Line1.LineCoeffToXYPlane(a_Line2, a_Min.z); if ((c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c)) @@ -310,13 +320,13 @@ bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Min, const Vector3d & Face = (a_Line1.x > a_Line2.x) ? BLOCK_FACE_XP : BLOCK_FACE_XM; Coeff = c; } - + if (Coeff >= Vector3d::NO_INTERSECTION) { // There has been no intersection return false; } - + a_LineCoeff = Coeff; a_Face = Face; return true; diff --git a/src/BoundingBox.h b/src/BoundingBox.h index 1f9d0ebee..c2aa40dc7 100644 --- a/src/BoundingBox.h +++ b/src/BoundingBox.h @@ -27,56 +27,57 @@ public: cBoundingBox(double a_MinX, double a_MaxX, double a_MinY, double a_MaxY, double a_MinZ, double a_MaxZ); cBoundingBox(const Vector3d & a_Min, const Vector3d & a_Max); cBoundingBox(const Vector3d & a_Pos, double a_Radius, double a_Height); + cBoundingBox(const Vector3d & a_Pos, double a_CubeLength); cBoundingBox(const cBoundingBox & a_Orig); - + /** Moves the entire boundingbox by the specified offset */ void Move(double a_OffX, double a_OffY, double a_OffZ); - + /** Moves the entire boundingbox by the specified offset */ void Move(const Vector3d & a_Off); - + /** Expands the bounding box by the specified amount in each direction (so the box becomes larger by 2 * Expand in each direction) */ void Expand(double a_ExpandX, double a_ExpandY, double a_ExpandZ); - + /** Returns true if the two bounding boxes intersect */ bool DoesIntersect(const cBoundingBox & a_Other); - + /** Returns the union of the two bounding boxes */ cBoundingBox Union(const cBoundingBox & a_Other); - + /** Returns true if the point is inside the bounding box */ bool IsInside(const Vector3d & a_Point); - + /** Returns true if the point is inside the bounding box */ bool IsInside(double a_X, double a_Y, double a_Z); - + /** Returns true if a_Other is inside this bounding box */ bool IsInside(cBoundingBox & a_Other); - + /** Returns true if a boundingbox specified by a_Min and a_Max is inside this bounding box */ bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max); - + /** Returns true if the specified point is inside the bounding box specified by its min / max corners */ static bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Point); - + /** Returns true if the specified point is inside the bounding box specified by its min / max corners */ static bool IsInside(const Vector3d & a_Min, const Vector3d & a_Max, double a_X, double a_Y, double a_Z); - + /** Returns true if this bounding box is intersected by the line specified by its two points Also calculates the distance along the line in which the intersection occurs (0 .. 1) Only forward collisions (a_LineCoeff >= 0) are returned. */ bool CalcLineIntersection(const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, eBlockFace & a_Face); - + /** Returns true if the specified bounding box is intersected by the line specified by its two points Also calculates the distance along the line in which the intersection occurs (0 .. 1) and the face hit (BLOCK_FACE_ constants) Only forward collisions (a_LineCoeff >= 0) are returned. */ static bool CalcLineIntersection(const Vector3d & a_Min, const Vector3d & a_Max, const Vector3d & a_Line1, const Vector3d & a_Line2, double & a_LineCoeff, eBlockFace & a_Face); - + // tolua_end - + /** Calculates the intersection of the two bounding boxes; returns true if nonempty */ bool Intersect(const cBoundingBox & a_Other, cBoundingBox & a_Intersection); - + double GetMinX(void) const { return m_Min.x; } double GetMinY(void) const { return m_Min.y; } double GetMinZ(void) const { return m_Min.z; } @@ -84,14 +85,14 @@ public: double GetMaxX(void) const { return m_Max.x; } double GetMaxY(void) const { return m_Max.y; } double GetMaxZ(void) const { return m_Max.z; } - + const Vector3d & GetMin(void) const { return m_Min; } const Vector3d & GetMax(void) const { return m_Max; } - + protected: Vector3d m_Min; Vector3d m_Max; - + } ; // tolua_export diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 6585a38b2..4e882b5d8 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -1642,7 +1642,7 @@ void cClientHandle::HandleUseEntity(UInt32 a_TargetEntityID, bool a_IsLeftClick) m_Me->AddFoodExhaustion(0.3); if (a_Entity->IsPawn()) { - m_Me->NotifyFriendlyWolves(static_cast<cPawn*>(a_Entity)); + m_Me->NotifyNearbyWolves(static_cast<cPawn*>(a_Entity), true); } return true; } diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp index 47789992c..380af101c 100644 --- a/src/Entities/ArrowEntity.cpp +++ b/src/Entities/ArrowEntity.cpp @@ -133,7 +133,7 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) } // a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, KnockbackAmount); // TODO fix knockback. - a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 0); // Until knockback is fixed. + a_EntityHit.TakeDamage(dtRangedAttack, GetCreatorUniqueID(), Damage, 0); // Until knockback is fixed. if (IsOnFire() && !a_EntityHit.IsSubmerged() && !a_EntityHit.IsSwimming()) { diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 69f64eb40..aeb70b552 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -238,6 +238,47 @@ 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) +{ + class cNotifyWolves : 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()) + { + Attacker = static_cast<cPawn*>(a_Attacker); + } + else + { + Attacker = nullptr; + } + + + int FinalDamage = m_RawDamage - m_Entity->GetArmorCoverAgainst(Attacker, m_DamageType, m_RawDamage); + m_Entity->TakeDamage(m_DamageType, Attacker, m_RawDamage, FinalDamage, 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); +} + + + + + void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, int a_FinalDamage, double a_KnockbackAmount) { TakeDamageInfo TDI; diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index fdc5437b3..3715fb5c4 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -263,6 +263,9 @@ public: /** Makes this entity take the specified damage. The final damage is calculated using current armor, then DoTakeDamage() called */ void TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, double a_KnockbackAmount); + /** Makes this entity take the specified damage. The final damage is calculated using current armor, then DoTakeDamage() called */ + void TakeDamage(eDamageType a_DamageType, UInt32 a_Attacker, int a_RawDamage, double a_KnockbackAmount); + /** Makes this entity take the specified damage. The values are packed into a TDI, knockback calculated, then sent through DoTakeDamage() */ void TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_RawDamage, int a_FinalDamage, double a_KnockbackAmount); diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index dd26f1491..767ee2061 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -862,7 +862,7 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) { if (a_TDI.Attacker->IsPawn()) { - NotifyFriendlyWolves(static_cast<cPawn*>(a_TDI.Attacker)); + NotifyNearbyWolves(static_cast<cPawn*>(a_TDI.Attacker), true); } } m_Stats.AddValue(statDamageTaken, FloorC<StatValue>(a_TDI.FinalDamage * 10 + 0.5)); @@ -875,7 +875,7 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) -void cPlayer::NotifyFriendlyWolves(cPawn * a_Opponent) +void cPlayer::NotifyNearbyWolves(cPawn * a_Opponent, bool a_IsPlayerInvolved) { ASSERT(a_Opponent != nullptr); class LookForWolves : public cEntityCallback @@ -883,10 +883,12 @@ void cPlayer::NotifyFriendlyWolves(cPawn * a_Opponent) public: cPlayer * m_Player; cPawn * m_Attacker; + bool m_IsPlayerInvolved; - LookForWolves(cPlayer * a_Me, cPawn * a_MyAttacker) : + LookForWolves(cPlayer * a_Me, cPawn * a_MyAttacker, bool a_PlayerInvolved) : m_Player(a_Me), - m_Attacker(a_MyAttacker) + m_Attacker(a_MyAttacker), + m_IsPlayerInvolved(a_PlayerInvolved) { } @@ -898,14 +900,14 @@ void cPlayer::NotifyFriendlyWolves(cPawn * a_Opponent) if (Mob->GetMobType() == mtWolf) { cWolf * Wolf = static_cast<cWolf*>(Mob); - Wolf->NearbyPlayerIsFighting(m_Player, m_Attacker); + Wolf->ReceiveNearbyFightInfo(m_Player->GetUUID(), m_Attacker, m_IsPlayerInvolved); } } return false; } - } Callback(this, a_Opponent); + } Callback(this, a_Opponent, a_IsPlayerInvolved); - m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), 16, 16), Callback); + m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), 16), Callback); } diff --git a/src/Entities/Player.h b/src/Entities/Player.h index fbb09b815..efd515b23 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -499,8 +499,11 @@ public: Assumes that all the blocks are in currently loaded chunks. */ bool PlaceBlocks(const sSetBlockVector & a_Blocks); - /** Notify friendly wolves that we took damage or did damage to an entity so that they might assist us. */ - void NotifyFriendlyWolves(cPawn * a_Opponent); + /** Notify nearby wolves that the player or one of the player's wolves took damage or did damage to an entity + @param a_Opponent the opponent we're fighting. + @param a_IsPlayerInvolved Should be true if the player took or did damage, and false if one of the player's wolves took or did damage. + */ + void NotifyNearbyWolves(cPawn * a_Opponent, bool a_IsPlayerInvolved); // cEntity overrides: virtual bool IsCrouched (void) const override { return m_IsCrouched; } diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index bb08f38d9..72dccbfb4 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -314,26 +314,24 @@ void cProjectileEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_ void cProjectileEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) { - if (a_EntityHit.IsPawn() && (GetCreatorName() != "")) // If we're hitting a mob or a player and we were created by a player - { + UNUSED(a_HitPos); + // If we were created by a player and we hit a pawn, notify attacking player's wolves + if (a_EntityHit.IsPawn() && (GetCreatorName() != "")) + { class cNotifyWolves : public cEntityCallback { public: cPawn * m_EntityHit; - cNotifyWolves(cPawn * a_Entity) : - m_EntityHit(a_Entity) - { - } - - virtual bool Item(cEntity * a_Player) override + virtual bool Item(cEntity * a_Hitter) override { - static_cast<cPlayer*>(a_Player)->NotifyFriendlyWolves(m_EntityHit); + static_cast<cPlayer*>(a_Hitter)->NotifyNearbyWolves(m_EntityHit, true); return true; } - } Callback(static_cast<cPawn*>(&a_EntityHit)); + } Callback; + Callback.m_EntityHit = static_cast<cPawn*>(&a_EntityHit); m_World->DoWithEntityByID(GetCreatorUniqueID(), Callback); } } diff --git a/src/Entities/ThrownSnowballEntity.cpp b/src/Entities/ThrownSnowballEntity.cpp index ab5429011..ef88bfd18 100644 --- a/src/Entities/ThrownSnowballEntity.cpp +++ b/src/Entities/ThrownSnowballEntity.cpp @@ -41,7 +41,7 @@ void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & } } // TODO: If entity is Ender Crystal, destroy it - a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); + a_EntityHit.TakeDamage(dtRangedAttack, GetCreatorUniqueID(), TotalDamage, 1); m_DestroyTimer = 5; } diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp index 174fee9b1..3be14211b 100644 --- a/src/Mobs/Wolf.cpp +++ b/src/Mobs/Wolf.cpp @@ -18,7 +18,8 @@ cWolf::cWolf(void) : m_IsBegging(false), m_IsAngry(false), m_OwnerName(""), - m_CollarColor(E_META_DYE_ORANGE) + m_CollarColor(E_META_DYE_ORANGE), + m_NotificationCooldown(0) { m_RelativeWalkSpeed = 2; } @@ -29,15 +30,42 @@ cWolf::cWolf(void) : bool cWolf::DoTakeDamage(TakeDamageInfo & a_TDI) { + cEntity * PreviousTarget = m_Target; if (!super::DoTakeDamage(a_TDI)) { return false; } - if (!m_IsTame) + if ((a_TDI.Attacker != nullptr) && a_TDI.Attacker->IsPawn()) { - m_IsAngry = true; + cPawn * Pawn = static_cast<cPawn*>(m_Target); + if (Pawn->IsPlayer()) + { + if (m_IsTame) + { + if ((static_cast<cPlayer*>(Pawn)->GetUUID() == m_OwnerUUID)) + { + m_Target = PreviousTarget; // Do not attack owner + } + else + { + SetIsSitting(false); + NotifyAlliesOfFight(static_cast<cPawn*>(a_TDI.Attacker)); + } + } + else + { + m_IsAngry = true; + } + } + else if (m_IsTame) + { + SetIsSitting(false); + NotifyAlliesOfFight(static_cast<cPawn*>(a_TDI.Attacker)); + } } + + m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face return true; } @@ -46,56 +74,94 @@ bool cWolf::DoTakeDamage(TakeDamageInfo & a_TDI) +void cWolf::NotifyAlliesOfFight(cPawn * a_Opponent) +{ + if (GetOwnerName() == "") + { + return; + } + m_NotificationCooldown = 15; + class cCallback : public cPlayerListCallback + { + virtual bool Item(cPlayer * a_Player) override + { + a_Player->NotifyNearbyWolves(m_Opponent, false); + return false; + } + public: + cPawn * m_Opponent; + } Callback; + + Callback.m_Opponent = a_Opponent; + m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback); +} + bool cWolf::Attack(std::chrono::milliseconds a_Dt) { UNUSED(a_Dt); if ((m_Target != nullptr) && (m_Target->IsPlayer())) { - if (static_cast<cPlayer *>(m_Target)->GetName() != m_OwnerName) - { - return super::Attack(a_Dt); - } - else + if (static_cast<cPlayer *>(m_Target)->GetUUID() == m_OwnerUUID) { m_Target = nullptr; + return false; } } - else - { - return super::Attack(a_Dt); - } - return false; + NotifyAlliesOfFight(static_cast<cPawn*>(m_Target)); + return super::Attack(a_Dt); + } -void cWolf::NearbyPlayerIsFighting(cPlayer * a_Player, cPawn * a_Opponent) +void cWolf::ReceiveNearbyFightInfo(AString a_PlayerID, cPawn * a_Opponent, bool a_IsPlayerInvolved) { - if (a_Opponent == nullptr) + if ( + (a_Opponent == nullptr) || IsSitting() || (!IsTame()) || + (!a_Opponent->IsPawn()) || (a_PlayerID != m_OwnerUUID) + ) { return; } - if ((m_Target == nullptr) && (a_Player->GetName() == m_OwnerName) && !IsSitting() && (a_Opponent->IsPawn())) + + // If we already have a target + if (m_Target != nullptr) { - m_Target = a_Opponent; - if (m_Target->IsPlayer() && static_cast<cPlayer *>(m_Target)->GetName() == m_OwnerName) + // If a wolf is asking for help and we already have a target, do nothing + if (!a_IsPlayerInvolved) { - m_Target = nullptr; // Our owner has hurt himself, avoid attacking them. + return; } - if (m_Target->IsMob() && static_cast<cMonster *>(m_Target)->GetMobType() == mtWolf) + // If a player is asking for help and we already have a target, + // there's a 50% chance of helping and a 50% chance of doing nothing + // This helps spread a wolf pack's targets over several mobs + else if (m_World->GetTickRandomNumber(9)> 4) { - cWolf * Wolf = static_cast<cWolf *>(m_Target); - if (Wolf->GetOwnerUUID() == GetOwnerUUID()) - { - m_Target = nullptr; // Our owner attacked one of their wolves. Abort attacking wolf. - } + return; } } + if (a_Opponent->IsPlayer() && static_cast<cPlayer *>(a_Opponent)->GetUUID() == m_OwnerUUID) + { + return; // Our owner has hurt himself, avoid attacking them. + } + + if (a_Opponent->IsMob() && static_cast<cMonster *>(a_Opponent)->GetMobType() == mtWolf) + { + cWolf * Wolf = static_cast<cWolf *>(a_Opponent); + if (Wolf->GetOwnerUUID() == GetOwnerUUID()) + { + return; // Our owner attacked one of their wolves. Abort attacking wolf. + } + } + + m_Target = a_Opponent; + + } @@ -156,7 +222,7 @@ void cWolf::OnRightClicked(cPlayer & a_Player) } case E_ITEM_DYE: { - if (a_Player.GetName() == m_OwnerName) // Is the player the owner of the dog? + if (a_Player.GetUUID() == m_OwnerUUID) // Is the player the owner of the dog? { SetCollarColor(a_Player.GetEquippedItem().m_ItemDamage); if (!a_Player.IsGameModeCreative()) @@ -168,7 +234,7 @@ void cWolf::OnRightClicked(cPlayer & a_Player) } default: { - if (a_Player.GetName() == m_OwnerName) // Is the player the owner of the dog? + if (a_Player.GetUUID() == m_OwnerUUID) // Is the player the owner of the dog? { SetIsSitting(!IsSitting()); } @@ -188,6 +254,10 @@ void cWolf::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) if (!IsAngry()) { cMonster::Tick(a_Dt, a_Chunk); + if (m_NotificationCooldown > 0) + { + m_NotificationCooldown -= 1; + } } else { @@ -275,13 +345,13 @@ void cWolf::TickFollowPlayer() virtual bool Item(cPlayer * a_Player) override { OwnerPos = a_Player->GetPosition(); - return false; + return true; } public: Vector3d OwnerPos; } Callback; - if (m_World->DoWithPlayer(m_OwnerName, Callback)) + if (m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback)) { // The player is present in the world, follow him: double Distance = (Callback.OwnerPos - GetPosition()).Length(); diff --git a/src/Mobs/Wolf.h b/src/Mobs/Wolf.h index 90d38f15c..70e761469 100644 --- a/src/Mobs/Wolf.h +++ b/src/Mobs/Wolf.h @@ -18,6 +18,7 @@ public: CLASS_PROTODEF(cWolf) + void NotifyAlliesOfFight(cPawn * a_Opponent); virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void OnRightClicked(cPlayer & a_Player) override; virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; @@ -45,13 +46,14 @@ public: m_OwnerUUID = a_NewOwnerUUID; } - /** Notfies the wolf that the player a_Player is being attacked by a_Attacker. - The wolf will then defend the player by attacking a_Attacker if all these conditions are met: - - a_Player is the wolf's owner. - - The wolf is not already attacking a mob. - - The wolf is not sitting. - This is called by cPlayer::NotifyFriendlyWolves whenever a player takes or deals damage and a wolf is nearby. */ - void NearbyPlayerIsFighting(cPlayer * a_Player, cPawn * a_Opponent); + /** Notfies the wolf of a nearby fight. + The wolf may then decide to attack a_Opponent. + If a_IsPlayer is true, then the player whose ID is a_PlayerID is fighting a_Opponent + If false, then a wolf owned by the player whose ID is a_PlayerID is fighting a_Opponent + @param a_PlayerID The ID of the fighting player, or the ID of the owner whose wolf is fighting. + @param a_Opponent The opponent who is being faught. + @param a_IsPlayerInvolved Whether the fighter a player or a wolf. */ + void ReceiveNearbyFightInfo(AString a_PlayerID, cPawn * a_Opponent, bool a_IsPlayerInvolved); virtual void InStateIdle(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; @@ -64,6 +66,7 @@ protected: AString m_OwnerName; AString m_OwnerUUID; int m_CollarColor; + int m_NotificationCooldown; } ; |