aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormegamage <none@none>2009-05-20 11:44:38 -0500
committermegamage <none@none>2009-05-20 11:44:38 -0500
commit6473e943581439f57918abfa91a4d5a29e2f343c (patch)
tree01b7419dcc1ac0444375d11b22cd55d72897854a /src
parentd1d194b4c78aec34d65a15ea68acff5c3a48687c (diff)
*Update Naxx scripts. Now only Kelthuzad is incompleted
--HG-- branch : trunk
Diffstat (limited to 'src')
-rw-r--r--src/bindings/scripts/include/sc_creature.cpp28
-rw-r--r--src/bindings/scripts/include/sc_creature.h5
-rw-r--r--src/bindings/scripts/scripts/creature/mob_generic_creature.cpp34
-rw-r--r--src/bindings/scripts/scripts/zone/naxxramas/boss_four_horsemen.cpp541
-rw-r--r--src/bindings/scripts/scripts/zone/naxxramas/boss_maexxna.cpp273
-rw-r--r--src/bindings/scripts/scripts/zone/naxxramas/boss_thaddius.cpp6
-rw-r--r--src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp18
-rw-r--r--src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_alar.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/zulaman/boss_nalorakk.cpp2
-rw-r--r--src/game/AggressorAI.cpp21
-rw-r--r--src/game/CreatureAI.cpp202
-rw-r--r--src/game/CreatureAI.h19
-rw-r--r--src/game/CreatureAIImpl.h10
-rw-r--r--src/game/InstanceData.cpp16
-rw-r--r--src/game/InstanceData.h2
-rw-r--r--src/game/Spell.cpp43
-rw-r--r--src/game/SpellAuras.cpp21
-rw-r--r--src/game/SpellEffects.cpp50
-rw-r--r--src/game/SpellMgr.cpp5
-rw-r--r--src/game/SpellMgr.h6
-rw-r--r--src/game/Unit.h4
-rw-r--r--src/game/UnitAI.cpp281
-rw-r--r--src/game/UnitAI.h19
23 files changed, 713 insertions, 895 deletions
diff --git a/src/bindings/scripts/include/sc_creature.cpp b/src/bindings/scripts/include/sc_creature.cpp
index e22157cd28c..3e7a1a39878 100644
--- a/src/bindings/scripts/include/sc_creature.cpp
+++ b/src/bindings/scripts/include/sc_creature.cpp
@@ -134,23 +134,6 @@ void ScriptedAI::DoStopAttack()
}
}
-void ScriptedAI::DoCast(Unit* victim, uint32 spellId, bool triggered)
-{
- if (!victim || m_creature->hasUnitState(UNIT_STAT_CASTING) && !triggered)
- return;
-
- //m_creature->StopMoving();
- m_creature->CastSpell(victim, spellId, triggered);
-}
-
-void ScriptedAI::DoCastAOE(uint32 spellId, bool triggered)
-{
- if(!triggered && m_creature->hasUnitState(UNIT_STAT_CASTING))
- return;
-
- m_creature->CastSpell((Unit*)NULL, spellId, triggered);
-}
-
void ScriptedAI::DoCastSpell(Unit* who,SpellEntry const *spellInfo, bool triggered)
{
if (!who || m_creature->IsNonMeleeSpellCasted(false))
@@ -370,15 +353,6 @@ bool ScriptedAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered)
return true;
}
-float GetSpellMaxRangeForHostile(uint32 id)
-{
- SpellEntry const *spellInfo = GetSpellStore()->LookupEntry(id);
- if(!spellInfo) return 0;
- SpellRangeEntry const *range = GetSpellRangeStore()->LookupEntry(spellInfo->rangeIndex);
- if(!range) return 0;
- return range->maxRangeHostile;
-}
-
void FillSpellSummary()
{
SpellSummary = new TSpellSummary[GetSpellStore()->GetNumRows()];
@@ -647,6 +621,7 @@ BossAI::BossAI(Creature *c, uint32 id) : ScriptedAI(c)
void BossAI::_Reset()
{
+ me->setActive(false);
events.Reset();
summons.DespawnAll();
if(instance)
@@ -663,6 +638,7 @@ void BossAI::_JustDied()
void BossAI::_EnterCombat()
{
+ me->setActive(true);
DoZoneInCombat();
if(instance)
instance->SetBossState(bossId, IN_PROGRESS);
diff --git a/src/bindings/scripts/include/sc_creature.h b/src/bindings/scripts/include/sc_creature.h
index 7ce9e7e18ff..95bcadaceeb 100644
--- a/src/bindings/scripts/include/sc_creature.h
+++ b/src/bindings/scripts/include/sc_creature.h
@@ -29,7 +29,6 @@ class SummonList : private std::list<uint64>
Creature *m_creature;
};
-float GetSpellMaxRangeForHostile(uint32 id);
//Get a single creature of given entry
Unit* FindCreature(uint32 entry, float range, Unit* Finder);
@@ -123,10 +122,6 @@ struct TRINITY_DLL_DECL ScriptedAI : public CreatureAI
//Stop attack of current victim
void DoStopAttack();
- //Cast spell by Id
- void DoCast(Unit* victim, uint32 spellId, bool triggered = false);
- void DoCastAOE(uint32 spellId, bool triggered = false);
-
//Cast spell by spell info
void DoCastSpell(Unit* who,SpellEntry const *spellInfo, bool triggered = false);
diff --git a/src/bindings/scripts/scripts/creature/mob_generic_creature.cpp b/src/bindings/scripts/scripts/creature/mob_generic_creature.cpp
index d26b724cdbf..2189cf60c6f 100644
--- a/src/bindings/scripts/scripts/creature/mob_generic_creature.cpp
+++ b/src/bindings/scripts/scripts/creature/mob_generic_creature.cpp
@@ -167,7 +167,7 @@ struct TRINITY_DLL_DECL trigger_periodicAI : public NullCreatureAI
trigger_periodicAI(Creature* c) : NullCreatureAI(c)
{
spell = me->m_spells[0] ? GetSpellStore()->LookupEntry(me->m_spells[0]) : NULL;
- interval = spell ? GetAISpellInfo(me->m_spells[0])->cooldown : 100000; //me->m_spells[1] ? me->m_spells[1] : 1000;
+ interval = me->GetAttackTime(BASE_ATTACK);
timer = interval;
}
@@ -197,6 +197,28 @@ struct TRINITY_DLL_DECL trigger_deathAI : public NullCreatureAI
}
};
+struct TRINITY_DLL_DECL mob_webwrapAI : public NullCreatureAI
+{
+ mob_webwrapAI(Creature *c) : NullCreatureAI(c), victimGUID(0) {}
+
+ uint64 victimGUID;
+
+ void SetGUID(const uint64 &guid, const int32 param)
+ {
+ victimGUID = guid;
+ if(me->m_spells[0] && victimGUID)
+ if(Unit *victim = Unit::GetUnit(*me, victimGUID))
+ victim->CastSpell(victim, me->m_spells[0], true, NULL, NULL, me->GetGUID());
+ }
+
+ void JustDied(Unit *killer)
+ {
+ if(me->m_spells[0] && victimGUID)
+ if(Unit *victim = Unit::GetUnit(*me, victimGUID))
+ victim->RemoveAurasDueToSpell(me->m_spells[0], me->GetGUID());
+ }
+};
+
CreatureAI* GetAI_trigger_periodic(Creature *_Creature)
{
return new trigger_periodicAI (_Creature);
@@ -207,6 +229,11 @@ CreatureAI* GetAI_trigger_death(Creature *_Creature)
return new trigger_deathAI (_Creature);
}
+CreatureAI* GetAI_mob_webwrap(Creature* _Creature)
+{
+ return new mob_webwrapAI (_Creature);
+}
+
void AddSC_generic_creature()
{
Script *newscript;
@@ -224,5 +251,10 @@ void AddSC_generic_creature()
newscript->Name="trigger_death";
newscript->GetAI = &GetAI_trigger_death;
newscript->RegisterSelf();*/
+
+ newscript = new Script;
+ newscript->Name="mob_webwrap";
+ newscript->GetAI = &GetAI_mob_webwrap;
+ newscript->RegisterSelf();
}
diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_four_horsemen.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_four_horsemen.cpp
index 7e77afa7167..d7969431511 100644
--- a/src/bindings/scripts/scripts/zone/naxxramas/boss_four_horsemen.cpp
+++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_four_horsemen.cpp
@@ -1,402 +1,167 @@
-/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
- /* ScriptData
- SDName: Boss_Four_Horsemen
- SD%Complete: 75
- SDComment: Lady Blaumeux, Thane Korthazz, Sir Zeliek, Baron Rivendare
- SDCategory: Naxxramas
- EndScriptData */
-
- #include "precompiled.h"
-
- //all horsemen
- #define SPELL_SHIELDWALL 29061
- #define SPELL_BESERK 26662
-
- //lady blaumeux
- #define SAY_BLAU_AGGRO -1533044
- #define SAY_BLAU_TAUNT1 -1533045
- #define SAY_BLAU_TAUNT2 -1533046
- #define SAY_BLAU_TAUNT3 -1533047
- #define SAY_BLAU_SPECIAL -1533048
- #define SAY_BLAU_SLAY -1533049
- #define SAY_BLAU_DEATH -1533050
-
- #define SPELL_MARK_OF_BLAUMEUX 28833
- #define SPELL_UNYILDING_PAIN 57381
- #define SPELL_VOIDZONE 28863
- #define H_SPELL_VOIDZONE 57463
- #define SPELL_SHADOW_BOLT 57374
- #define H_SPELL_SHADOW_BOLT 57464
+/* Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/>
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "precompiled.h"
+#include "def_naxxramas.h"
+
+enum Horsemen
+{
+ HORSEMEN_THANE,
+ HORSEMEN_LADY,
+ HORSEMEN_BARON,
+ HORSEMEN_SIR,
+};
+
+enum Events
+{
+ EVENT_MARK = 1,
+ EVENT_CAST,
+ EVENT_BERSERK,
+};
+
+const uint32 MOB_HORSEMEN[] = {16064, 16065, 30549, 16063};
+const uint32 SPELL_MARK[] = {28832, 28833, 28834, 28835};
+#define SPELL_PRIMARY(i) HEROIC(SPELL_PRIMARY_N[i],SPELL_PRIMARY_H[i])
+const uint32 SPELL_PRIMARY_N[] = {28884, 28863, 28882, 28883};
+const uint32 SPELL_PRIMARY_H[] = {57467, 57463, 57369, 57466};
+#define SPELL_SECONDARY(i) HEROIC(SPELL_SECONDARY_N[i],SPELL_SECONDARY_H[i])
+const uint32 SPELL_SECONDARY_N[]= {0, 57374, 0, 57376};
+const uint32 SPELL_SECONDARY_H[]= {0, 57464, 0, 57465};
+const uint32 SPELL_PUNISH[] = {0, 57381, 0, 57377};
+#define SPELL_BERSERK 26662
+
+const int32 SAY_AGGRO[] = {-1533051, -1533044, -1533065, -1533058};
+const int32 SAY_TAUNT[3][4] ={ {-1533052, -1533045, -1533071, -1533059},
+ {-1533053, -1533046, -1533072, -1533060},
+ {-1533054, -1533047, -1533073, -1533061},};
+const int32 SAY_SPECIAL[] = {-1533055, -1533048, -1533070, -1533062};
+const int32 SAY_SLAY[] = {-1533056, -1533049, -1533068, -1533063};
+const int32 SAY_DEATH[] = {-1533057, -1533050, -1533074, -1533064};
+
+#define SAY_BARON_AGGRO RAND(-1533065,-1533066,-1533067)
+#define SAY_BARON_SLAY RAND(-1533068,-1533069)
+
+struct TRINITY_DLL_DECL boss_four_horsemenAI : public BossAI
+{
+ boss_four_horsemenAI(Creature *c) : BossAI(c, BOSS_HORSEMEN)
+ {
+ id = Horsemen(0);
+ for(uint32 i = 1; i < 4; ++i)
+ if(me->GetEntry() == MOB_HORSEMEN[i])
+ id = Horsemen(i);
+ caster = (id == HORSEMEN_LADY || id == HORSEMEN_SIR);
+ }
- #define C_SPIRIT_OF_BLAUMEUX 16776
+ Horsemen id;
+ bool caster;
- struct TRINITY_DLL_DECL boss_lady_blaumeuxAI : public ScriptedAI
+ void MoveInLineOfSight(Unit *who)
{
- boss_lady_blaumeuxAI(Creature *c) : ScriptedAI(c) {}
-
- uint32 Mark_Timer;
- uint32 VoidZone_Timer;
- bool ShieldWall1;
- bool ShieldWall2;
+ BossAI::MoveInLineOfSight(who);
+ if(caster)
+ SelectNearestTarget(who);
+ }
- void Reset()
- {
- Mark_Timer = 20000; // First Horsemen Mark is applied at 20 sec.
- VoidZone_Timer = 12000; // right
- ShieldWall1 = true;
- ShieldWall2 = true;
- }
+ void AttackStart(Unit *who)
+ {
+ if(caster)
+ AttackStartCaster(who, 20);
+ else
+ BossAI::AttackStart(who);
+ }
- void EnterCombat(Unit *who)
+ void KilledUnit(Unit* victim)
+ {
+ if(!(rand()%5))
{
- DoScriptText(SAY_BLAU_AGGRO, m_creature);
+ if(id == HORSEMEN_BARON)
+ DoScriptText(SAY_BARON_SLAY, me);
+ else
+ DoScriptText(SAY_SLAY[id], me);
}
+ }
- void KilledUnit(Unit* Victim)
- {
- DoScriptText(SAY_BLAU_SLAY, m_creature);
- }
+ void JustDied(Unit* killer)
+ {
+ _JustDied();
+ DoScriptText(SAY_DEATH[id], me);
+ }
- void JustDied(Unit* Killer)
- {
- DoScriptText(SAY_BLAU_DEATH, m_creature);
- }
+ void EnterCombat(Unit *who)
+ {
+ _EnterCombat();
+ if(id == HORSEMEN_BARON)
+ DoScriptText(SAY_BARON_AGGRO, me);
+ else
+ DoScriptText(SAY_AGGRO[id], me);
+ events.ScheduleEvent(EVENT_MARK, 15000);
+ events.ScheduleEvent(EVENT_CAST, 20000+rand()%5000);
+ events.ScheduleEvent(EVENT_BERSERK, 15*100*1000);
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ if(!UpdateVictim() || !CheckInRoom())
+ return;
- void UpdateAI(const uint32 diff)
- {
- if (!UpdateVictim())
- return;
+ events.Update(diff);
- // Mark of Blaumeux
- if (Mark_Timer < diff)
- {
- DoCast(m_creature->getVictim(),SPELL_MARK_OF_BLAUMEUX);
- Mark_Timer = 12000;
- }else Mark_Timer -= diff;
+ if(me->hasUnitState(UNIT_STAT_CASTING))
+ return;
- // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds
- if (ShieldWall1 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50)
+ while(uint32 eventId = events.ExecuteEvent())
+ {
+ switch(eventId)
{
- if(ShieldWall1)
- {
- DoCast(m_creature,SPELL_SHIELDWALL);
- ShieldWall1 = false;
- }
- }
- if (ShieldWall2 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20)
- {
- if (ShieldWall2)
- {
- DoCast(m_creature,SPELL_SHIELDWALL);
- ShieldWall2 = false;
- }
- }
-
- // Void Zone
- if (VoidZone_Timer < diff)
- {
- DoCast(m_creature->getVictim(),SPELL_VOIDZONE);
- VoidZone_Timer = 12000;
- }else VoidZone_Timer -= diff;
-
- DoMeleeAttackIfReady();
- }
- };
-
- CreatureAI* GetAI_boss_lady_blaumeux(Creature *_Creature)
- {
- return new boss_lady_blaumeuxAI (_Creature);
- }
-
- //baron rivendare
- #define SAY_RIVE_AGGRO1 -1533065
- #define SAY_RIVE_AGGRO2 -1533066
- #define SAY_RIVE_AGGRO3 -1533067
- #define SAY_RIVE_SLAY1 -1533068
- #define SAY_RIVE_SLAY2 -1533069
- #define SAY_RIVE_SPECIAL -1533070
- #define SAY_RIVE_TAUNT1 -1533071
- #define SAY_RIVE_TAUNT2 -1533072
- #define SAY_RIVE_TAUNT3 -1533073
- #define SAY_RIVE_DEATH -1533074
-
- #define SPELL_MARK_OF_RIVENDARE 28834
- #define SPELL_UNHOLY_SHADOW 28882
- #define H_SPELL_UNHOLY_SHADOW 57369
-
- #define C_SPIRIT_OF_RIVENDARE 0 //creature entry not known yet
-
- struct TRINITY_DLL_DECL boss_rivendare_naxxAI : public ScriptedAI
- {
- boss_rivendare_naxxAI(Creature *c) : ScriptedAI(c) {}
-
- void Reset()
- {
- }
-
- void EnterCombat(Unit *who)
- {
- switch(rand()%3)
- {
- case 0: DoScriptText(SAY_RIVE_AGGRO1, m_creature); break;
- case 1: DoScriptText(SAY_RIVE_AGGRO2, m_creature); break;
- case 2: DoScriptText(SAY_RIVE_AGGRO3, m_creature); break;
- }
- }
-
- void KilledUnit(Unit* Victim)
- {
- switch(rand()%2)
- {
- case 0: DoScriptText(SAY_RIVE_SLAY1, m_creature); break;
- case 1: DoScriptText(SAY_RIVE_SLAY2, m_creature); break;
- }
- }
-
- void JustDied(Unit* Killer)
- {
- DoScriptText(SAY_RIVE_DEATH, m_creature);
- }
-
- void UpdateAI(const uint32 diff)
- {
- if (!UpdateVictim())
- return;
-
- DoMeleeAttackIfReady();
- }
- };
-
- CreatureAI* GetAI_boss_rivendare_naxx(Creature *_Creature)
- {
- return new boss_rivendare_naxxAI (_Creature);
- }
-
- //thane korthazz
- #define SAY_KORT_AGGRO -1533051
- #define SAY_KORT_TAUNT1 -1533052
- #define SAY_KORT_TAUNT2 -1533053
- #define SAY_KORT_TAUNT3 -1533054
- #define SAY_KORT_SPECIAL -1533055
- #define SAY_KORT_SLAY -1533056
- #define SAY_KORT_DEATH -1533057
-
- #define SPELL_MARK_OF_KORTHAZZ 28832
- #define SPELL_METEOR 26558 // m_creature->getVictim() auto-area spell but with a core problem
-
- #define C_SPIRIT_OF_KORTHAZZ 16778
-
- struct TRINITY_DLL_DECL boss_thane_korthazzAI : public ScriptedAI
- {
- boss_thane_korthazzAI(Creature *c) : ScriptedAI(c) {}
-
- uint32 Mark_Timer;
- uint32 Meteor_Timer;
- bool ShieldWall1;
- bool ShieldWall2;
-
- void Reset()
- {
- Mark_Timer = 20000; // First Horsemen Mark is applied at 20 sec.
- Meteor_Timer = 30000; // wrong
- ShieldWall1 = true;
- ShieldWall2 = true;
- }
-
- void EnterCombat(Unit *who)
- {
- DoScriptText(SAY_KORT_AGGRO, m_creature);
- }
-
- void KilledUnit(Unit* Victim)
- {
- DoScriptText(SAY_KORT_SLAY, m_creature);
- }
-
- void JustDied(Unit* Killer)
- {
- DoScriptText(SAY_KORT_DEATH, m_creature);
- }
-
- void UpdateAI(const uint32 diff)
- {
- if (!UpdateVictim())
- return;
-
- // Mark of Korthazz
- if (Mark_Timer < diff)
- {
- DoCast(m_creature->getVictim(),SPELL_MARK_OF_KORTHAZZ);
- Mark_Timer = 12000;
- }else Mark_Timer -= diff;
-
- // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds
- if (ShieldWall1 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50)
- {
- if (ShieldWall1)
- {
- DoCast(m_creature,SPELL_SHIELDWALL);
- ShieldWall1 = false;
- }
- }
- if (ShieldWall2 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20)
- {
- if (ShieldWall2)
- {
- DoCast(m_creature,SPELL_SHIELDWALL);
- ShieldWall2 = false;
- }
- }
-
- // Meteor
- if (Meteor_Timer < diff)
- {
- DoCast(m_creature->getVictim(),SPELL_METEOR);
- Meteor_Timer = 20000; // wrong
- }else Meteor_Timer -= diff;
-
- DoMeleeAttackIfReady();
- }
- };
-
- CreatureAI* GetAI_boss_thane_korthazz(Creature *_Creature)
- {
- return new boss_thane_korthazzAI (_Creature);
- }
-
- //sir zeliek
- #define SAY_ZELI_AGGRO -1533058
- #define SAY_ZELI_TAUNT1 -1533059
- #define SAY_ZELI_TAUNT2 -1533060
- #define SAY_ZELI_TAUNT3 -1533061
- #define SAY_ZELI_SPECIAL -1533062
- #define SAY_ZELI_SLAY -1533063
- #define SAY_ZELI_DEATH -1533064
-
- #define SPELL_MARK_OF_ZELIEK 28835
- #define SPELL_HOLY_WRATH 28883
- #define H_SPELL_HOLY_WRATH 57466
- #define SPELL_HOLY_BOLT 57376
- #define H_SPELL_HOLY_BOLT 57465
-
- #define C_SPIRIT_OF_ZELIREK 16777
-
- struct TRINITY_DLL_DECL boss_sir_zeliekAI : public ScriptedAI
- {
- boss_sir_zeliekAI(Creature *c) : ScriptedAI(c) {}
-
- uint32 Mark_Timer;
- uint32 HolyWrath_Timer;
- bool ShieldWall1;
- bool ShieldWall2;
-
- void Reset()
- {
- Mark_Timer = 20000; // First Horsemen Mark is applied at 20 sec.
- HolyWrath_Timer = 12000; // right
- ShieldWall1 = true;
- ShieldWall2 = true;
- }
-
- void EnterCombat(Unit *who)
- {
- DoScriptText(SAY_ZELI_AGGRO, m_creature);
- }
-
- void KilledUnit(Unit* Victim)
- {
- DoScriptText(SAY_ZELI_SLAY, m_creature);
- }
-
- void JustDied(Unit* Killer)
- {
- DoScriptText(SAY_ZELI_DEATH, m_creature);
- }
-
- void UpdateAI(const uint32 diff)
- {
- //Return since we have no target
- if (!UpdateVictim())
- return;
-
- // Mark of Zeliek
- if (Mark_Timer < diff)
- {
- DoCast(m_creature->getVictim(),SPELL_MARK_OF_ZELIEK);
- Mark_Timer = 12000;
- }else Mark_Timer -= diff;
-
- // Shield Wall - All 4 horsemen will shield wall at 50% hp and 20% hp for 20 seconds
- if (ShieldWall1 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50)
- {
- if (ShieldWall1)
- {
- DoCast(m_creature,SPELL_SHIELDWALL);
- ShieldWall1 = false;
- }
- }
- if (ShieldWall2 && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 20)
- {
- if (ShieldWall2)
- {
- DoCast(m_creature,SPELL_SHIELDWALL);
- ShieldWall2 = false;
- }
- }
-
- // Holy Wrath
- if (HolyWrath_Timer < diff)
- {
- DoCast(m_creature->getVictim(),SPELL_HOLY_WRATH);
- HolyWrath_Timer = 12000;
- }else HolyWrath_Timer -= diff;
-
- DoMeleeAttackIfReady();
- }
- };
-
- CreatureAI* GetAI_boss_sir_zeliek(Creature *_Creature)
- {
- return new boss_sir_zeliekAI (_Creature);
- }
-
- void AddSC_boss_four_horsemen()
- {
- Script *newscript;
-
- newscript = new Script;
- newscript->Name = "boss_lady_blaumeux";
- newscript->GetAI = &GetAI_boss_lady_blaumeux;
- newscript->RegisterSelf();
-
- newscript = new Script;
- newscript->Name = "boss_rivendare_naxx";
- newscript->GetAI = &GetAI_boss_rivendare_naxx;
- newscript->RegisterSelf();
-
- newscript = new Script;
- newscript->Name = "boss_thane_korthazz";
- newscript->GetAI = &GetAI_boss_thane_korthazz;
- newscript->RegisterSelf();
-
- newscript = new Script;
- newscript->Name = "boss_sir_zeliek";
- newscript->GetAI = &GetAI_boss_sir_zeliek;
- newscript->RegisterSelf();
- }
+ case EVENT_MARK:
+ if(!(rand()%5))
+ DoScriptText(SAY_SPECIAL[id], me);
+ DoCastAOE(SPELL_MARK[id]);
+ events.ScheduleEvent(EVENT_MARK, 15000);
+ return;
+ case EVENT_CAST:
+ if(!(rand()%5))
+ DoScriptText(SAY_TAUNT[rand()%3][id], me);
+ DoCast(SPELL_PRIMARY(id));
+ events.ScheduleEvent(EVENT_CAST, 15000);
+ return;
+ case EVENT_BERSERK:
+ DoScriptText(SAY_SPECIAL[id], me);
+ DoCast(me, EVENT_BERSERK);
+ return;
+ }
+ }
+ if(!caster)
+ DoMeleeAttackIfReady();
+ else if(!DoSpellAttackIfReady(SPELL_SECONDARY(id)))
+ DoCastAOE(SPELL_PUNISH[id]);
+ }
+};
+
+CreatureAI* GetAI_four_horsemen(Creature *_Creature)
+{
+ return new boss_four_horsemenAI (_Creature);
+}
+
+void AddSC_boss_four_horsemen()
+{
+ Script *newscript;
+ newscript = new Script;
+ newscript->Name = "boss_four_horsemen";
+ newscript->GetAI = &GetAI_four_horsemen;
+ newscript->RegisterSelf();
+}
diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_maexxna.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_maexxna.cpp
index e84374432ca..ff23e77a673 100644
--- a/src/bindings/scripts/scripts/zone/naxxramas/boss_maexxna.cpp
+++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_maexxna.cpp
@@ -1,4 +1,6 @@
-/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
+/*
+ * Copyright (C) 2008 - 2009 Trinity <http://www.trinitycore.org/>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -14,223 +16,113 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/* ScriptData
-SDName: Boss_Maexxna
-SD%Complete: 60
-SDComment: this needs review, and rewrite of the webwrap ability
-SDCategory: Naxxramas
-EndScriptData */
-
#include "precompiled.h"
+#include "def_naxxramas.h"
-#define SPELL_WEBTRAP 28622 //Spell is normally used by the webtrap on the wall NOT by Maexxna
-#define SPELL_WEBSPRAY 29484
-#define H_SPELL_WEBSPRAY 54125
-#define SPELL_POISONSHOCK 28741
-#define H_SPELL_POISONSHOCK 54122
-#define SPELL_NECROTICPOISON 28776
-#define H_SPELL_NECROTICPOISON 54121
-#define SPELL_FRENZY 54123
-#define H_SPELL_FRENZY 54124
-
-#define SPELL_SUMMON_SPIDERLING 29434
-
-#define LOC_X1 3546.796
-#define LOC_Y1 -3869.082
-#define LOC_Z1 296.450
-
-#define LOC_X2 3531.271
-#define LOC_Y2 -3847.424
-#define LOC_Z2 299.450
+#define SPELL_WEB_WRAP 28622
+#define SPELL_WEB_SPRAY HEROIC(29484,54125)
+#define SPELL_POISON_SHOCK HEROIC(28741,54122)
+#define SPELL_NECROTIC_POISON HEROIC(54121,28776)
+#define SPELL_FRENZY HEROIC(54123,54124)
-#define LOC_X3 3497.067
-#define LOC_Y3 -3843.384
-#define LOC_Z3 302.384
+#define MOB_WEB_WRAP 16486
+#define MOB_SPIDERLING 17055
-struct TRINITY_DLL_DECL mob_webwrapAI : public ScriptedAI
+#define MAX_POS_WRAP 3
+const float PosWrap[MAX_POS_WRAP][3] =
{
- mob_webwrapAI(Creature *c) : ScriptedAI(c) {}
-
- uint64 victimGUID;
-
- void Reset()
- {
- victimGUID = 0;
- }
-
- void SetVictim(Unit* victim)
- {
- if(victim)
- {
- victimGUID = victim->GetGUID();
- victim->CastSpell(victim, SPELL_WEBTRAP, true);
- }
- }
-
- void DamageTaken(Unit *done_by, uint32 &damage)
- {
- if(damage > m_creature->GetHealth())
- {
- if(victimGUID)
- {
- Unit* victim = NULL;
- victim = Unit::GetUnit((*m_creature), victimGUID);
- if(victim)
- victim->RemoveAurasDueToSpell(SPELL_WEBTRAP);
- }
- }
- }
-
- void EnterCombat(Unit *who)
- {
- }
-
- void MoveInLineOfSight(Unit *who)
- {
- }
-
- void UpdateAI(const uint32 diff)
- {
- }
+ {3546.796, -3869.082, 296.450+20},
+ {3531.271, -3847.424, 299.450+20},
+ {3497.067, -3843.384, 302.384+20},
};
-struct TRINITY_DLL_DECL boss_maexxnaAI : public ScriptedAI
+enum Events
{
- boss_maexxnaAI(Creature *c) : ScriptedAI(c) {}
+ EVENT_SPRAY = 1,
+ EVENT_SHOCK,
+ EVENT_POISON,
+ EVENT_WRAP,
+ EVENT_SUMMON,
+};
- uint32 WebTrap_Timer;
- uint32 WebSpray_Timer;
- uint32 PoisonShock_Timer;
- uint32 NecroticPoison_Timer;
- uint32 SummonSpiderling_Timer;
- bool Enraged;
+struct TRINITY_DLL_DECL boss_maexxnaAI : public BossAI
+{
+ boss_maexxnaAI(Creature *c) : BossAI(c, BOSS_MAEXXNA) {}
- void Reset()
- {
- WebTrap_Timer = 20000; //20 sec init, 40 sec normal
- WebSpray_Timer = 40000; //40 seconds
- PoisonShock_Timer = 20000; //20 seconds
- NecroticPoison_Timer = 30000; //30 seconds
- SummonSpiderling_Timer = 30000; //30 sec init, 40 sec normal
- Enraged = false;
- }
+ bool enraged;
void EnterCombat(Unit *who)
{
+ _EnterCombat();
+ enraged = false;
+ events.ScheduleEvent(EVENT_WRAP, 20000);
+ events.ScheduleEvent(EVENT_SPRAY, 40000);
+ events.ScheduleEvent(EVENT_SHOCK, 10000);
+ events.ScheduleEvent(EVENT_POISON, 5000);
+ events.ScheduleEvent(EVENT_SUMMON, 40000);
}
- void DoCastWebWrap()
+ void UpdateAI(const uint32 diff)
{
- std::list<HostilReference *> t_list = m_creature->getThreatManager().getThreatList();
- std::vector<Unit *> targets;
-
- //This spell doesn't work if we only have 1 player on threat list
- if(t_list.size() < 2)
+ if(!UpdateVictim() || !CheckInRoom())
return;
- //begin + 1 , so we don't target the one with the highest threat
- std::list<HostilReference *>::iterator itr = t_list.begin();
- std::advance(itr, 1);
- for( ; itr!= t_list.end(); ++itr) //store the threat list in a different container
- {
- Unit *target = Unit::GetUnit(*m_creature, (*itr)->getUnitGuid());
- //only on alive players
- if(target && target->isAlive() && target->GetTypeId() == TYPEID_PLAYER )
- targets.push_back( target);
- }
+ events.Update(diff);
- while(targets.size() > 3)
- //cut down to size if we have more than 3 targets
- targets.erase(targets.begin()+rand()%targets.size());
-
- int i = 0;
- for(std::vector<Unit *>::iterator itr = targets.begin(); itr!= targets.end(); ++itr, ++i)
+ while(uint32 eventId = events.ExecuteEvent())
{
- // Teleport the 3 targets to a location on the wall and summon a Web Wrap on them
- Unit *target = *itr;
- Creature* Wrap = NULL;
- if(target)
+ switch(eventId)
{
- switch(i)
+ case EVENT_WRAP:
+ for(uint32 i = 0; i < HEROIC(1,2); ++i)
+ {
+ if(Unit *target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0, true, -SPELL_WEB_WRAP))
+ {
+ target->RemoveAura(SPELL_WEB_SPRAY);
+ uint32 pos = rand()%MAX_POS_WRAP;
+ target->GetMotionMaster()->MoveJump(PosWrap[pos][0], PosWrap[pos][1], PosWrap[pos][2], 20, 20);
+ if(Creature *wrap = DoSummon(MOB_WEB_WRAP, target, 0, 60000))
+ {
+ wrap->AI()->SetGUID(target->GetGUID());
+ wrap->GetMotionMaster()->MoveJump(PosWrap[pos][0], PosWrap[pos][1], PosWrap[pos][2], 20, 20);
+ }
+ }
+ }
+ events.ScheduleEvent(EVENT_WRAP, 40000);
+ return;
+ case EVENT_SPRAY:
+ DoCastAOE(SPELL_WEB_SPRAY);
+ events.ScheduleEvent(EVENT_SPRAY, 40000);
+ return;
+ case EVENT_SHOCK:
+ DoCastAOE(SPELL_POISON_SHOCK);
+ events.ScheduleEvent(EVENT_SHOCK, 10000);
+ return;
+ case EVENT_POISON:
+ DoCast(me->getVictim(), SPELL_NECROTIC_POISON);
+ events.ScheduleEvent(EVENT_POISON, 30000);
+ return;
+ case EVENT_SUMMON:
{
- case 0:
- DoTeleportPlayer(target, LOC_X1, LOC_Y1, LOC_Z1, target->GetOrientation());
- Wrap = m_creature->SummonCreature(16486, LOC_X1, LOC_Y1, LOC_Z1, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000);
- break;
- case 1:
- DoTeleportPlayer(target, LOC_X2, LOC_Y2, LOC_Z2, target->GetOrientation());
- Wrap = m_creature->SummonCreature(16486, LOC_X2, LOC_Y2, LOC_Z2, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000);
- break;
- case 2:
- DoTeleportPlayer(target, LOC_X3, LOC_Y3, LOC_Z3, target->GetOrientation());
- Wrap = m_creature->SummonCreature(16486, LOC_X3, LOC_Y3, LOC_Z3, 0, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 120000);
- break;
- }
- if(Wrap)
- {
- Wrap->setFaction(m_creature->getFaction());
- ((mob_webwrapAI*)Wrap->AI())->SetVictim(target);
+ uint32 amount = 8+rand()%2;
+ for(uint32 i = 0; i < amount; ++i)
+ DoSummon(MOB_SPIDERLING, me);
+ events.ScheduleEvent(EVENT_SUMMON, 40000);
+ break;
}
}
- }
- }
-
- void UpdateAI(const uint32 diff)
- {
- if (!UpdateVictim())
- return;
+ }
- //WebTrap_Timer
- if (WebTrap_Timer < diff)
+ if(!enraged && HealthBelowPct(30))
{
- DoCastWebWrap();
- WebTrap_Timer = 40000;
- }else WebTrap_Timer -= diff;
-
- //WebSpray_Timer
- if (WebSpray_Timer < diff)
- {
- DoCast(m_creature->getVictim(), SPELL_WEBSPRAY);
- WebSpray_Timer = 40000;
- }else WebSpray_Timer -= diff;
-
- //PoisonShock_Timer
- if (PoisonShock_Timer < diff)
- {
- DoCast(m_creature->getVictim(), SPELL_POISONSHOCK);
- PoisonShock_Timer = 20000;
- }else PoisonShock_Timer -= diff;
-
- //NecroticPoison_Timer
- if (NecroticPoison_Timer < diff)
- {
- DoCast(m_creature->getVictim(), SPELL_NECROTICPOISON);
- NecroticPoison_Timer = 30000;
- }else NecroticPoison_Timer -= diff;
-
- //SummonSpiderling_Timer
- if (SummonSpiderling_Timer < diff)
- {
- DoCast(m_creature, SPELL_SUMMON_SPIDERLING);
- SummonSpiderling_Timer = 40000;
- }else SummonSpiderling_Timer -= diff;
-
- //Enrage if not already enraged and below 30%
- if (!Enraged && (m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 30)
- {
- DoCast(m_creature,SPELL_FRENZY);
- Enraged = true;
+ DoCast(me, SPELL_FRENZY);
+ enraged = true;
}
-
- DoMeleeAttackIfReady();
+ else
+ DoMeleeAttackIfReady();
}
};
-CreatureAI* GetAI_mob_webwrap(Creature* _Creature)
-{
- return new mob_webwrapAI (_Creature);
-}
-
CreatureAI* GetAI_boss_maexxna(Creature *_Creature)
{
return new boss_maexxnaAI (_Creature);
@@ -244,10 +136,5 @@ void AddSC_boss_maexxna()
newscript->Name="boss_maexxna";
newscript->GetAI = &GetAI_boss_maexxna;
newscript->RegisterSelf();
-
- newscript = new Script;
- newscript->Name="mob_webwrap";
- newscript->GetAI = &GetAI_mob_webwrap;
- newscript->RegisterSelf();
}
diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_thaddius.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_thaddius.cpp
index 40404b8adc3..f9f4d7edacc 100644
--- a/src/bindings/scripts/scripts/zone/naxxramas/boss_thaddius.cpp
+++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_thaddius.cpp
@@ -52,14 +52,14 @@
#define SAY_SCREAM3 -1533038
#define SAY_SCREAM4 -1533039
-#define SPELL_POLARITY_SHIFT HEROIC(39096,28089)
+#define SPELL_POLARITY_SHIFT 28089
#define SPELL_BALL_LIGHTNING 28299
#define SPELL_CHAIN_LIGHTNING HEROIC(28167,54531)
#define SPELL_BERSERK 27680
enum Events
{
- EVENT_SHIFT,
+ EVENT_SHIFT = 1,
EVENT_CHAIN,
EVENT_BERSERK,
};
@@ -69,7 +69,7 @@ struct TRINITY_DLL_DECL boss_thaddiusAI : public BossAI
boss_thaddiusAI(Creature *c) : BossAI(c, BOSS_THADDIUS)
{
// temp
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2 | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED);
}
void KilledUnit(Unit* victim)
diff --git a/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp b/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp
index d9a2c80064d..f2ba97d2858 100644
--- a/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp
+++ b/src/bindings/scripts/scripts/zone/naxxramas/instance_naxxramas.cpp
@@ -57,6 +57,7 @@ const MinionData minionData[] =
};
#define GO_GOTHIK_GATE 181170
+#define GO_HORSEMEN_CHEST 181366
#define SPELL_ERUPTION 29371
@@ -92,7 +93,7 @@ inline uint32 GetEruptionSection(float x, float y)
struct TRINITY_DLL_DECL instance_naxxramas : public InstanceData
{
instance_naxxramas(Map *map) : InstanceData(map)
- , Sapphiron(NULL)
+ , Sapphiron(NULL), GothikGate(NULL), HorsemenChest(NULL), HorsemenNum(0)
{
SetBossNumber(MAX_BOSS_NUMBER);
LoadDoorData(doorData);
@@ -100,8 +101,9 @@ struct TRINITY_DLL_DECL instance_naxxramas : public InstanceData
}
std::set<GameObject*> HeiganEruption[4];
- GameObject *GothikGate;
+ GameObject *GothikGate, *HorsemenChest;
Creature *Sapphiron;
+ uint32 HorsemenNum;
void OnCreatureCreate(Creature *creature, bool add)
{
@@ -129,6 +131,7 @@ struct TRINITY_DLL_DECL instance_naxxramas : public InstanceData
{
case GO_BIRTH: if(!add && Sapphiron) Sapphiron->AI()->DoAction(DATA_SAPPHIRON_BIRTH); return;
case GO_GOTHIK_GATE: GothikGate = add ? go : NULL; break;
+ case GO_HORSEMEN_CHEST: HorsemenChest = add ? go : NULL; break;
}
AddDoor(go, add);
@@ -148,6 +151,17 @@ struct TRINITY_DLL_DECL instance_naxxramas : public InstanceData
}
}
+ bool SetBossState(uint32 id, EncounterState state)
+ {
+ if(!InstanceData::SetBossState(id, state))
+ return false;
+
+ if(id == BOSS_HORSEMEN && state == DONE && HorsemenChest)
+ HorsemenChest->SetRespawnTime(HorsemenChest->GetRespawnDelay());
+
+ return true;
+ }
+
void HeiganErupt(uint32 section)
{
for(uint32 i = 0; i < 4; ++i)
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 5f1d92beaf1..132747a31bd 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= SelectTarget(SELECT_TARGET_RANDOM, 1, GetSpellMaxRangeForHostile(SPELL_CHARGE), true);
+ Unit *target= SelectTarget(SELECT_TARGET_RANDOM, 1, 100, true);
if(target)
DoCast(target, SPELL_CHARGE);
Charge_Timer = 30000;
diff --git a/src/bindings/scripts/scripts/zone/zulaman/boss_nalorakk.cpp b/src/bindings/scripts/scripts/zone/zulaman/boss_nalorakk.cpp
index 68b92590025..1f810059997 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 = SelectTarget(SELECT_TARGET_RANDOM, 1, GetSpellMaxRangeForHostile(SPELL_SURGE), true);
+ Unit *target = SelectTarget(SELECT_TARGET_RANDOM, 1, 45, true);
if(target)
DoCast(target, SPELL_SURGE);
Surge_Timer = 15000 + rand()%5000;
diff --git a/src/game/AggressorAI.cpp b/src/game/AggressorAI.cpp
index 218f19a1c21..d827e3e2672 100644
--- a/src/game/AggressorAI.cpp
+++ b/src/game/AggressorAI.cpp
@@ -85,26 +85,7 @@ void SpellAI::UpdateAI(const uint32 diff)
if(uint32 spellId = events.ExecuteEvent())
{
- Unit *target = NULL;
- //sLog.outError("aggre %u %u", spellId, (uint32)AISpellInfo[spellId].target);
- switch(AISpellInfo[spellId].target)
- {
- default:
- case AITARGET_SELF: target = me; break;
- case AITARGET_VICTIM: target = me->getVictim(); break;
- case AITARGET_ENEMY: target = SelectTarget(SELECT_TARGET_RANDOM); break;
- case AITARGET_ALLY: target = me; break;
- case AITARGET_BUFF: target = me; break;
- case AITARGET_DEBUFF:
- {
- const SpellEntry * spellInfo = GetSpellStore()->LookupEntry(spellId);
- bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY;
- float range = GetSpellMaxRange(spellInfo, false);
- target = SelectTarget(SELECT_TARGET_RANDOM, 0, range, playerOnly, -(int32)spellId);
- break;
- }
- }
- if(target) me->CastSpell(target, spellId, false);
+ DoCast(spellId);
events.ScheduleEvent(spellId, AISpellInfo[spellId].cooldown + rand()%AISpellInfo[spellId].cooldown);
}
else
diff --git a/src/game/CreatureAI.cpp b/src/game/CreatureAI.cpp
index 230c1d446fc..465d67ded20 100644
--- a/src/game/CreatureAI.cpp
+++ b/src/game/CreatureAI.cpp
@@ -32,7 +32,7 @@ void CreatureAI::OnCharmed(bool apply)
me->IsAIEnabled = false;
}
-AISpellInfoType * CreatureAI::AISpellInfo;
+AISpellInfoType * UnitAI::AISpellInfo;
TRINITY_DLL_SPEC AISpellInfoType * GetAISpellInfo(uint32 i) { return &CreatureAI::AISpellInfo[i]; }
void CreatureAI::DoZoneInCombat(Creature* creature)
@@ -98,6 +98,15 @@ void CreatureAI::MoveInLineOfSight(Unit *who)
AttackStart(who->getVictim());
}
+void CreatureAI::SelectNearestTarget(Unit *who)
+{
+ if(me->getVictim() && me->GetDistanceOrder(who, me->getVictim()) && me->canAttack(who))
+ {
+ me->getThreatManager().modifyThreatPercent(me->getVictim(), -100);
+ me->AddThreat(who, 1000000.0f);
+ }
+}
+
void CreatureAI::SetGazeOn(Unit *target)
{
if(me->canAttack(target))
@@ -182,197 +191,6 @@ void CreatureAI::EnterEvadeMode()
Reset();
}
-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 *, const Unit *, bool>
-{
- 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<HostilReference*> &m_threatlist = me->getThreatManager().getThreatList();
- if(position >= m_threatlist.size())
- return NULL;
-
- std::list<Unit*> targetList;
- for(std::list<HostilReference*>::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<Unit*>::iterator i = targetList.begin();
- advance(i, position);
- return *i;
- }
- else
- {
- std::list<Unit*>::reverse_iterator i = targetList.rbegin();
- advance(i, position);
- return *i;
- }
- }
- else
- {
- std::list<HostilReference*> m_threatlist = me->getThreatManager().getThreatList();
- std::list<HostilReference*>::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<Unit*> &targetList, uint32 num, SelectAggroTarget targetType, float dist, bool playerOnly, int32 aura)
-{
- if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST)
- {
- std::list<HostilReference*> &m_threatlist = m_creature->getThreatManager().getThreatList();
- if(m_threatlist.empty())
- return;
-
- for(std::list<HostilReference*>::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<HostilReference*> m_threatlist = me->getThreatManager().getThreatList();
- std::list<HostilReference*>::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 CreatureAI::FillAISpellInfo()
-{
- AISpellInfo = new AISpellInfoType[GetSpellStore()->GetNumRows()];
-
- AISpellInfoType *AIInfo = AISpellInfo;
- const SpellEntry * spellInfo;
-
- for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i, ++AIInfo)
- {
- spellInfo = GetSpellStore()->LookupEntry(i);
- if(!spellInfo)
- continue;
-
- if(spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD)
- AIInfo->condition = AICOND_DIE;
- else if(IsPassiveSpell(i) || GetSpellDuration(spellInfo) == -1)
- AIInfo->condition = AICOND_AGGRO;
- else
- AIInfo->condition = AICOND_COMBAT;
-
- if(AIInfo->cooldown < spellInfo->RecoveryTime)
- AIInfo->cooldown = spellInfo->RecoveryTime;
-
- for(uint32 j = 0; j < 3; ++j)
- {
- if(spellInfo->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ENEMY
- || spellInfo->EffectImplicitTargetA[j] == TARGET_DST_TARGET_ENEMY)
- {
- if(AIInfo->target < AITARGET_VICTIM)
- AIInfo->target = AITARGET_VICTIM;
- }
-
- if(spellInfo->Effect[j] == SPELL_EFFECT_APPLY_AURA)
- {
- if(spellInfo->EffectImplicitTargetA[j] == TARGET_UNIT_TARGET_ENEMY)
- {
- if(AIInfo->target < AITARGET_DEBUFF)
- AIInfo->target = AITARGET_DEBUFF;
- }
- else if(IsPositiveSpell(i))
- {
- if(AIInfo->target < AITARGET_BUFF)
- AIInfo->target = AITARGET_BUFF;
- }
- }
- }
- }
-}
-
/*void CreatureAI::AttackedBy( Unit* attacker )
{
if(!m_creature->getVictim())
diff --git a/src/game/CreatureAI.h b/src/game/CreatureAI.h
index fbc3e5c17b4..6a639be74bb 100644
--- a/src/game/CreatureAI.h
+++ b/src/game/CreatureAI.h
@@ -29,7 +29,6 @@ class Unit;
class Creature;
class Player;
struct SpellEntry;
-struct AISpellInfoType;
#define TIME_INTERVAL_LOOK 5000
#define VISIBILITY_RANGE 10000
@@ -59,16 +58,6 @@ enum SelectEffect
SELECT_EFFECT_AURA, //Spell applies an aura
};
-//Selection method used by SelectTarget
-enum SelectAggroTarget
-{
- SELECT_TARGET_RANDOM = 0, //Just selects a random target
- SELECT_TARGET_TOPAGGRO, //Selects targes from top aggro to bottom
- SELECT_TARGET_BOTTOMAGGRO, //Selects targets from bottom aggro to top
- SELECT_TARGET_NEAREST,
- SELECT_TARGET_FARTHEST,
-};
-
enum SCEquip
{
EQUIP_NO_CHANGE = -1,
@@ -84,6 +73,8 @@ class TRINITY_DLL_SPEC CreatureAI : public UnitAI
bool UpdateVictim();
bool UpdateVictimByReact();
bool UpdateVictimWithGaze();
+
+ void SelectNearestTarget(Unit *who);
public:
explicit CreatureAI(Creature *c) : UnitAI((Unit*)c), me(c), m_creature(c) {}
@@ -165,14 +156,8 @@ 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<Unit*> &targetList, uint32 num, SelectAggroTarget target, float dist = 0, bool playerOnly = false, int32 aura = 0);
-
void SetGazeOn(Unit *target);
- static AISpellInfoType *AISpellInfo;
- static void FillAISpellInfo();
-
protected:
bool _EnterEvadeMode();
};
diff --git a/src/game/CreatureAIImpl.h b/src/game/CreatureAIImpl.h
index f404f0d954f..38dec554f13 100644
--- a/src/game/CreatureAIImpl.h
+++ b/src/game/CreatureAIImpl.h
@@ -175,5 +175,15 @@ struct AISpellInfoType
TRINITY_DLL_SPEC AISpellInfoType * GetAISpellInfo(uint32 i);
+//Selection method used by SelectTarget
+enum SelectAggroTarget
+{
+ SELECT_TARGET_RANDOM = 0, //Just selects a random target
+ SELECT_TARGET_TOPAGGRO, //Selects targes from top aggro to bottom
+ SELECT_TARGET_BOTTOMAGGRO, //Selects targets from bottom aggro to top
+ SELECT_TARGET_NEAREST,
+ SELECT_TARGET_FARTHEST,
+};
+
#endif
diff --git a/src/game/InstanceData.cpp b/src/game/InstanceData.cpp
index fcc708e274c..bb4bfe5e8fc 100644
--- a/src/game/InstanceData.cpp
+++ b/src/game/InstanceData.cpp
@@ -188,17 +188,26 @@ void InstanceData::AddMinion(Creature *minion, bool add)
itr->second.bossInfo->minion.erase(minion);
}
-void InstanceData::SetBossState(uint32 id, EncounterState state)
+bool InstanceData::SetBossState(uint32 id, EncounterState state)
{
if(id < bosses.size())
{
BossInfo *bossInfo = &bosses[id];
if(bossInfo->state == TO_BE_DECIDED) // loading
+ {
bossInfo->state = state;
+ return false;
+ }
else
{
if(bossInfo->state == state)
- return;
+ return false;
+
+ if(state == DONE)
+ for(MinionSet::iterator i = bossInfo->minion.begin(); i != bossInfo->minion.end(); ++i)
+ if((*i)->isWorldBoss() && (*i)->isAlive())
+ return false;
+
bossInfo->state = state;
SaveToDB();
}
@@ -209,7 +218,10 @@ void InstanceData::SetBossState(uint32 id, EncounterState state)
for(MinionSet::iterator i = bossInfo->minion.begin(); i != bossInfo->minion.end(); ++i)
UpdateMinionState(*i, state);
+
+ return true;
}
+ return false;
}
std::string InstanceData::LoadBossState(const char * data)
diff --git a/src/game/InstanceData.h b/src/game/InstanceData.h
index 43042a7f914..133f92ecc60 100644
--- a/src/game/InstanceData.h
+++ b/src/game/InstanceData.h
@@ -158,7 +158,7 @@ class TRINITY_DLL_SPEC InstanceData
//use HandleGameObject(GUID,boolen,NULL); in any other script
void HandleGameObject(uint64 GUID, bool open, GameObject *go = NULL);
- virtual void SetBossState(uint32 id, EncounterState state);
+ virtual bool SetBossState(uint32 id, EncounterState state);
const BossBoundaryMap * GetBossBoundary(uint32 id) const { return id < bosses.size() ? &bosses[id].boundary : NULL; }
protected:
void SetBossNumber(uint32 number) { bosses.resize(number); }
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp
index 424bfd097fe..b1e1549cc5b 100644
--- a/src/game/Spell.cpp
+++ b/src/game/Spell.cpp
@@ -1249,8 +1249,43 @@ SpellMissInfo Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
}
// Prayer of Mending (jump animation), we need formal caster instead original for correct animation
- if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags[1] & 0x000020))
- m_caster->CastSpell(unit, 41637, true, NULL, NULL, m_originalCasterGUID);
+ if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST)
+ {
+ if(m_spellInfo->SpellFamilyFlags[1] & 0x000020)
+ m_caster->CastSpell(unit, 41637, true, NULL, NULL, m_originalCasterGUID);
+ }
+ else
+ {
+ // spell is triggered with only stackamount change but no amount change
+ switch(m_spellInfo->Id)
+ {
+ case 28832: // Mark of Korth'azz
+ case 28833: // Mark of Blaumeux
+ case 28834: // Mark of Rivendare
+ case 28835: // Mark of Zeliek
+ {
+ Aura *aur = unit->GetAura(m_spellInfo->Id);
+ if(!aur) break;
+ //int8 stack = GetParentAura()->GetStackAmount();
+ int8 stack = aur->GetStackAmount();
+ ++stack;
+ int32 damage;
+ switch(stack)
+ {
+ case 1: damage = 0; break;
+ case 2: damage = 500; break;
+ case 3: damage = 1000; break;
+ case 4: damage = 1500; break;
+ case 5: damage = 4000; break;
+ case 6: damage = 12000; break;
+ default:damage = 20000 + 1000 * (stack - 7); break;
+ }
+ if(damage)
+ m_caster->CastCustomSpell(28836, SPELLVALUE_BASE_POINT0, damage, unit);
+ break;
+ }
+ }
+ }
}
// Set aura only when successfully applied
if (unit->AddAura(Aur, false))
@@ -4610,9 +4645,9 @@ SpellCastResult Spell::CheckCast(bool strict)
case SPELL_AURA_FLY:
{
// not allow cast fly spells at old maps by players (all spells is self target)
- if(m_caster->GetTypeId()==TYPEID_PLAYER)
+ if(m_originalCaster && m_originalCaster->GetTypeId()==TYPEID_PLAYER)
{
- if( !((Player*)m_caster)->IsAllowUseFlyMountsHere() )
+ if( !((Player*)m_originalCaster)->IsAllowUseFlyMountsHere() )
return SPELL_FAILED_NOT_HERE;
}
break;
diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp
index 2145c19e6de..18abbd4c2e8 100644
--- a/src/game/SpellAuras.cpp
+++ b/src/game/SpellAuras.cpp
@@ -2351,27 +2351,6 @@ void AuraEffect::HandleAuraDummy(bool apply, bool Real, bool changeAmount)
if(caster)
caster->CastSpell(caster,13138,true,NULL,this);
return;
- case 28832: // Mark of Korth'azz
- case 28833: // Mark of Blaumeux
- case 28834: // Mark of Rivendare
- case 28835: // Mark of Zeliek
- {
- int8 stack = GetParentAura()->GetStackAmount();
- int32 damage;
- switch(stack)
- {
- case 1: return;
- case 2: damage = 500; break;
- case 3: damage = 1000; break;
- case 4: damage = 1500; break;
- case 5: damage = 4000; break;
- case 6: damage = 12000; break;
- default:damage = 20000 + 1000 * (stack - 7); break;
- }
- if(caster)
- caster->CastCustomSpell(28836, SPELLVALUE_BASE_POINT0, damage, m_target);
- return;
- }
case 34026: // kill command
{
Unit * pet = m_target->GetGuardianPet();
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp
index 3d1cdbf595b..ada90e881ae 100644
--- a/src/game/SpellEffects.cpp
+++ b/src/game/SpellEffects.cpp
@@ -339,14 +339,45 @@ void Spell::SpellDamageSchoolDmg(uint32 effect_idx)
{
// Positive/Negative Charge
case 28062:
- case 39090:
case 28085:
+ case 39090:
case 39093:
- if(m_triggeredByAuraSpell && unitTarget->HasAura(m_triggeredByAuraSpell->Id))
+ if(!m_triggeredByAuraSpell)
+ break;
+ if(unitTarget == m_caster)
{
- damage = 0;
- m_caster->CastSpell(m_caster, (m_spellInfo->Id == 28062 || m_spellInfo->Id == 39090) ? 29659 : 29660, true);
+ uint8 count = 0;
+ for(std::list<TargetInfo>::iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
+ if(ihit->targetGUID != m_caster->GetGUID())
+ if(Player *target = ObjectAccessor::FindPlayer(ihit->targetGUID))
+ if(target->HasAura(m_triggeredByAuraSpell->Id))
+ ++count;
+ if(count)
+ {
+ uint32 spellId;
+ switch(m_spellInfo->Id)
+ {
+ case 28062: spellId = 29659; break;
+ case 28085: spellId = 29660; break;
+ case 39090: spellId = 39089; break;
+ case 39093: spellId = 39092; break;
+ }
+ Aura *aur = m_caster->GetAura(spellId);
+ if(!aur)
+ {
+ m_caster->CastSpell(m_caster, spellId, true);
+ aur = m_caster->GetAura(spellId);
+ }
+ if(aur)
+ aur->SetStackAmount(count);
+ }
}
+ else if(unitTarget->HasAura(m_triggeredByAuraSpell->Id))
+ damage = 0;
+ break;
+ // Consumption
+ case 28865:
+ damage = (m_caster->GetMap()->IsHeroic() ? 4250 : 2750);
break;
// percent from health with min
case 25599: // Thundercrash
@@ -1023,8 +1054,15 @@ void Spell::EffectDummy(uint32 i)
return;
}
// Polarity Shift
- case 28089: spell_id = roll_chance_i(50) ? 28059 : 28084; break;
- case 39096: spell_id = roll_chance_i(50) ? 39088 : 39091; break;
+ case 28089:
+ if(unitTarget)
+ unitTarget->CastSpell(unitTarget, roll_chance_i(50) ? 28059 : 28084, true, NULL, NULL, m_caster->GetGUID());
+ break;
+ // Polarity Shift
+ case 39096:
+ if(unitTarget)
+ unitTarget->CastSpell(unitTarget, roll_chance_i(50) ? 39088 : 39091, true, NULL, NULL, m_caster->GetGUID());
+ break;
case 29200: // Purify Helboar Meat
{
if( m_caster->GetTypeId() != TYPEID_PLAYER )
diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp
index 4c83d286620..e60931dc11e 100644
--- a/src/game/SpellMgr.cpp
+++ b/src/game/SpellMgr.cpp
@@ -3190,6 +3190,7 @@ void SpellMgr::LoadSpellCustomAttr()
break;
case 24340: case 26558: case 28884: // Meteor
case 36837: case 38903: case 41276: // Meteor
+ case 57467: // Meteor
case 26789: // Shard of the Fallen Star
case 31436: // Malevolent Cleave
case 35181: // Dive Bomb
@@ -3199,8 +3200,8 @@ void SpellMgr::LoadSpellCustomAttr()
mSpellCustomAttr[i] |= SPELL_ATTR_CU_SHARE_DAMAGE;
break;
case 27820: // Mana Detonation
- case 28062: case 39090: // Positive/Negative Charge
- case 28085: case 39093:
+ //case 28062: case 39090: // Positive/Negative Charge
+ //case 28085: case 39093:
mSpellCustomAttr[i] |= SPELL_ATTR_CU_EXCLUDE_SELF;
break;
case 44978: case 45001: case 45002: // Wild Magic
diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h
index 4427e4c6abb..66874f02b57 100644
--- a/src/game/SpellMgr.h
+++ b/src/game/SpellMgr.h
@@ -184,6 +184,12 @@ inline float GetSpellMinRange(SpellEntry const *spellInfo, bool positive)
? GetSpellMinRangeForFriend(sSpellRangeStore.LookupEntry(spellInfo->rangeIndex))
: GetSpellMinRangeForHostile(sSpellRangeStore.LookupEntry(spellInfo->rangeIndex));
}
+inline float GetSpellMaxRange(uint32 id, bool positive)
+{
+ SpellEntry const *spellInfo = GetSpellStore()->LookupEntry(id);
+ if(!spellInfo) return 0;
+ return GetSpellMaxRange(spellInfo, positive);
+}
/*struct DispelEntry
{
diff --git a/src/game/Unit.h b/src/game/Unit.h
index 5267c272677..b22902ba40b 100644
--- a/src/game/Unit.h
+++ b/src/game/Unit.h
@@ -83,7 +83,9 @@ enum SpellAuraInterruptFlags
AURA_INTERRUPT_FLAG_UNK21 = 0x00200000, // 21
AURA_INTERRUPT_FLAG_TELEPORTED = 0x00400000, // 22
AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT = 0x00800000, // 23 removed by entering pvp combat
- AURA_INTERRUPT_FLAG_DIRECT_DAMAGE = 0x01000000 // 24 removed by any direct damage
+ AURA_INTERRUPT_FLAG_DIRECT_DAMAGE = 0x01000000, // 24 removed by any direct damage
+
+ AURA_INTERRUPT_FLAG_NOT_VICTIM = (AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_DAMAGE | AURA_INTERRUPT_FLAG_DIRECT_DAMAGE),
};
enum SpellModOp
diff --git a/src/game/UnitAI.cpp b/src/game/UnitAI.cpp
index 12dc20692c6..c159861697c 100644
--- a/src/game/UnitAI.cpp
+++ b/src/game/UnitAI.cpp
@@ -22,17 +22,19 @@
#include "Player.h"
#include "Creature.h"
#include "SpellAuras.h"
+#include "SpellMgr.h"
+#include "CreatureAIImpl.h"
void UnitAI::AttackStart(Unit *victim)
{
- if(!victim)
- return;
-
- if(me->Attack(victim, true))
- {
- //DEBUG_LOG("Creature %s tagged a victim to kill [guid=%u]", me->GetName(), victim->GetGUIDLow());
+ if(victim && me->Attack(victim, true))
me->GetMotionMaster()->MoveChase(victim);
- }
+}
+
+void UnitAI::AttackStartCaster(Unit *victim, float dist)
+{
+ if(victim && me->Attack(victim, false))
+ me->GetMotionMaster()->MoveChase(victim, dist);
}
void UnitAI::DoMeleeAttackIfReady()
@@ -61,6 +63,271 @@ void UnitAI::DoMeleeAttackIfReady()
}
}
+bool UnitAI::DoSpellAttackIfReady(uint32 spell)
+{
+ if(me->hasUnitState(UNIT_STAT_CASTING))
+ return true;
+
+ if(me->isAttackReady())
+ {
+ if(me->IsWithinCombatRange(me->getVictim(), GetSpellMaxRange(spell, false)))
+ {
+ me->CastSpell(me->getVictim(), spell, false);
+ me->resetAttackTimer();
+ }
+ else
+ return false;
+ }
+ return true;
+}
+
+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 *, const Unit *, bool>
+{
+ 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* UnitAI::SelectTarget(SelectAggroTarget targetType, uint32 position, float dist, bool playerOnly, int32 aura)
+{
+ if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST)
+ {
+ std::list<HostilReference*> &m_threatlist = me->getThreatManager().getThreatList();
+ if(position >= m_threatlist.size())
+ return NULL;
+
+ std::list<Unit*> targetList;
+ for(std::list<HostilReference*>::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(me));
+
+ if(targetType == SELECT_TARGET_NEAREST)
+ {
+ std::list<Unit*>::iterator i = targetList.begin();
+ advance(i, position);
+ return *i;
+ }
+ else
+ {
+ std::list<Unit*>::reverse_iterator i = targetList.rbegin();
+ advance(i, position);
+ return *i;
+ }
+ }
+ else
+ {
+ std::list<HostilReference*> m_threatlist = me->getThreatManager().getThreatList();
+ std::list<HostilReference*>::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 UnitAI::SelectTargetList(std::list<Unit*> &targetList, uint32 num, SelectAggroTarget targetType, float dist, bool playerOnly, int32 aura)
+{
+ if(targetType == SELECT_TARGET_NEAREST || targetType == SELECT_TARGET_FARTHEST)
+ {
+ std::list<HostilReference*> &m_threatlist = me->getThreatManager().getThreatList();
+ if(m_threatlist.empty())
+ return;
+
+ for(std::list<HostilReference*>::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<HostilReference*> m_threatlist = me->getThreatManager().getThreatList();
+ std::list<HostilReference*>::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 UnitAI::DoCast(uint32 spellId)
+{
+ Unit *target = NULL;
+ //sLog.outError("aggre %u %u", spellId, (uint32)AISpellInfo[spellId].target);
+ switch(AISpellInfo[spellId].target)
+ {
+ default:
+ case AITARGET_SELF: target = me; break;
+ case AITARGET_VICTIM: target = me->getVictim(); break;
+ case AITARGET_ENEMY:
+ {
+ const SpellEntry * spellInfo = GetSpellStore()->LookupEntry(spellId);
+ bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY;
+ float range = GetSpellMaxRange(spellInfo, false);
+ target = SelectTarget(SELECT_TARGET_RANDOM, 0, GetSpellMaxRange(spellInfo, false), playerOnly);
+ break;
+ }
+ case AITARGET_ALLY: target = me; break;
+ case AITARGET_BUFF: target = me; break;
+ case AITARGET_DEBUFF:
+ {
+ const SpellEntry * spellInfo = GetSpellStore()->LookupEntry(spellId);
+ bool playerOnly = spellInfo->AttributesEx3 & SPELL_ATTR_EX3_PLAYERS_ONLY;
+ float range = GetSpellMaxRange(spellInfo, false);
+ if(!(spellInfo->Attributes & SPELL_ATTR_BREAKABLE_BY_DAMAGE)
+ && !(spellInfo->AuraInterruptFlags & AURA_INTERRUPT_FLAG_NOT_VICTIM)
+ && SelectTargetHelper(me, me->getVictim(), playerOnly, range, -(int32)spellId))
+ target = me->getVictim();
+ else
+ target = SelectTarget(SELECT_TARGET_RANDOM, 0, range, playerOnly, -(int32)spellId);
+ break;
+ }
+ }
+
+ if(target)
+ me->CastSpell(target, spellId, false);
+}
+
+void UnitAI::DoCast(Unit* victim, uint32 spellId, bool triggered)
+{
+ if(!victim || me->hasUnitState(UNIT_STAT_CASTING) && !triggered)
+ return;
+
+ me->CastSpell(victim, spellId, triggered);
+}
+
+void UnitAI::DoCastAOE(uint32 spellId, bool triggered)
+{
+ if(!triggered && me->hasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ me->CastSpell((Unit*)NULL, spellId, triggered);
+}
+
+#define UPDATE_TARGET(a) {if(AIInfo->target<a) AIInfo->target=a;}
+
+void UnitAI::FillAISpellInfo()
+{
+ AISpellInfo = new AISpellInfoType[GetSpellStore()->GetNumRows()];
+
+ AISpellInfoType *AIInfo = AISpellInfo;
+ const SpellEntry * spellInfo;
+
+ for(uint32 i = 0; i < GetSpellStore()->GetNumRows(); ++i, ++AIInfo)
+ {
+ spellInfo = GetSpellStore()->LookupEntry(i);
+ if(!spellInfo)
+ continue;
+
+ if(spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_DEAD)
+ AIInfo->condition = AICOND_DIE;
+ else if(IsPassiveSpell(i) || GetSpellDuration(spellInfo) == -1)
+ AIInfo->condition = AICOND_AGGRO;
+ else
+ AIInfo->condition = AICOND_COMBAT;
+
+ if(AIInfo->cooldown < spellInfo->RecoveryTime)
+ AIInfo->cooldown = spellInfo->RecoveryTime;
+
+ if(!GetSpellMaxRange(spellInfo, false))
+ UPDATE_TARGET(AITARGET_SELF)
+ else
+ {
+ for(uint32 j = 0; j < 3; ++j)
+ {
+ uint32 targetType = spellInfo->EffectImplicitTargetA[j];
+
+ if(targetType == TARGET_UNIT_TARGET_ENEMY
+ || targetType == TARGET_DST_TARGET_ENEMY)
+ UPDATE_TARGET(AITARGET_VICTIM)
+ else if(targetType == TARGET_UNIT_AREA_ENEMY_DST)
+ UPDATE_TARGET(AITARGET_ENEMY)
+
+ if(spellInfo->Effect[j] == SPELL_EFFECT_APPLY_AURA)
+ {
+ if(targetType == TARGET_UNIT_TARGET_ENEMY)
+ UPDATE_TARGET(AITARGET_DEBUFF)
+ else if(IsPositiveSpell(i))
+ UPDATE_TARGET(AITARGET_BUFF)
+ }
+ }
+ }
+ }
+}
+
//Enable PlayerAI when charmed
void PlayerAI::OnCharmed(bool apply) { me->IsAIEnabled = apply; }
diff --git a/src/game/UnitAI.h b/src/game/UnitAI.h
index 04de74f480e..095edb0fc3e 100644
--- a/src/game/UnitAI.h
+++ b/src/game/UnitAI.h
@@ -25,6 +25,8 @@
class Unit;
class Player;
+struct AISpellInfoType;
+enum SelectAggroTarget;
class TRINITY_DLL_SPEC UnitAI
{
@@ -43,10 +45,23 @@ class TRINITY_DLL_SPEC UnitAI
virtual void OnCharmed(bool apply) = 0;
// Pass parameters between AI
- virtual void DoAction(const int32 param) {}
+ virtual void DoAction(const int32 param = 0) {}
+ virtual void SetGUID(const uint64 &guid, const int32 param = 0) {}
+
+ Unit* SelectTarget(SelectAggroTarget target, uint32 position = 0, float dist = 0, bool playerOnly = false, int32 aura = 0);
+ void SelectTargetList(std::list<Unit*> &targetList, uint32 num, SelectAggroTarget target, float dist = 0, bool playerOnly = false, int32 aura = 0);
+
+ void AttackStartCaster(Unit *victim, float dist);
+
+ void DoCast(uint32 spellId);
+ void DoCast(Unit* victim, uint32 spellId, bool triggered = false);
+ void DoCastAOE(uint32 spellId, bool triggered = false);
- //Do melee swing of current victim if in rnage and ready and not casting
void DoMeleeAttackIfReady();
+ bool DoSpellAttackIfReady(uint32 spell);
+
+ static AISpellInfoType *AISpellInfo;
+ static void FillAISpellInfo();
};
class TRINITY_DLL_SPEC PlayerAI : public UnitAI