aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/EventAI.txt20
-rw-r--r--sql/updates/3233_world_scripts_naxx.sql46
-rw-r--r--sql/updates/3427_world_scripts_(naxx).sql113
-rw-r--r--sql/world_scripts_full.sql7
-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
27 files changed, 871 insertions, 923 deletions
diff --git a/doc/EventAI.txt b/doc/EventAI.txt
index 0cb27885328..7a2087decc7 100644
--- a/doc/EventAI.txt
+++ b/doc/EventAI.txt
@@ -1,6 +1,6 @@
-=========================================
-EventAI documentation
-=========================================
+=============================================
+EventAI documentation: (Updated May 19, 2009)
+=============================================
EventAI allows users to create new creature scripts entierly within the database.
@@ -67,7 +67,7 @@ Some events such as EVENT_T_AGGRO, EVENT_T_DEATH, EVENT_T_SPAWNED, and EVENT_T_E
5 EVENT_T_KILL RepeatMin, RepeatMax Expires upon killing a player. Will repeat between every (Param1) and (Param2).
6 EVENT_T_DEATH NONE Expires upon Death of the Creature.
7 EVENT_T_EVADE NONE Expires upon creature EnterEvadeMode().
-8 EVENT_T_SPELLHIT SpellID, School, RepeatMin, RepeatMax Expires upon Spell hit. If (param1) is set will only expire on that spell. If (param2) will only expire on spells of that school (-1 for all). Will repeat every (Param3) and (Param4) .
+8 EVENT_T_SPELLHIT SpellID, Schoolmask, RepeatMin, RepeatMax Expires upon Spell hit. If (param1) is set will only expire on that spell. If (param2) will only expire on spells of the selected schools (-1 for all). Will repeat every (Param3) and (Param4) .
9 EVENT_T_RANGE MinDist, MaxDist, RepeatMin, RepeatMax Expires when the highest threat target distance is greater than (Param1) and less than (Param2). Will repeat every (Param3) and (Param4) .
10 EVENT_T_OOC_LOS Hostile-or-Not, MaxAllowedRange, RepeatMin, RepeatMax Expires when a Unit moves within distance(MaxAllowedRange) to creature. If Param1=0 it will expire if Unit are Hostile. If Param1=1 it will only expire if Unit are not Hostile(generally determined by faction). Will repeat every (Param3) and (Param4). Does not expire when the creature is in combat.
11 EVENT_T_SPAWNED NONE Expires at initial spawn and at creature respawn (useful for setting ranged movement type)
@@ -219,9 +219,19 @@ Parameter 2: School - Spell School to trigger the event (NOTE: If you use a Spel
Parameter 3: RepeatMin - Minimum Time used to calculate Random Repeat Expire
Parameter 4: RepeatMax - Maximum Time used to calculate Random Repeat Expire
-BOTH - Expires upon Spell hit. If (param1) is set will only expire on that spell. If (param2) will only expire on spells of that school. Will repeat every (Param3) and (Param4).
+BOTH - Expires upon Spell hit. If (param1) is set will only expire on that spell OR If (param2) is set it will only expire on spells of that school. Will repeat every (Param3) and (Param4).
This Event is commonly used for NPC's who can do special things when you cast a spell (Or specific spell) on them.
+(name, school, schoolmask)
+SPELL_SCHOOL_NORMAL = 0, ==> 1
+SPELL_SCHOOL_HOLY = 1, ==> 2
+SPELL_SCHOOL_FIRE = 2, ==> 4
+SPELL_SCHOOL_NATURE = 3, ==> 8
+SPELL_SCHOOL_FROST = 4, ==> 16
+SPELL_SCHOOL_SHADOW = 5, ==> 32
+SPELL_SCHOOL_ARCANE = 6, ==> 64
+Use These Values For Schoolmask (Param2) or Any Combinations Of These Schoolmasks for Multiple Schools.
+
------------------
9 = EVENT_T_RANGE:
------------------
diff --git a/sql/updates/3233_world_scripts_naxx.sql b/sql/updates/3233_world_scripts_naxx.sql
index fc582058259..bb437c29669 100644
--- a/sql/updates/3233_world_scripts_naxx.sql
+++ b/sql/updates/3233_world_scripts_naxx.sql
@@ -1,4 +1,11 @@
-DELETE FROM `spell_linked_spell` WHERE `spell_trigger` IN (28732,54097,-29865,-55053,-28169,28059,39088,-28059,-39088,28062,39090,28084,39091,-28084,-39091,28085,39093);
+UPDATE `creature_template` SET `ScriptName`='mob_webwrap' WHERE `entry`=16486;
+UPDATE `creature_template` SET `ScriptName`='boss_grobbulus' WHERE entry = 15931;
+UPDATE `creature_template` SET `ScriptName`='mob_gothik_minion' WHERE entry IN (16124,16125,16126,16127,16148,16149,16150);
+UPDATE `creature_template` SET `ScriptName`='boss_four_horsemen' WHERE `entry` IN (16063,16064,16065,30549);
+
+DELETE FROM `spell_linked_spell` WHERE `spell_trigger` IN
+(28732,54097,-29865,-55053,-28169,28059,39088,-28059,-39088,28062,39090,28084,
+39091,-28084,-39091,28085,39093);
INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comment`) VALUES
( 28732,-28798, 1, 'Widow\'s Embrace - Frenzy'),
( 54097,-54100, 1, 'Widow\'s Embrace - Frenzy (H)'),
@@ -7,36 +14,35 @@ INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comm
(-28169, 28206, 0, 'Mutating Injection - Mutagen Explosion'),
(-28169, 28240, 0, 'Mutating Injection - Poison Cloud'),
( 28059,-28084, 1, 'Positive Charge - Negative Charge'),
-( 39088,-39091, 1, 'Positive Charge - Negative Charge'),
(-28059,-29659, 0, 'Positive Charge'),
-(-39088,-29659, 0, 'Positive Charge'),
-( 28062,-29659, 0, 'Positive Charge'),
-( 39090,-29659, 0, 'Positive Charge'),
+# ( 28062,-29659, 0, 'Positive Charge'),
( 28084,-28059, 1, 'Negative Charge - Positive Charge'),
-( 39091,-39088, 1, 'Negative Charge - Positive Charge'),
(-28084,-29660, 0, 'Negative Charge'),
-(-39091,-29660, 0, 'Negative Charge'),
-( 28085,-29660, 0, 'Negative Charge'),
-( 39093,-29660, 0, 'Negative Charge');
-
-
-UPDATE creature_template SET scriptname = 'boss_grobbulus' WHERE entry = 15931;
-update creature_template set scriptname='mob_gothik_minion' where entry in (16124,16125,16126,16127,16148,16149,16150);
+# ( 28085,-29660, 0, 'Negative Charge'),
+( 39088,-39091, 1, 'Positive Charge - Negative Charge'),
+(-39088,-29659, 0, 'Positive Charge'),
+# ( 39090,-29659, 0, 'Positive Charge'),
+( 39091,-39088, 1, 'Negative Charge - Positive Charge'),
+(-39091,-39092, 0, 'Negative Charge');
+# ( 39093,-39092, 0, 'Negative Charge');
INSERT INTO creature_template (entry, spell1, flags_extra, scriptname) VALUES
(16363, 28158, 128, ''), # Grobbulus Cloud
-(29379, 54362, 128, '') # Grobbulus Cloud (H)
+(29379, 54362, 128, ''), # Grobbulus Cloud (H)
+(16697, 28158, 128, ''), # Void Zone
+(29379, 54362, 128, '') # Void Zone (H)
ON DUPLICATE KEY UPDATE
spell1 = VALUES(spell1),
flags_extra = VALUES(flags_extra),
scriptname = VALUES(scriptname);
-INSERT INTO creature_template (entry, spell1, spell2, flags_extra, scriptname) VALUES
-(16474, 28547, 0, 128, 'trigger_periodic'), # Blizzard (Sapphiron)
-(30000, 55699, 0, 128, 'trigger_periodic') # Blizzard (Sapphiron) (H)
+INSERT INTO creature_template (entry, baseattacktime, spell1, flags_extra, scriptname) VALUES
+(16474, 1000, 28547, 128, 'trigger_periodic'), # Blizzard (Sapphiron)
+(30000, 1000, 55699, 128, 'trigger_periodic'), # Blizzard (Sapphiron) (H)
+(16697, 1000, 28865, 128, 'trigger_periodic') # Void Zone (Lady Blaumeux)
ON DUPLICATE KEY UPDATE
+baseattacktime = VALUES(baseattacktime),
spell1 = VALUES(spell1),
-spell2 = VALUES(spell2),
flags_extra = VALUES(flags_extra),
scriptname = VALUES(scriptname);
@@ -64,6 +70,10 @@ INSERT INTO creature_template (entry, spell1, spell2, spell3, spell4, spell5, sp
(29256, 15284, 28991, 56098, 34970, 0, 0, 0, 28864), # Crypt Guard (H)
(16506, 54095, 0, 0, 0, 0, 0, 0, 28732), # Naxxramas Worshipper
(29274, 54096, 0, 0, 0, 0, 0, 0, 54097), # Naxxramas Worshipper (H)
+(17055, 54121, 0, 0, 0, 0, 0, 0, 0), # Maexxna Spiderling
+(29279, 28776, 0, 0, 0, 0, 0, 0, 0), # Maexxna Spiderling (H)
+(16486, 28622, 0, 0, 0, 0, 0, 0, 0), # Web Wrap
+(30183, 28622, 0, 0, 0, 0, 0, 0, 0), # Web Wrap (H)
(16984, 15496, 0, 0, 0, 0, 0, 0, 0), # Plagued Warrior
(29632, 15496, 0, 0, 0, 0, 0, 0, 0), # Plagued Warrior (H)
(16983, 32736, 30138, 0, 0, 0, 0, 0, 0), # Plagued Champion
diff --git a/sql/updates/3427_world_scripts_(naxx).sql b/sql/updates/3427_world_scripts_(naxx).sql
new file mode 100644
index 00000000000..bb437c29669
--- /dev/null
+++ b/sql/updates/3427_world_scripts_(naxx).sql
@@ -0,0 +1,113 @@
+UPDATE `creature_template` SET `ScriptName`='mob_webwrap' WHERE `entry`=16486;
+UPDATE `creature_template` SET `ScriptName`='boss_grobbulus' WHERE entry = 15931;
+UPDATE `creature_template` SET `ScriptName`='mob_gothik_minion' WHERE entry IN (16124,16125,16126,16127,16148,16149,16150);
+UPDATE `creature_template` SET `ScriptName`='boss_four_horsemen' WHERE `entry` IN (16063,16064,16065,30549);
+
+DELETE FROM `spell_linked_spell` WHERE `spell_trigger` IN
+(28732,54097,-29865,-55053,-28169,28059,39088,-28059,-39088,28062,39090,28084,
+39091,-28084,-39091,28085,39093);
+INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comment`) VALUES
+( 28732,-28798, 1, 'Widow\'s Embrace - Frenzy'),
+( 54097,-54100, 1, 'Widow\'s Embrace - Frenzy (H)'),
+(-29865, 55594, 0, 'Deathbloom'),
+(-55053, 55601, 0, 'Deathbloom (H)'),
+(-28169, 28206, 0, 'Mutating Injection - Mutagen Explosion'),
+(-28169, 28240, 0, 'Mutating Injection - Poison Cloud'),
+( 28059,-28084, 1, 'Positive Charge - Negative Charge'),
+(-28059,-29659, 0, 'Positive Charge'),
+# ( 28062,-29659, 0, 'Positive Charge'),
+( 28084,-28059, 1, 'Negative Charge - Positive Charge'),
+(-28084,-29660, 0, 'Negative Charge'),
+# ( 28085,-29660, 0, 'Negative Charge'),
+( 39088,-39091, 1, 'Positive Charge - Negative Charge'),
+(-39088,-29659, 0, 'Positive Charge'),
+# ( 39090,-29659, 0, 'Positive Charge'),
+( 39091,-39088, 1, 'Negative Charge - Positive Charge'),
+(-39091,-39092, 0, 'Negative Charge');
+# ( 39093,-39092, 0, 'Negative Charge');
+
+INSERT INTO creature_template (entry, spell1, flags_extra, scriptname) VALUES
+(16363, 28158, 128, ''), # Grobbulus Cloud
+(29379, 54362, 128, ''), # Grobbulus Cloud (H)
+(16697, 28158, 128, ''), # Void Zone
+(29379, 54362, 128, '') # Void Zone (H)
+ON DUPLICATE KEY UPDATE
+spell1 = VALUES(spell1),
+flags_extra = VALUES(flags_extra),
+scriptname = VALUES(scriptname);
+
+INSERT INTO creature_template (entry, baseattacktime, spell1, flags_extra, scriptname) VALUES
+(16474, 1000, 28547, 128, 'trigger_periodic'), # Blizzard (Sapphiron)
+(30000, 1000, 55699, 128, 'trigger_periodic'), # Blizzard (Sapphiron) (H)
+(16697, 1000, 28865, 128, 'trigger_periodic') # Void Zone (Lady Blaumeux)
+ON DUPLICATE KEY UPDATE
+baseattacktime = VALUES(baseattacktime),
+spell1 = VALUES(spell1),
+flags_extra = VALUES(flags_extra),
+scriptname = VALUES(scriptname);
+
+DELETE FROM `npc_spellclick_spells` WHERE `npc_entry` IN (29912);
+INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `quest_id`, `cast_flags`) VALUES
+(29912, 55479, 0, 1); # Obedience Crystal - Force Obedience
+
+DELETE FROM `spell_script_target` WHERE `entry` IN
+(28732,54097,55479,
+27892,27893,27928,27929,27935,27936);
+INSERT INTO `spell_script_target` (`entry`, `type`, `targetEntry`) VALUES
+(28732, 1, 15953), # Widow's Embrace
+(54097, 1, 15953), # Widow's Embrace
+(55479, 1, 16803), # Force Obedience - Death Knight Understudy
+# (29105, 1, 16803), # Hopeless - Death Knight Understudy
+(27892, 1, 16060), # To Anchor 1 - Gothik
+(27893, 1, 16060), # To Anchor 2 - Gothik
+(27928, 1, 16060), # To Anchor 1 - Gothik
+(27929, 1, 16060), # To Anchor 2 - Gothik
+(27935, 1, 16060), # To Anchor 1 - Gothik
+(27936, 1, 16060); # To Anchor 2 - Gothik
+
+INSERT INTO creature_template (entry, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8) VALUES
+(16573, 15284, 28991, 28969, 34970, 0, 0, 0, 28864), # Crypt Guard
+(29256, 15284, 28991, 56098, 34970, 0, 0, 0, 28864), # Crypt Guard (H)
+(16506, 54095, 0, 0, 0, 0, 0, 0, 28732), # Naxxramas Worshipper
+(29274, 54096, 0, 0, 0, 0, 0, 0, 54097), # Naxxramas Worshipper (H)
+(17055, 54121, 0, 0, 0, 0, 0, 0, 0), # Maexxna Spiderling
+(29279, 28776, 0, 0, 0, 0, 0, 0, 0), # Maexxna Spiderling (H)
+(16486, 28622, 0, 0, 0, 0, 0, 0, 0), # Web Wrap
+(30183, 28622, 0, 0, 0, 0, 0, 0, 0), # Web Wrap (H)
+(16984, 15496, 0, 0, 0, 0, 0, 0, 0), # Plagued Warrior
+(29632, 15496, 0, 0, 0, 0, 0, 0, 0), # Plagued Warrior (H)
+(16983, 32736, 30138, 0, 0, 0, 0, 0, 0), # Plagued Champion
+(29632, 32736, 54889, 0, 0, 0, 0, 0, 0), # Plagued Champion (H)
+(16981, 15496, 54890, 0, 0, 0, 0, 0, 0), # Plagued Guardian
+(29632, 15496, 54891, 0, 0, 0, 0, 0, 0), # Plagued Guardian (H)
+(16286, 0, 0, 0, 0, 0, 0, 0, 29232), # Spore
+(30068, 0, 0, 0, 0, 0, 0, 0, 29232), # Spore (H)
+(16290, 28156, 0, 0, 0, 0, 0, 0, 0), # Fallout Slime
+(29388, 54367, 0, 0, 0, 0, 0, 0, 0), # Fallout Slime (H)
+(16360, 29307, 0, 0, 0, 0, 0, 0, 0), # Zombie Chow
+(30303, 29307, 0, 0, 0, 0, 0, 0, 0), # Zombie Chow (H)
+(16803, 0, 0, 0, 61696, 29060, 29061, 0, 0), # Death Knight Understudy
+(29941, 0, 0, 0, 61696, 29060, 29061, 0, 0), # Death Knight Understudy (H)
+(16124, 55604, 0, 0, 0, 0, 0, 0, 27892), # Unrelenting Trainee
+(16125, 27825, 0, 0, 0, 0, 0, 0, 27928), # Unrelenting Death Knight
+(16126, 27831, 55606, 0, 0, 0, 0, 0, 27935), # Unrelenting Rider
+(16127, 27989, 0, 0, 0, 0, 0, 0, 0), # Spectral Trainee
+(16148, 56408, 0, 0, 0, 0, 0, 0, 0), # Spectral Death Knight
+(16150, 27994, 55648, 55606, 0, 0, 0, 0, 0), # Spectral Rider
+(16149, 27993, 0, 0, 0, 0, 0, 0, 0), # Spectral Horse
+(29985, 55645, 0, 0, 0, 0, 0, 0, 27892), # Unrelenting Trainee (H)
+(29986, 27825, 0, 0, 0, 0, 0, 0, 27928), # Unrelenting Death Knight (H)
+(29987, 55638, 55608, 0, 0, 0, 0, 0, 27935), # Unrelenting Rider (H)
+(30264, 56407, 0, 0, 0, 0, 0, 0, 0), # Spectral Trainee (H)
+(29990, 56408, 0, 0, 0, 0, 0, 0, 0), # Spectral Death Knight (H)
+(29988, 55646, 27995, 55608, 0, 0, 0, 0, 0), # Spectral Rider (H)
+(29989, 27993, 0, 0, 0, 0, 0, 0, 0) # Spectral Horse (H)
+ON DUPLICATE KEY UPDATE
+spell1 = VALUES(spell1),
+spell2 = VALUES(spell2),
+spell3 = VALUES(spell3),
+spell4 = VALUES(spell4),
+spell5 = VALUES(spell5),
+spell6 = VALUES(spell6),
+spell7 = VALUES(spell7),
+spell8 = VALUES(spell8); \ No newline at end of file
diff --git a/sql/world_scripts_full.sql b/sql/world_scripts_full.sql
index 4026eee9b2c..ce502d37bf9 100644
--- a/sql/world_scripts_full.sql
+++ b/sql/world_scripts_full.sql
@@ -637,15 +637,14 @@ UPDATE `instance_template` SET `script`='instance_naxxramas' WHERE `map`=533;
UPDATE `creature_template` SET `ScriptName`='boss_anubrekhan' WHERE `entry`=15956;
UPDATE `creature_template` SET `ScriptName`='boss_faerlina' WHERE `entry`=15953;
UPDATE `creature_template` SET `ScriptName`='boss_maexxna' WHERE `entry`=15952;
+UPDATE `creature_template` SET `ScriptName`='mob_webwrap' WHERE `entry`=16486;
UPDATE `creature_template` SET `ScriptName`='boss_noth' WHERE `entry`=15954;
UPDATE `creature_template` SET `ScriptName`='boss_heigan' WHERE `entry`=15936;
UPDATE `creature_template` SET `ScriptName`='boss_loatheb' WHERE `entry`=16011;
UPDATE `creature_template` SET `ScriptName`='boss_razuvious' WHERE `entry`=16061;
UPDATE `creature_template` SET `ScriptName`='boss_gothik' WHERE `entry`=16060;
UPDATE `creature_template` SET `ScriptName`='mob_gothik_minion' where `entry` IN (16124,16125,16126,16127,16148,16149,16150);
-UPDATE `creature_template` SET `ScriptName`='boss_thane_korthazz' WHERE `entry`=16064;
-UPDATE `creature_template` SET `ScriptName`='boss_sir_zeliek' WHERE `entry`=16063;
-UPDATE `creature_template` SET `ScriptName`='boss_lady_blaumeux' WHERE `entry`=16065;
+UPDATE `creature_template` SET `ScriptName`='boss_four_horsemen' WHERE `entry` IN (16063,16064,16065,30549);
UPDATE `creature_template` SET `ScriptName`='boss_patchwerk' WHERE `entry`=16028;
UPDATE `creature_template` SET `ScriptName`='boss_grobbulus' WHERE `entry`=15931;
UPDATE `creature_template` SET `ScriptName`='boss_gluth' WHERE `entry`=15932;
@@ -655,8 +654,6 @@ UPDATE `creature_template` SET `ScriptName`='boss_fugen' WHERE `entry`=15930;
UPDATE `creature_template` SET `ScriptName`='boss_sapphiron' WHERE `entry`=15989;
UPDATE `creature_template` SET `ScriptName`='boss_kelthuzad' WHERE `entry`=15990;
UPDATE `creature_template` SET `ScriptName`='' WHERE `entry`=16062;
-UPDATE `creature_template` SET `ScriptName`='boss_rivendare_naxx' WHERE `entry`=30549;
-UPDATE `creature_template` SET `ScriptName`='mob_webwrap' WHERE `entry`=16486;
/* NETHERSTORM */
UPDATE `gameobject_template` SET `ScriptName`='go_manaforge_control_console' WHERE `entry` IN (183770,183956,184311,184312);
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