diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 20d4fe420..c2373ab71 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -4502,8 +4502,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui if (!me || !me->IsInCombat()) return; - ObjectList* _targets = nullptr; - + Unit* target = nullptr; switch (e.GetTargetType()) { case SMART_TARGET_CREATURE_RANGE: @@ -4513,33 +4512,34 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui case SMART_TARGET_CLOSEST_PLAYER: case SMART_TARGET_PLAYER_RANGE: case SMART_TARGET_PLAYER_DISTANCE: - _targets = GetTargets(e); + { + ObjectList* targets = GetTargets(e); + for (WorldObject* target : *targets) + { + if (IsUnit(target) && me->IsFriendlyTo(target->ToUnit()) && target->ToUnit()->IsAlive() && target->ToUnit()->IsInCombat()) + { + uint32 healthPct = uint32(target->ToUnit()->GetHealthPct()); + if (healthPct > e.event.friendlyHealthPct.maxHpPct || healthPct < e.event.friendlyHealthPct.minHpPct) + { + continue; + } + + target = target->ToUnit(); + break; + } + } + + delete targets; + break; + } + case SMART_TARGET_SELF: + case SMART_TARGET_ACTION_INVOKER: + target = DoSelectLowestHpPercentFriendly((float)e.event.friendlyHealthPct.radius, e.event.friendlyHealthPct.minHpPct, e.event.friendlyHealthPct.maxHpPct); break; default: return; } - if (!_targets) - return; - - Unit* target = nullptr; - - for (ObjectList::const_iterator itr = _targets->begin(); itr != _targets->end(); ++itr) - { - if (IsUnit(*itr) && me->IsFriendlyTo((*itr)->ToUnit()) && (*itr)->ToUnit()->IsAlive() && (*itr)->ToUnit()->IsInCombat()) - { - uint32 healthPct = uint32((*itr)->ToUnit()->GetHealthPct()); - - if (healthPct > e.event.friendlyHealthPct.maxHpPct || healthPct < e.event.friendlyHealthPct.minHpPct) - continue; - - target = (*itr)->ToUnit(); - break; - } - } - - delete _targets; - if (!target) return; @@ -5033,6 +5033,20 @@ Unit* SmartScript::DoSelectLowestHpFriendly(float range, uint32 MinHPDiff) return unit; } +Unit* SmartScript::DoSelectLowestHpPercentFriendly(float range, uint32 minHpPct, uint32 maxHpPct) const +{ + if (!me) + { + return nullptr; + } + + Unit* unit = nullptr; + Acore::MostHPPercentMissingInRange u_check(me, range, minHpPct, maxHpPct); + Acore::UnitLastSearcher searcher(me, unit, u_check); + Cell::VisitGridObjects(me, searcher, range); + return unit; +} + void SmartScript::DoFindFriendlyCC(std::list& _list, float range) { if (!me) diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index 8fc9136cd..ab63b9745 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -85,6 +85,7 @@ public: void OnMoveInLineOfSight(Unit* who); Unit* DoSelectLowestHpFriendly(float range, uint32 MinHPDiff); + Unit* DoSelectLowestHpPercentFriendly(float range, uint32 minHpPct, uint32 maxHpPct) const; void DoFindFriendlyCC(std::list& _list, float range); void DoFindFriendlyMissingBuff(std::list& list, float range, uint32 spellid); Unit* DoFindClosestFriendlyInRange(float range, bool playerOnly); diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 54f36d279..fb98247a1 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -1138,6 +1138,13 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_TARGET_PLAYER_RANGE: case SMART_TARGET_PLAYER_DISTANCE: break; + case SMART_TARGET_SELF: + case SMART_TARGET_ACTION_INVOKER: + if (!NotNULL(e, e.event.friendlyHealthPct.radius)) + { + return false; + } + break; default: LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses invalid target_type {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType()); return false; diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index bf8b0731e..dc5b60dc6 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -419,6 +419,7 @@ struct SmartEvent uint32 maxHpPct; uint32 repeatMin; uint32 repeatMax; + uint32 radius; } friendlyHealthPct; struct diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 19f1dc9bf..654f0aa27 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -787,6 +787,30 @@ namespace Acore uint32 i_hp; }; + class MostHPPercentMissingInRange + { + public: + MostHPPercentMissingInRange(Unit const* obj, float range, uint32 minHpPct, uint32 maxHpPct) : + i_obj(obj), i_range(range), i_minHpPct(minHpPct), i_maxHpPct(maxHpPct), i_hpPct(101.f) { } + + bool operator()(Unit* u) + { + if (u->IsAlive() && u->IsInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && + i_minHpPct <= u->GetHealthPct() && u->GetHealthPct() <= i_maxHpPct && u->GetHealthPct() < i_hpPct) + { + i_hpPct = u->GetHealthPct(); + return true; + } + + return false; + } + + private: + Unit const* i_obj; + float i_range; + float i_minHpPct, i_maxHpPct, i_hpPct; + }; + class FriendlyCCedInRange { public: