From bbc0c0769794bde29a38a13825c9fdea38106606 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Wed, 23 Feb 2022 16:28:32 -0500 Subject: [PATCH] Core/SmartAI: allow AreaTrigger SAI scripts to use the player triggering it as base object for actions and targeting Port From (https://github.com/TrinityCore/TrinityCore/commit/1ddde5ca3cac8ac03239882778af3702b59d582d) --- Source/Game/AI/CoreAI/UnitAI.cs | 28 ++--- Source/Game/AI/PlayerAI/PlayerAI.cs | 2 +- Source/Game/AI/ScriptedAI/ScriptedAI.cs | 4 +- Source/Game/AI/SmartScripts/SmartScript.cs | 119 +++++++-------------- Source/Scripts/Smart/SmartAI.cs | 14 +-- 5 files changed, 60 insertions(+), 107 deletions(-) diff --git a/Source/Game/AI/CoreAI/UnitAI.cs b/Source/Game/AI/CoreAI/UnitAI.cs index ba4de316e..6f49ad19e 100644 --- a/Source/Game/AI/CoreAI/UnitAI.cs +++ b/Source/Game/AI/CoreAI/UnitAI.cs @@ -119,7 +119,7 @@ namespace Game.AI /// - Has aura with ID (if aura > 0) /// - Does not have aura with ID - (if aura < 0) /// - public Unit SelectTarget(SelectAggroTarget targetType, uint offset = 0, float dist = 0.0f, bool playerOnly = false, bool withTank = true, int aura = 0) + public Unit SelectTarget(SelectTargetMethod targetType, uint offset = 0, float dist = 0.0f, bool playerOnly = false, bool withTank = true, int aura = 0) { return SelectTarget(targetType, offset, new DefaultTargetSelector(me, dist, playerOnly, withTank, aura)); } @@ -128,7 +128,7 @@ namespace Game.AI /// Select the best target (in order) satisfying from the threat list. /// If is nonzero, the first entries in order (or MAXTHREAT order, if is RANDOM) are skipped. /// - public Unit SelectTarget(SelectAggroTarget targetType, uint offset, ICheck selector) + public Unit SelectTarget(SelectTargetMethod targetType, uint offset, ICheck selector) { ThreatManager mgr = GetThreatManager(); // shortcut: if we ignore the first elements, and there are at most elements, then we ignore ALL elements @@ -143,8 +143,8 @@ namespace Game.AI return targetType switch { - SelectAggroTarget.MaxThreat or SelectAggroTarget.MinThreat or SelectAggroTarget.MaxDistance or SelectAggroTarget.MinDistance => targetList[0], - SelectAggroTarget.Random => targetList.SelectRandom(), + SelectTargetMethod.MaxThreat or SelectTargetMethod.MinThreat or SelectTargetMethod.MaxDistance or SelectTargetMethod.MinDistance => targetList[0], + SelectTargetMethod.Random => targetList.SelectRandom(), _ => null, }; } @@ -160,7 +160,7 @@ namespace Game.AI /// - Does not have aura with ID - (if aura < 0) /// The resulting targets are stored in (which is cleared first). /// - public List SelectTargetList(uint num, SelectAggroTarget targetType, uint offset = 0, float dist = 0f, bool playerOnly = false, bool withTank = true, int aura = 0) + public List SelectTargetList(uint num, SelectTargetMethod targetType, uint offset = 0, float dist = 0f, bool playerOnly = false, bool withTank = true, int aura = 0) { return SelectTargetList(num, targetType, offset, new DefaultTargetSelector(me, dist, playerOnly, withTank, aura)); } @@ -169,7 +169,7 @@ namespace Game.AI /// Select the best (up to) targets (in order) satisfying from the threat list and stores them in (which is cleared first). /// If is nonzero, the first entries in order (or MAXTHREAT order, if is RANDOM) are skipped. /// - public List SelectTargetList(uint num, SelectAggroTarget targetType, uint offset, ICheck selector) + public List SelectTargetList(uint num, SelectTargetMethod targetType, uint offset, ICheck selector) { var targetList = new List(); @@ -178,7 +178,7 @@ namespace Game.AI if (mgr.GetThreatListSize() <= offset) return targetList; - if (targetType == SelectAggroTarget.MaxDistance || targetType == SelectAggroTarget.MinDistance) + if (targetType == SelectTargetMethod.MaxDistance || targetType == SelectTargetMethod.MinDistance) { foreach (ThreatReference refe in mgr.GetSortedThreatList()) { @@ -213,11 +213,11 @@ namespace Game.AI } // right now, list is unsorted for DISTANCE types - re-sort by MAXDISTANCE - if (targetType == SelectAggroTarget.MaxDistance || targetType == SelectAggroTarget.MinDistance) - SortByDistance(targetList, targetType == SelectAggroTarget.MinDistance); + if (targetType == SelectTargetMethod.MaxDistance || targetType == SelectTargetMethod.MinDistance) + SortByDistance(targetList, targetType == SelectTargetMethod.MinDistance); // now the list is MAX sorted, reverse for MIN types - if (targetType == SelectAggroTarget.MinThreat) + if (targetType == SelectTargetMethod.MinThreat) targetList.Reverse(); // ignore the first elements @@ -233,7 +233,7 @@ namespace Game.AI if (targetList.Count <= num) return targetList; - if (targetType == SelectAggroTarget.Random) + if (targetType == SelectTargetMethod.Random) targetList = targetList.SelectRandom(num).ToList(); else targetList.Resize(num); @@ -265,7 +265,7 @@ namespace Game.AI if (spellInfo != null) { bool playerOnly = spellInfo.HasAttribute(SpellAttr3.OnlyTargetPlayers); - target = SelectTarget(SelectAggroTarget.Random, 0, spellInfo.GetMaxRange(false), playerOnly); + target = SelectTarget(SelectTargetMethod.Random, 0, spellInfo.GetMaxRange(false), playerOnly); } break; } @@ -286,7 +286,7 @@ namespace Game.AI && targetSelector.Invoke(me.GetVictim())) target = me.GetVictim(); else - target = SelectTarget(SelectAggroTarget.Random, 0, targetSelector); + target = SelectTarget(SelectTargetMethod.Random, 0, targetSelector); } break; } @@ -515,7 +515,7 @@ namespace Game.AI } } - public enum SelectAggroTarget + public enum SelectTargetMethod { Random = 0, // just pick a random target MaxThreat, // prefer targets higher in the threat list diff --git a/Source/Game/AI/PlayerAI/PlayerAI.cs b/Source/Game/AI/PlayerAI/PlayerAI.cs index 6c1613386..0495e14e9 100644 --- a/Source/Game/AI/PlayerAI/PlayerAI.cs +++ b/Source/Game/AI/PlayerAI/PlayerAI.cs @@ -711,7 +711,7 @@ namespace Game.AI { UnitAI charmerAI = charmer.GetAI(); if (charmerAI != null) - return charmerAI.SelectTarget(SelectAggroTarget.Random, 0, new ValidTargetSelectPredicate(this)); + return charmerAI.SelectTarget(SelectTargetMethod.Random, 0, new ValidTargetSelectPredicate(this)); return charmer.GetVictim(); } diff --git a/Source/Game/AI/ScriptedAI/ScriptedAI.cs b/Source/Game/AI/ScriptedAI/ScriptedAI.cs index 5a3c69caf..980e37b12 100644 --- a/Source/Game/AI/ScriptedAI/ScriptedAI.cs +++ b/Source/Game/AI/ScriptedAI/ScriptedAI.cs @@ -706,7 +706,7 @@ namespace Game.AI void _JustEngagedWith() { - Unit target = SelectTarget(SelectAggroTarget.Random, 0, 0.0f, true); + Unit target = SelectTarget(SelectTargetMethod.Random, 0, 0.0f, true); if (target) AttackStart(target); } @@ -714,7 +714,7 @@ namespace Game.AI public override void JustSummoned(Creature summon) { summons.Summon(summon); - Unit target = SelectTarget(SelectAggroTarget.Random, 0, 0.0f, true); + Unit target = SelectTarget(SelectTargetMethod.Random, 0, 0.0f, true); if (target) summon.GetAI().AttackStart(target); } diff --git a/Source/Game/AI/SmartScripts/SmartScript.cs b/Source/Game/AI/SmartScripts/SmartScript.cs index a38e0b341..cd4c2a41d 100644 --- a/Source/Game/AI/SmartScripts/SmartScript.cs +++ b/Source/Game/AI/SmartScripts/SmartScript.cs @@ -44,6 +44,7 @@ namespace Game.AI ObjectGuid _meOrigGUID; GameObject _go; ObjectGuid _goOrigGUID; + Player _atPlayer; AreaTriggerRecord _trigger; AreaTrigger _areaTrigger; SceneTemplate _sceneTemplate; @@ -1181,7 +1182,7 @@ namespace Game.AI { SmartActionSummonCreatureFlags flags = (SmartActionSummonCreatureFlags)e.Action.summonCreature.flags; bool preferUnit = flags.HasAnyFlag(SmartActionSummonCreatureFlags.PreferUnit); - WorldObject summoner = preferUnit ? unit : GetBaseObjectOrUnit(unit); + WorldObject summoner = preferUnit ? unit : GetBaseObjectOrPlayerTrigger() ?? unit; if (summoner == null) break; @@ -2654,7 +2655,7 @@ namespace Game.AI scriptTrigger = tempLastInvoker; } - WorldObject baseObject = GetBaseObject(); + WorldObject baseObject = GetBaseObjectOrPlayerTrigger(); List targets = new(); switch (e.GetTargetType()) @@ -2672,13 +2673,13 @@ namespace Game.AI { if (e.Target.hostilRandom.powerType != 0) { - Unit u = _me.GetAI().SelectTarget(SelectAggroTarget.MaxThreat, 1, new PowerUsersSelector(_me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0)); + Unit u = _me.GetAI().SelectTarget(SelectTargetMethod.MaxThreat, 1, new PowerUsersSelector(_me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0)); if (u != null) targets.Add(u); } else { - Unit u = _me.GetAI().SelectTarget(SelectAggroTarget.MaxThreat, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0); + Unit u = _me.GetAI().SelectTarget(SelectTargetMethod.MaxThreat, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0); if (u != null) targets.Add(u); } @@ -2689,13 +2690,13 @@ namespace Game.AI { if (e.Target.hostilRandom.powerType != 0) { - Unit u = _me.GetAI().SelectTarget(SelectAggroTarget.MinThreat, 1, new PowerUsersSelector(_me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0)); + Unit u = _me.GetAI().SelectTarget(SelectTargetMethod.MinThreat, 1, new PowerUsersSelector(_me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0)); if (u != null) targets.Add(u); } else { - Unit u = _me.GetAI().SelectTarget(SelectAggroTarget.MinThreat, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0); + Unit u = _me.GetAI().SelectTarget(SelectTargetMethod.MinThreat, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0); if (u != null) targets.Add(u); } @@ -2706,13 +2707,13 @@ namespace Game.AI { if (e.Target.hostilRandom.powerType != 0) { - Unit u = _me.GetAI().SelectTarget(SelectAggroTarget.Random, 1, new PowerUsersSelector(_me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0)); + Unit u = _me.GetAI().SelectTarget(SelectTargetMethod.Random, 1, new PowerUsersSelector(_me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0)); if (u != null) targets.Add(u); } else { - Unit u = _me.GetAI().SelectTarget(SelectAggroTarget.Random, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0); + Unit u = _me.GetAI().SelectTarget(SelectTargetMethod.Random, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0); if (u != null) targets.Add(u); } @@ -2723,13 +2724,13 @@ namespace Game.AI { if (e.Target.hostilRandom.powerType != 0) { - Unit u = _me.GetAI().SelectTarget(SelectAggroTarget.Random, 1, new PowerUsersSelector(_me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0)); + Unit u = _me.GetAI().SelectTarget(SelectTargetMethod.Random, 1, new PowerUsersSelector(_me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0)); if (u != null) targets.Add(u); } else { - Unit u = _me.GetAI().SelectTarget(SelectAggroTarget.Random, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0); + Unit u = _me.GetAI().SelectTarget(SelectTargetMethod.Random, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0); if (u != null) targets.Add(u); } @@ -2738,7 +2739,7 @@ namespace Game.AI case SmartTargets.Farthest: if (_me) { - Unit u = _me.GetAI().SelectTarget(SelectAggroTarget.MaxDistance, 0, new FarthestTargetSelector(_me, (float)e.Target.farthest.maxDist, e.Target.farthest.playerOnly != 0, e.Target.farthest.isInLos != 0)); + Unit u = _me.GetAI().SelectTarget(SelectTargetMethod.MaxDistance, 0, new FarthestTargetSelector(_me, (float)e.Target.farthest.maxDist, e.Target.farthest.playerOnly != 0, e.Target.farthest.isInLos != 0)); if (u != null) targets.Add(u); } @@ -3118,7 +3119,7 @@ namespace Game.AI List GetWorldObjectsInDist(float dist) { List targets = new(); - WorldObject obj = GetBaseObject(); + WorldObject obj = GetBaseObjectOrPlayerTrigger(); if (obj == null) return targets; @@ -4039,7 +4040,7 @@ namespace Game.AI } } - public void OnInitialize(WorldObject obj) + public void OnInitialize(WorldObject obj, AreaTriggerRecord at = null, SceneTemplate scene = null, Quest qst = null) { if (obj != null) { @@ -4048,12 +4049,23 @@ namespace Game.AI case TypeId.Unit: _scriptType = SmartScriptType.Creature; _me = obj.ToCreature(); - Log.outDebug(LogFilter.Scripts, "SmartScript.OnInitialize: source is Creature {0}", _me.GetEntry()); + Log.outDebug(LogFilter.Scripts, $"SmartScript.OnInitialize: source is Creature {_me.GetEntry()}"); break; case TypeId.GameObject: _scriptType = SmartScriptType.GameObject; _go = obj.ToGameObject(); - Log.outDebug(LogFilter.Scripts, "SmartScript.OnInitialize: source is GameObject {0}", _go.GetEntry()); + Log.outDebug(LogFilter.Scripts, $"SmartScript.OnInitialize: source is GameObject {_go.GetEntry()}"); + break; + case TypeId.Player: + if (at != null) + { + _scriptType = SmartScriptType.AreaTrigger; + _trigger = at; + _atPlayer = obj.ToPlayer(); + Log.outDebug(LogFilter.ScriptsAi, $"SmartScript::OnInitialize: source is AreaTrigger {_trigger.Id}, triggered by player {_atPlayer.GetGUID()}"); + } + else + Log.outError(LogFilter.Misc, "SmartScript::OnInitialize: !WARNING! Player TypeID is only allowed for AreaTriggers"); break; case TypeId.AreaTrigger: _areaTrigger = obj.ToAreaTrigger(); @@ -4065,76 +4077,13 @@ namespace Game.AI return; } } - else - { - Log.outError(LogFilter.ScriptsAi, "SmartScript.OnInitialize: !WARNING! Initialized WorldObject is Null."); - return; - } - - GetScript();//load copy of script - - foreach (var holder in _events) - InitTimer(holder);//calculate timers for first time use - - ProcessEventsFor(SmartEvents.AiInit); - InstallEvents(); - ProcessEventsFor(SmartEvents.JustCreated); - _counterList.Clear(); - } - - public void OnInitialize(AreaTriggerRecord at) - { - if (at != null) - { - _scriptType = SmartScriptType.AreaTrigger; - _trigger = at; - Log.outDebug(LogFilter.ScriptsAi, "SmartScript.OnInitialize: AreaTrigger {0}", _trigger.Id); - } - else - { - Log.outError(LogFilter.ScriptsAi, "SmartScript.OnInitialize: !WARNING! Initialized AreaTrigger is Null."); - return; - } - - GetScript();//load copy of script - - foreach (var holder in _events) - InitTimer(holder);//calculate timers for first time use - - ProcessEventsFor(SmartEvents.AiInit); - InstallEvents(); - ProcessEventsFor(SmartEvents.JustCreated); - _counterList.Clear(); - } - - public void OnInitialize(SceneTemplate scene) - { - if (scene != null) + else if (scene != null) { _scriptType = SmartScriptType.Scene; _sceneTemplate = scene; - Log.outDebug(LogFilter.ScriptsAi, "SmartScript.OnInitialize: Scene with id {0}", scene.SceneId); + Log.outDebug(LogFilter.ScriptsAi, $"SmartScript.OnInitialize: Scene with id {scene.SceneId}"); } - else - { - Log.outError(LogFilter.ScriptsAi, "SmartScript.OnInitialize: !WARNING! Initialized Scene is Null."); - return; - } - - GetScript();//load copy of script - - foreach (var holder in _events) - InitTimer(holder);//calculate timers for first time use - - ProcessEventsFor(SmartEvents.AiInit); - InstallEvents(); - ProcessEventsFor(SmartEvents.JustCreated); - _counterList.Clear(); - } - - public void OnInitialize(Quest qst) - { - if (qst != null) + else if (qst != null) { _scriptType = SmartScriptType.Quest; _quest = qst; @@ -4142,7 +4091,7 @@ namespace Game.AI } else { - Log.outError(LogFilter.ScriptsAi, "SmartScript.OnInitialize: !WARNING! Initialized quest is Null."); + Log.outError(LogFilter.ScriptsAi, "SmartScript.OnInitialize: !WARNING! Initialized WorldObject is Null."); return; } @@ -4280,7 +4229,11 @@ namespace Game.AI return summoner; } - + WorldObject GetBaseObjectOrPlayerTrigger() + { + return _trigger != null ? _atPlayer : GetBaseObject(); + } + public bool IsUnit(WorldObject obj) { return obj != null && (obj.IsTypeId(TypeId.Unit) || obj.IsTypeId(TypeId.Player)); } public bool IsPlayer(WorldObject obj) { return obj != null && obj.IsTypeId(TypeId.Player); } public bool IsCreature(WorldObject obj) { return obj != null && obj.IsTypeId(TypeId.Unit); } diff --git a/Source/Scripts/Smart/SmartAI.cs b/Source/Scripts/Smart/SmartAI.cs index 28364b711..217f657e1 100644 --- a/Source/Scripts/Smart/SmartAI.cs +++ b/Source/Scripts/Smart/SmartAI.cs @@ -36,7 +36,7 @@ namespace Scripts.Smart Log.outDebug(LogFilter.ScriptsAi, "AreaTrigger {0} is using SmartTrigger script", trigger.Id); SmartScript script = new(); - script.OnInitialize(trigger); + script.OnInitialize(player, trigger); script.ProcessEventsFor(SmartEvents.AreatriggerOntrigger, player, trigger.Id); return true; } @@ -61,28 +61,28 @@ namespace Scripts.Smart public override void OnSceneStart(Player player, uint sceneInstanceID, SceneTemplate sceneTemplate) { SmartScript smartScript = new(); - smartScript.OnInitialize(sceneTemplate); + smartScript.OnInitialize(null, null, sceneTemplate); smartScript.ProcessEventsFor(SmartEvents.SceneStart, player); } public override void OnSceneTriggerEvent(Player player, uint sceneInstanceID, SceneTemplate sceneTemplate, string triggerName) { SmartScript smartScript = new(); - smartScript.OnInitialize(sceneTemplate); + smartScript.OnInitialize(null, null, sceneTemplate); smartScript.ProcessEventsFor(SmartEvents.SceneTrigger, player, 0, 0, false, null, null, triggerName); } public override void OnSceneCancel(Player player, uint sceneInstanceID, SceneTemplate sceneTemplate) { SmartScript smartScript = new(); - smartScript.OnInitialize(sceneTemplate); + smartScript.OnInitialize(null, null, sceneTemplate); smartScript.ProcessEventsFor(SmartEvents.SceneCancel, player); } public override void OnSceneComplete(Player player, uint sceneInstanceID, SceneTemplate sceneTemplate) { SmartScript smartScript = new(); - smartScript.OnInitialize(sceneTemplate); + smartScript.OnInitialize(null, null, sceneTemplate); smartScript.ProcessEventsFor(SmartEvents.SceneComplete, player); } } @@ -96,7 +96,7 @@ namespace Scripts.Smart public override void OnQuestStatusChange(Player player, Quest quest, QuestStatus oldStatus, QuestStatus newStatus) { SmartScript smartScript = new(); - smartScript.OnInitialize(quest); + smartScript.OnInitialize(null, null, null, quest); switch (newStatus) { case QuestStatus.Incomplete: @@ -124,7 +124,7 @@ namespace Scripts.Smart if (slot < SharedConst.MaxQuestLogSize && player.IsQuestObjectiveComplete(slot, quest, objective)) { SmartScript smartScript = new(); - smartScript.OnInitialize(quest); + smartScript.OnInitialize(null, null, null, quest); smartScript.ProcessEventsFor(SmartEvents.QuestObjCompletion, player, objective.Id); } }