Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp
- index 1dd66d7699..8683884b25 100644
- --- a/src/server/game/AI/CreatureAI.cpp
- +++ b/src/server/game/AI/CreatureAI.cpp
- @@ -350,6 +350,40 @@ void CreatureAI::SetBoundary(CreatureBoundary const* boundary, bool negateBounda
- me->DoImmediateBoundaryCheck();
- }
- +bool CreatureAI::CheckMeleeRepositionRequirements()
- +{
- + if (Unit* victim = me->GetVictim())
- + {
- + Position victimPos = victim->GetPosition();
- +
- + // If we are closer than 50% of the combat reach we are going to reposition ourself
- + // Dont call if we have more than one attacker because Circling Target will take place.
- + float reach = CalculatePct(me->GetCombatReach() + victim->GetCombatReach(), 50);
- + float moveDist = CalculatePct(me->GetCombatReach() + victim->GetCombatReach(), 100);
- + if (me->IsFreeToMove() && victim->getAttackers().size() == 1 && me->GetDistance(victimPos) < reach)
- + {
- + me->GetMotionMaster()->MoveBackwards(victim, moveDist);
- + return true;
- + }
- + }
- + return false;
- +}
- +
- +bool CreatureAI::CheckCircleRepositionRequirements()
- +{
- + if (Unit* victim = me->GetVictim())
- + {
- + Position victimPos = victim->GetPosition();
- +
- + if (me->IsFreeToMove() && victim->getAttackers().size() > 1)
- + {
- + me->GetMotionMaster()->MoveCircleTarget(victim);
- + return true;
- + }
- + }
- + return false;
- +}
- +
- Creature* CreatureAI::DoSummon(uint32 entry, Position const& pos, uint32 despawnTime, TempSummonType summonType)
- {
- return me->SummonCreature(entry, pos, summonType, despawnTime);
- diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h
- index d7cfec7b0b..25284740d3 100644
- --- a/src/server/game/AI/CreatureAI.h
- +++ b/src/server/game/AI/CreatureAI.h
- @@ -226,6 +226,9 @@ class TC_GAME_API CreatureAI : public UnitAI
- static bool IsInBounds(CreatureBoundary const& boundary, Position const* who);
- bool IsInBoundary(Position const* who = nullptr) const;
- + bool CheckMeleeRepositionRequirements();
- + bool CheckCircleRepositionRequirements();
- +
- protected:
- virtual void MoveInLineOfSight(Unit* /*who*/);
- diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
- index 0ac2b3be02..6a0b813a15 100644
- --- a/src/server/game/Entities/Creature/Creature.cpp
- +++ b/src/server/game/Entities/Creature/Creature.cpp
- @@ -779,6 +779,25 @@ void Creature::Update(uint32 diff)
- m_boundaryCheckTime -= diff;
- }
- + // Moving back from the target.
- + if (diff >= m_moveBackMovementTime)
- + {
- + AI()->CheckMeleeRepositionRequirements();
- + m_moveBackMovementTime = MOVE_BACK_CHECK_INTERVAL;
- + }
- + else
- + m_moveBackMovementTime -= diff;
- +
- + // Circling the target.
- + if (diff >= m_moveCircleMovementTime)
- + {
- + AI()->CheckCircleRepositionRequirements();
- + m_moveCircleMovementTime = MOVE_CIRCLE_CHECK_INTERVAL;
- + }
- + else
- + m_moveCircleMovementTime -= diff;
- +
- +
- // if periodic combat pulse is enabled and we are both in combat and in a dungeon, do this now
- if (m_combatPulseDelay > 0 && IsEngaged() && GetMap()->IsDungeon())
- {
- @@ -3272,3 +3291,15 @@ bool Creature::IsEscortNPC(bool onlyIfActive)
- return AI()->IsEscortNPC(onlyIfActive);
- }
- +
- +bool Creature::IsFreeToMove()
- +{
- + uint32 moveFlags = m_movementInfo.GetMovementFlags();
- + // Do not reposition ourself when we are not allowed to move
- + if ((IsMovementPreventedByCasting() || isMoving() || !CanFreeMove()) &&
- + GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE ||
- + moveFlags & MOVEMENTFLAG_SPLINE_ENABLED)
- + return false;
- +
- + return true;
- +}
- diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
- index 23e567f733..ff1dde1039 100644
- --- a/src/server/game/Entities/Creature/Creature.h
- +++ b/src/server/game/Entities/Creature/Creature.h
- @@ -348,6 +348,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
- void ReleaseFocus(Spell const* focusSpell = nullptr, bool withDelay = true);
- bool IsMovementPreventedByCasting() const override;
- + bool IsFreeToMove();
- // Part of Evade mechanics
- time_t GetLastDamagedTime() const { return _lastDamagedTime; }
- @@ -386,6 +387,11 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
- uint32 m_combatPulseTime; // (msecs) remaining time for next zone-in-combat pulse
- uint32 m_combatPulseDelay; // (secs) how often the creature puts the entire zone in combat (only works in dungeons)
- + static constexpr uint32 MOVE_BACK_CHECK_INTERVAL = 3000;
- + static constexpr uint32 MOVE_CIRCLE_CHECK_INTERVAL = 3000;
- + uint32 m_moveBackMovementTime = MOVE_BACK_CHECK_INTERVAL;
- + uint32 m_moveCircleMovementTime = MOVE_CIRCLE_CHECK_INTERVAL;
- +
- ReactStates m_reactState; // for AI, not charmInfo
- void RegenerateHealth();
- void Regenerate(Powers power);
- diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
- index 09f5ef01a5..1d39fd9cdc 100644
- --- a/src/server/game/Entities/Unit/Unit.cpp
- +++ b/src/server/game/Entities/Unit/Unit.cpp
- @@ -287,6 +287,7 @@ bool DispelableAura::RollDispel() const
- return roll_chance_i(_chance);
- }
- +
- Unit::Unit(bool isWorldObject) :
- WorldObject(isWorldObject), m_playerMovingMe(nullptr), m_lastSanctuaryTime(0),
- IsAIEnabled(false), NeedChangeAI(false), LastCharmerGUID(), m_ControlledByPlayer(false),
- @@ -294,7 +295,8 @@ Unit::Unit(bool isWorldObject) :
- m_AutoRepeatFirstCast(false), m_procDeep(0), m_removedAurasCount(0),
- i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_vehicle(nullptr),
- m_vehicleKit(nullptr), m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_combatManager(this),
- - m_threatManager(this), m_comboTarget(nullptr), m_comboPoints(0), m_spellHistory(new SpellHistory(this))
- + m_threatManager(this), m_comboTarget(nullptr), m_comboPoints(0), m_spellHistory(new SpellHistory(this)),
- + m_attackPosition(NULL)
- {
- m_objectType |= TYPEMASK_UNIT;
- m_objectTypeId = TYPEID_UNIT;
- @@ -451,6 +453,16 @@ void Unit::Update(uint32 p_time)
- ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, HealthAbovePct(75));
- }
- + if (_attackPointCheckTimer > p_time)
- + {
- + _attackPointCheckTimer -= p_time;
- + }
- + else
- + {
- + _attackPointCheckTimer = ATTACK_POINT_CHECK_INTERVAL;
- + SetMeleeAttackPoints();
- + }
- +
- UpdateSplineMovement(p_time);
- i_motionMaster->Update(p_time);
- }
- @@ -554,6 +566,20 @@ bool Unit::IsWithinMeleeRangeAt(Position const& pos, Unit const* obj) const
- return distsq <= maxdist * maxdist;
- }
- +bool Unit::IsWithinRange(Unit const* obj, float dist) const
- +{
- + if (!obj || !IsInMap(obj) || !InSamePhase(obj))
- + return false;
- +
- + float dx = GetPositionX() - obj->GetPositionX();
- + float dy = GetPositionY() - obj->GetPositionY();
- + float dz = GetPositionZ() - obj->GetPositionZ();
- + float distsq = dx * dx + dy * dy + dz * dz;
- +
- + return distsq <= dist * dist;
- +}
- +
- +
- float Unit::GetMeleeRange(Unit const* target) const
- {
- float range = GetCombatReach() + target->GetCombatReach() + 4.0f / 3.0f;
- @@ -2005,7 +2031,7 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr
- if (GetTypeId() == TYPEID_UNIT && !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_POSSESSED) && !HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISABLE_TURN))
- SetFacingToObject(victim, false); // update client side facing to face the target (prevents visual glitches when casting untargeted spells)
- -
- +
- // melee attack spell cast at main hand attack only - no normal melee dmg dealt
- if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL] && !extra)
- m_currentSpells[CURRENT_MELEE_SPELL]->cast();
- @@ -13501,3 +13527,91 @@ float Unit::GetCollisionHeight() const
- float const collisionHeight = scaleMod * modelData->CollisionHeight * modelData->Scale * displayInfo->scale;
- return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight;
- }
- +
- +
- +struct AttackDistance {
- + AttackDistance(uint8 index, AttackPosition attackPos) : _index(index), _attackPos(attackPos) {}
- + uint8 _index;
- + AttackPosition _attackPos;
- +};
- +
- +void Unit::SetMeleeAttackPoints()
- +{
- + if (getAttackers().size() <= 1)
- + {
- + return;
- + }
- +
- + // Delete the attack positions each iteration.
- + attackMeleePositions.clear();
- +
- + // Calculate the attack positions.
- + // radius (Melee range unknown so use default).
- + float radius = MIN_MELEE_REACH;
- + uint8 attackPoints = getAttackers().size() * 3;
- + for (uint8 i = 0; i < attackPoints; ++i)
- + {
- + int8 anglePosition = ceil((i+1)/2) * ((i+1) % 2 ? -1 : 1);
- + float step = float(M_PI*2) / attackPoints;
- + Position const& pos = GetPosition();
- + float angle = GetOrientation() + float(M_PI * 2) + (step * anglePosition);
- + //TC_LOG_DEBUG("server", "AttackPosition (z,y,z)=(%4.1f,%4.1f,%4.1f)", pos.m_positionX + radius * cosf(angle), pos.m_positionY + radius * sinf(angle), pos.m_positionZ);
- + attackMeleePositions.push_back(AttackPosition(Position(pos.m_positionX + radius * cosf(angle), pos.m_positionY + radius * sinf(angle), pos.m_positionZ)));
- + }
- + m_previousAttackerCount = getAttackers().size();
- + m_previousPosition = GetPosition();
- +}
- +
- +Position Unit::GetMeleeAttackPoint(Unit* attacker)
- +{
- + if (getAttackers().size() <= 1)
- + return NULL;
- +
- + // If already on an attack Position and close to Target abort.
- + if (attacker->GetDistance(GetPosition()) < GetCombatReach() && !(attacker->m_attackPosition == NULL) && attacker->GetDistance(attacker->m_attackPosition._pos) < 0.25f)
- + return NULL;
- + attacker->m_attackPosition = NULL;
- +
- + // Get all the distances.
- + std::vector<AttackDistance> distances;
- + distances.reserve( attackMeleePositions.size());
- + for (uint8 i = 0; i < attackMeleePositions.size(); ++i)
- + {
- + // If the spot has been taken.
- + if (!attackMeleePositions[i]._taken)
- + distances.push_back(AttackDistance(i,attackMeleePositions[i]));
- + }
- +
- + if (distances.size() == 0)
- + return NULL;
- +
- + // Get the shortest point.
- + uint8 shortestIndex = 0;
- + float shortestLength = 100.0f;
- + for (uint8 i = 0; i < distances.size(); ++i)
- + {
- + float dist = attacker->GetDistance2d(distances[i]._attackPos._pos.m_positionX, distances[i]._attackPos._pos.m_positionY); // +GetDistance(distances[i]._attackPos._pos);
- + //TC_LOG_DEBUG("server", "dist=(%4.1f)", dist);
- + if (shortestLength > dist)
- + {
- + shortestLength = dist;
- + shortestIndex = i;
- + }
- + }
- + //TC_LOG_DEBUG("server", "shortestLength=(%4.1f)", shortestLength);
- +
- + // Create closest Position.
- + Position closestPos(distances[shortestIndex]._attackPos._pos);
- +
- + // Too close mark point taken and find another spot.
- + for (uint8 i = 0; i < attackMeleePositions.size(); ++i)
- + {
- + float dist = closestPos.GetExactDist(attackMeleePositions[i]._pos);
- + //TC_LOG_DEBUG("server", "points_dist=(%4.1f)", dist);
- + if (dist < GetCombatReach()/2)
- + attackMeleePositions[i]._taken = true;
- + }
- + attacker->m_attackPosition = distances[shortestIndex]._attackPos;
- +
- + return closestPos;
- +}
- diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
- index dfd1c1e020..6bd4005951 100644
- --- a/src/server/game/Entities/Unit/Unit.h
- +++ b/src/server/game/Entities/Unit/Unit.h
- @@ -702,6 +702,26 @@ struct TC_GAME_API CharmInfo
- float _stayZ;
- };
- +struct AttackPosition {
- + AttackPosition(Position pos) : _pos(pos), _taken(false) {}
- + bool operator==(const int val)
- + {
- + return val == NULL;
- + };
- + int operator=(const int val)
- + {
- + if (val == NULL)
- + {
- + _pos = NULL;
- + _taken = false;
- + return NULL;
- + }
- + return NULL;
- + };
- + Position _pos;
- + bool _taken;
- +};
- +
- // for clearing special attacks
- #define REACTIVE_TIMER_START 4000
- @@ -789,6 +809,7 @@ class TC_GAME_API Unit : public WorldObject
- bool CanDualWield() const { return m_canDualWield; }
- virtual void SetCanDualWield(bool value) { m_canDualWield = value; }
- float GetCombatReach() const override { return m_floatValues[UNIT_FIELD_COMBATREACH]; }
- + bool IsWithinRange(Unit const* obj, float dist) const;
- bool IsWithinCombatRange(Unit const* obj, float dist2compare) const;
- bool IsWithinMeleeRange(Unit const* obj) const { return IsWithinMeleeRangeAt(GetPosition(), obj); }
- bool IsWithinMeleeRangeAt(Position const& pos, Unit const* obj) const;
- @@ -805,6 +826,10 @@ class TC_GAME_API Unit : public WorldObject
- bool AttackStop();
- void RemoveAllAttackers();
- AttackerSet const& getAttackers() const { return m_attackers; }
- +
- + void Unit::SetMeleeAttackPoints();
- + Position GetMeleeAttackPoint(Unit* attacker);
- +
- bool isAttackingPlayer() const;
- Unit* GetVictim() const { return m_attacking; }
- // Use this only when 100% sure there is a victim
- @@ -1676,6 +1701,9 @@ class TC_GAME_API Unit : public WorldObject
- virtual void Whisper(uint32 textId, Player* target, bool isBossWhisper = false);
- float GetCollisionHeight() const override;
- +
- + AttackPosition getAttackPosition() { return m_attackPosition; }
- +
- protected:
- explicit Unit (bool isWorldObject);
- @@ -1756,6 +1784,10 @@ class TC_GAME_API Unit : public WorldObject
- virtual void AtEnterCombat() { }
- virtual void AtExitCombat();
- + std::vector<AttackPosition> attackMeleePositions;
- + Position m_previousPosition;
- + uint8 m_previousAttackerCount;
- + AttackPosition m_attackPosition;
- private:
- void UpdateSplineMovement(uint32 t_diff);
- @@ -1799,6 +1831,9 @@ class TC_GAME_API Unit : public WorldObject
- bool _isWalkingBeforeCharm; ///< Are we walking before we were charmed?
- SpellHistory* m_spellHistory;
- +
- + static constexpr uint32 ATTACK_POINT_CHECK_INTERVAL = 200;
- + uint32 _attackPointCheckTimer = ATTACK_POINT_CHECK_INTERVAL;
- };
- namespace Trinity
- diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp
- index ebccc6fa48..2712c85cf8 100644
- --- a/src/server/game/Movement/MotionMaster.cpp
- +++ b/src/server/game/Movement/MotionMaster.cpp
- @@ -595,6 +595,54 @@ void MotionMaster::MoveChase(Unit* target, Optional<ChaseRange> dist, Optional<C
- Add(new ChaseMovementGenerator(target, dist, angle));
- }
- +void MotionMaster::MoveCircleTarget(Unit* target)
- +{
- + if (!target)
- + return;
- +
- + //TC_LOG_DEBUG("server", "MoveCircleTarget");
- +
- + Position point = target->GetMeleeAttackPoint(_owner);
- + if (point == NULL)
- + return;
- +
- + if (_owner->IsFlying())
- + ; // Dont do anything yet might add later.
- + else
- + point.m_positionZ = _owner->GetMapHeight(point.m_positionX, point.m_positionY, point.m_positionZ);
- +
- + Movement::MoveSplineInit init(_owner);
- + init.MoveTo(point.m_positionX, point.m_positionY, point.m_positionZ, true, true);
- + init.SetFacing(target);
- + init.Launch();
- +}
- +
- +void MotionMaster::MoveBackwards(Unit* target, float dist)
- +{
- + if (!target)
- + return;
- +
- + //TC_LOG_DEBUG("server", "MoveBackwards");
- +
- + Position const& pos = target->GetPosition();
- + float angle = pos.GetOrientation() + (M_PI*2);
- + G3D::Vector3 point;
- + point.x = pos.m_positionX + dist * cosf(angle);
- + point.y = pos.m_positionY + dist * sinf(angle);
- + point.z = pos.m_positionZ;
- +
- + //if (_owner->IsFlying())
- + // point.z = pos.m_positionZ;
- + //else
- + // point.z = _owner->GetMapHeight(point.x, point.y, point.z);
- +
- + Movement::MoveSplineInit init(_owner);
- + init.MoveTo(point.x, point.y, point.z);
- + init.SetFacing(target);
- + init.SetBackward();
- + init.Launch();
- +}
- +
- void MotionMaster::MoveConfused()
- {
- if (_owner->GetTypeId() == TYPEID_PLAYER)
- diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h
- index 3be8d735a2..592fec1c92 100644
- --- a/src/server/game/Movement/MotionMaster.h
- +++ b/src/server/game/Movement/MotionMaster.h
- @@ -142,6 +142,8 @@ class TC_GAME_API MotionMaster
- void MoveFollow(Unit* target, float dist, ChaseAngle angle, MovementSlot slot = MOTION_SLOT_ACTIVE);
- void MoveChase(Unit* target, Optional<ChaseRange> dist = {}, Optional<ChaseAngle> angle = {});
- void MoveChase(Unit* target, float dist, float angle = 0.0f) { MoveChase(target, Optional<ChaseRange>(dist), Optional<ChaseAngle>(angle)); }
- + void MoveCircleTarget(Unit* target);
- + void MoveBackwards(Unit* target, float dist);
- void MoveConfused();
- void MoveFleeing(Unit* enemy, uint32 time = 0);
- void MovePoint(uint32 id, Position const& pos, bool generatePath = true, Optional<float> finalOrient = {});
- diff --git a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp
- index f83c7e8b16..f6554e932a 100644
- --- a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp
- +++ b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp
- @@ -73,7 +73,7 @@ void ChaseMovementGenerator::Initialize(Unit* owner)
- owner->SetWalk(false);
- _path = nullptr;
- - _lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f);
- + //_lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f);
- }
- void ChaseMovementGenerator::Reset(Unit* owner)
- @@ -121,7 +121,8 @@ bool ChaseMovementGenerator::Update(Unit* owner, uint32 diff)
- else
- {
- _rangeCheckTimer = RANGE_CHECK_INTERVAL;
- - if (PositionOkay(owner, target, _movingTowards ? Optional<float>() : minTarget, _movingTowards ? maxTarget : Optional<float>(), angle))
- + if (PositionOkay(owner, target, _movingTowards ? Optional<float>() : minTarget, _movingTowards ? maxTarget : Optional<float>(), angle) &&
- + owner->getAttackPosition() == NULL)
- {
- _path = nullptr;
- owner->StopMoving();
- @@ -141,73 +142,100 @@ bool ChaseMovementGenerator::Update(Unit* owner, uint32 diff)
- DoMovementInform(owner, target);
- }
- - // if the target moved, we have to consider whether to adjust
- - if (_lastTargetPosition != target->GetPosition() || mutualChase != _mutualChase)
- + //if (owner->HasUnitState(UNIT_STATE_CHASE_MOVE))
- + //{
- + if (_pathCheckTimer > diff)
- {
- - _lastTargetPosition = target->GetPosition();
- - _mutualChase = mutualChase;
- - if (owner->HasUnitState(UNIT_STATE_CHASE_MOVE) || !PositionOkay(owner, target, minRange, maxRange, angle))
- + _pathCheckTimer -= diff;
- + return true;
- + }
- + else
- + {
- + _pathCheckTimer = PATH_CHECK_INTERVAL;
- + }
- + //}
- +
- + if (owner->HasUnitState(UNIT_STATE_CHASE_MOVE) || !PositionOkay(owner, target, minRange, maxRange, angle))
- + {
- + Creature* const cOwner = owner->ToCreature();
- + // can we get to the target?
- + if (cOwner && !target->isInAccessiblePlaceFor(cOwner))
- {
- - Creature* const cOwner = owner->ToCreature();
- - // can we get to the target?
- - if (cOwner && !target->isInAccessiblePlaceFor(cOwner))
- - {
- - cOwner->SetCannotReachTarget(true);
- - cOwner->StopMoving();
- - _path = nullptr;
- - return true;
- - }
- + cOwner->SetCannotReachTarget(true);
- + cOwner->StopMoving();
- + _path = nullptr;
- + return true;
- + }
- - // figure out which way we want to move
- - bool const moveToward = !owner->IsInDist(target, maxRange);
- + // Fan Creatures around target if there are more than one.
- + Unit * target = GetTarget();
- + int chaserCount = target->getAttackers().size();
- + // Only start fanning if its within a certain distance.
- + if (chaserCount > 1)
- + {
- + owner->GetMotionMaster()->MoveCircleTarget(target);
- + return true;
- + }
- - // make a new path if we have to...
- - if (!_path || moveToward != _movingTowards)
- - _path = std::make_unique<PathGenerator>(owner);
- + // figure out which way we want to move
- + bool const moveToward = !owner->IsInDist(target, maxRange);
- - float x, y, z;
- - bool shortenPath;
- - // if we want to move toward the target and there's no fixed angle...
- - if (moveToward && !angle)
- - {
- - // ...we'll pathfind to the center, then shorten the path
- - target->GetPosition(x, y, z);
- - shortenPath = true;
- - }
- - else
- - {
- - // otherwise, we fall back to nearpoint finding
- - target->GetNearPoint(owner, x, y, z, (moveToward ? maxTarget : minTarget) - hitboxSum, angle ? target->ToAbsoluteAngle(angle->RelativeAngle) : target->GetAbsoluteAngle(owner));
- - shortenPath = false;
- - }
- + // make a new path if we have to...
- + if (!_path || moveToward != _movingTowards)
- + _path = std::make_unique<PathGenerator>(owner);
- - if (owner->IsHovering())
- - owner->UpdateAllowedPositionZ(x, y, z);
- + float x, y, z;
- + bool shortenPath;
- + // if we want to move toward the target and there's no fixed angle...
- + if (moveToward && !angle)
- + {
- + // ...we'll pathfind to the center, then shorten the path
- + target->GetPosition(x, y, z);
- + shortenPath = true;
- + }
- + else
- + {
- + // otherwise, we fall back to nearpoint finding
- + target->GetNearPoint(owner, x, y, z, (moveToward ? maxTarget : minTarget) - hitboxSum, angle ? target->ToAbsoluteAngle(angle->RelativeAngle) : target->GetAbsoluteAngle(owner));
- + shortenPath = false;
- + }
- - bool success = _path->CalculatePath(x, y, z);
- - if (!success || (_path->GetPathType() & PATHFIND_NOPATH))
- - {
- - if (cOwner)
- - cOwner->SetCannotReachTarget(true);
- - owner->StopMoving();
- - return true;
- - }
- + if (owner->IsHovering())
- + owner->UpdateAllowedPositionZ(x, y, z);
- - if (shortenPath)
- - _path->ShortenPathUntilDist(PositionToVector3(target), maxTarget);
- + bool success = _path->CalculatePath(x, y, z);
- + // Special case where Enemy cant get close to player to Melee because of height difference.
- + float floorZ;
- + bool canReach = true;
- + if (target && target->IsFlying() && !owner->IsFlying())
- + {
- + target->UpdateAllowedPositionZ(_path->GetEndPosition().x, _path->GetEndPosition().y, floorZ);
- + if (abs(floorZ - _path->GetStartPosition().z) > MELEE_RANGE)
- + canReach = false;
- + }
- +
- + if ((!success || (!canReach && success)) || (_path->GetPathType() & PATHFIND_NOPATH))
- + {
- if (cOwner)
- - cOwner->SetCannotReachTarget(false);
- + cOwner->SetCannotReachTarget(true);
- + owner->StopMoving();
- + return true;
- + }
- +
- + if (shortenPath)
- + _path->ShortenPathUntilDist(PositionToVector3(target), maxTarget);
- - owner->AddUnitState(UNIT_STATE_CHASE_MOVE);
- + if (cOwner)
- + cOwner->SetCannotReachTarget(false);
- - Movement::MoveSplineInit init(owner);
- - init.MovebyPath(_path->GetPath());
- - init.SetWalk(false);
- - init.SetFacing(target);
- + owner->AddUnitState(UNIT_STATE_CHASE_MOVE);
- - init.Launch();
- - }
- + Movement::MoveSplineInit moveSplineInit(owner);
- + moveSplineInit.MovebyPath(_path->GetPath());
- + moveSplineInit.SetWalk(false);
- + moveSplineInit.SetFacing(target);
- + moveSplineInit.Launch();
- }
- // and then, finally, we're done for the tick
- diff --git a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h
- index 48d828b760..aef1a9c166 100644
- --- a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h
- +++ b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h
- @@ -40,19 +40,21 @@ class ChaseMovementGenerator : public MovementGenerator, public AbstractFollower
- void Finalize(Unit*, bool, bool) override;
- MovementGeneratorType GetMovementGeneratorType() const override { return CHASE_MOTION_TYPE; }
- - void UnitSpeedChanged() override { _lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f); }
- + //void UnitSpeedChanged() override { _lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f); }
- private:
- - static constexpr uint32 RANGE_CHECK_INTERVAL = 100; // time (ms) until we attempt to recalculate
- + static constexpr uint32 RANGE_CHECK_INTERVAL = 500; // time (ms) until we attempt to recalculate
- + static constexpr uint32 PATH_CHECK_INTERVAL = 500;
- Optional<ChaseRange> const _range;
- Optional<ChaseAngle> const _angle;
- std::unique_ptr<PathGenerator> _path;
- - Position _lastTargetPosition;
- + //Position _lastTargetPosition;
- uint32 _rangeCheckTimer = RANGE_CHECK_INTERVAL;
- + uint32 _pathCheckTimer = PATH_CHECK_INTERVAL;
- bool _movingTowards = true;
- - bool _mutualChase = true;
- + //bool _mutualChase = true;
- };
- #endif
Add Comment
Please, Sign In to add comment