Skip to content

Instantly share code, notes, and snippets.

@Langerz82
Last active December 28, 2019 18:20
Show Gist options
  • Save Langerz82/2ba589313bff0880e9217a9a49238d8b to your computer and use it in GitHub Desktop.
Save Langerz82/2ba589313bff0880e9217a9a49238d8b to your computer and use it in GitHub Desktop.
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