diff options
30 files changed, 2576 insertions, 794 deletions
diff --git a/dep/g3dlite/G3D-v8.0.diff b/dep/g3dlite/G3D-v8.0_hotfix1.diff index a82d5378a8b..ec90cebbecf 100644 --- a/dep/g3dlite/G3D-v8.0.diff +++ b/dep/g3dlite/G3D-v8.0_hotfix1.diff @@ -1,6 +1,6 @@ -diff -urN g3d-beta4/include/G3D/debugAssert.h g3d-mangos/include/G3D/debugAssert.h ---- g3d-beta4/include/G3D/debugAssert.h 2010-02-07 23:39:20.000000000 +0100 -+++ g3d-mangos/include/G3D/debugAssert.h 2010-08-26 21:36:32.000000000 +0200 +diff -urN a/dep/g3dlite/include/G3D/debugAssert.h b/dep/g3dlite/include/G3D/debugAssert.h +--- a/dep/g3dlite/include/G3D/debugAssert.h 2010-02-07 23:39:20.000000000 +0100 ++++ b/dep/g3dlite/include/G3D/debugAssert.h 2010-08-26 21:36:32.000000000 +0200 @@ -39,10 +39,12 @@ #ifdef G3D_LINUX // Needed so we can define a global display @@ -30,9 +30,9 @@ diff -urN g3d-beta4/include/G3D/debugAssert.h g3d-mangos/include/G3D/debugAssert /** Pops up an assertion dialog or prints an assertion -diff -urN g3d-beta4/include/G3D/g3dmath.h g3d-mangos/include/G3D/g3dmath.h ---- g3d-beta4/include/G3D/g3dmath.h 2010-02-07 23:39:20.000000000 +0100 -+++ g3d-mangos/include/G3D/g3dmath.h 2010-08-26 21:36:32.000000000 +0200 +diff -urN a/dep/g3dlite/include/G3D/g3dmath.h b/dep/g3dlite/include/G3D/g3dmath.h +--- a/dep/g3dlite/include/G3D/g3dmath.h 2010-02-07 23:39:20.000000000 +0100 ++++ b/dep/g3dlite/include/G3D/g3dmath.h 2010-08-26 21:36:32.000000000 +0200 @@ -65,6 +65,8 @@ return ::rand() / double(RAND_MAX); } @@ -62,9 +62,9 @@ diff -urN g3d-beta4/include/G3D/g3dmath.h g3d-mangos/include/G3D/g3dmath.h #endif -diff -urN g3d-beta4/include/G3D/platform.h g3d-mangos/include/G3D/platform.h ---- g3d-beta4/include/G3D/platform.h 2010-02-07 23:39:20.000000000 +0100 -+++ g3d-mangos/include/G3D/platform.h 2010-08-26 21:36:32.000000000 +0200 +diff -urN a/dep/g3dlite/include/G3D/platform.h b/dep/g3dlite/include/G3D/platform.h +--- a/dep/g3dlite/include/G3D/platform.h 2010-02-07 23:39:20.000000000 +0100 ++++ b/dep/g3dlite/include/G3D/platform.h 2010-08-26 21:36:32.000000000 +0200 @@ -56,12 +57,15 @@ // pi as a constant, which creates a conflict with G3D #define __FP__ @@ -97,9 +97,9 @@ diff -urN g3d-beta4/include/G3D/platform.h g3d-mangos/include/G3D/platform.h /** @def G3D_CHECK_PRINTF_METHOD_ARGS() Enables printf parameter validation on gcc. */ -diff -urN g3d-beta4/include/G3D/System.h g3d-mangos/include/G3D/System.h ---- g3d-beta4/include/G3D/System.h 2010-02-07 23:39:20.000000000 +0100 -+++ g3d-mangos/include/G3D/System.h 2010-08-26 21:36:32.000000000 +0200 +diff -urN a/dep/g3dlite/include/G3D/System.h b/dep/g3dlite/include/G3D/System.h +--- a/dep/g3dlite/include/G3D/System.h 2010-02-07 23:39:20.000000000 +0100 ++++ b/dep/g3dlite/include/G3D/System.h 2010-08-26 21:36:32.000000000 +0200 @@ -375,10 +375,10 @@ // count now contains the cycle count for the intervening operation. </PRE> @@ -141,9 +141,9 @@ diff -urN g3d-beta4/include/G3D/System.h g3d-mangos/include/G3D/System.h } // namespace -diff -urN g3d-beta4/source/BinaryInput.cpp g3d-mangos/source/BinaryInput.cpp ---- g3d-beta4/source/BinaryInput.cpp 2010-02-07 23:39:20.000000000 +0100 -+++ g3d-mangos/source/BinaryInput.cpp 2010-08-15 11:37:26.000000000 +0200 +diff -urN a/dep/g3dlite/source/BinaryInput.cpp b/dep/g3dlite/source/BinaryInput.cpp +--- a/dep/g3dlite/source/BinaryInput.cpp 2010-02-07 23:39:20.000000000 +0100 ++++ b/dep/g3dlite/source/BinaryInput.cpp 2010-08-15 11:37:26.000000000 +0200 @@ -39,7 +39,9 @@ #include "G3D/Log.h" #include "G3D/FileSystem.h" @@ -171,9 +171,9 @@ diff -urN g3d-beta4/source/BinaryInput.cpp g3d-mangos/source/BinaryInput.cpp // Figure out how big the file is and verify that it exists. m_length = FileSystem::size(m_filename); -diff -urN g3d-beta4/source/debugAssert.cpp g3d-mangos/source/debugAssert.cpp ---- g3d-beta4/source/debugAssert.cpp 2010-02-07 23:39:20.000000000 +0100 -+++ g3d-mangos/source/debugAssert.cpp 2010-08-15 11:37:26.000000000 +0200 +diff -urN a/dep/g3dlite/source/debugAssert.cpp b/dep/g3dlite/source/debugAssert.cpp +--- a/dep/g3dlite/source/debugAssert.cpp 2010-02-07 23:39:20.000000000 +0100 ++++ b/dep/g3dlite/source/debugAssert.cpp 2010-08-15 11:37:26.000000000 +0200 @@ -37,9 +37,11 @@ AssertionHook _failureHook = _handleErrorCheck_; @@ -202,9 +202,9 @@ diff -urN g3d-beta4/source/debugAssert.cpp g3d-mangos/source/debugAssert.cpp #elif defined(G3D_OSX) // TODO: OS X #endif -diff -urN g3d-beta4/source/FileSystem.cpp g3d-mangos/source/FileSystem.cpp ---- g3d-beta4/source/FileSystem.cpp 2010-02-07 23:39:20.000000000 +0100 -+++ g3d-mangos/source/FileSystem.cpp 2010-08-15 11:37:26.000000000 +0200 +diff -urN a/dep/g3dlite/source/FileSystem.cpp b/dep/g3dlite/source/FileSystem.cpp +--- a/dep/g3dlite/source/FileSystem.cpp 2010-02-07 23:39:20.000000000 +0100 ++++ b/dep/g3dlite/source/FileSystem.cpp 2010-08-15 11:37:26.000000000 +0200 @@ -12,7 +12,9 @@ #include "G3D/fileutils.h" #include <sys/stat.h> @@ -252,9 +252,9 @@ diff -urN g3d-beta4/source/FileSystem.cpp g3d-mangos/source/FileSystem.cpp } return st.st_size; -diff -urN g3d-beta4/source/fileutils.cpp g3d-mangos/source/fileutils.cpp ---- g3d-beta4/source/fileutils.cpp 2010-02-07 23:39:20.000000000 +0100 -+++ g3d-mangos/source/fileutils.cpp 2010-08-15 11:37:26.000000000 +0200 +diff -urN a/dep/g3dlite/source/fileutils.cpp b/dep/g3dlite/source/fileutils.cpp +--- a/dep/g3dlite/source/fileutils.cpp 2010-02-07 23:39:20.000000000 +0100 ++++ b/dep/g3dlite/source/fileutils.cpp 2010-08-15 11:37:26.000000000 +0200 @@ -20,7 +20,9 @@ #include <sys/stat.h> @@ -368,9 +368,9 @@ diff -urN g3d-beta4/source/fileutils.cpp g3d-mangos/source/fileutils.cpp } -diff -urN g3d-beta4/source/prompt.cpp g3d-mangos/source/prompt.cpp ---- g3d-beta4/source/prompt.cpp 2010-02-07 23:39:20.000000000 +0100 -+++ g3d-mangos/source/prompt.cpp 2010-08-15 11:37:26.000000000 +0200 +diff -urN a/dep/g3dlite/source/prompt.cpp b/dep/g3dlite/source/prompt.cpp +--- a/dep/g3dlite/source/prompt.cpp 2010-02-07 23:39:20.000000000 +0100 ++++ b/dep/g3dlite/source/prompt.cpp 2010-08-15 11:37:26.000000000 +0200 @@ -21,6 +21,7 @@ # define _getch getchar #endif @@ -433,9 +433,9 @@ diff -urN g3d-beta4/source/prompt.cpp g3d-mangos/source/prompt.cpp return textPrompt(windowTitle, prompt, choice, numChoices); } -diff -urN g3d-beta4/source/RegistryUtil.cpp g3d-mangos/source/RegistryUtil.cpp ---- g3d-beta4/source/RegistryUtil.cpp 2010-02-07 23:39:20.000000000 +0100 -+++ g3d-mangos/source/RegistryUtil.cpp 2010-08-15 11:37:26.000000000 +0200 +diff -urN a/dep/g3dlite/source/RegistryUtil.cpp b/dep/g3dlite/source/RegistryUtil.cpp +--- a/dep/g3dlite/source/RegistryUtil.cpp 2010-02-07 23:39:20.000000000 +0100 ++++ b/dep/g3dlite/source/RegistryUtil.cpp 2010-08-15 11:37:26.000000000 +0200 @@ -257,7 +257,7 @@ @@ -445,9 +445,9 @@ diff -urN g3d-beta4/source/RegistryUtil.cpp g3d-mangos/source/RegistryUtil.cpp debugAssert(str); if (str) { -diff -urN g3d-beta4/source/System.cpp g3d-mangos/source/System.cpp ---- g3d-beta4/source/System.cpp 2010-02-07 23:39:20.000000000 +0100 -+++ g3d-mangos/source/System.cpp 2010-08-15 11:37:26.000000000 +0200 +diff -urN a/dep/g3dlite/source/System.cpp b/dep/g3dlite/source/System.cpp +--- a/dep/g3dlite/source/System.cpp 2010-02-07 23:39:20.000000000 +0100 ++++ b/dep/g3dlite/source/System.cpp 2010-08-15 11:37:26.000000000 +0200 @@ -80,8 +80,9 @@ #endif diff --git a/dep/g3dlite/G3D-v8.0_hotfix2.diff b/dep/g3dlite/G3D-v8.0_hotfix2.diff new file mode 100644 index 00000000000..bb66c4a6a29 --- /dev/null +++ b/dep/g3dlite/G3D-v8.0_hotfix2.diff @@ -0,0 +1,14 @@ +diff --git a/dep/g3dlite/source/g3dmath.cpp b/dep/g3dlite/source/g3dmath.cpp +index e846f8c..84e8345 100644 +--- a/dep/g3dlite/source/g3dmath.cpp ++++ b/dep/g3dlite/source/g3dmath.cpp +@@ -41,7 +41,7 @@ double inf() { + } + + bool isNaN(float x) { +- static const float n = nan(); ++ static const float n = fnan(); + return memcmp(&x, &n, sizeof(float)) == 0; + } + + diff --git a/dep/g3dlite/G3D-v8.0_hotfix3.diff b/dep/g3dlite/G3D-v8.0_hotfix3.diff new file mode 100644 index 00000000000..d556103c96d --- /dev/null +++ b/dep/g3dlite/G3D-v8.0_hotfix3.diff @@ -0,0 +1,12 @@ +diff --git a/dep/g3dlite/include/G3D/GMutex.h b/dep/g3dlite/include/G3D/GMutex.h +index 3469b81..9fe098d 100644 +--- a/dep/g3dlite/include/G3D/GMutex.h ++++ b/dep/g3dlite/include/G3D/GMutex.h +@@ -16,6 +16,7 @@ + #ifndef G3D_WIN32 + # include <pthread.h> + # include <signal.h> ++# include <unistd.h> + #endif + + diff --git a/dep/g3dlite/G3D-v8.0_extra.diff b/dep/g3dlite/G3D-v8.0_hotfix4.diff index 62c513435b9..cae92747a9a 100644 --- a/dep/g3dlite/G3D-v8.0_extra.diff +++ b/dep/g3dlite/G3D-v8.0_hotfix4.diff @@ -1,15 +1,3 @@ -diff --git a/dep/g3dlite/include/G3D/GMutex.h b/dep/g3dlite/include/G3D/GMutex.h -index 3469b81..9fe098d 100644 ---- a/dep/g3dlite/include/G3D/GMutex.h -+++ b/dep/g3dlite/include/G3D/GMutex.h -@@ -16,6 +16,7 @@ - #ifndef G3D_WIN32 - # include <pthread.h> - # include <signal.h> -+# include <unistd.h> - #endif - - diff --git a/dep/g3dlite/include/G3D/platform.h b/dep/g3dlite/include/G3D/platform.h index c8d2f0b..11093f4 100644 --- a/dep/g3dlite/include/G3D/platform.h diff --git a/dep/g3dlite/G3D-v8.0_hotfix5.diff b/dep/g3dlite/G3D-v8.0_hotfix5.diff new file mode 100644 index 00000000000..fd02b329c4a --- /dev/null +++ b/dep/g3dlite/G3D-v8.0_hotfix5.diff @@ -0,0 +1,73 @@ +diff --git a/dep/g3dlite/include/G3D/System.h b/dep/g3dlite/include/G3D/System.h +index 1c0cf99..f160774 100644 +--- a/dep/g3dlite/include/G3D/System.h ++++ b/dep/g3dlite/include/G3D/System.h +@@ -19,6 +19,9 @@ + #include "G3D/G3DGameUnits.h" + #include "G3D/BinaryFormat.h" + #include <string> ++#ifdef G3D_LINUX ++# include <sys/socket.h> ++#endif + + #ifdef G3D_OSX + # include <CoreServices/CoreServices.h> +diff --git a/dep/g3dlite/include/G3D/platform.h b/dep/g3dlite/include/G3D/platform.h +index 11093f4..614c0ed 100644 +--- a/dep/g3dlite/include/G3D/platform.h ++++ b/dep/g3dlite/include/G3D/platform.h +@@ -56,6 +56,8 @@ + #define G3D_LINUX + #elif defined(__linux__) + #define G3D_LINUX ++#elif defined(__CYGWIN__) ++ #define G3D_LINUX + #elif defined(__APPLE__) + #define G3D_LINUX + +diff --git a/dep/g3dlite/source/BinaryOutput.cpp b/dep/g3dlite/source/BinaryOutput.cpp +index 054211d..81fa982 100644 +--- a/dep/g3dlite/source/BinaryOutput.cpp ++++ b/dep/g3dlite/source/BinaryOutput.cpp +@@ -22,6 +22,10 @@ + # include <errno.h> + #endif + ++#ifdef __CYGWIN__ ++# include <errno.h> ++#endif ++ + // Largest memory buffer that the system will use for writing to + // disk. After this (or if the system runs out of memory) + // chunks of the file will be dumped to disk. +diff --git a/dep/g3dlite/source/FileSystem.cpp b/dep/g3dlite/source/FileSystem.cpp +index 2cf890a..76a3611 100644 +--- a/dep/g3dlite/source/FileSystem.cpp ++++ b/dep/g3dlite/source/FileSystem.cpp +@@ -35,6 +35,10 @@ + # define _stat stat + #endif + ++#ifdef __CYGWIN__ ++#define stat64 stat ++#endif ++ + namespace G3D { + + static FileSystem* common = NULL; +diff --git a/dep/g3dlite/source/System.cpp b/dep/g3dlite/source/System.cpp +index 809f05c..f6b0e03 100644 +--- a/dep/g3dlite/source/System.cpp ++++ b/dep/g3dlite/source/System.cpp +@@ -888,7 +888,11 @@ void System::initTime() { + + if (localTimeVals) { + // tm_gmtoff is already corrected for daylight savings. ++ #ifdef __CYGWIN__ ++ local = local + _timezone; ++ #else + local = local + localTimeVals->tm_gmtoff; ++ #endif + } + + m_realWorldGetTickTime0 = local; diff --git a/dep/g3dlite/Readme.txt b/dep/g3dlite/Readme.txt index b91c20dce38..055574ee654 100644 --- a/dep/g3dlite/Readme.txt +++ b/dep/g3dlite/Readme.txt @@ -1,3 +1,8 @@ - Due to issues with G3D (normally requiring X11 and the ZIP-library), the -sourcetree version contains a modified version. The applied patch is -commited to the repository for future reference. + Due to issues with G3D normally requiring X11 and the ZIP-library, the library version in this sourcetree contains a modified version. +The applied patches are added as .diff-files to the repository for future reference (knowing what was changed is quite handy). + +G3D-v8.0_hotfix1.diff - 2010-08-27 - remove dependency on zip/z11 libraries, add support for 64-bit arch +G3D-v8.0_hotfix2.diff - 2012-01-14 - fix typo in isNaN(float x) +G3D-v8.0_hotfix3.diff - 2012-08-26 - fix compilation on Fedora Linux +G3D-v8.0_hotfix4.diff - 2012-11-09 - fix compilation on OSX +G3D-v8.0_hotfix5.diff - 2013-02-27 - fix compilation in cygwin environments diff --git a/dep/g3dlite/include/G3D/System.h b/dep/g3dlite/include/G3D/System.h index 1c0cf99410c..45aef1549b6 100644 --- a/dep/g3dlite/include/G3D/System.h +++ b/dep/g3dlite/include/G3D/System.h @@ -19,6 +19,9 @@ #include "G3D/G3DGameUnits.h" #include "G3D/BinaryFormat.h" #include <string> +#ifdef G3D_LINUX +# include <sys/socket.h> +#endif #ifdef G3D_OSX # include <CoreServices/CoreServices.h> diff --git a/dep/g3dlite/include/G3D/platform.h b/dep/g3dlite/include/G3D/platform.h index 11093f4a6ce..614c0ed7cad 100644 --- a/dep/g3dlite/include/G3D/platform.h +++ b/dep/g3dlite/include/G3D/platform.h @@ -56,6 +56,8 @@ #define G3D_LINUX #elif defined(__linux__) #define G3D_LINUX +#elif defined(__CYGWIN__) + #define G3D_LINUX #elif defined(__APPLE__) #define G3D_LINUX diff --git a/dep/g3dlite/source/BinaryOutput.cpp b/dep/g3dlite/source/BinaryOutput.cpp index 054211d906c..81fa9822206 100644 --- a/dep/g3dlite/source/BinaryOutput.cpp +++ b/dep/g3dlite/source/BinaryOutput.cpp @@ -22,6 +22,10 @@ # include <errno.h> #endif +#ifdef __CYGWIN__ +# include <errno.h> +#endif + // Largest memory buffer that the system will use for writing to // disk. After this (or if the system runs out of memory) // chunks of the file will be dumped to disk. diff --git a/dep/g3dlite/source/FileSystem.cpp b/dep/g3dlite/source/FileSystem.cpp index 2cf890a1cd5..76a361162c9 100644 --- a/dep/g3dlite/source/FileSystem.cpp +++ b/dep/g3dlite/source/FileSystem.cpp @@ -35,6 +35,10 @@ # define _stat stat #endif +#ifdef __CYGWIN__ +#define stat64 stat +#endif + namespace G3D { static FileSystem* common = NULL; diff --git a/dep/g3dlite/source/System.cpp b/dep/g3dlite/source/System.cpp index 809f05c0ab4..f6b0e038f27 100644 --- a/dep/g3dlite/source/System.cpp +++ b/dep/g3dlite/source/System.cpp @@ -888,7 +888,11 @@ void System::initTime() { if (localTimeVals) { // tm_gmtoff is already corrected for daylight savings. + #ifdef __CYGWIN__ + local = local + _timezone; + #else local = local + localTimeVals->tm_gmtoff; + #endif } m_realWorldGetTickTime0 = local; diff --git a/sql/updates/world/2013_02_28_00_world_eye_of_eternity.sql b/sql/updates/world/2013_02_28_00_world_eye_of_eternity.sql new file mode 100644 index 00000000000..9aef8f358d2 --- /dev/null +++ b/sql/updates/world/2013_02_28_00_world_eye_of_eternity.sql @@ -0,0 +1,200 @@ +-- Add spell script names +DELETE FROM `spell_script_names` WHERE `spell_id` IN (56046,56047,61693,61694,57459,56438,61210,56397,58842,59084,59099,56070,56072,60936,60939,61028,61023); +INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES +(56046, 'spell_malygos_portal_beam'), +(56047, 'spell_malygos_random_portal'), +(61693, 'spell_malygos_arcane_storm'), -- Phase I /10/ +(61694, 'spell_malygos_arcane_storm'), -- Phase I /25/ +(57459, 'spell_malygos_arcane_storm'), -- Phase III +(56438, 'spell_arcane_overload'), +(61210, 'spell_nexus_lord_align_disk_aggro'), +(56397, 'spell_scion_of_eternity_arcane_barrage'), +(58842, 'spell_malygos_destroy_platform_channel'), +(59084, 'spell_alexstrasza_bunny_destroy_platform_boom_visual'), +(59099, 'spell_alexstrasza_bunny_destroy_platform_event'), +(56070, 'spell_wyrmrest_skytalon_summon_red_dragon_buddy'), +(56072, 'spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger'), +(60936, 'spell_malygos_surge_of_power_25'), +(60939, 'spell_malygos_surge_of_power_warning_selector_25'), +(61028, 'spell_alexstrasza_gift_beam'), +(61023, 'spell_alexstrasza_gift_beam_visual'); + +-- Add spell difficulties +DELETE FROM `spelldifficulty_dbc` WHERE `id` IN (61693,56272,57058); +INSERT INTO `spelldifficulty_dbc` (`id`,`spellid0`,`spellid1`,`spellid2`,`spellid3`) VALUES +(61693,61693,61694,0,0), -- Arcane Storm - Phase I +(56272,56272,60072,0,0), -- Arcane Breath +(57058,57058,60073,0,0); -- Arcane Shock (Nexus Lord) + +-- Insert missing creature template addon +DELETE FROM `creature_template_addon` WHERE `entry` IN (28859,30234,30248,32295,30592,31748,31749); +INSERT INTO `creature_template_addon` (`entry`,`path_id`,`mount`,`bytes1`,`bytes2`,`emote`,`auras`) VALUES +(28859,0,0,0x1000000|0x2000000,0x1,0, ''), -- Malygos +(30234,0,0,0x1000000|0x2000000,0x1,0, '43775'), -- Hover Disk (Nexus Lord), add aura "Flight" +(30248,0,0,0x1000000|0x2000000,0x1,0, '43775'), -- Hover Disk (Scion of Eternity), add aura "Flight" +(31748,0,0,0x1000000|0x2000000,0x1,0, '43775'), -- Hover Disk Difficulty (Nexus Lord), add aura "Flight" +(31749,0,0,0x1000000|0x2000000,0x1,0, '43775'), -- Hover Disk Difficulty (Scion of Eternity), add aura "Flight" +(32295,0,0,0x1000000|0x2000000,0x1,0, ''), -- Alexstrasza +(30592,0,0,0x1000000|0x2000000,0x1,0, '57428'); -- Static Field bunny + +-- Add, restructure and update missing texts and sounds +DELETE FROM `creature_text` WHERE `entry` IN (28859,32295); +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`comment`) VALUES +(28859,0,0, 'Lesser beings, intruding here! A shame that your excess courage does not compensate for your stupidity!',14,0,100,0,10000,14512,'Malygos - Intro'), +(28859,0,1, 'None but the blue dragonflight are welcome here. Perhaps this is the work of Alexstrasza? Well, then, she has sent you to your deaths!',14,0,100,0,11000,14513,'Malygos - Intro'), +(28859,0,2, 'What could you hope to accomplish? To storm brazenly into my domain... to employ magic... against ME?',14,0,100,0,13000,14514,'Malygos - Intro'), +(28859,0,3, 'I am without limits here. The rules of your cherished reality do not apply. In this realm, I am in control!',14,0,100,0,10000,14515,'Malygos - Intro'), +(28859,0,4, 'I give you one chance. Pledge fealty to me, and perhaps I will not slaughter you for your insolence.',14,0,100,0,7000,14516,'Malygos - Intro'), +(28859,1,0, 'My patience has reached its limit, I will be rid of you!',14,0,100,0,4000,14517,'Malygos - Start phase 1'), +(28859,2,0, 'You will not succeed while I draw breath!',14,0,100,0,3000,14518,'Malygos - Begin to cast Deep Breath'), +(28859,3,0, 'Your stupidity has finally caught up to you!',14,0,100,0,3250,14519,'Malygos - Killed Player (Phase 1)'), +(28859,3,1, 'More artifacts to confiscate...',14,0,100,0,2800,14520,'Malygos - Killed Player (Phase 1)'), +(28859,3,2, 'How very naive.',14,0,100,0,4800,14521,'Malygos - Killed Player (Phase 1)'), +(28859,4,0, 'I had hoped to end your lives quickly, but you have proven more... resilient than I anticipated. Nonetheless, your efforts are in vain. It is you reckless, careless mortals who are to blame for this war. I do what I must, and if it means your extinction.... then SO BE IT!!',14,0,100,0,22900,14522,'Malygos - End Phase One'), +(28859,5,0, 'Few have experienced the pain I will now inflict upon you!',14,0,100,0,5500,14523,'Malygos - Start phase 2'), -- Unused by Blizzard for some reason +(28859,6,0, 'I will teach you IGNORANT children just how little you know of magic...',14,0,100,0,7000,14524,'Malygos - Anti-Magic Shell'), +(28859,7,0, 'Watch helplessly as your hopes are swept away...',14,0,100,0,4000,14525,'Malygos - Magic Blast'), +(28859,8,0, 'Your energy will be put to good use!',14,0,100,0,2000,14526,'Malygos - Killed Player (Phase 2)'), +(28859,8,1, 'I am the spell-weaver! My power is infinite!',14,0,100,0,5200,14527,'Malygos - Killed Player (Phase 2)'), +(28859,8,2, 'Your spirit will linger here forever!',14,0,100,0,3800,14528,'Malygos - Killed Player (Phase 2)'), +(28859,9,0, 'ENOUGH! If you intend to reclaim Azeroth''s magic, then you shall have it...',14,0,100,0,7000,14529,'Malygos - End Phase 2'), +(28859,10,0, 'Now your benefactors make their appearance... But they are too late. The powers contained here are sufficient to destroy the world ten times over! What do you think they will do to you?',14,0,100,0,13000,14530,'Intro Phase 3'), +(28859,11,0, 'SUBMIT!',14,0,100,0,1000,14531,'Malygos - Start phase 3'), -- Unused by Blizzard for some reason +(28859,12,0, 'Malygos takes a deep breath.',41,0,100,0,10000,0,'Malygos - Surge of Power warning (Phase 2)'), +(28859,13,0, 'The powers at work here exceed anything you could possibly imagine!',14,0,100,0,5000,14532,'Malygos - Surge of Power'), +(28859,14,0, 'I AM UNSTOPPABLE!',14,0,100,0,2000,14533,'Malygos - Buffed by a spark'), +(28859,15,0, 'Alexstrasza! Another of your brood falls!',14,0,100,0,3600,14534,'Malygos - Killed Player (Phase 3)'), +(28859,15,1, 'Little more then gnats!',14,0,100,0,2650,14535,'Malygos - Killed Player (Phase 3)'), +(28859,15,2, 'Your red allies will share your fate...',14,0,100,0,3000,14536,'Malygos - Killed Player (Phase 3)'), +(28859,16,0, 'Still standing? Not for long...',14,0,100,0,3600,14537,'Malygos - Spell Casting 1(Phase 3)'), +(28859,16,1, 'Your cause is lost!',14,0,100,0,2000,14538,'Malygos - Spell Casting 2 (Phase 3)'), +(28859,16,2, 'Your fragile mind will be shattered!',14,0,100,0,4000,14539,'Malygos - Spell Casting 3 (Phase 3)'), +(28859,17,0, 'Unthinkable! The mortals will destroy... everything! My sister, what have you...',14,0,100,0,8500,14540,'Malygos - Death'), +(28859,18,0, '%s fixes his eyes on you!',42,0,100,0,3000,0,'Malygos - Surge of Power warning (Phase 3)'), +(28859,19,0, '%s goes into a berserker rage!',41,0,100,0,10000,0,'Malygos - Hit berserk timer (Any phase)'), +(32295,0,0, 'I did what I had to, brother. You gave me no alternative.',14,0,100,0,4000,14406,'Alexstrasza - Yell text 1'), +(32295,1,0, 'And so ends the Nexus War.',14,0,100,0,4000,14407,'Alexstrasza - Yell text 2'), +(32295,2,0, 'This resolution pains me deeply, but the destruction, the monumental loss of life had to end. Regardless of Malygos''s recent transgressions, I will mourn his loss. He was once a guardian, a protector. This day, one of the world''s mightiest has fallen.',14,0,100,0,24000,14408,'Alexstrasza - Yell text 3'), +(32295,3,0, 'The red dragonflight will take on the burden of mending the devastation wrought on Azeroth. Return home to your people and rest. Tomorrow will bring you new challenges, and you must be ready to face them. Life... goes on.',14,0,100,0,22000,14409,'Alexstrasza - Yell text 4'); +-- Update wrong sound and add duration for Power Sparks warning +UPDATE `creature_text` SET `duration`=10000,`sound`=0 WHERE `entry`=30084 AND `groupid`=0 AND`id`=0; + +-- Add conditions +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry` IN (56047,58846,61028,56429,56505,59099,61714,61715,57432,57429,61210,56548,56431,56438); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorType`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES +(13,1,56047,0,0,31,0,3,30118,0,0,0,0,'', 'Random Portal can implicitly hit only Portal (Malygos)'), +(13,1,56047,0,0,29,0,28859,30,0,1,0,0,'', 'Random Portal can implicitly hit only target that is not in 30 yards near Malygos'), +(13,1,58846,0,0,32,0,0x0010,0,0,0,0,0,'', 'Summon Red Dragon Buddy force cast can implicitly hit only players'), +(13,1,61028,0,0,31,0,3,32448,0,0,0,0,'', 'Alexstrasza''s Gift Beam can hit only Alexstrasza''s Gift'), +(13,1,56429,0,0,31,0,3,31253,0,0,0,0,'', 'Summon Arcane Bomb can hit only Alexstrasza the Life-Binder (bunny)'), +(13,1,56505,0,0,31,0,3,30334,0,0,0,0,'', 'Surge of Power (phase II) can hit only Surge of Power'), +(13,1,56548,0,0,31,0,3,30234,0,1,0,0,'', 'Surge of Power triggered damage spell (phase II) can''t hit melee Hover Disk'), +(13,3,56431,0,0,31,0,3,30234,0,1,0,0,'', 'Arcane Overload damage and knockback spell can''t hit melee Hover Disk'), +(13,1,56438,0,0,1,0,1,56438,0,1,0,0,'', 'Arcane Overload damage reduce aura can''t apply to target that already is affected by such'), +(13,6,59099,0,0,32,0,0x0010,0,0,0,0,0,'', 'Destroy Platform Event effect 1 and 2 can hit only players'), +(13,7,61714,0,0,31,0,3,30245,0,0,0,0,'', 'Berserk (spell 2) can hit Nexus Lord'), +(13,7,61714,0,1,31,0,3,30249,0,0,0,0,'', 'Berserk (spell 2) can hit Scion of Eternity'), +(13,7,61715,0,0,31,0,3,30592,0,0,0,0,'', 'Berserk (spell 3) can hit Static Field bunny'), +(13,1,57432,0,0,31,0,3,30161,0,0,0,0,'', 'Arcane Pulse can hit only drakes'), +(13,3,57429,0,0,31,0,3,30161,0,0,0,0,'', 'Static Field can hit only drakes'), +(13,1,61210,0,0,33,1,0,4,0,0,0,0,'', 'Align Disk Aggro can only hit the vehicle of the passenger caster'); + +-- Add missing equipment +DELETE FROM `creature_equip_template` WHERE `entry` IN (30245,31750,30249,31751); +INSERT INTO `creature_equip_template` (`entry`,`id`,`itemEntry1`,`itemEntry2`,`itemEntry3`) VALUES +(30245,1,30714,0,0), -- Nexus Lord +(31750,1,30714,0,0), -- Nexus Lord (Difficulty) +(30249,1,29107,0,0), -- Scion of Eternity +(31751,1,29107,0,0); -- Scion of Eternity (Difficulty) + +-- Update accessories of hover disks to die with the vehicle and have lower despawn time. They should fall from hover disks, +-- and despawn after 5 sec, but for some reason they keep staying standing while dead. This needs to be fixed coreside. +UPDATE `vehicle_template_accessory` SET `minion`=1,`summontype`=6,`summontimer`=1000 WHERE `entry`=30234 AND `seat_id`=0; +UPDATE `vehicle_template_accessory` SET `minion`=1,`summontype`=6,`summontimer`=1000 WHERE `entry`=30248 AND `seat_id`=0; + +-- Add flag GO not selectable for both and extra condition for Heart of Magic +UPDATE `gameobject_template` SET `flags`=16 WHERE `entry`=193967; -- Alexstrasza Gift +UPDATE `gameobject_template` SET `flags`=20 WHERE `entry`=194159; -- Heart of Magic + +-- Add some gameobject data update +UPDATE `gameobject` SET `animprogress`=255,`spawntimesecs`=300 WHERE `guid` IN (151791,193960); -- that spawn time has no influence, but having different values doesn't look correct + +-- Delete static GO spawns of Alexstrasza's Gift Boxes, they are dynamic (10/25) +DELETE FROM `gameobject` WHERE `guid` IN (151792,151793); + +-- Add map difficulty checks for achievement "Denyin the Scion" +DELETE FROM `achievement_criteria_data` WHERE `criteria_id` IN (7573,7574) AND `type`=12; +INSERT INTO `achievement_criteria_data` (`criteria_id`,`type`,`value1`) VALUES +(7573,12,0), -- 10 mode +(7574,12,1); -- 25 mode + +-- Delete Nexus Lords SAI script, because of incapacity to handle the combat spell mechanic of Arcane Shock correctly +-- Delete Scions of Eternity SAI script, because of incapacity to handle non reactive AI when being attacked in a way it won't bug other encounter mechanics. +DELETE FROM `smart_scripts` WHERE `entryorguid` IN (30245,30249) AND `source_type`=0; + +-- Add SAI support for Alexstrasza since is only short timed event after boss mechanic ends +SET @NPC_ALEXSTRASZA := 32295; +SET @ACTIONLIST := @NPC_ALEXSTRASZA * 100; +SET @SPELL_GIFT_BEAM := 61028; + +UPDATE `creature_template` SET `AIName`='SmartAI',`ScriptName`='' WHERE `entry`=@NPC_ALEXSTRASZA; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@NPC_ALEXSTRASZA AND `source_type`=0; +DELETE FROM `smart_scripts` WHERE `entryorguid`=@ACTIONLIST AND `source_type`=9; +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_phase_mask`,`event_chance`,`event_flags`,`event_param1`,`event_param2`,`event_param3`,`event_param4`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`action_param4`,`action_param5`,`action_param6`,`target_type`,`target_param1`,`target_param2`,`target_param3`,`target_x`,`target_y`,`target_z`,`target_o`,`comment`) VALUES +(@NPC_ALEXSTRASZA,0,0,0,54,0,100,0,0,0,0,0,69,1,0,0,0,0,0,8,0,0,0,788.07,1276.09,246.9,0,'Alexstrasza - On just summoned - Move to pos'), +(@NPC_ALEXSTRASZA,0,1,0,34,0,100,0,8,1,0,0,80,@ACTIONLIST,2,0,0,0,0,1,0,0,0,0,0,0,0,'Alexstrasza - On point 1 reached - Start actionlist'), +(@ACTIONLIST,9,0,0,0,0,100,0,0,0,0,0,11,@SPELL_GIFT_BEAM,0,0,0,0,0,1,0,0,0,0,0,0,0,'Alexstrasza - Action 0 - Cast Gift Beam'), +(@ACTIONLIST,9,1,0,0,0,100,0,4000,4000,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,'Alexstrasza - Action 1 - Yell 0'), +(@ACTIONLIST,9,2,0,0,0,100,0,6000,6000,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,'Alexstrasza - Action 2 - Yell 1'), +(@ACTIONLIST,9,3,0,0,0,100,0,5000,5000,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,'Alexstrasza - Action 3 - Yell 2'), +(@ACTIONLIST,9,4,0,0,0,100,0,24000,24000,0,0,1,3,0,0,0,0,0,1,0,0,0,0,0,0,0,'Alexstrasza - Action 4 - Yell 3'); + +-- Add areatrigger script for the improvised platform that is killing/rooting falling players +DELETE FROM `areatrigger_scripts` WHERE `entry`=5342; +INSERT INTO `areatrigger_scripts` (`entry`,`ScriptName`) VALUES +(5342, 'at_eye_of_eternity_improvised_floor'); + +-- /////////////// Various misc in creature, creature template and creature addon /////////////// +-- Update some guids spawn positions +UPDATE `creature` SET `position_x`=754.362,`position_y`=1301.61,`position_z`=266.171,`orientation`=4.24115 WHERE `guid`=132302; -- Alexstrasza the Life-Binder (Bunny) +UPDATE `creature` SET `position_x`=747.61,`position_y`=1393.43,`position_z`=295.9722,`orientation`=3.03832 WHERE `guid`=132313; -- Malygos + +-- Update some creature guids to be have static MovementType and spawn dist to 0 accordingly +UPDATE `creature` SET `spawndist`=0,`MovementType`=0 WHERE `guid` IN +(132313, -- Malygos +132314, -- Alexstrasza''s Gift Bunny +132302); -- Alexstrasza the Life-Binder (Bunny) + +-- Update template to InhabitType "Air" for various creatures +UPDATE `creature_template` SET `InhabitType`=4 WHERE `entry` IN (28859,31734,30245,31750,30249,31751,32295,32448); + +-- Clear scripts names for Alexstrasza the Life-Binder (Bunny) +UPDATE `creature_template` SET `AIName`='',`ScriptName`='' WHERE `entry`=31253; + +-- Update Portal (Malygos) initial flags before the encounter starts +UPDATE `creature_template` SET `unit_flags`=`unit_flags`|0x00000100|0x02000000,`flags_extra`=128 WHERE `entry`=30118; -- Immunity to Players + Not selectable + +-- Update flags extra to trigger & civilian for Static Field and add script name +UPDATE `creature_template` SET `AIName`='',`ScriptName`='npc_static_field',`flags_extra`=130 WHERE `entry`=30592; + +-- Update flags extra to extra trigger & extra civilian for Alexstrasza Bunny +UPDATE `creature_template` SET `flags_extra`=130, `ScriptName`='' WHERE `entry`=31253; + +-- Remove uneeded creature_addon data +DELETE FROM `creature_addon` WHERE `guid` IN +(30592, -- The spawn for Static Field is dynamique, so not fixed guid. +132313); -- Malygos is boss so is unique and needs only the template addon. + +-- Update templates for both types of hover disks +UPDATE `creature_template` SET `faction_A`=14,`faction_H`=14,`VehicleId`=223,`InhabitType`=4 WHERE `entry` IN (30248,31749); -- Hover disk for Scions +UPDATE `creature_template` SET `ScriptName`='npc_caster_hover_disk' WHERE `entry`=30248; +UPDATE `creature_template` SET `faction_A`=14,`faction_H`=14,`InhabitType`=4 WHERE `entry` IN (30234,31748); -- Hover disk for Nexus Lords +UPDATE `creature_template` SET `ScriptName`='npc_melee_hover_disk' WHERE `entry`=30234; +UPDATE `creature_template` SET `AIName`='',`ScriptName`='npc_nexus_lord' WHERE `entry`=30245; -- Nexus Lord +UPDATE `creature_template` SET `AIName`='',`ScriptName`='npc_scion_of_eternity' WHERE `entry`=30249; -- Scion of Eternity + +-- Fix model display for Vortex Triggers (in creature handling). +-- Remove extra trigger flag because for some reason it was bugging model displaying as always visible, +-- since it has the invisible one for triggers first and other as second, this is the only nonhacky way (don't try to change it unless core side != c++ hack in instance script) +UPDATE `creature_template` SET `flags_extra`=flags_extra &~ 0x00000080 WHERE `entry`=30090; +UPDATE `creature` SET `modelid`=11686 WHERE `guid` BETWEEN 132304 AND 132308; diff --git a/sql/updates/world/2013_02_28_00_world_playercreateinfo_spell.sql b/sql/updates/world/2013_02_28_00_world_playercreateinfo_spell.sql new file mode 100644 index 00000000000..9f0ce0d8533 --- /dev/null +++ b/sql/updates/world/2013_02_28_00_world_playercreateinfo_spell.sql @@ -0,0 +1,11 @@ +-- Add missing generic spell for opening chests for most of Blood Elf's classes +-- (was preventing them to loot Eye of Eternity Alexstrasza's Gift Box, Heart of Magic and maybe more.) +DELETE FROM `playercreateinfo_spell` WHERE `race`=10 AND `Spell`=61437; +INSERT INTO `playercreateinfo_spell` (`race`,`class`,`Spell`,`Note`) VALUES +(10,2,61437, 'Opening'), +(10,3,61437, 'Opening'), +(10,4,61437, 'Opening'), +(10,5,61437, 'Opening'), +(10,6,61437, 'Opening'), +(10,8,61437, 'Opening'), +(10,9,61437, 'Opening'); diff --git a/src/server/collision/BoundingIntervalHierarchy.cpp b/src/server/collision/BoundingIntervalHierarchy.cpp index bca738d1ff6..4c1f449da25 100644 --- a/src/server/collision/BoundingIntervalHierarchy.cpp +++ b/src/server/collision/BoundingIntervalHierarchy.cpp @@ -20,6 +20,8 @@ #if defined __APPLE__ #define isnan std::isnan +#elif defined __CYGWIN__ + #define isnan std::isnan #elif defined _MSC_VER #define isnan _isnan #endif diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.h b/src/server/game/Battlefield/Zones/BattlefieldWG.h index 09ad5b284fd..047455ce8fb 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.h +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.h @@ -102,21 +102,21 @@ enum WintergraspData enum WintergraspAchievements { ACHIEVEMENTS_WIN_WG = 1717, - ACHIEVEMENTS_WIN_WG_100 = 1718, // todo - ACHIEVEMENTS_WG_GNOMESLAUGHTER = 1723, // todo + ACHIEVEMENTS_WIN_WG_100 = 1718, /// @todo: Has to be implemented + ACHIEVEMENTS_WG_GNOMESLAUGHTER = 1723, /// @todo: Has to be implemented ACHIEVEMENTS_WG_TOWER_DESTROY = 1727, - ACHIEVEMENTS_DESTRUCTION_DERBY_A = 1737, // todo - ACHIEVEMENTS_WG_TOWER_CANNON_KILL = 1751, // todo - ACHIEVEMENTS_WG_MASTER_A = 1752, // todo + ACHIEVEMENTS_DESTRUCTION_DERBY_A = 1737, /// @todo: Has to be implemented + ACHIEVEMENTS_WG_TOWER_CANNON_KILL = 1751, /// @todo: Has to be implemented + ACHIEVEMENTS_WG_MASTER_A = 1752, /// @todo: Has to be implemented ACHIEVEMENTS_WIN_WG_TIMER_10 = 1755, - ACHIEVEMENTS_STONE_KEEPER_50 = 2085, // todo - ACHIEVEMENTS_STONE_KEEPER_100 = 2086, // todo - ACHIEVEMENTS_STONE_KEEPER_250 = 2087, // todo - ACHIEVEMENTS_STONE_KEEPER_500 = 2088, // todo - ACHIEVEMENTS_STONE_KEEPER_1000 = 2089, // todo - ACHIEVEMENTS_WG_RANGER = 2199, // todo - ACHIEVEMENTS_DESTRUCTION_DERBY_H = 2476, // todo - ACHIEVEMENTS_WG_MASTER_H = 2776 // todo + ACHIEVEMENTS_STONE_KEEPER_50 = 2085, /// @todo: Has to be implemented + ACHIEVEMENTS_STONE_KEEPER_100 = 2086, /// @todo: Has to be implemented + ACHIEVEMENTS_STONE_KEEPER_250 = 2087, /// @todo: Has to be implemented + ACHIEVEMENTS_STONE_KEEPER_500 = 2088, /// @todo: Has to be implemented + ACHIEVEMENTS_STONE_KEEPER_1000 = 2089, /// @todo: Has to be implemented + ACHIEVEMENTS_WG_RANGER = 2199, /// @todo: Has to be implemented + ACHIEVEMENTS_DESTRUCTION_DERBY_H = 2476, /// @todo: Has to be implemented + ACHIEVEMENTS_WG_MASTER_H = 2776 /// @todo: Has to be implemented }; enum WintergraspWorldStates @@ -499,7 +499,7 @@ enum WintergraspTeamControl BATTLEFIELD_WG_TEAM_NEUTRAL }; -// TODO: Handle this with creature_text ? +/// @todo: Can this be handled with creature_text or SmartAI ? enum WintergraspText { BATTLEFIELD_WG_TEXT_WORKSHOP_NAME_NE = 12055, @@ -562,7 +562,7 @@ struct WintergraspObjectPositionData }; // ***************************************************** -// ************ Destructible (Wall, Tower..) ************ +// ************ Destructible (Wall, Tower..) *********** // ***************************************************** struct WintergraspBuildingSpawnData @@ -755,7 +755,7 @@ const WintergraspTeleporterData WGPortalDefenderData[WG_MAX_TELEPORTER] = }; // ********************************************************* -// **********Tower Element(GameObject, Creature)************* +// **********Tower Element(GameObject, Creature)************ // ********************************************************* struct WintergraspTowerData @@ -764,7 +764,7 @@ struct WintergraspTowerData uint8 nbObject; // Number of gameobjects spawned on this point WintergraspObjectPositionData GameObject[6]; // Gameobject position and entry (Horde/Alliance) - // Creature : Turrets and Guard, TODO: check if killed on tower destruction? tower damage? + // Creature: Turrets and Guard /// @todo: Killed on Tower destruction ? Tower damage ? Requires confirming uint8 nbCreatureBottom; WintergraspObjectPositionData CreatureBottom[9]; uint8 nbCreatureTop; @@ -1055,7 +1055,7 @@ const WGWorkshopData WorkshopsData[WG_MAX_WORKSHOP] = }; // ******************************************************************** -// * Structs using for Building, Graveyard, Workshop * +// * Structs using for Building, Graveyard, Workshop * // ******************************************************************** // Structure for different buildings that can be destroyed during battle struct BfWGGameObjectBuilding diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h index 7cd4d571cad..7a0af0b06d7 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h @@ -53,7 +53,7 @@ #define AV_EVENT_START_BATTLE 9166 // Achievement: The Alterac Blitz enum BG_AV_Sounds -{ //TODO: get out if there comes a sound when neutral team captures mine +{ /// @todo: get out if there comes a sound when neutral team captures mine /* 8212: @@ -86,7 +86,7 @@ horde: horde wins */ - AV_SOUND_NEAR_VICTORY = 8456, //not confirmed yet + AV_SOUND_NEAR_VICTORY = 8456, /// @todo: Not confirmed yet AV_SOUND_ALLIANCE_ASSAULTS = 8212, //tower, grave + enemy boss if someone tries to attack him AV_SOUND_HORDE_ASSAULTS = 8174, @@ -104,7 +104,7 @@ enum BG_AV_OTHER_VALUES AV_NORTH_MINE = 0, AV_SOUTH_MINE = 1, AV_MINE_TICK_TIMER = 45000, - AV_MINE_RECLAIM_TIMER = 1200000, //TODO: get the right value.. this is currently 20 minutes + AV_MINE_RECLAIM_TIMER = 1200000, /// @todo: get the right value.. this is currently 20 minutes AV_NEUTRAL_TEAM = 0 //this is the neutral owner of snowfall }; enum BG_AV_ObjectIds @@ -547,7 +547,7 @@ enum BG_AV_CreaturePlace AV_CPLACE_SPIRIT_FROST_HUT = 6, AV_CPLACE_SPIRIT_MAIN_ALLIANCE = 7, AV_CPLACE_SPIRIT_MAIN_HORDE = 8, -//i don't will add for all 4 positions a variable.. i think one is enough to compute the rest +//I don't add a variable for all 4 positions... I think one is enough to compute the rest AV_CPLACE_DEFENSE_STORM_AID = 9, AV_CPLACE_DEFEMSE_STORM_GRAVE = 13, AV_CPLACE_DEFENSE_STONE_GRAVE = 17, @@ -680,7 +680,7 @@ const float BG_AV_CreaturePos[AV_CPLACE_MAX][4] = {575.411f, -83.597f, 52.3626f, 6.26573f}, {571.352f, -75.6582f, 52.479f, 0.523599f}, //dun north - OK - {668.60f, -122.53f, 64.12f, 2.34f}, //not 100% ok + {668.60f, -122.53f, 64.12f, 2.34f}, /// @todo: To be confirm - Not completely okay {662.253f, -129.105f, 64.1794f, 2.77507f}, {661.209f, -138.877f, 64.2251f, 3.38594f}, {665.481f, -146.857f, 64.1271f, 3.75246f}, @@ -720,7 +720,7 @@ const float BG_AV_CreaturePos[AV_CPLACE_MAX][4] = {723.058f, -14.1548f, 50.7046f, 3.40339f}, // north {715.691f, -4.72233f, 50.2187f, 3.47321f}, // icewing {720.046f, -19.9413f, 50.2187f, 3.36849f}, // stone -//horde (coords not 100% ok) +/// horde @todo: Confirm positions {-1363.99f, -221.99f, 98.4053f, 4.93012f}, {-1370.96f, -223.532f, 98.4266f, 4.93012f}, {-1378.37f, -228.614f, 99.3546f, 5.38565f}, @@ -1039,14 +1039,14 @@ enum BG_AV_CreatureIds }; //entry, team, minlevel, maxlevel -//TODO this array should be removed, the only needed things are the entrys (for spawning(?) and handlekillunit) +/// @todo: this array should be removed, the only needed things are the entrys (for spawning(?) and handlekillunit) const uint32 BG_AV_CreatureInfo[AV_NPC_INFO_MAX][4] = { { 12050, 1216, 58, 58 }, //Stormpike Defender { 13326, 1216, 59, 59 }, //Seasoned Defender { 13331, 1216, 60, 60 }, //Veteran Defender { 13422, 1216, 61, 61 }, //Champion Defender - { 13358, 1216, 59, 60 }, //Stormpike Bowman //i think its 60, 61 and 69, 70.. but this is until now not possible TODO look if this is ok + { 13358, 1216, 59, 60 }, //Stormpike Bowman /// @todo: Confirm if this is correct. Author assumpted 60,61 & 69,70, but wouldn't work here { 11949, 469, 0, 0}, //not spawned with this data, but used for handlekillunit { 11948, 469, 0, 0}, //not spawned with this data, but used for handlekillunit { 12053, 1214, 58, 58 }, //Frostwolf Guardian @@ -1071,7 +1071,7 @@ const uint32 BG_AV_CreatureInfo[AV_NPC_INFO_MAX][4] = { 11602, 59, 54, 55 }, //Irondeep Skullthumper { 11657, 59, 58, 58 }, //Morloch - {13396, 469, 52, 53}, //irondeep alliance TODO: get the right ids + {13396, 469, 52, 53}, // irondeep alliance /// @todo: Correct and give correct ids {13080, 469, 53, 54}, {13098, 469, 54, 55}, {13078, 469, 58, 58}, @@ -1246,7 +1246,7 @@ const uint32 BG_AV_StaticCreatureInfo[51][4] = { 11675, 514, 53, 53 }, //Snowblind Windcaller { 11678, 14, 52, 53 }, //Snowblind Ambusher { 11839, 39, 56, 56 }, //Wildpaw Brute - { 11947, 1214, 61, 61 }, //Captain Galvangar --TODO: doubled + { 11947, 1214, 61, 61 }, // Captain Galvangar /// @todo: Duplicate ? Check and confirm { 11948, 1216, 63, 63 }, //Vanndar Stormpike { 11949, 1216, 61, 61 }, //Captain Balinda Stonehearth { 11997, 1334, 60, 60 }, //Stormpike Herald @@ -1277,7 +1277,7 @@ const uint32 BG_AV_StaticCreatureInfo[51][4] = { 14282, 1214, 53, 54 }, //Frostwolf Bloodhound { 14283, 1216, 53, 54 }, //Stormpike Owl { 14284, 1216, 61, 61 }, //Stormpike Battleguard - { 11946, 1214, 63, 63 }, //Drek'Thar //TODO: make the levels right (boss=0 maybe) + { 11946, 1214, 63, 63 }, //Drek'Thar /// @todo: Correct the level (Level 80 for boss ?) { 11948, 1216, 63, 63 }, //Vanndar Stormpike { 11947, 1214, 61, 61 }, //Captain Galvangar { 11949, 1216, 61, 61 } //Captain Balinda Stonehearth @@ -1310,7 +1310,7 @@ const uint32 BG_AV_GraveyardIds[9]= }; enum BG_AV_BUFF -{ //TODO add all other buffs here +{ /// @todo: Add all other buffs here AV_BUFF_ARMOR = 21163, AV_BUFF_A_CAPTAIN = 23693, //the buff which the alliance captain does AV_BUFF_H_CAPTAIN = 22751 //the buff which the horde captain does @@ -1607,7 +1607,7 @@ class BattlegroundAV : public Battleground /*general */ Creature* AddAVCreature(uint16 cinfoid, uint16 type); - uint16 GetBonusHonor(uint8 kills); //TODO remove this when the core handles this right + uint16 GetBonusHonor(uint8 kills); /// @todo: Remove this when the core handles this properly /*variables */ int32 m_Team_Scores[2]; @@ -1622,7 +1622,7 @@ class BattlegroundAV : public Battleground uint32 m_CaptainBuffTimer[2]; bool m_CaptainAlive[2]; - uint8 m_MaxLevel; //TODO remove this when battleground-getmaxlevel() returns something usefull + uint8 m_MaxLevel; /// @todo: Remove this once battleground->getmaxlevel() returns something usefull/is reworked (?) bool m_IsInformedNearVictory[2]; }; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 82b0573d875..816c6e73b7a 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1708,7 +1708,7 @@ struct SpellEffectEntry // SpellAuraOptions.dbc struct SpellAuraOptionsEntry { - uint32 Id; // 0 m_ID + uint32 Id; // 0 m_ID uint32 StackAmount; // 1 m_cumulativeAura uint32 procChance; // 2 m_procChance uint32 procCharges; // 3 m_procCharges diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 4127ab281dd..23a443e134f 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -483,15 +483,13 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature SetReactState(REACT_DEFENSIVE);*/; } - ///// TODO RENAME THIS!!!!! + /// @todo Rename these properly bool isCanTrainingOf(Player* player, bool msg) const; bool isCanInteractWithBattleMaster(Player* player, bool msg) const; bool isCanTrainingAndResetTalentsOf(Player* player) const; bool canCreatureAttack(Unit const* victim, bool force = true) const; - bool IsImmunedToSpell(SpellInfo const* spellInfo); - // redefine Unit::IsImmunedToSpell - bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const; - // redefine Unit::IsImmunedToSpellEffect + bool IsImmunedToSpell(SpellInfo const* spellInfo); //override Unit::IsImmunedToSpell + bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const; //override Unit::IsImmunedToSpellEffect bool isElite() const { if (isPet()) @@ -766,10 +764,10 @@ class Creature : public Unit, public GridObject<Creature>, public MapCreature bool DisableReputationGain; - CreatureTemplate const* m_creatureInfo; // in difficulty mode > 0 can different from sObjectMgr->GetCreatureTemplate(GetEntry()) + CreatureTemplate const* m_creatureInfo; // Can differ from sObjectMgr->GetCreatureTemplate(GetEntry()) in difficulty mode > 0 CreatureData const* m_creatureData; - uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable + uint16 m_LootMode; // Bitmask (default: LOOT_MODE_DEFAULT) that determines what loot will be lootable uint32 guid_transport; bool IsInvisibleDueToDespawn() const; diff --git a/src/server/game/Entities/Item/ItemPrototype.h b/src/server/game/Entities/Item/ItemPrototype.h index 6f0919520a3..9393b32d48a 100644 --- a/src/server/game/Entities/Item/ItemPrototype.h +++ b/src/server/game/Entities/Item/ItemPrototype.h @@ -107,10 +107,8 @@ enum ItemBondingType #define MAX_BIND_TYPE 6 -/* TODO - // need to know cases when using item is not allowed in shapeshift - ITEM_PROTO_FLAG_USABLE_WHEN_SHAPESHIFTED = 0x00800000, // Item can be used in shapeshift forms -*/ +/* /// @todo: Requiring actual cases in which using (an) item isn't allowed while shapeshifted. Else, this flag would need an implementation. + ITEM_PROTO_FLAG_USABLE_WHEN_SHAPESHIFTED = 0x00800000, // Item can be used in shapeshift forms */ enum ItemProtoFlags { @@ -148,9 +146,6 @@ enum ItemProtoFlags ITEM_PROTO_FLAG_BOP_TRADEABLE = 0x80000000 // bound item that can be traded }; -/* TODO -*/ - enum ItemFieldFlags { ITEM_FLAG_SOULBOUND = 0x00000001, // Item is soulbound and cannot be traded <<-- diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 948bb240026..b07c6183257 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -21886,7 +21886,7 @@ void Player::AddSpellAndCategoryCooldowns(SpellInfo const* spellInfo, uint32 ite if (rec > 0) ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, rec, spell); - if (catrec > 0) + if (catrec > 0 && !(spellInfo->AttributesEx6 & SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS)) ApplySpellMod(spellInfo->Id, SPELLMOD_COOLDOWN, catrec, spell); // replace negative cooldowns by 0 diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 6295db693d6..89a3a47b25d 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1336,11 +1336,16 @@ class Player : public Unit, public GridObject<Player> PhaseMgr& GetPhaseMgr() { return phaseMgr; } + /// Handles said message in regular chat based on declared language and in config pre-defined Range. void Say(std::string const& text, const uint32 language); + /// Handles yelled message in regular chat based on declared language and in config pre-defined Range. void Yell(std::string const& text, const uint32 language); + /// Outputs an universal text which is supposed to be an action. void TextEmote(std::string const& text); + /// Handles whispers from Addons and players based on sender, receiver's guid and language. void Whisper(std::string const& text, const uint32 language, uint64 receiver); void WhisperAddon(std::string const& text, std::string const& prefix, Player* receiver); + /// Constructs the player Chat data for the specific functions to use void BuildPlayerChat(WorldPacket* data, uint8 msgtype, std::string const& text, uint32 language, const char* addonPrefix = NULL) const; /*********************************************************/ diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 97758b3d0b7..6421f6d07d3 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -10652,7 +10652,7 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE)) return false; - if (!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_UNK3)) + if (!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG)) { if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE)) { @@ -10699,7 +10699,7 @@ bool Unit::_IsValidAssistTarget(Unit const* target, SpellInfo const* bySpell) co // PvC case - player can assist creature only if has specific type flags // !target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) && else if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE) - && (!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_UNK3)) + && (!bySpell || !(bySpell->AttributesEx6 & SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG)) && !((target->GetByteValue(UNIT_FIELD_BYTES_2, 1) & UNIT_BYTE2_FLAG_PVP))) { if (Creature const* creatureTarget = target->ToCreature()) diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h index 113ef1dec83..6a53d58c57f 100644 --- a/src/server/game/Globals/ObjectAccessor.h +++ b/src/server/game/Globals/ObjectAccessor.h @@ -90,7 +90,7 @@ class ObjectAccessor ObjectAccessor& operator=(const ObjectAccessor&); public: - // TODO: override these template functions for each holder type and add assertions + /// @todo: Override these template functions for each holder type and add assertions template<class T> static T* GetObjectInOrOutOfWorld(uint64 guid, T* /*typeSpecifier*/) { diff --git a/src/server/game/Instances/InstanceSaveMgr.h b/src/server/game/Instances/InstanceSaveMgr.h index a99b4c66b27..c5dcaf32463 100644 --- a/src/server/game/Instances/InstanceSaveMgr.h +++ b/src/server/game/Instances/InstanceSaveMgr.h @@ -101,8 +101,8 @@ class InstanceSave private: bool UnloadIfEmpty(); /* the only reason the instSave-object links are kept is because - the object-instSave links need to be broken at reset time - TODO: maybe it's enough to just store the number of players/groups */ + the object-instSave links need to be broken at reset time */ + /// @todo: Check if maybe it's enough to just store the number of players/groups PlayerListType m_playerList; GroupListType m_groupList; time_t m_resetTime; diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 0a2761abf6c..a54e671d7d0 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -484,8 +484,8 @@ enum SpellAttr5 SPELL_ATTR5_UNK24 = 0x01000000, // 24 SPELL_ATTR5_UNK25 = 0x02000000, // 25 SPELL_ATTR5_UNK26 = 0x04000000, // 26 aoe related - Boulder, Cannon, Corpse Explosion, Fire Nova, Flames, Frost Bomb, Living Bomb, Seed of Corruption, Starfall, Thunder Clap, Volley - SPELL_ATTR5_UNK27 = 0x08000000, // 27 - SPELL_ATTR5_UNK28 = 0x10000000, // 28 + SPELL_ATTR5_DONT_SHOW_AURA_IF_SELF_CAST = 0x08000000, // 27 Auras with this attribute are not visible on units that are the caster + SPELL_ATTR5_DONT_SHOW_AURA_IF_NOT_SELF_CAST = 0x10000000, // 28 Auras with this attribute are not visible on units that are not the caster SPELL_ATTR5_UNK29 = 0x20000000, // 29 SPELL_ATTR5_UNK30 = 0x40000000, // 30 SPELL_ATTR5_UNK31 = 0x80000000 // 31 Forces all nearby enemies to focus attacks caster @@ -496,10 +496,10 @@ enum SpellAttr6 SPELL_ATTR6_DONT_DISPLAY_COOLDOWN = 0x00000001, // 0 client doesn't display cooldown in tooltip for these spells SPELL_ATTR6_ONLY_IN_ARENA = 0x00000002, // 1 only usable in arena SPELL_ATTR6_IGNORE_CASTER_AURAS = 0x00000004, // 2 - SPELL_ATTR6_UNK3 = 0x00000008, // 3 + SPELL_ATTR6_ASSIST_IGNORE_IMMUNE_FLAG = 0x00000008, // 3 skips checking UNIT_FLAG_IMMUNE_TO_PC and UNIT_FLAG_IMMUNE_TO_NPC flags on assist SPELL_ATTR6_UNK4 = 0x00000010, // 4 SPELL_ATTR6_UNK5 = 0x00000020, // 5 - SPELL_ATTR6_PRINT_SPELLNAME = 0x00000040, // 6 when activated, spell name is shown at the center of the screen: <Spell name> (client-side attribute) + SPELL_ATTR6_USE_SPELL_CAST_EVENT = 0x00000040, // 6 Auras with this attribute trigger SPELL_CAST combat log event instead of SPELL_AURA_START (clientside attribute) SPELL_ATTR6_UNK7 = 0x00000080, // 7 SPELL_ATTR6_CANT_TARGET_CROWD_CONTROLLED = 0x00000100, // 8 SPELL_ATTR6_UNK9 = 0x00000200, // 9 @@ -513,7 +513,7 @@ enum SpellAttr6 SPELL_ATTR6_UNK17 = 0x00020000, // 17 Mount spell SPELL_ATTR6_CAST_BY_CHARMER = 0x00040000, // 18 client won't allow to cast these spells when unit is not possessed && charmer of caster will be original caster SPELL_ATTR6_UNK19 = 0x00080000, // 19 only 47488, 50782 - SPELL_ATTR6_UNK20 = 0x00100000, // 20 only 58371, 62218 + SPELL_ATTR6_ONLY_VISIBLE_TO_CASTER = 0x00100000, // 20 Auras with this attribute are only visible to their caster (or pet's owner) SPELL_ATTR6_CLIENT_UI_TARGET_EFFECTS = 0x00200000, // 21 it's only client-side attribute SPELL_ATTR6_UNK22 = 0x00400000, // 22 only 72054 SPELL_ATTR6_UNK23 = 0x00800000, // 23 @@ -524,7 +524,7 @@ enum SpellAttr6 SPELL_ATTR6_UNK28 = 0x10000000, // 28 Death Grip SPELL_ATTR6_NO_DONE_PCT_DAMAGE_MODS = 0x20000000, // 29 ignores done percent damage mods? SPELL_ATTR6_UNK30 = 0x40000000, // 30 - SPELL_ATTR6_UNK31 = 0x80000000 // 31 some special cooldown calc? only 2894 + SPELL_ATTR6_IGNORE_CATEGORY_COOLDOWN_MODS = 0x80000000 // 31 Spells with this attribute skip applying modifiers to category cooldowns }; enum SpellAttr7 @@ -557,7 +557,7 @@ enum SpellAttr7 SPELL_ATTR7_UNK25 = 0x02000000, // 25 SPELL_ATTR7_UNK26 = 0x04000000, // 26 SPELL_ATTR7_UNK27 = 0x08000000, // 27 Not set - SPELL_ATTR7_BENEFIT_FROM_SPELLMOD = 0x10000000, // 28 Non-permanent, non-passive buffs that may benefit from spellmods + SPELL_ATTR7_CONSOLIDATED_RAID_BUFF = 0x10000000, // 28 May be collapsed in raid buff frame (clientside attribute) SPELL_ATTR7_UNK29 = 0x20000000, // 29 only 69028, 71237 SPELL_ATTR7_UNK30 = 0x40000000, // 30 Burning Determination, Divine Sacrifice, Earth Shield, Prayer of Mending SPELL_ATTR7_CLIENT_INDICATOR = 0x80000000 diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index febfac27ee1..3c134b3a88e 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3592,6 +3592,30 @@ void SpellMgr::LoadSpellInfoCorrections() break; // ENDOF RUBY SANCTUM SPELLS // + // EYE OF ETERNITY SPELLS + // All spells below work even without these changes. The LOS attribute is due to problem + // from collision between maps & gos with active destroyed state. + case 57473: // Arcane Storm bonus explicit visual spell + case 57430: // Summon Static Field + case 56091: // Flame Spike (Wyrmrest Skytalon) + case 56092: // Engulf in Flames (Wyrmrest Skytalon) + case 57090: // Revivify (Wyrmrest Skytalon) + case 57143: // Life Burst (Wyrmrest Skytalon) + spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS; + break; + // ENDOF EYE OF ETERNITY SPELLS + // + // OCULUS SPELLS + // The spells below are here because their effect 1 is giving warning due to + // triggered spell not found in any dbc and is missing from encounter source* of data. + // Even judged as clientside these spells can't be guessed for* now. + case 49462: // Call Ruby Drake + case 49461: // Call Amber Drake + case 49345: // Call Emerald Drake + spellInfo->Effects[EFFECT_1].Effect = 0; + break; + // ENDOF OCULUS SPELLS + // case 40055: // Introspection case 40165: // Introspection case 40166: // Introspection @@ -3602,13 +3626,6 @@ void SpellMgr::LoadSpellInfoCorrections() spellInfo->ManaCost = 0; spellInfo->ManaPerSecond = 0; break; - // OCULUS SPELLS - // The spells below are here, because their effect 1 is giving warning, because the triggered spell is not found in dbc and is missing from encounter sniff. - case 49462: // Call Ruby Drake - case 49461: // Call Amber Drake - case 49345: // Call Emerald Drake - spellInfo->Effects[EFFECT_1].Effect = 0; - break; // Halls Of Origination spells // Temple Guardian Anhuur case 76606: // Disable Beacon Beams L diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp index b0a34047c0e..b258be20feb 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/boss_malygos.cpp @@ -16,143 +16,208 @@ */ /* Script Data Start -SDName: Boss malygos +SDName: Boss Malygos Script Data End */ -// TO-DOs: -// Implement a better pathing for Malygos. -// Find sniffed spawn position for chest -// Implement a better way to disappear the gameobjects -// Implement achievements -// Remove hack that re-adds targets to the aggro list after they enter to a vehicle when it works as expected -// Improve whatever can be improved :) +/* Check TO DOs in the script, but here is one essential hack to be removed only if core changes are made: + At Wyrmrest Skytalon script I make it kill player if the drake dies, because at 100.0f z yards the map is + supposed to handle the air as ground or something to which you will fall and die. However, currently maps/movements + stop flying below it, however they don't stop movementflag FALLING. Which leads to % player falling at - 1200000.0 z, + Which leads due to some desynch to not being able to press "release spirit". + Also the teleport using while on vehicle is lacking support, but soon will have. + You can still click afer leaving vehicle. */ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "SpellScript.h" #include "SpellAuraEffects.h" -#include "PassiveAI.h" #include "eye_of_eternity.h" -#include "ScriptedEscortAI.h" #include "Player.h" #include "Vehicle.h" #include "CombatAI.h" +#include "GameObjectAI.h" #include "CreatureTextMgr.h" - -enum Achievements -{ - ACHIEV_TIMED_START_EVENT = 20387, -}; +#include "MoveSplineInit.h" enum Events { - // =========== PHASE ONE =============== - EVENT_ARCANE_BREATH = 1, - EVENT_ARCANE_STORM = 2, - EVENT_VORTEX = 3, - EVENT_POWER_SPARKS = 4, + // =========== INTRO BEFORE WE START ENCOUNTER =============== + EVENT_STOP_PORTAL_BEAM = 1, + EVENT_RANDOM_PORTAL = 2, + EVENT_SAY_INTRO = 3, + EVENT_LAND_START_ENCOUNTER = 4, - // =========== PHASE TWO =============== - EVENT_SURGE_POWER = 5, // wowhead is wrong, Surge of Power is casted instead of Arcane Pulse (source sniffs!) - EVENT_SUMMON_ARCANE = 6, + // =========== PHASE ONE =============== + EVENT_ARCANE_BREATH = 5, + EVENT_ARCANE_STORM = 6, + EVENT_VORTEX = 7, + EVENT_POWER_SPARKS = 8, // =========== PHASE TWO =============== - EVENT_SURGE_POWER_PHASE_3 = 7, - EVENT_STATIC_FIELD = 8, - - // =============== YELLS =============== - EVENT_YELL_0 = 9, - EVENT_YELL_1 = 10, - EVENT_YELL_2 = 11, - EVENT_YELL_3 = 12, - EVENT_YELL_4 = 13, + EVENT_FLY_OUT_OF_PLATFORM = 9, + EVENT_DELAYED_REINFORCEMENTS = 10, + EVENT_PATHING_AROUND_PLATFORM = 11, + EVENT_SURGE_OF_POWER_P_TWO = 12, + EVENT_SUMMON_ARCANE_BOMB = 13, + EVENT_MOVE_TO_POINT_SURGE_P_TWO = 14, + EVENT_LIGHT_DIMENSION_CHANGE = 15, + EVENT_MOVE_TO_P_THREE_POINT = 16, + EVENT_START_P_THREE = 17, + + // =========== PHASE THREE ============= + EVENT_ARCANE_PULSE = 18, + EVENT_SURGE_OF_POWER_P_THREE = 19, + EVENT_STATIC_FIELD = 20, + + // ========== MISC MECHANICS =========== + EVENT_PREVENT_SAY_SPAM_ON_KILL = 21, + EVENT_MOVE_TO_VORTEX_POINT = 22, // This should be fixed someday in core, we can't call new movement from MovementInform + EVENT_START_FIRST_RANDOM_PORTAL = 23, // There is something that is still loading when we first enter instance and it breaks + // first visual cast of intro portal beam mechanic, so we need short delay from the event. + // ============ NEXUS LORDS ============ + EVENT_ARCANE_SHOCK = 1, + EVENT_HASTE_BUFF = 2, + EVENT_NUKE_DUMMY = 3, + + // ======== SCIONS OF ETERNITY ========= + EVENT_ARCANE_BARRAGE = 1 }; enum Phases { - PHASE_ONE = 1, - PHASE_TWO = 2, - PHASE_THREE = 3 + PHASE_NOT_STARTED = 1, + PHASE_ONE = 2, + PHASE_TWO = 3, + PHASE_THREE = 4 }; enum Spells { - SPELL_ARCANE_BREATH = 56272, - SPELL_ARCANE_STORM = 57459, - SPELL_BERSEKER = 60670, - - SPELL_VORTEX_1 = 56237, // seems that frezze object animation - SPELL_VORTEX_2 = 55873, // visual effect - SPELL_VORTEX_3 = 56105, // this spell must handle all the script - casted by the boss and to himself - //SPELL_VORTEX_4 = 55853, // damage | used to enter to the vehicle - defined in eye_of_eternity.h - //SPELL_VORTEX_5 = 56263, // damage | used to enter to the vehicle - defined in eye_of_eternity.h - SPELL_VORTEX_6 = 73040, // teleport - (casted to all raid) | caster 30090 | target player - - SPELL_PORTAL_VISUAL_CLOSED = 55949, - SPELL_SUMMON_POWER_PARK = 56142, - SPELL_POWER_SPARK_DEATH = 55852, - SPELL_POWER_SPARK_MALYGOS = 56152, - - SPELL_SURGE_POWER = 56505, // used in phase 2 - SPELL_SUMMON_ARCANE_BOMB = 56429, - SPELL_ARCANE_OVERLOAD = 56432, - SPELL_SUMMOM_RED_DRAGON = 56070, - SPELL_SURGE_POWER_PHASE_3 = 57407, - SPELL_STATIC_FIELD = 57430 + // Intro + SPELL_RANDOM_PORTAL = 56047, + SPELL_PORTAL_BEAM = 56046, // Malygos cast on portal to activate it during PHASE_NOT_STARTED + + //Phase I + SPELL_BERSEKER = 60670, + SPELL_MALYGOS_BERSERK = 47008, // it's the berserk spell that will hit only Malygos after 10 min of 60670 + SPELL_PORTAL_VISUAL_CLOSED = 55949, + SPELL_SUMMON_POWER_PARK = 56142, + SPELL_POWER_SPARK_DEATH = 55852, + SPELL_POWER_SPARK_MALYGOS = 56152, + SPELL_ARCANE_BREATH = 56272, + SPELL_ARCANE_STORM_P_I = 61693, + SPELL_VORTEX_1 = 56237, // seems that frezze object animation + SPELL_VORTEX_2 = 55873, // visual effect + SPELL_VORTEX_3 = 56105, // this spell must handle all the script - casted by the boss and to himself + SPELL_VORTEX_6 = 73040, // teleport - (casted to all raid), caster vortex bunnies, targets players. + + // Phase II + SPELL_TELEPORT_VISUAL_ONLY = 41232, // Light blue animation cast by arcane NPCs when spawned on Hover Disks + SPELL_RIDE_HOVER_DISK = 61421, + SPELL_ALIGN_DISK_AGGRO = 61210, + SPELL_DUMMY_NUKE = 61215, + SPELL_SUMMON_ARCANE_BOMB = 56429, + SPELL_ARCANE_BOMB_TRIGGER = 56430, + SPELL_ARCANE_BOMB_KNOCKBACK_DAMAGE = 56431, + SPELL_ARCANE_OVERLOAD_1 = 56432, // casted by npc Arcane Overload ID: 30282 + // SPELL_ARCANE_OVERLOAD_2 = 56435, // Triggered by 56432 + // SPELL_ARCANE_OVERLOAD_3 = 56438, // Triggered by 56432 + SPELL_SURGE_OF_POWER_P_II = 56505, + // SPELL_SURGE_OF_POWER_TRIGGERED = 56548, + SPELL_ARCANE_SHOCK = 57058, // used by Nexus Lords + SPELL_HASTE = 57060, // used by Nexus Lords + SPELL_ARCANE_BARRAGE = 56397, // used by Scions of Eternity + + // Transition /II-III/ + SPELL_SUMMOM_RED_DRAGON_BUDYY = 56070, + SPELL_RIDE_RED_DRAGON_BUDDY = 56071, + SPELL_SUMMON_RED_DRAGON_BUDDY_F_CAST = 58846, // After implicitly hit player targets they will force cast 56070 on self + SPELL_DESTROY_PLATFORM_CHANNEL = 58842, + SPELL_DESTROY_PLATFORM_BOOM_VISUAL = 59084, + SPELL_DESTROY_PLATFORM_EVENT = 59099, + + // Phase III + SPELL_CLEAR_ALL_DEBUFFS = 34098, + SPELL_IMMUNE_CURSES = 64515, + SPELL_STATIC_FIELD_MISSLE = 57430, + SPELL_ARCANE_PULSE = 57432, + SPELL_SURGE_OF_POWER_PHASE_3_10 = 57407, + SPELL_SURGE_OF_POWER_PHASE_3_25 = 60936, + SPELL_SURGE_OF_POWER_WARNING_SELECTOR_25 = 60939, // used in 25 player mode for selecting targets for warnings and then sends to actual spell + SPELL_ARCANE_STORM_P_III = 57459, + + // Phase I and III + SPELL_ARCANE_STORM_EXTRA_VISUAL = 57473, + + // Outro + SPELL_ALEXSTRASZAS_GIFT_BEAM_VISUAL = 61023 }; enum Movements { - MOVE_VORTEX = 1, - MOVE_PHASE_TWO, - MOVE_DEEP_BREATH_ROTATION, - MOVE_INIT_PHASE_ONE, - MOVE_CENTER_PLATFORM + POINT_NEAR_RANDOM_PORTAL_P_NONE = 1, + POINT_LAND_P_ONE, + POINT_VORTEX_P_ONE, + POINT_LAND_AFTER_VORTEX_P_ONE, + POINT_LIFT_IN_AIR_P_ONE, + POINT_PHASE_ONE_TO_TWO_TRANSITION, + POINT_FLY_OUT_OF_PLATFORM_P_TWO, + POINT_SURGE_OF_POWER_P_TWO, + POINT_DESTROY_PLATFORM_P_TWO, + POINT_IDLE_P_THREE, }; enum Seats { - SEAT_0 = 0, + SEAT_0 = 0 }; enum Factions { - FACTION_FRIENDLY = 35, - FACTION_HOSTILE = 14 + // Needed for melee hover disks /when Nexus Lords die/ + FACTION_FRIENDLY = 35 }; enum Actions { - ACTION_HOVER_DISK_START_WP_1, - ACTION_HOVER_DISK_START_WP_2 -}; - -enum MalygosEvents -{ - DATA_SUMMON_DEATHS, // phase 2 - DATA_PHASE + // Malygos + ACTION_LAND_ENCOUNTER_START = 0, + ACTION_EXECUTE_VORTEX = 1, + ACTION_HANDLE_P_THREE_INTRO = 2, + ACTION_LIFT_IN_AIR = 3, + ACTION_HANDLE_RESPAWN = 4, + ACTION_CYCLIC_MOVEMENT = 5, + + // Caster hover disk despawn action + ACTION_DELAYED_DESPAWN = 8, + + // Nexus Lord's action used to shedule casting spell that determine disk's target to chase + ACTION_SET_DISK_VICTIM_CHASE = 0 }; -#define TEN_MINUTES 600000 - enum Texts { // Malygos - SAY_AGGRO_P_ONE = 0, - SAY_KILLED_PLAYER_P_ONE = 1, - SAY_END_P_ONE = 2, - SAY_AGGRO_P_TWO = 3, - SAY_ANTI_MAGIC_SHELL = 4, // not sure when execute it - SAY_MAGIC_BLAST = 5, // not sure when execute it - SAY_KILLED_PLAYER_P_TWO = 6, - SAY_END_P_TWO = 7, - SAY_INTRO_P_THREE = 8, - SAY_AGGRO_P_THREE = 9, - SAY_SURGE_POWER = 10, // not sure when execute it - SAY_BUFF_SPARK = 11, - SAY_KILLED_PLAYER_P_THREE = 12, - SAY_SPELL_CASTING_P_THREE = 13, - SAY_DEATH, + SAY_INTRO_EVENT = 0, + SAY_START_P_ONE = 1, + SAY_DEEP_BREATH = 2, + SAY_KILLED_PLAYER_P_ONE = 3, + SAY_END_P_ONE = 4, + // SAY_START_P_TWO = 5, // Unused by Blizzard for some reason on any version + SAY_ANTI_MAGIC_SHELL = 6, + SAY_MAGIC_BLAST = 7, + SAY_KILLED_PLAYER_P_TWO = 8, + SAY_END_P_TWO = 9, + SAY_START_P_THREE = 10, + // SAY_START_P_THREE = 11, // Unused by Blizzard for some reason on any version + EMOTE_SURGE_OF_POWER_WARNING_P2 = 12, + SAY_SURGE_OF_POWER = 13, + SAY_BUFF_SPARK = 14, + SAY_KILLED_PLAYER_P_THREE = 15, + SAY_SPELL_CASTING_P_THREE = 16, + SAY_DEATH = 17, + EMOTE_SURGE_OF_POWER_WARNING_P3 = 18, + EMOTE_HIT_BERSERKER_TIMER = 19, // Alexstrasza SAY_ONE = 0, @@ -161,252 +226,438 @@ enum Texts SAY_FOUR = 3, // Power Sparks - EMOTE_POWER_SPARK_SUMMONED = 0 + EMOTE_POWER_SPARK_SUMMONED = 0 }; +#define MAX_SUMMONS_PHASE_TWO_10MAN 6 +#define MAX_SUMMONS_PHASE_TWO_25MAN 12 -#define MAX_HOVER_DISK_WAYPOINTS 18 +#define MAX_RANGE_HOVER_DISK_SPAWNPOINTS 8 +Position const RangeHoverDisksSpawnPositions[MAX_RANGE_HOVER_DISK_SPAWNPOINTS] = +{ + { 782.9821f, 1296.652f, 282.1114f, 0.0f }, + { 764.3126f, 1328.871f, 282.3091f, 0.0f }, + { 725.8506f, 1306.749f, 282.2698f, 0.0f }, + { 744.5175f, 1274.396f, 282.3402f, 0.0f }, + { 764.3936f, 1274.371f, 282.6011f, 0.0f }, + { 779.3761f, 1316.166f, 282.1653f, 0.0f }, + { 744.4915f, 1328.901f, 282.2112f, 0.0f }, + { 729.2364f, 1287.328f, 282.4173f, 0.0f } +}; -// Sniffed data (x, y, z) -const Position HoverDiskWaypoints[MAX_HOVER_DISK_WAYPOINTS] = +#define MAX_MELEE_HOVER_DISK_SPAWNPOINTS 4 +Position const MeleeHoverDisksSpawnPositions[MAX_RANGE_HOVER_DISK_SPAWNPOINTS] = { - {782.9821f, 1296.652f, 282.1114f, 0.0f}, - {779.5459f, 1287.228f, 282.1393f, 0.0f}, - {773.0028f, 1279.52f, 282.4164f, 0.0f}, - {764.3626f, 1274.476f, 282.4731f, 0.0f}, - {754.3961f, 1272.639f, 282.4171f, 0.0f}, - {744.4422f, 1274.412f, 282.222f, 0.0f}, - {735.575f, 1279.742f, 281.9674f, 0.0f}, - {729.2788f, 1287.187f, 281.9943f, 0.0f}, - {726.1191f, 1296.688f, 282.2997f, 0.0f}, - {725.9396f, 1306.531f, 282.2448f, 0.0f}, - {729.3045f, 1316.122f, 281.9108f, 0.0f}, - {735.8322f, 1323.633f, 282.1887f, 0.0f}, - {744.4616f, 1328.999f, 281.9948f, 0.0f}, - {754.4739f, 1330.666f, 282.049f, 0.0f}, - {764.074f, 1329.053f, 281.9949f, 0.0f}, - {772.8409f, 1323.951f, 282.077f, 0.0f}, - {779.5085f, 1316.412f, 281.9145f, 0.0f}, - {782.8365f, 1306.778f, 282.3035f, 0.0f}, + { 754.4617f, 1283.859f, 285.0522f, 0.0f }, + { 771.7864f, 1301.853f, 285.0522f, 0.0f }, + { 753.9635f, 1319.003f, 285.0522f, 0.0f }, + { 736.4914f, 1301.683f, 285.0522f, 0.0f } }; -#define GROUND_Z 268 +#define MAX_MELEE_HOVER_DISK_WAYPOINTS 16 +Position const MeleeHoverDisksWaypoints[MAX_MELEE_HOVER_DISK_WAYPOINTS] = +{ + // First melee hover disk wps + { 766.2931f, 1312.904f, 277.0551f, 0.0f }, + { 754.3397f, 1319.759f, 274.0536f, 0.0f }, + { 742.1018f, 1312.714f, 270.1367f, 0.0f }, + { 735.6851f, 1301.422f, 266.7208f, 0.0f }, + // Second melee hover disk wps + { 742.6257f, 1313.471f, 275.9713f, 0.0f }, + { 736.8845f, 1301.921f, 274.0264f, 0.0f }, + { 742.6632f, 1289.951f, 269.8603f, 0.0f }, + { 754.3682f, 1283.942f, 266.6098f, 0.0f }, + // Third melee hover disk wps + { 742.2078f, 1290.518f, 276.2484f, 0.0f }, + { 754.5398f, 1284.311f, 273.5815f, 0.0f }, + { 766.5588f, 1290.345f, 269.6655f, 0.0f }, + { 773.4768f, 1301.474f, 266.5821f, 0.0f }, + // Forth melee hover disk wps + { 766.1189f, 1290.197f, 276.9436f, 0.0f }, + { 771.9507f, 1301.602f, 273.9712f, 0.0f }, + { 766.1253f, 1313.451f, 270.4991f, 0.0f }, + { 754.5378f, 1319.399f, 266.6653f, 0.0f } +}; -// Source: Sniffs (x, y, z) -#define MALYGOS_MAX_WAYPOINTS 16 -const Position MalygosPhaseTwoWaypoints[MALYGOS_MAX_WAYPOINTS] = +#define MAX_MALYGOS_POS 10 +Position const MalygosPositions[MAX_MALYGOS_POS] = { - {812.7299f, 1391.672f, 283.2763f, 0.0f}, - {848.2912f, 1358.61f, 283.2763f, 0.0f}, - {853.9227f, 1307.911f, 283.2763f, 0.0f}, - {847.1437f, 1265.538f, 283.2763f, 0.0f}, - {839.9229f, 1245.245f, 283.2763f, 0.0f}, - {827.3463f, 1221.818f, 283.2763f, 0.0f}, - {803.2727f, 1203.851f, 283.2763f, 0.0f}, - {772.9372f, 1197.981f, 283.2763f, 0.0f}, - {732.1138f, 1200.647f, 283.2763f, 0.0f}, - {693.8761f, 1217.995f, 283.2763f, 0.0f}, - {664.5038f, 1256.539f, 283.2763f, 0.0f}, - {650.1497f, 1303.485f, 283.2763f, 0.0f}, - {662.9109f, 1350.291f, 283.2763f, 0.0f}, - {677.6391f, 1377.607f, 283.2763f, 0.0f}, - {704.8198f, 1401.162f, 283.2763f, 0.0f}, - {755.2642f, 1417.1f, 283.2763f, 0.0f}, + { 754.544f, 1301.71f, 320.01f, 0.0f }, // Point destroy platform + { 754.393f, 1301.27f, 292.91f, 0.0f }, // Point vortex + { 754.362f, 1301.61f, 266.17f, 0.0f }, // Land after vortex + { 754.695f, 1301.66f, 316.65f, 0.0f }, // Point surge of Power phase II + { 755.681f, 1298.41f, 220.06f, 0.0f } // Point idle phase III }; -#define MAX_SUMMONS_PHASE_TWO 4 +Position const AlexstraszaSpawnPos = { 854.551f, 1225.31f, 300.901f, 0.0f }; // Alexstrasza's spawn position +Position const HeartOfMagicSpawnPos = { 755.351f, 1298.31f, 223.909f, 0.0f }; // Heart of Magic spawn position -#define MAX_MALYGOS_POS 2 -const Position MalygosPositions[MAX_MALYGOS_POS] = +#define TEN_MINUTES (10*MINUTE*IN_MILLISECONDS) + +enum Achievements { - {754.544f, 1301.71f, 320.0f, 0.0f}, - {754.39f, 1301.27f, 292.91f, 0.0f}, + ACHIEV_TIMED_START_EVENT = 20387 +}; + +enum AreaIds +{ + AREA_EYE_OF_ETERNITY = 4500 +}; + +enum MiscData +{ + // Lights + LIGHT_GET_DEFAULT_FOR_MAP = 0, + LIGHT_OBSCURE_SPACE = 1822, + LIGHT_CHANGE_DIMENSIONS = 1823, + LIGHT_ARCANE_RUNES = 1824, + LIGHT_OBSCURE_ARCANE_RUNES = 1825, + + // Data (setters/getters) + DATA_SUMMON_DEATHS = 0, // phase 2 + DATA_PHASE = 1, + + // Target guids + DATA_LAST_OVERLOAD_GUID = 13, // used to store last Arcane Overload guid + DATA_FIRST_SURGE_TARGET_GUID = 14, + DATA_SECOND_SURGE_TARGET_GUID = 15, + DATA_THIRD_SURGE_TARGET_GUID = 16 +}; + +// Used to check if summons guids come from vehicles +class VehicleCheckPredicate +{ + public: + bool operator()(uint64 guid) { return IS_VEHICLE_GUID(guid); } }; class boss_malygos : public CreatureScript { public: - boss_malygos() : CreatureScript("boss_malygos") {} - - CreatureAI* GetAI(Creature* creature) const - { - return new boss_malygosAI(creature); - } + boss_malygos() : CreatureScript("boss_malygos") { } struct boss_malygosAI : public BossAI { boss_malygosAI(Creature* creature) : BossAI(creature, DATA_MALYGOS_EVENT) { - // If we enter in combat when MovePoint generator is active, it overrwrites our homeposition - _homePosition = creature->GetHomePosition(); + _despawned = false; // We determine if Malygos will be realocated to spawning position on reset triggered by boss despawn on evade + _flySpeed = me->GetSpeed(MOVE_FLIGHT); // Get initial fly speed, otherwise on each wipe fly speed would add up if we get it } void Reset() { - _Reset(); - - _bersekerTimer = 0; - _currentPos = 0; - - SetPhase(PHASE_ONE, true); - - _delayedMovementTimer = 8000; - _delayedMovement = false; + // EnterEvadeMode and Reset() links are cut for the sake of properly functioning despawner. + if (!_despawned) + _Reset(); _summonDeaths = 0; + _preparingPulsesChecker = 0; + _arcaneOverloadGUID = NULL; + _firstSelectedSurgeTargetGUID = NULL; + _secondSelectedSurgeTargetGUID = NULL; + _thirdSelectedSurgeTargetGUID = NULL; + + _killSpamFilter = false; + _canAttack = false; + _executingVortex = false; + _arcaneReinforcements = true; + _flyingOutOfPlatform = false; + _firstCyclicMovementStarted = false; + _performingSurgeOfPower = false; + _performingDestroyPlatform = false; - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - - _cannotMove = true; - - me->SetCanFly(true); + me->SetDisableGravity(true); + me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + // TO DO: find what in core is making boss slower than in retail (when correct speed data) or find missing movement flag update or forced spline change + me->SetSpeed(MOVE_FLIGHT, _flySpeed * 0.25f); + if (_despawned) + DoAction(ACTION_HANDLE_RESPAWN); + SetPhase(PHASE_NOT_STARTED, true); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_PASSIVE); if (instance) instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); } uint32 GetData(uint32 data) const { - if (data == DATA_SUMMON_DEATHS) - return _summonDeaths; - else if (data == DATA_PHASE) - return _phase; + switch (data) + { + case DATA_SUMMON_DEATHS: + return _summonDeaths; + case DATA_PHASE: + return _phase; + } return 0; } void SetData(uint32 data, uint32 value) { - if (data == DATA_SUMMON_DEATHS && _phase == PHASE_TWO) + if (data == DATA_SUMMON_DEATHS && _phase == PHASE_TWO && !_despawned) { _summonDeaths = value; - if (_summonDeaths >= MAX_SUMMONS_PHASE_TWO) - StartPhaseThree(); + if (GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + { + if (_summonDeaths == MAX_SUMMONS_PHASE_TWO_10MAN) + { + _performingDestroyPlatform = true; + DoAction(ACTION_HANDLE_P_THREE_INTRO); + } + } + else if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + { + if (_summonDeaths == MAX_SUMMONS_PHASE_TWO_25MAN) + { + _performingDestroyPlatform = true; + DoAction(ACTION_HANDLE_P_THREE_INTRO); + } + } } } - void EnterEvadeMode() + uint64 GetGUID(int32 data) const { - me->SetHomePosition(_homePosition); + switch (data) + { + case DATA_FIRST_SURGE_TARGET_GUID: + return _firstSelectedSurgeTargetGUID; + case DATA_SECOND_SURGE_TARGET_GUID: + return _secondSelectedSurgeTargetGUID; + case DATA_THIRD_SURGE_TARGET_GUID: + return _thirdSelectedSurgeTargetGUID; + } - me->SetDisableGravity(true); + return 0; + } - BossAI::EnterEvadeMode(); + void SetGUID(uint64 guid, int32 type) + { + switch (type) + { + case DATA_LAST_OVERLOAD_GUID: + _arcaneOverloadGUID = guid; + case DATA_FIRST_SURGE_TARGET_GUID: + _firstSelectedSurgeTargetGUID = guid; + case DATA_SECOND_SURGE_TARGET_GUID: + _secondSelectedSurgeTargetGUID = guid; + case DATA_THIRD_SURGE_TARGET_GUID: + _thirdSelectedSurgeTargetGUID = guid; + } + } - if (instance) - instance->SetBossState(DATA_MALYGOS_EVENT, FAIL); + void DoAction(int32 action) + { + switch (action) + { + case ACTION_LAND_ENCOUNTER_START: + events.CancelEventGroup(1); + if (Creature* alexstraszaBunny = me->GetMap()->GetCreature(instance->GetData64(DATA_ALEXSTRASZA_BUNNY_GUID))) + { + Position pos; + pos.m_positionZ = alexstraszaBunny->GetPositionZ(); + alexstraszaBunny->GetNearPoint2D(pos.m_positionX, pos.m_positionY, 30.0f, alexstraszaBunny->GetAngle(me)); + me->GetMotionMaster()->MoveLand(POINT_LAND_P_ONE, pos); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + me->SetInCombatWithZone(); + events.ScheduleEvent(EVENT_LAND_START_ENCOUNTER, 7*IN_MILLISECONDS, 1, PHASE_NOT_STARTED); + } + break; + case ACTION_EXECUTE_VORTEX: + DoCast(me, SPELL_VORTEX_1, true); + DoCast(me, SPELL_VORTEX_2, true); + // the vortex execution continues in the dummy effect of this spell (see it's script) + DoCast(me, SPELL_VORTEX_3, true); + break; + case ACTION_LIFT_IN_AIR: + Position _zToLift; + me->GetPosition(&_zToLift); + if (_phase == PHASE_ONE) + { + _zToLift.m_positionZ += 20.0f; + me->GetMotionMaster()->MoveTakeoff(POINT_LIFT_IN_AIR_P_ONE, _zToLift); + } + else if (_phase == PHASE_TWO) + { + _zToLift.m_positionZ = 300.1f; + me->GetMotionMaster()->MoveTakeoff(POINT_PHASE_ONE_TO_TWO_TRANSITION, _zToLift); + } + break; + case ACTION_HANDLE_P_THREE_INTRO: + events.CancelEventGroup(0); + events.CancelEventGroup(1); + events.CancelEventGroup(2); + me->GetMotionMaster()->Initialize(); + me->StopMoving(); + // Vehicles shouldn't be despawned with 0 delay if the call comes from virtual function that overrides PassengerBoarded. + // Aside from that he doesn't despawn both vehicles and arcane overloads right away, but with some delay. + DummyEntryCheckPredicate pred; + summons.DoAction(ACTION_DELAYED_DESPAWN, pred); + Talk(SAY_END_P_TWO); + me->GetMotionMaster()->MovePoint(POINT_DESTROY_PLATFORM_P_TWO, MalygosPositions[0]); + events.ScheduleEvent(EVENT_LIGHT_DIMENSION_CHANGE, 1*IN_MILLISECONDS, 0, PHASE_TWO); + break; + case ACTION_HANDLE_RESPAWN: + // Teleport to spawn position, we can't use normal relocate + float x, y, z, o; + me->GetRespawnPosition(x, y, z, &o); + me->NearTeleportTo(x, y, z, o); + // Respawn Iris + instance->SetData(DATA_RESPAWN_IRIS, 0); + _despawned = false; + break; + case ACTION_CYCLIC_MOVEMENT: + Movement::MoveSplineInit init(me); + FillCirclePath(MalygosPositions[3], 130.0f, 283.2763f, init.Path(), true); + init.SetFly(); + init.SetCyclic(); + init.Launch(); + break; + } } void SetPhase(uint8 phase, bool setEvents = false) { events.Reset(); - events.SetPhase(phase); _phase = phase; - if (setEvents) SetPhaseEvents(); } - void StartPhaseThree() - { - if (!instance) - return; - - SetPhase(PHASE_THREE, true); - - // this despawns Hover Disks - summons.DespawnAll(); - // players that used Hover Disk are no in the aggro list - me->SetInCombatWithZone(); - ThreatContainer::StorageType const& m_threatlist = me->getThreatManager().getThreatList(); - for (ThreatContainer::StorageType::const_iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) - { - if (Unit* target = (*itr)->getTarget()) - { - if (target->GetTypeId() != TYPEID_PLAYER) - continue; - - // The rest is handled in the AI of the vehicle. - target->CastSpell(target, SPELL_SUMMOM_RED_DRAGON, true); - me->Attack(target, false); - } - } - - if (GameObject* go = GameObject::GetGameObject(*me, instance->GetData64(DATA_PLATFORM))) - go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED); // In sniffs it has this flag, but i don't know how is applied. - - // pos sniffed - me->GetMotionMaster()->MoveIdle(); - me->GetMotionMaster()->MovePoint(MOVE_CENTER_PLATFORM, MalygosPositions[0].GetPositionX(), MalygosPositions[0].GetPositionY(), MalygosPositions[0].GetPositionZ()); - } - void SetPhaseEvents() { switch (_phase) { + case PHASE_NOT_STARTED: + events.ScheduleEvent(EVENT_SAY_INTRO, 1*IN_MILLISECONDS, 1, _phase); + events.ScheduleEvent(EVENT_START_FIRST_RANDOM_PORTAL, 2*IN_MILLISECONDS, 1, _phase); + break; case PHASE_ONE: events.ScheduleEvent(EVENT_ARCANE_BREATH, urand(15, 20)*IN_MILLISECONDS, 0, _phase); - events.ScheduleEvent(EVENT_ARCANE_STORM, urand(5, 10)*IN_MILLISECONDS, 0, _phase); + events.ScheduleEvent(EVENT_ARCANE_STORM, 10*IN_MILLISECONDS, 0, _phase); events.ScheduleEvent(EVENT_VORTEX, urand(30, 40)*IN_MILLISECONDS, 0, _phase); events.ScheduleEvent(EVENT_POWER_SPARKS, urand(30, 35)*IN_MILLISECONDS, 0, _phase); break; case PHASE_TWO: - events.ScheduleEvent(EVENT_YELL_0, 0, 0, _phase); - events.ScheduleEvent(EVENT_YELL_1, 24*IN_MILLISECONDS, 0, _phase); - events.ScheduleEvent(EVENT_SURGE_POWER, urand(60, 70)*IN_MILLISECONDS, 0, _phase); - events.ScheduleEvent(EVENT_SUMMON_ARCANE, urand(2, 5)*IN_MILLISECONDS, 0, _phase); + events.ScheduleEvent(EVENT_MOVE_TO_POINT_SURGE_P_TWO, 60*IN_MILLISECONDS, 0, _phase); + me->AI()->DoAction(ACTION_LIFT_IN_AIR); break; case PHASE_THREE: - events.ScheduleEvent(EVENT_YELL_2, 0, 0, _phase); - events.ScheduleEvent(EVENT_YELL_3, 8*IN_MILLISECONDS, 0, _phase); - events.ScheduleEvent(EVENT_YELL_4, 16*IN_MILLISECONDS, 0, _phase); - events.ScheduleEvent(EVENT_SURGE_POWER_PHASE_3, urand(7, 16)*IN_MILLISECONDS, 0, _phase); + events.ScheduleEvent(EVENT_ARCANE_PULSE, 13*IN_MILLISECONDS, 0, _phase); + events.ScheduleEvent(EVENT_ARCANE_STORM, 20*IN_MILLISECONDS, 0, _phase); + events.ScheduleEvent(EVENT_SURGE_OF_POWER_P_THREE, urand(7, 16)*IN_MILLISECONDS, 0, _phase); events.ScheduleEvent(EVENT_STATIC_FIELD, urand(20, 30)*IN_MILLISECONDS, 0, _phase); break; - default: - break; } } + // There are moments where boss will do nothing while being attacked + void AttackStart(Unit* target) + { + if (_canAttack) + BossAI::AttackStart(target); + } + void EnterCombat(Unit* /*who*/) { - _EnterCombat(); + // We can't call full function here since it includes DoZoneInCombat(), + // if someone does it will be returned with a warning. + me->setActive(true); + if (instance) + { + if (!instance->CheckRequiredBosses(DATA_MALYGOS_EVENT)) + { + EnterEvadeMode(); + return; + } + + instance->SetBossState(DATA_MALYGOS_EVENT, IN_PROGRESS); + } + + Talk(SAY_START_P_ONE); + DoCast(SPELL_BERSEKER); // periodic aura, first tick in 10 minutes + if (instance) + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + } + + void EnterEvadeMode() + { + if (instance) + instance->SetBossState(DATA_MALYGOS_EVENT, FAIL); - me->SetDisableGravity(false); - me->SetCanFly(false); + SendLightOverride(LIGHT_GET_DEFAULT_FOR_MAP, 1*IN_MILLISECONDS); - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + if (_phase == PHASE_THREE) + me->SetControlled(false, UNIT_STATE_ROOT); + + uint32 corpseDelay = me->GetCorpseDelay(); + uint32 respawnDelay = me->GetRespawnDelay(); + me->SetCorpseDelay(1); + me->SetRespawnDelay(29); + me->DespawnOrUnsummon(); + me->SetCorpseDelay(corpseDelay); + me->SetRespawnDelay(respawnDelay); - Talk(SAY_AGGRO_P_ONE); + // Set speed to normal value + me->SetSpeed(MOVE_FLIGHT, _flySpeed); + me->RemoveAllAuras(); + me->CombatStop(); // Sometimes threat can remain, so it's a safety measure - DoCast(SPELL_BERSEKER); // periodic aura, first tick in 10 minutes + if (!_despawned) + _despawned = true; + + me->ResetLootMode(); + events.Reset(); + if (!summons.empty()) + { + if (_phase == PHASE_TWO) + { + VehicleCheckPredicate pred; + summons.DoAction(ACTION_DELAYED_DESPAWN, pred); + summons.remove_if(pred); + summons.DespawnAll(); + } + else if (_phase == PHASE_THREE) + summons.DespawnAll(); + } if (instance) - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); + instance->SetBossState(DATA_MALYGOS_EVENT, NOT_STARTED); } - void KilledUnit(Unit* who) + void KilledUnit(Unit* victim) { - if (who->GetTypeId() != TYPEID_PLAYER) + if (victim->GetTypeId() != TYPEID_PLAYER) return; - switch (_phase) + if (!_killSpamFilter) { - case PHASE_ONE: - Talk(SAY_KILLED_PLAYER_P_ONE); - break; - case PHASE_TWO: - Talk(SAY_KILLED_PLAYER_P_TWO); - break; - case PHASE_THREE: - Talk(SAY_KILLED_PLAYER_P_THREE); - break; + switch (_phase) + { + case PHASE_ONE: + Talk(SAY_KILLED_PLAYER_P_ONE); + events.ScheduleEvent(EVENT_PREVENT_SAY_SPAM_ON_KILL, 5*IN_MILLISECONDS, 0, _phase); + _killSpamFilter = true; + break; + case PHASE_TWO: + Talk(SAY_KILLED_PLAYER_P_TWO); + events.ScheduleEvent(EVENT_PREVENT_SAY_SPAM_ON_KILL, 5*IN_MILLISECONDS, 0, _phase); + _killSpamFilter = true; + break; + case PHASE_THREE: + Talk(SAY_KILLED_PLAYER_P_THREE); + events.ScheduleEvent(EVENT_PREVENT_SAY_SPAM_ON_KILL, 5*IN_MILLISECONDS, 0, _phase); + _killSpamFilter = true; + break; + } } } - void SpellHit(Unit* caster, const SpellInfo* spell) + void SpellHit(Unit* caster, SpellInfo const* spell) { if (spell->Id == SPELL_POWER_SPARK_MALYGOS) { @@ -415,346 +666,415 @@ public: Talk(SAY_BUFF_SPARK); } + else if (spell->Id == SPELL_MALYGOS_BERSERK) + sCreatureTextMgr->SendChat(me, EMOTE_HIT_BERSERKER_TIMER, 0, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_MAP); } void MoveInLineOfSight(Unit* who) { - if (!me->isInCombat()) + if (!me->isInCombat() || _phase != PHASE_ONE) return; if (who->GetEntry() == NPC_POWER_SPARK) - { - // not sure about the distance | I think it is better check this here than in the UpdateAI function... if (who->GetDistance(me) <= 2.5f) who->CastSpell(me, SPELL_POWER_SPARK_MALYGOS, true); - } - } - - void PrepareForVortex() - { - me->SetDisableGravity(true); - me->SetCanFly(true); - - me->GetMotionMaster()->MovementExpired(); - me->GetMotionMaster()->MovePoint(MOVE_VORTEX, MalygosPositions[1].GetPositionX(), MalygosPositions[1].GetPositionY(), MalygosPositions[1].GetPositionZ()); - // continues in MovementInform function. - } - - void ExecuteVortex() - { - DoCast(me, SPELL_VORTEX_1, true); - DoCast(me, SPELL_VORTEX_2, true); - - // the vortex execution continues in the dummy effect of this spell (see its script) - DoCast(me, SPELL_VORTEX_3, true); } void MovementInform(uint32 type, uint32 id) { - if (type != POINT_MOTION_TYPE) + if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) return; switch (id) { - case MOVE_VORTEX: + case POINT_NEAR_RANDOM_PORTAL_P_NONE: + if (Creature* portal = me->FindNearestCreature(NPC_PORTAL_TRIGGER, 31.0f, true)) + { + events.ScheduleEvent(EVENT_STOP_PORTAL_BEAM, 10*IN_MILLISECONDS, 1, PHASE_NOT_STARTED); + events.ScheduleEvent(EVENT_RANDOM_PORTAL, 14*IN_MILLISECONDS, 1, PHASE_NOT_STARTED); + DoCast(portal, SPELL_PORTAL_BEAM); + } + break; + case POINT_LAND_P_ONE: + me->SetDisableGravity(false); + break; + case POINT_VORTEX_P_ONE: me->GetMotionMaster()->MoveIdle(); - ExecuteVortex(); + DoAction(ACTION_EXECUTE_VORTEX); break; - case MOVE_DEEP_BREATH_ROTATION: - _currentPos = _currentPos == MALYGOS_MAX_WAYPOINTS - 1 ? 0 : _currentPos+1; - me->GetMotionMaster()->MovementExpired(); - me->GetMotionMaster()->MovePoint(MOVE_DEEP_BREATH_ROTATION, MalygosPhaseTwoWaypoints[_currentPos]); + case POINT_LAND_AFTER_VORTEX_P_ONE: + me->SetDisableGravity(false); + _executingVortex = false; + _canAttack = true; break; - case MOVE_INIT_PHASE_ONE: - me->SetInCombatWithZone(); + case POINT_LIFT_IN_AIR_P_ONE: + me->SetDisableGravity(true); + events.ScheduleEvent(EVENT_MOVE_TO_VORTEX_POINT, 1, 0, PHASE_ONE); break; - case MOVE_CENTER_PLATFORM: - // Malygos is already flying here, there is no need to set it again. - _cannotMove = false; - // malygos will move into center of platform and then he does not chase dragons, he just turns to his current target. - me->GetMotionMaster()->MoveIdle(); + case POINT_FLY_OUT_OF_PLATFORM_P_TWO: + if (!_firstCyclicMovementStarted) + { + _firstCyclicMovementStarted = true; + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetFacingToObject(me->GetMap()->GetCreature(instance->GetData64(DATA_ALEXSTRASZA_BUNNY_GUID))); + events.ScheduleEvent(EVENT_SUMMON_ARCANE_BOMB, 1*IN_MILLISECONDS, 0, PHASE_TWO); + } + _flyingOutOfPlatform = false; + _performingSurgeOfPower = false; + events.ScheduleEvent(EVENT_PATHING_AROUND_PLATFORM, 1*IN_MILLISECONDS, 0, PHASE_TWO); + break; + case POINT_PHASE_ONE_TO_TWO_TRANSITION: + me->SetDisableGravity(true); + me->SetFacingToObject(me->GetMap()->GetCreature(instance->GetData64(DATA_ALEXSTRASZA_BUNNY_GUID))); + SendLightOverride(LIGHT_ARCANE_RUNES, 5*IN_MILLISECONDS); + events.ScheduleEvent(EVENT_FLY_OUT_OF_PLATFORM, 18*IN_MILLISECONDS, 0, PHASE_TWO); + break; + case POINT_SURGE_OF_POWER_P_TWO: + if (!_performingDestroyPlatform) + { + Talk(EMOTE_SURGE_OF_POWER_WARNING_P2); + DoCastAOE(SPELL_SURGE_OF_POWER_P_II, true); + events.ScheduleEvent(EVENT_FLY_OUT_OF_PLATFORM, 7*IN_MILLISECONDS, 0, PHASE_TWO); + } + break; + case POINT_DESTROY_PLATFORM_P_TWO: + SendLightOverride(LIGHT_OBSCURE_SPACE, 1*IN_MILLISECONDS); + DoCast(me, SPELL_DESTROY_PLATFORM_CHANNEL); + events.ScheduleEvent(EVENT_MOVE_TO_P_THREE_POINT, 11*IN_MILLISECONDS, 0, PHASE_TWO); + break; + case POINT_IDLE_P_THREE: + me->SetControlled(true, UNIT_STATE_ROOT); + events.ScheduleEvent(EVENT_START_P_THREE, 5*IN_MILLISECONDS, 0, PHASE_TWO); break; - } - } - - void StartPhaseTwo() - { - SetPhase(PHASE_TWO, true); - - me->SetDisableGravity(true); - me->SetCanFly(true); - - me->GetMotionMaster()->MoveIdle(); - me->GetMotionMaster()->MovePoint(MOVE_DEEP_BREATH_ROTATION, MalygosPhaseTwoWaypoints[0]); - - for (uint8 i = 0; i < 2; i++) - { - // Starting position. One starts from the first waypoint and another from the last. - uint8 pos = !i ? MAX_HOVER_DISK_WAYPOINTS-1 : 0; - if (Creature* summon = me->SummonCreature(NPC_HOVER_DISK_CASTER, HoverDiskWaypoints[pos])) - if (summon->IsAIEnabled) - summon->AI()->DoAction(ACTION_HOVER_DISK_START_WP_1+i); - - // not sure about its position. - if (Creature* summon = me->SummonCreature(NPC_HOVER_DISK_MELEE, HoverDiskWaypoints[0])) - summon->SetInCombatWithZone(); } } void UpdateAI(uint32 diff) { - if (!UpdateVictim()) + if (!UpdateVictim() && _phase != PHASE_NOT_STARTED && _phase != PHASE_TWO) return; events.Update(diff); - if (_phase == PHASE_THREE) - { - if (!_cannotMove) - { - // it can change if the player falls from the vehicle. - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != IDLE_MOTION_TYPE) - { - me->GetMotionMaster()->MovementExpired(); - me->GetMotionMaster()->MoveIdle(); - } - } else - { - if (me->GetMotionMaster()->GetCurrentMovementGeneratorType() != POINT_MOTION_TYPE) - { - me->GetMotionMaster()->MovementExpired(); - me->GetMotionMaster()->MovePoint(MOVE_CENTER_PLATFORM, MalygosPositions[0].GetPositionX(), MalygosPositions[0].GetPositionY(), MalygosPositions[0].GetPositionZ()); - } - } - } + // we can't cast if we are casting already unless in PHASE_NOT_STARTED channeling PORTAL_BEAM + if (me->HasUnitState(UNIT_STATE_CASTING) && _phase != PHASE_NOT_STARTED) + return; - // we need a better way for pathing - if (_delayedMovement) + // at 50% hp Malygos switchs to phase 2 and removes hovering until reset or end of encounter + if (_phase == PHASE_ONE && me->GetHealthPct() <= 50.0f) { - if (_delayedMovementTimer <= diff) - { - me->GetMotionMaster()->MovePoint(MOVE_DEEP_BREATH_ROTATION, MalygosPhaseTwoWaypoints[_currentPos]); - _delayedMovementTimer = 8000; - _delayedMovement = false; - } _delayedMovementTimer -= diff; + SetPhase(PHASE_TWO, true); + _canAttack = false; + me->AttackStop(); + Talk(SAY_END_P_ONE); } - // at 50 % health malygos switch to phase 2 - if (me->GetHealthPct() <= 50.0f && _phase == PHASE_ONE) - StartPhaseTwo(); - - // the boss is handling vortex - if (me->HasAura(SPELL_VORTEX_2)) - return; - - // We can't cast if we are casting already. - if (me->HasUnitState(UNIT_STATE_CASTING)) - return; - while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) { - case EVENT_YELL_2: - Talk(SAY_END_P_TWO); - break; - case EVENT_YELL_3: - Talk(SAY_INTRO_P_THREE); + case EVENT_START_FIRST_RANDOM_PORTAL: + me->CastCustomSpell(SPELL_RANDOM_PORTAL, SPELLVALUE_MAX_TARGETS, 1); break; - case EVENT_YELL_4: - Talk(SAY_AGGRO_P_THREE); + case EVENT_STOP_PORTAL_BEAM: + me->InterruptNonMeleeSpells(true); break; - case EVENT_YELL_0: - Talk(SAY_END_P_ONE); + case EVENT_RANDOM_PORTAL: + me->CastCustomSpell(SPELL_RANDOM_PORTAL, SPELLVALUE_MAX_TARGETS, 1); break; - case EVENT_YELL_1: - Talk(SAY_AGGRO_P_TWO); - break; - case EVENT_ARCANE_BREATH: - DoCast(me->getVictim(), SPELL_ARCANE_BREATH); - events.ScheduleEvent(EVENT_ARCANE_BREATH, urand(35, 60)*IN_MILLISECONDS, 0, PHASE_ONE); + case EVENT_LAND_START_ENCOUNTER: + if (GameObject* iris = me->GetMap()->GetGameObject(instance->GetData64(DATA_FOCUSING_IRIS_GUID))) + { + me->SetFacingToObject(iris); + iris->Delete(); // this is not the best way. + } + _canAttack = true; + SetPhase(PHASE_ONE, true); break; - case EVENT_ARCANE_STORM: - DoCast(me->getVictim(), SPELL_ARCANE_STORM); - events.ScheduleEvent(EVENT_ARCANE_STORM, urand(5, 10)*IN_MILLISECONDS, 0, PHASE_ONE); + case EVENT_SAY_INTRO: + Talk(SAY_INTRO_EVENT); + events.ScheduleEvent(EVENT_SAY_INTRO, urand(85, 95)*IN_MILLISECONDS, 1, PHASE_NOT_STARTED); break; case EVENT_VORTEX: - PrepareForVortex(); + _executingVortex = true; + DoAction(ACTION_LIFT_IN_AIR); events.ScheduleEvent(EVENT_VORTEX, urand(60, 80)*IN_MILLISECONDS, 0, PHASE_ONE); break; + case EVENT_MOVE_TO_VORTEX_POINT: + _canAttack = false; + me->AttackStop(); + me->GetMotionMaster()->MovePoint(POINT_VORTEX_P_ONE, MalygosPositions[1]); + break; case EVENT_POWER_SPARKS: instance->SetData(DATA_POWER_SPARKS_HANDLING, 0); events.ScheduleEvent(EVENT_POWER_SPARKS, urand(30, 35)*IN_MILLISECONDS, 0, PHASE_ONE); break; - case EVENT_SURGE_POWER: - me->GetMotionMaster()->MoveIdle(); - _delayedMovement = true; - DoCast(SPELL_SURGE_POWER); - events.ScheduleEvent(EVENT_SURGE_POWER, urand(60, 70)*IN_MILLISECONDS, 0, PHASE_TWO); + case EVENT_ARCANE_BREATH: + if (_executingVortex) + { + events.ScheduleEvent(EVENT_ARCANE_BREATH, 20*IN_MILLISECONDS, 0, PHASE_ONE); + break; + } + + me->CastSpell(me->getVictim(), SPELL_ARCANE_BREATH); + events.ScheduleEvent(EVENT_ARCANE_BREATH, 20*IN_MILLISECONDS, 0, PHASE_ONE); break; - case EVENT_SUMMON_ARCANE: - DoCast(SPELL_SUMMON_ARCANE_BOMB); - events.ScheduleEvent(EVENT_SUMMON_ARCANE, urand(12, 15)*IN_MILLISECONDS, 0, PHASE_TWO); + case EVENT_ARCANE_STORM: + if (_phase == PHASE_ONE) + { + if (_executingVortex) + { + events.ScheduleEvent(EVENT_ARCANE_STORM, 10*IN_MILLISECONDS, 0, PHASE_ONE); + break; + } + + DoCast(me, SPELL_ARCANE_STORM_P_I, true); + events.ScheduleEvent(EVENT_ARCANE_STORM, 10*IN_MILLISECONDS, 0, PHASE_ONE); + } + else if (_phase == PHASE_THREE) + { + DoCast(me, SPELL_ARCANE_STORM_P_III, true); + events.ScheduleEvent(EVENT_ARCANE_STORM, urand(6, 12)*IN_MILLISECONDS, 0, PHASE_THREE); + } break; - case EVENT_SURGE_POWER_PHASE_3: - DoCast(GetTargetPhaseThree(), SPELL_SURGE_POWER_PHASE_3); - events.ScheduleEvent(EVENT_SURGE_POWER_PHASE_3, urand(7, 16)*IN_MILLISECONDS, 0, PHASE_THREE); + case EVENT_FLY_OUT_OF_PLATFORM: + if (Creature* alexstraszaBunny = me->GetMap()->GetCreature(instance->GetData64(DATA_ALEXSTRASZA_BUNNY_GUID))) + { + Position randomPosOnRadius; + // Hardcodded retail value, reason is Z getters can fail... (TO DO: Change to getter when height calculation works on 100%!) + randomPosOnRadius.m_positionZ = 283.0521f; + alexstraszaBunny->GetNearPoint2D(randomPosOnRadius.m_positionX, randomPosOnRadius.m_positionY, 130.0f, alexstraszaBunny->GetAngle(me)); + me->GetMotionMaster()->MovePoint(POINT_FLY_OUT_OF_PLATFORM_P_TWO, randomPosOnRadius); + _flyingOutOfPlatform = true; + } + + if (_arcaneReinforcements && instance) + { + for (uint8 rangeDisks = 0; rangeDisks < (GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL ? 4 : 5); rangeDisks++) + { + Creature* casterDiskSummon = me->SummonCreature(NPC_HOVER_DISK_CASTER, RangeHoverDisksSpawnPositions[rangeDisks]); + + if (casterDiskSummon->IsAIEnabled) + casterDiskSummon->AI()->DoAction(rangeDisks); + } + + for (uint8 meleeDisks = 0; meleeDisks < 2; meleeDisks++) + { + Creature* meleeDiskSummon = me->SummonCreature(NPC_HOVER_DISK_MELEE, MeleeHoverDisksSpawnPositions[meleeDisks]); + meleeDiskSummon->GetMotionMaster()->MovePoint(meleeDisks * MAX_MELEE_HOVER_DISK_SPAWNPOINTS, MeleeHoverDisksWaypoints[meleeDisks * MAX_MELEE_HOVER_DISK_SPAWNPOINTS]); + } + + _arcaneReinforcements = false; + + if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + events.ScheduleEvent(EVENT_DELAYED_REINFORCEMENTS, 1*IN_MILLISECONDS, 0, PHASE_TWO); + } + break; + case EVENT_DELAYED_REINFORCEMENTS: + for (uint8 rangeDisks = 5; rangeDisks < 8; rangeDisks++) + { + Creature* casterDiskSummon = me->SummonCreature(NPC_HOVER_DISK_CASTER, RangeHoverDisksSpawnPositions[rangeDisks]); + + if (casterDiskSummon->IsAIEnabled) + casterDiskSummon->AI()->DoAction(rangeDisks); + } + + for (uint8 meleeDisks = 2; meleeDisks < 4; meleeDisks++) + { + Creature* meleeDiskSummon = me->SummonCreature(NPC_HOVER_DISK_MELEE, MeleeHoverDisksSpawnPositions[meleeDisks]); + meleeDiskSummon->GetMotionMaster()->MovePoint(meleeDisks * MAX_MELEE_HOVER_DISK_SPAWNPOINTS, MeleeHoverDisksWaypoints[meleeDisks * MAX_MELEE_HOVER_DISK_SPAWNPOINTS]); + } + break; + case EVENT_PATHING_AROUND_PLATFORM: + DoAction(ACTION_CYCLIC_MOVEMENT); + break; + case EVENT_MOVE_TO_POINT_SURGE_P_TWO: + if (!_performingDestroyPlatform) + { + _performingSurgeOfPower = true; + Talk(SAY_DEEP_BREATH); + me->GetMotionMaster()->MovePoint(POINT_SURGE_OF_POWER_P_TWO, MalygosPositions[3]); + events.ScheduleEvent(EVENT_MOVE_TO_POINT_SURGE_P_TWO, 60*IN_MILLISECONDS, 2, PHASE_TWO); + } + break; + case EVENT_SUMMON_ARCANE_BOMB: + if (!_performingSurgeOfPower && !_performingDestroyPlatform) + { + me->StopMoving(); + events.ScheduleEvent(EVENT_PATHING_AROUND_PLATFORM, 3*IN_MILLISECONDS, 0, PHASE_TWO); + } + + if (!_flyingOutOfPlatform) + { + DoCast(me, SPELL_SUMMON_ARCANE_BOMB, true); + if (Creature* lastArcaneOverloadBunny = me->GetMap()->GetCreature(_arcaneOverloadGUID)) + DoCast(lastArcaneOverloadBunny, SPELL_ARCANE_BOMB_TRIGGER, true); + } + events.ScheduleEvent(EVENT_SUMMON_ARCANE_BOMB, urand(15, 16)*IN_MILLISECONDS, 2, PHASE_TWO); + break; + case EVENT_ARCANE_PULSE: + if (_preparingPulsesChecker < 2) + { + DoCastAOE(SPELL_ARCANE_PULSE, true); + events.ScheduleEvent(EVENT_ARCANE_PULSE, 7*IN_MILLISECONDS, 0, PHASE_THREE); + _preparingPulsesChecker++; + } + else + { + DoCastAOE(SPELL_ARCANE_PULSE, true); + events.ScheduleEvent(EVENT_ARCANE_PULSE, 2*IN_MILLISECONDS, 0, PHASE_THREE); + } + break; + case EVENT_LIGHT_DIMENSION_CHANGE: + SendLightOverride(LIGHT_CHANGE_DIMENSIONS, 2*IN_MILLISECONDS); + break; + case EVENT_MOVE_TO_P_THREE_POINT: + Talk(SAY_START_P_THREE); + me->GetMotionMaster()->MovePoint(POINT_IDLE_P_THREE, MalygosPositions[4]); + break; + case EVENT_START_P_THREE: + SendLightOverride(LIGHT_OBSCURE_ARCANE_RUNES, 1*IN_MILLISECONDS); + DoCast(me, SPELL_CLEAR_ALL_DEBUFFS); + DoCast(me, SPELL_IMMUNE_CURSES); + _canAttack = true; + UpdateVictim(); + me->SetFacingToObject(me->getVictim()); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + SetPhase(PHASE_THREE, true); + break; + case EVENT_SURGE_OF_POWER_P_THREE: + if (GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + { + _tempSurgeTarget = NULL; + _drakeVehicle = NULL; + _playerSurgeTarget = NULL; + if ((_tempSurgeTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, false, SPELL_RIDE_RED_DRAGON_BUDDY))) + if ((_drakeVehicle = _tempSurgeTarget->GetVehicleKit())) + if ((_playerSurgeTarget = _drakeVehicle->GetPassenger(0)->ToPlayer())) + { + Talk(EMOTE_SURGE_OF_POWER_WARNING_P3, _playerSurgeTarget->GetGUID()); + DoCast(_tempSurgeTarget, SPELL_SURGE_OF_POWER_PHASE_3_10); + } + } + else if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + { + _firstSelectedSurgeTargetGUID = NULL; + _secondSelectedSurgeTargetGUID = NULL; + _thirdSelectedSurgeTargetGUID = NULL; + DoCastAOE(SPELL_SURGE_OF_POWER_WARNING_SELECTOR_25); + } + + events.ScheduleEvent(EVENT_SURGE_OF_POWER_P_THREE, urand(9, 18)*IN_MILLISECONDS, 0, PHASE_THREE); break; case EVENT_STATIC_FIELD: - DoCast(GetTargetPhaseThree(), SPELL_STATIC_FIELD); - events.ScheduleEvent(EVENT_STATIC_FIELD, urand(20, 30)*IN_MILLISECONDS, 0, PHASE_THREE); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 60.0f, false, SPELL_RIDE_RED_DRAGON_BUDDY)) + DoCast(target, SPELL_STATIC_FIELD_MISSLE); + + events.ScheduleEvent(EVENT_STATIC_FIELD, urand(15, 30)*IN_MILLISECONDS, 0, PHASE_THREE); + break; + case EVENT_PREVENT_SAY_SPAM_ON_KILL: + _killSpamFilter = false; break; default: break; } } - DoMeleeAttackIfReady(); + if (_phase != PHASE_THREE) + DoMeleeAttackIfReady(); } - Unit* GetTargetPhaseThree() + void JustDied(Unit* /*killer*/) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - - // we are a drake - if (target->GetVehicleKit()) - return target; - - // we are a player using a drake (or at least you should) - if (target->GetTypeId() == TYPEID_PLAYER) + _JustDied(); + Talk(SAY_DEATH); + if (Creature* alexstraszaGiftBoxBunny = me->GetMap()->GetCreature(instance->GetData64(DATA_GIFT_BOX_BUNNY_GUID))) { - if (Unit* base = target->GetVehicleBase()) - return base; + if (GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + alexstraszaGiftBoxBunny->SummonGameObject(GO_HEART_OF_MAGIC_10, HeartOfMagicSpawnPos.GetPositionX(), HeartOfMagicSpawnPos.GetPositionY(), + HeartOfMagicSpawnPos.GetPositionZ(), HeartOfMagicSpawnPos.GetOrientation(), 0.0f, 0.0f, 0.0f, 1.0f, 0); + else if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + alexstraszaGiftBoxBunny->SummonGameObject(GO_HEART_OF_MAGIC_25, HeartOfMagicSpawnPos.GetPositionX(), HeartOfMagicSpawnPos.GetPositionY(), + HeartOfMagicSpawnPos.GetPositionZ(), HeartOfMagicSpawnPos.GetOrientation(), 0.0f, 0.0f, 0.0f, 1.0f, 0); } - // is a player falling from a vehicle? - return NULL; - } - - void JustDied(Unit* /*killer*/) - { - Talk(SAY_DEATH); - _JustDied(); + me->SummonCreature(NPC_ALEXSTRASZA, AlexstraszaSpawnPos, TEMPSUMMON_MANUAL_DESPAWN); + me->DespawnOrUnsummon(5*IN_MILLISECONDS); } private: - uint8 _phase; - uint32 _bersekerTimer; - uint8 _currentPos; // used for phase 2 rotation... - bool _delayedMovement; // used in phase 2. - uint32 _delayedMovementTimer; // used in phase 2 - uint8 _summonDeaths; - Position _homePosition; // it can get bugged because core thinks we are pathing - bool _mustTalk; - bool _cannotMove; - }; -}; - -class spell_malygos_vortex_dummy : public SpellScriptLoader -{ -public: - spell_malygos_vortex_dummy() : SpellScriptLoader("spell_malygos_vortex_dummy") {} - - class spell_malygos_vortex_dummy_SpellScript : public SpellScript - { - PrepareSpellScript(spell_malygos_vortex_dummy_SpellScript) - - void HandleScript(SpellEffIndex /*effIndex*/) + // Used to generate perfect cyclic movements (Enter Circle). + void FillCirclePath(Position const& centerPos, float radius, float z, Movement::PointsArray& path, bool clockwise) { - Unit* caster = GetCaster(); + float step = clockwise ? -M_PI / 8.0f : M_PI / 8.0f; + float angle = centerPos.GetAngle(me->GetPositionX(), me->GetPositionY()); - if (!caster) - return; - - // each player will enter to the trigger vehicle (entry 30090) already spawned (each one can hold up to 5 players, it has 5 seats) - // the players enter to the vehicles casting SPELL_VORTEX_4 OR SPELL_VORTEX_5 - if (InstanceScript* instance = caster->GetInstanceScript()) - instance->SetData(DATA_VORTEX_HANDLING, 0); + for (uint8 i = 0; i < 16; angle += step, ++i) + { + G3D::Vector3 point; + point.x = centerPos.GetPositionX() + radius * cosf(angle); + point.y = centerPos.GetPositionY() + radius * sinf(angle); + point.z = z; // Don't use any height getters unless all bugs are fixed. + path.push_back(point); + } + } - // the rest of the vortex execution continues when SPELL_VORTEX_2 is removed. + // Function that will change lights of map for all players on map. + void SendLightOverride(uint32 overrideId, uint32 fadeInTime) const + { + WorldPacket data(SMSG_OVERRIDE_LIGHT, 12); + data << uint32(1773); // Light.dbc entry (map default) + data << uint32(overrideId); // Light.dbc entry (override) + data << uint32(fadeInTime); + SendPacketToPlayers(&data); } - void Register() + // Send packet to all players in Eye of Eternity + void SendPacketToPlayers(WorldPacket const* data) const { - OnEffectHitTarget += SpellEffectFn(spell_malygos_vortex_dummy_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + Map::PlayerList const& players = me->GetMap()->GetPlayers(); + if (!players.isEmpty()) + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + if (Player* player = itr->getSource()) + if (player->GetAreaId() == AREA_EYE_OF_ETERNITY) + player->GetSession()->SendPacket(data); } + + uint8 _phase; // Counter for phases used with a getter. + uint8 _summonDeaths; // Keeps count of arcane trash. + uint8 _preparingPulsesChecker; // In retail they use 2 preparing pulses with 7 sec CD, after they pass 2 seconds. + uint64 _arcaneOverloadGUID; // Last Arcane Overload summoned to know to which should visual be cast to (the purple ball, not bubble). + uint64 _firstSelectedSurgeTargetGUID; // All these three are used to keep current tagets to which warning should be sent + uint64 _secondSelectedSurgeTargetGUID; // during Surge of Power 25 man, also they act as sent targets because of that mechanic. + uint64 _thirdSelectedSurgeTargetGUID; + + Unit* _tempSurgeTarget; // These three are used for 10 man Surge of Power targeting. + Vehicle* _drakeVehicle; + Player* _playerSurgeTarget; + + bool _killSpamFilter; // Prevent text spamming on killed player by helping implement a CD. + bool _canAttack; // Used to control attacking (Move Chase not being applied after Stop Attack, only few times should act like this). + bool _despawned; // Checks if boss pass through evade on reset. + bool _executingVortex; // Prevents some events being sheduled during Vortex takeoff/land. + bool _arcaneReinforcements; // Checks if 10 or 25 man arcane trash will be spawned. + bool _flyingOutOfPlatform; // Used to prevent Malygos casting Arcane Overload shields while leaving platform. + bool _firstCyclicMovementStarted; // At first movement start he throws one shield asap, so this check is needed for it only. + bool _performingSurgeOfPower; // Used to prevent starting Cyclic Movement called in Arcane Bomb event. + bool _performingDestroyPlatform; // Used to prevent starting some movements right when Destroy Platfrom event starts. + + float _flySpeed; // Used to store base fly speed to prevent stacking on each evade. }; - SpellScript* GetSpellScript() const + CreatureAI* GetAI(Creature* creature) const { - return new spell_malygos_vortex_dummy_SpellScript(); + return new boss_malygosAI(creature); } }; -class spell_malygos_vortex_visual : public SpellScriptLoader -{ - public: - spell_malygos_vortex_visual() : SpellScriptLoader("spell_malygos_vortex_visual") { } - - class spell_malygos_vortex_visual_AuraScript : public AuraScript - { - PrepareAuraScript(spell_malygos_vortex_visual_AuraScript); - - void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) - { - if (Unit* caster = GetCaster()) - { - ThreatContainer::StorageType const& m_threatlist = caster->getThreatManager().getThreatList(); - for (ThreatContainer::StorageType::const_iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) - { - if (Unit* target = (*itr)->getTarget()) - { - Player* targetPlayer = target->ToPlayer(); - - if (!targetPlayer || targetPlayer->isGameMaster()) - continue; - - if (InstanceScript* instance = caster->GetInstanceScript()) - { - // teleport spell - i am not sure but might be it must be casted by each vehicle when its passenger leaves it - if (Creature* trigger = caster->GetMap()->GetCreature(instance->GetData64(DATA_TRIGGER))) - trigger->CastSpell(targetPlayer, SPELL_VORTEX_6, true); - } - } - } - - if (Creature* malygos = caster->ToCreature()) - { - // This is a hack, we have to re add players to the threat list because when they enter to the vehicles they are removed. - // Anyway even with this issue, the boss does not enter in evade mode - this prevents iterate an empty list in the next vortex execution. - malygos->SetInCombatWithZone(); - - malygos->SetDisableGravity(false); - malygos->SetCanFly(false); - - malygos->GetMotionMaster()->MoveChase(caster->getVictim()); - malygos->RemoveAura(SPELL_VORTEX_1); - } - } - - } - - void Register() - { - AfterEffectRemove += AuraEffectRemoveFn(spell_malygos_vortex_visual_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_malygos_vortex_visual_AuraScript(); - } -}; - class npc_portal_eoe: public CreatureScript { public: - npc_portal_eoe() : CreatureScript("npc_portal_eoe") {} - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_portal_eoeAI(creature); - } + npc_portal_eoe() : CreatureScript("npc_portal_eoe") { } struct npc_portal_eoeAI : public ScriptedAI { @@ -763,27 +1083,29 @@ public: _instance = creature->GetInstanceScript(); } - void SpellHit(Unit* /*caster*/, const SpellInfo* spell) + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) { if (spell->Id == SPELL_PORTAL_OPENED) { - DoCast(me, SPELL_SUMMON_POWER_PARK, true); + if (Creature* malygos = me->GetMap()->GetCreature(_instance->GetData64(DATA_MALYGOS))) + { + if (malygos->AI()->GetData(DATA_PHASE) == PHASE_ONE) + DoCast(me, SPELL_SUMMON_POWER_PARK, true); + } } } void UpdateAI(uint32 /*diff*/) { - // When duration of oppened riff visual ends, - // closed one should be cast - if (!me->HasAura(SPELL_PORTAL_VISUAL_CLOSED) && - !me->HasAura(SPELL_PORTAL_OPENED)) + // When duration of opened riff visual ends, closed one should be cast + if (!me->HasAura(SPELL_PORTAL_VISUAL_CLOSED) && !me->HasAura(SPELL_PORTAL_OPENED)) DoCast(me, SPELL_PORTAL_VISUAL_CLOSED, true); if (_instance) { - if (Creature* malygos = Unit::GetCreature(*me, _instance->GetData64(DATA_MALYGOS))) + if (Creature* malygos = me->GetMap()->GetCreature(_instance->GetData64(DATA_MALYGOS))) { - if (malygos->AI()->GetData(DATA_PHASE) != PHASE_ONE) + if (malygos->AI()->GetData(DATA_PHASE) != PHASE_ONE && me->HasAura(SPELL_PORTAL_OPENED)) { me->RemoveAura(SPELL_PORTAL_OPENED); DoCast(me, SPELL_PORTAL_VISUAL_CLOSED, true); @@ -792,42 +1114,29 @@ public: } } - void JustSummoned(Creature* summon) - { - summon->SetInCombatWithZone(); - } - private: - uint32 _summonTimer; InstanceScript* _instance; }; -}; + CreatureAI* GetAI(Creature* creature) const + { + return new npc_portal_eoeAI(creature); + } +}; class npc_power_spark: public CreatureScript { public: - npc_power_spark() : CreatureScript("npc_power_spark") {} - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_power_sparkAI(creature); - } + npc_power_spark() : CreatureScript("npc_power_spark") { } struct npc_power_sparkAI : public ScriptedAI { npc_power_sparkAI(Creature* creature) : ScriptedAI(creature) { _instance = creature->GetInstanceScript(); - - MoveToMalygos(); // Talk range was not enough for this encounter sCreatureTextMgr->SendChat(me, EMOTE_POWER_SPARK_SUMMONED, 0, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_MAP); - } - - void EnterEvadeMode() - { - me->DespawnOrUnsummon(); + MoveToMalygos(); } void MoveToMalygos() @@ -835,10 +1144,8 @@ public: me->GetMotionMaster()->MoveIdle(); if (_instance) - { - if (Creature* malygos = Unit::GetCreature(*me, _instance->GetData64(DATA_MALYGOS))) + if (Creature* malygos = me->GetMap()->GetCreature(_instance->GetData64(DATA_MALYGOS))) me->GetMotionMaster()->MoveFollow(malygos, 0.0f, 0.0f); - } } void UpdateAI(uint32 /*diff*/) @@ -846,9 +1153,9 @@ public: if (!_instance) return; - if (Creature* malygos = Unit::GetCreature(*me, _instance->GetData64(DATA_MALYGOS))) + if (Creature* malygos = me->GetMap()->GetCreature(_instance->GetData64(DATA_MALYGOS))) { - if (malygos->AI()->GetData(DATA_PHASE) != PHASE_ONE) + if (malygos->AI()->GetData(DATA_PHASE) != PHASE_ONE || _instance->GetBossState(DATA_MALYGOS_EVENT) == FAIL) { me->DespawnOrUnsummon(); return; @@ -873,28 +1180,33 @@ public: private: InstanceScript* _instance; }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_power_sparkAI(creature); + } }; -class npc_hover_disk : public CreatureScript +class npc_melee_hover_disk : public CreatureScript { public: - npc_hover_disk() : CreatureScript("npc_hover_disk") { } + npc_melee_hover_disk() : CreatureScript("npc_melee_hover_disk") { } - CreatureAI* GetAI(Creature* creature) const + struct npc_melee_hover_diskAI : public VehicleAI { - return new npc_hover_diskAI(creature); - } + npc_melee_hover_diskAI(Creature* creature) : VehicleAI(creature) + { + _instance = creature->GetInstanceScript(); + me->SetReactState(REACT_PASSIVE); + // TO DO: These were a bit faster than what they should be. Not sure what is the reason. + me->SetSpeed(MOVE_FLIGHT, 1.25f); + } - struct npc_hover_diskAI : public npc_escortAI - { - npc_hover_diskAI(Creature* creature) : npc_escortAI(creature) + void Reset() { - if (me->GetEntry() == NPC_HOVER_DISK_CASTER) - me->SetReactState(REACT_PASSIVE); - else - me->SetInCombatWithZone(); + VehicleAI::Reset(); - _instance = creature->GetInstanceScript(); + _wpCount = 0; } void PassengerBoarded(Unit* unit, int8 /*seat*/, bool apply) @@ -903,208 +1215,1284 @@ public: { if (unit->GetTypeId() == TYPEID_UNIT) { - me->setFaction(FACTION_HOSTILE); + unit->CastSpell(unit, SPELL_TELEPORT_VISUAL_ONLY); unit->ToCreature()->SetInCombatWithZone(); } + else if (unit->GetTypeId() == TYPEID_PLAYER) + me->SetDisableGravity(true); } - else + else if (!apply) { - // Error found: This is not called if the passenger is a player - if (unit->GetTypeId() == TYPEID_UNIT || unit->GetTypeId() == TYPEID_PLAYER) + if (unit->GetTypeId() != TYPEID_PLAYER) { - // This will only be called if the passenger dies - if (_instance) - { - if (Creature* malygos = Unit::GetCreature(*me, _instance->GetData64(DATA_MALYGOS))) - malygos->AI()->SetData(DATA_SUMMON_DEATHS, malygos->AI()->GetData(DATA_SUMMON_DEATHS)+1); - } + me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetDisableGravity(false); + me->SetCanFly(false); } - - me->GetMotionMaster()->MoveIdle(); - - if (me->GetEntry() == NPC_HOVER_DISK_MELEE || me->GetEntry() == NPC_HOVER_DISK_CASTER) + else if (unit->GetTypeId() == TYPEID_PLAYER) { - // Hack: Fall ground function can fail (remember the platform is a gameobject), we will teleport the disk to the ground - if (me->GetPositionZ() > GROUND_Z) - me->NearTeleportTo(me->GetPositionX(), me->GetPositionY(), GROUND_Z, 0); - me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); - me->setFaction(FACTION_FRIENDLY); - me->AI()->EnterEvadeMode(); + me->SetDisableGravity(false); + me->SetCanFly(false); } + + me->setFaction(FACTION_FRIENDLY); + me->RemoveAllAuras(); } } - void EnterEvadeMode() + void UpdateAI(uint32 diff) { - // we dont evade + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + me->GetMotionMaster()->MovePoint(eventId, MeleeHoverDisksWaypoints[eventId]); } - void DoAction(int32 action) + void DoAction(int32 /*action*/) { - if (me->GetEntry() != NPC_HOVER_DISK_CASTER) + if (Vehicle* vehicleTemp = me->GetVehicleKit()) + if (vehicleTemp->GetPassenger(0) && vehicleTemp->GetPassenger(0)->GetTypeId() == TYPEID_PLAYER) + { + vehicleTemp->RemoveAllPassengers(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + } + + me->DespawnOrUnsummon(3*IN_MILLISECONDS); + } + + void MovementInform(uint32 type, uint32 id) + { + if (type != POINT_MOTION_TYPE) return; - switch (action) + if (_wpCount < 3) { - case ACTION_HOVER_DISK_START_WP_1: - for (uint8 i = 0; i < MAX_HOVER_DISK_WAYPOINTS; i++) - AddWaypoint(i, HoverDiskWaypoints[i].GetPositionX(), HoverDiskWaypoints[i].GetPositionY(), HoverDiskWaypoints[i].GetPositionZ()); - break; - case ACTION_HOVER_DISK_START_WP_2: - { - uint8 count = 0; - for (uint8 i = MAX_HOVER_DISK_WAYPOINTS-1; i > 0; i--) - { - AddWaypoint(count, HoverDiskWaypoints[i].GetPositionX(), HoverDiskWaypoints[i].GetPositionY(), HoverDiskWaypoints[i].GetPositionZ()); - count++; - } - break; - } - default: - return; + _events.ScheduleEvent(id + 1, 1); + ++_wpCount; } + else if (Vehicle* hoverDisk = me->GetVehicleKit()) + if (Unit* lordPassenger = hoverDisk->GetPassenger(0)) + lordPassenger->ToCreature()->AI()->DoAction(ACTION_SET_DISK_VICTIM_CHASE); + } + + private: + uint8 _wpCount; // how many points are triggered + InstanceScript* _instance; + EventMap _events; + }; - Start(true, false, 0, 0, false, true); + CreatureAI* GetAI(Creature* creature) const + { + return new npc_melee_hover_diskAI(creature); + } +}; + +class npc_caster_hover_disk : public CreatureScript +{ +public: + npc_caster_hover_disk() : CreatureScript("npc_caster_hover_disk") { } + + struct npc_caster_hover_diskAI : public VehicleAI + { + npc_caster_hover_diskAI(Creature* creature) : VehicleAI(creature) + { + _instance = creature->GetInstanceScript(); + me->SetReactState(REACT_PASSIVE); + // TO DO: Something is wrong with calculations for flying creatures that are on WP/Cyclic path. + // They should get the same difference as to when at ground from run creature switch to walk. + me->SetSpeed(MOVE_FLIGHT, 0.45f); } - void UpdateEscortAI(const uint32 /*diff*/) + void Reset() { - // we dont do melee damage! + VehicleAI::Reset(); } - void WaypointReached(uint32 /*waypointId*/) + void EnterEvadeMode() { + } + + void PassengerBoarded(Unit* unit, int8 /*seat*/, bool apply) + { + if (apply) + { + if (unit->GetTypeId() == TYPEID_UNIT) + unit->CastSpell(unit, SPELL_TELEPORT_VISUAL_ONLY); + } + else if (!apply) + { + me->StopMoving(); + me->SetDisableGravity(false); + me->SetCanFly(false); + me->RemoveAllAuras(); + } + } + void DoAction(int32 action) + { + if (action < ACTION_DELAYED_DESPAWN) + { + Movement::MoveSplineInit init(me); + FillCirclePath(MalygosPositions[3], 35.0f, 282.3402f, init.Path(), true); + init.SetFly(); + init.SetCyclic(); + init.Launch(); + } + else + { + me->DespawnOrUnsummon(3*IN_MILLISECONDS); + } } private: + void FillCirclePath(Position const& centerPos, float radius, float z, Movement::PointsArray& path, bool clockwise) + { + float step = clockwise ? -M_PI / 9.0f : M_PI / 9.0f; + float angle = centerPos.GetAngle(me->GetPositionX(), me->GetPositionY()); + + for (uint8 i = 0; i < 18; angle += step, ++i) + { + G3D::Vector3 point; + point.x = centerPos.GetPositionX() + radius * cosf(angle); + point.y = centerPos.GetPositionY() + radius * sinf(angle); + point.z = z; // Don't use any height getters unless all bugs are fixed. + path.push_back(point); + } + } + InstanceScript* _instance; }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_caster_hover_diskAI(creature); + } }; +class npc_nexus_lord : public CreatureScript +{ + public: + npc_nexus_lord() : CreatureScript("npc_nexus_lord") { } + + struct npc_nexus_lordAI : public ScriptedAI + { + npc_nexus_lordAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + } + + void Reset() + { + _events.Reset(); + } + + void EnterEvadeMode() + { + } + + void IsSummonedBy(Unit* /*summoner*/) + { + _events.ScheduleEvent(EVENT_ARCANE_SHOCK, 2*IN_MILLISECONDS); + _events.ScheduleEvent(EVENT_HASTE_BUFF, 12*IN_MILLISECONDS); + } + + void DoAction(int32 /*action*/) + { + _events.ScheduleEvent(EVENT_NUKE_DUMMY, 1); + } + + void UpdateAI(uint32 diff) + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ARCANE_SHOCK: + DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, 5.0f, true), SPELL_ARCANE_SHOCK); + _events.ScheduleEvent(EVENT_ARCANE_SHOCK, 3*IN_MILLISECONDS); + break; + case EVENT_HASTE_BUFF: + DoCast(me, SPELL_HASTE); + _events.ScheduleEvent(EVENT_HASTE_BUFF, 15*IN_MILLISECONDS); + break; + case EVENT_NUKE_DUMMY: + DoCast(me->getVictim(), SPELL_DUMMY_NUKE, true); + DoCast(me, SPELL_ALIGN_DISK_AGGRO, true); + _events.ScheduleEvent(EVENT_NUKE_DUMMY, 1*IN_MILLISECONDS); + break; + } + } + + DoMeleeAttackIfReady(); + } + + void JustDied(Unit* /*killer*/) + { + if (Creature* malygos = me->GetMap()->GetCreature(_instance->GetData64(DATA_MALYGOS))) + malygos->AI()->SetData(DATA_SUMMON_DEATHS, malygos->AI()->GetData(DATA_SUMMON_DEATHS) + 1); + } + + private: + InstanceScript* _instance; + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_nexus_lordAI(creature); + } +}; + +class npc_scion_of_eternity : public CreatureScript +{ + public: + npc_scion_of_eternity() : CreatureScript("npc_scion_of_eternity") { } + + struct npc_scion_of_eternityAI : public ScriptedAI + { + npc_scion_of_eternityAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + } + + void Reset() + { + _events.Reset(); + } + + void IsSummonedBy(Unit* /*summoner*/) + { + _events.SetPhase(PHASE_TWO); + _events.ScheduleEvent(EVENT_ARCANE_BARRAGE, urand(14, 17)*IN_MILLISECONDS, 0, PHASE_TWO); + } + + void EnterCombat(Unit* /*who*/) + { + } + + void AttackStart(Unit* /*target*/) + { + } + + void EnterEvadeMode() + { + } + + void UpdateAI(uint32 diff) + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ARCANE_BARRAGE: + DoCast(me, SPELL_ARCANE_BARRAGE); + _events.ScheduleEvent(EVENT_ARCANE_BARRAGE, urand(4, 12)*IN_MILLISECONDS, 0, PHASE_TWO); + break; + } + } + } + + void JustDied(Unit* /*killer*/) + { + if (Creature* malygos = me->GetMap()->GetCreature(_instance->GetData64(DATA_MALYGOS))) + malygos->AI()->SetData(DATA_SUMMON_DEATHS, malygos->AI()->GetData(DATA_SUMMON_DEATHS) + 1); + } + + private: + InstanceScript* _instance; + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_scion_of_eternityAI(creature); + } +}; -// The reason of this AI is to make the creature able to enter in combat otherwise the spell casting of SPELL_ARCANE_OVERLOAD fails. class npc_arcane_overload : public CreatureScript { public: - npc_arcane_overload() : CreatureScript("npc_arcane_overload") {} - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_arcane_overloadAI (creature); - } + npc_arcane_overload() : CreatureScript("npc_arcane_overload") { } struct npc_arcane_overloadAI : public ScriptedAI { - npc_arcane_overloadAI(Creature* creature) : ScriptedAI(creature) {} + npc_arcane_overloadAI(Creature* creature) : ScriptedAI(creature) + { + _instance = creature->GetInstanceScript(); + me->SetReactState(REACT_PASSIVE); + } - void AttackStart(Unit* who) + void IsSummonedBy(Unit* summoner) { - DoStartNoMovement(who); + if ((_malygos = summoner->ToCreature())) + _malygos->AI()->SetGUID(me->GetGUID(), DATA_LAST_OVERLOAD_GUID); } - void Reset() + void UpdateAI (uint32 /*diff*/) { - DoCast(me, SPELL_ARCANE_OVERLOAD, false); } - void UpdateAI(uint32 /*diff*/) + void DoAction(int32 /*action*/) { - // we dont do melee damage! + if (Creature* malygos = me->GetMap()->GetCreature(_instance->GetData64(DATA_MALYGOS))) + { + if (malygos->AI()->GetData(DATA_PHASE) == PHASE_TWO) + me->DespawnOrUnsummon(6*IN_MILLISECONDS); + // If evade is hit during phase II shields should disappear with no delay + else if (malygos->AI()->GetData(DATA_PHASE) == 0) + me->DespawnOrUnsummon(); + } + } + + void SpellHit(Unit* /*caster*/, SpellInfo const* spell) + { + if (spell->Id == SPELL_ARCANE_BOMB_TRIGGER) + { + DoCastAOE(SPELL_ARCANE_BOMB_KNOCKBACK_DAMAGE, true); + DoCast(me, SPELL_ARCANE_OVERLOAD_1, true); + } } + private: + InstanceScript* _instance; + Creature* _malygos; }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_arcane_overloadAI (creature); + } }; // SmartAI does not work correctly for vehicles class npc_wyrmrest_skytalon : public CreatureScript { public: - npc_wyrmrest_skytalon() : CreatureScript("npc_wyrmrest_skytalon") {} - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_wyrmrest_skytalonAI (creature); - } + npc_wyrmrest_skytalon() : CreatureScript("npc_wyrmrest_skytalon") { } struct npc_wyrmrest_skytalonAI : public VehicleAI { - npc_wyrmrest_skytalonAI(Creature* creature) : VehicleAI(creature) { } + npc_wyrmrest_skytalonAI(Creature* creature) : VehicleAI(creature) + { + } void IsSummonedBy(Unit* summoner) { - summoner->CastSpell(me, SPELL_RIDE_RED_DRAGON, true); + me->CastSpell(summoner, SPELL_RIDE_RED_DRAGON_TRIGGERED, true); } - void PassengerBoarded(Unit* /*unit*/, int8 /*seat*/, bool apply) + void PassengerBoarded(Unit* unit, int8 /*seat*/, bool apply) { + if (apply) + { + _playerController = NULL; + _playerController = unit->ToPlayer(); + } if (!apply) - me->DespawnOrUnsummon(); + { + me->DespawnOrUnsummon(2050); + me->SetOrientation(2.5f); + me->SetSpeed(MOVE_FLIGHT, 1.0f, true); + Position pos; + me->GetPosition(&pos); + pos.m_positionX += 10.0f; + pos.m_positionY += 10.0f; + pos.m_positionZ += 12.0f; + me->GetMotionMaster()->MovePoint(1, pos); + } + } + + void JustDied(Unit* /*killer*/) + { + // TO DOs: check script beginning for more info. + _playerController->Kill(_playerController, true); } + + private: + Player* _playerController; }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_wyrmrest_skytalonAI (creature); + } +}; + +// We shouldn't use SAI for stuff that aren't within boss main mechanic +// and SAI type of despawn can cause problems here. +class npc_static_field : public CreatureScript +{ + public: + npc_static_field() : CreatureScript("npc_static_field") { } + + struct npc_static_fieldAI : public ScriptedAI + { + npc_static_fieldAI(Creature* creature) : ScriptedAI(creature) + { + } + + void IsSummonedBy(Unit* /*summoner*/) + { + // For some great reason the spell doesn't time it... + me->DespawnOrUnsummon(30*IN_MILLISECONDS); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_static_fieldAI (creature); + } +}; + +class spell_malygos_portal_beam : public SpellScriptLoader +{ + public: + spell_malygos_portal_beam() : SpellScriptLoader("spell_malygos_portal_beam") { } + + class spell_malygos_portal_beam_AuraScript : public AuraScript + { + PrepareAuraScript(spell_malygos_portal_beam_AuraScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_PORTAL_OPENED)) + return false; + + return true; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + target->CastSpell(target, SPELL_PORTAL_OPENED); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + target->RemoveAura(SPELL_PORTAL_OPENED); + } + + void Register() + { + OnEffectApply += AuraEffectApplyFn(spell_malygos_portal_beam_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_malygos_portal_beam_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_malygos_portal_beam_AuraScript(); + } +}; + +class spell_malygos_random_portal : public SpellScriptLoader +{ + public: + spell_malygos_random_portal() : SpellScriptLoader("spell_malygos_random_portal") { } + + class spell_malygos_random_portal_SpellScript : public SpellScript + { + PrepareSpellScript(spell_malygos_random_portal_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + Creature* malygos = GetCaster()->ToCreature(); + if (Creature* target = GetHitCreature()) + { + Position pos; + pos.m_positionZ = target->GetPositionZ(); + target->GetNearPoint2D(pos.m_positionX, pos.m_positionY, frand(29.1f, 30.0f), target->GetAngle(malygos)); + malygos->GetMotionMaster()->MovePoint(POINT_NEAR_RANDOM_PORTAL_P_NONE, pos); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_malygos_random_portal_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_malygos_random_portal_SpellScript(); + } +}; + +class isPlayerOnVehicleChecker +{ + public: + isPlayerOnVehicleChecker(Unit* source) : _source(source) { } + + bool operator()(WorldObject* unit) + { + if (Unit* target = ObjectAccessor::GetUnit(*_source, unit->GetGUID())) + if (target->IsOnVehicle(target->GetVehicleBase())) + return true; + + return false; + } + + private: + Unit* _source; }; -class npc_alexstrasza_eoe : public CreatureScript +class spell_malygos_arcane_storm : public SpellScriptLoader +{ + public: + spell_malygos_arcane_storm() : SpellScriptLoader("spell_malygos_arcane_storm") { } + + class spell_malygos_arcane_storm_SpellScript : public SpellScript + { + PrepareSpellScript(spell_malygos_arcane_storm_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_ARCANE_STORM_EXTRA_VISUAL)) + return false; + + return true; + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + Creature* malygos = GetCaster()->ToCreature(); + if (GetSpellInfo()->Id == SPELL_ARCANE_STORM_P_III) + targets.remove_if(isPlayerOnVehicleChecker(malygos)); + + if (!targets.empty()) + Trinity::Containers::RandomResizeList(targets, (malygos->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL ? 4 : 10)); + + for (std::list<WorldObject*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr) + malygos->CastSpell((*itr)->ToUnit(), SPELL_ARCANE_STORM_EXTRA_VISUAL, true); + } + + void Register() + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_malygos_arcane_storm_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_malygos_arcane_storm_SpellScript(); + } +}; + +class spell_malygos_vortex_dummy : public SpellScriptLoader { public: - npc_alexstrasza_eoe() : CreatureScript("npc_alexstrasza_eoe") {} + spell_malygos_vortex_dummy() : SpellScriptLoader("spell_malygos_vortex_dummy") { } - CreatureAI* GetAI(Creature* creature) const + class spell_malygos_vortex_dummy_SpellScript : public SpellScript { - return new npc_alexstrasza_eoeAI (creature); - } + PrepareSpellScript(spell_malygos_vortex_dummy_SpellScript) - struct npc_alexstrasza_eoeAI : public ScriptedAI - { - npc_alexstrasza_eoeAI(Creature* creature) : ScriptedAI(creature) {} + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } - void Reset() + void HandleScript(SpellEffIndex /*effIndex*/) { - _events.Reset(); - _events.ScheduleEvent(EVENT_YELL_1, 0); + Creature* caster = GetCaster()->ToCreature(); + // Each player will enter to the trigger vehicle (entry 30090) which is already spawned (each one can hold up to 5 players, it has 5 seats, + // the players enter the vehicles casting SPELL_VORTEX_4 or SPELL_VORTEX_5. + if (InstanceScript* instance = caster->GetInstanceScript()) + instance->SetData(DATA_VORTEX_HANDLING, 0); + + // the rest of the vortex execution continues when SPELL_VORTEX_2 is removed. } - void UpdateAI(uint32 /*diff*/) + void Register() { - while (uint32 eventId = _events.ExecuteEvent()) + OnEffectHitTarget += SpellEffectFn(spell_malygos_vortex_dummy_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_malygos_vortex_dummy_SpellScript(); + } +}; + +class spell_malygos_vortex_visual : public SpellScriptLoader +{ + public: + spell_malygos_vortex_visual() : SpellScriptLoader("spell_malygos_vortex_visual") { } + + class spell_malygos_vortex_visual_AuraScript : public AuraScript + { + PrepareAuraScript(spell_malygos_vortex_visual_AuraScript); + + bool Load() { - switch (eventId) + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_VORTEX_1) || !sSpellMgr->GetSpellInfo(SPELL_VORTEX_6)) + return false; + + return true; + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* caster = GetCaster()->ToCreature()) { - case EVENT_YELL_1: - Talk(SAY_ONE); - _events.ScheduleEvent(EVENT_YELL_2, 4*IN_MILLISECONDS); - break; - case EVENT_YELL_2: - Talk(SAY_TWO); - _events.ScheduleEvent(EVENT_YELL_3, 4*IN_MILLISECONDS); - break; - case EVENT_YELL_3: - Talk(SAY_THREE); - _events.ScheduleEvent(EVENT_YELL_4, 7*IN_MILLISECONDS); - break; - case EVENT_YELL_4: - Talk(SAY_FOUR); - break; + ThreatContainer::StorageType const& m_threatlist = caster->getThreatManager().getThreatList(); + for (ThreatContainer::StorageType::const_iterator itr = m_threatlist.begin(); itr!= m_threatlist.end(); ++itr) + { + if (Unit* target = (*itr)->getTarget()) + { + Player* targetPlayer = target->ToPlayer(); + if (!targetPlayer || targetPlayer->isGameMaster()) + continue; + + if (InstanceScript* instance = caster->GetInstanceScript()) + { + // Teleport spell - I'm not sure but might be it must be casted by each vehicle when it's passenger leaves it. + if (Creature* trigger = caster->GetMap()->GetCreature(instance->GetData64(DATA_TRIGGER))) + trigger->CastSpell(targetPlayer, SPELL_VORTEX_6, true); + } + } + } + + if (Creature* malygos = caster->ToCreature()) + { + malygos->GetMotionMaster()->MoveLand(POINT_LAND_AFTER_VORTEX_P_ONE, MalygosPositions[2]); + malygos->RemoveAura(SPELL_VORTEX_1); + } } } + + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_malygos_vortex_visual_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_malygos_vortex_visual_AuraScript(); } +}; + +class ExactDistanceCheck +{ + public: + ExactDistanceCheck(Unit* source, float dist) : _source(source), _dist(dist) { } + + bool operator()(WorldObject* unit) + { + return _source->GetExactDist2d(unit) > _dist; + } + private: - EventMap _events; - }; + Unit* _source; + float _dist; +}; + +class spell_arcane_overload : public SpellScriptLoader +{ + public: + spell_arcane_overload() : SpellScriptLoader("spell_arcane_overload") { } + + class spell_arcane_overload_SpellScript : public SpellScript + { + PrepareSpellScript(spell_arcane_overload_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void ResizeEffectRadiusTargetChecker(std::list<WorldObject*>& targets) + { + Creature* arcaneOverload = GetCaster()->ToCreature(); + targets.remove_if(ExactDistanceCheck(arcaneOverload, + GetSpellInfo()->Effects[EFFECT_0].CalcRadius(arcaneOverload) * arcaneOverload->GetFloatValue(OBJECT_FIELD_SCALE_X))); + } + + void Register() + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_arcane_overload_SpellScript::ResizeEffectRadiusTargetChecker, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_arcane_overload_SpellScript(); + } +}; + +class spell_nexus_lord_align_disk_aggro : public SpellScriptLoader +{ + public: + spell_nexus_lord_align_disk_aggro() : SpellScriptLoader("spell_nexus_lord_align_disk_aggro") { } + + class spell_nexus_lord_align_disk_aggro_SpellScript : public SpellScript + { + PrepareSpellScript(spell_nexus_lord_align_disk_aggro_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Creature* caster = GetCaster()->ToCreature(); + + if (Creature* target = GetHitCreature()) + target->GetMotionMaster()->MoveChase(caster->getVictim()); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_nexus_lord_align_disk_aggro_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_nexus_lord_align_disk_aggro_SpellScript(); + } +}; + +class IsPlayerOnHoverDiskCheck +{ + public: + IsPlayerOnHoverDiskCheck(Unit* source, bool isOnHoverDisk) : _source(source), _isOnHoverDisk(isOnHoverDisk) { } + + bool operator()(WorldObject* unit) + { + if (_isOnHoverDisk) + { + if (Unit* passenger = ObjectAccessor::GetUnit(*_source, unit->GetGUID())) + if (passenger->GetVehicleBase() && passenger->GetVehicleBase()->GetEntry() == NPC_HOVER_DISK_MELEE) + return true; + } + else if (!_isOnHoverDisk) + { + if (Unit* passenger = ObjectAccessor::GetUnit(*_source, unit->GetGUID())) + if (!passenger->GetVehicleBase()) + return true; + } + + return false; + } + + private: + Unit* _source; + + bool _isOnHoverDisk; +}; + +class spell_scion_of_eternity_arcane_barrage : public SpellScriptLoader +{ + public: + spell_scion_of_eternity_arcane_barrage() : SpellScriptLoader("spell_scion_of_eternity_arcane_barrage") { } + + class spell_scion_of_eternity_arcane_barrage_SpellScript : public SpellScript + { + PrepareSpellScript(spell_scion_of_eternity_arcane_barrage_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void FilterMeleeHoverDiskPassangers(std::list<WorldObject*>& targets) + { + if (targets.empty()) + return; + + Creature* caster = GetCaster()->ToCreature(); + for (std::list<WorldObject*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr) + _playersWithoutDisk.push_back((*itr)); + + _playersWithoutDisk.remove_if(IsPlayerOnHoverDiskCheck(caster, false)); + if (_playersWithoutDisk.empty()) + targets.remove_if(IsPlayerOnHoverDiskCheck(caster, true)); + } + + void Register() + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_scion_of_eternity_arcane_barrage_SpellScript::FilterMeleeHoverDiskPassangers, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + + std::list<WorldObject*> _playersWithoutDisk; + }; + + SpellScript* GetSpellScript() const + { + return new spell_scion_of_eternity_arcane_barrage_SpellScript(); + } +}; + +class spell_malygos_destroy_platform_channel : public SpellScriptLoader +{ + public: + spell_malygos_destroy_platform_channel() : SpellScriptLoader("spell_malygos_destroy_platform_channel") { } + + class spell_malygos_destroy_platform_channel_AuraScript : public AuraScript + { + PrepareAuraScript(spell_malygos_destroy_platform_channel_AuraScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_DESTROY_PLATFORM_BOOM_VISUAL)) + return false; + + return true; + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + if (InstanceScript* instance = target->GetInstanceScript()) + if (Creature* platformTrigger = target->GetMap()->GetCreature(instance->GetData64(DATA_ALEXSTRASZA_BUNNY_GUID))) + platformTrigger->CastSpell(platformTrigger, SPELL_DESTROY_PLATFORM_BOOM_VISUAL); + } + + void Register() + { + AfterEffectRemove += AuraEffectRemoveFn(spell_malygos_destroy_platform_channel_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_malygos_destroy_platform_channel_AuraScript(); + } +}; + +class spell_alexstrasza_bunny_destroy_platform_boom_visual : public SpellScriptLoader +{ + public: + spell_alexstrasza_bunny_destroy_platform_boom_visual() : SpellScriptLoader("spell_alexstrasza_bunny_destroy_platform_boom_visual") { } + + class spell_alexstrasza_bunny_destroy_platform_boom_visual_SpellScript : public SpellScript + { + PrepareSpellScript(spell_alexstrasza_bunny_destroy_platform_boom_visual_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_DESTROY_PLATFORM_EVENT)) + return false; + + return true; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (Creature* target = GetHitCreature()) + { + target->CastSpell(target, SPELL_DESTROY_PLATFORM_EVENT); + } + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_alexstrasza_bunny_destroy_platform_boom_visual_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_alexstrasza_bunny_destroy_platform_boom_visual_SpellScript(); + } +}; + +class spell_alexstrasza_bunny_destroy_platform_event : public SpellScriptLoader +{ + public: + spell_alexstrasza_bunny_destroy_platform_event() : SpellScriptLoader("spell_alexstrasza_bunny_destroy_platform_event") { } + + class spell_alexstrasza_bunny_destroy_platform_event_SpellScript : public SpellScript + { + PrepareSpellScript(spell_alexstrasza_bunny_destroy_platform_event_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void HandleSendEvent(SpellEffIndex /*effIndex*/) + { + Creature* caster = GetCaster()->ToCreature(); + if (InstanceScript* instance = caster->GetInstanceScript()) + if (GameObject* platform = caster->GetMap()->GetGameObject(instance->GetData64(DATA_PLATFORM))) + platform->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Creature* caster = GetCaster()->ToCreature(); + caster->CastSpell(caster, SPELL_SUMMON_RED_DRAGON_BUDDY_F_CAST, true); + } + + void Register() + { + OnEffectHit += SpellEffectFn(spell_alexstrasza_bunny_destroy_platform_event_SpellScript::HandleSendEvent, EFFECT_0, SPELL_EFFECT_SEND_EVENT); + OnEffectHitTarget += SpellEffectFn(spell_alexstrasza_bunny_destroy_platform_event_SpellScript::HandleScript, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_alexstrasza_bunny_destroy_platform_event_SpellScript(); + } +}; + +class spell_wyrmrest_skytalon_summon_red_dragon_buddy : public SpellScriptLoader +{ + public: + spell_wyrmrest_skytalon_summon_red_dragon_buddy() : SpellScriptLoader("spell_wyrmrest_skytalon_summon_red_dragon_buddy") { } + + class spell_wyrmrest_skytalon_summon_red_dragon_buddy_SpellScript : public SpellScript + { + PrepareSpellScript(spell_wyrmrest_skytalon_summon_red_dragon_buddy_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_PLAYER; + } + + void ChangeSummonPos(SpellEffIndex /*effIndex*/) + { + // Adjust effect summon position to lower Z + WorldLocation summonPos = *GetExplTargetDest(); + Position offset = { 0.0f, 0.0f, -80.0f, 0.0f }; + summonPos.RelocateOffset(offset); + SetExplTargetDest(summonPos); + GetHitDest()->RelocateOffset(offset); + } + + void Register() + { + OnEffectHit += SpellEffectFn(spell_wyrmrest_skytalon_summon_red_dragon_buddy_SpellScript::ChangeSummonPos, EFFECT_0, SPELL_EFFECT_SUMMON); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_wyrmrest_skytalon_summon_red_dragon_buddy_SpellScript(); + } +}; + +class spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger : public SpellScriptLoader +{ + public: + spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger() : SpellScriptLoader("spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger") { } + + class spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger_SpellScript : public SpellScript + { + PrepareSpellScript(spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger_SpellScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + target->CastSpell(GetCaster(), GetEffectValue(), true); + } + + void Register() + { + OnEffectHitTarget += SpellEffectFn(spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger_SpellScript(); + } +}; + +class spell_malygos_surge_of_power_warning_selector_25 : public SpellScriptLoader +{ + public: + spell_malygos_surge_of_power_warning_selector_25() : SpellScriptLoader("spell_malygos_surge_of_power_warning_selector_25") { } + + class spell_malygos_surge_of_power_warning_selector_25_SpellScript : public SpellScript + { + PrepareSpellScript(spell_malygos_surge_of_power_warning_selector_25_SpellScript) + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_SURGE_OF_POWER_PHASE_3_25)) + return false; + + return true; + } + + void SendThreeTargets(std::list<WorldObject*>& targets) + { + Creature* caster = GetCaster()->ToCreature(); + targets.remove_if(isPlayerOnVehicleChecker(caster)); + if (targets.empty()) + return; + + for (std::list<WorldObject*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr) + _filteredSelectedTargets.push_back((*itr)); + + if (_filteredSelectedTargets.empty()) + return; + + uint8 guidDataSlot = 14; // SetGuid in Malygos AI is reserved for 14th, 15th and 16th Id for the three targets + Trinity::Containers::RandomResizeList(_filteredSelectedTargets, 3); + for (std::list<WorldObject*>::const_iterator itr = _filteredSelectedTargets.begin(); itr != _filteredSelectedTargets.end(); ++itr) + { + caster->AI()->SetGUID((*itr)->GetGUID(), guidDataSlot++); + if (IS_VEHICLE_GUID((*itr)->GetGUID())) + { + if (Vehicle* tempVehicle = (*itr)->ToCreature()->GetVehicleKit()) + if (tempVehicle->GetPassenger(0)) + if (Player* tempPlayer = tempVehicle->GetPassenger(0)->ToPlayer()) + caster->AI()->Talk(EMOTE_SURGE_OF_POWER_WARNING_P3, tempPlayer->GetGUID()); + } + else if (IS_PLAYER_GUID((*itr)->GetGUID())) + { + caster->AI()->Talk(EMOTE_SURGE_OF_POWER_WARNING_P3, (*itr)->GetGUID()); + } + } + } + + void ExecuteMainSpell() + { + // We shouldn't cast stuff from target selector hooks + Creature* caster = GetCaster()->ToCreature(); + caster->AI()->DoCastAOE(SPELL_SURGE_OF_POWER_PHASE_3_25); + } + + void Register() + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_malygos_surge_of_power_warning_selector_25_SpellScript::SendThreeTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + AfterHit += SpellHitFn(spell_malygos_surge_of_power_warning_selector_25_SpellScript::ExecuteMainSpell); + } + + std::list<WorldObject*> _filteredSelectedTargets; + }; + + SpellScript* GetSpellScript() const + { + return new spell_malygos_surge_of_power_warning_selector_25_SpellScript(); + } +}; + +class spell_malygos_surge_of_power_25 : public SpellScriptLoader +{ + public: + spell_malygos_surge_of_power_25() : SpellScriptLoader("spell_malygos_surge_of_power_25") { } + + class spell_malygos_surge_of_power_25_SpellScript : public SpellScript + { + PrepareSpellScript(spell_malygos_surge_of_power_25_SpellScript) + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + Creature* caster = GetCaster()->ToCreature(); + if (!targets.empty()) + targets.clear(); + + for (int guidSlot = 14; guidSlot <= 16; guidSlot++) + { + uint64 guidTypeChecker = caster->AI()->GetGUID(guidSlot); + if (IS_EMPTY_GUID(guidTypeChecker)) + continue; + + if (IS_VEHICLE_GUID(guidTypeChecker)) + { + WorldObject* tempTarget = caster->GetMap()->GetCreature(guidTypeChecker); + targets.push_back(tempTarget); + } + else if (IS_PLAYER_GUID(guidTypeChecker)) + { + WorldObject* tempTarget = ObjectAccessor::GetPlayer(*caster, guidTypeChecker); + targets.push_back(tempTarget); + } + } + } + + void Register() + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_malygos_surge_of_power_25_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_malygos_surge_of_power_25_SpellScript(); + } +}; + +class spell_alexstrasza_gift_beam : public SpellScriptLoader +{ + public: + spell_alexstrasza_gift_beam() : SpellScriptLoader("spell_alexstrasza_gift_beam") { } + + class spell_alexstrasza_gift_beam_AuraScript : public AuraScript + { + PrepareAuraScript(spell_alexstrasza_gift_beam_AuraScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + bool Validate(SpellInfo const* /*spell*/) + { + if (!sSpellMgr->GetSpellInfo(SPELL_ALEXSTRASZAS_GIFT_BEAM_VISUAL)) + return false; + + return true; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + target->CastSpell(target, SPELL_ALEXSTRASZAS_GIFT_BEAM_VISUAL); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + target->RemoveAura(SPELL_ALEXSTRASZAS_GIFT_BEAM_VISUAL); + } + + void Register() + { + OnEffectApply += AuraEffectApplyFn(spell_alexstrasza_gift_beam_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_alexstrasza_gift_beam_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_alexstrasza_gift_beam_AuraScript(); + } +}; + +class spell_alexstrasza_gift_beam_visual : public SpellScriptLoader +{ + public: + spell_alexstrasza_gift_beam_visual() : SpellScriptLoader("spell_alexstrasza_gift_beam_visual") { } + + class spell_alexstrasza_gift_beam_visual_AuraScript : public AuraScript + { + PrepareAuraScript(spell_alexstrasza_gift_beam_visual_AuraScript); + + bool Load() + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + { + if (target->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + _alexstraszaGift = target->SummonGameObject(GO_ALEXSTRASZA_S_GIFT_10, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0); + else if (target->GetMap()->GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + _alexstraszaGift = target->SummonGameObject(GO_ALEXSTRASZA_S_GIFT_25, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0); + } + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + { + _alexstraszaGift->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + if ((_heartMagic = target->GetMap()->GetGameObject(instance->GetData64(DATA_HEART_OF_MAGIC_GUID)))) + { + _heartMagic->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + // TO DO: This is hack, core doesn't have support for these flags, + // remove line below if it ever gets supported otherwise object won't be accessible. + _heartMagic->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); + } + } + } + + void Register() + { + OnEffectApply += AuraEffectApplyFn(spell_alexstrasza_gift_beam_visual_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_alexstrasza_gift_beam_visual_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + + GameObject* _alexstraszaGift; + GameObject* _heartMagic; + }; + + AuraScript* GetAuraScript() const + { + return new spell_alexstrasza_gift_beam_visual_AuraScript(); + } }; class achievement_denyin_the_scion : public AchievementCriteriaScript { public: - achievement_denyin_the_scion() : AchievementCriteriaScript("achievement_denyin_the_scion") {} + achievement_denyin_the_scion() : AchievementCriteriaScript("achievement_denyin_the_scion") { } bool OnCheck(Player* source, Unit* /*target*/) { + // Only melee disks can be used if (Unit* disk = source->GetVehicleBase()) - if (disk->GetEntry() == NPC_HOVER_DISK_CASTER || disk->GetEntry() == NPC_HOVER_DISK_MELEE) + if (disk->GetEntry() == NPC_HOVER_DISK_MELEE) return true; + return false; } }; @@ -1114,11 +2502,29 @@ void AddSC_boss_malygos() new boss_malygos(); new npc_portal_eoe(); new npc_power_spark(); - new npc_hover_disk(); + new npc_melee_hover_disk(); + new npc_caster_hover_disk(); + new npc_nexus_lord(); + new npc_scion_of_eternity(); new npc_arcane_overload(); new npc_wyrmrest_skytalon(); + new npc_static_field(); + new spell_malygos_portal_beam(); + new spell_malygos_random_portal(); + new spell_malygos_arcane_storm(); new spell_malygos_vortex_dummy(); new spell_malygos_vortex_visual(); - new npc_alexstrasza_eoe(); + new spell_arcane_overload(); + new spell_nexus_lord_align_disk_aggro(); + new spell_scion_of_eternity_arcane_barrage(); + new spell_malygos_destroy_platform_channel(); + new spell_alexstrasza_bunny_destroy_platform_boom_visual(); + new spell_alexstrasza_bunny_destroy_platform_event(); + new spell_wyrmrest_skytalon_summon_red_dragon_buddy(); + new spell_wyrmrest_skytalon_ride_red_dragon_buddy_trigger(); + new spell_malygos_surge_of_power_warning_selector_25(); + new spell_malygos_surge_of_power_25(); + new spell_alexstrasza_gift_beam(); + new spell_alexstrasza_gift_beam_visual(); new achievement_denyin_the_scion(); } diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h index c25feaafaf8..db879eab6fb 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/eye_of_eternity.h @@ -24,14 +24,19 @@ enum InstanceData MAX_ENCOUNTER, DATA_VORTEX_HANDLING, - DATA_POWER_SPARKS_HANDLING + DATA_POWER_SPARKS_HANDLING, + DATA_RESPAWN_IRIS }; enum InstanceData64 { DATA_TRIGGER, DATA_MALYGOS, - DATA_PLATFORM + DATA_PLATFORM, + DATA_ALEXSTRASZA_BUNNY_GUID, + DATA_HEART_OF_MAGIC_GUID, + DATA_FOCUSING_IRIS_GUID, + DATA_GIFT_BOX_BUNNY_GUID }; enum InstanceNpcs @@ -44,16 +49,22 @@ enum InstanceNpcs NPC_HOVER_DISK_CASTER = 30248, NPC_ARCANE_OVERLOAD = 30282, NPC_WYRMREST_SKYTALON = 30161, - NPC_ALEXSTRASZA = 32295 + NPC_ALEXSTRASZA = 32295, + NPC_ALEXSTRASZA_BUNNY = 31253, + NPC_ALEXSTRASZAS_GIFT = 32448, + NPC_SURGE_OF_POWER = 30334 }; enum InstanceGameObjects { GO_NEXUS_RAID_PLATFORM = 193070, GO_EXIT_PORTAL = 193908, - GO_FOCUSING_IRIS = 193958, - GO_ALEXSTRASZA_S_GIFT = 193905, - GO_ALEXSTRASZA_S_GIFT_2 = 193967 + GO_FOCUSING_IRIS_10 = 193958, + GO_FOCUSING_IRIS_25 = 193960, + GO_ALEXSTRASZA_S_GIFT_10 = 193905, + GO_ALEXSTRASZA_S_GIFT_25 = 193967, + GO_HEART_OF_MAGIC_10 = 194158, + GO_HEART_OF_MAGIC_25 = 194159 }; enum InstanceEvents @@ -63,10 +74,11 @@ enum InstanceEvents enum InstanceSpells { - SPELL_VORTEX_4 = 55853, // damage | used to enter to the vehicle - SPELL_VORTEX_5 = 56263, // damage | used to enter to the vehicle - SPELL_PORTAL_OPENED = 61236, - SPELL_RIDE_RED_DRAGON = 56071, + SPELL_VORTEX_4 = 55853, // damage | used to enter to the vehicle + SPELL_VORTEX_5 = 56263, // damage | used to enter to the vehicle + SPELL_PORTAL_OPENED = 61236, + SPELL_RIDE_RED_DRAGON_TRIGGERED = 56072, + SPELL_IRIS_OPENED = 61012 // visual when starting encounter }; #endif diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp index 6b1be15f110..52ce259117f 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp @@ -24,7 +24,7 @@ class instance_eye_of_eternity : public InstanceMapScript { public: - instance_eye_of_eternity() : InstanceMapScript("instance_eye_of_eternity", 616) {} + instance_eye_of_eternity() : InstanceMapScript("instance_eye_of_eternity", 616) { } InstanceScript* GetInstanceScript(InstanceMap* map) const { @@ -41,9 +41,11 @@ public: portalTriggers.clear(); malygosGUID = 0; + irisGUID = 0; lastPortalGUID = 0; platformGUID = 0; exitPortalGUID = 0; + alexstraszaBunnyGUID = 0; }; bool SetBossState(uint32 type, EncounterState state) @@ -65,31 +67,18 @@ public: } } - SpawnGameObject(GO_FOCUSING_IRIS, focusingIrisPosition); SpawnGameObject(GO_EXIT_PORTAL, exitPortalPosition); if (GameObject* platform = instance->GetGameObject(platformGUID)) platform->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED); } else if (state == DONE) - { - if (Creature* malygos = instance->GetCreature(malygosGUID)) - malygos->SummonCreature(NPC_ALEXSTRASZA, 829.0679f, 1244.77f, 279.7453f, 2.32f); - SpawnGameObject(GO_EXIT_PORTAL, exitPortalPosition); - - // we make the platform appear again because at the moment we don't support looting using a vehicle - if (GameObject* platform = instance->GetGameObject(platformGUID)) - platform->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_DESTROYED); - - if (GameObject* chest = instance->GetGameObject(chestGUID)) - chest->SetRespawnTime(7*DAY); - } } return true; } - //TODO: this should be handled in map, maybe add a summon function in map + // TO DO: this should be handled in map, maybe add a summon function in map // There is no other way afaik... void SpawnGameObject(uint32 entry, Position& pos) { @@ -112,16 +101,31 @@ public: case GO_NEXUS_RAID_PLATFORM: platformGUID = go->GetGUID(); break; - case GO_FOCUSING_IRIS: - go->GetPosition(&focusingIrisPosition); + case GO_FOCUSING_IRIS_10: + if (instance->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + { + irisGUID = go->GetGUID(); + go->GetPosition(&focusingIrisPosition); + } + break; + case GO_FOCUSING_IRIS_25: + if (instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + { + irisGUID = go->GetGUID(); + go->GetPosition(&focusingIrisPosition); + } break; case GO_EXIT_PORTAL: exitPortalGUID = go->GetGUID(); go->GetPosition(&exitPortalPosition); break; - case GO_ALEXSTRASZA_S_GIFT: - case GO_ALEXSTRASZA_S_GIFT_2: - chestGUID = go->GetGUID(); + case GO_HEART_OF_MAGIC_10: + if (instance->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL) + heartOfMagicGUID = go->GetGUID(); + break; + case GO_HEART_OF_MAGIC_25: + if (instance->GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL) + heartOfMagicGUID = go->GetGUID(); break; } } @@ -139,18 +143,27 @@ public: case NPC_PORTAL_TRIGGER: portalTriggers.push_back(creature->GetGUID()); break; + case NPC_ALEXSTRASZA_BUNNY: + alexstraszaBunnyGUID = creature->GetGUID(); + break; + case NPC_ALEXSTRASZAS_GIFT: + giftBoxBunnyGUID = creature->GetGUID(); + break; } } - void ProcessEvent(WorldObject* obj, uint32 eventId) + void ProcessEvent(WorldObject* /*obj*/, uint32 eventId) { if (eventId == EVENT_FOCUSING_IRIS) { - if (GameObject* go = obj->ToGameObject()) - go->Delete(); // this is not the best way. + if (Creature* alexstraszaBunny = instance->GetCreature(alexstraszaBunnyGUID)) + { + alexstraszaBunny->CastSpell(alexstraszaBunny, SPELL_IRIS_OPENED); + instance->GetGameObject(irisGUID)->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE); + } if (Creature* malygos = instance->GetCreature(malygosGUID)) - malygos->GetMotionMaster()->MovePoint(4, 770.10f, 1275.33f, 267.23f); // MOVE_INIT_PHASE_ONE + malygos->AI()->DoAction(0); // ACTION_LAND_ENCOUNTER_START if (GameObject* exitPortal = instance->GetGameObject(exitPortalGUID)) exitPortal->Delete(); @@ -194,7 +207,7 @@ public: void PowerSparksHandling() { - bool next = (lastPortalGUID == portalTriggers.back() || !lastPortalGUID ? true : false); + bool next = (lastPortalGUID == portalTriggers.back() || !lastPortalGUID ? true : false); for (std::list<uint64>::const_iterator itr_trigger = portalTriggers.begin(); itr_trigger != portalTriggers.end(); ++itr_trigger) { @@ -223,6 +236,9 @@ public: case DATA_POWER_SPARKS_HANDLING: PowerSparksHandling(); break; + case DATA_RESPAWN_IRIS: + SpawnGameObject(instance->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL ? GO_FOCUSING_IRIS_10 : GO_FOCUSING_IRIS_25, focusingIrisPosition); + break; } } @@ -236,6 +252,14 @@ public: return malygosGUID; case DATA_PLATFORM: return platformGUID; + case DATA_ALEXSTRASZA_BUNNY_GUID: + return alexstraszaBunnyGUID; + case DATA_HEART_OF_MAGIC_GUID: + return heartOfMagicGUID; + case DATA_FOCUSING_IRIS_GUID: + return irisGUID; + case DATA_GIFT_BOX_BUNNY_GUID: + return giftBoxBunnyGUID; } return 0; @@ -287,10 +311,13 @@ public: std::list<uint64> vortexTriggers; std::list<uint64> portalTriggers; uint64 malygosGUID; + uint64 irisGUID; uint64 lastPortalGUID; uint64 platformGUID; uint64 exitPortalGUID; - uint64 chestGUID; + uint64 heartOfMagicGUID; + uint64 alexstraszaBunnyGUID; + uint64 giftBoxBunnyGUID; Position focusingIrisPosition; Position exitPortalPosition; }; diff --git a/src/server/shared/Common.h b/src/server/shared/Common.h index f4e4ce7fe06..44a7749334d 100644 --- a/src/server/shared/Common.h +++ b/src/server/shared/Common.h @@ -170,7 +170,7 @@ enum LocaleConstant }; const uint8 TOTAL_LOCALES = 9; -const LocaleConstant DEFAULT_LOCALE = LOCALE_enUS; +#define DEFAULT_LOCALE LOCALE_enUS #define MAX_LOCALES 8 #define MAX_ACCOUNT_TUTORIAL_VALUES 8 |