diff options
author | megamage <none@none> | 2009-05-20 11:44:38 -0500 |
---|---|---|
committer | megamage <none@none> | 2009-05-20 11:44:38 -0500 |
commit | 6473e943581439f57918abfa91a4d5a29e2f343c (patch) | |
tree | 01b7419dcc1ac0444375d11b22cd55d72897854a /src | |
parent | d1d194b4c78aec34d65a15ea68acff5c3a48687c (diff) |
*Update Naxx scripts. Now only Kelthuzad is incompleted
--HG--
branch : trunk
Diffstat (limited to 'src')
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 |