aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/server/game/AI/CoreAI/PassiveAI.cpp30
-rw-r--r--src/server/game/AI/CoreAI/PassiveAI.h9
-rw-r--r--src/server/game/AI/CoreAI/UnitAI.h2
-rw-r--r--src/server/game/AI/CreatureAI.cpp15
-rw-r--r--src/server/game/AI/CreatureAI.h2
-rw-r--r--src/server/game/AI/ScriptedAI/ScriptedCreature.cpp2
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp4
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp2
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp41
-rw-r--r--src/server/game/Entities/Creature/Creature.h5
-rw-r--r--src/server/game/Entities/Creature/CreatureData.h4
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp8
-rw-r--r--src/server/game/Movement/MotionMaster.h1
-rw-r--r--src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp10
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp3
15 files changed, 101 insertions, 37 deletions
diff --git a/src/server/game/AI/CoreAI/PassiveAI.cpp b/src/server/game/AI/CoreAI/PassiveAI.cpp
index 82904e5f52f..196e23a1ea9 100644
--- a/src/server/game/AI/CoreAI/PassiveAI.cpp
+++ b/src/server/game/AI/CoreAI/PassiveAI.cpp
@@ -17,7 +17,7 @@
#include "PassiveAI.h"
#include "Creature.h"
-#include "MovementDefines.h"
+#include "World.h"
PassiveAI::PassiveAI(Creature* c, uint32 scriptId) : CreatureAI(c, scriptId)
{
@@ -73,23 +73,31 @@ void PossessedAI::JustDied(Unit* /*u*/)
me->RemoveDynamicFlag(UNIT_DYNFLAG_LOOTABLE);
}
-void CritterAI::JustEngagedWith(Unit* /*who*/)
+CritterAI::CritterAI(Creature* creature, uint32 scriptId) : PassiveAI(creature, scriptId)
{
- if (!me->HasUnitState(UNIT_STATE_FLEEING))
- me->SetControlled(true, UNIT_STATE_FLEEING);
+ me->SetCanMelee(false, true);
}
-void CritterAI::MovementInform(uint32 type, uint32 /*id*/)
+void CritterAI::JustEngagedWith(Unit* who)
{
- if (type == TIMED_FLEEING_MOTION_TYPE)
- EnterEvadeMode(EvadeReason::Other);
+ me->StartDefaultCombatMovement(who);
+ _evadeTimer.Reset(Milliseconds(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY)));
}
-void CritterAI::EnterEvadeMode(EvadeReason why)
+void CritterAI::UpdateAI(uint32 diff)
{
- if (me->HasUnitState(UNIT_STATE_FLEEING))
- me->SetControlled(false, UNIT_STATE_FLEEING);
- CreatureAI::EnterEvadeMode(why);
+ if (me->IsEngaged())
+ {
+ if (!me->IsInCombat())
+ {
+ EnterEvadeMode(EvadeReason::NoHostiles);
+ return;
+ }
+
+ _evadeTimer.Update(diff);
+ if (_evadeTimer.Passed())
+ EnterEvadeMode(EvadeReason::Other);
+ }
}
int32 CritterAI::Permissible(Creature const* creature)
diff --git a/src/server/game/AI/CoreAI/PassiveAI.h b/src/server/game/AI/CoreAI/PassiveAI.h
index cc4c3ce14c8..2e751ad0d38 100644
--- a/src/server/game/AI/CoreAI/PassiveAI.h
+++ b/src/server/game/AI/CoreAI/PassiveAI.h
@@ -19,6 +19,7 @@
#define TRINITY_PASSIVEAI_H
#include "CreatureAI.h"
+#include "Timer.h"
class TC_GAME_API PassiveAI : public CreatureAI
{
@@ -70,14 +71,16 @@ class TC_GAME_API NullCreatureAI : public CreatureAI
class TC_GAME_API CritterAI : public PassiveAI
{
public:
- using PassiveAI::PassiveAI;
+ explicit CritterAI(Creature* creature, uint32 scriptId = {});
void JustEngagedWith(Unit* /*who*/) override;
- void EnterEvadeMode(EvadeReason why) override;
- void MovementInform(uint32 type, uint32 id) override;
+ void UpdateAI(uint32 diff) override;
static int32 Permissible(Creature const* creature);
+
+ private:
+ TimeTracker _evadeTimer;
};
class TC_GAME_API TriggerAI : public NullCreatureAI
diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h
index 1ae52ff00a7..b5cda811617 100644
--- a/src/server/game/AI/CoreAI/UnitAI.h
+++ b/src/server/game/AI/CoreAI/UnitAI.h
@@ -55,7 +55,7 @@ class TC_GAME_API UnitAI
virtual ~UnitAI() { }
virtual bool CanAIAttack(Unit const* /*target*/) const { return true; }
- virtual void AttackStart(Unit* /*target*/);
+ virtual void AttackStart(Unit* victim);
virtual void UpdateAI(uint32 diff) = 0;
virtual void InitializeAI();
diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp
index c63e3c21ee1..1c33aec2a69 100644
--- a/src/server/game/AI/CreatureAI.cpp
+++ b/src/server/game/AI/CreatureAI.cpp
@@ -324,6 +324,21 @@ bool CreatureAI::_EnterEvadeMode(EvadeReason /*why*/)
return true;
}
+void CreatureAI::AttackStart(Unit* victim)
+{
+ if (victim && me->Attack(victim, true))
+ {
+ // Clear distracted state on attacking
+ if (me->HasUnitState(UNIT_STATE_DISTRACTED))
+ {
+ me->ClearUnitState(UNIT_STATE_DISTRACTED);
+ me->GetMotionMaster()->Clear();
+ }
+
+ me->StartDefaultCombatMovement(victim);
+ }
+}
+
Optional<QuestGiverStatus> CreatureAI::GetDialogStatus(Player const* /*player*/)
{
return {};
diff --git a/src/server/game/AI/CreatureAI.h b/src/server/game/AI/CreatureAI.h
index 61fe33d567e..c732da187d1 100644
--- a/src/server/game/AI/CreatureAI.h
+++ b/src/server/game/AI/CreatureAI.h
@@ -173,7 +173,7 @@ class TC_GAME_API CreatureAI : public UnitAI
/// == Triggered Actions Requested ==================
// Called when creature attack expected (if creature can and no have current victim)
- //virtual void AttackStart(Unit*) { }
+ void AttackStart(Unit* victim) override;
// Called at World update tick
//virtual void UpdateAI(const uint32 /*diff*/) { }
diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
index 82c8dac896f..576346aa47d 100644
--- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
+++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp
@@ -155,7 +155,7 @@ void ScriptedAI::UpdateAI(uint32 /*diff*/)
void ScriptedAI::DoStartMovement(Unit* victim, float distance, float angle)
{
if (victim)
- me->GetMotionMaster()->MoveChase(victim, distance, angle);
+ me->StartDefaultCombatMovement(victim, distance, angle);
}
void ScriptedAI::DoStartNoMovement(Unit* victim)
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index 9177443d57f..6885a1a66cc 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -586,7 +586,7 @@ void SmartAI::AttackStart(Unit* who)
if (_canCombatMove)
{
SetRun(_run);
- me->GetMotionMaster()->MoveChase(who);
+ me->StartDefaultCombatMovement(who);
}
}
}
@@ -793,7 +793,7 @@ void SmartAI::SetCombatMove(bool on, bool stopMoving)
}))
{
SetRun(_run);
- me->GetMotionMaster()->MoveChase(me->GetVictim());
+ me->StartDefaultCombatMovement(me->GetVictim());
}
}
else if (MovementGenerator* movement = me->GetMotionMaster()->GetMovementGenerator([](MovementGenerator const* a) -> bool
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index a7745d62f80..310539599ab 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -1609,7 +1609,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (Creature* creature = target->ToCreature())
if (IsSmart(creature) && creature->GetVictim())
if (ENSURE_AI(SmartAI, creature->AI())->CanCombatMove())
- creature->GetMotionMaster()->MoveChase(creature->GetVictim(), attackDistance, attackAngle);
+ creature->StartDefaultCombatMovement(creature->GetVictim(), attackDistance, attackAngle);
}
break;
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index c11fad802bd..4336680ce1f 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -2834,6 +2834,47 @@ void Creature::SendZoneUnderAttackMessage(Player* attacker)
sWorld->SendGlobalMessage(packet.Write(), nullptr, (enemy_team == ALLIANCE ? HORDE : ALLIANCE));
}
+void Creature::SetCanMelee(bool canMelee, bool fleeFromMelee /*= false*/)
+{
+ bool wasFleeingFromMelee = HasFlag(CREATURE_STATIC_FLAG_NO_MELEE_FLEE);
+
+ _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_NO_MELEE_FLEE, !canMelee && fleeFromMelee);
+ _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_4_NO_MELEE_APPROACH, !canMelee && !fleeFromMelee);
+
+ if (wasFleeingFromMelee == HasFlag(CREATURE_STATIC_FLAG_NO_MELEE_FLEE))
+ return;
+
+ Unit* victim = GetVictim();
+ if (!victim)
+ return;
+
+ MovementGenerator* currentMovement = GetMotionMaster()->GetCurrentMovementGenerator();
+ if (!currentMovement)
+ return;
+
+ bool canChangeMovement = [&]
+ {
+ if (wasFleeingFromMelee)
+ return currentMovement->GetMovementGeneratorType() == FLEEING_MOTION_TYPE && !HasUnitFlag(UNIT_FLAG_FLEEING);
+
+ return currentMovement->GetMovementGeneratorType() == CHASE_MOTION_TYPE;
+ }();
+
+ if (!canChangeMovement)
+ return;
+
+ GetMotionMaster()->Remove(currentMovement);
+ StartDefaultCombatMovement(victim);
+}
+
+void Creature::StartDefaultCombatMovement(Unit* victim, Optional<float> range /*= {}*/, Optional<float> angle /*= {}*/)
+{
+ if (!HasFlag(CREATURE_STATIC_FLAG_NO_MELEE_FLEE) || IsSummon())
+ GetMotionMaster()->MoveChase(victim, range, angle);
+ else
+ GetMotionMaster()->MoveFleeing(victim);
+}
+
bool Creature::HasSpell(uint32 spellID) const
{
return std::find(std::begin(m_spells), std::end(m_spells), spellID) != std::end(m_spells);
diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h
index dfdc30681f5..1e3735ad6b2 100644
--- a/src/server/game/Entities/Creature/Creature.h
+++ b/src/server/game/Entities/Creature/Creature.h
@@ -188,9 +188,10 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType /*attackType*/ = BASE_ATTACK) const override { return m_meleeDamageSchoolMask; }
void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); }
- bool CanMelee() const { return !_staticFlags.HasFlag(CREATURE_STATIC_FLAG_NO_MELEE); }
- void SetCanMelee(bool canMelee) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_NO_MELEE, !canMelee); }
+ bool CanMelee() const { return !_staticFlags.HasFlag(CREATURE_STATIC_FLAG_NO_MELEE_FLEE) && !_staticFlags.HasFlag(CREATURE_STATIC_FLAG_4_NO_MELEE_APPROACH); }
+ void SetCanMelee(bool canMelee, bool fleeFromMelee = false);
bool CanIgnoreLineOfSightWhenCastingOnMe() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_4_IGNORE_LOS_WHEN_CASTING_ON_ME); }
+ void StartDefaultCombatMovement(Unit* victim, Optional<float> range = {}, Optional<float> angle = {});
bool HasSpell(uint32 spellID) const override;
diff --git a/src/server/game/Entities/Creature/CreatureData.h b/src/server/game/Entities/Creature/CreatureData.h
index b0ea6ef0082..8a3d8655069 100644
--- a/src/server/game/Entities/Creature/CreatureData.h
+++ b/src/server/game/Entities/Creature/CreatureData.h
@@ -55,7 +55,7 @@ enum CreatureStaticFlags
CREATURE_STATIC_FLAG_COMBAT_PING = 0x00020000,
CREATURE_STATIC_FLAG_AQUATIC = 0x00040000, // aka Water Only, creature_template_movement.Ground = 0
CREATURE_STATIC_FLAG_AMPHIBIOUS = 0x00080000, // creature_template_movement.Swim = 1
- CREATURE_STATIC_FLAG_NO_MELEE = 0x00100000, // "No Melee (Flee)" Prevents melee(does not prevent chasing, does not make creature passive). Not sure what 'Flee' means but another flag is named NO_MELEE_APPROACH
+ CREATURE_STATIC_FLAG_NO_MELEE_FLEE = 0x00100000, // "No Melee (Flee)" Prevents melee (moves as-if feared, does not make creature passive)
CREATURE_STATIC_FLAG_VISIBLE_TO_GHOSTS = 0x00200000, // CREATURE_TYPE_FLAG_VISIBLE_TO_GHOSTS
CREATURE_STATIC_FLAG_PVP_ENABLING = 0x00400000, // Old UNIT_FLAG_PVP_ENABLING, now UNIT_BYTES_2_OFFSET_PVP_FLAG from UNIT_FIELD_BYTES_2
CREATURE_STATIC_FLAG_DO_NOT_PLAY_WOUND_ANIM = 0x00800000, // CREATURE_TYPE_FLAG_DO_NOT_PLAY_WOUND_ANIM
@@ -158,7 +158,7 @@ enum CreatureStaticFlags4
CREATURE_STATIC_FLAG_4_DEALS_TRIPLE_DAMAGE_TO_PC_CONTROLLED_PETS = 0x00000040,
CREATURE_STATIC_FLAG_4_NO_NPC_DAMAGE_BELOW_85PTC = 0x00000080,
CREATURE_STATIC_FLAG_4_OBEYS_TAUNT_DIMINISHING_RETURNS = 0x00000100, // CREATURE_FLAG_EXTRA_OBEYS_TAUNT_DIMINISHING_RETURNS
- CREATURE_STATIC_FLAG_4_NO_MELEE_APPROACH = 0x00000200,
+ CREATURE_STATIC_FLAG_4_NO_MELEE_APPROACH = 0x00000200, // "No Melee (Approach)" Prevents melee (chases into melee range, does not make creature passive)
CREATURE_STATIC_FLAG_4_UPDATE_CREATURE_RECORD_WHEN_INSTANCE_CHANGES_DIFFICULTY = 0x00000400, // Used only by Snobold Vassal
CREATURE_STATIC_FLAG_4_CANNOT_DAZE = 0x00000800, // "Cannot Daze (Combat Stun)"
CREATURE_STATIC_FLAG_4_FLAT_HONOR_AWARD = 0x00001000,
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 468e8e8bb3e..c19f5f1c05c 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -11005,20 +11005,22 @@ void Unit::SetFeared(bool apply)
SetTarget(ObjectGuid::Empty);
Unit* caster = nullptr;
- Unit::AuraEffectList const& fearAuras = GetAuraEffectsByType(SPELL_AURA_MOD_FEAR);
+ AuraEffectList const& fearAuras = GetAuraEffectsByType(SPELL_AURA_MOD_FEAR);
if (!fearAuras.empty())
caster = ObjectAccessor::GetUnit(*this, fearAuras.front()->GetCasterGUID());
if (!caster)
caster = getAttackerForHelper();
GetMotionMaster()->MoveFleeing(caster, fearAuras.empty() ? Milliseconds(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_FLEE_DELAY)) : 0ms); // caster == NULL processed in MoveFleeing
+ SetUnitFlag(UNIT_FLAG_FLEEING);
}
else
{
+ RemoveUnitFlag(UNIT_FLAG_FLEEING);
if (IsAlive())
{
GetMotionMaster()->Remove(FLEEING_MOTION_TYPE);
- if (GetVictim())
- SetTarget(EnsureVictim()->GetGUID());
+ if (Unit const* victim = GetVictim())
+ SetTarget(victim->GetGUID());
if (!IsPlayer() && !IsInCombat())
GetMotionMaster()->MoveTargetedHome();
}
diff --git a/src/server/game/Movement/MotionMaster.h b/src/server/game/Movement/MotionMaster.h
index 9ecabd77b76..dd9c322b706 100644
--- a/src/server/game/Movement/MotionMaster.h
+++ b/src/server/game/Movement/MotionMaster.h
@@ -160,7 +160,6 @@ class TC_GAME_API MotionMaster
void MoveFollow(Unit* target, float dist, ChaseAngle angle, Optional<Milliseconds> duration = {}, MovementSlot slot = MOTION_SLOT_ACTIVE);
void MoveChase(Unit* target, Optional<ChaseRange> dist = {}, Optional<ChaseAngle> angle = {});
void MoveChase(Unit* target, float dist, float angle) { MoveChase(target, ChaseRange(dist), ChaseAngle(angle)); }
- void MoveChase(Unit* target, float dist) { MoveChase(target, ChaseRange(dist)); }
void MoveConfused();
void MoveFleeing(Unit* enemy, Milliseconds time = 0ms);
void MovePoint(uint32 id, Position const& pos, bool generatePath = true, Optional<float> finalOrient = {}, Optional<float> speed = {},
diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
index c8916f45c1f..ea74fbbc895 100644
--- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
@@ -54,9 +54,6 @@ void FleeingMovementGenerator<T>::DoInitialize(T* owner)
if (!owner || !owner->IsAlive())
return;
- // TODO: UNIT_FIELD_FLAGS should not be handled by generators
- owner->SetUnitFlag(UNIT_FLAG_FLEEING);
-
_path = nullptr;
SetTargetLocation(owner);
}
@@ -114,7 +111,6 @@ void FleeingMovementGenerator<Player>::DoFinalize(Player* owner, bool active, bo
if (active)
{
- owner->RemoveUnitFlag(UNIT_FLAG_FLEEING);
owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE);
owner->StopMoving();
}
@@ -127,10 +123,9 @@ void FleeingMovementGenerator<Creature>::DoFinalize(Creature* owner, bool active
if (active)
{
- owner->RemoveUnitFlag(UNIT_FLAG_FLEEING);
owner->ClearUnitState(UNIT_STATE_FLEEING_MOVE);
- if (owner->GetVictim())
- owner->SetTarget(owner->EnsureVictim()->GetGUID());
+ if (Unit const* victim = owner->GetVictim())
+ owner->SetTarget(victim->GetGUID());
}
}
@@ -257,7 +252,6 @@ void TimedFleeingMovementGenerator::Finalize(Unit* owner, bool active, bool move
if (!active)
return;
- owner->RemoveUnitFlag(UNIT_FLAG_FLEEING);
owner->StopMoving();
if (Unit* victim = owner->GetVictim())
{
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
index 4337cc59996..9bbdc9149ac 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp
@@ -263,7 +263,7 @@ struct boss_lady_deathwhisper : public BossAI
break;
case 5:
Talk(SAY_INTRO_7);
- return;
+ break;
default:
break;
}
@@ -336,6 +336,7 @@ struct boss_lady_deathwhisper : public BossAI
});
Talk(SAY_AGGRO);
+ me->SetCanMelee(false);
DoStartNoMovement(who);
me->RemoveAurasDueToSpell(SPELL_SHADOW_CHANNELING);
DoCastSelf(SPELL_MANA_BARRIER, true);