diff options
27 files changed, 3527 insertions, 3173 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index cd460411e9e..74ad13fe060 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -1533,7 +1533,7 @@ DROP TABLE IF EXISTS `guild_bank_right`; CREATE TABLE `guild_bank_right` ( `guildid` int(11) unsigned NOT NULL default '0', `TabId` tinyint(1) unsigned NOT NULL default '0', - `rid` int(11) unsigned NOT NULL default '0', + `rid` tinyint(1) unsigned NOT NULL default '0', `gbright` tinyint(3) unsigned NOT NULL default '0', `SlotPerDay` int(11) unsigned NOT NULL default '0', PRIMARY KEY (`guildid`,`TabId`,`rid`), @@ -1659,7 +1659,7 @@ DROP TABLE IF EXISTS `guild_rank`; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `guild_rank` ( `guildid` int(6) unsigned NOT NULL default '0', - `rid` int(11) unsigned NOT NULL, + `rid` tinyint(1) unsigned NOT NULL, `rname` varchar(255) NOT NULL default '', `rights` int(3) unsigned NOT NULL default '0', `BankMoneyPerDay` int(11) unsigned NOT NULL default '0', diff --git a/sql/updates/10241_characters_guilds.sql b/sql/updates/10241_characters_guilds.sql new file mode 100644 index 00000000000..ba2d2cf7277 --- /dev/null +++ b/sql/updates/10241_characters_guilds.sql @@ -0,0 +1,2 @@ +ALTER TABLE guild_rank CHANGE COLUMN rid rid TINYINT(1) UNSIGNED NOT NULL; +ALTER TABLE guild_bank_right CHANGE COLUMN rid rid TINYINT(1) UNSIGNED NOT NULL DEFAULT 0; diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index 26d65133125..e506f8c608b 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -340,7 +340,7 @@ void AuctionHouseMgr::LoadAuctionItems() Item *item = NewItemOrBag(proto); - if (!item->LoadFromDB(item_guid, 0, result, item_template)) + if (!item->LoadFromDB(item_guid, 0, fields, item_template)) { delete item; continue; diff --git a/src/server/game/Chat/Commands/Level3.cpp b/src/server/game/Chat/Commands/Level3.cpp index 90c766dadfb..3f10d91fc0a 100755 --- a/src/server/game/Chat/Commands/Level3.cpp +++ b/src/server/game/Chat/Commands/Level3.cpp @@ -3996,10 +3996,7 @@ bool ChatHandler::HandleGuildInviteCommand(const char *args) return false; // player's guild membership checked in AddMember before add - if (!targetGuild->AddMember (target_guid,targetGuild->GetLowestRank ())) - return false; - - return true; + return targetGuild->AddMember(target_guid); } bool ChatHandler::HandleGuildUninviteCommand(const char *args) @@ -4018,7 +4015,7 @@ bool ChatHandler::HandleGuildUninviteCommand(const char *args) if (!targetGuild) return false; - targetGuild->DelMember (target_guid, false, true); + targetGuild->DeleteMember(target_guid, false, true); return true; } @@ -4045,11 +4042,7 @@ bool ChatHandler::HandleGuildRankCommand(const char *args) return false; uint32 newrank = uint32 (atoi (rankStr)); - if (newrank > targetGuild->GetLowestRank ()) - return false; - - targetGuild->ChangeRank (target_guid,newrank); - return true; + return targetGuild->ChangeMemberRank(target_guid, newrank); } bool ChatHandler::HandleGuildDeleteCommand(const char *args) diff --git a/src/server/game/Entities/Item/Container/Bag.cpp b/src/server/game/Entities/Item/Container/Bag.cpp index 2fe1a7c5ca0..ae04c0e4504 100755 --- a/src/server/game/Entities/Item/Container/Bag.cpp +++ b/src/server/game/Entities/Item/Container/Bag.cpp @@ -105,9 +105,9 @@ void Bag::SaveToDB(SQLTransaction& trans) Item::SaveToDB(trans); } -bool Bag::LoadFromDB(uint32 guid, uint64 owner_guid, PreparedQueryResult result, uint32 entry) +bool Bag::LoadFromDB(uint32 guid, uint64 owner_guid, Field* fields, uint32 entry) { - if (!Item::LoadFromDB(guid, owner_guid, result, entry)) + if (!Item::LoadFromDB(guid, owner_guid, fields, entry)) return false; ItemPrototype const* itemProto = GetProto(); // checked in Item::LoadFromDB diff --git a/src/server/game/Entities/Item/Container/Bag.h b/src/server/game/Entities/Item/Container/Bag.h index eb0df78516b..5ba01ebb9ee 100755 --- a/src/server/game/Entities/Item/Container/Bag.h +++ b/src/server/game/Entities/Item/Container/Bag.h @@ -54,7 +54,7 @@ class Bag : public Item // overwrite virtual Item::SaveToDB void SaveToDB(SQLTransaction& trans); // overwrite virtual Item::LoadFromDB - bool LoadFromDB(uint32 guid, uint64 owner_guid, PreparedQueryResult result, uint32 entry); + bool LoadFromDB(uint32 guid, uint64 owner_guid, Field* fields, uint32 entry); // overwrite virtual Item::DeleteFromDB void DeleteFromDB(SQLTransaction& trans); diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 8dcce98c040..55d5c80889c 100755 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -383,7 +383,7 @@ void Item::SaveToDB(SQLTransaction& trans) SetState(ITEM_UNCHANGED); } -bool Item::LoadFromDB(uint32 guid, uint64 owner_guid, PreparedQueryResult result, uint32 entry) +bool Item::LoadFromDB(uint32 guid, uint64 owner_guid, Field* fields, uint32 entry) { // 0 1 2 3 4 5 6 7 8 9 10 //result = CharacterDatabase.PQuery("SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text FROM item_instance WHERE guid = '%u'", guid); @@ -400,14 +400,6 @@ bool Item::LoadFromDB(uint32 guid, uint64 owner_guid, PreparedQueryResult result if (!proto) return false; - if (!result) - { - sLog.outError("Item (GUID: %u owner: %u) not found in table `item_instance`, can't load. ", guid, GUID_LOPART(owner_guid)); - return false; - } - - Field* fields = result->Fetch(); - // set owner (not if item is only loaded for gbank/auction/mail if (owner_guid != 0) SetOwnerGUID(owner_guid); diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 0de9ed9609c..f42a212dc02 100755 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -245,7 +245,7 @@ class Item : public Object bool IsBindedNotWith(Player const* player) const; bool IsBoundByEnchant() const; virtual void SaveToDB(SQLTransaction& trans); - virtual bool LoadFromDB(uint32 guid, uint64 owner_guid, PreparedQueryResult result, uint32 entry); + virtual bool LoadFromDB(uint32 guid, uint64 owner_guid, Field* fields, uint32 entry); virtual void DeleteFromDB(SQLTransaction& trans); void DeleteFromInventoryDB(SQLTransaction& trans); void SaveRefundDataToDB(); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index d5c9c6d6d94..53c5f0f2aa2 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -4458,8 +4458,8 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC sObjectAccessor.ConvertCorpseForPlayer(playerguid); if (uint32 guildId = GetGuildIdFromDB(playerguid)) - if (Guild* guild = sObjectMgr.GetGuildById(guildId)) - guild->DelMember(guid); + if (Guild* pGuild = sObjectMgr.GetGuildById(guildId)) + pGuild->DeleteMember(guid); // remove from arena teams LeaveAllArenaTeams(playerguid); @@ -4522,8 +4522,9 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC { do { - uint32 item_guidlow = (*resultItems)[11].GetUInt32(); - uint32 item_template = (*resultItems)[12].GetUInt32(); + Field* fields = resultItems->Fetch(); + uint32 item_guidlow = fields[11].GetUInt32(); + uint32 item_template = fields[12].GetUInt32(); ItemPrototype const* itemProto = sObjectMgr.GetItemPrototype(item_template); if (!itemProto) @@ -4535,7 +4536,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC } Item *pItem = NewItemOrBag(itemProto); - if (!pItem->LoadFromDB(item_guidlow, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER), resultItems, item_template)) + if (!pItem->LoadFromDB(item_guidlow, MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER), fields, item_template)) { pItem->FSetState(ITEM_REMOVED); pItem->SaveToDB(trans); // it also deletes item object! @@ -5117,28 +5118,8 @@ uint32 Player::DurabilityRepair(uint16 pos, bool cost, float discountMod, bool g if (!pGuild) return TotalCost; - if (!pGuild->HasRankRight(GetRank(), GR_RIGHT_WITHDRAW_REPAIR)) - { - sLog.outStaticDebug("You do not have rights to withdraw for repairs"); - return TotalCost; - } - - if (pGuild->GetMemberMoneyWithdrawRem(GetGUIDLow()) < costs) - { - sLog.outStaticDebug("You do not have enough money withdraw amount remaining"); + if (!pGuild->HandleMemberWithdrawMoney(GetSession(), costs, true)) return TotalCost; - } - - if (pGuild->GetGuildBankMoney() < costs) - { - sLog.outStaticDebug("There is not enough money in bank"); - return TotalCost; - } - - //- TODO: Fix bad function call design - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - pGuild->MemberMoneyWithdraw(costs, GetGUIDLow(), trans); - CharacterDatabase.CommitTransaction(trans); TotalCost = costs; } @@ -7004,12 +6985,12 @@ uint32 Player::GetGuildIdFromDB(uint64 guid) return id; } -uint32 Player::GetRankFromDB(uint64 guid) +uint8 Player::GetRankFromDB(uint64 guid) { QueryResult result = CharacterDatabase.PQuery("SELECT rank FROM guild_member WHERE guid='%u'", GUID_LOPART(guid)); if (result) { - uint32 v = result->Fetch()[0].GetUInt32(); + uint32 v = result->Fetch()[0].GetUInt8(); return v; } else @@ -16896,7 +16877,7 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timediff) Item *item = NewItemOrBag(proto); - if (!item->LoadFromDB(item_guid, GetGUID(), result, item_id)) + if (!item->LoadFromDB(item_guid, GetGUID(), fields, item_id)) { sLog.outError("Player::_LoadInventory: Player %s has broken item (id: #%u) in inventory, deleted.", GetName(),item_id); PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVENTORY_ITEM); @@ -17115,7 +17096,7 @@ void Player::_LoadMailedItems(Mail *mail) Item *item = NewItemOrBag(proto); - if (!item->LoadFromDB(item_guid_low, MAKE_NEW_GUID(fields[13].GetUInt32(), 0, HIGHGUID_PLAYER), result, item_template)) + if (!item->LoadFromDB(item_guid_low, MAKE_NEW_GUID(fields[13].GetUInt32(), 0, HIGHGUID_PLAYER), fields, item_template)) { sLog.outError("Player::_LoadMailedItems - Item in mail (%u) doesn't exist !!!! - item guid: %u, deleted from mail", mail->messageID, item_guid_low); CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", item_guid_low); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index c0c5d54cba1..42d8bc8b67d 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1715,12 +1715,12 @@ class Player : public Unit, public GridObject<Player> void SendUpdateToOutOfRangeGroupMembers(); void SetInGuild(uint32 GuildId) { SetUInt32Value(PLAYER_GUILDID, GuildId); } - void SetRank(uint32 rankId){ SetUInt32Value(PLAYER_GUILDRANK, rankId); } + void SetRank(uint8 rankId) { SetUInt32Value(PLAYER_GUILDRANK, rankId); } + uint8 GetRank() { return uint8(GetUInt32Value(PLAYER_GUILDRANK)); } void SetGuildIdInvited(uint32 GuildId) { m_GuildIdInvited = GuildId; } uint32 GetGuildId() { return GetUInt32Value(PLAYER_GUILDID); } static uint32 GetGuildIdFromDB(uint64 guid); - uint32 GetRank(){ return GetUInt32Value(PLAYER_GUILDRANK); } - static uint32 GetRankFromDB(uint64 guid); + static uint8 GetRankFromDB(uint64 guid); int GetGuildIdInvited() { return m_GuildIdInvited; } static void RemovePetitionsAndSigns(uint64 guid, uint32 type); diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index e0162c4988c..66348e29dc6 100755 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -346,7 +346,7 @@ std::string ObjectMgr::GetGuildNameById(uint32 GuildId) const Guild* ObjectMgr::GetGuildByLeader(const uint64 &guid) const { for (GuildMap::const_iterator itr = mGuildMap.begin(); itr != mGuildMap.end(); ++itr) - if (itr->second->GetLeader() == guid) + if (itr->second->GetLeaderGUID() == guid) return itr->second; return NULL; @@ -3488,288 +3488,282 @@ void ObjectMgr::BuildPlayerLevelInfo(uint8 race, uint8 _class, uint8 level, Play void ObjectMgr::LoadGuilds() { - Guild *newGuild; - - // 0 1 2 3 4 5 6 - QueryResult result = CharacterDatabase.Query("SELECT guild.guildid,guild.name,leaderguid,EmblemStyle,EmblemColor,BorderStyle,BorderColor," - // 7 8 9 10 11 12 - "BackgroundColor,info,motd,createdate,BankMoney,COUNT(guild_bank_tab.guildid) " - "FROM guild LEFT JOIN guild_bank_tab ON guild.guildid = guild_bank_tab.guildid GROUP BY guild.guildid ORDER BY guildid ASC"); + PreparedStatement* stmt = NULL; + PreparedQueryResult result; + sLog.outString("Loading Guilds..."); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_LOAD_GUILDS); + result = CharacterDatabase.Query(stmt); if (!result) { barGoLink bar(1); - bar.step(); - sLog.outString(); sLog.outString(">> Loaded 0 guild definitions"); + sLog.outString(); return; } - - // load guild ranks - // 0 1 2 3 4 - QueryResult guildRanksResult = CharacterDatabase.Query("SELECT guildid,rid,rname,rights,BankMoneyPerDay FROM guild_rank ORDER BY guildid ASC, rid ASC"); - - // load guild members - // 0 1 2 3 4 5 6 - QueryResult guildMembersResult = CharacterDatabase.Query("SELECT guildid,guild_member.guid,rank,pnote,offnote,BankResetTimeMoney,BankRemMoney," - // 7 8 9 10 11 12 - "BankResetTimeTab0,BankRemSlotsTab0,BankResetTimeTab1,BankRemSlotsTab1,BankResetTimeTab2,BankRemSlotsTab2," - // 13 14 15 16 17 18 - "BankResetTimeTab3,BankRemSlotsTab3,BankResetTimeTab4,BankRemSlotsTab4,BankResetTimeTab5,BankRemSlotsTab5," - // 19 20 21 22 23 24 - "characters.name, characters.level, characters.class, characters.zone, characters.logout_time, characters.account " - "FROM guild_member LEFT JOIN characters ON characters.guid = guild_member.guid ORDER BY guildid ASC"); - - // load guild bank tab rights - // 0 1 2 3 4 - QueryResult guildBankTabRightsResult = CharacterDatabase.Query("SELECT guildid,TabId,rid,gbright,SlotPerDay FROM guild_bank_right ORDER BY guildid ASC, TabId ASC"); - - + // 1. Load all guilds barGoLink bar(result->GetRowCount()); - - uint32 maxid = 0; do { - //Field *fields = result->Fetch(); - bar.step(); - newGuild = new Guild; - if (!newGuild->LoadGuildFromDB(result) || - !newGuild->LoadRanksFromDB(guildRanksResult) || - !newGuild->LoadMembersFromDB(guildMembersResult) || - !newGuild->LoadBankRightsFromDB(guildBankTabRightsResult) || - !newGuild->CheckGuildStructure() - ) + Field* fields = result->Fetch(); + Guild* pNewGuild = new Guild(); + if (!pNewGuild->LoadFromDB(fields)) { - newGuild->Disband(); - delete newGuild; + delete pNewGuild; continue; } - - AddGuild(newGuild); - - if (maxid < newGuild->GetId()) - maxid = newGuild->GetId(); - + AddGuild(pNewGuild); } while (result->NextRow()); - - std::vector<Guild*> GuildVector(maxid + 1); - - for (GuildMap::iterator itr = mGuildMap.begin(); itr != mGuildMap.end(); ++itr) - GuildVector[itr->second->GetId()] = (*itr).second; - - // 0 1 2 3 4 5 6 - QueryResult guildEventResult = CharacterDatabase.Query("SELECT LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp, guildid FROM guild_eventlog ORDER BY TimeStamp DESC, LogGuid DESC"); - - // 0 1 2 3 4 5 6 7 8 - QueryResult guildBankEventResult = CharacterDatabase.Query("SELECT LogGuid, EventType, PlayerGuid, ItemOrMoney, ItemStackCount, DestTabId, TimeStamp, guildid, TabId FROM guild_bank_eventlog ORDER BY TimeStamp DESC,LogGuid DESC"); - - // 0 1 2 3 4 - QueryResult guildBankTabResult = CharacterDatabase.Query("SELECT TabId, TabName, TabIcon, TabText, guildid FROM guild_bank_tab"); - - PreparedStatement* guildBankItemStmt = CharacterDatabase.GetPreparedStatement(CHAR_LOAD_GUILD_BANK_ITEMS); - PreparedQueryResult guildBankItemResult = CharacterDatabase.Query(guildBankItemStmt); - - LoadGuildEvents(GuildVector, guildEventResult); - LoadGuildBankEvents(GuildVector, guildBankEventResult); - LoadGuildBanks(GuildVector, guildBankTabResult, guildBankItemResult); - - //delete unused LogGuid records in guild_eventlog and guild_bank_eventlog table - //you can comment these lines if you don't plan to change CONFIG_GUILD_EVENT_LOG_COUNT and CONFIG_GUILD_BANK_EVENT_LOG_COUNT - PreparedStatement *guildEventLogStmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_OLD_GUILD_EVENT_LOGS); - guildEventLogStmt->setUInt32(0, sWorld.getIntConfig(CONFIG_GUILD_EVENT_LOG_COUNT)); - CharacterDatabase.Execute(guildEventLogStmt); - - PreparedStatement *guildBankEventLogStmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_OLD_GUILD_BANK_EVENT_LOGS); - guildBankEventLogStmt->setUInt32(0, sWorld.getIntConfig(CONFIG_GUILD_BANK_EVENT_LOG_COUNT)); - CharacterDatabase.Execute(guildBankEventLogStmt); - sLog.outString(); - sLog.outString(">> Loaded %u guild definitions", mGuildMap.size()); -} + sLog.outString(">> Loaded " UI64FMTD " guilds definitions", result->GetRowCount()); + sLog.outString(); -void ObjectMgr::LoadGuildEvents(std::vector<Guild*>& GuildVector, QueryResult& result) -{ + uint64 rowCount = 0; + // 2. Load all guild ranks + sLog.outString("Loading guild ranks..."); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_LOAD_GUILD_RANKS); + result = CharacterDatabase.Query(stmt); if (result) { + rowCount = result->GetRowCount(); + barGoLink bar(rowCount); do { - Field *fields = result->Fetch(); - uint32 guildid = fields[6].GetUInt32(); - if (guildid >= GuildVector.size() || GuildVector[guildid] == NULL) - continue; - - if (!GuildVector[guildid]->m_GuildEventLogNextGuid) - GuildVector[guildid]->m_GuildEventLogNextGuid = fields[0].GetUInt32(); - - if (GuildVector[guildid]->m_GuildEventLog.size() < GUILD_EVENTLOG_MAX_RECORDS) - { - GuildEventLogEntry NewEvent; - NewEvent.EventType = fields[1].GetUInt8(); - NewEvent.PlayerGuid1 = fields[2].GetUInt32(); - NewEvent.PlayerGuid2 = fields[3].GetUInt32(); - NewEvent.NewRank = fields[4].GetUInt8(); - NewEvent.TimeStamp = fields[5].GetUInt64(); + bar.step(); - GuildVector[guildid]->m_GuildEventLog.push_front(NewEvent); - } + Field* fields = result->Fetch(); + uint32 guildId = fields[0].GetUInt32(); + if (Guild* pGuild = GetGuildById(guildId)) + pGuild->LoadRankFromDB(fields); } while (result->NextRow()); } -} + else + { + barGoLink bar(1); + bar.step(); + } + sLog.outString(">> Loaded " UI64FMTD " ranks for all the guilds", rowCount); + sLog.outString(); -void ObjectMgr::LoadGuildBankEvents(std::vector<Guild*>& GuildVector, QueryResult& result) -{ + // 3. Load all guild members + sLog.outString("Loading guild members..."); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_LOAD_GUILD_MEMBERS); + result = CharacterDatabase.Query(stmt); if (result) { + rowCount = result->GetRowCount(); + barGoLink bar(rowCount); do { - Field *fields = result->Fetch(); - uint32 logGuid = fields[0].GetUInt32(); - uint32 guildid = fields[7].GetUInt32(); - if (guildid >= GuildVector.size() || GuildVector[guildid] == NULL) - continue; - - uint8 TabId = fields[8].GetUInt8(); - - if (TabId < GuildVector[guildid]->GetPurchasedTabs() || TabId == GUILD_BANK_MONEY_LOGS_TAB) - { - bool canInsert; - - if (TabId != GUILD_BANK_MONEY_LOGS_TAB) - { - if (!GuildVector[guildid]->m_GuildBankEventLogNextGuid_Item[TabId]) - GuildVector[guildid]->m_GuildBankEventLogNextGuid_Item[TabId] = logGuid; - } - else - { - if (!GuildVector[guildid]->m_GuildBankEventLogNextGuid_Money) - GuildVector[guildid]->m_GuildBankEventLogNextGuid_Money = logGuid; - } - - if (TabId != GUILD_BANK_MONEY_LOGS_TAB) - canInsert = GuildVector[guildid]->m_GuildBankEventLog_Item[TabId].size() < GUILD_BANK_MAX_LOGS; - else - canInsert = GuildVector[guildid]->m_GuildBankEventLog_Money.size() < GUILD_BANK_MAX_LOGS; + bar.step(); - if (canInsert) - { - GuildBankEventLogEntry NewEvent; - NewEvent.EventType = fields[1].GetUInt8(); - NewEvent.PlayerGuid = fields[2].GetUInt32(); - NewEvent.ItemOrMoney = fields[3].GetUInt32(); - NewEvent.ItemStackCount = fields[4].GetUInt8(); - NewEvent.DestTabId = fields[5].GetUInt8(); - NewEvent.TimeStamp = fields[6].GetUInt64(); - - if (TabId != GUILD_BANK_MONEY_LOGS_TAB) - { - if (NewEvent.isMoneyEvent()) - { - CharacterDatabase.PExecute("UPDATE guild_bank_eventlog SET TabId='%u' WHERE guildid='%u' AND TabId='%u' AND LogGuid='%u'", GUILD_BANK_MONEY_LOGS_TAB, guildid, TabId, logGuid); - sLog.outError("GuildBankEventLog ERROR: MoneyEvent LogGuid %u for Guild %u had incorrectly set its TabId to %u, correcting it to %u TabId", logGuid, guildid, TabId, GUILD_BANK_MONEY_LOGS_TAB); - continue; - } - else - GuildVector[guildid]->m_GuildBankEventLog_Item[TabId].push_front(NewEvent); - } - else - { - if (!NewEvent.isMoneyEvent()) - sLog.outError("GuildBankEventLog ERROR: MoneyEvent LogGuid %u for Guild %u is not MoneyEvent - ignoring...", logGuid, guildid); - else - GuildVector[guildid]->m_GuildBankEventLog_Money.push_front(NewEvent); - } - } - } + Field* fields = result->Fetch(); + uint32 guildId = fields[0].GetUInt32(); + if (Guild* pGuild = GetGuildById(guildId)) + pGuild->LoadMemberFromDB(fields); } while (result->NextRow()); } -} + else + { + rowCount = 0; + barGoLink bar(1); + bar.step(); + } + sLog.outString(">> Loaded " UI64FMTD " members from all the guilds", rowCount); + sLog.outString(); -void ObjectMgr::LoadGuildBanks(std::vector<Guild*>& GuildVector, QueryResult& result, PreparedQueryResult& itemResult) -{ + // 4. Load all guild bank tab rights + sLog.outString("Loading bank tab rights..."); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_LOAD_GUILD_BANK_RIGHTS); + result = CharacterDatabase.Query(stmt); if (result) { + rowCount = result->GetRowCount(); + barGoLink bar(rowCount); do { - Field *fields = result->Fetch(); - uint8 TabId = fields[0].GetUInt8(); - uint32 guildid = fields[4].GetUInt32(); - - if (guildid >= GuildVector.size() || GuildVector[guildid] == NULL) - continue; - - if (TabId < GuildVector[guildid]->GetPurchasedTabs()) - { - GuildBankTab *NewTab = new GuildBankTab; - - NewTab->Name = fields[1].GetString(); - NewTab->Icon = fields[2].GetString(); - NewTab->Text = fields[3].GetString(); + bar.step(); - GuildVector[guildid]->m_TabListMap[TabId] = NewTab; - } + Field* fields = result->Fetch(); + uint32 guildId = fields[0].GetUInt32(); + if (Guild* pGuild = GetGuildById(guildId)) + pGuild->LoadBankRightFromDB(fields); } while (result->NextRow()); } + else + { + rowCount = 0; + barGoLink bar(1); + bar.step(); + } + sLog.outString(">> Loaded " UI64FMTD " bank tab rights for all the guilds", rowCount); + sLog.outString(); - if (itemResult) + // 5. Load all event logs + sLog.outString("Loading guild event logs..."); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_LOAD_GUILD_EVENTLOGS); + result = CharacterDatabase.Query(stmt); + if (result) { + rowCount = result->GetRowCount(); + barGoLink bar(rowCount); do { - Field *fields = itemResult->Fetch(); - uint8 TabId = fields[11].GetUInt8(); - uint8 SlotId = fields[12].GetUInt8(); - uint32 ItemGuid = fields[13].GetUInt32(); - uint32 ItemId = fields[14].GetUInt32(); - uint32 guildid = fields[15].GetUInt32(); - if (guildid >= GuildVector.size() || GuildVector[guildid] == NULL) - continue; + bar.step(); - if (TabId >= GuildVector[guildid]->GetPurchasedTabs()) - { - sLog.outError("Guild::LoadGuildBankFromDB: Invalid tab for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid, ItemId); - continue; - } + Field* fields = result->Fetch(); + uint32 guildId = fields[0].GetUInt32(); + if (Guild* pGuild = GetGuildById(guildId)) + pGuild->LoadEventLogFromDB(fields); + } + while (result->NextRow()); + } + else + { + rowCount = 0; + barGoLink bar(1); + bar.step(); + } + sLog.outString(">> Loaded " UI64FMTD " event logs for all the guilds", rowCount); + sLog.outString(); - if (SlotId >= GUILD_BANK_MAX_SLOTS) - { - sLog.outError("Guild::LoadGuildBankFromDB: Invalid slot for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid, ItemId); - continue; - } + // 6. Load all bank event logs + sLog.outString("Loading guild bank event logs..."); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_LOAD_GUILD_BANK_EVENTLOGS); + result = CharacterDatabase.Query(stmt); + if (result) + { + rowCount = result->GetRowCount(); + barGoLink bar(rowCount); + do + { + bar.step(); - ItemPrototype const *proto = sObjectMgr.GetItemPrototype(ItemId); + Field* fields = result->Fetch(); + uint32 guildId = fields[0].GetUInt32(); + if (Guild* pGuild = GetGuildById(guildId)) + pGuild->LoadBankEventLogFromDB(fields); + } + while (result->NextRow()); + } + else + { + rowCount = 0; + barGoLink bar(1); + bar.step(); + } + sLog.outString(">> Loaded " UI64FMTD " bank event logs for all the guilds", rowCount); + sLog.outString(); - if (!proto) - { - sLog.outError("Guild::LoadGuildBankFromDB: Unknown item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid, ItemId); - continue; - } + // 7. Load all guild bank tabs + sLog.outString("Loading guild bank tabs..."); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_LOAD_GUILD_BANK_TABS); + result = CharacterDatabase.Query(stmt); + if (result) + { + rowCount = result->GetRowCount(); + barGoLink bar(rowCount); + do + { + bar.step(); - Item *pItem = NewItemOrBag(proto); - if (!pItem->LoadFromDB(ItemGuid, 0, itemResult, ItemId)) - { - PreparedStatement *stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_NONEXISTENT_GUILD_BANK_ITEM); - stmt->setUInt32(0, guildid); - stmt->setUInt32(1, uint32(TabId)); - stmt->setUInt32(2, uint32(SlotId)); - CharacterDatabase.Execute(stmt); + Field* fields = result->Fetch(); + uint32 guildId = fields[0].GetUInt32(); + if (Guild* pGuild = GetGuildById(guildId)) + pGuild->LoadBankTabFromDB(fields); + } + while (result->NextRow()); + } + else + { + rowCount = 0; + barGoLink bar(1); + bar.step(); + } + sLog.outString(">> Loaded " UI64FMTD " bank tabs for all the guilds", rowCount); + sLog.outString(); - sLog.outError("Item GUID %u not found in item_instance, deleting from Guild Bank!", ItemGuid); - delete pItem; - continue; - } + // 8. Fill all guild bank tabs + sLog.outString("Filling bank tabs with items..."); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_LOAD_GUILD_BANK_ITEMS); + result = CharacterDatabase.Query(stmt); + if (result) + { + rowCount = result->GetRowCount(); + barGoLink bar(rowCount); + do + { + bar.step(); - pItem->AddToWorld(); - GuildVector[guildid]->m_TabListMap[TabId]->Slots[SlotId] = pItem; + Field* fields = result->Fetch(); + uint32 guildId = fields[11].GetUInt32(); + if (Guild* pGuild = GetGuildById(guildId)) + pGuild->LoadBankItemFromDB(fields); } - while (itemResult->NextRow()); + while (result->NextRow()); } + else + { + rowCount = 0; + barGoLink bar(1); + bar.step(); + } + sLog.outString(">> Filled bank tabs with " UI64FMTD " items for all the guilds", rowCount); + sLog.outString(); + + // 9. Validate loaded guild data + sLog.outString("Validating data of loaded guilds..."); + barGoLink barGuilds(mGuildMap.size()); + for (GuildMap::iterator itr = mGuildMap.begin(); itr != mGuildMap.end(); ) + { + barGuilds.step(); + Guild* pGuild = itr->second; + if (!pGuild->Validate()) + { + ++itr; + mGuildMap.erase(pGuild->GetId()); + delete pGuild; + } + else + ++itr; + } + // Cleanup + // Delete orphan guild ranks + stmt = CharacterDatabase.GetPreparedStatement(CHAR_CLEAN_GUILD_RANKS); + CharacterDatabase.Execute(stmt); + // Delete orphan guild members + stmt = CharacterDatabase.GetPreparedStatement(CHAR_CLEAN_GUILD_MEMBERS); + CharacterDatabase.Execute(stmt); + // Delete orphan guild bank rights + stmt = CharacterDatabase.GetPreparedStatement(CHAR_CLEAN_GUILD_BANK_RIGHTS); + CharacterDatabase.Execute(stmt); + // Delete orphan guild bank tabs + stmt = CharacterDatabase.GetPreparedStatement(CHAR_CLEAN_GUILD_BANK_TABS); + CharacterDatabase.Execute(stmt); + // Delete orphan guild bank items + stmt = CharacterDatabase.GetPreparedStatement(CHAR_CLEAN_GUILD_BANK_ITEMS); + CharacterDatabase.Execute(stmt); + + // Delete unused LogGuid records in guild_eventlog and guild_bank_eventlog table. + // You can comment these lines if you don't plan to change CONFIG_GUILD_EVENT_LOG_COUNT and CONFIG_GUILD_BANK_EVENT_LOG_COUNT + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_OLD_GUILD_EVENT_LOGS); + stmt->setUInt32(0, sWorld.getIntConfig(CONFIG_GUILD_EVENT_LOG_COUNT)); + CharacterDatabase.Execute(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_OLD_GUILD_BANK_EVENT_LOGS); + stmt->setUInt32(0, sWorld.getIntConfig(CONFIG_GUILD_BANK_EVENT_LOG_COUNT)); + CharacterDatabase.Execute(stmt); + + sLog.outString(); + sLog.outString(">> Successfully loaded %u guilds", uint32(mGuildMap.size())); } void ObjectMgr::LoadArenaTeams() diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index af78f9c5a46..d75ab4c3e9a 100755 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -797,9 +797,6 @@ class ObjectMgr } void LoadGuilds(); - void LoadGuildEvents(std::vector<Guild*>& GuildVector, QueryResult& result); - void LoadGuildBankEvents(std::vector<Guild*>& GuildVector, QueryResult& result); - void LoadGuildBanks(std::vector<Guild*>& GuildVector, QueryResult& result, PreparedQueryResult& itemResult); void LoadArenaTeams(); void LoadGroups(); void LoadQuests(); diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 3ed1a6a9d7a..b0a4b1f4bc5 100755 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -17,763 +17,1211 @@ */ #include "DatabaseEnv.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Player.h" -#include "Opcodes.h" -#include "ObjectMgr.h" #include "Guild.h" +#include "ScriptMgr.h" #include "Chat.h" -#include "SocialMgr.h" -#include "Util.h" -#include "Language.h" -#include "World.h" #include "Config.h" -#include "ScriptMgr.h" +#include "SocialMgr.h" +#include "Log.h" -Guild::Guild() +#define MAX_GUILD_BANK_TAB_TEXT_LEN 500 +#define EMBLEM_PRICE 10 * GOLD + +inline void _CharacterExecutePreparedStatement(SQLTransaction& trans, PreparedStatement* stmt) { - m_Id = 0; - m_Name = ""; - m_LeaderGuid = 0; - GINFO = MOTD = ""; - m_EmblemStyle = 0; - m_EmblemColor = 0; - m_BorderStyle = 0; - m_BorderColor = 0; - m_BackgroundColor = 0; - m_accountsNumber = 0; + if (trans.null()) + CharacterDatabase.Execute(stmt); + else + trans->Append(stmt); +} - m_CreatedDate = time(0); +inline uint32 _GetGuildBankTabPrice(uint8 tabId) +{ + switch (tabId) + { + case 0: return 100; + case 1: return 250; + case 2: return 500; + case 3: return 1000; + case 4: return 2500; + case 5: return 5000; + default: return 0; + } +} - m_GuildBankMoney = 0; +void Guild::SendCommandResult(WorldSession* session, GuildCommandType type, GuildCommandError errCode, const std::string& param) +{ + WorldPacket data(SMSG_GUILD_COMMAND_RESULT, 8 + param.size() + 1); + data << uint32(type); + data << param; + data << uint32(errCode); + session->SendPacket(&data); - m_GuildEventLogNextGuid = 0; - m_GuildBankEventLogNextGuid_Money = 0; + sLog.outDebug("WORLD: Sent (SMSG_GUILD_COMMAND_RESULT)"); +} - for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i) - m_GuildBankEventLogNextGuid_Item[i] = 0; +void Guild::SendSaveEmblemResult(WorldSession* session, GuildEmblemError errCode) +{ + WorldPacket data(MSG_SAVE_GUILD_EMBLEM, 4); + data << uint32(errCode); + session->SendPacket(&data); + + sLog.outDebug("WORLD: Sent (MSG_SAVE_GUILD_EMBLEM)"); } -Guild::~Guild() +/////////////////////////////////////////////////////////////////////////////// +// LogHolder +Guild::LogHolder::~LogHolder() { - SQLTransaction temp = SQLTransaction(NULL); - DeleteGuildBankItems(temp); + // Cleanup + for (GuildLog::iterator itr = m_log.begin(); itr != m_log.end(); ++itr) + delete (*itr); } -bool Guild::Create(Player* leader, std::string gname) +// Adds event loaded from database to collection +inline void Guild::LogHolder::LoadEvent(LogEntry* entry) { - if (sObjectMgr.GetGuildByName(gname)) - return false; + if (m_nextGUID == GUILD_EVENT_LOG_GUID_UNDEFINED) + m_nextGUID = entry->GetGUID(); + m_log.push_front(entry); +} - WorldSession* lSession = leader->GetSession(); - if (!lSession) - return false; +// Adds new event happened in game. +// If maximum number of events is reached, oldest event is removed from collection. +inline void Guild::LogHolder::AddEvent(SQLTransaction& trans, LogEntry* entry) +{ + // Check max records limit + if (m_log.size() >= m_maxRecords) + { + LogEntry* oldEntry = m_log.front(); + delete oldEntry; + m_log.pop_front(); + } + // Add event to list + m_log.push_back(entry); + // Save to DB + entry->SaveToDB(trans); +} - m_LeaderGuid = leader->GetGUID(); - m_Name = gname; - GINFO = ""; - MOTD = "No message set."; - m_GuildBankMoney = 0; - m_Id = sObjectMgr.GenerateGuildId(); +// Writes information about all events into packet. +inline void Guild::LogHolder::WritePacket(WorldPacket& data) const +{ + data << uint8(m_log.size()); + for (GuildLog::const_iterator itr = m_log.begin(); itr != m_log.end(); ++itr) + (*itr)->WritePacket(data); +} - sLog.outDebug("GUILD: creating guild %s to leader: %u", gname.c_str(), GUID_LOPART(m_LeaderGuid)); +inline uint32 Guild::LogHolder::GetNextGUID() +{ + // Next guid was not initialized. It means there are no records for this holder in DB yet. + // Start from the beginning. + if (m_nextGUID == GUILD_EVENT_LOG_GUID_UNDEFINED) + m_nextGUID = 0; + else + m_nextGUID = (m_nextGUID + 1) % m_maxRecords; + return m_nextGUID; +} + +/////////////////////////////////////////////////////////////////////////////// +// EventLogEntry +void Guild::EventLogEntry::SaveToDB(SQLTransaction& trans) const +{ + PreparedStatement* stmt = NULL; + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_EVENTLOG); + stmt->setUInt32(0, m_guildId); + stmt->setUInt32(1, m_guid); + _CharacterExecutePreparedStatement(trans, stmt); + + uint8 index = 0; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_GUILD_EVENTLOG); + stmt->setUInt32( index, m_guildId); + stmt->setUInt32(++index, m_guid); + stmt->setUInt8 (++index, uint8(m_eventType)); + stmt->setUInt32(++index, m_playerGuid1); + stmt->setUInt32(++index, m_playerGuid2); + stmt->setUInt8 (++index, m_newRank); + stmt->setUInt64(++index, m_timestamp); + _CharacterExecutePreparedStatement(trans, stmt); +} + +void Guild::EventLogEntry::WritePacket(WorldPacket& data) const +{ + // Event type + data << uint8(m_eventType); + // Player 1 + data << uint64(MAKE_NEW_GUID(m_playerGuid1, 0, HIGHGUID_PLAYER)); + // Player 2 not for left/join guild events + if (m_eventType != GUILD_EVENT_LOG_JOIN_GUILD && m_eventType != GUILD_EVENT_LOG_LEAVE_GUILD) + data << uint64(MAKE_NEW_GUID(m_playerGuid2, 0, HIGHGUID_PLAYER)); + // New Rank - only for promote/demote guild events + if (m_eventType == GUILD_EVENT_LOG_PROMOTE_PLAYER || m_eventType == GUILD_EVENT_LOG_DEMOTE_PLAYER) + data << uint8(m_newRank); + // Event timestamp + data << uint32(::time(NULL) - m_timestamp); +} + +/////////////////////////////////////////////////////////////////////////////// +// BankEventLogEntry +void Guild::BankEventLogEntry::SaveToDB(SQLTransaction& trans) const +{ + PreparedStatement* stmt = NULL; + uint8 index = 0; + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_EVENTLOG); + stmt->setUInt32( index, m_guildId); + stmt->setUInt32(++index, m_guid); + stmt->setUInt8 (++index, m_bankTabId); + _CharacterExecutePreparedStatement(trans, stmt); + + index = 0; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_GUILD_BANK_EVENTLOG); + stmt->setUInt32( index, m_guildId); + stmt->setUInt32(++index, m_guid); + stmt->setUInt8 (++index, m_bankTabId); + stmt->setUInt8 (++index, uint8(m_eventType)); + stmt->setUInt32(++index, m_playerGuid); + stmt->setUInt32(++index, m_itemOrMoney); + stmt->setUInt16(++index, m_itemStackCount); + stmt->setUInt8 (++index, m_destTabId); + stmt->setUInt64(++index, m_timestamp); + _CharacterExecutePreparedStatement(trans, stmt); +} + +void Guild::BankEventLogEntry::WritePacket(WorldPacket& data) const +{ + data << uint8(m_eventType); + data << uint64(MAKE_NEW_GUID(m_playerGuid, 0, HIGHGUID_PLAYER)); + data << uint32(m_itemOrMoney); + if (!IsMoneyEvent(m_eventType)) + { + data << uint32(m_itemStackCount); + if (m_eventType == GUILD_BANK_LOG_MOVE_ITEM || m_eventType == GUILD_BANK_LOG_MOVE_ITEM2) + data << uint8(m_destTabId); + } + data << uint32(::time(NULL) - m_timestamp); +} - // gname already assigned to Guild::name, use it to encode string for DB - CharacterDatabase.escape_string(gname); +/////////////////////////////////////////////////////////////////////////////// +// RankInfo +bool Guild::RankInfo::LoadFromDB(Field* fields) +{ + m_rankId = fields[1].GetUInt8(); + m_name = fields[2].GetString(); + m_rights = fields[3].GetUInt32(); + m_bankMoneyPerDay = fields[4].GetUInt32(); + if (m_rankId == GR_GUILDMASTER) // Prevent loss of leader rights + m_rights |= GR_RIGHT_ALL; + return true; +} - std::string dbGINFO = GINFO; - std::string dbMOTD = MOTD; - CharacterDatabase.escape_string(dbGINFO); - CharacterDatabase.escape_string(dbMOTD); +void Guild::RankInfo::SaveToDB(SQLTransaction& trans) const +{ + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_GUILD_RANK); + stmt->setUInt32(0, m_guildId); + stmt->setUInt8 (1, m_rankId); + stmt->setString(2, m_name); + stmt->setUInt32(3, m_rights); + _CharacterExecutePreparedStatement(trans, stmt); +} - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - // CharacterDatabase.PExecute("DELETE FROM guild WHERE guildid='%u'", Id); - MAX(guildid)+1 not exist - trans->PAppend("DELETE FROM guild_member WHERE guildid='%u'", m_Id); - trans->PAppend("INSERT INTO guild (guildid,name,leaderguid,info,motd,createdate,EmblemStyle,EmblemColor,BorderStyle,BorderColor,BackgroundColor,BankMoney) " - "VALUES('%u','%s','%u', '%s', '%s', UNIX_TIMESTAMP(NOW()),'%u','%u','%u','%u','%u','" UI64FMTD "')", - m_Id, gname.c_str(), GUID_LOPART(m_LeaderGuid), dbGINFO.c_str(), dbMOTD.c_str(), m_EmblemStyle, m_EmblemColor, m_BorderStyle, m_BorderColor, m_BackgroundColor, m_GuildBankMoney); - CharacterDatabase.CommitTransaction(trans); +void Guild::RankInfo::WritePacket(WorldPacket& data) const +{ + data << uint32(m_rights); + data << uint32(m_bankMoneyPerDay); // In game set in gold, in packet set in bronze. + for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i) + { + data << uint32(m_bankTabRightsAndSlots[i].rights); + data << uint32(m_bankTabRightsAndSlots[i].slots); + } +} - CreateDefaultGuildRanks(lSession->GetSessionDbLocaleIndex()); +void Guild::RankInfo::SetName(const std::string& name) +{ + if (m_name == name) + return; - return AddMember(m_LeaderGuid, (uint32)GR_GUILDMASTER); + m_name = name; + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_GUILD_RANK_NAME); + stmt->setString(0, m_name); + stmt->setUInt8 (1, m_rankId); + stmt->setUInt32(2, m_guildId); + CharacterDatabase.Execute(stmt); } -void Guild::CreateDefaultGuildRanks(LocaleConstant locale_idx) +void Guild::RankInfo::SetRights(uint32 rights) { - CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", m_Id); - CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u'", m_Id); + if (m_rankId == GR_GUILDMASTER) // Prevent loss of leader rights + rights = GR_RIGHT_ALL; + + if (m_rights == rights) + return; + + m_rights = rights; - CreateRank(sObjectMgr.GetTrinityString(LANG_GUILD_MASTER, locale_idx), GR_RIGHT_ALL); - CreateRank(sObjectMgr.GetTrinityString(LANG_GUILD_OFFICER, locale_idx), GR_RIGHT_ALL); - CreateRank(sObjectMgr.GetTrinityString(LANG_GUILD_VETERAN, locale_idx), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); - CreateRank(sObjectMgr.GetTrinityString(LANG_GUILD_MEMBER, locale_idx), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); - CreateRank(sObjectMgr.GetTrinityString(LANG_GUILD_INITIATE, locale_idx), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_GUILD_RANK_RIGHTS); + stmt->setUInt32(0, m_rights); + stmt->setUInt8 (1, m_rankId); + stmt->setUInt32(2, m_guildId); + CharacterDatabase.Execute(stmt); } -bool Guild::AddMember(uint64 plGuid, uint32 plRank) +void Guild::RankInfo::SetBankMoneyPerDay(uint32 money) { - Player* pl = sObjectMgr.GetPlayer(plGuid); - if (pl) + if (m_rankId == GR_GUILDMASTER) // Prevent loss of leader rights + money = GUILD_WITHDRAW_MONEY_UNLIMITED; + + if (m_bankMoneyPerDay == money) + return; + + m_bankMoneyPerDay = money; + + PreparedStatement* stmt = NULL; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_GUILD_RANK_BANK_MONEY); + stmt->setUInt32(0, money); + stmt->setUInt8 (1, m_rankId); + stmt->setUInt32(2, m_guildId); + CharacterDatabase.Execute(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_RESET_GUILD_RANK_BANK_RESET_TIME); + stmt->setUInt32(0, m_guildId); + stmt->setUInt8 (1, m_rankId); + CharacterDatabase.Execute(stmt); +} + +void Guild::RankInfo::SetBankTabSlotsAndRights(uint8 tabId, GuildBankRightsAndSlots rightsAndSlots, bool saveToDB) +{ + if (m_rankId == GR_GUILDMASTER) // Prevent loss of leader rights + rightsAndSlots.SetGuildMasterValues(); + + if (m_bankTabRightsAndSlots[tabId].IsEqual(rightsAndSlots)) + return; + + m_bankTabRightsAndSlots[tabId] = rightsAndSlots; + + if (saveToDB) { - if (pl->GetGuildId() != 0) - return false; + PreparedStatement* stmt = NULL; + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_RIGHT); + stmt->setUInt32(0, m_guildId); + stmt->setUInt8 (1, tabId); + stmt->setUInt8 (2, m_rankId); + CharacterDatabase.Execute(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_GUILD_BANK_RIGHT); + stmt->setUInt32(0, m_guildId); + stmt->setUInt8 (1, tabId); + stmt->setUInt8 (2, m_rankId); + stmt->setUInt8 (3, m_bankTabRightsAndSlots[tabId].rights); + stmt->setUInt32(4, m_bankTabRightsAndSlots[tabId].slots); + CharacterDatabase.Execute(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_RESET_GUILD_RANK_BANK_TIME0 + tabId); + stmt->setUInt32(0, m_guildId); + stmt->setUInt8 (1, m_rankId); + CharacterDatabase.Execute(stmt); } - else +} + +/////////////////////////////////////////////////////////////////////////////// +// BankTab +bool Guild::BankTab::LoadFromDB(Field* fields) +{ + m_name = fields[2].GetString(); + m_icon = fields[3].GetString(); + m_text = fields[4].GetString(); + return true; +} + +bool Guild::BankTab::LoadItemFromDB(Field* fields) +{ + uint8 slotId = fields[13].GetUInt8(); + uint32 itemGuid = fields[14].GetUInt32(); + uint32 itemEntry = fields[15].GetUInt32(); + if (slotId >= GUILD_BANK_MAX_SLOTS) { - if (Player::GetGuildIdFromDB(plGuid) != 0) // player already in guild - return false; + sLog.outError("Invalid slot for item (GUID: %u, id: %u) in guild bank, skipped.", itemGuid, itemEntry); + return false; } - sScriptMgr.OnGuildAddMember(this, pl, plRank); + ItemPrototype const* proto = sObjectMgr.GetItemPrototype(itemEntry); + if (!proto) + { + sLog.outError("Unknown item (GUID: %u, id: %u) in guild bank, skipped.", itemGuid, itemEntry); + return false; + } - // remove all player signs from another petitions - // this will be prevent attempt joining player to many guilds and corrupt guild data integrity - Player::RemovePetitionsAndSigns(plGuid, 9); + Item *pItem = NewItemOrBag(proto); + if (!pItem->LoadFromDB(itemGuid, 0, fields, itemEntry)) + { + sLog.outError("Item (GUID %u, id: %u) not found in item_instance, deleting from guild bank!", itemGuid, itemEntry); - // fill player data - MemberSlot newmember; + PreparedStatement *stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_NONEXISTENT_GUILD_BANK_ITEM); + stmt->setUInt32(0, m_guildId); + stmt->setUInt8 (1, m_tabId); + stmt->setUInt8 (2, slotId); + CharacterDatabase.Execute(stmt); - if (pl) - { - newmember.accountId = pl->GetSession()->GetAccountId(); - newmember.Name = pl->GetName(); - newmember.ZoneId = pl->GetZoneId(); - newmember.Level = pl->getLevel(); - newmember.Class = pl->getClass(); + delete pItem; + return false; } - else - { - QueryResult result = CharacterDatabase.PQuery("SELECT name,zone,level,class,account FROM characters WHERE guid = '%u'", GUID_LOPART(plGuid)); - if (!result) - return false; // player doesn't exist - Field *fields = result->Fetch(); - newmember.Name = fields[0].GetString(); - newmember.ZoneId = fields[1].GetUInt32(); - newmember.Level = fields[2].GetUInt8(); - newmember.Class = fields[3].GetUInt8(); - newmember.accountId = fields[4].GetInt32(); + pItem->AddToWorld(); + m_items[slotId] = pItem; + return true; +} - if (newmember.Level < 1 || //newmember.Level > STRONG_MAX_LEVEL || - newmember.Class < CLASS_WARRIOR || newmember.Class >= MAX_CLASSES) +// Deletes contents of the tab from the world (and from DB if necessary) +void Guild::BankTab::Delete(SQLTransaction& trans, bool removeItemsFromDB) +{ + for (uint8 slotId = 0; slotId < GUILD_BANK_MAX_SLOTS; ++slotId) + if (Item* pItem = m_items[slotId]) { - sLog.outError("Player (GUID: %u) has a broken data in field `characters` table, cannot add him to guild.",GUID_LOPART(plGuid)); - return false; + pItem->RemoveFromWorld(); + if (removeItemsFromDB) + pItem->DeleteFromDB(trans); + delete pItem; + pItem = NULL; } - } - - newmember.RankId = plRank; - newmember.OFFnote = (std::string)""; - newmember.Pnote = (std::string)""; - newmember.LogoutTime = time(NULL); - newmember.BankResetTimeMoney = 0; // this will force update at first query - for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i) - newmember.BankResetTimeTab[i] = 0; - members[GUID_LOPART(plGuid)] = newmember; +} - std::string dbPnote = newmember.Pnote; - std::string dbOFFnote = newmember.OFFnote; - CharacterDatabase.escape_string(dbPnote); - CharacterDatabase.escape_string(dbOFFnote); +inline void Guild::BankTab::WritePacket(WorldPacket& data) const +{ + data << uint8(GUILD_BANK_MAX_SLOTS); + for (uint8 slotId = 0; slotId < GUILD_BANK_MAX_SLOTS; ++slotId) + WriteSlotPacket(data, slotId); +} - CharacterDatabase.PExecute("INSERT INTO guild_member (guildid,guid,rank,pnote,offnote) VALUES ('%u', '%u', '%u','%s','%s')", - m_Id, GUID_LOPART(plGuid), newmember.RankId, dbPnote.c_str(), dbOFFnote.c_str()); +// Writes information about contents of specified slot into packet. +void Guild::BankTab::WriteSlotPacket(WorldPacket& data, uint8 slotId) const +{ + Item *pItem = GetItem(slotId); + uint32 itemEntry = pItem ? pItem->GetEntry() : 0; - // If player not in game data in data field will be loaded from guild tables, no need to update it!! - if (pl) + data << uint8(slotId); + data << uint32(itemEntry); + if (itemEntry) { - pl->SetInGuild(m_Id); - pl->SetRank(newmember.RankId); - pl->SetGuildIdInvited(0); - } + data << uint32(0); // 3.3.0 (0x00018020, 0x00018000) + data << uint32(pItem->GetItemRandomPropertyId()); // Random item property id - UpdateAccountsNumber(); + if (pItem->GetItemRandomPropertyId()) + data << uint32(pItem->GetItemSuffixFactor()); // SuffixFactor - return true; + data << uint32(pItem->GetCount()); // ITEM_FIELD_STACK_COUNT + data << uint32(0); + data << uint8(abs(pItem->GetSpellCharges())); // Spell charges + + uint8 enchCount = 0; + size_t enchCountPos = data.wpos(); + + data << uint8(enchCount); // Number of enchantments + for (uint32 i = PERM_ENCHANTMENT_SLOT; i < MAX_ENCHANTMENT_SLOT; ++i) + if (uint32 enchId = pItem->GetEnchantmentId(EnchantmentSlot(i))) + { + data << uint8(i); + data << uint32(enchId); + ++enchCount; + } + data.put<uint8>(enchCountPos, enchCount); + } } -void Guild::SetMOTD(std::string motd) +void Guild::BankTab::SetInfo(const std::string& name, const std::string& icon) { - MOTD = motd; + if (m_name == name && m_icon == icon) + return; - sScriptMgr.OnGuildMOTDChanged(this, motd); + m_name = name; + m_icon = icon; - // motd now can be used for encoding to DB - CharacterDatabase.escape_string(motd); - CharacterDatabase.PExecute("UPDATE guild SET motd='%s' WHERE guildid='%u'", motd.c_str(), m_Id); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_GUILD_BANK_TAB_INFO); + stmt->setString(0, m_name); + stmt->setString(1, m_icon); + stmt->setUInt32(2, m_guildId); + stmt->setUInt8 (3, m_tabId); + CharacterDatabase.Execute(stmt); } -void Guild::SetGINFO(std::string ginfo) +void Guild::BankTab::SetText(const std::string& text) { - GINFO = ginfo; + if (m_text == text) + return; - sScriptMgr.OnGuildInfoChanged(this, ginfo); + m_text = text; + utf8truncate(m_text, MAX_GUILD_BANK_TAB_TEXT_LEN); // DB and client size limitation - // ginfo now can be used for encoding to DB - CharacterDatabase.escape_string(ginfo); - CharacterDatabase.PExecute("UPDATE guild SET info='%s' WHERE guildid='%u'", ginfo.c_str(), m_Id); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_GUILD_BANK_TAB_TEXT); + stmt->setString(0, m_text); + stmt->setUInt32(1, m_guildId); + stmt->setUInt8 (2, m_tabId); + CharacterDatabase.Execute(stmt); } -bool Guild::LoadGuildFromDB(QueryResult guildDataResult) +// Sets/removes contents of specified slot. +// If pItem == NULL contents are removed. +bool Guild::BankTab::SetItem(SQLTransaction& trans, uint8 slotId, Item* pItem) { - if (!guildDataResult) + if (slotId >= GUILD_BANK_MAX_SLOTS) return false; - Field *fields = guildDataResult->Fetch(); - - m_Id = fields[0].GetUInt32(); - m_Name = fields[1].GetString(); - m_LeaderGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER); - m_EmblemStyle = fields[3].GetUInt32(); - m_EmblemColor = fields[4].GetUInt32(); - m_BorderStyle = fields[5].GetUInt32(); - m_BorderColor = fields[6].GetUInt32(); - m_BackgroundColor = fields[7].GetUInt32(); - GINFO = fields[8].GetString(); - MOTD = fields[9].GetString(); - m_CreatedDate = fields[10].GetUInt64(); - m_GuildBankMoney = fields[11].GetUInt64(); - - uint32 purchasedTabs = fields[12].GetUInt32(); - if (purchasedTabs > GUILD_BANK_MAX_TABS) - purchasedTabs = GUILD_BANK_MAX_TABS; + m_items[slotId] = pItem; - m_TabListMap.resize(purchasedTabs); - for (uint8 i = 0; i < purchasedTabs; ++i) - m_TabListMap[i] = new GuildBankTab(); + PreparedStatement* stmt = NULL; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_ITEM); + stmt->setUInt32(0, m_guildId); + stmt->setUInt8 (1, m_tabId); + stmt->setUInt8 (2, slotId); + _CharacterExecutePreparedStatement(trans, stmt); + + if (pItem) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_GUILD_BANK_ITEM); + stmt->setUInt32(0, m_guildId); + stmt->setUInt8 (1, m_tabId); + stmt->setUInt8 (2, slotId); + stmt->setUInt32(3, pItem->GetGUIDLow()); + stmt->setUInt32(4, pItem->GetEntry()); + _CharacterExecutePreparedStatement(trans, stmt); + + pItem->SetUInt64Value(ITEM_FIELD_CONTAINED, 0); + pItem->SetUInt64Value(ITEM_FIELD_OWNER, 0); + pItem->FSetState(ITEM_NEW); + pItem->SaveToDB(trans); // Not in inventory and can be saved standalone + } return true; } -bool Guild::CheckGuildStructure() +void Guild::BankTab::SendText(const Guild* pGuild, WorldSession* session) const { - // Repair the structure of guild - // If the guildmaster doesn't exist or isn't the member of guild - // attempt to promote another member - int32 GM_rights = GetRank(GUID_LOPART(m_LeaderGuid)); - if (GM_rights == -1) - { - DelMember(m_LeaderGuid); - // check no members case (disbanded) - if (members.empty()) - return false; - } - else if (GM_rights != GR_GUILDMASTER) - SetLeader(m_LeaderGuid); + WorldPacket data(MSG_QUERY_GUILD_BANK_TEXT, 1 + m_text.size() + 1); + data << uint8(m_tabId); + data << m_text; - // Check config if multiple guildmasters are allowed - if (sConfig.GetBoolDefault("Guild.AllowMultipleGuildMaster", 0) == 0) - for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) - if (itr->second.RankId == GR_GUILDMASTER && GUID_LOPART(m_LeaderGuid) != itr->first) // Allow only 1 guildmaster - ChangeRank(itr->first, GR_OFFICER); // set right of member to officer + if (session) + session->SendPacket(&data); + else + pGuild->BroadcastPacket(&data); +} - return true; +/////////////////////////////////////////////////////////////////////////////// +// Member +void Guild::Member::SetStats(Player* player) +{ + m_name = player->GetName(); + m_level = player->getLevel(); + m_class = player->getClass(); + m_zoneId = player->GetZoneId(); + m_accountId = player->GetSession()->GetAccountId(); } -bool Guild::LoadRanksFromDB(QueryResult guildRanksResult) +void Guild::Member::SetStats(const std::string& name, uint8 level, uint8 _class, uint32 zoneId, uint32 accountId) { - if (!guildRanksResult) - { - sLog.outError("Guild %u has broken `guild_rank` data, creating new...",m_Id); - CreateDefaultGuildRanks(DEFAULT_LOCALE); - return true; - } + m_name = name; + m_level = level; + m_class = _class; + m_zoneId = zoneId; + m_accountId = accountId; +} - Field *fields; - bool broken_ranks = false; +void Guild::Member::SetPublicNote(const std::string& publicNote) +{ + if (m_publicNote == publicNote) + return; - //GUILD RANKS are sequence starting from 0 = GUILD_MASTER (ALL PRIVILEGES) to max 9 (lowest privileges) - //the lower rank id is considered higher rank - so promotion does rank-- and demotion does rank++ - //between ranks in sequence cannot be gaps - so 0,1,2,4 cannot be - //min ranks count is 5 and max is 10. + m_publicNote = publicNote; - do - { - fields = guildRanksResult->Fetch(); - //condition that would be true when all ranks in QueryResult will be processed and guild without ranks is being processed - if (!fields) - break; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_GUILD_MEMBER_PNOTE); + stmt->setString(0, publicNote); + stmt->setUInt32(1, GUID_LOPART(m_guid)); + CharacterDatabase.Execute(stmt); +} - uint32 guildId = fields[0].GetUInt32(); - if (guildId < m_Id) - { - //there is in table guild_rank record which doesn't have guildid in guild table, report error - sLog.outErrorDb("Guild %u does not exist but it has a record in guild_rank table, deleting it!", guildId); - CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid = '%u'", guildId); - continue; - } +void Guild::Member::SetOfficerNote(const std::string& officerNote) +{ + if (m_officerNote == officerNote) + return; - if (guildId > m_Id) - //we loaded all ranks for this guild already, break cycle - break; - uint32 rankID = fields[1].GetUInt32(); - std::string rankName = fields[2].GetString(); - uint32 rankRights = fields[3].GetUInt32(); - uint32 rankMoney = fields[4].GetUInt32(); + m_officerNote = officerNote; - if (rankID != m_Ranks.size()) // guild_rank.ids are sequence 0,1,2,3.. - broken_ranks = true; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_GUILD_MEMBER_OFFNOTE); + stmt->setString(0, officerNote); + stmt->setUInt32(1, GUID_LOPART(m_guid)); + CharacterDatabase.Execute(stmt); +} + +void Guild::Member::ChangeRank(uint8 newRank) +{ + m_rankId = newRank; - //first rank is guildmaster, prevent loss leader rights - if (m_Ranks.empty()) - rankRights |= GR_RIGHT_ALL; + // Update rank information in player's field, if he is online. + if (Player *player = FindPlayer()) + player->SetRank(newRank); - AddRank(rankName,rankRights,rankMoney); - }while (guildRanksResult->NextRow()); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_GUILD_MEMBER_RANK); + stmt->setUInt8 (0, newRank); + stmt->setUInt32(1, GUID_LOPART(m_guid)); + CharacterDatabase.Execute(stmt); +} + +void Guild::Member::SaveToDB(SQLTransaction& trans) const +{ + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_GUILD_MEMBER); + stmt->setUInt32(0, m_guildId); + stmt->setUInt32(1, GUID_LOPART(m_guid)); + stmt->setUInt8 (2, m_rankId); + stmt->setString(3, m_publicNote); + stmt->setString(4, m_officerNote); + _CharacterExecutePreparedStatement(trans, stmt); +} - if (m_Ranks.size() < GUILD_RANKS_MIN_COUNT) // if too few ranks, renew them +// Loads member's data from database. +// If member has broken fields (level, class) returns false. +// In this case member has to be removed from guild. +bool Guild::Member::LoadFromDB(Field* fields) +{ + m_publicNote = fields[3].GetString(); + m_officerNote = fields[4].GetString(); + m_bankRemaining[GUILD_BANK_MAX_TABS].resetTime = fields[5].GetUInt32(); + m_bankRemaining[GUILD_BANK_MAX_TABS].value = fields[6].GetUInt32(); + for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i) { - m_Ranks.clear(); - sLog.outError("Guild %u has broken `guild_rank` data, creating new...", m_Id); - CreateDefaultGuildRanks(DEFAULT_LOCALE); - broken_ranks = false; + m_bankRemaining[i].resetTime = fields[7 + i * 2].GetUInt32(); + m_bankRemaining[i].value = fields[8 + i * 2].GetUInt32(); } - // guild_rank have wrong numbered ranks, repair - if (broken_ranks) + + SetStats(fields[19].GetString(), + fields[20].GetUInt8(), + fields[21].GetUInt8(), + fields[22].GetUInt32(), + fields[23].GetUInt32()); + m_logoutTime = fields[24].GetUInt64(); + + if (!CheckStats()) + return false; + + if (!m_zoneId) { - sLog.outError("Guild %u has broken `guild_rank` data, repairing...", m_Id); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - trans->PAppend("DELETE FROM guild_rank WHERE guildid='%u'", m_Id); - for (size_t i = 0; i < m_Ranks.size(); ++i) - { - std::string name = m_Ranks[i].Name; - uint32 rights = m_Ranks[i].Rights; - CharacterDatabase.escape_string(name); - trans->PAppend("INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", m_Id, uint32(i), name.c_str(), rights); - } - CharacterDatabase.CommitTransaction(trans); + sLog.outError("Player (GUID: %u) has broken zone-data", GUID_LOPART(m_guid)); + m_zoneId = Player::GetZoneIdFromDB(m_guid); } - return true; } -bool Guild::LoadMembersFromDB(QueryResult guildMembersResult) +// Validate player fields. Returns false if corrupted fields are found. +bool Guild::Member::CheckStats() const { - if (!guildMembersResult) + if (m_level < 1) + { + sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`level`, deleting him from guild!", GUID_LOPART(m_guid)); return false; - - UpdateAccountsNumber(); - - do + } + if (m_class < CLASS_WARRIOR || m_class >= MAX_CLASSES) { - Field *fields = guildMembersResult->Fetch(); - //this condition will be true when all rows in QueryResult are processed and new guild without members is going to be loaded - prevent crash - if (!fields) - break; + sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`class`, deleting him from guild!", GUID_LOPART(m_guid)); + return false; + } + return true; +} - uint32 guildId = fields[0].GetUInt32(); - if (guildId < m_Id) - { - //there is in table guild_member record which doesn't have guildid in guild table, report error - sLog.outErrorDb("Guild %u does not exist but it has a record in guild_member table, deleting it!", guildId); - CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guildid = '%u'", guildId); - continue; - } +void Guild::Member::WritePacket(WorldPacket& data) const +{ + if (Player* player = FindPlayer()) + { + data << uint64(player->GetGUID()); + data << uint8(1); + data << player->GetName(); + data << uint32(m_rankId); + data << uint8(player->getLevel()); + data << uint8(player->getClass()); + data << uint8(0); // new 2.4.0 + data << uint32(player->GetZoneId()); + } + else + { + data << m_guid; + data << uint8(0); + data << m_name; + data << uint32(m_rankId); + data << uint8(m_level); + data << uint8(m_class); + data << uint8(0); // new 2.4.0 + data << uint32(m_zoneId); + data << float(float(::time(NULL) - m_logoutTime) / DAY); + } + data << m_publicNote; + data << m_officerNote; +} - if (guildId > m_Id) - //we loaded all members for this guild already, break cycle - break; - - MemberSlot newmember; - uint64 guid = MAKE_NEW_GUID(fields[1].GetUInt32(), 0, HIGHGUID_PLAYER); - newmember.RankId = fields[2].GetUInt32(); - //don't allow member to have not existing rank! - if (newmember.RankId >= m_Ranks.size()) - newmember.RankId = GetLowestRank(); - - newmember.Pnote = fields[3].GetString(); - newmember.OFFnote = fields[4].GetString(); - newmember.BankResetTimeMoney = fields[5].GetUInt32(); - newmember.BankRemMoney = fields[6].GetUInt32(); - for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i) - { - newmember.BankResetTimeTab[i] = fields[7+(2*i)].GetUInt32(); - newmember.BankRemSlotsTab[i] = fields[8+(2*i)].GetUInt32(); - } +// Decreases amount of money/slots left for today. +// If (tabId == GUILD_BANK_MAX_TABS) decrease money amount. +// Otherwise decrease remaining items amount for specified tab. +void Guild::Member::DecreaseBankRemainingValue(SQLTransaction& trans, uint8 tabId, uint32 amount) +{ + m_bankRemaining[tabId].value -= amount; - newmember.Name = fields[19].GetString(); - newmember.Level = fields[20].GetUInt8(); - newmember.Class = fields[21].GetUInt8(); - newmember.ZoneId = fields[22].GetUInt32(); - newmember.LogoutTime = fields[23].GetUInt64(); - newmember.accountId = fields[24].GetInt32(); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement( + tabId == GUILD_BANK_MAX_TABS ? + CHAR_SET_GUILD_MEMBER_BANK_REM_MONEY : + CHAR_SET_GUILD_MEMBER_BANK_REM_SLOTS0 + tabId); + stmt->setUInt32(0, m_bankRemaining[tabId].value); + stmt->setUInt32(1, m_guildId); + stmt->setUInt32(2, GUID_LOPART(m_guid)); + _CharacterExecutePreparedStatement(trans, stmt); +} - //this code will remove unexisting character guids from guild - if (newmember.Level < 1 /*|| newmember.Level > STRONG_MAX_LEVEL*/) // can be at broken `data` field - { - sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`data`, deleting him from guild!",GUID_LOPART(guid)); - CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid)); - continue; - } - if (!newmember.ZoneId) - { - sLog.outError("Player (GUID: %u) has broken zone-data", GUID_LOPART(guid)); - // here it will also try the same, to get the zone from characters-table, but additional it tries to find - // the zone through xy coords .. this is a bit redundant, but shouldn't be called often - newmember.ZoneId = Player::GetZoneIdFromDB(guid); - } - if (newmember.Class < CLASS_WARRIOR || newmember.Class >= MAX_CLASSES) // can be at broken `class` field - { - sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`class`, deleting him from guild!",GUID_LOPART(guid)); - CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid)); - continue; - } +// Get amount of money/slots left for today. +// If (tabId == GUILD_BANK_MAX_TABS) return money amount. +// Otherwise return remaining items amount for specified tab. +// If reset time was more than 24 hours ago, renew reset time and reset amount to maximum value. +uint32 Guild::Member::GetBankRemainingValue(uint8 tabId, const Guild* pGuild) const +{ + // Guild master has unlimited amount. + if (IsRank(GR_GUILDMASTER)) + return tabId == GUILD_BANK_MAX_TABS ? GUILD_WITHDRAW_MONEY_UNLIMITED : GUILD_WITHDRAW_SLOT_UNLIMITED; - members[GUID_LOPART(guid)] = newmember; + // Check rights for non-money tab. + if (tabId != GUILD_BANK_MAX_TABS) + if ((pGuild->_GetRankBankTabRights(m_rankId, tabId) & GUILD_BANK_RIGHT_VIEW_TAB) != GUILD_BANK_RIGHT_VIEW_TAB) + return 0; - }while (guildMembersResult->NextRow()); + uint32 curTime = uint32(::time(NULL) / MINUTE); // minutes + if (curTime > m_bankRemaining[tabId].resetTime + 24 * HOUR / MINUTE) + { + RemainingValue& rv = const_cast <RemainingValue&> (m_bankRemaining[tabId]); + rv.resetTime = curTime; + rv.value = tabId == GUILD_BANK_MAX_TABS ? + pGuild->_GetRankBankMoneyPerDay(m_rankId) : + pGuild->_GetRankBankTabSlotsPerDay(m_rankId, tabId); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement( + tabId == GUILD_BANK_MAX_TABS ? + CHAR_SET_GUILD_MEMBER_BANK_REM_MONEY : + CHAR_SET_GUILD_MEMBER_BANK_TIME_REM_SLOTS0 + tabId); + stmt->setUInt32(0, m_bankRemaining[tabId].resetTime); + stmt->setUInt32(1, m_bankRemaining[tabId].value); + stmt->setUInt32(2, m_guildId); + stmt->setUInt32(3, GUID_LOPART(m_guid)); + CharacterDatabase.Execute(stmt); + } + return m_bankRemaining[tabId].value; +} - if (members.empty()) - return false; +inline void Guild::Member::ResetTabTimes() +{ + for (uint8 tabId = 0; tabId < GUILD_BANK_MAX_TABS; ++tabId) + m_bankRemaining[tabId].resetTime = 0; +} - return true; +inline void Guild::Member::ResetMoneyTime() +{ + m_bankRemaining[GUILD_BANK_MAX_TABS].resetTime = 0; } -void Guild::SetMemberStats(uint64 guid) +/////////////////////////////////////////////////////////////////////////////// +// EmblemInfo +void EmblemInfo::LoadFromDB(Field* fields) { - MemberList::iterator itr = members.find(GUID_LOPART(guid)); - if (itr == members.end()) - return; + m_style = fields[3].GetUInt32(); + m_color = fields[4].GetUInt32(); + m_borderStyle = fields[5].GetUInt32(); + m_borderColor = fields[6].GetUInt32(); + m_backgroundColor = fields[7].GetUInt32(); +} - Player *pl = ObjectAccessor::FindPlayer(guid); - if (!pl) - return; - itr->second.Name = pl->GetName(); - itr->second.Level = pl->getLevel(); - itr->second.Class = pl->getClass(); - itr->second.ZoneId = pl->GetZoneId(); +void EmblemInfo::WritePacket(WorldPacket& data) const +{ + data << uint32(m_style); + data << uint32(m_color); + data << uint32(m_borderStyle); + data << uint32(m_borderColor); + data << uint32(m_backgroundColor); } -void Guild::SetLeader(uint64 guid) +void EmblemInfo::SaveToDB(uint32 guildId) const { - m_LeaderGuid = guid; - ChangeRank(guid, GR_GUILDMASTER); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_GUILD_EMBLEM_INFO); + stmt->setUInt32(0, m_style); + stmt->setUInt32(1, m_color); + stmt->setUInt32(2, m_borderStyle); + stmt->setUInt32(3, m_borderColor); + stmt->setUInt32(4, m_backgroundColor); + stmt->setUInt32(5, guildId); + CharacterDatabase.Execute(stmt); +} - CharacterDatabase.PExecute("UPDATE guild SET leaderguid='%u' WHERE guildid='%u'", GUID_LOPART(guid), m_Id); +/////////////////////////////////////////////////////////////////////////////// +// MoveItemData +bool Guild::MoveItemData::CheckItem(uint32& splitedAmount) +{ + ASSERT(m_pItem); + if (splitedAmount > m_pItem->GetCount()) + return false; + if (splitedAmount == m_pItem->GetCount()) + splitedAmount = 0; + return true; } -void Guild::DelMember(uint64 guid, bool isDisbanding, bool isKicked) +uint8 Guild::MoveItemData::CanStore(Item* pItem, bool swap, bool sendError) { - Player *player = sObjectMgr.GetPlayer(guid); - sScriptMgr.OnGuildRemoveMember(this, player, isDisbanding, isKicked); + m_vec.clear(); + uint8 msg = _CanStore(pItem, swap); + if (sendError && msg != EQUIP_ERR_OK) + m_pPlayer->SendEquipError(msg, pItem); + return (msg == EQUIP_ERR_OK); +} - //guild master can be deleted when loading guild and guid doesn't exist in characters table - //or when he is removed from guild by gm command - if (m_LeaderGuid == guid && !isDisbanding) +bool Guild::MoveItemData::CloneItem(uint32 count) +{ + ASSERT(m_pItem); + m_pClonedItem = m_pItem->CloneItem(count); + if (!m_pClonedItem) { - MemberSlot* oldLeader = NULL; - MemberSlot* best = NULL; - uint64 newLeaderGUID = 0; - for (Guild::MemberList::iterator i = members.begin(); i != members.end(); ++i) - { - if (i->first == GUID_LOPART(guid)) - { - oldLeader = &(i->second); - continue; - } + m_pPlayer->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, m_pItem); + return false; + } + return true; +} - if (!best || best->RankId > i->second.RankId) - { - best = &(i->second); - newLeaderGUID = i->first; - } - } - if (!best) - { - Disband(); - return; - } +void Guild::MoveItemData::LogAction(MoveItemData* pFrom) const +{ + ASSERT(pFrom->GetItem()); - SetLeader(newLeaderGUID); + sScriptMgr.OnGuildItemMove(m_pGuild, m_pPlayer, pFrom->GetItem(), + pFrom->IsBank(), pFrom->GetContainer(), pFrom->GetSlotId(), + IsBank(), GetContainer(), GetSlotId()); +} - // If player not online data in data field will be loaded from guild tabs no need to update it !! - if (Player *newLeader = sObjectMgr.GetPlayer(newLeaderGUID)) - newLeader->SetRank(GR_GUILDMASTER); +inline void Guild::MoveItemData::CopySlots(SlotIds& ids) const +{ + for (ItemPosCountVec::const_iterator itr = m_vec.begin(); itr != m_vec.end(); ++itr) + ids.insert(uint8(itr->pos)); +} - // when leader non-exist (at guild load with deleted leader only) not send broadcasts - if (oldLeader) +/////////////////////////////////////////////////////////////////////////////// +// PlayerMoveItemData +bool Guild::PlayerMoveItemData::InitItem() +{ + m_pItem = m_pPlayer->GetItemByPos(m_container, m_slotId); + if (m_pItem) + { + // Anti-WPE protection. Do not move non-empty bags to bank. + if (m_pItem->IsBag() && !((Bag*)m_pItem)->IsEmpty()) { - BroadcastEvent(GE_LEADER_CHANGED, 0, 2, oldLeader->Name, best->Name, ""); - - BroadcastEvent(GE_LEFT, guid, 1, oldLeader->Name, "", ""); + m_pPlayer->SendEquipError(EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS, m_pItem); + m_pItem = NULL; + } + // Bound items cannot be put into bank. + else if (!m_pItem->CanBeTraded()) + { + m_pPlayer->SendEquipError(EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, m_pItem); + m_pItem = NULL; } } + return (m_pItem != NULL); +} - members.erase(GUID_LOPART(guid)); - - // If player not online data in data field will be loaded from guild tabs no need to update it !! - if (player) +void Guild::PlayerMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* /*pOther*/, uint32 splitedAmount) +{ + if (splitedAmount) { - player->SetInGuild(0); - player->SetRank(0); + m_pItem->SetCount(m_pItem->GetCount() - splitedAmount); + m_pItem->SetState(ITEM_CHANGED, m_pPlayer); + m_pPlayer->SaveInventoryAndGoldToDB(trans); + } + else + { + m_pPlayer->MoveItemFromInventory(m_container, m_slotId, true); + m_pItem->DeleteFromInventoryDB(trans); + m_pItem = NULL; } - - CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid)); - - if (!isDisbanding) - UpdateAccountsNumber(); } -void Guild::ChangeRank(uint64 guid, uint32 newRank) +Item* Guild::PlayerMoveItemData::StoreItem(SQLTransaction& trans, Item* pItem) { - MemberList::iterator itr = members.find(GUID_LOPART(guid)); - if (itr != members.end()) - itr->second.RankId = newRank; - - Player *player = sObjectMgr.GetPlayer(guid); - // If player not online data in data field will be loaded from guild tabs no need to update it !! - if (player) - player->SetRank(newRank); + ASSERT(pItem); + m_pPlayer->MoveItemToInventory(m_vec, pItem, true); + m_pPlayer->SaveInventoryAndGoldToDB(trans); + return pItem; +} - CharacterDatabase.PExecute("UPDATE guild_member SET rank='%u' WHERE guid='%u'", newRank, GUID_LOPART(guid)); +void Guild::PlayerMoveItemData::LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const +{ + ASSERT(pFrom); + // Bank -> Char + m_pGuild->_LogBankEvent(trans, GUILD_BANK_LOG_WITHDRAW_ITEM, pFrom->GetContainer(), m_pPlayer->GetGUIDLow(), + pFrom->GetItem()->GetEntry(), count); } -void Guild::SetPNOTE(uint64 guid,std::string pnote) +inline uint8 Guild::PlayerMoveItemData::_CanStore(Item* pItem, bool swap) { - MemberList::iterator itr = members.find(GUID_LOPART(guid)); - if (itr == members.end()) - return; + return m_pPlayer->CanStoreItem(m_container, m_slotId, m_vec, pItem, swap); +} - itr->second.Pnote = pnote; +/////////////////////////////////////////////////////////////////////////////// +// BankMoveItemData +bool Guild::BankMoveItemData::InitItem() +{ + m_pItem = m_pGuild->_GetItem(m_container, m_slotId); + return (m_pItem != NULL); +} - // pnote now can be used for encoding to DB - CharacterDatabase.escape_string(pnote); - CharacterDatabase.PExecute("UPDATE guild_member SET pnote = '%s' WHERE guid = '%u'", pnote.c_str(), itr->first); +bool Guild::BankMoveItemData::HasStoreRights(MoveItemData* pOther) const +{ + ASSERT(pOther); + // Do not check rights if item is being swapped within the same bank tab + if (pOther->IsBank() && pOther->GetContainer() == m_container) + return true; + return m_pGuild->_MemberHasTabRights(m_pPlayer->GetGUID(), m_container, GUILD_BANK_RIGHT_DEPOSIT_ITEM); } -void Guild::SetOFFNOTE(uint64 guid,std::string offnote) +bool Guild::BankMoveItemData::HasWithdrawRights(MoveItemData* pOther) const { - MemberList::iterator itr = members.find(GUID_LOPART(guid)); - if (itr == members.end()) - return; - itr->second.OFFnote = offnote; - // offnote now can be used for encoding to DB - CharacterDatabase.escape_string(offnote); - CharacterDatabase.PExecute("UPDATE guild_member SET offnote = '%s' WHERE guid = '%u'", offnote.c_str(), itr->first); + ASSERT(pOther); + // Do not check rights if item is being swapped within the same bank tab + if (pOther->IsBank() && pOther->GetContainer() == m_container) + return true; + return (m_pGuild->_GetMemberRemainingSlots(m_pPlayer->GetGUID(), m_container) != 0); } -void Guild::BroadcastToGuild(WorldSession *session, const std::string& msg, uint32 language) +void Guild::BankMoveItemData::RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount) { - if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(),GR_RIGHT_GCHATSPEAK)) + ASSERT(m_pItem); + if (splitedAmount) { - WorldPacket data; - ChatHandler(session).FillMessageData(&data, CHAT_MSG_GUILD, language, 0, msg.c_str()); - - for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) - { - Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); - - if (pl && pl->GetSession() && HasRankRight(pl->GetRank(),GR_RIGHT_GCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow())) - pl->GetSession()->SendPacket(&data); - } + m_pItem->SetCount(m_pItem->GetCount() - splitedAmount); + m_pItem->FSetState(ITEM_CHANGED); + m_pItem->SaveToDB(trans); } + else + { + m_pGuild->_RemoveItem(trans, m_container, m_slotId); + m_pItem = NULL; + } + // Decrease amount of player's remaining items (if item is moved to different tab or to player) + if (!pOther->IsBank() || pOther->GetContainer() != m_container) + m_pGuild->_DecreaseMemberRemainingSlots(trans, m_pPlayer->GetGUID(), m_container); } -void Guild::BroadcastToOfficers(WorldSession *session, const std::string& msg, uint32 language) +Item* Guild::BankMoveItemData::StoreItem(SQLTransaction& trans, Item* pItem) { - if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(), GR_RIGHT_OFFCHATSPEAK)) - { - for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) - { - WorldPacket data; - ChatHandler::FillMessageData(&data, session, CHAT_MSG_OFFICER, language, NULL, 0, msg.c_str(), NULL); + if (!pItem) + return NULL; + + BankTab* pTab = m_pGuild->GetBankTab(m_container); + if (!pTab) + return NULL; - Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); + Item* pLastItem = pItem; + for (ItemPosCountVec::const_iterator itr = m_vec.begin(); itr != m_vec.end(); ) + { + ItemPosCount pos(*itr); + ++itr; - if (pl && pl->GetSession() && HasRankRight(pl->GetRank(),GR_RIGHT_OFFCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow())) - pl->GetSession()->SendPacket(&data); - } + sLog.outDebug("GUILD STORAGE: StoreItem tab = %u, slot = %u, item = %u, count = %u", + m_container, m_slotId, pItem->GetEntry(), pItem->GetCount()); + pLastItem = _StoreItem(trans, pTab, pItem, pos, itr != m_vec.end()); } + return pLastItem; } -void Guild::BroadcastPacket(WorldPacket *packet) +void Guild::BankMoveItemData::LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const { - for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) - { - Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); - if (player) - player->GetSession()->SendPacket(packet); - } + ASSERT(pFrom->GetItem()); + if (pFrom->IsBank()) + // Bank -> Bank + m_pGuild->_LogBankEvent(trans, GUILD_BANK_LOG_MOVE_ITEM, pFrom->GetContainer(), m_pPlayer->GetGUIDLow(), + pFrom->GetItem()->GetEntry(), count, m_container); + else + // Char -> Bank + m_pGuild->_LogBankEvent(trans, GUILD_BANK_LOG_DEPOSIT_ITEM, m_container, m_pPlayer->GetGUIDLow(), + pFrom->GetItem()->GetEntry(), count); +} + +void Guild::BankMoveItemData::LogAction(MoveItemData* pFrom) const +{ + MoveItemData::LogAction(pFrom); + if (!pFrom->IsBank() && sWorld.getBoolConfig(CONFIG_GM_LOG_TRADE) && m_pPlayer->GetSession()->GetSecurity() > SEC_PLAYER) // TODO: move to scripts + sLog.outCommand(m_pPlayer->GetSession()->GetAccountId(), + "GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u)", + m_pPlayer->GetName(), m_pPlayer->GetSession()->GetAccountId(), + pFrom->GetItem()->GetProto()->Name1, pFrom->GetItem()->GetEntry(), pFrom->GetItem()->GetCount(), + m_pGuild->GetId()); } -void Guild::BroadcastPacketToRank(WorldPacket *packet, uint32 rankId) +Item* Guild::BankMoveItemData::_StoreItem(SQLTransaction& trans, BankTab* pTab, Item *pItem, ItemPosCount& pos, bool clone) const { - for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) + uint8 slotId = uint8(pos.pos); + uint32 count = pos.count; + if (Item* pItemDest = pTab->GetItem(slotId)) { - if (itr->second.RankId == rankId) + pItemDest->SetCount(pItemDest->GetCount() + count); + pItemDest->FSetState(ITEM_CHANGED); + pItemDest->SaveToDB(trans); + if (!clone) { - Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); - if (player) - player->GetSession()->SendPacket(packet); + pItem->RemoveFromWorld(); + pItem->DeleteFromDB(trans); + delete pItem; } + return pItemDest; } -} -void Guild::CreateRank(std::string name_,uint32 rights) -{ - if (m_Ranks.size() >= GUILD_RANKS_MAX_COUNT) - return; + if (clone) + pItem = pItem->CloneItem(count); + else + pItem->SetCount(count); - // ranks are sequence 0,1,2,... where 0 means guildmaster - uint32 new_rank_id = m_Ranks.size(); + if (pItem && pTab->SetItem(trans, slotId, pItem)) + return pItem; - AddRank(name_, rights, 0); + return NULL; +} - //existing records in db should be deleted before calling this procedure and m_PurchasedTabs must be loaded already +// Tries to reserve space for source item. +// If item in destination slot exists it must be the item of the same entry +// and stack must have enough space to take at least one item. +// Returns false if destination item specified and it cannot be used to reserve space. +bool Guild::BankMoveItemData::_ReserveSpace(uint8 slotId, Item* pItem, Item* pItemDest, uint32& count) +{ + uint32 requiredSpace = pItem->GetMaxStackCount(); + if (pItemDest) + { + // Make sure source and destination items match and destination item has space for more stacks. + if (pItemDest->GetEntry() != pItem->GetEntry() || pItemDest->GetCount() >= pItem->GetMaxStackCount()) + return false; + requiredSpace -= pItemDest->GetCount(); + } + // Let's not be greedy, reserve only required space + requiredSpace = std::min(requiredSpace, count); - for (uint32 i = 0; i < uint32(GetPurchasedTabs()); ++i) + // Reserve space + ItemPosCount pos(slotId, requiredSpace); + if (!pos.isContainedIn(m_vec)) { - //create bank rights with 0 - CharacterDatabase.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid) VALUES ('%u','%u','%u')", m_Id, i, new_rank_id); + m_vec.push_back(pos); + count -= requiredSpace; } - // name now can be used for encoding to DB - CharacterDatabase.escape_string(name_); - CharacterDatabase.PExecute("INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", m_Id, new_rank_id, name_.c_str(), rights); + return true; } -void Guild::AddRank(const std::string& name_,uint32 rights, uint32 money) +void Guild::BankMoveItemData::_CanStoreItemInTab(Item* pItem, uint8 skipSlotId, bool merge, uint32& count) { - m_Ranks.push_back(RankInfo(name_,rights,money)); + for (uint8 slotId = 0; (slotId < GUILD_BANK_MAX_SLOTS) && (count > 0); ++slotId) + { + // Skip slot already processed in _CanStore (when destination slot was specified) + if (slotId == skipSlotId) + continue; + + Item* pItemDest = m_pGuild->_GetItem(m_container, slotId); + if (pItemDest == pItem) + pItemDest = NULL; + + // If merge skip empty, if not merge skip non-empty + if ((pItemDest != NULL) != merge) + continue; + + _ReserveSpace(slotId, pItem, pItemDest, count); + } } -void Guild::DelRank() +uint8 Guild::BankMoveItemData::_CanStore(Item* pItem, bool swap) { - // client won't allow to have less than GUILD_RANKS_MIN_COUNT ranks in guild - if (m_Ranks.size() <= GUILD_RANKS_MIN_COUNT) - return; + sLog.outDebug("GUILD STORAGE: CanStore() tab = %u, slot = %u, item = %u, count = %u", + m_container, m_slotId, pItem->GetEntry(), pItem->GetCount()); + + uint32 count = pItem->GetCount(); + // Soulbound items cannot be moved + if (pItem->IsSoulBound()) + return EQUIP_ERR_CANT_DROP_SOULBOUND; + + // Make sure destination bank tab exists + if (m_container >= m_pGuild->_GetPurchasedTabsSize()) + return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; - // delete lowest guild_rank - uint32 rank = GetLowestRank(); - CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE rid >= '%u' AND guildid='%u'", rank, m_Id); + // Slot explicitely specified. Check it. + if (m_slotId != NULL_SLOT) + { + Item* pItemDest = m_pGuild->_GetItem(m_container, m_slotId); + // Ignore swapped item (this slot will be empty after move) + if ((pItemDest == pItem) || swap) + pItemDest = NULL; + + if (!_ReserveSpace(m_slotId, pItem, pItemDest, count)) + return EQUIP_ERR_ITEM_CANT_STACK; - m_Ranks.pop_back(); + if (count == 0) + return EQUIP_ERR_OK; + } + + // Slot was not specified or it has not enough space for all the items in stack + // Search for stacks to merge with + if (pItem->GetMaxStackCount() > 1) + { + _CanStoreItemInTab(pItem, m_slotId, true, count); + if (count == 0) + return EQUIP_ERR_OK; + } + + // Search free slot for item + _CanStoreItemInTab(pItem, m_slotId, false, count); + if (count == 0) + return EQUIP_ERR_OK; + + return EQUIP_ERR_BANK_FULL; } -std::string Guild::GetRankName(uint32 rankId) +/////////////////////////////////////////////////////////////////////////////// +// Guild +Guild::Guild() : m_id(0), m_leaderGuid(0), m_createdDate(0), m_accountsNumber(0), m_bankMoney(0), m_eventLog(NULL) { - if (rankId >= m_Ranks.size()) - return "<unknown>"; - - return m_Ranks[rankId].Name; + memset(&m_bankEventLog, 0, (GUILD_BANK_MAX_TABS + 1) * sizeof(LogHolder*)); } -uint32 Guild::GetRankRights(uint32 rankId) +Guild::~Guild() { - if (rankId >= m_Ranks.size()) - return 0; + SQLTransaction temp(NULL); + _DeleteBankItems(temp); - return m_Ranks[rankId].Rights; + // Cleanup + if (m_eventLog) + delete m_eventLog; + for (uint8 tabId = 0; tabId <= GUILD_BANK_MAX_TABS; ++tabId) + if (m_bankEventLog[tabId]) + delete m_bankEventLog[tabId]; + for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + delete itr->second; } -void Guild::SetRankName(uint32 rankId, std::string name_) +// Creates new guild with default data and saves it to database. +bool Guild::Create(Player* pLeader, const std::string& name) { - if (rankId >= m_Ranks.size()) - return; + // Check if guild with such name already exists + if (sObjectMgr.GetGuildByName(name)) + return false; - m_Ranks[rankId].Name = name_; + WorldSession* pLeaderSession = pLeader->GetSession(); + if (!pLeaderSession) + return false; - // name now can be used for encoding to DB - CharacterDatabase.escape_string(name_); - CharacterDatabase.PExecute("UPDATE guild_rank SET rname='%s' WHERE rid='%u' AND guildid='%u'", name_.c_str(), rankId, m_Id); -} + m_id = sObjectMgr.GenerateGuildId(); + m_leaderGuid = pLeader->GetGUID(); + m_name = name; + m_info = ""; + m_motd = "No message set."; + m_bankMoney = 0; + m_createdDate = ::time(NULL); + _CreateLogHolders(); -void Guild::SetRankRights(uint32 rankId, uint32 rights) -{ - if (rankId >= m_Ranks.size()) - return; + sLog.outDebug("GUILD: creating guild [%s] for leader %s (%u)", + name.c_str(), pLeader->GetName(), GUID_LOPART(m_leaderGuid)); - m_Ranks[rankId].Rights = rights; + PreparedStatement* stmt = NULL; + SQLTransaction trans = CharacterDatabase.BeginTransaction(); - CharacterDatabase.PExecute("UPDATE guild_rank SET rights='%u' WHERE rid='%u' AND guildid='%u'", rights, rankId, m_Id); -} + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_MEMBERS); + stmt->setUInt32(0, m_id); + trans->Append(stmt); + + uint8 index = 0; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_GUILD); + stmt->setUInt32( index, m_id); + stmt->setString(++index, name); + stmt->setUInt32(++index, GUID_LOPART(m_leaderGuid)); + stmt->setString(++index, m_info); + stmt->setString(++index, m_motd); + stmt->setUInt64(++index, uint64(m_createdDate)); + stmt->setUInt32(++index, m_emblemInfo.GetStyle()); + stmt->setUInt32(++index, m_emblemInfo.GetColor()); + stmt->setUInt32(++index, m_emblemInfo.GetBorderStyle()); + stmt->setUInt32(++index, m_emblemInfo.GetBorderColor()); + stmt->setUInt32(++index, m_emblemInfo.GetBackgroundColor()); + stmt->setUInt64(++index, m_bankMoney); + trans->Append(stmt); -int32 Guild::GetRank(uint32 LowGuid) -{ - MemberList::const_iterator itr = members.find(LowGuid); - if (itr == members.end()) - return -1; + CharacterDatabase.CommitTransaction(trans); + // Create default ranks + _CreateDefaultGuildRanks(pLeaderSession->GetSessionDbLocaleIndex()); + // Add guildmaster + bool ret = AddMember(m_leaderGuid, GR_GUILDMASTER); + if (ret) + // Call scripts on successful create + sScriptMgr.OnGuildCreate(this, pLeader, name); - return itr->second.RankId; + return ret; } +// Disbands guild and deletes all related data from database void Guild::Disband() { + // Call scripts before guild data removed from database sScriptMgr.OnGuildDisband(this); - BroadcastEvent(GE_DISBANDED, 0, 0, "", "", ""); - while (!members.empty()) + _BroadcastEvent(GE_DISBANDED, 0); + // Remove all members + while (!m_members.empty()) { - MemberList::const_iterator itr = members.begin(); - DelMember(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER), true); + Members::const_iterator itr = m_members.begin(); + DeleteMember(itr->second->GetGUID(), true); } + PreparedStatement* stmt = NULL; SQLTransaction trans = CharacterDatabase.BeginTransaction(); - trans->PAppend("DELETE FROM guild WHERE guildid = '%u'", m_Id); - trans->PAppend("DELETE FROM guild_rank WHERE guildid = '%u'", m_Id); - trans->PAppend("DELETE FROM guild_bank_tab WHERE guildid = '%u'", m_Id); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD); + stmt->setUInt32(0, m_id); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_RANKS); + stmt->setUInt32(0, m_id); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_TABS); + stmt->setUInt32(0, m_id); + trans->Append(stmt); + + // Free bank tab used memory and delete items stored in them + _DeleteBankItems(trans, true); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_ITEMS); + stmt->setUInt32(0, m_id); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_RIGHTS); + stmt->setUInt32(0, m_id); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_EVENTLOGS); + stmt->setUInt32(0, m_id); + trans->Append(stmt); - //Free bank tab used memory and delete items stored in them - DeleteGuildBankItems(trans, true); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_EVENTLOGS); + stmt->setUInt32(0, m_id); + trans->Append(stmt); - trans->PAppend("DELETE FROM guild_bank_item WHERE guildid = '%u'", m_Id); - trans->PAppend("DELETE FROM guild_bank_right WHERE guildid = '%u'", m_Id); - trans->PAppend("DELETE FROM guild_bank_eventlog WHERE guildid = '%u'", m_Id); - trans->PAppend("DELETE FROM guild_eventlog WHERE guildid = '%u'", m_Id); CharacterDatabase.CommitTransaction(trans); - sObjectMgr.RemoveGuild(m_Id); + sObjectMgr.RemoveGuild(m_id); } -void Guild::Roster(WorldSession *session /*= NULL*/) +/////////////////////////////////////////////////////////////////////////////// +// HANDLE CLIENT COMMANDS +void Guild::HandleRoster(WorldSession *session /*= NULL*/) { - // we can only guess size - WorldPacket data(SMSG_GUILD_ROSTER, (4+MOTD.length()+1+GINFO.length()+1+4+m_Ranks.size()*(4+4+GUILD_BANK_MAX_TABS*(4+4))+members.size()*50)); - data << (uint32)members.size(); - data << MOTD; - data << GINFO; + // Guess size + WorldPacket data(SMSG_GUILD_ROSTER, (4 + m_motd.length() + 1 + m_info.length() + 1 + 4 + _GetRanksSize() * (4 + 4 + GUILD_BANK_MAX_TABS * (4 + 4)) + m_members.size() * 50)); + data << uint32(m_members.size()); + data << m_motd; + data << m_info; + + data << uint32(_GetRanksSize()); + for (Ranks::const_iterator ritr = m_ranks.begin(); ritr != m_ranks.end(); ++ritr) + ritr->WritePacket(data); + + for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + itr->second->WritePacket(data); - data << (uint32)m_Ranks.size(); - for (RankList::const_iterator ritr = m_Ranks.begin(); ritr != m_Ranks.end(); ++ritr) - { - data << uint32(ritr->Rights); - data << uint32(ritr->BankMoneyPerDay); // count of: withdraw gold(gold/day) Note: in game set gold, in packet set bronze. - for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) - { - data << uint32(ritr->TabRight[i]); // for TAB_i rights: view tabs = 0x01, deposit items =0x02 - data << uint32(ritr->TabSlotPerDay[i]); // for TAB_i count of: withdraw items(stack/day) - } - } - for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) - { - if (Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER))) - { - data << uint64(pl->GetGUID()); - data << uint8(1); - data << pl->GetName(); - data << uint32(itr->second.RankId); - data << uint8(pl->getLevel()); - data << uint8(pl->getClass()); - data << uint8(0); // new 2.4.0 - data << uint32(pl->GetZoneId()); - data << itr->second.Pnote; - data << itr->second.OFFnote; - } - else - { - data << uint64(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); - data << uint8(0); - data << itr->second.Name; - data << uint32(itr->second.RankId); - data << uint8(itr->second.Level); - data << uint8(itr->second.Class); - data << uint8(0); // new 2.4.0 - data << uint32(itr->second.ZoneId); - data << float(float(time(NULL)-itr->second.LogoutTime) / DAY); - data << itr->second.Pnote; - data << itr->second.OFFnote; - } - } if (session) session->SendPacket(&data); else @@ -781,1372 +1229,1522 @@ void Guild::Roster(WorldSession *session /*= NULL*/) sLog.outDebug("WORLD: Sent (SMSG_GUILD_ROSTER)"); } -void Guild::Query(WorldSession *session) +void Guild::HandleQuery(WorldSession *session) { - WorldPacket data(SMSG_GUILD_QUERY_RESPONSE, (8*32+200));// we can only guess size + WorldPacket data(SMSG_GUILD_QUERY_RESPONSE, 8 * 32 + 200); // Guess size - data << uint32(m_Id); - data << m_Name; + data << uint32(m_id); + data << m_name; - for (size_t i = 0 ; i < GUILD_RANKS_MAX_COUNT; ++i) // show always 10 ranks + for (uint8 i = 0 ; i < GUILD_RANKS_MAX_COUNT; ++i) // Alwayse show 10 ranks { - if (i < m_Ranks.size()) - data << m_Ranks[i].Name; + if (i < _GetRanksSize()) + data << m_ranks[i].GetName(); else - data << (uint8)0; // null string + data << uint8(0); // Empty string } - data << uint32(m_EmblemStyle); - data << uint32(m_EmblemColor); - data << uint32(m_BorderStyle); - data << uint32(m_BorderColor); - data << uint32(m_BackgroundColor); - data << uint32(0); // something new in WotLK + m_emblemInfo.WritePacket(data); + data << uint32(0); // Something new in WotLK session->SendPacket(&data); sLog.outDebug("WORLD: Sent (SMSG_GUILD_QUERY_RESPONSE)"); } -void Guild::SetEmblem(uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor) -{ - m_EmblemStyle = emblemStyle; - m_EmblemColor = emblemColor; - m_BorderStyle = borderStyle; - m_BorderColor = borderColor; - m_BackgroundColor = backgroundColor; - - CharacterDatabase.PExecute("UPDATE guild SET EmblemStyle=%u, EmblemColor=%u, BorderStyle=%u, BorderColor=%u, BackgroundColor=%u WHERE guildid = %u", m_EmblemStyle, m_EmblemColor, m_BorderStyle, m_BorderColor, m_BackgroundColor, m_Id); -} - -void Guild::UpdateLogoutTime(uint64 guid) +void Guild::HandleSetMOTD(WorldSession* session, const std::string& motd) { - MemberList::iterator itr = members.find(GUID_LOPART(guid)); - if (itr == members.end()) + if (m_motd == motd) return; - itr->second.LogoutTime = time(NULL); -} + // Player must have rights to set MOTD + if (!_HasRankRight(session->GetPlayer(), GR_RIGHT_SETMOTD)) + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_PERMISSIONS); + else + { + m_motd = motd; -/** - * Updates the number of accounts that are in the guild - * A player may have many characters in the guild, but with the same account - */ -void Guild::UpdateAccountsNumber() -{ - // We use a set to be sure each element will be unique - std::set<uint32> accountsIdSet; - for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) - accountsIdSet.insert(itr->second.accountId); + sScriptMgr.OnGuildMOTDChanged(this, motd); - m_accountsNumber = accountsIdSet.size(); -} + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_GUILD_MOTD); + stmt->setString(0, motd); + stmt->setUInt32(1, m_id); + CharacterDatabase.Execute(stmt); -// ************************************************* -// Guild Eventlog part -// ************************************************* -// Display guild eventlog -void Guild::DisplayGuildEventLog(WorldSession *session) -{ - // Sending result - WorldPacket data(MSG_GUILD_EVENT_LOG_QUERY, 0); - // count, max count == 100 - data << uint8(m_GuildEventLog.size()); - for (GuildEventLog::const_iterator itr = m_GuildEventLog.begin(); itr != m_GuildEventLog.end(); ++itr) - { - // Event type - data << uint8(itr->EventType); - // Player 1 - data << uint64(itr->PlayerGuid1); - // Player 2 not for left/join guild events - if (itr->EventType != GUILD_EVENT_LOG_JOIN_GUILD && itr->EventType != GUILD_EVENT_LOG_LEAVE_GUILD) - data << uint64(itr->PlayerGuid2); - // New Rank - only for promote/demote guild events - if (itr->EventType == GUILD_EVENT_LOG_PROMOTE_PLAYER || itr->EventType == GUILD_EVENT_LOG_DEMOTE_PLAYER) - data << uint8(itr->NewRank); - // Event timestamp - data << uint32(time(NULL)-itr->TimeStamp); + _BroadcastEvent(GE_MOTD, 0, motd.c_str()); } - session->SendPacket(&data); - sLog.outDebug("WORLD: Sent (MSG_GUILD_EVENT_LOG_QUERY)"); } -// Add entry to guild eventlog -void Guild::LogGuildEvent(uint8 EventType, uint32 PlayerGuid1, uint32 PlayerGuid2, uint8 NewRank) +void Guild::HandleSetInfo(WorldSession* session, const std::string& info) { - GuildEventLogEntry NewEvent; - // Create event - NewEvent.EventType = EventType; - NewEvent.PlayerGuid1 = PlayerGuid1; - NewEvent.PlayerGuid2 = PlayerGuid2; - NewEvent.NewRank = NewRank; - NewEvent.TimeStamp = uint32(time(NULL)); - // Count new LogGuid - m_GuildEventLogNextGuid = (m_GuildEventLogNextGuid + 1) % sWorld.getIntConfig(CONFIG_GUILD_EVENT_LOG_COUNT); - // Check max records limit - if (m_GuildEventLog.size() >= GUILD_EVENTLOG_MAX_RECORDS) - m_GuildEventLog.pop_front(); - // Add event to list - m_GuildEventLog.push_back(NewEvent); - // Save event to DB - CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid='%u' AND LogGuid='%u'", m_Id, m_GuildEventLogNextGuid); - CharacterDatabase.PExecute("INSERT INTO guild_eventlog (guildid, LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','" UI64FMTD "')", - m_Id, m_GuildEventLogNextGuid, uint32(NewEvent.EventType), NewEvent.PlayerGuid1, NewEvent.PlayerGuid2, uint32(NewEvent.NewRank), NewEvent.TimeStamp); -} - -// ************************************************* -// Guild Bank part -// ************************************************* -// Bank content related -void Guild::DisplayGuildBankContent(WorldSession *session, uint8 TabId) -{ - GuildBankTab const* tab = m_TabListMap[TabId]; - - if (!IsMemberHaveRights(session->GetPlayer()->GetGUIDLow(), TabId, GUILD_BANK_RIGHT_VIEW_TAB)) + if (m_info == info) return; - WorldPacket data(SMSG_GUILD_BANK_LIST, 1200); - - data << uint64(GetGuildBankMoney()); - data << uint8(TabId); - data << uint32(GetMemberSlotWithdrawRem(session->GetPlayer()->GetGUIDLow(), TabId)); // remaining slots for today - data << uint8(0); // Tell client that there's no tab info in this packet - - data << uint8(GUILD_BANK_MAX_SLOTS); - - for (uint8 i=0; i < GUILD_BANK_MAX_SLOTS; ++i) - AppendDisplayGuildBankSlot(data, tab, i); + // Player must have rights to set guild's info + if (!_HasRankRight(session->GetPlayer(), GR_RIGHT_MODIFY_GUILD_INFO)) + SendCommandResult(session, GUILD_CREATE_S, ERR_GUILD_PERMISSIONS); + else + { + m_info = info; - session->SendPacket(&data); + sScriptMgr.OnGuildInfoChanged(this, info); - sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_GUILD_INFO); + stmt->setString(0, info); + stmt->setUInt32(1, m_id); + CharacterDatabase.Execute(stmt); + } } -void Guild::DisplayGuildBankContentUpdate(uint8 TabId, int32 slot1, int32 slot2) +void Guild::HandleSetEmblem(WorldSession* session, const EmblemInfo& emblemInfo) { - GuildBankTab const* tab = m_TabListMap[TabId]; + Player* player = session->GetPlayer(); + if (!_IsLeader(player)) + // "Only pGuild leaders can create emblems." + SendSaveEmblemResult(session, ERR_GUILDEMBLEM_NOTGUILDMASTER); + else if (!player->HasEnoughMoney(EMBLEM_PRICE)) + // "You can't afford to do that." + SendSaveEmblemResult(session, ERR_GUILDEMBLEM_NOTENOUGHMONEY); + else + { + player->ModifyMoney(-int32(EMBLEM_PRICE)); - WorldPacket data(SMSG_GUILD_BANK_LIST, 1200); + m_emblemInfo = emblemInfo; + m_emblemInfo.SaveToDB(m_id); - data << uint64(GetGuildBankMoney()); - data << uint8(TabId); + // "Guild Emblem saved." + SendSaveEmblemResult(session, ERR_GUILDEMBLEM_SUCCESS); - size_t rempos = data.wpos(); - data << uint32(0); // item withdraw amount, will be filled later - data << uint8(0); // Tell client that there's no tab info in this packet + HandleQuery(session); + } +} - if (slot2 == -1) // single item in slot1 +void Guild::HandleSetLeader(WorldSession* session, const std::string& name) +{ + Player* player = session->GetPlayer(); + // Only leader can assign new leader + if (!_IsLeader(player)) + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_PERMISSIONS); + // Old leader must be a member of guild + else if (Member* pOldLeader = GetMember(player->GetGUID())) { - data << uint8(1); // item count - - AppendDisplayGuildBankSlot(data, tab, slot1); + // New leader must be a member of guild + if (Member* pNewLeader = GetMember(session, name)) + { + _SetLeaderGUID(pNewLeader); + pOldLeader->ChangeRank(GR_OFFICER); + _BroadcastEvent(GE_LEADER_CHANGED, 0, player->GetName(), name.c_str()); + } } - else // 2 items (in slot1 and slot2) - { - data << uint8(2); // item count + else + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_PERMISSIONS); +} - if (slot1 > slot2) - std::swap(slot1,slot2); +void Guild::HandleSetBankTabInfo(WorldSession* session, uint8 tabId, const std::string& name, const std::string& icon) +{ + if (BankTab* pTab = GetBankTab(tabId)) + { + pTab->SetInfo(name, icon); + SendBankTabsInfo(session); + _SendBankContent(session, tabId); + } +} - AppendDisplayGuildBankSlot(data, tab, slot1); - AppendDisplayGuildBankSlot(data, tab, slot2); +void Guild::HandleSetMemberNote(WorldSession* session, const std::string& name, const std::string& note, bool officer) +{ + // Player must have rights to set public/officer note + if (!_HasRankRight(session->GetPlayer(), officer ? GR_RIGHT_EOFFNOTE : GR_RIGHT_EPNOTE)) + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_PERMISSIONS); + // Noted player must be a member of guild + else if (Member* pMember = GetMember(session, name)) + { + if (officer) + pMember->SetOfficerNote(note); + else + pMember->SetPublicNote(note); + HandleRoster(session); } +} - for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) +void Guild::HandleSetRankInfo(WorldSession* session, uint8 rankId, const std::string& name, uint32 rights, uint32 moneyPerDay, GuildBankRightsAndSlotsVec rightsAndSlots) +{ + // Only leader can modify ranks + if (!_IsLeader(session->GetPlayer())) + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_PERMISSIONS); + else if (RankInfo* rankInfo = GetRankInfo(rankId)) { - Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); - if (!player) - continue; + sLog.outDebug("WORLD: Changed RankName to '%s', rights to 0x%08X", name.c_str(), rights); - if (!IsMemberHaveRights(itr->first,TabId,GUILD_BANK_RIGHT_VIEW_TAB)) - continue; + rankInfo->SetName(name); + rankInfo->SetRights(rights); + _SetRankBankMoneyPerDay(rankId, moneyPerDay); - data.put<uint32>(rempos,uint32(GetMemberSlotWithdrawRem(player->GetGUIDLow(), TabId))); + uint8 tabId = 0; + for (GuildBankRightsAndSlotsVec::const_iterator itr = rightsAndSlots.begin(); itr != rightsAndSlots.end(); ++itr) + _SetRankBankTabRightsAndSlots(rankId, tabId++, *itr); - player->GetSession()->SendPacket(&data); + HandleQuery(session); + HandleRoster(); // Broadcast for tab rights update } - - sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); } -void Guild::DisplayGuildBankContentUpdate(uint8 TabId, GuildItemPosCountVec const& slots) +void Guild::HandleBuyBankTab(WorldSession* session, uint8 tabId) { - GuildBankTab const* tab = m_TabListMap[TabId]; + if (tabId != _GetPurchasedTabsSize()) + return; - WorldPacket data(SMSG_GUILD_BANK_LIST, 1200); + uint32 tabCost = _GetGuildBankTabPrice(tabId) * GOLD; + if (!tabCost) + return; - data << uint64(GetGuildBankMoney()); - data << uint8(TabId); + Player* player = session->GetPlayer(); + if (!player->HasEnoughMoney(tabCost)) // Should not happen, this is checked by client + return; - size_t rempos = data.wpos(); - data << uint32(0); // item withdraw amount, will be filled later - data << uint8(0); // Tell client that there's no tab info in this packet + if (!_CreateNewBankTab()) + return; - data << uint8(slots.size()); // updates count + player->ModifyMoney(-int32(tabCost)); + _SetRankBankMoneyPerDay(player->GetRank(), GUILD_WITHDRAW_MONEY_UNLIMITED); + _SetRankBankTabRightsAndSlots(player->GetRank(), tabId, GuildBankRightsAndSlots(GUILD_BANK_RIGHT_FULL, GUILD_WITHDRAW_SLOT_UNLIMITED)); + HandleRoster(); // Broadcast for tab rights update + SendBankTabsInfo(session); +} - for (GuildItemPosCountVec::const_iterator itr = slots.begin(); itr != slots.end(); ++itr) - AppendDisplayGuildBankSlot(data, tab, itr->Slot); +void Guild::HandleInviteMember(WorldSession* session, const std::string& name) +{ + Player* pInvitee = sObjectAccessor.FindPlayerByName(name.c_str()); + if (!pInvitee) + { + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_PLAYER_NOT_FOUND_S, name); + return; + } - for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr) + Player* player = session->GetPlayer(); + // Do not show invitations from ignored players + if (pInvitee->GetSocial()->HasIgnore(player->GetGUIDLow())) + return; + if (!sWorld.getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && pInvitee->GetTeam() != player->GetTeam()) { - Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)); - if (!player) - continue; + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_NOT_ALLIED, name); + return; + } + // Invited player cannot be in another guild + if (pInvitee->GetGuildId()) + { + SendCommandResult(session, GUILD_INVITE_S, ERR_ALREADY_IN_GUILD_S, name); + return; + } + // Invited player cannot be invited + if (pInvitee->GetGuildIdInvited()) + { + SendCommandResult(session, GUILD_INVITE_S, ERR_ALREADY_INVITED_TO_GUILD_S, name); + return; + } + // Inviting player must have rights to invite + if (!_HasRankRight(player, GR_RIGHT_INVITE)) + { + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_PERMISSIONS); + return; + } - if (!IsMemberHaveRights(itr->first,TabId,GUILD_BANK_RIGHT_VIEW_TAB)) - continue; + sLog.outDebug("Player %s invited %s to join his Guild", player->GetName(), name.c_str()); - data.put<uint32>(rempos,uint32(GetMemberSlotWithdrawRem(player->GetGUIDLow(), TabId))); + pInvitee->SetGuildIdInvited(m_id); + _LogEvent(GUILD_EVENT_LOG_INVITE_PLAYER, player->GetGUIDLow(), pInvitee->GetGUIDLow()); - player->GetSession()->SendPacket(&data); - } + WorldPacket data(SMSG_GUILD_INVITE, 8 + 10); // Guess size + data << player->GetName(); + data << m_name; + pInvitee->GetSession()->SendPacket(&data); - sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); + sLog.outDebug("WORLD: Sent (SMSG_GUILD_INVITE)"); } -Item* Guild::GetItem(uint8 TabId, uint8 SlotId) +void Guild::HandleAcceptMember(WorldSession* session) { - if (TabId >= GetPurchasedTabs() || SlotId >= GUILD_BANK_MAX_SLOTS) - return NULL; - return m_TabListMap[TabId]->Slots[SlotId]; -} + Player* player = session->GetPlayer(); + if (!sWorld.getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && + player->GetTeam() != sObjectMgr.GetPlayerTeamByGUID(GetLeaderGUID())) + return; -// ************************************************* -// Tab related + if (AddMember(player->GetGUID())) + { + _LogEvent(GUILD_EVENT_LOG_JOIN_GUILD, player->GetGUIDLow()); + _BroadcastEvent(GE_JOINED, player->GetGUID(), player->GetName()); + } +} -void Guild::DisplayGuildBankTabsInfo(WorldSession *session) +void Guild::HandleLeaveMember(WorldSession* session) { - WorldPacket data(SMSG_GUILD_BANK_LIST, 500); + Player* player = session->GetPlayer(); + // If leader is leaving + if (_IsLeader(player)) + { + if (m_members.size() > 1) + // Leader cannot leave if he is not the last member + SendCommandResult(session, GUILD_QUIT_S, ERR_GUILD_LEADER_LEAVE); + else + // Guild is disbanded if leader leaves. + Disband(); + } + else + { + DeleteMember(player->GetGUID(), false, false); - data << uint64(GetGuildBankMoney()); - data << uint8(0); // TabInfo packet must be for TabId 0 - data << uint32(GetMemberSlotWithdrawRem(session->GetPlayer()->GetGUIDLow(), 0)); - data << uint8(1); // Tell client that this packet includes tab info - data << uint8(GetPurchasedTabs()); // here is the number of tabs + _LogEvent(GUILD_EVENT_LOG_LEAVE_GUILD, player->GetGUIDLow()); + _BroadcastEvent(GE_LEFT, player->GetGUID(), player->GetName()); - for (uint8 i = 0; i < GetPurchasedTabs(); ++i) - { - data << m_TabListMap[i]->Name.c_str(); - data << m_TabListMap[i]->Icon.c_str(); + SendCommandResult(session, GUILD_QUIT_S, ERR_PLAYER_NO_MORE_IN_GUILD, m_name); } - data << uint8(0); // Do not send tab content - session->SendPacket(&data); +} - sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); +void Guild::HandleRemoveMember(WorldSession* session, const std::string& name) +{ + Player* player = session->GetPlayer(); + // Player must have rights to remove members + if (!_HasRankRight(player, GR_RIGHT_REMOVE)) + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_PERMISSIONS); + // Removed player must be a member of guild + else if (Member* pMember = GetMember(session, name)) + { + // Leader cannot be removed + if (pMember->IsRank(GR_GUILDMASTER)) + SendCommandResult(session, GUILD_QUIT_S, ERR_GUILD_LEADER_LEAVE); + // Do not allow to remove player with the same rank or higher + else if (pMember->IsRankNotLower(player->GetRank())) + SendCommandResult(session, GUILD_QUIT_S, ERR_GUILD_RANK_TOO_HIGH_S, name); + else + { + const uint64& guid = pMember->GetGUID(); + // After call to DeleteMember pointer to member becomes invalid + DeleteMember(guid, false, true); + _LogEvent(GUILD_EVENT_LOG_UNINVITE_PLAYER, player->GetGUIDLow(), GUID_LOPART(guid)); + _BroadcastEvent(GE_REMOVED, 0, name.c_str(), player->GetName()); + } + } } -void Guild::DisplayGuildBankMoneyUpdate(WorldSession *session) +void Guild::HandleUpdateMemberRank(WorldSession* session, const std::string& name, bool demote) { - WorldPacket data(SMSG_GUILD_BANK_LIST, 8+1+4+1+1); + Player* player = session->GetPlayer(); + // Player must have rights to promote + if (!_HasRankRight(player, demote ? GR_RIGHT_DEMOTE : GR_RIGHT_PROMOTE)) + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_PERMISSIONS); + // Promoted player must be a member of guild + else if (Member* pMember = GetMember(session, name)) + { + // Player cannot promote himself + if (pMember->IsSamePlayer(player->GetGUID())) + { + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_NAME_INVALID); + return; + } - data << uint64(GetGuildBankMoney()); - data << uint8(0); // TabId, default 0 - data << uint32(GetMemberSlotWithdrawRem(session->GetPlayer()->GetGUIDLow(), 0)); - data << uint8(0); // Tell that there's no tab info in this packet - data << uint8(0); // not send items - BroadcastPacket(&data); + if (demote) + { + // Player can demote only lower rank members + if (pMember->IsRankNotLower(player->GetRank())) + { + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_RANK_TOO_HIGH_S, name); + return; + } + // Lowest rank cannot be demoted + if (pMember->GetRankId() >= _GetLowestRankId()) + { + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_RANK_TOO_LOW_S, name); + return; + } + } + else + { + // Allow to promote only to lower rank than member's rank + // pMember->GetRank() + 1 is the highest rank that current player can promote to + if (pMember->IsRankNotLower(player->GetRank() + 1)) + { + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_RANK_TOO_HIGH_S, name); + return; + } + } - sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); + // When promoting player, rank is decreased, when demoting - increased + uint32 newRankId = pMember->GetRankId() + (demote ? 1 : -1); + pMember->ChangeRank(newRankId); + _LogEvent(demote ? GUILD_EVENT_LOG_DEMOTE_PLAYER : GUILD_EVENT_LOG_PROMOTE_PLAYER, player->GetGUIDLow(), GUID_LOPART(pMember->GetGUID()), newRankId); + _BroadcastEvent(demote ? GE_DEMOTION : GE_PROMOTION, 0, player->GetName(), name.c_str(), _GetRankName(newRankId).c_str()); + } } -void Guild::CreateNewBankTab() +void Guild::HandleAddNewRank(WorldSession* session, const std::string& name) { - if (GetPurchasedTabs() >= GUILD_BANK_MAX_TABS) + if (_GetRanksSize() >= GUILD_RANKS_MAX_COUNT) return; - uint32 tabId = GetPurchasedTabs(); // next free id - m_TabListMap.push_back(new GuildBankTab); - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - trans->PAppend("DELETE FROM guild_bank_tab WHERE guildid='%u' AND TabId='%u'", m_Id, tabId); - trans->PAppend("INSERT INTO guild_bank_tab (guildid,TabId) VALUES ('%u','%u')", m_Id, tabId); - CharacterDatabase.CommitTransaction(trans); + // Only leader can add new rank + if (!_IsLeader(session->GetPlayer())) + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_PERMISSIONS); + else + { + _CreateRank(name, GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + HandleQuery(session); + HandleRoster(); // Broadcast for tab rights update + } } -void Guild::SetGuildBankTabInfo(uint8 TabId, std::string Name, std::string Icon) +void Guild::HandleRemoveLowestRank(WorldSession* session) { - if (m_TabListMap[TabId]->Name == Name && m_TabListMap[TabId]->Icon == Icon) + // Cannot remove rank if total count is minimum allowed by the client + if (_GetRanksSize() <= GUILD_RANKS_MIN_COUNT) return; - m_TabListMap[TabId]->Name = Name; - m_TabListMap[TabId]->Icon = Icon; - - CharacterDatabase.escape_string(Name); - CharacterDatabase.escape_string(Icon); - CharacterDatabase.PExecute("UPDATE guild_bank_tab SET TabName='%s',TabIcon='%s' WHERE guildid='%u' AND TabId='%u'", Name.c_str(), Icon.c_str(), m_Id, uint32(TabId)); + // Only leader can delete ranks + if (!_IsLeader(session->GetPlayer())) + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_PERMISSIONS); + else + { + uint8 rankId = _GetLowestRankId(); + // Delete bank rights for rank + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_RIGHTS_FOR_RANK); + stmt->setUInt32(0, m_id); + stmt->setUInt8 (1, rankId); + CharacterDatabase.Execute(stmt); + // Delete rank + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_LOWEST_RANK); + stmt->setUInt32(0, m_id); + stmt->setUInt8 (1, rankId); + CharacterDatabase.Execute(stmt); + + m_ranks.pop_back(); + + HandleQuery(session); + HandleRoster(); // Broadcast for tab rights update + } } -uint32 Guild::GetBankRights(uint32 rankId, uint8 TabId) const +void Guild::HandleMemberDepositMoney(WorldSession* session, uint32 amount) { - if (rankId >= m_Ranks.size() || TabId >= GUILD_BANK_MAX_TABS) - return 0; + if (!_GetPurchasedTabsSize()) + return; // No guild bank tabs - no money in bank - return m_Ranks[rankId].TabRight[TabId]; -} + Player* player = session->GetPlayer(); -// ************************************************* -// Money deposit/withdraw related + // Call script after validation and before money transfer. + sScriptMgr.OnGuildMemberDepositMoney(this, player, amount); -void Guild::SendMoneyInfo(WorldSession *session, uint32 LowGuid) -{ - WorldPacket data(MSG_GUILD_BANK_MONEY_WITHDRAWN, 4); - data << uint32(GetMemberMoneyWithdrawRem(LowGuid)); - session->SendPacket(&data); - sLog.outDebug("WORLD: Sent MSG_GUILD_BANK_MONEY_WITHDRAWN"); + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + // Add money to bank + _ModifyBankMoney(trans, amount, true); + // Remove money from player + player->ModifyMoney(-int32(amount)); + player->SaveGoldToDB(trans); + // Log GM action (TODO: move to scripts) + if (player->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getBoolConfig(CONFIG_GM_LOG_TRADE)) + { + sLog.outCommand(player->GetSession()->GetAccountId(), + "GM %s (Account: %u) deposit money (Amount: %u) to pGuild bank (Guild ID %u)", + player->GetName(), player->GetSession()->GetAccountId(), amount, m_id); + } + // Log guild bank event + _LogBankEvent(trans, GUILD_BANK_LOG_DEPOSIT_MONEY, uint8(0), player->GetGUIDLow(), amount); + + CharacterDatabase.CommitTransaction(trans); + + SendBankTabsInfo(session); + _SendBankContent(session, 0); + _SendBankMoneyUpdate(session); } -bool Guild::MemberMoneyWithdraw(uint32 amount, uint32 LowGuid, SQLTransaction& trans) +bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool repair) { - uint32 MoneyWithDrawRight = GetMemberMoneyWithdrawRem(LowGuid); + if (!_GetPurchasedTabsSize()) + return false; // No guild bank tabs - no money + + if (m_bankMoney < amount) // Not enough money in bank + return false; - if (MoneyWithDrawRight < amount || GetGuildBankMoney() < amount) + Player* player = session->GetPlayer(); + if (!_HasRankRight(player, repair ? GR_RIGHT_WITHDRAW_REPAIR : GR_RIGHT_WITHDRAW_GOLD)) return false; - SetBankMoney(GetGuildBankMoney()-amount, trans); + uint32 remainingMoney = _GetMemberRemainingMoney(player->GetGUID()); + if (!remainingMoney) + return false; - if (MoneyWithDrawRight < WITHDRAW_MONEY_UNLIMITED) + // Call script after validation and before money transfer. + sScriptMgr.OnGuildMemberWitdrawMoney(this, player, amount, repair); + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + // Update remaining money amount + if (remainingMoney >= amount && remainingMoney < GUILD_WITHDRAW_MONEY_UNLIMITED) + if (Member* pMember = GetMember(player->GetGUID())) + pMember->DecreaseBankRemainingValue(trans, GUILD_BANK_MAX_TABS, amount); + // Remove money from bank + _ModifyBankMoney(trans, amount, false); + // Add money to player (if required) + if (!repair) { - MemberList::iterator itr = members.find(LowGuid); - if (itr == members.end()) - return false; - itr->second.BankRemMoney -= amount; - trans->PAppend("UPDATE guild_member SET BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'", - itr->second.BankRemMoney, m_Id, LowGuid); + player->ModifyMoney(amount); + player->SaveGoldToDB(trans); + } + // Log guild bank event + _LogBankEvent(trans, repair ? GUILD_BANK_LOG_REPAIR_MONEY : GUILD_BANK_LOG_WITHDRAW_MONEY, uint8(0), player->GetGUIDLow(), amount); + CharacterDatabase.CommitTransaction(trans); + + SendMoneyInfo(session); + if (!repair) + { + SendBankTabsInfo(session); + _SendBankContent(session, 0); + _SendBankMoneyUpdate(session); } return true; } -void Guild::SetBankMoney(int64 money, SQLTransaction& trans) +void Guild::HandleMemberLogout(WorldSession* session) { - if (money < 0) // I don't know how this happens, it does!! - money = 0; - m_GuildBankMoney = money; - - trans->PAppend("UPDATE guild SET BankMoney='" UI64FMTD "' WHERE guildid='%u'", money, m_Id); + Player* player = session->GetPlayer(); + if (Member* pMember = GetMember(player->GetGUID())) + { + pMember->SetStats(player); + pMember->UpdateLogoutTime(); + } + _BroadcastEvent(GE_SIGNED_OFF, player->GetGUID(), player->GetName()); } -// ************************************************* -// Item per day and money per day related - -bool Guild::MemberItemWithdraw(uint8 TabId, uint32 LowGuid, SQLTransaction& trans) +void Guild::HandleDisband(WorldSession* session) { - uint32 SlotsWithDrawRight = GetMemberSlotWithdrawRem(LowGuid, TabId); - - if (SlotsWithDrawRight == 0) - return false; - - if (SlotsWithDrawRight < WITHDRAW_SLOT_UNLIMITED) + // Only leader can disband guild + if (!_IsLeader(session->GetPlayer())) + Guild::SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_PERMISSIONS); + else { - MemberList::iterator itr = members.find(LowGuid); - if (itr == members.end()) - return false; - --itr->second.BankRemSlotsTab[TabId]; - trans->PAppend("UPDATE guild_member SET BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'", - uint32(TabId), itr->second.BankRemSlotsTab[TabId], m_Id, LowGuid); + Disband(); + sLog.outDebug("WORLD: Guild Successfully Disbanded"); } - return true; } -bool Guild::IsMemberHaveRights(uint32 LowGuid, uint8 TabId, uint32 rights) const +/////////////////////////////////////////////////////////////////////////////// +// Send data to client +void Guild::SendInfo(WorldSession* session) const { - MemberList::const_iterator itr = members.find(LowGuid); - if (itr == members.end()) - return false; - - if (itr->second.RankId == GR_GUILDMASTER) - return true; + WorldPacket data(SMSG_GUILD_INFO, m_name.size() + 4 + 4 + 4); + data << m_name; + data << secsToTimeBitFields(m_createdDate); // 3.x (prev. year + month + day) + data << uint32(m_members.size()); // Number of members + data << m_accountsNumber; // Number of accounts - return (GetBankRights(itr->second.RankId,TabId) & rights) == rights; + session->SendPacket(&data); + sLog.outDebug("WORLD: Sent (SMSG_GUILD_INFO)"); } -uint32 Guild::GetMemberSlotWithdrawRem(uint32 LowGuid, uint8 TabId) +void Guild::SendEventLog(WorldSession *session) const { - MemberList::iterator itr = members.find(LowGuid); - if (itr == members.end()) - return 0; - - if (itr->second.RankId == GR_GUILDMASTER) - return WITHDRAW_SLOT_UNLIMITED; - - if ((GetBankRights(itr->second.RankId,TabId) & GUILD_BANK_RIGHT_VIEW_TAB) != GUILD_BANK_RIGHT_VIEW_TAB) - return 0; + WorldPacket data(MSG_GUILD_EVENT_LOG_QUERY, 1 + m_eventLog->GetSize() * (1 + 8 + 4)); + m_eventLog->WritePacket(data); + session->SendPacket(&data); + sLog.outDebug("WORLD: Sent (MSG_GUILD_EVENT_LOG_QUERY)"); +} - uint32 curTime = uint32(time(NULL)/MINUTE); - if (curTime - itr->second.BankResetTimeTab[TabId] >= 24*HOUR/MINUTE) +void Guild::SendBankLog(WorldSession *session, uint8 tabId) const +{ + // GUILD_BANK_MAX_TABS send by client for money log + if (tabId < _GetPurchasedTabsSize() || tabId == GUILD_BANK_MAX_TABS) { - itr->second.BankResetTimeTab[TabId] = curTime; - itr->second.BankRemSlotsTab[TabId] = GetBankSlotPerDay(itr->second.RankId, TabId); - CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeTab%u='%u', BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'", - uint32(TabId), itr->second.BankResetTimeTab[TabId], uint32(TabId), itr->second.BankRemSlotsTab[TabId], m_Id, LowGuid); + const LogHolder* pLog = m_bankEventLog[tabId]; + WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, pLog->GetSize() * (4 * 4 + 1) + 1 + 1); + data << uint8(tabId); + pLog->WritePacket(data); + session->SendPacket(&data); + sLog.outDebug("WORLD: Sent (MSG_GUILD_BANK_LOG_QUERY)"); } - return itr->second.BankRemSlotsTab[TabId]; } -uint32 Guild::GetMemberMoneyWithdrawRem(uint32 LowGuid) +void Guild::SendBankTabData(WorldSession* session, uint8 tabId) const { - MemberList::iterator itr = members.find(LowGuid); - if (itr == members.end()) - return 0; - - if (itr->second.RankId == GR_GUILDMASTER) - return WITHDRAW_MONEY_UNLIMITED; - - uint32 curTime = uint32(time(NULL)/MINUTE); // minutes - // 24 hours - if (curTime > itr->second.BankResetTimeMoney + 24*HOUR/MINUTE) + if (tabId < _GetPurchasedTabsSize()) { - itr->second.BankResetTimeMoney = curTime; - itr->second.BankRemMoney = GetBankMoneyPerDay(itr->second.RankId); - CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeMoney='%u', BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'", - itr->second.BankResetTimeMoney, itr->second.BankRemMoney, m_Id, LowGuid); + SendMoneyInfo(session); + _SendBankContent(session, tabId); } - return itr->second.BankRemMoney; } -void Guild::SetBankMoneyPerDay(uint32 rankId, uint32 money) +void Guild::SendBankTabsInfo(WorldSession *session) const { - if (rankId >= m_Ranks.size()) - return; + WorldPacket data(SMSG_GUILD_BANK_LIST, 500); - if (rankId == GR_GUILDMASTER) - money = WITHDRAW_MONEY_UNLIMITED; + data << uint64(m_bankMoney); + data << uint8(0); // TabInfo packet must be for tabId 0 + data << uint32(_GetMemberRemainingSlots(session->GetPlayer()->GetGUID(), 0)); + data << uint8(1); // Tell client that this packet includes tab info - m_Ranks[rankId].BankMoneyPerDay = money; + data << uint8(_GetPurchasedTabsSize()); // Number of tabs + for (uint8 i = 0; i < _GetPurchasedTabsSize(); ++i) + m_bankTabs[i]->WriteInfoPacket(data); - for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) - if (itr->second.RankId == rankId) - itr->second.BankResetTimeMoney = 0; + data << uint8(0); // Do not send tab content + session->SendPacket(&data); - CharacterDatabase.PExecute("UPDATE guild_rank SET BankMoneyPerDay='%u' WHERE rid='%u' AND guildid='%u'", money, rankId, m_Id); - CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeMoney='0' WHERE guildid='%u' AND rank='%u'", m_Id, rankId); + sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); } -void Guild::SetBankRightsAndSlots(uint32 rankId, uint8 TabId, uint32 right, uint32 nbSlots, bool db) +void Guild::SendBankTabText(WorldSession *session, uint8 tabId) const { - if (rankId >= m_Ranks.size() || TabId >= GetPurchasedTabs()) - return; - - if (rankId == GR_GUILDMASTER) - { - nbSlots = WITHDRAW_SLOT_UNLIMITED; - right = GUILD_BANK_RIGHT_FULL; - } + if (const BankTab* pTab = GetBankTab(tabId)) + pTab->SendText(this, session); +} - m_Ranks[rankId].TabSlotPerDay[TabId] = nbSlots; - m_Ranks[rankId].TabRight[TabId] = right; +void Guild::SendPermissions(WorldSession *session) const +{ + const uint64& guid = session->GetPlayer()->GetGUID(); + uint8 rankId = session->GetPlayer()->GetRank(); - if (db) + WorldPacket data(MSG_GUILD_PERMISSIONS, 4 * 15 + 1); + data << uint32(rankId); + data << uint32(_GetRankRights(rankId)); + data << uint32(_GetMemberRemainingMoney(guid)); + data << uint8 (_GetPurchasedTabsSize()); + // Why sending all info when not all tabs are purchased??? + for (uint8 tabId = 0; tabId < GUILD_BANK_MAX_TABS; ++tabId) { - for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) - if (itr->second.RankId == rankId) - for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i) - itr->second.BankResetTimeTab[i] = 0; - - CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid='%u' AND TabId='%u' AND rid='%u'", m_Id, uint32(TabId), rankId); - CharacterDatabase.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid,gbright,SlotPerDay) VALUES " - "('%u','%u','%u','%u','%u')", m_Id, uint32(TabId), rankId, m_Ranks[rankId].TabRight[TabId], m_Ranks[rankId].TabSlotPerDay[TabId]); - CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeTab%u='0' WHERE guildid='%u' AND rank='%u'", uint32(TabId), m_Id, rankId); + data << uint32(_GetRankBankTabRights(rankId, tabId)); + data << uint32(_GetMemberRemainingSlots(guid, tabId)); } + session->SendPacket(&data); + sLog.outDebug("WORLD: Sent (MSG_GUILD_PERMISSIONS)"); } -uint32 Guild::GetBankMoneyPerDay(uint32 rankId) +void Guild::SendMoneyInfo(WorldSession *session) const { - if (rankId >= m_Ranks.size()) - return 0; - - if (rankId == GR_GUILDMASTER) - return WITHDRAW_MONEY_UNLIMITED; - return m_Ranks[rankId].BankMoneyPerDay; + WorldPacket data(MSG_GUILD_BANK_MONEY_WITHDRAWN, 4); + data << uint32(_GetMemberRemainingMoney(session->GetPlayer()->GetGUID())); + session->SendPacket(&data); + sLog.outDebug("WORLD: Sent MSG_GUILD_BANK_MONEY_WITHDRAWN"); } -uint32 Guild::GetBankSlotPerDay(uint32 rankId, uint8 TabId) +void Guild::SendLoginInfo(WorldSession* session) const { - if (rankId >= m_Ranks.size() || TabId >= GUILD_BANK_MAX_TABS) - return 0; + WorldPacket data(SMSG_GUILD_EVENT, 1 + 1 + m_motd.size() + 1); + data << uint8(GE_MOTD); + data << uint8(1); + data << m_motd; + session->SendPacket(&data); + sLog.outDebug("WORLD: Sent guild MOTD (SMSG_GUILD_EVENT)"); - if (rankId == GR_GUILDMASTER) - return WITHDRAW_SLOT_UNLIMITED; - return m_Ranks[rankId].TabSlotPerDay[TabId]; -} + SendBankTabsInfo(session); -// ************************************************* -// Rights per day related + _BroadcastEvent(GE_SIGNED_ON, session->GetPlayer()->GetGUID(), session->GetPlayer()->GetName()); +} -bool Guild::LoadBankRightsFromDB(QueryResult guildBankTabRightsResult) +/////////////////////////////////////////////////////////////////////////////// +// Loading methods +bool Guild::LoadFromDB(Field* fields) { - if (!guildBankTabRightsResult) - return true; + m_id = fields[0].GetUInt32(); + m_name = fields[1].GetString(); + m_leaderGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER); + m_emblemInfo.LoadFromDB(fields); + m_info = fields[8].GetString(); + m_motd = fields[9].GetString(); + m_createdDate = fields[10].GetUInt64(); + m_bankMoney = fields[11].GetUInt64(); - do - { - Field *fields = guildBankTabRightsResult->Fetch(); - //prevent crash when all rights in result are already processed - if (!fields) - break; - uint32 guildId = fields[0].GetUInt32(); - if (guildId < m_Id) - { - //there is in table guild_bank_right record which doesn't have guildid in guild table, report error - sLog.outErrorDb("Guild %u does not exist but it has a record in guild_bank_right table, deleting it!", guildId); - CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u'", guildId); - continue; - } - - if (guildId > m_Id) - //we loaded all ranks for this guild bank already, break cycle - break; - uint8 TabId = fields[1].GetUInt8(); - uint32 rankId = fields[2].GetUInt32(); - uint16 right = fields[3].GetUInt16(); - uint16 SlotPerDay = fields[4].GetUInt16(); - - SetBankRightsAndSlots(rankId, TabId, right, SlotPerDay, false); + uint8 purchasedTabs = uint8(fields[12].GetUInt32()); + if (purchasedTabs > GUILD_BANK_MAX_TABS) + purchasedTabs = GUILD_BANK_MAX_TABS; - }while (guildBankTabRightsResult->NextRow()); + m_bankTabs.resize(purchasedTabs); + for (uint8 i = 0; i < purchasedTabs; ++i) + m_bankTabs[i] = new BankTab(m_id, i); + _CreateLogHolders(); return true; } -// ************************************************* -// Bank log related +bool Guild::LoadRankFromDB(Field* fields) +{ + RankInfo rankInfo(m_id); + if (!rankInfo.LoadFromDB(fields)) + return false; + m_ranks.push_back(rankInfo); + return true; +} +bool Guild::LoadMemberFromDB(Field* fields) +{ + uint32 lowguid = fields[1].GetUInt32(); + Member *pMember = new Member(m_id, MAKE_NEW_GUID(lowguid, 0, HIGHGUID_PLAYER), fields[2].GetUInt8()); + if (!pMember->LoadFromDB(fields)) + { + _DeleteMemberFromDB(lowguid); + delete pMember; + return false; + } + m_members[lowguid] = pMember; + return true; +} -void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId) +bool Guild::LoadBankRightFromDB(Field* fields) { - if (TabId > GUILD_BANK_MAX_TABS) // tabs starts in 0 - return; + // rights slots + GuildBankRightsAndSlots rightsAndSlots(fields[3].GetUInt8(), fields[4].GetUInt32()); + // rankId tabId + _SetRankBankTabRightsAndSlots(fields[2].GetUInt8(), fields[1].GetUInt8(), rightsAndSlots, false); + return true; +} - if (TabId == GUILD_BANK_MAX_TABS) +bool Guild::LoadEventLogFromDB(Field* fields) +{ + if (m_eventLog->CanInsert()) { - // Here we display money logs - WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, m_GuildBankEventLog_Money.size()*(4*4+1)+1+1); - data << uint8(TabId); // Here GUILD_BANK_MAX_TABS - data << uint8(m_GuildBankEventLog_Money.size()); // number of log entries - for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Money.begin(); itr != m_GuildBankEventLog_Money.end(); ++itr) - { - data << uint8(itr->EventType); - data << uint64(MAKE_NEW_GUID(itr->PlayerGuid,0,HIGHGUID_PLAYER)); - data << uint32(itr->ItemOrMoney); - data << uint32(time(NULL) - itr->TimeStamp); - } - session->SendPacket(&data); + m_eventLog->LoadEvent(new EventLogEntry( + m_id, // guild id + fields[1].GetUInt32(), // guid + fields[6].GetUInt64(), // timestamp + GuildEventLogTypes(fields[2].GetUInt8()), // event type + fields[3].GetUInt32(), // player guid 1 + fields[4].GetUInt32(), // player guid 2 + fields[5].GetUInt8())); // rank + return true; } - else + return false; +} + +bool Guild::LoadBankEventLogFromDB(Field* fields) +{ + uint8 dbTabId = fields[1].GetUInt8(); + bool isMoneyTab = (dbTabId == GUILD_BANK_MONEY_LOGS_TAB); + if (dbTabId < _GetPurchasedTabsSize() || isMoneyTab) { - // here we display current tab logs - WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, m_GuildBankEventLog_Item[TabId].size()*(4*4+1+1)+1+1); - data << uint8(TabId); // Here a real Tab Id - data << uint8(m_GuildBankEventLog_Item[TabId].size()); // number of log entries - for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Item[TabId].begin(); itr != m_GuildBankEventLog_Item[TabId].end(); ++itr) + uint8 tabId = isMoneyTab ? uint8(GUILD_BANK_MAX_TABS) : dbTabId; + LogHolder* pLog = m_bankEventLog[tabId]; + if (pLog->CanInsert()) { - data << uint8(itr->EventType); - data << uint64(MAKE_NEW_GUID(itr->PlayerGuid,0,HIGHGUID_PLAYER)); - data << uint32(itr->ItemOrMoney); - data << uint32(itr->ItemStackCount); - if (itr->EventType == GUILD_BANK_LOG_MOVE_ITEM || itr->EventType == GUILD_BANK_LOG_MOVE_ITEM2) - data << uint8(itr->DestTabId); // moved tab - data << uint32(time(NULL) - itr->TimeStamp); + uint32 guid = fields[2].GetUInt32(); + GuildBankEventLogTypes eventType = GuildBankEventLogTypes(fields[3].GetUInt8()); + if (BankEventLogEntry::IsMoneyEvent(eventType)) + { + if (!isMoneyTab) + { + sLog.outError("GuildBankEventLog ERROR: MoneyEvent(LogGuid: %u, Guild: %u) does not belong to money tab (%u), ignoring...", guid, m_id, dbTabId); + return false; + } + } + else if (isMoneyTab) + { + sLog.outError("GuildBankEventLog ERROR: non-money event (LogGuid: %u, Guild: %u) belongs to money tab, ignoring...", guid, m_id); + return false; + } + pLog->LoadEvent(new BankEventLogEntry( + m_id, // guild id + guid, // guid + fields[8].GetUInt64(), // timestamp + dbTabId, // tab id + eventType, // event type + fields[4].GetUInt32(), // player guid + fields[5].GetUInt32(), // item or money + fields[6].GetUInt16(), // itam stack count + fields[7].GetUInt8())); // dest tab id } - session->SendPacket(&data); } - sLog.outDebug("WORLD: Sent (MSG_GUILD_BANK_LOG_QUERY)"); + return true; } -void Guild::LogBankEvent(SQLTransaction& trans, uint8 EventType, uint8 TabId, uint32 PlayerGuidLow, uint32 ItemOrMoney, uint16 ItemStackCount, uint8 DestTabId) +bool Guild::LoadBankTabFromDB(Field* fields) { - //create Event - GuildBankEventLogEntry NewEvent; - NewEvent.EventType = EventType; - NewEvent.PlayerGuid = PlayerGuidLow; - NewEvent.ItemOrMoney = ItemOrMoney; - NewEvent.ItemStackCount = ItemStackCount; - NewEvent.DestTabId = DestTabId; - NewEvent.TimeStamp = uint32(time(NULL)); + uint32 tabId = fields[1].GetUInt8(); + if (tabId >= _GetPurchasedTabsSize()) + { + sLog.outError("Invalid tab (tabId: %u) in guild bank, skipped.", tabId); + return false; + } + return m_bankTabs[tabId]->LoadFromDB(fields); +} - //add new event to the end of event list - uint32 currentTabId = TabId; - uint32 currentLogGuid = 0; - if (NewEvent.isMoneyEvent()) +bool Guild::LoadBankItemFromDB(Field* fields) +{ + uint8 tabId = fields[12].GetUInt8(); + if (tabId >= _GetPurchasedTabsSize()) { - m_GuildBankEventLogNextGuid_Money = (m_GuildBankEventLogNextGuid_Money + 1) % sWorld.getIntConfig(CONFIG_GUILD_BANK_EVENT_LOG_COUNT); - currentLogGuid = m_GuildBankEventLogNextGuid_Money; - currentTabId = GUILD_BANK_MONEY_LOGS_TAB; - if (m_GuildBankEventLog_Money.size() >= GUILD_BANK_MAX_LOGS) - m_GuildBankEventLog_Money.pop_front(); + sLog.outError("Invalid tab for item (GUID: %u, id: #%u) in guild bank, skipped.", + fields[14].GetUInt32(), fields[15].GetUInt32()); + return false; + } + return m_bankTabs[tabId]->LoadItemFromDB(fields); +} - m_GuildBankEventLog_Money.push_back(NewEvent); +// Validates guild data loaded from database. Returns false if guild should be deleted. +bool Guild::Validate() +{ + // Validate ranks data + // GUILD RANKS represent a sequence starting from 0 = GUILD_MASTER (ALL PRIVILEGES) to max 9 (lowest privileges). + // The lower rank id is considered higher rank - so promotion does rank-- and demotion does rank++ + // Between ranks in sequence cannot be gaps - so 0,1,2,4 is impossible + // Min ranks count is 5 and max is 10. + bool broken_ranks = false; + if (_GetRanksSize() < GUILD_RANKS_MIN_COUNT || _GetRanksSize() > GUILD_RANKS_MAX_COUNT) + { + sLog.outError("Guild %u has invalid number of ranks, creating new...", m_id); + broken_ranks = true; } else { - m_GuildBankEventLogNextGuid_Item[TabId] = ((m_GuildBankEventLogNextGuid_Item[TabId]) + 1) % sWorld.getIntConfig(CONFIG_GUILD_BANK_EVENT_LOG_COUNT); - currentLogGuid = m_GuildBankEventLogNextGuid_Item[TabId]; - if (m_GuildBankEventLog_Item[TabId].size() >= GUILD_BANK_MAX_LOGS) - m_GuildBankEventLog_Item[TabId].pop_front(); + for (uint8 rankId = 0; rankId < _GetRanksSize(); ++rankId) + { + RankInfo* rankInfo = GetRankInfo(rankId); + if (rankInfo->GetId() != rankId) + { + sLog.outError("Guild %u has broken rank id %u, creating default set of ranks...", m_id, rankId); + broken_ranks = true; + } + } + } + if (broken_ranks) + { + m_ranks.clear(); + _CreateDefaultGuildRanks(DEFAULT_LOCALE); + } + + // Validate members' data + for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + if (itr->second->GetRankId() > _GetRanksSize()) + itr->second->ChangeRank(_GetLowestRankId()); - m_GuildBankEventLog_Item[TabId].push_back(NewEvent); + // Repair the structure of the guild. + // If the guildmaster doesn't exist or isn't member of the guild + // attempt to promote another member. + Member* pLeader = GetMember(m_leaderGuid); + if (!pLeader) + { + DeleteMember(m_leaderGuid); + // If no more members left, disband guild + if (m_members.empty()) + { + Disband(); + return false; + } } + else if (!pLeader->IsRank(GR_GUILDMASTER)) + _SetLeaderGUID(pLeader); - //save event to database - trans->PAppend("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u' AND TabId='%u'", m_Id, currentLogGuid, currentTabId); + // Check config if multiple guildmasters are allowed + if (!sConfig.GetBoolDefault("Guild.AllowMultipleGuildMaster", 0)) + for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + if (itr->second->GetRankId() == GR_GUILDMASTER && !itr->second->IsSamePlayer(m_leaderGuid)) + itr->second->ChangeRank(GR_OFFICER); - trans->PAppend("INSERT INTO guild_bank_eventlog (guildid,LogGuid,TabId,EventType,PlayerGuid,ItemOrMoney,ItemStackCount,DestTabId,TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','%u','%u','" UI64FMTD "')", - m_Id, currentLogGuid, currentTabId, uint32(NewEvent.EventType), NewEvent.PlayerGuid, NewEvent.ItemOrMoney, uint32(NewEvent.ItemStackCount), uint32(NewEvent.DestTabId), NewEvent.TimeStamp); + _UpdateAccountsNumber(); + return true; } -bool Guild::AddGBankItemToDB(uint32 GuildId, uint32 BankTab , uint32 BankTabSlot , uint32 GUIDLow, uint32 Entry, SQLTransaction& trans) +/////////////////////////////////////////////////////////////////////////////// +// Broadcasts +void Guild::BroadcastToGuild(WorldSession *session, bool officerOnly, const std::string& msg, uint32 language) const { - trans->PAppend("DELETE FROM guild_bank_item WHERE guildid = '%u' AND TabId = '%u'AND SlotId = '%u'", GuildId, BankTab, BankTabSlot); - trans->PAppend("INSERT INTO guild_bank_item (guildid,TabId,SlotId,item_guid,item_entry) " - "VALUES ('%u', '%u', '%u', '%u', '%u')", GuildId, BankTab, BankTabSlot, GUIDLow, Entry); - return true; + if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK)) + { + WorldPacket data; + ChatHandler::FillMessageData(&data, session, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, language, NULL, 0, msg.c_str(), NULL); + for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + if (Player *player = itr->second->FindPlayer()) + if (player->GetSession() && _HasRankRight(player, officerOnly ? GR_RIGHT_OFFCHATLISTEN : GR_RIGHT_GCHATLISTEN) && + !player->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow())) + player->GetSession()->SendPacket(&data); + } } -void Guild::AppendDisplayGuildBankSlot(WorldPacket& data, GuildBankTab const *tab, int slot) +void Guild::BroadcastPacketToRank(WorldPacket *packet, uint8 rankId) const { - Item *pItem = tab->Slots[slot]; - uint32 entry = pItem ? pItem->GetEntry() : 0; + for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + if (itr->second->IsRank(rankId)) + if (Player *player = itr->second->FindPlayer()) + player->GetSession()->SendPacket(packet); +} - data << uint8(slot); - data << uint32(entry); - if (entry) +void Guild::BroadcastPacket(WorldPacket *packet) const +{ + for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + if (Player *player = itr->second->FindPlayer()) + player->GetSession()->SendPacket(packet); +} + +/////////////////////////////////////////////////////////////////////////////// +// Members handling +bool Guild::AddMember(const uint64& guid, uint8 rankId) +{ + Player* player = sObjectMgr.GetPlayer(guid); + // Player cannot be in guild + if (player) { - data << uint32(0); // 3.3.0 (0x8000, 0x8020) - data << uint32(pItem->GetItemRandomPropertyId()); // random item property id + 8 + if (player->GetGuildId() != 0) + return false; + } + else if (Player::GetGuildIdFromDB(guid) != 0) + return false; - if (pItem->GetItemRandomPropertyId()) - data << uint32(pItem->GetItemSuffixFactor()); // SuffixFactor + 4 + // Remove all player signs from another petitions + // This will be prevent attempt to join many guilds and corrupt guild data integrity + Player::RemovePetitionsAndSigns(guid, GUILD_CHARTER_TYPE); - data << uint32(pItem->GetCount()); // +12 ITEM_FIELD_STACK_COUNT - data << uint32(0); // +16 Unknown value - data << uint8(abs(pItem->GetSpellCharges())); // spell charges + uint32 lowguid = GUID_LOPART(guid); - uint8 enchCount = 0; - size_t enchCountPos = data.wpos(); + // If rank was not passed, assing lowest possible rank + if (rankId == GUILD_RANK_NONE) + rankId = _GetLowestRankId(); - data << uint8(enchCount); // number of enchantments - for (uint32 i = PERM_ENCHANTMENT_SLOT; i < MAX_ENCHANTMENT_SLOT; ++i) + Member* pMember = new Member(m_id, guid, rankId); + if (player) + pMember->SetStats(player); + else + { + bool ok = false; + // Player must exist + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_LOAD_CHAR_DATA_FOR_GUILD); + stmt->setUInt32(0, lowguid); + if (PreparedQueryResult result = CharacterDatabase.Query(stmt)) { - if (uint32 enchId = pItem->GetEnchantmentId(EnchantmentSlot(i))) - { - data << uint8(i); - data << uint32(enchId); - ++enchCount; - } + Field *fields = result->Fetch(); + pMember->SetStats( + fields[0].GetString(), + fields[1].GetUInt8(), + fields[2].GetUInt8(), + fields[3].GetUInt32(), + fields[4].GetUInt32()); + + ok = pMember->CheckStats(); } - data.put<uint8>(enchCountPos, enchCount); + if (!ok) + { + delete pMember; + return false; + } + } + m_members[lowguid] = pMember; + + SQLTransaction trans(NULL); + pMember->SaveToDB(trans); + // If player not in game data in will be loaded from guild tables, so no need to update it! + if (player) + { + player->SetInGuild(m_id); + player->SetRank(rankId); + player->SetGuildIdInvited(0); } + + _UpdateAccountsNumber(); + + // Call scripts if member was succesfully added (and stored to database) + sScriptMgr.OnGuildAddMember(this, player, rankId); + + return true; } -Item* Guild::StoreItem(uint8 tabId, GuildItemPosCountVec const& dest, Item* pItem, SQLTransaction& trans) +void Guild::DeleteMember(const uint64& guid, bool isDisbanding, bool isKicked) { - if (!pItem) - return NULL; - - Item* lastItem = pItem; + uint32 lowguid = GUID_LOPART(guid); + Player *player = sObjectMgr.GetPlayer(guid); - for (GuildItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end();) + // Guild master can be deleted when loading guild and guid doesn't exist in characters table + // or when he is removed from guild by gm command + if (m_leaderGuid == guid && !isDisbanding) { - uint8 slot = itr->Slot; - uint32 count = itr->Count; + Member* oldLeader = NULL; + Member* newLeader = NULL; + for (Guild::Members::iterator i = m_members.begin(); i != m_members.end(); ++i) + { + if (i->first == lowguid) + oldLeader = i->second; + else if (!newLeader || newLeader->GetRankId() > i->second->GetRankId()) + newLeader = i->second; + } + if (!newLeader) + { + Disband(); + return; + } - ++itr; + _SetLeaderGUID(newLeader); - if (itr == dest.end()) + // If player not online data in data field will be loaded from guild tabs no need to update it !! + if (Player *newLeaderPlayer = newLeader->FindPlayer()) + newLeaderPlayer->SetRank(GR_GUILDMASTER); + + // If leader does not exist (at guild loading with deleted leader) do not send broadcasts + if (oldLeader) { - lastItem = _StoreItem(tabId, slot, pItem, count, false, trans); - break; + _BroadcastEvent(GE_LEADER_CHANGED, 0, oldLeader->GetName().c_str(), newLeader->GetName().c_str()); + _BroadcastEvent(GE_LEFT, guid, oldLeader->GetName().c_str()); } + } + // Call script on remove before member is acutally removed from guild (and database) + sScriptMgr.OnGuildRemoveMember(this, player, isDisbanding, isKicked); + + if (Member* pMember = GetMember(guid)) + delete pMember; + m_members.erase(lowguid); - lastItem = _StoreItem(tabId, slot, pItem, count, true, trans); + // If player not online data in data field will be loaded from guild tabs no need to update it !! + if (player) + { + player->SetInGuild(0); + player->SetRank(0); } - return lastItem; + _DeleteMemberFromDB(lowguid); + if (!isDisbanding) + _UpdateAccountsNumber(); } -// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case. -Item* Guild::_StoreItem(uint8 tab, uint8 slot, Item *pItem, uint32 count, bool clone, SQLTransaction& trans) +bool Guild::ChangeMemberRank(const uint64& guid, uint8 newRank) { - if (!pItem) - return NULL; - - sLog.outDebug("GUILD STORAGE: StoreItem tab = %u, slot = %u, item = %u, count = %u", tab, slot, pItem->GetEntry(), count); - - Item* pItem2 = m_TabListMap[tab]->Slots[slot]; + if (newRank <= _GetLowestRankId()) // Validate rank (allow only existing ranks) + if (Member* pMember = GetMember(guid)) + { + pMember->ChangeRank(newRank); + return true; + } + return false; +} - if (!pItem2) - { - if (clone) - pItem = pItem->CloneItem(count); - else - pItem->SetCount(count); +/////////////////////////////////////////////////////////////////////////////// +// Bank (items move) +void Guild::SwapItems(Player* player, uint8 tabId, uint8 slotId, uint8 destTabId, uint8 destSlotId, uint32 splitedAmount) +{ + if (tabId >= _GetPurchasedTabsSize() || slotId >= GUILD_BANK_MAX_SLOTS || + destTabId >= _GetPurchasedTabsSize() || destSlotId >= GUILD_BANK_MAX_SLOTS) + return; - if (!pItem) - return NULL; + if (tabId == destTabId && slotId == destSlotId) + return; - m_TabListMap[tab]->Slots[slot] = pItem; + BankMoveItemData from(this, player, tabId, slotId); + BankMoveItemData to(this, player, destTabId, destSlotId); + _MoveItems(&from, &to, splitedAmount); +} - pItem->SetUInt64Value(ITEM_FIELD_CONTAINED, 0); - pItem->SetUInt64Value(ITEM_FIELD_OWNER, 0); - AddGBankItemToDB(GetId(), tab, slot, pItem->GetGUIDLow(), pItem->GetEntry(), trans); - pItem->FSetState(ITEM_NEW); - pItem->SaveToDB(trans); // not in inventory and can be save standalone +void Guild::SwapItemsWithInventory(Player* player, bool toChar, uint8 tabId, uint8 slotId, uint8 playerBag, uint8 playerSlotId, uint32 splitedAmount) +{ + if ((slotId >= GUILD_BANK_MAX_SLOTS && slotId != NULL_SLOT) || tabId >= _GetPurchasedTabsSize()) + return; - return pItem; - } + BankMoveItemData bankData(this, player, tabId, slotId); + PlayerMoveItemData charData(this, player, playerBag, playerSlotId); + if (toChar) + _MoveItems(&bankData, &charData, splitedAmount); else - { - pItem2->SetCount(pItem2->GetCount() + count); - pItem2->FSetState(ITEM_CHANGED); - pItem2->SaveToDB(trans); // not in inventory and can be save standalone - - if (!clone) - { - pItem->RemoveFromWorld(); - pItem->DeleteFromDB(trans); - delete pItem; - } + _MoveItems(&charData, &bankData, splitedAmount); +} - return pItem2; +/////////////////////////////////////////////////////////////////////////////// +// Bank tabs +void Guild::SetBankTabText(uint8 tabId, const std::string& text) +{ + if (BankTab* pTab = GetBankTab(tabId)) + { + pTab->SetText(text); + pTab->SendText(this, NULL); } } -void Guild::RemoveItem(uint8 tab, uint8 slot, SQLTransaction& trans) +/////////////////////////////////////////////////////////////////////////////// +// Private methods +void Guild::_CreateLogHolders() { - m_TabListMap[tab]->Slots[slot] = NULL; - trans->PAppend("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'", - GetId(), uint32(tab), uint32(slot)); + m_eventLog = new LogHolder(m_id, sWorld.getIntConfig(CONFIG_GUILD_EVENT_LOG_COUNT)); + for (uint8 tabId = 0; tabId <= GUILD_BANK_MAX_TABS; ++tabId) + m_bankEventLog[tabId] = new LogHolder(m_id, sWorld.getIntConfig(CONFIG_GUILD_BANK_EVENT_LOG_COUNT)); } -uint8 Guild::_CanStoreItem_InSpecificSlot(uint8 tab, uint8 slot, GuildItemPosCountVec &dest, uint32& count, bool swap, Item* pSrcItem) const +bool Guild::_CreateNewBankTab() { - Item* pItem2 = m_TabListMap[tab]->Slots[slot]; + if (_GetPurchasedTabsSize() >= GUILD_BANK_MAX_TABS) + return false; - // ignore move item (this slot will be empty at move) - if (pItem2 == pSrcItem) - pItem2 = NULL; + uint8 tabId = _GetPurchasedTabsSize(); // Next free id + m_bankTabs.push_back(new BankTab(m_id, tabId)); - uint32 need_space; + PreparedStatement* stmt = NULL; + SQLTransaction trans = CharacterDatabase.BeginTransaction(); - // empty specific slot - check item fit to slot - if (!pItem2 || swap) - { - // non empty stack with space - need_space = pSrcItem->GetMaxStackCount(); - } - // non empty slot, check item type - else - { - // check item type - if (pItem2->GetEntry() != pSrcItem->GetEntry()) - return EQUIP_ERR_ITEM_CANT_STACK; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_TAB); + stmt->setUInt32(0, m_id); + stmt->setUInt8 (1, tabId); + trans->Append(stmt); - // check free space - if (pItem2->GetCount() >= pSrcItem->GetMaxStackCount()) - return EQUIP_ERR_ITEM_CANT_STACK; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_GUILD_BANK_TAB); + stmt->setUInt32(0, m_id); + stmt->setUInt8 (1, tabId); + trans->Append(stmt); - need_space = pSrcItem->GetMaxStackCount() - pItem2->GetCount(); - } + CharacterDatabase.CommitTransaction(trans); + return true; +} + +void Guild::_CreateDefaultGuildRanks(LocaleConstant loc) +{ + PreparedStatement* stmt = NULL; - if (need_space > count) - need_space = count; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_RANKS); + stmt->setUInt32(0, m_id); + CharacterDatabase.Execute(stmt); - GuildItemPosCount newPosition = GuildItemPosCount(slot,need_space); - if (!newPosition.isContainedIn(dest)) - { - dest.push_back(newPosition); - count -= need_space; - } + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_RIGHTS); + stmt->setUInt32(0, m_id); + CharacterDatabase.Execute(stmt); - return EQUIP_ERR_OK; + _CreateRank(sObjectMgr.GetTrinityString(LANG_GUILD_MASTER, loc), GR_RIGHT_ALL); + _CreateRank(sObjectMgr.GetTrinityString(LANG_GUILD_OFFICER, loc), GR_RIGHT_ALL); + _CreateRank(sObjectMgr.GetTrinityString(LANG_GUILD_VETERAN, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + _CreateRank(sObjectMgr.GetTrinityString(LANG_GUILD_MEMBER, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + _CreateRank(sObjectMgr.GetTrinityString(LANG_GUILD_INITIATE, loc), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); } -uint8 Guild::_CanStoreItem_InTab(uint8 tab, GuildItemPosCountVec &dest, uint32& count, bool merge, Item* pSrcItem, uint8 skip_slot) const +void Guild::_CreateRank(const std::string& name, uint32 rights) { - ASSERT(pSrcItem); - for (uint32 j = 0; j < GUILD_BANK_MAX_SLOTS; ++j) - { - // skip specific slot already processed in first called _CanStoreItem_InSpecificSlot - if (j == skip_slot) - continue; - - Item* pItem2 = m_TabListMap[tab]->Slots[j]; + if (_GetRanksSize() >= GUILD_RANKS_MAX_COUNT) + return; - // ignore move item (this slot will be empty at move) - if (pItem2 == pSrcItem) - pItem2 = NULL; + // Ranks represent sequence 0,1,2,... where 0 means guildmaster + uint8 newRankId = _GetRanksSize(); - // if merge skip empty, if !merge skip non-empty - if ((pItem2 != NULL) != merge) - continue; + RankInfo info(m_id, newRankId, name, rights, 0); + m_ranks.push_back(info); - if (pItem2) - { - if (pItem2->GetEntry() == pSrcItem->GetEntry() && pItem2->GetCount() < pSrcItem->GetMaxStackCount()) - { - uint32 need_space = pSrcItem->GetMaxStackCount() - pItem2->GetCount(); - if (need_space > count) - need_space = count; + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + for (uint8 i = 0; i < _GetPurchasedTabsSize(); ++i) + { + // Create bank rights with default values + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_GUILD_BANK_RIGHT_DEFAULT); + stmt->setUInt32(0, m_id); + stmt->setUInt8 (1, i); + stmt->setUInt8 (2, newRankId); + trans->Append(stmt); + } + info.SaveToDB(trans); + CharacterDatabase.CommitTransaction(trans); +} - GuildItemPosCount newPosition = GuildItemPosCount(j, need_space); - if (!newPosition.isContainedIn(dest)) - { - dest.push_back(newPosition); - count -= need_space; +// Updates the number of accounts that are in the guild +// Player may have many characters in the guild, but with the same account +void Guild::_UpdateAccountsNumber() +{ + // We use a set to be sure each element will be unique + std::set<uint32> accountsIdSet; + for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + accountsIdSet.insert(itr->second->GetAccountId()); - if (count == 0) - return EQUIP_ERR_OK; - } - } - } - else - { - uint32 need_space = pSrcItem->GetMaxStackCount(); - if (need_space > count) - need_space = count; + m_accountsNumber = accountsIdSet.size(); +} - GuildItemPosCount newPosition = GuildItemPosCount(j, need_space); - if (!newPosition.isContainedIn(dest)) - { - dest.push_back(newPosition); - count -= need_space; +// Detects if player is the guild master. +// Check both leader guid and player's rank (otherwise multiple feature with +// multiple guild masters won't work) +bool Guild::_IsLeader(Player* player) const +{ + if (player->GetGUID() == m_leaderGuid) + return true; + if (const Member* pMember = GetMember(player->GetGUID())) + return pMember->IsRank(GR_GUILDMASTER); + return false; +} - if (count == 0) - return EQUIP_ERR_OK; - } - } +void Guild::_DeleteBankItems(SQLTransaction& trans, bool removeItemsFromDB) +{ + for (uint8 tabId = 0; tabId < _GetPurchasedTabsSize(); ++tabId) + { + m_bankTabs[tabId]->Delete(trans, removeItemsFromDB); + delete m_bankTabs[tabId]; + m_bankTabs[tabId] = NULL; } - return EQUIP_ERR_OK; + m_bankTabs.clear(); } -uint8 Guild::CanStoreItem(uint8 tab, uint8 slot, GuildItemPosCountVec &dest, uint32 count, Item *pItem, bool swap) const +bool Guild::_ModifyBankMoney(SQLTransaction& trans, const uint64& amount, bool add) { - sLog.outDebug("GUILD STORAGE: CanStoreItem tab = %u, slot = %u, item = %u, count = %u", tab, slot, pItem->GetEntry(), count); + if (add) + m_bankMoney += amount; + else + { + // Check if there is enough money in bank. + if (m_bankMoney < amount) + return false; + m_bankMoney -= amount; + } - if (count > pItem->GetCount()) - return EQUIP_ERR_COULDNT_SPLIT_ITEMS; + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_GUILD_BANK_MONEY); + stmt->setUInt64(0, m_bankMoney); + stmt->setUInt32(1, m_id); + trans->Append(stmt); + return true; +} - if (pItem->IsSoulBound()) - return EQUIP_ERR_CANT_DROP_SOULBOUND; +void Guild::_SetLeaderGUID(Member* pLeader) +{ + if (!pLeader) + return; - // in specific tab - if (tab >= m_TabListMap.size() || tab >= GUILD_BANK_MAX_TABS) - return EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG; + m_leaderGuid = pLeader->GetGUID(); + pLeader->ChangeRank(GR_GUILDMASTER); + + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SET_GUILD_LEADER); + stmt->setUInt32(0, GUID_LOPART(m_leaderGuid)); + stmt->setUInt32(1, m_id); + CharacterDatabase.Execute(stmt); +} - // in specific slot - if (slot != NULL_SLOT) +void Guild::_SetRankBankMoneyPerDay(uint8 rankId, uint32 moneyPerDay) +{ + if (RankInfo* rankInfo = GetRankInfo(rankId)) { - uint8 res = _CanStoreItem_InSpecificSlot(tab,slot,dest,count,swap,pItem); - if (res != EQUIP_ERR_OK) - return res; + for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + if (itr->second->IsRank(rankId)) + itr->second->ResetMoneyTime(); - if (count == 0) - return EQUIP_ERR_OK; + rankInfo->SetBankMoneyPerDay(moneyPerDay); } +} - // not specific slot or have space for partly store only in specific slot +void Guild::_SetRankBankTabRightsAndSlots(uint8 rankId, uint8 tabId, GuildBankRightsAndSlots rightsAndSlots, bool saveToDB) +{ + if (tabId >= _GetPurchasedTabsSize()) + return; - // search stack in tab for merge to - if (pItem->GetMaxStackCount() > 1) + if (RankInfo* rankInfo = GetRankInfo(rankId)) { - uint8 res = _CanStoreItem_InTab(tab, dest, count, true, pItem, slot); - if (res != EQUIP_ERR_OK) - return res; + for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + if (itr->second->IsRank(rankId)) + itr->second->ResetTabTimes(); - if (count == 0) - return EQUIP_ERR_OK; + rankInfo->SetBankTabSlotsAndRights(tabId, rightsAndSlots, saveToDB); } +} - // search free slot in bag for place to - uint8 res = _CanStoreItem_InTab(tab, dest, count, false, pItem, slot); - if (res != EQUIP_ERR_OK) - return res; +inline std::string Guild::_GetRankName(uint8 rankId) const +{ + if (const RankInfo* rankInfo = GetRankInfo(rankId)) + return rankInfo->GetName(); + return "<unknown>"; +} - if (count == 0) - return EQUIP_ERR_OK; +inline uint32 Guild::_GetRankRights(uint8 rankId) const +{ + if (const RankInfo* rankInfo = GetRankInfo(rankId)) + return rankInfo->GetRights(); + return 0; +} - return EQUIP_ERR_BANK_FULL; +inline uint32 Guild::_GetRankBankMoneyPerDay(uint8 rankId) const +{ + if (const RankInfo* rankInfo = GetRankInfo(rankId)) + return rankInfo->GetBankMoneyPerDay(); + return 0; } -void Guild::SetGuildBankTabText(uint8 TabId, std::string text) +inline uint32 Guild::_GetRankBankTabSlotsPerDay(uint8 rankId, uint8 tabId) const { - if (TabId >= GetPurchasedTabs()) - return; + if (tabId < _GetPurchasedTabsSize()) + if (const RankInfo* rankInfo = GetRankInfo(rankId)) + return rankInfo->GetBankTabSlotsPerDay(tabId); + return 0; +} - if (!m_TabListMap[TabId]) - return; +inline uint8 Guild::_GetRankBankTabRights(uint8 rankId, uint8 tabId) const +{ + if (const RankInfo* rankInfo = GetRankInfo(rankId)) + return rankInfo->GetBankTabRights(tabId); + return 0; +} - if (m_TabListMap[TabId]->Text == text) - return; +inline uint32 Guild::_GetMemberRemainingSlots(const uint64& guid, uint8 tabId) const +{ + if (const Member* pMember = GetMember(guid)) + return pMember->GetBankRemainingValue(tabId, this); + return 0; +} - utf8truncate(text, 500); // DB and client size limitation +inline uint32 Guild::_GetMemberRemainingMoney(const uint64& guid) const +{ + if (const Member* pMember = GetMember(guid)) + return pMember->GetBankRemainingValue(GUILD_BANK_MAX_TABS, this); + return 0; +} - m_TabListMap[TabId]->Text = text; +inline void Guild::_DecreaseMemberRemainingSlots(SQLTransaction& trans, const uint64& guid, uint8 tabId) +{ + // Remaining slots must be more then 0 + if (uint32 remainingSlots = _GetMemberRemainingSlots(guid, tabId)) + // Ignore guild master + if (remainingSlots < GUILD_WITHDRAW_SLOT_UNLIMITED) + if (Member* pMember = GetMember(guid)) + pMember->DecreaseBankRemainingValue(trans, tabId, 1); +} - CharacterDatabase.escape_string(text); - CharacterDatabase.PExecute("UPDATE guild_bank_tab SET TabText='%s' WHERE guildid='%u' AND TabId='%u'", text.c_str(), m_Id, uint32(TabId)); +inline bool Guild::_MemberHasTabRights(const uint64& guid, uint8 tabId, uint32 rights) const +{ + if (const Member* pMember = GetMember(guid)) + { + // Leader always has full rights + if (pMember->IsRank(GR_GUILDMASTER) || m_leaderGuid == guid) + return true; + return (_GetRankBankTabRights(pMember->GetRankId(), tabId) & rights) == rights; + } + return false; +} - // announce - SendGuildBankTabText(NULL,TabId); +// Add new event log record +inline void Guild::_LogEvent(GuildEventLogTypes eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank) +{ + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + m_eventLog->AddEvent(trans, new EventLogEntry(m_id, m_eventLog->GetNextGUID(), eventType, playerGuid1, playerGuid2, newRank)); + CharacterDatabase.CommitTransaction(trans); + + sScriptMgr.OnGuildEvent(this, uint8(eventType), playerGuid1, playerGuid2, newRank); } -void Guild::SendGuildBankTabText(WorldSession *session, uint8 TabId) +// Add new bank event log record +void Guild::_LogBankEvent(SQLTransaction& trans, GuildBankEventLogTypes eventType, uint8 tabId, uint32 lowguid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) { - GuildBankTab const* tab = m_TabListMap[TabId]; + if (tabId > GUILD_BANK_MAX_TABS) + return; - WorldPacket data(MSG_QUERY_GUILD_BANK_TEXT, 1+tab->Text.size()+1); - data << uint8(TabId); - data << tab->Text; + uint8 dbTabId = tabId; + if (BankEventLogEntry::IsMoneyEvent(eventType)) + { + tabId = GUILD_BANK_MAX_TABS; + dbTabId = GUILD_BANK_MONEY_LOGS_TAB; + } + LogHolder* pLog = m_bankEventLog[tabId]; + pLog->AddEvent(trans, new BankEventLogEntry(m_id, pLog->GetNextGUID(), eventType, dbTabId, lowguid, itemOrMoney, itemStackCount, destTabId)); - if (session) - session->SendPacket(&data); - else - BroadcastPacket(&data); + sScriptMgr.OnGuildBankEvent(this, uint8(eventType), tabId, lowguid, itemOrMoney, itemStackCount, destTabId); } -void Guild::SwapItems(Player * pl, uint8 BankTab, uint8 BankTabSlot, uint8 BankTabDst, uint8 BankTabSlotDst, uint32 SplitedAmount) +inline Item* Guild::_GetItem(uint8 tabId, uint8 slotId) const { - // empty operation - if (BankTab == BankTabDst && BankTabSlot == BankTabSlotDst) - return; + if (const BankTab* tab = GetBankTab(tabId)) + return tab->GetItem(slotId); + return NULL; +} - Item *pItemSrc = GetItem(BankTab, BankTabSlot); - if (!pItemSrc) // may prevent crash - return; +inline void Guild::_RemoveItem(SQLTransaction& trans, uint8 tabId, uint8 slotId) +{ + if (BankTab* pTab = GetBankTab(tabId)) + pTab->SetItem(trans, slotId, NULL); +} + +void Guild::_MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAmount) +{ + // 1. Initialize source item + if (!pSrc->InitItem()) + return; // No source item + // 2. Check source item + if (!pSrc->CheckItem(splitedAmount)) + return; // Source item or splited amount is invalid + /* if (pItemSrc->GetCount() == 0) { sLog.outCrash("Guild::SwapItems: Player %s(GUIDLow: %u) tried to move item %u from tab %u slot %u to tab %u slot %u, but item %u has a stack of zero!", - pl->GetName(), pl->GetGUIDLow(), pItemSrc->GetEntry(), BankTab, BankTabSlot, BankTabDst, BankTabSlotDst, pItemSrc->GetEntry()); + player->GetName(), player->GetGUIDLow(), pItemSrc->GetEntry(), tabId, slotId, destTabId, destSlotId, pItemSrc->GetEntry()); //return; // Commented out for now, uncomment when it's verified that this causes a crash!! } + //*/ - if (SplitedAmount >= pItemSrc->GetCount()) - SplitedAmount = 0; // no split + // 3. Check destination rights + if (!pDest->HasStoreRights(pSrc)) + return; // Player has no rights to store item in destination - Item *pItemDst = GetItem(BankTabDst, BankTabSlotDst); + // 4. Check source withdraw rights + if (!pSrc->HasWithdrawRights(pDest)) + return; // Player has no rights to withdraw items from source - if (BankTab != BankTabDst) + // 5. Check split + if (splitedAmount) { - // check dest pos rights (if different tabs) - if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTabDst, GUILD_BANK_RIGHT_DEPOSIT_ITEM)) - return; + // 5.1. Clone source item + if (!pSrc->CloneItem(splitedAmount)) + return; // Item could not be cloned - // check source pos rights (if different tabs) - uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab); - if (remRight <= 0) - return; + // 5.2. Move splited item to destination + _DoItemsMove(pSrc, pDest, true, splitedAmount); } - - if (SplitedAmount) - { // Bank -> Bank item split (in empty or non empty slot - GuildItemPosCountVec dest; - uint8 msg = CanStoreItem(BankTabDst, BankTabSlotDst, dest, SplitedAmount, pItemSrc, false); - if (msg != EQUIP_ERR_OK) - { - pl->SendEquipError(msg, pItemSrc, NULL); - return; - } - - Item *pNewItem = pItemSrc->CloneItem(SplitedAmount); - if (!pNewItem) - { - pl->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItemSrc, NULL); - return; - } - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - LogBankEvent(trans, GUILD_BANK_LOG_MOVE_ITEM, BankTab, pl->GetGUIDLow(), pItemSrc->GetEntry(), SplitedAmount, BankTabDst); - - pl->ItemRemovedQuestCheck(pItemSrc->GetEntry(), SplitedAmount); - pItemSrc->SetCount(pItemSrc->GetCount() - SplitedAmount); - pItemSrc->FSetState(ITEM_CHANGED); - pItemSrc->SaveToDB(trans); // not in inventory and can be save standalone - StoreItem(BankTabDst, dest, pNewItem, trans); - CharacterDatabase.CommitTransaction(trans); - } - else // non split + else // 6. No split { - GuildItemPosCountVec gDest; - uint8 msg = CanStoreItem(BankTabDst, BankTabSlotDst, gDest, pItemSrc->GetCount(), pItemSrc, false); - if (msg == EQUIP_ERR_OK) // merge to + // 6.1. Try to merge items in destination (pDest->GetItem() == NULL) + if (!_DoItemsMove(pSrc, pDest, false)) // Item could not be merged { - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - LogBankEvent(trans, GUILD_BANK_LOG_MOVE_ITEM, BankTab, pl->GetGUIDLow(), pItemSrc->GetEntry(), pItemSrc->GetCount(), BankTabDst); - - RemoveItem(BankTab, BankTabSlot, trans); - StoreItem(BankTabDst, gDest, pItemSrc, trans); - CharacterDatabase.CommitTransaction(trans); - } - else // swap - { - gDest.clear(); - msg = CanStoreItem(BankTabDst, BankTabSlotDst, gDest, pItemSrc->GetCount(), pItemSrc, true); - if (msg != EQUIP_ERR_OK) - { - pl->SendEquipError(msg, pItemSrc, NULL); - return; - } - - GuildItemPosCountVec gSrc; - msg = CanStoreItem(BankTab, BankTabSlot, gSrc, pItemDst->GetCount(), pItemDst, true); - if (msg != EQUIP_ERR_OK) - { - pl->SendEquipError(msg, pItemDst, NULL); + // 6.2. Try to swap items + // 6.2.1. Initialize destination item + if (!pDest->InitItem()) return; - } - if (BankTab != BankTabDst) - { - // check source pos rights (item swapped to src) - if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTab, GUILD_BANK_RIGHT_DEPOSIT_ITEM)) - return; - - // check dest pos rights (item swapped to src) - uint32 remRightDst = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTabDst); - if (remRightDst <= 0) - return; - } + // 6.2.2. Check rights to store item in source (opposite direction) + if (!pSrc->HasStoreRights(pDest)) + return; // Player has no rights to store item in source (opposite direction) - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - LogBankEvent(trans, GUILD_BANK_LOG_MOVE_ITEM, BankTab, pl->GetGUIDLow(), pItemSrc->GetEntry(), pItemSrc->GetCount(), BankTabDst); - LogBankEvent(trans, GUILD_BANK_LOG_MOVE_ITEM, BankTabDst, pl->GetGUIDLow(), pItemDst->GetEntry(), pItemDst->GetCount(), BankTab); + if (!pDest->HasWithdrawRights(pSrc)) + return; // Player has no rights to withdraw item from destination (opposite direction) - RemoveItem(BankTab, BankTabSlot, trans); - RemoveItem(BankTabDst, BankTabSlotDst, trans); - StoreItem(BankTab, gSrc, pItemDst, trans); - StoreItem(BankTabDst, gDest, pItemSrc, trans); - CharacterDatabase.CommitTransaction(trans); + // 6.2.3. Swap items (pDest->GetItem() != NULL) + _DoItemsMove(pSrc, pDest, true); } } - DisplayGuildBankContentUpdate(BankTab,BankTabSlot,BankTab == BankTabDst ? BankTabSlotDst : -1); - if (BankTab != BankTabDst) - DisplayGuildBankContentUpdate(BankTabDst,BankTabSlotDst); + // 7. Send changes + _SendBankContentUpdate(pSrc, pDest); } -void Guild::MoveFromBankToChar(Player * pl, uint8 BankTab, uint8 BankTabSlot, uint8 PlayerBag, uint8 PlayerSlot, uint32 SplitedAmount) +bool Guild::_DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError, uint32 splitedAmount) { - Item *pItemBank = GetItem(BankTab, BankTabSlot); - Item *pItemChar = pl->GetItemByPos(PlayerBag, PlayerSlot); - - if (!pItemBank) // Problem to get bank item - return; + Item* pDestItem = pDest->GetItem(); + bool swap = (pDestItem != NULL); - if (SplitedAmount > pItemBank->GetCount()) - return; // cheating? - else if (SplitedAmount == pItemBank->GetCount()) - SplitedAmount = 0; // no split + Item* pSrcItem = pSrc->GetItem(splitedAmount); + // 1. Can store source item in destination + if (!pDest->CanStore(pSrcItem, swap, sendError)) + return false; - if (SplitedAmount) - { // Bank -> Char split to slot (patly move) - Item *pNewItem = pItemBank->CloneItem(SplitedAmount); - if (!pNewItem) - { - pl->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItemBank, NULL); - return; - } + // 2. Can store destination item in source + if (swap) + if (!pSrc->CanStore(pDestItem, true, true)) + return false; - ItemPosCountVec dest; - uint8 msg = pl->CanStoreItem(PlayerBag, PlayerSlot, dest, pNewItem, false); - if (msg != EQUIP_ERR_OK) - { - pl->SendEquipError(msg, pNewItem, NULL); - delete pNewItem; - return; - } + // GM LOG (TODO: move to scripts) + pDest->LogAction(pSrc); + if (swap) + pSrc->LogAction(pDest); - // check source pos rights (item moved to inventory) - uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab); - if (remRight <= 0) - { - delete pNewItem; - return; - } + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + // 3. Log bank events + pDest->LogBankEvent(trans, pSrc, pSrcItem->GetCount()); + if (swap) + pSrc->LogBankEvent(trans, pDest, pDestItem->GetCount()); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - LogBankEvent(trans, GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), SplitedAmount); + // 4. Remove item from source + pSrc->RemoveItem(trans, pDest, splitedAmount); - pItemBank->SetCount(pItemBank->GetCount()-SplitedAmount); - pItemBank->FSetState(ITEM_CHANGED); - pItemBank->SaveToDB(trans); // not in inventory and can be save standalone - pl->MoveItemToInventory(dest, pNewItem, true); - pl->SaveInventoryAndGoldToDB(trans); + // 5. Remove item from destination + if (swap) + pDest->RemoveItem(trans, pSrc); - MemberItemWithdraw(BankTab, pl->GetGUIDLow(), trans); - CharacterDatabase.CommitTransaction(trans); - } - else // Bank -> Char swap with slot (move) - { - ItemPosCountVec dest; - uint8 msg = pl->CanStoreItem(PlayerBag, PlayerSlot, dest, pItemBank, false); - if (msg == EQUIP_ERR_OK) // merge case - { - // check source pos rights (item moved to inventory) - uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab); - if (remRight <= 0) - return; + // 6. Store item in destination + pDest->StoreItem(trans, pSrcItem); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - LogBankEvent(trans, GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), pItemBank->GetCount()); + // 7. Store item in source + if (swap) + pSrc->StoreItem(trans, pDestItem); - RemoveItem(BankTab, BankTabSlot, trans); - pl->MoveItemToInventory(dest, pItemBank, true); - pl->SaveInventoryAndGoldToDB(trans); + CharacterDatabase.CommitTransaction(trans); + return true; +} - MemberItemWithdraw(BankTab, pl->GetGUIDLow(), trans); - CharacterDatabase.CommitTransaction(trans); - } - else // Bank <-> Char swap items +void Guild::_SendBankContent(WorldSession *session, uint8 tabId) const +{ + const uint64& guid = session->GetPlayer()->GetGUID(); + if (_MemberHasTabRights(guid, tabId, GUILD_BANK_RIGHT_VIEW_TAB)) + if (const BankTab* pTab = GetBankTab(tabId)) { - // check source pos rights (item swapped to bank) - if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTab, GUILD_BANK_RIGHT_DEPOSIT_ITEM)) - return; - - if (pItemChar) - { - if (!pItemChar->CanBeTraded()) - { - pl->SendEquipError(EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, pItemChar, NULL); - return; - } - } + WorldPacket data(SMSG_GUILD_BANK_LIST, 1200); - ItemPosCountVec iDest; - msg = pl->CanStoreItem(PlayerBag, PlayerSlot, iDest, pItemBank, true); - if (msg != EQUIP_ERR_OK) - { - pl->SendEquipError(msg, pItemBank, NULL); - return; - } + data << uint64(m_bankMoney); + data << uint8(tabId); + data << uint32(_GetMemberRemainingSlots(guid, tabId)); + data << uint8(0); // Tell client that there's no tab info in this packet - GuildItemPosCountVec gDest; - if (pItemChar) - { - msg = CanStoreItem(BankTab, BankTabSlot, gDest, pItemChar->GetCount(), pItemChar, true); - if (msg != EQUIP_ERR_OK) - { - pl->SendEquipError(msg, pItemChar, NULL); - return; - } - } + pTab->WritePacket(data); - // check source pos rights (item moved to inventory) - uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab); - if (remRight <= 0) - return; + session->SendPacket(&data); - if (pItemChar) - { - // logging item move to bank - if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getBoolConfig(CONFIG_GM_LOG_TRADE)) - { - sLog.outCommand(pl->GetSession()->GetAccountId(), "GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u)", - pl->GetName(), pl->GetSession()->GetAccountId(), - pItemChar->GetProto()->Name1, pItemChar->GetEntry(), pItemChar->GetCount(), - m_Id); - } - } - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - LogBankEvent(trans, GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), pItemBank->GetCount()); - if (pItemChar) - LogBankEvent(trans, GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), pItemChar->GetCount()); + sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); + } +} - RemoveItem(BankTab, BankTabSlot, trans); - if (pItemChar) - { - pl->MoveItemFromInventory(PlayerBag, PlayerSlot, true); - pItemChar->DeleteFromInventoryDB(trans); - } +void Guild::_SendBankMoneyUpdate(WorldSession *session) const +{ + WorldPacket data(SMSG_GUILD_BANK_LIST, 8 + 1 + 4 + 1 + 1); - if (pItemChar) - StoreItem(BankTab, gDest, pItemChar, trans); - pl->MoveItemToInventory(iDest, pItemBank, true); - pl->SaveInventoryAndGoldToDB(trans); + data << uint64(m_bankMoney); + data << uint8(0); // tabId, default 0 + data << uint32(_GetMemberRemainingSlots(session->GetPlayer()->GetGUID(), 0)); + data << uint8(0); // Tell that there's no tab info in this packet + data << uint8(0); // No items + BroadcastPacket(&data); - MemberItemWithdraw(BankTab, pl->GetGUIDLow(), trans); - CharacterDatabase.CommitTransaction(trans); - } - } - DisplayGuildBankContentUpdate(BankTab,BankTabSlot); + sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); } -void Guild::MoveFromCharToBank(Player * pl, uint8 PlayerBag, uint8 PlayerSlot, uint8 BankTab, uint8 BankTabSlot, uint32 SplitedAmount) +void Guild::_SendBankContentUpdate(MoveItemData* pSrc, MoveItemData* pDest) const { - Item *pItemBank = GetItem(BankTab, BankTabSlot); - Item *pItemChar = pl->GetItemByPos(PlayerBag, PlayerSlot); + ASSERT(pSrc->IsBank() || pDest->IsBank()); - if (!pItemChar) // Problem to get item from player - return; - - // prevent storing non-empty bags - if (pItemChar && pItemChar->IsBag() && !((Bag*)pItemChar)->IsEmpty()) + uint8 tabId; + SlotIds slots; + if (pSrc->IsBank()) // B -> { - pl->SendEquipError(EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS, pItemChar, NULL); - return; + tabId = pSrc->GetContainer(); + slots.insert(pSrc->GetSlotId()); + if (pDest->IsBank()) // B -> B + { + // Same tab - add destination slots to collection + if (pDest->GetContainer() == pSrc->GetContainer()) + pDest->CopySlots(slots); + else // Different tabs - send second message + { + SlotIds destSlots; + pDest->CopySlots(destSlots); + _SendBankContentUpdate(pDest->GetContainer(), destSlots); + } + } } - - if (!pItemChar->CanBeTraded()) + else if (pDest->IsBank()) // C -> B { - pl->SendEquipError(EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, pItemChar, NULL); - return; + tabId = pDest->GetContainer(); + pDest->CopySlots(slots); } + _SendBankContentUpdate(tabId, slots); +} - // check source pos rights (item moved to bank) - if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTab, GUILD_BANK_RIGHT_DEPOSIT_ITEM)) - return; - - if (SplitedAmount > pItemChar->GetCount()) - return; // cheating? - else if (SplitedAmount == pItemChar->GetCount()) - SplitedAmount = 0; // no split - - if (SplitedAmount) - { // Char -> Bank split to empty or non-empty slot (partly move) - GuildItemPosCountVec dest; - uint8 msg = CanStoreItem(BankTab, BankTabSlot, dest, SplitedAmount, pItemChar, false); - if (msg != EQUIP_ERR_OK) - { - pl->SendEquipError(msg, pItemChar, NULL); - return; - } - - Item *pNewItem = pItemChar->CloneItem(SplitedAmount); - if (!pNewItem) - { - pl->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pItemChar, NULL); - return; - } - - // logging item move to bank (before items merge - if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getBoolConfig(CONFIG_GM_LOG_TRADE)) - { - sLog.outCommand(pl->GetSession()->GetAccountId(), "GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u)", - pl->GetName(), pl->GetSession()->GetAccountId(), - pItemChar->GetProto()->Name1, pItemChar->GetEntry(), SplitedAmount,m_Id); - } - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - LogBankEvent(trans, GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), SplitedAmount); - - pl->ItemRemovedQuestCheck(pItemChar->GetEntry(), SplitedAmount); - pItemChar->SetCount(pItemChar->GetCount()-SplitedAmount); - pItemChar->SetState(ITEM_CHANGED, pl); - pl->SaveInventoryAndGoldToDB(trans); - StoreItem(BankTab, dest, pNewItem, trans); - CharacterDatabase.CommitTransaction(trans); - - DisplayGuildBankContentUpdate(BankTab, dest); - } - else // Char -> Bank swap with empty or non-empty (move) +void Guild::_SendBankContentUpdate(uint8 tabId, SlotIds slots) const +{ + if (const BankTab* pTab = GetBankTab(tabId)) { - GuildItemPosCountVec dest; - uint8 msg = CanStoreItem(BankTab, BankTabSlot, dest, pItemChar->GetCount(), pItemChar, false); - if (msg == EQUIP_ERR_OK) // merge - { - // logging item move to bank - if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getBoolConfig(CONFIG_GM_LOG_TRADE)) - { - sLog.outCommand(pl->GetSession()->GetAccountId(), "GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u)", - pl->GetName(), pl->GetSession()->GetAccountId(), - pItemChar->GetProto()->Name1, pItemChar->GetEntry(), pItemChar->GetCount(), - m_Id); - } + WorldPacket data(SMSG_GUILD_BANK_LIST, 1200); - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - LogBankEvent(trans, GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), pItemChar->GetCount()); + data << uint64(m_bankMoney); + data << uint8(tabId); - pl->MoveItemFromInventory(PlayerBag, PlayerSlot, true); - pItemChar->DeleteFromInventoryDB(trans); + size_t rempos = data.wpos(); + data << uint32(0); // Item withdraw amount, will be filled later + data << uint8(0); // Tell client that there's no tab info in this packet - StoreItem(BankTab, dest, pItemChar, trans); - pl->SaveInventoryAndGoldToDB(trans); - CharacterDatabase.CommitTransaction(trans); + data << uint8(slots.size()); + for (uint8 slotId = 0; slotId < GUILD_BANK_MAX_SLOTS; ++slotId) + if (slots.find(slotId) != slots.end()) + pTab->WriteSlotPacket(data, slotId); - DisplayGuildBankContentUpdate(BankTab, dest); - } - else // Char <-> Bank swap items (posible NULL bank item) - { - ItemPosCountVec iDest; - if (pItemBank) - { - msg = pl->CanStoreItem(PlayerBag, PlayerSlot, iDest, pItemBank, true); - if (msg != EQUIP_ERR_OK) + for (Members::const_iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + if (_MemberHasTabRights(itr->second->GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB)) + if (Player *player = itr->second->FindPlayer()) { - pl->SendEquipError(msg, pItemBank, NULL); - return; + data.put<uint32>(rempos, uint32(_GetMemberRemainingSlots(player->GetGUID(), tabId))); + player->GetSession()->SendPacket(&data); } - } - GuildItemPosCountVec gDest; - msg = CanStoreItem(BankTab, BankTabSlot, gDest, pItemChar->GetCount(), pItemChar, true); - if (msg != EQUIP_ERR_OK) - { - pl->SendEquipError(msg, pItemChar, NULL); - return; - } - - if (pItemBank) - { - // check bank pos rights (item swapped with inventory) - uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab); - if (remRight <= 0) - return; - } - - // logging item move to bank - if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getBoolConfig(CONFIG_GM_LOG_TRADE)) - { - sLog.outCommand(pl->GetSession()->GetAccountId(), "GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u)", - pl->GetName(), pl->GetSession()->GetAccountId(), - pItemChar->GetProto()->Name1, pItemChar->GetEntry(), pItemChar->GetCount(), - m_Id); - } - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - if (pItemBank) - LogBankEvent(trans, GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), pItemBank->GetCount()); - LogBankEvent(trans, GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), pItemChar->GetCount()); - - pl->MoveItemFromInventory(PlayerBag, PlayerSlot, true); - pItemChar->DeleteFromInventoryDB(trans); - if (pItemBank) - RemoveItem(BankTab, BankTabSlot, trans); - - StoreItem(BankTab,gDest,pItemChar, trans); - if (pItemBank) - pl->MoveItemToInventory(iDest, pItemBank, true); - pl->SaveInventoryAndGoldToDB(trans); - if (pItemBank) - MemberItemWithdraw(BankTab, pl->GetGUIDLow(), trans); - CharacterDatabase.CommitTransaction(trans); - - DisplayGuildBankContentUpdate(BankTab, gDest); - } + sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)"); } } -void Guild::BroadcastEvent(GuildEvents event, uint64 guid, uint8 strCount, std::string str1, std::string str2, std::string str3) +void Guild::_BroadcastEvent(GuildEvents guildEvent, const uint64& guid, const char* param1, const char* param2, const char* param3) const { - WorldPacket data(SMSG_GUILD_EVENT, 1+1+(guid ? 8 : 0)); - data << uint8(event); - data << uint8(strCount); + uint8 count = !param3 ? (!param2 ? (!param1 ? 0 : 1) : 2) : 3; - switch(strCount) - { - case 0: - break; - case 1: - data << str1; - break; - case 2: - data << str1 << str2; - break; - case 3: - data << str1 << str2 << str3; - break; - default: - sLog.outError("Guild::BroadcastEvent: incorrect strings count %u!", strCount); - break; - } + WorldPacket data(SMSG_GUILD_EVENT, 1 + 1 + count + (guid ? 8 : 0)); + data << uint8(guildEvent); + data << uint8(count); + + if (param3) + data << param1 << param2 << param3; + else if (param2) + data << param1 << param2; + else if (param1) + data << param1; if (guid) data << uint64(guid); @@ -2155,35 +2753,3 @@ void Guild::BroadcastEvent(GuildEvents event, uint64 guid, uint8 strCount, std:: sLog.outDebug("WORLD: Sent SMSG_GUILD_EVENT"); } - -void Guild::DeleteGuildBankItems(SQLTransaction& trans, bool alsoInDB /*= false*/) -{ - for (size_t i = 0; i < m_TabListMap.size(); ++i) - { - for (uint8 j = 0; j < GUILD_BANK_MAX_SLOTS; ++j) - { - if (Item*& pItem = m_TabListMap[i]->Slots[j]) - { - pItem->RemoveFromWorld(); - - if (alsoInDB) - pItem->DeleteFromDB(trans); - - delete pItem; - pItem = NULL; - } - } - delete m_TabListMap[i]; - m_TabListMap[i] = NULL; - } - m_TabListMap.clear(); -} - -bool GuildItemPosCount::isContainedIn(GuildItemPosCountVec const &vec) const -{ - for (GuildItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end(); ++itr) - if (itr->Slot == this->Slot) - return true; - - return false; -} diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index 5ebb646cd73..311c0e4bcb8 100755 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -19,52 +19,63 @@ #ifndef TRINITYCORE_GUILD_H #define TRINITYCORE_GUILD_H -#define WITHDRAW_MONEY_UNLIMITED 0xFFFFFFFF -#define WITHDRAW_SLOT_UNLIMITED 0xFFFFFFFF - +#include "World.h" #include "Item.h" +#include "WorldPacket.h" +#include "ObjectMgr.h" +#include "Player.h" class Item; -#define GUILD_RANKS_MIN_COUNT 5 -#define GUILD_RANKS_MAX_COUNT 10 +enum GuildMisc +{ + GUILD_BANK_MAX_TABS = 6, // send by client for money log also + GUILD_BANK_MAX_SLOTS = 98, + GUILD_BANK_MONEY_LOGS_TAB = 100, // used for money log in DB + GUILD_RANKS_MIN_COUNT = 5, + GUILD_RANKS_MAX_COUNT = 10, + GUILD_RANK_NONE = 0xFF, + GUILD_WITHDRAW_MONEY_UNLIMITED = 0xFFFFFFFF, + GUILD_WITHDRAW_SLOT_UNLIMITED = 0xFFFFFFFF, + GUILD_EVENT_LOG_GUID_UNDEFINED = 0xFFFFFFFF, +}; enum GuildDefaultRanks { - //these ranks can be modified, but they cannot be deleted + // These ranks can be modified, but they cannot be deleted GR_GUILDMASTER = 0, GR_OFFICER = 1, GR_VETERAN = 2, GR_MEMBER = 3, GR_INITIATE = 4, - //When promoting member server does: rank--;! - //When demoting member server does: rank++;! + // When promoting member server does: rank-- + // When demoting member server does: rank++ }; enum GuildRankRights { GR_RIGHT_EMPTY = 0x00000040, - GR_RIGHT_GCHATLISTEN = 0x00000041, - GR_RIGHT_GCHATSPEAK = 0x00000042, - GR_RIGHT_OFFCHATLISTEN = 0x00000044, - GR_RIGHT_OFFCHATSPEAK = 0x00000048, - GR_RIGHT_PROMOTE = 0x000000C0, - GR_RIGHT_DEMOTE = 0x00000140, - GR_RIGHT_INVITE = 0x00000050, - GR_RIGHT_REMOVE = 0x00000060, - GR_RIGHT_SETMOTD = 0x00001040, - GR_RIGHT_EPNOTE = 0x00002040, - GR_RIGHT_VIEWOFFNOTE = 0x00004040, - GR_RIGHT_EOFFNOTE = 0x00008040, - GR_RIGHT_MODIFY_GUILD_INFO = 0x00010040, - GR_RIGHT_WITHDRAW_GOLD_LOCK = 0x00020000, // remove money withdraw capacity - GR_RIGHT_WITHDRAW_REPAIR = 0x00040000, // withdraw for repair - GR_RIGHT_WITHDRAW_GOLD = 0x00080000, // withdraw gold - GR_RIGHT_CREATE_GUILD_EVENT = 0x00100000, // wotlk + GR_RIGHT_GCHATLISTEN = GR_RIGHT_EMPTY | 0x00000001, + GR_RIGHT_GCHATSPEAK = GR_RIGHT_EMPTY | 0x00000002, + GR_RIGHT_OFFCHATLISTEN = GR_RIGHT_EMPTY | 0x00000004, + GR_RIGHT_OFFCHATSPEAK = GR_RIGHT_EMPTY | 0x00000008, + GR_RIGHT_INVITE = GR_RIGHT_EMPTY | 0x00000010, + GR_RIGHT_REMOVE = GR_RIGHT_EMPTY | 0x00000020, + GR_RIGHT_PROMOTE = GR_RIGHT_EMPTY | 0x00000080, + GR_RIGHT_DEMOTE = GR_RIGHT_EMPTY | 0x00000100, + GR_RIGHT_SETMOTD = GR_RIGHT_EMPTY | 0x00001000, + GR_RIGHT_EPNOTE = GR_RIGHT_EMPTY | 0x00002000, + GR_RIGHT_VIEWOFFNOTE = GR_RIGHT_EMPTY | 0x00004000, + GR_RIGHT_EOFFNOTE = GR_RIGHT_EMPTY | 0x00008000, + GR_RIGHT_MODIFY_GUILD_INFO = GR_RIGHT_EMPTY | 0x00010000, + GR_RIGHT_WITHDRAW_GOLD_LOCK = 0x00020000, // remove money withdraw capacity + GR_RIGHT_WITHDRAW_REPAIR = 0x00040000, // withdraw for repair + GR_RIGHT_WITHDRAW_GOLD = 0x00080000, // withdraw gold + GR_RIGHT_CREATE_GUILD_EVENT = 0x00100000, // wotlk GR_RIGHT_ALL = 0x001DF1FF }; -enum Typecommand +enum GuildCommandType { GUILD_CREATE_S = 0x00, GUILD_INVITE_S = 0x01, @@ -74,7 +85,7 @@ enum Typecommand GUILD_UNK2 = 0x14 }; -enum CommandErrors +enum GuildCommandError { ERR_PLAYER_NO_MORE_IN_GUILD = 0x00, ERR_GUILD_INTERNAL = 0x01, @@ -118,11 +129,11 @@ enum GuildEvents GE_UNK2 = 0x0B, // EVENT_GUILD_ROSTER_UPDATE GE_SIGNED_ON = 0x0C, // ERR_FRIEND_ONLINE_SS GE_SIGNED_OFF = 0x0D, // ERR_FRIEND_OFFLINE_S - GE_GUILDBANKBAGSLOTS_CHANGED = 0x0E, // EVENT_GUILDBANKBAGSLOTS_CHANGED - GE_BANKTAB_PURCHASED = 0x0F, // EVENT_GUILDBANK_UPDATE_TABS + GE_GUILDBANK_BAGSLOTS_CHANGED = 0x0E, // EVENT_GUILDBANK_BAGSLOTS_CHANGED + GE_GUILDBANK_TAB_PURCHASED = 0x0F, // EVENT_GUILDBANK_UPDATE_TABS GE_UNK5 = 0x10, // EVENT_GUILDBANK_UPDATE_TABS - GE_GUILDBANK_UPDATE_MONEY = 0x11, // EVENT_GUILDBANK_UPDATE_MONEY, string 0000000000002710 is 1 gold - GE_GUILD_BANK_MONEY_WITHDRAWN = 0x12, // MSG_GUILD_BANK_MONEY_WITHDRAWN + GE_GUILDBANK_MONEY_UPDATE = 0x11, // EVENT_GUILDBANK_UPDATE_MONEY, string 0000000000002710 is 1 gold + GE_GUILDBANK_MONEY_WITHDRAWN = 0x12, // MSG_GUILD_BANK_MONEY_WITHDRAWN GE_GUILDBANK_TEXT_CHANGED = 0x13 // EVENT_GUILDBANK_TEXT_CHANGED }; @@ -175,7 +186,7 @@ enum GuildEventLogTypes GUILD_EVENT_LOG_LEAVE_GUILD = 6, }; -enum GuildEmblem +enum GuildEmblemError { ERR_GUILDEMBLEM_SUCCESS = 0, ERR_GUILDEMBLEM_INVALID_TABARD_COLORS = 1, @@ -185,298 +196,575 @@ enum GuildEmblem ERR_GUILDEMBLEM_INVALIDVENDOR = 5 }; -inline uint32 GetGuildBankTabPrice(uint8 Index) -{ - switch(Index) - { - case 0: return 100; - case 1: return 250; - case 2: return 500; - case 3: return 1000; - case 4: return 2500; - case 5: return 5000; - default: - return 0; - } -} - -struct GuildEventLogEntry +//////////////////////////////////////////////////////////////////////////////////////////// +// Emblem info +class EmblemInfo { - uint8 EventType; - uint32 PlayerGuid1; - uint32 PlayerGuid2; - uint8 NewRank; - uint64 TimeStamp; +public: + EmblemInfo() : m_style(0), m_color(0), m_borderStyle(0), m_borderColor(0), m_backgroundColor(0) { } + + void LoadFromDB(Field* fields); + void SaveToDB(uint32 guildId) const; + void ReadPacket(WorldPacket& recv) { recv >> m_style >> m_color >> m_borderStyle >> m_borderColor >> m_backgroundColor; } + void WritePacket(WorldPacket& data) const; + + uint32 GetStyle() const { return m_style; } + uint32 GetColor() const { return m_color; } + uint32 GetBorderStyle() const { return m_borderStyle; } + uint32 GetBorderColor() const { return m_borderColor; } + uint32 GetBackgroundColor() const { return m_backgroundColor; } + +private: + uint32 m_style; + uint32 m_color; + uint32 m_borderStyle; + uint32 m_borderColor; + uint32 m_backgroundColor; }; -struct GuildBankEventLogEntry +// Structure for storing guild bank rights and remaining slots together. +struct GuildBankRightsAndSlots { - uint8 EventType; - uint32 PlayerGuid; - uint32 ItemOrMoney; - uint16 ItemStackCount; - uint8 DestTabId; - uint64 TimeStamp; - - bool isMoneyEvent() + GuildBankRightsAndSlots() : rights(0), slots(0) { } + GuildBankRightsAndSlots(uint8 _rights, uint32 _slots) : rights(_rights), slots(_slots) { } + + inline bool IsEqual(const GuildBankRightsAndSlots& rhs) const { return rights == rhs.rights && slots == rhs.slots; } + void SetGuildMasterValues() { - return EventType == GUILD_BANK_LOG_DEPOSIT_MONEY || - EventType == GUILD_BANK_LOG_WITHDRAW_MONEY || - EventType == GUILD_BANK_LOG_REPAIR_MONEY; + rights = GUILD_BANK_RIGHT_FULL; + slots = GUILD_WITHDRAW_SLOT_UNLIMITED; } + + uint8 rights; + uint32 slots; }; +typedef std::vector <GuildBankRightsAndSlots> GuildBankRightsAndSlotsVec; + +typedef std::set <uint8> SlotIds; -struct GuildBankTab +class Guild { - GuildBankTab() { memset(Slots, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*)); } +private: + // Class representing guild member + class Member + { + struct RemainingValue + { + RemainingValue() : value(0), resetTime(0) { } - Item* Slots[GUILD_BANK_MAX_SLOTS]; - std::string Name; - std::string Icon; - std::string Text; -}; + uint32 value; + uint32 resetTime; + }; -struct GuildItemPosCount -{ - GuildItemPosCount(uint8 _slot, uint32 _count) : Slot(_slot), Count(_count) {} + public: + Member(uint32 guildId, const uint64& guid, uint8 rankId) : m_guildId(guildId), m_guid(guid), m_logoutTime(::time(NULL)), m_rankId(rankId) { } - bool isContainedIn(std::vector<GuildItemPosCount> const& vec) const; + void SetStats(Player* player); + void SetStats(const std::string& name, uint8 level, uint8 _class, uint32 zoneId, uint32 accountId); + bool CheckStats() const; - uint8 Slot; - uint32 Count; -}; -typedef std::vector<GuildItemPosCount> GuildItemPosCountVec; + void SetPublicNote(const std::string& publicNote); + void SetOfficerNote(const std::string& officerNote); -struct MemberSlot -{ - uint64 LogoutTime; - uint32 accountId; - std::string Name; - std::string Pnote; - std::string OFFnote; - uint32 RankId; - uint32 ZoneId; - uint8 Level; - uint8 Class; - uint32 BankResetTimeMoney; - uint32 BankRemMoney; - uint32 BankResetTimeTab[GUILD_BANK_MAX_TABS]; - uint32 BankRemSlotsTab[GUILD_BANK_MAX_TABS]; -}; + bool LoadFromDB(Field* fields); + void SaveToDB(SQLTransaction& trans) const; + void WritePacket(WorldPacket& data) const; -struct RankInfo -{ - RankInfo(const std::string& _name, uint32 _rights, uint32 _money) : Name(_name), Rights(_rights), BankMoneyPerDay(_money) + const uint64& GetGUID() const { return m_guid; } + std::string GetName() const { return m_name; } + uint32 GetAccountId() const { return m_accountId; } + uint8 GetRankId() const { return m_rankId; } + + void ChangeRank(uint8 newRank); + + inline void UpdateLogoutTime() { m_logoutTime = ::time(NULL); } + inline bool IsRank(uint8 rankId) const { return m_rankId == rankId; } + inline bool IsRankNotLower(uint8 rankId) const { return m_rankId <= rankId; } + inline bool IsSamePlayer(const uint64& guid) const { return m_guid == guid; } + + void DecreaseBankRemainingValue(SQLTransaction& trans, uint8 tabId, uint32 amount); + uint32 GetBankRemainingValue(uint8 tabId, const Guild* guild) const; + + void ResetTabTimes(); + void ResetMoneyTime(); + + inline Player* FindPlayer() const { return sObjectMgr.GetPlayer(m_guid); } + + private: + uint32 m_guildId; + // Fields from characters table + uint64 m_guid; + std::string m_name; + uint32 m_zoneId; + uint8 m_level; + uint8 m_class; + uint64 m_logoutTime; + uint32 m_accountId; + // Fields from guild_member table + uint8 m_rankId; + std::string m_publicNote; + std::string m_officerNote; + + RemainingValue m_bankRemaining[GUILD_BANK_MAX_TABS + 1]; + }; + + // Base class for event entries + class LogEntry { - for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i) - { - TabRight[i] = 0; - TabSlotPerDay[i] = 0; - } - } + public: + LogEntry(uint32 guildId, uint32 guid) : m_guildId(guildId), m_guid(guid), m_timestamp(::time(NULL)) { } + LogEntry(uint32 guildId, uint32 guid, time_t timestamp) : m_guildId(guildId), m_guid(guid), m_timestamp(timestamp) { } + virtual ~LogEntry() { } - std::string Name; - uint32 Rights; - uint32 BankMoneyPerDay; - uint32 TabRight[GUILD_BANK_MAX_TABS]; - uint32 TabSlotPerDay[GUILD_BANK_MAX_TABS]; -}; + uint32 GetGUID() const { return m_guid; } -class Guild -{ - friend class ObjectMgr; + virtual void SaveToDB(SQLTransaction& trans) const = 0; + virtual void WritePacket(WorldPacket& data) const = 0; + + protected: + uint32 m_guildId; + uint32 m_guid; + uint64 m_timestamp; + }; + + // Event log entry + class EventLogEntry : public LogEntry + { public: - Guild(); - ~Guild(); - - bool Create(Player* leader, std::string gname); - void CreateDefaultGuildRanks(LocaleConstant locale_idx); - void Disband(); - - void DeleteGuildBankItems(SQLTransaction& trans, bool alsoInDB = false); - typedef std::map<uint32, MemberSlot> MemberList; - typedef std::vector<RankInfo> RankList; - - uint32 GetId(){ return m_Id; } - const uint64& GetLeader(){ return m_LeaderGuid; } - std::string const& GetName() const { return m_Name; } - std::string const& GetMOTD() const { return MOTD; } - std::string const& GetGINFO() const { return GINFO; } - - time_t GetCreatedDate() const { return m_CreatedDate; } - - uint32 GetEmblemStyle() const { return m_EmblemStyle; } - uint32 GetEmblemColor() const { return m_EmblemColor; } - uint32 GetBorderStyle() const { return m_BorderStyle; } - uint32 GetBorderColor() const { return m_BorderColor; } - uint32 GetBackgroundColor() const { return m_BackgroundColor; } - - void SetLeader(uint64 guid); - bool AddMember(uint64 plGuid, uint32 plRank); - void ChangeRank(uint64 guid, uint32 newRank); - void DelMember(uint64 guid, bool isDisbanding = false, bool isKicked = false); - //lowest rank is the count of ranks - 1 (the highest rank_id in table) - uint32 GetLowestRank() const { return m_Ranks.size() - 1; } - - void SetMOTD(std::string motd); - void SetGINFO(std::string ginfo); - void SetPNOTE(uint64 guid, std::string pnote); - void SetOFFNOTE(uint64 guid, std::string offnote); - void SetEmblem(uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor); - - uint32 GetMemberSize() const { return members.size(); } - uint32 GetAccountsNumber() const { return m_accountsNumber; } - - bool LoadGuildFromDB(QueryResult guildDataResult); - bool CheckGuildStructure(); - bool LoadRanksFromDB(QueryResult guildRanksResult); - bool LoadMembersFromDB(QueryResult guildMembersResult); - - void SetMemberStats(uint64 guid); - - void BroadcastToGuild(WorldSession *session, const std::string& msg, uint32 language = LANG_UNIVERSAL); - void BroadcastToOfficers(WorldSession *session, const std::string& msg, uint32 language = LANG_UNIVERSAL); - void BroadcastPacketToRank(WorldPacket *packet, uint32 rankId); - void BroadcastPacket(WorldPacket *packet); - void BroadcastEvent(GuildEvents event, uint64 guid, uint8 strCount, std::string str1, std::string str2, std::string str3); - - template<class Do> - void BroadcastWorker(Do& _do, Player* except = NULL) + EventLogEntry(uint32 guildId, uint32 guid, GuildEventLogTypes eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank) : + LogEntry(guildId, guid), m_eventType(eventType), m_playerGuid1(playerGuid1), m_playerGuid2(playerGuid2), m_newRank(newRank) { } + + EventLogEntry(uint32 guildId, uint32 guid, time_t timestamp, GuildEventLogTypes eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank) : + LogEntry(guildId, guid, timestamp), m_eventType(eventType), m_playerGuid1(playerGuid1), m_playerGuid2(playerGuid2), m_newRank(newRank) { } + + ~EventLogEntry() { } + + void SaveToDB(SQLTransaction& trans) const; + void WritePacket(WorldPacket& data) const; + + private: + GuildEventLogTypes m_eventType; + uint32 m_playerGuid1; + uint32 m_playerGuid2; + uint8 m_newRank; + }; + + // Bank event log entry + class BankEventLogEntry : public LogEntry + { + public: + static bool IsMoneyEvent(GuildBankEventLogTypes eventType) { - for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) - if (Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER))) - if (player != except) - _do(player); + return + eventType == GUILD_BANK_LOG_DEPOSIT_MONEY || + eventType == GUILD_BANK_LOG_WITHDRAW_MONEY || + eventType == GUILD_BANK_LOG_REPAIR_MONEY; } - void CreateRank(std::string name,uint32 rights); - void DelRank(); - std::string GetRankName(uint32 rankId); - uint32 GetRankRights(uint32 rankId); - uint32 GetRanksSize() const { return m_Ranks.size(); } + BankEventLogEntry(uint32 guildId, uint32 guid, GuildBankEventLogTypes eventType, uint8 tabId, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) : + LogEntry(guildId, guid), m_eventType(eventType), m_bankTabId(tabId), m_playerGuid(playerGuid), + m_itemOrMoney(itemOrMoney), m_itemStackCount(itemStackCount), m_destTabId(destTabId) { } + + BankEventLogEntry(uint32 guildId, uint32 guid, time_t timestamp, uint8 tabId, GuildBankEventLogTypes eventType, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) : + LogEntry(guildId, guid, timestamp), m_eventType(eventType), m_bankTabId(tabId), m_playerGuid(playerGuid), + m_itemOrMoney(itemOrMoney), m_itemStackCount(itemStackCount), m_destTabId(destTabId) { } - void SetRankName(uint32 rankId, std::string name); - void SetRankRights(uint32 rankId, uint32 rights); - bool HasRankRight(uint32 rankId, uint32 right) + ~BankEventLogEntry() { } + + void SaveToDB(SQLTransaction& trans) const; + void WritePacket(WorldPacket& data) const; + + private: + GuildBankEventLogTypes m_eventType; + uint8 m_bankTabId; + uint32 m_playerGuid; + uint32 m_itemOrMoney; + uint16 m_itemStackCount; + uint8 m_destTabId; + }; + + // Class encapsulating work with events collection + class LogHolder + { + public: + LogHolder(uint32 guildId, uint32 maxRecords) : m_guildId(guildId), m_maxRecords(maxRecords), m_nextGUID(GUILD_EVENT_LOG_GUID_UNDEFINED) { } + ~LogHolder(); + + uint8 GetSize() const { return uint8(m_log.size()); } + // Checks if new log entry can be added to holder when loading from DB + inline bool CanInsert() const { return m_log.size() < m_maxRecords; } + // Adds event from DB to collection + void LoadEvent(LogEntry* entry); + // Adds new event to collection and saves it to DB + void AddEvent(SQLTransaction& trans, LogEntry* entry); + // Writes information about all events to packet + void WritePacket(WorldPacket& data) const; + uint32 GetNextGUID(); + + private: + typedef std::list<LogEntry*> GuildLog; + GuildLog m_log; + uint32 m_guildId; + uint32 m_maxRecords; + uint32 m_nextGUID; + }; + + // Class incapsulating guild rank data + class RankInfo + { + public: + RankInfo(uint32 guildId) : m_guildId(guildId), m_rankId(GUILD_RANK_NONE), m_rights(GR_RIGHT_EMPTY), m_bankMoneyPerDay(0) { } + RankInfo(uint32 guildId, uint8 rankId, const std::string& name, uint32 rights, uint32 money) : + m_guildId(guildId), m_rankId(rankId), m_name(name), m_rights(rights), m_bankMoneyPerDay(money) { } + + bool LoadFromDB(Field* fields); + void SaveToDB(SQLTransaction& trans) const; + void WritePacket(WorldPacket& data) const; + + uint8 GetId() const { return m_rankId; } + + std::string GetName() const { return m_name; } + void SetName(const std::string& name); + + uint32 GetRights() const { return m_rights; } + void SetRights(uint32 rights); + + uint32 GetBankMoneyPerDay() const { return m_rankId == GR_GUILDMASTER ? GUILD_WITHDRAW_MONEY_UNLIMITED : m_bankMoneyPerDay; } + void SetBankMoneyPerDay(uint32 money); + + inline uint8 GetBankTabRights(uint8 tabId) const { return tabId < GUILD_BANK_MAX_TABS ? m_bankTabRightsAndSlots[tabId].rights : 0; } + inline uint32 GetBankTabSlotsPerDay(uint8 tabId) const { - return ((GetRankRights(rankId) & right) != GR_RIGHT_EMPTY) ? true : false; + if (tabId < GUILD_BANK_MAX_TABS) + return m_rankId == GR_GUILDMASTER ? GUILD_WITHDRAW_SLOT_UNLIMITED : m_bankTabRightsAndSlots[tabId].slots; + return 0; } - int32 GetRank(uint32 LowGuid); - bool IsMember(uint32 LowGuid) + void SetBankTabSlotsAndRights(uint8 tabId, GuildBankRightsAndSlots rightsAndSlots, bool saveToDB); + + private: + uint32 m_guildId; + + uint8 m_rankId; + std::string m_name; + uint32 m_rights; + uint32 m_bankMoneyPerDay; + GuildBankRightsAndSlots m_bankTabRightsAndSlots[GUILD_BANK_MAX_TABS]; + }; + + class BankTab + { + public: + BankTab(uint32 guildId, uint8 tabId) : m_guildId(guildId), m_tabId(tabId) { - return (members.find(LowGuid) != members.end()); + memset(m_items, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*)); } - MemberSlot* GetMemberSlot(const std::string& name, uint64& guid) + + bool LoadFromDB(Field* fields); + bool LoadItemFromDB(Field* fields); + void Delete(SQLTransaction& trans, bool removeItemsFromDB = false); + + void WritePacket(WorldPacket& data) const; + void WriteSlotPacket(WorldPacket& data, uint8 slotId) const; + void WriteInfoPacket(WorldPacket& data) const { - for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr) - { - if (itr->second.Name == name) - { - guid = itr->first; - return &itr->second; - } - } - return NULL; + data << m_name; + data << m_icon; } - void Roster(WorldSession *session = NULL); // NULL = broadcast - void Query(WorldSession *session); - - void UpdateLogoutTime(uint64 guid); - // Guild EventLog - void DisplayGuildEventLog(WorldSession *session); - void LogGuildEvent(uint8 EventType, uint32 PlayerGuid1, uint32 PlayerGuid2, uint8 NewRank); - - // ** Guild bank ** - // Content & item deposit/withdraw - void DisplayGuildBankContent(WorldSession *session, uint8 TabId); - void DisplayGuildBankMoneyUpdate(WorldSession *session); - - void SwapItems(Player * pl, uint8 BankTab, uint8 BankTabSlot, uint8 BankTabDst, uint8 BankTabSlotDst, uint32 SplitedAmount); - void MoveFromBankToChar(Player * pl, uint8 BankTab, uint8 BankTabSlot, uint8 PlayerBag, uint8 PlayerSlot, uint32 SplitedAmount); - void MoveFromCharToBank(Player * pl, uint8 PlayerBag, uint8 PlayerSlot, uint8 BankTab, uint8 BankTabSlot, uint32 SplitedAmount); - - // Tabs - void DisplayGuildBankTabsInfo(WorldSession *session); - void CreateNewBankTab(); - void SetGuildBankTabText(uint8 TabId, std::string text); - void SendGuildBankTabText(WorldSession *session, uint8 TabId); - void SetGuildBankTabInfo(uint8 TabId, std::string name, std::string icon); - uint8 GetPurchasedTabs() const { return m_TabListMap.size(); } - uint32 GetBankRights(uint32 rankId, uint8 TabId) const; - bool IsMemberHaveRights(uint32 LowGuid, uint8 TabId,uint32 rights) const; - bool CanMemberViewTab(uint32 LowGuid, uint8 TabId) const; - // Money deposit/withdraw - void SendMoneyInfo(WorldSession *session, uint32 LowGuid); - bool MemberMoneyWithdraw(uint32 amount, uint32 LowGuid, SQLTransaction& trans); - uint64 GetGuildBankMoney() { return m_GuildBankMoney; } - void SetBankMoney(int64 money, SQLTransaction& trans); - // per days - bool MemberItemWithdraw(uint8 TabId, uint32 LowGuid, SQLTransaction& trans); - uint32 GetMemberSlotWithdrawRem(uint32 LowGuid, uint8 TabId); - uint32 GetMemberMoneyWithdrawRem(uint32 LowGuid); - void SetBankMoneyPerDay(uint32 rankId, uint32 money); - void SetBankRightsAndSlots(uint32 rankId, uint8 TabId, uint32 right, uint32 SlotPerDay, bool db); - uint32 GetBankMoneyPerDay(uint32 rankId); - uint32 GetBankSlotPerDay(uint32 rankId, uint8 TabId); - // rights per day - bool LoadBankRightsFromDB(QueryResult guildBankTabRightsResult); - // Guild Bank Event Logs - void DisplayGuildBankLogs(WorldSession *session, uint8 TabId); - void LogBankEvent(SQLTransaction& trans, uint8 EventType, uint8 TabId, uint32 PlayerGuidLow, uint32 ItemOrMoney, uint16 ItemStackCount=0, uint8 DestTabId=0); - bool AddGBankItemToDB(uint32 GuildId, uint32 BankTab , uint32 BankTabSlot , uint32 GUIDLow, uint32 Entry, SQLTransaction& trans); + void SetInfo(const std::string& name, const std::string& icon); + void SetText(const std::string& text); + void SendText(const Guild* pGuild, WorldSession* session) const; - protected: - void AddRank(const std::string& name,uint32 rights,uint32 money); + inline Item* GetItem(uint8 slotId) const { return slotId < GUILD_BANK_MAX_SLOTS ? m_items[slotId] : NULL; } + bool SetItem(SQLTransaction& trans, uint8 slotId, Item* pItem); - uint32 m_Id; - std::string m_Name; - uint64 m_LeaderGuid; - std::string MOTD; - std::string GINFO; - time_t m_CreatedDate; + private: + uint32 m_guildId; + uint8 m_tabId; - uint32 m_EmblemStyle; - uint32 m_EmblemColor; - uint32 m_BorderStyle; - uint32 m_BorderColor; - uint32 m_BackgroundColor; - uint32 m_accountsNumber; + Item* m_items[GUILD_BANK_MAX_SLOTS]; + std::string m_name; + std::string m_icon; + std::string m_text; + }; - RankList m_Ranks; + // Movement data + class MoveItemData + { + public: + MoveItemData(Guild* pGuild, Player* player, uint8 container, uint8 slotId) : m_pGuild(pGuild), m_pPlayer(player), + m_container(container), m_slotId(slotId), m_pItem(NULL), m_pClonedItem(NULL) { } + virtual ~MoveItemData() { } + + virtual bool IsBank() const = 0; + // Initializes item pointer. Returns true, if item exists, false otherwise. + virtual bool InitItem() = 0; + // Checks splited amount against item. Splited amount cannot be more that number of items in stack. + virtual bool CheckItem(uint32& splitedAmount); + // Defines if player has rights to save item in container + virtual bool HasStoreRights(MoveItemData* /*pOther*/) const { return true; } + // Defines if player has rights to withdraw item from container + virtual bool HasWithdrawRights(MoveItemData* /*pOther*/) const { return true; } + // Checks if container can store specified item + uint8 CanStore(Item* pItem, bool swap, bool sendError); + // Clones stored item + bool CloneItem(uint32 count); + // Remove item from container (if splited update items fields) + virtual void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount = 0) = 0; + // Saves item to container + virtual Item* StoreItem(SQLTransaction& trans, Item* pItem) = 0; + // Log bank event + virtual void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const = 0; + // Log GM action + virtual void LogAction(MoveItemData* pFrom) const; + // Copy slots id from position vector + void CopySlots(SlotIds& ids) const; + + Item* GetItem(bool isCloned = false) const { return isCloned ? m_pClonedItem : m_pItem; } + uint8 GetContainer() const { return m_container; } + uint8 GetSlotId() const { return m_slotId; } + protected: + virtual uint8 _CanStore(Item* pItem, bool swap) = 0; + + Guild* m_pGuild; + Player *m_pPlayer; + uint8 m_container; + uint8 m_slotId; + Item* m_pItem; + Item* m_pClonedItem; + ItemPosCountVec m_vec; + }; + + class PlayerMoveItemData : public MoveItemData + { + public: + PlayerMoveItemData(Guild* pGuild, Player* player, uint8 container, uint8 slotId) : + MoveItemData(pGuild, player, container, slotId) { } + + bool IsBank() const { return false; } + bool InitItem(); + void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount = 0); + Item* StoreItem(SQLTransaction& trans, Item* pItem); + void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const; + protected: + uint8 _CanStore(Item* pItem, bool swap); + }; - MemberList members; + class BankMoveItemData : public MoveItemData + { + public: + BankMoveItemData(Guild* pGuild, Player* player, uint8 container, uint8 slotId) : + MoveItemData(pGuild, player, container, slotId) { } + + bool IsBank() const { return true; } + bool InitItem(); + bool HasStoreRights(MoveItemData* pOther) const; + bool HasWithdrawRights(MoveItemData* pOther) const; + void RemoveItem(SQLTransaction& trans, MoveItemData* pOther, uint32 splitedAmount); + Item* StoreItem(SQLTransaction& trans, Item* pItem); + void LogBankEvent(SQLTransaction& trans, MoveItemData* pFrom, uint32 count) const; + void LogAction(MoveItemData* pFrom) const; - typedef std::vector<GuildBankTab*> TabListMap; - TabListMap m_TabListMap; + protected: + uint8 _CanStore(Item* pItem, bool swap); - /** These are actually ordered lists. The first element is the oldest entry.*/ - typedef std::list<GuildEventLogEntry> GuildEventLog; - typedef std::list<GuildBankEventLogEntry> GuildBankEventLog; - GuildEventLog m_GuildEventLog; - GuildBankEventLog m_GuildBankEventLog_Money; - GuildBankEventLog m_GuildBankEventLog_Item[GUILD_BANK_MAX_TABS]; + private: + Item* _StoreItem(SQLTransaction& trans, BankTab* pTab, Item *pItem, ItemPosCount& pos, bool clone) const; + bool _ReserveSpace(uint8 slotId, Item* pItem, Item* pItemDest, uint32& count); + void _CanStoreItemInTab(Item* pItem, uint8 skipSlotId, bool merge, uint32& count); + }; + + typedef UNORDERED_MAP<uint32, Member*> Members; + typedef std::vector<RankInfo> Ranks; + typedef std::vector<BankTab*> BankTabs; + +public: + static void SendCommandResult(WorldSession* session, GuildCommandType type, GuildCommandError errCode, const std::string& param = ""); + static void SendSaveEmblemResult(WorldSession* session, GuildEmblemError errCode); + + Guild(); + ~Guild(); + + bool Create(Player* pLeader, const std::string& name); + void Disband(); + + // Getters + uint32 GetId() const { return m_id; } + const uint64& GetLeaderGUID() const { return m_leaderGuid; } + const std::string& GetName() const { return m_name; } + const std::string& GetMOTD() const { return m_motd; } + const std::string& GetInfo() const { return m_info; } + + // Handle client commands + void HandleRoster(WorldSession *session = NULL); // NULL = broadcast + void HandleQuery(WorldSession *session); + void HandleSetMOTD(WorldSession* session, const std::string& motd); + void HandleSetInfo(WorldSession* session, const std::string& info); + void HandleSetEmblem(WorldSession* session, const EmblemInfo& emblemInfo); + void HandleSetLeader(WorldSession* session, const std::string& name); + void HandleSetBankTabInfo(WorldSession* session, uint8 tabId, const std::string& name, const std::string& icon); + void HandleSetMemberNote(WorldSession* session, const std::string& name, const std::string& note, bool officer); + void HandleSetRankInfo(WorldSession* session, uint8 rankId, const std::string& name, uint32 rights, uint32 moneyPerDay, GuildBankRightsAndSlotsVec rightsAndSlots); + void HandleBuyBankTab(WorldSession* session, uint8 tabId); + void HandleInviteMember(WorldSession* session, const std::string& name); + void HandleAcceptMember(WorldSession* session); + void HandleLeaveMember(WorldSession* session); + void HandleRemoveMember(WorldSession* session, const std::string& name); + void HandleUpdateMemberRank(WorldSession* session, const std::string& name, bool demote); + void HandleAddNewRank(WorldSession* session, const std::string& name); + void HandleRemoveLowestRank(WorldSession* session); + void HandleMemberDepositMoney(WorldSession* session, uint32 amount); + bool HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool repair = false); + void HandleMemberLogout(WorldSession* session); + void HandleDisband(WorldSession* session); + + // Send info to client + void SendInfo(WorldSession* session) const; + void SendEventLog(WorldSession *session) const; + void SendBankLog(WorldSession *session, uint8 tabId) const; + void SendBankTabsInfo(WorldSession *session) const; + void SendBankTabData(WorldSession* session, uint8 tabId) const; + void SendBankTabText(WorldSession *session, uint8 tabId) const; + void SendPermissions(WorldSession *session) const; + void SendMoneyInfo(WorldSession *session) const; + void SendLoginInfo(WorldSession* session) const; + + // Load from DB + bool LoadFromDB(Field* fields); + bool LoadRankFromDB(Field* fields); + bool LoadMemberFromDB(Field* fields); + bool LoadEventLogFromDB(Field* fields); + bool LoadBankRightFromDB(Field* fields); + bool LoadBankTabFromDB(Field* fields); + bool LoadBankEventLogFromDB(Field* fields); + bool LoadBankItemFromDB(Field* fields); + bool Validate(); + + // Broadcasts + void BroadcastToGuild(WorldSession *session, bool officerOnly, const std::string& msg, uint32 language = LANG_UNIVERSAL) const; + void BroadcastPacketToRank(WorldPacket *packet, uint8 rankId) const; + void BroadcastPacket(WorldPacket *packet) const; + + template<class Do> + void BroadcastWorker(Do& _do, Player* except = NULL) + { + for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + if (Player *player = itr->second->FindPlayer()) + if (player != except) + _do(player); + } - uint32 m_GuildEventLogNextGuid; - uint32 m_GuildBankEventLogNextGuid_Money; - uint32 m_GuildBankEventLogNextGuid_Item[GUILD_BANK_MAX_TABS]; + // Members + // Adds member to guild. If rankId == GUILD_RANK_NONE, lowest rank is assigned. + bool AddMember(const uint64& guid, uint8 rankId = GUILD_RANK_NONE); + void DeleteMember(const uint64& guid, bool isDisbanding = false, bool isKicked = false); + bool ChangeMemberRank(const uint64& guid, uint8 newRank); + + // Bank + void SwapItems(Player* player, uint8 tabId, uint8 slotId, uint8 destTabId, uint8 destSlotId, uint32 splitedAmount); + void SwapItemsWithInventory(Player* player, bool toChar, uint8 tabId, uint8 slotId, uint8 playerBag, uint8 playerSlotId, uint32 splitedAmount); + + // Bank tabs + void SetBankTabText(uint8 tabId, const std::string& text); + +protected: + uint32 m_id; + std::string m_name; + uint64 m_leaderGuid; + std::string m_motd; + std::string m_info; + time_t m_createdDate; + + EmblemInfo m_emblemInfo; + uint32 m_accountsNumber; + uint64 m_bankMoney; + + Ranks m_ranks; + Members m_members; + BankTabs m_bankTabs; + + // These are actually ordered lists. The first element is the oldest entry. + LogHolder* m_eventLog; + LogHolder* m_bankEventLog[GUILD_BANK_MAX_TABS + 1]; + +private: + inline uint8 _GetRanksSize() const { return uint8(m_ranks.size()); } + inline const RankInfo *GetRankInfo(uint8 rankId) const { return rankId < _GetRanksSize() ? &m_ranks[rankId] : NULL; } + inline RankInfo *GetRankInfo(uint8 rankId) { return rankId < _GetRanksSize() ? &m_ranks[rankId] : NULL; } + inline bool _HasRankRight(Player* player, uint32 right) const { return (_GetRankRights(player->GetRank()) & right) != GR_RIGHT_EMPTY; } + inline uint8 _GetLowestRankId() const { return uint8(m_ranks.size() - 1); } + + inline uint8 _GetPurchasedTabsSize() const { return uint8(m_bankTabs.size()); } + inline BankTab* GetBankTab(uint8 tabId) { return tabId < m_bankTabs.size() ? m_bankTabs[tabId] : NULL; } + inline const BankTab* GetBankTab(uint8 tabId) const { return tabId < m_bankTabs.size() ? m_bankTabs[tabId] : NULL; } + + inline const Member* GetMember(const uint64& guid) const + { + Members::const_iterator itr = m_members.find(GUID_LOPART(guid)); + return itr != m_members.end() ? itr->second : NULL; + } + inline Member* GetMember(const uint64& guid) + { + Members::iterator itr = m_members.find(GUID_LOPART(guid)); + return itr != m_members.end() ? itr->second : NULL; + } + inline Member* GetMember(WorldSession* session, const std::string& name) + { + for (Members::iterator itr = m_members.begin(); itr != m_members.end(); ++itr) + if (itr->second->GetName() == name) + return itr->second; - uint64 m_GuildBankMoney; + SendCommandResult(session, GUILD_INVITE_S, ERR_GUILD_PLAYER_NOT_IN_GUILD_S, name); + return NULL; + } + inline void _DeleteMemberFromDB(uint32 lowguid) const + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_MEMBER); + stmt->setUInt32(0, lowguid); + CharacterDatabase.Execute(stmt); + } - private: - void UpdateAccountsNumber(); - // used only from high level Swap/Move functions - Item* GetItem(uint8 TabId, uint8 SlotId); - uint8 CanStoreItem(uint8 tab, uint8 slot, GuildItemPosCountVec& dest, uint32 count, Item *pItem, bool swap = false) const; - Item* StoreItem(uint8 tab, GuildItemPosCountVec const& pos, Item *pItem, SQLTransaction& trans); - void RemoveItem(uint8 tab, uint8 slot, SQLTransaction& trans); - void DisplayGuildBankContentUpdate(uint8 TabId, int32 slot1, int32 slot2 = -1); - void DisplayGuildBankContentUpdate(uint8 TabId, GuildItemPosCountVec const& slots); - - // internal common parts for CanStore/StoreItem functions - void AppendDisplayGuildBankSlot(WorldPacket& data, GuildBankTab const *tab, int32 slot); - uint8 _CanStoreItem_InSpecificSlot(uint8 tab, uint8 slot, GuildItemPosCountVec& dest, uint32& count, bool swap, Item *pSrcItem) const; - uint8 _CanStoreItem_InTab(uint8 tab, GuildItemPosCountVec& dest, uint32& count, bool merge, Item *pSrcItem, uint8 skip_slot) const; - Item* _StoreItem(uint8 tab, uint8 slot, Item *pItem, uint32 count, bool clone, SQLTransaction& trans); + // Creates log holders (either when loading or when creating guild) + void _CreateLogHolders(); + // Tries to create new bank tab + bool _CreateNewBankTab(); + // Creates default guild ranks with names in given locale + void _CreateDefaultGuildRanks(LocaleConstant loc); + // Creates new rank + void _CreateRank(const std::string& name, uint32 rights); + // Update account number when member added/removed from guild + void _UpdateAccountsNumber(); + bool _IsLeader(Player* player) const; + void _DeleteBankItems(SQLTransaction& trans, bool removeItemsFromDB = false); + bool _ModifyBankMoney(SQLTransaction& trans, const uint64& amount, bool add); + void _SetLeaderGUID(Member* pLeader); + + void _SetRankBankMoneyPerDay(uint8 rankId, uint32 moneyPerDay); + void _SetRankBankTabRightsAndSlots(uint8 rankId, uint8 tabId, GuildBankRightsAndSlots rightsAndSlots, bool saveToDB = true); + uint8 _GetRankBankTabRights(uint8 rankId, uint8 tabId) const; + uint32 _GetRankRights(uint8 rankId) const; + uint32 _GetRankBankMoneyPerDay(uint8 rankId) const; + uint32 _GetRankBankTabSlotsPerDay(uint8 rankId, uint8 tabId) const; + std::string _GetRankName(uint8 rankId) const; + + uint32 _GetMemberRemainingSlots(const uint64& guid, uint8 tabId) const; + uint32 _GetMemberRemainingMoney(const uint64& guid) const; + void _DecreaseMemberRemainingSlots(SQLTransaction& trans, const uint64& guid, uint8 tabId); + bool _MemberHasTabRights(const uint64& guid, uint8 tabId, uint32 rights) const; + + void _LogEvent(GuildEventLogTypes eventType, uint32 playerGuid1, uint32 playerGuid2 = 0, uint8 newRank = 0); + void _LogBankEvent(SQLTransaction& trans, GuildBankEventLogTypes eventType, uint8 tabId, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount = 0, uint8 destTabId = 0); + + Item* _GetItem(uint8 tabId, uint8 slotId) const; + void _RemoveItem(SQLTransaction& trans, uint8 tabId, uint8 slotId); + void _MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAmount); + bool _DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError, uint32 splitedAmount = 0); + + void _SendBankContent(WorldSession *session, uint8 tabId) const; + void _SendBankMoneyUpdate(WorldSession *session) const; + void _SendBankContentUpdate(MoveItemData* pSrc, MoveItemData* pDest) const; + void _SendBankContentUpdate(uint8 tabId, SlotIds slots) const; + + void _BroadcastEvent(GuildEvents guildEvent, const uint64& guid, const char* param1 = NULL, const char* param2 = NULL, const char* param3 = NULL) const; }; #endif diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 5f49e7e60a7..2f4601c493d 100755 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -2505,14 +2505,8 @@ enum PetDiet #define CHAIN_SPELL_JUMP_RADIUS 10 -// Max values for Guild & Guild Bank -#define GUILD_BANK_MAX_TABS 6 // send by client for money log also -#define GUILD_BANK_MAX_SLOTS 98 -#define GUILD_BANK_MAX_LOGS 25 -#define GUILD_BANK_MONEY_LOGS_TAB 100 // used for money log in DB +#define GUILD_BANKLOG_MAX_RECORDS 25 #define GUILD_EVENTLOG_MAX_RECORDS 100 -#define GUILD_RANKS_MIN_COUNT 5 -#define GUILD_RANKS_MAX_COUNT 10 enum AiReaction { diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 562e6aa6f7d..9fcf084ca06 100755 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -1076,6 +1076,7 @@ bool ScriptMgr::OnCriteriaCheck(AchievementCriteriaData const* data, Player* sou return tmpscript->OnCheck(source, target); } +// Player void ScriptMgr::OnPVPKill(Player *killer, Player *killed) { FOREACH_SCRIPT(PlayerScript)->OnPVPKill(killer, killed); @@ -1196,7 +1197,8 @@ void ScriptMgr::OnPlayerDelete(uint64 guid) FOREACH_SCRIPT(PlayerScript)->OnDelete(guid); } -void ScriptMgr::OnGuildAddMember(Guild *guild, Player *player, uint32& plRank) +// Guild +void ScriptMgr::OnGuildAddMember(Guild *guild, Player *player, uint8& plRank) { FOREACH_SCRIPT(GuildScript)->OnAddMember(guild, player, plRank); } @@ -1206,14 +1208,19 @@ void ScriptMgr::OnGuildRemoveMember(Guild *guild, Player *player, bool isDisband FOREACH_SCRIPT(GuildScript)->OnRemoveMember(guild, player, isDisbanding, isKicked); } -void ScriptMgr::OnGuildMOTDChanged(Guild *guild, std::string newMotd) +void ScriptMgr::OnGuildMOTDChanged(Guild *guild, const std::string& newMotd) { FOREACH_SCRIPT(GuildScript)->OnMOTDChanged(guild, newMotd); } -void ScriptMgr::OnGuildInfoChanged(Guild *guild, std::string newGInfo) +void ScriptMgr::OnGuildInfoChanged(Guild *guild, const std::string& newInfo) { - FOREACH_SCRIPT(GuildScript)->OnGInfoChanged(guild, newGInfo); + FOREACH_SCRIPT(GuildScript)->OnInfoChanged(guild, newInfo); +} + +void ScriptMgr::OnGuildCreate(Guild *guild, Player* leader, const std::string& name) +{ + FOREACH_SCRIPT(GuildScript)->OnCreate(guild, leader, name); } void ScriptMgr::OnGuildDisband(Guild *guild) @@ -1221,6 +1228,33 @@ void ScriptMgr::OnGuildDisband(Guild *guild) FOREACH_SCRIPT(GuildScript)->OnDisband(guild); } +void ScriptMgr::OnGuildMemberWitdrawMoney(Guild* guild, Player* player, uint32 &amount, bool isRepair) +{ + FOREACH_SCRIPT(GuildScript)->OnMemberWitdrawMoney(guild, player, amount, isRepair); +} + +void ScriptMgr::OnGuildMemberDepositMoney(Guild* guild, Player* player, uint32 &amount) +{ + FOREACH_SCRIPT(GuildScript)->OnMemberDepositMoney(guild, player, amount); +} + +void ScriptMgr::OnGuildItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId, + bool isDestBank, uint8 destContainer, uint8 destSlotId) +{ + FOREACH_SCRIPT(GuildScript)->OnItemMove(guild, player, pItem, isSrcBank, srcContainer, srcSlotId, isDestBank, destContainer, destSlotId); +} + +void ScriptMgr::OnGuildEvent(Guild* guild, uint8 eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank) +{ + FOREACH_SCRIPT(GuildScript)->OnEvent(guild, eventType, playerGuid1, playerGuid2, newRank); +} + +void ScriptMgr::OnGuildBankEvent(Guild* guild, uint8 eventType, uint8 tabId, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId) +{ + FOREACH_SCRIPT(GuildScript)->OnBankEvent(guild, eventType, tabId, playerGuid, itemOrMoney, itemStackCount, destTabId); +} + +// Group void ScriptMgr::OnGroupAddMember(Group* group, uint64 guid) { ASSERT(group); diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index 2847e55a687..eb20e28f0cc 100755 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -725,11 +725,18 @@ class GuildScript : public ScriptObject bool IsDatabaseBound() const { return false; } - virtual void OnAddMember(Guild* /*guild*/, Player* /*player*/, uint32& /*plRank*/) { } + virtual void OnAddMember(Guild* /*guild*/, Player* /*player*/, uint8& /*plRank*/) { } virtual void OnRemoveMember(Guild* /*guild*/, Player* /*player*/, bool /*isDisbanding*/, bool /*isKicked*/) { } - virtual void OnMOTDChanged(Guild* /*guild*/, std::string /*newMotd*/) { } - virtual void OnGInfoChanged(Guild* /*guild*/, std::string /*newGInfo*/) { } + virtual void OnMOTDChanged(Guild* /*guild*/, const std::string& /*newMotd*/) { } + virtual void OnInfoChanged(Guild* /*guild*/, const std::string& /*newInfo*/) { } + virtual void OnCreate(Guild* /*guild*/, Player* /*leader*/, const std::string& /*name*/) { } virtual void OnDisband(Guild* /*guild*/) { } + virtual void OnMemberWitdrawMoney(Guild* /*guild*/, Player* /*player*/, uint32& /*amount*/, bool /*isRepair*/) { } + virtual void OnMemberDepositMoney(Guild* /*guild*/, Player* /*player*/, uint32& /*amount*/) { } + virtual void OnItemMove(Guild* /*guild*/, Player* /*player*/, Item* /*pItem*/, bool /*isSrcBank*/, uint8 /*srcContainer*/, uint8 /*srcSlotId*/, + bool /*isDestBank*/, uint8 /*destContainer*/, uint8 /*destSlotId*/) { } + virtual void OnEvent(Guild* /*guild*/, uint8 /*eventType*/, uint32 /*playerGuid1*/, uint32 /*playerGuid2*/, uint8 /*newRank*/) { } + virtual void OnBankEvent(Guild* /*guild*/, uint8 /*eventType*/, uint8 /*tabId*/, uint32 /*playerGuid*/, uint32 /*itemOrMoney*/, uint16 /*itemStackCount*/, uint8 /*destTabId*/) { } }; class GroupScript : public ScriptObject @@ -943,11 +950,18 @@ class ScriptMgr void OnPlayerDelete(uint64 guid); public: /* GuildScript */ - void OnGuildAddMember(Guild *guild, Player *player, uint32& plRank); + void OnGuildAddMember(Guild *guild, Player *player, uint8& plRank); void OnGuildRemoveMember(Guild *guild, Player *player, bool isDisbanding, bool isKicked); - void OnGuildMOTDChanged(Guild *guild, std::string newMotd); - void OnGuildInfoChanged(Guild *guild, std::string newGInfo); + void OnGuildMOTDChanged(Guild *guild, const std::string& newMotd); + void OnGuildInfoChanged(Guild *guild, const std::string& newInfo); + void OnGuildCreate(Guild *guild, Player* leader, const std::string& name); void OnGuildDisband(Guild *guild); + void OnGuildMemberWitdrawMoney(Guild* guild, Player* player, uint32 &amount, bool isRepair); + void OnGuildMemberDepositMoney(Guild* guild, Player* player, uint32 &amount); + void OnGuildItemMove(Guild* guild, Player* player, Item* pItem, bool isSrcBank, uint8 srcContainer, uint8 srcSlotId, + bool isDestBank, uint8 destContainer, uint8 destSlotId); + void OnGuildEvent(Guild* guild, uint8 eventType, uint32 playerGuid1, uint32 playerGuid2, uint8 newRank); + void OnGuildBankEvent(Guild* guild, uint8 eventType, uint8 tabId, uint32 playerGuid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId); public: /* GroupScript */ void OnGroupAddMember(Group* group, uint64 guid); diff --git a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp index 7593fc96c63..3a3a23cc4ec 100755 --- a/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/CharacterHandler.cpp @@ -751,24 +751,12 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder) if (pCurrChar->GetGuildId() != 0) { - Guild* guild = sObjectMgr.GetGuildById(pCurrChar->GetGuildId()); - if (guild) - { - data.Initialize(SMSG_GUILD_EVENT, (1+1+guild->GetMOTD().size()+1)); - data << uint8(GE_MOTD); - data << uint8(1); - data << guild->GetMOTD(); - SendPacket(&data); - sLog.outStaticDebug("WORLD: Sent guild-motd (SMSG_GUILD_EVENT)"); - - guild->DisplayGuildBankTabsInfo(this); - - guild->BroadcastEvent(GE_SIGNED_ON, pCurrChar->GetGUID(), 1, pCurrChar->GetName(), "", ""); - } + if (Guild* pGuild = sObjectMgr.GetGuildById(pCurrChar->GetGuildId())) + pGuild->SendLoginInfo(this); else { // remove wrong guild data - sLog.outError("Player %s (GUID: %u) marked as member not existed guild (id: %u), removing guild membership for player.",pCurrChar->GetName(),pCurrChar->GetGUIDLow(),pCurrChar->GetGuildId()); + sLog.outError("Player %s (GUID: %u) marked as member of not existing guild (id: %u), removing guild membership for player.",pCurrChar->GetName(),pCurrChar->GetGUIDLow(),pCurrChar->GetGuildId()); pCurrChar->SetInGuild(0); } } diff --git a/src/server/game/Server/Protocol/Handlers/ChatHandler.cpp b/src/server/game/Server/Protocol/Handlers/ChatHandler.cpp index d01814dad7e..5caa120ec0c 100755 --- a/src/server/game/Server/Protocol/Handlers/ChatHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/ChatHandler.cpp @@ -331,7 +331,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket & recv_data) { sScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, guild); - guild->BroadcastToGuild(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); + guild->BroadcastToGuild(this, false, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); } } @@ -360,7 +360,7 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket & recv_data) { sScriptMgr.OnPlayerChat(GetPlayer(), type, lang, msg, guild); - guild->BroadcastToOfficers(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); + guild->BroadcastToGuild(this, true, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL); } } break; diff --git a/src/server/game/Server/Protocol/Handlers/GuildHandler.cpp b/src/server/game/Server/Protocol/Handlers/GuildHandler.cpp index e185cccf805..421275c94be 100755 --- a/src/server/game/Server/Protocol/Handlers/GuildHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/GuildHandler.cpp @@ -27,186 +27,80 @@ #include "GossipDef.h" #include "SocialMgr.h" +// Helper for getting guild object of session's player. +// If guild does not exist, sends error (if necessary). +inline Guild* _GetPlayerGuild(WorldSession* session, bool sendError = false) +{ + if (uint32 guildId = session->GetPlayer()->GetGuildId()) // If guild id = 0, player is not in guild + if (Guild* pGuild = sObjectMgr.GetGuildById(guildId)) // Find guild by id + return pGuild; + if (sendError) + Guild::SendCommandResult(session, GUILD_CREATE_S, ERR_GUILD_PLAYER_NOT_IN_GUILD); + return NULL; +} + void WorldSession::HandleGuildQueryOpcode(WorldPacket& recvPacket) { sLog.outDebug("WORLD: Received CMSG_GUILD_QUERY"); uint32 guildId; recvPacket >> guildId; - - if (Guild *guild = sObjectMgr.GetGuildById(guildId)) - { - guild->Query(this); - return; - } - - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); + // Use received guild id to access guild method (not player's guild id) + if (Guild* pGuild = sObjectMgr.GetGuildById(guildId)) + pGuild->HandleQuery(this); + else + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_PLAYER_NOT_IN_GUILD); } void WorldSession::HandleGuildCreateOpcode(WorldPacket& recvPacket) { sLog.outDebug("WORLD: Received CMSG_GUILD_CREATE"); - std::string gname; - recvPacket >> gname; - - if (GetPlayer()->GetGuildId()) // already in guild - return; + std::string name; + recvPacket >> name; - Guild *guild = new Guild; - if (!guild->Create(GetPlayer(), gname)) + if (!GetPlayer()->GetGuildId()) // Player cannot be in guild { - delete guild; - return; + Guild* pGuild = new Guild(); + if (pGuild->Create(GetPlayer(), name)) + sObjectMgr.AddGuild(pGuild); + else + delete pGuild; } - - sObjectMgr.AddGuild(guild); } void WorldSession::HandleGuildInviteOpcode(WorldPacket& recvPacket) { sLog.outDebug("WORLD: Received CMSG_GUILD_INVITE"); - std::string Invitedname, plname; - - Player * player = NULL; - recvPacket >> Invitedname; - - if (normalizePlayerName(Invitedname)) - player = sObjectAccessor.FindPlayerByName(Invitedname.c_str()); - - if (!player) - { - SendGuildCommandResult(GUILD_INVITE_S, Invitedname, ERR_GUILD_PLAYER_NOT_FOUND_S); - return; - } - - Guild *guild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - // OK result but not send invite - if (player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow())) - return; + std::string invitedName; + recvPacket >> invitedName; - // not let enemies sign guild charter - if (!sWorld.getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && player->GetTeam() != GetPlayer()->GetTeam()) - { - SendGuildCommandResult(GUILD_INVITE_S, Invitedname, ERR_GUILD_NOT_ALLIED); - return; - } - - if (player->GetGuildId()) - { - plname = player->GetName(); - SendGuildCommandResult(GUILD_INVITE_S, plname, ERR_ALREADY_IN_GUILD_S); - return; - } - - if (player->GetGuildIdInvited()) - { - plname = player->GetName(); - SendGuildCommandResult(GUILD_INVITE_S, plname, ERR_ALREADY_INVITED_TO_GUILD_S); - return; - } - - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_INVITE)) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - sLog.outDebug("Player %s Invited %s to Join his Guild", GetPlayer()->GetName(), Invitedname.c_str()); - - player->SetGuildIdInvited(GetPlayer()->GetGuildId()); - // Put record into guildlog - guild->LogGuildEvent(GUILD_EVENT_LOG_INVITE_PLAYER, GetPlayer()->GetGUIDLow(), player->GetGUIDLow(), 0); - - WorldPacket data(SMSG_GUILD_INVITE, (8+10)); // guess size - data << GetPlayer()->GetName(); - data << guild->GetName(); - player->GetSession()->SendPacket(&data); - - sLog.outDebug("WORLD: Sent (SMSG_GUILD_INVITE)"); + if (normalizePlayerName(invitedName)) + if (Guild* pGuild = _GetPlayerGuild(this, true)) + pGuild->HandleInviteMember(this, invitedName); } void WorldSession::HandleGuildRemoveOpcode(WorldPacket& recvPacket) { sLog.outDebug("WORLD: Received CMSG_GUILD_REMOVE"); - std::string plName; - recvPacket >> plName; - - if (!normalizePlayerName(plName)) - return; - - Guild* guild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_REMOVE)) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - uint64 plGuid; - MemberSlot* slot = guild->GetMemberSlot(plName, plGuid); - if (!slot) - { - SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); - return; - } - - if (slot->RankId == GR_GUILDMASTER) - { - SendGuildCommandResult(GUILD_QUIT_S, "", ERR_GUILD_LEADER_LEAVE); - return; - } - - //do not allow to kick player with same or higher rights - if (GetPlayer()->GetRank() >= slot->RankId) - { - SendGuildCommandResult(GUILD_QUIT_S, plName, ERR_GUILD_RANK_TOO_HIGH_S); - return; - } - - guild->DelMember(plGuid, false, true); - // Put record into guildlog - guild->LogGuildEvent(GUILD_EVENT_LOG_UNINVITE_PLAYER, GetPlayer()->GetGUIDLow(), GUID_LOPART(plGuid), 0); + std::string playerName; + recvPacket >> playerName; - guild->BroadcastEvent(GE_REMOVED, 0, 2, plName, _player->GetName(), ""); + if (normalizePlayerName(playerName)) + if (Guild* pGuild = _GetPlayerGuild(this, true)) + pGuild->HandleRemoveMember(this, playerName); } void WorldSession::HandleGuildAcceptOpcode(WorldPacket& /*recvPacket*/) { - Guild *guild; - Player *player = GetPlayer(); - sLog.outDebug("WORLD: Received CMSG_GUILD_ACCEPT"); - - guild = sObjectMgr.GetGuildById(player->GetGuildIdInvited()); - if (!guild || player->GetGuildId()) - return; - - // not let enemies sign guild charter - if (!sWorld.getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && player->GetTeam() != sObjectMgr.GetPlayerTeamByGUID(guild->GetLeader())) - return; - - if (!guild->AddMember(GetPlayer()->GetGUID(),guild->GetLowestRank())) - return; - // Put record into guildlog - guild->LogGuildEvent(GUILD_EVENT_LOG_JOIN_GUILD, GetPlayer()->GetGUIDLow(), 0, 0); - - guild->BroadcastEvent(GE_JOINED, player->GetGUID(), 1, player->GetName(), "", ""); - - sLog.outDebug("WORLD: Sent (SMSG_GUILD_EVENT)"); + // Player cannot be in guild + if (!GetPlayer()->GetGuildId()) + // Guild where player was invited must exist + if (Guild* pGuild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildIdInvited())) + pGuild->HandleAcceptMember(this); } void WorldSession::HandleGuildDeclineOpcode(WorldPacket& /*recvPacket*/) @@ -219,204 +113,58 @@ void WorldSession::HandleGuildDeclineOpcode(WorldPacket& /*recvPacket*/) void WorldSession::HandleGuildInfoOpcode(WorldPacket& /*recvPacket*/) { - Guild *guild; sLog.outDebug("WORLD: Received CMSG_GUILD_INFO"); - guild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - WorldPacket data(SMSG_GUILD_INFO, (guild->GetName().size() + 4 + 4 + 4)); - data << guild->GetName(); - data << secsToTimeBitFields(guild->GetCreatedDate()); // 3.x (prev. year + month + day) - data << guild->GetMemberSize(); // char amount - data << guild->GetAccountsNumber(); // amount of accounts - - SendPacket(&data); + if (Guild* pGuild = _GetPlayerGuild(this, true)) + pGuild->SendInfo(this); } void WorldSession::HandleGuildRosterOpcode(WorldPacket& /*recvPacket*/) { sLog.outDebug("WORLD: Received CMSG_GUILD_ROSTER"); - if (Guild* guild = sObjectMgr.GetGuildById(_player->GetGuildId())) - guild->Roster(this); + if (Guild* pGuild = _GetPlayerGuild(this)) + pGuild->HandleRoster(this); } void WorldSession::HandleGuildPromoteOpcode(WorldPacket& recvPacket) { sLog.outDebug("WORLD: Received CMSG_GUILD_PROMOTE"); - std::string plName; - recvPacket >> plName; - - if (!normalizePlayerName(plName)) - return; - - Guild* guild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_PROMOTE)) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } + std::string playerName; + recvPacket >> playerName; - uint64 plGuid; - MemberSlot* slot = guild->GetMemberSlot(plName, plGuid); - - if (!slot) - { - SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); - return; - } - - if (plGuid == GetPlayer()->GetGUID()) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_NAME_INVALID); - return; - } - - //allow to promote only to lower rank than member's rank - //guildmaster's rank = 0 - //GetPlayer()->GetRank() + 1 is highest rank that current player can promote to - if (GetPlayer()->GetRank() + 1 >= slot->RankId) - { - SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_RANK_TOO_HIGH_S); - return; - } - - uint32 newRankId = slot->RankId - 1; //when promoting player, rank is decreased - - guild->BroadcastEvent(GE_PROMOTION, 0, 3, _player->GetName(), plName, guild->GetRankName(newRankId)); - - guild->ChangeRank(plGuid, newRankId); - // Put record into guildlog - guild->LogGuildEvent(GUILD_EVENT_LOG_PROMOTE_PLAYER, GetPlayer()->GetGUIDLow(), GUID_LOPART(plGuid), newRankId); + if (normalizePlayerName(playerName)) + if (Guild* pGuild = _GetPlayerGuild(this, true)) + pGuild->HandleUpdateMemberRank(this, playerName, false); } void WorldSession::HandleGuildDemoteOpcode(WorldPacket& recvPacket) { sLog.outDebug("WORLD: Received CMSG_GUILD_DEMOTE"); - std::string plName; - recvPacket >> plName; - - if (!normalizePlayerName(plName)) - return; - - Guild* guild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildId()); - - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_DEMOTE)) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - uint64 plGuid; - MemberSlot* slot = guild->GetMemberSlot(plName, plGuid); - - if (!slot) - { - SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); - return; - } - - if (plGuid == GetPlayer()->GetGUID()) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_NAME_INVALID); - return; - } - - //do not allow to demote same or higher rank - if (GetPlayer()->GetRank() >= slot->RankId) - { - SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_RANK_TOO_HIGH_S); - return; - } - - //do not allow to demote lowest rank - if (slot->RankId >= guild->GetLowestRank()) - { - SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_RANK_TOO_LOW_S); - return; - } - - uint32 newRankId = slot->RankId + 1; //when demoting player, rank is increased + std::string playerName; + recvPacket >> playerName; - guild->ChangeRank(plGuid, newRankId); - // Put record into guildlog - guild->LogGuildEvent(GUILD_EVENT_LOG_DEMOTE_PLAYER, GetPlayer()->GetGUIDLow(), GUID_LOPART(plGuid), newRankId); - - guild->BroadcastEvent(GE_DEMOTION, 0, 3, _player->GetName(), plName, guild->GetRankName(slot->RankId)); + if (normalizePlayerName(playerName)) + if (Guild* pGuild = _GetPlayerGuild(this, true)) + pGuild->HandleUpdateMemberRank(this, playerName, true); } void WorldSession::HandleGuildLeaveOpcode(WorldPacket& /*recvPacket*/) { sLog.outDebug("WORLD: Received CMSG_GUILD_LEAVE"); - Guild *guild = sObjectMgr.GetGuildById(_player->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (_player->GetGUID() == guild->GetLeader() && guild->GetMemberSize() > 1) - { - SendGuildCommandResult(GUILD_QUIT_S, "", ERR_GUILD_LEADER_LEAVE); - return; - } - - if (_player->GetGUID() == guild->GetLeader()) - { - guild->Disband(); - return; - } - - guild->DelMember(_player->GetGUID(), false, false); - - // Put record into guildlog - guild->LogGuildEvent(GUILD_EVENT_LOG_LEAVE_GUILD, _player->GetGUIDLow(), 0, 0); - - guild->BroadcastEvent(GE_LEFT, _player->GetGUID(), 1, _player->GetName(), "", ""); - - SendGuildCommandResult(GUILD_QUIT_S, guild->GetName(), ERR_PLAYER_NO_MORE_IN_GUILD); + if (Guild* pGuild = _GetPlayerGuild(this, true)) + pGuild->HandleLeaveMember(this); } void WorldSession::HandleGuildDisbandOpcode(WorldPacket& /*recvPacket*/) { sLog.outDebug("WORLD: Received CMSG_GUILD_DISBAND"); - Guild *guild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (GetPlayer()->GetGUID() != guild->GetLeader()) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - guild->Disband(); - - sLog.outDebug("WORLD: Guild Successfully Disbanded"); + if (Guild* pGuild = _GetPlayerGuild(this, true)) + pGuild->HandleDisband(this); } void WorldSession::HandleGuildLeaderOpcode(WorldPacket& recvPacket) @@ -426,280 +174,119 @@ void WorldSession::HandleGuildLeaderOpcode(WorldPacket& recvPacket) std::string name; recvPacket >> name; - Player *oldLeader = GetPlayer(); - - if (!normalizePlayerName(name)) - return; - - Guild *guild = sObjectMgr.GetGuildById(oldLeader->GetGuildId()); - - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (oldLeader->GetGUID() != guild->GetLeader()) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - uint64 newLeaderGUID; - MemberSlot* slot = guild->GetMemberSlot(name, newLeaderGUID); - - if (!slot) - { - SendGuildCommandResult(GUILD_INVITE_S, name, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); - return; - } - - guild->SetLeader(newLeaderGUID); - guild->ChangeRank(oldLeader->GetGUID(), GR_OFFICER); - - guild->BroadcastEvent(GE_LEADER_CHANGED, 0, 2, oldLeader->GetName(), name, ""); + if (normalizePlayerName(name)) + if (Guild* pGuild = _GetPlayerGuild(this, true)) + pGuild->HandleSetLeader(this, name); } void WorldSession::HandleGuildMOTDOpcode(WorldPacket& recvPacket) { sLog.outDebug("WORLD: Received CMSG_GUILD_MOTD"); - std::string MOTD; - + std::string motd; // Empty by default if (!recvPacket.empty()) - recvPacket >> MOTD; - else - MOTD = ""; - - Guild *guild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } + recvPacket >> motd; - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_SETMOTD)) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - guild->SetMOTD(MOTD); - - guild->BroadcastEvent(GE_MOTD, 0, 1, MOTD, "", ""); + if (Guild* pGuild = _GetPlayerGuild(this, true)) + pGuild->HandleSetMOTD(this, motd); } void WorldSession::HandleGuildSetPublicNoteOpcode(WorldPacket& recvPacket) { sLog.outDebug("WORLD: Received CMSG_GUILD_SET_PUBLIC_NOTE"); - std::string name,PNOTE; - recvPacket >> name; + std::string playerName; + recvPacket >> playerName; - if (!normalizePlayerName(name)) - return; - - Guild* guild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_EPNOTE)) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - uint64 plGuid; - MemberSlot* slot = guild->GetMemberSlot(name, plGuid); - - if (!slot) - { - SendGuildCommandResult(GUILD_INVITE_S, name, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); - return; - } + std::string publicNote; + recvPacket >> publicNote; - recvPacket >> PNOTE; - guild->SetPNOTE(plGuid, PNOTE); - - guild->Roster(this); + if (normalizePlayerName(playerName)) + if (Guild* pGuild = _GetPlayerGuild(this, true)) + pGuild->HandleSetMemberNote(this, playerName, publicNote, false); } void WorldSession::HandleGuildSetOfficerNoteOpcode(WorldPacket& recvPacket) { sLog.outDebug("WORLD: Received CMSG_GUILD_SET_OFFICER_NOTE"); - std::string plName, OFFNOTE; - recvPacket >> plName; + std::string playerName; + recvPacket >> playerName; - if (!normalizePlayerName(plName)) - return; + std::string officerNote; + recvPacket >> officerNote; - Guild* guild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_EOFFNOTE)) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - uint64 plGuid; - MemberSlot* slot = guild->GetMemberSlot(plName, plGuid); - - if (!slot) - { - SendGuildCommandResult(GUILD_INVITE_S, plName, ERR_GUILD_PLAYER_NOT_IN_GUILD_S); - return; - } - - recvPacket >> OFFNOTE; - guild->SetOFFNOTE(plGuid, OFFNOTE); - - guild->Roster(this); + if (normalizePlayerName(playerName)) + if (Guild* pGuild = _GetPlayerGuild(this, true)) + pGuild->HandleSetMemberNote(this, playerName, officerNote, true); } void WorldSession::HandleGuildRankOpcode(WorldPacket& recvPacket) { - std::string rankname; - uint32 rankId; - uint32 rights, MoneyPerDay; - sLog.outDebug("WORLD: Received CMSG_GUILD_RANK"); - Guild *guild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - recvPacket.rpos(recvPacket.wpos()); // set to end to avoid warnings spam - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - else if (GetPlayer()->GetGUID() != guild->GetLeader()) + Guild* pGuild = _GetPlayerGuild(this, true); + if (!pGuild) { - recvPacket.rpos(recvPacket.wpos()); // set to end to avoid warnings spam - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); + recvPacket.rpos(recvPacket.wpos()); return; } + uint32 rankId; recvPacket >> rankId; - recvPacket >> rights; - recvPacket >> rankname; - recvPacket >> MoneyPerDay; - for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) - { - uint32 BankRights; - uint32 BankSlotPerDay; + uint32 rights; + recvPacket >> rights; - recvPacket >> BankRights; - recvPacket >> BankSlotPerDay; - guild->SetBankRightsAndSlots(rankId, uint8(i), uint16(BankRights & 0xFF), uint16(BankSlotPerDay), true); - } + std::string rankName; + recvPacket >> rankName; - sLog.outDebug("WORLD: Changed RankName to %s , Rights to 0x%.4X", rankname.c_str(), rights); + uint32 money; + recvPacket >> money; - guild->SetBankMoneyPerDay(rankId, MoneyPerDay); - guild->SetRankName(rankId, rankname); + GuildBankRightsAndSlotsVec rightsAndSlots(GUILD_BANK_MAX_TABS); + for (uint8 tabId = 0; tabId < GUILD_BANK_MAX_TABS; ++tabId) + { + uint32 bankRights; + uint32 slots; - if (rankId == GR_GUILDMASTER) // prevent loss leader rights - rights = GR_RIGHT_ALL; + recvPacket >> bankRights; + recvPacket >> slots; - guild->SetRankRights(rankId, rights); + rightsAndSlots[tabId] = GuildBankRightsAndSlots(uint8(bankRights), slots); + } - guild->Query(this); - guild->Roster(); // broadcast for tab rights update + pGuild->HandleSetRankInfo(this, rankId, rankName, rights, money, rightsAndSlots); } void WorldSession::HandleGuildAddRankOpcode(WorldPacket& recvPacket) { sLog.outDebug("WORLD: Received CMSG_GUILD_ADD_RANK"); - std::string rankname; - recvPacket >> rankname; - - Guild *guild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (GetPlayer()->GetGUID() != guild->GetLeader()) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - if (guild->GetRanksSize() >= GUILD_RANKS_MAX_COUNT) // client not let create more 10 than ranks - return; - - guild->CreateRank(rankname, GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK); + std::string rankName; + recvPacket >> rankName; - guild->Query(this); - guild->Roster(); // broadcast for tab rights update + if (Guild* pGuild = _GetPlayerGuild(this, true)) + pGuild->HandleAddNewRank(this, rankName); } void WorldSession::HandleGuildDelRankOpcode(WorldPacket& /*recvPacket*/) { sLog.outDebug("WORLD: Received CMSG_GUILD_DEL_RANK"); - Guild *guild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - else if (GetPlayer()->GetGUID() != guild->GetLeader()) - { - SendGuildCommandResult(GUILD_INVITE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - guild->DelRank(); - - guild->Query(this); - guild->Roster(); // broadcast for tab rights update -} - -void WorldSession::SendGuildCommandResult(uint32 typecmd, const std::string& str,uint32 cmdresult) -{ - WorldPacket data(SMSG_GUILD_COMMAND_RESULT, (8+str.size()+1)); - data << typecmd; - data << str; - data << cmdresult; - SendPacket(&data); - - sLog.outDebug("WORLD: Sent (SMSG_GUILD_COMMAND_RESULT)"); + if (Guild* pGuild = _GetPlayerGuild(this, true)) + pGuild->HandleRemoveLowestRank(this); } void WorldSession::HandleGuildChangeInfoTextOpcode(WorldPacket& recvPacket) { sLog.outDebug("WORLD: Received CMSG_GUILD_INFO_TEXT"); - std::string GINFO; - - recvPacket >> GINFO; + std::string info; + recvPacket >> info; - Guild *guild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); - return; - } - - if (!guild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_MODIFY_GUILD_INFO)) - { - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_PERMISSIONS); - return; - } - - guild->SetGINFO(GINFO); + if (Guild* pGuild = _GetPlayerGuild(this, true)) + pGuild->HandleSetInfo(this, info); } void WorldSession::HandleSaveGuildEmblemOpcode(WorldPacket& recvPacket) @@ -707,154 +294,92 @@ void WorldSession::HandleSaveGuildEmblemOpcode(WorldPacket& recvPacket) sLog.outDebug("WORLD: Received MSG_SAVE_GUILD_EMBLEM"); uint64 vendorGuid; - - uint32 EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor; - recvPacket >> vendorGuid; - recvPacket >> EmblemStyle >> EmblemColor >> BorderStyle >> BorderColor >> BackgroundColor; - - Creature *pCreature = GetPlayer()->GetNPCIfCanInteractWith(vendorGuid,UNIT_NPC_FLAG_TABARDDESIGNER); - if (!pCreature) - { - //"That's not an emblem vendor!" - SendSaveGuildEmblem(ERR_GUILDEMBLEM_INVALIDVENDOR); - sLog.outDebug("WORLD: HandleSaveGuildEmblemOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(vendorGuid)); - return; - } - // remove fake death - if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) - GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); + EmblemInfo emblemInfo; + emblemInfo.ReadPacket(recvPacket); - Guild *guild = sObjectMgr.GetGuildById(GetPlayer()->GetGuildId()); - if (!guild) + if (GetPlayer()->GetNPCIfCanInteractWith(vendorGuid, UNIT_NPC_FLAG_TABARDDESIGNER)) { - //"You are not part of a guild!"; - SendSaveGuildEmblem(ERR_GUILDEMBLEM_NOGUILD); - return; - } + // Remove fake death + if (GetPlayer()->hasUnitState(UNIT_STAT_DIED)) + GetPlayer()->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH); - if (guild->GetLeader() != GetPlayer()->GetGUID()) - { - //"Only guild leaders can create emblems." - SendSaveGuildEmblem(ERR_GUILDEMBLEM_NOTGUILDMASTER); - return; + if (Guild* pGuild = _GetPlayerGuild(this)) + pGuild->HandleSetEmblem(this, emblemInfo); + else + // "You are not part of a pGuild!"; + Guild::SendSaveEmblemResult(this, ERR_GUILDEMBLEM_NOGUILD); } - - if (!GetPlayer()->HasEnoughMoney(10 * GOLD)) + else { - //"You can't afford to do that." - SendSaveGuildEmblem(ERR_GUILDEMBLEM_NOTENOUGHMONEY); - return; + // "That's not an emblem vendor!" + Guild::SendSaveEmblemResult(this, ERR_GUILDEMBLEM_INVALIDVENDOR); + sLog.outDebug("WORLD: HandleSaveGuildEmblemOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(vendorGuid)); } - - GetPlayer()->ModifyMoney(-10*GOLD); - guild->SetEmblem(EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor); - - //"Guild Emblem saved." - SendSaveGuildEmblem(ERR_GUILDEMBLEM_SUCCESS); - - guild->Query(this); } void WorldSession::HandleGuildEventLogQueryOpcode(WorldPacket& /* recvPacket */) { - // empty sLog.outDebug("WORLD: Received (MSG_GUILD_EVENT_LOG_QUERY)"); - if (uint32 GuildId = GetPlayer()->GetGuildId()) - if (Guild *pGuild = sObjectMgr.GetGuildById(GuildId)) - pGuild->DisplayGuildEventLog(this); -} -/****** GUILD BANK *******/ + if (Guild* pGuild = _GetPlayerGuild(this)) + pGuild->SendEventLog(this); +} void WorldSession::HandleGuildBankMoneyWithdrawn(WorldPacket & /* recv_data */) { sLog.outDebug("WORLD: Received (MSG_GUILD_BANK_MONEY_WITHDRAWN)"); - if (uint32 GuildId = GetPlayer()->GetGuildId()) - if (Guild *pGuild = sObjectMgr.GetGuildById(GuildId)) - pGuild->SendMoneyInfo(this, GetPlayer()->GetGUIDLow()); + + if (Guild* pGuild = _GetPlayerGuild(this)) + pGuild->SendMoneyInfo(this); } void WorldSession::HandleGuildPermissions(WorldPacket& /* recv_data */) { sLog.outDebug("WORLD: Received (MSG_GUILD_PERMISSIONS)"); - if (uint32 GuildId = GetPlayer()->GetGuildId()) - { - if (Guild *pGuild = sObjectMgr.GetGuildById(GuildId)) - { - uint32 rankId = GetPlayer()->GetRank(); - - WorldPacket data(MSG_GUILD_PERMISSIONS, 4*15+1); - data << uint32(rankId); // guild rank id - data << uint32(pGuild->GetRankRights(rankId)); // rank rights - // money per day left - data << uint32(pGuild->GetMemberMoneyWithdrawRem(GetPlayer()->GetGUIDLow())); - data << uint8(pGuild->GetPurchasedTabs()); // tabs count - // why sending all info when not all tabs are purchased??? - for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i) - { - data << uint32(pGuild->GetBankRights(rankId, uint8(i))); - data << uint32(pGuild->GetMemberSlotWithdrawRem(GetPlayer()->GetGUIDLow(), uint8(i))); - } - SendPacket(&data); - sLog.outDebug("WORLD: Sent (MSG_GUILD_PERMISSIONS)"); - } - } + if (Guild* pGuild = _GetPlayerGuild(this)) + pGuild->SendPermissions(this); } -/* Called when clicking on Guild bank gameobject */ +// Called when clicking on Guild bank gameobject void WorldSession::HandleGuildBankerActivate(WorldPacket & recv_data) { sLog.outDebug("WORLD: Received (CMSG_GUILD_BANKER_ACTIVATE)"); uint64 GoGuid; - uint8 unk; - recv_data >> GoGuid >> unk; + recv_data >> GoGuid; - if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - return; + uint8 unk; + recv_data >> unk; - if (uint32 GuildId = GetPlayer()->GetGuildId()) + if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) { - if (Guild *pGuild = sObjectMgr.GetGuildById(GuildId)) - { - pGuild->DisplayGuildBankTabsInfo(this); // this also will load guild bank if not yet - return; - } + if (Guild* pGuild = _GetPlayerGuild(this)) + pGuild->SendBankTabsInfo(this); + else + Guild::SendCommandResult(this, GUILD_UNK1, ERR_GUILD_PLAYER_NOT_IN_GUILD); } - - SendGuildCommandResult(GUILD_UNK1, "", ERR_GUILD_PLAYER_NOT_IN_GUILD); } -/* Called when opening guild bank tab only (first one) */ +// Called when opening pGuild bank tab only (first one) void WorldSession::HandleGuildBankQueryTab(WorldPacket & recv_data) { sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_QUERY_TAB)"); uint64 GoGuid; - uint8 TabId, unk1; - recv_data >> GoGuid >> TabId >> unk1; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - return; + recv_data >> GoGuid; - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) - return; + uint8 tabId; + recv_data >> tabId; - Guild *pGuild = sObjectMgr.GetGuildById(GuildId); - if (!pGuild) - return; - - if (TabId >= pGuild->GetPurchasedTabs()) - return; + uint8 unk1; + recv_data >> unk1; - // Let's update the amount of gold the player can withdraw before displaying the content - // This is useful if money withdraw right has changed - pGuild->SendMoneyInfo(this, GetPlayer()->GetGUIDLow()); - pGuild->DisplayGuildBankContent(this, TabId); + if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + if (Guild* pGuild = _GetPlayerGuild(this)) + pGuild->SendBankTabData(this, tabId); } void WorldSession::HandleGuildBankDepositMoney(WorldPacket & recv_data) @@ -862,50 +387,15 @@ void WorldSession::HandleGuildBankDepositMoney(WorldPacket & recv_data) sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_DEPOSIT_MONEY)"); uint64 GoGuid; - uint32 money; - recv_data >> GoGuid >> money; - - if (!money) - return; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - return; - - if (!GetPlayer()->HasEnoughMoney(money)) - return; - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) - return; - - Guild *pGuild = sObjectMgr.GetGuildById(GuildId); - if (!pGuild) - return; - - if (!pGuild->GetPurchasedTabs()) - return; - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - - pGuild->SetBankMoney(pGuild->GetGuildBankMoney()+money, trans); - GetPlayer()->ModifyMoney(-int(money)); - GetPlayer()->SaveGoldToDB(trans); - - // logging money - if (_player->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getBoolConfig(CONFIG_GM_LOG_TRADE)) - { - sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit money (Amount: %u) to guild bank (Guild ID %u)", - _player->GetName(),_player->GetSession()->GetAccountId(),money,GuildId); - } - - // log - pGuild->LogBankEvent(trans, GUILD_BANK_LOG_DEPOSIT_MONEY, uint8(0), GetPlayer()->GetGUIDLow(), money); + recv_data >> GoGuid; - CharacterDatabase.CommitTransaction(trans); + uint32 money; + recv_data >> money; - pGuild->DisplayGuildBankTabsInfo(this); - pGuild->DisplayGuildBankContent(this, 0); - pGuild->DisplayGuildBankMoneyUpdate(this); + if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + if (money && GetPlayer()->HasEnoughMoney(money)) + if (Guild* pGuild = _GetPlayerGuild(this)) + pGuild->HandleMemberDepositMoney(this, money); } void WorldSession::HandleGuildBankWithdrawMoney(WorldPacket & recv_data) @@ -913,49 +403,15 @@ void WorldSession::HandleGuildBankWithdrawMoney(WorldPacket & recv_data) sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_WITHDRAW_MONEY)"); uint64 GoGuid; - uint32 money; - recv_data >> GoGuid >> money; - - if (!money) - return; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - return; - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (GuildId == 0) - return; - - Guild *pGuild = sObjectMgr.GetGuildById(GuildId); - if (!pGuild) - return; - - if (!pGuild->GetPurchasedTabs()) - return; - - if (pGuild->GetGuildBankMoney()<money) // not enough money in bank - return; - - if (!pGuild->HasRankRight(GetPlayer()->GetRank(), GR_RIGHT_WITHDRAW_GOLD)) - return; - - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - - if (!pGuild->MemberMoneyWithdraw(money, GetPlayer()->GetGUIDLow(), trans)) - return; - - GetPlayer()->ModifyMoney(money); - GetPlayer()->SaveGoldToDB(trans); - - // Log - pGuild->LogBankEvent(trans, GUILD_BANK_LOG_WITHDRAW_MONEY, uint8(0), GetPlayer()->GetGUIDLow(), money); + recv_data >> GoGuid; - CharacterDatabase.CommitTransaction(trans); + uint32 money; + recv_data >> money; - pGuild->SendMoneyInfo(this, GetPlayer()->GetGUIDLow()); - pGuild->DisplayGuildBankTabsInfo(this); - pGuild->DisplayGuildBankContent(this,0); - pGuild->DisplayGuildBankMoneyUpdate(this); + if (money) + if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + if (Guild* pGuild = _GetPlayerGuild(this)) + pGuild->HandleMemberWithdrawMoney(this, money); } void WorldSession::HandleGuildBankSwapItems(WorldPacket & recv_data) @@ -963,108 +419,81 @@ void WorldSession::HandleGuildBankSwapItems(WorldPacket & recv_data) sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_SWAP_ITEMS)"); uint64 GoGuid; - uint8 BankToBank; - - uint8 BankTab, BankTabSlot, AutoStore; - uint8 PlayerSlot = NULL_SLOT; - uint8 PlayerBag = NULL_BAG; - uint8 BankTabDst = 0, BankTabSlotDst = 0, unk2; - uint8 ToChar = 1; - uint32 ItemEntry, unk1; - uint32 AutoStoreCount = 0; - uint32 SplitedAmount = 0; - - recv_data >> GoGuid >> BankToBank; + recv_data >> GoGuid; - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) + if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) { - recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet + recv_data.rpos(recv_data.wpos()); // Prevent additional spam at rejected packet return; } - Guild *pGuild = sObjectMgr.GetGuildById(GuildId); + Guild* pGuild = _GetPlayerGuild(this); if (!pGuild) { - recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet + recv_data.rpos(recv_data.wpos()); // Prevent additional spam at rejected packet return; } - if (BankToBank) + uint8 bankToBank; + recv_data >> bankToBank; + + uint8 tabId; + uint8 slotId; + uint32 itemEntry; + uint32 splitedAmount = 0; + + if (bankToBank) { - recv_data >> BankTabDst; - recv_data >> BankTabSlotDst; - recv_data >> unk1; // always 0 - recv_data >> BankTab; - recv_data >> BankTabSlot; - recv_data >> ItemEntry; - recv_data >> unk2; // always 0 - recv_data >> SplitedAmount; - - if (BankTabSlotDst >= GUILD_BANK_MAX_SLOTS || - (BankTabDst == BankTab && BankTabSlotDst == BankTabSlot) || - BankTab >= pGuild->GetPurchasedTabs() || - BankTabDst >= pGuild->GetPurchasedTabs()) - { - recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet - return; - } + uint8 destTabId; + recv_data >> destTabId; + + uint8 destSlotId; + recv_data >> destSlotId; + recv_data.read_skip<uint32>(); // Always 0 + + recv_data >> tabId; + recv_data >> slotId; + recv_data >> itemEntry; + recv_data.read_skip<uint8>(); // Always 0 + + recv_data >> splitedAmount; + + pGuild->SwapItems(GetPlayer(), tabId, slotId, destTabId, destSlotId, splitedAmount); } else { - recv_data >> BankTab; - recv_data >> BankTabSlot; - recv_data >> ItemEntry; - recv_data >> AutoStore; - if (AutoStore) + uint8 playerBag = NULL_BAG; + uint8 playerSlotId = NULL_SLOT; + uint8 toChar = 1; + uint32 autoStoreCount = 0; + + recv_data >> tabId; + recv_data >> slotId; + recv_data >> itemEntry; + + uint8 autoStore; + recv_data >> autoStore; + if (autoStore) { - recv_data >> AutoStoreCount; - recv_data.read_skip<uint8>(); // ToChar (?), always and expected to be 1 (autostore only triggered in guild->ToChar) - recv_data.read_skip<uint32>(); // unknown, always 0 + recv_data >> autoStoreCount; + recv_data.read_skip<uint8>(); // ToChar (?), always and expected to be 1 (autostore only triggered in Bank -> Char) + recv_data.read_skip<uint32>(); // Always 0 } else { - recv_data >> PlayerBag; - recv_data >> PlayerSlot; - recv_data >> ToChar; - recv_data >> SplitedAmount; + recv_data >> playerBag; + recv_data >> playerSlotId; + recv_data >> toChar; + recv_data >> splitedAmount; } - if ((BankTabSlot >= GUILD_BANK_MAX_SLOTS && BankTabSlot != 0xFF) || - BankTab >= pGuild->GetPurchasedTabs()) - { - recv_data.rpos(recv_data.wpos()); // prevent additional spam at rejected packet - return; - } - } - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - return; - - if (BankTab >= pGuild->GetPurchasedTabs()) - return; - - // Bank <-> Bank - if (BankToBank) - { - pGuild->SwapItems(_player, BankTab, BankTabSlot, BankTabDst, BankTabSlotDst, SplitedAmount); - return; - } - - // Player <-> Bank - - // allow work with inventory only - if (!Player::IsInventoryPos(PlayerBag, PlayerSlot) && !(PlayerBag == NULL_BAG && PlayerSlot == NULL_SLOT)) - { - _player->SendEquipError(EQUIP_ERR_NONE, NULL, NULL); - return; + // Player <-> Bank + // Allow to work with inventory only + if (!Player::IsInventoryPos(playerBag, playerSlotId) && !(playerBag == NULL_BAG && playerSlotId == NULL_SLOT)) + GetPlayer()->SendEquipError(EQUIP_ERR_NONE, NULL); + else + pGuild->SwapItemsWithInventory(GetPlayer(), toChar, tabId, slotId, playerBag, playerSlotId, splitedAmount); } - - // BankToChar swap or char to bank remaining - if (ToChar) // Bank -> Char cases - pGuild->MoveFromBankToChar(_player, BankTab, BankTabSlot, PlayerBag, PlayerSlot, SplitedAmount); - else // Char -> Bank cases - pGuild->MoveFromCharToBank(_player, PlayerBag, PlayerSlot, BankTab, BankTabSlot, SplitedAmount); } void WorldSession::HandleGuildBankBuyTab(WorldPacket & recv_data) @@ -1072,40 +501,14 @@ void WorldSession::HandleGuildBankBuyTab(WorldPacket & recv_data) sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_BUY_TAB)"); uint64 GoGuid; - uint8 TabId; - recv_data >> GoGuid; - recv_data >> TabId; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - return; - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) - return; - Guild *pGuild = sObjectMgr.GetGuildById(GuildId); - if (!pGuild) - return; - - // m_PurchasedTabs = 0 when buying Tab 0, that is why this check can be made - if (TabId != pGuild->GetPurchasedTabs()) - return; + uint8 tabId; + recv_data >> tabId; - uint32 TabCost = GetGuildBankTabPrice(TabId) * GOLD; - if (!TabCost) - return; - - if (!GetPlayer()->HasEnoughMoney(TabCost)) // Should not happen, this is checked by client - return; - - // Go on with creating tab - pGuild->CreateNewBankTab(); - GetPlayer()->ModifyMoney(-int(TabCost)); - pGuild->SetBankMoneyPerDay(GetPlayer()->GetRank(), WITHDRAW_MONEY_UNLIMITED); - pGuild->SetBankRightsAndSlots(GetPlayer()->GetRank(), TabId, GUILD_BANK_RIGHT_FULL, WITHDRAW_SLOT_UNLIMITED, true); - pGuild->Roster(); // broadcast for tab rights update - pGuild->DisplayGuildBankTabsInfo(this); + if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + if (Guild* pGuild = _GetPlayerGuild(this)) + pGuild->HandleBuyBankTab(this, tabId); } void WorldSession::HandleGuildBankUpdateTab(WorldPacket & recv_data) @@ -1113,109 +516,55 @@ void WorldSession::HandleGuildBankUpdateTab(WorldPacket & recv_data) sLog.outDebug("WORLD: Received (CMSG_GUILD_BANK_UPDATE_TAB)"); uint64 GoGuid; - uint8 TabId; - std::string Name; - std::string IconIndex; - recv_data >> GoGuid; - recv_data >> TabId; - recv_data >> Name; - recv_data >> IconIndex; - - if (Name.empty()) - return; - if (IconIndex.empty()) - return; - - if (!GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) - return; - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) - return; + uint8 tabId; + recv_data >> tabId; - Guild *pGuild = sObjectMgr.GetGuildById(GuildId); - if (!pGuild) - return; + std::string name; + recv_data >> name; - if (TabId >= pGuild->GetPurchasedTabs()) - return; + std::string icon; + recv_data >> icon; - pGuild->SetGuildBankTabInfo(TabId, Name, IconIndex); - pGuild->DisplayGuildBankTabsInfo(this); - pGuild->DisplayGuildBankContent(this, TabId); + if (!name.empty() && !icon.empty()) + if (GetPlayer()->GetGameObjectIfCanInteractWith(GoGuid, GAMEOBJECT_TYPE_GUILD_BANK)) + if (Guild* pGuild = _GetPlayerGuild(this)) + pGuild->HandleSetBankTabInfo(this, tabId, name, icon); } void WorldSession::HandleGuildBankLogQuery(WorldPacket & recv_data) { sLog.outDebug("WORLD: Received (MSG_GUILD_BANK_LOG_QUERY)"); - uint8 TabId; - recv_data >> TabId; - - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) - return; - - Guild *pGuild = sObjectMgr.GetGuildById(GuildId); - if (!pGuild) - return; - - // GUILD_BANK_MAX_TABS send by client for money log - if (TabId >= pGuild->GetPurchasedTabs() && TabId != GUILD_BANK_MAX_TABS) - return; + uint8 tabId; + recv_data >> tabId; - pGuild->DisplayGuildBankLogs(this, TabId); + if (Guild* pGuild = _GetPlayerGuild(this)) + pGuild->SendBankLog(this, tabId); } void WorldSession::HandleQueryGuildBankTabText(WorldPacket &recv_data) { sLog.outDebug("WORLD: Received MSG_QUERY_GUILD_BANK_TEXT"); - uint8 TabId; - recv_data >> TabId; + uint8 tabId; + recv_data >> tabId; - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) - return; - - Guild *pGuild = sObjectMgr.GetGuildById(GuildId); - if (!pGuild) - return; - - if (TabId >= pGuild->GetPurchasedTabs()) - return; - - pGuild->SendGuildBankTabText(this, TabId); + if (Guild* pGuild = _GetPlayerGuild(this)) + pGuild->SendBankTabText(this, tabId); } void WorldSession::HandleSetGuildBankTabText(WorldPacket &recv_data) { sLog.outDebug("WORLD: Received CMSG_SET_GUILD_BANK_TEXT"); - uint8 TabId; - std::string Text; - recv_data >> TabId; - recv_data >> Text; + uint8 tabId; + recv_data >> tabId; - uint32 GuildId = GetPlayer()->GetGuildId(); - if (!GuildId) - return; + std::string text; + recv_data >> text; - Guild *pGuild = sObjectMgr.GetGuildById(GuildId); - if (!pGuild) - return; - - if (TabId >= pGuild->GetPurchasedTabs()) - return; - - pGuild->SetGuildBankTabText(TabId, Text); -} - -void WorldSession::SendSaveGuildEmblem(uint32 msg) -{ - WorldPacket data(MSG_SAVE_GUILD_EMBLEM, 4); - data << uint32(msg); // not part of guild - SendPacket(&data); + if (Guild* pGuild = _GetPlayerGuild(this)) + pGuild->SetBankTabText(tabId, text); } diff --git a/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp b/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp index 2a2f24a82b4..5841d9c48f6 100755 --- a/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/NPCHandler.cpp @@ -33,7 +33,6 @@ #include "Pet.h" #include "BattlegroundMgr.h" #include "Battleground.h" -#include "Guild.h" #include "ScriptMgr.h" enum StableResultCode @@ -880,31 +879,13 @@ void WorldSession::HandleRepairItemOpcode(WorldPacket & recv_data) sLog.outDebug("ITEM: Repair item, itemGUID = %u, npcGUID = %u", GUID_LOPART(itemGUID), GUID_LOPART(npcGUID)); Item* item = _player->GetItemByGuid(itemGUID); - if (item) - TotalCost= _player->DurabilityRepair(item->GetPos(),true,discountMod,guildBank>0?true:false); + TotalCost = _player->DurabilityRepair(item->GetPos(), true, discountMod, guildBank); } else { sLog.outDebug("ITEM: Repair all items, npcGUID = %u", GUID_LOPART(npcGUID)); - - TotalCost = _player->DurabilityRepairAll(true,discountMod,guildBank>0?true:false); - } - if (guildBank) - { - uint32 GuildId = _player->GetGuildId(); - if (!GuildId) - return; - Guild *pGuild = sObjectMgr.GetGuildById(GuildId); - if (!pGuild) - return; - - //- TODO: Fix poor function call design - SQLTransaction trans = CharacterDatabase.BeginTransaction(); - pGuild->LogBankEvent(trans, GUILD_BANK_LOG_REPAIR_MONEY, 0, _player->GetGUIDLow(), TotalCost); - CharacterDatabase.CommitTransaction(trans); - - pGuild->SendMoneyInfo(this, _player->GetGUIDLow()); + TotalCost = _player->DurabilityRepairAll(true, discountMod, guildBank); } } diff --git a/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp b/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp index cc4e6028406..37bb3efe62e 100755 --- a/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/PetitionsHandler.cpp @@ -46,14 +46,6 @@ enum CharterItemIDs ARENA_TEAM_CHARTER_5v5 = 23562 }; -enum CharterTypes -{ - GUILD_CHARTER_TYPE = 9, - ARENA_TEAM_CHARTER_2v2_TYPE = 2, - ARENA_TEAM_CHARTER_3v3_TYPE = 3, - ARENA_TEAM_CHARTER_5v5_TYPE = 5 -}; - enum CharterCosts { GUILD_CHARTER_COST = 1000, @@ -164,12 +156,12 @@ void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data) { if (sObjectMgr.GetGuildByName(name)) { - SendGuildCommandResult(GUILD_CREATE_S, name, ERR_GUILD_NAME_EXISTS_S); + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_EXISTS_S, name); return; } if (sObjectMgr.IsReservedName(name) || !ObjectMgr::IsValidCharterName(name)) { - SendGuildCommandResult(GUILD_CREATE_S, name, ERR_GUILD_NAME_INVALID); + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_INVALID, name); return; } } @@ -414,12 +406,12 @@ void WorldSession::HandlePetitionRenameOpcode(WorldPacket & recv_data) { if (sObjectMgr.GetGuildByName(newname)) { - SendGuildCommandResult(GUILD_CREATE_S, newname, ERR_GUILD_NAME_EXISTS_S); + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_EXISTS_S, newname); return; } if (sObjectMgr.IsReservedName(newname) || !ObjectMgr::IsValidCharterName(newname)) { - SendGuildCommandResult(GUILD_CREATE_S, newname, ERR_GUILD_NAME_INVALID); + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_INVALID, newname); return; } } @@ -484,14 +476,14 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data) // not let enemies sign guild charter if (!sWorld.getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != sObjectMgr.GetPlayerTeamByGUID(ownerguid)) { - if (type != 9) + if (type != GUILD_CHARTER_TYPE) SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); else - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_NOT_ALLIED); + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NOT_ALLIED); return; } - if (type != 9) + if (type != GUILD_CHARTER_TYPE) { if (_player->getLevel() < sWorld.getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) { @@ -519,12 +511,12 @@ void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data) { if (_player->GetGuildId()) { - SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_IN_GUILD_S); + Guild::SendCommandResult(this, GUILD_INVITE_S, ERR_ALREADY_IN_GUILD_S, _player->GetName()); return; } if (_player->GetGuildIdInvited()) { - SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_INVITED_TO_GUILD_S); + Guild::SendCommandResult(this, GUILD_INVITE_S, ERR_ALREADY_INVITED_TO_GUILD_S, _player->GetName()); return; } } @@ -628,14 +620,14 @@ void WorldSession::HandleOfferPetitionOpcode(WorldPacket & recv_data) if (!sWorld.getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != player->GetTeam()) { - if (type != 9) + if (type != GUILD_CHARTER_TYPE) SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED); else - SendGuildCommandResult(GUILD_CREATE_S, "", ERR_GUILD_NOT_ALLIED); + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NOT_ALLIED); return; } - if (type != 9) + if (type != GUILD_CHARTER_TYPE) { if (player->getLevel() < sWorld.getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) { @@ -665,13 +657,13 @@ void WorldSession::HandleOfferPetitionOpcode(WorldPacket & recv_data) { if (player->GetGuildId()) { - SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_IN_GUILD_S); + Guild::SendCommandResult(this, GUILD_INVITE_S, ERR_ALREADY_IN_GUILD_S, _player->GetName()); return; } if (player->GetGuildIdInvited()) { - SendGuildCommandResult(GUILD_INVITE_S, _player->GetName(), ERR_ALREADY_INVITED_TO_GUILD_S); + Guild::SendCommandResult(this, GUILD_INVITE_S, ERR_ALREADY_INVITED_TO_GUILD_S, _player->GetName()); return; } } @@ -787,7 +779,7 @@ void WorldSession::HandleTurnInPetitionOpcode(WorldPacket & recv_data) { if (sObjectMgr.GetGuildByName(name)) { - SendGuildCommandResult(GUILD_CREATE_S, name, ERR_GUILD_NAME_EXISTS_S); + Guild::SendCommandResult(this, GUILD_CREATE_S, ERR_GUILD_NAME_EXISTS_S, name); return; } } @@ -826,7 +818,7 @@ void WorldSession::HandleTurnInPetitionOpcode(WorldPacket & recv_data) for (uint8 i = 0; i < signs; ++i) { Field* fields = result->Fetch(); - guild->AddMember(fields[0].GetUInt64(), guild->GetLowestRank()); + guild->AddMember(fields[0].GetUInt64()); result->NextRow(); } } diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index ef1b5c4d339..ab269f58204 100755 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -410,14 +410,8 @@ void WorldSession::LogoutPlayer(bool Save) HandleMoveWorldportAckOpcode(); ///- If the player is in a guild, update the guild roster and broadcast a logout message to other guild members - Guild *guild = sObjectMgr.GetGuildById(_player->GetGuildId()); - if (guild) - { - guild->SetMemberStats(_player->GetGUID()); - guild->UpdateLogoutTime(_player->GetGUID()); - - guild->BroadcastEvent(GE_SIGNED_OFF, _player->GetGUID(), 1, _player->GetName(), "", ""); - } + if (Guild *pGuild = sObjectMgr.GetGuildById(_player->GetGuildId())) + pGuild->HandleMemberLogout(this); ///- Remove pet _player->RemovePet(NULL,PET_SAVE_AS_CURRENT, true); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 5f5f4d1b335..d92c8c609d7 100755 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -129,6 +129,14 @@ enum ChatRestrictionType ERR_YELL_RESTRICTED = 3 }; +enum CharterTypes +{ + GUILD_CHARTER_TYPE = 9, + ARENA_TEAM_CHARTER_2v2_TYPE = 2, + ARENA_TEAM_CHARTER_3v3_TYPE = 3, + ARENA_TEAM_CHARTER_5v5_TYPE = 5 +}; + /// Player session in the World class WorldSession { @@ -272,11 +280,9 @@ class WorldSession void SendDiscoverNewTaxiNode(uint32 nodeid); // Guild/Arena Team - void SendGuildCommandResult(uint32 typecmd, const std::string& str, uint32 cmdresult); void SendArenaTeamCommandResult(uint32 team_action, const std::string& team, const std::string& player, uint32 error_id); void SendNotInArenaTeamPacket(uint8 type); void SendPetitionShowList(uint64 guid); - void SendSaveGuildEmblem(uint32 msg); void BuildPartyMemberStatsChangedPacket(Player *player, WorldPacket *data); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index f4117fb9671..27fa609ff16 100755 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1052,9 +1052,9 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_GUILD_EVENT_LOG_COUNT] = sConfig.GetIntDefault("Guild.EventLogRecordsCount", GUILD_EVENTLOG_MAX_RECORDS); if (m_int_configs[CONFIG_GUILD_EVENT_LOG_COUNT] < GUILD_EVENTLOG_MAX_RECORDS) m_int_configs[CONFIG_GUILD_EVENT_LOG_COUNT] = GUILD_EVENTLOG_MAX_RECORDS; - m_int_configs[CONFIG_GUILD_BANK_EVENT_LOG_COUNT] = sConfig.GetIntDefault("Guild.BankEventLogRecordsCount", GUILD_BANK_MAX_LOGS); - if (m_int_configs[CONFIG_GUILD_BANK_EVENT_LOG_COUNT] < GUILD_BANK_MAX_LOGS) - m_int_configs[CONFIG_GUILD_BANK_EVENT_LOG_COUNT] = GUILD_BANK_MAX_LOGS; + m_int_configs[CONFIG_GUILD_BANK_EVENT_LOG_COUNT] = sConfig.GetIntDefault("Guild.BankEventLogRecordsCount", GUILD_BANKLOG_MAX_RECORDS); + if (m_int_configs[CONFIG_GUILD_BANK_EVENT_LOG_COUNT] < GUILD_BANKLOG_MAX_RECORDS) + m_int_configs[CONFIG_GUILD_BANK_EVENT_LOG_COUNT] = GUILD_BANKLOG_MAX_RECORDS; m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1); if (m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) @@ -1530,7 +1530,7 @@ void World::SetInitialWorldSettings() sLog.outString("Loading Auctions..."); sAuctionMgr.LoadAuctions(); - sLog.outString("Loading Guilds..."); + sLog.outString("***** GUILDS *****"); sObjectMgr.LoadGuilds(); sLog.outString("Loading ArenaTeams..."); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 60e29f22f54..4963a0b89f3 100755 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -88,7 +88,6 @@ bool CharacterDatabaseConnection::Open() PrepareStatement(CHAR_LOAD_ACCOUNT_DATA, "SELECT type, time, data FROM account_data WHERE account = ?"); PrepareStatement(CHAR_LOAD_PLAYER_MAILITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, item_guid, item_template, owner_guid FROM mail_items JOIN item_instance ON item_guid = guid WHERE mail_id = ?"); PrepareStatement(CHAR_LOAD_AUCTION_ITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, itemguid, item_template FROM auctionhouse JOIN item_instance ON itemguid = guid"); - PrepareStatement(CHAR_LOAD_GUILD_BANK_ITEMS, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, TabId, SlotId, item_guid, item_entry, guildid FROM guild_bank_item JOIN item_instance ON item_guid = guid"); PrepareStatement(CHAR_LOAD_ITEM_REFUNDS, "SELECT player_guid, paidMoney, paidExtendedCost FROM item_refund_instance WHERE item_guid = ? AND player_guid = ? LIMIT 1"); PrepareStatement(CHAR_LOAD_ITEM_BOP_TRADE, "SELECT allowedPlayers FROM item_soulbound_trade_data WHERE itemGuid = ? LIMIT 1"); PrepareStatement(CHAR_DEL_ITEM_BOP_TRADE, "DELETE FROM item_soulbound_trade_data WHERE itemGuid = ? LIMIT 1"); @@ -97,5 +96,120 @@ bool CharacterDatabaseConnection::Open() PrepareStatement(CHAR_DEL_ITEM_INSTANCE, "DELETE FROM item_instance WHERE guid = ?"); PrepareStatement(CHAR_GET_ACCOUNT_BY_NAME, "SELECT account FROM characters WHERE name = ?"); + // Guild handling + // 0: uint32, 1: string, 2: uint32, 3: string, 4: string, 5: uint64, 6-10: uint32, 11: uint64 + PrepareStatement(CHAR_ADD_GUILD, "INSERT INTO guild (guildid, name, leaderguid, info, motd, createdate, EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor, BankMoney) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + PrepareStatement(CHAR_DEL_GUILD, "DELETE FROM guild WHERE guildid = ?"); // 0: uint32 + // 0: uint32, 1: uint32, 2: uint8, 4: string, 5: string + PrepareStatement(CHAR_ADD_GUILD_MEMBER, "INSERT INTO guild_member (guildid, guid, rank, pnote, offnote) VALUES (?, ?, ?, ?, ?)"); + PrepareStatement(CHAR_DEL_GUILD_MEMBER, "DELETE FROM guild_member WHERE guid = ?"); // 0: uint32 + PrepareStatement(CHAR_DEL_GUILD_MEMBERS, "DELETE FROM guild_member WHERE guildid = ?"); // 0: uint32 + // 0: uint32, 1: uint8, 3: string, 4: uint32 + PrepareStatement(CHAR_ADD_GUILD_RANK, "INSERT INTO guild_rank (guildid, rid, rname, rights) VALUES (?, ?, ?, ?)"); + PrepareStatement(CHAR_DEL_GUILD_RANKS, "DELETE FROM guild_rank WHERE guildid = ?"); // 0: uint32 + PrepareStatement(CHAR_DEL_GUILD_LOWEST_RANK, "DELETE FROM guild_rank WHERE guildid = ? AND rid >= ?"); // 0: uint32, 1: uint8 + PrepareStatement(CHAR_ADD_GUILD_BANK_TAB, "INSERT INTO guild_bank_tab (guildid, TabId) VALUES (?, ?)"); // 0: uint32, 1: uint8 + PrepareStatement(CHAR_DEL_GUILD_BANK_TAB, "DELETE FROM guild_bank_tab WHERE guildid = ? AND TabId = ?"); // 0: uint32, 1: uint8 + PrepareStatement(CHAR_DEL_GUILD_BANK_TABS, "DELETE FROM guild_bank_tab WHERE guildid = ?"); // 0: uint32 + // 0: uint32, 1: uint8, 2: uint8, 3: uint32, 4: uint32 + PrepareStatement(CHAR_ADD_GUILD_BANK_ITEM, "INSERT INTO guild_bank_item (guildid, TabId, SlotId, item_guid, item_entry) VALUES (?, ?, ?, ?, ?)"); + PrepareStatement(CHAR_DEL_GUILD_BANK_ITEM, "DELETE FROM guild_bank_item WHERE guildid = ? AND TabId = ? AND SlotId = ?"); // 0: uint32, 1: uint8, 2: uint8 + PrepareStatement(CHAR_DEL_GUILD_BANK_ITEMS, "DELETE FROM guild_bank_item WHERE guildid = ?"); // 0: uint32 + PrepareStatement(CHAR_ADD_GUILD_BANK_RIGHT_DEFAULT, "INSERT INTO guild_bank_right (guildid, TabId, rid) VALUES (?, ?, ?)"); // 0: uint32, 1: uint8, 2: uint8 + // 0: uint32, 1: uint8, 2: uint8, 3: uint8, 4: uint32 + PrepareStatement(CHAR_ADD_GUILD_BANK_RIGHT, "INSERT INTO guild_bank_right (guildid, TabId, rid, gbright, SlotPerDay) VALUES (?, ?, ?, ?, ?)"); + PrepareStatement(CHAR_DEL_GUILD_BANK_RIGHT, "DELETE FROM guild_bank_right WHERE guildid = ? AND TabId = ? AND rid = ?"); // 0: uint32, 1: uint8, 2: uint8 + PrepareStatement(CHAR_DEL_GUILD_BANK_RIGHTS, "DELETE FROM guild_bank_right WHERE guildid = ?"); // 0: uint32 + PrepareStatement(CHAR_DEL_GUILD_BANK_RIGHTS_FOR_RANK, "DELETE FROM guild_bank_right WHERE guildid = ? AND rid = ?"); // 0: uint32, 1: uint8 + // 0-1: uint32, 2-3: uint8, 4-5: uint32, 6: uint16, 7: uint8, 8: uint64 + PrepareStatement(CHAR_ADD_GUILD_BANK_EVENTLOG, "INSERT INTO guild_bank_eventlog (guildid, LogGuid, TabId, EventType, PlayerGuid, ItemOrMoney, ItemStackCount, DestTabId, TimeStamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); + PrepareStatement(CHAR_DEL_GUILD_BANK_EVENTLOG, "DELETE FROM guild_bank_eventlog WHERE guildid = ? AND LogGuid = ? AND TabId = ?"); // 0: uint32, 1: uint32, 2: uint8 + PrepareStatement(CHAR_DEL_GUILD_BANK_EVENTLOGS, "DELETE FROM guild_bank_eventlog WHERE guildid = ?"); // 0: uint32 + // 0-1: uint32, 2: uint8, 3-4: uint32, 5: uint8, 6: uint64 + PrepareStatement(CHAR_ADD_GUILD_EVENTLOG, "INSERT INTO guild_eventlog (guildid, LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp) VALUES (?, ?, ?, ?, ?, ?, ?)"); + PrepareStatement(CHAR_DEL_GUILD_EVENTLOG, "DELETE FROM guild_eventlog WHERE guildid = ? AND LogGuid = ?"); // 0: uint32, 1: uint32 + PrepareStatement(CHAR_DEL_GUILD_EVENTLOGS, "DELETE FROM guild_eventlog WHERE guildid = ?"); // 0: uint32 + PrepareStatement(CHAR_SET_GUILD_MEMBER_PNOTE, "UPDATE guild_member SET pnote = ? WHERE guid = ?"); // 0: string, 1: uint32 + PrepareStatement(CHAR_SET_GUILD_MEMBER_OFFNOTE, "UPDATE guild_member SET offnote = ? WHERE guid = ?"); // 0: string, 1: uint32 + PrepareStatement(CHAR_SET_GUILD_MEMBER_RANK, "UPDATE guild_member SET rank = ? WHERE guid = ?"); // 0: uint8, 1: uint32 + PrepareStatement(CHAR_SET_GUILD_MOTD, "UPDATE guild SET motd = ? WHERE guildid = ?"); // 0: string, 1: uint32 + PrepareStatement(CHAR_SET_GUILD_INFO, "UPDATE guild SET info = ? WHERE guildid = ?"); // 0: string, 1: uint32 + PrepareStatement(CHAR_SET_GUILD_LEADER, "UPDATE guild SET leaderguid = ? WHERE guildid = ?"); // 0: uint32, 1: uint32 + PrepareStatement(CHAR_SET_GUILD_RANK_NAME, "UPDATE guild_rank SET rname = ? WHERE rid = ? AND guildid = ?"); // 0: string, 1: uint8, 2: uint32 + PrepareStatement(CHAR_SET_GUILD_RANK_RIGHTS, "UPDATE guild_rank SET rights = ? WHERE rid = ? AND guildid = ?"); // 0: uint32, 1: uint8, 2: uint32 + // 0-5: uint32 + PrepareStatement(CHAR_SET_GUILD_EMBLEM_INFO, "UPDATE guild SET EmblemStyle = ?, EmblemColor = ?, BorderStyle = ?, BorderColor = ?, BackgroundColor = ? WHERE guildid = ?"); + // 0: string, 1: string, 2: uint32, 3: uint8 + PrepareStatement(CHAR_SET_GUILD_BANK_TAB_INFO, "UPDATE guild_bank_tab SET TabName = ?,TabIcon = ? WHERE guildid = ? AND TabId = ?"); + PrepareStatement(CHAR_SET_GUILD_BANK_MONEY, "UPDATE guild SET BankMoney = ? WHERE guildid = ?"); // 0: uint64, 1: uint32 + // 0: uint8, 1: uint32, 2: uint8, 3: uint32 + PrepareStatement(CHAR_SET_GUILD_BANK_EVENTLOG_TAB, "UPDATE guild_bank_eventlog SET TabId = ? WHERE guildid = ? AND TabId = ? AND LogGuid = ?"); + PrepareStatement(CHAR_SET_GUILD_MEMBER_BANK_REM_MONEY, "UPDATE guild_member SET BankRemMoney = ? WHERE guildid = ? AND guid = ?"); // 0: uint32, 1: uint32, 2: uint32 + PrepareStatement(CHAR_SET_GUILD_MEMBER_BANK_TIME_MONEY, "UPDATE guild_member SET BankResetTimeMoney = ?, BankRemMoney = ? WHERE guildid = ? AND guid = ?"); // 0: uint32, 1: uint32, 2: uint32, 3: uint32 + PrepareStatement(CHAR_RESET_GUILD_RANK_BANK_RESET_TIME, "UPDATE guild_member SET BankResetTimeMoney = 0 WHERE guildid = ? AND rank = ?"); // 0: uint32, 1: uint8 + PrepareStatement(CHAR_SET_GUILD_RANK_BANK_MONEY, "UPDATE guild_rank SET BankMoneyPerDay = ? WHERE rid = ? AND guildid = ?"); // 0: uint32, 1: uint8, 2: uint32 + PrepareStatement(CHAR_SET_GUILD_BANK_TAB_TEXT, "UPDATE guild_bank_tab SET TabText = ? WHERE guildid = ? AND TabId = ?"); // 0: string, 1: uint32, 2: uint8 + // 0: uint32, 1: uint32, 2: uint32 + PrepareStatement(CHAR_SET_GUILD_MEMBER_BANK_REM_SLOTS0, "UPDATE guild_member SET BankRemSlotsTab0 = ? WHERE guildid = ? AND guid = ?"); + PrepareStatement(CHAR_SET_GUILD_MEMBER_BANK_REM_SLOTS1, "UPDATE guild_member SET BankRemSlotsTab1 = ? WHERE guildid = ? AND guid = ?"); + PrepareStatement(CHAR_SET_GUILD_MEMBER_BANK_REM_SLOTS2, "UPDATE guild_member SET BankRemSlotsTab2 = ? WHERE guildid = ? AND guid = ?"); + PrepareStatement(CHAR_SET_GUILD_MEMBER_BANK_REM_SLOTS3, "UPDATE guild_member SET BankRemSlotsTab3 = ? WHERE guildid = ? AND guid = ?"); + PrepareStatement(CHAR_SET_GUILD_MEMBER_BANK_REM_SLOTS4, "UPDATE guild_member SET BankRemSlotsTab4 = ? WHERE guildid = ? AND guid = ?"); + PrepareStatement(CHAR_SET_GUILD_MEMBER_BANK_REM_SLOTS5, "UPDATE guild_member SET BankRemSlotsTab5 = ? WHERE guildid = ? AND guid = ?"); + // 0: uint32, 1: uint32, 2: uint32, 3: uint32 + PrepareStatement(CHAR_SET_GUILD_MEMBER_BANK_TIME_REM_SLOTS0, "UPDATE guild_member SET BankResetTimeTab0 = ?, BankRemSlotsTab0 = ? WHERE guildid = ? AND guid = ?"); + PrepareStatement(CHAR_SET_GUILD_MEMBER_BANK_TIME_REM_SLOTS1, "UPDATE guild_member SET BankResetTimeTab1 = ?, BankRemSlotsTab1 = ? WHERE guildid = ? AND guid = ?"); + PrepareStatement(CHAR_SET_GUILD_MEMBER_BANK_TIME_REM_SLOTS2, "UPDATE guild_member SET BankResetTimeTab2 = ?, BankRemSlotsTab2 = ? WHERE guildid = ? AND guid = ?"); + PrepareStatement(CHAR_SET_GUILD_MEMBER_BANK_TIME_REM_SLOTS3, "UPDATE guild_member SET BankResetTimeTab3 = ?, BankRemSlotsTab3 = ? WHERE guildid = ? AND guid = ?"); + PrepareStatement(CHAR_SET_GUILD_MEMBER_BANK_TIME_REM_SLOTS4, "UPDATE guild_member SET BankResetTimeTab4 = ?, BankRemSlotsTab4 = ? WHERE guildid = ? AND guid = ?"); + PrepareStatement(CHAR_SET_GUILD_MEMBER_BANK_TIME_REM_SLOTS5, "UPDATE guild_member SET BankResetTimeTab5 = ?, BankRemSlotsTab5 = ? WHERE guildid = ? AND guid = ?"); + // 0: uint32, 1: uint8 + PrepareStatement(CHAR_RESET_GUILD_RANK_BANK_TIME0, "UPDATE guild_member SET BankResetTimeTab0 = 0 WHERE guildid = ? AND rank = ?"); + PrepareStatement(CHAR_RESET_GUILD_RANK_BANK_TIME1, "UPDATE guild_member SET BankResetTimeTab1 = 0 WHERE guildid = ? AND rank = ?"); + PrepareStatement(CHAR_RESET_GUILD_RANK_BANK_TIME2, "UPDATE guild_member SET BankResetTimeTab2 = 0 WHERE guildid = ? AND rank = ?"); + PrepareStatement(CHAR_RESET_GUILD_RANK_BANK_TIME3, "UPDATE guild_member SET BankResetTimeTab3 = 0 WHERE guildid = ? AND rank = ?"); + PrepareStatement(CHAR_RESET_GUILD_RANK_BANK_TIME4, "UPDATE guild_member SET BankResetTimeTab4 = 0 WHERE guildid = ? AND rank = ?"); + PrepareStatement(CHAR_RESET_GUILD_RANK_BANK_TIME5, "UPDATE guild_member SET BankResetTimeTab5 = 0 WHERE guildid = ? AND rank = ?"); + PrepareStatement(CHAR_LOAD_GUILDS, + // 0 1 2 3 4 5 6 + "SELECT g.guildid, g.name, g.leaderguid, g.EmblemStyle, g.EmblemColor, g.BorderStyle, g.BorderColor," + // 7 8 9 10 11 12 + "g.BackgroundColor, g.info, g.motd, g.createdate, g.BankMoney, COUNT(gbt.guildid) " + "FROM guild g LEFT JOIN guild_bank_tab gbt ON g.guildid = gbt.guildid GROUP BY g.guildid ORDER BY g.guildid ASC"); + // 0 1 2 3 4 + PrepareStatement(CHAR_LOAD_GUILD_RANKS, "SELECT guildid, rid, rname, rights, BankMoneyPerDay FROM guild_rank ORDER BY guildid ASC, rid ASC"); + PrepareStatement(CHAR_LOAD_CHAR_DATA_FOR_GUILD, "SELECT name, level, class, zone, account FROM characters WHERE guid = ?"); + PrepareStatement(CHAR_LOAD_GUILD_MEMBERS, + // 0 1 2 3 4 5 6 + "SELECT guildid, gm.guid, rank, pnote, offnote, BankResetTimeMoney, BankRemMoney," + // 7 8 9 10 11 12 + "BankResetTimeTab0, BankRemSlotsTab0, BankResetTimeTab1, BankRemSlotsTab1, BankResetTimeTab2, BankRemSlotsTab2," + // 13 14 15 16 17 18 + "BankResetTimeTab3, BankRemSlotsTab3, BankResetTimeTab4, BankRemSlotsTab4, BankResetTimeTab5, BankRemSlotsTab5," + // 19 20 21 22 23 24 + "c.name, c.level, c.class, c.zone, c.account, c.logout_time " + "FROM guild_member gm LEFT JOIN characters c ON c.guid = gm.guid ORDER BY guildid ASC"); + PrepareStatement(CHAR_LOAD_GUILD_BANK_RIGHTS, + // 0 1 2 3 4 + "SELECT guildid, TabId, rid, gbright, SlotPerDay FROM guild_bank_right ORDER BY guildid ASC, TabId ASC"); + // 0 1 2 3 4 + PrepareStatement(CHAR_LOAD_GUILD_BANK_TABS, "SELECT guildid, TabId, TabName, TabIcon, TabText FROM guild_bank_tab ORDER BY guildid ASC, TabId ASC"); + PrepareStatement(CHAR_LOAD_GUILD_EVENTLOGS, + // 0 1 2 3 4 5 6 + "SELECT guildid, LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp FROM guild_eventlog ORDER BY TimeStamp DESC, LogGuid DESC"); + PrepareStatement(CHAR_LOAD_GUILD_BANK_EVENTLOGS, + // 0 1 2 3 4 5 6 7 8 + "SELECT guildid, TabId, LogGuid, EventType, PlayerGuid, ItemOrMoney, ItemStackCount, DestTabId, TimeStamp FROM guild_bank_eventlog ORDER BY TimeStamp DESC, LogGuid DESC"); + PrepareStatement(CHAR_LOAD_GUILD_BANK_ITEMS, + // 0 1 2 3 4 5 6 7 8 9 10 + "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, " + // 11 12 13 14 15 + "guildid, TabId, SlotId, item_guid, item_entry FROM guild_bank_item INNER JOIN item_instance ON item_guid = guid"); + + PrepareStatement(CHAR_CLEAN_GUILD_RANKS, "DELETE FROM guild_rank WHERE guildId NOT IN (SELECT guildid FROM guild)"); + PrepareStatement(CHAR_CLEAN_GUILD_MEMBERS, "DELETE FROM guild_member WHERE guildId NOT IN (SELECT guildid FROM guild)"); + PrepareStatement(CHAR_CLEAN_GUILD_BANK_TABS, "DELETE FROM guild_bank_tab WHERE guildId NOT IN (SELECT guildid FROM guild)"); + PrepareStatement(CHAR_CLEAN_GUILD_BANK_RIGHTS, "DELETE FROM guild_bank_right WHERE guildId NOT IN (SELECT guildid FROM guild)"); + PrepareStatement(CHAR_CLEAN_GUILD_BANK_ITEMS, "DELETE FROM guild_bank_item WHERE guildId NOT IN (SELECT guildid FROM guild)"); return true; } diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index ae3c730d1a5..041afca2a23 100755 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -102,6 +102,81 @@ enum CharacterDatabaseStatements CHAR_DEL_INVENTORY_ITEM, CHAR_DEL_ITEM_INSTANCE, CHAR_GET_ACCOUNT_BY_NAME, + + CHAR_ADD_GUILD, + CHAR_DEL_GUILD, + CHAR_ADD_GUILD_MEMBER, + CHAR_DEL_GUILD_MEMBER, + CHAR_DEL_GUILD_MEMBERS, + CHAR_ADD_GUILD_RANK, + CHAR_DEL_GUILD_RANKS, + CHAR_DEL_GUILD_LOWEST_RANK, + CHAR_ADD_GUILD_BANK_TAB, + CHAR_DEL_GUILD_BANK_TAB, + CHAR_DEL_GUILD_BANK_TABS, + CHAR_ADD_GUILD_BANK_ITEM, + CHAR_DEL_GUILD_BANK_ITEM, + CHAR_DEL_GUILD_BANK_ITEMS, + CHAR_ADD_GUILD_BANK_RIGHT_DEFAULT, + CHAR_ADD_GUILD_BANK_RIGHT, + CHAR_DEL_GUILD_BANK_RIGHT, + CHAR_DEL_GUILD_BANK_RIGHTS, + CHAR_DEL_GUILD_BANK_RIGHTS_FOR_RANK, + CHAR_ADD_GUILD_BANK_EVENTLOG, + CHAR_DEL_GUILD_BANK_EVENTLOG, + CHAR_DEL_GUILD_BANK_EVENTLOGS, + CHAR_ADD_GUILD_EVENTLOG, + CHAR_DEL_GUILD_EVENTLOG, + CHAR_DEL_GUILD_EVENTLOGS, + CHAR_SET_GUILD_MEMBER_PNOTE, + CHAR_SET_GUILD_MEMBER_OFFNOTE, + CHAR_SET_GUILD_MEMBER_RANK, + CHAR_SET_GUILD_MOTD, + CHAR_SET_GUILD_INFO, + CHAR_SET_GUILD_LEADER, + CHAR_SET_GUILD_RANK_NAME, + CHAR_SET_GUILD_RANK_RIGHTS, + CHAR_SET_GUILD_EMBLEM_INFO, + CHAR_SET_GUILD_BANK_TAB_INFO, + CHAR_SET_GUILD_BANK_MONEY, + CHAR_SET_GUILD_BANK_EVENTLOG_TAB, + CHAR_SET_GUILD_MEMBER_BANK_REM_MONEY, + CHAR_SET_GUILD_MEMBER_BANK_TIME_MONEY, + CHAR_RESET_GUILD_RANK_BANK_RESET_TIME, + CHAR_SET_GUILD_RANK_BANK_MONEY, + CHAR_SET_GUILD_BANK_TAB_TEXT, + CHAR_SET_GUILD_MEMBER_BANK_TIME_REM_SLOTS0, + CHAR_SET_GUILD_MEMBER_BANK_TIME_REM_SLOTS1, + CHAR_SET_GUILD_MEMBER_BANK_TIME_REM_SLOTS2, + CHAR_SET_GUILD_MEMBER_BANK_TIME_REM_SLOTS3, + CHAR_SET_GUILD_MEMBER_BANK_TIME_REM_SLOTS4, + CHAR_SET_GUILD_MEMBER_BANK_TIME_REM_SLOTS5, + CHAR_SET_GUILD_MEMBER_BANK_REM_SLOTS0, + CHAR_SET_GUILD_MEMBER_BANK_REM_SLOTS1, + CHAR_SET_GUILD_MEMBER_BANK_REM_SLOTS2, + CHAR_SET_GUILD_MEMBER_BANK_REM_SLOTS3, + CHAR_SET_GUILD_MEMBER_BANK_REM_SLOTS4, + CHAR_SET_GUILD_MEMBER_BANK_REM_SLOTS5, + CHAR_RESET_GUILD_RANK_BANK_TIME0, + CHAR_RESET_GUILD_RANK_BANK_TIME1, + CHAR_RESET_GUILD_RANK_BANK_TIME2, + CHAR_RESET_GUILD_RANK_BANK_TIME3, + CHAR_RESET_GUILD_RANK_BANK_TIME4, + CHAR_RESET_GUILD_RANK_BANK_TIME5, + CHAR_LOAD_GUILDS, + CHAR_LOAD_GUILD_RANKS, + CHAR_LOAD_CHAR_DATA_FOR_GUILD, + CHAR_LOAD_GUILD_MEMBERS, + CHAR_LOAD_GUILD_BANK_RIGHTS, + CHAR_LOAD_GUILD_BANK_TABS, + CHAR_LOAD_GUILD_EVENTLOGS, + CHAR_LOAD_GUILD_BANK_EVENTLOGS, + CHAR_CLEAN_GUILD_RANKS, + CHAR_CLEAN_GUILD_MEMBERS, + CHAR_CLEAN_GUILD_BANK_TABS, + CHAR_CLEAN_GUILD_BANK_RIGHTS, + CHAR_CLEAN_GUILD_BANK_ITEMS, + MAX_CHARACTERDATABASE_STATEMENTS, }; |