2 * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "Database/DatabaseEnv.h"
20 #include "WorldPacket.h"
21 #include "WorldSession.h"
22 #include "MapManager.h"
25 #include "ObjectMgr.h"
28 #include "SocialMgr.h"
53 bool Guild::create(uint64 lGuid
, std::string gname
)
58 if(!objmgr
.GetPlayerNameByGUID(lGuid
, lName
))
60 if(objmgr
.GetGuildByName(gname
))
63 sLog
.outDebug("GUILD: creating guild %s to leader: %u", gname
.c_str(), GUID_LOPART(lGuid
));
68 MOTD
= "No message set.";
72 Id
= objmgr
.GenerateGuildId();
74 // gname already assigned to Guild::name, use it to encode string for DB
75 CharacterDatabase
.escape_string(gname
);
77 std::string dbGINFO
= GINFO
;
78 std::string dbMOTD
= MOTD
;
79 CharacterDatabase
.escape_string(dbGINFO
);
80 CharacterDatabase
.escape_string(dbMOTD
);
82 CharacterDatabase
.BeginTransaction();
83 // CharacterDatabase.PExecute("DELETE FROM guild WHERE guildid='%u'", Id); - MAX(guildid)+1 not exist
84 CharacterDatabase
.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", Id
);
85 CharacterDatabase
.PExecute("DELETE FROM guild_member WHERE guildid='%u'", Id
);
86 CharacterDatabase
.PExecute("INSERT INTO guild (guildid,name,leaderguid,info,motd,createdate,EmblemStyle,EmblemColor,BorderStyle,BorderColor,BackgroundColor,BankMoney) "
87 "VALUES('%u','%s','%u', '%s', '%s', NOW(),'%u','%u','%u','%u','%u','" I64FMTD
"')",
88 Id
, gname
.c_str(), GUID_LOPART(leaderGuid
), dbGINFO
.c_str(), dbMOTD
.c_str(), EmblemStyle
, EmblemColor
, BorderStyle
, BorderColor
, BackgroundColor
, guildbank_money
);
89 CharacterDatabase
.CommitTransaction();
91 rname
= "Guild Master";
92 CreateRank(rname
,GR_RIGHT_ALL
);
94 CreateRank(rname
,GR_RIGHT_ALL
);
96 CreateRank(rname
,GR_RIGHT_GCHATLISTEN
| GR_RIGHT_GCHATSPEAK
);
98 CreateRank(rname
,GR_RIGHT_GCHATLISTEN
| GR_RIGHT_GCHATSPEAK
);
100 CreateRank(rname
,GR_RIGHT_GCHATLISTEN
| GR_RIGHT_GCHATSPEAK
);
102 return AddMember(lGuid
, (uint32
)GR_GUILDMASTER
);
105 bool Guild::AddMember(uint64 plGuid
, uint32 plRank
)
107 Player
* pl
= objmgr
.GetPlayer(plGuid
);
110 if(pl
->GetGuildId() != 0)
115 if(Player::GetGuildIdFromDB(plGuid
) != 0) // player already in guild
119 // remove all player signs from another petitions
120 // this will be prevent attempt joining player to many guilds and corrupt guild data integrity
121 Player::RemovePetitionsAndSigns(plGuid
, 9);
124 MemberSlot newmember
;
126 if(!FillPlayerData(plGuid
, &newmember
)) // problems with player data collection
129 newmember
.RankId
= plRank
;
130 newmember
.OFFnote
= (std::string
)"";
131 newmember
.Pnote
= (std::string
)"";
132 newmember
.logout_time
= time(NULL
);
133 newmember
.BankResetTimeMoney
= 0; // this will force update at first query
134 for (int i
= 0; i
< GUILD_BANK_MAX_TABS
; ++i
)
135 newmember
.BankResetTimeTab
[i
] = 0;
136 members
[GUID_LOPART(plGuid
)] = newmember
;
138 std::string dbPnote
= newmember
.Pnote
;
139 std::string dbOFFnote
= newmember
.OFFnote
;
140 CharacterDatabase
.escape_string(dbPnote
);
141 CharacterDatabase
.escape_string(dbOFFnote
);
143 CharacterDatabase
.PExecute("INSERT INTO guild_member (guildid,guid,rank,pnote,offnote) VALUES ('%u', '%u', '%u','%s','%s')",
144 Id
, GUID_LOPART(plGuid
), newmember
.RankId
, dbPnote
.c_str(), dbOFFnote
.c_str());
146 // If player not in game data in data field will be loaded from guild tables, no need to update it!!
150 pl
->SetRank(newmember
.RankId
);
151 pl
->SetGuildIdInvited(0);
156 void Guild::SetMOTD(std::string motd
)
160 // motd now can be used for encoding to DB
161 CharacterDatabase
.escape_string(motd
);
162 CharacterDatabase
.PExecute("UPDATE guild SET motd='%s' WHERE guildid='%u'", motd
.c_str(), Id
);
165 void Guild::SetGINFO(std::string ginfo
)
169 // ginfo now can be used for encoding to DB
170 CharacterDatabase
.escape_string(ginfo
);
171 CharacterDatabase
.PExecute("UPDATE guild SET info='%s' WHERE guildid='%u'", ginfo
.c_str(), Id
);
174 bool Guild::LoadGuildFromDB(uint32 GuildId
)
176 if(!LoadRanksFromDB(GuildId
))
179 if(!LoadMembersFromDB(GuildId
))
182 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT MAX(TabId) FROM guild_bank_tab WHERE guildid='%u'", GuildId
);
185 Field
*fields
= result
->Fetch();
186 purchased_tabs
= fields
[0].GetUInt8()+1; // Because TabId begins at 0
192 LoadBankRightsFromDB(GuildId
); // Must be after LoadRanksFromDB because it populates rank struct
195 result
= CharacterDatabase
.PQuery("SELECT guildid, name, leaderguid, EmblemStyle, EmblemColor, BorderStyle, BorderColor,"
197 "BackgroundColor, info, motd, createdate, BankMoney FROM guild WHERE guildid = '%u'", GuildId
);
202 Field
*fields
= result
->Fetch();
204 Id
= fields
[0].GetUInt32();
205 name
= fields
[1].GetCppString();
206 leaderGuid
= MAKE_NEW_GUID(fields
[2].GetUInt32(), 0, HIGHGUID_PLAYER
);
208 EmblemStyle
= fields
[3].GetUInt32();
209 EmblemColor
= fields
[4].GetUInt32();
210 BorderStyle
= fields
[5].GetUInt32();
211 BorderColor
= fields
[6].GetUInt32();
212 BackgroundColor
= fields
[7].GetUInt32();
213 GINFO
= fields
[8].GetCppString();
214 MOTD
= fields
[9].GetCppString();
215 uint64 time
= fields
[10].GetUInt64(); //datetime is uint64 type ... YYYYmmdd:hh:mm:ss
216 guildbank_money
= fields
[11].GetUInt64();
220 uint64 dTime
= time
/1000000;
221 CreatedDay
= dTime
%100;
222 CreatedMonth
= (dTime
/100)%100;
223 CreatedYear
= (dTime
/10000)%10000;
225 // If the leader does not exist attempt to promote another member
226 if(!objmgr
.GetPlayerAccountIdByGUID(leaderGuid
))
228 DelMember(leaderGuid
);
230 // check no members case (disbanded)
235 sLog
.outDebug("Guild %u Creation time Loaded day: %u, month: %u, year: %u", GuildId
, CreatedDay
, CreatedMonth
, CreatedYear
);
236 m_bankloaded
= false;
237 m_eventlogloaded
= false;
240 RenumGuildEventlog();
244 bool Guild::LoadRanksFromDB(uint32 GuildId
)
247 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT rname,rights,BankMoneyPerDay,rid FROM guild_rank WHERE guildid = '%u' ORDER BY rid ASC", GuildId
);
252 bool broken_ranks
= false;
256 fields
= result
->Fetch();
258 std::string rankName
= fields
[0].GetCppString();
259 uint32 rankRights
= fields
[1].GetUInt32();
260 uint32 rankMoney
= fields
[2].GetUInt32();
261 uint32 rankRID
= fields
[3].GetUInt32();
263 if(rankRID
!= m_ranks
.size()+1) // guild_rank.rid always store rank+1
266 if(m_ranks
.size()==GR_GUILDMASTER
) // prevent loss leader rights
267 rankRights
|= GR_RIGHT_ALL
;
269 AddRank(rankName
,rankRights
,rankMoney
);
270 }while( result
->NextRow() );
273 if(m_ranks
.size()==0) // empty rank table?
275 AddRank("Guild Master",GR_RIGHT_ALL
,0);
279 // guild_rank have wrong numbered ranks, repair
282 sLog
.outError("Guild %u have broken `guild_rank` data, repairing...",GuildId
);
283 CharacterDatabase
.BeginTransaction();
284 CharacterDatabase
.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", GuildId
);
285 for(size_t i
=0; i
< m_ranks
.size(); ++i
)
287 // guild_rank.rid always store rank+1
288 std::string name
= m_ranks
[i
].name
;
289 uint32 rights
= m_ranks
[i
].rights
;
290 CharacterDatabase
.escape_string(name
);
291 CharacterDatabase
.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", GuildId
, i
+1, name
.c_str(), rights
);
293 CharacterDatabase
.CommitTransaction();
299 bool Guild::LoadMembersFromDB(uint32 GuildId
)
302 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT guild_member.guid,rank, pnote, offnote, BankResetTimeMoney,BankRemMoney,"
304 "BankResetTimeTab0, BankRemSlotsTab0, BankResetTimeTab1, BankRemSlotsTab1, BankResetTimeTab2, BankRemSlotsTab2,"
306 "BankResetTimeTab3, BankRemSlotsTab3, BankResetTimeTab4, BankRemSlotsTab4, BankResetTimeTab5, BankRemSlotsTab5,"
308 "logout_time FROM guild_member LEFT JOIN characters ON characters.guid = guild_member.guid WHERE guildid = '%u'", GuildId
);
315 Field
*fields
= result
->Fetch();
316 MemberSlot newmember
;
317 newmember
.RankId
= fields
[1].GetUInt32();
318 uint64 guid
= MAKE_NEW_GUID(fields
[0].GetUInt32(), 0, HIGHGUID_PLAYER
);
320 // Player does not exist
321 if(!FillPlayerData(guid
, &newmember
))
324 newmember
.Pnote
= fields
[2].GetCppString();
325 newmember
.OFFnote
= fields
[3].GetCppString();
326 newmember
.BankResetTimeMoney
= fields
[4].GetUInt32();
327 newmember
.BankRemMoney
= fields
[5].GetUInt32();
328 for (int i
= 0; i
< GUILD_BANK_MAX_TABS
; ++i
)
330 newmember
.BankResetTimeTab
[i
] = fields
[6+(2*i
)].GetUInt32();
331 newmember
.BankRemSlotsTab
[i
] = fields
[7+(2*i
)].GetUInt32();
333 newmember
.logout_time
= fields
[18].GetUInt64();
334 members
[GUID_LOPART(guid
)] = newmember
;
336 }while( result
->NextRow() );
345 bool Guild::FillPlayerData(uint64 guid
, MemberSlot
* memslot
)
352 Player
* pl
= objmgr
.GetPlayer(guid
);
355 plName
= pl
->GetName();
356 plLevel
= pl
->getLevel();
357 plClass
= pl
->getClass();
358 plZone
= pl
->GetZoneId();
362 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT name,data,zone,class FROM characters WHERE guid = '%u'", GUID_LOPART(guid
));
364 return false; // player doesn't exist
366 Field
*fields
= result
->Fetch();
368 plName
= fields
[0].GetCppString();
370 Tokens data
= StrSplit(fields
[1].GetCppString(), " ");
371 plLevel
= Player::GetUInt32ValueFromArray(data
,UNIT_FIELD_LEVEL
);
373 plZone
= fields
[2].GetUInt32();
374 plClass
= fields
[3].GetUInt32();
377 if(plLevel
<1||plLevel
>STRONG_MAX_LEVEL
) // can be at broken `data` field
379 sLog
.outError("Player (GUID: %u) has a broken data in field `characters`.`data`.",GUID_LOPART(guid
));
385 sLog
.outError("Player (GUID: %u) has broken zone-data",GUID_LOPART(guid
));
386 //here it will also try the same, to get the zone from characters-table, but additional it tries to find
387 plZone
= Player::GetZoneIdFromDB(guid
);
388 //the zone through xy coords.. this is a bit redundant, but
389 //shouldn't be called often
392 if(plClass
<CLASS_WARRIOR
||plClass
>=MAX_CLASSES
) // can be at broken `class` field
394 sLog
.outError("Player (GUID: %u) has a broken data in field `characters`.`class`.",GUID_LOPART(guid
));
399 memslot
->name
= plName
;
400 memslot
->level
= plLevel
;
401 memslot
->Class
= plClass
;
402 memslot
->zoneId
= plZone
;
407 void Guild::LoadPlayerStatsByGuid(uint64 guid
)
409 MemberList::iterator itr
= members
.find(GUID_LOPART(guid
));
410 if (itr
== members
.end() )
413 Player
*pl
= ObjectAccessor::FindPlayer(guid
);
416 itr
->second
.name
= pl
->GetName();
417 itr
->second
.level
= pl
->getLevel();
418 itr
->second
.Class
= pl
->getClass();
421 void Guild::SetLeader(uint64 guid
)
424 ChangeRank(guid
, GR_GUILDMASTER
);
426 CharacterDatabase
.PExecute("UPDATE guild SET leaderguid='%u' WHERE guildid='%u'", GUID_LOPART(guid
), Id
);
429 void Guild::DelMember(uint64 guid
, bool isDisbanding
)
431 if(leaderGuid
== guid
&& !isDisbanding
)
433 MemberSlot
* oldLeader
= NULL
;
434 MemberSlot
* best
= NULL
;
435 uint64 newLeaderGUID
= 0;
436 for(Guild::MemberList::iterator i
= members
.begin(); i
!= members
.end(); ++i
)
438 if(i
->first
== GUID_LOPART(guid
))
440 oldLeader
= &(i
->second
);
444 if(!best
|| best
->RankId
> i
->second
.RankId
)
447 newLeaderGUID
= i
->first
;
456 SetLeader(newLeaderGUID
);
458 // If player not online data in data field will be loaded from guild tabs no need to update it !!
459 if(Player
*newLeader
= objmgr
.GetPlayer(newLeaderGUID
))
460 newLeader
->SetRank(GR_GUILDMASTER
);
462 // when leader non-exist (at guild load with deleted leader only) not send broadcasts
465 WorldPacket
data(SMSG_GUILD_EVENT
, (1+1+(oldLeader
->name
).size()+1+(best
->name
).size()+1));
466 data
<< (uint8
)GE_LEADER_CHANGED
;
468 data
<< oldLeader
->name
;
470 BroadcastPacket(&data
);
472 data
.Initialize(SMSG_GUILD_EVENT
, (1+1+(oldLeader
->name
).size()+1));
473 data
<< (uint8
)GE_LEFT
;
475 data
<< oldLeader
->name
;
476 BroadcastPacket(&data
);
479 sLog
.outDebug( "WORLD: Sent (SMSG_GUILD_EVENT)" );
482 members
.erase(GUID_LOPART(guid
));
484 Player
*player
= objmgr
.GetPlayer(guid
);
485 // If player not online data in data field will be loaded from guild tabs no need to update it !!
488 player
->SetInGuild(0);
492 CharacterDatabase
.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid
));
495 void Guild::ChangeRank(uint64 guid
, uint32 newRank
)
497 MemberList::iterator itr
= members
.find(GUID_LOPART(guid
));
498 if( itr
!= members
.end() )
499 itr
->second
.RankId
= newRank
;
501 Player
*player
= objmgr
.GetPlayer(guid
);
502 // If player not online data in data field will be loaded from guild tabs no need to update it !!
504 player
->SetRank(newRank
);
506 CharacterDatabase
.PExecute( "UPDATE guild_member SET rank='%u' WHERE guid='%u'", newRank
, GUID_LOPART(guid
) );
509 void Guild::SetPNOTE(uint64 guid
,std::string pnote
)
511 MemberList::iterator itr
= members
.find(GUID_LOPART(guid
));
512 if( itr
== members
.end() )
515 itr
->second
.Pnote
= pnote
;
517 // pnote now can be used for encoding to DB
518 CharacterDatabase
.escape_string(pnote
);
519 CharacterDatabase
.PExecute("UPDATE guild_member SET pnote = '%s' WHERE guid = '%u'", pnote
.c_str(), itr
->first
);
522 void Guild::SetOFFNOTE(uint64 guid
,std::string offnote
)
524 MemberList::iterator itr
= members
.find(GUID_LOPART(guid
));
525 if( itr
== members
.end() )
527 itr
->second
.OFFnote
= offnote
;
528 // offnote now can be used for encoding to DB
529 CharacterDatabase
.escape_string(offnote
);
530 CharacterDatabase
.PExecute("UPDATE guild_member SET offnote = '%s' WHERE guid = '%u'", offnote
.c_str(), itr
->first
);
533 void Guild::BroadcastToGuild(WorldSession
*session
, const std::string
& msg
, uint32 language
)
535 if (session
&& session
->GetPlayer() && HasRankRight(session
->GetPlayer()->GetRank(),GR_RIGHT_GCHATSPEAK
))
538 ChatHandler(session
).FillMessageData(&data
, CHAT_MSG_GUILD
, language
, 0, msg
.c_str());
540 for (MemberList::const_iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
542 Player
*pl
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
544 if (pl
&& pl
->GetSession() && HasRankRight(pl
->GetRank(),GR_RIGHT_GCHATLISTEN
) && !pl
->GetSocial()->HasIgnore(session
->GetPlayer()->GetGUIDLow()) )
545 pl
->GetSession()->SendPacket(&data
);
550 void Guild::BroadcastToOfficers(WorldSession
*session
, const std::string
& msg
, uint32 language
)
552 if (session
&& session
->GetPlayer() && HasRankRight(session
->GetPlayer()->GetRank(),GR_RIGHT_OFFCHATSPEAK
))
554 for(MemberList::iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
557 ChatHandler::FillMessageData(&data
, session
, CHAT_MSG_OFFICER
, language
, NULL
, 0, msg
.c_str(),NULL
);
559 Player
*pl
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
561 if (pl
&& pl
->GetSession() && HasRankRight(pl
->GetRank(),GR_RIGHT_OFFCHATLISTEN
) && !pl
->GetSocial()->HasIgnore(session
->GetPlayer()->GetGUIDLow()))
562 pl
->GetSession()->SendPacket(&data
);
567 void Guild::BroadcastPacket(WorldPacket
*packet
)
569 for(MemberList::iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
571 Player
*player
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
573 player
->GetSession()->SendPacket(packet
);
577 void Guild::BroadcastPacketToRank(WorldPacket
*packet
, uint32 rankId
)
579 for(MemberList::iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
581 if (itr
->second
.RankId
== rankId
)
583 Player
*player
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
585 player
->GetSession()->SendPacket(packet
);
590 void Guild::CreateRank(std::string name_
,uint32 rights
)
592 if(m_ranks
.size() >= GUILD_MAX_RANKS
)
595 AddRank(name_
,rights
,0);
597 for (int i
= 0; i
< purchased_tabs
; ++i
)
599 CreateBankRightForTab(m_ranks
.size()-1, uint8(i
));
602 // guild_rank.rid always store rank+1 value
604 // name now can be used for encoding to DB
605 CharacterDatabase
.escape_string(name_
);
606 CharacterDatabase
.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", Id
, m_ranks
.size(), name_
.c_str(), rights
);
609 void Guild::AddRank(const std::string
& name_
,uint32 rights
, uint32 money
)
611 m_ranks
.push_back(RankInfo(name_
,rights
,money
));
614 void Guild::DelRank()
619 // guild_rank.rid always store rank+1 value
620 uint32 rank
= m_ranks
.size()-1;
621 CharacterDatabase
.PExecute("DELETE FROM guild_rank WHERE rid>='%u' AND guildid='%u'", (rank
+1), Id
);
626 std::string
Guild::GetRankName(uint32 rankId
)
628 if(rankId
>= m_ranks
.size())
631 return m_ranks
[rankId
].name
;
634 uint32
Guild::GetRankRights(uint32 rankId
)
636 if(rankId
>= m_ranks
.size())
639 return m_ranks
[rankId
].rights
;
642 void Guild::SetRankName(uint32 rankId
, std::string name_
)
644 if(rankId
>= m_ranks
.size())
647 m_ranks
[rankId
].name
= name_
;
649 // name now can be used for encoding to DB
650 CharacterDatabase
.escape_string(name_
);
651 CharacterDatabase
.PExecute("UPDATE guild_rank SET rname='%s' WHERE rid='%u' AND guildid='%u'", name_
.c_str(), (rankId
+1), Id
);
654 void Guild::SetRankRights(uint32 rankId
, uint32 rights
)
656 if(rankId
>= m_ranks
.size())
659 m_ranks
[rankId
].rights
= rights
;
661 CharacterDatabase
.PExecute("UPDATE guild_rank SET rights='%u' WHERE rid='%u' AND guildid='%u'", rights
, (rankId
+1), Id
);
664 int32
Guild::GetRank(uint32 LowGuid
)
666 MemberList::iterator itr
= members
.find(LowGuid
);
667 if (itr
==members
.end())
670 return itr
->second
.RankId
;
673 void Guild::Disband()
675 WorldPacket
data(SMSG_GUILD_EVENT
, 1);
676 data
<< (uint8
)GE_DISBANDED
;
677 BroadcastPacket(&data
);
679 while (!members
.empty())
681 MemberList::iterator itr
= members
.begin();
682 DelMember(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
), true);
685 CharacterDatabase
.BeginTransaction();
686 CharacterDatabase
.PExecute("DELETE FROM guild WHERE guildid = '%u'",Id
);
687 CharacterDatabase
.PExecute("DELETE FROM guild_rank WHERE guildid = '%u'",Id
);
688 CharacterDatabase
.PExecute("DELETE FROM guild_bank_tab WHERE guildid = '%u'",Id
);
689 CharacterDatabase
.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u'",Id
);
690 CharacterDatabase
.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u'",Id
);
691 CharacterDatabase
.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid = '%u'",Id
);
692 CharacterDatabase
.PExecute("DELETE FROM guild_eventlog WHERE guildid = '%u'",Id
);
693 CharacterDatabase
.CommitTransaction();
694 objmgr
.RemoveGuild(this);
697 void Guild::Roster(WorldSession
*session
)
699 // we can only guess size
700 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));
701 data
<< (uint32
)members
.size();
705 data
<< (uint32
)m_ranks
.size();
706 for (RankList::iterator ritr
= m_ranks
.begin(); ritr
!= m_ranks
.end();++ritr
)
708 data
<< (uint32
)ritr
->rights
;
709 data
<< (uint32
)ritr
->BankMoneyPerDay
; // count of: withdraw gold(gold/day) Note: in game set gold, in packet set bronze.
710 for (int i
= 0; i
< GUILD_BANK_MAX_TABS
; ++i
)
712 data
<< (uint32
)ritr
->TabRight
[i
]; // for TAB_i rights: view tabs = 0x01, deposit items =0x02
713 data
<< (uint32
)ritr
->TabSlotPerDay
[i
]; // for TAB_i count of: withdraw items(stack/day)
716 for (MemberList::iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
718 if (Player
*pl
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
)))
720 data
<< (uint64
)pl
->GetGUID();
722 data
<< (std::string
)pl
->GetName();
723 data
<< (uint32
)itr
->second
.RankId
;
724 data
<< (uint8
)pl
->getLevel();
725 data
<< (uint8
)pl
->getClass();
726 data
<< (uint8
)0; // new 2.4.0
727 data
<< (uint32
)pl
->GetZoneId();
728 data
<< itr
->second
.Pnote
;
729 data
<< itr
->second
.OFFnote
;
733 data
<< uint64(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
735 data
<< itr
->second
.name
;
736 data
<< (uint32
)itr
->second
.RankId
;
737 data
<< (uint8
)itr
->second
.level
;
738 data
<< (uint8
)itr
->second
.Class
;
739 data
<< (uint8
)0; // new 2.4.0
740 data
<< (uint32
)itr
->second
.zoneId
;
741 data
<< (float(time(NULL
)-itr
->second
.logout_time
) / DAY
);
742 data
<< itr
->second
.Pnote
;
743 data
<< itr
->second
.OFFnote
;
746 session
->SendPacket(&data
);;
747 sLog
.outDebug( "WORLD: Sent (SMSG_GUILD_ROSTER)" );
750 void Guild::Query(WorldSession
*session
)
752 WorldPacket
data(SMSG_GUILD_QUERY_RESPONSE
, (8*32+200));// we can only guess size
756 RankList::iterator itr
;
757 for (size_t i
= 0 ; i
< 10; ++i
) // show always 10 ranks
759 if(i
< m_ranks
.size())
760 data
<< m_ranks
[i
].name
;
762 data
<< (uint8
)0; // null string
765 data
<< uint32(EmblemStyle
);
766 data
<< uint32(EmblemColor
);
767 data
<< uint32(BorderStyle
);
768 data
<< uint32(BorderColor
);
769 data
<< uint32(BackgroundColor
);
770 data
<< uint32(0); // something new in WotLK
772 session
->SendPacket( &data
);
773 sLog
.outDebug( "WORLD: Sent (SMSG_GUILD_QUERY_RESPONSE)" );
776 void Guild::SetEmblem(uint32 emblemStyle
, uint32 emblemColor
, uint32 borderStyle
, uint32 borderColor
, uint32 backgroundColor
)
778 EmblemStyle
= emblemStyle
;
779 EmblemColor
= emblemColor
;
780 BorderStyle
= borderStyle
;
781 BorderColor
= borderColor
;
782 BackgroundColor
= backgroundColor
;
784 CharacterDatabase
.PExecute("UPDATE guild SET EmblemStyle=%u, EmblemColor=%u, BorderStyle=%u, BorderColor=%u, BackgroundColor=%u WHERE guildid = %u", EmblemStyle
, EmblemColor
, BorderStyle
, BorderColor
, BackgroundColor
, Id
);
787 void Guild::UpdateLogoutTime(uint64 guid
)
789 MemberList::iterator itr
= members
.find(GUID_LOPART(guid
));
790 if (itr
== members
.end() )
793 itr
->second
.logout_time
= time(NULL
);
795 if (m_onlinemembers
> 0)
800 UnloadGuildEventlog();
804 // *************************************************
805 // Guild Eventlog part
806 // *************************************************
807 // Display guild eventlog
808 void Guild::DisplayGuildEventlog(WorldSession
*session
)
810 // Load guild eventlog, if not already done
811 if (!m_eventlogloaded
)
812 LoadGuildEventLogFromDB();
815 WorldPacket
data(MSG_GUILD_EVENT_LOG_QUERY
, 0);
816 // count, max count == 100
817 data
<< uint8(m_GuildEventlog
.size());
818 for (GuildEventlog::const_iterator itr
= m_GuildEventlog
.begin(); itr
!= m_GuildEventlog
.end(); ++itr
)
821 data
<< uint8((*itr
)->EventType
);
823 data
<< uint64((*itr
)->PlayerGuid1
);
824 // Player 2 not for left/join guild events
825 if( (*itr
)->EventType
!= GUILD_EVENT_LOG_JOIN_GUILD
&& (*itr
)->EventType
!= GUILD_EVENT_LOG_LEAVE_GUILD
)
826 data
<< uint64((*itr
)->PlayerGuid2
);
827 // New Rank - only for promote/demote guild events
828 if( (*itr
)->EventType
== GUILD_EVENT_LOG_PROMOTE_PLAYER
|| (*itr
)->EventType
== GUILD_EVENT_LOG_DEMOTE_PLAYER
)
829 data
<< uint8((*itr
)->NewRank
);
831 data
<< uint32(time(NULL
)-(*itr
)->TimeStamp
);
833 session
->SendPacket(&data
);
834 sLog
.outDebug("WORLD: Sent (MSG_GUILD_EVENT_LOG_QUERY)");
837 // Load guild eventlog from DB
838 void Guild::LoadGuildEventLogFromDB()
840 // Return if already loaded
841 if (m_eventlogloaded
)
844 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
);
849 Field
*fields
= result
->Fetch();
850 GuildEventlogEntry
*NewEvent
= new GuildEventlogEntry
;
852 NewEvent
->LogGuid
= fields
[0].GetUInt32();
853 NewEvent
->EventType
= fields
[1].GetUInt8();
854 NewEvent
->PlayerGuid1
= fields
[2].GetUInt32();
855 NewEvent
->PlayerGuid2
= fields
[3].GetUInt32();
856 NewEvent
->NewRank
= fields
[4].GetUInt8();
857 NewEvent
->TimeStamp
= fields
[5].GetUInt64();
859 m_GuildEventlog
.push_front(NewEvent
);
861 } while( result
->NextRow() );
864 // Check lists size in case to many event entries in db
865 // This cases can happen only if a crash occured somewhere and table has too many log entries
866 if (!m_GuildEventlog
.empty())
868 CharacterDatabase
.PExecute("DELETE FROM guild_eventlog WHERE guildid=%u AND LogGuid < %u", Id
, m_GuildEventlog
.front()->LogGuid
);
870 m_eventlogloaded
= true;
873 // Unload guild eventlog
874 void Guild::UnloadGuildEventlog()
876 if (!m_eventlogloaded
)
878 GuildEventlogEntry
*EventLogEntry
;
879 if( !m_GuildEventlog
.empty() )
883 EventLogEntry
= *(m_GuildEventlog
.begin());
884 m_GuildEventlog
.pop_front();
885 delete EventLogEntry
;
886 }while( !m_GuildEventlog
.empty() );
888 m_eventlogloaded
= false;
891 // This will renum guids used at load to prevent always going up until infinit
892 void Guild::RenumGuildEventlog()
894 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT Min(LogGuid), Max(LogGuid) FROM guild_eventlog WHERE guildid = %u", Id
);
898 Field
*fields
= result
->Fetch();
899 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");
900 GuildEventlogMaxGuid
= fields
[1].GetUInt32()+1;
904 // Add entry to guild eventlog
905 void Guild::LogGuildEvent(uint8 EventType
, uint32 PlayerGuid1
, uint32 PlayerGuid2
, uint8 NewRank
)
907 GuildEventlogEntry
*NewEvent
= new GuildEventlogEntry
;
909 NewEvent
->LogGuid
= GuildEventlogMaxGuid
++;
910 NewEvent
->EventType
= EventType
;
911 NewEvent
->PlayerGuid1
= PlayerGuid1
;
912 NewEvent
->PlayerGuid2
= PlayerGuid2
;
913 NewEvent
->NewRank
= NewRank
;
914 NewEvent
->TimeStamp
= uint32(time(NULL
));
915 // Check max entry limit and delete from db if needed
916 if (m_GuildEventlog
.size() > GUILD_EVENTLOG_MAX_ENTRIES
)
918 GuildEventlogEntry
*OldEvent
= *(m_GuildEventlog
.begin());
919 m_GuildEventlog
.pop_front();
920 CharacterDatabase
.PExecute("DELETE FROM guild_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id
, OldEvent
->LogGuid
);
924 m_GuildEventlog
.push_back(NewEvent
);
925 // Add new eventlog entry into DB
926 CharacterDatabase
.PExecute("INSERT INTO guild_eventlog (guildid, LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','" I64FMTD
"')",
927 Id
, NewEvent
->LogGuid
, uint32(NewEvent
->EventType
), NewEvent
->PlayerGuid1
, NewEvent
->PlayerGuid2
, uint32(NewEvent
->NewRank
), NewEvent
->TimeStamp
);
930 // *************************************************
932 // *************************************************
933 // Bank content related
934 void Guild::DisplayGuildBankContent(WorldSession
*session
, uint8 TabId
)
936 WorldPacket
data(SMSG_GUILD_BANK_LIST
,1200);
938 GuildBankTab
const* tab
= GetBankTab(TabId
);
942 if(!IsMemberHaveRights(session
->GetPlayer()->GetGUIDLow(),TabId
,GUILD_BANK_RIGHT_VIEW_TAB
))
945 data
<< uint64(GetGuildBankMoney());
946 data
<< uint8(TabId
);
947 // remaining slots for today
948 data
<< uint32(GetMemberSlotWithdrawRem(session
->GetPlayer()->GetGUIDLow(), TabId
));
949 data
<< uint8(0); // Tell client this is a tab content packet
951 data
<< uint8(GUILD_BANK_MAX_SLOTS
);
953 for (int i
=0; i
<GUILD_BANK_MAX_SLOTS
; ++i
)
954 AppendDisplayGuildBankSlot(data
, tab
, i
);
956 session
->SendPacket(&data
);
958 sLog
.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
961 void Guild::DisplayGuildBankMoneyUpdate()
963 WorldPacket
data(SMSG_GUILD_BANK_LIST
, 8+1+4+1+1);
965 data
<< uint64(GetGuildBankMoney());
966 data
<< uint8(0); // TabId, default 0
967 data
<< uint32(0); // slot withdrow, default 0
968 data
<< uint8(0); // Tell client this is a tab content packet
969 data
<< uint8(0); // not send items
970 BroadcastPacket(&data
);
972 sLog
.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
975 void Guild::DisplayGuildBankContentUpdate(uint8 TabId
, int32 slot1
, int32 slot2
)
977 GuildBankTab
const* tab
= GetBankTab(TabId
);
981 WorldPacket
data(SMSG_GUILD_BANK_LIST
,1200);
983 data
<< uint64(GetGuildBankMoney());
984 data
<< uint8(TabId
);
985 // remaining slots for today
987 size_t rempos
= data
.wpos();
988 data
<< uint32(0); // will be filled later
989 data
<< uint8(0); // Tell client this is a tab content packet
991 if(slot2
==-1) // single item in slot1
995 AppendDisplayGuildBankSlot(data
, tab
, slot1
);
997 else // 2 items (in slot1 and slot2)
1002 std::swap(slot1
,slot2
);
1004 AppendDisplayGuildBankSlot(data
, tab
, slot1
);
1005 AppendDisplayGuildBankSlot(data
, tab
, slot2
);
1008 for(MemberList::iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
1010 Player
*player
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
1014 if(!IsMemberHaveRights(itr
->first
,TabId
,GUILD_BANK_RIGHT_VIEW_TAB
))
1017 data
.put
<uint32
>(rempos
,uint32(GetMemberSlotWithdrawRem(player
->GetGUIDLow(), TabId
)));
1019 player
->GetSession()->SendPacket(&data
);
1022 sLog
.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1025 void Guild::DisplayGuildBankContentUpdate(uint8 TabId
, GuildItemPosCountVec
const& slots
)
1027 GuildBankTab
const* tab
= GetBankTab(TabId
);
1031 WorldPacket
data(SMSG_GUILD_BANK_LIST
,1200);
1033 data
<< uint64(GetGuildBankMoney());
1034 data
<< uint8(TabId
);
1035 // remaining slots for today
1037 size_t rempos
= data
.wpos();
1038 data
<< uint32(0); // will be filled later
1039 data
<< uint8(0); // Tell client this is a tab content packet
1041 data
<< uint8(slots
.size()); // updates count
1043 for(GuildItemPosCountVec::const_iterator itr
= slots
.begin(); itr
!= slots
.end(); ++itr
)
1044 AppendDisplayGuildBankSlot(data
, tab
, itr
->slot
);
1046 for(MemberList::iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
1048 Player
*player
= ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr
->first
, 0, HIGHGUID_PLAYER
));
1052 if(!IsMemberHaveRights(itr
->first
,TabId
,GUILD_BANK_RIGHT_VIEW_TAB
))
1055 data
.put
<uint32
>(rempos
,uint32(GetMemberSlotWithdrawRem(player
->GetGUIDLow(), TabId
)));
1057 player
->GetSession()->SendPacket(&data
);
1060 sLog
.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1063 Item
* Guild::GetItem(uint8 TabId
, uint8 SlotId
)
1065 if (TabId
>= m_TabListMap
.size() || SlotId
>= GUILD_BANK_MAX_SLOTS
)
1067 return m_TabListMap
[TabId
]->Slots
[SlotId
];
1070 // *************************************************
1073 void Guild::DisplayGuildBankTabsInfo(WorldSession
*session
)
1075 // Time to load bank if not already done
1077 LoadGuildBankFromDB();
1079 WorldPacket
data(SMSG_GUILD_BANK_LIST
, 500);
1081 data
<< uint64(GetGuildBankMoney());
1082 data
<< uint8(0); // TabInfo packet must be for TabId 0
1083 data
<< uint32(0xFFFFFFFF); // bit 9 must be set for this packet to work
1084 data
<< uint8(1); // Tell Client this is a TabInfo packet
1086 data
<< uint8(purchased_tabs
); // here is the number of tabs
1088 for(int i
= 0; i
< purchased_tabs
; ++i
)
1090 data
<< m_TabListMap
[i
]->Name
.c_str();
1091 data
<< m_TabListMap
[i
]->Icon
.c_str();
1093 data
<< uint8(0); // Do not send tab content
1094 session
->SendPacket(&data
);
1096 sLog
.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1099 void Guild::CreateNewBankTab()
1101 if (purchased_tabs
>= GUILD_BANK_MAX_TABS
)
1106 GuildBankTab
* AnotherTab
= new GuildBankTab
;
1107 memset(AnotherTab
->Slots
, 0, GUILD_BANK_MAX_SLOTS
* sizeof(Item
*));
1108 m_TabListMap
.resize(purchased_tabs
);
1109 m_TabListMap
[purchased_tabs
-1] = AnotherTab
;
1111 CharacterDatabase
.BeginTransaction();
1112 CharacterDatabase
.PExecute("DELETE FROM guild_bank_tab WHERE guildid='%u' AND TabId='%u'", Id
, uint32(purchased_tabs
-1));
1113 CharacterDatabase
.PExecute("INSERT INTO guild_bank_tab (guildid,TabId) VALUES ('%u','%u')", Id
, uint32(purchased_tabs
-1));
1114 CharacterDatabase
.CommitTransaction();
1117 void Guild::SetGuildBankTabInfo(uint8 TabId
, std::string Name
, std::string Icon
)
1119 if (TabId
>= GUILD_BANK_MAX_TABS
)
1121 if (TabId
>= m_TabListMap
.size())
1124 if (!m_TabListMap
[TabId
])
1127 if(m_TabListMap
[TabId
]->Name
== Name
&& m_TabListMap
[TabId
]->Icon
== Icon
)
1130 m_TabListMap
[TabId
]->Name
= Name
;
1131 m_TabListMap
[TabId
]->Icon
= Icon
;
1133 CharacterDatabase
.escape_string(Name
);
1134 CharacterDatabase
.escape_string(Icon
);
1135 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
));
1138 void Guild::CreateBankRightForTab(uint32 rankId
, uint8 TabId
)
1140 sLog
.outDebug("CreateBankRightForTab. rank: %u, TabId: %u", rankId
, uint32(TabId
));
1141 if (rankId
>= m_ranks
.size() || TabId
>= GUILD_BANK_MAX_TABS
)
1144 m_ranks
[rankId
].TabRight
[TabId
]=0;
1145 m_ranks
[rankId
].TabSlotPerDay
[TabId
]=0;
1146 CharacterDatabase
.BeginTransaction();
1147 CharacterDatabase
.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u' AND TabId = '%u' AND rid = '%u'", Id
, uint32(TabId
), rankId
);
1148 CharacterDatabase
.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid) VALUES ('%u','%u','%u')", Id
, uint32(TabId
), rankId
);
1149 CharacterDatabase
.CommitTransaction();
1152 uint32
Guild::GetBankRights(uint32 rankId
, uint8 TabId
) const
1154 if(rankId
>= m_ranks
.size() || TabId
>= GUILD_BANK_MAX_TABS
)
1157 return m_ranks
[rankId
].TabRight
[TabId
];
1160 // *************************************************
1161 // Guild bank loading/unloading related
1163 // This load should be called when the bank is first accessed by a guild member
1164 void Guild::LoadGuildBankFromDB()
1169 m_bankloaded
= true;
1170 LoadGuildBankEventLogFromDB();
1173 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT TabId, TabName, TabIcon, TabText FROM guild_bank_tab WHERE guildid='%u' ORDER BY TabId", Id
);
1180 m_TabListMap
.resize(purchased_tabs
);
1183 Field
*fields
= result
->Fetch();
1184 uint8 TabId
= fields
[0].GetUInt8();
1186 GuildBankTab
*NewTab
= new GuildBankTab
;
1187 memset(NewTab
->Slots
, 0, GUILD_BANK_MAX_SLOTS
* sizeof(Item
*));
1189 NewTab
->Name
= fields
[1].GetCppString();
1190 NewTab
->Icon
= fields
[2].GetCppString();
1191 NewTab
->Text
= fields
[3].GetCppString();
1193 m_TabListMap
[TabId
] = NewTab
;
1194 }while( result
->NextRow() );
1199 result
= CharacterDatabase
.PQuery("SELECT TabId, SlotId, item_guid, item_entry FROM guild_bank_item WHERE guildid='%u' ORDER BY TabId", Id
);
1205 Field
*fields
= result
->Fetch();
1206 uint8 TabId
= fields
[0].GetUInt8();
1207 uint8 SlotId
= fields
[1].GetUInt8();
1208 uint32 ItemGuid
= fields
[2].GetUInt32();
1209 uint32 ItemEntry
= fields
[3].GetUInt32();
1211 if (TabId
>= purchased_tabs
|| TabId
>= GUILD_BANK_MAX_TABS
)
1213 sLog
.outError( "Guild::LoadGuildBankFromDB: Invalid tab for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid
,ItemEntry
);
1217 if (SlotId
>= GUILD_BANK_MAX_SLOTS
)
1219 sLog
.outError( "Guild::LoadGuildBankFromDB: Invalid slot for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid
,ItemEntry
);
1223 ItemPrototype
const *proto
= objmgr
.GetItemPrototype(ItemEntry
);
1227 sLog
.outError( "Guild::LoadGuildBankFromDB: Unknown item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid
,ItemEntry
);
1231 Item
*pItem
= NewItemOrBag(proto
);
1232 if(!pItem
->LoadFromDB(ItemGuid
, 0))
1234 CharacterDatabase
.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'", Id
, uint32(TabId
), uint32(SlotId
));
1235 sLog
.outError("Item GUID %u not found in item_instance, deleting from Guild Bank!", ItemGuid
);
1240 pItem
->AddToWorld();
1241 m_TabListMap
[TabId
]->Slots
[SlotId
] = pItem
;
1242 }while( result
->NextRow() );
1247 // This unload should be called when the last member of the guild gets offline
1248 void Guild::UnloadGuildBank()
1252 for (uint8 i
= 0 ; i
< purchased_tabs
; ++i
)
1254 for (uint8 j
= 0 ; j
< GUILD_BANK_MAX_SLOTS
; ++j
)
1256 if (m_TabListMap
[i
]->Slots
[j
])
1258 m_TabListMap
[i
]->Slots
[j
]->RemoveFromWorld();
1259 delete m_TabListMap
[i
]->Slots
[j
];
1262 delete m_TabListMap
[i
];
1264 m_TabListMap
.clear();
1266 UnloadGuildBankEventLog();
1267 m_bankloaded
= false;
1270 // *************************************************
1271 // Money deposit/withdraw related
1273 void Guild::SendMoneyInfo(WorldSession
*session
, uint32 LowGuid
)
1275 WorldPacket
data(MSG_GUILD_BANK_MONEY_WITHDRAWN
, 4);
1276 data
<< uint32(GetMemberMoneyWithdrawRem(LowGuid
));
1277 session
->SendPacket(&data
);
1278 sLog
.outDebug("WORLD: Sent MSG_GUILD_BANK_MONEY_WITHDRAWN");
1281 bool Guild::MemberMoneyWithdraw(uint32 amount
, uint32 LowGuid
)
1283 uint32 MoneyWithDrawRight
= GetMemberMoneyWithdrawRem(LowGuid
);
1285 if (MoneyWithDrawRight
< amount
|| GetGuildBankMoney() < amount
)
1288 SetBankMoney(GetGuildBankMoney()-amount
);
1290 if (MoneyWithDrawRight
< WITHDRAW_MONEY_UNLIMITED
)
1292 MemberList::iterator itr
= members
.find(LowGuid
);
1293 if (itr
== members
.end() )
1295 itr
->second
.BankRemMoney
-= amount
;
1296 CharacterDatabase
.PExecute("UPDATE guild_member SET BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'",
1297 itr
->second
.BankRemMoney
, Id
, LowGuid
);
1302 void Guild::SetBankMoney(int64 money
)
1304 if (money
< 0) // I don't know how this happens, it does!!
1306 guildbank_money
= money
;
1308 CharacterDatabase
.PExecute("UPDATE guild SET BankMoney='" I64FMTD
"' WHERE guildid='%u'", money
, Id
);
1311 // *************************************************
1312 // Item per day and money per day related
1314 bool Guild::MemberItemWithdraw(uint8 TabId
, uint32 LowGuid
)
1316 uint32 SlotsWithDrawRight
= GetMemberSlotWithdrawRem(LowGuid
, TabId
);
1318 if (SlotsWithDrawRight
== 0)
1321 if (SlotsWithDrawRight
< WITHDRAW_SLOT_UNLIMITED
)
1323 MemberList::iterator itr
= members
.find(LowGuid
);
1324 if (itr
== members
.end() )
1326 --itr
->second
.BankRemSlotsTab
[TabId
];
1327 CharacterDatabase
.PExecute("UPDATE guild_member SET BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'",
1328 uint32(TabId
), itr
->second
.BankRemSlotsTab
[TabId
], Id
, LowGuid
);
1333 bool Guild::IsMemberHaveRights(uint32 LowGuid
, uint8 TabId
, uint32 rights
) const
1335 MemberList::const_iterator itr
= members
.find(LowGuid
);
1336 if (itr
== members
.end() )
1339 if (itr
->second
.RankId
== GR_GUILDMASTER
)
1342 return (GetBankRights(itr
->second
.RankId
,TabId
) & rights
)==rights
;
1345 uint32
Guild::GetMemberSlotWithdrawRem(uint32 LowGuid
, uint8 TabId
)
1347 MemberList::iterator itr
= members
.find(LowGuid
);
1348 if (itr
== members
.end() )
1351 if (itr
->second
.RankId
== GR_GUILDMASTER
)
1352 return WITHDRAW_SLOT_UNLIMITED
;
1354 if((GetBankRights(itr
->second
.RankId
,TabId
) & GUILD_BANK_RIGHT_VIEW_TAB
)!=GUILD_BANK_RIGHT_VIEW_TAB
)
1357 uint32 curTime
= uint32(time(NULL
)/MINUTE
);
1358 if (curTime
- itr
->second
.BankResetTimeTab
[TabId
] >= 24*HOUR
/MINUTE
)
1360 itr
->second
.BankResetTimeTab
[TabId
] = curTime
;
1361 itr
->second
.BankRemSlotsTab
[TabId
] = GetBankSlotPerDay(itr
->second
.RankId
, TabId
);
1362 CharacterDatabase
.PExecute("UPDATE guild_member SET BankResetTimeTab%u='%u',BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'",
1363 uint32(TabId
), itr
->second
.BankResetTimeTab
[TabId
], uint32(TabId
), itr
->second
.BankRemSlotsTab
[TabId
], Id
, LowGuid
);
1365 return itr
->second
.BankRemSlotsTab
[TabId
];
1368 uint32
Guild::GetMemberMoneyWithdrawRem(uint32 LowGuid
)
1370 MemberList::iterator itr
= members
.find(LowGuid
);
1371 if (itr
== members
.end() )
1374 if (itr
->second
.RankId
== GR_GUILDMASTER
)
1375 return WITHDRAW_MONEY_UNLIMITED
;
1377 uint32 curTime
= uint32(time(NULL
)/MINUTE
); // minutes
1379 if (curTime
> itr
->second
.BankResetTimeMoney
+ 24*HOUR
/MINUTE
)
1381 itr
->second
.BankResetTimeMoney
= curTime
;
1382 itr
->second
.BankRemMoney
= GetBankMoneyPerDay(itr
->second
.RankId
);
1383 CharacterDatabase
.PExecute("UPDATE guild_member SET BankResetTimeMoney='%u',BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'",
1384 itr
->second
.BankResetTimeMoney
, itr
->second
.BankRemMoney
, Id
, LowGuid
);
1386 return itr
->second
.BankRemMoney
;
1389 void Guild::SetBankMoneyPerDay(uint32 rankId
, uint32 money
)
1391 if (rankId
>= m_ranks
.size())
1394 if (rankId
== GR_GUILDMASTER
)
1395 money
= WITHDRAW_MONEY_UNLIMITED
;
1397 m_ranks
[rankId
].BankMoneyPerDay
= money
;
1399 for (MemberList::iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
1400 if (itr
->second
.RankId
== rankId
)
1401 itr
->second
.BankResetTimeMoney
= 0;
1403 CharacterDatabase
.PExecute("UPDATE guild_rank SET BankMoneyPerDay='%u' WHERE rid='%u' AND guildid='%u'", money
, (rankId
+1), Id
);
1404 CharacterDatabase
.PExecute("UPDATE guild_member SET BankResetTimeMoney='0' WHERE guildid='%u' AND rank='%u'", Id
, rankId
);
1407 void Guild::SetBankRightsAndSlots(uint32 rankId
, uint8 TabId
, uint32 right
, uint32 nbSlots
, bool db
)
1409 if(rankId
>= m_ranks
.size() ||
1410 TabId
>= GUILD_BANK_MAX_TABS
||
1411 TabId
>= purchased_tabs
)
1414 if (rankId
== GR_GUILDMASTER
)
1416 nbSlots
= WITHDRAW_SLOT_UNLIMITED
;
1417 right
= GUILD_BANK_RIGHT_FULL
;
1420 m_ranks
[rankId
].TabSlotPerDay
[TabId
]=nbSlots
;
1421 m_ranks
[rankId
].TabRight
[TabId
]=right
;
1425 for (MemberList::iterator itr
= members
.begin(); itr
!= members
.end(); ++itr
)
1426 if (itr
->second
.RankId
== rankId
)
1427 for (int i
= 0; i
< GUILD_BANK_MAX_TABS
; ++i
)
1428 itr
->second
.BankResetTimeTab
[i
] = 0;
1430 CharacterDatabase
.PExecute("DELETE FROM guild_bank_right WHERE guildid='%u' AND TabId='%u' AND rid='%u'", Id
, uint32(TabId
), rankId
);
1431 CharacterDatabase
.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid,gbright,SlotPerDay) VALUES "
1432 "('%u','%u','%u','%u','%u')", Id
, uint32(TabId
), rankId
, m_ranks
[rankId
].TabRight
[TabId
], m_ranks
[rankId
].TabSlotPerDay
[TabId
]);
1433 CharacterDatabase
.PExecute("UPDATE guild_member SET BankResetTimeTab%u='0' WHERE guildid='%u' AND rank='%u'", uint32(TabId
), Id
, rankId
);
1437 uint32
Guild::GetBankMoneyPerDay(uint32 rankId
)
1439 if(rankId
>= m_ranks
.size())
1442 if (rankId
== GR_GUILDMASTER
)
1443 return WITHDRAW_MONEY_UNLIMITED
;
1444 return m_ranks
[rankId
].BankMoneyPerDay
;
1447 uint32
Guild::GetBankSlotPerDay(uint32 rankId
, uint8 TabId
)
1449 if(rankId
>= m_ranks
.size() || TabId
>= GUILD_BANK_MAX_TABS
)
1452 if (rankId
== GR_GUILDMASTER
)
1453 return WITHDRAW_SLOT_UNLIMITED
;
1454 return m_ranks
[rankId
].TabSlotPerDay
[TabId
];
1457 // *************************************************
1458 // Rights per day related
1460 void Guild::LoadBankRightsFromDB(uint32 GuildId
)
1463 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT TabId, rid, gbright, SlotPerDay FROM guild_bank_right WHERE guildid = '%u' ORDER BY TabId", GuildId
);
1470 Field
*fields
= result
->Fetch();
1471 uint8 TabId
= fields
[0].GetUInt8();
1472 uint32 rankId
= fields
[1].GetUInt32();
1473 uint16 right
= fields
[2].GetUInt16();
1474 uint16 SlotPerDay
= fields
[3].GetUInt16();
1476 SetBankRightsAndSlots(rankId
, TabId
, right
, SlotPerDay
, false);
1478 }while( result
->NextRow() );
1484 // *************************************************
1487 void Guild::LoadGuildBankEventLogFromDB()
1489 // We can't add a limit as in Guild::LoadGuildEventLogFromDB since we fetch both money and bank log and know nothing about the composition
1491 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
);
1497 Field
*fields
= result
->Fetch();
1498 GuildBankEvent
*NewEvent
= new GuildBankEvent
;
1500 NewEvent
->LogGuid
= fields
[0].GetUInt32();
1501 NewEvent
->LogEntry
= fields
[1].GetUInt8();
1502 uint8 TabId
= fields
[2].GetUInt8();
1503 NewEvent
->PlayerGuid
= fields
[3].GetUInt32();
1504 NewEvent
->ItemOrMoney
= fields
[4].GetUInt32();
1505 NewEvent
->ItemStackCount
= fields
[5].GetUInt8();
1506 NewEvent
->DestTabId
= fields
[6].GetUInt8();
1507 NewEvent
->TimeStamp
= fields
[7].GetUInt64();
1509 if (TabId
>= GUILD_BANK_MAX_TABS
)
1511 sLog
.outError( "Guild::LoadGuildBankEventLogFromDB: Invalid tabid '%u' for guild bank log entry (guild: '%s', LogGuid: %u), skipped.", TabId
, GetName().c_str(), NewEvent
->LogGuid
);
1515 if (NewEvent
->isMoneyEvent() && m_GuildBankEventLog_Money
.size() >= GUILD_BANK_MAX_LOGS
1516 || m_GuildBankEventLog_Item
[TabId
].size() >= GUILD_BANK_MAX_LOGS
)
1521 if (NewEvent
->isMoneyEvent())
1522 m_GuildBankEventLog_Money
.push_front(NewEvent
);
1524 m_GuildBankEventLog_Item
[TabId
].push_front(NewEvent
);
1526 }while( result
->NextRow() );
1529 // Check lists size in case to many event entries in db for a tab or for money
1530 // This cases can happen only if a crash occured somewhere and table has too many log entries
1531 if (!m_GuildBankEventLog_Money
.empty())
1533 CharacterDatabase
.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid=%u AND LogGuid < %u",
1534 Id
, m_GuildBankEventLog_Money
.front()->LogGuid
);
1536 for (int i
= 0; i
< GUILD_BANK_MAX_TABS
; ++i
)
1538 if (!m_GuildBankEventLog_Item
[i
].empty())
1540 CharacterDatabase
.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid=%u AND LogGuid < %u",
1541 Id
, m_GuildBankEventLog_Item
[i
].front()->LogGuid
);
1546 void Guild::UnloadGuildBankEventLog()
1548 GuildBankEvent
*EventLogEntry
;
1549 if( !m_GuildBankEventLog_Money
.empty() )
1553 EventLogEntry
= *(m_GuildBankEventLog_Money
.begin());
1554 m_GuildBankEventLog_Money
.pop_front();
1555 delete EventLogEntry
;
1556 }while( !m_GuildBankEventLog_Money
.empty() );
1559 for (int i
= 0; i
< GUILD_BANK_MAX_TABS
; ++i
)
1561 if( !m_GuildBankEventLog_Item
[i
].empty() )
1565 EventLogEntry
= *(m_GuildBankEventLog_Item
[i
].begin());
1566 m_GuildBankEventLog_Item
[i
].pop_front();
1567 delete EventLogEntry
;
1568 }while( !m_GuildBankEventLog_Item
[i
].empty() );
1573 void Guild::DisplayGuildBankLogs(WorldSession
*session
, uint8 TabId
)
1575 if (TabId
> GUILD_BANK_MAX_TABS
)
1578 if (TabId
== GUILD_BANK_MAX_TABS
)
1580 // Here we display money logs
1581 WorldPacket
data(MSG_GUILD_BANK_LOG_QUERY
, m_GuildBankEventLog_Money
.size()*(4*4+1)+1+1);
1582 data
<< uint8(TabId
); // Here GUILD_BANK_MAX_TABS
1583 data
<< uint8(m_GuildBankEventLog_Money
.size()); // number of log entries
1584 for (GuildBankEventLog::const_iterator itr
= m_GuildBankEventLog_Money
.begin(); itr
!= m_GuildBankEventLog_Money
.end(); ++itr
)
1586 data
<< uint8((*itr
)->LogEntry
);
1587 data
<< uint64(MAKE_NEW_GUID((*itr
)->PlayerGuid
,0,HIGHGUID_PLAYER
));
1588 if ((*itr
)->LogEntry
== GUILD_BANK_LOG_DEPOSIT_MONEY
||
1589 (*itr
)->LogEntry
== GUILD_BANK_LOG_WITHDRAW_MONEY
||
1590 (*itr
)->LogEntry
== GUILD_BANK_LOG_REPAIR_MONEY
||
1591 (*itr
)->LogEntry
== GUILD_BANK_LOG_UNK1
||
1592 (*itr
)->LogEntry
== GUILD_BANK_LOG_UNK2
)
1594 data
<< uint32((*itr
)->ItemOrMoney
);
1598 data
<< uint32((*itr
)->ItemOrMoney
);
1599 data
<< uint32((*itr
)->ItemStackCount
);
1600 if ((*itr
)->LogEntry
== GUILD_BANK_LOG_MOVE_ITEM
|| (*itr
)->LogEntry
== GUILD_BANK_LOG_MOVE_ITEM2
)
1601 data
<< uint8((*itr
)->DestTabId
); // moved tab
1603 data
<< uint32(time(NULL
)-(*itr
)->TimeStamp
);
1605 session
->SendPacket(&data
);
1609 // here we display current tab logs
1610 WorldPacket
data(MSG_GUILD_BANK_LOG_QUERY
, m_GuildBankEventLog_Item
[TabId
].size()*(4*4+1+1)+1+1);
1611 data
<< uint8(TabId
); // Here a real Tab Id
1612 // number of log entries
1613 data
<< uint8(m_GuildBankEventLog_Item
[TabId
].size());
1614 for (GuildBankEventLog::const_iterator itr
= m_GuildBankEventLog_Item
[TabId
].begin(); itr
!= m_GuildBankEventLog_Item
[TabId
].end(); ++itr
)
1616 data
<< uint8((*itr
)->LogEntry
);
1617 data
<< uint64(MAKE_NEW_GUID((*itr
)->PlayerGuid
,0,HIGHGUID_PLAYER
));
1618 if ((*itr
)->LogEntry
== GUILD_BANK_LOG_DEPOSIT_MONEY
||
1619 (*itr
)->LogEntry
== GUILD_BANK_LOG_WITHDRAW_MONEY
||
1620 (*itr
)->LogEntry
== GUILD_BANK_LOG_REPAIR_MONEY
||
1621 (*itr
)->LogEntry
== GUILD_BANK_LOG_UNK1
||
1622 (*itr
)->LogEntry
== GUILD_BANK_LOG_UNK2
)
1624 data
<< uint32((*itr
)->ItemOrMoney
);
1628 data
<< uint32((*itr
)->ItemOrMoney
);
1629 data
<< uint32((*itr
)->ItemStackCount
);
1630 if ((*itr
)->LogEntry
== GUILD_BANK_LOG_MOVE_ITEM
|| (*itr
)->LogEntry
== GUILD_BANK_LOG_MOVE_ITEM2
)
1631 data
<< uint8((*itr
)->DestTabId
); // moved tab
1633 data
<< uint32(time(NULL
)-(*itr
)->TimeStamp
);
1635 session
->SendPacket(&data
);
1637 sLog
.outDebug("WORLD: Sent (MSG_GUILD_BANK_LOG_QUERY)");
1640 void Guild::LogBankEvent(uint8 LogEntry
, uint8 TabId
, uint32 PlayerGuidLow
, uint32 ItemOrMoney
, uint8 ItemStackCount
, uint8 DestTabId
)
1642 GuildBankEvent
*NewEvent
= new GuildBankEvent
;
1644 NewEvent
->LogGuid
= LogMaxGuid
++;
1645 NewEvent
->LogEntry
= LogEntry
;
1646 NewEvent
->PlayerGuid
= PlayerGuidLow
;
1647 NewEvent
->ItemOrMoney
= ItemOrMoney
;
1648 NewEvent
->ItemStackCount
= ItemStackCount
;
1649 NewEvent
->DestTabId
= DestTabId
;
1650 NewEvent
->TimeStamp
= uint32(time(NULL
));
1652 if (NewEvent
->isMoneyEvent())
1654 if (m_GuildBankEventLog_Money
.size() > GUILD_BANK_MAX_LOGS
)
1656 GuildBankEvent
*OldEvent
= *(m_GuildBankEventLog_Money
.begin());
1657 m_GuildBankEventLog_Money
.pop_front();
1658 CharacterDatabase
.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id
, OldEvent
->LogGuid
);
1661 m_GuildBankEventLog_Money
.push_back(NewEvent
);
1665 if (m_GuildBankEventLog_Item
[TabId
].size() > GUILD_BANK_MAX_LOGS
)
1667 GuildBankEvent
*OldEvent
= *(m_GuildBankEventLog_Item
[TabId
].begin());
1668 m_GuildBankEventLog_Item
[TabId
].pop_front();
1669 CharacterDatabase
.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id
, OldEvent
->LogGuid
);
1672 m_GuildBankEventLog_Item
[TabId
].push_back(NewEvent
);
1674 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
"')",
1675 Id
, NewEvent
->LogGuid
, uint32(NewEvent
->LogEntry
), uint32(TabId
), NewEvent
->PlayerGuid
, NewEvent
->ItemOrMoney
, uint32(NewEvent
->ItemStackCount
), uint32(NewEvent
->DestTabId
), NewEvent
->TimeStamp
);
1678 // This will renum guids used at load to prevent always going up until infinit
1679 void Guild::RenumBankLogs()
1681 QueryResult
*result
= CharacterDatabase
.PQuery("SELECT Min(LogGuid), Max(LogGuid) FROM guild_bank_eventlog WHERE guildid = %u", Id
);
1685 Field
*fields
= result
->Fetch();
1686 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");
1687 LogMaxGuid
= fields
[1].GetUInt32()+1;
1691 bool Guild::AddGBankItemToDB(uint32 GuildId
, uint32 BankTab
, uint32 BankTabSlot
, uint32 GUIDLow
, uint32 Entry
)
1693 CharacterDatabase
.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u' AND TabId = '%u'AND SlotId = '%u'", GuildId
, BankTab
, BankTabSlot
);
1694 CharacterDatabase
.PExecute("INSERT INTO guild_bank_item (guildid,TabId,SlotId,item_guid,item_entry) "
1695 "VALUES ('%u', '%u', '%u', '%u', '%u')", GuildId
, BankTab
, BankTabSlot
, GUIDLow
, Entry
);
1699 void Guild::AppendDisplayGuildBankSlot( WorldPacket
& data
, GuildBankTab
const *tab
, int slot
)
1701 Item
*pItem
= tab
->Slots
[slot
];
1702 uint32 entry
= pItem
? pItem
->GetEntry() : 0;
1704 data
<< uint8(slot
);
1705 data
<< uint32(entry
);
1708 // random item property id +8
1709 data
<< (uint32
) pItem
->GetItemRandomPropertyId();
1710 if (pItem
->GetItemRandomPropertyId())
1712 data
<< (uint32
) pItem
->GetItemSuffixFactor();
1713 // +12 // ITEM_FIELD_STACK_COUNT
1714 data
<< uint32(pItem
->GetCount());
1715 data
<< uint32(0); // +16 // Unknown value
1716 data
<< uint8(0); // unknown 2.4.2
1717 if (uint32 Enchant0
= pItem
->GetEnchantmentId(PERM_ENCHANTMENT_SLOT
))
1719 data
<< uint8(1); // number of enchantments (max 3) why max 3?
1720 data
<< uint8(PERM_ENCHANTMENT_SLOT
); // enchantment slot (range: 0:2)
1721 data
<< uint32(Enchant0
); // enchantment id
1724 data
<< uint8(0); // no enchantments (0)
1728 Item
* Guild::StoreItem(uint8 tabId
, GuildItemPosCountVec
const& dest
, Item
* pItem
)
1733 Item
* lastItem
= pItem
;
1735 for(GuildItemPosCountVec::const_iterator itr
= dest
.begin(); itr
!= dest
.end(); )
1737 uint8 slot
= itr
->slot
;
1738 uint32 count
= itr
->count
;
1742 if(itr
== dest
.end())
1744 lastItem
= _StoreItem(tabId
,slot
,pItem
,count
,false);
1748 lastItem
= _StoreItem(tabId
,slot
,pItem
,count
,true);
1754 // Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
1755 Item
* Guild::_StoreItem( uint8 tab
, uint8 slot
, Item
*pItem
, uint32 count
, bool clone
)
1760 sLog
.outDebug( "GUILD STORAGE: StoreItem tab = %u, slot = %u, item = %u, count = %u", tab
, slot
, pItem
->GetEntry(), count
);
1762 Item
* pItem2
= m_TabListMap
[tab
]->Slots
[slot
];
1767 pItem
= pItem
->CloneItem(count
);
1769 pItem
->SetCount(count
);
1774 m_TabListMap
[tab
]->Slots
[slot
] = pItem
;
1776 pItem
->SetUInt64Value(ITEM_FIELD_CONTAINED
, 0);
1777 pItem
->SetUInt64Value(ITEM_FIELD_OWNER
, 0);
1778 AddGBankItemToDB(GetId(), tab
, slot
, pItem
->GetGUIDLow(), pItem
->GetEntry());
1779 pItem
->FSetState(ITEM_NEW
);
1780 pItem
->SaveToDB(); // not in onventory and can be save standalone
1786 pItem2
->SetCount( pItem2
->GetCount() + count
);
1787 pItem2
->FSetState(ITEM_CHANGED
);
1788 pItem2
->SaveToDB(); // not in onventory and can be save standalone
1792 pItem
->RemoveFromWorld();
1793 pItem
->DeleteFromDB();
1801 void Guild::RemoveItem(uint8 tab
, uint8 slot
)
1803 m_TabListMap
[tab
]->Slots
[slot
] = NULL
;
1804 CharacterDatabase
.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'",
1805 GetId(), uint32(tab
), uint32(slot
));
1808 uint8
Guild::_CanStoreItem_InSpecificSlot( uint8 tab
, uint8 slot
, GuildItemPosCountVec
&dest
, uint32
& count
, bool swap
, Item
* pSrcItem
) const
1810 Item
* pItem2
= m_TabListMap
[tab
]->Slots
[slot
];
1812 // ignore move item (this slot will be empty at move)
1813 if(pItem2
==pSrcItem
)
1818 // empty specific slot - check item fit to slot
1819 if( !pItem2
|| swap
)
1821 // non empty stack with space
1822 need_space
= pSrcItem
->GetMaxStackCount();
1824 // non empty slot, check item type
1828 if(pItem2
->GetEntry() != pSrcItem
->GetEntry())
1829 return EQUIP_ERR_ITEM_CANT_STACK
;
1832 if(pItem2
->GetCount() >= pSrcItem
->GetMaxStackCount())
1833 return EQUIP_ERR_ITEM_CANT_STACK
;
1835 need_space
= pSrcItem
->GetMaxStackCount() - pItem2
->GetCount();
1838 if(need_space
> count
)
1841 GuildItemPosCount newPosition
= GuildItemPosCount(slot
,need_space
);
1842 if(!newPosition
.isContainedIn(dest
))
1844 dest
.push_back(newPosition
);
1845 count
-= need_space
;
1848 return EQUIP_ERR_OK
;
1851 uint8
Guild::_CanStoreItem_InTab( uint8 tab
, GuildItemPosCountVec
&dest
, uint32
& count
, bool merge
, Item
* pSrcItem
, uint8 skip_slot
) const
1853 for(uint32 j
= 0; j
< GUILD_BANK_MAX_SLOTS
; j
++)
1855 // skip specific slot already processed in first called _CanStoreItem_InSpecificSlot
1859 Item
* pItem2
= m_TabListMap
[tab
]->Slots
[j
];
1861 // ignore move item (this slot will be empty at move)
1862 if(pItem2
==pSrcItem
)
1865 // if merge skip empty, if !merge skip non-empty
1866 if((pItem2
!=NULL
)!=merge
)
1871 if(pItem2
->GetEntry() == pSrcItem
->GetEntry() && pItem2
->GetCount() < pSrcItem
->GetMaxStackCount() )
1873 uint32 need_space
= pSrcItem
->GetMaxStackCount() - pItem2
->GetCount();
1874 if(need_space
> count
)
1877 GuildItemPosCount newPosition
= GuildItemPosCount(j
,need_space
);
1878 if(!newPosition
.isContainedIn(dest
))
1880 dest
.push_back(newPosition
);
1881 count
-= need_space
;
1884 return EQUIP_ERR_OK
;
1890 uint32 need_space
= pSrcItem
->GetMaxStackCount();
1891 if(need_space
> count
)
1894 GuildItemPosCount newPosition
= GuildItemPosCount(j
,need_space
);
1895 if(!newPosition
.isContainedIn(dest
))
1897 dest
.push_back(newPosition
);
1898 count
-= need_space
;
1901 return EQUIP_ERR_OK
;
1905 return EQUIP_ERR_OK
;
1908 uint8
Guild::CanStoreItem( uint8 tab
, uint8 slot
, GuildItemPosCountVec
&dest
, uint32 count
, Item
*pItem
, bool swap
) const
1910 sLog
.outDebug( "GUILD STORAGE: CanStoreItem tab = %u, slot = %u, item = %u, count = %u", tab
, slot
, pItem
->GetEntry(), count
);
1912 if(count
> pItem
->GetCount())
1913 return EQUIP_ERR_COULDNT_SPLIT_ITEMS
;
1915 if(pItem
->IsSoulBound())
1916 return EQUIP_ERR_CANT_DROP_SOULBOUND
;
1919 if( slot
!= NULL_SLOT
)
1921 uint8 res
= _CanStoreItem_InSpecificSlot(tab
,slot
,dest
,count
,swap
,pItem
);
1922 if(res
!=EQUIP_ERR_OK
)
1926 return EQUIP_ERR_OK
;
1929 // not specific slot or have spece for partly store only in specific slot
1931 // search stack in tab for merge to
1932 if( pItem
->GetMaxStackCount() > 1 )
1934 uint8 res
= _CanStoreItem_InTab(tab
,dest
,count
,true,pItem
,slot
);
1935 if(res
!=EQUIP_ERR_OK
)
1939 return EQUIP_ERR_OK
;
1942 // search free slot in bag for place to
1943 uint8 res
= _CanStoreItem_InTab(tab
,dest
,count
,false,pItem
,slot
);
1944 if(res
!=EQUIP_ERR_OK
)
1948 return EQUIP_ERR_OK
;
1950 return EQUIP_ERR_BANK_FULL
;
1953 void Guild::SetGuildBankTabText(uint8 TabId
, std::string text
)
1955 if (TabId
>= GUILD_BANK_MAX_TABS
)
1957 if (TabId
>= m_TabListMap
.size())
1959 if (!m_TabListMap
[TabId
])
1962 if(m_TabListMap
[TabId
]->Text
==text
)
1965 utf8truncate(text
,500); // DB and client size limitation
1967 m_TabListMap
[TabId
]->Text
= text
;
1969 CharacterDatabase
.escape_string(text
);
1970 CharacterDatabase
.PExecute("UPDATE guild_bank_tab SET TabText='%s' WHERE guildid='%u' AND TabId='%u'", text
.c_str(), Id
, uint32(TabId
));
1973 void Guild::SendGuildBankTabText(WorldSession
*session
, uint8 TabId
)
1975 if (TabId
> GUILD_BANK_MAX_TABS
)
1978 GuildBankTab
const *tab
= GetBankTab(TabId
);
1982 WorldPacket
data(MSG_QUERY_GUILD_BANK_TEXT
, 1+tab
->Text
.size()+1);
1983 data
<< uint8(TabId
);
1985 session
->SendPacket(&data
);
1988 bool GuildItemPosCount::isContainedIn(GuildItemPosCountVec
const &vec
) const
1990 for(GuildItemPosCountVec::const_iterator itr
= vec
.begin(); itr
!= vec
.end();++itr
)
1991 if(itr
->slot
== slot
)