diff options
-rw-r--r-- | src/server/game/AI/CoreAI/PassiveAI.cpp | 30 | ||||
-rw-r--r-- | src/server/game/AI/CoreAI/PassiveAI.h | 9 | ||||
-rw-r--r-- | src/server/game/AI/CoreAI/UnitAI.h | 2 | ||||
-rw-r--r-- | src/server/game/AI/CreatureAI.cpp | 15 | ||||
-rw-r--r-- | src/server/game/AI/CreatureAI.h | 2 | ||||
-rw-r--r-- | src/server/game/AI/ScriptedAI/ScriptedCreature.cpp | 2 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartAI.cpp | 4 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScript.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/Creature.cpp | 41 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/Creature.h | 5 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/CreatureData.h | 4 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 8 | ||||
-rw-r--r-- | src/server/game/Movement/MotionMaster.h | 1 | ||||
-rw-r--r-- | src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp | 10 | ||||
-rw-r--r-- | src/server/scripts/Northrend/IcecrownCitadel/boss_lady_deathwhisper.cpp | 3 |
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); |