Merge branch 'azerothcore:master' into Playerbot

This commit is contained in:
ZhengPeiRu21
2022-06-13 15:00:30 -06:00
committed by GitHub
24 changed files with 707 additions and 155 deletions

View 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);

View 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;

View 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');

View 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;

View 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";

View 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');

View File

@@ -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 ""

View File

@@ -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));
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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);

View File

@@ -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())

View File

@@ -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)
{

View File

@@ -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)

View File

@@ -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()

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -80,7 +80,10 @@ public:
{
if (hasYelled < 5)
{
Talk(SenatorYells[hasYelled]);
if (me->IsAlive())
{
Talk(SenatorYells[hasYelled]);
}
}
hasYelled++;
}

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
}