Improved Combat Movement handling
* Improved Combat Movement handling * Some fixes to previous commit * Another bunch of fixes combat movement
This commit is contained in:
parent
17ebddd19d
commit
2776812b2e
@ -32,6 +32,11 @@
|
|||||||
|
|
||||||
static_assert(MAXIMAL_AI_EVENT_EVENTAI <= 32, "Maximal 32 AI_EVENTs supported with EventAI");
|
static_assert(MAXIMAL_AI_EVENT_EVENTAI <= 32, "Maximal 32 AI_EVENTs supported with EventAI");
|
||||||
|
|
||||||
|
CreatureAI::CreatureAI(Creature* creature) : m_creature(creature), m_combatMovement(CM_SCRIPT),
|
||||||
|
m_attackDistance(0.0f), m_attackAngle(0.0f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
CreatureAI::~CreatureAI()
|
CreatureAI::~CreatureAI()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -52,7 +57,7 @@ CanCastResult CreatureAI::CanCastSpell(Unit* pTarget, const SpellEntry* pSpell,
|
|||||||
{ return CAST_FAIL_STATE; }
|
{ return CAST_FAIL_STATE; }
|
||||||
|
|
||||||
if (pSpell->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
|
if (pSpell->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
|
||||||
{ return CAST_FAIL_STATE; }
|
{ return CAST_FAIL_SILENCED; }
|
||||||
|
|
||||||
if (pSpell->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
|
if (pSpell->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
|
||||||
{ return CAST_FAIL_STATE; }
|
{ return CAST_FAIL_STATE; }
|
||||||
@ -94,7 +99,6 @@ CanCastResult CreatureAI::DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32
|
|||||||
if (uiCastFlags & CAST_FORCE_TARGET_SELF)
|
if (uiCastFlags & CAST_FORCE_TARGET_SELF)
|
||||||
{ pCaster = pTarget; }
|
{ pCaster = pTarget; }
|
||||||
|
|
||||||
// Allowed to cast only if not casting (unless we interrupt ourself) or if spell is triggered
|
|
||||||
if (!pCaster->IsNonMeleeSpellCasted(false) || (uiCastFlags & (CAST_TRIGGERED | CAST_INTERRUPT_PREVIOUS)))
|
if (!pCaster->IsNonMeleeSpellCasted(false) || (uiCastFlags & (CAST_TRIGGERED | CAST_INTERRUPT_PREVIOUS)))
|
||||||
{
|
{
|
||||||
if (const SpellEntry* pSpell = sSpellStore.LookupEntry(uiSpell))
|
if (const SpellEntry* pSpell = sSpellStore.LookupEntry(uiSpell))
|
||||||
@ -112,24 +116,27 @@ CanCastResult CreatureAI::DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32
|
|||||||
CanCastResult castResult = CanCastSpell(pTarget, pSpell, uiCastFlags & CAST_TRIGGERED);
|
CanCastResult castResult = CanCastSpell(pTarget, pSpell, uiCastFlags & CAST_TRIGGERED);
|
||||||
|
|
||||||
if (castResult != CAST_OK)
|
if (castResult != CAST_OK)
|
||||||
{ return castResult; }
|
{
|
||||||
|
return castResult;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interrupt any previous spell
|
if ( (uiCastFlags & CAST_INTERRUPT_PREVIOUS) && pCaster->IsNonMeleeSpellCasted(false))
|
||||||
if (uiCastFlags & CAST_INTERRUPT_PREVIOUS && pCaster->IsNonMeleeSpellCasted(false))
|
pCaster->CastStop();
|
||||||
{ pCaster->InterruptNonMeleeSpells(false); }
|
|
||||||
|
pCaster->StopMoving();
|
||||||
|
|
||||||
pCaster->CastSpell(pTarget, pSpell, uiCastFlags & CAST_TRIGGERED, NULL, NULL, uiOriginalCasterGUID);
|
pCaster->CastSpell(pTarget, pSpell, uiCastFlags & CAST_TRIGGERED, NULL, NULL, uiOriginalCasterGUID);
|
||||||
return CAST_OK;
|
return CAST_OK;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sLog.outErrorDb("DoCastSpellIfCan by creature entry %u attempt to cast spell %u but spell does not exist.", m_creature->GetEntry(), uiSpell);
|
sLog.outErrorDb("DoCastSpellIfCan: %s attempt to cast spell %u but spell does not exist.",
|
||||||
|
m_creature->GetGuidStr().c_str(), uiSpell);
|
||||||
return CAST_FAIL_OTHER;
|
return CAST_FAIL_OTHER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
return CAST_FAIL_IS_CASTING;
|
||||||
{ return CAST_FAIL_IS_CASTING; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CreatureAI::DoMeleeAttackIfReady()
|
bool CreatureAI::DoMeleeAttackIfReady()
|
||||||
@ -137,46 +144,54 @@ bool CreatureAI::DoMeleeAttackIfReady()
|
|||||||
return m_creature->UpdateMeleeAttackingState();
|
return m_creature->UpdateMeleeAttackingState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatureAI::AddCombatMovementFlags(uint32 cmFlags)
|
|
||||||
{
|
|
||||||
if (!m_combatMovement)
|
|
||||||
{ m_creature->clearUnitState(UNIT_STAT_NO_COMBAT_MOVEMENT); }
|
|
||||||
|
|
||||||
m_combatMovement |= cmFlags;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreatureAI::ClearCombatMovementFlags(uint32 cmFlags)
|
|
||||||
{
|
|
||||||
m_combatMovement &= ~cmFlags;
|
|
||||||
|
|
||||||
if (!m_combatMovement)
|
|
||||||
{ m_creature->addUnitState(UNIT_STAT_NO_COMBAT_MOVEMENT); }
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreatureAI::SetCombatMovement(bool enable, bool stopOrStartMovement /*=false*/)
|
void CreatureAI::SetCombatMovement(bool enable, bool stopOrStartMovement /*=false*/)
|
||||||
{
|
{
|
||||||
if (stopOrStartMovement && m_creature->getVictim()) // Only change current movement while in combat
|
SetCombatMovementFlag(CM_SCRIPT, enable);
|
||||||
|
|
||||||
|
if (stopOrStartMovement) // Only change current movement while in combat
|
||||||
|
SetChase(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreatureAI::SetCombatMovementFlag(uint8 flag, bool setFlag)
|
||||||
|
{
|
||||||
|
if (setFlag)
|
||||||
|
{
|
||||||
|
m_combatMovement |= flag;
|
||||||
|
if (m_combatMovement)
|
||||||
|
m_creature->clearUnitState(UNIT_STAT_NO_COMBAT_MOVEMENT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_combatMovement &= ~flag;
|
||||||
|
if (m_combatMovement == 0)
|
||||||
|
m_creature->addUnitState(UNIT_STAT_NO_COMBAT_MOVEMENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreatureAI::SetChase(bool chase)
|
||||||
|
{
|
||||||
|
if (IsCombatMovement() && m_creature->getVictim())
|
||||||
{
|
{
|
||||||
MotionMaster* creatureMotion = m_creature->GetMotionMaster();
|
MotionMaster* creatureMotion = m_creature->GetMotionMaster();
|
||||||
creatureMotion->MovementExpired(false);
|
if (chase)
|
||||||
if (enable)
|
|
||||||
{
|
{
|
||||||
switch(creatureMotion->GetCurrentMovementGeneratorType())
|
switch(creatureMotion->GetCurrentMovementGeneratorType())
|
||||||
{
|
{
|
||||||
|
case IDLE_MOTION_TYPE:
|
||||||
case CHASE_MOTION_TYPE:
|
case CHASE_MOTION_TYPE:
|
||||||
case FOLLOW_MOTION_TYPE:
|
case FOLLOW_MOTION_TYPE:
|
||||||
creatureMotion->Clear(false);
|
creatureMotion->Clear(false);
|
||||||
|
creatureMotion->MoveChase(m_creature->getVictim(), 0.0f, 0.0f);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
creatureMotion->MoveChase(m_creature->getVictim(), m_attackDistance, m_creature->GetAngle(m_creature->getVictim()));
|
|
||||||
}
|
}
|
||||||
else if (creatureMotion->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
|
else if (creatureMotion->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
|
||||||
{
|
{
|
||||||
creatureMotion->Clear(false);
|
|
||||||
m_creature->StopMoving();
|
m_creature->StopMoving();
|
||||||
creatureMotion->MoveIdle();
|
if (!m_creature->CanReachWithMeleeAttack(m_creature->getVictim()))
|
||||||
|
m_creature->SendMeleeAttackStop(m_creature->getVictim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,15 +199,16 @@ void CreatureAI::SetCombatMovement(bool enable, bool stopOrStartMovement /*=fals
|
|||||||
void CreatureAI::HandleMovementOnAttackStart(Unit* victim)
|
void CreatureAI::HandleMovementOnAttackStart(Unit* victim)
|
||||||
{
|
{
|
||||||
MotionMaster* creatureMotion = m_creature->GetMotionMaster();
|
MotionMaster* creatureMotion = m_creature->GetMotionMaster();
|
||||||
creatureMotion->MovementExpired(false);
|
MovementGeneratorType mmgen = creatureMotion->GetCurrentMovementGeneratorType();
|
||||||
|
|
||||||
if (IsCombatMovement())
|
if (IsCombatMovement())
|
||||||
{ creatureMotion->MoveChase(victim, m_attackDistance, m_attackAngle); }
|
{ creatureMotion->MoveChase(victim, m_attackDistance, m_attackAngle); }
|
||||||
|
|
||||||
// TODO - adapt this to only stop OOC-MMGens when MotionMaster rewrite is finished
|
// TODO - adapt this to only stop OOC-MMGens when MotionMaster rewrite is finished
|
||||||
else if (creatureMotion->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE || creatureMotion->GetCurrentMovementGeneratorType() == RANDOM_MOTION_TYPE)
|
else if (mmgen == WAYPOINT_MOTION_TYPE || mmgen == RANDOM_MOTION_TYPE)
|
||||||
{
|
{
|
||||||
m_creature->StopMoving();
|
|
||||||
creatureMotion->MoveIdle();
|
creatureMotion->MoveIdle();
|
||||||
|
m_creature->StopMoving();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,8 @@ enum CanCastResult
|
|||||||
CAST_FAIL_POWER = 5,
|
CAST_FAIL_POWER = 5,
|
||||||
CAST_FAIL_STATE = 6,
|
CAST_FAIL_STATE = 6,
|
||||||
CAST_FAIL_TARGET_AURA = 7,
|
CAST_FAIL_TARGET_AURA = 7,
|
||||||
CAST_FAIL_NO_LOS = 8
|
CAST_FAIL_NO_LOS = 8,
|
||||||
|
CAST_FAIL_SILENCED = 9
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CastFlags
|
enum CastFlags
|
||||||
@ -68,10 +69,8 @@ enum CastFlags
|
|||||||
|
|
||||||
enum CombatMovementFlags
|
enum CombatMovementFlags
|
||||||
{
|
{
|
||||||
COMBAT_MOVEMENT_SCRIPT = 0x01, // Combat movement enforced by script
|
CM_SCRIPT = 0x01,
|
||||||
COMBAT_MOVEMENT_LOS = 0x02, // Combat movement triggered by LoS issues
|
CM_SPELL = 0x02,
|
||||||
COMBAT_MOVEMENT_OOM = 0x04, // Combat movement triggered by power exhaustion
|
|
||||||
COMBAT_MOVEMENT_DISTANCE = 0x08 // Combat movement triggered by distance checks
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum AIEventType
|
enum AIEventType
|
||||||
@ -109,13 +108,7 @@ enum AIEventType
|
|||||||
class CreatureAI
|
class CreatureAI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit CreatureAI(Creature* creature) :
|
explicit CreatureAI(Creature* creature);
|
||||||
m_creature(creature),
|
|
||||||
m_combatMovement(0),
|
|
||||||
m_attackDistance(0.0f),
|
|
||||||
m_attackAngle(0.0f)
|
|
||||||
{ AddCombatMovementFlags(COMBAT_MOVEMENT_SCRIPT); }
|
|
||||||
|
|
||||||
virtual ~CreatureAI();
|
virtual ~CreatureAI();
|
||||||
|
|
||||||
///== Information about AI ========================
|
///== Information about AI ========================
|
||||||
@ -232,6 +225,12 @@ class CreatureAI
|
|||||||
*/
|
*/
|
||||||
virtual void SpellHit(Unit* /*pCaster*/, const SpellEntry* /*pSpell*/) {}
|
virtual void SpellHit(Unit* /*pCaster*/, const SpellEntry* /*pSpell*/) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the current casted spell is processed
|
||||||
|
* @param pSpell The spell that is casted currently
|
||||||
|
* @param reason The spell state (see SpellCastResult enum)
|
||||||
|
*/
|
||||||
|
virtual void OnSpellCastChange(const SpellEntry* /*pSpell*/, SpellCastResult /*reason*/) {}
|
||||||
/**
|
/**
|
||||||
* Called when spell hits creature's target
|
* Called when spell hits creature's target
|
||||||
* @param pTarget Target that we hit with the spell
|
* @param pTarget Target that we hit with the spell
|
||||||
@ -318,13 +317,13 @@ class CreatureAI
|
|||||||
* @param uiCastFlags Some flags to define how to cast, see enum CastFlags
|
* @param uiCastFlags Some flags to define how to cast, see enum CastFlags
|
||||||
* @param OriginalCasterGuid the original caster of the spell if required, empty by default
|
* @param OriginalCasterGuid the original caster of the spell if required, empty by default
|
||||||
*/
|
*/
|
||||||
CanCastResult DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 uiCastFlags = 0, ObjectGuid OriginalCasterGuid = ObjectGuid());
|
virtual CanCastResult DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 uiCastFlags = 0, ObjectGuid OriginalCasterGuid = ObjectGuid());
|
||||||
|
|
||||||
/// Combat movement functions
|
/// Combat movement functions
|
||||||
void SetCombatMovement(bool enable, bool stopOrStartMovement = false);
|
void SetCombatMovement(bool enable, bool stopOrStartMovement = false);
|
||||||
bool IsCombatMovement() const { return m_combatMovement != 0; }
|
bool IsCombatMovement() const { return m_combatMovement != 0; }
|
||||||
void AddCombatMovementFlags(uint32 cmFlags);
|
uint8 GetCombatMovementFlags() const { return m_combatMovement; }
|
||||||
void ClearCombatMovementFlags(uint32 cmFlags);
|
void SetCombatMovementFlag(uint8 flag, bool setFlag = true);
|
||||||
|
|
||||||
///== Event Handling ===============================
|
///== Event Handling ===============================
|
||||||
|
|
||||||
@ -354,21 +353,23 @@ class CreatureAI
|
|||||||
virtual void ReceiveAIEvent(AIEventType /*eventType*/, Creature* /*pSender*/, Unit* /*pInvoker*/, uint32 /*miscValue*/) {}
|
virtual void ReceiveAIEvent(AIEventType /*eventType*/, Creature* /*pSender*/, Unit* /*pInvoker*/, uint32 /*miscValue*/) {}
|
||||||
|
|
||||||
// Reset should be defined here, as it is called from out the AI ctor now
|
// Reset should be defined here, as it is called from out the AI ctor now
|
||||||
virtual void Reset() {}
|
virtual void Reset() { m_combatMovement = CM_SCRIPT; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void HandleMovementOnAttackStart(Unit* victim);
|
void HandleMovementOnAttackStart(Unit* victim);
|
||||||
|
void SetChase(bool chase);
|
||||||
|
|
||||||
///== Fields =======================================
|
///== Fields =======================================
|
||||||
|
|
||||||
/// Pointer to the Creature controlled by this AI
|
/// Pointer to the Creature controlled by this AI
|
||||||
Creature* const m_creature;
|
Creature* const m_creature;
|
||||||
|
|
||||||
/// Combat movement currently enabled
|
|
||||||
uint32 m_combatMovement;
|
|
||||||
/// How should an enemy be chased
|
/// How should an enemy be chased
|
||||||
float m_attackDistance;
|
float m_attackDistance;
|
||||||
float m_attackAngle;
|
float m_attackAngle;
|
||||||
|
private:
|
||||||
|
/// Combat movement currently enabled
|
||||||
|
uint8 m_combatMovement;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SelectableAI : public FactoryHolder<CreatureAI>, public Permissible<Creature>
|
struct SelectableAI : public FactoryHolder<CreatureAI>, public Permissible<Creature>
|
||||||
|
@ -84,6 +84,7 @@ void CreatureEventAI::GetAIInformation(ChatHandler& reader)
|
|||||||
CreatureEventAI::CreatureEventAI(Creature* c) : CreatureAI(c),
|
CreatureEventAI::CreatureEventAI(Creature* c) : CreatureAI(c),
|
||||||
m_Phase(0),
|
m_Phase(0),
|
||||||
m_MeleeEnabled(true),
|
m_MeleeEnabled(true),
|
||||||
|
m_currSpell(0),
|
||||||
m_HasOOCLoSEvent(false),
|
m_HasOOCLoSEvent(false),
|
||||||
m_InvinceabilityHpLevel(0),
|
m_InvinceabilityHpLevel(0),
|
||||||
m_throwAIEventMask(0),
|
m_throwAIEventMask(0),
|
||||||
@ -627,7 +628,6 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
|
|||||||
{
|
{
|
||||||
uint32 selectFlags = 0;
|
uint32 selectFlags = 0;
|
||||||
uint32 spellId = 0;
|
uint32 spellId = 0;
|
||||||
uint32 cmFlags = 0;
|
|
||||||
|
|
||||||
if (!(action.cast.castFlags & (CAST_TRIGGERED | CAST_FORCE_CAST | CAST_FORCE_TARGET_SELF)))
|
if (!(action.cast.castFlags & (CAST_TRIGGERED | CAST_FORCE_CAST | CAST_FORCE_TARGET_SELF)))
|
||||||
{
|
{
|
||||||
@ -643,45 +643,8 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CanCastResult castResult = DoCastSpellIfCan(target, action.cast.spellId, action.cast.castFlags);
|
DoCastSpellIfCan(target, action.cast.spellId, action.cast.castFlags);
|
||||||
|
|
||||||
switch (castResult)
|
|
||||||
{
|
|
||||||
case CAST_FAIL_POWER:
|
|
||||||
cmFlags |= COMBAT_MOVEMENT_OOM;
|
|
||||||
break;
|
|
||||||
case CAST_FAIL_TOO_FAR:
|
|
||||||
cmFlags |= COMBAT_MOVEMENT_DISTANCE;
|
|
||||||
break;
|
|
||||||
case CAST_FAIL_NO_LOS:
|
|
||||||
cmFlags |= COMBAT_MOVEMENT_LOS;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Melee current victim if flag not set
|
|
||||||
if (cmFlags)
|
|
||||||
{
|
|
||||||
if (!(action.cast.castFlags & CAST_NO_MELEE_IF_OOM))
|
|
||||||
{
|
|
||||||
AddCombatMovementFlags(cmFlags);
|
|
||||||
SetCombatMovement(true,true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (m_combatMovement & (COMBAT_MOVEMENT_LOS | COMBAT_MOVEMENT_DISTANCE | COMBAT_MOVEMENT_OOM))
|
|
||||||
{
|
|
||||||
ClearCombatMovementFlags(COMBAT_MOVEMENT_LOS | COMBAT_MOVEMENT_DISTANCE | COMBAT_MOVEMENT_OOM);
|
|
||||||
|
|
||||||
if (!IsCombatMovement() && m_creature->IsNonMeleeSpellCasted(false) && m_creature->IsInCombat() && m_creature->getVictim())
|
|
||||||
{
|
|
||||||
SetCombatMovement(false,true);
|
|
||||||
m_creature->SendMeleeAttackStop(m_creature->getVictim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ACTION_T_SUMMON: //12
|
case ACTION_T_SUMMON: //12
|
||||||
@ -766,26 +729,22 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
|
|||||||
m_MeleeEnabled = action.auto_attack.state != 0;
|
m_MeleeEnabled = action.auto_attack.state != 0;
|
||||||
break;
|
break;
|
||||||
case ACTION_T_COMBAT_MOVEMENT: //21
|
case ACTION_T_COMBAT_MOVEMENT: //21
|
||||||
// ignore no affect case
|
|
||||||
if (IsCombatMovement() == (action.combat_movement.state != 0) || m_creature->IsNonMeleeSpellCasted(false))
|
|
||||||
{
|
{
|
||||||
if (IsCombatMovement())
|
// ignore no affect case
|
||||||
{ AddCombatMovementFlags(COMBAT_MOVEMENT_SCRIPT); }
|
if ((GetCombatMovementFlags() & CM_SCRIPT) == (action.combat_movement.state != 0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
SetCombatMovement(action.combat_movement.state != 0, true);
|
||||||
|
|
||||||
|
if (m_creature->IsInCombat() && m_creature->getVictim())
|
||||||
|
{
|
||||||
|
if (IsCombatMovement() && action.combat_movement.melee)
|
||||||
|
m_creature->SendMeleeAttackStart(m_creature->getVictim());
|
||||||
|
else if (action.combat_movement.melee)
|
||||||
|
m_creature->SendMeleeAttackStop(m_creature->getVictim());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.combat_movement.state != 0)
|
|
||||||
{ AddCombatMovementFlags(COMBAT_MOVEMENT_SCRIPT); }
|
|
||||||
else
|
|
||||||
{ ClearCombatMovementFlags(COMBAT_MOVEMENT_SCRIPT); }
|
|
||||||
|
|
||||||
SetCombatMovement(IsCombatMovement(), true);
|
|
||||||
|
|
||||||
if (IsCombatMovement() && action.combat_movement.melee && m_creature->IsInCombat() && m_creature->getVictim())
|
|
||||||
{ m_creature->SendMeleeAttackStart(m_creature->getVictim()); }
|
|
||||||
else if (action.combat_movement.melee && m_creature->IsInCombat() && m_creature->getVictim())
|
|
||||||
{ m_creature->SendMeleeAttackStop(m_creature->getVictim()); }
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case ACTION_T_SET_PHASE: //22
|
case ACTION_T_SET_PHASE: //22
|
||||||
m_Phase = action.set_phase.phase;
|
m_Phase = action.set_phase.phase;
|
||||||
DEBUG_FILTER_LOG(LOG_FILTER_EVENT_AI_DEV, "CreatureEventAI: ACTION_T_SET_PHASE - script %u for %s, phase is now %u", EventId, m_creature->GetGuidStr().c_str(), m_Phase);
|
DEBUG_FILTER_LOG(LOG_FILTER_EVENT_AI_DEV, "CreatureEventAI: ACTION_T_SET_PHASE - script %u for %s, phase is now %u", EventId, m_creature->GetGuidStr().c_str(), m_Phase);
|
||||||
@ -1111,6 +1070,7 @@ void CreatureEventAI::JustRespawned() // NOTE that this is
|
|||||||
|
|
||||||
void CreatureEventAI::Reset()
|
void CreatureEventAI::Reset()
|
||||||
{
|
{
|
||||||
|
m_currSpell = 0;
|
||||||
m_EventUpdateTime = EVENT_UPDATE_TIME;
|
m_EventUpdateTime = EVENT_UPDATE_TIME;
|
||||||
m_EventDiff = 0;
|
m_EventDiff = 0;
|
||||||
m_throwAIEventStep = 0;
|
m_throwAIEventStep = 0;
|
||||||
@ -1618,3 +1578,71 @@ bool CreatureEventAI::SpawnedEventConditionsCheck(CreatureEventAI_Event const& e
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CreatureEventAI::OnSpellCastChange(const SpellEntry* pSpell, SpellCastResult reason)
|
||||||
|
{
|
||||||
|
//sLog.outError("Received reason %u for %s, spell %u (curSpell = %u)", reason, m_creature->GetGuidStr().c_str(), pSpell->Id, m_currSpell);
|
||||||
|
|
||||||
|
if (!pSpell || pSpell->Id != m_currSpell)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_currSpell = 0;
|
||||||
|
|
||||||
|
switch (reason)
|
||||||
|
{
|
||||||
|
case SPELL_CAST_OK:
|
||||||
|
break;
|
||||||
|
// Add more cases here
|
||||||
|
case SPELL_FAILED_OUT_OF_RANGE:
|
||||||
|
case SPELL_FAILED_LINE_OF_SIGHT:
|
||||||
|
case SPELL_FAILED_NO_POWER:
|
||||||
|
case SPELL_FAILED_INTERRUPTED:
|
||||||
|
case SPELL_FAILED_SILENCED:
|
||||||
|
m_creature->CastStop();
|
||||||
|
SetCombatMovementFlag(CM_SPELL);
|
||||||
|
SetChase(true);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
m_creature->CastStop();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SetCombatMovementFlag(CM_SPELL, false);
|
||||||
|
SetChase(false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CanCastResult CreatureEventAI::DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 uiCastFlags, ObjectGuid uiOriginalCasterGuid)
|
||||||
|
{
|
||||||
|
SetCombatMovementFlag(CM_SPELL, false);
|
||||||
|
m_currSpell = uiSpell;
|
||||||
|
SetChase(false);
|
||||||
|
|
||||||
|
CanCastResult result = CreatureAI::DoCastSpellIfCan(pTarget, uiSpell, uiCastFlags, uiOriginalCasterGuid);
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case CAST_OK:
|
||||||
|
break;
|
||||||
|
case CAST_FAIL_TOO_FAR:
|
||||||
|
case CAST_FAIL_NO_LOS:
|
||||||
|
case CAST_FAIL_POWER:
|
||||||
|
case CAST_FAIL_SILENCED:
|
||||||
|
{
|
||||||
|
if (!(uiCastFlags & CAST_NO_MELEE_IF_OOM))
|
||||||
|
{
|
||||||
|
SetCombatMovementFlag(CM_SPELL);
|
||||||
|
SetChase(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_currSpell = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
m_currSpell = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -665,6 +665,8 @@ class CreatureEventAI : public CreatureAI
|
|||||||
void AttackStart(Unit* who) override;
|
void AttackStart(Unit* who) override;
|
||||||
void MoveInLineOfSight(Unit* who) override;
|
void MoveInLineOfSight(Unit* who) override;
|
||||||
void SpellHit(Unit* pUnit, const SpellEntry* pSpell) override;
|
void SpellHit(Unit* pUnit, const SpellEntry* pSpell) override;
|
||||||
|
void OnSpellCastChange(const SpellEntry* pSpell, SpellCastResult reason) override;
|
||||||
|
virtual CanCastResult DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 uiCastFlags = 0, ObjectGuid OriginalCasterGuid = ObjectGuid());
|
||||||
void DamageTaken(Unit* done_by, uint32& damage) override;
|
void DamageTaken(Unit* done_by, uint32& damage) override;
|
||||||
void HealedBy(Unit* healer, uint32& healedAmount) override;
|
void HealedBy(Unit* healer, uint32& healedAmount) override;
|
||||||
void UpdateAI(const uint32 diff) override;
|
void UpdateAI(const uint32 diff) override;
|
||||||
@ -701,6 +703,7 @@ class CreatureEventAI : public CreatureAI
|
|||||||
bool m_MeleeEnabled; // If we allow melee auto attack
|
bool m_MeleeEnabled; // If we allow melee auto attack
|
||||||
bool m_HasOOCLoSEvent; // Cache if a OOC-LoS Event exists
|
bool m_HasOOCLoSEvent; // Cache if a OOC-LoS Event exists
|
||||||
uint32 m_InvinceabilityHpLevel; // Minimal health level allowed at damage apply
|
uint32 m_InvinceabilityHpLevel; // Minimal health level allowed at damage apply
|
||||||
|
uint32 m_currSpell; // track current spell from ACTION_T_CAST if any
|
||||||
|
|
||||||
uint32 m_throwAIEventMask; // Automatically throw AIEvents that are encoded into this mask
|
uint32 m_throwAIEventMask; // Automatically throw AIEvents that are encoded into this mask
|
||||||
// Note that Step 100 means that AI_EVENT_GOT_FULL_HEALTH was sent
|
// Note that Step 100 means that AI_EVENT_GOT_FULL_HEALTH was sent
|
||||||
|
@ -8591,7 +8591,9 @@ void Unit::SetFeared(bool apply, ObjectGuid casterGuid, uint32 spellID, uint32 t
|
|||||||
|
|
||||||
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
|
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_FLEEING);
|
||||||
|
|
||||||
|
StopMoving(GetTypeId() == TYPEID_PLAYER);
|
||||||
GetMotionMaster()->MovementExpired(false);
|
GetMotionMaster()->MovementExpired(false);
|
||||||
|
|
||||||
CastStop(GetObjectGuid() == casterGuid ? spellID : 0);
|
CastStop(GetObjectGuid() == casterGuid ? spellID : 0);
|
||||||
|
|
||||||
if (GetTypeId() == TYPEID_UNIT)
|
if (GetTypeId() == TYPEID_UNIT)
|
||||||
@ -8637,7 +8639,9 @@ void Unit::SetConfused(bool apply, ObjectGuid casterGuid, uint32 spellID)
|
|||||||
{
|
{
|
||||||
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
|
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_CONFUSED);
|
||||||
|
|
||||||
|
StopMoving(GetTypeId() == TYPEID_PLAYER);
|
||||||
GetMotionMaster()->MovementExpired(false);
|
GetMotionMaster()->MovementExpired(false);
|
||||||
|
|
||||||
CastStop(GetObjectGuid() == casterGuid ? spellID : 0);
|
CastStop(GetObjectGuid() == casterGuid ? spellID : 0);
|
||||||
|
|
||||||
if (GetTypeId() == TYPEID_UNIT)
|
if (GetTypeId() == TYPEID_UNIT)
|
||||||
|
@ -3261,7 +3261,11 @@ void Spell::finish(bool ok)
|
|||||||
void Spell::SendCastResult(SpellCastResult result)
|
void Spell::SendCastResult(SpellCastResult result)
|
||||||
{
|
{
|
||||||
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
if (m_caster->GetTypeId() != TYPEID_PLAYER)
|
||||||
{ return; }
|
{
|
||||||
|
if (((Creature*)m_caster)->AI())
|
||||||
|
((Creature*)m_caster)->AI()->OnSpellCastChange(m_spellInfo, result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (((Player*)m_caster)->GetSession()->PlayerLoading()) // don't send cast results at loading time
|
if (((Player*)m_caster)->GetSession()->PlayerLoading()) // don't send cast results at loading time
|
||||||
{ return; }
|
{ return; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user