diff options
Diffstat (limited to 'src/server/scripts')
13 files changed, 1895 insertions, 1023 deletions
diff --git a/src/server/scripts/Commands/CMakeLists.txt b/src/server/scripts/Commands/CMakeLists.txt index 15e16c2caf1..ce31fa1f4d3 100644 --- a/src/server/scripts/Commands/CMakeLists.txt +++ b/src/server/scripts/Commands/CMakeLists.txt @@ -12,6 +12,7 @@ set(scripts_STAT_SRCS ${scripts_STAT_SRCS} Commands/cs_account.cpp Commands/cs_achievement.cpp + Commands/cs_arena.cpp Commands/cs_ban.cpp Commands/cs_bf.cpp Commands/cs_cast.cpp diff --git a/src/server/scripts/Commands/cs_arena.cpp b/src/server/scripts/Commands/cs_arena.cpp new file mode 100644 index 00000000000..82a1109efd2 --- /dev/null +++ b/src/server/scripts/Commands/cs_arena.cpp @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* ScriptData +Name: arena_commandscript +%Complete: 100 +Comment: All arena team related commands +Category: commandscripts +EndScriptData */ + +#include "ObjectMgr.h" +#include "Chat.h" +#include "Language.h" +#include "ArenaTeamMgr.h" +#include "Player.h" +#include "ScriptMgr.h" + +class arena_commandscript : public CommandScript +{ +public: + arena_commandscript() : CommandScript("arena_commandscript") { } + + ChatCommand* GetCommands() const + { + static ChatCommand arenaCommandTable[] = + { + { "create", SEC_ADMINISTRATOR, true, &HandleArenaCreateCommand, "", NULL }, + { "disband", SEC_ADMINISTRATOR, true, &HandleArenaDisbandCommand, "", NULL }, + { "rename", SEC_ADMINISTRATOR, true, &HandleArenaRenameCommand, "", NULL }, + { "captain", SEC_ADMINISTRATOR, false, &HandleArenaCaptainCommand, "", NULL }, + { "info", SEC_GAMEMASTER, true, &HandleArenaInfoCommand, "", NULL }, + { "lookup", SEC_GAMEMASTER, false, &HandleArenaLookupCommand, "", NULL }, + { NULL, SEC_GAMEMASTER, false, NULL, "", NULL } + }; + static ChatCommand commandTable[] = + { + { "arena", SEC_GAMEMASTER, false, NULL, "", arenaCommandTable }, + { NULL, SEC_PLAYER, false, NULL, "", NULL } + }; + return commandTable; + } + + static bool HandleArenaCreateCommand(ChatHandler* handler, char const* args) + { + if (!*args) + return false; + + Player* target; + if (!handler->extractPlayerTarget(*args != '"' ? (char*)args : NULL, &target)) + return false; + + char* tailStr = *args != '"' ? strtok(NULL, "") : (char*)args; + if (!tailStr) + return false; + + char* name = handler->extractQuotedArg(tailStr); + if (!name) + return false; + char* typeStr = strtok(NULL, ""); + if (!typeStr) + return false; + int8 type = atoi(typeStr); + if (sArenaTeamMgr->GetArenaTeamByName(name)) + { + handler->PSendSysMessage(LANG_ARENA_ERROR_NAME_EXISTS, name); + handler->SetSentErrorMessage(true); + return false; + } + + if (type == 2 || type == 3 || type == 5 ) + { + if (Player::GetArenaTeamIdFromDB(target->GetGUID(), type) != 0) + { + handler->PSendSysMessage(LANG_ARENA_ERROR_SIZE, target->GetName().c_str()); + handler->SetSentErrorMessage(true); + return false; + } + + ArenaTeam* Arena = new ArenaTeam(); + + if (!Arena->Create(target->GetGUID(), type, name, 4293102085, 101, 4293253939, 4, 4284049911)) + { + delete Arena; + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + + sArenaTeamMgr->AddArenaTeam(Arena); + handler->PSendSysMessage(LANG_ARENA_CREATE, Arena->GetName().c_str(), Arena->GetId(), Arena->GetType(), Arena->GetCaptain()); + } + else + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + return true; + } + + static bool HandleArenaDisbandCommand(ChatHandler* handler, char const* args) + { + if (!*args) + return false; + + uint32 teamId = atoi((char*)args); + if (!teamId) + return false; + + ArenaTeam* Arena = sArenaTeamMgr->GetArenaTeamById(teamId); + + if (!Arena) + { + handler->PSendSysMessage(LANG_ARENA_ERROR_NOT_FOUND, teamId); + handler->SetSentErrorMessage(true); + return false; + } + + if (Arena->IsFighting()) + { + handler->SendSysMessage(LANG_ARENA_ERROR_COMBAT); + handler->SetSentErrorMessage(true); + return false; + } + std::string name = Arena->GetName(); + Arena->Disband(); + if (handler->GetSession()) + TC_LOG_DEBUG(LOG_FILTER_ARENAS, "GameMaster: %s [GUID: %u] disbanded arena team type: %u [Id: %u].", + handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow(), Arena->GetType(), teamId); + else + TC_LOG_DEBUG(LOG_FILTER_ARENAS, "Console: disbanded arena team type: %u [Id: %u].", Arena->GetType(), teamId); + delete(Arena); + handler->PSendSysMessage(LANG_ARENA_DISBAND, name.c_str(), teamId); + return true; + } + + static bool HandleArenaRenameCommand(ChatHandler* handler, char const* _args) + { + if (!*_args) + return false; + + char* args = (char *)_args; + + char const* oldArenaStr = handler->extractQuotedArg(args); + if (!oldArenaStr) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + + char const* newArenaStr = handler->extractQuotedArg(strtok(NULL, "")); + if (!newArenaStr) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + + ArenaTeam* Arena = sArenaTeamMgr->GetArenaTeamByName(oldArenaStr); + if (!Arena) + { + handler->PSendSysMessage(LANG_AREAN_ERROR_NAME_NOT_FOUND, oldArenaStr); + handler->SetSentErrorMessage(true); + return false; + } + + if (sArenaTeamMgr->GetArenaTeamByName(newArenaStr)) + { + handler->PSendSysMessage(LANG_ARENA_ERROR_NAME_EXISTS, oldArenaStr); + handler->SetSentErrorMessage(true); + return false; + } + + if (Arena->IsFighting()) + { + handler->SendSysMessage(LANG_ARENA_ERROR_COMBAT); + handler->SetSentErrorMessage(true); + return false; + } + + if (!Arena->SetName(newArenaStr)) + { + handler->SendSysMessage(LANG_BAD_VALUE); + handler->SetSentErrorMessage(true); + return false; + } + handler->PSendSysMessage(LANG_ARENA_RENAME, Arena->GetId(), oldArenaStr, newArenaStr); + if (handler->GetSession()) + TC_LOG_DEBUG(LOG_FILTER_ARENAS, "GameMaster: %s [GUID: %u] rename arena team \"%s\"[Id: %u] to \"%s\"", + handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow(), oldArenaStr, Arena->GetId(), newArenaStr); + else + TC_LOG_DEBUG(LOG_FILTER_ARENAS, "Console: rename arena team \"%s\"[Id: %u] to \"%s\"", oldArenaStr, Arena->GetId(), newArenaStr); + return true; + } + + static bool HandleArenaCaptainCommand(ChatHandler* handler, char const* args) + { + if (!*args) + return false; + + char* idStr; + char* nameStr; + handler->extractOptFirstArg((char*)args, &idStr, &nameStr); + if (!idStr) + return false; + + uint32 teamId = atoi(idStr); + if (!teamId) + return false; + + Player* target; + uint64 targetGuid; + if (!handler->extractPlayerTarget(nameStr, &target, &targetGuid)) + return false; + + ArenaTeam* Arena = sArenaTeamMgr->GetArenaTeamById(teamId); + + if (!Arena) + { + handler->PSendSysMessage(LANG_ARENA_ERROR_NOT_FOUND, teamId); + handler->SetSentErrorMessage(true); + return false; + } + + if (!target) + { + handler->PSendSysMessage(LANG_PLAYER_NOT_EXIST_OR_OFFLINE, nameStr); + handler->SetSentErrorMessage(true); + return false; + } + + if (Arena->IsFighting()) + { + handler->SendSysMessage(LANG_ARENA_ERROR_COMBAT); + handler->SetSentErrorMessage(true); + return false; + } + + if (!Arena->IsMember(targetGuid)) + { + handler->PSendSysMessage(LANG_ARENA_ERROR_NOT_MEMBER, nameStr, Arena->GetName().c_str()); + handler->SetSentErrorMessage(true); + return false; + } + + if (Arena->GetCaptain() == targetGuid) + { + handler->PSendSysMessage(LANG_ARENA_ERROR_CAPTAIN, nameStr, Arena->GetName().c_str()); + handler->SetSentErrorMessage(true); + return false; + } + + Player* oldCaptain = sObjectMgr->GetPlayerByLowGUID(Arena->GetCaptain()); + Arena->SetCaptain(targetGuid); + handler->PSendSysMessage(LANG_ARENA_CAPTAIN, Arena->GetName().c_str(), Arena->GetId(), oldCaptain->GetName().c_str(), target->GetName().c_str()); + if (handler->GetSession()) + TC_LOG_DEBUG(LOG_FILTER_ARENAS, "GameMaster: %s [GUID: %u] promoted player: %s [GUID: %u] to leader of arena team \"%s\"[Id: %u]", + handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow(), target->GetName().c_str(), target->GetGUIDLow(), Arena->GetName().c_str(), Arena->GetId()); + else + TC_LOG_DEBUG(LOG_FILTER_ARENAS, "Console: promoted player: %s [GUID: %u] to leader of arena team \"%s\"[Id: %u]", + target->GetName().c_str(), target->GetGUIDLow(), Arena->GetName().c_str(), Arena->GetId()); + return true; + } + + static bool HandleArenaInfoCommand(ChatHandler* handler, char const* args) + { + if (!*args) + return false; + + uint32 teamId = atoi((char*)args); + if (!teamId) + return false; + + ArenaTeam* Arena = sArenaTeamMgr->GetArenaTeamById(teamId); + + if (!Arena) + { + handler->PSendSysMessage(LANG_ARENA_ERROR_NOT_FOUND, teamId); + handler->SetSentErrorMessage(true); + return false; + } + + handler->PSendSysMessage(LANG_ARENA_INFO_HEADER, Arena->GetName().c_str(), Arena->GetId(), Arena->GetRating(), Arena->GetType(), Arena->GetType()); + for (ArenaTeam::MemberList::iterator itr = Arena->m_membersBegin(); itr != Arena->m_membersEnd(); ++itr) + { + handler->PSendSysMessage(LANG_ARENA_INFO_MEMBERS, itr->Name.c_str(), GUID_LOPART(itr->Guid), itr->PersonalRating, (Arena->GetCaptain() == itr->Guid ? "- Captain" : "")); + } + return true; + } + + static bool HandleArenaLookupCommand(ChatHandler* handler, char const* args) + { + if (!*args) + return false; + + std::string namepart = args; + std::wstring wnamepart; + + if (!Utf8toWStr(namepart, wnamepart)) + return false; + + wstrToLower(wnamepart); + + bool found = false; + ArenaTeamMgr::ArenaTeamContainer::const_iterator i = sArenaTeamMgr->GetArenaTeamMapBegin(); + for (; i != sArenaTeamMgr->GetArenaTeamMapEnd(); ++i) + { + ArenaTeam* Arena = i->second; + + if (Utf8FitTo(Arena->GetName(), wnamepart)) + { + if (handler->GetSession()) + handler->PSendSysMessage(LANG_ARENA_LOOKUP, Arena->GetName().c_str(), Arena->GetId(), Arena->GetType(), Arena->GetType()); + + if (!found) + found = true; + + continue; + } + } + + if (!found) + handler->PSendSysMessage(LANG_AREAN_ERROR_NAME_NOT_FOUND, namepart.c_str()); + + return true; + } +}; + +void AddSC_arena_commandscript() +{ + new arena_commandscript(); +} diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 489c11e0f94..46eda11bfed 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -1472,37 +1472,124 @@ public: return true; } - // show info of player + + /** + * @name Player command: .pinfo + * @date 05/19/2013 + * + * @brief Prints information about a character and it's linked account to the commander + * + * Non-applying information, e.g. a character that is not in gm mode right now or + * that is not banned/muted, is not printed + * + * This can be done either by giving a name or by targeting someone, else, it'll use the commander + * + * @param args name Prints information according to the given name to the commander + * target Prints information on the target to the commander + * none No given args results in printing information on the commander + * + * @return Several pieces of information about the character and the account + **/ + static bool HandlePInfoCommand(ChatHandler* handler, char const* args) { + // Define ALL the player variables! Player* target; uint64 targetGuid; std::string targetName; + // To make sure we get a target, we convert our guid to an omniversal... uint32 parseGUID = MAKE_NEW_GUID(atol((char*)args), 0, HIGHGUID_PLAYER); + // ... and make sure we get a target, somehow. if (sObjectMgr->GetPlayerNameByGUID(parseGUID, targetName)) { target = sObjectMgr->GetPlayerByLowGUID(parseGUID); targetGuid = parseGUID; } + // if not, then return false. Which shouldn't happen, now should it ? else if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName)) return false; - uint32 accId = 0; - uint32 money = 0; - uint32 totalPlayerTime = 0; - uint8 level = 0; - uint32 latency = 0; - uint8 race; - uint8 Class; - int64 muteTime = 0; - int64 banTime = -1; + /* The variables we extract for the command. They are + * default as "does not exist" to prevent problems + * The output is printed in the follow manner: + * + * Player %s %s (guid: %u) - I. LANG_PINFO_PLAYER + * ** GM Mode active, Phase: -1 - II. LANG_PINFO_GM_ACTIVE (if GM) + * ** Banned: (Type, Reason, Time, By) - III. LANG_PINFO_BANNED (if banned) + * ** Muted: (Time, Reason, By) - IV. LANG_PINFO_MUTED (if muted) + * * Account: %s (id: %u), GM Level: %u - V. LANG_PINFO_ACC_ACCOUNT + * * Last Login: %u (Failed Logins: %u) - VI. LANG_PINFO_ACC_LASTLOGIN + * * Uses OS: %s - Latency: %u ms - Email %s - VII. LANG_PINFO_ACC_OS + * * Last IP: %u (Locked: %s) - VIII. LANG_PINFO_ACC_IP + * * Level: %u (%u/%u XP (%u XP left) - IX. LANG_PINFO_CHR_LEVEL + * * Race: %s %s, Class %s - X. LANG_PINFO_CHR_RACE + * * Alive ?: %s - XI. LANG_PINFO_CHR_ALIVE + * * Phase: %s - XII. LANG_PINFO_CHR_PHASE (if not GM) + * * Money: %ug%us%uc - XIII. LANG_PINFO_CHR_MONEY + * * Map: %s, Area: %s - XIV. LANG_PINFO_CHR_MAP + * * Guild: %s (Id: %u) - XV. LANG_PINFO_CHR_GUILD (if in guild) + * ** Rank: %s - XVI. LANG_PINFO_CHR_GUILD_RANK (if in guild) + * ** Note: %s - XVII. LANG_PINFO_CHR_GUILD_NOTE (if in guild and has note) + * ** O. Note: %s - XVIII.LANG_PINFO_CHR_GUILD_ONOTE (if in guild and has officer note) + * * Played time: %s - XIX. LANG_PINFO_CHR_PLAYEDTIME + * * Mails: %u Read/%u Total - XX. LANG_PINFO_CHR_MAILS (if has mails) + * + * Not all of them can be moved to the top. These should + * place the most important ones to the head, though. + * + * For a cleaner overview, I segment each output in Roman numerals + */ + + // Account data print variables + std::string userName = handler->GetTrinityString(LANG_ERROR); + uint32 accId = 0; + uint32 lowguid = GUID_LOPART(targetGuid); + std::string eMail = handler->GetTrinityString(LANG_ERROR); + uint32 security = 0; + std::string lastIp = handler->GetTrinityString(LANG_ERROR); + uint8 locked = 0; + std::string lastLogin = handler->GetTrinityString(LANG_ERROR); + uint32 failedLogins = 0; + uint32 latency = 0; + std::string OS = "None"; + + // Mute data print variables + int64 muteTime = -1; + std::string muteReason = "unknown"; + std::string muteBy = "unknown"; + + // Ban data print variables + int64 banTime = -1; + std::string banType = "None"; + std::string banReason = "Unknown"; + std::string bannedBy = "Unknown"; + + // Character data print variables + uint8 raceid, classid = 0; //RACE_NONE, CLASS_NONE + std::string raceStr, classStr = "None"; + uint8 gender = 0; + int8 locale = handler->GetSessionDbcLocale(); + std::string genderStr = handler->GetTrinityString(LANG_ERROR); + uint32 totalPlayerTime = 0; + uint8 level = 0; + std::string alive = handler->GetTrinityString(LANG_ERROR); + uint32 money = 0; + uint32 xp = 0; + uint32 xptotal = 0; + + // Position data print uint32 mapId; uint32 areaId; uint32 phase = 0; + std::string areaName = "<unknown>"; + std::string zoneName = "<unknown>"; + + // Guild data print is only defined if part of Guild + + // Mail data print is only defined if you have a mail - // get additional information from Player object if (target) { // check online security @@ -1514,11 +1601,13 @@ public: totalPlayerTime = target->GetTotalPlayedTime(); level = target->getLevel(); latency = target->GetSession()->GetLatency(); - race = target->getRace(); - Class = target->getClass(); + raceid = target->getRace(); + classid = target->getClass(); muteTime = target->GetSession()->m_muteTime; mapId = target->GetMapId(); areaId = target->GetAreaId(); + alive = target->isAlive() ? "Yes" : "No"; + gender = target->getGender(); phase = target->GetPhaseMask(); } // get additional information from DB @@ -1528,8 +1617,9 @@ public: if (handler->HasLowerSecurity(NULL, targetGuid)) return false; + // Query informations from the DB PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PINFO); - stmt->setUInt32(0, GUID_LOPART(targetGuid)); + stmt->setUInt32(0, lowguid); PreparedQueryResult result = CharacterDatabase.Query(stmt); if (!result) @@ -1540,20 +1630,20 @@ public: level = fields[1].GetUInt8(); money = fields[2].GetUInt32(); accId = fields[3].GetUInt32(); - race = fields[4].GetUInt8(); - Class = fields[5].GetUInt8(); + raceid = fields[4].GetUInt8(); + classid = fields[5].GetUInt8(); mapId = fields[6].GetUInt16(); areaId = fields[7].GetUInt16(); + gender = fields[8].GetUInt8(); + uint32 health = fields[9].GetUInt32(); + uint32 playerFlags = fields[10].GetUInt32(); + if (!health || playerFlags & PLAYER_FLAGS_GHOST) + alive = "No"; + else + alive = "Yes"; } - std::string userName = handler->GetTrinityString(LANG_ERROR); - std::string eMail = handler->GetTrinityString(LANG_ERROR); - std::string muteReason = ""; - std::string muteBy = ""; - std::string lastIp = handler->GetTrinityString(LANG_ERROR); - uint32 security = 0; - std::string lastLogin = handler->GetTrinityString(LANG_ERROR); - + // Query the prepared statement for login data PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_PINFO); stmt->setInt32(0, int32(realmID)); stmt->setUInt32(1, accId); @@ -1565,23 +1655,18 @@ public: userName = fields[0].GetString(); security = fields[1].GetUInt8(); eMail = fields[2].GetString(); - muteTime = fields[5].GetUInt64(); - muteReason = fields[6].GetString(); - muteBy = fields[7].GetString(); - - if (eMail.empty()) - eMail = "-"; + // Only fetch these fields if commander has sufficient rights AND is online (prevent cheating) + /// @TODO: Add RBAC for "Can query ip and login data" if (!handler->GetSession() || handler->GetSession()->GetSecurity() >= AccountTypes(security)) { lastIp = fields[3].GetString(); lastLogin = fields[4].GetString(); uint32 ip = inet_addr(lastIp.c_str()); -#if TRINITY_ENDIAN == BIGENDIAN EndianConvertReverse(ip); -#endif + // If ip2nation table is populated, it displays the country PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP2NATION_COUNTRY); stmt->setUInt32(0, ip); if (PreparedQueryResult result2 = LoginDatabase.Query(stmt)) @@ -1592,27 +1677,26 @@ public: lastIp.append(")"); } } - else - { - lastIp = "-"; - lastLogin = "-"; - } + muteTime = fields[5].GetUInt64(); + muteReason = fields[6].GetString(); + muteBy = fields[7].GetString(); + failedLogins = fields[8].GetUInt32(); + locked = fields[9].GetUInt8(); + OS = fields[10].GetString(); } + // Creates a chat link to the character. Returns nameLink std::string nameLink = handler->playerLink(targetName); - handler->PSendSysMessage(LANG_PINFO_ACCOUNT, (target ? "" : handler->GetTrinityString(LANG_OFFLINE)), nameLink.c_str(), GUID_LOPART(targetGuid), userName.c_str(), accId, eMail.c_str(), security, lastIp.c_str(), lastLogin.c_str(), latency); - - std::string bannedby = "unknown"; - std::string banreason = ""; - - stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_PINFO_BANS); - stmt->setUInt32(0, accId); - PreparedQueryResult result2 = LoginDatabase.Query(stmt); + // Returns banType, banTime, bannedBy, banreason + PreparedStatement* stmt2 = LoginDatabase.GetPreparedStatement(LOGIN_SEL_PINFO_BANS); + stmt2->setUInt32(0, accId); + PreparedQueryResult result2 = LoginDatabase.Query(stmt2); if (!result2) { + banType = "Character"; stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PINFO_BANS); - stmt->setUInt32(0, GUID_LOPART(targetGuid)); + stmt->setUInt32(0, lowguid); result2 = CharacterDatabase.Query(stmt); } @@ -1620,49 +1704,19 @@ public: { Field* fields = result2->Fetch(); banTime = int64(fields[1].GetUInt64() ? 0 : fields[0].GetUInt32()); - bannedby = fields[2].GetString(); - banreason = fields[3].GetString(); + bannedBy = fields[2].GetString(); + banReason = fields[3].GetString(); } - if (muteTime > 0) - handler->PSendSysMessage(LANG_PINFO_MUTE, secsToTimeString(muteTime - time(NULL), true).c_str(), muteBy.c_str(), muteReason.c_str()); - - if (banTime >= 0) - handler->PSendSysMessage(LANG_PINFO_BAN, banTime > 0 ? secsToTimeString(banTime - time(NULL), true).c_str() : "permanently", bannedby.c_str(), banreason.c_str()); + // Can be used to query data from World database + stmt2 = WorldDatabase.GetPreparedStatement(WORLD_SEL_REQ_XP); + stmt2->setUInt8(0, level); + PreparedQueryResult result3 = WorldDatabase.Query(stmt2); - std::string raceStr, ClassStr; - switch (race) + if (result3) { - case RACE_HUMAN: - raceStr = "Human"; - break; - case RACE_ORC: - raceStr = "Orc"; - break; - case RACE_DWARF: - raceStr = "Dwarf"; - break; - case RACE_NIGHTELF: - raceStr = "Night Elf"; - break; - case RACE_UNDEAD_PLAYER: - raceStr = "Undead"; - break; - case RACE_TAUREN: - raceStr = "Tauren"; - break; - case RACE_GNOME: - raceStr = "Gnome"; - break; - case RACE_TROLL: - raceStr = "Troll"; - break; - case RACE_BLOODELF: - raceStr = "Blood Elf"; - break; - case RACE_DRAENEI: - raceStr = "Draenei"; - break; + Field* fields = result3->Fetch(); + xptotal = fields[0].GetUInt32(); case RACE_GOBLIN: raceStr = "Goblin"; break; @@ -1671,52 +1725,68 @@ public: break; } - switch (Class) + // Can be used to query data from Characters database + stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PINFO_XP); + stmt2->setUInt32(0, lowguid); + PreparedQueryResult result4 = CharacterDatabase.Query(stmt2); + + if (result4) { - case CLASS_WARRIOR: - ClassStr = "Warrior"; - break; - case CLASS_PALADIN: - ClassStr = "Paladin"; - break; - case CLASS_HUNTER: - ClassStr = "Hunter"; - break; - case CLASS_ROGUE: - ClassStr = "Rogue"; - break; - case CLASS_PRIEST: - ClassStr = "Priest"; - break; - case CLASS_DEATH_KNIGHT: - ClassStr = "Death Knight"; - break; - case CLASS_SHAMAN: - ClassStr = "Shaman"; - break; - case CLASS_MAGE: - ClassStr = "Mage"; - break; - case CLASS_WARLOCK: - ClassStr = "Warlock"; - break; - case CLASS_DRUID: - ClassStr = "Druid"; - break; + Field* fields = result4->Fetch(); + xp = fields[0].GetUInt32(); } - std::string timeStr = secsToTimeString(totalPlayerTime, true, true); - uint32 gold = money /GOLD; - uint32 silv = (money % GOLD) / SILVER; - uint32 copp = (money % GOLD) % SILVER; - handler->PSendSysMessage(LANG_PINFO_LEVEL, raceStr.c_str(), ClassStr.c_str(), timeStr.c_str(), level, gold, silv, copp); + // Initiate output + // Output I. LANG_PINFO_PLAYER + handler->PSendSysMessage(LANG_PINFO_PLAYER, target ? "" : handler->GetTrinityString(LANG_OFFLINE), nameLink.c_str(), lowguid); - // Add map, zone, subzone and phase to output - std::string areaName = "<unknown>"; - std::string zoneName = ""; + // Output II. LANG_PINFO_GM_ACTIVE + if (target && target->isGameMaster()) + handler->PSendSysMessage(LANG_PINFO_GM_ACTIVE); - MapEntry const* map = sMapStore.LookupEntry(mapId); + // Output III. LANG_PINFO_BANNED if ban exists and is applied + if (banTime >= 0) + handler->PSendSysMessage(LANG_PINFO_BANNED, banType.c_str(), banTime > 0 ? secsToTimeString(banTime - time(NULL), true).c_str() : "permanently", banReason.c_str(), bannedBy.c_str()); + + // Output IV. LANG_PINFO_MUTED if mute is applied + if (muteTime > 0) + handler->PSendSysMessage(LANG_PINFO_MUTED, secsToTimeString(muteTime - time(NULL), true).c_str(), muteReason.c_str(), muteBy.c_str()); + + // Output V. LANG_PINFO_ACC_ACCOUNT + handler->PSendSysMessage(LANG_PINFO_ACC_ACCOUNT, userName.c_str(), accId, security); + + // Output VI. LANG_PINFO_ACC_LASTLOGIN + handler->PSendSysMessage(LANG_PINFO_ACC_LASTLOGIN, lastLogin.c_str(), failedLogins); + + // Output VIII. LANG_PINFO_ACC_OS + handler->PSendSysMessage(LANG_PINFO_ACC_OS, OS.c_str(), latency, eMail.c_str()); + // Output IX. LANG_PINFO_ACC_IP + handler->PSendSysMessage(LANG_PINFO_ACC_IP, lastIp.c_str(), locked ? "Yes" : "No"); + + // Output X. LANG_PINFO_CHR_LEVEL + handler->PSendSysMessage(LANG_PINFO_CHR_LEVEL, level, xp, xptotal, (xptotal - xp)); + + // Output XI. LANG_PINFO_CHR_RACE + raceStr = GetRaceName(raceid, locale); + classStr = GetClassName(classid, locale); + handler->PSendSysMessage(LANG_PINFO_CHR_RACE, (gender == 0 ? handler->GetTrinityString(LANG_CHARACTER_GENDER_MALE) : handler->GetTrinityString(LANG_CHARACTER_GENDER_FEMALE)), raceStr.c_str(), classStr.c_str()); + + // Output XII. LANG_PINFO_CHR_ALIVE + handler->PSendSysMessage(LANG_PINFO_CHR_ALIVE, alive.c_str()); + + // Output XIII. LANG_PINFO_CHR_PHASE if player is not in GM mode (GM is in every phase) + if (target && !target->isGameMaster()) // IsInWorld() returns false on loadingscreen, so it's more + handler->PSendSysMessage(LANG_PINFO_CHR_PHASE, phase); // precise than just target (safer ?). + // However, as we usually just require a target here, we use target instead. + // Output XIV. LANG_PINFO_CHR_MONEY + uint32 gold = money / GOLD; + uint32 silv = (money % GOLD) / SILVER; + uint32 copp = (money % GOLD) % SILVER; + handler->PSendSysMessage(LANG_PINFO_CHR_MONEY, gold, silv, copp); + + // Position data + MapEntry const* map = sMapStore.LookupEntry(mapId); AreaTableEntry const* area = GetAreaEntryByAreaID(areaId); if (area) { @@ -1728,30 +1798,55 @@ public: } if (target) - { - if (!zoneName.empty()) - handler->PSendSysMessage(LANG_PINFO_MAP_ONLINE, map->name, zoneName.c_str(), areaName.c_str(), phase); - else - handler->PSendSysMessage(LANG_PINFO_MAP_ONLINE, map->name, areaName.c_str(), "<unknown>", phase); + handler->PSendSysMessage(LANG_PINFO_CHR_MAP, map->name[locale], (!zoneName.empty() ? zoneName.c_str() : "<Unknown>"), (!areaName.empty() ? areaName.c_str() : "<Unknown>")); + + // Guild Data - an own query, because it may not happen. + PreparedStatement* stmt3 = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED); + stmt3->setUInt32(0, lowguid); + PreparedQueryResult result5 = CharacterDatabase.Query(stmt3); + if (result5) + { + Field* fields = result5->Fetch(); + uint32 guildId = fields[0].GetUInt32(); + std::string guildName = fields[1].GetString(); + std::string guildRank = fields[2].GetString(); + std::string note = fields[3].GetString(); + std::string officeNote = fields[4].GetString(); + + // Output XVII. - XX. + handler->PSendSysMessage(LANG_PINFO_CHR_GUILD, guildName.c_str(), guildId); + handler->PSendSysMessage(LANG_PINFO_CHR_GUILD_RANK, guildRank.c_str()); + // Only output XIX and XX if they are not empty + if (!note.empty()) + handler->PSendSysMessage(LANG_PINFO_CHR_GUILD_NOTE, note.c_str()); + if (!officeNote.empty()) + handler->PSendSysMessage(LANG_PINFO_CHR_GUILD_ONOTE, officeNote.c_str()); } - else - handler->PSendSysMessage(LANG_PINFO_MAP_OFFLINE, map->name, areaName.c_str()); - stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER_EXTENDED); - stmt->setUInt32(0, GUID_LOPART(targetGuid)); + // Output XXI. LANG_PINFO_CHR_PLAYEDTIME + handler->PSendSysMessage(LANG_PINFO_CHR_PLAYEDTIME, (secsToTimeString(totalPlayerTime, true, true)).c_str()); - result = CharacterDatabase.Query(stmt); - if (result) + // Mail Data - an own query, because it may or may not be useful. + // SQL: "SELECT SUM(CASE WHEN (checked & 1) THEN 1 ELSE 0 END) AS 'readmail', COUNT(*) AS 'totalmail' FROM mail WHERE `receiver` = ?" + stmt3 = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PINFO_MAILS); + stmt3->setUInt32(0, lowguid); + PreparedQueryResult result6 = CharacterDatabase.Query(stmt3); + if (result6) { - Field* fields = result->Fetch(); + // Define the variables, so the compiler knows they exist + uint32 rmailint = 0; - uint32 guildId = fields[0].GetUInt32(); - std::string guildName = fields[1].GetString(); - std::string guildRank = fields[2].GetString(); - std::string note = fields[3].GetString(); - std::string officeNote = fields[4].GetString(); + // Fetch the fields - readmail is a SUM(x) and given out as char! Thus... + Field* fields = result6->Fetch(); + std::string readmail = fields[0].GetString(); + uint64 totalmail = fields[1].GetUInt64(); - handler->PSendSysMessage(LANG_PINFO_GUILD_INFO, guildName.c_str(), guildId, guildRank.c_str(), note.c_str(), officeNote.c_str()); + // ... we have to convert it from Char to int. We can use totalmail as it is + rmailint = atol(readmail.c_str()); + + // Output XXII. LANG_INFO_CHR_MAILS if at least one mails is given + if (totalmail >= 1) + handler->PSendSysMessage(LANG_PINFO_CHR_MAILS, rmailint, totalmail); } return true; @@ -1789,6 +1884,7 @@ public: return true; } + // mute player for some times static bool HandleMuteCommand(ChatHandler* handler, char const* args) { diff --git a/src/server/scripts/Commands/cs_server.cpp b/src/server/scripts/Commands/cs_server.cpp index 309380a9cbb..11b4ebf33ae 100644 --- a/src/server/scripts/Commands/cs_server.cpp +++ b/src/server/scripts/Commands/cs_server.cpp @@ -338,7 +338,8 @@ public: } else sWorld->ShutdownServ(time, SHUTDOWN_MASK_IDLE, SHUTDOWN_EXIT_CODE); - return true; + + return true; } // Exit the realm diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp index 9e312ef8f94..b6b701c513d 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp @@ -716,27 +716,27 @@ public: if (CheckTimer <= diff) { Creature* Kalec = Unit::GetCreature(*me, KalecGUID); - if (!Kalec || (Kalec && !Kalec->isAlive())) + if (!Kalec || !Kalec->isAlive()) { if (Creature* Kalecgos = Unit::GetCreature(*me, KalecgosGUID)) Kalecgos->AI()->EnterEvadeMode(); - return; + return; } + if (HealthBelowPct(10) && !isEnraged) { if (Creature* Kalecgos = Unit::GetCreature(*me, KalecgosGUID)) Kalecgos->AI()->DoAction(DO_ENRAGE); DoAction(DO_ENRAGE); } + Creature* Kalecgos = Unit::GetCreature(*me, KalecgosGUID); - if (Kalecgos) + if (Kalecgos && !Kalecgos->isInCombat()) { - if (!Kalecgos->isInCombat()) - { - me->AI()->EnterEvadeMode(); - return; - } + me->AI()->EnterEvadeMode(); + return; } + if (!isBanished && HealthBelowPct(1)) { if (Kalecgos) @@ -746,8 +746,7 @@ public: me->DealDamage(me, me->GetHealth()); return; } - else - DoAction(DO_BANISH); + DoAction(DO_BANISH); } else { diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp index 58dc74d0f0a..9d266c77b77 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_falric.cpp @@ -19,7 +19,7 @@ #include "ScriptedCreature.h" #include "halls_of_reflection.h" -enum Yells +enum Texts { SAY_AGGRO = 0, SAY_SLAY = 1, @@ -68,14 +68,14 @@ public: uiHopelessnessCount = 0; if (instance) - instance->SetData(DATA_FALRIC_EVENT, NOT_STARTED); + instance->SetBossState(DATA_FALRIC_EVENT, NOT_STARTED); } void EnterCombat(Unit* /*who*/) { Talk(SAY_AGGRO); if (instance) - instance->SetData(DATA_FALRIC_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_FALRIC_EVENT, IN_PROGRESS); events.ScheduleEvent(EVENT_QUIVERING_STRIKE, 23000); events.ScheduleEvent(EVENT_IMPENDING_DESPAIR, 9000); @@ -87,7 +87,7 @@ public: Talk(SAY_DEATH); if (instance) - instance->SetData(DATA_FALRIC_EVENT, DONE); + instance->SetBossState(DATA_FALRIC_EVENT, DONE); } void KilledUnit(Unit* /*victim*/) diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp index 08d5cf70ee1..e82f0d48ebd 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/boss_marwyn.cpp @@ -19,7 +19,7 @@ #include "ScriptedCreature.h" #include "halls_of_reflection.h" -enum Yells +enum Texts { SAY_AGGRO = 0, SAY_SLAY = 1, @@ -63,14 +63,14 @@ public: boss_horAI::Reset(); if (instance) - instance->SetData(DATA_MARWYN_EVENT, NOT_STARTED); + instance->SetBossState(DATA_MARWYN_EVENT, NOT_STARTED); } void EnterCombat(Unit* /*who*/) { Talk(SAY_AGGRO); if (instance) - instance->SetData(DATA_MARWYN_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_MARWYN_EVENT, IN_PROGRESS); events.ScheduleEvent(EVENT_OBLITERATE, 30000); /// @todo Check timer events.ScheduleEvent(EVENT_WELL_OF_CORRUPTION, 13000); @@ -83,7 +83,7 @@ public: Talk(SAY_DEATH); if (instance) - instance->SetData(DATA_MARWYN_EVENT, DONE); + instance->SetBossState(DATA_MARWYN_EVENT, DONE); } void KilledUnit(Unit* /*victim*/) diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp index b140801d8f1..a64f2cf5467 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -18,10 +18,10 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "ScriptedGossip.h" -#include "halls_of_reflection.h" #include "Player.h" +#include "halls_of_reflection.h" -enum Yells +enum Text { SAY_JAINA_INTRO_1 = 0, SAY_JAINA_INTRO_2 = 1, @@ -66,17 +66,19 @@ enum Yells SAY_LK_INTRO_1 = 0, SAY_LK_INTRO_2 = 1, SAY_LK_INTRO_3 = 2, + SAY_LK_JAINA_INTRO_END = 3, + SAY_LK_SYLVANAS_INTRO_END = 4, SAY_FALRIC_INTRO_1 = 5, SAY_FALRIC_INTRO_2 = 6, - SAY_MARWYN_INTRO_1 = 4 + SAY_MARWYN_INTRO_1 = 4, }; enum Events { - EVENT_NONE, - + EVENT_WALK_INTRO1 = 1, + EVENT_WALK_INTRO2, EVENT_START_INTRO, EVENT_SKIP_INTRO, @@ -125,8 +127,13 @@ enum Events EVENT_INTRO_LK_7, EVENT_INTRO_LK_8, EVENT_INTRO_LK_9, + EVENT_INTRO_LK_10, + EVENT_INTRO_LK_11, EVENT_INTRO_END, + + EVENT_OPEN_FROSTWORN_DOOR, + EVENT_CLOSE_FROSTWORN_DOOR, }; enum eEnum @@ -140,6 +147,17 @@ enum eEnum QUEST_WRATH_OF_THE_LICH_KING_H2 = 24802, }; +enum Spells +{ + SPELL_CAST_VISUAL = 65633, // Jaina/Sylavana + SPELL_BOSS_SPAWN_AURA = 72712, // Falric and Marwyn + SPELL_UTHER_DESPAWN = 70693, + SPELL_TAKE_FROSTMOURNE = 72729, + SPELL_FROSTMOURNE_DESPAWN = 72726, + SPELL_FROSTMOURNE_VISUAL = 73220, + SPELL_FROSTMOURNE_SOUNDS = 70667, +}; + const Position HallsofReflectionLocs[]= { {5283.234863f, 1990.946777f, 707.695679f, 0.929097f}, // 2 Loralen Follows @@ -147,7 +165,7 @@ const Position HallsofReflectionLocs[]= {5401.866699f, 2110.837402f, 707.695251f, 0.800610f}, // 10 Loralen follows }; -const Position SpawnPos = {5262.540527f, 1949.693726f, 707.695007f, 0.808736f}; // Jaina/Sylvanas Beginning Position +const Position IntroPos = {5265.89f, 1952.98f, 707.6978f, 0.0f}; // Jaina/Sylvanas Intro Start Position const Position MoveThronePos = {5306.952148f, 1998.499023f, 709.341431f, 1.277278f}; // Jaina/Sylvanas walks to throne const Position UtherSpawnPos = {5308.310059f, 2003.857178f, 709.341431f, 4.650315f}; const Position LichKingSpawnPos = {5362.917480f, 2062.307129f, 707.695374f, 3.945812f}; @@ -156,58 +174,10 @@ const Position LichKingMoveAwayPos = {5400.069824f, 2102.7131689f, 707.69525f, class npc_jaina_or_sylvanas_hor : public CreatureScript { -private: - bool m_isSylvana; - -public: - npc_jaina_or_sylvanas_hor(bool isSylvana, const char* name) : CreatureScript(name), m_isSylvana(isSylvana) { } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) - { - player->PlayerTalkClass->ClearMenus(); - switch (action) - { - case GOSSIP_ACTION_INFO_DEF+1: - player->CLOSE_GOSSIP_MENU(); - if (creature->AI()) - creature->AI()->DoAction(ACTION_START_INTRO); - creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - break; - case GOSSIP_ACTION_INFO_DEF+2: - player->CLOSE_GOSSIP_MENU(); - if (creature->AI()) - creature->AI()->DoAction(ACTION_SKIP_INTRO); - creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - break; - } + public: + npc_jaina_or_sylvanas_hor() : CreatureScript("npc_jaina_or_sylvanas_hor") { } - return true; - } - - bool OnGossipHello(Player* player, Creature* creature) - { - if (creature->isQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - QuestStatus status = player->GetQuestStatus(m_isSylvana ? QUEST_DELIVRANCE_FROM_THE_PIT_H2 : QUEST_DELIVRANCE_FROM_THE_PIT_A2); - if (status == QUEST_STATUS_COMPLETE || status == QUEST_STATUS_REWARDED) - player->ADD_GOSSIP_ITEM( 0, "Can you remove the sword?", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - // once last quest is completed, she offers this shortcut of the starting event - status = player->GetQuestStatus(m_isSylvana ? QUEST_WRATH_OF_THE_LICH_KING_H2 : QUEST_WRATH_OF_THE_LICH_KING_A2); - if (status == QUEST_STATUS_COMPLETE || status == QUEST_STATUS_REWARDED) - player->ADD_GOSSIP_ITEM( 0, "Dark Lady, I think I hear Arthas coming. Whatever you're going to do, do it quickly.", GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2); - - player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID()); - return true; - } - - CreatureAI* GetAI(Creature* creature) const - { - return new npc_jaina_or_sylvanas_horAI(creature); - } - - // AI of Part1: handle the intro till start of gauntlet event. + // AI of Part1 struct npc_jaina_or_sylvanas_horAI : public ScriptedAI { npc_jaina_or_sylvanas_horAI(Creature* creature) : ScriptedAI(creature) @@ -221,6 +191,24 @@ public: EventMap events; + void sGossipSelect(Player* player, uint32 /*sender*/, uint32 action) + { + player->PlayerTalkClass->ClearMenus(); + switch (action) + { + case 0: + player->CLOSE_GOSSIP_MENU(); + events.ScheduleEvent(EVENT_START_INTRO, 1000); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER); + break; + case 1: + player->CLOSE_GOSSIP_MENU(); + events.ScheduleEvent(EVENT_SKIP_INTRO, 1000); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER); + break; + } + } + void Reset() { events.Reset(); @@ -228,22 +216,9 @@ public: utherGUID = 0; lichkingGUID = 0; - me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); + me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER); me->SetStandState(UNIT_STAND_STATE_STAND); - me->SetVisible(true); - } - - void DoAction(int32 actionId) - { - switch (actionId) - { - case ACTION_START_INTRO: - events.ScheduleEvent(EVENT_START_INTRO, 0); - break; - case ACTION_SKIP_INTRO: - events.ScheduleEvent(EVENT_SKIP_INTRO, 0); - break; - } + events.ScheduleEvent(EVENT_WALK_INTRO1, 3000); } void UpdateAI(uint32 diff) @@ -251,6 +226,26 @@ public: events.Update(diff); switch (events.ExecuteEvent()) { + case EVENT_WALK_INTRO1: + me->GetMotionMaster()->MovePoint(0, IntroPos); + if (instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + { + Talk(SAY_JAINA_INTRO_1); + events.ScheduleEvent(EVENT_WALK_INTRO2, 7000); + } + else + { + Talk(SAY_SYLVANAS_INTRO_1); + events.ScheduleEvent(EVENT_WALK_INTRO2, 9000); + } + break; + case EVENT_WALK_INTRO2: + if (instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + Talk(SAY_JAINA_INTRO_2); + else + Talk(SAY_SYLVANAS_INTRO_2); + me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER); + break; case EVENT_START_INTRO: me->GetMotionMaster()->MovePoint(0, MoveThronePos); // Begining of intro is differents between fActions as the speech sequence and timers are differents. @@ -259,27 +254,25 @@ public: else events.ScheduleEvent(EVENT_INTRO_H2_1, 0); break; - - // A2 Intro Events + // A2 Intro Events case EVENT_INTRO_A2_1: Talk(SAY_JAINA_INTRO_3); - events.ScheduleEvent(EVENT_INTRO_A2_2, 5000); + events.ScheduleEvent(EVENT_INTRO_A2_2, 7000); break; case EVENT_INTRO_A2_2: Talk(SAY_JAINA_INTRO_4); events.ScheduleEvent(EVENT_INTRO_A2_3, 10000); break; case EVENT_INTRO_A2_3: - /// @todo she's doing some kind of spell casting emote + me->CastSpell(me, SPELL_CAST_VISUAL, false); + me->CastSpell(me, SPELL_FROSTMOURNE_SOUNDS, true); instance->HandleGameObject(instance->GetData64(DATA_FROSTMOURNE), true); events.ScheduleEvent(EVENT_INTRO_A2_4, 10000); break; case EVENT_INTRO_A2_4: - // spawn UTHER during speach 2 if (Creature* uther = me->SummonCreature(NPC_UTHER, UtherSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) { uther->GetMotionMaster()->MoveIdle(); - uther->SetReactState(REACT_PASSIVE); // be sure he will not aggro arthas utherGUID = uther->GetGUID(); } events.ScheduleEvent(EVENT_INTRO_A2_5, 2000); @@ -291,57 +284,57 @@ public: break; case EVENT_INTRO_A2_6: Talk(SAY_JAINA_INTRO_5); - events.ScheduleEvent(EVENT_INTRO_A2_7, 6000); + events.ScheduleEvent(EVENT_INTRO_A2_7, 7000); break; case EVENT_INTRO_A2_7: if (Creature* uther = me->GetCreature(*me, utherGUID)) uther->AI()->Talk(SAY_UTHER_INTRO_A2_2); - events.ScheduleEvent(EVENT_INTRO_A2_8, 6500); + events.ScheduleEvent(EVENT_INTRO_A2_8, 7000); break; case EVENT_INTRO_A2_8: Talk(SAY_JAINA_INTRO_6); - events.ScheduleEvent(EVENT_INTRO_A2_9, 2000); + events.ScheduleEvent(EVENT_INTRO_A2_9, 1200); break; case EVENT_INTRO_A2_9: if (Creature* uther = me->GetCreature(*me, utherGUID)) uther->AI()->Talk(SAY_UTHER_INTRO_A2_3); - events.ScheduleEvent(EVENT_INTRO_A2_10, 9000); + events.ScheduleEvent(EVENT_INTRO_A2_10, 11000); break; case EVENT_INTRO_A2_10: Talk(SAY_JAINA_INTRO_7); - events.ScheduleEvent(EVENT_INTRO_A2_11, 5000); + events.ScheduleEvent(EVENT_INTRO_A2_11, 6000); break; case EVENT_INTRO_A2_11: if (Creature* uther = me->GetCreature(*me, utherGUID)) uther->AI()->Talk(SAY_UTHER_INTRO_A2_4); - events.ScheduleEvent(EVENT_INTRO_A2_12, 11000); + events.ScheduleEvent(EVENT_INTRO_A2_12, 12000); break; case EVENT_INTRO_A2_12: Talk(SAY_JAINA_INTRO_8); - events.ScheduleEvent(EVENT_INTRO_A2_13, 4000); + events.ScheduleEvent(EVENT_INTRO_A2_13, 6000); break; case EVENT_INTRO_A2_13: if (Creature* uther = me->GetCreature(*me, utherGUID)) uther->AI()->Talk(SAY_UTHER_INTRO_A2_5); - events.ScheduleEvent(EVENT_INTRO_A2_14, 12500); + events.ScheduleEvent(EVENT_INTRO_A2_14, 13000); break; case EVENT_INTRO_A2_14: Talk(SAY_JAINA_INTRO_9); - events.ScheduleEvent(EVENT_INTRO_A2_15, 10000); + events.ScheduleEvent(EVENT_INTRO_A2_15, 12000); break; case EVENT_INTRO_A2_15: if (Creature* uther = me->GetCreature(*me, utherGUID)) uther->AI()->Talk(SAY_UTHER_INTRO_A2_6); - events.ScheduleEvent(EVENT_INTRO_A2_16, 22000); + events.ScheduleEvent(EVENT_INTRO_A2_16, 25000); break; case EVENT_INTRO_A2_16: if (Creature* uther = me->GetCreature(*me, utherGUID)) uther->AI()->Talk(SAY_UTHER_INTRO_A2_7); - events.ScheduleEvent(EVENT_INTRO_A2_17, 4000); + events.ScheduleEvent(EVENT_INTRO_A2_17, 6000); break; case EVENT_INTRO_A2_17: Talk(SAY_JAINA_INTRO_10); - events.ScheduleEvent(EVENT_INTRO_A2_18, 2000); + events.ScheduleEvent(EVENT_INTRO_A2_18, 5000); break; case EVENT_INTRO_A2_18: if (Creature* uther = me->GetCreature(*me, utherGUID)) @@ -349,14 +342,13 @@ public: uther->HandleEmoteCommand(EMOTE_ONESHOT_NO); uther->AI()->Talk(SAY_UTHER_INTRO_A2_8); } - events.ScheduleEvent(EVENT_INTRO_A2_19, 11000); + events.ScheduleEvent(EVENT_INTRO_A2_19, 12000); break; case EVENT_INTRO_A2_19: Talk(SAY_JAINA_INTRO_11); - events.ScheduleEvent(EVENT_INTRO_LK_1, 2000); + events.ScheduleEvent(EVENT_INTRO_LK_1, 3000); break; - - // H2 Intro Events + // H2 Intro Events case EVENT_INTRO_H2_1: Talk(SAY_SYLVANAS_INTRO_1); events.ScheduleEvent(EVENT_INTRO_H2_2, 8000); @@ -367,7 +359,9 @@ public: break; case EVENT_INTRO_H2_3: Talk(SAY_SYLVANAS_INTRO_3); - /// @todo she's doing some kind of spell casting emote + me->CastSpell(me, SPELL_CAST_VISUAL, false); + me->CastSpell(me, SPELL_FROSTMOURNE_SOUNDS, true); + instance->HandleGameObject(instance->GetData64(DATA_FROSTMOURNE), true); events.ScheduleEvent(EVENT_INTRO_H2_4, 6000); break; case EVENT_INTRO_H2_4: @@ -375,7 +369,6 @@ public: if (Creature* uther = me->SummonCreature(NPC_UTHER, UtherSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) { uther->GetMotionMaster()->MoveIdle(); - uther->SetReactState(REACT_PASSIVE); // be sure he will not aggro arthas utherGUID = uther->GetGUID(); } events.ScheduleEvent(EVENT_INTRO_H2_5, 2000); @@ -433,126 +426,159 @@ public: Talk(SAY_SYLVANAS_INTRO_8); events.ScheduleEvent(EVENT_INTRO_LK_1, 2000); break; - - // Remaining Intro Events common for both faction + // Remaining Intro Events common for both faction case EVENT_INTRO_LK_1: // Spawn LK in front of door, and make him move to the sword. - if (Creature* lichking = me->SummonCreature(NPC_LICH_KING_EVENT, LichKingSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) + if (Creature* lichking = me->SummonCreature(NPC_LICH_KING_PART1, LichKingSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) { + lichking->SetUnitMovementFlags(MOVEMENTFLAG_WALKING); lichking->GetMotionMaster()->MovePoint(0, LichKingMoveThronePos); - lichking->SetReactState(REACT_PASSIVE); + //lichking->SetReactState(REACT_PASSIVE); lichkingGUID = lichking->GetGUID(); + events.ScheduleEvent(EVENT_OPEN_FROSTWORN_DOOR, 0); + events.ScheduleEvent(EVENT_CLOSE_FROSTWORN_DOOR, 4000); } - if (Creature* uther = me->GetCreature(*me, utherGUID)) { + uther->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_COWER); if (instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) uther->AI()->Talk(SAY_UTHER_INTRO_A2_9); else uther->AI()->Talk(SAY_UTHER_INTRO_H2_7); } - - events.ScheduleEvent(EVENT_INTRO_LK_2, 11000); + events.ScheduleEvent(EVENT_INTRO_LK_2, 10000); break; - case EVENT_INTRO_LK_2: - if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) - lichking->AI()->Talk(SAY_LK_INTRO_1); - events.ScheduleEvent(EVENT_INTRO_LK_3, 2000); - break; - + if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) + lichking->AI()->Talk(SAY_LK_INTRO_1); + events.ScheduleEvent(EVENT_INTRO_LK_3, 1000); + break; case EVENT_INTRO_LK_3: - // The Lich King banishes Uther to the abyss. - if (Creature* uther = me->GetCreature(*me, utherGUID)) - { - uther->DisappearAndDie(); - utherGUID = 0; - } - - // He steps forward and removes the runeblade from the heap of skulls. - - events.ScheduleEvent(EVENT_INTRO_LK_4, 4000); - break; - + // The Lich King banishes Uther to the abyss. + if (Creature* uther = me->GetCreature(*me, utherGUID)) + { + uther->CastSpell(uther, SPELL_UTHER_DESPAWN, true); + uther->DespawnOrUnsummon(5000); + utherGUID = 0; + } + events.ScheduleEvent(EVENT_INTRO_LK_4, 9000); + break; case EVENT_INTRO_LK_4: - if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) - lichking->AI()->Talk(SAY_LK_INTRO_2); - events.ScheduleEvent(EVENT_INTRO_LK_5, 10000); + // He steps forward and removes the runeblade from the heap of skulls. + if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) + { + if (GameObject* frostmourne = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_FROSTMOURNE))) + frostmourne->SetPhaseMask(2, true); + lichking->CastSpell(lichking, SPELL_TAKE_FROSTMOURNE, true); + lichking->CastSpell(lichking, SPELL_FROSTMOURNE_VISUAL, true); + } + events.ScheduleEvent(EVENT_INTRO_LK_5, 8000); break; - case EVENT_INTRO_LK_5: + if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) + lichking->AI()->Talk(SAY_LK_INTRO_2); + events.ScheduleEvent(EVENT_INTRO_LK_6, 8000); + break; + case EVENT_INTRO_LK_6: // summon Falric and Marwyn. then go back to the door - if (Creature* pFalric = me->GetCreature(*me, instance->GetData64(DATA_FALRIC))) - pFalric->SetVisible(true); - if (Creature* pMarwyn = me->GetCreature(*me, instance->GetData64(DATA_MARWYN))) - pMarwyn->SetVisible(true); - + if (Creature* falric = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_FALRIC_EVENT))) + { + falric->CastSpell(falric, SPELL_BOSS_SPAWN_AURA, true); + falric->SetVisible(true); + } + if (Creature* marwyn = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_MARWYN_EVENT))) + { + marwyn->CastSpell(marwyn, SPELL_BOSS_SPAWN_AURA, true); + marwyn->SetVisible(true); + } if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) { - lichking->GetMotionMaster()->MovePoint(0, LichKingSpawnPos); lichking->AI()->Talk(SAY_LK_INTRO_3); + lichking->SetUnitMovementFlags(MOVEMENTFLAG_WALKING); + lichking->GetMotionMaster()->MovePoint(0, LichKingMoveAwayPos); } - - events.ScheduleEvent(EVENT_INTRO_LK_6, 8000); - break; - - case EVENT_INTRO_LK_6: - if (Creature* falric = me->GetCreature(*me, instance->GetData64(DATA_FALRIC))) - falric->AI()->Talk(SAY_FALRIC_INTRO_1); - - events.ScheduleEvent(EVENT_INTRO_LK_7, 2000); + events.ScheduleEvent(EVENT_INTRO_LK_7, 10000); + events.ScheduleEvent(EVENT_OPEN_FROSTWORN_DOOR, 5000); break; - case EVENT_INTRO_LK_7: - if (Creature* marwyn = me->GetCreature(*me, instance->GetData64(DATA_MARWYN))) + if (Creature* marwyn = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_MARWYN_EVENT))) marwyn->AI()->Talk(SAY_MARWYN_INTRO_1); - - events.ScheduleEvent(EVENT_INTRO_LK_8, 2000); + events.ScheduleEvent(EVENT_INTRO_LK_8, 1000); break; - case EVENT_INTRO_LK_8: - if (Creature* falric = me->GetCreature(*me, instance->GetData64(DATA_FALRIC))) - falric->AI()->Talk(SAY_FALRIC_INTRO_2); - + if (Creature* falric = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_FALRIC_EVENT))) + falric->AI()->Talk(SAY_FALRIC_INTRO_1); events.ScheduleEvent(EVENT_INTRO_LK_9, 5000); break; - case EVENT_INTRO_LK_9: + if (Creature* falric = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_FALRIC_EVENT))) + falric->AI()->Talk(SAY_FALRIC_INTRO_2); + events.ScheduleEvent(EVENT_INTRO_LK_10, 7000); + break; + case EVENT_INTRO_LK_10: if (instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) Talk(SAY_JAINA_INTRO_END); else Talk(SAY_SYLVANAS_INTRO_END); - - me->GetMotionMaster()->MovePoint(0, LichKingSpawnPos); + me->GetMotionMaster()->MovePoint(0, LichKingMoveAwayPos); /// @todo Loralen/Koreln shall run also - events.ScheduleEvent(EVENT_INTRO_END, 10000); + events.ScheduleEvent(EVENT_INTRO_LK_11, 5000); + break; + case EVENT_INTRO_LK_11: + if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) + { + if (instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE) + lichking->AI()->Talk(SAY_LK_JAINA_INTRO_END); + else + lichking->AI()->Talk(SAY_LK_SYLVANAS_INTRO_END); + } + events.ScheduleEvent(EVENT_INTRO_END, 5000); break; - case EVENT_INTRO_END: if (instance) - instance->SetData(DATA_WAVE_COUNT, SPECIAL); // start first wave - + { + instance->SetData(DATA_INTRO_EVENT, DONE); + instance->ProcessEvent(0, EVENT_SPAWN_WAVES); + } // Loralen or Koreln disappearAndDie() - me->DisappearAndDie(); + if (Creature* lichking = me->GetCreature(*me, lichkingGUID)) + { + lichking->DespawnOrUnsummon(5000); + lichkingGUID = 0; + } + me->DespawnOrUnsummon(10000); + events.ScheduleEvent(EVENT_CLOSE_FROSTWORN_DOOR, 7000); break; - case EVENT_SKIP_INTRO: - /// @todo implement - - if (Creature* pFalric = me->GetCreature(*me, instance->GetData64(DATA_FALRIC))) - pFalric->SetVisible(true); - if (Creature* pMarwyn = me->GetCreature(*me, instance->GetData64(DATA_MARWYN))) - pMarwyn->SetVisible(true); - - me->GetMotionMaster()->MovePoint(0, LichKingSpawnPos); + me->GetMotionMaster()->MovePoint(0, MoveThronePos); /// @todo Loralen/Koreln shall run also - - events.ScheduleEvent(EVENT_INTRO_END, 15000); + if (Creature* lichking = me->SummonCreature(NPC_LICH_KING_PART1, LichKingSpawnPos, TEMPSUMMON_MANUAL_DESPAWN)) + { + lichking->SetUnitMovementFlags(MOVEMENTFLAG_WALKING); + lichking->GetMotionMaster()->MovePoint(0, LichKingMoveThronePos); + lichking->SetReactState(REACT_PASSIVE); + lichkingGUID = lichking->GetGUID(); + events.ScheduleEvent(EVENT_OPEN_FROSTWORN_DOOR, 0); + events.ScheduleEvent(EVENT_CLOSE_FROSTWORN_DOOR, 4000); + } + events.ScheduleEvent(EVENT_INTRO_LK_4, 15000); + break; + case EVENT_OPEN_FROSTWORN_DOOR: + if (GameObject* gate = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_FROSTWORN_DOOR))) + instance->HandleGameObject(0 ,true, gate); + break; + case EVENT_CLOSE_FROSTWORN_DOOR: + if (GameObject* gate = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_FROSTWORN_DOOR))) + instance->HandleGameObject(0 ,false, gate); break; } } }; + CreatureAI* GetAI(Creature* creature) const + { + return new npc_jaina_or_sylvanas_horAI(creature); + } }; enum TrashSpells @@ -626,27 +652,56 @@ enum TrashEvents EVENT_ICE_SHOT, }; -class npc_ghostly_priest : public CreatureScript +struct npc_gauntlet_trash : public ScriptedAI { -public: - npc_ghostly_priest() : CreatureScript("npc_ghostly_priest") { } + npc_gauntlet_trash(Creature* creature) : ScriptedAI(creature), + instance(creature->GetInstanceScript()) + { + } - CreatureAI* GetAI(Creature* creature) const + void Reset() { - return new npc_ghostly_priestAI(creature); + me->CastSpell(me, SPELL_WELL_OF_SOULS, true); + events.Reset(); } - struct npc_ghostly_priestAI: public ScriptedAI + void EnterEvadeMode() { - npc_ghostly_priestAI(Creature* creature) : ScriptedAI(creature) - { - } + if (instance->GetData(DATA_WAVE_COUNT) != NOT_STARTED) + instance->SetData(DATA_WAVE_COUNT, NOT_STARTED); + } - EventMap events; + void SetData(uint32 type, uint32 value) + { + if (type) + return; - void Reset() + InternalWaveId = value; + } + + uint32 GetData(uint32 type) const + { + if (type) + return 0; + + return InternalWaveId; + } + +protected: + EventMap events; + InstanceScript* instance; + uint32 InternalWaveId; +}; + +class npc_ghostly_priest : public CreatureScript +{ +public: + npc_ghostly_priest() : CreatureScript("npc_ghostly_priest") { } + + struct npc_ghostly_priestAI : public npc_gauntlet_trash + { + npc_ghostly_priestAI(Creature* creature) : npc_gauntlet_trash(creature) { - events.Reset(); } void EnterCombat(Unit* /*who*/) @@ -667,45 +722,46 @@ public: if (me->HasUnitState(UNIT_STATE_CASTING)) return; - while (uint32 eventId = events.ExecuteEvent()) + switch (events.ExecuteEvent()) { - switch (eventId) - { - case EVENT_SHADOW_WORD_PAIN: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_SHADOW_WORD_PAIN); - events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 8000); - return; - case EVENT_CIRCLE_OF_DESTRUCTION: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_CIRCLE_OF_DESTRUCTION); - events.ScheduleEvent(EVENT_CIRCLE_OF_DESTRUCTION, 12000); - return; - case EVENT_COWER_IN_FEAR: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_COWER_IN_FEAR); - events.ScheduleEvent(EVENT_COWER_IN_FEAR, 10000); - return; - case EVENT_DARK_MENDING: - // find an ally with missing HP - if (Unit* target = DoSelectLowestHpFriendly(40, DUNGEON_MODE(30000, 50000))) - { - DoCast(target, SPELL_DARK_MENDING); - events.ScheduleEvent(EVENT_DARK_MENDING, 20000); - } - else - { - // no friendly unit with missing hp. re-check in just 5 sec. - events.ScheduleEvent(EVENT_DARK_MENDING, 5000); - } - return; - } + case EVENT_SHADOW_WORD_PAIN: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_SHADOW_WORD_PAIN); + events.ScheduleEvent(EVENT_SHADOW_WORD_PAIN, 8000); + break; + case EVENT_CIRCLE_OF_DESTRUCTION: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_CIRCLE_OF_DESTRUCTION); + events.ScheduleEvent(EVENT_CIRCLE_OF_DESTRUCTION, 12000); + break; + case EVENT_COWER_IN_FEAR: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_COWER_IN_FEAR); + events.ScheduleEvent(EVENT_COWER_IN_FEAR, 10000); + break; + case EVENT_DARK_MENDING: + // find an ally with missing HP + if (Unit* target = DoSelectLowestHpFriendly(40, DUNGEON_MODE(30000, 50000))) + { + DoCast(target, SPELL_DARK_MENDING); + events.ScheduleEvent(EVENT_DARK_MENDING, 20000); + } + else + { + // no friendly unit with missing hp. re-check in just 5 sec. + events.ScheduleEvent(EVENT_DARK_MENDING, 5000); + } + break; } DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI(Creature* creature) const + { + return new npc_ghostly_priestAI(creature); + } }; class npc_phantom_mage : public CreatureScript @@ -713,22 +769,10 @@ class npc_phantom_mage : public CreatureScript public: npc_phantom_mage() : CreatureScript("npc_phantom_mage") { } - CreatureAI* GetAI(Creature* creature) const - { - return new npc_phantom_mageAI(creature); - } - - struct npc_phantom_mageAI: public ScriptedAI + struct npc_phantom_mageAI : public npc_gauntlet_trash { - npc_phantom_mageAI(Creature* creature) : ScriptedAI(creature) - { - } - - EventMap events; - - void Reset() + npc_phantom_mageAI(Creature* creature) : npc_gauntlet_trash(creature) { - events.Reset(); } void EnterCombat(Unit* /*who*/) @@ -750,39 +794,40 @@ public: if (me->HasUnitState(UNIT_STATE_CASTING)) return; - while (uint32 eventId = events.ExecuteEvent()) + switch (events.ExecuteEvent()) { - switch (eventId) - { - case EVENT_FIREBALL: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_FIREBALL); - events.ScheduleEvent(EVENT_FIREBALL, 15000); - return; - case EVENT_FLAMESTRIKE: - DoCast(SPELL_FLAMESTRIKE); - events.ScheduleEvent(EVENT_FLAMESTRIKE, 15000); - return; - case EVENT_FROSTBOLT: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_FROSTBOLT); - events.ScheduleEvent(EVENT_FROSTBOLT, 15000); - return; - case EVENT_CHAINS_OF_ICE: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_CHAINS_OF_ICE); - events.ScheduleEvent(EVENT_CHAINS_OF_ICE, 15000); - return; - case EVENT_HALLUCINATION: - DoCast(SPELL_HALLUCINATION); - return; - } + case EVENT_FIREBALL: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_FIREBALL); + events.ScheduleEvent(EVENT_FIREBALL, 15000); + break; + case EVENT_FLAMESTRIKE: + DoCast(SPELL_FLAMESTRIKE); + events.ScheduleEvent(EVENT_FLAMESTRIKE, 15000); + break; + case EVENT_FROSTBOLT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_FROSTBOLT); + events.ScheduleEvent(EVENT_FROSTBOLT, 15000); + break; + case EVENT_CHAINS_OF_ICE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_CHAINS_OF_ICE); + events.ScheduleEvent(EVENT_CHAINS_OF_ICE, 15000); + break; + case EVENT_HALLUCINATION: + DoCast(SPELL_HALLUCINATION); + break; } DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI(Creature* creature) const + { + return new npc_phantom_mageAI(creature); + } }; class npc_phantom_hallucination : public CreatureScript @@ -790,16 +835,9 @@ class npc_phantom_hallucination : public CreatureScript public: npc_phantom_hallucination() : CreatureScript("npc_phantom_hallucination") { } - CreatureAI* GetAI(Creature* creature) const - { - return new npc_phantom_hallucinationAI(creature); - } - struct npc_phantom_hallucinationAI : public npc_phantom_mage::npc_phantom_mageAI { - npc_phantom_hallucinationAI(Creature* creature) : npc_phantom_mage::npc_phantom_mageAI(creature) - { - } + npc_phantom_hallucinationAI(Creature* creature) : npc_phantom_mage::npc_phantom_mageAI(creature) {} void JustDied(Unit* /*killer*/) { @@ -807,6 +845,10 @@ public: } }; + CreatureAI* GetAI(Creature* creature) const + { + return new npc_phantom_hallucinationAI(creature); + } }; class npc_shadowy_mercenary : public CreatureScript @@ -814,22 +856,10 @@ class npc_shadowy_mercenary : public CreatureScript public: npc_shadowy_mercenary() : CreatureScript("npc_shadowy_mercenary") { } - CreatureAI* GetAI(Creature* creature) const + struct npc_shadowy_mercenaryAI : public npc_gauntlet_trash { - return new npc_shadowy_mercenaryAI(creature); - } - - struct npc_shadowy_mercenaryAI: public ScriptedAI - { - npc_shadowy_mercenaryAI(Creature* creature) : ScriptedAI(creature) - { - } - - EventMap events; - - void Reset() + npc_shadowy_mercenaryAI(Creature* creature) : npc_gauntlet_trash(creature) { - events.Reset(); } void EnterCombat(Unit* /*who*/) @@ -850,34 +880,35 @@ public: if (me->HasUnitState(UNIT_STATE_CASTING)) return; - while (uint32 eventId = events.ExecuteEvent()) + switch (events.ExecuteEvent()) { - switch (eventId) - { - case EVENT_SHADOW_STEP: - DoCast(SPELL_SHADOW_STEP); - events.ScheduleEvent(EVENT_SHADOW_STEP, 8000); - return; - case EVENT_DEADLY_POISON: - DoCast(me->getVictim(), SPELL_DEADLY_POISON); - events.ScheduleEvent(EVENT_DEADLY_POISON, 10000); - return; - case EVENT_ENVENOMED_DAGGER_THROW: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_ENVENOMED_DAGGER_THROW); - events.ScheduleEvent(EVENT_ENVENOMED_DAGGER_THROW, 10000); - return; - case EVENT_KIDNEY_SHOT: - DoCast(me->getVictim(), SPELL_KIDNEY_SHOT); - events.ScheduleEvent(EVENT_KIDNEY_SHOT, 10000); - return; - } + case EVENT_SHADOW_STEP: + DoCast(SPELL_SHADOW_STEP); + events.ScheduleEvent(EVENT_SHADOW_STEP, 8000); + break; + case EVENT_DEADLY_POISON: + DoCast(me->getVictim(), SPELL_DEADLY_POISON); + events.ScheduleEvent(EVENT_DEADLY_POISON, 10000); + break; + case EVENT_ENVENOMED_DAGGER_THROW: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_ENVENOMED_DAGGER_THROW); + events.ScheduleEvent(EVENT_ENVENOMED_DAGGER_THROW, 10000); + break; + case EVENT_KIDNEY_SHOT: + DoCast(me->getVictim(), SPELL_KIDNEY_SHOT); + events.ScheduleEvent(EVENT_KIDNEY_SHOT, 10000); + break; } DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI(Creature* creature) const + { + return new npc_shadowy_mercenaryAI(creature); + } }; class npc_spectral_footman : public CreatureScript @@ -885,29 +916,176 @@ class npc_spectral_footman : public CreatureScript public: npc_spectral_footman() : CreatureScript("npc_spectral_footman") { } + struct npc_spectral_footmanAI : public npc_gauntlet_trash + { + npc_spectral_footmanAI(Creature* creature) : npc_gauntlet_trash(creature) + { + } + + void EnterCombat(Unit* /*who*/) + { + events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5000); /// @todo adjust timers + events.ScheduleEvent(EVENT_SHIELD_BASH, 10000); + events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15000); + } + + void UpdateAI(uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_SPECTRAL_STRIKE: + DoCast(me->getVictim(), SPELL_SPECTRAL_STRIKE); + events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5000); + break; + case EVENT_SHIELD_BASH: + DoCast(me->getVictim(), SPELL_SHIELD_BASH); + events.ScheduleEvent(EVENT_SHIELD_BASH, 5000); + break; + case EVENT_TORTURED_ENRAGE: + DoCast(SPELL_TORTURED_ENRAGE); + events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15000); + break; + } + + DoMeleeAttackIfReady(); + } + }; + CreatureAI* GetAI(Creature* creature) const { return new npc_spectral_footmanAI(creature); } +}; + +class npc_tortured_rifleman : public CreatureScript +{ +public: + npc_tortured_rifleman() : CreatureScript("npc_tortured_rifleman") { } - struct npc_spectral_footmanAI: public ScriptedAI + struct npc_tortured_riflemanAI : public npc_gauntlet_trash { - npc_spectral_footmanAI(Creature* creature) : ScriptedAI(creature) + npc_tortured_riflemanAI(Creature* creature) : npc_gauntlet_trash(creature) { } + void EnterCombat(Unit* /*who*/) + { + events.ScheduleEvent(EVENT_SHOOT, 2000); /// @todo adjust timers + events.ScheduleEvent(EVENT_CURSED_ARROW, 10000); + events.ScheduleEvent(EVENT_FROST_TRAP, 1000); + events.ScheduleEvent(EVENT_ICE_SHOT, 15000); + } + + void UpdateAI(uint32 diff) + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + switch (events.ExecuteEvent()) + { + case EVENT_SHOOT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_SHOOT); + events.ScheduleEvent(EVENT_SHOOT, 2000); + break; + case EVENT_CURSED_ARROW: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_CURSED_ARROW); + events.ScheduleEvent(EVENT_CURSED_ARROW, 10000); + break; + case EVENT_FROST_TRAP: + DoCast(SPELL_FROST_TRAP); + events.ScheduleEvent(EVENT_FROST_TRAP, 30000); + break; + case EVENT_ICE_SHOT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_ICE_SHOT); + events.ScheduleEvent(EVENT_ICE_SHOT, 15000); + break; + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_tortured_riflemanAI(creature); + } +}; + + +enum GeneralEvents +{ + //General + EVENT_SHIELD = 0, + EVENT_SPIKE = 1, + EVENT_CLONE = 2, + + SAY_AGGRO = 0, + SAY_DEATH = 1, + + SPELL_SHIELD_THROWN = 69222, // 73076 on hc + SPELL_SPIKE = 69184, // 70399 on hc + SPELL_CLONE_NAME = 57507, + SPELL_CLONE_MODEL = 45204, + + // Reflection + EVENT_BALEFUL_STRIKE = 0, + + SPELL_BALEFUL_STRIKE = 69933, // 70400 on hc + SPELL_SPIRIT_BURST = 69900, // 73046 on hc +}; + +class npc_frostworn_general : public CreatureScript +{ +public: + npc_frostworn_general() : CreatureScript("npc_frostworn_general") { } + + struct npc_frostworn_generalAI : public ScriptedAI + { + npc_frostworn_generalAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + Reset(); + } + + InstanceScript* instance; + EventMap events; void Reset() { events.Reset(); + instance->SetData(DATA_FROSWORN_EVENT, NOT_STARTED); } - void EnterCombat(Unit* /*who*/) + void JustDied(Unit* /*killer*/) { - events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5000); /// @todo adjust timers - events.ScheduleEvent(EVENT_SHIELD_BASH, 10000); - events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15000); + Talk(SAY_DEATH); + instance->SetData(DATA_FROSWORN_EVENT, DONE); + } + + void EnterCombat(Unit* /*victim*/) + { + Talk(SAY_AGGRO); + events.ScheduleEvent(EVENT_SHIELD, 5000); + events.ScheduleEvent(EVENT_SPIKE, 14000); + events.ScheduleEvent(EVENT_CLONE, 22000); + instance->SetData(DATA_FROSWORN_EVENT, IN_PROGRESS); } void UpdateAI(uint32 diff) @@ -920,45 +1098,61 @@ public: if (me->HasUnitState(UNIT_STATE_CASTING)) return; - while (uint32 eventId = events.ExecuteEvent()) + switch (events.ExecuteEvent()) { - switch (eventId) - { - case EVENT_SPECTRAL_STRIKE: - DoCast(me->getVictim(), SPELL_SPECTRAL_STRIKE); - events.ScheduleEvent(EVENT_SPECTRAL_STRIKE, 5000); - return; - case EVENT_SHIELD_BASH: - DoCast(me->getVictim(), SPELL_SHIELD_BASH); - events.ScheduleEvent(EVENT_SHIELD_BASH, 5000); - return; - case EVENT_TORTURED_ENRAGE: - DoCast(SPELL_TORTURED_ENRAGE); - events.ScheduleEvent(EVENT_TORTURED_ENRAGE, 15000); - return; - } + case EVENT_SHIELD: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_SHIELD_THROWN); + events.ScheduleEvent(EVENT_SHIELD, urand(8000, 12000)); + break; + case EVENT_SPIKE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_SPIKE); + events.ScheduleEvent(EVENT_SPIKE, urand(15000, 20000)); + break; + case EVENT_CLONE: + SummonClones(); + events.ScheduleEvent(EVENT_CLONE, 60000); + break; } DoMeleeAttackIfReady(); } - }; -}; + void SummonClones() + { + std::list<Unit *> playerList; + SelectTargetList(playerList, 5, SELECT_TARGET_TOPAGGRO, 0, true); + for (std::list<Unit*>::const_iterator itr = playerList.begin(); itr != playerList.end(); ++itr) + { + Unit* temp = (*itr); + Creature* reflection = me->SummonCreature(NPC_REFLECTION, temp->GetPositionX(), temp->GetPositionY(), temp->GetPositionZ(), temp->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000); + reflection->SetName(temp->GetName()); + temp->CastSpell(reflection, SPELL_CLONE_NAME, true); + temp->CastSpell(reflection, SPELL_CLONE_MODEL, true); + reflection->setFaction(me->getFaction()); + reflection->AI()->AttackStart(temp); + } -class npc_tortured_rifleman : public CreatureScript -{ -public: - npc_tortured_rifleman() : CreatureScript("npc_tortured_rifleman") { } + } + }; CreatureAI* GetAI(Creature* creature) const { - return new npc_tortured_riflemanAI(creature); + return new npc_frostworn_generalAI(creature); } +}; + +class npc_spiritual_reflection : public CreatureScript +{ +public: + npc_spiritual_reflection() : CreatureScript("npc_spiritual_reflection") { } - struct npc_tortured_riflemanAI : public ScriptedAI + struct npc_spiritual_reflectionAI : public ScriptedAI { - npc_tortured_riflemanAI(Creature* creature) : ScriptedAI(creature) + npc_spiritual_reflectionAI(Creature *creature) : ScriptedAI(creature) { + Reset(); } EventMap events; @@ -968,12 +1162,14 @@ public: events.Reset(); } - void EnterCombat(Unit* /*who*/) + void EnterCombat(Unit* /*victim*/) { - events.ScheduleEvent(EVENT_SHOOT, 2000); /// @todo adjust timers - events.ScheduleEvent(EVENT_CURSED_ARROW, 10000); - events.ScheduleEvent(EVENT_FROST_TRAP, 1000); - events.ScheduleEvent(EVENT_ICE_SHOT, 15000); + events.ScheduleEvent(EVENT_BALEFUL_STRIKE, 3000); + } + + void JustDied(Unit* killer) + { + DoCast(killer, SPELL_SPIRIT_BURST); } void UpdateAI(uint32 diff) @@ -986,46 +1182,90 @@ public: if (me->HasUnitState(UNIT_STATE_CASTING)) return; - while (uint32 eventId = events.ExecuteEvent()) + switch (events.ExecuteEvent()) { - switch (eventId) - { - case EVENT_SHOOT: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_SHOOT); - events.ScheduleEvent(EVENT_SHOOT, 2000); - return; - case EVENT_CURSED_ARROW: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_CURSED_ARROW); - events.ScheduleEvent(EVENT_CURSED_ARROW, 10000); - return; - case EVENT_FROST_TRAP: - DoCast(SPELL_FROST_TRAP); - events.ScheduleEvent(EVENT_FROST_TRAP, 30000); - return; - case EVENT_ICE_SHOT: - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) - DoCast(target, SPELL_ICE_SHOT); - events.ScheduleEvent(EVENT_ICE_SHOT, 15000); - return; - } + case EVENT_BALEFUL_STRIKE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_BALEFUL_STRIKE); + events.ScheduleEvent(EVENT_BALEFUL_STRIKE, urand(3000, 8000)); } DoMeleeAttackIfReady(); } }; + CreatureAI* GetAI(Creature* creature) const + { + return new npc_spiritual_reflectionAI(creature); + } +}; + +class at_hor_intro_start : public AreaTriggerScript +{ +public: + at_hor_intro_start() : AreaTriggerScript("at_hor_intro_start") {} + + bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) + { + InstanceScript* instance = player->GetInstanceScript(); + + if (player->isGameMaster()) + return true; + + if (instance->GetData(DATA_INTRO_EVENT) == NOT_STARTED) + { + instance->SetData(DATA_INTRO_EVENT, IN_PROGRESS); + } + + return true; + } +}; + +class at_hor_waves_restarter : public AreaTriggerScript +{ +public: + at_hor_waves_restarter() : AreaTriggerScript("at_hor_waves_restarter") {} + + bool OnTrigger(Player* player, AreaTriggerEntry const* /*trigger*/) + { + InstanceScript* instance = player->GetInstanceScript(); + + if (player->isGameMaster()) + return true; + + if (instance->GetData(DATA_WAVE_COUNT)) + return true; + + if (instance->GetData(DATA_INTRO_EVENT) == DONE && instance->GetBossState(DATA_MARWYN_EVENT) != DONE) + { + instance->ProcessEvent(0, EVENT_SPAWN_WAVES); + + if (Creature* falric = player->GetCreature(*player, instance->GetData64(DATA_FALRIC_EVENT))) + { + falric->CastSpell(falric, SPELL_BOSS_SPAWN_AURA, true); + falric->SetVisible(true); + } + if (Creature* marwyn = player->GetCreature(*player, instance->GetData64(DATA_MARWYN_EVENT))) + { + marwyn->CastSpell(marwyn, SPELL_BOSS_SPAWN_AURA, true); + marwyn->SetVisible(true); + } + } + return true; + } }; void AddSC_halls_of_reflection() { - new npc_jaina_or_sylvanas_hor(true, "npc_sylvanas_hor_part1"); - new npc_jaina_or_sylvanas_hor(false, "npc_jaina_hor_part1"); + new npc_jaina_or_sylvanas_hor(); new npc_ghostly_priest(); new npc_phantom_mage(); new npc_phantom_hallucination(); new npc_shadowy_mercenary(); new npc_spectral_footman(); new npc_tortured_rifleman(); + new at_hor_intro_start(); + new at_hor_waves_restarter(); + new npc_frostworn_general(); + new npc_spiritual_reflection(); } diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h index 2cab1cca214..4787a6b9fdc 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.h @@ -18,54 +18,83 @@ #ifndef DEF_HALLS_OF_REFLECTION_H #define DEF_HALLS_OF_REFLECTION_H -enum Data -{ - DATA_FALRIC_EVENT, - DATA_MARWYN_EVENT, - DATA_LICHKING_EVENT, - DATA_WAVE_COUNT, - DATA_TEAM_IN_INSTANCE, -}; +#define HoRScriptName "instance_halls_of_reflection" +#define MAX_ENCOUNTER 3 -enum Data64 +/* Halls of Reflection encounters: +0- Falric +1- Marwyn +2- The Lich King +*/ + +enum Data { - DATA_FALRIC, - DATA_MARWYN, - DATA_LICHKING, - DATA_FROSTMOURNE, + DATA_FALRIC_EVENT = 0, + DATA_MARWYN_EVENT = 1, + DATA_LICHKING_EVENT = 2, + DATA_INTRO_EVENT = 3, + DATA_FROSWORN_EVENT = 4, + + DATA_WAVE_COUNT = 5, + DATA_TEAM_IN_INSTANCE = 6, + DATA_FROSTMOURNE = 7, + DATA_FROSTWORN_DOOR = 8, }; enum Creatures { - NPC_FALRIC = 38112, - NPC_MARWYN = 38113, - NPC_LICH_KING_EVENT = 37226, - NPC_LICH_KING_BOSS = 36954, - - NPC_UTHER = 37225, NPC_JAINA_PART1 = 37221, - NPC_JAINA_PART2 = 36955, NPC_SYLVANAS_PART1 = 37223, - NPC_SYLVANAS_PART2 = 37554, + NPC_UTHER = 37225, + NPC_LICH_KING_PART1 = 37226, + NPC_LORALEN = 37779, + NPC_KORELN = 37582, + NPC_FALRIC = 38112, + NPC_MARWYN = 38113, NPC_WAVE_MERCENARY = 38177, NPC_WAVE_FOOTMAN = 38173, NPC_WAVE_RIFLEMAN = 38176, NPC_WAVE_PRIEST = 38175, NPC_WAVE_MAGE = 38172, + + NPC_FROSTWORN_GENERAL = 36723, + NPC_REFLECTION = 37068, // 37107 for tank only? + + NPC_JAINA_PART2 = 36955, + NPC_SYLVANAS_PART2 = 37554, + NPC_LICH_KING_PART2 = 36954, + NPC_BARTLETT = 37182, // High Captain Justin Bartlett + NPC_KORM = 37833, // Sky-Reaver Korm Blackscar + NPC_ICE_WALL = 37014, // Ice Wall Target }; enum GameObjects { GO_FROSTMOURNE = 202302, - GO_FROSTMOURNE_ALTAR = 202236, - GO_FRONT_DOOR = 201976, - GO_ARTHAS_DOOR = 197341, + GO_ENTRANCE_DOOR = 201976, + GO_FROSTWORN_DOOR = 197341, + GO_ARTHAS_DOOR = 197342, + //GO_ESCAPE_DOOR = 197343, // always open ? + + GO_ICE_WALL = 201385, + GO_CAVE = 201596, + + GO_STAIRS_SKYBREAKER = 201709, + GO_SKYBREAKER = 201598, + GO_STAIRS_ORGRIM_HAMMER = 202211, + GO_ORGRIM_HAMMER = 201599, + GO_PORTAL = 202079, + + GO_CAPTAIN_CHEST_1 = 202212, //3145 + GO_CAPTAIN_CHEST_2 = 201710, //30357 + GO_CAPTAIN_CHEST_3 = 202337, //3246 + GO_CAPTAIN_CHEST_4 = 202336, //3333 }; enum HorWorldStates { - WORLD_STATE_HOR = 4884, + WORLD_STATE_HOR_WAVES_ENABLED = 4884, WORLD_STATE_HOR_WAVE_COUNT = 4882, }; @@ -75,6 +104,21 @@ enum Actions ACTION_ENTER_COMBAT, }; +enum TrashGeneralSpells +{ + // General spells + SPELL_WELL_OF_SOULS = 72630, // cast when spawn(become visible) + SPELL_SPIRIT_ACTIVATE = 72130, // cast when unit activates +}; + +enum InstanceEvents +{ + EVENT_SPAWN_WAVES = 1, + EVENT_NEXT_WAVE = 2, + EVENT_DO_WIPE = 3, + EVENT_ADD_WAVE = 4, +}; + // Base class for FALRIC and MARWYN // handled the summonList and the notification events to/from the InstanceScript struct boss_horAI : ScriptedAI @@ -92,14 +136,10 @@ struct boss_horAI : ScriptedAI { events.Reset(); me->SetVisible(false); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC); me->SetReactState(REACT_PASSIVE); - } - - void DamageTaken(Unit* /*who*/, uint32 &uiDamage) - { - if (me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)) - uiDamage = 0; + if (instance->GetData(DATA_WAVE_COUNT) != NOT_STARTED) + instance->ProcessEvent(0, EVENT_DO_WIPE); } void DoAction(int32 actionID) @@ -107,11 +147,7 @@ struct boss_horAI : ScriptedAI switch (actionID) { case ACTION_ENTER_COMBAT: // called by InstanceScript when boss shall enter in combat. - // Just in case. Should have been done by InstanceScript - me->SetVisible(true); - - // Reset flags - me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_NOT_SELECTABLE); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC); me->SetReactState(REACT_AGGRESSIVE); if (Unit* unit = me->SelectNearestTarget()) @@ -125,32 +161,6 @@ struct boss_horAI : ScriptedAI void JustSummoned(Creature* summoned) { summons.Summon(summoned); - - if (Unit* target = summoned->SelectNearestTarget()) - { - if (summoned->AI()) - summoned->AI()->AttackStart(target); - else - { - summoned->GetMotionMaster()->MoveChase(target); - summoned->Attack(target, true); - } - } - - if (summoned->AI()) - summoned->AI()->DoZoneInCombat(); - } - - void SummonedCreatureDespawn(Creature* summoned) - { - summons.Despawn(summoned); - if (summons.empty()) - { - if (summoned->isAlive()) - instance->SetData(DATA_WAVE_COUNT, NOT_STARTED); - else - instance->SetData(DATA_WAVE_COUNT, SPECIAL); - } } }; diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp index dde3f7acc67..bff18b508d5 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp @@ -18,85 +18,50 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "InstanceScript.h" -#include "halls_of_reflection.h" #include "Player.h" +#include "WorldPacket.h" +#include "halls_of_reflection.h" -#define MAX_ENCOUNTER 3 - -/* Halls of Reflection encounters: -0- Falric -1- Marwyn -2- The Lich King -*/ - -enum eEnum -{ - ENCOUNTER_WAVE_MERCENARY = 6, - ENCOUNTER_WAVE_FOOTMAN = 10, - ENCOUNTER_WAVE_RIFLEMAN = 6, - ENCOUNTER_WAVE_PRIEST = 6, - ENCOUNTER_WAVE_MAGE = 6, -}; - -enum Events -{ - EVENT_NONE, - EVENT_NEXT_WAVE, - EVENT_START_LICH_KING, -}; - -static Position PriestSpawnPos[ENCOUNTER_WAVE_PRIEST] = -{ - {5277.74f, 2016.88f, 707.778f, 5.96903f}, - {5295.88f, 2040.34f, 707.778f, 5.07891f}, - {5320.37f, 1980.13f, 707.778f, 2.00713f}, - {5280.51f, 1997.84f, 707.778f, 0.296706f}, - {5302.45f, 2042.22f, 707.778f, 4.90438f}, - {5306.57f, 1977.47f, 707.778f, 1.50098f}, -}; - -static Position MageSpawnPos[ENCOUNTER_WAVE_MAGE] = -{ - {5312.75f, 2037.12f, 707.778f, 4.59022f}, - {5309.58f, 2042.67f, 707.778f, 4.69494f}, - {5275.08f, 2008.72f, 707.778f, 6.21337f}, - {5279.65f, 2004.66f, 707.778f, 0.069813f}, - {5275.48f, 2001.14f, 707.778f, 0.174533f}, - {5316.7f, 2041.55f, 707.778f, 4.50295f}, -}; - -static Position MercenarySpawnPos[ENCOUNTER_WAVE_MERCENARY] = -{ - {5302.25f, 1972.41f, 707.778f, 1.37881f}, - {5311.03f, 1972.23f, 707.778f, 1.64061f}, - {5277.36f, 1993.23f, 707.778f, 0.401426f}, - {5318.7f, 2036.11f, 707.778f, 4.2237f}, - {5335.72f, 1996.86f, 707.778f, 2.74017f}, - {5299.43f, 1979.01f, 707.778f, 1.23918f}, -}; +Position const JainaSpawnPos = {5236.659f, 1929.894f, 707.7781f, 0.8726646f}; // Jaina Spawn Position +Position const SylvanasSpawnPos = {5236.667f, 1929.906f, 707.7781f, 0.8377581f}; // Sylvanas Spawn Position +Position const GeneralSpawnPos = {5415.538f, 2117.842f, 707.7781f, 3.944444f}; // Frostsworn General -static Position FootmenSpawnPos[ENCOUNTER_WAVE_FOOTMAN] = +Position const SpawnPos[] = { - {5306.06f, 2037, 707.778f, 4.81711f}, - {5344.15f, 2007.17f, 707.778f, 3.15905f}, - {5337.83f, 2010.06f, 707.778f, 3.22886f}, - {5343.29f, 1999.38f, 707.778f, 2.9147f}, - {5340.84f, 1992.46f, 707.778f, 2.75762f}, - {5325.07f, 1977.6f, 707.778f, 2.07694f}, - {5336.6f, 2017.28f, 707.778f, 3.47321f}, - {5313.82f, 1978.15f, 707.778f, 1.74533f}, - {5280.63f, 2012.16f, 707.778f, 6.05629f}, - {5322.96f, 2040.29f, 707.778f, 4.34587f}, -}; - -static Position RiflemanSpawnPos[ENCOUNTER_WAVE_RIFLEMAN] = -{ - {5343.47f, 2015.95f, 707.778f, 3.49066f}, - {5337.86f, 2003.4f, 707.778f, 2.98451f}, - {5319.16f, 1974, 707.778f, 1.91986f}, - {5299.25f, 2036, 707.778f, 5.02655f}, - {5295.64f, 1973.76f, 707.778f, 1.18682f}, - {5282.9f, 2019.6f, 707.778f, 5.88176f}, + {5309.577f, 2042.668f, 707.7781f, 4.694936f}, + {5295.885f, 2040.342f, 707.7781f, 5.078908f}, + {5340.836f, 1992.458f, 707.7781f, 2.757620f}, + {5325.072f, 1977.597f, 707.7781f, 2.076942f}, + {5277.365f, 1993.229f, 707.7781f, 0.401426f}, + {5275.479f, 2001.135f, 707.7781f, 0.174533f}, + {5302.448f, 2042.222f, 707.7781f, 4.904375f}, + {5343.293f, 1999.384f, 707.7781f, 2.914700f}, + {5295.635f, 1973.757f, 707.7781f, 1.186824f}, + {5311.031f, 1972.229f, 707.7781f, 1.640610f}, + {5275.076f, 2008.724f, 707.7781f, 6.213372f}, + {5316.701f, 2041.550f, 707.7781f, 4.502949f}, + {5344.150f, 2007.168f, 707.7781f, 3.159046f}, + {5319.158f, 1973.998f, 707.7781f, 1.919862f}, + {5302.247f, 1972.415f, 707.7781f, 1.378810f}, + {5277.739f, 2016.882f, 707.7781f, 5.969026f}, + {5322.964f, 2040.288f, 707.7781f, 4.345870f}, + {5343.467f, 2015.951f, 707.7781f, 3.490659f}, + {5313.820f, 1978.146f, 707.7781f, 1.745329f}, + {5279.649f, 2004.656f, 707.7781f, 0.069814f}, + {5306.057f, 2037.002f, 707.7781f, 4.817109f}, + {5337.865f, 2003.403f, 707.7781f, 2.984513f}, + {5299.434f, 1979.009f, 707.7781f, 1.239184f}, + {5312.752f, 2037.122f, 707.7781f, 4.590216f}, + {5335.724f, 1996.859f, 707.7781f, 2.740167f}, + {5280.632f, 2012.156f, 707.7781f, 6.056293f}, + {5320.369f, 1980.125f, 707.7781f, 2.007129f}, + {5306.572f, 1977.474f, 707.7781f, 1.500983f}, + {5336.599f, 2017.278f, 707.7781f, 3.473205f}, + {5282.897f, 2019.597f, 707.7781f, 5.881760f}, + {5318.704f, 2036.108f, 707.7781f, 4.223697f}, + {5280.513f, 1997.842f, 707.7781f, 0.296706f}, + {5337.833f, 2010.057f, 707.7781f, 3.228859f}, + {5299.250f, 2035.998f, 707.7781f, 5.026548f}, }; class instance_halls_of_reflection : public InstanceMapScript @@ -104,107 +69,107 @@ class instance_halls_of_reflection : public InstanceMapScript public: instance_halls_of_reflection() : InstanceMapScript("instance_halls_of_reflection", 668) { } - InstanceScript* GetInstanceScript(InstanceMap* map) const - { - return new instance_halls_of_reflection_InstanceMapScript(map); - } - struct instance_halls_of_reflection_InstanceMapScript : public InstanceScript { - instance_halls_of_reflection_InstanceMapScript(Map* map) : InstanceScript(map) {}; - - uint64 uiFalric; - uint64 uiMarwyn; - uint64 uiLichKingEvent; - uint64 uiJainaPart1; - uint64 uiSylvanasPart1; - - uint64 uiFrostmourne; - uint64 uiFrostmourneAltar; - uint64 uiArthasDoor; - uint64 uiFrontDoor; - - uint32 uiEncounter[MAX_ENCOUNTER]; - uint32 uiTeamInInstance; - uint32 uiWaveCount; - bool bIntroDone; - - EventMap events; + instance_halls_of_reflection_InstanceMapScript(Map* map) : InstanceScript(map) {} void Initialize() { + SetBossNumber(MAX_ENCOUNTER); events.Reset(); + _falricGUID = 0; + _marwynGUID = 0; + _jainaOrSylvanasPart1GUID = 0; + _frostwornGeneralGUID = 0; + _frostmourneGUID = 0; + _entranceDoorGUID = 0; + _frostwornDoorGUID = 0; + _arthasDoorGUID = 0; + _teamInInstance = 0; + _waveCount = 0; + _introEvent = NOT_STARTED; + _frostwornGeneral = NOT_STARTED; + } - uiFalric = 0; - uiMarwyn = 0; - uiLichKingEvent = 0; - uiJainaPart1 = 0; - uiSylvanasPart1 = 0; - - uiFrostmourne = 0; - uiFrostmourneAltar = 0; - uiArthasDoor = 0; - uiFrontDoor = 0; - uiTeamInInstance = 0; - uiWaveCount = 0; - bIntroDone = false; - - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - uiEncounter[i] = NOT_STARTED; + void OnPlayerEnter(Player* player) + { + if (!_teamInInstance) + _teamInInstance = player->GetTeam(); } void OnCreatureCreate(Creature* creature) { - Map::PlayerList const &players = instance->GetPlayers(); + Map::PlayerList const& players = instance->GetPlayers(); if (!players.isEmpty()) if (Player* player = players.begin()->getSource()) - uiTeamInInstance = player->GetTeam(); + _teamInInstance = player->GetTeam(); switch (creature->GetEntry()) { + case NPC_JAINA_PART1: + case NPC_SYLVANAS_PART1: + _jainaOrSylvanasPart1GUID = creature->GetGUID(); + break; case NPC_FALRIC: - uiFalric = creature->GetGUID(); + _falricGUID = creature->GetGUID(); break; case NPC_MARWYN: - uiMarwyn = creature->GetGUID(); - break; - case NPC_LICH_KING_EVENT: - uiLichKingEvent = creature->GetGUID(); + _marwynGUID = creature->GetGUID(); break; - case NPC_JAINA_PART1: - uiJainaPart1 = creature->GetGUID(); + case NPC_FROSTWORN_GENERAL: + _frostwornGeneralGUID = creature->GetGUID(); + if (GetBossState(DATA_MARWYN_EVENT) == DONE) + if (Creature* general = instance->GetCreature(_frostwornGeneralGUID)) + general->SetPhaseMask(1, true); break; - case NPC_SYLVANAS_PART1: - uiSylvanasPart1 = creature->GetGUID(); + } + } + + void OnCreatureRemove(Creature* creature) + { + switch (creature->GetEntry()) + { + case NPC_WAVE_MERCENARY: + case NPC_WAVE_FOOTMAN: + case NPC_WAVE_RIFLEMAN: + case NPC_WAVE_PRIEST: + case NPC_WAVE_MAGE: + { + uint32 internalWaveId = creature->AI()->GetData(0); + waveGuidList[internalWaveId].erase(creature->GetGUID()); break; + } } } void OnGameObjectCreate(GameObject* go) { - /// @todo init state depending on encounters switch (go->GetEntry()) { case GO_FROSTMOURNE: - uiFrostmourne = go->GetGUID(); + _frostmourneGUID = go->GetGUID(); go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); HandleGameObject(0, false, go); + if (GetData(DATA_INTRO_EVENT) == DONE) + go->SetPhaseMask(2, true); break; - case GO_FROSTMOURNE_ALTAR: - uiFrostmourneAltar = go->GetGUID(); + case GO_ENTRANCE_DOOR: + _entranceDoorGUID = go->GetGUID(); go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); HandleGameObject(0, true, go); break; - case GO_FRONT_DOOR: - uiFrontDoor = go->GetGUID(); + case GO_FROSTWORN_DOOR: + _frostwornDoorGUID = go->GetGUID(); go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); - HandleGameObject(0, true, go); + if (GetBossState(DATA_MARWYN_EVENT) == DONE) + HandleGameObject(0, true, go); + else + HandleGameObject(0, false, go); break; case GO_ARTHAS_DOOR: - uiArthasDoor = go->GetGUID(); + _arthasDoorGUID = go->GetGUID(); go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); - - if (uiEncounter[1] == DONE) + if (GetBossState(DATA_FROSWORN_EVENT) == DONE) HandleGameObject(0, true, go); else HandleGameObject(0, false, go); @@ -212,61 +177,273 @@ public: } } - void SetData(uint32 type, uint32 data) + void FillInitialWorldStates(WorldPacket& data) { - if (type == DATA_WAVE_COUNT && data == SPECIAL) - { - bIntroDone = true; - events.ScheduleEvent(EVENT_NEXT_WAVE, 10000); - return; - } + data << uint32(WORLD_STATE_HOR_WAVES_ENABLED) << uint32(0); + data << uint32(WORLD_STATE_HOR_WAVE_COUNT) << uint32(0); + } - if (uiWaveCount && data == NOT_STARTED) - DoWipe(); + bool SetBossState(uint32 type, EncounterState state) + { + if (!InstanceScript::SetBossState(type, state)) + return false; switch (type) { case DATA_FALRIC_EVENT: - uiEncounter[0] = data; - if (data == DONE) + if (state == DONE) + { + ++_waveCount; events.ScheduleEvent(EVENT_NEXT_WAVE, 60000); + } break; case DATA_MARWYN_EVENT: - uiEncounter[1] = data; - if (data == DONE) - HandleGameObject(uiArthasDoor, true); + if (state == DONE) + { + HandleGameObject(_entranceDoorGUID, true); + HandleGameObject(_frostwornDoorGUID, true); + if (Creature* general = instance->GetCreature(_frostwornGeneralGUID)) + general->SetPhaseMask(1, true); + } break; case DATA_LICHKING_EVENT: - uiEncounter[2] = data; break; + default: + break; + } + + return true; + } + + void SetData(uint32 type, uint32 data) + { + switch (type) + { + case DATA_INTRO_EVENT: + if (data == IN_PROGRESS) + { + if (!_introEvent) + { + if (_teamInInstance == ALLIANCE) + instance->SummonCreature(NPC_JAINA_PART1, JainaSpawnPos); + else + instance->SummonCreature(NPC_SYLVANAS_PART1, SylvanasSpawnPos); + } + } + _introEvent = data; + break; + case DATA_WAVE_COUNT: + if (_waveCount && data == NOT_STARTED) + ProcessEvent(NULL, EVENT_DO_WIPE); + break; + case DATA_FROSWORN_EVENT: + if (data == DONE) + { + HandleGameObject(_arthasDoorGUID, true); + // spawn Jaina part 2 + // spawn LK part 2 + } + _frostwornGeneral = data; + break; + } + + SaveToDB(); + } + + + // wave scheduling,checked when wave npcs die + void OnUnitDeath(Unit* unit) + { + Creature* creature = unit->ToCreature(); + if (!creature) + return; + + switch (creature->GetEntry()) + { + case NPC_WAVE_MERCENARY: + case NPC_WAVE_FOOTMAN: + case NPC_WAVE_RIFLEMAN: + case NPC_WAVE_PRIEST: + case NPC_WAVE_MAGE: + { + uint32 deadNpcs = 0; + uint32 waveId = creature->AI()->GetData(0); + for (std::set<uint64>::const_iterator itr = waveGuidList[waveId].begin(); itr != waveGuidList[waveId].end(); ++itr) + { + Creature* npc = instance->GetCreature(*itr); + if (!npc || !npc->isAlive()) + ++deadNpcs; + } + + // because the current npc returns isAlive when OnUnitDeath happens + // we check if the number of dead npcs is equal to the list-1 + if (deadNpcs == waveGuidList[waveId].size() - 1) + { + ++_waveCount; + events.ScheduleEvent(EVENT_NEXT_WAVE, 10000); + } + break; + } } + } + + void Update(uint32 diff) + { + if (!instance->HavePlayers()) + return; - if (data == DONE) - SaveToDB(); + events.Update(diff); + + switch (events.ExecuteEvent()) + { + case EVENT_NEXT_WAVE: + ProcessEvent(NULL, EVENT_ADD_WAVE); + break; + } + } + + void ProcessEvent(WorldObject* /*go*/, uint32 eventId) + { + switch (eventId) + { + // spawning all wave npcs at once + case EVENT_SPAWN_WAVES: + _waveCount = 1; + DoUpdateWorldState(WORLD_STATE_HOR_WAVES_ENABLED, 1); + DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, _waveCount); + { + std::list<uint32> possibilityList, tempList; + uint32 posIndex = 0; + + possibilityList.push_back(NPC_WAVE_MERCENARY); + possibilityList.push_back(NPC_WAVE_FOOTMAN); + possibilityList.push_back(NPC_WAVE_RIFLEMAN); + possibilityList.push_back(NPC_WAVE_PRIEST); + possibilityList.push_back(NPC_WAVE_MAGE); + + // iterate each wave + for (uint8 i = 0; i < 8; ++i) + { + tempList = possibilityList; + + uint64 bossGuid = i <= 3 ? _falricGUID : _marwynGUID; + + if (!i) + Trinity::Containers::RandomResizeList(tempList, 3); + else if (i < 6 && i != 3) + Trinity::Containers::RandomResizeList(tempList, 4); + + for (std::list<uint32>::const_iterator itr = tempList.begin(); itr != tempList.end(); ++itr) + { + if (Creature* boss = instance->GetCreature(bossGuid)) + { + if (Creature* temp = boss->SummonCreature(*itr, SpawnPos[posIndex], TEMPSUMMON_DEAD_DESPAWN)) + { + temp->AI()->SetData(0, i); + waveGuidList[i].insert(temp->GetGUID()); + } + } + + ++posIndex; + } + } + } + events.ScheduleEvent(EVENT_NEXT_WAVE, 10000); + break; + case EVENT_ADD_WAVE: + DoUpdateWorldState(WORLD_STATE_HOR_WAVES_ENABLED, 1); + DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, _waveCount); + HandleGameObject(_entranceDoorGUID, false); + + if (_waveCount % 5) + { + uint32 internalWaveId = _waveCount - ((_waveCount < 5) ? 1 : 2); + for (std::set<uint64>::const_iterator itr = waveGuidList[internalWaveId].begin(); itr != waveGuidList[internalWaveId].end(); ++itr) + { + if (Creature* temp = instance->GetCreature(*itr)) + { + temp->CastSpell(temp, SPELL_SPIRIT_ACTIVATE, true); + temp->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC|UNIT_FLAG_NOT_SELECTABLE); + temp->AI()->DoZoneInCombat(); + } + } + } + else + { + uint32 bossIndex = (_waveCount / 5) - 1; + if (GetBossState(DATA_FALRIC_EVENT + bossIndex) != DONE) + { + if (Creature* boss = instance->GetCreature(bossIndex ? _marwynGUID : _falricGUID)) + if (boss->AI()) + boss->AI()->DoAction(ACTION_ENTER_COMBAT); + } + else if (_waveCount != 10) + { + ++_waveCount; + events.ScheduleEvent(EVENT_NEXT_WAVE, 10000); + } + } + break; + case EVENT_DO_WIPE: + _waveCount = 0; + events.Reset(); + DoUpdateWorldState(WORLD_STATE_HOR_WAVES_ENABLED, 1); + DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, _waveCount); + HandleGameObject(_entranceDoorGUID, true); + + if (Creature* falric = instance->GetCreature(_falricGUID)) + falric->SetVisible(false); + if (Creature* marwyn = instance->GetCreature(_marwynGUID)) + marwyn->SetVisible(false); + + //despawn wave npcs + for (uint8 i = 0; i < 8; ++i) + { + for (std::set<uint64>::const_iterator itr = waveGuidList[i].begin(); itr != waveGuidList[i].end(); ++itr) + if (Creature* creature = instance->GetCreature(*itr)) + creature->DespawnOrUnsummon(1); + + waveGuidList[i].clear(); + } + break; + } } uint32 GetData(uint32 type) const { switch (type) { - case DATA_FALRIC_EVENT: return uiEncounter[0]; - case DATA_MARWYN_EVENT: return uiEncounter[1]; - case DATA_LICHKING_EVENT: return uiEncounter[2]; - case DATA_WAVE_COUNT: return uiWaveCount; - case DATA_TEAM_IN_INSTANCE: return uiTeamInInstance; + case DATA_WAVE_COUNT: + return _waveCount; + case DATA_TEAM_IN_INSTANCE: + return _teamInInstance; + case DATA_INTRO_EVENT: + return _introEvent; + case DATA_FROSWORN_EVENT: + return _frostwornGeneral; + default: + break; } return 0; } - uint64 GetData64(uint32 identifier) const + uint64 GetData64(uint32 type) const { - switch (identifier) + switch (type) { - case DATA_FALRIC: return uiFalric; - case DATA_MARWYN: return uiMarwyn; - case DATA_LICHKING: return uiLichKingEvent; - case DATA_FROSTMOURNE: return uiFrostmourne; + case DATA_FALRIC_EVENT: + return _falricGUID; + case DATA_MARWYN_EVENT: + return _marwynGUID; + case DATA_FROSWORN_EVENT: + return _frostwornGeneralGUID; + case DATA_FROSTWORN_DOOR: + return _frostwornDoorGUID; + case DATA_FROSTMOURNE: + return _frostmourneGUID; + default: + break; } return 0; @@ -277,13 +454,13 @@ public: OUT_SAVE_INST_DATA; std::ostringstream saveStream; - saveStream << "H R 1 " << uiEncounter[0] << ' ' << uiEncounter[1] << ' ' << uiEncounter[2]; + saveStream << "H R " << GetBossSaveData() << _introEvent << ' ' << _frostwornGeneral; OUT_SAVE_INST_DATA_COMPLETE; return saveStream.str(); } - void Load(const char* in) + void Load(char const* in) { if (!in) { @@ -294,135 +471,67 @@ public: OUT_LOAD_INST_DATA(in); char dataHead1, dataHead2; - uint16 version; - uint16 data0, data1, data2; std::istringstream loadStream(in); - loadStream >> dataHead1 >> dataHead2 >> version >> data0 >> data1 >> data2; + loadStream >> dataHead1 >> dataHead2; if (dataHead1 == 'H' && dataHead2 == 'R') { - uiEncounter[0] = data0; - uiEncounter[1] = data1; - uiEncounter[2] = data2; - for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) - if (uiEncounter[i] == IN_PROGRESS) - uiEncounter[i] = NOT_STARTED; - - } else OUT_LOAD_INST_DATA_FAIL; - - if (uiEncounter[0] == DONE || uiEncounter[1] == DONE) - bIntroDone = true; - - OUT_LOAD_INST_DATA_COMPLETE; - } - - void AddWave() - { - DoUpdateWorldState(WORLD_STATE_HOR, 1); - DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, uiWaveCount); - - switch (uiWaveCount) - { - case 1: - case 2: - case 3: - case 4: - if (Creature* pFalric = instance->GetCreature(uiFalric)) - SpawnWave(pFalric); - break; - case 5: - if (GetData(DATA_FALRIC_EVENT) == DONE) - events.ScheduleEvent(EVENT_NEXT_WAVE, 10000); - else if (Creature* pFalric = instance->GetCreature(uiFalric)) - if (pFalric->AI()) - pFalric->AI()->DoAction(ACTION_ENTER_COMBAT); - break; - case 6: - case 7: - case 8: - case 9: - if (Creature* pMarwyn = instance->GetCreature(uiMarwyn)) - SpawnWave(pMarwyn); - break; - case 10: - if (GetData(DATA_MARWYN_EVENT) != DONE) // wave should not have been started if DONE. Check anyway to avoid bug exploit! - if (Creature* pMarwyn = instance->GetCreature(uiMarwyn)) - if (pMarwyn->AI()) - pMarwyn->AI()->DoAction(ACTION_ENTER_COMBAT); - break; + { + uint32 tmpState; + loadStream >> tmpState; + if (tmpState == IN_PROGRESS || tmpState > SPECIAL) + tmpState = NOT_STARTED; + + SetBossState(i, EncounterState(tmpState)); + } + + uint32 temp = 0; + loadStream >> temp; + if (temp == DONE) + SetData(DATA_INTRO_EVENT, DONE); + else + SetData(DATA_INTRO_EVENT, NOT_STARTED); + + loadStream >> temp; + if (temp == DONE) + SetData(DATA_FROSWORN_EVENT, DONE); + else + SetData(DATA_FROSWORN_EVENT, NOT_STARTED); } - } + else + OUT_LOAD_INST_DATA_FAIL; - // Wipe has been detected. Perform cleanup and reset. - void DoWipe() - { - uiWaveCount = 0; - events.Reset(); - DoUpdateWorldState(WORLD_STATE_HOR, 1); - DoUpdateWorldState(WORLD_STATE_HOR_WAVE_COUNT, uiWaveCount); - HandleGameObject(uiFrontDoor, true); - - /// @todo - // in case of wipe, the event is normally restarted by jumping into the center of the room. - // As I can't find a trigger area there, just respawn Jaina/Sylvanas so the event may be restarted. - if (Creature* pJaina = instance->GetCreature(uiJainaPart1)) - pJaina->Respawn(); - if (Creature* pSylvanas = instance->GetCreature(uiSylvanasPart1)) - pSylvanas->Respawn(); - - if (Creature* pFalric = instance->GetCreature(uiFalric)) - pFalric->SetVisible(false); - if (Creature* pMarwyn = instance->GetCreature(uiMarwyn)) - pMarwyn->SetVisible(false); + OUT_LOAD_INST_DATA_COMPLETE; } - // spawn a wave on behalf of the summoner. - void SpawnWave(Creature* summoner) - { - uint32 index; - - summoner->SetVisible(true); - - /// @todo do composition at random. # of spawn also depends on uiWaveCount - // As of now, it is just one of each. - index = urand(0, ENCOUNTER_WAVE_MERCENARY-1); - summoner->SummonCreature(NPC_WAVE_MERCENARY, MercenarySpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); - - index = urand(0, ENCOUNTER_WAVE_FOOTMAN-1); - summoner->SummonCreature(NPC_WAVE_FOOTMAN, FootmenSpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); - - index = urand(0, ENCOUNTER_WAVE_RIFLEMAN-1); - summoner->SummonCreature(NPC_WAVE_RIFLEMAN, RiflemanSpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); + private: + uint64 _falricGUID; + uint64 _marwynGUID; + uint64 _jainaOrSylvanasPart1GUID; + uint64 _frostwornGeneralGUID; - index = urand(0, ENCOUNTER_WAVE_PRIEST-1); - summoner->SummonCreature(NPC_WAVE_PRIEST, PriestSpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); + uint64 _frostmourneGUID; + uint64 _entranceDoorGUID; + uint64 _frostwornDoorGUID; + uint64 _arthasDoorGUID; + uint64 _escapeDoorGUID; - index = urand(0, ENCOUNTER_WAVE_MAGE-1); - summoner->SummonCreature(NPC_WAVE_MAGE, MageSpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0); - } - - void Update(uint32 diff) - { - if (!instance->HavePlayers()) - return; + uint32 _teamInInstance; + uint32 _waveCount; + uint32 _introEvent; + uint32 _frostwornGeneral; - events.Update(diff); + EventMap events; - switch (events.ExecuteEvent()) - { - case EVENT_NEXT_WAVE: - uiWaveCount++; - AddWave(); - break; - case EVENT_START_LICH_KING: - /// @todo - break; - } - } + std::set<uint64> waveGuidList[8]; }; + InstanceScript* GetInstanceScript(InstanceMap* map) const + { + return new instance_halls_of_reflection_InstanceMapScript(map); + } }; void AddSC_instance_halls_of_reflection() diff --git a/src/server/scripts/Northrend/Gundrak/gundrak.h b/src/server/scripts/Northrend/Gundrak/gundrak.h index 0c65b4d16de..a43edb4fcd7 100644 --- a/src/server/scripts/Northrend/Gundrak/gundrak.h +++ b/src/server/scripts/Northrend/Gundrak/gundrak.h @@ -43,12 +43,31 @@ enum Data64 enum mainCreatures { - CREATURE_RUIN_DWELLER = 29920, - CREATURE_SLAD_RAN = 29304, - CREATURE_MOORABI = 29305, - CREATURE_GALDARAH = 29306, - CREATURE_DRAKKARICOLOSSUS = 29307, - CREATURE_ECK = 29932 + CREATURE_RUIN_DWELLER = 29920, + CREATURE_SLAD_RAN = 29304, + CREATURE_MOORABI = 29305, + CREATURE_GALDARAH = 29306, + CREATURE_DRAKKARICOLOSSUS = 29307, + CREATURE_ECK = 29932 +}; + +enum Gameobjects { + + GO_SLADRAN_ALTAR = 192518, + GO_MOORABI_ALTAR = 192519, + GO_DRAKKARI_COLOSSUS_ALTAR = 192520, + GO_SLADRAN_STATUE = 192564, + GO_MOORABI_STATUE = 192565, + GO_GALDARAH_STATUE = 192566, + GO_DRAKKARI_COLOSSUS_STATUE = 192567, + GO_ECK_THE_FEROCIOUS_DOOR = 192632, + GO_ECK_THE_FEROCIOUS_DOOR_BEHIND = 192569, + GO_GALDARAH_DOOR1 = 193208, + GO_GALDARAH_DOOR2 = 193209, + GO_GALDARAH_DOOR3 = 192568, + GO_BRIDGE = 193188, + GO_COLLISION = 192633 + }; #endif diff --git a/src/server/scripts/Northrend/Gundrak/instance_gundrak.cpp b/src/server/scripts/Northrend/Gundrak/instance_gundrak.cpp index a9bbffa5fb0..d17198b0c92 100644 --- a/src/server/scripts/Northrend/Gundrak/instance_gundrak.cpp +++ b/src/server/scripts/Northrend/Gundrak/instance_gundrak.cpp @@ -45,44 +45,45 @@ public: { instance_gundrak_InstanceMapScript(Map* map) : InstanceScript(map) { - bHeroicMode = map->IsHeroic(); + isHeroic = map->IsHeroic(); } - bool bHeroicMode; + bool isHeroic; bool spawnSupport; uint32 timer; uint32 phase; uint64 toActivate; - uint64 uiSladRan; - uint64 uiMoorabi; - uint64 uiDrakkariColossus; - uint64 uiGalDarah; - uint64 uiEckTheFerocious; - - uint64 uiSladRanAltar; - uint64 uiMoorabiAltar; - uint64 uiDrakkariColossusAltar; - uint64 uiSladRanStatue; - uint64 uiMoorabiStatue; - uint64 uiDrakkariColossusStatue; - uint64 uiGalDarahStatue; - uint64 uiEckTheFerociousDoor; - uint64 uiEckTheFerociousDoorBehind; - uint64 uiGalDarahDoor1; - uint64 uiGalDarahDoor2; - uint64 uiBridge; - uint64 uiCollision; + uint64 sladRanGUID; + uint64 moorabiGUID; + uint64 drakkariColossusGUID; + uint64 galDarahGUID; + uint64 eckTheFerociousGUID; + + uint64 sladRanAltarGUID; + uint64 moorabiAltarGUID; + uint64 drakkariColossusAltarGUID; + uint64 sladRanStatueGUID; + uint64 moorabiStatueGUID; + uint64 drakkariColossusStatueGUID; + uint64 galDarahStatueGUID; + uint64 eckTheFerociousDoorGUID; + uint64 eckTheFerociousDoorBehindGUID; + uint64 galDarahDoor1GUID; + uint64 galDarahDoor2GUID; + uint64 galDarahDoor3GUID; + uint64 bridgeGUID; + uint64 collisionGUID; uint32 m_auiEncounter[MAX_ENCOUNTER]; - GOState uiSladRanStatueState; - GOState uiMoorabiStatueState; - GOState uiDrakkariColossusStatueState; - GOState uiGalDarahStatueState; - GOState uiBridgeState; - GOState uiCollisionState; + GOState sladRanStatueState; + GOState moorabiStatueState; + GOState drakkariColossusStatueState; + GOState galDarahStatueState; + GOState bridgeState; + GOState collisionState; std::set<uint64> DwellerGUIDs; @@ -96,35 +97,36 @@ public: phase = 0; toActivate = 0; - uiSladRan = 0; - uiMoorabi = 0; - uiDrakkariColossus = 0; - uiGalDarah = 0; - uiEckTheFerocious = 0; - - uiSladRanAltar = 0; - uiMoorabiAltar = 0; - uiDrakkariColossusAltar = 0; - - uiSladRanStatue = 0; - uiMoorabiStatue = 0; - uiDrakkariColossusStatue = 0; - uiGalDarahStatue = 0; - - uiEckTheFerociousDoor = 0; - uiEckTheFerociousDoorBehind = 0; - uiGalDarahDoor1 = 0; - uiGalDarahDoor2 = 0; - - uiBridge = 0; - uiCollision = 0; - - uiSladRanStatueState = GO_STATE_ACTIVE; - uiMoorabiStatueState = GO_STATE_ACTIVE; - uiDrakkariColossusStatueState = GO_STATE_ACTIVE; - uiGalDarahStatueState = GO_STATE_READY; - uiBridgeState = GO_STATE_ACTIVE; - uiCollisionState = GO_STATE_READY; + sladRanGUID = 0; + moorabiGUID = 0; + drakkariColossusGUID = 0; + galDarahGUID = 0; + eckTheFerociousGUID = 0; + + sladRanAltarGUID = 0; + moorabiAltarGUID = 0; + drakkariColossusAltarGUID = 0; + + sladRanStatueGUID = 0; + moorabiStatueGUID = 0; + drakkariColossusStatueGUID = 0; + galDarahStatueGUID = 0; + + eckTheFerociousDoorGUID = 0; + eckTheFerociousDoorBehindGUID = 0; + galDarahDoor1GUID = 0; + galDarahDoor2GUID = 0; + galDarahDoor3GUID = 0; + + bridgeGUID = 0; + collisionGUID = 0; + + sladRanStatueState = GO_STATE_ACTIVE; + moorabiStatueState = GO_STATE_ACTIVE; + drakkariColossusStatueState = GO_STATE_ACTIVE; + galDarahStatueState = GO_STATE_READY; + bridgeState = GO_STATE_ACTIVE; + collisionState = GO_STATE_READY; DwellerGUIDs.clear(); @@ -144,11 +146,21 @@ public: { switch (creature->GetEntry()) { - case CREATURE_SLAD_RAN: uiSladRan = creature->GetGUID(); break; - case CREATURE_MOORABI: uiMoorabi = creature->GetGUID(); break; - case CREATURE_GALDARAH: uiGalDarah = creature->GetGUID(); break; - case CREATURE_DRAKKARICOLOSSUS: uiDrakkariColossus = creature->GetGUID(); break; - case CREATURE_ECK: uiEckTheFerocious = creature->GetGUID(); break; + case CREATURE_SLAD_RAN: + sladRanGUID = creature->GetGUID(); + break; + case CREATURE_MOORABI: + moorabiGUID = creature->GetGUID(); + break; + case CREATURE_GALDARAH: + galDarahGUID = creature->GetGUID(); + break; + case CREATURE_DRAKKARICOLOSSUS: + drakkariColossusGUID = creature->GetGUID(); + break; + case CREATURE_ECK: + eckTheFerociousGUID = creature->GetGUID(); + break; case CREATURE_RUIN_DWELLER: if (creature->isAlive()) DwellerGUIDs.insert(creature->GetGUID()); @@ -160,13 +172,13 @@ public: { switch (go->GetEntry()) { - case 192518: - uiSladRanAltar = go->GetGUID(); + case GO_SLADRAN_ALTAR: + sladRanAltarGUID = go->GetGUID(); // Make sure that they start out as unusuable go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); if (m_auiEncounter[0] == DONE) { - if (uiSladRanStatueState == GO_STATE_ACTIVE) + if (sladRanStatueState == GO_STATE_ACTIVE) go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); else { @@ -175,13 +187,13 @@ public: } } break; - case 192519: - uiMoorabiAltar = go->GetGUID(); + case GO_MOORABI_ALTAR: + moorabiAltarGUID = go->GetGUID(); // Make sure that they start out as unusuable go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); if (m_auiEncounter[0] == DONE) { - if (uiMoorabiStatueState == GO_STATE_ACTIVE) + if (moorabiStatueState == GO_STATE_ACTIVE) go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); else { @@ -190,13 +202,13 @@ public: } } break; - case 192520: - uiDrakkariColossusAltar = go->GetGUID(); + case GO_DRAKKARI_COLOSSUS_ALTAR: + drakkariColossusAltarGUID = go->GetGUID(); // Make sure that they start out as unusuable go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); if (m_auiEncounter[0] == DONE) { - if (uiDrakkariColossusStatueState == GO_STATE_ACTIVE) + if (drakkariColossusStatueState == GO_STATE_ACTIVE) go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); else { @@ -205,53 +217,58 @@ public: } } break; - case 192564: - uiSladRanStatue = go->GetGUID(); - go->SetGoState(uiSladRanStatueState); + case GO_SLADRAN_STATUE: + sladRanStatueGUID = go->GetGUID(); + go->SetGoState(sladRanStatueState); break; - case 192565: - uiMoorabiStatue = go->GetGUID(); - go->SetGoState(uiMoorabiStatueState); + case GO_MOORABI_STATUE: + moorabiStatueGUID = go->GetGUID(); + go->SetGoState(moorabiStatueState); break; - case 192566: - uiGalDarahStatue = go->GetGUID(); - go->SetGoState(uiGalDarahStatueState); + case GO_GALDARAH_STATUE: + galDarahStatueGUID = go->GetGUID(); + go->SetGoState(galDarahStatueState); break; - case 192567: - uiDrakkariColossusStatue = go->GetGUID(); - go->SetGoState(uiDrakkariColossusStatueState); + case GO_DRAKKARI_COLOSSUS_STATUE: + drakkariColossusStatueGUID = go->GetGUID(); + go->SetGoState(drakkariColossusStatueState); break; - case 192632: - uiEckTheFerociousDoor = go->GetGUID(); - if (bHeroicMode && m_auiEncounter[1] == DONE) + case GO_ECK_THE_FEROCIOUS_DOOR: + eckTheFerociousDoorGUID = go->GetGUID(); + if (isHeroic && m_auiEncounter[1] == DONE) HandleGameObject(0, true, go); break; - case 192569: - uiEckTheFerociousDoorBehind = go->GetGUID(); - if (bHeroicMode && m_auiEncounter[4] == DONE) + case GO_ECK_THE_FEROCIOUS_DOOR_BEHIND: + eckTheFerociousDoorBehindGUID = go->GetGUID(); + if (isHeroic && m_auiEncounter[4] == DONE) HandleGameObject(0, true, go); - case 193208: - uiGalDarahDoor1 = go->GetGUID(); + case GO_GALDARAH_DOOR1: + galDarahDoor1GUID = go->GetGUID(); if (m_auiEncounter[3] == DONE) HandleGameObject(0, true, go); break; - case 193209: - uiGalDarahDoor2 = go->GetGUID(); + case GO_GALDARAH_DOOR2: + galDarahDoor2GUID = go->GetGUID(); if (m_auiEncounter[3] == DONE) HandleGameObject(0, true, go); break; - case 193188: - uiBridge = go->GetGUID(); - go->SetGoState(uiBridgeState); + case GO_BRIDGE: + bridgeGUID = go->GetGUID(); + go->SetGoState(bridgeState); break; - case 192633: - uiCollision = go->GetGUID(); - go->SetGoState(uiCollisionState); + case GO_COLLISION: + collisionGUID = go->GetGUID(); + go->SetGoState(collisionState); // Can't spawn here with SpawnGameObject because go isn't added to world yet... - if (uiCollisionState == GO_STATE_ACTIVE_ALTERNATIVE) + if (collisionState == GO_STATE_ACTIVE_ALTERNATIVE) spawnSupport = true; break; + case GO_GALDARAH_DOOR3: + galDarahDoor3GUID = go->GetGUID(); + if (m_auiEncounter[3] != IN_PROGRESS) + HandleGameObject(galDarahDoor3GUID, true, go); + break; } } @@ -263,7 +280,7 @@ public: m_auiEncounter[0] = data; if (data == DONE) { - GameObject* go = instance->GetGameObject(uiSladRanAltar); + GameObject* go = instance->GetGameObject(sladRanAltarGUID); if (go) go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); } @@ -272,18 +289,18 @@ public: m_auiEncounter[1] = data; if (data == DONE) { - GameObject* go = instance->GetGameObject(uiMoorabiAltar); + GameObject* go = instance->GetGameObject(moorabiAltarGUID); if (go) go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); - if (bHeroicMode) - HandleGameObject(uiEckTheFerociousDoor, true); + if (isHeroic) + HandleGameObject(eckTheFerociousDoorGUID, true); } break; case DATA_DRAKKARI_COLOSSUS_EVENT: m_auiEncounter[2] = data; if (data == DONE) { - GameObject* go = instance->GetGameObject(uiDrakkariColossusAltar); + GameObject* go = instance->GetGameObject(drakkariColossusAltarGUID); if (go) go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); } @@ -292,14 +309,15 @@ public: m_auiEncounter[3] = data; if (data == DONE) { - HandleGameObject(uiGalDarahDoor1, true); - HandleGameObject(uiGalDarahDoor2, true); + HandleGameObject(galDarahDoor1GUID, true); + HandleGameObject(galDarahDoor2GUID, true); } + HandleGameObject(galDarahDoor3GUID, data == IN_PROGRESS ? false : true); break; case DATA_ECK_THE_FEROCIOUS_EVENT: m_auiEncounter[4] = data; - if (bHeroicMode && data == DONE) - HandleGameObject(uiEckTheFerociousDoorBehind, true); + if (isHeroic && data == DONE) + HandleGameObject(eckTheFerociousDoorBehindGUID, true); break; } @@ -345,19 +363,19 @@ public: switch (type) { case DATA_SLAD_RAN_ALTAR: - return uiSladRanAltar; + return sladRanAltarGUID; case DATA_MOORABI_ALTAR: - return uiMoorabiAltar; + return moorabiAltarGUID; case DATA_DRAKKARI_COLOSSUS_ALTAR: - return uiDrakkariColossusAltar; + return drakkariColossusAltarGUID; case DATA_SLAD_RAN_STATUE: - return uiSladRanStatue; + return sladRanStatueGUID; case DATA_MOORABI_STATUE: - return uiMoorabiStatue; + return moorabiStatueGUID; case DATA_DRAKKARI_COLOSSUS_STATUE: - return uiDrakkariColossusStatue; + return drakkariColossusStatueGUID; case DATA_DRAKKARI_COLOSSUS: - return uiDrakkariColossus; + return drakkariColossusGUID; case DATA_STATUE_ACTIVATE: return toActivate; } @@ -372,9 +390,9 @@ public: std::ostringstream saveStream; saveStream << "G D " << m_auiEncounter[0] << ' ' << m_auiEncounter[1] << ' ' << m_auiEncounter[2] << ' ' << m_auiEncounter[3] << ' ' << m_auiEncounter[4] << ' ' - << (uiSladRanStatue ? GetObjState(uiSladRanStatue) : GO_STATE_ACTIVE) << ' ' << (uiMoorabiStatue ? GetObjState(uiMoorabiStatue) : GO_STATE_ACTIVE) << ' ' - << (uiDrakkariColossusStatue ? GetObjState(uiDrakkariColossusStatue) : GO_STATE_ACTIVE) << ' ' << (uiGalDarahStatue ? GetObjState(uiGalDarahStatue) : GO_STATE_READY) << ' ' - << (uiBridge ? GetObjState(uiBridge) : GO_STATE_ACTIVE) << ' ' << (uiCollision ? GetObjState(uiCollision) : GO_STATE_READY); + << (sladRanStatueGUID ? GetObjState(sladRanStatueGUID) : GO_STATE_ACTIVE) << ' ' << (moorabiStatueGUID ? GetObjState(moorabiStatueGUID) : GO_STATE_ACTIVE) << ' ' + << (drakkariColossusStatueGUID ? GetObjState(drakkariColossusStatueGUID) : GO_STATE_ACTIVE) << ' ' << (galDarahStatueGUID ? GetObjState(galDarahStatueGUID) : GO_STATE_READY) << ' ' + << (bridgeGUID ? GetObjState(bridgeGUID) : GO_STATE_ACTIVE) << ' ' << (collisionGUID ? GetObjState(collisionGUID) : GO_STATE_READY); str_data = saveStream.str(); @@ -406,12 +424,12 @@ public: m_auiEncounter[2] = data2; m_auiEncounter[3] = data3; m_auiEncounter[4] = data4; - uiSladRanStatueState = GOState(data5); - uiMoorabiStatueState = GOState(data6); - uiDrakkariColossusStatueState = GOState(data7); - uiGalDarahStatueState = GOState(data8); - uiBridgeState = GOState(data9); - uiCollisionState = GOState(data10); + sladRanStatueState = GOState(data5); + moorabiStatueState = GOState(data6); + drakkariColossusStatueState = GOState(data7); + galDarahStatueState = GOState(data8); + bridgeState = GOState(data9); + collisionState = GOState(data10); for (uint8 i = 0; i < MAX_ENCOUNTER; ++i) if (m_auiEncounter[i] == IN_PROGRESS) @@ -426,8 +444,8 @@ public: // Spawn the support for the bridge if necessary if (spawnSupport) { - if (GameObject* pCollision = instance->GetGameObject(uiCollision)) - pCollision->SummonGameObject(192743, pCollision->GetPositionX(), pCollision->GetPositionY(), pCollision->GetPositionZ(), pCollision->GetOrientation(), 0, 0, 0, 0, 0); + if (GameObject* collision = instance->GetGameObject(collisionGUID)) + collision->SummonGameObject(192743, collision->GetPositionX(), collision->GetPositionY(), collision->GetPositionZ(), collision->GetOrientation(), 0, 0, 0, 0, 0); spawnSupport = false; } @@ -438,25 +456,25 @@ public: if (timer < diff) { timer = 0; - if (toActivate == uiBridge) + if (toActivate == bridgeGUID) { - GameObject* pBridge = instance->GetGameObject(uiBridge); - GameObject* pCollision = instance->GetGameObject(uiCollision); - GameObject* pSladRanStatue = instance->GetGameObject(uiSladRanStatue); - GameObject* pMoorabiStatue = instance->GetGameObject(uiMoorabiStatue); - GameObject* pDrakkariColossusStatue = instance->GetGameObject(uiDrakkariColossusStatue); - GameObject* pGalDarahStatue = instance->GetGameObject(uiGalDarahStatue); + GameObject* bridge = instance->GetGameObject(bridgeGUID); + GameObject* collision = instance->GetGameObject(collisionGUID); + GameObject* sladRanStatue = instance->GetGameObject(sladRanStatueGUID); + GameObject* moorabiStatue = instance->GetGameObject(moorabiStatueGUID); + GameObject* drakkariColossusStatue = instance->GetGameObject(drakkariColossusStatueGUID); + GameObject* galDarahStatue = instance->GetGameObject(galDarahStatueGUID); toActivate = 0; - if (pBridge && pCollision && pSladRanStatue && pMoorabiStatue && pDrakkariColossusStatue && pGalDarahStatue) + if (bridge && collision && sladRanStatue && moorabiStatue && drakkariColossusStatue && galDarahStatue) { - pBridge->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); - pCollision->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); - pSladRanStatue->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); - pMoorabiStatue->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); - pDrakkariColossusStatue->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); - pGalDarahStatue->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + bridge->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + collision->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + sladRanStatue->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + moorabiStatue->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + drakkariColossusStatue->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + galDarahStatue->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); // Add the GO that solidifies the bridge so you can walk on it spawnSupport = true; @@ -466,27 +484,27 @@ public: else { uint32 spell = 0; - GameObject* pAltar = NULL; - if (toActivate == uiSladRanStatue) + GameObject* altar = NULL; + if (toActivate == sladRanStatueGUID) { spell = 57071; - pAltar = instance->GetGameObject(uiSladRanAltar); + altar = instance->GetGameObject(sladRanAltarGUID); } - else if (toActivate == uiMoorabiStatue) + else if (toActivate == moorabiStatueGUID) { spell = 57068; - pAltar = instance->GetGameObject(uiMoorabiAltar); + altar = instance->GetGameObject(moorabiAltarGUID); } - else if (toActivate == uiDrakkariColossusStatue) + else if (toActivate == drakkariColossusStatueGUID) { spell = 57072; - pAltar = instance->GetGameObject(uiDrakkariColossusAltar); + altar = instance->GetGameObject(drakkariColossusAltarGUID); } // This is a workaround to make the beam cast properly. The caster should be ID 30298 but since the spells // all are with scripted target for that same ID, it will hit itself. - if (pAltar) - if (Creature* trigger = pAltar->SummonCreature(18721, pAltar->GetPositionX(), pAltar->GetPositionY(), pAltar->GetPositionZ() + 3, pAltar->GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 5000)) + if (altar) + if (Creature* trigger = altar->SummonCreature(18721, altar->GetPositionX(), altar->GetPositionY(), altar->GetPositionZ() + 3, altar->GetOrientation(), TEMPSUMMON_CORPSE_DESPAWN, 5000)) { // Set the trigger model to invisible trigger->SetDisplayId(11686); @@ -499,7 +517,7 @@ public: toActivate = 0; if (phase == 3) - SetData64(DATA_STATUE_ACTIVATE, uiBridge); + SetData64(DATA_STATUE_ACTIVATE, bridgeGUID); else SaveToDB(); // Don't save in between last statue and bridge turning in case of crash leading to stuck instance } @@ -526,7 +544,7 @@ public: bool OnGossipHello(Player* /*player*/, GameObject* go) { InstanceScript* instance = go->GetInstanceScript(); - uint64 uiStatue = 0; + uint64 statueGUID = 0; go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); go->SetGoState(GO_STATE_ACTIVE); @@ -535,20 +553,20 @@ public: { switch (go->GetEntry()) { - case 192518: - uiStatue = instance->GetData64(DATA_SLAD_RAN_STATUE); + case GO_SLADRAN_ALTAR: + statueGUID = instance->GetData64(DATA_SLAD_RAN_STATUE); break; - case 192519: - uiStatue = instance->GetData64(DATA_MOORABI_STATUE); + case GO_MOORABI_ALTAR: + statueGUID = instance->GetData64(DATA_MOORABI_STATUE); break; - case 192520: - uiStatue = instance->GetData64(DATA_DRAKKARI_COLOSSUS_STATUE); + case GO_DRAKKARI_COLOSSUS_ALTAR: + statueGUID = instance->GetData64(DATA_DRAKKARI_COLOSSUS_STATUE); break; } if (!instance->GetData64(DATA_STATUE_ACTIVATE)) { - instance->SetData64(DATA_STATUE_ACTIVATE, uiStatue); + instance->SetData64(DATA_STATUE_ACTIVATE, statueGUID); go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); go->SetGoState(GO_STATE_ACTIVE); } diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index 3036c52876d..4cc464af9ab 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -1640,6 +1640,37 @@ class spell_q13291_q13292_q13239_q13261_armored_decoy_summon_skytalon : public S } }; +class spell_q12847_summon_soul_moveto_bunny : public SpellScriptLoader +{ + public: + spell_q12847_summon_soul_moveto_bunny() : SpellScriptLoader("spell_q12847_summon_soul_moveto_bunny") { } + + class spell_q12847_summon_soul_moveto_bunny_SpellScript : public SpellScript + { + PrepareSpellScript(spell_q12847_summon_soul_moveto_bunny_SpellScript); + + void ChangeSummonPos(SpellEffIndex /*effIndex*/) + { + // Adjust effect summon position + WorldLocation summonPos = *GetExplTargetDest(); + Position offset = { 0.0f, 0.0f, 2.5f, 0.0f }; + summonPos.RelocateOffset(offset); + SetExplTargetDest(summonPos); + GetHitDest()->RelocateOffset(offset); + } + + void Register() + { + OnEffectHit += SpellEffectFn(spell_q12847_summon_soul_moveto_bunny_SpellScript::ChangeSummonPos, EFFECT_0, SPELL_EFFECT_SUMMON); + } + }; + + SpellScript *GetSpellScript() const + { + return new spell_q12847_summon_soul_moveto_bunny_SpellScript(); + } +}; + void AddSC_quest_spell_scripts() { new spell_q55_sacred_cleansing(); @@ -1680,4 +1711,5 @@ void AddSC_quest_spell_scripts() new spell_q12527_zuldrak_rat(); new spell_q13291_q13292_q13239_q13261_frostbrood_skytalon_grab_decoy(); new spell_q13291_q13292_q13239_q13261_armored_decoy_summon_skytalon(); + new spell_q12847_summon_soul_moveto_bunny(); } |
