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"
53 bool Guild::create(Player
* leader
, std::string gname
)
55 if(objmgr
.GetGuildByName(gname
))
58 WorldSession
* lSession
= leader
->GetSession();
62 leaderGuid
= leader
->GetGUID();
65 MOTD
= "No message set.";
68 Id
= objmgr
.GenerateGuildId();
70 sLog
.outDebug("GUILD: creating guild %s to leader: %u", gname
.c_str(), GUID_LOPART(leaderGuid
));
72 // gname already assigned to Guild::name, use it to encode string for DB
73 CharacterDatabase
.escape_string(gname
);
75 std::string dbGINFO
= GINFO
;
76 std::string dbMOTD
= MOTD
;
77 CharacterDatabase
.escape_string(dbGINFO
);
78 CharacterDatabase
.escape_string(dbMOTD
);
80 CharacterDatabase
.BeginTransaction();
81 // CharacterDatabase.PExecute("DELETE FROM guild WHERE guildid='%u'", Id); - MAX(guildid)+1 not exist
82 CharacterDatabase
.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", Id
);
83 CharacterDatabase
.PExecute("DELETE FROM guild_member WHERE guildid='%u'", Id
);
84 CharacterDatabase
.PExecute("INSERT INTO guild (guildid,name,leaderguid,info,motd,createdate,EmblemStyle,EmblemColor,BorderStyle,BorderColor,BackgroundColor,BankMoney) "
85 "VALUES('%u','%s','%u', '%s', '%s', NOW(),'%u','%u','%u','%u','%u','" I64FMTD
"')",
86 Id
, gname
.c_str(), GUID_LOPART(leaderGuid
), dbGINFO
.c_str(), dbMOTD
.c_str(), EmblemStyle
, EmblemColor
, BorderStyle
, BorderColor
, BackgroundColor
, guildbank_money
);
87 CharacterDatabase
.CommitTransaction();
89 CreateRank(lSession
->GetMangosString(LANG_GUILD_MASTER
), GR_RIGHT_ALL
);
90 CreateRank(lSession
->GetMangosString(LANG_GUILD_OFFICER
), GR_RIGHT_ALL
);
91 CreateRank(lSession
->GetMangosString(LANG_GUILD_VETERAN
), GR_RIGHT_GCHATLISTEN
| GR_RIGHT_GCHATSPEAK
);
92 CreateRank(lSession
->GetMangosString(LANG_GUILD_MEMBER
), GR_RIGHT_GCHATLISTEN
| GR_RIGHT_GCHATSPEAK
);
93 CreateRank(lSession
->GetMangosString(LANG_GUILD_INITIATE
),GR_RIGHT_GCHATLISTEN
| GR_RIGHT_GCHATSPEAK
);
95 return AddMember(leaderGuid
, (uint32
)GR_GUILDMASTER
);
98 bool Guild::AddMember(uint64 plGuid
, uint32 plRank
)
100 Player
* pl
= objmgr
.GetPlayer(plGuid
);
103 if(pl
->GetGuildId() != 0)
108 if(Player::GetGuildIdFromDB(plGuid
) != 0) // player already in guild
112 // remove all player signs from another petitions
113 // this will be prevent attempt joining player to many guilds and corrupt guild data integrity
114 Player::RemovePetitionsAndSigns(plGuid
, 9);
117 MemberSlot newmember
;
119 if(!FillPlayerData(plGuid
, &newmember
)) // problems with player data collection
122 newmember
.RankId
= plRank
;
123 newmember
.OFFnote
= (std::string
)"";
124 newmember
.Pnote
= (std::string
)"";
125 newmember
.logout_time
= time(NULL
);
126 newmember
.BankResetTimeMoney
= 0; // this will force update at first query
127 for (int i
= 0; i
< GUILD_BANK_MAX_TABS
; ++i
)
128 newmember
.BankResetTimeTab
[i
] = 0;
129 members
[GUID_LOPART(plGuid
)] = newmember
;
131 std::string dbPnote
= newmember
.Pnote
;
132 std::string dbOFFnote
= newmember
.OFFnote
;
133 CharacterDatabase
.escape_string(dbPnote
);
134 CharacterDatabase
.escape_string(dbOFFnote
);
136 CharacterDatabase
.PExecute("INSERT INTO guild_member (guildid,guid,rank,pnote,offnote) VALUES ('%u', '%u', '%u','%s','%s')",
137 Id
, GUID_LOPART(plGuid
), newmember
.RankId
, dbPnote
.c_str(), dbOFFnote
.c_str());
139 // If player not in game data in data field will be loaded from guild tables, no need to update it!!
143 pl
->SetRank(newmember
.RankId
);
144 pl
->SetGuildIdInvited(0);
149 void Guild::SetMOTD(std::string motd
)
153 // motd now can be used for encoding to DB
154 CharacterDatabase
.escape_string(motd
);
155 CharacterDatabase
.PExecute("UPDATE guild SET motd='%s' WHERE guildid='%u'", motd
.c_str(), Id
);
158 void Guild::SetGINFO(std::string ginfo
)
162 // ginfo now can be used for encoding to DB
163 CharacterDatabase
.escape_string(ginfo
);
164 CharacterDatabase
.PExecute("UPDATE guild SET info='%s' WHERE guildid='%u'", ginfo
.c_str(), Id
);
167 bool Guild::LoadGuildFromDB(uint32 GuildId
)
169 if(!LoadRanksFromDB(GuildId
))
172 if(!LoadMembersFromDB(GuildId
))
175 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT MAX(TabId) FROM guild_bank_tab WHERE guildid='%u'", GuildId
);
178 Field
*fields
= result
->Fetch();
179 purchased_tabs
= fields
[0].GetUInt8()+1; // Because TabId begins at 0
185 LoadBankRightsFromDB(GuildId
); // Must be after LoadRanksFromDB because it populates rank struct
188 result
= CharacterDatabase
.PQuery("SELECT guildid, name, leaderguid, EmblemStyle, EmblemColor, BorderStyle, BorderColor,"
190 "BackgroundColor, info, motd, createdate, BankMoney FROM guild WHERE guildid = '%u'", GuildId
);
195 Field
*fields
= result
->Fetch();
197 Id
= fields
[0].GetUInt32();
198 name
= fields
[1].GetCppString();
199 leaderGuid
= MAKE_NEW_GUID(fields
[2].GetUInt32(), 0, HIGHGUID_PLAYER
);
201 EmblemStyle
= fields
[3].GetUInt32();
202 EmblemColor
= fields
[4].GetUInt32();
203 BorderStyle
= fields
[5].GetUInt32();
204 BorderColor
= fields
[6].GetUInt32();
205 BackgroundColor
= fields
[7].GetUInt32();
206 GINFO
= fields
[8].GetCppString();
207 MOTD
= fields
[9].GetCppString();
208 uint64 time
= fields
[10].GetUInt64(); //datetime is uint64 type ... YYYYmmdd:hh:mm:ss
209 guildbank_money
= fields
[11].GetUInt64();
213 uint64 dTime
= time
/1000000;
214 CreatedDay
= dTime
%100;
215 CreatedMonth
= (dTime
/100)%100;
216 CreatedYear
= (dTime
/10000)%10000;
218 // If the leader does not exist attempt to promote another member
219 if(!objmgr
.GetPlayerAccountIdByGUID(leaderGuid
))
221 DelMember(leaderGuid
);
223 // check no members case (disbanded)
228 sLog
.outDebug("Guild %u Creation time Loaded day: %u, month: %u, year: %u", GuildId
, CreatedDay
, CreatedMonth
, CreatedYear
);
229 m_bankloaded
= false;
230 m_eventlogloaded
= false;
233 RenumGuildEventlog();
237 bool Guild::LoadRanksFromDB(uint32 GuildId
)
240 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT rname,rights,BankMoneyPerDay,rid FROM guild_rank WHERE guildid = '%u' ORDER BY rid ASC", GuildId
);
245 bool broken_ranks
= false;
249 fields
= result
->Fetch();
251 std::string rankName
= fields
[0].GetCppString();
252 uint32 rankRights
= fields
[1].GetUInt32();
253 uint32 rankMoney
= fields
[2].GetUInt32();
254 uint32 rankRID
= fields
[3].GetUInt32();
256 if(rankRID
!= m_ranks
.size()+1) // guild_rank.rid always store rank+1
259 if(m_ranks
.size()==GR_GUILDMASTER
) // prevent loss leader rights
260 rankRights
|= GR_RIGHT_ALL
;
262 AddRank(rankName
,rankRights
,rankMoney
);
263 }while( result
->NextRow() );
266 if(m_ranks
.size()==0) // empty rank table?
268 AddRank("Guild Master",GR_RIGHT_ALL
,0);
272 // guild_rank have wrong numbered ranks, repair
275 sLog
.outError("Guild %u have broken `guild_rank` data, repairing...",GuildId
);
276 CharacterDatabase
.BeginTransaction();
277 CharacterDatabase
.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", GuildId
);
278 for(size_t i
=0; i
< m_ranks
.size(); ++i
)
280 // guild_rank.rid always store rank+1
281 std::string name
= m_ranks
[i
].name
;
282 uint32 rights
= m_ranks
[i
].rights
;
283 CharacterDatabase
.escape_string(name
);
284 CharacterDatabase
.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", GuildId
, i
+1, name
.c_str(), rights
);
286 CharacterDatabase
.CommitTransaction();
292 bool Guild::LoadMembersFromDB(uint32 GuildId
)
295 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT guild_member.guid,rank, pnote, offnote, BankResetTimeMoney,BankRemMoney,"
297 "BankResetTimeTab0, BankRemSlotsTab0, BankResetTimeTab1, BankRemSlotsTab1, BankResetTimeTab2, BankRemSlotsTab2,"
299 "BankResetTimeTab3, BankRemSlotsTab3, BankResetTimeTab4, BankRemSlotsTab4, BankResetTimeTab5, BankRemSlotsTab5,"
301 "logout_time FROM guild_member LEFT JOIN characters ON characters.guid = guild_member.guid WHERE guildid = '%u'", GuildId
);
308 Field
*fields
= result
->Fetch();
309 MemberSlot newmember
;
310 newmember
.RankId
= fields
[1].GetUInt32();
311 uint64 guid
= MAKE_NEW_GUID(fields
[0].GetUInt32(), 0, HIGHGUID_PLAYER
);
313 // Player does not exist
314 if(!FillPlayerData(guid
, &newmember
))
317 newmember
.Pnote
= fields
[2].GetCppString();
318 newmember
.OFFnote
= fields
[3].GetCppString();
319 newmember
.BankResetTimeMoney
= fields
[4].GetUInt32();
320 newmember
.BankRemMoney
= fields
[5].GetUInt32();
321 for (int i
= 0; i
< GUILD_BANK_MAX_TABS
; ++i
)
323 newmember
.BankResetTimeTab
[i
] = fields
[6+(2*i
)].GetUInt32();
324 newmember
.BankRemSlotsTab
[i
] = fields
[7+(2*i
)].GetUInt32();
326 newmember
.logout_time
= fields
[18].GetUInt64();
327 members
[GUID_LOPART(guid
)] = newmember
;
329 }while( result
->NextRow() );
338 bool Guild::FillPlayerData(uint64 guid
, MemberSlot
* memslot
)
345 Player
* pl
= objmgr
.GetPlayer(guid
);
348 plName
= pl
->GetName();
349 plLevel
= pl
->getLevel();
350 plClass
= pl
->getClass();
351 plZone
= pl
->GetZoneId();
355 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT name,data,zone,class FROM characters WHERE guid = '%u'", GUID_LOPART(guid
));
357 return false; // player doesn't exist
359 Field
*fields
= result
->Fetch();
361 plName
= fields
[0].GetCppString();
363 Tokens data
= StrSplit(fields
[1].GetCppString(), " ");
364 plLevel
= Player::GetUInt32ValueFromArray(data
,UNIT_FIELD_LEVEL
);
366 plZone
= fields
[2].GetUInt32();
367 plClass
= fields
[3].GetUInt32();
370 if(plLevel
<1||plLevel
>STRONG_MAX_LEVEL
) // can be at broken `data` field
372 sLog
.outError("Player (GUID: %u) has a broken data in field `characters`.`data`.",GUID_LOPART(guid
));
378 sLog
.outError("Player (GUID: %u) has broken zone-data",GUID_LOPART(guid
));
379 //here it will also try the same, to get the zone from characters-table, but additional it tries to find
380 plZone
= Player::GetZoneIdFromDB(guid
);
381 //the zone through xy coords.. this is a bit redundant, but
382 //shouldn't be called often
385 if(plClass
<CLASS_WARRIOR
||plClass
>=MAX_CLASSES
) // can be at broken `class` field
387 sLog
.outError("Player (GUID: %u) has a broken data in field `characters`.`class`.",GUID_LOPART(guid
));
392 memslot
->name
= plName
;
393 memslot
->level
= plLevel
;
394 memslot
->Class
= plClass
;
395 memslot
->zoneId
= plZone
;
400 void Guild::LoadPlayerStatsByGuid(uint64 guid
)
402 MemberList::iterator itr
= members
.find(GUID_LOPART(guid
));
403 if (itr
== members
.end() )
406 Player
*pl
= ObjectAccessor::FindPlayer(guid
);
409 itr
->second
.name
= pl
->GetName();
410 itr
->second
.level
= pl
->getLevel();
411 itr
->second
.Class
= pl
->getClass();
414 void Guild::SetLeader(uint64 guid
)
417 ChangeRank(guid
, GR_GUILDMASTER
);
419 CharacterDatabase
.PExecute("UPDATE guild SET leaderguid='%u' WHERE guildid='%u'", GUID_LOPART(guid
), Id
);
422 void Guild::DelMember(uint64 guid
, bool isDisbanding
)
424 if(leaderGuid
== guid
&& !isDisbanding
)
426 MemberSlot
* oldLeader
= NULL
;
427 MemberSlot
* best
= NULL
;
428 uint64 newLeaderGUID
= 0;
429 for(Guild::MemberList::iterator i
= members
.begin(); i
!= members
.end(); ++i
)
431 if(i
->first
== GUID_LOPART(guid
))
433 oldLeader
= &(i
->second
);
437 if(!best
|| best
->RankId
> i
->second
.RankId
)
440 newLeaderGUID
= i
->first
;
449 SetLeader(newLeaderGUID
);
451 // If player not online data in data field will be loaded from guild tabs no need to update it !!
452 if(Player
*newLeader
= objmgr
.GetPlayer(newLeaderGUID
))
453 newLeader
->SetRank(GR_GUILDMASTER
);
455 // when leader non-exist (at guild load with deleted leader only) not send broadcasts
458 WorldPacket
data(SMSG_GUILD_EVENT
, (1+1+(oldLeader
->name
).size()+1+(best
->name
).size()+1));
459 data
<< (uint8
)GE_LEADER_CHANGED
;
461 data
<< oldLeader
->name
;
463 BroadcastPacket(&data
);
465 data
.Initialize(SMSG_GUILD_EVENT
, (1+1+(oldLeader
->name
).size()+1));
466 data
<< (uint8
)GE_LEFT
;
468 data
<< oldLeader
->name
;
469 BroadcastPacket(&data
);
472 sLog
.outDebug( "WORLD: Sent (SMSG_GUILD_EVENT)" );
475 members
.erase(GUID_LOPART(guid
));
477 Player
*player
= objmgr
.GetPlayer(guid
);
478 // If player not online data in data field will be loaded from guild tabs no need to update it !!
481 player
->SetInGuild(0);
485 CharacterDatabase
.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid
));
488 void Guild::ChangeRank(uint64 guid
, uint32 newRank
)
490 MemberList::iterator itr
= members
.find(GUID_LOPART(guid
));
491 if( itr
!= members
.end() )
492 itr
->second
.RankId
= newRank
;
494 Player
*player
= objmgr
.GetPlayer(guid
);
495 // If player not online data in data field will be loaded from guild tabs no need to update it !!
497 player
->SetRank(newRank
);
499 CharacterDatabase
.PExecute( "UPDATE guild_member SET rank='%u' WHERE guid='%u'", newRank
, GUID_LOPART(guid
) );
502 void Guild::SetPNOTE(uint64 guid
,std::string pnote
)
504 MemberList::iterator itr
= members
.find(GUID_LOPART(guid
));
505 if( itr
== members
.end() )
508 itr
->second
.Pnote
= pnote
;
510 // pnote now can be used for encoding to DB
511 CharacterDatabase
.escape_string(pnote
);
512 CharacterDatabase
.PExecute("UPDATE guild_member SET pnote = '%s' WHERE guid = '%u'", pnote
.c_str(), itr
->first
);
515 void Guild::SetOFFNOTE(uint64 guid
,std::string offnote
)
517 MemberList::iterator itr
= members
.find(GUID_LOPART(guid
));
518 if( itr
== members
.end() )
520 itr
->second
.OFFnote
= offnote
;
521 // offnote now can be used for encoding to DB
522 CharacterDatabase
.escape_string(offnote
);
523 CharacterDatabase
.PExecute("UPDATE guild_member SET offnote = '%s' WHERE guid = '%u'", offnote
.c_str(), itr
->first
);
526 void Guild::BroadcastToGuild(WorldSession
*session
, const std::string
& msg
, uint32 language
)
528 if (session
&& session
->GetPlayer() && HasRankRight(session
->GetPlayer()->GetRank(),GR_RIGHT_GCHATSPEAK
))
531 ChatHandler(session
).FillMessageData(&data
, CHAT_MSG_GUILD
, language
, 0, msg
.c_str());
533 for (MemberList::const_iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
535 Player
*pl
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
537 if (pl
&& pl
->GetSession() && HasRankRight(pl
->GetRank(),GR_RIGHT_GCHATLISTEN
) && !pl
->GetSocial()->HasIgnore(session
->GetPlayer()->GetGUIDLow()) )
538 pl
->GetSession()->SendPacket(&data
);
543 void Guild::BroadcastToOfficers(WorldSession
*session
, const std::string
& msg
, uint32 language
)
545 if (session
&& session
->GetPlayer() && HasRankRight(session
->GetPlayer()->GetRank(),GR_RIGHT_OFFCHATSPEAK
))
547 for(MemberList::iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
550 ChatHandler::FillMessageData(&data
, session
, CHAT_MSG_OFFICER
, language
, NULL
, 0, msg
.c_str(),NULL
);
552 Player
*pl
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
554 if (pl
&& pl
->GetSession() && HasRankRight(pl
->GetRank(),GR_RIGHT_OFFCHATLISTEN
) && !pl
->GetSocial()->HasIgnore(session
->GetPlayer()->GetGUIDLow()))
555 pl
->GetSession()->SendPacket(&data
);
560 void Guild::BroadcastPacket(WorldPacket
*packet
)
562 for(MemberList::iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
564 Player
*player
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
566 player
->GetSession()->SendPacket(packet
);
570 void Guild::BroadcastPacketToRank(WorldPacket
*packet
, uint32 rankId
)
572 for(MemberList::iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
574 if (itr
->second
.RankId
== rankId
)
576 Player
*player
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
578 player
->GetSession()->SendPacket(packet
);
583 void Guild::CreateRank(std::string name_
,uint32 rights
)
585 if(m_ranks
.size() >= GUILD_MAX_RANKS
)
588 AddRank(name_
,rights
,0);
590 for (int i
= 0; i
< purchased_tabs
; ++i
)
592 CreateBankRightForTab(m_ranks
.size()-1, uint8(i
));
595 // guild_rank.rid always store rank+1 value
597 // name now can be used for encoding to DB
598 CharacterDatabase
.escape_string(name_
);
599 CharacterDatabase
.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", Id
, (unsigned int)m_ranks
.size(), name_
.c_str(), rights
);
602 void Guild::AddRank(const std::string
& name_
,uint32 rights
, uint32 money
)
604 m_ranks
.push_back(RankInfo(name_
,rights
,money
));
607 void Guild::DelRank()
612 // guild_rank.rid always store rank+1 value
613 uint32 rank
= m_ranks
.size()-1;
614 CharacterDatabase
.PExecute("DELETE FROM guild_rank WHERE rid>='%u' AND guildid='%u'", (rank
+1), Id
);
619 std::string
Guild::GetRankName(uint32 rankId
)
621 if(rankId
>= m_ranks
.size())
624 return m_ranks
[rankId
].name
;
627 uint32
Guild::GetRankRights(uint32 rankId
)
629 if(rankId
>= m_ranks
.size())
632 return m_ranks
[rankId
].rights
;
635 void Guild::SetRankName(uint32 rankId
, std::string name_
)
637 if(rankId
>= m_ranks
.size())
640 m_ranks
[rankId
].name
= name_
;
642 // name now can be used for encoding to DB
643 CharacterDatabase
.escape_string(name_
);
644 CharacterDatabase
.PExecute("UPDATE guild_rank SET rname='%s' WHERE rid='%u' AND guildid='%u'", name_
.c_str(), (rankId
+1), Id
);
647 void Guild::SetRankRights(uint32 rankId
, uint32 rights
)
649 if(rankId
>= m_ranks
.size())
652 m_ranks
[rankId
].rights
= rights
;
654 CharacterDatabase
.PExecute("UPDATE guild_rank SET rights='%u' WHERE rid='%u' AND guildid='%u'", rights
, (rankId
+1), Id
);
657 int32
Guild::GetRank(uint32 LowGuid
)
659 MemberList::iterator itr
= members
.find(LowGuid
);
660 if (itr
==members
.end())
663 return itr
->second
.RankId
;
666 void Guild::Disband()
668 WorldPacket
data(SMSG_GUILD_EVENT
, 1);
669 data
<< (uint8
)GE_DISBANDED
;
670 BroadcastPacket(&data
);
672 while (!members
.empty())
674 MemberList::iterator itr
= members
.begin();
675 DelMember(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
), true);
678 CharacterDatabase
.BeginTransaction();
679 CharacterDatabase
.PExecute("DELETE FROM guild WHERE guildid = '%u'",Id
);
680 CharacterDatabase
.PExecute("DELETE FROM guild_rank WHERE guildid = '%u'",Id
);
681 CharacterDatabase
.PExecute("DELETE FROM guild_bank_tab WHERE guildid = '%u'",Id
);
682 CharacterDatabase
.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u'",Id
);
683 CharacterDatabase
.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u'",Id
);
684 CharacterDatabase
.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid = '%u'",Id
);
685 CharacterDatabase
.PExecute("DELETE FROM guild_eventlog WHERE guildid = '%u'",Id
);
686 CharacterDatabase
.CommitTransaction();
687 objmgr
.RemoveGuild(Id
);
690 void Guild::Roster(WorldSession
*session
)
692 // we can only guess size
693 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));
694 data
<< (uint32
)members
.size();
698 data
<< (uint32
)m_ranks
.size();
699 for (RankList::const_iterator ritr
= m_ranks
.begin(); ritr
!= m_ranks
.end(); ++ritr
)
701 data
<< (uint32
)ritr
->rights
;
702 data
<< (uint32
)ritr
->BankMoneyPerDay
; // count of: withdraw gold(gold/day) Note: in game set gold, in packet set bronze.
703 for (int i
= 0; i
< GUILD_BANK_MAX_TABS
; ++i
)
705 data
<< (uint32
)ritr
->TabRight
[i
]; // for TAB_i rights: view tabs = 0x01, deposit items =0x02
706 data
<< (uint32
)ritr
->TabSlotPerDay
[i
]; // for TAB_i count of: withdraw items(stack/day)
709 for (MemberList::const_iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
711 if (Player
*pl
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
)))
713 data
<< (uint64
)pl
->GetGUID();
715 data
<< (std::string
)pl
->GetName();
716 data
<< (uint32
)itr
->second
.RankId
;
717 data
<< (uint8
)pl
->getLevel();
718 data
<< (uint8
)pl
->getClass();
719 data
<< (uint8
)0; // new 2.4.0
720 data
<< (uint32
)pl
->GetZoneId();
721 data
<< itr
->second
.Pnote
;
722 data
<< itr
->second
.OFFnote
;
726 data
<< uint64(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
728 data
<< itr
->second
.name
;
729 data
<< (uint32
)itr
->second
.RankId
;
730 data
<< (uint8
)itr
->second
.level
;
731 data
<< (uint8
)itr
->second
.Class
;
732 data
<< (uint8
)0; // new 2.4.0
733 data
<< (uint32
)itr
->second
.zoneId
;
734 data
<< (float(time(NULL
)-itr
->second
.logout_time
) / DAY
);
735 data
<< itr
->second
.Pnote
;
736 data
<< itr
->second
.OFFnote
;
739 session
->SendPacket(&data
);;
740 sLog
.outDebug( "WORLD: Sent (SMSG_GUILD_ROSTER)" );
743 void Guild::Query(WorldSession
*session
)
745 WorldPacket
data(SMSG_GUILD_QUERY_RESPONSE
, (8*32+200));// we can only guess size
750 for (size_t i
= 0 ; i
< 10; ++i
) // show always 10 ranks
752 if(i
< m_ranks
.size())
753 data
<< m_ranks
[i
].name
;
755 data
<< (uint8
)0; // null string
758 data
<< uint32(EmblemStyle
);
759 data
<< uint32(EmblemColor
);
760 data
<< uint32(BorderStyle
);
761 data
<< uint32(BorderColor
);
762 data
<< uint32(BackgroundColor
);
763 data
<< uint32(0); // something new in WotLK
765 session
->SendPacket( &data
);
766 sLog
.outDebug( "WORLD: Sent (SMSG_GUILD_QUERY_RESPONSE)" );
769 void Guild::SetEmblem(uint32 emblemStyle
, uint32 emblemColor
, uint32 borderStyle
, uint32 borderColor
, uint32 backgroundColor
)
771 EmblemStyle
= emblemStyle
;
772 EmblemColor
= emblemColor
;
773 BorderStyle
= borderStyle
;
774 BorderColor
= borderColor
;
775 BackgroundColor
= backgroundColor
;
777 CharacterDatabase
.PExecute("UPDATE guild SET EmblemStyle=%u, EmblemColor=%u, BorderStyle=%u, BorderColor=%u, BackgroundColor=%u WHERE guildid = %u", EmblemStyle
, EmblemColor
, BorderStyle
, BorderColor
, BackgroundColor
, Id
);
780 void Guild::UpdateLogoutTime(uint64 guid
)
782 MemberList::iterator itr
= members
.find(GUID_LOPART(guid
));
783 if (itr
== members
.end() )
786 itr
->second
.logout_time
= time(NULL
);
788 if (m_onlinemembers
> 0)
793 UnloadGuildEventlog();
797 // *************************************************
798 // Guild Eventlog part
799 // *************************************************
800 // Display guild eventlog
801 void Guild::DisplayGuildEventlog(WorldSession
*session
)
803 // Load guild eventlog, if not already done
804 if (!m_eventlogloaded
)
805 LoadGuildEventLogFromDB();
808 WorldPacket
data(MSG_GUILD_EVENT_LOG_QUERY
, 0);
809 // count, max count == 100
810 data
<< uint8(m_GuildEventlog
.size());
811 for (GuildEventlog::const_iterator itr
= m_GuildEventlog
.begin(); itr
!= m_GuildEventlog
.end(); ++itr
)
814 data
<< uint8((*itr
)->EventType
);
816 data
<< uint64((*itr
)->PlayerGuid1
);
817 // Player 2 not for left/join guild events
818 if( (*itr
)->EventType
!= GUILD_EVENT_LOG_JOIN_GUILD
&& (*itr
)->EventType
!= GUILD_EVENT_LOG_LEAVE_GUILD
)
819 data
<< uint64((*itr
)->PlayerGuid2
);
820 // New Rank - only for promote/demote guild events
821 if( (*itr
)->EventType
== GUILD_EVENT_LOG_PROMOTE_PLAYER
|| (*itr
)->EventType
== GUILD_EVENT_LOG_DEMOTE_PLAYER
)
822 data
<< uint8((*itr
)->NewRank
);
824 data
<< uint32(time(NULL
)-(*itr
)->TimeStamp
);
826 session
->SendPacket(&data
);
827 sLog
.outDebug("WORLD: Sent (MSG_GUILD_EVENT_LOG_QUERY)");
830 // Load guild eventlog from DB
831 void Guild::LoadGuildEventLogFromDB()
833 // Return if already loaded
834 if (m_eventlogloaded
)
837 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp FROM guild_eventlog WHERE guildid=%u ORDER BY LogGuid DESC LIMIT %u", Id
, GUILD_EVENTLOG_MAX_ENTRIES
);
842 Field
*fields
= result
->Fetch();
843 GuildEventlogEntry
*NewEvent
= new GuildEventlogEntry
;
845 NewEvent
->LogGuid
= fields
[0].GetUInt32();
846 NewEvent
->EventType
= fields
[1].GetUInt8();
847 NewEvent
->PlayerGuid1
= fields
[2].GetUInt32();
848 NewEvent
->PlayerGuid2
= fields
[3].GetUInt32();
849 NewEvent
->NewRank
= fields
[4].GetUInt8();
850 NewEvent
->TimeStamp
= fields
[5].GetUInt64();
852 m_GuildEventlog
.push_front(NewEvent
);
854 } while( result
->NextRow() );
857 // Check lists size in case to many event entries in db
858 // This cases can happen only if a crash occured somewhere and table has too many log entries
859 if (!m_GuildEventlog
.empty())
861 CharacterDatabase
.PExecute("DELETE FROM guild_eventlog WHERE guildid=%u AND LogGuid < %u", Id
, m_GuildEventlog
.front()->LogGuid
);
863 m_eventlogloaded
= true;
866 // Unload guild eventlog
867 void Guild::UnloadGuildEventlog()
869 if (!m_eventlogloaded
)
871 GuildEventlogEntry
*EventLogEntry
;
872 if( !m_GuildEventlog
.empty() )
876 EventLogEntry
= *(m_GuildEventlog
.begin());
877 m_GuildEventlog
.pop_front();
878 delete EventLogEntry
;
879 }while( !m_GuildEventlog
.empty() );
881 m_eventlogloaded
= false;
884 // This will renum guids used at load to prevent always going up until infinit
885 void Guild::RenumGuildEventlog()
887 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT Min(LogGuid), Max(LogGuid) FROM guild_eventlog WHERE guildid = %u", Id
);
891 Field
*fields
= result
->Fetch();
892 CharacterDatabase
.PExecute("UPDATE guild_eventlog SET LogGuid=LogGuid-%u+1 WHERE guildid=%u ORDER BY LogGuid %s",fields
[0].GetUInt32(), Id
, fields
[0].GetUInt32()?"ASC":"DESC");
893 GuildEventlogMaxGuid
= fields
[1].GetUInt32()+1;
897 // Add entry to guild eventlog
898 void Guild::LogGuildEvent(uint8 EventType
, uint32 PlayerGuid1
, uint32 PlayerGuid2
, uint8 NewRank
)
900 GuildEventlogEntry
*NewEvent
= new GuildEventlogEntry
;
902 NewEvent
->LogGuid
= GuildEventlogMaxGuid
++;
903 NewEvent
->EventType
= EventType
;
904 NewEvent
->PlayerGuid1
= PlayerGuid1
;
905 NewEvent
->PlayerGuid2
= PlayerGuid2
;
906 NewEvent
->NewRank
= NewRank
;
907 NewEvent
->TimeStamp
= uint32(time(NULL
));
908 // Check max entry limit and delete from db if needed
909 if (m_GuildEventlog
.size() > GUILD_EVENTLOG_MAX_ENTRIES
)
911 GuildEventlogEntry
*OldEvent
= *(m_GuildEventlog
.begin());
912 m_GuildEventlog
.pop_front();
913 CharacterDatabase
.PExecute("DELETE FROM guild_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id
, OldEvent
->LogGuid
);
917 m_GuildEventlog
.push_back(NewEvent
);
918 // Add new eventlog entry into DB
919 CharacterDatabase
.PExecute("INSERT INTO guild_eventlog (guildid, LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','" I64FMTD
"')",
920 Id
, NewEvent
->LogGuid
, uint32(NewEvent
->EventType
), NewEvent
->PlayerGuid1
, NewEvent
->PlayerGuid2
, uint32(NewEvent
->NewRank
), NewEvent
->TimeStamp
);
923 // *************************************************
925 // *************************************************
926 // Bank content related
927 void Guild::DisplayGuildBankContent(WorldSession
*session
, uint8 TabId
)
929 WorldPacket
data(SMSG_GUILD_BANK_LIST
,1200);
931 GuildBankTab
const* tab
= GetBankTab(TabId
);
935 if(!IsMemberHaveRights(session
->GetPlayer()->GetGUIDLow(),TabId
,GUILD_BANK_RIGHT_VIEW_TAB
))
938 data
<< uint64(GetGuildBankMoney());
939 data
<< uint8(TabId
);
940 // remaining slots for today
941 data
<< uint32(GetMemberSlotWithdrawRem(session
->GetPlayer()->GetGUIDLow(), TabId
));
942 data
<< uint8(0); // Tell client this is a tab content packet
944 data
<< uint8(GUILD_BANK_MAX_SLOTS
);
946 for (int i
=0; i
<GUILD_BANK_MAX_SLOTS
; ++i
)
947 AppendDisplayGuildBankSlot(data
, tab
, i
);
949 session
->SendPacket(&data
);
951 sLog
.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
954 void Guild::DisplayGuildBankMoneyUpdate()
956 WorldPacket
data(SMSG_GUILD_BANK_LIST
, 8+1+4+1+1);
958 data
<< uint64(GetGuildBankMoney());
959 data
<< uint8(0); // TabId, default 0
960 data
<< uint32(0); // slot withdrow, default 0
961 data
<< uint8(0); // Tell client this is a tab content packet
962 data
<< uint8(0); // not send items
963 BroadcastPacket(&data
);
965 sLog
.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
968 void Guild::DisplayGuildBankContentUpdate(uint8 TabId
, int32 slot1
, int32 slot2
)
970 GuildBankTab
const* tab
= GetBankTab(TabId
);
974 WorldPacket
data(SMSG_GUILD_BANK_LIST
,1200);
976 data
<< uint64(GetGuildBankMoney());
977 data
<< uint8(TabId
);
978 // remaining slots for today
980 size_t rempos
= data
.wpos();
981 data
<< uint32(0); // will be filled later
982 data
<< uint8(0); // Tell client this is a tab content packet
984 if(slot2
==-1) // single item in slot1
988 AppendDisplayGuildBankSlot(data
, tab
, slot1
);
990 else // 2 items (in slot1 and slot2)
995 std::swap(slot1
,slot2
);
997 AppendDisplayGuildBankSlot(data
, tab
, slot1
);
998 AppendDisplayGuildBankSlot(data
, tab
, slot2
);
1001 for(MemberList::const_iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
1003 Player
*player
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
1007 if(!IsMemberHaveRights(itr
->first
,TabId
,GUILD_BANK_RIGHT_VIEW_TAB
))
1010 data
.put
<uint32
>(rempos
,uint32(GetMemberSlotWithdrawRem(player
->GetGUIDLow(), TabId
)));
1012 player
->GetSession()->SendPacket(&data
);
1015 sLog
.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1018 void Guild::DisplayGuildBankContentUpdate(uint8 TabId
, GuildItemPosCountVec
const& slots
)
1020 GuildBankTab
const* tab
= GetBankTab(TabId
);
1024 WorldPacket
data(SMSG_GUILD_BANK_LIST
,1200);
1026 data
<< uint64(GetGuildBankMoney());
1027 data
<< uint8(TabId
);
1028 // remaining slots for today
1030 size_t rempos
= data
.wpos();
1031 data
<< uint32(0); // will be filled later
1032 data
<< uint8(0); // Tell client this is a tab content packet
1034 data
<< uint8(slots
.size()); // updates count
1036 for(GuildItemPosCountVec::const_iterator itr
= slots
.begin(); itr
!= slots
.end(); ++itr
)
1037 AppendDisplayGuildBankSlot(data
, tab
, itr
->slot
);
1039 for(MemberList::const_iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
1041 Player
*player
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
1045 if(!IsMemberHaveRights(itr
->first
,TabId
,GUILD_BANK_RIGHT_VIEW_TAB
))
1048 data
.put
<uint32
>(rempos
,uint32(GetMemberSlotWithdrawRem(player
->GetGUIDLow(), TabId
)));
1050 player
->GetSession()->SendPacket(&data
);
1053 sLog
.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1056 Item
* Guild::GetItem(uint8 TabId
, uint8 SlotId
)
1058 if (TabId
>= m_TabListMap
.size() || SlotId
>= GUILD_BANK_MAX_SLOTS
)
1060 return m_TabListMap
[TabId
]->Slots
[SlotId
];
1063 // *************************************************
1066 void Guild::DisplayGuildBankTabsInfo(WorldSession
*session
)
1068 // Time to load bank if not already done
1070 LoadGuildBankFromDB();
1072 WorldPacket
data(SMSG_GUILD_BANK_LIST
, 500);
1074 data
<< uint64(GetGuildBankMoney());
1075 data
<< uint8(0); // TabInfo packet must be for TabId 0
1076 data
<< uint32(0xFFFFFFFF); // bit 9 must be set for this packet to work
1077 data
<< uint8(1); // Tell Client this is a TabInfo packet
1079 data
<< uint8(purchased_tabs
); // here is the number of tabs
1081 for(int i
= 0; i
< purchased_tabs
; ++i
)
1083 data
<< m_TabListMap
[i
]->Name
.c_str();
1084 data
<< m_TabListMap
[i
]->Icon
.c_str();
1086 data
<< uint8(0); // Do not send tab content
1087 session
->SendPacket(&data
);
1089 sLog
.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1092 void Guild::CreateNewBankTab()
1094 if (purchased_tabs
>= GUILD_BANK_MAX_TABS
)
1099 GuildBankTab
* AnotherTab
= new GuildBankTab
;
1100 memset(AnotherTab
->Slots
, 0, GUILD_BANK_MAX_SLOTS
* sizeof(Item
*));
1101 m_TabListMap
.resize(purchased_tabs
);
1102 m_TabListMap
[purchased_tabs
-1] = AnotherTab
;
1104 CharacterDatabase
.BeginTransaction();
1105 CharacterDatabase
.PExecute("DELETE FROM guild_bank_tab WHERE guildid='%u' AND TabId='%u'", Id
, uint32(purchased_tabs
-1));
1106 CharacterDatabase
.PExecute("INSERT INTO guild_bank_tab (guildid,TabId) VALUES ('%u','%u')", Id
, uint32(purchased_tabs
-1));
1107 CharacterDatabase
.CommitTransaction();
1110 void Guild::SetGuildBankTabInfo(uint8 TabId
, std::string Name
, std::string Icon
)
1112 if (TabId
>= GUILD_BANK_MAX_TABS
)
1114 if (TabId
>= m_TabListMap
.size())
1117 if (!m_TabListMap
[TabId
])
1120 if(m_TabListMap
[TabId
]->Name
== Name
&& m_TabListMap
[TabId
]->Icon
== Icon
)
1123 m_TabListMap
[TabId
]->Name
= Name
;
1124 m_TabListMap
[TabId
]->Icon
= Icon
;
1126 CharacterDatabase
.escape_string(Name
);
1127 CharacterDatabase
.escape_string(Icon
);
1128 CharacterDatabase
.PExecute("UPDATE guild_bank_tab SET TabName='%s',TabIcon='%s' WHERE guildid='%u' AND TabId='%u'", Name
.c_str(), Icon
.c_str(), Id
, uint32(TabId
));
1131 void Guild::CreateBankRightForTab(uint32 rankId
, uint8 TabId
)
1133 sLog
.outDebug("CreateBankRightForTab. rank: %u, TabId: %u", rankId
, uint32(TabId
));
1134 if (rankId
>= m_ranks
.size() || TabId
>= GUILD_BANK_MAX_TABS
)
1137 m_ranks
[rankId
].TabRight
[TabId
]=0;
1138 m_ranks
[rankId
].TabSlotPerDay
[TabId
]=0;
1139 CharacterDatabase
.BeginTransaction();
1140 CharacterDatabase
.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u' AND TabId = '%u' AND rid = '%u'", Id
, uint32(TabId
), rankId
);
1141 CharacterDatabase
.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid) VALUES ('%u','%u','%u')", Id
, uint32(TabId
), rankId
);
1142 CharacterDatabase
.CommitTransaction();
1145 uint32
Guild::GetBankRights(uint32 rankId
, uint8 TabId
) const
1147 if(rankId
>= m_ranks
.size() || TabId
>= GUILD_BANK_MAX_TABS
)
1150 return m_ranks
[rankId
].TabRight
[TabId
];
1153 // *************************************************
1154 // Guild bank loading/unloading related
1156 // This load should be called when the bank is first accessed by a guild member
1157 void Guild::LoadGuildBankFromDB()
1162 m_bankloaded
= true;
1163 LoadGuildBankEventLogFromDB();
1166 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT TabId, TabName, TabIcon, TabText FROM guild_bank_tab WHERE guildid='%u' ORDER BY TabId", Id
);
1173 m_TabListMap
.resize(purchased_tabs
);
1176 Field
*fields
= result
->Fetch();
1177 uint8 TabId
= fields
[0].GetUInt8();
1179 GuildBankTab
*NewTab
= new GuildBankTab
;
1180 memset(NewTab
->Slots
, 0, GUILD_BANK_MAX_SLOTS
* sizeof(Item
*));
1182 NewTab
->Name
= fields
[1].GetCppString();
1183 NewTab
->Icon
= fields
[2].GetCppString();
1184 NewTab
->Text
= fields
[3].GetCppString();
1186 m_TabListMap
[TabId
] = NewTab
;
1187 }while( result
->NextRow() );
1191 // data needs to be at first place for Item::LoadFromDB
1193 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", Id
);
1199 Field
*fields
= result
->Fetch();
1200 uint8 TabId
= fields
[1].GetUInt8();
1201 uint8 SlotId
= fields
[2].GetUInt8();
1202 uint32 ItemGuid
= fields
[3].GetUInt32();
1203 uint32 ItemEntry
= fields
[4].GetUInt32();
1205 if (TabId
>= purchased_tabs
|| TabId
>= GUILD_BANK_MAX_TABS
)
1207 sLog
.outError( "Guild::LoadGuildBankFromDB: Invalid tab for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid
,ItemEntry
);
1211 if (SlotId
>= GUILD_BANK_MAX_SLOTS
)
1213 sLog
.outError( "Guild::LoadGuildBankFromDB: Invalid slot for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid
,ItemEntry
);
1217 ItemPrototype
const *proto
= objmgr
.GetItemPrototype(ItemEntry
);
1221 sLog
.outError( "Guild::LoadGuildBankFromDB: Unknown item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid
,ItemEntry
);
1225 Item
*pItem
= NewItemOrBag(proto
);
1226 if(!pItem
->LoadFromDB(ItemGuid
, 0, result
))
1228 CharacterDatabase
.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'", Id
, uint32(TabId
), uint32(SlotId
));
1229 sLog
.outError("Item GUID %u not found in item_instance, deleting from Guild Bank!", ItemGuid
);
1234 pItem
->AddToWorld();
1235 m_TabListMap
[TabId
]->Slots
[SlotId
] = pItem
;
1236 }while( result
->NextRow() );
1241 // This unload should be called when the last member of the guild gets offline
1242 void Guild::UnloadGuildBank()
1246 for (uint8 i
= 0 ; i
< purchased_tabs
; ++i
)
1248 for (uint8 j
= 0 ; j
< GUILD_BANK_MAX_SLOTS
; ++j
)
1250 if (m_TabListMap
[i
]->Slots
[j
])
1252 m_TabListMap
[i
]->Slots
[j
]->RemoveFromWorld();
1253 delete m_TabListMap
[i
]->Slots
[j
];
1256 delete m_TabListMap
[i
];
1258 m_TabListMap
.clear();
1260 UnloadGuildBankEventLog();
1261 m_bankloaded
= false;
1264 // *************************************************
1265 // Money deposit/withdraw related
1267 void Guild::SendMoneyInfo(WorldSession
*session
, uint32 LowGuid
)
1269 WorldPacket
data(MSG_GUILD_BANK_MONEY_WITHDRAWN
, 4);
1270 data
<< uint32(GetMemberMoneyWithdrawRem(LowGuid
));
1271 session
->SendPacket(&data
);
1272 sLog
.outDebug("WORLD: Sent MSG_GUILD_BANK_MONEY_WITHDRAWN");
1275 bool Guild::MemberMoneyWithdraw(uint32 amount
, uint32 LowGuid
)
1277 uint32 MoneyWithDrawRight
= GetMemberMoneyWithdrawRem(LowGuid
);
1279 if (MoneyWithDrawRight
< amount
|| GetGuildBankMoney() < amount
)
1282 SetBankMoney(GetGuildBankMoney()-amount
);
1284 if (MoneyWithDrawRight
< WITHDRAW_MONEY_UNLIMITED
)
1286 MemberList::iterator itr
= members
.find(LowGuid
);
1287 if (itr
== members
.end() )
1289 itr
->second
.BankRemMoney
-= amount
;
1290 CharacterDatabase
.PExecute("UPDATE guild_member SET BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'",
1291 itr
->second
.BankRemMoney
, Id
, LowGuid
);
1296 void Guild::SetBankMoney(int64 money
)
1298 if (money
< 0) // I don't know how this happens, it does!!
1300 guildbank_money
= money
;
1302 CharacterDatabase
.PExecute("UPDATE guild SET BankMoney='" I64FMTD
"' WHERE guildid='%u'", money
, Id
);
1305 // *************************************************
1306 // Item per day and money per day related
1308 bool Guild::MemberItemWithdraw(uint8 TabId
, uint32 LowGuid
)
1310 uint32 SlotsWithDrawRight
= GetMemberSlotWithdrawRem(LowGuid
, TabId
);
1312 if (SlotsWithDrawRight
== 0)
1315 if (SlotsWithDrawRight
< WITHDRAW_SLOT_UNLIMITED
)
1317 MemberList::iterator itr
= members
.find(LowGuid
);
1318 if (itr
== members
.end() )
1320 --itr
->second
.BankRemSlotsTab
[TabId
];
1321 CharacterDatabase
.PExecute("UPDATE guild_member SET BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'",
1322 uint32(TabId
), itr
->second
.BankRemSlotsTab
[TabId
], Id
, LowGuid
);
1327 bool Guild::IsMemberHaveRights(uint32 LowGuid
, uint8 TabId
, uint32 rights
) const
1329 MemberList::const_iterator itr
= members
.find(LowGuid
);
1330 if (itr
== members
.end() )
1333 if (itr
->second
.RankId
== GR_GUILDMASTER
)
1336 return (GetBankRights(itr
->second
.RankId
,TabId
) & rights
)==rights
;
1339 uint32
Guild::GetMemberSlotWithdrawRem(uint32 LowGuid
, uint8 TabId
)
1341 MemberList::iterator itr
= members
.find(LowGuid
);
1342 if (itr
== members
.end() )
1345 if (itr
->second
.RankId
== GR_GUILDMASTER
)
1346 return WITHDRAW_SLOT_UNLIMITED
;
1348 if((GetBankRights(itr
->second
.RankId
,TabId
) & GUILD_BANK_RIGHT_VIEW_TAB
)!=GUILD_BANK_RIGHT_VIEW_TAB
)
1351 uint32 curTime
= uint32(time(NULL
)/MINUTE
);
1352 if (curTime
- itr
->second
.BankResetTimeTab
[TabId
] >= 24*HOUR
/MINUTE
)
1354 itr
->second
.BankResetTimeTab
[TabId
] = curTime
;
1355 itr
->second
.BankRemSlotsTab
[TabId
] = GetBankSlotPerDay(itr
->second
.RankId
, TabId
);
1356 CharacterDatabase
.PExecute("UPDATE guild_member SET BankResetTimeTab%u='%u',BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'",
1357 uint32(TabId
), itr
->second
.BankResetTimeTab
[TabId
], uint32(TabId
), itr
->second
.BankRemSlotsTab
[TabId
], Id
, LowGuid
);
1359 return itr
->second
.BankRemSlotsTab
[TabId
];
1362 uint32
Guild::GetMemberMoneyWithdrawRem(uint32 LowGuid
)
1364 MemberList::iterator itr
= members
.find(LowGuid
);
1365 if (itr
== members
.end() )
1368 if (itr
->second
.RankId
== GR_GUILDMASTER
)
1369 return WITHDRAW_MONEY_UNLIMITED
;
1371 uint32 curTime
= uint32(time(NULL
)/MINUTE
); // minutes
1373 if (curTime
> itr
->second
.BankResetTimeMoney
+ 24*HOUR
/MINUTE
)
1375 itr
->second
.BankResetTimeMoney
= curTime
;
1376 itr
->second
.BankRemMoney
= GetBankMoneyPerDay(itr
->second
.RankId
);
1377 CharacterDatabase
.PExecute("UPDATE guild_member SET BankResetTimeMoney='%u',BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'",
1378 itr
->second
.BankResetTimeMoney
, itr
->second
.BankRemMoney
, Id
, LowGuid
);
1380 return itr
->second
.BankRemMoney
;
1383 void Guild::SetBankMoneyPerDay(uint32 rankId
, uint32 money
)
1385 if (rankId
>= m_ranks
.size())
1388 if (rankId
== GR_GUILDMASTER
)
1389 money
= WITHDRAW_MONEY_UNLIMITED
;
1391 m_ranks
[rankId
].BankMoneyPerDay
= money
;
1393 for (MemberList::iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
1394 if (itr
->second
.RankId
== rankId
)
1395 itr
->second
.BankResetTimeMoney
= 0;
1397 CharacterDatabase
.PExecute("UPDATE guild_rank SET BankMoneyPerDay='%u' WHERE rid='%u' AND guildid='%u'", money
, (rankId
+1), Id
);
1398 CharacterDatabase
.PExecute("UPDATE guild_member SET BankResetTimeMoney='0' WHERE guildid='%u' AND rank='%u'", Id
, rankId
);
1401 void Guild::SetBankRightsAndSlots(uint32 rankId
, uint8 TabId
, uint32 right
, uint32 nbSlots
, bool db
)
1403 if(rankId
>= m_ranks
.size() ||
1404 TabId
>= GUILD_BANK_MAX_TABS
||
1405 TabId
>= purchased_tabs
)
1408 if (rankId
== GR_GUILDMASTER
)
1410 nbSlots
= WITHDRAW_SLOT_UNLIMITED
;
1411 right
= GUILD_BANK_RIGHT_FULL
;
1414 m_ranks
[rankId
].TabSlotPerDay
[TabId
]=nbSlots
;
1415 m_ranks
[rankId
].TabRight
[TabId
]=right
;
1419 for (MemberList::iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
1420 if (itr
->second
.RankId
== rankId
)
1421 for (int i
= 0; i
< GUILD_BANK_MAX_TABS
; ++i
)
1422 itr
->second
.BankResetTimeTab
[i
] = 0;
1424 CharacterDatabase
.PExecute("DELETE FROM guild_bank_right WHERE guildid='%u' AND TabId='%u' AND rid='%u'", Id
, uint32(TabId
), rankId
);
1425 CharacterDatabase
.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid,gbright,SlotPerDay) VALUES "
1426 "('%u','%u','%u','%u','%u')", Id
, uint32(TabId
), rankId
, m_ranks
[rankId
].TabRight
[TabId
], m_ranks
[rankId
].TabSlotPerDay
[TabId
]);
1427 CharacterDatabase
.PExecute("UPDATE guild_member SET BankResetTimeTab%u='0' WHERE guildid='%u' AND rank='%u'", uint32(TabId
), Id
, rankId
);
1431 uint32
Guild::GetBankMoneyPerDay(uint32 rankId
)
1433 if(rankId
>= m_ranks
.size())
1436 if (rankId
== GR_GUILDMASTER
)
1437 return WITHDRAW_MONEY_UNLIMITED
;
1438 return m_ranks
[rankId
].BankMoneyPerDay
;
1441 uint32
Guild::GetBankSlotPerDay(uint32 rankId
, uint8 TabId
)
1443 if(rankId
>= m_ranks
.size() || TabId
>= GUILD_BANK_MAX_TABS
)
1446 if (rankId
== GR_GUILDMASTER
)
1447 return WITHDRAW_SLOT_UNLIMITED
;
1448 return m_ranks
[rankId
].TabSlotPerDay
[TabId
];
1451 // *************************************************
1452 // Rights per day related
1454 void Guild::LoadBankRightsFromDB(uint32 GuildId
)
1457 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT TabId, rid, gbright, SlotPerDay FROM guild_bank_right WHERE guildid = '%u' ORDER BY TabId", GuildId
);
1464 Field
*fields
= result
->Fetch();
1465 uint8 TabId
= fields
[0].GetUInt8();
1466 uint32 rankId
= fields
[1].GetUInt32();
1467 uint16 right
= fields
[2].GetUInt16();
1468 uint16 SlotPerDay
= fields
[3].GetUInt16();
1470 SetBankRightsAndSlots(rankId
, TabId
, right
, SlotPerDay
, false);
1472 }while( result
->NextRow() );
1478 // *************************************************
1481 void Guild::LoadGuildBankEventLogFromDB()
1483 // We can't add a limit as in Guild::LoadGuildEventLogFromDB since we fetch both money and bank log and know nothing about the composition
1485 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT LogGuid, LogEntry, TabId, PlayerGuid, ItemOrMoney, ItemStackCount, DestTabId, TimeStamp FROM guild_bank_eventlog WHERE guildid='%u' ORDER BY TimeStamp DESC", Id
);
1491 Field
*fields
= result
->Fetch();
1492 GuildBankEvent
*NewEvent
= new GuildBankEvent
;
1494 NewEvent
->LogGuid
= fields
[0].GetUInt32();
1495 NewEvent
->LogEntry
= fields
[1].GetUInt8();
1496 uint8 TabId
= fields
[2].GetUInt8();
1497 NewEvent
->PlayerGuid
= fields
[3].GetUInt32();
1498 NewEvent
->ItemOrMoney
= fields
[4].GetUInt32();
1499 NewEvent
->ItemStackCount
= fields
[5].GetUInt8();
1500 NewEvent
->DestTabId
= fields
[6].GetUInt8();
1501 NewEvent
->TimeStamp
= fields
[7].GetUInt64();
1503 if (TabId
>= GUILD_BANK_MAX_TABS
)
1505 sLog
.outError( "Guild::LoadGuildBankEventLogFromDB: Invalid tabid '%u' for guild bank log entry (guild: '%s', LogGuid: %u), skipped.", TabId
, GetName().c_str(), NewEvent
->LogGuid
);
1509 if (NewEvent
->isMoneyEvent() && m_GuildBankEventLog_Money
.size() >= GUILD_BANK_MAX_LOGS
1510 || m_GuildBankEventLog_Item
[TabId
].size() >= GUILD_BANK_MAX_LOGS
)
1515 if (NewEvent
->isMoneyEvent())
1516 m_GuildBankEventLog_Money
.push_front(NewEvent
);
1518 m_GuildBankEventLog_Item
[TabId
].push_front(NewEvent
);
1520 }while( result
->NextRow() );
1523 // Check lists size in case to many event entries in db for a tab or for money
1524 // This cases can happen only if a crash occured somewhere and table has too many log entries
1525 if (!m_GuildBankEventLog_Money
.empty())
1527 CharacterDatabase
.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid=%u AND LogGuid < %u",
1528 Id
, m_GuildBankEventLog_Money
.front()->LogGuid
);
1530 for (int i
= 0; i
< GUILD_BANK_MAX_TABS
; ++i
)
1532 if (!m_GuildBankEventLog_Item
[i
].empty())
1534 CharacterDatabase
.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid=%u AND LogGuid < %u",
1535 Id
, m_GuildBankEventLog_Item
[i
].front()->LogGuid
);
1540 void Guild::UnloadGuildBankEventLog()
1542 GuildBankEvent
*EventLogEntry
;
1543 if( !m_GuildBankEventLog_Money
.empty() )
1547 EventLogEntry
= *(m_GuildBankEventLog_Money
.begin());
1548 m_GuildBankEventLog_Money
.pop_front();
1549 delete EventLogEntry
;
1550 }while( !m_GuildBankEventLog_Money
.empty() );
1553 for (int i
= 0; i
< GUILD_BANK_MAX_TABS
; ++i
)
1555 if( !m_GuildBankEventLog_Item
[i
].empty() )
1559 EventLogEntry
= *(m_GuildBankEventLog_Item
[i
].begin());
1560 m_GuildBankEventLog_Item
[i
].pop_front();
1561 delete EventLogEntry
;
1562 }while( !m_GuildBankEventLog_Item
[i
].empty() );
1567 void Guild::DisplayGuildBankLogs(WorldSession
*session
, uint8 TabId
)
1569 if (TabId
> GUILD_BANK_MAX_TABS
)
1572 if (TabId
== GUILD_BANK_MAX_TABS
)
1574 // Here we display money logs
1575 WorldPacket
data(MSG_GUILD_BANK_LOG_QUERY
, m_GuildBankEventLog_Money
.size()*(4*4+1)+1+1);
1576 data
<< uint8(TabId
); // Here GUILD_BANK_MAX_TABS
1577 data
<< uint8(m_GuildBankEventLog_Money
.size()); // number of log entries
1578 for (GuildBankEventLog::const_iterator itr
= m_GuildBankEventLog_Money
.begin(); itr
!= m_GuildBankEventLog_Money
.end(); ++itr
)
1580 data
<< uint8((*itr
)->LogEntry
);
1581 data
<< uint64(MAKE_NEW_GUID((*itr
)->PlayerGuid
,0,HIGHGUID_PLAYER
));
1582 if ((*itr
)->LogEntry
== GUILD_BANK_LOG_DEPOSIT_MONEY
||
1583 (*itr
)->LogEntry
== GUILD_BANK_LOG_WITHDRAW_MONEY
||
1584 (*itr
)->LogEntry
== GUILD_BANK_LOG_REPAIR_MONEY
||
1585 (*itr
)->LogEntry
== GUILD_BANK_LOG_UNK1
||
1586 (*itr
)->LogEntry
== GUILD_BANK_LOG_UNK2
)
1588 data
<< uint32((*itr
)->ItemOrMoney
);
1592 data
<< uint32((*itr
)->ItemOrMoney
);
1593 data
<< uint32((*itr
)->ItemStackCount
);
1594 if ((*itr
)->LogEntry
== GUILD_BANK_LOG_MOVE_ITEM
|| (*itr
)->LogEntry
== GUILD_BANK_LOG_MOVE_ITEM2
)
1595 data
<< uint8((*itr
)->DestTabId
); // moved tab
1597 data
<< uint32(time(NULL
)-(*itr
)->TimeStamp
);
1599 session
->SendPacket(&data
);
1603 // here we display current tab logs
1604 WorldPacket
data(MSG_GUILD_BANK_LOG_QUERY
, m_GuildBankEventLog_Item
[TabId
].size()*(4*4+1+1)+1+1);
1605 data
<< uint8(TabId
); // Here a real Tab Id
1606 // number of log entries
1607 data
<< uint8(m_GuildBankEventLog_Item
[TabId
].size());
1608 for (GuildBankEventLog::const_iterator itr
= m_GuildBankEventLog_Item
[TabId
].begin(); itr
!= m_GuildBankEventLog_Item
[TabId
].end(); ++itr
)
1610 data
<< uint8((*itr
)->LogEntry
);
1611 data
<< uint64(MAKE_NEW_GUID((*itr
)->PlayerGuid
,0,HIGHGUID_PLAYER
));
1612 if ((*itr
)->LogEntry
== GUILD_BANK_LOG_DEPOSIT_MONEY
||
1613 (*itr
)->LogEntry
== GUILD_BANK_LOG_WITHDRAW_MONEY
||
1614 (*itr
)->LogEntry
== GUILD_BANK_LOG_REPAIR_MONEY
||
1615 (*itr
)->LogEntry
== GUILD_BANK_LOG_UNK1
||
1616 (*itr
)->LogEntry
== GUILD_BANK_LOG_UNK2
)
1618 data
<< uint32((*itr
)->ItemOrMoney
);
1622 data
<< uint32((*itr
)->ItemOrMoney
);
1623 data
<< uint32((*itr
)->ItemStackCount
);
1624 if ((*itr
)->LogEntry
== GUILD_BANK_LOG_MOVE_ITEM
|| (*itr
)->LogEntry
== GUILD_BANK_LOG_MOVE_ITEM2
)
1625 data
<< uint8((*itr
)->DestTabId
); // moved tab
1627 data
<< uint32(time(NULL
)-(*itr
)->TimeStamp
);
1629 session
->SendPacket(&data
);
1631 sLog
.outDebug("WORLD: Sent (MSG_GUILD_BANK_LOG_QUERY)");
1634 void Guild::LogBankEvent(uint8 LogEntry
, uint8 TabId
, uint32 PlayerGuidLow
, uint32 ItemOrMoney
, uint8 ItemStackCount
, uint8 DestTabId
)
1636 GuildBankEvent
*NewEvent
= new GuildBankEvent
;
1638 NewEvent
->LogGuid
= LogMaxGuid
++;
1639 NewEvent
->LogEntry
= LogEntry
;
1640 NewEvent
->PlayerGuid
= PlayerGuidLow
;
1641 NewEvent
->ItemOrMoney
= ItemOrMoney
;
1642 NewEvent
->ItemStackCount
= ItemStackCount
;
1643 NewEvent
->DestTabId
= DestTabId
;
1644 NewEvent
->TimeStamp
= uint32(time(NULL
));
1646 if (NewEvent
->isMoneyEvent())
1648 if (m_GuildBankEventLog_Money
.size() > GUILD_BANK_MAX_LOGS
)
1650 GuildBankEvent
*OldEvent
= *(m_GuildBankEventLog_Money
.begin());
1651 m_GuildBankEventLog_Money
.pop_front();
1652 CharacterDatabase
.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id
, OldEvent
->LogGuid
);
1655 m_GuildBankEventLog_Money
.push_back(NewEvent
);
1659 if (m_GuildBankEventLog_Item
[TabId
].size() > GUILD_BANK_MAX_LOGS
)
1661 GuildBankEvent
*OldEvent
= *(m_GuildBankEventLog_Item
[TabId
].begin());
1662 m_GuildBankEventLog_Item
[TabId
].pop_front();
1663 CharacterDatabase
.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id
, OldEvent
->LogGuid
);
1666 m_GuildBankEventLog_Item
[TabId
].push_back(NewEvent
);
1668 CharacterDatabase
.PExecute("INSERT INTO guild_bank_eventlog (guildid,LogGuid,LogEntry,TabId,PlayerGuid,ItemOrMoney,ItemStackCount,DestTabId,TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','%u','%u','" I64FMTD
"')",
1669 Id
, NewEvent
->LogGuid
, uint32(NewEvent
->LogEntry
), uint32(TabId
), NewEvent
->PlayerGuid
, NewEvent
->ItemOrMoney
, uint32(NewEvent
->ItemStackCount
), uint32(NewEvent
->DestTabId
), NewEvent
->TimeStamp
);
1672 // This will renum guids used at load to prevent always going up until infinit
1673 void Guild::RenumBankLogs()
1675 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT Min(LogGuid), Max(LogGuid) FROM guild_bank_eventlog WHERE guildid = %u", Id
);
1679 Field
*fields
= result
->Fetch();
1680 CharacterDatabase
.PExecute("UPDATE guild_bank_eventlog SET LogGuid=LogGuid-%u+1 WHERE guildid=%u ORDER BY LogGuid %s",fields
[0].GetUInt32(), Id
, fields
[0].GetUInt32()?"ASC":"DESC");
1681 LogMaxGuid
= fields
[1].GetUInt32()+1;
1685 bool Guild::AddGBankItemToDB(uint32 GuildId
, uint32 BankTab
, uint32 BankTabSlot
, uint32 GUIDLow
, uint32 Entry
)
1687 CharacterDatabase
.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u' AND TabId = '%u'AND SlotId = '%u'", GuildId
, BankTab
, BankTabSlot
);
1688 CharacterDatabase
.PExecute("INSERT INTO guild_bank_item (guildid,TabId,SlotId,item_guid,item_entry) "
1689 "VALUES ('%u', '%u', '%u', '%u', '%u')", GuildId
, BankTab
, BankTabSlot
, GUIDLow
, Entry
);
1693 void Guild::AppendDisplayGuildBankSlot( WorldPacket
& data
, GuildBankTab
const *tab
, int slot
)
1695 Item
*pItem
= tab
->Slots
[slot
];
1696 uint32 entry
= pItem
? pItem
->GetEntry() : 0;
1698 data
<< uint8(slot
);
1699 data
<< uint32(entry
);
1702 // random item property id +8
1703 data
<< (uint32
) pItem
->GetItemRandomPropertyId();
1704 if (pItem
->GetItemRandomPropertyId())
1706 data
<< (uint32
) pItem
->GetItemSuffixFactor();
1707 // +12 // ITEM_FIELD_STACK_COUNT
1708 data
<< uint32(pItem
->GetCount());
1709 data
<< uint32(0); // +16 // Unknown value
1710 data
<< uint8(0); // unknown 2.4.2
1711 if (uint32 Enchant0
= pItem
->GetEnchantmentId(PERM_ENCHANTMENT_SLOT
))
1713 data
<< uint8(1); // number of enchantments (max 3) why max 3?
1714 data
<< uint8(PERM_ENCHANTMENT_SLOT
); // enchantment slot (range: 0:2)
1715 data
<< uint32(Enchant0
); // enchantment id
1718 data
<< uint8(0); // no enchantments (0)
1722 Item
* Guild::StoreItem(uint8 tabId
, GuildItemPosCountVec
const& dest
, Item
* pItem
)
1727 Item
* lastItem
= pItem
;
1729 for(GuildItemPosCountVec::const_iterator itr
= dest
.begin(); itr
!= dest
.end(); )
1731 uint8 slot
= itr
->slot
;
1732 uint32 count
= itr
->count
;
1736 if(itr
== dest
.end())
1738 lastItem
= _StoreItem(tabId
,slot
,pItem
,count
,false);
1742 lastItem
= _StoreItem(tabId
,slot
,pItem
,count
,true);
1748 // Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
1749 Item
* Guild::_StoreItem( uint8 tab
, uint8 slot
, Item
*pItem
, uint32 count
, bool clone
)
1754 sLog
.outDebug( "GUILD STORAGE: StoreItem tab = %u, slot = %u, item = %u, count = %u", tab
, slot
, pItem
->GetEntry(), count
);
1756 Item
* pItem2
= m_TabListMap
[tab
]->Slots
[slot
];
1761 pItem
= pItem
->CloneItem(count
);
1763 pItem
->SetCount(count
);
1768 m_TabListMap
[tab
]->Slots
[slot
] = pItem
;
1770 pItem
->SetUInt64Value(ITEM_FIELD_CONTAINED
, 0);
1771 pItem
->SetUInt64Value(ITEM_FIELD_OWNER
, 0);
1772 AddGBankItemToDB(GetId(), tab
, slot
, pItem
->GetGUIDLow(), pItem
->GetEntry());
1773 pItem
->FSetState(ITEM_NEW
);
1774 pItem
->SaveToDB(); // not in onventory and can be save standalone
1780 pItem2
->SetCount( pItem2
->GetCount() + count
);
1781 pItem2
->FSetState(ITEM_CHANGED
);
1782 pItem2
->SaveToDB(); // not in onventory and can be save standalone
1786 pItem
->RemoveFromWorld();
1787 pItem
->DeleteFromDB();
1795 void Guild::RemoveItem(uint8 tab
, uint8 slot
)
1797 m_TabListMap
[tab
]->Slots
[slot
] = NULL
;
1798 CharacterDatabase
.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'",
1799 GetId(), uint32(tab
), uint32(slot
));
1802 uint8
Guild::_CanStoreItem_InSpecificSlot( uint8 tab
, uint8 slot
, GuildItemPosCountVec
&dest
, uint32
& count
, bool swap
, Item
* pSrcItem
) const
1804 Item
* pItem2
= m_TabListMap
[tab
]->Slots
[slot
];
1806 // ignore move item (this slot will be empty at move)
1807 if(pItem2
==pSrcItem
)
1812 // empty specific slot - check item fit to slot
1813 if( !pItem2
|| swap
)
1815 // non empty stack with space
1816 need_space
= pSrcItem
->GetMaxStackCount();
1818 // non empty slot, check item type
1822 if(pItem2
->GetEntry() != pSrcItem
->GetEntry())
1823 return EQUIP_ERR_ITEM_CANT_STACK
;
1826 if(pItem2
->GetCount() >= pSrcItem
->GetMaxStackCount())
1827 return EQUIP_ERR_ITEM_CANT_STACK
;
1829 need_space
= pSrcItem
->GetMaxStackCount() - pItem2
->GetCount();
1832 if(need_space
> count
)
1835 GuildItemPosCount newPosition
= GuildItemPosCount(slot
,need_space
);
1836 if(!newPosition
.isContainedIn(dest
))
1838 dest
.push_back(newPosition
);
1839 count
-= need_space
;
1842 return EQUIP_ERR_OK
;
1845 uint8
Guild::_CanStoreItem_InTab( uint8 tab
, GuildItemPosCountVec
&dest
, uint32
& count
, bool merge
, Item
* pSrcItem
, uint8 skip_slot
) const
1847 for(uint32 j
= 0; j
< GUILD_BANK_MAX_SLOTS
; j
++)
1849 // skip specific slot already processed in first called _CanStoreItem_InSpecificSlot
1853 Item
* pItem2
= m_TabListMap
[tab
]->Slots
[j
];
1855 // ignore move item (this slot will be empty at move)
1856 if(pItem2
==pSrcItem
)
1859 // if merge skip empty, if !merge skip non-empty
1860 if((pItem2
!=NULL
)!=merge
)
1865 if(pItem2
->GetEntry() == pSrcItem
->GetEntry() && pItem2
->GetCount() < pSrcItem
->GetMaxStackCount() )
1867 uint32 need_space
= pSrcItem
->GetMaxStackCount() - pItem2
->GetCount();
1868 if(need_space
> count
)
1871 GuildItemPosCount newPosition
= GuildItemPosCount(j
,need_space
);
1872 if(!newPosition
.isContainedIn(dest
))
1874 dest
.push_back(newPosition
);
1875 count
-= need_space
;
1878 return EQUIP_ERR_OK
;
1884 uint32 need_space
= pSrcItem
->GetMaxStackCount();
1885 if(need_space
> count
)
1888 GuildItemPosCount newPosition
= GuildItemPosCount(j
,need_space
);
1889 if(!newPosition
.isContainedIn(dest
))
1891 dest
.push_back(newPosition
);
1892 count
-= need_space
;
1895 return EQUIP_ERR_OK
;
1899 return EQUIP_ERR_OK
;
1902 uint8
Guild::CanStoreItem( uint8 tab
, uint8 slot
, GuildItemPosCountVec
&dest
, uint32 count
, Item
*pItem
, bool swap
) const
1904 sLog
.outDebug( "GUILD STORAGE: CanStoreItem tab = %u, slot = %u, item = %u, count = %u", tab
, slot
, pItem
->GetEntry(), count
);
1906 if(count
> pItem
->GetCount())
1907 return EQUIP_ERR_COULDNT_SPLIT_ITEMS
;
1909 if(pItem
->IsSoulBound())
1910 return EQUIP_ERR_CANT_DROP_SOULBOUND
;
1913 if( slot
!= NULL_SLOT
)
1915 uint8 res
= _CanStoreItem_InSpecificSlot(tab
,slot
,dest
,count
,swap
,pItem
);
1916 if(res
!=EQUIP_ERR_OK
)
1920 return EQUIP_ERR_OK
;
1923 // not specific slot or have spece for partly store only in specific slot
1925 // search stack in tab for merge to
1926 if( pItem
->GetMaxStackCount() > 1 )
1928 uint8 res
= _CanStoreItem_InTab(tab
,dest
,count
,true,pItem
,slot
);
1929 if(res
!=EQUIP_ERR_OK
)
1933 return EQUIP_ERR_OK
;
1936 // search free slot in bag for place to
1937 uint8 res
= _CanStoreItem_InTab(tab
,dest
,count
,false,pItem
,slot
);
1938 if(res
!=EQUIP_ERR_OK
)
1942 return EQUIP_ERR_OK
;
1944 return EQUIP_ERR_BANK_FULL
;
1947 void Guild::SetGuildBankTabText(uint8 TabId
, std::string text
)
1949 if (TabId
>= GUILD_BANK_MAX_TABS
)
1951 if (TabId
>= m_TabListMap
.size())
1953 if (!m_TabListMap
[TabId
])
1956 if(m_TabListMap
[TabId
]->Text
==text
)
1959 utf8truncate(text
,500); // DB and client size limitation
1961 m_TabListMap
[TabId
]->Text
= text
;
1963 CharacterDatabase
.escape_string(text
);
1964 CharacterDatabase
.PExecute("UPDATE guild_bank_tab SET TabText='%s' WHERE guildid='%u' AND TabId='%u'", text
.c_str(), Id
, uint32(TabId
));
1967 SendGuildBankTabText(NULL
,TabId
);
1970 void Guild::SendGuildBankTabText(WorldSession
*session
, uint8 TabId
)
1972 if (TabId
> GUILD_BANK_MAX_TABS
)
1975 GuildBankTab
const *tab
= GetBankTab(TabId
);
1979 WorldPacket
data(MSG_QUERY_GUILD_BANK_TEXT
, 1+tab
->Text
.size()+1);
1980 data
<< uint8(TabId
);
1984 session
->SendPacket(&data
);
1986 BroadcastPacket(&data
);
1990 bool GuildItemPosCount::isContainedIn(GuildItemPosCountVec
const &vec
) const
1992 for(GuildItemPosCountVec::const_iterator itr
= vec
.begin(); itr
!= vec
.end();++itr
)
1993 if(itr
->slot
== slot
)