Core/ScriptSystem/SpellScripts: Runtime checks for functions working only during spell hit phase

--HG--
branch : trunk
This commit is contained in:
QAston
2010-10-04 19:12:20 +02:00
parent caaa77deb2
commit 69057dcaeb
3 changed files with 87 additions and 137 deletions

View File

@@ -4857,7 +4857,6 @@ SpellCastResult Spell::CheckCast(bool strict)
}
else if (m_caster == target)
{
if (m_caster->GetTypeId() == TYPEID_PLAYER) // Target - is player caster
{
// Additional check for some spells
@@ -5005,141 +5004,6 @@ SpellCastResult Spell::CheckCast(bool strict)
return castResult;
}
/*//ImpliciteTargetA-B = 38, If fact there is 0 Spell with ImpliciteTargetB=38
if (m_UniqueTargetInfo.empty()) // skip second CheckCast apply (for delayed spells for example)
{
for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
{
if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_UNIT_NEARBY_ENTRY ||
m_spellInfo->EffectImplicitTargetB[j] == TARGET_UNIT_NEARBY_ENTRY && m_spellInfo->EffectImplicitTargetA[j] != TARGET_UNIT_CASTER ||
m_spellInfo->EffectImplicitTargetA[j] == TARGET_DST_NEARBY_ENTRY ||
m_spellInfo->EffectImplicitTargetB[j] == TARGET_DST_NEARBY_ENTRY)
{
SpellScriptTarget::const_iterator lower = sSpellMgr.GetBeginSpellScriptTarget(m_spellInfo->Id);
SpellScriptTarget::const_iterator upper = sSpellMgr.GetEndSpellScriptTarget(m_spellInfo->Id);
if (lower == upper)
sLog.outErrorDb("Spell (ID: %u) has effect EffectImplicitTargetA/EffectImplicitTargetB = TARGET_UNIT_NEARBY_ENTRY or TARGET_DST_NEARBY_ENTRY, but does not have record in `spell_script_target`",m_spellInfo->Id);
SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex);
float range = GetSpellMaxRange(srange);
Creature* creatureScriptTarget = NULL;
GameObject* goScriptTarget = NULL;
for (SpellScriptTarget::const_iterator i_spellST = bounds.first; i_spellST != bounds.second; ++i_spellST)
{
switch(i_spellST->second.type)
{
case SPELL_TARGET_TYPE_GAMEOBJECT:
{
GameObject* p_GameObject = NULL;
if (i_spellST->second.targetEntry)
{
CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
Cell cell(p);
cell.data.Part.reserved = ALL_DISTRICT;
Trinity::NearestGameObjectEntryInObjectRangeCheck go_check(*m_caster,i_spellST->second.targetEntry,range);
Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> checker(m_caster, p_GameObject,go_check);
TypeContainerVisitor<Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck>, GridTypeMapContainer > object_checker(checker);
CellLock<GridReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, object_checker, *m_caster->GetMap());
if (p_GameObject)
{
// remember found target and range, next attempt will find more near target with another entry
creatureScriptTarget = NULL;
goScriptTarget = p_GameObject;
range = go_check.GetLastRange();
}
}
else if (focusObject) // Focus Object
{
float frange = m_caster->GetDistance(focusObject);
if (range >= frange)
{
creatureScriptTarget = NULL;
goScriptTarget = focusObject;
range = frange;
}
}
break;
}
case SPELL_TARGET_TYPE_CREATURE:
case SPELL_TARGET_TYPE_DEAD:
default:
{
Creature *p_Creature = NULL;
CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
Cell cell(p);
cell.data.Part.reserved = ALL_DISTRICT;
cell.SetNoCreate(); // Really don't know what is that???
Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster,i_spellST->second.targetEntry,i_spellST->second.type != SPELL_TARGET_TYPE_DEAD,range);
Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(m_caster, p_Creature, u_check);
TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer > grid_creature_searcher(searcher);
CellLock<GridReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, grid_creature_searcher, *m_caster->GetMap(), *m_caster, range);
if (p_Creature)
{
creatureScriptTarget = p_Creature;
goScriptTarget = NULL;
range = u_check.GetLastRange();
}
break;
}
}
}
if (creatureScriptTarget)
{
// store coordinates for TARGET_DST_NEARBY_ENTRY
if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_DST_NEARBY_ENTRY ||
m_spellInfo->EffectImplicitTargetB[j] == TARGET_DST_NEARBY_ENTRY)
{
m_targets.setDst(creatureScriptTarget->GetPositionX(),creatureScriptTarget->GetPositionY(),creatureScriptTarget->GetPositionZ());
if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_DST_NEARBY_ENTRY && m_spellInfo->EffectImplicitTargetB[j] == 0 && m_spellInfo->Effect[j] != SPELL_EFFECT_PERSISTENT_AREA_AURA)
AddUnitTarget(creatureScriptTarget, j);
}
// store explicit target for TARGET_UNIT_NEARBY_ENTRY
else
AddUnitTarget(creatureScriptTarget, j);
}
else if (goScriptTarget)
{
// store coordinates for TARGET_DST_NEARBY_ENTRY
if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_DST_NEARBY_ENTRY ||
m_spellInfo->EffectImplicitTargetB[j] == TARGET_DST_NEARBY_ENTRY)
{
m_targets.setDst(goScriptTarget->GetPositionX(),goScriptTarget->GetPositionY(),goScriptTarget->GetPositionZ());
if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_DST_NEARBY_ENTRY && m_spellInfo->EffectImplicitTargetB[j] == 0 && m_spellInfo->Effect[j] != SPELL_EFFECT_PERSISTENT_AREA_AURA)
AddGOTarget(goScriptTarget, j);
}
// store explicit target for TARGET_UNIT_NEARBY_ENTRY
else
AddGOTarget(goScriptTarget, j);
}
//Missing DB Entry or targets for this spellEffect.
else
{
// not report target not existence for triggered spells
if (m_triggeredByAuraSpell || m_IsTriggeredSpell)
return SPELL_FAILED_DONT_REPORT;
else
return SPELL_FAILED_BAD_TARGETS;
}
}
}
}*/
if (!m_IsTriggeredSpell)
{
SpellCastResult castResult = CheckRange(strict);

View File

@@ -219,11 +219,21 @@ WorldLocation * SpellScript::GetDest()
Unit * SpellScript::GetHitUnit()
{
if (!IsInHitPhase())
{
sLog.outError("TSCR: Script: `%s` Spell: `%u`: function SpellScript::GetHitUnit was called while spell not in hit phase!", m_scriptName, m_scriptSpellId);
return NULL;
}
return m_spell->unitTarget;
}
Creature * SpellScript::GetHitCreature()
{
if (!IsInHitPhase())
{
sLog.outError("TSCR: Script: `%s` Spell: `%u`: function SpellScript::GetHitCreature was called while spell not in hit phase!", m_scriptName, m_scriptSpellId);
return NULL;
}
if (m_spell->unitTarget)
return m_spell->unitTarget->ToCreature();
else
@@ -232,6 +242,11 @@ Creature * SpellScript::GetHitCreature()
Player * SpellScript::GetHitPlayer()
{
if (!IsInHitPhase())
{
sLog.outError("TSCR: Script: `%s` Spell: `%u`: function SpellScript::GetHitPlayer was called while spell not in hit phase!", m_scriptName, m_scriptSpellId);
return NULL;
}
if (m_spell->unitTarget)
return m_spell->unitTarget->ToPlayer();
else
@@ -240,36 +255,71 @@ Player * SpellScript::GetHitPlayer()
Item * SpellScript::GetHitItem()
{
if (!IsInHitPhase())
{
sLog.outError("TSCR: Script: `%s` Spell: `%u`: function SpellScript::GetHitItem was called while spell not in hit phase!", m_scriptName, m_scriptSpellId);
return NULL;
}
return m_spell->itemTarget;
}
GameObject * SpellScript::GetHitGObj()
{
if (!IsInHitPhase())
{
sLog.outError("TSCR: Script: `%s` Spell: `%u`: function SpellScript::GetHitGObj was called while spell not in hit phase!", m_scriptName, m_scriptSpellId);
return NULL;
}
return m_spell->gameObjTarget;
}
int32 SpellScript::GetHitDamage()
{
if (!IsInHitPhase())
{
sLog.outError("TSCR: Script: `%s` Spell: `%u`: function SpellScript::GetHitDamage was called while spell not in hit phase!", m_scriptName, m_scriptSpellId);
return NULL;
}
return m_spell->m_damage;
}
void SpellScript::SetHitDamage(int32 damage)
{
if (!IsInHitPhase())
{
sLog.outError("TSCR: Script: `%s` Spell: `%u`: function SpellScript::SetHitDamage was called while spell not in hit phase!", m_scriptName, m_scriptSpellId);
return;
}
m_spell->m_damage = damage;
}
int32 SpellScript::GetHitHeal()
{
if (!IsInHitPhase())
{
sLog.outError("TSCR: Script: `%s` Spell: `%u`: function SpellScript::GetHitHeal was called while spell not in hit phase!", m_scriptName, m_scriptSpellId);
return NULL;
}
return m_spell->m_healing;
}
void SpellScript::SetHitHeal(int32 heal)
{
if (!IsInHitPhase())
{
sLog.outError("TSCR: Script: `%s` Spell: `%u`: function SpellScript::SetHitHeal was called while spell not in hit phase!", m_scriptName, m_scriptSpellId);
return;
}
m_spell->m_healing = heal;
}
Aura* SpellScript::GetHitAura()
{
if (!IsInHitPhase())
{
sLog.outError("TSCR: Script: `%s` Spell: `%u`: function SpellScript::GetHitAura was called while spell not in hit phase!", m_scriptName, m_scriptSpellId);
return NULL;
}
if (!m_spell->m_spellAura)
return NULL;
if (m_spell->m_spellAura->IsRemoved())
@@ -279,23 +329,43 @@ Aura* SpellScript::GetHitAura()
void SpellScript::PreventHitAura()
{
if (!IsInHitPhase())
{
sLog.outError("TSCR: Script: `%s` Spell: `%u`: function SpellScript::PreventHitAura was called while spell not in hit phase!", m_scriptName, m_scriptSpellId);
return;
}
if (m_spell->m_spellAura)
m_spell->m_spellAura->Remove();
}
void SpellScript::PreventHitEffect(SpellEffIndex effIndex)
{
if (!IsInHitPhase())
{
sLog.outError("TSCR: Script: `%s` Spell: `%u`: function SpellScript::PreventHitEffect was called while spell not in hit phase!", m_scriptName, m_scriptSpellId);
return;
}
m_hitPreventEffectMask |= 1 << effIndex;
PreventHitDefaultEffect(effIndex);
}
void SpellScript::PreventHitDefaultEffect(SpellEffIndex effIndex)
{
if (!IsInHitPhase())
{
sLog.outError("TSCR: Script: `%s` Spell: `%u`: function SpellScript::PreventHitDefaultEffect was called while spell not in hit phase!", m_scriptName, m_scriptSpellId);
return;
}
m_hitPreventDefaultEffectMask |= 1 << effIndex;
}
int32 SpellScript::GetEffectValue()
{
if (!IsInEffectHook())
{
sLog.outError("TSCR: Script: `%s` Spell: `%u`: function SpellScript::PreventHitDefaultEffect was called while spell not in hit phase!", m_scriptName, m_scriptSpellId);
return 0;
}
return m_spell->damage;
}

View File

@@ -113,6 +113,20 @@ class _SpellScript
virtual void Unload() {};
};
// SpellScript interface - enum used for runtime checks of script function calls
enum SpellScriptHookType
{
SPELL_SCRIPT_HOOK_EFFECT = SPELL_SCRIPT_STATE_END,
SPELL_SCRIPT_HOOK_BEFORE_HIT,
SPELL_SCRIPT_HOOK_HIT,
SPELL_SCRIPT_HOOK_AFTER_HIT,
};
#define HOOK_SPELL_HIT_START SPELL_SCRIPT_HOOK_EFFECT
#define HOOK_SPELL_HIT_END SPELL_SCRIPT_HOOK_AFTER_HIT + 1
#define HOOK_SPELL_START SPELL_SCRIPT_HOOK_EFFECT
#define HOOK_SPELL_END SPELL_SCRIPT_HOOK_AFTER_HIT + 1
#define HOOK_SPELL_COUNT HOOK_SPELL_END - HOOK_SPELL_START
class SpellScript : public _SpellScript
{
// internal use classes & functions
@@ -138,6 +152,8 @@ class SpellScript : public _SpellScript
void _InitHit();
bool _IsEffectPrevented(SpellEffIndex effIndex) {return m_hitPreventEffectMask & (1<<effIndex);};
bool _IsDefaultEffectPrevented(SpellEffIndex effIndex) {return m_hitPreventDefaultEffectMask & (1<<effIndex);};
bool IsInHitPhase() { return (m_currentScriptState >= HOOK_SPELL_HIT_START && m_currentScriptState < HOOK_SPELL_HIT_END); };
bool IsInEffectHook() { return (m_currentScriptState == SPELL_SCRIPT_HOOK_EFFECT); };
private:
Spell * m_spell;
uint8 m_hitPreventEffectMask;
@@ -226,7 +242,7 @@ class SpellScript : public _SpellScript
void CreateItem(uint32 effIndex, uint32 itemId);
};
// AuraScript interface - enum used for manipulations on hooks by their type
// AuraScript interface - enum used for runtime checks of script function calls
enum AuraScriptHookType
{
AURA_SCRIPT_HOOK_EFFECT_APPLY = SPELL_SCRIPT_STATE_END,