Merge branch 'master' of github.com:TrinityCore/TrinityCore into 4.3.4

Conflicts:
	src/server/game/Achievements/AchievementMgr.cpp
	src/server/game/Entities/Unit/Unit.cpp
	src/server/game/Entities/Vehicle/Vehicle.cpp
	src/server/game/Handlers/ItemHandler.cpp
	src/server/game/Handlers/MailHandler.cpp
	src/server/game/Server/Protocol/Opcodes.cpp
	src/server/game/Server/Protocol/Opcodes.h
	src/server/scripts/Commands/cs_misc.cpp
This commit is contained in:
Shauren
2013-05-30 20:57:07 +02:00
79 changed files with 3922 additions and 1330 deletions

View File

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

View File

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

View File

@@ -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());
// 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);
if (banTime >= 0)
handler->PSendSysMessage(LANG_PINFO_BAN, banTime > 0 ? secsToTimeString(banTime - time(NULL), true).c_str() : "permanently", bannedby.c_str(), banreason.c_str());
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);
// 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)
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)
{
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);
}
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));
result = CharacterDatabase.Query(stmt);
if (result)
{
Field* fields = result->Fetch();
uint32 guildId = fields[0].GetUInt32();
std::string guildName = fields[1].GetString();
std::string guildRank = fields[2].GetString();
std::string note = fields[3].GetString();
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();
handler->PSendSysMessage(LANG_PINFO_GUILD_INFO, guildName.c_str(), guildId, guildRank.c_str(), note.c_str(), officeNote.c_str());
// 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());
}
// Output XXI. LANG_PINFO_CHR_PLAYEDTIME
handler->PSendSysMessage(LANG_PINFO_CHR_PLAYEDTIME, (secsToTimeString(totalPlayerTime, true, true)).c_str());
// 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)
{
// Define the variables, so the compiler knows they exist
uint32 rmailint = 0;
// 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();
// ... 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)
{

View File

@@ -338,7 +338,8 @@ public:
}
else
sWorld->ShutdownServ(time, SHUTDOWN_MASK_IDLE, SHUTDOWN_EXIT_CODE);
return true;
return true;
}
// Exit the realm

View File

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

View File

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

View File

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

View File

@@ -18,54 +18,83 @@
#ifndef DEF_HALLS_OF_REFLECTION_H
#define DEF_HALLS_OF_REFLECTION_H
#define HoRScriptName "instance_halls_of_reflection"
#define MAX_ENCOUNTER 3
/* Halls of Reflection encounters:
0- Falric
1- Marwyn
2- The Lich King
*/
enum Data
{
DATA_FALRIC_EVENT,
DATA_MARWYN_EVENT,
DATA_LICHKING_EVENT,
DATA_WAVE_COUNT,
DATA_TEAM_IN_INSTANCE,
};
DATA_FALRIC_EVENT = 0,
DATA_MARWYN_EVENT = 1,
DATA_LICHKING_EVENT = 2,
DATA_INTRO_EVENT = 3,
DATA_FROSWORN_EVENT = 4,
enum Data64
{
DATA_FALRIC,
DATA_MARWYN,
DATA_LICHKING,
DATA_FROSTMOURNE,
DATA_WAVE_COUNT = 5,
DATA_TEAM_IN_INSTANCE = 6,
DATA_FROSTMOURNE = 7,
DATA_FROSTWORN_DOOR = 8,
};
enum Creatures
{
NPC_JAINA_PART1 = 37221,
NPC_SYLVANAS_PART1 = 37223,
NPC_UTHER = 37225,
NPC_LICH_KING_PART1 = 37226,
NPC_LORALEN = 37779,
NPC_KORELN = 37582,
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_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);
}
}
};

View File

@@ -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
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
/* Halls of Reflection encounters:
0- Falric
1- Marwyn
2- The Lich King
*/
enum eEnum
Position const SpawnPos[] =
{
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},
};
static Position FootmenSpawnPos[ENCOUNTER_WAVE_FOOTMAN] =
{
{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();
_marwynGUID = creature->GetGUID();
break;
case NPC_LICH_KING_EVENT:
uiLichKingEvent = 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_JAINA_PART1:
uiJainaPart1 = creature->GetGUID();
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,197 +177,116 @@ 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;
}
if (data == DONE)
SaveToDB();
return true;
}
uint32 GetData(uint32 type) const
void SetData(uint32 type, uint32 data)
{
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_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;
}
return 0;
SaveToDB();
}
uint64 GetData64(uint32 identifier) const
// wave scheduling,checked when wave npcs die
void OnUnitDeath(Unit* unit)
{
switch (identifier)
{
case DATA_FALRIC: return uiFalric;
case DATA_MARWYN: return uiMarwyn;
case DATA_LICHKING: return uiLichKingEvent;
case DATA_FROSTMOURNE: return uiFrostmourne;
}
return 0;
}
std::string GetSaveData()
{
OUT_SAVE_INST_DATA;
std::ostringstream saveStream;
saveStream << "H R 1 " << uiEncounter[0] << ' ' << uiEncounter[1] << ' ' << uiEncounter[2];
OUT_SAVE_INST_DATA_COMPLETE;
return saveStream.str();
}
void Load(const char* in)
{
if (!in)
{
OUT_LOAD_INST_DATA_FAIL;
Creature* creature = unit->ToCreature();
if (!creature)
return;
}
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;
if (dataHead1 == 'H' && dataHead2 == 'R')
switch (creature->GetEntry())
{
uiEncounter[0] = data0;
uiEncounter[1] = data1;
uiEncounter[2] = data2;
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;
}
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)
// 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);
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;
}
}
}
// 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);
}
// 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);
index = urand(0, ENCOUNTER_WAVE_PRIEST-1);
summoner->SummonCreature(NPC_WAVE_PRIEST, PriestSpawnPos[index], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0);
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())
@@ -413,16 +297,241 @@ public:
switch (events.ExecuteEvent())
{
case EVENT_NEXT_WAVE:
uiWaveCount++;
AddWave();
break;
case EVENT_START_LICH_KING:
/// @todo
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_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 type) const
{
switch (type)
{
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;
}
std::string GetSaveData()
{
OUT_SAVE_INST_DATA;
std::ostringstream saveStream;
saveStream << "H R " << GetBossSaveData() << _introEvent << ' ' << _frostwornGeneral;
OUT_SAVE_INST_DATA_COMPLETE;
return saveStream.str();
}
void Load(char const* in)
{
if (!in)
{
OUT_LOAD_INST_DATA_FAIL;
return;
}
OUT_LOAD_INST_DATA(in);
char dataHead1, dataHead2;
std::istringstream loadStream(in);
loadStream >> dataHead1 >> dataHead2;
if (dataHead1 == 'H' && dataHead2 == 'R')
{
for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
{
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;
OUT_LOAD_INST_DATA_COMPLETE;
}
private:
uint64 _falricGUID;
uint64 _marwynGUID;
uint64 _jainaOrSylvanasPart1GUID;
uint64 _frostwornGeneralGUID;
uint64 _frostmourneGUID;
uint64 _entranceDoorGUID;
uint64 _frostwornDoorGUID;
uint64 _arthasDoorGUID;
uint64 _escapeDoorGUID;
uint32 _teamInInstance;
uint32 _waveCount;
uint32 _introEvent;
uint32 _frostwornGeneral;
EventMap events;
std::set<uint64> waveGuidList[8];
};
InstanceScript* GetInstanceScript(InstanceMap* map) const
{
return new instance_halls_of_reflection_InstanceMapScript(map);
}
};
void AddSC_instance_halls_of_reflection()

View File

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

View File

@@ -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 sladRanGUID;
uint64 moorabiGUID;
uint64 drakkariColossusGUID;
uint64 galDarahGUID;
uint64 eckTheFerociousGUID;
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 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;
sladRanGUID = 0;
moorabiGUID = 0;
drakkariColossusGUID = 0;
galDarahGUID = 0;
eckTheFerociousGUID = 0;
uiSladRanAltar = 0;
uiMoorabiAltar = 0;
uiDrakkariColossusAltar = 0;
sladRanAltarGUID = 0;
moorabiAltarGUID = 0;
drakkariColossusAltarGUID = 0;
uiSladRanStatue = 0;
uiMoorabiStatue = 0;
uiDrakkariColossusStatue = 0;
uiGalDarahStatue = 0;
sladRanStatueGUID = 0;
moorabiStatueGUID = 0;
drakkariColossusStatueGUID = 0;
galDarahStatueGUID = 0;
uiEckTheFerociousDoor = 0;
uiEckTheFerociousDoorBehind = 0;
uiGalDarahDoor1 = 0;
uiGalDarahDoor2 = 0;
eckTheFerociousDoorGUID = 0;
eckTheFerociousDoorBehindGUID = 0;
galDarahDoor1GUID = 0;
galDarahDoor2GUID = 0;
galDarahDoor3GUID = 0;
uiBridge = 0;
uiCollision = 0;
bridgeGUID = 0;
collisionGUID = 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;
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);
}

View File

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