fix(Core/SAI): SMARTCAST_COMBAT_MOVE prevents movement on successful cast (#23913)

This commit is contained in:
blinkysc
2025-12-02 09:44:23 -06:00
committed by GitHub
parent be37b5e395
commit bb7753d363
5 changed files with 61 additions and 18 deletions

View File

@@ -858,7 +858,7 @@ void SmartAI::AttackStart(Unit* who)
return;
}
if (who && me->Attack(who, me->IsWithinMeleeRange(who)))
if (who && me->Attack(who, me->IsWithinMeleeRange(who) || _currentRangeMode))
{
if (!me->HasUnitState(UNIT_STATE_NO_COMBAT_MOVEMENT))
{
@@ -870,7 +870,7 @@ void SmartAI::AttackStart(Unit* who)
me->GetMotionMaster()->Clear(false);
}
me->GetMotionMaster()->MoveChase(who);
me->GetMotionMaster()->MoveChase(who, _attackDistance);
}
}
}
@@ -941,6 +941,35 @@ void SmartAI::PassengerBoarded(Unit* who, int8 seatId, bool apply)
void SmartAI::InitializeAI()
{
GetScript()->OnInitialize(me);
for (SmartScriptHolder const& event : GetScript()->GetEvents())
{
if (event.GetActionType() != SMART_ACTION_CAST)
continue;
if (!(event.action.cast.castFlags & SMARTCAST_MAIN_SPELL))
continue;
SetMainSpell(event.action.cast.spell);
break;
}
// Fallback: use first SMARTCAST_COMBAT_MOVE if no MAIN_SPELL found
if (!_currentRangeMode)
{
for (SmartScriptHolder const& event : GetScript()->GetEvents())
{
if (event.GetActionType() != SMART_ACTION_CAST)
continue;
if (!(event.action.cast.castFlags & SMARTCAST_COMBAT_MOVE))
continue;
SetMainSpell(event.action.cast.spell);
break;
}
}
if (!me->isDead())
{
mJustReset = true;
@@ -1083,6 +1112,20 @@ void SmartAI::SetCurrentRangeMode(bool on, float range)
me->GetMotionMaster()->MoveChase(victim, _attackDistance);
}
void SmartAI::SetMainSpell(uint32 spellId)
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
if (!spellInfo)
return;
float maxRange = spellInfo->GetMaxRange(false);
if (maxRange <= NOMINAL_MELEE_RANGE)
return;
_attackDistance = std::max(maxRange - NOMINAL_MELEE_RANGE, 0.0f);
_currentRangeMode = true;
}
void SmartAI::DistanceYourself(float range)
{
Unit* victim = me->GetVictim();

View File

@@ -67,6 +67,7 @@ public:
void SetAutoAttack(bool on) { mCanAutoAttack = on; }
void SetCombatMovement(bool on, bool stopOrStartMovement);
void SetCurrentRangeMode(bool on, float range = 0.f);
void SetMainSpell(uint32 spellId);
void DistanceYourself(float range);
void SetFollow(Unit* target, float dist = 0.0f, float angle = 0.0f, uint32 credit = 0, uint32 end = 0, uint32 creditType = 0, bool aliveState = true);
void StopFollow(bool complete);

View File

@@ -707,7 +707,6 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
continue;
}
// Let us not try to cast spell if we know it is going to fail anyway. Stick to chasing and continue.
if (distanceToTarget > spellMaxRange && isWithinLOSInMap)
{
failedSpellCast = true;
@@ -745,12 +744,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
if (e.action.cast.castFlags & SMARTCAST_COMBAT_MOVE)
{
// If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed unless target is outside spell range, out of mana, or LOS.
if (result == SPELL_FAILED_OUT_OF_RANGE || result == SPELL_CAST_OK)
// if we are just out of range, we only chase until we are back in spell range.
if (result == SPELL_FAILED_OUT_OF_RANGE)
CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(true, std::max(spellMaxRange - NOMINAL_MELEE_RANGE, 0.0f));
else // move into melee on any other fail
// if spell fail for any other reason, we chase to melee range, or stay where we are if spellcast was successful.
else if (result != SPELL_CAST_OK)
CAST_AI(SmartAI, me->AI())->SetCurrentRangeMode(false, 0.f);
}

View File

@@ -207,6 +207,8 @@ public:
void AddCreatureSummon(ObjectGuid const& guid);
void RemoveCreatureSummon(ObjectGuid const& guid);
SmartAIEventList const& GetEvents() const { return mEvents; }
private:
void IncPhase(uint32 p);
void DecPhase(uint32 p);

View File

@@ -1932,16 +1932,17 @@ enum SmartEventFlags
enum SmartCastFlags
{
SMARTCAST_INTERRUPT_PREVIOUS = 0x001, // Interrupt any spell casting
SMARTCAST_TRIGGERED = 0x002, // Triggered (this makes spell cost zero mana and have no cast time)
//CAST_FORCE_CAST = 0x004, // Forces cast even if creature is out of mana or out of range
//CAST_NO_MELEE_IF_OOM = 0x008, // Prevents creature from entering melee if out of mana or out of range
//CAST_FORCE_TARGET_SELF = 0x010, // Forces the target to cast this spell on itself
SMARTCAST_AURA_NOT_PRESENT = 0x020, // Only casts the spell if the target does not have an aura from the spell
SMARTCAST_COMBAT_MOVE = 0x040, // Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
SMARTCAST_THREATLIST_NOT_SINGLE = 0x080, // Only cast if the source's threatlist is higher than one. This includes pets (see Skeram's True Fulfillment)
SMARTCAST_TARGET_POWER_MANA = 0x100, // Only cast if the target has power type mana (e.g. Mana Drain)
SMARTCAST_ENABLE_COMBAT_MOVE_ON_LOS = 0x200,
SMARTCAST_INTERRUPT_PREVIOUS = 0x001, // Interrupt any spell casting
SMARTCAST_TRIGGERED = 0x002, // Triggered (this makes spell cost zero mana and have no cast time)
//CAST_FORCE_CAST = 0x004, // Forces cast even if creature is out of mana or out of range
//CAST_NO_MELEE_IF_OOM = 0x008, // Prevents creature from entering melee if out of mana or out of range
//CAST_FORCE_TARGET_SELF = 0x010, // Forces the target to cast this spell on itself
SMARTCAST_AURA_NOT_PRESENT = 0x020, // Only casts the spell if the target does not have an aura from the spell
SMARTCAST_COMBAT_MOVE = 0x040, // Prevents combat movement if cast successful. Allows movement on range, OOM, LOS
SMARTCAST_THREATLIST_NOT_SINGLE = 0x080, // Only cast if the source's threatlist is higher than one. This includes pets (see Skeram's True Fulfillment)
SMARTCAST_TARGET_POWER_MANA = 0x100, // Only cast if the target has power type mana (e.g. Mana Drain)
SMARTCAST_ENABLE_COMBAT_MOVE_ON_LOS = 0x200, // Allows combat movement when not in line of sight
SMARTCAST_MAIN_SPELL = 0x400, // Sets this spell's max range as the creature's chase distance on spawn
};
enum SmartFollowType