public override bool Update(Unit owner, uint diff) { if (!owner || HasFlag(MovementGeneratorFlags.Finalized)) { return(false); } _duration.Update((int)diff); if (_duration.Passed() || owner.MoveSpline.Finalized()) { AddFlag(MovementGeneratorFlags.InformEnabled); return(false); } return(true); }
public override bool DoUpdate(T creature, uint diff) { if (creature.HasUnitState(UnitState.Root | UnitState.Stunned | UnitState.Distracted)) { i_nextMoveTime.Reset(0); // Expire the timer creature.ClearUnitState(UnitState.Roaming_Move); return(true); } if (creature.movespline.Finalized()) { i_nextMoveTime.Update((int)diff); if (i_nextMoveTime.Passed()) { _setRandomLocation(creature); } } return(true); }
public override bool Update(Unit owner, uint diff) { if (!owner || HasFlag(MovementGeneratorFlags.Finalized)) { return(false); } // Cyclic splines never expire, so update the duration only if it's not cyclic if (!owner.MoveSpline.IsCyclic()) { _duration.Update((int)diff); } if (_duration.Passed() || owner.MoveSpline.Finalized()) { AddFlag(MovementGeneratorFlags.InformEnabled); return(false); } return(true); }
public override bool Update(Unit owner, uint diff) { // owner might be dead or gone if (owner == null || !owner.IsAlive()) { return(false); } // our target might have gone away Unit target = _abstractFollower.GetTarget(); if (target == null || !target.IsInWorld) { return(false); } if (owner.HasUnitState(UnitState.NotMove) || owner.IsMovementPreventedByCasting()) { _path = null; owner.StopMoving(); _lastTargetPosition = null; return(true); } _checkTimer.Update((int)diff); if (_checkTimer.Passed()) { _checkTimer.Reset(CHECK_INTERVAL); if (HasFlag(MovementGeneratorFlags.InformEnabled) && PositionOkay(owner, target, _range, _angle)) { RemoveFlag(MovementGeneratorFlags.InformEnabled); _path = null; owner.StopMoving(); _lastTargetPosition = new(); DoMovementInform(owner, target); return(true); } } if (owner.HasUnitState(UnitState.FollowMove) && owner.MoveSpline.Finalized()) { RemoveFlag(MovementGeneratorFlags.InformEnabled); _path = null; owner.ClearUnitState(UnitState.FollowMove); DoMovementInform(owner, target); } if (_lastTargetPosition == null || _lastTargetPosition.GetExactDistSq(target.GetPosition()) > 0.0f) { _lastTargetPosition = new(target.GetPosition()); if (owner.HasUnitState(UnitState.FollowMove) || !PositionOkay(owner, target, _range + FOLLOW_RANGE_TOLERANCE)) { if (_path == null) { _path = new PathGenerator(owner); } float x, y, z; // select angle float tAngle; float curAngle = target.GetRelativeAngle(owner); if (_angle.IsAngleOkay(curAngle)) { tAngle = curAngle; } else { float diffUpper = Position.NormalizeOrientation(curAngle - _angle.UpperBound()); float diffLower = Position.NormalizeOrientation(_angle.LowerBound() - curAngle); if (diffUpper < diffLower) { tAngle = _angle.UpperBound(); } else { tAngle = _angle.LowerBound(); } } target.GetNearPoint(owner, out x, out y, out z, _range, target.ToAbsoluteAngle(tAngle)); if (owner.IsHovering()) { owner.UpdateAllowedPositionZ(x, y, ref z); } // pets are allowed to "cheat" on pathfinding when following their master bool allowShortcut = false; Pet oPet = owner.ToPet(); if (oPet != null) { if (target.GetGUID() == oPet.GetOwnerGUID()) { allowShortcut = true; } } bool success = _path.CalculatePath(x, y, z, allowShortcut); if (!success || _path.GetPathType().HasFlag(PathType.NoPath)) { owner.StopMoving(); return(true); } owner.AddUnitState(UnitState.FollowMove); AddFlag(MovementGeneratorFlags.InformEnabled); MoveSplineInit init = new(owner); init.MovebyPath(_path.GetPath()); init.SetWalk(target.IsWalking()); init.SetFacing(target.GetOrientation()); init.Launch(); } } return(true); }
public override bool Update(Unit owner, uint diff) { // owner might be dead or gone (can we even get nullptr here?) if (!owner || !owner.IsAlive()) { return(false); } // our target might have gone away Unit target = _abstractFollower.GetTarget(); if (target == null || !target.IsInWorld) { return(false); } // the owner might be unable to move (rooted or casting), or we have lost the target, pause movement if (owner.HasUnitState(UnitState.NotMove) || owner.IsMovementPreventedByCasting() || HasLostTarget(owner, target)) { owner.StopMoving(); _lastTargetPosition = null; Creature cOwner = owner.ToCreature(); if (cOwner != null) { cOwner.SetCannotReachTarget(false); } return(true); } bool mutualChase = IsMutualChase(owner, target); float hitboxSum = owner.GetCombatReach() + target.GetCombatReach(); float minRange = _range.HasValue ? _range.Value.MinRange + hitboxSum : SharedConst.ContactDistance; float minTarget = (_range.HasValue ? _range.Value.MinTolerance : 0.0f) + hitboxSum; float maxRange = _range.HasValue ? _range.Value.MaxRange + hitboxSum : owner.GetMeleeRange(target); // melee range already includes hitboxes float maxTarget = _range.HasValue ? _range.Value.MaxTolerance + hitboxSum : SharedConst.ContactDistance + hitboxSum; ChaseAngle?angle = mutualChase ? null : _angle; // periodically check if we're already in the expected range... _rangeCheckTimer.Update((int)diff); if (_rangeCheckTimer.Passed()) { _rangeCheckTimer.Reset(RANGE_CHECK_INTERVAL); if (HasFlag(MovementGeneratorFlags.InformEnabled) && PositionOkay(owner, target, _movingTowards ? null : minTarget, _movingTowards ? maxTarget : null, angle)) { RemoveFlag(MovementGeneratorFlags.InformEnabled); _path = null; Creature cOwner = owner.ToCreature(); if (cOwner != null) { cOwner.SetCannotReachTarget(false); } owner.StopMoving(); owner.SetInFront(target); DoMovementInform(owner, target); return(true); } } // if we're done moving, we want to clean up if (owner.HasUnitState(UnitState.ChaseMove) && owner.MoveSpline.Finalized()) { RemoveFlag(MovementGeneratorFlags.InformEnabled); _path = null; Creature cOwner = owner.ToCreature(); if (cOwner != null) { cOwner.SetCannotReachTarget(false); } owner.ClearUnitState(UnitState.ChaseMove); owner.SetInFront(target); DoMovementInform(owner, target); } // if the target moved, we have to consider whether to adjust if (_lastTargetPosition == null || target.GetPosition() != _lastTargetPosition || mutualChase != _mutualChase) { _lastTargetPosition = new(target.GetPosition()); _mutualChase = mutualChase; if (owner.HasUnitState(UnitState.ChaseMove) || !PositionOkay(owner, target, minRange, maxRange, angle)) { Creature cOwner = owner.ToCreature(); // can we get to the target? if (cOwner != null && !target.IsInAccessiblePlaceFor(cOwner)) { cOwner.SetCannotReachTarget(true); cOwner.StopMoving(); _path = null; return(true); } // figure out which way we want to move bool moveToward = !owner.IsInDist(target, maxRange); // make a new path if we have to... if (_path == null || moveToward != _movingTowards) { _path = new PathGenerator(owner); } float x, y, z; bool shortenPath; // if we want to move toward the target and there's no fixed angle... if (moveToward && !angle.HasValue) { // ...we'll pathfind to the center, then shorten the path target.GetPosition(out x, out y, out z); shortenPath = true; } else { // otherwise, we fall back to nearpoint finding target.GetNearPoint(owner, out x, out y, out z, (moveToward ? maxTarget : minTarget) - hitboxSum, angle.HasValue ? target.ToAbsoluteAngle(angle.Value.RelativeAngle) : target.GetAbsoluteAngle(owner)); shortenPath = false; } if (owner.IsHovering()) { owner.UpdateAllowedPositionZ(x, y, ref z); } bool success = _path.CalculatePath(x, y, z, owner.CanFly()); if (!success || _path.GetPathType().HasAnyFlag(PathType.NoPath)) { if (cOwner) { cOwner.SetCannotReachTarget(true); } owner.StopMoving(); return(true); } if (shortenPath) { _path.ShortenPathUntilDist(target, maxTarget); } if (cOwner) { cOwner.SetCannotReachTarget(false); } bool walk = false; if (cOwner && !cOwner.IsPet()) { switch (cOwner.GetMovementTemplate().GetChase()) { case CreatureChaseMovementType.CanWalk: walk = owner.IsWalking(); break; case CreatureChaseMovementType.AlwaysWalk: walk = true; break; default: break; } } owner.AddUnitState(UnitState.ChaseMove); AddFlag(MovementGeneratorFlags.InformEnabled); MoveSplineInit init = new(owner); init.MovebyPath(_path.GetPath()); init.SetWalk(walk); init.SetFacing(target); init.Launch(); } } // and then, finally, we're done for the tick return(true); }