From 1de52e5570f5bd669932fffcc20b9abe63dd0f71 Mon Sep 17 00:00:00 2001 From: UltraNix <80540499+UltraNix@users.noreply.github.com> Date: Thu, 19 Jan 2023 20:08:51 +0100 Subject: [PATCH] =?UTF-8?q?fix(Core/Formations):=20Implemented=20new=20cre?= =?UTF-8?q?ature=20formation=20flag:=20GROUP=5F=E2=80=A6=20(#14537)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix(Core/Formations): Implemented new creature formation flag: GROUP_AI_FLAG_ACQUIRE_NEW_TARGET_ON_EVADE. Fixes #14494 --- .../rev_1673079889836910900.sql | 2 + .../game/Entities/Creature/CreatureGroups.cpp | 65 +++++++++++++++++-- .../game/Entities/Creature/CreatureGroups.h | 28 ++++---- src/server/game/Entities/Unit/Unit.cpp | 10 +++ 4 files changed, 85 insertions(+), 20 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1673079889836910900.sql diff --git a/data/sql/updates/pending_db_world/rev_1673079889836910900.sql b/data/sql/updates/pending_db_world/rev_1673079889836910900.sql new file mode 100644 index 000000000..a8ccc8f23 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1673079889836910900.sql @@ -0,0 +1,2 @@ +-- +UPDATE `creature_formations` SET `groupAI`=`groupAI`|0x020 WHERE `leaderGUID` IN (84634,84648); diff --git a/src/server/game/Entities/Creature/CreatureGroups.cpp b/src/server/game/Entities/Creature/CreatureGroups.cpp index 871101b2b..c24edb79b 100644 --- a/src/server/game/Entities/Creature/CreatureGroups.cpp +++ b/src/server/game/Entities/Creature/CreatureGroups.cpp @@ -208,24 +208,75 @@ void CreatureGroup::MemberEngagingTarget(Creature* member, Unit* target) for (auto const& itr : m_members) { Creature* pMember = itr.first; - if (m_leader) // avoid crash if leader was killed and reset. - LOG_DEBUG("entities.unit", "GROUP ATTACK: group instance id {} calls member instid {}", m_leader->GetInstanceId(), member->GetInstanceId()); - - //Skip one check - if (pMember == member) + if (!pMember) + { continue; + } - if (!pMember->IsAlive()) + if (pMember == member || !pMember->IsAlive() || pMember->GetVictim()) + { continue; + } - if (pMember->GetVictim()) + if (pMember == m_leader && !(groupAI & std::underlying_type_t(GroupAIFlags::GROUP_AI_FLAG_LEADER_ASSIST_MEMBER))) + { continue; + } if (pMember->IsValidAttackTarget(target) && pMember->AI()) + { pMember->AI()->AttackStart(target); + } } } +Unit* CreatureGroup::GetNewTargetForMember(Creature* member) +{ + uint8 const groupAI = sFormationMgr->CreatureGroupMap[member->GetSpawnId()].groupAI; + if (!(groupAI & std::underlying_type_t(GroupAIFlags::GROUP_AI_FLAG_ACQUIRE_NEW_TARGET_ON_EVADE))) + { + return nullptr; + } + + if (member == m_leader) + { + if (!(groupAI & std::underlying_type_t(GroupAIFlags::GROUP_AI_FLAG_MEMBER_ASSIST_LEADER))) + { + return nullptr; + } + } + else if (!(groupAI & std::underlying_type_t(GroupAIFlags::GROUP_AI_FLAG_LEADER_ASSIST_MEMBER))) + { + return nullptr; + } + + for (auto const& itr : m_members) + { + Creature* pMember = itr.first; + if (!pMember) + { + continue; + } + + if (pMember == member || !pMember->IsAlive() || !pMember->GetVictim()) + { + continue; + } + + if (pMember == m_leader && !(groupAI & std::underlying_type_t(GroupAIFlags::GROUP_AI_FLAG_MEMBER_ASSIST_LEADER))) + { + continue; + } + + if (member->IsValidAttackTarget(pMember->GetVictim())) + { + return pMember->GetVictim(); + } + } + + return nullptr; +} + void CreatureGroup::MemberEvaded(Creature* member) { uint8 const groupAI = sFormationMgr->CreatureGroupMap[member->GetSpawnId()].groupAI; diff --git a/src/server/game/Entities/Creature/CreatureGroups.h b/src/server/game/Entities/Creature/CreatureGroups.h index c3a9fc13a..b424b3503 100644 --- a/src/server/game/Entities/Creature/CreatureGroups.h +++ b/src/server/game/Entities/Creature/CreatureGroups.h @@ -28,22 +28,23 @@ class CreatureGroup; enum class GroupAIFlags : uint16 { - GROUP_AI_FLAG_MEMBER_ASSIST_LEADER = 0x001, - GROUP_AI_FLAG_LEADER_ASSIST_MEMBER = 0x002, - GROUP_AI_FLAG_EVADE_TOGETHER = 0x004, - GROUP_AI_FLAG_RESPAWN_ON_EVADE = 0x008, - GROUP_AI_FLAG_DONT_RESPAWN_LEADER_ON_EVADE = 0x010, - //GROUP_AI_FLAG_UNK3 = 0x010, - //GROUP_AI_FLAG_UNK4 = 0x020, - //GROUP_AI_FLAG_UNK5 = 0x040, - //GROUP_AI_FLAG_UNK6 = 0x080, - //GROUP_AI_FLAG_UNK7 = 0x100, - GROUP_AI_FLAG_FOLLOW_LEADER = 0x200, + GROUP_AI_FLAG_MEMBER_ASSIST_LEADER = 0x001, + GROUP_AI_FLAG_LEADER_ASSIST_MEMBER = 0x002, + GROUP_AI_FLAG_EVADE_TOGETHER = 0x004, + GROUP_AI_FLAG_RESPAWN_ON_EVADE = 0x008, + GROUP_AI_FLAG_DONT_RESPAWN_LEADER_ON_EVADE = 0x010, + GROUP_AI_FLAG_ACQUIRE_NEW_TARGET_ON_EVADE = 0x020, + //GROUP_AI_FLAG_UNK5 = 0x040, + //GROUP_AI_FLAG_UNK6 = 0x080, + //GROUP_AI_FLAG_UNK7 = 0x100, + GROUP_AI_FLAG_FOLLOW_LEADER = 0x200, - GROUP_AI_FLAG_EVADE_MASK = GROUP_AI_FLAG_EVADE_TOGETHER | GROUP_AI_FLAG_RESPAWN_ON_EVADE, + GROUP_AI_FLAG_ASSIST_MASK = GROUP_AI_FLAG_MEMBER_ASSIST_LEADER | GROUP_AI_FLAG_LEADER_ASSIST_MEMBER, + GROUP_AI_FLAG_EVADE_MASK = GROUP_AI_FLAG_EVADE_TOGETHER | GROUP_AI_FLAG_RESPAWN_ON_EVADE, // Used to verify valid and usable flags - GROUP_AI_FLAG_SUPPORTED = GROUP_AI_FLAG_MEMBER_ASSIST_LEADER | GROUP_AI_FLAG_LEADER_ASSIST_MEMBER | GROUP_AI_FLAG_EVADE_MASK | GROUP_AI_FLAG_FOLLOW_LEADER + GROUP_AI_FLAG_SUPPORTED = GROUP_AI_FLAG_ASSIST_MASK | GROUP_AI_FLAG_EVADE_MASK | GROUP_AI_FLAG_DONT_RESPAWN_LEADER_ON_EVADE | + GROUP_AI_FLAG_FOLLOW_LEADER | GROUP_AI_FLAG_ACQUIRE_NEW_TARGET_ON_EVADE }; struct FormationInfo @@ -108,6 +109,7 @@ public: void LeaderMoveTo(float x, float y, float z, bool run); void MemberEngagingTarget(Creature* member, Unit* target); + Unit* GetNewTargetForMember(Creature* member); void MemberEvaded(Creature* member); void RespawnFormation(bool force = false); [[nodiscard]] bool IsFormationInCombat(); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 2a124c523..d9b177cd8 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -14687,6 +14687,16 @@ Unit* Creature::SelectVictim() return nullptr; } + // Last chance: creature group + if (CreatureGroup* group = GetFormation()) + { + if (Unit* groupTarget = group->GetNewTargetForMember(this)) + { + SetInFront(groupTarget); + return groupTarget; + } + } + // enter in evade mode in other case AI()->EnterEvadeMode();