* Added the option to specify target entry in conditions table for spells with AoE GO targets.

* A few examples where this is desirable are posted on the forum.

--HG--
branch : trunk
This commit is contained in:
Xanadu
2010-07-30 01:51:33 +02:00
parent cad437d7f0
commit eb852f5bbd
6 changed files with 209 additions and 148 deletions
+7 -2
View File
@@ -770,6 +770,10 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond)
spellProto->EffectImplicitTargetB[i] == TARGET_UNIT_NEARBY_ENTRY ||
spellProto->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT_NEARBY_ENTRY ||
spellProto->EffectImplicitTargetB[i] == TARGET_GAMEOBJECT_NEARBY_ENTRY ||
spellProto->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT_AREA_SRC ||
spellProto->EffectImplicitTargetB[i] == TARGET_GAMEOBJECT_AREA_SRC ||
spellProto->EffectImplicitTargetA[i] == TARGET_GAMEOBJECT_AREA_DST ||
spellProto->EffectImplicitTargetB[i] == TARGET_GAMEOBJECT_AREA_DST ||
spellProto->EffectImplicitTargetA[i] == TARGET_DST_NEARBY_ENTRY ||
spellProto->EffectImplicitTargetB[i] == TARGET_DST_NEARBY_ENTRY ||
spellProto->EffectImplicitTargetA[i] == TARGET_UNIT_CONE_ENTRY ||
@@ -781,8 +785,9 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond)
}
if (!targetfound)
{
sLog.outErrorDb("SourceEntry %u in `condition` table does not have any implicit target TARGET_UNIT_NEARBY_ENTRY(38) or TARGET_DST_NEARBY_ENTRY (46)\
,TARGET_UNIT_AREA_ENTRY_SRC(7), TARGET_UNIT_AREA_ENTRY_DST(8), TARGET_UNIT_CONE_ENTRY(60), TARGET_GAMEOBJECT_NEARBY_ENTRY(40)",cond->mSourceEntry);
sLog.outErrorDb("SourceEntry %u in `condition` table does not have any implicit target TARGET_UNIT_NEARBY_ENTRY(38) or TARGET_DST_NEARBY_ENTRY (46)"
",TARGET_UNIT_AREA_ENTRY_SRC(7), TARGET_UNIT_AREA_ENTRY_DST(8), TARGET_UNIT_CONE_ENTRY(60), TARGET_GAMEOBJECT_NEARBY_ENTRY(40)"
"TARGET_GAMEOBJECT_AREA_SRC(51), TARGET_GAMEOBJECT_AREA_DST(52)", cond->mSourceEntry);
return false;
}
break;
@@ -1177,13 +1177,17 @@ namespace Trinity
class GameObjectInRangeCheck
{
public:
GameObjectInRangeCheck(float _x, float _y, float _z, float _range) : x(_x), y(_y), z(_z), range(_range) {}
GameObjectInRangeCheck(float _x, float _y, float _z, float _range, uint32 _entry = 0) :
x(_x), y(_y), z(_z), range(_range), entry(_entry) {}
bool operator() (GameObject* go)
{
return go->IsInRange(x, y, z, range);
if (!entry || go->GetGOInfo() && go->GetGOInfo()->id == entry)
return go->IsInRange(x, y, z, range);
else return false;
}
private:
float x, y, z, range;
uint32 entry;
};
// Player checks and do
@@ -1148,8 +1148,8 @@ enum Targets
TARGET_DEST_CASTER_BACK = 48,
TARGET_DEST_CASTER_RIGHT = 49,
TARGET_DEST_CASTER_LEFT = 50,
TARGET_OBJECT_AREA_SRC = 51,
TARGET_OBJECT_AREA_DST = 52,
TARGET_GAMEOBJECT_AREA_SRC = 51, // If used with SPELL_EFFECT_ACTIVATE_OBJECT, appliccable GO entries should be specified in conditions table
TARGET_GAMEOBJECT_AREA_DST = 52, // If used with SPELL_EFFECT_ACTIVATE_OBJECT, appliccable GO entries should be specified in conditions table
TARGET_DST_TARGET_ENEMY = 53, // set unit coordinates as dest, only 16 target B imlemented
TARGET_UNIT_CONE_ENEMY_UNKNOWN = 54, // 180 degree, or different angle
TARGET_DEST_CASTER_FRONT_LEAP = 55, // for a leap spell
+190 -140
View File
@@ -1729,6 +1729,9 @@ void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, float max_range, uin
void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry)
{
if (TargetType == SPELL_TARGETS_GO)
return;
Position *pos;
switch(type)
{
@@ -1767,6 +1770,32 @@ void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, SpellNo
TagUnitMap.remove(m_caster);
}
void Spell::SearchGOAreaTarget(std::list<GameObject*> &TagGOMap, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry)
{
if (TargetType != SPELL_TARGETS_GO)
return;
Position *pos;
switch (type)
{
case PUSH_DST_CENTER:
CheckDst();
pos = &m_targets.m_dstPos;
break;
case PUSH_SRC_CENTER:
CheckSrc();
pos = &m_targets.m_srcPos;
break;
default:
pos = m_caster;
break;
}
Trinity::GameObjectInRangeCheck check(pos->m_positionX, pos->m_positionY, pos->m_positionZ, radius + 50, entry);
Trinity::GameObjectListSearcher<Trinity::GameObjectInRangeCheck> searcher(m_caster, TagGOMap, check);
m_caster->GetMap()->VisitGrid(pos->m_positionX, pos->m_positionY, radius, searcher);
}
WorldObject* Spell::SearchNearbyTarget(float range, SpellTargets TargetType)
{
switch(TargetType)
@@ -2328,6 +2357,11 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur)
radius = GetSpellRadius(m_spellInfo, i, IsPositiveSpell(m_spellInfo->Id));
targetType = SPELL_TARGETS_ENTRY;
break;
case TARGET_GAMEOBJECT_AREA_SRC:
case TARGET_GAMEOBJECT_AREA_DST:
radius = GetSpellRadius(m_spellInfo, i, true);
targetType = SPELL_TARGETS_GO;
break;
default:
radius = GetSpellRadius(m_spellInfo, i, true);
targetType = SPELL_TARGETS_NONE;
@@ -2339,169 +2373,170 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur)
radius *= m_spellValue->RadiusMod;
std::list<Unit*> unitList;
if (targetType == SPELL_TARGETS_ENTRY)
std::list<GameObject*> gobjectList;
switch (targetType)
{
ConditionList conditions = sConditionMgr.GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET, m_spellInfo->Id);
if (conditions.empty())
case SPELL_TARGETS_ENTRY:
{
// Custom entries
// TODO: move these to sql
switch (m_spellInfo->Id)
ConditionList conditions = sConditionMgr.GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET, m_spellInfo->Id);
if (!conditions.empty())
{
case 46584: // Raise Dead
for (ConditionList::const_iterator i_spellST = conditions.begin(); i_spellST != conditions.end(); ++i_spellST)
{
if (WorldObject* result = FindCorpseUsing<Trinity::RaiseDeadObjectCheck> ())
if ((*i_spellST)->mConditionType != CONDITION_SPELL_SCRIPT_TARGET)
continue;
if ((*i_spellST)->mConditionValue1 == SPELL_TARGET_TYPE_CREATURE)
SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, (*i_spellST)->mConditionValue2);
else if ((*i_spellST)->mConditionValue1 == SPELL_TARGET_TYPE_CONTROLLED)
{
switch(result->GetTypeId())
{
case TYPEID_UNIT:
m_targets.setDst(result);
}
for (Unit::ControlList::iterator itr = m_caster->m_Controlled.begin(); itr != m_caster->m_Controlled.end(); ++itr)
if ((*itr)->GetEntry() == (*i_spellST)->mConditionValue2 &&
/*(*itr)->IsWithinDistInMap(m_caster, radius)*/ (*itr)->IsInMap(m_caster)) // For 60243 and 52173 need skip radius check or use range (no radius entry for effect)
unitList.push_back(*itr);
}
break;
}
// Corpse Explosion
case 49158:
case 51325:
case 51326:
case 51327:
case 51328:
// Search for ghoul if our ghoul or dead body not valid unit target
if (!(m_targets.getUnitTarget() && (m_targets.getUnitTarget()->GetEntry() == 26125 && m_targets.getUnitTarget()->GetOwnerGUID() == m_caster->GetGUID()
|| (m_targets.getUnitTarget()->getDeathState() == CORPSE
&& m_targets.getUnitTarget()->GetDisplayId() == m_targets.getUnitTarget()->GetNativeDisplayId()
&& m_targets.getUnitTarget()->GetTypeId() == TYPEID_UNIT
&& !m_targets.getUnitTarget()->ToCreature()->isDeadByDefault()
&& !(m_targets.getUnitTarget()->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL))
&& m_targets.getUnitTarget()->GetDisplayId() == m_targets.getUnitTarget()->GetNativeDisplayId())))
}
else
{
// Custom entries
// TODO: move these to sql
switch (m_spellInfo->Id)
{
case 46584: // Raise Dead
{
CleanupTargetList();
WorldObject* result = FindCorpseUsing <Trinity::ExplodeCorpseObjectCheck> ();
if (result)
if (WorldObject* result = FindCorpseUsing<Trinity::RaiseDeadObjectCheck> ())
{
switch (result->GetTypeId())
switch(result->GetTypeId())
{
case TYPEID_UNIT:
case TYPEID_PLAYER:
m_targets.setUnitTarget((Unit*)result);
break;
m_targets.setDst(result);
}
}
break;
}
// Corpse Explosion
case 49158:
case 51325:
case 51326:
case 51327:
case 51328:
// Search for ghoul if our ghoul or dead body not valid unit target
if (!(m_targets.getUnitTarget() && (m_targets.getUnitTarget()->GetEntry() == 26125 && m_targets.getUnitTarget()->GetOwnerGUID() == m_caster->GetGUID()
|| (m_targets.getUnitTarget()->getDeathState() == CORPSE
&& m_targets.getUnitTarget()->GetDisplayId() == m_targets.getUnitTarget()->GetNativeDisplayId()
&& m_targets.getUnitTarget()->GetTypeId() == TYPEID_UNIT
&& !m_targets.getUnitTarget()->ToCreature()->isDeadByDefault()
&& !(m_targets.getUnitTarget()->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL))
&& m_targets.getUnitTarget()->GetDisplayId() == m_targets.getUnitTarget()->GetNativeDisplayId())))
{
CleanupTargetList();
WorldObject* result = FindCorpseUsing <Trinity::ExplodeCorpseObjectCheck> ();
if (result)
{
switch (result->GetTypeId())
{
case TYPEID_UNIT:
case TYPEID_PLAYER:
m_targets.setUnitTarget((Unit*)result);
break;
}
}
else
{
if (m_caster->GetTypeId() == TYPEID_PLAYER)
m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id,true);
SendCastResult(SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW);
finish(false);
}
}
break;
default:
sLog.outDebug("Spell (ID: %u) (caster Entry: %u) does not have type CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET record in `conditions` table.", m_spellInfo->Id, m_caster->GetEntry());
if (m_spellInfo->Effect[i] == SPELL_EFFECT_TELEPORT_UNITS)
SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, 0);
else if (IsPositiveEffect(m_spellInfo->Id, i))
SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ALLY);
else
{
if (m_caster->GetTypeId() == TYPEID_PLAYER)
m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id,true);
SendCastResult(SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW);
finish(false);
}
}
SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENEMY);
}
}
break;
}
case SPELL_TARGETS_GO:
{
ConditionList conditions = sConditionMgr.GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET, m_spellInfo->Id);
if (!conditions.empty())
{
for (ConditionList::const_iterator i_spellST = conditions.begin(); i_spellST != conditions.end(); ++i_spellST)
{
if ((*i_spellST)->mConditionType != CONDITION_SPELL_SCRIPT_TARGET)
continue;
if ((*i_spellST)->mConditionValue1 == SPELL_TARGET_TYPE_GAMEOBJECT)
SearchGOAreaTarget(gobjectList, radius, pushType, SPELL_TARGETS_GO, (*i_spellST)->mConditionValue2);
}
}
else
{
if (m_spellInfo->Effect[i] == SPELL_EFFECT_ACTIVATE_OBJECT)
sLog.outDebug("Spell (ID: %u) (caster Entry: %u) with SPELL_EFFECT_ACTIVATE_OBJECT does not have type CONDITION_SOURCE_TYPE_SPELL_SCRIPT_TARGET record in `conditions` table.", m_spellInfo->Id, m_caster->GetEntry());
SearchGOAreaTarget(gobjectList, radius, pushType, SPELL_TARGETS_GO);
}
break;
}
case SPELL_TARGETS_ALLY:
case SPELL_TARGETS_ENEMY:
case SPELL_TARGETS_CHAINHEAL:
case SPELL_TARGETS_ANY:
SearchAreaTarget(unitList, radius, pushType, targetType);
break;
default:
switch (cur)
{
case TARGET_UNIT_AREA_PARTY_SRC:
case TARGET_UNIT_AREA_PARTY_DST:
m_caster->GetPartyMemberInDist(unitList, radius); //fix me
break;
default:
sLog.outDebug("Spell (ID: %u) (caster Entry: %u) does not have record in `spell_script_target`", m_spellInfo->Id, m_caster->GetEntry());
if (m_spellInfo->Effect[i] == SPELL_EFFECT_TELEPORT_UNITS)
SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, 0);
else if (IsPositiveEffect(m_spellInfo->Id, i))
SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ALLY);
else
SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENEMY);
}
}
// let it be done in one check?
else
{
for (ConditionList::const_iterator i_spellST = conditions.begin(); i_spellST != conditions.end(); ++i_spellST)
{
if ((*i_spellST)->mConditionType != CONDITION_SPELL_SCRIPT_TARGET)
continue;
if ((*i_spellST)->mConditionValue1 == SPELL_TARGET_TYPE_CREATURE)
SearchAreaTarget(unitList, radius, pushType, SPELL_TARGETS_ENTRY, (*i_spellST)->mConditionValue2);
else if ((*i_spellST)->mConditionValue1 == SPELL_TARGET_TYPE_CONTROLLED)
case TARGET_UNIT_PARTY_TARGET:
m_targets.getUnitTarget()->GetPartyMemberInDist(unitList, radius);
break;
case TARGET_UNIT_PARTY_CASTER:
m_caster->GetPartyMemberInDist(unitList, radius);
break;
case TARGET_UNIT_RAID_CASTER:
m_caster->GetRaidMember(unitList, radius);
break;
case TARGET_UNIT_CLASS_TARGET:
{
for (Unit::ControlList::iterator itr = m_caster->m_Controlled.begin(); itr != m_caster->m_Controlled.end(); ++itr)
if ((*itr)->GetEntry() == (*i_spellST)->mConditionValue2 &&
/*(*itr)->IsWithinDistInMap(m_caster, radius)*/ (*itr)->IsInMap(m_caster)) // For 60243 and 52173 need skip radius check or use range (no radius entry for effect)
unitList.push_back(*itr);
}
}
}
}
else if (targetType)
SearchAreaTarget(unitList, radius, pushType, targetType);
else
{
switch (cur)
{
case TARGET_UNIT_AREA_PARTY_SRC:
case TARGET_UNIT_AREA_PARTY_DST:
m_caster->GetPartyMemberInDist(unitList, radius); //fix me
break;
case TARGET_OBJECT_AREA_SRC: // fix me
case TARGET_OBJECT_AREA_DST:
{
float x, y, z;
if (cur == TARGET_OBJECT_AREA_SRC)
{
if (m_targets.HasSrc())
m_targets.m_srcPos.GetPosition(x, y, z);
else
break;
}
else
{
if (m_targets.HasDst())
m_targets.m_dstPos.GetPosition(x, y, z);
else
break;
}
Player* targetPlayer = m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER
? (Player*)m_targets.getUnitTarget() : NULL;
Trinity::GameObjectInRangeCheck check(x, y, z, radius + 50);
std::list<GameObject*> goList;
Trinity::GameObjectListSearcher<Trinity::GameObjectInRangeCheck> searcher(m_caster, goList, check);
m_caster->GetMap()->VisitGrid(x, y, radius, searcher);
for (std::list<GameObject*>::iterator itr = goList.begin(); itr != goList.end(); ++itr)
AddGOTarget(*itr, i);
break;
}
case TARGET_UNIT_PARTY_TARGET:
m_targets.getUnitTarget()->GetPartyMemberInDist(unitList, radius);
break;
case TARGET_UNIT_PARTY_CASTER:
m_caster->GetPartyMemberInDist(unitList, radius);
break;
case TARGET_UNIT_RAID_CASTER:
m_caster->GetRaidMember(unitList, radius);
break;
case TARGET_UNIT_CLASS_TARGET:
{
Player* targetPlayer = m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER
? (Player*)m_targets.getUnitTarget() : NULL;
Group* pGroup = targetPlayer ? targetPlayer->GetGroup() : NULL;
if (pGroup)
{
for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
Group* pGroup = targetPlayer ? targetPlayer->GetGroup() : NULL;
if (pGroup)
{
Player* Target = itr->getSource();
// IsHostileTo check duel and controlled by enemy
if (Target && targetPlayer->IsWithinDistInMap(Target, radius) &&
targetPlayer->getClass() == Target->getClass() &&
!m_caster->IsHostileTo(Target))
for (GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
{
AddUnitTarget(Target, i);
Player* Target = itr->getSource();
// IsHostileTo check duel and controlled by enemy
if (Target && targetPlayer->IsWithinDistInMap(Target, radius) &&
targetPlayer->getClass() == Target->getClass() &&
!m_caster->IsHostileTo(Target))
{
AddUnitTarget(Target, i);
}
}
}
else if (m_targets.getUnitTarget())
AddUnitTarget(m_targets.getUnitTarget(), i);
break;
}
else if (m_targets.getUnitTarget())
AddUnitTarget(m_targets.getUnitTarget(), i);
break;
}
break;
}
}
if (!unitList.empty())
{
@@ -2625,7 +2660,7 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur)
if (m_spellInfo->Id == 5246) //Intimidating Shout
unitList.remove(m_targets.getUnitTarget());
Trinity::RandomResizeList(unitList, m_spellValue->MaxAffectedTargets);
Trinity::RandomResizeList(unitList, maxTargets);
}
else
{
@@ -2671,6 +2706,21 @@ void Spell::SelectEffectTargets(uint32 i, uint32 cur)
for (std::list<Unit*>::iterator itr = unitList.begin(); itr != unitList.end(); ++itr)
AddUnitTarget(*itr, i);
}
if (!gobjectList.empty())
{
if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
{
Unit::AuraEffectList const& Auras = m_caster->GetAuraEffectsByType(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS);
for (Unit::AuraEffectList::const_iterator j = Auras.begin(); j != Auras.end(); ++j)
if ((*j)->IsAffectedOnSpell(m_spellInfo))
maxTargets += (*j)->GetAmount();
Trinity::RandomResizeList(gobjectList, maxTargets);
}
for (std::list<GameObject*>::iterator itr = gobjectList.begin(); itr != gobjectList.end(); ++itr)
AddGOTarget(*itr, i);
}
}
}
+2
View File
@@ -265,6 +265,7 @@ enum SpellTargets
SPELL_TARGETS_ENTRY,
SPELL_TARGETS_CHAINHEAL,
SPELL_TARGETS_ANY,
SPELL_TARGETS_GO
};
class Spell
@@ -645,6 +646,7 @@ class Spell
void DoAllEffectOnTarget(ItemTargetInfo *target);
bool UpdateChanneledTargetList();
void SearchAreaTarget(std::list<Unit*> &unitList, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry = 0);
void SearchGOAreaTarget(std::list<GameObject*> &gobjectList, float radius, SpellNotifyPushType type, SpellTargets TargetType, uint32 entry = 0);
void SearchChainTarget(std::list<Unit*> &unitList, float radius, uint32 unMaxTargets, SpellTargets TargetType);
WorldObject* SearchNearbyTarget(float range, SpellTargets TargetType);
bool IsValidSingleTargetEffect(Unit const* target, Targets type) const;
+2 -2
View File
@@ -145,14 +145,14 @@ SpellMgr::SpellMgr()
case TARGET_UNIT_AREA_ALLY_SRC:
case TARGET_UNIT_AREA_ENTRY_SRC:
case TARGET_UNIT_AREA_PARTY_SRC:
case TARGET_OBJECT_AREA_SRC:
case TARGET_GAMEOBJECT_AREA_SRC:
SpellTargetType[i] = TARGET_TYPE_AREA_SRC;
break;
case TARGET_UNIT_AREA_ENEMY_DST:
case TARGET_UNIT_AREA_ALLY_DST:
case TARGET_UNIT_AREA_ENTRY_DST:
case TARGET_UNIT_AREA_PARTY_DST:
case TARGET_OBJECT_AREA_DST:
case TARGET_GAMEOBJECT_AREA_DST:
SpellTargetType[i] = TARGET_TYPE_AREA_DST;
break;
case TARGET_UNIT_CONE_ENEMY: