summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Accounts/AccountMgr.cpp335
-rw-r--r--src/server/game/Accounts/AccountMgr.h4
-rw-r--r--src/server/game/AuctionHouse/AuctionHouseMgr.cpp5
-rw-r--r--src/server/game/Chat/Channels/Channel.cpp9
-rw-r--r--src/server/game/Chat/Channels/ChannelMgr.cpp406
-rw-r--r--src/server/game/DungeonFinding/LFGMgr.cpp5194
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp2
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp2
-rw-r--r--src/server/game/Entities/Object/Object.cpp6
-rw-r--r--src/server/game/Entities/Player/Player.cpp21
-rw-r--r--src/server/game/Entities/Player/SocialMgr.cpp8
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp35
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp4
-rw-r--r--src/server/game/Guilds/Guild.cpp12
-rw-r--r--src/server/game/Handlers/ArenaTeamHandler.cpp22
-rw-r--r--src/server/game/Handlers/AuctionHouseHandler.cpp6
-rw-r--r--src/server/game/Handlers/CalendarHandler.cpp2
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp32
-rw-r--r--src/server/game/Handlers/ChatHandler.cpp53
-rw-r--r--src/server/game/Handlers/GroupHandler.cpp2
-rw-r--r--src/server/game/Handlers/ItemHandler.cpp6
-rw-r--r--src/server/game/Handlers/MailHandler.cpp2
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp308
-rw-r--r--src/server/game/Handlers/PetitionsHandler.cpp2
-rw-r--r--src/server/game/Handlers/TradeHandler.cpp10
-rw-r--r--src/server/game/Handlers/VehicleHandler.cpp2
-rw-r--r--src/server/game/Instances/InstanceScript.h3
-rw-r--r--src/server/game/Server/WorldSession.cpp2
-rw-r--r--src/server/game/Server/WorldSession.h6
-rw-r--r--src/server/game/Spells/Spell.cpp2
-rw-r--r--src/server/game/World/World.cpp81
-rw-r--r--src/server/game/World/World.h19
-rw-r--r--src/server/scripts/Commands/cs_account.cpp617
-rw-r--r--src/server/scripts/Commands/cs_go.cpp2
-rw-r--r--src/server/scripts/Commands/cs_gobject.cpp2
-rw-r--r--src/server/scripts/Commands/cs_npc.cpp6
-rw-r--r--src/server/scripts/Commands/cs_reload.cpp2
-rw-r--r--src/server/scripts/Custom/Multivendor/MultivendorExample.sql10
-rw-r--r--src/server/scripts/Custom/Multivendor/README.md42
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.cpp4
-rw-r--r--src/server/shared/Database/Implementation/LoginDatabase.h2
-rw-r--r--src/server/shared/Database/MySQLThreading.h4
-rw-r--r--src/server/shared/Debugging/WheatyExceptionReport.cpp4
43 files changed, 4115 insertions, 3183 deletions
diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp
index 0ee49bef76..9a952c7fdf 100644
--- a/src/server/game/Accounts/AccountMgr.cpp
+++ b/src/server/game/Accounts/AccountMgr.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (C)
- * Copyright (C)
+ * Copyright (C)
+ * Copyright (C)
*
* 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
@@ -27,125 +27,276 @@
namespace AccountMgr
{
-uint32 GetId(std::string const& username)
-{
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME);
- stmt->setString(0, username);
- PreparedQueryResult result = LoginDatabase.Query(stmt);
+ AccountOpResult CreateAccount(std::string username, std::string password)
+ {
+ if (utf8length(username) > MAX_ACCOUNT_STR)
+ return AOR_NAME_TOO_LONG; // username's too long
- return (result) ? (*result)[0].GetUInt32() : 0;
-}
+ normalizeString(username);
+ normalizeString(password);
-uint32 GetSecurity(uint32 accountId)
-{
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ACCESS_GMLEVEL);
- stmt->setUInt32(0, accountId);
- PreparedQueryResult result = LoginDatabase.Query(stmt);
+ if (GetId(username))
+ return AOR_NAME_ALREDY_EXIST; // username does already exist
- return (result) ? (*result)[0].GetUInt8() : uint32(SEC_PLAYER);
-}
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT);
-uint32 GetSecurity(uint32 accountId, int32 realmId)
-{
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID);
- stmt->setUInt32(0, accountId);
- stmt->setInt32(1, realmId);
- PreparedQueryResult result = LoginDatabase.Query(stmt);
+ stmt->setString(0, username);
+ stmt->setString(1, CalculateShaPassHash(username, password));
- return (result) ? (*result)[0].GetUInt8() : uint32(SEC_PLAYER);
-}
+ LoginDatabase.Execute(stmt);
-bool GetName(uint32 accountId, std::string& name)
-{
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_USERNAME_BY_ID);
- stmt->setUInt32(0, accountId);
- PreparedQueryResult result = LoginDatabase.Query(stmt);
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_REALM_CHARACTERS_INIT);
- if (result)
- {
- name = (*result)[0].GetString();
- return true;
- }
+ LoginDatabase.Execute(stmt);
- return false;
-}
+ return AOR_OK; // everything's fine
+ }
-bool CheckPassword(uint32 accountId, std::string password)
-{
- std::string username;
+ AccountOpResult DeleteAccount(uint32 accountId)
+ {
+ // Check if accounts exists
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID);
+ stmt->setUInt32(0, accountId);
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
- if (!GetName(accountId, username))
- return false;
+ if (!result)
+ return AOR_NAME_NOT_EXIST;
- normalizeString(username);
- normalizeString(password);
+ // Obtain accounts characters
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARS_BY_ACCOUNT_ID);
- PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD);
- stmt->setUInt32(0, accountId);
- stmt->setString(1, CalculateShaPassHash(username, password));
- PreparedQueryResult result = LoginDatabase.Query(stmt);
+ stmt->setUInt32(0, accountId);
- return (result) ? true : false;
-}
+ result = CharacterDatabase.Query(stmt);
-uint32 GetCharactersCount(uint32 accountId)
-{
- // check character count
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS);
- stmt->setUInt32(0, accountId);
- PreparedQueryResult result = CharacterDatabase.Query(stmt);
+ if (result)
+ {
+ do
+ {
+ uint32 guidLow = (*result)[0].GetUInt32();
+ uint64 guid = MAKE_NEW_GUID(guidLow, 0, HIGHGUID_PLAYER);
- return (result) ? (*result)[0].GetUInt64() : 0;
-}
+ // Kick if player is online
+ if (Player* p = ObjectAccessor::FindPlayer(guid))
+ {
+ WorldSession* s = p->GetSession();
+ s->KickPlayer(); // mark session to remove at next session list update
+ s->LogoutPlayer(false); // logout player without waiting next session list update
+ }
-bool normalizeString(std::string& utf8String)
-{
- wchar_t buffer[MAX_ACCOUNT_STR+1];
+ Player::DeleteFromDB(guid, accountId, false, true); // no need to update realm characters
+ } while (result->NextRow());
+ }
+
+ // table realm specific but common for all characters of account for realm
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_TUTORIALS);
+ stmt->setUInt32(0, accountId);
+ CharacterDatabase.Execute(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ACCOUNT_DATA);
+ stmt->setUInt32(0, accountId);
+ CharacterDatabase.Execute(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_BAN);
+ stmt->setUInt32(0, accountId);
+ CharacterDatabase.Execute(stmt);
+
+ SQLTransaction trans = LoginDatabase.BeginTransaction();
+
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT);
+ stmt->setUInt32(0, accountId);
+ trans->Append(stmt);
+
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS);
+ stmt->setUInt32(0, accountId);
+ trans->Append(stmt);
+
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_REALM_CHARACTERS);
+ stmt->setUInt32(0, accountId);
+ trans->Append(stmt);
+
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_BANNED);
+ stmt->setUInt32(0, accountId);
+ trans->Append(stmt);
+
+ LoginDatabase.CommitTransaction(trans);
+
+ return AOR_OK;
+ }
+
+
+ AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword)
+ {
+ // Check if accounts exists
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BY_ID);
+ stmt->setUInt32(0, accountId);
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ if (!result)
+ return AOR_NAME_NOT_EXIST;
+
+ if (utf8length(newUsername) > MAX_ACCOUNT_STR)
+ return AOR_NAME_TOO_LONG;
+
+ if (utf8length(newPassword) > MAX_ACCOUNT_STR)
+ return AOR_PASS_TOO_LONG;
+
+ normalizeString(newUsername);
+ normalizeString(newPassword);
+
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_USERNAME);
+
+ stmt->setString(0, newUsername);
+ stmt->setString(1, CalculateShaPassHash(newUsername, newPassword));
+ stmt->setUInt32(2, accountId);
+
+ LoginDatabase.Execute(stmt);
+
+ return AOR_OK;
+ }
+
+ AccountOpResult ChangePassword(uint32 accountId, std::string newPassword)
+ {
+ std::string username;
+
+ if (!GetName(accountId, username))
+ return AOR_NAME_NOT_EXIST; // account doesn't exist
- size_t maxLength = MAX_ACCOUNT_STR;
- if (!Utf8toWStr(utf8String, buffer, maxLength))
- return false;
+ if (utf8length(newPassword) > MAX_ACCOUNT_STR)
+ return AOR_PASS_TOO_LONG;
+
+ normalizeString(username);
+ normalizeString(newPassword);
+
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_PASSWORD);
+
+ stmt->setString(0, CalculateShaPassHash(username, newPassword));
+ stmt->setUInt32(1, accountId);
+
+ LoginDatabase.Execute(stmt);
+
+ return AOR_OK;
+ }
+
+ uint32 GetId(std::string const& username)
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ID_BY_USERNAME);
+ stmt->setString(0, username);
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ return (result) ? (*result)[0].GetUInt32() : 0;
+ }
+
+ uint32 GetSecurity(uint32 accountId)
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_ACCOUNT_ACCESS_GMLEVEL);
+ stmt->setUInt32(0, accountId);
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ return (result) ? (*result)[0].GetUInt8() : uint32(SEC_PLAYER);
+ }
+
+ uint32 GetSecurity(uint32 accountId, int32 realmId)
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID);
+ stmt->setUInt32(0, accountId);
+ stmt->setInt32(1, realmId);
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ return (result) ? (*result)[0].GetUInt8() : uint32(SEC_PLAYER);
+ }
+
+ bool GetName(uint32 accountId, std::string& name)
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_USERNAME_BY_ID);
+ stmt->setUInt32(0, accountId);
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ if (result)
+ {
+ name = (*result)[0].GetString();
+ return true;
+ }
+
+ return false;
+ }
+
+ bool CheckPassword(uint32 accountId, std::string password)
+ {
+ std::string username;
+
+ if (!GetName(accountId, username))
+ return false;
+
+ normalizeString(username);
+ normalizeString(password);
+
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD);
+ stmt->setUInt32(0, accountId);
+ stmt->setString(1, CalculateShaPassHash(username, password));
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ return (result) ? true : false;
+ }
+
+ uint32 GetCharactersCount(uint32 accountId)
+ {
+ // check character count
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SUM_CHARS);
+ stmt->setUInt32(0, accountId);
+ PreparedQueryResult result = CharacterDatabase.Query(stmt);
+
+ return (result) ? (*result)[0].GetUInt64() : 0;
+ }
+
+ bool normalizeString(std::string& utf8String)
+ {
+ wchar_t buffer[MAX_ACCOUNT_STR + 1];
+
+ size_t maxLength = MAX_ACCOUNT_STR;
+ if (!Utf8toWStr(utf8String, buffer, maxLength))
+ return false;
#ifdef _MSC_VER
#pragma warning(disable: 4996)
#endif
- std::transform(&buffer[0], buffer+maxLength, &buffer[0], wcharToUpperOnlyLatin);
+ std::transform(&buffer[0], buffer + maxLength, &buffer[0], wcharToUpperOnlyLatin);
#ifdef _MSC_VER
#pragma warning(default: 4996)
#endif
- return WStrToUtf8(buffer, maxLength, utf8String);
-}
+ return WStrToUtf8(buffer, maxLength, utf8String);
+ }
-std::string CalculateShaPassHash(std::string const& name, std::string const& password)
-{
- SHA1Hash sha;
- sha.Initialize();
- sha.UpdateData(name);
- sha.UpdateData(":");
- sha.UpdateData(password);
- sha.Finalize();
+ std::string CalculateShaPassHash(std::string const& name, std::string const& password)
+ {
+ SHA1Hash sha;
+ sha.Initialize();
+ sha.UpdateData(name);
+ sha.UpdateData(":");
+ sha.UpdateData(password);
+ sha.Finalize();
- return ByteArrayToHexStr(sha.GetDigest(), sha.GetLength());
-}
+ return ByteArrayToHexStr(sha.GetDigest(), sha.GetLength());
+ }
-bool IsPlayerAccount(uint32 gmlevel)
-{
- return gmlevel == SEC_PLAYER;
-}
+ bool IsPlayerAccount(uint32 gmlevel)
+ {
+ return gmlevel == SEC_PLAYER;
+ }
-bool IsGMAccount(uint32 gmlevel)
-{
- return gmlevel >= SEC_GAMEMASTER && gmlevel <= SEC_CONSOLE;
-}
+ bool IsGMAccount(uint32 gmlevel)
+ {
+ return gmlevel >= SEC_GAMEMASTER && gmlevel <= SEC_CONSOLE;
+ }
-bool IsAdminAccount(uint32 gmlevel)
-{
- return gmlevel >= SEC_ADMINISTRATOR && gmlevel <= SEC_CONSOLE;
-}
+ bool IsAdminAccount(uint32 gmlevel)
+ {
+ return gmlevel >= SEC_ADMINISTRATOR && gmlevel <= SEC_CONSOLE;
+ }
-bool IsConsoleAccount(uint32 gmlevel)
-{
- return gmlevel == SEC_CONSOLE;
-}
+ bool IsConsoleAccount(uint32 gmlevel)
+ {
+ return gmlevel == SEC_CONSOLE;
+ }
} // Namespace AccountMgr
diff --git a/src/server/game/Accounts/AccountMgr.h b/src/server/game/Accounts/AccountMgr.h
index e4f070121f..0a17e7da01 100644
--- a/src/server/game/Accounts/AccountMgr.h
+++ b/src/server/game/Accounts/AccountMgr.h
@@ -36,6 +36,10 @@ enum AccountOpResult
namespace AccountMgr
{
+ AccountOpResult CreateAccount(std::string username, std::string password);
+ AccountOpResult DeleteAccount(uint32 accountId);
+ AccountOpResult ChangeUsername(uint32 accountId, std::string newUsername, std::string newPassword);
+ AccountOpResult ChangePassword(uint32 accountId, std::string newPassword);
bool CheckPassword(uint32 accountId, std::string password);
uint32 GetId(std::string const& username);
diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
index ecd4df7363..52e37d23d2 100644
--- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
+++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp
@@ -51,6 +51,9 @@ AuctionHouseMgr::~AuctionHouseMgr()
AuctionHouseObject* AuctionHouseMgr::GetAuctionsMap(uint32 factionTemplateId)
{
+ if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
+ return &mNeutralAuctions;
+
// team have linked auction houses
FactionTemplateEntry const* u_entry = sFactionTemplateStore.LookupEntry(factionTemplateId);
if (!u_entry)
@@ -372,7 +375,7 @@ AuctionHouseEntry const* AuctionHouseMgr::GetAuctionHouseEntry(uint32 factionTem
{
uint32 houseid = 7; // goblin auction house
- //if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
+ if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
{
//FIXME: found way for proper auctionhouse selection by another way
// AuctionHouse.dbc have faction field with _player_ factions associated with auction house races.
diff --git a/src/server/game/Chat/Channels/Channel.cpp b/src/server/game/Chat/Channels/Channel.cpp
index a2c31b2fee..8c801afef6 100644
--- a/src/server/game/Chat/Channels/Channel.cpp
+++ b/src/server/game/Chat/Channels/Channel.cpp
@@ -594,7 +594,8 @@ void Channel::SetMode(Player const* player, std::string const& p2n, bool mod, bo
if (!victim || !IsOn(victim) ||
// allow make moderator from another team only if both is GMs
// at this moment this only way to show channel post for GM from another team
- ((!AccountMgr::IsGMAccount(sec) || !AccountMgr::IsGMAccount(newp->GetSession()->GetSecurity())) && player->GetTeamId() != newp->GetTeamId()))
+ ((!AccountMgr::IsGMAccount(sec) || !AccountMgr::IsGMAccount(newp->GetSession()->GetSecurity())) && player->GetTeamId() != newp->GetTeamId() &&
+ !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL)))
{
WorldPacket data;
MakePlayerNotFound(&data, p2n);
@@ -659,7 +660,8 @@ void Channel::SetOwner(Player const* player, std::string const& newname)
Player* newp = ObjectAccessor::FindPlayerByName(newname, false);
uint64 victim = newp ? newp->GetGUID() : 0;
- if (!victim || !IsOn(victim) || newp->GetTeamId() != player->GetTeamId())
+ if (!victim || !IsOn(victim) || newp->GetTeamId() != player->GetTeamId() &&
+ !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL))
{
WorldPacket data;
MakePlayerNotFound(&data, newname);
@@ -764,6 +766,9 @@ void Channel::Say(uint64 guid, std::string const& what, uint32 lang)
if (what.empty())
return;
+ if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL))
+ lang = LANG_UNIVERSAL;
+
if (!IsOn(guid))
{
WorldPacket data;
diff --git a/src/server/game/Chat/Channels/ChannelMgr.cpp b/src/server/game/Chat/Channels/ChannelMgr.cpp
index 5716d3a2d6..2826aa298a 100644
--- a/src/server/game/Chat/Channels/ChannelMgr.cpp
+++ b/src/server/game/Chat/Channels/ChannelMgr.cpp
@@ -1,201 +1,205 @@
-/*
- * Copyright (C)
- * Copyright (C)
- *
- * 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/>.
- */
-
-#include "ChannelMgr.h"
-#include "Player.h"
-#include "World.h"
-
-ChannelMgr::~ChannelMgr()
-{
- for (ChannelMap::iterator itr = channels.begin(); itr != channels.end(); ++itr)
- delete itr->second;
-
- channels.clear();
-}
-
-ChannelMgr* ChannelMgr::forTeam(TeamId teamId)
-{
- if (teamId == TEAM_ALLIANCE)
- return ACE_Singleton<AllianceChannelMgr, ACE_Null_Mutex>::instance();
-
- if (teamId == TEAM_HORDE)
- return ACE_Singleton<HordeChannelMgr, ACE_Null_Mutex>::instance();
-
- return NULL;
-}
-
-
-void ChannelMgr::LoadChannels()
-{
- uint32 oldMSTime = getMSTime();
- uint32 count = 0;
-
- QueryResult result = CharacterDatabase.PQuery("SELECT channelId, name, team, announce, password FROM channels WHERE team = %u ORDER BY channelId ASC", _teamId);
- if (!result)
- {
- sLog->outString(">> Loaded 0 channels for %s", _teamId == TEAM_ALLIANCE ? "Alliance" : "Horde");
- sLog->outString();
- return;
- }
-
- do
- {
- Field* fields = result->Fetch();
- if (!fields)
- break;
-
- uint32 channelDBId = fields[0].GetUInt32();
- std::string channelName = fields[1].GetString();
- std::string password = fields[4].GetString();
- std::wstring channelWName;
- Utf8toWStr(channelName, channelWName);
-
- Channel* newChannel = new Channel(channelName, 0, channelDBId, TeamId(fields[2].GetUInt32()), fields[3].GetUInt8());
- newChannel->SetPassword(password);
- channels[channelWName] = newChannel;
-
- if (QueryResult banResult = CharacterDatabase.PQuery("SELECT playerGUID, banTime FROM channels_bans WHERE channelId = %u", channelDBId))
- {
- do
- {
- Field* banFields = banResult->Fetch();
- if (!banFields)
- break;
- newChannel->AddBan(banFields[0].GetUInt32(), banFields[1].GetUInt32());
- }
- while (banResult->NextRow());
- }
-
- if (channelDBId > ChannelMgr::_channelIdMax) ChannelMgr::_channelIdMax = channelDBId;
- ++count;
- }
- while (result->NextRow());
-
- sLog->outString(">> Loaded %u channels for %s in %ums", count, _teamId == TEAM_ALLIANCE ? "Alliance" : "Horde", GetMSTimeDiffToNow(oldMSTime));
- sLog->outString();
-}
-
-Channel* ChannelMgr::GetJoinChannel(std::string const& name, uint32 channelId)
-{
- std::wstring wname;
- Utf8toWStr(name, wname);
- wstrToLower(wname);
-
- ChannelMap::const_iterator i = channels.find(wname);
-
- if (i == channels.end())
- {
- std::string chNameLower = name;
- std::transform(chNameLower.begin(), chNameLower.end(), chNameLower.begin(), ::tolower);
- Channel* nchan = new Channel(chNameLower, channelId, 0, _teamId);
- channels[wname] = nchan;
- return nchan;
- }
-
- return i->second;
-}
-
-Channel* ChannelMgr::GetChannel(std::string const& name, Player* player, bool pkt)
-{
- std::wstring wname;
- Utf8toWStr(name, wname);
- wstrToLower(wname);
-
- ChannelMap::const_iterator i = channels.find(wname);
-
- if (i == channels.end())
- {
- if (pkt)
- {
- WorldPacket data;
- MakeNotOnPacket(&data, name);
- player->GetSession()->SendPacket(&data);
- }
-
- return NULL;
- }
-
- return i->second;
-}
-
-
-uint32 ChannelMgr::_channelIdMax = 0;
-ChannelMgr::ChannelRightsMap ChannelMgr::channels_rights;
-ChannelRights ChannelMgr::channelRightsEmpty;
-
-void ChannelMgr::LoadChannelRights()
-{
- uint32 oldMSTime = getMSTime();
- channels_rights.clear();
-
- QueryResult result = CharacterDatabase.Query("SELECT name, flags, speakdelay, joinmessage, delaymessage, moderators FROM channels_rights");
- if (!result)
- {
- sLog->outString();
- sLog->outString(">> Loaded 0 Channel Rights!");
- return;
- }
-
- uint32 count = 0;
- do
- {
- Field* fields = result->Fetch();
- std::set<uint32> moderators;
- const char* moderatorList = fields[5].GetCString();
- if (moderatorList)
- {
- Tokenizer tokens(moderatorList, ' ');
- for (Tokenizer::const_iterator i = tokens.begin(); i != tokens.end(); ++i)
- {
- uint64 moderator_acc = atol(*i);
- if (moderator_acc && ((uint32)moderator_acc) == moderator_acc)
- moderators.insert((uint32)moderator_acc);
- }
- }
-
- SetChannelRightsFor(fields[0].GetString(), fields[1].GetUInt32(), fields[2].GetUInt32(), fields[3].GetString(), fields[4].GetString(), moderators);
-
- ++count;
- } while (result->NextRow());
-
- sLog->outString(">> Loaded %d Channel Rights in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
- sLog->outString();
-}
-
-const ChannelRights& ChannelMgr::GetChannelRightsFor(const std::string& name)
-{
- std::string nameStr = name;
- std::transform(nameStr.begin(), nameStr.end(), nameStr.begin(), ::tolower);
- ChannelRightsMap::const_iterator itr = channels_rights.find(nameStr);
- if (itr != channels_rights.end())
- return itr->second;
- return channelRightsEmpty;
-}
-
-void ChannelMgr::SetChannelRightsFor(const std::string& name, const uint32& flags, const uint32& speakDelay, const std::string& joinmessage, const std::string& speakmessage, const std::set<uint32>& moderators)
-{
- std::string nameStr = name;
- std::transform(nameStr.begin(), nameStr.end(), nameStr.begin(), ::tolower);
- channels_rights[nameStr] = ChannelRights(flags, speakDelay, joinmessage, speakmessage, moderators);
-}
-
-void ChannelMgr::MakeNotOnPacket(WorldPacket* data, std::string const& name)
-{
- data->Initialize(SMSG_CHANNEL_NOTIFY, 1 + name.size());
- (*data) << uint8(5) << name;
-}
+/*
+ * Copyright (C)
+ * Copyright (C)
+ *
+ * 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/>.
+ */
+
+#include "ChannelMgr.h"
+#include "Player.h"
+#include "World.h"
+
+ChannelMgr::~ChannelMgr()
+{
+ for (ChannelMap::iterator itr = channels.begin(); itr != channels.end(); ++itr)
+ delete itr->second;
+
+ channels.clear();
+}
+
+ChannelMgr* ChannelMgr::forTeam(TeamId teamId)
+{
+ if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL))
+ return ACE_Singleton<AllianceChannelMgr, ACE_Null_Mutex>::instance(); // cross-faction
+
+ if (teamId == TEAM_ALLIANCE)
+ return ACE_Singleton<AllianceChannelMgr, ACE_Null_Mutex>::instance();
+
+ if (teamId == TEAM_HORDE)
+ return ACE_Singleton<HordeChannelMgr, ACE_Null_Mutex>::instance();
+
+ return NULL;
+}
+
+
+void ChannelMgr::LoadChannels()
+{
+ uint32 oldMSTime = getMSTime();
+ uint32 count = 0;
+
+ QueryResult result = CharacterDatabase.PQuery("SELECT channelId, name, team, announce, password FROM channels WHERE team = %u ORDER BY channelId ASC", _teamId);
+ if (!result)
+ {
+ sLog->outString(">> Loaded 0 channels for %s", _teamId == TEAM_ALLIANCE ? "Alliance" : "Horde");
+ sLog->outString();
+ return;
+ }
+
+ do
+ {
+ Field* fields = result->Fetch();
+ if (!fields)
+ break;
+
+ uint32 channelDBId = fields[0].GetUInt32();
+ std::string channelName = fields[1].GetString();
+ std::string password = fields[4].GetString();
+ std::wstring channelWName;
+ Utf8toWStr(channelName, channelWName);
+
+ Channel* newChannel = new Channel(channelName, 0, channelDBId, TeamId(fields[2].GetUInt32()), fields[3].GetUInt8());
+ newChannel->SetPassword(password);
+ channels[channelWName] = newChannel;
+
+ if (QueryResult banResult = CharacterDatabase.PQuery("SELECT playerGUID, banTime FROM channels_bans WHERE channelId = %u", channelDBId))
+ {
+ do
+ {
+ Field* banFields = banResult->Fetch();
+ if (!banFields)
+ break;
+ newChannel->AddBan(banFields[0].GetUInt32(), banFields[1].GetUInt32());
+ }
+ while (banResult->NextRow());
+ }
+
+ if (channelDBId > ChannelMgr::_channelIdMax)
+ ChannelMgr::_channelIdMax = channelDBId;
+ ++count;
+ }
+ while (result->NextRow());
+
+ sLog->outString(">> Loaded %u channels for %s in %ums", count, _teamId == TEAM_ALLIANCE ? "Alliance" : "Horde", GetMSTimeDiffToNow(oldMSTime));
+ sLog->outString();
+}
+
+Channel* ChannelMgr::GetJoinChannel(std::string const& name, uint32 channelId)
+{
+ std::wstring wname;
+ Utf8toWStr(name, wname);
+ wstrToLower(wname);
+
+ ChannelMap::const_iterator i = channels.find(wname);
+
+ if (i == channels.end())
+ {
+ std::string chNameLower = name;
+ std::transform(chNameLower.begin(), chNameLower.end(), chNameLower.begin(), ::tolower);
+ Channel* nchan = new Channel(chNameLower, channelId, 0, _teamId);
+ channels[wname] = nchan;
+ return nchan;
+ }
+
+ return i->second;
+}
+
+Channel* ChannelMgr::GetChannel(std::string const& name, Player* player, bool pkt)
+{
+ std::wstring wname;
+ Utf8toWStr(name, wname);
+ wstrToLower(wname);
+
+ ChannelMap::const_iterator i = channels.find(wname);
+
+ if (i == channels.end())
+ {
+ if (pkt)
+ {
+ WorldPacket data;
+ MakeNotOnPacket(&data, name);
+ player->GetSession()->SendPacket(&data);
+ }
+
+ return NULL;
+ }
+
+ return i->second;
+}
+
+
+uint32 ChannelMgr::_channelIdMax = 0;
+ChannelMgr::ChannelRightsMap ChannelMgr::channels_rights;
+ChannelRights ChannelMgr::channelRightsEmpty;
+
+void ChannelMgr::LoadChannelRights()
+{
+ uint32 oldMSTime = getMSTime();
+ channels_rights.clear();
+
+ QueryResult result = CharacterDatabase.Query("SELECT name, flags, speakdelay, joinmessage, delaymessage, moderators FROM channels_rights");
+ if (!result)
+ {
+ sLog->outString();
+ sLog->outString(">> Loaded 0 Channel Rights!");
+ return;
+ }
+
+ uint32 count = 0;
+ do
+ {
+ Field* fields = result->Fetch();
+ std::set<uint32> moderators;
+ const char* moderatorList = fields[5].GetCString();
+ if (moderatorList)
+ {
+ Tokenizer tokens(moderatorList, ' ');
+ for (Tokenizer::const_iterator i = tokens.begin(); i != tokens.end(); ++i)
+ {
+ uint64 moderator_acc = atol(*i);
+ if (moderator_acc && ((uint32)moderator_acc) == moderator_acc)
+ moderators.insert((uint32)moderator_acc);
+ }
+ }
+
+ SetChannelRightsFor(fields[0].GetString(), fields[1].GetUInt32(), fields[2].GetUInt32(), fields[3].GetString(), fields[4].GetString(), moderators);
+
+ ++count;
+ } while (result->NextRow());
+
+ sLog->outString(">> Loaded %d Channel Rights in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ sLog->outString();
+}
+
+const ChannelRights& ChannelMgr::GetChannelRightsFor(const std::string& name)
+{
+ std::string nameStr = name;
+ std::transform(nameStr.begin(), nameStr.end(), nameStr.begin(), ::tolower);
+ ChannelRightsMap::const_iterator itr = channels_rights.find(nameStr);
+ if (itr != channels_rights.end())
+ return itr->second;
+ return channelRightsEmpty;
+}
+
+void ChannelMgr::SetChannelRightsFor(const std::string& name, const uint32& flags, const uint32& speakDelay, const std::string& joinmessage, const std::string& speakmessage, const std::set<uint32>& moderators)
+{
+ std::string nameStr = name;
+ std::transform(nameStr.begin(), nameStr.end(), nameStr.begin(), ::tolower);
+ channels_rights[nameStr] = ChannelRights(flags, speakDelay, joinmessage, speakmessage, moderators);
+}
+
+void ChannelMgr::MakeNotOnPacket(WorldPacket* data, std::string const& name)
+{
+ data->Initialize(SMSG_CHANNEL_NOTIFY, 1 + name.size());
+ (*data) << uint8(5) << name;
+}
diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp
index 2ecf497505..c72eac5699 100644
--- a/src/server/game/DungeonFinding/LFGMgr.cpp
+++ b/src/server/game/DungeonFinding/LFGMgr.cpp
@@ -1,2595 +1,2599 @@
-/*
- * Copyright (C)
- *
- * 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/>.
- */
-
-#include "Common.h"
-#include "SharedDefines.h"
-#include "DBCStores.h"
-#include "DisableMgr.h"
-#include "ObjectMgr.h"
-#include "SocialMgr.h"
-#include "Language.h"
-#include "LFGMgr.h"
-#include "LFGScripts.h"
-#include "LFGGroupData.h"
-#include "LFGPlayerData.h"
-#include "LFGQueue.h"
-#include "Group.h"
-#include "SpellAuras.h"
-#include "Player.h"
-#include "GroupMgr.h"
-#include "GameEventMgr.h"
-#include "WorldSession.h"
-
-namespace lfg
-{
-
-LFGMgr::LFGMgr(): m_lfgProposalId(1), m_options(sWorld->getIntConfig(CONFIG_LFG_OPTIONSMASK))
-{
- new LFGPlayerScript();
- new LFGGroupScript();
-
- for (uint8 team=0; team<2; ++team)
- {
- m_raidBrowserUpdateTimer[team] = 10000;
- m_raidBrowserLastUpdatedDungeonId[team] = 0;
- }
-}
-
-LFGMgr::~LFGMgr()
-{
- for (LfgRewardContainer::iterator itr = RewardMapStore.begin(); itr != RewardMapStore.end(); ++itr)
- delete itr->second;
-}
-
-void LFGMgr::_LoadFromDB(Field* fields, uint64 guid)
-{
- if (!fields)
- return;
-
- if (!IS_GROUP_GUID(guid))
- return;
-
- SetLeader(guid, MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER));
-
- uint32 dungeon = fields[17].GetUInt32();
- uint8 state = fields[18].GetUInt8();
-
- if (!dungeon || !state)
- return;
-
- SetDungeon(guid, dungeon);
-
- switch (state)
- {
- case LFG_STATE_DUNGEON:
- case LFG_STATE_FINISHED_DUNGEON:
- SetState(guid, (LfgState)state);
- break;
- default:
- break;
- }
-}
-
-void LFGMgr::_SaveToDB(uint64 guid)
-{
- if (!IS_GROUP_GUID(guid))
- return;
-
- PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_LFG_DATA);
- stmt->setUInt32(0, GUID_LOPART(guid));
- stmt->setUInt32(1, GetDungeon(guid));
- stmt->setUInt32(2, GetState(guid));
- CharacterDatabase.Execute(stmt);
-}
-
-/// Load rewards for completing dungeons
-void LFGMgr::LoadRewards()
-{
- uint32 oldMSTime = getMSTime();
-
- for (LfgRewardContainer::iterator itr = RewardMapStore.begin(); itr != RewardMapStore.end(); ++itr)
- delete itr->second;
- RewardMapStore.clear();
-
- // ORDER BY is very important for GetRandomDungeonReward!
- QueryResult result = WorldDatabase.Query("SELECT dungeonId, maxLevel, firstQuestId, otherQuestId FROM lfg_dungeon_rewards ORDER BY dungeonId, maxLevel ASC");
-
- if (!result)
- {
- sLog->outError(">> Loaded 0 lfg dungeon rewards. DB table `lfg_dungeon_rewards` is empty!");
- return;
- }
-
- uint32 count = 0;
-
- Field* fields = NULL;
- do
- {
- fields = result->Fetch();
- uint32 dungeonId = fields[0].GetUInt32();
- uint32 maxLevel = fields[1].GetUInt8();
- uint32 firstQuestId = fields[2].GetUInt32();
- uint32 otherQuestId = fields[3].GetUInt32();
-
- if (!GetLFGDungeonEntry(dungeonId))
- {
- sLog->outError("Dungeon %u specified in table `lfg_dungeon_rewards` does not exist!", dungeonId);
- continue;
- }
-
- if (!maxLevel || maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
- {
- sLog->outError("Level %u specified for dungeon %u in table `lfg_dungeon_rewards` can never be reached!", maxLevel, dungeonId);
- maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
- }
-
- if (!firstQuestId || !sObjectMgr->GetQuestTemplate(firstQuestId))
- {
- sLog->outError("First quest %u specified for dungeon %u in table `lfg_dungeon_rewards` does not exist!", firstQuestId, dungeonId);
- continue;
- }
-
- if (otherQuestId && !sObjectMgr->GetQuestTemplate(otherQuestId))
- {
- sLog->outError("Other quest %u specified for dungeon %u in table `lfg_dungeon_rewards` does not exist!", otherQuestId, dungeonId);
- otherQuestId = 0;
- }
-
- RewardMapStore.insert(LfgRewardContainer::value_type(dungeonId, new LfgReward(maxLevel, firstQuestId, otherQuestId)));
- ++count;
- }
- while (result->NextRow());
-
- sLog->outString(">> Loaded %u lfg dungeon rewards in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
- sLog->outString();
-}
-
-LFGDungeonData const* LFGMgr::GetLFGDungeon(uint32 id)
-{
- LFGDungeonContainer::const_iterator itr = LfgDungeonStore.find(id);
- if (itr != LfgDungeonStore.end())
- return &(itr->second);
-
- return NULL;
-}
-
-void LFGMgr::LoadLFGDungeons(bool reload /* = false */)
-{
- uint32 oldMSTime = getMSTime();
-
- LfgDungeonStore.clear();
-
- // Initialize Dungeon map with data from dbcs
- for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i)
- {
- LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(i);
- if (!dungeon)
- continue;
-
- switch (dungeon->type)
- {
- case LFG_TYPE_DUNGEON:
- case LFG_TYPE_HEROIC:
- case LFG_TYPE_RAID:
- case LFG_TYPE_RANDOM:
- LfgDungeonStore[dungeon->ID] = LFGDungeonData(dungeon);
- break;
- }
- }
-
- // Fill teleport locations from DB
- QueryResult result = WorldDatabase.Query("SELECT dungeonId, position_x, position_y, position_z, orientation FROM lfg_entrances");
-
- if (!result)
- {
- sLog->outError(">> Loaded 0 lfg entrance positions. DB table `lfg_entrances` is empty!");
- return;
- }
-
- uint32 count = 0;
-
- do
- {
- Field* fields = result->Fetch();
- uint32 dungeonId = fields[0].GetUInt32();
- LFGDungeonContainer::iterator dungeonItr = LfgDungeonStore.find(dungeonId);
- if (dungeonItr == LfgDungeonStore.end())
- {
- sLog->outError("table `lfg_entrances` contains coordinates for wrong dungeon %u", dungeonId);
- continue;
- }
-
- LFGDungeonData& data = dungeonItr->second;
- data.x = fields[1].GetFloat();
- data.y = fields[2].GetFloat();
- data.z = fields[3].GetFloat();
- data.o = fields[4].GetFloat();
-
- ++count;
- }
- while (result->NextRow());
-
- sLog->outString(">> Loaded %u lfg entrance positions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
-
- // Fill all other teleport coords from areatriggers
- for (LFGDungeonContainer::iterator itr = LfgDungeonStore.begin(); itr != LfgDungeonStore.end(); ++itr)
- {
- LFGDungeonData& dungeon = itr->second;
-
- // No teleport coords in database, load from areatriggers
- if (dungeon.type != LFG_TYPE_RANDOM && dungeon.x == 0.0f && dungeon.y == 0.0f && dungeon.z == 0.0f)
- {
- AreaTrigger const* at = sObjectMgr->GetMapEntranceTrigger(dungeon.map);
- if (!at)
- {
- sLog->outError("LFGMgr::LoadLFGDungeons: Failed to load dungeon %s, cant find areatrigger for map %u", dungeon.name.c_str(), dungeon.map);
- continue;
- }
-
- dungeon.map = at->target_mapId;
- dungeon.x = at->target_X;
- dungeon.y = at->target_Y;
- dungeon.z = at->target_Z;
- dungeon.o = at->target_Orientation;
- }
-
- if (dungeon.type != LFG_TYPE_RANDOM)
- CachedDungeonMapStore[dungeon.group].insert(dungeon.id);
- CachedDungeonMapStore[0].insert(dungeon.id);
- }
-
- if (reload)
- {
- CachedDungeonMapStore.clear();
- // Recalculate locked dungeons
- for (LfgPlayerDataContainer::const_iterator it = PlayersStore.begin(); it != PlayersStore.end(); ++it)
- if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(it->first))
- InitializeLockedDungeons(player);
- }
-}
-
-void LFGMgr::Update(uint32 tdiff, uint8 task)
-{
- if (!isOptionEnabled(LFG_OPTION_ENABLE_DUNGEON_FINDER | LFG_OPTION_ENABLE_RAID_BROWSER))
- return;
-
- if (task == 0)
- {
- time_t currTime = time(NULL);
-
- // Remove obsolete role checks
- for (LfgRoleCheckContainer::iterator it = RoleChecksStore.begin(); it != RoleChecksStore.end();)
- {
- LfgRoleCheckContainer::iterator itRoleCheck = it++;
- LfgRoleCheck& roleCheck = itRoleCheck->second;
- if (currTime < roleCheck.cancelTime)
- continue;
- roleCheck.state = LFG_ROLECHECK_MISSING_ROLE;
-
- for (LfgRolesMap::const_iterator itRoles = roleCheck.roles.begin(); itRoles != roleCheck.roles.end(); ++itRoles)
- {
- uint64 guid = itRoles->first;
- RestoreState(guid, "Remove Obsolete RoleCheck");
- SendLfgRoleCheckUpdate(guid, roleCheck);
- if (guid == roleCheck.leader)
- SendLfgJoinResult(guid, LfgJoinResultData(LFG_JOIN_FAILED, LFG_ROLECHECK_MISSING_ROLE));
- }
-
- RestoreState(itRoleCheck->first, "Remove Obsolete RoleCheck");
- RoleChecksStore.erase(itRoleCheck);
- }
-
- // Remove obsolete proposals
- for (LfgProposalContainer::iterator it = ProposalsStore.begin(); it != ProposalsStore.end();)
- {
- LfgProposalContainer::iterator itRemove = it++;
- if (itRemove->second.cancelTime < currTime)
- RemoveProposal(itRemove, LFG_UPDATETYPE_PROPOSAL_FAILED);
- }
-
- // Remove obsolete kicks
- for (LfgPlayerBootContainer::iterator it = BootsStore.begin(); it != BootsStore.end();)
- {
- LfgPlayerBootContainer::iterator itBoot = it++;
- LfgPlayerBoot& boot = itBoot->second;
- if (boot.cancelTime < currTime)
- {
- boot.inProgress = false;
- for (LfgAnswerContainer::const_iterator itVotes = boot.votes.begin(); itVotes != boot.votes.end(); ++itVotes)
- {
- uint64 pguid = itVotes->first;
- if (pguid != boot.victim)
- SendLfgBootProposalUpdate(pguid, boot);
- SetState(pguid, LFG_STATE_DUNGEON);
- }
- SetState(itBoot->first, LFG_STATE_DUNGEON);
- BootsStore.erase(itBoot);
- }
- }
- }
- else if (task == 1)
- {
- this->lastProposalId = m_lfgProposalId; // pussywizard: task 2 is done independantly, store previous value in LFGMgr for future use
- uint8 newGroupsProcessed = 0;
- // Check if a proposal can be formed with the new groups being added
- for (LfgQueueContainer::iterator it = QueuesStore.begin(); it != QueuesStore.end(); ++it)
- {
- newGroupsProcessed += it->second.FindGroups();
- if (newGroupsProcessed)
- break;
- }
-
- // Update all players status queue info
- if (!newGroupsProcessed) // don't do this on updates that precessed groups (performance)
- for (LfgQueueContainer::iterator it = QueuesStore.begin(); it != QueuesStore.end(); ++it)
- it->second.UpdateQueueTimers(tdiff);
- }
- else if (task == 2)
- {
- if (lastProposalId != m_lfgProposalId)
- {
- // pussywizard: only one proposal can be created in World::Update (during maps update), and it has id == m_lfgProposalId, so try to find only that one, dunno why for loop here xD
- for (LfgProposalContainer::const_iterator itProposal = ProposalsStore.find(m_lfgProposalId); itProposal != ProposalsStore.end(); ++itProposal)
- {
- uint32 proposalId = itProposal->first;
- LfgProposal& proposal = ProposalsStore[proposalId];
-
- uint64 guid = 0;
- for (LfgProposalPlayerContainer::const_iterator itPlayers = proposal.players.begin(); itPlayers != proposal.players.end(); ++itPlayers)
- {
- guid = itPlayers->first;
- SetState(guid, LFG_STATE_PROPOSAL);
- if (uint64 gguid = GetGroup(guid))
- {
- SetState(gguid, LFG_STATE_PROPOSAL);
- SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid)));
- }
- else
- SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid)));
- SendLfgUpdateProposal(guid, proposal);
- }
-
- if (proposal.state == LFG_PROPOSAL_SUCCESS) // pussywizard: no idea what's the purpose of this xD
- UpdateProposal(proposalId, guid, true);
- }
- }
-
- UpdateRaidBrowser(tdiff);
- }
-}
-
-/**
- Generate the dungeon lock map for a given player
-
- @param[in] player Player we need to initialize the lock status map
-*/
-void LFGMgr::InitializeLockedDungeons(Player* player, uint8 level /* = 0 */)
-{
- uint64 guid = player->GetGUID();
- if (!level)
- level = player->getLevel();
- uint8 expansion = player->GetSession()->Expansion();
- LfgDungeonSet const& dungeons = GetDungeonsByRandom(0);
- LfgLockMap lock;
-
- float avgItemLevel = player->GetAverageItemLevelForDF();
-
- for (LfgDungeonSet::const_iterator it = dungeons.begin(); it != dungeons.end(); ++it)
- {
- LFGDungeonData const* dungeon = GetLFGDungeon(*it);
- if (!dungeon) // should never happen - We provide a list from sLFGDungeonStore
- continue;
- MapEntry const* mapEntry = sMapStore.LookupEntry(dungeon->map);
-
- uint32 lockData = 0;
- if (dungeon->expansion > expansion)
- lockData = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION;
- else if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, dungeon->map, player))
- lockData = LFG_LOCKSTATUS_RAID_LOCKED;
- else if (dungeon->difficulty > DUNGEON_DIFFICULTY_NORMAL && (!mapEntry || !mapEntry->IsRaid()) && sInstanceSaveMgr->PlayerIsPermBoundToInstance(player->GetGUIDLow(), dungeon->map, Difficulty(dungeon->difficulty)))
- lockData = LFG_LOCKSTATUS_RAID_LOCKED;
- else if (dungeon->minlevel > level)
- lockData = LFG_LOCKSTATUS_TOO_LOW_LEVEL;
- else if (dungeon->maxlevel < level)
- lockData = LFG_LOCKSTATUS_TOO_HIGH_LEVEL;
- else if (dungeon->seasonal && !IsSeasonActive(dungeon->id))
- lockData = LFG_LOCKSTATUS_NOT_IN_SEASON;
- else if (AccessRequirement const* ar = sObjectMgr->GetAccessRequirement(dungeon->map, Difficulty(dungeon->difficulty)))
- {
- if (ar->achievement && !player->HasAchieved(ar->achievement))
- lockData = LFG_LOCKSTATUS_MISSING_ACHIEVEMENT;
- else if (ar->reqItemLevel && (float)ar->reqItemLevel > avgItemLevel)
- lockData = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE;
- else if (player->GetTeamId() == TEAM_ALLIANCE && ar->quest_A && !player->GetQuestRewardStatus(ar->quest_A))
- lockData = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED;
- else if (player->GetTeamId() == TEAM_HORDE && ar->quest_H && !player->GetQuestRewardStatus(ar->quest_H))
- lockData = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED;
- else
- if (ar->item)
- {
- if (!player->HasItemCount(ar->item) && (!ar->item2 || !player->HasItemCount(ar->item2)))
- lockData = LFG_LOCKSTATUS_MISSING_ITEM;
- }
- else if (ar->item2 && !player->HasItemCount(ar->item2))
- lockData = LFG_LOCKSTATUS_MISSING_ITEM;
- }
-
- /* TODO VoA closed if WG is not under team control (LFG_LOCKSTATUS_RAID_LOCKED)
- lockData = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE;
- lockData = LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE;
- lockData = LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL;
- lockData = LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL;
- */
-
- if (lockData)
- lock[dungeon->Entry()] = lockData;
- }
- SetLockedDungeons(guid, lock);
-}
-
-/**
- Adds the player/group to lfg queue. If player is in a group then it is the leader
- of the group tying to join the group. Join conditions are checked before adding
- to the new queue.
-
- @param[in] player Player trying to join (or leader of group trying to join)
- @param[in] roles Player selected roles
- @param[in] dungeons Dungeons the player/group is applying for
- @param[in] comment Player selected comment
-*/
-void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const std::string& comment)
-{
- if (!player || dungeons.empty())
- return;
-
- Group* grp = player->GetGroup();
- uint64 guid = player->GetGUID();
- uint64 gguid = grp ? grp->GetGUID() : guid;
- LfgJoinResultData joinData;
- LfgGuidSet players;
- uint32 rDungeonId = 0;
- bool isContinue = grp && grp->isLFGGroup() && GetState(gguid) != LFG_STATE_FINISHED_DUNGEON;
-
- if (grp && (grp->isBGGroup() || grp->isBFGroup()))
- return;
-
- // pussywizard: can't join LFG/LFR while using LFR
- if (GetState(player->GetGUID()) == LFG_STATE_RAIDBROWSER)
- {
- LfgDungeonSet tmp;
- SendRaidBrowserJoinedPacket(player, tmp, ""); // the df "eye" can disappear in various case, resend if needed
- return;
- }
-
- // Do not allow to change dungeon in the middle of a current dungeon
- if (isContinue)
- {
- dungeons.clear();
- dungeons.insert(GetDungeon(gguid));
- }
-
- LfgState state = GetState(gguid);
- switch (state)
- {
- case LFG_STATE_ROLECHECK: // if joining again during rolecheck (eg. many players clicked continue inside instance)
- if (IS_GROUP_GUID(gguid))
- UpdateRoleCheck(gguid); // abort role check and remove from RoleChecksStore
- break;
- case LFG_STATE_QUEUED: // joining again while in a queue
- {
- LFGQueue& queue = GetQueue(gguid);
- queue.RemoveFromQueue(gguid);
- }
- break;
- case LFG_STATE_PROPOSAL: // if joining again during proposal
- joinData.result = LFG_JOIN_INTERNAL_ERROR;
- break;
- case LFG_STATE_FINISHED_DUNGEON:
- if (grp && grp->isLFGGroup())
- joinData.result = LFG_JOIN_PARTY_NOT_MEET_REQS;
- break;
- default:
- break;
- }
-
- // Check if all dungeons are valid
- bool isRaid = false;
- if (joinData.result == LFG_JOIN_OK)
- {
- bool isDungeon = false;
- for (LfgDungeonSet::const_iterator it = dungeons.begin(); it != dungeons.end() && joinData.result == LFG_JOIN_OK; ++it)
- {
- LfgType type = GetDungeonType(*it);
- switch (type)
- {
- case LFG_TYPE_RANDOM:
- if (dungeons.size() > 1) // Only allow 1 random dungeon
- joinData.result = LFG_JOIN_DUNGEON_INVALID;
- else
- rDungeonId = (*dungeons.begin());
- // No break on purpose (Random can only be dungeon or heroic dungeon)
- case LFG_TYPE_HEROIC:
- case LFG_TYPE_DUNGEON:
- if (isRaid)
- joinData.result = LFG_JOIN_MIXED_RAID_DUNGEON;
- isDungeon = true;
- break;
- case LFG_TYPE_RAID:
- if (isDungeon)
- joinData.result = LFG_JOIN_MIXED_RAID_DUNGEON;
- isRaid = true;
- break;
- default:
- sLog->outError("Wrong dungeon type %u for dungeon %u", type, *it);
- joinData.result = LFG_JOIN_DUNGEON_INVALID;
- break;
- }
- }
- }
-
- if (!isRaid && joinData.result == LFG_JOIN_OK)
- {
- // Check player or group member restrictions
- if (player->InBattleground() || player->InArena() || player->InBattlegroundQueue())
- joinData.result = LFG_JOIN_USING_BG_SYSTEM;
- else if (player->HasAura(LFG_SPELL_DUNGEON_DESERTER))
- joinData.result = LFG_JOIN_DESERTER;
- else if (dungeons.empty())
- joinData.result = LFG_JOIN_NOT_MEET_REQS;
- else if (grp)
- {
- if (grp->GetMembersCount() > MAXGROUPSIZE)
- joinData.result = LFG_JOIN_TOO_MUCH_MEMBERS;
- else
- {
- uint8 memberCount = 0;
- for (GroupReference* itr = grp->GetFirstMember(); itr != NULL && joinData.result == LFG_JOIN_OK; itr = itr->next())
- {
- if (Player* plrg = itr->GetSource())
- {
- if (plrg->HasAura(LFG_SPELL_DUNGEON_DESERTER))
- joinData.result = LFG_JOIN_PARTY_DESERTER;
- else if (plrg->InBattleground() || plrg->InArena() || plrg->InBattlegroundQueue())
- joinData.result = LFG_JOIN_USING_BG_SYSTEM;
- ++memberCount;
- players.insert(plrg->GetGUID());
- }
- }
-
- if (joinData.result == LFG_JOIN_OK && memberCount != grp->GetMembersCount())
- joinData.result = LFG_JOIN_DISCONNECTED;
- }
- }
- else
- players.insert(player->GetGUID());
-
- // Xinef: Check dungeon cooldown only for random dungeons
- // Xinef: Moreover check this only if dungeon is not started, afterwards its obvious that players will have the cooldown
- if (joinData.result == LFG_JOIN_OK && !isContinue && rDungeonId)
- {
- if (player->HasAura(LFG_SPELL_DUNGEON_COOLDOWN)) // xinef: added !isContinue
- joinData.result = LFG_JOIN_RANDOM_COOLDOWN;
- else if (grp)
- {
- for (GroupReference* itr = grp->GetFirstMember(); itr != NULL && joinData.result == LFG_JOIN_OK; itr = itr->next())
- if (Player* plrg = itr->GetSource())
- if (plrg->HasAura(LFG_SPELL_DUNGEON_COOLDOWN)) // xinef: added !isContinue
- joinData.result = LFG_JOIN_PARTY_RANDOM_COOLDOWN;
- }
- }
- }
-
- if (isRaid)
- players.insert(player->GetGUID());
-
- if (joinData.result == LFG_JOIN_OK)
- {
- // Expand random dungeons and check restrictions
- if (rDungeonId)
- dungeons = GetDungeonsByRandom(rDungeonId);
-
- // if we have lockmap then there are no compatible dungeons
- // xinef: dont check compatibile dungeons for already running group (bind problems)
- if (!isContinue)
- {
- GetCompatibleDungeons(dungeons, players, joinData.lockmap);
- if (dungeons.empty())
- joinData.result = grp ? LFG_JOIN_PARTY_NOT_MEET_REQS : LFG_JOIN_NOT_MEET_REQS;
- }
- }
-
- // pussywizard:
- if (isRaid && grp && (grp->isLFGGroup() || guid != grp->GetLeaderGUID()))
- return;
-
- // Can't join. Send result
- if (joinData.result != LFG_JOIN_OK)
- {
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::Join: [" UI64FMTD "] joining with %u members. result: %u", guid, grp ? grp->GetMembersCount() : 1, joinData.result);
- if (!dungeons.empty()) // Only should show lockmap when have no dungeons available
- joinData.lockmap.clear();
- player->GetSession()->SendLfgJoinResult(joinData);
- return;
- }
-
- SetComment(guid, comment);
-
- if (isRaid)
- {
- if (grp)
- roles = PLAYER_ROLE_LEADER;
- else
- roles &= (PLAYER_ROLE_TANK | PLAYER_ROLE_HEALER | PLAYER_ROLE_DAMAGE);
- if (!roles)
- return;
- JoinRaidBrowser(player, roles, dungeons, comment);
- SetState(guid, LFG_STATE_RAIDBROWSER);
- SendRaidBrowserJoinedPacket(player, dungeons, comment);
- return;
- }
-
- std::string debugNames = "";
- if (grp) // Begin rolecheck
- {
- // Create new rolecheck
- LfgRoleCheck& roleCheck = RoleChecksStore[gguid];
- roleCheck.roles.clear(); // pussywizard: NEW rolecheck, not old one with trash data >_>
- roleCheck.cancelTime = time_t(time(NULL)) + LFG_TIME_ROLECHECK;
- roleCheck.state = LFG_ROLECHECK_INITIALITING;
- roleCheck.leader = guid;
- roleCheck.dungeons = dungeons;
- roleCheck.rDungeonId = rDungeonId;
-
- if (rDungeonId)
- {
- dungeons.clear();
- dungeons.insert(rDungeonId);
- }
-
- SetState(gguid, LFG_STATE_ROLECHECK);
- // Send update to player
- LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_JOIN_QUEUE, dungeons, comment);
- for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
- {
- if (Player* plrg = itr->GetSource())
- {
- uint64 pguid = plrg->GetGUID();
- plrg->GetSession()->SendLfgUpdateParty(updateData);
- SetState(pguid, LFG_STATE_ROLECHECK);
- if (!isContinue)
- SetSelectedDungeons(pguid, dungeons);
- roleCheck.roles[pguid] = 0;
- if (!debugNames.empty())
- debugNames.append(", ");
- debugNames.append(plrg->GetName());
- }
- }
- // Update leader role
- UpdateRoleCheck(gguid, guid, roles);
- }
- else // Add player to queue
- {
- LfgRolesMap rolesMap;
- rolesMap[guid] = roles;
- LFGQueue& queue = GetQueue(guid);
- queue.AddQueueData(guid, time(NULL), dungeons, rolesMap);
-
- if (!isContinue)
- {
- if (rDungeonId)
- {
- dungeons.clear();
- dungeons.insert(rDungeonId);
- }
- SetSelectedDungeons(guid, dungeons);
- }
- // Send update to player
- player->GetSession()->SendLfgJoinResult(joinData);
- player->GetSession()->SendLfgUpdatePlayer(LfgUpdateData(LFG_UPDATETYPE_JOIN_QUEUE, dungeons, comment));
- SetState(guid, LFG_STATE_QUEUED);
- SetRoles(guid, roles);
- debugNames.append(player->GetName());
- }
-
- /*if (sLog->ShouldLog(LOG_FILTER_LFG, LOG_LEVEL_DEBUG))
- {
- std::ostringstream o;
- o << "LFGMgr::Join: [" << guid << "] joined (" << (grp ? "group" : "player") << ") Members: " << debugNames.c_str()
- << ". Dungeons (" << uint32(dungeons.size()) << "): " << ConcatenateDungeons(dungeons);
- ;//sLog->outDebug((LOG_FILTER_LFG, "%s", o.str().c_str());
- }*/
-}
-
-/**
- Leaves Dungeon System. Player/Group is removed from queue, rolechecks, proposals
- or votekicks. Player or group needs to be not NULL and using Dungeon System
-
- @param[in] guid Player or group guid
-*/
-void LFGMgr::LeaveLfg(uint64 guid)
-{
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::Leave: [" UI64FMTD "]", guid);
-
- uint64 gguid = IS_GROUP_GUID(guid) ? guid : GetGroup(guid);
- LfgState state = GetState(guid);
- switch (state)
- {
- case LFG_STATE_QUEUED:
- if (gguid)
- {
- LFGQueue& queue = GetQueue(gguid);
- queue.RemoveFromQueue(gguid);
- SetState(gguid, LFG_STATE_NONE);
- const LfgGuidSet& players = GetPlayers(gguid);
- for (LfgGuidSet::const_iterator it = players.begin(); it != players.end(); ++it)
- {
- SetState(*it, LFG_STATE_NONE);
- SendLfgUpdateParty(*it, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE));
- }
- }
- else
- {
- LFGQueue& queue = GetQueue(guid);
- queue.RemoveFromQueue(guid);
- SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE));
- SetState(guid, LFG_STATE_NONE);
- }
- break;
- case LFG_STATE_ROLECHECK:
- if (gguid)
- UpdateRoleCheck(gguid); // No player to update role = LFG_ROLECHECK_ABORTED
- break;
- case LFG_STATE_PROPOSAL:
- {
- // Remove from Proposals
- LfgProposalContainer::iterator it = ProposalsStore.begin();
- uint64 pguid = gguid == guid ? GetLeader(gguid) : guid;
- while (it != ProposalsStore.end())
- {
- LfgProposalPlayerContainer::iterator itPlayer = it->second.players.find(pguid);
- if (itPlayer != it->second.players.end())
- {
- // Mark the player/leader of group who left as didn't accept the proposal
- itPlayer->second.accept = LFG_ANSWER_DENY;
- break;
- }
- ++it;
- }
-
- // Remove from queue - if proposal is found, RemoveProposal will call RemoveFromQueue
- if (it != ProposalsStore.end())
- RemoveProposal(it, LFG_UPDATETYPE_PROPOSAL_DECLINED);
- break;
- }
- case LFG_STATE_NONE:
- break;
- case LFG_STATE_DUNGEON:
- case LFG_STATE_FINISHED_DUNGEON:
- case LFG_STATE_BOOT:
- if (guid != gguid) // Player
- SetState(guid, LFG_STATE_NONE);
- break;
- case LFG_STATE_RAIDBROWSER:
- LeaveRaidBrowser(guid);
- SetCanOverrideRBState(guid, true);
- SetState(guid, LFG_STATE_NONE);
- SetCanOverrideRBState(guid, false);
- SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_LEAVE_RAIDBROWSER));
- SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_LEAVE_RAIDBROWSER));
- break;
- }
-}
-
-void LFGMgr::JoinRaidBrowser(Player* player, uint8 roles, LfgDungeonSet& dungeons, std::string comment)
-{
- // pussywizard: client limit for comment length is 64 @ 3.3.5a
- if (comment.size() > 64)
- comment = comment.substr(0, 64);
-
- RBEntryInfo entry(roles, comment);
- for (LfgDungeonSet::const_iterator itr = dungeons.begin(); itr != dungeons.end(); ++itr)
- if (GetLFGDungeon(*itr)) // ensure dungeon data exists for such dungeon id
- {
- RaidBrowserStore[player->GetTeamId()][*itr][player->GetGUIDLow()] = entry;
- RBUsedDungeonsStore[player->GetTeamId()].insert(*itr);
- }
-}
-
-void LFGMgr::LeaveRaidBrowser(uint64 guid)
-{
- uint32 guidLow = GUID_LOPART(guid);
- for (uint8 team=0; team<2; ++team)
- for (RBStoreMap::iterator itr = RaidBrowserStore[team].begin(); itr != RaidBrowserStore[team].end(); ++itr)
- itr->second.erase(guidLow);
-}
-
-void LFGMgr::SendRaidBrowserJoinedPacket(Player* p, LfgDungeonSet& dungeons, std::string comment)
-{
- if (dungeons.empty())
- {
- RBEntryInfoMap::iterator iter;
- uint8 team = p->GetTeamId();
- bool setComment = true;
- for (RBStoreMap::iterator itr = RaidBrowserStore[team].begin(); itr != RaidBrowserStore[team].end(); ++itr)
- if ((iter = itr->second.find(p->GetGUIDLow())) != itr->second.end())
- {
- dungeons.insert(itr->first);
- if (setComment)
- {
- comment = iter->second.comment;
- setComment = false;
- }
- }
- }
- LfgJoinResultData joinData;
- p->GetSession()->SendLfgJoinResult(joinData);
- LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_JOIN_RAIDBROWSER, dungeons, comment);
- if (p->GetGroup())
- p->GetSession()->SendLfgUpdateParty(updateData);
- else
- p->GetSession()->SendLfgUpdatePlayer(updateData);
-}
-
-void LFGMgr::LfrSearchAdd(Player* p, uint32 dungeonId)
-{
- RBSearchersStore[p->GetTeamId()][p->GetGUIDLow()] = dungeonId;
-}
-
-void LFGMgr::LfrSearchRemove(Player* p)
-{
- RBSearchersStore[p->GetTeamId()].erase(p->GetGUIDLow());
-}
-
-void LFGMgr::SendRaidBrowserCachedList(Player* player, uint32 dungeonId)
-{
- RBCacheMap::iterator itr = RBCacheStore[player->GetTeamId()].find(dungeonId);
- if (itr != RBCacheStore[player->GetTeamId()].end())
- {
- player->GetSession()->SendPacket(&(itr->second));
- return;
- }
- // send empty packet if cache not found
- WorldPacket data(SMSG_UPDATE_LFG_LIST, 1000);
- data << (uint32)LFG_TYPE_RAID;
- data << (uint32)dungeonId;
- data << (uint8)0;
- data << (uint32)0;
- data << (uint32)0;
- data << (uint32)0;
- data << (uint32)0;
- player->GetSession()->SendPacket(&data);
-}
-
-void LFGMgr::UpdateRaidBrowser(uint32 diff)
-{
- for (uint8 team=0; team<2; ++team)
- {
- if (m_raidBrowserUpdateTimer[team] > diff)
- m_raidBrowserUpdateTimer[team] -= diff;
- else
- m_raidBrowserUpdateTimer[team] = 0;
- }
-
- if (getMSTimeDiff(World::GetGameTimeMS(), getMSTime()) > (70*7)/5) // prevent lagging
- return;
-
- uint64 guid, groupGuid, instanceGuid;
- uint8 level, Class, race, talents[3];
- float iLevel, mp5, mp5combat, baseAP, rangedAP;
- int32 spellDamage, spellHeal;
- uint32 dungeonId, encounterMask, maxPower;
- uint32 deletedCounter, groupCounter, playerCounter;
- ByteBuffer buffer_deleted, buffer_groups, buffer_players;
- std::string emptyComment;
- std::set<uint64> deletedGroups, deletedGroupsToErase;
- RBInternalInfoMap copy;
-
- for (uint8 team=0; team<2; ++team)
- {
- if (m_raidBrowserLastUpdatedDungeonId[team] == 0) // new loop
- {
- if (m_raidBrowserUpdateTimer[team] > 0) // allowed only with some time interval
- continue;
- else // reset timer
- m_raidBrowserUpdateTimer[team] = 5000;
- }
-
- RBUsedDungeonsSet::const_iterator neitr, titr;
- for (neitr = RBUsedDungeonsStore[team].begin(); neitr != RBUsedDungeonsStore[team].end(); )
- {
- titr = neitr++;
- dungeonId = (*titr);
-
- // go to next dungeon than previously (one dungeon updated in one LFGMgr::UpdateRaidBrowser)
- if (dungeonId <= m_raidBrowserLastUpdatedDungeonId[team])
- continue;
- m_raidBrowserLastUpdatedDungeonId[team] = dungeonId;
-
- RBEntryInfoMap& entryInfoMap = RaidBrowserStore[team][dungeonId];
- LFGDungeonData const* dungeonData = GetLFGDungeon(dungeonId); // checked if exists before inserting to the container
- RBInternalInfoMap& currInternalInfoMap = RBInternalInfoStoreCurr[team][dungeonId];
- for (RBEntryInfoMap::const_iterator sitr = entryInfoMap.begin(); sitr != entryInfoMap.end(); ++sitr)
- {
- guid = MAKE_NEW_GUID(sitr->first, 0, HIGHGUID_PLAYER);
- groupGuid = 0;
- Player* p = ObjectAccessor::FindPlayerInOrOutOfWorld(guid);
- ASSERT(p);
- if (sitr->second.roles == PLAYER_ROLE_LEADER)
- {
- ASSERT(p->GetGroup());
- groupGuid = p->GetGroup()->GetGUID();
- }
- encounterMask = 0;
- instanceGuid = 0;
- if (InstancePlayerBind* bind = sInstanceSaveMgr->PlayerGetBoundInstance(sitr->first, dungeonData->map, dungeonData->difficulty))
- if (bind->perm)
- {
- instanceGuid = MAKE_NEW_GUID(bind->save->GetInstanceId(), 0, HIGHGUID_INSTANCE);
- encounterMask = bind->save->GetCompletedEncounterMask();
- }
-
- talents[0] = 0;
- talents[1] = 0;
- talents[2] = 0;
- p->GetTalentTreePoints(talents);
- spellDamage = p->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_ALL);
- spellHeal = p->SpellBaseHealingBonusDone(SPELL_SCHOOL_MASK_ALL);
- mp5 = p->GetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER);
- mp5combat = p->GetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER);
- baseAP = p->GetTotalAttackPowerValue(BASE_ATTACK);
- rangedAP = p->GetTotalAttackPowerValue(RANGED_ATTACK);
- maxPower = 0;
- if (p->getClass() == CLASS_DRUID)
- maxPower = p->GetMaxPower(POWER_MANA);
- else
- maxPower = (p->getPowerType() == POWER_RAGE || p->getPowerType() == POWER_RUNIC_POWER) ? p->GetMaxPower(p->getPowerType())/10 : p->GetMaxPower(p->getPowerType());
-
- currInternalInfoMap[sitr->first] = RBInternalInfo(guid, sitr->second.comment, groupGuid != 0, groupGuid, sitr->second.roles, encounterMask, instanceGuid,
- 1, p->getLevel(), p->getClass(), p->getRace(), p->GetAverageItemLevel(),
- talents, p->m_last_area_id, p->GetArmor(), (uint32)std::max<int32>(0, spellDamage), (uint32)std::max<int32>(0, spellHeal),
- p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_CRIT_MELEE), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_CRIT_RANGED), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_CRIT_SPELL), std::max<float>(0.0f, mp5), std::max<float>(0.0f, mp5combat),
- std::max<uint32>(baseAP, rangedAP), (uint32)p->GetStat(STAT_AGILITY), p->GetMaxHealth(), maxPower, p->GetDefenseSkillValue(),
- p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_DODGE), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_BLOCK), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_PARRY), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_HASTE_SPELL), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_EXPERTISE));
-
- if (!groupGuid)
- continue;
- for (Group::member_citerator mitr = p->GetGroup()->GetMemberSlots().begin(); mitr != p->GetGroup()->GetMemberSlots().end(); ++mitr)
- {
- if (mitr->guid == sitr->first) // leader already added
- continue;
- guid = MAKE_NEW_GUID(mitr->guid, 0, HIGHGUID_PLAYER);
- level = 1;
- Class = 0;
- race = 0;
- iLevel = 0.0f;
- talents[0] = 0;
- talents[1] = 0;
- talents[2] = 0;
- if (const GlobalPlayerData* gpd = sWorld->GetGlobalPlayerData(mitr->guid))
- {
- level = gpd->level;
- Class = gpd->playerClass;
- race = gpd->race;
- }
- Player* mplr = ObjectAccessor::FindPlayerInOrOutOfWorld(guid);
- if (mplr)
- {
- iLevel = mplr->GetAverageItemLevel();
- mplr->GetTalentTreePoints(talents);
- }
- currInternalInfoMap[mitr->guid] = RBInternalInfo(guid, emptyComment, false, groupGuid, 0, 0, 0,
- (mplr ? 1 : 0), level, Class, race, iLevel,
- talents, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0);
- }
- }
-
- copy.clear();
- copy = currInternalInfoMap; // will be saved as prev at the end
-
- // compare prev with curr to build difference packet
- deletedCounter = 0; groupCounter = 0; playerCounter = 0;
- buffer_deleted.clear(); buffer_groups.clear(); buffer_players.clear();
- deletedGroups.clear(); deletedGroupsToErase.clear();
-
- RBInternalInfoMap& prevInternalInfoMap = RBInternalInfoStorePrev[team][dungeonId];
- RBInternalInfoMap::iterator iter, iterTmp;
- for (RBInternalInfoMap::const_iterator sitr = prevInternalInfoMap.begin(); sitr != prevInternalInfoMap.end(); ++sitr)
- {
- iter = currInternalInfoMap.find(sitr->first);
- if (iter == currInternalInfoMap.end()) // was -> isn't
- {
- if (sitr->second.isGroupLeader)
- deletedGroups.insert(sitr->second.groupGuid);
- ++deletedCounter;
- buffer_deleted << (uint64)sitr->second.guid;
- }
- else // was -> is
- {
- if (sitr->second.isGroupLeader) // was a leader
- {
- if (!iter->second.isGroupLeader) // leader -> no longer a leader
- deletedGroups.insert(sitr->second.groupGuid);
- else if (sitr->second.groupGuid != iter->second.groupGuid) // leader -> leader of another group
- {
- deletedGroups.insert(sitr->second.groupGuid);
- deletedGroupsToErase.insert(iter->second.groupGuid);
- ++groupCounter;
- RBPacketAppendGroup(iter->second, buffer_groups);
- }
- else if (sitr->second.comment != iter->second.comment || sitr->second.encounterMask != iter->second.encounterMask || sitr->second.instanceGuid != iter->second.instanceGuid) // leader -> nothing changed
- {
- ++groupCounter;
- RBPacketAppendGroup(iter->second, buffer_groups);
- }
- }
- else if (iter->second.isGroupLeader) // wasn't a leader -> is a leader
- {
- deletedGroupsToErase.insert(iter->second.groupGuid);
- ++groupCounter;
- RBPacketAppendGroup(iter->second, buffer_groups);
- }
-
- if (!iter->second._online) // if offline, copy previous stats (itemLevel, talents, area, etc.)
- {
- iterTmp = copy.find(sitr->first); // copied container is for building a full packet, so modify it there (currInternalInfoMap is erased)
- iterTmp->second.CopyStats(sitr->second);
- if (!sitr->second.PlayerSameAs(iterTmp->second)) // player info changed
- {
- ++playerCounter;
- RBPacketAppendPlayer(iterTmp->second, buffer_players);
- }
- }
- else if (!sitr->second.PlayerSameAs(iter->second)) // player info changed
- {
- ++playerCounter;
- RBPacketAppendPlayer(iter->second, buffer_players);
- }
- currInternalInfoMap.erase(iter);
- }
- }
- // left entries (new)
- for (RBInternalInfoMap::const_iterator sitr = currInternalInfoMap.begin(); sitr != currInternalInfoMap.end(); ++sitr)
- {
- if (sitr->second.isGroupLeader)
- {
- deletedGroupsToErase.insert(sitr->second.groupGuid);
- ++groupCounter;
- RBPacketAppendGroup(sitr->second, buffer_groups);
- }
- ++playerCounter;
- RBPacketAppendPlayer(sitr->second, buffer_players);
- }
-
- if (!deletedGroupsToErase.empty())
- for (std::set<uint64>::const_iterator sitr = deletedGroupsToErase.begin(); sitr != deletedGroupsToErase.end(); ++sitr)
- deletedGroups.erase(*sitr);
-
- if (!deletedGroups.empty())
- for (std::set<uint64>::const_iterator sitr = deletedGroups.begin(); sitr != deletedGroups.end(); ++sitr)
- {
- ++deletedCounter;
- buffer_deleted << (*sitr);
- }
-
- WorldPacket differencePacket(SMSG_UPDATE_LFG_LIST, 1000);
- RBPacketBuildDifference(differencePacket, dungeonId, deletedCounter, buffer_deleted, groupCounter, buffer_groups, playerCounter, buffer_players);
- WorldPacket fullPacket(SMSG_UPDATE_LFG_LIST, 1000);
- RBPacketBuildFull(fullPacket, dungeonId, copy);
-
- RBCacheStore[team][dungeonId] = fullPacket;
- prevInternalInfoMap = copy;
- currInternalInfoMap.clear();
-
- if (entryInfoMap.empty())
- RBUsedDungeonsStore[team].erase(titr);
-
- // send difference packet to browsing players
- for (RBSearchersMap::const_iterator sitr = RBSearchersStore[team].begin(); sitr != RBSearchersStore[team].end(); ++sitr)
- if (sitr->second == dungeonId)
- if (Player* p = ObjectAccessor::FindPlayerInOrOutOfWorld(MAKE_NEW_GUID(sitr->first, 0, HIGHGUID_PLAYER)))
- p->GetSession()->SendPacket(&differencePacket);
-
- break; // one dungeon updated in one LFGMgr::UpdateRaidBrowser
- }
-
- // already updated all in this time interval
- if (neitr == RBUsedDungeonsStore[team].end())
- m_raidBrowserLastUpdatedDungeonId[team] = 0;
- }
-}
-
-void LFGMgr::RBPacketAppendGroup(const RBInternalInfo& info, ByteBuffer& buffer)
-{
- buffer << (uint64)info.groupGuid;
- uint32 flags = LFG_UPDATE_FLAG_COMMENT | LFG_UPDATE_FLAG_ROLES | LFG_UPDATE_FLAG_BINDED;
- buffer << (uint32)flags;
- if (flags & LFG_UPDATE_FLAG_COMMENT)
- buffer << info.comment;
- if (flags & LFG_UPDATE_FLAG_ROLES)
- for (uint8 j=0; j<3; ++j)
- buffer << (uint8)0;
- if (!(flags & LFG_UPDATE_FLAG_BINDED))
- return;
- buffer << (uint64)info.instanceGuid;
- buffer << (uint32)info.encounterMask;
-}
-
-void LFGMgr::RBPacketAppendPlayer(const RBInternalInfo& info, ByteBuffer& buffer)
-{
- buffer << (uint64)info.guid;
- uint32 flags = LFG_UPDATE_FLAG_CHARACTERINFO | LFG_UPDATE_FLAG_ROLES | LFG_UPDATE_FLAG_COMMENT | (info.groupGuid ? LFG_UPDATE_FLAG_GROUPGUID : LFG_UPDATE_FLAG_BINDED) | (info.isGroupLeader ? LFG_UPDATE_FLAG_GROUPLEADER : 0) | (!info.groupGuid || info.isGroupLeader ? LFG_UPDATE_FLAG_AREA : 0);
- buffer << (uint32)flags;
-
- if (flags & LFG_UPDATE_FLAG_CHARACTERINFO)
- {
- buffer << (uint8)info._level;
- buffer << (uint8)info._class;
- buffer << (uint8)info._race;
- buffer << (uint8)info._talents0;
- buffer << (uint8)info._talents1;
- buffer << (uint8)info._talents2;
- buffer << (uint32)info._armor;
- buffer << (uint32)info._spellDamage;
- buffer << (uint32)info._spellHeal;
- buffer << (uint32)info._critRatingMelee;
- buffer << (uint32)info._critRatingRanged;
- buffer << (uint32)info._critRatingSpell;
- buffer << (float)info._mp5;
- buffer << (float)info._mp5combat;
- buffer << (uint32)info._attackPower;
- buffer << (uint32)info._agility;
- buffer << (uint32)info._health;
- buffer << (uint32)info._mana;
- buffer << (uint32)info._online; // talentpoints, used as online/offline marker :D
- buffer << (float)info._avgItemLevel; // avgitemlevel
- buffer << (uint32)info._defenseSkill;
- buffer << (uint32)info._dodgeRating;
- buffer << (uint32)info._blockRating;
- buffer << (uint32)info._parryRating;
- buffer << (uint32)info._hasteRating;
- buffer << (uint32)info._expertiseRating;
- }
-
- if (flags & LFG_UPDATE_FLAG_COMMENT)
- buffer << (info.groupGuid ? std::string("") : info.comment);
- if (flags & LFG_UPDATE_FLAG_GROUPLEADER)
- buffer << (uint8)1; // isLFM
- if (flags & LFG_UPDATE_FLAG_GROUPGUID)
- buffer << (uint64)info.groupGuid;
- if (flags & LFG_UPDATE_FLAG_ROLES)
- buffer << (uint8)(info.groupGuid ? (info.isGroupLeader ? PLAYER_ROLE_LEADER : 0) : info.roles);
- if (flags & LFG_UPDATE_FLAG_AREA)
- buffer << (uint32)info._area;
- if (flags & LFG_UPDATE_FLAG_STATUS)
- buffer << (uint8)0;
- if (!(flags & LFG_UPDATE_FLAG_BINDED))
- return;
- buffer << (uint64)info.instanceGuid;
- buffer << (uint32)info.encounterMask;
-}
-
-void LFGMgr::RBPacketBuildDifference(WorldPacket& differencePacket, uint32 dungeonId, uint32 deletedCounter, ByteBuffer& buffer_deleted, uint32 groupCounter, ByteBuffer& buffer_groups, uint32 playerCounter, ByteBuffer& buffer_players)
-{
- differencePacket << (uint32)LFG_TYPE_RAID;
- differencePacket << (uint32)dungeonId;
- differencePacket << (uint8)1;
- differencePacket << (uint32)deletedCounter;
- differencePacket.append(buffer_deleted);
- differencePacket << (uint32)groupCounter;
- differencePacket << (uint32)0;
- differencePacket.append(buffer_groups);
- differencePacket << (uint32)playerCounter;
- differencePacket << (uint32)0;
- differencePacket.append(buffer_players);
-}
-
-void LFGMgr::RBPacketBuildFull(WorldPacket& fullPacket, uint32 dungeonId, RBInternalInfoMap& infoMap)
-{
- fullPacket << (uint32)LFG_TYPE_RAID;
- fullPacket << (uint32)dungeonId;
- fullPacket << (uint8)0;
- uint32 groupCounter = 0, playerCounter = 0;
- ByteBuffer buffer_groups, buffer_players;
- for (RBInternalInfoMap::const_iterator itr = infoMap.begin(); itr != infoMap.end(); ++itr)
- {
- if (itr->second.isGroupLeader)
- {
- ++groupCounter;
- RBPacketAppendGroup(itr->second, buffer_groups);
- }
- ++playerCounter;
- RBPacketAppendPlayer(itr->second, buffer_players);
- }
- fullPacket << (uint32)groupCounter;
- fullPacket << (uint32)0;
- fullPacket.append(buffer_groups);
- fullPacket << (uint32)playerCounter;
- fullPacket << (uint32)0;
- fullPacket.append(buffer_players);
-}
-
-// pussywizard:
-void LFGMgr::LeaveAllLfgQueues(uint64 guid, bool allowgroup, uint64 groupguid)
-{
- uint64 pguid = 0, gguid = 0;
- if (IS_GROUP_GUID(guid))
- gguid = guid;
- else if (groupguid && IS_GROUP_GUID(groupguid))
- {
- pguid = guid;
- gguid = groupguid;
- }
- else
- {
- pguid = guid;
- gguid = GetGroup(guid);
- }
- if (!allowgroup)
- gguid = 0;
-
- if (pguid)
- for (lfg::LfgQueueContainer::iterator itr = QueuesStore.begin(); itr != QueuesStore.end(); ++itr)
- itr->second.RemoveFromQueue(pguid);
- if (gguid)
- for (lfg::LfgQueueContainer::iterator itr = QueuesStore.begin(); itr != QueuesStore.end(); ++itr)
- itr->second.RemoveFromQueue(gguid);
-
- if (pguid && !gguid)
- {
- if (GetState(pguid) == LFG_STATE_QUEUED)
- {
- SendLfgUpdatePlayer(pguid, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE));
- SetState(pguid, LFG_STATE_NONE);
- }
- }
- if (gguid)
- {
- if (GetState(gguid) == LFG_STATE_QUEUED)
- {
- SetState(gguid, LFG_STATE_NONE);
- const LfgGuidSet& players = GetPlayers(gguid);
- for (LfgGuidSet::const_iterator it = players.begin(); it != players.end(); ++it)
- {
- SetState(*it, LFG_STATE_NONE);
- SendLfgUpdateParty(*it, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE));
- }
- }
- }
-}
-
-/**
- Update the Role check info with the player selected role.
-
- @param[in] grp Group guid to update rolecheck
- @param[in] guid Player guid (0 = rolecheck failed)
- @param[in] roles Player selected roles
-*/
-void LFGMgr::UpdateRoleCheck(uint64 gguid, uint64 guid /* = 0 */, uint8 roles /* = PLAYER_ROLE_NONE */)
-{
- if (!gguid)
- return;
-
- LfgRolesMap check_roles;
- LfgRoleCheckContainer::iterator itRoleCheck = RoleChecksStore.find(gguid);
- if (itRoleCheck == RoleChecksStore.end())
- return;
-
- LfgRoleCheck& roleCheck = itRoleCheck->second;
- bool sendRoleChosen = roleCheck.state != LFG_ROLECHECK_DEFAULT && guid;
-
- if (!guid)
- roleCheck.state = LFG_ROLECHECK_ABORTED;
- else if (roles < PLAYER_ROLE_TANK) // Player selected no role.
- roleCheck.state = LFG_ROLECHECK_NO_ROLE;
- else
- {
- roleCheck.roles[guid] = roles;
-
- // Check if all players have selected a role
- LfgRolesMap::const_iterator itRoles = roleCheck.roles.begin();
- while (itRoles != roleCheck.roles.end() && itRoles->second != PLAYER_ROLE_NONE)
- ++itRoles;
-
- if (itRoles == roleCheck.roles.end())
- {
- // use temporal var to check roles, CheckGroupRoles modifies the roles
- check_roles = roleCheck.roles;
- roleCheck.state = CheckGroupRoles(check_roles) ? LFG_ROLECHECK_FINISHED : LFG_ROLECHECK_WRONG_ROLES;
- }
- }
-
- LfgDungeonSet dungeons;
- if (roleCheck.rDungeonId)
- dungeons.insert(roleCheck.rDungeonId);
- else
- dungeons = roleCheck.dungeons;
-
- LfgJoinResultData joinData = LfgJoinResultData(LFG_JOIN_FAILED, roleCheck.state);
- for (LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it)
- {
- uint64 pguid = it->first;
-
- if (sendRoleChosen)
- SendLfgRoleChosen(pguid, guid, roles);
-
- SendLfgRoleCheckUpdate(pguid, roleCheck);
- switch (roleCheck.state)
- {
- case LFG_ROLECHECK_INITIALITING:
- continue;
- case LFG_ROLECHECK_FINISHED:
- SetState(pguid, LFG_STATE_QUEUED);
- SetRoles(pguid, it->second);
- SendLfgUpdateParty(pguid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, dungeons, GetComment(pguid)));
- break;
- default:
- if (roleCheck.leader == pguid)
- SendLfgJoinResult(pguid, joinData);
- SendLfgUpdateParty(pguid, LfgUpdateData(LFG_UPDATETYPE_ROLECHECK_FAILED));
- RestoreState(pguid, "Rolecheck Failed");
- break;
- }
- }
-
- if (roleCheck.state == LFG_ROLECHECK_FINISHED)
- {
- SetState(gguid, LFG_STATE_QUEUED);
- LFGQueue& queue = GetQueue(gguid);
- queue.AddQueueData(gguid, time_t(time(NULL)), roleCheck.dungeons, roleCheck.roles);
- RoleChecksStore.erase(itRoleCheck);
- }
- else if (roleCheck.state != LFG_ROLECHECK_INITIALITING)
- {
- RestoreState(gguid, "Rolecheck Failed");
- RoleChecksStore.erase(itRoleCheck);
- }
-}
-
-/**
- Given a list of dungeons remove the dungeons players have restrictions.
-
- @param[in, out] dungeons Dungeons to check restrictions
- @param[in] players Set of players to check their dungeon restrictions
- @param[out] lockMap Map of players Lock status info of given dungeons (Empty if dungeons is not empty)
-*/
-void LFGMgr::GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap)
-{
- lockMap.clear();
- for (LfgGuidSet::const_iterator it = players.begin(); it != players.end() && !dungeons.empty(); ++it)
- {
- uint64 guid = (*it);
- LfgLockMap const& cachedLockMap = GetLockedDungeons(guid);
- for (LfgLockMap::const_iterator it2 = cachedLockMap.begin(); it2 != cachedLockMap.end() && !dungeons.empty(); ++it2)
- {
- uint32 dungeonId = (it2->first & 0x00FFFFFF); // Compare dungeon ids
- LfgDungeonSet::iterator itDungeon = dungeons.find(dungeonId);
- if (itDungeon != dungeons.end())
- {
- dungeons.erase(itDungeon);
- lockMap[guid][dungeonId] = it2->second;
- }
- }
- }
- if (!dungeons.empty())
- lockMap.clear();
-}
-
-uint8 LFGMgr::CheckGroupRoles(LfgRolesMap& groles, bool removeLeaderFlag /*= true*/)
-{
- if (groles.empty())
- return 0;
-
- uint8 damage = 0;
- uint8 tank = 0;
- uint8 healer = 0;
-
- if (removeLeaderFlag)
- for (LfgRolesMap::iterator it = groles.begin(); it != groles.end(); ++it)
- it->second &= ~PLAYER_ROLE_LEADER;
-
- for (LfgRolesMap::iterator it = groles.begin(); it != groles.end(); ++it)
- {
- if (it->second == PLAYER_ROLE_NONE)
- return 0;
-
- if (it->second & PLAYER_ROLE_DAMAGE)
- {
- if (it->second != PLAYER_ROLE_DAMAGE)
- {
- it->second -= PLAYER_ROLE_DAMAGE;
- if (uint8 x = CheckGroupRoles(groles, false))
- return x;
- it->second += PLAYER_ROLE_DAMAGE;
- }
- else if (damage == LFG_DPS_NEEDED)
- return 0;
- else
- damage++;
- }
-
- if (it->second & PLAYER_ROLE_HEALER)
- {
- if (it->second != PLAYER_ROLE_HEALER)
- {
- it->second -= PLAYER_ROLE_HEALER;
- if (uint8 x = CheckGroupRoles(groles, false))
- return x;
- it->second += PLAYER_ROLE_HEALER;
- }
- else if (healer == LFG_HEALERS_NEEDED)
- return 0;
- else
- healer++;
- }
-
- if (it->second & PLAYER_ROLE_TANK)
- {
- if (it->second != PLAYER_ROLE_TANK)
- {
- it->second -= PLAYER_ROLE_TANK;
- if (uint8 x = CheckGroupRoles(groles, false))
- return x;
- it->second += PLAYER_ROLE_TANK;
- }
- else if (tank == LFG_TANKS_NEEDED)
- return 0;
- else
- tank++;
- }
- }
- if ((tank + healer + damage) == uint8(groles.size()))
- return (8*tank + 4*healer + damage);
- return 0;
-}
-
-/**
- Makes a new group given a proposal
- @param[in] proposal Proposal to get info from
-*/
-void LFGMgr::MakeNewGroup(LfgProposal const& proposal)
-{
- LfgGuidList players;
- LfgGuidList playersToTeleport;
-
- for (LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
- {
- uint64 guid = it->first;
- if (guid == proposal.leader)
- players.push_front(guid);
- else
- players.push_back(guid);
-
- if (proposal.isNew || GetGroup(guid) != proposal.group)
- playersToTeleport.push_back(guid);
- }
-
- // Set the dungeon difficulty
- LFGDungeonData const* dungeon = GetLFGDungeon(proposal.dungeonId);
- ASSERT(dungeon);
-
- Group* grp = proposal.group ? sGroupMgr->GetGroupByGUID(GUID_LOPART(proposal.group)) : NULL;
- uint64 oldGroupGUID = 0;
- for (LfgGuidList::const_iterator it = players.begin(); it != players.end(); ++it)
- {
- uint64 pguid = (*it);
- Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(pguid);
- if (!player)
- continue;
-
- Group* group = player->GetGroup();
-
- // Xinef: Apply Random Buff
- if (grp && !grp->IsLfgWithBuff())
- {
- if (!group || group->GetGUID() != oldGroupGUID)
- grp->AddLfgBuffFlag();
- else
- oldGroupGUID = group->GetGUID();
- }
-
- // Xinef: Store amount of random players player grouped with
- if (group)
- {
- SetRandomPlayersCount(pguid, group->GetMembersCount() >= MAXGROUPSIZE ? 0 : MAXGROUPSIZE-group->GetMembersCount());
- oldGroupGUID = group->GetGUID();
- if (group != grp)
- group->RemoveMember(player->GetGUID());
- }
- else
- SetRandomPlayersCount(pguid, MAXGROUPSIZE-1);
-
- if (!grp)
- {
- grp = new Group();
- grp->ConvertToLFG();
- grp->Create(player);
- uint64 gguid = grp->GetGUID();
- SetState(gguid, LFG_STATE_PROPOSAL);
- sGroupMgr->AddGroup(grp);
- }
- else if (group != grp)
- {
- // pussywizard:
- if (!grp->IsFull())
- grp->AddMember(player);
- //else // some cleanup? LeaveLFG?
- // ;
- }
-
- grp->SetLfgRoles(pguid, proposal.players.find(pguid)->second.role);
- }
-
- // pussywizard: crashfix, group wasn't created when iterating players (no player found by guid), proposal is deleted by the calling function
- if (!grp)
- return;
-
- grp->SetDungeonDifficulty(Difficulty(dungeon->difficulty));
- uint64 gguid = grp->GetGUID();
- SetDungeon(gguid, dungeon->Entry());
- SetState(gguid, LFG_STATE_DUNGEON);
-
- _SaveToDB(gguid);
-
- bool randomDungeon = false;
- // Teleport Player
- for (LfgGuidList::const_iterator it = playersToTeleport.begin(); it != playersToTeleport.end(); ++it)
- if (Player* player = ObjectAccessor::FindPlayer(*it))
- {
- if (player->GetGroup() != grp) // pussywizard: could not add because group was full (some shitness happened)
- continue;
- // Add the cooldown spell if queued for a random dungeon
- // xinef: add aura
- if ((randomDungeon || selectedRandomLfgDungeon(player->GetGUID())) && !player->HasAura(LFG_SPELL_DUNGEON_COOLDOWN))
- {
- randomDungeon = true;
- player->AddAura(LFG_SPELL_DUNGEON_COOLDOWN, player);
- }
- TeleportPlayer(player, false);
- }
-
- if (randomDungeon)
- grp->AddLfgRandomInstanceFlag();
- if (Difficulty(dungeon->difficulty) == DUNGEON_DIFFICULTY_HEROIC)
- grp->AddLfgHeroicFlag();
-
- // Update group info
- grp->SendUpdate();
-}
-
-uint32 LFGMgr::AddProposal(LfgProposal& proposal)
-{
- proposal.id = ++m_lfgProposalId;
- ProposalsStore[m_lfgProposalId] = proposal;
- return m_lfgProposalId;
-}
-
-/**
- Update Proposal info with player answer
-
- @param[in] proposalId Proposal id to be updated
- @param[in] guid Player guid to update answer
- @param[in] accept Player answer
-*/
-void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept)
-{
- // Check if the proposal exists
- LfgProposalContainer::iterator itProposal = ProposalsStore.find(proposalId);
- if (itProposal == ProposalsStore.end())
- return;
-
- LfgProposal& proposal = itProposal->second;
-
- // Check if proposal have the current player
- LfgProposalPlayerContainer::iterator itProposalPlayer = proposal.players.find(guid);
- if (itProposalPlayer == proposal.players.end())
- return;
-
- LfgProposalPlayer& player = itProposalPlayer->second;
- player.accept = LfgAnswer(accept);
-
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::UpdateProposal: Player [" UI64FMTD "] of proposal %u selected: %u", guid, proposalId, accept);
- if (!accept)
- {
- RemoveProposal(itProposal, LFG_UPDATETYPE_PROPOSAL_DECLINED);
- return;
- }
-
- // check if all have answered and reorder players (leader first)
- bool allAnswered = true;
- for (LfgProposalPlayerContainer::const_iterator itPlayers = proposal.players.begin(); itPlayers != proposal.players.end(); ++itPlayers)
- if (itPlayers->second.accept != LFG_ANSWER_AGREE) // No answer (-1) or not accepted (0)
- allAnswered = false;
-
- if (!allAnswered)
- {
- for (LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
- SendLfgUpdateProposal(it->first, proposal);
-
- return;
- }
-
- bool sendUpdate = proposal.state != LFG_PROPOSAL_SUCCESS;
- proposal.state = LFG_PROPOSAL_SUCCESS;
- time_t joinTime = time(NULL);
-
- LFGQueue& queue = GetQueue(guid);
- LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_GROUP_FOUND);
- for (LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
- {
- uint64 pguid = it->first;
- uint64 gguid = it->second.group;
- uint32 dungeonId = (*GetSelectedDungeons(pguid).begin());
- int32 waitTime = -1;
- if (sendUpdate)
- SendLfgUpdateProposal(pguid, proposal);
-
- if (gguid)
- {
- waitTime = int32((joinTime - queue.GetJoinTime(gguid)) / IN_MILLISECONDS);
- SendLfgUpdateParty(pguid, updateData);
- }
- else
- {
- waitTime = int32((joinTime - queue.GetJoinTime(pguid)) / IN_MILLISECONDS);
- SendLfgUpdatePlayer(pguid, updateData);
- }
- updateData.updateType = LFG_UPDATETYPE_REMOVED_FROM_QUEUE;
- SendLfgUpdatePlayer(pguid, updateData);
- SendLfgUpdateParty(pguid, updateData);
-
- // Update timers
- uint8 role = GetRoles(pguid);
- role &= ~PLAYER_ROLE_LEADER;
- switch (role)
- {
- case PLAYER_ROLE_DAMAGE:
- queue.UpdateWaitTimeDps(waitTime, dungeonId);
- break;
- case PLAYER_ROLE_HEALER:
- queue.UpdateWaitTimeHealer(waitTime, dungeonId);
- break;
- case PLAYER_ROLE_TANK:
- queue.UpdateWaitTimeTank(waitTime, dungeonId);
- break;
- default:
- queue.UpdateWaitTimeAvg(waitTime, dungeonId);
- break;
- }
-
- SetState(pguid, LFG_STATE_DUNGEON);
- }
-
- // Remove players/groups from Queue
- for (uint8 i=0; i<5 && proposal.queues.guid[i]; ++i)
- queue.RemoveQueueData(proposal.queues.guid[i]);
-
- MakeNewGroup(proposal);
- ProposalsStore.erase(itProposal);
-}
-
-/**
- Remove a proposal from the pool, remove the group that didn't accept (if needed) and readd the other members to the queue
-
- @param[in] itProposal Iterator to the proposal to remove
- @param[in] type Type of removal (LFG_UPDATETYPE_PROPOSAL_FAILED, LFG_UPDATETYPE_PROPOSAL_DECLINED)
-*/
-void LFGMgr::RemoveProposal(LfgProposalContainer::iterator itProposal, LfgUpdateType type)
-{
- LfgProposal& proposal = itProposal->second;
- proposal.state = LFG_PROPOSAL_FAILED;
-
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::RemoveProposal: Proposal %u, state FAILED, UpdateType %u", itProposal->first, type);
- // Mark all people that didn't answered as no accept
- if (type == LFG_UPDATETYPE_PROPOSAL_FAILED)
- for (LfgProposalPlayerContainer::iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
- if (it->second.accept == LFG_ANSWER_PENDING)
- it->second.accept = LFG_ANSWER_DENY;
-
- // pussywizard: add cooldown for not accepting (after 40 secs) or declining
- for (LfgProposalPlayerContainer::iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
- if (it->second.accept == LFG_ANSWER_DENY)
- if (Player* plr = sObjectAccessor->FindPlayer(it->first))
- if (Aura* aura = plr->AddAura(LFG_SPELL_DUNGEON_COOLDOWN, plr)) aura->SetDuration(150*IN_MILLISECONDS);
-
- // Mark players/groups to be removed
- LfgGuidSet toRemove;
- for (LfgProposalPlayerContainer::iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
- {
- if (it->second.accept == LFG_ANSWER_AGREE)
- continue;
-
- uint64 guid = it->second.group ? it->second.group : it->first;
- // Player didn't accept or still pending when no secs left
- if (it->second.accept == LFG_ANSWER_DENY || type == LFG_UPDATETYPE_PROPOSAL_FAILED)
- {
- it->second.accept = LFG_ANSWER_DENY;
- toRemove.insert(guid);
- }
- }
-
- // Notify players
- for (LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
- {
- uint64 guid = it->first;
- uint64 gguid = it->second.group ? it->second.group : guid;
-
- SendLfgUpdateProposal(guid, proposal);
-
- if (toRemove.find(gguid) != toRemove.end()) // Didn't accept or in same group that someone that didn't accept
- {
- LfgUpdateData updateData;
- if (it->second.accept == LFG_ANSWER_DENY)
- {
- updateData.updateType = type;
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::RemoveProposal: [" UI64FMTD "] didn't accept. Removing from queue and compatible cache", guid);
- }
- else
- {
- updateData.updateType = LFG_UPDATETYPE_REMOVED_FROM_QUEUE;
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::RemoveProposal: [" UI64FMTD "] in same group that someone that didn't accept. Removing from queue and compatible cache", guid);
- }
-
- RestoreState(guid, "Proposal Fail (didn't accepted or in group with someone that didn't accept");
- if (gguid != guid)
- {
- RestoreState(it->second.group, "Proposal Fail (someone in group didn't accepted)");
- SendLfgUpdateParty(guid, updateData);
- }
- else
- SendLfgUpdatePlayer(guid, updateData);
- }
- else
- {
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::RemoveProposal: Readding [" UI64FMTD "] to queue.", guid);
- SetState(guid, LFG_STATE_QUEUED);
- if (gguid != guid)
- {
- SetState(gguid, LFG_STATE_QUEUED);
- SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid)));
- }
- else
- SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid)));
- }
- }
-
- LFGQueue& queue = GetQueue(proposal.players.begin()->first);
- // Remove players/groups from queue
- for (LfgGuidSet::const_iterator it = toRemove.begin(); it != toRemove.end(); ++it)
- {
- uint64 guid = *it;
- queue.RemoveFromQueue(guid);
- proposal.queues.remove(guid);
- }
-
- // Readd to queue
- for (uint8 i=0; i<5 && proposal.queues.guid[i]; ++i)
- {
- // xinef: this will work as data is not deleted, only references to this data are cleared
- // xinef: when new proposal is created
- // xinef: successful proposal is also taken into account is similar manner
- queue.AddToQueue(proposal.queues.guid[i], true);
- }
-
- ProposalsStore.erase(itProposal);
-}
-
-/**
- Initialize a boot kick vote
-
- @param[in] gguid Group the vote kicks belongs to
- @param[in] kicker Kicker guid
- @param[in] victim Victim guid
- @param[in] reason Kick reason
-*/
-void LFGMgr::InitBoot(uint64 gguid, uint64 kicker, uint64 victim, std::string const& reason)
-{
- SetState(gguid, LFG_STATE_BOOT);
-
- LfgPlayerBoot& boot = BootsStore[gguid];
- boot.inProgress = true;
- boot.cancelTime = time_t(time(NULL)) + LFG_TIME_BOOT;
- boot.reason = reason;
- boot.victim = victim;
-
- LfgGuidSet const& players = GetPlayers(gguid);
-
- // Set votes
- for (LfgGuidSet::const_iterator itr = players.begin(); itr != players.end(); ++itr)
- {
- uint64 guid = (*itr);
- SetState(guid, LFG_STATE_BOOT);
- boot.votes[guid] = LFG_ANSWER_PENDING;
- }
-
- boot.votes[victim] = LFG_ANSWER_DENY; // Victim auto vote NO
- boot.votes[kicker] = LFG_ANSWER_AGREE; // Kicker auto vote YES
-
- // Notify players
- for (LfgGuidSet::const_iterator it = players.begin(); it != players.end(); ++it)
- SendLfgBootProposalUpdate(*it, boot);
-}
-
-/**
- Update Boot info with player answer
-
- @param[in] guid Player who has answered
- @param[in] player answer
-*/
-void LFGMgr::UpdateBoot(uint64 guid, bool accept)
-{
- uint64 gguid = GetGroup(guid);
- if (!gguid)
- return;
-
- LfgPlayerBootContainer::iterator itBoot = BootsStore.find(gguid);
- if (itBoot == BootsStore.end())
- return;
-
- LfgPlayerBoot& boot = itBoot->second;
-
- if (boot.votes[guid] != LFG_ANSWER_PENDING) // Cheat check: Player can't vote twice
- return;
-
- boot.votes[guid] = LfgAnswer(accept);
-
- uint8 votesNum = 0;
- uint8 agreeNum = 0;
- for (LfgAnswerContainer::const_iterator itVotes = boot.votes.begin(); itVotes != boot.votes.end(); ++itVotes)
- {
- if (itVotes->second != LFG_ANSWER_PENDING)
- {
- ++votesNum;
- if (itVotes->second == LFG_ANSWER_AGREE)
- ++agreeNum;
- }
- }
-
- // if we don't have enough votes (agree or deny) do nothing
- if (agreeNum < LFG_GROUP_KICK_VOTES_NEEDED && (votesNum - agreeNum) < LFG_GROUP_KICK_VOTES_NEEDED)
- return;
-
- // Send update info to all players
- boot.inProgress = false;
- for (LfgAnswerContainer::const_iterator itVotes = boot.votes.begin(); itVotes != boot.votes.end(); ++itVotes)
- {
- uint64 pguid = itVotes->first;
- if (pguid != boot.victim)
- {
- SetState(pguid, LFG_STATE_DUNGEON);
- SendLfgBootProposalUpdate(pguid, boot);
- }
- }
-
- SetState(gguid, LFG_STATE_DUNGEON);
- if (agreeNum == LFG_GROUP_KICK_VOTES_NEEDED) // Vote passed - Kick player
- {
- if (Group* group = sGroupMgr->GetGroupByGUID(GUID_LOPART(gguid)))
- Player::RemoveFromGroup(group, boot.victim, GROUP_REMOVEMETHOD_KICK_LFG);
- DecreaseKicksLeft(gguid);
- }
- BootsStore.erase(itBoot);
-}
-
-/**
- Teleports the player in or out the dungeon
-
- @param[in] player Player to teleport
- @param[in] out Teleport out (true) or in (false)
- @param[in] fromOpcode Function called from opcode handlers? (Default false)
-*/
-void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*/)
-{
- LFGDungeonData const* dungeon = NULL;
- Group* group = player->GetGroup();
-
- if (group && group->isLFGGroup())
- dungeon = GetLFGDungeon(GetDungeon(group->GetGUID()));
-
- if (!dungeon)
- {
- player->GetSession()->SendLfgTeleportError(uint8(LFG_TELEPORTERROR_INVALID_LOCATION));
- return;
- }
-
- if (out)
- {
- if (player->GetMapId() == uint32(dungeon->map))
- player->TeleportToEntryPoint();
-
- return;
- }
-
- LfgTeleportError error = LFG_TELEPORTERROR_OK;
-
- if (!player->IsAlive())
- error = LFG_TELEPORTERROR_PLAYER_DEAD;
- else if (player->IsFalling() || player->HasUnitState(UNIT_STATE_JUMPING))
- error = LFG_TELEPORTERROR_FALLING;
- else if (player->IsMirrorTimerActive(FATIGUE_TIMER))
- error = LFG_TELEPORTERROR_FATIGUE;
- else if (player->GetVehicle())
- error = LFG_TELEPORTERROR_IN_VEHICLE;
- else if (player->GetCharmGUID())
- error = LFG_TELEPORTERROR_CHARMING;
- else if (player->GetMapId() != uint32(dungeon->map)) // Do not teleport players in dungeon to the entrance
- {
- uint32 mapid = dungeon->map;
- float x = dungeon->x;
- float y = dungeon->y;
- float z = dungeon->z;
- float orientation = dungeon->o;
-
- if (!fromOpcode)
- {
- // Select a player inside to be teleported to
- for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player* plrg = itr->GetSource();
- if (plrg && plrg != player && plrg->GetMapId() == uint32(dungeon->map))
- {
- mapid = plrg->GetMapId();
- x = plrg->GetPositionX();
- y = plrg->GetPositionY();
- z = plrg->GetPositionZ();
- orientation = plrg->GetOrientation();
- break;
- }
- }
- }
-
- if (!player->GetMap()->IsDungeon())
- player->SetEntryPoint();
-
- if (!player->TeleportTo(mapid, x, y, z, orientation))
- error = LFG_TELEPORTERROR_INVALID_LOCATION;
- }
- else
- error = LFG_TELEPORTERROR_INVALID_LOCATION;
-
- if (error != LFG_TELEPORTERROR_OK)
- player->GetSession()->SendLfgTeleportError(uint8(error));
-
- //sLog->outDebug(LOG_FILTER_LFG, "TeleportPlayer: Player %s is being teleported in to map %u "
- // "(x: %f, y: %f, z: %f) Result: %u", player->GetName().c_str(), dungeon->map,
- // dungeon->x, dungeon->y, dungeon->z, error);
-}
-
-/**
- Finish a dungeon and give reward, if any.
-
- @param[in] guid Group guid
- @param[in] dungeonId Dungeonid
-*/
-void LFGMgr::FinishDungeon(uint64 gguid, const uint32 dungeonId, const Map* currMap)
-{
- uint32 gDungeonId = GetDungeon(gguid);
- if (gDungeonId != dungeonId)
- {
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FinishDungeon: [" UI64FMTD "] Finished dungeon %u but group queued for %u. Ignoring", gguid, dungeonId, gDungeonId);
- return;
- }
-
- if (GetState(gguid) == LFG_STATE_FINISHED_DUNGEON) // Shouldn't happen. Do not reward multiple times
- {
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FinishDungeon: [" UI64FMTD "] Already rewarded group. Ignoring", gguid);
- return;
- }
-
- SetState(gguid, LFG_STATE_FINISHED_DUNGEON);
- _SaveToDB(gguid); // pussywizard
-
- const LfgGuidSet& players = GetPlayers(gguid);
- for (LfgGuidSet::const_iterator it = players.begin(); it != players.end(); ++it)
- {
- uint64 guid = (*it);
- if (GetState(guid) == LFG_STATE_FINISHED_DUNGEON)
- {
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FinishDungeon: [" UI64FMTD "] Already rewarded player. Ignoring", guid);
- continue;
- }
-
- uint32 rDungeonId = 0;
- const LfgDungeonSet& dungeons = GetSelectedDungeons(guid);
- if (!dungeons.empty())
- rDungeonId = (*dungeons.begin());
-
- SetState(guid, LFG_STATE_FINISHED_DUNGEON);
-
- // Give rewards only if its a random dungeon
- LFGDungeonData const* dungeon = GetLFGDungeon(rDungeonId);
-
- if (!dungeon || (dungeon->type != LFG_TYPE_RANDOM && !dungeon->seasonal))
- {
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FinishDungeon: [" UI64FMTD "] dungeon %u is not random or seasonal", guid, rDungeonId);
- continue;
- }
-
- Player* player = ObjectAccessor::FindPlayer(guid);
- if (!player || player->FindMap() != currMap) // pussywizard: currMap - multithreading crash if on other map (map id check is not enough, binding system is not reliable)
- {
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FinishDungeon: [" UI64FMTD "] not found in world", guid);
- continue;
- }
-
- LFGDungeonData const* dungeonDone = GetLFGDungeon(dungeonId);
- uint32 mapId = dungeonDone ? uint32(dungeonDone->map) : 0;
-
- if (player->GetMapId() != mapId)
- {
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FinishDungeon: [" UI64FMTD "] is in map %u and should be in %u to get reward", guid, player->GetMapId(), mapId);
- continue;
- }
-
- // Xinef: Update achievements, set correct amount of randomly grouped players
- if (dungeon->difficulty == DUNGEON_DIFFICULTY_HEROIC)
- if (uint8 count = GetRandomPlayersCount(player->GetGUID()))
- player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS, count);
-
- LfgReward const* reward = GetRandomDungeonReward(rDungeonId, player->getLevel());
- if (!reward)
- continue;
-
- bool done = false;
- Quest const* quest = sObjectMgr->GetQuestTemplate(reward->firstQuest);
- if (!quest)
- continue;
-
- // if we can take the quest, means that we haven't done this kind of "run", IE: First Heroic Random of Day.
- if (player->CanRewardQuest(quest, false))
- player->RewardQuest(quest, 0, NULL, false);
- else
- {
- done = true;
- quest = sObjectMgr->GetQuestTemplate(reward->otherQuest);
- if (!quest)
- continue;
- // we give reward without informing client (retail does this)
- player->RewardQuest(quest, 0, NULL, false);
- }
-
- // Give rewards
- sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FinishDungeon: [" UI64FMTD "] done dungeon %u, %s previously done.", player->GetGUID(), GetDungeon(gguid), done? " " : " not");
- LfgPlayerRewardData data = LfgPlayerRewardData(dungeon->Entry(), GetDungeon(gguid, false), done, quest);
- player->GetSession()->SendLfgPlayerReward(data);
- }
-}
-
-// --------------------------------------------------------------------------//
-// Auxiliar Functions
-// --------------------------------------------------------------------------//
-
-/**
- Get the dungeon list that can be done given a random dungeon entry.
-
- @param[in] randomdungeon Random dungeon id (if value = 0 will return all dungeons)
- @returns Set of dungeons that can be done.
-*/
-LfgDungeonSet const& LFGMgr::GetDungeonsByRandom(uint32 randomdungeon)
-{
- LFGDungeonData const* dungeon = GetLFGDungeon(randomdungeon);
- uint32 group = dungeon ? dungeon->group : 0;
- return CachedDungeonMapStore[group];
-}
-
-/**
- Get the reward of a given random dungeon at a certain level
-
- @param[in] dungeon dungeon id
- @param[in] level Player level
- @returns Reward
-*/
-LfgReward const* LFGMgr::GetRandomDungeonReward(uint32 dungeon, uint8 level)
-{
- LfgReward const* rew = NULL;
- LfgRewardContainerBounds bounds = RewardMapStore.equal_range(dungeon & 0x00FFFFFF);
- for (LfgRewardContainer::const_iterator itr = bounds.first; itr != bounds.second; ++itr)
- {
- rew = itr->second;
- // ordered properly at loading
- if (itr->second->maxLevel >= level)
- break;
- }
-
- return rew;
-}
-
-/**
- Given a Dungeon id returns the dungeon Type
-
- @param[in] dungeon dungeon id
- @returns Dungeon type
-*/
-LfgType LFGMgr::GetDungeonType(uint32 dungeonId)
-{
- LFGDungeonData const* dungeon = GetLFGDungeon(dungeonId);
- if (!dungeon)
- return LFG_TYPE_NONE;
-
- return LfgType(dungeon->type);
-}
-
-LfgState LFGMgr::GetState(uint64 guid)
-{
- LfgState state;
- if (IS_GROUP_GUID(guid))
- state = GroupsStore[guid].GetState();
- else
- state = PlayersStore[guid].GetState();
-
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::GetState: [" UI64FMTD "] = %u", guid, state);
- return state;
-}
-
-LfgState LFGMgr::GetOldState(uint64 guid)
-{
- LfgState state;
- if (IS_GROUP_GUID(guid))
- state = GroupsStore[guid].GetOldState();
- else
- state = PlayersStore[guid].GetOldState();
-
- ;//sLog->outTrace(LOG_FILTER_LFG, "LFGMgr::GetOldState: [" UI64FMTD "] = %u", guid, state);
- return state;
-}
-
-uint32 LFGMgr::GetDungeon(uint64 guid, bool asId /*= true */)
-{
- uint32 dungeon = GroupsStore[guid].GetDungeon(asId);
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::GetDungeon: [" UI64FMTD "] asId: %u = %u", guid, asId, dungeon);
- return dungeon;
-}
-
-uint32 LFGMgr::GetDungeonMapId(uint64 guid)
-{
- uint32 dungeonId = GroupsStore[guid].GetDungeon(true);
- uint32 mapId = 0;
- if (dungeonId)
- if (LFGDungeonData const* dungeon = GetLFGDungeon(dungeonId))
- mapId = dungeon->map;
-
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::GetDungeonMapId: [" UI64FMTD "] = %u (DungeonId = %u)", guid, mapId, dungeonId);
- return mapId;
-}
-
-uint8 LFGMgr::GetRoles(uint64 guid)
-{
- uint8 roles = PlayersStore[guid].GetRoles();
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::GetRoles: [" UI64FMTD "] = %u", guid, roles);
- return roles;
-}
-
-const std::string& LFGMgr::GetComment(uint64 guid)
-{
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::GetComment: [" UI64FMTD "] = %s", guid, PlayersStore[guid].GetComment().c_str());
- return PlayersStore[guid].GetComment();
-}
-
-LfgDungeonSet const& LFGMgr::GetSelectedDungeons(uint64 guid)
-{
- ;//sLog->outTrace(LOG_FILTER_LFG, "LFGMgr::GetSelectedDungeons: [" UI64FMTD "]", guid);
- return PlayersStore[guid].GetSelectedDungeons();
-}
-
-LfgLockMap const& LFGMgr::GetLockedDungeons(uint64 guid)
-{
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::GetLockedDungeons: [" UI64FMTD "]", guid);
- return PlayersStore[guid].GetLockedDungeons();
-}
-
-uint8 LFGMgr::GetKicksLeft(uint64 guid)
-{
- uint8 kicks = GroupsStore[guid].GetKicksLeft();
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::GetKicksLeft: [" UI64FMTD "] = %u", guid, kicks);
- return kicks;
-}
-
-void LFGMgr::RestoreState(uint64 guid, char const* debugMsg)
-{
- if (IS_GROUP_GUID(guid))
- {
- LfgGroupData& data = GroupsStore[guid];
- /*if (sLog->ShouldLog(LOG_FILTER_LFG, LOG_LEVEL_DEBUG))
- {
- std::string const& ps = GetStateString(data.GetState());
- std::string const& os = GetStateString(data.GetOldState());
- sLog->outTrace(LOG_FILTER_LFG, "LFGMgr::RestoreState: Group: [" UI64FMTD "] (%s) State: %s, oldState: %s",
- guid, debugMsg, ps.c_str(), os.c_str());
- }*/
-
- data.RestoreState();
- }
- else
- {
- LfgPlayerData& data = PlayersStore[guid];
- /*if (sLog->ShouldLog(LOG_FILTER_LFG, LOG_LEVEL_DEBUG))
- {
- std::string const& ps = GetStateString(data.GetState());
- std::string const& os = GetStateString(data.GetOldState());
- sLog->outTrace(LOG_FILTER_LFG, "LFGMgr::RestoreState: Player: [" UI64FMTD "] (%s) State: %s, oldState: %s",
- guid, debugMsg, ps.c_str(), os.c_str());
- }*/
- data.RestoreState();
- }
-}
-
-void LFGMgr::SetState(uint64 guid, LfgState state)
-{
- if (IS_GROUP_GUID(guid))
- {
- LfgGroupData& data = GroupsStore[guid];
- //char const * const ns = GetStateString(state);
- //char const * const ps = GetStateString(data.GetState());
- //char const * const os = GetStateString(data.GetOldState());
- //sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::SetState: Group: [" UI64FMTD "] newState: %s, previous: %s, oldState: %s", guid, ns, ps, os);
- data.SetState(state);
- }
- else
- {
- LfgPlayerData& data = PlayersStore[guid];
- //char const * const ns = GetStateString(state);
- //char const * const ps = GetStateString(data.GetState());
- //char const * const os = GetStateString(data.GetOldState());
- //sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::SetState: Player: [" UI64FMTD "] newState: %s, previous: %s, oldState: %s", guid, ns, ps, os);
- data.SetState(state);
- }
-}
-
-void LFGMgr::SetCanOverrideRBState(uint64 guid, bool val)
-{
- PlayersStore[guid].SetCanOverrideRBState(val);
-}
-
-void LFGMgr::SetDungeon(uint64 guid, uint32 dungeon)
-{
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::SetDungeon: [" UI64FMTD "] dungeon %u", guid, dungeon);
- GroupsStore[guid].SetDungeon(dungeon);
-}
-
-void LFGMgr::SetRoles(uint64 guid, uint8 roles)
-{
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::SetRoles: [" UI64FMTD "] roles: %u", guid, roles);
- PlayersStore[guid].SetRoles(roles);
-}
-
-void LFGMgr::SetComment(uint64 guid, std::string const& comment)
-{
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::SetComment: [" UI64FMTD "] comment: %s", guid, comment.c_str());
- PlayersStore[guid].SetComment(comment);
-}
-
-void LFGMgr::LfrSetComment(Player* p, std::string comment)
-{
- // pussywizard: client limit for comment length is 64 @ 3.3.5a
- if (comment.size() > 64)
- comment = comment.substr(0, 64);
-
- uint8 teamId = p->GetTeamId();
- RBEntryInfoMap::iterator iter;
- for (RBStoreMap::iterator itr = RaidBrowserStore[teamId].begin(); itr != RaidBrowserStore[teamId].end(); ++itr)
- if ((iter = itr->second.find(p->GetGUIDLow())) != itr->second.end())
- iter->second.comment = comment;
-}
-
-void LFGMgr::SetSelectedDungeons(uint64 guid, LfgDungeonSet const& dungeons)
-{
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::SetSelectedDungeons: [" UI64FMTD "]", guid);
- PlayersStore[guid].SetSelectedDungeons(dungeons);
-}
-
-void LFGMgr::SetLockedDungeons(uint64 guid, LfgLockMap const& lock)
-{
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::SetLockedDungeons: [" UI64FMTD "]", guid);
- PlayersStore[guid].SetLockedDungeons(lock);
-}
-
-void LFGMgr::DecreaseKicksLeft(uint64 guid)
-{
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::DecreaseKicksLeft: [" UI64FMTD "]", guid);
- GroupsStore[guid].DecreaseKicksLeft();
-}
-
-void LFGMgr::RemoveGroupData(uint64 guid)
-{
- ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::RemoveGroupData: [" UI64FMTD "]", guid);
- LfgGroupDataContainer::iterator it = GroupsStore.find(guid);
- if (it == GroupsStore.end())
- return;
-
- LfgState state = GetState(guid);
- // If group is being formed after proposal success do nothing more
- LfgGuidSet const& players = it->second.GetPlayers();
- for (LfgGuidSet::const_iterator it = players.begin(); it != players.end(); ++it)
- {
- uint64 guid = (*it);
- SetGroup(*it, 0);
- if (state != LFG_STATE_PROPOSAL)
- {
- SetState(*it, LFG_STATE_NONE);
- SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE));
- }
- }
- GroupsStore.erase(it);
-}
-
-TeamId LFGMgr::GetTeam(uint64 guid)
-{
- return PlayersStore[guid].GetTeam();
-}
-
-uint8 LFGMgr::RemovePlayerFromGroup(uint64 gguid, uint64 guid)
-{
- return GroupsStore[gguid].RemovePlayer(guid);
-}
-
-void LFGMgr::AddPlayerToGroup(uint64 gguid, uint64 guid)
-{
- GroupsStore[gguid].AddPlayer(guid);
-}
-
-void LFGMgr::SetLeader(uint64 gguid, uint64 leader)
-{
- GroupsStore[gguid].SetLeader(leader);
-}
-
-void LFGMgr::SetTeam(uint64 guid, TeamId teamId)
-{
- PlayersStore[guid].SetTeam(teamId);
-}
-
-uint64 LFGMgr::GetGroup(uint64 guid)
-{
- return PlayersStore[guid].GetGroup();
-}
-
-void LFGMgr::SetGroup(uint64 guid, uint64 group)
-{
- PlayersStore[guid].SetGroup(group);
-}
-
-LfgGuidSet const& LFGMgr::GetPlayers(uint64 guid)
-{
- return GroupsStore[guid].GetPlayers();
-}
-
-uint8 LFGMgr::GetPlayerCount(uint64 guid)
-{
- return GroupsStore[guid].GetPlayerCount();
-}
-
-uint64 LFGMgr::GetLeader(uint64 guid)
-{
- return GroupsStore[guid].GetLeader();
-}
-
-void LFGMgr::SetRandomPlayersCount(uint64 guid, uint8 count)
-{
- PlayersStore[guid].SetRandomPlayersCount(count);
-}
-
-uint8 LFGMgr::GetRandomPlayersCount(uint64 guid)
-{
- return PlayersStore[guid].GetRandomPlayersCount();
-}
-
-bool LFGMgr::HasIgnore(uint64 guid1, uint64 guid2)
-{
- Player* plr1 = ObjectAccessor::FindPlayerInOrOutOfWorld(guid1);
- Player* plr2 = ObjectAccessor::FindPlayerInOrOutOfWorld(guid2);
- uint32 low1 = GUID_LOPART(guid1);
- uint32 low2 = GUID_LOPART(guid2);
- return plr1 && plr2 && (plr1->GetSocial()->HasIgnore(low2) || plr2->GetSocial()->HasIgnore(low1));
-}
-
-void LFGMgr::SendLfgRoleChosen(uint64 guid, uint64 pguid, uint8 roles)
-{
- if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
- player->GetSession()->SendLfgRoleChosen(pguid, roles);
-}
-
-void LFGMgr::SendLfgRoleCheckUpdate(uint64 guid, LfgRoleCheck const& roleCheck)
-{
- if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
- player->GetSession()->SendLfgRoleCheckUpdate(roleCheck);
-}
-
-void LFGMgr::SendLfgUpdatePlayer(uint64 guid, LfgUpdateData const& data)
-{
- if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
- player->GetSession()->SendLfgUpdatePlayer(data);
-}
-
-void LFGMgr::SendLfgUpdateParty(uint64 guid, LfgUpdateData const& data)
-{
- if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
- player->GetSession()->SendLfgUpdateParty(data);
-}
-
-void LFGMgr::SendLfgJoinResult(uint64 guid, LfgJoinResultData const& data)
-{
- if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
- player->GetSession()->SendLfgJoinResult(data);
-}
-
-void LFGMgr::SendLfgBootProposalUpdate(uint64 guid, LfgPlayerBoot const& boot)
-{
- if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
- player->GetSession()->SendLfgBootProposalUpdate(boot);
-}
-
-void LFGMgr::SendLfgUpdateProposal(uint64 guid, LfgProposal const& proposal)
-{
- if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
- player->GetSession()->SendLfgUpdateProposal(proposal);
-}
-
-void LFGMgr::SendLfgQueueStatus(uint64 guid, LfgQueueStatusData const& data)
-{
- if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
- player->GetSession()->SendLfgQueueStatus(data);
-}
-
-bool LFGMgr::IsLfgGroup(uint64 guid)
-{
- return guid && IS_GROUP_GUID(guid) && GroupsStore[guid].IsLfgGroup();
-}
-
-LFGQueue& LFGMgr::GetQueue(uint64 guid)
-{
- uint8 queueId = 0;
- if (IS_GROUP_GUID(guid))
- {
- LfgGuidSet const& players = GetPlayers(guid);
- uint64 pguid = players.empty() ? 0 : (*players.begin());
- if (pguid)
- queueId = GetTeam(pguid);
- else
- queueId = GetTeam(GetLeader(guid));
- }
- else
- queueId = GetTeam(guid);
- return QueuesStore[queueId];
-}
-
-bool LFGMgr::AllQueued(Lfg5Guids const& check)
-{
- bool ok = true;
-
- if (check.empty())
- return false;
-
- for (uint8 i=0; i<5 && check.guid[i]; ++i)
- {
- uint64 guid = check.guid[i];
- if (GetState(guid) != LFG_STATE_QUEUED)
- {
- LFGQueue& queue = GetQueue(guid);
- queue.RemoveFromQueue(guid);
- ok = false;
- }
- }
-
- return ok;
-}
-
-// Only for debugging purposes
-void LFGMgr::Clean()
-{
- QueuesStore.clear();
-}
-
-bool LFGMgr::isOptionEnabled(uint32 option)
-{
- return m_options & option;
-}
-
-uint32 LFGMgr::GetOptions()
-{
- return m_options;
-}
-
-void LFGMgr::SetOptions(uint32 options)
-{
- m_options = options;
-}
-
-LfgUpdateData LFGMgr::GetLfgStatus(uint64 guid)
-{
- LfgPlayerData& playerData = PlayersStore[guid];
- return LfgUpdateData(LFG_UPDATETYPE_UPDATE_STATUS, playerData.GetState(), playerData.GetSelectedDungeons());
-}
-
-bool LFGMgr::IsSeasonActive(uint32 dungeonId)
-{
- switch (dungeonId)
- {
- case 285: // The Headless Horseman
- return IsHolidayActive(HOLIDAY_HALLOWS_END);
- case 286: // The Frost Lord Ahune
- return IsHolidayActive(HOLIDAY_FIRE_FESTIVAL);
- case 287: // Coren Direbrew
- return IsHolidayActive(HOLIDAY_BREWFEST);
- case 288: // The Crown Chemical Co.
- return IsHolidayActive(HOLIDAY_LOVE_IS_IN_THE_AIR);
- }
- return false;
-}
-
-void LFGMgr::SetupGroupMember(uint64 guid, uint64 gguid)
-{
- LfgDungeonSet dungeons;
- dungeons.insert(GetDungeon(gguid));
- SetSelectedDungeons(guid, dungeons);
- SetState(guid, GetState(gguid));
- SetGroup(guid, gguid);
- AddPlayerToGroup(gguid, guid);
-}
-
-bool LFGMgr::selectedRandomLfgDungeon(uint64 guid)
-{
- if (GetState(guid) != LFG_STATE_NONE)
- {
- LfgDungeonSet const& dungeons = GetSelectedDungeons(guid);
- if (!dungeons.empty())
- {
- LFGDungeonData const* dungeon = GetLFGDungeon(*dungeons.begin());
- if (dungeon && (dungeon->type == LFG_TYPE_RANDOM || dungeon->seasonal))
- return true;
- }
- }
-
- return false;
-}
-
-bool LFGMgr::inLfgDungeonMap(uint64 guid, uint32 map, Difficulty difficulty)
-{
- if (!IS_GROUP_GUID(guid))
- guid = GetGroup(guid);
-
- if (uint32 dungeonId = GetDungeon(guid, true))
- if (LFGDungeonData const* dungeon = GetLFGDungeon(dungeonId))
- if (uint32(dungeon->map) == map && dungeon->difficulty == difficulty)
- return true;
-
- return false;
-}
-
-uint32 LFGMgr::GetLFGDungeonEntry(uint32 id)
-{
- if (id)
- if (LFGDungeonData const* dungeon = GetLFGDungeon(id))
- return dungeon->Entry();
-
- return 0;
-}
-
-LfgDungeonSet LFGMgr::GetRandomAndSeasonalDungeons(uint8 level, uint8 expansion)
-{
- LfgDungeonSet randomDungeons;
- for (lfg::LFGDungeonContainer::const_iterator itr = LfgDungeonStore.begin(); itr != LfgDungeonStore.end(); ++itr)
- {
- lfg::LFGDungeonData const& dungeon = itr->second;
- if ((dungeon.type == lfg::LFG_TYPE_RANDOM || (dungeon.seasonal && sLFGMgr->IsSeasonActive(dungeon.id)))
- && dungeon.expansion <= expansion && dungeon.minlevel <= level && level <= dungeon.maxlevel)
- randomDungeons.insert(dungeon.Entry());
- }
- return randomDungeons;
-}
-
-} // namespace lfg
+/*
+ * Copyright (C)
+ *
+ * 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/>.
+ */
+
+#include "Common.h"
+#include "SharedDefines.h"
+#include "DBCStores.h"
+#include "DisableMgr.h"
+#include "ObjectMgr.h"
+#include "SocialMgr.h"
+#include "Language.h"
+#include "LFGMgr.h"
+#include "LFGScripts.h"
+#include "LFGGroupData.h"
+#include "LFGPlayerData.h"
+#include "LFGQueue.h"
+#include "Group.h"
+#include "SpellAuras.h"
+#include "Player.h"
+#include "GroupMgr.h"
+#include "GameEventMgr.h"
+#include "WorldSession.h"
+
+namespace lfg
+{
+
+LFGMgr::LFGMgr(): m_lfgProposalId(1), m_options(sWorld->getIntConfig(CONFIG_LFG_OPTIONSMASK))
+{
+ new LFGPlayerScript();
+ new LFGGroupScript();
+
+ for (uint8 team=0; team<2; ++team)
+ {
+ m_raidBrowserUpdateTimer[team] = 10000;
+ m_raidBrowserLastUpdatedDungeonId[team] = 0;
+ }
+}
+
+LFGMgr::~LFGMgr()
+{
+ for (LfgRewardContainer::iterator itr = RewardMapStore.begin(); itr != RewardMapStore.end(); ++itr)
+ delete itr->second;
+}
+
+void LFGMgr::_LoadFromDB(Field* fields, uint64 guid)
+{
+ if (!fields)
+ return;
+
+ if (!IS_GROUP_GUID(guid))
+ return;
+
+ SetLeader(guid, MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER));
+
+ uint32 dungeon = fields[17].GetUInt32();
+ uint8 state = fields[18].GetUInt8();
+
+ if (!dungeon || !state)
+ return;
+
+ SetDungeon(guid, dungeon);
+
+ switch (state)
+ {
+ case LFG_STATE_DUNGEON:
+ case LFG_STATE_FINISHED_DUNGEON:
+ SetState(guid, (LfgState)state);
+ break;
+ default:
+ break;
+ }
+}
+
+void LFGMgr::_SaveToDB(uint64 guid)
+{
+ if (!IS_GROUP_GUID(guid))
+ return;
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_LFG_DATA);
+ stmt->setUInt32(0, GUID_LOPART(guid));
+ stmt->setUInt32(1, GetDungeon(guid));
+ stmt->setUInt32(2, GetState(guid));
+ CharacterDatabase.Execute(stmt);
+}
+
+/// Load rewards for completing dungeons
+void LFGMgr::LoadRewards()
+{
+ uint32 oldMSTime = getMSTime();
+
+ for (LfgRewardContainer::iterator itr = RewardMapStore.begin(); itr != RewardMapStore.end(); ++itr)
+ delete itr->second;
+ RewardMapStore.clear();
+
+ // ORDER BY is very important for GetRandomDungeonReward!
+ QueryResult result = WorldDatabase.Query("SELECT dungeonId, maxLevel, firstQuestId, otherQuestId FROM lfg_dungeon_rewards ORDER BY dungeonId, maxLevel ASC");
+
+ if (!result)
+ {
+ sLog->outError(">> Loaded 0 lfg dungeon rewards. DB table `lfg_dungeon_rewards` is empty!");
+ return;
+ }
+
+ uint32 count = 0;
+
+ Field* fields = NULL;
+ do
+ {
+ fields = result->Fetch();
+ uint32 dungeonId = fields[0].GetUInt32();
+ uint32 maxLevel = fields[1].GetUInt8();
+ uint32 firstQuestId = fields[2].GetUInt32();
+ uint32 otherQuestId = fields[3].GetUInt32();
+
+ if (!GetLFGDungeonEntry(dungeonId))
+ {
+ sLog->outError("Dungeon %u specified in table `lfg_dungeon_rewards` does not exist!", dungeonId);
+ continue;
+ }
+
+ if (!maxLevel || maxLevel > sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
+ {
+ sLog->outError("Level %u specified for dungeon %u in table `lfg_dungeon_rewards` can never be reached!", maxLevel, dungeonId);
+ maxLevel = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
+ }
+
+ if (!firstQuestId || !sObjectMgr->GetQuestTemplate(firstQuestId))
+ {
+ sLog->outError("First quest %u specified for dungeon %u in table `lfg_dungeon_rewards` does not exist!", firstQuestId, dungeonId);
+ continue;
+ }
+
+ if (otherQuestId && !sObjectMgr->GetQuestTemplate(otherQuestId))
+ {
+ sLog->outError("Other quest %u specified for dungeon %u in table `lfg_dungeon_rewards` does not exist!", otherQuestId, dungeonId);
+ otherQuestId = 0;
+ }
+
+ RewardMapStore.insert(LfgRewardContainer::value_type(dungeonId, new LfgReward(maxLevel, firstQuestId, otherQuestId)));
+ ++count;
+ }
+ while (result->NextRow());
+
+ sLog->outString(">> Loaded %u lfg dungeon rewards in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+ sLog->outString();
+}
+
+LFGDungeonData const* LFGMgr::GetLFGDungeon(uint32 id)
+{
+ LFGDungeonContainer::const_iterator itr = LfgDungeonStore.find(id);
+ if (itr != LfgDungeonStore.end())
+ return &(itr->second);
+
+ return NULL;
+}
+
+void LFGMgr::LoadLFGDungeons(bool reload /* = false */)
+{
+ uint32 oldMSTime = getMSTime();
+
+ LfgDungeonStore.clear();
+
+ // Initialize Dungeon map with data from dbcs
+ for (uint32 i = 0; i < sLFGDungeonStore.GetNumRows(); ++i)
+ {
+ LFGDungeonEntry const* dungeon = sLFGDungeonStore.LookupEntry(i);
+ if (!dungeon)
+ continue;
+
+ switch (dungeon->type)
+ {
+ case LFG_TYPE_DUNGEON:
+ case LFG_TYPE_HEROIC:
+ case LFG_TYPE_RAID:
+ case LFG_TYPE_RANDOM:
+ LfgDungeonStore[dungeon->ID] = LFGDungeonData(dungeon);
+ break;
+ }
+ }
+
+ // Fill teleport locations from DB
+ QueryResult result = WorldDatabase.Query("SELECT dungeonId, position_x, position_y, position_z, orientation FROM lfg_entrances");
+
+ if (!result)
+ {
+ sLog->outError(">> Loaded 0 lfg entrance positions. DB table `lfg_entrances` is empty!");
+ return;
+ }
+
+ uint32 count = 0;
+
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 dungeonId = fields[0].GetUInt32();
+ LFGDungeonContainer::iterator dungeonItr = LfgDungeonStore.find(dungeonId);
+ if (dungeonItr == LfgDungeonStore.end())
+ {
+ sLog->outError("table `lfg_entrances` contains coordinates for wrong dungeon %u", dungeonId);
+ continue;
+ }
+
+ LFGDungeonData& data = dungeonItr->second;
+ data.x = fields[1].GetFloat();
+ data.y = fields[2].GetFloat();
+ data.z = fields[3].GetFloat();
+ data.o = fields[4].GetFloat();
+
+ ++count;
+ }
+ while (result->NextRow());
+
+ sLog->outString(">> Loaded %u lfg entrance positions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+
+ // Fill all other teleport coords from areatriggers
+ for (LFGDungeonContainer::iterator itr = LfgDungeonStore.begin(); itr != LfgDungeonStore.end(); ++itr)
+ {
+ LFGDungeonData& dungeon = itr->second;
+
+ // No teleport coords in database, load from areatriggers
+ if (dungeon.type != LFG_TYPE_RANDOM && dungeon.x == 0.0f && dungeon.y == 0.0f && dungeon.z == 0.0f)
+ {
+ AreaTrigger const* at = sObjectMgr->GetMapEntranceTrigger(dungeon.map);
+ if (!at)
+ {
+ sLog->outError("LFGMgr::LoadLFGDungeons: Failed to load dungeon %s, cant find areatrigger for map %u", dungeon.name.c_str(), dungeon.map);
+ continue;
+ }
+
+ dungeon.map = at->target_mapId;
+ dungeon.x = at->target_X;
+ dungeon.y = at->target_Y;
+ dungeon.z = at->target_Z;
+ dungeon.o = at->target_Orientation;
+ }
+
+ if (dungeon.type != LFG_TYPE_RANDOM)
+ CachedDungeonMapStore[dungeon.group].insert(dungeon.id);
+ CachedDungeonMapStore[0].insert(dungeon.id);
+ }
+
+ if (reload)
+ {
+ CachedDungeonMapStore.clear();
+ // Recalculate locked dungeons
+ for (LfgPlayerDataContainer::const_iterator it = PlayersStore.begin(); it != PlayersStore.end(); ++it)
+ if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(it->first))
+ InitializeLockedDungeons(player);
+ }
+}
+
+void LFGMgr::Update(uint32 tdiff, uint8 task)
+{
+ if (!isOptionEnabled(LFG_OPTION_ENABLE_DUNGEON_FINDER | LFG_OPTION_ENABLE_RAID_BROWSER))
+ return;
+
+ if (task == 0)
+ {
+ time_t currTime = time(NULL);
+
+ // Remove obsolete role checks
+ for (LfgRoleCheckContainer::iterator it = RoleChecksStore.begin(); it != RoleChecksStore.end();)
+ {
+ LfgRoleCheckContainer::iterator itRoleCheck = it++;
+ LfgRoleCheck& roleCheck = itRoleCheck->second;
+ if (currTime < roleCheck.cancelTime)
+ continue;
+ roleCheck.state = LFG_ROLECHECK_MISSING_ROLE;
+
+ for (LfgRolesMap::const_iterator itRoles = roleCheck.roles.begin(); itRoles != roleCheck.roles.end(); ++itRoles)
+ {
+ uint64 guid = itRoles->first;
+ RestoreState(guid, "Remove Obsolete RoleCheck");
+ SendLfgRoleCheckUpdate(guid, roleCheck);
+ if (guid == roleCheck.leader)
+ SendLfgJoinResult(guid, LfgJoinResultData(LFG_JOIN_FAILED, LFG_ROLECHECK_MISSING_ROLE));
+ }
+
+ RestoreState(itRoleCheck->first, "Remove Obsolete RoleCheck");
+ RoleChecksStore.erase(itRoleCheck);
+ }
+
+ // Remove obsolete proposals
+ for (LfgProposalContainer::iterator it = ProposalsStore.begin(); it != ProposalsStore.end();)
+ {
+ LfgProposalContainer::iterator itRemove = it++;
+ if (itRemove->second.cancelTime < currTime)
+ RemoveProposal(itRemove, LFG_UPDATETYPE_PROPOSAL_FAILED);
+ }
+
+ // Remove obsolete kicks
+ for (LfgPlayerBootContainer::iterator it = BootsStore.begin(); it != BootsStore.end();)
+ {
+ LfgPlayerBootContainer::iterator itBoot = it++;
+ LfgPlayerBoot& boot = itBoot->second;
+ if (boot.cancelTime < currTime)
+ {
+ boot.inProgress = false;
+ for (LfgAnswerContainer::const_iterator itVotes = boot.votes.begin(); itVotes != boot.votes.end(); ++itVotes)
+ {
+ uint64 pguid = itVotes->first;
+ if (pguid != boot.victim)
+ SendLfgBootProposalUpdate(pguid, boot);
+ SetState(pguid, LFG_STATE_DUNGEON);
+ }
+ SetState(itBoot->first, LFG_STATE_DUNGEON);
+ BootsStore.erase(itBoot);
+ }
+ }
+ }
+ else if (task == 1)
+ {
+ this->lastProposalId = m_lfgProposalId; // pussywizard: task 2 is done independantly, store previous value in LFGMgr for future use
+ uint8 newGroupsProcessed = 0;
+ // Check if a proposal can be formed with the new groups being added
+ for (LfgQueueContainer::iterator it = QueuesStore.begin(); it != QueuesStore.end(); ++it)
+ {
+ newGroupsProcessed += it->second.FindGroups();
+ if (newGroupsProcessed)
+ break;
+ }
+
+ // Update all players status queue info
+ if (!newGroupsProcessed) // don't do this on updates that precessed groups (performance)
+ for (LfgQueueContainer::iterator it = QueuesStore.begin(); it != QueuesStore.end(); ++it)
+ it->second.UpdateQueueTimers(tdiff);
+ }
+ else if (task == 2)
+ {
+ if (lastProposalId != m_lfgProposalId)
+ {
+ // pussywizard: only one proposal can be created in World::Update (during maps update), and it has id == m_lfgProposalId, so try to find only that one, dunno why for loop here xD
+ for (LfgProposalContainer::const_iterator itProposal = ProposalsStore.find(m_lfgProposalId); itProposal != ProposalsStore.end(); ++itProposal)
+ {
+ uint32 proposalId = itProposal->first;
+ LfgProposal& proposal = ProposalsStore[proposalId];
+
+ uint64 guid = 0;
+ for (LfgProposalPlayerContainer::const_iterator itPlayers = proposal.players.begin(); itPlayers != proposal.players.end(); ++itPlayers)
+ {
+ guid = itPlayers->first;
+ SetState(guid, LFG_STATE_PROPOSAL);
+ if (uint64 gguid = GetGroup(guid))
+ {
+ SetState(gguid, LFG_STATE_PROPOSAL);
+ SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid)));
+ }
+ else
+ SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_PROPOSAL_BEGIN, GetSelectedDungeons(guid), GetComment(guid)));
+ SendLfgUpdateProposal(guid, proposal);
+ }
+
+ if (proposal.state == LFG_PROPOSAL_SUCCESS) // pussywizard: no idea what's the purpose of this xD
+ UpdateProposal(proposalId, guid, true);
+ }
+ }
+
+ UpdateRaidBrowser(tdiff);
+ }
+}
+
+/**
+ Generate the dungeon lock map for a given player
+
+ @param[in] player Player we need to initialize the lock status map
+*/
+void LFGMgr::InitializeLockedDungeons(Player* player, uint8 level /* = 0 */)
+{
+ uint64 guid = player->GetGUID();
+ if (!level)
+ level = player->getLevel();
+ uint8 expansion = player->GetSession()->Expansion();
+ LfgDungeonSet const& dungeons = GetDungeonsByRandom(0);
+ LfgLockMap lock;
+
+ float avgItemLevel = player->GetAverageItemLevelForDF();
+
+ for (LfgDungeonSet::const_iterator it = dungeons.begin(); it != dungeons.end(); ++it)
+ {
+ LFGDungeonData const* dungeon = GetLFGDungeon(*it);
+ if (!dungeon) // should never happen - We provide a list from sLFGDungeonStore
+ continue;
+ MapEntry const* mapEntry = sMapStore.LookupEntry(dungeon->map);
+
+ uint32 lockData = 0;
+ if (dungeon->expansion > expansion)
+ lockData = LFG_LOCKSTATUS_INSUFFICIENT_EXPANSION;
+ else if (DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, dungeon->map, player))
+ lockData = LFG_LOCKSTATUS_RAID_LOCKED;
+ else if (dungeon->difficulty > DUNGEON_DIFFICULTY_NORMAL && (!mapEntry || !mapEntry->IsRaid()) && sInstanceSaveMgr->PlayerIsPermBoundToInstance(player->GetGUIDLow(), dungeon->map, Difficulty(dungeon->difficulty)))
+ lockData = LFG_LOCKSTATUS_RAID_LOCKED;
+ else if (dungeon->minlevel > level)
+ lockData = LFG_LOCKSTATUS_TOO_LOW_LEVEL;
+ else if (dungeon->maxlevel < level)
+ lockData = LFG_LOCKSTATUS_TOO_HIGH_LEVEL;
+ else if (dungeon->seasonal && !IsSeasonActive(dungeon->id))
+ lockData = LFG_LOCKSTATUS_NOT_IN_SEASON;
+ else if (AccessRequirement const* ar = sObjectMgr->GetAccessRequirement(dungeon->map, Difficulty(dungeon->difficulty)))
+ {
+ if (ar->achievement && !player->HasAchieved(ar->achievement))
+ lockData = LFG_LOCKSTATUS_MISSING_ACHIEVEMENT;
+ else if (ar->reqItemLevel && (float)ar->reqItemLevel > avgItemLevel)
+ lockData = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE;
+ else if (player->GetTeamId() == TEAM_ALLIANCE && ar->quest_A && !player->GetQuestRewardStatus(ar->quest_A))
+ lockData = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED;
+ else if (player->GetTeamId() == TEAM_HORDE && ar->quest_H && !player->GetQuestRewardStatus(ar->quest_H))
+ lockData = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED;
+ else
+ if (ar->item)
+ {
+ if (!player->HasItemCount(ar->item) && (!ar->item2 || !player->HasItemCount(ar->item2)))
+ lockData = LFG_LOCKSTATUS_MISSING_ITEM;
+ }
+ else if (ar->item2 && !player->HasItemCount(ar->item2))
+ lockData = LFG_LOCKSTATUS_MISSING_ITEM;
+ }
+
+ /* TODO VoA closed if WG is not under team control (LFG_LOCKSTATUS_RAID_LOCKED)
+ lockData = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE;
+ lockData = LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE;
+ lockData = LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL;
+ lockData = LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL;
+ */
+
+ if (lockData)
+ lock[dungeon->Entry()] = lockData;
+ }
+ SetLockedDungeons(guid, lock);
+}
+
+/**
+ Adds the player/group to lfg queue. If player is in a group then it is the leader
+ of the group tying to join the group. Join conditions are checked before adding
+ to the new queue.
+
+ @param[in] player Player trying to join (or leader of group trying to join)
+ @param[in] roles Player selected roles
+ @param[in] dungeons Dungeons the player/group is applying for
+ @param[in] comment Player selected comment
+*/
+void LFGMgr::JoinLfg(Player* player, uint8 roles, LfgDungeonSet& dungeons, const std::string& comment)
+{
+ if (!player || dungeons.empty())
+ return;
+
+ Group* grp = player->GetGroup();
+ uint64 guid = player->GetGUID();
+ uint64 gguid = grp ? grp->GetGUID() : guid;
+ LfgJoinResultData joinData;
+ LfgGuidSet players;
+ uint32 rDungeonId = 0;
+ bool isContinue = grp && grp->isLFGGroup() && GetState(gguid) != LFG_STATE_FINISHED_DUNGEON;
+
+ if (grp && (grp->isBGGroup() || grp->isBFGroup()))
+ return;
+
+ // pussywizard: can't join LFG/LFR while using LFR
+ if (GetState(player->GetGUID()) == LFG_STATE_RAIDBROWSER)
+ {
+ LfgDungeonSet tmp;
+ SendRaidBrowserJoinedPacket(player, tmp, ""); // the df "eye" can disappear in various case, resend if needed
+ return;
+ }
+
+ // Do not allow to change dungeon in the middle of a current dungeon
+ if (isContinue)
+ {
+ dungeons.clear();
+ dungeons.insert(GetDungeon(gguid));
+ }
+
+ LfgState state = GetState(gguid);
+ switch (state)
+ {
+ case LFG_STATE_ROLECHECK: // if joining again during rolecheck (eg. many players clicked continue inside instance)
+ if (IS_GROUP_GUID(gguid))
+ UpdateRoleCheck(gguid); // abort role check and remove from RoleChecksStore
+ break;
+ case LFG_STATE_QUEUED: // joining again while in a queue
+ {
+ LFGQueue& queue = GetQueue(gguid);
+ queue.RemoveFromQueue(gguid);
+ }
+ break;
+ case LFG_STATE_PROPOSAL: // if joining again during proposal
+ joinData.result = LFG_JOIN_INTERNAL_ERROR;
+ break;
+ case LFG_STATE_FINISHED_DUNGEON:
+ if (grp && grp->isLFGGroup())
+ joinData.result = LFG_JOIN_PARTY_NOT_MEET_REQS;
+ break;
+ default:
+ break;
+ }
+
+ // Check if all dungeons are valid
+ bool isRaid = false;
+ if (joinData.result == LFG_JOIN_OK)
+ {
+ bool isDungeon = false;
+ for (LfgDungeonSet::const_iterator it = dungeons.begin(); it != dungeons.end() && joinData.result == LFG_JOIN_OK; ++it)
+ {
+ LfgType type = GetDungeonType(*it);
+ switch (type)
+ {
+ case LFG_TYPE_RANDOM:
+ if (dungeons.size() > 1) // Only allow 1 random dungeon
+ joinData.result = LFG_JOIN_DUNGEON_INVALID;
+ else
+ rDungeonId = (*dungeons.begin());
+ // No break on purpose (Random can only be dungeon or heroic dungeon)
+ case LFG_TYPE_HEROIC:
+ case LFG_TYPE_DUNGEON:
+ if (isRaid)
+ joinData.result = LFG_JOIN_MIXED_RAID_DUNGEON;
+ isDungeon = true;
+ break;
+ case LFG_TYPE_RAID:
+ if (isDungeon)
+ joinData.result = LFG_JOIN_MIXED_RAID_DUNGEON;
+ isRaid = true;
+ break;
+ default:
+ sLog->outError("Wrong dungeon type %u for dungeon %u", type, *it);
+ joinData.result = LFG_JOIN_DUNGEON_INVALID;
+ break;
+ }
+ }
+ }
+
+ if (!isRaid && joinData.result == LFG_JOIN_OK)
+ {
+ // Check player or group member restrictions
+ if (player->InBattleground() || player->InArena() || player->InBattlegroundQueue())
+ joinData.result = LFG_JOIN_USING_BG_SYSTEM;
+ else if (player->HasAura(LFG_SPELL_DUNGEON_DESERTER))
+ joinData.result = LFG_JOIN_DESERTER;
+ else if (dungeons.empty())
+ joinData.result = LFG_JOIN_NOT_MEET_REQS;
+ else if (grp)
+ {
+ if (grp->GetMembersCount() > MAXGROUPSIZE)
+ joinData.result = LFG_JOIN_TOO_MUCH_MEMBERS;
+ else
+ {
+ uint8 memberCount = 0;
+ for (GroupReference* itr = grp->GetFirstMember(); itr != NULL && joinData.result == LFG_JOIN_OK; itr = itr->next())
+ {
+ if (Player* plrg = itr->GetSource())
+ {
+ if (plrg->HasAura(LFG_SPELL_DUNGEON_DESERTER))
+ joinData.result = LFG_JOIN_PARTY_DESERTER;
+ else if (plrg->InBattleground() || plrg->InArena() || plrg->InBattlegroundQueue())
+ joinData.result = LFG_JOIN_USING_BG_SYSTEM;
+ ++memberCount;
+ players.insert(plrg->GetGUID());
+ }
+ }
+
+ if (joinData.result == LFG_JOIN_OK && memberCount != grp->GetMembersCount())
+ joinData.result = LFG_JOIN_DISCONNECTED;
+ }
+ }
+ else
+ players.insert(player->GetGUID());
+
+ // Xinef: Check dungeon cooldown only for random dungeons
+ // Xinef: Moreover check this only if dungeon is not started, afterwards its obvious that players will have the cooldown
+ if (joinData.result == LFG_JOIN_OK && !isContinue && rDungeonId)
+ {
+ if (player->HasAura(LFG_SPELL_DUNGEON_COOLDOWN)) // xinef: added !isContinue
+ joinData.result = LFG_JOIN_RANDOM_COOLDOWN;
+ else if (grp)
+ {
+ for (GroupReference* itr = grp->GetFirstMember(); itr != NULL && joinData.result == LFG_JOIN_OK; itr = itr->next())
+ if (Player* plrg = itr->GetSource())
+ if (plrg->HasAura(LFG_SPELL_DUNGEON_COOLDOWN)) // xinef: added !isContinue
+ joinData.result = LFG_JOIN_PARTY_RANDOM_COOLDOWN;
+ }
+ }
+ }
+
+ if (isRaid)
+ players.insert(player->GetGUID());
+
+ if (joinData.result == LFG_JOIN_OK)
+ {
+ // Expand random dungeons and check restrictions
+ if (rDungeonId)
+ dungeons = GetDungeonsByRandom(rDungeonId);
+
+ // if we have lockmap then there are no compatible dungeons
+ // xinef: dont check compatibile dungeons for already running group (bind problems)
+ if (!isContinue)
+ {
+ GetCompatibleDungeons(dungeons, players, joinData.lockmap);
+ if (dungeons.empty())
+ joinData.result = grp ? LFG_JOIN_PARTY_NOT_MEET_REQS : LFG_JOIN_NOT_MEET_REQS;
+ }
+ }
+
+ // pussywizard:
+ if (isRaid && grp && (grp->isLFGGroup() || guid != grp->GetLeaderGUID()))
+ return;
+
+ // Can't join. Send result
+ if (joinData.result != LFG_JOIN_OK)
+ {
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::Join: [" UI64FMTD "] joining with %u members. result: %u", guid, grp ? grp->GetMembersCount() : 1, joinData.result);
+ if (!dungeons.empty()) // Only should show lockmap when have no dungeons available
+ joinData.lockmap.clear();
+ player->GetSession()->SendLfgJoinResult(joinData);
+ return;
+ }
+
+ SetComment(guid, comment);
+
+ if (isRaid)
+ {
+ if (grp)
+ roles = PLAYER_ROLE_LEADER;
+ else
+ roles &= (PLAYER_ROLE_TANK | PLAYER_ROLE_HEALER | PLAYER_ROLE_DAMAGE);
+ if (!roles)
+ return;
+ JoinRaidBrowser(player, roles, dungeons, comment);
+ SetState(guid, LFG_STATE_RAIDBROWSER);
+ SendRaidBrowserJoinedPacket(player, dungeons, comment);
+ return;
+ }
+
+ std::string debugNames = "";
+ if (grp) // Begin rolecheck
+ {
+ // Create new rolecheck
+ LfgRoleCheck& roleCheck = RoleChecksStore[gguid];
+ roleCheck.roles.clear(); // pussywizard: NEW rolecheck, not old one with trash data >_>
+ roleCheck.cancelTime = time_t(time(NULL)) + LFG_TIME_ROLECHECK;
+ roleCheck.state = LFG_ROLECHECK_INITIALITING;
+ roleCheck.leader = guid;
+ roleCheck.dungeons = dungeons;
+ roleCheck.rDungeonId = rDungeonId;
+
+ if (rDungeonId)
+ {
+ dungeons.clear();
+ dungeons.insert(rDungeonId);
+ }
+
+ SetState(gguid, LFG_STATE_ROLECHECK);
+ // Send update to player
+ LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_JOIN_QUEUE, dungeons, comment);
+ for (GroupReference* itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ if (Player* plrg = itr->GetSource())
+ {
+ uint64 pguid = plrg->GetGUID();
+ plrg->GetSession()->SendLfgUpdateParty(updateData);
+ SetState(pguid, LFG_STATE_ROLECHECK);
+ if (!isContinue)
+ SetSelectedDungeons(pguid, dungeons);
+ roleCheck.roles[pguid] = 0;
+ if (!debugNames.empty())
+ debugNames.append(", ");
+ debugNames.append(plrg->GetName());
+ }
+ }
+ // Update leader role
+ UpdateRoleCheck(gguid, guid, roles);
+ }
+ else // Add player to queue
+ {
+ LfgRolesMap rolesMap;
+ rolesMap[guid] = roles;
+ LFGQueue& queue = GetQueue(guid);
+ queue.AddQueueData(guid, time(NULL), dungeons, rolesMap);
+
+ if (!isContinue)
+ {
+ if (rDungeonId)
+ {
+ dungeons.clear();
+ dungeons.insert(rDungeonId);
+ }
+ SetSelectedDungeons(guid, dungeons);
+ }
+ // Send update to player
+ player->GetSession()->SendLfgJoinResult(joinData);
+ player->GetSession()->SendLfgUpdatePlayer(LfgUpdateData(LFG_UPDATETYPE_JOIN_QUEUE, dungeons, comment));
+ SetState(guid, LFG_STATE_QUEUED);
+ SetRoles(guid, roles);
+ debugNames.append(player->GetName());
+ }
+
+ /*if (sLog->ShouldLog(LOG_FILTER_LFG, LOG_LEVEL_DEBUG))
+ {
+ std::ostringstream o;
+ o << "LFGMgr::Join: [" << guid << "] joined (" << (grp ? "group" : "player") << ") Members: " << debugNames.c_str()
+ << ". Dungeons (" << uint32(dungeons.size()) << "): " << ConcatenateDungeons(dungeons);
+ ;//sLog->outDebug((LOG_FILTER_LFG, "%s", o.str().c_str());
+ }*/
+}
+
+/**
+ Leaves Dungeon System. Player/Group is removed from queue, rolechecks, proposals
+ or votekicks. Player or group needs to be not NULL and using Dungeon System
+
+ @param[in] guid Player or group guid
+*/
+void LFGMgr::LeaveLfg(uint64 guid)
+{
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::Leave: [" UI64FMTD "]", guid);
+
+ uint64 gguid = IS_GROUP_GUID(guid) ? guid : GetGroup(guid);
+ LfgState state = GetState(guid);
+ switch (state)
+ {
+ case LFG_STATE_QUEUED:
+ if (gguid)
+ {
+ LFGQueue& queue = GetQueue(gguid);
+ queue.RemoveFromQueue(gguid);
+ SetState(gguid, LFG_STATE_NONE);
+ const LfgGuidSet& players = GetPlayers(gguid);
+ for (LfgGuidSet::const_iterator it = players.begin(); it != players.end(); ++it)
+ {
+ SetState(*it, LFG_STATE_NONE);
+ SendLfgUpdateParty(*it, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE));
+ }
+ }
+ else
+ {
+ LFGQueue& queue = GetQueue(guid);
+ queue.RemoveFromQueue(guid);
+ SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE));
+ SetState(guid, LFG_STATE_NONE);
+ }
+ break;
+ case LFG_STATE_ROLECHECK:
+ if (gguid)
+ UpdateRoleCheck(gguid); // No player to update role = LFG_ROLECHECK_ABORTED
+ break;
+ case LFG_STATE_PROPOSAL:
+ {
+ // Remove from Proposals
+ LfgProposalContainer::iterator it = ProposalsStore.begin();
+ uint64 pguid = gguid == guid ? GetLeader(gguid) : guid;
+ while (it != ProposalsStore.end())
+ {
+ LfgProposalPlayerContainer::iterator itPlayer = it->second.players.find(pguid);
+ if (itPlayer != it->second.players.end())
+ {
+ // Mark the player/leader of group who left as didn't accept the proposal
+ itPlayer->second.accept = LFG_ANSWER_DENY;
+ break;
+ }
+ ++it;
+ }
+
+ // Remove from queue - if proposal is found, RemoveProposal will call RemoveFromQueue
+ if (it != ProposalsStore.end())
+ RemoveProposal(it, LFG_UPDATETYPE_PROPOSAL_DECLINED);
+ break;
+ }
+ case LFG_STATE_NONE:
+ break;
+ case LFG_STATE_DUNGEON:
+ case LFG_STATE_FINISHED_DUNGEON:
+ case LFG_STATE_BOOT:
+ if (guid != gguid) // Player
+ SetState(guid, LFG_STATE_NONE);
+ break;
+ case LFG_STATE_RAIDBROWSER:
+ LeaveRaidBrowser(guid);
+ SetCanOverrideRBState(guid, true);
+ SetState(guid, LFG_STATE_NONE);
+ SetCanOverrideRBState(guid, false);
+ SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_LEAVE_RAIDBROWSER));
+ SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_LEAVE_RAIDBROWSER));
+ break;
+ }
+}
+
+void LFGMgr::JoinRaidBrowser(Player* player, uint8 roles, LfgDungeonSet& dungeons, std::string comment)
+{
+ // pussywizard: client limit for comment length is 64 @ 3.3.5a
+ if (comment.size() > 64)
+ comment = comment.substr(0, 64);
+
+ RBEntryInfo entry(roles, comment);
+ for (LfgDungeonSet::const_iterator itr = dungeons.begin(); itr != dungeons.end(); ++itr)
+ if (GetLFGDungeon(*itr)) // ensure dungeon data exists for such dungeon id
+ {
+ RaidBrowserStore[player->GetTeamId()][*itr][player->GetGUIDLow()] = entry;
+ RBUsedDungeonsStore[player->GetTeamId()].insert(*itr);
+ }
+}
+
+void LFGMgr::LeaveRaidBrowser(uint64 guid)
+{
+ uint32 guidLow = GUID_LOPART(guid);
+ for (uint8 team=0; team<2; ++team)
+ for (RBStoreMap::iterator itr = RaidBrowserStore[team].begin(); itr != RaidBrowserStore[team].end(); ++itr)
+ itr->second.erase(guidLow);
+}
+
+void LFGMgr::SendRaidBrowserJoinedPacket(Player* p, LfgDungeonSet& dungeons, std::string comment)
+{
+ if (dungeons.empty())
+ {
+ RBEntryInfoMap::iterator iter;
+ uint8 team = p->GetTeamId();
+ bool setComment = true;
+ for (RBStoreMap::iterator itr = RaidBrowserStore[team].begin(); itr != RaidBrowserStore[team].end(); ++itr)
+ if ((iter = itr->second.find(p->GetGUIDLow())) != itr->second.end())
+ {
+ dungeons.insert(itr->first);
+ if (setComment)
+ {
+ comment = iter->second.comment;
+ setComment = false;
+ }
+ }
+ }
+ LfgJoinResultData joinData;
+ p->GetSession()->SendLfgJoinResult(joinData);
+ LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_JOIN_RAIDBROWSER, dungeons, comment);
+ if (p->GetGroup())
+ p->GetSession()->SendLfgUpdateParty(updateData);
+ else
+ p->GetSession()->SendLfgUpdatePlayer(updateData);
+}
+
+void LFGMgr::LfrSearchAdd(Player* p, uint32 dungeonId)
+{
+ RBSearchersStore[p->GetTeamId()][p->GetGUIDLow()] = dungeonId;
+}
+
+void LFGMgr::LfrSearchRemove(Player* p)
+{
+ RBSearchersStore[p->GetTeamId()].erase(p->GetGUIDLow());
+}
+
+void LFGMgr::SendRaidBrowserCachedList(Player* player, uint32 dungeonId)
+{
+ RBCacheMap::iterator itr = RBCacheStore[player->GetTeamId()].find(dungeonId);
+ if (itr != RBCacheStore[player->GetTeamId()].end())
+ {
+ player->GetSession()->SendPacket(&(itr->second));
+ return;
+ }
+ // send empty packet if cache not found
+ WorldPacket data(SMSG_UPDATE_LFG_LIST, 1000);
+ data << (uint32)LFG_TYPE_RAID;
+ data << (uint32)dungeonId;
+ data << (uint8)0;
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)0;
+ player->GetSession()->SendPacket(&data);
+}
+
+void LFGMgr::UpdateRaidBrowser(uint32 diff)
+{
+ for (uint8 team=0; team<2; ++team)
+ {
+ if (m_raidBrowserUpdateTimer[team] > diff)
+ m_raidBrowserUpdateTimer[team] -= diff;
+ else
+ m_raidBrowserUpdateTimer[team] = 0;
+ }
+
+ if (getMSTimeDiff(World::GetGameTimeMS(), getMSTime()) > (70*7)/5) // prevent lagging
+ return;
+
+ uint64 guid, groupGuid, instanceGuid;
+ uint8 level, Class, race, talents[3];
+ float iLevel, mp5, mp5combat, baseAP, rangedAP;
+ int32 spellDamage, spellHeal;
+ uint32 dungeonId, encounterMask, maxPower;
+ uint32 deletedCounter, groupCounter, playerCounter;
+ ByteBuffer buffer_deleted, buffer_groups, buffer_players;
+ std::string emptyComment;
+ std::set<uint64> deletedGroups, deletedGroupsToErase;
+ RBInternalInfoMap copy;
+
+ for (uint8 team=0; team<2; ++team)
+ {
+ if (m_raidBrowserLastUpdatedDungeonId[team] == 0) // new loop
+ {
+ if (m_raidBrowserUpdateTimer[team] > 0) // allowed only with some time interval
+ continue;
+ else // reset timer
+ m_raidBrowserUpdateTimer[team] = 5000;
+ }
+
+ RBUsedDungeonsSet::const_iterator neitr, titr;
+ for (neitr = RBUsedDungeonsStore[team].begin(); neitr != RBUsedDungeonsStore[team].end(); )
+ {
+ titr = neitr++;
+ dungeonId = (*titr);
+
+ // go to next dungeon than previously (one dungeon updated in one LFGMgr::UpdateRaidBrowser)
+ if (dungeonId <= m_raidBrowserLastUpdatedDungeonId[team])
+ continue;
+ m_raidBrowserLastUpdatedDungeonId[team] = dungeonId;
+
+ RBEntryInfoMap& entryInfoMap = RaidBrowserStore[team][dungeonId];
+ LFGDungeonData const* dungeonData = GetLFGDungeon(dungeonId); // checked if exists before inserting to the container
+ RBInternalInfoMap& currInternalInfoMap = RBInternalInfoStoreCurr[team][dungeonId];
+ for (RBEntryInfoMap::const_iterator sitr = entryInfoMap.begin(); sitr != entryInfoMap.end(); ++sitr)
+ {
+ guid = MAKE_NEW_GUID(sitr->first, 0, HIGHGUID_PLAYER);
+ groupGuid = 0;
+ Player* p = ObjectAccessor::FindPlayerInOrOutOfWorld(guid);
+ ASSERT(p);
+ if (sitr->second.roles == PLAYER_ROLE_LEADER)
+ {
+ ASSERT(p->GetGroup());
+ groupGuid = p->GetGroup()->GetGUID();
+ }
+ encounterMask = 0;
+ instanceGuid = 0;
+ if (InstancePlayerBind* bind = sInstanceSaveMgr->PlayerGetBoundInstance(sitr->first, dungeonData->map, dungeonData->difficulty))
+ if (bind->perm)
+ {
+ instanceGuid = MAKE_NEW_GUID(bind->save->GetInstanceId(), 0, HIGHGUID_INSTANCE);
+ encounterMask = bind->save->GetCompletedEncounterMask();
+ }
+
+ talents[0] = 0;
+ talents[1] = 0;
+ talents[2] = 0;
+ p->GetTalentTreePoints(talents);
+ spellDamage = p->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_ALL);
+ spellHeal = p->SpellBaseHealingBonusDone(SPELL_SCHOOL_MASK_ALL);
+ mp5 = p->GetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER);
+ mp5combat = p->GetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER);
+ baseAP = p->GetTotalAttackPowerValue(BASE_ATTACK);
+ rangedAP = p->GetTotalAttackPowerValue(RANGED_ATTACK);
+ maxPower = 0;
+ if (p->getClass() == CLASS_DRUID)
+ maxPower = p->GetMaxPower(POWER_MANA);
+ else
+ maxPower = (p->getPowerType() == POWER_RAGE || p->getPowerType() == POWER_RUNIC_POWER) ? p->GetMaxPower(p->getPowerType())/10 : p->GetMaxPower(p->getPowerType());
+
+ currInternalInfoMap[sitr->first] = RBInternalInfo(guid, sitr->second.comment, groupGuid != 0, groupGuid, sitr->second.roles, encounterMask, instanceGuid,
+ 1, p->getLevel(), p->getClass(), p->getRace(), p->GetAverageItemLevel(),
+ talents, p->m_last_area_id, p->GetArmor(), (uint32)std::max<int32>(0, spellDamage), (uint32)std::max<int32>(0, spellHeal),
+ p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_CRIT_MELEE), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_CRIT_RANGED), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_CRIT_SPELL), std::max<float>(0.0f, mp5), std::max<float>(0.0f, mp5combat),
+ std::max<uint32>(baseAP, rangedAP), (uint32)p->GetStat(STAT_AGILITY), p->GetMaxHealth(), maxPower, p->GetDefenseSkillValue(),
+ p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_DODGE), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_BLOCK), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_PARRY), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_HASTE_SPELL), p->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_EXPERTISE));
+
+ if (!groupGuid)
+ continue;
+ for (Group::member_citerator mitr = p->GetGroup()->GetMemberSlots().begin(); mitr != p->GetGroup()->GetMemberSlots().end(); ++mitr)
+ {
+ if (mitr->guid == sitr->first) // leader already added
+ continue;
+ guid = MAKE_NEW_GUID(mitr->guid, 0, HIGHGUID_PLAYER);
+ level = 1;
+ Class = 0;
+ race = 0;
+ iLevel = 0.0f;
+ talents[0] = 0;
+ talents[1] = 0;
+ talents[2] = 0;
+ if (const GlobalPlayerData* gpd = sWorld->GetGlobalPlayerData(mitr->guid))
+ {
+ level = gpd->level;
+ Class = gpd->playerClass;
+ race = gpd->race;
+ }
+ Player* mplr = ObjectAccessor::FindPlayerInOrOutOfWorld(guid);
+ if (mplr)
+ {
+ iLevel = mplr->GetAverageItemLevel();
+ mplr->GetTalentTreePoints(talents);
+ }
+ currInternalInfoMap[mitr->guid] = RBInternalInfo(guid, emptyComment, false, groupGuid, 0, 0, 0,
+ (mplr ? 1 : 0), level, Class, race, iLevel,
+ talents, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0);
+ }
+ }
+
+ copy.clear();
+ copy = currInternalInfoMap; // will be saved as prev at the end
+
+ // compare prev with curr to build difference packet
+ deletedCounter = 0; groupCounter = 0; playerCounter = 0;
+ buffer_deleted.clear(); buffer_groups.clear(); buffer_players.clear();
+ deletedGroups.clear(); deletedGroupsToErase.clear();
+
+ RBInternalInfoMap& prevInternalInfoMap = RBInternalInfoStorePrev[team][dungeonId];
+ RBInternalInfoMap::iterator iter, iterTmp;
+ for (RBInternalInfoMap::const_iterator sitr = prevInternalInfoMap.begin(); sitr != prevInternalInfoMap.end(); ++sitr)
+ {
+ iter = currInternalInfoMap.find(sitr->first);
+ if (iter == currInternalInfoMap.end()) // was -> isn't
+ {
+ if (sitr->second.isGroupLeader)
+ deletedGroups.insert(sitr->second.groupGuid);
+ ++deletedCounter;
+ buffer_deleted << (uint64)sitr->second.guid;
+ }
+ else // was -> is
+ {
+ if (sitr->second.isGroupLeader) // was a leader
+ {
+ if (!iter->second.isGroupLeader) // leader -> no longer a leader
+ deletedGroups.insert(sitr->second.groupGuid);
+ else if (sitr->second.groupGuid != iter->second.groupGuid) // leader -> leader of another group
+ {
+ deletedGroups.insert(sitr->second.groupGuid);
+ deletedGroupsToErase.insert(iter->second.groupGuid);
+ ++groupCounter;
+ RBPacketAppendGroup(iter->second, buffer_groups);
+ }
+ else if (sitr->second.comment != iter->second.comment || sitr->second.encounterMask != iter->second.encounterMask || sitr->second.instanceGuid != iter->second.instanceGuid) // leader -> nothing changed
+ {
+ ++groupCounter;
+ RBPacketAppendGroup(iter->second, buffer_groups);
+ }
+ }
+ else if (iter->second.isGroupLeader) // wasn't a leader -> is a leader
+ {
+ deletedGroupsToErase.insert(iter->second.groupGuid);
+ ++groupCounter;
+ RBPacketAppendGroup(iter->second, buffer_groups);
+ }
+
+ if (!iter->second._online) // if offline, copy previous stats (itemLevel, talents, area, etc.)
+ {
+ iterTmp = copy.find(sitr->first); // copied container is for building a full packet, so modify it there (currInternalInfoMap is erased)
+ iterTmp->second.CopyStats(sitr->second);
+ if (!sitr->second.PlayerSameAs(iterTmp->second)) // player info changed
+ {
+ ++playerCounter;
+ RBPacketAppendPlayer(iterTmp->second, buffer_players);
+ }
+ }
+ else if (!sitr->second.PlayerSameAs(iter->second)) // player info changed
+ {
+ ++playerCounter;
+ RBPacketAppendPlayer(iter->second, buffer_players);
+ }
+ currInternalInfoMap.erase(iter);
+ }
+ }
+ // left entries (new)
+ for (RBInternalInfoMap::const_iterator sitr = currInternalInfoMap.begin(); sitr != currInternalInfoMap.end(); ++sitr)
+ {
+ if (sitr->second.isGroupLeader)
+ {
+ deletedGroupsToErase.insert(sitr->second.groupGuid);
+ ++groupCounter;
+ RBPacketAppendGroup(sitr->second, buffer_groups);
+ }
+ ++playerCounter;
+ RBPacketAppendPlayer(sitr->second, buffer_players);
+ }
+
+ if (!deletedGroupsToErase.empty())
+ for (std::set<uint64>::const_iterator sitr = deletedGroupsToErase.begin(); sitr != deletedGroupsToErase.end(); ++sitr)
+ deletedGroups.erase(*sitr);
+
+ if (!deletedGroups.empty())
+ for (std::set<uint64>::const_iterator sitr = deletedGroups.begin(); sitr != deletedGroups.end(); ++sitr)
+ {
+ ++deletedCounter;
+ buffer_deleted << (*sitr);
+ }
+
+ WorldPacket differencePacket(SMSG_UPDATE_LFG_LIST, 1000);
+ RBPacketBuildDifference(differencePacket, dungeonId, deletedCounter, buffer_deleted, groupCounter, buffer_groups, playerCounter, buffer_players);
+ WorldPacket fullPacket(SMSG_UPDATE_LFG_LIST, 1000);
+ RBPacketBuildFull(fullPacket, dungeonId, copy);
+
+ RBCacheStore[team][dungeonId] = fullPacket;
+ prevInternalInfoMap = copy;
+ currInternalInfoMap.clear();
+
+ if (entryInfoMap.empty())
+ RBUsedDungeonsStore[team].erase(titr);
+
+ // send difference packet to browsing players
+ for (RBSearchersMap::const_iterator sitr = RBSearchersStore[team].begin(); sitr != RBSearchersStore[team].end(); ++sitr)
+ if (sitr->second == dungeonId)
+ if (Player* p = ObjectAccessor::FindPlayerInOrOutOfWorld(MAKE_NEW_GUID(sitr->first, 0, HIGHGUID_PLAYER)))
+ p->GetSession()->SendPacket(&differencePacket);
+
+ break; // one dungeon updated in one LFGMgr::UpdateRaidBrowser
+ }
+
+ // already updated all in this time interval
+ if (neitr == RBUsedDungeonsStore[team].end())
+ m_raidBrowserLastUpdatedDungeonId[team] = 0;
+ }
+}
+
+void LFGMgr::RBPacketAppendGroup(const RBInternalInfo& info, ByteBuffer& buffer)
+{
+ buffer << (uint64)info.groupGuid;
+ uint32 flags = LFG_UPDATE_FLAG_COMMENT | LFG_UPDATE_FLAG_ROLES | LFG_UPDATE_FLAG_BINDED;
+ buffer << (uint32)flags;
+ if (flags & LFG_UPDATE_FLAG_COMMENT)
+ buffer << info.comment;
+ if (flags & LFG_UPDATE_FLAG_ROLES)
+ for (uint8 j=0; j<3; ++j)
+ buffer << (uint8)0;
+ if (!(flags & LFG_UPDATE_FLAG_BINDED))
+ return;
+ buffer << (uint64)info.instanceGuid;
+ buffer << (uint32)info.encounterMask;
+}
+
+void LFGMgr::RBPacketAppendPlayer(const RBInternalInfo& info, ByteBuffer& buffer)
+{
+ buffer << (uint64)info.guid;
+ uint32 flags = LFG_UPDATE_FLAG_CHARACTERINFO | LFG_UPDATE_FLAG_ROLES | LFG_UPDATE_FLAG_COMMENT | (info.groupGuid ? LFG_UPDATE_FLAG_GROUPGUID : LFG_UPDATE_FLAG_BINDED) | (info.isGroupLeader ? LFG_UPDATE_FLAG_GROUPLEADER : 0) | (!info.groupGuid || info.isGroupLeader ? LFG_UPDATE_FLAG_AREA : 0);
+ buffer << (uint32)flags;
+
+ if (flags & LFG_UPDATE_FLAG_CHARACTERINFO)
+ {
+ buffer << (uint8)info._level;
+ buffer << (uint8)info._class;
+ buffer << (uint8)info._race;
+ buffer << (uint8)info._talents0;
+ buffer << (uint8)info._talents1;
+ buffer << (uint8)info._talents2;
+ buffer << (uint32)info._armor;
+ buffer << (uint32)info._spellDamage;
+ buffer << (uint32)info._spellHeal;
+ buffer << (uint32)info._critRatingMelee;
+ buffer << (uint32)info._critRatingRanged;
+ buffer << (uint32)info._critRatingSpell;
+ buffer << (float)info._mp5;
+ buffer << (float)info._mp5combat;
+ buffer << (uint32)info._attackPower;
+ buffer << (uint32)info._agility;
+ buffer << (uint32)info._health;
+ buffer << (uint32)info._mana;
+ buffer << (uint32)info._online; // talentpoints, used as online/offline marker :D
+ buffer << (float)info._avgItemLevel; // avgitemlevel
+ buffer << (uint32)info._defenseSkill;
+ buffer << (uint32)info._dodgeRating;
+ buffer << (uint32)info._blockRating;
+ buffer << (uint32)info._parryRating;
+ buffer << (uint32)info._hasteRating;
+ buffer << (uint32)info._expertiseRating;
+ }
+
+ if (flags & LFG_UPDATE_FLAG_COMMENT)
+ buffer << (info.groupGuid ? std::string("") : info.comment);
+ if (flags & LFG_UPDATE_FLAG_GROUPLEADER)
+ buffer << (uint8)1; // isLFM
+ if (flags & LFG_UPDATE_FLAG_GROUPGUID)
+ buffer << (uint64)info.groupGuid;
+ if (flags & LFG_UPDATE_FLAG_ROLES)
+ buffer << (uint8)(info.groupGuid ? (info.isGroupLeader ? PLAYER_ROLE_LEADER : 0) : info.roles);
+ if (flags & LFG_UPDATE_FLAG_AREA)
+ buffer << (uint32)info._area;
+ if (flags & LFG_UPDATE_FLAG_STATUS)
+ buffer << (uint8)0;
+ if (!(flags & LFG_UPDATE_FLAG_BINDED))
+ return;
+ buffer << (uint64)info.instanceGuid;
+ buffer << (uint32)info.encounterMask;
+}
+
+void LFGMgr::RBPacketBuildDifference(WorldPacket& differencePacket, uint32 dungeonId, uint32 deletedCounter, ByteBuffer& buffer_deleted, uint32 groupCounter, ByteBuffer& buffer_groups, uint32 playerCounter, ByteBuffer& buffer_players)
+{
+ differencePacket << (uint32)LFG_TYPE_RAID;
+ differencePacket << (uint32)dungeonId;
+ differencePacket << (uint8)1;
+ differencePacket << (uint32)deletedCounter;
+ differencePacket.append(buffer_deleted);
+ differencePacket << (uint32)groupCounter;
+ differencePacket << (uint32)0;
+ differencePacket.append(buffer_groups);
+ differencePacket << (uint32)playerCounter;
+ differencePacket << (uint32)0;
+ differencePacket.append(buffer_players);
+}
+
+void LFGMgr::RBPacketBuildFull(WorldPacket& fullPacket, uint32 dungeonId, RBInternalInfoMap& infoMap)
+{
+ fullPacket << (uint32)LFG_TYPE_RAID;
+ fullPacket << (uint32)dungeonId;
+ fullPacket << (uint8)0;
+ uint32 groupCounter = 0, playerCounter = 0;
+ ByteBuffer buffer_groups, buffer_players;
+ for (RBInternalInfoMap::const_iterator itr = infoMap.begin(); itr != infoMap.end(); ++itr)
+ {
+ if (itr->second.isGroupLeader)
+ {
+ ++groupCounter;
+ RBPacketAppendGroup(itr->second, buffer_groups);
+ }
+ ++playerCounter;
+ RBPacketAppendPlayer(itr->second, buffer_players);
+ }
+ fullPacket << (uint32)groupCounter;
+ fullPacket << (uint32)0;
+ fullPacket.append(buffer_groups);
+ fullPacket << (uint32)playerCounter;
+ fullPacket << (uint32)0;
+ fullPacket.append(buffer_players);
+}
+
+// pussywizard:
+void LFGMgr::LeaveAllLfgQueues(uint64 guid, bool allowgroup, uint64 groupguid)
+{
+ uint64 pguid = 0, gguid = 0;
+ if (IS_GROUP_GUID(guid))
+ gguid = guid;
+ else if (groupguid && IS_GROUP_GUID(groupguid))
+ {
+ pguid = guid;
+ gguid = groupguid;
+ }
+ else
+ {
+ pguid = guid;
+ gguid = GetGroup(guid);
+ }
+ if (!allowgroup)
+ gguid = 0;
+
+ if (pguid)
+ for (lfg::LfgQueueContainer::iterator itr = QueuesStore.begin(); itr != QueuesStore.end(); ++itr)
+ itr->second.RemoveFromQueue(pguid);
+ if (gguid)
+ for (lfg::LfgQueueContainer::iterator itr = QueuesStore.begin(); itr != QueuesStore.end(); ++itr)
+ itr->second.RemoveFromQueue(gguid);
+
+ if (pguid && !gguid)
+ {
+ if (GetState(pguid) == LFG_STATE_QUEUED)
+ {
+ SendLfgUpdatePlayer(pguid, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE));
+ SetState(pguid, LFG_STATE_NONE);
+ }
+ }
+ if (gguid)
+ {
+ if (GetState(gguid) == LFG_STATE_QUEUED)
+ {
+ SetState(gguid, LFG_STATE_NONE);
+ const LfgGuidSet& players = GetPlayers(gguid);
+ for (LfgGuidSet::const_iterator it = players.begin(); it != players.end(); ++it)
+ {
+ SetState(*it, LFG_STATE_NONE);
+ SendLfgUpdateParty(*it, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE));
+ }
+ }
+ }
+}
+
+/**
+ Update the Role check info with the player selected role.
+
+ @param[in] grp Group guid to update rolecheck
+ @param[in] guid Player guid (0 = rolecheck failed)
+ @param[in] roles Player selected roles
+*/
+void LFGMgr::UpdateRoleCheck(uint64 gguid, uint64 guid /* = 0 */, uint8 roles /* = PLAYER_ROLE_NONE */)
+{
+ if (!gguid)
+ return;
+
+ LfgRolesMap check_roles;
+ LfgRoleCheckContainer::iterator itRoleCheck = RoleChecksStore.find(gguid);
+ if (itRoleCheck == RoleChecksStore.end())
+ return;
+
+ LfgRoleCheck& roleCheck = itRoleCheck->second;
+ bool sendRoleChosen = roleCheck.state != LFG_ROLECHECK_DEFAULT && guid;
+
+ if (!guid)
+ roleCheck.state = LFG_ROLECHECK_ABORTED;
+ else if (roles < PLAYER_ROLE_TANK) // Player selected no role.
+ roleCheck.state = LFG_ROLECHECK_NO_ROLE;
+ else
+ {
+ roleCheck.roles[guid] = roles;
+
+ // Check if all players have selected a role
+ LfgRolesMap::const_iterator itRoles = roleCheck.roles.begin();
+ while (itRoles != roleCheck.roles.end() && itRoles->second != PLAYER_ROLE_NONE)
+ ++itRoles;
+
+ if (itRoles == roleCheck.roles.end())
+ {
+ // use temporal var to check roles, CheckGroupRoles modifies the roles
+ check_roles = roleCheck.roles;
+ roleCheck.state = CheckGroupRoles(check_roles) ? LFG_ROLECHECK_FINISHED : LFG_ROLECHECK_WRONG_ROLES;
+ }
+ }
+
+ LfgDungeonSet dungeons;
+ if (roleCheck.rDungeonId)
+ dungeons.insert(roleCheck.rDungeonId);
+ else
+ dungeons = roleCheck.dungeons;
+
+ LfgJoinResultData joinData = LfgJoinResultData(LFG_JOIN_FAILED, roleCheck.state);
+ for (LfgRolesMap::const_iterator it = roleCheck.roles.begin(); it != roleCheck.roles.end(); ++it)
+ {
+ uint64 pguid = it->first;
+
+ if (sendRoleChosen)
+ SendLfgRoleChosen(pguid, guid, roles);
+
+ SendLfgRoleCheckUpdate(pguid, roleCheck);
+ switch (roleCheck.state)
+ {
+ case LFG_ROLECHECK_INITIALITING:
+ continue;
+ case LFG_ROLECHECK_FINISHED:
+ SetState(pguid, LFG_STATE_QUEUED);
+ SetRoles(pguid, it->second);
+ SendLfgUpdateParty(pguid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, dungeons, GetComment(pguid)));
+ break;
+ default:
+ if (roleCheck.leader == pguid)
+ SendLfgJoinResult(pguid, joinData);
+ SendLfgUpdateParty(pguid, LfgUpdateData(LFG_UPDATETYPE_ROLECHECK_FAILED));
+ RestoreState(pguid, "Rolecheck Failed");
+ break;
+ }
+ }
+
+ if (roleCheck.state == LFG_ROLECHECK_FINISHED)
+ {
+ SetState(gguid, LFG_STATE_QUEUED);
+ LFGQueue& queue = GetQueue(gguid);
+ queue.AddQueueData(gguid, time_t(time(NULL)), roleCheck.dungeons, roleCheck.roles);
+ RoleChecksStore.erase(itRoleCheck);
+ }
+ else if (roleCheck.state != LFG_ROLECHECK_INITIALITING)
+ {
+ RestoreState(gguid, "Rolecheck Failed");
+ RoleChecksStore.erase(itRoleCheck);
+ }
+}
+
+/**
+ Given a list of dungeons remove the dungeons players have restrictions.
+
+ @param[in, out] dungeons Dungeons to check restrictions
+ @param[in] players Set of players to check their dungeon restrictions
+ @param[out] lockMap Map of players Lock status info of given dungeons (Empty if dungeons is not empty)
+*/
+void LFGMgr::GetCompatibleDungeons(LfgDungeonSet& dungeons, LfgGuidSet const& players, LfgLockPartyMap& lockMap)
+{
+ lockMap.clear();
+ for (LfgGuidSet::const_iterator it = players.begin(); it != players.end() && !dungeons.empty(); ++it)
+ {
+ uint64 guid = (*it);
+ LfgLockMap const& cachedLockMap = GetLockedDungeons(guid);
+ for (LfgLockMap::const_iterator it2 = cachedLockMap.begin(); it2 != cachedLockMap.end() && !dungeons.empty(); ++it2)
+ {
+ uint32 dungeonId = (it2->first & 0x00FFFFFF); // Compare dungeon ids
+ LfgDungeonSet::iterator itDungeon = dungeons.find(dungeonId);
+ if (itDungeon != dungeons.end())
+ {
+ dungeons.erase(itDungeon);
+ lockMap[guid][dungeonId] = it2->second;
+ }
+ }
+ }
+ if (!dungeons.empty())
+ lockMap.clear();
+}
+
+uint8 LFGMgr::CheckGroupRoles(LfgRolesMap& groles, bool removeLeaderFlag /*= true*/)
+{
+ if (groles.empty())
+ return 0;
+
+ uint8 damage = 0;
+ uint8 tank = 0;
+ uint8 healer = 0;
+
+ if (removeLeaderFlag)
+ for (LfgRolesMap::iterator it = groles.begin(); it != groles.end(); ++it)
+ it->second &= ~PLAYER_ROLE_LEADER;
+
+ for (LfgRolesMap::iterator it = groles.begin(); it != groles.end(); ++it)
+ {
+ if (it->second == PLAYER_ROLE_NONE)
+ return 0;
+
+ if (it->second & PLAYER_ROLE_DAMAGE)
+ {
+ if (it->second != PLAYER_ROLE_DAMAGE)
+ {
+ it->second -= PLAYER_ROLE_DAMAGE;
+ if (uint8 x = CheckGroupRoles(groles, false))
+ return x;
+ it->second += PLAYER_ROLE_DAMAGE;
+ }
+ else if (damage == LFG_DPS_NEEDED)
+ return 0;
+ else
+ damage++;
+ }
+
+ if (it->second & PLAYER_ROLE_HEALER)
+ {
+ if (it->second != PLAYER_ROLE_HEALER)
+ {
+ it->second -= PLAYER_ROLE_HEALER;
+ if (uint8 x = CheckGroupRoles(groles, false))
+ return x;
+ it->second += PLAYER_ROLE_HEALER;
+ }
+ else if (healer == LFG_HEALERS_NEEDED)
+ return 0;
+ else
+ healer++;
+ }
+
+ if (it->second & PLAYER_ROLE_TANK)
+ {
+ if (it->second != PLAYER_ROLE_TANK)
+ {
+ it->second -= PLAYER_ROLE_TANK;
+ if (uint8 x = CheckGroupRoles(groles, false))
+ return x;
+ it->second += PLAYER_ROLE_TANK;
+ }
+ else if (tank == LFG_TANKS_NEEDED)
+ return 0;
+ else
+ tank++;
+ }
+ }
+ if ((tank + healer + damage) == uint8(groles.size()))
+ return (8*tank + 4*healer + damage);
+ return 0;
+}
+
+/**
+ Makes a new group given a proposal
+ @param[in] proposal Proposal to get info from
+*/
+void LFGMgr::MakeNewGroup(LfgProposal const& proposal)
+{
+ LfgGuidList players;
+ LfgGuidList playersToTeleport;
+
+ for (LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
+ {
+ uint64 guid = it->first;
+ if (guid == proposal.leader)
+ players.push_front(guid);
+ else
+ players.push_back(guid);
+
+ if (proposal.isNew || GetGroup(guid) != proposal.group)
+ playersToTeleport.push_back(guid);
+ }
+
+ // Set the dungeon difficulty
+ LFGDungeonData const* dungeon = GetLFGDungeon(proposal.dungeonId);
+ ASSERT(dungeon);
+
+ Group* grp = proposal.group ? sGroupMgr->GetGroupByGUID(GUID_LOPART(proposal.group)) : NULL;
+ uint64 oldGroupGUID = 0;
+ for (LfgGuidList::const_iterator it = players.begin(); it != players.end(); ++it)
+ {
+ uint64 pguid = (*it);
+ Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(pguid);
+ if (!player)
+ continue;
+
+ Group* group = player->GetGroup();
+
+ // Xinef: Apply Random Buff
+ if (grp && !grp->IsLfgWithBuff())
+ {
+ if (!group || group->GetGUID() != oldGroupGUID)
+ grp->AddLfgBuffFlag();
+ else
+ oldGroupGUID = group->GetGUID();
+ }
+
+ // Xinef: Store amount of random players player grouped with
+ if (group)
+ {
+ SetRandomPlayersCount(pguid, group->GetMembersCount() >= MAXGROUPSIZE ? 0 : MAXGROUPSIZE-group->GetMembersCount());
+ oldGroupGUID = group->GetGUID();
+ if (group != grp)
+ group->RemoveMember(player->GetGUID());
+ }
+ else
+ SetRandomPlayersCount(pguid, MAXGROUPSIZE-1);
+
+ if (!grp)
+ {
+ grp = new Group();
+ grp->ConvertToLFG();
+ grp->Create(player);
+ uint64 gguid = grp->GetGUID();
+ SetState(gguid, LFG_STATE_PROPOSAL);
+ sGroupMgr->AddGroup(grp);
+ }
+ else if (group != grp)
+ {
+ // pussywizard:
+ if (!grp->IsFull())
+ grp->AddMember(player);
+ //else // some cleanup? LeaveLFG?
+ // ;
+ }
+
+ grp->SetLfgRoles(pguid, proposal.players.find(pguid)->second.role);
+ }
+
+ // pussywizard: crashfix, group wasn't created when iterating players (no player found by guid), proposal is deleted by the calling function
+ if (!grp)
+ return;
+
+ grp->SetDungeonDifficulty(Difficulty(dungeon->difficulty));
+ uint64 gguid = grp->GetGUID();
+ SetDungeon(gguid, dungeon->Entry());
+ SetState(gguid, LFG_STATE_DUNGEON);
+
+ _SaveToDB(gguid);
+
+ bool randomDungeon = false;
+ // Teleport Player
+ for (LfgGuidList::const_iterator it = playersToTeleport.begin(); it != playersToTeleport.end(); ++it)
+ if (Player* player = ObjectAccessor::FindPlayer(*it))
+ {
+ if (player->GetGroup() != grp) // pussywizard: could not add because group was full (some shitness happened)
+ continue;
+ // Add the cooldown spell if queued for a random dungeon
+ // xinef: add aura
+ if ((randomDungeon || selectedRandomLfgDungeon(player->GetGUID())) && !player->HasAura(LFG_SPELL_DUNGEON_COOLDOWN))
+ {
+ randomDungeon = true;
+ player->AddAura(LFG_SPELL_DUNGEON_COOLDOWN, player);
+ }
+ TeleportPlayer(player, false);
+ }
+
+ if (randomDungeon)
+ grp->AddLfgRandomInstanceFlag();
+ if (Difficulty(dungeon->difficulty) == DUNGEON_DIFFICULTY_HEROIC)
+ grp->AddLfgHeroicFlag();
+
+ // Update group info
+ grp->SendUpdate();
+}
+
+uint32 LFGMgr::AddProposal(LfgProposal& proposal)
+{
+ proposal.id = ++m_lfgProposalId;
+ ProposalsStore[m_lfgProposalId] = proposal;
+ return m_lfgProposalId;
+}
+
+/**
+ Update Proposal info with player answer
+
+ @param[in] proposalId Proposal id to be updated
+ @param[in] guid Player guid to update answer
+ @param[in] accept Player answer
+*/
+void LFGMgr::UpdateProposal(uint32 proposalId, uint64 guid, bool accept)
+{
+ // Check if the proposal exists
+ LfgProposalContainer::iterator itProposal = ProposalsStore.find(proposalId);
+ if (itProposal == ProposalsStore.end())
+ return;
+
+ LfgProposal& proposal = itProposal->second;
+
+ // Check if proposal have the current player
+ LfgProposalPlayerContainer::iterator itProposalPlayer = proposal.players.find(guid);
+ if (itProposalPlayer == proposal.players.end())
+ return;
+
+ LfgProposalPlayer& player = itProposalPlayer->second;
+ player.accept = LfgAnswer(accept);
+
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::UpdateProposal: Player [" UI64FMTD "] of proposal %u selected: %u", guid, proposalId, accept);
+ if (!accept)
+ {
+ RemoveProposal(itProposal, LFG_UPDATETYPE_PROPOSAL_DECLINED);
+ return;
+ }
+
+ // check if all have answered and reorder players (leader first)
+ bool allAnswered = true;
+ for (LfgProposalPlayerContainer::const_iterator itPlayers = proposal.players.begin(); itPlayers != proposal.players.end(); ++itPlayers)
+ if (itPlayers->second.accept != LFG_ANSWER_AGREE) // No answer (-1) or not accepted (0)
+ allAnswered = false;
+
+ if (!allAnswered)
+ {
+ for (LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
+ SendLfgUpdateProposal(it->first, proposal);
+
+ return;
+ }
+
+ bool sendUpdate = proposal.state != LFG_PROPOSAL_SUCCESS;
+ proposal.state = LFG_PROPOSAL_SUCCESS;
+ time_t joinTime = time(NULL);
+
+ LFGQueue& queue = GetQueue(guid);
+ LfgUpdateData updateData = LfgUpdateData(LFG_UPDATETYPE_GROUP_FOUND);
+ for (LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
+ {
+ uint64 pguid = it->first;
+ uint64 gguid = it->second.group;
+ uint32 dungeonId = (*GetSelectedDungeons(pguid).begin());
+ int32 waitTime = -1;
+ if (sendUpdate)
+ SendLfgUpdateProposal(pguid, proposal);
+
+ if (gguid)
+ {
+ waitTime = int32((joinTime - queue.GetJoinTime(gguid)) / IN_MILLISECONDS);
+ SendLfgUpdateParty(pguid, updateData);
+ }
+ else
+ {
+ waitTime = int32((joinTime - queue.GetJoinTime(pguid)) / IN_MILLISECONDS);
+ SendLfgUpdatePlayer(pguid, updateData);
+ }
+ updateData.updateType = LFG_UPDATETYPE_REMOVED_FROM_QUEUE;
+ SendLfgUpdatePlayer(pguid, updateData);
+ SendLfgUpdateParty(pguid, updateData);
+
+ // Update timers
+ uint8 role = GetRoles(pguid);
+ role &= ~PLAYER_ROLE_LEADER;
+ switch (role)
+ {
+ case PLAYER_ROLE_DAMAGE:
+ queue.UpdateWaitTimeDps(waitTime, dungeonId);
+ break;
+ case PLAYER_ROLE_HEALER:
+ queue.UpdateWaitTimeHealer(waitTime, dungeonId);
+ break;
+ case PLAYER_ROLE_TANK:
+ queue.UpdateWaitTimeTank(waitTime, dungeonId);
+ break;
+ default:
+ queue.UpdateWaitTimeAvg(waitTime, dungeonId);
+ break;
+ }
+
+ SetState(pguid, LFG_STATE_DUNGEON);
+ }
+
+ // Remove players/groups from Queue
+ for (uint8 i=0; i<5 && proposal.queues.guid[i]; ++i)
+ queue.RemoveQueueData(proposal.queues.guid[i]);
+
+ MakeNewGroup(proposal);
+ ProposalsStore.erase(itProposal);
+}
+
+/**
+ Remove a proposal from the pool, remove the group that didn't accept (if needed) and readd the other members to the queue
+
+ @param[in] itProposal Iterator to the proposal to remove
+ @param[in] type Type of removal (LFG_UPDATETYPE_PROPOSAL_FAILED, LFG_UPDATETYPE_PROPOSAL_DECLINED)
+*/
+void LFGMgr::RemoveProposal(LfgProposalContainer::iterator itProposal, LfgUpdateType type)
+{
+ LfgProposal& proposal = itProposal->second;
+ proposal.state = LFG_PROPOSAL_FAILED;
+
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::RemoveProposal: Proposal %u, state FAILED, UpdateType %u", itProposal->first, type);
+ // Mark all people that didn't answered as no accept
+ if (type == LFG_UPDATETYPE_PROPOSAL_FAILED)
+ for (LfgProposalPlayerContainer::iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
+ if (it->second.accept == LFG_ANSWER_PENDING)
+ it->second.accept = LFG_ANSWER_DENY;
+
+ // pussywizard: add cooldown for not accepting (after 40 secs) or declining
+ for (LfgProposalPlayerContainer::iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
+ if (it->second.accept == LFG_ANSWER_DENY)
+ if (Player* plr = sObjectAccessor->FindPlayer(it->first))
+ if (Aura* aura = plr->AddAura(LFG_SPELL_DUNGEON_COOLDOWN, plr))
+ aura->SetDuration(150*IN_MILLISECONDS);
+
+ // Mark players/groups to be removed
+ LfgGuidSet toRemove;
+ for (LfgProposalPlayerContainer::iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
+ {
+ if (it->second.accept == LFG_ANSWER_AGREE)
+ continue;
+
+ uint64 guid = it->second.group ? it->second.group : it->first;
+ // Player didn't accept or still pending when no secs left
+ if (it->second.accept == LFG_ANSWER_DENY || type == LFG_UPDATETYPE_PROPOSAL_FAILED)
+ {
+ it->second.accept = LFG_ANSWER_DENY;
+ toRemove.insert(guid);
+ }
+ }
+
+ // Notify players
+ for (LfgProposalPlayerContainer::const_iterator it = proposal.players.begin(); it != proposal.players.end(); ++it)
+ {
+ uint64 guid = it->first;
+ uint64 gguid = it->second.group ? it->second.group : guid;
+
+ SendLfgUpdateProposal(guid, proposal);
+
+ if (toRemove.find(gguid) != toRemove.end()) // Didn't accept or in same group that someone that didn't accept
+ {
+ LfgUpdateData updateData;
+ if (it->second.accept == LFG_ANSWER_DENY)
+ {
+ updateData.updateType = type;
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::RemoveProposal: [" UI64FMTD "] didn't accept. Removing from queue and compatible cache", guid);
+ }
+ else
+ {
+ updateData.updateType = LFG_UPDATETYPE_REMOVED_FROM_QUEUE;
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::RemoveProposal: [" UI64FMTD "] in same group that someone that didn't accept. Removing from queue and compatible cache", guid);
+ }
+
+ RestoreState(guid, "Proposal Fail (didn't accepted or in group with someone that didn't accept");
+ if (gguid != guid)
+ {
+ RestoreState(it->second.group, "Proposal Fail (someone in group didn't accepted)");
+ SendLfgUpdateParty(guid, updateData);
+ }
+ else
+ SendLfgUpdatePlayer(guid, updateData);
+ }
+ else
+ {
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::RemoveProposal: Readding [" UI64FMTD "] to queue.", guid);
+ SetState(guid, LFG_STATE_QUEUED);
+ if (gguid != guid)
+ {
+ SetState(gguid, LFG_STATE_QUEUED);
+ SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid)));
+ }
+ else
+ SendLfgUpdatePlayer(guid, LfgUpdateData(LFG_UPDATETYPE_ADDED_TO_QUEUE, GetSelectedDungeons(guid), GetComment(guid)));
+ }
+ }
+
+ LFGQueue& queue = GetQueue(proposal.players.begin()->first);
+ // Remove players/groups from queue
+ for (LfgGuidSet::const_iterator it = toRemove.begin(); it != toRemove.end(); ++it)
+ {
+ uint64 guid = *it;
+ queue.RemoveFromQueue(guid);
+ proposal.queues.remove(guid);
+ }
+
+ // Readd to queue
+ for (uint8 i=0; i<5 && proposal.queues.guid[i]; ++i)
+ {
+ // xinef: this will work as data is not deleted, only references to this data are cleared
+ // xinef: when new proposal is created
+ // xinef: successful proposal is also taken into account is similar manner
+ queue.AddToQueue(proposal.queues.guid[i], true);
+ }
+
+ ProposalsStore.erase(itProposal);
+}
+
+/**
+ Initialize a boot kick vote
+
+ @param[in] gguid Group the vote kicks belongs to
+ @param[in] kicker Kicker guid
+ @param[in] victim Victim guid
+ @param[in] reason Kick reason
+*/
+void LFGMgr::InitBoot(uint64 gguid, uint64 kicker, uint64 victim, std::string const& reason)
+{
+ SetState(gguid, LFG_STATE_BOOT);
+
+ LfgPlayerBoot& boot = BootsStore[gguid];
+ boot.inProgress = true;
+ boot.cancelTime = time_t(time(NULL)) + LFG_TIME_BOOT;
+ boot.reason = reason;
+ boot.victim = victim;
+
+ LfgGuidSet const& players = GetPlayers(gguid);
+
+ // Set votes
+ for (LfgGuidSet::const_iterator itr = players.begin(); itr != players.end(); ++itr)
+ {
+ uint64 guid = (*itr);
+ SetState(guid, LFG_STATE_BOOT);
+ boot.votes[guid] = LFG_ANSWER_PENDING;
+ }
+
+ boot.votes[victim] = LFG_ANSWER_DENY; // Victim auto vote NO
+ boot.votes[kicker] = LFG_ANSWER_AGREE; // Kicker auto vote YES
+
+ // Notify players
+ for (LfgGuidSet::const_iterator it = players.begin(); it != players.end(); ++it)
+ SendLfgBootProposalUpdate(*it, boot);
+}
+
+/**
+ Update Boot info with player answer
+
+ @param[in] guid Player who has answered
+ @param[in] player answer
+*/
+void LFGMgr::UpdateBoot(uint64 guid, bool accept)
+{
+ uint64 gguid = GetGroup(guid);
+ if (!gguid)
+ return;
+
+ LfgPlayerBootContainer::iterator itBoot = BootsStore.find(gguid);
+ if (itBoot == BootsStore.end())
+ return;
+
+ LfgPlayerBoot& boot = itBoot->second;
+
+ if (boot.votes[guid] != LFG_ANSWER_PENDING) // Cheat check: Player can't vote twice
+ return;
+
+ boot.votes[guid] = LfgAnswer(accept);
+
+ uint8 votesNum = 0;
+ uint8 agreeNum = 0;
+ for (LfgAnswerContainer::const_iterator itVotes = boot.votes.begin(); itVotes != boot.votes.end(); ++itVotes)
+ {
+ if (itVotes->second != LFG_ANSWER_PENDING)
+ {
+ ++votesNum;
+ if (itVotes->second == LFG_ANSWER_AGREE)
+ ++agreeNum;
+ }
+ }
+
+ // if we don't have enough votes (agree or deny) do nothing
+ if (agreeNum < LFG_GROUP_KICK_VOTES_NEEDED && (votesNum - agreeNum) < LFG_GROUP_KICK_VOTES_NEEDED)
+ return;
+
+ // Send update info to all players
+ boot.inProgress = false;
+ for (LfgAnswerContainer::const_iterator itVotes = boot.votes.begin(); itVotes != boot.votes.end(); ++itVotes)
+ {
+ uint64 pguid = itVotes->first;
+ if (pguid != boot.victim)
+ {
+ SetState(pguid, LFG_STATE_DUNGEON);
+ SendLfgBootProposalUpdate(pguid, boot);
+ }
+ }
+
+ SetState(gguid, LFG_STATE_DUNGEON);
+ if (agreeNum == LFG_GROUP_KICK_VOTES_NEEDED) // Vote passed - Kick player
+ {
+ if (Group* group = sGroupMgr->GetGroupByGUID(GUID_LOPART(gguid)))
+ Player::RemoveFromGroup(group, boot.victim, GROUP_REMOVEMETHOD_KICK_LFG);
+ DecreaseKicksLeft(gguid);
+ }
+ BootsStore.erase(itBoot);
+}
+
+/**
+ Teleports the player in or out the dungeon
+
+ @param[in] player Player to teleport
+ @param[in] out Teleport out (true) or in (false)
+ @param[in] fromOpcode Function called from opcode handlers? (Default false)
+*/
+void LFGMgr::TeleportPlayer(Player* player, bool out, bool fromOpcode /*= false*/)
+{
+ LFGDungeonData const* dungeon = NULL;
+ Group* group = player->GetGroup();
+
+ if (group && group->isLFGGroup())
+ dungeon = GetLFGDungeon(GetDungeon(group->GetGUID()));
+
+ if (!dungeon)
+ {
+ player->GetSession()->SendLfgTeleportError(uint8(LFG_TELEPORTERROR_INVALID_LOCATION));
+ return;
+ }
+
+ if (out)
+ {
+ if (player->GetMapId() == uint32(dungeon->map))
+ player->TeleportToEntryPoint();
+
+ return;
+ }
+
+ LfgTeleportError error = LFG_TELEPORTERROR_OK;
+
+ if (!player->IsAlive())
+ error = LFG_TELEPORTERROR_PLAYER_DEAD;
+ else if (player->IsFalling() || player->HasUnitState(UNIT_STATE_JUMPING))
+ error = LFG_TELEPORTERROR_FALLING;
+ else if (player->IsMirrorTimerActive(FATIGUE_TIMER))
+ error = LFG_TELEPORTERROR_FATIGUE;
+ else if (player->GetVehicle())
+ error = LFG_TELEPORTERROR_IN_VEHICLE;
+ else if (player->GetCharmGUID())
+ error = LFG_TELEPORTERROR_CHARMING;
+ else if (player->GetMapId() != uint32(dungeon->map)) // Do not teleport players in dungeon to the entrance
+ {
+ uint32 mapid = dungeon->map;
+ float x = dungeon->x;
+ float y = dungeon->y;
+ float z = dungeon->z;
+ float orientation = dungeon->o;
+
+ if (!fromOpcode)
+ {
+ // Select a player inside to be teleported to
+ for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player* plrg = itr->GetSource();
+ if (plrg && plrg != player && plrg->GetMapId() == uint32(dungeon->map))
+ {
+ mapid = plrg->GetMapId();
+ x = plrg->GetPositionX();
+ y = plrg->GetPositionY();
+ z = plrg->GetPositionZ();
+ orientation = plrg->GetOrientation();
+ break;
+ }
+ }
+ }
+
+ if (!player->GetMap()->IsDungeon())
+ player->SetEntryPoint();
+
+ if (!player->TeleportTo(mapid, x, y, z, orientation))
+ error = LFG_TELEPORTERROR_INVALID_LOCATION;
+ }
+ else
+ error = LFG_TELEPORTERROR_INVALID_LOCATION;
+
+ if (error != LFG_TELEPORTERROR_OK)
+ player->GetSession()->SendLfgTeleportError(uint8(error));
+
+ //sLog->outDebug(LOG_FILTER_LFG, "TeleportPlayer: Player %s is being teleported in to map %u "
+ // "(x: %f, y: %f, z: %f) Result: %u", player->GetName().c_str(), dungeon->map,
+ // dungeon->x, dungeon->y, dungeon->z, error);
+}
+
+/**
+ Finish a dungeon and give reward, if any.
+
+ @param[in] guid Group guid
+ @param[in] dungeonId Dungeonid
+*/
+void LFGMgr::FinishDungeon(uint64 gguid, const uint32 dungeonId, const Map* currMap)
+{
+ uint32 gDungeonId = GetDungeon(gguid);
+ if (gDungeonId != dungeonId)
+ {
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FinishDungeon: [" UI64FMTD "] Finished dungeon %u but group queued for %u. Ignoring", gguid, dungeonId, gDungeonId);
+ return;
+ }
+
+ if (GetState(gguid) == LFG_STATE_FINISHED_DUNGEON) // Shouldn't happen. Do not reward multiple times
+ {
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FinishDungeon: [" UI64FMTD "] Already rewarded group. Ignoring", gguid);
+ return;
+ }
+
+ SetState(gguid, LFG_STATE_FINISHED_DUNGEON);
+ _SaveToDB(gguid); // pussywizard
+
+ const LfgGuidSet& players = GetPlayers(gguid);
+ for (LfgGuidSet::const_iterator it = players.begin(); it != players.end(); ++it)
+ {
+ uint64 guid = (*it);
+ if (GetState(guid) == LFG_STATE_FINISHED_DUNGEON)
+ {
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FinishDungeon: [" UI64FMTD "] Already rewarded player. Ignoring", guid);
+ continue;
+ }
+
+ uint32 rDungeonId = 0;
+ const LfgDungeonSet& dungeons = GetSelectedDungeons(guid);
+ if (!dungeons.empty())
+ rDungeonId = (*dungeons.begin());
+
+ SetState(guid, LFG_STATE_FINISHED_DUNGEON);
+
+ // Give rewards only if its a random dungeon
+ LFGDungeonData const* dungeon = GetLFGDungeon(rDungeonId);
+
+ if (!dungeon || (dungeon->type != LFG_TYPE_RANDOM && !dungeon->seasonal))
+ {
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FinishDungeon: [" UI64FMTD "] dungeon %u is not random or seasonal", guid, rDungeonId);
+ continue;
+ }
+
+ Player* player = ObjectAccessor::FindPlayer(guid);
+ if (!player || player->FindMap() != currMap) // pussywizard: currMap - multithreading crash if on other map (map id check is not enough, binding system is not reliable)
+ {
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FinishDungeon: [" UI64FMTD "] not found in world", guid);
+ continue;
+ }
+
+ LFGDungeonData const* dungeonDone = GetLFGDungeon(dungeonId);
+ uint32 mapId = dungeonDone ? uint32(dungeonDone->map) : 0;
+
+ if (player->GetMapId() != mapId)
+ {
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FinishDungeon: [" UI64FMTD "] is in map %u and should be in %u to get reward", guid, player->GetMapId(), mapId);
+ continue;
+ }
+
+ // Xinef: Update achievements, set correct amount of randomly grouped players
+ if (dungeon->difficulty == DUNGEON_DIFFICULTY_HEROIC)
+ if (uint8 count = GetRandomPlayersCount(player->GetGUID()))
+ player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS, count);
+
+ LfgReward const* reward = GetRandomDungeonReward(rDungeonId, player->getLevel());
+ if (!reward)
+ continue;
+
+ bool done = false;
+ Quest const* quest = sObjectMgr->GetQuestTemplate(reward->firstQuest);
+ if (!quest)
+ continue;
+
+ // if we can take the quest, means that we haven't done this kind of "run", IE: First Heroic Random of Day.
+ if (player->CanRewardQuest(quest, false))
+ player->RewardQuest(quest, 0, NULL, false);
+ else
+ {
+ done = true;
+ quest = sObjectMgr->GetQuestTemplate(reward->otherQuest);
+ if (!quest)
+ continue;
+ // we give reward without informing client (retail does this)
+ player->RewardQuest(quest, 0, NULL, false);
+ }
+
+ // Give rewards
+ sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::FinishDungeon: [" UI64FMTD "] done dungeon %u, %s previously done.", player->GetGUID(), GetDungeon(gguid), done? " " : " not");
+ LfgPlayerRewardData data = LfgPlayerRewardData(dungeon->Entry(), GetDungeon(gguid, false), done, quest);
+ player->GetSession()->SendLfgPlayerReward(data);
+ }
+}
+
+// --------------------------------------------------------------------------//
+// Auxiliar Functions
+// --------------------------------------------------------------------------//
+
+/**
+ Get the dungeon list that can be done given a random dungeon entry.
+
+ @param[in] randomdungeon Random dungeon id (if value = 0 will return all dungeons)
+ @returns Set of dungeons that can be done.
+*/
+LfgDungeonSet const& LFGMgr::GetDungeonsByRandom(uint32 randomdungeon)
+{
+ LFGDungeonData const* dungeon = GetLFGDungeon(randomdungeon);
+ uint32 group = dungeon ? dungeon->group : 0;
+ return CachedDungeonMapStore[group];
+}
+
+/**
+ Get the reward of a given random dungeon at a certain level
+
+ @param[in] dungeon dungeon id
+ @param[in] level Player level
+ @returns Reward
+*/
+LfgReward const* LFGMgr::GetRandomDungeonReward(uint32 dungeon, uint8 level)
+{
+ LfgReward const* rew = NULL;
+ LfgRewardContainerBounds bounds = RewardMapStore.equal_range(dungeon & 0x00FFFFFF);
+ for (LfgRewardContainer::const_iterator itr = bounds.first; itr != bounds.second; ++itr)
+ {
+ rew = itr->second;
+ // ordered properly at loading
+ if (itr->second->maxLevel >= level)
+ break;
+ }
+
+ return rew;
+}
+
+/**
+ Given a Dungeon id returns the dungeon Type
+
+ @param[in] dungeon dungeon id
+ @returns Dungeon type
+*/
+LfgType LFGMgr::GetDungeonType(uint32 dungeonId)
+{
+ LFGDungeonData const* dungeon = GetLFGDungeon(dungeonId);
+ if (!dungeon)
+ return LFG_TYPE_NONE;
+
+ return LfgType(dungeon->type);
+}
+
+LfgState LFGMgr::GetState(uint64 guid)
+{
+ LfgState state;
+ if (IS_GROUP_GUID(guid))
+ state = GroupsStore[guid].GetState();
+ else
+ state = PlayersStore[guid].GetState();
+
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::GetState: [" UI64FMTD "] = %u", guid, state);
+ return state;
+}
+
+LfgState LFGMgr::GetOldState(uint64 guid)
+{
+ LfgState state;
+ if (IS_GROUP_GUID(guid))
+ state = GroupsStore[guid].GetOldState();
+ else
+ state = PlayersStore[guid].GetOldState();
+
+ ;//sLog->outTrace(LOG_FILTER_LFG, "LFGMgr::GetOldState: [" UI64FMTD "] = %u", guid, state);
+ return state;
+}
+
+uint32 LFGMgr::GetDungeon(uint64 guid, bool asId /*= true */)
+{
+ uint32 dungeon = GroupsStore[guid].GetDungeon(asId);
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::GetDungeon: [" UI64FMTD "] asId: %u = %u", guid, asId, dungeon);
+ return dungeon;
+}
+
+uint32 LFGMgr::GetDungeonMapId(uint64 guid)
+{
+ uint32 dungeonId = GroupsStore[guid].GetDungeon(true);
+ uint32 mapId = 0;
+ if (dungeonId)
+ if (LFGDungeonData const* dungeon = GetLFGDungeon(dungeonId))
+ mapId = dungeon->map;
+
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::GetDungeonMapId: [" UI64FMTD "] = %u (DungeonId = %u)", guid, mapId, dungeonId);
+ return mapId;
+}
+
+uint8 LFGMgr::GetRoles(uint64 guid)
+{
+ uint8 roles = PlayersStore[guid].GetRoles();
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::GetRoles: [" UI64FMTD "] = %u", guid, roles);
+ return roles;
+}
+
+const std::string& LFGMgr::GetComment(uint64 guid)
+{
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::GetComment: [" UI64FMTD "] = %s", guid, PlayersStore[guid].GetComment().c_str());
+ return PlayersStore[guid].GetComment();
+}
+
+LfgDungeonSet const& LFGMgr::GetSelectedDungeons(uint64 guid)
+{
+ ;//sLog->outTrace(LOG_FILTER_LFG, "LFGMgr::GetSelectedDungeons: [" UI64FMTD "]", guid);
+ return PlayersStore[guid].GetSelectedDungeons();
+}
+
+LfgLockMap const& LFGMgr::GetLockedDungeons(uint64 guid)
+{
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::GetLockedDungeons: [" UI64FMTD "]", guid);
+ return PlayersStore[guid].GetLockedDungeons();
+}
+
+uint8 LFGMgr::GetKicksLeft(uint64 guid)
+{
+ uint8 kicks = GroupsStore[guid].GetKicksLeft();
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::GetKicksLeft: [" UI64FMTD "] = %u", guid, kicks);
+ return kicks;
+}
+
+void LFGMgr::RestoreState(uint64 guid, char const* debugMsg)
+{
+ if (IS_GROUP_GUID(guid))
+ {
+ LfgGroupData& data = GroupsStore[guid];
+ /*if (sLog->ShouldLog(LOG_FILTER_LFG, LOG_LEVEL_DEBUG))
+ {
+ std::string const& ps = GetStateString(data.GetState());
+ std::string const& os = GetStateString(data.GetOldState());
+ sLog->outTrace(LOG_FILTER_LFG, "LFGMgr::RestoreState: Group: [" UI64FMTD "] (%s) State: %s, oldState: %s",
+ guid, debugMsg, ps.c_str(), os.c_str());
+ }*/
+
+ data.RestoreState();
+ }
+ else
+ {
+ LfgPlayerData& data = PlayersStore[guid];
+ /*if (sLog->ShouldLog(LOG_FILTER_LFG, LOG_LEVEL_DEBUG))
+ {
+ std::string const& ps = GetStateString(data.GetState());
+ std::string const& os = GetStateString(data.GetOldState());
+ sLog->outTrace(LOG_FILTER_LFG, "LFGMgr::RestoreState: Player: [" UI64FMTD "] (%s) State: %s, oldState: %s",
+ guid, debugMsg, ps.c_str(), os.c_str());
+ }*/
+ data.RestoreState();
+ }
+}
+
+void LFGMgr::SetState(uint64 guid, LfgState state)
+{
+ if (IS_GROUP_GUID(guid))
+ {
+ LfgGroupData& data = GroupsStore[guid];
+ //char const * const ns = GetStateString(state);
+ //char const * const ps = GetStateString(data.GetState());
+ //char const * const os = GetStateString(data.GetOldState());
+ //sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::SetState: Group: [" UI64FMTD "] newState: %s, previous: %s, oldState: %s", guid, ns, ps, os);
+ data.SetState(state);
+ }
+ else
+ {
+ LfgPlayerData& data = PlayersStore[guid];
+ //char const * const ns = GetStateString(state);
+ //char const * const ps = GetStateString(data.GetState());
+ //char const * const os = GetStateString(data.GetOldState());
+ //sLog->outDebug(LOG_FILTER_LFG, "LFGMgr::SetState: Player: [" UI64FMTD "] newState: %s, previous: %s, oldState: %s", guid, ns, ps, os);
+ data.SetState(state);
+ }
+}
+
+void LFGMgr::SetCanOverrideRBState(uint64 guid, bool val)
+{
+ PlayersStore[guid].SetCanOverrideRBState(val);
+}
+
+void LFGMgr::SetDungeon(uint64 guid, uint32 dungeon)
+{
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::SetDungeon: [" UI64FMTD "] dungeon %u", guid, dungeon);
+ GroupsStore[guid].SetDungeon(dungeon);
+}
+
+void LFGMgr::SetRoles(uint64 guid, uint8 roles)
+{
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::SetRoles: [" UI64FMTD "] roles: %u", guid, roles);
+ PlayersStore[guid].SetRoles(roles);
+}
+
+void LFGMgr::SetComment(uint64 guid, std::string const& comment)
+{
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::SetComment: [" UI64FMTD "] comment: %s", guid, comment.c_str());
+ PlayersStore[guid].SetComment(comment);
+}
+
+void LFGMgr::LfrSetComment(Player* p, std::string comment)
+{
+ // pussywizard: client limit for comment length is 64 @ 3.3.5a
+ if (comment.size() > 64)
+ comment = comment.substr(0, 64);
+
+ uint8 teamId = p->GetTeamId();
+ RBEntryInfoMap::iterator iter;
+ for (RBStoreMap::iterator itr = RaidBrowserStore[teamId].begin(); itr != RaidBrowserStore[teamId].end(); ++itr)
+ if ((iter = itr->second.find(p->GetGUIDLow())) != itr->second.end())
+ iter->second.comment = comment;
+}
+
+void LFGMgr::SetSelectedDungeons(uint64 guid, LfgDungeonSet const& dungeons)
+{
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::SetSelectedDungeons: [" UI64FMTD "]", guid);
+ PlayersStore[guid].SetSelectedDungeons(dungeons);
+}
+
+void LFGMgr::SetLockedDungeons(uint64 guid, LfgLockMap const& lock)
+{
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::SetLockedDungeons: [" UI64FMTD "]", guid);
+ PlayersStore[guid].SetLockedDungeons(lock);
+}
+
+void LFGMgr::DecreaseKicksLeft(uint64 guid)
+{
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::DecreaseKicksLeft: [" UI64FMTD "]", guid);
+ GroupsStore[guid].DecreaseKicksLeft();
+}
+
+void LFGMgr::RemoveGroupData(uint64 guid)
+{
+ ;//sLog->outDebug((LOG_FILTER_LFG, "LFGMgr::RemoveGroupData: [" UI64FMTD "]", guid);
+ LfgGroupDataContainer::iterator it = GroupsStore.find(guid);
+ if (it == GroupsStore.end())
+ return;
+
+ LfgState state = GetState(guid);
+ // If group is being formed after proposal success do nothing more
+ LfgGuidSet const& players = it->second.GetPlayers();
+ for (LfgGuidSet::const_iterator it = players.begin(); it != players.end(); ++it)
+ {
+ uint64 guid = (*it);
+ SetGroup(*it, 0);
+ if (state != LFG_STATE_PROPOSAL)
+ {
+ SetState(*it, LFG_STATE_NONE);
+ SendLfgUpdateParty(guid, LfgUpdateData(LFG_UPDATETYPE_REMOVED_FROM_QUEUE));
+ }
+ }
+ GroupsStore.erase(it);
+}
+
+TeamId LFGMgr::GetTeam(uint64 guid)
+{
+ return PlayersStore[guid].GetTeam();
+}
+
+uint8 LFGMgr::RemovePlayerFromGroup(uint64 gguid, uint64 guid)
+{
+ return GroupsStore[gguid].RemovePlayer(guid);
+}
+
+void LFGMgr::AddPlayerToGroup(uint64 gguid, uint64 guid)
+{
+ GroupsStore[gguid].AddPlayer(guid);
+}
+
+void LFGMgr::SetLeader(uint64 gguid, uint64 leader)
+{
+ GroupsStore[gguid].SetLeader(leader);
+}
+
+void LFGMgr::SetTeam(uint64 guid, TeamId teamId)
+{
+ if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
+ teamId = TEAM_ALLIANCE; // @Not Sure About That TeamId is supposed to be uint8 Team = 0(@TrinityCore)
+
+ PlayersStore[guid].SetTeam(teamId);
+}
+
+uint64 LFGMgr::GetGroup(uint64 guid)
+{
+ return PlayersStore[guid].GetGroup();
+}
+
+void LFGMgr::SetGroup(uint64 guid, uint64 group)
+{
+ PlayersStore[guid].SetGroup(group);
+}
+
+LfgGuidSet const& LFGMgr::GetPlayers(uint64 guid)
+{
+ return GroupsStore[guid].GetPlayers();
+}
+
+uint8 LFGMgr::GetPlayerCount(uint64 guid)
+{
+ return GroupsStore[guid].GetPlayerCount();
+}
+
+uint64 LFGMgr::GetLeader(uint64 guid)
+{
+ return GroupsStore[guid].GetLeader();
+}
+
+void LFGMgr::SetRandomPlayersCount(uint64 guid, uint8 count)
+{
+ PlayersStore[guid].SetRandomPlayersCount(count);
+}
+
+uint8 LFGMgr::GetRandomPlayersCount(uint64 guid)
+{
+ return PlayersStore[guid].GetRandomPlayersCount();
+}
+
+bool LFGMgr::HasIgnore(uint64 guid1, uint64 guid2)
+{
+ Player* plr1 = ObjectAccessor::FindPlayerInOrOutOfWorld(guid1);
+ Player* plr2 = ObjectAccessor::FindPlayerInOrOutOfWorld(guid2);
+ uint32 low1 = GUID_LOPART(guid1);
+ uint32 low2 = GUID_LOPART(guid2);
+ return plr1 && plr2 && (plr1->GetSocial()->HasIgnore(low2) || plr2->GetSocial()->HasIgnore(low1));
+}
+
+void LFGMgr::SendLfgRoleChosen(uint64 guid, uint64 pguid, uint8 roles)
+{
+ if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
+ player->GetSession()->SendLfgRoleChosen(pguid, roles);
+}
+
+void LFGMgr::SendLfgRoleCheckUpdate(uint64 guid, LfgRoleCheck const& roleCheck)
+{
+ if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
+ player->GetSession()->SendLfgRoleCheckUpdate(roleCheck);
+}
+
+void LFGMgr::SendLfgUpdatePlayer(uint64 guid, LfgUpdateData const& data)
+{
+ if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
+ player->GetSession()->SendLfgUpdatePlayer(data);
+}
+
+void LFGMgr::SendLfgUpdateParty(uint64 guid, LfgUpdateData const& data)
+{
+ if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
+ player->GetSession()->SendLfgUpdateParty(data);
+}
+
+void LFGMgr::SendLfgJoinResult(uint64 guid, LfgJoinResultData const& data)
+{
+ if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
+ player->GetSession()->SendLfgJoinResult(data);
+}
+
+void LFGMgr::SendLfgBootProposalUpdate(uint64 guid, LfgPlayerBoot const& boot)
+{
+ if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
+ player->GetSession()->SendLfgBootProposalUpdate(boot);
+}
+
+void LFGMgr::SendLfgUpdateProposal(uint64 guid, LfgProposal const& proposal)
+{
+ if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
+ player->GetSession()->SendLfgUpdateProposal(proposal);
+}
+
+void LFGMgr::SendLfgQueueStatus(uint64 guid, LfgQueueStatusData const& data)
+{
+ if (Player* player = ObjectAccessor::FindPlayerInOrOutOfWorld(guid))
+ player->GetSession()->SendLfgQueueStatus(data);
+}
+
+bool LFGMgr::IsLfgGroup(uint64 guid)
+{
+ return guid && IS_GROUP_GUID(guid) && GroupsStore[guid].IsLfgGroup();
+}
+
+LFGQueue& LFGMgr::GetQueue(uint64 guid)
+{
+ uint8 queueId = 0;
+ if (IS_GROUP_GUID(guid))
+ {
+ LfgGuidSet const& players = GetPlayers(guid);
+ uint64 pguid = players.empty() ? 0 : (*players.begin());
+ if (pguid)
+ queueId = GetTeam(pguid);
+ else
+ queueId = GetTeam(GetLeader(guid));
+ }
+ else
+ queueId = GetTeam(guid);
+ return QueuesStore[queueId];
+}
+
+bool LFGMgr::AllQueued(Lfg5Guids const& check)
+{
+ bool ok = true;
+
+ if (check.empty())
+ return false;
+
+ for (uint8 i=0; i<5 && check.guid[i]; ++i)
+ {
+ uint64 guid = check.guid[i];
+ if (GetState(guid) != LFG_STATE_QUEUED)
+ {
+ LFGQueue& queue = GetQueue(guid);
+ queue.RemoveFromQueue(guid);
+ ok = false;
+ }
+ }
+
+ return ok;
+}
+
+// Only for debugging purposes
+void LFGMgr::Clean()
+{
+ QueuesStore.clear();
+}
+
+bool LFGMgr::isOptionEnabled(uint32 option)
+{
+ return m_options & option;
+}
+
+uint32 LFGMgr::GetOptions()
+{
+ return m_options;
+}
+
+void LFGMgr::SetOptions(uint32 options)
+{
+ m_options = options;
+}
+
+LfgUpdateData LFGMgr::GetLfgStatus(uint64 guid)
+{
+ LfgPlayerData& playerData = PlayersStore[guid];
+ return LfgUpdateData(LFG_UPDATETYPE_UPDATE_STATUS, playerData.GetState(), playerData.GetSelectedDungeons());
+}
+
+bool LFGMgr::IsSeasonActive(uint32 dungeonId)
+{
+ switch (dungeonId)
+ {
+ case 285: // The Headless Horseman
+ return IsHolidayActive(HOLIDAY_HALLOWS_END);
+ case 286: // The Frost Lord Ahune
+ return IsHolidayActive(HOLIDAY_FIRE_FESTIVAL);
+ case 287: // Coren Direbrew
+ return IsHolidayActive(HOLIDAY_BREWFEST);
+ case 288: // The Crown Chemical Co.
+ return IsHolidayActive(HOLIDAY_LOVE_IS_IN_THE_AIR);
+ }
+ return false;
+}
+
+void LFGMgr::SetupGroupMember(uint64 guid, uint64 gguid)
+{
+ LfgDungeonSet dungeons;
+ dungeons.insert(GetDungeon(gguid));
+ SetSelectedDungeons(guid, dungeons);
+ SetState(guid, GetState(gguid));
+ SetGroup(guid, gguid);
+ AddPlayerToGroup(gguid, guid);
+}
+
+bool LFGMgr::selectedRandomLfgDungeon(uint64 guid)
+{
+ if (GetState(guid) != LFG_STATE_NONE)
+ {
+ LfgDungeonSet const& dungeons = GetSelectedDungeons(guid);
+ if (!dungeons.empty())
+ {
+ LFGDungeonData const* dungeon = GetLFGDungeon(*dungeons.begin());
+ if (dungeon && (dungeon->type == LFG_TYPE_RANDOM || dungeon->seasonal))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool LFGMgr::inLfgDungeonMap(uint64 guid, uint32 map, Difficulty difficulty)
+{
+ if (!IS_GROUP_GUID(guid))
+ guid = GetGroup(guid);
+
+ if (uint32 dungeonId = GetDungeon(guid, true))
+ if (LFGDungeonData const* dungeon = GetLFGDungeon(dungeonId))
+ if (uint32(dungeon->map) == map && dungeon->difficulty == difficulty)
+ return true;
+
+ return false;
+}
+
+uint32 LFGMgr::GetLFGDungeonEntry(uint32 id)
+{
+ if (id)
+ if (LFGDungeonData const* dungeon = GetLFGDungeon(id))
+ return dungeon->Entry();
+
+ return 0;
+}
+
+LfgDungeonSet LFGMgr::GetRandomAndSeasonalDungeons(uint8 level, uint8 expansion)
+{
+ LfgDungeonSet randomDungeons;
+ for (lfg::LFGDungeonContainer::const_iterator itr = LfgDungeonStore.begin(); itr != LfgDungeonStore.end(); ++itr)
+ {
+ lfg::LFGDungeonData const& dungeon = itr->second;
+ if ((dungeon.type == lfg::LFG_TYPE_RANDOM || (dungeon.seasonal && sLFGMgr->IsSeasonActive(dungeon.id)))
+ && dungeon.expansion <= expansion && dungeon.minlevel <= level && level <= dungeon.maxlevel)
+ randomDungeons.insert(dungeon.Entry());
+ }
+ return randomDungeons;
+}
+
+} // namespace lfg
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 3270dc0bf3..8104a840c4 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -1015,8 +1015,6 @@ void Creature::SaveToDB()
void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
{
- return;
-
// update in loaded data
if (!m_DBTableGuid)
m_DBTableGuid = GetGUIDLow();
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 96483bab7f..4fec5c0d90 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -813,8 +813,6 @@ void GameObject::SaveToDB()
void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
{
- return;
-
const GameObjectTemplate* goI = GetGOInfo();
if (!goI)
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index dbdd264a7c..9661b0eef2 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -93,7 +93,7 @@ WorldObject::~WorldObject()
{
if (GetTypeId() == TYPEID_CORPSE)
{
- sLog->outCrash("Object::~Object Corpse guid=" UI64FMTD", type=%d, entry=%u deleted but still in map!!", GetGUID(), ((Corpse*)this)->GetType(), GetEntry());
+ sLog->outCrash("Object::~Object Corpse guid="UI64FMTD", type=%d, entry=%u deleted but still in map!!", GetGUID(), ((Corpse*)this)->GetType(), GetEntry());
ASSERT(false);
}
ResetMap();
@@ -104,7 +104,7 @@ Object::~Object()
{
if (IsInWorld())
{
- sLog->outCrash("Object::~Object - guid=" UI64FMTD", typeid=%d, entry=%u deleted but still in world!!", GetGUID(), GetTypeId(), GetEntry());
+ sLog->outCrash("Object::~Object - guid="UI64FMTD", typeid=%d, entry=%u deleted but still in world!!", GetGUID(), GetTypeId(), GetEntry());
if (isType(TYPEMASK_ITEM))
sLog->outCrash("Item slot %u", ((Item*)this)->GetSlot());
ASSERT(false);
@@ -113,7 +113,7 @@ Object::~Object()
if (m_objectUpdated)
{
- sLog->outCrash("Object::~Object - guid=" UI64FMTD", typeid=%d, entry=%u deleted but still in update list!!", GetGUID(), GetTypeId(), GetEntry());
+ sLog->outCrash("Object::~Object - guid="UI64FMTD", typeid=%d, entry=%u deleted but still in update list!!", GetGUID(), GetTypeId(), GetEntry());
ASSERT(false);
sObjectAccessor->RemoveUpdateObject(this);
}
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 097e9345e0..a1c9d50172 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -4204,7 +4204,7 @@ void Player::removeSpell(uint32 spellId, uint8 removeSpecMask, bool onlyTemporar
// not reset skills for professions and racial abilities
if ((pSkill->categoryId == SKILL_CATEGORY_SECONDARY || pSkill->categoryId == SKILL_CATEGORY_PROFESSION) && (IsProfessionSkill(pSkill->id) || _spell_idx->second->racemask != 0))
continue;
-
+
// pussywizard: this is needed for weapon/armor/language skills to remove them when loosing spell
SetSkill(pSkill->id, GetSkillStep(pSkill->id), 0, 0);
}
@@ -14584,8 +14584,8 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool
break;
case GOSSIP_OPTION_VENDOR:
{
- VendorItemData const* vendorItems = creature->GetVendorItems();
- if (!vendorItems || vendorItems->Empty())
+ VendorItemData const* vendorItems = itr->second.ActionMenuId ? nullptr : creature->GetVendorItems();
+ if (!itr->second.ActionMenuId && (!vendorItems || vendorItems->Empty()))
{
sLog->outErrorDb("Creature %u (Entry: %u) have UNIT_NPC_FLAG_VENDOR but have empty trading item list.", creature->GetGUIDLow(), creature->GetEntry());
canTalk = false;
@@ -14759,7 +14759,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men
break;
case GOSSIP_OPTION_VENDOR:
case GOSSIP_OPTION_ARMORER:
- GetSession()->SendListInventory(guid);
+ GetSession()->SendListInventory(guid, menuItemData->GossipActionMenuId);
break;
case GOSSIP_OPTION_STABLEPET:
GetSession()->SendStablePet(guid);
@@ -20407,7 +20407,7 @@ void Player::TextEmote(const std::string& text)
{
WorldPacket data;
ChatHandler::BuildChatPacket(data, CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, text);
- SendMessageToSetInRange_OwnTeam(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), true);
+ SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), true, !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT));
}
void Player::Whisper(const std::string& text, uint32 language, uint64 receiver)
@@ -20514,7 +20514,7 @@ void Player::PossessSpellInitialize()
if (!charmInfo)
{
- sLog->outError("Player::PossessSpellInitialize(): charm (" UI64FMTD") has no charminfo!", charm->GetGUID());
+ sLog->outError("Player::PossessSpellInitialize(): charm ("UI64FMTD") has no charminfo!", charm->GetGUID());
return;
}
@@ -20604,7 +20604,7 @@ void Player::CharmSpellInitialize()
CharmInfo* charmInfo = charm->GetCharmInfo();
if (!charmInfo)
{
- sLog->outError("Player::CharmSpellInitialize(): the player's charm (" UI64FMTD") has no charminfo!", charm->GetGUID());
+ sLog->outError("Player::CharmSpellInitialize(): the player's charm ("UI64FMTD") has no charminfo!", charm->GetGUID());
return;
}
@@ -21533,8 +21533,9 @@ bool Player::BuyItemFromVendorSlot(uint64 vendorguid, uint32 vendorslot, uint32
return false;
}
- VendorItemData const* vItems = creature->GetVendorItems();
- if (!vItems || vItems->Empty())
+
+ VendorItemData const* vItems = GetSession()->GetCurrentVendor() ? sObjectMgr->GetNpcVendorItemList(GetSession()->GetCurrentVendor()) : creature->GetVendorItems();
+ if (!vItems || vItems->Empty())
{
SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, item, 0);
return false;
@@ -25555,7 +25556,7 @@ void Player::SetEquipmentSet(uint32 index, EquipmentSet eqset)
if (!found) // something wrong...
{
- sLog->outError("Player %s tried to save equipment set " UI64FMTD" (index %u), but that equipment set not found!", GetName().c_str(), eqset.Guid, index);
+ sLog->outError("Player %s tried to save equipment set "UI64FMTD" (index %u), but that equipment set not found!", GetName().c_str(), eqset.Guid, index);
return;
}
}
diff --git a/src/server/game/Entities/Player/SocialMgr.cpp b/src/server/game/Entities/Player/SocialMgr.cpp
index ad7e145aa4..1616c70e07 100644
--- a/src/server/game/Entities/Player/SocialMgr.cpp
+++ b/src/server/game/Entities/Player/SocialMgr.cpp
@@ -222,6 +222,7 @@ void SocialMgr::GetFriendInfo(Player* player, uint32 friendGUID, FriendInfo &fri
TeamId teamId = player->GetTeamId();
AccountTypes security = player->GetSession()->GetSecurity();
+ bool allowTwoSideWhoList = sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
AccountTypes gmLevelInWhoList = AccountTypes(sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST));
PlayerSocialMap::iterator itr = player->GetSocial()->m_playerSocialMap.find(friendGUID);
@@ -230,7 +231,7 @@ void SocialMgr::GetFriendInfo(Player* player, uint32 friendGUID, FriendInfo &fri
// PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
// MODERATOR, GAME MASTER, ADMINISTRATOR can see all
- if (pFriend && (!AccountMgr::IsPlayerAccount(security) || (pFriend->GetTeamId() == teamId && pFriend->GetSession()->GetSecurity() <= gmLevelInWhoList)) && pFriend->IsVisibleGloballyFor(player))
+ if (pFriend && (!AccountMgr::IsPlayerAccount(security) || ((pFriend->GetTeamId() == teamId || allowTwoSideWhoList) && pFriend->GetSession()->GetSecurity() <= gmLevelInWhoList)) && pFriend->IsVisibleGloballyFor(player))
{
friendInfo.Status = FRIEND_STATUS_ONLINE;
if (pFriend->isAFK())
@@ -293,7 +294,8 @@ void SocialMgr::BroadcastToFriendListers(Player* player, WorldPacket* packet)
TeamId teamId = player->GetTeamId();
AccountTypes security = player->GetSession()->GetSecurity();
- uint32 guid = player->GetGUIDLow();
+ uint32 guid = player->GetGUIDLow();
+ bool allowTwoSideWhoList = sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
AccountTypes gmLevelInWhoList = AccountTypes(sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST));
for (SocialMap::const_iterator itr = m_socialMap.begin(); itr != m_socialMap.end(); ++itr)
@@ -305,7 +307,7 @@ void SocialMgr::BroadcastToFriendListers(Player* player, WorldPacket* packet)
// PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
// MODERATOR, GAME MASTER, ADMINISTRATOR can see all
- if (pFriend && (!AccountMgr::IsPlayerAccount(pFriend->GetSession()->GetSecurity()) || (pFriend->GetTeamId() == teamId && security <= gmLevelInWhoList)) && player->IsVisibleGloballyFor(pFriend))
+ if (pFriend && (!AccountMgr::IsPlayerAccount(pFriend->GetSession()->GetSecurity()) || ((pFriend->GetTeamId() == teamId || allowTwoSideWhoList) && security <= gmLevelInWhoList)) && player->IsVisibleGloballyFor(pFriend))
pFriend->GetSession()->SendPacket(packet);
}
}
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index e445cd4c5f..c20ddcd3b9 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -10587,6 +10587,10 @@ uint32 Unit::SpellDamageBonusDone(Unit* victim, SpellInfo const* spellProto, uin
float ApCoeffMod = 1.0f;
int32 DoneTotal = 0;
float DoneTotalMod = TotalMod ? TotalMod : SpellPctDamageModsDone(victim, spellProto, damagetype);
+
+ // Config : RATE_CREATURE_X_SPELLDAMAGE & Do Not Modify Pet/Guardian/Mind Controled Damage
+ if (GetTypeId() == TYPEID_UNIT && (!ToCreature()->IsPet() || !ToCreature()->IsGuardian() || !ToCreature()->IsControlledByPlayer()))
+ DoneTotalMod *= ToCreature()->GetSpellDamageMod(ToCreature()->GetCreatureTemplate()->rank);
// Some spells don't benefit from pct done mods
if (!spellProto->HasAttribute(SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS))
@@ -17062,7 +17066,7 @@ void Unit::RemoveCharmedBy(Unit* charmer)
if (GetCharmInfo())
GetCharmInfo()->SetPetNumber(0, true);
else
- sLog->outError("Aura::HandleModCharm: target=" UI64FMTD" with typeid=%d has a charm aura but no charm info!", GetGUID(), GetTypeId());
+ sLog->outError("Aura::HandleModCharm: target="UI64FMTD" with typeid=%d has a charm aura but no charm info!", GetGUID(), GetTypeId());
}
}
break;
@@ -18472,8 +18476,8 @@ void Unit::StopAttackFaction(uint32 faction_id)
void Unit::OutDebugInfo() const
{
sLog->outError("Unit::OutDebugInfo");
- sLog->outString("GUID " UI64FMTD", entry %u, type %u, name %s", GetGUID(), GetEntry(), (uint32)GetTypeId(), GetName().c_str());
- sLog->outString("OwnerGUID " UI64FMTD", MinionGUID " UI64FMTD", CharmerGUID " UI64FMTD", CharmedGUID " UI64FMTD, GetOwnerGUID(), GetMinionGUID(), GetCharmerGUID(), GetCharmGUID());
+ sLog->outString("GUID "UI64FMTD", entry %u, type %u, name %s", GetGUID(), GetEntry(), (uint32)GetTypeId(), GetName().c_str());
+ sLog->outString("OwnerGUID "UI64FMTD", MinionGUID "UI64FMTD", CharmerGUID "UI64FMTD", CharmedGUID "UI64FMTD, GetOwnerGUID(), GetMinionGUID(), GetCharmerGUID(), GetCharmGUID());
sLog->outString("In world %u, unit type mask %u", (uint32)(IsInWorld() ? 1 : 0), m_unitTypeMask);
if (IsInWorld())
sLog->outString("Mapid %u", GetMapId());
@@ -19190,21 +19194,36 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target)
// FG: pretend that OTHER players in own group are friendly ("blue")
else if (index == UNIT_FIELD_BYTES_2 || index == UNIT_FIELD_FACTIONTEMPLATE)
{
- if (target->IsSpectator() && target->FindMap() && target->FindMap()->IsBattleArena() && (this->GetTypeId() == TYPEID_PLAYER || this->GetTypeId() == TYPEID_UNIT || this->GetTypeId() == TYPEID_DYNAMICOBJECT)) // pussywizard
+ if (IsControlledByPlayer() && target != this && sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && IsInRaidWith(target))
+ {
+ FactionTemplateEntry const* ft1 = GetFactionTemplateEntry();
+ FactionTemplateEntry const* ft2 = target->GetFactionTemplateEntry();
+ if (ft1 && ft2 && !ft1->IsFriendlyTo(*ft2))
+ {
+ if (index == UNIT_FIELD_BYTES_2)
+ // Allow targetting opposite faction in party when enabled in config
+ fieldBuffer << (m_uint32Values[UNIT_FIELD_BYTES_2] & ((UNIT_BYTE2_FLAG_SANCTUARY /*| UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5*/) << 8)); // this flag is at uint8 offset 1 !!
+ else
+ // pretend that all other HOSTILE players have own faction, to allow follow, heal, rezz (trade wont work)
+ fieldBuffer << uint32(target->getFaction());
+ }
+ else
+ fieldBuffer << m_uint32Values[index];
+ }// pussywizard / Callmephil
+ else if (target->IsSpectator() && target->FindMap() && target->FindMap()->IsBattleArena() &&
+ (this->GetTypeId() == TYPEID_PLAYER || this->GetTypeId() == TYPEID_UNIT || this->GetTypeId() == TYPEID_DYNAMICOBJECT))
{
if (index == UNIT_FIELD_BYTES_2)
fieldBuffer << (m_uint32Values[index] & 0xFFFFF2FF); // clear UNIT_BYTE2_FLAG_PVP, UNIT_BYTE2_FLAG_FFA_PVP, UNIT_BYTE2_FLAG_SANCTUARY
else
fieldBuffer << (uint32)target->getFaction();
}
- else
- fieldBuffer << m_uint32Values[index];
+ else
+ fieldBuffer << m_uint32Values[index];
}
else
- {
// send in current format (float as float, uint32 as uint32)
fieldBuffer << m_uint32Values[index];
- }
}
}
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index fe466c7f28..4104bf80b1 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -8540,8 +8540,9 @@ bool ObjectMgr::RemoveVendorItem(uint32 entry, uint32 item, bool persist /*= tru
return true;
}
-bool ObjectMgr::IsVendorItemValid(uint32 vendor_entry, uint32 item_id, int32 maxcount, uint32 incrtime, uint32 ExtendedCost, Player* player, std::set<uint32>* skip_vendors, uint32 ORnpcflag) const
+bool ObjectMgr::IsVendorItemValid(uint32 vendor_entry, uint32 item_id, int32 maxcount, uint32 incrtime, uint32 ExtendedCost, Player* player, std::set<uint32>* /*skip_vendors*/, uint32 /*ORnpcflag*/) const
{
+ /*
CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(vendor_entry);
if (!cInfo)
{
@@ -8566,6 +8567,7 @@ bool ObjectMgr::IsVendorItemValid(uint32 vendor_entry, uint32 item_id, int32 max
}
return false;
}
+ */
if (!sObjectMgr->GetItemTemplate(item_id))
{
diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp
index ef498ba3e0..1848f92453 100644
--- a/src/server/game/Guilds/Guild.cpp
+++ b/src/server/game/Guilds/Guild.cpp
@@ -1504,11 +1504,12 @@ void Guild::HandleInviteMember(WorldSession* session, std::string const& name)
if (pInvitee->GetSocial()->HasIgnore(player->GetGUIDLow()))
return;
- if (pInvitee->GetTeamId() != player->GetTeamId())
+ if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && pInvitee->GetTeamId() != player->GetTeamId())
{
SendCommandResult(session, GUILD_COMMAND_INVITE, ERR_GUILD_NOT_ALLIED, name);
return;
}
+
// Invited player cannot be in another guild
if (pInvitee->GetGuildId())
{
@@ -1545,7 +1546,8 @@ void Guild::HandleInviteMember(WorldSession* session, std::string const& name)
void Guild::HandleAcceptMember(WorldSession* session)
{
Player* player = session->GetPlayer();
- if (player->GetTeamId() != sObjectMgr->GetPlayerTeamIdByGUID(GetLeaderGUID()))
+ if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) &&
+ player->GetTeamId() != sObjectMgr->GetPlayerTeamIdByGUID(GetLeaderGUID()))
return;
AddMember(player->GetGUID());
@@ -1729,7 +1731,7 @@ void Guild::HandleMemberDepositMoney(WorldSession* session, uint32 amount)
_BroadcastEvent(GE_BANK_MONEY_SET, 0, aux.c_str());
if (amount > 10*GOLD)
- CharacterDatabase.PExecute("INSERT INTO log_money VALUES(%u, %u, \"%s\", \"%s\", %u, \"%s\", %u, \"<GB DEPOSIT> %s (guild id: %u, members: %u, new amount: " UI64FMTD", leader guid low: %u, char level: %u)\", NOW())", session->GetAccountId(), player->GetGUIDLow(), player->GetName().c_str(), session->GetRemoteAddress().c_str(), 0, "", amount, GetName().c_str(), GetId(), GetMemberCount(), GetTotalBankMoney(), (uint32)(GetLeaderGUID()&0xFFFFFFFF), player->getLevel());
+ CharacterDatabase.PExecute("INSERT INTO log_money VALUES(%u, %u, \"%s\", \"%s\", %u, \"%s\", %u, \"<GB DEPOSIT> %s (guild id: %u, members: %u, new amount: "UI64FMTD", leader guid low: %u, char level: %u)\", NOW())", session->GetAccountId(), player->GetGUIDLow(), player->GetName().c_str(), session->GetRemoteAddress().c_str(), 0, "", amount, GetName().c_str(), GetId(), GetMemberCount(), GetTotalBankMoney(), (uint32)(GetLeaderGUID()&0xFFFFFFFF), player->getLevel());
}
bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool repair)
@@ -1772,7 +1774,7 @@ bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool
CharacterDatabase.CommitTransaction(trans);
if (amount > 10*GOLD)
- CharacterDatabase.PExecute("INSERT INTO log_money VALUES(%u, %u, \"%s\", \"%s\", %u, \"%s\", %u, \"<GB WITHDRAW> %s (guild id: %u, members: %u, new amount: " UI64FMTD", leader guid low: %u, char level: %u)\", NOW())", session->GetAccountId(), player->GetGUIDLow(), player->GetName().c_str(), session->GetRemoteAddress().c_str(), 0, "", amount, GetName().c_str(), GetId(), GetMemberCount(), GetTotalBankMoney(), (uint32)(GetLeaderGUID()&0xFFFFFFFF), player->getLevel());
+ CharacterDatabase.PExecute("INSERT INTO log_money VALUES(%u, %u, \"%s\", \"%s\", %u, \"%s\", %u, \"<GB WITHDRAW> %s (guild id: %u, members: %u, new amount: "UI64FMTD", leader guid low: %u, char level: %u)\", NOW())", session->GetAccountId(), player->GetGUIDLow(), player->GetName().c_str(), session->GetRemoteAddress().c_str(), 0, "", amount, GetName().c_str(), GetId(), GetMemberCount(), GetTotalBankMoney(), (uint32)(GetLeaderGUID()&0xFFFFFFFF), player->getLevel());
std::string aux = ByteArrayToHexStr(reinterpret_cast<uint8*>(&m_bankMoney), 8, true);
_BroadcastEvent(GE_BANK_MONEY_SET, 0, aux.c_str());
@@ -1845,8 +1847,6 @@ void Guild::SendBankTabData(WorldSession* session, uint8 tabId) const
void Guild::SendBankTabsInfo(WorldSession* session, bool sendAllSlots /*= false*/) const
{
- if (session->GetSecurity())
- return;
_SendBankList(session, 0, sendAllSlots);
}
diff --git a/src/server/game/Handlers/ArenaTeamHandler.cpp b/src/server/game/Handlers/ArenaTeamHandler.cpp
index 079f7f91a7..51c9e2605a 100644
--- a/src/server/game/Handlers/ArenaTeamHandler.cpp
+++ b/src/server/game/Handlers/ArenaTeamHandler.cpp
@@ -123,11 +123,11 @@ void WorldSession::HandleArenaTeamInviteOpcode(WorldPacket & recvData)
if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()))
return;
- if (player->GetTeamId() != GetPlayer()->GetTeamId())
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED);
- return;
- }
+ if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && player->GetTeamId() != GetPlayer()->GetTeamId())
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED);
+ return;
+ }
if (player->GetArenaTeamId(arenaTeam->GetSlot()))
{
@@ -174,12 +174,12 @@ void WorldSession::HandleArenaTeamAcceptOpcode(WorldPacket & /*recvData*/)
return;
}
- // Only allow members of the other faction to join the team if cross faction interaction is enabled
- if (_player->GetTeamId() != sObjectMgr->GetPlayerTeamIdByGUID(arenaTeam->GetCaptain()))
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_NOT_ALLIED);
- return;
- }
+ // Only allow members of the other faction to join the team if cross faction interaction is enabled
+ if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && _player->GetTeamId() != sObjectMgr->GetPlayerTeamIdByGUID(arenaTeam->GetCaptain()))
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_NOT_ALLIED);
+ return;
+ }
// Add player to team
if (!arenaTeam->AddMember(_player->GetGUID()))
diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp
index e75ac20e08..fcbf36beec 100644
--- a/src/server/game/Handlers/AuctionHouseHandler.cpp
+++ b/src/server/game/Handlers/AuctionHouseHandler.cpp
@@ -265,7 +265,11 @@ void WorldSession::HandleAuctionSellItem(WorldPacket & recvData)
AuctionEntry* AH = new AuctionEntry;
AH->Id = sObjectMgr->GenerateAuctionID();
- AH->auctioneer = GUID_LOPART(auctioneer);
+
+ if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
+ AH->auctioneer = 23442;
+ else
+ AH->auctioneer = GUID_LOPART(auctioneer);
// Required stack size of auction matches to current item stack size, just move item to auctionhouse
if (itemsCount == 1 && item->GetCount() == count[i])
diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp
index b454cbcab8..13637b4d5d 100644
--- a/src/server/game/Handlers/CalendarHandler.cpp
+++ b/src/server/game/Handlers/CalendarHandler.cpp
@@ -462,7 +462,7 @@ void WorldSession::HandleCalendarEventInvite(WorldPacket& recvData)
return;
}
- if (_player->GetTeamId() != inviteeTeamId /*&& !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CALENDAR)*/)
+ if (_player->GetTeamId() != inviteeTeamId && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CALENDAR))
{
sCalendarMgr->SendCalendarCommandResult(playerGuid, CALENDAR_ERROR_NOT_ALLIED);
return;
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 81227d6be5..872cd7df1f 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -468,7 +468,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte
}
}
- bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || true/*sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS)*/ || !AccountMgr::IsPlayerAccount(GetSecurity());
+ bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || !AccountMgr::IsPlayerAccount(GetSecurity());
uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS);
_charCreateCallback.FreeResult();
@@ -492,7 +492,7 @@ void WorldSession::HandleCharCreateCallback(PreparedQueryResult result, Characte
bool haveSameRace = false;
uint32 heroicReqLevel = sWorld->getIntConfig(CONFIG_CHARACTER_CREATING_MIN_LEVEL_FOR_HEROIC_CHARACTER);
bool hasHeroicReqLevel = (heroicReqLevel == 0);
- bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || true/*sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS)*/ || !AccountMgr::IsPlayerAccount(GetSecurity());
+ bool allowTwoSideAccounts = !sWorld->IsPvPRealm() || sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || !AccountMgr::IsPlayerAccount(GetSecurity());
uint32 skipCinematics = sWorld->getIntConfig(CONFIG_SKIP_CINEMATICS);
if (result)
@@ -2327,18 +2327,24 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData)
}
// Reset guild
- if (uint32 guildId = playerData->guildId)
- if (Guild* guild = sGuildMgr->GetGuildById(guildId))
- guild->DeleteMember(MAKE_NEW_GUID(lowGuid, 0, HIGHGUID_PLAYER), false, false, true);
-
- // Delete Friend List
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_GUID);
- stmt->setUInt32(0, lowGuid);
- trans->Append(stmt);
+ if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD))
+ {
+ if (uint32 guildId = playerData->guildId)
+ if (Guild* guild = sGuildMgr->GetGuildById(guildId))
+ guild->DeleteMember(MAKE_NEW_GUID(lowGuid, 0, HIGHGUID_PLAYER), false, false, true);
+ }
- stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_FRIEND);
- stmt->setUInt32(0, lowGuid);
- trans->Append(stmt);
+ if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND))
+ {
+ // Delete Friend List
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_GUID);
+ stmt->setUInt32(0, lowGuid);
+ trans->Append(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_FRIEND);
+ stmt->setUInt32(0, lowGuid);
+ trans->Append(stmt);
+ }
// Leave Arena Teams
Player::LeaveAllArenaTeams(guid);
diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp
index cee25fa435..a9d628601b 100644
--- a/src/server/game/Handlers/ChatHandler.cpp
+++ b/src/server/game/Handlers/ChatHandler.cpp
@@ -165,25 +165,38 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket & recvData)
lang = LANG_UNIVERSAL;
else
{
- switch (type)
- {
- case CHAT_MSG_PARTY:
- case CHAT_MSG_PARTY_LEADER:
- case CHAT_MSG_RAID:
- case CHAT_MSG_RAID_LEADER:
- case CHAT_MSG_RAID_WARNING:
- specialMessageLimit = 35;
- break;
- case CHAT_MSG_GUILD:
- case CHAT_MSG_OFFICER:
- specialMessageLimit = 15;
- break;
- case CHAT_MSG_WHISPER:
- if (sender->getLevel() >= 80)
- specialMessageLimit = 15;
- break;
- }
-
+ // send in universal language in two side iteration allowed mode
+ if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT))
+ lang = LANG_UNIVERSAL;
+ else
+ {
+ switch (type)
+ {
+ case CHAT_MSG_PARTY:
+ case CHAT_MSG_PARTY_LEADER:
+ case CHAT_MSG_RAID:
+ case CHAT_MSG_RAID_LEADER:
+ case CHAT_MSG_RAID_WARNING:
+ // allow two side chat at group channel if two side group allowed
+ if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
+ lang = LANG_UNIVERSAL;
+
+ specialMessageLimit = 35;
+ break;
+ case CHAT_MSG_GUILD:
+ case CHAT_MSG_OFFICER:
+ // allow two side chat at guild channel if two side guild allowed
+ if (sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD))
+ lang = LANG_UNIVERSAL;
+
+ specialMessageLimit = 15;
+ break;
+ case CHAT_MSG_WHISPER:
+ if (sender->getLevel() >= 80)
+ specialMessageLimit = 15;
+ break;
+ }
+ }
// but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used)
Unit::AuraEffectList const& ModLangAuras = sender->GetAuraEffectsByType(SPELL_AURA_MOD_LANGUAGE);
if (!ModLangAuras.empty())
@@ -335,7 +348,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket & recvData)
return;
}
- if (senderIsPlayer && receiverIsPlayer)
+ if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT) && senderIsPlayer && receiverIsPlayer)
if (GetPlayer()->GetTeamId() != receiver->GetTeamId())
{
SendWrongFactionNotice();
diff --git a/src/server/game/Handlers/GroupHandler.cpp b/src/server/game/Handlers/GroupHandler.cpp
index 05ea23060b..b0863fcf7d 100644
--- a/src/server/game/Handlers/GroupHandler.cpp
+++ b/src/server/game/Handlers/GroupHandler.cpp
@@ -97,7 +97,7 @@ void WorldSession::HandleGroupInviteOpcode(WorldPacket& recvData)
}
// can't group with
- if (!GetPlayer()->IsGameMaster() && GetPlayer()->GetTeamId() != player->GetTeamId())
+ if (!GetPlayer()->IsGameMaster() && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && GetPlayer()->GetTeamId() != player->GetTeamId())
{
SendPartyResult(PARTY_OP_INVITE, membername, ERR_PLAYER_WRONG_FACTION);
return;
diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp
index d1f903301f..9fe0b5ea19 100644
--- a/src/server/game/Handlers/ItemHandler.cpp
+++ b/src/server/game/Handlers/ItemHandler.cpp
@@ -724,7 +724,7 @@ void WorldSession::HandleListInventoryOpcode(WorldPacket & recvData)
SendListInventory(guid);
}
-void WorldSession::SendListInventory(uint64 vendorGuid)
+void WorldSession::SendListInventory(uint64 vendorGuid, uint32 vendorEntry)
{
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Sent SMSG_LIST_INVENTORY");
@@ -744,7 +744,9 @@ void WorldSession::SendListInventory(uint64 vendorGuid)
if (vendor->HasUnitState(UNIT_STATE_MOVING))
vendor->StopMoving();
- VendorItemData const* items = vendor->GetVendorItems();
+ SetCurrentVendor(vendorEntry);
+
+ VendorItemData const* items = vendorEntry ? sObjectMgr->GetNpcVendorItemList(vendorEntry) : vendor->GetVendorItems();
if (!items)
{
WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + 1);
diff --git a/src/server/game/Handlers/MailHandler.cpp b/src/server/game/Handlers/MailHandler.cpp
index 63d30598c0..3e5e04e56d 100644
--- a/src/server/game/Handlers/MailHandler.cpp
+++ b/src/server/game/Handlers/MailHandler.cpp
@@ -189,7 +189,7 @@ void WorldSession::HandleSendMail(WorldPacket & recvData)
? receive->GetSession()->GetAccountId()
: sObjectMgr->GetPlayerAccountIdByGUID(rc);
- if (/*!accountBound*/ GetAccountId() != rc_account && player->GetTeamId() != rc_teamId && AccountMgr::IsPlayerAccount(GetSecurity()))
+ if (/*!accountBound*/ GetAccountId() != rc_account && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL) && player->GetTeamId() != rc_teamId && AccountMgr::IsPlayerAccount(GetSecurity()))
{
player->SendMailResult(0, MAIL_SEND, MAIL_ERR_NOT_YOUR_TEAM);
return;
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index 922afa328a..cd0a585d9a 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -170,193 +170,205 @@ void WorldSession::HandleGossipSelectOptionOpcode(WorldPacket & recv_data)
}
}
-void WorldSession::HandleWhoOpcode(WorldPacket & recv_data)
-{
- ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_WHO Message");
-
- time_t now = time(NULL);
- if (now < timeWhoCommandAllowed)
- return;
- timeWhoCommandAllowed = now+3;
-
- uint32 matchcount = 0;
- uint32 level_min, level_max, racemask, classmask, zones_count, str_count;
- uint32 zoneids[10]; // 10 is client limit
- std::string player_name, guild_name;
-
- recv_data >> level_min; // maximal player level, default 0
- recv_data >> level_max; // minimal player level, default 100 (MAX_LEVEL)
- recv_data >> player_name; // player name, case sensitive...
-
- recv_data >> guild_name; // guild name, case sensitive...
+void WorldSession::HandleWhoOpcode(WorldPacket& recvData)
+{
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_WHO Message");
- recv_data >> racemask; // race mask
- recv_data >> classmask; // class mask
- recv_data >> zones_count; // zones count, client limit = 10 (2.0.10)
+ time_t now = time(NULL);
+ if (now < timeWhoCommandAllowed)
+ return;
+ timeWhoCommandAllowed = now + 3;
- if (zones_count > 10)
- return; // can't be received from real client or broken packet
+ uint32 matchcount = 0;
- for (uint32 i = 0; i < zones_count; ++i)
- {
- uint32 temp;
- recv_data >> temp; // zone id, 0 if zone is unknown...
- zoneids[i] = temp;
- ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "Zone %u: %u", i, zoneids[i]);
- }
+ uint32 level_min, level_max, racemask, classmask, zones_count, str_count;
+ uint32 zoneids[10]; // 10 is client limit
+ std::string player_name, guild_name;
- recv_data >> str_count; // user entered strings count, client limit=4 (checked on 2.0.10)
+ recvData >> level_min; // maximal player level, default 0
+ recvData >> level_max; // minimal player level, default 100 (MAX_LEVEL)
+ recvData >> player_name; // player name, case sensitive...
- if (str_count > 4)
- return; // can't be received from real client or broken packet
+ recvData >> guild_name; // guild name, case sensitive...
- ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "Minlvl %u, maxlvl %u, name %s, guild %s, racemask %u, classmask %u, zones %u, strings %u", level_min, level_max, player_name.c_str(), guild_name.c_str(), racemask, classmask, zones_count, str_count);
+ recvData >> racemask; // race mask
+ recvData >> classmask; // class mask
+ recvData >> zones_count; // zones count, client limit = 10 (2.0.10)
- std::wstring str[4]; // 4 is client limit
- for (uint32 i = 0; i < str_count; ++i)
- {
- std::string temp;
- recv_data >> temp; // user entered string, it used as universal search pattern(guild+player name)?
+ if (zones_count > 10)
+ return; // can't be received from real client or broken packet
- if (!Utf8toWStr(temp, str[i]))
- continue;
+ for (uint32 i = 0; i < zones_count; ++i)
+ {
+ uint32 temp;
+ recvData >> temp; // zone id, 0 if zone is unknown...
+ zoneids[i] = temp;
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "Zone %u: %u", i, zoneids[i]);
+ }
- wstrToLower(str[i]);
+ recvData >> str_count; // user entered strings count, client limit=4 (checked on 2.0.10)
- ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "String %u: %s", i, temp.c_str());
- }
+ if (str_count > 4)
+ return; // can't be received from real client or broken packet
- std::wstring wplayer_name;
- std::wstring wguild_name;
- if (!(Utf8toWStr(player_name, wplayer_name) && Utf8toWStr(guild_name, wguild_name)))
- return;
- wstrToLower(wplayer_name);
- wstrToLower(wguild_name);
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "Minlvl %u, maxlvl %u, name %s, guild %s, racemask %u, classmask %u, zones %u, strings %u", level_min, level_max, player_name.c_str(), guild_name.c_str(), racemask, classmask, zones_count, str_count);
- // client send in case not set max level value 100 but Trinity supports 255 max level,
- // update it to show GMs with characters after 100 level
- if (level_max >= MAX_LEVEL)
- level_max = STRONG_MAX_LEVEL;
+ std::wstring str[4]; // 4 is client limit
+ for (uint32 i = 0; i < str_count; ++i)
+ {
+ std::string temp;
+ recvData >> temp; // user entered string, it used as universal search pattern(guild+player name)?
- TeamId teamId = _player->GetTeamId();
- uint32 security = GetSecurity();
- uint32 gmLevelInWhoList = sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST);
- uint32 displaycount = 0;
+ if (!Utf8toWStr(temp, str[i]))
+ continue;
- WorldPacket data(SMSG_WHO, 500); // guess size
- data << uint32(matchcount); // placeholder, count of players matching criteria
- data << uint32(displaycount); // placeholder, count of players displayed
+ wstrToLower(str[i]);
- std::vector<WhoListPlayerInfo> * m = WhoListCacheMgr::GetWhoList();
- for (std::vector<WhoListPlayerInfo>::const_iterator itr = m->begin(); itr != m->end(); ++itr)
- {
- if (AccountMgr::IsPlayerAccount(security))
- {
- if ((*itr).teamId != teamId)
- continue;
+ sLog->outDebug(LOG_FILTER_NETWORKIO, "String %u: %s", i, temp.c_str());
+ }
- // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST
- //if ((*itr).security > AccountTypes(gmLevelInWhoList))
- // continue;
- }
+ std::wstring wplayer_name;
+ std::wstring wguild_name;
+ if (!(Utf8toWStr(player_name, wplayer_name) && Utf8toWStr(guild_name, wguild_name)))
+ return;
+ wstrToLower(wplayer_name);
+ wstrToLower(wguild_name);
+
+ // client send in case not set max level value 100 but Trinity supports 255 max level,
+ // update it to show GMs with characters after 100 level
+ if (level_max >= MAX_LEVEL)
+ level_max = STRONG_MAX_LEVEL;
+
+ uint32 team = _player->GetTeamId();
+ uint32 security = GetSecurity();
+ bool allowTwoSideWhoList = sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
+ uint32 gmLevelInWhoList = sWorld->getIntConfig(CONFIG_GM_LEVEL_IN_WHO_LIST);
+ uint32 displaycount = 0;
+
+ WorldPacket data(SMSG_WHO, 50); // guess size
+ data << uint32(matchcount); // placeholder, count of players matching criteria
+ data << uint32(displaycount); // placeholder, count of players displayed
+
+ TRINITY_READ_GUARD(HashMapHolder<Player>::LockType, *HashMapHolder<Player>::GetLock());
+ HashMapHolder<Player>::MapType const& m = sObjectAccessor->GetPlayers();
+ for (HashMapHolder<Player>::MapType::const_iterator itr = m.begin(); itr != m.end(); ++itr)
+ {
+ if (AccountMgr::IsPlayerAccount(security))
+ {
+ // player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST
+ if (itr->second->GetTeamId() != team && !allowTwoSideWhoList)
+ continue;
- //do not process players which are not in world
- //if (!(itr->second->IsInWorld()))
- // continue;
+ // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST
+ if ((itr->second->GetSession()->GetSecurity() > AccountTypes(gmLevelInWhoList)))
+ continue;
+ }
- // check if target is globally visible for player
- //if (!(itr->second->IsVisibleGloballyFor(_player)))
- // continue;
+ //do not process players which are not in world
+ if (!(itr->second->IsInWorld()))
+ continue;
- // check if target's level is in level range
- uint8 lvl = (*itr).level;
- if (lvl < level_min || lvl > level_max)
- continue;
+ // check if target is globally visible for player
+ if (!(itr->second->IsVisibleGloballyFor(_player)))
+ continue;
- // check if class matches classmask
- uint32 class_ = (*itr).clas;
- if (!(classmask & (1 << class_)))
- continue;
+ // check if target's level is in level range
+ uint8 lvl = itr->second->getLevel();
+ if (lvl < level_min || lvl > level_max)
+ continue;
- // check if race matches racemask
- uint32 race = (*itr).race;
- if (!(racemask & (1 << race)))
- continue;
+ // check if class matches classmask
+ uint32 class_ = itr->second->getClass();
+ if (!(classmask & (1 << class_)))
+ continue;
- uint32 pzoneid = (*itr).zoneid;
- uint8 gender = (*itr).gender;
+ // check if race matches racemask
+ uint32 race = itr->second->getRace();
+ if (!(racemask & (1 << race)))
+ continue;
- bool z_show = true;
- for (uint32 i = 0; i < zones_count; ++i)
- {
- if (zoneids[i] == pzoneid)
- {
- z_show = true;
- break;
- }
+ uint32 pzoneid = itr->second->GetZoneId();
+ uint8 gender = itr->second->getGender();
- z_show = false;
- }
- if (!z_show)
- continue;
+ bool z_show = true;
+ for (uint32 i = 0; i < zones_count; ++i)
+ {
+ if (zoneids[i] == pzoneid)
+ {
+ z_show = true;
+ break;
+ }
- std::wstring wpname = (*itr).wpname;
+ z_show = false;
+ }
+ if (!z_show)
+ continue;
- if (!(wplayer_name.empty() || wpname.find(wplayer_name) != std::wstring::npos))
- continue;
+ std::string pname = itr->second->GetName();
+ std::wstring wpname;
+ if (!Utf8toWStr(pname, wpname))
+ continue;
+ wstrToLower(wpname);
- std::wstring wgname = (*itr).wgname;
+ if (!(wplayer_name.empty() || wpname.find(wplayer_name) != std::wstring::npos))
+ continue;
- if (!(wguild_name.empty() || wgname.find(wguild_name) != std::wstring::npos))
- continue;
+ std::string gname = sGuildMgr->GetGuildNameById(itr->second->GetGuildId());
+ std::wstring wgname;
+ if (!Utf8toWStr(gname, wgname))
+ continue;
+ wstrToLower(wgname);
- std::string aname = (*itr).aname;
+ if (!(wguild_name.empty() || wgname.find(wguild_name) != std::wstring::npos))
+ continue;
- bool s_show = true;
- for (uint32 i = 0; i < str_count; ++i)
- {
- if (!str[i].empty())
- {
- if (wgname.find(str[i]) != std::wstring::npos ||
- wpname.find(str[i]) != std::wstring::npos ||
- Utf8FitTo(aname, str[i]))
- {
- s_show = true;
- break;
- }
- s_show = false;
- }
- }
- if (!s_show)
- continue;
+ std::string aname;
+ if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId()))
+ aname = areaEntry->area_name[GetSessionDbcLocale()];
- // 50 is maximum player count sent to client
- if (matchcount >= 50)
+ bool s_show = true;
+ for (uint32 i = 0; i < str_count; ++i)
{
- ++matchcount;
- continue;
+ if (!str[i].empty())
+ {
+ if (wgname.find(str[i]) != std::wstring::npos ||
+ wpname.find(str[i]) != std::wstring::npos ||
+ Utf8FitTo(aname, str[i]))
+ {
+ s_show = true;
+ break;
+ }
+ s_show = false;
+ }
}
+ if (!s_show)
+ continue;
- data << (*itr).pname; // player name
- data << (*itr).gname; // guild name
- data << uint32(lvl); // player level
- data << uint32(class_); // player class
- data << uint32(race); // player race
- data << uint8(gender); // player gender
- data << uint32(pzoneid); // player zone id
+ // 49 is maximum player count sent to client - can be overridden
+ // through config, but is unstable
+ if ((matchcount++) >= 50 /*sWorld->getIntConfig(CONFIG_MAX_WHO)*/)
+ continue;
- ++matchcount;
- ++displaycount;
- }
+ data << pname; // player name
+ data << gname; // guild name
+ data << uint32(lvl); // player level
+ data << uint32(class_); // player class
+ data << uint32(race); // player race
+ data << uint8(gender); // player gender
+ data << uint32(pzoneid); // player zone id
- data.put(0, displaycount); // insert right count, count displayed
- data.put(4, matchcount); // insert right count, count of matches
+ ++displaycount;
+ }
- SendPacket(&data);
- ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Send SMSG_WHO Message");
+ data.put(0, displaycount); // insert right count, count displayed
+ data.put(4, matchcount); // insert right count, count of matches
+
+ SendPacket(&data);
+ ;// sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Send SMSG_WHO Message");
}
+
void WorldSession::HandleLogoutRequestOpcode(WorldPacket & /*recv_data*/)
{
;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_LOGOUT_REQUEST Message, security - %u", GetSecurity());
@@ -532,7 +544,7 @@ void WorldSession::HandleAddFriendOpcode(WorldPacket & recv_data)
{
if (friendGuid == GetPlayer()->GetGUID())
friendResult = FRIEND_SELF;
- else if (GetPlayer()->GetTeamId() != teamId && AccountMgr::IsPlayerAccount(GetSecurity()))
+ else if (GetPlayer()->GetTeamId() != teamId && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && AccountMgr::IsPlayerAccount(GetSecurity()))
friendResult = FRIEND_ENEMY;
else if (GetPlayer()->GetSocial()->HasFriend(guidLow))
friendResult = FRIEND_ALREADY;
diff --git a/src/server/game/Handlers/PetitionsHandler.cpp b/src/server/game/Handlers/PetitionsHandler.cpp
index f9a136a780..0640d58ee5 100644
--- a/src/server/game/Handlers/PetitionsHandler.cpp
+++ b/src/server/game/Handlers/PetitionsHandler.cpp
@@ -435,7 +435,7 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket & recvData)
return;
// not let enemies sign guild charter
- if (GetPlayer()->GetTeamId() != sObjectMgr->GetPlayerTeamIdByGUID(ownerGuid))
+ if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeamId() != sObjectMgr->GetPlayerTeamIdByGUID(ownerGuid))
{
if (type != GUILD_CHARTER_TYPE)
SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED);
diff --git a/src/server/game/Handlers/TradeHandler.cpp b/src/server/game/Handlers/TradeHandler.cpp
index 1aa78e17d4..f043ccfa8c 100644
--- a/src/server/game/Handlers/TradeHandler.cpp
+++ b/src/server/game/Handlers/TradeHandler.cpp
@@ -618,11 +618,11 @@ void WorldSession::HandleInitiateTradeOpcode(WorldPacket& recvPacket)
return;
}
- if (pOther->GetTeamId() !=_player->GetTeamId())
- {
- SendTradeStatus(TRADE_STATUS_WRONG_FACTION);
- return;
- }
+ if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_TRADE) && pOther->GetTeamId() != _player->GetTeamId())
+ {
+ SendTradeStatus(TRADE_STATUS_WRONG_FACTION);
+ return;
+ }
if (!pOther->IsWithinDistInMap(_player, 10.0f, false))
{
diff --git a/src/server/game/Handlers/VehicleHandler.cpp b/src/server/game/Handlers/VehicleHandler.cpp
index 86cf595053..7bedfa63f1 100644
--- a/src/server/game/Handlers/VehicleHandler.cpp
+++ b/src/server/game/Handlers/VehicleHandler.cpp
@@ -222,7 +222,7 @@ void WorldSession::HandleEjectPassenger(WorldPacket &data)
sLog->outError("Player %u attempted to eject creature GUID %u from non-ejectable seat.", GetPlayer()->GetGUIDLow(), GUID_LOPART(guid));
}
else
- sLog->outError("HandleEjectPassenger: Player %u tried to eject invalid GUID " UI64FMTD, GetPlayer()->GetGUIDLow(), guid);
+ sLog->outError("HandleEjectPassenger: Player %u tried to eject invalid GUID "UI64FMTD, GetPlayer()->GetGUIDLow(), guid);
}
void WorldSession::HandleRequestVehicleExit(WorldPacket& /*recvData*/)
diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h
index aad9e17332..f2949ec157 100644
--- a/src/server/game/Instances/InstanceScript.h
+++ b/src/server/game/Instances/InstanceScript.h
@@ -192,6 +192,9 @@ class InstanceScript : public ZoneScript
// Cast spell on all players in instance
void DoCastSpellOnPlayers(uint32 spell);
+ // Return wether server allow two side groups or not
+ bool ServerAllowsTwoSideGroups() { return sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP); }
+
virtual bool SetBossState(uint32 id, EncounterState state);
EncounterState GetBossState(uint32 id) const { return id < bosses.size() ? bosses[id].state : TO_BE_DECIDED; }
BossBoundaryMap const* GetBossBoundary(uint32 id) const { return id < bosses.size() ? &bosses[id].boundary : NULL; }
diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp
index 7de5d1e38a..760059bfc6 100644
--- a/src/server/game/Server/WorldSession.cpp
+++ b/src/server/game/Server/WorldSession.cpp
@@ -101,7 +101,7 @@ m_inQueue(false), m_playerLoading(false), m_playerLogout(false), m_playerSave(fa
m_sessionDbcLocale(sWorld->GetDefaultDbcLocale()),
m_sessionDbLocaleIndex(locale),
m_latency(0), m_clientTimeDelay(0), m_TutorialsChanged(false), recruiterId(recruiter),
-isRecruiter(isARecruiter), m_currentBankerGUID(0), timeWhoCommandAllowed(0), _lastAuctionListItemsMSTime(0), _lastAuctionListOwnerItemsMSTime(0), _skipQueue(skipQueue)
+isRecruiter(isARecruiter), m_currentVendorEntry(0), m_currentBankerGUID(0), timeWhoCommandAllowed(0), _lastAuctionListItemsMSTime(0), _lastAuctionListOwnerItemsMSTime(0), _skipQueue(skipQueue)
{
memset(m_Tutorials, 0, sizeof(m_Tutorials));
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 09c337e495..34b921f0d3 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -228,6 +228,9 @@ class WorldSession
Player* GetPlayer() const { return _player; }
std::string const& GetPlayerName() const;
std::string GetPlayerInfo() const;
+
+ uint32 GetCurrentVendor() const { return m_currentVendorEntry; }
+ void SetCurrentVendor(uint32 vendorEntry) { m_currentVendorEntry = vendorEntry; }
uint32 GetGuidLow() const;
void SetSecurity(AccountTypes security) { _security = security; }
@@ -269,7 +272,7 @@ class WorldSession
void SendTrainerList(uint64 guid);
void SendTrainerList(uint64 guid, std::string const& strTitle);
- void SendListInventory(uint64 guid);
+ void SendListInventory(uint64 guid, uint32 vendorEntry = 0);
void SendShowBank(uint64 guid);
bool CanOpenMailBox(uint64 guid);
void SendShowMailBox(uint64 guid);
@@ -998,6 +1001,7 @@ class WorldSession
uint32 recruiterId;
bool isRecruiter;
ACE_Based::LockedQueue<WorldPacket*, ACE_Thread_Mutex> _recvQueue;
+ uint32 m_currentVendorEntry;
uint64 m_currentBankerGUID;
time_t timeWhoCommandAllowed;
uint32 _offlineTime;
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index ccfbd1bd80..ad09aca587 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -6139,7 +6139,7 @@ SpellCastResult Spell::CheckCasterAuras(bool preventionOnly) const
if (usableInStun)
{
bool foundNotStun = false;
- uint32 mask = 1<<MECHANIC_STUN;
+ uint32 mask = (1 << MECHANIC_STUN) | (1 << MECHANIC_FREEZE) | (1 << MECHANIC_HORROR);
// Barkskin should skip sleep effects, sap and fears
if (m_spellInfo->Id == 22812)
mask |= 1<<MECHANIC_SAPPED | 1<<MECHANIC_HORROR | 1<<MECHANIC_SLEEP;
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 688380d276..6b5781249b 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -680,7 +680,19 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_STRICT_CHARTER_NAMES] = sConfigMgr->GetIntDefault ("StrictCharterNames", 0);
m_int_configs[CONFIG_STRICT_CHANNEL_NAMES] = sConfigMgr->GetIntDefault ("StrictChannelNames", 0);
m_int_configs[CONFIG_STRICT_PET_NAMES] = sConfigMgr->GetIntDefault ("StrictPetNames", 0);
-
+
+ m_bool_configs[CONFIG_ALLOW_TWO_SIDE_ACCOUNTS] = sConfigMgr->GetBoolDefault("AllowTwoSide.Accounts", true);
+ m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CALENDAR]= sConfigMgr->GetBoolDefault("AllowTwoSide.Interaction.Calendar", false);
+ m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT] = sConfigMgr->GetBoolDefault("AllowTwoSide.Interaction.Chat", false);
+ m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL] = sConfigMgr->GetBoolDefault("AllowTwoSide.Interaction.Channel", false);
+ m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP] = sConfigMgr->GetBoolDefault("AllowTwoSide.Interaction.Group", false);
+ m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD] = sConfigMgr->GetBoolDefault("AllowTwoSide.Interaction.Guild", false);
+ m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION] = sConfigMgr->GetBoolDefault("AllowTwoSide.Interaction.Auction", false);
+ m_bool_configs[CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL] = sConfigMgr->GetBoolDefault("AllowTwoSide.Interaction.Mail", false);
+ m_bool_configs[CONFIG_ALLOW_TWO_SIDE_WHO_LIST] = sConfigMgr->GetBoolDefault("AllowTwoSide.WhoList", false);
+ m_bool_configs[CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND] = sConfigMgr->GetBoolDefault("AllowTwoSide.AddFriend", false);
+ m_bool_configs[CONFIG_ALLOW_TWO_SIDE_TRADE] = sConfigMgr->GetBoolDefault("AllowTwoSide.trade", false);
+
m_int_configs[CONFIG_MIN_PLAYER_NAME] = sConfigMgr->GetIntDefault ("MinPlayerName", 2);
if (m_int_configs[CONFIG_MIN_PLAYER_NAME] < 1 || m_int_configs[CONFIG_MIN_PLAYER_NAME] > MAX_PLAYER_NAME)
{
@@ -1664,6 +1676,10 @@ void World::SetInitialWorldSettings()
///- Handle outdated emails (delete/return)
sLog->outString("Returning old mails...");
sObjectMgr->ReturnOrDeleteOldMails(false);
+
+ ///- Load AutoBroadCast
+ sLog->outString("Loading Autobroadcasts...");
+ LoadAutobroadcasts();
///- Load and initialize scripts
sObjectMgr->LoadSpellScripts(); // must be after load Creature/Gameobject(Template/Data)
@@ -1842,6 +1858,40 @@ void World::DetectDBCLang()
sLog->outString();
}
+void World::LoadAutobroadcasts()
+{
+ uint32 oldMSTime = getMSTime();
+
+ m_Autobroadcasts.clear();
+ m_AutobroadcastsWeights.clear();
+
+ uint32 realmId = sConfigMgr->GetIntDefault("RealmID", 0);
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_AUTOBROADCAST);
+ stmt->setInt32(0, realmId);
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ if (!result)
+ {
+ sLog->outString(">> Loaded 0 autobroadcasts definitions. DB table `autobroadcast` is empty for this realm!");
+ return;
+ }
+
+ uint32 count = 0;
+
+ do
+ {
+ Field* fields = result->Fetch();
+ uint8 id = fields[0].GetUInt8();
+
+ m_Autobroadcasts[id] = fields[2].GetString();
+ m_AutobroadcastsWeights[id] = fields[1].GetUInt8();
+
+ ++count;
+ } while (result->NextRow());
+
+ sLog->outString(">> Loaded %u autobroadcast definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
+}
+
/// Update the World !
void World::Update(uint32 diff)
{
@@ -2579,10 +2629,37 @@ void World::SendAutoBroadcast()
{
if (m_Autobroadcasts.empty())
return;
+
+ uint32 weight = 0;
+ AutobroadcastsWeightMap selectionWeights;
std::string msg;
- msg = Trinity::Containers::SelectRandomContainerElement(m_Autobroadcasts);
+ for (AutobroadcastsWeightMap::const_iterator it = m_AutobroadcastsWeights.begin(); it != m_AutobroadcastsWeights.end(); ++it)
+ {
+ if (it->second)
+ {
+ weight += it->second;
+ selectionWeights[it->first] = it->second;
+ }
+ }
+
+ if (weight)
+ {
+ uint32 selectedWeight = urand(0, weight - 1);
+ weight = 0;
+ for (AutobroadcastsWeightMap::const_iterator it = selectionWeights.begin(); it != selectionWeights.end(); ++it)
+ {
+ weight += it->second;
+ if (selectedWeight < weight)
+ {
+ msg = m_Autobroadcasts[it->first];
+ break;
+ }
+ }
+ }
+ else
+ msg = m_Autobroadcasts[urand(0, m_Autobroadcasts.size())];
uint32 abcenter = sWorld->getIntConfig(CONFIG_AUTOBROADCAST_CENTER);
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index b9a5aaeca7..d5a052fe42 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -90,6 +90,17 @@ enum WorldBoolConfigs
CONFIG_ALLOW_PLAYER_COMMANDS,
CONFIG_CLEAN_CHARACTER_DB,
CONFIG_STATS_SAVE_ONLY_ON_LOGOUT,
+ CONFIG_ALLOW_TWO_SIDE_ACCOUNTS,
+ CONFIG_ALLOW_TWO_SIDE_INTERACTION_CALENDAR,
+ CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT,
+ CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHANNEL,
+ CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP,
+ CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD,
+ CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION,
+ CONFIG_ALLOW_TWO_SIDE_INTERACTION_MAIL,
+ CONFIG_ALLOW_TWO_SIDE_WHO_LIST,
+ CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND,
+ CONFIG_ALLOW_TWO_SIDE_TRADE,
CONFIG_ALL_TAXI_PATHS,
CONFIG_INSTANT_TAXI,
CONFIG_INSTANCE_IGNORE_LEVEL,
@@ -741,6 +752,8 @@ class World
void LoadDBVersion();
char const* GetDBVersion() const { return m_DBVersion.c_str(); }
+ void LoadAutobroadcasts();
+
void UpdateAreaDependentAuras();
uint32 GetCleaningFlags() const { return m_CleaningFlags; }
@@ -841,7 +854,11 @@ class World
// used versions
std::string m_DBVersion;
- std::list<std::string> m_Autobroadcasts;
+ typedef std::map<uint8, std::string> AutobroadcastsMap;
+ AutobroadcastsMap m_Autobroadcasts;
+
+ typedef std::map<uint8, uint8> AutobroadcastsWeightMap;
+ AutobroadcastsWeightMap m_AutobroadcastsWeights;
void ProcessQueryCallbacks();
ACE_Future_Set<PreparedQueryResult> m_realmCharCallbacks;
diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp
index 86175ca6f4..0fd076021a 100644
--- a/src/server/scripts/Commands/cs_account.cpp
+++ b/src/server/scripts/Commands/cs_account.cpp
@@ -1,19 +1,19 @@
/*
- * Copyright (C)
- *
- * 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/>.
- */
+* Copyright (C) 2008-2012 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: account_commandscript
@@ -22,36 +22,581 @@ Comment: All account related commands
Category: commandscripts
EndScriptData */
+#include "ScriptMgr.h"
#include "AccountMgr.h"
#include "Chat.h"
#include "Language.h"
-#include "Player.h"
-#include "ScriptMgr.h"
class account_commandscript : public CommandScript
{
public:
- account_commandscript() : CommandScript("account_commandscript") { }
-
- ChatCommand* GetCommands() const
- {
- static ChatCommand commandTable[] =
- {
- { "account", SEC_PLAYER, false, &HandleAccountCommand, "", NULL },
- { NULL, 0, false, NULL, "", NULL }
- };
- return commandTable;
- }
-
- static bool HandleAccountCommand(ChatHandler* handler, char const* /*args*/)
- {
- AccountTypes gmLevel = handler->GetSession()->GetSecurity();
- handler->PSendSysMessage(LANG_ACCOUNT_LEVEL, uint32(gmLevel));
- return true;
- }
+ account_commandscript() : CommandScript("account_commandscript") { }
+
+ ChatCommand* GetCommands() const
+ {
+ static ChatCommand accountSetCommandTable[] =
+ {
+ { "addon", SEC_ADMINISTRATOR, true, &HandleAccountSetAddonCommand, "", NULL },
+ { "gmlevel", SEC_CONSOLE, true, &HandleAccountSetGmLevelCommand, "", NULL },
+ { "password", SEC_CONSOLE, true, &HandleAccountSetPasswordCommand, "", NULL },
+ { NULL, SEC_PLAYER, false, NULL, "", NULL }
+ };
+ static ChatCommand accountCommandTable[] =
+ {
+ { "addon", SEC_MODERATOR, false, &HandleAccountAddonCommand, "", NULL },
+ { "create", SEC_CONSOLE, true, &HandleAccountCreateCommand, "", NULL },
+ { "delete", SEC_CONSOLE, true, &HandleAccountDeleteCommand, "", NULL },
+ { "onlinelist", SEC_CONSOLE, true, &HandleAccountOnlineListCommand, "", NULL },
+ { "lock", SEC_PLAYER, false, &HandleAccountLockCommand, "", NULL },
+ { "set", SEC_ADMINISTRATOR, true, NULL, "", accountSetCommandTable },
+ { "password", SEC_PLAYER, false, &HandleAccountPasswordCommand, "", NULL },
+ { "", SEC_PLAYER, false, &HandleAccountCommand, "", NULL },
+ { NULL, SEC_PLAYER, false, NULL, "", NULL }
+ };
+ static ChatCommand commandTable[] =
+ {
+ { "account", SEC_PLAYER, true, NULL, "", accountCommandTable },
+ { NULL, SEC_PLAYER, false, NULL, "", NULL }
+ };
+ return commandTable;
+ }
+
+ static bool HandleAccountAddonCommand(ChatHandler* handler, char const* args)
+ {
+ if (!*args)
+ {
+ handler->SendSysMessage(LANG_CMD_SYNTAX);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ char* exp = strtok((char*)args, " ");
+
+ uint32 accountId = handler->GetSession()->GetAccountId();
+
+ int expansion = atoi(exp); //get int anyway (0 if error)
+ if (expansion < 0 || uint8(expansion) > sWorld->getIntConfig(CONFIG_EXPANSION))
+ {
+ handler->SendSysMessage(LANG_IMPROPER_VALUE);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPANSION);
+
+ stmt->setUInt8(0, uint8(expansion));
+ stmt->setUInt32(1, accountId);
+
+ LoginDatabase.Execute(stmt);
+
+ handler->PSendSysMessage(LANG_ACCOUNT_ADDON, expansion);
+ return true;
+ }
+
+ /// Create an account
+ static bool HandleAccountCreateCommand(ChatHandler* handler, char const* args)
+ {
+ if (!*args)
+ return false;
+
+ ///- %Parse the command line arguments
+ char* accountName = strtok((char*)args, " ");
+ char* password = strtok(NULL, " ");
+ if (!accountName || !password)
+ return false;
+
+ AccountOpResult result = AccountMgr::CreateAccount(std::string(accountName), std::string(password));
+ switch (result)
+ {
+ case AOR_OK:
+ handler->PSendSysMessage(LANG_ACCOUNT_CREATED, accountName);
+ if (handler->GetSession())
+ {
+ sLog->outDebug(LOG_FILTER_WARDEN, "Account: %d (IP: %s) Character:[%s] (GUID: %u) Change Password.",
+ handler->GetSession()->GetAccountId(), handler->GetSession()->GetRemoteAddress().c_str(),
+ handler->GetSession()->GetPlayer()->GetName().c_str(), handler->GetSession()->GetPlayer()->GetGUIDLow());
+ }
+ break;
+ case AOR_NAME_TOO_LONG:
+ handler->SendSysMessage(LANG_ACCOUNT_TOO_LONG);
+ handler->SetSentErrorMessage(true);
+ return false;
+ case AOR_NAME_ALREDY_EXIST:
+ handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST);
+ handler->SetSentErrorMessage(true);
+ return false;
+ case AOR_DB_INTERNAL_ERROR:
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED_SQL_ERROR, accountName);
+ handler->SetSentErrorMessage(true);
+ return false;
+ default:
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_CREATED, accountName);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ return true;
+ }
+
+ /// Delete a user account and all associated characters in this realm
+ /// \todo This function has to be enhanced to respect the login/realm split (delete char, delete account chars in realm then delete account)
+ static bool HandleAccountDeleteCommand(ChatHandler* handler, char const* args)
+ {
+ if (!*args)
+ return false;
+
+ ///- Get the account name from the command line
+ char* account = strtok((char*)args, " ");
+ if (!account)
+ return false;
+
+ std::string accountName = account;
+ if (!AccountMgr::normalizeString(accountName))
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 accountId = AccountMgr::GetId(accountName);
+ if (!accountId)
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ /// Commands not recommended call from chat, but support anyway
+ /// can delete only for account with less security
+ /// This is also reject self apply in fact
+ if (handler->HasLowerSecurityAccount(NULL, accountId, true))
+ return false;
+
+ AccountOpResult result = AccountMgr::DeleteAccount(accountId);
+ switch (result)
+ {
+ case AOR_OK:
+ handler->PSendSysMessage(LANG_ACCOUNT_DELETED, accountName.c_str());
+ break;
+ case AOR_NAME_NOT_EXIST:
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ case AOR_DB_INTERNAL_ERROR:
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_DELETED_SQL_ERROR, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ default:
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_DELETED, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ return true;
+ }
+
+ /// Display info on users currently in the realm
+ static bool HandleAccountOnlineListCommand(ChatHandler* handler, char const* /*args*/)
+ {
+ ///- Get the list of accounts ID logged to the realm
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ONLINE);
+
+ PreparedQueryResult result = CharacterDatabase.Query(stmt);
+
+ if (!result)
+ {
+ handler->SendSysMessage(LANG_ACCOUNT_LIST_EMPTY);
+ return true;
+ }
+
+ ///- Display the list of account/characters online
+ handler->SendSysMessage(LANG_ACCOUNT_LIST_BAR_HEADER);
+ handler->SendSysMessage(LANG_ACCOUNT_LIST_HEADER);
+ handler->SendSysMessage(LANG_ACCOUNT_LIST_BAR);
+
+ ///- Cycle through accounts
+ do
+ {
+ Field* fieldsDB = result->Fetch();
+ std::string name = fieldsDB[0].GetString();
+ uint32 account = fieldsDB[1].GetUInt32();
+
+ ///- Get the username, last IP and GM level of each account
+ // No SQL injection. account is uint32.
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_INFO);
+ stmt->setUInt32(0, account);
+ PreparedQueryResult resultLogin = LoginDatabase.Query(stmt);
+
+ if (resultLogin)
+ {
+ Field* fieldsLogin = resultLogin->Fetch();
+ handler->PSendSysMessage(LANG_ACCOUNT_LIST_LINE,
+ fieldsLogin[0].GetCString(), name.c_str(), fieldsLogin[1].GetCString(),
+ fieldsDB[2].GetUInt16(), fieldsDB[3].GetUInt16(), fieldsLogin[3].GetUInt8(),
+ fieldsLogin[2].GetUInt8());
+ }
+ else
+ handler->PSendSysMessage(LANG_ACCOUNT_LIST_ERROR, name.c_str());
+ } while (result->NextRow());
+
+ handler->SendSysMessage(LANG_ACCOUNT_LIST_BAR);
+ return true;
+ }
+
+ static bool HandleAccountLockCommand(ChatHandler* handler, char const* args)
+ {
+ if (!*args)
+ {
+ handler->SendSysMessage(LANG_USE_BOL);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ std::string param = (char*)args;
+
+ if (!param.empty())
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_LOCK);
+
+ if (param == "on")
+ {
+ stmt->setBool(0, true); // locked
+ handler->PSendSysMessage(LANG_COMMAND_ACCLOCKLOCKED);
+ }
+ else if (param == "off")
+ {
+ stmt->setBool(0, false); // unlocked
+ handler->PSendSysMessage(LANG_COMMAND_ACCLOCKUNLOCKED);
+ }
+
+ stmt->setUInt32(1, handler->GetSession()->GetAccountId());
+
+ LoginDatabase.Execute(stmt);
+ return true;
+ }
+
+ handler->SendSysMessage(LANG_USE_BOL);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ static bool HandleAccountPasswordCommand(ChatHandler* handler, char const* args)
+ {
+ if (!*args)
+ {
+ handler->SendSysMessage(LANG_CMD_SYNTAX);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ char* oldPassword = strtok((char*)args, " ");
+ char* newPassword = strtok(NULL, " ");
+ char* passwordConfirmation = strtok(NULL, " ");
+
+ if (!oldPassword || !newPassword || !passwordConfirmation)
+ {
+ handler->SendSysMessage(LANG_CMD_SYNTAX);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ if (!AccountMgr::CheckPassword(handler->GetSession()->GetAccountId(), std::string(oldPassword)))
+ {
+ handler->SendSysMessage(LANG_COMMAND_WRONGOLDPASSWORD);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ if (strcmp(newPassword, passwordConfirmation) != 0)
+ {
+ handler->SendSysMessage(LANG_NEW_PASSWORDS_NOT_MATCH);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ AccountOpResult result = AccountMgr::ChangePassword(handler->GetSession()->GetAccountId(), std::string(newPassword));
+ switch (result)
+ {
+ case AOR_OK:
+ handler->SendSysMessage(LANG_COMMAND_PASSWORD);
+ break;
+ case AOR_PASS_TOO_LONG:
+ handler->SendSysMessage(LANG_PASSWORD_TOO_LONG);
+ handler->SetSentErrorMessage(true);
+ return false;
+ default:
+ handler->SendSysMessage(LANG_COMMAND_NOTCHANGEPASSWORD);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool HandleAccountCommand(ChatHandler* handler, char const* /*args*/)
+ {
+ AccountTypes gmLevel = handler->GetSession()->GetSecurity();
+ handler->PSendSysMessage(LANG_ACCOUNT_LEVEL, uint32(gmLevel));
+ return true;
+ }
+
+ /// Set/Unset the expansion level for an account
+ static bool HandleAccountSetAddonCommand(ChatHandler* handler, char const* args)
+ {
+ ///- Get the command line arguments
+ char* account = strtok((char*)args, " ");
+ char* exp = strtok(NULL, " ");
+
+ if (!account)
+ return false;
+
+ std::string accountName;
+ uint32 accountId;
+
+ if (!exp)
+ {
+ Player* player = handler->getSelectedPlayer();
+ if (!player)
+ return false;
+
+ accountId = player->GetSession()->GetAccountId();
+ AccountMgr::GetName(accountId, accountName);
+ exp = account;
+ }
+ else
+ {
+ ///- Convert Account name to Upper Format
+ accountName = account;
+ if (!AccountMgr::normalizeString(accountName))
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ accountId = AccountMgr::GetId(accountName);
+ if (!accountId)
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+ }
+
+ // Let set addon state only for lesser (strong) security level
+ // or to self account
+ if (handler->GetSession() && handler->GetSession()->GetAccountId() != accountId &&
+ handler->HasLowerSecurityAccount(NULL, accountId, true))
+ return false;
+
+ int expansion = atoi(exp); //get int anyway (0 if error)
+ if (expansion < 0 || uint8(expansion) > sWorld->getIntConfig(CONFIG_EXPANSION))
+ return false;
+
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_EXPANSION);
+
+ stmt->setUInt8(0, expansion);
+ stmt->setUInt32(1, accountId);
+
+ LoginDatabase.Execute(stmt);
+
+ handler->PSendSysMessage(LANG_ACCOUNT_SETADDON, accountName.c_str(), accountId, expansion);
+ return true;
+ }
+
+ static bool HandleAccountSetGmLevelCommand(ChatHandler* handler, char const* args)
+ {
+ if (!*args)
+ return false;
+
+ std::string targetAccountName;
+ uint32 targetAccountId = 0;
+ uint32 targetSecurity = 0;
+ uint32 gm = 0;
+ char* arg1 = strtok((char*)args, " ");
+ char* arg2 = strtok(NULL, " ");
+ char* arg3 = strtok(NULL, " ");
+ bool isAccountNameGiven = true;
+
+ if (arg1 && !arg3)
+ {
+ if (!handler->getSelectedPlayer())
+ return false;
+ isAccountNameGiven = false;
+ }
+
+ // Check for second parameter
+ if (!isAccountNameGiven && !arg2)
+ return false;
+
+ // Check for account
+ if (isAccountNameGiven)
+ {
+ targetAccountName = arg1;
+ if (!AccountMgr::normalizeString(targetAccountName))
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, targetAccountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+ }
+
+ // Check for invalid specified GM level.
+ gm = (isAccountNameGiven) ? atoi(arg2) : atoi(arg1);
+ if (gm > SEC_CONSOLE)
+ {
+ handler->SendSysMessage(LANG_BAD_VALUE);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ // handler->getSession() == NULL only for console
+ targetAccountId = (isAccountNameGiven) ? AccountMgr::GetId(targetAccountName) : handler->getSelectedPlayer()->GetSession()->GetAccountId();
+ int32 gmRealmID = (isAccountNameGiven) ? atoi(arg3) : atoi(arg2);
+ uint32 playerSecurity;
+ if (handler->GetSession())
+ playerSecurity = AccountMgr::GetSecurity(handler->GetSession()->GetAccountId(), gmRealmID);
+ else
+ playerSecurity = SEC_CONSOLE;
+
+ // can set security level only for target with less security and to less security that we have
+ // This is also reject self apply in fact
+ targetSecurity = AccountMgr::GetSecurity(targetAccountId, gmRealmID);
+ if (targetSecurity >= playerSecurity || gm >= playerSecurity)
+ {
+ handler->SendSysMessage(LANG_YOURS_SECURITY_IS_LOW);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ // Check and abort if the target gm has a higher rank on one of the realms and the new realm is -1
+ if (gmRealmID == -1 && !AccountMgr::IsConsoleAccount(playerSecurity))
+ {
+ PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_ACCESS_GMLEVEL_TEST);
+
+ stmt->setUInt32(0, targetAccountId);
+ stmt->setUInt8(1, uint8(gm));
+
+ PreparedQueryResult result = LoginDatabase.Query(stmt);
+
+ if (result)
+ {
+ handler->SendSysMessage(LANG_YOURS_SECURITY_IS_LOW);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+ }
+
+ // Check if provided realmID has a negative value other than -1
+ if (gmRealmID < -1)
+ {
+ handler->SendSysMessage(LANG_INVALID_REALMID);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ // If gmRealmID is -1, delete all values for the account id, else, insert values for the specific realmID
+ PreparedStatement* stmt;
+
+ if (gmRealmID == -1)
+ {
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS);
+
+ stmt->setUInt32(0, targetAccountId);
+ }
+ else
+ {
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_ACCOUNT_ACCESS_BY_REALM);
+
+ stmt->setUInt32(0, targetAccountId);
+ stmt->setUInt32(1, realmID);
+ }
+
+ LoginDatabase.Execute(stmt);
+
+ if (gm != 0)
+ {
+ stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT_ACCESS);
+
+ stmt->setUInt32(0, targetAccountId);
+ stmt->setUInt8(1, uint8(gm));
+ stmt->setInt32(2, gmRealmID);
+
+ LoginDatabase.Execute(stmt);
+ }
+
+
+ handler->PSendSysMessage(LANG_YOU_CHANGE_SECURITY, targetAccountName.c_str(), gm);
+ return true;
+ }
+
+ /// Set password for account
+ static bool HandleAccountSetPasswordCommand(ChatHandler* handler, char const* args)
+ {
+ if (!*args)
+ return false;
+
+ ///- Get the command line arguments
+ char* account = strtok((char*)args, " ");
+ char* password = strtok(NULL, " ");
+ char* passwordConfirmation = strtok(NULL, " ");
+
+ if (!account || !password || !passwordConfirmation)
+ return false;
+
+ std::string accountName = account;
+ if (!AccountMgr::normalizeString(accountName))
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 targetAccountId = AccountMgr::GetId(accountName);
+ if (!targetAccountId)
+ {
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ /// can set password only for target with less security
+ /// This is also reject self apply in fact
+ if (handler->HasLowerSecurityAccount(NULL, targetAccountId, true))
+ return false;
+
+ if (strcmp(password, passwordConfirmation))
+ {
+ handler->SendSysMessage(LANG_NEW_PASSWORDS_NOT_MATCH);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+
+ AccountOpResult result = AccountMgr::ChangePassword(targetAccountId, password);
+
+ switch (result)
+ {
+ case AOR_OK:
+ handler->SendSysMessage(LANG_COMMAND_PASSWORD);
+ break;
+ case AOR_NAME_NOT_EXIST:
+ handler->PSendSysMessage(LANG_ACCOUNT_NOT_EXIST, accountName.c_str());
+ handler->SetSentErrorMessage(true);
+ return false;
+ case AOR_PASS_TOO_LONG:
+ handler->SendSysMessage(LANG_PASSWORD_TOO_LONG);
+ handler->SetSentErrorMessage(true);
+ return false;
+ default:
+ handler->SendSysMessage(LANG_COMMAND_NOTCHANGEPASSWORD);
+ handler->SetSentErrorMessage(true);
+ return false;
+ }
+ return true;
+ }
};
void AddSC_account_commandscript()
{
- new account_commandscript();
+ new account_commandscript();
}
diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp
index 069f6f719b..fb627e3891 100644
--- a/src/server/scripts/Commands/cs_go.cpp
+++ b/src/server/scripts/Commands/cs_go.cpp
@@ -112,7 +112,7 @@ public:
{
std::string name = param1;
WorldDatabase.EscapeString(name);
- whereClause << ", creature_template WHERE creature.id = creature_template.entry AND creature_template.name " _LIKE_" '" << name << '\'';
+ whereClause << ", creature_template WHERE creature.id = creature_template.entry AND creature_template.name "_LIKE_" '" << name << '\'';
}
else
whereClause << "WHERE guid = '" << guid << '\'';
diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp
index 7b5c264352..9daaf82b78 100644
--- a/src/server/scripts/Commands/cs_gobject.cpp
+++ b/src/server/scripts/Commands/cs_gobject.cpp
@@ -244,7 +244,7 @@ public:
WorldDatabase.EscapeString(name);
result = WorldDatabase.PQuery(
"SELECT guid, id, position_x, position_y, position_z, orientation, map, phaseMask, (POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ "
- "FROM gameobject, gameobject_template WHERE gameobject_template.entry = gameobject.id AND map = %i AND name " _LIKE_" " _CONCAT3_("'%%'", "'%s'", "'%%'")" ORDER BY order_ ASC LIMIT 1",
+ "FROM gameobject, gameobject_template WHERE gameobject_template.entry = gameobject.id AND map = %i AND name "_LIKE_" "_CONCAT3_("'%%'", "'%s'", "'%%'")" ORDER BY order_ ASC LIMIT 1",
player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetMapId(), name.c_str());
}
}
diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp
index d642f3f6fc..ed4e0c040d 100644
--- a/src/server/scripts/Commands/cs_npc.cpp
+++ b/src/server/scripts/Commands/cs_npc.cpp
@@ -260,7 +260,8 @@ public:
return false;
}
- uint32 vendor_entry = vendor ? vendor->GetEntry() : 0;
+ char* addMulti = strtok(NULL, " ");
+ uint32 vendor_entry = addMulti ? handler->GetSession()->GetCurrentVendor() : vendor ? vendor->GetEntry() : 0;
if (!sObjectMgr->IsVendorItemValid(vendor_entry, itemId, maxcount, incrtime, extendedcost, handler->GetSession()->GetPlayer()))
{
@@ -483,7 +484,8 @@ public:
}
uint32 itemId = atol(pitem);
- if (!sObjectMgr->RemoveVendorItem(vendor->GetEntry(), itemId))
+ char* addMulti = strtok(NULL, " ");
+ if (!sObjectMgr->RemoveVendorItem(addMulti ? handler->GetSession()->GetCurrentVendor() : vendor->GetEntry(), itemId))
{
handler->PSendSysMessage(LANG_ITEM_NOT_IN_LIST, itemId);
handler->SetSentErrorMessage(true);
diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp
index dac7bafc2e..3913adf095 100644
--- a/src/server/scripts/Commands/cs_reload.cpp
+++ b/src/server/scripts/Commands/cs_reload.cpp
@@ -363,7 +363,7 @@ public:
static bool HandleReloadAutobroadcastCommand(ChatHandler* handler, const char* /*args*/)
{
sLog->outString("Re-Loading Autobroadcasts...");
- //sWorld->LoadAutobroadcasts();
+ sWorld->LoadAutobroadcasts();
handler->SendGlobalGMSysMessage("DB table `autobroadcast` reloaded.");
return true;
}
diff --git a/src/server/scripts/Custom/Multivendor/MultivendorExample.sql b/src/server/scripts/Custom/Multivendor/MultivendorExample.sql
new file mode 100644
index 0000000000..ef94f213da
--- /dev/null
+++ b/src/server/scripts/Custom/Multivendor/MultivendorExample.sql
@@ -0,0 +1,10 @@
+SET @ENTRY = (SELECT max(entry)+1 FROM creature_template);
+SET @MENU_ID = (SELECT max(menu_id)+1 FROM gossip_menu_option);
+
+INSERT INTO `creature_template` (`entry`, `modelid1`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `scale`, `rank`, `dmgschool`, `baseattacktime`, `rangeattacktime`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `HoverHeight`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`) VALUES
+(@ENTRY, 1298, "Herbert", "MultiVendor", NULL, @MENU_ID, 10, 10, 0, 35, 129, 1, 1.14286, 1, 0, 0, 1500, 0, 1, 512, 2048, 8, 0, 0, 0, 0, 0, 7, 138412032, 0, 0, 0, 0, 0, 0, 0, '', 0, 3, 1, 0, 0, 1, 0, 2, '');
+
+INSERT INTO `gossip_menu_option` (`menu_id`, `id`, `option_icon`, `option_text`, `option_id`, `npc_option_npcflag`, `action_menu_id`, `action_poi_id`, `box_coded`, `box_money`, `box_text`) VALUES
+(@MENU_ID, 0, 4, 'VendorTest 465', 3, 128, 465, 0, 0, 0, ''),
+(@MENU_ID, 1, 9, 'VendorTest 54', 3, 128, 54, 0, 0, 0, ''),
+(@MENU_ID, 2, 6, 'VendorTest 35574', 3, 128, 35574, 0, 0, 100, 'These goods are special, so pay up!');
diff --git a/src/server/scripts/Custom/Multivendor/README.md b/src/server/scripts/Custom/Multivendor/README.md
new file mode 100644
index 0000000000..39680beb37
--- /dev/null
+++ b/src/server/scripts/Custom/Multivendor/README.md
@@ -0,0 +1,42 @@
+#Multivendor [![Build Status](https://travis-ci.org/Rochet2/TrinityCore.svg?branch=multivendor)](https://travis-ci.org/Rochet2/TrinityCore)
+
+####About
+Allows you to show gossip options that show different vendors from npc_vendor.<br />
+Source: http://rochet2.github.io/Multivendor.html
+
+####Installation
+
+Available as:
+- Direct merge: https://github.com/Rochet2/TrinityCore/tree/multivendor
+- Diff: https://github.com/Rochet2/TrinityCore/compare/TrinityCore:3.3.5...multivendor.diff
+- Diff in github view: https://github.com/Rochet2/TrinityCore/compare/TrinityCore:3.3.5...multivendor
+
+Using direct merge:
+- open git bash to source location
+- do `git remote add rochet2 https://github.com/Rochet2/TrinityCore.git`
+- do `git pull rochet2 multivendor`
+- use cmake and compile
+
+Using diff:
+- DO NOT COPY THE DIFF DIRECTLY! It causes apply to fail.
+- download the diff by __right clicking__ the link and select __Save link as__
+- place the downloaded `multivendor.diff` to the source root folder
+- open git bash to source location
+- do `git apply multivendor.diff`
+- use cmake and compile
+
+####Usage
+Set your NPC to have gossip and vendor NPCflags (129)<br />
+Add a gossip menu for him and add a new option to it.<br />
+The option needs to have option_id set to 3 so it acts as a vendor button,<br />
+npc_option_npcflag can be 1 or 128 (shows only if the NPC has vendor flag then)<br />
+and the action_menu_id is the vendor entry from npc_vendor that you want to show to the player.<br />
+
+YOU CAN also send menus from C++. All you need to do is to provide the vendor entry to the<br />
+`void WorldSession::SendListInventory(ObjectGuid guid, uint32 vendorEntry)` function.
+
+The npc add item command was modified so you can add items to multivendors as well.<br />
+The last vendor window must have been the multivendor you want to add your item to.<br />
+After opening the window you need to type `.npc add item #itemId <#maxcount><#incrtime><#extendedcost> 1`<br />
+The 1 in the end specifies that you are adding the item to the multivendor currently open.<br />
+Same thing works with `.npc delete item #itemId 1`
diff --git a/src/server/shared/Database/Implementation/LoginDatabase.cpp b/src/server/shared/Database/Implementation/LoginDatabase.cpp
index f8aad99be9..660994cfba 100644
--- a/src/server/shared/Database/Implementation/LoginDatabase.cpp
+++ b/src/server/shared/Database/Implementation/LoginDatabase.cpp
@@ -55,7 +55,8 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_DEL_REALM_CHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_REALM_CHARACTERS, "INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_SUM_REALM_CHARACTERS, "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC);
- PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, sha_pass_hash, joindate) VALUES(?, ?, NOW())", CONNECTION_SYNCH);
+ PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, sha_pass_hash, joindate) VALUES(?, ?, NOW())", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_INS_REALM_CHARACTERS_INIT, "INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist, account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_EXPANSION, "UPDATE account SET expansion = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_ACCOUNT_LOCK, "UPDATE account SET locked = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_USERNAME, "UPDATE account SET v = 0, s = 0, username = ?, sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC);
@@ -84,4 +85,5 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_SEL_ACCOUNT_WHOIS, "SELECT username, email, last_ip FROM account WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_REALMLIST_SECURITY_LEVEL, "SELECT allowedSecurityLevel from realmlist WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_DEL_ACCOUNT, "DELETE FROM account WHERE id = ?", CONNECTION_ASYNC);
+ PrepareStatement(LOGIN_SEL_AUTOBROADCAST, "SELECT id, weight, text FROM autobroadcast WHERE realmid = ? OR realmid = -1", CONNECTION_SYNCH);
}
diff --git a/src/server/shared/Database/Implementation/LoginDatabase.h b/src/server/shared/Database/Implementation/LoginDatabase.h
index 60acd47c44..8ccf28b64e 100644
--- a/src/server/shared/Database/Implementation/LoginDatabase.h
+++ b/src/server/shared/Database/Implementation/LoginDatabase.h
@@ -76,6 +76,7 @@ enum LoginDatabaseStatements
LOGIN_INS_REALM_CHARACTERS,
LOGIN_SEL_SUM_REALM_CHARACTERS,
LOGIN_INS_ACCOUNT,
+ LOGIN_INS_REALM_CHARACTERS_INIT,
LOGIN_UPD_EXPANSION,
LOGIN_UPD_ACCOUNT_LOCK,
LOGIN_UPD_USERNAME,
@@ -104,6 +105,7 @@ enum LoginDatabaseStatements
LOGIN_SEL_ACCOUNT_WHOIS,
LOGIN_SEL_REALMLIST_SECURITY_LEVEL,
LOGIN_DEL_ACCOUNT,
+ LOGIN_SEL_AUTOBROADCAST,
MAX_LOGINDATABASE_STATEMENTS
};
diff --git a/src/server/shared/Database/MySQLThreading.h b/src/server/shared/Database/MySQLThreading.h
index b31f693c91..0b0a5e6cca 100644
--- a/src/server/shared/Database/MySQLThreading.h
+++ b/src/server/shared/Database/MySQLThreading.h
@@ -33,7 +33,7 @@ class MySQL
static void Thread_Init()
{
mysql_thread_init();
- sLog->outSQLDriver("Core thread with ID [" UI64FMTD"] initializing MySQL thread.",
+ sLog->outSQLDriver("Core thread with ID ["UI64FMTD"] initializing MySQL thread.",
(uint64)ACE_Based::Thread::currentId());
}
@@ -44,7 +44,7 @@ class MySQL
static void Thread_End()
{
mysql_thread_end();
- sLog->outSQLDriver("Core thread with ID [" UI64FMTD"] shutting down MySQL thread.",
+ sLog->outSQLDriver("Core thread with ID ["UI64FMTD"] shutting down MySQL thread.",
(uint64)ACE_Based::Thread::currentId());
}
diff --git a/src/server/shared/Debugging/WheatyExceptionReport.cpp b/src/server/shared/Debugging/WheatyExceptionReport.cpp
index 52ad4939ee..3b6bd3d2cc 100644
--- a/src/server/shared/Debugging/WheatyExceptionReport.cpp
+++ b/src/server/shared/Debugging/WheatyExceptionReport.cpp
@@ -1080,10 +1080,10 @@ PVOID pAddress)
switch (basicType)
{
case btChar:
- pszCurrBuffer += sprintf(pszCurrBuffer, " = \" %s\"", pAddress);
+ pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%s\"", pAddress);
break;
case btStdString:
- pszCurrBuffer += sprintf(pszCurrBuffer, " = \" %s\"", static_cast<std::string*>(pAddress)->c_str());
+ pszCurrBuffer += sprintf(pszCurrBuffer, " = \"%s\"", static_cast<std::string*>(pAddress)->c_str());
break;
default:
// Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!)