diff options
21 files changed, 540 insertions, 302 deletions
diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 35abaa2611c..9da864cb9a2 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -455,7 +455,8 @@ DROP TABLE IF EXISTS `rbac_default_permissions`; CREATE TABLE `rbac_default_permissions` ( `secId` int(10) unsigned NOT NULL COMMENT 'Security Level id', `permissionId` int(10) unsigned NOT NULL COMMENT 'permission id', - PRIMARY KEY (`secId`,`permissionId`), + `realmId` int(11) NOT NULL DEFAULT '-1' COMMENT 'Realm Id, -1 means all', + PRIMARY KEY (`secId`,`permissionId`, `realmId`), KEY `fk__rbac_default_permissions__rbac_permissions` (`permissionId`), CONSTRAINT `fk__rbac_default_permissions__rbac_permissions` FOREIGN KEY (`permissionId`) REFERENCES `rbac_permissions` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Default permission to assign to different account security levels'; @@ -467,7 +468,7 @@ CREATE TABLE `rbac_default_permissions` ( LOCK TABLES `rbac_default_permissions` WRITE; /*!40000 ALTER TABLE `rbac_default_permissions` DISABLE KEYS */; -INSERT INTO `rbac_default_permissions` VALUES (0,195),(1,194),(2,193),(3,192); +INSERT INTO `rbac_default_permissions` VALUES (3,192,-1),(2,193,-1),(1,194,-1),(0,195,-1); /*!40000 ALTER TABLE `rbac_default_permissions` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/auth/2014_12_10_00_auth.sql b/sql/updates/auth/2014_12_10_00_auth.sql new file mode 100644 index 00000000000..8068fd3c459 --- /dev/null +++ b/sql/updates/auth/2014_12_10_00_auth.sql @@ -0,0 +1,3 @@ +ALTER TABLE `rbac_default_permissions` +ADD COLUMN `realmId` INT(11) NOT NULL DEFAULT '-1' COMMENT 'Realm Id, -1 means all', +DROP PRIMARY KEY, ADD PRIMARY KEY (`secId`, `permissionId`, `realmId`); diff --git a/sql/updates/world/2014_12_12_00_world.sql b/sql/updates/world/2014_12_12_00_world.sql new file mode 100644 index 00000000000..bf1854689b3 --- /dev/null +++ b/sql/updates/world/2014_12_12_00_world.sql @@ -0,0 +1,34 @@ +-- Spawn few missing Bloodcursed Voyagers +SET @CGUID := 75068; +DELETE FROM `creature` WHERE `guid` BETWEEN @CGUID+0 AND @CGUID+13; +INSERT INTO `creature` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `MovementType`) VALUES +(@CGUID+0, 17714, 530, 1, 1, -981.0825, -12847.73, -78.35015, 2.45272, 120, 5, 1), +(@CGUID+1, 17714, 530, 1, 1, -981.314, -12813.58, -51.96035, 0.8106143, 120, 5, 1), +(@CGUID+2, 17714, 530, 1, 1, -1135.072, -12931.56, -98.48705, 2.435335, 120, 5, 1), +(@CGUID+3, 17714, 530, 1, 1, -1119.166, -12949.73, -99.68898, 2.535294, 120, 5, 1), +(@CGUID+4, 17714, 530, 1, 1, -1151.618, -12952.28, -101.0686, 2.985196, 120, 5, 1), +(@CGUID+5, 17714, 530, 1, 1, -1150.575, -12917.89, -101.5449, 3.950372, 120, 5, 1), +(@CGUID+6, 17714, 530, 1, 1, -1201.324, -12933.42, -102.7079, 1.193372, 120, 5, 1), +(@CGUID+7, 17714, 530, 1, 1, -1183.288, -12912.58, -102.4625, 3.731045, 120, 5, 1), +(@CGUID+8, 17714, 530, 1, 1, -1221.537, -12954.43, -104.158, 4.284279, 120, 5, 1), +(@CGUID+9, 17714, 530, 1, 1, -1252.931, -12952.77, -104.744, 3.633311, 120, 5, 1), +(@CGUID+10, 17714, 530, 1, 1, -1134.563, -12897.89, -102.6108, 2.934096, 120, 5, 1), +(@CGUID+11, 17714, 530, 1, 1, -1147.651, -12879.45, -102.4199, 4.143747, 120, 5, 1), +(@CGUID+12, 17714, 530, 1, 1, -1411.555, -12765.24, -16.17389, 1.595299, 120, 5, 1), +(@CGUID+13, 17714, 530, 1, 1, -1415.727, -12795.06, -15.76654, 1.830911, 120, 5, 1); + +DELETE FROM `gossip_menu_option` WHERE (`menu_id`=8298 AND `id`=0); +INSERT INTO `gossip_menu_option` (`menu_id`, `id`, `option_icon`, `option_text`, `option_id`, `OptionBroadcastTextID`, `npc_option_npcflag`, `box_coded`, `box_money`, `box_text`) VALUES +(8298, 0, 0, 'Can you cast the spell to help me breathe and move underwater?', 1, 19071, 1, 0, 0, ''); -- 17712 + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 15 AND `SourceGroup` = 8298; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `Comment`) VALUES +(15, 8298, 0, 0, 0, 9, 0, 9674, 0, 0, 0, 0, 0, 'Captain Edward Hanes - Show Gossip if player has quest 9674 incomplete'), +(15, 8298, 0, 0, 1, 9, 0, 9682, 0, 0, 0, 0, 0, 'Captain Edward Hanes - Show Gossip if player has quest 9682 incomplete'); + +DELETE FROM `smart_scripts` WHERE `entryorguid` = 17712 AND `id` IN (1, 2, 3, 4); +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 +(17712,0,1,2,62,0,100,0,8298,0,0,0,11,31319,0,0,0,0,0,7,0,0,0,0,0,0,0,'Captain Edward Hanes - On Gossip Select - Cast "The Captain\'s Kiss"'), +(17712,0,2,0,61,0,100,0,0,0,0,0,72,0,0,0,0,0,0,7,0,0,0,0,0,0,0,'Captain Edward Hanes - On Gossip Select - Close Gossip'), +(17712,0,3,0,19,0,100,0,9674,0,0,0,11,31319,0,0,0,0,0,7,0,0,0,0,0,0,0,'Captain Edward Hanes - On Quest Accept - Cast "The Captain\'s Kiss"'), +(17712,0,4,0,19,0,100,0,9682,0,0,0,11,31319,0,0,0,0,0,7,0,0,0,0,0,0,0,'Captain Edward Hanes - On Quest Accept - Cast "The Captain\'s Kiss"'); diff --git a/sql/updates/world/2014_12_12_01_world.sql b/sql/updates/world/2014_12_12_01_world.sql new file mode 100644 index 00000000000..aa5b1641320 --- /dev/null +++ b/sql/updates/world/2014_12_12_01_world.sql @@ -0,0 +1,2 @@ +-- +UPDATE `creature_template` SET `mechanic_immune_mask` = `mechanic_immune_mask` |33554432, `flags_extra` = `flags_extra` &~256 WHERE entry IN (10184, 36538); diff --git a/sql/updates/world/2014_12_12_02_world.sql b/sql/updates/world/2014_12_12_02_world.sql new file mode 100644 index 00000000000..6dc657b39e9 --- /dev/null +++ b/sql/updates/world/2014_12_12_02_world.sql @@ -0,0 +1,2 @@ +-- +UPDATE `conditions` SET `conditionValue1` = 11 WHERE `SourceGroup` = 10389 AND `SourceEntry` = 15 AND `SourceTypeOrReferenceId` = 15; diff --git a/sql/updates/world/2014_12_12_03_world.sql b/sql/updates/world/2014_12_12_03_world.sql new file mode 100644 index 00000000000..0f939f81670 --- /dev/null +++ b/sql/updates/world/2014_12_12_03_world.sql @@ -0,0 +1,3 @@ +-- Ungroup some improperly grouped texts and set their text range +UPDATE `creature_text` SET `groupid` = 5, `TextRange` = 3 WHERE `entry` IN (16065, 16064, 30549, 16063) AND `groupid` = 1 AND `id` = 0; +UPDATE `creature_text` SET `groupid` = 6, `TextRange` = 3, `id` = 0 WHERE `entry` IN (16065, 16064, 30549, 16063) AND `groupid` = 1 AND `id` = 1;
diff --git a/sql/updates/world/2014_12_13_00_world.sql b/sql/updates/world/2014_12_13_00_world.sql new file mode 100644 index 00000000000..3be9f73a293 --- /dev/null +++ b/sql/updates/world/2014_12_13_00_world.sql @@ -0,0 +1,6 @@ +-- Ungroup some improperly grouped texts and set their text range +UPDATE `creature_text` SET `TextRange` = 3 WHERE `entry` = 15990 AND `groupid` = 5; +UPDATE `creature_text` SET `groupid` = 16, `TextRange` = 3, `id` = 0 WHERE `entry` = 15990 AND `groupid` = 6 AND `id` = 0; +UPDATE `creature_text` SET `groupid` = 17, `TextRange` = 3, `id` = 0 WHERE `entry` = 15990 AND `groupid` = 6 AND `id` = 1; +UPDATE `creature_text` SET `groupid` = 18, `TextRange` = 3, `id` = 0 WHERE `entry` = 15990 AND `groupid` = 6 AND `id` = 2; +UPDATE `creature_text` SET `groupid` = 19, `TextRange` = 3, `id` = 0 WHERE `entry` = 15990 AND `groupid` = 6 AND `id` = 3; diff --git a/sql/updates/world/2014_12_15_00_world.sql b/sql/updates/world/2014_12_15_00_world.sql new file mode 100644 index 00000000000..8ed026454c6 --- /dev/null +++ b/sql/updates/world/2014_12_15_00_world.sql @@ -0,0 +1,18 @@ +SET @CGUID := 6747; +DELETE FROM `creature` WHERE `guid`=@CGUID; +INSERT INTO `creature` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `MovementType`) VALUES +(@CGUID, 22418, 534, 1, 1, 5502.288, -3525.471, 1607.909, 2.617994, 7200, 0, 0); + +DELETE FROM `creature_text` WHERE `entry`=17968 AND `groupid`=8; +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(17968, 8, 0, 'All of your efforts have been in vain, for the draining of the World Tree has already begun! Soon the heart of your world will beat no more!', 14, 0, 100, 0, 0, 10986, 20432, 3, 'Archimonde - Intro'); + +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry` IN (39140,39141,39142); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,1,39140,0,0,31,0,3,22418,0,0,0, '', 'Drain World Tree Visual'), +(13,1,39141,0,0,31,0,3,17968,0,0,0, '', 'Drain World Tree Visual 2'), +(13,1,39142,0,0,31,0,3,22418,0,0,0, '', 'Drain World Tree Dummy'); + +DELETE FROM `spell_script_names` WHERE `spell_id`=39142; +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(39142, 'spell_archimonde_drain_world_tree_dummy'); diff --git a/sql/updates/world/2014_12_17_00_world.sql b/sql/updates/world/2014_12_17_00_world.sql new file mode 100644 index 00000000000..fd1e88f9c1a --- /dev/null +++ b/sql/updates/world/2014_12_17_00_world.sql @@ -0,0 +1,23 @@ +-- +UPDATE `creature_text` SET `TextRange` = 3 WHERE `entry` = 15990 AND `groupid` IN (0, 2, 4); +DELETE FROM `creature_text` WHERE `entry` = 15990 AND `groupid` IN (13, 20); +DELETE FROM `creature_text` WHERE `entry` = 16980 AND `groupid` IN (1, 2, 3); +DELETE FROM `creature_text` WHERE `entry` = 15384 AND `groupid` = 0; +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextID`, `TextRange`, `comment`) VALUES +(15990, 20, 0, 'Come, heroes... By the will of the Lich King, you shall be destroyed.', 14, 0, 100, 0, 0, 0, 12993, 3, 'Kel''Thuzad SAY_DIALOGUE_SAPPHIRON_KELTHUZAD4'), +(15990, 13, 0, 'Kel''Thuzad strikes!', 41, 0, 100, 0, 0, 0, 32803, 0, 'Kel''Thuzad EMOTE_PHASE_TWO'), +(16980, 1, 0, 'Soon we will eradicate the Alliance and Horde. Then the rest of Azeroth will fall before the might of my army.', 14, 0, 100, 0, 0, 14768, 12988, 3, 'The Lich King SAY_DIALOGUE_SAPPHIRON_LICHKING'), +(16980, 2, 0, 'Invaders... here?! DESTROY them, Kel''Thuzad! Naxxramas must not fall!', 14, 0, 100, 0, 0, 14769, 12989, 3, 'The Lich King SAY_DIALOGUE_SAPPHIRON_LICHKING2'), +(16980, 3, 0, 'Very well. Warriors of the frozen wastes, rise up! I command you to fight, kill and die for your master! Let none survive!', 14, 0, 100, 0, 0, 14770, 12994, 3, 'The Lich King SAY_ANSWER_REQUEST'), +(15384, 0, 0, 'A Guardian of Icecrown enters the fight!', 41, 0, 100, 0, 0, 0, 32804, 0, 'OLDWorld Trigger (DO NOT DELETE)'); + +-- Spawn some missing triggers and the Lich King dummy. Triggers are used to emote when a Guardian of Icecrown is spawned, currently not implemented. +SET @CGUID = 75082; +DELETE FROM `creature` WHERE `guid` BETWEEN @CGUID+0 AND @CGUID+5; +INSERT INTO `creature` (`guid`, `id`, `map`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `MovementType`) VALUES +(@CGUID+0, 16980, 533, 3, 1, 3762.382, -5115.862, 143.9382, 0.1919862, 7200, 0, 0), -- 16980 (Area: -1) +(@CGUID+1, 15384, 533, 3, 1, 3759.62, -5172.786, 143.8345, 5.148721, 7200, 0, 0), -- 15384 (Area: -1) +(@CGUID+2, 15384, 533, 3, 1, 3716.097, -5106.208, 141.373, 4.939282, 7200, 0, 0), -- 15384 (Area: -1) +(@CGUID+3, 15384, 533, 3, 1, 3777.213, -5066.177, 143.6412, 1.53589, 7200, 0, 0), -- 15384 (Area: -1) +(@CGUID+4, 15384, 533, 3, 1, 3732.598, -5028.03, 144.0342, 5.951573, 7200, 0, 0), -- 15384 (Area: -1) +(@CGUID+5, 15384, 533, 3, 1, 3700.7, -5182.372, 143.9172, 3.525565, 7200, 0, 0); -- 15384 (Area: -1) diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index 55f19d1612e..8b2365079c7 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -456,7 +456,7 @@ void AccountMgr::LoadRBAC() while (result->NextRow()); TC_LOG_DEBUG("rbac", "AccountMgr::LoadRBAC: Loading default permissions"); - result = LoginDatabase.Query("SELECT secId, permissionId FROM rbac_default_permissions ORDER BY secId ASC"); + result = LoginDatabase.PQuery("SELECT secId, permissionId FROM rbac_default_permissions WHERE (realmId = %u OR realmId = -1) ORDER BY secId ASC", realmHandle.Index); if (!result) { TC_LOG_INFO("server.loading", ">> Loaded 0 default permission definitions. DB table `rbac_default_permissions` is empty."); diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp index a0ff40c8a3c..e0416b56397 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/boss_archimonde.cpp @@ -25,10 +25,9 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" -#include "hyjal.h" -#include "SpellAuras.h" -#include "hyjal_trash.h" +#include "SpellScript.h" #include "Player.h" +#include "hyjal.h" enum Texts { @@ -39,44 +38,44 @@ enum Texts SAY_ENRAGE = 5, SAY_DEATH = 6, SAY_SOUL_CHARGE = 7, + // YELL_ARCHIMONDE_INTRO = 8 }; enum Spells { - SPELL_DENOUEMENT_WISP = 32124, - SPELL_ANCIENT_SPARK = 39349, - SPELL_PROTECTION_OF_ELUNE = 38528, - - SPELL_DRAIN_WORLD_TREE = 39140, - SPELL_DRAIN_WORLD_TREE_2 = 39141, - - SPELL_FINGER_OF_DEATH = 31984, - SPELL_HAND_OF_DEATH = 35354, - SPELL_AIR_BURST = 32014, - SPELL_GRIP_OF_THE_LEGION = 31972, - SPELL_DOOMFIRE_STRIKE = 31903, //summons two creatures - SPELL_DOOMFIRE_SPAWN = 32074, - SPELL_DOOMFIRE = 31945, - SPELL_SOUL_CHARGE_YELLOW = 32045, - SPELL_SOUL_CHARGE_GREEN = 32051, - SPELL_SOUL_CHARGE_RED = 32052, - SPELL_UNLEASH_SOUL_YELLOW = 32054, - SPELL_UNLEASH_SOUL_GREEN = 32057, - SPELL_UNLEASH_SOUL_RED = 32053, - SPELL_FEAR = 31970, + SPELL_DENOUEMENT_WISP = 32124, + SPELL_ANCIENT_SPARK = 39349, + SPELL_PROTECTION_OF_ELUNE = 38528, + + SPELL_DRAIN_WORLD_TREE = 39140, + SPELL_DRAIN_WORLD_TREE_TRIGGERED = 39141, + + SPELL_FINGER_OF_DEATH = 31984, + SPELL_HAND_OF_DEATH = 35354, + SPELL_AIR_BURST = 32014, + SPELL_GRIP_OF_THE_LEGION = 31972, + SPELL_DOOMFIRE_STRIKE = 31903, // summons two creatures + SPELL_DOOMFIRE_SPAWN = 32074, + SPELL_DOOMFIRE = 31945, + SPELL_SOUL_CHARGE_YELLOW = 32045, + SPELL_SOUL_CHARGE_GREEN = 32051, + SPELL_SOUL_CHARGE_RED = 32052, + SPELL_UNLEASH_SOUL_YELLOW = 32054, + SPELL_UNLEASH_SOUL_GREEN = 32057, + SPELL_UNLEASH_SOUL_RED = 32053, + SPELL_FEAR = 31970 }; enum Events { - EVENT_DRAIN_NORDRASSIL = 1, - EVENT_HAND_OF_DEATH, // Raid wiper + EVENT_HAND_OF_DEATH = 1, // Raid wiper EVENT_UNLEASH_SOUL_CHARGE, EVENT_FINGER_OF_DEATH, EVENT_GRIP_OF_THE_LEGION, EVENT_FEAR, EVENT_AIR_BURST, EVENT_DOOMFIRE, - EVENT_DISTANCE_CHECK, // This checks if he's too close to the World Tree (75 yards from a point on the tree), if true then he will enrage + EVENT_DISTANCE_CHECK, // This checks if he's too close to the World Tree (75 yards from a point on the tree), if true then he will enrage EVENT_SUMMON_WHISP }; @@ -84,8 +83,7 @@ enum Summons { NPC_DOOMFIRE = 18095, NPC_DOOMFIRE_SPIRIT = 18104, - NPC_ANCIENT_WISP = 17946, - NPC_CHANNEL_TARGET = 22418 + NPC_ANCIENT_WISP = 17946 }; enum Actions @@ -94,8 +92,6 @@ enum Actions ACTION_CHANNEL_WORLD_TREE }; -Position const NordrassilLoc = {5503.713f, -3523.436f, 1608.781f, 0.0f}; - class npc_ancient_wisp : public CreatureScript { public: @@ -220,7 +216,6 @@ public: } void MoveInLineOfSight(Unit* who) override - { //will update once TargetGUID is 0. In case noone actually moves(not likely) and this is 0 //when UpdateAI needs it, it will be forced to select randomPoint @@ -279,10 +274,9 @@ public: void Initialize() { DoomfireSpiritGUID.Clear(); - WorldTreeGUID.Clear(); SoulChargeCount = 0; - WispCount = 0; // When ~30 wisps are summoned, Archimonde dies + WispCount = 0; // When ~30 wisps are summoned, Archimonde dies _unleashSpell = 0; _chargeSpell = 0; @@ -290,13 +284,17 @@ public: HasProtected = false; } + void InitializeAI() override + { + BossAI::InitializeAI(); + DoAction(ACTION_CHANNEL_WORLD_TREE); + } + void Reset() override { Initialize(); _Reset(); me->RemoveAllAuras(); // Reset Soul Charge auras. - if (!me->isMoving()) - DoAction(ACTION_CHANNEL_WORLD_TREE); } void EnterCombat(Unit* /*who*/) override @@ -317,11 +315,6 @@ public: { switch (eventId) { - case EVENT_DRAIN_NORDRASSIL: - if (Unit* Nordrassil = ObjectAccessor::GetUnit(*me, WorldTreeGUID)) - Nordrassil->CastSpell(me, SPELL_DRAIN_WORLD_TREE_2, true); - events.ScheduleEvent(EVENT_DRAIN_NORDRASSIL, 1000); - break; case EVENT_HAND_OF_DEATH: DoCastAOE(SPELL_HAND_OF_DEATH); events.ScheduleEvent(EVENT_HAND_OF_DEATH, 2000); @@ -387,7 +380,7 @@ public: events.ScheduleEvent(EVENT_DOOMFIRE, 20000); break; case EVENT_DISTANCE_CHECK: - if (Creature* channelTrigger = ObjectAccessor::GetCreature(*me, WorldTreeGUID)) + if (Creature* channelTrigger = instance->GetCreature(DATA_CHANNEL_TARGET)) if (me->IsWithinDistInMap(channelTrigger, 75.0f)) DoAction(ACTION_ENRAGE); events.ScheduleEvent(EVENT_DISTANCE_CHECK, 5000); @@ -503,18 +496,7 @@ public: Talk(SAY_ENRAGE); break; case ACTION_CHANNEL_WORLD_TREE: - if (Creature* temp = me->SummonCreature(NPC_CHANNEL_TARGET, NordrassilLoc, TEMPSUMMON_TIMED_DESPAWN, 1200000)) - { - WorldTreeGUID = temp->GetGUID(); - - if (Unit* Nordrassil = ObjectAccessor::GetUnit(*me, WorldTreeGUID)) - { - Nordrassil->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); - Nordrassil->SetDisplayId(11686); - DoCast(Nordrassil, SPELL_DRAIN_WORLD_TREE); - } - events.ScheduleEvent(EVENT_DRAIN_NORDRASSIL, 1000); - } + DoCastAOE(SPELL_DRAIN_WORLD_TREE, true); break; default: break; @@ -538,7 +520,6 @@ public: private: ObjectGuid DoomfireSpiritGUID; - ObjectGuid WorldTreeGUID; uint8 SoulChargeCount; uint8 WispCount; uint32 _chargeSpell; @@ -553,10 +534,46 @@ public: } }; +// 39142 - Drain World Tree Dummy +class spell_archimonde_drain_world_tree_dummy : public SpellScriptLoader +{ + public: + spell_archimonde_drain_world_tree_dummy() : SpellScriptLoader("spell_archimonde_drain_world_tree_dummy") { } + + class spell_archimonde_drain_world_tree_dummy_SpellScript : public SpellScript + { + PrepareSpellScript(spell_archimonde_drain_world_tree_dummy_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_DRAIN_WORLD_TREE_TRIGGERED)) + return false; + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* target = GetHitUnit()) + target->CastSpell(GetCaster(), SPELL_DRAIN_WORLD_TREE_TRIGGERED, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_archimonde_drain_world_tree_dummy_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_archimonde_drain_world_tree_dummy_SpellScript(); + } +}; + void AddSC_boss_archimonde() { new boss_archimonde(); new npc_doomfire(); new npc_doomfire_targetting(); new npc_ancient_wisp(); + new spell_archimonde_drain_world_tree_dummy(); } diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.h b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.h index c5f4d4ae679..54a763573ed 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.h +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal.h @@ -44,7 +44,8 @@ enum DataTypes DATA_HORDE_RETREAT = 17, DATA_RAIDDAMAGE = 18, DATA_RESET_RAIDDAMAGE = 19, - TYPE_RETREAT = 20 + TYPE_RETREAT = 20, + DATA_CHANNEL_TARGET = 21 }; enum WorldStateIds @@ -77,7 +78,8 @@ enum CreaturesIds KAZROGAL = 17888, AZGALOR = 17842, ARCHIMONDE = 17968, - NPC_WORLD_TRIGGER_TINY = 21987 + NPC_WORLD_TRIGGER_TINY = 21987, + NPC_CHANNEL_TARGET = 22418 }; enum GameobjectIds @@ -89,5 +91,6 @@ enum GameobjectIds GO_ROARING_FLAME = 182592 }; -#endif +#define MINRAIDDAMAGE 700000 // minimal damage before trash can drop loot and reputation, resets if faction leader dies +#endif diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp index 56b79b6b3e1..0394b8535e5 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp @@ -26,7 +26,6 @@ enum Spells SPELL_METEOR = 33814, //infernal visual SPELL_IMMOLATION = 37059, SPELL_FLAME_BUFFET = 31724, - NPC_TRIGGER = 21987, //World Trigger (Tiny) MODEL_INVIS = 11686, //invisible model SPELL_DISEASE_CLOUD = 31607, SPELL_KNOCKDOWN = 31610, @@ -465,10 +464,7 @@ public: } if (!meteor) { - float x, y, z; - me->GetPosition(x, y, z); - Creature* trigger = me->SummonCreature(NPC_TRIGGER, x + 8, y + 8, z + 25 + rand32() % 10, me->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, 1000); - if (trigger) + if (Creature* trigger = me->SummonCreature(NPC_WORLD_TRIGGER_TINY, me->GetPositionWithOffset({ 8.0f, 8.0f, frand(25.0f, 35.0f), 0.0f }), TEMPSUMMON_TIMED_DESPAWN, 1000)) { trigger->SetVisible(false); trigger->setFaction(me->getFaction()); diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.h b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.h index 18122ba2b0c..62f82ebcee1 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.h +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.h @@ -21,8 +21,6 @@ #include "hyjal.h" #include "ScriptedEscortAI.h" -#define MINRAIDDAMAGE 700000//minimal damage before trash can drop loot and reputation, resets if faction leader dies - struct hyjal_trashAI : public npc_escortAI { hyjal_trashAI(Creature* creature); diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/instance_hyjal.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/instance_hyjal.cpp index bd3f4fc62cc..99b8515c6e8 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/instance_hyjal.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/instance_hyjal.cpp @@ -26,12 +26,7 @@ EndScriptData */ #include "ScriptMgr.h" #include "InstanceScript.h" #include "ScriptedCreature.h" -#include "hyjal_trash.h" -#include "Player.h" -#include "WorldPacket.h" -#include "Chat.h" -#include "WorldSession.h" -#include "Packets/ChatPackets.h" +#include "hyjal.h" /* Battle of Mount Hyjal encounters: 0 - Rage Winterchill event @@ -41,8 +36,16 @@ EndScriptData */ 4 - Archimonde event */ -#define YELL_EFFORTS "All of your efforts have been in vain, for the draining of the World Tree has already begun. Soon the heart of your world will beat no more." -#define YELL_EFFORTS_NAME "Archimonde" +enum Yells +{ + YELL_ARCHIMONDE_INTRO = 8 +}; + +ObjectData const creatureData[] = +{ + { NPC_CHANNEL_TARGET, DATA_CHANNEL_TARGET }, + { 0, 0 } // END +}; class instance_hyjal : public InstanceMapScript { @@ -59,6 +62,7 @@ public: instance_mount_hyjal_InstanceMapScript(Map* map) : InstanceScript(map) { SetHeaders(DataHeader); + LoadObjectData(creatureData, nullptr); memset(&m_auiEncounter, 0, sizeof(m_auiEncounter)); RaidDamage = 0; @@ -133,6 +137,8 @@ public: TyrandeWhisperwind = creature->GetGUID(); break; } + + InstanceScript::OnCreatureCreate(creature); } ObjectGuid GetGuidData(uint32 identifier) const override @@ -166,42 +172,18 @@ public: m_auiEncounter[2] = data; break; case DATA_AZGALOREVENT: + m_auiEncounter[3] = data; + if (data == DONE) { - m_auiEncounter[3] = data; - if (data == DONE) + instance->LoadGrid(5581.49f, -3445.63f); + if (Creature* archimonde = instance->GetCreature(Archimonde)) { - if (Creature* archimonde = instance->GetCreature(Archimonde)) - archimonde->SetVisible(true); - - if (ArchiYell) - break; - - ArchiYell = true; + archimonde->SetVisible(true); - Creature* creature = instance->GetCreature(Azgalor); - if (creature) + if (!ArchiYell) { - Creature* unit = creature->SummonCreature(NPC_WORLD_TRIGGER_TINY, creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000); - - Map* map = creature->GetMap(); - if (map->IsDungeon() && unit) - { - unit->SetVisible(false); - Map::PlayerList const &PlayerList = map->GetPlayers(); - if (PlayerList.isEmpty()) - return; - - for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) - { - if (Player* player = i->GetSource()) - { - WorldPackets::Chat::Chat packet; - ChatHandler::BuildChatPacket(&packet, CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, unit, player, YELL_EFFORTS); - player->SendDirectMessage(packet.Write()); - player->PlayDirectSound(10986, player); - } - } - } + ArchiYell = true; + archimonde->AI()->Talk(YELL_ARCHIMONDE_INTRO); } } } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp index 102d1f0fb5b..8c927dcb0ac 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp @@ -30,26 +30,23 @@ EndScriptData */ #include "naxxramas.h" #include "Player.h" -enum Yells +enum Texts { - //when shappiron dies. dialog between kel and lich king (in this order) - SAY_SAPP_DIALOG1 = 0, //not used - SAY_SAPP_DIALOG2_LICH = 1, //not used - SAY_SAPP_DIALOG3 = 2, //not used - SAY_SAPP_DIALOG4_LICH = 3, //not used - SAY_SAPP_DIALOG5 = 4, //not used - SAY_CAT_DIED = 5, //when cat dies, not used - //when each of the 4 wing bosses dies - SAY_TAUNT = 6, SAY_AGGRO = 7, SAY_SLAY = 8, SAY_DEATH = 9, SAY_CHAIN = 10, SAY_FROST_BLAST = 11, SAY_REQUEST_AID = 12, //start of phase 3 - SAY_ANSWER_REQUEST = 13, //lich king answer + EMOTE_PHASE_TWO = 13, SAY_SUMMON_MINIONS = 14, //start of phase 1 - SAY_SPECIAL = 15 + SAY_SPECIAL = 15, + + // The Lich King + SAY_ANSWER_REQUEST = 3, + + // Old World Trigger + SAY_GUARDIAN_SPAWNED = 0 }; enum Events @@ -70,7 +67,10 @@ enum Events EVENT_TRIGGER, EVENT_PHASE, - EVENT_MORTAL_WOUND + EVENT_MORTAL_WOUND, + + EVENT_ANSWER_REQUEST, + EVENT_SUMMON_GUARDIANS }; enum Spells @@ -123,6 +123,13 @@ enum Spells SPELL_MORTAL_WOUND = 28467 }; +enum Phases +{ + PHASE_ONE = 1, // Players move in the circle and Kel'Thuzad spawns his minions. + PHASE_TWO = 2, // Starts on a timer. + PHASE_THREE = 3 // At 45% health. +}; + enum Creatures { NPC_WASTE = 16427, // Soldiers of the Frozen Wastes @@ -270,15 +277,11 @@ public: void Initialize() { nGuardiansOfIcecrownCount = 0; - uiGuardiansOfIcecrownTimer = 5000; // 5 seconds for summoning each Guardian of Icecrown in phase 3 - Phase = 0; nAbomination = 0; nWeaver = 0; } - uint32 Phase; - uint32 uiGuardiansOfIcecrownTimer; uint32 uiFaction; uint8 nGuardiansOfIcecrownCount; @@ -345,7 +348,6 @@ public: void EnterCombat(Unit* /*who*/) override { me->setFaction(uiFaction); - _EnterCombat(); for (uint8 i = 0; i <= 3; ++i) { @@ -354,10 +356,10 @@ public: } DoCast(me, SPELL_KELTHUZAD_CHANNEL, false); Talk(SAY_SUMMON_MINIONS); - Phase = 1; me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NOT_SELECTABLE); me->SetFloatValue(UNIT_FIELD_COMBATREACH, 4); me->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, 4); + events.SetPhase(PHASE_ONE); events.ScheduleEvent(EVENT_TRIGGER, 5000); events.ScheduleEvent(EVENT_WASTE, 15000); events.ScheduleEvent(EVENT_ABOMIN, 30000); @@ -365,6 +367,23 @@ public: events.ScheduleEvent(EVENT_PHASE, 228000); } + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (events.IsInPhase(PHASE_TWO) && me->HealthBelowPctDamaged(45, damage)) + { + Talk(SAY_REQUEST_AID); + events.SetPhase(PHASE_THREE); + events.ScheduleEvent(EVENT_ANSWER_REQUEST, 4000); + + for (uint8 i = 0; i <= 3; ++i) + { + if (GameObject* portal = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_KELTHUZAD_PORTAL01 + i))) + if (portal->getLootState() == GO_READY) + portal->UseDoorOrButton(); + } + } + } + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) @@ -372,7 +391,7 @@ public: events.Update(diff); - if (Phase == 1) + if (events.IsInPhase(PHASE_ONE)) { while (uint32 eventId = events.ExecuteEvent()) { @@ -405,6 +424,7 @@ public: case EVENT_PHASE: events.Reset(); Talk(SAY_AGGRO); + Talk(EMOTE_PHASE_TWO); spawns.DespawnAll(); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NOT_SELECTABLE); me->CastStop(); @@ -417,7 +437,7 @@ public: events.ScheduleEvent(EVENT_BLAST, urand(60000, 120000)); if (GetDifficulty() == DIFFICULTY_25_N) events.ScheduleEvent(EVENT_CHAIN, urand(30000, 60000)); - Phase = 2; + events.SetPhase(PHASE_TWO); break; default: break; @@ -426,38 +446,6 @@ public: } else { - //start phase 3 when we are 45% health - if (Phase != 3) - { - if (HealthBelowPct(45)) - { - Phase = 3; - Talk(SAY_REQUEST_AID); - //here Lich King should respond to KelThuzad but I don't know which Creature to make talk - //so for now just make Kelthuzad says it. - Talk(SAY_ANSWER_REQUEST); - - for (uint8 i = 0; i <= 3; ++i) - { - if (GameObject* portal = ObjectAccessor::GetGameObject(*me, instance->GetGuidData(DATA_KELTHUZAD_PORTAL01 + i))) - if (portal->getLootState() == GO_READY) - portal->UseDoorOrButton(); - } - } - } - else if (nGuardiansOfIcecrownCount < RAID_MODE(2, 4)) - { - if (uiGuardiansOfIcecrownTimer <= diff) - { - /// @todo Add missing text - if (Creature* guardian = DoSummon(NPC_ICECROWN, Pos[RAND(2, 5, 8, 11)])) - guardian->SetFloatValue(UNIT_FIELD_COMBATREACH, 2); - ++nGuardiansOfIcecrownCount; - uiGuardiansOfIcecrownTimer = 5000; - } - else uiGuardiansOfIcecrownTimer -= diff; - } - if (me->HasUnitState(UNIT_STATE_CASTING)) return; @@ -609,6 +597,18 @@ public: Talk(SAY_FROST_BLAST); events.Repeat(30000, 90000); break; + case EVENT_ANSWER_REQUEST: + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_LICH_KING))) + lichKing->AI()->Talk(SAY_ANSWER_REQUEST); + events.ScheduleEvent(EVENT_SUMMON_GUARDIANS, 5000); + break; + case EVENT_SUMMON_GUARDIANS: + if (Creature* guardian = DoSummon(NPC_ICECROWN, Pos[RAND(2, 5, 8, 11)])) + guardian->SetFloatValue(UNIT_FIELD_COMBATREACH, 2); + ++nGuardiansOfIcecrownCount; + if (nGuardiansOfIcecrownCount < RAID_MODE(2, 4)) + events.ScheduleEvent(EVENT_SUMMON_GUARDIANS, 5000); + break; default: break; } diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index bada44b20a0..ce478cd0664 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -115,6 +115,7 @@ class instance_naxxramas : public InstanceMapScript minHorsemenDiedTime = 0; maxHorsemenDiedTime = 0; AbominationCount = 0; + CurrentWingTaunt = SAY_KELTHUZAD_FIRST_WING_TAUNT; playerDied = 0; } @@ -156,6 +157,9 @@ class instance_naxxramas : public InstanceMapScript case NPC_KEL_THUZAD: KelthuzadGUID = creature->GetGUID(); break; + case NPC_LICH_KING: + LichKingGUID = creature->GetGUID(); + break; default: break; } @@ -201,6 +205,9 @@ class instance_naxxramas : public InstanceMapScript case GO_KELTHUZAD_TRIGGER: KelthuzadTriggerGUID = go->GetGUID(); break; + case GO_ROOM_KELTHUZAD: + KelthuzadDoorGUID = go->GetGUID(); + break; default: break; } @@ -242,6 +249,15 @@ class instance_naxxramas : public InstanceMapScript playerDied = 1; SaveToDB(); } + + if (Creature* creature = unit->ToCreature()) + if (creature->GetEntry() == NPC_BIGGLESWORTH) + { + // Loads Kel'Thuzad's grid. We need this as he must be active in order for his texts to work. + instance->LoadGrid(3749.67f, -5114.06f); + if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID)) + kelthuzad->AI()->Talk(SAY_KELTHUZAD_CAT_DIED); + } } void SetData(uint32 id, uint32 value) override @@ -327,6 +343,8 @@ class instance_naxxramas : public InstanceMapScript return PortalsGUID[3]; case DATA_KELTHUZAD_TRIGGER: return KelthuzadTriggerGUID; + case DATA_LICH_KING: + return LichKingGUID; } return ObjectGuid::Empty; @@ -337,18 +355,131 @@ class instance_naxxramas : public InstanceMapScript if (!InstanceScript::SetBossState(id, state)) return false; - if (id == BOSS_HORSEMEN && state == DONE) + switch (id) { - if (GameObject* horsemenChest = instance->GetGameObject(HorsemenChestGUID)) - { - horsemenChest->SetRespawnTime(horsemenChest->GetRespawnDelay()); - horsemenChest->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - } + case BOSS_MAEXXNA: + case BOSS_LOATHEB: + case BOSS_THADDIUS: + if (state == DONE) + events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000); + break; + case BOSS_GOTHIK: + if (state == DONE) + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ, 10000); + break; + case BOSS_HORSEMEN: + if (state == DONE) + { + if (GameObject* horsemenChest = instance->GetGameObject(HorsemenChestGUID)) + { + horsemenChest->SetRespawnTime(horsemenChest->GetRespawnDelay()); + horsemenChest->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + } + events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000); + } + break; + case BOSS_SAPPHIRON: + if (state == DONE) + events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD, 6000); + break; + default: + break; } return true; } + void Update(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_DIALOGUE_GOTHIK_KORTHAZZ: + if (Creature* korthazz = instance->GetCreature(ThaneGUID)) + korthazz->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN); + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK, 5000); + break; + case EVENT_DIALOGUE_GOTHIK_ZELIEK: + if (Creature* zeliek = instance->GetCreature(SirGUID)) + zeliek->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN); + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX, 6000); + break; + case EVENT_DIALOGUE_GOTHIK_BLAUMEUX: + if (Creature* blaumeux = instance->GetCreature(LadyGUID)) + blaumeux->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN); + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE, 6000); + break; + case EVENT_DIALOGUE_GOTHIK_RIVENDARE: + if (Creature* rivendare = instance->GetCreature(BaronGUID)) + rivendare->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN); + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX2, 6000); + break; + case EVENT_DIALOGUE_GOTHIK_BLAUMEUX2: + if (Creature* blaumeux = instance->GetCreature(LadyGUID)) + blaumeux->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2); + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK2, 6000); + break; + case EVENT_DIALOGUE_GOTHIK_ZELIEK2: + if (Creature* zeliek = instance->GetCreature(SirGUID)) + zeliek->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2); + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ2, 6000); + break; + case EVENT_DIALOGUE_GOTHIK_KORTHAZZ2: + if (Creature* korthazz = instance->GetCreature(ThaneGUID)) + korthazz->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2); + events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE2, 6000); + break; + case EVENT_DIALOGUE_GOTHIK_RIVENDARE2: + if (Creature* rivendare = instance->GetCreature(BaronGUID)) + rivendare->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2); + break; + case EVENT_KELTHUZAD_WING_TAUNT: + // Loads Kel'Thuzad's grid. We need this as he must be active in order for his texts to work. + instance->LoadGrid(3749.67f, -5114.06f); + if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID)) + kelthuzad->AI()->Talk(CurrentWingTaunt); + ++CurrentWingTaunt; + break; + case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD: + if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID)) + kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD); + HandleGameObject(KelthuzadDoorGUID, false); + events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING, 6000); + break; + case EVENT_DIALOGUE_SAPPHIRON_LICHKING: + if (Creature* lichKing = instance->GetCreature(LichKingGUID)) + lichKing->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_LICH_KING); + events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD2, 16000); + break; + case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD2: + if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID)) + kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD2); + events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING2, 9000); + break; + case EVENT_DIALOGUE_SAPPHIRON_LICHKING2: + if (Creature* lichKing = instance->GetCreature(LichKingGUID)) + lichKing->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_LICH_KING2); + events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD3, 12000); + break; + case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD3: + if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID)) + kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD3); + events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD4, 6000); + break; + case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD4: + if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID)) + kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD4); + HandleGameObject(KelthuzadDoorGUID, true); + break; + default: + break; + } + } + } + void HeiganErupt(uint32 section) { for (uint32 i = 0; i < 4; ++i) @@ -450,10 +581,15 @@ class instance_naxxramas : public InstanceMapScript ObjectGuid KelthuzadGUID; ObjectGuid KelthuzadTriggerGUID; ObjectGuid PortalsGUID[4]; + ObjectGuid KelthuzadDoorGUID; + ObjectGuid LichKingGUID; uint8 AbominationCount; + uint8 CurrentWingTaunt; /* The Immortal / The Undying */ uint32 playerDied; + + EventMap events; }; InstanceScript* GetInstanceScript(InstanceMap* map) const override diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h index 8325271a403..eb77980f3ba 100644 --- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h +++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h @@ -71,6 +71,7 @@ enum Data64 DATA_KELTHUZAD_PORTAL03, DATA_KELTHUZAD_PORTAL04, DATA_KELTHUZAD_TRIGGER, + DATA_LICH_KING }; enum CreaturesIds @@ -89,7 +90,10 @@ enum CreaturesIds NPC_CRYPT_GUARD = 16573, NPC_NAXXRAMAS_FOLLOWER = 16505, NPC_FOLLOWER_WORSHIPPER = 16506, - NPC_DK_UNDERSTUDY = 16803 + NPC_DK_UNDERSTUDY = 16803, + NPC_BIGGLESWORTH = 16998, + NPC_LICH_KING = 16980, + NPC_OLD_WORLD_TRIGGER = 15384 }; enum GameObjectsIds @@ -142,6 +146,50 @@ enum SpellIds SPELL_SLIME = 28801 }; +enum InstanceEvents +{ + // Dialogue that happens after Gothik's death. + EVENT_DIALOGUE_GOTHIK_KORTHAZZ = 1, + EVENT_DIALOGUE_GOTHIK_ZELIEK, + EVENT_DIALOGUE_GOTHIK_BLAUMEUX, + EVENT_DIALOGUE_GOTHIK_RIVENDARE, + EVENT_DIALOGUE_GOTHIK_BLAUMEUX2, + EVENT_DIALOGUE_GOTHIK_ZELIEK2, + EVENT_DIALOGUE_GOTHIK_KORTHAZZ2, + EVENT_DIALOGUE_GOTHIK_RIVENDARE2, + + // Dialogue that happens after each wing. + EVENT_KELTHUZAD_WING_TAUNT, + + // Dialogue that happens after Sapphiron's death. + EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD, + EVENT_DIALOGUE_SAPPHIRON_LICHKING, + EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD2, + EVENT_DIALOGUE_SAPPHIRON_LICHKING2, + EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD3, + EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD4 +}; + +enum InstanceTexts +{ + // The Four Horsemen + SAY_DIALOGUE_GOTHIK_HORSEMAN = 5, + SAY_DIALOGUE_GOTHIK_HORSEMAN2 = 6, + + // Kel'Thuzad + SAY_DIALOGUE_SAPPHIRON_KELTHUZAD = 0, + SAY_DIALOGUE_SAPPHIRON_KELTHUZAD2 = 2, + SAY_DIALOGUE_SAPPHIRON_KELTHUZAD3 = 4, + SAY_DIALOGUE_SAPPHIRON_KELTHUZAD4 = 20, + + SAY_KELTHUZAD_CAT_DIED = 5, + SAY_KELTHUZAD_FIRST_WING_TAUNT = 16, + + // Lich King + SAY_DIALOGUE_SAPPHIRON_LICH_KING = 1, + SAY_DIALOGUE_SAPPHIRON_LICH_KING2 = 2 +}; + /* template<class AI> CreatureAI* GetNaxxramasAI(Creature* creature) diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp index c0760afec23..8c7d0c2797f 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp @@ -28,7 +28,7 @@ EndScriptData */ #include "SpellScript.h" #include "halls_of_lightning.h" -enum Yells +enum Texts { SAY_INTRO_1 = 0, SAY_INTRO_2 = 1, @@ -51,6 +51,21 @@ enum Spells SPELL_PULSING_SHOCKWAVE_AURA = 59414 }; +enum Events +{ + EVENT_ARC_LIGHTNING = 1, + EVENT_LIGHTNING_NOVA, + EVENT_RESUME_PULSING_SHOCKWAVE, + EVENT_INTRO_DIALOGUE +}; + +enum Phases +{ + // Phases are used to allow executing the intro event while UpdateVictim() returns false and convenience. + PHASE_INTRO = 1, + PHASE_NORMAL +}; + enum Misc { ACHIEV_TIMELY_DEATH_START_EVENT = 20384 @@ -65,57 +80,41 @@ class boss_loken : public CreatureScript public: boss_loken() : CreatureScript("boss_loken") { } - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<boss_lokenAI>(creature); - } - - struct boss_lokenAI : public ScriptedAI + struct boss_lokenAI : public BossAI { - boss_lokenAI(Creature* creature) : ScriptedAI(creature) + boss_lokenAI(Creature* creature) : BossAI(creature, DATA_LOKEN) { Initialize(); - instance = creature->GetInstanceScript(); + _isIntroDone = false; } void Initialize() { - m_uiArcLightning_Timer = 15000; - m_uiLightningNova_Timer = 20000; - m_uiResumePulsingShockwave_Timer = 1000; - - m_uiHealthAmountModifier = 1; + _healthAmountModifier = 1; } - InstanceScript* instance; - - uint32 m_uiArcLightning_Timer; - uint32 m_uiLightningNova_Timer; - uint32 m_uiResumePulsingShockwave_Timer; - - uint32 m_uiHealthAmountModifier; - void Reset() override { Initialize(); - - instance->SetBossState(DATA_LOKEN, NOT_STARTED); + _Reset(); instance->DoStopTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMELY_DEATH_START_EVENT); } void EnterCombat(Unit* /*who*/) override { + _EnterCombat(); Talk(SAY_AGGRO); - - instance->SetBossState(DATA_LOKEN, IN_PROGRESS); + events.SetPhase(PHASE_NORMAL); + events.ScheduleEvent(EVENT_ARC_LIGHTNING, 15000); + events.ScheduleEvent(EVENT_LIGHTNING_NOVA, 20000); + events.ScheduleEvent(EVENT_RESUME_PULSING_SHOCKWAVE, 1000); instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMELY_DEATH_START_EVENT); } void JustDied(Unit* /*killer*/) override { Talk(SAY_DEATH); - - instance->SetBossState(DATA_LOKEN, DONE); + _JustDied(); instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_PULSING_SHOCKWAVE_AURA); } @@ -125,66 +124,89 @@ public: Talk(SAY_SLAY); } - void UpdateAI(uint32 uiDiff) override + void MoveInLineOfSight(Unit* who) override { - //Return since we have no target - if (!UpdateVictim()) - return; - - if (m_uiResumePulsingShockwave_Timer) + if (!_isIntroDone && me->IsValidAttackTarget(who) && me->IsWithinDistInMap(who, 40.0f)) { - if (m_uiResumePulsingShockwave_Timer <= uiDiff) - { - DoCast(me, SPELL_PULSING_SHOCKWAVE_AURA, true); - me->ClearUnitState(UNIT_STATE_CASTING); // this flag breaks movement - - DoCast(me, SPELL_PULSING_SHOCKWAVE, true); - m_uiResumePulsingShockwave_Timer = 0; - } - else - m_uiResumePulsingShockwave_Timer -= uiDiff; + _isIntroDone = true; + Talk(SAY_INTRO_1); + events.ScheduleEvent(EVENT_INTRO_DIALOGUE, 20000, 0, PHASE_INTRO); } + BossAI::MoveInLineOfSight(who); + } - if (m_uiArcLightning_Timer <= uiDiff) - { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_ARC_LIGHTNING); + void UpdateAI(uint32 diff) override + { + if (events.IsInPhase(PHASE_NORMAL) && !UpdateVictim()) + return; - m_uiArcLightning_Timer = urand(15000, 16000); - } - else - m_uiArcLightning_Timer -= uiDiff; + events.Update(diff); - if (m_uiLightningNova_Timer <= uiDiff) + while (uint32 eventId = events.ExecuteEvent()) { - Talk(SAY_NOVA); - Talk(EMOTE_NOVA); - DoCast(me, SPELL_LIGHTNING_NOVA); - - me->RemoveAurasDueToSpell(SPELL_PULSING_SHOCKWAVE); - m_uiResumePulsingShockwave_Timer = DUNGEON_MODE(5000, 4000); // Pause Pulsing Shockwave aura - m_uiLightningNova_Timer = urand(20000, 21000); + switch (eventId) + { + case EVENT_ARC_LIGHTNING: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_ARC_LIGHTNING); + events.ScheduleEvent(EVENT_ARC_LIGHTNING, urand(15000, 16000)); + break; + case EVENT_LIGHTNING_NOVA: + Talk(SAY_NOVA); + Talk(EMOTE_NOVA); + DoCastAOE(SPELL_LIGHTNING_NOVA); + me->RemoveAurasDueToSpell(sSpellMgr->GetSpellIdForDifficulty(SPELL_PULSING_SHOCKWAVE, me)); + events.ScheduleEvent(EVENT_RESUME_PULSING_SHOCKWAVE, DUNGEON_MODE(5000, 4000)); // Pause Pulsing Shockwave aura + events.ScheduleEvent(EVENT_LIGHTNING_NOVA, urand(20000, 21000)); + break; + case EVENT_RESUME_PULSING_SHOCKWAVE: + DoCast(me, SPELL_PULSING_SHOCKWAVE_AURA, true); + me->ClearUnitState(UNIT_STATE_CASTING); // This flag breaks movement. + DoCast(me, SPELL_PULSING_SHOCKWAVE, true); + break; + case EVENT_INTRO_DIALOGUE: + Talk(SAY_INTRO_2); + events.SetPhase(PHASE_NORMAL); + break; + default: + break; + } } - else - m_uiLightningNova_Timer -= uiDiff; - // Health check - if (HealthBelowPct(100 - 25 * m_uiHealthAmountModifier)) + DoMeleeAttackIfReady(); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (me->HealthBelowPctDamaged(100 - 25 * _healthAmountModifier, damage)) { - switch (m_uiHealthAmountModifier) + switch (_healthAmountModifier) { - case 1: Talk(SAY_75HEALTH); break; - case 2: Talk(SAY_50HEALTH); break; - case 3: Talk(SAY_25HEALTH); break; + case 1: + Talk(SAY_75HEALTH); + break; + case 2: + Talk(SAY_50HEALTH); + break; + case 3: + Talk(SAY_25HEALTH); + break; + default: + break; } - - ++m_uiHealthAmountModifier; + ++_healthAmountModifier; } - - DoMeleeAttackIfReady(); } + + private: + uint32 _healthAmountModifier; + bool _isIntroDone; }; + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_lokenAI>(creature); + } }; class spell_loken_pulsing_shockwave : public SpellScriptLoader diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 36395d4d06e..1aefbfa13de 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -3034,7 +3034,7 @@ AuctionHouseBot.Buyer.Neutral.Chance.Ratio = 3 ################################################################################################### ################################################################################################### -# LOGGING SYSTEM SETTINGS +# LOGGING SYSTEM SETTINGS # # Appender config values: Given a appender "name" # Appender.name @@ -3192,67 +3192,6 @@ Allow.IP.Based.Action.Logging = 0 ################################################################################################### ################################################################################################### -# GUILD LEVELING SETTINGS -# -# Guild.LevelingEnabled -# Description: Controls whether guild can gain levels -# Default: 1 -# - -Guild.LevelingEnabled = 1 - -# -# Guild.SaveInterval -# Description: Time (in minutes) between guild experience saves -# Default: 15 -# - -Guild.SaveInterval = 15 - -# -# Guild.MaxLevel -# Description: Defines max level a guild can reach -# Default: 25 -# - -Guild.MaxLevel = 25 - -# -# Guild.UndeletableLevel -# Description: Guild reaching this level (and higher) cannot be disbanded anymore -# Default: 4 -# - -Guild.UndeletableLevel = 4 - -# -# Guild.XPModifier -# Description: Multiplier for guild experience gained from quests -# Default: 0.25 -# - -Guild.XPModifier = 0.25 - -# -# Guild.DailyXPCap -# Description: Maximum experience points a guild can earn each day -# Default: 7807500 -# - -Guild.DailyXPCap = 7807500 - -# -# Guild.WeeklyReputationCap -# Description: Maximum guild reputation a player can earn every week -# Default: 4375 -# - -Guild.WeeklyReputationCap = 4375 - -# -################################################################################################### - -################################################################################################### # CURRENCIES SETTINGS # # Currency.ResetInterval diff --git a/src/tools/connection_patcher/Program.cpp b/src/tools/connection_patcher/Program.cpp index 56007232d20..fe86936a95e 100644 --- a/src/tools/connection_patcher/Program.cpp +++ b/src/tools/connection_patcher/Program.cpp @@ -194,6 +194,11 @@ int main(int argc, char** argv) do_patches<Patches::Mac::x64, Patterns::Mac::x64> (&patcher, renamed_binary_path); + { + namespace fs = boost::filesystem; + fs::permissions(renamed_binary_path, fs::add_perms | fs::others_exe | fs::group_exe | fs::owner_exe); + } + do_module<Patches::Mac::x64, Patterns::Mac::x64> ( "97eeb2e28e9e56ed6a22d09f44e2ff43c93315e006bbad43bafc0defaa6f50ae.auth" , "/Users/Shared/Blizzard/Battle.net/Cache/" |
