Merge branch 'master' of github.com:azerothcore/azerothcore-wotlk into Playerbot

This commit is contained in:
Yunfan Li
2023-10-22 19:52:23 +08:00
203 changed files with 7031 additions and 2667 deletions

View File

@@ -25,13 +25,8 @@ EndScriptData */
#include "Chat.h"
#include "Guild.h"
#include "GuildMgr.h"
#include "Language.h"
#include "ScriptMgr.h"
#if AC_COMPILER == AC_COMPILER_GNU
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
using namespace Acore::ChatCommands;
class guild_commandscript : public CommandScript
@@ -43,50 +38,38 @@ public:
{
static ChatCommandTable guildCommandTable =
{
{ "create", SEC_GAMEMASTER, true, &HandleGuildCreateCommand, "" },
{ "delete", SEC_GAMEMASTER, true, &HandleGuildDeleteCommand, "" },
{ "invite", SEC_GAMEMASTER, true, &HandleGuildInviteCommand, "" },
{ "uninvite", SEC_GAMEMASTER, true, &HandleGuildUninviteCommand, "" },
{ "rank", SEC_GAMEMASTER, true, &HandleGuildRankCommand, "" },
{ "rename", SEC_GAMEMASTER, true, &HandleGuildRenameCommand, "" },
{ "info", SEC_GAMEMASTER, true, &HandleGuildInfoCommand, "" }
{ "create", HandleGuildCreateCommand, SEC_GAMEMASTER, Console::Yes },
{ "delete", HandleGuildDeleteCommand, SEC_GAMEMASTER, Console::Yes },
{ "invite", HandleGuildInviteCommand, SEC_GAMEMASTER, Console::Yes },
{ "uninvite", HandleGuildUninviteCommand, SEC_GAMEMASTER, Console::Yes },
{ "rank", HandleGuildRankCommand, SEC_GAMEMASTER, Console::Yes },
{ "rename", HandleGuildRenameCommand, SEC_GAMEMASTER, Console::Yes },
{ "info", HandleGuildInfoCommand, SEC_GAMEMASTER, Console::Yes }
};
static ChatCommandTable commandTable =
{
{ "guild", SEC_GAMEMASTER, true, nullptr, "", guildCommandTable }
{ "guild", guildCommandTable }
};
return commandTable;
}
/** \brief GM command level 3 - Create a guild.
*
* This command allows a GM (level 3) to create a guild.
*
* The "args" parameter contains the name of the guild leader
* and then the name of the guild.
*
*/
static bool HandleGuildCreateCommand(ChatHandler* handler, char const* args)
static bool HandleGuildCreateCommand(ChatHandler* handler, Optional<PlayerIdentifier> target, std::string_view guildName)
{
if (!*args)
if (!target)
{
target = PlayerIdentifier::FromTargetOrSelf(handler);
}
if (!target || !target->IsConnected())
{
handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
handler->SetSentErrorMessage(true);
return false;
}
// if not guild name only (in "") then player name
Player* target;
if (!handler->extractPlayerTarget(*args != '"' ? (char*)args : nullptr, &target))
return false;
Player* playerTarget = target->GetConnectedPlayer();
char* tailStr = *args != '"' ? strtok(nullptr, "") : (char*)args;
if (!tailStr)
return false;
char* guildStr = handler->extractQuotedArg(tailStr);
if (!guildStr)
return false;
std::string guildName = guildStr;
if (target->GetGuildId())
if (playerTarget->GetGuildId())
{
handler->SendSysMessage(LANG_PLAYER_IN_GUILD);
handler->SetSentErrorMessage(true);
@@ -108,7 +91,7 @@ public:
}
Guild* guild = new Guild;
if (!guild->Create(target, guildName))
if (!guild->Create(playerTarget, guildName))
{
delete guild;
handler->SendSysMessage(LANG_GUILD_NOT_CREATED);
@@ -121,16 +104,12 @@ public:
return true;
}
static bool HandleGuildDeleteCommand(ChatHandler* handler, char const* args)
static bool HandleGuildDeleteCommand(ChatHandler*, std::string_view guildName)
{
if (!*args)
if (guildName.empty())
{
return false;
char* guildStr = handler->extractQuotedArg((char*)args);
if (!guildStr)
return false;
std::string guildName = guildStr;
}
Guild* targetGuild = sGuildMgr->GetGuildByName(guildName);
if (!targetGuild)
@@ -142,41 +121,41 @@ public:
return true;
}
static bool HandleGuildInviteCommand(ChatHandler* handler, char const* args)
static bool HandleGuildInviteCommand(ChatHandler* handler, Optional<PlayerIdentifier> target, std::string_view guildName)
{
if (!*args)
return false;
if (!target)
{
target = PlayerIdentifier::FromTargetOrSelf(handler);
}
// if not guild name only (in "") then player name
ObjectGuid targetGuid;
if (!handler->extractPlayerTarget(*args != '"' ? (char*)args : nullptr, nullptr, &targetGuid))
if (!target)
{
return false;
}
char* tailStr = *args != '"' ? strtok(nullptr, "") : (char*)args;
if (!tailStr)
return false;
char* guildStr = handler->extractQuotedArg(tailStr);
if (!guildStr)
return false;
std::string guildName = guildStr;
Guild* targetGuild = sGuildMgr->GetGuildByName(guildName);
if (!targetGuild)
return false;
// player's guild membership checked in AddMember before add
return targetGuild->AddMember(targetGuid);
return targetGuild->AddMember(target->GetGUID());
}
static bool HandleGuildUninviteCommand(ChatHandler* handler, char const* args)
static bool HandleGuildUninviteCommand(ChatHandler* handler, Optional<PlayerIdentifier> target)
{
Player* target;
ObjectGuid targetGuid;
if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid))
return false;
if (!target)
{
target = PlayerIdentifier::FromTargetOrSelf(handler);
}
uint32 guildId = target ? target->GetGuildId() : sCharacterCache->GetCharacterGuildIdByGuid(targetGuid);
if (!target)
{
return false;
}
Player* playerTarget = target->GetConnectedPlayer();
uint32 guildId = playerTarget ? playerTarget->GetGuildId() : sCharacterCache->GetCharacterGuildIdByGuid(target->GetGUID());
if (!guildId)
return false;
@@ -184,7 +163,7 @@ public:
if (!targetGuild)
return false;
targetGuild->DeleteMember(targetGuid, false, true, true);
targetGuild->DeleteMember(target->GetGUID(), false, true, true);
return true;
}
@@ -207,26 +186,15 @@ public:
return targetGuild->ChangeMemberRank(player->GetGUID(), rank);
}
static bool HandleGuildRenameCommand(ChatHandler* handler, char const* _args)
static bool HandleGuildRenameCommand(ChatHandler* handler, std::string_view oldGuildStr, std::string_view newGuildStr)
{
if (!*_args)
return false;
char *args = (char *)_args;
char const* oldGuildStr = handler->extractQuotedArg(args);
if (!oldGuildStr)
if (!oldGuildStr.empty())
{
handler->SendSysMessage(LANG_BAD_VALUE);
handler->SetSentErrorMessage(true);
return false;
}
char const* newGuildStr = handler->extractQuotedArg(strtok(nullptr, ""));
if (!newGuildStr)
if (newGuildStr.empty())
{
handler->SendSysMessage(LANG_INSERT_GUILD_NAME);
handler->SetSentErrorMessage(true);
return false;
}
@@ -256,35 +224,40 @@ public:
return true;
}
static bool HandleGuildInfoCommand(ChatHandler* handler, char const* args)
static bool HandleGuildInfoCommand(ChatHandler* handler, Optional<Variant<ObjectGuid::LowType, std::string_view>> const& guildIdentifier)
{
Guild* guild = nullptr;
if (args && args[0] != '\0')
if (guildIdentifier)
{
if (isNumeric(args))
guild = sGuildMgr->GetGuildById(strtoull(args, nullptr, 10));
if (ObjectGuid::LowType const* guid = std::get_if<ObjectGuid::LowType>(&*guildIdentifier))
guild = sGuildMgr->GetGuildById(*guid);
else
guild = sGuildMgr->GetGuildByName(args);
guild = sGuildMgr->GetGuildByName(guildIdentifier->get<std::string_view>());
}
else if (Player* target = handler->getSelectedPlayerOrSelf())
guild = target->GetGuild();
else if (Optional<PlayerIdentifier> target = PlayerIdentifier::FromTargetOrSelf(handler); target && target->IsConnected())
guild = target->GetConnectedPlayer()->GetGuild();
if (!guild)
return false;
// Display Guild Information
handler->PSendSysMessage(LANG_GUILD_INFO_NAME, guild->GetName().c_str(), guild->GetId()); // Guild Id + Name
std::string guildMasterName;
if (sCharacterCache->GetCharacterNameByGuid(guild->GetLeaderGUID(), guildMasterName))
{
handler->PSendSysMessage(LANG_GUILD_INFO_GUILD_MASTER, guildMasterName.c_str(), guild->GetLeaderGUID().GetCounter()); // Guild Master
}
handler->PSendSysMessage(LANG_GUILD_INFO_CREATION_DATE, Acore::Time::TimeToHumanReadable(Seconds(guild->GetCreatedDate())).c_str()); // Creation Date
// Format creation date
char createdDateStr[20];
time_t createdDate = guild->GetCreatedDate();
tm localTm;
strftime(createdDateStr, 20, "%Y-%m-%d %H:%M:%S", localtime_r(&createdDate, &localTm));
handler->PSendSysMessage(LANG_GUILD_INFO_CREATION_DATE, createdDateStr); // Creation Date
handler->PSendSysMessage(LANG_GUILD_INFO_MEMBER_COUNT, guild->GetMemberCount()); // Number of Members
handler->PSendSysMessage(LANG_GUILD_INFO_BANK_GOLD, guild->GetTotalBankMoney() / 100 / 100); // Bank Gold (in gold coins)
handler->PSendSysMessage(LANG_GUILD_INFO_MOTD, guild->GetMOTD().c_str()); // Message of the day
handler->PSendSysMessage(LANG_GUILD_INFO_MOTD, guild->GetMOTD().c_str()); // Message of the Day
handler->PSendSysMessage(LANG_GUILD_INFO_EXTRA_INFO, guild->GetInfo().c_str()); // Extra Information
return true;
}

View File

@@ -88,6 +88,7 @@ public:
{
static ChatCommandTable commandTable =
{
{ "commentator", HandleCommentatorCommand, SEC_MODERATOR, Console::No },
{ "dev", HandleDevCommand, SEC_ADMINISTRATOR, Console::No },
{ "gps", HandleGPSCommand, SEC_MODERATOR, Console::No },
{ "aura", HandleAuraCommand, SEC_GAMEMASTER, Console::No },
@@ -451,6 +452,51 @@ public:
return true;
}
static bool HandleCommentatorCommand(ChatHandler* handler, Optional<bool> enableArg)
{
WorldSession* session = handler->GetSession();
if (!session)
{
return false;
}
auto SetCommentatorMod = [&](bool enable)
{
session->SendNotification(enable ? "Commentator mode on" : "Commentator mode off");
session->GetPlayer()->SetCommentator(enable);
};
if (!enableArg)
{
if (!AccountMgr::IsPlayerAccount(session->GetSecurity()) && session->GetPlayer()->IsCommentator())
{
SetCommentatorMod(true);
}
else
{
SetCommentatorMod(false);
}
return true;
}
if (*enableArg)
{
SetCommentatorMod(true);
return true;
}
else
{
SetCommentatorMod(false);
return true;
}
handler->SendSysMessage(LANG_USE_BOL);
handler->SetSentErrorMessage(true);
return false;
}
static bool HandleDevCommand(ChatHandler* handler, Optional<bool> enableArg)
{
WorldSession* session = handler->GetSession();
@@ -467,32 +513,29 @@ public:
sScriptMgr->OnHandleDevCommand(handler->GetSession()->GetPlayer(), enable);
};
if (WorldSession* session = handler->GetSession())
if (!enableArg)
{
if (!enableArg)
{
if (!AccountMgr::IsPlayerAccount(session->GetSecurity()) && session->GetPlayer()->IsDeveloper())
{
SetDevMod(true);
}
else
{
SetDevMod(false);
}
return true;
}
if (*enableArg)
if (!AccountMgr::IsPlayerAccount(session->GetSecurity()) && session->GetPlayer()->IsDeveloper())
{
SetDevMod(true);
return true;
}
else
{
SetDevMod(false);
return true;
}
return true;
}
if (*enableArg)
{
SetDevMod(true);
return true;
}
else
{
SetDevMod(false);
return true;
}
handler->SendSysMessage(LANG_USE_BOL);

View File

@@ -30,10 +30,6 @@ EndScriptData */
#include "Player.h"
#include "ScriptMgr.h"
#if AC_COMPILER == AC_COMPILER_GNU
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
using namespace Acore::ChatCommands;
class reset_commandscript : public CommandScript
@@ -45,48 +41,53 @@ public:
{
static ChatCommandTable resetCommandTable =
{
{ "achievements", SEC_CONSOLE, true, &HandleResetAchievementsCommand, "" },
{ "honor", SEC_ADMINISTRATOR, true, &HandleResetHonorCommand, "" },
{ "level", SEC_ADMINISTRATOR, true, &HandleResetLevelCommand, "" },
{ "spells", SEC_ADMINISTRATOR, true, &HandleResetSpellsCommand, "" },
{ "stats", SEC_ADMINISTRATOR, true, &HandleResetStatsCommand, "" },
{ "talents", SEC_ADMINISTRATOR, true, &HandleResetTalentsCommand, "" },
{ "all", SEC_CONSOLE, true, &HandleResetAllCommand, "" }
{ "achievements", HandleResetAchievementsCommand, SEC_CONSOLE, Console::Yes },
{ "honor", HandleResetHonorCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "level", HandleResetLevelCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "spells", HandleResetSpellsCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "stats", HandleResetStatsCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "talents", HandleResetTalentsCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "all", HandleResetAllCommand, SEC_CONSOLE, Console::Yes }
};
static ChatCommandTable commandTable =
{
{ "reset", SEC_ADMINISTRATOR, true, nullptr, "", resetCommandTable }
{ "reset", resetCommandTable }
};
return commandTable;
}
static bool HandleResetAchievementsCommand(ChatHandler* handler, char const* args)
static bool HandleResetAchievementsCommand(ChatHandler*, Optional<PlayerIdentifier> target)
{
Player* target;
ObjectGuid targetGuid;
if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid))
if (!target)
{
return false;
}
if (target)
target->ResetAchievements();
Player* playerTarget = target->GetConnectedPlayer();
if (playerTarget)
playerTarget->ResetAchievements();
else
AchievementMgr::DeleteFromDB(targetGuid.GetCounter());
AchievementMgr::DeleteFromDB(target->GetGUID().GetCounter());
return true;
}
static bool HandleResetHonorCommand(ChatHandler* handler, char const* args)
static bool HandleResetHonorCommand(ChatHandler*, Optional<PlayerIdentifier> target)
{
Player* target;
if (!handler->extractPlayerTarget((char*)args, &target))
if (!target)
{
return false;
}
target->SetHonorPoints(0);
target->SetUInt32Value(PLAYER_FIELD_KILLS, 0);
target->SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, 0);
target->SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0);
target->SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0);
target->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL);
Player* playerTarget = target->GetConnectedPlayer();
playerTarget->SetHonorPoints(0);
playerTarget->SetUInt32Value(PLAYER_FIELD_KILLS, 0);
playerTarget->SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, 0);
playerTarget->SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0);
playerTarget->SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0);
playerTarget->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL);
return true;
}
@@ -123,156 +124,145 @@ public:
return true;
}
static bool HandleResetLevelCommand(ChatHandler* handler, char const* args)
static bool HandleResetLevelCommand(ChatHandler*, Optional<PlayerIdentifier> target)
{
Player* target;
if (!handler->extractPlayerTarget((char*)args, &target))
if (!target)
{
return false;
}
Player* playerTarget = target->GetConnectedPlayer();
if (!HandleResetStatsOrLevelHelper(playerTarget))
return false;
if (!HandleResetStatsOrLevelHelper(target))
return false;
uint8 oldLevel = target->GetLevel();
uint8 oldLevel = playerTarget->GetLevel();
// set starting level
uint32 startLevel = target->getClass() != CLASS_DEATH_KNIGHT
uint32 startLevel = playerTarget->getClass() != CLASS_DEATH_KNIGHT
? sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL)
: sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL);
target->_ApplyAllLevelScaleItemMods(false);
target->SetLevel(startLevel);
target->InitRunes();
target->InitStatsForLevel(true);
target->InitTaxiNodesForLevel();
target->InitGlyphsForLevel();
target->InitTalentForLevel();
target->SetUInt32Value(PLAYER_XP, 0);
playerTarget->_ApplyAllLevelScaleItemMods(false);
playerTarget->SetLevel(startLevel);
playerTarget->InitRunes();
playerTarget->InitStatsForLevel(true);
playerTarget->InitTaxiNodesForLevel();
playerTarget->InitGlyphsForLevel();
playerTarget->InitTalentForLevel();
playerTarget->SetUInt32Value(PLAYER_XP, 0);
target->_ApplyAllLevelScaleItemMods(true);
playerTarget->_ApplyAllLevelScaleItemMods(true);
// reset level for pet
if (Pet* pet = target->GetPet())
if (Pet* pet = playerTarget->GetPet())
pet->SynchronizeLevelWithOwner();
sScriptMgr->OnPlayerLevelChanged(target, oldLevel);
sScriptMgr->OnPlayerLevelChanged(playerTarget, oldLevel);
return true;
}
static bool HandleResetSpellsCommand(ChatHandler* handler, char const* args)
static bool HandleResetSpellsCommand(ChatHandler* handler, Optional<PlayerIdentifier> target)
{
Player* target;
ObjectGuid targetGuid;
std::string targetName;
if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName))
if (!target)
{
target = PlayerIdentifier::FromTargetOrSelf(handler);
}
if (!target)
{
return false;
}
Player* playerTarget = target->GetConnectedPlayer();
if (target)
{
target->resetSpells(/* bool myClassOnly */);
playerTarget->resetSpells(/* bool myClassOnly */);
ChatHandler(target->GetSession()).SendSysMessage(LANG_RESET_SPELLS);
if (!handler->GetSession() || handler->GetSession()->GetPlayer() != target)
handler->PSendSysMessage(LANG_RESET_SPELLS_ONLINE, handler->GetNameLink(target).c_str());
ChatHandler(playerTarget->GetSession()).SendSysMessage(LANG_RESET_SPELLS);
if (!handler->GetSession() || handler->GetSession()->GetPlayer() != playerTarget)
handler->PSendSysMessage(LANG_RESET_SPELLS_ONLINE, handler->GetNameLink(playerTarget).c_str());
}
else
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
stmt->SetData(0, uint16(AT_LOGIN_RESET_SPELLS));
stmt->SetData(1, targetGuid.GetCounter());
stmt->SetData(1, playerTarget->GetGUID().GetCounter());
CharacterDatabase.Execute(stmt);
handler->PSendSysMessage(LANG_RESET_SPELLS_OFFLINE, targetName.c_str());
handler->PSendSysMessage(LANG_RESET_SPELLS_OFFLINE, target->GetName());
}
return true;
}
static bool HandleResetStatsCommand(ChatHandler* handler, char const* args)
static bool HandleResetStatsCommand(ChatHandler*, Optional<PlayerIdentifier> target)
{
Player* target;
if (!handler->extractPlayerTarget((char*)args, &target))
if (!target)
{
return false;
}
Player* playerTarget = target->GetConnectedPlayer();
if (!HandleResetStatsOrLevelHelper(playerTarget))
return false;
if (!HandleResetStatsOrLevelHelper(target))
return false;
target->InitRunes();
target->InitStatsForLevel(true);
target->InitTaxiNodesForLevel();
target->InitGlyphsForLevel();
target->InitTalentForLevel();
playerTarget->InitRunes();
playerTarget->InitStatsForLevel(true);
playerTarget->InitTaxiNodesForLevel();
playerTarget->InitGlyphsForLevel();
playerTarget->InitTalentForLevel();
return true;
}
static bool HandleResetTalentsCommand(ChatHandler* handler, char const* args)
static bool HandleResetTalentsCommand(ChatHandler* handler, Optional<PlayerIdentifier> target)
{
Player* target;
ObjectGuid targetGuid;
std::string targetName;
if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName))
Player* targetPlayer = nullptr;
if (target)
{
targetPlayer = target->GetConnectedPlayer();
}
else
{
// Try reset talents as Hunter Pet
Creature* creature = handler->getSelectedCreature();
if (!*args && creature && creature->IsPet())
{
Unit* owner = creature->GetOwner();
if (owner && owner->GetTypeId() == TYPEID_PLAYER && creature->ToPet()->IsPermanentPetFor(owner->ToPlayer()))
{
creature->ToPet()->resetTalents();
owner->ToPlayer()->SendTalentsInfoData(true);
ChatHandler(owner->ToPlayer()->GetSession()).SendSysMessage(LANG_RESET_PET_TALENTS);
if (!handler->GetSession() || handler->GetSession()->GetPlayer() != owner->ToPlayer())
handler->PSendSysMessage(LANG_RESET_PET_TALENTS_ONLINE, handler->GetNameLink(owner->ToPlayer()).c_str());
}
return true;
}
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
handler->SetSentErrorMessage(true);
return false;
}
if (target)
if (targetPlayer)
{
target->resetTalents(true);
target->SendTalentsInfoData(false);
ChatHandler(target->GetSession()).SendSysMessage(LANG_RESET_TALENTS);
if (!handler->GetSession() || handler->GetSession()->GetPlayer() != target)
handler->PSendSysMessage(LANG_RESET_TALENTS_ONLINE, handler->GetNameLink(target).c_str());
targetPlayer->resetTalents(true);
targetPlayer->SendTalentsInfoData(false);
ChatHandler(targetPlayer->GetSession()).SendSysMessage(LANG_RESET_TALENTS);
if (!handler->GetSession() || handler->GetSession()->GetPlayer() != targetPlayer)
handler->PSendSysMessage(LANG_RESET_TALENTS_ONLINE, handler->GetNameLink(targetPlayer).c_str());
Pet* pet = target->GetPet();
Pet::resetTalentsForAllPetsOf(target, pet);
Pet* pet = targetPlayer->GetPet();
Pet::resetTalentsForAllPetsOf(targetPlayer, pet);
if (pet)
target->SendTalentsInfoData(true);
targetPlayer->SendTalentsInfoData(true);
return true;
}
else if (targetGuid)
else
{
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
stmt->SetData(0, uint16(AT_LOGIN_RESET_TALENTS | AT_LOGIN_RESET_PET_TALENTS));
stmt->SetData(1, targetGuid.GetCounter());
stmt->SetData(1, target->GetGUID().GetCounter());
CharacterDatabase.Execute(stmt);
std::string nameLink = handler->playerLink(targetName);
std::string nameLink = handler->playerLink(target->GetName());
handler->PSendSysMessage(LANG_RESET_TALENTS_OFFLINE, nameLink.c_str());
return true;
}
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
handler->SetSentErrorMessage(true);
return false;
}
static bool HandleResetAllCommand(ChatHandler* handler, char const* args)
static bool HandleResetAllCommand(ChatHandler* handler, std::string_view caseName)
{
if (!*args)
return false;
std::string caseName = args;
AtLoginFlags atLogin;
// Command specially created as single command to prevent using short case names
@@ -292,7 +282,7 @@ public:
}
else
{
handler->PSendSysMessage(LANG_RESETALL_UNKNOWN_CASE, args);
handler->PSendSysMessage(LANG_RESETALL_UNKNOWN_CASE, caseName);
handler->SetSentErrorMessage(true);
return false;
}
@@ -303,7 +293,7 @@ public:
std::shared_lock<std::shared_mutex> lock(*HashMapHolder<Player>::GetLock());
HashMapHolder<Player>::MapType const& plist = ObjectAccessor::GetPlayers();
for (HashMapHolder<Player>::MapType::const_iterator itr = plist.begin(); itr != plist.end(); ++itr)
for (auto itr = plist.begin(); itr != plist.end(); ++itr)
itr->second->SetAtLoginFlag(atLogin);
return true;

View File

@@ -24,7 +24,6 @@ EndScriptData */
#include "AccountMgr.h"
#include "Chat.h"
#include "Language.h"
#include "ObjectMgr.h"
#include "Opcodes.h"
#include "Player.h"
@@ -32,10 +31,6 @@ EndScriptData */
#include "ScriptMgr.h"
#include "TicketMgr.h"
#if AC_COMPILER == AC_COMPILER_GNU
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
using namespace Acore::ChatCommands;
class ticket_commandscript : public CommandScript
@@ -47,48 +42,38 @@ public:
{
static ChatCommandTable ticketResponseCommandTable =
{
{ "append", SEC_GAMEMASTER, true, &HandleGMTicketResponseAppendCommand, "" },
{ "appendln", SEC_GAMEMASTER, true, &HandleGMTicketResponseAppendLnCommand, "" }
{ "append", HandleGMTicketResponseAppendCommand, SEC_GAMEMASTER, Console::Yes },
{ "appendln", HandleGMTicketResponseAppendLnCommand, SEC_GAMEMASTER, Console::Yes }
};
static ChatCommandTable ticketCommandTable =
{
{ "assign", SEC_GAMEMASTER, true, &HandleGMTicketAssignToCommand, "" },
{ "close", SEC_GAMEMASTER, true, &HandleGMTicketCloseByIdCommand, "" },
{ "closedlist", SEC_GAMEMASTER, true, &HandleGMTicketListClosedCommand, "" },
{ "comment", SEC_GAMEMASTER, true, &HandleGMTicketCommentCommand, "" },
{ "complete", SEC_GAMEMASTER, true, &HandleGMTicketCompleteCommand, "" },
{ "delete", SEC_ADMINISTRATOR, true, &HandleGMTicketDeleteByIdCommand, "" },
{ "escalate", SEC_GAMEMASTER, true, &HandleGMTicketEscalateCommand, "" },
{ "escalatedlist", SEC_GAMEMASTER, true, &HandleGMTicketListEscalatedCommand, "" },
{ "list", SEC_GAMEMASTER, true, &HandleGMTicketListCommand, "" },
{ "onlinelist", SEC_GAMEMASTER, true, &HandleGMTicketListOnlineCommand, "" },
{ "reset", SEC_CONSOLE, true, &HandleGMTicketResetCommand, "" },
{ "response", SEC_GAMEMASTER, true, nullptr, "", ticketResponseCommandTable },
{ "togglesystem", SEC_ADMINISTRATOR, true, &HandleToggleGMTicketSystem, "" },
{ "unassign", SEC_GAMEMASTER, true, &HandleGMTicketUnAssignCommand, "" },
{ "viewid", SEC_GAMEMASTER, true, &HandleGMTicketGetByIdCommand, "" },
{ "viewname", SEC_GAMEMASTER, true, &HandleGMTicketGetByNameCommand, "" }
{ "assign", HandleGMTicketAssignToCommand, SEC_GAMEMASTER, Console::Yes },
{ "close", HandleGMTicketCloseByIdCommand, SEC_GAMEMASTER, Console::Yes },
{ "closedlist", HandleGMTicketListClosedCommand, SEC_GAMEMASTER, Console::Yes },
{ "comment", HandleGMTicketCommentCommand, SEC_GAMEMASTER, Console::Yes },
{ "complete", HandleGMTicketCompleteCommand, SEC_GAMEMASTER, Console::Yes },
{ "delete", HandleGMTicketDeleteByIdCommand, SEC_ADMINISTRATOR, Console::Yes },
{ "escalate", HandleGMTicketEscalateCommand, SEC_GAMEMASTER, Console::Yes },
{ "escalatedlist", HandleGMTicketListEscalatedCommand, SEC_GAMEMASTER, Console::Yes },
{ "list", HandleGMTicketListCommand, SEC_GAMEMASTER, Console::Yes },
{ "onlinelist", HandleGMTicketListOnlineCommand, SEC_GAMEMASTER, Console::Yes },
{ "reset", HandleGMTicketResetCommand, SEC_CONSOLE, Console::Yes },
{ "response", ticketResponseCommandTable },
{ "togglesystem", HandleToggleGMTicketSystem, SEC_ADMINISTRATOR, Console::Yes },
{ "unassign", HandleGMTicketUnAssignCommand, SEC_GAMEMASTER, Console::Yes },
{ "viewid", HandleGMTicketGetByIdCommand, SEC_GAMEMASTER, Console::Yes },
{ "viewname", HandleGMTicketGetByNameCommand, SEC_GAMEMASTER, Console::Yes }
};
static ChatCommandTable commandTable =
{
{ "ticket", SEC_GAMEMASTER, false, nullptr, "", ticketCommandTable }
{ "ticket", ticketCommandTable }
};
return commandTable;
}
static bool HandleGMTicketAssignToCommand(ChatHandler* handler, char const* args)
static bool HandleGMTicketAssignToCommand(ChatHandler* handler, uint32 ticketId, std::string target)
{
if (!*args)
return false;
char* ticketIdStr = strtok((char*)args, " ");
uint32 ticketId = atoi(ticketIdStr);
char* targetStr = strtok(nullptr, " ");
if (!targetStr)
return false;
std::string target(targetStr);
if (!normalizePlayerName(target))
return false;
@@ -138,12 +123,8 @@ public:
return true;
}
static bool HandleGMTicketCloseByIdCommand(ChatHandler* handler, char const* args)
static bool HandleGMTicketCloseByIdCommand(ChatHandler* handler, uint32 ticketId)
{
if (!*args)
return false;
uint32 ticketId = atoi(args);
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
if (!ticket || ticket->IsClosed() || ticket->IsCompleted())
{
@@ -177,14 +158,8 @@ public:
return true;
}
static bool HandleGMTicketCommentCommand(ChatHandler* handler, char const* args)
static bool HandleGMTicketCommentCommand(ChatHandler* handler, uint32 ticketId)
{
if (!*args)
return false;
char* ticketIdStr = strtok((char*)args, " ");
uint32 ticketId = atoi(ticketIdStr);
char* comment = strtok(nullptr, "\n");
if (!comment)
return false;
@@ -218,20 +193,14 @@ public:
return true;
}
static bool HandleGMTicketListClosedCommand(ChatHandler* handler, char const* /*args*/)
static bool HandleGMTicketListClosedCommand(ChatHandler* handler)
{
sTicketMgr->ShowClosedList(*handler);
return true;
}
static bool HandleGMTicketCompleteCommand(ChatHandler* handler, char const* args)
static bool HandleGMTicketCompleteCommand(ChatHandler* handler, uint32 ticketId)
{
if (!*args)
return false;
char* ticketIdStr = strtok((char*)args, " ");
uint32 ticketId = atoi(ticketIdStr);
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
if (!ticket || ticket->IsClosed() || ticket->IsCompleted())
{
@@ -272,12 +241,8 @@ public:
return true;
}
static bool HandleGMTicketDeleteByIdCommand(ChatHandler* handler, char const* args)
static bool HandleGMTicketDeleteByIdCommand(ChatHandler* handler, uint32 ticketId)
{
if (!*args)
return false;
uint32 ticketId = atoi(args);
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
if (!ticket)
{
@@ -308,12 +273,8 @@ public:
return true;
}
static bool HandleGMTicketEscalateCommand(ChatHandler* handler, char const* args)
static bool HandleGMTicketEscalateCommand(ChatHandler* handler, uint32 ticketId)
{
if (!*args)
return false;
uint32 ticketId = atoi(args);
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
if (!ticket || ticket->IsClosed() || ticket->IsCompleted() || ticket->GetEscalatedStatus() != TICKET_UNASSIGNED)
{
@@ -330,25 +291,25 @@ public:
return true;
}
static bool HandleGMTicketListEscalatedCommand(ChatHandler* handler, char const* /*args*/)
static bool HandleGMTicketListEscalatedCommand(ChatHandler* handler)
{
sTicketMgr->ShowEscalatedList(*handler);
return true;
}
static bool HandleGMTicketListCommand(ChatHandler* handler, char const* /*args*/)
static bool HandleGMTicketListCommand(ChatHandler* handler)
{
sTicketMgr->ShowList(*handler, false);
return true;
}
static bool HandleGMTicketListOnlineCommand(ChatHandler* handler, char const* /*args*/)
static bool HandleGMTicketListOnlineCommand(ChatHandler* handler)
{
sTicketMgr->ShowList(*handler, true);
return true;
}
static bool HandleGMTicketResetCommand(ChatHandler* handler, char const* /*args*/)
static bool HandleGMTicketResetCommand(ChatHandler* handler)
{
if (sTicketMgr->GetOpenTicketCount())
{
@@ -364,7 +325,7 @@ public:
return true;
}
static bool HandleToggleGMTicketSystem(ChatHandler* handler, char const* /*args*/)
static bool HandleToggleGMTicketSystem(ChatHandler* handler)
{
bool status = !sTicketMgr->GetStatus();
sTicketMgr->SetStatus(status);
@@ -372,12 +333,8 @@ public:
return true;
}
static bool HandleGMTicketUnAssignCommand(ChatHandler* handler, char const* args)
static bool HandleGMTicketUnAssignCommand(ChatHandler* handler, uint32 ticketId)
{
if (!*args)
return false;
uint32 ticketId = atoi(args);
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
if (!ticket || ticket->IsClosed())
{
@@ -425,12 +382,8 @@ public:
return true;
}
static bool HandleGMTicketGetByIdCommand(ChatHandler* handler, char const* args)
static bool HandleGMTicketGetByIdCommand(ChatHandler* handler, uint32 ticketId)
{
if (!*args)
return false;
uint32 ticketId = atoi(args);
GmTicket* ticket = sTicketMgr->GetTicket(ticketId);
if (!ticket || ticket->IsClosed() || ticket->IsCompleted())
{
@@ -442,16 +395,12 @@ public:
ticket->SetViewed();
ticket->SaveToDB(trans);
handler->SendSysMessage(ticket->FormatMessageString(*handler, true).c_str());
handler->SendSysMessage(ticket->FormatMessageString(*handler, true));
return true;
}
static bool HandleGMTicketGetByNameCommand(ChatHandler* handler, char const* args)
static bool HandleGMTicketGetByNameCommand(ChatHandler* handler, std::string name)
{
if (!*args)
return false;
std::string name(args);
if (!normalizePlayerName(name))
return false;
@@ -485,18 +434,12 @@ public:
ticket->SetViewed();
ticket->SaveToDB(trans);
handler->SendSysMessage(ticket->FormatMessageString(*handler, true).c_str());
handler->SendSysMessage(ticket->FormatMessageString(*handler, true));
return true;
}
static bool _HandleGMTicketResponseAppendCommand(char const* args, bool newLine, ChatHandler* handler)
static bool _HandleGMTicketResponseAppendCommand(uint32 ticketId, bool newLine, ChatHandler* handler)
{
if (!*args)
return false;
char* ticketIdStr = strtok((char*)args, " ");
uint32 ticketId = atoi(ticketIdStr);
char* response = strtok(nullptr, "\n");
if (!response)
return false;
@@ -526,14 +469,14 @@ public:
return true;
}
static bool HandleGMTicketResponseAppendCommand(ChatHandler* handler, char const* args)
static bool HandleGMTicketResponseAppendCommand(ChatHandler* handler, uint32 ticketId)
{
return _HandleGMTicketResponseAppendCommand(args, false, handler);
return _HandleGMTicketResponseAppendCommand(ticketId, false, handler);
}
static bool HandleGMTicketResponseAppendLnCommand(ChatHandler* handler, char const* args)
static bool HandleGMTicketResponseAppendLnCommand(ChatHandler* handler, uint32 ticketId)
{
return _HandleGMTicketResponseAppendCommand(args, true, handler);
return _HandleGMTicketResponseAppendCommand(ticketId, true, handler);
}
};

View File

@@ -44,12 +44,18 @@ enum Spells
struct boss_curator : public BossAI
{
boss_curator(Creature* creature) : BossAI(creature, DATA_CURATOR) { }
boss_curator(Creature* creature) : BossAI(creature, DATA_CURATOR)
{
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
void Reset() override
{
BossAI::Reset();
me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_ARCANE, true);
me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_ARCANE, true);
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_PERIODIC_MANA_LEECH, true);
me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_POWER_BURN, true);
me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_POWER_BURN, true);
@@ -132,18 +138,6 @@ struct boss_curator : public BossAI
}
summon->SetInCombatWithZone();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
DoMeleeAttackIfReady();
}
};
void AddSC_boss_curator()

View File

@@ -101,6 +101,7 @@ struct boss_netherspite : public BossAI
BossAI::Reset();
berserk = false;
HandleDoors(true);
DestroyPortals();
}
void SummonPortals()
@@ -219,6 +220,24 @@ struct boss_netherspite : public BossAI
});
}
void DestroyPortals()
{
for (int i = 0; i < 3; ++i)
{
if (Creature* portal = ObjectAccessor::GetCreature(*me, PortalGUID[i]))
{
portal->DisappearAndDie();
}
if (Creature* portal = ObjectAccessor::GetCreature(*me, BeamerGUID[i]))
{
portal->DisappearAndDie();
}
PortalGUID[i].Clear();
BeamTarget[i].Clear();
}
}
void SwitchToBanishPhase()
{
Talk(EMOTE_PHASE_BANISH);
@@ -228,10 +247,7 @@ struct boss_netherspite : public BossAI
DoCastSelf(SPELL_BANISH_VISUAL, true);
DoCastSelf(SPELL_BANISH_ROOT, true);
for (uint32 id : PortalID)
{
summons.DespawnEntry(id);
}
DestroyPortals();
scheduler.Schedule(30s, [this](TaskContext)
{

View File

@@ -87,9 +87,19 @@ struct boss_nightbane : public BossAI
{
BossAI::Reset();
_skeletonscheduler.CancelAll();
Phase = 1;
MovePhase = 0;
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
if (!_intro)
{
//when boss is reset and we're past the intro
//cannot despawn, but have to move to a location where he normally is
//me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0);
Position preSpawnPosis = me->GetHomePosition();
EnterEvadeMode();
me->NearTeleportTo(preSpawnPosis);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
_intro = true;
Phase = 1;
MovePhase = 0;
}
me->SetSpeed(MOVE_RUN, 2.0f);
me->SetDisableGravity(_intro);
@@ -109,19 +119,6 @@ struct boss_nightbane : public BossAI
_flying = false;
_movement = false;
if (!_intro)
{
//when boss is reset and we're past the intro
//cannot despawn, but have to move to a location where he normally is
//me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0);
Position preSpawnPosis = me->GetHomePosition();
me->NearTeleportTo(preSpawnPosis);
instance->SetData(DATA_NIGHTBANE, NOT_STARTED);
_intro = true;
Phase = 1;
MovePhase = 0;
}
ScheduleHealthCheckEvent({ 75, 50, 25 }, [&]{
TakeOff();
});
@@ -136,11 +133,10 @@ struct boss_nightbane : public BossAI
}
}
void JustEngagedWith(Unit* /*who*/) override
void JustEngagedWith(Unit* who) override
{
_JustEngagedWith();
if (instance)
instance->SetData(DATA_NIGHTBANE, IN_PROGRESS);
BossAI::JustEngagedWith(who);
_intro = false;
HandleTerraceDoors(false);
Talk(YELL_AGGRO);
@@ -238,7 +234,6 @@ struct boss_nightbane : public BossAI
{
if (id >= 8)
{
_intro = false;
//me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0);
//doesn't need home position because we have to "despawn" boss on reset
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);

View File

@@ -18,51 +18,58 @@
#include "GameObject.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuras.h"
#include "SpellInfo.h"
#include "SpellScript.h"
#include "karazhan.h"
#include "TaskScheduler.h"
enum Texts
{
SAY_AGGRO = 0,
SAY_FLAMEWREATH = 1,
SAY_BLIZZARD = 2,
SAY_EXPLOSION = 3,
SAY_DRINK = 4,
SAY_ELEMENTALS = 5,
SAY_KILL = 6,
SAY_TIMEOVER = 7,
SAY_DEATH = 8
SAY_AGGRO = 0,
SAY_FLAMEWREATH = 1,
SAY_BLIZZARD = 2,
SAY_EXPLOSION = 3,
SAY_DRINK = 4,
SAY_ELEMENTALS = 5,
SAY_KILL = 6,
SAY_TIMEOVER = 7,
SAY_DEATH = 8,
SAY_ATIESH = 9,
EMOTE_ARCANE_EXPLOSION = 10
};
enum Spells
{
//Spells
SPELL_FROSTBOLT = 29954,
SPELL_FIREBALL = 29953,
SPELL_ARCMISSLE = 29955,
SPELL_CHAINSOFICE = 29991,
SPELL_DRAGONSBREATH = 29964,
SPELL_MASSSLOW = 30035,
SPELL_FLAME_WREATH = 29946,
SPELL_AOE_CS = 29961,
SPELL_PLAYERPULL = 32265,
SPELL_AEXPLOSION = 29973,
SPELL_MASS_POLY = 29963,
SPELL_BLINK_CENTER = 29967,
SPELL_CONJURE = 29975,
SPELL_DRINK = 30024,
SPELL_POTION = 32453,
SPELL_AOE_PYROBLAST = 29978,
SPELL_FROSTBOLT = 29954,
SPELL_FIREBALL = 29953,
SPELL_ARCMISSLE = 29955,
SPELL_CHAINSOFICE = 29991,
SPELL_DRAGONSBREATH = 29964,
SPELL_MASSSLOW = 30035,
SPELL_FLAME_WREATH = 30004,
SPELL_FLAME_WREATH_RING = 29946,
SPELL_FLAME_WREATH_RAN_THRU = 29947, // You ran through the flames!
SPELL_FLAME_WREATH_EXPLOSION = 29949,
SPELL_AOE_CS = 29961,
SPELL_PLAYERPULL = 32265,
SPELL_AEXPLOSION = 29973,
SPELL_MASS_POLY = 29963,
SPELL_BLINK_CENTER = 29967,
SPELL_CONJURE = 29975,
SPELL_DRINK = 30024,
SPELL_POTION = 32453,
SPELL_AOE_PYROBLAST = 29978,
SPELL_SUMMON_WELEMENTAL_1 = 29962,
SPELL_SUMMON_WELEMENTAL_2 = 37051,
SPELL_SUMMON_WELEMENTAL_3 = 37052,
SPELL_SUMMON_WELEMENTAL_4 = 37053,
SPELL_SUMMON_WELEMENTAL_1 = 29962,
SPELL_SUMMON_WELEMENTAL_2 = 37051,
SPELL_SUMMON_WELEMENTAL_3 = 37052,
SPELL_SUMMON_WELEMENTAL_4 = 37053,
SPELL_SUMMON_BLIZZARD = 29969, // Activates the Blizzard NPC
SPELL_SUMMON_BLIZZARD = 29969, // Activates the Blizzard NPC
SPELL_SHADOW_PYRO = 29978
SPELL_SHADOW_PYRO = 29978
};
enum Creatures
@@ -79,20 +86,11 @@ enum SuperSpell
enum Groups
{
GROUP_FLAMEWREATH = 0,
GROUP_DRINKING = 1
GROUP_DRINKING = 0
};
Position const roomCenter = {-11158.f, -1920.f};
Position const elementalPos[4] =
{
{-11168.1f, -1939.29f, 232.092f, 1.46f},
{-11138.2f, -1915.38f, 232.092f, 3.00f},
{-11161.7f, -1885.36f, 232.092f, 4.59f},
{-11192.4f, -1909.36f, 232.092f, 6.19f}
};
struct boss_shade_of_aran : public BossAI
{
boss_shade_of_aran(Creature* creature) : BossAI(creature, DATA_ARAN)
@@ -103,22 +101,11 @@ struct boss_shade_of_aran : public BossAI
});
}
uint8 LastSuperSpell;
ObjectGuid FlameWreathTarget[3];
float FWTargPosX[3];
float FWTargPosY[3];
uint32 CurrentNormalSpell;
void Reset() override
{
BossAI::Reset();
_drinkScheduler.CancelAll();
LastSuperSpell = rand() % 3;
for (uint8 i = 0; i < 3; ++i)
FlameWreathTarget[i].Clear();
_lastSuperSpell = rand() % 3;
CurrentNormalSpell = 0;
@@ -127,9 +114,7 @@ struct boss_shade_of_aran : public BossAI
_frostCooledDown = true;
_drinking = false;
// Not in progress
instance->SetData(DATA_ARAN, NOT_STARTED);
_hasDrunk = false;
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
{
@@ -198,8 +183,7 @@ struct boss_shade_of_aran : public BossAI
void JustDied(Unit* /*killer*/) override
{
Talk(SAY_DEATH);
instance->SetData(DATA_ARAN, DONE);
_JustDied();
if (GameObject* libraryDoor = instance->instance->GetGameObject(instance->GetGuidData(DATA_GO_LIBRARY_DOOR)))
{
@@ -208,14 +192,30 @@ struct boss_shade_of_aran : public BossAI
}
}
void DamageTaken(Unit* doneBy, uint32& damage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask) override
{
BossAI::DamageTaken(doneBy, damage, damagetype, damageSchoolMask);
if ((damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE) && _drinking && me->GetReactState() == REACT_PASSIVE)
{
me->RemoveAurasDueToSpell(SPELL_DRINK);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
_drinkScheduler.CancelGroup(GROUP_DRINKING);
_drinkScheduler.Schedule(1s, [this](TaskContext)
{
DoCastSelf(SPELL_AOE_PYROBLAST, false);
_drinking = false;
});
}
}
void JustEngagedWith(Unit* /*who*/) override
{
_JustEngagedWith();
Talk(SAY_AGGRO);
instance->SetData(DATA_ARAN, IN_PROGRESS);
DoZoneInCombat();
//handle timed closing door
scheduler.Schedule(15s, [this](TaskContext)
{
@@ -226,11 +226,14 @@ struct boss_shade_of_aran : public BossAI
}
}).Schedule(1s, [this](TaskContext context)
{
if (!me->IsNonMeleeSpellCast(false) && !_drinking)
context.Repeat(2s);
if (!_drinking)
{
Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true);
if (!target)
if (me->IsNonMeleeSpellCast(false))
{
return;
}
uint32 Spells[3];
uint8 AvailableSpells = 0;
@@ -252,49 +255,87 @@ struct boss_shade_of_aran : public BossAI
++AvailableSpells;
}
// Should drink at 10%, need 10% mana for mass polymorph
if (!_hasDrunk && me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA)) < 13)
{
_drinking = true;
_hasDrunk = true;
me->InterruptNonMeleeSpells(true);
Talk(SAY_DRINK);
DoCastAOE(SPELL_MASS_POLY);
me->SetReactState(REACT_PASSIVE);
// Start drinking after conjuring drinks
_drinkScheduler.Schedule(2s, GROUP_DRINKING, [this](TaskContext)
{
DoCastSelf(SPELL_CONJURE);
}).Schedule(4s, GROUP_DRINKING, [this](TaskContext)
{
me->SetStandState(UNIT_STAND_STATE_SIT);
DoCastSelf(SPELL_DRINK);
});
_drinkScheduler.Schedule(10s, GROUP_DRINKING, [this](TaskContext)
{
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
DoCastSelf(SPELL_AOE_PYROBLAST);
_drinkScheduler.CancelGroup(GROUP_DRINKING);
_drinking = false;
});
return;
}
//If no available spells wait 1 second and try again
if (AvailableSpells)
{
CurrentNormalSpell = Spells[rand() % AvailableSpells];
if (!me->CanCastSpell(CurrentNormalSpell))
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(CurrentNormalSpell))
{
me->SetWalk(false);
me->ResumeChasingVictim();
}
else
{
DoCast(target, CurrentNormalSpell);
if (me->GetVictim())
if (int32(me->GetPower(POWER_MANA)) < spellInfo->CalcPowerCost(me, (SpellSchoolMask)spellInfo->SchoolMask))
{
me->GetMotionMaster()->MoveChase(me->GetVictim(), 45.0f);
DoCastSelf(SPELL_POTION);
}
else
{
if (!me->CanCastSpell(CurrentNormalSpell))
{
me->SetWalk(false);
me->ResumeChasingVictim();
}
else
{
DoCastRandomTarget(CurrentNormalSpell, 0, 100.0f);
if (me->GetVictim())
{
me->GetMotionMaster()->MoveChase(me->GetVictim(), 45.0f);
}
}
}
}
}
}
context.Repeat(2s);
}).Schedule(5s, [this](TaskContext context)
{
if (!_drinking)
{
switch (urand(0, 1))
{
case 0:
DoCastSelf(SPELL_AOE_CS);
break;
case 1:
DoCastRandomTarget(SPELL_CHAINSOFICE);
break;
}
urand(0, 1) ? DoCastSelf(SPELL_AOE_CS) : DoCastRandomTarget(SPELL_CHAINSOFICE);
}
context.Repeat(5s, 20s);
}).Schedule(35s, [this](TaskContext context)
}).Schedule(6s, [this](TaskContext context)
{
if (!_drinking)
{
me->ClearProhibitedSpellTimers();
DoCastSelf(SPELL_BLINK_CENTER, true);
uint8 Available[2];
switch (LastSuperSpell)
switch (_lastSuperSpell)
{
case SUPER_AE:
Available[0] = SUPER_FLAME;
@@ -310,49 +351,21 @@ struct boss_shade_of_aran : public BossAI
break;
}
LastSuperSpell = Available[urand(0, 1)];
_lastSuperSpell = Available[urand(0, 1)];
switch (LastSuperSpell)
switch (_lastSuperSpell)
{
case SUPER_AE:
Talk(SAY_EXPLOSION);
DoCastSelf(SPELL_BLINK_CENTER, true);
Talk(EMOTE_ARCANE_EXPLOSION);
DoCastSelf(SPELL_PLAYERPULL, true);
DoCastSelf(SPELL_MASSSLOW, true);
DoCastSelf(SPELL_AEXPLOSION, false);
break;
case SUPER_FLAME:
Talk(SAY_FLAMEWREATH);
scheduler.Schedule(20s, GROUP_FLAMEWREATH, [this](TaskContext)
{
scheduler.CancelGroup(GROUP_FLAMEWREATH);
}).Schedule(500ms, GROUP_FLAMEWREATH, [this](TaskContext context)
{
for (uint8 i = 0; i < 3; ++i)
{
if (!FlameWreathTarget[i])
continue;
Unit* unit = ObjectAccessor::GetUnit(*me, FlameWreathTarget[i]);
if (unit && !unit->IsWithinDist2d(FWTargPosX[i], FWTargPosY[i], 3))
{
unit->CastSpell(unit, 20476, true, 0, 0, me->GetGUID());
FlameWreathTarget[i].Clear();
}
}
context.Repeat(500ms);
});
FlameWreathTarget[0].Clear();
FlameWreathTarget[1].Clear();
FlameWreathTarget[2].Clear();
FlameWreathEffect();
DoCastAOE(SPELL_FLAME_WREATH);
break;
case SUPER_BLIZZARD:
Talk(SAY_BLIZZARD);
DoCastAOE(SPELL_SUMMON_BLIZZARD);
@@ -360,51 +373,6 @@ struct boss_shade_of_aran : public BossAI
}
}
context.Repeat(35s, 40s);
}).Schedule(1s, [this](TaskContext context){
if (me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA) * 100 / me->GetMaxPower(POWER_MANA)) < 20)
{
_drinking = true;
me->InterruptNonMeleeSpells(true);
Talk(SAY_DRINK);
DoCastSelf(SPELL_MASS_POLY, true);
DoCastSelf(SPELL_CONJURE, false);
me->SetReactState(REACT_PASSIVE);
me->SetStandState(UNIT_STAND_STATE_SIT);
DoCastSelf(SPELL_DRINK, true);
_currentHealth = me->GetHealth();
_drinkScheduler.Schedule(500ms, GROUP_DRINKING, [this](TaskContext context)
{
//check for damage to interrupt
if (me->GetHealth() < _currentHealth)
{
me->RemoveAurasDueToSpell(SPELL_DRINK);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
DoCastSelf(SPELL_POTION, false);
DoCastSelf(SPELL_AOE_PYROBLAST, false);
_drinkScheduler.CancelGroup(GROUP_DRINKING);
_drinking = false;
} else
{
context.Repeat(500ms);
}
}).Schedule(10s, GROUP_DRINKING, [this](TaskContext)
{
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA) - 32000);
DoCastSelf(SPELL_POTION, true);
DoCastSelf(SPELL_AOE_PYROBLAST, false);
_drinkScheduler.CancelGroup(GROUP_DRINKING);
_drinking = false;
});
context.Repeat(12s); //semi-arbitrary duration to envelop drinking duration
}
else
{
context.Repeat(1s);
}
}).Schedule(12min, [this](TaskContext context)
{
for (uint32 i = 0; i < 5; ++i)
@@ -422,41 +390,6 @@ struct boss_shade_of_aran : public BossAI
});
}
void FlameWreathEffect()
{
std::vector<Unit*> targets;
ThreatContainer::StorageType const& t_list = me->GetThreatMgr().GetThreatList();
if (t_list.empty())
return;
//store the threat list in a different container
for (ThreatContainer::StorageType::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr)
{
Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid());
//only on alive players
if (target && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER)
targets.push_back(target);
}
//cut down to size if we have more than 3 targets
while (targets.size() > 3)
targets.erase(targets.begin() + rand() % targets.size());
uint32 i = 0;
for (std::vector<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
{
if (*itr)
{
FlameWreathTarget[i] = (*itr)->GetGUID();
FWTargPosX[i] = (*itr)->GetPositionX();
FWTargPosY[i] = (*itr)->GetPositionY();
DoCast((*itr), SPELL_FLAME_WREATH, true);
++i;
}
}
}
void UpdateAI(uint32 diff) override
{
scheduler.Update(diff);
@@ -483,9 +416,6 @@ struct boss_shade_of_aran : public BossAI
Spell->Effects[2].Effect != SPELL_EFFECT_INTERRUPT_CAST) || !me->IsNonMeleeSpellCast(false))
return;
//Interrupt effect
me->InterruptNonMeleeSpells(false);
//Normally we would set the cooldown equal to the spell duration
//but we do not have access to the DurationStore
@@ -505,14 +435,95 @@ struct boss_shade_of_aran : public BossAI
private:
TaskScheduler _drinkScheduler;
uint32 _lastSuperSpell;
uint32 CurrentNormalSpell;
bool _arcaneCooledDown;
bool _fireCooledDown;
bool _frostCooledDown;
bool _drinking;
uint32 _currentHealth;
bool _hasDrunk;
};
// 30004 - Flame Wreath
class spell_flamewreath : public SpellScript
{
PrepareSpellScript(spell_flamewreath);
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_FLAME_WREATH_RING });
}
void FilterTargets(std::list<WorldObject*>& targets)
{
uint8 maxSize = 3;
if (targets.size() > maxSize)
{
Acore::Containers::RandomResize(targets, maxSize);
}
_targets = targets;
}
void HandleFinish()
{
for (auto const& target : _targets)
{
if (Unit* targetUnit = target->ToUnit())
{
GetCaster()->CastSpell(targetUnit, SPELL_FLAME_WREATH_RING, true);
}
}
}
private:
std::list<WorldObject*> _targets;
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_flamewreath::FilterTargets, EFFECT_ALL, TARGET_UNIT_SRC_AREA_ENEMY);
AfterCast += SpellCastFn(spell_flamewreath::HandleFinish);
}
};
// 29946 - Flame Wreath (visual effect)
class spell_flamewreath_aura : public AuraScript
{
PrepareAuraScript(spell_flamewreath_aura);
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_FLAME_WREATH_RAN_THRU, SPELL_FLAME_WREATH_EXPLOSION });
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_DEFAULT && GetDuration())
{
if (Unit* target = GetTarget())
{
target->CastSpell(target, SPELL_FLAME_WREATH_RAN_THRU, true);
target->m_Events.AddEventAtOffset([target] {
target->RemoveAurasDueToSpell(SPELL_FLAME_WREATH_RAN_THRU);
target->CastSpell(target, SPELL_FLAME_WREATH_EXPLOSION, true);
}, 1s);
}
}
}
void Register() override
{
OnEffectRemove += AuraEffectRemoveFn(spell_flamewreath_aura::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_boss_shade_of_aran()
{
RegisterKarazhanCreatureAI(boss_shade_of_aran);
RegisterSpellScript(spell_flamewreath);
RegisterSpellScript(spell_flamewreath_aura);
}

View File

@@ -231,20 +231,12 @@ struct boss_dorothee : public ScriptedAI
me->DespawnOrUnsummon();
}
void AttackStart(Unit* who) override
void SummonedCreatureDies(Creature* creature, Unit* /*killer*/) override
{
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
return;
ScriptedAI::AttackStart(who);
}
void MoveInLineOfSight(Unit* who) override
{
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
return;
ScriptedAI::MoveInLineOfSight(who);
if (creature->GetEntry() == NPC_TITO)
{
Talk(SAY_DOROTHEE_TITO_DEATH);
}
}
void EnterEvadeMode(EvadeReason reason) override
@@ -288,8 +280,6 @@ struct npc_tito : public ScriptedAI
InstanceScript* instance;
void Reset() override { }
void JustEngagedWith(Unit* /*who*/) override
{
_scheduler.Schedule(10s, [this](TaskContext context)
@@ -299,18 +289,6 @@ struct npc_tito : public ScriptedAI
});
}
void JustDied(Unit* /*killer*/) override
{
if (Creature* Dorothee = instance->GetCreature(DATA_DOROTHEE))
{
if (Dorothee->IsAlive())
{
Talk(SAY_DOROTHEE_TITO_DEATH, Dorothee);
}
}
me->DespawnOrUnsummon();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
@@ -351,17 +329,6 @@ struct boss_roar : public ScriptedAI
}
}
void Reset() override { }
void MoveInLineOfSight(Unit* who) override
{
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
return;
ScriptedAI::MoveInLineOfSight(who);
}
void EnterEvadeMode(EvadeReason reason) override
{
ScriptedAI::EnterEvadeMode(reason);
@@ -373,14 +340,6 @@ struct boss_roar : public ScriptedAI
}
}
void AttackStart(Unit* who) override
{
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
return;
ScriptedAI::AttackStart(who);
}
void JustEngagedWith(Unit* /*who*/) override
{
Talk(SAY_ROAR_AGGRO);
@@ -458,24 +417,6 @@ struct boss_strawman : public ScriptedAI
}
}
void Reset() override { }
void AttackStart(Unit* who) override
{
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
return;
ScriptedAI::AttackStart(who);
}
void MoveInLineOfSight(Unit* who) override
{
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
return;
ScriptedAI::MoveInLineOfSight(who);
}
void EnterEvadeMode(EvadeReason reason) override
{
ScriptedAI::EnterEvadeMode(reason);
@@ -601,22 +542,6 @@ struct boss_tinhead : public ScriptedAI
me->DespawnOrUnsummon();
}
void AttackStart(Unit* who) override
{
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
return;
ScriptedAI::AttackStart(who);
}
void MoveInLineOfSight(Unit* who) override
{
if (me->HasUnitFlag(UNIT_FLAG_NON_ATTACKABLE))
return;
ScriptedAI::MoveInLineOfSight(who);
}
void EnterEvadeMode(EvadeReason reason) override
{
ScriptedAI::EnterEvadeMode(reason);
@@ -763,6 +688,7 @@ enum RedRidingHood
SPELL_LITTLE_RED_RIDING_HOOD = 30768,
SPELL_TERRIFYING_HOWL = 30752,
SPELL_WIDE_SWIPE = 30761,
SPELL_PICNIC_BASKET_SMELL = 30755,
CREATURE_BIG_BAD_WOLF = 17521,
@@ -826,16 +752,6 @@ struct boss_bigbadwolf : public ScriptedAI
InstanceScript* instance;
ObjectGuid HoodGUID;
void Reset() override
{
HoodGUID.Clear();
_tempThreat = 0;
_isChasing = false;
}
void JustEngagedWith(Unit* /*who*/) override
{
instance->DoUseDoorOrButton(instance->GetGuidData(DATA_GO_STAGEDOORLEFT));
@@ -844,40 +760,14 @@ struct boss_bigbadwolf : public ScriptedAI
_scheduler.Schedule(30s, [this](TaskContext context)
{
if (!_isChasing)
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
{
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
{
Talk(SAY_WOLF_HOOD);
DoCast(target, SPELL_LITTLE_RED_RIDING_HOOD, true);
_tempThreat = DoGetThreat(target);
if (_tempThreat)
{
DoModifyThreatByPercent(target, -100);
}
HoodGUID = target->GetGUID();
me->AddThreat(target, 1000000.0f);
_isChasing = true;
context.Repeat(20s);
}
Talk(SAY_WOLF_HOOD);
DoCast(target, SPELL_LITTLE_RED_RIDING_HOOD, true);
target->CastSpell(me, SPELL_PICNIC_BASKET_SMELL, true);
}
else
{
_isChasing = false;
if (Unit* target = ObjectAccessor::GetUnit(*me, HoodGUID))
{
HoodGUID.Clear();
if (DoGetThreat(target))
{
DoModifyThreatByPercent(target, -100);
}
me->AddThreat(target, _tempThreat);
_tempThreat = 0;
}
context.Repeat(40s);
}
context.Repeat(40s);
}).Schedule(25s, 35s, [this](TaskContext context)
{
DoCastAOE(SPELL_TERRIFYING_HOWL);
@@ -920,15 +810,10 @@ struct boss_bigbadwolf : public ScriptedAI
DoMeleeAttackIfReady();
if (_isChasing)
return;
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
bool _isChasing;
float _tempThreat;
};
/**********************************************/

View File

@@ -48,6 +48,12 @@ ObjectData const creatureData[] =
{ 0, 0 }
};
ObjectData const gameObjectData[] =
{
{ GO_SIDE_ENTRANCE_DOOR, DATA_GO_SIDE_ENTRANCE_DOOR },
{ 0, 0 }
};
class instance_karazhan : public InstanceMapScript
{
public:
@@ -64,7 +70,7 @@ public:
{
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
LoadObjectData(creatureData, nullptr);
LoadObjectData(creatureData, gameObjectData);
// 1 - OZ, 2 - HOOD, 3 - RAJ, this never gets altered.
OperaEvent = urand(EVENT_OZ, EVENT_RAJ);
@@ -300,13 +306,11 @@ public:
{
HandleGameObject(m_uiStageDoorLeftGUID, true);
HandleGameObject(m_uiStageDoorRightGUID, true);
if (GameObject* sideEntrance = instance->GetGameObject(m_uiSideEntranceDoor))
sideEntrance->RemoveGameObjectFlag(GO_FLAG_LOCKED);
instance->UpdateEncounterState(ENCOUNTER_CREDIT_KILL_CREATURE, 16812, nullptr);
}
else if (state == FAIL)
{
HandleGameObject(m_uiStageDoorLeftGUID, false);
HandleGameObject(m_uiStageDoorLeftGUID, true);
HandleGameObject(m_uiStageDoorRightGUID, false);
HandleGameObject(m_uiCurtainGUID, false);
DoRespawnCreature(_barnesGUID, true);
@@ -372,11 +376,10 @@ public:
MastersTerraceDoor[1] = go->GetGUID();
break;
case GO_SIDE_ENTRANCE_DOOR:
m_uiSideEntranceDoor = go->GetGUID();
if (GetBossState(DATA_OPERA_PERFORMANCE) == DONE)
go->SetGameObjectFlag(GO_FLAG_LOCKED);
else
go->RemoveGameObjectFlag(GO_FLAG_LOCKED);
else
go->SetGameObjectFlag(GO_FLAG_LOCKED);
break;
case GO_DUST_COVERED_CHEST:
DustCoveredChest = go->GetGUID();
@@ -477,8 +480,6 @@ public:
return m_uiLibraryDoor;
case DATA_GO_MASSIVE_DOOR:
return m_uiMassiveDoor;
case DATA_GO_SIDE_ENTRANCE_DOOR:
return m_uiSideEntranceDoor;
case DATA_GO_GAME_DOOR:
return m_uiGamesmansDoor;
case DATA_GO_GAME_EXIT_DOOR:
@@ -519,7 +520,6 @@ public:
ObjectGuid m_uiNightBaneGUID;
ObjectGuid m_uiLibraryDoor; // Door at Shade of Aran
ObjectGuid m_uiMassiveDoor; // Door at Netherspite
ObjectGuid m_uiSideEntranceDoor; // Side Entrance
ObjectGuid m_uiGamesmansDoor; // Door before Chess
ObjectGuid m_uiGamesmansExitDoor; // Door after Chess
ObjectGuid m_uiNetherspaceDoor; // Door at Malchezaar

View File

@@ -135,7 +135,6 @@ public:
{
npc_barnesAI(Creature* creature) : npc_escortAI(creature)
{
RaidWiped = false;
m_uiEventId = 0;
instance = creature->GetInstanceScript();
}
@@ -146,11 +145,9 @@ public:
uint32 TalkCount;
uint32 TalkTimer;
uint32 WipeTimer;
uint32 m_uiEventId;
bool PerformanceReady;
bool RaidWiped;
void Reset() override
{
@@ -158,7 +155,6 @@ public:
TalkCount = 0;
TalkTimer = 2000;
WipeTimer = 5000;
PerformanceReady = false;
@@ -183,8 +179,8 @@ public:
switch (waypointId)
{
case 0:
DoCast(me, SPELL_TUXEDO, false);
instance->DoUseDoorOrButton(instance->GetGuidData(DATA_GO_STAGEDOORLEFT));
DoCastSelf(SPELL_TUXEDO);
instance->HandleGameObject(instance->GetGuidData(DATA_GO_STAGEDOORLEFT), true);
break;
case 4:
TalkCount = 0;
@@ -276,8 +272,6 @@ public:
creature->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
}
RaidWiped = false;
instance->SetData(DATA_SPAWN_OPERA_DECORATIONS, m_uiEventId);
}
@@ -303,43 +297,6 @@ public:
}
else TalkTimer -= diff;
}
if (PerformanceReady)
{
if (!RaidWiped)
{
if (WipeTimer <= diff)
{
Map* map = me->GetMap();
if (!map->IsDungeon())
return;
Map::PlayerList const& PlayerList = map->GetPlayers();
if (PlayerList.IsEmpty())
return;
RaidWiped = true;
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
{
if (i->GetSource()->IsAlive() && !i->GetSource()->IsGameMaster())
{
RaidWiped = false;
break;
}
}
if (RaidWiped)
{
RaidWiped = true;
EnterEvadeMode();
return;
}
WipeTimer = 15000;
}
else WipeTimer -= diff;
}
}
}
};
@@ -391,15 +348,16 @@ public:
AddGossipItemFor(player, GOSSIP_ICON_DOT, OZ_GM_GOSSIP3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 5);
}
if (npc_barnesAI* pBarnesAI = CAST_AI(npc_barnes::npc_barnesAI, creature->AI()))
if (instance->GetBossState(DATA_OPERA_PERFORMANCE) != FAIL)
{
if (!pBarnesAI->RaidWiped)
SendGossipMenuFor(player, BARNES_TEXT_IS_READY, creature->GetGUID());
else
SendGossipMenuFor(player, BARNES_TEXT_WIPED, creature->GetGUID());
return true;
SendGossipMenuFor(player, BARNES_TEXT_IS_READY, creature->GetGUID());
}
else
{
SendGossipMenuFor(player, BARNES_TEXT_WIPED, creature->GetGUID());
}
return true;
}
}
@@ -604,8 +562,32 @@ public:
};
};
class at_karazhan_side_entrance : public OnlyOnceAreaTriggerScript
{
public:
at_karazhan_side_entrance() : OnlyOnceAreaTriggerScript("at_karazhan_side_entrance") { }
bool _OnTrigger(Player* player, AreaTrigger const* /*at*/) override
{
if (InstanceScript* instance = player->GetInstanceScript())
{
if (instance->GetBossState(DATA_OPERA_PERFORMANCE) == DONE)
{
if (GameObject* door = instance->GetGameObject(DATA_GO_SIDE_ENTRANCE_DOOR))
{
instance->HandleGameObject(ObjectGuid::Empty, true, door);
door->RemoveGameObjectFlag(GO_FLAG_LOCKED);
}
}
}
return false;
}
};
void AddSC_karazhan()
{
new npc_barnes();
new npc_image_of_medivh();
new at_karazhan_side_entrance();
}

View File

@@ -203,52 +203,6 @@ enum ScarletMonasteryTrashMisc
SPELL_FORGIVENESS = 28697,
};
class npc_scarlet_guard : public CreatureScript
{
public:
npc_scarlet_guard() : CreatureScript("npc_scarlet_guard") { }
struct npc_scarlet_guardAI : public SmartAI
{
npc_scarlet_guardAI(Creature* creature) : SmartAI(creature) { }
void Reset() override
{
SayAshbringer = false;
}
void MoveInLineOfSight(Unit* who) override
{
if (who && who->GetDistance2d(me) < 12.0f)
{
if (Player* player = who->ToPlayer())
{
if (player->HasAura(AURA_ASHBRINGER) && !SayAshbringer)
{
Talk(SAY_WELCOME);
me->SetFaction(FACTION_FRIENDLY);
me->SetSheath(SHEATH_STATE_UNARMED);
me->SetFacingToObject(player);
me->SetStandState(UNIT_STAND_STATE_KNEEL);
me->AddAura(SPELL_AURA_MOD_ROOT, me);
me->CastSpell(me, SPELL_AURA_MOD_ROOT, true);
SayAshbringer = true;
}
}
}
SmartAI::MoveInLineOfSight(who);
}
private:
bool SayAshbringer = false;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetScarletMonasteryAI<npc_scarlet_guardAI>(creature);
}
};
enum MograineEvents
{
EVENT_SPELL_CRUSADER_STRIKE = 1,
@@ -733,7 +687,6 @@ public:
void AddSC_instance_scarlet_monastery()
{
new instance_scarlet_monastery();
new npc_scarlet_guard();
new npc_fairbanks();
new npc_mograine();
new boss_high_inquisitor_whitemane();

View File

@@ -289,9 +289,6 @@ public:
ResetTimer = 5000;
SpawnAdds();
me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, 46916);
me->SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE);
}
void JustEngagedWith(Unit* /*who*/) override

View File

@@ -1367,13 +1367,15 @@ enum BrewfestRevelerEnum
FACTION_ALLIANCE = 1934,
FACTION_HORDE = 1935,
SPELL_BREWFEST_REVELER_TRANSFORM_GOBLIN_MALE = 44003,
SPELL_BREWFEST_REVELER_TRANSFORM_GOBLIN_FEMALE = 44004,
SPELL_BREWFEST_REVELER_TRANSFORM_BE = 43907,
SPELL_BREWFEST_REVELER_TRANSFORM_ORC = 43914,
SPELL_BREWFEST_REVELER_TRANSFORM_TAUREN = 43915,
SPELL_BREWFEST_REVELER_TRANSFORM_TROLL = 43916,
SPELL_BREWFEST_REVELER_TRANSFORM_UNDEAD = 43917
SPELL_BREWFEST_REVELER_TRANSFORM_GOBLIN_MALE = 44003,
SPELL_BREWFEST_REVELER_TRANSFORM_GOBLIN_FEMALE = 44004,
SPELL_BREWFEST_REVELER_TRANSFORM_BE = 43907,
SPELL_BREWFEST_REVELER_TRANSFORM_ORC = 43914,
SPELL_BREWFEST_REVELER_TRANSFORM_TAUREN = 43915,
SPELL_BREWFEST_REVELER_TRANSFORM_TROLL = 43916,
SPELL_BREWFEST_REVELER_TRANSFORM_UNDEAD = 43917,
SPELL_DRUNKEN_BREWFEST_REVELER_TRANSFORM_GOBLIN_MALE = 44096
};
class spell_brewfest_reveler_transform : public AuraScript
@@ -1394,6 +1396,7 @@ class spell_brewfest_reveler_transform : public AuraScript
break;
case SPELL_BREWFEST_REVELER_TRANSFORM_GOBLIN_MALE:
case SPELL_BREWFEST_REVELER_TRANSFORM_GOBLIN_FEMALE:
case SPELL_DRUNKEN_BREWFEST_REVELER_TRANSFORM_GOBLIN_MALE:
factionId = FACTION_FRIENDLY;
break;
default:

View File

@@ -23,6 +23,7 @@
#include "Spell.h"
#include "SpellAuras.h"
#include "SpellScript.h"
#include <random>
enum eBonfire
{
@@ -46,6 +47,19 @@ public:
}
};
enum torchToss
{
GO_TORCH_TARGET_BRAZIER = 187708,
NPC_TORCH_TOSS_TARGET_BUNNY = 25535,
SPELL_TARGET_INDICATOR_RANK_1 = 43313,
SPELL_TORCH_TOSS_LAND = 46054,
SPELL_BRAZIERS_HIT_VISUAL = 45724,
SPELL_TORCH_TOSS_SUCCESS_A = 45719,
SPELL_TORCH_TOSS_SUCCESS_H = 46651,
SPELL_TORCH_TOSS_TRAINING = 45716,
};
struct npc_midsummer_torch_target : public ScriptedAI
{
npc_midsummer_torch_target(Creature* creature) : ScriptedAI(creature)
@@ -54,7 +68,7 @@ struct npc_midsummer_torch_target : public ScriptedAI
startTimer = 1;
posVec.clear();
playerGUID.Clear();
me->CastSpell(me, 43313, true);
me->CastSpell(me, SPELL_TARGET_INDICATOR_RANK_1, true);
counter = 0;
maxCount = 0;
}
@@ -82,12 +96,12 @@ struct npc_midsummer_torch_target : public ScriptedAI
if (posVec.empty())
return;
// Triggered spell from torch
if (spellInfo->Id == 46054 && caster->GetTypeId() == TYPEID_PLAYER)
if (spellInfo->Id == SPELL_TORCH_TOSS_LAND && caster->GetTypeId() == TYPEID_PLAYER)
{
me->CastSpell(me, 45724, true); // hit visual anim
me->CastSpell(me, SPELL_BRAZIERS_HIT_VISUAL, true); // hit visual anim
if (++counter >= maxCount)
{
caster->CastSpell(caster, (caster->ToPlayer()->GetTeamId() ? 46651 : 45719), true); // quest complete spell
caster->CastSpell(caster, (caster->ToPlayer()->GetTeamId() ? SPELL_TORCH_TOSS_SUCCESS_H : SPELL_TORCH_TOSS_SUCCESS_A), true); // quest complete spell
me->DespawnOrUnsummon(1);
return;
}
@@ -129,7 +143,7 @@ struct npc_midsummer_torch_target : public ScriptedAI
void FillPositions()
{
std::list<GameObject*> gobjList;
me->GetGameObjectListWithEntryInGrid(gobjList, 187708 /*TORCH_GO*/, 30.0f);
me->GetGameObjectListWithEntryInGrid(gobjList, GO_TORCH_TARGET_BRAZIER, 30.0f);
for (std::list<GameObject*>::const_iterator itr = gobjList.begin(); itr != gobjList.end(); ++itr)
{
Position pos;
@@ -145,8 +159,6 @@ struct npc_midsummer_torch_target : public ScriptedAI
int8 num = urand(0, posVec.size() - 1);
Position pos;
pos.Relocate(posVec.at(num));
me->m_last_notify_position.Relocate(0.0f, 0.0f, 0.0f);
me->m_last_notify_mstime = GameTime::GetGameTimeMS().count() + 10000;
me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation());
}
@@ -169,7 +181,7 @@ class spell_gen_crab_disguise : public AuraScript
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_CRAB_DISGUISE });
return ValidateSpellInfo({ SPELL_APPLY_DIGUISE, SPELL_FADE_DIGUISE });
}
void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
@@ -199,17 +211,293 @@ class spell_gen_crab_disguise : public AuraScript
enum RibbonPole
{
GO_RIBBON_POLE = 181605,
SPELL_RIBBON_POLE_CHANNEL_VISUAL = 29172,
SPELL_RIBBON_POLE_CHANNEL_VISUAL_2 = 29531,
SPELL_TEST_RIBBON_POLE_CHANNEL_BLUE = 29705,
SPELL_TEST_RIBBON_POLE_CHANNEL_RED = 29726,
SPELL_TEST_RIBBON_POLE_CHANNEL_PINK = 29727,
// player spinning/rorating around himself
SPELL_RIBBON_POLE_PERIODIC_VISUAL = 45406,
// spew lava trails
SPELL_RIBBON_POLE_FIRE_SPIRAL_VISUAL= 45421,
// blue fire ring, duration 5s
SPELL_FLAME_RING = 46842,
// red fire ring, duration 5s
SPELL_FLAME_PATCH = 46836,
// single firework explosion
SPELL_RIBBON_POLE_FIREWORK = 46847,
SPELL_RIBBON_POLE_GROUND_FLOWER = 46969,
SPELL_RIBBON_POLE_XP = 29175,
SPELL_RIBBON_POLE_FIREWORKS = 46971,
NPC_RIBBON_POLE_DEBUG_TARGET = 17066,
NPC_GROUND_FLOWER = 25518,
NPC_BIG_DANCING_FLAMES = 26267,
NPC_RIBBON_POLE_FIRE_SPIRAL_BUNNY = 25303,
// dancing players count
THRESHOLD_FLAME_CIRCLE = 1,
THRESHOLD_FIREWORK = 2,
THRESHOLD_FIREWORK_3 = 3,
THRESHOLD_FIREWORK_5 = 5,
THRESHOLD_GROUND_FLOWERS = 3,
THRESHOLD_SPEW_LAVA = 6,
THRESHOLD_DANCING_FLAMES = 7,
MAX_COUNT_GROUND_FLOWERS = 3,
MAX_COUNT_SPEW_LAVA_TARGETS = 2,
MAX_COUNT_DANCING_FLAMES = 4,
};
struct npc_midsummer_ribbon_pole_target : public ScriptedAI
{
npc_midsummer_ribbon_pole_target(Creature* creature) : ScriptedAI(creature)
{
// ribbonPole trap also spawns this NPC (currently unwanted)
if (me->ToTempSummon())
me->DespawnOrUnsummon();
_ribbonPole = nullptr;
_bunny = nullptr;
_dancerList.clear();
LocateRibbonPole();
SpawnFireSpiralBunny();
_scheduler.Schedule(1s, [this](TaskContext context)
{
DoCleanupChecks();
context.Repeat();
})
.Schedule(5s, [this](TaskContext context)
{
DoFlameCircleChecks();
context.Repeat();
})
.Schedule(15s, [this](TaskContext context)
{
DoFireworkChecks();
context.Repeat();
})
.Schedule(10s, [this](TaskContext context)
{
DoGroundFlowerChecks();
context.Repeat();
})
.Schedule(10s, [this](TaskContext context)
{
DoSpewLavaChecks();
context.Repeat();
})
.Schedule(15s, [this](TaskContext context)
{
DoDancingFLameChecks();
context.Repeat();
});
}
void SpellHit(Unit* caster, SpellInfo const* spell) override
{
Player* dancer = caster->ToPlayer();
if (!dancer)
return;
switch (spell->Id)
{
case SPELL_TEST_RIBBON_POLE_CHANNEL_BLUE:
case SPELL_TEST_RIBBON_POLE_CHANNEL_RED:
case SPELL_TEST_RIBBON_POLE_CHANNEL_PINK:
break;
default:
return;
}
// prevent duplicates
if (std::find(_dancerList.begin(), _dancerList.end(), dancer) != _dancerList.end())
return;
_dancerList.push_back(dancer);
}
void LocateRibbonPole()
{
_scheduler.Schedule(420ms, [this](TaskContext context)
{
_ribbonPole = me->FindNearestGameObject(GO_RIBBON_POLE, 10.0f);
if (!_ribbonPole)
context.Repeat(420ms);
});
}
void SpawnFireSpiralBunny()
{
_bunny = me->FindNearestCreature(NPC_RIBBON_POLE_FIRE_SPIRAL_BUNNY, 10.0f);
if (!_bunny)
_bunny = DoSpawnCreature(NPC_RIBBON_POLE_FIRE_SPIRAL_BUNNY, 0, 0, 0, 0, TEMPSUMMON_MANUAL_DESPAWN, 0);
}
void DoCleanupChecks()
{
if (_dancerList.empty())
return;
// remove non-dancing players from list
std::erase_if(_dancerList, [](Player* dancer)
{
return !dancer->HasAura(SPELL_RIBBON_POLE_PERIODIC_VISUAL);
});
}
void DoFlameCircleChecks()
{
if (!_ribbonPole)
return;
if (_dancerList.size() >= THRESHOLD_FLAME_CIRCLE)
{
// random blue / red circle
if (urand(0, 1))
_ribbonPole->CastSpell(me, SPELL_FLAME_RING);
else
_ribbonPole->CastSpell(me, SPELL_FLAME_PATCH);
}
}
void DoFireworkChecks()
{
if (!_bunny)
return;
if (_dancerList.size() >= THRESHOLD_FIREWORK)
{
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_FIREWORK);
}
if (_dancerList.size() >= THRESHOLD_FIREWORK_3)
{
_scheduler.Schedule(500ms, [this](TaskContext /*context*/)
{
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_FIREWORK);
})
.Schedule(1s, [this](TaskContext /*context*/)
{
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_FIREWORK);
});
}
if (_dancerList.size() >= THRESHOLD_FIREWORK_5)
{
_scheduler.Schedule(1500ms, [this](TaskContext /*context*/)
{
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_FIREWORK);
})
.Schedule(2s, [this](TaskContext /*context*/)
{
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_FIREWORK);
});
}
}
void DoGroundFlowerChecks()
{
if (!_bunny)
return;
if (_dancerList.size() >= THRESHOLD_GROUND_FLOWERS)
{
std::list<Creature*> crList;
me->GetCreaturesWithEntryInRange(crList, 20.0f, NPC_GROUND_FLOWER);
if (crList.size() < MAX_COUNT_GROUND_FLOWERS)
_bunny->CastSpell(nullptr, SPELL_RIBBON_POLE_GROUND_FLOWER);
}
}
void DoSpewLavaChecks()
{
if (!_bunny)
return;
if (_dancerList.size() >= THRESHOLD_SPEW_LAVA)
{
if (!_dancerList.empty())
{
Acore::Containers::RandomShuffle(_dancerList);
for (uint8 i = 0; (i < MAX_COUNT_SPEW_LAVA_TARGETS) && (i < _dancerList.size()); i++)
{
Player* dancerTarget = _dancerList[i];
if (dancerTarget)
{
Creature* fireSpiralBunny = dancerTarget->SummonCreature(NPC_RIBBON_POLE_FIRE_SPIRAL_BUNNY, dancerTarget->GetPositionX(), dancerTarget->GetPositionY(), dancerTarget->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 10000);
if (fireSpiralBunny)
fireSpiralBunny->CastSpell(_bunny, SPELL_RIBBON_POLE_FIRE_SPIRAL_VISUAL, true);
}
}
}
}
}
void DoDancingFLameChecks()
{
if (_dancerList.size() >= THRESHOLD_DANCING_FLAMES)
{
std::list<Creature*> crList;
me->GetCreaturesWithEntryInRange(crList, 20.0f, NPC_BIG_DANCING_FLAMES);
if (crList.size() < MAX_COUNT_DANCING_FLAMES)
{
float spawnDist = 12.0f;
float angle = rand_norm() * 2 * M_PI;
DoSpawnCreature(NPC_BIG_DANCING_FLAMES, spawnDist * cos(angle), spawnDist * std::sin(angle), 0, angle + M_PI, TEMPSUMMON_TIMED_DESPAWN, 60000);
}
}
}
void UpdateAI(uint32 diff) override
{
_scheduler.Update(diff);
}
private:
TaskScheduler _scheduler;
std::vector<Player*> _dancerList;
GameObject* _ribbonPole;
Creature* _bunny;
};
class spell_midsummer_ribbon_pole_firework : public SpellScript
{
PrepareSpellScript(spell_midsummer_ribbon_pole_firework)
void ModDestHeight(SpellDestination& dest)
{
Position const offset = { 0.0f, 0.0f, 20.0f , 0.0f };
dest.RelocateOffset(offset);
}
void Register() override
{
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_midsummer_ribbon_pole_firework::ModDestHeight, EFFECT_0, TARGET_DEST_CASTER_RANDOM);
}
};
class spell_midsummer_ribbon_pole : public AuraScript
{
PrepareAuraScript(spell_midsummer_ribbon_pole)
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo(
{
SPELL_RIBBON_POLE_XP,
SPELL_TEST_RIBBON_POLE_CHANNEL_BLUE,
SPELL_TEST_RIBBON_POLE_CHANNEL_RED,
SPELL_TEST_RIBBON_POLE_CHANNEL_PINK
});
}
void HandleEffectPeriodic(AuraEffect const* /*aurEff*/)
{
PreventDefaultAction();
@@ -218,7 +506,9 @@ class spell_midsummer_ribbon_pole : public AuraScript
Creature* cr = target->FindNearestCreature(NPC_RIBBON_POLE_DEBUG_TARGET, 10.0f);
if (!cr)
{
target->RemoveAura(SPELL_RIBBON_POLE_CHANNEL_VISUAL);
target->RemoveAura(SPELL_TEST_RIBBON_POLE_CHANNEL_BLUE);
target->RemoveAura(SPELL_TEST_RIBBON_POLE_CHANNEL_RED);
target->RemoveAura(SPELL_TEST_RIBBON_POLE_CHANNEL_PINK);
SetDuration(1);
return;
}
@@ -243,7 +533,19 @@ class spell_midsummer_ribbon_pole : public AuraScript
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* ar = GetTarget();
ar->CastSpell(ar, SPELL_RIBBON_POLE_CHANNEL_VISUAL, true);
switch (urand(0, 2))
{
case 0:
ar->CastSpell(ar, SPELL_TEST_RIBBON_POLE_CHANNEL_BLUE, true);
break;
case 1:
ar->CastSpell(ar, SPELL_TEST_RIBBON_POLE_CHANNEL_RED, true);
break;
case 2:
default:
ar->CastSpell(ar, SPELL_TEST_RIBBON_POLE_CHANNEL_PINK, true);
break;
}
}
void Register() override
@@ -301,10 +603,10 @@ class spell_midsummer_torch_quest : public AuraScript
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
Unit* ar = GetTarget();
if (Creature* cr = ar->SummonCreature(25535, ar->GetPositionX(), ar->GetPositionY(), ar->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 90000))
if (Creature* cr = ar->SummonCreature(NPC_TORCH_TOSS_TARGET_BUNNY, ar->GetPositionX(), ar->GetPositionY(), ar->GetPositionZ(), 0.0f, TEMPSUMMON_TIMED_DESPAWN, 90000))
{
torchGUID = cr->GetGUID();
CAST_AI(npc_midsummer_torch_target, cr->AI())->SetPlayerGUID(ar->GetGUID(), (GetId() == 45716 ? 8 : 20));
CAST_AI(npc_midsummer_torch_target, cr->AI())->SetPlayerGUID(ar->GetGUID(), (GetId() == SPELL_TORCH_TOSS_TRAINING ? 8 : 20));
}
}
@@ -329,13 +631,32 @@ enum flingTorch
SPELL_FLING_TORCH_DUMMY = 46747,
SPELL_MISSED_TORCH = 45676,
SPELL_TORCH_COUNTER = 45693,
SPELL_TORCH_SHADOW = 46105
SPELL_TORCH_SHADOW = 46105,
SPELL_TORCH_CATCH_SUCCESS_A = 46081,
SPELL_TORCH_CATCH_SUCCESS_H = 46654,
SPELL_JUGGLE_TORCH = 45671,
QUEST_MORE_TORCH_TOSS_A = 11924,
QUEST_MORE_TORCH_TOSS_H = 11925,
};
class spell_midsummer_fling_torch : public SpellScript
{
PrepareSpellScript(spell_midsummer_fling_torch);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_FLING_TORCH,
SPELL_TORCH_SHADOW,
SPELL_MISSED_TORCH,
SPELL_TORCH_CATCH_SUCCESS_A,
SPELL_TORCH_CATCH_SUCCESS_H,
SPELL_TORCH_COUNTER
});
}
bool handled;
bool Load() override { handled = false; return true; }
@@ -412,13 +733,13 @@ class spell_midsummer_fling_torch : public SpellScript
{
aur->ModStackAmount(1);
uint8 count = 4;
if (target->GetQuestStatus(target->GetTeamId() ? 11925 : 11924) == QUEST_STATUS_INCOMPLETE) // More Torch Catching quests
if (target->GetQuestStatus(target->GetTeamId() ? QUEST_MORE_TORCH_TOSS_H : QUEST_MORE_TORCH_TOSS_A) == QUEST_STATUS_INCOMPLETE) // More Torch Catching quests
count = 10;
if (aur->GetStackAmount() >= count)
{
//target->CastSpell(target, 46711, true); // Set Flag: all torch returning quests are complete
target->CastSpell(target, (target->GetTeamId() ? 46654 : 46081), true); // Quest completion
target->CastSpell(target, (target->GetTeamId() ? SPELL_TORCH_CATCH_SUCCESS_H : SPELL_TORCH_CATCH_SUCCESS_A), true); // Quest completion
aur->SetDuration(1);
return;
}
@@ -433,7 +754,7 @@ class spell_midsummer_fling_torch : public SpellScript
void Register() override
{
AfterCast += SpellCastFn(spell_midsummer_fling_torch::HandleFinish);
if (m_scriptSpellId == 45671)
if (m_scriptSpellId == SPELL_JUGGLE_TORCH)
{
OnCheckCast += SpellCheckCastFn(spell_midsummer_fling_torch::CheckCast);
OnEffectHitTarget += SpellEffectFn(spell_midsummer_fling_torch::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
@@ -466,6 +787,21 @@ class spell_midsummer_juggling_torch : public SpellScript
{
PrepareSpellScript(spell_midsummer_juggling_torch);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_JUGGLE_SELF,
SPELL_JUGGLE_SLOW,
SPELL_JUGGLE_MED,
SPELL_JUGGLE_FAST,
SPELL_TORCH_SHADOW_SELF,
SPELL_TORCH_SHADOW_SLOW,
SPELL_TORCH_SHADOW_MED,
SPELL_TORCH_SHADOW_FAST
});
}
void HandleFinish()
{
Unit* caster = GetCaster();
@@ -543,9 +879,11 @@ void AddSC_event_midsummer_scripts()
// NPCs
new go_midsummer_bonfire();
RegisterCreatureAI(npc_midsummer_torch_target);
RegisterCreatureAI(npc_midsummer_ribbon_pole_target);
// Spells
RegisterSpellScript(spell_gen_crab_disguise);
RegisterSpellScript(spell_midsummer_ribbon_pole_firework);
RegisterSpellScript(spell_midsummer_ribbon_pole);
RegisterSpellScript(spell_midsummer_ribbon_pole_visual);
RegisterSpellScript(spell_midsummer_torch_quest);

View File

@@ -15,99 +15,12 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ScriptData
SDName: Dustwallow_Marsh
SD%Complete: 95
SDComment: Quest support: 11180, 11126, 11174
SDCategory: Dustwallow Marsh
EndScriptData */
/* ContentData
npc_cassa_crimsonwing - handled by npc_taxi
EndContentData */
#include "Player.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
#include "SpellScript.h"
/*######
## npc_zelfrax
######*/
Position const MovePosition = {-2967.030f, -3872.1799f, 35.620f, 0.0f};
enum Zelfrax
{
SAY_ZELFRAX1 = 0,
SAY_ZELFRAX2 = 1
};
class npc_zelfrax : public CreatureScript
{
public:
npc_zelfrax() : CreatureScript("npc_zelfrax") { }
CreatureAI* GetAI(Creature* creature) const override
{
return new npc_zelfraxAI(creature);
}
struct npc_zelfraxAI : public ScriptedAI
{
npc_zelfraxAI(Creature* creature) : ScriptedAI(creature)
{
MoveToDock();
}
void AttackStart(Unit* who) override
{
if (!who)
return;
if (me->Attack(who, true))
{
me->SetInCombatWith(who);
who->SetInCombatWith(me);
if (IsCombatMovementAllowed())
me->GetMotionMaster()->MoveChase(who);
}
}
void MovementInform(uint32 Type, uint32 /*Id*/) override
{
if (Type != POINT_MOTION_TYPE)
return;
me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation());
me->SetImmuneToPC(false);
SetCombatMovement(true);
if (me->IsInCombat())
if (Unit* unit = me->GetVictim())
me->GetMotionMaster()->MoveChase(unit);
}
void MoveToDock()
{
SetCombatMovement(false);
me->GetMotionMaster()->MovePoint(0, MovePosition);
Talk(SAY_ZELFRAX1);
Talk(SAY_ZELFRAX2);
}
void UpdateAI(uint32 /*Diff*/) override
{
if (!UpdateVictim())
return;
DoMeleeAttackIfReady();
}
};
};
enum SpellScripts
{
SPELL_OOZE_ZAP = 42489,
@@ -243,7 +156,6 @@ public:
void AddSC_dustwallow_marsh()
{
new npc_zelfrax();
new spell_ooze_zap();
new spell_ooze_zap_channel_end();
new spell_energize_aoe();

View File

@@ -157,7 +157,6 @@ enum ThrallWarchief : uint32
QUEST_WHAT_THE_WIND_CARRIES = 6566,
GOSSIP_MENU_THRALL = 3664,
GOSSIP_RESPONSE_THRALL_FIRST = 5733,
GOSSIP_OPTION_DEFAULT = 0
};
const Position heraldOfThrallPos = { -462.404f, -2637.68f, 96.0656f, 5.8606f };
@@ -179,7 +178,7 @@ public:
uint32 NextAction = GOSSIP_ACTION_INFO_DEF + DiscussionOrder + 1;
uint32 GossipResponse = GOSSIP_RESPONSE_THRALL_FIRST + DiscussionOrder - 1;
AddGossipItemFor(player, GOSSIP_MENU_THRALL + DiscussionOrder, GOSSIP_OPTION_DEFAULT, GOSSIP_SENDER_MAIN, NextAction);
AddGossipItemFor(player, GOSSIP_MENU_THRALL + DiscussionOrder, 0, GOSSIP_SENDER_MAIN, NextAction);
SendGossipMenuFor(player, GossipResponse, creature->GetGUID());
}
else if (DiscussionOrder == 7)
@@ -200,7 +199,7 @@ public:
if (player->GetQuestStatus(QUEST_WHAT_THE_WIND_CARRIES) == QUEST_STATUS_INCOMPLETE)
{
AddGossipItemFor(player, GOSSIP_MENU_THRALL, GOSSIP_OPTION_DEFAULT, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
AddGossipItemFor(player, GOSSIP_MENU_THRALL, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
}
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());

View File

@@ -918,7 +918,8 @@ public:
player->AddAura(SPELL_WARTS, player);
else
{
DoCast(player, SPELL_FROG_KISS); // Removes SPELL_WARTSBGONE_LIP_BALM
// Removes SPELL_WARTSBGONE_LIP_BALM
player->CastSpell(player, SPELL_FROG_KISS, true);
if (me->GetEntry() == NPC_LAKE_FROG)
{
@@ -1298,6 +1299,30 @@ public:
}
};
// 62536 - Frog Kiss
class spell_frog_kiss : public SpellScript
{
PrepareSpellScript(spell_frog_kiss);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_WARTSBGONE_LIP_BALM });
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
if (Player* target = GetHitPlayer())
{
target->RemoveAurasDueToSpell(SPELL_WARTSBGONE_LIP_BALM);
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_frog_kiss::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
void AddSC_grizzly_hills()
{
// Theirs
@@ -1319,4 +1344,5 @@ void AddSC_grizzly_hills()
new spell_warhead_fuse();
RegisterSpellScript(spell_q12227_outhouse_groans);
RegisterSpellScript(spell_q12227_camera_shake);
RegisterSpellScript(spell_frog_kiss);
}

View File

@@ -65,16 +65,13 @@ enum Spells
enum Misc
{
MAX_ADVISORS = 3,
MAX_ADVISORS = 2,
NPC_SEER_OLUM = 22820,
GO_CAGE = 185952,
};
const Position advisorsPosition[MAX_ADVISORS + 2] =
const Position advisorsPosition[MAX_ADVISORS] =
{
{459.61f, -534.81f, -7.54f, 3.82f},
{463.83f, -540.23f, -7.54f, 3.15f},
{459.94f, -547.28f, -7.54f, 2.42f},
{448.37f, -544.71f, -7.54f, 0.00f},
{457.37f, -544.71f, -7.54f, 0.00f}
};
@@ -94,21 +91,13 @@ struct boss_fathomlord_karathress : public BossAI
BossAI::Reset();
_recentlySpoken = false;
me->SummonCreature(NPC_FATHOM_GUARD_TIDALVESS, advisorsPosition[0], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 600000);
me->SummonCreature(NPC_FATHOM_GUARD_SHARKKIS, advisorsPosition[1], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 600000);
me->SummonCreature(NPC_FATHOM_GUARD_CARIBDIS, advisorsPosition[2], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 600000);
ScheduleHealthCheckEvent(75, [&]{
for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr)
{
if (Creature* summon = ObjectAccessor::GetCreature(*me, *itr))
instance->DoForAllMinions(DATA_FATHOM_LORD_KARATHRESS, [&](Creature* fathomguard) {
if (fathomguard->IsAlive())
{
if (summon->GetMaxHealth() > 500000)
{
summon->CastSpell(me, SPELL_BLESSING_OF_THE_TIDES, true);
}
fathomguard->CastSpell(me, SPELL_BLESSING_OF_THE_TIDES, true);
}
}
});
if (me->HasAura(SPELL_BLESSING_OF_THE_TIDES))
{
Talk(SAY_GAIN_BLESSING);
@@ -122,19 +111,22 @@ struct boss_fathomlord_karathress : public BossAI
if (summon->GetEntry() == NPC_SEER_OLUM)
{
summon->SetWalk(true);
summon->GetMotionMaster()->MovePoint(0, advisorsPosition[MAX_ADVISORS + 1], false);
summon->GetMotionMaster()->MovePoint(0, advisorsPosition[MAX_ADVISORS - 1], false);
}
}
void SummonedCreatureDies(Creature* summon, Unit*) override
{
summons.Despawn(summon);
if (summon->GetEntry() == NPC_FATHOM_GUARD_TIDALVESS)
Talk(SAY_GAIN_ABILITY1);
if (summon->GetEntry() == NPC_FATHOM_GUARD_SHARKKIS)
Talk(SAY_GAIN_ABILITY2);
if (summon->GetEntry() == NPC_FATHOM_GUARD_CARIBDIS)
Talk(SAY_GAIN_ABILITY3);
scheduler.Schedule(1s, [this, summon](TaskContext)
{
summons.Despawn(summon);
});
}
void KilledUnit(Unit* /*victim*/) override
@@ -154,7 +146,7 @@ struct boss_fathomlord_karathress : public BossAI
{
Talk(SAY_DEATH);
BossAI::JustDied(killer);
me->SummonCreature(NPC_SEER_OLUM, advisorsPosition[MAX_ADVISORS], TEMPSUMMON_TIMED_DESPAWN, 3600000);
me->SummonCreature(NPC_SEER_OLUM, advisorsPosition[MAX_ADVISORS-2], TEMPSUMMON_TIMED_DESPAWN, 3600000);
if (GameObject* gobject = me->FindNearestGameObject(GO_CAGE, 100.0f))
{
gobject->SetGoState(GO_STATE_ACTIVE);
@@ -207,8 +199,6 @@ struct boss_fathomguard_sharkkis : public ScriptedAI
{
boss_fathomguard_sharkkis(Creature* creature) : ScriptedAI(creature), summons(creature)
{
summons.clear();
_instance = creature->GetInstanceScript();
_scheduler.SetValidator([this]
@@ -224,6 +214,7 @@ struct boss_fathomguard_sharkkis : public ScriptedAI
_scheduler.CancelAll();
summons.DespawnAll();
summons.clear();
}
void JustSummoned(Creature* summon) override
@@ -232,8 +223,12 @@ struct boss_fathomguard_sharkkis : public ScriptedAI
summons.Summon(summon);
}
void JustEngagedWith(Unit* /*who*/) override
void JustEngagedWith(Unit* who) override
{
if (Creature* karathress = _instance->GetCreature(DATA_FATHOM_LORD_KARATHRESS))
{
karathress->Attack(who, false);
}
_scheduler.Schedule(2500ms, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_HURL_TRIDENT);
@@ -268,7 +263,7 @@ struct boss_fathomguard_sharkkis : public ScriptedAI
{
if (Creature* karathress = _instance->GetCreature(DATA_FATHOM_LORD_KARATHRESS))
{
me->CastSpell(karathress, SPELL_POWER_OF_SHARKKIS);
me->CastSpell(karathress, SPELL_POWER_OF_SHARKKIS, true);
}
}
@@ -416,8 +411,12 @@ struct boss_fathomguard_tidalvess : public ScriptedAI
}
}
void JustEngagedWith(Unit* /*who*/) override
void JustEngagedWith(Unit* who) override
{
if (Creature* karathress = _instance->GetCreature(DATA_FATHOM_LORD_KARATHRESS))
{
karathress->Attack(who, false);
}
_scheduler.Schedule(10900ms, [this](TaskContext context)
{
DoCastVictim(SPELL_FROST_SHOCK);
@@ -439,7 +438,7 @@ struct boss_fathomguard_tidalvess : public ScriptedAI
{
if (Creature* karathress = _instance->GetCreature(DATA_FATHOM_LORD_KARATHRESS))
{
me->CastSpell(karathress, SPELL_POWER_OF_TIDALVESS);
me->CastSpell(karathress, SPELL_POWER_OF_TIDALVESS, true);
}
}
@@ -489,8 +488,12 @@ struct boss_fathomguard_caribdis : public ScriptedAI
summons.Summon(summon);
}
void JustEngagedWith(Unit* /*who*/) override
void JustEngagedWith(Unit* who) override
{
if (Creature* karathress = _instance->GetCreature(DATA_FATHOM_LORD_KARATHRESS))
{
karathress->Attack(who, false);
}
_scheduler.Schedule(27900ms, [this](TaskContext context)
{
DoCastSelf(SPELL_WATER_BOLT_VOLLEY);
@@ -517,7 +520,7 @@ struct boss_fathomguard_caribdis : public ScriptedAI
{
if (Creature* karathress = _instance->GetCreature(DATA_FATHOM_LORD_KARATHRESS))
{
me->CastSpell(karathress, SPELL_POWER_OF_CARIBDIS);
me->CastSpell(karathress, SPELL_POWER_OF_CARIBDIS, true);
}
}

View File

@@ -19,6 +19,7 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "serpent_shrine.h"
#include "TaskScheduler.h"
enum Talk
{
@@ -59,18 +60,12 @@ enum Misc
NPC_GREYHEART_SPELLBINDER = 21806,
NPC_SHADOW_OF_LEOTHERAS = 21875,
};
EVENT_SPELL_BERSERK = 1,
EVENT_HEALTH_CHECK = 2,
EVENT_SWITCH_TO_DEMON = 3,
EVENT_SPELL_WHIRLWIND = 4,
EVENT_KILL_TALK = 5,
EVENT_SWITCH_TO_ELF = 6,
EVENT_SPELL_INSIDIOUS_WHISPER = 7,
EVENT_SUMMON_DEMON = 8,
EVENT_RESTORE_FIGHT = 9,
EVENT_SPELL_SHADOW_BOLT = 20
enum Groups
{
GROUP_COMBAT = 1,
GROUP_DEMON = 2
};
const Position channelersPos[MAX_CHANNELERS] =
@@ -80,267 +75,231 @@ const Position channelersPos[MAX_CHANNELERS] =
{362.11f, -437.48f, 29.52f, 0.9f}
};
class boss_leotheras_the_blind : public CreatureScript
struct boss_leotheras_the_blind : public BossAI
{
public:
boss_leotheras_the_blind() : CreatureScript("boss_leotheras_the_blind") { }
CreatureAI* GetAI(Creature* creature) const override
boss_leotheras_the_blind(Creature* creature) : BossAI(creature, DATA_LEOTHERAS_THE_BLIND)
{
return GetSerpentShrineAI<boss_leotheras_the_blindAI>(creature);
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
struct boss_leotheras_the_blindAI : public BossAI
void Reset() override
{
boss_leotheras_the_blindAI(Creature* creature) : BossAI(creature, DATA_LEOTHERAS_THE_BLIND)
{
}
BossAI::Reset();
DoCastSelf(SPELL_CLEAR_CONSUMING_MADNESS, true);
DoCastSelf(SPELL_DUAL_WIELD, true);
me->SetStandState(UNIT_STAND_STATE_KNEEL);
me->LoadEquipment(0, true);
me->SetReactState(REACT_PASSIVE);
_recentlySpoken = false;
SummonChannelers();
ScheduleHealthCheckEvent(15, [&]{
if (me->GetDisplayId() != me->GetNativeDisplayId())
{
//is currently in metamorphosis
DoResetThreatList();
me->LoadEquipment();
me->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS);
scheduler.RescheduleGroup(GROUP_COMBAT, 10s);
}
scheduler.CancelGroup(GROUP_DEMON);
scheduler.DelayAll(10s);
void Reset() override
{
BossAI::Reset();
me->CastSpell(me, SPELL_CLEAR_CONSUMING_MADNESS, true);
me->CastSpell(me, SPELL_DUAL_WIELD, true);
me->SetStandState(UNIT_STAND_STATE_KNEEL);
me->LoadEquipment(0, true);
me->SetReactState(REACT_PASSIVE);
}
me->GetMotionMaster()->Clear();
me->StopMoving();
Talk(SAY_FINAL_FORM);
void InitializeAI() override
{
BossAI::InitializeAI();
SummonChannelers();
}
void JustReachedHome() override
{
BossAI::JustReachedHome();
SummonChannelers();
}
void SummonChannelers()
{
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, false);
me->CastSpell(me, SPELL_BANISH, true);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true);
summons.DespawnAll();
for (uint8 i = 0; i < MAX_CHANNELERS; ++i)
me->SummonCreature(NPC_GREYHEART_SPELLBINDER, channelersPos[i], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
}
void MoveInLineOfSight(Unit* /*who*/) override { }
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
}
void SummonedCreatureDies(Creature* summon, Unit*) override
{
me->SetInCombatWithZone();
summons.Despawn(summon);
if (summon->GetEntry() == NPC_GREYHEART_SPELLBINDER)
if (!summons.HasEntry(NPC_GREYHEART_SPELLBINDER))
{
me->RemoveAllAuras();
me->LoadEquipment();
me->SetReactState(REACT_AGGRESSIVE);
me->SetStandState(UNIT_STAND_STATE_STAND);
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_SPELL_BERSERK, 600000);
events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000);
events.ScheduleEvent(EVENT_SWITCH_TO_DEMON, 55000);
events.ScheduleEvent(EVENT_SPELL_WHIRLWIND, 10000);
}
}
void KilledUnit(Unit* /*victim*/) override
{
if (events.GetNextEventTime(EVENT_KILL_TALK) == 0)
scheduler.Schedule(4s, [this](TaskContext)
{
Talk(me->GetDisplayId() != me->GetNativeDisplayId() ? SAY_DEMON_SLAY : SAY_NIGHTELF_SLAY);
events.ScheduleEvent(EVENT_KILL_TALK, 6000);
}
}
void JustDied(Unit* killer) override
{
me->CastSpell(me, SPELL_CLEAR_CONSUMING_MADNESS, true);
Talk(SAY_DEATH);
BossAI::JustDied(killer);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
me->SetStandState(UNIT_STAND_STATE_KNEEL);
}
void AttackStart(Unit* who) override
{
if (who && me->Attack(who, true))
me->GetMotionMaster()->MoveChase(who, me->GetDisplayId() == me->GetNativeDisplayId() ? 0.0f : 25.0f);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
DoCastSelf(SPELL_SUMMON_SHADOW_OF_LEOTHERAS);
}).Schedule(6s, [this](TaskContext)
{
case EVENT_SPELL_BERSERK:
me->CastSpell(me, SPELL_BERSERK, true);
break;
case EVENT_HEALTH_CHECK:
if (me->HealthBelowPct(15))
{
if (me->GetDisplayId() != me->GetNativeDisplayId())
{
DoResetThreatList();
me->LoadEquipment();
me->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS);
events.ScheduleEvent(EVENT_SPELL_WHIRLWIND, 10000);
}
events.CancelEvent(EVENT_SWITCH_TO_DEMON);
events.CancelEvent(EVENT_SPELL_INSIDIOUS_WHISPER);
events.DelayEvents(10000);
events.ScheduleEvent(EVENT_SUMMON_DEMON, 4000);
events.ScheduleEvent(EVENT_RESTORE_FIGHT, 6000);
me->SetStandState(UNIT_STAND_STATE_KNEEL);
me->SetReactState(REACT_PASSIVE);
me->GetMotionMaster()->Clear();
me->StopMoving();
Talk(SAY_FINAL_FORM);
break;
}
events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000);
break;
case EVENT_SWITCH_TO_DEMON:
DoResetThreatList();
Talk(SAY_SWITCH_TO_DEMON);
me->LoadEquipment(0, true);
me->GetMotionMaster()->MoveChase(me->GetVictim(), 25.0f);
me->CastSpell(me, SPELL_METAMORPHOSIS, true);
events.CancelEvent(EVENT_SPELL_WHIRLWIND);
events.ScheduleEvent(EVENT_SPELL_INSIDIOUS_WHISPER, 25000);
events.ScheduleEvent(EVENT_SWITCH_TO_ELF, 60000);
break;
case EVENT_SWITCH_TO_ELF:
DoResetThreatList();
me->LoadEquipment();
me->GetMotionMaster()->MoveChase(me->GetVictim(), 0.0f);
me->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS);
events.ScheduleEvent(EVENT_SWITCH_TO_DEMON, 55000);
events.ScheduleEvent(EVENT_SPELL_WHIRLWIND, 10000);
break;
case EVENT_SPELL_WHIRLWIND:
me->CastSpell(me, SPELL_WHIRLWIND, false);
events.ScheduleEvent(EVENT_SPELL_WHIRLWIND, 27000);
break;
case EVENT_SPELL_INSIDIOUS_WHISPER:
Talk(SAY_INNER_DEMONS);
me->CastCustomSpell(SPELL_INSIDIOUS_WHISPER, SPELLVALUE_MAX_TARGETS, 5, me, false);
break;
case EVENT_SUMMON_DEMON:
me->CastSpell(me, SPELL_SUMMON_SHADOW_OF_LEOTHERAS, true);
break;
case EVENT_RESTORE_FIGHT:
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->GetMotionMaster()->MoveChase(me->GetVictim());
break;
}
if (me->GetDisplayId() == me->GetNativeDisplayId())
DoMeleeAttackIfReady();
else if (me->isAttackReady(BASE_ATTACK))
{
me->CastSpell(me->GetVictim(), SPELL_CHAOS_BLAST, false);
me->setAttackTimer(BASE_ATTACK, 2000);
}
}
};
};
class npc_inner_demon : public CreatureScript
{
public:
npc_inner_demon() : CreatureScript("npc_inner_demon") { }
CreatureAI* GetAI(Creature* creature) const override
{
return GetSerpentShrineAI<npc_inner_demonAI>(creature);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetReactState(REACT_AGGRESSIVE);
me->GetMotionMaster()->MoveChase(me->GetVictim());
});
});
}
struct npc_inner_demonAI : public ScriptedAI
void SummonChannelers()
{
npc_inner_demonAI(Creature* creature) : ScriptedAI(creature)
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, false);
DoCastSelf(SPELL_BANISH);
me->ApplySpellImmune(0, IMMUNITY_MECHANIC, MECHANIC_BANISH, true);
//probably needs a spell instead
summons.DespawnAll();
for (uint8 i = 0; i < MAX_CHANNELERS; ++i)
{
me->SummonCreature(NPC_GREYHEART_SPELLBINDER, channelersPos[i], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 5000);
}
}
ObjectGuid ownerGUID;
EventMap events;
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
}
void EnterEvadeMode(EvadeReason /*why*/) override
void SummonedCreatureDies(Creature* summon, Unit*) override
{
me->SetInCombatWithZone();
summons.Despawn(summon);
if (summon->GetEntry() == NPC_GREYHEART_SPELLBINDER)
{
me->DespawnOrUnsummon(1);
}
void IsSummonedBy(WorldObject* summoner) override
{
if (!summoner)
return;
ownerGUID = summoner->GetGUID();
events.Reset();
events.ScheduleEvent(EVENT_SPELL_SHADOW_BOLT, 4000);
}
void JustDied(Unit* /*killer*/) override
{
if (Unit* unit = ObjectAccessor::GetUnit(*me, ownerGUID))
unit->RemoveAurasDueToSpell(SPELL_INSIDIOUS_WHISPER);
}
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (!who || who->GetGUID() != ownerGUID)
damage = 0;
}
bool CanAIAttack(Unit const* who) const override
{
return who->GetGUID() == ownerGUID;
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
switch (events.ExecuteEvent())
if (!summons.HasEntry(NPC_GREYHEART_SPELLBINDER))
{
case EVENT_SPELL_SHADOW_BOLT:
me->CastSpell(me->GetVictim(), SPELL_SHADOW_BOLT, false);
events.ScheduleEvent(EVENT_SPELL_SHADOW_BOLT, 6000);
break;
}
me->RemoveAllAuras();
me->LoadEquipment();
me->SetReactState(REACT_AGGRESSIVE);
me->SetStandState(UNIT_STAND_STATE_STAND);
Talk(SAY_AGGRO);
scheduler.Schedule(10min, [this](TaskContext)
{
DoCastSelf(SPELL_BERSERK);
});
ElfTime();
}
}
}
void ElfTime()
{
scheduler.Schedule(25050ms, 32550ms, GROUP_COMBAT, [this](TaskContext context)
{
DoCastSelf(SPELL_WHIRLWIND);
context.Repeat(30250ms, 34900ms);
}).Schedule(60350ms, GROUP_DEMON, [this](TaskContext)
{
DoResetThreatList();
Talk(SAY_SWITCH_TO_DEMON);
DemonTime();
});
}
void DemonTime()
{
me->LoadEquipment(0, true);
me->GetMotionMaster()->MoveChase(me->GetVictim(), 25.0f);
DoCastSelf(SPELL_METAMORPHOSIS, true);
scheduler.CancelGroup(GROUP_COMBAT);
scheduler.Schedule(24250ms, GROUP_DEMON, [this](TaskContext)
{
Talk(SAY_INNER_DEMONS);
me->CastCustomSpell(SPELL_INSIDIOUS_WHISPER, SPELLVALUE_MAX_TARGETS, 5, me, false);
}).Schedule(60s, [this](TaskContext)
{
DoResetThreatList();
me->LoadEquipment();
me->GetMotionMaster()->MoveChase(me->GetVictim(), 0.0f);
me->RemoveAurasDueToSpell(SPELL_METAMORPHOSIS);
ElfTime();
});
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
if (me->GetDisplayId() == me->GetNativeDisplayId())
{
DoMeleeAttackIfReady();
}
};
else if (me->isAttackReady(BASE_ATTACK))
{
me->CastSpell(me->GetVictim(), SPELL_CHAOS_BLAST, false);
me->setAttackTimer(BASE_ATTACK, 2000);
}
}
private:
bool _recentlySpoken;
};
struct npc_inner_demon : public ScriptedAI
{
npc_inner_demon(Creature* creature) : ScriptedAI(creature)
{
_scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
_instance = creature->GetInstanceScript();
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
me->DespawnOrUnsummon(1);
}
void IsSummonedBy(WorldObject* summoner) override
{
if (!summoner)
return;
_scheduler.CancelAll();
_scheduler.Schedule(4s, [this](TaskContext context)
{
DoCastVictim(SPELL_SHADOW_BOLT);
context.Repeat(6s);
});
}
void JustDied(Unit* /*killer*/) override
{
if (Creature* leotheras = _instance->GetCreature(DATA_LEOTHERAS_THE_BLIND))
{
leotheras->RemoveAurasDueToSpell(SPELL_INSIDIOUS_WHISPER);
}
}
void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override
{
if (Creature* leotheras = _instance->GetCreature(DATA_LEOTHERAS_THE_BLIND))
{
if (!who || who->GetGUID() != leotheras->GetGUID())
{
damage = 0;
}
}
}
bool CanAIAttack(Unit const* who) const override
{
if (Creature* leotheras = _instance->GetCreature(DATA_LEOTHERAS_THE_BLIND))
{
return who->GetGUID() == leotheras->GetGUID();
}
return false;
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
{
return;
}
_scheduler.Update(diff);
DoMeleeAttackIfReady();
}
private:
TaskScheduler _scheduler;
InstanceScript* _instance;
};
class spell_leotheras_whirlwind : public SpellScriptLoader
@@ -516,8 +475,8 @@ public:
void AddSC_boss_leotheras_the_blind()
{
new boss_leotheras_the_blind();
new npc_inner_demon();
RegisterSerpentShrineAI(boss_leotheras_the_blind);
RegisterSerpentShrineAI(npc_inner_demon);
new spell_leotheras_whirlwind();
new spell_leotheras_chaos_blast();
new spell_leotheras_insidious_whisper();

View File

@@ -26,7 +26,10 @@ enum Spells
SPELL_GEYSER = 37478,
SPELL_SPOUT_VISUAL = 37431,
SPELL_SPOUT_PERIODIC = 37430,
SPELL_LURKER_SPAWN_TRIGGER = 54587 // Needed for achievement
SPELL_LURKER_SPAWN_TRIGGER = 54587, // Needed for achievement
SPELL_CLEAR_ALL_DEBUFFS = 34098,
SPELL_SUBMERGE_VISUAL = 28819,
};
enum Misc
@@ -37,13 +40,12 @@ enum Misc
NPC_COILFANG_GUARDIAN = 21873,
NPC_COILFANG_AMBUSHER = 21865,
};
EVENT_PHASE_1 = 1,
EVENT_PHASE_2 = 2,
EVENT_SPELL_WHIRL = 3,
EVENT_SPELL_SPOUT = 4,
EVENT_SPELL_GEYSER = 5,
EVENT_SPELL_SPOUT_PERIODIC = 6
enum Groups
{
GROUP_WHIRL = 1,
GROUP_GEYSER = 2
};
const Position positions[MAX_SUMMONS] =
@@ -59,152 +61,149 @@ const Position positions[MAX_SUMMONS] =
{42.471519f, -445.115295f, -19.769423f, 0.0f}
};
class boss_the_lurker_below : public CreatureScript
struct boss_the_lurker_below : public BossAI
{
public:
boss_the_lurker_below() : CreatureScript("boss_the_lurker_below") { }
CreatureAI* GetAI(Creature* creature) const override
boss_the_lurker_below(Creature* creature) : BossAI(creature, DATA_THE_LURKER_BELOW)
{
return GetSerpentShrineAI<boss_the_lurker_belowAI>(creature);
scheduler.SetValidator([this]
{
return !me->HasUnitState(UNIT_STATE_CASTING);
});
}
struct boss_the_lurker_belowAI : public BossAI
void Reset() override
{
boss_the_lurker_belowAI(Creature* creature) : BossAI(creature, DATA_THE_LURKER_BELOW) { }
BossAI::Reset();
me->SetReactState(REACT_PASSIVE);
me->SetStandState(UNIT_STAND_STATE_SUBMERGED);
me->SetVisible(false);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
void Reset() override
void DoAction(int32 action) override
{
if (action == ACTION_START_EVENT)
{
BossAI::Reset();
me->SetReactState(REACT_AGGRESSIVE);
me->setAttackTimer(BASE_ATTACK, 6000);
me->SetVisible(true);
me->UpdateObjectVisibility(true);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetInCombatWithZone();
}
}
void AttackStart(Unit* who) override
{
if (who && me->GetReactState() == REACT_AGGRESSIVE)
{
me->Attack(who, true);
}
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
SchedulerPhaseOne(38800ms, 91000ms);
}
void SchedulerPhaseOne(std::chrono::milliseconds spoutTimer, std::chrono::milliseconds p2Timer)
{
scheduler.Schedule(10900ms, GROUP_GEYSER, [this](TaskContext context)
{
DoCastRandomTarget(SPELL_GEYSER);
context.Repeat(10200ms, 54900ms);
}).Schedule(18150ms, GROUP_WHIRL, [this](TaskContext context)
{
DoCastSelf(SPELL_WHIRL);
context.Repeat(34150ms, 68550ms);
}).Schedule(spoutTimer, [this](TaskContext context)
{
Talk(EMOTE_TAKE_BREATH);
me->CastSpell(me, SPELL_SPOUT_VISUAL, TRIGGERED_IGNORE_SET_FACING);
me->SetReactState(REACT_PASSIVE);
me->SetFacingToObject(me->GetVictim());
me->SetTarget();
scheduler.RescheduleGroup(GROUP_GEYSER, 25s);
scheduler.RescheduleGroup(GROUP_WHIRL, 18s);
scheduler.Schedule(3s, [this](TaskContext)
{
me->InterruptNonMeleeSpells(false);
DoCastSelf(SPELL_SPOUT_PERIODIC, true);
});
context.Repeat(60s);
}).Schedule(p2Timer, [this](TaskContext)
{
//phase2
scheduler.CancelAll();
DoCastSelf(SPELL_SUBMERGE_VISUAL, true);
DoCastSelf(SPELL_CLEAR_ALL_DEBUFFS, true);
me->SetStandState(UNIT_STAND_STATE_SUBMERGED);
me->SetVisible(false);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
// Reset summons
summons.DespawnAll();
}
void JustSummoned(Creature* summon) override
{
summon->SetInCombatWithZone();
summons.Summon(summon);
}
void DoAction(int32 param) override
{
if (param == ACTION_START_EVENT)
for (uint8 i = 0; i < MAX_SUMMONS; ++i)
{
me->SetReactState(REACT_AGGRESSIVE);
me->setAttackTimer(BASE_ATTACK, 6000);
me->SetVisible(true);
me->UpdateObjectVisibility(true);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetInCombatWithZone();
//needs sniffed spell probably
me->SummonCreature(i < 6 ? NPC_COILFANG_AMBUSHER : NPC_COILFANG_GUARDIAN, positions[i].GetPositionX(), positions[i].GetPositionY(), positions[i].GetPositionZ(), positions[i].GetAngle(me), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000);
}
SchedulerPhaseTwo();
});
}
void SchedulerPhaseTwo()
{
scheduler.Schedule(60s, [this](TaskContext)
{
me->setAttackTimer(BASE_ATTACK, 6000);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
scheduler.CancelAll();
SchedulerPhaseOne(10000ms, 90750ms);
});
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
scheduler.Update(diff);
if (me->getStandState() != UNIT_STAND_STATE_STAND || !me->isAttackReady() || me->GetReactState() != REACT_AGGRESSIVE)
return;
Unit* target = nullptr;
if (me->IsWithinMeleeRange(me->GetVictim()))
{
target = me->GetVictim();
}
else
{
ThreatContainer::StorageType const& t_list = me->GetThreatMgr().GetThreatList();
for (ThreatReference const* ref : t_list)
{
if (Unit* threatTarget = ObjectAccessor::GetUnit(*me, ref->getUnitGuid()))
{
if (me->IsWithinMeleeRange(threatTarget))
{
target = threatTarget;
break;
}
}
}
}
void JustDied(Unit* killer) override
if (target)
{
BossAI::JustDied(killer);
me->AttackerStateUpdate(target);
}
void AttackStart(Unit* who) override
else if ((target = SelectTarget(SelectTargetMethod::Random, 0)))
{
if (who && me->GetReactState() == REACT_AGGRESSIVE)
me->Attack(who, true);
me->CastSpell(target, SPELL_WATER_BOLT, false);
}
void JustEngagedWith(Unit* /*who*/) override
{
events.ScheduleEvent(EVENT_SPELL_WHIRL, 18000);
events.ScheduleEvent(EVENT_SPELL_SPOUT, 45000);
events.ScheduleEvent(EVENT_SPELL_GEYSER, 10000);
events.ScheduleEvent(EVENT_PHASE_2, 125000);
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
events.Update(diff);
switch (events.ExecuteEvent())
{
case EVENT_SPELL_WHIRL:
me->CastSpell(me, SPELL_WHIRL, false);
events.ScheduleEvent(EVENT_SPELL_WHIRL, 18000);
break;
case EVENT_SPELL_GEYSER:
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
me->CastSpell(target, SPELL_GEYSER, false);
events.ScheduleEvent(EVENT_SPELL_GEYSER, 10000);
break;
case EVENT_SPELL_SPOUT:
Talk(EMOTE_TAKE_BREATH);
me->CastSpell(me, SPELL_SPOUT_VISUAL, TRIGGERED_IGNORE_SET_FACING);
me->SetReactState(REACT_PASSIVE);
me->SetFacingToObject(me->GetVictim());
me->SetTarget();
events.ScheduleEvent(EVENT_SPELL_SPOUT, 60000);
events.RescheduleEvent(EVENT_SPELL_WHIRL, 18000);
events.RescheduleEvent(EVENT_SPELL_GEYSER, 25000);
events.ScheduleEvent(EVENT_SPELL_SPOUT_PERIODIC, 3000);
break;
case EVENT_SPELL_SPOUT_PERIODIC:
me->InterruptNonMeleeSpells(false);
me->CastSpell(me, SPELL_SPOUT_PERIODIC, true);
break;
case EVENT_PHASE_2:
events.Reset();
events.ScheduleEvent(EVENT_PHASE_1, 60000);
me->SetStandState(UNIT_STAND_STATE_SUBMERGED);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
for (uint8 i = 0; i < MAX_SUMMONS; ++i)
me->SummonCreature(i < 6 ? NPC_COILFANG_AMBUSHER : NPC_COILFANG_GUARDIAN, positions[i].GetPositionX(), positions[i].GetPositionY(), positions[i].GetPositionZ(), positions[i].GetAngle(me), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000);
break;
case EVENT_PHASE_1:
me->setAttackTimer(BASE_ATTACK, 6000);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
events.Reset();
events.ScheduleEvent(EVENT_SPELL_SPOUT, 10000);
events.ScheduleEvent(EVENT_PHASE_2, 120000);
break;
}
if (me->getStandState() != UNIT_STAND_STATE_STAND || !me->isAttackReady() || me->GetReactState() != REACT_AGGRESSIVE)
return;
Unit* target = nullptr;
if (me->IsWithinMeleeRange(me->GetVictim()))
target = me->GetVictim();
else
{
ThreatContainer::StorageType const& t_list = me->GetThreatMgr().GetThreatList();
for (ThreatContainer::StorageType::const_iterator itr = t_list.begin(); itr != t_list.end(); ++itr)
if (Unit* threatTarget = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()))
if (me->IsWithinMeleeRange(threatTarget))
{
target = threatTarget;
break;
}
}
if (target)
me->AttackerStateUpdate(target);
else if ((target = SelectTarget(SelectTargetMethod::Random, 0)))
me->CastSpell(target, SPELL_WATER_BOLT, false);
me->resetAttackTimer();
}
};
me->resetAttackTimer();
}
};
class go_strange_pool : public GameObjectScript
@@ -315,7 +314,7 @@ public:
void AddSC_boss_the_lurker_below()
{
new boss_the_lurker_below();
RegisterSerpentShrineAI(boss_the_lurker_below);
new go_strange_pool();
new spell_lurker_below_spout();
new spell_lurker_below_spout_cone();

View File

@@ -112,7 +112,7 @@ struct boss_morogrim_tidewalker : public BossAI
else
{
Talk(EMOTE_WATERY_GLOBULES);
for (uint8 waterGlobuleId : waterGlobuleIds)
for (uint32 waterGlobuleId : waterGlobuleIds)
{
DoCastSelf(waterGlobuleId, true);
}

View File

@@ -138,7 +138,10 @@ public:
if (Creature* vashj = instance->GetCreature(LadyVashjGUID))
vashj->AI()->JustSummoned(creature);
break;
default:
break;
}
InstanceScript::OnCreatureCreate(creature);
}
ObjectGuid GetGuidData(uint32 identifier) const override

View File

@@ -166,7 +166,7 @@ struct boss_magtheridon : public BossAI
{
me->CastCustomSpell(SPELL_BLAZE, SPELLVALUE_MAX_TARGETS, 1);
context.Repeat(11s, 39s);
}).Schedule(40s, [this](TaskContext context)
}).Schedule(28300ms, [this](TaskContext context)
{
DoCastSelf(SPELL_QUAKE);
_castingQuake = true;
@@ -175,29 +175,33 @@ struct boss_magtheridon : public BossAI
me->SetOrientation(me->GetAngle(me->GetVictim()));
me->SetTarget(ObjectGuid::Empty);
scheduler.DelayAll(6999ms);
scheduler.Schedule(7s, [this](TaskContext /*context*/)
scheduler.Schedule(7s, [this](TaskContext)
{
_castingQuake = false;
me->SetReactState(REACT_AGGRESSIVE);
me->GetMotionMaster()->MoveChase(me->GetVictim());
DoCastSelf(SPELL_BLAST_NOVA);
_interruptScheduler.Schedule(50ms, GROUP_INTERRUPT_CHECK, [this](TaskContext context)
{
if (me->GetAuraCount(SPELL_SHADOW_GRASP_VISUAL) == 5)
{
Talk(SAY_BANISH);
me->InterruptNonMeleeSpells(true);
scheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
}
else
context.Repeat(50ms);
}).Schedule(12s, GROUP_INTERRUPT_CHECK, [this](TaskContext /*context*/)
{
_interruptScheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
});
});
context.Repeat(53s, 56s);
context.Repeat(56300ms, 64300ms);
}).Schedule(55650ms, [this](TaskContext context)
{
DoCastSelf(SPELL_BLAST_NOVA);
scheduler.DelayAll(10s);
_interruptScheduler.Schedule(50ms, GROUP_INTERRUPT_CHECK, [this](TaskContext context)
{
if (me->GetAuraCount(SPELL_SHADOW_GRASP_VISUAL) == 5)
{
Talk(SAY_BANISH);
me->InterruptNonMeleeSpells(true);
scheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
}
else
context.Repeat(50ms);
}).Schedule(12s, GROUP_INTERRUPT_CHECK, [this](TaskContext /*context*/)
{
_interruptScheduler.CancelGroup(GROUP_INTERRUPT_CHECK);
});
context.Repeat(54350ms, 55400ms);
}).Schedule(22min, [this](TaskContext /*context*/)
{
DoCastSelf(SPELL_BERSERK, true);

View File

@@ -443,8 +443,6 @@ public:
GetUnitOwner()->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
GetUnitOwner()->SetStandState(UNIT_STAND_STATE_DEAD);
GetUnitOwner()->m_last_notify_position.Relocate(0.0f, 0.0f, 0.0f);
GetUnitOwner()->m_delayed_unit_relocation_timer = 1000;
}
void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)

View File

@@ -208,7 +208,11 @@ class spell_capacitus_polarity_shift : public SpellScript
void HandleDummy(SpellEffIndex /*effIndex*/)
{
if (Unit* target = GetHitUnit())
{
target->RemoveAurasDueToSpell(SPELL_POSITIVE_CHARGE_STACK);
target->RemoveAurasDueToSpell(SPELL_NEGATIVE_CHARGE_STACK);
target->CastSpell(target, roll_chance_i(50) ? SPELL_POSITIVE_POLARITY : SPELL_NEGATIVE_POLARITY, true, nullptr, nullptr, GetCaster()->GetGUID());
}
}
void Register() override

View File

@@ -731,8 +731,19 @@ public:
## npc_flanis_swiftwing_and_kagrosh
######*/
#define GOSSIP_HSK1 "Take Flanis's Pack"
#define GOSSIP_HSK2 "Take Kagrosh's Pack"
enum Flanis : uint32
{
QUEST_THE_FATE_OF_FLANIS = 10583,
ITEM_FLAUNISS_PACK = 30658,
GOSSIP_MENU_FLANIS = 8356,
};
enum Kagrosh : uint32
{
QUEST_THE_FATE_OF_KAGROSH = 10601,
ITEM_KAGROSHS_PACK = 30659,
GOSSIP_MENU_KAGROSH = 8371,
};
class npcs_flanis_swiftwing_and_kagrosh : public CreatureScript
{
@@ -745,32 +756,33 @@ public:
if (action == GOSSIP_ACTION_INFO_DEF + 1)
{
ItemPosCountVec dest;
uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, 30658, 1, nullptr);
uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, ITEM_FLAUNISS_PACK, 1, nullptr);
if (msg == EQUIP_ERR_OK)
{
player->StoreNewItem(dest, 30658, true);
ClearGossipMenuFor(player);
player->StoreNewItem(dest, ITEM_FLAUNISS_PACK, true);
}
}
if (action == GOSSIP_ACTION_INFO_DEF + 2)
{
ItemPosCountVec dest;
uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, 30659, 1, nullptr);
uint8 msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, ITEM_KAGROSHS_PACK, 1, nullptr);
if (msg == EQUIP_ERR_OK)
{
player->StoreNewItem(dest, 30659, true);
ClearGossipMenuFor(player);
player->StoreNewItem(dest, ITEM_KAGROSHS_PACK, true);
}
}
CloseGossipMenuFor(player);
return true;
}
bool OnGossipHello(Player* player, Creature* creature) override
{
if (player->GetQuestStatus(10583) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(30658, 1, true))
AddGossipItemFor(player, 0, GOSSIP_HSK1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
if (player->GetQuestStatus(10601) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(30659, 1, true))
AddGossipItemFor(player, 0, GOSSIP_HSK2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
if (player->GetQuestStatus(QUEST_THE_FATE_OF_FLANIS) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(ITEM_FLAUNISS_PACK, 1, true))
AddGossipItemFor(player, GOSSIP_MENU_FLANIS, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
if (player->GetQuestStatus(QUEST_THE_FATE_OF_KAGROSH) == QUEST_STATUS_INCOMPLETE && !player->HasItemCount(ITEM_KAGROSHS_PACK, 1, true))
AddGossipItemFor(player, GOSSIP_MENU_KAGROSH, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());
@@ -1734,6 +1746,97 @@ public:
}
};
enum KorWild
{
SAY_LAND = 0,
POINT_LAND = 1
};
class npc_korkron_or_wildhammer : public ScriptedAI
{
public:
npc_korkron_or_wildhammer(Creature* creature) : ScriptedAI(creature)
{
creature->SetDisableGravity(true);
creature->SetHover(true);
}
void Reset() override
{
me->SetReactState(REACT_PASSIVE);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE);
}
void JustDied(Unit* /*killer*/) override
{
me->DespawnOrUnsummon(3s, 0s);
}
void IsSummonedBy(WorldObject* summoner) override
{
_playerGUID = summoner->GetGUID();
me->SetFacingToObject(summoner);
Position pos = summoner->GetPosition();
me->GetMotionMaster()->MovePoint(POINT_LAND, pos);
}
void MovementInform(uint32 type, uint32 id) override
{
if (type == POINT_MOTION_TYPE && id == POINT_LAND)
{
if (Player* player = ObjectAccessor::GetPlayer(*me, _playerGUID))
Talk(SAY_LAND, player);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
}
private:
ObjectGuid _playerGUID;
};
class spell_calling_korkron_or_wildhammer : public SpellScript
{
PrepareSpellScript(spell_calling_korkron_or_wildhammer);
void SetDest(SpellDestination& dest)
{
// Adjust effect summon position
Position const offset = { -14.0f, -14.0f, 16.0f, 0.0f };
dest.RelocateOffset(offset);
}
void Register() override
{
OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_calling_korkron_or_wildhammer::SetDest, EFFECT_0, TARGET_DEST_CASTER);
}
};
enum InfernalOversoul
{
NPC_INFERNAL_OVERSOUL = 21735,
SPELL_DISRUPT_SUMMONING_RITUAL = 37285
};
class spell_disrupt_summoning_ritual : public SpellScript
{
public:
PrepareSpellScript(spell_disrupt_summoning_ritual);
SpellCastResult CheckRequirement()
{
if (Unit* caster = GetCaster())
if (Creature* infernal = caster->FindNearestCreature(NPC_INFERNAL_OVERSOUL, 100.0f))
if (!infernal->HasAura(SPELL_DISRUPT_SUMMONING_RITUAL))
return SPELL_FAILED_CASTER_AURASTATE;
return SPELL_CAST_OK;
}
void Register() override
{
OnCheckCast += SpellCheckCastFn(spell_disrupt_summoning_ritual::CheckRequirement);
}
};
void AddSC_shadowmoon_valley()
{
// Ours
@@ -1755,4 +1858,7 @@ void AddSC_shadowmoon_valley()
new npc_torloth_the_magnificent();
new npc_enraged_spirit();
new npc_shadowmoon_tuber_node();
RegisterCreatureAI(npc_korkron_or_wildhammer);
RegisterSpellScript(spell_calling_korkron_or_wildhammer);
RegisterSpellScript(spell_disrupt_summoning_ritual);
}

View File

@@ -85,7 +85,11 @@ public:
# npc_zephyr
######*/
#define GOSSIP_HZ "Take me to the Caverns of Time."
enum Zephyr : int32
{
GOSSIP_MENU_ZEPHYR = 9205,
SPELL_TELEPORT_CAVERNS_OF_TIME = 37778,
};
class npc_zephyr : public CreatureScript
{
@@ -96,7 +100,7 @@ public:
{
ClearGossipMenuFor(player);
if (action == GOSSIP_ACTION_INFO_DEF + 1)
player->CastSpell(player, 37778, false);
player->CastSpell(player, SPELL_TELEPORT_CAVERNS_OF_TIME, false);
return true;
}
@@ -104,7 +108,7 @@ public:
bool OnGossipHello(Player* player, Creature* creature) override
{
if (player->GetReputationRank(989) >= REP_REVERED)
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_HZ, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
AddGossipItemFor(player, GOSSIP_MENU_ZEPHYR, 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
SendGossipMenuFor(player, player->GetGossipTextId(creature), creature->GetGUID());

View File

@@ -575,10 +575,25 @@ public:
/*######
## go_skull_pile
######*/
#define GOSSIP_S_DARKSCREECHER_AKKARAI "Summon Darkscreecher Akkarai"
#define GOSSIP_S_KARROG "Summon Karrog"
#define GOSSIP_S_GEZZARAK_THE_HUNTRESS "Summon Gezzarak the Huntress"
#define GOSSIP_S_VAKKIZ_THE_WINDRAGER "Summon Vakkiz the Windrager"
enum SkullPile : uint32
{
QUEST_ADVERSARIAL_BLOOD = 11885,
GOSSIP_MENU_SKULL_PILE = 8660,
GOSSIP_MENU_TEXT_SKULL_PILE = 10888,
GOSSIP_MENU_TEXT_SKULL_PILE_QUEST = 11057,
GOSSIP_OPTION_SUMMON_GEZZARAK_THE_HUNTRESS = 0,
GOSSIP_OPTION_SUMMON_DARKSCREECHER_AKKARAI = 1,
GOSSIP_OPTION_SUMMON_KARROG = 2,
GOSSIP_OPTION_SUMMON_VAKKIZ_THE_WINDRAGER = 3,
SPELL_SUMMON_GEZZARAK_THE_HUNTRESS = 40632,
SPELL_SUMMON_DARKSCREECHER_AKKARAI = 40642,
SPELL_SUMMON_KARROG = 40640,
SPELL_SUMMON_VAKKIZ_THE_WINDRAGER = 40644,
};
class go_skull_pile : public GameObjectScript
{
@@ -588,26 +603,29 @@ public:
bool OnGossipSelect(Player* player, GameObject* go, uint32 sender, uint32 action) override
{
ClearGossipMenuFor(player);
switch (sender)
if (sender == GOSSIP_SENDER_MAIN)
{
case GOSSIP_SENDER_MAIN:
SendActionMenu(player, go, action);
break;
SendActionMenu(player, go, action);
CloseGossipMenuFor(player);
}
return true;
}
bool OnGossipHello(Player* player, GameObject* go) override
{
if ((player->GetQuestStatus(11885) == QUEST_STATUS_INCOMPLETE) || player->GetQuestRewardStatus(11885))
if ((player->GetQuestStatus(QUEST_ADVERSARIAL_BLOOD) == QUEST_STATUS_INCOMPLETE) || player->GetQuestRewardStatus(QUEST_ADVERSARIAL_BLOOD))
{
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_S_DARKSCREECHER_AKKARAI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_S_KARROG, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_S_GEZZARAK_THE_HUNTRESS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GOSSIP_S_VAKKIZ_THE_WINDRAGER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4);
}
AddGossipItemFor(player, GOSSIP_MENU_SKULL_PILE, GOSSIP_OPTION_SUMMON_GEZZARAK_THE_HUNTRESS, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1);
AddGossipItemFor(player, GOSSIP_MENU_SKULL_PILE, GOSSIP_OPTION_SUMMON_DARKSCREECHER_AKKARAI, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 2);
AddGossipItemFor(player, GOSSIP_MENU_SKULL_PILE, GOSSIP_OPTION_SUMMON_KARROG, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 3);
AddGossipItemFor(player, GOSSIP_MENU_SKULL_PILE, GOSSIP_OPTION_SUMMON_VAKKIZ_THE_WINDRAGER, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 4);
SendGossipMenuFor(player, GOSSIP_MENU_TEXT_SKULL_PILE_QUEST, go->GetGUID());
}
else
SendGossipMenuFor(player, GOSSIP_MENU_TEXT_SKULL_PILE, go->GetGUID());
SendGossipMenuFor(player, go->GetGOInfo()->questgiver.gossipID, go->GetGUID());
return true;
}
@@ -616,16 +634,16 @@ public:
switch (action)
{
case GOSSIP_ACTION_INFO_DEF + 1:
player->CastSpell(player, 40642, false);
player->CastSpell(player, SPELL_SUMMON_GEZZARAK_THE_HUNTRESS, false);
break;
case GOSSIP_ACTION_INFO_DEF + 2:
player->CastSpell(player, 40640, false);
player->CastSpell(player, SPELL_SUMMON_DARKSCREECHER_AKKARAI, false);
break;
case GOSSIP_ACTION_INFO_DEF + 3:
player->CastSpell(player, 40632, false);
player->CastSpell(player, SPELL_SUMMON_KARROG, false);
break;
case GOSSIP_ACTION_INFO_DEF + 4:
player->CastSpell(player, 40644, false);
player->CastSpell(player, SPELL_SUMMON_VAKKIZ_THE_WINDRAGER, false);
break;
}
}

View File

@@ -410,6 +410,26 @@ class spell_dru_dash : public SpellScript
}
};
// -1850 - Dash
class spell_dru_dash_aura : public AuraScript
{
PrepareAuraScript(spell_dru_dash_aura);
void CalculateAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
// do not set speed if not in cat form
if (GetUnitOwner()->GetShapeshiftForm() != FORM_CAT)
{
amount = 0;
}
}
void Register() override
{
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_dru_dash_aura::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_INCREASE_SPEED);
}
};
// 5229 - Enrage
class spell_dru_enrage : public AuraScript
{
@@ -1185,7 +1205,7 @@ void AddSC_druid_spell_scripts()
RegisterSpellScript(spell_dru_barkskin);
RegisterSpellScript(spell_dru_treant_scaling);
RegisterSpellScript(spell_dru_berserk);
RegisterSpellScript(spell_dru_dash);
RegisterSpellAndAuraScriptPair(spell_dru_dash, spell_dru_dash_aura);
RegisterSpellScript(spell_dru_enrage);
RegisterSpellScript(spell_dru_glyph_of_starfire);
RegisterSpellScript(spell_dru_idol_lifebloom);

View File

@@ -4997,6 +4997,111 @@ class spell_gen_spirit_of_competition_winner : public SpellScript
}
};
// 27360 - Lord Valthalak's Amulet
enum Valthalak
{
SPELL_INSTILL_LORD_VALTHALAK_SPIRIT = 27360,
NPC_LORD_VALTHALAK = 16042
};
class spell_gen_valthalak_amulet : public SpellScript
{
PrepareSpellScript(spell_gen_valthalak_amulet)
SpellCastResult CheckCast()
{
if (Unit* target = GetExplTargetUnit())
if (target->GetEntry() == NPC_LORD_VALTHALAK && target->isDead())
return SPELL_CAST_OK;
return SPELL_FAILED_BAD_TARGETS;
}
void Register() override
{
OnCheckCast += SpellCheckCastFn(spell_gen_valthalak_amulet::CheckCast);
}
};
enum ScourgeBanner
{
GO_COMMAND_TENT = 176210,
};
class spell_gen_planting_scourge_banner : public SpellScript
{
PrepareSpellScript(spell_gen_planting_scourge_banner)
SpellCastResult CheckCast()
{
if (GameObject* tent = GetCaster()->FindNearestGameObject(GO_COMMAND_TENT, 20.0f))
if (tent->GetGoState() != GO_STATE_READY) // If tent is burned down
return SPELL_CAST_OK;
return SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW;
}
void Register() override
{
OnCheckCast += SpellCheckCastFn(spell_gen_planting_scourge_banner::CheckCast);
}
};
enum Jubling
{
SPELL_JUBLING_COOLDOWN_1_WEEK = 23852
};
// 23853 - Jubling Cooldown
class spell_gen_jubling_cooldown : public SpellScript
{
PrepareSpellScript(spell_gen_jubling_cooldown);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_JUBLING_COOLDOWN_1_WEEK });
}
void HandleScript(SpellEffIndex /*effIndex*/)
{
if (Player* target = GetHitPlayer())
{
target->CastSpell(target, SPELL_JUBLING_COOLDOWN_1_WEEK); // 1 week
}
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_gen_jubling_cooldown::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
}
};
// 12699 - Yeh'kinya's Bramble
enum YehkinyaBramble
{
NPC_VALE_SCREECHER = 5307,
NPC_ROGUE_VALE_SCREECHER = 5308
};
class spell_gen_yehkinya_bramble : public SpellScript
{
PrepareSpellScript(spell_gen_yehkinya_bramble)
SpellCastResult CheckCast()
{
if (Unit* target = GetExplTargetUnit())
if ((target->GetEntry() == NPC_VALE_SCREECHER || target->GetEntry() == NPC_ROGUE_VALE_SCREECHER) && target->isDead())
return SPELL_CAST_OK;
return SPELL_FAILED_BAD_TARGETS;
}
void Register() override
{
OnCheckCast += SpellCheckCastFn(spell_gen_yehkinya_bramble::CheckCast);
}
};
void AddSC_generic_spell_scripts()
{
RegisterSpellScript(spell_silithyst);
@@ -5145,4 +5250,8 @@ void AddSC_generic_spell_scripts()
RegisterSpellScript(spell_gen_curse_of_pain);
RegisterSpellScript(spell_gen_spirit_of_competition_participant);
RegisterSpellScript(spell_gen_spirit_of_competition_winner);
RegisterSpellScript(spell_gen_valthalak_amulet);
RegisterSpellScript(spell_gen_planting_scourge_banner);
RegisterSpellScript(spell_gen_jubling_cooldown);
RegisterSpellScript(spell_gen_yehkinya_bramble);
}

View File

@@ -69,7 +69,8 @@ enum HunterSpells
SPELL_DRAENEI_GIFT_OF_THE_NAARU = 59543,
SPELL_HUNTER_GLYPH_OF_ARCANE_SHOT = 61389,
SPELL_LOCK_AND_LOAD_TRIGGER = 56453,
SPELL_LOCK_AND_LOAD_MARKER = 67544
SPELL_LOCK_AND_LOAD_MARKER = 67544,
SPELL_HUNTER_PET_LEGGINGS_OF_BEAST_MASTERY = 38297, // Leggings of Beast Mastery
};
class spell_hun_check_pet_los : public SpellScript
@@ -165,6 +166,10 @@ class spell_hun_generic_scaling : public AuraScript
SpellSchoolMask schoolMask = SpellSchoolMask(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue);
int32 modifier = schoolMask == SPELL_SCHOOL_MASK_NORMAL ? 35 : 40;
amount = CalculatePct(std::max<int32>(0, owner->GetResistance(schoolMask)), modifier);
if (owner->HasAura(SPELL_HUNTER_PET_LEGGINGS_OF_BEAST_MASTERY) && schoolMask == SPELL_SCHOOL_MASK_NORMAL)
{
amount += 490;
}
}
}
@@ -180,6 +185,10 @@ class spell_hun_generic_scaling : public AuraScript
AddPct(modifier, wildHuntEff->GetAmount());
amount = CalculatePct(std::max<int32>(0, owner->GetStat(Stats(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue))), modifier);
if (owner->HasAura(SPELL_HUNTER_PET_LEGGINGS_OF_BEAST_MASTERY))
{
amount += 52;
}
}
}
@@ -201,6 +210,10 @@ class spell_hun_generic_scaling : public AuraScript
ownerAP += CalculatePct(owner->GetStat(STAT_STAMINA), HvWEff->GetAmount());
amount = CalculatePct(std::max<int32>(0, ownerAP), modifier);
if (owner->HasAura(SPELL_HUNTER_PET_LEGGINGS_OF_BEAST_MASTERY))
{
amount += 70;
}
}
}
@@ -1308,9 +1321,11 @@ class spell_hun_bestial_wrath : public SpellScript
}
};
class spell_hun_furious_howl : public SpellScript
// -24604 - Furious Howl
// 53434 - Call of the Wild
class spell_hun_target_self_and_pet : public SpellScript
{
PrepareSpellScript(spell_hun_furious_howl);
PrepareSpellScript(spell_hun_target_self_and_pet);
bool Load() override
{
@@ -1327,7 +1342,7 @@ class spell_hun_furious_howl : public SpellScript
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hun_furious_howl::FilterTargets, EFFECT_ALL, TARGET_UNIT_CASTER_AREA_PARTY);
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_hun_target_self_and_pet::FilterTargets, EFFECT_ALL, TARGET_UNIT_CASTER_AREA_PARTY);
}
};
@@ -1361,5 +1376,5 @@ void AddSC_hunter_spell_scripts()
RegisterSpellScript(spell_hun_lock_and_load);
RegisterSpellScript(spell_hun_intimidation);
RegisterSpellScript(spell_hun_bestial_wrath);
RegisterSpellScript(spell_hun_furious_howl);
RegisterSpellScript(spell_hun_target_self_and_pet);
}

View File

@@ -3883,6 +3883,64 @@ class spell_item_worn_troll_dice : public SpellScript
}
};
enum VenomhideHatchling
{
NPC_VENOMHIDE_HATCHLING = 34320
};
class spell_item_venomhide_feed : public SpellScript
{
PrepareSpellScript(spell_item_venomhide_feed)
SpellCastResult CheckCast()
{
if (Player* player = GetCaster()->ToPlayer())
{
std::list<Creature*> hatchling;
player->GetAllMinionsByEntry(hatchling, NPC_VENOMHIDE_HATCHLING);
if (!hatchling.empty())
{
return SPELL_CAST_OK;
}
}
return SPELL_FAILED_BAD_TARGETS;
}
void UpdateTarget(WorldObject*& target)
{
if (!target)
{
return;
}
if (Player* player = GetCaster()->ToPlayer())
{
std::list<Creature*> hatchling;
player->GetAllMinionsByEntry(hatchling, NPC_VENOMHIDE_HATCHLING);
if (hatchling.empty())
{
return;
}
for (Creature* creature : hatchling)
{
if (creature)
{
target = creature;
return;
}
}
}
}
void Register() override
{
OnCheckCast += SpellCheckCastFn(spell_item_venomhide_feed::CheckCast);
OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_item_venomhide_feed::UpdateTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY);
}
};
void AddSC_item_spell_scripts()
{
RegisterSpellScript(spell_item_massive_seaforium_charge);
@@ -4003,4 +4061,5 @@ void AddSC_item_spell_scripts()
RegisterSpellScript(spell_item_green_whelp_armor);
RegisterSpellScript(spell_item_elixir_of_shadows);
RegisterSpellScript(spell_item_worn_troll_dice);
RegisterSpellScript(spell_item_venomhide_feed);
}

View File

@@ -80,6 +80,12 @@ enum PaladinSpells
SPELL_PALADIN_SANCTIFIED_RETRIBUTION_AURA = 63531,
SPELL_PALADIN_AURA_MASTERY_IMMUNE = 64364,
SPELL_JUDGEMENTS_OF_THE_JUST = 68055,
SPELL_JUDGEMENT_OF_VENGEANCE_EFFECT = 31804,
SPELL_HOLY_VENGEANCE = 31803,
SPELL_JUDGEMENT_OF_CORRUPTION_EFFECT = 53733,
SPELL_BLOOD_CORRUPTION = 53742,
SPELL_GENERIC_ARENA_DAMPENING = 74410,
SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411
};
@@ -874,7 +880,26 @@ public:
// Judgement of the Just
if (GetCaster()->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_PALADIN, 3015, 0))
GetCaster()->CastSpell(GetHitUnit(), 68055, true);
{
if (GetCaster()->CastSpell(GetHitUnit(), SPELL_JUDGEMENTS_OF_THE_JUST, true) && (spellId2 == SPELL_JUDGEMENT_OF_VENGEANCE_EFFECT || spellId2 == SPELL_JUDGEMENT_OF_CORRUPTION_EFFECT))
{
//hidden effect only cast when spellcast of judgements of the just is succesful
GetCaster()->CastSpell(GetHitUnit(), SealApplication(spellId2), true); //add hidden seal apply effect for vengeance and corruption
}
}
}
uint32 SealApplication(uint32 correspondingSpellId)
{
switch (correspondingSpellId)
{
case SPELL_JUDGEMENT_OF_VENGEANCE_EFFECT:
return SPELL_HOLY_VENGEANCE;
case SPELL_JUDGEMENT_OF_CORRUPTION_EFFECT:
return SPELL_BLOOD_CORRUPTION;
default:
return 0;
}
}
void Register() override

View File

@@ -48,6 +48,7 @@ enum PriestSpells
SPELL_PRIEST_SHADOW_WORD_DEATH = 32409,
SPELL_PRIEST_T9_HEALING_2P = 67201,
SPELL_PRIEST_VAMPIRIC_TOUCH_DISPEL = 64085,
SPELL_PRIEST_T4_4P_FLEXIBILITY = 37565,
SPELL_GENERIC_ARENA_DAMPENING = 74410,
SPELL_GENERIC_BATTLEGROUND_DAMPENING = 74411,
@@ -926,6 +927,28 @@ class spell_pri_mind_control : public AuraScript
}
};
// 37565 - Flexibility | Item - Priest T4 Holy/Discipline 4P Bonus
class spell_pri_t4_4p_bonus : public AuraScript
{
PrepareAuraScript(spell_pri_t4_4p_bonus);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_PRIEST_T4_4P_FLEXIBILITY });
}
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
{
PreventDefaultAction();
GetTarget()->RemoveAurasDueToSpell(SPELL_PRIEST_T4_4P_FLEXIBILITY);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_pri_t4_4p_bonus::HandleProc, EFFECT_ALL, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
}
};
void AddSC_priest_spell_scripts()
{
RegisterSpellScript(spell_pri_shadowfiend_scaling);
@@ -949,4 +972,5 @@ void AddSC_priest_spell_scripts()
RegisterSpellScript(spell_pri_shadow_word_death);
RegisterSpellScript(spell_pri_vampiric_touch);
RegisterSpellScript(spell_pri_mind_control);
RegisterSpellScript(spell_pri_t4_4p_bonus);
}

View File

@@ -37,6 +37,7 @@ enum ShamanSpells
SPELL_SHAMAN_CLEANSING_TOTEM_EFFECT = 52025,
SPELL_SHAMAN_EARTH_SHIELD_HEAL = 379,
SPELL_SHAMAN_ELEMENTAL_MASTERY = 16166,
SPELL_SHAMAN_ELECTRIFIED = 64930,
SPELL_SHAMAN_EXHAUSTION = 57723,
SPELL_SHAMAN_FIRE_NOVA_R1 = 1535,
SPELL_SHAMAN_FIRE_NOVA_TRIGGERED_R1 = 8349,
@@ -59,7 +60,8 @@ enum ShamanSpells
SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL = 52042,
SPELL_SHAMAN_BLESSING_OF_THE_ETERNALS_R1 = 51554,
SPELL_SHAMAN_STORMSTRIKE = 17364,
SPELL_SHAMAN_LAVA_LASH = 60103
SPELL_SHAMAN_LAVA_LASH = 60103,
SPELL_SHAMAN_LIGHTNING_BOLT_OVERLOAD = 45284,
};
enum ShamanSpellIcons
@@ -1104,6 +1106,45 @@ class spell_sha_flurry_proc : public AuraScript
}
};
// 64928 - Item - Shaman T8 Elemental 4P Bonus
class spell_sha_t8_electrified : public AuraScript
{
PrepareAuraScript(spell_sha_t8_electrified);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SHAMAN_ELECTRIFIED });
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)
{
PreventDefaultAction();
DamageInfo* damageInfo = eventInfo.GetDamageInfo();
if (!damageInfo || !damageInfo->GetDamage())
return;
// Do not proc from Lightning Overload (patch 3.1~)
if (SpellInfo const* spellInfo = eventInfo.GetSpellInfo())
{
if (spellInfo->Id == SPELL_SHAMAN_LIGHTNING_BOLT_OVERLOAD)
{
return;
}
}
SpellInfo const* electrifiedDot = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_ELECTRIFIED);
int32 amount = int32(CalculatePct(eventInfo.GetDamageInfo()->GetDamage(), aurEff->GetAmount()) / electrifiedDot->GetMaxTicks());
eventInfo.GetProcTarget()->CastDelayedSpellWithPeriodicAmount(eventInfo.GetActor(), SPELL_SHAMAN_ELECTRIFIED, SPELL_AURA_PERIODIC_DAMAGE, amount);
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_sha_t8_electrified::HandleProc, EFFECT_0, SPELL_AURA_DUMMY);
}
};
void AddSC_shaman_spell_scripts()
{
RegisterSpellScript(spell_sha_totem_of_wrath);
@@ -1135,4 +1176,5 @@ void AddSC_shaman_spell_scripts()
RegisterSpellScript(spell_sha_sentry_totem);
RegisterSpellScript(spell_sha_thunderstorm);
RegisterSpellScript(spell_sha_flurry_proc);
RegisterSpellScript(spell_sha_t8_electrified);
}

View File

@@ -63,7 +63,8 @@ enum WarlockSpells
SPELL_WARLOCK_UNSTABLE_AFFLICTION_DISPEL = 31117,
SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_R1 = 18213,
SPELL_WARLOCK_IMPROVED_DRAIN_SOUL_PROC = 18371,
SPELL_WARLOCK_EYE_OF_KILROGG_FLY = 58083
SPELL_WARLOCK_EYE_OF_KILROGG_FLY = 58083,
SPELL_WARLOCK_PET_VOID_STAR_TALISMAN = 37386, // Void Star Talisman
};
enum WarlockSpellIcons
@@ -242,6 +243,7 @@ class spell_warl_demonic_aegis : public AuraScript
}
};
// -35696 - Demonic Knowledge
class spell_warl_demonic_knowledge : public AuraScript
{
PrepareAuraScript(spell_warl_demonic_knowledge);
@@ -249,7 +251,10 @@ class spell_warl_demonic_knowledge : public AuraScript
void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/)
{
if (Unit* caster = GetCaster())
amount = CalculatePct(caster->GetStat(STAT_STAMINA) + caster->GetStat(STAT_INTELLECT), aurEff->GetBaseAmount());
{
uint8 pct = aurEff->GetBaseAmount() + aurEff->GetDieSides();
amount = CalculatePct(caster->GetStat(STAT_STAMINA) + caster->GetStat(STAT_INTELLECT), pct);
}
}
void CalcPeriodic(AuraEffect const* /*aurEff*/, bool& isPeriodic, int32& amplitude)
@@ -284,6 +289,11 @@ class spell_warl_generic_scaling : public AuraScript
SpellSchoolMask schoolMask = SpellSchoolMask(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue);
int32 modifier = schoolMask == SPELL_SCHOOL_MASK_NORMAL ? 35 : 40;
amount = CalculatePct(std::max<int32>(0, owner->GetResistance(schoolMask)), modifier);
if (owner->HasAura(SPELL_WARLOCK_PET_VOID_STAR_TALISMAN) && schoolMask != SPELL_SCHOOL_MASK_NORMAL)
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_WARLOCK_PET_VOID_STAR_TALISMAN);
amount += spellInfo->Effects[EFFECT_0].CalcValue(); // 130
}
}
}
@@ -390,6 +400,11 @@ class spell_warl_infernal_scaling : public AuraScript
SpellSchoolMask schoolMask = SpellSchoolMask(aurEff->GetSpellInfo()->Effects[aurEff->GetEffIndex()].MiscValue);
int32 modifier = schoolMask == SPELL_SCHOOL_MASK_NORMAL ? 35 : 40;
amount = CalculatePct(std::max<int32>(0, owner->GetResistance(schoolMask)), modifier);
if (owner->HasAura(SPELL_WARLOCK_PET_VOID_STAR_TALISMAN) && schoolMask != SPELL_SCHOOL_MASK_NORMAL)
{
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(SPELL_WARLOCK_PET_VOID_STAR_TALISMAN);
amount += spellInfo->Effects[EFFECT_0].CalcValue(); // 130
}
}
}

View File

@@ -15,34 +15,8 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* ContentData
go_cat_figurine (the "trap" version of GO, two different exist)
go_barov_journal
go_ethereum_prison
go_ethereum_stasis
go_sacred_fire_of_life
go_shrine_of_the_birds
go_southfury_moonstone
go_resonite_cask
go_tablet_of_the_seven
go_tele_to_dalaran_crystal
go_tele_to_violet_stand
go_scourge_cage
go_jotunheim_cage
go_table_theka
go_soulwell
go_bashir_crystalforge
go_soulwell
go_dragonflayer_cage
go_tadpole_cage
go_amberpine_outhouse
go_hive_pod
go_veil_skith_cage
EndContentData */
#include "CellImpl.h"
#include "GameObjectAI.h"
#include "GameTime.h"
#include "GridNotifiersImpl.h"
#include "Player.h"
#include "ScriptMgr.h"
@@ -1385,41 +1359,6 @@ public:
}
};
/*######
## go_inconspicuous_landmark
######*/
enum InconspicuousLandmark
{
SPELL_SUMMON_PIRATES_TREASURE_AND_TRIGGER_MOB = 11462,
ITEM_CUERGOS_KEY = 9275,
};
class go_inconspicuous_landmark : public GameObjectScript
{
public:
go_inconspicuous_landmark() : GameObjectScript("go_inconspicuous_landmark")
{
_lastUsedTime = GameTime::GetGameTime().count();
}
bool OnGossipHello(Player* player, GameObject* /*go*/) override
{
if (player->HasItemCount(ITEM_CUERGOS_KEY))
return true;
if (_lastUsedTime > GameTime::GetGameTime().count())
return true;
_lastUsedTime = GameTime::GetGameTime().count() + MINUTE;
player->CastSpell(player, SPELL_SUMMON_PIRATES_TREASURE_AND_TRIGGER_MOB, true);
return true;
}
private:
uint32 _lastUsedTime;
};
/*######
## go_soulwell
######*/
@@ -1989,7 +1928,6 @@ void AddSC_go_scripts()
new go_arcane_prison();
new go_jotunheim_cage();
new go_table_theka();
new go_inconspicuous_landmark();
new go_soulwell();
new go_dragonflayer_cage();
new go_amberpine_outhouse();

View File

@@ -2506,9 +2506,9 @@ enum VenomhideHatchlingMisc
ITEM_VENOMHIDE_BABY_TOOTH = 47196,
MODEL_BABY_RAPTOR = 29251,
MODEL_BABY_RAPTOR_REPTILE_EYES = 29809,
MODEL_ADOLESCENT_RAPTOR = 29103,
MODEL_FULL_RAPTOR = 5291,
MODEL_BABY_RAPTOR_REPTILE_EYES = 29274,
MODEL_ADOLESCENT_RAPTOR = 29275,
MODEL_FULL_RAPTOR = 29276,
};
enum VenomhideHatchlingTexts