Last active
December 28, 2019 18:20
-
-
Save Langerz82/2ba589313bff0880e9217a9a49238d8b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp | |
index 09f5ef01a5..1d8ccf5aec 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), | |
@@ -451,6 +452,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 +565,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; | |
@@ -2006,6 +2031,13 @@ 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) | |
+ float tolerance = MIN_MELEE_REACH; | |
+ float radius = MIN_MELEE_REACH + 0.1f; | |
+ if (this->ToCreature() && this->IsWithinRange(victim, tolerance)) | |
+ { | |
+ this->GetMotionMaster()->MoveBackwards(victim, radius); | |
+ } | |
+ | |
// 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 +13533,73 @@ 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, float dist) : _index(index), _dist(dist) {} | |
+ uint8 _index; | |
+ float _dist; | |
+}; | |
+ | |
+void Unit::SetMeleeAttackPoints() | |
+{ | |
+ if (getAttackers().size() <= 1) | |
+ { | |
+ return; | |
+ } | |
+ | |
+ // Delete the attack positions. | |
+ attackMeleePositions.clear(); | |
+ | |
+ // Calculate the attack positions. | |
+ float radius = MELEE_RANGE + GetCombatReach(); | |
+ uint8 attackPoints = getAttackers().size() * 2; | |
+ for (uint8 i = 0; i < attackPoints; ++i) | |
+ { | |
+ int8 anglePosition = ceil((i+1.0f) / 2) * (i % 2 ? -1 : 1); | |
+ float step = float(M_PI) / attackPoints; | |
+ Position const& pos = GetPosition(); | |
+ float angle = GetOrientation() + (step * anglePosition); | |
+ attackMeleePositions.push_back(AttackPosition(Position(pos.m_positionX + radius * cosf(angle), pos.m_positionY + radius * sinf(angle), pos.m_positionZ))); | |
+ } | |
+ m_previousAttackerCount = getAttackers().size(); | |
+} | |
+ | |
+Position Unit::GetMeleeAttackPoint(Unit* attacker) | |
+{ | |
+ if (getAttackers().size() <= 1) | |
+ return 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,attacker->GetDistance(attackMeleePositions[i]._pos))); | |
+ } | |
+ | |
+ 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) | |
+ { | |
+ if (shortestLength > distances[i]._dist) | |
+ { | |
+ shortestLength = distances[i]._dist; | |
+ shortestIndex = distances[i]._index; | |
+ } | |
+ } | |
+ | |
+ // Create closest Position. | |
+ Position closestPos(attackMeleePositions[shortestIndex]._pos.m_positionX, attackMeleePositions[shortestIndex]._pos.m_positionY, attackMeleePositions[shortestIndex]._pos.m_positionZ); | |
+ | |
+ // Add taken to the position to prevent overlapping of Mobs. | |
+ attackMeleePositions[shortestIndex]._taken = true; | |
+ | |
+ return closestPos; | |
+} | |
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h | |
index dfd1c1e020..b91232c3be 100644 | |
--- a/src/server/game/Entities/Unit/Unit.h | |
+++ b/src/server/game/Entities/Unit/Unit.h | |
@@ -702,6 +702,13 @@ struct TC_GAME_API CharmInfo | |
float _stayZ; | |
}; | |
+struct AttackPosition { | |
+ AttackPosition(Position pos) : _pos(pos), _taken(false) {} | |
+ | |
+ Position _pos; | |
+ bool _taken; | |
+}; | |
+ | |
// for clearing special attacks | |
#define REACTIVE_TIMER_START 4000 | |
@@ -789,6 +796,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 +813,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 | |
@@ -1756,6 +1768,10 @@ class TC_GAME_API Unit : public WorldObject | |
virtual void AtEnterCombat() { } | |
virtual void AtExitCombat(); | |
+ std::vector<AttackPosition> attackMeleePositions; | |
+ Position m_previousPosition; | |
+ uint8 m_previousAttackerCount; | |
+ | |
private: | |
void UpdateSplineMovement(uint32 t_diff); | |
@@ -1799,6 +1815,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 = 250; | |
+ 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..320561b3eb 100644 | |
--- a/src/server/game/Movement/MotionMaster.cpp | |
+++ b/src/server/game/Movement/MotionMaster.cpp | |
@@ -595,6 +595,27 @@ void MotionMaster::MoveChase(Unit* target, Optional<ChaseRange> dist, Optional<C | |
Add(new ChaseMovementGenerator(target, dist, angle)); | |
} | |
+void MotionMaster::MoveBackwards(Unit* target, float dist) | |
+{ | |
+ Position const& pos = target->GetPosition(); | |
+ //float angle = pos.GetAngle(_owner->GetPositionX(), _owner->GetPositionY()); | |
+ float angle = pos.GetOrientation(); | |
+ G3D::Vector3 point; | |
+ point.x = pos.m_positionX + dist * cosf(angle); | |
+ point.y = pos.m_positionY + dist * sinf(angle); | |
+ | |
+ if (_owner->IsFlying()) | |
+ point.z = pos.m_positionZ; | |
+ else | |
+ point.z = _owner->GetMapHeight(point.x, point.y, pos.m_positionZ); | |
+ | |
+ 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..4154726bdf 100644 | |
--- a/src/server/game/Movement/MotionMaster.h | |
+++ b/src/server/game/Movement/MotionMaster.h | |
@@ -142,6 +142,7 @@ 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 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..58ffdd7c86 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) | |
@@ -141,11 +141,24 @@ 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)) | |
{ | |
- _lastTargetPosition = target->GetPosition(); | |
- _mutualChase = mutualChase; | |
+ if (_pathCheckTimer > diff) | |
+ { | |
+ _pathCheckTimer -= diff; | |
+ return true; | |
+ } | |
+ else | |
+ { | |
+ _pathCheckTimer = PATH_CHECK_INTERVAL; | |
+ } | |
+ } | |
+ | |
+ // if the target moved, we have to consider whether to adjust | |
+ //if (_lastTargetPosition != target->GetPosition() || mutualChase != _mutualChase ) | |
+ //{ | |
+ //_lastTargetPosition = target->GetPosition(); | |
+ //_mutualChase = mutualChase; | |
if (owner->HasUnitState(UNIT_STATE_CHASE_MOVE) || !PositionOkay(owner, target, minRange, maxRange, angle)) | |
{ | |
Creature* const cOwner = owner->ToCreature(); | |
@@ -184,8 +197,36 @@ bool ChaseMovementGenerator::Update(Unit* owner, uint32 diff) | |
if (owner->IsHovering()) | |
owner->UpdateAllowedPositionZ(x, y, z); | |
+ // Fan Creatures around target if there are more than one. | |
+ Unit * target = GetTarget(); | |
+ Movement::MoveSplineInit init(owner); | |
+ int chaserCount = target->getAttackers().size(); | |
+ if (chaserCount > 1) | |
+ { | |
+ Position attackPos = target->GetMeleeAttackPoint(owner); | |
+ if (attackPos == NULL) // No free point to attack so abort. | |
+ return true; | |
+ else | |
+ { | |
+ x = attackPos.m_positionX; | |
+ y = attackPos.m_positionY; | |
+ z = attackPos.m_positionZ; | |
+ } | |
+ } | |
+ | |
bool success = _path->CalculatePath(x, y, z); | |
- if (!success || (_path->GetPathType() & PATHFIND_NOPATH)) | |
+ | |
+ // 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(true); | |
@@ -201,14 +242,12 @@ bool ChaseMovementGenerator::Update(Unit* owner, uint32 diff) | |
owner->AddUnitState(UNIT_STATE_CHASE_MOVE); | |
- Movement::MoveSplineInit init(owner); | |
- init.MovebyPath(_path->GetPath()); | |
- init.SetWalk(false); | |
- init.SetFacing(target); | |
- | |
- 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 | |
return true; | |
diff --git a/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h b/src/server/game/Movement/MovementGenerators/ChaseMovementGenerator.h | |
index 48d828b760..fdc9b49f10 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 = 200; // 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment