From b875d77dc8b1acb8d37ba6675c0415da886bdce4 Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Thu, 25 Feb 2021 15:40:05 +0100 Subject: [PATCH] Core/SAI: refactored SMART_EVENT_FRIENDLY_HEALTH_PCT to reflect the behavior of SMART_EVENT_FRIENDLY_HEALTH * added radius event parameter to limit the search range of the executing creature * moved the pct check to a macro and corrected the selection logic to support all target types --- .../world/4.3.4/2021_02_25_01_world.sql | 3 ++ .../game/AI/ScriptedAI/ScriptedCreature.cpp | 4 +- .../game/AI/SmartScripts/SmartScript.cpp | 54 ++++++++----------- src/server/game/AI/SmartScripts/SmartScript.h | 1 + .../game/AI/SmartScripts/SmartScriptMgr.cpp | 20 ++----- .../game/AI/SmartScripts/SmartScriptMgr.h | 1 + .../game/Grids/Notifiers/GridNotifiers.h | 26 ++++++++- .../IcecrownCitadel/icecrown_citadel.cpp | 4 +- 8 files changed, 59 insertions(+), 54 deletions(-) create mode 100644 sql/updates/world/4.3.4/2021_02_25_01_world.sql diff --git a/sql/updates/world/4.3.4/2021_02_25_01_world.sql b/sql/updates/world/4.3.4/2021_02_25_01_world.sql new file mode 100644 index 00000000000..c3210979712 --- /dev/null +++ b/sql/updates/world/4.3.4/2021_02_25_01_world.sql @@ -0,0 +1,3 @@ +UPDATE `smart_scripts` SET `event_param5`= `event_param4` WHERE `event_type`= 74; +UPDATE `smart_scripts` SET `event_param4`= `event_param3` WHERE `event_type`= 74; +UPDATE `smart_scripts` SET `event_param3`= 100 WHERE `event_type`= 74; -- normalizing all existing uses of this smart event to 100 yards diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 69cb56e0aaa..f5b3c2bed65 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -374,8 +374,8 @@ void ScriptedAI::DoTeleportAll(float x, float y, float z, float o) Unit* ScriptedAI::DoSelectLowestHpFriendly(float range, uint32 minHPDiff) { Unit* unit = nullptr; - Trinity::MostHPMissingInRange u_check(me, range, minHPDiff); - Trinity::UnitLastSearcher searcher(me, unit, u_check); + Trinity::FriendlyMostHPMissingInRange u_check(me, range, minHPDiff); + Trinity::UnitLastSearcher searcher(me, unit, u_check); Cell::VisitAllObjects(me, searcher, range); return unit; diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 000f97a8f25..0bf32068644 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -3381,40 +3381,15 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui if (!me || !me->IsEngaged()) return; - ObjectVector targets; - switch (e.GetTargetType()) + Unit* target = DoSelectLowestHpPctFriendly((float)e.event.friendlyHealthPct.radius, e.event.friendlyHealthPct.minHpPct, e.event.friendlyHealthPct.maxHpPct); + if (!target || !target->IsEngaged()) { - case SMART_TARGET_CREATURE_RANGE: - case SMART_TARGET_CREATURE_GUID: - case SMART_TARGET_CREATURE_DISTANCE: - case SMART_TARGET_CLOSEST_CREATURE: - case SMART_TARGET_CLOSEST_PLAYER: - case SMART_TARGET_PLAYER_RANGE: - case SMART_TARGET_PLAYER_DISTANCE: - GetTargets(targets, e); - break; - default: - return; - } - - Unit* unitTarget = nullptr; - 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; - - unitTarget = target->ToUnit(); - break; - } - } - - if (!unitTarget) + // if there are at least two same npcs, they will perform the same action immediately even if this is useless... + RecalcTimer(e, 1000, 3000); return; + } - ProcessTimedAction(e, e.event.friendlyHealthPct.repeatMin, e.event.friendlyHealthPct.repeatMax, unitTarget); + ProcessTimedAction(e, e.event.friendlyHealthPct.repeatMin, e.event.friendlyHealthPct.repeatMax, target); break; } case SMART_EVENT_DISTANCE_CREATURE: @@ -3845,8 +3820,21 @@ Unit* SmartScript::DoSelectLowestHpFriendly(float range, uint32 MinHPDiff) Unit* unit = nullptr; - Trinity::MostHPMissingInRange u_check(me, range, MinHPDiff); - Trinity::UnitLastSearcher searcher(me, unit, u_check); + Trinity::FriendlyMostHPMissingInRange u_check(me, range, MinHPDiff); + Trinity::UnitLastSearcher searcher(me, unit, u_check); + Cell::VisitGridObjects(me, searcher, range); + return unit; +} + +Unit* SmartScript::DoSelectLowestHpPctFriendly(float range, uint8 hpPctMin, uint8 hpPctMax) +{ + if (!me) + return nullptr; + + Unit* unit = nullptr; + + Trinity::FriendlyMostHPPctMissingInRange u_check(me, range, hpPctMin, hpPctMax); + Trinity::UnitLastSearcher searcher(me, unit, u_check); Cell::VisitGridObjects(me, searcher, range); return unit; } diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index b568244fe93..231b9c86c9c 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -65,6 +65,7 @@ class TC_GAME_API SmartScript void OnMoveInLineOfSight(Unit* who); Unit* DoSelectLowestHpFriendly(float range, uint32 MinHPDiff); + Unit* DoSelectLowestHpPctFriendly(float range, uint8 hpPctMin, uint8 hpPctMax); 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 775e8073b58..5e74f36f442 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -938,6 +938,10 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) break; } case SMART_EVENT_FRIENDLY_HEALTH_PCT: + { + if (!NotNULL(e, e.event.friendlyHealth.radius)) + return false; + if (!IsMinMaxValid(e, e.event.friendlyHealthPct.repeatMin, e.event.friendlyHealthPct.repeatMax)) return false; @@ -946,22 +950,8 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u has pct value above 100, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType()); return false; } - - switch (e.GetTargetType()) - { - case SMART_TARGET_CREATURE_RANGE: - case SMART_TARGET_CREATURE_GUID: - case SMART_TARGET_CREATURE_DISTANCE: - case SMART_TARGET_CLOSEST_CREATURE: - case SMART_TARGET_CLOSEST_PLAYER: - case SMART_TARGET_PLAYER_RANGE: - case SMART_TARGET_PLAYER_DISTANCE: - break; - default: - TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid target_type %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType()); - return false; - } break; + } case SMART_EVENT_DISTANCE_CREATURE: if (e.event.distance.guid == 0 && e.event.distance.entry == 0) { diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index 7a52b0bce6d..cb3b40e4a6e 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -409,6 +409,7 @@ struct SmartEvent { uint32 minHpPct; uint32 maxHpPct; + uint32 radius; uint32 repeatMin; uint32 repeatMax; } friendlyHealthPct; diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 1927d945236..4c71dd73073 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -794,10 +794,11 @@ namespace Trinity // Unit checks - class MostHPMissingInRange + class FriendlyMostHPMissingInRange { public: - MostHPMissingInRange(Unit const* obj, float range, uint32 hp) : i_obj(obj), i_range(range), i_hp(hp) { } + FriendlyMostHPMissingInRange(Unit const* obj, float range, uint32 hp) : i_obj(obj), i_range(range), i_hp(hp) { } + bool operator()(Unit* u) { if (u->IsAlive() && u->IsInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && u->GetMaxHealth() - u->GetHealth() > i_hp) @@ -813,6 +814,27 @@ namespace Trinity uint32 i_hp; }; + class FriendlyMostHPPctMissingInRange + { + public: + FriendlyMostHPPctMissingInRange(Unit const* obj, float range, uint8 hpPctMin, uint8 hpPctMax) : i_obj(obj), i_range(range), i_hpPctMin(hpPctMin), i_hpPctMax(hpPctMax) { } + + bool operator()(Unit* u) + { + if (u->IsAlive() && u->IsInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && u->GetHealthPct() > i_hpPctMin && u->GetHealthPct() < i_hpPctMax) + { + i_hpPctMax = u->GetHealthPct(); + return true; + } + return false; + } + private: + Unit const* i_obj; + float i_range; + uint8 i_hpPctMin; + uint8 i_hpPctMax; + }; + class FriendlyBelowHpPctEntryInRange { public: diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index 64b625f410e..04e6c5618fc 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -1331,8 +1331,8 @@ class npc_captain_arnath : public CreatureScript Creature* FindFriendlyCreature() const { Creature* target = nullptr; - Trinity::MostHPMissingInRange u_check(me, 60.0f, 0); - Trinity::CreatureLastSearcher searcher(me, target, u_check); + Trinity::FriendlyMostHPMissingInRange u_check(me, 60.0f, 0); + Trinity::CreatureLastSearcher searcher(me, target, u_check); Cell::VisitGridObjects(me, searcher, 60.0f); return target; }