*Allow channeled spells to be casted on dead target
*Define relted spell attributes --HG-- branch : trunk
This commit is contained in:
@@ -823,6 +823,11 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond)
|
||||
"TARGET_GAMEOBJECT_AREA_SRC(51), TARGET_GAMEOBJECT_AREA_DST(52)", cond->mSourceEntry);
|
||||
return false;
|
||||
}
|
||||
if ((cond->mConditionValue1 == SPELL_TARGET_TYPE_DEAD) && !IsAllowingDeadTargetSpell(spellProto))
|
||||
{
|
||||
sLog.outErrorDb("SourceEntry %u in `condition` table does have SPELL_TARGET_TYPE_DEAD specified but spell does not have SPELL_ATTR_EX2_ALLOW_DEAD_TARGET", cond->mSourceEntry);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONDITION_SOURCE_TYPE_CREATURE_TEMPLATE_VEHICLE:
|
||||
|
||||
@@ -16388,6 +16388,8 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
|
||||
// Do now before stats re-calculation cleanup for ghost state unexpected auras
|
||||
if (!isAlive())
|
||||
RemoveAllAurasOnDeath();
|
||||
else
|
||||
RemoveAllAurasRequiringDeadTarget();
|
||||
|
||||
//apply all stat bonuses from items and auras
|
||||
SetCanModifyStats(true);
|
||||
|
||||
@@ -12504,8 +12504,9 @@ void Unit::setDeathState(DeathState s)
|
||||
|
||||
if (oldDeathState != ALIVE && s == ALIVE)
|
||||
{
|
||||
//_ApplyAllAuraMods();
|
||||
// Reset display id on resurection - needed by corpse explosion to cleanup after display change
|
||||
// TODO: fix this
|
||||
if (!HasAuraType(SPELL_AURA_TRANSFORM))
|
||||
SetDisplayId(GetNativeDisplayId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1609,6 +1609,7 @@ class Unit : public WorldObject
|
||||
void RemoveAllAuras();
|
||||
void RemoveArenaAuras(bool onleave = false);
|
||||
void RemoveAllAurasOnDeath();
|
||||
void RemoveAllAurasRequiringDeadTarget();
|
||||
void DelayOwnedAuras(uint32 spellId, uint64 caster, int32 delaytime);
|
||||
|
||||
void _RemoveAllAuraStatMods();
|
||||
|
||||
@@ -323,7 +323,7 @@ const uint32 ItemQualityColors[MAX_ITEM_QUALITY] = {
|
||||
#define SPELL_ATTR_EX_ENABLE_AT_DODGE 0x40000000 // 30 Overpower, Wolverine Bite
|
||||
#define SPELL_ATTR_EX_UNK31 0x80000000 // 31
|
||||
|
||||
#define SPELL_ATTR_EX2_UNK0 0x00000001 // 0
|
||||
#define SPELL_ATTR_EX2_ALLOW_DEAD_TARGET 0x00000001 // 0
|
||||
#define SPELL_ATTR_EX2_UNK1 0x00000002 // 1 ? many triggered spells have this flag
|
||||
#define SPELL_ATTR_EX2_CANT_REFLECTED 0x00000004 // 2 ? used for detect can or not spell reflected
|
||||
#define SPELL_ATTR_EX2_UNK3 0x00000008 // 3
|
||||
@@ -368,7 +368,7 @@ const uint32 ItemQualityColors[MAX_ITEM_QUALITY] = {
|
||||
#define SPELL_ATTR_EX3_TRIGGERED_CAN_TRIGGER_2 0x00000200 // 9 triggered from effect?
|
||||
#define SPELL_ATTR_EX3_MAIN_HAND 0x00000400 // 10 Main hand weapon required
|
||||
#define SPELL_ATTR_EX3_BATTLEGROUND 0x00000800 // 11 Can casted only on battleground
|
||||
#define SPELL_ATTR_EX3_UNK12 0x00001000 // 12
|
||||
#define SPELL_ATTR_EX3_REQUIRE_DEAD_TARGET 0x00001000 // 12
|
||||
#define SPELL_ATTR_EX3_UNK13 0x00002000 // 13
|
||||
#define SPELL_ATTR_EX3_UNK14 0x00004000 // 14 "Honorless Target" only this spells have this flag
|
||||
#define SPELL_ATTR_EX3_UNK15 0x00008000 // 15 Auto Shoot, Shoot, Throw, - this is autoshot flag
|
||||
|
||||
@@ -1244,15 +1244,6 @@ void AuraEffect::SendTickImmune(Unit * target, Unit *caster) const
|
||||
|
||||
void AuraEffect::PeriodicTick(Unit * target, Unit * caster) const
|
||||
{
|
||||
if (!target->isAlive())
|
||||
return;
|
||||
|
||||
if (target->hasUnitState(UNIT_STAT_ISOLATED))
|
||||
{
|
||||
SendTickImmune(target, caster);
|
||||
return;
|
||||
}
|
||||
|
||||
bool prevented = GetBase()->CallScriptEffectPeriodicHandlers(const_cast<AuraEffect const *>(this), GetBase()->GetApplicationOfTarget(target->GetGUID()));
|
||||
if (prevented)
|
||||
return;
|
||||
@@ -1265,6 +1256,15 @@ void AuraEffect::PeriodicTick(Unit * target, Unit * caster) const
|
||||
if (!caster)
|
||||
break;
|
||||
|
||||
if (!target->isAlive())
|
||||
return;
|
||||
|
||||
if (target->hasUnitState(UNIT_STAT_ISOLATED))
|
||||
{
|
||||
SendTickImmune(target, caster);
|
||||
return;
|
||||
}
|
||||
|
||||
// Consecrate ticks can miss and will not show up in the combat log
|
||||
if (GetSpellProto()->Effect[GetEffIndex()] == SPELL_EFFECT_PERSISTENT_AREA_AURA &&
|
||||
caster->SpellHitResult(target,GetSpellProto(),false) != SPELL_MISS_NONE)
|
||||
@@ -1405,6 +1405,15 @@ void AuraEffect::PeriodicTick(Unit * target, Unit * caster) const
|
||||
if (!caster->isAlive())
|
||||
return;
|
||||
|
||||
if (!target->isAlive())
|
||||
return;
|
||||
|
||||
if (target->hasUnitState(UNIT_STAT_ISOLATED))
|
||||
{
|
||||
SendTickImmune(target, caster);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetSpellProto()->Effect[GetEffIndex()] == SPELL_EFFECT_PERSISTENT_AREA_AURA &&
|
||||
caster->SpellHitResult(target,GetSpellProto(),false) != SPELL_MISS_NONE)
|
||||
return;
|
||||
@@ -1485,6 +1494,15 @@ void AuraEffect::PeriodicTick(Unit * target, Unit * caster) const
|
||||
if (!caster || !caster->GetHealth())
|
||||
break;
|
||||
|
||||
if (!target->isAlive())
|
||||
return;
|
||||
|
||||
if (target->hasUnitState(UNIT_STAT_ISOLATED))
|
||||
{
|
||||
SendTickImmune(target, caster);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 damage = GetAmount();
|
||||
// do not kill health donator
|
||||
if (caster->GetHealth() < damage)
|
||||
@@ -1509,6 +1527,15 @@ void AuraEffect::PeriodicTick(Unit * target, Unit * caster) const
|
||||
if (!caster)
|
||||
break;
|
||||
|
||||
if (!target->isAlive())
|
||||
return;
|
||||
|
||||
if (target->hasUnitState(UNIT_STAT_ISOLATED))
|
||||
{
|
||||
SendTickImmune(target, caster);
|
||||
return;
|
||||
}
|
||||
|
||||
// heal for caster damage (must be alive)
|
||||
if (target != caster && GetSpellProto()->AttributesEx2 & SPELL_ATTR_EX2_HEALTH_FUNNEL && !caster->isAlive())
|
||||
break;
|
||||
@@ -1607,6 +1634,15 @@ void AuraEffect::PeriodicTick(Unit * target, Unit * caster) const
|
||||
if (GetMiscValue() < 0 || GetMiscValue() >= int8(MAX_POWERS))
|
||||
break;
|
||||
|
||||
if (!target->isAlive())
|
||||
return;
|
||||
|
||||
if (target->hasUnitState(UNIT_STAT_ISOLATED))
|
||||
{
|
||||
SendTickImmune(target, caster);
|
||||
return;
|
||||
}
|
||||
|
||||
Powers power = Powers(GetMiscValue());
|
||||
|
||||
// power type might have changed between aura applying and tick (druid's shapeshift)
|
||||
@@ -1711,6 +1747,15 @@ void AuraEffect::PeriodicTick(Unit * target, Unit * caster) const
|
||||
if (GetMiscValue() < 0)
|
||||
return;
|
||||
|
||||
if (!target->isAlive())
|
||||
return;
|
||||
|
||||
if (target->hasUnitState(UNIT_STAT_ISOLATED))
|
||||
{
|
||||
SendTickImmune(target, caster);
|
||||
return;
|
||||
}
|
||||
|
||||
Powers power;
|
||||
if (GetMiscValue() == POWER_ALL)
|
||||
power = target->getPowerType();
|
||||
@@ -1742,6 +1787,15 @@ void AuraEffect::PeriodicTick(Unit * target, Unit * caster) const
|
||||
if (m_amount < 0 || GetMiscValue() >= int8(MAX_POWERS))
|
||||
return;
|
||||
|
||||
if (!target->isAlive())
|
||||
return;
|
||||
|
||||
if (target->hasUnitState(UNIT_STAT_ISOLATED))
|
||||
{
|
||||
SendTickImmune(target, caster);
|
||||
return;
|
||||
}
|
||||
|
||||
Powers power = Powers(GetMiscValue());
|
||||
|
||||
if (target->GetMaxPower(power) == 0)
|
||||
@@ -1769,6 +1823,15 @@ void AuraEffect::PeriodicTick(Unit * target, Unit * caster) const
|
||||
if (!caster)
|
||||
return;
|
||||
|
||||
if (!target->isAlive())
|
||||
return;
|
||||
|
||||
if (target->hasUnitState(UNIT_STAT_ISOLATED))
|
||||
{
|
||||
SendTickImmune(target, caster);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for immune (not use charges)
|
||||
if (target->IsImmunedToDamage(GetSpellProto()))
|
||||
{
|
||||
|
||||
@@ -507,7 +507,7 @@ m_caster(Caster), m_spellValue(new SpellValue(m_spellInfo))
|
||||
m_casttime = 0; // setup to correct value in Spell::prepare, don't must be used before.
|
||||
m_timer = 0; // will set to castime in prepare
|
||||
|
||||
m_needAliveTargetMask = 0;
|
||||
m_channelTargetEffectMask = 0;
|
||||
|
||||
// determine reflection
|
||||
m_canReflect = false;
|
||||
@@ -789,7 +789,7 @@ void Spell::SelectSpellTargets()
|
||||
{
|
||||
if (ihit->effectMask & mask)
|
||||
{
|
||||
m_needAliveTargetMask |= mask;
|
||||
m_channelTargetEffectMask |= mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1682,19 +1682,19 @@ void Spell::DoAllEffectOnTarget(ItemTargetInfo *target)
|
||||
bool Spell::UpdateChanneledTargetList()
|
||||
{
|
||||
// Not need check return true
|
||||
if (m_needAliveTargetMask == 0)
|
||||
if (m_channelTargetEffectMask == 0)
|
||||
return true;
|
||||
|
||||
uint8 needAliveTargetMask = m_needAliveTargetMask;
|
||||
uint8 needAuraMask = 0;
|
||||
uint8 channelTargetEffectMask = m_channelTargetEffectMask;
|
||||
uint8 channelAuraMask = 0;
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
if (m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA)
|
||||
needAuraMask |= 1<<i;
|
||||
channelAuraMask |= 1<<i;
|
||||
|
||||
needAuraMask &= needAliveTargetMask;
|
||||
channelAuraMask &= channelTargetEffectMask;
|
||||
|
||||
float range = 0;
|
||||
if (needAuraMask)
|
||||
if (channelAuraMask)
|
||||
{
|
||||
range = GetSpellMaxRange(m_spellInfo, IsPositiveSpell(m_spellInfo->Id));
|
||||
if (Player * modOwner = m_caster->GetSpellModOwner())
|
||||
@@ -1703,13 +1703,16 @@ bool Spell::UpdateChanneledTargetList()
|
||||
|
||||
for (std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
|
||||
{
|
||||
if (ihit->missCondition == SPELL_MISS_NONE && (needAliveTargetMask & ihit->effectMask))
|
||||
if (ihit->missCondition == SPELL_MISS_NONE && (channelTargetEffectMask & ihit->effectMask))
|
||||
{
|
||||
Unit *unit = m_caster->GetGUID() == ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);
|
||||
|
||||
if (unit && unit->isAlive())
|
||||
if (!unit)
|
||||
continue;
|
||||
|
||||
if (IsValidDeadOrAliveTarget(unit))
|
||||
{
|
||||
if (needAuraMask & ihit->effectMask)
|
||||
if (channelAuraMask & ihit->effectMask)
|
||||
{
|
||||
if (AuraApplication * aurApp = unit->GetAuraApplication(m_spellInfo->Id, m_originalCasterGUID))
|
||||
{
|
||||
@@ -1724,13 +1727,13 @@ bool Spell::UpdateChanneledTargetList()
|
||||
continue;
|
||||
}
|
||||
|
||||
needAliveTargetMask &= ~ihit->effectMask; // remove from need alive mask effect that have alive target
|
||||
channelTargetEffectMask &= ~ihit->effectMask; // remove from need alive mask effect that have alive target
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// is all effects from m_needAliveTargetMask have alive targets
|
||||
return needAliveTargetMask == 0;
|
||||
return channelTargetEffectMask == 0;
|
||||
}
|
||||
|
||||
// Helper for Chain Healing
|
||||
@@ -4092,7 +4095,7 @@ void Spell::WriteSpellGoTargets(WorldPacket * data)
|
||||
if ((*ihit).missCondition == SPELL_MISS_NONE) // Add only hits
|
||||
{
|
||||
*data << uint64(ihit->targetGUID);
|
||||
m_needAliveTargetMask |=ihit->effectMask;
|
||||
m_channelTargetEffectMask |=ihit->effectMask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4112,7 +4115,7 @@ void Spell::WriteSpellGoTargets(WorldPacket * data)
|
||||
}
|
||||
// Reset m_needAliveTargetMask for non channeled spell
|
||||
if (!IsChanneledSpell(m_spellInfo))
|
||||
m_needAliveTargetMask = 0;
|
||||
m_channelTargetEffectMask = 0;
|
||||
}
|
||||
|
||||
void Spell::SendLogExecute()
|
||||
@@ -6915,6 +6918,15 @@ bool Spell::IsValidSingleTargetSpell(Unit const* target) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Spell::IsValidDeadOrAliveTarget(Unit const* target) const
|
||||
{
|
||||
if (target->isAlive())
|
||||
return !IsRequiringDeadTargetSpell(m_spellInfo);
|
||||
if (IsAllowingDeadTargetSpell(m_spellInfo))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Spell::CalculateDamageDoneForAllTargets()
|
||||
{
|
||||
float multiplier[MAX_SPELL_EFFECTS];
|
||||
|
||||
@@ -631,7 +631,7 @@ class Spell
|
||||
int32 damage;
|
||||
};
|
||||
std::list<TargetInfo> m_UniqueTargetInfo;
|
||||
uint8 m_needAliveTargetMask; // Mask req. alive targets
|
||||
uint8 m_channelTargetEffectMask; // Mask req. alive targets
|
||||
|
||||
struct GOTargetInfo
|
||||
{
|
||||
@@ -666,6 +666,7 @@ class Spell
|
||||
WorldObject* SearchNearbyTarget(float range, SpellTargets TargetType);
|
||||
bool IsValidSingleTargetEffect(Unit const* target, Targets type) const;
|
||||
bool IsValidSingleTargetSpell(Unit const* target) const;
|
||||
bool IsValidDeadOrAliveTarget(Unit const* target) const;
|
||||
void CalculateDamageDoneForAllTargets();
|
||||
int32 CalculateDamageDone(Unit *unit, const uint32 effectMask, float *multiplier);
|
||||
void SpellDamageSchoolDmg(SpellEffIndex effIndex);
|
||||
|
||||
@@ -322,6 +322,21 @@ inline bool IsDeathPersistentSpell(SpellEntry const *spellInfo)
|
||||
return spellInfo->AttributesEx3 & SPELL_ATTR_EX3_DEATH_PERSISTENT;
|
||||
}
|
||||
|
||||
inline bool IsRequiringDeadTargetSpell(SpellEntry const *spellInfo)
|
||||
{
|
||||
return spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQUIRE_DEAD_TARGET;
|
||||
}
|
||||
|
||||
inline bool IsAllowingDeadTargetSpell(SpellEntry const *spellInfo)
|
||||
{
|
||||
return spellInfo->AttributesEx2 & SPELL_ATTR_EX2_ALLOW_DEAD_TARGET;
|
||||
}
|
||||
|
||||
inline bool IsDeadTargetSpell(SpellEntry const *spellInfo)
|
||||
{
|
||||
return IsAllowingDeadTargetSpell(spellInfo) || IsRequiringDeadTargetSpell(spellInfo);
|
||||
}
|
||||
|
||||
inline bool IsNonCombatSpell(SpellEntry const *spellInfo)
|
||||
{
|
||||
return (spellInfo->Attributes & SPELL_ATTR_CANT_USED_IN_COMBAT) != 0;
|
||||
|
||||
Reference in New Issue
Block a user