Guest User

Untitled

a guest
Jul 21st, 2018
85
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 26.00 KB | None | 0 0
  1. diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp
  2. index 1dd66d7699..8683884b25 100644
  3. --- a/src/server/game/AI/CreatureAI.cpp
  4. +++ b/src/server/game/AI/CreatureAI.cpp
  5. @@ -350,6 +350,40 @@ void CreatureAI::SetBoundary(CreatureBoundary const* boundary, bool negateBounda
  6. me->DoImmediateBoundaryCheck();
  7. }
  8.  
  9. +bool CreatureAI::CheckMeleeRepositionRequirements()
  10. +{
  11. + if (Unit* victim = me->GetVictim())
  12. + {
  13. + Position victimPos = victim->GetPosition();
  14. +
  15. + // If we are closer than 50% of the combat reach we are going to reposition ourself
  16. + // Dont call if we have more than one attacker because Circling Target will take place.
  17. + float reach = CalculatePct(me->GetCombatReach() + victim->GetCombatReach(), 50);
  18. + float moveDist = CalculatePct(me->GetCombatReach() + victim->GetCombatReach(), 100);
  19. + if (me->IsFreeToMove() && victim->getAttackers().size() == 1 && me->GetDistance(victimPos) < reach)
  20. + {
  21. + me->GetMotionMaster()->MoveBackwards(victim, moveDist);
  22. + return true;
  23. + }
  24. + }
  25. + return false;
  26. +}
  27. +
  28. +bool CreatureAI::CheckCircleRepositionRequirements()
  29. +{
  30. + if (Unit* victim = me->GetVictim())
  31. + {
  32. + Position victimPos = victim->GetPosition();
  33. +
  34. + if (me->IsFreeToMove() && victim->getAttackers().size() > 1)
  35. + {
  36. + me->GetMotionMaster()->MoveCircleTarget(victim);
  37. + return true;
  38. + }
  39. + }
  40. + return false;
  41. +}
  42. +
  43. Creature* CreatureAI::DoSummon(uint32 entry, Position const& pos, uint32 despawnTime, TempSummonType summonType)
  44. {
  45. return me->SummonCreature(entry, pos, summonType, despawnTime);
  46. diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h
  47. index d7cfec7b0b..25284740d3 100644
  48. --- a/src/server/game/AI/CreatureAI.h
  49. +++ b/src/server/game/AI/CreatureAI.h
  50. @@ -226,6 +226,9 @@ class TC_GAME_API CreatureAI : public UnitAI
  51. static bool IsInBounds(CreatureBoundary const& boundary, Position const* who);
  52. bool IsInBoundary(Position const* who = nullptr) const;
  53.  
  54. + bool CheckMeleeRepositionRequirements();
  55. + bool CheckCircleRepositionRequirements();
  56. +
  57. protected:
  58. virtual void MoveInLineOfSight(Unit* /*who*/);
  59.  
  60. diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
  61. index 0ac2b3be02..6a0b813a15 100644
  62. --- a/src/server/game/Entities/Creature/Creature.cpp
  63. +++ b/src/server/game/Entities/Creature/Creature.cpp
  64. @@ -779,6 +779,25 @@ void Creature::Update(uint32 diff)
  65. m_boundaryCheckTime -= diff;
  66. }
  67.  
  68. + // Moving back from the target.
  69. + if (diff >= m_moveBackMovementTime)
  70. + {
  71. + AI()->CheckMeleeRepositionRequirements();
  72. + m_moveBackMovementTime = MOVE_BACK_CHECK_INTERVAL;
  73. + }
  74. + else
  75. + m_moveBackMovementTime -= diff;
  76. +
  77. + // Circling the target.
  78. + if (diff >= m_moveCircleMovementTime)
  79. + {
  80. + AI()->CheckCircleRepositionRequirements();
  81. + m_moveCircleMovementTime = MOVE_CIRCLE_CHECK_INTERVAL;
  82. + }
  83. + else
  84. + m_moveCircleMovementTime -= diff;
  85. +
  86. +
  87. // if periodic combat pulse is enabled and we are both in combat and in a dungeon, do this now
  88. if (m_combatPulseDelay > 0 && IsEngaged() && GetMap()->IsDungeon())
  89. {
  90. @@ -3272,3 +3291,15 @@ bool Creature::IsEscortNPC(bool onlyIfActive)
  91.  
  92. return AI()->IsEscortNPC(onlyIfActive);
  93. }
  94. +
  95. +bool Creature::IsFreeToMove()
  96. +{
  97. + uint32 moveFlags = m_movementInfo.GetMovementFlags();
  98. + // Do not reposition ourself when we are not allowed to move
  99. + if ((IsMovementPreventedByCasting() || isMoving() || !CanFreeMove()) &&
  100. + GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE ||
  101. + moveFlags & MOVEMENTFLAG_SPLINE_ENABLED)
  102. + return false;
  103. +
  104. + return true;
  105. +}
  106. diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
  107. index 23e567f733..ff1dde1039 100644
  108. --- a/src/server/game/Entities/Creature/Creature.h
  109. +++ b/src/server/game/Entities/Creature/Creature.h
  110. @@ -348,6 +348,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
  111. void ReleaseFocus(Spell const* focusSpell = nullptr, bool withDelay = true);
  112.  
  113. bool IsMovementPreventedByCasting() const override;
  114. + bool IsFreeToMove();
  115.  
  116. // Part of Evade mechanics
  117. time_t GetLastDamagedTime() const { return _lastDamagedTime; }
  118. @@ -386,6 +387,11 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
  119. uint32 m_combatPulseTime; // (msecs) remaining time for next zone-in-combat pulse
  120. uint32 m_combatPulseDelay; // (secs) how often the creature puts the entire zone in combat (only works in dungeons)
  121.  
  122. + static constexpr uint32 MOVE_BACK_CHECK_INTERVAL = 3000;
  123. + static constexpr uint32 MOVE_CIRCLE_CHECK_INTERVAL = 3000;
  124. + uint32 m_moveBackMovementTime = MOVE_BACK_CHECK_INTERVAL;
  125. + uint32 m_moveCircleMovementTime = MOVE_CIRCLE_CHECK_INTERVAL;
  126. +
  127. ReactStates m_reactState; // for AI, not charmInfo
  128. void RegenerateHealth();
  129. void Regenerate(Powers power);
  130. diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
  131. index 09f5ef01a5..1d39fd9cdc 100644
  132. --- a/src/server/game/Entities/Unit/Unit.cpp
  133. +++ b/src/server/game/Entities/Unit/Unit.cpp
  134. @@ -287,6 +287,7 @@ bool DispelableAura::RollDispel() const
  135. return roll_chance_i(_chance);
  136. }
  137.  
  138. +
  139. Unit::Unit(bool isWorldObject) :
  140. WorldObject(isWorldObject), m_playerMovingMe(nullptr), m_lastSanctuaryTime(0),
  141. IsAIEnabled(false), NeedChangeAI(false), LastCharmerGUID(), m_ControlledByPlayer(false),
  142. @@ -294,7 +295,8 @@ Unit::Unit(bool isWorldObject) :
  143. m_AutoRepeatFirstCast(false), m_procDeep(0), m_removedAurasCount(0),
  144. i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_vehicle(nullptr),
  145. m_vehicleKit(nullptr), m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_combatManager(this),
  146. - m_threatManager(this), m_comboTarget(nullptr), m_comboPoints(0), m_spellHistory(new SpellHistory(this))
  147. + m_threatManager(this), m_comboTarget(nullptr), m_comboPoints(0), m_spellHistory(new SpellHistory(this)),
  148. + m_attackPosition(NULL)
  149. {
  150. m_objectType |= TYPEMASK_UNIT;
  151. m_objectTypeId = TYPEID_UNIT;
  152. @@ -451,6 +453,16 @@ void Unit::Update(uint32 p_time)
  153. ModifyAuraState(AURA_STATE_HEALTH_ABOVE_75_PERCENT, HealthAbovePct(75));
  154. }
  155.  
  156. + if (_attackPointCheckTimer > p_time)
  157. + {
  158. + _attackPointCheckTimer -= p_time;
  159. + }
  160. + else
  161. + {
  162. + _attackPointCheckTimer = ATTACK_POINT_CHECK_INTERVAL;
  163. + SetMeleeAttackPoints();
  164. + }
  165. +
  166. UpdateSplineMovement(p_time);
  167. i_motionMaster->Update(p_time);
  168. }
  169. @@ -554,6 +566,20 @@ bool Unit::IsWithinMeleeRangeAt(Position const& pos, Unit const* obj) const
  170. return distsq <= maxdist * maxdist;
  171. }
  172.  
  173. +bool Unit::IsWithinRange(Unit const* obj, float dist) const
  174. +{
  175. + if (!obj || !IsInMap(obj) || !InSamePhase(obj))
  176. + return false;
  177. +
  178. + float dx = GetPositionX() - obj->GetPositionX();
  179. + float dy = GetPositionY() - obj->GetPositionY();
  180. + float dz = GetPositionZ() - obj->GetPositionZ();
  181. + float distsq = dx * dx + dy * dy + dz * dz;
  182. +
  183. + return distsq <= dist * dist;
  184. +}
  185. +
  186. +
  187. float Unit::GetMeleeRange(Unit const* target) const
  188. {
  189. float range = GetCombatReach() + target->GetCombatReach() + 4.0f / 3.0f;
  190. @@ -2005,7 +2031,7 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr
  191.  
  192. if (GetTypeId() == TYPEID_UNIT && !HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_POSSESSED) && !HasFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_DISABLE_TURN))
  193. SetFacingToObject(victim, false); // update client side facing to face the target (prevents visual glitches when casting untargeted spells)
  194. -
  195. +
  196. // melee attack spell cast at main hand attack only - no normal melee dmg dealt
  197. if (attType == BASE_ATTACK && m_currentSpells[CURRENT_MELEE_SPELL] && !extra)
  198. m_currentSpells[CURRENT_MELEE_SPELL]->cast();
  199. @@ -13501,3 +13527,91 @@ float Unit::GetCollisionHeight() const
  200. float const collisionHeight = scaleMod * modelData->CollisionHeight * modelData->Scale * displayInfo->scale;
  201. return collisionHeight == 0.0f ? DEFAULT_COLLISION_HEIGHT : collisionHeight;
  202. }
  203. +
  204. +
  205. +struct AttackDistance {
  206. + AttackDistance(uint8 index, AttackPosition attackPos) : _index(index), _attackPos(attackPos) {}
  207. + uint8 _index;
  208. + AttackPosition _attackPos;
  209. +};
  210. +
  211. +void Unit::SetMeleeAttackPoints()
  212. +{
  213. + if (getAttackers().size() <= 1)
  214. + {
  215. + return;
  216. + }
  217. +
  218. + // Delete the attack positions each iteration.
  219. + attackMeleePositions.clear();
  220. +
  221. + // Calculate the attack positions.
  222. + // radius (Melee range unknown so use default).
  223. + float radius = MIN_MELEE_REACH;
  224. + uint8 attackPoints = getAttackers().size() * 3;
  225. + for (uint8 i = 0; i < attackPoints; ++i)
  226. + {
  227. + int8 anglePosition = ceil((i+1)/2) * ((i+1) % 2 ? -1 : 1);
  228. + float step = float(M_PI*2) / attackPoints;
  229. + Position const& pos = GetPosition();
  230. + float angle = GetOrientation() + float(M_PI * 2) + (step * anglePosition);
  231. + //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);
  232. + attackMeleePositions.push_back(AttackPosition(Position(pos.m_positionX + radius * cosf(angle), pos.m_positionY + radius * sinf(angle), pos.m_positionZ)));
  233. + }
  234. + m_previousAttackerCount = getAttackers().size();
  235. + m_previousPosition = GetPosition();
  236. +}
  237. +
  238. +Position Unit::GetMeleeAttackPoint(Unit* attacker)
  239. +{
  240. + if (getAttackers().size() <= 1)
  241. + return NULL;
  242. +
  243. + // If already on an attack Position and close to Target abort.
  244. + if (attacker->GetDistance(GetPosition()) < GetCombatReach() && !(attacker->m_attackPosition == NULL) && attacker->GetDistance(attacker->m_attackPosition._pos) < 0.25f)
  245. + return NULL;
  246. + attacker->m_attackPosition = NULL;
  247. +
  248. + // Get all the distances.
  249. + std::vector<AttackDistance> distances;
  250. + distances.reserve( attackMeleePositions.size());
  251. + for (uint8 i = 0; i < attackMeleePositions.size(); ++i)
  252. + {
  253. + // If the spot has been taken.
  254. + if (!attackMeleePositions[i]._taken)
  255. + distances.push_back(AttackDistance(i,attackMeleePositions[i]));
  256. + }
  257. +
  258. + if (distances.size() == 0)
  259. + return NULL;
  260. +
  261. + // Get the shortest point.
  262. + uint8 shortestIndex = 0;
  263. + float shortestLength = 100.0f;
  264. + for (uint8 i = 0; i < distances.size(); ++i)
  265. + {
  266. + float dist = attacker->GetDistance2d(distances[i]._attackPos._pos.m_positionX, distances[i]._attackPos._pos.m_positionY); // +GetDistance(distances[i]._attackPos._pos);
  267. + //TC_LOG_DEBUG("server", "dist=(%4.1f)", dist);
  268. + if (shortestLength > dist)
  269. + {
  270. + shortestLength = dist;
  271. + shortestIndex = i;
  272. + }
  273. + }
  274. + //TC_LOG_DEBUG("server", "shortestLength=(%4.1f)", shortestLength);
  275. +
  276. + // Create closest Position.
  277. + Position closestPos(distances[shortestIndex]._attackPos._pos);
  278. +
  279. + // Too close mark point taken and find another spot.
  280. + for (uint8 i = 0; i < attackMeleePositions.size(); ++i)
  281. + {
  282. + float dist = closestPos.GetExactDist(attackMeleePositions[i]._pos);
  283. + //TC_LOG_DEBUG("server", "points_dist=(%4.1f)", dist);
  284. + if (dist < GetCombatReach()/2)
  285. + attackMeleePositions[i]._taken = true;
  286. + }
  287. + attacker->m_attackPosition = distances[shortestIndex]._attackPos;
  288. +
  289. + return closestPos;
  290. +}
  291. diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
  292. index dfd1c1e020..6bd4005951 100644
  293. --- a/src/server/game/Entities/Unit/Unit.h
  294. +++ b/src/server/game/Entities/Unit/Unit.h
  295. @@ -702,6 +702,26 @@ struct TC_GAME_API CharmInfo
  296. float _stayZ;
  297. };
  298.  
  299. +struct AttackPosition {
  300. + AttackPosition(Position pos) : _pos(pos), _taken(false) {}
  301. + bool operator==(const int val)
  302. + {
  303. + return val == NULL;
  304. + };
  305. + int operator=(const int val)
  306. + {
  307. + if (val == NULL)
  308. + {
  309. + _pos = NULL;
  310. + _taken = false;
  311. + return NULL;
  312. + }
  313. + return NULL;
  314. + };
  315. + Position _pos;
  316. + bool _taken;
  317. +};
  318. +
  319. // for clearing special attacks
  320. #define REACTIVE_TIMER_START 4000
  321.  
  322. @@ -789,6 +809,7 @@ class TC_GAME_API Unit : public WorldObject
  323. bool CanDualWield() const { return m_canDualWield; }
  324. virtual void SetCanDualWield(bool value) { m_canDualWield = value; }
  325. float GetCombatReach() const override { return m_floatValues[UNIT_FIELD_COMBATREACH]; }
  326. + bool IsWithinRange(Unit const* obj, float dist) const;
  327. bool IsWithinCombatRange(Unit const* obj, float dist2compare) const;
  328. bool IsWithinMeleeRange(Unit const* obj) const { return IsWithinMeleeRangeAt(GetPosition(), obj); }
  329. bool IsWithinMeleeRangeAt(Position const& pos, Unit const* obj) const;
  330. @@ -805,6 +826,10 @@ class TC_GAME_API Unit : public WorldObject
  331. bool AttackStop();
  332. void RemoveAllAttackers();
  333. AttackerSet const& getAttackers() const { return m_attackers; }
  334. +
  335. + void Unit::SetMeleeAttackPoints();
  336. + Position GetMeleeAttackPoint(Unit* attacker);
  337. +
  338. bool isAttackingPlayer() const;
  339. Unit* GetVictim() const { return m_attacking; }
  340. // Use this only when 100% sure there is a victim
  341. @@ -1676,6 +1701,9 @@ class TC_GAME_API Unit : public WorldObject
  342. virtual void Whisper(uint32 textId, Player* target, bool isBossWhisper = false);
  343.  
  344. float GetCollisionHeight() const override;
  345. +
  346. + AttackPosition getAttackPosition() { return m_attackPosition; }
  347. +
  348. protected:
  349. explicit Unit (bool isWorldObject);
  350.  
  351. @@ -1756,6 +1784,10 @@ class TC_GAME_API Unit : public WorldObject
  352. virtual void AtEnterCombat() { }
  353. virtual void AtExitCombat();
  354.  
  355. + std::vector<AttackPosition> attackMeleePositions;
  356. + Position m_previousPosition;
  357. + uint8 m_previousAttackerCount;
  358. + AttackPosition m_attackPosition;
  359. private:
  360.  
  361. void UpdateSplineMovement(uint32 t_diff);
  362. @@ -1799,6 +1831,9 @@ class TC_GAME_API Unit : public WorldObject
  363. bool _isWalkingBeforeCharm; ///< Are we walking before we were charmed?
  364.  
  365. SpellHistory* m_spellHistory;
  366. +
  367. + static constexpr uint32 ATTACK_POINT_CHECK_INTERVAL = 200;
  368. + uint32 _attackPointCheckTimer = ATTACK_POINT_CHECK_INTERVAL;
  369. };
  370.  
  371. namespace Trinity
  372. diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp
  373. index ebccc6fa48..2712c85cf8 100644
  374. --- a/src/server/game/Movement/MotionMaster.cpp
  375. +++ b/src/server/game/Movement/MotionMaster.cpp
  376. @@ -595,6 +595,54 @@ void MotionMaster::MoveChase(Unit* target, Optional<ChaseRange> dist, Optional<C
  377. Add(new ChaseMovementGenerator(target, dist, angle));
  378. }
  379.  
  380. +void MotionMaster::MoveCircleTarget(Unit* target)
  381. +{
  382. + if (!target)
  383. + return;
  384. +
  385. + //TC_LOG_DEBUG("server", "MoveCircleTarget");
  386. +
  387. + Position point = target->GetMeleeAttackPoint(_owner);
  388. + if (point == NULL)
  389. + return;
  390. +
  391. + if (_owner->IsFlying())
  392. + ; // Dont do anything yet might add later.
  393. + else
  394. + point.m_positionZ = _owner->GetMapHeight(point.m_positionX, point.m_positionY, point.m_positionZ);
  395. +
  396. + Movement::MoveSplineInit init(_owner);
  397. + init.MoveTo(point.m_positionX, point.m_positionY, point.m_positionZ, true, true);
  398. + init.SetFacing(target);
  399. + init.Launch();
  400. +}
  401. +
  402. +void MotionMaster::MoveBackwards(Unit* target, float dist)
  403. +{
  404. + if (!target)
  405. + return;
  406. +
  407. + //TC_LOG_DEBUG("server", "MoveBackwards");
  408. +
  409. + Position const& pos = target->GetPosition();
  410. + float angle = pos.GetOrientation() + (M_PI*2);
  411. + G3D::Vector3 point;
  412. + point.x = pos.m_positionX + dist * cosf(angle);
  413. + point.y = pos.m_positionY + dist * sinf(angle);
  414. + point.z = pos.m_positionZ;
  415. +
  416. + //if (_owner->IsFlying())
  417. + // point.z = pos.m_positionZ;
  418. + //else
  419. + // point.z = _owner->GetMapHeight(point.x, point.y, point.z);
  420. +
  421. + Movement::MoveSplineInit init(_owner);
  422. + init.MoveTo(point.x, point.y, point.z);
  423. + init.SetFacing(target);
  424. + init.SetBackward();
  425. + init.Launch();
  426. +}
  427. +
  428. void MotionMaster::MoveConfused()
  429. {
  430. if (_owner->GetTypeId() == TYPEID_PLAYER)
  431. diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h
  432. index 3be8d735a2..592fec1c92 100644
  433. --- a/src/server/game/Movement/MotionMaster.h
  434. +++ b/src/server/game/Movement/MotionMaster.h
  435. @@ -142,6 +142,8 @@ class TC_GAME_API MotionMaster
  436. void MoveFollow(Unit* target, float dist, ChaseAngle angle, MovementSlot slot = MOTION_SLOT_ACTIVE);
  437. void MoveChase(Unit* target, Optional<ChaseRange> dist = {}, Optional<ChaseAngle> angle = {});
  438. void MoveChase(Unit* target, float dist, float angle = 0.0f) { MoveChase(target, Optional<ChaseRange>(dist), Optional<ChaseAngle>(angle)); }
  439. + void MoveCircleTarget(Unit* target);
  440. + void MoveBackwards(Unit* target, float dist);
  441. void MoveConfused();
  442. void MoveFleeing(Unit* enemy, uint32 time = 0);
  443. void MovePoint(uint32 id, Position const& pos, bool generatePath = true, Optional<float> finalOrient = {});
  444. diff --git a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp
  445. index f83c7e8b16..f6554e932a 100644
  446. --- a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp
  447. +++ b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.cpp
  448. @@ -73,7 +73,7 @@ void ChaseMovementGenerator::Initialize(Unit* owner)
  449.  
  450. owner->SetWalk(false);
  451. _path = nullptr;
  452. - _lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f);
  453. + //_lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f);
  454. }
  455.  
  456. void ChaseMovementGenerator::Reset(Unit* owner)
  457. @@ -121,7 +121,8 @@ bool ChaseMovementGenerator::Update(Unit* owner, uint32 diff)
  458. else
  459. {
  460. _rangeCheckTimer = RANGE_CHECK_INTERVAL;
  461. - if (PositionOkay(owner, target, _movingTowards ? Optional<float>() : minTarget, _movingTowards ? maxTarget : Optional<float>(), angle))
  462. + if (PositionOkay(owner, target, _movingTowards ? Optional<float>() : minTarget, _movingTowards ? maxTarget : Optional<float>(), angle) &&
  463. + owner->getAttackPosition() == NULL)
  464. {
  465. _path = nullptr;
  466. owner->StopMoving();
  467. @@ -141,73 +142,100 @@ bool ChaseMovementGenerator::Update(Unit* owner, uint32 diff)
  468. DoMovementInform(owner, target);
  469. }
  470.  
  471. - // if the target moved, we have to consider whether to adjust
  472. - if (_lastTargetPosition != target->GetPosition() || mutualChase != _mutualChase)
  473. + //if (owner->HasUnitState(UNIT_STATE_CHASE_MOVE))
  474. + //{
  475. + if (_pathCheckTimer > diff)
  476. {
  477. - _lastTargetPosition = target->GetPosition();
  478. - _mutualChase = mutualChase;
  479. - if (owner->HasUnitState(UNIT_STATE_CHASE_MOVE) || !PositionOkay(owner, target, minRange, maxRange, angle))
  480. + _pathCheckTimer -= diff;
  481. + return true;
  482. + }
  483. + else
  484. + {
  485. + _pathCheckTimer = PATH_CHECK_INTERVAL;
  486. + }
  487. + //}
  488. +
  489. + if (owner->HasUnitState(UNIT_STATE_CHASE_MOVE) || !PositionOkay(owner, target, minRange, maxRange, angle))
  490. + {
  491. + Creature* const cOwner = owner->ToCreature();
  492. + // can we get to the target?
  493. + if (cOwner && !target->isInAccessiblePlaceFor(cOwner))
  494. {
  495. - Creature* const cOwner = owner->ToCreature();
  496. - // can we get to the target?
  497. - if (cOwner && !target->isInAccessiblePlaceFor(cOwner))
  498. - {
  499. - cOwner->SetCannotReachTarget(true);
  500. - cOwner->StopMoving();
  501. - _path = nullptr;
  502. - return true;
  503. - }
  504. + cOwner->SetCannotReachTarget(true);
  505. + cOwner->StopMoving();
  506. + _path = nullptr;
  507. + return true;
  508. + }
  509.  
  510. - // figure out which way we want to move
  511. - bool const moveToward = !owner->IsInDist(target, maxRange);
  512. + // Fan Creatures around target if there are more than one.
  513. + Unit * target = GetTarget();
  514. + int chaserCount = target->getAttackers().size();
  515. + // Only start fanning if its within a certain distance.
  516. + if (chaserCount > 1)
  517. + {
  518. + owner->GetMotionMaster()->MoveCircleTarget(target);
  519. + return true;
  520. + }
  521.  
  522. - // make a new path if we have to...
  523. - if (!_path || moveToward != _movingTowards)
  524. - _path = std::make_unique<PathGenerator>(owner);
  525. + // figure out which way we want to move
  526. + bool const moveToward = !owner->IsInDist(target, maxRange);
  527.  
  528. - float x, y, z;
  529. - bool shortenPath;
  530. - // if we want to move toward the target and there's no fixed angle...
  531. - if (moveToward && !angle)
  532. - {
  533. - // ...we'll pathfind to the center, then shorten the path
  534. - target->GetPosition(x, y, z);
  535. - shortenPath = true;
  536. - }
  537. - else
  538. - {
  539. - // otherwise, we fall back to nearpoint finding
  540. - target->GetNearPoint(owner, x, y, z, (moveToward ? maxTarget : minTarget) - hitboxSum, angle ? target->ToAbsoluteAngle(angle->RelativeAngle) : target->GetAbsoluteAngle(owner));
  541. - shortenPath = false;
  542. - }
  543. + // make a new path if we have to...
  544. + if (!_path || moveToward != _movingTowards)
  545. + _path = std::make_unique<PathGenerator>(owner);
  546.  
  547. - if (owner->IsHovering())
  548. - owner->UpdateAllowedPositionZ(x, y, z);
  549. + float x, y, z;
  550. + bool shortenPath;
  551. + // if we want to move toward the target and there's no fixed angle...
  552. + if (moveToward && !angle)
  553. + {
  554. + // ...we'll pathfind to the center, then shorten the path
  555. + target->GetPosition(x, y, z);
  556. + shortenPath = true;
  557. + }
  558. + else
  559. + {
  560. + // otherwise, we fall back to nearpoint finding
  561. + target->GetNearPoint(owner, x, y, z, (moveToward ? maxTarget : minTarget) - hitboxSum, angle ? target->ToAbsoluteAngle(angle->RelativeAngle) : target->GetAbsoluteAngle(owner));
  562. + shortenPath = false;
  563. + }
  564.  
  565. - bool success = _path->CalculatePath(x, y, z);
  566. - if (!success || (_path->GetPathType() & PATHFIND_NOPATH))
  567. - {
  568. - if (cOwner)
  569. - cOwner->SetCannotReachTarget(true);
  570. - owner->StopMoving();
  571. - return true;
  572. - }
  573. + if (owner->IsHovering())
  574. + owner->UpdateAllowedPositionZ(x, y, z);
  575.  
  576. - if (shortenPath)
  577. - _path->ShortenPathUntilDist(PositionToVector3(target), maxTarget);
  578. + bool success = _path->CalculatePath(x, y, z);
  579.  
  580. + // Special case where Enemy cant get close to player to Melee because of height difference.
  581. + float floorZ;
  582. + bool canReach = true;
  583. + if (target && target->IsFlying() && !owner->IsFlying())
  584. + {
  585. + target->UpdateAllowedPositionZ(_path->GetEndPosition().x, _path->GetEndPosition().y, floorZ);
  586. + if (abs(floorZ - _path->GetStartPosition().z) > MELEE_RANGE)
  587. + canReach = false;
  588. + }
  589. +
  590. + if ((!success || (!canReach && success)) || (_path->GetPathType() & PATHFIND_NOPATH))
  591. + {
  592. if (cOwner)
  593. - cOwner->SetCannotReachTarget(false);
  594. + cOwner->SetCannotReachTarget(true);
  595. + owner->StopMoving();
  596. + return true;
  597. + }
  598. +
  599. + if (shortenPath)
  600. + _path->ShortenPathUntilDist(PositionToVector3(target), maxTarget);
  601.  
  602. - owner->AddUnitState(UNIT_STATE_CHASE_MOVE);
  603. + if (cOwner)
  604. + cOwner->SetCannotReachTarget(false);
  605.  
  606. - Movement::MoveSplineInit init(owner);
  607. - init.MovebyPath(_path->GetPath());
  608. - init.SetWalk(false);
  609. - init.SetFacing(target);
  610. + owner->AddUnitState(UNIT_STATE_CHASE_MOVE);
  611.  
  612. - init.Launch();
  613. - }
  614. + Movement::MoveSplineInit moveSplineInit(owner);
  615. + moveSplineInit.MovebyPath(_path->GetPath());
  616. + moveSplineInit.SetWalk(false);
  617. + moveSplineInit.SetFacing(target);
  618. + moveSplineInit.Launch();
  619. }
  620.  
  621. // and then, finally, we're done for the tick
  622. diff --git a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h
  623. index 48d828b760..aef1a9c166 100644
  624. --- a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h
  625. +++ b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h
  626. @@ -40,19 +40,21 @@ class ChaseMovementGenerator : public MovementGenerator, public AbstractFollower
  627. void Finalize(Unit*, bool, bool) override;
  628. MovementGeneratorType GetMovementGeneratorType() const override { return CHASE_MOTION_TYPE; }
  629.  
  630. - void UnitSpeedChanged() override { _lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f); }
  631. + //void UnitSpeedChanged() override { _lastTargetPosition.Relocate(0.0f, 0.0f, 0.0f); }
  632.  
  633. private:
  634. - static constexpr uint32 RANGE_CHECK_INTERVAL = 100; // time (ms) until we attempt to recalculate
  635. + static constexpr uint32 RANGE_CHECK_INTERVAL = 500; // time (ms) until we attempt to recalculate
  636. + static constexpr uint32 PATH_CHECK_INTERVAL = 500;
  637.  
  638. Optional<ChaseRange> const _range;
  639. Optional<ChaseAngle> const _angle;
  640.  
  641. std::unique_ptr<PathGenerator> _path;
  642. - Position _lastTargetPosition;
  643. + //Position _lastTargetPosition;
  644. uint32 _rangeCheckTimer = RANGE_CHECK_INTERVAL;
  645. + uint32 _pathCheckTimer = PATH_CHECK_INTERVAL;
  646. bool _movingTowards = true;
  647. - bool _mutualChase = true;
  648. + //bool _mutualChase = true;
  649. };
  650.  
  651. #endif
Add Comment
Please, Sign In to add comment