Core/Scripts: Integrate new ActionResultSetter with movement generators and spells
Port From (https://github.com/TrinityCore/TrinityCore/commit/b265c49977235dea5e7e69d7b6fb93f4943bf87a)
This commit is contained in:
@@ -2497,6 +2497,8 @@ namespace Game.Entities
|
||||
}
|
||||
|
||||
spell.m_customArg = args.CustomArg;
|
||||
spell.m_scriptResult = args.ScriptResult;
|
||||
spell.m_scriptWaitsForSpellHit = args.ScriptWaitsForSpellHit;
|
||||
|
||||
return spell.Prepare(targets.Targets, args.TriggeringAura);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ using Game.Spells;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using static Global;
|
||||
|
||||
namespace Game.Entities
|
||||
@@ -6920,7 +6921,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)
|
||||
public bool ActivateTaxiPathTo(List<uint> nodes, Creature npc = null, uint spellid = 0, uint preferredMountDisplay = 0, float? speed = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
if (nodes.Count < 2)
|
||||
{
|
||||
@@ -7097,18 +7098,18 @@ namespace Game.Entities
|
||||
ModifyMoney(-firstcost);
|
||||
UpdateCriteria(CriteriaType.MoneySpentOnTaxis, firstcost);
|
||||
GetSession().SendActivateTaxiReply();
|
||||
StartTaxiMovement(mount_display_id, sourcepath, 0, speed);
|
||||
StartTaxiMovement(mount_display_id, sourcepath, 0, speed, scriptResult);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ActivateTaxiPathTo(uint taxi_path_id, uint spellid = 0, float? speed = null)
|
||||
public bool ActivateTaxiPathTo(uint taxi_path_id, uint spellid = 0, float? speed = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
var entry = CliDB.TaxiPathStorage.LookupByKey(taxi_path_id);
|
||||
if (entry == null)
|
||||
return false;
|
||||
|
||||
return ActivateTaxiPathTo([entry.FromTaxiNode, entry.ToTaxiNode], null, spellid, 0, speed);
|
||||
return ActivateTaxiPathTo([entry.FromTaxiNode, entry.ToTaxiNode], null, spellid, 0, speed, scriptResult);
|
||||
}
|
||||
|
||||
public void FinishTaxiFlight()
|
||||
@@ -7174,10 +7175,10 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
|
||||
StartTaxiMovement(mountDisplayId, path, startNode, null);
|
||||
StartTaxiMovement(mountDisplayId, path, startNode, null, null);
|
||||
}
|
||||
|
||||
void StartTaxiMovement(uint mountDisplayId, uint path, uint pathNode, float? speed)
|
||||
void StartTaxiMovement(uint mountDisplayId, uint path, uint pathNode, float? speed, TaskCompletionSource<MovementStopReason> scriptResult)
|
||||
{
|
||||
// remove fake death
|
||||
RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Interacting);
|
||||
@@ -7185,7 +7186,7 @@ namespace Game.Entities
|
||||
if (mountDisplayId != 0)
|
||||
Mount(mountDisplayId);
|
||||
|
||||
GetMotionMaster().MoveTaxiFlight(path, pathNode, speed);
|
||||
GetMotionMaster().MoveTaxiFlight(path, pathNode, speed, scriptResult);
|
||||
}
|
||||
|
||||
public bool GetsRecruitAFriendBonus(bool forXP)
|
||||
|
||||
@@ -5,6 +5,7 @@ using Framework.Constants;
|
||||
using Game.AI;
|
||||
using Game.Entities;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -13,15 +14,16 @@ namespace Game.Movement
|
||||
public const float MIN_QUIET_DISTANCE = 28.0f;
|
||||
public const float MAX_QUIET_DISTANCE = 43.0f;
|
||||
|
||||
public FleeingMovementGenerator(ObjectGuid fright)
|
||||
public FleeingMovementGenerator(ObjectGuid fleeTargetGUID, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
_fleeTargetGUID = fright;
|
||||
_fleeTargetGUID = fleeTargetGUID;
|
||||
_timer = new TimeTracker();
|
||||
|
||||
Mode = MovementGeneratorMode.Default;
|
||||
Priority = MovementGeneratorPriority.Highest;
|
||||
Flags = MovementGeneratorFlags.InitializationPending;
|
||||
BaseUnitState = UnitState.Fleeing;
|
||||
ScriptResult = scriptResult;
|
||||
}
|
||||
|
||||
public override void Initialize(Unit owner)
|
||||
@@ -90,6 +92,9 @@ namespace Game.Movement
|
||||
else if (owner.IsPlayer())
|
||||
owner.StopMoving();
|
||||
}
|
||||
|
||||
if (movementInform)
|
||||
SetScriptResult(MovementStopReason.Finished);
|
||||
}
|
||||
|
||||
void SetTargetLocation(Unit owner)
|
||||
@@ -192,7 +197,7 @@ namespace Game.Movement
|
||||
|
||||
public class TimedFleeingMovementGenerator : FleeingMovementGenerator
|
||||
{
|
||||
public TimedFleeingMovementGenerator(ObjectGuid fright, TimeSpan time) : base(fright)
|
||||
public TimedFleeingMovementGenerator(ObjectGuid fleeTargetGUID, TimeSpan time, TaskCompletionSource<MovementStopReason> scriptResult = null) : base(fleeTargetGUID, scriptResult)
|
||||
{
|
||||
_totalFleeTime = new TimeTracker(time);
|
||||
}
|
||||
@@ -228,6 +233,8 @@ namespace Game.Movement
|
||||
|
||||
if (movementInform)
|
||||
{
|
||||
SetScriptResult(MovementStopReason.Finished);
|
||||
|
||||
Creature ownerCreature = owner.ToCreature();
|
||||
CreatureAI ai = ownerCreature != null ? ownerCreature.GetAI() : null;
|
||||
if (ai != null)
|
||||
|
||||
@@ -9,6 +9,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -24,13 +25,14 @@ namespace Game.Movement
|
||||
int _currentNode;
|
||||
List<TaxiNodeChangeInfo> _pointsForPathSwitch = new(); //! node indexes and costs where TaxiPath changes
|
||||
|
||||
public FlightPathMovementGenerator(float? speed)
|
||||
public FlightPathMovementGenerator(float? speed, TaskCompletionSource<MovementStopReason> scriptResult)
|
||||
{
|
||||
_speed = speed;
|
||||
Mode = MovementGeneratorMode.Default;
|
||||
Priority = MovementGeneratorPriority.Highest;
|
||||
Flags = MovementGeneratorFlags.InitializationPending;
|
||||
BaseUnitState = UnitState.InFlight;
|
||||
ScriptResult = scriptResult;
|
||||
}
|
||||
|
||||
public override void DoInitialize(Player owner)
|
||||
@@ -157,6 +159,9 @@ namespace Game.Movement
|
||||
}
|
||||
|
||||
owner.RemovePlayerFlag(PlayerFlags.TaxiBenchmark);
|
||||
|
||||
if (movementInform)
|
||||
SetScriptResult(MovementStopReason.Finished);
|
||||
}
|
||||
|
||||
uint GetPathAtMapEnd()
|
||||
|
||||
@@ -5,6 +5,7 @@ using Framework.Constants;
|
||||
using Game.AI;
|
||||
using Game.Entities;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -23,7 +24,7 @@ namespace Game.Movement
|
||||
|
||||
AbstractFollower _abstractFollower;
|
||||
|
||||
public FollowMovementGenerator(Unit target, float range, ChaseAngle angle, TimeSpan? duration)
|
||||
public FollowMovementGenerator(Unit target, float range, ChaseAngle angle, TimeSpan? duration, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
_abstractFollower = new AbstractFollower(target);
|
||||
_range = range;
|
||||
@@ -33,6 +34,7 @@ namespace Game.Movement
|
||||
Priority = MovementGeneratorPriority.Normal;
|
||||
Flags = MovementGeneratorFlags.InitializationPending;
|
||||
BaseUnitState = UnitState.Follow;
|
||||
ScriptResult = scriptResult;
|
||||
|
||||
if (duration.HasValue)
|
||||
_duration = new(duration.Value);
|
||||
@@ -186,6 +188,8 @@ namespace Game.Movement
|
||||
{
|
||||
owner.ClearUnitState(UnitState.FollowMove);
|
||||
UpdatePetSpeed(owner);
|
||||
if (movementInform)
|
||||
SetScriptResult(MovementStopReason.Finished);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -38,6 +39,8 @@ namespace Game.Movement
|
||||
_duration = new(args.Duration.Value);
|
||||
_durationTracksSpline = false;
|
||||
}
|
||||
|
||||
ScriptResult = args.ScriptResult;
|
||||
}
|
||||
|
||||
public override void Initialize(Unit owner)
|
||||
@@ -99,6 +102,8 @@ namespace Game.Movement
|
||||
if (_arrivalSpellId != 0)
|
||||
owner.CastSpell(Global.ObjAccessor.GetUnit(owner, _arrivalSpellTargetGuid), _arrivalSpellId, true);
|
||||
|
||||
SetScriptResult(MovementStopReason.Finished);
|
||||
|
||||
Creature creature = owner.ToCreature();
|
||||
if (creature != null && creature.GetAI() != null)
|
||||
creature.GetAI().MovementInform(_type, _pointId);
|
||||
@@ -112,5 +117,6 @@ namespace Game.Movement
|
||||
public uint? ArrivalSpellId;
|
||||
public ObjectGuid? ArrivalSpellTarget;
|
||||
public TimeSpan? Duration;
|
||||
public TaskCompletionSource<MovementStopReason> ScriptResult;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -56,7 +57,7 @@ namespace Game.Movement
|
||||
float? _totalTurnAngle;
|
||||
uint _diffSinceLastUpdate;
|
||||
|
||||
public RotateMovementGenerator(uint id, RotateDirection direction, TimeSpan? duration, float? turnSpeed, float? totalTurnAngle)
|
||||
public RotateMovementGenerator(uint id, RotateDirection direction, TimeSpan? duration, float? turnSpeed, float? totalTurnAngle, TaskCompletionSource<MovementStopReason> scriptResult)
|
||||
{
|
||||
_id = id;
|
||||
_direction = direction;
|
||||
@@ -70,6 +71,7 @@ namespace Game.Movement
|
||||
Priority = MovementGeneratorPriority.Normal;
|
||||
Flags = MovementGeneratorFlags.InitializationPending;
|
||||
BaseUnitState = UnitState.Rotating;
|
||||
ScriptResult = scriptResult;
|
||||
}
|
||||
|
||||
public override void Initialize(Unit owner)
|
||||
@@ -142,8 +144,12 @@ namespace Game.Movement
|
||||
{
|
||||
AddFlag(MovementGeneratorFlags.Finalized);
|
||||
|
||||
if (movementInform && owner.IsCreature())
|
||||
owner.ToCreature().GetAI().MovementInform(MovementGeneratorType.Rotate, _id);
|
||||
if (movementInform)
|
||||
{
|
||||
SetScriptResult(MovementStopReason.Finished);
|
||||
if (owner.IsCreature())
|
||||
owner.ToCreature().GetAI().MovementInform(MovementGeneratorType.Rotate, _id);
|
||||
}
|
||||
}
|
||||
|
||||
public override MovementGeneratorType GetMovementGeneratorType() { return MovementGeneratorType.Rotate; }
|
||||
|
||||
@@ -5,6 +5,7 @@ using Framework.Constants;
|
||||
using Game.AI;
|
||||
using Game.Entities;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -14,6 +15,7 @@ namespace Game.Movement
|
||||
public MovementGeneratorPriority Priority;
|
||||
public MovementGeneratorFlags Flags;
|
||||
public UnitState BaseUnitState;
|
||||
public TaskCompletionSource<MovementStopReason> ScriptResult;
|
||||
|
||||
// on top first update
|
||||
public virtual void Initialize(Unit owner) { }
|
||||
@@ -68,8 +70,17 @@ namespace Game.Movement
|
||||
{
|
||||
return $"Mode: {Mode} Priority: {Priority} Flags: {Flags} BaseUniteState: {BaseUnitState}";
|
||||
}
|
||||
|
||||
public void SetScriptResult(MovementStopReason reason)
|
||||
{
|
||||
if (ScriptResult != null)
|
||||
{
|
||||
ScriptResult.SetResult(reason);
|
||||
ScriptResult = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public abstract class MovementGeneratorMedium<T> : MovementGenerator where T : Unit
|
||||
{
|
||||
public override void Initialize(Unit owner)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -21,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)
|
||||
MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, float? closeEnoughDistance = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
_movementId = id;
|
||||
_destination = new Position(x, y, z);
|
||||
@@ -37,6 +38,7 @@ namespace Game.Movement
|
||||
Priority = MovementGeneratorPriority.Normal;
|
||||
Flags = MovementGeneratorFlags.InitializationPending;
|
||||
BaseUnitState = UnitState.Roaming;
|
||||
ScriptResult = scriptResult;
|
||||
}
|
||||
|
||||
public override void Initialize(Unit owner)
|
||||
@@ -192,6 +194,8 @@ namespace Game.Movement
|
||||
|
||||
public void MovementInform(Unit owner)
|
||||
{
|
||||
SetScriptResult(MovementStopReason.Finished);
|
||||
|
||||
// deliver EVENT_CHARGE to scripts, EVENT_CHARGE_PREPATH is just internal implementation detail of this movement generator
|
||||
uint movementId = _movementId == EventId.ChargePrepath ? EventId.Charge : _movementId;
|
||||
owner.ToCreature()?.GetAI()?.MovementInform(MovementGeneratorType.Point, movementId);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -16,7 +17,7 @@ namespace Game.Movement
|
||||
float _wanderDistance;
|
||||
uint _wanderSteps;
|
||||
|
||||
public RandomMovementGenerator(float spawnDist = 0.0f, TimeSpan? duration = null)
|
||||
public RandomMovementGenerator(float spawnDist = 0.0f, TimeSpan? duration = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
_timer = new TimeTracker();
|
||||
_reference = new();
|
||||
@@ -26,6 +27,8 @@ namespace Game.Movement
|
||||
Priority = MovementGeneratorPriority.Normal;
|
||||
Flags = MovementGeneratorFlags.InitializationPending;
|
||||
BaseUnitState = UnitState.Roaming;
|
||||
ScriptResult = scriptResult;
|
||||
|
||||
if (duration.HasValue)
|
||||
_duration = new TimeTracker(duration.Value);
|
||||
}
|
||||
@@ -112,8 +115,11 @@ namespace Game.Movement
|
||||
}
|
||||
|
||||
if (movementInform && HasFlag(MovementGeneratorFlags.InformEnabled))
|
||||
{
|
||||
SetScriptResult(MovementStopReason.Finished);
|
||||
if (owner.IsAIEnabled())
|
||||
owner.GetAI().MovementInform(MovementGeneratorType.Random, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Pause(uint timer)
|
||||
|
||||
@@ -7,6 +7,7 @@ using Game.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -30,8 +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)
|
||||
|
||||
(TimeSpan min, TimeSpan max)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool? followPathBackwardsFromEndToStart = null, bool generatePath = true, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
_nextMoveTime = new TimeTracker(0);
|
||||
_pathId = pathId;
|
||||
@@ -49,13 +49,14 @@ namespace Game.Movement
|
||||
Priority = MovementGeneratorPriority.Normal;
|
||||
Flags = MovementGeneratorFlags.InitializationPending;
|
||||
BaseUnitState = UnitState.Roaming;
|
||||
ScriptResult = scriptResult;
|
||||
|
||||
if (duration.HasValue)
|
||||
_duration = new(duration.Value);
|
||||
}
|
||||
|
||||
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)
|
||||
(TimeSpan min, TimeSpan max)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool? followPathBackwardsFromEndToStart = null, bool generatePath = true, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
_nextMoveTime = new TimeTracker(0);
|
||||
_repeating = repeating;
|
||||
@@ -72,6 +73,7 @@ namespace Game.Movement
|
||||
Priority = MovementGeneratorPriority.Normal;
|
||||
Flags = MovementGeneratorFlags.InitializationPending;
|
||||
BaseUnitState = UnitState.Roaming;
|
||||
ScriptResult = scriptResult;
|
||||
|
||||
if (duration.HasValue)
|
||||
_duration = new(duration.Value);
|
||||
@@ -176,6 +178,9 @@ namespace Game.Movement
|
||||
{
|
||||
RemoveFlag(MovementGeneratorFlags.Transitory);
|
||||
AddFlag(MovementGeneratorFlags.InformEnabled);
|
||||
AddFlag(MovementGeneratorFlags.Finalized);
|
||||
owner.UpdateCurrentWaypointInfo(0, 0);
|
||||
SetScriptResult(MovementStopReason.Finished);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -268,6 +273,9 @@ namespace Game.Movement
|
||||
// TODO: Research if this modification is needed, which most likely isnt
|
||||
owner.SetWalk(false);
|
||||
}
|
||||
|
||||
if (movementInform)
|
||||
SetScriptResult(MovementStopReason.Finished);
|
||||
}
|
||||
|
||||
public void MovementInform(Creature owner)
|
||||
@@ -367,6 +375,8 @@ namespace Game.Movement
|
||||
CreatureAI ai = owner.GetAI();
|
||||
if (ai != null)
|
||||
ai.WaypointPathEnded(currentWaypoint.Id, _path.Id);
|
||||
|
||||
SetScriptResult(MovementStopReason.Finished);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -406,7 +416,7 @@ namespace Game.Movement
|
||||
init.SetAnimation(AnimTier.Ground);
|
||||
break;
|
||||
case WaypointMoveType.Takeoff:
|
||||
init.SetAnimation(AnimTier.Hover);
|
||||
init.SetAnimation(AnimTier.Fly);
|
||||
break;
|
||||
case WaypointMoveType.Run:
|
||||
init.SetWalk(false);
|
||||
|
||||
@@ -10,6 +10,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Movement
|
||||
{
|
||||
@@ -544,21 +545,30 @@ 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)
|
||||
public void MoveRandom(float wanderDistance = 0.0f, TimeSpan? duration = null, MovementSlot slot = MovementSlot.Default, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
if (_owner.IsTypeId(TypeId.Unit))
|
||||
Add(new RandomMovementGenerator(wanderDistance, duration), slot);
|
||||
Add(new RandomMovementGenerator(wanderDistance, duration, scriptResult), slot);
|
||||
else if (scriptResult != null)
|
||||
scriptResult.SetResult(MovementStopReason.Interrupted);
|
||||
}
|
||||
|
||||
public void MoveFollow(Unit target, float dist, float angle = 0.0f, TimeSpan? duration = null, MovementSlot slot = MovementSlot.Active) { MoveFollow(target, dist, new ChaseAngle(angle), duration, slot); }
|
||||
public void MoveFollow(Unit target, float dist, float angle = 0.0f, TimeSpan? duration = null, MovementSlot slot = MovementSlot.Active, TaskCompletionSource<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)
|
||||
public void MoveFollow(Unit target, float dist, ChaseAngle angle, TimeSpan? duration = null, MovementSlot slot = MovementSlot.Active, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
// Ignore movement request if target not exist
|
||||
if (target == null || target == _owner)
|
||||
{
|
||||
if (scriptResult != null)
|
||||
scriptResult.SetResult(MovementStopReason.Interrupted);
|
||||
return;
|
||||
}
|
||||
|
||||
Add(new FollowMovementGenerator(target, dist, angle, duration), slot);
|
||||
Add(new FollowMovementGenerator(target, dist, angle, duration, scriptResult), slot);
|
||||
}
|
||||
|
||||
public void MoveChase(Unit target, float dist, float angle = 0.0f) { MoveChase(target, new ChaseRange(dist), new ChaseAngle(angle)); }
|
||||
@@ -579,26 +589,30 @@ namespace Game.Movement
|
||||
Add(new ConfusedMovementGenerator<Creature>());
|
||||
}
|
||||
|
||||
public void MoveFleeing(Unit enemy, TimeSpan time = default)
|
||||
public void MoveFleeing(Unit enemy, TimeSpan time = default, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
if (enemy == null)
|
||||
{
|
||||
if (scriptResult != null)
|
||||
scriptResult.SetResult(MovementStopReason.Interrupted);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_owner.IsCreature() && time > TimeSpan.Zero)
|
||||
Add(new TimedFleeingMovementGenerator(enemy.GetGUID(), time));
|
||||
Add(new TimedFleeingMovementGenerator(enemy.GetGUID(), time, scriptResult));
|
||||
else
|
||||
Add(new FleeingMovementGenerator(enemy.GetGUID()));
|
||||
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)
|
||||
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)
|
||||
{
|
||||
MovePoint(id, pos.posX, pos.posY, pos.posZ, generatePath, finalOrient, speed, speedSelectionMode, closeEnoughDistance);
|
||||
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)
|
||||
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)
|
||||
{
|
||||
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));
|
||||
Add(new PointMovementGenerator(id, x, y, z, generatePath, speed, finalOrient, null, null, speedSelectionMode, closeEnoughDistance, scriptResult));
|
||||
}
|
||||
|
||||
public void MoveCloserAndStop(uint id, Unit target, float distance)
|
||||
@@ -625,12 +639,12 @@ namespace Game.Movement
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveLand(uint id, Position pos, uint? tierTransitionId = null, float? velocity = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default)
|
||||
public void MoveLand(uint id, Position pos, uint? tierTransitionId = null, float? velocity = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
var initializer = (MoveSplineInit init) =>
|
||||
{
|
||||
init.MoveTo(pos, false);
|
||||
init.SetAnimation(AnimTier.Ground, tierTransitionId.GetValueOrDefault(0));
|
||||
init.SetAnimation(AnimTier.Ground, tierTransitionId.GetValueOrDefault(1));
|
||||
switch (speedSelectionMode)
|
||||
{
|
||||
case MovementWalkRunSpeedSelectionMode.ForceRun:
|
||||
@@ -647,15 +661,15 @@ namespace Game.Movement
|
||||
init.SetVelocity(velocity.Value);
|
||||
};
|
||||
|
||||
Add(new GenericMovementGenerator(initializer, MovementGeneratorType.Effect, id));
|
||||
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)
|
||||
public void MoveTakeoff(uint id, Position pos, uint? tierTransitionId = null, float? velocity = null, MovementWalkRunSpeedSelectionMode speedSelectionMode = MovementWalkRunSpeedSelectionMode.Default, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
var initializer = (MoveSplineInit init) =>
|
||||
{
|
||||
init.MoveTo(pos, false);
|
||||
init.SetAnimation(AnimTier.Hover, tierTransitionId.GetValueOrDefault(0));
|
||||
init.SetAnimation(AnimTier.Hover, tierTransitionId.GetValueOrDefault(15));
|
||||
switch (speedSelectionMode)
|
||||
{
|
||||
case MovementWalkRunSpeedSelectionMode.ForceRun:
|
||||
@@ -672,7 +686,7 @@ namespace Game.Movement
|
||||
init.SetVelocity(velocity.Value);
|
||||
};
|
||||
|
||||
Add(new GenericMovementGenerator(initializer, MovementGeneratorType.Effect, id));
|
||||
Add(new GenericMovementGenerator(initializer, MovementGeneratorType.Effect, id, new() { ScriptResult = scriptResult }));
|
||||
}
|
||||
|
||||
public void MoveCharge(float x, float y, float z, float speed = SPEED_CHARGE, uint id = EventId.Charge, bool generatePath = false, Unit target = null, SpellEffectExtraData spellEffectExtraData = null)
|
||||
@@ -755,16 +769,20 @@ 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)
|
||||
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)
|
||||
{
|
||||
MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), speedXY, speedZ, id, hasOrientation, arrivalCast, spellEffectExtraData);
|
||||
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)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (scriptResult != null)
|
||||
scriptResult.SetResult(MovementStopReason.Interrupted);
|
||||
return;
|
||||
}
|
||||
|
||||
float moveTimeHalf = (float)(speedZ / gravity);
|
||||
float max_height = -MoveSpline.ComputeFallElevation(moveTimeHalf, false, -speedZ);
|
||||
@@ -788,17 +806,21 @@ namespace Game.Movement
|
||||
arrivalSpellTargetGuid = arrivalCast.Target;
|
||||
}
|
||||
|
||||
GenericMovementGenerator movement = new(initializer, MovementGeneratorType.Effect, id, new GenericMovementGeneratorArgs() { ArrivalSpellId = arrivalSpellId, ArrivalSpellTarget = arrivalSpellTargetGuid });
|
||||
GenericMovementGenerator movement = new(initializer, MovementGeneratorType.Effect, id, new GenericMovementGeneratorArgs() { ArrivalSpellId = arrivalSpellId, ArrivalSpellTarget = arrivalSpellTargetGuid, ScriptResult = scriptResult });
|
||||
movement.Priority = MovementGeneratorPriority.Highest;
|
||||
movement.BaseUnitState = UnitState.Jumping;
|
||||
Add(movement);
|
||||
}
|
||||
|
||||
public void MoveJumpWithGravity(Position pos, float speedXY, float gravity, uint id = EventId.Jump, bool hasOrientation = false, JumpArrivalCastArgs arrivalCast = null, SpellEffectExtraData spellEffectExtraData = null)
|
||||
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)
|
||||
{
|
||||
Log.outDebug(LogFilter.Movement, $"MotionMaster.MoveJumpWithGravity: '{_owner.GetGUID()}', jumps to point Id: {id} ({pos})");
|
||||
if (speedXY < 0.01f)
|
||||
{
|
||||
if (scriptResult != null)
|
||||
scriptResult.SetResult(MovementStopReason.Interrupted);
|
||||
return;
|
||||
}
|
||||
|
||||
var initializer = (MoveSplineInit init) =>
|
||||
{
|
||||
@@ -821,14 +843,14 @@ namespace Game.Movement
|
||||
arrivalSpellTargetGuid = arrivalCast.Target;
|
||||
}
|
||||
|
||||
GenericMovementGenerator movement = new GenericMovementGenerator(initializer, MovementGeneratorType.Effect, id, new GenericMovementGeneratorArgs() { ArrivalSpellId = arrivalSpellId, ArrivalSpellTarget = arrivalSpellTargetGuid });
|
||||
GenericMovementGenerator movement = new GenericMovementGenerator(initializer, MovementGeneratorType.Effect, id, new GenericMovementGeneratorArgs() { ArrivalSpellId = arrivalSpellId, ArrivalSpellTarget = arrivalSpellTargetGuid, ScriptResult = scriptResult });
|
||||
movement.Priority = MovementGeneratorPriority.Highest;
|
||||
movement.BaseUnitState = UnitState.Jumping;
|
||||
movement.AddFlag(MovementGeneratorFlags.PersistOnDeath);
|
||||
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)
|
||||
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)
|
||||
{
|
||||
var initializer = (MoveSplineInit init) =>
|
||||
{
|
||||
@@ -879,7 +901,7 @@ namespace Game.Movement
|
||||
init.SetVelocity(speed.Value);
|
||||
};
|
||||
|
||||
Add(new GenericMovementGenerator(initializer, MovementGeneratorType.Effect, 0, new GenericMovementGeneratorArgs() { Duration = duration }));
|
||||
Add(new GenericMovementGenerator(initializer, MovementGeneratorType.Effect, 0, new GenericMovementGeneratorArgs() { Duration = duration, ScriptResult = scriptResult }));
|
||||
}
|
||||
|
||||
public void MoveSmoothPath(uint pointId, Vector3[] pathPoints, int pathSize, bool walk = false, bool fly = false)
|
||||
@@ -935,7 +957,7 @@ namespace Game.Movement
|
||||
Add(new SplineChainMovementGenerator(info));
|
||||
}
|
||||
|
||||
public void MoveFall(uint id = 0)
|
||||
public void MoveFall(uint id = 0, TaskCompletionSource<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);
|
||||
@@ -965,7 +987,7 @@ namespace Game.Movement
|
||||
init.SetFall();
|
||||
};
|
||||
|
||||
GenericMovementGenerator movement = new(initializer, MovementGeneratorType.Effect, id);
|
||||
GenericMovementGenerator movement = new(initializer, MovementGeneratorType.Effect, id, new() { ScriptResult = scriptResult });
|
||||
movement.Priority = MovementGeneratorPriority.Highest;
|
||||
Add(movement);
|
||||
}
|
||||
@@ -994,7 +1016,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)
|
||||
public void MoveTaxiFlight(uint path, uint pathnode, float? speed = null, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
if (_owner.IsTypeId(TypeId.Player))
|
||||
{
|
||||
@@ -1006,7 +1028,7 @@ namespace Game.Movement
|
||||
bool hasExisting = HasMovementGenerator(gen => gen.GetMovementGeneratorType() == MovementGeneratorType.Flight);
|
||||
Cypher.Assert(!hasExisting, "Duplicate flight path movement generator");
|
||||
|
||||
FlightPathMovementGenerator movement = new(speed);
|
||||
FlightPathMovementGenerator movement = new(speed, scriptResult);
|
||||
movement.LoadPath(_owner.ToPlayer());
|
||||
Add(movement);
|
||||
}
|
||||
@@ -1029,20 +1051,24 @@ namespace Game.Movement
|
||||
}
|
||||
|
||||
public void MovePath(uint pathId, bool repeatable, 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)
|
||||
(TimeSpan, TimeSpan)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool? followPathBackwardsFromEndToStart = null, bool generatePath = true, TaskCompletionSource<MovementStopReason> scriptResult = null)
|
||||
{
|
||||
if (pathId == 0)
|
||||
{
|
||||
if (scriptResult != null)
|
||||
scriptResult.SetResult(MovementStopReason.Interrupted);
|
||||
return;
|
||||
}
|
||||
|
||||
Log.outDebug(LogFilter.Movement, $"MotionMaster::MovePath: '{_owner.GetGUID()}', starts moving over path Id: {pathId} (repeatable: {repeatable})");
|
||||
Add(new WaypointMovementGenerator(pathId, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd, wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath), MovementSlot.Default);
|
||||
Add(new WaypointMovementGenerator(pathId, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd, wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath, scriptResult), MovementSlot.Default);
|
||||
}
|
||||
|
||||
public void MovePath(WaypointPath path, bool repeatable, 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)
|
||||
(TimeSpan, TimeSpan)? waitTimeRangeAtPathEnd = null, float? wanderDistanceAtPathEnds = null, bool? followPathBackwardsFromEndToStart = null, bool generatePath = true, TaskCompletionSource<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), MovementSlot.Default);
|
||||
Add(new WaypointMovementGenerator(path, repeatable, duration, speed, speedSelectionMode, waitTimeRangeAtPathEnd, wanderDistanceAtPathEnds, followPathBackwardsFromEndToStart, generatePath, scriptResult), MovementSlot.Default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1053,11 +1079,11 @@ 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)
|
||||
public void MoveRotate(uint id, RotateDirection direction, TimeSpan? time = null, float? turnSpeed = null, float? totalTurnAngle = null, TaskCompletionSource<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})");
|
||||
|
||||
Add(new RotateMovementGenerator(id, direction, time, turnSpeed, totalTurnAngle));
|
||||
Add(new RotateMovementGenerator(id, direction, time, turnSpeed, totalTurnAngle, scriptResult));
|
||||
}
|
||||
|
||||
public void MoveFormation(Unit leader, float range, float angle, uint point1, uint point2)
|
||||
|
||||
@@ -19,6 +19,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Game.Spells
|
||||
{
|
||||
@@ -3000,6 +3001,9 @@ namespace Game.Spells
|
||||
HandleImmediate();
|
||||
}
|
||||
|
||||
if (m_scriptResult != null && !m_scriptWaitsForSpellHit)
|
||||
m_scriptResult.SetResult(SpellCastResult.SpellCastOk);
|
||||
|
||||
CallScriptAfterCastHandlers();
|
||||
|
||||
var spell_triggered = Global.SpellMgr.GetSpellLinked(SpellLinkedType.Cast, m_spellInfo.Id);
|
||||
@@ -3438,6 +3442,9 @@ namespace Game.Spells
|
||||
|
||||
m_spellState = SpellState.Finished;
|
||||
|
||||
if (m_scriptResult != null && (m_scriptWaitsForSpellHit || result != SpellCastResult.SpellCastOk))
|
||||
m_scriptResult.SetResult(result);
|
||||
|
||||
if (m_caster == null)
|
||||
return;
|
||||
|
||||
@@ -8225,6 +8232,9 @@ namespace Game.Spells
|
||||
|
||||
public List<Aura> m_appliedMods = new();
|
||||
|
||||
public TaskCompletionSource<SpellCastResult> m_scriptResult;
|
||||
public bool m_scriptWaitsForSpellHit;
|
||||
|
||||
WorldObject m_caster;
|
||||
public SpellValue m_spellValue;
|
||||
ObjectGuid m_originalCasterGUID;
|
||||
@@ -9516,6 +9526,9 @@ namespace Game.Spells
|
||||
public Dictionary<SpellValueMod, int> SpellValueOverrides = new();
|
||||
public object CustomArg;
|
||||
|
||||
public TaskCompletionSource<SpellCastResult> ScriptResult;
|
||||
public bool ScriptWaitsForSpellHit;
|
||||
|
||||
public CastSpellExtraArgs() { }
|
||||
|
||||
public CastSpellExtraArgs(bool triggered)
|
||||
@@ -9618,6 +9631,17 @@ namespace Game.Spells
|
||||
return this;
|
||||
}
|
||||
|
||||
public CastSpellExtraArgs SetScriptResult(TaskCompletionSource<SpellCastResult> scriptResult)
|
||||
{
|
||||
ScriptResult = scriptResult;
|
||||
return this;
|
||||
}
|
||||
public CastSpellExtraArgs SetScriptWaitsForSpellHit(bool scriptWaitsForSpellHit)
|
||||
{
|
||||
ScriptWaitsForSpellHit = scriptWaitsForSpellHit;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static implicit operator CastSpellExtraArgs(bool triggered) => new CastSpellExtraArgs(triggered);
|
||||
|
||||
public static implicit operator CastSpellExtraArgs(TriggerCastFlags trigger) => new CastSpellExtraArgs(trigger);
|
||||
|
||||
Reference in New Issue
Block a user