feat(Core/WorldState): improved WorldState scripting (#20141)

* implement world state script

based on
0b87ca9d9e

Co-authored-by: killerwife <killerwife@gmail.com>

* refactor to use onleave and onenter instead of spell_area

allows players to right click remove adal's buff

* add MapMgr.h

* refactor: use condition enum instead of uint32, prefix WORLD_STATE where needed

* remove lock from WorldState::Update

sWorldState->Update() is only called from World::Update

* remove unsafe SmartAI action of setWorldState

---------

Co-authored-by: killerwife <killerwife@gmail.com>
This commit is contained in:
Jelle Meeus
2024-11-12 16:15:27 +01:00
committed by GitHub
parent e80b0ce8b8
commit 3565e4a9eb
20 changed files with 785 additions and 37 deletions

View File

@@ -0,0 +1,149 @@
--
DELETE FROM `spell_script_names` WHERE `spell_id`=39953 AND `ScriptName`='spell_gen_adals_song_of_battle';
-- A'dal
UPDATE `smart_scripts` SET `link` = 5 WHERE (`entryorguid` = 18481) AND (`source_type` = 0) AND (`id` = 4);
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 18481) AND (`source_type` = 0) AND (`id` = 5);
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(18481, 0, 5, 0, 61, 0, 100, 512, 0, 0, 0, 0, 0, 0, 237, 39953, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'A Dal - On Quest Reward 11007 - Run World State Script Event 39953');
-- Magtheridon's Head
UPDATE `gameobject_template` SET `ScriptName` = 'go_magtheridons_head' WHERE (`entry` = 184640);
-- Trollbane
UPDATE `smart_scripts` SET `link` = 4 WHERE (`entryorguid` = 16819) AND (`source_type` = 0) AND (`id` = 2);
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 16819) AND (`source_type` = 0) AND (`id` = 4);
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(16819, 0, 4, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 50, 184640, 7200, 0, 0, 0, 0, 8, 0, 0, 0, 0, -732.28, 2670.99, 94.5875, -0.541051, 'Force Commander Danath Trollbane - On Quest \'The Fall of Magtheridon\' Finished - Summon Gameobject \'Magtheridon\'s Head\' Alliance');
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 22) AND (`SourceGroup` = 5) AND (`SourceEntry` = 16819);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(22, 5, 16819, 3, 0, 103, 0, 39911, 0, 0, 1, 0, 0, '', 'if Gameobject \'Magtheridon\'s Head\' Alliance is not already spawned');
-- Nazgrel
UPDATE `smart_scripts` SET `link` = 3 WHERE (`entryorguid` = 3230) AND (`source_type` = 0) AND (`id` = 1);
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 3230) AND (`source_type` = 0) AND (`id` = 3);
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(3230, 0, 3, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 50, 184640, 7200, 0, 0, 0, 0, 8, 0, 0, 0, 0, 143.417, 2673.36, 85.3014, 3.01941, 'Nazgrel - On Quest \'The Fall of Magtheridon\' Finished - Summon Gameobject \'Magtheridon\'s Head\' Horde');
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 22) AND (`SourceGroup` = 4) AND (`SourceEntry` = 3230);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(22, 4, 3230, 3, 0, 103, 0, 39913, 0, 0, 1, 0, 0, '', 'if Gameobject \'Magtheridon\'s Head\' Horde is not already spawned');
-- Zeppelin transports
SET @RADIUS:=24; -- radius unknown
-- arrival events, play zeppelin horn
DELETE FROM `event_scripts` WHERE `command` = 16 and `id` IN (15312, 15314, 15318, 15320, 15322, 15324, 15430, 15431, 19126, 19127, 19137, 19139, 21868, 21870);
INSERT INTO `event_scripts` (`id`, `delay`, `command`, `datalong`, `datalong2`, `dataint`, `x`, `y`, `z`, `o`) VALUES
(15312, 0, 16, 11804, 4, @RADIUS, 0.0, 0.0, 0.0, 0.0),
(15314, 0, 16, 11804, 4, @RADIUS, 0.0, 0.0, 0.0, 0.0),
(15318, 0, 16, 11804, 4, @RADIUS, 0.0, 0.0, 0.0, 0.0),
(15320, 0, 16, 11804, 4, @RADIUS, 0.0, 0.0, 0.0, 0.0),
(15322, 0, 16, 11804, 4, @RADIUS, 0.0, 0.0, 0.0, 0.0),
(15324, 0, 16, 11804, 4, @RADIUS, 0.0, 0.0, 0.0, 0.0),
(15430, 0, 16, 11804, 4, @RADIUS, 0.0, 0.0, 0.0, 0.0),
(15431, 0, 16, 11804, 4, @RADIUS, 0.0, 0.0, 0.0, 0.0),
(19126, 0, 16, 11804, 4, @RADIUS, 0.0, 0.0, 0.0, 0.0),
(19127, 0, 16, 11804, 4, @RADIUS, 0.0, 0.0, 0.0, 0.0),
(19137, 0, 16, 11804, 4, @RADIUS, 0.0, 0.0, 0.0, 0.0),
(19139, 0, 16, 11804, 4, @RADIUS, 0.0, 0.0, 0.0, 0.0),
(21868, 0, 16, 11804, 4, @RADIUS, 0.0, 0.0, 0.0, 0.0),
(21870, 0, 16, 11804, 4, @RADIUS, 0.0, 0.0, 0.0, 0.0);
-- The Iron Eagle - Grom'Gol to Orgrimmar
UPDATE `gameobject_template` SET `ScriptName` = 'go_transport_the_iron_eagle' WHERE (`entry` = 175080);
-- Snurk Bucksquick Master Orgrimmar The Iron Eagle
DELETE FROM `gossip_menu_option` WHERE `MenuID` = 3841;
INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`, `ActionPoiID`, `BoxCoded`, `BoxMoney`, `BoxText`, `BoxBroadcastTextID`, `VerifiedBuild`) VALUES
(3841, 0, 0, 'Where is the zeppelin now?', 22086, 1, 1, 8764, 0, 0, 0, '', 0, 0);
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 15) AND (`SourceGroup` = 3841) AND (`SourceEntry` = 0);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 3841, 0, 0, 0, 103, 0, 175080, 15322, 0, 1, 0, 0, '', 'The zeppelin should not have just arrived at Orgrimmar');
-- Zez'raz Master Grom'gol The Iron Eagle
DELETE FROM `gossip_menu_option` WHERE `MenuID` = 2441;
INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`, `ActionPoiID`, `BoxCoded`, `BoxMoney`, `BoxText`, `BoxBroadcastTextID`, `VerifiedBuild`) VALUES
(2441, 0, 0, 'Where is the zeppelin now?', 22086, 1, 1, 8764, 0, 0, 0, '', 0, 0);
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 15) AND (`SourceGroup` = 2441);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 2441, 0, 0, 0, 103, 0, 175080, 15324, 0, 1, 0, 0, '', 'The zeppelin should not have just arrived at Grom\'gol');
-- Krixx Engineer Orgrimmar The Iron Eagle, The Thundercaller
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 14) AND (`SourceGroup` = 8764);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(14, 8764, 11167, 0, 0, 103, 0, 175080, 15324, 0, 0, 0, 0, '', 'The zeppelin should have just arrived at Grom\'gol'),
(14, 8764, 11169, 0, 1, 103, 0, 175080, 15322, 0, 0, 0, 0, '', 'The zeppelin should have just arrived at Orgrimmar'),
(14, 8764, 11170, 0, 2, 103, 0, 175080, 15323, 0, 0, 0, 0, '', 'The zeppelin should have just departed from Orgrimmar'),
(14, 8764, 11172, 0, 3, 103, 0, 175080, 15325, 0, 0, 0, 0, '', 'The zeppelin should have just departed from Grom\'gol'),
(14, 8764, 11163, 0, 4, 103, 0, 175080, 0, 0, 0, 0, 0, '', 'I\'m not sure where the zeppelin is right now, actually...');
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 14) AND (`SourceGroup` = 8765);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(14, 8765, 11165, 0, 0, 103, 0, 164871, 15318, 0, 0, 0, 0, '', 'The zeppelin should have just arrived at Orgrimmar'),
(14, 8765, 11173, 0, 1, 103, 0, 164871, 15320, 0, 0, 0, 0, '', 'The zeppelin should have just arrived at Undercity'),
(14, 8765, 11174, 0, 2, 103, 0, 164871, 15319, 0, 0, 0, 0, '', 'The zeppelin should have just departed from Orgrimmar'),
(14, 8765, 11175, 0, 3, 103, 0, 164871, 15321, 0, 0, 0, 0, '', 'The zeppelin should have just departed from Undercity'),
(14, 8765, 11163, 0, 4, 103, 0, 164871, 0, 0, 0, 0, 0, '', 'I\'m not sure where the zeppelin is right now, actually...');
-- The Thundercaller - Undercity to Orgrimmar
UPDATE `gameobject_template` SET `ScriptName` = 'go_transport_the_thundercaller' WHERE (`entry` = 164871);
-- Frezza Master Orgrimmar The Thundercaller
DELETE FROM `gossip_menu_option` WHERE `MenuID` = 1969;
INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`, `ActionPoiID`, `BoxCoded`, `BoxMoney`, `BoxText`, `BoxBroadcastTextID`, `VerifiedBuild`) VALUES
(1969, 0, 0, 'Where is the zeppelin now?', 22086, 1, 1, 8765, 0, 0, 0, '', 0, 0);
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 15) AND (`SourceGroup` = 1969) AND (`SourceEntry` = 0);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 1969, 0, 0, 0, 103, 0, 164871, 15318, 0, 1, 0, 0, '', 'The zeppelin should not have just arrived at Orgrimmar');
-- Zapetta Master Undercity The Thundercaller
DELETE FROM `gossip_menu_option` WHERE `MenuID` = 1971;
INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`, `ActionPoiID`, `BoxCoded`, `BoxMoney`, `BoxText`, `BoxBroadcastTextID`, `VerifiedBuild`) VALUES
(1971, 0, 0, 'Where is the zeppelin now?', 22086, 1, 1, 8765, 0, 0, 0, '', 0, 0);
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 15) AND (`SourceGroup` = 1971) AND (`SourceEntry` = 0);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 1971, 0, 0, 0, 103, 0, 164871, 15320, 0, 1, 0, 0, '', 'The zeppelin should not have just arrived at Undercity');
DELETE FROM `creature_text` WHERE (`CreatureID` = 9566) AND (`GroupID` = 1);
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(9566, 1, 0, 'There goes the zeppelin to Orgrimmar. I hope there\'s no explosions this time.', 12, 0, 100, 0, 0, 0, 22080, 0, 'Zapetta - Departure');
UPDATE `creature_text` SET `comment` = 'Zapetta - Arrival' WHERE (`CreatureID` = 9566) AND (`GroupID` = 0);
-- The Purple Princess - Grom'Gol to Undercity
UPDATE `gameobject_template` SET `ScriptName` = 'go_transport_the_purple_princess' WHERE (`entry` = 176495);
-- Hin Denburg Master Undercity The Purple Princess
DELETE FROM `gossip_menu` WHERE `MenuID` = 8766 AND `TextID` IN (11179, 11182);
INSERT INTO `gossip_menu` (`MenuID`, `TextID`) VALUES
(8766, 11179),
(8766, 11182);
DELETE FROM `gossip_menu_option` WHERE `MenuID` = 2101;
INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`, `ActionPoiID`, `BoxCoded`, `BoxMoney`, `BoxText`, `BoxBroadcastTextID`, `VerifiedBuild`) VALUES
(2101, 0, 0, 'Where is the zeppelin now?', 22086, 1, 1, 8766, 0, 0, 0, '', 0, 0);
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 15) AND (`SourceGroup` = 2101) AND (`SourceEntry` = 0);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 2101, 0, 0, 0, 103, 0, 176495, 15312, 0, 1, 0, 0, '', 'The zeppelin should not have just arrived at Undercity');
-- Squibby Overspeck Master Grom'gol The Purple Princess
DELETE FROM `gossip_menu_option` WHERE `MenuID` = 3842;
INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`, `ActionPoiID`, `BoxCoded`, `BoxMoney`, `BoxText`, `BoxBroadcastTextID`, `VerifiedBuild`) VALUES
(3842, 0, 0, 'Where is the zeppelin now?', 22086, 1, 1, 8766, 0, 0, 0, '', 0, 0);
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 15) AND (`SourceGroup` = 3842) AND (`SourceEntry` = 0) AND (`SourceId` = 0);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(15, 3842, 0, 0, 0, 103, 0, 176495, 15314, 0, 1, 0, 0, '', 'The zeppelin should not have just arrived at Grom\'gol');
-- Kraxx Engineer Undercity The Thundercaller, The Purple Princess
DELETE FROM `gossip_menu_option` WHERE `MenuID` = 8786;
INSERT INTO `gossip_menu_option` (`MenuID`, `OptionID`, `OptionIcon`, `OptionText`, `OptionBroadcastTextID`, `OptionType`, `OptionNpcFlag`, `ActionMenuID`, `ActionPoiID`, `BoxCoded`, `BoxMoney`, `BoxText`, `BoxBroadcastTextID`, `VerifiedBuild`) VALUES
(8786, 0, 0, 'Where is the zeppelin to Orgrimmar right now?', 22185, 1, 1, 8765, 0, 0, 0, '', 0, 0),
(8786, 1, 0, 'Where is the zeppelin to Grom\'gol right now?', 22199, 1, 1, 8766, 0, 0, 0, '', 0, 0);
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 14) AND (`SourceGroup` = 8766);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(14, 8766, 11179, 0, 0, 103, 0, 176495, 15312, 0, 0, 0, 0, '', 'The zeppelin should have just arrived at Undercity'),
(14, 8766, 11180, 0, 1, 103, 0, 176495, 15314, 0, 0, 0, 0, '', 'The zeppelin should have just arrived at Grom\'gol'),
(14, 8766, 11182, 0, 2, 103, 0, 176495, 15313, 0, 0, 0, 0, '', 'The zeppelin should have just departed from Undercity'),
(14, 8766, 11181, 0, 3, 103, 0, 176495, 15315, 0, 0, 0, 0, '', 'The zeppelin should have just departed from Grom\'gol'),
(14, 8766, 11163, 0, 4, 103, 0, 176495, 0, 0, 0, 0, 0, '', 'I\'m not sure where the zeppelin is right now, actually...');
-- I\'m not sure where the zeppelin is right now, actually...
DELETE FROM `gossip_menu` WHERE (`MenuID` IN (8764, 8765, 8766)) and `TextID` = 11163;
INSERT INTO `gossip_menu` (`MenuID`, `TextID`) VALUES
(8764, 11163),
(8765, 11163),
(8766, 11163);

View File

@@ -35,6 +35,7 @@
#include "SmartAI.h"
#include "SpellMgr.h"
#include "Vehicle.h"
#include "WorldState.h"
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
// however, for some reasons removing it would cause a damn linking issue
@@ -3269,6 +3270,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
break;
}
case SMART_ACTION_WORLD_SCRIPT:
{
sWorldState->HandleExternalEvent(static_cast<WorldStateEvent>(e.action.worldStateScript.eventId), e.action.worldStateScript.param);
break;
}
default:
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
break;

View File

@@ -777,6 +777,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
case SMART_ACTION_MOVEMENT_STOP: return NO_PARAMS;
case SMART_ACTION_MOVEMENT_PAUSE: return sizeof(SmartAction::move);
case SMART_ACTION_MOVEMENT_RESUME: return sizeof(SmartAction::move);
case SMART_ACTION_WORLD_SCRIPT: return sizeof(SmartAction::worldStateScript);
default:
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.",
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
@@ -1960,6 +1961,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_MOVEMENT_STOP:
case SMART_ACTION_MOVEMENT_PAUSE:
case SMART_ACTION_MOVEMENT_RESUME:
case SMART_ACTION_WORLD_SCRIPT:
break;
default:
LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type({}), event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);

View File

@@ -727,8 +727,9 @@ enum SMART_ACTION
SMART_ACTION_MOVEMENT_STOP = 234, //
SMART_ACTION_MOVEMENT_PAUSE = 235, // timer
SMART_ACTION_MOVEMENT_RESUME = 236, // timerOverride
SMART_ACTION_WORLD_SCRIPT = 237, // eventId, param
SMART_ACTION_AC_END = 237, // placeholder
SMART_ACTION_AC_END = 238, // placeholder
};
enum class SmartActionSummonCreatureFlags
@@ -1472,6 +1473,12 @@ struct SmartAction
{
uint32 timer;
} move;
struct
{
uint32 eventId;
uint32 param;
} worldStateScript;
//! Note for any new future actions
//! All parameters must have type uint32

View File

@@ -28,6 +28,7 @@
#include "Spell.h"
#include "SpellAuras.h"
#include "SpellMgr.h"
#include "WorldState.h"
// Checks if object meets the condition
// Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: eventAI)
@@ -570,6 +571,11 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
condMeets = unit->IsCharmed();
break;
}
case CONDITION_WORLD_SCRIPT:
{
condMeets = sWorldState->IsConditionFulfilled(static_cast<WorldStateCondition>(ConditionValue1), static_cast<WorldStateConditionState>(ConditionValue2));
break;
}
default:
condMeets = false;
break;
@@ -770,6 +776,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition()
case CONDITION_CHARMED:
mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
break;
case CONDITION_WORLD_SCRIPT:
mask |= GRID_MAP_TYPE_MASK_ALL;
break;
default:
ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!");
break;

View File

@@ -86,7 +86,9 @@ enum ConditionTypes
CONDITION_AC_START = 100,
CONDITION_QUEST_SATISFY_EXCLUSIVE = 101, // quest_id 0 0 true if satisfied exclusive group
CONDITION_HAS_AURA_TYPE = 102, // aura_type 0 0 true if has aura type
CONDITION_AC_END = 103 // placeholder
CONDITION_WORLD_SCRIPT = 103, // conditionId state 0 true if WorldState::IsConditionFulfilled returns true
CONDITION_AC_END = 104 // placeholder
};
/*! Documentation on implementing a new ConditionSourceType:

View File

@@ -83,6 +83,7 @@
#include "World.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "WorldState.h"
#include <cmath>
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
@@ -1722,6 +1723,7 @@ void Player::RemoveFromWorld()
m_session->DoLootRelease(lguid);
sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
sBattlefieldMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
sWorldState->HandlePlayerLeaveZone(this, static_cast<WorldStateZoneId>(m_zoneUpdateId));
}
// Remove items from world before self - player must be found in Item::RemoveFromObjectUpdate

View File

@@ -38,6 +38,7 @@
#include "Vehicle.h"
#include "Weather.h"
#include "WeatherMgr.h"
#include "WorldState.h"
#include "WorldStatePackets.h"
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
@@ -1215,6 +1216,8 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
{
sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
sOutdoorPvPMgr->HandlePlayerEnterZone(this, newZone);
sWorldState->HandlePlayerLeaveZone(this, static_cast<WorldStateZoneId>(m_zoneUpdateId));
sWorldState->HandlePlayerEnterZone(this, static_cast<WorldStateZoneId>(newZone));
sBattlefieldMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
sBattlefieldMgr->HandlePlayerEnterZone(this, newZone);
SendInitWorldStates(newZone,

View File

@@ -180,6 +180,7 @@ enum eScriptFlags
// Playsound flags
SF_PLAYSOUND_TARGET_PLAYER = 0x1,
SF_PLAYSOUND_DISTANCE_SOUND = 0x2,
SF_PLAYSOUND_DISTANCE_RADIUS = 0x4,
// Orientation flags
SF_ORIENTATION_FACE_TARGET = 0x1,
@@ -307,6 +308,7 @@ struct ScriptInfo
{
uint32 SoundID; // datalong
uint32 Flags; // datalong2
int32 Radius; // dataint
} Playsound;
struct // SCRIPT_COMMAND_CREATE_ITEM (17)

View File

@@ -730,8 +730,10 @@ void Map::ScriptsProcess()
break;
}
// Playsound.Flags bitmask: 0/2=without/with distance dependent
if (step.script->Playsound.Flags & SF_PLAYSOUND_DISTANCE_SOUND)
// Playsound.Flags bitmask: 0/2/4=without/with distance dependent/radius
if (step.script->Playsound.Flags & SF_PLAYSOUND_DISTANCE_RADIUS)
object->PlayRadiusSound(step.script->Playsound.SoundID, step.script->Playsound.Radius);
else if (step.script->Playsound.Flags & SF_PLAYSOUND_DISTANCE_SOUND)
object->PlayDistanceSound(step.script->Playsound.SoundID, player);
else
object->PlayDirectSound(step.script->Playsound.SoundID, player);

View File

@@ -49,6 +49,7 @@
#include "World.h"
#include "WorldPacket.h"
#include "WorldSocket.h"
#include "WorldState.h"
#include <zlib.h>
#include "BanMgr.h"
@@ -617,6 +618,7 @@ void WorldSession::LogoutPlayer(bool save)
_player->RepopAtGraveyard();
sOutdoorPvPMgr->HandlePlayerLeaveZone(_player, _player->GetZoneId());
sWorldState->HandlePlayerLeaveZone(_player, static_cast<WorldStateZoneId>(_player->GetZoneId()));
// pussywizard: remove from battleground queues on logout
for (int i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)

View File

@@ -1389,18 +1389,6 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000yd
});
// A'dal's Song of Battle
ApplySpellFix({ 39953 }, [](SpellInfo* spellInfo)
{
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_SRC_CASTER);
spellInfo->Effects[EFFECT_1].TargetA = SpellImplicitTargetInfo(TARGET_SRC_CASTER);
spellInfo->Effects[EFFECT_2].TargetA = SpellImplicitTargetInfo(TARGET_SRC_CASTER);
spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY);
spellInfo->Effects[EFFECT_1].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY);
spellInfo->Effects[EFFECT_2].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY);
spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(367); // 2 Hours
});
ApplySpellFix({
57607, // WintergraspCatapult - Spell Plague Barrel - EffectRadiusIndex
57619, // WintergraspDemolisher - Spell Hourl Boulder - EffectRadiusIndex

View File

@@ -92,6 +92,7 @@
#include "WhoListCacheMgr.h"
#include "WorldPacket.h"
#include "WorldSession.h"
#include "WorldState.h"
#include <boost/asio/ip/address.hpp>
#include <cmath>
@@ -2411,6 +2412,11 @@ void World::Update(uint32 diff)
sOutdoorPvPMgr->Update(diff);
}
{
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update worldstate"));
sWorldState->Update(diff);
}
{
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update battlefields"));
sBattlefieldMgr->Update(diff);

View File

@@ -0,0 +1,293 @@
/*
* This file is part of the AzerothCore 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 Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero 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 "MapMgr.h"
#include "Player.h"
#include "SharedDefines.h"
#include "WorldState.h"
WorldState* WorldState::instance()
{
static WorldState instance;
return &instance;
}
WorldState::WorldState() : _isMagtheridonHeadSpawnedHorde(false), _isMagtheridonHeadSpawnedAlliance(false)
{
_transportStates[WORLD_STATE_CONDITION_THE_IRON_EAGLE] = WORLD_STATE_CONDITION_STATE_NONE;
_transportStates[WORLD_STATE_CONDITION_THE_PURPLE_PRINCESS] = WORLD_STATE_CONDITION_STATE_NONE;
_transportStates[WORLD_STATE_CONDITION_THE_THUNDERCALLER] = WORLD_STATE_CONDITION_STATE_NONE;
}
WorldState::~WorldState()
{
}
bool WorldState::IsConditionFulfilled(WorldStateCondition conditionId, WorldStateConditionState state) const
{
switch (conditionId)
{
case WORLD_STATE_CONDITION_TROLLBANES_COMMAND:
return _isMagtheridonHeadSpawnedAlliance;
case WORLD_STATE_CONDITION_NAZGRELS_FAVOR:
return _isMagtheridonHeadSpawnedHorde;
case WORLD_STATE_CONDITION_THE_IRON_EAGLE:
case WORLD_STATE_CONDITION_THE_PURPLE_PRINCESS:
case WORLD_STATE_CONDITION_THE_THUNDERCALLER:
return _transportStates.at(conditionId) == state;
default:
LOG_ERROR("scripts", "WorldState::IsConditionFulfilled: Unhandled WorldStateCondition {}", conditionId);
return false;
}
}
void WorldState::HandleConditionStateChange(WorldStateCondition conditionId, WorldStateConditionState state)
{
_transportStates[conditionId] = state;
}
void WorldState::HandleExternalEvent(WorldStateEvent eventId, uint32 param)
{
std::lock_guard<std::mutex> guard(_mutex);
switch (eventId)
{
case WORLD_STATE_CUSTOM_EVENT_ON_ADALS_SONG_OF_BATTLE:
if (!_adalSongOfBattleTimer)
{
_adalSongOfBattleTimer = 120 * MINUTE * IN_MILLISECONDS;
BuffAdalsSongOfBattle();
}
break;
case WORLD_STATE_CUSTOM_EVENT_ON_MAGTHERIDON_HEAD_SPAWN:
if (param == TEAM_ALLIANCE)
{
_isMagtheridonHeadSpawnedAlliance = true;
BuffMagtheridonTeam(TEAM_ALLIANCE);
}
else
{
_isMagtheridonHeadSpawnedHorde = true;
BuffMagtheridonTeam(TEAM_HORDE);
}
break;
case WORLD_STATE_CUSTOM_EVENT_ON_MAGTHERIDON_HEAD_DESPAWN:
if (param == TEAM_ALLIANCE)
{
_isMagtheridonHeadSpawnedAlliance = false;
DispelMagtheridonTeam(TEAM_ALLIANCE);
}
else
{
_isMagtheridonHeadSpawnedHorde = false;
DispelMagtheridonTeam(TEAM_HORDE);
}
break;
default:
break;
}
}
void WorldState::Update(uint32 diff)
{
if (_adalSongOfBattleTimer)
{
if (_adalSongOfBattleTimer <= diff)
{
_adalSongOfBattleTimer = 0;
DispelAdalsSongOfBattle();
}
else
{
_adalSongOfBattleTimer -= diff;
}
}
}
void WorldState::HandlePlayerEnterZone(Player* player, WorldStateZoneId zoneId)
{
std::lock_guard<std::mutex> guard(_mutex);
switch (zoneId)
{
case ZONEID_SHATTRATH:
case ZONEID_BOTANICA:
case ZONEID_MECHANAR:
case ZONEID_ARCATRAZ:
if (_adalSongOfBattleTimer)
player->CastSpell(player, SPELL_ADAL_SONG_OF_BATTLE, true);
break;
case ZONEID_HELLFIRE_PENINSULA:
case ZONEID_HELLFIRE_RAMPARTS:
case ZONEID_HELLFIRE_CITADEL:
case ZONEID_BLOOD_FURNACE:
case ZONEID_SHATTERED_HALLS:
case ZONEID_MAGTHERIDON_LAIR:
if (_isMagtheridonHeadSpawnedAlliance && player->GetTeamId() == TEAM_ALLIANCE)
player->CastSpell(player, SPELL_TROLLBANES_COMMAND, true);
else if (_isMagtheridonHeadSpawnedHorde && player->GetTeamId() == TEAM_HORDE)
player->CastSpell(player, SPELL_NAZGRELS_FAVOR, true);
break;
default:
break;
}
};
void WorldState::HandlePlayerLeaveZone(Player* player, WorldStateZoneId zoneId)
{
std::lock_guard<std::mutex> guard(_mutex);
switch (zoneId)
{
case ZONEID_SHATTRATH:
case ZONEID_BOTANICA:
case ZONEID_MECHANAR:
case ZONEID_ARCATRAZ:
if (!_adalSongOfBattleTimer)
player->RemoveAurasDueToSpell(SPELL_ADAL_SONG_OF_BATTLE);
break;
case ZONEID_HELLFIRE_PENINSULA:
case ZONEID_HELLFIRE_RAMPARTS:
case ZONEID_HELLFIRE_CITADEL:
case ZONEID_BLOOD_FURNACE:
case ZONEID_SHATTERED_HALLS:
case ZONEID_MAGTHERIDON_LAIR:
if (player->GetTeamId() == TEAM_ALLIANCE)
player->RemoveAurasDueToSpell(SPELL_TROLLBANES_COMMAND);
else if (player->GetTeamId() == TEAM_HORDE)
player->RemoveAurasDueToSpell(SPELL_NAZGRELS_FAVOR);
break;
default:
break;
}
};
void WorldState::BuffMagtheridonTeam(TeamId team)
{
sMapMgr->DoForAllMaps([&](Map* map) -> void
{
switch (map->GetId())
{
case 530: // Outland
map->DoForAllPlayers([&](Player* player)
{
if (player->GetZoneId() == ZONEID_HELLFIRE_PENINSULA && player->GetTeamId() == TEAM_ALLIANCE && team == TEAM_ALLIANCE)
player->CastSpell(player, SPELL_TROLLBANES_COMMAND, true);
else if (player->GetZoneId() == ZONEID_HELLFIRE_PENINSULA && player->GetTeamId() == TEAM_HORDE && team == TEAM_HORDE)
player->CastSpell(player, SPELL_NAZGRELS_FAVOR, true);
});
break;
case 540: // The Shattered Halls
case 542: // The Blood Furnace
case 543: // Ramparts
case 544: // Magtheridon's Lair
map->DoForAllPlayers([&](Player* player)
{
if (player->GetTeamId() == TEAM_ALLIANCE && team == TEAM_ALLIANCE)
player->CastSpell(player, SPELL_TROLLBANES_COMMAND, true);
else if (player->GetTeamId() == TEAM_HORDE && team == TEAM_HORDE)
player->CastSpell(player, SPELL_NAZGRELS_FAVOR, true);
});
break;
default:
break;
}
});
}
void WorldState::DispelMagtheridonTeam(TeamId team)
{
sMapMgr->DoForAllMaps([&](Map* map) -> void
{
switch (map->GetId())
{
case 530: // Outland
map->DoForAllPlayers([&](Player* player)
{
if (player->GetZoneId() == ZONEID_HELLFIRE_PENINSULA && player->GetTeamId() == TEAM_ALLIANCE && team == TEAM_ALLIANCE)
player->RemoveAurasDueToSpell(SPELL_TROLLBANES_COMMAND);
else if (player->GetZoneId() == ZONEID_HELLFIRE_PENINSULA && player->GetTeamId() == TEAM_HORDE && team == TEAM_HORDE)
player->RemoveAurasDueToSpell(SPELL_NAZGRELS_FAVOR);
});
break;
case 540: // The Shattered Halls
case 542: // The Blood Furnace
case 543: // Ramparts
case 544: // Magtheridon's Lair
map->DoForAllPlayers([&](Player* player)
{
if (player->GetTeamId() == TEAM_ALLIANCE && team == TEAM_ALLIANCE)
player->RemoveAurasDueToSpell(SPELL_TROLLBANES_COMMAND);
else if (player->GetTeamId() == TEAM_HORDE && team == TEAM_HORDE)
player->RemoveAurasDueToSpell(SPELL_NAZGRELS_FAVOR);
});
break;
default:
break;
}
});
}
void WorldState::BuffAdalsSongOfBattle()
{
sMapMgr->DoForAllMaps([&](Map* map) -> void
{
switch (map->GetId())
{
case 530: // Outland
map->DoForAllPlayers([&](Player* player)
{
if (player->GetZoneId() == ZONEID_SHATTRATH)
player->CastSpell(player, SPELL_ADAL_SONG_OF_BATTLE, true);
});
break;
case 552: // Arcatraz
case 553: // Botanica
case 554: // Mechanar
map->DoForAllPlayers([&](Player* player)
{
player->CastSpell(player, SPELL_ADAL_SONG_OF_BATTLE, true);
});
break;
default:
break;
}
});
}
void WorldState::DispelAdalsSongOfBattle()
{
sMapMgr->DoForAllMaps([&](Map* map) -> void
{
switch (map->GetId())
{
case 530: // Outland
map->DoForAllPlayers([&](Player* player)
{
if (player->GetZoneId() == ZONEID_SHATTRATH)
player->RemoveAurasDueToSpell(SPELL_ADAL_SONG_OF_BATTLE);
});
break;
case 552: // Arcatraz
case 553: // Botanica
case 554: // Mechanar
map->DoForAllPlayers([&](Player* player)
{
player->RemoveAurasDueToSpell(SPELL_ADAL_SONG_OF_BATTLE);
});
break;
default:
break;
}
});
}

View File

@@ -0,0 +1,95 @@
/*
* This file is part of the AzerothCore 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 Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero 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/>.
*/
#ifndef WORLD_STATE_H
#define WORLD_STATE_H
#include "Player.h"
#include <atomic>
enum WorldStateCondition
{
WORLD_STATE_CONDITION_TROLLBANES_COMMAND = 39911,
WORLD_STATE_CONDITION_NAZGRELS_FAVOR = 39913,
// Zeppelins
WORLD_STATE_CONDITION_THE_THUNDERCALLER = 164871,
WORLD_STATE_CONDITION_THE_IRON_EAGLE = 175080,
WORLD_STATE_CONDITION_THE_PURPLE_PRINCESS = 176495,
};
enum WorldStateConditionState
{
WORLD_STATE_CONDITION_STATE_NONE = 0,
};
enum WorldStateEvent
{
WORLD_STATE_CUSTOM_EVENT_ON_ADALS_SONG_OF_BATTLE = 39953,
WORLD_STATE_CUSTOM_EVENT_ON_MAGTHERIDON_HEAD_SPAWN = 184640,
WORLD_STATE_CUSTOM_EVENT_ON_MAGTHERIDON_HEAD_DESPAWN = 184641,
};
enum WorldStateZoneId
{
ZONEID_SHATTRATH = 3703,
ZONEID_BOTANICA = 3847,
ZONEID_ARCATRAZ = 3848,
ZONEID_MECHANAR = 3849,
ZONEID_HELLFIRE_PENINSULA = 3483,
ZONEID_HELLFIRE_RAMPARTS = 3562,
ZONEID_HELLFIRE_CITADEL = 3563,
ZONEID_BLOOD_FURNACE = 3713,
ZONEID_SHATTERED_HALLS = 3714,
ZONEID_MAGTHERIDON_LAIR = 3836,
};
enum WorldStateSpells
{
SPELL_ADAL_SONG_OF_BATTLE = 39953,
SPELL_TROLLBANES_COMMAND = 39911,
SPELL_NAZGRELS_FAVOR = 39913,
};
// Intended for implementing server wide scripts, note: all behaviour must be safeguarded towards multithreading
class WorldState
{
public:
WorldState();
virtual ~WorldState();
static WorldState* instance();
void HandlePlayerEnterZone(Player* player, WorldStateZoneId zoneId);
void HandlePlayerLeaveZone(Player* player, WorldStateZoneId zoneId);
bool IsConditionFulfilled(WorldStateCondition conditionId, WorldStateConditionState state = WORLD_STATE_CONDITION_STATE_NONE) const;
void HandleConditionStateChange(WorldStateCondition conditionId, WorldStateConditionState state);
void HandleExternalEvent(WorldStateEvent eventId, uint32 param);
void Update(uint32 diff);
private:
void BuffAdalsSongOfBattle();
void DispelAdalsSongOfBattle();
uint32 _adalSongOfBattleTimer;
void BuffMagtheridonTeam(TeamId team);
void DispelMagtheridonTeam(TeamId team);
bool _isMagtheridonHeadSpawnedHorde;
bool _isMagtheridonHeadSpawnedAlliance;
std::map<WorldStateCondition, std::atomic<WorldStateConditionState>> _transportStates; // atomic to avoid having to lock
std::mutex _mutex; // all World State operations are threat unsafe
};
#define sWorldState WorldState::instance()
#endif

View File

@@ -24,6 +24,7 @@
#include "ScriptedGossip.h"
#include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "WorldState.h"
enum q10935Exorcism
{
@@ -602,6 +603,26 @@ public:
}
};
struct go_magtheridons_head : public GameObjectAI
{
go_magtheridons_head(GameObject* gameObject) : GameObjectAI(gameObject) { }
void InitializeAI() override
{
me->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); // spawn head on spike
me->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
sWorldState->HandleExternalEvent(WORLD_STATE_CUSTOM_EVENT_ON_MAGTHERIDON_HEAD_SPAWN, me->GetPositionX() > 0.f ? TEAM_HORDE : TEAM_ALLIANCE);
}
void OnStateChanged(uint32 state, Unit* /*unit*/) override
{
if (state == GO_JUST_DEACTIVATED)
{
sWorldState->HandleExternalEvent(WORLD_STATE_CUSTOM_EVENT_ON_MAGTHERIDON_HEAD_DESPAWN, me->GetPositionX() > 0.f ? TEAM_HORDE : TEAM_ALLIANCE);
}
}
};
void AddSC_hellfire_peninsula()
{
// Ours
@@ -615,4 +636,5 @@ void AddSC_hellfire_peninsula()
new go_beacon();
RegisterCreatureAI(npc_magister_aledis);
RegisterGameObjectAI(go_magtheridons_head);
}

View File

@@ -554,26 +554,6 @@ class spell_gen_rallying_cry_of_the_dragonslayer : public SpellScript
}
};
// 39953 - A'dal's Song of Battle
class spell_gen_adals_song_of_battle : public SpellScript
{
PrepareSpellScript(spell_gen_adals_song_of_battle);
void SelectTarget(std::list<WorldObject*>& targets)
{
targets.clear();
Map::PlayerList const& pList = GetCaster()->GetMap()->GetPlayers();
for (Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
if (itr->GetSource()->GetZoneId() == 3703 /*Shattrath*/)
targets.push_back(itr->GetSource());
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gen_adals_song_of_battle::SelectTarget, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ALLY);
}
};
/* 15366 - Songflower Serenade
22888 - Rallying Cry of the Dragonslayer */
class spell_gen_disabled_above_63 : public AuraScript
@@ -5336,7 +5316,6 @@ void AddSC_generic_spell_scripts()
RegisterSpellScript(spell_pet_hit_expertise_scalling);
RegisterSpellScript(spell_gen_grow_flower_patch);
RegisterSpellScript(spell_gen_rallying_cry_of_the_dragonslayer);
RegisterSpellScript(spell_gen_adals_song_of_battle);
RegisterSpellScript(spell_gen_disabled_above_63);
RegisterSpellScript(spell_gen_black_magic_enchant);
RegisterSpellScript(spell_gen_area_aura_select_players);

View File

@@ -0,0 +1,68 @@
/*
* This file is part of the AzerothCore 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 Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero 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/>.
*/
enum ZeppelinEvent
{
EVENT_UC_FROM_GROMGOL_ARRIVAL = 15312,
EVENT_GROMGOL_FROM_UC_ARRIVAL = 15314,
EVENT_OG_FROM_UC_ARRIVAL = 15318,
EVENT_UC_FROM_OG_ARRIVAL = 15320,
EVENT_OG_FROM_GROMGOL_ARRIVAL = 15322,
EVENT_GROMGOL_FROM_OG_ARRIVAL = 15324,
EVENT_WK_ARRIVAL = 15431,
EVENT_VL_FROM_UC_ARRIVAL = 19126,
EVENT_UC_FROM_VL_ARRIVAL = 19127,
EVENT_OG_FROM_BT_ARRIVAL = 19137,
EVENT_BT_FROM_OG_ARRIVAL = 19139,
EVENT_OG_FROM_TB_ARRIVAL = 21868,
EVENT_TB_FROM_OG_ARRIVAL = 21870,
EVENT_OG_TO_GROMGOL_DEPARTURE = 15323,
EVENT_GROMGOL_TO_OG_DEPARTURE = 15325,
EVENT_OG_TO_UC_DEPARTURE = 15319,
EVENT_UC_TO_OG_DEPARTURE = 15321,
EVENT_UC_TO_GROMGOL_DEPARTURE = 15313,
EVENT_GROMGOL_TO_UC_DEPARTURE = 15315,
};
enum ZeppelinMaster
{
NPC_NEZRAZ = 3149,
NPC_HINDENBURG = 3150,
NPC_FREZZA = 9564,
NPC_ZAPETTA = 9566,
NPC_SNURK_BUCKSQUICK = 12136,
NPC_SQUIBBY_OVERSPECK = 12137,
NPC_HARROWMEISER = 23823,
NPC_GREEB_RAMROCKET = 26537,
NPC_NARGO_SCREWBORE = 26538,
NPC_MEEFI_FARTHROTTLE = 26539,
NPC_DRENK_SPANNERSPARK = 26540,
NPC_ZELLI_HOTNOZZLE = 34765,
NPC_KRENDLE_BIGPOCKETS = 34766,
};
const float SEARCH_RANGE_ZEPPELIN_MASTER = 32.0f;
enum ZeppelinPassenger
{
// The Thundercaller
NPC_SKY_CAPTAIN_CLOUDKICKER = 25077,
NPC_CHIEF_OFFICER_COPPERNUT = 25070,
// The Purple Princess
NPC_SKY_CAPTAIN_CABLELAMP = 25105,
NPC_WATCHER_UMJIN = 25107,
};

View File

@@ -0,0 +1,109 @@
/*
* This file is part of the AzerothCore 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 Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero 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 "GameObjectAI.h"
#include "GameObjectScript.h"
#include "WorldState.h"
#include "transport_zeppelin.h"
// 175080 The Iron Eagle - Grom'gol to Orgrimmar
struct go_transport_the_iron_eagle : GameObjectAI
{
go_transport_the_iron_eagle(GameObject *object) : GameObjectAI(object) { };
void EventInform(uint32 eventId) override
{
sWorldState->HandleConditionStateChange(WORLD_STATE_CONDITION_THE_IRON_EAGLE, static_cast<WorldStateConditionState>(eventId));
switch (eventId)
{
case EVENT_GROMGOL_FROM_OG_ARRIVAL:
if (Creature *creature = me->FindNearestCreature(NPC_NEZRAZ, SEARCH_RANGE_ZEPPELIN_MASTER))
creature->AI()->Talk(0);
break;
case EVENT_OG_FROM_GROMGOL_ARRIVAL:
if (Creature *creature = me->FindNearestCreature(NPC_SNURK_BUCKSQUICK, 150.0f))
creature->AI()->Talk(0);
break;
default:
return;
}
}
};
// 164871 The Thundercaller - Undercity to Orgrimmar
struct go_transport_the_thundercaller : GameObjectAI
{
go_transport_the_thundercaller(GameObject *object) : GameObjectAI(object) { };
void EventInform(uint32 eventId) override
{
sWorldState->HandleConditionStateChange(WORLD_STATE_CONDITION_THE_THUNDERCALLER, static_cast<WorldStateConditionState>(eventId));
switch (eventId)
{
case EVENT_OG_FROM_UC_ARRIVAL:
if (Creature *creature = me->FindNearestCreature(NPC_FREZZA, SEARCH_RANGE_ZEPPELIN_MASTER))
creature->AI()->Talk(0);
break;
case EVENT_UC_FROM_OG_ARRIVAL:
if (Creature *creature = me->FindNearestCreature(NPC_ZAPETTA, SEARCH_RANGE_ZEPPELIN_MASTER))
creature->AI()->Talk(0);
break;
case EVENT_OG_TO_UC_DEPARTURE:
break;
case EVENT_UC_TO_OG_DEPARTURE:
if (Creature *creature = me->FindNearestCreature(NPC_ZAPETTA, SEARCH_RANGE_ZEPPELIN_MASTER))
creature->AI()->Talk(1);
break;
default:
return;
}
}
};
// 176495 The Purple Princess - Grom'Gol to Undercity
struct go_transport_the_purple_princess : GameObjectAI
{
go_transport_the_purple_princess(GameObject *object) : GameObjectAI(object) { };
void EventInform(uint32 eventId) override
{
sWorldState->HandleConditionStateChange(WORLD_STATE_CONDITION_THE_PURPLE_PRINCESS, static_cast<WorldStateConditionState>(eventId));
switch (eventId)
{
case EVENT_GROMGOL_FROM_UC_ARRIVAL:
if (Creature *creature = me->FindNearestCreature(NPC_SQUIBBY_OVERSPECK, SEARCH_RANGE_ZEPPELIN_MASTER))
creature->AI()->Talk(0);
break;
case EVENT_UC_FROM_GROMGOL_ARRIVAL:
if (Creature *creature = me->FindNearestCreature(NPC_HINDENBURG, SEARCH_RANGE_ZEPPELIN_MASTER))
creature->AI()->Talk(0);
break;
case EVENT_UC_TO_GROMGOL_DEPARTURE:
case EVENT_GROMGOL_TO_UC_DEPARTURE:
break;
default:
return;
}
}
};
void AddSC_transport_zeppelins()
{
RegisterGameObjectAI(go_transport_the_iron_eagle);
RegisterGameObjectAI(go_transport_the_thundercaller);
RegisterGameObjectAI(go_transport_the_purple_princess);
}

View File

@@ -32,6 +32,7 @@ void AddSC_action_ip_logger(); // location: scripts\World\action_ip_logger.cpp
void AddSC_player_scripts();
void AddSC_npc_stave_of_ancients();
void AddSC_server_mail();
void AddSC_transport_zeppelins();
// The name of this function should match:
// void Add${NameOfDirectory}Scripts()
@@ -53,4 +54,5 @@ void AddWorldScripts()
AddSC_player_scripts();
AddSC_npc_stave_of_ancients();
AddSC_server_mail();
AddSC_transport_zeppelins();
}