Core/SAI: Implement waiting for actions on action list to finish before continuing the action list
Port From (https://github.com/TrinityCore/TrinityCore/commit/5dfac0ef142c1b59e41c51ab2cca48083be4cb9e)
This commit is contained in:
@@ -88,14 +88,14 @@ namespace Framework.Constants
|
||||
Difficulty1_Deprecated = 0x04, //Event only occurs in instance difficulty 1
|
||||
Difficulty2_Deprecated = 0x08, //Event only occurs in instance difficulty 2
|
||||
Difficulty3_Deprecated = 0x10, //Event only occurs in instance difficulty 3
|
||||
Reserved5 = 0x20,
|
||||
ActionlistWaits = 0x20, // Timed action list will wait for action from this event to finish before moving on to next action
|
||||
Reserved6 = 0x40,
|
||||
DebugOnly = 0x80, //Event only occurs in debug build
|
||||
DontReset = 0x100, //Event will not reset in SmartScript.OnReset()
|
||||
WhileCharmed = 0x200, //Event occurs even if AI owner is charmed
|
||||
|
||||
Deprecated = (Difficulty0_Deprecated | Difficulty1_Deprecated | Difficulty2_Deprecated | Difficulty3_Deprecated),
|
||||
All = (NotRepeatable | Deprecated | Reserved5 | Reserved6 | DebugOnly | DontReset | WhileCharmed),
|
||||
All = (NotRepeatable | Deprecated | ActionlistWaits | Reserved6 | DebugOnly | DontReset | WhileCharmed),
|
||||
|
||||
// Temp flags, used only at runtime, never stored in DB
|
||||
TempIgnoreChanceRoll = 0x40000000, //Event occurs no matter what roll_chance_i(e.event.event_chance) returns.
|
||||
@@ -127,7 +127,8 @@ namespace Framework.Constants
|
||||
//CAST_NO_MELEE_IF_OOM = 0x08, //Prevents creature from entering melee if out of mana or out of range
|
||||
//CAST_FORCE_TARGET_SELF = 0x10, //Forces the target to cast this spell on itself
|
||||
AuraNotPresent = 0x20, //Only casts the spell if the target does not have an aura from the spell
|
||||
CombatMove = 0x40 //Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
|
||||
CombatMove = 0x40, //Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
|
||||
WaitForHit = 0x80
|
||||
}
|
||||
|
||||
public enum SmartActionSummonCreatureFlags
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Groups;
|
||||
using Game.Maps;
|
||||
using Game.Scripting.v2;
|
||||
using Game.Spells;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -70,7 +69,7 @@ namespace Game.AI
|
||||
return !_isCharmed;
|
||||
}
|
||||
|
||||
public void StartPath(uint pathId = 0, bool repeat = false, Unit invoker = null, uint nodeId = 0)
|
||||
public void StartPath(uint pathId = 0, bool repeat = false, Unit invoker = null, uint nodeId = 0, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
if (HasEscortState(SmartEscortState.Escorting))
|
||||
StopPath();
|
||||
@@ -96,7 +95,7 @@ namespace Game.AI
|
||||
me.ReplaceAllNpcFlags(NPCFlags.None);
|
||||
}
|
||||
|
||||
me.GetMotionMaster().MovePath(path, _repeatWaypointPath);
|
||||
me.GetMotionMaster().MovePath(path, _repeatWaypointPath, null, null, MovementWalkRunSpeedSelectionMode.Default, null, null, null, true, scriptResult);
|
||||
}
|
||||
|
||||
WaypointPath LoadPath(uint entry)
|
||||
@@ -562,7 +561,7 @@ namespace Game.AI
|
||||
if (me.GetMotionMaster().GetCurrentMovementGeneratorType(MovementSlot.Default) != MovementGeneratorType.Waypoint)
|
||||
if (me.GetWaypointPathId() != 0)
|
||||
me.GetMotionMaster().MovePath(me.GetWaypointPathId(), true);
|
||||
|
||||
|
||||
me.ResumeMovement();
|
||||
}
|
||||
else if (formation.IsFormed())
|
||||
@@ -627,7 +626,7 @@ namespace Game.AI
|
||||
{
|
||||
GetScript().ProcessEventsFor(SmartEvents.SpellHit, caster.ToUnit(), 0, 0, false, spellInfo, caster.ToGameObject());
|
||||
}
|
||||
|
||||
|
||||
public override void SpellHitTarget(WorldObject target, SpellInfo spellInfo)
|
||||
{
|
||||
GetScript().ProcessEventsFor(SmartEvents.SpellHitTarget, target.ToUnit(), 0, 0, false, spellInfo, target.ToGameObject());
|
||||
@@ -647,7 +646,7 @@ namespace Game.AI
|
||||
{
|
||||
GetScript().ProcessEventsFor(SmartEvents.OnSpellStart, null, 0, 0, false, spellInfo);
|
||||
}
|
||||
|
||||
|
||||
public override void DamageTaken(Unit attacker, ref uint damage, DamageEffectType damageType, SpellInfo spellInfo = null)
|
||||
{
|
||||
GetScript().ProcessEventsFor(SmartEvents.Damaged, attacker, damage);
|
||||
@@ -1139,7 +1138,7 @@ namespace Game.AI
|
||||
}
|
||||
|
||||
public override void SetData(uint id, uint value) { SetData(id, value, null); }
|
||||
|
||||
|
||||
public void SetData(uint id, uint value, Unit invoker)
|
||||
{
|
||||
GetScript().ProcessEventsFor(SmartEvents.DataSet, invoker, id, value);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
|
||||
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Framework.Collections;
|
||||
using Framework.Constants;
|
||||
using Framework.Database;
|
||||
using Game.DataStorage;
|
||||
@@ -12,7 +11,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Game.AI.SmartAction;
|
||||
|
||||
namespace Game.AI
|
||||
{
|
||||
@@ -1369,6 +1367,11 @@ namespace Game.AI
|
||||
Log.outError(LogFilter.ScriptsAi, "SmartAIMgr: Not handled event_type({0}), Entry {1} SourceType {2} Event {3} Action {4}, skipped.", e.GetEventType(), e.EntryOrGuid, e.GetScriptType(), e.EventId, e.GetActionType());
|
||||
return false;
|
||||
}
|
||||
if (e.Event.event_flags.HasAnyFlag(SmartEventFlags.ActionlistWaits))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "SmartAIMgr: {e}, uses SMART_EVENT_FLAG_ACTIONLIST_WAITS but is not part of a timed actionlist.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!CheckUnusedEventParams(e))
|
||||
@@ -1506,6 +1509,11 @@ namespace Game.AI
|
||||
Log.outError(LogFilter.Sql, $"SmartAIMgr: {e} Effect: SPELL_EFFECT_KILL_CREDIT: (SpellId: {e.Action.cast.spell} targetA: {spellEffectInfo.TargetA.GetTarget()} - targetB: {spellEffectInfo.TargetB.GetTarget()}) has invalid target for this Action");
|
||||
}
|
||||
}
|
||||
if (e.Action.cast.castFlags.HasAnyFlag((uint)SmartCastFlags.WaitForHit) && !e.Event.event_flags.HasAnyFlag(SmartEventFlags.ActionlistWaits))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "SmartAIMgr: {e} uses SMARTCAST_WAIT_FOR_HIT but is not part of actionlist event that has SMART_EVENT_FLAG_ACTIONLIST_WAITS");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SmartActions.CrossCast:
|
||||
@@ -1538,6 +1546,11 @@ namespace Game.AI
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (e.Action.crossCast.castFlags.HasAnyFlag((uint)SmartCastFlags.WaitForHit) && !e.Event.event_flags.HasAnyFlag(SmartEventFlags.ActionlistWaits))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "SmartAIMgr: {e} uses SMARTCAST_WAIT_FOR_HIT but is not part of actionlist event that has SMART_EVENT_FLAG_ACTIONLIST_WAITS");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SmartActions.InvokerCast:
|
||||
@@ -1552,6 +1565,11 @@ namespace Game.AI
|
||||
case SmartActions.SelfCast:
|
||||
if (!IsSpellValid(e, e.Action.cast.spell))
|
||||
return false;
|
||||
if (e.Action.cast.castFlags.HasAnyFlag((uint)SmartCastFlags.WaitForHit) && !e.Event.event_flags.HasAnyFlag(SmartEventFlags.ActionlistWaits))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "SmartAIMgr: {e} uses SMARTCAST_WAIT_FOR_HIT but is not part of actionlist event that has SMART_EVENT_FLAG_ACTIONLIST_WAITS");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SmartActions.CallAreaexploredoreventhappens:
|
||||
case SmartActions.CallGroupeventhappens:
|
||||
|
||||
@@ -9,6 +9,7 @@ using Game.Groups;
|
||||
using Game.Maps;
|
||||
using Game.Misc;
|
||||
using Game.Movement;
|
||||
using Game.Scripting.v2;
|
||||
using Game.Spells;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -30,6 +31,7 @@ namespace Game.AI
|
||||
List<SmartScriptHolder> _installEvents = new();
|
||||
List<SmartScriptHolder> _timedActionList = new();
|
||||
ObjectGuid mTimedActionListInvoker;
|
||||
ActionBase mTimedActionWaitEvent;
|
||||
Creature _me;
|
||||
ObjectGuid _meOrigGUID;
|
||||
GameObject _go;
|
||||
@@ -185,27 +187,29 @@ namespace Game.AI
|
||||
_talkerEntry = talker.GetEntry();
|
||||
_lastTextID = e.Action.talk.textGroupId;
|
||||
_textTimer = e.Action.talk.duration;
|
||||
|
||||
_useTextTimer = true;
|
||||
Global.CreatureTextMgr.SendChat(talker, (byte)e.Action.talk.textGroupId, talkTarget);
|
||||
uint duration = Global.CreatureTextMgr.SendChat(talker, (byte)e.Action.talk.textGroupId, talkTarget);
|
||||
mTimedActionWaitEvent = CreateTimedActionListWaitEventFor<WaitAction>(e, [GameTime.Now() + TimeSpan.FromMilliseconds(duration)]);
|
||||
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction: SMART_ACTION_TALK: talker: {0} (Guid: {1}), textGuid: {2}",
|
||||
talker.GetName(), talker.GetGUID().ToString(), _textGUID.ToString());
|
||||
break;
|
||||
}
|
||||
case SmartActions.SimpleTalk:
|
||||
{
|
||||
uint duration = 0;
|
||||
foreach (var target in targets)
|
||||
{
|
||||
if (IsCreature(target))
|
||||
Global.CreatureTextMgr.SendChat(target.ToCreature(), (byte)e.Action.simpleTalk.textGroupId, IsPlayer(GetLastInvoker()) ? GetLastInvoker() : null);
|
||||
duration = Math.Max(Global.CreatureTextMgr.SendChat(target.ToCreature(), (byte)e.Action.simpleTalk.textGroupId, IsPlayer(GetLastInvoker()) ? GetLastInvoker() : null), duration);
|
||||
else if (IsPlayer(target) && _me != null)
|
||||
{
|
||||
Unit templastInvoker = GetLastInvoker();
|
||||
Global.CreatureTextMgr.SendChat(_me, (byte)e.Action.simpleTalk.textGroupId, IsPlayer(templastInvoker) ? templastInvoker : null, ChatMsg.Addon, Language.Addon, CreatureTextRange.Normal, 0, SoundKitPlayType.Normal, Team.Other, false, target.ToPlayer());
|
||||
duration = Math.Max(Global.CreatureTextMgr.SendChat(_me, (byte)e.Action.simpleTalk.textGroupId, IsPlayer(templastInvoker) ? templastInvoker : null, ChatMsg.Addon, Language.Addon, CreatureTextRange.Normal, 0, SoundKitPlayType.Normal, Team.Other, false, target.ToPlayer()), duration);
|
||||
}
|
||||
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction. SMART_ACTION_SIMPLE_TALK: talker: {0} (GuidLow: {1}), textGroupId: {2}",
|
||||
target.GetName(), target.GetGUID().ToString(), e.Action.simpleTalk.textGroupId);
|
||||
}
|
||||
mTimedActionWaitEvent = CreateTimedActionListWaitEventFor<WaitAction>(e, [GameTime.Now() + TimeSpan.FromMilliseconds(duration)]);
|
||||
break;
|
||||
}
|
||||
case SmartActions.PlayEmote:
|
||||
@@ -439,6 +443,9 @@ namespace Game.AI
|
||||
}
|
||||
case SmartActions.Cast:
|
||||
{
|
||||
if (targets.Empty())
|
||||
break;
|
||||
|
||||
if (e.Action.cast.targetsLimit > 0 && targets.Count > e.Action.cast.targetsLimit)
|
||||
targets.RandomResize(e.Action.cast.targetsLimit);
|
||||
|
||||
@@ -454,6 +461,8 @@ namespace Game.AI
|
||||
args.TriggerFlags = TriggerCastFlags.FullMask;
|
||||
}
|
||||
|
||||
MultiActionResult<SpellCastResult> waitEvent = CreateTimedActionListWaitEventFor<MultiActionResult<SpellCastResult>>(e);
|
||||
|
||||
foreach (WorldObject target in targets)
|
||||
{
|
||||
if (e.Action.cast.castFlags.HasAnyFlag((uint)SmartCastFlags.AuraNotPresent) && (!target.IsUnit() || target.ToUnit().HasAura(e.Action.cast.spell)))
|
||||
@@ -462,6 +471,11 @@ namespace Game.AI
|
||||
continue;
|
||||
}
|
||||
|
||||
if (waitEvent != null)
|
||||
{
|
||||
args.SetScriptResult(ActionResult<SpellCastResult>.GetResultSetter(waitEvent.CreateAndGetResult()));
|
||||
args.SetScriptWaitsForSpellHit(e.Action.cast.castFlags.HasAnyFlag((uint)SmartCastFlags.WaitForHit));
|
||||
}
|
||||
|
||||
SpellCastResult result = SpellCastResult.BadTargets;
|
||||
if (_me != null)
|
||||
@@ -489,6 +503,9 @@ namespace Game.AI
|
||||
Log.outDebug(LogFilter.ScriptsAi, $"SmartScript::ProcessAction:: SMART_ACTION_CAST:: {(_me != null ? _me.GetGUID() : _go.GetGUID())} casts spell {e.Action.cast.spell} on target {target.GetGUID()} with castflags {e.Action.cast.castFlags}");
|
||||
}
|
||||
|
||||
if (waitEvent != null && !waitEvent.Results.Empty())
|
||||
mTimedActionWaitEvent = waitEvent;
|
||||
|
||||
// If there is at least 1 failed cast and no successful casts at all, retry again on next loop
|
||||
if (failedSpellCast && !successfulSpellCast)
|
||||
{
|
||||
@@ -507,6 +524,8 @@ namespace Game.AI
|
||||
if (e.Action.cast.targetsLimit != 0)
|
||||
targets.RandomResize(e.Action.cast.targetsLimit);
|
||||
|
||||
MultiActionResult<SpellCastResult> waitEvent = CreateTimedActionListWaitEventFor<MultiActionResult<SpellCastResult>>(e);
|
||||
|
||||
CastSpellExtraArgs args = new();
|
||||
if (e.Action.cast.castFlags.HasAnyFlag((uint)SmartCastFlags.Triggered))
|
||||
{
|
||||
@@ -521,11 +540,20 @@ namespace Game.AI
|
||||
if (e.Action.cast.castFlags.HasAnyFlag((uint)SmartCastFlags.AuraNotPresent) && (!target.IsUnit() || target.ToUnit().HasAura(e.Action.cast.spell)))
|
||||
continue;
|
||||
|
||||
if (waitEvent != null)
|
||||
{
|
||||
args.SetScriptResult(ActionResult<SpellCastResult>.GetResultSetter(waitEvent.CreateAndGetResult()));
|
||||
args.SetScriptWaitsForSpellHit(e.Action.cast.castFlags.HasAnyFlag((uint)SmartCastFlags.WaitForHit));
|
||||
}
|
||||
|
||||
if (e.Action.cast.castFlags.HasAnyFlag((uint)SmartCastFlags.InterruptPrevious) && target.IsUnit())
|
||||
target.ToUnit().InterruptNonMeleeSpells(false);
|
||||
|
||||
target.CastSpell(target, e.Action.cast.spell, args);
|
||||
}
|
||||
|
||||
if (waitEvent != null && !waitEvent.Results.Empty())
|
||||
mTimedActionWaitEvent = waitEvent;
|
||||
break;
|
||||
}
|
||||
case SmartActions.InvokerCast:
|
||||
@@ -549,6 +577,8 @@ namespace Game.AI
|
||||
args.TriggerFlags = TriggerCastFlags.FullMask;
|
||||
}
|
||||
|
||||
MultiActionResult<SpellCastResult> waitEvent = CreateTimedActionListWaitEventFor<MultiActionResult<SpellCastResult>>(e);
|
||||
|
||||
foreach (var target in targets)
|
||||
{
|
||||
if (e.Action.cast.castFlags.HasAnyFlag((uint)SmartCastFlags.AuraNotPresent) && (!target.IsUnit() || target.ToUnit().HasAura(e.Action.cast.spell)))
|
||||
@@ -560,9 +590,18 @@ namespace Game.AI
|
||||
if (e.Action.cast.castFlags.HasAnyFlag((uint)SmartCastFlags.InterruptPrevious))
|
||||
tempLastInvoker.InterruptNonMeleeSpells(false);
|
||||
|
||||
if (waitEvent != null)
|
||||
{
|
||||
args.SetScriptResult(ActionResult<SpellCastResult>.GetResultSetter(waitEvent.CreateAndGetResult()));
|
||||
args.SetScriptWaitsForSpellHit(e.Action.cast.castFlags.HasAnyFlag((uint)SmartCastFlags.WaitForHit));
|
||||
}
|
||||
|
||||
tempLastInvoker.CastSpell(target, e.Action.cast.spell, args);
|
||||
Log.outDebug(LogFilter.ScriptsAi, $"SmartScript::ProcessAction:: SMART_ACTION_INVOKER_CAST: Invoker {tempLastInvoker.GetGUID()} casts spell {e.Action.cast.spell} on target {target.GetGUID()} with castflags {e.Action.cast.castFlags}");
|
||||
}
|
||||
|
||||
if (waitEvent != null && !waitEvent.Results.Empty())
|
||||
mTimedActionWaitEvent = waitEvent;
|
||||
break;
|
||||
}
|
||||
case SmartActions.ActivateGobject:
|
||||
@@ -1073,6 +1112,8 @@ namespace Game.AI
|
||||
}
|
||||
case SmartActions.MoveOffset:
|
||||
{
|
||||
MultiActionResult<MovementStopReason> waitEvent = CreateTimedActionListWaitEventFor<MultiActionResult<MovementStopReason>>(e);
|
||||
|
||||
foreach (var target in targets)
|
||||
{
|
||||
if (!IsCreature(target))
|
||||
@@ -1088,8 +1129,16 @@ namespace Game.AI
|
||||
float x = (float)(pos.GetPositionX() + (Math.Cos(o - (Math.PI / 2)) * e.Target.x) + (Math.Cos(o) * e.Target.y));
|
||||
float y = (float)(pos.GetPositionY() + (Math.Sin(o - (Math.PI / 2)) * e.Target.x) + (Math.Sin(o) * e.Target.y));
|
||||
float z = pos.GetPositionZ() + e.Target.z;
|
||||
target.ToCreature().GetMotionMaster().MovePoint(e.Action.moveOffset.PointId, x, y, z);
|
||||
|
||||
ActionResultSetter<MovementStopReason> scriptResult = null;
|
||||
if (waitEvent != null)
|
||||
scriptResult = ActionResult<MovementStopReason>.GetResultSetter(waitEvent.CreateAndGetResult());
|
||||
|
||||
target.ToCreature().GetMotionMaster().MovePoint(e.Action.moveOffset.PointId, x, y, z, true, null, null, MovementWalkRunSpeedSelectionMode.Default, null, scriptResult);
|
||||
}
|
||||
|
||||
if (waitEvent != null && !waitEvent.Results.Empty())
|
||||
mTimedActionWaitEvent = waitEvent;
|
||||
break;
|
||||
}
|
||||
case SmartActions.SetVisibility:
|
||||
@@ -1294,7 +1343,13 @@ namespace Game.AI
|
||||
}
|
||||
}
|
||||
|
||||
_me.GetAI<SmartAI>().StartPath(entry, repeat, unit);
|
||||
ActionResult<MovementStopReason> waitEvent = CreateTimedActionListWaitEventFor<MovementStopReason, ActionResult>(e);
|
||||
ActionResultSetter<MovementStopReason> scriptResult = null;
|
||||
if (waitEvent != null)
|
||||
scriptResult = ActionResult<MovementStopReason>.GetResultSetter(waitEvent);
|
||||
|
||||
_me.GetAI<SmartAI>().StartPath(entry, repeat, unit, 0, scriptResult);
|
||||
mTimedActionWaitEvent = waitEvent;
|
||||
|
||||
uint quest = e.Action.wpStart.quest;
|
||||
uint DespawnTime = e.Action.wpStart.despawnTime;
|
||||
@@ -1368,6 +1423,11 @@ namespace Game.AI
|
||||
if (!targets.Empty())
|
||||
target = targets.SelectRandom();
|
||||
|
||||
ActionResult<MovementStopReason> waitEvent = CreateTimedActionListWaitEventFor<MovementStopReason, ActionResult>(e);
|
||||
ActionResultSetter<MovementStopReason> scriptResult = null;
|
||||
if (waitEvent != null)
|
||||
scriptResult = ActionResult<MovementStopReason>.GetResultSetter(waitEvent);
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
float x, y, z;
|
||||
@@ -1375,6 +1435,7 @@ namespace Game.AI
|
||||
if (e.Action.moveToPos.contactDistance > 0)
|
||||
target.GetContactPoint(_me, out x, out y, out z, e.Action.moveToPos.contactDistance);
|
||||
_me.GetMotionMaster().MovePoint(e.Action.moveToPos.pointId, x + e.Target.x, y + e.Target.y, z + e.Target.z, e.Action.moveToPos.disablePathfinding == 0);
|
||||
mTimedActionWaitEvent = waitEvent;
|
||||
}
|
||||
|
||||
if (e.GetTargetType() != SmartTargets.Position)
|
||||
@@ -1388,7 +1449,8 @@ namespace Game.AI
|
||||
trans.CalculatePassengerPosition(ref dest.posX, ref dest.posY, ref dest.posZ, ref dest.Orientation);
|
||||
}
|
||||
|
||||
_me.GetMotionMaster().MovePoint(e.Action.moveToPos.pointId, dest, e.Action.moveToPos.disablePathfinding == 0);
|
||||
_me.GetMotionMaster().MovePoint(e.Action.moveToPos.pointId, dest, e.Action.moveToPos.disablePathfinding == 0, null, null, MovementWalkRunSpeedSelectionMode.Default, null, scriptResult);
|
||||
mTimedActionWaitEvent = waitEvent;
|
||||
break;
|
||||
}
|
||||
case SmartActions.EnableTempGobj:
|
||||
@@ -1577,6 +1639,8 @@ namespace Game.AI
|
||||
|
||||
List<WorldObject> casters = GetTargets(CreateSmartEvent(SmartEvents.UpdateIc, 0, 0, 0, 0, 0, 0, SmartActions.None, 0, 0, 0, 0, 0, 0, 0, (SmartTargets)e.Action.crossCast.targetType, e.Action.crossCast.targetParam1, e.Action.crossCast.targetParam2, e.Action.crossCast.targetParam3, e.Action.crossCast.targetParam4, e.Action.param_string, 0), unit);
|
||||
|
||||
MultiActionResult<SpellCastResult> waitEvent = CreateTimedActionListWaitEventFor<MultiActionResult<SpellCastResult>>(e);
|
||||
|
||||
CastSpellExtraArgs args = new();
|
||||
if (e.Action.crossCast.castFlags.HasAnyFlag((uint)SmartCastFlags.Triggered))
|
||||
args.TriggerFlags = TriggerCastFlags.FullMask;
|
||||
@@ -1603,9 +1667,18 @@ namespace Game.AI
|
||||
interruptedSpell = true;
|
||||
}
|
||||
|
||||
if (waitEvent != null)
|
||||
{
|
||||
args.SetScriptResult(ActionResult<SpellCastResult>.GetResultSetter(waitEvent.CreateAndGetResult()));
|
||||
args.SetScriptWaitsForSpellHit(e.Action.cast.castFlags.HasAnyFlag((uint)SmartCastFlags.WaitForHit));
|
||||
}
|
||||
|
||||
casterUnit.CastSpell(target, e.Action.crossCast.spell, args);
|
||||
}
|
||||
}
|
||||
|
||||
if (waitEvent != null && !waitEvent.Results.Empty())
|
||||
mTimedActionWaitEvent = waitEvent;
|
||||
break;
|
||||
}
|
||||
case SmartActions.CallRandomTimedActionlist:
|
||||
@@ -1694,9 +1767,24 @@ namespace Game.AI
|
||||
}
|
||||
case SmartActions.ActivateTaxi:
|
||||
{
|
||||
MultiActionResult<MovementStopReason> waitEvent = CreateTimedActionListWaitEventFor<MultiActionResult<MovementStopReason>>(e);
|
||||
|
||||
foreach (var target in targets)
|
||||
{
|
||||
if (IsPlayer(target))
|
||||
target.ToPlayer().ActivateTaxiPathTo(e.Action.taxi.id);
|
||||
{
|
||||
ActionResultSetter<MovementStopReason> scriptResult = null;
|
||||
if (waitEvent != null)
|
||||
scriptResult = ActionResult<MovementStopReason>.GetResultSetter(waitEvent.CreateAndGetResult());
|
||||
|
||||
if (!target.ToPlayer().ActivateTaxiPathTo(e.Action.taxi.id, 0, null, scriptResult))
|
||||
if (scriptResult != null)
|
||||
scriptResult.SetResult(MovementStopReason.Interrupted);
|
||||
}
|
||||
}
|
||||
|
||||
if (waitEvent != null && !waitEvent.Results.Empty())
|
||||
mTimedActionWaitEvent = waitEvent;
|
||||
break;
|
||||
}
|
||||
case SmartActions.RandomMove:
|
||||
@@ -1813,13 +1901,20 @@ namespace Game.AI
|
||||
else if (e.GetTargetType() != SmartTargets.Position)
|
||||
break;
|
||||
|
||||
ActionResult<MovementStopReason> waitEvent = CreateTimedActionListWaitEventFor<MovementStopReason, ActionResult>(e);
|
||||
ActionResultSetter<MovementStopReason> actionResultSetter = null;
|
||||
if (waitEvent != null)
|
||||
actionResultSetter = ActionResult<MovementStopReason>.GetResultSetter(waitEvent);
|
||||
|
||||
if (e.Action.jump.Gravity != 0 || e.Action.jump.UseDefaultGravity != 0)
|
||||
{
|
||||
float gravity = e.Action.jump.UseDefaultGravity != 0 ? (float)MotionMaster.gravity : e.Action.jump.Gravity;
|
||||
_me.GetMotionMaster().MoveJumpWithGravity(pos, e.Action.jump.SpeedXY, gravity, e.Action.jump.PointId);
|
||||
_me.GetMotionMaster().MoveJumpWithGravity(pos, e.Action.jump.SpeedXY, gravity, e.Action.jump.PointId, false, null, null, actionResultSetter);
|
||||
}
|
||||
else
|
||||
_me.GetMotionMaster().MoveJump(pos, e.Action.jump.SpeedXY, e.Action.jump.SpeedZ, e.Action.jump.PointId);
|
||||
_me.GetMotionMaster().MoveJump(pos, e.Action.jump.SpeedXY, e.Action.jump.SpeedZ, e.Action.jump.PointId, false, null, null, actionResultSetter);
|
||||
|
||||
mTimedActionWaitEvent = waitEvent;
|
||||
break;
|
||||
}
|
||||
case SmartActions.GoSetLootState:
|
||||
@@ -1997,11 +2092,7 @@ namespace Game.AI
|
||||
}
|
||||
case SmartActions.StartClosestWaypoint:
|
||||
{
|
||||
List<uint> waypoints = new();
|
||||
var closestWaypointFromList = e.Action.closestWaypointFromList;
|
||||
foreach (var id in new[] { closestWaypointFromList.wp1, closestWaypointFromList.wp2, closestWaypointFromList.wp3, closestWaypointFromList.wp4, closestWaypointFromList.wp5, closestWaypointFromList.wp6 })
|
||||
if (id != 0)
|
||||
waypoints.Add(id);
|
||||
MultiActionResult<MovementStopReason> waitEvent = CreateTimedActionListWaitEventFor<MultiActionResult<MovementStopReason>>(e);
|
||||
|
||||
float distanceToClosest = float.MaxValue;
|
||||
uint closestPathId = 0;
|
||||
@@ -2014,12 +2105,12 @@ namespace Game.AI
|
||||
{
|
||||
if (IsSmart(creature))
|
||||
{
|
||||
foreach (uint pathId in waypoints)
|
||||
var closestWaypointFromList = e.Action.closestWaypointFromList;
|
||||
foreach (uint pathId in new[] { closestWaypointFromList.wp1, closestWaypointFromList.wp2, closestWaypointFromList.wp3, closestWaypointFromList.wp4, closestWaypointFromList.wp5, closestWaypointFromList.wp6 })
|
||||
{
|
||||
WaypointPath path = Global.WaypointMgr.GetPath(pathId);
|
||||
if (path == null || path.Nodes.Empty())
|
||||
continue;
|
||||
|
||||
foreach (var waypoint in path.Nodes)
|
||||
{
|
||||
float distanceToThisNode = creature.GetDistance(waypoint.X, waypoint.Y, waypoint.Z);
|
||||
@@ -2033,10 +2124,19 @@ namespace Game.AI
|
||||
}
|
||||
|
||||
if (closestPathId != 0)
|
||||
((SmartAI)creature.GetAI()).StartPath(closestPathId, true, null, closestWaypointId);
|
||||
{
|
||||
ActionResultSetter<MovementStopReason> actionResultSetter = null;
|
||||
if (waitEvent != null)
|
||||
actionResultSetter = ActionResult<MovementStopReason>.GetResultSetter(waitEvent.CreateAndGetResult());
|
||||
|
||||
creature.GetAI<SmartAI>().StartPath(closestPathId, true, null, closestWaypointId, actionResultSetter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (waitEvent != null && !waitEvent.Results.Empty())
|
||||
mTimedActionWaitEvent = waitEvent;
|
||||
break;
|
||||
}
|
||||
case SmartActions.RandomSound:
|
||||
@@ -3614,6 +3714,9 @@ namespace Game.AI
|
||||
if (e.GetEventType() == SmartEvents.UpdateOoc && (_me != null && _me.IsEngaged()))//can be used with me=NULL (go script)
|
||||
return;
|
||||
|
||||
if (e.GetScriptType() == SmartScriptType.TimedActionlist && mTimedActionWaitEvent != null && !mTimedActionWaitEvent.IsReady())
|
||||
return;
|
||||
|
||||
if (e.Timer < diff)
|
||||
{
|
||||
// delay spell cast event if another spell is being casted
|
||||
@@ -4362,6 +4465,29 @@ namespace Game.AI
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//template<typename Result, typename ConcreteActionImpl = Scripting::v2::ActionResult<Result>, typename...Args>
|
||||
public static ActionResult<Result> CreateTimedActionListWaitEventFor<Result, ConcreteActionImpl>(SmartScriptHolder e, object[] args = null) where ConcreteActionImpl : ActionBase
|
||||
{
|
||||
if (e.GetScriptType() != SmartScriptType.TimedActionlist)
|
||||
return null;
|
||||
|
||||
if (!e.Event.event_flags.HasFlag(SmartEventFlags.ActionlistWaits))
|
||||
return null;
|
||||
|
||||
return (ActionResult<Result>)Activator.CreateInstance(typeof(ActionResult<Result>), args);
|
||||
}
|
||||
|
||||
public static ConcreteActionImpl CreateTimedActionListWaitEventFor<ConcreteActionImpl>(SmartScriptHolder e, object[] args = null) where ConcreteActionImpl : ActionBase
|
||||
{
|
||||
if (e.GetScriptType() != SmartScriptType.TimedActionlist)
|
||||
return null;
|
||||
|
||||
if (!e.Event.event_flags.HasFlag(SmartEventFlags.ActionlistWaits))
|
||||
return null;
|
||||
|
||||
return (ConcreteActionImpl)Activator.CreateInstance(typeof(ConcreteActionImpl), args);
|
||||
}
|
||||
}
|
||||
|
||||
class ObjectGuidList
|
||||
|
||||
@@ -7,7 +7,6 @@ using Framework.Dynamic;
|
||||
using Game.Achievements;
|
||||
using Game.AI;
|
||||
using Game.Arenas;
|
||||
using Game.BattleFields;
|
||||
using Game.BattleGrounds;
|
||||
using Game.BattlePets;
|
||||
using Game.Chat;
|
||||
@@ -22,11 +21,11 @@ using Game.Misc;
|
||||
using Game.Miscellaneous;
|
||||
using Game.Networking;
|
||||
using Game.Networking.Packets;
|
||||
using Game.Scripting.v2;
|
||||
using Game.Spells;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using static Global;
|
||||
|
||||
namespace Game.Entities
|
||||
@@ -6921,7 +6920,7 @@ namespace Game.Entities
|
||||
|
||||
public uint GetDeathTimer() { return m_deathTimer; }
|
||||
|
||||
public bool ActivateTaxiPathTo(List<uint> nodes, Creature npc = null, uint spellid = 0, uint preferredMountDisplay = 0, float? speed = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public bool ActivateTaxiPathTo(List<uint> nodes, Creature npc = null, uint spellid = 0, uint preferredMountDisplay = 0, float? speed = null, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
if (nodes.Count < 2)
|
||||
{
|
||||
@@ -7103,7 +7102,7 @@ namespace Game.Entities
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ActivateTaxiPathTo(uint taxi_path_id, uint spellid = 0, float? speed = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public bool ActivateTaxiPathTo(uint taxi_path_id, uint spellid = 0, float? speed = null, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
var entry = CliDB.TaxiPathStorage.LookupByKey(taxi_path_id);
|
||||
if (entry == null)
|
||||
@@ -7178,7 +7177,7 @@ namespace Game.Entities
|
||||
StartTaxiMovement(mountDisplayId, path, startNode, null, null);
|
||||
}
|
||||
|
||||
void StartTaxiMovement(uint mountDisplayId, uint path, uint pathNode, float? speed, TaskCompletionSource<MovementStopReason> scriptResult)
|
||||
void StartTaxiMovement(uint mountDisplayId, uint path, uint pathNode, float? speed, ActionResultSetter<MovementStopReason> scriptResult)
|
||||
{
|
||||
// remove fake death
|
||||
RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Interacting);
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
using Framework.Constants;
|
||||
using Game.AI;
|
||||
using Game.Entities;
|
||||
using Game.Scripting.v2;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -14,7 +14,7 @@ namespace Game.Movement
|
||||
public const float MIN_QUIET_DISTANCE = 28.0f;
|
||||
public const float MAX_QUIET_DISTANCE = 43.0f;
|
||||
|
||||
public FleeingMovementGenerator(ObjectGuid fleeTargetGUID, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public FleeingMovementGenerator(ObjectGuid fleeTargetGUID, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
_fleeTargetGUID = fleeTargetGUID;
|
||||
_timer = new TimeTracker();
|
||||
@@ -197,7 +197,7 @@ namespace Game.Movement
|
||||
|
||||
public class TimedFleeingMovementGenerator : FleeingMovementGenerator
|
||||
{
|
||||
public TimedFleeingMovementGenerator(ObjectGuid fleeTargetGUID, TimeSpan time, TaskCompletionSource<MovementStopReason> scriptResult = null) : base(fleeTargetGUID, scriptResult)
|
||||
public TimedFleeingMovementGenerator(ObjectGuid fleeTargetGUID, TimeSpan time, ActionResultSetter<MovementStopReason> scriptResult = null) : base(fleeTargetGUID, scriptResult)
|
||||
{
|
||||
_totalFleeTime = new TimeTracker(time);
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ using Framework.Constants;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Maps;
|
||||
using Game.Scripting.v2;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -25,7 +25,7 @@ namespace Game.Movement
|
||||
int _currentNode;
|
||||
List<TaxiNodeChangeInfo> _pointsForPathSwitch = new(); //! node indexes and costs where TaxiPath changes
|
||||
|
||||
public FlightPathMovementGenerator(float? speed, TaskCompletionSource<MovementStopReason> scriptResult)
|
||||
public FlightPathMovementGenerator(float? speed, ActionResultSetter<MovementStopReason> scriptResult)
|
||||
{
|
||||
_speed = speed;
|
||||
Mode = MovementGeneratorMode.Default;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using Framework.Constants;
|
||||
using Game.AI;
|
||||
using Game.Entities;
|
||||
using Game.Scripting.v2;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -24,7 +25,7 @@ namespace Game.Movement
|
||||
|
||||
AbstractFollower _abstractFollower;
|
||||
|
||||
public FollowMovementGenerator(Unit target, float range, ChaseAngle angle, TimeSpan? duration, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public FollowMovementGenerator(Unit target, float range, ChaseAngle angle, TimeSpan? duration, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
_abstractFollower = new AbstractFollower(target);
|
||||
_range = range;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Scripting.v2;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -117,6 +117,6 @@ namespace Game.Movement
|
||||
public uint? ArrivalSpellId;
|
||||
public ObjectGuid? ArrivalSpellTarget;
|
||||
public TimeSpan? Duration;
|
||||
public TaskCompletionSource<MovementStopReason> ScriptResult;
|
||||
public ActionResultSetter<MovementStopReason> ScriptResult;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Scripting.v2;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -57,7 +57,7 @@ namespace Game.Movement
|
||||
float? _totalTurnAngle;
|
||||
uint _diffSinceLastUpdate;
|
||||
|
||||
public RotateMovementGenerator(uint id, RotateDirection direction, TimeSpan? duration, float? turnSpeed, float? totalTurnAngle, TaskCompletionSource<MovementStopReason> scriptResult)
|
||||
public RotateMovementGenerator(uint id, RotateDirection direction, TimeSpan? duration, float? turnSpeed, float? totalTurnAngle, ActionResultSetter<MovementStopReason> scriptResult)
|
||||
{
|
||||
_id = id;
|
||||
_direction = direction;
|
||||
|
||||
@@ -2,10 +2,9 @@
|
||||
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.AI;
|
||||
using Game.Entities;
|
||||
using Game.Scripting.v2;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -15,7 +14,7 @@ namespace Game.Movement
|
||||
public MovementGeneratorPriority Priority;
|
||||
public MovementGeneratorFlags Flags;
|
||||
public UnitState BaseUnitState;
|
||||
public TaskCompletionSource<MovementStopReason> ScriptResult;
|
||||
public ActionResultSetter<MovementStopReason> ScriptResult;
|
||||
|
||||
~MovementGenerator()
|
||||
{
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Scripting.v2;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -22,7 +22,7 @@ namespace Game.Movement
|
||||
float? _closeEnoughDistance;
|
||||
|
||||
public PointMovementGenerator(uint id, float x, float y, float z, bool generatePath, float? speed = null, float? finalOrient = null, Unit faceTarget = null, SpellEffectExtraData spellEffectExtraData = null,
|
||||
MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, float? closeEnoughDistance = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, float? closeEnoughDistance = null, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
_movementId = id;
|
||||
_destination = new Position(x, y, z);
|
||||
@@ -207,7 +207,7 @@ namespace Game.Movement
|
||||
}
|
||||
|
||||
public uint GetId() { return _movementId; }
|
||||
|
||||
|
||||
public override MovementGeneratorType GetMovementGeneratorType()
|
||||
{
|
||||
return MovementGeneratorType.Point;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using Game.Scripting.v2;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -17,7 +18,7 @@ namespace Game.Movement
|
||||
float _wanderDistance;
|
||||
uint _wanderSteps;
|
||||
|
||||
public RandomMovementGenerator(float spawnDist = 0.0f, TimeSpan? duration = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public RandomMovementGenerator(float spawnDist = 0.0f, TimeSpan? duration = null, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
_timer = new TimeTracker();
|
||||
_reference = new();
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
using Framework.Constants;
|
||||
using Game.AI;
|
||||
using Game.Entities;
|
||||
using Game.Scripting.v2;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -31,7 +31,7 @@ namespace Game.Movement
|
||||
bool _generatePath;
|
||||
|
||||
public WaypointMovementGenerator(uint pathId = 0, bool repeating = true, TimeSpan? duration = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default,
|
||||
(TimeSpan min, TimeSpan max)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool? followPathBackwardsFromEndToStart = null, bool generatePath = true, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
(TimeSpan min, TimeSpan max)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool? followPathBackwardsFromEndToStart = null, bool generatePath = true, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
_nextMoveTime = new TimeTracker(0);
|
||||
_pathId = pathId;
|
||||
@@ -56,7 +56,7 @@ namespace Game.Movement
|
||||
}
|
||||
|
||||
public WaypointMovementGenerator(WaypointPath path, bool repeating = true, TimeSpan? duration = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default,
|
||||
(TimeSpan min, TimeSpan max)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool? followPathBackwardsFromEndToStart = null, bool generatePath = true, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
(TimeSpan min, TimeSpan max)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool? followPathBackwardsFromEndToStart = null, bool generatePath = true, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
_nextMoveTime = new TimeTracker(0);
|
||||
_repeating = repeating;
|
||||
|
||||
@@ -2,15 +2,14 @@
|
||||
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
||||
|
||||
using Framework.Constants;
|
||||
using Framework.Dynamic;
|
||||
using Game.AI;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Scripting.v2;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -545,7 +544,7 @@ namespace Game.Movement
|
||||
Add(new FollowMovementGenerator(target, SharedConst.PetFollowDist, new ChaseAngle(SharedConst.PetFollowAngle), null));
|
||||
}
|
||||
|
||||
public void MoveRandom(float wanderDistance = 0.0f, TimeSpan? duration = null, MovementSlot slot = MovementSlot.Default, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public void MoveRandom(float wanderDistance = 0.0f, TimeSpan? duration = null, MovementSlot slot = MovementSlot.Default, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
if (_owner.IsTypeId(TypeId.Unit))
|
||||
Add(new RandomMovementGenerator(wanderDistance, duration, scriptResult), slot);
|
||||
@@ -553,12 +552,12 @@ namespace Game.Movement
|
||||
scriptResult.SetResult(MovementStopReason.Interrupted);
|
||||
}
|
||||
|
||||
public void MoveFollow(Unit target, float dist, float angle = 0.0f, TimeSpan? duration = null, MovementSlot slot = MovementSlot.Active, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public void MoveFollow(Unit target, float dist, float angle = 0.0f, TimeSpan? duration = null, MovementSlot slot = MovementSlot.Active, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
MoveFollow(target, dist, new ChaseAngle(angle), duration, slot, scriptResult);
|
||||
}
|
||||
|
||||
public void MoveFollow(Unit target, float dist, ChaseAngle angle, TimeSpan? duration = null, MovementSlot slot = MovementSlot.Active, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public void MoveFollow(Unit target, float dist, ChaseAngle angle, TimeSpan? duration = null, MovementSlot slot = MovementSlot.Active, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
// Ignore movement request if target not exist
|
||||
if (target == null || target == _owner)
|
||||
@@ -589,7 +588,7 @@ namespace Game.Movement
|
||||
Add(new ConfusedMovementGenerator<Creature>());
|
||||
}
|
||||
|
||||
public void MoveFleeing(Unit enemy, TimeSpan time = default, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public void MoveFleeing(Unit enemy, TimeSpan time = default, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
if (enemy == null)
|
||||
{
|
||||
@@ -604,12 +603,12 @@ namespace Game.Movement
|
||||
Add(new FleeingMovementGenerator(enemy.GetGUID(), scriptResult));
|
||||
}
|
||||
|
||||
public void MovePoint(uint id, Position pos, bool generatePath = true, float? finalOrient = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, float? closeEnoughDistance = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public void MovePoint(uint id, Position pos, bool generatePath = true, float? finalOrient = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, float? closeEnoughDistance = null, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
MovePoint(id, pos.posX, pos.posY, pos.posZ, generatePath, finalOrient, speed, speedSelectionMode, closeEnoughDistance, scriptResult);
|
||||
}
|
||||
|
||||
public void MovePoint(uint id, float x, float y, float z, bool generatePath = true, float? finalOrient = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, float? closeEnoughDistance = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public void MovePoint(uint id, float x, float y, float z, bool generatePath = true, float? finalOrient = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, float? closeEnoughDistance = null, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Movement, $"MotionMaster::MovePoint: '{_owner.GetGUID()}', targeted point Id: {id} (X: {x}, Y: {y}, Z: {z})");
|
||||
Add(new PointMovementGenerator(id, x, y, z, generatePath, speed, finalOrient, null, null, speedSelectionMode, closeEnoughDistance, scriptResult));
|
||||
@@ -639,7 +638,7 @@ namespace Game.Movement
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveLand(uint id, Position pos, uint? tierTransitionId = null, float? velocity = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public void MoveLand(uint id, Position pos, uint? tierTransitionId = null, float? velocity = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
var initializer = (MoveSplineInit init) =>
|
||||
{
|
||||
@@ -666,7 +665,7 @@ namespace Game.Movement
|
||||
Add(new GenericMovementGenerator(initializer, MovementGeneratorType.Effect, id, new() { ScriptResult = scriptResult }));
|
||||
}
|
||||
|
||||
public void MoveTakeoff(uint id, Position pos, uint? tierTransitionId = null, float? velocity = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public void MoveTakeoff(uint id, Position pos, uint? tierTransitionId = null, float? velocity = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
var initializer = (MoveSplineInit init) =>
|
||||
{
|
||||
@@ -772,12 +771,12 @@ namespace Game.Movement
|
||||
MoveJump(x, y, z, 0.0f, speedXY, speedZ);
|
||||
}
|
||||
|
||||
public void MoveJump(Position pos, float speedXY, float speedZ, uint id = EventId.Jump, bool hasOrientation = false, JumpArrivalCastArgs arrivalCast = null, SpellEffectExtraData spellEffectExtraData = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public void MoveJump(Position pos, float speedXY, float speedZ, uint id = EventId.Jump, bool hasOrientation = false, JumpArrivalCastArgs arrivalCast = null, SpellEffectExtraData spellEffectExtraData = null, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), speedXY, speedZ, id, hasOrientation, arrivalCast, spellEffectExtraData, scriptResult);
|
||||
}
|
||||
|
||||
public void MoveJump(float x, float y, float z, float o, float speedXY, float speedZ, uint id = EventId.Jump, bool hasOrientation = false, JumpArrivalCastArgs arrivalCast = null, SpellEffectExtraData spellEffectExtraData = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public void MoveJump(float x, float y, float z, float o, float speedXY, float speedZ, uint id = EventId.Jump, bool hasOrientation = false, JumpArrivalCastArgs arrivalCast = null, SpellEffectExtraData spellEffectExtraData = null, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Server, "Unit ({0}) jump to point (X: {1} Y: {2} Z: {3})", _owner.GetGUID().ToString(), x, y, z);
|
||||
if (speedXY < 0.01f)
|
||||
@@ -815,7 +814,7 @@ namespace Game.Movement
|
||||
Add(movement);
|
||||
}
|
||||
|
||||
public void MoveJumpWithGravity(Position pos, float speedXY, float gravity, uint id = EventId.Jump, bool hasOrientation = false, JumpArrivalCastArgs arrivalCast = null, SpellEffectExtraData spellEffectExtraData = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public void MoveJumpWithGravity(Position pos, float speedXY, float gravity, uint id = EventId.Jump, bool hasOrientation = false, JumpArrivalCastArgs arrivalCast = null, SpellEffectExtraData spellEffectExtraData = null, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Movement, $"MotionMaster.MoveJumpWithGravity: '{_owner.GetGUID()}', jumps to point Id: {id} ({pos})");
|
||||
if (speedXY < 0.01f)
|
||||
@@ -853,7 +852,7 @@ namespace Game.Movement
|
||||
Add(movement);
|
||||
}
|
||||
|
||||
public void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, byte stepCount, TimeSpan? duration = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public void MoveCirclePath(float x, float y, float z, float radius, bool clockwise, byte stepCount, TimeSpan? duration = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
var initializer = (MoveSplineInit init) =>
|
||||
{
|
||||
@@ -960,7 +959,7 @@ namespace Game.Movement
|
||||
Add(new SplineChainMovementGenerator(info));
|
||||
}
|
||||
|
||||
public void MoveFall(uint id = 0, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public void MoveFall(uint id = 0, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
// Use larger distance for vmap height search than in most other cases
|
||||
float tz = _owner.GetMapHeight(_owner.GetPositionX(), _owner.GetPositionY(), _owner.GetPositionZ(), true, MapConst.MaxFallDistance);
|
||||
@@ -1019,7 +1018,7 @@ namespace Game.Movement
|
||||
Log.outError(LogFilter.Server, $"MotionMaster::MoveSeekAssistanceDistract: {_owner.GetGUID()} attempted to call distract after assistance");
|
||||
}
|
||||
|
||||
public void MoveTaxiFlight(uint path, uint pathnode, float? speed = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public void MoveTaxiFlight(uint path, uint pathnode, float? speed = null, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
if (_owner.IsTypeId(TypeId.Player))
|
||||
{
|
||||
@@ -1054,7 +1053,7 @@ namespace Game.Movement
|
||||
}
|
||||
|
||||
public void MovePath(uint pathId, bool repeatable, TimeSpan? duration = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default,
|
||||
(TimeSpan, TimeSpan)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool? followPathBackwardsFromEndToStart = null, bool generatePath = true, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
(TimeSpan, TimeSpan)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool? followPathBackwardsFromEndToStart = null, bool generatePath = true, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
if (pathId == 0)
|
||||
{
|
||||
@@ -1068,7 +1067,7 @@ namespace Game.Movement
|
||||
}
|
||||
|
||||
public void MovePath(WaypointPath path, bool repeatable, TimeSpan? duration = null, float? speed = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default,
|
||||
(TimeSpan, TimeSpan)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool? followPathBackwardsFromEndToStart = null, bool generatePath = true, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
(TimeSpan, TimeSpan)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool? followPathBackwardsFromEndToStart = null, bool generatePath = true, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Movement, $"MotionMaster::MovePath: '{_owner.GetGUID()}', starts moving over path Id: {path.Id} (repeatable: {repeatable})");
|
||||
Add(new WaypointMovementGenerator(path, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd, wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath, scriptResult), MovementSlot.Default);
|
||||
@@ -1082,7 +1081,7 @@ namespace Game.Movement
|
||||
/// <param name="time">How long should this movement last, infinite if not set</param>
|
||||
/// <param name="turnSpeed">How fast should the unit rotate, in radians per second. Uses unit's turn speed if not set</param>
|
||||
/// <param name="totalTurnAngle">Total angle of the entire movement, infinite if not set</param>
|
||||
public void MoveRotate(uint id, RotateDirection direction, TimeSpan? time = null, float? turnSpeed = null, float? totalTurnAngle = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
public void MoveRotate(uint id, RotateDirection direction, TimeSpan? time = null, float? turnSpeed = null, float? totalTurnAngle = null, ActionResultSetter<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
Log.outDebug(LogFilter.Movement, $"MotionMaster::MoveRotate: '{_owner.GetGUID()}', starts rotate (time: {time.GetValueOrDefault(TimeSpan.Zero)}ms, turnSpeed: {turnSpeed}, totalTurnAngle: {totalTurnAngle}, direction: {direction})");
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
|
||||
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace Game.Scripting.v2
|
||||
{
|
||||
public class ActionResultSetter<T>
|
||||
{
|
||||
ActionBase _action;
|
||||
T _result;
|
||||
|
||||
public ActionResultSetter(ActionBase action, T result)
|
||||
{
|
||||
_action = action;
|
||||
_result = result;
|
||||
}
|
||||
|
||||
public void SetResult(T result)
|
||||
{
|
||||
_result = result;
|
||||
_action.MarkCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
public class ActionResultSetter
|
||||
{
|
||||
ActionBase _action;
|
||||
|
||||
public ActionResultSetter(ActionBase action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
public void SetResult()
|
||||
{
|
||||
_action.MarkCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
|
||||
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game.Scripting.v2
|
||||
{
|
||||
public class ActionBase
|
||||
{
|
||||
bool _isReady;
|
||||
|
||||
public virtual bool IsReady()
|
||||
{
|
||||
return _isReady;
|
||||
}
|
||||
|
||||
public void MarkCompleted()
|
||||
{
|
||||
_isReady = true;
|
||||
}
|
||||
}
|
||||
|
||||
public class WaitAction : ActionBase
|
||||
{
|
||||
DateTime _waitEnd;
|
||||
|
||||
public WaitAction(DateTime waitEnd)
|
||||
{
|
||||
_waitEnd = waitEnd;
|
||||
}
|
||||
|
||||
public override bool IsReady()
|
||||
{
|
||||
return _waitEnd <= GameTime.Now();
|
||||
}
|
||||
}
|
||||
|
||||
public class ActionResult<T> : ActionBase
|
||||
{
|
||||
T _result;
|
||||
|
||||
public static ActionResultSetter<T> GetResultSetter(ActionResult<T> action)
|
||||
{
|
||||
T resultPtr = action._result;
|
||||
return new ActionResultSetter<T>(action, resultPtr);
|
||||
}
|
||||
}
|
||||
|
||||
public class ActionResult : ActionBase
|
||||
{
|
||||
public static ActionResultSetter GetResultSetter(ActionResult action)
|
||||
{
|
||||
return new ActionResultSetter(action);
|
||||
}
|
||||
}
|
||||
|
||||
public class MultiActionResult<InnerResult> : ActionResult
|
||||
{
|
||||
public List<ActionResult<InnerResult>> Results = new();
|
||||
|
||||
public ActionResult<InnerResult> CreateAndGetResult()
|
||||
{
|
||||
ActionResult<InnerResult> result = new();
|
||||
Results.Add(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public override bool IsReady()
|
||||
{
|
||||
return Results.All(result => result.IsReady());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,11 @@ using Game.Miscellaneous;
|
||||
using Game.Movement;
|
||||
using Game.Networking.Packets;
|
||||
using Game.Scripting;
|
||||
using Game.Scripting.v2;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Spells
|
||||
{
|
||||
@@ -8267,7 +8267,7 @@ namespace Game.Spells
|
||||
|
||||
public List<Aura> m_appliedMods = new();
|
||||
|
||||
public TaskCompletionSource<SpellCastResult> m_scriptResult;
|
||||
public ActionResultSetter<SpellCastResult> m_scriptResult;
|
||||
public bool m_scriptWaitsForSpellHit;
|
||||
|
||||
WorldObject m_caster;
|
||||
@@ -9551,7 +9551,7 @@ namespace Game.Spells
|
||||
public Dictionary<SpellValueMod, int> SpellValueOverrides = new();
|
||||
public object CustomArg;
|
||||
|
||||
public TaskCompletionSource<SpellCastResult> ScriptResult;
|
||||
public ActionResultSetter<SpellCastResult> ScriptResult;
|
||||
public bool ScriptWaitsForSpellHit;
|
||||
|
||||
public CastSpellExtraArgs() { }
|
||||
@@ -9656,7 +9656,7 @@ namespace Game.Spells
|
||||
return this;
|
||||
}
|
||||
|
||||
public CastSpellExtraArgs SetScriptResult(TaskCompletionSource<SpellCastResult> scriptResult)
|
||||
public CastSpellExtraArgs SetScriptResult(ActionResultSetter<SpellCastResult> scriptResult)
|
||||
{
|
||||
ScriptResult = scriptResult;
|
||||
return this;
|
||||
|
||||
Reference in New Issue
Block a user