Merge branch 'azerothcore:master' into Playerbot

This commit is contained in:
ZhengPeiRu21
2022-06-16 10:04:30 -06:00
committed by GitHub
53 changed files with 1362 additions and 693 deletions
@@ -0,0 +1,22 @@
-- DB update 2022_06_13_04 -> 2022_06_13_05
--
DELETE FROM `spell_dbc` WHERE `ID` = 24081;
INSERT INTO `spell_dbc` (`ID`, `Category`, `DispelType`, `Mechanic`, `Attributes`, `AttributesEx`, `AttributesEx2`, `AttributesEx3`, `AttributesEx4`, `AttributesEx5`, `AttributesEx6`, `AttributesEx7`, `ShapeshiftMask`, `unk_320_2`, `ShapeshiftExclude`, `unk_320_3`, `Targets`, `TargetCreatureType`, `RequiresSpellFocus`, `FacingCasterFlags`, `CasterAuraState`, `TargetAuraState`, `ExcludeCasterAuraState`, `ExcludeTargetAuraState`, `CasterAuraSpell`, `TargetAuraSpell`, `ExcludeCasterAuraSpell`, `ExcludeTargetAuraSpell`, `CastingTimeIndex`, `RecoveryTime`, `CategoryRecoveryTime`, `InterruptFlags`, `AuraInterruptFlags`, `ChannelInterruptFlags`, `ProcTypeMask`, `ProcChance`, `ProcCharges`, `MaxLevel`, `BaseLevel`, `SpellLevel`, `DurationIndex`, `PowerType`, `ManaCost`, `ManaCostPerLevel`, `ManaPerSecond`, `ManaPerSecondPerLevel`, `RangeIndex`, `Speed`, `ModalNextSpell`, `CumulativeAura`, `Totem_1`, `Totem_2`, `Reagent_1`, `Reagent_2`, `Reagent_3`, `Reagent_4`, `Reagent_5`, `Reagent_6`, `Reagent_7`, `Reagent_8`, `ReagentCount_1`, `ReagentCount_2`, `ReagentCount_3`, `ReagentCount_4`, `ReagentCount_5`, `ReagentCount_6`, `ReagentCount_7`, `ReagentCount_8`, `EquippedItemClass`, `EquippedItemSubclass`, `EquippedItemInvTypes`, `Effect_1`, `Effect_2`, `Effect_3`, `EffectDieSides_1`, `EffectDieSides_2`, `EffectDieSides_3`, `EffectRealPointsPerLevel_1`, `EffectRealPointsPerLevel_2`, `EffectRealPointsPerLevel_3`, `EffectBasePoints_1`, `EffectBasePoints_2`, `EffectBasePoints_3`, `EffectMechanic_1`, `EffectMechanic_2`, `EffectMechanic_3`, `ImplicitTargetA_1`, `ImplicitTargetA_2`, `ImplicitTargetA_3`, `ImplicitTargetB_1`, `ImplicitTargetB_2`, `ImplicitTargetB_3`, `EffectRadiusIndex_1`, `EffectRadiusIndex_2`, `EffectRadiusIndex_3`, `EffectAura_1`, `EffectAura_2`, `EffectAura_3`, `EffectAuraPeriod_1`, `EffectAuraPeriod_2`, `EffectAuraPeriod_3`, `EffectMultipleValue_1`, `EffectMultipleValue_2`, `EffectMultipleValue_3`, `EffectChainTargets_1`, `EffectChainTargets_2`, `EffectChainTargets_3`, `EffectItemType_1`, `EffectItemType_2`, `EffectItemType_3`, `EffectMiscValue_1`, `EffectMiscValue_2`, `EffectMiscValue_3`, `EffectMiscValueB_1`, `EffectMiscValueB_2`, `EffectMiscValueB_3`, `EffectTriggerSpell_1`, `EffectTriggerSpell_2`, `EffectTriggerSpell_3`, `EffectPointsPerCombo_1`, `EffectPointsPerCombo_2`, `EffectPointsPerCombo_3`, `EffectSpellClassMaskA_1`, `EffectSpellClassMaskA_2`, `EffectSpellClassMaskA_3`, `EffectSpellClassMaskB_1`, `EffectSpellClassMaskB_2`, `EffectSpellClassMaskB_3`, `EffectSpellClassMaskC_1`, `EffectSpellClassMaskC_2`, `EffectSpellClassMaskC_3`, `SpellVisualID_1`, `SpellVisualID_2`, `SpellIconID`, `ActiveIconID`, `SpellPriority`, `Name_Lang_enUS`, `Name_Lang_enGB`, `Name_Lang_koKR`, `Name_Lang_frFR`, `Name_Lang_deDE`, `Name_Lang_enCN`, `Name_Lang_zhCN`, `Name_Lang_enTW`, `Name_Lang_zhTW`, `Name_Lang_esES`, `Name_Lang_esMX`, `Name_Lang_ruRU`, `Name_Lang_ptPT`, `Name_Lang_ptBR`, `Name_Lang_itIT`, `Name_Lang_Unk`, `Name_Lang_Mask`, `NameSubtext_Lang_enUS`, `NameSubtext_Lang_enGB`, `NameSubtext_Lang_koKR`, `NameSubtext_Lang_frFR`, `NameSubtext_Lang_deDE`, `NameSubtext_Lang_enCN`, `NameSubtext_Lang_zhCN`, `NameSubtext_Lang_enTW`, `NameSubtext_Lang_zhTW`, `NameSubtext_Lang_esES`, `NameSubtext_Lang_esMX`, `NameSubtext_Lang_ruRU`, `NameSubtext_Lang_ptPT`, `NameSubtext_Lang_ptBR`, `NameSubtext_Lang_itIT`, `NameSubtext_Lang_Unk`, `NameSubtext_Lang_Mask`, `Description_Lang_enUS`, `Description_Lang_enGB`, `Description_Lang_koKR`, `Description_Lang_frFR`, `Description_Lang_deDE`, `Description_Lang_enCN`, `Description_Lang_zhCN`, `Description_Lang_enTW`, `Description_Lang_zhTW`, `Description_Lang_esES`, `Description_Lang_esMX`, `Description_Lang_ruRU`, `Description_Lang_ptPT`, `Description_Lang_ptBR`, `Description_Lang_itIT`, `Description_Lang_Unk`, `Description_Lang_Mask`, `AuraDescription_Lang_enUS`, `AuraDescription_Lang_enGB`, `AuraDescription_Lang_koKR`, `AuraDescription_Lang_frFR`, `AuraDescription_Lang_deDE`, `AuraDescription_Lang_enCN`, `AuraDescription_Lang_zhCN`, `AuraDescription_Lang_enTW`, `AuraDescription_Lang_zhTW`, `AuraDescription_Lang_esES`, `AuraDescription_Lang_esMX`, `AuraDescription_Lang_ruRU`, `AuraDescription_Lang_ptPT`, `AuraDescription_Lang_ptBR`, `AuraDescription_Lang_itIT`, `AuraDescription_Lang_Unk`, `AuraDescription_Lang_Mask`, `ManaCostPct`, `StartRecoveryCategory`, `StartRecoveryTime`, `MaxTargetLevel`, `SpellClassSet`, `SpellClassMask_1`, `SpellClassMask_2`, `SpellClassMask_3`, `MaxTargets`, `DefenseType`, `PreventionType`, `StanceBarOrder`, `EffectChainAmplitude_1`, `EffectChainAmplitude_2`, `EffectChainAmplitude_3`, `MinFactionID`, `MinReputation`, `RequiredAuraVision`, `RequiredTotemCategoryID_1`, `RequiredTotemCategoryID_2`, `RequiredAreasID`, `SchoolMask`, `RuneCostID`, `SpellMissileID`, `PowerDisplayID`, `EffectBonusMultiplier_1`, `EffectBonusMultiplier_2`, `EffectBonusMultiplier_3`, `SpellDescriptionVariableID`, `SpellDifficultyID`) VALUES
(24081, 0, 0, 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 28, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 15041, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Summon Spawn of Mar\'li', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 0, '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 0, '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 0, '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0);
DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_hatch_eggs', 'spell_enveloping_webs', 'spell_marli_transform');
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(24083, 'spell_hatch_eggs'),
(24110, 'spell_enveloping_webs'),
(24084, 'spell_marli_transform');
DELETE FROM `creature_text` WHERE `CreatureID` = 15041;
DELETE FROM `creature_text` WHERE `CreatureID` = 14510 AND `GroupID` = 4;
INSERT INTO `creature_text` (`CreatureID`,`GroupID`,`ID`,`Text`,`Type`,`Language`,`Probability`,`Emote`,`Duration`,`Sound`,`BroadcastTextId`,`TextRange`,`comment`) VALUES
(15041, 0, 0, '%s is fully grown!', 16, 0, 100, 0, 0, 0, 10445, 0, 'Spawn of Mar\'li - EMOTE_FULL_GROWN'),
(14510, 4, 0, 'The brood shall not fall!', 14, 0, 100, 0, 0, 0, 10444, 0, 'Mar\'li - SAY_TRANSFORM_BACK');
DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 13 AND `SourceEntry` IN (24082, 24083);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(13, 1, 24082, 0, 0, 31, 0, 5, 179985, 0, 0, 0, 0, '', 'Hatch Spider Egg targets Spider Egg'),
(13, 1, 24083, 0, 0, 31, 0, 5, 179985, 0, 0, 0, 0, '', 'Hatch Eggs targets Spider Egg');
@@ -0,0 +1,5 @@
-- DB update 2022_06_13_05 -> 2022_06_14_00
--
DELETE FROM `spell_script_names` WHERE `spell_id`=24684;
INSERT INTO `spell_script_names` VALUES
(24684,'spell_chain_burn');
@@ -0,0 +1,57 @@
-- DB update 2022_06_14_00 -> 2022_06_14_01
--
ALTER TABLE `gameobject_template_addon`
ADD COLUMN `artkit0` INT NOT NULL DEFAULT 0 AFTER `maxgold`,
ADD COLUMN `artkit1` INT NOT NULL DEFAULT 0 AFTER `artkit0`,
ADD COLUMN `artkit2` INT NOT NULL DEFAULT 0 AFTER `artkit1`,
ADD COLUMN `artkit3` INT NOT NULL DEFAULT 0 AFTER `artkit2`;
DROP TABLE IF EXISTS `gameobjectartkit_dbc`;
CREATE TABLE `gameobjectartkit_dbc`
(
`ID` INT NOT NULL DEFAULT 0,
`Texture_1` INT NOT NULL DEFAULT 0,
`Texture_2` INT NOT NULL DEFAULT 0,
`Texture_3` INT NOT NULL DEFAULT 0,
`Attach_Model_1` INT NOT NULL DEFAULT 0,
`Attach_Model_2` INT NOT NULL DEFAULT 0,
`Attach_Model_3` INT NOT NULL DEFAULT 0,
`Attach_Model_4` INT NOT NULL DEFAULT 0,
PRIMARY KEY (`ID`)
) ENGINE=MYISAM DEFAULT CHARSET=utf8mb4;
-- Note: All of these should be targetable by spells 46904 and 46903, but conditions are only set for Stormwind (damn Horde fanatics)
UPDATE `gameobject_template_addon` SET `artkit0` = 121, `artkit1` = 122 WHERE `entry` IN (
188352, -- Flame of Shattrath
188129, -- Flame of Silvermoon
188128, -- Flame of the Exodar
181567, -- Flame of the Wetlands
181566, -- Flame of Hillsbrad
181565, -- Flame of Westfall
181564, -- Flame of Silverpine
181563, -- Flame of Darkshore
181562, -- Flame of Stonetalon
181561, -- Flame of Ashenvale
181560, -- Flame of the Barrens
181349, -- Flame of the Scholomance
181348, -- Flame of Stratholme
181347, -- Flame of Blackrock Spire
181346, -- Flame of Dire Maul
181345, -- Flame of the Hinterlands
181344, -- Flame of the Blasted Lands
181343, -- Flame of Un'Goro
181342, -- Flame of Azshara
181341, -- Flame of Searing Gorge
181340, -- Flame of Winterspring
181339, -- Flame of Silithus
181338, -- Flame of the Plaguelands
181337, -- Flame of Thunder Bluff
181336, -- Flame of Orgrimmar
181335, -- Flame of the Undercity
181334, -- Flame of Darnassus
181333, -- Flame of Ironforge
181332 -- Flame of Stormwind
);
DELETE FROM `spell_script_names` WHERE `ScriptName`= "spell_banging_the_gong";
@@ -0,0 +1,13 @@
-- DB update 2022_06_14_01 -> 2022_06_14_02
--
UPDATE `spell_target_position` SET `PositionX`=-11688.5, `PositionY`=-1737.74, `PositionZ`=8.409842 WHERE `id` IN (24325, 24593);
DELETE FROM `event_scripts` WHERE `id`=9104;
DELETE FROM `spell_script_names` WHERE `spell_id`=24325;
INSERT INTO `spell_script_names` VALUES
(24325, 'spell_pagles_point_cast');
DELETE FROM `waypoint_data` WHERE `id`=151140;
INSERT INTO `waypoint_data` VALUES
(151140,1,-11697.263,-1759.001,10.364448,0,0,0,0,100,0),
(151140,2,-11689.899,-1776.087,12.593142,6.098,0,0,0,100,0);
@@ -0,0 +1,3 @@
-- DB update 2022_06_14_02 -> 2022_06_14_03
-- Update movement for Tarindralla
UPDATE `creature` SET `wander_distance` = 7, `MovementType` = 1 WHERE `guid` = 47347 AND `id1` = 1992;
@@ -0,0 +1,6 @@
-- DB update 2022_06_14_03 -> 2022_06_14_04
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 1540201) AND (`source_type` = 9) AND (`id` IN (4, 5, 6));
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`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(1540201, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 12, 15958, 4, 15000, 0, 0, 0, 8, 0, 0, 0, 0, 8750.1, -7129.7, 35.2976, 3.8041, 'Apprentice Mirveda - Actionlist - Summon Creature \'Gharsul the Remorseless\''),
(1540201, 9, 5, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 12, 15656, 4, 15000, 0, 0, 0, 8, 0, 0, 0, 0, 8753.61, -7133.15, 35, 3.8576, 'Apprentice Mirveda - Actionlist - Summon Creature \'Angershade\''),
(1540201, 9, 6, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 12, 15656, 4, 15000, 0, 0, 0, 8, 0, 0, 0, 0, 8747.14, -7125.71, 35.848, 3.8576, 'Apprentice Mirveda - Actionlist - Summon Creature \'Angershade\'');
@@ -0,0 +1,16 @@
-- DB update 2022_06_14_04 -> 2022_06_14_05
--
DELETE FROM `creature_text` WHERE `CreatureID`=15111 AND `GroupID` IN (0,1);
INSERT INTO `creature_text` (`CreatureID`, `ID`, `Text`, `Type`, `Probability`, `BroadcastTextId`) VALUES
(15111, 0, 'I gonna make you into mojo!', 12, 100, 10435),
(15111, 1, 'Troll mojo da strongest mojo!', 12, 100, 10437);
DELETE FROM `creature_template_spell` WHERE (`CreatureID` = 15111) AND (`Index` IN (0, 1));
INSERT INTO `creature_template_spell` (`CreatureID`, `Index`, `Spell`, `VerifiedBuild`) VALUES
(15111, 0, 24611, 0),
(15111, 1, 24612, 0);
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 15111;
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 15111) AND (`source_type` = 0) AND (`id` IN (3));
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`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(15111, 0, 3, 0, 4, 0, 15, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Mad Servant - On Aggro - Say Line GroupID 0');
@@ -0,0 +1,6 @@
-- DB update 2022_06_14_05 -> 2022_06_14_06
--
DELETE FROM `spell_group` WHERE `spell_id` IN (8042,20005);
INSERT INTO `spell_group` VALUES
(1014,8042,0),
(1014,20005,0);
@@ -0,0 +1,5 @@
-- DB update 2022_06_14_06 -> 2022_06_14_07
--
DELETE FROM `spell_script_names` WHERE `spell_id`=29341;
INSERT INTO `spell_script_names` VALUES
(29341,'spell_warl_shadowburn');
@@ -0,0 +1,24 @@
-- DB update 2022_06_14_07 -> 2022_06_14_08
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 4966;
DELETE FROM `smart_scripts` WHERE ((`entryorguid` = 496603) AND (`source_type` = 9) AND (`id` IN (0, 1, 2, 3))) OR ((`entryorguid` = 496600) AND (`source_type` = 9) AND (`id` IN (0, 1, 2, 3, 4, 5, 6))) OR ((`entryorguid` = 5184) AND (`source_type` = 0)) OR (`source_type` = 0 AND `entryorguid` = 4966 AND (`id` IN (0, 1, 2, 3, 4, 5, 6, 7)));
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`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(4966, 0, 0, 1, 11, 0, 100, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Private Hendel - On Respawn - Set Emote State 0'),
(4966, 0, 1, 2, 61, 0, 100, 512, 0, 0, 0, 0, 0, 82, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Private Hendel - On Respawn - Add Npc Flags Questgiver'),
(4966, 0, 2, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Private Hendel - On Respawn - Reset Invincibility Hp'),
(4966, 0, 3, 0, 19, 0, 100, 512, 1324, 0, 0, 0, 0, 80, 496600, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Private Hendel - On Quest \'The Missing Diplomat\' Taken - Run Script'),
(4966, 0, 4, 0, 7, 1, 100, 513, 0, 0, 0, 0, 0, 80, 496603, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Private Hendel - On Evade - Run Script (Phase 1) (No Repeat)'),
(4966, 0, 6, 0, 2, 1, 100, 512, 0, 20, 300, 500, 0, 80, 496601, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Private Hendel - Between 0-20% Health - Run Script (Phase 1)'),
(4966, 0, 7, 0, 40, 2, 100, 512, 1, 496600, 0, 0, 0, 80, 496602, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Private Hendel - On Waypoint 1 Reached - Run Script (Phase 2)'),
(496600, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 83, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Private Hendel - Actionlist - Remove Npc Flags Questgiver'),
(496600, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 42, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Private Hendel - Actionlist - Set Invincibility Hp 1'),
(496600, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 2, 168, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Private Hendel - Actionlist - Set Faction 168'),
(496600, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 45, 1, 1, 0, 0, 0, 0, 11, 5184, 50, 0, 0, 0, 0, 0, 0, 'Private Hendel - Actionlist - Set Data 1 1'),
(496600, 9, 4, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 64, 1, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Private Hendel - Actionlist - Store Targetlist'),
(496600, 9, 5, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Private Hendel - Actionlist - Start Attacking'),
(496600, 9, 6, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Private Hendel - Actionlist - Set Event Phase 1'),
(5184, 0, 0, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 11, 7165, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Theramore Sentry - On Aggro - Cast \'Battle Stance\''),
(5184, 0, 1, 0, 38, 0, 100, 513, 3, 3, 1, 2, 0, 41, 60000, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Theramore Sentry - On Data Set 3 3 - Despawn In 60000 ms (No Repeat)'),
(496603, 9, 0, 0, 0, 0, 100, 0, 2000, 2000, 0, 0, 0, 41, 1, 300, 0, 0, 0, 0, 19, 5184, 50, 0, 0, 0, 0, 0, 0, 'Private Hendel - Actionlist - Despawn In 1000 ms'),
(496603, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 6, 1324, 0, 0, 0, 0, 0, 12, 1, 0, 0, 0, 0, 0, 0, 0, 'Private Hendel - Actionlist - Fail Quest \'The Missing Diplomat\''),
(496603, 9, 2, 0, 0, 0, 100, 0, 1000, 1000, 0, 0, 0, 41, 1, 300, 0, 0, 0, 0, 19, 5184, 50, 0, 0, 0, 0, 0, 0, 'Private Hendel - Actionlist - Despawn Instant'),
(496603, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 41, 1, 300, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Private Hendel - Actionlist - Despawn Instant');
@@ -0,0 +1,3 @@
-- DB update 2022_06_14_08 -> 2022_06_15_00
DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_gen_proc_once_per_cast';
@@ -0,0 +1,3 @@
-- DB update 2022_06_15_00 -> 2022_06_15_01
-- Adjust drop rate of Ritual salve to 72% (based by a sniffer with 325 kills)
UPDATE `creature_loot_template` SET `Chance` = 72 WHERE `Entry` = 2953 AND `Item` = 6634;
@@ -0,0 +1,4 @@
-- DB update 2022_06_15_01 -> 2022_06_15_02
DELETE FROM `spell_script_names` WHERE `spell_id` = 24834;
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(24834, 'spell_shadow_bolt_whirl');
@@ -0,0 +1,3 @@
-- DB update 2022_06_15_02 -> 2022_06_16_00
UPDATE `quest_template_addon` SET `RewardMailTemplateID` = 107 WHERE (`ID` = 5237);
UPDATE `quest_template_addon` SET `RewardMailTemplateID` = 101 WHERE (`ID` = 5238);
@@ -0,0 +1,19 @@
-- DB update 2022_06_16_00 -> 2022_06_16_01
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE `entry` = 16332;
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 16332);
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`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(16332, 0, 0, 1, 1, 0, 100, 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassian Huntress - Out of Combat - Disable Combat Movement'),
(16332, 0, 1, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassian Huntress - Out of Combat - Stop Attacking'),
(16332, 0, 2, 0, 4, 0, 100, 0, 0, 0, 0, 0, 0, 11, 6660, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassian Huntress - On Aggro - Cast \'Shoot\''),
(16332, 0, 3, 4, 9, 0, 100, 0, 5, 30, 2300, 3900, 0, 11, 6660, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassian Huntress - Within 5-30 Range - Cast \'Shoot\''),
(16332, 0, 4, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 40, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassian Huntress - Within 5-30 Range - Set Sheath Ranged'),
(16332, 0, 5, 6, 9, 0, 100, 0, 25, 80, 0, 0, 0, 21, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassian Huntress - Within 25-80 Range - Enable Combat Movement'),
(16332, 0, 6, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 20, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassian Huntress - Within 25-80 Range - Start Attacking'),
(16332, 0, 7, 8, 9, 0, 100, 0, 0, 5, 0, 0, 0, 21, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassian Huntress - Within 0-5 Range - Enable Combat Movement'),
(16332, 0, 8, 9, 61, 0, 100, 0, 0, 0, 0, 0, 0, 40, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassian Huntress - Within 0-5 Range - Set Sheath Melee'),
(16332, 0, 9, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 20, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassian Huntress - Within 0-5 Range - Start Attacking'),
(16332, 0, 10, 0, 9, 0, 100, 0, 5, 15, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassian Huntress - Within 5-15 Range - Disable Combat Movement'),
(16332, 0, 11, 0, 9, 0, 100, 0, 0, 5, 5000, 9000, 0, 11, 11976, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassian Huntress - Within 0-5 Range - Cast \'Strike\''),
(16332, 0, 12, 13, 2, 0, 100, 0, 0, 15, 0, 0, 0, 21, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassian Huntress - Between 0-15% Health - Enable Combat Movement'),
(16332, 0, 13, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassian Huntress - Between 0-15% Health - Flee For Assist'),
(16332, 0, 14, 0, 7, 0, 100, 0, 0, 0, 0, 0, 0, 40, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Darnassian Huntress - On Evade - Set Sheath Melee');
@@ -0,0 +1,2 @@
-- DB update 2022_06_16_01 -> 2022_06_16_02
UPDATE `creature_template` SET `unit_flags` = `unit_flags`&~33554432 WHERE `entry` = 14467;
@@ -0,0 +1,4 @@
-- DB update 2022_06_16_02 -> 2022_06_16_03
--
UPDATE `creature_template` SET `unit_flags`=`unit_flags`|33554432,`flags_extra`=`flags_extra`|2 WHERE `entry`=13148;
@@ -0,0 +1,11 @@
-- DB update 2022_06_16_03 -> 2022_06_16_04
UPDATE `creature_template` SET `DamageModifier` = 29, `BaseAttackTime` = 1100 WHERE (`entry` = 15114);
UPDATE `creature_template` SET `DamageModifier` = 27, `BaseAttackTime` = 1300 WHERE (`entry` = 15083);
UPDATE `creature_template` SET `DamageModifier` = 24, `BaseAttackTime` = 2000 WHERE (`entry` = 15085);
UPDATE `creature_template` SET `DamageModifier` = 23, `BaseAttackTime` = 1108 WHERE (`entry` = 15084);
UPDATE `creature_template` SET `DamageModifier` = 20 WHERE `entry` IN (14834, 15082);
UPDATE `creature_template` SET `DamageModifier` = 17 WHERE `entry` IN (11382, 11380);
UPDATE `creature_template` SET `DamageModifier` = 15 WHERE `entry` IN (14517, 14515);
UPDATE `creature_template` SET `DamageModifier` = 14 WHERE `entry` IN (14510, 14507);
UPDATE `creature_template` SET `DamageModifier` = 13 WHERE (`entry` = 14509);
UPDATE `creature_template` SET `BaseAttackTime` = 1108 WHERE (`entry` = 15084);
@@ -0,0 +1,10 @@
-- DB update 2022_06_16_04 -> 2022_06_16_05
--
DELETE FROM `game_event_gameobject` WHERE `guid`=28704;
INSERT INTO `game_event_gameobject` VALUES
(27,28704),
(28,28704),
(29,28704),
(30,28704);
UPDATE `gameobject_template` SET `ScriptName`='go_brazier_of_madness' WHERE `entry`=180327;
@@ -0,0 +1,2 @@
-- DB update 2022_06_16_05 -> 2022_06_16_06
UPDATE `creature_template` SET `flags_extra` = `flags_extra`|4194304 WHERE `entry` = 15261;
@@ -0,0 +1,11 @@
-- DB update 2022_06_16_06 -> 2022_06_16_07
UPDATE `creature_template` SET `AIName`='SmartAI',`flags_extra`=2 WHERE `entry`=14989;
DELETE FROM `smart_scripts` WHERE `entryorguid`= 14989 AND `source_type`= 0 AND `id`= 0;
INSERT INTO `smart_scripts` (`entryorguid`, `event_type`, `event_flags`, `action_type`, `action_param1`, `target_type`, `comment`) VALUES
(14989, 54, 1, 11, 26744, 1, 'Poisonous Cloud - OOC - Cast \'Serverside - Poisonous Blood\'');
DELETE FROM `smart_scripts` WHERE `entryorguid`= 11357 AND `source_type`= 0 AND `id`= 2;
INSERT INTO `smart_scripts` (`entryorguid`, `id`, `event_type`, `event_flags`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `target_type`, `comment`) VALUES
(11357, 2, 6, 512, 12, 14989, 3, 10000, 1, 'Son of Hakkar - On Just Died - Summon \'Poisonous Cloud\'');
+4 -12
View File
@@ -134,14 +134,6 @@ void CreatureAI::DoZoneInCombat(Creature* creature /*= nullptr*/, float maxRange
{ {
creature->AddThreat(player, 0.0f); creature->AddThreat(player, 0.0f);
} }
/* Causes certain things to never leave the threat list (Priest Lightwell, etc):
for (Unit::ControlSet::const_iterator itr = player->m_Controlled.begin(); itr != player->m_Controlled.end(); ++itr)
{
creature->SetInCombatWith(*itr);
(*itr)->SetInCombatWith(creature);
creature->AddThreat(*itr, 0.0f);
}*/
} }
} }
} }
@@ -161,7 +153,7 @@ void CreatureAI::MoveInLineOfSight_Safe(Unit* who)
void CreatureAI::MoveInLineOfSight(Unit* who) void CreatureAI::MoveInLineOfSight(Unit* who)
{ {
if (me->GetVictim()) if (me->IsEngaged())
return; return;
// pussywizard: civilian, non-combat pet or any other NOT HOSTILE TO ANYONE (!) // pussywizard: civilian, non-combat pet or any other NOT HOSTILE TO ANYONE (!)
@@ -182,7 +174,7 @@ void CreatureAI::TriggerAlert(Unit const* who) const
if (!who || who->GetTypeId() != TYPEID_PLAYER) if (!who || who->GetTypeId() != TYPEID_PLAYER)
return; return;
// If this unit isn't an NPC, is already distracted, is in combat, is confused, stunned or fleeing, do nothing // If this unit isn't an NPC, is already distracted, is in combat, is confused, stunned or fleeing, do nothing
if (me->GetTypeId() != TYPEID_UNIT || me->IsInCombat() || me->HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING | UNIT_STATE_DISTRACTED)) if (me->GetTypeId() != TYPEID_UNIT || me->IsEngaged() || me->HasUnitState(UNIT_STATE_CONFUSED | UNIT_STATE_STUNNED | UNIT_STATE_FLEEING | UNIT_STATE_DISTRACTED))
return; return;
// Only alert for hostiles! // Only alert for hostiles!
if (me->IsCivilian() || me->HasReactState(REACT_PASSIVE) || !me->IsHostileTo(who) || !me->_IsTargetAcceptable(who)) if (me->IsCivilian() || me->HasReactState(REACT_PASSIVE) || !me->IsHostileTo(who) || !me->_IsTargetAcceptable(who))
@@ -253,7 +245,7 @@ void CreatureAI::SetGazeOn(Unit* target)
bool CreatureAI::UpdateVictimWithGaze() bool CreatureAI::UpdateVictimWithGaze()
{ {
if (!me->IsInCombat()) if (!me->IsEngaged())
return false; return false;
if (me->HasReactState(REACT_PASSIVE)) if (me->HasReactState(REACT_PASSIVE))
@@ -271,7 +263,7 @@ bool CreatureAI::UpdateVictimWithGaze()
bool CreatureAI::UpdateVictim() bool CreatureAI::UpdateVictim()
{ {
if (!me->IsInCombat()) if (!me->IsEngaged())
return false; return false;
if (!me->HasReactState(REACT_PASSIVE)) if (!me->HasReactState(REACT_PASSIVE))
+2 -1
View File
@@ -114,7 +114,7 @@ public:
// Called for reaction at stopping attack at no attackers or targets // Called for reaction at stopping attack at no attackers or targets
virtual void EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER); virtual void EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER);
// Called for reaction at enter to combat if not in combat yet (enemy can be nullptr) // Called for reaction when initially engaged
virtual void EnterCombat(Unit* /*victim*/) {} virtual void EnterCombat(Unit* /*victim*/) {}
// Called when the creature is killed // Called when the creature is killed
@@ -196,6 +196,7 @@ public:
virtual bool CanSeeAlways(WorldObject const* /*obj*/) { return false; } virtual bool CanSeeAlways(WorldObject const* /*obj*/) { return false; }
virtual bool CanBeSeen(Player const* /*seer*/) { return true; } virtual bool CanBeSeen(Player const* /*seer*/) { return true; }
virtual bool CanAlwaysBeDetectable(WorldObject const* /*seer*/) { return false; }
virtual void PetStopAttack() { } virtual void PetStopAttack() { }
@@ -574,7 +574,7 @@ void BossAI::TeleportCheaters()
void BossAI::JustSummoned(Creature* summon) void BossAI::JustSummoned(Creature* summon)
{ {
summons.Summon(summon); summons.Summon(summon);
if (me->IsInCombat()) if (me->IsEngaged())
DoZoneInCombat(summon); DoZoneInCombat(summon);
} }
+16 -16
View File
@@ -4044,18 +4044,18 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
break; break;
case SMART_EVENT_UPDATE_OOC: case SMART_EVENT_UPDATE_OOC:
if (me && me->IsInCombat()) if (me && me->IsEngaged())
return; return;
ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
break; break;
case SMART_EVENT_UPDATE_IC: case SMART_EVENT_UPDATE_IC:
if (!me || !me->IsInCombat()) if (!me || !me->IsEngaged())
return; return;
ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax); ProcessTimedAction(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax);
break; break;
case SMART_EVENT_HEALTH_PCT: case SMART_EVENT_HEALTH_PCT:
{ {
if (!me || !me->IsInCombat() || !me->GetMaxHealth()) if (!me || !me->IsEngaged() || !me->GetMaxHealth())
return; return;
uint32 perc = (uint32)me->GetHealthPct(); uint32 perc = (uint32)me->GetHealthPct();
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min) if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
@@ -4065,7 +4065,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
} }
case SMART_EVENT_TARGET_HEALTH_PCT: case SMART_EVENT_TARGET_HEALTH_PCT:
{ {
if (!me || !me->IsInCombat() || !me->GetVictim() || !me->GetVictim()->GetMaxHealth()) if (!me || !me->IsEngaged() || !me->GetVictim() || !me->GetVictim()->GetMaxHealth())
return; return;
uint32 perc = (uint32)me->GetVictim()->GetHealthPct(); uint32 perc = (uint32)me->GetVictim()->GetHealthPct();
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min) if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
@@ -4075,7 +4075,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
} }
case SMART_EVENT_MANA_PCT: case SMART_EVENT_MANA_PCT:
{ {
if (!me || !me->IsInCombat() || !me->GetMaxPower(POWER_MANA)) if (!me || !me->IsEngaged() || !me->GetMaxPower(POWER_MANA))
return; return;
uint32 perc = uint32(me->GetPowerPct(POWER_MANA)); uint32 perc = uint32(me->GetPowerPct(POWER_MANA));
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min) if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
@@ -4085,7 +4085,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
} }
case SMART_EVENT_TARGET_MANA_PCT: case SMART_EVENT_TARGET_MANA_PCT:
{ {
if (!me || !me->IsInCombat() || !me->GetVictim() || !me->GetVictim()->GetMaxPower(POWER_MANA)) if (!me || !me->IsEngaged() || !me->GetVictim() || !me->GetVictim()->GetMaxPower(POWER_MANA))
return; return;
uint32 perc = uint32(me->GetVictim()->GetPowerPct(POWER_MANA)); uint32 perc = uint32(me->GetVictim()->GetPowerPct(POWER_MANA));
if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min) if (perc > e.event.minMaxRepeat.max || perc < e.event.minMaxRepeat.min)
@@ -4095,7 +4095,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
} }
case SMART_EVENT_RANGE: case SMART_EVENT_RANGE:
{ {
if (!me || !me->IsInCombat() || !me->GetVictim()) if (!me || !me->IsEngaged() || !me->GetVictim())
return; return;
if (me->IsInRange(me->GetVictim(), (float)e.event.minMaxRepeat.min, (float)e.event.minMaxRepeat.max)) if (me->IsInRange(me->GetVictim(), (float)e.event.minMaxRepeat.min, (float)e.event.minMaxRepeat.max))
@@ -4106,7 +4106,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
} }
case SMART_EVENT_VICTIM_CASTING: case SMART_EVENT_VICTIM_CASTING:
{ {
if (!me || !me->IsInCombat()) if (!me || !me->IsEngaged())
return; return;
Unit* victim = me->GetVictim(); Unit* victim = me->GetVictim();
@@ -4124,7 +4124,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
} }
case SMART_EVENT_FRIENDLY_HEALTH: case SMART_EVENT_FRIENDLY_HEALTH:
{ {
if (!me || !me->IsInCombat()) if (!me || !me->IsEngaged())
return; return;
Unit* target = DoSelectLowestHpFriendly((float)e.event.friendlyHealth.radius, e.event.friendlyHealth.hpDeficit); Unit* target = DoSelectLowestHpFriendly((float)e.event.friendlyHealth.radius, e.event.friendlyHealth.hpDeficit);
@@ -4139,7 +4139,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
} }
case SMART_EVENT_FRIENDLY_IS_CC: case SMART_EVENT_FRIENDLY_IS_CC:
{ {
if (!me || !me->IsInCombat()) if (!me || !me->IsEngaged())
return; return;
std::list<Creature*> pList; std::list<Creature*> pList;
@@ -4285,7 +4285,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
} }
case SMART_EVENT_OOC_LOS: case SMART_EVENT_OOC_LOS:
{ {
if (!me || me->IsInCombat()) if (!me || me->IsEngaged())
return; return;
//can trigger if closer than fMaxAllowedRange //can trigger if closer than fMaxAllowedRange
float range = (float)e.event.los.maxDist; float range = (float)e.event.los.maxDist;
@@ -4309,7 +4309,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
} }
case SMART_EVENT_IC_LOS: case SMART_EVENT_IC_LOS:
{ {
if (!me || !me->IsInCombat()) if (!me || !me->IsEngaged())
return; return;
//can trigger if closer than fMaxAllowedRange //can trigger if closer than fMaxAllowedRange
float range = (float)e.event.los.maxDist; float range = (float)e.event.los.maxDist;
@@ -4507,7 +4507,7 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
} }
case SMART_EVENT_FRIENDLY_HEALTH_PCT: case SMART_EVENT_FRIENDLY_HEALTH_PCT:
{ {
if (!me || !me->IsInCombat()) if (!me || !me->IsEngaged())
return; return;
Unit* target = nullptr; Unit* target = nullptr;
@@ -4701,10 +4701,10 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff)
if (e.event.event_phase_mask && !IsInPhase(e.event.event_phase_mask)) if (e.event.event_phase_mask && !IsInPhase(e.event.event_phase_mask))
return; return;
if (e.GetEventType() == SMART_EVENT_UPDATE_IC && (!me || !me->IsInCombat())) if (e.GetEventType() == SMART_EVENT_UPDATE_IC && (!me || !me->IsEngaged()))
return; return;
if (e.GetEventType() == SMART_EVENT_UPDATE_OOC && (me && me->IsInCombat()))//can be used with me=nullptr (go script) if (e.GetEventType() == SMART_EVENT_UPDATE_OOC && (me && me->IsEngaged()))//can be used with me=nullptr (go script)
return; return;
if (e.timer < diff) if (e.timer < diff)
@@ -4982,7 +4982,7 @@ void SmartScript::OnMoveInLineOfSight(Unit* who)
if (!me) if (!me)
return; return;
ProcessEventsFor(me->IsInCombat() ? SMART_EVENT_IC_LOS : SMART_EVENT_OOC_LOS, who); ProcessEventsFor(me->IsEngaged() ? SMART_EVENT_IC_LOS : SMART_EVENT_OOC_LOS, who);
} }
/* /*
+3
View File
@@ -86,6 +86,8 @@ static FactionTeamMap sFactionTeamMap;
DBCStorage <FactionEntry> sFactionStore(FactionEntryfmt); DBCStorage <FactionEntry> sFactionStore(FactionEntryfmt);
DBCStorage <FactionTemplateEntry> sFactionTemplateStore(FactionTemplateEntryfmt); DBCStorage <FactionTemplateEntry> sFactionTemplateStore(FactionTemplateEntryfmt);
DBCStorage <GameObjectArtKitEntry> sGameObjectArtKitStore(GameObjectArtKitfmt);
DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore(GameObjectDisplayInfofmt); DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore(GameObjectDisplayInfofmt);
DBCStorage <GemPropertiesEntry> sGemPropertiesStore(GemPropertiesEntryfmt); DBCStorage <GemPropertiesEntry> sGemPropertiesStore(GemPropertiesEntryfmt);
DBCStorage <GlyphPropertiesEntry> sGlyphPropertiesStore(GlyphPropertiesfmt); DBCStorage <GlyphPropertiesEntry> sGlyphPropertiesStore(GlyphPropertiesfmt);
@@ -306,6 +308,7 @@ void LoadDBCStores(const std::string& dataPath)
LOAD_DBC(sEmotesTextSoundStore, "EmotesTextSound.dbc", "emotetextsound_dbc"); LOAD_DBC(sEmotesTextSoundStore, "EmotesTextSound.dbc", "emotetextsound_dbc");
LOAD_DBC(sFactionStore, "Faction.dbc", "faction_dbc"); LOAD_DBC(sFactionStore, "Faction.dbc", "faction_dbc");
LOAD_DBC(sFactionTemplateStore, "FactionTemplate.dbc", "factiontemplate_dbc"); LOAD_DBC(sFactionTemplateStore, "FactionTemplate.dbc", "factiontemplate_dbc");
LOAD_DBC(sGameObjectArtKitStore, "GameObjectArtKit.dbc", "gameobjectartkit_dbc");
LOAD_DBC(sGameObjectDisplayInfoStore, "GameObjectDisplayInfo.dbc", "gameobjectdisplayinfo_dbc"); LOAD_DBC(sGameObjectDisplayInfoStore, "GameObjectDisplayInfo.dbc", "gameobjectdisplayinfo_dbc");
LOAD_DBC(sGemPropertiesStore, "GemProperties.dbc", "gemproperties_dbc"); LOAD_DBC(sGemPropertiesStore, "GemProperties.dbc", "gemproperties_dbc");
LOAD_DBC(sGlyphPropertiesStore, "GlyphProperties.dbc", "glyphproperties_dbc"); LOAD_DBC(sGlyphPropertiesStore, "GlyphProperties.dbc", "glyphproperties_dbc");
+1
View File
@@ -110,6 +110,7 @@ extern DBCStorage <EmotesTextEntry> sEmotesTextStore;
extern DBCStorage <EmotesTextSoundEntry> sEmotesTextSoundStore; extern DBCStorage <EmotesTextSoundEntry> sEmotesTextSoundStore;
extern DBCStorage <FactionEntry> sFactionStore; extern DBCStorage <FactionEntry> sFactionStore;
extern DBCStorage <FactionTemplateEntry> sFactionTemplateStore; extern DBCStorage <FactionTemplateEntry> sFactionTemplateStore;
extern DBCStorage <GameObjectArtKitEntry> sGameObjectArtKitStore;
extern DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore; extern DBCStorage <GameObjectDisplayInfoEntry> sGameObjectDisplayInfoStore;
extern DBCStorage <GemPropertiesEntry> sGemPropertiesStore; extern DBCStorage <GemPropertiesEntry> sGemPropertiesStore;
extern DBCStorage <GlyphPropertiesEntry> sGlyphPropertiesStore; extern DBCStorage <GlyphPropertiesEntry> sGlyphPropertiesStore;
+19 -5
View File
@@ -704,7 +704,7 @@ void Creature::Update(uint32 diff)
} }
// periodic check to see if the creature has passed an evade boundary // periodic check to see if the creature has passed an evade boundary
if (IsAIEnabled && !IsInEvadeMode() && IsInCombat()) if (IsAIEnabled && !IsInEvadeMode() && IsEngaged())
{ {
if (diff >= m_boundaryCheckTime) if (diff >= m_boundaryCheckTime)
{ {
@@ -1810,6 +1810,21 @@ bool Creature::CanAlwaysSee(WorldObject const* obj) const
return false; return false;
} }
bool Creature::IsAlwaysDetectableFor(WorldObject const* seer) const
{
if (Unit::IsAlwaysDetectableFor(seer))
{
return true;
}
if (IsAIEnabled && AI()->CanAlwaysBeDetectable(seer))
{
return true;
}
return false;
}
bool Creature::CanStartAttack(Unit const* who) const bool Creature::CanStartAttack(Unit const* who) const
{ {
if (IsCivilian()) if (IsCivilian())
@@ -1839,7 +1854,7 @@ bool Creature::CanStartAttack(Unit const* who) const
// pussywizard: at this point we are either hostile to who or friendly to who->getAttackerForHelper() // pussywizard: at this point we are either hostile to who or friendly to who->getAttackerForHelper()
// pussywizard: if who is in combat and has an attacker, help him if the distance is right (help because who is hostile or help because attacker is friendly) // pussywizard: if who is in combat and has an attacker, help him if the distance is right (help because who is hostile or help because attacker is friendly)
bool assist = false; bool assist = false;
if (who->IsInCombat() && IsWithinDist(who, ATTACK_DISTANCE)) if (who->IsEngaged() && IsWithinDist(who, ATTACK_DISTANCE))
if (Unit* victim = who->getAttackerForHelper()) if (Unit* victim = who->getAttackerForHelper())
if (IsWithinDistInMap(victim, sWorld->getFloatConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS))) if (IsWithinDistInMap(victim, sWorld->getFloatConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS)))
assist = true; assist = true;
@@ -2358,7 +2373,7 @@ bool Creature::CanAssistTo(Unit const* u, Unit const* enemy, bool checkfaction /
return false; return false;
// skip fighting creature // skip fighting creature
if (IsInCombat()) if (IsEngaged())
return false; return false;
// only free creature // only free creature
@@ -2409,11 +2424,10 @@ bool Creature::_IsTargetAcceptable(Unit const* target) const
return false; return false;
} }
Unit const* myVictim = getAttackerForHelper();
Unit const* targetVictim = target->getAttackerForHelper(); Unit const* targetVictim = target->getAttackerForHelper();
// if I'm already fighting target, or I'm hostile towards the target, the target is acceptable // if I'm already fighting target, or I'm hostile towards the target, the target is acceptable
if (myVictim == target || targetVictim == this || IsHostileTo(target)) if (IsEngagedBy(target) || IsHostileTo(target))
return true; return true;
// if the target's victim is friendly, and the target is neutral, the target is acceptable // if the target's victim is friendly, and the target is neutral, the target is acceptable
@@ -443,6 +443,7 @@ protected:
[[nodiscard]] bool IsInvisibleDueToDespawn() const override; [[nodiscard]] bool IsInvisibleDueToDespawn() const override;
bool CanAlwaysSee(WorldObject const* obj) const override; bool CanAlwaysSee(WorldObject const* obj) const override;
bool IsAlwaysDetectableFor(WorldObject const* seer) const override;
private: private:
void ForcedDespawn(uint32 timeMSToDespawn = 0, Seconds forcedRespawnTimer = 0s); void ForcedDespawn(uint32 timeMSToDespawn = 0, Seconds forcedRespawnTimer = 0s);
@@ -190,7 +190,7 @@ void CreatureGroup::RemoveMember(Creature* member)
member->SetFormation(nullptr); member->SetFormation(nullptr);
} }
void CreatureGroup::MemberAttackStart(Creature* member, Unit* target) void CreatureGroup::MemberEngagingTarget(Creature* member, Unit* target)
{ {
uint8 const groupAI = sFormationMgr->CreatureGroupMap[member->GetSpawnId()].groupAI; uint8 const groupAI = sFormationMgr->CreatureGroupMap[member->GetSpawnId()].groupAI;
if (member == m_leader) if (member == m_leader)
@@ -106,7 +106,7 @@ public:
void FormationReset(bool dismiss, bool initMotionMaster); void FormationReset(bool dismiss, bool initMotionMaster);
void LeaderMoveTo(float x, float y, float z, bool run); void LeaderMoveTo(float x, float y, float z, bool run);
void MemberAttackStart(Creature* member, Unit* target); void MemberEngagingTarget(Creature* member, Unit* target);
void MemberEvaded(Creature* member); void MemberEvaded(Creature* member);
private: private:
@@ -25,6 +25,7 @@
#include "Object.h" #include "Object.h"
#include "SharedDefines.h" #include "SharedDefines.h"
#include "Unit.h" #include "Unit.h"
#include <array>
class GameObjectAI; class GameObjectAI;
class Transport; class Transport;
@@ -676,6 +677,7 @@ struct GameObjectTemplateAddon
uint32 flags; uint32 flags;
uint32 mingold; uint32 mingold;
uint32 maxgold; uint32 maxgold;
std::array<uint32, 4> artKits = {};
}; };
// Benchmarked: Faster than std::map (insert/find) // Benchmarked: Faster than std::map (insert/find)
@@ -736,6 +738,35 @@ enum GOState
#define MAX_GO_STATE 3 #define MAX_GO_STATE 3
enum class GameObjectActions : uint32
{
// Name from client executable // Comments
None, // -NONE-
AnimateCustom0, // Animate Custom0
AnimateCustom1, // Animate Custom1
AnimateCustom2, // Animate Custom2
AnimateCustom3, // Animate Custom3
Disturb, // Disturb // Triggers trap
Unlock, // Unlock // Resets GO_FLAG_LOCKED
Lock, // Lock // Sets GO_FLAG_LOCKED
Open, // Open // Sets GO_STATE_ACTIVE
OpenAndUnlock, // Open + Unlock // Sets GO_STATE_ACTIVE and resets GO_FLAG_LOCKED
Close, // Close // Sets GO_STATE_READY
ToggleOpen, // Toggle Open
Destroy, // Destroy // Sets GO_STATE_DESTROYED
Rebuild, // Rebuild // Resets from GO_STATE_DESTROYED
Creation, // Creation
Despawn, // Despawn
MakeInert, // Make Inert // Disables interactions
MakeActive, // Make Active // Enables interactions
CloseAndLock, // Close + Lock // Sets GO_STATE_READY and sets GO_FLAG_LOCKED
UseArtKit0, // Use ArtKit0 // 46904: 121
UseArtKit1, // Use ArtKit1 // 36639: 81, 46903: 122
UseArtKit2, // Use ArtKit2
UseArtKit3, // Use ArtKit3
SetTapList, // Set Tap List
};
// from `gameobject` // from `gameobject`
struct GameObjectData struct GameObjectData
{ {
+2
View File
@@ -85,6 +85,8 @@ void Totem::InitStats(uint32 duration)
void Totem::InitSummon() void Totem::InitSummon()
{ {
Minion::InitSummon();
if (m_type == TOTEM_PASSIVE && GetSpell()) if (m_type == TOTEM_PASSIVE && GetSpell())
CastSpell(this, GetSpell(), true); CastSpell(this, GetSpell(), true);
+14 -2
View File
@@ -316,6 +316,8 @@ Unit::Unit(bool isWorldObject) : WorldObject(isWorldObject),
_oldFactionId = 0; _oldFactionId = 0;
_isWalkingBeforeCharm = false;
_lastExtraAttackSpell = 0; _lastExtraAttackSpell = 0;
} }
@@ -10482,8 +10484,12 @@ void Unit::SetCharm(Unit* charm, bool apply)
if (!charm->AddGuidValue(UNIT_FIELD_CHARMEDBY, GetGUID())) if (!charm->AddGuidValue(UNIT_FIELD_CHARMEDBY, GetGUID()))
LOG_FATAL("entities.unit", "Unit {} is being charmed, but it already has a charmer {}", charm->GetEntry(), charm->GetCharmerGUID().ToString()); LOG_FATAL("entities.unit", "Unit {} is being charmed, but it already has a charmer {}", charm->GetEntry(), charm->GetCharmerGUID().ToString());
if (charm->HasUnitMovementFlag(MOVEMENTFLAG_WALKING)) _isWalkingBeforeCharm = charm->IsWalking();
if (_isWalkingBeforeCharm)
{
charm->SetWalk(false); charm->SetWalk(false);
charm->SendMovementFlagUpdate();
}
m_Controlled.insert(charm); m_Controlled.insert(charm);
} }
@@ -10521,6 +10527,12 @@ void Unit::SetCharm(Unit* charm, bool apply)
charm->SetByteValue(UNIT_FIELD_BYTES_2, 1, 0); charm->SetByteValue(UNIT_FIELD_BYTES_2, 1, 0);
} }
if (charm->IsWalking() != _isWalkingBeforeCharm)
{
charm->SetWalk(_isWalkingBeforeCharm);
charm->SendMovementFlagUpdate(true); // send packet to self, to update movement state on player.
}
m_Controlled.erase(charm); m_Controlled.erase(charm);
} }
} }
@@ -13168,7 +13180,7 @@ void Unit::SetInCombatState(bool PvP, Unit* enemy, uint32 duration)
creature->AI()->EnterCombat(enemy); creature->AI()->EnterCombat(enemy);
if (creature->GetFormation()) if (creature->GetFormation())
creature->GetFormation()->MemberAttackStart(creature, enemy); creature->GetFormation()->MemberEngagingTarget(creature, enemy);
} }
creature->RefreshSwimmingFlag(); creature->RefreshSwimmingFlag();
+9 -2
View File
@@ -1326,6 +1326,7 @@ public:
bool IsWithinCombatRange(Unit const* obj, float dist2compare) const; bool IsWithinCombatRange(Unit const* obj, float dist2compare) const;
bool IsWithinMeleeRange(Unit const* obj, float dist = 0.f) const; bool IsWithinMeleeRange(Unit const* obj, float dist = 0.f) const;
float GetMeleeRange(Unit const* target) const; float GetMeleeRange(Unit const* target) const;
[[nodiscard]] virtual SpellSchoolMask GetMeleeDamageSchoolMask() const;
bool GetRandomContactPoint(Unit const* target, float& x, float& y, float& z, bool force = false) const; bool GetRandomContactPoint(Unit const* target, float& x, float& y, float& z, bool force = false) const;
uint32 m_extraAttacks; uint32 m_extraAttacks;
bool m_canDualWield; bool m_canDualWield;
@@ -1343,6 +1344,9 @@ public:
if (GetVictim() != nullptr) if (GetVictim() != nullptr)
return GetVictim(); return GetVictim();
if (!IsEngaged())
return nullptr;
if (!m_attackers.empty()) if (!m_attackers.empty())
return *(m_attackers.begin()); return *(m_attackers.begin());
@@ -1644,6 +1648,9 @@ public:
[[nodiscard]] bool IsInFlight() const { return HasUnitState(UNIT_STATE_IN_FLIGHT); } [[nodiscard]] bool IsInFlight() const { return HasUnitState(UNIT_STATE_IN_FLIGHT); }
bool IsEngaged() const { return IsInCombat(); }
bool IsEngagedBy(Unit const* who) const { return IsInCombatWith(who); }
[[nodiscard]] bool IsInCombat() const { return HasUnitFlag(UNIT_FLAG_IN_COMBAT); } [[nodiscard]] bool IsInCombat() const { return HasUnitFlag(UNIT_FLAG_IN_COMBAT); }
bool IsInCombatWith(Unit const* who) const; bool IsInCombatWith(Unit const* who) const;
@@ -2105,6 +2112,7 @@ public:
void TauntApply(Unit* victim); void TauntApply(Unit* victim);
void TauntFadeOut(Unit* taunter); void TauntFadeOut(Unit* taunter);
ThreatMgr& GetThreatMgr() { return m_ThreatMgr; } ThreatMgr& GetThreatMgr() { return m_ThreatMgr; }
ThreatMgr const& GetThreatMgr() const { return m_ThreatMgr; }
void addHatedBy(HostileReference* pHostileReference) { m_HostileRefMgr.insertFirst(pHostileReference); }; void addHatedBy(HostileReference* pHostileReference) { m_HostileRefMgr.insertFirst(pHostileReference); };
void removeHatedBy(HostileReference* /*pHostileReference*/) { /* nothing to do yet */ } void removeHatedBy(HostileReference* /*pHostileReference*/) { /* nothing to do yet */ }
HostileRefMgr& getHostileRefMgr() { return m_HostileRefMgr; } HostileRefMgr& getHostileRefMgr() { return m_HostileRefMgr; }
@@ -2478,8 +2486,6 @@ protected:
CharmInfo* m_charmInfo; CharmInfo* m_charmInfo;
SharedVisionList m_sharedVision; SharedVisionList m_sharedVision;
[[nodiscard]] virtual SpellSchoolMask GetMeleeDamageSchoolMask() const;
MotionMaster* i_motionMaster; MotionMaster* i_motionMaster;
uint32 m_reactiveTimer[MAX_REACTIVE]; uint32 m_reactiveTimer[MAX_REACTIVE];
@@ -2549,6 +2555,7 @@ private:
bool m_duringRemoveFromWorld; // lock made to not add stuff after begining removing from world bool m_duringRemoveFromWorld; // lock made to not add stuff after begining removing from world
uint32 _oldFactionId; ///< faction before charm uint32 _oldFactionId; ///< faction before charm
bool _isWalkingBeforeCharm; ///< Are we walking before we were charmed?
[[nodiscard]] float processDummyAuras(float TakenTotalMod) const; [[nodiscard]] float processDummyAuras(float TakenTotalMod) const;
+17 -2
View File
@@ -7183,8 +7183,8 @@ void ObjectMgr::LoadGameObjectTemplateAddons()
{ {
uint32 oldMSTime = getMSTime(); uint32 oldMSTime = getMSTime();
// 0 1 2 3 4 // 0 1 2 3 4 5 6 7 8
QueryResult result = WorldDatabase.Query("SELECT entry, faction, flags, mingold, maxgold FROM gameobject_template_addon"); QueryResult result = WorldDatabase.Query("SELECT entry, faction, flags, mingold, maxgold, artkit0, artkit1, artkit2, artkit3 FROM gameobject_template_addon");
if (!result) if (!result)
{ {
@@ -7215,6 +7215,21 @@ void ObjectMgr::LoadGameObjectTemplateAddons()
gameObjectAddon.mingold = fields[3].Get<uint32>(); gameObjectAddon.mingold = fields[3].Get<uint32>();
gameObjectAddon.maxgold = fields[4].Get<uint32>(); gameObjectAddon.maxgold = fields[4].Get<uint32>();
for (uint32 i = 0; i < gameObjectAddon.artKits.size(); i++)
{
uint32 artKitID = fields[5 + i].Get<uint32>();
if (!artKitID)
continue;
if (!sGameObjectArtKitStore.LookupEntry(artKitID))
{
LOG_ERROR("sql.sql", "GameObject (Entry: {}) has invalid `artkit{}` {} defined, set to zero instead.", entry, i, artKitID);
continue;
}
gameObjectAddon.artKits[i] = artKitID;
}
// checks // checks
if (gameObjectAddon.faction && !sFactionTemplateStore.LookupEntry(gameObjectAddon.faction)) if (gameObjectAddon.faction && !sFactionTemplateStore.LookupEntry(gameObjectAddon.faction))
LOG_ERROR("sql.sql", LOG_ERROR("sql.sql",
+67 -10
View File
@@ -2677,7 +2677,7 @@ void Spell::EffectDistract(SpellEffIndex /*effIndex*/)
return; return;
// Check for possible target // Check for possible target
if (!unitTarget || unitTarget->IsInCombat()) if (!unitTarget || unitTarget->IsEngaged())
return; return;
// target must be OK to do this // target must be OK to do this
@@ -4263,7 +4263,7 @@ void Spell::EffectSummonPlayer(SpellEffIndex /*effIndex*/)
player->GetSession()->SendPacket(&data); player->GetSession()->SendPacket(&data);
} }
void Spell::EffectActivateObject(SpellEffIndex /*effIndex*/) void Spell::EffectActivateObject(SpellEffIndex effIndex)
{ {
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
return; return;
@@ -4271,17 +4271,74 @@ void Spell::EffectActivateObject(SpellEffIndex /*effIndex*/)
if (!gameObjTarget) if (!gameObjTarget)
return; return;
Player* player = m_caster->GetTypeId() == TYPEID_PLAYER ? m_caster->ToPlayer() : m_caster->GetCharmerOrOwnerPlayerOrPlayerItself(); GameObjectActions action = GameObjectActions(m_spellInfo->Effects[effIndex].MiscValue);
gameObjTarget->Use(player ? player : m_caster); switch (action)
{
case GameObjectActions::AnimateCustom0:
case GameObjectActions::AnimateCustom1:
case GameObjectActions::AnimateCustom2:
case GameObjectActions::AnimateCustom3:
gameObjTarget->SendCustomAnim(uint32(action) - uint32(GameObjectActions::AnimateCustom0));
break;
case GameObjectActions::Disturb: // What's the difference with Open?
case GameObjectActions::Open:
if (Unit* unitCaster = m_caster->ToUnit())
gameObjTarget->Use(unitCaster);
break;
case GameObjectActions::OpenAndUnlock:
if (Unit* unitCaster = m_caster->ToUnit())
gameObjTarget->UseDoorOrButton(0, false, unitCaster);
[[fallthrough]];
case GameObjectActions::Unlock:
case GameObjectActions::Lock:
gameObjTarget->ApplyModFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED, action == GameObjectActions::Lock);
break;
case GameObjectActions::Close:
case GameObjectActions::Rebuild:
gameObjTarget->ResetDoorOrButton();
break;
case GameObjectActions::Despawn:
gameObjTarget->DespawnOrUnsummon();
break;
case GameObjectActions::MakeInert:
case GameObjectActions::MakeActive:
gameObjTarget->ApplyModFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE, action == GameObjectActions::MakeInert);
break;
case GameObjectActions::CloseAndLock:
gameObjTarget->ResetDoorOrButton();
gameObjTarget->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_LOCKED);
break;
case GameObjectActions::Destroy:
if (Unit* unitCaster = m_caster->ToUnit())
gameObjTarget->UseDoorOrButton(0, true, unitCaster);
break;
case GameObjectActions::UseArtKit0:
case GameObjectActions::UseArtKit1:
case GameObjectActions::UseArtKit2:
case GameObjectActions::UseArtKit3:
{
GameObjectTemplateAddon const* templateAddon = gameObjTarget->GetTemplateAddon();
//ScriptInfo activateCommand; uint32 artKitIndex = uint32(action) - uint32(GameObjectActions::UseArtKit0);
//activateCommand.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
// int32 unk = m_spellInfo->Effects[effIndex].MiscValue; // This is set for EffectActivateObject spells; needs research uint32 artKitValue = 0;
if (templateAddon)
artKitValue = templateAddon->artKits[artKitIndex];
// xinef: pass player to allow gossip scripts to work if (artKitValue == 0)
// LOG_ERROR("sql.sql", "GameObject {} hit by spell {} needs `artkit{}` in `gameobject_template_addon`", gameObjTarget->GetEntry(), m_spellInfo->Id, artKitIndex);
//gameObjTarget->GetMap()->ScriptCommandStart(activateCommand, 0, player ? player : m_caster, gameObjTarget); else
gameObjTarget->SetGoArtKit(artKitValue);
break;
}
case GameObjectActions::None:
LOG_FATAL("spell", "Spell {} has action type NONE in effect {}", m_spellInfo->Id, int32(effIndex));
break;
default:
LOG_ERROR("spell", "Spell {} has unhandled action {} in effect {}", m_spellInfo->Id, int32(action), int32(effIndex));
break;
}
} }
void Spell::EffectApplyGlyph(SpellEffIndex effIndex) void Spell::EffectApplyGlyph(SpellEffIndex effIndex)
@@ -339,7 +339,7 @@ struct boss_priestess_lackey_commonAI : public ScriptedAI
void EnterCombat(Unit* who) override void EnterCombat(Unit* who) override
{ {
if (Creature* delrissa = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_DELRISSA))) if (Creature* delrissa = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_DELRISSA)))
if (delrissa->IsAlive() && !delrissa->IsInCombat()) if (delrissa->IsAlive() && !delrissa->IsEngaged())
delrissa->AI()->AttackStart(who); delrissa->AI()->AttackStart(who);
events.ScheduleEvent(EVENT_SPELL_HELPER_HEALING_POTION, 1000); events.ScheduleEvent(EVENT_SPELL_HELPER_HEALING_POTION, 1000);
@@ -783,37 +783,9 @@ public:
} }
}; };
class spell_banging_the_gong : public SpellScriptLoader
{
public:
spell_banging_the_gong() : SpellScriptLoader("spell_banging_the_gong") { }
class spell_banging_the_gong_SpellScript : public SpellScript
{
PrepareSpellScript(spell_banging_the_gong_SpellScript);
void Activate(SpellEffIndex index)
{
PreventHitDefaultEffect(index);
GetHitGObj()->SendCustomAnim(0);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_banging_the_gong_SpellScript::Activate, EFFECT_1, SPELL_EFFECT_ACTIVATE_OBJECT);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_banging_the_gong_SpellScript();
}
};
void AddSC_zulaman() void AddSC_zulaman()
{ {
new npc_forest_frog(); new npc_forest_frog();
new npc_zulaman_hostage(); new npc_zulaman_hostage();
new npc_harrison_jones(); new npc_harrison_jones();
new spell_banging_the_gong();
} }
@@ -32,7 +32,8 @@ enum Spells
SPELL_FROSTBREATH = 16099, SPELL_FROSTBREATH = 16099,
SPELL_MASSIVEGEYSER = 22421, SPELL_MASSIVEGEYSER = 22421,
SPELL_SLAM = 24326, SPELL_SLAM = 24326,
SPELL_THRASH = 3417 // Triggers 3391 SPELL_THRASH = 3417, // Triggers 3391
SPELL_SPLASH = 24593
}; };
enum Events enum Events
@@ -42,6 +43,11 @@ enum Events
EVENT_SLAM = 3 EVENT_SLAM = 3
}; };
enum Misc
{
GAMEOBJECT_MUDSKUNK_LURE = 180346
};
class boss_gahzranka : public CreatureScript class boss_gahzranka : public CreatureScript
{ {
public: public:
@@ -51,6 +57,11 @@ public:
{ {
boss_gahzrankaAI(Creature* creature) : BossAI(creature, DATA_GAHZRANKA) { } boss_gahzrankaAI(Creature* creature) : BossAI(creature, DATA_GAHZRANKA) { }
void IsSummonedBy(Unit* /*summoner*/) override
{
me->GetMotionMaster()->MovePath(me->GetEntry() * 10, false);
}
void Reset() override void Reset() override
{ {
_Reset(); _Reset();
@@ -147,8 +158,45 @@ private:
bool _wipeThreat = false; bool _wipeThreat = false;
}; };
class spell_pagles_point_cast : public SpellScript
{
PrepareSpellScript(spell_pagles_point_cast);
void OnEffect(SpellEffIndex /*effIndex*/)
{
if (Unit* caster = GetCaster())
{
if (InstanceScript* instanceScript = caster->GetInstanceScript())
{
if (!instanceScript->GetData(DATA_GAHZRANKA))
{
caster->m_Events.AddEventAtOffset([caster]()
{
if (GameObject* lure = caster->SummonGameObject(GAMEOBJECT_MUDSKUNK_LURE, -11688.5f, -1737.74f, 10.409842f, 1.f, 0.f, 0.f, 0.f, 0.f, 30 * IN_MILLISECONDS))
{
caster->m_Events.AddEventAtOffset([caster, lure]()
{
if (lure)
lure->DespawnOrUnsummon();
caster->CastSpell(caster, SPELL_SPLASH, true);
caster->SummonCreature(NPC_GAHZRANKA, -11688.5f, -1723.74f, -5.78f, 0.f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5 * DAY * IN_MILLISECONDS);
}, 5s);
}
}, 2s);
}
}
}
}
void Register() override
{
OnEffectLaunch += SpellEffectFn(spell_pagles_point_cast::OnEffect, EFFECT_1, SPELL_EFFECT_SEND_EVENT);
}
};
void AddSC_boss_gahzranka() void AddSC_boss_gahzranka()
{ {
new boss_gahzranka(); new boss_gahzranka();
RegisterSpellScript(spell_gahzranka_slam); RegisterSpellScript(spell_gahzranka_slam);
RegisterSpellScript(spell_pagles_point_cast);
} }
@@ -24,19 +24,25 @@ EndScriptData */
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
#include "SpellScript.h"
#include "zulgurub.h" #include "zulgurub.h"
enum Spells enum Spells
{ {
SPELL_MANABURN = 26046, SPELL_SLEEP = 24664,
SPELL_SLEEP = 24664 SPELL_EARTH_SHOCK = 24685,
SPELL_CHAIN_BURN = 24684,
SPELL_SUMMON_NIGHTMARE_ILLUSION_LEFT = 24681,
SPELL_SUMMON_NIGHTMARE_ILLUSION_BACK = 24728,
SPELL_SUMMON_NIGHTMARE_ILLUSION_RIGHT = 24729
}; };
enum Events enum Events
{ {
EVENT_MANABURN = 1, EVENT_SLEEP = 1,
EVENT_SLEEP = 2, EVENT_EARTH_SHOCK = 2,
EVENT_ILLUSIONS = 3 EVENT_CHAIN_BURN = 3,
EVENT_ILLUSIONS = 4
}; };
class boss_hazzarah : public CreatureScript class boss_hazzarah : public CreatureScript
@@ -48,22 +54,42 @@ public:
{ {
boss_hazzarahAI(Creature* creature) : BossAI(creature, DATA_EDGE_OF_MADNESS) { } boss_hazzarahAI(Creature* creature) : BossAI(creature, DATA_EDGE_OF_MADNESS) { }
void Reset() override void JustSummoned(Creature* summon) override
{ {
_Reset(); summons.Summon(summon);
}
void JustDied(Unit* /*killer*/) override summon->SetCorpseDelay(10);
{ summon->SetReactState(REACT_PASSIVE);
_JustDied(); summon->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
summon->SetVisible(false);
summon->m_Events.AddEventAtOffset([summon]()
{
summon->SetVisible(true);
}, 2s);
summon->m_Events.AddEventAtOffset([summon]()
{
summon->RemoveUnitFlag(UNIT_FLAG_DISABLE_MOVE);
summon->SetReactState(REACT_AGGRESSIVE);
summon->SetInCombatWithZone();
}, 3500ms);
} }
void EnterCombat(Unit* /*who*/) override void EnterCombat(Unit* /*who*/) override
{ {
_EnterCombat(); _EnterCombat();
events.ScheduleEvent(EVENT_MANABURN, urand(4000, 10000)); events.ScheduleEvent(EVENT_SLEEP, 12s, 15s);
events.ScheduleEvent(EVENT_SLEEP, urand(10000, 18000)); events.ScheduleEvent(EVENT_EARTH_SHOCK, 8s, 18s);
events.ScheduleEvent(EVENT_ILLUSIONS, urand(10000, 18000)); events.ScheduleEvent(EVENT_CHAIN_BURN, 12s, 28s);
events.ScheduleEvent(EVENT_ILLUSIONS, 16s, 24s);
}
bool CanAIAttack(Unit const* target) const override
{
if (me->GetThreatMgr().getThreatList().size() > 1 && me->GetThreatMgr().getOnlineContainer().getMostHated()->getTarget() == target)
return !target->HasAura(SPELL_SLEEP);
return true;
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
@@ -80,27 +106,26 @@ public:
{ {
switch (eventId) switch (eventId)
{ {
case EVENT_MANABURN:
DoCastVictim(SPELL_MANABURN, true);
events.ScheduleEvent(EVENT_MANABURN, urand(8000, 16000));
break;
case EVENT_SLEEP: case EVENT_SLEEP:
DoCastVictim(SPELL_SLEEP, true); DoCastVictim(SPELL_SLEEP, true);
events.ScheduleEvent(EVENT_SLEEP, urand(12000, 20000)); events.ScheduleEvent(EVENT_SLEEP, 24s, 32s);
return;
case EVENT_EARTH_SHOCK:
DoCastVictim(SPELL_EARTH_SHOCK);
events.ScheduleEvent(EVENT_EARTH_SHOCK, 8s, 18s);
break;
case EVENT_CHAIN_BURN:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1, [&](Unit* u) { return u && !u->IsPet() && u->getPowerType() == POWER_MANA; }))
{
DoCast(target, SPELL_CHAIN_BURN, false);
}
events.ScheduleEvent(EVENT_CHAIN_BURN, 12s, 28s);
break; break;
case EVENT_ILLUSIONS: case EVENT_ILLUSIONS:
// We will summon 3 illusions that will spawn on a random gamer and attack this gamer DoCastSelf(SPELL_SUMMON_NIGHTMARE_ILLUSION_LEFT, true);
// We will just use one model for the beginning DoCastSelf(SPELL_SUMMON_NIGHTMARE_ILLUSION_BACK, true);
for (uint8 i = 0; i < 3; ++i) DoCastSelf(SPELL_SUMMON_NIGHTMARE_ILLUSION_RIGHT, true);
{ events.ScheduleEvent(EVENT_ILLUSIONS, 16s, 24s);
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
Creature* Illusion = me->SummonCreature(NPC_NIGHTMARE_ILLUSION, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000);
if (Illusion)
Illusion->AI()->AttackStart(target);
}
}
events.ScheduleEvent(EVENT_ILLUSIONS, urand(15000, 25000));
break; break;
default: default:
break; break;
@@ -117,7 +142,28 @@ public:
} }
}; };
class spell_chain_burn : public SpellScript
{
PrepareSpellScript(spell_chain_burn);
void FilterTargets(std::list<WorldObject*>& targets)
{
Unit* caster = GetCaster();
targets.remove_if([caster](WorldObject* target) -> bool
{
Unit* unit = target->ToUnit();
return !unit || unit->getPowerType() != POWER_MANA || caster->GetVictim() == unit;
});
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_chain_burn::FilterTargets, EFFECT_0, TARGET_UNIT_TARGET_ENEMY);
}
};
void AddSC_boss_hazzarah() void AddSC_boss_hazzarah()
{ {
new boss_hazzarah(); new boss_hazzarah();
RegisterSpellScript(spell_chain_burn);
} }
@@ -86,6 +86,23 @@ public:
Talk(SAY_AGGRO); Talk(SAY_AGGRO);
} }
void JustSummoned(Creature* summon) override
{
BossAI::JustSummoned(summon);
switch (summon->GetEntry())
{
case NPC_BRAIN_WASH_TOTEM:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1))
{
summon->CastSpell(target, summon->m_spells[0], true);
}
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
{ {
if (!UpdateVictim()) if (!UpdateVictim())
@@ -15,45 +15,72 @@
* with this program. If not, see <http://www.gnu.org/licenses/>. * with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* ScriptData #include "GameObjectAI.h"
SDName: Boss_Marli #include "SpellScript.h"
SD%Complete: 80
SDComment: Charging healers and casters not working. Perhaps wrong Spell Timers.
SDCategory: Zul'Gurub
EndScriptData */
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
#include "TaskScheduler.h"
#include "zulgurub.h" #include "zulgurub.h"
enum Says enum Says
{ {
// Mar'li
SAY_AGGRO = 0, SAY_AGGRO = 0,
SAY_TRANSFORM = 1, SAY_TRANSFORM = 1,
SAY_SPIDER_SPAWN = 2, SAY_SPIDER_SPAWN = 2,
SAY_DEATH = 3 SAY_DEATH = 3,
SAY_TRANSFORM_BACK = 4,
// Spawn of Mar'li
EMOTE_FULL_GROWN = 0
}; };
enum Spells enum Spells
{ {
// Spider form
SPELL_CHARGE = 22911, SPELL_CHARGE = 22911,
SPELL_ASPECT_OF_MARLI = 24686, // A stun spell SPELL_ENVELOPING_WEB = 24110,
SPELL_ENVOLWINGWEB = 24110, SPELL_CORROSIVE_POISON = 24111,
SPELL_POISON_SHOCK = 24112,
//Troll form
SPELL_POISON_VOLLEY = 24099, SPELL_POISON_VOLLEY = 24099,
SPELL_DRAIN_LIFE = 24300,
SPELL_ENLARGE = 24109,
SPELL_SPIDER_EGGS = 24082,
// All
SPELL_SPIDER_FORM = 24084, SPELL_SPIDER_FORM = 24084,
// The Spider Spell SPELL_TRANSFORM_BACK = 24085,
SPELL_LEVELUP = 24312 // Not right Spell. SPELL_THRASH = 3391,
SPELL_HATCH_SPIDER_EGG = 24082,
SPELL_HATCH_EGGS = 24083,
// Spawn of Mar'li
SPELL_GROWTH = 24086,
SPELL_FULL_GROWN = 24088
}; };
enum Events enum Events
{ {
EVENT_SPAWN_START_SPIDERS = 1, // Phase 1 // Spider form
EVENT_POISON_VOLLEY = 2, // Phase All EVENT_CHARGE_PLAYER = 7,
EVENT_SPAWN_SPIDER = 3, // Phase All EVENT_ENVELOPING_WEB = 8,
EVENT_CHARGE_PLAYER = 4, // Phase 3 EVENT_CORROSIVE_POISON = 9,
EVENT_ASPECT_OF_MARLI = 5, // Phase 2 EVENT_POISON_SHOCK = 10,
EVENT_TRANSFORM = 6, // Phase 2
EVENT_TRANSFORM_BACK = 7 // Phase 3 // Troll form
EVENT_POISON_VOLLEY = 11,
EVENT_DRAIN_LIFE = 12,
EVENT_ENLARGE = 13,
// All
EVENT_SPAWN_START_SPIDERS = 1,
EVENT_TRANSFORM = 2,
EVENT_TRANSFORM_BACK = 3,
EVENT_HATCH_SPIDER_EGG = 4,
EVENT_THRASH = 5,
EVENT_TALK_FIRST_SPIDERS = 6,
}; };
enum Phases enum Phases
@@ -63,208 +90,269 @@ enum Phases
PHASE_THREE = 3 PHASE_THREE = 3
}; };
class boss_marli : public CreatureScript enum Misc
{ {
public: GO_SPIDER_EGGS = 179985,
boss_marli() : CreatureScript("boss_marli") { } };
struct boss_marliAI : public BossAI struct boss_marli : public BossAI
{
boss_marli(Creature* creature) : BossAI(creature, DATA_MARLI) { }
void Reset() override
{ {
boss_marliAI(Creature* creature) : BossAI(creature, DATA_MARLI) { } if (events.IsInPhase(PHASE_THREE))
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
void Reset() override std::list<GameObject*> eggs;
me->GetGameObjectListWithEntryInGrid(eggs, GO_SPIDER_EGGS, DEFAULT_VISIBILITY_INSTANCE);
for (auto const& egg : eggs)
{ {
if (events.IsInPhase(PHASE_THREE)) egg->Respawn();
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack egg->UpdateObjectVisibility();
_Reset();
} }
void JustDied(Unit* /*killer*/) override BossAI::Reset();
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH);
}
void EnterCombat(Unit* who) override
{
BossAI::EnterCombat(who);
events.ScheduleEvent(EVENT_SPAWN_START_SPIDERS, 1000, 0, PHASE_ONE);
Talk(SAY_AGGRO);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
_JustDied(); switch (eventId)
Talk(SAY_DEATH);
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
events.ScheduleEvent(EVENT_SPAWN_START_SPIDERS, 1000, 0, PHASE_ONE);
Talk(SAY_AGGRO);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
switch (eventId) case EVENT_SPAWN_START_SPIDERS:
events.ScheduleEvent(EVENT_TALK_FIRST_SPIDERS, 500, 0, PHASE_TWO);
DoCastAOE(SPELL_HATCH_EGGS);
events.ScheduleEvent(EVENT_TRANSFORM, 60000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_POISON_VOLLEY, 15000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_HATCH_SPIDER_EGG, 30000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_DRAIN_LIFE, 30000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_THRASH, urand(4000, 6000)); // all phases
events.ScheduleEvent(EVENT_ENLARGE, urand(10000, 20000), 0, PHASE_TWO);
events.SetPhase(PHASE_TWO);
break;
case EVENT_TALK_FIRST_SPIDERS:
Talk(SAY_SPIDER_SPAWN);
break;
case EVENT_POISON_VOLLEY:
DoCastVictim(SPELL_POISON_VOLLEY, true);
events.ScheduleEvent(EVENT_POISON_VOLLEY, urand(10000, 20000), 0, PHASE_TWO);
break;
case EVENT_HATCH_SPIDER_EGG:
DoCastSelf(SPELL_HATCH_SPIDER_EGG, true);
events.ScheduleEvent(EVENT_HATCH_SPIDER_EGG, 20000, 0, PHASE_TWO);
break;
case EVENT_DRAIN_LIFE:
DoCastRandomTarget(SPELL_DRAIN_LIFE);
events.ScheduleEvent(EVENT_DRAIN_LIFE, urand(20000, 50000), 0, PHASE_TWO);
break;
case EVENT_ENLARGE:
{ {
case EVENT_SPAWN_START_SPIDERS: std::list<Creature*> targets = DoFindFriendlyMissingBuff(100.f, SPELL_ENLARGE);
if (targets.size() > 0)
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0)) DoCast(*(targets.begin()), SPELL_ENLARGE);
{ events.ScheduleEvent(EVENT_ENLARGE, urand(20000, 40000), 0, PHASE_TWO);
Talk(SAY_SPIDER_SPAWN); break;
Creature* Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Spider)
Spider->AI()->AttackStart(target);
Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Spider)
Spider->AI()->AttackStart(target);
Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Spider)
Spider->AI()->AttackStart(target);
Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Spider)
Spider->AI()->AttackStart(target);
}
events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, 12000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_TRANSFORM, 45000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_POISON_VOLLEY, 15000);
events.ScheduleEvent(EVENT_SPAWN_SPIDER, 30000);
events.ScheduleEvent(EVENT_TRANSFORM, 45000, 0, PHASE_TWO);
events.SetPhase(PHASE_TWO);
break;
case EVENT_POISON_VOLLEY:
DoCastVictim(SPELL_POISON_VOLLEY, true);
events.ScheduleEvent(EVENT_POISON_VOLLEY, urand(10000, 20000));
break;
case EVENT_ASPECT_OF_MARLI:
DoCastVictim(SPELL_ASPECT_OF_MARLI, true);
events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, urand(13000, 18000), 0, PHASE_TWO);
break;
case EVENT_SPAWN_SPIDER:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
Creature* Spider = me->SummonCreature(15041, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000);
if (Spider)
Spider->AI()->AttackStart(target);
}
events.ScheduleEvent(EVENT_SPAWN_SPIDER, urand(12000, 17000));
break;
case EVENT_TRANSFORM:
{
Talk(SAY_TRANSFORM);
DoCast(me, SPELL_SPIDER_FORM); // SPELL_AURA_TRANSFORM
/*
CreatureTemplate const* cinfo = me->GetCreatureTemplate();
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 35)));
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 35)));
me->UpdateDamagePhysical(BASE_ATTACK);
*/
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, true); // hack
DoCastVictim(SPELL_ENVOLWINGWEB);
if (DoGetThreat(me->GetVictim()))
DoModifyThreatPercent(me->GetVictim(), -100);
events.ScheduleEvent(EVENT_CHARGE_PLAYER, 1500, 0, PHASE_THREE);
events.ScheduleEvent(EVENT_TRANSFORM_BACK, 25000, 0, PHASE_THREE);
events.SetPhase(PHASE_THREE);
break;
}
case EVENT_CHARGE_PLAYER:
{
Unit* target = nullptr;
int i = 0;
while (i++ < 3) // max 3 tries to get a random target with power_mana
{
target = SelectTarget(SelectTargetMethod::Random, 1, 100, true); // not aggro leader
if (target && target->getPowerType() == POWER_MANA)
break;
}
if (target)
{
DoCast(target, SPELL_CHARGE);
AttackStart(target);
}
events.ScheduleEvent(EVENT_CHARGE_PLAYER, 8000, 0, PHASE_THREE);
break;
}
case EVENT_TRANSFORM_BACK:
{
me->RemoveAura(SPELL_SPIDER_FORM);
/*
CreatureTemplate const* cinfo = me->GetCreatureTemplate();
me->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, (cinfo->mindmg +((cinfo->mindmg/100) * 1)));
me->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, (cinfo->maxdmg +((cinfo->maxdmg/100) * 1)));
me->UpdateDamagePhysical(BASE_ATTACK);
*/
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
events.ScheduleEvent(EVENT_ASPECT_OF_MARLI, 12000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_TRANSFORM, 45000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_POISON_VOLLEY, 15000);
events.ScheduleEvent(EVENT_SPAWN_SPIDER, 30000);
events.ScheduleEvent(EVENT_TRANSFORM, urand(35000, 60000), 0, PHASE_TWO);
events.SetPhase(PHASE_TWO);
break;
}
default:
break;
} }
case EVENT_TRANSFORM:
Talk(SAY_TRANSFORM);
DoCastSelf(SPELL_SPIDER_FORM, true);
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, true); // hack
events.ScheduleEvent(EVENT_ENVELOPING_WEB, 5000, 0, PHASE_THREE);
events.ScheduleEvent(EVENT_CHARGE_PLAYER, 6000, 0, PHASE_THREE);
events.ScheduleEvent(EVENT_CORROSIVE_POISON, 1000, 0, PHASE_THREE);
events.ScheduleEvent(EVENT_POISON_SHOCK, urand(5000, 10000), 0, PHASE_THREE);
events.ScheduleEvent(EVENT_TRANSFORM_BACK, 60000, 0, PHASE_THREE);
events.SetPhase(PHASE_THREE);
break;
case EVENT_ENVELOPING_WEB:
DoCastAOE(SPELL_ENVELOPING_WEB);
events.ScheduleEvent(EVENT_CHARGE_PLAYER, 500, 0, PHASE_THREE);
events.ScheduleEvent(EVENT_ENVELOPING_WEB, urand(15000, 20000), 0, PHASE_THREE);
break;
case EVENT_CHARGE_PLAYER:
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [this](Unit* target) -> bool
{
if (target->GetTypeId() != TYPEID_PLAYER || target->getPowerType() != Powers::POWER_MANA)
return false;
if (me->IsWithinMeleeRange(target) || me->GetVictim() == target)
return false;
return true;
});
if (target)
{
DoCast(target, SPELL_CHARGE);
AttackStart(target);
}
break;
}
case EVENT_CORROSIVE_POISON:
DoCastVictim(SPELL_CORROSIVE_POISON);
events.ScheduleEvent(EVENT_CORROSIVE_POISON, urand(25000, 35000), 0, PHASE_THREE);
break;
case EVENT_POISON_SHOCK:
DoCastRandomTarget(SPELL_POISON_SHOCK);
events.ScheduleEvent(EVENT_POISON_SHOCK, 10000, 0, PHASE_THREE);
break;
case EVENT_TRANSFORM_BACK:
me->RemoveAura(SPELL_SPIDER_FORM);
DoCastSelf(SPELL_TRANSFORM_BACK, true);
Talk(SAY_TRANSFORM_BACK);
me->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, 35.0f, false); // hack
events.ScheduleEvent(EVENT_TRANSFORM, 60000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_POISON_VOLLEY, 15000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_HATCH_SPIDER_EGG, 30000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_DRAIN_LIFE, 30000, 0, PHASE_TWO);
events.ScheduleEvent(EVENT_ENLARGE, urand(10000, 20000), 0, PHASE_TWO);
events.SetPhase(PHASE_TWO);
break;
case EVENT_THRASH:
DoCastVictim(SPELL_THRASH);
events.ScheduleEvent(EVENT_THRASH, urand(10000, 20000));
break;
default:
break;
} }
DoMeleeAttackIfReady();
} }
};
CreatureAI* GetAI(Creature* creature) const override DoMeleeAttackIfReady();
{
return GetZulGurubAI<boss_marliAI>(creature);
} }
}; };
// Spawn of Marli // Spawn of Mar'li
class npc_spawn_of_marli : public CreatureScript struct npc_spawn_of_marli : public ScriptedAI
{ {
public: npc_spawn_of_marli(Creature* creature) : ScriptedAI(creature) { }
npc_spawn_of_marli() : CreatureScript("npc_spawn_of_marli") { }
struct npc_spawn_of_marliAI : public ScriptedAI void Reset() override
{ {
npc_spawn_of_marliAI(Creature* creature) : ScriptedAI(creature) { } _scheduler.CancelAll();
}
uint32 LevelUp_Timer; void EnterCombat(Unit* /*who*/) override
{
void Reset() override _scheduler.Schedule(4s, [this](TaskContext context)
{ {
LevelUp_Timer = 3000; if (context.GetRepeatCounter() < 5)
}
void EnterCombat(Unit* /*who*/) override
{
}
void UpdateAI(uint32 diff) override
{
//Return since we have no target
if (!UpdateVictim())
return;
//LevelUp_Timer
if (LevelUp_Timer <= diff)
{ {
DoCast(me, SPELL_LEVELUP); DoCastSelf(SPELL_GROWTH);
LevelUp_Timer = 3000; context.Repeat(4s);
} }
else LevelUp_Timer -= diff; else
{
Talk(EMOTE_FULL_GROWN);
DoCastSelf(SPELL_FULL_GROWN);
}
});
}
DoMeleeAttackIfReady(); void UpdateAI(uint32 diff) override
}
};
CreatureAI* GetAI(Creature* creature) const override
{ {
return GetZulGurubAI<npc_spawn_of_marliAI>(creature); //Return since we have no target
if (!UpdateVictim())
return;
_scheduler.Update(diff, [this]
{
DoMeleeAttackIfReady();
});
}
private:
TaskScheduler _scheduler;
};
// 24083 - Hatch Eggs
class spell_hatch_eggs : public SpellScript
{
PrepareSpellScript(spell_hatch_eggs);
void HandleObjectAreaTargetSelect(std::list<WorldObject*>& targets)
{
targets.sort(Acore::ObjectDistanceOrderPred(GetCaster()));
targets.resize(GetSpellInfo()->MaxAffectedTargets);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hatch_eggs::HandleObjectAreaTargetSelect, EFFECT_0, TARGET_GAMEOBJECT_DEST_AREA);
}
};
// 24110 - Enveloping Webs
class spell_enveloping_webs : public SpellScript
{
PrepareSpellScript(spell_enveloping_webs);
void HandleOnHit()
{
Unit* caster = GetCaster();
Unit* hitUnit = GetHitUnit();
if (caster && hitUnit && hitUnit->GetTypeId() == TYPEID_PLAYER)
{
caster->GetThreatMgr().modifyThreatPercent(hitUnit, -100);
}
}
void Register() override
{
OnHit += SpellHitFn(spell_enveloping_webs::HandleOnHit);
}
};
// 24084 - Mar'li Transform
class spell_marli_transform : public AuraScript
{
PrepareAuraScript(spell_marli_transform);
void HandleApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetCaster() && GetCaster()->ToCreature())
GetCaster()->ToCreature()->LoadEquipment(0, true);
}
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetCaster() && GetCaster()->ToCreature())
GetCaster()->ToCreature()->LoadEquipment(1, true);
}
void Register() override
{
OnEffectApply += AuraEffectApplyFn(spell_marli_transform::HandleApply, EFFECT_0, SPELL_AURA_TRANSFORM, AURA_EFFECT_HANDLE_REAL);
OnEffectRemove += AuraEffectRemoveFn(spell_marli_transform::HandleRemove, EFFECT_0, SPELL_AURA_TRANSFORM, AURA_EFFECT_HANDLE_REAL);
} }
}; };
void AddSC_boss_marli() void AddSC_boss_marli()
{ {
new boss_marli(); RegisterCreatureAI(boss_marli);
new npc_spawn_of_marli(); RegisterCreatureAI(npc_spawn_of_marli);
RegisterSpellScript(spell_hatch_eggs);
RegisterSpellScript(spell_enveloping_webs);
RegisterSpellScript(spell_marli_transform);
} }
@@ -28,13 +28,20 @@ EndScriptData */
enum Spells enum Spells
{ {
SPELL_AMBUSH = 34794, SPELL_VANISH = 24699,
SPELL_THOUSANDBLADES = 34799 SPELL_AMBUSH = 24337,
SPELL_GOUGE = 24698,
SPELL_THOUSAND_BLADES = 24649,
SPELL_THRASH = 3417,
SPELL_ENRAGE = 8269
}; };
enum Misc enum Events
{ {
EQUIP_ID_MAIN_HAND = 0 //was item display id 31818, but this id does not exist EVENT_VANISH = 1,
EVENT_AMBUSH = 2,
EVENT_GOUGE = 3,
EVENT_THOUSAND_BLADES = 4
}; };
class boss_renataki : public CreatureScript class boss_renataki : public CreatureScript
@@ -46,36 +53,67 @@ public:
{ {
boss_renatakiAI(Creature* creature) : BossAI(creature, DATA_EDGE_OF_MADNESS) { } boss_renatakiAI(Creature* creature) : BossAI(creature, DATA_EDGE_OF_MADNESS) { }
uint32 Invisible_Timer;
uint32 Ambush_Timer;
uint32 Visible_Timer;
uint32 Aggro_Timer;
uint32 ThousandBlades_Timer;
bool Invisible;
bool Ambushed;
void Reset() override void Reset() override
{ {
_Reset(); _Reset();
Invisible_Timer = urand(8000, 18000); me->SetReactState(REACT_AGGRESSIVE);
Ambush_Timer = 3000; _enraged = false;
Visible_Timer = 4000; _thousandBladesCount = urand(2, 5);
Aggro_Timer = urand(15000, 25000); _thousandBladesTargets.clear();
ThousandBlades_Timer = urand(4000, 8000); _dynamicFlags = me->GetDynamicFlags();
Invisible = false;
Ambushed = false;
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
} }
void EnterCombat(Unit* /*who*/) override void EnterCombat(Unit* /*who*/) override
{ {
_EnterCombat(); _EnterCombat();
events.ScheduleEvent(EVENT_VANISH, 23s, 25s);
events.ScheduleEvent(EVENT_GOUGE, 5s, 10s);
events.ScheduleEvent(EVENT_THOUSAND_BLADES, 15s, 20s);
DoCastSelf(SPELL_THRASH, true);
}
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
{
if (!_enraged && HealthBelowPct(30))
{
me->TextEmote("%s becomes enraged", me, false);
DoCast(me, SPELL_ENRAGE);
_enraged = true;
}
}
bool CanAIAttack(Unit const* target) const override
{
if (me->GetThreatMgr().getThreatList().size() > 1 && me->GetThreatMgr().getOnlineContainer().getMostHated()->getTarget() == target)
return !target->HasAura(SPELL_GOUGE);
return true;
}
bool CanBeSeen(Player const* /*player*/) override
{
return me->GetReactState() == REACT_AGGRESSIVE;
}
bool CanSeeAlways(WorldObject const* obj) override
{
if (me->GetReactState() == REACT_PASSIVE)
{
return obj->ToCreature() && obj->ToCreature()->IsPet();
}
return false;
}
bool CanAlwaysBeDetectable(WorldObject const* seer) override
{
if (me->GetReactState() == REACT_PASSIVE)
{
return seer->ToCreature() && seer->ToCreature()->IsPet();
}
return false;
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
@@ -83,86 +121,122 @@ public:
if (!UpdateVictim()) if (!UpdateVictim())
return; return;
//Invisible_Timer events.Update(diff);
if (Invisible_Timer <= diff)
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{ {
me->InterruptSpell(CURRENT_GENERIC_SPELL); switch (eventId)
SetEquipmentSlots(false, EQUIP_UNEQUIP, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE);
me->SetDisplayId(11686);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
Invisible = true;
Invisible_Timer = urand(15000, 30000);
}
else Invisible_Timer -= diff;
if (Invisible)
{
if (Ambush_Timer <= diff)
{ {
Unit* target = SelectTarget(SelectTargetMethod::Random, 0); case EVENT_VANISH:
if (target) me->SetReactState(REACT_PASSIVE);
_dynamicFlags = me->GetDynamicFlags();
me->RemoveDynamicFlag(UNIT_DYNFLAG_TRACK_UNIT);
DoCastSelf(SPELL_VANISH);
events.DelayEvents(5s);
events.ScheduleEvent(EVENT_AMBUSH, 5s);
events.ScheduleEvent(EVENT_VANISH, 38s, 45s);
return;
case EVENT_AMBUSH:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 1))
{
me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), me->GetOrientation());
DoCast(target, SPELL_AMBUSH, true);
}
me->SetDynamicFlag(_dynamicFlags);
me->RemoveAurasDueToSpell(SPELL_VANISH);
me->SetReactState(REACT_AGGRESSIVE);
break;
case EVENT_GOUGE:
DoCastAOE(SPELL_GOUGE);
events.ScheduleEvent(EVENT_GOUGE, 10s, 15s);
return;
case EVENT_THOUSAND_BLADES:
{ {
me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), me->GetOrientation()); if (_thousandBladesTargets.empty())
DoCast(target, SPELL_AMBUSH); {
} std::vector<Unit*> targetList;
ThreatContainer::StorageType const& threatlist = me->GetThreatMgr().getThreatList();
for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
{
if (Unit* target = (*itr)->getTarget())
{
if (target->IsAlive() && target->IsWithinDist2d(me, 100.f))
{
targetList.push_back(target);
}
}
}
Ambushed = true; if (!targetList.empty())
Ambush_Timer = 3000; {
Acore::Containers::RandomShuffle(targetList);
// First get ranged targets
for (Unit* target : targetList)
{
if (!target->IsWithinMeleeRange(me))
{
_thousandBladesTargets.push_back(target);
}
}
if (_thousandBladesTargets.size() < _thousandBladesCount)
{
// if still not enough, get melee targets
for (Unit* target : targetList)
{
if (target->IsWithinMeleeRange(me))
{
_thousandBladesTargets.push_back(target);
}
}
}
if (!_thousandBladesTargets.empty())
{
Acore::Containers::RandomResize(_thousandBladesTargets, _thousandBladesCount);
}
}
}
if (!_thousandBladesTargets.empty())
{
std::vector<Unit*>::iterator itr = _thousandBladesTargets.begin();
std::advance(itr, urand(0, _thousandBladesTargets.size() - 1));
if (Unit* target = *itr)
{
DoCast(target, SPELL_THOUSAND_BLADES, false);
}
_thousandBladesTargets.erase(itr);
events.ScheduleEvent(EVENT_THOUSAND_BLADES, 500ms);
}
else
{
_thousandBladesCount = urand(2, 5);
events.ScheduleEvent(EVENT_THOUSAND_BLADES, 15s, 22s);
}
break;
}
default:
break;
} }
else Ambush_Timer -= diff;
} }
if (Ambushed) if (me->GetReactState() == REACT_AGGRESSIVE)
{ DoMeleeAttackIfReady();
if (Visible_Timer <= diff)
{
me->InterruptSpell(CURRENT_GENERIC_SPELL);
me->SetDisplayId(15268);
SetEquipmentSlots(false, EQUIP_ID_MAIN_HAND, EQUIP_NO_CHANGE, EQUIP_NO_CHANGE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
Invisible = false;
Visible_Timer = 4000;
}
else Visible_Timer -= diff;
}
//Resetting some aggro so he attacks other gamers
if (!Invisible)
{
if (Aggro_Timer <= diff)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 1);
if (DoGetThreat(me->GetVictim()))
{
DoModifyThreatPercent(me->GetVictim(), -50);
}
if (target)
{
AttackStart(target);
}
Aggro_Timer = urand(7000, 20000);
}
else Aggro_Timer -= diff;
if (ThousandBlades_Timer <= diff)
{
DoCastVictim(SPELL_THOUSANDBLADES);
ThousandBlades_Timer = urand(7000, 12000);
}
else ThousandBlades_Timer -= diff;
}
DoMeleeAttackIfReady();
} }
private:
bool _enraged;
uint32 _dynamicFlags;
uint8 _thousandBladesCount;
std::vector<Unit*> _thousandBladesTargets;
}; };
CreatureAI* GetAI(Creature* creature) const override CreatureAI* GetAI(Creature* creature) const override
@@ -22,6 +22,7 @@ SDComment: Missing reset function after killing a boss for Ohgan, Thekal.
SDCategory: Zul'Gurub SDCategory: Zul'Gurub
EndScriptData */ EndScriptData */
#include "GameObjectAI.h"
#include "InstanceScript.h" #include "InstanceScript.h"
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "zulgurub.h" #include "zulgurub.h"
@@ -36,7 +37,8 @@ ObjectData const creatureData[] =
{ {
{ NPC_HIGH_PRIEST_THEKAL, DATA_THEKAL }, { NPC_HIGH_PRIEST_THEKAL, DATA_THEKAL },
{ NPC_ZEALOT_LORKHAN, DATA_LORKHAN }, { NPC_ZEALOT_LORKHAN, DATA_LORKHAN },
{ NPC_ZEALOT_ZATH, DATA_ZATH } { NPC_ZEALOT_ZATH, DATA_ZATH },
{ NPC_PRIESTESS_MARLI, DATA_MARLI }
}; };
class instance_zulgurub : public InstanceMapScript class instance_zulgurub : public InstanceMapScript
@@ -49,6 +51,7 @@ public:
instance_zulgurub_InstanceMapScript(Map* map) : InstanceScript(map) instance_zulgurub_InstanceMapScript(Map* map) : InstanceScript(map)
{ {
SetBossNumber(EncounterCount); SetBossNumber(EncounterCount);
LoadObjectData(creatureData, nullptr);
LoadDoorData(doorData); LoadDoorData(doorData);
LoadObjectData(creatureData, nullptr); LoadObjectData(creatureData, nullptr);
} }
@@ -71,7 +74,20 @@ public:
case NPC_HAKKAR: case NPC_HAKKAR:
_hakkarGUID = creature->GetGUID(); _hakkarGUID = creature->GetGUID();
break; break;
case NPC_SPAWN_OF_MARLI:
if (Creature* marli = GetCreature(DATA_MARLI))
{
marli->AI()->JustSummoned(creature);
}
break;
case NPC_GAHZRANKA:
_gahzrankaGUID = creature->GetGUID();
break;
default:
break;
} }
InstanceScript::OnCreatureCreate(creature);
} }
void OnGameObjectCreate(GameObject* go) override void OnGameObjectCreate(GameObject* go) override
@@ -109,6 +125,16 @@ public:
return ObjectGuid::Empty; return ObjectGuid::Empty;
} }
uint32 GetData(uint32 type) const override
{
if (type == DATA_GAHZRANKA)
{
return _gahzrankaGUID || GetBossState(DATA_GAHZRANKA) == DONE;
}
return 0;
}
std::string GetSaveData() override std::string GetSaveData() override
{ {
OUT_SAVE_INST_DATA; OUT_SAVE_INST_DATA;
@@ -160,6 +186,7 @@ public:
ObjectGuid _arlokkGUID; ObjectGuid _arlokkGUID;
ObjectGuid _goGongOfBethekkGUID; ObjectGuid _goGongOfBethekkGUID;
ObjectGuid _hakkarGUID; ObjectGuid _hakkarGUID;
ObjectGuid _gahzrankaGUID;
}; };
InstanceScript* GetInstanceScript(InstanceMap* map) const override InstanceScript* GetInstanceScript(InstanceMap* map) const override
@@ -168,7 +195,56 @@ public:
} }
}; };
enum EdgeOfMadnessEnum
{
EVENT_EDGE_OF_MADNESS_GRILEK = 27,
EVENT_EDGE_OF_MADNESS_HAZZARAH = 28,
EVENT_EDGE_OF_MADNESS_RENATAKI = 29,
EVENT_EDGE_OF_MADNESS_WUSHOOLAY = 30
};
std::vector<std::pair<uint32, uint32>> BrazierOfMadnessContainer =
{
{ EVENT_EDGE_OF_MADNESS_GRILEK, NPC_GRILEK },
{ EVENT_EDGE_OF_MADNESS_HAZZARAH, NPC_HAZZARAH },
{ EVENT_EDGE_OF_MADNESS_RENATAKI, NPC_RENATAKI },
{ EVENT_EDGE_OF_MADNESS_WUSHOOLAY, NPC_WUSHOOLAY }
};
Position const edgeOfMagnessSummonPos = { -11901.229f, -1906.366f, 65.358f, 0.942f };
struct go_brazier_of_madness : public GameObjectAI
{
go_brazier_of_madness(GameObject* go) : GameObjectAI(go) { }
bool GossipHello(Player* /*player*/, bool reportUse) override
{
if (reportUse)
{
return true;
}
uint32 bossEntry = 0;
for (uint8 i = 0; i < 4; ++i)
{
if (sGameEventMgr->IsActiveEvent(BrazierOfMadnessContainer[i].first))
{
bossEntry = BrazierOfMadnessContainer[i].second;
break;
}
}
if (bossEntry)
{
me->SummonCreature(bossEntry, edgeOfMagnessSummonPos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 2 * HOUR * IN_MILLISECONDS);
}
return false;
}
};
void AddSC_instance_zulgurub() void AddSC_instance_zulgurub()
{ {
new instance_zulgurub(); new instance_zulgurub();
RegisterGameObjectAI(go_brazier_of_madness);
} }
@@ -49,6 +49,8 @@ enum CreatureIds
NPC_ZULIAN_PROWLER = 15101, // Arlokk Event NPC_ZULIAN_PROWLER = 15101, // Arlokk Event
NPC_ZEALOT_LORKHAN = 11347, NPC_ZEALOT_LORKHAN = 11347,
NPC_ZEALOT_ZATH = 11348, NPC_ZEALOT_ZATH = 11348,
NPC_PRIESTESS_MARLI = 14510,
NPC_SPAWN_OF_MARLI = 15041,
NPC_HIGH_PRIEST_THEKAL = 14509, NPC_HIGH_PRIEST_THEKAL = 14509,
NPC_JINDO_THE_HEXXER = 11380, NPC_JINDO_THE_HEXXER = 11380,
NPC_NIGHTMARE_ILLUSION = 15163, NPC_NIGHTMARE_ILLUSION = 15163,
@@ -59,7 +61,13 @@ enum CreatureIds
NPC_VILEBRANCH_SPEAKER = 11391, // Mandokir Event NPC_VILEBRANCH_SPEAKER = 11391, // Mandokir Event
NPC_CHAINED_SPIRIT = 15117, // Mandokir Event NPC_CHAINED_SPIRIT = 15117, // Mandokir Event
NPC_HAKKAR = 14834, NPC_HAKKAR = 14834,
NPC_ZULGURUB_TIGER = 11361 NPC_ZULGURUB_TIGER = 11361,
NPC_BRAIN_WASH_TOTEM = 15112,
NPC_GAHZRANKA = 15114,
NPC_GRILEK = 15082,
NPC_HAZZARAH = 15083,
NPC_RENATAKI = 15084,
NPC_WUSHOOLAY = 15085
}; };
enum GameobjectIds enum GameobjectIds
@@ -25,38 +25,9 @@ EndScriptData */
#include "Player.h" #include "Player.h"
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "ScriptedCreature.h" #include "ScriptedCreature.h"
#include "TaskScheduler.h"
#include "temple_of_ahnqiraj.h" #include "temple_of_ahnqiraj.h"
/*
* This is a 2 phases events. Here follows an explanation of the main events and transition between phases and sub-phases.
*
* The first phase is the EYE phase: the Eye of C'Thun is active and C'thun is not active.
* During this phase, the "Eye of C'Thun" alternates between 2 sub-phases:
* - PHASE_EYE_GREEN_BEAM:
* 50 sec phase during which the Eye mainly casts its Green Beam every 3 sec.
* - PHASE_EYE_RED_BEAM:
* 35 sec phase during which the Eye casts its red beam every sec.
* This EYE phase ends when the "Eye of C'Thun" is killed. Then starts the CTHUN phase.
*
* The second phase is the CTHUN phase. The Eye of C'Thun is not active and C'Thun is active.
* This phase starts with the transformation of the Eye into C'Thun (PHASE_CTHUN_TRANSITION).
* After the transformation, C'Thun alternates between 2 sub-phases:
* - PHASE_CTHUN_STOMACH:
* - C'Thun is almost insensible to all damage (99% damage reduction).
* - It spawns 2 tentacles in its stomach.
* - C'Thun swallows players.
* - This sub-phase ends when the 2 tentacles are killed. Swallowed players are regurgitate.
*
* - PHASE_CTHUN_WEAK:
* - weakened C'Thun takes normal damage.
* - This sub-phase ends after 45 secs.
*
* This CTHUN phase ends when C'Thun is killed
*
* Note:
* - the current phase is stored in the instance data to be easily shared between the eye and cthun.
*/
enum Phases enum Phases
{ {
PHASE_NOT_STARTED = 0, PHASE_NOT_STARTED = 0,
@@ -99,7 +70,7 @@ enum Spells
//SAME AS PHASE1 //SAME AS PHASE1
//Giant Claw Tentacles //Giant Claw Tentacles
SPELL_MASSIVE_GROUND_RUPTURE = 26100, SPELL_MASSIVE_GROUND_RUPTURE = 26478,
//Also casts Hamstring //Also casts Hamstring
SPELL_THRASH = 3391, SPELL_THRASH = 3391,
@@ -111,6 +82,10 @@ enum Spells
SPELL_MOUTH_TENTACLE = 26332, SPELL_MOUTH_TENTACLE = 26332,
SPELL_EXIT_STOMACH_KNOCKBACK = 25383, SPELL_EXIT_STOMACH_KNOCKBACK = 25383,
SPELL_DIGESTIVE_ACID = 26476, SPELL_DIGESTIVE_ACID = 26476,
// Tentacles
SPELL_SUBMERGE_VISUAL = 26234,
SPELL_BIRTH = 26262
}; };
enum Actions enum Actions
@@ -142,6 +117,20 @@ const Position FleshTentaclePos[2] =
{ -8525.0f, 1994.0f, -98.0f, 2.12f}, { -8525.0f, 1994.0f, -98.0f, 2.12f},
}; };
class NotInStomachSelector
{
public:
NotInStomachSelector() { }
bool operator()(Unit* unit) const
{
if (unit->GetTypeId() != TYPEID_PLAYER || unit->HasAura(SPELL_DIGESTIVE_ACID))
return false;
return true;
}
};
//Kick out position //Kick out position
const Position KickPos = { -8545.0f, 1984.0f, -96.0f, 0.0f}; const Position KickPos = { -8545.0f, 1984.0f, -96.0f, 0.0f};
@@ -917,32 +906,40 @@ public:
{ {
eye_tentacleAI(Creature* creature) : ScriptedAI(creature) eye_tentacleAI(Creature* creature) : ScriptedAI(creature)
{ {
if (Creature* pPortal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN)) if (Creature* portal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{ {
pPortal->SetReactState(REACT_PASSIVE); portal->SetReactState(REACT_PASSIVE);
Portal = pPortal->GetGUID(); _portalGUID = portal->GetGUID();
} }
SetCombatMovement(false); SetCombatMovement(false);
} }
uint32 MindflayTimer;
uint32 KillSelfTimer;
ObjectGuid Portal;
void JustDied(Unit* /*killer*/) override void JustDied(Unit* /*killer*/) override
{ {
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal)) if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
{
Unit::Kill(p, p); Unit::Kill(p, p);
}
} }
void Reset() override void Reset() override
{ {
//Mind flay half a second after we spawn _scheduler.Schedule(500ms, [this](TaskContext /*task*/)
MindflayTimer = 500; {
DoCastAOE(SPELL_GROUND_RUPTURE);
}).Schedule(5min, [this](TaskContext /*task*/)
{
me->DespawnOrUnsummon();
}).Schedule(1s, 5s, [this](TaskContext context)
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, [&](Unit* u) { return u && u->GetTypeId() == TYPEID_PLAYER && !u->HasAura(SPELL_DIGESTIVE_ACID) && !u->HasAura(SPELL_MIND_FLAY); }))
{
DoCast(target, SPELL_MIND_FLAY);
}
//This prevents eyes from overlapping context.Repeat(10s, 15s);
KillSelfTimer = 35000; });
} }
void EnterCombat(Unit* /*who*/) override void EnterCombat(Unit* /*who*/) override
@@ -956,26 +953,12 @@ public:
if (!UpdateVictim()) if (!UpdateVictim())
return; return;
//KillSelfTimer _scheduler.Update(diff);
if (KillSelfTimer <= diff)
{
Unit::Kill(me, me);
return;
}
else KillSelfTimer -= diff;
//MindflayTimer
if (MindflayTimer <= diff)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0);
if (target && !target->HasAura(SPELL_DIGESTIVE_ACID))
DoCast(target, SPELL_MIND_FLAY);
//Mindflay every 10 seconds
MindflayTimer = 10000;
}
else MindflayTimer -= diff;
} }
private:
TaskScheduler _scheduler;
ObjectGuid _portalGUID;
}; };
}; };
@@ -995,35 +978,41 @@ public:
{ {
SetCombatMovement(false); SetCombatMovement(false);
if (Creature* pPortal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN)) if (Creature* portal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{ {
pPortal->SetReactState(REACT_PASSIVE); portal->SetReactState(REACT_PASSIVE);
Portal = pPortal->GetGUID(); _portalGUID = portal->GetGUID();
} }
} }
uint32 GroundRuptureTimer;
uint32 HamstringTimer;
uint32 EvadeTimer;
ObjectGuid Portal;
void JustDied(Unit* /*killer*/) override void JustDied(Unit* /*killer*/) override
{ {
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal)) if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
{
Unit::Kill(p, p); Unit::Kill(p, p);
}
} }
void Reset() override void Reset() override
{ {
//First rupture should happen half a second after we spawn _scheduler.Schedule(Milliseconds(500), [this](TaskContext /*task*/)
GroundRuptureTimer = 500; {
HamstringTimer = 2000; DoCastAOE(SPELL_GROUND_RUPTURE);
EvadeTimer = 5000; }).Schedule(Minutes(5), [this](TaskContext /*task*/)
{
me->DespawnOrUnsummon();
});
} }
void EnterCombat(Unit* /*who*/) override void EnterCombat(Unit* /*who*/) override
{ {
DoZoneInCombat(); DoZoneInCombat();
_scheduler.Schedule(2s, [this](TaskContext context)
{
DoCastVictim(SPELL_HAMSTRING);
context.Repeat(5s);
});
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
@@ -1032,62 +1021,14 @@ public:
if (!UpdateVictim()) if (!UpdateVictim())
return; return;
//EvadeTimer _scheduler.Update(diff);
if (!me->IsWithinMeleeRange(me->GetVictim()))
{
if (EvadeTimer <= diff)
{
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal))
Unit::Kill(p, p);
//Dissapear and reappear at new position
me->SetVisible(false);
Unit* target = SelectTarget(SelectTargetMethod::Random, 0);
if (!target)
{
Unit::Kill(me, me);
return;
}
if (!target->HasAura(SPELL_DIGESTIVE_ACID))
{
me->SetPosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0);
if (Creature* pPortal = me->SummonCreature(NPC_SMALL_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{
pPortal->SetReactState(REACT_PASSIVE);
Portal = pPortal->GetGUID();
}
GroundRuptureTimer = 500;
HamstringTimer = 2000;
EvadeTimer = 5000;
AttackStart(target);
}
me->SetVisible(true);
}
else EvadeTimer -= diff;
}
//GroundRuptureTimer
if (GroundRuptureTimer <= diff)
{
DoCastVictim(SPELL_GROUND_RUPTURE);
GroundRuptureTimer = 30000;
}
else GroundRuptureTimer -= diff;
//HamstringTimer
if (HamstringTimer <= diff)
{
DoCastVictim(SPELL_HAMSTRING);
HamstringTimer = 5000;
}
else HamstringTimer -= diff;
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
} }
private:
TaskScheduler _scheduler;
ObjectGuid _portalGUID;
}; };
}; };
@@ -1107,37 +1048,112 @@ public:
{ {
SetCombatMovement(false); SetCombatMovement(false);
if (Creature* pPortal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN)) if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{ {
pPortal->SetReactState(REACT_PASSIVE); portal->SetReactState(REACT_PASSIVE);
Portal = pPortal->GetGUID(); _portalGUID = portal->GetGUID();
} }
} }
uint32 GroundRuptureTimer;
uint32 ThrashTimer;
uint32 HamstringTimer;
uint32 EvadeTimer;
ObjectGuid Portal;
void JustDied(Unit* /*killer*/) override void JustDied(Unit* /*killer*/) override
{ {
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal)) if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
{
Unit::Kill(p, p); Unit::Kill(p, p);
}
} }
void Reset() override void Reset() override
{ {
//First rupture should happen half a second after we spawn _scheduler.Schedule(500ms, [this](TaskContext /*task*/)
GroundRuptureTimer = 500; {
HamstringTimer = 2000; DoCastAOE(SPELL_MASSIVE_GROUND_RUPTURE);
ThrashTimer = 5000; });
EvadeTimer = 5000;
} }
void EnterCombat(Unit* /*who*/) override void EnterCombat(Unit* /*who*/) override
{ {
DoZoneInCombat(); DoZoneInCombat();
_scheduler.Schedule(2s, [this](TaskContext context)
{
DoCastVictim(SPELL_HAMSTRING);
context.Repeat(10s);
}).Schedule(5s, [this](TaskContext context) {
DoCastSelf(SPELL_THRASH);
context.Repeat(10s);
});
}
void ScheduleMeleeCheck()
{
// Check if a target is in melee range
_scheduler.Schedule(10s, [this](TaskContext task)
{
if (Unit* target = me->GetVictim())
{
if (!target->IsWithinMeleeRange(me))
{
// Main target not found within melee range, try to select a new one
if (Player* newTarget = me->SelectNearestPlayer(5.0f))
{
AttackStart(newTarget);
}
else // Main target not found, and failed to acquire a new target... Submerge
{
Submerge();
}
}
}
task.Repeat();
});
}
void Submerge()
{
if (me->SelectNearestPlayer(5.0f))
{
return;
}
// Despawn portal
if (Creature* p = ObjectAccessor::GetCreature(*me, _portalGUID))
{
p->DespawnOrUnsummon();
}
DoCastSelf(SPELL_SUBMERGE_VISUAL);
me->SetHealth(me->GetMaxHealth());
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
_scheduler.CancelAll();
_scheduler.Schedule(5s, [this](TaskContext /*task*/)
{
Emerge();
});
}
void Emerge()
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, NotInStomachSelector()))
{
Position pos = target->GetPosition();
me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), 0);
if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, pos, TEMPSUMMON_CORPSE_DESPAWN))
{
portal->SetReactState(REACT_PASSIVE);
_portalGUID = portal->GetGUID();
}
me->RemoveAurasDueToSpell(SPELL_SUBMERGE_VISUAL);
DoCastSelf(SPELL_BIRTH);
DoCastAOE(SPELL_MASSIVE_GROUND_RUPTURE, true);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
ScheduleMeleeCheck();
}
} }
void UpdateAI(uint32 diff) override void UpdateAI(uint32 diff) override
@@ -1146,70 +1162,14 @@ public:
if (!UpdateVictim()) if (!UpdateVictim())
return; return;
//EvadeTimer _scheduler.Update(diff);
if (!me->IsWithinMeleeRange(me->GetVictim()))
{
if (EvadeTimer <= diff)
{
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal))
Unit::Kill(p, p);
//Dissapear and reappear at new position
me->SetVisible(false);
Unit* target = SelectTarget(SelectTargetMethod::Random, 0);
if (!target)
{
Unit::Kill(me, me);
return;
}
if (!target->HasAura(SPELL_DIGESTIVE_ACID))
{
me->SetPosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0);
if (Creature* pPortal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{
pPortal->SetReactState(REACT_PASSIVE);
Portal = pPortal->GetGUID();
}
GroundRuptureTimer = 500;
HamstringTimer = 2000;
ThrashTimer = 5000;
EvadeTimer = 5000;
AttackStart(target);
}
me->SetVisible(true);
}
else EvadeTimer -= diff;
}
//GroundRuptureTimer
if (GroundRuptureTimer <= diff)
{
DoCastVictim(SPELL_GROUND_RUPTURE);
GroundRuptureTimer = 30000;
}
else GroundRuptureTimer -= diff;
//ThrashTimer
if (ThrashTimer <= diff)
{
DoCastVictim(SPELL_THRASH);
ThrashTimer = 10000;
}
else ThrashTimer -= diff;
//HamstringTimer
if (HamstringTimer <= diff)
{
DoCastVictim(SPELL_HAMSTRING);
HamstringTimer = 10000;
}
else HamstringTimer -= diff;
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
} }
private:
TaskScheduler _scheduler;
ObjectGuid _portalGUID;
}; };
}; };
@@ -1229,26 +1189,34 @@ public:
{ {
SetCombatMovement(false); SetCombatMovement(false);
if (Creature* pPortal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN)) if (Creature* portal = me->SummonCreature(NPC_GIANT_PORTAL, *me, TEMPSUMMON_CORPSE_DESPAWN))
{ {
pPortal->SetReactState(REACT_PASSIVE); portal->SetReactState(REACT_PASSIVE);
Portal = pPortal->GetGUID(); _portalGUID = portal->GetGUID();
} }
} }
uint32 BeamTimer;
ObjectGuid Portal;
void JustDied(Unit* /*killer*/) override void JustDied(Unit* /*killer*/) override
{ {
if (Unit* p = ObjectAccessor::GetUnit(*me, Portal)) if (Unit* p = ObjectAccessor::GetUnit(*me, _portalGUID))
{
Unit::Kill(p, p); Unit::Kill(p, p);
}
} }
void Reset() override void Reset() override
{ {
//Green Beam half a second after we spawn _scheduler.Schedule(500ms, [this](TaskContext /*task*/)
BeamTimer = 500; {
DoCastAOE(SPELL_MASSIVE_GROUND_RUPTURE);
}).Schedule(1s, 5s, [this](TaskContext context) {
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, -SPELL_DIGESTIVE_ACID))
{
DoCast(target, SPELL_GREEN_BEAM);
}
context.Repeat(2100ms);
});
} }
void EnterCombat(Unit* /*who*/) override void EnterCombat(Unit* /*who*/) override
@@ -1262,18 +1230,12 @@ public:
if (!UpdateVictim()) if (!UpdateVictim())
return; return;
//BeamTimer _scheduler.Update(diff);
if (BeamTimer <= diff)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0);
if (target && !target->HasAura(SPELL_DIGESTIVE_ACID))
DoCast(target, SPELL_GREEN_BEAM);
//Beam every 2 seconds
BeamTimer = 2100;
}
else BeamTimer -= diff;
} }
private:
TaskScheduler _scheduler;
ObjectGuid _portalGUID;
}; };
}; };
@@ -69,8 +69,6 @@ public:
{ {
if (p->GetZoneId() == me->GetZoneId()) if (p->GetZoneId() == me->GetZoneId())
{ {
p->RemoveAurasDueToSpell(SPELL_AURA_OF_FROST);
p->RemoveAurasDueToSpell(SPELL_CHILL); p->RemoveAurasDueToSpell(SPELL_CHILL);
p->RemoveAurasDueToSpell(SPELL_FROST_BREATH); p->RemoveAurasDueToSpell(SPELL_FROST_BREATH);
} }
@@ -738,48 +738,6 @@ class spell_gen_no_offhand_proc : public AuraScript
} }
}; };
/* 71602 - Item - Icecrown 25 Normal Caster Trinket 1 Base
71645 - Item - Icecrown 25 Heroic Caster Trinket 1 Base
71845 - Item - Icecrown 25 Normal Caster Weapon Proc
71846 - Item - Icecrown 25 Heroic Caster Weapon Proc
72419 - Item - Icecrown Reputation Ring Healer Trigger
75465 - Item - Chamber of Aspects 25 Nuker Trinket
75474 - Item - Chamber of Aspects 25 Heroic Nuker Trinket */
class spell_gen_proc_once_per_cast : public AuraScript
{
PrepareAuraScript(spell_gen_proc_once_per_cast);
bool Load() override
{
_spellPointer = nullptr;
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
if (eventInfo.GetActor())
{
if (Player* player = eventInfo.GetActor()->ToPlayer())
{
if (player->m_spellModTakingSpell == _spellPointer)
{
return false;
}
_spellPointer = player->m_spellModTakingSpell;
}
}
return true;
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_gen_proc_once_per_cast::CheckProc);
}
private:
Spell* _spellPointer;
};
// 70805 - Item - Rogue T10 2P Bonus // 70805 - Item - Rogue T10 2P Bonus
class spell_gen_proc_on_self : public AuraScript class spell_gen_proc_on_self : public AuraScript
{ {
@@ -4545,7 +4503,6 @@ void AddSC_generic_spell_scripts()
RegisterSpellScript(spell_gen_use_spell_base_level_check); RegisterSpellScript(spell_gen_use_spell_base_level_check);
RegisterSpellScript(spell_gen_proc_from_direct_damage); RegisterSpellScript(spell_gen_proc_from_direct_damage);
RegisterSpellScript(spell_gen_no_offhand_proc); RegisterSpellScript(spell_gen_no_offhand_proc);
RegisterSpellScript(spell_gen_proc_once_per_cast);
RegisterSpellScript(spell_gen_proc_on_self); RegisterSpellScript(spell_gen_proc_on_self);
RegisterSpellScript(spell_gen_proc_not_self); RegisterSpellScript(spell_gen_proc_not_self);
RegisterSpellScript(spell_gen_baby_murloc_passive); RegisterSpellScript(spell_gen_baby_murloc_passive);
@@ -1208,6 +1208,27 @@ class spell_warl_drain_soul : public AuraScript
} }
}; };
// 29341 - Shadowburn
class spell_warl_shadowburn : public AuraScript
{
PrepareAuraScript(spell_warl_shadowburn);
void RemoveEffect(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* caster = GetCaster();
Unit* target = GetTarget();
if (!(GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH && caster && target && caster->IsPlayer() && caster->ToPlayer()->isHonorOrXPTarget(target)))
{
PreventDefaultAction();
}
}
void Register() override
{
OnEffectRemove += AuraEffectRemoveFn(spell_warl_shadowburn::RemoveEffect, EFFECT_0, SPELL_AURA_CHANNEL_DEATH_ITEM, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_warlock_spell_scripts() void AddSC_warlock_spell_scripts()
{ {
RegisterSpellScript(spell_warl_eye_of_kilrogg); RegisterSpellScript(spell_warl_eye_of_kilrogg);
@@ -1238,4 +1259,5 @@ void AddSC_warlock_spell_scripts()
RegisterSpellScript(spell_warl_soulshatter); RegisterSpellScript(spell_warl_soulshatter);
RegisterSpellScript(spell_warl_unstable_affliction); RegisterSpellScript(spell_warl_unstable_affliction);
RegisterSpellScript(spell_warl_drain_soul); RegisterSpellScript(spell_warl_drain_soul);
RegisterSpellScript(spell_warl_shadowburn);
} }
@@ -302,9 +302,6 @@ public:
* --- * ---
* --- Dragonspecific scripts and handling: LETHON * --- Dragonspecific scripts and handling: LETHON
* --- * ---
*
* @todo
* - Spell: Shadow bolt whirl casts needs custom handling (spellscript)
*/ */
enum LethonTexts enum LethonTexts
@@ -318,6 +315,14 @@ enum LethonSpells
SPELL_DRAW_SPIRIT = 24811, SPELL_DRAW_SPIRIT = 24811,
SPELL_SHADOW_BOLT_WHIRL = 24834, SPELL_SHADOW_BOLT_WHIRL = 24834,
SPELL_DARK_OFFERING = 24804, SPELL_DARK_OFFERING = 24804,
SPELL_SHADOW_BOLT_WHIRL1 = 24820,
SPELL_SHADOW_BOLT_WHIRL2 = 24821,
SPELL_SHADOW_BOLT_WHIRL3 = 24822,
SPELL_SHADOW_BOLT_WHIRL4 = 24823,
SPELL_SHADOW_BOLT_WHIRL5 = 24835,
SPELL_SHADOW_BOLT_WHIRL6 = 24836,
SPELL_SHADOW_BOLT_WHIRL7 = 24837,
SPELL_SHADOW_BOLT_WHIRL8 = 24838,
}; };
enum LethonCreatures enum LethonCreatures
@@ -340,13 +345,14 @@ public:
{ {
_stage = 1; _stage = 1;
emerald_dragonAI::Reset(); emerald_dragonAI::Reset();
events.ScheduleEvent(EVENT_SHADOW_BOLT_WHIRL, 10000); me->RemoveAurasDueToSpell(SPELL_SHADOW_BOLT_WHIRL);
} }
void EnterCombat(Unit* who) override void EnterCombat(Unit* who) override
{ {
Talk(SAY_LETHON_AGGRO); Talk(SAY_LETHON_AGGRO);
WorldBossAI::EnterCombat(who); WorldBossAI::EnterCombat(who);
DoCastSelf(SPELL_SHADOW_BOLT_WHIRL, true);
} }
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
@@ -368,20 +374,6 @@ public:
} }
} }
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_SHADOW_BOLT_WHIRL:
me->CastSpell((Unit*)nullptr, SPELL_SHADOW_BOLT_WHIRL, false);
events.ScheduleEvent(EVENT_SHADOW_BOLT_WHIRL, urand(15000, 30000));
break;
default:
emerald_dragonAI::ExecuteEvent(eventId);
break;
}
}
private: private:
uint8 _stage; uint8 _stage;
}; };
@@ -712,6 +704,41 @@ public:
} }
}; };
class spell_shadow_bolt_whirl : public AuraScript
{
PrepareAuraScript(spell_shadow_bolt_whirl);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SHADOW_BOLT_WHIRL1, SPELL_SHADOW_BOLT_WHIRL2, SPELL_SHADOW_BOLT_WHIRL3, SPELL_SHADOW_BOLT_WHIRL4, SPELL_SHADOW_BOLT_WHIRL5, SPELL_SHADOW_BOLT_WHIRL6, SPELL_SHADOW_BOLT_WHIRL7, SPELL_SHADOW_BOLT_WHIRL8 });
}
void HandlePeriodic(AuraEffect const* aurEff)
{
Unit* caster = GetCaster();
Unit* target = GetTarget();
if (!caster || !target)
return;
std::array<uint32, 8> spellForTick = { SPELL_SHADOW_BOLT_WHIRL1, SPELL_SHADOW_BOLT_WHIRL2, SPELL_SHADOW_BOLT_WHIRL3, SPELL_SHADOW_BOLT_WHIRL4, SPELL_SHADOW_BOLT_WHIRL5, SPELL_SHADOW_BOLT_WHIRL6, SPELL_SHADOW_BOLT_WHIRL7, SPELL_SHADOW_BOLT_WHIRL8 };
uint32 tick = (aurEff->GetTickNumber() + 7/*-1*/) % 8;
// casted in left/right (but triggered spell have wide forward cone)
float forward = target->GetOrientation();
if (tick <= 3)
target->SetOrientation(forward + 0.75f * M_PI - tick * M_PI / 8); // Left
else
target->SetOrientation(forward - 0.75f * M_PI + (8 - tick) * M_PI / 8); // Right
target->CastSpell(target, spellForTick[tick], true);
target->SetOrientation(forward);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_shadow_bolt_whirl::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
class spell_mark_of_nature : public SpellScriptLoader class spell_mark_of_nature : public SpellScriptLoader
{ {
public: public:
@@ -765,4 +792,5 @@ void AddSC_emerald_dragons()
// dragon spellscripts // dragon spellscripts
new spell_dream_fog_sleep(); new spell_dream_fog_sleep();
new spell_mark_of_nature(); new spell_mark_of_nature();
RegisterSpellScript(spell_shadow_bolt_whirl);
}; };
@@ -1015,6 +1015,13 @@ struct FactionTemplateEntry
[[nodiscard]] bool IsContestedGuardFaction() const { return (factionFlags & FACTION_TEMPLATE_FLAG_ATTACK_PVP_ACTIVE_PLAYERS) != 0; } [[nodiscard]] bool IsContestedGuardFaction() const { return (factionFlags & FACTION_TEMPLATE_FLAG_ATTACK_PVP_ACTIVE_PLAYERS) != 0; }
}; };
struct GameObjectArtKitEntry
{
uint32 ID; // 0
//char* TextureVariation[3] // 1-3 m_textureVariations[3]
//char* AttachModel[4] // 4-8 m_attachModels[4]
};
struct GameObjectDisplayInfoEntry struct GameObjectDisplayInfoEntry
{ {
uint32 Displayid; // 0 m_ID uint32 Displayid; // 0 m_ID
+1
View File
@@ -52,6 +52,7 @@ char constexpr EmotesTextEntryfmt[] = "nxixxxxxxxxxxxxxxxx";
char constexpr EmotesTextSoundEntryfmt[] = "niiii"; char constexpr EmotesTextSoundEntryfmt[] = "niiii";
char constexpr FactionEntryfmt[] = "niiiiiiiiiiiiiiiiiiffixssssssssssssssssxxxxxxxxxxxxxxxxxx"; char constexpr FactionEntryfmt[] = "niiiiiiiiiiiiiiiiiiffixssssssssssssssssxxxxxxxxxxxxxxxxxx";
char constexpr FactionTemplateEntryfmt[] = "niiiiiiiiiiiii"; char constexpr FactionTemplateEntryfmt[] = "niiiiiiiiiiiii";
char constexpr GameObjectArtKitfmt[] = "nxxxxxxx";
char constexpr GameObjectDisplayInfofmt[] = "nsxxxxxxxxxxffffffx"; char constexpr GameObjectDisplayInfofmt[] = "nsxxxxxxxxxxffffffx";
char constexpr GemPropertiesEntryfmt[] = "nixxi"; char constexpr GemPropertiesEntryfmt[] = "nixxi";
char constexpr GlyphPropertiesfmt[] = "niii"; char constexpr GlyphPropertiesfmt[] = "niii";