mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-13 09:17:18 +00:00
Merge branch 'azerothcore:master' into Playerbot
This commit is contained in:
7
data/sql/updates/db_world/2022_06_11_00.sql
Normal file
7
data/sql/updates/db_world/2022_06_11_00.sql
Normal file
@@ -0,0 +1,7 @@
|
||||
-- DB update 2022_06_09_01 -> 2022_06_11_00
|
||||
-- Add Chinese translation of road signs
|
||||
DELETE FROM `gameobject_template_locale` WHERE `entry` IN (184084,176365,176364) AND `locale` = 'zhCN';
|
||||
INSERT INTO `gameobject_template_locale` (`entry`, `locale`, `name`, `castBarCaption`, `VerifiedBuild`) VALUES
|
||||
(184084, 'zhCN', '开往秘蓝岛的船只', '', 18019),
|
||||
(176365, 'zhCN', '开往泰达希尔的船只', '', 18019),
|
||||
(176364, 'zhCN', '开往暴风城的船只', '', 18019);
|
||||
3
data/sql/updates/db_world/2022_06_13_00.sql
Normal file
3
data/sql/updates/db_world/2022_06_13_00.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
-- DB update 2022_06_11_00 -> 2022_06_13_00
|
||||
--
|
||||
UPDATE `creature_model_info` SET `CombatReach`=1.5 WHERE `DisplayID`=2836;
|
||||
8
data/sql/updates/db_world/2022_06_13_01.sql
Normal file
8
data/sql/updates/db_world/2022_06_13_01.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
-- DB update 2022_06_13_00 -> 2022_06_13_01
|
||||
--
|
||||
UPDATE `gameobject_template` SET `AIName` = 'SmartGameObjectAI' WHERE `entry` = 180517;
|
||||
|
||||
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 180517) AND (`source_type` = 1) AND (`id` IN (0, 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`, `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
|
||||
(180517, 1, 0, 0, 63, 0, 100, 0, 0, 0, 0, 0, 0, 11, 24871, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Putrid Mushroom - On Just Created - Cast \'Spore Cloud\''),
|
||||
(180517, 1, 1, 0, 1, 0, 100, 0, 120000, 120000, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Putrid Mushroom - Out of Combat - Despawn Instant');
|
||||
4
data/sql/updates/db_world/2022_06_13_02.sql
Normal file
4
data/sql/updates/db_world/2022_06_13_02.sql
Normal file
@@ -0,0 +1,4 @@
|
||||
-- DB update 2022_06_13_01 -> 2022_06_13_02
|
||||
|
||||
UPDATE `creature_template` SET `ScriptName`='npc_chained_spirit', `speed_run`=0.4, `unit_flags`=`unit_flags`|33554432 WHERE `entry`=15117;
|
||||
|
||||
19
data/sql/updates/db_world/2022_06_13_03.sql
Normal file
19
data/sql/updates/db_world/2022_06_13_03.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
-- DB update 2022_06_13_02 -> 2022_06_13_03
|
||||
--
|
||||
DELETE FROM `acore_string` WHERE `entry` IN (283,298,300,301,11003);
|
||||
INSERT INTO `acore_string` (`entry`, `content_default`, `locale_koKR`, `locale_frFR`, `locale_deDE`, `locale_zhCN`, `locale_zhTW`, `locale_esES`, `locale_esMX`, `locale_ruRU`) VALUES
|
||||
(283, "%s has disabled %s's chat for %s, effective at the player's next login. Reason: %s.", NULL, NULL, "Ihr habt dem Spieler %s das chatten für %s gesperrt, beginnend mit dem nächsten Login des Spielers. Grund: %s.", "你已经被 %s 禁言 %s,将在下一次登陆时生效。原因: %s。", NULL, "%s ha deshabilitado el chat de %s por %s, efectivo en el próximo ingreso del jugador. Razón: %s.", "%s ha deshabilitado el chat de %s por %s, efectivo en el próximo ingreso del jugador. Razón: %s.", NULL),
|
||||
(298, "Spawn time changed to: %s", NULL, NULL, "Spawnzeit wurde auf: %s abgeändert", "复生时间改变为: %s", NULL, "Tiempo de desove cambiado a: %s", "Tiempo de desove cambiado a: %s", NULL),
|
||||
(300, "Your chat has been disabled for %s. By: %s, Reason: %s.", NULL, NULL, "Euer Chat wurde für %s abgeschaltet. Von: %s, Grund: %s", "你将被禁言 %s.", NULL, "Tu chat ha sido desactivado durante %u. Por: %s ,Razón: %s.", "Tu chat ha sido desactivado durante %u. Por: %s ,Razón: %s.", NULL),
|
||||
(301, "%s has disabled %s's chat for %s. Reason: %s.", NULL, NULL, "Ihr hab den Chat von %s für %s abgeschaltet. Von: %s, Grund: %s", NULL, NULL, "%s ha desactivado el chat de %s durante %s. Razón: %s.", "%s ha desactivado el chat de %s durante %s. Razón: %s.", NULL),
|
||||
(11003, "Server: %s has muted %s for %s, reason: %s", NULL, NULL, NULL, "系统公告: %s has muted %s for %s, 原因: %s", NULL, NULL, NULL, "Server: %s замутил %s на %s, причина: %s");
|
||||
|
||||
UPDATE `command` SET `help` = "Syntax: .mute [$playerName] $mutetime [$reason]\r\nDisible chat messaging for any character from account of character $playerName (or currently selected) at $mutetime time. Player can be offline.\n$mutetime: use a timestring like \"1d15h33s\"." WHERE `name` = "mute";
|
||||
UPDATE `command` SET `help` = "Syntax: .npc set spawntime #time\r\nAdjust spawntime of selected creature to #time.\n#time: use a timestring like \"10m30s\"." WHERE `name` = "npc set spawntime";
|
||||
UPDATE `command` SET `help` = "Syntax: .server idlerestart #delay\r\nRestart the server after #delay if no active connections are present (no players). Use #exist_code or 2 as program exist code.\n#delay: use a timestring like \"1h15m30s\"." WHERE `name` = "server idlerestart";
|
||||
UPDATE `command` SET `help` = "Syntax: .server idleshutdown #delay [#exist_code]\r\nShut the server down after #delay if no active connections are present (no players). Use #exist_code or 0 as program exist code.\n#delay: use a timestring like \"1h15m30s\"." WHERE `name` = "server idleshutdown";
|
||||
UPDATE `command` SET `help` = "Syntax: .server restart #delay\r\nRestart the server after #delay. Use #exist_code or 2 as program exist code.\n#delay: use a timestring like \"1h15m30s\"." WHERE `name` = "server restart";
|
||||
UPDATE `command` SET `help` = "Syntax: .server shutdown #delay [#exit_code]\r\nShut the server down after #delay. Use #exit_code or 0 as program exit code.\n#delay: use a timestring like \"1h15m30s\"." WHERE `name` = "server shutdown";
|
||||
UPDATE `command` SET `help` = "Syntax: .bf timer #battleid #timer\n#timer: use a timestring like \"1h15m30s\"." WHERE `name` = "bf timer";
|
||||
UPDATE `command` SET `help` = "Syntax: .deserter bg add $playerName <$time>\r\nAdds the bg deserter debuff to a player or your target with $time.\nOptional $time: use a timestring like \"1h15m30s\".Default: 15m" WHERE `name` = "deserter bg add";
|
||||
UPDATE `command` SET `help` = "Syntax: .deserter instance add $playerName <$time>\r\nAdds the instance deserter debuff to a player or your target with $time.\nOptional $time: use a timestring like \"1h15m30s\". Default: 30m" WHERE `name` = "deserter instance add";
|
||||
45
data/sql/updates/db_world/2022_06_13_04.sql
Normal file
45
data/sql/updates/db_world/2022_06_13_04.sql
Normal file
@@ -0,0 +1,45 @@
|
||||
-- DB update 2022_06_13_03 -> 2022_06_13_04
|
||||
DELETE FROM `player_factionchange_items` WHERE `alliance_id` IN (16393, 16397, 16423, 16422, 16424, 16421, 16401, 16403, 16425, 16426, 16427, 16428, 16369, 16391, 16413, 16414, 16415, 16416, 17594, 17596, 17598, 17599, 17600, 17601) OR `horde_id` IN (16498, 16499, 16505, 16506, 16507, 16508, 17570, 17571, 17572, 17573, 17576, 17577, 16509, 16510, 16513, 16514, 16515, 16516, 16494, 16496, 16501, 16503, 16504);
|
||||
INSERT INTO `player_factionchange_items` (`alliance_id`, `alliance_comment`, `horde_id`, `horde_comment`) VALUES
|
||||
(16393, 'Knight-Lieutenant\'s Dragonhide Footwraps', 16494, 'Blood Guard\'s Dragonhide Boots'),
|
||||
(16397, 'Knight-Lieutenant\'s Dragonhide Gloves', 16496, 'Blood Guard\'s Dragonhide Gauntlets'),
|
||||
(16423, 'Lieutenant Commander\'s Dragonhide Epaulets', 16501, 'Champion\'s Dragonhide Spaulders'),
|
||||
(16422, 'Knight-Captain\'s Dragonhide Leggings', 16502, 'Legionnaire\'s Dragonhide Trousers'),
|
||||
(16424, 'Lieutenant Commander\'s Dragonhide Shroud', 16503, 'Champion\'s Dragonhide Helm'),
|
||||
(16421, 'Knight-Captain\'s Dragonhide Tunic', 16504, 'Legionnaire\'s Dragonhide Breastplate'),
|
||||
(16401, 'Knight-Lieutenant\'s Chain Boots', 16531, 'Blood Guard\'s Chain Boots'),
|
||||
(16403, 'Knight-Lieutenant\'s Chain Gauntlets', 16530, 'Blood Guard\'s Chain Gauntlets'),
|
||||
(16425, 'Knight-Captain\'s Chain Hauberk', 16525, 'Legionnaire\'s Chain Breastplate'),
|
||||
(16426, 'Knight-Captain\'s Chain Leggings', 16527, 'Legionnaire\'s Chain Leggings'),
|
||||
(16427, 'Lieutenant Commander\'s Chain Pauldrons', 16528, 'Champion\'s Chain Pauldrons'),
|
||||
(16428, 'Lieutenant Commander\'s Chain Helmet', 16526, 'Champion\'s Chain Headguard'),
|
||||
(16369, 'Knight-Lieutenant\'s Silk Boots', 16485, 'Blood Guard\'s Silk Footwraps'),
|
||||
(16391, 'Knight-Lieutenant\'s Silk Gloves', 16487, 'Blood Guard\'s Silk Gloves'),
|
||||
(16413, 'Knight-Captain\'s Silk Raiment', 16491, 'Legionnaire\'s Silk Robes'),
|
||||
(16414, 'Knight-Captain\'s Silk Leggings', 16490, 'Legionnaire\'s Silk Pants'),
|
||||
(16415, 'Lieutenant Commander\'s Silk Spaulders', 16492, 'Champion\'s Silk Shoulderpads'),
|
||||
(16416, 'Lieutenant Commander\'s Crown', 16489, 'Champion\'s Silk Hood'),
|
||||
(16392, 'Knight-Lieutenant\'s Leather Boots', 16498, 'Blood Guard\'s Leather Treads'),
|
||||
(16396, 'Knight-Lieutenant\'s Leather Gauntlets', 16499, 'Blood Guard\'s Leather Vices'),
|
||||
(16417, 'Knight-Captain\'s Leather Armor', 16505, 'Legionnaire\'s Leather Hauberk'),
|
||||
(16418, 'Lieutenant Commander\'s Leather Veil', 16506, 'Champion\'s Leather Headguard'),
|
||||
(16419, 'Knight-Captain\'s Leather Legguards', 16508, 'Legionnaire\'s Leather Leggings'),
|
||||
(16420, 'Lieutenant Commander\'s Leather Spaulders', 16507, 'Champion\'s Leather Mantle'),
|
||||
(17594, 'Knight-Lieutenant\'s Satin Boots', 17616, 'Blood Guard\'s Satin Boots'),
|
||||
(17596, 'Knight-Lieutenant\'s Satin Gloves', 17617, 'Blood Guard\'s Satin Gloves'),
|
||||
(17598, 'Lieutenant Commander\'s Diadem', 17610, 'Champion\'s Satin Cowl'),
|
||||
(17599, 'Knight-Captain\'s Satin Leggings', 17611, 'Legionnaire\'s Satin Trousers'),
|
||||
(17600, 'Knight-Captain\'s Satin Robes', 17612, 'Legionnaire\'s Satin Vestments'),
|
||||
(17601, 'Lieutenant Commander\'s Satin Amice', 17613, 'Champion\'s Satin Shoulderpads'),
|
||||
(17562, 'Knight-Lieutenant\'s Dreadweave Boots', 17576, 'Blood Guard\'s Dreadweave Boots'),
|
||||
(17564, 'Knight-Lieutenant\'s Dreadweave Gloves', 17577, 'Blood Guard\'s Dreadweave Gloves'),
|
||||
(17566, 'Lieutenant Commander\'s Headguard', 17570, 'Champion\'s Dreadweave Hood'),
|
||||
(17567, 'Knight-Captain\'s Dreadweave Leggings', 17571, 'Legionnaire\'s Dreadweave Leggings'),
|
||||
(17568, 'Knight-Captain\'s Dreadweave Robe', 17572, 'Legionnaire\'s Dreadweave Robe'),
|
||||
(17569, 'Lieutenant Commander\'s Dreadweave Mantle', 17573, 'Champion\'s Dreadweave Shoulders'),
|
||||
(16405, 'Knight-Lieutenant\'s Plate Boots', 16509, 'Blood Guard\'s Plate Boots'),
|
||||
(16406, 'Knight-Lieutenant\'s Plate Gauntlets', 16510, 'Blood Guard\'s Plate Gloves'),
|
||||
(16429, 'Lieutenant Commander\'s Plate Helm',16514, 'Champion\'s Plate Headguard'),
|
||||
(16430, 'Knight-Captain\'s Plate Chestguard', 16513, 'Legionnaire\'s Plate Armor'),
|
||||
(16431, 'Knight-Captain\'s Plate Leggings', 16515, 'Legionnaire\'s Plate Legguards'),
|
||||
(16432, 'Lieutenant Commander\'s Plate Pauldrons', 16516, 'Champion\'s Plate Pauldrons');
|
||||
@@ -22,7 +22,7 @@ ExternalProject_Add(
|
||||
SOURCE_DIR "@GOOGLETEST_DOWNLOAD_ROOT@/googletest-src"
|
||||
BINARY_DIR "@GOOGLETEST_DOWNLOAD_ROOT@/googletest-build"
|
||||
GIT_REPOSITORY
|
||||
https://github.com/Helias/googletest.git
|
||||
https://github.com/google/googletest.git
|
||||
GIT_TAG
|
||||
main
|
||||
CONFIGURE_COMMAND ""
|
||||
|
||||
@@ -1234,7 +1234,7 @@ Position WorldObject::GetHitSpherePointFor(Position const& dest) const
|
||||
{
|
||||
G3D::Vector3 vThis(GetPositionX(), GetPositionY(), GetPositionZ() + GetCollisionHeight());
|
||||
G3D::Vector3 vObj(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ());
|
||||
G3D::Vector3 contactPoint = vThis + (vObj - vThis).directionOrZero() * std::min(dest.GetExactDist(this), GetObjectSize());
|
||||
G3D::Vector3 contactPoint = vThis + (vObj - vThis).directionOrZero() * std::min(dest.GetExactDist(this), GetCombatReach());
|
||||
|
||||
return Position(contactPoint.x, contactPoint.y, contactPoint.z, GetAngle(contactPoint.x, contactPoint.y));
|
||||
}
|
||||
|
||||
@@ -1620,7 +1620,11 @@ void Player::ProcessDelayedOperations()
|
||||
SaveToDB(false, false);
|
||||
|
||||
if (m_DelayedOperations & DELAYED_SPELL_CAST_DESERTER)
|
||||
CastSpell(this, 26013, true); // Deserter
|
||||
{
|
||||
Aura* aura = GetAura(26013);
|
||||
if (!aura || aura->GetDuration() <= 900000)
|
||||
CastSpell(this, 26013, true);
|
||||
}
|
||||
|
||||
if (m_DelayedOperations & DELAYED_BG_MOUNT_RESTORE)
|
||||
{
|
||||
@@ -2139,10 +2143,8 @@ void Player::SetInWater(bool apply)
|
||||
getHostileRefMgr().updateThreatTables();
|
||||
}
|
||||
|
||||
bool Player::IsInAreaTriggerRadius(const AreaTrigger* trigger) const
|
||||
bool Player::IsInAreaTriggerRadius(AreaTrigger const* trigger, float delta) const
|
||||
{
|
||||
static const float delta = 5.0f;
|
||||
|
||||
if (!trigger || GetMapId() != trigger->map)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -1095,7 +1095,7 @@ public:
|
||||
|
||||
[[nodiscard]] bool IsInWater() const override { return m_isInWater; }
|
||||
[[nodiscard]] bool IsFalling() const;
|
||||
bool IsInAreaTriggerRadius(const AreaTrigger* trigger) const;
|
||||
bool IsInAreaTriggerRadius(AreaTrigger const* trigger, float delta = 0.f) const;
|
||||
|
||||
void SendInitialPacketsBeforeAddToMap();
|
||||
void SendInitialPacketsAfterAddToMap();
|
||||
|
||||
@@ -277,10 +277,11 @@ void Player::Update(uint32 p_time)
|
||||
// supposed to be in one
|
||||
if (HasRestFlag(REST_FLAG_IN_TAVERN))
|
||||
{
|
||||
AreaTrigger const* atEntry =
|
||||
sObjectMgr->GetAreaTrigger(GetInnTriggerId());
|
||||
if (!atEntry || !IsInAreaTriggerRadius(atEntry))
|
||||
AreaTrigger const* atEntry = sObjectMgr->GetAreaTrigger(GetInnTriggerId());
|
||||
if (!atEntry || !IsInAreaTriggerRadius(atEntry, 5.f))
|
||||
{
|
||||
RemoveRestFlag(REST_FLAG_IN_TAVERN);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 newzone, newarea;
|
||||
|
||||
@@ -731,7 +731,8 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player->IsInAreaTriggerRadius(atEntry))
|
||||
bool isTavernAreatrigger = sObjectMgr->IsTavernAreaTrigger(triggerId);
|
||||
if (!player->IsInAreaTriggerRadius(atEntry, isTavernAreatrigger ? 5.f : 0.f))
|
||||
{
|
||||
LOG_DEBUG("network", "HandleAreaTriggerOpcode: Player {} ({}) too far (trigger map: {} player map: {}), ignore Area Trigger ID: {}",
|
||||
player->GetName(), player->GetGUID().ToString(), atEntry->map, player->GetMapId(), triggerId);
|
||||
@@ -749,7 +750,7 @@ void WorldSession::HandleAreaTriggerOpcode(WorldPacket& recv_data)
|
||||
if (player->GetQuestStatus(questId) == QUEST_STATUS_INCOMPLETE)
|
||||
player->AreaExploredOrEventHappens(questId);
|
||||
|
||||
if (sObjectMgr->IsTavernAreaTrigger(triggerId))
|
||||
if (isTavernAreatrigger)
|
||||
{
|
||||
// set resting flag we are in the inn
|
||||
player->SetRestFlag(REST_FLAG_IN_TAVERN, atEntry->entry);
|
||||
|
||||
@@ -2842,9 +2842,10 @@ void DynObjAura::FillTargetMap(std::map<Unit*, uint8>& targets, Unit* /*caster*/
|
||||
{
|
||||
if (!HasEffect(effIndex))
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = GetSpellInfo();
|
||||
UnitList targetList;
|
||||
if (GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_ALLY
|
||||
|| GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ALLY)
|
||||
if (spellInfo->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_ALLY || spellInfo->Effects[effIndex].TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ALLY)
|
||||
{
|
||||
Acore::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
|
||||
Acore::UnitListSearcher<Acore::AnyFriendlyUnitInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check);
|
||||
@@ -2852,7 +2853,7 @@ void DynObjAura::FillTargetMap(std::map<Unit*, uint8>& targets, Unit* /*caster*/
|
||||
}
|
||||
// pussywizard: TARGET_DEST_DYNOBJ_NONE is supposed to search for both friendly and unfriendly targets, so for any unit
|
||||
// what about EffectImplicitTargetA?
|
||||
else if (GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_NONE)
|
||||
else if (spellInfo->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_NONE)
|
||||
{
|
||||
Acore::AnyAttackableUnitExceptForOriginalCasterInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius);
|
||||
Acore::UnitListSearcher<Acore::AnyAttackableUnitExceptForOriginalCasterInObjectRangeCheck> searcher(GetDynobjOwner(), targetList, u_check);
|
||||
@@ -2867,12 +2868,11 @@ void DynObjAura::FillTargetMap(std::map<Unit*, uint8>& targets, Unit* /*caster*/
|
||||
|
||||
for (UnitList::iterator itr = targetList.begin(); itr != targetList.end(); ++itr)
|
||||
{
|
||||
// xinef: check z level and los dependence
|
||||
Unit* target = *itr;
|
||||
float zLevel = GetDynobjOwner()->GetPositionZ();
|
||||
if (target->GetPositionZ() + 3.0f < zLevel || target->GetPositionZ() - 5.0f > zLevel)
|
||||
if (!target->IsWithinLOSInMap(GetDynobjOwner()))
|
||||
continue;
|
||||
if (!spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) && !spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT) && !target->IsWithinLOSInMap(GetDynobjOwner()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::map<Unit*, uint8>::iterator existing = targets.find(*itr);
|
||||
if (existing != targets.end())
|
||||
|
||||
@@ -1363,6 +1363,12 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->Effects[EFFECT_0].Amplitude = 15000;
|
||||
});
|
||||
|
||||
// Threatening Gaze
|
||||
ApplySpellFix({ 24314 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CAST;
|
||||
});
|
||||
|
||||
// Isle of Conquest
|
||||
ApplySpellFix({ 66551 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
|
||||
@@ -117,8 +117,33 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleBattlefieldTimer(ChatHandler* handler, uint32 battleId, uint32 time)
|
||||
static bool HandleBattlefieldTimer(ChatHandler* handler, uint32 battleId, std::string timeStr)
|
||||
{
|
||||
if (timeStr.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Acore::StringTo<int32>(timeStr).value_or(0) < 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 time = TimeStringToSecs(timeStr);
|
||||
if (time <= 0)
|
||||
{
|
||||
time = Acore::StringTo<int32>(timeStr).value_or(0);
|
||||
}
|
||||
|
||||
if (time <= 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
Battlefield* bf = sBattlefieldMgr->GetBattlefieldByBattleId(battleId);
|
||||
|
||||
if (!bf)
|
||||
|
||||
@@ -79,7 +79,8 @@ public:
|
||||
* selected player, with the provided duration in seconds.
|
||||
*
|
||||
* @param handler The ChatHandler, passed by the system.
|
||||
* @param time The provided duration in seconds.
|
||||
* @param playerName Player by name. Optional, defaults to selected or self.
|
||||
* @param time The provided duration as TimeString. Optional, defaults to bg/instance default time.
|
||||
* @param isInstance provided by the relaying functions, so we don't have
|
||||
* to write that much code :)
|
||||
*
|
||||
@@ -87,53 +88,113 @@ public:
|
||||
*
|
||||
* Example Usage:
|
||||
* @code
|
||||
* .deserter instance add 3600 (one hour)
|
||||
* .deserter instance add 1h30m
|
||||
* -or-
|
||||
* .deserter bg add 3600 (one hour)
|
||||
* .deserter bg add 1h30m
|
||||
* @endcode
|
||||
*/
|
||||
static bool HandleDeserterAdd(ChatHandler* handler, Optional<PlayerIdentifier> player, uint32 time, bool isInstance)
|
||||
static bool HandleDeserterAdd(ChatHandler* handler, Optional<std::string> playerName, Optional<std::string> time, bool isInstance)
|
||||
{
|
||||
if (!player)
|
||||
Player* target = handler->getSelectedPlayerOrSelf();
|
||||
ObjectGuid guid;
|
||||
|
||||
if (playerName)
|
||||
{
|
||||
player = PlayerIdentifier::FromTargetOrSelf(handler);
|
||||
if (!normalizePlayerName(*playerName))
|
||||
{
|
||||
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
guid = sCharacterCache->GetCharacterGuidByName(*playerName);
|
||||
if (guid)
|
||||
{
|
||||
target = ObjectAccessor::FindPlayerByName(*playerName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (time)
|
||||
{
|
||||
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
time = playerName;
|
||||
playerName = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (!player)
|
||||
if (!playerName || playerName->empty())
|
||||
{
|
||||
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
if (!handler->GetSession())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
playerName = target->GetName();
|
||||
guid = target->GetGUID();
|
||||
}
|
||||
|
||||
if (!time)
|
||||
{
|
||||
time = isInstance ? "30m" : "15m";
|
||||
}
|
||||
|
||||
int32 duration = TimeStringToSecs(*time);
|
||||
|
||||
if (duration == 0)
|
||||
{
|
||||
duration = Acore::StringTo<int32>(*time).value_or(0);
|
||||
}
|
||||
|
||||
if (duration == 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
Player* target = player->GetConnectedPlayer();
|
||||
|
||||
if (target)
|
||||
{
|
||||
Aura* aura = target->AddAura(isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER, target);
|
||||
Aura* aura = target->GetAura(isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER);
|
||||
if (aura && aura->GetDuration() >= duration * IN_MILLISECONDS)
|
||||
{
|
||||
handler->PSendSysMessage("Player %s already has a longer %s Deserter active.", handler->playerLink(*playerName), isInstance ? "Instance" : "Battleground");
|
||||
return true;
|
||||
}
|
||||
|
||||
aura = target->AddAura(isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER, target);
|
||||
if (!aura)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
aura->SetDuration(time * IN_MILLISECONDS);
|
||||
aura->SetDuration(duration * IN_MILLISECONDS);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int32 remainTime = 0;
|
||||
if (QueryResult result = CharacterDatabase.Query("SELECT remainTime FROM character_aura WHERE guid = {} AND spell = {}", guid.GetCounter(), isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER))
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
remainTime = fields[0].Get<int32>();
|
||||
|
||||
if (remainTime < 0 || remainTime >= duration * IN_MILLISECONDS)
|
||||
{
|
||||
handler->PSendSysMessage("Player %s already has a longer %s Deserter active.", handler->playerLink(*playerName), isInstance ? "Instance" : "Battleground");
|
||||
return true;
|
||||
}
|
||||
CharacterDatabase.Query("DELETE FROM character_aura WHERE guid = {} AND spell = {}", guid.GetCounter(), isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER);
|
||||
}
|
||||
|
||||
uint8 index = 0;
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_AURA);
|
||||
stmt->SetData(index++, player->GetGUID().GetCounter());
|
||||
stmt->SetData(index++, player->GetGUID().GetCounter());
|
||||
stmt->SetData(index++, guid.GetCounter());
|
||||
stmt->SetData(index++, guid.GetCounter());
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, isInstance ? LFG_SPELL_DUNGEON_DESERTER : BG_SPELL_DESERTER);
|
||||
stmt->SetData(index++, 1);
|
||||
@@ -146,7 +207,7 @@ public:
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, 0);
|
||||
stmt->SetData(index++, isInstance ? 1800000 : 900000);
|
||||
stmt->SetData(index++, time * 1000);
|
||||
stmt->SetData(index++, duration * 1000);
|
||||
stmt->SetData(index, 0);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
@@ -220,15 +281,15 @@ public:
|
||||
}
|
||||
|
||||
/// @sa HandleDeserterAdd()
|
||||
static bool HandleDeserterInstanceAdd(ChatHandler* handler, Optional<PlayerIdentifier> player, uint32 time)
|
||||
static bool HandleDeserterInstanceAdd(ChatHandler* handler, Optional<std::string> playerName, Optional<std::string> time)
|
||||
{
|
||||
return HandleDeserterAdd(handler, player, time, true);
|
||||
return HandleDeserterAdd(handler, playerName, time, true);
|
||||
}
|
||||
|
||||
/// @sa HandleDeserterAdd()
|
||||
static bool HandleDeserterBGAdd(ChatHandler* handler, Optional<PlayerIdentifier> player, uint32 time)
|
||||
static bool HandleDeserterBGAdd(ChatHandler* handler, Optional<std::string> playerName, Optional<std::string> time)
|
||||
{
|
||||
return HandleDeserterAdd(handler, player, time, false);
|
||||
return HandleDeserterAdd(handler, playerName, time, false);
|
||||
}
|
||||
|
||||
/// @sa HandleDeserterRemove()
|
||||
|
||||
@@ -2374,10 +2374,22 @@ public:
|
||||
}
|
||||
|
||||
// mute player for some times
|
||||
static bool HandleMuteCommand(ChatHandler* handler, Optional<PlayerIdentifier> player, uint32 notSpeakTime, Tail muteReason)
|
||||
static bool HandleMuteCommand(ChatHandler* handler, Optional<PlayerIdentifier> player, std::string notSpeakTime, Tail muteReason)
|
||||
{
|
||||
std::string muteReasonStr{ muteReason };
|
||||
|
||||
if (notSpeakTime.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Acore::StringTo<int32>(notSpeakTime).value_or(0) < 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (muteReason.empty())
|
||||
{
|
||||
muteReasonStr = handler->GetAcoreString(LANG_NO_REASON);
|
||||
@@ -2412,6 +2424,19 @@ public:
|
||||
}
|
||||
|
||||
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME);
|
||||
int32 muteDuration = TimeStringToSecs(notSpeakTime);
|
||||
if (muteDuration <= 0)
|
||||
{
|
||||
muteDuration = Acore::StringTo<int32>(notSpeakTime).value_or(0);
|
||||
}
|
||||
|
||||
if (muteDuration <= 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string muteBy = "";
|
||||
if (handler->GetSession())
|
||||
{
|
||||
@@ -2425,22 +2450,22 @@ public:
|
||||
if (target)
|
||||
{
|
||||
// Target is online, mute will be in effect right away.
|
||||
int64 muteTime = GameTime::GetGameTime().count() + notSpeakTime * MINUTE;
|
||||
int64 muteTime = GameTime::GetGameTime().count() + muteDuration;
|
||||
target->GetSession()->m_muteTime = muteTime;
|
||||
stmt->SetData(0, muteTime);
|
||||
std::string nameLink = handler->playerLink(player->GetName());
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_SHOW_MUTE_IN_WORLD))
|
||||
{
|
||||
sWorld->SendWorldText(LANG_COMMAND_MUTEMESSAGE_WORLD, muteBy.c_str(), nameLink.c_str(), notSpeakTime, muteReasonStr.c_str());
|
||||
sWorld->SendWorldText(LANG_COMMAND_MUTEMESSAGE_WORLD, muteBy.c_str(), nameLink.c_str(), secsToTimeString(muteDuration, true).c_str(), muteReasonStr.c_str());
|
||||
}
|
||||
|
||||
ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notSpeakTime, muteBy.c_str(), muteReasonStr.c_str());
|
||||
ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, secsToTimeString(muteDuration, true).c_str(), muteBy.c_str(), muteReasonStr.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Target is offline, mute will be in effect starting from the next login.
|
||||
stmt->SetData(0, -int32(notSpeakTime * MINUTE));
|
||||
stmt->SetData(0, -int32(muteDuration));
|
||||
}
|
||||
|
||||
stmt->SetData(1, muteReasonStr);
|
||||
@@ -2450,7 +2475,7 @@ public:
|
||||
|
||||
stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_MUTE);
|
||||
stmt->SetData(0, accountId);
|
||||
stmt->SetData(1, notSpeakTime);
|
||||
stmt->SetData(1, muteDuration / MINUTE);
|
||||
stmt->SetData(2, muteBy);
|
||||
stmt->SetData(3, muteReasonStr);
|
||||
LoginDatabase.Execute(stmt);
|
||||
@@ -2459,7 +2484,7 @@ public:
|
||||
|
||||
if (sWorld->getBoolConfig(CONFIG_SHOW_MUTE_IN_WORLD) && !target)
|
||||
{
|
||||
sWorld->SendWorldText(LANG_COMMAND_MUTEMESSAGE_WORLD, muteBy.c_str(), nameLink.c_str(), notSpeakTime, muteReasonStr.c_str());
|
||||
sWorld->SendWorldText(LANG_COMMAND_MUTEMESSAGE_WORLD, muteBy.c_str(), nameLink.c_str(), secsToTimeString(muteDuration, true).c_str(), muteReasonStr.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2469,7 +2494,7 @@ public:
|
||||
for (HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr)
|
||||
if (itr->second->GetSession()->GetSecurity())
|
||||
ChatHandler(itr->second->GetSession()).PSendSysMessage(target ? LANG_YOU_DISABLE_CHAT : LANG_COMMAND_DISABLE_CHAT_DELAYED,
|
||||
(handler->GetSession() ? handler->GetSession()->GetPlayerName().c_str() : handler->GetAcoreString(LANG_CONSOLE)), nameLink.c_str(), notSpeakTime, muteReasonStr.c_str());
|
||||
(handler->GetSession() ? handler->GetSession()->GetPlayerName().c_str() : handler->GetAcoreString(LANG_CONSOLE)), nameLink.c_str(), secsToTimeString(muteDuration, true).c_str(), muteReasonStr.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -988,19 +988,44 @@ public:
|
||||
}
|
||||
|
||||
//spawn time handling
|
||||
static bool HandleNpcSetSpawnTimeCommand(ChatHandler* handler, uint32 spawnTime)
|
||||
static bool HandleNpcSetSpawnTimeCommand(ChatHandler* handler, std::string spawnTimeStr)
|
||||
{
|
||||
if (spawnTimeStr.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Acore::StringTo<int32>(spawnTimeStr).value_or(0) < 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
Creature* creature = handler->getSelectedCreature();
|
||||
if (!creature)
|
||||
return false;
|
||||
|
||||
int32 spawnTime = TimeStringToSecs(spawnTimeStr);
|
||||
if (spawnTime <= 0)
|
||||
{
|
||||
spawnTime = Acore::StringTo<int32>(spawnTimeStr).value_or(0);
|
||||
}
|
||||
|
||||
if (spawnTime <= 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_CREATURE_SPAWN_TIME_SECS);
|
||||
stmt->SetData(0, spawnTime);
|
||||
stmt->SetData(1, creature->GetSpawnId());
|
||||
WorldDatabase.Execute(stmt);
|
||||
|
||||
creature->SetRespawnDelay(spawnTime);
|
||||
handler->PSendSysMessage(LANG_COMMAND_SPAWNTIME, spawnTime);
|
||||
handler->PSendSysMessage(LANG_COMMAND_SPAWNTIME, secsToTimeString(spawnTime, true).c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -280,11 +280,23 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleServerShutDownCommand(ChatHandler* /*handler*/, int32 time, Optional<int32> exitCode, Tail reason)
|
||||
static bool HandleServerShutDownCommand(ChatHandler* handler, std::string time, Optional<int32> exitCode, Tail reason)
|
||||
{
|
||||
std::wstring wReason = std::wstring();
|
||||
std::string strReason = std::string();
|
||||
|
||||
if (time.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Acore::StringTo<int32>(time).value_or(0) < 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reason.empty())
|
||||
{
|
||||
if (!Utf8toWStr(reason, wReason))
|
||||
@@ -298,23 +310,48 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
int32 delay = TimeStringToSecs(time);
|
||||
if (delay <= 0)
|
||||
{
|
||||
delay = Acore::StringTo<int32>(time).value_or(0);
|
||||
}
|
||||
|
||||
if (delay <= 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exitCode && *exitCode >= 0 && *exitCode <= 125)
|
||||
{
|
||||
sWorld->ShutdownServ(time, 0, *exitCode);
|
||||
sWorld->ShutdownServ(delay, 0, *exitCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
sWorld->ShutdownServ(time, 0, SHUTDOWN_EXIT_CODE, strReason);
|
||||
sWorld->ShutdownServ(delay, 0, SHUTDOWN_EXIT_CODE, strReason);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleServerRestartCommand(ChatHandler* /*handler*/, int32 time, Optional<int32> exitCode, Tail reason)
|
||||
static bool HandleServerRestartCommand(ChatHandler* handler, std::string time, Optional<int32> exitCode, Tail reason)
|
||||
{
|
||||
std::wstring wReason = std::wstring();
|
||||
std::string strReason = std::string();
|
||||
|
||||
if (time.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Acore::StringTo<int32>(time).value_or(0) < 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reason.empty())
|
||||
{
|
||||
if (!Utf8toWStr(reason, wReason))
|
||||
@@ -328,23 +365,48 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
int32 delay = TimeStringToSecs(time);
|
||||
if (delay <= 0)
|
||||
{
|
||||
delay = Acore::StringTo<int32>(time).value_or(0);
|
||||
}
|
||||
|
||||
if (delay <= 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exitCode && *exitCode >= 0 && *exitCode <= 125)
|
||||
{
|
||||
sWorld->ShutdownServ(time, SHUTDOWN_MASK_RESTART, *exitCode);
|
||||
sWorld->ShutdownServ(delay, SHUTDOWN_MASK_RESTART, *exitCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
sWorld->ShutdownServ(time, SHUTDOWN_MASK_RESTART, RESTART_EXIT_CODE, strReason);
|
||||
sWorld->ShutdownServ(delay, SHUTDOWN_MASK_RESTART, RESTART_EXIT_CODE, strReason);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleServerIdleRestartCommand(ChatHandler* /*handler*/, int32 time, Optional<int32> exitCode, Tail reason)
|
||||
static bool HandleServerIdleRestartCommand(ChatHandler* handler, std::string time, Optional<int32> exitCode, Tail reason)
|
||||
{
|
||||
std::wstring wReason = std::wstring();
|
||||
std::string strReason = std::string();
|
||||
|
||||
if (time.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Acore::StringTo<int32>(time).value_or(0) < 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reason.empty())
|
||||
{
|
||||
if (!Utf8toWStr(reason, wReason))
|
||||
@@ -358,23 +420,48 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
int32 delay = TimeStringToSecs(time);
|
||||
if (delay <= 0)
|
||||
{
|
||||
delay = Acore::StringTo<int32>(time).value_or(0);
|
||||
}
|
||||
|
||||
if (delay <= 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exitCode && *exitCode >= 0 && *exitCode <= 125)
|
||||
{
|
||||
sWorld->ShutdownServ(time, SHUTDOWN_MASK_RESTART | SHUTDOWN_MASK_IDLE, *exitCode);
|
||||
sWorld->ShutdownServ(delay, SHUTDOWN_MASK_RESTART | SHUTDOWN_MASK_IDLE, *exitCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
sWorld->ShutdownServ(time, SHUTDOWN_MASK_RESTART | SHUTDOWN_MASK_IDLE, RESTART_EXIT_CODE, strReason);
|
||||
sWorld->ShutdownServ(delay, SHUTDOWN_MASK_RESTART | SHUTDOWN_MASK_IDLE, RESTART_EXIT_CODE, strReason);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleServerIdleShutDownCommand(ChatHandler* /*handler*/, int32 time, Optional<int32> exitCode, Tail reason)
|
||||
static bool HandleServerIdleShutDownCommand(ChatHandler* handler, std::string time, Optional<int32> exitCode, Tail reason)
|
||||
{
|
||||
std::wstring wReason = std::wstring();
|
||||
std::string strReason = std::string();
|
||||
|
||||
if (time.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Acore::StringTo<int32>(time).value_or(0) < 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reason.empty())
|
||||
{
|
||||
if (!Utf8toWStr(reason, wReason))
|
||||
@@ -388,13 +475,26 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
int32 delay = TimeStringToSecs(time);
|
||||
if (delay <= 0)
|
||||
{
|
||||
delay = Acore::StringTo<int32>(time).value_or(0);
|
||||
}
|
||||
|
||||
if (delay <= 0)
|
||||
{
|
||||
handler->SendSysMessage(LANG_BAD_VALUE);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (exitCode && *exitCode >= 0 && *exitCode <= 125)
|
||||
{
|
||||
sWorld->ShutdownServ(time, SHUTDOWN_MASK_IDLE, *exitCode);
|
||||
sWorld->ShutdownServ(delay, SHUTDOWN_MASK_IDLE, *exitCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
sWorld->ShutdownServ(time, SHUTDOWN_MASK_IDLE, SHUTDOWN_EXIT_CODE, strReason);
|
||||
sWorld->ShutdownServ(delay, SHUTDOWN_MASK_IDLE, SHUTDOWN_EXIT_CODE, strReason);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -80,7 +80,10 @@ public:
|
||||
{
|
||||
if (hasYelled < 5)
|
||||
{
|
||||
Talk(SenatorYells[hasYelled]);
|
||||
if (me->IsAlive())
|
||||
{
|
||||
Talk(SenatorYells[hasYelled]);
|
||||
}
|
||||
}
|
||||
hasYelled++;
|
||||
}
|
||||
|
||||
@@ -15,19 +15,14 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* ScriptData
|
||||
SDName: Boss_Mandokir
|
||||
SD%Complete: 90
|
||||
SDComment: Ohgan function needs improvements.
|
||||
SDCategory: Zul'Gurub
|
||||
EndScriptData */
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "Spell.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellScript.h"
|
||||
#include "zulgurub.h"
|
||||
#include "Player.h"
|
||||
#include "TaskScheduler.h"
|
||||
|
||||
enum Says
|
||||
{
|
||||
@@ -41,15 +36,19 @@ enum Says
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_CHARGE = 24408, // seen
|
||||
SPELL_OVERPOWER = 24407, // Seen
|
||||
SPELL_FEAR = 29321,
|
||||
SPELL_WHIRLWIND = 13736, // Triggers 15589
|
||||
SPELL_MORTAL_STRIKE = 16856, // Seen
|
||||
SPELL_FRENZY = 24318, // seen
|
||||
SPELL_WATCH = 24314, // seen 24315, 24316
|
||||
SPELL_WATCH_CHARGE = 24315, // Triggers 24316
|
||||
SPELL_LEVEL_UP = 24312 //
|
||||
SPELL_CHARGE = 24408,
|
||||
SPELL_OVERPOWER = 24407,
|
||||
SPELL_FRIGHTENING_SHOUT = 19134,
|
||||
SPELL_WHIRLWIND = 13736, // triggers 15589
|
||||
SPELL_MORTAL_STRIKE = 16856,
|
||||
SPELL_FRENZY = 24318,
|
||||
SPELL_WATCH = 24314, // triggers 24315 and 24316
|
||||
SPELL_WATCH_CHARGE = 24315, // triggers 24316
|
||||
SPELL_LEVEL_UP = 24312,
|
||||
SPELL_EXECUTE = 7160,
|
||||
SPELL_MANDOKIR_CLEAVE = 20691,
|
||||
|
||||
SPELL_REVIVE = 24341 // chained spirit
|
||||
};
|
||||
|
||||
enum Events
|
||||
@@ -62,18 +61,29 @@ enum Events
|
||||
EVENT_WHIRLWIND = 6,
|
||||
EVENT_CHECK_OHGAN = 7,
|
||||
EVENT_WATCH_PLAYER = 8,
|
||||
EVENT_CHARGE_PLAYER = 9
|
||||
EVENT_CHARGE_PLAYER = 9,
|
||||
EVENT_EXECUTE = 10,
|
||||
EVENT_FRIGHTENING_SHOUT = 11,
|
||||
EVENT_CLEAVE = 12
|
||||
};
|
||||
|
||||
enum Action
|
||||
{
|
||||
ACTION_START_REVIVE = 1, // broodlord mandokir
|
||||
ACTION_REVIVE = 2 // chained spirit
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
POINT_START_REVIVE = 1, // chained spirit
|
||||
|
||||
MODEL_OHGAN_MOUNT = 15271,
|
||||
PATH_MANDOKIR = 492861,
|
||||
POINT_MANDOKIR_END = 24,
|
||||
CHAINED_SPIRT_COUNT = 20
|
||||
CHAINED_SPIRIT_COUNT = 20
|
||||
};
|
||||
|
||||
Position const PosSummonChainedSpirits[CHAINED_SPIRT_COUNT] =
|
||||
Position const PosSummonChainedSpirits[CHAINED_SPIRIT_COUNT] =
|
||||
{
|
||||
{ -12167.17f, -1979.330f, 133.0992f, 2.268928f },
|
||||
{ -12262.74f, -1953.394f, 133.5496f, 0.593412f },
|
||||
@@ -114,28 +124,36 @@ public:
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
BossAI::Reset();
|
||||
killCount = 0;
|
||||
if (me->GetPositionZ() > 140.0f)
|
||||
{
|
||||
events.ScheduleEvent(EVENT_CHECK_START, 1000);
|
||||
if (Creature* speaker = ObjectAccessor::GetCreature(*me, instance->GetGuidData(NPC_VILEBRANCH_SPEAKER)))
|
||||
{
|
||||
if (!speaker->IsAlive())
|
||||
{
|
||||
speaker->Respawn(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
killCount = 0;
|
||||
me->RemoveAurasDueToSpell(SPELL_FRENZY);
|
||||
me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
|
||||
summons.DespawnAll();
|
||||
instance->SetBossState(DATA_OHGAN, NOT_STARTED);
|
||||
me->Mount(MODEL_OHGAN_MOUNT);
|
||||
reviveGUID.Clear();
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
// Do not want to unsummon Ohgan
|
||||
for (int i = 0; i < CHAINED_SPIRT_COUNT; ++i)
|
||||
if (Creature* unsummon = ObjectAccessor::GetCreature(*me, chainedSpirtGUIDs[i]))
|
||||
for (int i = 0; i < CHAINED_SPIRIT_COUNT; ++i)
|
||||
{
|
||||
if (Creature* unsummon = ObjectAccessor::GetCreature(*me, chainedSpiritGUIDs[i]))
|
||||
{
|
||||
unsummon->DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
instance->SetBossState(DATA_MANDOKIR, DONE);
|
||||
instance->SaveToDB();
|
||||
}
|
||||
@@ -143,22 +161,23 @@ public:
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_OVERPOWER, urand(7000, 9000));
|
||||
events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(12000, 18000));
|
||||
events.ScheduleEvent(EVENT_OVERPOWER, urand(6000, 8000));
|
||||
events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(14000, 28000));
|
||||
events.ScheduleEvent(EVENT_WHIRLWIND, urand(24000, 30000));
|
||||
events.ScheduleEvent(EVENT_CHECK_OHGAN, 1000);
|
||||
events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(13000, 15000));
|
||||
events.ScheduleEvent(EVENT_CHARGE_PLAYER, urand(33000, 38000));
|
||||
events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 24000));
|
||||
events.ScheduleEvent(EVENT_CHARGE_PLAYER, urand(30000, 40000));
|
||||
events.ScheduleEvent(EVENT_EXECUTE, urand(7000, 14000));
|
||||
events.ScheduleEvent(EVENT_CLEAVE, urand(10000, 20000));
|
||||
me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
|
||||
Talk(SAY_AGGRO);
|
||||
me->Dismount();
|
||||
// Summon Ohgan (Spell missing) TEMP HACK
|
||||
me->SummonCreature(NPC_OHGAN, me->GetPositionX() - 3, me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 35000);
|
||||
// Summon Chained Spirits
|
||||
for (int i = 0; i < CHAINED_SPIRT_COUNT; ++i)
|
||||
for (int i = 0; i < CHAINED_SPIRIT_COUNT; ++i)
|
||||
{
|
||||
Creature* chainedSpirt = me->SummonCreature(NPC_CHAINED_SPIRT, PosSummonChainedSpirits[i], TEMPSUMMON_CORPSE_DESPAWN);
|
||||
chainedSpirtGUIDs[i] = chainedSpirt->GetGUID();
|
||||
Creature* chainedSpirit = me->SummonCreature(NPC_CHAINED_SPIRIT, PosSummonChainedSpirits[i], TEMPSUMMON_CORPSE_DESPAWN);
|
||||
chainedSpiritGUIDs[i] = chainedSpirit->GetGUID();
|
||||
}
|
||||
DoZoneInCombat();
|
||||
}
|
||||
@@ -168,17 +187,49 @@ public:
|
||||
if (victim->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
reviveGUID = victim->GetGUID();
|
||||
DoAction(ACTION_START_REVIVE);
|
||||
if (++killCount == 3)
|
||||
{
|
||||
Talk(SAY_DING_KILL);
|
||||
if (Creature* jindo = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_JINDO)))
|
||||
{
|
||||
if (jindo->IsAlive())
|
||||
{
|
||||
jindo->AI()->Talk(SAY_GRATS_JINDO);
|
||||
}
|
||||
}
|
||||
DoCast(me, SPELL_LEVEL_UP, true);
|
||||
killCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action == ACTION_START_REVIVE)
|
||||
{
|
||||
std::list<Creature*> creatures;
|
||||
GetCreatureListWithEntryInGrid(creatures, me, NPC_CHAINED_SPIRIT, 200.0f);
|
||||
if (creatures.empty())
|
||||
return;
|
||||
|
||||
for (std::list<Creature*>::iterator itr = creatures.begin(); itr != creatures.end(); ++itr)
|
||||
{
|
||||
if (Creature* chainedSpirit = ObjectAccessor::GetCreature(*me, (*itr)->GetGUID()))
|
||||
{
|
||||
chainedSpirit->AI()->SetGUID(reviveGUID);
|
||||
chainedSpirit->AI()->DoAction(ACTION_REVIVE);
|
||||
reviveGUID.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetGUID(ObjectGuid const guid, int32 /*type = 0 */) override
|
||||
{
|
||||
reviveGUID = guid;
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 id) override
|
||||
{
|
||||
if (type == WAYPOINT_MOTION_TYPE)
|
||||
@@ -211,7 +262,9 @@ public:
|
||||
events.ScheduleEvent(EVENT_STARTED, 6000);
|
||||
}
|
||||
else
|
||||
{
|
||||
events.ScheduleEvent(EVENT_CHECK_START, 1000);
|
||||
}
|
||||
break;
|
||||
case EVENT_STARTED:
|
||||
me->RemoveUnitFlag(UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_IMMUNE_TO_NPC);
|
||||
@@ -232,13 +285,12 @@ public:
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_OVERPOWER:
|
||||
DoCastVictim(SPELL_OVERPOWER, true);
|
||||
events.ScheduleEvent(EVENT_OVERPOWER, urand(6000, 12000));
|
||||
DoCastVictim(SPELL_OVERPOWER);
|
||||
events.ScheduleEvent(EVENT_OVERPOWER, urand(6000, 8000));
|
||||
break;
|
||||
case EVENT_MORTAL_STRIKE:
|
||||
if (me->GetVictim() && me->GetVictim()->HealthBelowPct(50))
|
||||
DoCastVictim(SPELL_MORTAL_STRIKE, true);
|
||||
events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(12000, 18000));
|
||||
DoCastVictim(SPELL_MORTAL_STRIKE);
|
||||
events.ScheduleEvent(EVENT_MORTAL_STRIKE, urand(14000, 28000));
|
||||
break;
|
||||
case EVENT_WHIRLWIND:
|
||||
DoCast(me, SPELL_WHIRLWIND);
|
||||
@@ -251,7 +303,9 @@ public:
|
||||
Talk(SAY_OHGAN_DEAD);
|
||||
}
|
||||
else
|
||||
{
|
||||
events.ScheduleEvent(EVENT_CHECK_OHGAN, 1000);
|
||||
}
|
||||
break;
|
||||
case EVENT_WATCH_PLAYER:
|
||||
if (Unit* player = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
|
||||
@@ -259,23 +313,57 @@ public:
|
||||
DoCast(player, SPELL_WATCH);
|
||||
Talk(SAY_WATCH, player);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 15000));
|
||||
events.ScheduleEvent(EVENT_WATCH_PLAYER, urand(12000, 24000));
|
||||
break;
|
||||
case EVENT_CHARGE_PLAYER:
|
||||
DoCast(SelectTarget(SelectTargetMethod::Random, 0, 40, true), SPELL_CHARGE);
|
||||
events.ScheduleEvent(EVENT_CHARGE_PLAYER, urand(22000, 30000));
|
||||
events.ScheduleEvent(EVENT_FRIGHTENING_SHOUT, 1500);
|
||||
if (Unit* mainTarget = SelectTarget(SelectTargetMethod::MaxThreat, 0, 100.0f))
|
||||
{
|
||||
me->GetThreatMgr().modifyThreatPercent(mainTarget, -100);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHARGE_PLAYER, urand(30000, 40000));
|
||||
break;
|
||||
case EVENT_EXECUTE:
|
||||
if (me->GetVictim() && me->GetVictim()->HealthBelowPct(20))
|
||||
{
|
||||
DoCastVictim(SPELL_EXECUTE, true);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_EXECUTE, urand(7000, 14000));
|
||||
break;
|
||||
case EVENT_FRIGHTENING_SHOUT:
|
||||
DoCastAOE(SPELL_FRIGHTENING_SHOUT);
|
||||
break;
|
||||
case EVENT_CLEAVE:
|
||||
{
|
||||
std::list<Unit*> meleeRangeTargets;
|
||||
auto i = me->GetThreatMgr().getThreatList().begin();
|
||||
for (; i != me->GetThreatMgr().getThreatList().end(); ++i)
|
||||
{
|
||||
Unit* target = (*i)->getTarget();
|
||||
if (me->IsWithinMeleeRange(target))
|
||||
{
|
||||
meleeRangeTargets.push_back(target);
|
||||
}
|
||||
}
|
||||
if (meleeRangeTargets.size() >= 5)
|
||||
{
|
||||
DoCastVictim(SPELL_MANDOKIR_CLEAVE);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CLEAVE, urand(10000, 20000));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
uint8 killCount;
|
||||
ObjectGuid chainedSpirtGUIDs[CHAINED_SPIRT_COUNT];
|
||||
ObjectGuid chainedSpiritGUIDs[CHAINED_SPIRIT_COUNT];
|
||||
ObjectGuid reviveGUID;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
@@ -288,7 +376,8 @@ public:
|
||||
|
||||
enum OhganSpells
|
||||
{
|
||||
SPELL_SUNDERARMOR = 24317
|
||||
SPELL_SUNDERARMOR = 24317,
|
||||
SPELL_THRASH = 3417 // Triggers 3391
|
||||
};
|
||||
|
||||
class npc_ohgan : public CreatureScript
|
||||
@@ -302,10 +391,61 @@ public:
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
SunderArmor_Timer = 5000;
|
||||
me->AddAura(SPELL_THRASH, me);
|
||||
_scheduler.CancelAll();
|
||||
_scheduler.SetValidator([this]
|
||||
{
|
||||
return !me->HasUnitState(UNIT_STATE_CASTING);
|
||||
});
|
||||
|
||||
reviveGUID.Clear();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override { }
|
||||
void EnterCombat(Unit* victim) override
|
||||
{
|
||||
if (victim->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
reviveGUID = victim->GetGUID();
|
||||
DoAction(ACTION_START_REVIVE);
|
||||
_scheduler.Schedule(6s, 12s, [this](TaskContext context)
|
||||
{
|
||||
DoCastVictim(SPELL_SUNDERARMOR);
|
||||
context.Repeat(6s, 12s);
|
||||
});
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (victim->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
reviveGUID = victim->GetGUID();
|
||||
DoAction(ACTION_START_REVIVE);
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action == ACTION_START_REVIVE)
|
||||
{
|
||||
std::list<Creature*> creatures;
|
||||
GetCreatureListWithEntryInGrid(creatures, me, NPC_CHAINED_SPIRIT, 200.0f);
|
||||
if (creatures.empty())
|
||||
return;
|
||||
|
||||
for (Creature* chainedSpirit : creatures)
|
||||
{
|
||||
chainedSpirit->AI()->SetGUID(reviveGUID);
|
||||
chainedSpirit->AI()->DoAction(ACTION_REVIVE);
|
||||
reviveGUID.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetGUID(ObjectGuid const guid, int32 /*type = 0 */) override
|
||||
{
|
||||
reviveGUID = guid;
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
@@ -314,23 +454,20 @@ public:
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
// Return since we have no target
|
||||
if (!UpdateVictim())
|
||||
return;
|
||||
_scheduler.Update(diff);
|
||||
|
||||
if (SunderArmor_Timer <= diff)
|
||||
if (!UpdateVictim())
|
||||
{
|
||||
DoCastVictim(SPELL_SUNDERARMOR, true);
|
||||
SunderArmor_Timer = urand(10000, 15000);
|
||||
return;
|
||||
}
|
||||
else SunderArmor_Timer -= diff;
|
||||
|
||||
DoMeleeAttackIfReady();
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 SunderArmor_Timer;
|
||||
InstanceScript* instance;
|
||||
ObjectGuid reviveGUID;
|
||||
TaskScheduler _scheduler;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
@@ -339,6 +476,75 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct npc_chained_spirit : public ScriptedAI
|
||||
{
|
||||
public:
|
||||
npc_chained_spirit(Creature* creature) : ScriptedAI(creature)
|
||||
{
|
||||
instance = me->GetInstanceScript();
|
||||
me->AddUnitMovementFlag(MOVEMENTFLAG_HOVER);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
revivePlayerGUID.Clear();
|
||||
}
|
||||
|
||||
void SetGUID(ObjectGuid const guid, int32 /*id*/) override
|
||||
{
|
||||
revivePlayerGUID = guid;
|
||||
}
|
||||
|
||||
void DoAction(int32 action) override
|
||||
{
|
||||
if (action == ACTION_REVIVE)
|
||||
{
|
||||
if (Player* target = ObjectAccessor::GetPlayer(*me, revivePlayerGUID))
|
||||
{
|
||||
Position pos;
|
||||
target->GetNearPoint(me, pos.m_positionX, pos.m_positionY, pos.m_positionZ, 0.0f, 0.0f, target->GetAbsoluteAngle(me));
|
||||
me->GetMotionMaster()->MovePoint(POINT_START_REVIVE, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MovementInform(uint32 type, uint32 pointId) override
|
||||
{
|
||||
if (type != POINT_MOTION_TYPE || !revivePlayerGUID)
|
||||
return;
|
||||
|
||||
if (pointId == POINT_START_REVIVE)
|
||||
{
|
||||
if (Player* target = ObjectAccessor::GetPlayer(*me, revivePlayerGUID))
|
||||
{
|
||||
DoCast(target, SPELL_REVIVE);
|
||||
}
|
||||
me->DespawnOrUnsummon(1000);
|
||||
}
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
Player* target = ObjectAccessor::GetPlayer(*me, revivePlayerGUID);
|
||||
if (!target || target->IsAlive())
|
||||
return;
|
||||
|
||||
if (Creature* mandokir = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MANDOKIR)))
|
||||
{
|
||||
mandokir->GetAI()->SetGUID(target->GetGUID());
|
||||
mandokir->GetAI()->DoAction(ACTION_START_REVIVE);
|
||||
}
|
||||
me->DespawnOrUnsummon();
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 /*diff*/) override { }
|
||||
|
||||
private:
|
||||
InstanceScript* instance;
|
||||
ObjectGuid revivePlayerGUID;
|
||||
|
||||
};
|
||||
|
||||
enum VilebranchSpells
|
||||
{
|
||||
SPELL_DEMORALIZING_SHOUT = 13730,
|
||||
@@ -414,9 +620,15 @@ public:
|
||||
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (Unit* caster = GetCaster())
|
||||
{
|
||||
if (Unit* target = GetTarget())
|
||||
{
|
||||
if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE && GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH)
|
||||
caster->CastSpell(target, SPELL_WATCH_CHARGE);
|
||||
{
|
||||
caster->CastSpell(target, SPELL_WATCH_CHARGE, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
@@ -435,6 +647,7 @@ void AddSC_boss_mandokir()
|
||||
{
|
||||
new boss_mandokir();
|
||||
new npc_ohgan();
|
||||
RegisterZulGurubCreatureAI(npc_chained_spirit);
|
||||
new npc_vilebranch_speaker();
|
||||
new spell_threatening_gaze();
|
||||
}
|
||||
|
||||
@@ -28,14 +28,16 @@ EndScriptData */
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_LIGHTNINGCLOUD = 25033,
|
||||
SPELL_LIGHTNINGWAVE = 24819
|
||||
SPELL_LIGHTNING_CLOUD = 24683,
|
||||
SPELL_CHAIN_LIGHTNING = 24680,
|
||||
SPELL_FORKED_LIGHTNING = 24682
|
||||
};
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_LIGHTNINGCLOUD = 1,
|
||||
EVENT_LIGHTNINGWAVE = 2
|
||||
EVENT_LIGHTNING_CLOUD = 1,
|
||||
EVENT_CHAIN_LIGHTNING = 2,
|
||||
EVENT_FORKED_LIGHTNING = 3
|
||||
};
|
||||
|
||||
class boss_wushoolay : public CreatureScript
|
||||
@@ -47,21 +49,12 @@ public:
|
||||
{
|
||||
boss_wushoolayAI(Creature* creature) : BossAI(creature, DATA_EDGE_OF_MADNESS) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_LIGHTNINGCLOUD, urand(5000, 10000));
|
||||
events.ScheduleEvent(EVENT_LIGHTNINGWAVE, urand(8000, 16000));
|
||||
events.ScheduleEvent(EVENT_LIGHTNING_CLOUD, 7s, 15s);
|
||||
events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 12s, 16s);
|
||||
events.ScheduleEvent(EVENT_FORKED_LIGHTNING, 8s, 12s);
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
@@ -78,13 +71,23 @@ public:
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_LIGHTNINGCLOUD:
|
||||
DoCastVictim(SPELL_LIGHTNINGCLOUD, true);
|
||||
events.ScheduleEvent(EVENT_LIGHTNINGCLOUD, urand(15000, 20000));
|
||||
case EVENT_LIGHTNING_CLOUD:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
{
|
||||
me->CastSpell(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), SPELL_LIGHTNING_CLOUD, false);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_LIGHTNING_CLOUD, 9s, 20s);
|
||||
break;
|
||||
case EVENT_LIGHTNINGWAVE:
|
||||
DoCast(SelectTarget(SelectTargetMethod::Random, 0, 100, true), SPELL_LIGHTNINGWAVE);
|
||||
events.ScheduleEvent(EVENT_LIGHTNINGWAVE, urand(12000, 16000));
|
||||
case EVENT_CHAIN_LIGHTNING:
|
||||
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
|
||||
{
|
||||
DoCast(target, SPELL_CHAIN_LIGHTNING);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 12s, 24s);
|
||||
break;
|
||||
case EVENT_FORKED_LIGHTNING:
|
||||
DoCastAOE(SPELL_FORKED_LIGHTNING);
|
||||
events.ScheduleEvent(EVENT_FORKED_LIGHTNING, 8s, 20s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -57,7 +57,7 @@ enum CreatureIds
|
||||
NPC_MANDOKIR = 11382, // Mandokir Event
|
||||
NPC_OHGAN = 14988, // Mandokir Event
|
||||
NPC_VILEBRANCH_SPEAKER = 11391, // Mandokir Event
|
||||
NPC_CHAINED_SPIRT = 15117, // Mandokir Event
|
||||
NPC_CHAINED_SPIRIT = 15117, // Mandokir Event
|
||||
NPC_HAKKAR = 14834,
|
||||
NPC_ZULGURUB_TIGER = 11361
|
||||
};
|
||||
@@ -74,4 +74,6 @@ inline AI* GetZulGurubAI(T* obj)
|
||||
return GetInstanceAI<AI>(obj, ZGScriptName);
|
||||
}
|
||||
|
||||
#define RegisterZulGurubCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetZulGurubAI)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -262,9 +262,9 @@ public:
|
||||
}
|
||||
|
||||
// Summon druid spirits on 75%, 50% and 25% health
|
||||
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
|
||||
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (!HealthAbovePct(100 - 25 * _stage))
|
||||
if (me->HealthBelowPctDamaged(100 - (25 * _stage), damage))
|
||||
{
|
||||
Talk(SAY_YSONDRE_SUMMON_DRUIDS);
|
||||
|
||||
@@ -349,9 +349,9 @@ public:
|
||||
WorldBossAI::EnterCombat(who);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
|
||||
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (!HealthAbovePct(100 - 25 * _stage))
|
||||
if (me->HealthBelowPctDamaged(100 - (25 * _stage), damage))
|
||||
{
|
||||
Talk(SAY_LETHON_DRAW_SPIRIT);
|
||||
DoCast(me, SPELL_DRAW_SPIRIT);
|
||||
@@ -471,7 +471,10 @@ public:
|
||||
void KilledUnit(Unit* who) override
|
||||
{
|
||||
if (who->GetTypeId() == TYPEID_PLAYER)
|
||||
DoCast(who, SPELL_PUTRID_MUSHROOM, true);
|
||||
{
|
||||
who->CastSpell(who, SPELL_PUTRID_MUSHROOM, true);
|
||||
}
|
||||
|
||||
emerald_dragonAI::KilledUnit(who);
|
||||
}
|
||||
|
||||
@@ -481,9 +484,9 @@ public:
|
||||
WorldBossAI::EnterCombat(who);
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
|
||||
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
if (!HealthAbovePct(100 - 25 * _stage))
|
||||
if (me->HealthBelowPctDamaged(100 - (25 * _stage), damage))
|
||||
{
|
||||
Talk(SAY_EMERISS_CAST_CORRUPTION);
|
||||
DoCast(me, SPELL_CORRUPTION_OF_EARTH, true);
|
||||
@@ -541,7 +544,6 @@ uint32 const TaerarShadeSpells[] =
|
||||
{
|
||||
SPELL_SUMMON_SHADE_1, SPELL_SUMMON_SHADE_2, SPELL_SUMMON_SHADE_3
|
||||
};
|
||||
|
||||
class boss_taerar : public CreatureScript
|
||||
{
|
||||
public:
|
||||
@@ -578,11 +580,11 @@ public:
|
||||
--_shades;
|
||||
}
|
||||
|
||||
void DamageTaken(Unit*, uint32& /*damage*/, DamageEffectType, SpellSchoolMask) override
|
||||
void DamageTaken(Unit*, uint32& damage, DamageEffectType, SpellSchoolMask) override
|
||||
{
|
||||
// At 75, 50 or 25 percent health, we need to activate the shades and go "banished"
|
||||
// Note: _stage holds the amount of times they have been summoned
|
||||
if (!_banished && !HealthAbovePct(100 - 25 * _stage))
|
||||
if (!_banished && me->HealthBelowPctDamaged(100 - (25 * _stage), damage))
|
||||
{
|
||||
_banished = true;
|
||||
_banishedTimer = 60000;
|
||||
@@ -594,9 +596,8 @@ public:
|
||||
|
||||
uint32 count = sizeof(TaerarShadeSpells) / sizeof(uint32);
|
||||
for (uint32 i = 0; i < count; ++i)
|
||||
DoCastVictim(TaerarShadeSpells[i], true);
|
||||
DoCast(TaerarShadeSpells[i]);
|
||||
_shades += count;
|
||||
|
||||
DoCast(SPELL_SHADE);
|
||||
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
@@ -604,7 +605,6 @@ public:
|
||||
++_stage;
|
||||
}
|
||||
}
|
||||
|
||||
void ExecuteEvent(uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
@@ -648,7 +648,6 @@ public:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
emerald_dragonAI::UpdateAI(diff);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user