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

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