From 6df3ca3a3ba11e57bb162b64a3be287279f6331e Mon Sep 17 00:00:00 2001 From: hondacrx Date: Sun, 27 Feb 2022 14:29:40 -0500 Subject: [PATCH] Core/SAI: Add SMART_ACTION_BECOME_PERSONAL_CLONE_FOR_PLAYER Port From (https://github.com/TrinityCore/TrinityCore/commit/f383c0ea214cc4da2d02b81e26297d77ff59c7ed) --- Source/Framework/Constants/SmartAIConst.cs | 1 + Source/Game/AI/SmartScripts/SmartAI.cs | 4 +-- Source/Game/AI/SmartScripts/SmartAIManager.cs | 17 ++++++++++ Source/Game/AI/SmartScripts/SmartScript.cs | 33 ++++++++++++++++--- Source/Game/Entities/Object/WorldObject.cs | 16 +++++++++ 5 files changed, 65 insertions(+), 6 deletions(-) diff --git a/Source/Framework/Constants/SmartAIConst.cs b/Source/Framework/Constants/SmartAIConst.cs index 24061f045..932da2f33 100644 --- a/Source/Framework/Constants/SmartAIConst.cs +++ b/Source/Framework/Constants/SmartAIConst.cs @@ -397,6 +397,7 @@ namespace Framework.Constants SetUninteractible = 146, // 0/1 ActivateGameobject = 147, // GameObjectActions AddToStoredTargetList = 148, // varID + BecomePersonalCloneForPlayer = 149, // summonType 1-8, duration in ms End } diff --git a/Source/Game/AI/SmartScripts/SmartAI.cs b/Source/Game/AI/SmartScripts/SmartAI.cs index 55877a7c7..d7d47c44e 100644 --- a/Source/Game/AI/SmartScripts/SmartAI.cs +++ b/Source/Game/AI/SmartScripts/SmartAI.cs @@ -925,9 +925,9 @@ namespace Game.AI GetScript().ProcessEventsFor(SmartEvents.FollowCompleted, player); } - public void SetTimedActionList(SmartScriptHolder e, uint entry, Unit invoker) + public void SetTimedActionList(SmartScriptHolder e, uint entry, Unit invoker, uint startFromEventId = 0) { - GetScript().SetTimedActionList(e, entry, invoker); + GetScript().SetTimedActionList(e, entry, invoker, startFromEventId); } public override void OnGameEvent(bool start, ushort eventId) diff --git a/Source/Game/AI/SmartScripts/SmartAIManager.cs b/Source/Game/AI/SmartScripts/SmartAIManager.cs index d0412151a..f2f6da4c0 100644 --- a/Source/Game/AI/SmartScripts/SmartAIManager.cs +++ b/Source/Game/AI/SmartScripts/SmartAIManager.cs @@ -1588,6 +1588,15 @@ namespace Game.AI case SmartActions.DespawnSpawngroup: case SmartActions.AddToStoredTargetList: break; + case SmartActions.BecomePersonalCloneForPlayer: + { + if (e.Action.becomePersonalClone.type < (uint)TempSummonType.TimedOrDeadDespawn || e.Action.becomePersonalClone.type > (uint)TempSummonType.ManualDespawn) + { + Log.outError(LogFilter.Sql, $"SmartAIMgr: {e} uses incorrect TempSummonType {e.Action.becomePersonalClone.type}, skipped."); + return false; + } + break; + } default: Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Not handled action_type({0}), event_type({1}), Entry {2} SourceType {3} Event {4}, skipped.", e.GetActionType(), e.GetEventType(), e.EntryOrGuid, e.GetScriptType(), e.EventId); return false; @@ -2619,6 +2628,9 @@ namespace Game.AI [FieldOffset(4)] public AddToStoredTargets addToStoredTargets; + [FieldOffset(4)] + public BecomePersonalClone becomePersonalClone; + [FieldOffset(4)] public Raw raw; @@ -3162,6 +3174,11 @@ namespace Game.AI { public uint id; } + public struct BecomePersonalClone + { + public uint type; + public uint duration; + } public struct Raw { public uint param1; diff --git a/Source/Game/AI/SmartScripts/SmartScript.cs b/Source/Game/AI/SmartScripts/SmartScript.cs index 1531d6166..f76df2071 100644 --- a/Source/Game/AI/SmartScripts/SmartScript.cs +++ b/Source/Game/AI/SmartScripts/SmartScript.cs @@ -2466,6 +2466,27 @@ namespace Game.AI } break; } + case SmartActions.BecomePersonalCloneForPlayer: + { + foreach (WorldObject target in targets) + { + if (!IsPlayer(target)) + continue; + + ObjectGuid privateObjectOwner = target.GetGUID(); + Creature summon = GetBaseObject().SummonPersonalClone((TempSummonType)e.Action.becomePersonalClone.type, e.Action.becomePersonalClone.duration, 0, 0, privateObjectOwner); + if (summon != null) + { + if (IsSmart(summon)) + ((SmartAI)summon.GetAI()).SetTimedActionList(e, (uint)e.EntryOrGuid, target.ToUnit(), e.EventId + 1); + + } + } + + // action list will continue on personal clones + _timedActionList.RemoveAll(script => { return script.EventId > e.EventId; }); + break; + } default: Log.outError(LogFilter.Sql, "SmartScript.ProcessAction: Entry {0} SourceType {1}, Event {2}, Unhandled Action type {3}", e.EntryOrGuid, e.GetScriptType(), e.EventId, e.GetActionType()); break; @@ -3879,15 +3900,17 @@ namespace Game.AI bool needCleanup = true; if (!_timedActionList.Empty()) { - foreach (var holder in _timedActionList) + for (int i = 0; i < _timedActionList.Count; ++i) { - if (holder.EnableTimed) + SmartScriptHolder scriptHolder = _timedActionList[i]; + if (scriptHolder.EnableTimed) { - UpdateTimer(holder, diff); + UpdateTimer(scriptHolder, diff); needCleanup = false; } } } + if (needCleanup) _timedActionList.Clear(); @@ -4129,7 +4152,7 @@ namespace Game.AI return searcher.GetTarget(); } - public void SetTimedActionList(SmartScriptHolder e, uint entry, Unit invoker) + public void SetTimedActionList(SmartScriptHolder e, uint entry, Unit invoker, uint startFromEventId = 0) { // Do NOT allow to start a new actionlist if a previous one is already running, unless explicitly allowed. We need to always finish the current actionlist if (e.Action.timedActionList.allowOverride == 0 && !_timedActionList.Empty()) @@ -4140,6 +4163,8 @@ namespace Game.AI if (_timedActionList.Empty()) return; + _timedActionList.RemoveAll(script => { return script.EventId < startFromEventId; }); + mTimedActionListInvoker = invoker != null ? invoker.GetGUID() : ObjectGuid.Empty; for (var i = 0; i < _timedActionList.Count; ++i) { diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index 681a5931d..050906b94 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -1442,6 +1442,22 @@ namespace Game.Entities return null; } + public TempSummon SummonPersonalClone(TempSummonType despawnType = TempSummonType.ManualDespawn, uint despawnTime = 0, uint vehId = 0, uint spellId = 0, ObjectGuid privateObjectOwner = default) + { + Map map = GetMap(); + if (map != null) + { + TempSummon summon = map.SummonCreature(GetEntry(), GetPosition(), null, despawnTime, this, spellId, vehId, privateObjectOwner); + if (summon != null) + { + summon.SetTempSummonType(despawnType); + return summon; + } + } + + return null; + } + public GameObject SummonGameObject(uint entry, float x, float y, float z, float ang, Quaternion rotation, uint respawnTime, GameObjectSummonType summonType = GameObjectSummonType.TimedOrCorpseDespawn) { if (x == 0 && y == 0 && z == 0)