Compare commits
43
Commits
bfe79dc2d0
...
3005443985
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3005443985 | ||
|
|
ee02d40e37 | ||
|
|
1c1756a1b5 | ||
|
|
11a25ded12 | ||
|
|
ed4bc78023 | ||
|
|
f58e739dcc | ||
|
|
a20c8988e8 | ||
|
|
13962ebc9f | ||
|
|
83fad1dae2 | ||
|
|
721396ef88 | ||
|
|
de14780789 | ||
|
|
bb3f84a87b | ||
|
|
0811620d76 | ||
|
|
1a914f5d74 | ||
|
|
01eaf563aa | ||
|
|
1cb0bb3f18 | ||
|
|
7e0bf614d4 | ||
|
|
41bf69e6e3 | ||
|
|
9e85d7bfa1 | ||
|
|
92949ff547 | ||
|
|
ae1c5f670f | ||
|
|
14ba04a2c0 | ||
|
|
2b4c49e31a | ||
|
|
47823f7416 | ||
|
|
5b5ce961e4 | ||
|
|
5cdb343842 | ||
|
|
472a782291 | ||
|
|
8a385c320b | ||
|
|
c694852504 | ||
|
|
67e0962a8b | ||
|
|
515efb2f86 | ||
|
|
6aee5fae08 | ||
|
|
89c539930f | ||
|
|
d3c0feebd9 | ||
|
|
b3076a01e0 | ||
|
|
ce8f02e48c | ||
|
|
246e9dccac | ||
|
|
5aa2a95eb6 | ||
|
|
c86a787d30 | ||
|
|
958e6e1ce6 | ||
|
|
8bca310f58 | ||
|
|
03b07adc15 | ||
|
|
899d0bde96 |
@@ -1,6 +1,6 @@
|
||||
# Introduction:
|
||||
|
||||
WowCommunity Project is a World of Warcraft blizzlike design based on TrinityCore, which is based on the Midnight Expansion version 12.1.0.69875.
|
||||
WowCommunity Project is a World of Warcraft blizzlike design based on TrinityCore, which is based on the Midnight Expansion version 12.1.0.69933.
|
||||
|
||||
|
||||
# Developers:
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `account` MODIFY COLUMN `username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' AFTER `id`;
|
||||
@@ -0,0 +1,23 @@
|
||||
DELETE FROM `build_info` WHERE `build` IN (69933);
|
||||
INSERT INTO `build_info` (`build`,`majorVersion`,`minorVersion`,`bugfixVersion`,`hotfixVersion`) VALUES
|
||||
(69933,12,1,0,NULL);
|
||||
|
||||
DELETE FROM `build_auth_key` WHERE `build`=69933 AND `platform`='Mac' AND `arch`='A64' AND `type`='WoW';
|
||||
DELETE FROM `build_auth_key` WHERE `build`=69933 AND `platform`='Mac' AND `arch`='A64' AND `type`='WoWC';
|
||||
DELETE FROM `build_auth_key` WHERE `build`=69933 AND `platform`='Mac' AND `arch`='x64' AND `type`='WoW';
|
||||
DELETE FROM `build_auth_key` WHERE `build`=69933 AND `platform`='Mac' AND `arch`='x64' AND `type`='WoWC';
|
||||
DELETE FROM `build_auth_key` WHERE `build`=69933 AND `platform`='Win' AND `arch`='A64' AND `type`='WoW';
|
||||
DELETE FROM `build_auth_key` WHERE `build`=69933 AND `platform`='Win' AND `arch`='x64' AND `type`='WoW';
|
||||
DELETE FROM `build_auth_key` WHERE `build`=69933 AND `platform`='Win' AND `arch`='x64' AND `type`='WoWC';
|
||||
INSERT INTO `build_auth_key` (`build`,`platform`,`arch`,`type`,`key`) VALUES
|
||||
(69933,'Mac','A64','WoW',0x855F995BA81FABAEC8282A64623EF654),
|
||||
(69933,'Mac','A64','WoWC',0x87753E122E07CFF1C89D513425D51F16),
|
||||
(69933,'Mac','x64','WoW',0x4F461CA5A8E12A654EE7ECFF66577256),
|
||||
(69933,'Mac','x64','WoWC',0x55CEFA786E7BAD5C88814CB42A440A4C),
|
||||
(69933,'Win','A64','WoW',0x8D8FD4D1186C83F2641AF2ADBBB1E674),
|
||||
(69933,'Win','x64','WoW',0xDE452B2BD2640E83AD944B07B4C76649),
|
||||
(69933,'Win','x64','WoWC',0x7CD51CFAFB5CE86AFE85D6EDDEC7CF61);
|
||||
|
||||
UPDATE `realmlist` SET `gamebuild`=69933 WHERE `gamebuild`=69875;
|
||||
|
||||
ALTER TABLE `realmlist` CHANGE `gamebuild` `gamebuild` int unsigned NOT NULL DEFAULT '69933';
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE `mail` MODIFY COLUMN `checked` int UNSIGNED NOT NULL DEFAULT 0 AFTER `cod`;
|
||||
@@ -0,0 +1,11 @@
|
||||
UPDATE `trinity_string` SET
|
||||
`content_default`=REPLACE(`content_default`,'16','%u'),
|
||||
`content_loc1`=REPLACE(`content_loc1`,'16','%u'),
|
||||
`content_loc2`=REPLACE(`content_loc2`,'16','%u'),
|
||||
`content_loc3`=REPLACE(`content_loc3`,'16','%u'),
|
||||
`content_loc4`=REPLACE(`content_loc4`,'16','%u'),
|
||||
`content_loc5`=REPLACE(`content_loc5`,'16','%u'),
|
||||
`content_loc6`=REPLACE(`content_loc6`,'16','%u'),
|
||||
`content_loc7`=REPLACE(`content_loc7`,'16','%u'),
|
||||
`content_loc8`=REPLACE(`content_loc8`,'16','%u')
|
||||
WHERE `entry`=1005;
|
||||
@@ -0,0 +1,6 @@
|
||||
-- Bind spell 459397 (Equip Earthen Weapons) to its server-side script.
|
||||
-- The spell uses SPELL_EFFECT_DUMMY + server-side script instead of SPELL_EFFECT_FORCE_EQUIP_ITEM.
|
||||
|
||||
DELETE FROM `spell_script_names` WHERE `spell_id` = 459397;
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(459397, 'spell_equip_earthen_weapons');
|
||||
@@ -0,0 +1,49 @@
|
||||
-- ==============
|
||||
-- DBErrors Fixes
|
||||
-- ==============
|
||||
DELETE FROM `disables` WHERE `sourceType`=0 AND `entry` IN (448180,1264040,1254858,1307371);
|
||||
INSERT INTO `disables` (`sourceType`, `entry`, `flags`, `params_0`, `params_1`, `comment`) VALUES
|
||||
(0, 448180, 8, '0', '0', 'Spell AI Cast AoE - Invalid Areatrigger 33235 Create Properties'),
|
||||
(0, 1264040, 8, '0', '0', 'Spell Flux Collapse - Invalid Areatrigger 33235 Create Properties'),
|
||||
(0, 1254858, 8, '0', '0', 'Spell Void Bombardment - Invalid Areatrigger 33235 Create Properties'),
|
||||
(0, 1307371, 8, '0', '0', 'Spell Fiery Demise - Invalid Areatrigger 33235 & 44010 Create Properties');
|
||||
|
||||
|
||||
DELETE FROM `quest_template` WHERE `ID` IN (90746);
|
||||
INSERT INTO `quest_template` (`ID`, `QuestType`, `QuestPackageID`, `ContentTuningID`, `QuestSortID`, `QuestInfoID`, `SuggestedGroupNum`, `RewardNextQuest`, `RewardXPDifficulty`, `RewardXPMultiplier`, `RewardMoneyDifficulty`, `RewardMoneyMultiplier`, `RewardSpell`, `RewardHonor`, `RewardKillHonor`, `RewardFavor`, `StartItem`, `RewardArtifactXPDifficulty`, `RewardArtifactXPMultiplier`, `RewardArtifactCategoryID`, `Flags`, `FlagsEx`, `FlagsEx2`, `FlagsEx3`, `RewardSkillLineID`, `RewardNumSkillUps`, `PortraitGiver`, `PortraitGiverMount`, `PortraitGiverModelSceneID`, `PortraitTurnIn`, `RewardItem1`, `RewardItem2`, `RewardItem3`, `RewardItem4`, `RewardAmount1`, `RewardAmount2`, `RewardAmount3`, `RewardAmount4`, `ItemDrop1`, `ItemDrop2`, `ItemDrop3`, `ItemDrop4`, `ItemDropQuantity1`, `ItemDropQuantity2`, `ItemDropQuantity3`, `ItemDropQuantity4`, `RewardChoiceItemID1`, `RewardChoiceItemID2`, `RewardChoiceItemID3`, `RewardChoiceItemID4`, `RewardChoiceItemID5`, `RewardChoiceItemID6`, `RewardChoiceItemQuantity1`, `RewardChoiceItemQuantity2`, `RewardChoiceItemQuantity3`, `RewardChoiceItemQuantity4`, `RewardChoiceItemQuantity5`, `RewardChoiceItemQuantity6`, `RewardChoiceItemDisplayID1`, `RewardChoiceItemDisplayID2`, `RewardChoiceItemDisplayID3`, `RewardChoiceItemDisplayID4`, `RewardChoiceItemDisplayID5`, `RewardChoiceItemDisplayID6`, `POIContinent`, `POIx`, `POIy`, `POIPriority`, `RewardTitle`, `RewardArenaPoints`, `RewardFactionID1`, `RewardFactionID2`, `RewardFactionID3`, `RewardFactionID4`, `RewardFactionID5`, `RewardFactionValue1`, `RewardFactionValue2`, `RewardFactionValue3`, `RewardFactionValue4`, `RewardFactionValue5`, `RewardFactionCapIn1`, `RewardFactionCapIn2`, `RewardFactionCapIn3`, `RewardFactionCapIn4`, `RewardFactionCapIn5`, `RewardFactionOverride1`, `RewardFactionOverride2`, `RewardFactionOverride3`, `RewardFactionOverride4`, `RewardFactionOverride5`, `RewardFactionFlags`, `AreaGroupID`, `TimeAllowed`, `AllowableRaces`, `Expansion`, `ManagedWorldStateID`, `QuestSessionBonus`, `LogTitle`, `LogDescription`, `QuestDescription`, `AreaDescription`, `QuestCompletionLog`, `RewardCurrencyID1`, `RewardCurrencyID2`, `RewardCurrencyID3`, `RewardCurrencyID4`, `RewardCurrencyQty1`, `RewardCurrencyQty2`, `RewardCurrencyQty3`, `RewardCurrencyQty4`, `PortraitGiverText`, `PortraitGiverName`, `PortraitTurnInText`, `PortraitTurnInName`, `AcceptedSoundKitID`, `CompleteSoundKitID`, `VerifiedBuild`) VALUES
|
||||
(90746, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 'The Elves Assemble', 'Speak to Arator at the war table.', 'The time for preparations have passed. Xal''atath''s forces are upon us.
|
||||
|
||||
Join us, champion, as we must rebuff this assault and then press our attack on the Darkwell.', '', '', 0, 0, 0, 0, 0, 0, 0, 0, '', '', '', '', 0, 0, 0); -- The Elves Assemble
|
||||
|
||||
UPDATE `quest_template_addon` SET `BreadcrumbForQuestId`=0 WHERE `ID` IN (89193,89402,89388,92897,88941,88769);
|
||||
UPDATE `conversation_actors` SET `CreatureId`=162804, `CreatureDisplayInfoId`=95004 WHERE `ConversationId`=15507 AND `Idx`=0;
|
||||
|
||||
UPDATE `creature_template` SET `ScriptName`='boss_speaker_brokk' WHERE `entry`=213217;
|
||||
UPDATE `creature_template` SET `ScriptName`='boss_anubzekt' WHERE `entry`=215405;
|
||||
UPDATE `creature_template` SET `ScriptName`='npc_crawler_egg' WHERE `entry`=218183;
|
||||
UPDATE `creature_template` SET `ScriptName`='boss_void_speaker_eirich' WHERE `entry`=213119;
|
||||
UPDATE `creature_template` SET `ScriptName`='boss_speaker_dorlita' WHERE `entry`=213216;
|
||||
UPDATE `creature_template` SET `ScriptName`='boss_avanoxx' WHERE `entry`=213179;
|
||||
UPDATE `creature_template` SET `ScriptName`='boss_kikatal' WHERE `entry`=215407;
|
||||
UPDATE `creature_template` SET `ScriptName`='npc_bloodstained_webmage' WHERE `entry`=223253;
|
||||
UPDATE `creature_template` SET `ScriptName`='npc_bloodworker' WHERE `entry`=215826;
|
||||
UPDATE `creature_template` SET `ScriptName`='npc_starved_crawler' WHERE `entry`=218961;
|
||||
UPDATE `creature_template` SET `ScriptName`='npc_void_rift' WHERE `entry`=213125;
|
||||
UPDATE `instance_template` SET `script`='instance_city_of_echoes' WHERE `map`=2660;
|
||||
|
||||
DELETE FROM `spell_script_names` WHERE `spell_id`=427329 AND `ScriptName`='spell_eirich_void_corruption';
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(427329, 'spell_eirich_void_corruption');
|
||||
|
||||
DELETE FROM `spell_script_names` WHERE `spell_id`=321240 AND `ScriptName`='spell_tunk_interrupting_shout';
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(321240, 'spell_tunk_interrupting_shout');
|
||||
|
||||
DELETE FROM `spell_script_names` WHERE `spell_id`=308454 AND `ScriptName`='spell_tunk_seismic_slam_selector';
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(308454, 'spell_tunk_seismic_slam_selector');
|
||||
|
||||
DELETE FROM `spell_script_names` WHERE `spell_id`=308455 AND `ScriptName`='at_tunk_seismic_slam';
|
||||
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
|
||||
(308455, 'at_tunk_seismic_slam');
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
DELETE FROM `creature_equip_template` WHERE (`CreatureID`=210264 AND `ID`=2);
|
||||
INSERT INTO `creature_equip_template` (`CreatureID`, `ID`, `ItemID1`, `AppearanceModID1`, `ItemVisual1`, `ItemID2`, `AppearanceModID2`, `ItemVisual2`, `ItemID3`, `AppearanceModID3`, `ItemVisual3`, `VerifiedBuild`) VALUES
|
||||
(210264, 2, 2703, 0, 0, 0, 0, 0, 159639, 0, 0, 69933); -- Bee Wrangler
|
||||
|
||||
DELETE FROM `areatrigger_create_properties` WHERE (`Id`=32431 AND `IsCustom`=0);
|
||||
INSERT INTO `areatrigger_create_properties` (`Id`, `IsCustom`, `AreaTriggerId`, `IsAreatriggerCustom`, `Flags`, `MoveCurveId`, `ScaleCurveId`, `MorphCurveId`, `FacingCurveId`, `AnimId`, `AnimKitId`, `DecalPropertiesId`, `SpellForVisuals`, `PositionalSoundKitId`, `TimeToTargetScale`, `Speed`, `Shape`, `ShapeData0`, `ShapeData1`, `ShapeData2`, `ShapeData3`, `ShapeData4`, `ShapeData5`, `ShapeData6`, `ShapeData7`, `Roll`, `Pitch`, `Yaw`, `TargetRoll`, `TargetPitch`, `TargetYaw`, `VerifiedBuild`) VALUES
|
||||
(32431, 0, 35085, 0, 0, 0, 0, 0, 0, -1, 0, 0, NULL, 255025, 2000, 10, 0, 120, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, 69933); -- Spell: 439524 (Fluttering Wing)
|
||||
|
||||
|
||||
UPDATE `quest_details` SET `Emote2`=0, `VerifiedBuild`=69933 WHERE `ID`=83099; -- Mergers and Acquisitions
|
||||
|
||||
DELETE FROM `world_quest_template` WHERE `QuestID` IN (57323 /*Serpent Binding*/, 55787 /*Requisition: More Kelp Buds*/, 58487 /*Plunder the Plunderers*/, 51656 /*Saurolisk Tamer Mugg*/, 57158 /*Electric Empowerment*/, 51017 /*Supplies Needed: Monelite Ore*/, 70416 /*Dragonrider Racing - Uktulut Coaster*/, 49800 /*Atal'Dazar: Spiders!*/, 57582 /*Executor of N'Zoth*/, 51112 /*Warbringer Hozzik*/, 54089 /*Omgar Doombow*/, 54666 /*Packmaster Swiftarrow*/, 58230 /*Blind the Eyes*/, 54604 /*Molok the Crusher*/, 65230 /*Bot-any*/, 57541 /*Call of the Void*/, 65268 /*Bzzzzt!*/, 71212 /*Attackin' the Brackenhide*/);
|
||||
INSERT INTO `world_quest_template` (`QuestID`, `Duration`, `VariableID`, `Value`) VALUES
|
||||
(57323, 86400, 18128, 1), -- Serpent Binding
|
||||
(55787, 86400, 17467, 1), -- Requisition: More Kelp Buds
|
||||
(58487, 86400, 18540, 3), -- Plunder the Plunderers
|
||||
(51656, 86400, 15428, 1), -- Saurolisk Tamer Mugg
|
||||
(57158, 86400, 18102, 1), -- Electric Empowerment
|
||||
(51017, 86400, 16092, 1), -- Supplies Needed: Monelite Ore
|
||||
(70416, 302400, 22376, 1), -- Dragonrider Racing - Uktulut Coaster
|
||||
(49800, 345600, 14496, 1), -- Atal'Dazar: Spiders!
|
||||
(57582, 86400, 18486, 1), -- Executor of N'Zoth
|
||||
(51112, 86400, 15085, 1), -- Warbringer Hozzik
|
||||
(54089, 25200, 16290, 1), -- Omgar Doombow
|
||||
(54666, 25200, 16290, 1), -- Packmaster Swiftarrow
|
||||
(58230, 86400, 18449, 1), -- Blind the Eyes
|
||||
(54604, 86400, 16886, 1), -- Molok the Crusher
|
||||
(65230, 86400, 21339, 1), -- Bot-any
|
||||
(57541, 86400, 18483, 1), -- Call of the Void
|
||||
(65268, 86400, 21404, 1), -- Bzzzzt!
|
||||
(71212, 302400, 22402, 1); -- Attackin' the Brackenhide
|
||||
|
||||
UPDATE `world_quest_template` SET `VariableID`=14060 WHERE `QuestID`=49096; -- Invasion Point: Naigtal
|
||||
UPDATE `world_quest_template` SET `Value`=4 WHERE `QuestID`=81632; -- Lizard Looters
|
||||
UPDATE `world_quest_template` SET `Value`=4 WHERE `QuestID`=78915; -- Squashing the Threat
|
||||
UPDATE `world_quest_template` SET `Value`=4 WHERE `QuestID`=79216; -- Web of Manipulation
|
||||
UPDATE `world_quest_template` SET `Value`=4 WHERE `QuestID`=79346; -- Chew On That
|
||||
|
||||
|
||||
|
||||
REPLACE INTO `spell_target_position` (`ID`, `EffectIndex`, `OrderIndex`, `MapID`, `PositionX`, `PositionY`, `PositionZ`, `VerifiedBuild`) VALUES
|
||||
(351936, 0, 0, 2222, 4541.384765625, 7000.7509765625, 4915.783203125, 69933), -- Spell: 351936 (Trueheart Spear) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(351936, 0, 1, 2222, 4452.28369140625, 7000.7509765625, 4915.783203125, 69933), -- Spell: 351936 (Trueheart Spear) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(351936, 0, 2, 2222, 4502.14306640625, 6967.92626953125, 4915.19287109375, 69933), -- Spell: 351936 (Trueheart Spear) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 0, 2661, 2624.0673828125, -4995.6142578125, 110.3875045776367187, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 1, 2661, 2674.609619140625, -4993.5341796875, 110.3906326293945312, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 2, 2661, 2657.208740234375, -4997.396484375, 110.5293197631835937, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 3, 2661, 2650.568359375, -5000.017578125, 110.5397491455078125, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 4, 2661, 2635.939208984375, -5002.1279296875, 110.4859695434570312, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 5, 2661, 2622.01025390625, -5000.1904296875, 110.3875045776367187, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 6, 2661, 2676.29541015625, -5006.57275390625, 110.3906326293945312, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 7, 2661, 2649.7314453125, -4984.90380859375, 110.4437332153320312, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 8, 2661, 2641.65625, -4990.5166015625, 110.4888916015625, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 9, 2661, 2671.49560546875, -5001.31591796875, 110.390625, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 10, 2661, 2669.96142578125, -4996.384765625, 110.390625, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 11, 2661, 2630.158935546875, -5001.83056640625, 110.3874969482421875, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 12, 2661, 2644.51318359375, -4992.2509765625, 110.4852523803710937, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 13, 2661, 2622.2822265625, -4994.4365234375, 110.3875045776367187, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 14, 2661, 2656.617919921875, -4988.5, 110.4727096557617187, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 15, 2661, 2620.27197265625, -4998.31787109375, 110.3875045776367187, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 16, 2661, 2643.868408203125, -4992.53759765625, 110.4864654541015625, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 17, 2661, 2633.208251953125, -4994.8095703125, 110.4166183471679687, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 18, 2661, 2649.9736328125, -5002.794921875, 110.55670166015625, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 19, 2661, 2669.12158203125, -4994.8623046875, 110.390625, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 20, 2661, 2637.28466796875, -4995.2607421875, 110.4648208618164062, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 21, 2661, 2637.918701171875, -4994.23193359375, 110.4665145874023437, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 22, 2661, 2643.307861328125, -4996.2265625, 110.5376052856445312, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 23, 2661, 2629.775390625, -4999.11669921875, 110.3874969482421875, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 24, 2661, 2651.85302734375, -4990.34326171875, 110.4799575805664062, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 25, 2661, 2638.861328125, -4994.609375, 110.4791030883789062, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 26, 2661, 2643.9560546875, -4993.86767578125, 110.49493408203125, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 27, 2661, 2653.0078125, -4987.3125, 110.4619216918945312, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 28, 2661, 2634.024169921875, -5000.3701171875, 110.4551620483398437, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 29, 2661, 2631.736572265625, -4997.20166015625, 110.3875045776367187, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 30, 2661, 2643.67333984375, -4996.85205078125, 110.5450286865234375, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 31, 2661, 2652.63818359375, -4986.99951171875, 110.4596023559570312, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 32, 2661, 2649.56298828125, -5002.04443359375, 110.5515975952148437, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 33, 2661, 2676.409912109375, -4990.60888671875, 110.3906326293945312, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 34, 2661, 2652.658935546875, -5002.55126953125, 110.5576324462890625, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 35, 2661, 2668.32275390625, -5005.16552734375, 110.390625, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 36, 2661, 2656.49951171875, -4987.41845703125, 110.4657821655273437, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 37, 2661, 2645.437744140625, -5001.26513671875, 110.588165283203125, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 38, 2661, 2675.99658203125, -4990.50634765625, 110.3906326293945312, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 39, 2661, 2645.124267578125, -5000.80615234375, 110.58221435546875, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 40, 2661, 2655.4755859375, -4986.75537109375, 110.4606704711914062, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 41, 2661, 2656.38671875, -4993.65185546875, 110.5049667358398437, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 42, 2661, 2668.746826171875, -5003.345703125, 110.390625, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 43, 2661, 2681.89794921875, -4999.205078125, 110.3906326293945312, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 44, 2661, 2658.269775390625, -4991.56201171875, 110.4935226440429687, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 45, 2661, 2630.8251953125, -4997.931640625, 110.3874969482421875, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 46, 2661, 2647.0322265625, -4991.53076171875, 110.4830245971679687, 69933), -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
(436900, 0, 47, 2661, 2670.502685546875, -4994.49755859375, 110.390625, 69933); -- Spell: 436900 (Cinder-BOOM!) Effect 0: 3 (SPELL_EFFECT_DUMMY)
|
||||
|
||||
|
||||
DELETE FROM `creature_template_difficulty` WHERE (`DifficultyID`=205 AND `Entry` IN (221194,218000,225633,219955,222951,219667,218523,210270,218865,220141,222889,220946,220060,219415,48340,48341,48342,48343,214920,214697,217126,218876,218877,216088,210269,214668,218671));
|
||||
INSERT INTO `creature_template_difficulty` (`Entry`, `DifficultyID`, `HealthScalingExpansion`, `HealthModifier`, `ManaModifier`, `CreatureDifficultyID`, `TypeFlags`, `TypeFlags2`, `TypeFlags3`) VALUES
|
||||
(221194, 205, 10, 1, 1, 270822, 0x1000400, 16, 0), -- [DNT] Beehive Trash Stalker
|
||||
(218000, 205, 10, 4.5, 1, 267495, 0x200068, 128, 0), -- Benk Buzzbee
|
||||
(225633, 205, 10, 1, 1, 276603, 0x1000000, 16, 0), -- Mead Machine
|
||||
(219955, 205, 10, 1, 1, 269527, 0x200048, 4, 0), -- Cinderbee
|
||||
(222951, 205, 10, 1, 1, 273749, 0x1000000, 16, 0), -- I'pa
|
||||
(219667, 205, 10, 1, 1, 269239, 0x40000000, 67108866, 0), -- Flamethrower
|
||||
(218523, 205, 10, 40, 1, 268029, 0x200008, 0, 0), -- Goldie Baronbottom
|
||||
(210270, 205, 10, 1.70000004768371582, 1, 258047, 0x200048, 0, 0), -- Brew Drop
|
||||
(218865, 205, 10, 1, 1, 268425, 0x200048, 0, 0), -- Bee-let
|
||||
(220141, 205, 10, 5, 1, 269750, 0x200048, 0, 0), -- Royal Jelly Purveyor
|
||||
(222889, 205, 10, 1, 1, 273686, 0x1000000, 16, 0), -- Mead Machine
|
||||
(220946, 205, 10, 8, 1, 270554, 0x200048, 2147483648, 0), -- Venture Co. Honey Harvester
|
||||
(220060, 205, 10, 5, 1, 269666, 0x200048, 0, 0), -- Taste Tester
|
||||
(219415, 205, 10, 1, 1, 268979, 0x40000000, 67108866, 0), -- Cooking Pot
|
||||
(48340, 205, 11, 1, 1, 41503, 0x0, 0, 0), -- Drink Tray
|
||||
(48341, 205, 11, 1, 1, 41501, 0x0, 0, 0), -- Goblin Cocktail
|
||||
(48342, 205, 11, 1, 1, 41499, 0x0, 0, 0), -- Goblin Cocktail
|
||||
(48343, 205, 11, 1, 1, 41497, 0x0, 0, 0), -- Goblin Cocktail
|
||||
(214920, 205, 10, 4.5, 1, 264372, 0x200048, 0, 0), -- Tasting Room Attendant
|
||||
(214697, 205, 10, 15, 1, 264148, 0x200048, 2147483648, 0), -- Chef Chewie
|
||||
(217126, 205, 10, 1, 1, 266617, 0x200048, 0, 0), -- Over-Indulged Patron
|
||||
(218876, 205, 11, 1, 1, 268436, 0x0, 0, 0), -- Rat
|
||||
(218877, 205, 11, 1, 1, 268437, 0x0, 0, 0), -- Cockroach
|
||||
(216088, 205, 10, 20, 1, 265570, 0x0, 0, 0), -- Wenbrandt
|
||||
(210269, 205, 10, 8, 1, 258046, 0x200048, 2147483648, 0), -- Hired Muscle
|
||||
(214668, 205, 10, 4.5, 1, 264119, 0x200048, 0, 0), -- Venture Co. Patron
|
||||
(218671, 205, 10, 4.5, 1, 268186, 0x200048, 0, 0); -- Venture Co. Pyromaniac
|
||||
|
||||
|
||||
DELETE FROM `creature_template_difficulty` WHERE (`DifficultyID`=205 AND `Entry` IN (221194,225633,218000,222951,219955,220141,219667,218523,210270,218865,222889,220946,220060,219415,214697,48341,48342,48343,48340,214920,216088,218671,217126,218877,218876,210269,214668));
|
||||
INSERT INTO `creature_template_difficulty` (`Entry`, `DifficultyID`, `LevelScalingDeltaMin`, `LevelScalingDeltaMax`, `ContentTuningID`, `StaticFlags1`, `StaticFlags2`, `StaticFlags3`, `StaticFlags4`, `StaticFlags5`, `StaticFlags6`, `StaticFlags7`, `StaticFlags8`, `VerifiedBuild`) VALUES
|
||||
(221194, 205, 0, 0, 2893, 0x100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 221194 ([DNT] Beehive Trash Stalker) - Sessile
|
||||
(225633, 205, 0, 0, 2893, 0x30000000, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 69933), -- 225633 (Mead Machine) - CanSwim, Floating - UninteractibleIfHostile
|
||||
(218000, 205, 2, 2, 2893, 0x10000100, 0x0, 0x0, 0x400000, 0x0, 0x0, 0x0, 0x0, 69933), -- 218000 (Benk Buzzbee) - Sessile, CanSwim - IgnoreSpellMinRangeRestrictions
|
||||
(222951, 205, 0, 0, 2893, 0x10000100, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 69933), -- 222951 (I'pa) - Sessile, CanSwim - UntargetableByClient
|
||||
(219955, 205, 0, 0, 2893, 0x30000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 219955 (Cinderbee) - CanSwim, Floating
|
||||
(220141, 205, 0, 0, 2893, 0x10000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 220141 (Royal Jelly Purveyor) - CanSwim
|
||||
(219667, 205, 0, 0, 2893, 0x100, 0x0, 0x2000000, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 219667 (Flamethrower) - Sessile - CannotTurn
|
||||
(218523, 205, 2, 2, 2893, 0x10000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 218523 (Goldie Baronbottom) - CanSwim
|
||||
(210270, 205, 0, 0, 2893, 0x10000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 210270 (Brew Drop) - CanSwim
|
||||
(218865, 205, 0, 0, 2893, 0x30000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 218865 (Bee-let) - CanSwim, Floating
|
||||
(222889, 205, 0, 0, 2893, 0x10000100, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 69933), -- 222889 (Mead Machine) - Sessile, CanSwim - UninteractibleIfHostile
|
||||
(220946, 205, 1, 1, 2893, 0x10000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 220946 (Venture Co. Honey Harvester) - CanSwim
|
||||
(220060, 205, 0, 0, 2893, 0x10000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 220060 (Taste Tester) - CanSwim
|
||||
(219415, 205, 0, 0, 2893, 0x100, 0x0, 0x2000000, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 219415 (Cooking Pot) - Sessile - CannotTurn
|
||||
(214697, 205, 1, 1, 2893, 0x10000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 214697 (Chef Chewie) - CanSwim
|
||||
(48341, 205, 0, 0, 181, 0x100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 48341 (Goblin Cocktail) - Sessile
|
||||
(48342, 205, 0, 0, 181, 0x100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 48342 (Goblin Cocktail) - Sessile
|
||||
(48343, 205, 0, 0, 181, 0x100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 48343 (Goblin Cocktail) - Sessile
|
||||
(48340, 205, 0, 0, 181, 0x100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 48340 (Drink Tray) - Sessile
|
||||
(214920, 205, 0, 0, 2893, 0x10000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 214920 (Tasting Room Attendant) - CanSwim
|
||||
(216088, 205, 0, 0, 2893, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 216088 (Wenbrandt) -
|
||||
(218671, 205, 0, 0, 2893, 0x10000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 218671 (Venture Co. Pyromaniac) - CanSwim
|
||||
(217126, 205, 0, 0, 2893, 0x10000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 217126 (Over-Indulged Patron) - CanSwim
|
||||
(218877, 205, 0, 0, 81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 218877 (Cockroach) -
|
||||
(218876, 205, 0, 0, 81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 218876 (Rat) -
|
||||
(210269, 205, 1, 1, 2893, 0x10000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933), -- 210269 (Hired Muscle) - CanSwim
|
||||
(214668, 205, 0, 0, 2893, 0x10000000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 69933); -- 214668 (Venture Co. Patron) - CanSwim
|
||||
|
||||
UPDATE `creature_model_info` SET `VerifiedBuild`=69933 WHERE `DisplayID` IN (100332, 95824, 95821, 95711, 99862, 80962, 65130, 7891, 65129, 90426, 93611, 94434, 97442, 92728, 92451, 94281, 96103, 99120, 92729, 94593, 28067, 93169, 92704, 98189, 95707, 114807, 92725, 123097, 121102, 121109, 120631, 24109, 120498, 117177, 118074, 118270, 119017, 4587, 63016, 84893, 119445, 119441, 100041, 36638, 118378, 120557, 117818, 119459, 121056, 124003, 121064, 119460, 118000, 117828, 121061, 118004, 108585, 118003, 121058, 118076, 121055, 116429, 121087, 119023, 117811, 119437, 119020, 113757, 113756, 113753, 113752, 121035, 119022, 119026, 118068, 119032, 121036, 36115, 119019, 36116, 36117, 36114, 119018, 121037, 114514, 121034, 119030, 119033, 119013, 119015, 119034, 119021, 12191, 74917, 118999, 23767, 119028, 101418, 94627, 96603, 99054, 94586, 90397, 92345, 99382, 92714, 93595, 98692, 88012, 93600, 74802, 86231, 90422, 104785, 99205, 88016, 95964, 96614, 96637, 96281, 95843, 10095, 96714, 19283, 93151, 95260, 105361, 99478, 98076, 99162, 99156, 92192, 96642, 95948, 96754, 93577, 100398, 93587, 97425, 92399, 96747, 105360, 94491, 93585, 104818, 95042, 95194, 94665, 83350, 98220, 95253, 62093, 93578, 95252, 94286, 93582, 97347, 93951, 93579, 94141, 95464, 93598, 93584, 94626, 24103, 93601, 93232, 98697, 94611, 97025, 92385, 95511, 27153, 96591, 95532, 97424, 96196, 96748, 97650, 94614, 93580, 93593, 93586, 93599, 93588, 93597, 97649, 93589, 97651, 93596, 73364, 95529, 93590, 94449, 96624, 25420, 94655, 95081, 25375, 94657, 25439, 25423, 98194, 96625, 95557, 95660, 95004, 98159, 97386, 93645, 96576, 100066, 101294, 92627, 93606, 96173, 96174, 100494, 93241, 100712, 93305, 93306, 93223, 94101, 98176, 99134, 99208, 92915, 96348, 92676, 92191, 98015, 98598, 35372, 97186, 97107, 100299, 95479, 100289, 99189, 92411, 92412, 95169, 98814, 100015, 37926, 94426, 98486, 37916, 100287, 37921, 96827, 94390, 97315, 101324, 101286, 100290, 95012, 94396, 100403, 100188, 92415, 27823, 92534, 98538, 92410, 97086, 93631, 100302, 94398, 92416, 98550, 98529, 95630, 98547, 11686);
|
||||
UPDATE `creature_model_info` SET `BoundingRadius`=3.061506509780883789, `CombatReach`=2.519999980926513671, `VerifiedBuild`=69933 WHERE `DisplayID`=92701;
|
||||
UPDATE `creature_model_info` SET `BoundingRadius`=0.5, `CombatReach`=1, `VerifiedBuild`=69933 WHERE `DisplayID`=110046;
|
||||
UPDATE `creature_model_info` SET `BoundingRadius`=0.687459588050842285, `VerifiedBuild`=69933 WHERE `DisplayID`=93753;
|
||||
UPDATE `creature_model_info` SET `BoundingRadius`=3.66400146484375, `CombatReach`=4, `VerifiedBuild`=69933 WHERE `DisplayID`=100067;
|
||||
|
||||
|
||||
REPLACE INTO `npc_text` (`ID`, `Probability0`, `Probability1`, `Probability2`, `Probability3`, `Probability4`, `Probability5`, `Probability6`, `Probability7`, `BroadcastTextId0`, `BroadcastTextId1`, `BroadcastTextId2`, `BroadcastTextId3`, `BroadcastTextId4`, `BroadcastTextId5`, `BroadcastTextId6`, `BroadcastTextId7`, `VerifiedBuild`) VALUES
|
||||
(164079, 1, 0, 0, 0, 0, 0, 0, 0, 217158, 0, 0, 0, 0, 0, 0, 0, 69933); -- 164079 (Highlord Bolvar Fordragon)
|
||||
|
||||
REPLACE INTO `gossip_menu` (`MenuID`, `TextID`, `VerifiedBuild`) VALUES
|
||||
(25540, 164079, 69933); -- 164079 (Highlord Bolvar Fordragon)
|
||||
|
||||
|
||||
|
||||
UPDATE `gossip_menu` SET `VerifiedBuild`=69933 WHERE (`MenuID`=26693 AND `TextID`=42426) OR (`MenuID`=25278 AND `TextID`=40584);
|
||||
|
||||
|
||||
UPDATE `gossip_menu_addon` SET `VerifiedBuild`=69933 WHERE `MenuID`=25278;
|
||||
|
||||
UPDATE `gossip_menu_option` SET `VerifiedBuild`=69933 WHERE (`MenuID`=26693 AND `OptionID`=4) OR (`MenuID`=25278 AND `OptionID`=5);
|
||||
UPDATE `gossip_menu_option` SET `GossipOptionID`=55156, `VerifiedBuild`=69933 WHERE (`MenuID`=25540 AND `OptionID`=6); -- OptionBroadcastTextID: 137786 - 144263 - 160761 - 160763 - 160765 - 160768 - 167552 - 173473 - 176737 - 188459 - 202026 - 205118 - 205774
|
||||
|
||||
REPLACE INTO instance_template (map, parent, script, insideResurrection) VALUES (2661, 0, 'instance_cinderbrew_meadery', 1);
|
||||
|
||||
UPDATE creature_template SET ScriptName='boss_brew_master_aldryr' WHERE entry IN (210271);
|
||||
UPDATE creature_template SET ScriptName='boss_ipa' WHERE entry IN (210267);
|
||||
UPDATE creature_template SET ScriptName='boss_benk_buzzbee' WHERE entry IN (218002);
|
||||
UPDATE creature_template SET ScriptName='boss_goldie_baronbottom' WHERE entry IN (214661);
|
||||
UPDATE creature_template SET ScriptName='npc_goldie_desk' WHERE entry IN (218523);
|
||||
UPDATE creature_template SET ScriptName='npc_thirsty_patron' WHERE entry IN (215819);
|
||||
UPDATE creature_template SET ScriptName='npc_brew_drop' WHERE entry IN (219301, 223562);
|
||||
UPDATE creature_template SET ScriptName='npc_honey_barrel' WHERE entry IN (219005);
|
||||
UPDATE creature_template SET ScriptName='npc_bee_let' WHERE entry IN (218865);
|
||||
UPDATE creature_template SET ScriptName='npc_cinderbrew_bomb' WHERE entry IN (217837);
|
||||
UPDATE creature_template SET ScriptName='npc_pyromaniac' WHERE entry IN (218671);
|
||||
UPDATE creature_template SET ScriptName='npc_honey_harvester' WHERE entry IN (220946);
|
||||
UPDATE creature_template SET ScriptName='npc_royal_jelly_purveyor' WHERE entry IN (220141);
|
||||
UPDATE creature_template SET ScriptName='npc_bee_wrangler' WHERE entry IN (210264);
|
||||
UPDATE creature_template SET ScriptName='npc_hired_muscle' WHERE entry IN (210269);
|
||||
UPDATE creature_template SET ScriptName='npc_careless_hopgoblin' WHERE entry IN (223423);
|
||||
UPDATE creature_template SET ScriptName='npc_taste_tester' WHERE entry IN (220060);
|
||||
UPDATE creature_template SET ScriptName='npc_flavor_scientist' WHERE entry IN (214673);
|
||||
UPDATE creature_template SET ScriptName='npc_venture_patron' WHERE entry IN (214668);
|
||||
|
||||
-- Clear SmartAI on Pyromaniac so the script AI is used
|
||||
UPDATE creature_template SET AIName='' WHERE entry IN (218671);
|
||||
@@ -262,7 +262,10 @@ void VehicleAI::UpdateAI(uint32 diff)
|
||||
void VehicleAI::OnCharmed(bool /*isNew*/)
|
||||
{
|
||||
bool const charmed = me->IsCharmed();
|
||||
if (!me->GetVehicleKit()->IsVehicleInUse() && !charmed && _hasConditions) // was used and has conditions
|
||||
Vehicle* kit = me->GetVehicleKit();
|
||||
// A creature scripted as VehicleAI can be charmed before a kit exists. The giant boar
|
||||
// summon takes this path; dereferencing a missing kit took the worldserver down.
|
||||
if (kit && !kit->IsVehicleInUse() && !charmed && _hasConditions) // was used and has conditions
|
||||
{
|
||||
_dismiss = true; // needs reset
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "SRP6.h"
|
||||
#include "Util.h"
|
||||
#include "World.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
using AccountSRP6 = Trinity::Crypto::SRP::GruntSRP6;
|
||||
@@ -45,7 +46,7 @@ AccountMgr* AccountMgr::instance()
|
||||
|
||||
AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password, std::string email /*= ""*/, uint32 bnetAccountId /*= 0*/, uint8 bnetIndex /*= 0*/)
|
||||
{
|
||||
if (utf8length(username) > MAX_ACCOUNT_STR)
|
||||
if (utf8length(username) > MAX_ACCOUNT_STR[sWorld->getBoolConfig(CONFIG_EXTENDED_ACCOUNT_NAME_LENGTH_LIMIT)] || username.length() > MAX_ACCOUNT_NAME_BYTES)
|
||||
return AccountOpResult::AOR_NAME_TOO_LONG; // username's too long
|
||||
|
||||
if (utf8length(password) > MAX_PASS_STR)
|
||||
@@ -175,7 +176,7 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUser
|
||||
if (!result)
|
||||
return AccountOpResult::AOR_NAME_NOT_EXIST;
|
||||
|
||||
if (utf8length(newUsername) > MAX_ACCOUNT_STR)
|
||||
if (utf8length(newUsername) > MAX_ACCOUNT_STR[sWorld->getBoolConfig(CONFIG_EXTENDED_ACCOUNT_NAME_LENGTH_LIMIT)] || newUsername.length() > MAX_ACCOUNT_NAME_BYTES)
|
||||
return AccountOpResult::AOR_NAME_TOO_LONG;
|
||||
|
||||
if (utf8length(newPassword) > MAX_PASS_STR)
|
||||
|
||||
@@ -40,9 +40,10 @@ enum PasswordChangeSecurity
|
||||
PW_RBAC
|
||||
};
|
||||
|
||||
#define MAX_PASS_STR 16
|
||||
#define MAX_ACCOUNT_STR 16
|
||||
#define MAX_EMAIL_STR 64
|
||||
inline constexpr std::size_t MAX_ACCOUNT_STR[2] = { 16, 64 };
|
||||
inline constexpr std::size_t MAX_ACCOUNT_NAME_BYTES = 255;
|
||||
inline constexpr std::size_t MAX_PASS_STR = 16;
|
||||
inline constexpr std::size_t MAX_EMAIL_STR = 64;
|
||||
|
||||
namespace rbac
|
||||
{
|
||||
|
||||
@@ -1681,7 +1681,7 @@ bool AuctionHouseObject::BuyCommodity(CharacterDatabaseTransaction trans, Player
|
||||
MailDraft(AuctionHouseMgr::BuildCommodityAuctionMailSubject(AuctionMailType::Sold, itemId, boughtFromAuction),
|
||||
AuctionHouseMgr::BuildAuctionSoldMailBody(player->GetGUID(), auction->BuyoutOrUnitPrice * boughtFromAuction, boughtFromAuction, depositPart, auctionHouseCut))
|
||||
.AddMoney(profit)
|
||||
.SendMailTo(trans, MailReceiver(ObjectAccessor::FindConnectedPlayer(auction->Owner), auction->Owner), this, MAIL_CHECK_MASK_COPIED, sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY));
|
||||
.SendMailTo(trans, MailReceiver(ObjectAccessor::FindConnectedPlayer(auction->Owner), auction->Owner), this, MAIL_CHECK_MASK_COPIED | MAIL_CHECK_MASK_AUCTION, sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY));
|
||||
}
|
||||
|
||||
player->ModifyMoney(-int64(totalPrice));
|
||||
@@ -1703,7 +1703,7 @@ bool AuctionHouseObject::BuyCommodity(CharacterDatabaseTransaction trans, Player
|
||||
mail.AddItem(batch.Items[i]);
|
||||
}
|
||||
|
||||
mail.SendMailTo(trans, player, this, MAIL_CHECK_MASK_COPIED);
|
||||
mail.SendMailTo(trans, player, this, MAIL_CHECK_MASK_COPIED | MAIL_CHECK_MASK_AUCTION_WON | MAIL_CHECK_MASK_AUCTION);
|
||||
}
|
||||
|
||||
WorldPackets::AuctionHouse::AuctionWonNotification packet;
|
||||
@@ -1748,7 +1748,7 @@ void AuctionHouseObject::SendAuctionOutbid(AuctionPosting const* auction, Object
|
||||
|
||||
MailDraft(AuctionHouseMgr::BuildItemAuctionMailSubject(AuctionMailType::Outbid, auction), "")
|
||||
.AddMoney(auction->BidAmount)
|
||||
.SendMailTo(trans, MailReceiver(oldBidder, auction->Bidder), this, MAIL_CHECK_MASK_COPIED);
|
||||
.SendMailTo(trans, MailReceiver(oldBidder, auction->Bidder), this, MAIL_CHECK_MASK_COPIED | MAIL_CHECK_MASK_AUCTION);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1816,7 +1816,7 @@ void AuctionHouseObject::SendAuctionWon(AuctionPosting const* auction, Player* b
|
||||
bidder->UpdateCriteria(CriteriaType::AuctionsWon, 1);
|
||||
}
|
||||
|
||||
mail.SendMailTo(trans, MailReceiver(bidder, auction->Bidder), this, MAIL_CHECK_MASK_COPIED);
|
||||
mail.SendMailTo(trans, MailReceiver(bidder, auction->Bidder), this, MAIL_CHECK_MASK_COPIED | MAIL_CHECK_MASK_AUCTION_WON | MAIL_CHECK_MASK_AUCTION);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1853,7 +1853,7 @@ void AuctionHouseObject::SendAuctionSold(AuctionPosting const* auction, Player*
|
||||
MailDraft(AuctionHouseMgr::BuildItemAuctionMailSubject(AuctionMailType::Sold, auction),
|
||||
AuctionHouseMgr::BuildAuctionSoldMailBody(auction->Bidder, auction->BidAmount, auction->BuyoutOrUnitPrice, auction->Deposit, auctionHouseCut))
|
||||
.AddMoney(profit)
|
||||
.SendMailTo(trans, MailReceiver(owner, auction->Owner), this, MAIL_CHECK_MASK_COPIED, sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY));
|
||||
.SendMailTo(trans, MailReceiver(owner, auction->Owner), this, MAIL_CHECK_MASK_COPIED | MAIL_CHECK_MASK_AUCTION, sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1874,7 +1874,7 @@ void AuctionHouseObject::SendAuctionExpired(AuctionPosting const* auction, Chara
|
||||
for (std::size_t i = 0; i < MAX_MAIL_ITEMS && itemItr != auction->Items.end(); ++i, ++itemItr)
|
||||
mail.AddItem(*itemItr);
|
||||
|
||||
mail.SendMailTo(trans, MailReceiver(owner, auction->Owner), this, MAIL_CHECK_MASK_COPIED, 0);
|
||||
mail.SendMailTo(trans, MailReceiver(owner, auction->Owner), this, MAIL_CHECK_MASK_COPIED | MAIL_CHECK_MASK_AUCTION, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1898,7 +1898,7 @@ void AuctionHouseObject::SendAuctionRemoved(AuctionPosting const* auction, Playe
|
||||
for (std::size_t i = 0; i < MAX_MAIL_ITEMS && itemItr != auction->Items.end(); ++i, ++itemItr)
|
||||
draft.AddItem(*itemItr);
|
||||
|
||||
draft.SendMailTo(trans, owner, this, MAIL_CHECK_MASK_COPIED);
|
||||
draft.SendMailTo(trans, owner, this, MAIL_CHECK_MASK_COPIED | MAIL_CHECK_MASK_AUCTION);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1911,7 +1911,7 @@ void AuctionHouseObject::SendAuctionCancelledToBidder(AuctionPosting const* auct
|
||||
if ((bidder || sCharacterCache->HasCharacterCacheEntry(auction->Bidder)) && !sAuctionBotConfig->IsBotChar(auction->Bidder))
|
||||
MailDraft(AuctionHouseMgr::BuildItemAuctionMailSubject(AuctionMailType::Removed, auction), "")
|
||||
.AddMoney(auction->BidAmount)
|
||||
.SendMailTo(trans, MailReceiver(bidder, auction->Bidder), this, MAIL_CHECK_MASK_COPIED);
|
||||
.SendMailTo(trans, MailReceiver(bidder, auction->Bidder), this, MAIL_CHECK_MASK_COPIED | MAIL_CHECK_MASK_AUCTION);
|
||||
}
|
||||
|
||||
void AuctionHouseObject::SendAuctionInvoice(AuctionPosting const* auction, Player* owner, CharacterDatabaseTransaction trans) const
|
||||
@@ -1930,6 +1930,6 @@ void AuctionHouseObject::SendAuctionInvoice(AuctionPosting const* auction, Playe
|
||||
MailDraft(AuctionHouseMgr::BuildItemAuctionMailSubject(AuctionMailType::Invoice, auction),
|
||||
AuctionHouseMgr::BuildAuctionInvoiceMailBody(auction->Bidder, auction->BidAmount, auction->BuyoutOrUnitPrice, auction->Deposit,
|
||||
CalculateAuctionHouseCut(auction->BidAmount), sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY), eta.GetPackedTime()))
|
||||
.SendMailTo(trans, MailReceiver(owner, auction->Owner), this, MAIL_CHECK_MASK_COPIED);
|
||||
.SendMailTo(trans, MailReceiver(owner, auction->Owner), this, MAIL_CHECK_MASK_COPIED | MAIL_CHECK_MASK_AUCTION);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ void CalendarMgr::RemoveEvent(CalendarEvent* calendarEvent, ObjectGuid remover)
|
||||
if (!remover.IsEmpty() && invite->GetInviteeGUID() != remover)
|
||||
{
|
||||
MailDraft mail(calendarEvent->BuildCalendarMailSubject(remover), calendarEvent->BuildCalendarMailBody(ObjectAccessor::FindConnectedPlayer(invite->GetInviteeGUID())));
|
||||
mail.SendMailTo(trans, MailReceiver(invite->GetInviteeGUID().GetCounter()), calendarEvent, MAIL_CHECK_MASK_COPIED);
|
||||
mail.SendMailTo(trans, MailReceiver(invite->GetInviteeGUID().GetCounter()), calendarEvent, MAIL_CHECK_MASK_COPIED | MAIL_CHECK_MASK_CALENDAR_INVITE);
|
||||
}
|
||||
|
||||
delete invite;
|
||||
|
||||
@@ -913,7 +913,7 @@ namespace
|
||||
static const DB2FieldMeta ProfessionTraitXEffectLoadFields[4] =
|
||||
{
|
||||
{.IsSigned = false, .Type = FT_INT, .Name = "ID" },
|
||||
{.IsSigned = true, .Type = FT_INT, .Name = "ProfessionTraitID" },
|
||||
{.IsSigned = false, .Type = FT_INT, .Name = "ProfessionTraitID" },
|
||||
{.IsSigned = true, .Type = FT_INT, .Name = "ProfessionEffectID" },
|
||||
{.IsSigned = true, .Type = FT_INT, .Name = "Field_10_0_0_44649_003" },
|
||||
};
|
||||
@@ -949,7 +949,7 @@ namespace
|
||||
{.IsSigned = true, .Type = FT_INT, .Name = "ExpansionID" },
|
||||
{.IsSigned = true, .Type = FT_INT, .Name = "SpecResetSpellID" },
|
||||
{.IsSigned = true, .Type = FT_INT, .Name = "SpecResetCurrencyID" },
|
||||
{.IsSigned = true, .Type = FT_INT, .Name = "ProfessionID" },
|
||||
{.IsSigned = false, .Type = FT_INT, .Name = "ProfessionID" },
|
||||
};
|
||||
static const DB2FileLoadInfo ProfessionExpansionLoadInfo{ ProfessionExpansionLoadFields, 8, &ProfessionExpansionMeta };
|
||||
|
||||
|
||||
@@ -199,7 +199,9 @@ void Conversation::Create(ObjectGuid::LowType lowGuid, uint32 conversationEntry,
|
||||
if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_CONVERSATION_LINE, line->Id, creator))
|
||||
continue;
|
||||
|
||||
ConversationLineEntry const* convoLine = sConversationLineStore.LookupEntry(line->Id); // never null for conversationTemplate->Lines
|
||||
ConversationLineEntry const* convoLine = sConversationLineStore.LookupEntry(line->Id);
|
||||
if (!convoLine)
|
||||
continue;
|
||||
|
||||
UF::ConversationLine& lineField = lines.emplace_back();
|
||||
lineField.ConversationLineID = line->Id;
|
||||
@@ -226,7 +228,9 @@ void Conversation::Create(ObjectGuid::LowType lowGuid, uint32 conversationEntry,
|
||||
}
|
||||
}
|
||||
|
||||
_duration = *std::ranges::max_element(_lastLineEndTimes);
|
||||
// A conversation whose lines were all filtered out has no end times.
|
||||
// max_element on that empty map crashed the Re-Sizer conversation.
|
||||
_duration = _lastLineEndTimes.empty() ? 0ms : *std::ranges::max_element(_lastLineEndTimes);
|
||||
SetUpdateFieldValue(m_values.ModifyValue(&Conversation::m_conversationData).ModifyValue(&UF::ConversationData::LastLineEndTime), _duration.count());
|
||||
SetUpdateFieldValue(m_values.ModifyValue(&Conversation::m_conversationData).ModifyValue(&UF::ConversationData::Lines), std::move(lines));
|
||||
|
||||
|
||||
@@ -269,6 +269,9 @@ void TempSummon::InitSummon(WorldObject* summoner)
|
||||
{
|
||||
if (summoner)
|
||||
{
|
||||
if (Unit* unitSummoner = summoner->ToUnit())
|
||||
unitSummoner->RegisterSummonedCreature(this);
|
||||
|
||||
if (summoner->GetTypeId() == TYPEID_UNIT)
|
||||
{
|
||||
if (summoner->ToCreature()->IsAIEnabled())
|
||||
@@ -368,6 +371,9 @@ void TempSummon::RemoveFromWorld()
|
||||
if (!IsInWorld())
|
||||
return;
|
||||
|
||||
if (Unit* summoner = GetSummonerUnit())
|
||||
summoner->UnregisterSummonedCreature(GetGUID());
|
||||
|
||||
if (m_Properties && m_Properties->Slot != 0)
|
||||
if (Unit* owner = GetSummonerUnit())
|
||||
for (ObjectGuid& summonSlot : owner->m_SummonSlot)
|
||||
|
||||
@@ -186,7 +186,7 @@ void DynamicObject::SetDuration(int32 newDuration)
|
||||
|
||||
void DynamicObject::Delay(int32 delaytime)
|
||||
{
|
||||
SetDuration(GetDuration() - delaytime);
|
||||
SetDuration(std::max(GetDuration() - delaytime, 0));
|
||||
}
|
||||
|
||||
void DynamicObject::SetAura(Aura* aura)
|
||||
|
||||
@@ -2233,7 +2233,7 @@ uint32 Item::GetSellPrice(Player const* owner, bool forVendor /*= false*/) const
|
||||
{
|
||||
ItemTemplate const* itemTemplate = GetTemplate();
|
||||
int64 price = Item::GetSellPrice(itemTemplate, GetQuality(), GetItemLevel(owner));
|
||||
if (forVendor)
|
||||
if (price && forVendor)
|
||||
{
|
||||
std::span<ItemEffectEntry const* const> effects = GetEffects();
|
||||
auto effectWithCharges = std::ranges::find_if(effects,
|
||||
|
||||
@@ -54,6 +54,15 @@ void CinematicMgr::NextCinematicCamera()
|
||||
if (!cinematicCameraId)
|
||||
return;
|
||||
|
||||
CinematicSequencesEntry const* activeCinematic = m_activeCinematic;
|
||||
int32 activeCamera = m_activeCinematicCameraIndex;
|
||||
|
||||
if (!m_CinematicObjectGUID.IsEmpty())
|
||||
EndCinematic();
|
||||
|
||||
m_activeCinematic = activeCinematic;
|
||||
m_activeCinematicCameraIndex = activeCamera;
|
||||
|
||||
if (std::vector<FlyByCamera> const* flyByCameras = GetFlyByCameras(cinematicCameraId))
|
||||
{
|
||||
// Initialize diff, and set camera
|
||||
@@ -98,6 +107,8 @@ void CinematicMgr::EndCinematic()
|
||||
|
||||
if (WorldObject* cinematicObject = ObjectAccessor::GetWorldObject(*player, m_CinematicObjectGUID))
|
||||
cinematicObject->AddObjectToRemoveList();
|
||||
|
||||
m_CinematicObjectGUID.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11680,6 +11680,42 @@ Item* Player::_StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool
|
||||
}
|
||||
}
|
||||
|
||||
void Player::ForceEquipItemFromInventory(uint32 itemId, uint32 maxCount)
|
||||
{
|
||||
uint32 equipped = 0;
|
||||
while (Item* item = GetItemByEntry(itemId, ItemSearchLocation::Inventory))
|
||||
{
|
||||
if (maxCount && equipped >= maxCount)
|
||||
break;
|
||||
|
||||
uint16 src = item->GetPos();
|
||||
uint16 dest;
|
||||
if (CanEquipItem(NULL_SLOT, dest, item, true) != EQUIP_ERR_OK || dest == src)
|
||||
break;
|
||||
|
||||
Item* dstItem = GetItemByPos(dest);
|
||||
ItemPosCountVec sSrc;
|
||||
if (dstItem)
|
||||
{
|
||||
if (CanUnequipItem(dest, false) != EQUIP_ERR_OK)
|
||||
break;
|
||||
if (CanStoreItem(src >> 8, src & 255, sSrc, dstItem, true) != EQUIP_ERR_OK &&
|
||||
CanStoreItem(NULL_BAG, NULL_SLOT, sSrc, dstItem, true) != EQUIP_ERR_OK)
|
||||
break;
|
||||
RemoveItem(dest >> 8, dest & 255, false);
|
||||
}
|
||||
|
||||
RemoveItem(src >> 8, src & 255, true);
|
||||
EquipItem(dest, item, true);
|
||||
|
||||
if (dstItem)
|
||||
StoreItem(sSrc, dstItem, true);
|
||||
|
||||
AutoUnequipOffhandIfNeed();
|
||||
++equipped;
|
||||
}
|
||||
}
|
||||
|
||||
Item* Player::EquipNewItem(uint16 pos, uint32 item, ItemContext context, bool update)
|
||||
{
|
||||
if (Item* pItem = Item::CreateItem(item, 1, context, this))
|
||||
@@ -18619,6 +18655,14 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
|
||||
return false;
|
||||
}
|
||||
|
||||
m_atLoginFlags = fields.at_login;
|
||||
|
||||
if (HasAtLoginFlag(AT_LOGIN_RENAME))
|
||||
{
|
||||
TC_LOG_ERROR("entities.player.cheat", "Player::LoadFromDB: Player ({}) tried to login while forced to rename, can't load.'", guid.ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
_Create(guid);
|
||||
|
||||
m_name = std::move(fields.name);
|
||||
@@ -18708,8 +18752,6 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
|
||||
ReplaceAllPlayerFlagsEx(fields.playerFlagsEx);
|
||||
SetWatchedFactionIndex(fields.watchedFaction);
|
||||
|
||||
m_atLoginFlags = fields.at_login;
|
||||
|
||||
if (!GetSession()->ValidateAppearance(Races(GetRace()), Classes(GetClass()), fields.gender, MakeChrCustomizationChoiceRange(customizations)))
|
||||
{
|
||||
TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player ({}) has wrong Appearance values (Hair/Skin/Color), can't load.", guid.ToString());
|
||||
@@ -19011,6 +19053,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
|
||||
}
|
||||
}
|
||||
|
||||
// no early return is allowed past this point, player will be deleted and still referenced by the map and battleground AddPlayer can apply auras also
|
||||
SetMap(map);
|
||||
UpdatePositionData();
|
||||
|
||||
@@ -19058,12 +19101,6 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
|
||||
|
||||
_LoadPetStable(fields.summonedPetNumber, holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS));
|
||||
|
||||
if (HasAtLoginFlag(AT_LOGIN_RENAME))
|
||||
{
|
||||
TC_LOG_ERROR("entities.player.cheat", "Player::LoadFromDB: Player ({}) tried to login while forced to rename, can't load.'", GetGUID().ToString());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Honor system
|
||||
// Update Honor kills data
|
||||
m_lastHonorUpdateTime = logoutTime;
|
||||
@@ -19890,7 +19927,7 @@ void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult arti
|
||||
draft.AddItem(problematicItems.front());
|
||||
problematicItems.pop_front();
|
||||
}
|
||||
draft.SendMailTo(trans, this, MailSender(this, MAIL_STATIONERY_GM), MAIL_CHECK_MASK_COPIED);
|
||||
draft.SendMailTo(trans, this, MailSender(this, MAIL_STATIONERY_GM), MAIL_CHECK_MASK_COPIED | MAIL_CHECK_MASK_NOT_RETURNABLE | MAIL_CHECK_MASK_RESTORED_ITEM);
|
||||
}
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
@@ -20106,7 +20143,7 @@ void Player::_LoadMail(PreparedQueryResult mailsResult, PreparedQueryResult mail
|
||||
m->deliver_time = fields[7].GetInt64();
|
||||
m->money = fields[8].GetUInt64();
|
||||
m->COD = fields[9].GetUInt64();
|
||||
m->checked = fields[10].GetUInt8();
|
||||
m->checked = fields[10].GetUInt32();
|
||||
m->stationery = fields[11].GetUInt8();
|
||||
m->mailTemplateId = fields[12].GetInt16();
|
||||
|
||||
@@ -21738,7 +21775,7 @@ void Player::_SaveMail(CharacterDatabaseTransaction trans)
|
||||
stmt->setInt64(2, m->deliver_time);
|
||||
stmt->setUInt64(3, m->money);
|
||||
stmt->setUInt64(4, m->COD);
|
||||
stmt->setUInt8(5, uint8(m->checked));
|
||||
stmt->setUInt32(5, uint8(m->checked));
|
||||
stmt->setUInt64(6, m->messageID);
|
||||
|
||||
trans->Append(stmt);
|
||||
@@ -26465,6 +26502,26 @@ void Player::SendInitialPacketsAfterAddToMap()
|
||||
SendDirectMessage(setCompoundState.Write());
|
||||
}
|
||||
|
||||
//WowCommunity
|
||||
// Retail sends this on the instance connection once the player object exists. The client
|
||||
// answers with CMSG_MOVE_INITIAL_OBJECT_UPDATE_COMPLETE_ACK and the same counter.
|
||||
{
|
||||
WorldPackets::Movement::MoveInitialObjectUpdateComplete initialUpdate;
|
||||
initialUpdate.MoverGUID = GetGUID();
|
||||
initialUpdate.SequenceIndex = m_movementCounter++;
|
||||
SendDirectMessage(initialUpdate.Write());
|
||||
}
|
||||
|
||||
// Dungeon captures clear the treasure picker cache with an empty packet once the player is on
|
||||
// the instance connection. Open world does not get that clear.
|
||||
if (GetMap()->IsDungeon())
|
||||
{
|
||||
WorldPackets::Misc::ClearTreasurePickerCache clearTreasurePicker;
|
||||
SendDirectMessage(clearTreasurePicker.Write());
|
||||
}
|
||||
|
||||
//WowCommunity
|
||||
|
||||
if (HasUnitState(UNIT_STATE_FLEEING | UNIT_STATE_CONFUSED) || HasAuraType(SPELL_AURA_MOD_CONFUSE) || HasAuraType(SPELL_AURA_MOD_FEAR))
|
||||
SetClientControl(this, false);
|
||||
|
||||
@@ -27534,7 +27591,7 @@ void Player::AutoUnequipOffhandIfNeed(bool force /*= false*/)
|
||||
offItem->SaveToDB(trans); // recursive and not have transaction guard into self, item not in inventory and can be save standalone
|
||||
|
||||
std::string subject = GetSession()->GetTrinityString(LANG_NOT_EQUIPPED_ITEM);
|
||||
MailDraft(subject, "There were problems with equipping one or several items").AddItem(offItem).SendMailTo(trans, this, MailSender(this, MAIL_STATIONERY_GM), MAIL_CHECK_MASK_COPIED);
|
||||
MailDraft(subject, "There were problems with equipping one or several items").AddItem(offItem).SendMailTo(trans, this, MailSender(this, MAIL_STATIONERY_GM), MAIL_CHECK_MASK_COPIED | MAIL_CHECK_MASK_NOT_RETURNABLE | MAIL_CHECK_MASK_RESTORED_ITEM);
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
}
|
||||
|
||||
@@ -1693,6 +1693,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
|
||||
|
||||
void ApplyEquipCooldown(Item* pItem);
|
||||
void QuickEquipItem(uint16 pos, Item* pItem);
|
||||
void ForceEquipItemFromInventory(uint32 itemId, uint32 maxCount = 0);
|
||||
void VisualizeItem(uint8 slot, Item* pItem);
|
||||
void SetVisibleItemSlot(uint8 slot, Item const* item);
|
||||
Item* BankItem(ItemPosCountVec const& dest, Item* pItem, bool update);
|
||||
|
||||
@@ -5504,21 +5504,13 @@ void Unit::AddGameObject(GameObject* gameObj)
|
||||
ToCreature()->AI()->JustSummonedGameobject(gameObj);
|
||||
}
|
||||
|
||||
void Unit::RemoveGameObject(GameObject* gameObj, bool del)
|
||||
void Unit::RemoveGameObjectImpl(GameObject* gameObj, bool del)
|
||||
{
|
||||
if (!gameObj || gameObj->GetOwnerGUID() != GetGUID())
|
||||
return;
|
||||
|
||||
gameObj->SetOwnerGUID(ObjectGuid::Empty);
|
||||
|
||||
for (uint8 i = 0; i < MAX_GAMEOBJECT_SLOT; ++i)
|
||||
{
|
||||
if (m_ObjectSlot[i] == gameObj->GetGUID())
|
||||
{
|
||||
m_ObjectSlot[i].Clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
auto objectSlotItr = std::ranges::find(m_ObjectSlot, gameObj->GetGUID());
|
||||
if (objectSlotItr != std::ranges::end(m_ObjectSlot))
|
||||
objectSlotItr->Clear();
|
||||
|
||||
// GO created by some spell
|
||||
if (uint32 spellid = gameObj->GetSpellId())
|
||||
@@ -5532,8 +5524,6 @@ void Unit::RemoveGameObject(GameObject* gameObj, bool del)
|
||||
GetSpellHistory()->SendCooldownEvent(createBySpell);
|
||||
}
|
||||
|
||||
m_gameObj.remove(gameObj);
|
||||
|
||||
if (GetTypeId() == TYPEID_UNIT && ToCreature()->IsAIEnabled())
|
||||
ToCreature()->AI()->SummonedGameobjectDespawn(gameObj);
|
||||
|
||||
@@ -5544,27 +5534,30 @@ void Unit::RemoveGameObject(GameObject* gameObj, bool del)
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::RemoveGameObject(GameObject* gameObj, bool del)
|
||||
{
|
||||
if (!gameObj || gameObj->GetOwnerGUID() != GetGUID())
|
||||
return;
|
||||
|
||||
RemoveGameObjectImpl(gameObj, del);
|
||||
|
||||
m_gameObj.remove(gameObj);
|
||||
}
|
||||
|
||||
void Unit::RemoveGameObject(uint32 spellid, bool del)
|
||||
{
|
||||
if (m_gameObj.empty())
|
||||
return;
|
||||
GameObjectList::iterator i, next;
|
||||
for (i = m_gameObj.begin(); i != m_gameObj.end(); i = next)
|
||||
|
||||
for (auto i = m_gameObj.begin(); i != m_gameObj.end(); )
|
||||
{
|
||||
next = i;
|
||||
if (spellid == 0 || (*i)->GetSpellId() == spellid)
|
||||
{
|
||||
(*i)->SetOwnerGUID(ObjectGuid::Empty);
|
||||
if (del)
|
||||
{
|
||||
(*i)->SetRespawnTime(0);
|
||||
(*i)->Delete();
|
||||
}
|
||||
|
||||
next = m_gameObj.erase(i);
|
||||
RemoveGameObjectImpl(*i, del);
|
||||
i = m_gameObj.erase(i);
|
||||
}
|
||||
else
|
||||
++next;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5573,11 +5566,9 @@ void Unit::RemoveAllGameObjects()
|
||||
// remove references to unit
|
||||
while (!m_gameObj.empty())
|
||||
{
|
||||
GameObjectList::iterator i = m_gameObj.begin();
|
||||
(*i)->SetOwnerGUID(ObjectGuid::Empty);
|
||||
(*i)->SetRespawnTime(0);
|
||||
(*i)->Delete();
|
||||
m_gameObj.erase(i);
|
||||
GameObject* gameObj = m_gameObj.front();
|
||||
m_gameObj.pop_front();
|
||||
RemoveGameObjectImpl(gameObj, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15553,11 +15544,29 @@ Creature* Unit::GetSummonedCreatureByEntry(uint32 entry)
|
||||
return ObjectAccessor::GetCreature(*this, itr->first);
|
||||
}
|
||||
|
||||
void Unit::RegisterSummonedCreature(Creature* creature)
|
||||
{
|
||||
if (creature)
|
||||
m_SummonedCreatures[creature->GetGUID()] = creature->GetEntry();
|
||||
}
|
||||
|
||||
void Unit::UnregisterSummonedCreature(ObjectGuid guid)
|
||||
{
|
||||
m_SummonedCreatures.erase(guid);
|
||||
}
|
||||
|
||||
void Unit::UnsummonCreatureByEntry(uint32 entry, uint32 ms/* = 0*/)
|
||||
{
|
||||
if (Creature* creature = GetSummonedCreatureByEntry(entry))
|
||||
if (TempSummon* tempSummon = creature->ToTempSummon())
|
||||
tempSummon->UnSummon(ms);
|
||||
// A quest can leave more than one copy. Collect first: UnSummon removes them from this map.
|
||||
std::vector<ObjectGuid> guids;
|
||||
for (auto const& summoned : m_SummonedCreatures)
|
||||
if (summoned.second == entry)
|
||||
guids.push_back(summoned.first);
|
||||
|
||||
for (ObjectGuid const& guid : guids)
|
||||
if (Creature* creature = ObjectAccessor::GetCreature(*this, guid))
|
||||
if (TempSummon* tempSummon = creature->ToTempSummon())
|
||||
tempSummon->UnSummon(ms);
|
||||
}
|
||||
|
||||
void Unit::GetFriendlyUnitListInRange(std::list<Unit*>& list, float fMaxSearchRange, bool exceptSelf) const
|
||||
|
||||
@@ -1911,6 +1911,8 @@ class TC_GAME_API Unit : public WorldObject
|
||||
//WowCommunity
|
||||
TaskScheduler& GetScheduler() { return _scheduler; }
|
||||
Creature* GetSummonedCreatureByEntry(uint32 entry);
|
||||
void RegisterSummonedCreature(Creature* creature);
|
||||
void UnregisterSummonedCreature(ObjectGuid guid);
|
||||
void UnsummonCreatureByEntry(uint32 entry, uint32 ms = 0);
|
||||
void GetFriendlyUnitListInRange(std::list<Unit*>& list, float fMaxSearchRange, bool exceptSelf = false) const;
|
||||
void FollowTarget(Unit* target);
|
||||
@@ -1968,6 +1970,7 @@ class TC_GAME_API Unit : public WorldObject
|
||||
DynObjectList m_dynObj;
|
||||
|
||||
typedef std::list<GameObject*> GameObjectList;
|
||||
void RemoveGameObjectImpl(GameObject* gameObj, bool del);
|
||||
GameObjectList m_gameObj;
|
||||
|
||||
typedef std::vector<AreaTrigger*> AreaTriggerList;
|
||||
|
||||
@@ -6370,7 +6370,7 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
|
||||
m->expire_time = fields[5].GetInt64();
|
||||
m->deliver_time = 0;
|
||||
m->COD = fields[6].GetUInt64();
|
||||
m->checked = fields[7].GetUInt8();
|
||||
m->checked = fields[7].GetUInt32();
|
||||
m->mailTemplateId = fields[8].GetInt16();
|
||||
|
||||
// Delete or return mail
|
||||
@@ -6380,7 +6380,7 @@ void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
|
||||
m->items.swap(itemsCache[m->messageID]);
|
||||
|
||||
// if it is mail from non-player, or if it's already return mail, it shouldn't be returned, but deleted
|
||||
if (m->messageType != MAIL_NORMAL || (m->checked & (MAIL_CHECK_MASK_COD_PAYMENT | MAIL_CHECK_MASK_RETURNED)))
|
||||
if (m->messageType != MAIL_NORMAL || (m->checked & (MAIL_CHECK_MASK_COD_PAYMENT | MAIL_CHECK_MASK_RETURNED | MAIL_CHECK_MASK_NOT_RETURNABLE)))
|
||||
{
|
||||
CharacterDatabaseTransaction nonTransactional(nullptr);
|
||||
// mail open and then not returned
|
||||
|
||||
@@ -421,23 +421,6 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPackets::Battleground::Battl
|
||||
}
|
||||
else // leave queue
|
||||
{
|
||||
// Under a group proposal a decline is not just this player leaving: the whole proposal collapses, the
|
||||
// others get SMSG_BATTLEFIELD_STATUS_GROUP_PROPOSAL_FAILED and those who had already accepted are put
|
||||
// back in the queue at the position they held. This player's own removal is the code below.
|
||||
bgQueue.ProposalDecline(_player->GetGUID());
|
||||
|
||||
// if player leaves rated arena match before match start, it is counted as he played but he lost
|
||||
if (bgQueue.GetQueueId().Rated && ginfo.IsInvitedToBGInstanceGUID)
|
||||
{
|
||||
ArenaTeam* at = sArenaTeamMgr->GetArenaTeamById(ginfo.Team);
|
||||
if (at)
|
||||
{
|
||||
TC_LOG_DEBUG("bg.battleground", "UPDATING memberLost's personal arena rating for {} by opponents rating: {}, because he has left queue!", _player->GetGUID().ToString(), ginfo.OpponentsTeamRating);
|
||||
at->MemberLost(_player, ginfo.OpponentsMatchmakerRating);
|
||||
at->SaveToDB();
|
||||
}
|
||||
}
|
||||
|
||||
WorldPackets::Battleground::BattlefieldStatusNone battlefieldStatus;
|
||||
battlefieldStatus.Ticket = battlefieldPort.Ticket;
|
||||
SendPacket(battlefieldStatus.Write());
|
||||
|
||||
@@ -123,9 +123,9 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
// In-game Shop (BattlePay). P0: reply to the catalog request with the captured, client-validated
|
||||
// product list so the shop opens and displays real products. If no catalog blob is loaded we send
|
||||
// nothing (shop opens empty) rather than fabricating wire.
|
||||
// In-game Shop (BattlePay). The client asks for the product list every time the shop opens and
|
||||
// drops the list it already had. Answering only the first request leaves every later open empty.
|
||||
// The blob is the catalog built from shop_product at startup and on `.reload shop_catalog`.
|
||||
void WorldSession::HandleBattlePayGetProductList(WorldPackets::BattlePay::GetProductList& /*getProductList*/)
|
||||
{
|
||||
if (!sWorld->getBoolConfig(CONFIG_SHOP_ENABLED))
|
||||
@@ -137,20 +137,9 @@ void WorldSession::HandleBattlePayGetProductList(WorldPackets::BattlePay::GetPro
|
||||
return;
|
||||
}
|
||||
|
||||
// Throttle the 58 KB blob: serve it at most once per catalog generation for this session. The client
|
||||
// re-requests on every shop open, so without this a STATUS_AUTHED session could pull it repeatedly.
|
||||
// A `.reload shop_catalog` bumps the generation, so a fresh catalog still reaches the next request.
|
||||
uint32 const generation = sBattlePayMgr->GetCatalogGeneration();
|
||||
if (_battlePayCatalogGeneration == generation)
|
||||
{
|
||||
TC_LOG_DEBUG("network", "BattlePay: GetProductList from {} already served catalog gen {}.", GetPlayerInfo(), generation);
|
||||
return;
|
||||
}
|
||||
|
||||
WorldPackets::BattlePay::ProductListResponse response;
|
||||
response.RawData = &sBattlePayMgr->GetProductListBlob();
|
||||
SendPacket(response.Write());
|
||||
_battlePayCatalogGeneration = generation;
|
||||
}
|
||||
|
||||
// Drives the purchase to completion for a given productID: validate, charge (gold or a token item),
|
||||
@@ -1547,9 +1536,9 @@ void WorldSession::HandleBattlePayGetPurchaseList(WorldPackets::BattlePay::GetPu
|
||||
// VAS (Value Added Services) status queries.
|
||||
//
|
||||
// These are the only two VAS opcodes a retail client actually sends unprompted - both appear at character
|
||||
// select in every capture on this machine, and both have empty bodies. They were registered STATUS_IGNORED,
|
||||
// which in this core is a bare `break;` in WorldSession: the packet was dropped without even a log line, so
|
||||
// the client's VAS caches were never refreshed and never cleared.
|
||||
// select in every capture on this machine, and both have empty bodies. The replies were already written,
|
||||
// but the client opcodes were STATUS_IGNORED and the server opcodes were STATUS_UNHANDLED, so SendPacket
|
||||
// dropped them and the client's VAS caches were never cleared.
|
||||
//
|
||||
// Answering with "nothing in flight" is the accurate state of this realm, and it is byte-identical to what
|
||||
// retail sends when a player has no pending purchase.
|
||||
@@ -1824,3 +1813,15 @@ void WorldSession::HandleBattlePayCancelOpenCheckout(WorldPackets::BattlePay::Ba
|
||||
// (the web overlay owns that state), so there is nothing to release; acknowledged by log only.
|
||||
TC_LOG_DEBUG("network", "BattlePay: CancelOpenCheckout from {}.", GetPlayerInfo());
|
||||
}
|
||||
|
||||
void WorldSession::HandleGetLastCatalogFetch(WorldPackets::BattlePay::GetLastCatalogFetch& /*packet*/)
|
||||
{
|
||||
WorldPackets::BattlePay::LastCatalogFetchResponse response;
|
||||
response.LastFetchUnix = uint32(_lastCatalogFetch);
|
||||
SendPacket(response.Write());
|
||||
}
|
||||
|
||||
void WorldSession::HandleUpdateLastCatalogFetch(WorldPackets::BattlePay::UpdateLastCatalogFetch& /*packet*/)
|
||||
{
|
||||
_lastCatalogFetch = GameTime::GetGameTime();
|
||||
}
|
||||
|
||||
@@ -1351,15 +1351,6 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPackets::Character::PlayerLogin&
|
||||
//WowCommunity
|
||||
m_playerLoginRPE = playerLogin.RPE;
|
||||
//WowCommunity
|
||||
|
||||
// The Shop catalog is served at most once per catalog generation per session, but the client
|
||||
// throws its store state away when it leaves character select, so the copy it fetched there is
|
||||
// gone by the time the in-game Shop opens. Without this reset the in-world
|
||||
// CMSG_BATTLE_PAY_GET_PRODUCT_LIST is silently swallowed by that throttle and the Shop shows an
|
||||
// empty frame ("bad argument #1 to GetProducts" in Blizzard_StoreUI, because it has no product
|
||||
// groups). Clearing the marker on login gives each context exactly one copy, which is what the
|
||||
// throttle was actually meant to do.
|
||||
_battlePayCatalogGeneration = 0;
|
||||
|
||||
TC_LOG_DEBUG("network", "Character {} logging in (RPE={})", playerLogin.Guid.ToString(), playerLogin.RPE);
|
||||
|
||||
@@ -3564,4 +3555,14 @@ void WorldSession::HandleEncounterJournalStartArathiRpe(WorldPackets::Character:
|
||||
// play-testing shows retail force-grants it instead, add player->AddQuest(...) here.
|
||||
}
|
||||
|
||||
void WorldSession::HandleGetRegionwideCharacterRestrictionAndMailData(WorldPackets::Character::GetRegionwideCharacterRestrictionAndMailData& packet)
|
||||
{
|
||||
WorldPackets::Character::RegionwideCharacterRestrictionsData restrictions;
|
||||
SendPacket(restrictions.Write());
|
||||
|
||||
WorldPackets::Character::RegionwideCharacterMailData mail;
|
||||
mail.Characters = std::move(packet.Characters);
|
||||
SendPacket(mail.Write());
|
||||
}
|
||||
|
||||
//WowCommunity
|
||||
|
||||
@@ -543,10 +543,12 @@ void WorldSession::HandleLFGListSearch(WorldPackets::LFGList::LFGListSearch& pac
|
||||
filter.AdvancedFilterMask = packet.AdvancedFilterMask;
|
||||
filter.MinimumRating = packet.MinimumRating;
|
||||
filter.LanguageMask = packet.LanguageMask;
|
||||
filter.ListFilter = packet.Filter;
|
||||
filter.SearcherLevel = GetPlayer()->GetLevel();
|
||||
filter.SearcherClass = GetPlayer()->GetClass();
|
||||
// Not acted on, each for a reason recorded at its declaration: Filter (already consumed client-side before
|
||||
// ResolvedActivityIDs was built), PreferredFilters and FilterByte2, CrossFaction (every listing is already
|
||||
// visible to both factions), FilterByte1 (a client constant) and Guids (no client path fills it).
|
||||
// Not acted on, each for a reason recorded at its declaration: PreferredFilters and FilterByte2,
|
||||
// CrossFaction (every listing is already visible to both factions), FilterByte1 (a client constant)
|
||||
// and Guids (no client path fills it). Filter is applied in LFGListMgr::Matches.
|
||||
|
||||
// Keep this browser subscribed so listings published/edited from now on are pushed live via
|
||||
// SMSG_LFG_LIST_SEARCH_RESULTS_UPDATE instead of the player having to re-search. It records the SAME
|
||||
|
||||
@@ -299,11 +299,16 @@ void WorldSession::HandleSendMail(WorldPackets::Mail::SendMail& sendMail)
|
||||
if (mailInfo.Attachments.empty())
|
||||
mailInfo.Cod = 0;
|
||||
|
||||
MailCheckMask mailFlags = mailInfo.Body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY;
|
||||
|
||||
if (player->IsGameMaster())
|
||||
mailFlags |= MAIL_CHECK_MASK_NOT_RETURNABLE;
|
||||
|
||||
// will delete item or place to receiver mail list
|
||||
draft
|
||||
.AddMoney(mailInfo.SendMoney)
|
||||
.AddCOD(mailInfo.Cod)
|
||||
.SendMailTo(trans, MailReceiver(ObjectAccessor::FindConnectedPlayer(receiverGuid), receiverGuid.GetCounter()), MailSender(player), mailInfo.Body.empty() ? MAIL_CHECK_MASK_COPIED : MAIL_CHECK_MASK_HAS_BODY, deliver_delay);
|
||||
.SendMailTo(trans, MailReceiver(ObjectAccessor::FindConnectedPlayer(receiverGuid), receiverGuid.GetCounter()), MailSender(player), mailFlags, deliver_delay);
|
||||
|
||||
player->SaveInventoryAndGoldToDB(trans);
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
@@ -955,6 +955,10 @@ void InstanceScript::SendEncounterEnd()
|
||||
{
|
||||
WorldPackets::Instance::InstanceEncounterEnd encounterEndMessage;
|
||||
instance->SendToPlayers(encounterEndMessage.Write());
|
||||
|
||||
// The same end bundle in the dungeon captures clears the encounter timeline with a count of 0.
|
||||
WorldPackets::Instance::InstanceEncounterEventSequence clearTimeline;
|
||||
instance->SendToPlayers(clearTimeline.Write());
|
||||
}
|
||||
|
||||
void InstanceScript::SendBossKillCredit(uint32 encounterId)
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
#include "WorldSession.h" // TransferListingLeadership re-announces the entry to the new owner
|
||||
#include <cctype>
|
||||
#include <utility>
|
||||
//WowCommunity
|
||||
#include "ChallengeModeMgr.h"
|
||||
#include "SharedDefines.h"
|
||||
//WowCommunity
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -732,8 +736,8 @@ float LFGListMgr::GetLeaderDungeonScore(LFGList::Listing const& listing)
|
||||
}
|
||||
|
||||
// C_LFGList.GetActivityInfoTable's difficulty flags, as the 12.1.0.69587 client builds them (0x7FF7CF2B9F50) from
|
||||
// GroupFinderActivity.DifficultyID after remapping 233 -> 16 and 250 -> 17: isNormalActivity == 1, isHeroicActivity == 2,
|
||||
// isMythicActivity == 23, isMythicPlusActivity == 8. Everything else - raid difficulties 14-16 included - is in no band
|
||||
// isMythicActivity == 23, isMythicPlusActivity == 8. Raid difficulties use the same four checkboxes: 14 normal,
|
||||
// 15 heroic, 16 mythic. Anything outside those bands still passes, so an unknown difficulty is not hidden.
|
||||
// and passes, exactly like the Lua, which only rejects an activity that IS in a band the player left unticked.
|
||||
bool LFGListMgr::MatchesDifficultyBand(LFGList::Listing const& listing, uint32 advancedFilterMask)
|
||||
{
|
||||
@@ -753,14 +757,87 @@ bool LFGListMgr::MatchesDifficultyBand(LFGList::Listing const& listing, uint32 a
|
||||
|
||||
switch (difficulty)
|
||||
{
|
||||
case 1: return (advancedFilterMask & ADVANCED_FILTER_DIFFICULTY_NORMAL) != 0;
|
||||
case 2: return (advancedFilterMask & ADVANCED_FILTER_DIFFICULTY_HEROIC) != 0;
|
||||
case 1:
|
||||
case 14: return (advancedFilterMask & ADVANCED_FILTER_DIFFICULTY_NORMAL) != 0;
|
||||
case 2:
|
||||
case 15: return (advancedFilterMask & ADVANCED_FILTER_DIFFICULTY_HEROIC) != 0;
|
||||
case 16:
|
||||
case 23: return (advancedFilterMask & ADVANCED_FILTER_DIFFICULTY_MYTHIC) != 0;
|
||||
case 8: return (advancedFilterMask & ADVANCED_FILTER_DIFFICULTY_MYTHIC_PLUS) != 0;
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Enum.LFGListFilter bits for one GroupFinderActivity, from the searching player's level and the record.
|
||||
// The client builds the same mask at RVA 0x24DA960 and keeps a record only when it carries every bit of
|
||||
// CMSG_LFG_LIST_SEARCH.Filter. An empty search box sends no resolved activity ids, and the client does not
|
||||
// re-apply the mask to rows it already received, so this is the only place the category buttons can work.
|
||||
// Recommended is the expansion the player's level sits in. Current expansion content stays recommended from
|
||||
// the previous cap upward, so a level-80 character still sees Midnight. PvE/PvP come from
|
||||
// GroupFinderActivity.Flags (0x2 / 0x4). A keystone activity is current season only when its challenge mode
|
||||
// is in the live season; every other current-expansion activity is current season too.
|
||||
static uint32 ActivityListFilterMask(GroupFinderActivityEntry const* activity, uint32 searcherLevel)
|
||||
{
|
||||
using namespace LFGList;
|
||||
uint32 mask = 0;
|
||||
|
||||
if (activity->Flags & 0x4)
|
||||
mask |= LFG_LIST_FILTER_PVP;
|
||||
if ((activity->Flags & 0x2) || (activity->Flags & 0x4) == 0)
|
||||
mask |= LFG_LIST_FILTER_PVE;
|
||||
|
||||
if (activity->ExpansionID == int32(CURRENT_EXPANSION))
|
||||
mask |= LFG_LIST_FILTER_CURRENT_EXPANSION;
|
||||
|
||||
bool currentSeason = activity->ExpansionID == int32(CURRENT_EXPANSION);
|
||||
if (activity->MapChallengeModeID > 0)
|
||||
{
|
||||
currentSeason = false;
|
||||
for (uint32 challengeModeId : sChallengeModeMgr.GetSeasonMapChallengeModeIds())
|
||||
{
|
||||
if (challengeModeId == uint32(activity->MapChallengeModeID))
|
||||
{
|
||||
currentSeason = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mask |= currentSeason ? LFG_LIST_FILTER_CURRENT_SEASON : LFG_LIST_FILTER_NOT_CURRENT_SEASON;
|
||||
|
||||
bool recommended = false;
|
||||
if (activity->ExpansionID >= 0 && uint32(activity->ExpansionID) < MAX_EXPANSIONS)
|
||||
{
|
||||
uint32 const expansion = uint32(activity->ExpansionID);
|
||||
uint32 const bandMax = GetMaxLevelForExpansion(expansion);
|
||||
uint32 const bandMin = expansion > 0 ? GetMaxLevelForExpansion(expansion - 1) : 0;
|
||||
if (expansion == CURRENT_EXPANSION)
|
||||
recommended = searcherLevel >= bandMin && searcherLevel > 0;
|
||||
else if (bandMax > bandMin && searcherLevel > bandMin && searcherLevel <= bandMax)
|
||||
recommended = true;
|
||||
else if (bandMax > 0 && bandMax == bandMin && searcherLevel == bandMax)
|
||||
recommended = true;
|
||||
}
|
||||
mask |= recommended ? LFG_LIST_FILTER_RECOMMENDED : LFG_LIST_FILTER_NOT_RECOMMENDED;
|
||||
return mask;
|
||||
}
|
||||
|
||||
static bool MatchesListFilter(LFGList::Listing const& listing, LFGList::SearchFilter const& filter)
|
||||
{
|
||||
if (!filter.ListFilter)
|
||||
return true;
|
||||
|
||||
if (listing.Descriptor.ActivityIDs.empty())
|
||||
return false;
|
||||
|
||||
for (uint32 activityId : listing.Descriptor.ActivityIDs)
|
||||
if (GroupFinderActivityEntry const* activity = sGroupFinderActivityStore.LookupEntry(activityId))
|
||||
if ((ActivityListFilterMask(activity, filter.SearcherLevel) & filter.ListFilter) == filter.ListFilter)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// The advanced filter, applied exactly as LFGList.lua (12.1.0.69587) EntryStillSatisfiesFilters re-applies it to a row
|
||||
// the client already holds: role / class needs against GetSearchResultMemberCounts, minimumRating against
|
||||
// leaderOverallDungeonScore, the difficulty band of the listed activity, and the listing's general playstyle. The
|
||||
@@ -859,30 +936,17 @@ bool LFGListMgr::Matches(LFGList::Listing const& listing, LFGList::SearchFilter
|
||||
// Two consequences, and they decide the shape of this predicate:
|
||||
// - ResolvedActivityIds is non-empty ONLY when the player typed something. It is never the lone
|
||||
// carrier of a request, and the union below can never be reached with a wildcard on one side.
|
||||
// - The Filter narrowing therefore does not reach the server at all when the box is empty, and this
|
||||
// is a REAL GAP, stated here rather than smoothed over. mask() is the client's computed
|
||||
// Enum.LFGListFilter mask (RVA 0x24DA960), built from the SEARCHING PLAYER's level against the
|
||||
// activity's suggestion (Recommended 1 / NotRecommended 2), the record's own PvE 4 / PvP 8 /
|
||||
// Timerunning 16 flag bits, an expansion test (CurrentExpansion 32) and membership in a client-side
|
||||
// store (CurrentSeason 64 / NotCurrentSeason 128). The last three are not server state at all, and
|
||||
// the first two need a level/suggestion model this unit's listing does not carry.
|
||||
// The client does NOT make up for it either - that was checked rather than hoped. The UI displays
|
||||
// C_LFGList.GetFilteredSearchResults() (LFGList.lua 12.1.0.69404,
|
||||
// LFGListSearchPanel_UpdateResultList), whose implementation @ RVA 0x24E3A40 walks the received
|
||||
// rows and drops exactly those whose key at row+0x10 is present in a client-side map
|
||||
// (qword_7FF7853F17F0) - what fills that map was not identified. It re-applies neither the filter
|
||||
// mask nor the category nor the activity set. So a search with a Filter and an empty box really does
|
||||
// show the whole category, and closing it needs work outside this unit.
|
||||
// Reproducing the mask PARTIALLY would be worse than not reproducing it: the test is
|
||||
// `(mask & Filter) == Filter`, so a server mask that cannot carry Recommended would fail every
|
||||
// record for the one Filter value actually measured (1, which ResolveCategoryFilters forces for the
|
||||
// dungeon category) and empty the browse pane. Delivering too much is the recoverable error here.
|
||||
// - Filter is a separate test. An empty box leaves ResolvedActivityIds empty, and the client does
|
||||
// not re-apply Enum.LFGListFilter to the rows it is sent, so MatchesListFilter applies that mask
|
||||
// here. The dungeon category forces the Recommended bit; current-expansion activities carry it
|
||||
// from the previous level cap upward, which is why that forced bit does not empty the pane.
|
||||
//
|
||||
// Hence: a request with BOTH halves empty is the wildcard - that is the search box left blank, and the
|
||||
// whole category is the honest answer to it. Anything else has to satisfy at least one half, and each
|
||||
// half only counts when it was actually asked for. That is the fix for Runde 12's second finding: a
|
||||
// request carrying resolved activities and no keywords now filters by them instead of riding in an OR
|
||||
// that an empty keyword set satisfies on its own.
|
||||
// Hence: a request with BOTH halves empty is the wildcard for the search box. The category filter
|
||||
// above still applies. Anything else has to satisfy at least one half, and each half only counts
|
||||
// when it was actually asked for.
|
||||
if (!MatchesListFilter(listing, filter))
|
||||
return false;
|
||||
|
||||
if (!MatchesAdvancedFilter(listing, filter))
|
||||
return false;
|
||||
|
||||
|
||||
@@ -99,6 +99,19 @@ namespace LFGList
|
||||
| ADVANCED_FILTER_GENERAL_PLAYSTYLE_3 | ADVANCED_FILTER_GENERAL_PLAYSTYLE_4,
|
||||
};
|
||||
|
||||
// Enum.LFGListFilter, CMSG_LFG_LIST_SEARCH.Filter. A listing's activity must carry every set bit.
|
||||
enum ListFilter : uint32
|
||||
{
|
||||
LFG_LIST_FILTER_RECOMMENDED = 0x01,
|
||||
LFG_LIST_FILTER_NOT_RECOMMENDED = 0x02,
|
||||
LFG_LIST_FILTER_PVE = 0x04,
|
||||
LFG_LIST_FILTER_PVP = 0x08,
|
||||
LFG_LIST_FILTER_TIMERRUNNING = 0x10,
|
||||
LFG_LIST_FILTER_CURRENT_EXPANSION = 0x20,
|
||||
LFG_LIST_FILTER_CURRENT_SEASON = 0x40,
|
||||
LFG_LIST_FILTER_NOT_CURRENT_SEASON = 0x80,
|
||||
};
|
||||
|
||||
// What a listing's party looks like to a browser: C_LFGList.GetSearchResultMemberCounts' TANK / HEALER / DAMAGER
|
||||
// and per-class counts, taken from the very role bytes the search row carries so the two cannot disagree.
|
||||
struct MemberComposition
|
||||
@@ -130,6 +143,8 @@ namespace LFGList
|
||||
uint32 AdvancedFilterMask = 0; // AdvancedFilterFlag
|
||||
uint32 MinimumRating = 0; // advancedFilter.minimumRating, against the leader's dungeon score
|
||||
uint32 LanguageMask = 0; // one bit per LocaleConstant; 0 = no restriction
|
||||
uint32 ListFilter = 0; // Enum.LFGListFilter; 0 = no restriction
|
||||
uint32 SearcherLevel = 0; // recommended / not-recommended is relative to this level
|
||||
uint8 SearcherClass = 0; // needsMyClass is relative to the player who searches
|
||||
};
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@ void MailDraft::SendMailTo(CharacterDatabaseTransaction trans, MailReceiver cons
|
||||
stmt->setInt64 (++index, deliver_time);
|
||||
stmt->setUInt64(++index, m_money);
|
||||
stmt->setUInt64(++index, m_COD);
|
||||
stmt->setUInt8 (++index, uint8(checked));
|
||||
stmt->setUInt32(++index, checked);
|
||||
trans->Append(stmt);
|
||||
|
||||
for (MailItemMap::const_iterator mailItemIter = m_items.begin(); mailItemIter != m_items.end(); ++mailItemIter)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "Common.h"
|
||||
#include "DatabaseEnvFwd.h"
|
||||
#include "EnumFlag.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include <map>
|
||||
|
||||
@@ -47,16 +48,30 @@ enum MailMessageType
|
||||
MAIL_ARTISANS_CONSORTIUM = 9 // crafting orders
|
||||
};
|
||||
|
||||
enum MailCheckMask
|
||||
enum MailCheckMask : uint32
|
||||
{
|
||||
MAIL_CHECK_MASK_NONE = 0x00,
|
||||
MAIL_CHECK_MASK_READ = 0x01,
|
||||
MAIL_CHECK_MASK_RETURNED = 0x02, /// This mail was returned. Do not allow returning mail back again.
|
||||
MAIL_CHECK_MASK_COPIED = 0x04, /// This mail was copied. Do not allow making a copy of items in mail.
|
||||
MAIL_CHECK_MASK_COD_PAYMENT = 0x08,
|
||||
MAIL_CHECK_MASK_HAS_BODY = 0x10 /// This mail has body text.
|
||||
MAIL_CHECK_MASK_NONE = 0x00000,
|
||||
MAIL_CHECK_MASK_READ = 0x00001, ///< This mail was read.
|
||||
MAIL_CHECK_MASK_RETURNED = 0x00002, ///< This mail was returned. Do not allow returning mail back again.
|
||||
MAIL_CHECK_MASK_COPIED = 0x00004, ///< This mail was copied. Do not allow making a copy of items in mail.
|
||||
MAIL_CHECK_MASK_COD_PAYMENT = 0x00008, ///< This mail is payable on delivery
|
||||
MAIL_CHECK_MASK_HAS_BODY = 0x00010, ///< This mail has body text.
|
||||
MAIL_CHECK_MASK_UNK_5 = 0x00020,
|
||||
MAIL_CHECK_MASK_AUCTION_WON = 0x00040, ///< This mail is delivering won auction items.
|
||||
MAIL_CHECK_MASK_UNK_7 = 0x00080,
|
||||
MAIL_CHECK_MASK_CALENDAR_INVITE = 0x00100, ///< This mail is related to calendar invite.
|
||||
MAIL_CHECK_MASK_NOT_RETURNABLE = 0x00200, ///< This mail cannot be returned even if mail was not returned before.
|
||||
MAIL_CHECK_MASK_AUCTION = 0x00400, ///< This mail came from auction house.
|
||||
MAIL_CHECK_MASK_NOT_DELETABLE_WITH_ATTACHMENTS = 0x00800, ///< This mail cannot be deleted without taking attachments first.
|
||||
MAIL_CHECK_MASK_UNK_12 = 0x01000,
|
||||
MAIL_CHECK_MASK_UNK_13 = 0x02000,
|
||||
MAIL_CHECK_MASK_RESTORED_ITEM = 0x04000, ///< This mail contains recovered items.
|
||||
MAIL_CHECK_MASK_NOT_COPYABLE = 0x08000, ///< This mail cannot be copied.
|
||||
MAIL_CHECK_MASK_COMMERCE = 0x10000, ///< WoW Token mail.
|
||||
};
|
||||
|
||||
DEFINE_ENUM_FLAG(MailCheckMask);
|
||||
|
||||
// gathered from Stationery.dbc
|
||||
enum MailStationery
|
||||
{
|
||||
@@ -76,15 +91,6 @@ enum MailState
|
||||
MAIL_STATE_DELETED = 3
|
||||
};
|
||||
|
||||
enum MailShowFlags
|
||||
{
|
||||
MAIL_SHOW_UNK0 = 0x0001,
|
||||
MAIL_SHOW_DELETE = 0x0002, // forced show delete button instead return button
|
||||
MAIL_SHOW_AUCTION = 0x0004, // from old comment
|
||||
MAIL_SHOW_UNK2 = 0x0008, // unknown, COD will be shown even without that flag
|
||||
MAIL_SHOW_RETURN = 0x0010
|
||||
};
|
||||
|
||||
class TC_GAME_API MailSender
|
||||
{
|
||||
public: // Constructors
|
||||
|
||||
@@ -5862,7 +5862,7 @@ constexpr uint8 ClassByQuestSort(int32 QuestSort)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// SkillLine.db2 (12.0.1.66838)
|
||||
// SkillLine.db2 (12.1.0.69404)
|
||||
enum SkillType
|
||||
{
|
||||
SKILL_NONE = 0,
|
||||
@@ -6205,6 +6205,7 @@ enum SkillType
|
||||
SKILL_RACIAL_DRACTHYR = 2808,
|
||||
SKILL_EVOKER = 2810,
|
||||
SKILL_STYGIA_CRAFTING = 2811,
|
||||
SKILL_ADVENTURER = 2816,
|
||||
SKILL_LANGUAGE_CYPHER = 2817,
|
||||
SKILL_PROTOFORM_SYNTHESIS = 2819,
|
||||
SKILL_ARCANA_MANIPULATION = 2821,
|
||||
@@ -6256,11 +6257,13 @@ enum SkillType
|
||||
SKILL_MIDNIGHT_MINING = 2916,
|
||||
SKILL_MIDNIGHT_SKINNING = 2917,
|
||||
SKILL_MIDNIGHT_TAILORING = 2918,
|
||||
SKILL_TRAVELER = 2929,
|
||||
SKILL_RACIAL_HARANIR = 2930,
|
||||
SKILL_ALCHEMY_RESEARCH = 2950,
|
||||
SKILL_PET_EXOTIC_WHIPTAIL = 2961,
|
||||
SKILL_DYE_CRAFTING = 2984,
|
||||
SKILL_LANG_HARANI = 2987
|
||||
SKILL_LANG_HARANI = 2987,
|
||||
SKILL_HUNGRY_TORTOLLAN = 3004
|
||||
};
|
||||
|
||||
constexpr SkillType SkillByLockType(LockType locktype)
|
||||
|
||||
@@ -3304,16 +3304,24 @@ void ScriptMgr::OnQuestAbandon(Player* player, const Quest* quest)
|
||||
|
||||
void WowCommunity::PhaseShift(Player* player, std::vector<uint32> phaseIDs, bool add)
|
||||
{
|
||||
// Exile's Reach calls this every second. A false condition used to RemovePhase,
|
||||
// which stripped phases the world database had already applied and hid the quest
|
||||
// givers for the rest of the island. Only additions run here. A caller that must
|
||||
// drop a phase uses PhasingHandler::RemovePhase itself.
|
||||
if (!player || !add)
|
||||
// Exile's Reach calls this every second with the condition for that stage.
|
||||
// A true condition adds the phase. A false condition removes only that phase,
|
||||
// so a later quest stage does not leave the previous NPCs visible.
|
||||
// Callers that must keep a phase (the general ship and the general shore)
|
||||
// pass true. Phases this function never names are left untouched.
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
for (uint32 phaseID : phaseIDs)
|
||||
if (!player->GetPhaseShift().HasPhase(phaseID))
|
||||
PhasingHandler::AddPhase(player, phaseID, true);
|
||||
{
|
||||
if (add)
|
||||
{
|
||||
if (!player->GetPhaseShift().HasPhase(phaseID))
|
||||
PhasingHandler::AddPhase(player, phaseID, true);
|
||||
}
|
||||
else if (player->GetPhaseShift().HasPhase(phaseID))
|
||||
PhasingHandler::RemovePhase(player, phaseID, true);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptMgr::OnPlayerWorldObjectUpdate(Player* player, uint32 diff)
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
#include "GuildPackets.h"
|
||||
#include "HotfixPackets.h"
|
||||
#include "HousingPackets.h"
|
||||
#include "HousingInitiativePackets.h"
|
||||
#include "InspectPackets.h"
|
||||
#include "InstancePackets.h"
|
||||
#include "ItemPackets.h"
|
||||
|
||||
@@ -535,4 +535,11 @@ namespace WorldPackets::BattlePay
|
||||
_worldPacket >> Token;
|
||||
_worldPacket.rfinish(); // the remaining fields are not modelled (see header); consume them
|
||||
}
|
||||
|
||||
WorldPacket const* LastCatalogFetchResponse::Write()
|
||||
{
|
||||
_worldPacket << uint32(LastFetchUnix);
|
||||
_worldPacket << uint32(Result);
|
||||
return &_worldPacket;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1019,6 +1019,36 @@ namespace WorldPackets
|
||||
|
||||
uint32 Token = 0;
|
||||
};
|
||||
|
||||
// Empty in the 12.1.0.69587 housing and premade-group captures.
|
||||
class GetLastCatalogFetch final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
explicit GetLastCatalogFetch(WorldPacket&& packet) : ClientPacket(CMSG_GET_LAST_CATALOG_FETCH, std::move(packet)) {}
|
||||
|
||||
void Read() override {}
|
||||
};
|
||||
|
||||
class UpdateLastCatalogFetch final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
explicit UpdateLastCatalogFetch(WorldPacket&& packet) : ClientPacket(CMSG_UPDATE_LAST_CATALOG_FETCH, std::move(packet)) {}
|
||||
|
||||
void Read() override {}
|
||||
};
|
||||
|
||||
// Two dwords. The first is the unix time of the last fetch (0x6A93069A and 0x6AA04047
|
||||
// in two captures). The second dword is 0 in both.
|
||||
class LastCatalogFetchResponse final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
explicit LastCatalogFetchResponse() : ServerPacket(SMSG_LAST_CATALOG_FETCH_RESPONSE, 8) {}
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
uint32 LastFetchUnix = 0;
|
||||
uint32 Result = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -914,4 +914,38 @@ namespace WorldPackets::Character
|
||||
_worldPacket >> RaceAndFaction;
|
||||
}
|
||||
|
||||
void GetRegionwideCharacterRestrictionAndMailData::Read()
|
||||
{
|
||||
uint32 count = 0;
|
||||
_worldPacket >> count;
|
||||
if (count > 200)
|
||||
{
|
||||
_worldPacket.rfinish();
|
||||
return;
|
||||
}
|
||||
|
||||
Characters.resize(count);
|
||||
for (ObjectGuid& character : Characters)
|
||||
_worldPacket >> character;
|
||||
}
|
||||
|
||||
WorldPacket const* RegionwideCharacterMailData::Write()
|
||||
{
|
||||
_worldPacket << Size<uint32>(Characters);
|
||||
for (ObjectGuid const& character : Characters)
|
||||
{
|
||||
_worldPacket << uint8(0);
|
||||
_worldPacket << character;
|
||||
_worldPacket << uint32(0);
|
||||
_worldPacket << uint32(0);
|
||||
}
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
WorldPacket const* RegionwideCharacterRestrictionsData::Write()
|
||||
{
|
||||
_worldPacket << uint32(0);
|
||||
return &_worldPacket;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -943,6 +943,40 @@ namespace WorldPackets
|
||||
void Read() override {}
|
||||
};
|
||||
|
||||
// CMSG body verified on 12.1.0.69587: uint32 count, then that many packed guids.
|
||||
class GetRegionwideCharacterRestrictionAndMailData final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
explicit GetRegionwideCharacterRestrictionAndMailData(WorldPacket&& packet)
|
||||
: ClientPacket(CMSG_GET_REGIONWIDE_CHARACTER_RESTRICTION_AND_MAIL_DATA, std::move(packet)) {
|
||||
}
|
||||
|
||||
void Read() override;
|
||||
|
||||
std::vector<ObjectGuid> Characters;
|
||||
};
|
||||
|
||||
// Empty mail row verified in the same capture: one zero byte, the guid, then two zero counts.
|
||||
// A non-empty row appends sender types and a 6-bit cstring; this server has no such rows to publish.
|
||||
class RegionwideCharacterMailData final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
explicit RegionwideCharacterMailData() : ServerPacket(SMSG_REGIONWIDE_CHARACTER_MAIL_DATA, 4) {}
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
std::vector<ObjectGuid> Characters;
|
||||
};
|
||||
|
||||
// Restriction rows are a separate list. No restricted characters are published.
|
||||
class RegionwideCharacterRestrictionsData final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
explicit RegionwideCharacterRestrictionsData() : ServerPacket(SMSG_REGIONWIDE_CHARACTER_RESTRICTIONS_DATA, 4) {}
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
};
|
||||
|
||||
//WowCommunity
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,6 +593,20 @@ namespace WorldPackets
|
||||
uint32 TimerID = 0;
|
||||
bool KeepTimer = false;
|
||||
};
|
||||
|
||||
// SMSG_INSTANCE_ENCOUNTER_EVENT_SEQUENCE. A count of 0 is the 4-byte clear retail sends
|
||||
// with the encounter-end bundle. Populated event records are variable and not written here.
|
||||
class InstanceEncounterEventSequence final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
explicit InstanceEncounterEventSequence() : ServerPacket(SMSG_INSTANCE_ENCOUNTER_EVENT_SEQUENCE, 4) {}
|
||||
|
||||
WorldPacket const* Write() override
|
||||
{
|
||||
_worldPacket << uint32(0);
|
||||
return &_worldPacket;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1452,6 +1452,39 @@ namespace WorldPackets
|
||||
// viewer's own faction group to decide whether to show the win or the loss pose. Client default is -1.
|
||||
int32 Winner = -1;
|
||||
};
|
||||
|
||||
// SMSG_DISPLAY_PROMOTION at the glue screen. Captures send uint32 0: no promotion.
|
||||
class DisplayPromotion final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
explicit DisplayPromotion() : ServerPacket(SMSG_DISPLAY_PROMOTION, 4) {}
|
||||
|
||||
WorldPacket const* Write() override
|
||||
{
|
||||
_worldPacket << uint32(PromotionID);
|
||||
return &_worldPacket;
|
||||
}
|
||||
|
||||
uint32 PromotionID = 0;
|
||||
};
|
||||
|
||||
// SMSG_UNSET_INSTANCE_LEAVER at the glue screen. Captures send an empty body.
|
||||
class UnsetInstanceLeaver final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
explicit UnsetInstanceLeaver() : ServerPacket(SMSG_UNSET_INSTANCE_LEAVER, 0) {}
|
||||
|
||||
WorldPacket const* Write() override { return &_worldPacket; }
|
||||
};
|
||||
|
||||
// SMSG_CLEAR_TREASURE_PICKER_CACHE. Dungeon captures send an empty body on the instance connection.
|
||||
class ClearTreasurePickerCache final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
explicit ClearTreasurePickerCache() : ServerPacket(SMSG_CLEAR_TREASURE_PICKER_CACHE, 0) {}
|
||||
|
||||
WorldPacket const* Write() override { return &_worldPacket; }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1256,4 +1256,11 @@ void DiscardedTimeSyncAcks::Read()
|
||||
{
|
||||
_worldPacket >> MaxSequenceIndex;
|
||||
}
|
||||
|
||||
WorldPacket const* MoveInitialObjectUpdateComplete::Write()
|
||||
{
|
||||
_worldPacket << MoverGUID;
|
||||
_worldPacket << uint32(SequenceIndex);
|
||||
return &_worldPacket;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -849,6 +849,19 @@ namespace WorldPackets
|
||||
uint32 MaxSequenceIndex = 0;
|
||||
};
|
||||
|
||||
// 12.1 captures are a packed guid plus the movement counter (13 bytes). The client acks
|
||||
// with a normal movement ack whose AckIndex is that counter.
|
||||
class MoveInitialObjectUpdateComplete final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
explicit MoveInitialObjectUpdateComplete() : ServerPacket(SMSG_MOVE_INITIAL_OBJECT_UPDATE_COMPLETE, 16 + 4) {}
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
ObjectGuid MoverGUID;
|
||||
uint32 SequenceIndex = 0;
|
||||
};
|
||||
|
||||
ByteBuffer& operator>>(ByteBuffer& data, MovementAck& ack);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,12 +503,12 @@ void OpcodeTable::InitializeClientOpcodes()
|
||||
DEFINE_HANDLER(CMSG_GET_INITIATIVE_ACTIVITY_LOG_REQUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGetInitiativeActivityLogRequest);
|
||||
DEFINE_HANDLER(CMSG_GET_ITEM_PURCHASE_DATA, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGetItemPurchaseData);
|
||||
DEFINE_HANDLER(CMSG_GET_LANDING_PAGE_SHIPMENTS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGetLandingPageShipments);
|
||||
DEFINE_HANDLER(CMSG_GET_LAST_CATALOG_FETCH, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_GET_LAST_CATALOG_FETCH, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGetLastCatalogFetch);
|
||||
DEFINE_HANDLER(CMSG_GET_MIRROR_IMAGE_DATA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleMirrorImageDataRequest);
|
||||
DEFINE_HANDLER(CMSG_GET_PLAYER_INITIATIVE_INFO_REQUEST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_GET_PVP_OPTIONS_ENABLED, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGetPVPOptionsEnabled);
|
||||
DEFINE_HANDLER(CMSG_GET_RAF_ACCOUNT_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGetRafAccountInfo);
|
||||
DEFINE_HANDLER(CMSG_GET_REGIONWIDE_CHARACTER_RESTRICTION_AND_MAIL_DATA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_GET_REGIONWIDE_CHARACTER_RESTRICTION_AND_MAIL_DATA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGetRegionwideCharacterRestrictionAndMailData);
|
||||
DEFINE_HANDLER(CMSG_GET_REMAINING_GAME_TIME, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_GET_TROPHY_LIST, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGetTrophyList);
|
||||
DEFINE_HANDLER(CMSG_GET_UNDELETE_CHARACTER_COOLDOWN_STATUS, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleGetUndeleteCooldownStatus);
|
||||
@@ -746,7 +746,7 @@ void OpcodeTable::InitializeClientOpcodes()
|
||||
DEFINE_HANDLER(CMSG_MOVE_HOVER_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementAckMessage);
|
||||
DEFINE_HANDLER(CMSG_MOVE_INERTIA_DISABLE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementAckMessage);
|
||||
DEFINE_HANDLER(CMSG_MOVE_INERTIA_ENABLE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementAckMessage);
|
||||
DEFINE_HANDLER(CMSG_MOVE_INITIAL_OBJECT_UPDATE_COMPLETE_ACK, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_MOVE_INITIAL_OBJECT_UPDATE_COMPLETE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementAckMessage);
|
||||
DEFINE_HANDLER(CMSG_MOVE_INIT_ACTIVE_MOVER_COMPLETE, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveInitActiveMoverComplete);
|
||||
DEFINE_HANDLER(CMSG_MOVE_JUMP, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes);
|
||||
DEFINE_HANDLER(CMSG_MOVE_KNOCK_BACK_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveKnockBackAck);
|
||||
@@ -770,7 +770,7 @@ void OpcodeTable::InitializeClientOpcodes()
|
||||
DEFINE_HANDLER(CMSG_MOVE_SET_ALWAYS_ALLOW_PITCHING_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementAckMessage);
|
||||
DEFINE_HANDLER(CMSG_MOVE_SET_CANNOT_SWIM_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementAckMessage);
|
||||
DEFINE_HANDLER(CMSG_MOVE_SET_CAN_ADV_FLY_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementAckMessage);
|
||||
DEFINE_HANDLER(CMSG_MOVE_SET_CAN_DRIVE_ACK, STATUS_UNHANDLED, PROCESS_THREADSAFE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_MOVE_SET_CAN_DRIVE_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementAckMessage);
|
||||
DEFINE_HANDLER(CMSG_MOVE_SET_CAN_FLY_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementAckMessage);
|
||||
DEFINE_HANDLER(CMSG_MOVE_SET_CAN_TURN_WHILE_FALLING_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementAckMessage);
|
||||
DEFINE_HANDLER(CMSG_MOVE_SET_COLLISION_HEIGHT_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleSetCollisionHeightAck);
|
||||
@@ -842,7 +842,7 @@ void OpcodeTable::InitializeClientOpcodes()
|
||||
DEFINE_HANDLER(CMSG_OPEN_SHIPMENT_NPC, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleOpenShipmentNpc);
|
||||
DEFINE_HANDLER(CMSG_OPEN_TRADESKILL_NPC, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleOpenTradeskillNpc);
|
||||
DEFINE_HANDLER(CMSG_OPT_OUT_OF_LOOT, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleOptOutOfLootOpcode);
|
||||
DEFINE_HANDLER(CMSG_OVERRIDE_SCREEN_FLASH, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_OVERRIDE_SCREEN_FLASH, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleOverrideScreenFlash);
|
||||
DEFINE_HANDLER(CMSG_PARTY_INVITE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePartyInviteOpcode);
|
||||
DEFINE_HANDLER(CMSG_PARTY_INVITE_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePartyInviteResponseOpcode);
|
||||
DEFINE_HANDLER(CMSG_PARTY_UNINVITE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePartyUninviteOpcode);
|
||||
@@ -1146,11 +1146,11 @@ void OpcodeTable::InitializeClientOpcodes()
|
||||
DEFINE_HANDLER(CMSG_UPDATE_ACCOUNT_DATA, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateAccountData);
|
||||
DEFINE_HANDLER(CMSG_UPDATE_AREA_TRIGGER_VISUAL, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleUpdateAreaTriggerVisual);
|
||||
DEFINE_HANDLER(CMSG_UPDATE_CRAFTING_NPC_RECIPES, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleUpdateCraftingNpcRecipesRequest);
|
||||
DEFINE_HANDLER(CMSG_UPDATE_LAST_CATALOG_FETCH, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_UPDATE_LAST_CATALOG_FETCH, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateLastCatalogFetch);
|
||||
DEFINE_HANDLER(CMSG_UPDATE_MISSILE_TRAJECTORY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateMissileTrajectory);
|
||||
DEFINE_HANDLER(CMSG_UPDATE_RAID_TARGET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUpdateRaidTargetOpcode);
|
||||
DEFINE_HANDLER(CMSG_UPDATE_SPELL_VISUAL, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleUpdateAuraVisual);
|
||||
DEFINE_HANDLER(CMSG_UPDATE_VAS_PURCHASE_STATES, STATUS_IGNORED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_UPDATE_VAS_PURCHASE_STATES, STATUS_AUTHED, PROCESS_INPLACE, &WorldSession::HandleUpdateVasPurchaseStates);
|
||||
DEFINE_HANDLER(CMSG_UPGRADE_GARRISON, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUpgradeGarrison);
|
||||
DEFINE_HANDLER(CMSG_UPGRADE_RUNEFORGE_LEGENDARY, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleUpgradeRuneforgeLegendary);
|
||||
DEFINE_HANDLER(CMSG_USED_FOLLOW, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleUsedFollowOpcode);
|
||||
@@ -1160,7 +1160,7 @@ void OpcodeTable::InitializeClientOpcodes()
|
||||
DEFINE_HANDLER(CMSG_USE_TOY, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleUseToy);
|
||||
DEFINE_HANDLER(CMSG_VAS_CHECK_TRANSFER_OK, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleVasCheckTransferOk);
|
||||
DEFINE_HANDLER(CMSG_VAS_GET_QUEUE_MINUTES, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleVasGetQueueMinutes);
|
||||
DEFINE_HANDLER(CMSG_VAS_GET_SERVICE_STATUS, STATUS_IGNORED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_VAS_GET_SERVICE_STATUS, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleVasGetServiceStatus);
|
||||
DEFINE_HANDLER(CMSG_VIOLENCE_LEVEL, STATUS_AUTHED, PROCESS_INPLACE, &WorldSession::HandleViolenceLevel);
|
||||
DEFINE_HANDLER(CMSG_VOICE_CHANNEL_STT_TOKEN_REQUEST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_VOICE_CHAT_JOIN_CHANNEL, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
|
||||
@@ -1438,7 +1438,7 @@ void OpcodeTable::InitializeServerOpcodes()
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLEAR_RESURRECT, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLEAR_SPELL_CHARGES, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLEAR_TARGET, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLEAR_TREASURE_PICKER_CACHE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLEAR_TREASURE_PICKER_CACHE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLOSE_ARTIFACT_FORGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLUB_FINDER_ERROR_MESSAGE, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_CLUB_FINDER_GET_CLUB_POSTING_IDS_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
@@ -1517,7 +1517,7 @@ void OpcodeTable::InitializeServerOpcodes()
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPEL_FAILED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_GAME_ERROR, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_PLAYER_CHOICE, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_PROMOTION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_PROMOTION, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_QUEST_POPUP, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_TOAST, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_WORLD_TEXT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
@@ -1540,7 +1540,7 @@ void OpcodeTable::InitializeServerOpcodes()
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_END_LIGHTNING_STORM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENTER_ENCRYPTED_MODE, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENUM_CHARACTERS_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENUM_VAS_PURCHASE_STATES_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENUM_VAS_PURCHASE_STATES_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ENVIRONMENTAL_DAMAGE_LOG, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_EQUIPMENT_SET_ID, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_EXPECTED_SPAM_RECORDS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
@@ -1657,7 +1657,7 @@ void OpcodeTable::InitializeServerOpcodes()
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_INITIATIVE_ACTIVITY_LOG_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_INITIATIVE_REWARDS_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_LANDING_PAGE_SHIPMENTS_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_PLAYER_INITIATIVE_INFO_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_PLAYER_INITIATIVE_INFO_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_REALM_HIDDEN_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_REMAINING_GAME_TIME_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_GET_SELECTED_TROPHY_ID_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
@@ -1839,7 +1839,7 @@ void OpcodeTable::InitializeServerOpcodes()
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_ENCOUNTER_EVENT_BLOCKED_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_ENCOUNTER_EVENT_CAST_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_ENCOUNTER_EVENT_RESPAWN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_ENCOUNTER_EVENT_SEQUENCE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_ENCOUNTER_EVENT_SEQUENCE, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_ENCOUNTER_GAIN_COMBAT_RESURRECTION_CHARGE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_ENCOUNTER_IN_COMBAT_RESURRECTION, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_INSTANCE_ENCOUNTER_OBJECTIVE_COMPLETE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
@@ -1877,7 +1877,7 @@ void OpcodeTable::InitializeServerOpcodes()
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_PUSH_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ITEM_TIME_UPDATE, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_KICK_REASON, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_LAST_CATALOG_FETCH_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_LAST_CATALOG_FETCH_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_LATENCY_REPORT_PING, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_LEARNED_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_LEARN_PVP_TALENT_FAILED, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
@@ -1983,7 +1983,7 @@ void OpcodeTable::InitializeServerOpcodes()
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_ENABLE_JUMPING, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_ENABLE_STRAFING, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_ENABLE_TRANSITION_BETWEEN_SWIM_AND_FLY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_INITIAL_OBJECT_UPDATE_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_INITIAL_OBJECT_UPDATE_COMPLETE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_KNOCK_BACK, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_MARK_REMOTE_TIME_INVALID, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_MOVE_REMOVE_INERTIA, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
@@ -2316,8 +2316,8 @@ void OpcodeTable::InitializeServerOpcodes()
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFETCH_TACT_KEYS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFRESH_BLEEP_TOKENS_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFRESH_COMPONENT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REGIONWIDE_CHARACTER_MAIL_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REGIONWIDE_CHARACTER_RESTRICTIONS_DATA, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REGIONWIDE_CHARACTER_MAIL_DATA, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REGIONWIDE_CHARACTER_RESTRICTIONS_DATA, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REMOVE_ITEM_PASSIVE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REMOVE_SPELL_FROM_ACTION_BAR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_REPLACE_TROPHY_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
@@ -2519,7 +2519,7 @@ void OpcodeTable::InitializeServerOpcodes()
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNIT_DIMINISHING_RETURN_START, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNLEARNED_SPELLS, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNLOAD_CHILD_MAP, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNSET_INSTANCE_LEAVER, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UNSET_INSTANCE_LEAVER, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_AADC_STATUS_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_ACCOUNT_DATA, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_ACCOUNT_DATA_COMPLETE, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
@@ -2547,7 +2547,7 @@ void OpcodeTable::InitializeServerOpcodes()
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_USE_EQUIPMENT_SET_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_VAS_CHECK_TRANSFER_OK_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_VAS_GET_QUEUE_MINUTES_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_VAS_GET_SERVICE_STATUS_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_VAS_GET_SERVICE_STATUS_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_VAS_PURCHASE_COMPLETE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_VAS_PURCHASE_STATE_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
|
||||
DEFINE_SERVER_OPCODE_HANDLER(SMSG_VENDOR_INVENTORY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
|
||||
|
||||
@@ -1475,6 +1475,10 @@ void WorldSession::InitializeSessionCallback(LoginDatabaseQueryHolder const& hol
|
||||
SendAccountDataTimes(ObjectGuid::Empty, GLOBAL_CACHE_MASK);
|
||||
SendTutorialsData();
|
||||
|
||||
// Glue captures send promotion id 0 immediately after the tutorial flags.
|
||||
WorldPackets::Misc::DisplayPromotion displayPromotion;
|
||||
SendPacket(displayPromotion.Write());
|
||||
|
||||
if (PreparedQueryResult characterCountsResult = holder.GetPreparedResult(AccountInfoQueryHolder::GLOBAL_REALM_CHARACTER_COUNTS))
|
||||
{
|
||||
do
|
||||
@@ -1485,6 +1489,10 @@ void WorldSession::InitializeSessionCallback(LoginDatabaseQueryHolder const& hol
|
||||
} while (characterCountsResult->NextRow());
|
||||
}
|
||||
|
||||
// Glue captures clear the instance-leaver flag with an empty packet next to the bnet status.
|
||||
WorldPackets::Misc::UnsetInstanceLeaver unsetInstanceLeaver;
|
||||
SendPacket(unsetInstanceLeaver.Write());
|
||||
|
||||
WorldPackets::Battlenet::ConnectionStatus bnetConnected;
|
||||
bnetConnected.State = 1;
|
||||
SendPacket(bnetConnected.Write());
|
||||
|
||||
@@ -139,6 +139,8 @@ namespace WorldPackets
|
||||
class CharacterCheckUpgrade;
|
||||
class CharacterUpgradeManualUnrevokeRequest;
|
||||
class GetProductList;
|
||||
class GetLastCatalogFetch;
|
||||
class UpdateLastCatalogFetch;
|
||||
class GetPurchaseList;
|
||||
class StartPurchase;
|
||||
class OpenCheckout;
|
||||
@@ -363,6 +365,7 @@ namespace WorldPackets
|
||||
class GetAccountCharacterList;
|
||||
class ConvertTimerunningCharacter;
|
||||
class EncounterJournalStartArathiRpe;
|
||||
class GetRegionwideCharacterRestrictionAndMailData;
|
||||
//WowCommunity
|
||||
}
|
||||
|
||||
@@ -1647,6 +1650,7 @@ public:
|
||||
//WowCommunity
|
||||
void HandleSetupWarbandGroups(WorldPackets::Character::SetupWarbandGroups& setupWarbandGroups);
|
||||
void HandleGetAccountCharListOpcode(WorldPackets::Character::GetAccountCharacterList& accountCharList);
|
||||
void HandleGetRegionwideCharacterRestrictionAndMailData(WorldPackets::Character::GetRegionwideCharacterRestrictionAndMailData& packet);
|
||||
void HandleGetRafAccountInfo(WorldPackets::RaF::GetRafAccountInfo& packet);
|
||||
void HandleConvertTimerunningCharacter(WorldPackets::Character::ConvertTimerunningCharacter& convertTimerunningCharacter);
|
||||
// Arathi Returning Player Experience: shared in-world entry point (Adventure Guide tile)
|
||||
@@ -2222,6 +2226,8 @@ public:
|
||||
|
||||
// In-game Shop (BattlePay)
|
||||
void HandleBattlePayGetProductList(WorldPackets::BattlePay::GetProductList& getProductList);
|
||||
void HandleGetLastCatalogFetch(WorldPackets::BattlePay::GetLastCatalogFetch& packet);
|
||||
void HandleUpdateLastCatalogFetch(WorldPackets::BattlePay::UpdateLastCatalogFetch& packet);
|
||||
void HandleUpdateVasPurchaseStates(WorldPackets::BattlePay::UpdateVasPurchaseStates& packet);
|
||||
void HandleVasGetServiceStatus(WorldPackets::BattlePay::VasGetServiceStatus& packet);
|
||||
void HandleGetVasTransferTargetRealmList(WorldPackets::BattlePay::GetVasTransferTargetRealmList& packet);
|
||||
@@ -2779,6 +2785,7 @@ public:
|
||||
uint32 _battlenetRequestToken;
|
||||
|
||||
time_t _logoutTime;
|
||||
time_t _lastCatalogFetch = 0;
|
||||
bool m_inQueue; // session wait in auth.queue
|
||||
ObjectGuid m_playerLoading; // code processed in LoginPlayer
|
||||
bool m_playerLoginRPE = false; // CMSG_PLAYER_LOGIN.RPE - Returning Player ("Catch Up") Experience enter
|
||||
@@ -2828,10 +2835,6 @@ public:
|
||||
// Packets cooldown
|
||||
time_t _calendarEventCreationCooldown;
|
||||
|
||||
// In-game Shop: last catalog generation this session was served the product-list blob for
|
||||
// (0 = never). Throttles the 58 KB blob to once per generation; see BattlePayMgr.
|
||||
uint32 _battlePayCatalogGeneration = 0;
|
||||
|
||||
// In-game Shop: pending purchase awaiting the client's confirmation response (two-step flow,
|
||||
// Shop.PurchaseConfirmation). _battlePayConfirmToken 0 = nothing pending.
|
||||
uint32 _battlePayPendingProductID = 0;
|
||||
|
||||
@@ -2785,7 +2785,8 @@ void Spell::TargetInfo::PreprocessTarget(Spell* spell)
|
||||
// if target is flagged for pvp also flag caster if a player
|
||||
// but respect current pvp rules (buffing/healing npcs flagged for pvp only flags you if they are in combat)
|
||||
_enablePVP = (MissCondition == SPELL_MISS_NONE || spell->m_spellInfo->HasAttribute(SPELL_ATTR3_PVP_ENABLING))
|
||||
&& unit->IsPvP() && (unit->IsInCombat() || unit->IsCharmedOwnedByPlayerOrPlayer()) && spell->m_caster->GetTypeId() == TYPEID_PLAYER; // need to check PvP state before spell effects, but act on it afterwards
|
||||
&& unit->IsPvP() && spell->m_caster->IsPlayer() && spell->m_caster->GetGUID() != unit->GetGUID()
|
||||
&& (unit->IsInCombat() || unit->IsCharmedOwnedByPlayerOrPlayer()); // need to check PvP state before spell effects, but act on it afterwards
|
||||
|
||||
if (_spellHitTarget)
|
||||
{
|
||||
@@ -3678,7 +3679,14 @@ void Spell::cancel(SpellCastResult result /*= SPELL_FAILED_INTERRUPTED*/, Option
|
||||
{
|
||||
m_originalCaster->RemoveDynObject(m_spellInfo->Id);
|
||||
if (m_spellInfo->IsChanneled()) // if not channeled then the object for the current cast wasn't summoned yet
|
||||
m_originalCaster->RemoveGameObject(m_spellInfo->Id, true);
|
||||
{
|
||||
if (GameObject* gameObject = m_originalCaster->GetGameObject(m_spellInfo->Id))
|
||||
{
|
||||
m_originalCaster->RemoveGameObject(gameObject, true);
|
||||
if (gameObject->GetGoType() == GAMEOBJECT_TYPE_RITUAL)
|
||||
m_originalCaster->GetSpellHistory()->ResetCooldown(m_spellInfo->Id, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//set state back so finish will be processed
|
||||
|
||||
@@ -6700,10 +6700,17 @@ void Spell::EffectCreatePrivateConversation()
|
||||
if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
|
||||
return;
|
||||
|
||||
if (unitTarget->GetTypeId() != TYPEID_PLAYER)
|
||||
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
Conversation::CreateConversation(effectInfo->MiscValue, unitTarget, destTarget->GetPosition(), unitTarget->GetGUID(), GetSpellInfo());
|
||||
// The effect targets the caster and often has no destination. The old
|
||||
// destTarget->GetPosition() placed the conversation at 0,0,0 and crashed
|
||||
// while adding it to the map. The Re-Sizer result spells hit this path.
|
||||
Position pos = unitTarget->GetPosition();
|
||||
if (m_targets.HasDst() && destTarget)
|
||||
pos = destTarget->GetPosition();
|
||||
|
||||
Conversation::CreateConversation(effectInfo->MiscValue, unitTarget, pos, unitTarget->GetGUID(), GetSpellInfo());
|
||||
}
|
||||
|
||||
void Spell::EffectApplyMountEquipment()
|
||||
@@ -7971,22 +7978,18 @@ void Spell::EffectForceEquipItem()
|
||||
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
|
||||
return;
|
||||
|
||||
Player* player = m_caster->ToPlayer();
|
||||
Player* player = unitTarget ? unitTarget->ToPlayer() : m_caster->ToPlayer();
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
auto const& item = player->GetItemByEntry(effectInfo->ItemType);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
return;
|
||||
|
||||
uint16 dest;
|
||||
if (player->CanEquipItem(NULL_SLOT, dest, item, true) == EQUIP_ERR_OK)
|
||||
uint32 itemId = uint32(effectInfo->MiscValue);
|
||||
if (!effectInfo->MiscValue || !sObjectMgr->GetItemTemplate(itemId))
|
||||
{
|
||||
player->EquipItem(dest, item, true);
|
||||
player->AutoUnequipOffhandIfNeed();
|
||||
TC_LOG_ERROR("spells", "EffectForceEquipItem: invalid itemId {} for spell {}", itemId, m_spellInfo->Id);
|
||||
return;
|
||||
}
|
||||
|
||||
player->ForceEquipItemFromInventory(itemId);
|
||||
}
|
||||
|
||||
void Spell::EffectCraftItem()
|
||||
|
||||
@@ -647,6 +647,7 @@ void World::LoadConfigSettings(bool reload)
|
||||
{ .Name = "AllowTwoSide.Interaction.Guild"sv, .DefaultValue = false, .Index = CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD },
|
||||
{ .Name = "AllowTwoSide.Interaction.Auction"sv, .DefaultValue = true, .Index = CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION },
|
||||
{ .Name = "AllowTwoSide.Trade"sv, .DefaultValue = false, .Index = CONFIG_ALLOW_TWO_SIDE_TRADE },
|
||||
{ .Name = "ExtendedAccountNameLengthLimit"sv, .DefaultValue = false, .Index = CONFIG_EXTENDED_ACCOUNT_NAME_LENGTH_LIMIT },
|
||||
{ .Name = "CharacterCreating.DisableAlliedRaceAchievementRequirement"sv, .DefaultValue = false, .Index = CONFIG_CHARACTER_CREATING_DISABLE_ALLIED_RACE_ACHIEVEMENT_REQUIREMENT },
|
||||
{ .Name = "AllFlightPaths"sv, .DefaultValue = false, .Index = CONFIG_ALL_TAXI_PATHS },
|
||||
{ .Name = "InstantFlightPaths"sv, .DefaultValue = false, .Index = CONFIG_INSTANT_TAXI },
|
||||
@@ -874,7 +875,7 @@ void World::LoadConfigSettings(bool reload)
|
||||
{ .Name = "Arena.RatedUpdateTimer"sv, .DefaultValue = 5 * IN_MILLISECONDS, .Index = CONFIG_ARENA_RATED_UPDATE_TIMER },
|
||||
{ .Name = "Arena.ArenaSeason.ID"sv, .DefaultValue = 32, .Index = CONFIG_ARENA_SEASON_ID },
|
||||
{ .Name = "Arena.ArenaStartRating"sv, .DefaultValue = 0, .Index = CONFIG_ARENA_START_RATING },
|
||||
{ .Name = "Arena.ArenaStartPersonalRating"sv, .DefaultValue = 1000, .Index = CONFIG_ARENA_START_PERSONAL_RATING },
|
||||
{ .Name = "Arena.ArenaStartPersonalRating"sv, .DefaultValue = 0, .Index = CONFIG_ARENA_START_PERSONAL_RATING },
|
||||
{ .Name = "Arena.ArenaStartMatchmakerRating"sv, .DefaultValue = 1500, .Index = CONFIG_ARENA_START_MATCHMAKER_RATING },
|
||||
{ .Name = "Creature.PickPocketRefillDelay"sv, .DefaultValue = 10 * MINUTE, .Index = CONFIG_CREATURE_PICKPOCKET_REFILL },
|
||||
{ .Name = "Creature.MovingStopTimeForPlayer"sv, .DefaultValue = 3 * MINUTE * IN_MILLISECONDS, .Index = CONFIG_CREATURE_STOP_FOR_PLAYER },
|
||||
|
||||
@@ -194,6 +194,7 @@ enum WorldBoolConfigs : uint32
|
||||
CONFIG_RESPAWN_DYNAMIC_ESCORTNPC,
|
||||
CONFIG_REGEN_HP_CANNOT_REACH_TARGET_IN_RAID,
|
||||
CONFIG_ALLOW_LOGGING_IP_ADDRESSES_IN_DATABASE,
|
||||
CONFIG_EXTENDED_ACCOUNT_NAME_LENGTH_LIMIT,
|
||||
CONFIG_CHARACTER_CREATING_DISABLE_ALLIED_RACE_ACHIEVEMENT_REQUIREMENT,
|
||||
CONFIG_BATTLEGROUNDMAP_LOAD_GRIDS,
|
||||
CONFIG_ENABLE_AE_LOOT,
|
||||
|
||||
@@ -189,6 +189,14 @@ void WorldStateMgr::LoadFromDB()
|
||||
}
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded {} saved world state values {} ms", savedValueCount, GetMSTimeDiffToNow(oldMSTime));
|
||||
|
||||
// SMSG_INIT_WORLD_STATES copies this cache. It used to stay empty until some later realm-state
|
||||
// change, so a login before that change never received the loaded values. The Eversong captures
|
||||
// include every Prey hunt slot (set or zero) in the initial packet while the player is in Silvermoon.
|
||||
data.RealmWorldStatePacketCache.clear();
|
||||
data.RealmWorldStatePacketCache.reserve(data.RealmWorldStateValues.size());
|
||||
for (auto const& [worldStateId, value] : data.RealmWorldStateValues)
|
||||
data.RealmWorldStatePacketCache.emplace_back(worldStateId, value);
|
||||
}
|
||||
|
||||
void WorldStateMgr::Update()
|
||||
|
||||
@@ -265,7 +265,7 @@ public:
|
||||
}
|
||||
break;
|
||||
case AccountOpResult::AOR_NAME_TOO_LONG:
|
||||
handler->SendSysMessage(LANG_ACCOUNT_NAME_TOO_LONG);
|
||||
handler->PSendSysMessage(LANG_ACCOUNT_NAME_TOO_LONG, MAX_ACCOUNT_STR[sWorld->getBoolConfig(CONFIG_EXTENDED_ACCOUNT_NAME_LENGTH_LIMIT)]);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
case AccountOpResult::AOR_PASS_TOO_LONG:
|
||||
|
||||
@@ -36,7 +36,7 @@ using namespace Trinity::ChatCommands;
|
||||
class send_commandscript : public CommandScript
|
||||
{
|
||||
public:
|
||||
send_commandscript() : CommandScript("send_commandscript") { }
|
||||
send_commandscript() : CommandScript("send_commandscript") {}
|
||||
|
||||
std::span<ChatCommandBuilder const> GetCommands() const override
|
||||
{
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
|
||||
// msgSubject, msgText isn't NUL after prev. check
|
||||
std::string subject = msgSubject;
|
||||
std::string text = msgText;
|
||||
std::string text = msgText;
|
||||
|
||||
// from console, use non-existing sender
|
||||
MailSender sender(MAIL_NORMAL, handler->GetSession() ? handler->GetSession()->GetPlayer()->GetGUID().GetCounter() : UI64LIT(0), MAIL_STATIONERY_GM);
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
/// @todo Fix poor design
|
||||
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
MailDraft(subject, text)
|
||||
.SendMailTo(trans, MailReceiver(target, targetGuid.GetCounter()), sender);
|
||||
.SendMailTo(trans, MailReceiver(target, targetGuid.GetCounter()), sender, MAIL_CHECK_MASK_NOT_RETURNABLE);
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
@@ -128,7 +128,7 @@ public:
|
||||
|
||||
// msgSubject, msgText isn't NUL after prev. check
|
||||
std::string subject = msgSubject;
|
||||
std::string text = msgText;
|
||||
std::string text = msgText;
|
||||
|
||||
// extract items
|
||||
typedef std::pair<uint32, uint32> ItemPair;
|
||||
@@ -201,7 +201,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
draft.SendMailTo(trans, MailReceiver(receiver, receiverGuid.GetCounter()), sender);
|
||||
draft.SendMailTo(trans, MailReceiver(receiver, receiverGuid.GetCounter()), sender, MAIL_CHECK_MASK_NOT_RETURNABLE);
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
std::string nameLink = handler->playerLink(receiverName);
|
||||
@@ -220,7 +220,7 @@ public:
|
||||
|
||||
MailDraft(subject, text)
|
||||
.AddMoney(money)
|
||||
.SendMailTo(trans, MailReceiver(receiver.GetConnectedPlayer(), receiver.GetGUID().GetCounter()), sender);
|
||||
.SendMailTo(trans, MailReceiver(receiver.GetConnectedPlayer(), receiver.GetGUID().GetCounter()), sender, MAIL_CHECK_MASK_NOT_RETURNABLE);
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
|
||||
@@ -104,14 +104,7 @@ public:
|
||||
}
|
||||
|
||||
if (sceneEvent == "Trampling Time")
|
||||
{
|
||||
if (Creature* giantBoarVehicle = player->GetVehicleCreatureBase())
|
||||
{
|
||||
Position targetLoc = giantBoarVehicle->GetFirstCollisionPosition(20.f, 0.f);
|
||||
giantBoarVehicle->GetMotionMaster()->MoveCharge(targetLoc.GetPositionX(), targetLoc.GetPositionY(), targetLoc.GetPositionZ());
|
||||
player->CastSpell(player, SPELL_GIANT_BOAR_TRAMPLE, true);
|
||||
}
|
||||
}
|
||||
player->CastSpell(player, SPELL_GIANT_BOAR_TRAMPLE, true);
|
||||
}
|
||||
|
||||
void OnUpdateArea(Player* player, uint32 newArea, uint32 /*oldArea*/) override
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include "TemporarySummon.h"
|
||||
#include "Transport.h"
|
||||
#include "Vehicle.h"
|
||||
#include "WaypointDefines.h"
|
||||
#include "RaceMask.h"
|
||||
#include "ZoneScript.h"
|
||||
|
||||
enum ExileReachHelpers
|
||||
@@ -67,6 +69,8 @@ enum ExileReachHelpers
|
||||
QUEST_FINDING_THE_LOST_EXPEDITION = 54952,
|
||||
QUEST_COOKING_MEAT = 55174,
|
||||
QUEST_ENHANCED_COMBAT_TACTICS = 59254,
|
||||
QUEST_ENHANCED_COMBAT_TACTICS_MONK = 59339,
|
||||
QUEST_TAMING_THE_WILDS = 59342,
|
||||
QUEST_NORTHBOUND = 55173,
|
||||
QUEST_DOWN_WITH_THE_QUILBOAR = 55186,
|
||||
QUEST_FORBIDDEN_QUILBOAR_NECROMANCY = 55184,
|
||||
@@ -100,6 +104,8 @@ enum ExileReachHelpers
|
||||
QUEST_H_FINDING_THE_LOST_EXPEDITION = 59931,
|
||||
QUEST_H_COOKING_MEAT = 59932,
|
||||
QUEST_H_ENHANCED_COMBAT_TACTICS = 59933,
|
||||
QUEST_H_ENHANCED_COMBAT_TACTICS_MONK = 59934,
|
||||
QUEST_H_TAMING_THE_WILDS = 59937,
|
||||
QUEST_H_NORTHBOUND = 59935,
|
||||
QUEST_H_DOWN_WITH_THE_QUILBOAR = 59938,
|
||||
QUEST_H_FORBIDDEN_QUILBOAR_NECROMANCY = 59939,
|
||||
@@ -126,7 +132,8 @@ enum ExileReachHelpers
|
||||
SCENE_DEER_GO_UP = 2775,
|
||||
SCENE_HENRY_REUNION = 2717,
|
||||
SCENE_GRIMAXE_REUNION = 2905,
|
||||
SCENE_REUNION = 2497,
|
||||
SCENE_REUNION = 2497, // spell 326678, Horde, The Re-Deather
|
||||
SCENE_REUNION_ALLIANCE = 2341, // spell 305893, Alliance, Ride of the Scientifically Enhanced Boar
|
||||
SCENE_OGRE_BEFORE_BIG_BOAR_ATTACK = 2932,
|
||||
SCENE_GORGROTHS_RITUAL_A = 2418,
|
||||
SCENE_GORGROTHS_RITUAL_H = 2496,
|
||||
@@ -144,6 +151,9 @@ enum ExileReachHelpers
|
||||
SCENE_FLY_TO_STORMWIND = 2499,
|
||||
SCENE_FLY_TO_ORGRIMMAR = 2498,
|
||||
|
||||
MOVIE_ALLIANCE_SHIP_CRASH = 895,
|
||||
MOVIE_HORDE_SHIP_CRASH = 931,
|
||||
|
||||
ITEM_RAW_MEAT = 174072,
|
||||
ITEM_COOKED_MEAT = 174074,
|
||||
ITEM_WARD_STONE_1 = 168599,
|
||||
@@ -196,6 +206,7 @@ enum ExileReachHelpers
|
||||
SPELL_WANDERING_BOAR_MOB_CHARGE = 256089,
|
||||
SPELL_WANDERING_BOAR_MOB_GORE = 256077,
|
||||
SPELL_LINDIE_DESUMMON = 305756,
|
||||
SPELL_PING_LINDIE = 305754,
|
||||
SPELL_SUMMON_DARKMAUL_PLAINS_QUESTGIVERS = 305776,
|
||||
SPELL_CANCEL_ALL_SKELETAL_ARMY_SPELLS = 305830,
|
||||
SPELL_PING_GARRICK_TO_RIDE_THE_BOAR = 316984,
|
||||
@@ -343,11 +354,14 @@ enum ExileReachHelpers
|
||||
NPC_DARKMAUL_PLAINS_FIZZLEPOP_RESIZING_SUMMON = 167915,
|
||||
NPC_DARKMAUL_PLAINS_SPRINGSTOCK_RESIZING_SUMMON = 156749,
|
||||
NPC_DARKMAUL_PLAINS_WANDERING_BOAR = 156716,
|
||||
NPC_DARKMAUL_PLAINS_RESIZED_BOAR = 156736,
|
||||
NPC_DARKMAUL_PLAINS_WANDERING_BOAR_SUMMON = 156267,
|
||||
NPC_DARKMAUL_PLAINS_GIANT_BOAR_VEHICLE = 156595,
|
||||
NPC_OGRE_RUINS_TORGOK_FIGHTER_A = 156807,
|
||||
NPC_OGRE_RUINS_TORGOK_FIGHTER_H = 167145,
|
||||
NPC_OGRE_RUINS_CADAVER_KILL_CREDIT = 165150,
|
||||
NPC_OGRE_RUINS_MONSTROUS_CADAVER = 157091,
|
||||
NPC_OGRE_RUINS_ZOMBIE_SERVANT = 156532,
|
||||
NPC_OGRE_RUINS_TORGOK = 162817,
|
||||
NPC_OGRE_RUINS_ALARIA = 156803,
|
||||
NPC_OGRE_RUINS_BJORN = 154300,
|
||||
@@ -676,6 +690,7 @@ enum ExileReachHelpers
|
||||
SOUND_COPTER_SIZING_1 = 158017,
|
||||
SOUND_COPTER_SIZING_2 = 157686,
|
||||
SOUND_BOAR_SIZING = 157516,
|
||||
SOUND_RESIZED_BOAR_GROW = 157469,
|
||||
|
||||
ACHIEVEMENT_NPE_SOLD_ITEM = 14221,
|
||||
};
|
||||
@@ -1025,8 +1040,21 @@ public:
|
||||
|
||||
bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override
|
||||
{
|
||||
// _creature->GetMotionMaster()->MoveSmoothPath(_pointId, _pathPoints, _pathSize, _walk, _fly);
|
||||
if (!_creature || !_creature->IsInWorld() || !_pathPoints || !_pathSize)
|
||||
return true;
|
||||
|
||||
std::vector<WaypointNode> nodes;
|
||||
nodes.reserve(_pathSize);
|
||||
for (size_t i = 0; i < _pathSize; ++i)
|
||||
{
|
||||
Position const& pos = _pathPoints[i];
|
||||
nodes.emplace_back(uint32(i), pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation());
|
||||
}
|
||||
|
||||
WaypointPath path(_pointId ? _pointId : 1, std::move(nodes), _walk ? WaypointMoveType::Walk : WaypointMoveType::Run,
|
||||
_fly ? WaypointPathFlags::FlyingPath : WaypointPathFlags::None);
|
||||
_creature->SetWalk(_walk);
|
||||
_creature->GetMotionMaster()->MovePath(path, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1067,6 +1095,32 @@ static void StartPrivateConversation(Player* player, uint32 conversationId, std:
|
||||
conversation->Start();
|
||||
}
|
||||
|
||||
void ArriveExileBeach(Player* player);
|
||||
|
||||
// The sell-to-vendor step is a criteria objective. Credit that tree when the
|
||||
// sell criteria fires. Item and kill objectives stay untouched.
|
||||
static void CreditCriteriaTreeObjectives(Player* player, uint32 questId)
|
||||
{
|
||||
if (!player || player->GetQuestStatus(questId) != QUEST_STATUS_INCOMPLETE)
|
||||
return;
|
||||
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||
if (!quest)
|
||||
return;
|
||||
|
||||
uint16 const slot = player->FindQuestSlot(questId);
|
||||
for (QuestObjective const& obj : quest->GetObjectives())
|
||||
{
|
||||
if (obj.Type != QUEST_OBJECTIVE_CRITERIA_TREE)
|
||||
continue;
|
||||
|
||||
if (slot < MAX_QUEST_LOG_SIZE && player->IsQuestObjectiveComplete(slot, quest, obj))
|
||||
continue;
|
||||
|
||||
player->KillCreditCriteriaTreeObjective(obj);
|
||||
}
|
||||
}
|
||||
|
||||
static void AddCreditForQuestObjective(Player* player, uint32 questId, int32 objectiveId)
|
||||
{
|
||||
if (player->GetQuestStatus(questId) == QUEST_STATUS_INCOMPLETE)
|
||||
@@ -1106,3 +1160,19 @@ static void CancelExilesReachSceneAuras(Player* player)
|
||||
if (player->HasAura(SPELL_AMBIENCE_SCENE))
|
||||
player->RemoveAura(SPELL_AMBIENCE_SCENE);
|
||||
}
|
||||
|
||||
// Neutral pandaren are neither Alliance nor Horde, so the faction phase checks hide every quest giver.
|
||||
// Horde pandaren stay Horde. Alliance pandaren stay Alliance. A neutral one follows the ship deck they are on.
|
||||
inline bool ExileUsesHorde(Player const* player)
|
||||
{
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
if (player->GetRace() == RACE_PANDAREN_HORDE || player->IsInHorde())
|
||||
return true;
|
||||
|
||||
if (player->GetRace() == RACE_PANDAREN_ALLIANCE || player->IsInAlliance())
|
||||
return false;
|
||||
|
||||
return player->GetAreaId() == AREA_NORTH_SEA_H;
|
||||
}
|
||||
|
||||
@@ -21,10 +21,100 @@
|
||||
@TODO: Use conversations instead of scheduled talk
|
||||
*/
|
||||
|
||||
|
||||
#include "CellImpl.h"
|
||||
#include "GridNotifiersImpl.h"
|
||||
#include "Loot.h"
|
||||
#include "exiles_reach.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <initializer_list>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
uint32 constexpr NPC_COASTAL_GOAT = 161130;
|
||||
uint32 constexpr NPC_PRICKLY_PORCUPINE = 161131;
|
||||
|
||||
bool IsExileCampWildlifeOrNpc(uint32 entry)
|
||||
{
|
||||
switch (entry)
|
||||
{
|
||||
case NPC_COASTAL_GOAT:
|
||||
case NPC_PRICKLY_PORCUPINE:
|
||||
case NPC_ABANDONED_CAMP_ALARIA:
|
||||
case NPC_ABANDONED_CAMP_WONSA:
|
||||
case NPC_ABANDONED_CAMP_GARRICK:
|
||||
case NPC_ABANDONED_CAMP_BREKA:
|
||||
case NPC_ABANDONED_CAMP_GARRICK_WALKING:
|
||||
case NPC_ABANDONED_CAMP_BREKA_WALKING:
|
||||
case NPC_ABANDONED_CAMP_ALARIA_2: // 175031, Alaria after she has eaten
|
||||
case 175030: // Won'sa after she has eaten
|
||||
case 161265: // Jrok'gar
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsExileCampGolemDummy(Creature const* creature)
|
||||
{
|
||||
if (!creature || creature->IsSummon() || creature->IsPet())
|
||||
return false;
|
||||
|
||||
if (IsExileCampWildlifeOrNpc(creature->GetEntry()))
|
||||
return false;
|
||||
|
||||
std::string name = creature->GetName();
|
||||
for (char& character : name)
|
||||
character = char(std::tolower(static_cast<unsigned char>(character)));
|
||||
|
||||
if (creature->IsTrigger() || creature->GetCreatureTemplate()->family == CREATURE_FAMILY_INFERNAL)
|
||||
return true;
|
||||
|
||||
// Display 169 is infernal.m2. Anchors fall back to it when their invisible model is missing.
|
||||
if (creature->GetDisplayId() == 169)
|
||||
return true;
|
||||
|
||||
if (name.find("golem") != std::string::npos || name.find("infernal") != std::string::npos || name.find("dummy") != std::string::npos)
|
||||
return true;
|
||||
|
||||
// Spell anchors keep an infernal model when the invisibility aura never applied.
|
||||
return name.find("bunny") != std::string::npos || name.find("stalker") != std::string::npos || name.find("trigger") != std::string::npos;
|
||||
}
|
||||
|
||||
void HideExileCampGolemDummies(Player* player)
|
||||
{
|
||||
std::list<Creature*> creatures;
|
||||
Trinity::AnyUnitInObjectRangeCheck check(player, 150.0f, false, false);
|
||||
Trinity::CreatureListSearcher<Trinity::AnyUnitInObjectRangeCheck> searcher(player, creatures, check);
|
||||
Cell::VisitAllObjects(player, searcher, 150.0f);
|
||||
|
||||
for (Creature* creature : creatures)
|
||||
{
|
||||
if (!creature || !player->CanSeeOrDetect(creature))
|
||||
continue;
|
||||
|
||||
if (creature->GetEntry() == NPC_COASTAL_GOAT || creature->GetEntry() == NPC_PRICKLY_PORCUPINE)
|
||||
{
|
||||
if (creature->HasUnitFlag(UNIT_FLAG_UNINTERACTIBLE))
|
||||
creature->SetUninteractible(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsExileCampGolemDummy(creature))
|
||||
creature->SetVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveExilePhases(Player* player, std::initializer_list<uint32> phases)
|
||||
{
|
||||
for (uint32 phaseId : phases)
|
||||
if (player->GetPhaseShift().HasPhase(phaseId))
|
||||
PhasingHandler::RemovePhase(player, phaseId, true);
|
||||
}
|
||||
}
|
||||
|
||||
class exiles_reach_abandoned_camp_playerscript : public PlayerScript
|
||||
{
|
||||
@@ -40,25 +130,65 @@ public:
|
||||
{
|
||||
case AREA_ABANDONED_CAMP:
|
||||
{
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_SHORE }, false);
|
||||
// Later and earlier stages were left on, so their untargetable infernal anchors
|
||||
// were drawn across the wildlife field as soon as Cooking Meat started.
|
||||
RemoveExilePhases(player,
|
||||
{
|
||||
PHASE_GENERAL_SHORE,
|
||||
PHASE_ALLIANCE_SHORE_GARRICK_AND_FRIENDS_INJURED,
|
||||
PHASE_ALLIANCE_SHORE_GARRICK_AND_FRIENDS_HEALED,
|
||||
PHASE_ALLIANCE_SHORE_12940,
|
||||
PHASE_ALLIANCE_SHORE_13157,
|
||||
PHASE_ALLIANCE_SHORE_13503,
|
||||
PHASE_HORDE_SHORE_UNK,
|
||||
PHASE_HORDE_SHORE_BREKA_AND_FRIENDS_INJURED,
|
||||
PHASE_HORDE_SHORE_BREKA_AND_FRIENDS_HEALED,
|
||||
PHASE_GENERAL_SHIP,
|
||||
PHASE_ALLIANCE_SHIP_CREW_OUTSIDE,
|
||||
PHASE_ALLIANCE_SHIP_COLE,
|
||||
PHASE_ALLIANCE_SHIP_GARRICK_1,
|
||||
PHASE_ALLIANCE_SHIP_13619,
|
||||
PHASE_ALLIANCE_SHIP_14350,
|
||||
PHASE_ALLIANCE_SHIP_13454,
|
||||
PHASE_ALLIANCE_SHIP_GARRICK_2,
|
||||
PHASE_ALLIANCE_SHIP_CREW_INSIDE,
|
||||
PHASE_HORDE_SHIP_THROG,
|
||||
PHASE_HORDE_SHIP_15514,
|
||||
PHASE_HORDE_SHIP_15287,
|
||||
PHASE_HORDE_SHIP_15516,
|
||||
PHASE_GENERAL_QUILBOAR_BRIARPATCH,
|
||||
PHASE_ALLIANCE_QUILBOAR_BRIARPATCH_AUSTIN,
|
||||
PHASE_ALLIANCE_QUILBOAR_BRIARPATCH_GARRICK,
|
||||
PHASE_ALLIANCE_QUILBOAR_BRIARPATCH_15276,
|
||||
PHASE_ALLIANCE_QUILBOAR_BRIARPATCH_16917,
|
||||
PHASE_ALLIANCE_QUILBOAR_BRIARPATCH_SPRINGSTOCK,
|
||||
PHASE_HORDE_QUILBOAR_BRIARPATCH_FIZZLEPOP,
|
||||
PHASE_HORDE_QUILBOAR_BRIARPATCH_15477,
|
||||
PHASE_HORDE_QUILBOAR_BRIARPATCH_MITHDRAN,
|
||||
PHASE_HORDE_QUILBOAR_BRIARPATCH_BREKA_ARRIVED,
|
||||
PHASE_GENERAL_DARKMAUL_PLAINS_MOBS,
|
||||
PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS,
|
||||
PHASE_GENERAL_DARKMAUL_CITADEL_GORGROTH_AND_FRIENDS,
|
||||
PHASE_HORDE_DARKMAUL_CITADEL_GORGROTH_AND_FRIENDS_COOKING_AREA,
|
||||
PHASE_ALLIANCE_DARKMAUL_CITADEL_GORGROTH_AND_FRIENDS_SUMMON,
|
||||
});
|
||||
|
||||
if (player->IsInHorde())
|
||||
{
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_SHORE_UNK }, true);;
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_ABANDONED_CAMP_15324 }, true);
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_ABANDONED_CAMP_WONSA_STARVING }, !QuestRewarded(player, QUEST_H_COOKING_MEAT));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_ABANDONED_CAMP_WONSA_EATEN }, QuestRewarded(player, QUEST_H_COOKING_MEAT));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_ABANDONED_CAMP_BREKA_PEACEFUL }, QuestCompletedOrRewarded(player, QUEST_H_FINDING_THE_LOST_EXPEDITION) && !player->GetSummonedCreatureByEntry(NPC_ABANDONED_CAMP_BREKA) && !player->GetSummonedCreatureByEntry(NPC_ABANDONED_CAMP_BREKA_WALKING) && !player->GetQuestStatus(QUEST_H_NORTHBOUND));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_QUILBOAR_BRIARPATCH_MITHDRAN }, !QuestRewarded(player, QUEST_H_NORTHBOUND));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_ABANDONED_CAMP_BREKA_PEACEFUL }, QuestCompletedOrRewarded(player, QUEST_H_FINDING_THE_LOST_EXPEDITION) && !player->GetSummonedCreatureByEntry(NPC_ABANDONED_CAMP_BREKA) && !player->GetSummonedCreatureByEntry(NPC_ABANDONED_CAMP_BREKA_WALKING) && !player->GetSummonedCreatureByEntry(NPC_MURLOC_HIDEAWAY_BREKA) && player->GetQuestStatus(QUEST_H_NORTHBOUND) == QUEST_STATUS_NONE);
|
||||
}
|
||||
|
||||
if (player->IsInAlliance())
|
||||
{
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_ABANDONED_CAMP_ALARIA_STARVING }, !QuestRewarded(player, QUEST_COOKING_MEAT));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_ABANDONED_CAMP_ALARIA_EATEN }, QuestRewarded(player, QUEST_COOKING_MEAT));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_ABANDONED_CAMP_GARRICK_PEACEFUL }, QuestRewarded(player, QUEST_FINDING_THE_LOST_EXPEDITION) && !player->GetSummonedCreatureByEntry(NPC_ABANDONED_CAMP_GARRICK) && !player->GetQuestStatus(QUEST_NORTHBOUND));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_QUILBOAR_BRIARPATCH_AUSTIN }, !QuestRewarded(player, QUEST_NORTHBOUND));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_ABANDONED_CAMP_GARRICK_PEACEFUL }, QuestCompletedOrRewarded(player, QUEST_FINDING_THE_LOST_EXPEDITION) && !player->GetSummonedCreatureByEntry(NPC_ABANDONED_CAMP_GARRICK) && !player->GetSummonedCreatureByEntry(NPC_MURLOC_HIDEAWAY_GARRICK) && player->GetQuestStatus(QUEST_NORTHBOUND) == QUEST_STATUS_NONE);
|
||||
}
|
||||
|
||||
HideExileCampGolemDummies(player);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -70,7 +200,10 @@ public:
|
||||
// Remove summons if player abandons or rewards a quest
|
||||
if (player->GetMapId() == MAP_NPE)
|
||||
{
|
||||
if (player->GetQuestStatus(questId) == QUEST_STATUS_NONE || player->GetQuestStatus(questId) == QUEST_STATUS_REWARDED)
|
||||
QuestStatus const status = player->GetQuestStatus(questId);
|
||||
bool const escortDone = status == QUEST_STATUS_COMPLETE
|
||||
&& (questId == QUEST_FINDING_THE_LOST_EXPEDITION || questId == QUEST_H_FINDING_THE_LOST_EXPEDITION);
|
||||
if (status == QUEST_STATUS_NONE || status == QUEST_STATUS_REWARDED || escortDone)
|
||||
{
|
||||
std::vector<uint32> activeSummons;
|
||||
switch (questId)
|
||||
@@ -131,7 +264,8 @@ struct npc_exiles_reach_abandoned_camp_166854_156607 : public ScriptedAI
|
||||
|
||||
if (player->IsInDist(me, 10.0f))
|
||||
{
|
||||
if (player->GetQuestStatus(QUEST_FINDING_THE_LOST_EXPEDITION) || player->GetQuestStatus(QUEST_H_FINDING_THE_LOST_EXPEDITION))
|
||||
if (player->GetQuestStatus(QUEST_FINDING_THE_LOST_EXPEDITION) == QUEST_STATUS_INCOMPLETE
|
||||
|| player->GetQuestStatus(QUEST_H_FINDING_THE_LOST_EXPEDITION) == QUEST_STATUS_INCOMPLETE)
|
||||
player->KilledMonsterCredit(me->GetEntry());
|
||||
|
||||
if (player->HasItemCount(ITEM_COOKED_MEAT, 2, false))
|
||||
@@ -172,12 +306,16 @@ struct npc_exiles_reach_abandoned_camp_166854_156607 : public ScriptedAI
|
||||
|
||||
void OnQuestReward(Player* player, Quest const* quest, LootItemType /*type*/, uint32 /*opt*/) override
|
||||
{
|
||||
if (quest->GetQuestId() == QUEST_H_COOKING_MEAT && player->GetItemByEntry(ITEM_COOKED_MEAT))
|
||||
if ((quest->GetQuestId() == QUEST_COOKING_MEAT || quest->GetQuestId() == QUEST_H_COOKING_MEAT) && player->GetItemByEntry(ITEM_COOKED_MEAT))
|
||||
player->DestroyItemCount(ITEM_COOKED_MEAT, player->GetItemCount(ITEM_COOKED_MEAT), true, false);
|
||||
|
||||
if (quest->GetQuestId() == QUEST_H_FINDING_THE_LOST_EXPEDITION)
|
||||
if (Creature* brekatemp = player->GetSummonedCreatureByEntry(NPC_MURLOC_HIDEAWAY_BREKA))
|
||||
brekatemp->DespawnOrUnsummon();
|
||||
if (quest->GetQuestId() == QUEST_FINDING_THE_LOST_EXPEDITION || quest->GetQuestId() == QUEST_H_FINDING_THE_LOST_EXPEDITION)
|
||||
{
|
||||
if (Creature* garrick = player->GetSummonedCreatureByEntry(NPC_MURLOC_HIDEAWAY_GARRICK))
|
||||
garrick->DespawnOrUnsummon();
|
||||
if (Creature* breka = player->GetSummonedCreatureByEntry(NPC_MURLOC_HIDEAWAY_BREKA))
|
||||
breka->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
me->CastSpell(player, SPELL_UPDATE_PHASESHIFT, true);
|
||||
|
||||
@@ -190,6 +328,30 @@ private:
|
||||
bool talked, metBrekaOrGarrick;
|
||||
};
|
||||
|
||||
static bool IsExileEnhancedCombatQuest(uint32 questId)
|
||||
{
|
||||
return questId == QUEST_ENHANCED_COMBAT_TACTICS
|
||||
|| questId == QUEST_H_ENHANCED_COMBAT_TACTICS
|
||||
|| questId == QUEST_ENHANCED_COMBAT_TACTICS_MONK
|
||||
|| questId == QUEST_H_ENHANCED_COMBAT_TACTICS_MONK;
|
||||
}
|
||||
|
||||
static bool HasIncompleteExileEnhancedCombat(Player const* player)
|
||||
{
|
||||
return player->GetQuestStatus(QUEST_ENHANCED_COMBAT_TACTICS) == QUEST_STATUS_INCOMPLETE
|
||||
|| player->GetQuestStatus(QUEST_H_ENHANCED_COMBAT_TACTICS) == QUEST_STATUS_INCOMPLETE
|
||||
|| player->GetQuestStatus(QUEST_ENHANCED_COMBAT_TACTICS_MONK) == QUEST_STATUS_INCOMPLETE
|
||||
|| player->GetQuestStatus(QUEST_H_ENHANCED_COMBAT_TACTICS_MONK) == QUEST_STATUS_INCOMPLETE;
|
||||
}
|
||||
|
||||
static bool HasCompleteExileEnhancedCombat(Player const* player)
|
||||
{
|
||||
return player->GetQuestStatus(QUEST_ENHANCED_COMBAT_TACTICS) == QUEST_STATUS_COMPLETE
|
||||
|| player->GetQuestStatus(QUEST_H_ENHANCED_COMBAT_TACTICS) == QUEST_STATUS_COMPLETE
|
||||
|| player->GetQuestStatus(QUEST_ENHANCED_COMBAT_TACTICS_MONK) == QUEST_STATUS_COMPLETE
|
||||
|| player->GetQuestStatus(QUEST_H_ENHANCED_COMBAT_TACTICS_MONK) == QUEST_STATUS_COMPLETE;
|
||||
}
|
||||
|
||||
// Warlord Breka Grimaxe, Captain Garrick (abandoned camp)
|
||||
struct npc_exiles_reach_abandoned_camp_166906_156651 : public ScriptedAI
|
||||
{
|
||||
@@ -241,7 +403,7 @@ struct npc_exiles_reach_abandoned_camp_166906_156651 : public ScriptedAI
|
||||
}
|
||||
}
|
||||
|
||||
if (quest->GetQuestId() == QUEST_H_ENHANCED_COMBAT_TACTICS || quest->GetQuestId() == QUEST_ENHANCED_COMBAT_TACTICS)
|
||||
if (IsExileEnhancedCombatQuest(quest->GetQuestId()))
|
||||
{
|
||||
if (Creature* clone = player->SummonCreature(me->GetEntry(), me->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0U, 0U, player->GetGUID()))
|
||||
{
|
||||
@@ -277,18 +439,25 @@ struct npc_exiles_reach_abandoned_camp_166906_156651 : public ScriptedAI
|
||||
return;
|
||||
|
||||
PlayEnhancedCombatConversation(player, spell->Id);
|
||||
|
||||
// Monk Enhanced Combat Tactics (59339 / 59934) credits Tiger Palm and Blackout Kick
|
||||
// separately. Those are the two abilities the quest asks for.
|
||||
if (player->GetClass() == CLASS_MONK && HasIncompleteExileEnhancedCombat(player))
|
||||
{
|
||||
if (spell->Id == 100780)
|
||||
player->KilledMonsterCredit(164577);
|
||||
else if (spell->Id == 100784)
|
||||
player->KilledMonsterCredit(164775);
|
||||
}
|
||||
|
||||
hitCounter++;
|
||||
|
||||
if (hitCounter == 3)
|
||||
{
|
||||
if (player->GetQuestStatus(QUEST_ENHANCED_COMBAT_TACTICS) == QUEST_STATUS_INCOMPLETE ||
|
||||
player->GetQuestStatus(QUEST_H_ENHANCED_COMBAT_TACTICS) == QUEST_STATUS_INCOMPLETE)
|
||||
{
|
||||
if (HasIncompleteExileEnhancedCombat(player))
|
||||
player->KilledMonsterCredit(164577);
|
||||
}
|
||||
|
||||
if (player->GetQuestStatus(QUEST_ENHANCED_COMBAT_TACTICS) == QUEST_STATUS_COMPLETE ||
|
||||
player->GetQuestStatus(QUEST_H_ENHANCED_COMBAT_TACTICS) == QUEST_STATUS_COMPLETE)
|
||||
if (HasCompleteExileEnhancedCombat(player))
|
||||
{
|
||||
BeFriendly();
|
||||
trainingQuestDone = true;
|
||||
@@ -340,8 +509,7 @@ struct npc_exiles_reach_abandoned_camp_166906_156651 : public ScriptedAI
|
||||
private:
|
||||
void PlayEnhancedCombatConversation(Player* player, uint32 spellId)
|
||||
{
|
||||
if (player->GetQuestStatus(QUEST_ENHANCED_COMBAT_TACTICS) != QUEST_STATUS_INCOMPLETE &&
|
||||
player->GetQuestStatus(QUEST_H_ENHANCED_COMBAT_TACTICS) != QUEST_STATUS_INCOMPLETE)
|
||||
if (!HasIncompleteExileEnhancedCombat(player))
|
||||
return;
|
||||
|
||||
uint32 conversationId = 0;
|
||||
@@ -428,7 +596,15 @@ private:
|
||||
else if (spellId == 164812 || spellId == 8921)
|
||||
conversationId = _classCasts++ == 0 ? CONVERSATION_ENHANCED_MOONFIRE_PRE : CONVERSATION_ENHANCED_MOONFIRE_CREDIT;
|
||||
break;
|
||||
case CLASS_MONK:
|
||||
// 59339 / 59934 credit Tiger Palm (100780) and Blackout Kick (100784) in SpellHit.
|
||||
break;
|
||||
case CLASS_HUNTER:
|
||||
// Hunters take Taming the Wilds (59342 / 59937) instead of this spar.
|
||||
break;
|
||||
default:
|
||||
// Death Knight, Demon Hunter and Evoker have no separate Exile's Reach class quest.
|
||||
// The shared chain is open to them, and this spar still credits after three hits.
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -576,15 +752,33 @@ struct go_campfire_339769 : public GameObjectAI
|
||||
|
||||
bool OnGossipHello(Player* player) override
|
||||
{
|
||||
uint32 const questId = player->IsInHorde() ? QUEST_H_COOKING_MEAT : QUEST_COOKING_MEAT;
|
||||
if (player->GetQuestStatus(questId) != QUEST_STATUS_INCOMPLETE)
|
||||
return false;
|
||||
|
||||
if (player->hasQuest(QUEST_COOKING_MEAT) || player->hasQuest(QUEST_H_COOKING_MEAT))
|
||||
player->ForceCompleteQuest(QUEST_COOKING_MEAT);
|
||||
if (me->GetGOInfo()->GetLootId())
|
||||
return false;
|
||||
|
||||
player->AddItem(174074, 1);
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||
if (!quest)
|
||||
return false;
|
||||
|
||||
me->DespawnOrUnsummon(0s);
|
||||
bool handled = false;
|
||||
for (QuestObjective const& obj : quest->GetObjectives())
|
||||
{
|
||||
if (obj.Type == QUEST_OBJECTIVE_ITEM && obj.ObjectID == ITEM_COOKED_MEAT)
|
||||
{
|
||||
player->AddItem(ITEM_COOKED_MEAT, 1);
|
||||
handled = true;
|
||||
}
|
||||
else if (obj.Type == QUEST_OBJECTIVE_GAMEOBJECT && uint32(obj.ObjectID) == me->GetEntry())
|
||||
{
|
||||
player->KillCreditGO(me->GetEntry(), me->GetGUID());
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return handled;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -457,14 +457,14 @@ struct npc_exiles_reach_darkmaul_citadel_156954_167646 : public ScriptedAI
|
||||
{
|
||||
if (QuestAccepted(player, QUEST_RIGHT_BENEATH_THEIR_EYES))
|
||||
{
|
||||
//AddCreditForQuestObjective(player, QUEST_RIGHT_BENEATH_THEIR_EYES, QUEST_OBJECTIVE_RIGHT_BENEATH_THEIR_EYES_REACH_CITADEL);
|
||||
player->ForceCompleteQuest(QUEST_RIGHT_BENEATH_THEIR_EYES);
|
||||
AddCreditForQuestObjective(player, QUEST_RIGHT_BENEATH_THEIR_EYES, QUEST_OBJECTIVE_RIGHT_BENEATH_THEIR_EYES_REACH_CITADEL);
|
||||
AddCreditForQuestObjective(player, QUEST_RIGHT_BENEATH_THEIR_EYES, QUEST_OBJECTIVE_RIGHT_BENEATH_THEIR_EYES_REACHED_DARKMAUL_CITADEL_ENTRANCE);
|
||||
}
|
||||
|
||||
if (QuestAccepted(player, QUEST_H_RIGHT_BENEATH_THEIR_EYES))
|
||||
{
|
||||
//AddCreditForQuestObjective(player, QUEST_H_RIGHT_BENEATH_THEIR_EYES, QUEST_OBJECTIVE_RIGHT_BENEATH_THEIR_EYES_REACH_CITADEL);
|
||||
player->ForceCompleteQuest(QUEST_H_RIGHT_BENEATH_THEIR_EYES);
|
||||
AddCreditForQuestObjective(player, QUEST_H_RIGHT_BENEATH_THEIR_EYES, QUEST_OBJECTIVE_RIGHT_BENEATH_THEIR_EYES_REACH_CITADEL);
|
||||
AddCreditForQuestObjective(player, QUEST_H_RIGHT_BENEATH_THEIR_EYES, QUEST_OBJECTIVE_RIGHT_BENEATH_THEIR_EYES_REACHED_DARKMAUL_CITADEL_ENTRANCE);
|
||||
}
|
||||
|
||||
player->m_Events.AddEventAtOffset(new ReachCitadelEntranceEvent(player), 2s);
|
||||
@@ -537,16 +537,14 @@ struct go_exiles_reach_ogre_runestone_351476_339865 : public GameObjectAI
|
||||
player->KillCreditGO(me->GetEntry());
|
||||
invisibleStalker->DespawnOrUnsummon(200ms, 60s);
|
||||
|
||||
if (player->GetQuestObjectiveProgress(QUEST_CONTROLLING_THEIR_STONES, 4) == 3)
|
||||
if (QuestCompleted(player, QUEST_CONTROLLING_THEIR_STONES) || player->GetQuestObjectiveProgress(QUEST_CONTROLLING_THEIR_STONES, 4) >= 3)
|
||||
{
|
||||
player->ForceCompleteQuest(QUEST_CONTROLLING_THEIR_STONES);
|
||||
player->RemoveAura(SPELL_RITUAL_SCENE_OGRE_CITADEL);
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_DARKMAUL_CITADEL_MULGRIN_RITUAL }, false);
|
||||
}
|
||||
|
||||
if (player->GetQuestObjectiveProgress(QUEST_H_CONTROLLING_THEIR_STONES, 4) == 3)
|
||||
if (QuestCompleted(player, QUEST_H_CONTROLLING_THEIR_STONES) || player->GetQuestObjectiveProgress(QUEST_H_CONTROLLING_THEIR_STONES, 4) >= 3)
|
||||
{
|
||||
player->ForceCompleteQuest(QUEST_H_CONTROLLING_THEIR_STONES);
|
||||
player->RemoveAura(SPELL_RITUAL_SCENE_OGRE_CITADEL);
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_DARKMAUL_CITADEL_KEIRA_RITUAL }, false);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
#include "exiles_reach.h"
|
||||
#include <list>
|
||||
|
||||
class exiles_reach_darkmaul_plains_playerscript : public PlayerScript
|
||||
{
|
||||
@@ -43,7 +44,7 @@ public:
|
||||
|
||||
if (player->IsInHorde())
|
||||
{
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, !player->HasAura(SPELL_RESIZER_SLAUGHTER) && !player->GetVehicle() && !player->GetQuestStatus(QUEST_H_THE_REDEATHER));
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, !player->HasAura(SPELL_RESIZER_SLAUGHTER) && !QuestCompletedOrRewarded(player, QUEST_H_THE_REDEATHER));
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_OGRE_RUINS_TORGOK }, !QuestCompletedOrRewarded(player, QUEST_H_THE_REDEATHER));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_DARKMAUL_PLAINS_MITHDRAN }, QuestCompletedOrRewarded(player, QUEST_H_FORBIDDEN_QUILBOAR_NECROMANCY));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_DARKMAUL_PLAINS_BREKA }, QuestCompletedOrRewarded(player, QUEST_H_DOWN_WITH_THE_QUILBOAR));
|
||||
@@ -59,7 +60,7 @@ public:
|
||||
|
||||
if (player->IsInAlliance())
|
||||
{
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !player->HasAura(SPELL_RIDING_GIANT_BOAR) && !player->GetQuestStatus(QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !QuestCompletedOrRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_OGRE_RUINS_TORGOK }, !QuestCompletedOrRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_HARPY_ROOST_MEREDY_RITUAL }, true);
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_QUILBOAR_BRIARPATCH_15276, PHASE_ALLIANCE_QUILBOAR_BRIARPATCH_16917 }, player->GetQuestStatus(QUEST_DOWN_WITH_THE_QUILBOAR) != QUEST_STATUS_REWARDED);
|
||||
@@ -87,23 +88,36 @@ public:
|
||||
// Remove summons if player abandons or rewards a quest
|
||||
if (player->GetMapId() == MAP_NPE)
|
||||
{
|
||||
if (player->GetQuestStatus(questId) == QUEST_STATUS_NONE || player->GetQuestStatus(questId) == QUEST_STATUS_REWARDED)
|
||||
QuestStatus const status = player->GetQuestStatus(questId);
|
||||
// The copter scene summons a second Lindie on top of the camp. Once the quest is
|
||||
// ready to turn in she has to go, or she stands beside the phase copy and the follower.
|
||||
bool const copterSceneDone = status == QUEST_STATUS_COMPLETE
|
||||
&& (questId == QUEST_THE_SCOUT_O_MATIC_5000 || questId == QUEST_H_THE_CHOPPY_BOOSTER_MK5);
|
||||
if (status == QUEST_STATUS_NONE || status == QUEST_STATUS_REWARDED || copterSceneDone)
|
||||
{
|
||||
std::vector<uint32> activeSummons;
|
||||
switch (questId)
|
||||
{
|
||||
case QUEST_H_THE_CHOPPY_BOOSTER_MK5:
|
||||
activeSummons.push_back(NPC_DARKMAUL_PLAINS_CHOPPYBOOSTER_SUMMONER);
|
||||
activeSummons.push_back(NPC_DARKMAUL_PLAINS_CHOPPYBOOSTER_OBSERVER);
|
||||
if (!copterSceneDone)
|
||||
activeSummons.push_back(NPC_DARKMAUL_PLAINS_CHOPPYBOOSTER_OBSERVER);
|
||||
activeSummons.push_back(NPC_DARKMAUL_PLAINS_FIZZLEPOP);
|
||||
break;
|
||||
case QUEST_THE_SCOUT_O_MATIC_5000:
|
||||
activeSummons.push_back(NPC_DARKMAUL_PLAINS_SCOUTOMATIC_SUMMONER);
|
||||
activeSummons.push_back(NPC_DARKMAUL_PLAINS_SCOUTOMATIC_OBSERVER);
|
||||
if (!copterSceneDone)
|
||||
activeSummons.push_back(NPC_DARKMAUL_PLAINS_SCOUTOMATIC_OBSERVER);
|
||||
activeSummons.push_back(NPC_DARKMAUL_PLAINS_SPRINGSTOCK);
|
||||
break;
|
||||
case QUEST_RE_SIZING_THE_SITUATION:
|
||||
activeSummons.push_back(NPC_DARKMAUL_PLAINS_WANDERING_BOAR_SUMMON);
|
||||
activeSummons.push_back(NPC_DARKMAUL_PLAINS_RESIZED_BOAR);
|
||||
activeSummons.push_back(NPC_DARKMAUL_PLAINS_SPRINGSTOCK_RESIZING_SUMMON);
|
||||
break;
|
||||
case QUEST_H_RE_SIZING_THE_SITUATION:
|
||||
activeSummons.push_back(NPC_DARKMAUL_PLAINS_RESIZED_BOAR);
|
||||
activeSummons.push_back(NPC_DARKMAUL_PLAINS_FIZZLEPOP_RESIZING_SUMMON);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -267,7 +281,8 @@ struct npc_exiles_reach_darkmaul_plains_167905_156526 : public VehicleAI
|
||||
{
|
||||
if (timer <= diff)
|
||||
{
|
||||
if (Unit* passenger = me->GetVehicleKit()->GetPassenger(0))
|
||||
Vehicle* kit = me->GetVehicleKit();
|
||||
if (Unit* passenger = kit ? kit->GetPassenger(0) : nullptr)
|
||||
{
|
||||
if (Player* player = passenger->ToPlayer())
|
||||
{
|
||||
@@ -353,12 +368,10 @@ struct npc_exiles_reach_darkmaul_plains_156267 : public VehicleAI
|
||||
{
|
||||
if (Player* player = summoner->ToPlayer())
|
||||
{
|
||||
if (me->GetAreaId() == AREA_DARKMAUL_PLAINS)
|
||||
if (me->GetAreaId() == AREA_DARKMAUL_PLAINS && me->GetVehicleKit())
|
||||
{
|
||||
if (Creature* garrick = player->GetSummonedCreatureByEntry(NPC_OGRE_RUINS_TORGOK_FIGHTER_A))
|
||||
{
|
||||
garrick->EnterVehicle(me, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -382,19 +395,45 @@ struct npc_exiles_reach_darkmaul_plains_167915_156749 : public ScriptedAI
|
||||
me->FollowTarget(player);
|
||||
}
|
||||
|
||||
void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
|
||||
{
|
||||
// 305754 is the ping the third Re-Sizer test sends. She runs back to camp once.
|
||||
if (!spellInfo || spellInfo->Id != SPELL_PING_LINDIE)
|
||||
return;
|
||||
|
||||
_events.ScheduleEvent(EVENT_RESIZING_RUN_HOME, 2s);
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type != POINT_MOTION_TYPE || id != POINT_RESIZING_HOME)
|
||||
return;
|
||||
|
||||
if (Unit* owner = me->GetCharmerOrOwnerPlayerOrPlayerItself())
|
||||
me->CastSpell(owner, SPELL_LINDIE_DESUMMON, true);
|
||||
else
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (timer <= diff)
|
||||
_events.Update(diff);
|
||||
|
||||
while (uint32 eventId = _events.ExecuteEvent())
|
||||
{
|
||||
if (me->GetPosition().IsInDist(ResizingTheSituationPositions[1], 1.f))
|
||||
me->CastSpell(me->GetCharmerOrOwnerPlayerOrPlayerItself(), SPELL_LINDIE_DESUMMON, true);
|
||||
if (eventId == EVENT_RESIZING_RUN_HOME)
|
||||
me->GetMotionMaster()->MovePoint(POINT_RESIZING_HOME, ResizingTheSituationPositions[1]);
|
||||
}
|
||||
else
|
||||
timer -= diff;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 timer = 1000;
|
||||
enum ResizingGuardianEvents
|
||||
{
|
||||
EVENT_RESIZING_RUN_HOME = 1,
|
||||
POINT_RESIZING_HOME = 0
|
||||
};
|
||||
|
||||
EventMap _events;
|
||||
};
|
||||
|
||||
// Wandering Boar (Darkmaul Plains) (Re-Sizing the Situation)
|
||||
@@ -402,20 +441,52 @@ struct npc_exiles_reach_darkmaul_plains_156736_156716 : public ScriptedAI
|
||||
{
|
||||
npc_exiles_reach_darkmaul_plains_156736_156716(Creature* creature) : ScriptedAI(creature) {}
|
||||
|
||||
bool IsResizedBoar() const
|
||||
{
|
||||
return me->GetEntry() == NPC_DARKMAUL_PLAINS_RESIZED_BOAR;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
if (IsResizedBoar())
|
||||
{
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
return;
|
||||
}
|
||||
|
||||
_events.Reset();
|
||||
_events.ScheduleEvent(1, 3s);
|
||||
}
|
||||
|
||||
void JustAppeared() override
|
||||
{
|
||||
if (!IsResizedBoar())
|
||||
{
|
||||
CreatureAI::JustAppeared();
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not follow the player. The boar grows, then walks to the camp and despawns.
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
_events.Reset();
|
||||
_events.ScheduleEvent(EVENT_RESIZED_BOAR_GROW, 1s);
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
// The Re-Sizer roots the boar. Charging the player from that aura was crashing the channel.
|
||||
if (IsResizedBoar() || !who || me->HasAura(SPELL_RE_SIZING_2))
|
||||
return;
|
||||
|
||||
me->CastSpell(who, SPELL_WANDERING_BOAR_MOB_CHARGE);
|
||||
}
|
||||
|
||||
// creature shouldn't die at resizing the situation quest otherwise killcredit doubled
|
||||
void DamageTaken(Unit* attacker, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
|
||||
{
|
||||
if (IsResizedBoar())
|
||||
return;
|
||||
|
||||
if (Player* player = attacker->ToPlayer())
|
||||
{
|
||||
if (damage > me->GetHealth() && (player->GetQuestStatus(QUEST_RE_SIZING_THE_SITUATION) == QUEST_STATUS_INCOMPLETE || player->GetQuestStatus(QUEST_H_RE_SIZING_THE_SITUATION) == QUEST_STATUS_INCOMPLETE))
|
||||
@@ -426,32 +497,51 @@ struct npc_exiles_reach_darkmaul_plains_156736_156716 : public ScriptedAI
|
||||
}
|
||||
}
|
||||
|
||||
void IsSummonedBy(WorldObject* summoner) override
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
Player* player = summoner->ToPlayer();
|
||||
if (!player)
|
||||
if (!IsResizedBoar() || type != POINT_MOTION_TYPE || id != POINT_RESIZED_BOAR_CAMP)
|
||||
return;
|
||||
|
||||
me->CastSpell(me, SPELL_GROW_1);
|
||||
me->GetMotionMaster()->MovePoint(0, ResizingTheSituationPositions[0].GetPositionX(), ResizingTheSituationPositions[0].GetPositionY(), ResizingTheSituationPositions[0].GetPositionZ(), true, 0.7f);
|
||||
player->KilledMonsterCredit(156722);
|
||||
me->SetFacingTo(0.785398f);
|
||||
|
||||
if (Creature* springstock = player->GetSummonedCreatureByEntry(NPC_DARKMAUL_PLAINS_SPRINGSTOCK_RESIZING_SUMMON))
|
||||
springstock->GetMotionMaster()->MovePoint(0, ResizingTheSituationPositions[1].GetPositionX(), ResizingTheSituationPositions[1].GetPositionY(), ResizingTheSituationPositions[1].GetPositionZ(), true, 4.f);
|
||||
Unit* summoner = nullptr;
|
||||
if (TempSummon* summoned = me->ToTempSummon())
|
||||
summoner = summoned->GetSummonerUnit();
|
||||
if (!summoner)
|
||||
summoner = me->GetOwner();
|
||||
|
||||
if (Creature* fizzlepop = player->GetSummonedCreatureByEntry(NPC_DARKMAUL_PLAINS_FIZZLEPOP_RESIZING_SUMMON))
|
||||
fizzlepop->GetMotionMaster()->MovePoint(0, ResizingTheSituationPositions[1].GetPositionX(), ResizingTheSituationPositions[1].GetPositionY(), ResizingTheSituationPositions[1].GetPositionZ(), true, 4.f);
|
||||
if (summoner)
|
||||
if (Player* player = summoner->ToPlayer())
|
||||
player->CastSpell(player, SPELL_UPDATE_PHASESHIFT, true);
|
||||
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (timer <= diff)
|
||||
if (IsResizedBoar())
|
||||
{
|
||||
if (me->GetPosition().IsInDist(ResizingTheSituationPositions[0], 1.f))
|
||||
me->DespawnOrUnsummon();
|
||||
_events.Update(diff);
|
||||
|
||||
while (uint32 eventId = _events.ExecuteEvent())
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_RESIZED_BOAR_GROW:
|
||||
me->CastSpell(me, SPELL_GROW_1, true);
|
||||
me->PlayDirectSound(SOUND_RESIZED_BOAR_GROW);
|
||||
_events.ScheduleEvent(EVENT_RESIZED_BOAR_MOVE, 1s);
|
||||
break;
|
||||
case EVENT_RESIZED_BOAR_MOVE:
|
||||
me->SetWalk(false);
|
||||
me->GetMotionMaster()->MovePoint(POINT_RESIZED_BOAR_CAMP, ResizingTheSituationPositions[0]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
timer -= diff;
|
||||
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
@@ -476,8 +566,14 @@ struct npc_exiles_reach_darkmaul_plains_156736_156716 : public ScriptedAI
|
||||
}
|
||||
|
||||
private:
|
||||
enum ResizedBoarEvents
|
||||
{
|
||||
EVENT_RESIZED_BOAR_GROW = 2,
|
||||
EVENT_RESIZED_BOAR_MOVE = 3,
|
||||
POINT_RESIZED_BOAR_CAMP = 1
|
||||
};
|
||||
|
||||
EventMap _events;
|
||||
uint32 timer = 1000;
|
||||
};
|
||||
|
||||
// Lightspawn (Darkmaul Plains)
|
||||
@@ -700,20 +796,6 @@ public:
|
||||
|
||||
class spell_re_sizing_305716_AuraScript : public AuraScript
|
||||
{
|
||||
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
Unit* target = GetUnitOwner();
|
||||
|
||||
if (!caster || !target || !target->IsCreature())
|
||||
return;
|
||||
|
||||
Creature* creature = caster->ToCreature();
|
||||
|
||||
if (creature->GetEntry() != NPC_DARKMAUL_PLAINS_WANDERING_BOAR)
|
||||
return;
|
||||
}
|
||||
|
||||
void HandleRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
@@ -726,34 +808,50 @@ public:
|
||||
if (!player || !creature)
|
||||
return;
|
||||
|
||||
caster->ClearChannelObjects();
|
||||
caster->SetChannelSpellId(0);
|
||||
caster->SetChannelVisual({});
|
||||
// The core ends the channel before this aura is removed. Clearing the channel
|
||||
// fields here used to run while that spell was still finishing.
|
||||
|
||||
uint32 hitVariants[3] = { SPELL_RESIZER_HIT_TOSMALL, SPELL_RESIZER_HIT_EXPLODE, SPELL_RESIZER_OVERCHARGE };
|
||||
uint32 selectedFailedSpell = hitVariants[rand() % 3];
|
||||
// GetQuestStatus is an enum. Any non-zero status, including already turned in, used to count as "on the quest".
|
||||
uint32 questId = 0;
|
||||
if (player->GetQuestStatus(QUEST_RE_SIZING_THE_SITUATION) == QUEST_STATUS_INCOMPLETE)
|
||||
questId = QUEST_RE_SIZING_THE_SITUATION;
|
||||
else if (player->GetQuestStatus(QUEST_H_RE_SIZING_THE_SITUATION) == QUEST_STATUS_INCOMPLETE)
|
||||
questId = QUEST_H_RE_SIZING_THE_SITUATION;
|
||||
|
||||
if (player->GetQuestStatus(QUEST_RE_SIZING_THE_SITUATION) || player->GetQuestStatus(QUEST_H_RE_SIZING_THE_SITUATION))
|
||||
if (!questId || creature->GetEntry() != NPC_DARKMAUL_PLAINS_WANDERING_BOAR)
|
||||
return;
|
||||
|
||||
// 0 shrinks the boar, 1 bursts it, 2 grows the re-sized boar and sends Lindie home.
|
||||
// Despawn is delayed so the aura owner is not deleted inside this hook. The old
|
||||
// immediate despawn, plus a kill credit from the boar script, crashed the worldserver.
|
||||
int32 const tests = player->GetQuestObjectiveProgress(questId, 0);
|
||||
if (tests <= 0)
|
||||
{
|
||||
if (selectedFailedSpell == SPELL_RESIZER_HIT_EXPLODE && QuestAccepted(player, QUEST_H_THE_REDEATHER))
|
||||
PlayExileConversation(player, CONVERSATION_REDEATHER_EXPLODE);
|
||||
|
||||
if (player->GetQuestObjectiveProgress(QUEST_RE_SIZING_THE_SITUATION, 0) < 2)
|
||||
{
|
||||
player->CastSpell(target, selectedFailedSpell, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->CastSpell(target, SPELL_RESIZER_SPARKS_AND_BOAR_SUMMON, true);
|
||||
creature->DespawnOrUnsummon();
|
||||
}
|
||||
player->CastSpell(creature, SPELL_RESIZER_HIT_TOSMALL, true);
|
||||
creature->DespawnOrUnsummon(2s);
|
||||
}
|
||||
else if (tests == 1)
|
||||
{
|
||||
player->CastSpell(creature, SPELL_RESIZER_HIT_EXPLODE, true);
|
||||
creature->DespawnOrUnsummon(2s);
|
||||
}
|
||||
else if (questId == QUEST_H_RE_SIZING_THE_SITUATION)
|
||||
{
|
||||
player->CastSpell(creature, SPELL_RESIZER_OVERCHARGE, true);
|
||||
player->CastSpell(player, SPELL_PING_LINDIE, true);
|
||||
creature->DespawnOrUnsummon(3s);
|
||||
}
|
||||
else
|
||||
{
|
||||
player->CastSpell(creature, SPELL_RESIZER_SPARKS_AND_BOAR_SUMMON, true);
|
||||
player->CastSpell(player, SPELL_PING_LINDIE, true);
|
||||
creature->DespawnOrUnsummon(2s);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectApply += AuraEffectApplyFn(spell_re_sizing_305716_AuraScript::OnApply, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
OnEffectRemove += AuraEffectRemoveFn(spell_re_sizing_305716_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
AfterEffectRemove += AuraEffectRemoveFn(spell_re_sizing_305716_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -764,24 +862,19 @@ public:
|
||||
|
||||
class spell_re_sizing_305716_SpellScript : public SpellScript
|
||||
{
|
||||
void HandleCast()
|
||||
SpellCastResult CheckCast()
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
Unit* target = GetExplTargetUnit();
|
||||
Creature* creature = target ? target->ToCreature() : nullptr;
|
||||
if (!creature || creature->GetEntry() != NPC_DARKMAUL_PLAINS_WANDERING_BOAR)
|
||||
return SPELL_FAILED_BAD_TARGETS;
|
||||
|
||||
if (!caster || !target || !target->IsCreature())
|
||||
return;
|
||||
|
||||
Creature* creature = target->ToCreature();
|
||||
if (creature->GetEntry() != NPC_DARKMAUL_PLAINS_WANDERING_BOAR)
|
||||
return;
|
||||
|
||||
GetSpell()->SendChannelStart(3000);
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnCast += SpellCastFn(spell_re_sizing_305716_SpellScript::HandleCast);
|
||||
OnCheckCast += SpellCheckCastFn(spell_re_sizing_305716_SpellScript::CheckCast);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -929,6 +1022,100 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
void ChargeGiantBoar(Unit* mover)
|
||||
{
|
||||
if (!mover)
|
||||
return;
|
||||
|
||||
Position dest = mover->GetFirstCollisionPosition(20.0f, 0.0f);
|
||||
mover->GetMotionMaster()->MoveCharge(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ());
|
||||
}
|
||||
|
||||
// Trample is what the vehicle button casts. Cadavers only count when this runs.
|
||||
void TrampleUndeadInFront(Player* player, Unit* boar)
|
||||
{
|
||||
if (!player || !boar || player->GetMapId() != MAP_EXILES_REACH)
|
||||
return;
|
||||
|
||||
uint32 const questId = ExileUsesHorde(player) ? QUEST_H_THE_REDEATHER : QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR;
|
||||
if (player->GetQuestStatus(questId) != QUEST_STATUS_INCOMPLETE)
|
||||
return;
|
||||
|
||||
ChargeGiantBoar(boar);
|
||||
|
||||
std::list<Creature*> undead;
|
||||
player->GetCreatureListWithEntryInGrid(undead, NPC_OGRE_RUINS_MONSTROUS_CADAVER, 25.0f);
|
||||
player->GetCreatureListWithEntryInGrid(undead, NPC_OGRE_RUINS_ZOMBIE_SERVANT, 25.0f);
|
||||
|
||||
for (Creature* creature : undead)
|
||||
{
|
||||
if (!creature || !creature->IsAlive() || !player->CanSeeOrDetect(creature))
|
||||
continue;
|
||||
|
||||
bool const inFront = boar->HasInArc(3.14159265f, creature);
|
||||
bool const pointBlank = boar->IsWithinDist(creature, 10.0f);
|
||||
if (!inFront && !pointBlank)
|
||||
continue;
|
||||
|
||||
if (creature->GetEntry() == NPC_OGRE_RUINS_MONSTROUS_CADAVER)
|
||||
{
|
||||
uint32 const before = player->GetQuestObjectiveProgress(questId, 2);
|
||||
Unit::Kill(player, creature);
|
||||
if (before < 8 && player->GetQuestObjectiveProgress(questId, 2) == before)
|
||||
player->CastSpell(player, SPELL_CADAVER_KILL_CREDIT, true);
|
||||
}
|
||||
else
|
||||
Unit::Kill(player, creature);
|
||||
}
|
||||
|
||||
if (player->GetQuestObjectiveProgress(questId, 2) >= 8)
|
||||
player->CastSpell(player, SPELL_GIANT_BOAR_PING_VEHICLE, true);
|
||||
}
|
||||
}
|
||||
|
||||
// ID - 305557 Trample
|
||||
class spell_giant_boar_trample_305557 : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_giant_boar_trample_305557() : SpellScriptLoader("spell_giant_boar_trample_305557") {}
|
||||
|
||||
class spell_giant_boar_trample_305557_SpellScript : public SpellScript
|
||||
{
|
||||
void HandleOnCast()
|
||||
{
|
||||
Unit* caster = GetCaster();
|
||||
if (!caster)
|
||||
return;
|
||||
|
||||
Player* player = caster->ToPlayer();
|
||||
if (!player)
|
||||
player = caster->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
Unit* boar = player->GetVehicleBase();
|
||||
if (!boar)
|
||||
boar = caster->GetVehicleBase();
|
||||
if (!boar)
|
||||
boar = caster;
|
||||
|
||||
TrampleUndeadInFront(player, boar);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnCast += SpellCastFn(spell_giant_boar_trample_305557_SpellScript::HandleOnCast);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_giant_boar_trample_305557_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
// ID - 321627 Charge
|
||||
class spell_giant_boar_charge_321627 : public SpellScriptLoader
|
||||
{
|
||||
@@ -941,12 +1128,23 @@ public:
|
||||
{
|
||||
PreventHitDefaultEffect(effIndex);
|
||||
|
||||
WorldLocation const* loc = GetExplTargetDest();
|
||||
Unit* caster = GetCaster();
|
||||
if (!caster)
|
||||
return;
|
||||
|
||||
caster->GetMotionMaster()->MoveCharge(loc->GetPositionX(), loc->GetPositionY(), loc->GetPositionZ());
|
||||
// The button is cast by the rider. Charging the rider left the boar in place.
|
||||
Unit* boar = caster->GetVehicleBase();
|
||||
if (!boar)
|
||||
boar = caster;
|
||||
|
||||
Player* player = caster->ToPlayer();
|
||||
if (!player)
|
||||
player = boar->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
|
||||
if (player)
|
||||
TrampleUndeadInFront(player, boar);
|
||||
else
|
||||
ChargeGiantBoar(boar);
|
||||
}
|
||||
|
||||
void Register()
|
||||
@@ -1069,6 +1267,7 @@ void AddSC_exiles_reach_darkmaul_plains()
|
||||
new spell_resizer_hit_305742();
|
||||
new spell_riding_giant_boar_305068();
|
||||
new spell_ride_vehicle_173426();
|
||||
new spell_giant_boar_trample_305557();
|
||||
new spell_giant_boar_charge_321627();
|
||||
new spell_giant_boar_ping_vehicle_305559();
|
||||
}
|
||||
|
||||
@@ -623,7 +623,8 @@ struct go_exiles_reach_harpy_roost_350803_327146 : public GameObjectAI
|
||||
|
||||
bool OnGossipHello(Player* player) override
|
||||
{
|
||||
if (player->GetQuestStatus(QUEST_H_PURGE_THE_TOTEMS) || player->GetQuestStatus(QUEST_PURGE_THE_TOTEMS))
|
||||
if (player->GetQuestStatus(QUEST_H_PURGE_THE_TOTEMS) == QUEST_STATUS_INCOMPLETE
|
||||
|| player->GetQuestStatus(QUEST_PURGE_THE_TOTEMS) == QUEST_STATUS_INCOMPLETE)
|
||||
{
|
||||
if (Creature* burningTotem = player->SummonCreature(NPC_HARPY_ROOST_BURNING_TOTEM, me->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0U, 0U, player->GetGUID()))
|
||||
{
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
|
||||
if (player->IsInHorde())
|
||||
{
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, !player->HasAura(SPELL_RESIZER_SLAUGHTER) && !player->GetVehicle() && !player->GetQuestStatus(QUEST_H_THE_REDEATHER));
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, !player->HasAura(SPELL_RESIZER_SLAUGHTER) && !QuestCompletedOrRewarded(player, QUEST_H_THE_REDEATHER));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_OGRE_RUINS_SHUJA_RITUAL }, QuestsRewarded(player, { QUEST_H_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_H_DOWN_WITH_THE_QUILBOAR }) && !QuestCompletedOrRewarded(player, QUEST_H_THE_REDEATHER));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_OGRE_RUINS_SHUJA_QUEST_REWARDER }, QuestCompleted(player, QUEST_H_THE_REDEATHER));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_OGRE_RUINS_CAMP_OBJECTS }, QuestCompletedOrRewarded(player, QUEST_H_THE_REDEATHER));
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
|
||||
if (player->IsInAlliance())
|
||||
{
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !player->HasAura(SPELL_RIDING_GIANT_BOAR) && !player->GetQuestStatus(QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !QuestCompletedOrRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_OGRE_RUINS_HENRY_RITUAL }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !QuestCompletedOrRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_HRUNS_BARROW_RALIA_RITUAL }, QuestCompleted(player, QUEST_THE_SCOUT_O_MATIC_5000));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_OGRE_RUINS_13395 }, QuestCompleted(player, QUEST_THE_SCOUT_O_MATIC_5000));
|
||||
@@ -163,10 +163,10 @@ public:
|
||||
if (!player)
|
||||
continue;
|
||||
|
||||
if (player->GetQuestStatus(QUEST_WHO_LURKS_IN_THE_PIT))
|
||||
if (player->GetQuestStatus(QUEST_WHO_LURKS_IN_THE_PIT) == QUEST_STATUS_INCOMPLETE)
|
||||
player->SummonCreature(NPC_HRUNS_BARROW_RALIA_TRAVEL_FORM, RescuedFromHrun, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0U, 0U, player->GetGUID());
|
||||
|
||||
if (player->GetQuestStatus(QUEST_H_WHO_LURKS_IN_THE_PIT))
|
||||
if (player->GetQuestStatus(QUEST_H_WHO_LURKS_IN_THE_PIT) == QUEST_STATUS_INCOMPLETE)
|
||||
player->SummonCreature(NPC_HRUNS_BARROW_CRENNA_TRAVEL_FORM, RescuedFromHrun, TEMPSUMMON_MANUAL_DESPAWN, 0s, 0U, 0U, player->GetGUID());
|
||||
|
||||
if (player->HasAura(SPELL_RITUAL_SCENE_HRUN_BEAM))
|
||||
@@ -350,7 +350,7 @@ struct go_exiles_reach_hruns_barrow_339568_350796 : public GameObjectAI
|
||||
bool OnGossipHello(Player* player) override
|
||||
{
|
||||
// horde
|
||||
if (player->GetQuestStatus(QUEST_H_WHO_LURKS_IN_THE_PIT))
|
||||
if (player->GetQuestStatus(QUEST_H_WHO_LURKS_IN_THE_PIT) == QUEST_STATUS_INCOMPLETE)
|
||||
{
|
||||
player->KillCreditGO(GAMEOBJECT_THICK_COCOON_H);
|
||||
player->CastSpell(player, SPELL_FREED_EXPEDITION_MEMBER_H, true);
|
||||
@@ -359,7 +359,7 @@ struct go_exiles_reach_hruns_barrow_339568_350796 : public GameObjectAI
|
||||
}
|
||||
|
||||
// alli
|
||||
if (player->GetQuestStatus(QUEST_WHO_LURKS_IN_THE_PIT))
|
||||
if (player->GetQuestStatus(QUEST_WHO_LURKS_IN_THE_PIT) == QUEST_STATUS_INCOMPLETE)
|
||||
{
|
||||
player->KillCreditGO(GAMEOBJECT_THICK_COCOON_A);
|
||||
player->CastSpell(player, SPELL_FREED_EXPEDITION_MEMBER_A, true);
|
||||
|
||||
@@ -23,6 +23,31 @@
|
||||
|
||||
#include "exiles_reach.h"
|
||||
|
||||
void ArriveExileBeach(Player* player)
|
||||
{
|
||||
if (!player || !player->IsInWorld() || player->GetMapId() != MAP_EXILES_REACH)
|
||||
return;
|
||||
|
||||
if (player->HasAura(SPELL_KNOCKED_DOWN))
|
||||
return;
|
||||
|
||||
uint32 const area = player->GetAreaId();
|
||||
if (area != AREA_NORTH_SEA_A && area != AREA_NORTH_SEA_H && area != AREA_MURLOC_HIDEAWAY)
|
||||
return;
|
||||
|
||||
if (area == AREA_NORTH_SEA_A || area == AREA_NORTH_SEA_H)
|
||||
{
|
||||
player->TeleportTo(MAP_EXILES_REACH, -462.722f, -2620.544f, 0.472f, 0.760f);
|
||||
player->CastSpell(player, player->IsInHorde() ? SPELL_H_SHIP_CRASH : SPELL_A_SHIP_CRASH, true);
|
||||
}
|
||||
|
||||
player->GetSceneMgr().PlaySceneByPackageId(SCENE_ALI_HORDE_CRASHED_ON_ISLAND, SceneFlag::NotCancelable);
|
||||
if (player->HasAura(SPELL_HEAVY_FOG_AND_RAIN))
|
||||
player->RemoveAura(SPELL_HEAVY_FOG_AND_RAIN);
|
||||
player->CastSpell(player, SPELL_MEDIUM_FOG_AND_RAIN, true);
|
||||
player->CastSpell(player, SPELL_KNOCKED_DOWN, true);
|
||||
}
|
||||
|
||||
class exiles_reach_murloc_hideaway_playerscript : public PlayerScript
|
||||
{
|
||||
public:
|
||||
@@ -31,21 +56,39 @@ public:
|
||||
// after the ship crash movie play the tiny murloc scene
|
||||
void OnMovieComplete(Player* player, uint32 movieId) override
|
||||
{
|
||||
if (movieId == 931 || movieId == 895)
|
||||
{
|
||||
player->GetSceneMgr().PlaySceneByPackageId(SCENE_ALI_HORDE_CRASHED_ON_ISLAND, SceneFlag::NotCancelable);
|
||||
if (player->HasAura(SPELL_HEAVY_FOG_AND_RAIN))
|
||||
player->RemoveAura(SPELL_HEAVY_FOG_AND_RAIN);
|
||||
player->CastSpell(player, SPELL_MEDIUM_FOG_AND_RAIN, true);
|
||||
player->CastSpell(player, SPELL_KNOCKED_DOWN, true);
|
||||
}
|
||||
if (movieId == MOVIE_HORDE_SHIP_CRASH || movieId == MOVIE_ALLIANCE_SHIP_CRASH)
|
||||
ArriveExileBeach(player);
|
||||
}
|
||||
|
||||
void CheckExilesReachPhaseShift(Player* player)
|
||||
{
|
||||
if (player->GetMapId() == MAP_EXILES_REACH)
|
||||
{
|
||||
switch (player->GetAreaId())
|
||||
uint32 const area = player->GetAreaId();
|
||||
if (area != AREA_MURLOC_HIDEAWAY)
|
||||
{
|
||||
// These turn on after Murloc Mania and were never removed. Three of them stay
|
||||
// up together, so the same camp creatures (and the untargetable triggers in
|
||||
// those phases) are drawn again at the Abandoned Camp and on Darkmaul Plains.
|
||||
uint32 const shorePhases[] =
|
||||
{
|
||||
PHASE_GENERAL_SHORE,
|
||||
PHASE_ALLIANCE_SHORE_GARRICK_AND_FRIENDS_INJURED,
|
||||
PHASE_ALLIANCE_SHORE_GARRICK_AND_FRIENDS_HEALED,
|
||||
PHASE_ALLIANCE_SHORE_12940,
|
||||
PHASE_ALLIANCE_SHORE_13157,
|
||||
PHASE_ALLIANCE_SHORE_13503,
|
||||
PHASE_HORDE_SHORE_BREKA_AND_FRIENDS_INJURED,
|
||||
PHASE_HORDE_SHORE_BREKA_AND_FRIENDS_HEALED,
|
||||
};
|
||||
|
||||
for (uint32 phaseId : shorePhases)
|
||||
if (player->GetPhaseShift().HasPhase(phaseId))
|
||||
PhasingHandler::RemovePhase(player, phaseId, true);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (area)
|
||||
{
|
||||
case AREA_MURLOC_HIDEAWAY:
|
||||
{
|
||||
@@ -53,15 +96,14 @@ public:
|
||||
|
||||
if (player->IsInHorde())
|
||||
{
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_SHORE_BREKA_AND_FRIENDS_INJURED }, !player->GetQuestStatus(QUEST_H_EMERGENCY_FIRST_AID));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_SHORE_BREKA_AND_FRIENDS_INJURED }, !QuestRewarded(player, QUEST_H_EMERGENCY_FIRST_AID));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_SHORE_BREKA_AND_FRIENDS_HEALED }, QuestRewarded(player, QUEST_H_EMERGENCY_FIRST_AID) && !QuestAccepted(player, QUEST_H_FINDING_THE_LOST_EXPEDITION) && !player->GetSummonedCreatureByEntry(NPC_MURLOC_HIDEAWAY_BREKA));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_ABANDONED_CAMP_WONSA_STARVING }, !player->GetSummonedCreatureByEntry(NPC_MURLOC_HIDEAWAY_BREKA));
|
||||
}
|
||||
|
||||
if (player->IsInAlliance())
|
||||
{
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_SHORE_GARRICK_AND_FRIENDS_INJURED }, !player->GetQuestStatus(QUEST_EMERGENCY_FIRST_AID));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_SHIP_13619 }, !QuestAccepted(player, QUEST_MURLOC_MANIA));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_SHORE_GARRICK_AND_FRIENDS_INJURED }, !QuestRewarded(player, QUEST_EMERGENCY_FIRST_AID));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_SHORE_GARRICK_AND_FRIENDS_HEALED }, QuestRewarded(player, QUEST_EMERGENCY_FIRST_AID) && !QuestAccepted(player, QUEST_FINDING_THE_LOST_EXPEDITION) && !player->GetSummonedCreatureByEntry(NPC_MURLOC_HIDEAWAY_GARRICK));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_SHORE_12940, PHASE_ALLIANCE_SHORE_13157, PHASE_ALLIANCE_SHORE_13503 }, QuestRewarded(player, QUEST_MURLOC_MANIA));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_ABANDONED_CAMP_ALARIA_STARVING }, !player->GetSummonedCreatureByEntry(NPC_MURLOC_HIDEAWAY_GARRICK));
|
||||
@@ -172,7 +214,8 @@ struct npc_exiles_reach_shore_166782_156626 : public ScriptedAI
|
||||
std::list<Creature*> nearbyCreatures;
|
||||
player->GetCreatureListInGrid(nearbyCreatures, 200.f);
|
||||
|
||||
if (Creature* captainClone = player->SummonCreature(me->GetEntry(), me->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0U, 0U, player->GetGUID()))
|
||||
// Personal clone replaces the world copy for this player. A plain summon left both visible.
|
||||
if (Creature* captainClone = me->SummonPersonalClone(me->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player))
|
||||
{
|
||||
for (Creature* subactor : nearbyCreatures)
|
||||
{
|
||||
@@ -188,10 +231,8 @@ struct npc_exiles_reach_shore_166782_156626 : public ScriptedAI
|
||||
case NPC_MURLOC_HIDEAWAY_JINHAKE:
|
||||
case NPC_MURLOC_HIDEAWAY_COLE:
|
||||
case NPC_MURLOC_HIDEAWAY_RICHTER:
|
||||
if (Creature* clone = player->SummonCreature(subactor->GetEntry(), subactor->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0U, 0U, player->GetGUID()))
|
||||
if (Creature* clone = subactor->SummonPersonalClone(subactor->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player))
|
||||
{
|
||||
PhasingHandler::InheritPhaseShift(clone, player);
|
||||
|
||||
if (clone->GetEntry() == NPC_MURLOC_HIDEAWAY_COLE || clone->GetEntry() == NPC_MURLOC_HIDEAWAY_THROG)
|
||||
captainClone->m_Events.AddEventAtOffset(new FirstAidEvent(captainClone, clone), 2s);
|
||||
|
||||
@@ -222,7 +263,7 @@ struct npc_exiles_reach_shore_166782_156626 : public ScriptedAI
|
||||
case NPC_MURLOC_HIDEAWAY_KEELA_2:
|
||||
case NPC_MURLOC_HIDEAWAY_AUSTIN_2:
|
||||
case NPC_MURLOC_HIDEAWAY_BJORN_2:
|
||||
if (Creature* clone = player->SummonCreature(buddy->GetEntry(), buddy->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0U, 0U, player->GetGUID()))
|
||||
if (Creature* clone = buddy->SummonPersonalClone(buddy->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player))
|
||||
{
|
||||
clone->SetStandState(UNIT_STAND_STATE_STAND);
|
||||
clone->m_Events.AddEventAtOffset(new DelayedMoveEvent(player, clone, Position(-385.65f, -2594.42f, 3.2135f), 0, false, true), 3s);
|
||||
@@ -230,10 +271,9 @@ struct npc_exiles_reach_shore_166782_156626 : public ScriptedAI
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Creature* clone = player->SummonCreature(me->GetEntry(), me->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0U, 0U, player->GetGUID()))
|
||||
if (Creature* clone = me->SummonPersonalClone(me->GetPosition(), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0, 0, player))
|
||||
{
|
||||
clone->CastSpell(player, SPELL_UPDATE_PHASESHIFT);
|
||||
PhasingHandler::InheritPhaseShift(clone, player);
|
||||
|
||||
clone->FollowTarget(player);
|
||||
PlayExileConversation(player, player->IsInAlliance() ? CONVERSATION_ESCORT_SURVIVOR_A : CONVERSATION_ESCORT_SURVIVOR_H);
|
||||
@@ -283,6 +323,7 @@ struct npc_exiles_reach_shore_injured_buddie : public ScriptedAI
|
||||
{
|
||||
npc_exiles_reach_shore_injured_buddie(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
me->SetUninteractible(false);
|
||||
if (me->GetPhaseShift().HasPhase(PHASE_ALLIANCE_SHORE_GARRICK_AND_FRIENDS_INJURED) || me->GetPhaseShift().HasPhase(PHASE_HORDE_SHORE_BREKA_AND_FRIENDS_INJURED))
|
||||
me->SetEmoteState(EMOTE_ONESHOT_SLEEP);
|
||||
}
|
||||
@@ -338,7 +379,10 @@ struct npc_exiles_reach_shore_injured_buddie : public ScriptedAI
|
||||
// Throg 166784, Jin'Hake 166800, Cole 149917, Richter 156622 (murloc hideaway)
|
||||
struct npc_exiles_reach_shore_other_two_injured : public ScriptedAI
|
||||
{
|
||||
npc_exiles_reach_shore_other_two_injured(Creature* creature) : ScriptedAI(creature) {}
|
||||
npc_exiles_reach_shore_other_two_injured(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
me->SetUninteractible(false);
|
||||
}
|
||||
|
||||
void SpellHit(WorldObject* /*caster*/, SpellInfo const* spell) override
|
||||
{
|
||||
|
||||
@@ -29,40 +29,40 @@ class exiles_reach_north_sea_playerscript : public PlayerScript
|
||||
public:
|
||||
exiles_reach_north_sea_playerscript() : PlayerScript("exiles_reach_north_sea_playerscript") {}
|
||||
|
||||
void GiveExileShipIntroQuest(Player* player)
|
||||
{
|
||||
uint32 const questId = player->IsInHorde() ? QUEST_H_WARMING_UP : QUEST_WARMING_UP;
|
||||
if (player->GetQuestStatus(questId) != QUEST_STATUS_NONE)
|
||||
return;
|
||||
|
||||
uint32 const laterQuests[] =
|
||||
{
|
||||
player->IsInHorde() ? QUEST_H_STAND_YOUR_GROUND : QUEST_STAND_YOUR_GROUND,
|
||||
player->IsInHorde() ? QUEST_H_BRACE_FOR_IMPACT : QUEST_BRACE_FOR_IMPACT,
|
||||
player->IsInHorde() ? QUEST_H_MURLOC_MANIA : QUEST_MURLOC_MANIA,
|
||||
player->IsInHorde() ? QUEST_H_AN_END_TO_BEGINNINGS : QUEST_AN_END_TO_BEGINNINGS,
|
||||
};
|
||||
|
||||
for (uint32 laterQuestId : laterQuests)
|
||||
if (player->GetQuestStatus(laterQuestId) != QUEST_STATUS_NONE)
|
||||
return;
|
||||
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||
if (!quest || !player->CanTakeQuest(quest, false) || !player->CanAddQuest(quest, false))
|
||||
return;
|
||||
|
||||
player->AddQuestAndCheckCompletion(quest, nullptr);
|
||||
}
|
||||
|
||||
void CheckExilesReachPhaseShift(Player* player)
|
||||
{
|
||||
// A new character has no quest yet. Hand out Warming Up before the phase
|
||||
// update so the ship quest giver and the combat dummy stay visible.
|
||||
GiveExileShipIntroQuest(player);
|
||||
|
||||
if (player->GetMapId() == MAP_EXILES_REACH)
|
||||
{
|
||||
switch (player->GetAreaId())
|
||||
uint32 const area = player->GetAreaId();
|
||||
if (area != AREA_NORTH_SEA_A && area != AREA_NORTH_SEA_H)
|
||||
{
|
||||
// The deck phases are only updated while the player is still on the ship.
|
||||
// Leaving them on shows Jaina (and the Horde officers) a second time on the beach.
|
||||
uint32 const shipPhases[] =
|
||||
{
|
||||
PHASE_GENERAL_SHIP,
|
||||
PHASE_ALLIANCE_SHIP_CREW_OUTSIDE,
|
||||
PHASE_ALLIANCE_SHIP_COLE,
|
||||
PHASE_ALLIANCE_SHIP_GARRICK_1,
|
||||
PHASE_ALLIANCE_SHIP_13619,
|
||||
PHASE_ALLIANCE_SHIP_14350,
|
||||
PHASE_ALLIANCE_SHIP_13454,
|
||||
PHASE_ALLIANCE_SHIP_GARRICK_2,
|
||||
PHASE_ALLIANCE_SHIP_CREW_INSIDE,
|
||||
PHASE_HORDE_SHIP_THROG,
|
||||
PHASE_HORDE_SHIP_15514,
|
||||
PHASE_HORDE_SHIP_15287,
|
||||
PHASE_HORDE_SHIP_15516,
|
||||
};
|
||||
|
||||
for (uint32 phaseId : shipPhases)
|
||||
if (player->GetPhaseShift().HasPhase(phaseId))
|
||||
PhasingHandler::RemovePhase(player, phaseId, true);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (area)
|
||||
{
|
||||
case AREA_NORTH_SEA_H:
|
||||
{
|
||||
@@ -72,8 +72,8 @@ public:
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_SHIP }, true);
|
||||
if (player->IsInHorde())
|
||||
{
|
||||
// PhaseShift no longer removes phases. Drop the Alliance ship
|
||||
// phases here so a Horde character does not keep Jaina's crew.
|
||||
// A Horde character must not keep Jaina's crew. These phases are
|
||||
// only added for Alliance, so dropping them here is safe.
|
||||
uint32 const allianceShipPhases[] =
|
||||
{
|
||||
PHASE_ALLIANCE_SHIP_COLE,
|
||||
@@ -89,8 +89,8 @@ public:
|
||||
if (player->GetPhaseShift().HasPhase(phaseId))
|
||||
PhasingHandler::RemovePhase(player, phaseId, true);
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_SHIP_15514 }, !QuestRewarded(player, QUEST_H_WARMING_UP));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_SHIP_THROG }, !QuestAccepted(player, QUEST_H_STAND_YOUR_GROUND) && !QuestCompleted(player, QUEST_H_BRACE_FOR_IMPACT));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_SHIP_15287 }, QuestRewarded(player, QUEST_H_WARMING_UP) && !QuestCompleted(player, QUEST_H_BRACE_FOR_IMPACT));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_SHIP_THROG }, !QuestAccepted(player, QUEST_H_STAND_YOUR_GROUND) && !QuestCompletedOrRewarded(player, QUEST_H_BRACE_FOR_IMPACT));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_SHIP_15287 }, QuestRewarded(player, QUEST_H_WARMING_UP) && !QuestCompletedOrRewarded(player, QUEST_H_BRACE_FOR_IMPACT));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_SHIP_15516 }, QuestAcceptedOrCompleted(player, QUEST_H_BRACE_FOR_IMPACT));
|
||||
}
|
||||
}
|
||||
@@ -100,11 +100,11 @@ public:
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_SHIP }, true);
|
||||
if (player->IsInAlliance())
|
||||
{
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_SHIP_COLE }, !QuestAccepted(player, QUEST_STAND_YOUR_GROUND) && !QuestCompleted(player, QUEST_BRACE_FOR_IMPACT));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_SHIP_13619 }, QuestRewarded(player, QUEST_WARMING_UP) && !QuestAccepted(player, QUEST_STAND_YOUR_GROUND));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_SHIP_14350 }, QuestRewarded(player, QUEST_WARMING_UP) && !QuestCompleted(player, QUEST_BRACE_FOR_IMPACT));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_SHIP_COLE }, !QuestAccepted(player, QUEST_STAND_YOUR_GROUND) && !QuestCompletedOrRewarded(player, QUEST_BRACE_FOR_IMPACT));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_SHIP_13619 }, QuestRewarded(player, QUEST_WARMING_UP) && player->GetQuestStatus(QUEST_STAND_YOUR_GROUND) == QUEST_STATUS_NONE && !QuestCompletedOrRewarded(player, QUEST_BRACE_FOR_IMPACT));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_SHIP_14350 }, QuestRewarded(player, QUEST_WARMING_UP) && !QuestCompletedOrRewarded(player, QUEST_BRACE_FOR_IMPACT));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_SHIP_GARRICK_1 }, !QuestRewarded(player, QUEST_WARMING_UP));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_SHIP_CREW_OUTSIDE }, !QuestCompleted(player, QUEST_BRACE_FOR_IMPACT));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_SHIP_CREW_OUTSIDE }, !QuestCompletedOrRewarded(player, QUEST_BRACE_FOR_IMPACT));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_SHIP_GARRICK_2, PHASE_ALLIANCE_SHIP_CREW_INSIDE }, QuestCompleted(player, QUEST_BRACE_FOR_IMPACT));
|
||||
}
|
||||
}
|
||||
@@ -170,6 +170,14 @@ struct npc_exiles_reach_ship_166573_156280 : public ScriptedAI
|
||||
case QUEST_H_WARMING_UP:
|
||||
// Conversation 12818 is played from the quest-status script.
|
||||
break;
|
||||
case QUEST_BRACE_FOR_IMPACT:
|
||||
player->CastSpell(player, SPELL_HEAVY_FOG_AND_RAIN, true);
|
||||
Talk(4, player); // Everyone below decks! Now
|
||||
break;
|
||||
case QUEST_H_BRACE_FOR_IMPACT:
|
||||
player->CastSpell(player, SPELL_HEAVY_FOG_AND_RAIN, true);
|
||||
Talk(4, player); // Soldiers, brace yourselves!
|
||||
break;
|
||||
case QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR:
|
||||
if (Creature* clone = player->SummonCreature(NPC_OGRE_RUINS_TORGOK_FIGHTER_A, FindSummonPosition(player, NPC_DARKMAUL_PLAINS_GARRICK), TEMPSUMMON_MANUAL_DESPAWN, 0s, 0U, 0U, player->GetGUID()))
|
||||
clone->FollowTarget(player);
|
||||
@@ -186,13 +194,13 @@ struct npc_exiles_reach_ship_166573_156280 : public ScriptedAI
|
||||
// Completion conversation 12798 is played from the quest-status script.
|
||||
break;
|
||||
case QUEST_BRACE_FOR_IMPACT:
|
||||
player->TeleportTo(2175, -462.722f, -2620.544f, 0.472f, 0.760f);
|
||||
player->CastSpell(player, SPELL_A_SHIP_CRASH);
|
||||
break;
|
||||
case QUEST_H_BRACE_FOR_IMPACT:
|
||||
player->TeleportTo(2175, -462.722f, -2620.544f, 0.472f, 0.760f);
|
||||
player->CastSpell(player, SPELL_H_SHIP_CRASH);
|
||||
player->RemoveAllAuras();
|
||||
player->SendMovieStart(player->IsInHorde() ? MOVIE_HORDE_SHIP_CRASH : MOVIE_ALLIANCE_SHIP_CRASH);
|
||||
// If the client never finishes the movie, still put them on the beach.
|
||||
player->GetScheduler().Schedule(120s, [player](TaskContext /*context*/)
|
||||
{
|
||||
ArriveExileBeach(player);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -221,18 +229,48 @@ private:
|
||||
};
|
||||
|
||||
// Training Dummy - 160737,
|
||||
static void GrantWarmingUpDummyCredit(Player* player, Creature* dummy)
|
||||
{
|
||||
if (!player || !dummy)
|
||||
return;
|
||||
|
||||
uint32 const questId = player->IsInHorde() ? QUEST_H_WARMING_UP : QUEST_WARMING_UP;
|
||||
if (player->GetQuestStatus(questId) != QUEST_STATUS_INCOMPLETE)
|
||||
return;
|
||||
|
||||
player->KilledMonsterCredit(dummy->GetEntry(), dummy->GetGUID());
|
||||
|
||||
Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
|
||||
if (!quest)
|
||||
return;
|
||||
|
||||
for (QuestObjective const& obj : quest->GetObjectives())
|
||||
if (obj.Type == QUEST_OBJECTIVE_MONSTER && uint32(obj.ObjectID) != dummy->GetEntry())
|
||||
player->KilledMonsterCredit(uint32(obj.ObjectID));
|
||||
}
|
||||
|
||||
struct npc_exiles_reach_ship_training_dummy : public ScriptedAI
|
||||
{
|
||||
npc_exiles_reach_ship_training_dummy(Creature* creature) : ScriptedAI(creature) {}
|
||||
|
||||
void JustDied(Unit* killer /*killer*/) override
|
||||
void SpellHit(WorldObject* caster, SpellInfo const* spell) override
|
||||
{
|
||||
Player* player = killer->ToPlayer();
|
||||
if (!player)
|
||||
if (!caster || !spell || spell->IsPositive())
|
||||
return;
|
||||
|
||||
if (player->GetQuestStatus(QUEST_H_WARMING_UP) || player->GetQuestStatus(QUEST_WARMING_UP))
|
||||
player->CastSpell(player, SPELL_MEDIUM_FOG_AND_RAIN, true);
|
||||
Unit* unit = caster->ToUnit();
|
||||
if (!unit)
|
||||
return;
|
||||
|
||||
GrantWarmingUpDummyCredit(unit->GetCharmerOrOwnerPlayerOrPlayerItself(), me);
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override
|
||||
{
|
||||
if (!killer)
|
||||
return;
|
||||
|
||||
GrantWarmingUpDummyCredit(killer->GetCharmerOrOwnerPlayerOrPlayerItself(), me);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -241,6 +279,8 @@ struct npc_exiles_reach_ship_166583_160664 : public ScriptedAI
|
||||
{
|
||||
npc_exiles_reach_ship_166583_160664(Creature* creature) : ScriptedAI(creature) {}
|
||||
|
||||
bool _jumpedBehind = false;
|
||||
|
||||
void BeFriendly()
|
||||
{
|
||||
me->AttackStop();
|
||||
@@ -311,10 +351,12 @@ struct npc_exiles_reach_ship_166583_160664 : public ScriptedAI
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
if (damage > me->GetHealth())
|
||||
if (damage >= me->GetHealth())
|
||||
{
|
||||
damage = 0;
|
||||
me->SetFullHealth();
|
||||
me->SetHealth(1);
|
||||
me->SetImmuneToPC(true);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->SetFaction(35);
|
||||
me->AttackStop();
|
||||
player->KilledMonsterCredit(155607);
|
||||
@@ -327,8 +369,11 @@ struct npc_exiles_reach_ship_166583_160664 : public ScriptedAI
|
||||
me->DespawnOrUnsummon();
|
||||
});
|
||||
}
|
||||
else
|
||||
else if (!_jumpedBehind && (me->GetHealth() - damage) < uint32(me->GetMaxHealth() * 0.65f))
|
||||
{
|
||||
_jumpedBehind = true;
|
||||
me->CastSpell(player, SPELL_JUMP_BEHIND, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
return;
|
||||
|
||||
// tele to the scene position after reunion scene
|
||||
if (sceneTemplate->SceneId == SCENE_REUNION)
|
||||
if (sceneTemplate->SceneId == SCENE_REUNION || sceneTemplate->SceneId == SCENE_REUNION_ALLIANCE)
|
||||
{
|
||||
player->CastSpell(player, SPELL_TELEPORT_AFTER_REUNION_SCENE, true);
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
|
||||
if (player->IsInHorde())
|
||||
{
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, !player->HasAura(SPELL_RESIZER_SLAUGHTER) && !player->HasAura(SPELL_RIDING_GIANT_BOAR) && !player->GetQuestStatus(QUEST_H_THE_REDEATHER));
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, !player->HasAura(SPELL_RESIZER_SLAUGHTER) && !QuestCompletedOrRewarded(player, QUEST_H_THE_REDEATHER));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_OGRE_RUINS_SHUJA_RITUAL }, QuestsRewarded(player, { QUEST_H_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_H_DOWN_WITH_THE_QUILBOAR }) && !QuestCompletedOrRewarded(player, QUEST_H_THE_REDEATHER));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_OGRE_RUINS_SHUJA_QUEST_REWARDER }, QuestCompleted(player, QUEST_H_THE_REDEATHER));
|
||||
WowCommunity::PhaseShift(player, { PHASE_HORDE_OGRE_RUINS_CAMP_OBJECTS }, QuestCompletedOrRewarded(player, QUEST_H_THE_REDEATHER));
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
|
||||
if (player->IsInAlliance())
|
||||
{
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !player->HasAura(SPELL_RIDING_GIANT_BOAR) && !player->GetQuestStatus(QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
|
||||
WowCommunity::PhaseShift(player, { PHASE_GENERAL_DARKMAUL_PLAINS_ZOMBIES_AND_CADAVERS }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !QuestCompletedOrRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_OGRE_RUINS_HENRY_RITUAL }, QuestsRewarded(player, { QUEST_FORBIDDEN_QUILBOAR_NECROMANCY, QUEST_DOWN_WITH_THE_QUILBOAR }) && !QuestCompletedOrRewarded(player, QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_HRUNS_BARROW_RALIA_RITUAL }, QuestCompleted(player, QUEST_THE_SCOUT_O_MATIC_5000));
|
||||
WowCommunity::PhaseShift(player, { PHASE_ALLIANCE_OGRE_RUINS_13395 }, QuestCompleted(player, QUEST_THE_SCOUT_O_MATIC_5000));
|
||||
@@ -125,6 +125,15 @@ public:
|
||||
// Remove summons if player abandons or rewards a quest
|
||||
if (player->GetMapId() == MAP_NPE)
|
||||
{
|
||||
if (player->GetQuestStatus(questId) == QUEST_STATUS_REWARDED)
|
||||
{
|
||||
// Reunion (DNT). The spell aura plays the scene; the ship movies are a different packet.
|
||||
if (questId == QUEST_RIDE_OF_THE_SCIENTIFICALLY_ENHANCED_BOAR)
|
||||
player->CastSpell(player, SPELL_REUNION_SCENE_A, true);
|
||||
else if (questId == QUEST_H_THE_REDEATHER)
|
||||
player->CastSpell(player, SPELL_REUNION_SCENE_H, true);
|
||||
}
|
||||
|
||||
if (player->GetQuestStatus(questId) == QUEST_STATUS_NONE || player->GetQuestStatus(questId) == QUEST_STATUS_REWARDED)
|
||||
{
|
||||
std::vector<uint32> activeSummons;
|
||||
@@ -157,11 +166,11 @@ public:
|
||||
{
|
||||
if (QuestAccepted(player, QUEST_STOCKING_UP_ON_SUPPLIES))
|
||||
if (criteria->Entry->ID == 47940 || criteria->Entry->ID == 48009) // item sold to vendor
|
||||
player->ForceCompleteQuest(QUEST_STOCKING_UP_ON_SUPPLIES);
|
||||
CreditCriteriaTreeObjectives(player, QUEST_STOCKING_UP_ON_SUPPLIES);
|
||||
|
||||
if (QuestAccepted(player, QUEST_H_STOCKING_UP_ON_SUPPLIES))
|
||||
if (criteria->Entry->ID == 47940 || criteria->Entry->ID == 48009) // item sold to vendor
|
||||
player->ForceCompleteQuest(QUEST_H_STOCKING_UP_ON_SUPPLIES);
|
||||
CreditCriteriaTreeObjectives(player, QUEST_H_STOCKING_UP_ON_SUPPLIES);
|
||||
}
|
||||
|
||||
// Phase Update in every 1sec
|
||||
@@ -390,17 +399,15 @@ class Exiles_Reach_AchievementScript : public AchievementScript
|
||||
public:
|
||||
Exiles_Reach_AchievementScript() : AchievementScript("Exiles_Reach_AchievementScript") {}
|
||||
|
||||
// @todo make a hook for criteria update and use that
|
||||
|
||||
void OnCompleted(Player* player, AchievementEntry const* achievement) override
|
||||
{
|
||||
if (achievement->ID == ACHIEVEMENT_NPE_SOLD_ITEM)
|
||||
{
|
||||
if (QuestAccepted(player, QUEST_STOCKING_UP_ON_SUPPLIES))
|
||||
player->ForceCompleteQuest(QUEST_STOCKING_UP_ON_SUPPLIES);
|
||||
CreditCriteriaTreeObjectives(player, QUEST_STOCKING_UP_ON_SUPPLIES);
|
||||
|
||||
if (QuestAccepted(player, QUEST_H_STOCKING_UP_ON_SUPPLIES))
|
||||
player->ForceCompleteQuest(QUEST_H_STOCKING_UP_ON_SUPPLIES);
|
||||
CreditCriteriaTreeObjectives(player, QUEST_H_STOCKING_UP_ON_SUPPLIES);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -131,8 +131,17 @@ struct npc_exiles_reach_quilboar_briarpatch_166996_154327 : public ScriptedAI
|
||||
{
|
||||
npc_exiles_reach_quilboar_briarpatch_166996_154327(Creature* creature) : ScriptedAI(creature) {}
|
||||
|
||||
void OnQuestAccept(Player* player, Quest const* /*quest*/) override
|
||||
void OnQuestAccept(Player* player, Quest const* quest) override
|
||||
{
|
||||
// Taming the Wilds is the hunter quest in place of Enhanced Combat Tactics.
|
||||
// Austin / Mithdran teach Tame Beast (320840) and Call Pet (320842).
|
||||
if (quest->GetQuestId() == QUEST_TAMING_THE_WILDS || quest->GetQuestId() == QUEST_H_TAMING_THE_WILDS)
|
||||
{
|
||||
player->CastSpell(player, 320840, true);
|
||||
player->CastSpell(player, 320842, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fix the quest status check (operator precedence + correct status)
|
||||
bool hasQuests = false;
|
||||
if (player->IsInHorde())
|
||||
|
||||
@@ -157,7 +157,6 @@ void AddSC_dustwallow_marsh();
|
||||
void AddSC_felwood();
|
||||
void AddSC_feralas();
|
||||
void AddSC_moonglade();
|
||||
void AddSC_mulgore();
|
||||
void AddSC_orgrimmar();
|
||||
void AddSC_silithus();
|
||||
// void AddSC_stonetalon_mountains();
|
||||
@@ -302,7 +301,6 @@ void AddKalimdorScripts()
|
||||
AddSC_felwood();
|
||||
AddSC_feralas();
|
||||
AddSC_moonglade();
|
||||
AddSC_mulgore();
|
||||
AddSC_orgrimmar();
|
||||
AddSC_silithus();
|
||||
// AddSC_stonetalon_mountains();
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "MotionMaster.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "WaypointDefines.h"
|
||||
|
||||
/*######
|
||||
## npc_eagle_spirit
|
||||
######*/
|
||||
|
||||
enum EagleSpirit
|
||||
{
|
||||
SPELL_EJECT_ALL_PASSENGERS = 50630,
|
||||
SPELL_SPIRIT_FORM = 69324
|
||||
};
|
||||
|
||||
WaypointPath const EagleSpiritflightPath =
|
||||
{
|
||||
0,
|
||||
{
|
||||
{ 0, -2884.155f, -71.08681f, 242.0678f },
|
||||
{ 1, -2720.592f, -111.0035f, 242.5955f },
|
||||
{ 2, -2683.951f, -382.9010f, 231.1792f },
|
||||
{ 3, -2619.148f, -484.9288f, 231.1792f },
|
||||
{ 4, -2543.868f, -525.3333f, 231.1792f },
|
||||
{ 5, -2465.321f, -502.4896f, 190.7347f },
|
||||
{ 6, -2343.872f, -401.8281f, -8.320873f }
|
||||
},
|
||||
WaypointMoveType::Run,
|
||||
WaypointPathFlags::FlyingPath
|
||||
};
|
||||
|
||||
class npc_eagle_spirit : public CreatureScript
|
||||
{
|
||||
public:
|
||||
npc_eagle_spirit() : CreatureScript("npc_eagle_spirit") { }
|
||||
|
||||
struct npc_eagle_spirit_AI : public ScriptedAI
|
||||
{
|
||||
npc_eagle_spirit_AI(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void PassengerBoarded(Unit* /*who*/, int8 /*seatId*/, bool apply) override
|
||||
{
|
||||
if (!apply)
|
||||
return;
|
||||
|
||||
me->GetMotionMaster()->MovePath(EagleSpiritflightPath, false);
|
||||
me->CastSpell(me, SPELL_SPIRIT_FORM);
|
||||
}
|
||||
|
||||
void WaypointPathEnded(uint32 /*pointId*/, uint32 /*pathId*/) override
|
||||
{
|
||||
DoCast(SPELL_EJECT_ALL_PASSENGERS);
|
||||
}
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
{
|
||||
return new npc_eagle_spirit_AI(creature);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_mulgore()
|
||||
{
|
||||
new npc_eagle_spirit();
|
||||
}
|
||||
@@ -1628,7 +1628,7 @@ struct npc_delivery_cart : public ScriptedAI
|
||||
_events.ScheduleEvent(Events::YakCartPathStart, 1800ms);
|
||||
_events.ScheduleEvent(Events::YakCartRopes, 1s);
|
||||
|
||||
if (_data.QuestId && player->hasQuest(*_data.QuestId) && _data.CreditNPC)
|
||||
if (_data.QuestId && player->GetQuestStatus(*_data.QuestId) == QUEST_STATUS_INCOMPLETE && _data.CreditNPC)
|
||||
player->KilledMonsterCredit(*_data.CreditNPC, player->GetGUID());
|
||||
}
|
||||
|
||||
|
||||
@@ -5861,6 +5861,53 @@ class spell_warboard_horde_261655 : public SpellScript
|
||||
};
|
||||
|
||||
//WowCommunity
|
||||
// 459397 - Equip Earthen Weapons
|
||||
class spell_equip_earthen_weapons : public SpellScript
|
||||
{
|
||||
static constexpr uint32 EarthenDagger = 222993;
|
||||
|
||||
void HandleDummy(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
Player* player = GetHitPlayer();
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
static constexpr uint32 weaponIds[] = { 222999u, 222995u, 223000u, EarthenDagger, 222990u, 222994u };
|
||||
|
||||
uint32 toEquip = 0;
|
||||
player->ForEachItem(ItemSearchLocation::Inventory, [&](Item* item)
|
||||
{
|
||||
for (uint32 weaponId : weaponIds)
|
||||
if (item->GetEntry() == weaponId)
|
||||
{
|
||||
toEquip = weaponId;
|
||||
return ItemSearchCallbackResult::Stop;
|
||||
}
|
||||
return ItemSearchCallbackResult::Continue;
|
||||
});
|
||||
|
||||
if (!toEquip)
|
||||
return;
|
||||
|
||||
if (toEquip == EarthenDagger)
|
||||
{
|
||||
// daggers go in pairs: only when no other weapon is equipped
|
||||
if (player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND) ||
|
||||
player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND))
|
||||
return;
|
||||
|
||||
player->ForceEquipItemFromInventory(EarthenDagger);
|
||||
}
|
||||
else
|
||||
player->ForceEquipItemFromInventory(toEquip, 1);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_equip_earthen_weapons::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_generic_spell_scripts()
|
||||
{
|
||||
RegisterSpellScript(spell_gen_absorb0_hitlimit1);
|
||||
@@ -6065,5 +6112,6 @@ void AddSC_generic_spell_scripts()
|
||||
RegisterSpellScript(spell_class_mecagnomo_emergency);
|
||||
RegisterSpellScript(spell_warboard_alliance_261654);
|
||||
RegisterSpellScript(spell_warboard_horde_261655);
|
||||
RegisterSpellScript(spell_equip_earthen_weapons); // Spell 459397
|
||||
//WowCommunity
|
||||
}
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (C) WowCommunity Project
|
||||
*
|
||||
* This SourceCode is NOT free a software. Please hold everything Private
|
||||
* and read our Terms
|
||||
*/
|
||||
|
||||
#include "cinderbrew_meadery.h"
|
||||
#include "Containers.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
enum AldryrSpells
|
||||
{
|
||||
// Brew Master Aldryr (210271)
|
||||
SPELL_KEG_SMASH = 432228, // ~432229 AoE damage helper
|
||||
SPELL_KEG_SMASH_AOE = 432229, // Keg shatters dealing AoE + Hot Honey
|
||||
SPELL_HOT_HONEY = 432186, // Scalding ground DoT
|
||||
SPELL_THROW_CINDERBREW = 432183, // target DoT, leaves Hot Honey
|
||||
SPELL_BLAZING_BELCH = 432203, // frontal cone
|
||||
SPELL_BLAZING_BELCH_BC = 432198,
|
||||
SPELL_HAPPY_HOUR = 442542, // intermission start
|
||||
SPELL_HAPPY_HOUR_BC = 442525,
|
||||
SPELL_DISREGARD = 442611, // 99% damage reduction during intermission
|
||||
SPELL_CLEAR_THE_BAR = 454459, // end intermission helper
|
||||
|
||||
// Thirsty Patron (215819)
|
||||
SPELL_ROWDY_YELL = 452418,
|
||||
SPELL_ROWDY_YELL_BC = 431897,
|
||||
|
||||
// Mug of Cinderbrew (220830)
|
||||
SPELL_MUG_ADVERT = 448069,
|
||||
SPELL_MUG_HIGHLIGHT = 454452,
|
||||
SPELL_TOSS_CINDERBREW = 431902,
|
||||
SPELL_TOSS_CINDERBREW_ALT = 431906,
|
||||
SPELL_CARRYING_CINDERBREW = 431895,
|
||||
};
|
||||
|
||||
enum AldryrEvents
|
||||
{
|
||||
EVENT_KEG_SMASH = 1,
|
||||
EVENT_THROW_CINDERBREW,
|
||||
EVENT_BLAZING_BELCH,
|
||||
EVENT_SERVE_PATRON,
|
||||
EVENT_END_INTERMISSION,
|
||||
EVENT_ROWDY_YELL,
|
||||
};
|
||||
|
||||
enum AldryrMisc
|
||||
{
|
||||
HEALTH_PERCENT_HAPPY_HOUR_1 = 66,
|
||||
HEALTH_PERCENT_HAPPY_HOUR_2 = 33,
|
||||
PATRON_COUNT = 4,
|
||||
};
|
||||
|
||||
// 210271 - Brew Master Aldryr
|
||||
struct boss_brew_master_aldryr : public BossAI
|
||||
{
|
||||
boss_brew_master_aldryr(Creature* creature) : BossAI(creature, DATA_BREW_MASTER_ALDRYR) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
_intermission = false;
|
||||
_removed66 = false;
|
||||
_removed33 = false;
|
||||
}
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
events.ScheduleEvent(EVENT_KEG_SMASH, 10s);
|
||||
events.ScheduleEvent(EVENT_THROW_CINDERBREW, 6s);
|
||||
events.ScheduleEvent(EVENT_BLAZING_BELCH, 18s);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo*/) override
|
||||
{
|
||||
if (_intermission)
|
||||
return;
|
||||
|
||||
uint8 pct = uint8(me->GetHealthPct());
|
||||
if (!_removed66 && pct <= HEALTH_PERCENT_HAPPY_HOUR_1)
|
||||
{
|
||||
_removed66 = true;
|
||||
StartHappyHour();
|
||||
}
|
||||
else if (!_removed33 && pct <= HEALTH_PERCENT_HAPPY_HOUR_2)
|
||||
{
|
||||
_removed33 = true;
|
||||
StartHappyHour();
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
_intermission = false;
|
||||
summons.DespawnAll();
|
||||
BossAI::EnterEvadeMode(why);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_KEG_SMASH:
|
||||
if (_intermission)
|
||||
break;
|
||||
if (Unit* victim = me->GetVictim())
|
||||
{
|
||||
DoCast(victim, SPELL_KEG_SMASH);
|
||||
DoCastSelf(SPELL_KEG_SMASH_AOE, true);
|
||||
}
|
||||
events.Repeat(18s);
|
||||
break;
|
||||
case EVENT_THROW_CINDERBREW:
|
||||
if (_intermission)
|
||||
break;
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true))
|
||||
DoCast(target, SPELL_THROW_CINDERBREW);
|
||||
events.Repeat(9s);
|
||||
break;
|
||||
case EVENT_BLAZING_BELCH:
|
||||
if (_intermission)
|
||||
break;
|
||||
DoCastSelf(SPELL_BLAZING_BELCH);
|
||||
events.Repeat(22s);
|
||||
break;
|
||||
case EVENT_SERVE_PATRON:
|
||||
{
|
||||
std::list<Creature*> patrons;
|
||||
me->GetCreatureListWithEntryInGrid(patrons, NPC_THIRSTY_PATRON, 40.0f);
|
||||
patrons.remove_if([](Creature* c) { return !c->IsAlive(); });
|
||||
if (patrons.empty())
|
||||
break;
|
||||
|
||||
Creature* patron = Trinity::Containers::SelectRandomContainerElement(patrons);
|
||||
if (patron)
|
||||
{
|
||||
DoCast(patron, SPELL_TOSS_CINDERBREW, true);
|
||||
patron->KillSelf();
|
||||
}
|
||||
events.Repeat(4s);
|
||||
break;
|
||||
}
|
||||
case EVENT_END_INTERMISSION:
|
||||
EndHappyHour();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void StartHappyHour()
|
||||
{
|
||||
_intermission = true;
|
||||
|
||||
DoCastSelf(SPELL_HAPPY_HOUR);
|
||||
DoCastSelf(SPELL_DISREGARD, true);
|
||||
|
||||
for (uint8 i = 0; i < PATRON_COUNT; ++i)
|
||||
{
|
||||
Position pos = me->GetRandomNearPosition(10.0f);
|
||||
if (Creature* patron = me->SummonCreature(NPC_THIRSTY_PATRON, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 30s))
|
||||
patron->AI()->DoZoneInCombat();
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < 2; ++i)
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true))
|
||||
DoCast(target, SPELL_THROW_CINDERBREW, true);
|
||||
|
||||
events.ScheduleEvent(EVENT_SERVE_PATRON, 5s);
|
||||
events.ScheduleEvent(EVENT_END_INTERMISSION, 15s);
|
||||
}
|
||||
|
||||
void EndHappyHour()
|
||||
{
|
||||
_intermission = false;
|
||||
DoCastSelf(SPELL_HAPPY_HOUR_BC, true);
|
||||
DoCastSelf(SPELL_CLEAR_THE_BAR, true);
|
||||
me->RemoveAurasDueToSpell(SPELL_DISREGARD);
|
||||
summons.DespawnEntry(NPC_THIRSTY_PATRON);
|
||||
}
|
||||
|
||||
bool _intermission = false;
|
||||
bool _removed66 = false;
|
||||
bool _removed33 = false;
|
||||
};
|
||||
|
||||
// 215819 - Thirsty Patron: yells during the Happy Hour intermission.
|
||||
struct npc_thirsty_patron : public ScriptedAI
|
||||
{
|
||||
npc_thirsty_patron(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void ScheduleTasks() override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_ROWDY_YELL, 2s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_ROWDY_YELL:
|
||||
DoCastSelf(SPELL_ROWDY_YELL);
|
||||
events.Repeat(2s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_brew_master_aldryr()
|
||||
{
|
||||
RegisterCinderbrewMeaderyCreatureAI(boss_brew_master_aldryr);
|
||||
RegisterCinderbrewMeaderyCreatureAI(npc_thirsty_patron);
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (C) WowCommunity Project
|
||||
*
|
||||
* This SourceCode is NOT free a software. Please hold everything Private
|
||||
* and read our Terms
|
||||
*/
|
||||
|
||||
#include "cinderbrew_meadery.h"
|
||||
#include "Containers.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
enum BenkSpells
|
||||
{
|
||||
SPELL_HONEY_MARINADE = 440134, // player honey debuff
|
||||
SPELL_SUMMON_BEES_PASSIVE = 438663, // Honey Barrel bee spawning aura
|
||||
SPELL_SUMMON_BEES_CAST = 438665,
|
||||
SPELL_HONEY_BARREL_COS = 438585, // spawn cosmetic
|
||||
SPELL_BEE_VENOM = 441397, // Bee-let sting
|
||||
SPELL_BEE_SHREDDING_STING = 438971,
|
||||
};
|
||||
|
||||
enum BenkEvents
|
||||
{
|
||||
EVENT_HONEY_MARINADE = 1,
|
||||
EVENT_BEE_SWARM,
|
||||
EVENT_SUMMON_BARREL,
|
||||
};
|
||||
|
||||
// 218865 - Bee-let: harassing sting bot.
|
||||
struct npc_bee_let : public ScriptedAI
|
||||
{
|
||||
npc_bee_let(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void ScheduleTasks() override
|
||||
{
|
||||
me->SetCanFly(true);
|
||||
me->SetDisableGravity(true);
|
||||
events.ScheduleEvent(EVENT_BEE_STING, 2s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_BEE_STING:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 30.0f, true))
|
||||
{
|
||||
DoCast(target, SPELL_BEE_VENOM);
|
||||
DoCast(target, SPELL_BEE_SHREDDING_STING, true);
|
||||
}
|
||||
events.Repeat(3s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
enum { EVENT_BEE_STING = 1 };
|
||||
};
|
||||
|
||||
// 219005 - Honey Barrel: passively summons constant bee-let reinforcements.
|
||||
struct npc_honey_barrel : public ScriptedAI
|
||||
{
|
||||
npc_honey_barrel(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void ScheduleTasks() override
|
||||
{
|
||||
DoCastSelf(SPELL_HONEY_BARREL_COS, true);
|
||||
DoCastSelf(SPELL_SUMMON_BEES_PASSIVE, true);
|
||||
events.ScheduleEvent(EVENT_SUMMON_BARREL, 3s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SUMMON_BARREL:
|
||||
{
|
||||
Position pos = me->GetRandomNearPosition(5.0f);
|
||||
if (Creature* bee = me->SummonCreature(NPC_BEE_LET, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 10s))
|
||||
{
|
||||
DoCastSelf(SPELL_SUMMON_BEES_CAST, true);
|
||||
bee->AI()->DoZoneInCombat();
|
||||
}
|
||||
events.Repeat(3s);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
enum { EVENT_SUMMON_BARREL = 1 };
|
||||
};
|
||||
|
||||
// 218002 - Benk Buzzbee
|
||||
struct boss_benk_buzzbee : public BossAI
|
||||
{
|
||||
boss_benk_buzzbee(Creature* creature) : BossAI(creature, DATA_BENK_BUZZBEE) { }
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
events.ScheduleEvent(EVENT_HONEY_MARINADE, 6s);
|
||||
events.ScheduleEvent(EVENT_BEE_SWARM, 10s);
|
||||
events.ScheduleEvent(EVENT_SUMMON_BARREL, 15s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_HONEY_MARINADE:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true))
|
||||
DoCast(target, SPELL_HONEY_MARINADE);
|
||||
events.Repeat(14s);
|
||||
break;
|
||||
case EVENT_BEE_SWARM:
|
||||
{
|
||||
Position pos = me->GetRandomNearPosition(8.0f);
|
||||
if (Creature* bee = me->SummonCreature(NPC_BEE_LET, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20s))
|
||||
bee->AI()->DoZoneInCombat();
|
||||
events.Repeat(IsMythicPlus() ? 12s : 18s);
|
||||
break;
|
||||
}
|
||||
case EVENT_SUMMON_BARREL:
|
||||
{
|
||||
Position pos = me->GetRandomNearPosition(12.0f);
|
||||
if (Creature* barrel = me->SummonCreature(NPC_HONEY_BARREL, pos, TEMPSUMMON_MANUAL_DESPAWN))
|
||||
barrel->AI()->DoZoneInCombat();
|
||||
events.Repeat(30s);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_boss_benk_buzzbee()
|
||||
{
|
||||
RegisterCinderbrewMeaderyCreatureAI(boss_benk_buzzbee);
|
||||
RegisterCinderbrewMeaderyCreatureAI(npc_bee_let);
|
||||
RegisterCinderbrewMeaderyCreatureAI(npc_honey_barrel);
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) WowCommunity Project
|
||||
*
|
||||
* This SourceCode is NOT free a software. Please hold everything Private
|
||||
* and read our Terms
|
||||
*/
|
||||
|
||||
#include "cinderbrew_meadery.h"
|
||||
#include "Containers.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
enum GoldieSpells
|
||||
{
|
||||
SPELL_CASH_CANNON = 436600, // machine gun volley at a player
|
||||
SPELL_CASH_CANNON_BC = 436598, // bullet damage
|
||||
SPELL_LET_IT_HAIL = 442483, // coin hail aoe
|
||||
SPELL_LET_IT_HAIL_BC = 442484,
|
||||
SPELL_CINDER_BOOM = 436900, // bomb explosion
|
||||
SPELL_CINDER_BOOM_BC = 435661,
|
||||
SPELL_SPREAD_THE_LOVE = 439517, // heart spread aoe
|
||||
SPELL_BURNING_RICOCHET = 436654, // bouncing bullet at player
|
||||
|
||||
SPELL_BOMB_JUMP = 439519, // Cinderbrew Bomb jump visual
|
||||
SPELL_BOMB_EXPLODE = 435804, // bomb "Cinder-BOOM!"
|
||||
|
||||
SPELL_DESK_JUMP = 444267,
|
||||
SPELL_ENERGY = 436590, // [DNT] Energy Controller
|
||||
};
|
||||
|
||||
enum GoldieEvents
|
||||
{
|
||||
EVENT_ENERGY = 1,
|
||||
EVENT_CASH_CANNON,
|
||||
EVENT_LET_IT_HAIL,
|
||||
EVENT_SPREAD_THE_LOVE,
|
||||
EVENT_RICOCHET,
|
||||
EVENT_SUMMON_BOMB,
|
||||
EVENT_BOMB_EXPLODE,
|
||||
};
|
||||
|
||||
enum GoldieMisc
|
||||
{
|
||||
MAX_ENERGY = 100,
|
||||
ENERGY_GAIN_PER_SEC = 4,
|
||||
HAIL_ENERGY = 100,
|
||||
BOMB_EXPLOSION_MS = 8000,
|
||||
};
|
||||
|
||||
// 217837 - Cinderbrew Bomb: lands, then blows up.
|
||||
struct npc_cinderbrew_bomb : public ScriptedAI
|
||||
{
|
||||
npc_cinderbrew_bomb(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void ScheduleTasks() override
|
||||
{
|
||||
DoCastSelf(SPELL_BOMB_JUMP, true);
|
||||
events.ScheduleEvent(EVENT_BOMB_EXPLODE, 8s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_BOMB_EXPLODE:
|
||||
DoCastSelf(SPELL_BOMB_EXPLODE, true);
|
||||
me->KillSelf();
|
||||
events.CancelEvent(EVENT_BOMB_EXPLODE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 218523 - Goldie Baronbottom (desk): engages her combat form.
|
||||
struct npc_goldie_desk : public ScriptedAI
|
||||
{
|
||||
npc_goldie_desk(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
auto const& pos = me->GetPosition();
|
||||
if (Creature* boss = me->SummonCreature(BOSS_GOLDIE_BARONBOTTOM, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1min))
|
||||
{
|
||||
boss->AI()->DoZoneInCombat();
|
||||
if (who->ToPlayer())
|
||||
{
|
||||
boss->SetInCombatWith(who);
|
||||
who->SetInCombatWith(boss);
|
||||
boss->Attack(who, true);
|
||||
}
|
||||
me->DespawnOrUnsummon(100ms);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 214661 - Goldie Baronbottom
|
||||
struct boss_goldie_baronbottom : public BossAI
|
||||
{
|
||||
boss_goldie_baronbottom(Creature* creature) : BossAI(creature, DATA_GOLDIE_BARONBOTTOM) { }
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
_energy = 0;
|
||||
DoCastSelf(SPELL_ENERGY, true);
|
||||
DoCastSelf(SPELL_DESK_JUMP, true);
|
||||
|
||||
events.ScheduleEvent(EVENT_ENERGY, 1s);
|
||||
events.ScheduleEvent(EVENT_CASH_CANNON, 8s);
|
||||
events.ScheduleEvent(EVENT_SPREAD_THE_LOVE, 20s);
|
||||
events.ScheduleEvent(EVENT_RICOCHET, 26s);
|
||||
events.ScheduleEvent(EVENT_SUMMON_BOMB, 14s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_ENERGY:
|
||||
_energy += ENERGY_GAIN_PER_SEC;
|
||||
if (_energy >= HAIL_ENERGY && !me->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
_energy = 0;
|
||||
DoCastSelf(SPELL_LET_IT_HAIL);
|
||||
DoCastSelf(SPELL_LET_IT_HAIL_BC, true);
|
||||
events.DelayEvents(6s);
|
||||
}
|
||||
events.Repeat(1s);
|
||||
break;
|
||||
case EVENT_CASH_CANNON:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true))
|
||||
{
|
||||
DoCast(target, SPELL_CASH_CANNON);
|
||||
DoCast(target, SPELL_CASH_CANNON_BC, true);
|
||||
}
|
||||
events.Repeat(16s);
|
||||
break;
|
||||
case EVENT_LET_IT_HAIL:
|
||||
DoCastSelf(SPELL_LET_IT_HAIL);
|
||||
events.Repeat(20s);
|
||||
break;
|
||||
case EVENT_SPREAD_THE_LOVE:
|
||||
DoCastSelf(SPELL_SPREAD_THE_LOVE);
|
||||
DoCastSelf(SPELL_CINDER_BOOM_BC, true);
|
||||
events.Repeat(24s);
|
||||
break;
|
||||
case EVENT_RICOCHET:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true))
|
||||
DoCast(target, SPELL_BURNING_RICOCHET);
|
||||
events.Repeat(18s);
|
||||
break;
|
||||
case EVENT_SUMMON_BOMB:
|
||||
{
|
||||
Position pos = me->GetRandomNearPosition(10.0f);
|
||||
if (Creature* bomb = me->SummonCreature(NPC_CINDERBREW_BOMB, pos, TEMPSUMMON_MANUAL_DESPAWN))
|
||||
bomb->SetFacingToObject(me);
|
||||
events.Repeat(12s);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint8 _energy = 0;
|
||||
};
|
||||
|
||||
void AddSC_boss_goldie_baronbottom()
|
||||
{
|
||||
RegisterCinderbrewMeaderyCreatureAI(boss_goldie_baronbottom);
|
||||
RegisterCinderbrewMeaderyCreatureAI(npc_cinderbrew_bomb);
|
||||
RegisterCinderbrewMeaderyCreatureAI(npc_goldie_desk);
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) WowCommunity Project
|
||||
*
|
||||
* This SourceCode is NOT free a software. Please hold everything Private
|
||||
* and read our Terms
|
||||
*/
|
||||
|
||||
#include "cinderbrew_meadery.h"
|
||||
#include "Containers.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
enum IpaSpells
|
||||
{
|
||||
SPELL_ENERGY_GAIN = 440604, // [DNT] Energy Gain
|
||||
SPELL_SPOUTING_STOUT = 439645, // main mead expulsion
|
||||
SPELL_SPOUTING_STOUT_BC = 439657, // secondary damage casts
|
||||
SPELL_BURNING_FERMENTATION = 439202,
|
||||
SPELL_BURNING_FERMENTATION_BC = 439330,
|
||||
SPELL_BOTTOMS_UPPERCUT = 439031,
|
||||
SPELL_FILL_ER_UP = 442108, // I'pa shields from a Brew Drop
|
||||
SPELL_FILL_ER_UP_DROP = 440104, // Brew Drop delivering the keg
|
||||
SPELL_BREW_DROP_FROTHY = 442117, // energized running speed
|
||||
};
|
||||
|
||||
enum IpaEvents
|
||||
{
|
||||
EVENT_ENERGY = 1,
|
||||
EVENT_SPOUTING_STOUT,
|
||||
EVENT_BURNING_FERMENTATION,
|
||||
EVENT_BOTTOMS_UPPERCUT,
|
||||
EVENT_SUMMON_BREW_DROP,
|
||||
EVENT_RUN_TO_IPA,
|
||||
EVENT_REACH_IPA,
|
||||
};
|
||||
|
||||
enum IpaMisc
|
||||
{
|
||||
MAX_ENERGY = 100,
|
||||
ENERGY_GAIN_PER_SEC = 3,
|
||||
STOUT_ENERGY = 100,
|
||||
BREW_DROP_COUNT = 3,
|
||||
};
|
||||
|
||||
// Brew Drop (219301 / 223562): runs toward I'pa, delivers a keg, leaves honey when slain.
|
||||
struct npc_brew_drop : public ScriptedAI
|
||||
{
|
||||
npc_brew_drop(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void ScheduleTasks() override
|
||||
{
|
||||
if (Unit* ipa = me->ToTempSummon() ? me->ToTempSummon()->GetSummonerUnit() : nullptr)
|
||||
{
|
||||
_ipa = ipa;
|
||||
me->GetMotionMaster()->MoveChase(_ipa, 1.0f);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_RUN_TO_IPA, 1s);
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
// Oozing honey remains where the drop was slain.
|
||||
me->CastSpell(me, 441171, true);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_RUN_TO_IPA:
|
||||
if (_ipa && _ipa->IsAlive() && me->GetDistance(_ipa) <= 3.0f)
|
||||
{
|
||||
DoCast(_ipa, SPELL_FILL_ER_UP_DROP);
|
||||
me->KillSelf();
|
||||
break;
|
||||
}
|
||||
events.Repeat(1s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Unit* _ipa = nullptr;
|
||||
};
|
||||
|
||||
// 210267 - I'pa
|
||||
struct boss_ipa : public BossAI
|
||||
{
|
||||
boss_ipa(Creature* creature) : BossAI(creature, DATA_IPA) { }
|
||||
|
||||
void JustEngagedWith(Unit* who) override
|
||||
{
|
||||
BossAI::JustEngagedWith(who);
|
||||
_energy = 0;
|
||||
DoCastSelf(SPELL_ENERGY_GAIN, true);
|
||||
|
||||
events.ScheduleEvent(EVENT_ENERGY, 1s);
|
||||
events.ScheduleEvent(EVENT_BURNING_FERMENTATION, 8s);
|
||||
events.ScheduleEvent(EVENT_BOTTOMS_UPPERCUT, 14s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_ENERGY:
|
||||
if (_energy == 0)
|
||||
{
|
||||
_energy = STOUT_ENERGY;
|
||||
DoCastSelf(SPELL_SPOUTING_STOUT);
|
||||
for (uint8 i = 0; i < BREW_DROP_COUNT; ++i)
|
||||
{
|
||||
Position pos = me->GetRandomNearPosition(12.0f);
|
||||
if (Creature* drop = me->SummonCreature(NPC_BREW_DROP, pos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 20s))
|
||||
drop->AI()->DoZoneInCombat();
|
||||
}
|
||||
events.DelayEvents(6s);
|
||||
}
|
||||
else
|
||||
_energy += ENERGY_GAIN_PER_SEC;
|
||||
|
||||
if (_energy >= MAX_ENERGY)
|
||||
_energy = 0;
|
||||
|
||||
events.Repeat(1s);
|
||||
break;
|
||||
case EVENT_BURNING_FERMENTATION:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 40.0f, true))
|
||||
{
|
||||
DoCast(target, SPELL_BURNING_FERMENTATION);
|
||||
DoCast(target, SPELL_BURNING_FERMENTATION_BC, true);
|
||||
}
|
||||
events.Repeat(12s);
|
||||
break;
|
||||
case EVENT_BOTTOMS_UPPERCUT:
|
||||
if (Unit* victim = me->GetVictim())
|
||||
DoCast(victim, SPELL_BOTTOMS_UPPERCUT);
|
||||
events.Repeat(15s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint8 _energy = 0;
|
||||
};
|
||||
|
||||
void AddSC_boss_ipa()
|
||||
{
|
||||
RegisterCinderbrewMeaderyCreatureAI(boss_ipa);
|
||||
RegisterCinderbrewMeaderyCreatureAI(npc_brew_drop);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) WowCommunity Project
|
||||
*
|
||||
* This SourceCode is NOT free a software. Please hold everything Private
|
||||
* and read our Terms
|
||||
*/
|
||||
|
||||
#ifndef DEF_CINDERBREW_MEADERY_H_
|
||||
#define DEF_CINDERBREW_MEADERY_H_
|
||||
|
||||
#include "CreatureAIImpl.h"
|
||||
|
||||
#define CBMScriptName "instance_cinderbrew_meadery"
|
||||
#define DataHeader "CinderbrewMeadery"
|
||||
|
||||
uint32 const EncounterCount = 4;
|
||||
|
||||
enum CinderbrewMeaderyDataTypes
|
||||
{
|
||||
DATA_BREW_MASTER_ALDRYR = 0,
|
||||
DATA_IPA,
|
||||
DATA_BENK_BUZZBEE,
|
||||
DATA_GOLDIE_BARONBOTTOM,
|
||||
};
|
||||
|
||||
enum CinderbrewMeaderyCreatureIds
|
||||
{
|
||||
BOSS_BREW_MASTER_ALDRYR = 210271,
|
||||
BOSS_IPA = 210267,
|
||||
BOSS_BENK_BUZZBEE = 218002,
|
||||
BOSS_GOLDIE_BARONBOTTOM = 214661,
|
||||
|
||||
NPC_GOLDIE_DESK = 218523,
|
||||
NPC_THIRSTY_PATRON = 215819,
|
||||
NPC_MUG_OF_CINDERBREW = 220830,
|
||||
NPC_BREW_DROP = 219301,
|
||||
NPC_BREW_DROP_2 = 223562,
|
||||
NPC_HONEY_BARREL = 219005,
|
||||
NPC_BEE_LET = 218865,
|
||||
NPC_CINDERBREW_BOMB = 217837,
|
||||
NPC_GOLD_COIN = 218307,
|
||||
};
|
||||
|
||||
template <class AI, class T>
|
||||
inline AI* GetCinderbrewMeaderyAI(T* obj)
|
||||
{
|
||||
return GetInstanceAI<AI>(obj, CBMScriptName);
|
||||
}
|
||||
|
||||
#define RegisterCinderbrewMeaderyCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetCinderbrewMeaderyAI)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) WowCommunity Project
|
||||
*
|
||||
* This SourceCode is NOT free a software. Please hold everything Private
|
||||
* and read our Terms
|
||||
*/
|
||||
|
||||
#include "InstanceScript.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "cinderbrew_meadery.h"
|
||||
|
||||
static constexpr ObjectData creatureData[] =
|
||||
{
|
||||
{ BOSS_BREW_MASTER_ALDRYR, DATA_BREW_MASTER_ALDRYR },
|
||||
{ BOSS_IPA, DATA_IPA },
|
||||
{ BOSS_BENK_BUZZBEE, DATA_BENK_BUZZBEE },
|
||||
{ BOSS_GOLDIE_BARONBOTTOM, DATA_GOLDIE_BARONBOTTOM },
|
||||
};
|
||||
|
||||
static constexpr DungeonEncounterData const encounters[] =
|
||||
{
|
||||
{ DATA_BREW_MASTER_ALDRYR, {{ 2900 }} },
|
||||
{ DATA_IPA, {{ 2929 }} },
|
||||
{ DATA_BENK_BUZZBEE, {{ 2931 }} },
|
||||
{ DATA_GOLDIE_BARONBOTTOM, {{ 2930 }} },
|
||||
};
|
||||
|
||||
class instance_cinderbrew_meadery : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
instance_cinderbrew_meadery() : InstanceMapScript(CBMScriptName, 2661) { }
|
||||
|
||||
struct instance_cinderbrew_meadery_InstanceMapScript : public InstanceScript
|
||||
{
|
||||
instance_cinderbrew_meadery_InstanceMapScript(InstanceMap* map) : InstanceScript(map)
|
||||
{
|
||||
SetHeaders(DataHeader);
|
||||
SetBossNumber(EncounterCount);
|
||||
LoadObjectData(creatureData, {});
|
||||
LoadDungeonEncounterData(encounters);
|
||||
}
|
||||
|
||||
void OnPlayerEnter(Player* player) override
|
||||
{
|
||||
InstanceScript::OnPlayerEnter(player);
|
||||
|
||||
if (player->GetGroup())
|
||||
player->GetGroup()->AddFollowerModeBots(player);
|
||||
}
|
||||
|
||||
void OnPlayerExit(Player* player)
|
||||
{
|
||||
if (player->GetGroup())
|
||||
player->GetGroup()->DespawnFollowerModeBots(player);
|
||||
}
|
||||
};
|
||||
|
||||
InstanceScript* GetInstanceScript(InstanceMap* map) const override
|
||||
{
|
||||
return new instance_cinderbrew_meadery_InstanceMapScript(map);
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_instance_cinderbrew_meadery()
|
||||
{
|
||||
new instance_cinderbrew_meadery();
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* Copyright (C) WowCommunity Project
|
||||
*
|
||||
* This SourceCode is NOT free a software. Please hold everything Private
|
||||
* and read our Terms
|
||||
*/
|
||||
|
||||
#include "cinderbrew_meadery.h"
|
||||
#include "Containers.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "TemporarySummon.h"
|
||||
|
||||
enum TrashSpells
|
||||
{
|
||||
SPELL_MEAN_MUG = 434773, // Patron
|
||||
SPELL_GUZZLE_CINDERBREW = 434505, // Patron / Muscle
|
||||
SPELL_THIRSTY = 441408, // Patron
|
||||
|
||||
SPELL_BOILING_FLAMES = 453909, // Pyromaniac (channel)
|
||||
SPELL_BOILING_FLAMES_DMG = 454318, // Pyromaniac periodic from channel
|
||||
SPELL_ERUPTING_INFERNO = 437956, // Pyromaniac AoE on death / cast
|
||||
|
||||
SPELL_SWARMING_SURPRISE = 442995, // Honey Harvester
|
||||
SPELL_SWARMING_SURPRISE_BC = 442641,
|
||||
|
||||
SPELL_RAIN_OF_HONEY = 440887, // Royal Jelly Purveyor
|
||||
|
||||
SPELL_BEE_ZOOKA = 441119, // Bee Wrangler
|
||||
SPELL_BEE_STIAL_WRATH = 441351, // Bee Wrangler
|
||||
SPELL_SHOOT = 456891, // Bee Wrangler ranged
|
||||
|
||||
SPELL_VOLATILE_KEG = 463223, // Hired Muscle
|
||||
SPELL_THROW_CHAIR = 434756, // Hired Muscle
|
||||
|
||||
SPELL_RECKLESS_DELIVERY = 449090, // Careless Hopgoblin
|
||||
|
||||
SPELL_SPILL_DRINK = 441214, // Taste Tester
|
||||
SPELL_FREE_SAMPLES = 441242, // Taste Tester
|
||||
|
||||
SPELL_FAILED_BATCH = 441434, // Flavor Scientist
|
||||
SPELL_REJUVENATING_HONEY = 441627, // Flavor Scientist heals ally
|
||||
};
|
||||
|
||||
enum TrashEvents
|
||||
{
|
||||
EVENT_MEAN_MUG = 1,
|
||||
EVENT_BOILING_FLAMES,
|
||||
EVENT_ERUPTING_INFERNO,
|
||||
EVENT_SWARMING_SURPRISE,
|
||||
EVENT_RAIN_OF_HONEY,
|
||||
EVENT_BEE_ZOOKA,
|
||||
EVENT_BEE_STIAL_WRATH,
|
||||
EVENT_VOLATILE_KEG,
|
||||
EVENT_THROW_CHAIR,
|
||||
EVENT_RECKLESS_DELIVERY,
|
||||
EVENT_SPILL_DRINK,
|
||||
EVENT_FAILED_BATCH,
|
||||
EVENT_REJUVENATING_HONEY,
|
||||
};
|
||||
|
||||
// 218671 - Venture Co. Pyromaniac
|
||||
struct npc_pyromaniac : public ScriptedAI
|
||||
{
|
||||
npc_pyromaniac(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void ScheduleTasks() override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_BOILING_FLAMES, 4s);
|
||||
events.ScheduleEvent(EVENT_ERUPTING_INFERNO, 10s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_BOILING_FLAMES:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 20.0f, true))
|
||||
{
|
||||
DoCast(target, SPELL_BOILING_FLAMES);
|
||||
DoCast(target, SPELL_BOILING_FLAMES_DMG, true);
|
||||
}
|
||||
events.Repeat(14s);
|
||||
break;
|
||||
case EVENT_ERUPTING_INFERNO:
|
||||
DoCastSelf(SPELL_ERUPTING_INFERNO);
|
||||
events.Repeat(20s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 220946 - Honey Harvester
|
||||
struct npc_honey_harvester : public ScriptedAI
|
||||
{
|
||||
npc_honey_harvester(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void ScheduleTasks() override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_SWARMING_SURPRISE, 6s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SWARMING_SURPRISE:
|
||||
DoCastSelf(SPELL_SWARMING_SURPRISE);
|
||||
DoCastRandom(SPELL_SWARMING_SURPRISE_BC);
|
||||
events.Repeat(16s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 220141 - Royal Jelly Purveyor
|
||||
struct npc_royal_jelly_purveyor : public ScriptedAI
|
||||
{
|
||||
npc_royal_jelly_purveyor(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void ScheduleTasks() override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_RAIN_OF_HONEY, 5s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_RAIN_OF_HONEY:
|
||||
DoCastSelf(SPELL_RAIN_OF_HONEY);
|
||||
events.Repeat(12s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 210264 - Bee Wrangler
|
||||
struct npc_bee_wrangler : public ScriptedAI
|
||||
{
|
||||
npc_bee_wrangler(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void ScheduleTasks() override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_BEE_ZOOKA, 4s);
|
||||
events.ScheduleEvent(EVENT_BEE_STIAL_WRATH, 12s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_BEE_ZOOKA:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 30.0f, true))
|
||||
DoCast(target, SPELL_BEE_ZOOKA);
|
||||
events.Repeat(8s);
|
||||
break;
|
||||
case EVENT_BEE_STIAL_WRATH:
|
||||
DoCastSelf(SPELL_BEE_STIAL_WRATH);
|
||||
events.Repeat(18s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 210269 - Hired Muscle
|
||||
struct npc_hired_muscle : public ScriptedAI
|
||||
{
|
||||
npc_hired_muscle(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void ScheduleTasks() override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_VOLATILE_KEG, 7s);
|
||||
events.ScheduleEvent(EVENT_THROW_CHAIR, 13s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_VOLATILE_KEG:
|
||||
DoCastSelf(SPELL_VOLATILE_KEG);
|
||||
events.Repeat(15s);
|
||||
break;
|
||||
case EVENT_THROW_CHAIR:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 25.0f, true))
|
||||
DoCast(target, SPELL_THROW_CHAIR);
|
||||
events.Repeat(18s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 223423 - Careless Hopgoblin
|
||||
struct npc_careless_hopgoblin : public ScriptedAI
|
||||
{
|
||||
npc_careless_hopgoblin(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void ScheduleTasks() override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_RECKLESS_DELIVERY, 6s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_RECKLESS_DELIVERY:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 30.0f, true))
|
||||
{
|
||||
DoCast(target, SPELL_RECKLESS_DELIVERY);
|
||||
DoCast(target, 448619, true);
|
||||
}
|
||||
events.Repeat(9s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 220060 - Taste Tester
|
||||
struct npc_taste_tester : public ScriptedAI
|
||||
{
|
||||
npc_taste_tester(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void ScheduleTasks() override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_SPILL_DRINK, 8s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_SPILL_DRINK:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 20.0f, true))
|
||||
{
|
||||
DoCast(target, SPELL_SPILL_DRINK);
|
||||
DoCast(target, SPELL_FREE_SAMPLES, true);
|
||||
}
|
||||
events.Repeat(12s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 214673 - Flavor Scientist
|
||||
struct npc_flavor_scientist : public ScriptedAI
|
||||
{
|
||||
npc_flavor_scientist(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void ScheduleTasks() override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_FAILED_BATCH, 6s);
|
||||
events.ScheduleEvent(EVENT_REJUVENATING_HONEY, 14s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_FAILED_BATCH:
|
||||
DoCastSelf(SPELL_FAILED_BATCH);
|
||||
events.Repeat(14s);
|
||||
break;
|
||||
case EVENT_REJUVENATING_HONEY:
|
||||
{
|
||||
std::list<Creature*> allies;
|
||||
me->GetCreatureListWithEntryInGrid(allies, me->GetEntry(), 20.0f);
|
||||
if (!allies.empty())
|
||||
{
|
||||
Creature* ally = Trinity::Containers::SelectRandomContainerElement(allies);
|
||||
if (ally && ally->IsAlive())
|
||||
DoCast(ally, SPELL_REJUVENATING_HONEY);
|
||||
}
|
||||
events.Repeat(18s);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 214668 - Venture Co. Patron
|
||||
struct npc_venture_patron : public ScriptedAI
|
||||
{
|
||||
npc_venture_patron(Creature* creature) : ScriptedAI(creature) { }
|
||||
|
||||
void ScheduleTasks() override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_MEAN_MUG, 5s);
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_MEAN_MUG:
|
||||
if (Unit* victim = me->GetVictim())
|
||||
DoCast(victim, SPELL_MEAN_MUG);
|
||||
events.Repeat(9s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void AddSC_cinderbrew_meadery_trash()
|
||||
{
|
||||
RegisterCinderbrewMeaderyCreatureAI(npc_pyromaniac);
|
||||
RegisterCinderbrewMeaderyCreatureAI(npc_honey_harvester);
|
||||
RegisterCinderbrewMeaderyCreatureAI(npc_royal_jelly_purveyor);
|
||||
RegisterCinderbrewMeaderyCreatureAI(npc_bee_wrangler);
|
||||
RegisterCinderbrewMeaderyCreatureAI(npc_hired_muscle);
|
||||
RegisterCinderbrewMeaderyCreatureAI(npc_careless_hopgoblin);
|
||||
RegisterCinderbrewMeaderyCreatureAI(npc_taste_tester);
|
||||
RegisterCinderbrewMeaderyCreatureAI(npc_flavor_scientist);
|
||||
RegisterCinderbrewMeaderyCreatureAI(npc_venture_patron);
|
||||
}
|
||||
@@ -30,6 +30,14 @@ void AddSC_boss_avanoxx();
|
||||
void AddSC_boss_anubzekt();
|
||||
void AddSC_boss_kikatal();
|
||||
|
||||
//Cinderbrew Meadery
|
||||
void AddSC_instance_cinderbrew_meadery();
|
||||
void AddSC_boss_brew_master_aldryr();
|
||||
void AddSC_boss_ipa();
|
||||
void AddSC_boss_benk_buzzbee();
|
||||
void AddSC_boss_goldie_baronbottom();
|
||||
void AddSC_cinderbrew_meadery_trash();
|
||||
|
||||
// The name of this function should match:
|
||||
// void Add${NameOfDirectory}Scripts()
|
||||
void AddWarWithinScripts()
|
||||
@@ -55,4 +63,11 @@ void AddWarWithinScripts()
|
||||
AddSC_boss_anubzekt();
|
||||
AddSC_boss_kikatal();
|
||||
|
||||
//Cinderbrew Meadery
|
||||
AddSC_instance_cinderbrew_meadery();
|
||||
AddSC_boss_brew_master_aldryr();
|
||||
AddSC_boss_ipa();
|
||||
AddSC_boss_benk_buzzbee();
|
||||
AddSC_boss_goldie_baronbottom();
|
||||
AddSC_cinderbrew_meadery_trash();
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ constexpr float FOLLOWER_HEALING_MULTIPLIER = 28.0f;
|
||||
constexpr float FOLLOWER_DAMAGE_MULTIPLIER = 0.33f;
|
||||
// Global damage trim applied to every follower damage channel
|
||||
// (weapon swings, AP contribution and spell basepoints).
|
||||
constexpr float FOLLOWER_DAMAGE_OUTPUT_MOD = 0.85f;
|
||||
constexpr float FOLLOWER_DAMAGE_OUTPUT_MOD = 0.578f; // 0.85 * 0.85 * 0.8
|
||||
|
||||
// Level-scaled stat budget: followers carry the player, so on top of the
|
||||
// owner's mapped stats they get a per-level stat floor. Rule of three
|
||||
|
||||
@@ -676,6 +676,13 @@ GameType = 0
|
||||
|
||||
RealmZone = 1
|
||||
|
||||
#
|
||||
# ExtendedAccountNameLengthLimit
|
||||
# Description: Extends account name limit from 16 (retail-like) to 64 characters
|
||||
# Default 0
|
||||
|
||||
ExtendedAccountNameLengthLimit = 0
|
||||
|
||||
#
|
||||
# StrictPlayerNames
|
||||
# Description: Limit player name to language specific symbol set. Prevents character
|
||||
|
||||
Reference in New Issue
Block a user