*Fix some bugs about chain spells. Will not hit the selected target twice. Will always hit the selected target as the first target.
--HG-- branch : trunk
This commit is contained in:
+66
-61
@@ -1330,55 +1330,45 @@ struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, Unit* pUnitTarget, float max_range, uint32 unMaxTargets)
|
void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, float max_range, uint32 num, SpellTargets TargetType)
|
||||||
{
|
{
|
||||||
if(!pUnitTarget)
|
Unit *cur = m_targets.getUnitTarget();
|
||||||
|
if(!cur)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//FIXME: This very like horrible hack and wrong for most spells
|
//FIXME: This very like horrible hack and wrong for most spells
|
||||||
if(m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE)
|
if(m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE)
|
||||||
max_range += unMaxTargets * CHAIN_SPELL_JUMP_RADIUS;
|
max_range += num * CHAIN_SPELL_JUMP_RADIUS;
|
||||||
|
|
||||||
std::list<Unit *> tempUnitMap;
|
std::list<Unit*> tempUnitMap;
|
||||||
Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(pUnitTarget, m_caster, max_range);
|
SearchAreaTarget(tempUnitMap, max_range, PUSH_TARGET_CENTER, TargetType);
|
||||||
Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(tempUnitMap, u_check);
|
tempUnitMap.remove(cur);
|
||||||
m_caster->VisitNearbyObject(max_range, searcher);
|
|
||||||
|
|
||||||
tempUnitMap.sort(TargetDistanceOrder(pUnitTarget));
|
while(num)
|
||||||
|
{
|
||||||
|
TagUnitMap.push_back(cur);
|
||||||
|
--num;
|
||||||
|
|
||||||
if(tempUnitMap.empty())
|
if(tempUnitMap.empty())
|
||||||
return;
|
|
||||||
|
|
||||||
uint32 t = unMaxTargets;
|
|
||||||
if(pUnitTarget != m_caster)
|
|
||||||
{
|
|
||||||
if(*tempUnitMap.begin() == pUnitTarget)
|
|
||||||
tempUnitMap.erase(tempUnitMap.begin());
|
|
||||||
TagUnitMap.push_back(pUnitTarget);
|
|
||||||
--t;
|
|
||||||
}
|
|
||||||
Unit *prev = pUnitTarget;
|
|
||||||
|
|
||||||
std::list<Unit*>::iterator next = tempUnitMap.begin();
|
|
||||||
|
|
||||||
while(t && next != tempUnitMap.end())
|
|
||||||
{
|
|
||||||
if(prev->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(!prev->IsWithinLOSInMap(*next)
|
tempUnitMap.sort(TargetDistanceOrder(cur));
|
||||||
|| m_spellInfo->DmgClass==SPELL_DAMAGE_CLASS_MELEE && !m_caster->isInFront(*next, max_range))
|
std::list<Unit*>::iterator next = tempUnitMap.begin();
|
||||||
|
|
||||||
|
if(cur->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS)
|
||||||
|
break;
|
||||||
|
|
||||||
|
while(!cur->IsWithinLOSInMap(*next)
|
||||||
|
|| m_spellInfo->DmgClass==SPELL_DAMAGE_CLASS_MELEE
|
||||||
|
&& !m_caster->isInFront(*next, max_range))
|
||||||
{
|
{
|
||||||
++next;
|
++next;
|
||||||
continue;
|
if(next == tempUnitMap.end())
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev = *next;
|
cur = *next;
|
||||||
TagUnitMap.push_back(prev);
|
|
||||||
tempUnitMap.erase(next);
|
tempUnitMap.erase(next);
|
||||||
tempUnitMap.sort(TargetDistanceOrder(prev));
|
|
||||||
next = tempUnitMap.begin();
|
|
||||||
--t;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1395,11 +1385,22 @@ void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, const u
|
|||||||
x = m_targets.m_destX;
|
x = m_targets.m_destX;
|
||||||
y = m_targets.m_destY;
|
y = m_targets.m_destY;
|
||||||
}
|
}
|
||||||
else
|
else if(type == PUSH_SELF_CENTER)
|
||||||
{
|
{
|
||||||
x = m_caster->GetPositionX();
|
x = m_caster->GetPositionX();
|
||||||
y = m_caster->GetPositionY();
|
y = m_caster->GetPositionY();
|
||||||
}
|
}
|
||||||
|
else if(type == PUSH_TARGET_CENTER)
|
||||||
|
{
|
||||||
|
Unit *target = m_targets.getUnitTarget();
|
||||||
|
if(!target)
|
||||||
|
{
|
||||||
|
sLog.outError( "SPELL: cannot find unit target for spell ID %u\n", m_spellInfo->Id );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
x = target->GetPositionX();
|
||||||
|
y = target->GetPositionY();
|
||||||
|
}
|
||||||
|
|
||||||
Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, type, TargetType, entry);
|
Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, type, TargetType, entry);
|
||||||
if((m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY)
|
if((m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY)
|
||||||
@@ -1431,13 +1432,13 @@ Unit* Spell::SearchNearbyTarget(float radius, SpellTargets TargetType, uint32 en
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
case SPELL_TARGETS_AOE_DAMAGE:
|
case SPELL_TARGETS_ENEMY:
|
||||||
{
|
{
|
||||||
Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, radius);
|
Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, radius);
|
||||||
Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(target, u_check);
|
Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(target, u_check);
|
||||||
m_caster->VisitNearbyObject(radius, searcher);
|
m_caster->VisitNearbyObject(radius, searcher);
|
||||||
}break;
|
}break;
|
||||||
case SPELL_TARGETS_FRIENDLY:
|
case SPELL_TARGETS_ALLY:
|
||||||
{
|
{
|
||||||
Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, radius);
|
Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, radius);
|
||||||
Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(target, u_check);
|
Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(target, u_check);
|
||||||
@@ -1531,13 +1532,10 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
|
|||||||
target->GetPartyMember(TagUnitMap, radius);
|
target->GetPartyMember(TagUnitMap, radius);
|
||||||
break;
|
break;
|
||||||
case TARGET_UNIT_TARGET_ENEMY:
|
case TARGET_UNIT_TARGET_ENEMY:
|
||||||
if(Unit* pUnitTarget = SelectMagnetTarget())
|
|
||||||
{
|
|
||||||
if(EffectChainTarget <= 1)
|
if(EffectChainTarget <= 1)
|
||||||
TagUnitMap.push_back(pUnitTarget);
|
TagUnitMap.push_back(SelectMagnetTarget());
|
||||||
else //TODO: chain target should also use magnet target
|
else if(SelectMagnetTarget()) //TODO: chain target should also use magnet target
|
||||||
SearchChainTarget(TagUnitMap, pUnitTarget, radius, EffectChainTarget);
|
SearchChainTarget(TagUnitMap, radius, EffectChainTarget, SPELL_TARGETS_ENEMY);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}break;
|
}break;
|
||||||
@@ -1584,12 +1582,12 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
|
|||||||
case TARGET_UNIT_AREA_ENEMY_GROUND:
|
case TARGET_UNIT_AREA_ENEMY_GROUND:
|
||||||
m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION;
|
m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION;
|
||||||
case TARGET_UNIT_AREA_ENEMY:
|
case TARGET_UNIT_AREA_ENEMY:
|
||||||
SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_AOE_DAMAGE);
|
SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_ENEMY);
|
||||||
break;
|
break;
|
||||||
case TARGET_UNIT_AREA_ALLY_GROUND:
|
case TARGET_UNIT_AREA_ALLY_GROUND:
|
||||||
m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION;
|
m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION;
|
||||||
case TARGET_UNIT_AREA_ALLY:
|
case TARGET_UNIT_AREA_ALLY:
|
||||||
SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_FRIENDLY);
|
SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_ALLY);
|
||||||
break;
|
break;
|
||||||
case TARGET_UNIT_AREA_PARTY_GROUND:
|
case TARGET_UNIT_AREA_PARTY_GROUND:
|
||||||
m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION;
|
m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION;
|
||||||
@@ -1604,7 +1602,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
|
|||||||
SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id);
|
SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id);
|
||||||
if(lower==upper)
|
if(lower==upper)
|
||||||
{
|
{
|
||||||
SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_AOE_DAMAGE);
|
SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_ENEMY);
|
||||||
sLog.outErrorDb("Spell (ID: %u) (caster Entry: %u) does not have record in `spell_script_target`", m_spellInfo->Id, m_caster->GetEntry());
|
sLog.outErrorDb("Spell (ID: %u) (caster Entry: %u) does not have record in `spell_script_target`", m_spellInfo->Id, m_caster->GetEntry());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1664,32 +1662,39 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
|
|||||||
case TARGET_IN_FRONT_OF_CASTER:
|
case TARGET_IN_FRONT_OF_CASTER:
|
||||||
case TARGET_UNIT_CONE_ENEMY_UNKNOWN:
|
case TARGET_UNIT_CONE_ENEMY_UNKNOWN:
|
||||||
if(m_customAttr & SPELL_ATTR_CU_CONE_BACK)
|
if(m_customAttr & SPELL_ATTR_CU_CONE_BACK)
|
||||||
SearchAreaTarget(TagUnitMap, radius, PUSH_IN_BACK, SPELL_TARGETS_AOE_DAMAGE);
|
SearchAreaTarget(TagUnitMap, radius, PUSH_IN_BACK, SPELL_TARGETS_ENEMY);
|
||||||
else if(m_customAttr & SPELL_ATTR_CU_CONE_LINE)
|
else if(m_customAttr & SPELL_ATTR_CU_CONE_LINE)
|
||||||
SearchAreaTarget(TagUnitMap, radius, PUSH_IN_LINE, SPELL_TARGETS_AOE_DAMAGE);
|
SearchAreaTarget(TagUnitMap, radius, PUSH_IN_LINE, SPELL_TARGETS_ENEMY);
|
||||||
else
|
else
|
||||||
SearchAreaTarget(TagUnitMap, radius, PUSH_IN_FRONT, SPELL_TARGETS_AOE_DAMAGE);
|
SearchAreaTarget(TagUnitMap, radius, PUSH_IN_FRONT, SPELL_TARGETS_ENEMY);
|
||||||
break;
|
break;
|
||||||
case TARGET_UNIT_CONE_ALLY:
|
case TARGET_UNIT_CONE_ALLY:
|
||||||
SearchAreaTarget(TagUnitMap, radius, PUSH_IN_FRONT, SPELL_TARGETS_FRIENDLY);
|
SearchAreaTarget(TagUnitMap, radius, PUSH_IN_FRONT, SPELL_TARGETS_ALLY);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// nearby target
|
// nearby target
|
||||||
case TARGET_UNIT_NEARBY_ALLY:
|
case TARGET_UNIT_NEARBY_ALLY:
|
||||||
{
|
if(!m_targets.getUnitTarget())
|
||||||
if(Unit* pUnitTarget = SearchNearbyTarget(radius, SPELL_TARGETS_FRIENDLY))
|
m_targets.setUnitTarget(SearchNearbyTarget(radius, SPELL_TARGETS_ALLY));
|
||||||
TagUnitMap.push_back(pUnitTarget);
|
if(m_targets.getUnitTarget())
|
||||||
}break;
|
|
||||||
case TARGET_RANDOM_ENEMY_CHAIN_IN_AREA:
|
|
||||||
{
|
{
|
||||||
if(EffectChainTarget <= 1)
|
if(EffectChainTarget <= 1)
|
||||||
{
|
TagUnitMap.push_back(m_targets.getUnitTarget());
|
||||||
if(Unit* pUnitTarget = SearchNearbyTarget(radius, SPELL_TARGETS_AOE_DAMAGE))
|
|
||||||
TagUnitMap.push_back(pUnitTarget);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
SearchChainTarget(TagUnitMap, m_caster, radius, EffectChainTarget);
|
SearchChainTarget(TagUnitMap, radius, EffectChainTarget, SPELL_TARGETS_ALLY);
|
||||||
}break;
|
}
|
||||||
|
break;
|
||||||
|
case TARGET_RANDOM_ENEMY_CHAIN_IN_AREA:
|
||||||
|
if(!m_targets.getUnitTarget())
|
||||||
|
m_targets.setUnitTarget(SearchNearbyTarget(radius, SPELL_TARGETS_ENEMY));
|
||||||
|
if(m_targets.getUnitTarget())
|
||||||
|
{
|
||||||
|
if(EffectChainTarget <= 1)
|
||||||
|
TagUnitMap.push_back(m_targets.getUnitTarget());
|
||||||
|
else
|
||||||
|
SearchChainTarget(TagUnitMap, radius, EffectChainTarget, SPELL_TARGETS_ENEMY);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case TARGET_SCRIPT:
|
case TARGET_SCRIPT:
|
||||||
case TARGET_SCRIPT_COORDINATES:
|
case TARGET_SCRIPT_COORDINATES:
|
||||||
case TARGET_UNIT_AREA_SCRIPT:
|
case TARGET_UNIT_AREA_SCRIPT:
|
||||||
@@ -1800,7 +1805,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
|
|||||||
float max_range = radius + unMaxTargets * CHAIN_SPELL_JUMP_RADIUS;
|
float max_range = radius + unMaxTargets * CHAIN_SPELL_JUMP_RADIUS;
|
||||||
|
|
||||||
std::list<Unit *> tempUnitMap;
|
std::list<Unit *> tempUnitMap;
|
||||||
Trinity::SpellNotifierCreatureAndPlayer notifier(*this, tempUnitMap, max_range, PUSH_SELF_CENTER, SPELL_TARGETS_FRIENDLY);
|
Trinity::SpellNotifierCreatureAndPlayer notifier(*this, tempUnitMap, max_range, PUSH_SELF_CENTER, SPELL_TARGETS_ALLY);
|
||||||
m_caster->VisitNearbyObject(max_range, notifier);
|
m_caster->VisitNearbyObject(max_range, notifier);
|
||||||
|
|
||||||
if(m_caster != pUnitTarget && std::find(tempUnitMap.begin(),tempUnitMap.end(),m_caster) == tempUnitMap.end() )
|
if(m_caster != pUnitTarget && std::find(tempUnitMap.begin(),tempUnitMap.end(),m_caster) == tempUnitMap.end() )
|
||||||
|
|||||||
+8
-6
@@ -83,6 +83,7 @@ enum SpellNotifyPushType
|
|||||||
PUSH_IN_LINE,
|
PUSH_IN_LINE,
|
||||||
PUSH_SELF_CENTER,
|
PUSH_SELF_CENTER,
|
||||||
PUSH_DEST_CENTER,
|
PUSH_DEST_CENTER,
|
||||||
|
PUSH_TARGET_CENTER,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool IsQuestTameSpell(uint32 spellId);
|
bool IsQuestTameSpell(uint32 spellId);
|
||||||
@@ -202,8 +203,8 @@ enum ReplenishType
|
|||||||
|
|
||||||
enum SpellTargets
|
enum SpellTargets
|
||||||
{
|
{
|
||||||
SPELL_TARGETS_FRIENDLY,
|
SPELL_TARGETS_ALLY,
|
||||||
SPELL_TARGETS_AOE_DAMAGE,
|
SPELL_TARGETS_ENEMY,
|
||||||
SPELL_TARGETS_ENTRY
|
SPELL_TARGETS_ENTRY
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -539,8 +540,9 @@ class Spell
|
|||||||
bool IsAliveUnitPresentInTargetList();
|
bool IsAliveUnitPresentInTargetList();
|
||||||
void SearchAreaTarget(std::list<Unit*> &data, float radius, const uint32 &type,
|
void SearchAreaTarget(std::list<Unit*> &data, float radius, const uint32 &type,
|
||||||
SpellTargets TargetType, uint32 entry = 0);
|
SpellTargets TargetType, uint32 entry = 0);
|
||||||
|
void SearchChainTarget(std::list<Unit*> &data, float radius, uint32 unMaxTargets,
|
||||||
|
SpellTargets TargetType);
|
||||||
Unit* SearchNearbyTarget(float radius, SpellTargets TargetType, uint32 entry = 0);
|
Unit* SearchNearbyTarget(float radius, SpellTargets TargetType, uint32 entry = 0);
|
||||||
void SearchChainTarget(std::list<Unit*> &data, Unit* pUnitTarget, float max_range, uint32 unMaxTargets);
|
|
||||||
bool IsValidSingleTargetEffect(Unit const* target, Targets type) const;
|
bool IsValidSingleTargetEffect(Unit const* target, Targets type) const;
|
||||||
bool IsValidSingleTargetSpell(Unit const* target) const;
|
bool IsValidSingleTargetSpell(Unit const* target) const;
|
||||||
void CalculateDamageDoneForAllTargets();
|
void CalculateDamageDoneForAllTargets();
|
||||||
@@ -584,7 +586,7 @@ namespace Trinity
|
|||||||
uint32 i_entry;
|
uint32 i_entry;
|
||||||
|
|
||||||
SpellNotifierCreatureAndPlayer(Spell &spell, std::list<Unit*> &data, float radius, const uint32 &type,
|
SpellNotifierCreatureAndPlayer(Spell &spell, std::list<Unit*> &data, float radius, const uint32 &type,
|
||||||
SpellTargets TargetType = SPELL_TARGETS_AOE_DAMAGE, uint32 entry = 0)
|
SpellTargets TargetType = SPELL_TARGETS_ENEMY, uint32 entry = 0)
|
||||||
: i_data(&data), i_spell(spell), i_push_type(type), i_radius(radius), i_TargetType(TargetType), i_entry(entry)
|
: i_data(&data), i_spell(spell), i_push_type(type), i_radius(radius), i_TargetType(TargetType), i_entry(entry)
|
||||||
{
|
{
|
||||||
i_caster = spell.GetCaster();
|
i_caster = spell.GetCaster();
|
||||||
@@ -604,11 +606,11 @@ namespace Trinity
|
|||||||
|
|
||||||
switch (i_TargetType)
|
switch (i_TargetType)
|
||||||
{
|
{
|
||||||
case SPELL_TARGETS_FRIENDLY:
|
case SPELL_TARGETS_ALLY:
|
||||||
if (!itr->getSource()->isAttackableByAOE() || !i_caster->IsFriendlyTo( itr->getSource() ))
|
if (!itr->getSource()->isAttackableByAOE() || !i_caster->IsFriendlyTo( itr->getSource() ))
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
case SPELL_TARGETS_AOE_DAMAGE:
|
case SPELL_TARGETS_ENEMY:
|
||||||
{
|
{
|
||||||
if(itr->getSource()->GetTypeId()==TYPEID_UNIT && ((Creature*)itr->getSource())->isTotem())
|
if(itr->getSource()->GetTypeId()==TYPEID_UNIT && ((Creature*)itr->getSource())->isTotem())
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
Reference in New Issue
Block a user