mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-13 17:19:07 +00:00
Merge branch 'azerothcore:master' into Playerbot
This commit is contained in:
@@ -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