Merge pull request #54 from H0zen/develop21
[EventAI] Improved logic in ACTION_T_CAST
This commit is contained in:
commit
ed4886b0b2
@ -57,14 +57,14 @@ CanCastResult CreatureAI::CanCastSpell(Unit* pTarget, const SpellEntry* pSpell,
|
|||||||
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; }
|
||||||
|
|
||||||
if (!m_creature->IsWithinLOSInMap(pTarget))
|
|
||||||
{ return CAST_FAIL_NO_LOS; }
|
|
||||||
|
|
||||||
// Check for power (also done by Spell::CheckCast())
|
// Check for power (also done by Spell::CheckCast())
|
||||||
if (m_creature->GetPower((Powers)pSpell->powerType) < Spell::CalculatePowerCost(pSpell, m_creature))
|
if (m_creature->GetPower((Powers)pSpell->powerType) < Spell::CalculatePowerCost(pSpell, m_creature))
|
||||||
{ return CAST_FAIL_POWER; }
|
{ return CAST_FAIL_POWER; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!m_creature->IsWithinLOSInMap(pTarget))
|
||||||
|
{ return CAST_FAIL_NO_LOS; }
|
||||||
|
|
||||||
if (const SpellRangeEntry* pSpellRange = sSpellRangeStore.LookupEntry(pSpell->rangeIndex))
|
if (const SpellRangeEntry* pSpellRange = sSpellRangeStore.LookupEntry(pSpell->rangeIndex))
|
||||||
{
|
{
|
||||||
if (pTarget != m_creature)
|
if (pTarget != m_creature)
|
||||||
@ -137,26 +137,43 @@ 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*/)
|
||||||
{
|
{
|
||||||
m_isCombatMovement = enable;
|
|
||||||
|
|
||||||
if (enable)
|
|
||||||
{ m_creature->clearUnitState(UNIT_STAT_NO_COMBAT_MOVEMENT); }
|
|
||||||
else
|
|
||||||
{ m_creature->addUnitState(UNIT_STAT_NO_COMBAT_MOVEMENT); }
|
|
||||||
|
|
||||||
if (stopOrStartMovement && m_creature->getVictim()) // Only change current movement while in combat
|
if (stopOrStartMovement && m_creature->getVictim()) // Only change current movement while in combat
|
||||||
{
|
{
|
||||||
MotionMaster* creatureMotion = m_creature->GetMotionMaster();
|
MotionMaster* creatureMotion = m_creature->GetMotionMaster();
|
||||||
|
creatureMotion->MovementExpired(false);
|
||||||
if (enable)
|
if (enable)
|
||||||
{
|
{
|
||||||
m_creature->CastStop();
|
switch(creatureMotion->GetCurrentMovementGeneratorType())
|
||||||
creatureMotion->MoveChase(m_creature->getVictim(), m_attackDistance, m_attackAngle);
|
{
|
||||||
|
case CHASE_MOTION_TYPE:
|
||||||
|
case FOLLOW_MOTION_TYPE:
|
||||||
|
creatureMotion->Clear(false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
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->MovementExpired();
|
|
||||||
creatureMotion->Clear(false);
|
creatureMotion->Clear(false);
|
||||||
m_creature->StopMoving();
|
m_creature->StopMoving();
|
||||||
creatureMotion->MoveIdle();
|
creatureMotion->MoveIdle();
|
||||||
@ -167,7 +184,9 @@ 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();
|
||||||
if (m_isCombatMovement)
|
creatureMotion->MovementExpired(false);
|
||||||
|
|
||||||
|
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 (creatureMotion->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE || creatureMotion->GetCurrentMovementGeneratorType() == RANDOM_MOTION_TYPE)
|
||||||
|
@ -66,6 +66,14 @@ enum CastFlags
|
|||||||
CAST_AURA_NOT_PRESENT = 0x20, // Only casts the spell if the target does not have an aura from the spell
|
CAST_AURA_NOT_PRESENT = 0x20, // Only casts the spell if the target does not have an aura from the spell
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum CombatMovementFlags
|
||||||
|
{
|
||||||
|
COMBAT_MOVEMENT_SCRIPT = 0x01, // Combat movement enforced by script
|
||||||
|
COMBAT_MOVEMENT_LOS = 0x02, // Combat movement triggered by LoS issues
|
||||||
|
COMBAT_MOVEMENT_OOM = 0x04, // Combat movement triggered by power exhaustion
|
||||||
|
COMBAT_MOVEMENT_DISTANCE = 0x08 // Combat movement triggered by distance checks
|
||||||
|
};
|
||||||
|
|
||||||
enum AIEventType
|
enum AIEventType
|
||||||
{
|
{
|
||||||
// Usable with Event AI
|
// Usable with Event AI
|
||||||
@ -103,16 +111,16 @@ class CreatureAI
|
|||||||
public:
|
public:
|
||||||
explicit CreatureAI(Creature* creature) :
|
explicit CreatureAI(Creature* creature) :
|
||||||
m_creature(creature),
|
m_creature(creature),
|
||||||
m_isCombatMovement(true),
|
m_combatMovement(0),
|
||||||
m_attackDistance(0.0f),
|
m_attackDistance(0.0f),
|
||||||
m_attackAngle(0.0f)
|
m_attackAngle(0.0f)
|
||||||
{}
|
{ AddCombatMovementFlags(COMBAT_MOVEMENT_SCRIPT); }
|
||||||
|
|
||||||
virtual ~CreatureAI();
|
virtual ~CreatureAI();
|
||||||
|
|
||||||
///== Information about AI ========================
|
///== Information about AI ========================
|
||||||
/**
|
/**
|
||||||
* This funcion is used to display information about the AI.
|
* This function is used to display information about the AI.
|
||||||
* It is called when the .npc aiinfo command is used.
|
* It is called when the .npc aiinfo command is used.
|
||||||
* Use this for on-the-fly debugging
|
* Use this for on-the-fly debugging
|
||||||
* @param reader is a ChatHandler to send messages to.
|
* @param reader is a ChatHandler to send messages to.
|
||||||
@ -312,10 +320,12 @@ class CreatureAI
|
|||||||
*/
|
*/
|
||||||
CanCastResult DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 uiCastFlags = 0, ObjectGuid OriginalCasterGuid = ObjectGuid());
|
CanCastResult DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 uiCastFlags = 0, ObjectGuid OriginalCasterGuid = ObjectGuid());
|
||||||
|
|
||||||
/// Set combat movement (on/off), also sets UNIT_STAT_NO_COMBAT_MOVEMENT
|
/// Combat movement functions
|
||||||
void SetCombatMovement(bool enable, bool stopOrStartMovement = false);
|
void SetCombatMovement(bool enable, bool stopOrStartMovement = false);
|
||||||
bool IsCombatMovement() const { return m_isCombatMovement; }
|
bool IsCombatMovement() const { return m_combatMovement != 0; }
|
||||||
|
void AddCombatMovementFlags(uint32 cmFlags);
|
||||||
|
void ClearCombatMovementFlags(uint32 cmFlags);
|
||||||
|
|
||||||
///== Event Handling ===============================
|
///== Event Handling ===============================
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -355,7 +365,7 @@ class CreatureAI
|
|||||||
Creature* const m_creature;
|
Creature* const m_creature;
|
||||||
|
|
||||||
/// Combat movement currently enabled
|
/// Combat movement currently enabled
|
||||||
bool m_isCombatMovement;
|
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;
|
||||||
|
@ -63,7 +63,7 @@ int CreatureEventAI::Permissible(const Creature* creature)
|
|||||||
void CreatureEventAI::GetAIInformation(ChatHandler& reader)
|
void CreatureEventAI::GetAIInformation(ChatHandler& reader)
|
||||||
{
|
{
|
||||||
reader.PSendSysMessage(LANG_NPC_EVENTAI_PHASE, (uint32)m_Phase);
|
reader.PSendSysMessage(LANG_NPC_EVENTAI_PHASE, (uint32)m_Phase);
|
||||||
reader.PSendSysMessage(LANG_NPC_EVENTAI_MOVE, reader.GetOnOffStr(m_isCombatMovement));
|
reader.PSendSysMessage(LANG_NPC_EVENTAI_MOVE, reader.GetOnOffStr(IsCombatMovement()));
|
||||||
reader.PSendSysMessage(LANG_NPC_EVENTAI_COMBAT, reader.GetOnOffStr(m_MeleeEnabled));
|
reader.PSendSysMessage(LANG_NPC_EVENTAI_COMBAT, reader.GetOnOffStr(m_MeleeEnabled));
|
||||||
|
|
||||||
if (sLog.HasLogFilter(LOG_FILTER_EVENT_AI_DEV)) // Give some more details if in EventAI Dev Mode
|
if (sLog.HasLogFilter(LOG_FILTER_EVENT_AI_DEV)) // Give some more details if in EventAI Dev Mode
|
||||||
@ -627,6 +627,8 @@ 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)))
|
||||||
{
|
{
|
||||||
spellId = action.cast.spellId;
|
spellId = action.cast.spellId;
|
||||||
@ -646,19 +648,40 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
|
|||||||
switch (castResult)
|
switch (castResult)
|
||||||
{
|
{
|
||||||
case CAST_FAIL_POWER:
|
case CAST_FAIL_POWER:
|
||||||
case CAST_FAIL_TOO_FAR:
|
cmFlags |= COMBAT_MOVEMENT_OOM;
|
||||||
case CAST_FAIL_NO_LOS:
|
break;
|
||||||
{
|
case CAST_FAIL_TOO_FAR:
|
||||||
// Melee current victim if flag not set
|
cmFlags |= COMBAT_MOVEMENT_DISTANCE;
|
||||||
if (!(action.cast.castFlags & CAST_NO_MELEE_IF_OOM))
|
break;
|
||||||
{
|
case CAST_FAIL_NO_LOS:
|
||||||
SetCombatMovement(true,true);
|
cmFlags |= COMBAT_MOVEMENT_LOS;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break;
|
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
|
||||||
@ -744,12 +767,21 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
|
|||||||
break;
|
break;
|
||||||
case ACTION_T_COMBAT_MOVEMENT: //21
|
case ACTION_T_COMBAT_MOVEMENT: //21
|
||||||
// ignore no affect case
|
// ignore no affect case
|
||||||
if (m_isCombatMovement == (action.combat_movement.state != 0) || m_creature->IsNonMeleeSpellCasted(false))
|
if (IsCombatMovement() == (action.combat_movement.state != 0) || m_creature->IsNonMeleeSpellCasted(false))
|
||||||
{ return; }
|
{
|
||||||
|
if (IsCombatMovement())
|
||||||
|
{ AddCombatMovementFlags(COMBAT_MOVEMENT_SCRIPT); }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SetCombatMovement(action.combat_movement.state != 0, true);
|
if (action.combat_movement.state != 0)
|
||||||
|
{ AddCombatMovementFlags(COMBAT_MOVEMENT_SCRIPT); }
|
||||||
|
else
|
||||||
|
{ ClearCombatMovementFlags(COMBAT_MOVEMENT_SCRIPT); }
|
||||||
|
|
||||||
|
SetCombatMovement(IsCombatMovement(), true);
|
||||||
|
|
||||||
if (m_isCombatMovement && action.combat_movement.melee && m_creature->IsInCombat() && m_creature->getVictim())
|
if (IsCombatMovement() && action.combat_movement.melee && m_creature->IsInCombat() && m_creature->getVictim())
|
||||||
{ m_creature->SendMeleeAttackStart(m_creature->getVictim()); }
|
{ m_creature->SendMeleeAttackStart(m_creature->getVictim()); }
|
||||||
else if (action.combat_movement.melee && m_creature->IsInCombat() && m_creature->getVictim())
|
else if (action.combat_movement.melee && m_creature->IsInCombat() && m_creature->getVictim())
|
||||||
{ m_creature->SendMeleeAttackStop(m_creature->getVictim()); }
|
{ m_creature->SendMeleeAttackStop(m_creature->getVictim()); }
|
||||||
@ -805,7 +837,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
|
|||||||
m_attackDistance = (float)action.ranged_movement.distance;
|
m_attackDistance = (float)action.ranged_movement.distance;
|
||||||
m_attackAngle = action.ranged_movement.angle / 180.0f * M_PI_F;
|
m_attackAngle = action.ranged_movement.angle / 180.0f * M_PI_F;
|
||||||
|
|
||||||
if (m_isCombatMovement)
|
if (IsCombatMovement())
|
||||||
{
|
{
|
||||||
if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
|
if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == CHASE_MOTION_TYPE)
|
||||||
{
|
{
|
||||||
|
@ -2996,6 +2996,16 @@ void Spell::update(uint32 difftime)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_targets.getUnitTarget() && (m_targets.getUnitTarget() != m_caster) && IsSingleTargetSpell(m_spellInfo) &&
|
||||||
|
!IsNextMeleeSwingSpell() && !IsAutoRepeat() && !m_IsTriggeredSpell)
|
||||||
|
{
|
||||||
|
if (!m_caster->IsWithinLOSInMap(m_targets.getUnitTarget()))
|
||||||
|
{
|
||||||
|
cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check if the player or unit caster has moved before the spell finished (exclude casting on vehicles)
|
// check if the player or unit caster has moved before the spell finished (exclude casting on vehicles)
|
||||||
if (((m_caster->GetTypeId() == TYPEID_PLAYER || m_caster->GetTypeId() == TYPEID_UNIT) && m_timer != 0) &&
|
if (((m_caster->GetTypeId() == TYPEID_PLAYER || m_caster->GetTypeId() == TYPEID_UNIT) && m_timer != 0) &&
|
||||||
(m_castPositionX != m_caster->GetPositionX() || m_castPositionY != m_caster->GetPositionY() || m_castPositionZ != m_caster->GetPositionZ()) &&
|
(m_castPositionX != m_caster->GetPositionX() || m_castPositionY != m_caster->GetPositionY() || m_castPositionZ != m_caster->GetPositionZ()) &&
|
||||||
|
Loading…
x
Reference in New Issue
Block a user