[9062] Implement two helper-functions for casting spell in creatureAI.

Function will return a cast result, with fail reasons if spell can not be casted (can be used to take alternative action). Please note this is not a full list of cast fail errors/reasons, but will cover a few basic errors that may occur.
The virtual function CanCastSpell() may be adjusted for custom needs from script library if not the default is sufficient.

Signed-off-by: NoFantasy <nofantasy@nf.no>
This commit is contained in:
NoFantasy 2009-12-25 13:03:59 +01:00
parent 67dd48e2d4
commit f4c6cf7337
3 changed files with 104 additions and 1 deletions

View file

@ -28,3 +28,90 @@ void CreatureAI::AttackedBy( Unit* attacker )
if(!m_creature->getVictim())
AttackStart(attacker);
}
CanCastResult CreatureAI::CanCastSpell(Unit* pTarget, const SpellEntry *pSpell, bool isTriggered)
{
// If not triggered, we check
if (!isTriggered)
{
// State does not allow
if (m_creature->hasUnitState(UNIT_STAT_CONFUSED | UNIT_STAT_STUNNED | UNIT_STAT_FLEEING | UNIT_STAT_DIED))
return CAST_FAIL_STATE;
if (pSpell->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
return CAST_FAIL_STATE;
if (pSpell->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED))
return CAST_FAIL_STATE;
// Check for power (also done by Spell::CheckCast())
if (m_creature->GetPower((Powers)pSpell->powerType) < pSpell->manaCost)
return CAST_FAIL_POWER;
}
if (const SpellRangeEntry *pSpellRange = sSpellRangeStore.LookupEntry(pSpell->rangeIndex))
{
if (pTarget != m_creature)
{
// pTarget is out of range of this spell (also done by Spell::CheckCast())
float fDistance = m_creature->GetCombatDistance(pTarget);
if (fDistance > (m_creature->IsHostileTo(pTarget) ? pSpellRange->maxRange : pSpellRange->maxRangeFriendly))
return CAST_FAIL_TOO_FAR;
float fMinRange = m_creature->IsHostileTo(pTarget) ? pSpellRange->minRange : pSpellRange->minRangeFriendly;
if (fMinRange && fDistance < fMinRange)
return CAST_FAIL_TOO_CLOSE;
}
return CAST_OK;
}
else
return CAST_FAIL_OTHER;
}
CanCastResult CreatureAI::DoCastSpellIfCan(Unit* pTarget, uint32 uiSpell, uint32 uiCastFlags, uint64 uiOriginalCasterGUID)
{
Unit* pCaster = m_creature;
if (uiCastFlags & CAST_FORCE_TARGET_SELF)
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_INTURRUPT_PREVIOUS)))
{
if (const SpellEntry* pSpell = sSpellStore.LookupEntry(uiSpell))
{
// If cast flag CAST_AURA_NOT_PRESENT is active, check if target already has aura on them
if (uiCastFlags & CAST_AURA_NOT_PRESENT)
{
if (pTarget->HasAura(uiSpell))
return CAST_FAIL_TARGET_AURA;
}
// Check if cannot cast spell
if (!(uiCastFlags & (CAST_FORCE_TARGET_SELF | CAST_FORCE_CAST)))
{
CanCastResult castResult = CanCastSpell(pTarget, pSpell, uiCastFlags & CAST_TRIGGERED);
if (castResult != CAST_OK)
return castResult;
}
// Interrupt any previous spell
if (uiCastFlags & CAST_INTURRUPT_PREVIOUS && pCaster->IsNonMeleeSpellCasted(false))
pCaster->InterruptNonMeleeSpells(false);
pCaster->CastSpell(pTarget, pSpell, uiCastFlags & CAST_TRIGGERED, NULL, NULL, uiOriginalCasterGUID);
return CAST_OK;
}
else
{
sLog.outErrorDb("DoCastSpellIfCan by creature entry %u attempt to cast spell %u but spell does not exist.", m_creature->GetEntry(), uiSpell);
return CAST_FAIL_OTHER;
}
}
else
return CAST_FAIL_IS_CASTING;
}