TrinityCore
Loading...
Searching...
No Matches
Guild.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Guild.h"
19#include "AccountMgr.h"
20#include "Bag.h"
21#include "CalendarMgr.h"
22#include "CalendarPackets.h"
23#include "CharacterCache.h"
24#include "Chat.h"
25#include "Config.h"
26#include "DatabaseEnv.h"
27#include "GameTime.h"
28#include "GuildMgr.h"
29#include "GuildPackets.h"
30#include "Language.h"
31#include "Log.h"
32#include "ObjectAccessor.h"
33#include "ObjectMgr.h"
34#include "Opcodes.h"
35#include "Player.h"
36#include "ScriptMgr.h"
37#include "SocialMgr.h"
38#include "World.h"
39#include "WorldSession.h"
40#include <boost/iterator/counting_iterator.hpp>
41
42size_t const MAX_GUILD_BANK_TAB_TEXT_LEN = 500;
43
45
46// only used in logs
48{
49 switch (event)
50 {
51 case GE_PROMOTION:
52 return "Member promotion";
53 case GE_DEMOTION:
54 return "Member demotion";
55 case GE_MOTD:
56 return "Guild MOTD";
57 case GE_JOINED:
58 return "Member joined";
59 case GE_LEFT:
60 return "Member left";
61 case GE_REMOVED:
62 return "Member removed";
63 case GE_LEADER_IS:
64 return "Leader is";
66 return "Leader changed";
67 case GE_DISBANDED:
68 return "Guild disbanded";
69 case GE_TABARDCHANGE:
70 return "Tabard change";
71 case GE_RANK_UPDATED:
72 return "Rank updated";
73 case GE_RANK_DELETED:
74 return "Rank deleted";
75 case GE_SIGNED_ON:
76 return "Member signed on";
77 case GE_SIGNED_OFF:
78 return "Member signed off";
80 return "Bank bag slots changed";
82 return "Bank tab purchased";
84 return "Bank tab updated";
86 return "Bank money set";
88 return "Bank and money updated";
90 return "Bank tab text changed";
91 default:
92 break;
93 }
94 return "<None>";
95}
96
98{
99 // these prices are in gold units, not copper
100 static uint32 const tabPrices[GUILD_BANK_MAX_TABS] = { 100, 250, 500, 1000, 2500, 5000 };
102
103 return tabPrices[tabId];
104}
105
106void Guild::SendCommandResult(WorldSession* session, GuildCommandType type, GuildCommandError errCode, std::string_view param)
107{
109 resultPacket.Command = type;
110 resultPacket.Result = errCode;
111 resultPacket.Name = param;
112 session->SendPacket(resultPacket.Write());
113
114 TC_LOG_DEBUG("guild", "SMSG_GUILD_COMMAND_RESULT [{}]: Type: {}, code: {}, param: {}"
115 , session->GetPlayerInfo(), type, errCode, resultPacket.Name);
116}
117
119{
121 saveResponse.Error = int32(errCode);
122 session->SendPacket(saveResponse.Write());
123
124 TC_LOG_DEBUG("guild", "MSG_SAVE_GUILD_EMBLEM [{}] Code: {}", session->GetPlayerInfo(), errCode);
125}
126
127// LogHolder
128template <typename Entry>
132
133template <typename Entry> template <typename... Ts>
135{
136 Entry const& newEntry = m_log.emplace_front(std::forward<Ts>(args)...);
137 if (m_nextGUID == uint32(GUILD_EVENT_LOG_GUID_UNDEFINED))
138 m_nextGUID = newEntry.GetGUID();
139}
140
141template <typename Entry> template <typename... Ts>
143{
144 // Check max records limit
145 if (!CanInsert())
146 m_log.pop_front();
147
148 // Add event to list
149 Entry const& entry = m_log.emplace_back(std::forward<Ts>(args)...);
150 // Save to DB
151 entry.SaveToDB(trans);
152}
153
154template <typename Entry>
156{
157 // Next guid was not initialized. It means there are no records for this holder in DB yet.
158 // Start from the beginning.
159 if (m_nextGUID == uint32(GUILD_EVENT_LOG_GUID_UNDEFINED))
160 m_nextGUID = 0;
161 else
162 m_nextGUID = (m_nextGUID + 1) % m_maxRecords;
163 return m_nextGUID;
164}
165
166Guild::LogEntry::LogEntry(ObjectGuid::LowType guildId, uint32 guid) : m_guildId(guildId), m_guid(guid), m_timestamp(GameTime::GetGameTime()) { }
167
168// EventLogEntry
170{
172 stmt->setUInt32(0, m_guildId);
173 stmt->setUInt32(1, m_guid);
174 trans->Append(stmt);
175
176 uint8 index = 0;
177 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_EVENTLOG);
178 stmt->setUInt32( index, m_guildId);
179 stmt->setUInt32(++index, m_guid);
180 stmt->setUInt8 (++index, uint8(m_eventType));
181 stmt->setUInt32(++index, m_playerGuid1);
182 stmt->setUInt32(++index, m_playerGuid2);
183 stmt->setUInt8 (++index, m_newRank);
184 stmt->setUInt64(++index, m_timestamp);
185 trans->Append(stmt);
186}
187
189{
190 ObjectGuid playerGUID = ObjectGuid::Create<HighGuid::Player>(m_playerGuid1);
191 ObjectGuid otherGUID = ObjectGuid::Create<HighGuid::Player>(m_playerGuid2);
192
194 eventEntry.PlayerGUID = playerGUID;
195 eventEntry.OtherGUID = otherGUID;
196 eventEntry.TransactionType = uint8(m_eventType);
197 eventEntry.TransactionDate = uint32(GameTime::GetGameTime() - m_timestamp);
198 eventEntry.RankID = uint8(m_newRank);
199 packet.Entry.push_back(eventEntry);
200}
201
202// BankEventLogEntry
204{
205 uint8 index = 0;
206
208 stmt->setUInt32( index, m_guildId);
209 stmt->setUInt32(++index, m_guid);
210 stmt->setUInt8 (++index, m_bankTabId);
211 trans->Append(stmt);
212
213 index = 0;
214 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_BANK_EVENTLOG);
215 stmt->setUInt32( index, m_guildId);
216 stmt->setUInt32(++index, m_guid);
217 stmt->setUInt8 (++index, m_bankTabId);
218 stmt->setUInt8 (++index, uint8(m_eventType));
219 stmt->setUInt32(++index, m_playerGuid);
220 stmt->setUInt32(++index, m_itemOrMoney);
221 stmt->setUInt16(++index, m_itemStackCount);
222 stmt->setUInt8 (++index, m_destTabId);
223 stmt->setUInt64(++index, m_timestamp);
224 trans->Append(stmt);
225}
226
228{
230 bankLogEntry.PlayerGUID = ObjectGuid::Create<HighGuid::Player>(m_playerGuid);
231 bankLogEntry.TimeOffset = int32(GameTime::GetGameTime() - m_timestamp);
232 bankLogEntry.EntryType = int8(m_eventType);
233
234 switch (m_eventType)
235 {
238 bankLogEntry.ItemID = int32(m_itemOrMoney);
239 bankLogEntry.Count = int32(m_itemStackCount);
240 break;
243 bankLogEntry.ItemID = int32(m_itemOrMoney);
244 bankLogEntry.Count = int32(m_itemStackCount);
245 bankLogEntry.OtherTab = int8(m_destTabId);
246 break;
247 default:
248 bankLogEntry.Money = uint32(m_itemOrMoney);
249 break;
250 }
251
252 packet.Entry.push_back(bankLogEntry);
253}
254
255// RankInfo
257{
258 m_rankId = fields[1].GetUInt8();
259 m_name = fields[2].GetString();
260 m_rights = fields[3].GetUInt32();
261 m_bankMoneyPerDay = fields[4].GetUInt32();
262 if (m_rankId == GR_GUILDMASTER) // Prevent loss of leader rights
263 m_rights |= GR_RIGHT_ALL;
264}
265
267{
269 stmt->setUInt32(0, m_guildId);
270 stmt->setUInt8 (1, m_rankId);
271 stmt->setString(2, m_name);
272 stmt->setUInt32(3, m_rights);
273 stmt->setUInt32(4, m_bankMoneyPerDay);
274 CharacterDatabase.ExecuteOrAppend(trans, stmt);
275}
276
278{
279 for (uint8 i = 0; i < tabs; ++i)
280 {
281 GuildBankRightsAndSlots& rightsAndSlots = m_bankTabRightsAndSlots[i];
282 if (rightsAndSlots.GetTabId() == i)
283 continue;
284
285 rightsAndSlots.SetTabId(i);
286 if (m_rankId == GR_GUILDMASTER)
287 rightsAndSlots.SetGuildMasterValues();
288
289 if (logOnCreate)
290 TC_LOG_ERROR("guild", "Guild {} has broken Tab {} for rank {}. Created default tab.", m_guildId, i, m_rankId);
291
293 stmt->setUInt32(0, m_guildId);
294 stmt->setUInt8(1, i);
295 stmt->setUInt8(2, m_rankId);
296 stmt->setUInt8(3, rightsAndSlots.GetRights());
297 stmt->setUInt32(4, rightsAndSlots.GetSlots());
298 trans->Append(stmt);
299 }
300}
301
302void Guild::RankInfo::SetName(std::string_view name)
303{
304 if (m_name == name)
305 return;
306
307 m_name = name;
308
310 stmt->setString(0, m_name);
311 stmt->setUInt8 (1, m_rankId);
312 stmt->setUInt32(2, m_guildId);
313 CharacterDatabase.Execute(stmt);
314}
315
317{
318 if (m_rankId == GR_GUILDMASTER) // Prevent loss of leader rights
319 rights = GR_RIGHT_ALL;
320
321 if (m_rights == rights)
322 return;
323
324 m_rights = rights;
325
327 stmt->setUInt32(0, m_rights);
328 stmt->setUInt8 (1, m_rankId);
329 stmt->setUInt32(2, m_guildId);
330 CharacterDatabase.Execute(stmt);
331}
332
334{
335 if (m_rankId == GR_GUILDMASTER) // Prevent loss of leader rights
337
338 if (m_bankMoneyPerDay == money)
339 return;
340
341 m_bankMoneyPerDay = money;
342
344 stmt->setUInt32(0, money);
345 stmt->setUInt8 (1, m_rankId);
346 stmt->setUInt32(2, m_guildId);
347 CharacterDatabase.Execute(stmt);
348}
349
351{
352 if (m_rankId == GR_GUILDMASTER) // Prevent loss of leader rights
353 rightsAndSlots.SetGuildMasterValues();
354
355 GuildBankRightsAndSlots& guildBR = m_bankTabRightsAndSlots[rightsAndSlots.GetTabId()];
356 guildBR = rightsAndSlots;
357
358 if (saveToDB)
359 {
361 stmt->setUInt32(0, m_guildId);
362 stmt->setUInt8 (1, guildBR.GetTabId());
363 stmt->setUInt8 (2, m_rankId);
364 stmt->setUInt8 (3, guildBR.GetRights());
365 stmt->setUInt32(4, guildBR.GetSlots());
366 CharacterDatabase.Execute(stmt);
367 }
368}
369
370// BankTab
371Guild::BankTab::BankTab(ObjectGuid::LowType guildId, uint8 tabId) : m_guildId(guildId), m_tabId(tabId)
372{ }
373
375{
376 m_name = fields[2].GetString();
377 m_icon = fields[3].GetString();
378 m_text = fields[4].GetString();
379}
380
382{
383 uint8 slotId = fields[13].GetUInt8();
384 ObjectGuid::LowType itemGuid = fields[14].GetUInt32();
385 uint32 itemEntry = fields[15].GetUInt32();
386 if (slotId >= GUILD_BANK_MAX_SLOTS)
387 {
388 TC_LOG_ERROR("guild", "Invalid slot for item (GUID: {}, id: {}) in guild bank, skipped.", itemGuid, itemEntry);
389 return false;
390 }
391
392 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry);
393 if (!proto)
394 {
395 TC_LOG_ERROR("guild", "Unknown item (GUID: {}, id: {}) in guild bank, skipped.", itemGuid, itemEntry);
396 return false;
397 }
398
399 Item* pItem = NewItemOrBag(proto);
400 if (!pItem->LoadFromDB(itemGuid, ObjectGuid::Empty, fields, itemEntry))
401 {
402 TC_LOG_ERROR("guild", "Item (GUID {}, id: {}) not found in item_instance, deleting from guild bank!", itemGuid, itemEntry);
403
405 stmt->setUInt32(0, m_guildId);
406 stmt->setUInt8 (1, m_tabId);
407 stmt->setUInt8 (2, slotId);
408 CharacterDatabase.Execute(stmt);
409
410 delete pItem;
411 return false;
412 }
413
414 pItem->AddToWorld();
415 m_items[slotId] = pItem;
416 return true;
417}
418
419// Deletes contents of the tab from the world (and from DB if necessary)
420void Guild::BankTab::Delete(CharacterDatabaseTransaction trans, bool removeItemsFromDB)
421{
422 for (uint8 slotId = 0; slotId < GUILD_BANK_MAX_SLOTS; ++slotId)
423 {
424 if (Item* pItem = m_items[slotId])
425 {
426 pItem->RemoveFromWorld();
427 if (removeItemsFromDB)
428 pItem->DeleteFromDB(trans);
429 delete pItem;
430 pItem = nullptr;
431 }
432 }
433}
434
435void Guild::BankTab::SetInfo(std::string_view name, std::string_view icon)
436{
437 if ((m_name == name) && (m_icon == icon))
438 return;
439
440 m_name = name;
441 m_icon = icon;
442
444 stmt->setString(0, m_name);
445 stmt->setString(1, m_icon);
446 stmt->setUInt32(2, m_guildId);
447 stmt->setUInt8 (3, m_tabId);
448 CharacterDatabase.Execute(stmt);
449}
450
451void Guild::BankTab::SetText(std::string_view text)
453 if (m_text == text)
454 return;
455
456 m_text = text;
457 utf8truncate(m_text, MAX_GUILD_BANK_TAB_TEXT_LEN); // DB and client size limitation
458
460 stmt->setString(0, m_text);
461 stmt->setUInt32(1, m_guildId);
462 stmt->setUInt8 (2, m_tabId);
463 CharacterDatabase.Execute(stmt);
464}
465
466// Sets/removes contents of specified slot.
467// If pItem == nullptr contents are removed.
469{
470 if (slotId >= GUILD_BANK_MAX_SLOTS)
471 return false;
472
473 m_items[slotId] = item;
474
476 stmt->setUInt32(0, m_guildId);
477 stmt->setUInt8 (1, m_tabId);
478 stmt->setUInt8 (2, slotId);
479 trans->Append(stmt);
480
481 if (item)
482 {
483 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_BANK_ITEM);
484 stmt->setUInt32(0, m_guildId);
485 stmt->setUInt8 (1, m_tabId);
486 stmt->setUInt8 (2, slotId);
487 stmt->setUInt32(3, item->GetGUID().GetCounter());
488 trans->Append(stmt);
489
492 item->FSetState(ITEM_NEW);
493 item->SaveToDB(trans); // Not in inventory and can be saved standalone
494 }
495
496 return true;
497}
498
499void Guild::BankTab::SendText(Guild const* guild, WorldSession* session) const
500{
502 textQuery.Tab = m_tabId;
503 textQuery.Text = m_text;
504
505 if (session)
506 {
507 TC_LOG_DEBUG("guild", "MSG_QUERY_GUILD_BANK_TEXT [{}]: Tabid: {}, Text: {}"
508 , session->GetPlayerInfo(), m_tabId, m_text);
509 session->SendPacket(textQuery.Write());
510 }
511 else
512 {
513 TC_LOG_DEBUG("guild", "MSG_QUERY_GUILD_BANK_TEXT [Broadcast]: Tabid: {}, Text: {}", m_tabId, m_text);
514 guild->BroadcastPacket(textQuery.Write());
515 }
516}
517
518// Member
520 m_guildId(guildId),
521 m_guid(guid),
522 m_zoneId(0),
523 m_level(0),
524 m_class(0),
525 m_gender(0),
527 m_logoutTime(GameTime::GetGameTime()),
528 m_accountId(0),
529 m_rankId(rankId)
530{}
531
533{
534 m_name = player->GetName();
535 m_level = player->GetLevel();
536 m_class = player->GetClass();
537 m_gender = player->GetNativeGender();
538 m_zoneId = player->GetZoneId();
539 m_accountId = player->GetSession()->GetAccountId();
540}
541
542void Guild::Member::SetStats(std::string_view name, uint8 level, uint8 _class, uint8 gender, uint32 zoneId, uint32 accountId)
543{
544 m_name = name;
545 m_level = level;
546 m_class = _class;
547 m_gender = gender;
548 m_zoneId = zoneId;
549 m_accountId = accountId;
550}
551
552void Guild::Member::SetPublicNote(std::string_view publicNote)
553{
554 if (m_publicNote == publicNote)
555 return;
556
557 m_publicNote = publicNote;
558
560 stmt->setString(0, m_publicNote);
561 stmt->setUInt32(1, m_guid.GetCounter());
562 CharacterDatabase.Execute(stmt);
563}
564
565void Guild::Member::SetOfficerNote(std::string_view officerNote)
566{
567 if (m_officerNote == officerNote)
568 return;
569
570 m_officerNote = officerNote;
571
573 stmt->setString(0, m_officerNote);
574 stmt->setUInt32(1, m_guid.GetCounter());
575 CharacterDatabase.Execute(stmt);
576}
577
579{
580 m_rankId = newRank;
581
582 // Update rank information in player's field, if he is online.
583 if (Player* player = FindConnectedPlayer())
584 player->SetGuildRank(newRank);
585
587 stmt->setUInt8 (0, newRank);
588 stmt->setUInt32(1, m_guid.GetCounter());
589 CharacterDatabase.ExecuteOrAppend(trans, stmt);
590}
591
593{
594 m_logoutTime = GameTime::GetGameTime();
595}
596
598{
600 stmt->setUInt32(0, m_guildId);
601 stmt->setUInt32(1, m_guid.GetCounter());
602 stmt->setUInt8 (2, m_rankId);
603 stmt->setString(3, m_publicNote);
604 stmt->setString(4, m_officerNote);
605 CharacterDatabase.ExecuteOrAppend(trans, stmt);
606}
607
608// Loads member's data from database.
609// If member has broken fields (level, class) returns false.
610// In this case member has to be removed from guild.
612{
613 m_publicNote = fields[3].GetString();
614 m_officerNote = fields[4].GetString();
615
616 for (uint8 i = 0; i <= GUILD_BANK_MAX_TABS; ++i)
617 m_bankWithdraw[i] = fields[5 + i].GetUInt32();
618
619 SetStats(fields[12].GetString(),
620 fields[13].GetUInt8(), // characters.level
621 fields[14].GetUInt8(), // characters.class
622 fields[15].GetUInt8(), // characters.gender
623 fields[16].GetUInt16(), // characters.zone
624 fields[17].GetUInt32()); // characters.account
625 m_logoutTime = fields[18].GetUInt32(); // characters.logout_time
626
627 if (!CheckStats())
628 return false;
629
630 if (!m_zoneId)
631 {
632 TC_LOG_DEBUG("guild", "{} has broken zone-data", m_guid.ToString());
633 m_zoneId = Player::GetZoneIdFromDB(m_guid);
634 }
635
636 ResetFlags();
637 return true;
638}
639
640// Validate player fields. Returns false if corrupted fields are found.
642{
643 if (m_level < 1)
644 {
645 TC_LOG_ERROR("guild", "{} has a broken data in field `characters`.`level`, deleting him from guild!", m_guid.ToString());
646 return false;
647 }
648
649 if (m_class < CLASS_WARRIOR || m_class >= MAX_CLASSES)
650 {
651 TC_LOG_ERROR("guild", "{} has a broken data in field `characters`.`class`, deleting him from guild!", m_guid.ToString());
652 return false;
653 }
654 return true;
655}
656
658{
659 return ObjectAccessor::FindPlayer(m_guid);
660}
661
666
667// Decreases amount of money/slots left for today.
668// If (tabId == GUILD_BANK_MAX_TABS) decrease money amount.
669// Otherwise decrease remaining items amount for specified tab.
671{
672 m_bankWithdraw[tabId] += amount;
673
675 stmt->setUInt32(0, m_guid.GetCounter());
676 for (uint8 i = 0; i <= GUILD_BANK_MAX_TABS;)
677 {
678 uint32 withdraw = m_bankWithdraw[i++];
679 stmt->setUInt32(i, withdraw);
680 }
681
682 CharacterDatabase.ExecuteOrAppend(trans, stmt);
683}
684
686{
687 for (uint8 tabId = 0; tabId <= GUILD_BANK_MAX_TABS; ++tabId)
688 m_bankWithdraw[tabId] = 0;
689}
690
691// Get amount of money/slots left for today.
692// If (tabId == GUILD_BANK_MAX_TABS) return money amount.
693// Otherwise return remaining items amount for specified tab.
695{
696 // Guild master has unlimited amount.
697 if (IsRank(GR_GUILDMASTER))
699
700 return m_bankWithdraw[tabId];
701}
702
703// EmblemInfo
705{
706 m_style = packet.EStyle;
707 m_color = packet.EColor;
708 m_borderStyle = packet.BStyle;
709 m_borderColor = packet.BColor;
710 m_backgroundColor = packet.Bg;
711}
712
714{
715 m_style = fields[3].GetUInt8();
716 m_color = fields[4].GetUInt8();
717 m_borderStyle = fields[5].GetUInt8();
718 m_borderColor = fields[6].GetUInt8();
719 m_backgroundColor = fields[7].GetUInt8();
720}
721
723{
725 stmt->setUInt32(0, m_style);
726 stmt->setUInt32(1, m_color);
727 stmt->setUInt32(2, m_borderStyle);
728 stmt->setUInt32(3, m_borderColor);
729 stmt->setUInt32(4, m_backgroundColor);
730 stmt->setUInt32(5, guildId);
731 CharacterDatabase.Execute(stmt);
732}
733
734// MoveItemData
735Guild::MoveItemData::MoveItemData(Guild* guild, Player* player, uint8 container, uint8 slotId) : m_pGuild(guild), m_pPlayer(player),
736m_container(container), m_slotId(slotId), m_pItem(nullptr), m_pClonedItem(nullptr)
737{
738}
739
743
745{
746 ASSERT(m_pItem);
747 if (splitedAmount > m_pItem->GetCount())
748 return false;
749 if (splitedAmount == m_pItem->GetCount())
750 splitedAmount = 0;
751 return true;
752}
753
754bool Guild::MoveItemData::CanStore(Item* pItem, bool swap, bool sendError)
755{
756 m_vec.clear();
757 InventoryResult msg = CanStore(pItem, swap);
758 if (sendError && msg != EQUIP_ERR_OK)
759 m_pPlayer->SendEquipError(msg, pItem);
760 return (msg == EQUIP_ERR_OK);
761}
762
764{
765 ASSERT(m_pItem);
766 m_pClonedItem = m_pItem->CloneItem(count);
767 if (!m_pClonedItem)
768 {
769 m_pPlayer->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, m_pItem);
770 return false;
771 }
772 return true;
773}
774
776{
777 ASSERT(pFrom->GetItem());
778
779 sScriptMgr->OnGuildItemMove(m_pGuild, m_pPlayer, pFrom->GetItem(),
780 pFrom->IsBank(), pFrom->GetContainer(), pFrom->GetSlotId(),
781 IsBank(), GetContainer(), GetSlotId());
782}
783
785{
786 for (auto itr = m_vec.begin(); itr != m_vec.end(); ++itr)
787 ids.insert(uint8(itr->pos));
788}
789
790// PlayerMoveItemData
792{
793 m_pItem = m_pPlayer->GetItemByPos(m_container, m_slotId);
794 if (m_pItem)
795 {
796 // Anti-WPE protection. Do not move non-empty bags to bank.
797 if (m_pItem->IsNotEmptyBag())
798 {
799 m_pPlayer->SendEquipError(EQUIP_ERR_DESTROY_NONEMPTY_BAG, m_pItem);
800 m_pItem = nullptr;
801 }
802 // Bound items cannot be put into bank.
803 else if (!m_pItem->CanBeTraded())
804 {
805 m_pPlayer->SendEquipError(EQUIP_ERR_CANT_SWAP, m_pItem);
806 m_pItem = nullptr;
807 }
808 }
809 return (m_pItem != nullptr);
810}
811
813{
814 if (splitedAmount)
815 {
816 m_pItem->SetCount(m_pItem->GetCount() - splitedAmount);
817 m_pItem->SetState(ITEM_CHANGED, m_pPlayer);
818 m_pPlayer->SaveInventoryAndGoldToDB(trans);
819 }
820 else
821 {
822 m_pPlayer->MoveItemFromInventory(m_container, m_slotId, true);
823 m_pItem->DeleteFromInventoryDB(trans);
824 m_pItem = nullptr;
825 }
826}
827
829{
830 ASSERT(pItem);
831 m_pPlayer->MoveItemToInventory(m_vec, pItem, true);
832 m_pPlayer->SaveInventoryAndGoldToDB(trans);
833 return pItem;
834}
835
837{
838 ASSERT(pFrom);
839 // Bank -> Char
840 m_pGuild->_LogBankEvent(trans, GUILD_BANK_LOG_WITHDRAW_ITEM, pFrom->GetContainer(), m_pPlayer->GetGUID().GetCounter(),
841 pFrom->GetItem()->GetEntry(), count);
842}
843
845{
846 return m_pPlayer->CanStoreItem(m_container, m_slotId, m_vec, pItem, swap);
847}
848
849// BankMoveItemData
851{
852 m_pItem = m_pGuild->_GetItem(m_container, m_slotId);
853 return (m_pItem != nullptr);
854}
855
857{
858 ASSERT(pOther);
859 // Do not check rights if item is being swapped within the same bank tab
860 if (pOther->IsBank() && pOther->GetContainer() == m_container)
861 return true;
862 return m_pGuild->_MemberHasTabRights(m_pPlayer->GetGUID(), m_container, GUILD_BANK_RIGHT_DEPOSIT_ITEM);
863}
864
866{
867 ASSERT(pOther);
868 // Do not check rights if item is being swapped within the same bank tab
869 if (pOther->IsBank() && pOther->GetContainer() == m_container)
870 return true;
871
872 int32 slots = 0;
873 if (Member const* member = m_pGuild->GetMember(m_pPlayer->GetGUID()))
874 slots = m_pGuild->_GetMemberRemainingSlots(*member, m_container);
875
876 return slots != 0;
877}
878
880{
881 ASSERT(m_pItem);
882 if (splitedAmount)
883 {
884 m_pItem->SetCount(m_pItem->GetCount() - splitedAmount);
885 m_pItem->FSetState(ITEM_CHANGED);
886 m_pItem->SaveToDB(trans);
887 }
888 else
889 {
890 m_pGuild->_RemoveItem(trans, m_container, m_slotId);
891 m_pItem = nullptr;
892 }
893 // Decrease amount of player's remaining items (if item is moved to different tab or to player)
894 if (!pOther->IsBank() || pOther->GetContainer() != m_container)
895 m_pGuild->_UpdateMemberWithdrawSlots(trans, m_pPlayer->GetGUID(), m_container);
896}
897
899{
900 if (!pItem)
901 return nullptr;
902
903 BankTab* pTab = m_pGuild->GetBankTab(m_container);
904 if (!pTab)
905 return nullptr;
906
907 Item* pLastItem = pItem;
908 for (auto itr = m_vec.begin(); itr != m_vec.end(); )
909 {
910 ItemPosCount pos(*itr);
911 ++itr;
912
913 ASSERT(pItem);
914
915 TC_LOG_DEBUG("guild", "GUILD STORAGE: StoreItem tab = {}, slot = {}, item = {}, count = {}",
916 m_container, m_slotId, pItem->GetEntry(), pItem->GetCount());
917 pLastItem = _StoreItem(trans, pTab, pItem, pos, itr != m_vec.end());
918 }
919 return pLastItem;
920}
921
923{
924 ASSERT(pFrom->GetItem());
925 if (pFrom->IsBank())
926 // Bank -> Bank
927 m_pGuild->_LogBankEvent(trans, GUILD_BANK_LOG_MOVE_ITEM, pFrom->GetContainer(), m_pPlayer->GetGUID().GetCounter(),
928 pFrom->GetItem()->GetEntry(), count, m_container);
929 else
930 // Char -> Bank
931 m_pGuild->_LogBankEvent(trans, GUILD_BANK_LOG_DEPOSIT_ITEM, m_container, m_pPlayer->GetGUID().GetCounter(),
932 pFrom->GetItem()->GetEntry(), count);
933}
934
936{
938 if (!pFrom->IsBank() && m_pPlayer->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE))
939 {
940 sLog->OutCommand(m_pPlayer->GetSession()->GetAccountId(),
941 "GM {} ({}) (Account: {}) deposit item: {} (Entry: {} Count: {}) to guild bank named: {} (Guild ID: {})",
942 m_pPlayer->GetName(), m_pPlayer->GetGUID().ToString(), m_pPlayer->GetSession()->GetAccountId(),
943 pFrom->GetItem()->GetTemplate()->Name1, pFrom->GetItem()->GetEntry(), pFrom->GetItem()->GetCount(),
944 m_pGuild->GetName(), m_pGuild->GetId());
945 }
946}
947
949{
950 uint8 slotId = uint8(pos.pos);
951 uint32 count = pos.count;
952 if (Item* pItemDest = pTab->GetItem(slotId))
953 {
954 pItemDest->SetCount(pItemDest->GetCount() + count);
955 pItemDest->FSetState(ITEM_CHANGED);
956 pItemDest->SaveToDB(trans);
957 if (!clone)
958 {
959 pItem->RemoveFromWorld();
960 pItem->DeleteFromDB(trans);
961 delete pItem;
962 }
963 return pItemDest;
964 }
965
966 if (clone)
967 pItem = pItem->CloneItem(count);
968 else
969 pItem->SetCount(count);
970
971 if (pItem && pTab->SetItem(trans, slotId, pItem))
972 return pItem;
973
974 return nullptr;
975}
976
977// Tries to reserve space for source item.
978// If item in destination slot exists it must be the item of the same entry
979// and stack must have enough space to take at least one item.
980// Returns false if destination item specified and it cannot be used to reserve space.
981bool Guild::BankMoveItemData::_ReserveSpace(uint8 slotId, Item* pItem, Item* pItemDest, uint32& count)
982{
983 uint32 requiredSpace = pItem->GetMaxStackCount();
984 if (pItemDest)
985 {
986 // Make sure source and destination items match and destination item has space for more stacks.
987 if (pItemDest->GetEntry() != pItem->GetEntry() || pItemDest->GetCount() >= pItem->GetMaxStackCount())
988 return false;
989 requiredSpace -= pItemDest->GetCount();
990 }
991 // Let's not be greedy, reserve only required space
992 requiredSpace = std::min(requiredSpace, count);
993
994 // Reserve space
995 ItemPosCount pos(slotId, requiredSpace);
996 if (!pos.isContainedIn(m_vec))
997 {
998 m_vec.push_back(pos);
999 count -= requiredSpace;
1000 }
1001 return true;
1002}
1003
1004void Guild::BankMoveItemData::CanStoreItemInTab(Item* pItem, uint8 skipSlotId, bool merge, uint32& count)
1005{
1006 for (uint8 slotId = 0; (slotId < GUILD_BANK_MAX_SLOTS) && (count > 0); ++slotId)
1007 {
1008 // Skip slot already processed in CanStore (when destination slot was specified)
1009 if (slotId == skipSlotId)
1010 continue;
1011
1012 Item* pItemDest = m_pGuild->_GetItem(m_container, slotId);
1013 if (pItemDest == pItem)
1014 pItemDest = nullptr;
1015
1016 // If merge skip empty, if not merge skip non-empty
1017 if ((pItemDest != nullptr) != merge)
1018 continue;
1019
1020 _ReserveSpace(slotId, pItem, pItemDest, count);
1021 }
1022}
1023
1025{
1026 TC_LOG_DEBUG("guild", "GUILD STORAGE: CanStore() tab = {}, slot = {}, item = {}, count = {}",
1027 m_container, m_slotId, pItem->GetEntry(), pItem->GetCount());
1028
1029 uint32 count = pItem->GetCount();
1030 // Soulbound items cannot be moved
1031 if (pItem->IsSoulBound())
1033
1034 // Make sure destination bank tab exists
1035 if (m_container >= m_pGuild->_GetPurchasedTabsSize())
1037
1038 // Slot explicitely specified. Check it.
1039 if (m_slotId != NULL_SLOT)
1040 {
1041 Item* pItemDest = m_pGuild->_GetItem(m_container, m_slotId);
1042 // Ignore swapped item (this slot will be empty after move)
1043 if ((pItemDest == pItem) || swap)
1044 pItemDest = nullptr;
1045
1046 if (!_ReserveSpace(m_slotId, pItem, pItemDest, count))
1047 return EQUIP_ERR_CANT_STACK;
1048
1049 if (count == 0)
1050 return EQUIP_ERR_OK;
1051 }
1052
1053 // Slot was not specified or it has not enough space for all the items in stack
1054 // Search for stacks to merge with
1055 if (pItem->GetMaxStackCount() > 1)
1056 {
1057 CanStoreItemInTab(pItem, m_slotId, true, count);
1058 if (count == 0)
1059 return EQUIP_ERR_OK;
1060 }
1061
1062 // Search free slot for item
1063 CanStoreItemInTab(pItem, m_slotId, false, count);
1064 if (count == 0)
1065 return EQUIP_ERR_OK;
1066
1067 return EQUIP_ERR_BANK_FULL;
1068}
1069
1070// Guild
1072 m_id(0),
1073 m_leaderGuid(),
1074 m_createdDate(0),
1076 m_bankMoney(0)
1077{
1078}
1079
1081{
1082 CharacterDatabaseTransaction temp(nullptr);
1083 _DeleteBankItems(temp);
1084}
1085
1086// Creates new guild with default data and saves it to database.
1087bool Guild::Create(Player* pLeader, std::string_view name)
1088{
1089 // Check if guild with such name already exists
1090 if (sGuildMgr->GetGuildByName(name))
1091 return false;
1092
1093 WorldSession* pLeaderSession = pLeader->GetSession();
1094 if (!pLeaderSession)
1095 return false;
1096
1097 m_id = sGuildMgr->GenerateGuildId();
1098 m_leaderGuid = pLeader->GetGUID();
1099 m_name = name;
1100 m_info = "";
1101 m_motd = "No message set.";
1102 m_bankMoney = 0;
1104
1105 TC_LOG_DEBUG("guild", "GUILD: creating guild [{}] for leader {} {}",
1106 m_name, pLeader->GetName(), m_leaderGuid.ToString());
1107
1108 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1109
1111 stmt->setUInt32(0, m_id);
1112 trans->Append(stmt);
1113
1114 uint8 index = 0;
1115 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD);
1116 stmt->setUInt32( index, m_id);
1117 stmt->setString(++index, m_name);
1118 stmt->setUInt32(++index, m_leaderGuid.GetCounter());
1119 stmt->setString(++index, m_info);
1120 stmt->setString(++index, m_motd);
1121 stmt->setUInt64(++index, uint32(m_createdDate));
1122 stmt->setUInt32(++index, m_emblemInfo.GetStyle());
1123 stmt->setUInt32(++index, m_emblemInfo.GetColor());
1124 stmt->setUInt32(++index, m_emblemInfo.GetBorderStyle());
1125 stmt->setUInt32(++index, m_emblemInfo.GetBorderColor());
1126 stmt->setUInt32(++index, m_emblemInfo.GetBackgroundColor());
1127 stmt->setUInt64(++index, m_bankMoney);
1128 trans->Append(stmt);
1129
1130 _CreateDefaultGuildRanks(trans, pLeaderSession->GetSessionDbLocaleIndex()); // Create default ranks
1131 bool ret = AddMember(trans, m_leaderGuid, GR_GUILDMASTER); // Add guildmaster
1132
1133 CharacterDatabase.CommitTransaction(trans);
1134
1135 if (ret)
1136 sScriptMgr->OnGuildCreate(this, pLeader, m_name);
1137
1138 return ret;
1139}
1140
1141// Disbands guild and deletes all related data from database
1143{
1144 // Call scripts before guild data removed from database
1145 sScriptMgr->OnGuildDisband(this);
1146
1148
1149 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1150 // Remove all members
1151 while (!m_members.empty())
1152 {
1153 auto itr = m_members.begin();
1154 DeleteMember(trans, itr->second.GetGUID(), true);
1155 }
1156
1158 stmt->setUInt32(0, m_id);
1159 trans->Append(stmt);
1160
1161 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_RANKS);
1162 stmt->setUInt32(0, m_id);
1163 trans->Append(stmt);
1164
1165 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_TABS);
1166 stmt->setUInt32(0, m_id);
1167 trans->Append(stmt);
1168
1169 // Free bank tab used memory and delete items stored in them
1170 _DeleteBankItems(trans, true);
1171
1172 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_ITEMS);
1173 stmt->setUInt32(0, m_id);
1174 trans->Append(stmt);
1175
1176 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_RIGHTS);
1177 stmt->setUInt32(0, m_id);
1178 trans->Append(stmt);
1179
1180 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_EVENTLOGS);
1181 stmt->setUInt32(0, m_id);
1182 trans->Append(stmt);
1183
1184 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_EVENTLOGS);
1185 stmt->setUInt32(0, m_id);
1186 trans->Append(stmt);
1187
1188 CharacterDatabase.CommitTransaction(trans);
1189 sGuildMgr->RemoveGuild(m_id);
1190}
1191
1192void Guild::UpdateMemberData(Player* player, uint8 dataid, uint32 value)
1193{
1194 if (Member* member = GetMember(player->GetGUID()))
1195 {
1196 switch (dataid)
1197 {
1199 member->SetZoneID(value);
1200 break;
1202 member->SetLevel(value);
1203 break;
1204 default:
1205 TC_LOG_ERROR("guild", "Guild::UpdateMemberData: Called with incorrect DATAID {} (value {})", dataid, value);
1206 return;
1207 }
1208 //HandleRoster();
1209 }
1210}
1211
1212void Guild::OnPlayerStatusChange(Player* player, uint32 flag, bool state)
1213{
1214 if (Member* member = GetMember(player->GetGUID()))
1215 {
1216 if (state)
1217 member->AddFlag(flag);
1218 else member->RemFlag(flag);
1219 }
1220}
1221
1222bool Guild::SetName(std::string_view name)
1223{
1224 if (m_name == name || name.empty() || name.length() > 24 || sObjectMgr->IsReservedName(name) || !ObjectMgr::IsValidCharterName(name))
1225 return false;
1226
1227 m_name = name;
1229 stmt->setString(0, m_name);
1230 stmt->setUInt32(1, GetId());
1231 CharacterDatabase.Execute(stmt);
1232 return true;
1233}
1234
1236{
1238
1239 roster.RankData.reserve(m_ranks.size());
1240 for (RankInfo const& rank : m_ranks)
1241 {
1242 WorldPackets::Guild::GuildRankData& rankData = roster.RankData.emplace_back();
1243
1244 rankData.Flags = rank.GetRights();
1245 rankData.WithdrawGoldLimit = rank.GetBankMoneyPerDay();
1246 for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i)
1247 {
1248 rankData.TabFlags[i] = rank.GetBankTabRights(i);
1249 rankData.TabWithdrawItemLimit[i] = rank.GetBankTabSlotsPerDay(i);
1250 }
1251 }
1252
1253 bool sendOfficerNote = _HasRankRight(session->GetPlayer(), GR_RIGHT_VIEWOFFNOTE);
1254 roster.MemberData.reserve(m_members.size());
1255 for (auto const& [guid, member] : m_members)
1256 {
1257 WorldPackets::Guild::GuildRosterMemberData& memberData = roster.MemberData.emplace_back();
1258
1259 memberData.Guid = member.GetGUID();
1260 memberData.RankID = int32(member.GetRankId());
1261 memberData.AreaID = int32(member.GetZoneId());
1262 memberData.LastSave = float(float(GameTime::GetGameTime() - member.GetLogoutTime()) / float(DAY));
1263
1264 memberData.Status = member.GetFlags();
1265 memberData.Level = member.GetLevel();
1266 memberData.ClassID = member.GetClass();
1267 memberData.Gender = member.GetGender();
1268
1269 memberData.Name = member.GetName();
1270 memberData.Note = member.GetPublicNote();
1271 if (sendOfficerNote)
1272 memberData.OfficerNote = member.GetOfficerNote();
1273 }
1274
1275 roster.WelcomeText = m_motd;
1276 roster.InfoText = m_info;
1277
1278 TC_LOG_DEBUG("guild", "SMSG_GUILD_ROSTER [{}]", session->GetPlayerInfo());
1279 session->SendPacket(roster.Write());
1280}
1281
1283{
1285 response.GuildId = m_id;
1286
1292
1293 for (uint8 i = 0; i < _GetRanksSize(); ++i)
1294 response.Info.Ranks[i] = m_ranks[i].GetName();
1295
1296 response.Info.RankCount = _GetRanksSize();
1297
1298 response.Info.GuildName = m_name;
1299
1300 session->SendPacket(response.Write());
1301 TC_LOG_DEBUG("guild", "SMSG_GUILD_QUERY_RESPONSE [{}]", session->GetPlayerInfo());
1302}
1303
1304void Guild::HandleSetMOTD(WorldSession* session, std::string_view motd)
1305{
1306 if (m_motd == motd)
1307 return;
1308
1309 // Player must have rights to set MOTD
1310 if (!_HasRankRight(session->GetPlayer(), GR_RIGHT_SETMOTD))
1312 else
1313 {
1314 m_motd = motd;
1315
1316 sScriptMgr->OnGuildMOTDChanged(this, m_motd);
1317
1319 stmt->setString(0, m_motd);
1320 stmt->setUInt32(1, m_id);
1321 CharacterDatabase.Execute(stmt);
1322
1324 }
1325}
1326
1327void Guild::HandleSetInfo(WorldSession* session, std::string_view info)
1328{
1329 if (m_info == info)
1330 return;
1331
1332 // Player must have rights to set guild's info
1334 {
1335 m_info = info;
1336
1337 sScriptMgr->OnGuildInfoChanged(this, m_info);
1338
1340 stmt->setString(0, m_info);
1341 stmt->setUInt32(1, m_id);
1342 CharacterDatabase.Execute(stmt);
1343 }
1344}
1345
1346void Guild::HandleSetEmblem(WorldSession* session, EmblemInfo const& emblemInfo)
1347{
1348 Player* player = session->GetPlayer();
1349 if (!_IsLeader(player))
1350 SendSaveEmblemResult(session, ERR_GUILDEMBLEM_NOTGUILDMASTER); // "Only guild leaders can create emblems."
1351 else if (!player->HasEnoughMoney(EMBLEM_PRICE))
1352 SendSaveEmblemResult(session, ERR_GUILDEMBLEM_NOTENOUGHMONEY); // "You can't afford to do that."
1353 else
1354 {
1355 player->ModifyMoney(-int32(EMBLEM_PRICE));
1356
1357 m_emblemInfo = emblemInfo;
1359
1360 SendSaveEmblemResult(session, ERR_GUILDEMBLEM_SUCCESS); // "Guild Emblem saved."
1361
1362 HandleQuery(session);
1363 }
1364}
1365
1366void Guild::HandleSetNewGuildMaster(WorldSession* session, std::string_view name)
1367{
1368 Player* player = session->GetPlayer();
1369
1370 Member* oldGuildMaster = GetMember(GetLeaderGUID());
1371 ASSERT(oldGuildMaster);
1372
1373 if (!_IsLeader(player))
1374 {
1376 return;
1377 }
1378
1379 Member* newGuildMaster = GetMember(name);
1380 if (!newGuildMaster)
1381 return;
1382
1383 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1384
1385 _SetLeader(trans, *newGuildMaster);
1386 oldGuildMaster->ChangeRank(trans, GR_OFFICER);
1387
1388 _BroadcastEvent(GE_LEADER_CHANGED, ObjectGuid::Empty, player->GetName(), newGuildMaster->GetName());
1389
1390 CharacterDatabase.CommitTransaction(trans);
1391}
1392
1393void Guild::HandleSetBankTabInfo(WorldSession* session, uint8 tabId, std::string_view name, std::string_view icon)
1394{
1395 BankTab* tab = GetBankTab(tabId);
1396 if (!tab)
1397 {
1398 TC_LOG_ERROR("guild", "Guild::HandleSetBankTabInfo: Player {} trying to change bank tab info from unexisting tab {}.",
1399 session->GetPlayerInfo(), tabId);
1400 return;
1401 }
1402
1403 tab->SetInfo(name, icon);
1404 _BroadcastEvent(GE_BANK_TAB_UPDATED, ObjectGuid::Empty, std::to_string(tabId), tab->GetName(), tab->GetIcon());
1405}
1406
1407void Guild::HandleSetMemberNote(WorldSession* session, std::string_view note, std::string_view name, bool isPublic)
1408{
1409 // Player must have rights to set public/officer note
1410 if (!_HasRankRight(session->GetPlayer(), isPublic ? GR_RIGHT_EPNOTE : GR_RIGHT_EOFFNOTE))
1412 else if (Member* member = GetMember(name))
1413 {
1414 if (isPublic)
1415 member->SetPublicNote(note);
1416 else
1417 member->SetOfficerNote(note);
1418
1419 HandleRoster(session);
1420 }
1421}
1422
1423void Guild::HandleSetRankInfo(WorldSession* session, uint8 rankId, std::string_view name, uint32 rights, uint32 moneyPerDay, std::array<GuildBankRightsAndSlots, GUILD_BANK_MAX_TABS> const& rightsAndSlots)
1424{
1425 // Only leader can modify ranks
1426 if (!_IsLeader(session->GetPlayer()))
1428 else if (RankInfo* rankInfo = GetRankInfo(rankId))
1429 {
1430 rankInfo->SetName(name);
1431 rankInfo->SetRights(rights);
1432 _SetRankBankMoneyPerDay(rankId, moneyPerDay);
1433
1434 for (auto itr = rightsAndSlots.begin(); itr != rightsAndSlots.end(); ++itr)
1435 _SetRankBankTabRightsAndSlots(rankId, *itr);
1436
1437 _BroadcastEvent(GE_RANK_UPDATED, ObjectGuid::Empty, std::to_string(rankId), rankInfo->GetName(), std::to_string(m_ranks.size()));
1438
1439 TC_LOG_DEBUG("guild", "Changed RankName to '{}', rights to 0x{:08X}", rankInfo->GetName(), rights);
1440 }
1441}
1442
1444{
1445 Player* player = session->GetPlayer();
1446 if (!player)
1447 return;
1448
1449 Member const* member = GetMember(player->GetGUID());
1450 if (!member)
1451 return;
1452
1454 return;
1455
1456 if (tabId != _GetPurchasedTabsSize())
1457 return;
1458
1459 if (tabId >= GUILD_BANK_MAX_TABS)
1460 return;
1461
1462 uint32 tabCost = GetGuildBankTabPrice(tabId) * GOLD;
1463 if (!player->HasEnoughMoney(tabCost)) // Should not happen, this is checked by client
1464 return;
1465
1466 player->ModifyMoney(-int32(tabCost));
1467
1470 SendPermissions(session);
1471}
1472
1473void Guild::HandleInviteMember(WorldSession* session, std::string_view name)
1474{
1475 Player* pInvitee = ObjectAccessor::FindPlayerByName(name);
1476 if (!pInvitee)
1477 {
1479 return;
1480 }
1481
1482 Player* player = session->GetPlayer();
1483 // Do not show invitations from ignored players
1484 if (pInvitee->GetSocial()->HasIgnore(player->GetGUID()))
1485 return;
1486
1487 if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && pInvitee->GetTeam() != player->GetTeam())
1488 {
1490 return;
1491 }
1492 // Invited player cannot be in another guild
1493 if (pInvitee->GetGuildId())
1494 {
1496 return;
1497 }
1498 // Invited player cannot be invited
1499 if (pInvitee->GetGuildIdInvited())
1500 {
1502 return;
1503 }
1504 // Inviting player must have rights to invite
1505 if (!_HasRankRight(player, GR_RIGHT_INVITE))
1506 {
1508 return;
1509 }
1510
1512
1513 TC_LOG_DEBUG("guild", "Player {} invited {} to join his Guild", player->GetName(), pInvitee->GetName());
1514
1515 pInvitee->SetGuildIdInvited(m_id);
1517
1519
1520 invite.InviterName = player->GetName();
1521 invite.GuildName = GetName();
1522
1523 pInvitee->SendDirectMessage(invite.Write());
1524 TC_LOG_DEBUG("guild", "SMSG_GUILD_INVITE [{}]", pInvitee->GetName());
1525}
1526
1528{
1529 Player* player = session->GetPlayer();
1530 if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) &&
1531 player->GetTeam() != sCharacterCache->GetCharacterTeamByGuid(GetLeaderGUID()))
1532 return;
1533
1534 CharacterDatabaseTransaction trans(nullptr);
1535 AddMember(trans, player->GetGUID());
1536}
1537
1539{
1540 Player* player = session->GetPlayer();
1541
1542 sCalendarMgr->RemovePlayerGuildEventsAndSignups(player->GetGUID(), GetId());
1543
1544 // If leader is leaving
1545 if (_IsLeader(player))
1546 {
1547 if (m_members.size() > 1)
1548 // Leader cannot leave if he is not the last member
1550 else
1551 {
1552 // Guild is disbanded if leader leaves.
1553 Disband();
1554 }
1555 }
1556 else
1557 {
1558 CharacterDatabaseTransaction trans(nullptr);
1559 DeleteMember(trans, player->GetGUID(), false, false);
1560
1562 _BroadcastEvent(GE_LEFT, player->GetGUID(), player->GetName());
1563
1565 }
1566}
1567
1568void Guild::HandleRemoveMember(WorldSession* session, std::string_view name)
1569{
1570 Player* player = session->GetPlayer();
1571 // Player must have rights to remove members
1572 if (!_HasRankRight(player, GR_RIGHT_REMOVE))
1574 else if (Member* member = GetMember(name))
1575 {
1576 // Guild masters cannot be removed
1577 if (member->IsRank(GR_GUILDMASTER))
1579 // Do not allow to remove player with the same rank or higher
1580 else
1581 {
1582 Member const* memberMe = GetMember(player->GetGUID());
1583 if (!memberMe || member->IsRankNotLower(memberMe->GetRankId()))
1585 else
1586 {
1587 ObjectGuid guid = member->GetGUID();
1590
1591 // After call to DeleteMember pointer to member becomes invalid
1592 CharacterDatabaseTransaction trans(nullptr);
1593 DeleteMember(trans, guid, false, true);
1594 }
1595 }
1596 }
1597}
1598
1599void Guild::HandleUpdateMemberRank(WorldSession* session, std::string_view name, bool demote)
1600{
1601 Player* player = session->GetPlayer();
1603 // Player must have rights to promote
1604 if (!_HasRankRight(player, demote ? GR_RIGHT_DEMOTE : GR_RIGHT_PROMOTE))
1606 // Promoted player must be a member of guild
1607 else if (Member* member = GetMember(name))
1608 {
1609 // Player cannot promote himself
1610 if (member->IsSamePlayer(player->GetGUID()))
1611 {
1613 return;
1614 }
1615
1616 Member const* memberMe = GetMember(player->GetGUID());
1617 ASSERT(memberMe);
1618 uint8 rankId = memberMe->GetRankId();
1619 if (demote)
1620 {
1621 // Player can demote only lower rank members
1622 if (member->IsRankNotLower(rankId))
1623 {
1624 SendCommandResult(session, type, ERR_GUILD_RANK_TOO_HIGH_S, name);
1625 return;
1626 }
1627 // Lowest rank cannot be demoted
1628 if (member->GetRankId() >= _GetLowestRankId())
1629 {
1630 SendCommandResult(session, type, ERR_GUILD_RANK_TOO_LOW_S, name);
1631 return;
1632 }
1633 }
1634 else
1635 {
1636 // Allow to promote only to lower rank than member's rank
1637 // member->GetRankId() + 1 is the highest rank that current player can promote to
1638 if (member->IsRankNotLower(rankId + 1))
1639 {
1640 SendCommandResult(session, type, ERR_GUILD_RANK_TOO_HIGH_S, name);
1641 return;
1642 }
1643 }
1644
1645 uint32 newRankId = member->GetRankId() + (demote ? 1 : -1);
1646 CharacterDatabaseTransaction trans(nullptr);
1647 member->ChangeRank(trans, newRankId);
1648 _LogEvent(demote ? GUILD_EVENT_LOG_DEMOTE_PLAYER : GUILD_EVENT_LOG_PROMOTE_PLAYER, player->GetGUID().GetCounter(), member->GetGUID().GetCounter(), newRankId);
1649 _BroadcastEvent(demote ? GE_DEMOTION : GE_PROMOTION, ObjectGuid::Empty, player->GetName(), member->GetName(), _GetRankName(newRankId));
1650 }
1651}
1652
1653void Guild::HandleAddNewRank(WorldSession* session, std::string_view name)
1654{
1655 uint8 size = _GetRanksSize();
1656 if (size >= GUILD_RANKS_MAX_COUNT)
1657 return;
1658
1659 // Only leader can add new rank
1660 if (_IsLeader(session->GetPlayer()))
1661 {
1662 CharacterDatabaseTransaction trans(nullptr);
1664 _BroadcastEvent(GE_RANK_UPDATED, ObjectGuid::Empty, std::to_string(size), name, std::to_string(m_ranks.size()));
1665 }
1666}
1667
1672
1674{
1675 // Cannot remove rank if total count is minimum allowed by the client or is not leader
1676 if (_GetRanksSize() <= GUILD_RANKS_MIN_COUNT || rankId >= _GetRanksSize() || !_IsLeader(session->GetPlayer()))
1677 return;
1678
1679 // Delete bank rights for rank
1681 stmt->setUInt32(0, m_id);
1682 stmt->setUInt8(1, rankId);
1683 CharacterDatabase.Execute(stmt);
1684 // Delete rank
1685 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_RANK);
1686 stmt->setUInt32(0, m_id);
1687 stmt->setUInt8(1, rankId);
1688 CharacterDatabase.Execute(stmt);
1689
1690 // match what the sql statement does
1691 m_ranks.erase(m_ranks.begin() + rankId, m_ranks.end());
1692
1693 _BroadcastEvent(GE_RANK_DELETED, ObjectGuid::Empty, std::to_string(m_ranks.size()));
1694}
1695
1697{
1698 Player* player = session->GetPlayer();
1699
1700 // Call script after validation and before money transfer.
1701 sScriptMgr->OnGuildMemberDepositMoney(this, player, amount);
1702
1703 if (m_bankMoney > GUILD_BANK_MONEY_LIMIT - amount)
1704 {
1706 return;
1707 }
1708
1709 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1710 _ModifyBankMoney(trans, amount, true);
1711
1712 player->ModifyMoney(-int32(amount));
1713 player->SaveGoldToDB(trans);
1714 _LogBankEvent(trans, GUILD_BANK_LOG_DEPOSIT_MONEY, uint8(0), player->GetGUID().GetCounter(), amount);
1715
1716 CharacterDatabase.CommitTransaction(trans);
1717
1719
1721 {
1722 sLog->OutCommand(player->GetSession()->GetAccountId(),
1723 "GM {} (Account: {}) deposit money (Amount: {}) to guild bank (Guild ID {})",
1724 player->GetName(), player->GetSession()->GetAccountId(), amount, m_id);
1725 }
1726}
1727
1728bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool repair)
1729{
1730 //clamp amount to MAX_MONEY_AMOUNT, Players can't hold more than that anyway
1731 amount = std::min(amount, MAX_MONEY_AMOUNT);
1732
1733 if (m_bankMoney < amount) // Not enough money in bank
1734 return false;
1735
1736 Player* player = session->GetPlayer();
1737
1738 Member* member = GetMember(player->GetGUID());
1739 if (!member)
1740 return false;
1741
1742 if (uint32(_GetMemberRemainingMoney(*member)) < amount) // Check if we have enough slot/money today
1743 return false;
1744
1745 // Call script after validation and before money transfer.
1746 sScriptMgr->OnGuildMemberWitdrawMoney(this, player, amount, repair);
1747
1748 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1749 // Add money to player (if required)
1750 if (!repair)
1751 {
1752 if (!player->ModifyMoney(amount))
1753 return false;
1754
1755 player->SaveGoldToDB(trans);
1756 }
1757
1758 // Update remaining money amount
1759 member->UpdateBankWithdrawValue(trans, GUILD_BANK_MAX_TABS, amount);
1760 // Remove money from bank
1761 _ModifyBankMoney(trans, amount, false);
1762
1763 // Log guild bank event
1765 CharacterDatabase.CommitTransaction(trans);
1766
1768 return true;
1769}
1770
1772{
1773 Player* player = session->GetPlayer();
1774 if (Member* member = GetMember(player->GetGUID()))
1775 {
1776 member->SetStats(player);
1777 member->UpdateLogoutTime();
1778 member->ResetFlags();
1779 }
1780 _BroadcastEvent(GE_SIGNED_OFF, player->GetGUID(), player->GetName());
1781}
1782
1784{
1785 // Only leader can disband guild
1786 if (_IsLeader(session->GetPlayer()))
1787 {
1788 Disband();
1789 TC_LOG_DEBUG("guild", "Guild Successfully Disbanded");
1790 }
1791}
1792
1793// Send data to client
1794void Guild::SendInfo(WorldSession* session) const
1795{
1797 guildInfo.GuildName = m_name;
1799 guildInfo.CreateDate += session->GetTimezoneOffset();
1800 guildInfo.NumMembers = int32(m_members.size());
1801 guildInfo.NumAccounts = m_accountsNumber;
1802
1803 session->SendPacket(guildInfo.Write());
1804 TC_LOG_DEBUG("guild", "SMSG_GUILD_INFO [{}]", session->GetPlayerInfo());
1805}
1806
1808{
1809 std::list<EventLogEntry> const& eventLog = m_eventLog.GetGuildLog();
1810
1812 packet.Entry.reserve(eventLog.size());
1813
1814 for (EventLogEntry const& entry : eventLog)
1815 entry.WritePacket(packet);
1816
1817 session->SendPacket(packet.Write());
1818 TC_LOG_DEBUG("guild", "MSG_GUILD_EVENT_LOG_QUERY [{}]", session->GetPlayerInfo());
1819}
1820
1821void Guild::SendBankLog(WorldSession* session, uint8 tabId) const
1822{
1823 // GUILD_BANK_MAX_TABS send by client for money log
1824 if (tabId < _GetPurchasedTabsSize() || tabId == GUILD_BANK_MAX_TABS)
1825 {
1826 std::list<BankEventLogEntry> const& bankEventLog = m_bankEventLog[tabId].GetGuildLog();
1827
1829 packet.Tab = tabId;
1830
1831 packet.Entry.reserve(bankEventLog.size());
1832 for (BankEventLogEntry const& entry : bankEventLog)
1833 entry.WritePacket(packet);
1834
1835 session->SendPacket(packet.Write());
1836
1837 TC_LOG_DEBUG("guild", "MSG_GUILD_BANK_LOG_QUERY [{}]", session->GetPlayerInfo());
1838 }
1839}
1840
1841void Guild::SendBankTabData(WorldSession* session, uint8 tabId, bool sendAllSlots) const
1842{
1843 if (tabId < _GetPurchasedTabsSize())
1844 SendBankList(session, tabId, sendAllSlots);
1845}
1846
1847void Guild::SendBankTabText(WorldSession* session, uint8 tabId) const
1848{
1849 if (BankTab const* tab = GetBankTab(tabId))
1850 tab->SendText(this, session);
1851}
1852
1854{
1855 Member const* member = GetMember(session->GetPlayer()->GetGUID());
1856 if (!member)
1857 return;
1858
1859 uint8 rankId = member->GetRankId();
1860
1862 queryResult.RankID = rankId;
1863 queryResult.WithdrawGoldLimit = _GetRankBankMoneyPerDay(rankId);
1864 queryResult.Flags = _GetRankRights(rankId);
1865 queryResult.NumTabs = _GetPurchasedTabsSize();
1866
1867 for (uint8 tabId = 0; tabId < GUILD_BANK_MAX_TABS; ++tabId)
1868 {
1869 queryResult.Tab[tabId].Flags = _GetRankBankTabRights(rankId, tabId);
1870 queryResult.Tab[tabId].WithdrawItemLimit = _GetMemberRemainingSlots(*member, tabId);
1871 }
1872
1873 session->SendPacket(queryResult.Write());
1874 TC_LOG_DEBUG("guild", "MSG_GUILD_PERMISSIONS [{}] Rank: {}", session->GetPlayerInfo(), rankId);
1875}
1876
1878{
1879 Member const* member = GetMember(session->GetPlayer()->GetGUID());
1880 if (!member)
1881 return;
1882
1883 int32 amount = _GetMemberRemainingMoney(*member);
1884
1886 packet.RemainingWithdrawMoney = amount;
1887 session->SendPacket(packet.Write());
1888
1889 TC_LOG_DEBUG("guild", "MSG_GUILD_BANK_MONEY_WITHDRAWN [{}] Money: {}", session->GetPlayerInfo(), amount);
1890}
1891
1893{
1895 motd.Type = GE_MOTD;
1897 session->SendPacket(motd.Write());
1898
1899 TC_LOG_DEBUG("guild", "SMSG_GUILD_EVENT [{}] MOTD", session->GetPlayerInfo());
1900
1901 SendBankList(session);
1902
1903 Player* player = session->GetPlayer();
1904
1905 HandleRoster(session);
1906 _BroadcastEvent(GE_SIGNED_ON, player->GetGUID(), player->GetName());
1907
1908 if (Member* member = GetMember(player->GetGUID()))
1909 {
1910 member->SetStats(player);
1911 member->AddFlag(GUILDMEMBER_STATUS_ONLINE);
1912 }
1913}
1914
1915// Loading methods
1917{
1918 m_id = fields[0].GetUInt32();
1919 m_name = fields[1].GetString();
1920 m_leaderGuid = ObjectGuid::Create<HighGuid::Player>(fields[2].GetUInt32());
1921 m_emblemInfo.LoadFromDB(fields);
1922 m_info = fields[8].GetString();
1923 m_motd = fields[9].GetString();
1924 m_createdDate = time_t(fields[10].GetUInt32());
1925 m_bankMoney = fields[11].GetUInt64();
1926
1927 uint8 purchasedTabs = uint8(fields[12].GetUInt64());
1928 if (purchasedTabs > GUILD_BANK_MAX_TABS)
1929 purchasedTabs = GUILD_BANK_MAX_TABS;
1930
1931 m_bankTabs.clear();
1932 m_bankTabs.reserve(purchasedTabs);
1933 for (uint8 i = 0; i < purchasedTabs; ++i)
1934 m_bankTabs.emplace_back(m_id, i);
1935 return true;
1936}
1937
1939{
1940 RankInfo rankInfo(m_id);
1941
1942 rankInfo.LoadFromDB(fields);
1943
1944 m_ranks.push_back(rankInfo);
1945}
1946
1948{
1949 ObjectGuid::LowType lowguid = fields[1].GetUInt32();
1950 ObjectGuid playerGuid(ObjectGuid::Create<HighGuid::Player>(lowguid));
1951
1952 auto [memberIt, isNew] = m_members.try_emplace(playerGuid, m_id, playerGuid, fields[2].GetUInt8());
1953 if (!isNew)
1954 {
1955 TC_LOG_ERROR("guild", "Tried to add {} to guild '{}'. Member already exists.", playerGuid.ToString(), m_name);
1956 return false;
1957 }
1958
1959 Member& member = memberIt->second;
1960 if (!member.LoadFromDB(fields))
1961 {
1962 CharacterDatabaseTransaction trans(nullptr);
1963 _DeleteMemberFromDB(trans, lowguid);
1964 m_members.erase(memberIt);
1965 return false;
1966 }
1967
1968 sCharacterCache->UpdateCharacterGuildId(playerGuid, GetId());
1969 return true;
1970}
1971
1973{
1974 // tabId rights slots
1975 GuildBankRightsAndSlots rightsAndSlots(fields[1].GetUInt8(), fields[3].GetUInt8(), fields[4].GetUInt32());
1976 // rankId
1977 _SetRankBankTabRightsAndSlots(fields[2].GetUInt8(), rightsAndSlots, false);
1978}
1979
1981{
1982 if (m_eventLog.CanInsert())
1983 {
1984 m_eventLog.LoadEvent(
1985 m_id, // guild id
1986 fields[1].GetUInt32(), // guid
1987 time_t(fields[6].GetUInt32()), // timestamp
1988 GuildEventLogTypes(fields[2].GetUInt8()), // event type
1989 fields[3].GetUInt32(), // player guid 1
1990 fields[4].GetUInt32(), // player guid 2
1991 fields[5].GetUInt8()); // rank
1992 return true;
1993 }
1994 return false;
1995}
1996
1998{
1999 uint8 dbTabId = fields[1].GetUInt8();
2000 bool isMoneyTab = (dbTabId == GUILD_BANK_MONEY_LOGS_TAB);
2001 if (dbTabId < _GetPurchasedTabsSize() || isMoneyTab)
2002 {
2003 uint8 tabId = isMoneyTab ? uint8(GUILD_BANK_MAX_TABS) : dbTabId;
2005 if (bankLog.CanInsert())
2006 {
2007 ObjectGuid::LowType guid = fields[2].GetUInt32();
2008 GuildBankEventLogTypes eventType = GuildBankEventLogTypes(fields[3].GetUInt8());
2009 if (BankEventLogEntry::IsMoneyEvent(eventType))
2010 {
2011 if (!isMoneyTab)
2012 {
2013 TC_LOG_ERROR("guild", "GuildBankEventLog ERROR: MoneyEvent(LogGuid: {}, Guild: {}) does not belong to money tab ({}), ignoring...", guid, m_id, dbTabId);
2014 return false;
2015 }
2016 }
2017 else if (isMoneyTab)
2018 {
2019 TC_LOG_ERROR("guild", "GuildBankEventLog ERROR: non-money event (LogGuid: {}, Guild: {}) belongs to money tab, ignoring...", guid, m_id);
2020 return false;
2021 }
2022 bankLog.LoadEvent(
2023 m_id, // guild id
2024 guid, // guid
2025 time_t(fields[8].GetUInt32()), // timestamp
2026 dbTabId, // tab id
2027 eventType, // event type
2028 fields[4].GetUInt32(), // player guid
2029 fields[5].GetUInt32(), // item or money
2030 fields[6].GetUInt16(), // itam stack count
2031 fields[7].GetUInt8()); // dest tab id
2032 }
2033 }
2034 return true;
2035}
2036
2038{
2039 uint8 tabId = fields[1].GetUInt8();
2040 if (tabId >= _GetPurchasedTabsSize())
2041 TC_LOG_ERROR("guild", "Invalid tab (tabId: {}) in guild bank, skipped.", tabId);
2042 else
2043 m_bankTabs[tabId].LoadFromDB(fields);
2044}
2045
2047{
2048 uint8 tabId = fields[12].GetUInt8();
2049 if (tabId >= _GetPurchasedTabsSize())
2050 {
2051 TC_LOG_ERROR("guild", "Invalid tab for item (GUID: {}, id: #{}) in guild bank, skipped.",
2052 fields[14].GetUInt32(), fields[15].GetUInt32());
2053 return false;
2054 }
2055 return m_bankTabs[tabId].LoadItemFromDB(fields);
2056}
2057
2058// Validates guild data loaded from database. Returns false if guild should be deleted.
2060{
2061 // Validate ranks data
2062 // GUILD RANKS represent a sequence starting from 0 = GUILD_MASTER (ALL PRIVILEGES) to max 9 (lowest privileges).
2063 // The lower rank id is considered higher rank - so promotion does rank-- and demotion does rank++
2064 // Between ranks in sequence cannot be gaps - so 0, 1, 2, 4 is impossible
2065 // Min ranks count is 5 and max is 10.
2066 bool broken_ranks = false;
2067 uint8 ranks = _GetRanksSize();
2068
2069 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
2070 if (ranks < GUILD_RANKS_MIN_COUNT || ranks > GUILD_RANKS_MAX_COUNT)
2071 {
2072 TC_LOG_ERROR("guild", "Guild {} has invalid number of ranks, creating new...", m_id);
2073 broken_ranks = true;
2074 }
2075 else
2076 {
2077 for (uint8 rankId = 0; rankId < ranks; ++rankId)
2078 {
2079 RankInfo* rankInfo = GetRankInfo(rankId);
2080 if (rankInfo->GetId() != rankId)
2081 {
2082 TC_LOG_ERROR("guild", "Guild {} has broken rank id {}, creating default set of ranks...", m_id, rankId);
2083 broken_ranks = true;
2084 }
2085 else
2086 rankInfo->CreateMissingTabsIfNeeded(_GetPurchasedTabsSize(), trans, true);
2087 }
2088 }
2089
2090 if (broken_ranks)
2091 {
2092 m_ranks.clear();
2094 }
2095
2096 // Validate members' data
2097 for (auto& [guid, member] : m_members)
2098 if (member.GetRankId() > _GetRanksSize())
2099 member.ChangeRank(trans, _GetLowestRankId());
2100
2101 // Repair the structure of the guild.
2102 // If the guildmaster doesn't exist or isn't member of the guild
2103 // attempt to promote another member.
2104 Member* leader = GetMember(m_leaderGuid);
2105 if (!leader)
2106 {
2107 CharacterDatabaseTransaction dummy(nullptr);
2108 if (DeleteMember(dummy, m_leaderGuid))
2109 return false;
2110 }
2111 else if (!leader->IsRank(GR_GUILDMASTER))
2112 _SetLeader(trans, *leader);
2113
2114 // Check config if multiple guildmasters are allowed
2115 if (!sConfigMgr->GetBoolDefault("Guild.AllowMultipleGuildMaster", false))
2116 for (auto& [guid, member] : m_members)
2117 if ((member.GetRankId() == GR_GUILDMASTER) && !member.IsSamePlayer(m_leaderGuid))
2118 member.ChangeRank(trans, GR_OFFICER);
2119
2120 if (trans->GetSize() > 0)
2121 CharacterDatabase.CommitTransaction(trans);
2123 return true;
2124}
2125
2126// Broadcasts
2127void Guild::BroadcastToGuild(WorldSession* session, bool officerOnly, std::string_view msg, uint32 language) const
2128{
2129 if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK))
2130 {
2131 WorldPacket data;
2132 ChatHandler::BuildChatPacket(data, officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), nullptr, msg);
2133 for (auto const& [guid, member] : m_members)
2134 if (Player* player = member.FindConnectedPlayer())
2135 if (player->GetSession() && _HasRankRight(player, officerOnly ? GR_RIGHT_OFFCHATLISTEN : GR_RIGHT_GCHATLISTEN) &&
2136 !player->GetSocial()->HasIgnore(session->GetPlayer()->GetGUID()))
2137 player->SendDirectMessage(&data);
2138 }
2139}
2140
2141void Guild::BroadcastPacketToRank(WorldPacket const* packet, uint8 rankId) const
2142{
2143 for (auto const& [guid, member] : m_members)
2144 if (member.IsRank(rankId))
2145 if (Player* player = member.FindConnectedPlayer())
2146 player->SendDirectMessage(packet);
2147}
2148
2149void Guild::BroadcastPacket(WorldPacket const* packet) const
2150{
2151 for (auto const& [guid, member] : m_members)
2152 if (Player* player = member.FindConnectedPlayer())
2153 player->SendDirectMessage(packet);
2154}
2155
2156void Guild::MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 maxLevel, uint32 minRank)
2157{
2159
2160 for (auto const& [guid, member] : m_members)
2161 {
2162 // not sure if needed, maybe client checks it as well
2163 if (packet.Invites.size() >= CALENDAR_MAX_INVITES)
2164 {
2165 if (Player* player = session->GetPlayer())
2166 sCalendarMgr->SendCalendarCommandResult(player->GetGUID(), CALENDAR_ERROR_INVITES_EXCEEDED);
2167 return;
2168 }
2169
2170 if (member.GetGUID() == session->GetPlayer()->GetGUID())
2171 continue;
2172
2173 uint32 level = sCharacterCache->GetCharacterLevelByGuid(member.GetGUID());
2174 if (level < minLevel || level > maxLevel)
2175 continue;
2176
2177 if (!member.IsRankNotLower(minRank))
2178 continue;
2179
2180 packet.Invites.emplace_back(member.GetGUID(), level);
2181 }
2182
2183 session->SendPacket(packet.Write());
2184}
2185
2186// Members handling
2188{
2190 // Player cannot be in guild
2191 if (player)
2192 {
2193 if (player->GetGuildId())
2194 return false;
2195 }
2196 else if (sCharacterCache->GetCharacterGuildIdByGuid(guid))
2197 return false;
2198
2199 // Remove all player signs from another petitions
2200 // This will be prevent attempt to join many guilds and corrupt guild data integrity
2202
2203 ObjectGuid::LowType lowguid = guid.GetCounter();
2204
2205 // If rank was not passed, assign lowest possible rank
2206 if (rankId == GUILD_RANK_NONE)
2207 rankId = _GetLowestRankId();
2208
2209 auto [memberIt, isNew] = m_members.try_emplace(guid, m_id, guid, rankId);
2210 if (!isNew)
2211 {
2212 TC_LOG_ERROR("guild", "Tried to add {} to guild '{}'. Member already exists.", guid.ToString(), m_name);
2213 return false;
2214 }
2215
2216 Member& member = memberIt->second;
2217 std::string name;
2218 if (player)
2219 {
2220 player->SetInGuild(m_id);
2221 player->SetGuildIdInvited(0);
2222 player->SetGuildRank(rankId);
2223 member.SetStats(player);
2224 SendLoginInfo(player->GetSession());
2225 name = player->GetName();
2226 }
2227 else
2228 {
2229 member.ResetFlags();
2230
2231 bool ok = false;
2232 // Player must exist
2234 stmt->setUInt32(0, lowguid);
2235 if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
2236 {
2237 Field* fields = result->Fetch();
2238 name = fields[0].GetString();
2239 member.SetStats(
2240 name,
2241 fields[1].GetUInt8(),
2242 fields[2].GetUInt8(),
2243 fields[3].GetUInt8(),
2244 fields[4].GetUInt16(),
2245 fields[5].GetUInt32());
2246
2247 ok = member.CheckStats();
2248 }
2249 if (!ok)
2250 {
2251 m_members.erase(memberIt);
2252 return false;
2253 }
2254 sCharacterCache->UpdateCharacterGuildId(guid, GetId());
2255 }
2256
2257 member.SaveToDB(trans);
2258
2261 _BroadcastEvent(GE_JOINED, guid, name);
2262
2263 // Call scripts if member was succesfully added (and stored to database)
2264 sScriptMgr->OnGuildAddMember(this, player, rankId);
2265
2266 return true;
2267}
2268
2269bool Guild::DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bool isDisbanding, bool isKicked)
2270{
2272
2273 // Guild master can be deleted when loading guild and guid doesn't exist in characters table
2274 // or when he is removed from guild by gm command
2275 if (m_leaderGuid == guid && !isDisbanding)
2276 {
2277 Member* oldLeader = nullptr;
2278 Member* newLeader = nullptr;
2279 for (auto& [memberGuid, member] : m_members)
2280 {
2281 if (memberGuid == guid)
2282 oldLeader = &member;
2283 else if (!newLeader || newLeader->GetRankId() > member.GetRankId())
2284 newLeader = &member;
2285 }
2286
2287 if (!newLeader)
2288 {
2289 Disband();
2290 return true;
2291 }
2292
2293 _SetLeader(trans, *newLeader);
2294
2295 // If player not online data in data field will be loaded from guild tabs no need to update it !!
2296 if (Player* newLeaderPlayer = newLeader->FindPlayer())
2297 newLeaderPlayer->SetGuildRank(GR_GUILDMASTER);
2298
2299 // If leader does not exist (at guild loading with deleted leader) do not send broadcasts
2300 if (oldLeader)
2301 {
2303 _BroadcastEvent(GE_LEFT, guid, oldLeader->GetName());
2304 }
2305 }
2306 // Call script on remove before member is actually removed from guild (and database)
2307 sScriptMgr->OnGuildRemoveMember(this, player, isDisbanding, isKicked);
2308
2309 m_members.erase(guid);
2310
2311 // If player not online data in data field will be loaded from guild tabs no need to update it !!
2312 if (player)
2313 {
2314 player->SetInGuild(0);
2315 player->SetGuildRank(0);
2316 }
2317 else
2318 sCharacterCache->UpdateCharacterGuildId(guid, 0);
2319
2320 _DeleteMemberFromDB(trans, guid.GetCounter());
2321 if (!isDisbanding)
2323
2324 if (m_members.empty())
2325 {
2326 Disband();
2327 return true;
2328 }
2329
2330 return false;
2331}
2332
2334{
2335 if (newRank <= _GetLowestRankId()) // Validate rank (allow only existing ranks)
2336 {
2337 if (Member* member = GetMember(guid))
2338 {
2339 member->ChangeRank(trans, newRank);
2340 return true;
2341 }
2342 }
2343
2344 return false;
2345}
2346
2348{
2349 return m_members.find(guid) != m_members.end();
2350}
2351
2353{
2354 Member const* member = GetMember(guid);
2355 if (!member)
2356 return 0;
2357
2358 return std::min(m_bankMoney, static_cast<uint64>(_GetMemberRemainingMoney(*member)));
2359}
2360
2361// Bank (items move)
2362void Guild::SwapItems(Player* player, uint8 tabId, uint8 slotId, uint8 destTabId, uint8 destSlotId, uint32 splitedAmount)
2363{
2364 if (tabId >= _GetPurchasedTabsSize() || slotId >= GUILD_BANK_MAX_SLOTS ||
2365 destTabId >= _GetPurchasedTabsSize() || destSlotId >= GUILD_BANK_MAX_SLOTS)
2366 return;
2367
2368 if (tabId == destTabId && slotId == destSlotId)
2369 return;
2370
2371 BankMoveItemData from(this, player, tabId, slotId);
2372 BankMoveItemData to(this, player, destTabId, destSlotId);
2373 _MoveItems(&from, &to, splitedAmount);
2374}
2375
2376void Guild::SwapItemsWithInventory(Player* player, bool toChar, uint8 tabId, uint8 slotId, uint8 playerBag, uint8 playerSlotId, uint32 splitedAmount)
2377{
2378 if ((slotId >= GUILD_BANK_MAX_SLOTS && slotId != NULL_SLOT) || tabId >= _GetPurchasedTabsSize())
2379 return;
2380
2381 BankMoveItemData bankData(this, player, tabId, slotId);
2382 PlayerMoveItemData charData(this, player, playerBag, playerSlotId);
2383 if (toChar)
2384 _MoveItems(&bankData, &charData, splitedAmount);
2385 else
2386 _MoveItems(&charData, &bankData, splitedAmount);
2387}
2388
2389// Bank tabs
2390void Guild::SetBankTabText(uint8 tabId, std::string_view text)
2391{
2392 if (BankTab* pTab = GetBankTab(tabId))
2393 {
2394 pTab->SetText(text);
2395 pTab->SendText(this, nullptr);
2396 }
2397}
2398
2399bool Guild::_HasRankRight(Player* player, uint32 right) const
2400{
2401 if (player)
2402 if (Member const* member = GetMember(player->GetGUID()))
2403 return (_GetRankRights(member->GetRankId()) & right) != GR_RIGHT_EMPTY;
2404 return false;
2405}
2406
2408{
2410 stmt->setUInt32(0, lowguid);
2411 CharacterDatabase.ExecuteOrAppend(trans, stmt);
2412}
2413
2414// Private methods
2416{
2417 uint8 tabId = _GetPurchasedTabsSize(); // Next free id
2418 m_bankTabs.emplace_back(m_id, tabId);
2419
2420 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
2421
2423 stmt->setUInt32(0, m_id);
2424 stmt->setUInt8 (1, tabId);
2425 trans->Append(stmt);
2426
2427 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_BANK_TAB);
2428 stmt->setUInt32(0, m_id);
2429 stmt->setUInt8 (1, tabId);
2430 trans->Append(stmt);
2431
2432 ++tabId;
2433 for (auto itr = m_ranks.begin(); itr != m_ranks.end(); ++itr)
2434 (*itr).CreateMissingTabsIfNeeded(tabId, trans, false);
2435
2436 CharacterDatabase.CommitTransaction(trans);
2437}
2438
2440{
2441 ASSERT(trans);
2442
2444 stmt->setUInt32(0, m_id);
2445 trans->Append(stmt);
2446
2447 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_RIGHTS);
2448 stmt->setUInt32(0, m_id);
2449 trans->Append(stmt);
2450
2451 _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_MASTER, loc), GR_RIGHT_ALL);
2452 _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_OFFICER, loc), GR_RIGHT_ALL);
2456}
2457
2458bool Guild::_CreateRank(CharacterDatabaseTransaction trans, std::string_view name, uint32 rights)
2459{
2460 uint8 newRankId = _GetRanksSize();
2461 if (newRankId >= GUILD_RANKS_MAX_COUNT)
2462 return false;
2463
2464 // Ranks represent sequence 0, 1, 2, ... where 0 means guildmaster
2465 RankInfo info(m_id, newRankId, name, rights, 0);
2466 m_ranks.push_back(info);
2467
2468 bool const isInTransaction = bool(trans);
2469 if (!isInTransaction)
2470 trans = CharacterDatabase.BeginTransaction();
2471
2473 info.SaveToDB(trans);
2474
2475 if (!isInTransaction)
2476 CharacterDatabase.CommitTransaction(trans);
2477
2478 return true;
2479}
2480
2481// Updates the number of accounts that are in the guild
2482// Player may have many characters in the guild, but with the same account
2484{
2485 // We use a set to be sure each element will be unique
2486 std::unordered_set<uint32> accountsIdSet;
2487 for (auto const& [guid, member] : m_members)
2488 accountsIdSet.insert(member.GetAccountId());
2489
2490 m_accountsNumber = accountsIdSet.size();
2491}
2492
2493// Detects if player is the guild master.
2494// Check both leader guid and player's rank (otherwise multiple feature with
2495// multiple guild masters won't work)
2496bool Guild::_IsLeader(Player* player) const
2497{
2498 if (player->GetGUID() == m_leaderGuid)
2499 return true;
2500 if (Member const* member = GetMember(player->GetGUID()))
2501 return member->IsRank(GR_GUILDMASTER);
2502 return false;
2503}
2504
2506{
2507 for (uint8 tabId = 0; tabId < _GetPurchasedTabsSize(); ++tabId)
2508 m_bankTabs[tabId].Delete(trans, removeItemsFromDB);
2509
2510 m_bankTabs.clear();
2511}
2512
2514{
2515 if (add)
2516 m_bankMoney += amount;
2517 else
2518 {
2519 // Check if there is enough money in bank.
2520 if (m_bankMoney < amount)
2521 return false;
2522 m_bankMoney -= amount;
2523 }
2524
2526 stmt->setUInt64(0, m_bankMoney);
2527 stmt->setUInt32(1, m_id);
2528 trans->Append(stmt);
2529 return true;
2530}
2531
2533{
2534 bool isInTransaction = bool(trans);
2535 if (!isInTransaction)
2536 trans = CharacterDatabase.BeginTransaction();
2537
2538 m_leaderGuid = leader.GetGUID();
2539 leader.ChangeRank(trans, GR_GUILDMASTER);
2540
2542 stmt->setUInt32(0, m_leaderGuid.GetCounter());
2543 stmt->setUInt32(1, m_id);
2544 trans->Append(stmt);
2545
2546 if (!isInTransaction)
2547 CharacterDatabase.CommitTransaction(trans);
2548}
2549
2551{
2552 if (RankInfo* rankInfo = GetRankInfo(rankId))
2553 rankInfo->SetBankMoneyPerDay(moneyPerDay);
2554}
2555
2556void Guild::_SetRankBankTabRightsAndSlots(uint8 rankId, GuildBankRightsAndSlots rightsAndSlots, bool saveToDB)
2557{
2558 if (rightsAndSlots.GetTabId() >= _GetPurchasedTabsSize())
2559 return;
2560
2561 if (RankInfo* rankInfo = GetRankInfo(rankId))
2562 rankInfo->SetBankTabSlotsAndRights(rightsAndSlots, saveToDB);
2563}
2564
2565inline std::string Guild::_GetRankName(uint8 rankId) const
2566{
2567 if (RankInfo const* rankInfo = GetRankInfo(rankId))
2568 return rankInfo->GetName();
2569 return "<unknown>";
2570}
2571
2573{
2574 if (RankInfo const* rankInfo = GetRankInfo(rankId))
2575 return rankInfo->GetRights();
2576 return 0;
2577}
2578
2580{
2581 if (RankInfo const* rankInfo = GetRankInfo(rankId))
2582 return rankInfo->GetBankMoneyPerDay();
2583 return 0;
2584}
2585
2587{
2588 if (tabId < _GetPurchasedTabsSize())
2589 if (RankInfo const* rankInfo = GetRankInfo(rankId))
2590 return rankInfo->GetBankTabSlotsPerDay(tabId);
2591 return 0;
2592}
2593
2595{
2596 if (RankInfo const* rankInfo = GetRankInfo(rankId))
2597 return rankInfo->GetBankTabRights(tabId);
2598 return 0;
2599}
2600
2601inline int32 Guild::_GetMemberRemainingSlots(Member const& member, uint8 tabId) const
2602{
2603 uint8 rankId = member.GetRankId();
2604 if (rankId == GR_GUILDMASTER)
2605 return static_cast<int32>(GUILD_WITHDRAW_SLOT_UNLIMITED);
2606 if ((_GetRankBankTabRights(rankId, tabId) & GUILD_BANK_RIGHT_VIEW_TAB) != 0)
2607 {
2608 int32 remaining = _GetRankBankTabSlotsPerDay(rankId, tabId) - member.GetBankWithdrawValue(tabId);
2609 if (remaining > 0)
2610 return remaining;
2611 }
2612 return 0;
2613}
2614
2616{
2617 uint8 rankId = member.GetRankId();
2618 if (rankId == GR_GUILDMASTER)
2619 return static_cast<int32>(GUILD_WITHDRAW_MONEY_UNLIMITED);
2620
2622 {
2624 if (remaining > 0)
2625 return remaining;
2626 }
2627 return 0;
2628}
2629
2631{
2632 if (Member* member = GetMember(guid))
2633 {
2634 uint8 rankId = member->GetRankId();
2635 if (rankId != GR_GUILDMASTER
2636 && member->GetBankWithdrawValue(tabId) < _GetRankBankTabSlotsPerDay(rankId, tabId))
2637 member->UpdateBankWithdrawValue(trans, tabId, 1);
2638 }
2639}
2640
2641inline bool Guild::_MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 rights) const
2642{
2643 if (Member const* member = GetMember(guid))
2644 {
2645 // Leader always has full rights
2646 if (member->IsRank(GR_GUILDMASTER) || m_leaderGuid == guid)
2647 return true;
2648 return (_GetRankBankTabRights(member->GetRankId(), tabId) & rights) == rights;
2649 }
2650 return false;
2651}
2652
2653// Add new event log record
2654inline void Guild::_LogEvent(GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2, uint8 newRank)
2655{
2656 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
2657 m_eventLog.AddEvent(trans, m_id, m_eventLog.GetNextGUID(), eventType, playerGuid1, playerGuid2, newRank);
2658 CharacterDatabase.CommitTransaction(trans);
2659
2660 sScriptMgr->OnGuildEvent(this, uint8(eventType), playerGuid1, playerGuid2, newRank);
2661}
2662
2663// Add new bank event log record
2664void Guild::_LogBankEvent(CharacterDatabaseTransaction trans, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType lowguid, uint32 itemOrMoney, uint16 itemStackCount, uint8 destTabId)
2665{
2666 if (tabId > GUILD_BANK_MAX_TABS)
2667 return;
2668
2669 // not logging moves within the same tab
2670 if (eventType == GUILD_BANK_LOG_MOVE_ITEM && tabId == destTabId)
2671 return;
2672
2673 uint8 dbTabId = tabId;
2674 if (BankEventLogEntry::IsMoneyEvent(eventType))
2675 {
2676 tabId = GUILD_BANK_MAX_TABS;
2677 dbTabId = GUILD_BANK_MONEY_LOGS_TAB;
2678 }
2680 pLog.AddEvent(trans, m_id, pLog.GetNextGUID(), eventType, dbTabId, lowguid, itemOrMoney, itemStackCount, destTabId);
2681
2682 sScriptMgr->OnGuildBankEvent(this, uint8(eventType), tabId, lowguid, itemOrMoney, itemStackCount, destTabId);
2683}
2684
2685inline Item* Guild::_GetItem(uint8 tabId, uint8 slotId) const
2686{
2687 if (BankTab const* tab = GetBankTab(tabId))
2688 return tab->GetItem(slotId);
2689 return nullptr;
2690}
2691
2693{
2694 if (BankTab* pTab = GetBankTab(tabId))
2695 pTab->SetItem(trans, slotId, nullptr);
2696}
2697
2698void Guild::_MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAmount)
2699{
2700 // 1. Initialize source item
2701 if (!pSrc->InitItem())
2702 return; // No source item
2703
2704 // 2. Check source item
2705 if (!pSrc->CheckItem(splitedAmount))
2706 return; // Source item or splited amount is invalid
2707
2708 // 3. Check destination rights
2709 if (!pDest->HasStoreRights(pSrc))
2710 return; // Player has no rights to store item in destination
2711
2712 // 4. Check source withdraw rights
2713 if (!pSrc->HasWithdrawRights(pDest))
2714 return; // Player has no rights to withdraw items from source
2715
2716 // 5. Check split
2717 if (splitedAmount)
2718 {
2719 // 5.1. Clone source item
2720 if (!pSrc->CloneItem(splitedAmount))
2721 return; // Item could not be cloned
2722
2723 // 5.2. Move splited item to destination
2724 _DoItemsMove(pSrc, pDest, true, splitedAmount);
2725 }
2726 else // 6. No split
2727 {
2728 // 6.1. Try to merge items in destination (pDest->GetItem() == nullptr)
2729 if (!_DoItemsMove(pSrc, pDest, false)) // Item could not be merged
2730 {
2731 // 6.2. Try to swap items
2732 // 6.2.1. Initialize destination item
2733 if (!pDest->InitItem())
2734 return;
2735
2736 // 6.2.2. Check rights to store item in source (opposite direction)
2737 if (!pSrc->HasStoreRights(pDest))
2738 return; // Player has no rights to store item in source (opposite direction)
2739
2740 if (!pDest->HasWithdrawRights(pSrc))
2741 return; // Player has no rights to withdraw item from destination (opposite direction)
2742
2743 // 6.2.3. Swap items (pDest->GetItem() != nullptr)
2744 _DoItemsMove(pSrc, pDest, true);
2745 }
2746 }
2747 // 7. Send changes
2748 _SendBankContentUpdate(pSrc, pDest);
2749}
2750
2751bool Guild::_DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError, uint32 splitedAmount)
2752{
2753 Item* pDestItem = pDest->GetItem();
2754 bool swap = (pDestItem != nullptr);
2755
2756 Item* pSrcItem = pSrc->GetItem(splitedAmount != 0);
2757 // 1. Can store source item in destination
2758 if (!pDest->CanStore(pSrcItem, swap, sendError))
2759 return false;
2760
2761 // 2. Can store destination item in source
2762 if (swap)
2763 if (!pSrc->CanStore(pDestItem, true, true))
2764 return false;
2765
2766 // GM LOG (@todo move to scripts)
2767 pDest->LogAction(pSrc);
2768 if (swap)
2769 pSrc->LogAction(pDest);
2770
2771 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
2772 // 3. Log bank events
2773 pDest->LogBankEvent(trans, pSrc, pSrcItem->GetCount());
2774 if (swap)
2775 pSrc->LogBankEvent(trans, pDest, pDestItem->GetCount());
2776
2777 // 4. Remove item from source
2778 pSrc->RemoveItem(trans, pDest, splitedAmount);
2779
2780 // 5. Remove item from destination
2781 if (swap)
2782 pDest->RemoveItem(trans, pSrc);
2783
2784 // 6. Store item in destination
2785 pDest->StoreItem(trans, pSrcItem);
2786
2787 // 7. Store item in source
2788 if (swap)
2789 pSrc->StoreItem(trans, pDestItem);
2790
2791 CharacterDatabase.CommitTransaction(trans);
2792 return true;
2793}
2794
2796{
2797 ASSERT(pSrc->IsBank() || pDest->IsBank());
2798
2799 uint8 tabId = 0;
2800 SlotIds slots;
2801 if (pSrc->IsBank()) // B ->
2802 {
2803 tabId = pSrc->GetContainer();
2804 slots.insert(pSrc->GetSlotId());
2805 if (pDest->IsBank()) // B -> B
2806 {
2807 // Same tab - add destination slots to collection
2808 if (pDest->GetContainer() == pSrc->GetContainer())
2809 pDest->CopySlots(slots);
2810 else // Different tabs - send second message
2811 {
2812 SlotIds destSlots;
2813 pDest->CopySlots(destSlots);
2814 _SendBankContentUpdate(pDest->GetContainer(), destSlots);
2815 }
2816 }
2817 }
2818 else if (pDest->IsBank()) // C -> B
2819 {
2820 tabId = pDest->GetContainer();
2821 pDest->CopySlots(slots);
2822 }
2823
2824 _SendBankContentUpdate(tabId, slots);
2825}
2826
2828{
2829 SendBankList(nullptr, tabId, false, &slots);
2830}
2831
2833 Optional<std::string_view> param1 /*= {}*/, Optional<std::string_view> param2 /*= {}*/, Optional<std::string_view> param3 /*= {}*/) const
2834{
2836 event.Type = guildEvent;
2837 if (param1)
2838 event.Params.push_back(*param1);
2839
2840 if (param2)
2841 {
2842 event.Params.resize(2);
2843 event.Params[1] = *param2;
2844 }
2845
2846 if (param3)
2847 {
2848 event.Params.resize(3);
2849 event.Params[2] = *param3;
2850 }
2851
2852 event.Guid = guid;
2853 BroadcastPacket(event.Write());
2854
2855 TC_LOG_DEBUG("guild", "SMSG_GUILD_EVENT [Broadcast] Event: {} ({})", GetGuildEventString(guildEvent), guildEvent);
2856}
2857
2858void Guild::SendBankList(WorldSession* session /* = nullptr*/, uint8 tabId /*= 0*/, bool fullUpdate /*= false*/, SlotIds *slots /*= nullptr*/) const
2859{
2861
2862 packet.Money = m_bankMoney;
2863 packet.Tab = int32(tabId);
2864 packet.FullUpdate = fullUpdate;
2865
2866 if (fullUpdate && !tabId)
2867 {
2868 packet.TabInfo.reserve(_GetPurchasedTabsSize());
2869 for (uint8 i = 0; i < _GetPurchasedTabsSize(); ++i)
2870 {
2872 tabInfo.Name = m_bankTabs[i].GetName();
2873 tabInfo.Icon = m_bankTabs[i].GetIcon();
2874 packet.TabInfo.push_back(tabInfo);
2875 }
2876 }
2877
2878 if (!session || _MemberHasTabRights(session->GetPlayer()->GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB))
2879 {
2880 if (BankTab const* tab = GetBankTab(tabId))
2881 {
2882 auto fillItems = [&](auto begin, auto end, bool skipEmpty)
2883 {
2884 for (auto itr = begin; itr != end; ++itr)
2885 {
2886 if (Item* tabItem = tab->GetItem(*itr))
2887 {
2889
2890 itemInfo.Slot = *itr;
2891 itemInfo.ItemID = tabItem->GetEntry();
2892 itemInfo.RandomPropertiesID = tabItem->GetItemRandomPropertyId();
2893 itemInfo.RandomPropertiesSeed = tabItem->GetItemSuffixFactor();
2894 itemInfo.Count = int32(tabItem->GetCount());
2895 itemInfo.Charges = int32(abs(tabItem->GetSpellCharges()));
2896 itemInfo.EnchantmentID = int32(tabItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT));
2897 itemInfo.Flags = tabItem->GetInt32Value(ITEM_FIELD_FLAGS);
2898
2899 for (uint32 socketSlot = 0; socketSlot < MAX_GEM_SOCKETS; ++socketSlot)
2900 {
2901 if (uint32 enchId = tabItem->GetEnchantmentId(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT + socketSlot)))
2902 {
2904 gem.SocketIndex = socketSlot;
2905 gem.SocketEnchantID = int32(enchId);
2906 itemInfo.SocketEnchant.push_back(gem);
2907 }
2908 }
2909
2910 packet.ItemInfo.push_back(itemInfo);
2911 }
2912 else if (!skipEmpty)
2913 {
2915
2916 itemInfo.Slot = *itr;
2917 itemInfo.ItemID = 0;
2918
2919 packet.ItemInfo.push_back(itemInfo);
2920 }
2921 }
2922
2923 };
2924
2925 if (fullUpdate)
2926 fillItems(boost::make_counting_iterator(uint8(0)), boost::make_counting_iterator(uint8(GUILD_BANK_MAX_SLOTS)), true);
2927 else if (slots && !slots->empty())
2928 fillItems(slots->begin(), slots->end(), false);
2929 }
2930 }
2931
2932 if (session)
2933 {
2934 if (Member const* member = GetMember(session->GetPlayer()->GetGUID()))
2935 packet.WithdrawalsRemaining = _GetMemberRemainingSlots(*member, tabId);
2936
2937 session->SendPacket(packet.Write());
2938 TC_LOG_DEBUG("guild", "SMSG_GUILD_BANK_LIST [{}]: TabId: {}, FullSlots: {}, slots: {}",
2939 session->GetPlayerInfo(), tabId, fullUpdate, packet.WithdrawalsRemaining);
2940 }
2941 else
2942 {
2943 packet.Write();
2944 for (auto const& [guid, member] : m_members)
2945 {
2946 if (!_MemberHasTabRights(member.GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB))
2947 continue;
2948 Player* player = member.FindPlayer();
2949 if (!player)
2950 continue;
2951
2953 player->SendDirectMessage(packet.GetRawPacket());
2954 TC_LOG_DEBUG("guild", "SMSG_GUILD_BANK_LIST [{}]: TabId: {}, FullSlots: {}, slots: {}"
2955 , player->GetName(), tabId, fullUpdate, packet.WithdrawalsRemaining);
2956 }
2957 }
2958}
2959
2961{
2962 for (auto& [guid, member] : m_members)
2963 member.ResetValues();
2964
2966}
Item * NewItemOrBag(ItemTemplate const *proto)
Definition Bag.h:67
#define sCalendarMgr
@ CALENDAR_ERROR_INVITES_EXCEEDED
@ CALENDAR_MAX_INVITES
#define sCharacterCache
@ CHAR_INS_GUILD_MEMBER
@ CHAR_UPD_GUILD_MOTD
@ CHAR_DEL_GUILD_BANK_TABS
@ CHAR_UPD_GUILD_BANK_TAB_TEXT
@ CHAR_DEL_GUILD
@ CHAR_DEL_GUILD_BANK_RIGHTS
@ CHAR_UPD_GUILD_RANK_NAME
@ CHAR_UPD_GUILD_NAME
@ CHAR_INS_GUILD_EVENTLOG
@ CHAR_UPD_GUILD_EMBLEM_INFO
@ CHAR_DEL_GUILD_BANK_EVENTLOGS
@ CHAR_DEL_GUILD_BANK_RIGHTS_FOR_RANK
@ CHAR_DEL_NONEXISTENT_GUILD_BANK_ITEM
@ CHAR_UPD_GUILD_MEMBER_RANK
@ CHAR_INS_GUILD_RANK
@ CHAR_INS_GUILD
@ CHAR_UPD_GUILD_RANK_BANK_MONEY
@ CHAR_UPD_GUILD_LEADER
@ CHAR_UPD_GUILD_RANK_RIGHTS
@ CHAR_UPD_GUILD_MEMBER_PNOTE
@ CHAR_INS_GUILD_BANK_TAB
@ CHAR_SEL_CHAR_DATA_FOR_GUILD
@ CHAR_UPD_GUILD_BANK_MONEY
@ CHAR_DEL_GUILD_BANK_TAB
@ CHAR_DEL_GUILD_MEMBERS
@ CHAR_UPD_GUILD_MEMBER_OFFNOTE
@ CHAR_DEL_GUILD_BANK_EVENTLOG
@ CHAR_DEL_GUILD_MEMBER
@ CHAR_DEL_GUILD_BANK_ITEMS
@ CHAR_DEL_GUILD_BANK_ITEM
@ CHAR_DEL_GUILD_EVENTLOG
@ CHAR_UPD_GUILD_INFO
@ CHAR_DEL_GUILD_EVENTLOGS
@ CHAR_INS_GUILD_BANK_EVENTLOG
@ CHAR_DEL_GUILD_RANKS
@ CHAR_DEL_GUILD_RANK
@ CHAR_INS_GUILD_BANK_ITEM
@ CHAR_UPD_GUILD_BANK_TAB_INFO
@ CHAR_INS_GUILD_MEMBER_WITHDRAW
@ CHAR_INS_GUILD_BANK_RIGHT
LocaleConstant
Definition Common.h:48
#define DEFAULT_LOCALE
Definition Common.h:62
@ DAY
Definition Common.h:31
#define sConfigMgr
Definition Config.h:60
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint8_t uint8
Definition Define.h:135
int8_t int8
Definition Define.h:131
int32_t int32
Definition Define.h:129
uint64_t uint64
Definition Define.h:132
uint16_t uint16
Definition Define.h:134
uint32_t uint32
Definition Define.h:133
#define ASSERT
Definition Errors.h:68
#define sGuildMgr
Definition GuildMgr.h:59
uint32 GetGuildBankTabPrice(uint8 tabId)
Definition Guild.cpp:97
uint32 const EMBLEM_PRICE
Definition Guild.cpp:44
size_t const MAX_GUILD_BANK_TAB_TEXT_LEN
Definition Guild.cpp:42
char const * GetGuildEventString(GuildEvents event)
Definition Guild.cpp:47
GuildEvents
Definition Guild.h:154
@ GE_LEFT
Definition Guild.h:159
@ GE_LEADER_IS
Definition Guild.h:161
@ GE_TABARDCHANGE
Definition Guild.h:164
@ GE_REMOVED
Definition Guild.h:160
@ GE_JOINED
Definition Guild.h:158
@ GE_RANK_DELETED
Definition Guild.h:166
@ GE_GUILDBANKBAGSLOTS_CHANGED
Definition Guild.h:169
@ GE_PROMOTION
Definition Guild.h:155
@ GE_BANK_TAB_UPDATED
Definition Guild.h:171
@ GE_BANK_MONEY_SET
Definition Guild.h:172
@ GE_DISBANDED
Definition Guild.h:163
@ GE_BANK_TEXT_CHANGED
Definition Guild.h:174
@ GE_SIGNED_OFF
Definition Guild.h:168
@ GE_MOTD
Definition Guild.h:157
@ GE_BANK_TAB_PURCHASED
TODO: Sent when items are moved in gbank - all players with bank open will send tab query.
Definition Guild.h:170
@ GE_LEADER_CHANGED
Definition Guild.h:162
@ GE_SIGNED_ON
Definition Guild.h:167
@ GE_DEMOTION
Definition Guild.h:156
@ GE_BANK_TAB_AND_MONEY_UPDATED
Definition Guild.h:173
@ GE_RANK_UPDATED
Definition Guild.h:165
@ GUILD_RANKS_MIN_COUNT
Definition Guild.h:53
@ GUILD_EVENT_LOG_GUID_UNDEFINED
Definition Guild.h:58
@ GUILD_WITHDRAW_SLOT_UNLIMITED
Definition Guild.h:57
@ GUILD_BANK_MONEY_LOGS_TAB
Definition Guild.h:52
@ GUILD_WITHDRAW_MONEY_UNLIMITED
Definition Guild.h:56
@ GUILD_BANK_MAX_SLOTS
Definition Guild.h:51
@ GUILD_RANKS_MAX_COUNT
Definition Guild.h:54
@ GUILD_BANK_MAX_TABS
Definition Guild.h:50
@ GUILD_RANK_NONE
Definition Guild.h:55
@ GUILDMEMBER_STATUS_NONE
Definition Guild.h:222
@ GUILDMEMBER_STATUS_ONLINE
Definition Guild.h:223
@ GUILD_BANK_RIGHT_VIEW_TAB
Definition Guild.h:179
@ GUILD_BANK_RIGHT_DEPOSIT_ITEM
Definition Guild.h:183
constexpr uint64 GUILD_BANK_MONEY_LIMIT
Definition Guild.h:62
GuildCommandType
Definition Guild.h:106
@ GUILD_COMMAND_CHANGE_LEADER
Definition Guild.h:114
@ GUILD_COMMAND_INVITE
Definition Guild.h:108
@ GUILD_COMMAND_MOVE_ITEM
Definition Guild.h:121
@ GUILD_COMMAND_QUIT
Definition Guild.h:109
@ GUILD_COMMAND_PROMOTE
Definition Guild.h:111
@ GUILD_COMMAND_DEMOTE
Definition Guild.h:112
@ GUILD_COMMAND_PUBLIC_NOTE
Definition Guild.h:119
@ GUILD_COMMAND_CHANGE_RANK
Definition Guild.h:118
@ GUILD_COMMAND_REMOVE
Definition Guild.h:113
@ GUILD_COMMAND_EDIT_MOTD
Definition Guild.h:115
GuildCommandError
Definition Guild.h:126
@ ERR_GUILD_PERMISSIONS
Definition Guild.h:136
@ ERR_ALREADY_IN_GUILD_S
Definition Guild.h:130
@ ERR_GUILD_LEADER_LEAVE
Definition Guild.h:135
@ ERR_GUILD_COMMAND_SUCCESS
Definition Guild.h:127
@ ERR_GUILD_NOT_ALLIED
Definition Guild.h:140
@ ERR_GUILD_BANK_FULL
Definition Guild.h:149
@ ERR_GUILD_PLAYER_NOT_FOUND_S
Definition Guild.h:139
@ ERR_GUILD_RANK_TOO_LOW_S
Definition Guild.h:142
@ ERR_GUILD_RANK_TOO_HIGH_S
Definition Guild.h:141
@ ERR_ALREADY_INVITED_TO_GUILD_S
Definition Guild.h:132
@ ERR_GUILD_NAME_INVALID
Definition Guild.h:133
std::set< uint8 > SlotIds
Definition Guild.h:281
@ GR_GUILDMASTER
Definition Guild.h:73
@ GR_OFFICER
Definition Guild.h:74
GuildBankEventLogTypes
Definition Guild.h:188
@ GUILD_BANK_LOG_MOVE_ITEM
Definition Guild.h:191
@ GUILD_BANK_LOG_WITHDRAW_ITEM
Definition Guild.h:190
@ GUILD_BANK_LOG_DEPOSIT_MONEY
Definition Guild.h:192
@ GUILD_BANK_LOG_DEPOSIT_ITEM
Definition Guild.h:189
@ GUILD_BANK_LOG_WITHDRAW_MONEY
Definition Guild.h:193
@ GUILD_BANK_LOG_REPAIR_MONEY
Definition Guild.h:194
@ GUILD_BANK_LOG_MOVE_ITEM2
Definition Guild.h:195
@ GR_RIGHT_EMPTY
Definition Guild.h:84
@ GR_RIGHT_EOFFNOTE
Definition Guild.h:96
@ GR_RIGHT_GCHATSPEAK
Definition Guild.h:86
@ GR_RIGHT_OFFCHATSPEAK
Definition Guild.h:88
@ GR_RIGHT_ALL
Definition Guild.h:102
@ GR_RIGHT_EPNOTE
Definition Guild.h:94
@ GR_RIGHT_OFFCHATLISTEN
Definition Guild.h:87
@ GR_RIGHT_GCHATLISTEN
Definition Guild.h:85
@ GR_RIGHT_SETMOTD
Definition Guild.h:93
@ GR_RIGHT_MODIFY_GUILD_INFO
Definition Guild.h:97
@ GR_RIGHT_VIEWOFFNOTE
Definition Guild.h:95
@ GR_RIGHT_WITHDRAW_REPAIR
Definition Guild.h:99
@ GR_RIGHT_REMOVE
Definition Guild.h:90
@ GR_RIGHT_WITHDRAW_GOLD
Definition Guild.h:100
@ GR_RIGHT_INVITE
Definition Guild.h:89
@ GR_RIGHT_DEMOTE
Definition Guild.h:92
@ GR_RIGHT_PROMOTE
Definition Guild.h:91
@ GUILD_MEMBER_DATA_LEVEL
Definition Guild.h:67
@ GUILD_MEMBER_DATA_ZONEID
Definition Guild.h:66
GuildEmblemError
Definition Guild.h:211
@ ERR_GUILDEMBLEM_NOTGUILDMASTER
Definition Guild.h:215
@ ERR_GUILDEMBLEM_NOTENOUGHMONEY
Definition Guild.h:216
@ ERR_GUILDEMBLEM_SUCCESS
Definition Guild.h:212
GuildEventLogTypes
Definition Guild.h:201
@ GUILD_EVENT_LOG_LEAVE_GUILD
Definition Guild.h:207
@ GUILD_EVENT_LOG_PROMOTE_PLAYER
Definition Guild.h:204
@ GUILD_EVENT_LOG_UNINVITE_PLAYER
Definition Guild.h:206
@ GUILD_EVENT_LOG_INVITE_PLAYER
Definition Guild.h:202
@ GUILD_EVENT_LOG_DEMOTE_PLAYER
Definition Guild.h:205
@ GUILD_EVENT_LOG_JOIN_GUILD
Definition Guild.h:203
EnchantmentSlot
@ PERM_ENCHANTMENT_SLOT
@ SOCK_ENCHANTMENT_SLOT
InventoryResult
Definition ItemDefines.h:25
@ EQUIP_ERR_DESTROY_NONEMPTY_BAG
Definition ItemDefines.h:57
@ EQUIP_ERR_BANK_FULL
Definition ItemDefines.h:77
@ EQUIP_ERR_WRONG_BAG_TYPE
Definition ItemDefines.h:41
@ EQUIP_ERR_DROP_BOUND_ITEM
Definition ItemDefines.h:50
@ EQUIP_ERR_ITEM_NOT_FOUND
Definition ItemDefines.h:49
@ EQUIP_ERR_OK
Definition ItemDefines.h:26
@ EQUIP_ERR_CANT_SWAP
Definition ItemDefines.h:47
@ EQUIP_ERR_CANT_STACK
Definition ItemDefines.h:45
#define MAX_GEM_SOCKETS
Definition Item.h:40
@ ITEM_CHANGED
Definition Item.h:54
@ ITEM_NEW
Definition Item.h:55
@ LANG_GUILD_MASTER
Definition Language.h:766
@ LANG_GUILD_VETERAN
Definition Language.h:768
@ LANG_GUILD_OFFICER
Definition Language.h:767
@ LANG_GUILD_INITIATE
Definition Language.h:770
@ LANG_GUILD_MEMBER
Definition Language.h:769
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
#define sLog
Definition Log.h:130
#define sObjectMgr
Definition ObjectMgr.h:1721
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
uint32 const MAX_MONEY_AMOUNT
Definition Player.cpp:119
#define sScriptMgr
Definition ScriptMgr.h:1168
Language
@ CHAT_MSG_GUILD
@ CHAT_MSG_OFFICER
#define MAX_CLASSES
@ GOLD
@ GUILD_CHARTER_TYPE
@ NULL_SLOT
Definition Unit.h:62
@ ITEM_FIELD_FLAGS
@ ITEM_FIELD_CONTAINED
void utf8truncate(std::string &utf8str, size_t len)
Definition Util.cpp:362
static size_t BuildChatPacket(WorldPacket &data, ChatMsg chatType, Language language, ObjectGuid senderGUID, ObjectGuid receiverGUID, std::string_view message, uint8 chatTag, std::string const &senderName="", std::string const &receiverName="", uint32 achievementId=0, bool gmMessage=false, std::string const &channelName="")
Definition Chat.cpp:193
void SaveToDB(ObjectGuid::LowType guildId) const
Definition Guild.cpp:722
uint32 GetStyle() const
Definition Guild.h:239
uint32 GetColor() const
Definition Guild.h:240
void LoadFromDB(Field *fields)
Definition Guild.cpp:713
uint32 GetBackgroundColor() const
Definition Guild.h:243
uint32 GetBorderStyle() const
Definition Guild.h:241
void ReadPacket(WorldPackets::Guild::SaveGuildEmblem &packet)
Definition Guild.cpp:704
uint32 GetBorderColor() const
Definition Guild.h:242
Class used to access individual fields of database query result.
Definition Field.h:92
uint8 GetUInt8() const
Definition Field.cpp:29
std::string GetString() const
Definition Field.cpp:125
uint64 GetUInt64() const
Definition Field.cpp:77
uint32 GetUInt32() const
Definition Field.cpp:61
int32 GetSlots() const
Definition Guild.h:272
void SetGuildMasterValues()
Definition Guild.h:261
int8 GetRights() const
Definition Guild.h:273
int8 GetTabId() const
Definition Guild.h:271
void SetTabId(uint8 _tabId)
Definition Guild.h:267
void SaveToDB(CharacterDatabaseTransaction trans) const override
Definition Guild.cpp:203
void WritePacket(WorldPackets::Guild::GuildBankLogQueryResults &packet) const
Definition Guild.cpp:227
bool IsMoneyEvent() const
Definition Guild.h:409
void LogBankEvent(CharacterDatabaseTransaction trans, MoveItemData *pFrom, uint32 count) const override
Definition Guild.cpp:922
bool _ReserveSpace(uint8 slotId, Item *pItem, Item *pItemDest, uint32 &count)
Definition Guild.cpp:981
void LogAction(MoveItemData *pFrom) const override
Definition Guild.cpp:935
void CanStoreItemInTab(Item *pItem, uint8 skipSlotId, bool merge, uint32 &count)
Definition Guild.cpp:1004
bool InitItem() override
Definition Guild.cpp:850
Item * StoreItem(CharacterDatabaseTransaction trans, Item *pItem) override
Definition Guild.cpp:898
Item * _StoreItem(CharacterDatabaseTransaction trans, BankTab *pTab, Item *pItem, ItemPosCount &pos, bool clone) const
Definition Guild.cpp:948
void RemoveItem(CharacterDatabaseTransaction trans, MoveItemData *pOther, uint32 splitedAmount) override
Definition Guild.cpp:879
bool HasStoreRights(MoveItemData *pOther) const override
Definition Guild.cpp:856
InventoryResult CanStore(Item *pItem, bool swap) override
Definition Guild.cpp:1024
bool HasWithdrawRights(MoveItemData *pOther) const override
Definition Guild.cpp:865
void LoadFromDB(Field *fields)
Definition Guild.cpp:374
std::string const & GetName() const
Definition Guild.h:524
std::string const & GetIcon() const
Definition Guild.h:525
bool SetItem(CharacterDatabaseTransaction trans, uint8 slotId, Item *pItem)
Definition Guild.cpp:468
void SetText(std::string_view text)
Definition Guild.cpp:451
void Delete(CharacterDatabaseTransaction trans, bool removeItemsFromDB=false)
Definition Guild.cpp:420
Item * GetItem(uint8 slotId) const
Definition Guild.h:528
bool LoadItemFromDB(Field *fields)
Definition Guild.cpp:381
BankTab(ObjectGuid::LowType guildId, uint8 tabId)
Definition Guild.cpp:371
void SendText(Guild const *guild, WorldSession *session) const
Definition Guild.cpp:499
void SetInfo(std::string_view name, std::string_view icon)
Definition Guild.cpp:435
void SaveToDB(CharacterDatabaseTransaction trans) const override
Definition Guild.cpp:169
void WritePacket(WorldPackets::Guild::GuildEventLogQueryResults &packet) const
Definition Guild.cpp:188
LogEntry(ObjectGuid::LowType guildId, uint32 guid)
Definition Guild.cpp:166
void LoadEvent(Ts &&... args)
Definition Guild.cpp:134
void AddEvent(CharacterDatabaseTransaction trans, Ts &&... args)
Definition Guild.cpp:142
uint32 GetNextGUID()
Definition Guild.cpp:155
bool CanInsert() const
Definition Guild.h:444
std::string const & GetName() const
Definition Guild.h:309
void UpdateBankWithdrawValue(CharacterDatabaseTransaction trans, uint8 tabId, uint32 amount)
Definition Guild.cpp:670
bool IsRankNotLower(uint8 rankId) const
Definition Guild.h:326
Player * FindConnectedPlayer() const
Definition Guild.cpp:662
void ChangeRank(CharacterDatabaseTransaction trans, uint8 newRank)
Definition Guild.cpp:578
bool IsRank(uint8 rankId) const
Definition Guild.h:325
void SetPublicNote(std::string_view publicNote)
Definition Guild.cpp:552
void UpdateLogoutTime()
Definition Guild.cpp:592
int32 GetBankWithdrawValue(uint8 tabId) const
Definition Guild.cpp:694
void ResetValues()
Definition Guild.cpp:685
void SetOfficerNote(std::string_view officerNote)
Definition Guild.cpp:565
bool LoadFromDB(Field *fields)
Definition Guild.cpp:611
bool CheckStats() const
Definition Guild.cpp:641
void ResetFlags()
Definition Guild.h:303
Member(ObjectGuid::LowType guildId, ObjectGuid guid, uint8 rankId)
Definition Guild.cpp:519
uint8 GetRankId() const
Definition Guild.h:311
ObjectGuid GetGUID() const
Definition Guild.h:308
void SaveToDB(CharacterDatabaseTransaction trans) const
Definition Guild.cpp:597
Player * FindPlayer() const
Definition Guild.cpp:657
void SetStats(Player *player)
Definition Guild.cpp:532
MoveItemData(Guild *guild, Player *player, uint8 container, uint8 slotId)
Definition Guild.cpp:735
virtual void LogAction(MoveItemData *pFrom) const
Definition Guild.cpp:775
virtual Item * StoreItem(CharacterDatabaseTransaction trans, Item *pItem)=0
Item * GetItem(bool isCloned=false) const
Definition Guild.h:572
virtual void LogBankEvent(CharacterDatabaseTransaction trans, MoveItemData *pFrom, uint32 count) const =0
uint8 GetSlotId() const
Definition Guild.h:574
uint8 GetContainer() const
Definition Guild.h:573
virtual bool CheckItem(uint32 &splitedAmount)
Definition Guild.cpp:744
virtual bool HasWithdrawRights(MoveItemData *) const
Definition Guild.h:556
virtual bool HasStoreRights(MoveItemData *) const
Definition Guild.h:554
void CopySlots(SlotIds &ids) const
Definition Guild.cpp:784
virtual bool IsBank() const =0
bool CloneItem(uint32 count)
Definition Guild.cpp:763
virtual bool InitItem()=0
virtual ~MoveItemData()
Definition Guild.cpp:740
virtual void RemoveItem(CharacterDatabaseTransaction trans, MoveItemData *pOther, uint32 splitedAmount=0)=0
bool CanStore(Item *pItem, bool swap, bool sendError)
Definition Guild.cpp:754
InventoryResult CanStore(Item *pItem, bool swap) override
Definition Guild.cpp:844
Item * StoreItem(CharacterDatabaseTransaction trans, Item *pItem) override
Definition Guild.cpp:828
bool InitItem() override
Definition Guild.cpp:791
void LogBankEvent(CharacterDatabaseTransaction trans, MoveItemData *pFrom, uint32 count) const override
Definition Guild.cpp:836
void RemoveItem(CharacterDatabaseTransaction trans, MoveItemData *pOther, uint32 splitedAmount=0) override
Definition Guild.cpp:812
void CreateMissingTabsIfNeeded(uint8 ranks, CharacterDatabaseTransaction trans, bool logOnCreate=false)
Definition Guild.cpp:277
uint8 GetId() const
Definition Guild.h:477
void SetBankMoneyPerDay(uint32 money)
Definition Guild.cpp:333
void SetName(std::string_view name)
Definition Guild.cpp:302
void SetRights(uint32 rights)
Definition Guild.cpp:316
void SetBankTabSlotsAndRights(GuildBankRightsAndSlots rightsAndSlots, bool saveToDB)
Definition Guild.cpp:350
void SaveToDB(CharacterDatabaseTransaction trans) const
Definition Guild.cpp:266
void LoadFromDB(Field *fields)
Definition Guild.cpp:256
Definition Guild.h:284
void HandleSetNewGuildMaster(WorldSession *session, std::string_view name)
Definition Guild.cpp:1366
void HandleSetInfo(WorldSession *session, std::string_view info)
Definition Guild.cpp:1327
std::string _GetRankName(uint8 rankId) const
Definition Guild.cpp:2565
int8 _GetRankBankTabRights(uint8 rankId, uint8 tabId) const
Definition Guild.cpp:2594
void SwapItemsWithInventory(Player *player, bool toChar, uint8 tabId, uint8 slotId, uint8 playerBag, uint8 playerSlotId, uint32 splitedAmount)
Definition Guild.cpp:2376
void HandleRemoveMember(WorldSession *session, std::string_view name)
Definition Guild.cpp:1568
void _SetRankBankTabRightsAndSlots(uint8 rankId, GuildBankRightsAndSlots rightsAndSlots, bool saveToDB=true)
Definition Guild.cpp:2556
bool ChangeMemberRank(CharacterDatabaseTransaction trans, ObjectGuid guid, uint8 newRank)
Definition Guild.cpp:2333
uint64 m_bankMoney
Definition Guild.h:746
void BroadcastPacket(WorldPacket const *packet) const
Definition Guild.cpp:2149
int32 _GetRankBankTabSlotsPerDay(uint8 rankId, uint8 tabId) const
Definition Guild.cpp:2586
int32 _GetMemberRemainingMoney(Member const &member) const
Definition Guild.cpp:2615
void ResetTimes()
Definition Guild.cpp:2960
void HandleSetMOTD(WorldSession *session, std::string_view motd)
Definition Guild.cpp:1304
void _SetRankBankMoneyPerDay(uint8 rankId, uint32 moneyPerDay)
Definition Guild.cpp:2550
void LoadBankRightFromDB(Field *fields)
Definition Guild.cpp:1972
static void _DeleteMemberFromDB(CharacterDatabaseTransaction trans, ObjectGuid::LowType lowguid)
Definition Guild.cpp:2407
ObjectGuid GetLeaderGUID() const
Definition Guild.h:639
bool AddMember(CharacterDatabaseTransaction trans, ObjectGuid guid, uint8 rankId=GUILD_RANK_NONE)
Definition Guild.cpp:2187
uint32 _GetRankRights(uint8 rankId) const
Definition Guild.cpp:2572
void SwapItems(Player *player, uint8 tabId, uint8 slotId, uint8 destTabId, uint8 destSlotId, uint32 splitedAmount)
Definition Guild.cpp:2362
~Guild()
Definition Guild.cpp:1080
void _DeleteBankItems(CharacterDatabaseTransaction trans, bool removeItemsFromDB=false)
Definition Guild.cpp:2505
Guild()
Definition Guild.cpp:1071
void _BroadcastEvent(GuildEvents guildEvent, ObjectGuid guid, Optional< std::string_view > param1={}, Optional< std::string_view > param2={}, Optional< std::string_view > param3={}) const
Definition Guild.cpp:2832
bool LoadMemberFromDB(Field *fields)
Definition Guild.cpp:1947
std::vector< BankTab > m_bankTabs
Definition Guild.h:750
void OnPlayerStatusChange(Player *player, uint32 flag, bool state)
Definition Guild.cpp:1212
void HandleLeaveMember(WorldSession *session)
Definition Guild.cpp:1538
void HandleRemoveRank(WorldSession *session, uint8 rankId)
Definition Guild.cpp:1673
ObjectGuid::LowType GetId() const
Definition Guild.h:638
void SendPermissions(WorldSession *session) const
Definition Guild.cpp:1853
void UpdateMemberData(Player *player, uint8 dataid, uint32 value)
Definition Guild.cpp:1192
void HandleQuery(WorldSession *session)
Definition Guild.cpp:1282
void BroadcastPacketToRank(WorldPacket const *packet, uint8 rankId) const
Definition Guild.cpp:2141
uint32 m_accountsNumber
Definition Guild.h:745
void HandleSetRankInfo(WorldSession *session, uint8 rankId, std::string_view name, uint32 rights, uint32 moneyPerDay, std::array< GuildBankRightsAndSlots, GUILD_BANK_MAX_TABS > const &rightsAndSlots)
Definition Guild.cpp:1423
time_t m_createdDate
Definition Guild.h:742
int32 _GetMemberRemainingSlots(Member const &member, uint8 tabId) const
Definition Guild.cpp:2601
void SendEventLog(WorldSession *session) const
Definition Guild.cpp:1807
void SendBankList(WorldSession *session=nullptr, uint8 tabId=0, bool fullUpdate=false, SlotIds *slots=nullptr) const
Definition Guild.cpp:2858
uint8 _GetPurchasedTabsSize() const
Definition Guild.h:766
bool LoadBankItemFromDB(Field *fields)
Definition Guild.cpp:2046
void BroadcastToGuild(WorldSession *session, bool officerOnly, std::string_view msg, uint32 language=LANG_UNIVERSAL) const
Definition Guild.cpp:2127
void _LogBankEvent(CharacterDatabaseTransaction trans, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint32 itemOrMoney, uint16 itemStackCount=0, uint8 destTabId=0)
Definition Guild.cpp:2664
std::array< LogHolder< BankEventLogEntry >, GUILD_BANK_MAX_TABS+1 > m_bankEventLog
Definition Guild.h:754
bool LoadFromDB(Field *fields)
Definition Guild.cpp:1916
std::vector< RankInfo > m_ranks
Definition Guild.h:748
static void SendCommandResult(WorldSession *session, GuildCommandType type, GuildCommandError errCode, std::string_view param="")
Definition Guild.cpp:106
void HandleInviteMember(WorldSession *session, std::string_view name)
Definition Guild.cpp:1473
void SendLoginInfo(WorldSession *session)
Definition Guild.cpp:1892
std::string m_name
Definition Guild.h:738
RankInfo const * GetRankInfo(uint8 rankId) const
Definition Guild.h:760
std::unordered_map< ObjectGuid, Member > m_members
Definition Guild.h:749
std::string const & GetName() const
Definition Guild.h:640
void SetBankTabText(uint8 tabId, std::string_view text)
Definition Guild.cpp:2390
int32 _GetRankBankMoneyPerDay(uint8 rankId) const
Definition Guild.cpp:2579
void HandleUpdateMemberRank(WorldSession *session, std::string_view name, bool demote)
Definition Guild.cpp:1599
void _CreateNewBankTab()
Definition Guild.cpp:2415
bool HandleMemberWithdrawMoney(WorldSession *session, uint32 amount, bool repair=false)
Definition Guild.cpp:1728
bool SetName(std::string_view name)
Definition Guild.cpp:1222
ObjectGuid m_leaderGuid
Definition Guild.h:739
void _UpdateAccountsNumber()
Definition Guild.cpp:2483
LogHolder< EventLogEntry > m_eventLog
Definition Guild.h:753
Member const * GetMember(ObjectGuid guid) const
Definition Guild.h:770
bool Create(Player *pLeader, std::string_view name)
Definition Guild.cpp:1087
bool DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bool isDisbanding=false, bool isKicked=false)
Definition Guild.cpp:2269
bool LoadEventLogFromDB(Field *fields)
Definition Guild.cpp:1980
void HandleAddNewRank(WorldSession *session, std::string_view name)
Definition Guild.cpp:1653
void HandleSetBankTabInfo(WorldSession *session, uint8 tabId, std::string_view name, std::string_view icon)
Definition Guild.cpp:1393
void HandleMemberLogout(WorldSession *session)
Definition Guild.cpp:1771
bool IsMember(ObjectGuid guid) const
Definition Guild.cpp:2347
bool _MemberHasTabRights(ObjectGuid guid, uint8 tabId, uint32 rights) const
Definition Guild.cpp:2641
void _RemoveItem(CharacterDatabaseTransaction trans, uint8 tabId, uint8 slotId)
Definition Guild.cpp:2692
bool _IsLeader(Player *player) const
Definition Guild.cpp:2496
bool LoadBankEventLogFromDB(Field *fields)
Definition Guild.cpp:1997
void _LogEvent(GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2=0, uint8 newRank=0)
Definition Guild.cpp:2654
std::string m_motd
Definition Guild.h:740
void HandleDisband(WorldSession *session)
Definition Guild.cpp:1783
static void SendSaveEmblemResult(WorldSession *session, GuildEmblemError errCode)
Definition Guild.cpp:118
void SendBankTabText(WorldSession *session, uint8 tabId) const
Definition Guild.cpp:1847
uint8 _GetRanksSize() const
Definition Guild.h:759
void HandleSetEmblem(WorldSession *session, EmblemInfo const &emblemInfo)
Definition Guild.cpp:1346
BankTab * GetBankTab(uint8 tabId)
Definition Guild.h:767
bool _ModifyBankMoney(CharacterDatabaseTransaction trans, uint64 amount, bool add)
Definition Guild.cpp:2513
void SendBankTabData(WorldSession *session, uint8 tabId, bool sendAllSlots) const
Definition Guild.cpp:1841
void Disband()
Definition Guild.cpp:1142
bool _DoItemsMove(MoveItemData *pSrc, MoveItemData *pDest, bool sendError, uint32 splitedAmount=0)
Definition Guild.cpp:2751
bool _CreateRank(CharacterDatabaseTransaction trans, std::string_view name, uint32 rights)
Definition Guild.cpp:2458
void SendInfo(WorldSession *session) const
Definition Guild.cpp:1794
void _SendBankContentUpdate(MoveItemData *pSrc, MoveItemData *pDest) const
Definition Guild.cpp:2795
void _SetLeader(CharacterDatabaseTransaction trans, Member &leader)
Definition Guild.cpp:2532
uint64 GetMemberAvailableMoneyForRepairItems(ObjectGuid guid) const
Definition Guild.cpp:2352
EmblemInfo m_emblemInfo
Definition Guild.h:744
bool _HasRankRight(Player *player, uint32 right) const
Definition Guild.cpp:2399
void HandleSetMemberNote(WorldSession *session, std::string_view note, std::string_view name, bool isPublic)
Definition Guild.cpp:1407
void HandleMemberDepositMoney(WorldSession *session, uint32 amount)
Definition Guild.cpp:1696
void _CreateDefaultGuildRanks(CharacterDatabaseTransaction trans, LocaleConstant loc)
Definition Guild.cpp:2439
void HandleAcceptMember(WorldSession *session)
Definition Guild.cpp:1527
void MassInviteToEvent(WorldSession *session, uint32 minLevel, uint32 maxLevel, uint32 minRank)
Definition Guild.cpp:2156
std::string m_info
Definition Guild.h:741
Item * _GetItem(uint8 tabId, uint8 slotId) const
Definition Guild.cpp:2685
void SendMoneyInfo(WorldSession *session) const
Definition Guild.cpp:1877
void SendBankLog(WorldSession *session, uint8 tabId) const
Definition Guild.cpp:1821
void LoadBankTabFromDB(Field *fields)
Definition Guild.cpp:2037
void HandleRoster(WorldSession *session)
Definition Guild.cpp:1235
uint8 _GetLowestRankId() const
Definition Guild.h:764
void _MoveItems(MoveItemData *pSrc, MoveItemData *pDest, uint32 splitedAmount)
Definition Guild.cpp:2698
bool Validate()
Definition Guild.cpp:2059
void HandleBuyBankTab(WorldSession *session, uint8 tabId)
Definition Guild.cpp:1443
void _UpdateMemberWithdrawSlots(CharacterDatabaseTransaction trans, ObjectGuid guid, uint8 tabId)
Definition Guild.cpp:2630
void HandleRemoveLowestRank(WorldSession *session)
Definition Guild.cpp:1668
ObjectGuid::LowType m_id
Definition Guild.h:737
void LoadRankFromDB(Field *fields)
Definition Guild.cpp:1938
Definition Item.h:62
virtual bool LoadFromDB(ObjectGuid::LowType guid, ObjectGuid owner_guid, Field *fields, uint32 entry)
Definition Item.cpp:409
virtual void SaveToDB(CharacterDatabaseTransaction trans)
Definition Item.cpp:323
Item * CloneItem(uint32 count, Player const *player=nullptr) const
Definition Item.cpp:1071
void SetCount(uint32 value)
Definition Item.cpp:1250
ItemTemplate const * GetTemplate() const
Definition Item.cpp:535
bool IsSoulBound() const
Definition Item.h:81
void FSetState(ItemUpdateState state)
Definition Item.h:172
uint32 GetCount() const
Definition Item.h:119
void SetOwnerGUID(ObjectGuid guid)
Definition Item.h:77
uint32 GetMaxStackCount() const
Definition Item.h:121
static void DeleteFromDB(CharacterDatabaseTransaction trans, ObjectGuid::LowType itemGuid)
Definition Item.cpp:506
LowType GetCounter() const
Definition ObjectGuid.h:156
static ObjectGuid const Empty
Definition ObjectGuid.h:140
std::string ToString() const
uint32 LowType
Definition ObjectGuid.h:142
static bool IsValidCharterName(std::string_view name)
void SetGuidValue(uint16 index, ObjectGuid value)
Definition Object.cpp:699
uint32 GetEntry() const
Definition Object.h:81
virtual void AddToWorld()
Definition Object.cpp:126
virtual void RemoveFromWorld()
Definition Object.cpp:145
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
bool HasIgnore(ObjectGuid const &ignoreGuid)
uint32 GetTeam() const
Definition Player.h:1832
void SaveGoldToDB(CharacterDatabaseTransaction trans) const
Definition Player.cpp:19317
static uint32 GetZoneIdFromDB(ObjectGuid guid)
Definition Player.cpp:6722
Gender GetNativeGender() const override
Definition Player.h:1039
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6161
bool ModifyMoney(int32 amount, bool sendError=true)
Definition Player.cpp:22339
WorldSession * GetSession() const
Definition Player.h:1719
bool HasEnoughMoney(uint32 amount) const
Definition Player.h:1410
void SetInGuild(ObjectGuid::LowType guildId)
Definition Player.cpp:26257
ObjectGuid::LowType GetGuildId() const
Definition Player.h:1620
void SetGuildRank(uint8 rankId)
Definition Player.h:1617
ObjectGuid::LowType GetGuildIdInvited() const
Definition Player.h:1622
PlayerSocial * GetSocial()
Definition Player.h:982
void SetGuildIdInvited(ObjectGuid::LowType GuildId)
Definition Player.h:1619
static void RemovePetitionsAndSigns(ObjectGuid guid, CharterTypes type)
Definition Player.cpp:20953
void setUInt16(uint8 index, uint16 value)
void setUInt32(uint8 index, uint32 value)
void setUInt64(uint8 index, uint64 value)
void setUInt8(uint8 index, uint8 value)
void setString(uint8 index, std::string const &value)
uint8 GetClass() const
Definition Unit.h:895
uint8 GetLevel() const
Definition Unit.h:889
std::string const & GetName() const
Definition Object.h:382
uint32 GetZoneId() const
Definition Object.h:373
T & emplace_back(Args &&... args)
std::vector< CalendarEventInitialInviteInfo > Invites
std::vector< GuildBankLogEntry > Entry
WorldPacket const * Write() override
void SetWithdrawalsRemaining(int32 withdrawalsRemaining)
std::vector< GuildBankTabInfo > TabInfo
std::vector< GuildBankItemInfo > ItemInfo
WorldPacket const * Write() override
Array< std::string_view, 3 > Params
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
std::array< GuildRankTabPermissions, GUILD_BANK_MAX_TABS > Tab
WorldPacket const * Write() override
std::vector< GuildRankData > RankData
std::vector< GuildRosterMemberData > MemberData
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * GetRawPacket() const
Definition Packet.h:38
Player session in the World.
void SendPacket(WorldPacket const *packet)
Send a packet to the client.
LocaleConstant GetSessionDbLocaleIndex() const
Minutes GetTimezoneOffset() const
std::string GetPlayerInfo() const
Player * GetPlayer() const
bool HasPermission(uint32 permissionId)
uint32 GetAccountId() const
void SetUtcTimeFromUnixTime(std::time_t unixTime)
Definition WowTime.cpp:86
#define sWorld
Definition World.h:900
@ CONFIG_GUILD_EVENT_LOG_COUNT
Definition World.h:338
@ CONFIG_GUILD_BANK_EVENT_LOG_COUNT
Definition World.h:339
@ CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD
Definition World.h:99
uint32 const Entry[5]
time_t GetGameTime()
Definition GameTime.cpp:42
TC_GAME_API Player * FindPlayerByName(std::string_view name)
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
TC_GAME_API Player * FindConnectedPlayer(ObjectGuid const &)
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.
@ RBAC_PERM_LOG_GM_TRADE
Definition RBAC.h:64
STL namespace.
uint32 count
Definition Player.h:622
bool isContainedIn(std::vector< ItemPosCount > const &vec) const
Definition Player.cpp:24101
uint16 pos
Definition Player.h:621
std::string Name1
std::vector< GuildBankSocketEnchant > SocketEnchant
std::array< std::string, GUILD_RANKS_MAX_COUNT > Ranks
uint32 TabWithdrawItemLimit[GUILD_BANK_MAX_TABS]
uint32 TabFlags[GUILD_BANK_MAX_TABS]