Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2024-06-03 23:16:28 +08:00
40 changed files with 555 additions and 243 deletions
+1
View File
@@ -47,6 +47,7 @@ runs:
shell: bash
run: |
sudo apt update
sudo apt remove needrestart #refer: https://github.com/actions/runner-images/issues/9937
sudo apt-get -y install ccache clang cmake curl google-perftools \
libmysqlclient-dev make unzip build-essential cmake-data \
libboost-all-dev libbz2-dev libncurses5-dev libmysql++-dev \
+35 -18
View File
@@ -1,37 +1,54 @@
file-cpp:
- src/**/*.cpp
- src/**/*.h
- deps/**/*.cpp
- deps/**/*.h
- changed-files:
- any-glob-to-any-file:
- src/**/*.cpp
- src/**/*.h
- deps/**/*.cpp
- deps/**/*.h
DB:
- data/**/*.sql
- changed-files:
- any-glob-to-any-file: data/**/*.sql
CORE:
- any: ['src/**/*', '!src/server/scripts/*', '!src/tests/*']
- all:
- changed-files:
- any-glob-to-any-file: 'src/**/*'
- all-globs-to-all-files:
- '!src/server/scripts/*'
- '!src/tests/*'
Script:
- src/server/scripts/**/*.cpp
- src/server/scripts/**/*.h
- changed-files:
- any-glob-to-any-file:
- src/server/scripts/**/*.cpp
- src/server/scripts/**/*.h
UnitTests:
- src/test/**/*
- changed-files:
- any-glob-to-any-file: src/test/**/*
Documentation:
- ./*.md
- changed-files:
- any-glob-to-any-file: ./*.md
Bash:
- ./*.sh
- apps/**/*.sh
- conf/**/*.sh
- deps/**/*.sh
- modules/**/*.sh
- changed-files:
- any-glob-to-any-file:
- ./*.sh
- apps/**/*.sh
- conf/**/*.sh
- deps/**/*.sh
- modules/**/*.sh
CMake:
- ./*.cmake
- changed-files:
- any-glob-to-any-file: ./*.cmake
Workflow:
- .github/workflows/*
- changed-files:
- any-glob-to-any-file: .github/workflows/*
Batch:
- apps/**/*.bat
- changed-files:
- any-glob-to-any-file: apps/**/*.bat
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
- uses: actions/checkout@v4
with:
persist-credentials: true
- uses: actions/labeler@v4
- uses: actions/labeler@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
configuration-path: .github/labeler.yml
+1 -1
View File
@@ -3,7 +3,7 @@
## Warning
The code of AzerothCore is shipped as it is without any form of warranty,
and - except for third party libraries licensed under the AGPL 3,
which you can read from the file "LICENSE-AGPL3".
which you can read from the file "LICENSE".
## Point of current development
The project is currently hosted at https://www.azerothcore.org/ and developed under https://github.com/azerothcore
+1 -1
View File
@@ -1,5 +1,5 @@
#
# Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
# Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
# Copyright (C) 2021+ WarheadCore <https://github.com/WarheadCore>
#
# This file is free software; as a special exception the author gives
@@ -0,0 +1,3 @@
-- DB update 2024_05_25_01 -> 2024_05_26_00
--
UPDATE `spell_proc_event` SET `Cooldown`=600 WHERE `entry`=69762;
@@ -0,0 +1,5 @@
-- DB update 2024_05_26_00 -> 2024_05_26_01
--
DELETE FROM `creature_text` WHERE (`CreatureID` = 22515) AND (`GroupID` = 19);
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(22515, 19, 0, 'The Ancient Gate of the Keepers unlocks!', 41, 0, 100, 0, 0, 0, 34401, 0, 'Ulduar - The Ancient Gate of the Keepers unlocks!');
@@ -0,0 +1,6 @@
-- DB update 2024_05_26_01 -> 2024_05_26_02
--
DELETE FROM `creature` WHERE `id1` = 33742;
INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`) VALUES
(136768, 33742, 0, 0, 603, 0, 0, 3, 1, 0, 1809.8663330078125, -38.2449531555175781, 408.03680419921875, 0, 180, 0, 0, 26066, 0, 0, 0, 0, 0, '', 47720);
UPDATE `creature_template` SET `ScriptName` = 'boss_kologarn_pit_kill_bunny' WHERE `entry` = 33742;
@@ -0,0 +1,24 @@
-- DB update 2024_05_26_02 -> 2024_05_27_00
-- update DONT_OVERRIDE_SAI_ENTRY
-- #18734
UPDATE `creature_template` SET `flags_extra` = 134217728 WHERE (`entry` = 4300);
UPDATE `creature_template` SET `flags_extra` = 134217728 WHERE (`entry` = 4301);
UPDATE `creature_template` SET `flags_extra` = 134217728 WHERE (`entry` = 4294);
UPDATE `creature_template` SET `flags_extra` = 134217728 WHERE (`entry` = 4295);
UPDATE `creature_template` SET `flags_extra` = 134217728 WHERE (`entry` = 4299);
DELETE FROM `smart_scripts` WHERE (`source_type` = 9 AND `entryorguid` = 429400);
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
(429400, 9, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 2, 35, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Monaster AshbringerEvent - Actionlist - Set_Faction Friend'),
(429400, 9, 1, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Monaster AshbringerEvent - Actionlist - stop movement'),
-- new add
(429400, 9, 2, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 212, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Monaster AshbringerEvent - Actionlist - Stop motion (StopMoving: 1, MovementExpired: 1)'),
(429400, 9, 3, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Monaster AshbringerEvent - Actionlist - Set Facing player'),
(429400, 9, 4, 0, 0, 0, 100, 0, 500, 500, 0, 0, 0, 0, 91, 8, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Monaster AshbringerEvent - Actionlist - SetStandState UNIT_STAND_STATE_STAND'),
(429400, 9, 5, 0, 0, 0, 100, 0, 500, 2500, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Monaster AshbringerEvent - Actionlist - SetSheath SHEATH_STATE_UNARMED'),
(429400, 9, 6, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 90, 8, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Monaster AshbringerEvent - Actionlist - SetSheath UNIT_STAND_STATE_KNEEL'),
(429400, 9, 7, 0, 0, 0, 50, 0, 1000, 2000, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'Scarlet Monaster AshbringerEvent - Actionlist - Talk 0');
-- #18850 fix
UPDATE `creature_template` SET `flags_extra` = 134217728 WHERE (`entry` = 27202);
UPDATE `creature_template` SET `flags_extra` = 134217728 WHERE (`entry` = 27203);
@@ -0,0 +1,5 @@
-- DB update 2024_05_27_00 -> 2024_05_27_01
--
DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_azgalor_doom' AND `spell_id` = 31347;
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(31347, 'spell_azgalor_doom');
@@ -0,0 +1,5 @@
-- DB update 2024_05_27_01 -> 2024_05_27_02
--
DELETE FROM `spell_linked_spell` WHERE `spell_trigger` = -42201 AND `spell_effect` = 42205;
INSERT INTO `spell_linked_spell` (`spell_trigger`, `spell_effect`, `type`, `comment`) VALUES
(-42201, 42205, 0, 'Eternal Silence trigger Residue of Eternity on removal');
@@ -0,0 +1,20 @@
-- DB update 2024_05_27_02 -> 2024_05_28_00
--
-- Rocket Booster
UPDATE `gameobject` SET `position_x`=2307.000003, `position_y`=265.6011, `position_z`=424.287993 WHERE (`id` = 194904) AND (`guid` IN (35524));
-- Delete 2nd Activate Tram gameobject
DELETE FROM `gameobject` WHERE `id` = 194438;
UPDATE `gameobject_template` SET `ScriptName` = '' WHERE `entry` = 194438;
-- Call Tram objects start as non-selectable
UPDATE `gameobject_template_addon` SET `flags` = `flags` | 16 WHERE `entry` IN (194912, 194914);
-- Buttons
UPDATE `gameobject_template` SET `AIName` = 'SmartGameObjectAI', `ScriptName` = '' WHERE `entry` IN (194437,194912,194914);
DELETE FROM `smart_scripts` WHERE (`entryorguid` IN (194437,194912,194914)) AND (`source_type` = 1);
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
(194437, 1, 0, 0, 11, 0, 100, 0, 0, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Activate Tram - On Respawn - Set Event Phase 1'),
(194437, 1, 1, 2, 64, 1, 100, 0, 0, 0, 0, 0, 0, 0, 34, 710, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Activate Tram - On Gossip Hello - Set Instance Data 710 to 1 (Phase 1)'),
(194437, 1, 2, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 22, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Activate Tram - On Gossip Hello - Set Event Phase 2 (Phase 1)'),
(194437, 1, 3, 4, 64, 2, 100, 0, 0, 0, 0, 0, 0, 0, 34, 710, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Activate Tram - On Gossip Hello - Set Instance Data 710 to 0 (Phase 2)'),
(194437, 1, 4, 0, 61, 0, 100, 0, 0, 0, 0, 0, 0, 0, 22, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Activate Tram - On Gossip Hello - Set Event Phase 1 (Phase 2)'),
(194912, 1, 0, 0, 64, 0, 100, 0, 0, 0, 0, 0, 0, 0, 34, 710, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Call Tram - On Gossip Hello - Set Instance Data 710 to 1'),
(194914, 1, 0, 0, 64, 0, 100, 0, 0, 0, 0, 0, 0, 0, 34, 710, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Call Tram - On Gossip Hello - Set Instance Data 710 to 0');
@@ -0,0 +1,4 @@
-- DB update 2024_05_28_00 -> 2024_05_29_00
--
DELETE FROM `smart_scripts` WHERE `entryorguid` = 18104 AND `source_type` = 0;
UPDATE `creature_template` SET `speed_run` = 3, `AIName` = '', `ScriptName` = 'npc_doomfire_spirit' WHERE `entry` = 18104;
@@ -0,0 +1,16 @@
-- DB update 2024_05_29_00 -> 2024_06_01_00
UPDATE `gameobject_loot_template` SET `MaxCount` = 6 WHERE `Entry` = 22070 AND `Item` IN (22573, 22574); -- Mote of Fire/Earth
UPDATE `gameobject_loot_template` SET `MaxCount` = 4 WHERE `Entry` = 22070 AND `Item` = 32464; -- Nethercite Ore
UPDATE `item_loot_template` SET `Chance` = 60, `MaxCount` = 3 WHERE `Entry` = 32724 AND `Item` = 32728; -- Sludge
UPDATE `item_loot_template` SET `Chance` = 10 WHERE `Entry` = 32724 AND `Item` = 32727; -- Vial of Tears
UPDATE `item_loot_template` SET `Chance` = 2 WHERE `Entry` = 32724 AND `Item` = 32726; -- Murkblood Escape Plans
UPDATE `item_loot_template` SET `Chance` = 5 WHERE `Entry` = 32724 AND `Item` IN (32464, 32468, 32470); -- Ore, Pollen, Hide
UPDATE `creature_loot_template` SET `Chance` = 50 WHERE `Item` = 32427; -- Netherwing Crystal
UPDATE `creature_loot_template` SET `Chance` = 100 WHERE `Item` = 32502; -- Fel Gland
UPDATE `creature_loot_template` SET `Chance` = 1 WHERE `Item` = 32506; -- Netherwing Egg
INSERT INTO `gameobject_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
(22070, 32506, 0, 1, 0, 1, 0, 1, 1, 'Nethercite Deposit - Netherwing Egg');
INSERT INTO `item_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
(32724, 32506, 0, 1, 0, 1, 0, 1, 1, 'Sludge-covered Object - Netherwing Egg'),
(32724, 32725, 0, 10, 0, 1, 0, 1, 1, 'Sludge-covered Object - Murkblood Miner''s Pick');
@@ -0,0 +1,5 @@
-- DB update 2024_06_01_00 -> 2024_06_02_00
--
DELETE FROM `achievement_reward` WHERE `ID` = 431;
INSERT INTO `achievement_reward` (`ID`, `TitleA`, `TitleH`, `ItemID`, `Sender`, `Subject`, `Body`, `MailTemplateID`) VALUES
(431, 64, 64, 0, 0, null, null, 0);
+1 -1
View File
@@ -1,5 +1,5 @@
# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
# Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
# Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
+1 -1
View File
@@ -1,5 +1,5 @@
# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
# Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
# Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
+1 -1
View File
@@ -414,7 +414,7 @@ minimal-dynamic - builds commands and spells dynamically. Now don't support
- Example loader script for modules:
```cpp
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
// From SC
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*
* This file was based on
* https://embeddedartistry.com/blog/2017/05/17/creating-a-circular-buffer-in-c-and-c/
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Originally written by Rochet2 - Copyright (C) 2018+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: http://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Originally written by Rochet2 - Copyright (C) 2018+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: http://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE
*/
#ifndef _DATA_MAP_H_
@@ -2176,6 +2176,9 @@ void Player::SetInWater(bool apply)
RemoveAurasWithInterruptFlags(apply ? AURA_INTERRUPT_FLAG_NOT_ABOVEWATER : AURA_INTERRUPT_FLAG_NOT_UNDERWATER);
getHostileRefMgr().updateThreatTables();
if (InstanceScript* instance = GetInstanceScript())
instance->OnPlayerInWaterStateUpdate(this, apply);
}
bool Player::IsInAreaTriggerRadius(AreaTrigger const* trigger, float delta) const
@@ -436,31 +436,27 @@ void Player::UpdateNextMailTimeAndUnreads()
{
// Update the next delivery time and unread mails
time_t cTime = GameTime::GetGameTime().count();
// Get the next delivery time
CharacterDatabasePreparedStatement* stmtNextDeliveryTime =
CharacterDatabase.GetPreparedStatement(CHAR_SEL_NEXT_MAIL_DELIVERYTIME);
stmtNextDeliveryTime->SetData(0, GetGUID().GetCounter());
stmtNextDeliveryTime->SetData(1, uint32(cTime));
PreparedQueryResult resultNextDeliveryTime =
CharacterDatabase.Query(stmtNextDeliveryTime);
if (resultNextDeliveryTime)
{
Field* fields = resultNextDeliveryTime->Fetch();
m_nextMailDelivereTime = time_t(fields[0].Get<uint32>());
}
// Get unread mails count
CharacterDatabasePreparedStatement* stmtUnreadAmount =
CharacterDatabase.GetPreparedStatement(
CHAR_SEL_CHARACTER_MAILCOUNT_UNREAD_SYNCH);
stmtUnreadAmount->SetData(0, GetGUID().GetCounter());
stmtUnreadAmount->SetData(1, uint32(cTime));
PreparedQueryResult resultUnreadAmount =
CharacterDatabase.Query(stmtUnreadAmount);
if (resultUnreadAmount)
m_nextMailDelivereTime = 0;
unReadMails = 0;
for (Mail const* mail : GetMails())
{
Field* fields = resultUnreadAmount->Fetch();
unReadMails = uint8(fields[0].Get<uint64>());
if (mail->deliver_time > cTime)
{
if (!m_nextMailDelivereTime || m_nextMailDelivereTime > mail->deliver_time)
m_nextMailDelivereTime = mail->deliver_time;
}
// must be not checked yet
if (mail->checked & MAIL_CHECK_MASK_READ)
continue;
// and already delivered or expired
if (cTime < mail->deliver_time || cTime > mail->expire_time)
continue;
unReadMails++;
}
}
+1 -1
View File
@@ -4223,7 +4223,7 @@ void Unit::ProcessTerrainStatusUpdate()
// remove appropriate auras if we are swimming/not swimming respectively
if (liquidData.Status & MAP_LIQUID_STATUS_SWIMMING)
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_ABOVEWATER);
else
else if (!isSwimming())
RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER);
// liquid aura handling
+1 -4
View File
@@ -287,10 +287,7 @@ void WorldSession::HandlePetActionHelper(Unit* pet, ObjectGuid guid1, uint32 spe
case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet)
if (pet->GetCharmerGUID() == GetPlayer()->GetGUID())
{
if (pet->IsSummon())
pet->ToTempSummon()->UnSummon();
else
_player->StopCastingCharm();
_player->StopCastingCharm();
}
else if (pet->GetOwnerGUID() == GetPlayer()->GetGUID())
{
@@ -186,6 +186,9 @@ public:
virtual void OnPlayerAreaUpdate(Player* /*player*/, uint32 /*oldArea*/, uint32 /*newArea*/) {}
//Called when a player enters/leaves water bodies.
virtual void OnPlayerInWaterStateUpdate(Player* /*player*/, bool /*inWater*/) {}
//Handle open / close objects
//use HandleGameObject(ObjectGuid::Empty, boolen, GO); in OnObjectCreate in instance scripts
//use HandleGameObject(GUID, boolen, nullptr); in any other script
+18
View File
@@ -110,3 +110,21 @@ bool BoundaryUnionBoundary::IsWithinBoundaryArea(Position const* pos) const
{
return (_b1->IsWithinBoundary(pos) || _b2->IsWithinBoundary(pos));
}
// ---== INTERSECT OF 2 BOUNDARIES ==---
BoundaryIntersectBoundary::BoundaryIntersectBoundary(AreaBoundary const* b1, AreaBoundary const* b2, bool isInverted) :
AreaBoundary(isInverted), _b1(b1), _b2(b2)
{
ASSERT(b1 && b2);
}
BoundaryIntersectBoundary::~BoundaryIntersectBoundary()
{
delete _b1;
delete _b2;
}
bool BoundaryIntersectBoundary::IsWithinBoundaryArea(Position const* pos) const
{
return (_b1->IsWithinBoundary(pos) && _b2->IsWithinBoundary(pos));
}
+14
View File
@@ -165,4 +165,18 @@ class AC_GAME_API BoundaryUnionBoundary : public AreaBoundary
AreaBoundary const* const _b2;
};
class AC_GAME_API BoundaryIntersectBoundary : public AreaBoundary
{
public:
BoundaryIntersectBoundary(AreaBoundary const* b1, AreaBoundary const* b2, bool isInverted = false);
protected:
virtual ~BoundaryIntersectBoundary();
bool IsWithinBoundaryArea(Position const* pos) const override;
private:
AreaBoundary const* const _b1;
AreaBoundary const* const _b2;
};
#endif //ACORE_AREA_BOUNDARY_H
@@ -65,9 +65,8 @@ public:
context.Repeat(10s, 15s);
}).Schedule(25s, 32s, [this](TaskContext context)
{
if (DoCastRandomTarget(SPELL_SLEEP) == SPELL_CAST_OK)
Talk(SAY_SLEEP);
Talk(SAY_SLEEP);
DoCastRandomTarget(SPELL_SLEEP, 1, 0.0f, true, false, false);
context.Repeat(35s, 48s);
}).Schedule(30s, 48s, [this](TaskContext context)
{
@@ -137,7 +136,6 @@ public:
private:
bool _recentlySpoken;
};
class spell_anetheron_sleep : public SpellScript
@@ -97,8 +97,9 @@ uint32 const availableChargeAurasAndSpells[3][2] = {
Position const nordrassilPosition = { 5503.713f, -3523.436f, 1608.781f, 0.0f };
float const DOOMFIRE_OFFSET = 15.0f;
float const DOOMFIRE_OFFSET = 25.0f;
uint8 const WISP_OFFSET = 40;
uint8 NEAR_POINT = 0;
struct npc_ancient_wisp : public ScriptedAI
{
@@ -148,6 +149,39 @@ private:
InstanceScript* _instance;
};
struct npc_doomfire_spirit : public ScriptedAI
{
npc_doomfire_spirit(Creature* creature) : ScriptedAI(creature)
{
_instance = creature->GetInstanceScript();
}
void Reset() override
{
scheduler.CancelAll();
ScheduleTimedEvent(0s, [&]{
if (Creature* archimonde = _instance->GetCreature(DATA_ARCHIMONDE))
{
Position randomNearPosition = archimonde->GetRandomNearPosition(200.0f);
me->GetMotionMaster()->MovePoint(NEAR_POINT, randomNearPosition);
}
}, 6s);
}
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
if (!UpdateVictim())
return;
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
private:
InstanceScript* _instance;
};
struct boss_archimonde : public BossAI
{
boss_archimonde(Creature* creature) : BossAI(creature, DATA_ARCHIMONDE)
@@ -262,10 +296,7 @@ struct boss_archimonde : public BossAI
}, 25s, 40s);
ScheduleTimedEvent(25s, 35s, [&]
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true, false))
{
DoCastDoomFire(target);
}
DoCastDoomFire();
}, 20s);
ScheduleTimedEvent(25s, 35s, [&]
{
@@ -391,12 +422,12 @@ struct boss_archimonde : public BossAI
}
}
void DoCastDoomFire(Unit* target)
void DoCastDoomFire()
{
// hack because spell doesn't work?
Talk(SAY_DOOMFIRE);
Position spiritPosition = { target->GetPositionX() + DOOMFIRE_OFFSET, target->GetPositionY() + DOOMFIRE_OFFSET, target->GetPositionZ(), 0.0f };
Position doomfirePosition = { target->GetPositionX() - DOOMFIRE_OFFSET, target->GetPositionY() - DOOMFIRE_OFFSET, target->GetPositionZ(), 0.0f };
Position spiritPosition = me->GetRandomNearPosition(DOOMFIRE_OFFSET);
Position doomfirePosition = me->GetRandomNearPosition(DOOMFIRE_OFFSET);
if (Creature* doomfireSpirit = me->SummonCreature(CREATURE_DOOMFIRE_SPIRIT, spiritPosition, TEMPSUMMON_TIMED_DESPAWN, 27000))
{
if (Creature* doomfire = me->SummonCreature(CREATURE_DOOMFIRE, doomfirePosition, TEMPSUMMON_TIMED_DESPAWN, 27000))
@@ -508,5 +539,6 @@ void AddSC_boss_archimonde()
RegisterSpellScript(spell_finger_of_death);
RegisterHyjalAI(boss_archimonde);
RegisterHyjalAI(npc_ancient_wisp);
RegisterHyjalAI(npc_doomfire_spirit);
}
@@ -17,6 +17,8 @@
#include "CreatureScript.h"
#include "ScriptedCreature.h"
#include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "hyjal.h"
enum Spells
@@ -60,7 +62,7 @@ public:
context.Repeat(8s, 16s);
}).Schedule(25s, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_RAIN_OF_FIRE, 0, 40.f);
DoCastRandomTarget(SPELL_RAIN_OF_FIRE, 0, 40.f, false);
context.Repeat(15s);
}).Schedule(30s, [this](TaskContext context)
{
@@ -68,7 +70,7 @@ public:
context.Repeat(18s, 20s);
}).Schedule(45s, 55s, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_DOOM, 0, 100.f, true, false, false);
DoCastRandomTarget(SPELL_DOOM, 1, 100.f, true, false, false);
Talk(SAY_DOOM);
context.Repeat();
}).Schedule(10min, [this](TaskContext context)
@@ -114,10 +116,29 @@ public:
private:
bool _recentlySpoken;
};
class spell_azgalor_doom : public AuraScript
{
PrepareAuraScript(spell_azgalor_doom);
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* target = GetTarget();
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEATH && !IsExpired())
{
target->CastSpell(target, GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, true);
}
}
void Register() override
{
OnEffectRemove += AuraEffectRemoveFn(spell_azgalor_doom::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_boss_azgalor()
{
RegisterHyjalAI(boss_azgalor);
RegisterSpellScript(spell_azgalor_doom);
}
@@ -133,67 +133,51 @@ private:
uint8 _markCounter;
};
class spell_mark_of_kazrogal : public SpellScriptLoader
class spell_mark_of_kazrogal : public SpellScript
{
public:
spell_mark_of_kazrogal() : SpellScriptLoader("spell_mark_of_kazrogal") { }
PrepareSpellScript(spell_mark_of_kazrogal);
class spell_mark_of_kazrogal_SpellScript : public SpellScript
void FilterTargets(std::list<WorldObject*>& targets)
{
PrepareSpellScript(spell_mark_of_kazrogal_SpellScript);
void FilterTargets(std::list<WorldObject*>& targets)
{
targets.remove_if(Acore::PowerCheck(POWER_MANA, false));
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mark_of_kazrogal_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
class spell_mark_of_kazrogal_AuraScript : public AuraScript
{
PrepareAuraScript(spell_mark_of_kazrogal_AuraScript);
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_MARK_DAMAGE });
}
void OnPeriodic(AuraEffect const* aurEff)
{
Unit* target = GetTarget();
if ((int32)target->GetPower(POWER_MANA) < aurEff->GetBaseAmount())
{
target->CastSpell(target, SPELL_MARK_DAMAGE, true, nullptr, aurEff);
// Remove aura
SetDuration(0);
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_mark_of_kazrogal_AuraScript::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_MANA_LEECH);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_mark_of_kazrogal_SpellScript();
targets.remove_if(Acore::PowerCheck(POWER_MANA, false));
}
AuraScript* GetAuraScript() const override
void Register() override
{
return new spell_mark_of_kazrogal_AuraScript();
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mark_of_kazrogal::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
class spell_mark_of_kazrogal_aura : public AuraScript
{
PrepareAuraScript(spell_mark_of_kazrogal_aura);
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_MARK_DAMAGE });
}
void OnPeriodic(AuraEffect const* aurEff)
{
Unit* target = GetTarget();
if ((int32)target->GetPower(POWER_MANA) < aurEff->GetBaseAmount())
{
target->CastSpell(target, SPELL_MARK_DAMAGE, true, nullptr, aurEff);
// Remove aura
SetDuration(0);
}
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_mark_of_kazrogal_aura::OnPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_MANA_LEECH);
}
};
void AddSC_boss_kazrogal()
{
RegisterHyjalAI(boss_kazrogal);
new spell_mark_of_kazrogal();
RegisterSpellAndAuraScriptPair(spell_mark_of_kazrogal, spell_mark_of_kazrogal_aura);
}
@@ -120,7 +120,11 @@ enum HyjalCreaturesIds
NPC_KAZROGAL = 17888,
NPC_AZGALOR = 17842,
NPC_ARCHIMONDE = 17968,
NPC_WORLD_TRIGGER_TINY = 21987
NPC_WORLD_TRIGGER_TINY = 21987,
// Boss summons
NPC_TOWERING_INFERNAL = 17818,
NPC_LESSER_DOOMGUARD = 17864
};
enum HyjalGameobjectIds
@@ -144,7 +148,11 @@ enum HyjalMisc
START_WAVE_HORDE_RETREAT = 39,
START_WAVE_NIGHT_ELF = 42,
CONTEXT_GROUP_WAVES = 1
CONTEXT_GROUP_WAVES = 1,
AREA_NORDRASSIL = 3710,
SPELL_ETERNAL_SILENCE = 42201
};
enum HyjalPaths
@@ -19,6 +19,7 @@
#include "InstanceMapScript.h"
#include "InstanceScript.h"
#include "Opcodes.h"
#include "Player.h"
#include "WorldPacket.h"
#include "hyjal.h"
@@ -101,6 +102,7 @@ public:
trash = 0;
_currentWave = 0;
_encounterNPCs.clear();
_summonedNPCs.clear();
_baseAlliance.clear();
_baseHorde.clear();
_infernalTargets.clear();
@@ -199,6 +201,13 @@ public:
_encounterNPCs.insert(creature->GetGUID()); // Used for despawning on wipe
}
break;
case NPC_TOWERING_INFERNAL:
case NPC_LESSER_DOOMGUARD:
if (creature->IsSummon())
{
_summonedNPCs.insert(creature->GetGUID());
}
break;
}
InstanceScript::OnCreatureCreate(creature);
}
@@ -232,6 +241,10 @@ public:
}
}
break;
case NPC_TOWERING_INFERNAL:
case NPC_LESSER_DOOMGUARD:
_summonedNPCs.erase(unit->ToCreature()->GetGUID());
break;
case NPC_WINTERCHILL:
case NPC_ANETHERON:
case NPC_KAZROGAL:
@@ -401,6 +414,14 @@ public:
if (Creature* creature = instance->GetCreature(guid))
creature->DespawnOrUnsummon();
// also force despawn boss summons
for (ObjectGuid const& guid : _summonedNPCs)
if (Creature* creature = instance->GetCreature(guid))
creature->DespawnOrUnsummon();
if (_bossWave && (GetBossState(_bossWave) != DONE))
SetBossState(_bossWave, NOT_STARTED);
_scheduler.Schedule(300s, [this](TaskContext)
{
for (ObjectGuid const& guid : _baseAlliance)
@@ -419,6 +440,14 @@ public:
if (Creature* creature = instance->GetCreature(guid))
creature->DespawnOrUnsummon();
// also force despawn boss summons
for (ObjectGuid const& guid : _summonedNPCs)
if (Creature* creature = instance->GetCreature(guid))
creature->DespawnOrUnsummon();
if (_bossWave && (GetBossState(_bossWave) != DONE))
SetBossState(_bossWave, NOT_STARTED);
_scheduler.Schedule(300s, [this](TaskContext)
{
for (ObjectGuid const& guid : _baseHorde)
@@ -454,6 +483,7 @@ public:
case DATA_RESET_WAVES:
_scheduler.CancelGroup(CONTEXT_GROUP_WAVES);
_encounterNPCs.clear();
_summonedNPCs.clear();
_currentWave = 0;
trash = 0;
_bossWave = 0;
@@ -530,6 +560,14 @@ public:
_scheduler.Update(diff);
}
void OnPlayerInWaterStateUpdate(Player* player, bool inWater) override
{
if (inWater && player->GetAreaId() == AREA_NORDRASSIL)
{
player->CastSpell(player, SPELL_ETERNAL_SILENCE, true);
}
}
protected:
int32 trash;
uint8 _currentWave;
@@ -537,6 +575,7 @@ public:
uint8 _retreat;
TaskScheduler _scheduler;
GuidSet _encounterNPCs;
GuidSet _summonedNPCs;
GuidSet _baseAlliance;
GuidSet _baseHorde;
GuidVector _infernalTargets;
@@ -2383,20 +2383,45 @@ public:
return GetCaster()->GetTypeId() == TYPEID_UNIT;
}
void CheckEnergy()
void CalculatePower()
{
if (GetCaster()->GetPower(POWER_ENERGY) >= 100)
Unit* caster = GetCaster();
if (!caster)
return;
SpellInfo const* spellInfo = GetSpellInfo();
if (!spellInfo)
return;
// Check if the effect is energize
if (spellInfo->Effects[EFFECT_1].Effect == SPELL_EFFECT_ENERGIZE)
{
GetCaster()->CastSpell(GetCaster(), SPELL_OVERHEAT, true);
if (Vehicle* vehicle = GetCaster()->GetVehicleKit())
if (Unit* passenger = vehicle->GetPassenger(0))
sCreatureTextMgr->SendChat(GetCaster()->ToCreature(), SAY_OVERHEAT, passenger);
int32 energizeAmount = spellInfo->Effects[EFFECT_1].CalcValue(caster);
// Apply the power gain directly to the caster
caster->ModifyPower(POWER_ENERGY, energizeAmount);
}
if (caster->GetPower(POWER_ENERGY) >= 100)
{
caster->CastSpell(caster, SPELL_OVERHEAT, true);
if (Vehicle* vehicle = caster->GetVehicleKit())
if (Unit* passenger = vehicle->GetPassenger(0))
sCreatureTextMgr->SendChat(caster->ToCreature(), SAY_OVERHEAT, passenger);
}
}
void PreventPowerGainOnHit(SpellEffIndex effIndex)
{
PreventHitDefaultEffect(effIndex);
}
void Register() override
{
AfterHit += SpellHitFn(spell_igb_cannon_blast_SpellScript::CheckEnergy);
OnCast += SpellCastFn(spell_igb_cannon_blast_SpellScript::CalculatePower);
OnEffectHitTarget += SpellEffectFn(spell_igb_cannon_blast_SpellScript::PreventPowerGainOnHit, EFFECT_1, SPELL_EFFECT_ENERGIZE);
}
};
@@ -869,85 +869,29 @@ private:
bool _removeHealers;
};
class spell_sindragosa_unchained_magic : public SpellScriptLoader
class spell_sindragosa_unchained_magic : public SpellScript
{
public:
spell_sindragosa_unchained_magic() : SpellScriptLoader("spell_sindragosa_unchained_magic") { }
PrepareSpellScript(spell_sindragosa_unchained_magic);
class spell_sindragosa_unchained_magic_SpellScript : public SpellScript
void FilterTargets(std::list<WorldObject*>& unitList)
{
PrepareSpellScript(spell_sindragosa_unchained_magic_SpellScript);
void FilterTargets(std::list<WorldObject*>& unitList)
{
std::list<WorldObject*> healList = unitList;
std::list<WorldObject*> dpsList = unitList;
unitList.clear();
uint32 maxSize = uint32(GetCaster()->GetMap()->GetSpawnMode() & 1 ? 3 : 1);
healList.remove_if(UnchainedMagicTargetSelector(false));
if (healList.size() > maxSize)
Acore::Containers::RandomResize(healList, maxSize);
dpsList.remove_if(UnchainedMagicTargetSelector(true));
if (dpsList.size() > maxSize)
Acore::Containers::RandomResize(dpsList, maxSize);
unitList.splice(unitList.begin(), healList);
unitList.splice(unitList.begin(), dpsList);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sindragosa_unchained_magic_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_sindragosa_unchained_magic_SpellScript();
std::list<WorldObject*> healList = unitList;
std::list<WorldObject*> dpsList = unitList;
unitList.clear();
uint32 maxSize = uint32(GetCaster()->GetMap()->GetSpawnMode() & 1 ? 3 : 1);
healList.remove_if(UnchainedMagicTargetSelector(false));
if (healList.size() > maxSize)
Acore::Containers::RandomResize(healList, maxSize);
dpsList.remove_if(UnchainedMagicTargetSelector(true));
if (dpsList.size() > maxSize)
Acore::Containers::RandomResize(dpsList, maxSize);
unitList.splice(unitList.begin(), healList);
unitList.splice(unitList.begin(), dpsList);
}
class spell_sindragosa_unchained_magic_AuraScript : public AuraScript
void Register() override
{
PrepareAuraScript(spell_sindragosa_unchained_magic_AuraScript);
std::map<uint32, uint32> _lastMSTimeForSpell;
bool Validate(SpellInfo const* /*spellInfo*/) override
{
_lastMSTimeForSpell.clear();
return true;
}
bool CheckProc(ProcEventInfo& eventInfo)
{
SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
if (!spellInfo)
return false;
uint32 currMSTime = GameTime::GetGameTimeMS().count();
std::map<uint32, uint32>::iterator itr = _lastMSTimeForSpell.find(spellInfo->Id);
if (itr != _lastMSTimeForSpell.end())
{
uint32 lastMSTime = itr->second;
itr->second = currMSTime;
if (getMSTimeDiff(lastMSTime, currMSTime) < 600)
return false;
return true;
}
_lastMSTimeForSpell[spellInfo->Id] = currMSTime;
return true;
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_sindragosa_unchained_magic_AuraScript::CheckProc);
}
};
AuraScript* GetAuraScript() const override
{
return new spell_sindragosa_unchained_magic_AuraScript();
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sindragosa_unchained_magic::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
@@ -2012,7 +1956,7 @@ void AddSC_boss_sindragosa()
new boss_sindragosa();
new npc_ice_tomb();
new spell_sindragosa_s_fury();
new spell_sindragosa_unchained_magic();
RegisterSpellScript(spell_sindragosa_unchained_magic);
new spell_sindragosa_permeating_chill();
new spell_sindragosa_instability();
new spell_sindragosa_icy_grip();
@@ -665,6 +665,37 @@ public:
};
};
struct boss_kologarn_pit_kill_bunny : public NullCreatureAI
{
boss_kologarn_pit_kill_bunny(Creature* creature) : NullCreatureAI(creature) { }
void Reset() override
{
RectangleBoundary* _boundaryXY = new RectangleBoundary(1782.0f, 1832.0f, -56.0f, 8.0f);
ZRangeBoundary* _boundaryZ = new ZRangeBoundary(400.0f, 439.0f);
_boundaryIntersect = new BoundaryIntersectBoundary(_boundaryXY, _boundaryZ);
scheduler.Schedule(0s, [this](TaskContext context)
{
me->GetMap()->DoForAllPlayers([&](Player* player)
{
if (_boundaryIntersect->IsWithinBoundary(player->GetPosition()) && !player->IsGameMaster())
{
player->KillSelf(false);
}
});
context.Repeat(1s);
});
}
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
}
private:
BoundaryIntersectBoundary const* _boundaryIntersect;
};
// predicate function to select non main tank target
class StoneGripTargetSelector
{
@@ -894,6 +925,7 @@ void AddSC_boss_kologarn()
new boss_kologarn();
new boss_kologarn_arms();
new boss_kologarn_eyebeam();
RegisterUlduarCreatureAI(boss_kologarn_pit_kill_bunny);
// Spells
new spell_ulduar_stone_grip_cast_target();
@@ -86,7 +86,8 @@ enum SpellData
SPELL_HAND_PULSE_25_L = 64536,
SPELL_SELF_REPAIR = 64383,
SPELL_SLEEP = 64394,
SPELL_SLEEP_VISUAL_1 = 64393,
SPELL_SLEEP_VISUAL_2 = 64394,
};
enum NPCs
@@ -172,10 +173,11 @@ enum EVENTS
EVENT_JOIN_ACU = 35,
EVENT_START_PHASE4 = 36,
EVENT_FINISH = 50,
EVENT_SAY_VOLTRON_DEAD = 51,
EVENT_DISAPPEAR = 52,
EVENT_BERSERK = 53,
EVENT_BERSERK_2 = 54,
EVENT_STAND_UP_FRIENDLY = 51,
EVENT_SAY_VOLTRON_DEAD = 52,
EVENT_DISAPPEAR = 53,
EVENT_BERSERK = 54,
EVENT_BERSERK_2 = 55,
// Leviathan:
EVENT_SPELL_NAPALM_SHELL = 3,
@@ -754,17 +756,20 @@ public:
Position exitPos = me->GetPosition();
me->_ExitVehicle(&exitPos);
me->AttackStop();
me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK);
me->GetMotionMaster()->Clear();
summons.DoAction(1337); // despawn summons of summons
summons.DespawnEntry(NPC_FLAMES_INITIAL);
summons.DespawnEntry(33576);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
float angle = VX001->GetOrientation();
float v_x = me->GetPositionX() + cos(angle) * 10.0f;
float v_y = me->GetPositionY() + std::sin(angle) * 10.0f;
me->GetMotionMaster()->MoveJump(v_x, v_y, 364.32f, 7.0f, 7.0f);
DoCastSelf(SPELL_SLEEP_VISUAL_1);
if( pInstance )
for( uint16 i = 0; i < 3; ++i )
if( ObjectGuid guid = pInstance->GetGuidData(DATA_GO_MIMIRON_DOOR_1 + i) )
@@ -783,11 +788,20 @@ public:
computer->AI()->Talk(TALK_COMPUTER_TERMINATED);
events.Reset();
events.ScheduleEvent(EVENT_SAY_VOLTRON_DEAD, 6s);
events.ScheduleEvent(EVENT_STAND_UP_FRIENDLY, 6s);
}
break;
case EVENT_STAND_UP_FRIENDLY:
me->RemoveAurasDueToSpell(SPELL_SLEEP_VISUAL_1);
DoCastSelf(SPELL_SLEEP_VISUAL_2);
me->SetFaction(FACTION_FRIENDLY);
events.ScheduleEvent(EVENT_SAY_VOLTRON_DEAD, 4s);
break;
case EVENT_SAY_VOLTRON_DEAD:
Talk(SAY_V07TRON_DEATH);
me->HandleEmoteCommand(EMOTE_ONESHOT_TALK);
if (pInstance)
pInstance->SetData(TYPE_MIMIRON, DONE);
// spawn chest
if (uint32 chestId = (hardmode ? RAID_MODE(GO_MIMIRON_CHEST_HARD, GO_MIMIRON_CHEST_HERO_HARD) : RAID_MODE(GO_MIMIRON_CHEST, GO_MIMIRON_CHEST_HERO)))
{
@@ -797,11 +811,9 @@ public:
go->SetLootRecipient(me->GetMap());
}
}
events.ScheduleEvent(EVENT_DISAPPEAR, 15s);
events.ScheduleEvent(EVENT_DISAPPEAR, 9s);
break;
case EVENT_DISAPPEAR:
if( pInstance )
pInstance->SetData(TYPE_MIMIRON, DONE);
DoCastSelf(SPELL_TELEPORT);
summons.DespawnAll();
break;
@@ -100,6 +100,15 @@ public:
Position normalChestPosition = { 1967.152588f, -204.188461f, 432.686951f, 5.50957f };
Position hardChestPosition = { 2035.94600f, -202.084885f, 432.686859f, 3.164077f };
// Mimiron Tram
ObjectGuid m_mimironTramGUID;
ObjectGuid m_mimironActivateTramGUID;
ObjectGuid m_mimironTramRocketBoosterGUID;
ObjectGuid m_mimironTramTurnaround1GUID;
ObjectGuid m_mimironTramTurnaround2GUID;
ObjectGuid m_mimironCallTramCenterGUID;
ObjectGuid m_mimironCallTramMimironGUID;
// Mimiron
ObjectGuid m_MimironDoor[3];
ObjectGuid m_MimironLeviathanMKIIguid;
@@ -124,10 +133,12 @@ public:
ObjectGuid m_brannBronzebeardBaseCamp;
uint32 m_algalonTimer;
// Ancient Gate
const Position triggerAncientGatePosition = { 1883.65f, 269.272f, 418.406f };
// Shared
EventMap _events;
bool m_mimironTramUsed;
ObjectGuid m_mimironTramGUID;
ObjectGuid m_keepersgateGUID;
ObjectGuid m_keepersGossipGUID[4];
@@ -170,7 +181,18 @@ public:
// mimiron tram:
instance->LoadGrid(2307.0f, 284.632f);
if (GameObject* MimironTram = instance->GetGameObject(m_mimironTramGUID))
{
player->UpdateVisibilityOf(MimironTram);
if (StaticTransport* t = MimironTram->ToStaticTransport())
{
if (GameObject* go = instance->GetGameObject(m_mimironTramRocketBoosterGUID))
if (!go->GetTransport())
t->AddPassenger(go, true);
if (GameObject* go = instance->GetGameObject(m_mimironActivateTramGUID))
if (!go->GetTransport())
t->AddPassenger(go, true);
}
}
if (!m_uiAlgalonGUID && m_algalonTimer && (m_algalonTimer <= 60 || m_algalonTimer == TIMER_ALGALON_TO_SUMMON))
{
@@ -553,11 +575,30 @@ public:
case GO_SNOW_MOUND:
gameObject->EnableCollision(false);
break;
// Mimiron Tram
case GO_MIMIRON_TRAM:
if (GetData(TYPE_MIMIRON) == DONE)
m_mimironTramUsed = true;
m_mimironTramGUID = gameObject->GetGUID();
break;
case GO_MIMIRON_TRAM_ROCKET_BOOSTER:
m_mimironTramRocketBoosterGUID = gameObject->GetGUID();
break;
case GO_MIMIRON_ACTIVATE_TRAM:
m_mimironActivateTramGUID = gameObject->GetGUID();
break;
case GO_MIMIRON_CALL_TRAM_CENTER:
m_mimironCallTramCenterGUID = gameObject->GetGUID();
break;
case GO_MIMIRON_CALL_TRAM_MIMIRON:
m_mimironCallTramMimironGUID = gameObject->GetGUID();
break;
case GO_DOODAD_UL_TRAIN_TURNAROUND01:
m_mimironTramTurnaround1GUID = gameObject->GetGUID();
break;
case GO_DOODAD_UL_TRAIN_TURNAROUND02:
m_mimironTramTurnaround2GUID = gameObject->GetGUID();
break;
// Algalon the Observer
case GO_CELESTIAL_PLANETARIUM_ACCESS_10:
case GO_CELESTIAL_PLANETARIUM_ACCESS_25:
@@ -668,8 +709,17 @@ public:
m_auiEncounter[type] = data;
if (GetData(TYPE_MIMIRON) == DONE && GetData(TYPE_FREYA) == DONE && GetData(TYPE_HODIR) == DONE && GetData(TYPE_THORIM) == DONE)
{
if (GameObject* go = instance->GetGameObject(m_keepersgateGUID))
go->RemoveGameObjectFlag(GO_FLAG_LOCKED);
scheduler.Schedule(45s, [this](TaskContext /*context*/)
{
if (GameObject* go = instance->GetGameObject(m_keepersgateGUID))
{
go->RemoveGameObjectFlag(GO_FLAG_LOCKED);
if (Creature* trigger = instance->SummonCreature(NPC_ANCIENT_GATE_WORLD_TRIGGER, triggerAncientGatePosition, nullptr, 10*IN_MILLISECONDS))
{
trigger->AI()->Talk(EMOTE_ANCIENT_GATE_UNLOCKED);
}
}
});
}
if (type == TYPE_MIMIRON && data == IN_PROGRESS) // after reaching him without tram and starting the fight
m_mimironTramUsed = true;
@@ -785,9 +835,51 @@ public:
if (StaticTransport* t = MimironTram->ToStaticTransport())
{
if (data == 0 && t->GetGoState() == GO_STATE_ACTIVE && t->GetPathProgress() == t->GetPauseTime())
{
MimironTram->SetGoState(GO_STATE_READY);
if (GameObject* rocketBooster = instance->GetGameObject(m_mimironTramRocketBoosterGUID))
rocketBooster->SetGoState(GO_STATE_ACTIVE);
if (GameObject* activateTramButton = instance->GetGameObject(m_mimironActivateTramGUID))
activateTramButton->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
if (GameObject* callTramCenterButton = instance->GetGameObject(m_mimironCallTramCenterGUID))
callTramCenterButton->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
scheduler.Schedule(30s, [this](TaskContext /*context*/)
{
if (GameObject* turnaround1 = instance->GetGameObject(m_mimironTramTurnaround1GUID))
turnaround1->UseDoorOrButton();
if (GameObject* rocketBooster = instance->GetGameObject(m_mimironTramRocketBoosterGUID))
rocketBooster->SetGoState(GO_STATE_READY);
}).Schedule(60s, [this](TaskContext /*context*/)
{
if (GameObject* activateTramButton = instance->GetGameObject(m_mimironActivateTramGUID))
activateTramButton->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
if (GameObject* callTramMimironButton = instance->GetGameObject(m_mimironCallTramMimironGUID))
callTramMimironButton->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
});
}
if (data == 1 && t->GetGoState() == GO_STATE_READY && t->GetPathProgress() == 0)
{
MimironTram->SetGoState(GO_STATE_ACTIVE);
if (GameObject* rocketBooster = instance->GetGameObject(m_mimironTramRocketBoosterGUID))
rocketBooster->SetGoState(GO_STATE_ACTIVE);
if (GameObject* activateTramButton = instance->GetGameObject(m_mimironActivateTramGUID))
activateTramButton->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
if (GameObject* callTramMimironButton = instance->GetGameObject(m_mimironCallTramMimironGUID))
callTramMimironButton->SetGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
scheduler.Schedule(33s, [this](TaskContext /*context*/)
{
if (GameObject* turnaround2 = instance->GetGameObject(m_mimironTramTurnaround2GUID))
turnaround2->UseDoorOrButton();
if (GameObject* rocketBooster = instance->GetGameObject(m_mimironTramRocketBoosterGUID))
rocketBooster->SetGoState(GO_STATE_READY);
}).Schedule(63s, [this](TaskContext /*context*/)
{
if (GameObject* activateTramButton = instance->GetGameObject(m_mimironActivateTramGUID))
activateTramButton->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
if (GameObject* callTramCenterButton = instance->GetGameObject(m_mimironCallTramCenterGUID))
callTramCenterButton->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
});
}
}
break;
case DATA_BRANN_MEMOTESAY:
@@ -545,33 +545,6 @@ public:
}
};
class go_call_tram : public GameObjectScript
{
public:
go_call_tram() : GameObjectScript("go_call_tram") { }
bool OnGossipHello(Player* /*player*/, GameObject* go) override
{
InstanceScript* pInstance = go->GetInstanceScript();
if (!pInstance)
return false;
switch(go->GetEntry())
{
case 194914:
case 194438:
pInstance->SetData(DATA_CALL_TRAM, 0);
break;
case 194912:
case 194437:
pInstance->SetData(DATA_CALL_TRAM, 1);
break;
}
return true;
}
};
struct npc_salvaged_siege_engine : public VehicleAI
{
npc_salvaged_siege_engine(Creature* creature) : VehicleAI(creature) { }
@@ -609,7 +582,5 @@ void AddSC_ulduar()
new npc_ulduar_arachnopod_destroyer();
new spell_ulduar_arachnopod_damaged();
new AreaTrigger_at_celestial_planetarium_enterance();
new go_call_tram();
RegisterCreatureAI(npc_salvaged_siege_engine);
}
@@ -215,7 +215,15 @@ enum UlduarGameObjects
GO_KOLOGARN_DOORS = 194553,
GO_KEEPERS_GATE = 194255,
GO_XT002_DOORS = 194631,
// Tram
GO_MIMIRON_TRAM = 194675,
GO_MIMIRON_ACTIVATE_TRAM = 194437,
GO_MIMIRON_CALL_TRAM_CENTER = 194914,
GO_MIMIRON_CALL_TRAM_MIMIRON = 194912,
GO_MIMIRON_TRAM_ROCKET_BOOSTER = 194904,
GO_DOODAD_UL_TRAIN_TURNAROUND01 = 194915, // center
GO_DOODAD_UL_TRAIN_TURNAROUND02 = 194913, // mimiron
// Mimiron, Hodir, Vezax
GO_MIMIRON_ELEVATOR = 194749,
@@ -290,6 +298,10 @@ enum UlduarMisc
// Freya, Hodir, Mimiron, Thorim
EVENT_KEEPER_TELEPORTED = 62941,
// Ancient Gate
NPC_ANCIENT_GATE_WORLD_TRIGGER = 22515,
EMOTE_ANCIENT_GATE_UNLOCKED = 19,
// Yogg-Saron
ACTION_SARA_UPDATE_SUMMON_KEEPERS = 4,
KEEPER_FREYA = 0,