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"
24 #include "ObjectMgr.h"
27 #include "SocialMgr.h"
42 m_BackgroundColor
= 0;
48 m_EventLogLoaded
= false;
49 m_GuildBankLoaded
= false;
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;
65 bool Guild::Create(Player
* leader
, std::string gname
)
67 if (sObjectMgr
.GetGuildByName(gname
))
70 WorldSession
* lSession
= leader
->GetSession();
74 m_LeaderGuid
= leader
->GetGUID();
77 MOTD
= "No message set.";
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
);
124 if (pl
->GetGuildId() != 0)
129 if (Player::GetGuildIdFromDB(plGuid
) != 0) // player already in guild
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);
138 MemberSlot newmember
;
142 newmember
.Name
= pl
->GetName();
143 newmember
.Level
= pl
->getLevel();
144 newmember
.Class
= pl
->getClass();
145 newmember
.ZoneId
= pl
->GetZoneId();
150 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT name,level,class,zone FROM characters WHERE guid = '%u'", GUID_LOPART(plGuid
));
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();
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
));
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!!
188 pl
->SetInGuild(m_Id
);
189 pl
->SetRank(newmember
.RankId
);
190 pl
->SetGuildIdInvited(0);
195 void Guild::SetMOTD(std::string 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
)
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
)
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
;
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;
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
));
256 DelMember(m_LeaderGuid
);
257 // check no members case (disbanded)
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
);
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);
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
299 uint32 guildId
= fields
[0].GetUInt32();
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
);
309 //we loaded all ranks for this guild already, break cycle
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..
319 //first rank is guildmaster, prevent loss leader rights
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
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
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();
352 bool Guild::LoadMembersFromDB(QueryResult
*guildMembersResult
)
354 if (!guildMembersResult
)
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
363 uint32 guildId
= fields
[0].GetUInt32();
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
);
373 //we loaded all members for this guild already, break cycle
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
));
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
));
420 members
[GUID_LOPART(guid
)] = newmember
;
422 }while (guildMembersResult
->NextRow());
430 void Guild::SetMemberStats(uint64 guid
)
432 MemberList::iterator itr
= members
.find(GUID_LOPART(guid
));
433 if (itr
== members
.end() )
436 Player
*pl
= ObjectAccessor::FindPlayer(guid
);
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
)
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
);
470 if (!best
|| best
->RankId
> i
->second
.RankId
)
473 newLeaderGUID
= i
->first
;
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
491 WorldPacket
data(SMSG_GUILD_EVENT
, (1+1+(oldLeader
->Name
).size()+1+(best
->Name
).size()+1));
492 data
<< (uint8
)GE_LEADER_CHANGED
;
494 data
<< oldLeader
->Name
;
496 BroadcastPacket(&data
);
498 data
.Initialize(SMSG_GUILD_EVENT
, (1+1+(oldLeader
->Name
).size()+1));
499 data
<< (uint8
)GE_LEFT
;
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 !!
514 player
->SetInGuild(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 !!
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())
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())
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
))
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
)
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
));
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
));
611 player
->GetSession()->SendPacket(packet
);
616 void Guild::CreateRank(std::string name_
,uint32 rights
)
618 if (m_Ranks
.size() >= GUILD_RANKS_MAX_COUNT
)
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
)
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
);
657 std::string
Guild::GetRankName(uint32 rankId
)
659 if (rankId
>= m_Ranks
.size())
662 return m_Ranks
[rankId
].Name
;
665 uint32
Guild::GetRankRights(uint32 rankId
)
667 if (rankId
>= m_Ranks
.size())
670 return m_Ranks
[rankId
].Rights
;
673 void Guild::SetRankName(uint32 rankId
, std::string name_
)
675 if (rankId
>= m_Ranks
.size())
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())
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())
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();
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());
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
;
765 data
<< uint64(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
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
;
779 session
->SendPacket(&data
);
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
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
;
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() )
828 itr
->second
.LogoutTime
= time(NULL
);
830 if (m_OnlineMembers
> 0)
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();
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
)
856 data
<< uint8(itr
->EventType
);
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
);
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
)
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
);
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;
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
907 m_GuildEventLog
.push_front(NewEvent
);
909 } while( result
->NextRow() );
912 m_EventLogLoaded
= true;
915 // Unload guild eventlog
916 void Guild::UnloadGuildEventLog()
918 if (!m_EventLogLoaded
)
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
;
930 NewEvent
.EventType
= EventType
;
931 NewEvent
.PlayerGuid1
= PlayerGuid1
;
932 NewEvent
.PlayerGuid2
= PlayerGuid2
;
933 NewEvent
.NewRank
= NewRank
;
934 NewEvent
.TimeStamp
= uint32(time(NULL
));
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();
941 m_GuildEventLog
.push_back(NewEvent
);
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 // *************************************************
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
))
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
1009 AppendDisplayGuildBankSlot(data
, tab
, slot1
);
1011 else // 2 items (in slot1 and 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
));
1028 if (!IsMemberHaveRights(itr
->first
,TabId
,GUILD_BANK_RIGHT_VIEW_TAB
))
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
));
1064 if (!IsMemberHaveRights(itr
->first
,TabId
,GUILD_BANK_RIGHT_VIEW_TAB
))
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
)
1079 return m_TabListMap
[TabId
]->Slots
[SlotId
];
1082 // *************************************************
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
)
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
)
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
)
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
)
1159 m_GuildBankLoaded
= true;
1160 LoadGuildBankEventLogFromDB();
1163 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT TabId, TabName, TabIcon, TabText FROM guild_bank_tab WHERE guildid='%u' ORDER BY TabId", m_Id
);
1166 m_PurchasedTabs
= 0;
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());
1188 // data needs to be at first place for Item::LoadFromDB
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
);
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
);
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
);
1214 ItemPrototype
const *proto
= ObjectMgr::GetItemPrototype(ItemEntry
);
1218 sLog
.outError( "Guild::LoadGuildBankFromDB: Unknown item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid
,ItemEntry
);
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
);
1231 pItem
->AddToWorld();
1232 m_TabListMap
[TabId
]->Slots
[SlotId
] = pItem
;
1233 } while (result
->NextRow());
1238 // This unload should be called when the last member of the guild gets offline
1239 void Guild::UnloadGuildBank()
1241 if (!m_GuildBankLoaded
)
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
)
1279 SetBankMoney(GetGuildBankMoney()-amount
);
1281 if (MoneyWithDrawRight
< WITHDRAW_MONEY_UNLIMITED
)
1283 MemberList::iterator itr
= members
.find(LowGuid
);
1284 if (itr
== members
.end() )
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
);
1293 void Guild::SetBankMoney(int64 money
)
1295 if (money
< 0) // I don't know how this happens, it does!!
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)
1312 if (SlotsWithDrawRight
< WITHDRAW_SLOT_UNLIMITED
)
1314 MemberList::iterator itr
= members
.find(LowGuid
);
1315 if (itr
== members
.end() )
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
);
1324 bool Guild::IsMemberHaveRights(uint32 LowGuid
, uint8 TabId
, uint32 rights
) const
1326 MemberList::const_iterator itr
= members
.find(LowGuid
);
1327 if (itr
== members
.end() )
1330 if (itr
->second
.RankId
== GR_GUILDMASTER
)
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() )
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
)
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() )
1365 if (itr
->second
.RankId
== GR_GUILDMASTER
)
1366 return WITHDRAW_MONEY_UNLIMITED
;
1368 uint32 curTime
= uint32(time(NULL
)/MINUTE
); // minutes
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())
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
);
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
;
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())
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
)
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
)
1462 Field
*fields
= guildBankTabRightsResult
->Fetch();
1463 //prevent crash when all rights in result are already processed
1466 uint32 guildId
= fields
[0].GetUInt32();
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
);
1476 //we loaded all ranks for this guild bank already, break cycle
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());
1490 // *************************************************
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
++)
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
);
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
);
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());
1542 //special handle for guild bank money log
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
);
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
);
1572 //events are ordered from oldest (in beginning) to latest (in the end)
1573 m_GuildBankEventLog_Money
.push_front(NewEvent
);
1575 } while (result
->NextRow());
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
)
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
);
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
);
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
);
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
)
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
);
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
);
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
);
1712 // random item property id +8
1713 data
<< (uint32
) pItem
->GetItemRandomPropertyId();
1714 if (pItem
->GetItemRandomPropertyId())
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
1728 data
<< uint8(0); // no enchantments (0)
1732 Item
* Guild::StoreItem(uint8 tabId
, GuildItemPosCountVec
const& dest
, Item
* pItem
)
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
;
1746 if (itr
== dest
.end())
1748 lastItem
= _StoreItem(tabId
,slot
,pItem
,count
,false);
1752 lastItem
= _StoreItem(tabId
,slot
,pItem
,count
,true);
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
)
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
];
1771 pItem
= pItem
->CloneItem(count
);
1773 pItem
->SetCount(count
);
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
1790 pItem2
->SetCount( pItem2
->GetCount() + count
);
1791 pItem2
->FSetState(ITEM_CHANGED
);
1792 pItem2
->SaveToDB(); // not in onventory and can be save standalone
1796 pItem
->RemoveFromWorld();
1797 pItem
->DeleteFromDB();
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
)
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
1832 if (pItem2
->GetEntry() != pSrcItem
->GetEntry())
1833 return EQUIP_ERR_ITEM_CANT_STACK
;
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
)
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
1863 Item
* pItem2
= m_TabListMap
[tab
]->Slots
[j
];
1865 // ignore move item (this slot will be empty at move)
1866 if (pItem2
== pSrcItem
)
1869 // if merge skip empty, if !merge skip non-empty
1870 if ((pItem2
!= NULL
) != merge
)
1875 if (pItem2
->GetEntry() == pSrcItem
->GetEntry() && pItem2
->GetCount() < pSrcItem
->GetMaxStackCount())
1877 uint32 need_space
= pSrcItem
->GetMaxStackCount() - pItem2
->GetCount();
1878 if (need_space
> count
)
1881 GuildItemPosCount newPosition
= GuildItemPosCount(j
,need_space
);
1882 if (!newPosition
.isContainedIn(dest
))
1884 dest
.push_back(newPosition
);
1885 count
-= need_space
;
1888 return EQUIP_ERR_OK
;
1894 uint32 need_space
= pSrcItem
->GetMaxStackCount();
1895 if (need_space
> count
)
1898 GuildItemPosCount newPosition
= GuildItemPosCount(j
,need_space
);
1899 if (!newPosition
.isContainedIn(dest
))
1901 dest
.push_back(newPosition
);
1902 count
-= need_space
;
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
;
1923 if (slot
!= NULL_SLOT
)
1925 uint8 res
= _CanStoreItem_InSpecificSlot(tab
,slot
,dest
,count
,swap
,pItem
);
1926 if (res
!= EQUIP_ERR_OK
)
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
)
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
)
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
)
1961 if (TabId
>= m_TabListMap
.size())
1963 if (!m_TabListMap
[TabId
])
1966 if (m_TabListMap
[TabId
]->Text
== text
)
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
));
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
);
1989 session
->SendPacket(&data
);
1991 BroadcastPacket(&data
);
1994 void Guild::SwapItems(Player
* pl
, uint8 BankTab
, uint8 BankTabSlot
, uint8 BankTabDst
, uint8 BankTabSlotDst
, uint32 SplitedAmount
)
1997 if (BankTab
== BankTabDst
&& BankTabSlot
== BankTabSlotDst
)
2000 Item
*pItemSrc
= GetItem(BankTab
, BankTabSlot
);
2001 if (!pItemSrc
) // may prevent crash
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
))
2017 // check source pos rights (if different tabs)
2018 uint32 remRight
= GetMemberSlotWithdrawRem(pl
->GetGUIDLow(), BankTab
);
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
);
2033 Item
*pNewItem
= pItemSrc
->CloneItem( SplitedAmount
);
2036 pl
->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND
, pItemSrc
, NULL
);
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();
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();
2066 msg
= CanStoreItem(BankTabDst
,BankTabSlotDst
,gDest
,pItemSrc
->GetCount(),pItemSrc
,true);
2067 if (msg
!= EQUIP_ERR_OK
)
2069 pl
->SendEquipError( msg
, pItemSrc
, NULL
);
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
);
2081 if (BankTab
!= BankTabDst
)
2083 // check source pos rights (item swapped to src)
2084 if (!IsMemberHaveRights(pl
->GetGUIDLow(), BankTab
, GUILD_BANK_RIGHT_DEPOSIT_ITEM
))
2087 // check dest pos rights (item swapped to src)
2088 uint32 remRightDst
= GetMemberSlotWithdrawRem(pl
->GetGUIDLow(), BankTabDst
);
2089 if (remRightDst
<= 0)
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
2118 if (SplitedAmount
> pItemBank
->GetCount())
2119 return; // cheating?
2120 else if (SplitedAmount
== pItemBank
->GetCount())
2121 SplitedAmount
= 0; // no split
2124 { // Bank -> Char split to slot (patly move)
2125 Item
*pNewItem
= pItemBank
->CloneItem( SplitedAmount
);
2128 pl
->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND
, pItemBank
, NULL
);
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
);
2141 // check source pos rights (item moved to inventory)
2142 uint32 remRight
= GetMemberSlotWithdrawRem(pl
->GetGUIDLow(), BankTab
);
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
);
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
))
2190 if (!pItemChar
->CanBeTraded())
2192 pl
->SendEquipError( EQUIP_ERR_ITEMS_CANT_BE_SWAPPED
, pItemChar
, NULL
);
2197 ItemPosCountVec iDest
;
2198 msg
= pl
->CanStoreItem(PlayerBag
, PlayerSlot
, iDest
, pItemBank
, true);
2199 if (msg
!= EQUIP_ERR_OK
)
2201 pl
->SendEquipError( msg
, pItemBank
, NULL
);
2205 GuildItemPosCountVec gDest
;
2208 msg
= CanStoreItem(BankTab
,BankTabSlot
,gDest
,pItemChar
->GetCount(),pItemChar
,true);
2209 if (msg
!= EQUIP_ERR_OK
)
2211 pl
->SendEquipError( msg
, pItemChar
, NULL
);
2216 // check source pos rights (item moved to inventory)
2217 uint32 remRight
= GetMemberSlotWithdrawRem(pl
->GetGUIDLow(), BankTab
);
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(),
2233 CharacterDatabase
.BeginTransaction();
2234 LogBankEvent(GUILD_BANK_LOG_WITHDRAW_ITEM
, BankTab
, pl
->GetGUIDLow(), pItemBank
->GetEntry(), pItemBank
->GetCount());
2236 LogBankEvent(GUILD_BANK_LOG_DEPOSIT_ITEM
, BankTab
, pl
->GetGUIDLow(), pItemChar
->GetEntry(), pItemChar
->GetCount());
2238 RemoveItem(BankTab
, BankTabSlot
);
2241 pl
->MoveItemFromInventory(PlayerBag
, PlayerSlot
, true);
2242 pItemChar
->DeleteFromInventoryDB();
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
2266 if (!pItemChar
->CanBeTraded())
2268 pl
->SendEquipError( EQUIP_ERR_ITEMS_CANT_BE_SWAPPED
, pItemChar
, NULL
);
2272 // check source pos rights (item moved to bank)
2273 if (!IsMemberHaveRights(pl
->GetGUIDLow(), BankTab
, GUILD_BANK_RIGHT_DEPOSIT_ITEM
))
2276 if (SplitedAmount
> pItemChar
->GetCount())
2277 return; // cheating?
2278 else if (SplitedAmount
== pItemChar
->GetCount())
2279 SplitedAmount
= 0; // no split
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
);
2291 Item
*pNewItem
= pItemChar
->CloneItem( SplitedAmount
);
2294 pl
->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND
, pItemChar
, NULL
);
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(),
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
;
2350 msg
= pl
->CanStoreItem(PlayerBag
, PlayerSlot
, iDest
, pItemBank
, true);
2351 if (msg
!= EQUIP_ERR_OK
)
2353 pl
->SendEquipError( msg
, pItemBank
, NULL
);
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
);
2368 // check bank pos rights (item swapped with inventory)
2369 uint32 remRight
= GetMemberSlotWithdrawRem(pl
->GetGUIDLow(), BankTab
);
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(),
2383 CharacterDatabase
.BeginTransaction();
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();
2391 RemoveItem(BankTab
, BankTabSlot
);
2393 StoreItem(BankTab
,gDest
,pItemChar
);
2395 pl
->MoveItemToInventory(iDest
,pItemBank
,true);
2396 pl
->SaveInventoryAndGoldToDB();
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
)