[8483] Implement glyph 43361.
[getmangos.git] / src / game / Guild.cpp
blob48c258647bcbb197c32ab241bfca94c447a4b74b
1 /*
2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Database/DatabaseEnv.h"
20 #include "WorldPacket.h"
21 #include "WorldSession.h"
22 #include "Player.h"
23 #include "Opcodes.h"
24 #include "ObjectMgr.h"
25 #include "Guild.h"
26 #include "Chat.h"
27 #include "SocialMgr.h"
28 #include "Util.h"
29 #include "Language.h"
30 #include "World.h"
32 Guild::Guild()
34 m_Id = 0;
35 m_Name = "";
36 m_LeaderGuid = 0;
37 GINFO = MOTD = "";
38 m_EmblemStyle = 0;
39 m_EmblemColor = 0;
40 m_BorderStyle = 0;
41 m_BorderColor = 0;
42 m_BackgroundColor = 0;
44 m_CreatedYear = 0;
45 m_CreatedMonth = 0;
46 m_CreatedDay = 0;
48 m_EventLogLoaded = false;
49 m_GuildBankLoaded = false;
50 m_OnlineMembers = 0;
51 m_GuildBankMoney = 0;
52 m_PurchasedTabs = 0;
54 m_GuildEventLogNextGuid = 0;
55 m_GuildBankEventLogNextGuid_Money = 0;
56 for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; i++)
57 m_GuildBankEventLogNextGuid_Item[i] = 0;
60 Guild::~Guild()
65 bool Guild::Create(Player* leader, std::string gname)
67 if (objmgr.GetGuildByName(gname))
68 return false;
70 WorldSession* lSession = leader->GetSession();
71 if (!lSession)
72 return false;
74 m_LeaderGuid = leader->GetGUID();
75 m_Name = gname;
76 GINFO = "";
77 MOTD = "No message set.";
78 m_GuildBankMoney = 0;
79 m_PurchasedTabs = 0;
80 m_Id = objmgr.GenerateGuildId();
82 sLog.outDebug("GUILD: creating guild %s to leader: %u", gname.c_str(), GUID_LOPART(m_LeaderGuid));
84 // gname already assigned to Guild::name, use it to encode string for DB
85 CharacterDatabase.escape_string(gname);
87 std::string dbGINFO = GINFO;
88 std::string dbMOTD = MOTD;
89 CharacterDatabase.escape_string(dbGINFO);
90 CharacterDatabase.escape_string(dbMOTD);
92 CharacterDatabase.BeginTransaction();
93 // CharacterDatabase.PExecute("DELETE FROM guild WHERE guildid='%u'", Id); - MAX(guildid)+1 not exist
94 CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guildid='%u'", m_Id);
95 CharacterDatabase.PExecute("INSERT INTO guild (guildid,name,leaderguid,info,motd,createdate,EmblemStyle,EmblemColor,BorderStyle,BorderColor,BackgroundColor,BankMoney) "
96 "VALUES('%u','%s','%u', '%s', '%s', UNIX_TIMESTAMP(NOW()),'%u','%u','%u','%u','%u','" UI64FMTD "')",
97 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);
98 CharacterDatabase.CommitTransaction();
100 CreateDefaultGuildRanks(lSession->GetSessionDbLocaleIndex());
102 return AddMember(m_LeaderGuid, (uint32)GR_GUILDMASTER);
105 void Guild::CreateDefaultGuildRanks(int locale_idx)
107 CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", m_Id);
108 CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u'", m_Id);
110 CreateRank(objmgr.GetMangosString(LANG_GUILD_MASTER, locale_idx), GR_RIGHT_ALL);
111 CreateRank(objmgr.GetMangosString(LANG_GUILD_OFFICER, locale_idx), GR_RIGHT_ALL);
112 CreateRank(objmgr.GetMangosString(LANG_GUILD_VETERAN, locale_idx), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
113 CreateRank(objmgr.GetMangosString(LANG_GUILD_MEMBER, locale_idx), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
114 CreateRank(objmgr.GetMangosString(LANG_GUILD_INITIATE, locale_idx), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
117 bool Guild::AddMember(uint64 plGuid, uint32 plRank)
119 Player* pl = objmgr.GetPlayer(plGuid);
120 if (pl)
122 if (pl->GetGuildId() != 0)
123 return false;
125 else
127 if (Player::GetGuildIdFromDB(plGuid) != 0) // player already in guild
128 return false;
131 // remove all player signs from another petitions
132 // this will be prevent attempt joining player to many guilds and corrupt guild data integrity
133 Player::RemovePetitionsAndSigns(plGuid, 9);
135 // fill player data
136 MemberSlot newmember;
138 if (pl)
140 newmember.Name = pl->GetName();
141 newmember.Level = pl->getLevel();
142 newmember.Class = pl->getClass();
143 newmember.ZoneId = pl->GetZoneId();
145 else
147 // 0 1 2 3
148 QueryResult *result = CharacterDatabase.PQuery("SELECT name,level,class,zone FROM characters WHERE guid = '%u'", GUID_LOPART(plGuid));
149 if (!result)
150 return false; // player doesn't exist
152 Field *fields = result->Fetch();
153 newmember.Name = fields[0].GetCppString();
154 newmember.Level = fields[1].GetUInt8();
155 newmember.Class = fields[2].GetUInt8();
156 newmember.ZoneId = fields[3].GetUInt32();
157 delete result;
158 if (newmember.Level < 1 || newmember.Level > STRONG_MAX_LEVEL ||
159 newmember.Class < CLASS_WARRIOR || newmember.Class >= MAX_CLASSES)
161 sLog.outError("Player (GUID: %u) has a broken data in field `characters` table, cannot add him to guild.",GUID_LOPART(plGuid));
162 return false;
166 newmember.RankId = plRank;
167 newmember.OFFnote = (std::string)"";
168 newmember.Pnote = (std::string)"";
169 newmember.LogoutTime = time(NULL);
170 newmember.BankResetTimeMoney = 0; // this will force update at first query
171 for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
172 newmember.BankResetTimeTab[i] = 0;
173 members[GUID_LOPART(plGuid)] = newmember;
175 std::string dbPnote = newmember.Pnote;
176 std::string dbOFFnote = newmember.OFFnote;
177 CharacterDatabase.escape_string(dbPnote);
178 CharacterDatabase.escape_string(dbOFFnote);
180 CharacterDatabase.PExecute("INSERT INTO guild_member (guildid,guid,rank,pnote,offnote) VALUES ('%u', '%u', '%u','%s','%s')",
181 m_Id, GUID_LOPART(plGuid), newmember.RankId, dbPnote.c_str(), dbOFFnote.c_str());
183 // If player not in game data in data field will be loaded from guild tables, no need to update it!!
184 if (pl)
186 pl->SetInGuild(m_Id);
187 pl->SetRank(newmember.RankId);
188 pl->SetGuildIdInvited(0);
190 return true;
193 void Guild::SetMOTD(std::string motd)
195 MOTD = motd;
197 // motd now can be used for encoding to DB
198 CharacterDatabase.escape_string(motd);
199 CharacterDatabase.PExecute("UPDATE guild SET motd='%s' WHERE guildid='%u'", motd.c_str(), m_Id);
202 void Guild::SetGINFO(std::string ginfo)
204 GINFO = ginfo;
206 // ginfo now can be used for encoding to DB
207 CharacterDatabase.escape_string(ginfo);
208 CharacterDatabase.PExecute("UPDATE guild SET info='%s' WHERE guildid='%u'", ginfo.c_str(), m_Id);
211 bool Guild::LoadGuildFromDB(uint32 GuildId)
213 //set m_Id in case guild data are broken in DB and Guild will be Disbanded (deleted from DB)
214 m_Id = GuildId;
216 QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(TabId) FROM guild_bank_tab WHERE guildid='%u'", GuildId);
217 if (result)
219 Field *fields = result->Fetch();
220 m_PurchasedTabs = fields[0].GetUInt32();
221 if (m_PurchasedTabs > GUILD_BANK_MAX_TABS)
222 m_PurchasedTabs = GUILD_BANK_MAX_TABS;
223 delete result;
226 if (!LoadRanksFromDB(GuildId))
227 return false;
229 if (!LoadMembersFromDB(GuildId))
230 return false;
232 LoadBankRightsFromDB(GuildId); // Must be after LoadRanksFromDB because it populates rank struct
234 // 0 1 2 3 4 5
235 result = CharacterDatabase.PQuery("SELECT name, leaderguid, EmblemStyle, EmblemColor, BorderStyle, BorderColor,"
236 // 6 7 8 9 10
237 "BackgroundColor, info, motd, createdate, BankMoney FROM guild WHERE guildid = '%u'", GuildId);
239 if (!result)
240 return false;
242 Field *fields = result->Fetch();
244 m_Name = fields[0].GetCppString();
245 m_LeaderGuid = MAKE_NEW_GUID(fields[1].GetUInt32(), 0, HIGHGUID_PLAYER);
247 m_EmblemStyle = fields[2].GetUInt32();
248 m_EmblemColor = fields[3].GetUInt32();
249 m_BorderStyle = fields[4].GetUInt32();
250 m_BorderColor = fields[5].GetUInt32();
251 m_BackgroundColor = fields[6].GetUInt32();
252 GINFO = fields[7].GetCppString();
253 MOTD = fields[8].GetCppString();
254 time_t time = fields[9].GetUInt64();
255 m_GuildBankMoney = fields[10].GetUInt64();
257 delete result;
259 if (time > 0)
261 tm local = *(localtime(&time)); // dereference and assign
262 m_CreatedDay = local.tm_mday;
263 m_CreatedMonth = local.tm_mon + 1;
264 m_CreatedYear = local.tm_year + 1900;
267 // Repair the structure of guild
268 // If the guildmaster doesn't exist or isn't the member of guild
269 // attempt to promote another member
270 int32 GM_rights = GetRank(GUID_LOPART(m_LeaderGuid));
271 if (GM_rights == -1)
273 DelMember(m_LeaderGuid);
274 // check no members case (disbanded)
275 if (members.empty())
276 return false;
278 else if (GM_rights != GR_GUILDMASTER)
279 SetLeader(m_LeaderGuid);
281 // Allow only 1 guildmaster
282 for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
284 if (itr->second.RankId == GR_GUILDMASTER && GUID_LOPART(m_LeaderGuid) != itr->first)
285 //set right of member to officer
286 ChangeRank(itr->first, GR_OFFICER);
289 sLog.outDebug("Guild %u Creation time Loaded day: %u, month: %u, year: %u", GuildId, m_CreatedDay, m_CreatedMonth, m_CreatedYear);
291 return true;
294 bool Guild::LoadRanksFromDB(uint32 GuildId)
296 Field *fields;
297 // 0 1 2 3
298 QueryResult *result = CharacterDatabase.PQuery("SELECT rid,rname,rights,BankMoneyPerDay FROM guild_rank WHERE guildid = '%u' ORDER BY rid ASC", GuildId);
300 if (!result)
302 sLog.outError("Guild %u has broken `guild_rank` data, creating new...",GuildId);
303 CreateDefaultGuildRanks(0);
304 return true;
307 bool broken_ranks = false;
309 //GUILD RANKS are sequence starting from 0 = GUILD_MASTER (ALL PRIVILEGES) to max 9 (lowest privileges)
310 //the lower rank id is considered higher rank - so promotion does rank-- and demotion does rank++
311 //between ranks in sequence cannot be gaps - so 0,1,2,4 cannot be
312 //min ranks count is 5 and max is 10.
316 fields = result->Fetch();
318 uint32 rankID = fields[0].GetUInt32();
319 std::string rankName = fields[1].GetCppString();
320 uint32 rankRights = fields[2].GetUInt32();
321 uint32 rankMoney = fields[3].GetUInt32();
323 if (rankID != m_Ranks.size()) // guild_rank.ids are sequence 0,1,2,3..
324 broken_ranks = true;
326 //first rank is guildmaster, prevent loss leader rights
327 if (m_Ranks.empty())
328 rankRights |= GR_RIGHT_ALL;
330 AddRank(rankName,rankRights,rankMoney);
331 }while( result->NextRow() );
332 delete result;
334 if (m_Ranks.size() < GUILD_RANKS_MIN_COUNT) // if too few ranks, renew them
336 m_Ranks.clear();
337 sLog.outError("Guild %u has broken `guild_rank` data, creating new...",GuildId);
338 CreateDefaultGuildRanks(0); // 0 is default locale_idx
339 broken_ranks = false;
341 // guild_rank have wrong numbered ranks, repair
342 if (broken_ranks)
344 sLog.outError("Guild %u has broken `guild_rank` data, repairing...",GuildId);
345 CharacterDatabase.BeginTransaction();
346 CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", GuildId);
347 for(size_t i = 0; i < m_Ranks.size(); ++i)
349 std::string name = m_Ranks[i].Name;
350 uint32 rights = m_Ranks[i].Rights;
351 CharacterDatabase.escape_string(name);
352 CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", GuildId, uint32(i), name.c_str(), rights);
354 CharacterDatabase.CommitTransaction();
357 return true;
360 bool Guild::LoadMembersFromDB(uint32 GuildId)
362 // 0 1 2 3 4 5
363 QueryResult *result = CharacterDatabase.PQuery("SELECT guild_member.guid,rank, pnote, offnote, BankResetTimeMoney,BankRemMoney,"
364 // 6 7 8 9 10 11
365 "BankResetTimeTab0, BankRemSlotsTab0, BankResetTimeTab1, BankRemSlotsTab1, BankResetTimeTab2, BankRemSlotsTab2,"
366 // 12 13 14 15 16 17
367 "BankResetTimeTab3, BankRemSlotsTab3, BankResetTimeTab4, BankRemSlotsTab4, BankResetTimeTab5, BankRemSlotsTab5,"
368 // 18 19 20 21 22
369 "characters.name, characters.level, characters.class, characters.zone, characters.logout_time "
370 "FROM guild_member LEFT JOIN characters ON characters.guid = guild_member.guid WHERE guildid = '%u'", GuildId);
372 if (!result)
373 return false;
377 Field *fields = result->Fetch();
378 MemberSlot newmember;
379 uint64 guid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
380 newmember.RankId = fields[1].GetUInt32();
381 //don't allow member to have not existing rank!
382 if (newmember.RankId >= m_Ranks.size())
383 newmember.RankId = GetLowestRank();
385 newmember.Pnote = fields[2].GetCppString();
386 newmember.OFFnote = fields[3].GetCppString();
387 newmember.BankResetTimeMoney = fields[4].GetUInt32();
388 newmember.BankRemMoney = fields[5].GetUInt32();
389 for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
391 newmember.BankResetTimeTab[i] = fields[6+(2*i)].GetUInt32();
392 newmember.BankRemSlotsTab[i] = fields[7+(2*i)].GetUInt32();
395 newmember.Name = fields[18].GetCppString();
396 newmember.Level = fields[19].GetUInt8();
397 newmember.Class = fields[20].GetUInt8();
398 newmember.ZoneId = fields[21].GetUInt32();
399 newmember.LogoutTime = fields[22].GetUInt64();
401 //this code will remove unexisting character guids from guild
402 if (newmember.Level < 1 || newmember.Level > STRONG_MAX_LEVEL) // can be at broken `data` field
404 sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`data`, deleting him from guild!",GUID_LOPART(guid));
405 CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid));
406 continue;
408 if (!newmember.ZoneId)
410 sLog.outError("Player (GUID: %u) has broken zone-data", GUID_LOPART(guid));
411 // here it will also try the same, to get the zone from characters-table, but additional it tries to find
412 // the zone through xy coords .. this is a bit redundant, but shouldn't be called often
413 newmember.ZoneId = Player::GetZoneIdFromDB(guid);
415 if (newmember.Class < CLASS_WARRIOR || newmember.Class >= MAX_CLASSES) // can be at broken `class` field
417 sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`class`, deleting him from guild!",GUID_LOPART(guid));
418 CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid));
419 continue;
422 members[GUID_LOPART(guid)] = newmember;
424 }while( result->NextRow() );
425 delete result;
427 if (members.empty())
428 return false;
430 return true;
433 void Guild::SetMemberStats(uint64 guid)
435 MemberList::iterator itr = members.find(GUID_LOPART(guid));
436 if (itr == members.end() )
437 return;
439 Player *pl = ObjectAccessor::FindPlayer(guid);
440 if (!pl)
441 return;
442 itr->second.Name = pl->GetName();
443 itr->second.Level = pl->getLevel();
444 itr->second.Class = pl->getClass();
445 itr->second.ZoneId = pl->GetZoneId();
448 void Guild::SetLeader(uint64 guid)
450 m_LeaderGuid = guid;
451 ChangeRank(guid, GR_GUILDMASTER);
453 CharacterDatabase.PExecute("UPDATE guild SET leaderguid='%u' WHERE guildid='%u'", GUID_LOPART(guid), m_Id);
456 void Guild::DelMember(uint64 guid, bool isDisbanding)
458 //guild master can be deleted when loading guild and guid doesn't exist in characters table
459 //or when he is removed from guild by gm command
460 if (m_LeaderGuid == guid && !isDisbanding)
462 MemberSlot* oldLeader = NULL;
463 MemberSlot* best = NULL;
464 uint64 newLeaderGUID = 0;
465 for (Guild::MemberList::iterator i = members.begin(); i != members.end(); ++i)
467 if (i->first == GUID_LOPART(guid))
469 oldLeader = &(i->second);
470 continue;
473 if (!best || best->RankId > i->second.RankId)
475 best = &(i->second);
476 newLeaderGUID = i->first;
479 if (!best)
481 Disband();
482 return;
485 SetLeader(newLeaderGUID);
487 // If player not online data in data field will be loaded from guild tabs no need to update it !!
488 if (Player *newLeader = objmgr.GetPlayer(newLeaderGUID))
489 newLeader->SetRank(GR_GUILDMASTER);
491 // when leader non-exist (at guild load with deleted leader only) not send broadcasts
492 if (oldLeader)
494 WorldPacket data(SMSG_GUILD_EVENT, (1+1+(oldLeader->Name).size()+1+(best->Name).size()+1));
495 data << (uint8)GE_LEADER_CHANGED;
496 data << (uint8)2;
497 data << oldLeader->Name;
498 data << best->Name;
499 BroadcastPacket(&data);
501 data.Initialize(SMSG_GUILD_EVENT, (1+1+(oldLeader->Name).size()+1));
502 data << (uint8)GE_LEFT;
503 data << (uint8)1;
504 data << oldLeader->Name;
505 BroadcastPacket(&data);
508 sLog.outDebug( "WORLD: Sent (SMSG_GUILD_EVENT)" );
511 members.erase(GUID_LOPART(guid));
513 Player *player = objmgr.GetPlayer(guid);
514 // If player not online data in data field will be loaded from guild tabs no need to update it !!
515 if (player)
517 player->SetInGuild(0);
518 player->SetRank(0);
521 CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid));
524 void Guild::ChangeRank(uint64 guid, uint32 newRank)
526 MemberList::iterator itr = members.find(GUID_LOPART(guid));
527 if (itr != members.end())
528 itr->second.RankId = newRank;
530 Player *player = objmgr.GetPlayer(guid);
531 // If player not online data in data field will be loaded from guild tabs no need to update it !!
532 if (player)
533 player->SetRank(newRank);
535 CharacterDatabase.PExecute( "UPDATE guild_member SET rank='%u' WHERE guid='%u'", newRank, GUID_LOPART(guid) );
538 void Guild::SetPNOTE(uint64 guid,std::string pnote)
540 MemberList::iterator itr = members.find(GUID_LOPART(guid));
541 if (itr == members.end())
542 return;
544 itr->second.Pnote = pnote;
546 // pnote now can be used for encoding to DB
547 CharacterDatabase.escape_string(pnote);
548 CharacterDatabase.PExecute("UPDATE guild_member SET pnote = '%s' WHERE guid = '%u'", pnote.c_str(), itr->first);
551 void Guild::SetOFFNOTE(uint64 guid,std::string offnote)
553 MemberList::iterator itr = members.find(GUID_LOPART(guid));
554 if (itr == members.end())
555 return;
556 itr->second.OFFnote = offnote;
557 // offnote now can be used for encoding to DB
558 CharacterDatabase.escape_string(offnote);
559 CharacterDatabase.PExecute("UPDATE guild_member SET offnote = '%s' WHERE guid = '%u'", offnote.c_str(), itr->first);
562 void Guild::BroadcastToGuild(WorldSession *session, const std::string& msg, uint32 language)
564 if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(),GR_RIGHT_GCHATSPEAK))
566 WorldPacket data;
567 ChatHandler(session).FillMessageData(&data, CHAT_MSG_GUILD, language, 0, msg.c_str());
569 for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
571 Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
573 if (pl && pl->GetSession() && HasRankRight(pl->GetRank(),GR_RIGHT_GCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow()) )
574 pl->GetSession()->SendPacket(&data);
579 void Guild::BroadcastToOfficers(WorldSession *session, const std::string& msg, uint32 language)
581 if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(),GR_RIGHT_OFFCHATSPEAK))
583 for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
585 WorldPacket data;
586 ChatHandler::FillMessageData(&data, session, CHAT_MSG_OFFICER, language, NULL, 0, msg.c_str(),NULL);
588 Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
590 if (pl && pl->GetSession() && HasRankRight(pl->GetRank(),GR_RIGHT_OFFCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow()))
591 pl->GetSession()->SendPacket(&data);
596 void Guild::BroadcastPacket(WorldPacket *packet)
598 for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
600 Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
601 if (player)
602 player->GetSession()->SendPacket(packet);
606 void Guild::BroadcastPacketToRank(WorldPacket *packet, uint32 rankId)
608 for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
610 if (itr->second.RankId == rankId)
612 Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
613 if (player)
614 player->GetSession()->SendPacket(packet);
619 void Guild::CreateRank(std::string name_,uint32 rights)
621 if (m_Ranks.size() >= GUILD_RANKS_MAX_COUNT)
622 return;
624 // ranks are sequence 0,1,2,... where 0 means guildmaster
625 uint32 new_rank_id = m_Ranks.size();
627 AddRank(name_, rights, 0);
629 //existing records in db should be deleted before calling this procedure and m_PurchasedTabs must be loaded already
631 for (uint32 i = 0; i < m_PurchasedTabs; ++i)
633 //create bank rights with 0
634 CharacterDatabase.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid) VALUES ('%u','%u','%u')", m_Id, i, new_rank_id);
636 // name now can be used for encoding to DB
637 CharacterDatabase.escape_string(name_);
638 CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", m_Id, new_rank_id, name_.c_str(), rights );
641 void Guild::AddRank(const std::string& name_,uint32 rights, uint32 money)
643 m_Ranks.push_back(RankInfo(name_,rights,money));
646 void Guild::DelRank()
648 // client won't allow to have less than GUILD_RANKS_MIN_COUNT ranks in guild
649 if (m_Ranks.size() <= GUILD_RANKS_MIN_COUNT)
650 return;
652 // delete lowest guild_rank
653 uint32 rank = GetLowestRank();
654 CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE rid>='%u' AND guildid='%u'", rank, m_Id);
656 m_Ranks.pop_back();
659 std::string Guild::GetRankName(uint32 rankId)
661 if (rankId >= m_Ranks.size())
662 return "<unknown>";
664 return m_Ranks[rankId].Name;
667 uint32 Guild::GetRankRights(uint32 rankId)
669 if (rankId >= m_Ranks.size())
670 return 0;
672 return m_Ranks[rankId].Rights;
675 void Guild::SetRankName(uint32 rankId, std::string name_)
677 if (rankId >= m_Ranks.size())
678 return;
680 m_Ranks[rankId].Name = name_;
682 // name now can be used for encoding to DB
683 CharacterDatabase.escape_string(name_);
684 CharacterDatabase.PExecute("UPDATE guild_rank SET rname='%s' WHERE rid='%u' AND guildid='%u'", name_.c_str(), rankId, m_Id);
687 void Guild::SetRankRights(uint32 rankId, uint32 rights)
689 if (rankId >= m_Ranks.size())
690 return;
692 m_Ranks[rankId].Rights = rights;
694 CharacterDatabase.PExecute("UPDATE guild_rank SET rights='%u' WHERE rid='%u' AND guildid='%u'", rights, rankId, m_Id);
697 int32 Guild::GetRank(uint32 LowGuid)
699 MemberList::const_iterator itr = members.find(LowGuid);
700 if (itr == members.end())
701 return -1;
703 return itr->second.RankId;
706 void Guild::Disband()
708 WorldPacket data(SMSG_GUILD_EVENT, 1);
709 data << (uint8)GE_DISBANDED;
710 BroadcastPacket(&data);
712 while (!members.empty())
714 MemberList::const_iterator itr = members.begin();
715 DelMember(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER), true);
718 CharacterDatabase.BeginTransaction();
719 CharacterDatabase.PExecute("DELETE FROM guild WHERE guildid = '%u'", m_Id);
720 CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid = '%u'", m_Id);
721 CharacterDatabase.PExecute("DELETE FROM guild_bank_tab WHERE guildid = '%u'", m_Id);
722 // TODO item_instance should be deleted ?
723 CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u'", m_Id);
724 CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u'", m_Id);
725 CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid = '%u'", m_Id);
726 CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid = '%u'", m_Id);
727 CharacterDatabase.CommitTransaction();
728 objmgr.RemoveGuild(m_Id);
731 void Guild::Roster(WorldSession *session /*= NULL*/)
733 // we can only guess size
734 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));
735 data << (uint32)members.size();
736 data << MOTD;
737 data << GINFO;
739 data << (uint32)m_Ranks.size();
740 for (RankList::const_iterator ritr = m_Ranks.begin(); ritr != m_Ranks.end(); ++ritr)
742 data << uint32(ritr->Rights);
743 data << uint32(ritr->BankMoneyPerDay); // count of: withdraw gold(gold/day) Note: in game set gold, in packet set bronze.
744 for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
746 data << uint32(ritr->TabRight[i]); // for TAB_i rights: view tabs = 0x01, deposit items =0x02
747 data << uint32(ritr->TabSlotPerDay[i]); // for TAB_i count of: withdraw items(stack/day)
750 for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
752 if (Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)))
754 data << uint64(pl->GetGUID());
755 data << uint8(1);
756 data << pl->GetName();
757 data << uint32(itr->second.RankId);
758 data << uint8(pl->getLevel());
759 data << uint8(pl->getClass());
760 data << uint8(0); // new 2.4.0
761 data << uint32(pl->GetZoneId());
762 data << itr->second.Pnote;
763 data << itr->second.OFFnote;
765 else
767 data << uint64(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
768 data << uint8(0);
769 data << itr->second.Name;
770 data << uint32(itr->second.RankId);
771 data << uint8(itr->second.Level);
772 data << uint8(itr->second.Class);
773 data << uint8(0); // new 2.4.0
774 data << uint32(itr->second.ZoneId);
775 data << float(float(time(NULL)-itr->second.LogoutTime) / DAY);
776 data << itr->second.Pnote;
777 data << itr->second.OFFnote;
780 if (session)
781 session->SendPacket(&data);
782 else
783 BroadcastPacket(&data);
784 sLog.outDebug( "WORLD: Sent (SMSG_GUILD_ROSTER)" );
787 void Guild::Query(WorldSession *session)
789 WorldPacket data(SMSG_GUILD_QUERY_RESPONSE, (8*32+200));// we can only guess size
791 data << m_Id;
792 data << m_Name;
794 for (size_t i = 0 ; i < 10; ++i) // show always 10 ranks
796 if (i < m_Ranks.size())
797 data << m_Ranks[i].Name;
798 else
799 data << (uint8)0; // null string
802 data << uint32(m_EmblemStyle);
803 data << uint32(m_EmblemColor);
804 data << uint32(m_BorderStyle);
805 data << uint32(m_BorderColor);
806 data << uint32(m_BackgroundColor);
807 data << uint32(0); // something new in WotLK
809 session->SendPacket( &data );
810 sLog.outDebug( "WORLD: Sent (SMSG_GUILD_QUERY_RESPONSE)" );
813 void Guild::SetEmblem(uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor)
815 m_EmblemStyle = emblemStyle;
816 m_EmblemColor = emblemColor;
817 m_BorderStyle = borderStyle;
818 m_BorderColor = borderColor;
819 m_BackgroundColor = backgroundColor;
821 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);
824 void Guild::UpdateLogoutTime(uint64 guid)
826 MemberList::iterator itr = members.find(GUID_LOPART(guid));
827 if (itr == members.end() )
828 return;
830 itr->second.LogoutTime = time(NULL);
832 if (m_OnlineMembers > 0)
833 --m_OnlineMembers;
834 else
836 UnloadGuildBank();
837 UnloadGuildEventLog();
841 // *************************************************
842 // Guild Eventlog part
843 // *************************************************
844 // Display guild eventlog
845 void Guild::DisplayGuildEventLog(WorldSession *session)
847 // Load guild eventlog, if not already done
848 if (!m_EventLogLoaded)
849 LoadGuildEventLogFromDB();
851 // Sending result
852 WorldPacket data(MSG_GUILD_EVENT_LOG_QUERY, 0);
853 // count, max count == 100
854 data << uint8(m_GuildEventLog.size());
855 for (GuildEventLog::const_iterator itr = m_GuildEventLog.begin(); itr != m_GuildEventLog.end(); ++itr)
857 // Event type
858 data << uint8(itr->EventType);
859 // Player 1
860 data << uint64(itr->PlayerGuid1);
861 // Player 2 not for left/join guild events
862 if (itr->EventType != GUILD_EVENT_LOG_JOIN_GUILD && itr->EventType != GUILD_EVENT_LOG_LEAVE_GUILD)
863 data << uint64(itr->PlayerGuid2);
864 // New Rank - only for promote/demote guild events
865 if (itr->EventType == GUILD_EVENT_LOG_PROMOTE_PLAYER || itr->EventType == GUILD_EVENT_LOG_DEMOTE_PLAYER)
866 data << uint8(itr->NewRank);
867 // Event timestamp
868 data << uint32(time(NULL)-itr->TimeStamp);
870 session->SendPacket(&data);
871 sLog.outDebug("WORLD: Sent (MSG_GUILD_EVENT_LOG_QUERY)");
874 // Load guild eventlog from DB
875 void Guild::LoadGuildEventLogFromDB()
877 // Return if already loaded
878 if (m_EventLogLoaded)
879 return;
881 // 0 1 2 3 4 5
882 QueryResult *result = CharacterDatabase.PQuery("SELECT LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp FROM guild_eventlog WHERE guildid=%u ORDER BY TimeStamp DESC,LogGuid DESC LIMIT %u", m_Id, GUILD_EVENTLOG_MAX_RECORDS);
883 if (!result)
884 return;
885 bool isNextLogGuidSet = false;
886 //uint32 configCount = sWorld.getConfig(CONFIG_GUILD_EVENT_LOG_COUNT);
887 // First event in list will be the oldest and the latest event is last event in list
890 Field *fields = result->Fetch();
891 if (!isNextLogGuidSet)
893 m_GuildEventLogNextGuid = fields[0].GetUInt32();
894 isNextLogGuidSet = true;
896 // Fill entry
897 GuildEventLogEntry NewEvent;
898 NewEvent.EventType = fields[1].GetUInt8();
899 NewEvent.PlayerGuid1 = fields[2].GetUInt32();
900 NewEvent.PlayerGuid2 = fields[3].GetUInt32();
901 NewEvent.NewRank = fields[4].GetUInt8();
902 NewEvent.TimeStamp = fields[5].GetUInt64();
904 // There can be a problem if more events have same TimeStamp the ORDER can be broken when fields[0].GetUInt32() == configCount, but
905 // events with same timestamp can appear when there is lag, and we naivly suppose that mangos isn't laggy
906 // but if problem appears, player will see set of guild events that have same timestamp in bad order
908 // Add entry to list
909 m_GuildEventLog.push_front(NewEvent);
911 } while( result->NextRow() );
912 delete result;
914 m_EventLogLoaded = true;
917 // Unload guild eventlog
918 void Guild::UnloadGuildEventLog()
920 if (!m_EventLogLoaded)
921 return;
923 m_GuildEventLog.clear();
924 m_EventLogLoaded = false;
927 // Add entry to guild eventlog
928 void Guild::LogGuildEvent(uint8 EventType, uint32 PlayerGuid1, uint32 PlayerGuid2, uint8 NewRank)
930 GuildEventLogEntry NewEvent;
931 // Create event
932 NewEvent.EventType = EventType;
933 NewEvent.PlayerGuid1 = PlayerGuid1;
934 NewEvent.PlayerGuid2 = PlayerGuid2;
935 NewEvent.NewRank = NewRank;
936 NewEvent.TimeStamp = uint32(time(NULL));
937 // Count new LogGuid
938 m_GuildEventLogNextGuid = (m_GuildEventLogNextGuid + 1) % sWorld.getConfig(CONFIG_GUILD_EVENT_LOG_COUNT);
939 // Check max records limit
940 if (m_GuildEventLog.size() >= GUILD_EVENTLOG_MAX_RECORDS)
941 m_GuildEventLog.pop_front();
942 // Add event to list
943 m_GuildEventLog.push_back(NewEvent);
944 // Save event to DB
945 CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid='%u' AND LogGuid='%u'", m_Id, m_GuildEventLogNextGuid);
946 CharacterDatabase.PExecute("INSERT INTO guild_eventlog (guildid, LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','" UI64FMTD "')",
947 m_Id, m_GuildEventLogNextGuid, uint32(NewEvent.EventType), NewEvent.PlayerGuid1, NewEvent.PlayerGuid2, uint32(NewEvent.NewRank), NewEvent.TimeStamp);
950 // *************************************************
951 // Guild Bank part
952 // *************************************************
953 // Bank content related
954 void Guild::DisplayGuildBankContent(WorldSession *session, uint8 TabId)
956 WorldPacket data(SMSG_GUILD_BANK_LIST,1200);
958 GuildBankTab const* tab = GetBankTab(TabId);
959 if (!tab)
960 return;
962 if (!IsMemberHaveRights(session->GetPlayer()->GetGUIDLow(),TabId,GUILD_BANK_RIGHT_VIEW_TAB))
963 return;
965 data << uint64(GetGuildBankMoney());
966 data << uint8(TabId);
967 // remaining slots for today
968 data << uint32(GetMemberSlotWithdrawRem(session->GetPlayer()->GetGUIDLow(), TabId));
969 data << uint8(0); // Tell client this is a tab content packet
971 data << uint8(GUILD_BANK_MAX_SLOTS);
973 for (int i=0; i<GUILD_BANK_MAX_SLOTS; ++i)
974 AppendDisplayGuildBankSlot(data, tab, i);
976 session->SendPacket(&data);
978 sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
981 void Guild::DisplayGuildBankMoneyUpdate()
983 WorldPacket data(SMSG_GUILD_BANK_LIST, 8+1+4+1+1);
985 data << uint64(GetGuildBankMoney());
986 data << uint8(0); // TabId, default 0
987 data << uint32(0); // slot withdrow, default 0
988 data << uint8(0); // Tell client this is a tab content packet
989 data << uint8(0); // not send items
990 BroadcastPacket(&data);
992 sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
995 void Guild::DisplayGuildBankContentUpdate(uint8 TabId, int32 slot1, int32 slot2)
997 GuildBankTab const* tab = GetBankTab(TabId);
998 if (!tab)
999 return;
1001 WorldPacket data(SMSG_GUILD_BANK_LIST,1200);
1003 data << uint64(GetGuildBankMoney());
1004 data << uint8(TabId);
1005 // remaining slots for today
1007 size_t rempos = data.wpos();
1008 data << uint32(0); // will be filled later
1009 data << uint8(0); // Tell client this is a tab content packet
1011 if (slot2 == -1) // single item in slot1
1013 data << uint8(1);
1015 AppendDisplayGuildBankSlot(data, tab, slot1);
1017 else // 2 items (in slot1 and slot2)
1019 data << uint8(2);
1021 if (slot1 > slot2)
1022 std::swap(slot1,slot2);
1024 AppendDisplayGuildBankSlot(data, tab, slot1);
1025 AppendDisplayGuildBankSlot(data, tab, slot2);
1028 for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
1030 Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
1031 if (!player)
1032 continue;
1034 if (!IsMemberHaveRights(itr->first,TabId,GUILD_BANK_RIGHT_VIEW_TAB))
1035 continue;
1037 data.put<uint32>(rempos,uint32(GetMemberSlotWithdrawRem(player->GetGUIDLow(), TabId)));
1039 player->GetSession()->SendPacket(&data);
1042 sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1045 void Guild::DisplayGuildBankContentUpdate(uint8 TabId, GuildItemPosCountVec const& slots)
1047 GuildBankTab const* tab = GetBankTab(TabId);
1048 if (!tab)
1049 return;
1051 WorldPacket data(SMSG_GUILD_BANK_LIST,1200);
1053 data << uint64(GetGuildBankMoney());
1054 data << uint8(TabId);
1055 // remaining slots for today
1057 size_t rempos = data.wpos();
1058 data << uint32(0); // will be filled later
1059 data << uint8(0); // Tell client this is a tab content packet
1061 data << uint8(slots.size()); // updates count
1063 for (GuildItemPosCountVec::const_iterator itr = slots.begin(); itr != slots.end(); ++itr)
1064 AppendDisplayGuildBankSlot(data, tab, itr->Slot);
1066 for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
1068 Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
1069 if (!player)
1070 continue;
1072 if (!IsMemberHaveRights(itr->first,TabId,GUILD_BANK_RIGHT_VIEW_TAB))
1073 continue;
1075 data.put<uint32>(rempos,uint32(GetMemberSlotWithdrawRem(player->GetGUIDLow(), TabId)));
1077 player->GetSession()->SendPacket(&data);
1080 sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1083 Item* Guild::GetItem(uint8 TabId, uint8 SlotId)
1085 if (TabId >= m_TabListMap.size() || SlotId >= GUILD_BANK_MAX_SLOTS)
1086 return NULL;
1087 return m_TabListMap[TabId]->Slots[SlotId];
1090 // *************************************************
1091 // Tab related
1093 void Guild::DisplayGuildBankTabsInfo(WorldSession *session)
1095 // Time to load bank if not already done
1096 if (!m_GuildBankLoaded)
1097 LoadGuildBankFromDB();
1099 WorldPacket data(SMSG_GUILD_BANK_LIST, 500);
1101 data << uint64(GetGuildBankMoney());
1102 data << uint8(0); // TabInfo packet must be for TabId 0
1103 data << uint32(0xFFFFFFFF); // bit 9 must be set for this packet to work
1104 data << uint8(1); // Tell Client this is a TabInfo packet
1106 data << uint8(m_PurchasedTabs); // here is the number of tabs
1108 for (uint8 i = 0; i < m_PurchasedTabs; ++i)
1110 data << m_TabListMap[i]->Name.c_str();
1111 data << m_TabListMap[i]->Icon.c_str();
1113 data << uint8(0); // Do not send tab content
1114 session->SendPacket(&data);
1116 sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1119 void Guild::CreateNewBankTab()
1121 if (m_PurchasedTabs >= GUILD_BANK_MAX_TABS)
1122 return;
1124 ++m_PurchasedTabs;
1126 GuildBankTab* AnotherTab = new GuildBankTab;
1127 memset(AnotherTab->Slots, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*));
1128 m_TabListMap.resize(m_PurchasedTabs);
1129 m_TabListMap[m_PurchasedTabs-1] = AnotherTab;
1131 CharacterDatabase.BeginTransaction();
1132 CharacterDatabase.PExecute("DELETE FROM guild_bank_tab WHERE guildid='%u' AND TabId='%u'", m_Id, uint32(m_PurchasedTabs-1));
1133 CharacterDatabase.PExecute("INSERT INTO guild_bank_tab (guildid,TabId) VALUES ('%u','%u')", m_Id, uint32(m_PurchasedTabs-1));
1134 CharacterDatabase.CommitTransaction();
1137 void Guild::SetGuildBankTabInfo(uint8 TabId, std::string Name, std::string Icon)
1139 if (TabId >= GUILD_BANK_MAX_TABS)
1140 return;
1141 if (TabId >= m_TabListMap.size())
1142 return;
1144 if (!m_TabListMap[TabId])
1145 return;
1147 if (m_TabListMap[TabId]->Name == Name && m_TabListMap[TabId]->Icon == Icon)
1148 return;
1150 m_TabListMap[TabId]->Name = Name;
1151 m_TabListMap[TabId]->Icon = Icon;
1153 CharacterDatabase.escape_string(Name);
1154 CharacterDatabase.escape_string(Icon);
1155 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));
1158 uint32 Guild::GetBankRights(uint32 rankId, uint8 TabId) const
1160 if (rankId >= m_Ranks.size() || TabId >= GUILD_BANK_MAX_TABS)
1161 return 0;
1163 return m_Ranks[rankId].TabRight[TabId];
1166 // *************************************************
1167 // Guild bank loading/unloading related
1169 // This load should be called when the bank is first accessed by a guild member
1170 void Guild::LoadGuildBankFromDB()
1172 if (m_GuildBankLoaded)
1173 return;
1175 m_GuildBankLoaded = true;
1176 LoadGuildBankEventLogFromDB();
1178 // 0 1 2 3
1179 QueryResult *result = CharacterDatabase.PQuery("SELECT TabId, TabName, TabIcon, TabText FROM guild_bank_tab WHERE guildid='%u' ORDER BY TabId", m_Id);
1180 if (!result)
1182 m_PurchasedTabs = 0;
1183 return;
1186 m_TabListMap.resize(m_PurchasedTabs);
1189 Field *fields = result->Fetch();
1190 uint8 TabId = fields[0].GetUInt8();
1192 GuildBankTab *NewTab = new GuildBankTab;
1193 memset(NewTab->Slots, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*));
1195 NewTab->Name = fields[1].GetCppString();
1196 NewTab->Icon = fields[2].GetCppString();
1197 NewTab->Text = fields[3].GetCppString();
1199 m_TabListMap[TabId] = NewTab;
1200 } while (result->NextRow());
1202 delete result;
1204 // data needs to be at first place for Item::LoadFromDB
1205 // 0 1 2 3 4
1206 result = CharacterDatabase.PQuery("SELECT data, TabId, SlotId, item_guid, item_entry FROM guild_bank_item JOIN item_instance ON item_guid = guid WHERE guildid='%u' ORDER BY TabId", m_Id);
1207 if (!result)
1208 return;
1212 Field *fields = result->Fetch();
1213 uint8 TabId = fields[1].GetUInt8();
1214 uint8 SlotId = fields[2].GetUInt8();
1215 uint32 ItemGuid = fields[3].GetUInt32();
1216 uint32 ItemEntry = fields[4].GetUInt32();
1218 if (TabId >= m_PurchasedTabs || TabId >= GUILD_BANK_MAX_TABS)
1220 sLog.outError( "Guild::LoadGuildBankFromDB: Invalid tab for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry);
1221 continue;
1224 if (SlotId >= GUILD_BANK_MAX_SLOTS)
1226 sLog.outError( "Guild::LoadGuildBankFromDB: Invalid slot for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry);
1227 continue;
1230 ItemPrototype const *proto = objmgr.GetItemPrototype(ItemEntry);
1232 if (!proto)
1234 sLog.outError( "Guild::LoadGuildBankFromDB: Unknown item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry);
1235 continue;
1238 Item *pItem = NewItemOrBag(proto);
1239 if (!pItem->LoadFromDB(ItemGuid, 0, result))
1241 CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'", m_Id, uint32(TabId), uint32(SlotId));
1242 sLog.outError("Item GUID %u not found in item_instance, deleting from Guild Bank!", ItemGuid);
1243 delete pItem;
1244 continue;
1247 pItem->AddToWorld();
1248 m_TabListMap[TabId]->Slots[SlotId] = pItem;
1249 } while (result->NextRow());
1251 delete result;
1254 // This unload should be called when the last member of the guild gets offline
1255 void Guild::UnloadGuildBank()
1257 if (!m_GuildBankLoaded)
1258 return;
1259 for (uint8 i = 0 ; i < m_PurchasedTabs ; ++i )
1261 for (uint8 j = 0 ; j < GUILD_BANK_MAX_SLOTS ; ++j)
1263 if (m_TabListMap[i]->Slots[j])
1265 m_TabListMap[i]->Slots[j]->RemoveFromWorld();
1266 delete m_TabListMap[i]->Slots[j];
1269 delete m_TabListMap[i];
1271 m_TabListMap.clear();
1273 UnloadGuildBankEventLog();
1274 m_GuildBankLoaded = false;
1277 // *************************************************
1278 // Money deposit/withdraw related
1280 void Guild::SendMoneyInfo(WorldSession *session, uint32 LowGuid)
1282 WorldPacket data(MSG_GUILD_BANK_MONEY_WITHDRAWN, 4);
1283 data << uint32(GetMemberMoneyWithdrawRem(LowGuid));
1284 session->SendPacket(&data);
1285 sLog.outDebug("WORLD: Sent MSG_GUILD_BANK_MONEY_WITHDRAWN");
1288 bool Guild::MemberMoneyWithdraw(uint32 amount, uint32 LowGuid)
1290 uint32 MoneyWithDrawRight = GetMemberMoneyWithdrawRem(LowGuid);
1292 if (MoneyWithDrawRight < amount || GetGuildBankMoney() < amount)
1293 return false;
1295 SetBankMoney(GetGuildBankMoney()-amount);
1297 if (MoneyWithDrawRight < WITHDRAW_MONEY_UNLIMITED)
1299 MemberList::iterator itr = members.find(LowGuid);
1300 if (itr == members.end() )
1301 return false;
1302 itr->second.BankRemMoney -= amount;
1303 CharacterDatabase.PExecute("UPDATE guild_member SET BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'",
1304 itr->second.BankRemMoney, m_Id, LowGuid);
1306 return true;
1309 void Guild::SetBankMoney(int64 money)
1311 if (money < 0) // I don't know how this happens, it does!!
1312 money = 0;
1313 m_GuildBankMoney = money;
1315 CharacterDatabase.PExecute("UPDATE guild SET BankMoney='" UI64FMTD "' WHERE guildid='%u'", money, m_Id);
1318 // *************************************************
1319 // Item per day and money per day related
1321 bool Guild::MemberItemWithdraw(uint8 TabId, uint32 LowGuid)
1323 uint32 SlotsWithDrawRight = GetMemberSlotWithdrawRem(LowGuid, TabId);
1325 if (SlotsWithDrawRight == 0)
1326 return false;
1328 if (SlotsWithDrawRight < WITHDRAW_SLOT_UNLIMITED)
1330 MemberList::iterator itr = members.find(LowGuid);
1331 if (itr == members.end() )
1332 return false;
1333 --itr->second.BankRemSlotsTab[TabId];
1334 CharacterDatabase.PExecute("UPDATE guild_member SET BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'",
1335 uint32(TabId), itr->second.BankRemSlotsTab[TabId], m_Id, LowGuid);
1337 return true;
1340 bool Guild::IsMemberHaveRights(uint32 LowGuid, uint8 TabId, uint32 rights) const
1342 MemberList::const_iterator itr = members.find(LowGuid);
1343 if (itr == members.end() )
1344 return false;
1346 if (itr->second.RankId == GR_GUILDMASTER)
1347 return true;
1349 return (GetBankRights(itr->second.RankId,TabId) & rights)==rights;
1352 uint32 Guild::GetMemberSlotWithdrawRem(uint32 LowGuid, uint8 TabId)
1354 MemberList::iterator itr = members.find(LowGuid);
1355 if (itr == members.end() )
1356 return 0;
1358 if (itr->second.RankId == GR_GUILDMASTER)
1359 return WITHDRAW_SLOT_UNLIMITED;
1361 if ((GetBankRights(itr->second.RankId,TabId) & GUILD_BANK_RIGHT_VIEW_TAB)!=GUILD_BANK_RIGHT_VIEW_TAB)
1362 return 0;
1364 uint32 curTime = uint32(time(NULL)/MINUTE);
1365 if (curTime - itr->second.BankResetTimeTab[TabId] >= 24*HOUR/MINUTE)
1367 itr->second.BankResetTimeTab[TabId] = curTime;
1368 itr->second.BankRemSlotsTab[TabId] = GetBankSlotPerDay(itr->second.RankId, TabId);
1369 CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeTab%u='%u',BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'",
1370 uint32(TabId), itr->second.BankResetTimeTab[TabId], uint32(TabId), itr->second.BankRemSlotsTab[TabId], m_Id, LowGuid);
1372 return itr->second.BankRemSlotsTab[TabId];
1375 uint32 Guild::GetMemberMoneyWithdrawRem(uint32 LowGuid)
1377 MemberList::iterator itr = members.find(LowGuid);
1378 if (itr == members.end() )
1379 return 0;
1381 if (itr->second.RankId == GR_GUILDMASTER)
1382 return WITHDRAW_MONEY_UNLIMITED;
1384 uint32 curTime = uint32(time(NULL)/MINUTE); // minutes
1385 // 24 hours
1386 if (curTime > itr->second.BankResetTimeMoney + 24*HOUR/MINUTE)
1388 itr->second.BankResetTimeMoney = curTime;
1389 itr->second.BankRemMoney = GetBankMoneyPerDay(itr->second.RankId);
1390 CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeMoney='%u',BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'",
1391 itr->second.BankResetTimeMoney, itr->second.BankRemMoney, m_Id, LowGuid);
1393 return itr->second.BankRemMoney;
1396 void Guild::SetBankMoneyPerDay(uint32 rankId, uint32 money)
1398 if (rankId >= m_Ranks.size())
1399 return;
1401 if (rankId == GR_GUILDMASTER)
1402 money = WITHDRAW_MONEY_UNLIMITED;
1404 m_Ranks[rankId].BankMoneyPerDay = money;
1406 for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
1407 if (itr->second.RankId == rankId)
1408 itr->second.BankResetTimeMoney = 0;
1410 CharacterDatabase.PExecute("UPDATE guild_rank SET BankMoneyPerDay='%u' WHERE rid='%u' AND guildid='%u'", money, rankId, m_Id);
1411 CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeMoney='0' WHERE guildid='%u' AND rank='%u'", m_Id, rankId);
1414 void Guild::SetBankRightsAndSlots(uint32 rankId, uint8 TabId, uint32 right, uint32 nbSlots, bool db)
1416 if (rankId >= m_Ranks.size() ||
1417 TabId >= GUILD_BANK_MAX_TABS ||
1418 TabId >= m_PurchasedTabs)
1419 return;
1421 if (rankId == GR_GUILDMASTER)
1423 nbSlots = WITHDRAW_SLOT_UNLIMITED;
1424 right = GUILD_BANK_RIGHT_FULL;
1427 m_Ranks[rankId].TabSlotPerDay[TabId] = nbSlots;
1428 m_Ranks[rankId].TabRight[TabId] = right;
1430 if (db)
1432 for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
1433 if (itr->second.RankId == rankId)
1434 for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
1435 itr->second.BankResetTimeTab[i] = 0;
1437 CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid='%u' AND TabId='%u' AND rid='%u'", m_Id, uint32(TabId), rankId);
1438 CharacterDatabase.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid,gbright,SlotPerDay) VALUES "
1439 "('%u','%u','%u','%u','%u')", m_Id, uint32(TabId), rankId, m_Ranks[rankId].TabRight[TabId], m_Ranks[rankId].TabSlotPerDay[TabId]);
1440 CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeTab%u='0' WHERE guildid='%u' AND rank='%u'", uint32(TabId), m_Id, rankId);
1444 uint32 Guild::GetBankMoneyPerDay(uint32 rankId)
1446 if (rankId >= m_Ranks.size())
1447 return 0;
1449 if (rankId == GR_GUILDMASTER)
1450 return WITHDRAW_MONEY_UNLIMITED;
1451 return m_Ranks[rankId].BankMoneyPerDay;
1454 uint32 Guild::GetBankSlotPerDay(uint32 rankId, uint8 TabId)
1456 if (rankId >= m_Ranks.size() || TabId >= GUILD_BANK_MAX_TABS)
1457 return 0;
1459 if (rankId == GR_GUILDMASTER)
1460 return WITHDRAW_SLOT_UNLIMITED;
1461 return m_Ranks[rankId].TabSlotPerDay[TabId];
1464 // *************************************************
1465 // Rights per day related
1467 void Guild::LoadBankRightsFromDB(uint32 GuildId)
1469 // 0 1 2 3
1470 QueryResult *result = CharacterDatabase.PQuery("SELECT TabId, rid, gbright, SlotPerDay FROM guild_bank_right WHERE guildid = '%u' ORDER BY TabId", GuildId);
1472 if (!result)
1473 return;
1477 Field *fields = result->Fetch();
1478 uint8 TabId = fields[0].GetUInt8();
1479 uint32 rankId = fields[1].GetUInt32();
1480 uint16 right = fields[2].GetUInt16();
1481 uint16 SlotPerDay = fields[3].GetUInt16();
1483 SetBankRightsAndSlots(rankId, TabId, right, SlotPerDay, false);
1485 } while (result->NextRow());
1486 delete result;
1488 return;
1491 // *************************************************
1492 // Bank log related
1494 void Guild::LoadGuildBankEventLogFromDB()
1496 // Money log is in TabId = GUILD_BANK_MONEY_LOGS_TAB
1498 //uint32 configCount = sWorld.getConfig(CONFIG_GUILD_BANK_EVENT_LOG_COUNT);
1499 //cycle through all purchased guild bank item tabs
1500 for (uint32 tabId = 0; tabId < m_PurchasedTabs; tabId++)
1502 // 0 1 2 3 4 5 6
1503 QueryResult *result = CharacterDatabase.PQuery("SELECT LogGuid, EventType, PlayerGuid, ItemOrMoney, ItemStackCount, DestTabId, TimeStamp FROM guild_bank_eventlog WHERE guildid='%u' AND TabId='%u' ORDER BY TimeStamp DESC,LogGuid DESC LIMIT %u", m_Id, tabId, GUILD_BANK_MAX_LOGS);
1504 if (!result)
1505 continue;
1507 bool isNextLogGuidSet = false;
1510 Field *fields = result->Fetch();
1512 GuildBankEventLogEntry NewEvent;
1513 NewEvent.EventType = fields[1].GetUInt8();
1514 NewEvent.PlayerGuid = fields[2].GetUInt32();
1515 NewEvent.ItemOrMoney = fields[3].GetUInt32();
1516 NewEvent.ItemStackCount = fields[4].GetUInt8();
1517 NewEvent.DestTabId = fields[5].GetUInt8();
1518 NewEvent.TimeStamp = fields[6].GetUInt64();
1520 //if newEvent is moneyEvent, move it to moneyEventTab in DB and report error
1521 if (NewEvent.isMoneyEvent())
1523 uint32 logGuid = fields[0].GetUInt32();
1524 CharacterDatabase.PExecute("UPDATE guild_bank_eventlog SET TabId='%u' WHERE guildid='%u' AND TabId='%u' AND LogGuid='%u'", GUILD_BANK_MONEY_LOGS_TAB, m_Id, tabId, logGuid);
1525 sLog.outError("GuildBankEventLog ERROR: MoneyEvent LogGuid %u for Guild %u had incorrectly set its TabId to %u, correcting it to %u TabId", logGuid, m_Id, tabId, GUILD_BANK_MONEY_LOGS_TAB);
1526 continue;
1528 else
1529 //add event to list
1530 //events are ordered from oldest (in beginning) to latest (in the end)
1531 m_GuildBankEventLog_Item[tabId].push_front(NewEvent);
1533 if (!isNextLogGuidSet)
1535 m_GuildBankEventLogNextGuid_Item[tabId] = fields[0].GetUInt32();
1536 //we don't have to do m_GuildBankEventLogNextGuid_Item[tabId] %= configCount; - it will be done when creating new record
1537 isNextLogGuidSet = true;
1539 } while (result->NextRow());
1540 delete result;
1543 //special handle for guild bank money log
1544 // 0 1 2 3 4 5 6
1545 QueryResult *result = CharacterDatabase.PQuery("SELECT LogGuid, EventType, PlayerGuid, ItemOrMoney, ItemStackCount, DestTabId, TimeStamp FROM guild_bank_eventlog WHERE guildid='%u' AND TabId='%u' ORDER BY TimeStamp DESC,LogGuid DESC LIMIT %u", m_Id, GUILD_BANK_MONEY_LOGS_TAB, GUILD_BANK_MAX_LOGS);
1546 if (!result)
1547 return;
1549 bool isNextMoneyLogGuidSet = false;
1552 Field *fields = result->Fetch();
1553 if (!isNextMoneyLogGuidSet)
1555 m_GuildBankEventLogNextGuid_Money = fields[0].GetUInt32();
1556 //we don't have to do m_GuildBankEventLogNextGuid_Money %= configCount; - it will be done when creating new record
1557 isNextMoneyLogGuidSet = true;
1559 GuildBankEventLogEntry NewEvent;
1561 NewEvent.EventType = fields[1].GetUInt8();
1562 NewEvent.PlayerGuid = fields[2].GetUInt32();
1563 NewEvent.ItemOrMoney = fields[3].GetUInt32();
1564 NewEvent.ItemStackCount = fields[4].GetUInt8();
1565 NewEvent.DestTabId = fields[5].GetUInt8();
1566 NewEvent.TimeStamp = fields[6].GetUInt64();
1568 //if newEvent is not moneyEvent, then report error
1569 if (!NewEvent.isMoneyEvent())
1570 sLog.outError("GuildBankEventLog ERROR: MoneyEvent LogGuid %u for Guild %u is not MoneyEvent - ignoring...", fields[0].GetUInt32(), m_Id);
1571 else
1572 //add event to list
1573 //events are ordered from oldest (in beginning) to latest (in the end)
1574 m_GuildBankEventLog_Money.push_front(NewEvent);
1576 } while (result->NextRow());
1577 delete result;
1580 void Guild::UnloadGuildBankEventLog()
1582 m_GuildBankEventLog_Money.clear();
1584 for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
1585 m_GuildBankEventLog_Item[i].clear();
1588 void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId)
1590 if (TabId > GUILD_BANK_MAX_TABS)
1591 return;
1593 if (TabId == GUILD_BANK_MAX_TABS)
1595 // Here we display money logs
1596 WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, m_GuildBankEventLog_Money.size()*(4*4+1)+1+1);
1597 data << uint8(TabId); // Here GUILD_BANK_MAX_TABS
1598 data << uint8(m_GuildBankEventLog_Money.size()); // number of log entries
1599 for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Money.begin(); itr != m_GuildBankEventLog_Money.end(); ++itr)
1601 data << uint8(itr->EventType);
1602 data << uint64(MAKE_NEW_GUID(itr->PlayerGuid,0,HIGHGUID_PLAYER));
1603 if (itr->EventType == GUILD_BANK_LOG_DEPOSIT_MONEY ||
1604 itr->EventType == GUILD_BANK_LOG_WITHDRAW_MONEY ||
1605 itr->EventType == GUILD_BANK_LOG_REPAIR_MONEY ||
1606 itr->EventType == GUILD_BANK_LOG_UNK1 ||
1607 itr->EventType == GUILD_BANK_LOG_UNK2)
1609 data << uint32(itr->ItemOrMoney);
1611 else
1613 data << uint32(itr->ItemOrMoney);
1614 data << uint32(itr->ItemStackCount);
1615 if (itr->EventType == GUILD_BANK_LOG_MOVE_ITEM || itr->EventType == GUILD_BANK_LOG_MOVE_ITEM2)
1616 data << uint8(itr->DestTabId); // moved tab
1618 data << uint32(time(NULL) - itr->TimeStamp);
1620 session->SendPacket(&data);
1622 else
1624 // here we display current tab logs
1625 WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, m_GuildBankEventLog_Item[TabId].size()*(4*4+1+1)+1+1);
1626 data << uint8(TabId); // Here a real Tab Id
1627 // number of log entries
1628 data << uint8(m_GuildBankEventLog_Item[TabId].size());
1629 for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Item[TabId].begin(); itr != m_GuildBankEventLog_Item[TabId].end(); ++itr)
1631 data << uint8(itr->EventType);
1632 data << uint64(MAKE_NEW_GUID(itr->PlayerGuid,0,HIGHGUID_PLAYER));
1633 if (itr->EventType == GUILD_BANK_LOG_DEPOSIT_MONEY ||
1634 itr->EventType == GUILD_BANK_LOG_WITHDRAW_MONEY ||
1635 itr->EventType == GUILD_BANK_LOG_REPAIR_MONEY ||
1636 itr->EventType == GUILD_BANK_LOG_UNK1 ||
1637 itr->EventType == GUILD_BANK_LOG_UNK2)
1639 data << uint32(itr->ItemOrMoney);
1641 else
1643 data << uint32(itr->ItemOrMoney);
1644 data << uint32(itr->ItemStackCount);
1645 if (itr->EventType == GUILD_BANK_LOG_MOVE_ITEM || itr->EventType == GUILD_BANK_LOG_MOVE_ITEM2)
1646 data << uint8(itr->DestTabId); // moved tab
1648 data << uint32(time(NULL) - itr->TimeStamp);
1650 session->SendPacket(&data);
1652 sLog.outDebug("WORLD: Sent (MSG_GUILD_BANK_LOG_QUERY)");
1655 void Guild::LogBankEvent(uint8 EventType, uint8 TabId, uint32 PlayerGuidLow, uint32 ItemOrMoney, uint8 ItemStackCount, uint8 DestTabId)
1657 //create Event
1658 GuildBankEventLogEntry NewEvent;
1659 NewEvent.EventType = EventType;
1660 NewEvent.PlayerGuid = PlayerGuidLow;
1661 NewEvent.ItemOrMoney = ItemOrMoney;
1662 NewEvent.ItemStackCount = ItemStackCount;
1663 NewEvent.DestTabId = DestTabId;
1664 NewEvent.TimeStamp = uint32(time(NULL));
1666 //add new event to the end of event list
1667 uint32 currentTabId = TabId;
1668 uint32 currentLogGuid = 0;
1669 if (NewEvent.isMoneyEvent())
1671 m_GuildBankEventLogNextGuid_Money = (m_GuildBankEventLogNextGuid_Money + 1) % sWorld.getConfig(CONFIG_GUILD_BANK_EVENT_LOG_COUNT);
1672 currentLogGuid = m_GuildBankEventLogNextGuid_Money;
1673 currentTabId = GUILD_BANK_MONEY_LOGS_TAB;
1674 if (m_GuildBankEventLog_Money.size() >= GUILD_BANK_MAX_LOGS)
1675 m_GuildBankEventLog_Money.pop_front();
1677 m_GuildBankEventLog_Money.push_back(NewEvent);
1679 else
1681 m_GuildBankEventLogNextGuid_Item[TabId] = ((m_GuildBankEventLogNextGuid_Item[TabId]) + 1) % sWorld.getConfig(CONFIG_GUILD_BANK_EVENT_LOG_COUNT);
1682 currentLogGuid = m_GuildBankEventLogNextGuid_Item[TabId];
1683 if (m_GuildBankEventLog_Item[TabId].size() >= GUILD_BANK_MAX_LOGS)
1684 m_GuildBankEventLog_Item[TabId].pop_front();
1686 m_GuildBankEventLog_Item[TabId].push_back(NewEvent);
1689 //save event to database
1690 CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u' AND TabId='%u'", m_Id, currentLogGuid, currentTabId);
1692 CharacterDatabase.PExecute("INSERT INTO guild_bank_eventlog (guildid,LogGuid,TabId,EventType,PlayerGuid,ItemOrMoney,ItemStackCount,DestTabId,TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','%u','%u','" UI64FMTD "')",
1693 m_Id, currentLogGuid, currentTabId, uint32(NewEvent.EventType), NewEvent.PlayerGuid, NewEvent.ItemOrMoney, uint32(NewEvent.ItemStackCount), uint32(NewEvent.DestTabId), NewEvent.TimeStamp);
1696 bool Guild::AddGBankItemToDB(uint32 GuildId, uint32 BankTab , uint32 BankTabSlot , uint32 GUIDLow, uint32 Entry )
1698 CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u' AND TabId = '%u'AND SlotId = '%u'", GuildId, BankTab, BankTabSlot);
1699 CharacterDatabase.PExecute("INSERT INTO guild_bank_item (guildid,TabId,SlotId,item_guid,item_entry) "
1700 "VALUES ('%u', '%u', '%u', '%u', '%u')", GuildId, BankTab, BankTabSlot, GUIDLow, Entry);
1701 return true;
1704 void Guild::AppendDisplayGuildBankSlot( WorldPacket& data, GuildBankTab const *tab, int slot )
1706 Item *pItem = tab->Slots[slot];
1707 uint32 entry = pItem ? pItem->GetEntry() : 0;
1709 data << uint8(slot);
1710 data << uint32(entry);
1711 if (entry)
1713 // random item property id +8
1714 data << (uint32) pItem->GetItemRandomPropertyId();
1715 if (pItem->GetItemRandomPropertyId())
1716 // SuffixFactor +4
1717 data << (uint32) pItem->GetItemSuffixFactor();
1718 // +12 // ITEM_FIELD_STACK_COUNT
1719 data << uint32(pItem->GetCount());
1720 data << uint32(0); // +16 // Unknown value
1721 data << uint8(0); // unknown 2.4.2
1722 if (uint32 Enchant0 = pItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT))
1724 data << uint8(1); // number of enchantments (max 3) why max 3?
1725 data << uint8(PERM_ENCHANTMENT_SLOT); // enchantment slot (range: 0:2)
1726 data << uint32(Enchant0); // enchantment id
1728 else
1729 data << uint8(0); // no enchantments (0)
1733 Item* Guild::StoreItem(uint8 tabId, GuildItemPosCountVec const& dest, Item* pItem )
1735 if (!pItem)
1736 return NULL;
1738 Item* lastItem = pItem;
1740 for (GuildItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); )
1742 uint8 slot = itr->Slot;
1743 uint32 count = itr->Count;
1745 ++itr;
1747 if (itr == dest.end())
1749 lastItem = _StoreItem(tabId,slot,pItem,count,false);
1750 break;
1753 lastItem = _StoreItem(tabId,slot,pItem,count,true);
1756 return lastItem;
1759 // Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
1760 Item* Guild::_StoreItem( uint8 tab, uint8 slot, Item *pItem, uint32 count, bool clone )
1762 if (!pItem)
1763 return NULL;
1765 sLog.outDebug( "GUILD STORAGE: StoreItem tab = %u, slot = %u, item = %u, count = %u", tab, slot, pItem->GetEntry(), count);
1767 Item* pItem2 = m_TabListMap[tab]->Slots[slot];
1769 if (!pItem2)
1771 if (clone)
1772 pItem = pItem->CloneItem(count);
1773 else
1774 pItem->SetCount(count);
1776 if (!pItem)
1777 return NULL;
1779 m_TabListMap[tab]->Slots[slot] = pItem;
1781 pItem->SetUInt64Value(ITEM_FIELD_CONTAINED, 0);
1782 pItem->SetUInt64Value(ITEM_FIELD_OWNER, 0);
1783 AddGBankItemToDB(GetId(), tab, slot, pItem->GetGUIDLow(), pItem->GetEntry());
1784 pItem->FSetState(ITEM_NEW);
1785 pItem->SaveToDB(); // not in onventory and can be save standalone
1787 return pItem;
1789 else
1791 pItem2->SetCount( pItem2->GetCount() + count );
1792 pItem2->FSetState(ITEM_CHANGED);
1793 pItem2->SaveToDB(); // not in onventory and can be save standalone
1795 if (!clone)
1797 pItem->RemoveFromWorld();
1798 pItem->DeleteFromDB();
1799 delete pItem;
1802 return pItem2;
1806 void Guild::RemoveItem(uint8 tab, uint8 slot )
1808 m_TabListMap[tab]->Slots[slot] = NULL;
1809 CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'",
1810 GetId(), uint32(tab), uint32(slot));
1813 uint8 Guild::_CanStoreItem_InSpecificSlot( uint8 tab, uint8 slot, GuildItemPosCountVec &dest, uint32& count, bool swap, Item* pSrcItem ) const
1815 Item* pItem2 = m_TabListMap[tab]->Slots[slot];
1817 // ignore move item (this slot will be empty at move)
1818 if (pItem2 == pSrcItem)
1819 pItem2 = NULL;
1821 uint32 need_space;
1823 // empty specific slot - check item fit to slot
1824 if (!pItem2 || swap)
1826 // non empty stack with space
1827 need_space = pSrcItem->GetMaxStackCount();
1829 // non empty slot, check item type
1830 else
1832 // check item type
1833 if (pItem2->GetEntry() != pSrcItem->GetEntry())
1834 return EQUIP_ERR_ITEM_CANT_STACK;
1836 // check free space
1837 if (pItem2->GetCount() >= pSrcItem->GetMaxStackCount())
1838 return EQUIP_ERR_ITEM_CANT_STACK;
1840 need_space = pSrcItem->GetMaxStackCount() - pItem2->GetCount();
1843 if (need_space > count)
1844 need_space = count;
1846 GuildItemPosCount newPosition = GuildItemPosCount(slot,need_space);
1847 if (!newPosition.isContainedIn(dest))
1849 dest.push_back(newPosition);
1850 count -= need_space;
1853 return EQUIP_ERR_OK;
1856 uint8 Guild::_CanStoreItem_InTab( uint8 tab, GuildItemPosCountVec &dest, uint32& count, bool merge, Item* pSrcItem, uint8 skip_slot ) const
1858 for (uint32 j = 0; j < GUILD_BANK_MAX_SLOTS; j++)
1860 // skip specific slot already processed in first called _CanStoreItem_InSpecificSlot
1861 if (j == skip_slot)
1862 continue;
1864 Item* pItem2 = m_TabListMap[tab]->Slots[j];
1866 // ignore move item (this slot will be empty at move)
1867 if (pItem2 == pSrcItem)
1868 pItem2 = NULL;
1870 // if merge skip empty, if !merge skip non-empty
1871 if ((pItem2 != NULL) != merge)
1872 continue;
1874 if (pItem2)
1876 if (pItem2->GetEntry() == pSrcItem->GetEntry() && pItem2->GetCount() < pSrcItem->GetMaxStackCount())
1878 uint32 need_space = pSrcItem->GetMaxStackCount() - pItem2->GetCount();
1879 if (need_space > count)
1880 need_space = count;
1882 GuildItemPosCount newPosition = GuildItemPosCount(j,need_space);
1883 if (!newPosition.isContainedIn(dest))
1885 dest.push_back(newPosition);
1886 count -= need_space;
1888 if (count == 0)
1889 return EQUIP_ERR_OK;
1893 else
1895 uint32 need_space = pSrcItem->GetMaxStackCount();
1896 if (need_space > count)
1897 need_space = count;
1899 GuildItemPosCount newPosition = GuildItemPosCount(j,need_space);
1900 if (!newPosition.isContainedIn(dest))
1902 dest.push_back(newPosition);
1903 count -= need_space;
1905 if (count == 0)
1906 return EQUIP_ERR_OK;
1910 return EQUIP_ERR_OK;
1913 uint8 Guild::CanStoreItem( uint8 tab, uint8 slot, GuildItemPosCountVec &dest, uint32 count, Item *pItem, bool swap ) const
1915 sLog.outDebug( "GUILD STORAGE: CanStoreItem tab = %u, slot = %u, item = %u, count = %u", tab, slot, pItem->GetEntry(), count);
1917 if (count > pItem->GetCount())
1918 return EQUIP_ERR_COULDNT_SPLIT_ITEMS;
1920 if (pItem->IsSoulBound())
1921 return EQUIP_ERR_CANT_DROP_SOULBOUND;
1923 // in specific slot
1924 if (slot != NULL_SLOT)
1926 uint8 res = _CanStoreItem_InSpecificSlot(tab,slot,dest,count,swap,pItem);
1927 if (res != EQUIP_ERR_OK)
1928 return res;
1930 if (count == 0)
1931 return EQUIP_ERR_OK;
1934 // not specific slot or have spece for partly store only in specific slot
1936 // search stack in tab for merge to
1937 if (pItem->GetMaxStackCount() > 1)
1939 uint8 res = _CanStoreItem_InTab(tab,dest,count,true,pItem,slot);
1940 if (res != EQUIP_ERR_OK)
1941 return res;
1943 if (count == 0)
1944 return EQUIP_ERR_OK;
1947 // search free slot in bag for place to
1948 uint8 res = _CanStoreItem_InTab(tab,dest,count,false,pItem,slot);
1949 if (res != EQUIP_ERR_OK)
1950 return res;
1952 if (count == 0)
1953 return EQUIP_ERR_OK;
1955 return EQUIP_ERR_BANK_FULL;
1958 void Guild::SetGuildBankTabText(uint8 TabId, std::string text)
1960 if (TabId >= GUILD_BANK_MAX_TABS)
1961 return;
1962 if (TabId >= m_TabListMap.size())
1963 return;
1964 if (!m_TabListMap[TabId])
1965 return;
1967 if (m_TabListMap[TabId]->Text == text)
1968 return;
1970 utf8truncate(text,500); // DB and client size limitation
1972 m_TabListMap[TabId]->Text = text;
1974 CharacterDatabase.escape_string(text);
1975 CharacterDatabase.PExecute("UPDATE guild_bank_tab SET TabText='%s' WHERE guildid='%u' AND TabId='%u'", text.c_str(), m_Id, uint32(TabId));
1977 // announce
1978 SendGuildBankTabText(NULL,TabId);
1981 void Guild::SendGuildBankTabText(WorldSession *session, uint8 TabId)
1983 if (TabId > GUILD_BANK_MAX_TABS)
1984 return;
1986 GuildBankTab const *tab = GetBankTab(TabId);
1987 if (!tab)
1988 return;
1990 WorldPacket data(MSG_QUERY_GUILD_BANK_TEXT, 1+tab->Text.size()+1);
1991 data << uint8(TabId);
1992 data << tab->Text;
1994 if (session)
1995 session->SendPacket(&data);
1996 else
1997 BroadcastPacket(&data);
2000 void Guild::SwapItems(Player * pl, uint8 BankTab, uint8 BankTabSlot, uint8 BankTabDst, uint8 BankTabSlotDst, uint32 SplitedAmount )
2002 // empty operation
2003 if (BankTab == BankTabDst && BankTabSlot == BankTabSlotDst)
2004 return;
2006 Item *pItemSrc = GetItem(BankTab, BankTabSlot);
2007 if (!pItemSrc) // may prevent crash
2008 return;
2010 if (SplitedAmount > pItemSrc->GetCount())
2011 return; // cheating?
2012 else if (SplitedAmount == pItemSrc->GetCount())
2013 SplitedAmount = 0; // no split
2015 Item *pItemDst = GetItem(BankTabDst, BankTabSlotDst);
2017 if (BankTab != BankTabDst)
2019 // check dest pos rights (if different tabs)
2020 if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTabDst, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
2021 return;
2023 // check source pos rights (if different tabs)
2024 uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab);
2025 if (remRight <= 0)
2026 return;
2029 if (SplitedAmount)
2030 { // Bank -> Bank item split (in empty or non empty slot
2031 GuildItemPosCountVec dest;
2032 uint8 msg = CanStoreItem(BankTabDst,BankTabSlotDst,dest,SplitedAmount,pItemSrc,false);
2033 if (msg != EQUIP_ERR_OK)
2035 pl->SendEquipError( msg, pItemSrc, NULL );
2036 return;
2039 Item *pNewItem = pItemSrc->CloneItem( SplitedAmount );
2040 if (!pNewItem)
2042 pl->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pItemSrc, NULL );
2043 return;
2046 CharacterDatabase.BeginTransaction();
2047 LogBankEvent(GUILD_BANK_LOG_MOVE_ITEM, BankTab, pl->GetGUIDLow(), pItemSrc->GetEntry(), SplitedAmount, BankTabDst);
2049 pl->ItemRemovedQuestCheck( pItemSrc->GetEntry(), SplitedAmount );
2050 pItemSrc->SetCount( pItemSrc->GetCount() - SplitedAmount );
2051 pItemSrc->FSetState(ITEM_CHANGED);
2052 pItemSrc->SaveToDB(); // not in inventory and can be save standalone
2053 StoreItem(BankTabDst,dest,pNewItem);
2054 CharacterDatabase.CommitTransaction();
2056 else // non split
2058 GuildItemPosCountVec gDest;
2059 uint8 msg = CanStoreItem(BankTabDst,BankTabSlotDst,gDest,pItemSrc->GetCount(),pItemSrc,false);
2060 if (msg == EQUIP_ERR_OK) // merge to
2062 CharacterDatabase.BeginTransaction();
2063 LogBankEvent(GUILD_BANK_LOG_MOVE_ITEM, BankTab, pl->GetGUIDLow(), pItemSrc->GetEntry(), pItemSrc->GetCount(), BankTabDst);
2065 RemoveItem(BankTab, BankTabSlot);
2066 StoreItem(BankTabDst, gDest, pItemSrc);
2067 CharacterDatabase.CommitTransaction();
2069 else // swap
2071 gDest.clear();
2072 msg = CanStoreItem(BankTabDst,BankTabSlotDst,gDest,pItemSrc->GetCount(),pItemSrc,true);
2073 if (msg != EQUIP_ERR_OK)
2075 pl->SendEquipError( msg, pItemSrc, NULL );
2076 return;
2079 GuildItemPosCountVec gSrc;
2080 msg = CanStoreItem(BankTab,BankTabSlot,gSrc,pItemDst->GetCount(),pItemDst,true);
2081 if (msg != EQUIP_ERR_OK)
2083 pl->SendEquipError( msg, pItemDst, NULL );
2084 return;
2087 if (BankTab != BankTabDst)
2089 // check source pos rights (item swapped to src)
2090 if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTab, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
2091 return;
2093 // check dest pos rights (item swapped to src)
2094 uint32 remRightDst = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTabDst);
2095 if (remRightDst <= 0)
2096 return;
2099 CharacterDatabase.BeginTransaction();
2100 LogBankEvent(GUILD_BANK_LOG_MOVE_ITEM, BankTab, pl->GetGUIDLow(), pItemSrc->GetEntry(), pItemSrc->GetCount(), BankTabDst);
2101 LogBankEvent(GUILD_BANK_LOG_MOVE_ITEM, BankTabDst, pl->GetGUIDLow(), pItemDst->GetEntry(), pItemDst->GetCount(), BankTab);
2103 RemoveItem(BankTab, BankTabSlot);
2104 RemoveItem(BankTabDst, BankTabSlotDst);
2105 StoreItem(BankTab, gSrc, pItemDst);
2106 StoreItem(BankTabDst, gDest, pItemSrc);
2107 CharacterDatabase.CommitTransaction();
2110 DisplayGuildBankContentUpdate(BankTab,BankTabSlot,BankTab == BankTabDst ? BankTabSlotDst : -1);
2111 if (BankTab != BankTabDst)
2112 DisplayGuildBankContentUpdate(BankTabDst,BankTabSlotDst);
2116 void Guild::MoveFromBankToChar( Player * pl, uint8 BankTab, uint8 BankTabSlot, uint8 PlayerBag, uint8 PlayerSlot, uint32 SplitedAmount)
2118 Item *pItemBank = GetItem(BankTab, BankTabSlot);
2119 Item *pItemChar = pl->GetItemByPos(PlayerBag, PlayerSlot);
2121 if (!pItemBank) // Problem to get bank item
2122 return;
2124 if (SplitedAmount > pItemBank->GetCount())
2125 return; // cheating?
2126 else if (SplitedAmount == pItemBank->GetCount())
2127 SplitedAmount = 0; // no split
2129 if (SplitedAmount)
2130 { // Bank -> Char split to slot (patly move)
2131 Item *pNewItem = pItemBank->CloneItem( SplitedAmount );
2132 if (!pNewItem)
2134 pl->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pItemBank, NULL );
2135 return;
2138 ItemPosCountVec dest;
2139 uint8 msg = pl->CanStoreItem(PlayerBag, PlayerSlot, dest, pNewItem, false);
2140 if (msg != EQUIP_ERR_OK)
2142 pl->SendEquipError( msg, pNewItem, NULL );
2143 delete pNewItem;
2144 return;
2147 // check source pos rights (item moved to inventory)
2148 uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab);
2149 if (remRight <= 0)
2151 delete pNewItem;
2152 return;
2155 CharacterDatabase.BeginTransaction();
2156 LogBankEvent(GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), SplitedAmount);
2158 pItemBank->SetCount(pItemBank->GetCount()-SplitedAmount);
2159 pItemBank->FSetState(ITEM_CHANGED);
2160 pItemBank->SaveToDB(); // not in inventory and can be save standalone
2161 pl->MoveItemToInventory(dest,pNewItem,true);
2162 pl->SaveInventoryAndGoldToDB();
2164 MemberItemWithdraw(BankTab, pl->GetGUIDLow());
2165 CharacterDatabase.CommitTransaction();
2167 else // Bank -> Char swap with slot (move)
2169 ItemPosCountVec dest;
2170 uint8 msg = pl->CanStoreItem(PlayerBag, PlayerSlot, dest, pItemBank, false);
2171 if (msg == EQUIP_ERR_OK) // merge case
2173 // check source pos rights (item moved to inventory)
2174 uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab);
2175 if (remRight <= 0)
2176 return;
2178 CharacterDatabase.BeginTransaction();
2179 LogBankEvent(GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), pItemBank->GetCount());
2181 RemoveItem(BankTab, BankTabSlot);
2182 pl->MoveItemToInventory(dest,pItemBank,true);
2183 pl->SaveInventoryAndGoldToDB();
2185 MemberItemWithdraw(BankTab, pl->GetGUIDLow());
2186 CharacterDatabase.CommitTransaction();
2188 else // Bank <-> Char swap items
2190 // check source pos rights (item swapped to bank)
2191 if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTab, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
2192 return;
2194 if (pItemChar)
2196 if (!pItemChar->CanBeTraded())
2198 pl->SendEquipError( EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, pItemChar, NULL );
2199 return;
2203 ItemPosCountVec iDest;
2204 msg = pl->CanStoreItem(PlayerBag, PlayerSlot, iDest, pItemBank, true);
2205 if (msg != EQUIP_ERR_OK)
2207 pl->SendEquipError( msg, pItemBank, NULL );
2208 return;
2211 GuildItemPosCountVec gDest;
2212 if (pItemChar)
2214 msg = CanStoreItem(BankTab,BankTabSlot,gDest,pItemChar->GetCount(),pItemChar,true);
2215 if (msg != EQUIP_ERR_OK)
2217 pl->SendEquipError( msg, pItemChar, NULL );
2218 return;
2222 // check source pos rights (item moved to inventory)
2223 uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab);
2224 if (remRight <= 0)
2225 return;
2227 if (pItemChar)
2229 // logging item move to bank
2230 if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
2232 sLog.outCommand(pl->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
2233 pl->GetName(),pl->GetSession()->GetAccountId(),
2234 pItemChar->GetProto()->Name1,pItemChar->GetEntry(),pItemChar->GetCount(),
2235 m_Id);
2239 CharacterDatabase.BeginTransaction();
2240 LogBankEvent(GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), pItemBank->GetCount());
2241 if (pItemChar)
2242 LogBankEvent(GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), pItemChar->GetCount());
2244 RemoveItem(BankTab, BankTabSlot);
2245 if (pItemChar)
2247 pl->MoveItemFromInventory(PlayerBag, PlayerSlot, true);
2248 pItemChar->DeleteFromInventoryDB();
2251 if (pItemChar)
2252 StoreItem(BankTab, gDest, pItemChar);
2253 pl->MoveItemToInventory(iDest,pItemBank,true);
2254 pl->SaveInventoryAndGoldToDB();
2256 MemberItemWithdraw(BankTab, pl->GetGUIDLow());
2257 CharacterDatabase.CommitTransaction();
2260 DisplayGuildBankContentUpdate(BankTab,BankTabSlot);
2264 void Guild::MoveFromCharToBank( Player * pl, uint8 PlayerBag, uint8 PlayerSlot, uint8 BankTab, uint8 BankTabSlot, uint32 SplitedAmount )
2266 Item *pItemBank = GetItem(BankTab, BankTabSlot);
2267 Item *pItemChar = pl->GetItemByPos(PlayerBag, PlayerSlot);
2269 if (!pItemChar) // Problem to get item from player
2270 return;
2272 if (!pItemChar->CanBeTraded())
2274 pl->SendEquipError( EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, pItemChar, NULL );
2275 return;
2278 // check source pos rights (item moved to bank)
2279 if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTab, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
2280 return;
2282 if (SplitedAmount > pItemChar->GetCount())
2283 return; // cheating?
2284 else if (SplitedAmount == pItemChar->GetCount())
2285 SplitedAmount = 0; // no split
2287 if (SplitedAmount)
2288 { // Char -> Bank split to empty or non-empty slot (partly move)
2289 GuildItemPosCountVec dest;
2290 uint8 msg = CanStoreItem(BankTab,BankTabSlot,dest,SplitedAmount,pItemChar,false);
2291 if (msg != EQUIP_ERR_OK)
2293 pl->SendEquipError( msg, pItemChar, NULL );
2294 return;
2297 Item *pNewItem = pItemChar->CloneItem( SplitedAmount );
2298 if (!pNewItem)
2300 pl->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pItemChar, NULL );
2301 return;
2304 // logging item move to bank (before items merge
2305 if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
2307 sLog.outCommand(pl->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
2308 pl->GetName(),pl->GetSession()->GetAccountId(),
2309 pItemChar->GetProto()->Name1,pItemChar->GetEntry(),SplitedAmount,m_Id);
2312 CharacterDatabase.BeginTransaction();
2313 LogBankEvent(GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), SplitedAmount);
2315 pl->ItemRemovedQuestCheck( pItemChar->GetEntry(), SplitedAmount );
2316 pItemChar->SetCount(pItemChar->GetCount()-SplitedAmount);
2317 pItemChar->SetState(ITEM_CHANGED);
2318 pl->SaveInventoryAndGoldToDB();
2319 StoreItem(BankTab, dest, pNewItem);
2320 CharacterDatabase.CommitTransaction();
2322 DisplayGuildBankContentUpdate(BankTab,dest);
2324 else // Char -> Bank swap with empty or non-empty (move)
2326 GuildItemPosCountVec dest;
2327 uint8 msg = CanStoreItem(BankTab,BankTabSlot,dest,pItemChar->GetCount(),pItemChar,false);
2328 if (msg == EQUIP_ERR_OK) // merge
2330 // logging item move to bank
2331 if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
2333 sLog.outCommand(pl->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
2334 pl->GetName(),pl->GetSession()->GetAccountId(),
2335 pItemChar->GetProto()->Name1,pItemChar->GetEntry(),pItemChar->GetCount(),
2336 m_Id);
2339 CharacterDatabase.BeginTransaction();
2340 LogBankEvent(GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), pItemChar->GetCount());
2342 pl->MoveItemFromInventory(PlayerBag, PlayerSlot, true);
2343 pItemChar->DeleteFromInventoryDB();
2345 StoreItem(BankTab,dest,pItemChar);
2346 pl->SaveInventoryAndGoldToDB();
2347 CharacterDatabase.CommitTransaction();
2349 DisplayGuildBankContentUpdate(BankTab,dest);
2351 else // Char <-> Bank swap items (posible NULL bank item)
2353 ItemPosCountVec iDest;
2354 if (pItemBank)
2356 msg = pl->CanStoreItem(PlayerBag, PlayerSlot, iDest, pItemBank, true);
2357 if (msg != EQUIP_ERR_OK)
2359 pl->SendEquipError( msg, pItemBank, NULL );
2360 return;
2364 GuildItemPosCountVec gDest;
2365 msg = CanStoreItem(BankTab,BankTabSlot,gDest,pItemChar->GetCount(),pItemChar,true);
2366 if (msg != EQUIP_ERR_OK)
2368 pl->SendEquipError( msg, pItemChar, NULL );
2369 return;
2372 if (pItemBank)
2374 // check bank pos rights (item swapped with inventory)
2375 uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab);
2376 if (remRight <= 0)
2377 return;
2380 // logging item move to bank
2381 if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
2383 sLog.outCommand(pl->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
2384 pl->GetName(),pl->GetSession()->GetAccountId(),
2385 pItemChar->GetProto()->Name1,pItemChar->GetEntry(),pItemChar->GetCount(),
2386 m_Id);
2389 CharacterDatabase.BeginTransaction();
2390 if (pItemBank)
2391 LogBankEvent(GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), pItemBank->GetCount());
2392 LogBankEvent(GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), pItemChar->GetCount());
2394 pl->MoveItemFromInventory(PlayerBag, PlayerSlot, true);
2395 pItemChar->DeleteFromInventoryDB();
2396 if (pItemBank)
2397 RemoveItem(BankTab, BankTabSlot);
2399 StoreItem(BankTab,gDest,pItemChar);
2400 if (pItemBank)
2401 pl->MoveItemToInventory(iDest,pItemBank,true);
2402 pl->SaveInventoryAndGoldToDB();
2403 if (pItemBank)
2404 MemberItemWithdraw(BankTab, pl->GetGUIDLow());
2405 CharacterDatabase.CommitTransaction();
2407 DisplayGuildBankContentUpdate(BankTab,gDest);
2412 bool GuildItemPosCount::isContainedIn(GuildItemPosCountVec const &vec) const
2414 for(GuildItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end();++itr)
2415 if (itr->Slot == this->Slot)
2416 return true;
2418 return false;