From e35d07ad81f5acedcbe436bf429db5581edc6b81 Mon Sep 17 00:00:00 2001 From: megamage Date: Sat, 9 May 2009 10:50:41 -0500 Subject: *Update Sapphiron script. --HG-- branch : trunk --- src/game/Object.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'src/game/Object.cpp') diff --git a/src/game/Object.cpp b/src/game/Object.cpp index f649164e21b..6b7a3cdd4ac 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -1309,6 +1309,21 @@ bool WorldObject::HasInArc(const float arcangle, const WorldObject* obj) const return (( angle >= lborder ) && ( angle <= rborder )); } +bool WorldObject::IsInBetween(const WorldObject *obj1, const WorldObject *obj2, float size) const +{ + if(GetPositionX() > std::max(obj1->GetPositionX(), obj2->GetPositionX()) + || GetPositionX() < std::min(obj1->GetPositionX(), obj2->GetPositionX()) + || GetPositionY() > std::max(obj1->GetPositionY(), obj2->GetPositionY()) + || GetPositionY() < std::min(obj1->GetPositionY(), obj2->GetPositionY())) + return false; + + if(!size) + size = GetObjectSize() / 2; + + float angle = obj1->GetAngle(this) - obj1->GetAngle(obj2); + return abs(sin(angle)) * GetExactDistance2d(obj1->GetPositionX(), obj1->GetPositionY()) < size; +} + void WorldObject::GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z) const { if(distance==0) @@ -1658,6 +1673,8 @@ TempSummon *Map::SummonCreature(uint32 entry, float x, float y, float z, float a return NULL; } + summon->SetHomePosition(x, y, z, angle); + summon->InitStats(duration); Add((Creature*)summon); summon->InitSummon(); @@ -1680,7 +1697,6 @@ TempSummon* WorldObject::SummonCreature(uint32 entry, float x, float y, float z, if(!pCreature) return NULL; - pCreature->SetHomePosition(x, y, z, ang); pCreature->SetTempSummonType(spwtype); return pCreature; -- cgit v1.2.3 From 40a8e6d3aba7410fe34c4b6b81f4036f26e0f338 Mon Sep 17 00:00:00 2001 From: megamage Date: Sun, 10 May 2009 14:29:28 -0500 Subject: *Rename some script functions (no real change). --HG-- branch : trunk --- src/bindings/scripts/include/sc_creature.cpp | 150 +-------------------- src/bindings/scripts/include/sc_creature.h | 4 +- .../shadow_labyrinth/boss_grandmaster_vorpil.cpp | 2 +- .../aunchindoun/shadow_labyrinth/boss_murmur.cpp | 4 +- .../scripts/zone/black_temple/boss_illidan.cpp | 12 +- .../scripts/zone/black_temple/boss_supremus.cpp | 4 +- .../zone/black_temple/boss_warlord_najentus.cpp | 2 +- .../zone/caverns_of_time/hyjal/boss_anetheron.cpp | 6 +- .../zone/caverns_of_time/hyjal/boss_azgalor.cpp | 6 +- .../hyjal/boss_rage_winterchill.cpp | 2 +- .../zone/caverns_of_time/hyjal/hyjal_trash.cpp | 2 +- .../serpent_shrine/boss_lurker_below.cpp | 2 +- .../serpent_shrine/boss_morogrim_tidewalker.cpp | 4 +- .../underbog/boss_the_black_stalker.cpp | 2 +- .../scripts/scripts/zone/naxxramas/boss_gothik.cpp | 5 +- .../scripts/zone/sunwell_plateau/boss_felmyst.cpp | 8 +- .../zone/sunwell_plateau/boss_kiljaeden.cpp | 8 +- .../scripts/zone/sunwell_plateau/boss_muru.cpp | 10 +- .../zone/tempest_keep/the_eye/boss_alar.cpp | 2 +- .../zone/tempest_keep/the_eye/boss_astromancer.cpp | 4 +- .../zone/tempest_keep/the_eye/boss_kaelthas.cpp | 6 +- .../zone/temple_of_ahnqiraj/boss_twinemperors.cpp | 6 +- .../scripts/scripts/zone/zulaman/boss_akilzon.cpp | 2 +- .../scripts/scripts/zone/zulaman/boss_hexlord.cpp | 2 +- .../scripts/scripts/zone/zulaman/boss_nalorakk.cpp | 2 +- src/game/CreatureAI.cpp | 144 ++++++++++++++++++++ src/game/CreatureAI.h | 34 ++++- src/game/Object.cpp | 8 ++ src/game/Object.h | 1 + src/game/Unit.cpp | 4 +- src/game/Unit.h | 4 +- 31 files changed, 246 insertions(+), 206 deletions(-) (limited to 'src/game/Object.cpp') diff --git a/src/bindings/scripts/include/sc_creature.cpp b/src/bindings/scripts/include/sc_creature.cpp index 82743bcd9e5..4a9f8ec61e8 100644 --- a/src/bindings/scripts/include/sc_creature.cpp +++ b/src/bindings/scripts/include/sc_creature.cpp @@ -259,147 +259,7 @@ Unit* ScriptedAI::SelectUnit(SelectAggroTarget target, uint32 position) return NULL; } -struct TargetDistanceOrder : public std::binary_function -{ - const Unit* me; - TargetDistanceOrder(const Unit* Target) : me(Target) {}; - // functor for operator ">" - bool operator()(const Unit* _Left, const Unit* _Right) const - { - return (me->GetDistance(_Left) < me->GetDistance(_Right)); - } -}; - -Unit* ScriptedAI::SelectUnit(SelectAggroTarget targetType, uint32 position, float dist, bool playerOnly) -{ - if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST) - { - std::list &m_threatlist = m_creature->getThreatManager().getThreatList(); - if(m_threatlist.empty()) return NULL; - std::list targetList; - std::list::iterator itr = m_threatlist.begin(); - for(; itr!= m_threatlist.end(); ++itr) - { - Unit *target = (*itr)->getTarget(); - if(!target - || playerOnly && target->GetTypeId() != TYPEID_PLAYER - || dist && !m_creature->IsWithinCombatRange(target, dist)) - { - continue; - } - targetList.push_back(target); - } - if(position >= targetList.size()) - return NULL; - targetList.sort(TargetDistanceOrder(m_creature)); - if(targetType == SELECT_TARGET_NEAREST) - { - std::list::iterator i = targetList.begin(); - advance(i, position); - return *i; - } - else - { - std::list::reverse_iterator i = targetList.rbegin(); - advance(i, position); - return *i; - } - } - else - { - std::list m_threatlist = m_creature->getThreatManager().getThreatList(); - std::list::iterator i; - Unit *target; - while(position < m_threatlist.size()) - { - if(targetType == SELECT_TARGET_BOTTOMAGGRO) - { - i = m_threatlist.end(); - advance(i, - (int32)position - 1); - } - else - { - i = m_threatlist.begin(); - if(targetType == SELECT_TARGET_TOPAGGRO) - advance(i, position); - else // random - advance(i, position + rand()%(m_threatlist.size() - position)); - } - - target = (*i)->getTarget(); - if(!target - || playerOnly && target->GetTypeId() != TYPEID_PLAYER - || dist && !m_creature->IsWithinCombatRange(target, dist)) - { - m_threatlist.erase(i); - } - else - { - return target; - } - } - } - - return NULL; -} - -void ScriptedAI::SelectUnitList(std::list &targetList, uint32 num, SelectAggroTarget targetType, float dist, bool playerOnly) -{ - if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST) - { - std::list &m_threatlist = m_creature->getThreatManager().getThreatList(); - if(m_threatlist.empty()) return; - std::list::iterator itr = m_threatlist.begin(); - for(; itr!= m_threatlist.end(); ++itr) - { - Unit *target = (*itr)->getTarget(); - if(!target - || playerOnly && target->GetTypeId() != TYPEID_PLAYER - || dist && !m_creature->IsWithinCombatRange(target, dist)) - { - continue; - } - targetList.push_back(target); - } - targetList.sort(TargetDistanceOrder(m_creature)); - targetList.resize(num); - if(targetType == SELECT_TARGET_FARTHEST) - targetList.reverse(); - } - else - { - std::list m_threatlist = m_creature->getThreatManager().getThreatList(); - std::list::iterator i; - Unit *target; - while(m_threatlist.size() && num) - { - if(targetType == SELECT_TARGET_BOTTOMAGGRO) - { - i = m_threatlist.end(); - --i; - } - else - { - i = m_threatlist.begin(); - if(targetType == SELECT_TARGET_RANDOM) - advance(i, rand()%m_threatlist.size()); - } - - target = (*i)->getTarget(); - m_threatlist.erase(i); - if(!target - || playerOnly && target->GetTypeId() != TYPEID_PLAYER - || dist && !m_creature->IsWithinCombatRange(target, dist)) - { - continue; - } - targetList.push_back(target); - --num; - } - } -} - -SpellEntry const* ScriptedAI::SelectSpell(Unit* Target, int32 School, int32 Mechanic, SelectTarget Targets, uint32 PowerCostMin, uint32 PowerCostMax, float RangeMin, float RangeMax, SelectEffect Effects) +SpellEntry const* ScriptedAI::SelectSpell(Unit* Target, int32 School, int32 Mechanic, SelectTargetType Targets, uint32 PowerCostMin, uint32 PowerCostMax, float RangeMin, float RangeMax, SelectEffect Effects) { //No target so we can't cast if (!Target) @@ -531,7 +391,7 @@ void FillSpellSummary() SpellEntry const* TempSpell; - for (int i=0; i < GetSpellStore()->GetNumRows(); i++ ) + for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i) { SpellSummary[i].Effects = 0; SpellSummary[i].Targets = 0; @@ -541,7 +401,7 @@ void FillSpellSummary() if (!TempSpell) continue; - for (int j=0; j<3; j++) + for(uint32 j = 0; j < 3; ++j) { //Spell targets self if ( TempSpell->EffectImplicitTargetA[j] == TARGET_UNIT_CASTER ) @@ -802,10 +662,6 @@ void LoadOverridenDBCData() if(spellInfo = SPELL(41913)) spellInfo->EffectApplyAuraName[0] = 4; // proc debuff, and summon infinite fiends - // Naxxramas : Sapphiron : Frost Breath Visual Effect - //if(spellInfo = SPELL(30101)) - // spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DEST; // orig 18 - //temp, not needed in 310 if(spellInfo = SPELL(28531)) { diff --git a/src/bindings/scripts/include/sc_creature.h b/src/bindings/scripts/include/sc_creature.h index c2c93a520a9..44caf063162 100644 --- a/src/bindings/scripts/include/sc_creature.h +++ b/src/bindings/scripts/include/sc_creature.h @@ -227,13 +227,11 @@ struct TRINITY_DLL_DECL ScriptedAI : public CreatureAI //Selects a unit from the creature's current aggro list Unit* SelectUnit(SelectAggroTarget target, uint32 position); - Unit* SelectUnit(SelectAggroTarget target, uint32 position, float dist, bool playerOnly); - void SelectUnitList(std::list &targetList, uint32 num, SelectAggroTarget target, float dist, bool playerOnly); bool HealthBelowPct(uint32 pct) const { return me->GetHealth() * 100 < m_creature->GetMaxHealth() * pct; } //Returns spells that meet the specified criteria from the creatures spell list - SpellEntry const* SelectSpell(Unit* Target, int32 School, int32 Mechanic, SelectTarget Targets, uint32 PowerCostMin, uint32 PowerCostMax, float RangeMin, float RangeMax, SelectEffect Effect); + SpellEntry const* SelectSpell(Unit* Target, int32 School, int32 Mechanic, SelectTargetType Targets, uint32 PowerCostMin, uint32 PowerCostMax, float RangeMin, float RangeMax, SelectEffect Effect); //Checks if you can cast the specified spell bool CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered = false); diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp index 89fd75b9bc8..52e5a3e8915 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp @@ -262,7 +262,7 @@ struct TRINITY_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI if (HeroicMode && banish_Timer < diff) { - Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0,30,false); + Unit *target = SelectTarget(SELECT_TARGET_RANDOM,0,30,false); if (target) { DoCast(target,SPELL_BANISH); diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_murmur.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_murmur.cpp index 99bce54be62..599767b591f 100644 --- a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_murmur.cpp +++ b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_murmur.cpp @@ -118,7 +118,7 @@ struct TRINITY_DLL_DECL boss_murmurAI : public Scripted_NoMovementAI // Murmur's Touch if (MurmursTouch_Timer < diff) { - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0,80,true)) + if(Unit* target = SelectTarget(SELECT_TARGET_RANDOM,0,80,true)) DoCast(target, SPELL_MURMURS_TOUCH); MurmursTouch_Timer = 25000 + rand()%10000; }else MurmursTouch_Timer -= diff; @@ -162,7 +162,7 @@ struct TRINITY_DLL_DECL boss_murmurAI : public Scripted_NoMovementAI // Sonic Shock if(SonicShock_Timer < diff) { - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0,20,false)) + if(Unit* target = SelectTarget(SELECT_TARGET_RANDOM,0,20,false)) if(target->isAlive()) DoCast(target, SPELL_SONIC_SHOCK); SonicShock_Timer = 10000+rand()%10000; 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 60c51f0be33..68431cb81ee 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp @@ -785,7 +785,7 @@ struct TRINITY_DLL_DECL boss_illidan_stormrageAI : public ScriptedAI case EVENT_PARASITIC_SHADOWFIEND: { - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1, 200, true)) + if(Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 200, true)) m_creature->CastSpell(target, SPELL_PARASITIC_SHADOWFIEND, true); Timer[EVENT_PARASITIC_SHADOWFIEND] = 35000 + rand()%10000; }break; @@ -907,7 +907,7 @@ struct TRINITY_DLL_DECL flame_of_azzinothAI : public ScriptedAI void ChargeCheck() { - Unit* target = SelectUnit(SELECT_TARGET_FARTHEST, 0, 200, false); + Unit* target = SelectTarget(SELECT_TARGET_FARTHEST, 0, 200, false); if(target && (!m_creature->IsWithinCombatRange(target, FLAME_CHARGE_DISTANCE))) { m_creature->AddThreat(target, 5000000.0f); @@ -1765,7 +1765,7 @@ struct TRINITY_DLL_DECL mob_parasitic_shadowfiendAI : public ScriptedAI { if(!m_creature->getVictim()) { - if(Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0, 999, true)) + if(Unit *target = SelectTarget(SELECT_TARGET_RANDOM, 0, 999, true)) AttackStart(target); else { @@ -1862,15 +1862,15 @@ void boss_illidan_stormrageAI::JustSummoned(Creature* summon) summon->setDeathState(JUST_DIED); return; } - Unit *target = SelectUnit(SELECT_TARGET_TOPAGGRO, 0, 999, true); + Unit *target = SelectTarget(SELECT_TARGET_TOPAGGRO, 0, 999, true); if(!target || target->HasAura(SPELL_PARASITIC_SHADOWFIEND) || target->HasAura(SPELL_PARASITIC_SHADOWFIEND2)) - target = SelectUnit(SELECT_TARGET_RANDOM, 0, 999, true); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 999, true); if(target) summon->AI()->AttackStart(target); }break; case SHADOW_DEMON: - if(Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0, 999, true)) // only on players. + if(Unit *target = SelectTarget(SELECT_TARGET_RANDOM, 0, 999, true)) // only on players. { summon->AddThreat(target, 5000000.0f); summon->AI()->AttackStart(target); diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp index c01db75bd58..fdfdef396bb 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_supremus.cpp @@ -198,7 +198,7 @@ struct TRINITY_DLL_DECL boss_supremusAI : public ScriptedAI events.ScheduleEvent(EVENT_HATEFUL_STRIKE, 5000, GCD_CAST, PHASE_STRIKE); break; case EVENT_SWITCH_TARGET: - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1, 100, true)) + if(Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100, true)) { DoResetThreat(); m_creature->AddThreat(target, 5000000.0f); @@ -208,7 +208,7 @@ struct TRINITY_DLL_DECL boss_supremusAI : public ScriptedAI break; case EVENT_VOLCANO: { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0, 999, true); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 999, true); if(!target) target = m_creature->getVictim(); if(target) { diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp index 7d6b7140a9d..032bccc57ed 100644 --- a/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp +++ b/src/bindings/scripts/scripts/zone/black_temple/boss_warlord_najentus.cpp @@ -171,7 +171,7 @@ struct TRINITY_DLL_DECL boss_najentusAI : public ScriptedAI { //m_creature->CastSpell(m_creature, SPELL_NEEDLE_SPINE, true); std::list target; - SelectUnitList(target, 3, SELECT_TARGET_RANDOM, 80, true); + SelectTargetList(target, 3, SELECT_TARGET_RANDOM, 80, true); for(std::list::iterator i = target.begin(); i != target.end(); ++i) m_creature->CastSpell(*i, 39835, true); events.ScheduleEvent(EVENT_NEEDLE, 15000+rand()%10000, GCD_CAST); diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_anetheron.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_anetheron.cpp index 21b39fa378b..13b0c78ebc1 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_anetheron.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_anetheron.cpp @@ -148,7 +148,7 @@ struct TRINITY_DLL_DECL boss_anetheronAI : public hyjal_trashAI if(SwarmTimer < diff) { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0,100,true); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM,0,100,true); if(target) DoCast(target,SPELL_CARRION_SWARM); @@ -170,7 +170,7 @@ struct TRINITY_DLL_DECL boss_anetheronAI : public hyjal_trashAI { for(uint8 i=0;i<3;++i) { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0,100,true); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM,0,100,true); if(target) target->CastSpell(target,SPELL_SLEEP,true); } @@ -194,7 +194,7 @@ struct TRINITY_DLL_DECL boss_anetheronAI : public hyjal_trashAI }else AuraTimer -= diff; if(InfernoTimer < diff) { - DoCast(SelectUnit(SELECT_TARGET_RANDOM,0,100,true), SPELL_INFERNO); + DoCast(SelectTarget(SELECT_TARGET_RANDOM,0,100,true), SPELL_INFERNO); InfernoTimer = 45000; switch(rand()%2) { diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_azgalor.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_azgalor.cpp index 15085963b20..33e3d344da2 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_azgalor.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_azgalor.cpp @@ -140,13 +140,13 @@ struct TRINITY_DLL_DECL boss_azgalorAI : public hyjal_trashAI if(RainTimer < diff) { - DoCast(SelectUnit(SELECT_TARGET_RANDOM,0,30,true), SPELL_RAIN_OF_FIRE); + DoCast(SelectTarget(SELECT_TARGET_RANDOM,0,30,true), SPELL_RAIN_OF_FIRE); RainTimer = 20000+rand()%15000; }else RainTimer -= diff; if(DoomTimer < diff) { - DoCast(SelectUnit(SELECT_TARGET_RANDOM,1,100,true), SPELL_DOOM);//never on tank + DoCast(SelectTarget(SELECT_TARGET_RANDOM,1,100,true), SPELL_DOOM);//never on tank DoomTimer = 45000+rand()%5000; }else DoomTimer -= diff; @@ -260,7 +260,7 @@ struct TRINITY_DLL_DECL mob_lesser_doomguardAI : public hyjal_trashAI if(CrippleTimer < diff) { - DoCast(SelectUnit(SELECT_TARGET_RANDOM,0,100,true), SPELL_CRIPPLE); + DoCast(SelectTarget(SELECT_TARGET_RANDOM,0,100,true), SPELL_CRIPPLE); CrippleTimer = 25000+rand()%5000; }else CrippleTimer -= diff; diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_rage_winterchill.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_rage_winterchill.cpp index addbddab5b8..3e6b2bc8e98 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_rage_winterchill.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/boss_rage_winterchill.cpp @@ -169,7 +169,7 @@ struct TRINITY_DLL_DECL boss_rage_winterchillAI : public hyjal_trashAI }else NovaTimer -= diff; if(IceboltTimer < diff) { - DoCast(SelectUnit(SELECT_TARGET_RANDOM,0,40,true), SPELL_ICEBOLT); + DoCast(SelectTarget(SELECT_TARGET_RANDOM,0,40,true), SPELL_ICEBOLT); IceboltTimer = 11000+rand()%20000; }else IceboltTimer -= diff; diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal_trash.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal_trash.cpp index 583c7831af5..30f0c14caaf 100644 --- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal_trash.cpp +++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjal_trash.cpp @@ -724,7 +724,7 @@ struct mob_necromancerAI : public hyjal_trashAI void JustSummoned(Creature* summon) { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM,0,30,true); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM,0,30,true); if(target && summon) summon->Attack(target,false); summons.Summon(summon); diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lurker_below.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lurker_below.cpp index eb35a3c74b4..254a4d1d899 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lurker_below.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lurker_below.cpp @@ -322,7 +322,7 @@ struct TRINITY_DLL_DECL boss_the_lurker_belowAI : public Scripted_NoMovementAI if(WaterboltTimer < diff) { - Unit* target = SelectUnit(SELECT_TARGET_NEAREST,0,14,true); + Unit* target = SelectTarget(SELECT_TARGET_NEAREST,0,14,true); if(!target) { target = SelectUnit(SELECT_TARGET_RANDOM,0); diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp index cea591182d5..f8d27df5bb0 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp @@ -235,7 +235,7 @@ struct TRINITY_DLL_DECL boss_morogrim_tidewalkerAI : public ScriptedAI for(uint8 i = 0; i < 4; i++) { counter = 0; - do{target = SelectUnit(SELECT_TARGET_RANDOM, 1, 50, true); //target players only + do{target = SelectTarget(SELECT_TARGET_RANDOM, 1, 50, true); //target players only if(counter < Playercount) break; if(target) itr = list.find(target->GetGUID()); @@ -272,7 +272,7 @@ struct TRINITY_DLL_DECL boss_morogrim_tidewalkerAI : public ScriptedAI for (int8 g = 0; g < 4; g++) //one unit cant cast more than one spell per update, so some players have to cast for us XD { counter = 0; - do {globuletarget = SelectUnit(SELECT_TARGET_RANDOM, 0,50,true); + do {globuletarget = SelectTarget(SELECT_TARGET_RANDOM, 0,50,true); if(globuletarget) itr = globulelist.find(globuletarget->GetGUID()); if (counter > Playercount) break; diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_the_black_stalker.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_the_black_stalker.cpp index 370b07c8adc..72c7992e109 100644 --- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_the_black_stalker.cpp +++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/underbog/boss_the_black_stalker.cpp @@ -165,7 +165,7 @@ struct TRINITY_DLL_DECL boss_the_black_stalkerAI : public ScriptedAI // Static Charge if(StaticCharge_Timer < diff) { - if(Unit *target = SelectUnit(SELECT_TARGET_RANDOM,0,30,true)) + if(Unit *target = SelectTarget(SELECT_TARGET_RANDOM,0,30,true)) DoCast(target, SPELL_STATIC_CHARGE); StaticCharge_Timer = 10000; }else StaticCharge_Timer -= diff; diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp index 0becff399da..3a9c6a5b47a 100644 --- a/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp +++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_gothik.cpp @@ -30,8 +30,9 @@ EndScriptData */ //Gothik #define SPELL_HARVESTSOUL 28679 -#define SPELL_SHADOWBOLT 29317 -#define H_SPELL_SHADOWBOLT 56405 +#define SPELL_SHADOWBOLT HEROIC(29317,56405) +#define SPELL_SOUL_SIPHON 43591 // cannot find the correct spell + //Unrelenting Trainee #define SPELL_EAGLECLAW 30285 #define SPELL_KNOCKDOWN_PASSIVE 6961 diff --git a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_felmyst.cpp b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_felmyst.cpp index 8e42d074f88..e753d0b6047 100644 --- a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_felmyst.cpp +++ b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_felmyst.cpp @@ -306,7 +306,7 @@ struct TRINITY_DLL_DECL boss_felmystAI : public ScriptedAI case 2:{ error_log("Summon Vapor case 2"); Unit* target; - target = SelectUnit(SELECT_TARGET_RANDOM, 0, 150, true); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150, true); if(!target) target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_PLAYER_GUID)); if(target) { @@ -331,7 +331,7 @@ struct TRINITY_DLL_DECL boss_felmystAI : public ScriptedAI error_log("Summon Vapor case3"); //m_creature->CastSpell(m_creature, SPELL_VAPOR_SELECT); need core support Unit* target; - target = SelectUnit(SELECT_TARGET_RANDOM, 0, 150, true); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150, true); if(!target) target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_PLAYER_GUID)); if(target) { @@ -358,7 +358,7 @@ struct TRINITY_DLL_DECL boss_felmystAI : public ScriptedAI break; case 5:{ Unit* target; - target = SelectUnit(SELECT_TARGET_RANDOM, 0, 150, true); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150, true); if(!target) target = Unit::GetUnit((*m_creature), pInstance->GetData64(DATA_PLAYER_GUID)); if(target) { @@ -471,7 +471,7 @@ struct TRINITY_DLL_DECL boss_felmystAI : public ScriptedAI Timer[EVENT_GAS_NOVA] = 20000 + rand()%5 * 1000; break; case EVENT_ENCAPSULATE: - if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0, 150, true)) + if(Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 150, true)) { m_creature->CastSpell(target, SPELL_ENCAPSULATE_CHANNEL, false); target->CastSpell(target, SPELL_ENCAPSULATE_EFFECT, true);// linked aura, need core patch to remove this hack diff --git a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_kiljaeden.cpp b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_kiljaeden.cpp index 98cbfda7a7f..a0bd75cb156 100644 --- a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_kiljaeden.cpp +++ b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_kiljaeden.cpp @@ -540,7 +540,7 @@ struct TRINITY_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI float x,y,z; Unit* target; for(uint8 z = 0; z < 6; ++z){ - target = SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if (!target->HasAura(SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT,0)) break; } target->GetPosition(x,y,z); @@ -584,7 +584,7 @@ struct TRINITY_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI if(!m_creature->IsNonMeleeSpellCasted(false)){ m_creature->RemoveAurasDueToSpell(SPELL_SOUL_FLAY); for(uint8 z = 0; z < 6; ++z){ - randomPlayer = SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true); + randomPlayer = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if (!randomPlayer->HasAura(SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT,0)) break; } if(randomPlayer)DoCast(randomPlayer, SPELL_LEGION_LIGHTNING, false); @@ -658,7 +658,7 @@ struct TRINITY_DLL_DECL boss_kiljaedenAI : public Scripted_NoMovementAI case TIMER_ARMAGEDDON: //Phase 4 Unit* target; for(uint8 z = 0; z < 6; ++z){ - target = SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if (!target->HasAura(SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT,0)) break; } if(target){ @@ -1199,7 +1199,7 @@ struct TRINITY_DLL_DECL mob_sinster_reflectionAI : public ScriptedAI Timer[1] = 4000; } if(Timer[2] < diff){ - DoCast(SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true), SPELL_SR_CURSE_OF_AGONY, true); + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true), SPELL_SR_CURSE_OF_AGONY, true); Timer[2] = 3000; } DoMeleeAttackIfReady(); diff --git a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_muru.cpp b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_muru.cpp index 6000ee474e0..b38607e1a7f 100644 --- a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_muru.cpp +++ b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_muru.cpp @@ -155,7 +155,7 @@ struct TRINITY_DLL_DECL boss_entropiusAI : public ScriptedAI m_creature->SummonCreature(CREATURE_DARK_FIENDS, x,y,z,o, TEMPSUMMON_CORPSE_DESPAWN, 0); break; } - summoned->AI()->AttackStart(SelectUnit(SELECT_TARGET_RANDOM,0, 50, true)); + summoned->AI()->AttackStart(SelectTarget(SELECT_TARGET_RANDOM,0, 50, true)); Summons.Summon(summoned); } @@ -180,10 +180,10 @@ struct TRINITY_DLL_DECL boss_entropiusAI : public ScriptedAI }else EnrageTimer -= diff; if(BlackHoleSummonTimer < diff){ - Unit* random = SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true); + Unit* random = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if(!random)return; DoCast(random, SPELL_DARKNESS_E, false); - random = SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true); + random = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if(!random)return; random->CastSpell(random, SPELL_BLACKHOLE, false); BlackHoleSummonTimer = 15000; @@ -260,7 +260,7 @@ struct TRINITY_DLL_DECL boss_muruAI : public Scripted_NoMovementAI summoned->CastSpell(summoned,SPELL_DARKFIEND_VISUAL,false); break; } - summoned->AI()->AttackStart(SelectUnit(SELECT_TARGET_RANDOM,0, 50, true)); + summoned->AI()->AttackStart(SelectTarget(SELECT_TARGET_RANDOM,0, 50, true)); Summons.Summon(summoned); } @@ -441,7 +441,7 @@ struct TRINITY_DLL_DECL npc_dark_fiendAI : public ScriptedAI if(!InAction){ m_creature->clearUnitState(UNIT_STAT_STUNNED); DoCastAOE(SPELL_DARKFIEND_SKIN, false); - AttackStart(SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true)); + AttackStart(SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)); InAction = true; WaitTimer = 500; }else{ diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_alar.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_alar.cpp index 168f0f48e3a..af44d96d417 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_alar.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_alar.cpp @@ -352,7 +352,7 @@ struct TRINITY_DLL_DECL boss_alarAI : public ScriptedAI if(Charge_Timer < diff) { - Unit *target= SelectUnit(SELECT_TARGET_RANDOM, 1, GetSpellMaxRangeForHostile(SPELL_CHARGE), true); + Unit *target= SelectTarget(SELECT_TARGET_RANDOM, 1, GetSpellMaxRangeForHostile(SPELL_CHARGE), true); if(target) DoCast(target, SPELL_CHARGE); Charge_Timer = 30000; diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_astromancer.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_astromancer.cpp index 83cb789b189..6af14eceeed 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_astromancer.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_astromancer.cpp @@ -230,7 +230,7 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI if( Wrath_Timer < diff) { m_creature->InterruptNonMeleeSpells(false); - DoCast(SelectUnit(SELECT_TARGET_RANDOM,1,100,true), SPELL_WRATH_OF_THE_ASTROMANCER, true); + DoCast(SelectTarget(SELECT_TARGET_RANDOM,1,100,true), SPELL_WRATH_OF_THE_ASTROMANCER, true); Wrath_Timer = 20000+rand()%5000; }else Wrath_Timer -= diff; @@ -260,7 +260,7 @@ struct TRINITY_DLL_DECL boss_high_astromancer_solarianAI : public ScriptedAI if (MarkOfTheAstromancer_Timer < diff) //A debuff that lasts for 5 seconds, cast several times each phase on a random raid member, but not the main tank { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1, 100, true); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100, true); if(target) DoCast(target, SPELL_MARK_OF_THE_ASTROMANCER); else DoCast(m_creature->getVictim(), SPELL_MARK_OF_THE_ASTROMANCER); diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp index 6745c4fd9ec..7557e03f8e5 100644 --- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp +++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp @@ -804,7 +804,7 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI if (FlameStrike_Timer < diff) { - if (Unit* pUnit = SelectUnit(SELECT_TARGET_RANDOM, 0, 70, true)) + if (Unit* pUnit = SelectTarget(SELECT_TARGET_RANDOM, 0, 70, true)) DoCast(pUnit, SPELL_FLAME_STRIKE); FlameStrike_Timer = 30000; @@ -816,7 +816,7 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI for (uint32 i = 0; i < 3; i++) { - Unit* target =SelectUnit(SELECT_TARGET_RANDOM, 1, 70, true); + Unit* target =SelectTarget(SELECT_TARGET_RANDOM, 1, 70, true); if(!target) target = m_creature->getVictim(); debug_log("TSCR: Kael'Thas mind control not supported."); if(target) @@ -1080,7 +1080,7 @@ struct TRINITY_DLL_DECL boss_thaladred_the_darkenerAI : public advisorbase_ai //Gaze_Timer if(Gaze_Timer < diff) { - if (Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0, 100, true)) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) { DoResetThreat(); if(target) diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp index c3d4d0f35eb..d2fff0e569f 100644 --- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp +++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp @@ -465,7 +465,7 @@ struct TRINITY_DLL_DECL boss_veknilashAI : public boss_twinemperorsAI if (UpperCut_Timer < diff) { - Unit* randomMelee = SelectUnit(SELECT_TARGET_RANDOM, 0, NOMINAL_MELEE_RANGE, true); + Unit* randomMelee = SelectTarget(SELECT_TARGET_RANDOM, 0, NOMINAL_MELEE_RANGE, true); if (randomMelee) DoCast(randomMelee,SPELL_UPPERCUT); UpperCut_Timer = 15000+rand()%15000; @@ -560,7 +560,7 @@ struct TRINITY_DLL_DECL boss_veklorAI : public boss_twinemperorsAI if (Blizzard_Timer < diff) { Unit* target = NULL; - target = SelectUnit(SELECT_TARGET_RANDOM, 0, 45, true); + target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45, true); if (target) DoCast(target,SPELL_BLIZZARD); Blizzard_Timer = 15000+rand()%15000; @@ -569,7 +569,7 @@ struct TRINITY_DLL_DECL boss_veklorAI : public boss_twinemperorsAI if (ArcaneBurst_Timer < diff) { Unit *mvic; - if ((mvic=SelectUnit(SELECT_TARGET_NEAREST, 0, NOMINAL_MELEE_RANGE, true))!=NULL) + if ((mvic=SelectTarget(SELECT_TARGET_NEAREST, 0, NOMINAL_MELEE_RANGE, true))!=NULL) { DoCast(mvic,SPELL_ARCANEBURST); ArcaneBurst_Timer = 5000; diff --git a/src/bindings/scripts/scripts/zone/zulaman/boss_akilzon.cpp b/src/bindings/scripts/scripts/zone/zulaman/boss_akilzon.cpp index f31f944a3d4..85ba26ef20d 100644 --- a/src/bindings/scripts/scripts/zone/zulaman/boss_akilzon.cpp +++ b/src/bindings/scripts/scripts/zone/zulaman/boss_akilzon.cpp @@ -297,7 +297,7 @@ struct TRINITY_DLL_DECL boss_akilzonAI : public ScriptedAI } if (ElectricalStorm_Timer < diff) { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0, 50, true); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50, true); if(!target) { EnterEvadeMode(); diff --git a/src/bindings/scripts/scripts/zone/zulaman/boss_hexlord.cpp b/src/bindings/scripts/scripts/zone/zulaman/boss_hexlord.cpp index 7fb8dc9b321..26229261905 100644 --- a/src/bindings/scripts/scripts/zone/zulaman/boss_hexlord.cpp +++ b/src/bindings/scripts/scripts/zone/zulaman/boss_hexlord.cpp @@ -383,7 +383,7 @@ struct TRINITY_DLL_DECL boss_hex_lord_malacrassAI : public ScriptedAI if(SiphonSoul_Timer < diff) { - Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0, 70, true); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 70, true); Unit *trigger = DoSpawnCreature(MOB_TEMP_TRIGGER, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 30000); if(!target || !trigger) { diff --git a/src/bindings/scripts/scripts/zone/zulaman/boss_nalorakk.cpp b/src/bindings/scripts/scripts/zone/zulaman/boss_nalorakk.cpp index 9fc50e621ac..68b92590025 100644 --- a/src/bindings/scripts/scripts/zone/zulaman/boss_nalorakk.cpp +++ b/src/bindings/scripts/scripts/zone/zulaman/boss_nalorakk.cpp @@ -406,7 +406,7 @@ struct TRINITY_DLL_DECL boss_nalorakkAI : public ScriptedAI { DoYell(YELL_SURGE, LANG_UNIVERSAL, NULL); DoPlaySoundToSet(m_creature, SOUND_YELL_SURGE); - Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 1, GetSpellMaxRangeForHostile(SPELL_SURGE), true); + Unit *target = SelectTarget(SELECT_TARGET_RANDOM, 1, GetSpellMaxRangeForHostile(SPELL_SURGE), true); if(target) DoCast(target, SPELL_SURGE); Surge_Timer = 15000 + rand()%5000; diff --git a/src/game/CreatureAI.cpp b/src/game/CreatureAI.cpp index 5cde80aaccb..0713ef592d3 100644 --- a/src/game/CreatureAI.cpp +++ b/src/game/CreatureAI.cpp @@ -71,6 +71,8 @@ void CreatureAI::OnCharmed(bool apply) me->IsAIEnabled = false; } +AISpellInfoType *AISpellInfo; + void CreatureAI::DoZoneInCombat(Creature* creature) { if (!creature) @@ -151,6 +153,148 @@ void CreatureAI::EnterEvadeMode() me->GetMotionMaster()->MoveTargetedHome(); } +inline bool SelectTargetHelper(const Unit * me, const Unit * target, const bool &playerOnly, const float &dist, const int32 &aura) +{ + if(playerOnly && target->GetTypeId() != TYPEID_PLAYER) + return false; + + if(dist && !me->IsWithinCombatRange(target, dist)) + return false; + + if(aura) + { + if(aura > 0) + { + if(!target->HasAura(aura)) + return false; + } + else + { + if(target->HasAura(aura)) + return false; + } + } + + return true; +} + +struct TargetDistanceOrder : public std::binary_function +{ + const Unit * me; + TargetDistanceOrder(const Unit* Target) : me(Target) {}; + // functor for operator ">" + bool operator()(const Unit * _Left, const Unit * _Right) const + { + return (me->GetDistanceSq(_Left) < me->GetDistanceSq(_Right)); + } +}; + +Unit* CreatureAI::SelectTarget(SelectAggroTarget targetType, uint32 position, float dist, bool playerOnly, int32 aura) +{ + if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST) + { + std::list &m_threatlist = me->getThreatManager().getThreatList(); + if(position >= m_threatlist.size()) + return NULL; + + std::list targetList; + for(std::list::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) + if(SelectTargetHelper(me, (*itr)->getTarget(), playerOnly, dist, aura)) + targetList.push_back((*itr)->getTarget()); + + if(position >= targetList.size()) + return NULL; + + targetList.sort(TargetDistanceOrder(m_creature)); + + if(targetType == SELECT_TARGET_NEAREST) + { + std::list::iterator i = targetList.begin(); + advance(i, position); + return *i; + } + else + { + std::list::reverse_iterator i = targetList.rbegin(); + advance(i, position); + return *i; + } + } + else + { + std::list m_threatlist = me->getThreatManager().getThreatList(); + std::list::iterator i; + while(position < m_threatlist.size()) + { + if(targetType == SELECT_TARGET_BOTTOMAGGRO) + { + i = m_threatlist.end(); + advance(i, - (int32)position - 1); + } + else + { + i = m_threatlist.begin(); + if(targetType == SELECT_TARGET_TOPAGGRO) + advance(i, position); + else // random + advance(i, position + rand()%(m_threatlist.size() - position)); + } + + if(SelectTargetHelper(me, (*i)->getTarget(), playerOnly, dist, aura)) + return (*i)->getTarget(); + else + m_threatlist.erase(i); + } + } + + return NULL; +} + +void CreatureAI::SelectTargetList(std::list &targetList, uint32 num, SelectAggroTarget targetType, float dist, bool playerOnly, int32 aura) +{ + if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST) + { + std::list &m_threatlist = m_creature->getThreatManager().getThreatList(); + if(m_threatlist.empty()) + return; + + for(std::list::iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) + if(SelectTargetHelper(me, (*itr)->getTarget(), playerOnly, dist, aura)) + targetList.push_back((*itr)->getTarget()); + + targetList.sort(TargetDistanceOrder(me)); + targetList.resize(num); + if(targetType == SELECT_TARGET_FARTHEST) + targetList.reverse(); + } + else + { + std::list m_threatlist = me->getThreatManager().getThreatList(); + std::list::iterator i; + while(!m_threatlist.empty() && num) + { + if(targetType == SELECT_TARGET_BOTTOMAGGRO) + { + i = m_threatlist.end(); + --i; + } + else + { + i = m_threatlist.begin(); + if(targetType == SELECT_TARGET_RANDOM) + advance(i, rand()%m_threatlist.size()); + } + + if(SelectTargetHelper(me, (*i)->getTarget(), playerOnly, dist, aura)) + { + targetList.push_back((*i)->getTarget()); + --num; + } + m_threatlist.erase(i); + } + } +} + void SimpleCharmedAI::UpdateAI(const uint32 /*diff*/) { Creature *charmer = (Creature*)me->GetCharmer(); diff --git a/src/game/CreatureAI.h b/src/game/CreatureAI.h index e3a5a674e68..16271775728 100644 --- a/src/game/CreatureAI.h +++ b/src/game/CreatureAI.h @@ -37,7 +37,7 @@ struct SpellEntry; #define VISIBILITY_RANGE 10000 //Spell targets used by SelectSpell -enum SelectTarget +enum SelectTargetType { SELECT_TARGET_DONTCARE = 0, //All target types allowed @@ -77,6 +77,35 @@ enum SCEquip EQUIP_UNEQUIP = 0 }; +enum AITarget +{ + AITARGET_SELF, + AITARGET_VICTIM, + AITARGET_ENEMY, + AITARGET_ALLY, + AITARGET_BUFF, + AITARGET_DEBUFF, +}; + +enum AICondition +{ + AICOND_AGGRO, + AICOND_COMBAT, + AICOND_DIE, +}; + +#define AI_DEFAULT_COOLDOWN 5000 + +struct AISpellInfoType +{ + AISpellInfoType() : target(AITARGET_SELF), condition(AICOND_COMBAT), cooldown(AI_DEFAULT_COOLDOWN) {} + AITarget target; + AICondition condition; + uint32 cooldown; +}; + +extern AISpellInfoType *AISpellInfo; + class EventMap : private std::map { private: @@ -273,6 +302,9 @@ class TRINITY_DLL_SPEC CreatureAI : public UnitAI // Pointer to controlled by AI creature //Creature* const m_creature; + + Unit* SelectTarget(SelectAggroTarget target, uint32 position = 0, float dist = 0, bool playerOnly = false, int32 aura = 0); + void SelectTargetList(std::list &targetList, uint32 num, SelectAggroTarget target, float dist = 0, bool playerOnly = false, int32 aura = 0); }; struct SelectableAI : public FactoryHolder, public Permissible diff --git a/src/game/Object.cpp b/src/game/Object.cpp index 6b7a3cdd4ac..a436732f0a6 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -1194,6 +1194,14 @@ float WorldObject::GetDistanceSq(const float &x, const float &y, const float &z) return dx*dx + dy*dy + dz*dz; } +float WorldObject::GetDistanceSq(const WorldObject *obj) const +{ + float dx = GetPositionX() - obj->GetPositionX(); + float dy = GetPositionY() - obj->GetPositionY(); + float dz = GetPositionZ() - obj->GetPositionZ(); + return dx*dx + dy*dy + dz*dz; +} + float WorldObject::GetDistance2d(const WorldObject* obj) const { float dx = GetPositionX() - obj->GetPositionX(); diff --git a/src/game/Object.h b/src/game/Object.h index e7e03501dc1..01c31d5b9b4 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -463,6 +463,7 @@ class TRINITY_DLL_SPEC WorldObject : public Object float GetDistance( const WorldObject* obj ) const; float GetDistance(const float x, const float y, const float z) const; float GetDistanceSq(const float &x, const float &y, const float &z) const; + float GetDistanceSq(const WorldObject *obj) const; float GetDistance2d(const WorldObject* obj) const; float GetDistance2d(const float x, const float y) const; float GetExactDistance2d(const float x, const float y) const; diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 6a9f122adf4..3f09eec9351 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -413,7 +413,7 @@ void Unit::resetAttackTimer(WeaponAttackType type) m_attackTimer[type] = uint32(GetAttackTime(type) * m_modAttackSpeedPct[type]); } -bool Unit::IsWithinCombatRange(Unit *obj, float dist2compare) const +bool Unit::IsWithinCombatRange(const Unit *obj, float dist2compare) const { if (!obj || !IsInMap(obj)) return false; @@ -428,7 +428,7 @@ bool Unit::IsWithinCombatRange(Unit *obj, float dist2compare) const return distsq < maxdist * maxdist; } -bool Unit::IsWithinMeleeRange(Unit *obj, float dist) const +bool Unit::IsWithinMeleeRange(const Unit *obj, float dist) const { if (!obj || !IsInMap(obj)) return false; diff --git a/src/game/Unit.h b/src/game/Unit.h index 5d08cbfa2fb..bb303473e7b 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -940,8 +940,8 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void SetCanDualWield(bool value) { m_canDualWield = value; } float GetCombatReach() const { return m_floatValues[UNIT_FIELD_COMBATREACH]; } float GetMeleeReach() const { float reach = m_floatValues[UNIT_FIELD_COMBATREACH]; return reach > MIN_MELEE_REACH ? reach : MIN_MELEE_REACH; } - bool IsWithinCombatRange(Unit *obj, float dist2compare) const; - bool IsWithinMeleeRange(Unit *obj, float dist = MELEE_RANGE) const; + bool IsWithinCombatRange(const Unit *obj, float dist2compare) const; + bool IsWithinMeleeRange(const Unit *obj, float dist = MELEE_RANGE) const; void GetRandomContactPoint( const Unit* target, float &x, float &y, float &z, float distance2dMin, float distance2dMax ) const; uint32 m_extraAttacks; bool m_canDualWield; -- cgit v1.2.3 From 047cc95388a67d5f33cb86082bbef03f654acec1 Mon Sep 17 00:00:00 2001 From: megamage Date: Thu, 14 May 2009 16:50:47 -0500 Subject: *Add some distance check functions. By VladimirMangos. --HG-- branch : trunk --- src/game/Creature.cpp | 4 +- src/game/CreatureEventAI.cpp | 12 +- src/game/GridNotifiers.h | 2 +- src/game/Group.cpp | 14 +- src/game/GuardAI.cpp | 2 +- src/game/LootHandler.cpp | 2 +- src/game/MiscHandler.cpp | 4 +- src/game/Object.cpp | 305 ++++++++++++++++++++++++++++++++++- src/game/Object.h | 23 ++- src/game/Pet.h | 2 +- src/game/Player.cpp | 2 +- src/game/RandomMovementGenerator.cpp | 2 +- src/game/Spell.cpp | 9 +- src/game/Spell.h | 8 +- src/game/TradeHandler.cpp | 26 +-- src/game/Unit.cpp | 4 +- src/game/Unit.h | 4 +- 17 files changed, 364 insertions(+), 61 deletions(-) (limited to 'src/game/Object.cpp') diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index f322d8326e1..8d7b877d4f5 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -2058,12 +2058,12 @@ bool Creature::IsOutOfThreatArea(Unit* pVictim) const if(sMapStore.LookupEntry(GetMapId())->IsDungeon()) return false; - float length = pVictim->GetDistance(mHome_X, mHome_Y, mHome_Z); float AttackDist = GetAttackDistance(pVictim); uint32 ThreatRadius = sWorld.getConfig(CONFIG_THREAT_RADIUS); //Use AttackDistance in distance check if threat radius is lower. This prevents creature bounce in and out of combat every update tick. - return ( length > (ThreatRadius > AttackDist ? ThreatRadius : AttackDist)); + return !pVictim->IsWithinDist3d(mHome_X,mHome_Y,mHome_Z, + ThreatRadius > AttackDist ? ThreatRadius : AttackDist); } CreatureDataAddon const* Creature::GetCreatureAddon() const diff --git a/src/game/CreatureEventAI.cpp b/src/game/CreatureEventAI.cpp index 470225e0da0..5a84d43e80f 100644 --- a/src/game/CreatureEventAI.cpp +++ b/src/game/CreatureEventAI.cpp @@ -1288,13 +1288,10 @@ void CreatureEventAI::UpdateAI(const uint32 diff) break; case EVENT_T_RANGE: if (Combat) - { - if (m_creature->IsWithinDistInMap(m_creature->getVictim(),(float)(*i).Event.event_param2)) - { - if (m_creature->GetDistance(m_creature->getVictim()) >= (float)(*i).Event.event_param1) + if (m_creature->IsInMap(m_creature->getVictim())) + if (m_creature->IsInRange(m_creature->getVictim(), + (float)(*i).Event.event_param1,(float)(*i).Event.event_param2)) ProcessEvent(*i); - } - } break; } } @@ -1548,8 +1545,7 @@ bool CreatureEventAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Trigge return false; //Unit is out of range of this spell - if (me->GetDistance(Target) > me->GetSpellMaxRangeForTarget(Target, TempRange) - || me->GetDistance(Target) < me->GetSpellMinRangeForTarget(Target, TempRange)) + if (!m_creature->IsInRange(Target,TempRange->minRangeHostile,TempRange->maxRangeHostile)) return false; return true; diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h index 195f7206264..a9925f67406 100644 --- a/src/game/GridNotifiers.h +++ b/src/game/GridNotifiers.h @@ -489,7 +489,7 @@ namespace Trinity void Visit(PlayerMapType &m) { for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if(itr->getSource()->InSamePhase(i_searcher) && itr->getSource()->GetDistance(i_searcher) <= i_dist) + if (itr->getSource()->InSamePhase(i_searcher) && itr->getSource()->IsWithinDist(i_searcher,i_dist)) i_do(itr->getSource()); } diff --git a/src/game/Group.cpp b/src/game/Group.cpp index 02fc72f2022..d2c17680e52 100644 --- a/src/game/Group.cpp +++ b/src/game/Group.cpp @@ -571,7 +571,7 @@ void Group::GroupLoot(const uint64& playerGUID, Loot *loot, Creature *creature) continue; if ( i->AllowedForPlayer(member) ) { - if (member->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if (member->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) { r->playerVote[member->GetGUID()] = NOT_EMITED_YET; ++r->totalPlayersRolling; @@ -621,7 +621,7 @@ void Group::NeedBeforeGreed(const uint64& playerGUID, Loot *loot, Creature *crea if (playerToRoll->CanUseItem(item) && i->AllowedForPlayer(playerToRoll) ) { - if (playerToRoll->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if (playerToRoll->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) { r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET; ++r->totalPlayersRolling; @@ -669,7 +669,7 @@ void Group::MasterLoot(const uint64& playerGUID, Loot* /*loot*/, Creature *creat if (!looter->IsInWorld()) continue; - if (looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if (looter->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) { data << looter->GetGUID(); ++real_count; @@ -681,7 +681,7 @@ void Group::MasterLoot(const uint64& playerGUID, Loot* /*loot*/, Creature *creat for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next()) { Player *looter = itr->getSource(); - if (looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if (looter->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) looter->GetSession()->SendPacket(&data); } } @@ -1338,7 +1338,7 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed ) { // not update if only update if need and ok Player* looter = ObjectAccessor::FindPlayer(guid_itr->guid); - if(looter && looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if(looter && looter->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) return; } ++guid_itr; @@ -1351,7 +1351,7 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed ) { if(Player* pl = ObjectAccessor::FindPlayer(itr->guid)) { - if (pl->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if (pl->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) { bool refresh = pl->GetLootGUID()==creature->GetGUID(); @@ -1372,7 +1372,7 @@ void Group::UpdateLooterGuid( Creature* creature, bool ifneed ) { if(Player* pl = ObjectAccessor::FindPlayer(itr->guid)) { - if (pl->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if (pl->IsWithinDist(creature,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) { bool refresh = pl->GetLootGUID()==creature->GetGUID(); diff --git a/src/game/GuardAI.cpp b/src/game/GuardAI.cpp index b716642ebd7..b7268758583 100644 --- a/src/game/GuardAI.cpp +++ b/src/game/GuardAI.cpp @@ -126,7 +126,7 @@ void GuardAI::UpdateAI(const uint32 /*diff*/) bool GuardAI::IsVisible(Unit *pl) const { - return m_creature->GetDistance(pl) < sWorld.getConfig(CONFIG_SIGHT_GUARDER) + return m_creature->IsWithinDist(pl,sWorld.getConfig(CONFIG_SIGHT_GUARDER)) && pl->isVisibleForOrDetect(m_creature,true); } diff --git a/src/game/LootHandler.cpp b/src/game/LootHandler.cpp index f8e2a6cde15..172a6ef46c2 100644 --- a/src/game/LootHandler.cpp +++ b/src/game/LootHandler.cpp @@ -224,7 +224,7 @@ void WorldSession::HandleLootMoneyOpcode( WorldPacket & /*recv_data*/ ) Player* playerGroup = itr->getSource(); if(!playerGroup) continue; - if (player->GetDistance2d(playerGroup) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE)) + if (player->IsWithinDist(playerGroup,sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE),false)) playersNear.push_back(playerGroup); } diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp index a75141e2937..5a1f97cdf8c 100644 --- a/src/game/MiscHandler.cpp +++ b/src/game/MiscHandler.cpp @@ -775,9 +775,7 @@ void WorldSession::HandleCorpseReclaimOpcode(WorldPacket &recv_data) if(corpse->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse->GetType()==CORPSE_RESURRECTABLE_PVP) > time(NULL)) return; - float dist = corpse->GetDistance2d(GetPlayer()); - sLog.outDebug("Corpse 2D Distance: \t%f",dist); - if (dist > CORPSE_RECLAIM_RADIUS) + if (!corpse->IsWithinDist(GetPlayer(),CORPSE_RECLAIM_RADIUS,false)) return; uint64 guid; diff --git a/src/game/Object.cpp b/src/game/Object.cpp index a436732f0a6..5c186921524 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -1148,7 +1148,6 @@ InstanceData* WorldObject::GetInstanceData() Map *map = GetMap(); return map->IsDungeon() ? ((InstanceMap*)map)->GetInstanceData() : NULL; } - //slow float WorldObject::GetDistance(const WorldObject* obj) const { @@ -1176,7 +1175,7 @@ float WorldObject::GetExactDistance2d(const float x, const float y) const return sqrt((dx*dx) + (dy*dy)); } -float WorldObject::GetDistance(const float x, const float y, const float z) const +float WorldObject::GetDistance(float x, float y, float z) const { float dx = GetPositionX() - x; float dy = GetPositionY() - y; @@ -1219,10 +1218,33 @@ float WorldObject::GetDistanceZ(const WorldObject* obj) const return ( dist > 0 ? dist : 0); } -bool WorldObject::IsWithinDistInMap(const WorldObject* obj, const float dist2compare, const bool is3D) const +bool WorldObject::IsWithinDist3d(float x, float y, float z, float dist2compare) const { - if (!obj || !IsInMap(obj)) return false; + float dx = GetPositionX() - x; + float dy = GetPositionY() - y; + float dz = GetPositionZ() - z; + float distsq = dx*dx + dy*dy + dz*dz; + + float sizefactor = GetObjectSize(); + float maxdist = dist2compare + sizefactor; + + return distsq < maxdist * maxdist; +} + +bool WorldObject::IsWithinDist2d(float x, float y, float dist2compare) const +{ + float dx = GetPositionX() - x; + float dy = GetPositionY() - y; + float distsq = dx*dx + dy*dy; + + float sizefactor = GetObjectSize(); + float maxdist = dist2compare + sizefactor; + + return distsq < maxdist * maxdist; +} +bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const +{ float dx = GetPositionX() - obj->GetPositionX(); float dy = GetPositionY() - obj->GetPositionY(); float distsq = dx*dx + dy*dy; @@ -1245,7 +1267,7 @@ bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const return(IsWithinLOS(ox, oy, oz )); } -bool WorldObject::IsWithinLOS(const float ox, const float oy, const float oz ) const +bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const { float x,y,z; GetPosition(x,y,z); @@ -1253,6 +1275,83 @@ bool WorldObject::IsWithinLOS(const float ox, const float oy, const float oz ) c return vMapManager->isInLineOfSight(GetMapId(), x, y, z+2.0f, ox, oy, oz+2.0f); } +bool WorldObject::GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D /* = true */) const +{ + float dx1 = GetPositionX() - obj1->GetPositionX(); + float dy1 = GetPositionY() - obj1->GetPositionY(); + float distsq1 = dx1*dx1 + dy1*dy1; + if(is3D) + { + float dz1 = GetPositionZ() - obj1->GetPositionZ(); + distsq1 += dz1*dz1; + } + + float dx2 = GetPositionX() - obj2->GetPositionX(); + float dy2 = GetPositionY() - obj2->GetPositionY(); + float distsq2 = dx2*dx2 + dy2*dy2; + if(is3D) + { + float dz2 = GetPositionZ() - obj2->GetPositionZ(); + distsq2 += dz2*dz2; + } + + return distsq1 < distsq2; +} + +bool WorldObject::IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D /* = true */) const +{ + float dx = GetPositionX() - obj->GetPositionX(); + float dy = GetPositionY() - obj->GetPositionY(); + float distsq = dx*dx + dy*dy; + if(is3D) + { + float dz = GetPositionZ() - obj->GetPositionZ(); + distsq += dz*dz; + } + + float sizefactor = GetObjectSize() + obj->GetObjectSize(); + + float mindist = minRange + sizefactor; + if(distsq < mindist * mindist) + return false; + + float maxdist = maxRange + sizefactor; + return distsq < maxdist * maxdist; +} + +bool WorldObject::IsInRange2d(float x, float y, float minRange, float maxRange) const +{ + float dx = GetPositionX() - x; + float dy = GetPositionY() - y; + float distsq = dx*dx + dy*dy; + + float sizefactor = GetObjectSize(); + + float mindist = minRange + sizefactor; + if(distsq < mindist * mindist) + return false; + + float maxdist = maxRange + sizefactor; + return distsq < maxdist * maxdist; +} + +bool WorldObject::IsInRange3d(float x, float y, float z, float minRange, float maxRange) const +{ + float dx = GetPositionX() - x; + float dy = GetPositionY() - y; + float dz = GetPositionZ() - z; + float distsq = dx*dx + dy*dy + dz*dz; + + float sizefactor = GetObjectSize(); + + float mindist = minRange + sizefactor; + if(distsq < mindist * mindist) + return false; + + float maxdist = maxRange + sizefactor; + return distsq < maxdist * maxdist; +} + float WorldObject::GetAngle(const WorldObject* obj) const { if(!obj) return 0; @@ -1914,6 +2013,81 @@ Creature* WorldObject::SummonTrigger(float x, float y, float z, float ang, uint3 return summon; } +/* +namespace MaNGOS +{ + class NearUsedPosDo + { + public: + NearUsedPosDo(WorldObject const& obj, WorldObject const* searcher, float angle, ObjectPosSelector& selector) + : i_object(obj), i_searcher(searcher), i_angle(angle), i_selector(selector) {} + + void operator()(Corpse*) const {} + void operator()(DynamicObject*) const {} + + void operator()(Creature* c) const + { + // skip self or target + if(c==i_searcher || c==&i_object) + return; + + float x,y,z; + + if( !c->isAlive() || c->hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED) || + !c->GetMotionMaster()->GetDestination(x,y,z) ) + { + x = c->GetPositionX(); + y = c->GetPositionY(); + } + + add(c,x,y); + } + + template + void operator()(T* u) const + { + // skip self or target + if(u==i_searcher || u==&i_object) + return; + + float x,y; + + x = u->GetPositionX(); + y = u->GetPositionY(); + + add(u,x,y); + } + + // we must add used pos that can fill places around center + void add(WorldObject* u, float x, float y) const + { + // u is too nearest/far away to i_object + if(!i_object.IsInRange2d(x,y,i_selector.m_dist - i_selector.m_size,i_selector.m_dist + i_selector.m_size)) + return; + + float angle = i_object.GetAngle(u)-i_angle; + + // move angle to range -pi ... +pi + while( angle > M_PI) + angle -= 2.0f * M_PI; + while(angle < -M_PI) + angle += 2.0f * M_PI; + + // dist include size of u + float dist2d = i_object.GetDistance2d(x,y); + i_selector.AddUsedPos(u->GetObjectSize(),angle,dist2d + i_object.GetObjectSize()); + } + private: + WorldObject const& i_object; + WorldObject const* i_searcher; + float i_angle; + ObjectPosSelector& i_selector; + }; +} // namespace MaNGOS +*/ + +//=================================================================================================== + void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float absAngle ) const { x = GetPositionX() + (GetObjectSize() + distance2d) * cos(absAngle); @@ -1926,10 +2100,127 @@ void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float abs void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, float &z, float searcher_size, float distance2d, float absAngle ) const { GetNearPoint2D(x,y,distance2d+searcher_size,absAngle); - z = GetPositionZ(); - UpdateGroundPositionZ(x,y,z); + + /* + // if detection disabled, return first point + if(!sWorld.getConfig(CONFIG_DETECT_POS_COLLISION)) + { + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + return; + } + + // or remember first point + float first_x = x; + float first_y = y; + bool first_los_conflict = false; // first point LOS problems + + // prepare selector for work + ObjectPosSelector selector(GetPositionX(),GetPositionY(),GetObjectSize(),distance2d+searcher_size); + + // adding used positions around object + { + CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY())); + Cell cell(p); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + + MaNGOS::NearUsedPosDo u_do(*this,searcher,absAngle,selector); + MaNGOS::WorldObjectWorker worker(this,u_do); + + TypeContainerVisitor, GridTypeMapContainer > grid_obj_worker(worker); + TypeContainerVisitor, WorldTypeMapContainer > world_obj_worker(worker); + + CellLock cell_lock(cell, p); + cell_lock->Visit(cell_lock, grid_obj_worker, *GetMap()); + cell_lock->Visit(cell_lock, world_obj_worker, *GetMap()); + } + + // maybe can just place in primary position + if( selector.CheckOriginal() ) + { + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + + if(IsWithinLOS(x,y,z)) + return; + + first_los_conflict = true; // first point have LOS problems + } + + float angle; // candidate of angle for free pos + + // special case when one from list empty and then empty side preferred + if(selector.FirstAngle(angle)) + { + GetNearPoint2D(x,y,distance2d,absAngle+angle); + z = GetPositionZ(); + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + + if(IsWithinLOS(x,y,z)) + return; + } + + // set first used pos in lists + selector.InitializeAngle(); + + // select in positions after current nodes (selection one by one) + while(selector.NextAngle(angle)) // angle for free pos + { + GetNearPoint2D(x,y,distance2d,absAngle+angle); + z = GetPositionZ(); + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + + if(IsWithinLOS(x,y,z)) + return; + } + + // BAD NEWS: not free pos (or used or have LOS problems) + // Attempt find _used_ pos without LOS problem + + if(!first_los_conflict) + { + x = first_x; + y = first_y; + + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + return; + } + + // special case when one from list empty and then empty side preferred + if( selector.IsNonBalanced() ) + { + if(!selector.FirstAngle(angle)) // _used_ pos + { + GetNearPoint2D(x,y,distance2d,absAngle+angle); + z = GetPositionZ(); + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + + if(IsWithinLOS(x,y,z)) + return; + } + } + + // set first used pos in lists + selector.InitializeAngle(); + + // select in positions after current nodes (selection one by one) + while(selector.NextUsedAngle(angle)) // angle for used pos but maybe without LOS problem + { + GetNearPoint2D(x,y,distance2d,absAngle+angle); + z = GetPositionZ(); + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + + if(IsWithinLOS(x,y,z)) + return; + } + + // BAD BAD NEWS: all found pos (free and used) have LOS problem :( + x = first_x; + y = first_y; + + UpdateGroundPositionZ(x,y,z); // update to LOS height if available + */ } void WorldObject::GetGroundPoint(float &x, float &y, float &z, float dist, float angle) diff --git a/src/game/Object.h b/src/game/Object.h index 01c31d5b9b4..326b09cfb73 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -461,11 +461,11 @@ class TRINITY_DLL_SPEC WorldObject : public Object virtual const char* GetNameForLocaleIdx(int32 /*locale_idx*/) const { return GetName(); } float GetDistance( const WorldObject* obj ) const; - float GetDistance(const float x, const float y, const float z) const; + float GetDistance(float x, float y, float z) const; float GetDistanceSq(const float &x, const float &y, const float &z) const; float GetDistanceSq(const WorldObject *obj) const; float GetDistance2d(const WorldObject* obj) const; - float GetDistance2d(const float x, const float y) const; + float GetDistance2d(float x, float y) const; float GetExactDistance2d(const float x, const float y) const; float GetDistanceZ(const WorldObject* obj) const; bool IsInMap(const WorldObject* obj) const @@ -473,9 +473,24 @@ class TRINITY_DLL_SPEC WorldObject : public Object return IsInWorld() && obj->IsInWorld() && GetMapId()==obj->GetMapId() && GetInstanceId()==obj->GetInstanceId() && InSamePhase(obj); } - bool IsWithinDistInMap(const WorldObject* obj, const float dist2compare, const bool is3D = true) const; - bool IsWithinLOS(const float x, const float y, const float z ) const; + bool IsWithinDist3d(float x, float y, float z, float dist2compare) const; + bool IsWithinDist2d(float x, float y, float dist2compare) const; + bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const; + bool IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D = true) const + // use only if you will sure about placing both object at same map + { + return obj && _IsWithinDist(obj,dist2compare,is3D); + } + bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true) const + { + return obj && IsInMap(obj) && _IsWithinDist(obj,dist2compare,is3D); + } + bool IsWithinLOS(float x, float y, float z) const; bool IsWithinLOSInMap(const WorldObject* obj) const; + bool GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D = true) const; + bool IsInRange(WorldObject const* obj, float minRange, float maxRange, bool is3D = true) const; + bool IsInRange2d(float x, float y, float minRange, float maxRange) const; + bool IsInRange3d(float x, float y, float z, float minRange, float maxRange) const; float GetAngle( const WorldObject* obj ) const; float GetAngle( const float x, const float y ) const; diff --git a/src/game/Pet.h b/src/game/Pet.h index ea82b7360bc..b76b53ab554 100644 --- a/src/game/Pet.h +++ b/src/game/Pet.h @@ -121,7 +121,7 @@ typedef std::vector AutoSpellList; #define ACTIVE_SPELLS_MAX 4 -#define OWNER_MAX_DISTANCE 100 +#define OWNER_MAX_DISTANCE 100.0f #define PET_FOLLOW_DIST 1 #define PET_FOLLOW_ANGLE (M_PI/2) diff --git a/src/game/Player.cpp b/src/game/Player.cpp index e7fab7ac107..a68002445bc 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -1673,7 +1673,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (!(options & TELE_TO_NOT_UNSUMMON_PET)) { //same map, only remove pet if out of range for new position - if(pet && pet->GetDistance(x,y,z) >= OWNER_MAX_DISTANCE) + if(pet && !pet->IsWithinDist3d(x,y,z, OWNER_MAX_DISTANCE)) UnsummonPetTemporaryIfAny(); } diff --git a/src/game/RandomMovementGenerator.cpp b/src/game/RandomMovementGenerator.cpp index 2e0e0174a40..93e10ad6115 100644 --- a/src/game/RandomMovementGenerator.cpp +++ b/src/game/RandomMovementGenerator.cpp @@ -195,7 +195,7 @@ RandomMovementGenerator::Update(Creature &creature, const uint32 &diff creature.SetUnitMovementFlags(irand(0,RUNNING_CHANCE_RANDOMMV) > 0 ? MOVEMENTFLAG_WALK_MODE : MOVEMENTFLAG_NONE); _setRandomLocation(creature); } - else if(creature.isPet() && creature.GetOwner() && creature.GetDistance(creature.GetOwner()) > PET_FOLLOW_DIST+2.5f) + else if(creature.isPet() && creature.GetOwner() && !creature.IsWithinDist(creature.GetOwner(),PET_FOLLOW_DIST+2.5f)) { creature.SetUnitMovementFlags(MOVEMENTFLAG_NONE); _setRandomLocation(creature); diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index b8b92cbbadf..2c778616d78 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -1425,7 +1425,7 @@ struct TargetDistanceOrder : public std::binary_function" bool operator()(const Unit* _Left, const Unit* _Right) const { - return (MainTarget->GetDistance(_Left) < MainTarget->GetDistance(_Right)); + return MainTarget->GetDistanceOrder(_Left,_Right); } }; @@ -1490,7 +1490,7 @@ void Spell::SearchChainTarget(std::list &TagUnitMap, float max_range, uin if(cur->GetDistance(*next) > CHAIN_SPELL_JUMP_RADIUS) break; while(m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE - && !m_caster->isInFront(*next, max_range) + && !m_caster->isInFrontInMap(*next, max_range) || !m_caster->canSeeOrDetect(*next, false) || !cur->IsWithinLOSInMap(*next)) { @@ -4857,10 +4857,9 @@ SpellCastResult Spell::CheckRange(bool strict) if(m_targets.m_targetMask == TARGET_FLAG_DEST_LOCATION && m_targets.m_destX != 0 && m_targets.m_destY != 0 && m_targets.m_destZ != 0) { - float dist = m_caster->GetDistance(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ); - if(dist > max_range) + if(!m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ,max_range)) return SPELL_FAILED_OUT_OF_RANGE; - if(dist < min_range) + if(m_caster->IsWithinDist3d(m_targets.m_destX, m_targets.m_destY, m_targets.m_destZ,min_range)) return SPELL_FAILED_TOO_CLOSE; } diff --git a/src/game/Spell.h b/src/game/Spell.h index e2ce4668952..694bcf11277 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -668,6 +668,10 @@ namespace Trinity { Unit *target = (Unit*)itr->getSource(); + // mostly phase check + if(!itr->getSource()->IsInMap(i_source)) + continue; + switch (i_TargetType) { case SPELL_TARGETS_ENEMY: @@ -708,11 +712,11 @@ namespace Trinity i_data->push_back(target); break; case PUSH_IN_FRONT: - if(i_source->isInFront(target, i_radius, M_PI/3)) + if(i_source->isInFrontInMap(target, i_radius, M_PI/3)) i_data->push_back(target); break; case PUSH_IN_BACK: - if(i_source->isInBack(target, i_radius, M_PI/3)) + if(i_source->isInBackInMap(target, i_radius, M_PI/3)) i_data->push_back(target); break; case PUSH_IN_LINE: diff --git a/src/game/TradeHandler.cpp b/src/game/TradeHandler.cpp index 439626861fd..3cead4551c1 100644 --- a/src/game/TradeHandler.cpp +++ b/src/game/TradeHandler.cpp @@ -461,30 +461,30 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) { CHECK_PACKET_SIZE(recvPacket,8); - if( GetPlayer()->pTrader ) + if (GetPlayer()->pTrader) return; uint64 ID; - if( !GetPlayer()->isAlive() ) + if (!GetPlayer()->isAlive()) { SendTradeStatus(TRADE_STATUS_YOU_DEAD); return; } - if( GetPlayer()->hasUnitState(UNIT_STAT_STUNNED) ) + if (GetPlayer()->hasUnitState(UNIT_STAT_STUNNED)) { SendTradeStatus(TRADE_STATUS_YOU_STUNNED); return; } - if( isLogingOut() ) + if (isLogingOut()) { SendTradeStatus(TRADE_STATUS_YOU_LOGOUT); return; } - if( GetPlayer()->isInFlight() ) + if (GetPlayer()->isInFlight()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; @@ -494,43 +494,43 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) Player* pOther = ObjectAccessor::FindPlayer( ID ); - if( !pOther ) + if (!pOther) { SendTradeStatus(TRADE_STATUS_NO_TARGET); return; } - if( pOther == GetPlayer() || pOther->pTrader ) + if (pOther == GetPlayer() || pOther->pTrader) { SendTradeStatus(TRADE_STATUS_BUSY); return; } - if( !pOther->isAlive() ) + if (!pOther->isAlive()) { SendTradeStatus(TRADE_STATUS_TARGET_DEAD); return; } - if( pOther->isInFlight() ) + if (pOther->isInFlight()) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; } - if( pOther->hasUnitState(UNIT_STAT_STUNNED) ) + if (pOther->hasUnitState(UNIT_STAT_STUNNED)) { SendTradeStatus(TRADE_STATUS_TARGET_STUNNED); return; } - if( pOther->GetSession()->isLogingOut() ) + if (pOther->GetSession()->isLogingOut()) { SendTradeStatus(TRADE_STATUS_TARGET_LOGOUT); return; } - if( pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()) ) + if (pOther->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) { SendTradeStatus(TRADE_STATUS_IGNORE_YOU); return; @@ -542,7 +542,7 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket) return; } - if( pOther->GetDistance2d( _player ) > 10.0f ) + if (!pOther->IsWithinDistInMap(_player,10.0f,false)) { SendTradeStatus(TRADE_STATUS_TARGET_TO_FAR); return; diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 2c1c50c20ae..e176405d043 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -3562,7 +3562,7 @@ Spell* Unit::FindCurrentSpellBySpellId(uint32 spell_id) const return NULL; } -bool Unit::isInFront(Unit const* target, float distance, float arc) const +bool Unit::isInFrontInMap(Unit const* target, float distance, float arc) const { return IsWithinDistInMap(target, distance) && HasInArc( arc, target ); } @@ -3572,7 +3572,7 @@ void Unit::SetInFront(Unit const* target) SetOrientation(GetAngle(target)); } -bool Unit::isInBack(Unit const* target, float distance, float arc) const +bool Unit::isInBackInMap(Unit const* target, float distance, float arc) const { return IsWithinDistInMap(target, distance) && !HasInArc( 2 * M_PI - arc, target ); } diff --git a/src/game/Unit.h b/src/game/Unit.h index bb303473e7b..bbd7471b1b8 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1403,9 +1403,9 @@ class TRINITY_DLL_SPEC Unit : public WorldObject float GetWeaponDamageRange(WeaponAttackType attType ,WeaponDamageRange type) const; void SetBaseWeaponDamage(WeaponAttackType attType ,WeaponDamageRange damageRange, float value) { m_weaponDamage[attType][damageRange] = value; } - bool isInFront(Unit const* target,float distance, float arc = M_PI) const; + bool isInFrontInMap(Unit const* target,float distance, float arc = M_PI) const; void SetInFront(Unit const* target); - bool isInBack(Unit const* target, float distance, float arc = M_PI) const; + bool isInBackInMap(Unit const* target, float distance, float arc = M_PI) const; bool isInLine(Unit const* target, float distance) const; // Visibility system -- cgit v1.2.3