root/trunk/src/game/Guild.cpp @ 148

Revision 102, 67.2 kB (checked in by yumileroy, 17 years ago)

[svn] Fixed copyright notices to comply with GPL.

Original author: w12x
Date: 2008-10-23 03:29:52-05:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "Database/DatabaseEnv.h"
22#include "WorldPacket.h"
23#include "WorldSession.h"
24#include "MapManager.h"
25#include "Player.h"
26#include "Opcodes.h"
27#include "ObjectMgr.h"
28#include "Guild.h"
29#include "Chat.h"
30#include "SocialMgr.h"
31#include "Util.h"
32
33Guild::Guild()
34{
35    Id = 0;
36    name = "";
37    leaderGuid = 0;
38    GINFO = MOTD = "";
39    EmblemStyle = 0;
40    EmblemColor = 0;
41    BorderStyle = 0;
42    BorderColor = 0;
43    BackgroundColor = 0;
44
45    CreatedYear = 0;
46    CreatedMonth = 0;
47    CreatedDay = 0;
48}
49
50Guild::~Guild()
51{
52
53}
54
55bool Guild::create(uint64 lGuid, std::string gname)
56{
57    std::string rname;
58    std::string lName;
59
60    if(!objmgr.GetPlayerNameByGUID(lGuid, lName))
61        return false;
62    if(objmgr.GetGuildByName(gname))
63        return false;
64
65    sLog.outDebug("GUILD: creating guild %s to leader: %u", gname.c_str(), GUID_LOPART(lGuid));
66
67    leaderGuid = lGuid;
68    name = gname;
69    GINFO = "";
70    MOTD = "No message set.";
71    guildbank_money = 0;
72    purchased_tabs = 0;
73
74    QueryResult *result = CharacterDatabase.Query( "SELECT MAX(guildid) FROM guild" );
75    if( result )
76    {
77        Id = (*result)[0].GetUInt32()+1;
78        delete result;
79    }
80    else Id = 1;
81
82    // gname already assigned to Guild::name, use it to encode string for DB
83    CharacterDatabase.escape_string(gname);
84
85    std::string dbGINFO = GINFO;
86    std::string dbMOTD = MOTD;
87    CharacterDatabase.escape_string(dbGINFO);
88    CharacterDatabase.escape_string(dbMOTD);
89
90    CharacterDatabase.BeginTransaction();
91    // CharacterDatabase.PExecute("DELETE FROM guild WHERE guildid='%u'", Id); - MAX(guildid)+1 not exist
92    CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", Id);
93    CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guildid='%u'", Id);
94    CharacterDatabase.PExecute("INSERT INTO guild (guildid,name,leaderguid,info,motd,createdate,EmblemStyle,EmblemColor,BorderStyle,BorderColor,BackgroundColor,BankMoney) "
95        "VALUES('%u','%s','%u', '%s', '%s', NOW(),'%u','%u','%u','%u','%u','" I64FMTD "')",
96        Id, gname.c_str(), GUID_LOPART(leaderGuid), dbGINFO.c_str(), dbMOTD.c_str(), EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor, guildbank_money);
97    CharacterDatabase.CommitTransaction();
98
99    rname = "Guild Master";
100    CreateRank(rname,GR_RIGHT_ALL);
101    rname = "Officer";
102    CreateRank(rname,GR_RIGHT_ALL);
103    rname = "Veteran";
104    CreateRank(rname,GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
105    rname = "Member";
106    CreateRank(rname,GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
107    rname = "Initiate";
108    CreateRank(rname,GR_RIGHT_GCHATLISTEN | GR_RIGHT_GCHATSPEAK);
109
110    return AddMember(lGuid, (uint32)GR_GUILDMASTER);
111}
112
113bool Guild::AddMember(uint64 plGuid, uint32 plRank)
114{
115    if(Player::GetGuildIdFromDB(plGuid) != 0)               // player already in guild
116        return false;
117
118    // remove all player signs from another petitions
119    // this will be prevent attempt joining player to many guilds and corrupt guild data integrity
120    Player::RemovePetitionsAndSigns(plGuid, 9);
121
122    // fill player data
123    MemberSlot newmember;
124
125    if(!FillPlayerData(plGuid, &newmember))                 // problems with player data collection
126        return false;
127
128    newmember.RankId = plRank;
129    newmember.OFFnote = (std::string)"";
130    newmember.Pnote = (std::string)"";
131    newmember.logout_time = time(NULL);
132    newmember.BankResetTimeMoney = 0;                       // this will force update at first query
133    for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
134        newmember.BankResetTimeTab[i] = 0;
135    members[GUID_LOPART(plGuid)] = newmember;
136
137    std::string dbPnote = newmember.Pnote;
138    std::string dbOFFnote = newmember.OFFnote;
139    CharacterDatabase.escape_string(dbPnote);
140    CharacterDatabase.escape_string(dbOFFnote);
141
142    CharacterDatabase.PExecute("INSERT INTO guild_member (guildid,guid,rank,pnote,offnote) VALUES ('%u', '%u', '%u','%s','%s')",
143        Id, GUID_LOPART(plGuid), newmember.RankId, dbPnote.c_str(), dbOFFnote.c_str());
144
145    Player* pl = objmgr.GetPlayer(plGuid);
146    if(pl)
147    {
148        pl->SetInGuild(Id);
149        pl->SetRank(newmember.RankId);
150        pl->SetGuildIdInvited(0);
151    }
152    else
153    {
154        Player::SetUInt32ValueInDB(PLAYER_GUILDID, Id, plGuid);
155        Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, newmember.RankId, plGuid);
156    }
157    return true;
158}
159
160void Guild::SetMOTD(std::string motd)
161{
162    MOTD = motd;
163
164    // motd now can be used for encoding to DB
165    CharacterDatabase.escape_string(motd);
166    CharacterDatabase.PExecute("UPDATE guild SET motd='%s' WHERE guildid='%u'", motd.c_str(), Id);
167}
168
169void Guild::SetGINFO(std::string ginfo)
170{
171    GINFO = ginfo;
172
173    // ginfo now can be used for encoding to DB
174    CharacterDatabase.escape_string(ginfo);
175    CharacterDatabase.PExecute("UPDATE guild SET info='%s' WHERE guildid='%u'", ginfo.c_str(), Id);
176}
177
178bool Guild::LoadGuildFromDB(uint32 GuildId)
179{
180    if(!LoadRanksFromDB(GuildId))
181        return false;
182
183    if(!LoadMembersFromDB(GuildId))
184        return false;
185
186    QueryResult *result = CharacterDatabase.PQuery("SELECT MAX(TabId) FROM guild_bank_tab WHERE guildid='%u'", GuildId);
187    if(result)
188    {
189        Field *fields = result->Fetch();
190        purchased_tabs = fields[0].GetUInt8()+1;            // Because TabId begins at 0
191        delete result;
192    }
193    else
194        purchased_tabs = 0;
195
196    LoadBankRightsFromDB(GuildId);                          // Must be after LoadRanksFromDB because it populates rank struct
197
198    //                                        0        1     2           3            4            5           6
199    result = CharacterDatabase.PQuery("SELECT guildid, name, leaderguid, EmblemStyle, EmblemColor, BorderStyle, BorderColor,"
200    //   7                8     9     10          11
201        "BackgroundColor, info, motd, createdate, BankMoney FROM guild WHERE guildid = '%u'", GuildId);
202
203    if(!result)
204        return false;
205
206    Field *fields = result->Fetch();
207
208    Id = fields[0].GetUInt32();
209    name = fields[1].GetCppString();
210    leaderGuid  = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER);
211
212    EmblemStyle = fields[3].GetUInt32();
213    EmblemColor = fields[4].GetUInt32();
214    BorderStyle = fields[5].GetUInt32();
215    BorderColor = fields[6].GetUInt32();
216    BackgroundColor = fields[7].GetUInt32();
217    GINFO = fields[8].GetCppString();
218    MOTD = fields[9].GetCppString();
219    uint64 time = fields[10].GetUInt64();                   //datetime is uint64 type ... YYYYmmdd:hh:mm:ss
220    guildbank_money = fields[11].GetUInt64();
221
222    delete result;
223
224    uint64 dTime = time /1000000;
225    CreatedDay   = dTime%100;
226    CreatedMonth = (dTime/100)%100;
227    CreatedYear  = (dTime/10000)%10000;
228
229    // If the leader does not exist attempt to promote another member
230    if(!objmgr.GetPlayerAccountIdByGUID(leaderGuid ))
231    {
232        DelMember(leaderGuid);
233
234        // check no members case (disbanded)
235        if(members.empty())
236            return false;
237    }
238
239    sLog.outDebug("Guild %u Creation time Loaded day: %u, month: %u, year: %u", GuildId, CreatedDay, CreatedMonth, CreatedYear);
240    m_bankloaded = false;
241    m_eventlogloaded = false;
242    m_onlinemembers = 0;
243    RenumBankLogs();
244    RenumGuildEventlog();
245    return true;
246}
247
248bool Guild::LoadRanksFromDB(uint32 GuildId)
249{
250    Field *fields;
251    QueryResult *result = CharacterDatabase.PQuery("SELECT rname,rights,BankMoneyPerDay,rid FROM guild_rank WHERE guildid = '%u' ORDER BY rid ASC", GuildId);
252
253    if(!result)
254        return false;
255
256    bool broken_ranks = false;
257
258    do
259    {
260        fields = result->Fetch();
261
262        std::string rankName = fields[0].GetCppString();
263        uint32 rankRights    = fields[1].GetUInt32();
264        uint32 rankMoney     = fields[2].GetUInt32();
265        uint32 rankRID       = fields[3].GetUInt32();
266
267        if(rankRID != m_ranks.size()+1)                     // guild_rank.rid always store rank+1
268            broken_ranks =  true;
269
270        if(m_ranks.size()==GR_GUILDMASTER)                  // prevent loss leader rights
271            rankRights |= GR_RIGHT_ALL;
272
273        AddRank(rankName,rankRights,rankMoney);
274    }while( result->NextRow() );
275    delete result;
276
277    if(m_ranks.size()==0)                                   // empty rank table?
278    {
279        AddRank("Guild Master",GR_RIGHT_ALL,0);
280        broken_ranks = true;
281    }
282
283    // guild_rank have wrong numbered ranks, repair
284    if(broken_ranks)
285    {
286        sLog.outError("Guild %u have broken `guild_rank` data, repairing...",GuildId);
287        CharacterDatabase.BeginTransaction();
288        CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid='%u'", GuildId);
289        for(size_t i =0; i < m_ranks.size(); ++i)
290        {
291            // guild_rank.rid always store rank+1
292            std::string name = m_ranks[i].name;
293            uint32 rights = m_ranks[i].rights;
294            CharacterDatabase.escape_string(name);
295            CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", GuildId, i+1, name.c_str(), rights);
296        }
297        CharacterDatabase.CommitTransaction();
298    }
299
300    return true;
301}
302
303bool Guild::LoadMembersFromDB(uint32 GuildId)
304{
305    //                                                     0                 1     2      3        4                  5
306    QueryResult *result = CharacterDatabase.PQuery("SELECT guild_member.guid,rank, pnote, offnote, BankResetTimeMoney,BankRemMoney,"
307    //   6                  7                 8                  9                 10                 11
308        "BankResetTimeTab0, BankRemSlotsTab0, BankResetTimeTab1, BankRemSlotsTab1, BankResetTimeTab2, BankRemSlotsTab2,"
309    //   12                 13                14                 15                16                 17
310        "BankResetTimeTab3, BankRemSlotsTab3, BankResetTimeTab4, BankRemSlotsTab4, BankResetTimeTab5, BankRemSlotsTab5,"
311    //   18
312        "logout_time FROM guild_member LEFT JOIN characters ON characters.guid = guild_member.guid WHERE guildid = '%u'", GuildId);
313
314    if(!result)
315        return false;
316
317    do
318    {
319        Field *fields = result->Fetch();
320        MemberSlot newmember;
321        newmember.RankId = fields[1].GetUInt32();
322        uint64 guid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
323
324        // Player does not exist
325        if(!FillPlayerData(guid, &newmember))
326            continue;
327
328        newmember.Pnote                 = fields[2].GetCppString();
329        newmember.OFFnote               = fields[3].GetCppString();
330        newmember.BankResetTimeMoney    = fields[4].GetUInt32();
331        newmember.BankRemMoney          = fields[5].GetUInt32();
332        for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
333        {
334            newmember.BankResetTimeTab[i] = fields[6+(2*i)].GetUInt32();
335            newmember.BankRemSlotsTab[i]  = fields[7+(2*i)].GetUInt32();
336        }
337        newmember.logout_time           = fields[18].GetUInt64();
338        members[GUID_LOPART(guid)]      = newmember;
339
340    }while( result->NextRow() );
341    delete result;
342
343    if(members.empty())
344        return false;
345
346    return true;
347}
348
349bool Guild::FillPlayerData(uint64 guid, MemberSlot* memslot)
350{
351    std::string plName;
352    uint32 plLevel;
353    uint32 plClass;
354    uint32 plZone;
355
356    Player* pl = objmgr.GetPlayer(guid);
357    if(pl)
358    {
359        plName  = pl->GetName();
360        plLevel = pl->getLevel();
361        plClass = pl->getClass();
362        plZone  = pl->GetZoneId();
363    }
364    else
365    {
366                PCachePlayerInfo pInfo = objmgr.GetPlayerInfoFromCache(GUID_LOPART(guid));
367        if(pInfo)
368        {
369            plName = pInfo->sPlayerName;
370            plClass = pInfo->unClass;
371            if(plClass<CLASS_WARRIOR||plClass>=MAX_CLASSES)     // can be at broken `class` field
372            {
373                sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`class`.",GUID_LOPART(guid));
374                return false;
375            }
376            plLevel = pInfo->unLevel;
377            plZone = Player::GetZoneIdFromDB(guid);
378        }
379        else
380        {
381        if(!objmgr.GetPlayerNameByGUID(guid, plName))       // player doesn't exist
382            return false;
383
384        plLevel = Player::GetUInt32ValueFromDB(UNIT_FIELD_LEVEL, guid);
385        if(plLevel<1||plLevel>255)                          // can be at broken `data` field
386        {
387            sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`data`.",GUID_LOPART(guid));
388            return false;
389        }
390        plZone = Player::GetZoneIdFromDB(guid);
391
392        QueryResult *result = CharacterDatabase.PQuery("SELECT class FROM characters WHERE guid='%u'", GUID_LOPART(guid));
393        if(!result)
394            return false;
395        plClass = (*result)[0].GetUInt32();
396        if(plClass<CLASS_WARRIOR||plClass>=MAX_CLASSES)     // can be at broken `class` field
397        {
398            sLog.outError("Player (GUID: %u) has a broken data in field `characters`.`class`.",GUID_LOPART(guid));
399            return false;
400        }
401
402        delete result;
403    }
404        }
405
406    memslot->name = plName;
407    memslot->level = plLevel;
408    memslot->Class = plClass;
409    memslot->zoneId = plZone;
410
411    return(true);
412}
413
414void Guild::LoadPlayerStatsByGuid(uint64 guid)
415{
416    MemberList::iterator itr = members.find(GUID_LOPART(guid));
417    if (itr == members.end() )
418        return;
419
420    Player *pl = ObjectAccessor::FindPlayer(guid);
421    if(!pl)
422        return;
423    itr->second.name  = pl->GetName();
424    itr->second.level = pl->getLevel();
425    itr->second.Class = pl->getClass();
426}
427
428void Guild::SetLeader(uint64 guid)
429{
430    leaderGuid = guid;
431    this->ChangeRank(guid, GR_GUILDMASTER);
432
433    CharacterDatabase.PExecute("UPDATE guild SET leaderguid='%u' WHERE guildid='%u'", GUID_LOPART(guid), Id);
434}
435
436void Guild::DelMember(uint64 guid, bool isDisbanding)
437{
438    if(this->leaderGuid == guid && !isDisbanding)
439    {
440        std::ostringstream ss;
441        ss<<"SELECT guid FROM guild_member WHERE guildid='"<<Id<<"' AND guid!='"<<this->leaderGuid<<"' ORDER BY rank ASC LIMIT 1";
442        QueryResult *result = CharacterDatabase.Query( ss.str().c_str() );
443        if( result )
444        {
445            uint64 newLeaderGUID;
446            Player *newLeader;
447            std::string newLeaderName, oldLeaderName;
448
449            newLeaderGUID = (*result)[0].GetUInt64();
450            delete result;
451
452            this->SetLeader(newLeaderGUID);
453
454            newLeader = objmgr.GetPlayer(newLeaderGUID);
455            if(newLeader)
456            {
457                newLeader->SetRank(GR_GUILDMASTER);
458                newLeaderName = newLeader->GetName();
459            }
460            else
461            {
462                Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, GR_GUILDMASTER, newLeaderGUID);
463                objmgr.GetPlayerNameByGUID(newLeaderGUID, newLeaderName);
464            }
465
466            // when leader non-exist (at guild load with deleted leader only) not send broadcasts
467            if(objmgr.GetPlayerNameByGUID(guid, oldLeaderName))
468            {
469                WorldPacket data(SMSG_GUILD_EVENT, (1+1+oldLeaderName.size()+1+newLeaderName.size()+1));
470                data << (uint8)GE_LEADER_CHANGED;
471                data << (uint8)2;
472                data << oldLeaderName;
473                data << newLeaderName;
474                this->BroadcastPacket(&data);
475
476                data.Initialize(SMSG_GUILD_EVENT, (1+1+oldLeaderName.size()+1));
477                data << (uint8)GE_LEFT;
478                data << (uint8)1;
479                data << oldLeaderName;
480                this->BroadcastPacket(&data);
481            }
482
483            sLog.outDebug( "WORLD: Sent (SMSG_GUILD_EVENT)" );
484        }
485        else
486        {
487            this->Disband();
488            return;
489        }
490    }
491
492    members.erase(GUID_LOPART(guid));
493
494    Player *player = objmgr.GetPlayer(guid);
495    if(player)
496    {
497        player->SetInGuild(0);
498        player->SetRank(0);
499    }
500    else
501    {
502        Player::SetUInt32ValueInDB(PLAYER_GUILDID, 0, guid);
503        Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, GR_GUILDMASTER, guid);
504    }
505
506    CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid));
507}
508
509void Guild::ChangeRank(uint64 guid, uint32 newRank)
510{
511    MemberList::iterator itr = members.find(GUID_LOPART(guid));
512    if( itr != members.end() )
513        itr->second.RankId = newRank;
514
515    Player *player = objmgr.GetPlayer(guid);
516    if(player)
517        player->SetRank(newRank);
518    else
519        Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, newRank, guid);
520
521    CharacterDatabase.PExecute( "UPDATE guild_member SET rank='%u' WHERE guid='%u'", newRank, GUID_LOPART(guid) );
522}
523
524void Guild::SetPNOTE(uint64 guid,std::string pnote)
525{
526    MemberList::iterator itr = members.find(GUID_LOPART(guid));
527    if( itr == members.end() )
528        return;
529
530    itr->second.Pnote = pnote;
531
532    // pnote now can be used for encoding to DB
533    CharacterDatabase.escape_string(pnote);
534    CharacterDatabase.PExecute("UPDATE guild_member SET pnote = '%s' WHERE guid = '%u'", pnote.c_str(), itr->first);
535}
536
537void Guild::SetOFFNOTE(uint64 guid,std::string offnote)
538{
539    MemberList::iterator itr = members.find(GUID_LOPART(guid));
540    if( itr == members.end() )
541        return;
542    itr->second.OFFnote = offnote;
543    // offnote now can be used for encoding to DB
544    CharacterDatabase.escape_string(offnote);
545    CharacterDatabase.PExecute("UPDATE guild_member SET offnote = '%s' WHERE guid = '%u'", offnote.c_str(), itr->first);
546}
547
548void Guild::BroadcastToGuild(WorldSession *session, std::string msg, uint32 language)
549{
550    if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(),GR_RIGHT_GCHATSPEAK))
551    {
552        WorldPacket data;
553        ChatHandler(session).FillMessageData(&data, CHAT_MSG_GUILD, language, 0, msg.c_str());
554
555        for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
556        {
557            Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
558
559            if (pl && pl->GetSession() && HasRankRight(pl->GetRank(),GR_RIGHT_GCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow()) )
560                pl->GetSession()->SendPacket(&data);
561        }
562    }
563}
564
565void Guild::BroadcastToOfficers(WorldSession *session, std::string msg, uint32 language)
566{
567    if (session && session->GetPlayer() && HasRankRight(session->GetPlayer()->GetRank(),GR_RIGHT_OFFCHATSPEAK))
568    {
569        for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
570        {
571            WorldPacket data;
572            ChatHandler::FillMessageData(&data, session, CHAT_MSG_OFFICER, language, NULL, 0, msg.c_str(),NULL);
573
574            Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
575
576            if (pl && pl->GetSession() && HasRankRight(pl->GetRank(),GR_RIGHT_OFFCHATLISTEN) && !pl->GetSocial()->HasIgnore(session->GetPlayer()->GetGUIDLow()))
577                pl->GetSession()->SendPacket(&data);
578        }
579    }
580}
581
582void Guild::BroadcastPacket(WorldPacket *packet)
583{
584    for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
585    {
586        Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
587        if(player)
588            player->GetSession()->SendPacket(packet);
589    }
590}
591
592void Guild::BroadcastPacketToRank(WorldPacket *packet, uint32 rankId)
593{
594    for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
595    {
596        if (itr->second.RankId == rankId)
597        {
598            Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
599            if(player)
600                player->GetSession()->SendPacket(packet);
601        }
602    }
603}
604
605void Guild::CreateRank(std::string name_,uint32 rights)
606{
607    if(m_ranks.size() >= GUILD_MAX_RANKS)
608        return;
609
610    AddRank(name_,rights,0);
611
612    for (int i = 0; i < purchased_tabs; ++i)
613    {
614        CreateBankRightForTab(m_ranks.size()-1, uint8(i));
615    }
616
617    // guild_rank.rid always store rank+1 value
618
619    // name now can be used for encoding to DB
620    CharacterDatabase.escape_string(name_);
621    CharacterDatabase.PExecute( "INSERT INTO guild_rank (guildid,rid,rname,rights) VALUES ('%u', '%u', '%s', '%u')", Id, m_ranks.size(), name_.c_str(), rights );
622}
623
624void Guild::AddRank(std::string name_,uint32 rights, uint32 money)
625{
626    m_ranks.push_back(RankInfo(name_,rights,money));
627}
628
629void Guild::DelRank()
630{
631    if(m_ranks.empty())
632        return;
633
634    // guild_rank.rid always store rank+1 value
635    uint32 rank = m_ranks.size()-1;
636    CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE rid>='%u' AND guildid='%u'", (rank+1), Id);
637
638    m_ranks.pop_back();
639}
640
641std::string Guild::GetRankName(uint32 rankId)
642{
643    if(rankId >= m_ranks.size())
644        return "<unknown>";
645
646    return m_ranks[rankId].name;
647}
648
649uint32 Guild::GetRankRights(uint32 rankId)
650{
651    if(rankId >= m_ranks.size())
652        return 0;
653
654    return m_ranks[rankId].rights;
655}
656
657void Guild::SetRankName(uint32 rankId, std::string name_)
658{
659    if(rankId >= m_ranks.size())
660        return;
661
662    m_ranks[rankId].name = name_;
663
664    // name now can be used for encoding to DB
665    CharacterDatabase.escape_string(name_);
666    CharacterDatabase.PExecute("UPDATE guild_rank SET rname='%s' WHERE rid='%u' AND guildid='%u'", name_.c_str(), (rankId+1), Id);
667}
668
669void Guild::SetRankRights(uint32 rankId, uint32 rights)
670{
671    if(rankId >= m_ranks.size())
672        return;
673
674    m_ranks[rankId].rights = rights;
675
676    CharacterDatabase.PExecute("UPDATE guild_rank SET rights='%u' WHERE rid='%u' AND guildid='%u'", rights, (rankId+1), Id);
677}
678
679void Guild::Disband()
680{
681    WorldPacket data(SMSG_GUILD_EVENT, 1);
682    data << (uint8)GE_DISBANDED;
683    this->BroadcastPacket(&data);
684
685    while (!members.empty())
686    {
687        MemberList::iterator itr = members.begin();
688        DelMember(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER), true);
689    }
690
691    CharacterDatabase.BeginTransaction();
692    CharacterDatabase.PExecute("DELETE FROM guild WHERE guildid = '%u'",Id);
693    CharacterDatabase.PExecute("DELETE FROM guild_rank WHERE guildid = '%u'",Id);
694    CharacterDatabase.PExecute("DELETE FROM guild_bank_tab WHERE guildid = '%u'",Id);
695    CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u'",Id);
696    CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u'",Id);
697    CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid = '%u'",Id);
698    CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid = '%u'",Id);
699    CharacterDatabase.CommitTransaction();
700    objmgr.RemoveGuild(this);
701}
702
703void Guild::Roster(WorldSession *session)
704{
705                                                            // we can only guess size
706    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));
707    data << (uint32)members.size();
708    data << MOTD;
709    data << GINFO;
710
711    data << (uint32)m_ranks.size();
712    for (RankList::iterator ritr = m_ranks.begin(); ritr != m_ranks.end();++ritr)
713    {
714        data << (uint32)ritr->rights;
715        data << (uint32)ritr->BankMoneyPerDay;              // count of: withdraw gold(gold/day) Note: in game set gold, in packet set bronze.
716        for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
717        {
718            data << (uint32)ritr->TabRight[i];              // for TAB_i rights: view tabs = 0x01, deposit items =0x02
719            data << (uint32)ritr->TabSlotPerDay[i];         // for TAB_i count of: withdraw items(stack/day)
720        }
721    }
722    for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
723    {
724        if (Player *pl = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)))
725        {
726            data << (uint64)pl->GetGUID();
727            data << (uint8)1;
728            data << (std::string)pl->GetName();
729            data << (uint32)itr->second.RankId;
730            data << (uint8)pl->getLevel();
731            data << (uint8)pl->getClass();
732            data << (uint8)0;                               // new 2.4.0
733            data << (uint32)pl->GetZoneId();
734            data << itr->second.Pnote;
735            data << itr->second.OFFnote;
736        }
737        else
738        {
739            data << uint64(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
740            data << (uint8)0;
741            data << itr->second.name;
742            data << (uint32)itr->second.RankId;
743            data << (uint8)itr->second.level;
744            data << (uint8)itr->second.Class;
745            data << (uint8)0;                               // new 2.4.0
746            data << (uint32)itr->second.zoneId;
747            data << (float(time(NULL)-itr->second.logout_time) / DAY);
748            data << itr->second.Pnote;
749            data << itr->second.OFFnote;
750        }
751    }
752    session->SendPacket(&data);;
753    sLog.outDebug( "WORLD: Sent (SMSG_GUILD_ROSTER)" );
754}
755
756void Guild::Query(WorldSession *session)
757{
758    WorldPacket data(SMSG_GUILD_QUERY_RESPONSE, (8*32+200));// we can only guess size
759
760    data << Id;
761    data << name;
762    RankList::iterator itr;
763    for (size_t i = 0 ; i < 10; ++i)                        // show always 10 ranks
764    {
765        if(i < m_ranks.size())
766            data << m_ranks[i].name;
767        else
768            data << (uint8)0;                               // null string
769    }
770
771    data << uint32(EmblemStyle);
772    data << uint32(EmblemColor);
773    data << uint32(BorderStyle);
774    data << uint32(BorderColor);
775    data << uint32(BackgroundColor);
776
777    session->SendPacket( &data );
778    sLog.outDebug( "WORLD: Sent (SMSG_GUILD_QUERY_RESPONSE)" );
779}
780
781void Guild::SetEmblem(uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor)
782{
783    this->EmblemStyle = emblemStyle;
784    this->EmblemColor = emblemColor;
785    this->BorderStyle = borderStyle;
786    this->BorderColor = borderColor;
787    this->BackgroundColor = backgroundColor;
788
789    CharacterDatabase.PExecute("UPDATE guild SET EmblemStyle=%u, EmblemColor=%u, BorderStyle=%u, BorderColor=%u, BackgroundColor=%u WHERE guildid = %u", EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor, Id);
790}
791
792void Guild::UpdateLogoutTime(uint64 guid)
793{
794    MemberList::iterator itr = members.find(GUID_LOPART(guid));
795    if (itr == members.end() )
796        return;
797
798    itr->second.logout_time = time(NULL);
799
800    if (m_onlinemembers > 0)
801        --m_onlinemembers;
802    else
803    {
804        UnloadGuildBank();
805        UnloadGuildEventlog();
806    }
807}
808
809// *************************************************
810// Guild Eventlog part
811// *************************************************
812// Display guild eventlog
813void Guild::DisplayGuildEventlog(WorldSession *session)
814{
815    // Load guild eventlog, if not already done
816    if (!m_eventlogloaded)
817        LoadGuildEventLogFromDB();
818
819    // Sending result
820    WorldPacket data(MSG_GUILD_EVENT_LOG_QUERY, 0);
821    // count, max count == 100
822    data << uint8(m_GuildEventlog.size());
823    for (GuildEventlog::const_iterator itr = m_GuildEventlog.begin(); itr != m_GuildEventlog.end(); ++itr)
824    {
825        // Event type
826        data << uint8((*itr)->EventType);
827        // Player 1
828        data << uint64((*itr)->PlayerGuid1);
829        // Player 2 not for left/join guild events
830        if( (*itr)->EventType != GUILD_EVENT_LOG_JOIN_GUILD && (*itr)->EventType != GUILD_EVENT_LOG_LEAVE_GUILD )
831            data << uint64((*itr)->PlayerGuid2);
832        // New Rank - only for promote/demote guild events
833        if( (*itr)->EventType == GUILD_EVENT_LOG_PROMOTE_PLAYER || (*itr)->EventType == GUILD_EVENT_LOG_DEMOTE_PLAYER )
834            data << uint8((*itr)->NewRank);
835        // Event timestamp
836        data << uint32(time(NULL)-(*itr)->TimeStamp);
837    }
838    session->SendPacket(&data);
839    sLog.outDebug("WORLD: Sent (MSG_GUILD_EVENT_LOG_QUERY)");
840}
841
842// Load guild eventlog from DB
843void Guild::LoadGuildEventLogFromDB()
844{
845    // Return if already loaded
846    if (m_eventlogloaded)
847        return;
848
849    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);
850    if(!result)
851        return;
852    do
853    {
854        Field *fields = result->Fetch();
855        GuildEventlogEntry *NewEvent = new GuildEventlogEntry;
856        // Fill entry
857        NewEvent->LogGuid = fields[0].GetUInt32();
858        NewEvent->EventType = fields[1].GetUInt8();
859        NewEvent->PlayerGuid1 = fields[2].GetUInt32();
860        NewEvent->PlayerGuid2 = fields[3].GetUInt32();
861        NewEvent->NewRank = fields[4].GetUInt8();
862        NewEvent->TimeStamp = fields[5].GetUInt64();
863        // Add entry to map
864        m_GuildEventlog.push_front(NewEvent);
865
866    } while( result->NextRow() );
867    delete result;
868
869    // Check lists size in case to many event entries in db
870    // This cases can happen only if a crash occured somewhere and table has too many log entries
871    if (!m_GuildEventlog.empty())
872    {
873        CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid=%u AND LogGuid < %u", Id, m_GuildEventlog.front()->LogGuid);
874    }
875    m_eventlogloaded = true;
876}
877
878// Unload guild eventlog
879void Guild::UnloadGuildEventlog()
880{
881    if (!m_eventlogloaded)
882        return;
883    GuildEventlogEntry *EventLogEntry;
884    if( !m_GuildEventlog.empty() )
885    {
886        do
887        {
888            EventLogEntry = *(m_GuildEventlog.begin());
889            m_GuildEventlog.pop_front();
890            delete EventLogEntry;
891        }while( !m_GuildEventlog.empty() );
892    }
893    m_eventlogloaded = false;
894}
895
896// This will renum guids used at load to prevent always going up until infinit
897void Guild::RenumGuildEventlog()
898{
899    QueryResult *result = CharacterDatabase.PQuery("SELECT Min(LogGuid), Max(LogGuid) FROM guild_eventlog WHERE guildid = %u", Id);
900    if(!result)
901        return;
902
903    Field *fields = result->Fetch();
904    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");
905    GuildEventlogMaxGuid = fields[1].GetUInt32()+1;
906    delete result;
907}
908
909// Add entry to guild eventlog
910void Guild::LogGuildEvent(uint8 EventType, uint32 PlayerGuid1, uint32 PlayerGuid2, uint8 NewRank)
911{
912    GuildEventlogEntry *NewEvent = new GuildEventlogEntry;
913    // Fill entry
914    NewEvent->LogGuid = GuildEventlogMaxGuid++;
915    NewEvent->EventType = EventType;
916    NewEvent->PlayerGuid1 = PlayerGuid1;
917    NewEvent->PlayerGuid2 = PlayerGuid2;
918    NewEvent->NewRank = NewRank;
919    NewEvent->TimeStamp = uint32(time(NULL));
920    // Check max entry limit and delete from db if needed
921    if (m_GuildEventlog.size() > GUILD_EVENTLOG_MAX_ENTRIES)
922    {
923        GuildEventlogEntry *OldEvent = *(m_GuildEventlog.begin());
924        m_GuildEventlog.pop_front();
925        CharacterDatabase.PExecute("DELETE FROM guild_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, OldEvent->LogGuid);
926        delete OldEvent;
927    }
928    // Add entry to map
929    m_GuildEventlog.push_back(NewEvent);
930    // Add new eventlog entry into DB
931    CharacterDatabase.PExecute("INSERT INTO guild_eventlog (guildid, LogGuid, EventType, PlayerGuid1, PlayerGuid2, NewRank, TimeStamp) VALUES ('%u','%u','%u','%u','%u','%u','" I64FMTD "')",
932        Id, NewEvent->LogGuid, uint32(NewEvent->EventType), NewEvent->PlayerGuid1, NewEvent->PlayerGuid2, uint32(NewEvent->NewRank), NewEvent->TimeStamp);
933}
934
935// *************************************************
936// Guild Bank part
937// *************************************************
938// Bank content related
939void Guild::DisplayGuildBankContent(WorldSession *session, uint8 TabId)
940{
941    WorldPacket data(SMSG_GUILD_BANK_LIST,1200);
942
943    GuildBankTab const* tab = GetBankTab(TabId);
944    if (!tab)
945        return;
946
947    if(!IsMemberHaveRights(session->GetPlayer()->GetGUIDLow(),TabId,GUILD_BANK_RIGHT_VIEW_TAB))
948        return;
949
950    data << uint64(GetGuildBankMoney());
951    data << uint8(TabId);
952                                                            // remaining slots for today
953    data << uint32(GetMemberSlotWithdrawRem(session->GetPlayer()->GetGUIDLow(), TabId));
954    data << uint8(0);                                       // Tell client this is a tab content packet
955
956    data << uint8(GUILD_BANK_MAX_SLOTS);
957
958    for (int i=0; i<GUILD_BANK_MAX_SLOTS; ++i)
959        AppendDisplayGuildBankSlot(data, tab, i);
960
961    session->SendPacket(&data);
962
963    sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
964}
965
966void Guild::DisplayGuildBankMoneyUpdate()
967{
968    WorldPacket data(SMSG_GUILD_BANK_LIST, 8+1+4+1+1);
969
970    data << uint64(GetGuildBankMoney());
971    data << uint8(0);
972    // remaining slots for today
973
974    size_t rempos = data.wpos();
975    data << uint32(0);                                      // will be filled later
976    data << uint8(0);                                       // Tell client this is a tab content packet
977
978    data << uint8(0);                                       // not send items
979
980    BroadcastPacket(&data);
981
982    sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
983}
984
985void Guild::DisplayGuildBankContentUpdate(uint8 TabId, int32 slot1, int32 slot2)
986{
987    GuildBankTab const* tab = GetBankTab(TabId);
988    if (!tab)
989        return;
990
991    WorldPacket data(SMSG_GUILD_BANK_LIST,1200);
992
993    data << uint64(GetGuildBankMoney());
994    data << uint8(TabId);
995    // remaining slots for today
996
997    size_t rempos = data.wpos();
998    data << uint32(0);                                      // will be filled later
999    data << uint8(0);                                       // Tell client this is a tab content packet
1000
1001    if(slot2==-1)                                           // single item in slot1
1002    {
1003        data << uint8(1);
1004
1005        AppendDisplayGuildBankSlot(data, tab, slot1);
1006    }
1007    else                                                    // 2 items (in slot1 and slot2)
1008    {
1009        data << uint8(2);
1010
1011        if(slot1 > slot2)
1012            std::swap(slot1,slot2);
1013
1014        AppendDisplayGuildBankSlot(data, tab, slot1);
1015        AppendDisplayGuildBankSlot(data, tab, slot2);
1016    }
1017
1018    for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
1019    {
1020        Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
1021        if(!player)
1022            continue;
1023
1024        if(!IsMemberHaveRights(itr->first,TabId,GUILD_BANK_RIGHT_VIEW_TAB))
1025            continue;
1026
1027        data.put<uint32>(rempos,uint32(GetMemberSlotWithdrawRem(player->GetGUIDLow(), TabId)));
1028
1029        player->GetSession()->SendPacket(&data);
1030    }
1031
1032    sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1033}
1034
1035void Guild::DisplayGuildBankContentUpdate(uint8 TabId, GuildItemPosCountVec const& slots)
1036{
1037    GuildBankTab const* tab = GetBankTab(TabId);
1038    if (!tab)
1039        return;
1040
1041    WorldPacket data(SMSG_GUILD_BANK_LIST,1200);
1042
1043    data << uint64(GetGuildBankMoney());
1044    data << uint8(TabId);
1045    // remaining slots for today
1046
1047    size_t rempos = data.wpos();
1048    data << uint32(0);                                      // will be filled later
1049    data << uint8(0);                                       // Tell client this is a tab content packet
1050
1051    data << uint8(slots.size());                            // updates count
1052
1053    for(GuildItemPosCountVec::const_iterator itr = slots.begin(); itr != slots.end(); ++itr)
1054        AppendDisplayGuildBankSlot(data, tab, itr->slot);
1055
1056    for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
1057    {
1058        Player *player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
1059        if(!player)
1060            continue;
1061
1062        if(!IsMemberHaveRights(itr->first,TabId,GUILD_BANK_RIGHT_VIEW_TAB))
1063            continue;
1064
1065        data.put<uint32>(rempos,uint32(GetMemberSlotWithdrawRem(player->GetGUIDLow(), TabId)));
1066
1067        player->GetSession()->SendPacket(&data);
1068    }
1069
1070    sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1071}
1072
1073Item* Guild::GetItem(uint8 TabId, uint8 SlotId)
1074{
1075    if (TabId >= m_TabListMap.size() || SlotId >= GUILD_BANK_MAX_SLOTS)
1076        return NULL;
1077    return m_TabListMap[TabId]->Slots[SlotId];
1078}
1079
1080// *************************************************
1081// Tab related
1082
1083void Guild::DisplayGuildBankTabsInfo(WorldSession *session)
1084{
1085    // Time to load bank if not already done
1086    if (!m_bankloaded)
1087        LoadGuildBankFromDB();
1088
1089    WorldPacket data(SMSG_GUILD_BANK_LIST, 500);
1090
1091    data << uint64(GetGuildBankMoney());
1092    data << uint8(0);                                       // TabInfo packet must be for TabId 0
1093    data << uint32(0xFFFFFFFF);                             // bit 9 must be set for this packet to work
1094    data << uint8(1);                                       // Tell Client this is a TabInfo packet
1095
1096    data << uint8(purchased_tabs);                          // here is the number of tabs
1097
1098    for(int i = 0; i < purchased_tabs; ++i)
1099    {
1100        data << m_TabListMap[i]->Name.c_str();
1101        data << m_TabListMap[i]->Icon.c_str();
1102    }
1103    data << uint8(0);                                       // Do not send tab content
1104    session->SendPacket(&data);
1105
1106    sLog.outDebug("WORLD: Sent (SMSG_GUILD_BANK_LIST)");
1107}
1108
1109void Guild::CreateNewBankTab()
1110{
1111    if (purchased_tabs >= GUILD_BANK_MAX_TABS)
1112        return;
1113
1114    ++purchased_tabs;
1115
1116    GuildBankTab* AnotherTab = new GuildBankTab;
1117    memset(AnotherTab->Slots, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*));
1118    m_TabListMap.resize(purchased_tabs);
1119    m_TabListMap[purchased_tabs-1] = AnotherTab;
1120
1121    CharacterDatabase.BeginTransaction();
1122    CharacterDatabase.PExecute("DELETE FROM guild_bank_tab WHERE guildid='%u' AND TabId='%u'", Id, uint32(purchased_tabs-1));
1123    CharacterDatabase.PExecute("INSERT INTO guild_bank_tab (guildid,TabId) VALUES ('%u','%u')", Id, uint32(purchased_tabs-1));
1124    CharacterDatabase.CommitTransaction();
1125}
1126
1127void Guild::SetGuildBankTabInfo(uint8 TabId, std::string Name, std::string Icon)
1128{
1129    if (TabId >= GUILD_BANK_MAX_TABS)
1130        return;
1131    if (TabId >= m_TabListMap.size())
1132        return;
1133
1134    if (!m_TabListMap[TabId])
1135        return;
1136
1137    if(m_TabListMap[TabId]->Name == Name && m_TabListMap[TabId]->Icon == Icon)
1138        return;
1139
1140    m_TabListMap[TabId]->Name = Name;
1141    m_TabListMap[TabId]->Icon = Icon;
1142
1143    CharacterDatabase.escape_string(Name);
1144    CharacterDatabase.escape_string(Icon);
1145    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));
1146}
1147
1148void Guild::CreateBankRightForTab(uint32 rankId, uint8 TabId)
1149{
1150    sLog.outDebug("CreateBankRightForTab. rank: %u, TabId: %u", rankId, uint32(TabId));
1151    if (rankId >= m_ranks.size() || TabId >= GUILD_BANK_MAX_TABS)
1152        return;
1153
1154    m_ranks[rankId].TabRight[TabId]=0;
1155    m_ranks[rankId].TabSlotPerDay[TabId]=0;
1156    CharacterDatabase.BeginTransaction();
1157    CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid = '%u' AND TabId = '%u' AND rid = '%u'", Id, uint32(TabId), rankId);
1158    CharacterDatabase.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid) VALUES ('%u','%u','%u')", Id, uint32(TabId), rankId);
1159    CharacterDatabase.CommitTransaction();
1160}
1161
1162uint32 Guild::GetBankRights(uint32 rankId, uint8 TabId) const
1163{
1164    if(rankId >= m_ranks.size() || TabId >= GUILD_BANK_MAX_TABS)
1165        return 0;
1166
1167    return m_ranks[rankId].TabRight[TabId];
1168}
1169
1170// *************************************************
1171// Guild bank loading/unloading related
1172
1173// This load should be called when the bank is first accessed by a guild member
1174void Guild::LoadGuildBankFromDB()
1175{
1176    if (m_bankloaded)
1177        return;
1178
1179    m_bankloaded = true;
1180    LoadGuildBankEventLogFromDB();
1181
1182    //                                                     0      1        2        3
1183    QueryResult *result = CharacterDatabase.PQuery("SELECT TabId, TabName, TabIcon, TabText FROM guild_bank_tab WHERE guildid='%u' ORDER BY TabId", Id);
1184    if(!result)
1185    {
1186        purchased_tabs = 0;
1187        return;
1188    }
1189
1190    m_TabListMap.resize(purchased_tabs);
1191    do
1192    {
1193        Field *fields = result->Fetch();
1194        uint8 TabId = fields[0].GetUInt8();
1195
1196        GuildBankTab *NewTab = new GuildBankTab;
1197        memset(NewTab->Slots, 0, GUILD_BANK_MAX_SLOTS * sizeof(Item*));
1198
1199        NewTab->Name = fields[1].GetCppString();
1200        NewTab->Icon = fields[2].GetCppString();
1201        NewTab->Text = fields[3].GetCppString();
1202
1203        m_TabListMap[TabId] = NewTab;
1204    }while( result->NextRow() );
1205
1206    delete result;
1207
1208    //                                        0      1       2          3
1209    result = CharacterDatabase.PQuery("SELECT TabId, SlotId, item_guid, item_entry FROM guild_bank_item WHERE guildid='%u' ORDER BY TabId", Id);
1210    if(!result)
1211        return;
1212
1213    do
1214    {
1215        Field *fields = result->Fetch();
1216        uint8 TabId = fields[0].GetUInt8();
1217        uint8 SlotId = fields[1].GetUInt8();
1218        uint32 ItemGuid = fields[2].GetUInt32();
1219        uint32 ItemEntry = fields[3].GetUInt32();
1220
1221        if (TabId >= purchased_tabs || TabId >= GUILD_BANK_MAX_TABS)
1222        {
1223            sLog.outError( "Guild::LoadGuildBankFromDB: Invalid tab for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry);
1224            continue;
1225        }
1226
1227        if (SlotId >= GUILD_BANK_MAX_SLOTS)
1228        {
1229            sLog.outError( "Guild::LoadGuildBankFromDB: Invalid slot for item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry);
1230            continue;
1231        }
1232
1233        ItemPrototype const *proto = objmgr.GetItemPrototype(ItemEntry);
1234
1235        if(!proto)
1236        {
1237            sLog.outError( "Guild::LoadGuildBankFromDB: Unknown item (GUID: %u id: #%u) in guild bank, skipped.", ItemGuid,ItemEntry);
1238            continue;
1239        }
1240
1241        Item *pItem = NewItemOrBag(proto);
1242        if(!pItem->LoadFromDB(ItemGuid, 0))
1243        {
1244            CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'", Id, uint32(TabId), uint32(SlotId));
1245            sLog.outError("Item GUID %u not found in item_instance, deleting from Guild Bank!", ItemGuid);
1246            delete pItem;
1247            continue;
1248        }
1249
1250        pItem->AddToWorld();
1251        m_TabListMap[TabId]->Slots[SlotId] = pItem;
1252    }while( result->NextRow() );
1253
1254    delete result;
1255}
1256
1257// This unload should be called when the last member of the guild gets offline
1258void Guild::UnloadGuildBank()
1259{
1260    if (!m_bankloaded)
1261        return;
1262    for (uint8 i = 0 ; i < purchased_tabs ; ++i )
1263    {
1264        for (uint8 j = 0 ; j < GUILD_BANK_MAX_SLOTS ; ++j)
1265        {
1266            if (m_TabListMap[i]->Slots[j])
1267            {
1268                m_TabListMap[i]->Slots[j]->RemoveFromWorld();
1269                delete m_TabListMap[i]->Slots[j];
1270            }
1271        }
1272        delete m_TabListMap[i];
1273    }
1274    m_TabListMap.clear();
1275
1276    UnloadGuildBankEventLog();
1277    m_bankloaded = false;
1278}
1279
1280// *************************************************
1281// Money deposit/withdraw related
1282
1283void Guild::SendMoneyInfo(WorldSession *session, uint32 LowGuid)
1284{
1285    WorldPacket data(MSG_GUILD_BANK_MONEY_WITHDRAWN, 4);
1286    data << uint32(GetMemberMoneyWithdrawRem(LowGuid));
1287    session->SendPacket(&data);
1288    sLog.outDebug("WORLD: Sent MSG_GUILD_BANK_MONEY_WITHDRAWN");
1289}
1290
1291bool Guild::MemberMoneyWithdraw(uint32 amount, uint32 LowGuid)
1292{
1293    uint32 MoneyWithDrawRight = GetMemberMoneyWithdrawRem(LowGuid);
1294
1295    if (MoneyWithDrawRight < amount || GetGuildBankMoney() < amount)
1296        return false;
1297
1298    SetBankMoney(GetGuildBankMoney()-amount);
1299
1300    if (MoneyWithDrawRight < WITHDRAW_MONEY_UNLIMITED)
1301    {
1302        MemberList::iterator itr = members.find(LowGuid);
1303        if (itr == members.end() )
1304            return false;
1305        itr->second.BankRemMoney -= amount;
1306        CharacterDatabase.PExecute("UPDATE guild_member SET BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'",
1307            itr->second.BankRemMoney, Id, LowGuid);
1308    }
1309    return true;
1310}
1311
1312void Guild::SetBankMoney(int64 money)
1313{
1314    if (money < 0)                                          // I don't know how this happens, it does!!
1315        money = 0;
1316    guildbank_money = money;
1317
1318    CharacterDatabase.PExecute("UPDATE guild SET BankMoney='" I64FMTD "' WHERE guildid='%u'", money, Id);
1319}
1320
1321// *************************************************
1322// Item per day and money per day related
1323
1324bool Guild::MemberItemWithdraw(uint8 TabId, uint32 LowGuid)
1325{
1326    uint32 SlotsWithDrawRight = GetMemberSlotWithdrawRem(LowGuid, TabId);
1327
1328    if (SlotsWithDrawRight == 0)
1329        return false;
1330
1331    if (SlotsWithDrawRight < WITHDRAW_SLOT_UNLIMITED)
1332    {
1333        MemberList::iterator itr = members.find(LowGuid);
1334        if (itr == members.end() )
1335            return false;
1336        --itr->second.BankRemSlotsTab[TabId];
1337        CharacterDatabase.PExecute("UPDATE guild_member SET BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'",
1338            uint32(TabId), itr->second.BankRemSlotsTab[TabId], Id, LowGuid);
1339    }
1340    return true;
1341}
1342
1343bool Guild::IsMemberHaveRights(uint32 LowGuid, uint8 TabId, uint32 rights) const
1344{
1345    MemberList::const_iterator itr = members.find(LowGuid);
1346    if (itr == members.end() )
1347        return false;
1348
1349    if (itr->second.RankId == GR_GUILDMASTER)
1350        return true;
1351
1352    return (GetBankRights(itr->second.RankId,TabId) & rights)==rights;
1353}
1354
1355uint32 Guild::GetMemberSlotWithdrawRem(uint32 LowGuid, uint8 TabId)
1356{
1357    MemberList::iterator itr = members.find(LowGuid);
1358    if (itr == members.end() )
1359        return 0;
1360
1361    if (itr->second.RankId == GR_GUILDMASTER)
1362        return WITHDRAW_SLOT_UNLIMITED;
1363
1364    if((GetBankRights(itr->second.RankId,TabId) & GUILD_BANK_RIGHT_VIEW_TAB)!=GUILD_BANK_RIGHT_VIEW_TAB)
1365        return 0;
1366
1367    uint32 curTime = uint32(time(NULL)/MINUTE);
1368    if (curTime - itr->second.BankResetTimeTab[TabId] >= 24*HOUR/MINUTE)
1369    {
1370        itr->second.BankResetTimeTab[TabId] = curTime;
1371        itr->second.BankRemSlotsTab[TabId] = GetBankSlotPerDay(itr->second.RankId, TabId);
1372        CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeTab%u='%u',BankRemSlotsTab%u='%u' WHERE guildid='%u' AND guid='%u'",
1373            uint32(TabId), itr->second.BankResetTimeTab[TabId], uint32(TabId), itr->second.BankRemSlotsTab[TabId], Id, LowGuid);
1374    }
1375    return itr->second.BankRemSlotsTab[TabId];
1376}
1377
1378uint32 Guild::GetMemberMoneyWithdrawRem(uint32 LowGuid)
1379{
1380    MemberList::iterator itr = members.find(LowGuid);
1381    if (itr == members.end() )
1382        return 0;
1383
1384    if (itr->second.RankId == GR_GUILDMASTER)
1385        return WITHDRAW_MONEY_UNLIMITED;
1386
1387    uint32 curTime = uint32(time(NULL)/MINUTE);             // minutes
1388                                                            // 24 hours
1389    if (curTime > itr->second.BankResetTimeMoney + 24*HOUR/MINUTE)
1390    {
1391        itr->second.BankResetTimeMoney = curTime;
1392        itr->second.BankRemMoney = GetBankMoneyPerDay(itr->second.RankId);
1393        CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeMoney='%u',BankRemMoney='%u' WHERE guildid='%u' AND guid='%u'",
1394            itr->second.BankResetTimeMoney, itr->second.BankRemMoney, Id, LowGuid);
1395    }
1396    return itr->second.BankRemMoney;
1397}
1398
1399void Guild::SetBankMoneyPerDay(uint32 rankId, uint32 money)
1400{
1401    if (rankId >= m_ranks.size())
1402        return;
1403
1404    if (rankId == GR_GUILDMASTER)
1405        money = WITHDRAW_MONEY_UNLIMITED;
1406
1407    m_ranks[rankId].BankMoneyPerDay = money;
1408
1409    for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
1410        if (itr->second.RankId == rankId)
1411            itr->second.BankResetTimeMoney = 0;
1412
1413    CharacterDatabase.PExecute("UPDATE guild_rank SET BankMoneyPerDay='%u' WHERE rid='%u' AND guildid='%u'", money, (rankId+1), Id);
1414    CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeMoney='0' WHERE guildid='%u' AND rank='%u'", Id, rankId);
1415}
1416
1417void Guild::SetBankRightsAndSlots(uint32 rankId, uint8 TabId, uint32 right, uint32 nbSlots, bool db)
1418{
1419    if(rankId >= m_ranks.size() ||
1420        TabId >= GUILD_BANK_MAX_TABS ||
1421        TabId >= purchased_tabs)
1422        return;
1423
1424    if (rankId == GR_GUILDMASTER)
1425    {
1426        nbSlots = WITHDRAW_SLOT_UNLIMITED;
1427        right = GUILD_BANK_RIGHT_FULL;
1428    }
1429
1430    m_ranks[rankId].TabSlotPerDay[TabId]=nbSlots;
1431    m_ranks[rankId].TabRight[TabId]=right;
1432
1433    if (db)
1434    {
1435        for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
1436            if (itr->second.RankId == rankId)
1437                for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
1438                    itr->second.BankResetTimeTab[i] = 0;
1439
1440        CharacterDatabase.PExecute("DELETE FROM guild_bank_right WHERE guildid='%u' AND TabId='%u' AND rid='%u'", Id, uint32(TabId), rankId);
1441        CharacterDatabase.PExecute("INSERT INTO guild_bank_right (guildid,TabId,rid,gbright,SlotPerDay) VALUES "
1442            "('%u','%u','%u','%u','%u')", Id, uint32(TabId), rankId, m_ranks[rankId].TabRight[TabId], m_ranks[rankId].TabSlotPerDay[TabId]);
1443        CharacterDatabase.PExecute("UPDATE guild_member SET BankResetTimeTab%u='0' WHERE guildid='%u' AND rank='%u'", uint32(TabId), Id, rankId);
1444    }
1445}
1446
1447uint32 Guild::GetBankMoneyPerDay(uint32 rankId)
1448{
1449    if(rankId >= m_ranks.size())
1450        return 0;
1451
1452    if (rankId == GR_GUILDMASTER)
1453        return WITHDRAW_MONEY_UNLIMITED;
1454    return m_ranks[rankId].BankMoneyPerDay;
1455}
1456
1457uint32 Guild::GetBankSlotPerDay(uint32 rankId, uint8 TabId)
1458{
1459    if(rankId >= m_ranks.size() || TabId >= GUILD_BANK_MAX_TABS)
1460        return 0;
1461
1462    if (rankId == GR_GUILDMASTER)
1463        return WITHDRAW_SLOT_UNLIMITED;
1464    return m_ranks[rankId].TabSlotPerDay[TabId];
1465}
1466
1467// *************************************************
1468// Rights per day related
1469
1470void Guild::LoadBankRightsFromDB(uint32 GuildId)
1471{
1472    //                                                     0      1    2        3
1473    QueryResult *result = CharacterDatabase.PQuery("SELECT TabId, rid, gbright, SlotPerDay FROM guild_bank_right WHERE guildid = '%u' ORDER BY TabId", GuildId);
1474
1475    if(!result)
1476        return;
1477
1478    do
1479    {
1480        Field *fields = result->Fetch();
1481        uint8 TabId = fields[0].GetUInt8();
1482        uint32 rankId = fields[1].GetUInt32();
1483        uint16 right = fields[2].GetUInt16();
1484        uint16 SlotPerDay = fields[3].GetUInt16();
1485
1486        SetBankRightsAndSlots(rankId, TabId, right, SlotPerDay, false);
1487
1488    }while( result->NextRow() );
1489    delete result;
1490
1491    return;
1492}
1493
1494// *************************************************
1495// Bank log related
1496
1497void Guild::LoadGuildBankEventLogFromDB()
1498{
1499    // We can't add a limit as in Guild::LoadGuildEventLogFromDB since we fetch both money and bank log and know nothing about the composition
1500    //                                                     0        1         2      3           4            5               6          7
1501    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);
1502    if(!result)
1503        return;
1504
1505    do
1506    {
1507        Field *fields = result->Fetch();
1508        GuildBankEvent *NewEvent = new GuildBankEvent;
1509
1510        NewEvent->LogGuid = fields[0].GetUInt32();
1511        NewEvent->LogEntry = fields[1].GetUInt8();
1512        uint8 TabId = fields[2].GetUInt8();
1513        NewEvent->PlayerGuid = fields[3].GetUInt32();
1514        NewEvent->ItemOrMoney = fields[4].GetUInt32();
1515        NewEvent->ItemStackCount = fields[5].GetUInt8();
1516        NewEvent->DestTabId = fields[6].GetUInt8();
1517        NewEvent->TimeStamp = fields[7].GetUInt64();
1518
1519        if (TabId >= GUILD_BANK_MAX_TABS)
1520        {
1521            sLog.outError( "Guild::LoadGuildBankEventLogFromDB: Invalid tabid '%u' for guild bank log entry (guild: '%s', LogGuid: %u), skipped.", TabId, GetName().c_str(), NewEvent->LogGuid);
1522            delete NewEvent;
1523            continue;
1524        }
1525        if (NewEvent->isMoneyEvent() && m_GuildBankEventLog_Money.size() >= GUILD_BANK_MAX_LOGS
1526                || m_GuildBankEventLog_Item[TabId].size() >= GUILD_BANK_MAX_LOGS)
1527        {
1528            delete NewEvent;
1529            continue;
1530        }
1531        if (NewEvent->isMoneyEvent())
1532            m_GuildBankEventLog_Money.push_front(NewEvent);
1533        else
1534            m_GuildBankEventLog_Item[TabId].push_front(NewEvent);
1535
1536    }while( result->NextRow() );
1537    delete result;
1538
1539    // Check lists size in case to many event entries in db for a tab or for money
1540    // This cases can happen only if a crash occured somewhere and table has too many log entries
1541    if (!m_GuildBankEventLog_Money.empty())
1542    {
1543        CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid=%u AND LogGuid < %u",
1544            Id, m_GuildBankEventLog_Money.front()->LogGuid);
1545    }
1546    for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
1547    {
1548        if (!m_GuildBankEventLog_Item[i].empty())
1549        {
1550            CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid=%u AND LogGuid < %u",
1551                Id, m_GuildBankEventLog_Item[i].front()->LogGuid);
1552        }
1553    }
1554}
1555
1556void Guild::UnloadGuildBankEventLog()
1557{
1558    GuildBankEvent *EventLogEntry;
1559    if( !m_GuildBankEventLog_Money.empty() )
1560    {
1561        do
1562        {
1563            EventLogEntry = *(m_GuildBankEventLog_Money.begin());
1564            m_GuildBankEventLog_Money.pop_front();
1565            delete EventLogEntry;
1566        }while( !m_GuildBankEventLog_Money.empty() );
1567    }
1568
1569    for (int i = 0; i < GUILD_BANK_MAX_TABS; ++i)
1570    {
1571        if( !m_GuildBankEventLog_Item[i].empty() )
1572        {
1573            do
1574            {
1575                EventLogEntry = *(m_GuildBankEventLog_Item[i].begin());
1576                m_GuildBankEventLog_Item[i].pop_front();
1577                delete EventLogEntry;
1578            }while( !m_GuildBankEventLog_Item[i].empty() );
1579        }
1580    }
1581}
1582
1583void Guild::DisplayGuildBankLogs(WorldSession *session, uint8 TabId)
1584{
1585    if (TabId > GUILD_BANK_MAX_TABS)
1586        return;
1587
1588    if (TabId == GUILD_BANK_MAX_TABS)
1589    {
1590        // Here we display money logs
1591        WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, m_GuildBankEventLog_Money.size()*(4*4+1)+1+1);
1592        data << uint8(TabId);                               // Here GUILD_BANK_MAX_TABS
1593        data << uint8(m_GuildBankEventLog_Money.size());    // number of log entries
1594        for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Money.begin(); itr != m_GuildBankEventLog_Money.end(); ++itr)
1595        {
1596            data << uint8((*itr)->LogEntry);
1597            data << uint64(MAKE_NEW_GUID((*itr)->PlayerGuid,0,HIGHGUID_PLAYER));
1598            data << uint32((*itr)->ItemOrMoney);
1599            data << uint32(time(NULL)-(*itr)->TimeStamp);
1600        }
1601        session->SendPacket(&data);
1602    }
1603    else
1604    {
1605        // here we display current tab logs
1606        WorldPacket data(MSG_GUILD_BANK_LOG_QUERY, m_GuildBankEventLog_Item[TabId].size()*(4*4+1+1)+1+1);
1607        data << uint8(TabId);                               // Here a real Tab Id
1608                                                            // number of log entries
1609        data << uint8(m_GuildBankEventLog_Item[TabId].size());
1610        for (GuildBankEventLog::const_iterator itr = m_GuildBankEventLog_Item[TabId].begin(); itr != m_GuildBankEventLog_Item[TabId].end(); ++itr)
1611        {
1612            data << uint8((*itr)->LogEntry);
1613            data << uint64(MAKE_NEW_GUID((*itr)->PlayerGuid,0,HIGHGUID_PLAYER));
1614            data << uint32((*itr)->ItemOrMoney);
1615            data << uint8((*itr)->ItemStackCount);
1616            if ((*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM || (*itr)->LogEntry == GUILD_BANK_LOG_MOVE_ITEM2)
1617                data << uint8((*itr)->DestTabId);           // moved tab
1618            data << uint32(time(NULL)-(*itr)->TimeStamp);
1619        }
1620        session->SendPacket(&data);
1621    }
1622    sLog.outDebug("WORLD: Sent (MSG_GUILD_BANK_LOG_QUERY)");
1623}
1624
1625void Guild::LogBankEvent(uint8 LogEntry, uint8 TabId, uint32 PlayerGuidLow, uint32 ItemOrMoney, uint8 ItemStackCount, uint8 DestTabId)
1626{
1627    GuildBankEvent *NewEvent = new GuildBankEvent;
1628
1629    NewEvent->LogGuid = LogMaxGuid++;
1630    NewEvent->LogEntry = LogEntry;
1631    NewEvent->PlayerGuid = PlayerGuidLow;
1632    NewEvent->ItemOrMoney = ItemOrMoney;
1633    NewEvent->ItemStackCount = ItemStackCount;
1634    NewEvent->DestTabId = DestTabId;
1635    NewEvent->TimeStamp = uint32(time(NULL));
1636
1637    if (NewEvent->isMoneyEvent())
1638    {
1639        if (m_GuildBankEventLog_Money.size() > GUILD_BANK_MAX_LOGS)
1640        {
1641            GuildBankEvent *OldEvent = *(m_GuildBankEventLog_Money.begin());
1642            m_GuildBankEventLog_Money.pop_front();
1643            CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, OldEvent->LogGuid);
1644            delete OldEvent;
1645        }
1646        m_GuildBankEventLog_Money.push_back(NewEvent);
1647    }
1648    else
1649    {
1650        if (m_GuildBankEventLog_Item[TabId].size() > GUILD_BANK_MAX_LOGS)
1651        {
1652            GuildBankEvent *OldEvent = *(m_GuildBankEventLog_Item[TabId].begin());
1653            m_GuildBankEventLog_Item[TabId].pop_front();
1654            CharacterDatabase.PExecute("DELETE FROM guild_bank_eventlog WHERE guildid='%u' AND LogGuid='%u'", Id, OldEvent->LogGuid);
1655            delete OldEvent;
1656        }
1657        m_GuildBankEventLog_Item[TabId].push_back(NewEvent);
1658    }
1659    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 "')",
1660        Id, NewEvent->LogGuid, uint32(NewEvent->LogEntry), uint32(TabId), NewEvent->PlayerGuid, NewEvent->ItemOrMoney, uint32(NewEvent->ItemStackCount), uint32(NewEvent->DestTabId), NewEvent->TimeStamp);
1661}
1662
1663// This will renum guids used at load to prevent always going up until infinit
1664void Guild::RenumBankLogs()
1665{
1666    QueryResult *result = CharacterDatabase.PQuery("SELECT Min(LogGuid), Max(LogGuid) FROM guild_bank_eventlog WHERE guildid = %u", Id);
1667    if(!result)
1668        return;
1669
1670    Field *fields = result->Fetch();
1671    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");
1672    LogMaxGuid = fields[1].GetUInt32()+1;
1673    delete result;
1674}
1675
1676bool Guild::AddGBankItemToDB(uint32 GuildId, uint32 BankTab , uint32 BankTabSlot , uint32 GUIDLow, uint32 Entry )
1677{
1678    CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid = '%u' AND TabId = '%u'AND SlotId = '%u'", GuildId, BankTab, BankTabSlot);
1679    CharacterDatabase.PExecute("INSERT INTO guild_bank_item (guildid,TabId,SlotId,item_guid,item_entry) "
1680        "VALUES ('%u', '%u', '%u', '%u', '%u')", GuildId, BankTab, BankTabSlot, GUIDLow, Entry);
1681    return true;
1682}
1683
1684void Guild::AppendDisplayGuildBankSlot( WorldPacket& data, GuildBankTab const *tab, int slot )
1685{
1686    Item *pItem = tab->Slots[slot];
1687    uint32 entry = pItem ? pItem->GetEntry() : 0;
1688
1689    data << uint8(slot);
1690    data << uint32(entry);
1691    if (entry)
1692    {
1693        // random item property id +8
1694        data << (uint32) pItem->GetItemRandomPropertyId();
1695        if (pItem->GetItemRandomPropertyId())
1696            // SuffixFactor +4
1697            data << (uint32) pItem->GetItemSuffixFactor();
1698        // +12 // ITEM_FIELD_STACK_COUNT
1699        data << uint8(pItem->GetCount());
1700        data << uint32(0);                                  // +16 // Unknown value
1701        data << uint8(0);                                   // unknown 2.4.2
1702        if (uint32 Enchant0 = pItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT))
1703        {
1704            data << uint8(1);                               // number of enchantments (max 3) why max 3?
1705            data << uint8(PERM_ENCHANTMENT_SLOT);           // enchantment slot (range: 0:2)
1706            data << uint32(Enchant0);                       // enchantment id
1707        }
1708        else
1709            data << uint8(0);                               // no enchantments (0)
1710    }
1711}
1712
1713Item* Guild::StoreItem(uint8 tabId, GuildItemPosCountVec const& dest, Item* pItem )
1714{
1715    if( !pItem )
1716        return NULL;
1717
1718    Item* lastItem = pItem;
1719
1720    for(GuildItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end(); )
1721    {
1722        uint8 slot = itr->slot;
1723        uint32 count = itr->count;
1724
1725        ++itr;
1726
1727        if(itr == dest.end())
1728        {
1729            lastItem = _StoreItem(tabId,slot,pItem,count,false);
1730            break;
1731        }
1732
1733        lastItem = _StoreItem(tabId,slot,pItem,count,true);
1734    }
1735
1736    return lastItem;
1737}
1738
1739// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
1740Item* Guild::_StoreItem( uint8 tab, uint8 slot, Item *pItem, uint32 count, bool clone )
1741{
1742    if( !pItem )
1743        return NULL;
1744
1745    sLog.outDebug( "GUILD STORAGE: StoreItem tab = %u, slot = %u, item = %u, count = %u", tab, slot, pItem->GetEntry(), count);
1746
1747    Item* pItem2 = m_TabListMap[tab]->Slots[slot];
1748
1749    if( !pItem2 )
1750    {
1751        if(clone)
1752            pItem = pItem->CloneItem(count);
1753        else
1754            pItem->SetCount(count);
1755
1756        if(!pItem)
1757            return NULL;
1758
1759        m_TabListMap[tab]->Slots[slot] = pItem;
1760
1761        pItem->SetUInt64Value(ITEM_FIELD_CONTAINED, 0);
1762        pItem->SetUInt64Value(ITEM_FIELD_OWNER, 0);
1763        AddGBankItemToDB(GetId(), tab, slot, pItem->GetGUIDLow(), pItem->GetEntry());
1764        pItem->FSetState(ITEM_NEW);
1765        pItem->SaveToDB();                                  // not in onventory and can be save standalone
1766
1767        return pItem;
1768    }
1769    else
1770    {
1771        pItem2->SetCount( pItem2->GetCount() + count );
1772        pItem2->FSetState(ITEM_CHANGED);
1773        pItem2->SaveToDB();                                 // not in onventory and can be save standalone
1774
1775        if(!clone)
1776        {
1777            pItem->RemoveFromWorld();
1778            pItem->DeleteFromDB();
1779            delete pItem;
1780        }
1781
1782        return pItem2;
1783    }
1784}
1785
1786void Guild::RemoveItem(uint8 tab, uint8 slot )
1787{
1788    m_TabListMap[tab]->Slots[slot] = NULL;
1789    CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE guildid='%u' AND TabId='%u' AND SlotId='%u'",
1790        GetId(), uint32(tab), uint32(slot));
1791}
1792
1793uint8 Guild::_CanStoreItem_InSpecificSlot( uint8 tab, uint8 slot, GuildItemPosCountVec &dest, uint32& count, bool swap, Item* pSrcItem ) const
1794{
1795    Item* pItem2 = m_TabListMap[tab]->Slots[slot];
1796
1797    // ignore move item (this slot will be empty at move)
1798    if(pItem2==pSrcItem)
1799        pItem2 = NULL;
1800
1801    uint32 need_space;
1802
1803    // empty specific slot - check item fit to slot
1804    if( !pItem2 || swap )
1805    {
1806        // non empty stack with space
1807        need_space = pSrcItem->GetMaxStackCount();
1808    }
1809    // non empty slot, check item type
1810    else
1811    {
1812        // check item type
1813        if(pItem2->GetEntry() != pSrcItem->GetEntry())
1814            return EQUIP_ERR_ITEM_CANT_STACK;
1815
1816        // check free space
1817        if(pItem2->GetCount() >= pSrcItem->GetMaxStackCount())
1818            return EQUIP_ERR_ITEM_CANT_STACK;
1819
1820        need_space = pSrcItem->GetMaxStackCount() - pItem2->GetCount();
1821    }
1822
1823    if(need_space > count)
1824        need_space = count;
1825
1826    GuildItemPosCount newPosition = GuildItemPosCount(slot,need_space);
1827    if(!newPosition.isContainedIn(dest))
1828    {
1829        dest.push_back(newPosition);
1830        count -= need_space;
1831    }
1832
1833    return EQUIP_ERR_OK;
1834}
1835
1836uint8 Guild::_CanStoreItem_InTab( uint8 tab, GuildItemPosCountVec &dest, uint32& count, bool merge, Item* pSrcItem, uint8 skip_slot ) const
1837{
1838    for(uint32 j = 0; j < GUILD_BANK_MAX_SLOTS; j++)
1839    {
1840        // skip specific slot already processed in first called _CanStoreItem_InSpecificSlot
1841        if(j==skip_slot)
1842            continue;
1843
1844        Item* pItem2 = m_TabListMap[tab]->Slots[j];
1845
1846        // ignore move item (this slot will be empty at move)
1847        if(pItem2==pSrcItem)
1848            pItem2 = NULL;
1849
1850        // if merge skip empty, if !merge skip non-empty
1851        if((pItem2!=NULL)!=merge)
1852            continue;
1853
1854        if( pItem2 )
1855        {
1856            if(pItem2->GetEntry() == pSrcItem->GetEntry() && pItem2->GetCount() < pSrcItem->GetMaxStackCount() )
1857            {
1858                uint32 need_space = pSrcItem->GetMaxStackCount() - pItem2->GetCount();
1859                if(need_space > count)
1860                    need_space = count;
1861
1862                GuildItemPosCount newPosition = GuildItemPosCount(j,need_space);
1863                if(!newPosition.isContainedIn(dest))
1864                {
1865                    dest.push_back(newPosition);
1866                    count -= need_space;
1867
1868                    if(count==0)
1869                        return EQUIP_ERR_OK;
1870                }
1871            }
1872        }
1873        else
1874        {
1875            uint32 need_space = pSrcItem->GetMaxStackCount();
1876            if(need_space > count)
1877                need_space = count;
1878
1879            GuildItemPosCount newPosition = GuildItemPosCount(j,need_space);
1880            if(!newPosition.isContainedIn(dest))
1881            {
1882                dest.push_back(newPosition);
1883                count -= need_space;
1884
1885                if(count==0)
1886                    return EQUIP_ERR_OK;
1887            }
1888        }
1889    }
1890    return EQUIP_ERR_OK;
1891}
1892
1893uint8 Guild::CanStoreItem( uint8 tab, uint8 slot, GuildItemPosCountVec &dest, uint32 count, Item *pItem, bool swap ) const
1894{
1895    sLog.outDebug( "GUILD STORAGE: CanStoreItem tab = %u, slot = %u, item = %u, count = %u", tab, slot, pItem->GetEntry(), count);
1896
1897    if(count > pItem->GetCount())
1898        return EQUIP_ERR_COULDNT_SPLIT_ITEMS;
1899
1900    if(pItem->IsSoulBound())
1901        return EQUIP_ERR_CANT_DROP_SOULBOUND;
1902
1903    // in specific slot
1904    if( slot != NULL_SLOT )
1905    {
1906        uint8 res = _CanStoreItem_InSpecificSlot(tab,slot,dest,count,swap,pItem);
1907        if(res!=EQUIP_ERR_OK)
1908            return res;
1909
1910        if(count==0)
1911            return EQUIP_ERR_OK;
1912    }
1913
1914    // not specific slot or have spece for partly store only in specific slot
1915
1916    // search stack in tab for merge to
1917    if( pItem->GetMaxStackCount() > 1 )
1918    {
1919        uint8 res = _CanStoreItem_InTab(tab,dest,count,true,pItem,slot);
1920        if(res!=EQUIP_ERR_OK)
1921            return res;
1922
1923        if(count==0)
1924            return EQUIP_ERR_OK;
1925    }
1926
1927    // search free slot in bag for place to
1928    uint8 res = _CanStoreItem_InTab(tab,dest,count,false,pItem,slot);
1929    if(res!=EQUIP_ERR_OK)
1930        return res;
1931
1932    if(count==0)
1933        return EQUIP_ERR_OK;
1934
1935    return EQUIP_ERR_BANK_FULL;
1936}
1937
1938void Guild::SetGuildBankTabText(uint8 TabId, std::string text)
1939{
1940    if (TabId >= GUILD_BANK_MAX_TABS)
1941        return;
1942    if (TabId >= m_TabListMap.size())
1943        return;
1944    if (!m_TabListMap[TabId])
1945        return;
1946
1947    if(m_TabListMap[TabId]->Text==text)
1948        return;
1949
1950    utf8truncate(text,500);                                 // DB and client size limitation
1951
1952    m_TabListMap[TabId]->Text = text;
1953
1954    CharacterDatabase.escape_string(text);
1955    CharacterDatabase.PExecute("UPDATE guild_bank_tab SET TabText='%s' WHERE guildid='%u' AND TabId='%u'", text.c_str(), Id, uint32(TabId));
1956}
1957
1958void Guild::SendGuildBankTabText(WorldSession *session, uint8 TabId)
1959{
1960    if (TabId > GUILD_BANK_MAX_TABS)
1961        return;
1962
1963    GuildBankTab const *tab = GetBankTab(TabId);
1964    if (!tab)
1965        return;
1966
1967    WorldPacket data(MSG_QUERY_GUILD_BANK_TEXT, 1+tab->Text.size()+1);
1968    data << uint8(TabId);
1969    data << tab->Text;
1970    session->SendPacket(&data);
1971}
1972
1973bool GuildItemPosCount::isContainedIn(GuildItemPosCountVec const &vec) const
1974{
1975    for(GuildItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end();++itr)
1976        if(itr->slot == this->slot)
1977            return true;
1978
1979    return false;
1980}
1981
Note: See TracBrowser for help on using the browser.