diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp | 35 | ||||
-rw-r--r-- | src/bindings/scripts/scripts/zone/black_temple/illidari_council.cpp | 3 | ||||
-rw-r--r-- | src/game/SharedDefines.h | 4 | ||||
-rw-r--r-- | src/game/Spell.cpp | 1048 | ||||
-rw-r--r-- | src/game/Spell.h | 103 | ||||
-rw-r--r-- | src/game/SpellMgr.cpp | 4 |
6 files changed, 482 insertions, 715 deletions
diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp index 87152a249f2..505f73e7f21 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp @@ -96,6 +96,7 @@ EndScriptData */ #define SPELL_DUAL_WIELD 42459 //Phase Normal spells #define SPELL_FLAME_CRASH_EFFECT 40836 // Firey blue ring of circle that the other flame crash summons +#define SPELL_SUMMON_SHADOWDEMON 41117 // Summon four shadowfiends #define SPELL_SHADOWFIEND_PASSIVE 41913 // Passive aura for shadowfiends #define SPELL_SHADOW_DEMON_PASSIVE 41079 // Adds the "shadowform" aura to Shadow Demons. #define SPELL_CONSUME_SOUL 41080 // Once the Shadow Demons reach their target, they use this to kill them @@ -385,13 +386,18 @@ struct TRINITY_DLL_DECL boss_illidan_stormrageAI : public ScriptedAI void Reset(); - void JustSummoned(Creature* summon)//, TempSummonType type) + void JustSummoned(Creature* summon) { - if(summon->GetCreatureInfo()->Entry == FLAME_CRASH) + if(summon->GetCreatureInfo()->Entry == SHADOW_DEMON) { - // type = TEMPSUMMON_TIMED_DESPAWN; + Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0); + if(target && target->GetTypeId() == TYPEID_PLAYER) // only on players. + { + summon->AddThreat(target, 5000000.0f); + summon->AI()->AttackStart(target); + } + DoZoneInCombat(summon); } - //error_log("justsummoned %d %d", summon->GetCreatureInfo()->Entry, summon->GetGUID()); } void SummonedCreatureDespawn(Creature* summon) @@ -558,25 +564,6 @@ struct TRINITY_DLL_DECL boss_illidan_stormrageAI : public ScriptedAI void CastEyeBlast(); void SummonFlamesOfAzzinoth(); void SummonMaiev(); - void SummonShadowDemon() - { - Creature* ShadowDemon = NULL; - Unit* target = NULL; - for(uint8 i = 0; i < 4; i++) - { - ShadowDemon = DoSpawnCreature(SHADOW_DEMON, 0,0,0,0,TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN,25000); - if(ShadowDemon) - { - target = SelectUnit(SELECT_TARGET_RANDOM, 0); - if(target && target->GetTypeId() == TYPEID_PLAYER) // only on players. - { - ShadowDemon->AddThreat(target, 5000000.0f); - ShadowDemon->AI()->AttackStart(target); - } - DoZoneInCombat(ShadowDemon); - } - } - } void HandleTalkSequence(); void HandleFlightSequence() { @@ -943,7 +930,7 @@ struct TRINITY_DLL_DECL boss_illidan_stormrageAI : public ScriptedAI Timer[EVENT_SHADOW_BLAST] = 4000; break; case EVENT_SHADOWDEMON: - SummonShadowDemon(); + DoCast(m_creature, SPELL_SUMMON_SHADOWDEMON); Timer[EVENT_SHADOWDEMON] = 0; Timer[EVENT_FLAME_BURST] += 10000; break; diff --git a/src/bindings/scripts/scripts/zone/black_temple/illidari_council.cpp b/src/bindings/scripts/scripts/zone/black_temple/illidari_council.cpp index 13f30cf37da..6e5cabc034c 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/illidari_council.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/illidari_council.cpp @@ -695,8 +695,7 @@ struct TRINITY_DLL_DECL boss_lady_malandeAI : public boss_illidari_councilAI if(CircleOfHealingTimer < diff) { - //Currently bugged and puts Malande on the threatlist of the other council members. It also heals players. - //DoCast(m_creature, SPELL_CIRCLE_OF_HEALING); + DoCast(m_creature, SPELL_CIRCLE_OF_HEALING); CircleOfHealingTimer = 60000; }else CircleOfHealingTimer -= diff; diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index 988c43a826b..f950a9ceb6c 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -807,7 +807,7 @@ enum Targets TARGET_IN_FRONT_OF_CASTER = 24, //TARGET_UNIT_CONE_ENEMY TARGET_DUELVSPLAYER = 25, - //TARGET_UNIT_SINGLE + //TARGET_UNIT_TARGET TARGET_GAMEOBJECT_ITEM = 26, //TARGET_OBJECT_ITEM_PICKLOCK TARGET_MASTER = 27, @@ -842,7 +842,7 @@ enum Targets TARGET_CHAIN_HEAL = 45, //TARGET_UNIT_CHAINHEAL TARGET_SCRIPT_COORDINATES = 46, - //TARGET_DEST_TABLE_UNKNOWN + //TARGET_DEST_NEARBY_ENTRY TARGET_DEST_CASTER_FRONT = 47, TARGET_DEST_CASTER_BACK = 48, TARGET_DEST_CASTER_RIGHT = 49, diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 7684d31eee9..716cc7a518e 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -392,12 +392,6 @@ void Spell::FillTargetMap() if(m_spellInfo->Effect[i]==0) continue; - // targets for TARGET_SCRIPT_COORDINATES (A) and TARGET_SCRIPT filled in Spell::canCast call - if( m_spellInfo->EffectImplicitTargetA[i] == TARGET_SCRIPT_COORDINATES || - m_spellInfo->EffectImplicitTargetA[i] == TARGET_SCRIPT || - m_spellInfo->EffectImplicitTargetB[i] == TARGET_SCRIPT && m_spellInfo->EffectImplicitTargetA[i] != TARGET_SELF ) - continue; - // TODO: find a way so this is not needed? // for area auras always add caster as target (needed for totems for example) if(IsAreaAuraEffect(m_spellInfo->Effect[i])) @@ -405,52 +399,31 @@ void Spell::FillTargetMap() std::list<Unit*> tmpUnitMap; - // TargetA/TargetB dependent from each other, we not switch to full support this dependences - // but need it support in some know cases - switch(m_spellInfo->EffectImplicitTargetA[i]) + // Note: this hack with search required until GO casting not implemented + // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support + // currently each enemy selected explicitly and self cast damage + if(m_spellInfo->EffectImplicitTargetA[i] == TARGET_ALL_AROUND_CASTER + && m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_ENEMY_IN_AREA + && m_spellInfo->Effect[i]==SPELL_EFFECT_ENVIRONMENTAL_DAMAGE) { - case TARGET_ALL_AROUND_CASTER: - if( m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_PARTY || - m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER || - m_spellInfo->EffectImplicitTargetB[i]==TARGET_RANDOM_RAID_MEMBER ) - { - SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); - } - // Note: this hack with search required until GO casting not implemented - // environment damage spells already have around enemies targeting but this not help in case not existed GO casting support - // currently each enemy selected explicitly and self cast damage - else if(m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_ENEMY_IN_AREA && m_spellInfo->Effect[i]==SPELL_EFFECT_ENVIRONMENTAL_DAMAGE) - { - if(m_targets.getUnitTarget()) - tmpUnitMap.push_back(m_targets.getUnitTarget()); - } - else - { - SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); - SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); - } - break; - case TARGET_TABLE_X_Y_Z_COORDINATES: - // Only if target A, for target B (used in teleports) dest select in effect - SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); - break; - default: - switch(m_spellInfo->EffectImplicitTargetB[i]) - { - case TARGET_SCRIPT_COORDINATES: // B case filled in canCast but we need fill unit list base at A case - SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); - break; - default: - SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); - SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); - break; - } - break; + tmpUnitMap.push_back(m_targets.getUnitTarget()); + } + else + { + SetTargetMap(i,m_spellInfo->EffectImplicitTargetA[i],tmpUnitMap); + SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap); } - if( (m_spellInfo->EffectImplicitTargetA[i]==0 || m_spellInfo->EffectImplicitTargetA[i]==TARGET_EFFECT_SELECT) && - (m_spellInfo->EffectImplicitTargetB[i]==0 || m_spellInfo->EffectImplicitTargetB[i]==TARGET_EFFECT_SELECT) ) + if(tmpUnitMap.empty()) { + if( m_spellInfo->EffectImplicitTargetA[i]==TARGET_SCRIPT || + m_spellInfo->EffectImplicitTargetB[i]==TARGET_SCRIPT || + m_spellInfo->EffectImplicitTargetA[i]==TARGET_SCRIPT_COORDINATES || + m_spellInfo->EffectImplicitTargetB[i]==TARGET_SCRIPT_COORDINATES ) + { + if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)) + continue; + } // add here custom effects that need default target. // FOR EVERY TARGET TYPE THERE IS A DIFFERENT FILL!! switch(m_spellInfo->Effect[i]) @@ -1166,6 +1139,140 @@ struct TargetDistanceOrder : public std::binary_function<const Unit, const Unit, } }; +void Spell::SearchChainTarget(std::list<Unit*> &TagUnitMap, Unit* pUnitTarget, float max_range, uint32 unMaxTargets) +{ + if(!pUnitTarget) + return; + + //FIXME: This very like horrible hack and wrong for most spells + if(m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE) + max_range += unMaxTargets * CHAIN_SPELL_JUMP_RADIUS; + + CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + std::list<Unit *> tempUnitMap; + + { + Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(pUnitTarget, m_caster, max_range); + Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(tempUnitMap, u_check); + + TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher); + TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher); + + CellLock<GridReadGuard> cell_lock(cell, p); + cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + } + + tempUnitMap.sort(TargetDistanceOrder(pUnitTarget)); + + 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; + + if(!prev->IsWithinLOSInMap(*next) + || m_spellInfo->DmgClass==SPELL_DAMAGE_CLASS_MELEE && !m_caster->isInFront(*next, max_range)) + { + ++next; + continue; + } + + prev = *next; + TagUnitMap.push_back(prev); + tempUnitMap.erase(next); + tempUnitMap.sort(TargetDistanceOrder(prev)); + next = tempUnitMap.begin(); + --t; + } +} + +void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, const uint32 &type, SpellTargets TargetType, uint32 entry) +{ + if(type == PUSH_DEST_CENTER && !m_targets.m_destX && !m_targets.m_destY && !m_targets.m_destZ) + { + sLog.outError( "SPELL: cannot find destination for spell ID %u\n", m_spellInfo->Id ); + return; + } + + CellPair p(Trinity::ComputeCellPair(m_targets.m_destX, m_targets.m_destY)); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + CellLock<GridReadGuard> cell_lock(cell, p); + + Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, type, TargetType, entry); + + if(TargetType != SPELL_TARGETS_ENTRY) + { + TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier); + cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + } + TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_object_notifier(notifier); + cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); +} + +Unit* Spell::SearchNearbyTarget(float radius, SpellTargets TargetType, uint32 entry) +{ + CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + CellLock<GridReadGuard> cell_lock(cell, p); + + Unit* target = NULL; + switch(TargetType) + { + case SPELL_TARGETS_ENTRY: + { + Creature* target = NULL; + Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster, entry, true, radius); + Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(target, u_check); + TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher); + cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + return target; + }break; + default: + case SPELL_TARGETS_AOE_DAMAGE: + { + Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, radius); + Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(target, u_check); + TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher); + TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher); + cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + }break; + case SPELL_TARGETS_FRIENDLY: + { + Trinity::AnyFriendlyUnitInObjectRangeCheck u_check(m_caster, m_caster, radius); + Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(target, u_check); + TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher); + TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher); + cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); + }break; + } + return target; +} + void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap) { float radius; @@ -1186,311 +1293,249 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap) uint32 unMaxTargets = m_spellInfo->MaxAffectedTargets; switch(cur) { - // destination around caster - case TARGET_DEST_CASTER_FRONT_LEFT: - case TARGET_DEST_CASTER_BACK_LEFT: - case TARGET_DEST_CASTER_BACK_RIGHT: - case TARGET_DEST_CASTER_FRONT_RIGHT: - case TARGET_DEST_CASTER_FRONT: - case TARGET_DEST_CASTER_BACK: - case TARGET_DEST_CASTER_RIGHT: - case TARGET_DEST_CASTER_LEFT: - case TARGET_DEST_CASTER_RANDOM: - case TARGET_DEST_CASTER_RADIUS: + // specific unit + case TARGET_SELF: + case TARGET_SELF_FISHING: { - float x, y, z, angle, dist; - - if (m_spellInfo->EffectRadiusIndex[i]) - dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - else - dist = 3.0f;//do we need this? - if (cur == TARGET_DEST_CASTER_RANDOM) - dist *= rand_norm(); // This case we need to consider caster size - else - dist -= m_caster->GetObjectSize(); // Size is calculated in GetNearPoint(), but we do not need it - //need a new function to remove this repeated work - - switch(cur) + TagUnitMap.push_back(m_caster); + }break; + case TARGET_MASTER: + { + if(Unit* owner = m_caster->GetCharmerOrOwner()) + TagUnitMap.push_back(owner); + }break; + case TARGET_PET: + { + if(Pet* tmpUnit = m_caster->GetPet()) + TagUnitMap.push_back(tmpUnit); + }break; + case TARGET_NONCOMBAT_PET: + { + if(Unit* target = m_targets.getUnitTarget()) + if( target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isPet() && ((Pet*)target)->getPetType() == MINI_PET) + TagUnitMap.push_back(target); + }break; + case TARGET_SINGLE_FRIEND: // ally + case TARGET_SINGLE_FRIEND_2: // raid member + case TARGET_DUELVSPLAYER: // all (SelectMagnetTarget()?) + case TARGET_UNIT_SINGLE_UNKNOWN: + { + if(m_targets.getUnitTarget()) + TagUnitMap.push_back(m_targets.getUnitTarget()); + }break; + case TARGET_CHAIN_DAMAGE: + { + if(Unit* pUnitTarget = SelectMagnetTarget()) { - case TARGET_DEST_CASTER_FRONT_LEFT: angle = -M_PI/4; break; - case TARGET_DEST_CASTER_BACK_LEFT: angle = -3*M_PI/4; break; - case TARGET_DEST_CASTER_BACK_RIGHT: angle = 3*M_PI/4; break; - case TARGET_DEST_CASTER_FRONT_RIGHT:angle = M_PI/4; break; - case TARGET_DEST_CASTER_FRONT: angle = 0.0f; break; - case TARGET_DEST_CASTER_BACK: angle = M_PI; break; - case TARGET_DEST_CASTER_RIGHT: angle = M_PI/2; break; - case TARGET_DEST_CASTER_LEFT: angle = -M_PI/2; break; - default: angle = rand_norm()*2*M_PI; break; + if(EffectChainTarget <= 1) + TagUnitMap.push_back(pUnitTarget); + else //TODO: chain target should also use magnet target + SearchChainTarget(TagUnitMap, pUnitTarget, radius, EffectChainTarget); } - - m_caster->GetClosePoint(x, y, z, 0, dist, angle); - m_targets.setDestination(x, y, z); // do not know if has ground visual - TagUnitMap.push_back(m_caster); // may remove this in the future, if unitmap is empty, push m_caster + }break; + case TARGET_GAMEOBJECT: + { + if(m_targets.getGOTarget()) + AddGOTarget(m_targets.getGOTarget(), i); + }break; + case TARGET_GAMEOBJECT_ITEM: + { + if(m_targets.getGOTargetGUID()) + AddGOTarget(m_targets.getGOTarget(), i); + else if(m_targets.getItemTarget()) + AddItemTarget(m_targets.getItemTarget(), i); }break; - // destination around target - case TARGET_DEST_TARGET_FRONT: - case TARGET_DEST_TARGET_BACK: - case TARGET_DEST_TARGET_RIGHT: - case TARGET_DEST_TARGET_LEFT: - case TARGET_DEST_TARGET_RANDOM: - case TARGET_DEST_TARGET_RADIUS: + // reference dest + case TARGET_EFFECT_SELECT: + m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION; + case TARGET_ALL_AROUND_CASTER: { - Unit *target = m_targets.getUnitTarget(); - if(!target) + m_caster->GetPosition(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ); + }break; + case TARGET_CURRENT_ENEMY_COORDINATES: + m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION; + case TARGET_DUELVSPLAYER_COORDINATES: // no ground? + { + if(Unit* currentTarget = m_targets.getUnitTarget()) + currentTarget->GetPosition(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ); + }break; + case TARGET_DEST_TABLE_UNKNOWN2: + case TARGET_TABLE_X_Y_Z_COORDINATES: + { + SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id); + if(st) { - sLog.outError("SPELL: no unit target for spell ID %u\n", m_spellInfo->Id); - break; + if (st->target_mapId == m_caster->GetMapId()) + m_targets.setDestination(st->target_X, st->target_Y, st->target_Z); } - - float x, y, z, angle, dist; - - if (m_spellInfo->EffectRadiusIndex[i]) - dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - else - dist = 3.0f;//do we need this? - if (cur == TARGET_DEST_TARGET_RANDOM) - dist *= rand_norm(); // This case we need to consider caster size else - dist -= target->GetObjectSize(); // Size is calculated in GetNearPoint(), but we do not need it - //need a new function to remove this repeated work - - switch(cur) - { - case TARGET_DEST_TARGET_FRONT: angle = 0.0f; break; - case TARGET_DEST_TARGET_BACK: angle = M_PI; break; - case TARGET_DEST_TARGET_RIGHT: angle = M_PI/2; break; - case TARGET_DEST_TARGET_LEFT: angle = -M_PI/2; break; - default: angle = rand_norm()*2*M_PI; break; - } - - target->GetClosePoint(x, y, z, 0, dist, angle); - m_targets.setDestination(x, y, z); // do not know if has ground visual - TagUnitMap.push_back(m_caster); // may remove this in the future, if unitmap is empty, push m_caster + sLog.outError( "SPELL: unknown target coordinates for spell ID %u\n", m_spellInfo->Id ); }break; - // destination around destination - case TARGET_DEST_DEST_RANDOM: + // area targets + case TARGET_ALL_ENEMY_IN_AREA_INSTANT: { - if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)) - { - sLog.outError("SPELL: no destination for spell ID %u\n", m_spellInfo->Id); + if(m_spellInfo->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA) break; - } - float x, y, z, dist, px, py, pz; - dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); - x = m_targets.m_destX; - y = m_targets.m_destY; - z = m_targets.m_destZ; - m_caster->GetRandomPoint(x, y, z, dist, px, py, pz); - m_targets.setDestination(px, py, pz); - TagUnitMap.push_back(m_caster); + m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION; + } + case TARGET_ALL_ENEMY_IN_AREA: + { + SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_AOE_DAMAGE); }break; - case TARGET_SELF2: + case TARGET_ALL_FRIENDLY_UNITS_IN_AREA: + m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION; + case TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER: { - TagUnitMap.push_back(m_caster); + SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_FRIENDLY); }break; - - case TARGET_SELF: case TARGET_AREAEFFECT_CUSTOM: - case TARGET_AREAEFFECT_CUSTOM_2: - { - TagUnitMap.push_back(m_caster); - break; - } - case TARGET_RANDOM_ENEMY_CHAIN_IN_AREA: + m_targets.m_targetMask |= TARGET_FLAG_DEST_LOCATION; + case TARGET_UNIT_AREA_ENTRY: { - m_targets.m_targetMask = 0; - unMaxTargets = EffectChainTarget; - float max_range = radius + unMaxTargets * CHAIN_SPELL_JUMP_RADIUS; - - CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - std::list<Unit *> tempUnitMap; - + SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id); + SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id); + if(lower==upper) { - Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(m_caster, m_caster, max_range); - Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(tempUnitMap, u_check); - - TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher); - TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher); - - CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - } - - if(tempUnitMap.empty()) + sLog.outErrorDb("Spell (ID: %u) has effect EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT, but does not have record in `spell_script_target`",m_spellInfo->Id); break; - - tempUnitMap.sort(TargetDistanceOrder(m_caster)); - - //Now to get us a random target that's in the initial range of the spell - uint32 t = 0; - std::list<Unit *>::iterator itr = tempUnitMap.begin(); - while(itr!= tempUnitMap.end() && (*itr)->GetDistance(m_caster) < radius) - ++t, ++itr; - - if(!t) - break; - - itr = tempUnitMap.begin(); - std::advance(itr, rand()%t); - Unit *pUnitTarget = *itr; - TagUnitMap.push_back(pUnitTarget); - - tempUnitMap.erase(itr); - - tempUnitMap.sort(TargetDistanceOrder(pUnitTarget)); - - t = unMaxTargets - 1; - Unit *prev = pUnitTarget; - std::list<Unit*>::iterator next = tempUnitMap.begin(); - - while(t && next != tempUnitMap.end() ) + } + // let it be done in one check? + for(SpellScriptTarget::const_iterator i_spellST = lower; i_spellST != upper; ++i_spellST) { - if(prev->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) - break; - - if(!prev->IsWithinLOSInMap(*next)) + if(i_spellST->second.type != SPELL_TARGET_TYPE_CREATURE) { - ++next; + sLog.outError( "SPELL: spell ID %u requires non-creature target\n", m_spellInfo->Id ); continue; } - - prev = *next; - TagUnitMap.push_back(prev); - tempUnitMap.erase(next); - tempUnitMap.sort(TargetDistanceOrder(prev)); - next = tempUnitMap.begin(); - - --t; + SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_ENTRY, i_spellST->second.targetEntry); } }break; - case TARGET_PET: + case TARGET_IN_FRONT_OF_CASTER: { - Pet* tmpUnit = m_caster->GetPet(); - if (!tmpUnit) break; - TagUnitMap.push_back(tmpUnit); - break; - } - case TARGET_CHAIN_DAMAGE: + bool inFront = m_spellInfo->SpellVisual != 3879; + SearchAreaTarget(TagUnitMap, radius, inFront ? PUSH_IN_FRONT : PUSH_IN_BACK,SPELL_TARGETS_AOE_DAMAGE); + }break; + + // nearby target + case TARGET_UNIT_NEARBY_ALLY: { - if (EffectChainTarget <= 1) + if(Unit* pUnitTarget = SearchNearbyTarget(radius, SPELL_TARGETS_FRIENDLY)) + TagUnitMap.push_back(pUnitTarget); + }break; + case TARGET_RANDOM_ENEMY_CHAIN_IN_AREA: + { + if(EffectChainTarget <= 1) { - Unit* pUnitTarget = SelectMagnetTarget(); - if(pUnitTarget) + if(Unit* pUnitTarget = SearchNearbyTarget(radius, SPELL_TARGETS_AOE_DAMAGE)) TagUnitMap.push_back(pUnitTarget); } else - { - Unit* pUnitTarget = m_targets.getUnitTarget(); - if(!pUnitTarget) - break; + SearchChainTarget(TagUnitMap, m_caster, radius, EffectChainTarget); + }break; + case TARGET_SCRIPT: + case TARGET_SCRIPT_COORDINATES: + { + SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id); + SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id); + if(lower==upper) + sLog.outErrorDb("Spell (ID: %u) has effect EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT or TARGET_SCRIPT_COORDINATES, but does not have record in `spell_script_target`",m_spellInfo->Id); - unMaxTargets = EffectChainTarget; + SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex); + float range = GetSpellMaxRange(srange); - float max_range; - if(m_spellInfo->DmgClass==SPELL_DAMAGE_CLASS_MELEE) - max_range = radius; // - else - //FIXME: This very like horrible hack and wrong for most spells - max_range = radius + unMaxTargets * CHAIN_SPELL_JUMP_RADIUS; + Creature* creatureScriptTarget = NULL; + GameObject* goScriptTarget = NULL; - CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - Unit* originalCaster = GetOriginalCaster(); - if(originalCaster) + for(SpellScriptTarget::const_iterator i_spellST = lower; i_spellST != upper; ++i_spellST) + { + switch(i_spellST->second.type) { - std::list<Unit *> tempUnitMap; - + case SPELL_TARGET_TYPE_GAMEOBJECT: { - Trinity::AnyAoETargetUnitInObjectRangeCheck u_check(pUnitTarget, originalCaster, max_range); - Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck> searcher(tempUnitMap, u_check); + GameObject* p_GameObject = NULL; - TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher); - TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyAoETargetUnitInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher); + if(i_spellST->second.targetEntry) + { + CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; - CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - } + Trinity::NearestGameObjectEntryInObjectRangeCheck go_check(*m_caster,i_spellST->second.targetEntry,range); + Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck> checker(p_GameObject,go_check); - tempUnitMap.sort(TargetDistanceOrder(pUnitTarget)); + TypeContainerVisitor<Trinity::GameObjectLastSearcher<Trinity::NearestGameObjectEntryInObjectRangeCheck>, GridTypeMapContainer > object_checker(checker); + CellLock<GridReadGuard> cell_lock(cell, p); + cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - if(tempUnitMap.empty()) + 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; - if(*tempUnitMap.begin() == pUnitTarget) - tempUnitMap.erase(tempUnitMap.begin()); + 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??? - TagUnitMap.push_back(pUnitTarget); - uint32 t = unMaxTargets - 1; - Unit *prev = pUnitTarget; - std::list<Unit*>::iterator next = tempUnitMap.begin(); + Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster,i_spellST->second.targetEntry,i_spellST->second.type!=SPELL_TARGET_TYPE_DEAD,range); + Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(p_Creature, u_check); - while(t && next != tempUnitMap.end() ) - { - if(prev->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) - break; + TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer > grid_creature_searcher(searcher); + + CellLock<GridReadGuard> cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_creature_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - if(!prev->IsWithinLOSInMap(*next)) + if(p_Creature ) { - ++next; - continue; + creatureScriptTarget = p_Creature; + goScriptTarget = NULL; + range = u_check.GetLastRange(); } - - prev = *next; - TagUnitMap.push_back(prev); - tempUnitMap.erase(next); - tempUnitMap.sort(TargetDistanceOrder(prev)); - next = tempUnitMap.begin(); - - --t; + break; } } } - }break; - case TARGET_ALL_ENEMY_IN_AREA: - { - }break; - case TARGET_ALL_ENEMY_IN_AREA_INSTANT: - { - // targets the ground, not the units in the area - if (m_spellInfo->Effect[i]!=SPELL_EFFECT_PERSISTENT_AREA_AURA) - { - CellPair p(Trinity::ComputeCellPair(m_targets.m_destX, m_targets.m_destY)); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_DEST_CENTER,SPELL_TARGETS_AOE_DAMAGE); - - TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier); - TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_object_notifier(notifier); - - CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - // exclude caster (this can be important if this not original caster) - TagUnitMap.remove(m_caster); - } - }break; - case TARGET_DUELVSPLAYER_COORDINATES: - { - if(Unit* currentTarget = m_targets.getUnitTarget()) + if(cur == TARGET_SCRIPT_COORDINATES) { - m_targets.setDestination(currentTarget->GetPositionX(), currentTarget->GetPositionY(), currentTarget->GetPositionZ()); - TagUnitMap.push_back(currentTarget); + if(creatureScriptTarget) + m_targets.setDestination(creatureScriptTarget->GetPositionX(),creatureScriptTarget->GetPositionY(),creatureScriptTarget->GetPositionZ()); + else if(goScriptTarget) + m_targets.setDestination(goScriptTarget->GetPositionX(),goScriptTarget->GetPositionY(),goScriptTarget->GetPositionZ()); } }break; + + + // dummy + case TARGET_AREAEFFECT_CUSTOM_2: + { + TagUnitMap.push_back(m_caster); + break; + } + case TARGET_ALL_PARTY_AROUND_CASTER: case TARGET_ALL_PARTY_AROUND_CASTER_2: case TARGET_ALL_PARTY: @@ -1534,66 +1579,6 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap) if(Player* target = ((Player*)m_caster)->GetNextRandomRaidMember(radius)) TagUnitMap.push_back(target); }break; - case TARGET_SINGLE_FRIEND: - case TARGET_SINGLE_FRIEND_2: - { - if(m_targets.getUnitTarget()) - TagUnitMap.push_back(m_targets.getUnitTarget()); - }break; - case TARGET_NONCOMBAT_PET: - { - if(Unit* target = m_targets.getUnitTarget()) - if( target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isPet() && ((Pet*)target)->getPetType() == MINI_PET) - TagUnitMap.push_back(target); - }break; - case TARGET_ALL_AROUND_CASTER: - { - CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_SELF_CENTER,SPELL_TARGETS_AOE_DAMAGE); - - TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier); - TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_object_notifier(notifier); - - CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - }break; - case TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER: - { - CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_SELF_CENTER,SPELL_TARGETS_FRIENDLY); - - TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier); - TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_object_notifier(notifier); - - CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - }break; - case TARGET_ALL_FRIENDLY_UNITS_IN_AREA: - { - CellPair p(Trinity::ComputeCellPair(m_targets.m_destX, m_targets.m_destY)); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, PUSH_DEST_CENTER,SPELL_TARGETS_FRIENDLY); - - TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier); - TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_object_notifier(notifier); - - CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - }break; // TARGET_SINGLE_PARTY means that the spells can only be casted on a party member and not on the caster (some sceals, fire shield from imp, etc..) case TARGET_SINGLE_PARTY: { @@ -1649,59 +1634,6 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap) } } }break; - case TARGET_GAMEOBJECT: - { - if(m_targets.getGOTarget()) - AddGOTarget(m_targets.getGOTarget(), i); - }break; - case TARGET_IN_FRONT_OF_CASTER: - { - CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - - bool inFront = m_spellInfo->SpellVisual != 3879; - Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, inFront ? PUSH_IN_FRONT : PUSH_IN_BACK,SPELL_TARGETS_AOE_DAMAGE); - - TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier); - TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_object_notifier(notifier); - - CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - }break; - case TARGET_DUELVSPLAYER: - { - Unit *target = m_targets.getUnitTarget(); - if(target) - { - if(m_caster->IsFriendlyTo(target)) - { - TagUnitMap.push_back(target); - } - else - { - Unit* pUnitTarget = SelectMagnetTarget(); - if(pUnitTarget) - TagUnitMap.push_back(pUnitTarget); - } - } - }break; - case TARGET_GAMEOBJECT_ITEM: - { - if(m_targets.getGOTargetGUID()) - AddGOTarget(m_targets.getGOTarget(), i); - else if(m_targets.getItemTarget()) - AddItemTarget(m_targets.getItemTarget(), i); - break; - } - case TARGET_MASTER: - { - if(Unit* owner = m_caster->GetCharmerOrOwner()) - TagUnitMap.push_back(owner); - break; - } case TARGET_ALL_ENEMY_IN_AREA_CHANNELED: { // targets the ground, not the units in the area @@ -1799,17 +1731,6 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap) } }break; - case TARGET_SCRIPT: - { - if(m_targets.getUnitTarget()) - TagUnitMap.push_back(m_targets.getUnitTarget()); - if(m_targets.getItemTarget()) - AddItemTarget(m_targets.getItemTarget(), i); - }break; - case TARGET_SELF_FISHING: - { - TagUnitMap.push_back(m_caster); - }break; case TARGET_CHAIN_HEAL: { Unit* pUnitTarget = m_targets.getUnitTarget(); @@ -1885,28 +1806,6 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap) } } }break; - case TARGET_CURRENT_ENEMY_COORDINATES: - { - Unit* currentTarget = m_targets.getUnitTarget(); - if(currentTarget) - { - TagUnitMap.push_back(currentTarget); - m_targets.setDestination(currentTarget->GetPositionX(), currentTarget->GetPositionY(), currentTarget->GetPositionZ()); - if(m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_ENEMY_IN_AREA_INSTANT) - { - CellPair p(Trinity::ComputeCellPair(currentTarget->GetPositionX(), currentTarget->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); - Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius,PUSH_TARGET_CENTER, SPELL_TARGETS_AOE_DAMAGE); - TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_notifier(notifier); - TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_notifier(notifier); - CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - } - } - }break; case TARGET_AREAEFFECT_PARTY_AND_CLASS: { Player* targetPlayer = m_targets.getUnitTarget() && m_targets.getUnitTarget()->GetTypeId() == TYPEID_PLAYER @@ -1932,40 +1831,106 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap) TagUnitMap.push_back(m_targets.getUnitTarget()); break; } - case TARGET_TABLE_X_Y_Z_COORDINATES: + + // destination around caster + case TARGET_DEST_CASTER_FRONT_LEFT: + case TARGET_DEST_CASTER_BACK_LEFT: + case TARGET_DEST_CASTER_BACK_RIGHT: + case TARGET_DEST_CASTER_FRONT_RIGHT: + case TARGET_DEST_CASTER_FRONT: + case TARGET_DEST_CASTER_BACK: + case TARGET_DEST_CASTER_RIGHT: + case TARGET_DEST_CASTER_LEFT: + case TARGET_DEST_CASTER_RANDOM: + case TARGET_DEST_CASTER_RADIUS: { - SpellTargetPosition const* st = spellmgr.GetSpellTargetPosition(m_spellInfo->Id); - if(st) + float x, y, z, angle, dist; + + if (m_spellInfo->EffectRadiusIndex[i]) + dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + else + dist = 3.0f;//do we need this? + if (cur == TARGET_DEST_CASTER_RANDOM) + dist *= rand_norm(); // This case we need to consider caster size + else + dist -= m_caster->GetObjectSize(); // Size is calculated in GetNearPoint(), but we do not need it + //need a new function to remove this repeated work + + switch(cur) { - if (st->target_mapId == m_caster->GetMapId()) - m_targets.setDestination(st->target_X, st->target_Y, st->target_Z); + case TARGET_DEST_CASTER_FRONT_LEFT: angle = -M_PI/4; break; + case TARGET_DEST_CASTER_BACK_LEFT: angle = -3*M_PI/4; break; + case TARGET_DEST_CASTER_BACK_RIGHT: angle = 3*M_PI/4; break; + case TARGET_DEST_CASTER_FRONT_RIGHT:angle = M_PI/4; break; + case TARGET_DEST_CASTER_FRONT: angle = 0.0f; break; + case TARGET_DEST_CASTER_BACK: angle = M_PI; break; + case TARGET_DEST_CASTER_RIGHT: angle = M_PI/2; break; + case TARGET_DEST_CASTER_LEFT: angle = -M_PI/2; break; + default: angle = rand_norm()*2*M_PI; break; + } - // if B==TARGET_TABLE_X_Y_Z_COORDINATES then A already fill all required targets - if (m_spellInfo->EffectImplicitTargetB[i] && m_spellInfo->EffectImplicitTargetB[i]!=TARGET_TABLE_X_Y_Z_COORDINATES) - { - CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); - Cell cell(p); - cell.data.Part.reserved = ALL_DISTRICT; - cell.SetNoCreate(); + m_caster->GetClosePoint(x, y, z, 0, dist, angle); + m_targets.setDestination(x, y, z); // do not know if has ground visual + }break; - SpellTargets targetB = SPELL_TARGETS_AOE_DAMAGE; - // Select friendly targets for positive effect - if (IsPositiveEffect(m_spellInfo->Id, i)) - targetB = SPELL_TARGETS_FRIENDLY; + // destination around target + case TARGET_DEST_TARGET_FRONT: + case TARGET_DEST_TARGET_BACK: + case TARGET_DEST_TARGET_RIGHT: + case TARGET_DEST_TARGET_LEFT: + case TARGET_DEST_TARGET_RANDOM: + case TARGET_DEST_TARGET_RADIUS: + { + Unit *target = m_targets.getUnitTarget(); + if(!target) + { + sLog.outError("SPELL: no unit target for spell ID %u\n", m_spellInfo->Id); + break; + } - Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius,PUSH_DEST_CENTER, targetB); + float x, y, z, angle, dist; - TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_notifier(notifier); - TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, GridTypeMapContainer > grid_notifier(notifier); + if (m_spellInfo->EffectRadiusIndex[i]) + dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + else + dist = 3.0f;//do we need this? + if (cur == TARGET_DEST_TARGET_RANDOM) + dist *= rand_norm(); // This case we need to consider caster size + else + dist -= target->GetObjectSize(); // Size is calculated in GetNearPoint(), but we do not need it + //need a new function to remove this repeated work - CellLock<GridReadGuard> cell_lock(cell, p); - cell_lock->Visit(cell_lock, world_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - cell_lock->Visit(cell_lock, grid_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - } + switch(cur) + { + case TARGET_DEST_TARGET_FRONT: angle = 0.0f; break; + case TARGET_DEST_TARGET_BACK: angle = M_PI; break; + case TARGET_DEST_TARGET_RIGHT: angle = M_PI/2; break; + case TARGET_DEST_TARGET_LEFT: angle = -M_PI/2; break; + default: angle = rand_norm()*2*M_PI; break; } - else - sLog.outError( "SPELL: unknown target coordinates for spell ID %u\n", m_spellInfo->Id ); + + target->GetClosePoint(x, y, z, 0, dist, angle); + m_targets.setDestination(x, y, z); // do not know if has ground visual + }break; + + // destination around destination + case TARGET_DEST_DEST_RANDOM: + { + if(!(m_targets.m_targetMask & TARGET_FLAG_DEST_LOCATION)) + { + sLog.outError("SPELL: no destination for spell ID %u\n", m_spellInfo->Id); + break; + } + float x, y, z, dist, px, py, pz; + dist = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[i])); + x = m_targets.m_destX; + y = m_targets.m_destY; + z = m_targets.m_destZ; + m_caster->GetRandomPoint(x, y, z, dist, px, py, pz); + m_targets.setDestination(px, py, pz); }break; + case TARGET_SELF2: + break; default: break; } @@ -2012,9 +1977,7 @@ void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura) m_spellState = SPELL_STATE_PREPARING; - m_castPositionX = m_caster->GetPositionX(); - m_castPositionY = m_caster->GetPositionY(); - m_castPositionZ = m_caster->GetPositionZ(); + m_caster->GetPosition(m_castPositionX, m_castPositionY, m_castPositionZ); m_castOrientation = m_caster->GetOrientation(); if(triggeredByAura) @@ -2170,6 +2133,9 @@ void Spell::cast(bool skipCheck) } } + FillTargetMap(); + + // who did this hack? // Conflagrate - consumes immolate if ((m_spellInfo->TargetAuraState == AURA_STATE_IMMOLATE) && m_targets.getUnitTarget()) { @@ -2195,7 +2161,6 @@ void Spell::cast(bool skipCheck) TakePower(); TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot - FillTargetMap(); if(m_spellState == SPELL_STATE_FINISHED) // stop cast if spell marked as finish somewhere in Take*/FillTargetMap return; @@ -3438,143 +3403,6 @@ uint8 Spell::CanCast(bool strict) if(uint8 castResult = CheckItems()) return castResult; - //ImpliciteTargetA-B = 38, If fact there is 0 Spell with ImpliciteTargetB=38 - if(m_UniqueTargetInfo.empty()) // skip second canCast apply (for delayed spells for example) - { - for(uint8 j = 0; j < 3; j++) - { - if( m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT || - m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT && m_spellInfo->EffectImplicitTargetA[j] != TARGET_SELF || - m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || - m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES ) - { - bool okDoo = false; - - SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id); - SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id); - if(lower==upper) - sLog.outErrorDb("Spell (ID: %u) has effect EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT or TARGET_SCRIPT_COORDINATES, 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 = lower; i_spellST != upper; ++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(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, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - - 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(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, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - - if(p_Creature ) - { - creatureScriptTarget = p_Creature; - goScriptTarget = NULL; - range = u_check.GetLastRange(); - } - break; - } - } - } - - if(creatureScriptTarget) - { - // store coordinates for TARGET_SCRIPT_COORDINATES - if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || - m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES ) - { - m_targets.setDestination(creatureScriptTarget->GetPositionX(),creatureScriptTarget->GetPositionY(),creatureScriptTarget->GetPositionZ()); - - if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES && m_spellInfo->EffectImplicitTargetB[j] == 0 && m_spellInfo->Effect[j]!=SPELL_EFFECT_PERSISTENT_AREA_AURA) - AddUnitTarget(creatureScriptTarget, j); - } - // store explicit target for TARGET_SCRIPT - else - AddUnitTarget(creatureScriptTarget, j); - } - else if(goScriptTarget) - { - // store coordinates for TARGET_SCRIPT_COORDINATES - if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES || - m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES ) - { - m_targets.setDestination(goScriptTarget->GetPositionX(),goScriptTarget->GetPositionY(),goScriptTarget->GetPositionZ()); - - if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES && m_spellInfo->EffectImplicitTargetB[j] == 0 && m_spellInfo->Effect[j]!=SPELL_EFFECT_PERSISTENT_AREA_AURA) - AddGOTarget(goScriptTarget, j); - } - // store explicit target for TARGET_SCRIPT - 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(uint8 castResult = CheckRange(strict)) return castResult; diff --git a/src/game/Spell.h b/src/game/Spell.h index 5f7ec033381..e66a5af0876 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -75,14 +75,12 @@ enum SpellNotifyPushType PUSH_IN_BACK, PUSH_SELF_CENTER, PUSH_DEST_CENTER, - PUSH_TARGET_CENTER }; bool IsQuestTameSpell(uint32 spellId); namespace Trinity { - struct SpellNotifierPlayer; struct SpellNotifierCreatureAndPlayer; } @@ -180,13 +178,27 @@ enum SpellState SPELL_STATE_DELAYED = 5 }; +enum ReplenishType +{ + REPLENISH_UNDEFINED = 0, + REPLENISH_HEALTH = 20, + REPLENISH_MANA = 21, + REPLENISH_RAGE = 22 +}; + +enum SpellTargets +{ + SPELL_TARGETS_FRIENDLY, + SPELL_TARGETS_AOE_DAMAGE, + SPELL_TARGETS_ENTRY +}; + #define SPELL_SPELL_CHANNEL_UPDATE_INTERVAL 1000 typedef std::multimap<uint64, uint64> SpellTargetTimeMap; class Spell { - friend struct Trinity::SpellNotifierPlayer; friend struct Trinity::SpellNotifierCreatureAndPlayer; public: @@ -497,6 +509,10 @@ class Spell void DoAllEffectOnTarget(GOTargetInfo *target); void DoAllEffectOnTarget(ItemTargetInfo *target); bool IsAliveUnitPresentInTargetList(); + void SearchAreaTarget(std::list<Unit*> &data, float radius, const uint32 &type, + 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); // ------------------------------------------- //List For Triggered Spells @@ -518,60 +534,8 @@ class Spell SpellEntry const* m_triggeredByAuraSpell; }; -enum ReplenishType -{ - REPLENISH_UNDEFINED = 0, - REPLENISH_HEALTH = 20, - REPLENISH_MANA = 21, - REPLENISH_RAGE = 22 -}; - -enum SpellTargets -{ - SPELL_TARGETS_HOSTILE, - SPELL_TARGETS_NOT_FRIENDLY, - SPELL_TARGETS_NOT_HOSTILE, - SPELL_TARGETS_FRIENDLY, - SPELL_TARGETS_AOE_DAMAGE -}; - namespace Trinity { - struct TRINITY_DLL_DECL SpellNotifierPlayer - { - std::list<Unit*> &i_data; - Spell &i_spell; - const uint32& i_index; - float i_radius; - Unit* i_originalCaster; - - SpellNotifierPlayer(Spell &spell, std::list<Unit*> &data, const uint32 &i, float radius) - : i_data(data), i_spell(spell), i_index(i), i_radius(radius) - { - i_originalCaster = i_spell.GetOriginalCaster(); - } - - void Visit(PlayerMapType &m) - { - if(!i_originalCaster) - return; - - for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - { - Player * pPlayer = itr->getSource(); - if( !pPlayer->isAlive() || pPlayer->isInFlight()) - continue; - - if( i_originalCaster->IsFriendlyTo(pPlayer) ) - continue; - - if( pPlayer->GetDistance(i_spell.m_targets.m_destX, i_spell.m_targets.m_destY, i_spell.m_targets.m_destZ) < i_radius ) - i_data.push_back(pPlayer); - } - } - template<class SKIP> void Visit(GridRefManager<SKIP> &) {} - }; - struct TRINITY_DLL_DECL SpellNotifierCreatureAndPlayer { std::list<Unit*> *i_data; @@ -580,10 +544,11 @@ namespace Trinity float i_radius; SpellTargets i_TargetType; Unit* i_originalCaster; + uint32 i_entry; SpellNotifierCreatureAndPlayer(Spell &spell, std::list<Unit*> &data, float radius, const uint32 &type, - SpellTargets TargetType = SPELL_TARGETS_NOT_FRIENDLY) - : i_data(&data), i_spell(spell), i_push_type(type), i_radius(radius), i_TargetType(TargetType) + SpellTargets TargetType = SPELL_TARGETS_AOE_DAMAGE, uint32 entry = 0) + : i_data(&data), i_spell(spell), i_push_type(type), i_radius(radius), i_TargetType(TargetType), i_entry(entry) { i_originalCaster = spell.GetOriginalCaster(); } @@ -602,18 +567,6 @@ namespace Trinity switch (i_TargetType) { - case SPELL_TARGETS_HOSTILE: - if (!itr->getSource()->isTargetableForAttack() || !i_originalCaster->IsHostileTo( itr->getSource() )) - continue; - break; - case SPELL_TARGETS_NOT_FRIENDLY: - if (!itr->getSource()->isTargetableForAttack() || i_originalCaster->IsFriendlyTo( itr->getSource() )) - continue; - break; - case SPELL_TARGETS_NOT_HOSTILE: - if (!itr->getSource()->isTargetableForAttack() || i_originalCaster->IsHostileTo( itr->getSource() )) - continue; - break; case SPELL_TARGETS_FRIENDLY: if (!itr->getSource()->isTargetableForAttack() || !i_originalCaster->IsFriendlyTo( itr->getSource() )) continue; @@ -637,8 +590,12 @@ namespace Trinity if (!check->IsHostileTo( itr->getSource() )) continue; } - } - break; + }break; + case SPELL_TARGETS_ENTRY: + { + if(itr->getSource()->GetTypeId()!=TYPEID_UNIT || itr->getSource()->GetEntry()!= i_entry) + continue; + }break; default: continue; } @@ -660,10 +617,6 @@ namespace Trinity if((itr->getSource()->GetDistance(i_spell.m_targets.m_destX, i_spell.m_targets.m_destY, i_spell.m_targets.m_destZ) < i_radius )) i_data->push_back(itr->getSource()); break; - case PUSH_TARGET_CENTER: - if(i_spell.m_targets.getUnitTarget()->IsWithinDistInMap((Unit*)(itr->getSource()), i_radius)) - i_data->push_back(itr->getSource()); - break; } } } diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index bafc54ba2f0..efb83aa0fe2 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -1793,7 +1793,7 @@ void SpellMgr::LoadSpellScriptTarget() continue; } - bool targetfound = false; + /*bool targetfound = false; for(int i = 0; i <3; ++i) { if( spellProto->EffectImplicitTargetA[i]==TARGET_SCRIPT || @@ -1809,7 +1809,7 @@ void SpellMgr::LoadSpellScriptTarget() { sLog.outErrorDb("Table `spell_script_target`: spellId %u listed for TargetEntry %u does not have any implicit target TARGET_SCRIPT(38) or TARGET_SCRIPT_COORDINATES (46).",spellId,targetEntry); continue; - } + }*/ if( type >= MAX_SPELL_TARGET_TYPE ) { |