fix(Core/Creature): Prevent combat movement disabled creatures from r… (#18428)

* fix(Core/Creature): Prevent combat movement disabled creatures from repositioning if target moves within model boundary

* fixbuild

* Apply suggestions from code review
This commit is contained in:
Andrew
2024-02-27 10:11:39 -03:00
committed by GitHub
parent b2e2cbfc13
commit 6df652a8dd
32 changed files with 71 additions and 74 deletions

View File

@@ -348,7 +348,7 @@ void CreatureAI::MoveCircleChecks()
!victim ||
!me->IsFreeToMove() || me->HasUnitMovementFlag(MOVEMENTFLAG_ROOT) ||
!me->IsWithinMeleeRange(victim) || me == victim->GetVictim() ||
(victim->GetTypeId() != TYPEID_PLAYER && !victim->IsPet()) // only player & pets to save CPU
(!victim->IsPlayer() && !victim->IsPet()) // only player & pets to save CPU
)
{
return;
@@ -357,14 +357,12 @@ void CreatureAI::MoveCircleChecks()
me->GetMotionMaster()->MoveCircleTarget(me->GetVictim());
}
void CreatureAI::MoveBackwardsChecks() {
void CreatureAI::MoveBackwardsChecks()
{
Unit *victim = me->GetVictim();
if (
!victim ||
!me->IsFreeToMove() || me->HasUnitMovementFlag(MOVEMENTFLAG_ROOT) ||
(victim->GetTypeId() != TYPEID_PLAYER && !victim->IsPet())
)
if (!victim || !me->IsFreeToMove() || me->HasUnitMovementFlag(MOVEMENTFLAG_ROOT) ||
(!victim->IsPlayer() && !victim->IsPet()))
{
return;
}

View File

@@ -191,8 +191,7 @@ bool SummonList::IsAnyCreatureInCombat() const
ScriptedAI::ScriptedAI(Creature* creature) : CreatureAI(creature),
me(creature),
IsFleeing(false),
_isCombatMovementAllowed(true)
IsFleeing(false)
{
_isHeroic = me->GetMap()->IsHeroic();
_difficulty = Difficulty(me->GetMap()->GetSpawnMode());
@@ -209,7 +208,7 @@ void ScriptedAI::AttackStartNoMove(Unit* who)
void ScriptedAI::AttackStart(Unit* who)
{
if (IsCombatMovementAllowed())
if (me->IsCombatMovementAllowed())
CreatureAI::AttackStart(who);
else
AttackStartNoMove(who);
@@ -537,11 +536,6 @@ void ScriptedAI::SetEquipmentSlots(bool loadDefault, int32 mainHand /*= EQUIP_NO
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, uint32(ranged));
}
void ScriptedAI::SetCombatMovement(bool allowMovement)
{
_isCombatMovementAllowed = allowMovement;
}
enum eNPCs
{
NPC_BROODLORD = 12017,

View File

@@ -373,14 +373,6 @@ struct ScriptedAI : public CreatureAI
void SetEquipmentSlots(bool loadDefault, int32 mainHand = EQUIP_NO_CHANGE, int32 offHand = EQUIP_NO_CHANGE, int32 ranged = EQUIP_NO_CHANGE);
// Used to control if MoveChase() is to be used or not in AttackStart(). Some creatures does not chase victims
// NOTE: If you use SetCombatMovement while the creature is in combat, it will do NOTHING - This only affects AttackStart
// You should make the necessary to make it happen so.
// Remember that if you modified _isCombatMovementAllowed (e.g: using SetCombatMovement) it will not be reset at Reset().
// It will keep the last value you set.
void SetCombatMovement(bool allowMovement);
bool IsCombatMovementAllowed() const { return _isCombatMovementAllowed; }
virtual bool CheckEvadeIfOutOfCombatArea() const { return false; }
// return true for heroic mode. i.e.
@@ -452,7 +444,6 @@ struct ScriptedAI : public CreatureAI
private:
Difficulty _difficulty;
bool _isCombatMovementAllowed;
bool _isHeroic;
std::unordered_set<uint32> _uniqueTimedEvents;
};

View File

@@ -64,7 +64,7 @@ void npc_escortAI::AttackStart(Unit* who)
me->StopMoving();
}
if (IsCombatMovementAllowed())
if (me->IsCombatMovementAllowed())
me->GetMotionMaster()->MoveChase(who);
}
}
@@ -178,8 +178,8 @@ void npc_escortAI::JustRespawned()
{
RemoveEscortState(STATE_ESCORT_ESCORTING | STATE_ESCORT_RETURNING | STATE_ESCORT_PAUSED);
if (!IsCombatMovementAllowed())
SetCombatMovement(true);
if (!me->IsCombatMovementAllowed())
me->SetCombatMovement(true);
//add a small delay before going to first waypoint, normal in near all cases
m_uiWPWaitTimer = 1000;

View File

@@ -55,7 +55,7 @@ void FollowerAI::AttackStart(Unit* who)
if (me->HasUnitState(UNIT_STATE_FOLLOW))
me->ClearUnitState(UNIT_STATE_FOLLOW);
if (IsCombatMovementAllowed())
if (me->IsCombatMovementAllowed())
me->GetMotionMaster()->MoveChase(who);
}
}
@@ -141,8 +141,8 @@ void FollowerAI::JustRespawned()
{
m_uiFollowState = STATE_FOLLOW_NONE;
if (!IsCombatMovementAllowed())
SetCombatMovement(true);
if (!me->IsCombatMovementAllowed())
me->SetCombatMovement(true);
if (me->GetFaction() != me->GetCreatureTemplate()->faction)
me->SetFaction(me->GetCreatureTemplate()->faction);

View File

@@ -220,7 +220,7 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MovableMapObject(),
m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_regenPower(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false),
m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), _lastDamagedTime(nullptr), m_cannotReachTimer(0),
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false)
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false), _isCombatMovementAllowed(true)
{
m_regenTimer = CREATURE_REGEN_INTERVAL;
m_valuesCount = UNIT_END;
@@ -877,7 +877,7 @@ bool Creature::IsFreeToMove()
{
uint32 moveFlags = m_movementInfo.GetMovementFlags();
// Do not reposition ourself when we are not allowed to move
if ((IsMovementPreventedByCasting() || isMoving() || !CanFreeMove()) &&
if ((IsMovementPreventedByCasting() || isMoving() || !CanFreeMove() || !IsCombatMovementAllowed()) &&
(GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE ||
moveFlags & MOVEMENTFLAG_SPLINE_ENABLED))
{
@@ -3738,6 +3738,11 @@ bool Creature::CanCastSpell(uint32 spellID) const
return true;
}
void Creature::SetCombatMovement(bool allowMovement)
{
_isCombatMovementAllowed = allowMovement;
}
ObjectGuid Creature::GetSummonerGUID() const
{
if (TempSummon const* temp = ToTempSummon())

View File

@@ -413,6 +413,14 @@ public:
* */
[[nodiscard]] ObjectGuid GetSummonerGUID() const;
// Used to control if MoveChase() is to be used or not in AttackStart(). Some creatures does not chase victims
// NOTE: If you use SetCombatMovement while the creature is in combat, it will do NOTHING - This only affects AttackStart
// You should make the necessary to make it happen so.
// Remember that if you modified _isCombatMovementAllowed (e.g: using SetCombatMovement) it will not be reset at Reset().
// It will keep the last value you set.
void SetCombatMovement(bool allowMovement);
bool IsCombatMovementAllowed() const { return _isCombatMovementAllowed; }
std::string GetDebugInfo() const override;
protected:
@@ -501,6 +509,7 @@ private:
uint32 _playerDamageReq;
bool _damagedByPlayer;
bool _isCombatMovementAllowed;
};
class AssistDelayEvent : public BasicEvent

View File

@@ -45,7 +45,7 @@ struct boss_quartermaster_zigris : public BossAI
void Reset() override
{
_Reset();
SetCombatMovement(false);
me->SetCombatMovement(false);
_hasDrunkPotion = false;
}
@@ -120,11 +120,11 @@ struct boss_quartermaster_zigris : public BossAI
{
DoCastVictim(SPELL_SHOOT);
me->GetMotionMaster()->Clear();
SetCombatMovement(false);
me->SetCombatMovement(false);
}
else if (!me->IsWithinLOSInMap(me->GetVictim()))
{
SetCombatMovement(true);
me->SetCombatMovement(true);
me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveChase(me->GetVictim());
}

View File

@@ -359,7 +359,7 @@ public:
Talk(SAY_GAMESBEGIN_2);
DoCast(me, SPELL_NEFARIANS_BARRIER);
SetCombatMovement(false);
me->SetCombatMovement(false);
me->SetImmuneToPC(false);
AttackStart(SelectTarget(SelectTargetMethod::Random, 0, 200.f, true));
events.ScheduleEvent(EVENT_SHADOWBLINK, 500ms);

View File

@@ -159,7 +159,7 @@ struct boss_dorothee : public ScriptedAI
{
boss_dorothee(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
//this is kinda a big no-no. but it will prevent her from moving to chase targets. she should just cast her spells. in this case, since there is not really something to LOS her with or get out of range this would work. but a more elegant solution would be better
instance = creature->GetInstanceScript();

View File

@@ -123,7 +123,7 @@ struct boss_jeklik : public BossAI
me->SetDisableGravity(false);
me->SetReactState(REACT_PASSIVE);
BossAI::SetCombatMovement(false);
BossAI::me->SetCombatMovement(false);
batRidersCount = 0;
DoCastSelf(SPELL_GREEN_CHANNELING, true);
@@ -148,7 +148,7 @@ struct boss_jeklik : public BossAI
BossAI::PathEndReached(pathId);
me->SetDisableGravity(false);
SetCombatMovement(true);
me->SetCombatMovement(true);
me->SetReactState(REACT_AGGRESSIVE);
//

View File

@@ -2168,7 +2168,7 @@ public:
{
boss_blight_wormAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
void Reset() override

View File

@@ -134,7 +134,7 @@ public:
{
npc_andorhal_towerAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
void MoveInLineOfSight(Unit* who) override

View File

@@ -1411,7 +1411,7 @@ public:
{
alliance_riflemanAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
uint32 ExplodeTimer;

View File

@@ -84,7 +84,7 @@ struct boss_ayamiss : public BossAI
void Reset() override
{
BossAI::Reset();
SetCombatMovement(false);
me->SetCombatMovement(false);
me->SetReactState(REACT_AGGRESSIVE);
ScheduleHealthCheckEvent(70, [&] {
@@ -127,7 +127,7 @@ struct boss_ayamiss : public BossAI
}
else if (type == WAYPOINT_MOTION_TYPE && id == POINT_GROUND)
{
SetCombatMovement(true);
me->SetCombatMovement(true);
me->SetDisableGravity(false);
me->m_Events.AddEventAtOffset([this]()

View File

@@ -188,7 +188,7 @@ struct npc_buru_egg : public ScriptedAI
npc_buru_egg(Creature* creature) : ScriptedAI(creature)
{
_instance = me->GetInstanceScript();
SetCombatMovement(false);
me->SetCombatMovement(false);
me->SetReactState(REACT_PASSIVE);
me->SetControlled(true, UNIT_STATE_STUNNED);
}

View File

@@ -147,7 +147,7 @@ struct boss_eye_of_cthun : public BossAI
{
boss_eye_of_cthun(Creature* creature) : BossAI(creature, DATA_CTHUN)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
me->m_SightDistance = 90.f;
}
@@ -377,7 +377,7 @@ struct boss_cthun : public BossAI
{
boss_cthun(Creature* creature) : BossAI(creature, DATA_CTHUN)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
void Reset() override
@@ -597,7 +597,7 @@ struct npc_eye_tentacle : public ScriptedAI
}
}
SetCombatMovement(false);
me->SetCombatMovement(false);
}
void JustDied(Unit* /*killer*/) override
@@ -651,7 +651,7 @@ struct npc_claw_tentacle : public ScriptedAI
{
npc_claw_tentacle(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
if (Creature* portal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{
@@ -720,7 +720,7 @@ struct npc_giant_claw_tentacle : public ScriptedAI
{
npc_giant_claw_tentacle(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{
@@ -870,7 +870,7 @@ struct npc_giant_eye_tentacle : public ScriptedAI
{
npc_giant_eye_tentacle(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{

View File

@@ -106,7 +106,7 @@ struct boss_ouro : public BossAI
{
boss_ouro(Creature* creature) : BossAI(creature, DATA_OURO)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
me->SetControlled(true, UNIT_STATE_ROOT);
}

View File

@@ -366,7 +366,7 @@ struct npc_toxic_slime : public ScriptedAI
void InitializeAI() override
{
SetCombatMovement(false);
me->SetCombatMovement(false);
DoCastSelf(SPELL_TOXIN);
InstanceScript* instance = me->GetInstanceScript();

View File

@@ -99,7 +99,7 @@ public:
{
npc_tiger_matriarch_creditAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
events.ScheduleEvent(EVENT_CHECK_SUMMON_AURA, 2s);
}

View File

@@ -235,7 +235,7 @@ struct npc_amanitar_mushrooms : public ScriptedAI
{
npc_amanitar_mushrooms(Creature* pCreature) : ScriptedAI(pCreature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
//TODO: this prolly needs to be done in database
pCreature->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);

View File

@@ -295,7 +295,7 @@ struct boss_jedoga_shadowseeker : public BossAI
{
if (!ritualTriggered && me->HealthBelowPctDamaged(55, damage) && events.IsInPhase(PHASE_NORMAL))
{
SetCombatMovement(false);
me->SetCombatMovement(false);
me->InterruptNonMeleeSpells(false);
me->AttackStop();
me->SetReactState(REACT_PASSIVE);
@@ -368,7 +368,7 @@ struct boss_jedoga_shadowseeker : public BossAI
me->RemoveAurasDueToSpell(SPELL_SPHERE_VISUAL);
me->RemoveAurasDueToSpell(SPELL_LIGHTNING_BOLTS);
me->RemoveAurasDueToSpell(SPELL_HOVER_FALL);
SetCombatMovement(true);
me->SetCombatMovement(true);
me->SetDisableGravity(false);
me->SetHover(false);

View File

@@ -606,14 +606,14 @@ struct boss_jormungarAI : public ScriptedAI
if( bIsStationary )
{
me->SetNativeDisplayId(_MODEL_MOBILE);
SetCombatMovement(true);
me->SetCombatMovement(true);
if( Unit* victim = me->GetVictim() )
me->GetMotionMaster()->MoveChase(victim);
}
else
{
me->SetNativeDisplayId(_MODEL_STATIONARY);
SetCombatMovement(false);
me->SetCombatMovement(false);
}
me->RemoveAurasDueToSpell(SPELL_SUBMERGE_0);
me->CastSpell(me, SPELL_EMERGE_0, false);
@@ -692,7 +692,7 @@ public:
_MODEL_STATIONARY = MODEL_ACIDMAW_STATIONARY;
_MODEL_MOBILE = MODEL_ACIDMAW_MOBILE;
_TYPE_OTHER = TYPE_DREADSCALE;
SetCombatMovement(false);
me->SetCombatMovement(false);
}
};

View File

@@ -1525,7 +1525,7 @@ public:
{
boss_yoggsaron_crusher_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
me->CastSpell(me, SPELL_CRUSH, true);
me->CastSpell(me, SPELL_FOCUSED_ANGER, true);
me->CastSpell(me, SPELL_DIMINISH_POWER, false);
@@ -1587,7 +1587,7 @@ public:
{
boss_yoggsaron_corruptor_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
void DoAction(int32 param) override
@@ -1644,7 +1644,7 @@ public:
{
boss_yoggsaron_constrictor_tentacleAI(Creature* pCreature) : ScriptedAI(pCreature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
_checkTimer = 1;
_playerGUID.Clear();
}

View File

@@ -1049,7 +1049,7 @@ public:
{
npc_warmage_coldarraAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
uint32 m_uiTimer; //Timer until recast

View File

@@ -147,7 +147,7 @@ struct npc_warmage_violetstand : public ScriptedAI
{
npc_warmage_violetstand(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
ObjectGuid targetGUID;

View File

@@ -1532,7 +1532,7 @@ public:
{
npc_guardian_pavilionAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
void MoveInLineOfSight(Unit* who) override
@@ -1596,7 +1596,7 @@ public:
{
npc_tournament_training_dummyAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);
}
@@ -1816,7 +1816,7 @@ public:
PhaseCount = 0;
Summons.DespawnAll();
SetCombatMovement(false);
me->SetCombatMovement(false);
}
EventMap events;

View File

@@ -57,7 +57,7 @@ struct boss_murmur : public BossAI
{
boss_murmur(Creature* creature) : BossAI(creature, DATA_MURMUR)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);

View File

@@ -98,7 +98,7 @@ struct boss_ahune : public ScriptedAI
{
boss_ahune(Creature* c) : ScriptedAI(c), summons(me)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
SetEquipmentSlots(false, 54806, EQUIP_UNEQUIP, EQUIP_UNEQUIP);
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
InvokerGUID.Clear();

View File

@@ -41,7 +41,7 @@ struct boss_omor_the_unscarred : public BossAI
{
boss_omor_the_unscarred(Creature* creature) : BossAI(creature, DATA_OMOR_THE_UNSCARRED)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);

View File

@@ -90,7 +90,7 @@ struct boss_alar : public BossAI
boss_alar(Creature* creature) : BossAI(creature, DATA_ALAR)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
}
void JustReachedHome() override

View File

@@ -334,7 +334,7 @@ public:
{
npc_training_dummyAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); //imune to knock aways like blast wave
}
@@ -392,7 +392,7 @@ public:
{
npc_target_dummyAI(Creature* creature) : ScriptedAI(creature)
{
SetCombatMovement(false);
me->SetCombatMovement(false);
deathTimer = 15000;
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true); //imune to knock aways like blast wave
}