From cf030b70b224059918fa04d865e7a7cbd13ec352 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Tue, 9 Feb 2021 11:29:50 -0500 Subject: [PATCH] Core/SAI: Added SAI support for new areatriggers Port From (https://github.com/TrinityCore/TrinityCore/commit/875fd4107f29c00f148ea77c6ff6d49f7ca92b76) --- Source/Framework/Constants/SmartAIConst.cs | 5 +- Source/Game/AI/SmartScripts/SmartAI.cs | 31 ++++++++++ Source/Game/AI/SmartScripts/SmartAIManager.cs | 56 +++++++++++++----- Source/Game/AI/SmartScripts/SmartScript.cs | 59 ++++++++++++++++--- .../DataStorage/AreaTriggerDataStorage.cs | 8 +-- .../Game/Entities/AreaTrigger/AreaTrigger.cs | 2 +- .../AreaTrigger/AreaTriggerTemplate.cs | 6 ++ Source/Game/Entities/Creature/Creature.cs | 6 +- Source/Game/Entities/GameObject/GameObject.cs | 2 + Source/Game/Entities/Unit/Unit.cs | 2 +- Source/Scripts/Smart/SmartAI.cs | 11 ++++ 11 files changed, 156 insertions(+), 32 deletions(-) diff --git a/Source/Framework/Constants/SmartAIConst.cs b/Source/Framework/Constants/SmartAIConst.cs index 9c9c05c95..7bc5740d1 100644 --- a/Source/Framework/Constants/SmartAIConst.cs +++ b/Source/Framework/Constants/SmartAIConst.cs @@ -31,7 +31,9 @@ namespace Framework.Constants Transport = 7, Instance = 8, TimedActionlist = 9, - Scene = 10, // done + Scene = 10, + AreaTriggerEntity = 11, + AreaTriggerEntityServerside = 12, Max = 11 } @@ -49,6 +51,7 @@ namespace Framework.Constants public const uint Instance = 256; public const uint TimedActionlist = 512; public const uint Scene = 1024; + public const uint AreatrigggerEntity = 2048; } public enum SmartPhase diff --git a/Source/Game/AI/SmartScripts/SmartAI.cs b/Source/Game/AI/SmartScripts/SmartAI.cs index f549d85c3..e5fd0d9f4 100644 --- a/Source/Game/AI/SmartScripts/SmartAI.cs +++ b/Source/Game/AI/SmartScripts/SmartAI.cs @@ -1176,6 +1176,37 @@ namespace Game.AI bool _gossipReturn; } + public class SmartAreaTriggerAI : AreaTriggerAI + { + public SmartAreaTriggerAI(AreaTrigger areaTrigger) : base(areaTrigger) { } + + public override void OnInitialize() + { + GetScript().OnInitialize(at); + } + + public override void OnUpdate(uint diff) + { + GetScript().OnUpdate(diff); + } + + public override void OnUnitEnter(Unit unit) + { + GetScript().ProcessEventsFor(SmartEvents.AreatriggerOntrigger, unit); + } + + public void SetScript9(SmartScriptHolder e, uint entry, Unit invoker) + { + if (invoker) + GetScript().mLastInvoker = invoker.GetGUID(); + GetScript().SetScript9(e, entry); + } + + SmartScript GetScript() { return mScript; } + + SmartScript mScript; + } + public enum SmartEscortState { None = 0x00, //nothing in progress diff --git a/Source/Game/AI/SmartScripts/SmartAIManager.cs b/Source/Game/AI/SmartScripts/SmartAIManager.cs index 4b5bc8aa8..fff69fe49 100644 --- a/Source/Game/AI/SmartScripts/SmartAIManager.cs +++ b/Source/Game/AI/SmartScripts/SmartAIManager.cs @@ -112,6 +112,24 @@ namespace Game.AI } case SmartScriptType.TimedActionlist: break;//nothing to check, really + case SmartScriptType.AreaTriggerEntity: + { + if (Global.AreaTriggerDataStorage.GetAreaTriggerTemplate(new AreaTriggerId((uint)temp.entryOrGuid, false)) == null) + { + Log.outError(LogFilter.Sql, $"SmartAIMgr.LoadSmartAIFromDB: AreaTrigger entry ({temp.entryOrGuid} IsServerSide false) does not exist, skipped loading."); + continue; + } + break; + } + case SmartScriptType.AreaTriggerEntityServerside: + { + if (Global.AreaTriggerDataStorage.GetAreaTriggerTemplate(new AreaTriggerId((uint)temp.entryOrGuid, true)) == null) + { + Log.outError(LogFilter.Sql, $"SmartAIMgr.LoadSmartAIFromDB: AreaTrigger entry ({temp.entryOrGuid} IsServerSide true) does not exist, skipped loading."); + continue; + } + break; + } default: Log.outError(LogFilter.Sql, "SmartAIMgr.LoadSmartAIFromDB: not yet implemented source_type {0}", source_type); continue; @@ -647,6 +665,12 @@ namespace Game.AI } case SmartEvents.AreatriggerOntrigger: { + if (e.Event.areatrigger.id != 0 && (e.GetScriptType() == SmartScriptType.AreaTriggerEntity || e.GetScriptType() == SmartScriptType.AreaTriggerEntityServerside)) + { + Log.outError(LogFilter.Sql, $"SmartAIMgr: Entry {e.entryOrGuid} SourceType {e.GetScriptType()} Event {e.event_id} Action {e.GetActionType()} areatrigger param not supported for SMART_SCRIPT_TYPE_AREATRIGGER_ENTITY and SMART_SCRIPT_TYPE_AREATRIGGER_ENTITY_SERVERSIDE, skipped."); + return false; + } + if (e.Event.areatrigger.id != 0 && !IsAreaTriggerValid(e, e.Event.areatrigger.id)) return false; break; @@ -1593,23 +1617,25 @@ namespace Game.AI Dictionary SmartAITypeMask = new Dictionary { - { SmartScriptType.Creature, SmartScriptTypeMaskId.Creature }, - { SmartScriptType.GameObject, SmartScriptTypeMaskId.Gameobject }, - { SmartScriptType.AreaTrigger, SmartScriptTypeMaskId.Areatrigger }, - { SmartScriptType.Event, SmartScriptTypeMaskId.Event }, - { SmartScriptType.Gossip, SmartScriptTypeMaskId.Gossip }, - { SmartScriptType.Quest, SmartScriptTypeMaskId.Quest }, - { SmartScriptType.Spell, SmartScriptTypeMaskId.Spell }, - { SmartScriptType.Transport, SmartScriptTypeMaskId.Transport }, - { SmartScriptType.Instance, SmartScriptTypeMaskId.Instance }, - { SmartScriptType.TimedActionlist, SmartScriptTypeMaskId.TimedActionlist }, - { SmartScriptType.Scene, SmartScriptTypeMaskId.Scene } + { SmartScriptType.Creature, SmartScriptTypeMaskId.Creature }, + { SmartScriptType.GameObject, SmartScriptTypeMaskId.Gameobject }, + { SmartScriptType.AreaTrigger, SmartScriptTypeMaskId.Areatrigger }, + { SmartScriptType.Event, SmartScriptTypeMaskId.Event }, + { SmartScriptType.Gossip, SmartScriptTypeMaskId.Gossip }, + { SmartScriptType.Quest, SmartScriptTypeMaskId.Quest }, + { SmartScriptType.Spell, SmartScriptTypeMaskId.Spell }, + { SmartScriptType.Transport, SmartScriptTypeMaskId.Transport }, + { SmartScriptType.Instance, SmartScriptTypeMaskId.Instance }, + { SmartScriptType.TimedActionlist, SmartScriptTypeMaskId.TimedActionlist }, + { SmartScriptType.Scene, SmartScriptTypeMaskId.Scene }, + { SmartScriptType.AreaTriggerEntity, SmartScriptTypeMaskId.AreatrigggerEntity }, + { SmartScriptType.AreaTriggerEntityServerside, SmartScriptTypeMaskId.AreatrigggerEntity } }; Dictionary SmartAIEventMask = new Dictionary { { SmartEvents.UpdateIc, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.TimedActionlist }, - { SmartEvents.UpdateOoc, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject + SmartScriptTypeMaskId.Instance }, + { SmartEvents.UpdateOoc, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject + SmartScriptTypeMaskId.Instance + SmartScriptTypeMaskId.AreatrigggerEntity }, { SmartEvents.HealthPct, SmartScriptTypeMaskId.Creature }, { SmartEvents.ManaPct, SmartScriptTypeMaskId.Creature }, { SmartEvents.Aggro, SmartScriptTypeMaskId.Creature }, @@ -1654,7 +1680,7 @@ namespace Game.AI { SmartEvents.TransportRemovePlayer, SmartScriptTypeMaskId.Transport }, { SmartEvents.TransportRelocate, SmartScriptTypeMaskId.Transport }, { SmartEvents.InstancePlayerEnter, SmartScriptTypeMaskId.Instance }, - { SmartEvents.AreatriggerOntrigger, SmartScriptTypeMaskId.Areatrigger }, + { SmartEvents.AreatriggerOntrigger, SmartScriptTypeMaskId.Areatrigger + SmartScriptTypeMaskId.AreatrigggerEntity }, { SmartEvents.QuestAccepted, SmartScriptTypeMaskId.Quest }, { SmartEvents.QuestObjCompletion, SmartScriptTypeMaskId.Quest }, { SmartEvents.QuestRewarded, SmartScriptTypeMaskId.Quest }, @@ -1668,8 +1694,8 @@ namespace Game.AI { SmartEvents.WaypointStopped, SmartScriptTypeMaskId.Creature }, { SmartEvents.WaypointEnded, SmartScriptTypeMaskId.Creature }, { SmartEvents.TimedEventTriggered, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject }, - { SmartEvents.Update, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject }, - { SmartEvents.Link, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject + SmartScriptTypeMaskId.Areatrigger + SmartScriptTypeMaskId.Event + SmartScriptTypeMaskId.Gossip + SmartScriptTypeMaskId.Quest + SmartScriptTypeMaskId.Spell + SmartScriptTypeMaskId.Transport + SmartScriptTypeMaskId.Instance }, + { SmartEvents.Update, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject + SmartScriptTypeMaskId.AreatrigggerEntity }, + { SmartEvents.Link, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject + SmartScriptTypeMaskId.Areatrigger + SmartScriptTypeMaskId.Event + SmartScriptTypeMaskId.Gossip + SmartScriptTypeMaskId.Quest + SmartScriptTypeMaskId.Spell + SmartScriptTypeMaskId.Transport + SmartScriptTypeMaskId.Instance + SmartScriptTypeMaskId.AreatrigggerEntity }, { SmartEvents.GossipSelect, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject }, { SmartEvents.JustCreated, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject }, { SmartEvents.GossipHello, SmartScriptTypeMaskId.Creature + SmartScriptTypeMaskId.Gameobject }, diff --git a/Source/Game/AI/SmartScripts/SmartScript.cs b/Source/Game/AI/SmartScripts/SmartScript.cs index 6c15912ad..bb32f93ae 100644 --- a/Source/Game/AI/SmartScripts/SmartScript.cs +++ b/Source/Game/AI/SmartScripts/SmartScript.cs @@ -1532,7 +1532,7 @@ namespace Game.AI if (creature != null) { if (IsSmart(creature)) - ((SmartAI)creature.GetAI()).SetScript9(e, e.Action.timedActionList.id, GetLastInvoker()); + creature.GetAI().SetScript9(e, e.Action.timedActionList.id, GetLastInvoker()); } else { @@ -1540,7 +1540,17 @@ namespace Game.AI if (go != null) { if (IsSmartGO(go)) - ((SmartGameObjectAI)go.GetAI()).SetScript9(e, e.Action.timedActionList.id, GetLastInvoker()); + go.GetAI().SetScript9(e, e.Action.timedActionList.id, GetLastInvoker()); + } + else + { + AreaTrigger areaTriggerTarget = target.ToAreaTrigger(); + if (areaTriggerTarget != null) + { + SmartAreaTriggerAI atSAI = areaTriggerTarget.GetAI(); + if (atSAI != null) + atSAI.SetScript9(e, e.Action.timedActionList.id, GetLastInvoker()); + } } } } @@ -1623,7 +1633,7 @@ namespace Game.AI if (creature != null) { if (IsSmart(creature)) - ((SmartAI)creature.GetAI()).SetScript9(e, randomId, GetLastInvoker()); + creature.GetAI().SetScript9(e, randomId, GetLastInvoker()); } else { @@ -1631,7 +1641,17 @@ namespace Game.AI if (go != null) { if (IsSmartGO(go)) - ((SmartGameObjectAI)go.GetAI()).SetScript9(e, randomId, GetLastInvoker()); + go.GetAI().SetScript9(e, randomId, GetLastInvoker()); + } + else + { + AreaTrigger areaTriggerTarget = target.ToAreaTrigger(); + if (areaTriggerTarget != null) + { + SmartAreaTriggerAI atSAI = areaTriggerTarget.GetAI(); + if (atSAI != null) + atSAI.SetScript9(e, randomId, GetLastInvoker()); + } } } } @@ -1652,7 +1672,7 @@ namespace Game.AI if (creature != null) { if (IsSmart(creature)) - ((SmartAI)creature.GetAI()).SetScript9(e, id, GetLastInvoker()); + creature.GetAI().SetScript9(e, id, GetLastInvoker()); } else { @@ -1660,7 +1680,17 @@ namespace Game.AI if (go != null) { if (IsSmartGO(go)) - ((SmartGameObjectAI)go.GetAI()).SetScript9(e, id, GetLastInvoker()); + go.GetAI().SetScript9(e, id, GetLastInvoker()); + } + else + { + AreaTrigger areaTriggerTarget = target.ToAreaTrigger(); + if (areaTriggerTarget != null) + { + SmartAreaTriggerAI atSAI = areaTriggerTarget.GetAI(); + if (atSAI != null) + atSAI.SetScript9(e, id, GetLastInvoker()); + } } } } @@ -3584,7 +3614,9 @@ namespace Game.AI public void OnUpdate(uint diff) { - if ((mScriptType == SmartScriptType.Creature || mScriptType == SmartScriptType.GameObject) && GetBaseObject() == null) + if ((mScriptType == SmartScriptType.Creature || mScriptType == SmartScriptType.GameObject + || mScriptType == SmartScriptType.AreaTriggerEntity || mScriptType == SmartScriptType.AreaTriggerEntityServerside) + && !GetBaseObject()) return; InstallEvents();//before UpdateTimers @@ -3707,6 +3739,11 @@ namespace Game.AI e = Global.SmartAIMgr.GetScript((int)trigger.Id, mScriptType); FillScript(e, null, trigger, null); } + else if (areaTrigger != null) + { + e = Global.SmartAIMgr.GetScript((int)areaTrigger.GetEntry(), mScriptType); + FillScript(e, areaTrigger, null, null); + } else if (sceneTemplate != null) { e = Global.SmartAIMgr.GetScript((int)sceneTemplate.SceneId, mScriptType); @@ -3735,6 +3772,11 @@ namespace Game.AI go = obj.ToGameObject(); Log.outDebug(LogFilter.Scripts, "SmartScript.OnInitialize: source is GameObject {0}", go.GetEntry()); break; + case TypeId.AreaTrigger: + areaTrigger = obj.ToAreaTrigger(); + mScriptType = areaTrigger.IsServerSide() ? SmartScriptType.AreaTriggerEntityServerside : SmartScriptType.AreaTriggerEntity; + Log.outDebug(LogFilter.ScriptsAi, $"SmartScript.OnInitialize: source is AreaTrigger {areaTrigger.GetEntry()}, IsServerSide {areaTrigger.IsServerSide()}"); + break; default: Log.outError(LogFilter.Scripts, "SmartScript.OnInitialize: Unhandled TypeID !WARNING!"); return; @@ -4056,6 +4098,7 @@ namespace Game.AI { me = m; go = null; + areaTrigger = null; } } @@ -4066,6 +4109,7 @@ namespace Game.AI { me = null; go = o; + areaTrigger = null; } } } @@ -4130,6 +4174,7 @@ namespace Game.AI GameObject go; ObjectGuid goOrigGUID; AreaTriggerRecord trigger; + AreaTrigger areaTrigger; SceneTemplate sceneTemplate; Spell spellTemplate; SmartScriptType mScriptType; diff --git a/Source/Game/DataStorage/AreaTriggerDataStorage.cs b/Source/Game/DataStorage/AreaTriggerDataStorage.cs index 64f43b16a..b5e921bb7 100644 --- a/Source/Game/DataStorage/AreaTriggerDataStorage.cs +++ b/Source/Game/DataStorage/AreaTriggerDataStorage.cs @@ -42,7 +42,7 @@ namespace Game.DataStorage { do { - AreaTriggerId areaTriggerId = new() { Id = templateActions.Read(0), IsServerSide = templateActions.Read(1) == 1 }; + AreaTriggerId areaTriggerId = new(templateActions.Read(0), templateActions.Read(1) == 1); AreaTriggerAction action; action.Param = templateActions.Read(3); @@ -128,7 +128,7 @@ namespace Game.DataStorage do { AreaTriggerTemplate areaTriggerTemplate = new AreaTriggerTemplate(); - areaTriggerTemplate.Id = new() { Id = templates.Read(0), IsServerSide = templates.Read(1) == 1 }; + areaTriggerTemplate.Id = new(templates.Read(0), templates.Read(1) == 1); AreaTriggerTypes type = (AreaTriggerTypes)templates.Read(2); if (type >= AreaTriggerTypes.Max) @@ -176,7 +176,7 @@ namespace Game.DataStorage miscTemplate.MiscId = areatriggerSpellMiscs.Read(0); uint areatriggerId = areatriggerSpellMiscs.Read(1); - miscTemplate.Template = GetAreaTriggerTemplate(new AreaTriggerId() { Id = areatriggerId, IsServerSide = false }); + miscTemplate.Template = GetAreaTriggerTemplate(new AreaTriggerId(areatriggerId, false)); if (miscTemplate.Template == null) { @@ -290,7 +290,7 @@ namespace Game.DataStorage do { ulong spawnId = templates.Read(0); - AreaTriggerId areaTriggerId = new() { Id = templates.Read(1), IsServerSide = templates.Read(2) == 1 }; + AreaTriggerId areaTriggerId = new(templates.Read(1), templates.Read(2) == 1); WorldLocation location = new(templates.Read(3), templates.Read(4), templates.Read(5), templates.Read(6), templates.Read(7)); if (GetAreaTriggerTemplate(areaTriggerId) == null) diff --git a/Source/Game/Entities/AreaTrigger/AreaTrigger.cs b/Source/Game/Entities/AreaTrigger/AreaTrigger.cs index 866d3cd37..de5858fff 100644 --- a/Source/Game/Entities/AreaTrigger/AreaTrigger.cs +++ b/Source/Game/Entities/AreaTrigger/AreaTrigger.cs @@ -969,7 +969,7 @@ namespace Game.Entities base.ClearUpdateMask(remove); } - AreaTriggerAI GetAI() { return _ai; } + public T GetAI() where T : AreaTriggerAI { return (T)_ai; } public bool IsServerSide() { return _areaTriggerTemplate.Id.IsServerSide; } diff --git a/Source/Game/Entities/AreaTrigger/AreaTriggerTemplate.cs b/Source/Game/Entities/AreaTrigger/AreaTriggerTemplate.cs index 234c0e34f..67af58ef2 100644 --- a/Source/Game/Entities/AreaTrigger/AreaTriggerTemplate.cs +++ b/Source/Game/Entities/AreaTrigger/AreaTriggerTemplate.cs @@ -192,6 +192,12 @@ namespace Game.Entities public uint Id; public bool IsServerSide; + public AreaTriggerId(uint id, bool isServerSide) + { + Id = id; + IsServerSide = isServerSide; + } + public override int GetHashCode() { return Id.GetHashCode() ^ IsServerSide.GetHashCode(); diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 10ecf1781..1b57ac0ed 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -1540,7 +1540,7 @@ namespace Game.Entities public override bool CanAlwaysSee(WorldObject obj) { - if (IsAIEnabled && GetAI().CanSeeAlways(obj)) + if (IsAIEnabled && GetAI().CanSeeAlways(obj)) return true; return false; @@ -3038,12 +3038,12 @@ namespace Game.Entities public bool IsInEvadeMode() { return HasUnitState(UnitState.Evade); } public bool IsEvadingAttacks() { return IsInEvadeMode() || CanNotReachTarget(); } - public new CreatureAI GetAI() + public override CreatureAI GetAI() { return (CreatureAI)i_AI; } - public T GetAI() where T : UnitAI + public T GetAI() where T : CreatureAI { return (T)i_AI; } diff --git a/Source/Game/Entities/GameObject/GameObject.cs b/Source/Game/Entities/GameObject/GameObject.cs index d979ca939..313b89e8a 100644 --- a/Source/Game/Entities/GameObject/GameObject.cs +++ b/Source/Game/Entities/GameObject/GameObject.cs @@ -2779,6 +2779,8 @@ namespace Game.Entities public GameObjectAI GetAI() { return m_AI; } + public T GetAI() where T : GameObjectAI { return (T)m_AI; } + public uint GetDisplayId() { return m_gameObjectData.DisplayID; } public uint GetFaction() { return m_gameObjectData.FactionTemplate; } diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index 734ede26a..8a8ea0c5c 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -1112,7 +1112,7 @@ namespace Game.Entities return m_vehicle != null && m_vehicle == vehicle.GetVehicleKit(); } - public UnitAI GetAI() { return i_AI; } + public virtual UnitAI GetAI() { return i_AI; } public void SetAI(UnitAI newAI) { i_AI = newAI; } public bool IsPossessing() diff --git a/Source/Scripts/Smart/SmartAI.cs b/Source/Scripts/Smart/SmartAI.cs index 2fac78466..a377faf6c 100644 --- a/Source/Scripts/Smart/SmartAI.cs +++ b/Source/Scripts/Smart/SmartAI.cs @@ -42,6 +42,17 @@ namespace Scripts.Smart } } + [Script] + class SmartAreaTriggerEntityScript : AreaTriggerEntityScript + { + public SmartAreaTriggerEntityScript() : base("SmartAreaTriggerAI") { } + + public override AreaTriggerAI GetAI(AreaTrigger areaTrigger) + { + return new SmartAreaTriggerAI(areaTrigger); + } + } + [Script] class SmartScene : SceneScript {