mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Core/ScriptSystem/SpellScripts: Runtime checks for functions working only during spell hit phase
--HG-- branch : trunk
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user