[9033] Fixed percent mana regneration from spell 53228 and ranks buff.
[getmangos.git] / src / game / Guild.cpp
blobb7bed38849999315d831a1ac47f2a5cb14f59b5e
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 (sObjectMgr.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 = sObjectMgr.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(sObjectMgr.GetMangosString(LANG_GUILD_MASTER, locale_idx), GR_RIGHT_ALL);
111 CreateRank(sObjectMgr.GetMangosString(LANG_GUILD_OFFICER, locale_idx), GR_RIGHT_ALL);
112 CreateRank(sObjectMgr.GetMangosString(LANG_GUILD_VETERAN, locale_idx), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
113 CreateRank(sObjectMgr.GetMangosString(LANG_GUILD_MEMBER, locale_idx), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
114 CreateRank(sObjectMgr.GetMangosString(LANG_GUILD_INITIATE, locale_idx), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
116 SetBankMoneyPerDay((uint32)GR_GUILDMASTER, WITHDRAW_MONEY_UNLIMITED);
119 bool Guild::AddMember(uint64 plGuid, uint32 plRank)
121 Player* pl = sObjectMgr.GetPlayer(plGuid);
122 if (pl)
124 if (pl->GetGuildId() != 0)
125 return false;
127 else
129 if (Player::GetGuildIdFromDB(plGuid) != 0) // player already in guild
130 return false;
133 // remove all player signs from another petitions
134 // this will be prevent attempt joining player to many guilds and corrupt guild data integrity
135 Player::RemovePetitionsAndSigns(plGuid, 9);
137 // fill player data
138 MemberSlot newmember;
140 if (pl)
142 newmember.Name = pl->GetName();
143 newmember.Level = pl->getLevel();
144 newmember.Class = pl->getClass();
145 newmember.ZoneId = pl->GetZoneId();
147 else
149 // 0 1 2 3
150 QueryResult *result = CharacterDatabase.PQuery("SELECT name,level,class,zone FROM characters WHERE guid = '%u'", GUID_LOPART(plGuid));
151 if (!result)
152 return false; // player doesn't exist
154 Field *fields = result->Fetch();
155 newmember.Name = fields[0].GetCppString();
156 newmember.Level = fields[1].GetUInt8();
157 newmember.Class = fields[2].GetUInt8();
158 newmember.ZoneId = fields[3].GetUInt32();
159 delete result;
160 if (newmember.Level < 1 || newmember.Level > STRONG_MAX_LEVEL ||
161 newmember.Class < CLASS_WARRIOR || newmember.Class >= MAX_CLASSES)
163 sLog.outError("Player (GUID: %u) has a broken data in field `characters` table, cannot add him to guild.",GUID_LOPART(plGuid));
164 return false;
168 newmember.RankId = plRank;
169 newmember.OFFnote = (std::string)"";
170 newmember.Pnote = (std::string)"";
171 newmember.LogoutTime = time(NULL);
172 newmember.BankResetTimeMoney = 0; // this will force update at first query
173 for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
174 newmember.BankResetTimeTab[i] = 0;
175 members[GUID_LOPART(plGuid)] = newmember;
177 std::string dbPnote = newmember.Pnote;
178 std::string dbOFFnote = newmember.OFFnote;
179 CharacterDatabase.escape_string(dbPnote);
180 CharacterDatabase.escape_string(dbOFFnote);
182 CharacterDatabase.PExecute("INSERT INTO guild_member (guildid,guid,rank,pnote,offnote) VALUES ('%u', '%u', '%u','%s','%s')",
183 m_Id, GUID_LOPART(plGuid), newmember.RankId, dbPnote.c_str(), dbOFFnote.c_str());
185 // If player not in game data in data field will be loaded from guild tables, no need to update it!!
186 if (pl)
188 pl->SetInGuild(m_Id);
189 pl->SetRank(newmember.RankId);
190 pl->SetGuildIdInvited(0);
192 return true;
195 void Guild::SetMOTD(std::string motd)
197 MOTD = motd;
199 // motd now can be used for encoding to DB
200 CharacterDatabase.escape_string(motd);
201 CharacterDatabase.PExecute("UPDATE guild SET motd='%s' WHERE guildid='%u'", motd.c_str(), m_Id);
204 void Guild::SetGINFO(std::string ginfo)
206 GINFO = ginfo;
208 // ginfo now can be used for encoding to DB
209 CharacterDatabase.escape_string(ginfo);
210 CharacterDatabase.PExecute("UPDATE guild SET info='%s' WHERE guildid='%u'", ginfo.c_str(), m_Id);
213 bool Guild::LoadGuildFromDB(QueryResult *guildDataResult)
215 if (!guildDataResult)
216 return false;
218 Field *fields = guildDataResult->Fetch();
220 m_Id = fields[0].GetUInt32();
221 m_Name = fields[1].GetCppString();
222 m_LeaderGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER);
223 m_EmblemStyle = fields[3].GetUInt32();
224 m_EmblemColor = fields[4].GetUInt32();
225 m_BorderStyle = fields[5].GetUInt32();
226 m_BorderColor = fields[6].GetUInt32();
227 m_BackgroundColor = fields[7].GetUInt32();
228 GINFO = fields[8].GetCppString();
229 MOTD = fields[9].GetCppString();
230 time_t time = fields[10].GetUInt64();
231 m_GuildBankMoney = fields[11].GetUInt64();
232 m_PurchasedTabs = fields[12].GetUInt32();
234 if (m_PurchasedTabs > GUILD_BANK_MAX_TABS)
235 m_PurchasedTabs = GUILD_BANK_MAX_TABS;
237 if (time > 0)
239 tm local = *(localtime(&time)); // dereference and assign
240 m_CreatedDay = local.tm_mday;
241 m_CreatedMonth = local.tm_mon + 1;
242 m_CreatedYear = local.tm_year + 1900;
245 return true;
248 bool Guild::CheckGuildStructure()
250 // Repair the structure of guild
251 // If the guildmaster doesn't exist or isn't the member of guild
252 // attempt to promote another member
253 int32 GM_rights = GetRank(GUID_LOPART(m_LeaderGuid));
254 if (GM_rights == -1)
256 DelMember(m_LeaderGuid);
257 // check no members case (disbanded)
258 if (members.empty())
259 return false;
261 else if (GM_rights != GR_GUILDMASTER)
262 SetLeader(m_LeaderGuid);
264 // Allow only 1 guildmaster
265 for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
267 if (itr->second.RankId == GR_GUILDMASTER && GUID_LOPART(m_LeaderGuid) != itr->first)
268 //set right of member to officer
269 ChangeRank(itr->first, GR_OFFICER);
272 return true;
275 bool Guild::LoadRanksFromDB(QueryResult *guildRanksResult)
277 if (!guildRanksResult)
279 sLog.outError("Guild %u has broken `guild_rank` data, creating new...",m_Id);
280 CreateDefaultGuildRanks(0);
281 return true;
284 Field *fields;
285 bool broken_ranks = false;
287 //GUILD RANKS are sequence starting from 0 = GUILD_MASTER (ALL PRIVILEGES) to max 9 (lowest privileges)
288 //the lower rank id is considered higher rank - so promotion does rank-- and demotion does rank++
289 //between ranks in sequence cannot be gaps - so 0,1,2,4 cannot be
290 //min ranks count is 5 and max is 10.
294 fields = guildRanksResult->Fetch();
295 //condition that would be true when all ranks in QueryResult will be processed and guild without ranks is being processed
296 if (!fields)
297 break;
299 uint32 guildId = fields[0].GetUInt32();
300 if (guildId < m_Id)
302 //there is in table guild_rank record which doesn't have guildid in guild table, report error
303 sLog.outErrorDb("Guild %u does not exist but it has a record in guild_rank table, deleting it!", guildId);
304 CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid = '%u'", guildId);
305 continue;
308 if (guildId > m_Id)
309 //we loaded all ranks for this guild already, break cycle
310 break;
311 uint32 rankID = fields[1].GetUInt32();
312 std::string rankName = fields[2].GetCppString();
313 uint32 rankRights = fields[3].GetUInt32();
314 uint32 rankMoney = fields[4].GetUInt32();
316 if (rankID != m_Ranks.size()) // guild_rank.ids are sequence 0,1,2,3..
317 broken_ranks = true;
319 //first rank is guildmaster, prevent loss leader rights
320 if (m_Ranks.empty())
321 rankRights |= GR_RIGHT_ALL;
323 AddRank(rankName,rankRights,rankMoney);
324 }while( guildRanksResult->NextRow() );
326 if (m_Ranks.size() < GUILD_RANKS_MIN_COUNT) // if too few ranks, renew them
328 m_Ranks.clear();
329 sLog.outError("Guild %u has broken `guild_rank` data, creating new...", m_Id);
330 CreateDefaultGuildRanks(0); // 0 is default locale_idx
331 broken_ranks = false;
333 // guild_rank have wrong numbered ranks, repair
334 if (broken_ranks)
336 sLog.outError("Guild %u has broken `guild_rank` data, repairing...", m_Id);
337 CharacterDatabase.BeginTransaction();
338 CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", m_Id);
339 for(size_t i = 0; i < m_Ranks.size(); ++i)
341 std::string name = m_Ranks[i].Name;
342 uint32 rights = m_Ranks[i].Rights;
343 CharacterDatabase.escape_string(name);
344 CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", m_Id, uint32(i), name.c_str(), rights);
346 CharacterDatabase.CommitTransaction();
349 return true;
352 bool Guild::LoadMembersFromDB(QueryResult *guildMembersResult)
354 if (!guildMembersResult)
355 return false;
359 Field *fields = guildMembersResult->Fetch();
360 //this condition will be true when all rows in QueryResult are processed and new guild without members is going to be loaded - prevent crash
361 if (!fields)
362 break;
363 uint32 guildId = fields[0].GetUInt32();
364 if (guildId < m_Id)
366 //there is in table guild_member record which doesn't have guildid in guild table, report error
367 sLog.outErrorDb("Guild %u does not exist but it has a record in guild_member table, deleting it!", guildId);
368 CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guildid = '%u'", guildId);
369 continue;
372 if (guildId > m_Id)
373 //we loaded all members for this guild already, break cycle
374 break;
376 MemberSlot newmember;
377 uint64 guid = MAKE_NEW_GUID(fields[1].GetUInt32(), 0, HIGHGUID_PLAYER);
378 newmember.RankId = fields[2].GetUInt32();
379 //don't allow member to have not existing rank!
380 if (newmember.RankId >= m_Ranks.size())
381 newmember.RankId = GetLowestRank();
383 newmember.Pnote = fields[3].GetCppString();
384 newmember.OFFnote = fields[4].GetCppString();
385 newmember.BankResetTimeMoney = fields[5].GetUInt32();
386 newmember.BankRemMoney = fields[6].GetUInt32();
387 for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
389 newmember.BankResetTimeTab[i] = fields[7+(2*i)].GetUInt32();
390 newmember.BankRemSlotsTab[i] = fields[8+(2*i)].GetUInt32();
393 newmember.Name = fields[19].GetCppString();
394 newmember.Level = fields[20].GetUInt8();
395 newmember.Class = fields[21].GetUInt8();
396 newmember.ZoneId = fields[22].GetUInt32();
397 newmember.LogoutTime = fields[23].GetUInt64();
399 //this code will remove unexisting character guids from guild
400 if (newmember.Level < 1 || newmember.Level > STRONG_MAX_LEVEL) // can be at broken `data` field
402 sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`data`, deleting him from guild!",GUID_LOPART(guid));
403 CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid));
404 continue;
406 if (!newmember.ZoneId)
408 sLog.outError("Player (GUID: %u) has broken zone-data", GUID_LOPART(guid));
409 // here it will also try the same, to get the zone from characters-table, but additional it tries to find
410 // the zone through xy coords .. this is a bit redundant, but shouldn't be called often
411 newmember.ZoneId = Player::GetZoneIdFromDB(guid);
413 if (newmember.Class < CLASS_WARRIOR || newmember.Class >= MAX_CLASSES) // can be at broken `class` field
415 sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`class`, deleting him from guild!",GUID_LOPART(guid));
416 CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid));
417 continue;
420 members[GUID_LOPART(guid)] = newmember;
422 }while (guildMembersResult->NextRow());
424 if (members.empty())
425 return false;
427 return true;
430 void Guild::SetMemberStats(uint64 guid)
432 MemberList::iterator itr = members.find(GUID_LOPART(guid));
433 if (itr == members.end() )
434 return;
436 Player *pl = ObjectAccessor::FindPlayer(guid);
437 if (!pl)
438 return;
439 itr->second.Name = pl->GetName();
440 itr->second.Level = pl->getLevel();
441 itr->second.Class = pl->getClass();
442 itr->second.ZoneId = pl->GetZoneId();
445 void Guild::SetLeader(uint64 guid)
447 m_LeaderGuid = guid;
448 ChangeRank(guid, GR_GUILDMASTER);
450 CharacterDatabase.PExecute("UPDATE guild SET leaderguid='%u' WHERE guildid='%u'", GUID_LOPART(guid), m_Id);
453 void Guild::DelMember(uint64 guid, bool isDisbanding)
455 //guild master can be deleted when loading guild and guid doesn't exist in characters table
456 //or when he is removed from guild by gm command
457 if (m_LeaderGuid == guid && !isDisbanding)
459 MemberSlot* oldLeader = NULL;
460 MemberSlot* best = NULL;
461 uint64 newLeaderGUID = 0;
462 for (Guild::MemberList::iterator i = members.begin(); i != members.end(); ++i)
464 if (i->first == GUID_LOPART(guid))
466 oldLeader = &(i->second);
467 continue;
470 if (!best || best->RankId > i->second.RankId)
472 best = &(i->second);
473 newLeaderGUID = i->first;
476 if (!best)
478 Disband();
479 return;
482 SetLeader(newLeaderGUID);
484 // If player not online data in data field will be loaded from guild tabs no need to update it !!
485 if (Player *newLeader = sObjectMgr.GetPlayer(newLeaderGUID))
486 newLeader->SetRank(GR_GUILDMASTER);
488 // when leader non-exist (at guild load with deleted leader only) not send broadcasts
489 if (oldLeader)
491 WorldPacket data(SMSG_GUILD_EVENT, (1+1+(oldLeader->Name).size()+1+(best->Name).size()+1));
492 data << (uint8)GE_LEADER_CHANGED;
493 data << (uint8)2;
494 data << oldLeader->Name;
495 data << best->Name;
496 BroadcastPacket(&data);
498 data.Initialize(SMSG_GUILD_EVENT, (1+1+(oldLeader->Name).size()+1));
499 data << (uint8)GE_LEFT;
500 data << (uint8)1;
501 data << oldLeader->Name;
502 BroadcastPacket(&data);
505 sLog.outDebug( "WORLD: Sent (SMSG_GUILD_EVENT)" );
508 members.erase(GUID_LOPART(guid));
510 Player *player = sObjectMgr.GetPlayer(guid);
511 // If player not online data in data field will be loaded from guild tabs no need to update it !!
512 if (player)
514 player->SetInGuild(0);
515 player->SetRank(0);
518 CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid));
521 void Guild::ChangeRank(uint64 guid, uint32 newRank)
523 MemberList::iterator itr = members.find(GUID_LOPART(guid));
524 if (itr != members.end())
525 itr->second.RankId = newRank;
527 Player *player = sObjectMgr.GetPlayer(guid);
528 // If player not online data in data field will be loaded from guild tabs no need to update it !!
529 if (player)
530 player->SetRank(newRank);
532 CharacterDatabase.PExecute( "UPDATE guild_member SET rank='%u' WHERE guid='%u'", newRank, GUID_LOPART(guid) );
535 void Guild::SetPNOTE(uint64 guid,std::string pnote)
537 MemberList::iterator itr = members.find(GUID_LOPART(guid));
538 if (itr == members.end())
539 return;
541 itr->second.Pnote = pnote;
543 // pnote now can be used for encoding to DB
544 CharacterDatabase.escape_string(pnote);
545 CharacterDatabase.PExecute("UPDATE guild_member SET pnote = '%s' WHERE guid = '%u'", pnote.c_str(), itr->first);
548 void Guild::SetOFFNOTE(uint64 guid,std::string offnote)
550 MemberList::iterator itr = members.find(GUID_LOPART(guid));
551 if (itr == members.end())
552 return;
553 itr->second.OFFnote = offnote;
554 // offnote now can be used for encoding to DB
555 CharacterDatabase.escape_string(offnote);
556 CharacterDatabase.PExecute("UPDATE guild_member SET offnote = '%s' WHERE guid = '%u'", offnote.c_str(), itr->first);
559 void Guild::BroadcastToGuild(WorldSession *session, const std::string& msg, uint32 language)
561 if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(),GR_RIGHT_GCHATSPEAK))
563 WorldPacket data;
564 ChatHandler(session).FillMessageData(&data, CHAT_MSG_GUILD, language, 0, msg.c_str());
566 for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
568 Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
570 if (pl && pl->GetSession() && HasRankRight(pl->GetRank(),GR_RIGHT_GCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow()) )
571 pl->GetSession()->SendPacket(&data);
576 void Guild::BroadcastToOfficers(WorldSession *session, const std::string& msg, uint32 language)
578 if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(),GR_RIGHT_OFFCHATSPEAK))
580 for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
582 WorldPacket data;
583 ChatHandler::FillMessageData(&data, session, CHAT_MSG_OFFICER, language, NULL, 0, msg.c_str(),NULL);
585 Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
587 if (pl && pl->GetSession() && HasRankRight(pl->GetRank(),GR_RIGHT_OFFCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow()))
588 pl->GetSession()->SendPacket(&data);
593 void Guild::BroadcastPacket(WorldPacket *packet)
595 for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
597 Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
598 if (player)
599 player->GetSession()->SendPacket(packet);
603 void Guild::BroadcastPacketToRank(WorldPacket *packet, uint32 rankId)
605 for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
607 if (itr->second.RankId == rankId)
609 Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
610 if (player)
611 player->GetSession()->SendPacket(packet);
616 void Guild::CreateRank(std::string name_,uint32 rights)
618 if (m_Ranks.size() >= GUILD_RANKS_MAX_COUNT)
619 return;
621 // ranks are sequence 0,1,2,... where 0 means guildmaster
622 uint32 new_rank_id = m_Ranks.size();
624 AddRank(name_, rights, 0);
626 //existing records in db should be deleted before calling this procedure and m_PurchasedTabs must be loaded already
628 for (uint32 i = 0; i < m_PurchasedTabs; ++i)
630 //create bank rights with 0
631 CharacterDatabase.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid) VALUES ('%u','%u','%u')", m_Id, i, new_rank_id);
633 // name now can be used for encoding to DB
634 CharacterDatabase.escape_string(name_);
635 CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", m_Id, new_rank_id, name_.c_str(), rights );
638 void Guild::AddRank(const std::string& name_,uint32 rights, uint32 money)
640 m_Ranks.push_back(RankInfo(name_,rights,money));
643 void Guild::DelRank()
645 // client won't allow to have less than GUILD_RANKS_MIN_COUNT ranks in guild
646 if (m_Ranks.size() <= GUILD_RANKS_MIN_COUNT)
647 return;
649 // delete lowest guild_rank
650 uint32 rank = GetLowestRank();
651 CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE rid>='%u' AND guildid='%u'", rank, m_Id);
652 CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE rid>='%u' AND guildid='%u'", rank, m_Id);
654 m_Ranks.pop_back();
657 std::string Guild::GetRankName(uint32 rankId)
659 if (rankId >= m_Ranks.size())
660 return "<unknown>";
662 return m_Ranks[rankId].Name;
665 uint32 Guild::GetRankRights(uint32 rankId)
667 if (rankId >= m_Ranks.size())
668 return 0;
670 return m_Ranks[rankId].Rights;
673 void Guild::SetRankName(uint32 rankId, std::string name_)
675 if (rankId >= m_Ranks.size())
676 return;
678 m_Ranks[rankId].Name = name_;
680 // name now can be used for encoding to DB
681 CharacterDatabase.escape_string(name_);
682 CharacterDatabase.PExecute("UPDATE guild_rank SET rname='%s' WHERE rid='%u' AND guildid='%u'", name_.c_str(), rankId, m_Id);
685 void Guild::SetRankRights(uint32 rankId, uint32 rights)
687 if (rankId >= m_Ranks.size())
688 return;
690 m_Ranks[rankId].Rights = rights;
692 CharacterDatabase.PExecute("UPDATE guild_rank SET rights='%u' WHERE rid='%u' AND guildid='%u'", rights, rankId, m_Id);
695 int32 Guild::GetRank(uint32 LowGuid)
697 MemberList::const_iterator itr = members.find(LowGuid);
698 if (itr == members.end())
699 return -1;
701 return itr->second.RankId;
704 void Guild::Disband()
706 WorldPacket data(SMSG_GUILD_EVENT, 1);
707 data << (uint8)GE_DISBANDED;
708 BroadcastPacket(&data);
710 while (!members.empty())
712 MemberList::const_iterator itr = members.begin();
713 DelMember(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER), true);
716 CharacterDatabase.BeginTransaction();
717 CharacterDatabase.PExecute("DELETE FROM guild WHERE guildid = '%u'", m_Id);
718 CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid = '%u'", m_Id);
719 CharacterDatabase.PExecute("DELETE FROM guild_bank_tab WHERE guildid = '%u'", m_Id);
720 // TODO item_instance should be deleted ?
721 CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u'", m_Id);
722 CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u'", m_Id);
723 CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid = '%u'", m_Id);
724 CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid = '%u'", m_Id);
725 CharacterDatabase.CommitTransaction();
726 sObjectMgr.RemoveGuild(m_Id);
729 void Guild::Roster(WorldSession *session /*= NULL*/)
731 // we can only guess size
732 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));
733 data << (uint32)members.size();
734 data << MOTD;
735 data << GINFO;
737 data << (uint32)m_Ranks.size();
738 for (RankList::const_iterator ritr = m_Ranks.begin(); ritr != m_Ranks.end(); ++ritr)
740 data << uint32(ritr->Rights);
741 data << uint32(ritr->BankMoneyPerDay); // count of: withdraw gold(gold/day) Note: in game set gold, in packet set bronze.
742 for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
744 data << uint32(ritr->TabRight[i]); // for TAB_i rights: view tabs = 0x01, deposit items =0x02
745 data << uint32(ritr->TabSlotPerDay[i]); // for TAB_i count of: withdraw items(stack/day)
748 for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
750 if (Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)))
752 data << uint64(pl->GetGUID());
753 data << uint8(1);
754 data << pl->GetName();
755 data << uint32(itr->second.RankId);
756 data << uint8(pl->getLevel());
757 data << uint8(pl->getClass());
758 data << uint8(0); // new 2.4.0
759 data << uint32(pl->GetZoneId());
760 data << itr->second.Pnote;
761 data << itr->second.OFFnote;
763 else
765 data << uint64(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
766 data << uint8(0);
767 data << itr->second.Name;
768 data << uint32(itr->second.RankId);
769 data << uint8(itr->second.Level);
770 data << uint8(itr->second.Class);
771 data << uint8(0); // new 2.4.0
772 data << uint32(itr->second.ZoneId);
773 data << float(float(time(NULL)-itr->second.LogoutTime) / DAY);
774 data << itr->second.Pnote;
775 data << itr->second.OFFnote;
778 if (session)
779 session->SendPacket(&data);
780 else
781 BroadcastPacket(&data);
782 sLog.outDebug( "WORLD: Sent (SMSG_GUILD_ROSTER)" );
785 void Guild::Query(WorldSession *session)
787 WorldPacket data(SMSG_GUILD_QUERY_RESPONSE, (8*32+200));// we can only guess size
789 data << m_Id;
790 data << m_Name;
792 for (size_t i = 0 ; i < 10; ++i) // show always 10 ranks
794 if (i < m_Ranks.size())
795 data << m_Ranks[i].Name;
796 else
797 data << (uint8)0; // null string
800 data << uint32(m_EmblemStyle);
801 data << uint32(m_EmblemColor);
802 data << uint32(m_BorderStyle);
803 data << uint32(m_BorderColor);
804 data << uint32(m_BackgroundColor);
805 data << uint32(0); // something new in WotLK
807 session->SendPacket( &data );
808 sLog.outDebug( "WORLD: Sent (SMSG_GUILD_QUERY_RESPONSE)" );
811 void Guild::SetEmblem(uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor)
813 m_EmblemStyle = emblemStyle;
814 m_EmblemColor = emblemColor;
815 m_BorderStyle = borderStyle;
816 m_BorderColor = borderColor;
817 m_BackgroundColor = backgroundColor;
819 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);
822 void Guild::UpdateLogoutTime(uint64 guid)
824 MemberList::iterator itr = members.find(GUID_LOPART(guid));
825 if (itr == members.end() )
826 return;
828 itr->second.LogoutTime = time(NULL);
830 if (m_OnlineMembers > 0)
831 --m_OnlineMembers;
832 else
834 UnloadGuildBank();
835 UnloadGuildEventLog();
839 // *************************************************
840 // Guild Eventlog part
841 // *************************************************
842 // Display guild eventlog
843 void Guild::DisplayGuildEventLog(WorldSession *session)
845 // Load guild eventlog, if not already done
846 if (!m_EventLogLoaded)
847 LoadGuildEventLogFromDB();
849 // Sending result
850 WorldPacket data(MSG_GUILD_EVENT_LOG_QUERY, 0);
851 // count, max count == 100
852 data << uint8(m_GuildEventLog.size());
853 for (GuildEventLog::const_iterator itr = m_GuildEventLog.begin(); itr != m_GuildEventLog.end(); ++itr)
855 // Event type
856 data << uint8(itr->EventType);
857 // Player 1
858 data << uint64(itr->PlayerGuid1);
859 // Player 2 not for left/join guild events
860 if (itr->EventType != GUILD_EVENT_LOG_JOIN_GUILD && itr->EventType != GUILD_EVENT_LOG_LEAVE_GUILD)
861 data << uint64(itr->PlayerGuid2);
862 // New Rank - only for promote/demote guild events
863 if (itr->EventType == GUILD_EVENT_LOG_PROMOTE_PLAYER || itr->EventType == GUILD_EVENT_LOG_DEMOTE_PLAYER)
864 data << uint8(itr->NewRank);
865 // Event timestamp
866 data << uint32(time(NULL)-itr->TimeStamp);
868 session->SendPacket(&data);
869 sLog.outDebug("WORLD: Sent (MSG_GUILD_EVENT_LOG_QUERY)");
872 // Load guild eventlog from DB
873 void Guild::LoadGuildEventLogFromDB()
875 // Return if already loaded
876 if (m_EventLogLoaded)
877 return;
879 // 0 1 2 3 4 5
880 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);
881 if (!result)
882 return;
883 bool isNextLogGuidSet = false;
884 //uint32 configCount = sWorld.getConfig(CONFIG_GUILD_EVENT_LOG_COUNT);
885 // First event in list will be the oldest and the latest event is last event in list
888 Field *fields = result->Fetch();
889 if (!isNextLogGuidSet)
891 m_GuildEventLogNextGuid = fields[0].GetUInt32();
892 isNextLogGuidSet = true;
894 // Fill entry
895 GuildEventLogEntry NewEvent;
896 NewEvent.EventType = fields[1].GetUInt8();
897 NewEvent.PlayerGuid1 = fields[2].GetUInt32();
898 NewEvent.PlayerGuid2 = fields[3].GetUInt32();
899 NewEvent.NewRank = fields[4].GetUInt8();
900 NewEvent.TimeStamp = fields[5].GetUInt64();
902 // There can be a problem if more events have same TimeStamp the ORDER can be broken when fields[0].GetUInt32() == configCount, but
903 // events with same timestamp can appear when there is lag, and we naivly suppose that mangos isn't laggy
904 // but if problem appears, player will see set of guild events that have same timestamp in bad order
906 // Add entry to list
907 m_GuildEventLog.push_front(NewEvent);
909 } while( result->NextRow() );
910 delete result;
912 m_EventLogLoaded = true;
915 // Unload guild eventlog
916 void Guild::UnloadGuildEventLog()
918 if (!m_EventLogLoaded)
919 return;
921 m_GuildEventLog.clear();
922 m_EventLogLoaded = false;
925 // Add entry to guild eventlog
926 void Guild::LogGuildEvent(uint8 EventType, uint32 PlayerGuid1, uint32 PlayerGuid2, uint8 NewRank)
928 GuildEventLogEntry NewEvent;
929 // Create event
930 NewEvent.EventType = EventType;
931 NewEvent.PlayerGuid1 = PlayerGuid1;
932 NewEvent.PlayerGuid2 = PlayerGuid2;
933 NewEvent.NewRank = NewRank;
934 NewEvent.TimeStamp = uint32(time(NULL));
935 // Count new LogGuid
936 m_GuildEventLogNextGuid = (m_GuildEventLogNextGuid + 1) % sWorld.getConfig(CONFIG_GUILD_EVENT_LOG_COUNT);
937 // Check max records limit
938 if (m_GuildEventLog.size() >= GUILD_EVENTLOG_MAX_RECORDS)
939 m_GuildEventLog.pop_front();
940 // Add event to list
941 m_GuildEventLog.push_back(NewEvent);
942 // Save event to DB
943 CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid='%u' AND LogGuid='%u'", m_Id, m_GuildEventLogNextGuid);
944 CharacterDatabase.PExecute("INSERT INTO guild_eventlog (guildid, LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','" UI64FMTD "')",
945 m_Id, m_GuildEventLogNextGuid, uint32(NewEvent.EventType), NewEvent.PlayerGuid1, NewEvent.PlayerGuid2, uint32(NewEvent.NewRank), NewEvent.TimeStamp);
948 // *************************************************
949 // Guild Bank part
950 // *************************************************
951 // Bank content related
952 void Guild::DisplayGuildBankContent(WorldSession *session, uint8 TabId)
954 GuildBankTab const* tab = m_TabListMap[TabId];
956 if (!IsMemberHaveRights(session->GetPlayer()->GetGUIDLow(),TabId,GUILD_BANK_RIGHT_VIEW_TAB))
957 return;
959 WorldPacket data(SMSG_GUILD_BANK_LIST,1200);
961 data << uint64(GetGuildBankMoney());
962 data << uint8(TabId);
963 // remaining slots for today
964 data << uint32(GetMemberSlotWithdrawRem(session->GetPlayer()->GetGUIDLow(), TabId));
965 data << uint8(0); // Tell client this is a tab content packet
967 data << uint8(GUILD_BANK_MAX_SLOTS);
969 for (int i=0; i<GUILD_BANK_MAX_SLOTS; ++i)
970 AppendDisplayGuildBankSlot(data, tab, i);
972 session->SendPacket(&data);
974 sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
977 void Guild::DisplayGuildBankMoneyUpdate()
979 WorldPacket data(SMSG_GUILD_BANK_LIST, 8+1+4+1+1);
981 data << uint64(GetGuildBankMoney());
982 data << uint8(0); // TabId, default 0
983 data << uint32(0); // slot withdrow, default 0
984 data << uint8(0); // Tell client this is a tab content packet
985 data << uint8(0); // not send items
986 BroadcastPacket(&data);
988 sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
991 void Guild::DisplayGuildBankContentUpdate(uint8 TabId, int32 slot1, int32 slot2)
993 GuildBankTab const* tab = m_TabListMap[TabId];
995 WorldPacket data(SMSG_GUILD_BANK_LIST,1200);
997 data << uint64(GetGuildBankMoney());
998 data << uint8(TabId);
999 // remaining slots for today
1001 size_t rempos = data.wpos();
1002 data << uint32(0); // will be filled later
1003 data << uint8(0); // Tell client this is a tab content packet
1005 if (slot2 == -1) // single item in slot1
1007 data << uint8(1);
1009 AppendDisplayGuildBankSlot(data, tab, slot1);
1011 else // 2 items (in slot1 and slot2)
1013 data << uint8(2);
1015 if (slot1 > slot2)
1016 std::swap(slot1,slot2);
1018 AppendDisplayGuildBankSlot(data, tab, slot1);
1019 AppendDisplayGuildBankSlot(data, tab, slot2);
1022 for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
1024 Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
1025 if (!player)
1026 continue;
1028 if (!IsMemberHaveRights(itr->first,TabId,GUILD_BANK_RIGHT_VIEW_TAB))
1029 continue;
1031 data.put<uint32>(rempos,uint32(GetMemberSlotWithdrawRem(player->GetGUIDLow(), TabId)));
1033 player->GetSession()->SendPacket(&data);
1036 sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1039 void Guild::DisplayGuildBankContentUpdate(uint8 TabId, GuildItemPosCountVec const& slots)
1041 GuildBankTab const* tab = m_TabListMap[TabId];
1043 WorldPacket data(SMSG_GUILD_BANK_LIST,1200);
1045 data << uint64(GetGuildBankMoney());
1046 data << uint8(TabId);
1047 // remaining slots for today
1049 size_t rempos = data.wpos();
1050 data << uint32(0); // will be filled later
1051 data << uint8(0); // Tell client this is a tab content packet
1053 data << uint8(slots.size()); // updates count
1055 for (GuildItemPosCountVec::const_iterator itr = slots.begin(); itr != slots.end(); ++itr)
1056 AppendDisplayGuildBankSlot(data, tab, itr->Slot);
1058 for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
1060 Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
1061 if (!player)
1062 continue;
1064 if (!IsMemberHaveRights(itr->first,TabId,GUILD_BANK_RIGHT_VIEW_TAB))
1065 continue;
1067 data.put<uint32>(rempos,uint32(GetMemberSlotWithdrawRem(player->GetGUIDLow(), TabId)));
1069 player->GetSession()->SendPacket(&data);
1072 sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1075 Item* Guild::GetItem(uint8 TabId, uint8 SlotId)
1077 if (TabId >= m_TabListMap.size() || SlotId >= GUILD_BANK_MAX_SLOTS)
1078 return NULL;
1079 return m_TabListMap[TabId]->Slots[SlotId];
1082 // *************************************************
1083 // Tab related
1085 void Guild::DisplayGuildBankTabsInfo(WorldSession *session)
1087 // Time to load bank if not already done
1088 if (!m_GuildBankLoaded)
1089 LoadGuildBankFromDB();
1091 WorldPacket data(SMSG_GUILD_BANK_LIST, 500);
1093 data << uint64(GetGuildBankMoney());
1094 data << uint8(0); // TabInfo packet must be for TabId 0
1095 data << uint32(0xFFFFFFFF); // bit 9 must be set for this packet to work
1096 data << uint8(1); // Tell Client this is a TabInfo packet
1098 data << uint8(m_PurchasedTabs); // here is the number of tabs
1100 for (uint8 i = 0; i < m_PurchasedTabs; ++i)
1102 data << m_TabListMap[i]->Name.c_str();
1103 data << m_TabListMap[i]->Icon.c_str();
1105 data << uint8(0); // Do not send tab content
1106 session->SendPacket(&data);
1108 sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1111 void Guild::CreateNewBankTab()
1113 if (m_PurchasedTabs >= GUILD_BANK_MAX_TABS)
1114 return;
1116 ++m_PurchasedTabs;
1118 GuildBankTab* AnotherTab = new GuildBankTab;
1119 memset(AnotherTab->Slots, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*));
1120 m_TabListMap.resize(m_PurchasedTabs);
1121 m_TabListMap[m_PurchasedTabs-1] = AnotherTab;
1123 CharacterDatabase.BeginTransaction();
1124 CharacterDatabase.PExecute("DELETE FROM guild_bank_tab WHERE guildid='%u' AND TabId='%u'", m_Id, uint32(m_PurchasedTabs-1));
1125 CharacterDatabase.PExecute("INSERT INTO guild_bank_tab (guildid,TabId) VALUES ('%u','%u')", m_Id, uint32(m_PurchasedTabs-1));
1126 CharacterDatabase.CommitTransaction();
1129 void Guild::SetGuildBankTabInfo(uint8 TabId, std::string Name, std::string Icon)
1131 if (m_TabListMap[TabId]->Name == Name && m_TabListMap[TabId]->Icon == Icon)
1132 return;
1134 m_TabListMap[TabId]->Name = Name;
1135 m_TabListMap[TabId]->Icon = Icon;
1137 CharacterDatabase.escape_string(Name);
1138 CharacterDatabase.escape_string(Icon);
1139 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));
1142 uint32 Guild::GetBankRights(uint32 rankId, uint8 TabId) const
1144 if (rankId >= m_Ranks.size() || TabId >= GUILD_BANK_MAX_TABS)
1145 return 0;
1147 return m_Ranks[rankId].TabRight[TabId];
1150 // *************************************************
1151 // Guild bank loading/unloading related
1153 // This load should be called when the bank is first accessed by a guild member
1154 void Guild::LoadGuildBankFromDB()
1156 if (m_GuildBankLoaded)
1157 return;
1159 m_GuildBankLoaded = true;
1160 LoadGuildBankEventLogFromDB();
1162 // 0 1 2 3
1163 QueryResult *result = CharacterDatabase.PQuery("SELECT TabId, TabName, TabIcon, TabText FROM guild_bank_tab WHERE guildid='%u' ORDER BY TabId", m_Id);
1164 if (!result)
1166 m_PurchasedTabs = 0;
1167 return;
1170 m_TabListMap.resize(m_PurchasedTabs);
1173 Field *fields = result->Fetch();
1174 uint8 TabId = fields[0].GetUInt8();
1176 GuildBankTab *NewTab = new GuildBankTab;
1177 memset(NewTab->Slots, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*));
1179 NewTab->Name = fields[1].GetCppString();
1180 NewTab->Icon = fields[2].GetCppString();
1181 NewTab->Text = fields[3].GetCppString();
1183 m_TabListMap[TabId] = NewTab;
1184 } while (result->NextRow());
1186 delete result;
1188 // data needs to be at first place for Item::LoadFromDB
1189 // 0 1 2 3 4
1190 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);
1191 if (!result)
1192 return;
1196 Field *fields = result->Fetch();
1197 uint8 TabId = fields[1].GetUInt8();
1198 uint8 SlotId = fields[2].GetUInt8();
1199 uint32 ItemGuid = fields[3].GetUInt32();
1200 uint32 ItemEntry = fields[4].GetUInt32();
1202 if (TabId >= m_PurchasedTabs || TabId >= GUILD_BANK_MAX_TABS)
1204 sLog.outError( "Guild::LoadGuildBankFromDB: Invalid tab for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry);
1205 continue;
1208 if (SlotId >= GUILD_BANK_MAX_SLOTS)
1210 sLog.outError( "Guild::LoadGuildBankFromDB: Invalid slot for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry);
1211 continue;
1214 ItemPrototype const *proto = ObjectMgr::GetItemPrototype(ItemEntry);
1216 if (!proto)
1218 sLog.outError( "Guild::LoadGuildBankFromDB: Unknown item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry);
1219 continue;
1222 Item *pItem = NewItemOrBag(proto);
1223 if (!pItem->LoadFromDB(ItemGuid, 0, result))
1225 CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'", m_Id, uint32(TabId), uint32(SlotId));
1226 sLog.outError("Item GUID %u not found in item_instance, deleting from Guild Bank!", ItemGuid);
1227 delete pItem;
1228 continue;
1231 pItem->AddToWorld();
1232 m_TabListMap[TabId]->Slots[SlotId] = pItem;
1233 } while (result->NextRow());
1235 delete result;
1238 // This unload should be called when the last member of the guild gets offline
1239 void Guild::UnloadGuildBank()
1241 if (!m_GuildBankLoaded)
1242 return;
1243 for (uint8 i = 0 ; i < m_PurchasedTabs ; ++i )
1245 for (uint8 j = 0 ; j < GUILD_BANK_MAX_SLOTS ; ++j)
1247 if (m_TabListMap[i]->Slots[j])
1249 m_TabListMap[i]->Slots[j]->RemoveFromWorld();
1250 delete m_TabListMap[i]->Slots[j];
1253 delete m_TabListMap[i];
1255 m_TabListMap.clear();
1257 UnloadGuildBankEventLog();
1258 m_GuildBankLoaded = false;
1261 // *************************************************
1262 // Money deposit/withdraw related
1264 void Guild::SendMoneyInfo(WorldSession *session, uint32 LowGuid)
1266 WorldPacket data(MSG_GUILD_BANK_MONEY_WITHDRAWN, 4);
1267 data << uint32(GetMemberMoneyWithdrawRem(LowGuid));
1268 session->SendPacket(&data);
1269 sLog.outDebug("WORLD: Sent MSG_GUILD_BANK_MONEY_WITHDRAWN");
1272 bool Guild::MemberMoneyWithdraw(uint32 amount, uint32 LowGuid)
1274 uint32 MoneyWithDrawRight = GetMemberMoneyWithdrawRem(LowGuid);
1276 if (MoneyWithDrawRight < amount || GetGuildBankMoney() < amount)
1277 return false;
1279 SetBankMoney(GetGuildBankMoney()-amount);
1281 if (MoneyWithDrawRight < WITHDRAW_MONEY_UNLIMITED)
1283 MemberList::iterator itr = members.find(LowGuid);
1284 if (itr == members.end() )
1285 return false;
1286 itr->second.BankRemMoney -= amount;
1287 CharacterDatabase.PExecute("UPDATE guild_member SET BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'",
1288 itr->second.BankRemMoney, m_Id, LowGuid);
1290 return true;
1293 void Guild::SetBankMoney(int64 money)
1295 if (money < 0) // I don't know how this happens, it does!!
1296 money = 0;
1297 m_GuildBankMoney = money;
1299 CharacterDatabase.PExecute("UPDATE guild SET BankMoney='" UI64FMTD "' WHERE guildid='%u'", money, m_Id);
1302 // *************************************************
1303 // Item per day and money per day related
1305 bool Guild::MemberItemWithdraw(uint8 TabId, uint32 LowGuid)
1307 uint32 SlotsWithDrawRight = GetMemberSlotWithdrawRem(LowGuid, TabId);
1309 if (SlotsWithDrawRight == 0)
1310 return false;
1312 if (SlotsWithDrawRight < WITHDRAW_SLOT_UNLIMITED)
1314 MemberList::iterator itr = members.find(LowGuid);
1315 if (itr == members.end() )
1316 return false;
1317 --itr->second.BankRemSlotsTab[TabId];
1318 CharacterDatabase.PExecute("UPDATE guild_member SET BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'",
1319 uint32(TabId), itr->second.BankRemSlotsTab[TabId], m_Id, LowGuid);
1321 return true;
1324 bool Guild::IsMemberHaveRights(uint32 LowGuid, uint8 TabId, uint32 rights) const
1326 MemberList::const_iterator itr = members.find(LowGuid);
1327 if (itr == members.end() )
1328 return false;
1330 if (itr->second.RankId == GR_GUILDMASTER)
1331 return true;
1333 return (GetBankRights(itr->second.RankId,TabId) & rights)==rights;
1336 uint32 Guild::GetMemberSlotWithdrawRem(uint32 LowGuid, uint8 TabId)
1338 MemberList::iterator itr = members.find(LowGuid);
1339 if (itr == members.end() )
1340 return 0;
1342 if (itr->second.RankId == GR_GUILDMASTER)
1343 return WITHDRAW_SLOT_UNLIMITED;
1345 if ((GetBankRights(itr->second.RankId,TabId) & GUILD_BANK_RIGHT_VIEW_TAB)!=GUILD_BANK_RIGHT_VIEW_TAB)
1346 return 0;
1348 uint32 curTime = uint32(time(NULL)/MINUTE);
1349 if (curTime - itr->second.BankResetTimeTab[TabId] >= 24*HOUR/MINUTE)
1351 itr->second.BankResetTimeTab[TabId] = curTime;
1352 itr->second.BankRemSlotsTab[TabId] = GetBankSlotPerDay(itr->second.RankId, TabId);
1353 CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeTab%u='%u',BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'",
1354 uint32(TabId), itr->second.BankResetTimeTab[TabId], uint32(TabId), itr->second.BankRemSlotsTab[TabId], m_Id, LowGuid);
1356 return itr->second.BankRemSlotsTab[TabId];
1359 uint32 Guild::GetMemberMoneyWithdrawRem(uint32 LowGuid)
1361 MemberList::iterator itr = members.find(LowGuid);
1362 if (itr == members.end() )
1363 return 0;
1365 if (itr->second.RankId == GR_GUILDMASTER)
1366 return WITHDRAW_MONEY_UNLIMITED;
1368 uint32 curTime = uint32(time(NULL)/MINUTE); // minutes
1369 // 24 hours
1370 if (curTime > itr->second.BankResetTimeMoney + 24*HOUR/MINUTE)
1372 itr->second.BankResetTimeMoney = curTime;
1373 itr->second.BankRemMoney = GetBankMoneyPerDay(itr->second.RankId);
1374 CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeMoney='%u',BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'",
1375 itr->second.BankResetTimeMoney, itr->second.BankRemMoney, m_Id, LowGuid);
1377 return itr->second.BankRemMoney;
1380 void Guild::SetBankMoneyPerDay(uint32 rankId, uint32 money)
1382 if (rankId >= m_Ranks.size())
1383 return;
1385 if (rankId == GR_GUILDMASTER)
1386 money = WITHDRAW_MONEY_UNLIMITED;
1388 m_Ranks[rankId].BankMoneyPerDay = money;
1390 for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
1391 if (itr->second.RankId == rankId)
1392 itr->second.BankResetTimeMoney = 0;
1394 CharacterDatabase.PExecute("UPDATE guild_rank SET BankMoneyPerDay='%u' WHERE rid='%u' AND guildid='%u'", money, rankId, m_Id);
1395 CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeMoney='0' WHERE guildid='%u' AND rank='%u'", m_Id, rankId);
1398 void Guild::SetBankRightsAndSlots(uint32 rankId, uint8 TabId, uint32 right, uint32 nbSlots, bool db)
1400 if (rankId >= m_Ranks.size() ||
1401 TabId >= GUILD_BANK_MAX_TABS ||
1402 TabId >= m_PurchasedTabs)
1404 //TODO remove next line, It is there just to repair existing bug in deleting guild rank
1405 CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid='%u' AND rid='%u' AND TabId='%u'", m_Id, rankId, TabId);
1406 return;
1409 if (rankId == GR_GUILDMASTER)
1411 nbSlots = WITHDRAW_SLOT_UNLIMITED;
1412 right = GUILD_BANK_RIGHT_FULL;
1415 m_Ranks[rankId].TabSlotPerDay[TabId] = nbSlots;
1416 m_Ranks[rankId].TabRight[TabId] = right;
1418 if (db)
1420 for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
1421 if (itr->second.RankId == rankId)
1422 for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
1423 itr->second.BankResetTimeTab[i] = 0;
1425 CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid='%u' AND TabId='%u' AND rid='%u'", m_Id, uint32(TabId), rankId);
1426 CharacterDatabase.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid,gbright,SlotPerDay) VALUES "
1427 "('%u','%u','%u','%u','%u')", m_Id, uint32(TabId), rankId, m_Ranks[rankId].TabRight[TabId], m_Ranks[rankId].TabSlotPerDay[TabId]);
1428 CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeTab%u='0' WHERE guildid='%u' AND rank='%u'", uint32(TabId), m_Id, rankId);
1432 uint32 Guild::GetBankMoneyPerDay(uint32 rankId)
1434 if (rankId >= m_Ranks.size())
1435 return 0;
1437 if (rankId == GR_GUILDMASTER)
1438 return WITHDRAW_MONEY_UNLIMITED;
1439 return m_Ranks[rankId].BankMoneyPerDay;
1442 uint32 Guild::GetBankSlotPerDay(uint32 rankId, uint8 TabId)
1444 if (rankId >= m_Ranks.size() || TabId >= GUILD_BANK_MAX_TABS)
1445 return 0;
1447 if (rankId == GR_GUILDMASTER)
1448 return WITHDRAW_SLOT_UNLIMITED;
1449 return m_Ranks[rankId].TabSlotPerDay[TabId];
1452 // *************************************************
1453 // Rights per day related
1455 bool Guild::LoadBankRightsFromDB(QueryResult *guildBankTabRightsResult)
1457 if (!guildBankTabRightsResult)
1458 return true;
1462 Field *fields = guildBankTabRightsResult->Fetch();
1463 //prevent crash when all rights in result are already processed
1464 if (!fields)
1465 break;
1466 uint32 guildId = fields[0].GetUInt32();
1467 if (guildId < m_Id)
1469 //there is in table guild_bank_right record which doesn't have guildid in guild table, report error
1470 sLog.outErrorDb("Guild %u does not exist but it has a record in guild_bank_right table, deleting it!", guildId);
1471 CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u'", guildId);
1472 continue;
1475 if (guildId > m_Id)
1476 //we loaded all ranks for this guild bank already, break cycle
1477 break;
1478 uint8 TabId = fields[1].GetUInt8();
1479 uint32 rankId = fields[2].GetUInt32();
1480 uint16 right = fields[3].GetUInt16();
1481 uint16 SlotPerDay = fields[4].GetUInt16();
1483 SetBankRightsAndSlots(rankId, TabId, right, SlotPerDay, false);
1485 } while (guildBankTabRightsResult->NextRow());
1487 return true;
1490 // *************************************************
1491 // Bank log related
1493 void Guild::LoadGuildBankEventLogFromDB()
1495 // Money log is in TabId = GUILD_BANK_MONEY_LOGS_TAB
1497 //uint32 configCount = sWorld.getConfig(CONFIG_GUILD_BANK_EVENT_LOG_COUNT);
1498 //cycle through all purchased guild bank item tabs
1499 for (uint32 tabId = 0; tabId < m_PurchasedTabs; tabId++)
1501 // 0 1 2 3 4 5 6
1502 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);
1503 if (!result)
1504 continue;
1506 bool isNextLogGuidSet = false;
1509 Field *fields = result->Fetch();
1511 GuildBankEventLogEntry NewEvent;
1512 NewEvent.EventType = fields[1].GetUInt8();
1513 NewEvent.PlayerGuid = fields[2].GetUInt32();
1514 NewEvent.ItemOrMoney = fields[3].GetUInt32();
1515 NewEvent.ItemStackCount = fields[4].GetUInt8();
1516 NewEvent.DestTabId = fields[5].GetUInt8();
1517 NewEvent.TimeStamp = fields[6].GetUInt64();
1519 //if newEvent is moneyEvent, move it to moneyEventTab in DB and report error
1520 if (NewEvent.isMoneyEvent())
1522 uint32 logGuid = fields[0].GetUInt32();
1523 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);
1524 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);
1525 continue;
1527 else
1528 //add event to list
1529 //events are ordered from oldest (in beginning) to latest (in the end)
1530 m_GuildBankEventLog_Item[tabId].push_front(NewEvent);
1532 if (!isNextLogGuidSet)
1534 m_GuildBankEventLogNextGuid_Item[tabId] = fields[0].GetUInt32();
1535 //we don't have to do m_GuildBankEventLogNextGuid_Item[tabId] %= configCount; - it will be done when creating new record
1536 isNextLogGuidSet = true;
1538 } while (result->NextRow());
1539 delete result;
1542 //special handle for guild bank money log
1543 // 0 1 2 3 4 5 6
1544 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);
1545 if (!result)
1546 return;
1548 bool isNextMoneyLogGuidSet = false;
1551 Field *fields = result->Fetch();
1552 if (!isNextMoneyLogGuidSet)
1554 m_GuildBankEventLogNextGuid_Money = fields[0].GetUInt32();
1555 //we don't have to do m_GuildBankEventLogNextGuid_Money %= configCount; - it will be done when creating new record
1556 isNextMoneyLogGuidSet = true;
1558 GuildBankEventLogEntry NewEvent;
1560 NewEvent.EventType = fields[1].GetUInt8();
1561 NewEvent.PlayerGuid = fields[2].GetUInt32();
1562 NewEvent.ItemOrMoney = fields[3].GetUInt32();
1563 NewEvent.ItemStackCount = fields[4].GetUInt8();
1564 NewEvent.DestTabId = fields[5].GetUInt8();
1565 NewEvent.TimeStamp = fields[6].GetUInt64();
1567 //if newEvent is not moneyEvent, then report error
1568 if (!NewEvent.isMoneyEvent())
1569 sLog.outError("GuildBankEventLog ERROR: MoneyEvent LogGuid %u for Guild %u is not MoneyEvent - ignoring...", fields[0].GetUInt32(), m_Id);
1570 else
1571 //add event to list
1572 //events are ordered from oldest (in beginning) to latest (in the end)
1573 m_GuildBankEventLog_Money.push_front(NewEvent);
1575 } while (result->NextRow());
1576 delete result;
1579 void Guild::UnloadGuildBankEventLog()
1581 m_GuildBankEventLog_Money.clear();
1583 for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
1584 m_GuildBankEventLog_Item[i].clear();
1587 void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId)
1589 if (TabId > GUILD_BANK_MAX_TABS)
1590 return;
1592 if (TabId == GUILD_BANK_MAX_TABS)
1594 // Here we display money logs
1595 WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, m_GuildBankEventLog_Money.size()*(4*4+1)+1+1);
1596 data << uint8(TabId); // Here GUILD_BANK_MAX_TABS
1597 data << uint8(m_GuildBankEventLog_Money.size()); // number of log entries
1598 for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Money.begin(); itr != m_GuildBankEventLog_Money.end(); ++itr)
1600 data << uint8(itr->EventType);
1601 data << uint64(MAKE_NEW_GUID(itr->PlayerGuid,0,HIGHGUID_PLAYER));
1602 if (itr->EventType == GUILD_BANK_LOG_DEPOSIT_MONEY ||
1603 itr->EventType == GUILD_BANK_LOG_WITHDRAW_MONEY ||
1604 itr->EventType == GUILD_BANK_LOG_REPAIR_MONEY ||
1605 itr->EventType == GUILD_BANK_LOG_UNK1 ||
1606 itr->EventType == GUILD_BANK_LOG_UNK2)
1608 data << uint32(itr->ItemOrMoney);
1610 else
1612 data << uint32(itr->ItemOrMoney);
1613 data << uint32(itr->ItemStackCount);
1614 if (itr->EventType == GUILD_BANK_LOG_MOVE_ITEM || itr->EventType == GUILD_BANK_LOG_MOVE_ITEM2)
1615 data << uint8(itr->DestTabId); // moved tab
1617 data << uint32(time(NULL) - itr->TimeStamp);
1619 session->SendPacket(&data);
1621 else
1623 // here we display current tab logs
1624 WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, m_GuildBankEventLog_Item[TabId].size()*(4*4+1+1)+1+1);
1625 data << uint8(TabId); // Here a real Tab Id
1626 // number of log entries
1627 data << uint8(m_GuildBankEventLog_Item[TabId].size());
1628 for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Item[TabId].begin(); itr != m_GuildBankEventLog_Item[TabId].end(); ++itr)
1630 data << uint8(itr->EventType);
1631 data << uint64(MAKE_NEW_GUID(itr->PlayerGuid,0,HIGHGUID_PLAYER));
1632 if (itr->EventType == GUILD_BANK_LOG_DEPOSIT_MONEY ||
1633 itr->EventType == GUILD_BANK_LOG_WITHDRAW_MONEY ||
1634 itr->EventType == GUILD_BANK_LOG_REPAIR_MONEY ||
1635 itr->EventType == GUILD_BANK_LOG_UNK1 ||
1636 itr->EventType == GUILD_BANK_LOG_UNK2)
1638 data << uint32(itr->ItemOrMoney);
1640 else
1642 data << uint32(itr->ItemOrMoney);
1643 data << uint32(itr->ItemStackCount);
1644 if (itr->EventType == GUILD_BANK_LOG_MOVE_ITEM || itr->EventType == GUILD_BANK_LOG_MOVE_ITEM2)
1645 data << uint8(itr->DestTabId); // moved tab
1647 data << uint32(time(NULL) - itr->TimeStamp);
1649 session->SendPacket(&data);
1651 sLog.outDebug("WORLD: Sent (MSG_GUILD_BANK_LOG_QUERY)");
1654 void Guild::LogBankEvent(uint8 EventType, uint8 TabId, uint32 PlayerGuidLow, uint32 ItemOrMoney, uint8 ItemStackCount, uint8 DestTabId)
1656 //create Event
1657 GuildBankEventLogEntry NewEvent;
1658 NewEvent.EventType = EventType;
1659 NewEvent.PlayerGuid = PlayerGuidLow;
1660 NewEvent.ItemOrMoney = ItemOrMoney;
1661 NewEvent.ItemStackCount = ItemStackCount;
1662 NewEvent.DestTabId = DestTabId;
1663 NewEvent.TimeStamp = uint32(time(NULL));
1665 //add new event to the end of event list
1666 uint32 currentTabId = TabId;
1667 uint32 currentLogGuid = 0;
1668 if (NewEvent.isMoneyEvent())
1670 m_GuildBankEventLogNextGuid_Money = (m_GuildBankEventLogNextGuid_Money + 1) % sWorld.getConfig(CONFIG_GUILD_BANK_EVENT_LOG_COUNT);
1671 currentLogGuid = m_GuildBankEventLogNextGuid_Money;
1672 currentTabId = GUILD_BANK_MONEY_LOGS_TAB;
1673 if (m_GuildBankEventLog_Money.size() >= GUILD_BANK_MAX_LOGS)
1674 m_GuildBankEventLog_Money.pop_front();
1676 m_GuildBankEventLog_Money.push_back(NewEvent);
1678 else
1680 m_GuildBankEventLogNextGuid_Item[TabId] = ((m_GuildBankEventLogNextGuid_Item[TabId]) + 1) % sWorld.getConfig(CONFIG_GUILD_BANK_EVENT_LOG_COUNT);
1681 currentLogGuid = m_GuildBankEventLogNextGuid_Item[TabId];
1682 if (m_GuildBankEventLog_Item[TabId].size() >= GUILD_BANK_MAX_LOGS)
1683 m_GuildBankEventLog_Item[TabId].pop_front();
1685 m_GuildBankEventLog_Item[TabId].push_back(NewEvent);
1688 //save event to database
1689 CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u' AND TabId='%u'", m_Id, currentLogGuid, currentTabId);
1691 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 "')",
1692 m_Id, currentLogGuid, currentTabId, uint32(NewEvent.EventType), NewEvent.PlayerGuid, NewEvent.ItemOrMoney, uint32(NewEvent.ItemStackCount), uint32(NewEvent.DestTabId), NewEvent.TimeStamp);
1695 bool Guild::AddGBankItemToDB(uint32 GuildId, uint32 BankTab , uint32 BankTabSlot , uint32 GUIDLow, uint32 Entry )
1697 CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u' AND TabId = '%u'AND SlotId = '%u'", GuildId, BankTab, BankTabSlot);
1698 CharacterDatabase.PExecute("INSERT INTO guild_bank_item (guildid,TabId,SlotId,item_guid,item_entry) "
1699 "VALUES ('%u', '%u', '%u', '%u', '%u')", GuildId, BankTab, BankTabSlot, GUIDLow, Entry);
1700 return true;
1703 void Guild::AppendDisplayGuildBankSlot( WorldPacket& data, GuildBankTab const *tab, int slot )
1705 Item *pItem = tab->Slots[slot];
1706 uint32 entry = pItem ? pItem->GetEntry() : 0;
1708 data << uint8(slot);
1709 data << uint32(entry);
1710 if (entry)
1712 // random item property id +8
1713 data << (uint32) pItem->GetItemRandomPropertyId();
1714 if (pItem->GetItemRandomPropertyId())
1715 // SuffixFactor +4
1716 data << (uint32) pItem->GetItemSuffixFactor();
1717 // +12 // ITEM_FIELD_STACK_COUNT
1718 data << uint32(pItem->GetCount());
1719 data << uint32(0); // +16 // Unknown value
1720 data << uint8(0); // unknown 2.4.2
1721 if (uint32 Enchant0 = pItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT))
1723 data << uint8(1); // number of enchantments (max 3) why max 3?
1724 data << uint8(PERM_ENCHANTMENT_SLOT); // enchantment slot (range: 0:2)
1725 data << uint32(Enchant0); // enchantment id
1727 else
1728 data << uint8(0); // no enchantments (0)
1732 Item* Guild::StoreItem(uint8 tabId, GuildItemPosCountVec const& dest, Item* pItem )
1734 if (!pItem)
1735 return NULL;
1737 Item* lastItem = pItem;
1739 for (GuildItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); )
1741 uint8 slot = itr->Slot;
1742 uint32 count = itr->Count;
1744 ++itr;
1746 if (itr == dest.end())
1748 lastItem = _StoreItem(tabId,slot,pItem,count,false);
1749 break;
1752 lastItem = _StoreItem(tabId,slot,pItem,count,true);
1755 return lastItem;
1758 // Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
1759 Item* Guild::_StoreItem( uint8 tab, uint8 slot, Item *pItem, uint32 count, bool clone )
1761 if (!pItem)
1762 return NULL;
1764 sLog.outDebug( "GUILD STORAGE: StoreItem tab = %u, slot = %u, item = %u, count = %u", tab, slot, pItem->GetEntry(), count);
1766 Item* pItem2 = m_TabListMap[tab]->Slots[slot];
1768 if (!pItem2)
1770 if (clone)
1771 pItem = pItem->CloneItem(count);
1772 else
1773 pItem->SetCount(count);
1775 if (!pItem)
1776 return NULL;
1778 m_TabListMap[tab]->Slots[slot] = pItem;
1780 pItem->SetUInt64Value(ITEM_FIELD_CONTAINED, 0);
1781 pItem->SetUInt64Value(ITEM_FIELD_OWNER, 0);
1782 AddGBankItemToDB(GetId(), tab, slot, pItem->GetGUIDLow(), pItem->GetEntry());
1783 pItem->FSetState(ITEM_NEW);
1784 pItem->SaveToDB(); // not in onventory and can be save standalone
1786 return pItem;
1788 else
1790 pItem2->SetCount( pItem2->GetCount() + count );
1791 pItem2->FSetState(ITEM_CHANGED);
1792 pItem2->SaveToDB(); // not in onventory and can be save standalone
1794 if (!clone)
1796 pItem->RemoveFromWorld();
1797 pItem->DeleteFromDB();
1798 delete pItem;
1801 return pItem2;
1805 void Guild::RemoveItem(uint8 tab, uint8 slot )
1807 m_TabListMap[tab]->Slots[slot] = NULL;
1808 CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'",
1809 GetId(), uint32(tab), uint32(slot));
1812 uint8 Guild::_CanStoreItem_InSpecificSlot( uint8 tab, uint8 slot, GuildItemPosCountVec &dest, uint32& count, bool swap, Item* pSrcItem ) const
1814 Item* pItem2 = m_TabListMap[tab]->Slots[slot];
1816 // ignore move item (this slot will be empty at move)
1817 if (pItem2 == pSrcItem)
1818 pItem2 = NULL;
1820 uint32 need_space;
1822 // empty specific slot - check item fit to slot
1823 if (!pItem2 || swap)
1825 // non empty stack with space
1826 need_space = pSrcItem->GetMaxStackCount();
1828 // non empty slot, check item type
1829 else
1831 // check item type
1832 if (pItem2->GetEntry() != pSrcItem->GetEntry())
1833 return EQUIP_ERR_ITEM_CANT_STACK;
1835 // check free space
1836 if (pItem2->GetCount() >= pSrcItem->GetMaxStackCount())
1837 return EQUIP_ERR_ITEM_CANT_STACK;
1839 need_space = pSrcItem->GetMaxStackCount() - pItem2->GetCount();
1842 if (need_space > count)
1843 need_space = count;
1845 GuildItemPosCount newPosition = GuildItemPosCount(slot,need_space);
1846 if (!newPosition.isContainedIn(dest))
1848 dest.push_back(newPosition);
1849 count -= need_space;
1852 return EQUIP_ERR_OK;
1855 uint8 Guild::_CanStoreItem_InTab( uint8 tab, GuildItemPosCountVec &dest, uint32& count, bool merge, Item* pSrcItem, uint8 skip_slot ) const
1857 for (uint32 j = 0; j < GUILD_BANK_MAX_SLOTS; j++)
1859 // skip specific slot already processed in first called _CanStoreItem_InSpecificSlot
1860 if (j == skip_slot)
1861 continue;
1863 Item* pItem2 = m_TabListMap[tab]->Slots[j];
1865 // ignore move item (this slot will be empty at move)
1866 if (pItem2 == pSrcItem)
1867 pItem2 = NULL;
1869 // if merge skip empty, if !merge skip non-empty
1870 if ((pItem2 != NULL) != merge)
1871 continue;
1873 if (pItem2)
1875 if (pItem2->GetEntry() == pSrcItem->GetEntry() && pItem2->GetCount() < pSrcItem->GetMaxStackCount())
1877 uint32 need_space = pSrcItem->GetMaxStackCount() - pItem2->GetCount();
1878 if (need_space > count)
1879 need_space = count;
1881 GuildItemPosCount newPosition = GuildItemPosCount(j,need_space);
1882 if (!newPosition.isContainedIn(dest))
1884 dest.push_back(newPosition);
1885 count -= need_space;
1887 if (count == 0)
1888 return EQUIP_ERR_OK;
1892 else
1894 uint32 need_space = pSrcItem->GetMaxStackCount();
1895 if (need_space > count)
1896 need_space = count;
1898 GuildItemPosCount newPosition = GuildItemPosCount(j,need_space);
1899 if (!newPosition.isContainedIn(dest))
1901 dest.push_back(newPosition);
1902 count -= need_space;
1904 if (count == 0)
1905 return EQUIP_ERR_OK;
1909 return EQUIP_ERR_OK;
1912 uint8 Guild::CanStoreItem( uint8 tab, uint8 slot, GuildItemPosCountVec &dest, uint32 count, Item *pItem, bool swap ) const
1914 sLog.outDebug( "GUILD STORAGE: CanStoreItem tab = %u, slot = %u, item = %u, count = %u", tab, slot, pItem->GetEntry(), count);
1916 if (count > pItem->GetCount())
1917 return EQUIP_ERR_COULDNT_SPLIT_ITEMS;
1919 if (pItem->IsSoulBound())
1920 return EQUIP_ERR_CANT_DROP_SOULBOUND;
1922 // in specific slot
1923 if (slot != NULL_SLOT)
1925 uint8 res = _CanStoreItem_InSpecificSlot(tab,slot,dest,count,swap,pItem);
1926 if (res != EQUIP_ERR_OK)
1927 return res;
1929 if (count == 0)
1930 return EQUIP_ERR_OK;
1933 // not specific slot or have spece for partly store only in specific slot
1935 // search stack in tab for merge to
1936 if (pItem->GetMaxStackCount() > 1)
1938 uint8 res = _CanStoreItem_InTab(tab,dest,count,true,pItem,slot);
1939 if (res != EQUIP_ERR_OK)
1940 return res;
1942 if (count == 0)
1943 return EQUIP_ERR_OK;
1946 // search free slot in bag for place to
1947 uint8 res = _CanStoreItem_InTab(tab,dest,count,false,pItem,slot);
1948 if (res != EQUIP_ERR_OK)
1949 return res;
1951 if (count == 0)
1952 return EQUIP_ERR_OK;
1954 return EQUIP_ERR_BANK_FULL;
1957 void Guild::SetGuildBankTabText(uint8 TabId, std::string text)
1959 if (TabId >= GUILD_BANK_MAX_TABS)
1960 return;
1961 if (TabId >= m_TabListMap.size())
1962 return;
1963 if (!m_TabListMap[TabId])
1964 return;
1966 if (m_TabListMap[TabId]->Text == text)
1967 return;
1969 utf8truncate(text,500); // DB and client size limitation
1971 m_TabListMap[TabId]->Text = text;
1973 CharacterDatabase.escape_string(text);
1974 CharacterDatabase.PExecute("UPDATE guild_bank_tab SET TabText='%s' WHERE guildid='%u' AND TabId='%u'", text.c_str(), m_Id, uint32(TabId));
1976 // announce
1977 SendGuildBankTabText(NULL,TabId);
1980 void Guild::SendGuildBankTabText(WorldSession *session, uint8 TabId)
1982 GuildBankTab const* tab = m_TabListMap[TabId];
1984 WorldPacket data(MSG_QUERY_GUILD_BANK_TEXT, 1+tab->Text.size()+1);
1985 data << uint8(TabId);
1986 data << tab->Text;
1988 if (session)
1989 session->SendPacket(&data);
1990 else
1991 BroadcastPacket(&data);
1994 void Guild::SwapItems(Player * pl, uint8 BankTab, uint8 BankTabSlot, uint8 BankTabDst, uint8 BankTabSlotDst, uint32 SplitedAmount )
1996 // empty operation
1997 if (BankTab == BankTabDst && BankTabSlot == BankTabSlotDst)
1998 return;
2000 Item *pItemSrc = GetItem(BankTab, BankTabSlot);
2001 if (!pItemSrc) // may prevent crash
2002 return;
2004 if (SplitedAmount > pItemSrc->GetCount())
2005 return; // cheating?
2006 else if (SplitedAmount == pItemSrc->GetCount())
2007 SplitedAmount = 0; // no split
2009 Item *pItemDst = GetItem(BankTabDst, BankTabSlotDst);
2011 if (BankTab != BankTabDst)
2013 // check dest pos rights (if different tabs)
2014 if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTabDst, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
2015 return;
2017 // check source pos rights (if different tabs)
2018 uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab);
2019 if (remRight <= 0)
2020 return;
2023 if (SplitedAmount)
2024 { // Bank -> Bank item split (in empty or non empty slot
2025 GuildItemPosCountVec dest;
2026 uint8 msg = CanStoreItem(BankTabDst,BankTabSlotDst,dest,SplitedAmount,pItemSrc,false);
2027 if (msg != EQUIP_ERR_OK)
2029 pl->SendEquipError( msg, pItemSrc, NULL );
2030 return;
2033 Item *pNewItem = pItemSrc->CloneItem( SplitedAmount );
2034 if (!pNewItem)
2036 pl->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pItemSrc, NULL );
2037 return;
2040 CharacterDatabase.BeginTransaction();
2041 LogBankEvent(GUILD_BANK_LOG_MOVE_ITEM, BankTab, pl->GetGUIDLow(), pItemSrc->GetEntry(), SplitedAmount, BankTabDst);
2043 pl->ItemRemovedQuestCheck( pItemSrc->GetEntry(), SplitedAmount );
2044 pItemSrc->SetCount( pItemSrc->GetCount() - SplitedAmount );
2045 pItemSrc->FSetState(ITEM_CHANGED);
2046 pItemSrc->SaveToDB(); // not in inventory and can be save standalone
2047 StoreItem(BankTabDst,dest,pNewItem);
2048 CharacterDatabase.CommitTransaction();
2050 else // non split
2052 GuildItemPosCountVec gDest;
2053 uint8 msg = CanStoreItem(BankTabDst,BankTabSlotDst,gDest,pItemSrc->GetCount(),pItemSrc,false);
2054 if (msg == EQUIP_ERR_OK) // merge to
2056 CharacterDatabase.BeginTransaction();
2057 LogBankEvent(GUILD_BANK_LOG_MOVE_ITEM, BankTab, pl->GetGUIDLow(), pItemSrc->GetEntry(), pItemSrc->GetCount(), BankTabDst);
2059 RemoveItem(BankTab, BankTabSlot);
2060 StoreItem(BankTabDst, gDest, pItemSrc);
2061 CharacterDatabase.CommitTransaction();
2063 else // swap
2065 gDest.clear();
2066 msg = CanStoreItem(BankTabDst,BankTabSlotDst,gDest,pItemSrc->GetCount(),pItemSrc,true);
2067 if (msg != EQUIP_ERR_OK)
2069 pl->SendEquipError( msg, pItemSrc, NULL );
2070 return;
2073 GuildItemPosCountVec gSrc;
2074 msg = CanStoreItem(BankTab,BankTabSlot,gSrc,pItemDst->GetCount(),pItemDst,true);
2075 if (msg != EQUIP_ERR_OK)
2077 pl->SendEquipError( msg, pItemDst, NULL );
2078 return;
2081 if (BankTab != BankTabDst)
2083 // check source pos rights (item swapped to src)
2084 if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTab, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
2085 return;
2087 // check dest pos rights (item swapped to src)
2088 uint32 remRightDst = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTabDst);
2089 if (remRightDst <= 0)
2090 return;
2093 CharacterDatabase.BeginTransaction();
2094 LogBankEvent(GUILD_BANK_LOG_MOVE_ITEM, BankTab, pl->GetGUIDLow(), pItemSrc->GetEntry(), pItemSrc->GetCount(), BankTabDst);
2095 LogBankEvent(GUILD_BANK_LOG_MOVE_ITEM, BankTabDst, pl->GetGUIDLow(), pItemDst->GetEntry(), pItemDst->GetCount(), BankTab);
2097 RemoveItem(BankTab, BankTabSlot);
2098 RemoveItem(BankTabDst, BankTabSlotDst);
2099 StoreItem(BankTab, gSrc, pItemDst);
2100 StoreItem(BankTabDst, gDest, pItemSrc);
2101 CharacterDatabase.CommitTransaction();
2104 DisplayGuildBankContentUpdate(BankTab,BankTabSlot,BankTab == BankTabDst ? BankTabSlotDst : -1);
2105 if (BankTab != BankTabDst)
2106 DisplayGuildBankContentUpdate(BankTabDst,BankTabSlotDst);
2110 void Guild::MoveFromBankToChar( Player * pl, uint8 BankTab, uint8 BankTabSlot, uint8 PlayerBag, uint8 PlayerSlot, uint32 SplitedAmount)
2112 Item *pItemBank = GetItem(BankTab, BankTabSlot);
2113 Item *pItemChar = pl->GetItemByPos(PlayerBag, PlayerSlot);
2115 if (!pItemBank) // Problem to get bank item
2116 return;
2118 if (SplitedAmount > pItemBank->GetCount())
2119 return; // cheating?
2120 else if (SplitedAmount == pItemBank->GetCount())
2121 SplitedAmount = 0; // no split
2123 if (SplitedAmount)
2124 { // Bank -> Char split to slot (patly move)
2125 Item *pNewItem = pItemBank->CloneItem( SplitedAmount );
2126 if (!pNewItem)
2128 pl->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pItemBank, NULL );
2129 return;
2132 ItemPosCountVec dest;
2133 uint8 msg = pl->CanStoreItem(PlayerBag, PlayerSlot, dest, pNewItem, false);
2134 if (msg != EQUIP_ERR_OK)
2136 pl->SendEquipError( msg, pNewItem, NULL );
2137 delete pNewItem;
2138 return;
2141 // check source pos rights (item moved to inventory)
2142 uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab);
2143 if (remRight <= 0)
2145 delete pNewItem;
2146 return;
2149 CharacterDatabase.BeginTransaction();
2150 LogBankEvent(GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), SplitedAmount);
2152 pItemBank->SetCount(pItemBank->GetCount()-SplitedAmount);
2153 pItemBank->FSetState(ITEM_CHANGED);
2154 pItemBank->SaveToDB(); // not in inventory and can be save standalone
2155 pl->MoveItemToInventory(dest,pNewItem,true);
2156 pl->SaveInventoryAndGoldToDB();
2158 MemberItemWithdraw(BankTab, pl->GetGUIDLow());
2159 CharacterDatabase.CommitTransaction();
2161 else // Bank -> Char swap with slot (move)
2163 ItemPosCountVec dest;
2164 uint8 msg = pl->CanStoreItem(PlayerBag, PlayerSlot, dest, pItemBank, false);
2165 if (msg == EQUIP_ERR_OK) // merge case
2167 // check source pos rights (item moved to inventory)
2168 uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab);
2169 if (remRight <= 0)
2170 return;
2172 CharacterDatabase.BeginTransaction();
2173 LogBankEvent(GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), pItemBank->GetCount());
2175 RemoveItem(BankTab, BankTabSlot);
2176 pl->MoveItemToInventory(dest,pItemBank,true);
2177 pl->SaveInventoryAndGoldToDB();
2179 MemberItemWithdraw(BankTab, pl->GetGUIDLow());
2180 CharacterDatabase.CommitTransaction();
2182 else // Bank <-> Char swap items
2184 // check source pos rights (item swapped to bank)
2185 if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTab, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
2186 return;
2188 if (pItemChar)
2190 if (!pItemChar->CanBeTraded())
2192 pl->SendEquipError( EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, pItemChar, NULL );
2193 return;
2197 ItemPosCountVec iDest;
2198 msg = pl->CanStoreItem(PlayerBag, PlayerSlot, iDest, pItemBank, true);
2199 if (msg != EQUIP_ERR_OK)
2201 pl->SendEquipError( msg, pItemBank, NULL );
2202 return;
2205 GuildItemPosCountVec gDest;
2206 if (pItemChar)
2208 msg = CanStoreItem(BankTab,BankTabSlot,gDest,pItemChar->GetCount(),pItemChar,true);
2209 if (msg != EQUIP_ERR_OK)
2211 pl->SendEquipError( msg, pItemChar, NULL );
2212 return;
2216 // check source pos rights (item moved to inventory)
2217 uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab);
2218 if (remRight <= 0)
2219 return;
2221 if (pItemChar)
2223 // logging item move to bank
2224 if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
2226 sLog.outCommand(pl->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
2227 pl->GetName(),pl->GetSession()->GetAccountId(),
2228 pItemChar->GetProto()->Name1,pItemChar->GetEntry(),pItemChar->GetCount(),
2229 m_Id);
2233 CharacterDatabase.BeginTransaction();
2234 LogBankEvent(GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), pItemBank->GetCount());
2235 if (pItemChar)
2236 LogBankEvent(GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), pItemChar->GetCount());
2238 RemoveItem(BankTab, BankTabSlot);
2239 if (pItemChar)
2241 pl->MoveItemFromInventory(PlayerBag, PlayerSlot, true);
2242 pItemChar->DeleteFromInventoryDB();
2245 if (pItemChar)
2246 StoreItem(BankTab, gDest, pItemChar);
2247 pl->MoveItemToInventory(iDest,pItemBank,true);
2248 pl->SaveInventoryAndGoldToDB();
2250 MemberItemWithdraw(BankTab, pl->GetGUIDLow());
2251 CharacterDatabase.CommitTransaction();
2254 DisplayGuildBankContentUpdate(BankTab,BankTabSlot);
2258 void Guild::MoveFromCharToBank( Player * pl, uint8 PlayerBag, uint8 PlayerSlot, uint8 BankTab, uint8 BankTabSlot, uint32 SplitedAmount )
2260 Item *pItemBank = GetItem(BankTab, BankTabSlot);
2261 Item *pItemChar = pl->GetItemByPos(PlayerBag, PlayerSlot);
2263 if (!pItemChar) // Problem to get item from player
2264 return;
2266 if (!pItemChar->CanBeTraded())
2268 pl->SendEquipError( EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, pItemChar, NULL );
2269 return;
2272 // check source pos rights (item moved to bank)
2273 if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTab, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
2274 return;
2276 if (SplitedAmount > pItemChar->GetCount())
2277 return; // cheating?
2278 else if (SplitedAmount == pItemChar->GetCount())
2279 SplitedAmount = 0; // no split
2281 if (SplitedAmount)
2282 { // Char -> Bank split to empty or non-empty slot (partly move)
2283 GuildItemPosCountVec dest;
2284 uint8 msg = CanStoreItem(BankTab,BankTabSlot,dest,SplitedAmount,pItemChar,false);
2285 if (msg != EQUIP_ERR_OK)
2287 pl->SendEquipError( msg, pItemChar, NULL );
2288 return;
2291 Item *pNewItem = pItemChar->CloneItem( SplitedAmount );
2292 if (!pNewItem)
2294 pl->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pItemChar, NULL );
2295 return;
2298 // logging item move to bank (before items merge
2299 if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
2301 sLog.outCommand(pl->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
2302 pl->GetName(),pl->GetSession()->GetAccountId(),
2303 pItemChar->GetProto()->Name1,pItemChar->GetEntry(),SplitedAmount,m_Id);
2306 CharacterDatabase.BeginTransaction();
2307 LogBankEvent(GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), SplitedAmount);
2309 pl->ItemRemovedQuestCheck( pItemChar->GetEntry(), SplitedAmount );
2310 pItemChar->SetCount(pItemChar->GetCount()-SplitedAmount);
2311 pItemChar->SetState(ITEM_CHANGED);
2312 pl->SaveInventoryAndGoldToDB();
2313 StoreItem(BankTab, dest, pNewItem);
2314 CharacterDatabase.CommitTransaction();
2316 DisplayGuildBankContentUpdate(BankTab,dest);
2318 else // Char -> Bank swap with empty or non-empty (move)
2320 GuildItemPosCountVec dest;
2321 uint8 msg = CanStoreItem(BankTab,BankTabSlot,dest,pItemChar->GetCount(),pItemChar,false);
2322 if (msg == EQUIP_ERR_OK) // merge
2324 // logging item move to bank
2325 if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
2327 sLog.outCommand(pl->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
2328 pl->GetName(),pl->GetSession()->GetAccountId(),
2329 pItemChar->GetProto()->Name1,pItemChar->GetEntry(),pItemChar->GetCount(),
2330 m_Id);
2333 CharacterDatabase.BeginTransaction();
2334 LogBankEvent(GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), pItemChar->GetCount());
2336 pl->MoveItemFromInventory(PlayerBag, PlayerSlot, true);
2337 pItemChar->DeleteFromInventoryDB();
2339 StoreItem(BankTab,dest,pItemChar);
2340 pl->SaveInventoryAndGoldToDB();
2341 CharacterDatabase.CommitTransaction();
2343 DisplayGuildBankContentUpdate(BankTab,dest);
2345 else // Char <-> Bank swap items (posible NULL bank item)
2347 ItemPosCountVec iDest;
2348 if (pItemBank)
2350 msg = pl->CanStoreItem(PlayerBag, PlayerSlot, iDest, pItemBank, true);
2351 if (msg != EQUIP_ERR_OK)
2353 pl->SendEquipError( msg, pItemBank, NULL );
2354 return;
2358 GuildItemPosCountVec gDest;
2359 msg = CanStoreItem(BankTab,BankTabSlot,gDest,pItemChar->GetCount(),pItemChar,true);
2360 if (msg != EQUIP_ERR_OK)
2362 pl->SendEquipError( msg, pItemChar, NULL );
2363 return;
2366 if (pItemBank)
2368 // check bank pos rights (item swapped with inventory)
2369 uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab);
2370 if (remRight <= 0)
2371 return;
2374 // logging item move to bank
2375 if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
2377 sLog.outCommand(pl->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
2378 pl->GetName(),pl->GetSession()->GetAccountId(),
2379 pItemChar->GetProto()->Name1,pItemChar->GetEntry(),pItemChar->GetCount(),
2380 m_Id);
2383 CharacterDatabase.BeginTransaction();
2384 if (pItemBank)
2385 LogBankEvent(GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), pItemBank->GetCount());
2386 LogBankEvent(GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), pItemChar->GetCount());
2388 pl->MoveItemFromInventory(PlayerBag, PlayerSlot, true);
2389 pItemChar->DeleteFromInventoryDB();
2390 if (pItemBank)
2391 RemoveItem(BankTab, BankTabSlot);
2393 StoreItem(BankTab,gDest,pItemChar);
2394 if (pItemBank)
2395 pl->MoveItemToInventory(iDest,pItemBank,true);
2396 pl->SaveInventoryAndGoldToDB();
2397 if (pItemBank)
2398 MemberItemWithdraw(BankTab, pl->GetGUIDLow());
2399 CharacterDatabase.CommitTransaction();
2401 DisplayGuildBankContentUpdate(BankTab,gDest);
2406 bool GuildItemPosCount::isContainedIn(GuildItemPosCountVec const &vec) const
2408 for(GuildItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end();++itr)
2409 if (itr->Slot == this->Slot)
2410 return true;
2412 return false;