*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:
megamage
2009-01-26 19:23:50 -06:00
parent 91d49437bd
commit 635d16439a
2 changed files with 77 additions and 70 deletions
+68 -63
View File
@@ -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)
if(tempUnitMap.empty())
return;
uint32 t = unMaxTargets;
if(pUnitTarget != m_caster)
{ {
if(*tempUnitMap.begin() == pUnitTarget) TagUnitMap.push_back(cur);
tempUnitMap.erase(tempUnitMap.begin()); --num;
TagUnitMap.push_back(pUnitTarget);
--t;
}
Unit *prev = pUnitTarget;
std::list<Unit*>::iterator next = tempUnitMap.begin(); if(tempUnitMap.empty())
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)
{ TagUnitMap.push_back(SelectMagnetTarget());
if(EffectChainTarget <= 1) else if(SelectMagnetTarget()) //TODO: chain target should also use magnet target
TagUnitMap.push_back(pUnitTarget); SearchChainTarget(TagUnitMap, radius, EffectChainTarget, SPELL_TARGETS_ENEMY);
else //TODO: chain target should also use magnet target
SearchChainTarget(TagUnitMap, pUnitTarget, radius, EffectChainTarget);
}
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(Unit* pUnitTarget = SearchNearbyTarget(radius, SPELL_TARGETS_AOE_DAMAGE)) if(EffectChainTarget <= 1)
TagUnitMap.push_back(pUnitTarget); TagUnitMap.push_back(m_targets.getUnitTarget());
else
SearchChainTarget(TagUnitMap, radius, EffectChainTarget, SPELL_TARGETS_ALLY);
} }
else break;
SearchChainTarget(TagUnitMap, m_caster, radius, EffectChainTarget); case TARGET_RANDOM_ENEMY_CHAIN_IN_AREA:
}break; 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
View File
@@ -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;