[9581] Fixed apply damage reduction to melee/ranged damage.
[getmangos.git] / src / game / Guild.cpp
bloba709db5ad0dce9f4c68b46b094987e2a407d05d8
1 /*
2 * Copyright (C) 2005-2010 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_GuildBankMoney = 0;
49 m_PurchasedTabs = 0;
51 m_GuildEventLogNextGuid = 0;
52 m_GuildBankEventLogNextGuid_Money = 0;
53 for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i)
54 m_GuildBankEventLogNextGuid_Item[i] = 0;
57 Guild::~Guild()
62 bool Guild::Create(Player* leader, std::string gname)
64 if (sObjectMgr.GetGuildByName(gname))
65 return false;
67 WorldSession* lSession = leader->GetSession();
68 if (!lSession)
69 return false;
71 m_LeaderGuid = leader->GetGUID();
72 m_Name = gname;
73 GINFO = "";
74 MOTD = "No message set.";
75 m_GuildBankMoney = 0;
76 m_PurchasedTabs = 0;
77 m_Id = sObjectMgr.GenerateGuildId();
79 sLog.outDebug("GUILD: creating guild %s to leader: %u", gname.c_str(), GUID_LOPART(m_LeaderGuid));
81 // gname already assigned to Guild::name, use it to encode string for DB
82 CharacterDatabase.escape_string(gname);
84 std::string dbGINFO = GINFO;
85 std::string dbMOTD = MOTD;
86 CharacterDatabase.escape_string(dbGINFO);
87 CharacterDatabase.escape_string(dbMOTD);
89 CharacterDatabase.BeginTransaction();
90 // CharacterDatabase.PExecute("DELETE FROM guild WHERE guildid='%u'", Id); - MAX(guildid)+1 not exist
91 CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guildid='%u'", m_Id);
92 CharacterDatabase.PExecute("INSERT INTO guild (guildid,name,leaderguid,info,motd,createdate,EmblemStyle,EmblemColor,BorderStyle,BorderColor,BackgroundColor,BankMoney) "
93 "VALUES('%u','%s','%u', '%s', '%s', UNIX_TIMESTAMP(NOW()),'%u','%u','%u','%u','%u','" UI64FMTD "')",
94 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);
95 CharacterDatabase.CommitTransaction();
97 CreateDefaultGuildRanks(lSession->GetSessionDbLocaleIndex());
99 return AddMember(m_LeaderGuid, (uint32)GR_GUILDMASTER);
102 void Guild::CreateDefaultGuildRanks(int locale_idx)
104 CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", m_Id);
105 CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u'", m_Id);
107 CreateRank(sObjectMgr.GetMangosString(LANG_GUILD_MASTER, locale_idx), GR_RIGHT_ALL);
108 CreateRank(sObjectMgr.GetMangosString(LANG_GUILD_OFFICER, locale_idx), GR_RIGHT_ALL);
109 CreateRank(sObjectMgr.GetMangosString(LANG_GUILD_VETERAN, locale_idx), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
110 CreateRank(sObjectMgr.GetMangosString(LANG_GUILD_MEMBER, locale_idx), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
111 CreateRank(sObjectMgr.GetMangosString(LANG_GUILD_INITIATE, locale_idx), GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
113 SetBankMoneyPerDay((uint32)GR_GUILDMASTER, WITHDRAW_MONEY_UNLIMITED);
116 bool Guild::AddMember(uint64 plGuid, uint32 plRank)
118 Player* pl = sObjectMgr.GetPlayer(plGuid);
119 if (pl)
121 if (pl->GetGuildId() != 0)
122 return false;
124 else
126 if (Player::GetGuildIdFromDB(plGuid) != 0) // player already in guild
127 return false;
130 // remove all player signs from another petitions
131 // this will be prevent attempt joining player to many guilds and corrupt guild data integrity
132 Player::RemovePetitionsAndSigns(plGuid, 9);
134 // fill player data
135 MemberSlot newmember;
137 if (pl)
139 newmember.Name = pl->GetName();
140 newmember.Level = pl->getLevel();
141 newmember.Class = pl->getClass();
142 newmember.ZoneId = pl->GetZoneId();
144 else
146 // 0 1 2 3
147 QueryResult *result = CharacterDatabase.PQuery("SELECT name,level,class,zone FROM characters WHERE guid = '%u'", GUID_LOPART(plGuid));
148 if (!result)
149 return false; // player doesn't exist
151 Field *fields = result->Fetch();
152 newmember.Name = fields[0].GetCppString();
153 newmember.Level = fields[1].GetUInt8();
154 newmember.Class = fields[2].GetUInt8();
155 newmember.ZoneId = fields[3].GetUInt32();
156 delete result;
157 if (newmember.Level < 1 || newmember.Level > STRONG_MAX_LEVEL ||
158 newmember.Class < CLASS_WARRIOR || newmember.Class >= MAX_CLASSES)
160 sLog.outError("Player (GUID: %u) has a broken data in field `characters` table, cannot add him to guild.",GUID_LOPART(plGuid));
161 return false;
165 newmember.RankId = plRank;
166 newmember.OFFnote = (std::string)"";
167 newmember.Pnote = (std::string)"";
168 newmember.LogoutTime = time(NULL);
169 newmember.BankResetTimeMoney = 0; // this will force update at first query
170 for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
171 newmember.BankResetTimeTab[i] = 0;
172 members[GUID_LOPART(plGuid)] = newmember;
174 std::string dbPnote = newmember.Pnote;
175 std::string dbOFFnote = newmember.OFFnote;
176 CharacterDatabase.escape_string(dbPnote);
177 CharacterDatabase.escape_string(dbOFFnote);
179 CharacterDatabase.PExecute("INSERT INTO guild_member (guildid,guid,rank,pnote,offnote) VALUES ('%u', '%u', '%u','%s','%s')",
180 m_Id, GUID_LOPART(plGuid), newmember.RankId, dbPnote.c_str(), dbOFFnote.c_str());
182 // If player not in game data in data field will be loaded from guild tables, no need to update it!!
183 if (pl)
185 pl->SetInGuild(m_Id);
186 pl->SetRank(newmember.RankId);
187 pl->SetGuildIdInvited(0);
189 return true;
192 void Guild::SetMOTD(std::string motd)
194 MOTD = motd;
196 // motd now can be used for encoding to DB
197 CharacterDatabase.escape_string(motd);
198 CharacterDatabase.PExecute("UPDATE guild SET motd='%s' WHERE guildid='%u'", motd.c_str(), m_Id);
201 void Guild::SetGINFO(std::string ginfo)
203 GINFO = ginfo;
205 // ginfo now can be used for encoding to DB
206 CharacterDatabase.escape_string(ginfo);
207 CharacterDatabase.PExecute("UPDATE guild SET info='%s' WHERE guildid='%u'", ginfo.c_str(), m_Id);
210 bool Guild::LoadGuildFromDB(QueryResult *guildDataResult)
212 if (!guildDataResult)
213 return false;
215 Field *fields = guildDataResult->Fetch();
217 m_Id = fields[0].GetUInt32();
218 m_Name = fields[1].GetCppString();
219 m_LeaderGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER);
220 m_EmblemStyle = fields[3].GetUInt32();
221 m_EmblemColor = fields[4].GetUInt32();
222 m_BorderStyle = fields[5].GetUInt32();
223 m_BorderColor = fields[6].GetUInt32();
224 m_BackgroundColor = fields[7].GetUInt32();
225 GINFO = fields[8].GetCppString();
226 MOTD = fields[9].GetCppString();
227 time_t time = fields[10].GetUInt64();
228 m_GuildBankMoney = fields[11].GetUInt64();
229 m_PurchasedTabs = fields[12].GetUInt32();
231 if (m_PurchasedTabs > GUILD_BANK_MAX_TABS)
232 m_PurchasedTabs = GUILD_BANK_MAX_TABS;
234 if (time > 0)
236 tm local = *(localtime(&time)); // dereference and assign
237 m_CreatedDay = local.tm_mday;
238 m_CreatedMonth = local.tm_mon + 1;
239 m_CreatedYear = local.tm_year + 1900;
242 return true;
245 bool Guild::CheckGuildStructure()
247 // Repair the structure of guild
248 // If the guildmaster doesn't exist or isn't the member of guild
249 // attempt to promote another member
250 int32 GM_rights = GetRank(GUID_LOPART(m_LeaderGuid));
251 if (GM_rights == -1)
253 DelMember(m_LeaderGuid);
254 // check no members case (disbanded)
255 if (members.empty())
256 return false;
258 else if (GM_rights != GR_GUILDMASTER)
259 SetLeader(m_LeaderGuid);
261 // Allow only 1 guildmaster
262 for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
264 if (itr->second.RankId == GR_GUILDMASTER && GUID_LOPART(m_LeaderGuid) != itr->first)
265 //set right of member to officer
266 ChangeRank(itr->first, GR_OFFICER);
269 return true;
272 bool Guild::LoadRanksFromDB(QueryResult *guildRanksResult)
274 if (!guildRanksResult)
276 sLog.outError("Guild %u has broken `guild_rank` data, creating new...",m_Id);
277 CreateDefaultGuildRanks(0);
278 return true;
281 Field *fields;
282 bool broken_ranks = false;
284 // GUILD RANKS are sequence starting from 0 = GUILD_MASTER (ALL PRIVILEGES) to max 9 (lowest privileges)
285 // the lower rank id is considered higher rank - so promotion does rank-- and demotion does rank++
286 // between ranks in sequence cannot be gaps - so 0,1,2,4 cannot be
287 // min ranks count is 5 and max is 10.
291 fields = guildRanksResult->Fetch();
292 //condition that would be true when all ranks in QueryResult will be processed and guild without ranks is being processed
293 if (!fields)
294 break;
296 uint32 guildId = fields[0].GetUInt32();
297 if (guildId < m_Id)
299 //there is in table guild_rank record which doesn't have guildid in guild table, report error
300 sLog.outErrorDb("Guild %u does not exist but it has a record in guild_rank table, deleting it!", guildId);
301 CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid = '%u'", guildId);
302 continue;
305 if (guildId > m_Id) //we loaded all ranks for this guild already, break cycle
306 break;
308 uint32 rankID = fields[1].GetUInt32();
309 std::string rankName = fields[2].GetCppString();
310 uint32 rankRights = fields[3].GetUInt32();
311 uint32 rankMoney = fields[4].GetUInt32();
313 if (rankID != m_Ranks.size()) // guild_rank.ids are sequence 0,1,2,3..
314 broken_ranks = true;
316 // first rank is guildmaster, prevent loss leader rights
317 if (m_Ranks.empty())
318 rankRights |= GR_RIGHT_ALL;
320 AddRank(rankName, rankRights, rankMoney);
321 } while( guildRanksResult->NextRow() );
323 if (m_Ranks.size() < GUILD_RANKS_MIN_COUNT) // if too few ranks, renew them
325 m_Ranks.clear();
326 sLog.outError("Guild %u has broken `guild_rank` data, creating new...", m_Id);
327 CreateDefaultGuildRanks(0); // 0 is default locale_idx
328 broken_ranks = false;
330 // guild_rank have wrong numbered ranks, repair
331 if (broken_ranks)
333 sLog.outError("Guild %u has broken `guild_rank` data, repairing...", m_Id);
334 CharacterDatabase.BeginTransaction();
335 CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", m_Id);
336 for(size_t i = 0; i < m_Ranks.size(); ++i)
338 std::string name = m_Ranks[i].Name;
339 uint32 rights = m_Ranks[i].Rights;
340 CharacterDatabase.escape_string(name);
341 CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", m_Id, uint32(i), name.c_str(), rights);
343 CharacterDatabase.CommitTransaction();
346 return true;
349 bool Guild::LoadMembersFromDB(QueryResult *guildMembersResult)
351 if (!guildMembersResult)
352 return false;
356 Field *fields = guildMembersResult->Fetch();
357 // this condition will be true when all rows in QueryResult are processed and new guild without members is going to be loaded - prevent crash
358 if (!fields)
359 break;
360 uint32 guildId = fields[0].GetUInt32();
361 if (guildId < m_Id)
363 // there is in table guild_member record which doesn't have guildid in guild table, report error
364 sLog.outErrorDb("Guild %u does not exist but it has a record in guild_member table, deleting it!", guildId);
365 CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guildid = '%u'", guildId);
366 continue;
369 if (guildId > m_Id)
370 // we loaded all members for this guild already, break cycle
371 break;
373 MemberSlot newmember;
374 uint64 guid = MAKE_NEW_GUID(fields[1].GetUInt32(), 0, HIGHGUID_PLAYER);
375 newmember.RankId = fields[2].GetUInt32();
376 // don't allow member to have not existing rank!
377 if (newmember.RankId >= m_Ranks.size())
378 newmember.RankId = GetLowestRank();
380 newmember.Pnote = fields[3].GetCppString();
381 newmember.OFFnote = fields[4].GetCppString();
382 newmember.BankResetTimeMoney = fields[5].GetUInt32();
383 newmember.BankRemMoney = fields[6].GetUInt32();
384 for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
386 newmember.BankResetTimeTab[i] = fields[7+(2*i)].GetUInt32();
387 newmember.BankRemSlotsTab[i] = fields[8+(2*i)].GetUInt32();
390 newmember.Name = fields[19].GetCppString();
391 newmember.Level = fields[20].GetUInt8();
392 newmember.Class = fields[21].GetUInt8();
393 newmember.ZoneId = fields[22].GetUInt32();
394 newmember.LogoutTime = fields[23].GetUInt64();
396 // this code will remove not existing character guids from guild
397 if (newmember.Level < 1 || newmember.Level > STRONG_MAX_LEVEL) // can be at broken `data` field
399 sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`data`, deleting him from guild!",GUID_LOPART(guid));
400 CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid));
401 continue;
403 if (!newmember.ZoneId)
405 sLog.outError("Player (GUID: %u) has broken zone-data", GUID_LOPART(guid));
406 // here it will also try the same, to get the zone from characters-table, but additional it tries to find
407 // the zone through xy coords .. this is a bit redundant, but shouldn't be called often
408 newmember.ZoneId = Player::GetZoneIdFromDB(guid);
410 if (newmember.Class < CLASS_WARRIOR || newmember.Class >= MAX_CLASSES) // can be at broken `class` field
412 sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`class`, deleting him from guild!",GUID_LOPART(guid));
413 CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid));
414 continue;
417 members[GUID_LOPART(guid)] = newmember;
419 } while (guildMembersResult->NextRow());
421 if (members.empty())
422 return false;
424 return true;
427 void Guild::SetMemberStats(uint64 guid)
429 MemberList::iterator itr = members.find(GUID_LOPART(guid));
430 if (itr == members.end() )
431 return;
433 Player *pl = ObjectAccessor::FindPlayer(guid);
434 if (!pl)
435 return;
436 itr->second.Name = pl->GetName();
437 itr->second.Level = pl->getLevel();
438 itr->second.Class = pl->getClass();
439 itr->second.ZoneId = pl->GetZoneId();
442 void Guild::SetLeader(uint64 guid)
444 m_LeaderGuid = guid;
445 ChangeRank(guid, GR_GUILDMASTER);
447 CharacterDatabase.PExecute("UPDATE guild SET leaderguid='%u' WHERE guildid='%u'", GUID_LOPART(guid), m_Id);
450 void Guild::DelMember(uint64 guid, bool isDisbanding)
452 // guild master can be deleted when loading guild and guid doesn't exist in characters table
453 // or when he is removed from guild by gm command
454 if (m_LeaderGuid == guid && !isDisbanding)
456 MemberSlot* oldLeader = NULL;
457 MemberSlot* best = NULL;
458 uint64 newLeaderGUID = 0;
459 for (Guild::MemberList::iterator i = members.begin(); i != members.end(); ++i)
461 if (i->first == GUID_LOPART(guid))
463 oldLeader = &(i->second);
464 continue;
467 if (!best || best->RankId > i->second.RankId)
469 best = &(i->second);
470 newLeaderGUID = i->first;
473 if (!best)
475 Disband();
476 return;
479 SetLeader(newLeaderGUID);
481 // If player not online data in data field will be loaded from guild tabs no need to update it !!
482 if (Player *newLeader = sObjectMgr.GetPlayer(newLeaderGUID))
483 newLeader->SetRank(GR_GUILDMASTER);
485 // when leader non-exist (at guild load with deleted leader only) not send broadcasts
486 if (oldLeader)
488 BroadcastEvent(GE_LEADER_CHANGED, 0, 2, oldLeader->Name, best->Name, "");
490 BroadcastEvent(GE_LEFT, guid, 1, oldLeader->Name, "", "");
494 members.erase(GUID_LOPART(guid));
496 Player *player = sObjectMgr.GetPlayer(guid);
497 // If player not online data in data field will be loaded from guild tabs no need to update it !!
498 if (player)
500 player->SetInGuild(0);
501 player->SetRank(0);
504 CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid));
507 void Guild::ChangeRank(uint64 guid, uint32 newRank)
509 MemberList::iterator itr = members.find(GUID_LOPART(guid));
510 if (itr != members.end())
511 itr->second.RankId = newRank;
513 Player *player = sObjectMgr.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)
516 player->SetRank(newRank);
518 CharacterDatabase.PExecute( "UPDATE guild_member SET rank='%u' WHERE guid='%u'", newRank, GUID_LOPART(guid) );
521 void Guild::SetPNOTE(uint64 guid,std::string pnote)
523 MemberList::iterator itr = members.find(GUID_LOPART(guid));
524 if (itr == members.end())
525 return;
527 itr->second.Pnote = pnote;
529 // pnote now can be used for encoding to DB
530 CharacterDatabase.escape_string(pnote);
531 CharacterDatabase.PExecute("UPDATE guild_member SET pnote = '%s' WHERE guid = '%u'", pnote.c_str(), itr->first);
534 void Guild::SetOFFNOTE(uint64 guid,std::string offnote)
536 MemberList::iterator itr = members.find(GUID_LOPART(guid));
537 if (itr == members.end())
538 return;
539 itr->second.OFFnote = offnote;
540 // offnote now can be used for encoding to DB
541 CharacterDatabase.escape_string(offnote);
542 CharacterDatabase.PExecute("UPDATE guild_member SET offnote = '%s' WHERE guid = '%u'", offnote.c_str(), itr->first);
545 void Guild::BroadcastToGuild(WorldSession *session, const std::string& msg, uint32 language)
547 if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(),GR_RIGHT_GCHATSPEAK))
549 WorldPacket data;
550 ChatHandler(session).FillMessageData(&data, CHAT_MSG_GUILD, language, 0, msg.c_str());
552 for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
554 Player *pl = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first));
556 if (pl && pl->GetSession() && HasRankRight(pl->GetRank(),GR_RIGHT_GCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow()) )
557 pl->GetSession()->SendPacket(&data);
562 void Guild::BroadcastToOfficers(WorldSession *session, const std::string& msg, uint32 language)
564 if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(), GR_RIGHT_OFFCHATSPEAK))
566 for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
568 WorldPacket data;
569 ChatHandler::FillMessageData(&data, session, CHAT_MSG_OFFICER, language, NULL, 0, msg.c_str(), NULL);
571 Player *pl = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first));
573 if (pl && pl->GetSession() && HasRankRight(pl->GetRank(),GR_RIGHT_OFFCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow()))
574 pl->GetSession()->SendPacket(&data);
579 void Guild::BroadcastPacket(WorldPacket *packet)
581 for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
583 Player *player = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first));
584 if (player)
585 player->GetSession()->SendPacket(packet);
589 void Guild::BroadcastPacketToRank(WorldPacket *packet, uint32 rankId)
591 for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
593 if (itr->second.RankId == rankId)
595 Player *player = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first));
596 if (player)
597 player->GetSession()->SendPacket(packet);
602 void Guild::CreateRank(std::string name_,uint32 rights)
604 if (m_Ranks.size() >= GUILD_RANKS_MAX_COUNT)
605 return;
607 // ranks are sequence 0,1,2,... where 0 means guildmaster
608 uint32 new_rank_id = m_Ranks.size();
610 AddRank(name_, rights, 0);
612 // existing records in db should be deleted before calling this procedure and m_PurchasedTabs must be loaded already
614 for (uint32 i = 0; i < m_PurchasedTabs; ++i)
616 // create bank rights with 0
617 CharacterDatabase.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid) VALUES ('%u','%u','%u')", m_Id, i, new_rank_id);
619 // name now can be used for encoding to DB
620 CharacterDatabase.escape_string(name_);
621 CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", m_Id, new_rank_id, name_.c_str(), rights );
624 void Guild::AddRank(const std::string& name_,uint32 rights, uint32 money)
626 m_Ranks.push_back(RankInfo(name_,rights,money));
629 void Guild::DelRank()
631 // client won't allow to have less than GUILD_RANKS_MIN_COUNT ranks in guild
632 if (m_Ranks.size() <= GUILD_RANKS_MIN_COUNT)
633 return;
635 // delete lowest guild_rank
636 uint32 rank = GetLowestRank();
637 CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE rid>='%u' AND guildid='%u'", rank, m_Id);
638 CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE rid>='%u' AND guildid='%u'", rank, m_Id);
640 m_Ranks.pop_back();
643 std::string Guild::GetRankName(uint32 rankId)
645 if (rankId >= m_Ranks.size())
646 return "<unknown>";
648 return m_Ranks[rankId].Name;
651 uint32 Guild::GetRankRights(uint32 rankId)
653 if (rankId >= m_Ranks.size())
654 return 0;
656 return m_Ranks[rankId].Rights;
659 void Guild::SetRankName(uint32 rankId, std::string name_)
661 if (rankId >= m_Ranks.size())
662 return;
664 m_Ranks[rankId].Name = name_;
666 // name now can be used for encoding to DB
667 CharacterDatabase.escape_string(name_);
668 CharacterDatabase.PExecute("UPDATE guild_rank SET rname='%s' WHERE rid='%u' AND guildid='%u'", name_.c_str(), rankId, m_Id);
671 void Guild::SetRankRights(uint32 rankId, uint32 rights)
673 if (rankId >= m_Ranks.size())
674 return;
676 m_Ranks[rankId].Rights = rights;
678 CharacterDatabase.PExecute("UPDATE guild_rank SET rights='%u' WHERE rid='%u' AND guildid='%u'", rights, rankId, m_Id);
681 int32 Guild::GetRank(uint32 LowGuid)
683 MemberList::const_iterator itr = members.find(LowGuid);
684 if (itr == members.end())
685 return -1;
687 return itr->second.RankId;
690 void Guild::Disband()
692 BroadcastEvent(GE_DISBANDED, 0, 0, "", "", "");
694 while (!members.empty())
696 MemberList::const_iterator itr = members.begin();
697 DelMember(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER), true);
700 CharacterDatabase.BeginTransaction();
701 CharacterDatabase.PExecute("DELETE FROM guild WHERE guildid = '%u'", m_Id);
702 CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid = '%u'", m_Id);
703 CharacterDatabase.PExecute("DELETE FROM guild_bank_tab WHERE guildid = '%u'", m_Id);
704 // TODO item_instance should be deleted ?
705 CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u'", m_Id);
706 CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u'", m_Id);
707 CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid = '%u'", m_Id);
708 CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid = '%u'", m_Id);
709 CharacterDatabase.CommitTransaction();
710 sObjectMgr.RemoveGuild(m_Id);
713 void Guild::Roster(WorldSession *session /*= NULL*/)
715 // we can only guess size
716 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));
717 data << uint32(members.size());
718 data << MOTD;
719 data << GINFO;
721 data << uint32(m_Ranks.size());
722 for (RankList::const_iterator ritr = m_Ranks.begin(); ritr != m_Ranks.end(); ++ritr)
724 data << uint32(ritr->Rights);
725 data << uint32(ritr->BankMoneyPerDay); // count of: withdraw gold(gold/day) Note: in game set gold, in packet set bronze.
726 for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
728 data << uint32(ritr->TabRight[i]); // for TAB_i rights: view tabs = 0x01, deposit items =0x02
729 data << uint32(ritr->TabSlotPerDay[i]); // for TAB_i count of: withdraw items(stack/day)
732 for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
734 if (Player *pl = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first)))
736 data << uint64(pl->GetGUID());
737 data << uint8(1);
738 data << pl->GetName();
739 data << uint32(itr->second.RankId);
740 data << uint8(pl->getLevel());
741 data << uint8(pl->getClass());
742 data << uint8(0); // new 2.4.0
743 data << uint32(pl->GetZoneId());
744 data << itr->second.Pnote;
745 data << itr->second.OFFnote;
747 else
749 data << ObjectGuid(HIGHGUID_PLAYER, itr->first);
750 data << uint8(0);
751 data << itr->second.Name;
752 data << uint32(itr->second.RankId);
753 data << uint8(itr->second.Level);
754 data << uint8(itr->second.Class);
755 data << uint8(0); // new 2.4.0
756 data << uint32(itr->second.ZoneId);
757 data << float(float(time(NULL)-itr->second.LogoutTime) / DAY);
758 data << itr->second.Pnote;
759 data << itr->second.OFFnote;
762 if (session)
763 session->SendPacket(&data);
764 else
765 BroadcastPacket(&data);
766 sLog.outDebug( "WORLD: Sent (SMSG_GUILD_ROSTER)" );
769 void Guild::Query(WorldSession *session)
771 WorldPacket data(SMSG_GUILD_QUERY_RESPONSE, (8*32+200));// we can only guess size
773 data << uint32(m_Id);
774 data << m_Name;
776 for (size_t i = 0 ; i < GUILD_RANKS_MAX_COUNT; ++i) // show always 10 ranks
778 if (i < m_Ranks.size())
779 data << m_Ranks[i].Name;
780 else
781 data << uint8(0); // null string
784 data << uint32(m_EmblemStyle);
785 data << uint32(m_EmblemColor);
786 data << uint32(m_BorderStyle);
787 data << uint32(m_BorderColor);
788 data << uint32(m_BackgroundColor);
789 data << uint32(0); // probably real ranks count
791 session->SendPacket( &data );
792 sLog.outDebug( "WORLD: Sent (SMSG_GUILD_QUERY_RESPONSE)" );
795 void Guild::SetEmblem(uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor)
797 m_EmblemStyle = emblemStyle;
798 m_EmblemColor = emblemColor;
799 m_BorderStyle = borderStyle;
800 m_BorderColor = borderColor;
801 m_BackgroundColor = backgroundColor;
803 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);
806 void Guild::UpdateLogoutTime(uint64 guid)
808 MemberList::iterator itr = members.find(GUID_LOPART(guid));
809 if (itr == members.end() )
810 return;
812 itr->second.LogoutTime = time(NULL);
815 // *************************************************
816 // Guild Eventlog part
817 // *************************************************
818 // Display guild eventlog
819 void Guild::DisplayGuildEventLog(WorldSession *session)
821 // Sending result
822 WorldPacket data(MSG_GUILD_EVENT_LOG_QUERY, 0);
823 // count, max count == 100
824 data << uint8(m_GuildEventLog.size());
825 for (GuildEventLog::const_iterator itr = m_GuildEventLog.begin(); itr != m_GuildEventLog.end(); ++itr)
827 // Event type
828 data << uint8(itr->EventType);
829 // Player 1
830 data << uint64(itr->PlayerGuid1);
831 // Player 2 not for left/join guild events
832 if (itr->EventType != GUILD_EVENT_LOG_JOIN_GUILD && itr->EventType != GUILD_EVENT_LOG_LEAVE_GUILD)
833 data << uint64(itr->PlayerGuid2);
834 // New Rank - only for promote/demote guild events
835 if (itr->EventType == GUILD_EVENT_LOG_PROMOTE_PLAYER || itr->EventType == GUILD_EVENT_LOG_DEMOTE_PLAYER)
836 data << uint8(itr->NewRank);
837 // Event timestamp
838 data << uint32(time(NULL)-itr->TimeStamp);
840 session->SendPacket(&data);
841 sLog.outDebug("WORLD: Sent (MSG_GUILD_EVENT_LOG_QUERY)");
844 // Load guild eventlog from DB
845 void Guild::LoadGuildEventLogFromDB()
847 // 0 1 2 3 4 5
848 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);
849 if (!result)
850 return;
851 bool isNextLogGuidSet = false;
852 //uint32 configCount = sWorld.getConfig(CONFIG_UINT32_GUILD_EVENT_LOG_COUNT);
853 // First event in list will be the oldest and the latest event is last event in list
856 Field *fields = result->Fetch();
857 if (!isNextLogGuidSet)
859 m_GuildEventLogNextGuid = fields[0].GetUInt32();
860 isNextLogGuidSet = true;
862 // Fill entry
863 GuildEventLogEntry NewEvent;
864 NewEvent.EventType = fields[1].GetUInt8();
865 NewEvent.PlayerGuid1 = fields[2].GetUInt32();
866 NewEvent.PlayerGuid2 = fields[3].GetUInt32();
867 NewEvent.NewRank = fields[4].GetUInt8();
868 NewEvent.TimeStamp = fields[5].GetUInt64();
870 // There can be a problem if more events have same TimeStamp the ORDER can be broken when fields[0].GetUInt32() == configCount, but
871 // events with same timestamp can appear when there is lag, and we naivly suppose that mangos isn't laggy
872 // but if problem appears, player will see set of guild events that have same timestamp in bad order
874 // Add entry to list
875 m_GuildEventLog.push_front(NewEvent);
877 } while( result->NextRow() );
878 delete result;
881 // Add entry to guild eventlog
882 void Guild::LogGuildEvent(uint8 EventType, uint32 PlayerGuid1, uint32 PlayerGuid2, uint8 NewRank)
884 GuildEventLogEntry NewEvent;
885 // Create event
886 NewEvent.EventType = EventType;
887 NewEvent.PlayerGuid1 = PlayerGuid1;
888 NewEvent.PlayerGuid2 = PlayerGuid2;
889 NewEvent.NewRank = NewRank;
890 NewEvent.TimeStamp = uint32(time(NULL));
891 // Count new LogGuid
892 m_GuildEventLogNextGuid = (m_GuildEventLogNextGuid + 1) % sWorld.getConfig(CONFIG_UINT32_GUILD_EVENT_LOG_COUNT);
893 // Check max records limit
894 if (m_GuildEventLog.size() >= GUILD_EVENTLOG_MAX_RECORDS)
895 m_GuildEventLog.pop_front();
896 // Add event to list
897 m_GuildEventLog.push_back(NewEvent);
898 // Save event to DB
899 CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid='%u' AND LogGuid='%u'", m_Id, m_GuildEventLogNextGuid);
900 CharacterDatabase.PExecute("INSERT INTO guild_eventlog (guildid, LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','" UI64FMTD "')",
901 m_Id, m_GuildEventLogNextGuid, uint32(NewEvent.EventType), NewEvent.PlayerGuid1, NewEvent.PlayerGuid2, uint32(NewEvent.NewRank), NewEvent.TimeStamp);
904 // *************************************************
905 // Guild Bank part
906 // *************************************************
907 // Bank content related
908 void Guild::DisplayGuildBankContent(WorldSession *session, uint8 TabId)
910 GuildBankTab const* tab = m_TabListMap[TabId];
912 if (!IsMemberHaveRights(session->GetPlayer()->GetGUIDLow(), TabId, GUILD_BANK_RIGHT_VIEW_TAB))
913 return;
915 WorldPacket data(SMSG_GUILD_BANK_LIST, 1200);
917 data << uint64(GetGuildBankMoney());
918 data << uint8(TabId);
919 // remaining slots for today
920 data << uint32(GetMemberSlotWithdrawRem(session->GetPlayer()->GetGUIDLow(), TabId));
921 data << uint8(0); // Tell client that there's no tab info in this packet
923 data << uint8(GUILD_BANK_MAX_SLOTS);
925 for (int i = 0; i < GUILD_BANK_MAX_SLOTS; ++i)
926 AppendDisplayGuildBankSlot(data, tab, i);
928 session->SendPacket(&data);
930 sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
933 void Guild::DisplayGuildBankMoneyUpdate(WorldSession *session)
935 WorldPacket data(SMSG_GUILD_BANK_LIST, 8+1+4+1+1);
937 data << uint64(GetGuildBankMoney());
938 data << uint8(0); // TabId, default 0
939 data << uint32(GetMemberSlotWithdrawRem(session->GetPlayer()->GetGUIDLow(), 0));
940 data << uint8(0); // Tell that there's no tab info in this packet
941 data << uint8(0); // not send items
942 BroadcastPacket(&data);
944 sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
947 void Guild::DisplayGuildBankContentUpdate(uint8 TabId, int32 slot1, int32 slot2)
949 GuildBankTab const* tab = m_TabListMap[TabId];
951 WorldPacket data(SMSG_GUILD_BANK_LIST, 1200);
953 data << uint64(GetGuildBankMoney());
954 data << uint8(TabId);
956 size_t rempos = data.wpos();
957 data << uint32(0); // item withdraw amount, will be filled later
958 data << uint8(0); // Tell client that there's no tab info in this packet
960 if (slot2 == -1) // single item in slot1
962 data << uint8(1); // item count
964 AppendDisplayGuildBankSlot(data, tab, slot1);
966 else // 2 items (in slot1 and slot2)
968 data << uint8(2); // item count
970 if (slot1 > slot2)
971 std::swap(slot1, slot2);
973 AppendDisplayGuildBankSlot(data, tab, slot1);
974 AppendDisplayGuildBankSlot(data, tab, slot2);
977 for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
979 Player *player = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first));
980 if (!player)
981 continue;
983 if (!IsMemberHaveRights(itr->first,TabId,GUILD_BANK_RIGHT_VIEW_TAB))
984 continue;
986 data.put<uint32>(rempos, uint32(GetMemberSlotWithdrawRem(player->GetGUIDLow(), TabId)));
988 player->GetSession()->SendPacket(&data);
991 sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
994 void Guild::DisplayGuildBankContentUpdate(uint8 TabId, GuildItemPosCountVec const& slots)
996 GuildBankTab const* tab = m_TabListMap[TabId];
998 WorldPacket data(SMSG_GUILD_BANK_LIST, 1200);
1000 data << uint64(GetGuildBankMoney());
1001 data << uint8(TabId);
1003 size_t rempos = data.wpos();
1004 data << uint32(0); // item withdraw amount, will be filled later
1005 data << uint8(0); // Tell client that there's no tab info in this packet
1007 data << uint8(slots.size()); // updates count
1009 for (GuildItemPosCountVec::const_iterator itr = slots.begin(); itr != slots.end(); ++itr)
1010 AppendDisplayGuildBankSlot(data, tab, itr->Slot);
1012 for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
1014 Player *player = ObjectAccessor::FindPlayer(ObjectGuid(HIGHGUID_PLAYER, itr->first));
1015 if (!player)
1016 continue;
1018 if (!IsMemberHaveRights(itr->first,TabId,GUILD_BANK_RIGHT_VIEW_TAB))
1019 continue;
1021 data.put<uint32>(rempos,uint32(GetMemberSlotWithdrawRem(player->GetGUIDLow(), TabId)));
1023 player->GetSession()->SendPacket(&data);
1026 sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1029 Item* Guild::GetItem(uint8 TabId, uint8 SlotId)
1031 if (TabId >= m_TabListMap.size() || SlotId >= GUILD_BANK_MAX_SLOTS)
1032 return NULL;
1033 return m_TabListMap[TabId]->Slots[SlotId];
1036 // *************************************************
1037 // Tab related
1039 void Guild::DisplayGuildBankTabsInfo(WorldSession *session)
1041 WorldPacket data(SMSG_GUILD_BANK_LIST, 500);
1043 data << uint64(GetGuildBankMoney());
1044 data << uint8(0); // TabInfo packet must be for TabId 0
1045 data << uint32(GetMemberSlotWithdrawRem(session->GetPlayer()->GetGUIDLow(), 0));
1046 data << uint8(1); // Tell client that this packet includes tab info
1048 data << uint8(m_PurchasedTabs); // here is the number of tabs
1050 for (uint8 i = 0; i < m_PurchasedTabs; ++i)
1052 data << m_TabListMap[i]->Name.c_str();
1053 data << m_TabListMap[i]->Icon.c_str();
1055 data << uint8(0); // Do not send tab content
1056 session->SendPacket(&data);
1058 sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1061 void Guild::CreateNewBankTab()
1063 if (m_PurchasedTabs >= GUILD_BANK_MAX_TABS)
1064 return;
1066 ++m_PurchasedTabs;
1068 GuildBankTab* AnotherTab = new GuildBankTab;
1069 memset(AnotherTab->Slots, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*));
1070 m_TabListMap.resize(m_PurchasedTabs);
1071 m_TabListMap[m_PurchasedTabs-1] = AnotherTab;
1073 CharacterDatabase.BeginTransaction();
1074 CharacterDatabase.PExecute("DELETE FROM guild_bank_tab WHERE guildid='%u' AND TabId='%u'", m_Id, uint32(m_PurchasedTabs-1));
1075 CharacterDatabase.PExecute("INSERT INTO guild_bank_tab (guildid,TabId) VALUES ('%u','%u')", m_Id, uint32(m_PurchasedTabs-1));
1076 CharacterDatabase.CommitTransaction();
1079 void Guild::SetGuildBankTabInfo(uint8 TabId, std::string Name, std::string Icon)
1081 if (m_TabListMap[TabId]->Name == Name && m_TabListMap[TabId]->Icon == Icon)
1082 return;
1084 m_TabListMap[TabId]->Name = Name;
1085 m_TabListMap[TabId]->Icon = Icon;
1087 CharacterDatabase.escape_string(Name);
1088 CharacterDatabase.escape_string(Icon);
1089 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));
1092 uint32 Guild::GetBankRights(uint32 rankId, uint8 TabId) const
1094 if (rankId >= m_Ranks.size() || TabId >= GUILD_BANK_MAX_TABS)
1095 return 0;
1097 return m_Ranks[rankId].TabRight[TabId];
1100 // *************************************************
1101 // Guild bank loading related
1103 // This load should be called on startup only
1104 void Guild::LoadGuildBankFromDB()
1106 // 0 1 2 3
1107 QueryResult *result = CharacterDatabase.PQuery("SELECT TabId, TabName, TabIcon, TabText FROM guild_bank_tab WHERE guildid='%u' ORDER BY TabId", m_Id);
1108 if (!result)
1110 m_PurchasedTabs = 0;
1111 return;
1114 m_TabListMap.resize(m_PurchasedTabs);
1117 Field *fields = result->Fetch();
1118 uint8 TabId = fields[0].GetUInt8();
1120 GuildBankTab *NewTab = new GuildBankTab;
1121 memset(NewTab->Slots, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*));
1123 NewTab->Name = fields[1].GetCppString();
1124 NewTab->Icon = fields[2].GetCppString();
1125 NewTab->Text = fields[3].GetCppString();
1127 m_TabListMap[TabId] = NewTab;
1128 } while (result->NextRow());
1130 delete result;
1132 // data needs to be at first place for Item::LoadFromDB
1133 // 0 1 2 3 4
1134 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);
1135 if (!result)
1136 return;
1140 Field *fields = result->Fetch();
1141 uint8 TabId = fields[1].GetUInt8();
1142 uint8 SlotId = fields[2].GetUInt8();
1143 uint32 ItemGuid = fields[3].GetUInt32();
1144 uint32 ItemEntry = fields[4].GetUInt32();
1146 if (TabId >= m_PurchasedTabs || TabId >= GUILD_BANK_MAX_TABS)
1148 sLog.outError( "Guild::LoadGuildBankFromDB: Invalid tab for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry);
1149 continue;
1152 if (SlotId >= GUILD_BANK_MAX_SLOTS)
1154 sLog.outError( "Guild::LoadGuildBankFromDB: Invalid slot for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry);
1155 continue;
1158 ItemPrototype const *proto = ObjectMgr::GetItemPrototype(ItemEntry);
1160 if (!proto)
1162 sLog.outError( "Guild::LoadGuildBankFromDB: Unknown item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry);
1163 continue;
1166 Item *pItem = NewItemOrBag(proto);
1167 if (!pItem->LoadFromDB(ItemGuid, 0, result))
1169 CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'", m_Id, uint32(TabId), uint32(SlotId));
1170 sLog.outError("Item GUID %u not found in item_instance, deleting from Guild Bank!", ItemGuid);
1171 delete pItem;
1172 continue;
1175 pItem->AddToWorld();
1176 m_TabListMap[TabId]->Slots[SlotId] = pItem;
1177 } while (result->NextRow());
1179 delete result;
1182 // *************************************************
1183 // Money deposit/withdraw related
1185 void Guild::SendMoneyInfo(WorldSession *session, uint32 LowGuid)
1187 WorldPacket data(MSG_GUILD_BANK_MONEY_WITHDRAWN, 4);
1188 data << uint32(GetMemberMoneyWithdrawRem(LowGuid));
1189 session->SendPacket(&data);
1190 sLog.outDebug("WORLD: Sent MSG_GUILD_BANK_MONEY_WITHDRAWN");
1193 bool Guild::MemberMoneyWithdraw(uint32 amount, uint32 LowGuid)
1195 uint32 MoneyWithDrawRight = GetMemberMoneyWithdrawRem(LowGuid);
1197 if (MoneyWithDrawRight < amount || GetGuildBankMoney() < amount)
1198 return false;
1200 SetBankMoney(GetGuildBankMoney()-amount);
1202 if (MoneyWithDrawRight < WITHDRAW_MONEY_UNLIMITED)
1204 MemberList::iterator itr = members.find(LowGuid);
1205 if (itr == members.end() )
1206 return false;
1207 itr->second.BankRemMoney -= amount;
1208 CharacterDatabase.PExecute("UPDATE guild_member SET BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'",
1209 itr->second.BankRemMoney, m_Id, LowGuid);
1211 return true;
1214 void Guild::SetBankMoney(int64 money)
1216 if (money < 0) // I don't know how this happens, it does!!
1217 money = 0;
1218 m_GuildBankMoney = money;
1220 CharacterDatabase.PExecute("UPDATE guild SET BankMoney='" UI64FMTD "' WHERE guildid='%u'", money, m_Id);
1223 // *************************************************
1224 // Item per day and money per day related
1226 bool Guild::MemberItemWithdraw(uint8 TabId, uint32 LowGuid)
1228 uint32 SlotsWithDrawRight = GetMemberSlotWithdrawRem(LowGuid, TabId);
1230 if (SlotsWithDrawRight == 0)
1231 return false;
1233 if (SlotsWithDrawRight < WITHDRAW_SLOT_UNLIMITED)
1235 MemberList::iterator itr = members.find(LowGuid);
1236 if (itr == members.end() )
1237 return false;
1238 --itr->second.BankRemSlotsTab[TabId];
1239 CharacterDatabase.PExecute("UPDATE guild_member SET BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'",
1240 uint32(TabId), itr->second.BankRemSlotsTab[TabId], m_Id, LowGuid);
1242 return true;
1245 bool Guild::IsMemberHaveRights(uint32 LowGuid, uint8 TabId, uint32 rights) const
1247 MemberList::const_iterator itr = members.find(LowGuid);
1248 if (itr == members.end() )
1249 return false;
1251 if (itr->second.RankId == GR_GUILDMASTER)
1252 return true;
1254 return (GetBankRights(itr->second.RankId, TabId) & rights) == rights;
1257 uint32 Guild::GetMemberSlotWithdrawRem(uint32 LowGuid, uint8 TabId)
1259 MemberList::iterator itr = members.find(LowGuid);
1260 if (itr == members.end() )
1261 return 0;
1263 if (itr->second.RankId == GR_GUILDMASTER)
1264 return WITHDRAW_SLOT_UNLIMITED;
1266 if ((GetBankRights(itr->second.RankId,TabId) & GUILD_BANK_RIGHT_VIEW_TAB) != GUILD_BANK_RIGHT_VIEW_TAB)
1267 return 0;
1269 uint32 curTime = uint32(time(NULL)/MINUTE);
1270 if (curTime - itr->second.BankResetTimeTab[TabId] >= 24*HOUR/MINUTE)
1272 itr->second.BankResetTimeTab[TabId] = curTime;
1273 itr->second.BankRemSlotsTab[TabId] = GetBankSlotPerDay(itr->second.RankId, TabId);
1274 CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeTab%u='%u', BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'",
1275 uint32(TabId), itr->second.BankResetTimeTab[TabId], uint32(TabId), itr->second.BankRemSlotsTab[TabId], m_Id, LowGuid);
1277 return itr->second.BankRemSlotsTab[TabId];
1280 uint32 Guild::GetMemberMoneyWithdrawRem(uint32 LowGuid)
1282 MemberList::iterator itr = members.find(LowGuid);
1283 if (itr == members.end() )
1284 return 0;
1286 if (itr->second.RankId == GR_GUILDMASTER)
1287 return WITHDRAW_MONEY_UNLIMITED;
1289 uint32 curTime = uint32(time(NULL)/MINUTE); // minutes
1290 // 24 hours
1291 if (curTime > itr->second.BankResetTimeMoney + 24*HOUR/MINUTE)
1293 itr->second.BankResetTimeMoney = curTime;
1294 itr->second.BankRemMoney = GetBankMoneyPerDay(itr->second.RankId);
1295 CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeMoney='%u', BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'",
1296 itr->second.BankResetTimeMoney, itr->second.BankRemMoney, m_Id, LowGuid);
1298 return itr->second.BankRemMoney;
1301 void Guild::SetBankMoneyPerDay(uint32 rankId, uint32 money)
1303 if (rankId >= m_Ranks.size())
1304 return;
1306 if (rankId == GR_GUILDMASTER)
1307 money = WITHDRAW_MONEY_UNLIMITED;
1309 m_Ranks[rankId].BankMoneyPerDay = money;
1311 for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
1312 if (itr->second.RankId == rankId)
1313 itr->second.BankResetTimeMoney = 0;
1315 CharacterDatabase.PExecute("UPDATE guild_rank SET BankMoneyPerDay='%u' WHERE rid='%u' AND guildid='%u'", money, rankId, m_Id);
1316 CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeMoney='0' WHERE guildid='%u' AND rank='%u'", m_Id, rankId);
1319 void Guild::SetBankRightsAndSlots(uint32 rankId, uint8 TabId, uint32 right, uint32 nbSlots, bool db)
1321 if (rankId >= m_Ranks.size() ||
1322 TabId >= GUILD_BANK_MAX_TABS ||
1323 TabId >= m_PurchasedTabs)
1325 // TODO remove next line, It is there just to repair existing bug in deleting guild rank
1326 CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid='%u' AND rid='%u' AND TabId='%u'", m_Id, rankId, TabId);
1327 return;
1330 if (rankId == GR_GUILDMASTER)
1332 nbSlots = WITHDRAW_SLOT_UNLIMITED;
1333 right = GUILD_BANK_RIGHT_FULL;
1336 m_Ranks[rankId].TabSlotPerDay[TabId] = nbSlots;
1337 m_Ranks[rankId].TabRight[TabId] = right;
1339 if (db)
1341 for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
1342 if (itr->second.RankId == rankId)
1343 for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
1344 itr->second.BankResetTimeTab[i] = 0;
1346 CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid='%u' AND TabId='%u' AND rid='%u'", m_Id, uint32(TabId), rankId);
1347 CharacterDatabase.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid,gbright,SlotPerDay) VALUES "
1348 "('%u','%u','%u','%u','%u')", m_Id, uint32(TabId), rankId, m_Ranks[rankId].TabRight[TabId], m_Ranks[rankId].TabSlotPerDay[TabId]);
1349 CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeTab%u='0' WHERE guildid='%u' AND rank='%u'", uint32(TabId), m_Id, rankId);
1353 uint32 Guild::GetBankMoneyPerDay(uint32 rankId)
1355 if (rankId >= m_Ranks.size())
1356 return 0;
1358 if (rankId == GR_GUILDMASTER)
1359 return WITHDRAW_MONEY_UNLIMITED;
1360 return m_Ranks[rankId].BankMoneyPerDay;
1363 uint32 Guild::GetBankSlotPerDay(uint32 rankId, uint8 TabId)
1365 if (rankId >= m_Ranks.size() || TabId >= GUILD_BANK_MAX_TABS)
1366 return 0;
1368 if (rankId == GR_GUILDMASTER)
1369 return WITHDRAW_SLOT_UNLIMITED;
1370 return m_Ranks[rankId].TabSlotPerDay[TabId];
1373 // *************************************************
1374 // Rights per day related
1376 bool Guild::LoadBankRightsFromDB(QueryResult *guildBankTabRightsResult)
1378 if (!guildBankTabRightsResult)
1379 return true;
1383 Field *fields = guildBankTabRightsResult->Fetch();
1384 // prevent crash when all rights in result are already processed
1385 if (!fields)
1386 break;
1387 uint32 guildId = fields[0].GetUInt32();
1388 if (guildId < m_Id)
1390 // there is in table guild_bank_right record which doesn't have guildid in guild table, report error
1391 sLog.outErrorDb("Guild %u does not exist but it has a record in guild_bank_right table, deleting it!", guildId);
1392 CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u'", guildId);
1393 continue;
1396 if (guildId > m_Id)
1397 // we loaded all ranks for this guild bank already, break cycle
1398 break;
1399 uint8 TabId = fields[1].GetUInt8();
1400 uint32 rankId = fields[2].GetUInt32();
1401 uint16 right = fields[3].GetUInt16();
1402 uint16 SlotPerDay = fields[4].GetUInt16();
1404 SetBankRightsAndSlots(rankId, TabId, right, SlotPerDay, false);
1406 } while (guildBankTabRightsResult->NextRow());
1408 return true;
1411 // *************************************************
1412 // Bank log related
1414 void Guild::LoadGuildBankEventLogFromDB()
1416 // Money log is in TabId = GUILD_BANK_MONEY_LOGS_TAB
1418 // uint32 configCount = sWorld.getConfig(CONFIG_UINT32_GUILD_BANK_EVENT_LOG_COUNT);
1419 // cycle through all purchased guild bank item tabs
1420 for (uint32 tabId = 0; tabId < m_PurchasedTabs; ++tabId)
1422 // 0 1 2 3 4 5 6
1423 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);
1424 if (!result)
1425 continue;
1427 bool isNextLogGuidSet = false;
1430 Field *fields = result->Fetch();
1432 GuildBankEventLogEntry NewEvent;
1433 NewEvent.EventType = fields[1].GetUInt8();
1434 NewEvent.PlayerGuid = fields[2].GetUInt32();
1435 NewEvent.ItemOrMoney = fields[3].GetUInt32();
1436 NewEvent.ItemStackCount = fields[4].GetUInt8();
1437 NewEvent.DestTabId = fields[5].GetUInt8();
1438 NewEvent.TimeStamp = fields[6].GetUInt64();
1440 // if newEvent is moneyEvent, move it to moneyEventTab in DB and report error
1441 if (NewEvent.isMoneyEvent())
1443 uint32 logGuid = fields[0].GetUInt32();
1444 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);
1445 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);
1446 continue;
1448 else
1449 // add event to list
1450 // events are ordered from oldest (in beginning) to latest (in the end)
1451 m_GuildBankEventLog_Item[tabId].push_front(NewEvent);
1453 if (!isNextLogGuidSet)
1455 m_GuildBankEventLogNextGuid_Item[tabId] = fields[0].GetUInt32();
1456 // we don't have to do m_GuildBankEventLogNextGuid_Item[tabId] %= configCount; - it will be done when creating new record
1457 isNextLogGuidSet = true;
1459 } while (result->NextRow());
1460 delete result;
1463 // special handle for guild bank money log
1464 // 0 1 2 3 4 5 6
1465 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);
1466 if (!result)
1467 return;
1469 bool isNextMoneyLogGuidSet = false;
1472 Field *fields = result->Fetch();
1473 if (!isNextMoneyLogGuidSet)
1475 m_GuildBankEventLogNextGuid_Money = fields[0].GetUInt32();
1476 // we don't have to do m_GuildBankEventLogNextGuid_Money %= configCount; - it will be done when creating new record
1477 isNextMoneyLogGuidSet = true;
1479 GuildBankEventLogEntry NewEvent;
1481 NewEvent.EventType = fields[1].GetUInt8();
1482 NewEvent.PlayerGuid = fields[2].GetUInt32();
1483 NewEvent.ItemOrMoney = fields[3].GetUInt32();
1484 NewEvent.ItemStackCount = fields[4].GetUInt8();
1485 NewEvent.DestTabId = fields[5].GetUInt8();
1486 NewEvent.TimeStamp = fields[6].GetUInt64();
1488 // if newEvent is not moneyEvent, then report error
1489 if (!NewEvent.isMoneyEvent())
1490 sLog.outError("GuildBankEventLog ERROR: MoneyEvent LogGuid %u for Guild %u is not MoneyEvent - ignoring...", fields[0].GetUInt32(), m_Id);
1491 else
1492 // add event to list
1493 // events are ordered from oldest (in beginning) to latest (in the end)
1494 m_GuildBankEventLog_Money.push_front(NewEvent);
1496 } while (result->NextRow());
1497 delete result;
1500 void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId)
1502 if (TabId > GUILD_BANK_MAX_TABS)
1503 return;
1505 if (TabId == GUILD_BANK_MAX_TABS)
1507 // Here we display money logs
1508 WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, m_GuildBankEventLog_Money.size()*(4*4+1)+1+1);
1509 data << uint8(TabId); // Here GUILD_BANK_MAX_TABS
1510 data << uint8(m_GuildBankEventLog_Money.size()); // number of log entries
1511 for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Money.begin(); itr != m_GuildBankEventLog_Money.end(); ++itr)
1513 data << uint8(itr->EventType);
1514 data << uint64(MAKE_NEW_GUID(itr->PlayerGuid,0,HIGHGUID_PLAYER));
1515 if (itr->EventType == GUILD_BANK_LOG_DEPOSIT_MONEY ||
1516 itr->EventType == GUILD_BANK_LOG_WITHDRAW_MONEY ||
1517 itr->EventType == GUILD_BANK_LOG_REPAIR_MONEY ||
1518 itr->EventType == GUILD_BANK_LOG_UNK1 ||
1519 itr->EventType == GUILD_BANK_LOG_UNK2)
1521 data << uint32(itr->ItemOrMoney);
1523 else
1525 data << uint32(itr->ItemOrMoney);
1526 data << uint32(itr->ItemStackCount);
1527 if (itr->EventType == GUILD_BANK_LOG_MOVE_ITEM || itr->EventType == GUILD_BANK_LOG_MOVE_ITEM2)
1528 data << uint8(itr->DestTabId); // moved tab
1530 data << uint32(time(NULL) - itr->TimeStamp);
1532 session->SendPacket(&data);
1534 else
1536 // here we display current tab logs
1537 WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, m_GuildBankEventLog_Item[TabId].size()*(4*4+1+1)+1+1);
1538 data << uint8(TabId); // Here a real Tab Id
1539 // number of log entries
1540 data << uint8(m_GuildBankEventLog_Item[TabId].size());
1541 for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Item[TabId].begin(); itr != m_GuildBankEventLog_Item[TabId].end(); ++itr)
1543 data << uint8(itr->EventType);
1544 data << uint64(MAKE_NEW_GUID(itr->PlayerGuid,0,HIGHGUID_PLAYER));
1545 if (itr->EventType == GUILD_BANK_LOG_DEPOSIT_MONEY ||
1546 itr->EventType == GUILD_BANK_LOG_WITHDRAW_MONEY ||
1547 itr->EventType == GUILD_BANK_LOG_REPAIR_MONEY ||
1548 itr->EventType == GUILD_BANK_LOG_UNK1 ||
1549 itr->EventType == GUILD_BANK_LOG_UNK2)
1551 data << uint32(itr->ItemOrMoney);
1553 else
1555 data << uint32(itr->ItemOrMoney);
1556 data << uint32(itr->ItemStackCount);
1557 if (itr->EventType == GUILD_BANK_LOG_MOVE_ITEM || itr->EventType == GUILD_BANK_LOG_MOVE_ITEM2)
1558 data << uint8(itr->DestTabId); // moved tab
1560 data << uint32(time(NULL) - itr->TimeStamp);
1562 session->SendPacket(&data);
1564 sLog.outDebug("WORLD: Sent (MSG_GUILD_BANK_LOG_QUERY)");
1567 void Guild::LogBankEvent(uint8 EventType, uint8 TabId, uint32 PlayerGuidLow, uint32 ItemOrMoney, uint8 ItemStackCount, uint8 DestTabId)
1569 // create Event
1570 GuildBankEventLogEntry NewEvent;
1571 NewEvent.EventType = EventType;
1572 NewEvent.PlayerGuid = PlayerGuidLow;
1573 NewEvent.ItemOrMoney = ItemOrMoney;
1574 NewEvent.ItemStackCount = ItemStackCount;
1575 NewEvent.DestTabId = DestTabId;
1576 NewEvent.TimeStamp = uint32(time(NULL));
1578 // add new event to the end of event list
1579 uint32 currentTabId = TabId;
1580 uint32 currentLogGuid = 0;
1581 if (NewEvent.isMoneyEvent())
1583 m_GuildBankEventLogNextGuid_Money = (m_GuildBankEventLogNextGuid_Money + 1) % sWorld.getConfig(CONFIG_UINT32_GUILD_BANK_EVENT_LOG_COUNT);
1584 currentLogGuid = m_GuildBankEventLogNextGuid_Money;
1585 currentTabId = GUILD_BANK_MONEY_LOGS_TAB;
1586 if (m_GuildBankEventLog_Money.size() >= GUILD_BANK_MAX_LOGS)
1587 m_GuildBankEventLog_Money.pop_front();
1589 m_GuildBankEventLog_Money.push_back(NewEvent);
1591 else
1593 m_GuildBankEventLogNextGuid_Item[TabId] = ((m_GuildBankEventLogNextGuid_Item[TabId]) + 1) % sWorld.getConfig(CONFIG_UINT32_GUILD_BANK_EVENT_LOG_COUNT);
1594 currentLogGuid = m_GuildBankEventLogNextGuid_Item[TabId];
1595 if (m_GuildBankEventLog_Item[TabId].size() >= GUILD_BANK_MAX_LOGS)
1596 m_GuildBankEventLog_Item[TabId].pop_front();
1598 m_GuildBankEventLog_Item[TabId].push_back(NewEvent);
1601 // save event to database
1602 CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u' AND TabId='%u'", m_Id, currentLogGuid, currentTabId);
1604 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 "')",
1605 m_Id, currentLogGuid, currentTabId, uint32(NewEvent.EventType), NewEvent.PlayerGuid, NewEvent.ItemOrMoney, uint32(NewEvent.ItemStackCount), uint32(NewEvent.DestTabId), NewEvent.TimeStamp);
1608 bool Guild::AddGBankItemToDB(uint32 GuildId, uint32 BankTab , uint32 BankTabSlot , uint32 GUIDLow, uint32 Entry )
1610 CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u' AND TabId = '%u'AND SlotId = '%u'", GuildId, BankTab, BankTabSlot);
1611 CharacterDatabase.PExecute("INSERT INTO guild_bank_item (guildid,TabId,SlotId,item_guid,item_entry) "
1612 "VALUES ('%u', '%u', '%u', '%u', '%u')", GuildId, BankTab, BankTabSlot, GUIDLow, Entry);
1613 return true;
1616 void Guild::AppendDisplayGuildBankSlot( WorldPacket& data, GuildBankTab const *tab, int slot )
1618 Item *pItem = tab->Slots[slot];
1619 uint32 entry = pItem ? pItem->GetEntry() : 0;
1621 data << uint8(slot);
1622 data << uint32(entry);
1623 if (entry)
1625 data << uint32(0); // 3.3.0 (0x8000, 0x8020)
1626 data << uint32(pItem->GetItemRandomPropertyId()); // random item property id + 8
1628 if (pItem->GetItemRandomPropertyId())
1629 data << uint32(pItem->GetItemSuffixFactor()); // SuffixFactor + 4
1631 data << uint32(pItem->GetCount()); // +12 ITEM_FIELD_STACK_COUNT
1632 data << uint32(0); // +16 Unknown value
1633 data << uint8(0); // +20
1635 uint8 enchCount = 0;
1636 size_t enchCountPos = data.wpos();
1638 data << uint8(enchCount); // number of enchantments
1639 for(uint32 i = PERM_ENCHANTMENT_SLOT; i < MAX_ENCHANTMENT_SLOT; ++i)
1641 if(uint32 enchId = pItem->GetEnchantmentId(EnchantmentSlot(i)))
1643 data << uint8(i);
1644 data << uint32(enchId);
1645 ++enchCount;
1648 data.put<uint8>(enchCountPos, enchCount);
1652 Item* Guild::StoreItem(uint8 tabId, GuildItemPosCountVec const& dest, Item* pItem )
1654 if (!pItem)
1655 return NULL;
1657 Item* lastItem = pItem;
1659 for (GuildItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); )
1661 uint8 slot = itr->Slot;
1662 uint32 count = itr->Count;
1664 ++itr;
1666 if (itr == dest.end())
1668 lastItem = _StoreItem(tabId, slot, pItem, count, false);
1669 break;
1672 lastItem = _StoreItem(tabId, slot, pItem, count, true);
1675 return lastItem;
1678 // Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
1679 Item* Guild::_StoreItem( uint8 tab, uint8 slot, Item *pItem, uint32 count, bool clone )
1681 if (!pItem)
1682 return NULL;
1684 sLog.outDebug( "GUILD STORAGE: StoreItem tab = %u, slot = %u, item = %u, count = %u", tab, slot, pItem->GetEntry(), count);
1686 Item* pItem2 = m_TabListMap[tab]->Slots[slot];
1688 if (!pItem2)
1690 if (clone)
1691 pItem = pItem->CloneItem(count);
1692 else
1693 pItem->SetCount(count);
1695 if (!pItem)
1696 return NULL;
1698 m_TabListMap[tab]->Slots[slot] = pItem;
1700 pItem->SetUInt64Value(ITEM_FIELD_CONTAINED, 0);
1701 pItem->SetUInt64Value(ITEM_FIELD_OWNER, 0);
1702 AddGBankItemToDB(GetId(), tab, slot, pItem->GetGUIDLow(), pItem->GetEntry());
1703 pItem->FSetState(ITEM_NEW);
1704 pItem->SaveToDB(); // not in inventory and can be save standalone
1706 return pItem;
1708 else
1710 pItem2->SetCount( pItem2->GetCount() + count );
1711 pItem2->FSetState(ITEM_CHANGED);
1712 pItem2->SaveToDB(); // not in inventory and can be save standalone
1714 if (!clone)
1716 pItem->RemoveFromWorld();
1717 pItem->DeleteFromDB();
1718 delete pItem;
1721 return pItem2;
1725 void Guild::RemoveItem(uint8 tab, uint8 slot )
1727 m_TabListMap[tab]->Slots[slot] = NULL;
1728 CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'",
1729 GetId(), uint32(tab), uint32(slot));
1732 uint8 Guild::_CanStoreItem_InSpecificSlot( uint8 tab, uint8 slot, GuildItemPosCountVec &dest, uint32& count, bool swap, Item* pSrcItem ) const
1734 Item* pItem2 = m_TabListMap[tab]->Slots[slot];
1736 // ignore move item (this slot will be empty at move)
1737 if (pItem2 == pSrcItem)
1738 pItem2 = NULL;
1740 uint32 need_space;
1742 // empty specific slot - check item fit to slot
1743 if (!pItem2 || swap)
1745 // non empty stack with space
1746 need_space = pSrcItem->GetMaxStackCount();
1748 // non empty slot, check item type
1749 else
1751 // check item type
1752 if (pItem2->GetEntry() != pSrcItem->GetEntry())
1753 return EQUIP_ERR_ITEM_CANT_STACK;
1755 // check free space
1756 if (pItem2->GetCount() >= pSrcItem->GetMaxStackCount())
1757 return EQUIP_ERR_ITEM_CANT_STACK;
1759 need_space = pSrcItem->GetMaxStackCount() - pItem2->GetCount();
1762 if (need_space > count)
1763 need_space = count;
1765 GuildItemPosCount newPosition = GuildItemPosCount(slot, need_space);
1766 if (!newPosition.isContainedIn(dest))
1768 dest.push_back(newPosition);
1769 count -= need_space;
1772 return EQUIP_ERR_OK;
1775 uint8 Guild::_CanStoreItem_InTab( uint8 tab, GuildItemPosCountVec &dest, uint32& count, bool merge, Item* pSrcItem, uint8 skip_slot ) const
1777 for (uint32 j = 0; j < GUILD_BANK_MAX_SLOTS; ++j)
1779 // skip specific slot already processed in first called _CanStoreItem_InSpecificSlot
1780 if (j == skip_slot)
1781 continue;
1783 Item* pItem2 = m_TabListMap[tab]->Slots[j];
1785 // ignore move item (this slot will be empty at move)
1786 if (pItem2 == pSrcItem)
1787 pItem2 = NULL;
1789 // if merge skip empty, if !merge skip non-empty
1790 if ((pItem2 != NULL) != merge)
1791 continue;
1793 if (pItem2)
1795 if (pItem2->GetEntry() == pSrcItem->GetEntry() && pItem2->GetCount() < pSrcItem->GetMaxStackCount())
1797 uint32 need_space = pSrcItem->GetMaxStackCount() - pItem2->GetCount();
1798 if (need_space > count)
1799 need_space = count;
1801 GuildItemPosCount newPosition = GuildItemPosCount(j, need_space);
1802 if (!newPosition.isContainedIn(dest))
1804 dest.push_back(newPosition);
1805 count -= need_space;
1807 if (count == 0)
1808 return EQUIP_ERR_OK;
1812 else
1814 uint32 need_space = pSrcItem->GetMaxStackCount();
1815 if (need_space > count)
1816 need_space = count;
1818 GuildItemPosCount newPosition = GuildItemPosCount(j, need_space);
1819 if (!newPosition.isContainedIn(dest))
1821 dest.push_back(newPosition);
1822 count -= need_space;
1824 if (count == 0)
1825 return EQUIP_ERR_OK;
1829 return EQUIP_ERR_OK;
1832 uint8 Guild::CanStoreItem( uint8 tab, uint8 slot, GuildItemPosCountVec &dest, uint32 count, Item *pItem, bool swap ) const
1834 sLog.outDebug( "GUILD STORAGE: CanStoreItem tab = %u, slot = %u, item = %u, count = %u", tab, slot, pItem->GetEntry(), count);
1836 if (count > pItem->GetCount())
1837 return EQUIP_ERR_COULDNT_SPLIT_ITEMS;
1839 if (pItem->IsSoulBound())
1840 return EQUIP_ERR_CANT_DROP_SOULBOUND;
1842 // in specific slot
1843 if (slot != NULL_SLOT)
1845 uint8 res = _CanStoreItem_InSpecificSlot(tab,slot,dest,count,swap,pItem);
1846 if (res != EQUIP_ERR_OK)
1847 return res;
1849 if (count == 0)
1850 return EQUIP_ERR_OK;
1853 // not specific slot or have space for partly store only in specific slot
1855 // search stack in tab for merge to
1856 if (pItem->GetMaxStackCount() > 1)
1858 uint8 res = _CanStoreItem_InTab(tab, dest, count, true, pItem, slot);
1859 if (res != EQUIP_ERR_OK)
1860 return res;
1862 if (count == 0)
1863 return EQUIP_ERR_OK;
1866 // search free slot in bag for place to
1867 uint8 res = _CanStoreItem_InTab(tab, dest, count, false, pItem, slot);
1868 if (res != EQUIP_ERR_OK)
1869 return res;
1871 if (count == 0)
1872 return EQUIP_ERR_OK;
1874 return EQUIP_ERR_BANK_FULL;
1877 void Guild::SetGuildBankTabText(uint8 TabId, std::string text)
1879 if (TabId >= GUILD_BANK_MAX_TABS)
1880 return;
1881 if (TabId >= m_TabListMap.size())
1882 return;
1883 if (!m_TabListMap[TabId])
1884 return;
1886 if (m_TabListMap[TabId]->Text == text)
1887 return;
1889 utf8truncate(text, 500); // DB and client size limitation
1891 m_TabListMap[TabId]->Text = text;
1893 CharacterDatabase.escape_string(text);
1894 CharacterDatabase.PExecute("UPDATE guild_bank_tab SET TabText='%s' WHERE guildid='%u' AND TabId='%u'", text.c_str(), m_Id, uint32(TabId));
1896 // announce
1897 SendGuildBankTabText(NULL,TabId);
1900 void Guild::SendGuildBankTabText(WorldSession *session, uint8 TabId)
1902 GuildBankTab const* tab = m_TabListMap[TabId];
1904 WorldPacket data(MSG_QUERY_GUILD_BANK_TEXT, 1+tab->Text.size()+1);
1905 data << uint8(TabId);
1906 data << tab->Text;
1908 if (session)
1909 session->SendPacket(&data);
1910 else
1911 BroadcastPacket(&data);
1914 void Guild::SwapItems(Player * pl, uint8 BankTab, uint8 BankTabSlot, uint8 BankTabDst, uint8 BankTabSlotDst, uint32 SplitedAmount )
1916 // empty operation
1917 if (BankTab == BankTabDst && BankTabSlot == BankTabSlotDst)
1918 return;
1920 Item *pItemSrc = GetItem(BankTab, BankTabSlot);
1921 if (!pItemSrc) // may prevent crash
1922 return;
1924 if (SplitedAmount > pItemSrc->GetCount())
1925 return; // cheating?
1926 else if (SplitedAmount == pItemSrc->GetCount())
1927 SplitedAmount = 0; // no split
1929 Item *pItemDst = GetItem(BankTabDst, BankTabSlotDst);
1931 if (BankTab != BankTabDst)
1933 // check dest pos rights (if different tabs)
1934 if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTabDst, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
1935 return;
1937 // check source pos rights (if different tabs)
1938 uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab);
1939 if (remRight <= 0)
1940 return;
1943 if (SplitedAmount)
1944 { // Bank -> Bank item split (in empty or non empty slot
1945 GuildItemPosCountVec dest;
1946 uint8 msg = CanStoreItem(BankTabDst, BankTabSlotDst, dest, SplitedAmount, pItemSrc, false);
1947 if (msg != EQUIP_ERR_OK)
1949 pl->SendEquipError( msg, pItemSrc, NULL );
1950 return;
1953 Item *pNewItem = pItemSrc->CloneItem( SplitedAmount );
1954 if (!pNewItem)
1956 pl->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pItemSrc, NULL );
1957 return;
1960 CharacterDatabase.BeginTransaction();
1961 LogBankEvent(GUILD_BANK_LOG_MOVE_ITEM, BankTab, pl->GetGUIDLow(), pItemSrc->GetEntry(), SplitedAmount, BankTabDst);
1963 pl->ItemRemovedQuestCheck( pItemSrc->GetEntry(), SplitedAmount );
1964 pItemSrc->SetCount( pItemSrc->GetCount() - SplitedAmount );
1965 pItemSrc->FSetState(ITEM_CHANGED);
1966 pItemSrc->SaveToDB(); // not in inventory and can be save standalone
1967 StoreItem(BankTabDst, dest, pNewItem);
1968 CharacterDatabase.CommitTransaction();
1970 else // non split
1972 GuildItemPosCountVec gDest;
1973 uint8 msg = CanStoreItem(BankTabDst,BankTabSlotDst,gDest,pItemSrc->GetCount(), pItemSrc, false);
1974 if (msg == EQUIP_ERR_OK) // merge to
1976 CharacterDatabase.BeginTransaction();
1977 LogBankEvent(GUILD_BANK_LOG_MOVE_ITEM, BankTab, pl->GetGUIDLow(), pItemSrc->GetEntry(), pItemSrc->GetCount(), BankTabDst);
1979 RemoveItem(BankTab, BankTabSlot);
1980 StoreItem(BankTabDst, gDest, pItemSrc);
1981 CharacterDatabase.CommitTransaction();
1983 else // swap
1985 gDest.clear();
1986 msg = CanStoreItem(BankTabDst, BankTabSlotDst, gDest, pItemSrc->GetCount(), pItemSrc, true);
1987 if (msg != EQUIP_ERR_OK)
1989 pl->SendEquipError( msg, pItemSrc, NULL );
1990 return;
1993 GuildItemPosCountVec gSrc;
1994 msg = CanStoreItem(BankTab, BankTabSlot, gSrc, pItemDst->GetCount(), pItemDst, true);
1995 if (msg != EQUIP_ERR_OK)
1997 pl->SendEquipError( msg, pItemDst, NULL );
1998 return;
2001 if (BankTab != BankTabDst)
2003 // check source pos rights (item swapped to src)
2004 if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTab, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
2005 return;
2007 // check dest pos rights (item swapped to src)
2008 uint32 remRightDst = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTabDst);
2009 if (remRightDst <= 0)
2010 return;
2013 CharacterDatabase.BeginTransaction();
2014 LogBankEvent(GUILD_BANK_LOG_MOVE_ITEM, BankTab, pl->GetGUIDLow(), pItemSrc->GetEntry(), pItemSrc->GetCount(), BankTabDst);
2015 LogBankEvent(GUILD_BANK_LOG_MOVE_ITEM, BankTabDst, pl->GetGUIDLow(), pItemDst->GetEntry(), pItemDst->GetCount(), BankTab);
2017 RemoveItem(BankTab, BankTabSlot);
2018 RemoveItem(BankTabDst, BankTabSlotDst);
2019 StoreItem(BankTab, gSrc, pItemDst);
2020 StoreItem(BankTabDst, gDest, pItemSrc);
2021 CharacterDatabase.CommitTransaction();
2024 DisplayGuildBankContentUpdate(BankTab, BankTabSlot, BankTab == BankTabDst ? BankTabSlotDst : -1);
2025 if (BankTab != BankTabDst)
2026 DisplayGuildBankContentUpdate(BankTabDst, BankTabSlotDst);
2030 void Guild::MoveFromBankToChar( Player * pl, uint8 BankTab, uint8 BankTabSlot, uint8 PlayerBag, uint8 PlayerSlot, uint32 SplitedAmount)
2032 Item *pItemBank = GetItem(BankTab, BankTabSlot);
2033 Item *pItemChar = pl->GetItemByPos(PlayerBag, PlayerSlot);
2035 if (!pItemBank) // Problem to get bank item
2036 return;
2038 if (SplitedAmount > pItemBank->GetCount())
2039 return; // cheating?
2040 else if (SplitedAmount == pItemBank->GetCount())
2041 SplitedAmount = 0; // no split
2043 if (SplitedAmount)
2044 { // Bank -> Char split to slot (patly move)
2045 Item *pNewItem = pItemBank->CloneItem( SplitedAmount );
2046 if (!pNewItem)
2048 pl->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pItemBank, NULL );
2049 return;
2052 ItemPosCountVec dest;
2053 uint8 msg = pl->CanStoreItem(PlayerBag, PlayerSlot, dest, pNewItem, false);
2054 if (msg != EQUIP_ERR_OK)
2056 pl->SendEquipError( msg, pNewItem, NULL );
2057 delete pNewItem;
2058 return;
2061 // check source pos rights (item moved to inventory)
2062 uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab);
2063 if (remRight <= 0)
2065 delete pNewItem;
2066 return;
2069 CharacterDatabase.BeginTransaction();
2070 LogBankEvent(GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), SplitedAmount);
2072 pItemBank->SetCount(pItemBank->GetCount()-SplitedAmount);
2073 pItemBank->FSetState(ITEM_CHANGED);
2074 pItemBank->SaveToDB(); // not in inventory and can be save standalone
2075 pl->MoveItemToInventory(dest, pNewItem, true);
2076 pl->SaveInventoryAndGoldToDB();
2078 MemberItemWithdraw(BankTab, pl->GetGUIDLow());
2079 CharacterDatabase.CommitTransaction();
2081 else // Bank -> Char swap with slot (move)
2083 ItemPosCountVec dest;
2084 uint8 msg = pl->CanStoreItem(PlayerBag, PlayerSlot, dest, pItemBank, false);
2085 if (msg == EQUIP_ERR_OK) // merge case
2087 // check source pos rights (item moved to inventory)
2088 uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab);
2089 if (remRight <= 0)
2090 return;
2092 CharacterDatabase.BeginTransaction();
2093 LogBankEvent(GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), pItemBank->GetCount());
2095 RemoveItem(BankTab, BankTabSlot);
2096 pl->MoveItemToInventory(dest, pItemBank, true);
2097 pl->SaveInventoryAndGoldToDB();
2099 MemberItemWithdraw(BankTab, pl->GetGUIDLow());
2100 CharacterDatabase.CommitTransaction();
2102 else // Bank <-> Char swap items
2104 // check source pos rights (item swapped to bank)
2105 if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTab, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
2106 return;
2108 if (pItemChar)
2110 if (!pItemChar->CanBeTraded())
2112 pl->SendEquipError( EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, pItemChar, NULL );
2113 return;
2117 ItemPosCountVec iDest;
2118 msg = pl->CanStoreItem(PlayerBag, PlayerSlot, iDest, pItemBank, true);
2119 if (msg != EQUIP_ERR_OK)
2121 pl->SendEquipError( msg, pItemBank, NULL );
2122 return;
2125 GuildItemPosCountVec gDest;
2126 if (pItemChar)
2128 msg = CanStoreItem(BankTab,BankTabSlot,gDest,pItemChar->GetCount(),pItemChar,true);
2129 if (msg != EQUIP_ERR_OK)
2131 pl->SendEquipError( msg, pItemChar, NULL );
2132 return;
2136 // check source pos rights (item moved to inventory)
2137 uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab);
2138 if (remRight <= 0)
2139 return;
2141 if (pItemChar)
2143 // logging item move to bank
2144 if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE))
2146 sLog.outCommand(pl->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
2147 pl->GetName(),pl->GetSession()->GetAccountId(),
2148 pItemChar->GetProto()->Name1, pItemChar->GetEntry(), pItemChar->GetCount(),
2149 m_Id);
2153 CharacterDatabase.BeginTransaction();
2154 LogBankEvent(GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), pItemBank->GetCount());
2155 if (pItemChar)
2156 LogBankEvent(GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), pItemChar->GetCount());
2158 RemoveItem(BankTab, BankTabSlot);
2159 if (pItemChar)
2161 pl->MoveItemFromInventory(PlayerBag, PlayerSlot, true);
2162 pItemChar->DeleteFromInventoryDB();
2165 if (pItemChar)
2166 StoreItem(BankTab, gDest, pItemChar);
2167 pl->MoveItemToInventory(iDest, pItemBank, true);
2168 pl->SaveInventoryAndGoldToDB();
2170 MemberItemWithdraw(BankTab, pl->GetGUIDLow());
2171 CharacterDatabase.CommitTransaction();
2174 DisplayGuildBankContentUpdate(BankTab, BankTabSlot);
2178 void Guild::MoveFromCharToBank( Player * pl, uint8 PlayerBag, uint8 PlayerSlot, uint8 BankTab, uint8 BankTabSlot, uint32 SplitedAmount )
2180 Item *pItemBank = GetItem(BankTab, BankTabSlot);
2181 Item *pItemChar = pl->GetItemByPos(PlayerBag, PlayerSlot);
2183 if (!pItemChar) // Problem to get item from player
2184 return;
2186 if (!pItemChar->CanBeTraded())
2188 pl->SendEquipError( EQUIP_ERR_ITEMS_CANT_BE_SWAPPED, pItemChar, NULL );
2189 return;
2192 // check source pos rights (item moved to bank)
2193 if (!IsMemberHaveRights(pl->GetGUIDLow(), BankTab, GUILD_BANK_RIGHT_DEPOSIT_ITEM))
2194 return;
2196 if (SplitedAmount > pItemChar->GetCount())
2197 return; // cheating?
2198 else if (SplitedAmount == pItemChar->GetCount())
2199 SplitedAmount = 0; // no split
2201 if (SplitedAmount)
2202 { // Char -> Bank split to empty or non-empty slot (partly move)
2203 GuildItemPosCountVec dest;
2204 uint8 msg = CanStoreItem(BankTab, BankTabSlot, dest, SplitedAmount, pItemChar, false);
2205 if (msg != EQUIP_ERR_OK)
2207 pl->SendEquipError( msg, pItemChar, NULL );
2208 return;
2211 Item *pNewItem = pItemChar->CloneItem( SplitedAmount );
2212 if (!pNewItem)
2214 pl->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, pItemChar, NULL );
2215 return;
2218 // logging item move to bank (before items merge
2219 if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE))
2221 sLog.outCommand(pl->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
2222 pl->GetName(),pl->GetSession()->GetAccountId(),
2223 pItemChar->GetProto()->Name1, pItemChar->GetEntry(), SplitedAmount, m_Id);
2226 CharacterDatabase.BeginTransaction();
2227 LogBankEvent(GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), SplitedAmount);
2229 pl->ItemRemovedQuestCheck( pItemChar->GetEntry(), SplitedAmount );
2230 pItemChar->SetCount(pItemChar->GetCount()-SplitedAmount);
2231 pItemChar->SetState(ITEM_CHANGED);
2232 pl->SaveInventoryAndGoldToDB();
2233 StoreItem(BankTab, dest, pNewItem);
2234 CharacterDatabase.CommitTransaction();
2236 DisplayGuildBankContentUpdate(BankTab, dest);
2238 else // Char -> Bank swap with empty or non-empty (move)
2240 GuildItemPosCountVec dest;
2241 uint8 msg = CanStoreItem(BankTab, BankTabSlot, dest, pItemChar->GetCount(), pItemChar, false);
2242 if (msg == EQUIP_ERR_OK) // merge
2244 // logging item move to bank
2245 if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE))
2247 sLog.outCommand(pl->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
2248 pl->GetName(),pl->GetSession()->GetAccountId(),
2249 pItemChar->GetProto()->Name1, pItemChar->GetEntry(), pItemChar->GetCount(),
2250 m_Id);
2253 CharacterDatabase.BeginTransaction();
2254 LogBankEvent(GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), pItemChar->GetCount());
2256 pl->MoveItemFromInventory(PlayerBag, PlayerSlot, true);
2257 pItemChar->DeleteFromInventoryDB();
2259 StoreItem(BankTab, dest, pItemChar);
2260 pl->SaveInventoryAndGoldToDB();
2261 CharacterDatabase.CommitTransaction();
2263 DisplayGuildBankContentUpdate(BankTab, dest);
2265 else // Char <-> Bank swap items (posible NULL bank item)
2267 ItemPosCountVec iDest;
2268 if (pItemBank)
2270 msg = pl->CanStoreItem(PlayerBag, PlayerSlot, iDest, pItemBank, true);
2271 if (msg != EQUIP_ERR_OK)
2273 pl->SendEquipError( msg, pItemBank, NULL );
2274 return;
2278 GuildItemPosCountVec gDest;
2279 msg = CanStoreItem(BankTab, BankTabSlot, gDest, pItemChar->GetCount(), pItemChar, true);
2280 if (msg != EQUIP_ERR_OK)
2282 pl->SendEquipError( msg, pItemChar, NULL );
2283 return;
2286 if (pItemBank)
2288 // check bank pos rights (item swapped with inventory)
2289 uint32 remRight = GetMemberSlotWithdrawRem(pl->GetGUIDLow(), BankTab);
2290 if (remRight <= 0)
2291 return;
2294 // logging item move to bank
2295 if (pl->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_BOOL_GM_LOG_TRADE))
2297 sLog.outCommand(pl->GetSession()->GetAccountId(), "GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
2298 pl->GetName(), pl->GetSession()->GetAccountId(),
2299 pItemChar->GetProto()->Name1, pItemChar->GetEntry(), pItemChar->GetCount(),
2300 m_Id);
2303 CharacterDatabase.BeginTransaction();
2304 if (pItemBank)
2305 LogBankEvent(GUILD_BANK_LOG_WITHDRAW_ITEM, BankTab, pl->GetGUIDLow(), pItemBank->GetEntry(), pItemBank->GetCount());
2306 LogBankEvent(GUILD_BANK_LOG_DEPOSIT_ITEM, BankTab, pl->GetGUIDLow(), pItemChar->GetEntry(), pItemChar->GetCount());
2308 pl->MoveItemFromInventory(PlayerBag, PlayerSlot, true);
2309 pItemChar->DeleteFromInventoryDB();
2310 if (pItemBank)
2311 RemoveItem(BankTab, BankTabSlot);
2313 StoreItem(BankTab, gDest, pItemChar);
2314 if (pItemBank)
2315 pl->MoveItemToInventory(iDest, pItemBank, true);
2316 pl->SaveInventoryAndGoldToDB();
2317 if (pItemBank)
2318 MemberItemWithdraw(BankTab, pl->GetGUIDLow());
2319 CharacterDatabase.CommitTransaction();
2321 DisplayGuildBankContentUpdate(BankTab, gDest);
2326 void Guild::BroadcastEvent(GuildEvents event, uint64 guid, uint8 strCount, std::string str1, std::string str2, std::string str3)
2328 WorldPacket data(SMSG_GUILD_EVENT, 1+1+(guid ? 8 : 0));
2329 data << uint8(event);
2330 data << uint8(strCount);
2332 switch(strCount)
2334 case 0:
2335 break;
2336 case 1:
2337 data << str1;
2338 break;
2339 case 2:
2340 data << str1 << str2;
2341 break;
2342 case 3:
2343 data << str1 << str2 << str3;
2344 break;
2345 default:
2346 sLog.outError("Guild::BroadcastEvent: incorrect strings count %u!", strCount);
2347 break;
2350 if(guid)
2351 data << uint64(guid);
2353 BroadcastPacket(&data);
2355 sLog.outDebug("WORLD: Sent SMSG_GUILD_EVENT");
2358 bool GuildItemPosCount::isContainedIn(GuildItemPosCountVec const &vec) const
2360 for(GuildItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end(); ++itr)
2361 if (itr->Slot == this->Slot)
2362 return true;
2364 return false;