TrinityCore
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 "AchievementMgr.h"
21#include "Bag.h"
22#include "CalendarMgr.h"
23#include "CalendarPackets.h"
24#include "CharacterCache.h"
25#include "Chat.h"
26#include "ChatPackets.h"
28#include "ClubService.h"
29#include "ClubUtils.h"
30#include "Config.h"
31#include "DB2Stores.h"
32#include "DatabaseEnv.h"
33#include "GameTime.h"
34#include "GuildMgr.h"
35#include "GuildPackets.h"
36#include "Language.h"
37#include "Log.h"
38#include "Map.h"
39#include "ObjectAccessor.h"
40#include "ObjectMgr.h"
41#include "Player.h"
42#include "ScriptMgr.h"
43#include "SocialMgr.h"
44#include "World.h"
45#include "WorldSession.h"
46#include "club_listener.pb.h"
48
49size_t const MAX_GUILD_BANK_TAB_TEXT_LEN = 500;
50
52
54{
55 // these prices are in gold units, not copper
56 static uint64 const tabPrices[GUILD_BANK_MAX_TABS] = { 100, 250, 500, 1000, 2500, 5000, 0, 0 };
58
59 return tabPrices[tabId];
60}
61
62void Guild::SendCommandResult(WorldSession* session, GuildCommandType type, GuildCommandError errCode, std::string_view param)
63{
65 resultPacket.Command = type;
66 resultPacket.Result = errCode;
67 resultPacket.Name = param;
68 session->SendPacket(resultPacket.Write());
69
70 TC_LOG_DEBUG("guild", "SMSG_GUILD_COMMAND_RESULT [{}]: Type: {}, code: {}, param: {}"
71 , session->GetPlayerInfo(), type, errCode, resultPacket.Name);
72}
73
75{
77 saveResponse.Error = int32(errCode);
78 session->SendPacket(saveResponse.Write());
79
80 TC_LOG_DEBUG("guild", "Sent SMSG_SAVE_GUILD_EMBLEM [{}] Code: {}", session->GetPlayerInfo(), errCode);
81}
82
83// LogHolder
84template <typename Entry>
87{ }
88
89template <typename Entry> template <typename... Ts>
91{
92 Entry const& newEntry = m_log.emplace_front(std::forward<Ts>(args)...);
93 if (m_nextGUID == uint32(GUILD_EVENT_LOG_GUID_UNDEFINED))
94 m_nextGUID = newEntry.GetGUID();
95}
96
97template <typename Entry> template <typename... Ts>
99{
100 // Check max records limit
101 if (!CanInsert())
102 m_log.pop_front();
103
104 // Add event to list
105 Entry& entry = m_log.emplace_back(std::forward<Ts>(args)...);
106 // Save to DB
107 entry.SaveToDB(trans);
108 return entry;
109}
110
111template <typename Entry>
113{
114 // Next guid was not initialized. It means there are no records for this holder in DB yet.
115 // Start from the beginning.
116 if (m_nextGUID == uint32(GUILD_EVENT_LOG_GUID_UNDEFINED))
117 m_nextGUID = 0;
118 else
119 m_nextGUID = (m_nextGUID + 1) % m_maxRecords;
120 return m_nextGUID;
121}
122
123Guild::LogEntry::LogEntry(ObjectGuid::LowType guildId, uint32 guid) : m_guildId(guildId), m_guid(guid), m_timestamp(GameTime::GetGameTime()) { }
124
125// EventLogEntry
127{
129 stmt->setUInt64(0, m_guildId);
130 stmt->setUInt32(1, m_guid);
131 trans->Append(stmt);
132
133 uint8 index = 0;
134 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_EVENTLOG);
135 stmt->setUInt64( index, m_guildId);
136 stmt->setUInt32(++index, m_guid);
137 stmt->setUInt8 (++index, uint8(m_eventType));
138 stmt->setUInt64(++index, m_playerGuid1);
139 stmt->setUInt64(++index, m_playerGuid2);
140 stmt->setUInt8 (++index, m_newRank);
141 stmt->setInt64 (++index, m_timestamp);
142 trans->Append(stmt);
143}
144
146{
147 ObjectGuid playerGUID = ObjectGuid::Create<HighGuid::Player>(m_playerGuid1);
148 ObjectGuid otherGUID = ObjectGuid::Create<HighGuid::Player>(m_playerGuid2);
149
151 eventEntry.PlayerGUID = playerGUID;
152 eventEntry.OtherGUID = otherGUID;
153 eventEntry.TransactionType = uint8(m_eventType);
154 eventEntry.TransactionDate = uint32(GameTime::GetGameTime() - m_timestamp);
155 eventEntry.RankID = uint8(m_newRank);
156 packet.Entry.push_back(eventEntry);
157}
158
159// BankEventLogEntry
161{
162 uint8 index = 0;
163
165 stmt->setUInt64( index, m_guildId);
166 stmt->setUInt32(++index, m_guid);
167 stmt->setUInt8 (++index, m_bankTabId);
168 trans->Append(stmt);
169
170 index = 0;
171 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_BANK_EVENTLOG);
172 stmt->setUInt64( index, m_guildId);
173 stmt->setUInt32(++index, m_guid);
174 stmt->setUInt8 (++index, m_bankTabId);
175 stmt->setUInt8 (++index, uint8(m_eventType));
176 stmt->setUInt64(++index, m_playerGuid);
177 stmt->setUInt64(++index, m_itemOrMoney);
178 stmt->setUInt16(++index, m_itemStackCount);
179 stmt->setUInt8 (++index, m_destTabId);
180 stmt->setInt64 (++index, m_timestamp);
181 trans->Append(stmt);
182}
183
185{
186 ObjectGuid logGuid = ObjectGuid::Create<HighGuid::Player>(m_playerGuid);
187
188 bool hasItem = m_eventType == GUILD_BANK_LOG_DEPOSIT_ITEM || m_eventType == GUILD_BANK_LOG_WITHDRAW_ITEM ||
189 m_eventType == GUILD_BANK_LOG_MOVE_ITEM || m_eventType == GUILD_BANK_LOG_MOVE_ITEM2;
190
191 bool itemMoved = (m_eventType == GUILD_BANK_LOG_MOVE_ITEM || m_eventType == GUILD_BANK_LOG_MOVE_ITEM2);
192
193 bool hasStack = (hasItem && m_itemStackCount > 1) || itemMoved;
194
196 bankLogEntry.PlayerGUID = logGuid;
197 bankLogEntry.TimeOffset = int32(GameTime::GetGameTime() - m_timestamp);
198 bankLogEntry.EntryType = int8(m_eventType);
199
200 if (hasStack)
201 bankLogEntry.Count = int32(m_itemStackCount);
202
203 if (IsMoneyEvent())
204 bankLogEntry.Money = uint64(m_itemOrMoney);
205
206 if (hasItem)
207 bankLogEntry.ItemID = int32(m_itemOrMoney);
208
209 if (itemMoved)
210 bankLogEntry.OtherTab = int8(m_destTabId);
211
212 packet.Entry.push_back(bankLogEntry);
213}
214
216{
217 uint8 index = 0;
219 stmt->setUInt64( index, m_guildId);
220 stmt->setUInt32(++index, GetGUID());
221 stmt->setUInt8 (++index, GetType());
222 stmt->setUInt64(++index, GetPlayerGuid().GetCounter());
223 stmt->setUInt32(++index, GetFlags());
224 stmt->setUInt32(++index, GetValue());
225 stmt->setInt64 (++index, GetTimestamp());
226 CharacterDatabase.ExecuteOrAppend(trans, stmt);
227}
228
230{
232 newsEvent.Id = int32(GetGUID());
233 newsEvent.MemberGuid = GetPlayerGuid();
234 newsEvent.CompletedDate.SetUtcTimeFromUnixTime(GetTimestamp());
235 newsEvent.Flags = int32(GetFlags());
236 newsEvent.Type = int32(GetType());
237
238 //for (uint8 i = 0; i < 2; i++)
239 // newsEvent.Data[i] =
240
241 //newsEvent.MemberList.push_back(MemberGuid);
242
243 if (GetType() == GUILD_NEWS_ITEM_LOOTED || GetType() == GUILD_NEWS_ITEM_CRAFTED || GetType() == GUILD_NEWS_ITEM_PURCHASED)
244 {
246 itemInstance.ItemID = GetValue();
247 newsEvent.Item = itemInstance;
248 }
249
250 newsPacket.NewsEvents.push_back(newsEvent);
251}
252
253// RankInfo
255{
256 m_rankId = GuildRankId(fields[1].GetUInt8());
257 m_rankOrder = GuildRankOrder(fields[2].GetUInt8());
258 m_name = fields[3].GetString();
259 m_rights = fields[4].GetUInt32();
260 m_bankMoneyPerDay = fields[5].GetUInt32();
261 if (m_rankId == GuildRankId::GuildMaster) // Prevent loss of leader rights
262 m_rights |= GR_RIGHT_ALL;
263}
264
266{
268 stmt->setUInt64(0, m_guildId);
269 stmt->setUInt8 (1, AsUnderlyingType(m_rankId));
270 stmt->setUInt8 (2, AsUnderlyingType(m_rankOrder));
271 stmt->setString(3, m_name);
272 stmt->setUInt32(4, m_rights);
273 stmt->setUInt32(5, 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 == GuildRankId::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, uint32(m_rankId));
291
293 stmt->setUInt64(0, m_guildId);
294 stmt->setUInt8(1, i);
295 stmt->setUInt8(2, AsUnderlyingType(m_rankId));
296 stmt->setInt8(3, rightsAndSlots.GetRights());
297 stmt->setInt32(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, AsUnderlyingType(m_rankId));
312 stmt->setUInt64(2, m_guildId);
313 CharacterDatabase.Execute(stmt);
314}
315
317{
318 if (m_rankId == GuildRankId::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, AsUnderlyingType(m_rankId));
329 stmt->setUInt64(2, m_guildId);
330 CharacterDatabase.Execute(stmt);
331}
332
334{
335 if (m_bankMoneyPerDay == money)
336 return;
337
338 m_bankMoneyPerDay = money;
339
341 stmt->setUInt32(0, money);
342 stmt->setUInt8 (1, AsUnderlyingType(m_rankId));
343 stmt->setUInt64(2, m_guildId);
344 CharacterDatabase.Execute(stmt);
345}
346
348{
349 if (m_rankId == GuildRankId::GuildMaster) // Prevent loss of leader rights
350 rightsAndSlots.SetGuildMasterValues();
351
352 GuildBankRightsAndSlots& guildBR = m_bankTabRightsAndSlots[rightsAndSlots.GetTabId()];
353 guildBR = rightsAndSlots;
354
355 if (saveToDB)
356 {
358 stmt->setUInt64(0, m_guildId);
359 stmt->setUInt8 (1, guildBR.GetTabId());
360 stmt->setUInt8 (2, AsUnderlyingType(m_rankId));
361 stmt->setInt8 (3, guildBR.GetRights());
362 stmt->setInt32 (4, guildBR.GetSlots());
363 CharacterDatabase.Execute(stmt);
364 }
365}
366
367// BankTab
368Guild::BankTab::BankTab(ObjectGuid::LowType guildId, uint8 tabId) : m_guildId(guildId), m_tabId(tabId)
369{ }
370
372{
373 m_name = fields[2].GetString();
374 m_icon = fields[3].GetString();
375 m_text = fields[4].GetString();
376}
377
379{
380 uint8 slotId = fields[53].GetUInt8();
381 ObjectGuid::LowType itemGuid = fields[0].GetUInt64();
382 uint32 itemEntry = fields[1].GetUInt32();
383 if (slotId >= GUILD_BANK_MAX_SLOTS)
384 {
385 TC_LOG_ERROR("guild", "Invalid slot for item (GUID: {}, id: {}) in guild bank, skipped.", itemGuid, itemEntry);
386 return false;
387 }
388
389 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry);
390 if (!proto)
391 {
392 TC_LOG_ERROR("guild", "Unknown item (GUID: {}, id: {}) in guild bank, skipped.", itemGuid, itemEntry);
393 return false;
394 }
395
396 Item* pItem = NewItemOrBag(proto);
397 if (!pItem->LoadFromDB(itemGuid, ObjectGuid::Empty, fields, itemEntry))
398 {
399 TC_LOG_ERROR("guild", "Item (GUID {}, id: {}) not found in item_instance, deleting from guild bank!", itemGuid, itemEntry);
400
402 stmt->setUInt64(0, m_guildId);
403 stmt->setUInt8 (1, m_tabId);
404 stmt->setUInt8 (2, slotId);
405 CharacterDatabase.Execute(stmt);
406
407 delete pItem;
408 return false;
409 }
410
411 pItem->AddToWorld();
412 m_items[slotId] = pItem;
413 return true;
414}
415
416// Deletes contents of the tab from the world (and from DB if necessary)
417void Guild::BankTab::Delete(CharacterDatabaseTransaction trans, bool removeItemsFromDB)
418{
419 for (uint8 slotId = 0; slotId < GUILD_BANK_MAX_SLOTS; ++slotId)
420 {
421 if (Item* item = m_items[slotId])
422 {
423 item->RemoveFromWorld();
424 if (removeItemsFromDB)
425 item->DeleteFromDB(trans);
426 delete item;
427 item = nullptr;
428 }
429 }
430}
431
432void Guild::BankTab::SetInfo(std::string_view name, std::string_view icon)
433{
434 if ((m_name == name) && (m_icon == icon))
435 return;
436
437 m_name = name;
438 m_icon = icon;
439
441 stmt->setString(0, m_name);
442 stmt->setString(1, m_icon);
443 stmt->setUInt64(2, m_guildId);
444 stmt->setUInt8 (3, m_tabId);
445 CharacterDatabase.Execute(stmt);
446}
447
448void Guild::BankTab::SetText(std::string_view text)
449{
450 if (m_text == text)
451 return;
452
453 m_text = text;
454 utf8truncate(m_text, MAX_GUILD_BANK_TAB_TEXT_LEN); // DB and client size limitation
455
457 stmt->setString(0, m_text);
458 stmt->setUInt64(1, m_guildId);
459 stmt->setUInt8 (2, m_tabId);
460 CharacterDatabase.Execute(stmt);
461}
462
463// Sets/removes contents of specified slot.
464// If pItem == nullptr contents are removed.
466{
467 if (slotId >= GUILD_BANK_MAX_SLOTS)
468 return false;
469
470 m_items[slotId] = item;
471
473 stmt->setUInt64(0, m_guildId);
474 stmt->setUInt8 (1, m_tabId);
475 stmt->setUInt8 (2, slotId);
476 trans->Append(stmt);
477
478 if (item)
479 {
480 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_BANK_ITEM);
481 stmt->setUInt64(0, m_guildId);
482 stmt->setUInt8 (1, m_tabId);
483 stmt->setUInt8 (2, slotId);
484 stmt->setUInt64(3, item->GetGUID().GetCounter());
485 trans->Append(stmt);
486
489 item->FSetState(ITEM_NEW);
490 item->SaveToDB(trans); // Not in inventory and can be saved standalone
491 }
492
493 return true;
494}
495
496void Guild::BankTab::SendText(Guild const* guild, WorldSession* session) const
497{
499 textQuery.Tab = m_tabId;
500 textQuery.Text = m_text;
501
502 if (session)
503 {
504 TC_LOG_DEBUG("guild", "SMSG_GUILD_BANK_QUERY_TEXT_RESULT [{}]: Tabid: {}, Text: {}"
505 , session->GetPlayerInfo(), m_tabId, m_text);
506 session->SendPacket(textQuery.Write());
507 }
508 else
509 {
510 TC_LOG_DEBUG("guild", "SMSG_GUILD_BANK_QUERY_TEXT_RESULT [Broadcast]: Tabid: {}, Text: {}", m_tabId, m_text);
511 guild->BroadcastPacket(textQuery.Write());
512 }
513}
514
515// Member
517 m_guildId(guildId),
518 m_guid(guid),
519 m_zoneId(0),
520 m_level(0),
521 m_race(0),
522 m_class(0),
523 m_gender(0),
525 m_logoutTime(GameTime::GetGameTime()),
526 m_accountId(0),
527 m_rankId(rankId),
528 m_bankWithdraw(),
529 m_bankWithdrawMoney(0),
530 m_achievementPoints(0),
531 m_totalActivity(0),
532 m_weekActivity(0),
533 m_totalReputation(0),
534 m_weekReputation(0)
535{}
536
538{
539 m_name = player->GetName();
540 m_level = player->GetLevel();
541 m_race = player->GetRace();
542 m_class = player->GetClass();
543 m_gender = player->GetNativeGender();
544 m_zoneId = player->GetZoneId();
545 m_accountId = player->GetSession()->GetAccountId();
546 m_achievementPoints = player->GetAchievementPoints();
547}
548
549void Guild::Member::SetStats(std::string_view name, uint8 level, uint8 race, uint8 _class, uint8 gender, uint32 zoneId, uint32 accountId, uint32 reputation)
550{
551 m_name = name;
552 m_level = level;
553 m_race = race;
554 m_class = _class;
555 m_gender = gender;
556 m_zoneId = zoneId;
557 m_accountId = accountId;
558 m_totalReputation = reputation;
559}
560
561void Guild::Member::SetPublicNote(std::string_view publicNote)
562{
563 if (m_publicNote == publicNote)
564 return;
565
566 m_publicNote = publicNote;
567
569 stmt->setString(0, m_publicNote);
570 stmt->setUInt64(1, m_guid.GetCounter());
571 CharacterDatabase.Execute(stmt);
572}
573
574void Guild::Member::SetOfficerNote(std::string_view officerNote)
575{
576 if (m_officerNote == officerNote)
577 return;
578
579 m_officerNote = officerNote;
580
582 stmt->setString(0, m_officerNote);
583 stmt->setUInt64(1, m_guid.GetCounter());
584 CharacterDatabase.Execute(stmt);
585}
586
588{
589 m_rankId = newRank;
590
591 // Update rank information in player's field, if he is online.
592 if (Player* player = FindConnectedPlayer())
593 player->SetGuildRank(AsUnderlyingType(newRank));
594
596 stmt->setUInt8 (0, AsUnderlyingType(newRank));
597 stmt->setUInt64(1, m_guid.GetCounter());
598 CharacterDatabase.ExecuteOrAppend(trans, stmt);
599}
600
602{
603 m_logoutTime = GameTime::GetGameTime();
604}
605
607{
609 stmt->setUInt64(0, m_guildId);
610 stmt->setUInt64(1, m_guid.GetCounter());
611 stmt->setUInt8 (2, AsUnderlyingType(m_rankId));
612 stmt->setString(3, m_publicNote);
613 stmt->setString(4, m_officerNote);
614 CharacterDatabase.ExecuteOrAppend(trans, stmt);
615}
616
617// Loads member's data from database.
618// If member has broken fields (level, class) returns false.
619// In this case member has to be removed from guild.
621{
622 m_publicNote = fields[3].GetString();
623 m_officerNote = fields[4].GetString();
624
625 for (uint8 i = 0; i < GUILD_BANK_MAX_TABS; ++i)
626 m_bankWithdraw[i] = fields[5 + i].GetUInt32();
627
628 m_bankWithdrawMoney = fields[13].GetUInt64();
629
630 SetStats(fields[14].GetString(),
631 fields[15].GetUInt8(), // characters.level
632 fields[16].GetUInt8(), // characters.race
633 fields[17].GetUInt8(), // characters.class
634 fields[18].GetUInt8(), // characters.gender
635 fields[19].GetUInt16(), // characters.zone
636 fields[20].GetUInt32(), // characters.account
637 0);
638 m_logoutTime = fields[21].GetUInt64(); // characters.logout_time
639 m_totalActivity = 0;
640 m_weekActivity = 0;
641 m_weekReputation = 0;
642
643 if (!CheckStats())
644 return false;
645
646 if (!m_zoneId)
647 {
648 TC_LOG_DEBUG("guild", "{} has broken zone-data", m_guid.ToString());
649 m_zoneId = Player::GetZoneIdFromDB(m_guid);
650 }
651
652 ResetFlags();
653 return true;
654}
655
656// Validate player fields. Returns false if corrupted fields are found.
658{
659 if (m_level < 1)
660 {
661 TC_LOG_ERROR("guild", "{} has a broken data in field `characters`.`level`, deleting him from guild!", m_guid.ToString());
662 return false;
663 }
664
665 if (!sChrRacesStore.LookupEntry(m_race))
666 {
667 TC_LOG_ERROR("guild", "{} has a broken data in field `characters`.`race`, deleting him from guild!", m_guid.ToString());
668 return false;
669 }
670
671 if (!sChrClassesStore.LookupEntry(m_class))
672 {
673 TC_LOG_ERROR("guild", "{} has a broken data in field `characters`.`class`, deleting him from guild!", m_guid.ToString());
674 return false;
675 }
676 return true;
677}
678
680{
681 if (IsOnline())
682 return 0.0f;
683 return float(GameTime::GetGameTime() - GetLogoutTime()) / float(DAY);
684}
685
686// Decreases amount of slots left for today.
688{
689 m_bankWithdraw[tabId] += amount;
690
692 stmt->setUInt64(0, m_guid.GetCounter());
693 for (uint8 i = 0; i < GUILD_BANK_MAX_TABS;)
694 {
695 uint32 withdraw = m_bankWithdraw[i++];
696 stmt->setUInt32(i, withdraw);
697 }
698
699 CharacterDatabase.ExecuteOrAppend(trans, stmt);
700}
701
702// Decreases amount of money left for today.
704{
705 m_bankWithdrawMoney += amount;
706
708 stmt->setUInt64(0, m_guid.GetCounter());
709 stmt->setUInt64(1, m_bankWithdrawMoney);
710 CharacterDatabase.ExecuteOrAppend(trans, stmt);
711}
712
713void Guild::Member::ResetValues(bool weekly /* = false*/)
714{
715 for (uint8 tabId = 0; tabId < GUILD_BANK_MAX_TABS; ++tabId)
716 m_bankWithdraw[tabId] = 0;
717
718 m_bankWithdrawMoney = 0;
719
720 if (weekly)
721 {
722 m_weekActivity = 0;
723 m_weekReputation = 0;
724 }
725}
726
728{
729 return ObjectAccessor::FindPlayer(m_guid);
730}
731
733{
735}
736
737// EmblemInfo
739{
740 m_style = packet.EStyle;
741 m_color = packet.EColor;
742 m_borderStyle = packet.BStyle;
743 m_borderColor = packet.BColor;
744 m_backgroundColor = packet.Bg;
745}
746
747bool EmblemInfo::ValidateEmblemColors(uint32 /*style*/, uint32 color, uint32 /*borderStyle*/, uint32 borderColor, uint32 backgroundColor)
748{
749 return sGuildColorBackgroundStore.LookupEntry(backgroundColor) &&
750 sGuildColorBorderStore.LookupEntry(borderColor) &&
751 sGuildColorEmblemStore.LookupEntry(color);
752}
753
755{
756 m_style = fields[3].GetUInt8();
757 m_color = fields[4].GetUInt8();
758 m_borderStyle = fields[5].GetUInt8();
759 m_borderColor = fields[6].GetUInt8();
760 m_backgroundColor = fields[7].GetUInt8();
761
762 return ValidateEmblemColors();
763}
764
766{
768 stmt->setUInt32(0, m_style);
769 stmt->setUInt32(1, m_color);
770 stmt->setUInt32(2, m_borderStyle);
771 stmt->setUInt32(3, m_borderColor);
772 stmt->setUInt32(4, m_backgroundColor);
773 stmt->setUInt64(5, guildId);
774 CharacterDatabase.Execute(stmt);
775}
776
777// MoveItemData
778Guild::MoveItemData::MoveItemData(Guild* guild, Player* player, uint8 container, uint8 slotId) : m_pGuild(guild), m_pPlayer(player),
779m_container(container), m_slotId(slotId), m_pItem(nullptr), m_pClonedItem(nullptr)
780{
781}
782
784{
785}
786
788{
789 ASSERT(m_pItem);
790 if (splitedAmount > m_pItem->GetCount())
791 return false;
792 if (splitedAmount == m_pItem->GetCount())
793 splitedAmount = 0;
794 return true;
795}
796
797InventoryResult Guild::MoveItemData::CanStore(Item* pItem, bool swap, bool sendError)
798{
799 m_vec.clear();
800 InventoryResult msg = CanStore(pItem, swap);
801 if (sendError && msg != EQUIP_ERR_OK)
802 SendEquipError(msg, pItem);
803 return msg;
804}
805
807{
808 ASSERT(m_pItem);
809 m_pClonedItem = m_pItem->CloneItem(count);
810 if (!m_pClonedItem)
811 {
812 SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, m_pItem);
813 return false;
814 }
815 return true;
816}
817
819{
820 ASSERT(pFrom->GetItem());
821
822 sScriptMgr->OnGuildItemMove(m_pGuild, m_pPlayer, pFrom->GetItem(),
823 pFrom->IsBank(), pFrom->GetContainer(), pFrom->GetSlotId(),
824 IsBank(), GetContainer(), GetSlotId());
825}
826
828{
829 for (auto itr = m_vec.begin(); itr != m_vec.end(); ++itr)
830 ids.insert(uint8(itr->pos));
831}
832
834{
835 m_pPlayer->SendEquipError(result, item);
836}
837
838// PlayerMoveItemData
840{
841 m_pItem = m_pPlayer->GetItemByPos(m_container, m_slotId);
842 if (m_pItem)
843 {
844 // Anti-WPE protection. Do not move non-empty bags to bank.
845 if (m_pItem->IsNotEmptyBag())
846 {
847 SendEquipError(EQUIP_ERR_DESTROY_NONEMPTY_BAG, m_pItem);
848 m_pItem = nullptr;
849 }
850 // Bound items cannot be put into bank.
851 else if (!m_pItem->CanBeTraded())
852 {
853 SendEquipError(EQUIP_ERR_CANT_SWAP, m_pItem);
854 m_pItem = nullptr;
855 }
856 }
857 return (m_pItem != nullptr);
858}
859
861{
862 if (splitedAmount)
863 {
864 m_pItem->SetCount(m_pItem->GetCount() - splitedAmount);
865 m_pItem->SetState(ITEM_CHANGED, m_pPlayer);
866 m_pPlayer->SaveInventoryAndGoldToDB(trans);
867 }
868 else
869 {
870 m_pPlayer->MoveItemFromInventory(m_container, m_slotId, true);
871 m_pItem->DeleteFromInventoryDB(trans);
872 m_pItem = nullptr;
873 }
874}
875
877{
878 ASSERT(pItem);
879 m_pPlayer->MoveItemToInventory(m_vec, pItem, true);
880 m_pPlayer->SaveInventoryAndGoldToDB(trans);
881 return pItem;
882}
883
885{
886 ASSERT(pFrom);
887 // Bank -> Char
888 m_pGuild->_LogBankEvent(trans, GUILD_BANK_LOG_WITHDRAW_ITEM, pFrom->GetContainer(), m_pPlayer->GetGUID().GetCounter(),
889 pFrom->GetItem()->GetEntry(), count);
890}
891
893{
894 return m_pPlayer->CanStoreItem(m_container, m_slotId, m_vec, pItem, swap);
895}
896
897// BankMoveItemData
899{
900 m_pItem = m_pGuild->_GetItem(m_container, m_slotId);
901 return (m_pItem != nullptr);
902}
903
905{
906 ASSERT(pOther);
907 // Do not check rights if item is being swapped within the same bank tab
908 if (pOther->IsBank() && pOther->GetContainer() == m_container)
909 return true;
910 return m_pGuild->_MemberHasTabRights(m_pPlayer->GetGUID(), m_container, GUILD_BANK_RIGHT_DEPOSIT_ITEM);
911}
912
914{
915 ASSERT(pOther);
916 // Do not check rights if item is being swapped within the same bank tab
917 if (pOther->IsBank() && pOther->GetContainer() == m_container)
918 return true;
919
920 int32 slots = 0;
921 if (Member const* member = m_pGuild->GetMember(m_pPlayer->GetGUID()))
922 slots = m_pGuild->_GetMemberRemainingSlots(*member, m_container);
923
924 return slots != 0;
925}
926
928{
929 ASSERT(m_pItem);
930 if (splitedAmount)
931 {
932 m_pItem->SetCount(m_pItem->GetCount() - splitedAmount);
933 m_pItem->FSetState(ITEM_CHANGED);
934 m_pItem->SaveToDB(trans);
935 }
936 else
937 {
938 m_pGuild->_RemoveItem(trans, m_container, m_slotId);
939 m_pItem = nullptr;
940 }
941 // Decrease amount of player's remaining items (if item is moved to different tab or to player)
942 if (!pOther->IsBank() || pOther->GetContainer() != m_container)
943 m_pGuild->_UpdateMemberWithdrawSlots(trans, m_pPlayer->GetGUID(), m_container);
944}
945
947{
948 if (!pItem)
949 return nullptr;
950
951 BankTab* pTab = m_pGuild->GetBankTab(m_container);
952 if (!pTab)
953 return nullptr;
954
955 Item* pLastItem = pItem;
956 for (auto itr = m_vec.begin(); itr != m_vec.end(); )
957 {
958 ItemPosCount pos(*itr);
959 ++itr;
960
961 ASSERT(pItem);
962
963 TC_LOG_DEBUG("guild", "GUILD STORAGE: StoreItem tab = {}, slot = {}, item = {}, count = {}",
964 m_container, m_slotId, pItem->GetEntry(), pItem->GetCount());
965 pLastItem = _StoreItem(trans, pTab, pItem, pos, itr != m_vec.end());
966 }
967 return pLastItem;
968}
969
971{
972 ASSERT(pFrom->GetItem());
973 if (pFrom->IsBank())
974 // Bank -> Bank
975 m_pGuild->_LogBankEvent(trans, GUILD_BANK_LOG_MOVE_ITEM, pFrom->GetContainer(), m_pPlayer->GetGUID().GetCounter(),
976 pFrom->GetItem()->GetEntry(), count, m_container);
977 else
978 // Char -> Bank
979 m_pGuild->_LogBankEvent(trans, GUILD_BANK_LOG_DEPOSIT_ITEM, m_container, m_pPlayer->GetGUID().GetCounter(),
980 pFrom->GetItem()->GetEntry(), count);
981}
982
984{
986 if (!pFrom->IsBank() && m_pPlayer->GetSession()->HasPermission(rbac::RBAC_PERM_LOG_GM_TRADE))
987 {
988 sLog->OutCommand(m_pPlayer->GetSession()->GetAccountId(),
989 "GM {} ({}) (Account: {}) deposit item: {} (Entry: {} Count: {}) to guild bank named: {} (Guild ID: {})",
990 m_pPlayer->GetName(), m_pPlayer->GetGUID().ToString(), m_pPlayer->GetSession()->GetAccountId(),
991 pFrom->GetItem()->GetTemplate()->GetDefaultLocaleName(), pFrom->GetItem()->GetEntry(), pFrom->GetItem()->GetCount(),
992 m_pGuild->GetName(), m_pGuild->GetId());
993 }
994}
995
997{
998 uint8 slotId = uint8(pos.pos);
999 uint32 count = pos.count;
1000 if (Item* pItemDest = pTab->GetItem(slotId))
1001 {
1002 pItemDest->SetCount(pItemDest->GetCount() + count);
1003 pItemDest->FSetState(ITEM_CHANGED);
1004 pItemDest->SaveToDB(trans);
1005 if (!clone)
1006 {
1007 pItem->RemoveFromWorld();
1008 pItem->DeleteFromDB(trans);
1009 delete pItem;
1010 }
1011 return pItemDest;
1012 }
1013
1014 if (clone)
1015 pItem = pItem->CloneItem(count);
1016 else
1017 pItem->SetCount(count);
1018
1019 if (pItem && pTab->SetItem(trans, slotId, pItem))
1020 return pItem;
1021
1022 return nullptr;
1023}
1024
1025// Tries to reserve space for source item.
1026// If item in destination slot exists it must be the item of the same entry
1027// and stack must have enough space to take at least one item.
1028// Returns false if destination item specified and it cannot be used to reserve space.
1029bool Guild::BankMoveItemData::_ReserveSpace(uint8 slotId, Item* pItem, Item* pItemDest, uint32& count)
1030{
1031 uint32 requiredSpace = pItem->GetMaxStackCount();
1032 if (pItemDest)
1033 {
1034 // Make sure source and destination items match and destination item has space for more stacks.
1035 if (pItemDest->GetEntry() != pItem->GetEntry() || pItemDest->GetCount() >= pItem->GetMaxStackCount())
1036 return false;
1037 requiredSpace -= pItemDest->GetCount();
1038 }
1039 // Let's not be greedy, reserve only required space
1040 requiredSpace = std::min(requiredSpace, count);
1041
1042 // Reserve space
1043 ItemPosCount pos(slotId, requiredSpace);
1044 if (!pos.isContainedIn(m_vec))
1045 {
1046 m_vec.push_back(pos);
1047 count -= requiredSpace;
1048 }
1049 return true;
1050}
1051
1052void Guild::BankMoveItemData::CanStoreItemInTab(Item* pItem, uint8 skipSlotId, bool merge, uint32& count)
1053{
1054 for (uint8 slotId = 0; (slotId < GUILD_BANK_MAX_SLOTS) && (count > 0); ++slotId)
1055 {
1056 // Skip slot already processed in CanStore (when destination slot was specified)
1057 if (slotId == skipSlotId)
1058 continue;
1059
1060 Item* pItemDest = m_pGuild->_GetItem(m_container, slotId);
1061 if (pItemDest == pItem)
1062 pItemDest = nullptr;
1063
1064 // If merge skip empty, if not merge skip non-empty
1065 if ((pItemDest != nullptr) != merge)
1066 continue;
1067
1068 _ReserveSpace(slotId, pItem, pItemDest, count);
1069 }
1070}
1071
1073{
1074 TC_LOG_DEBUG("guild", "GUILD STORAGE: CanStore() tab = {}, slot = {}, item = {}, count = {}",
1075 m_container, m_slotId, pItem->GetEntry(), pItem->GetCount());
1076
1077 uint32 count = pItem->GetCount();
1078 // Soulbound items cannot be moved
1079 if (pItem->IsSoulBound())
1081
1082 // Make sure destination bank tab exists
1083 if (m_container >= m_pGuild->_GetPurchasedTabsSize())
1085
1086 // Slot explicitely specified. Check it.
1087 if (m_slotId != NULL_SLOT)
1088 {
1089 Item* pItemDest = m_pGuild->_GetItem(m_container, m_slotId);
1090 // Ignore swapped item (this slot will be empty after move)
1091 if ((pItemDest == pItem) || swap)
1092 pItemDest = nullptr;
1093
1094 if (!_ReserveSpace(m_slotId, pItem, pItemDest, count))
1095 return EQUIP_ERR_CANT_STACK;
1096
1097 if (count == 0)
1098 return EQUIP_ERR_OK;
1099 }
1100
1101 // Slot was not specified or it has not enough space for all the items in stack
1102 // Search for stacks to merge with
1103 if (pItem->GetMaxStackCount() > 1)
1104 {
1105 CanStoreItemInTab(pItem, m_slotId, true, count);
1106 if (count == 0)
1107 return EQUIP_ERR_OK;
1108 }
1109
1110 // Search free slot for item
1111 CanStoreItemInTab(pItem, m_slotId, false, count);
1112 if (count == 0)
1113 return EQUIP_ERR_OK;
1114
1115 return EQUIP_ERR_BANK_FULL;
1116}
1117
1118// Guild
1120 m_id(UI64LIT(0)),
1121 m_leaderGuid(),
1122 m_createdDate(0),
1124 m_bankMoney(0),
1125 m_achievementMgr(std::make_unique<GuildAchievementMgr>(this))
1126{
1127}
1128
1130{
1131 CharacterDatabaseTransaction temp(nullptr);
1132 _DeleteBankItems(temp);
1133}
1134
1135// Creates new guild with default data and saves it to database.
1136bool Guild::Create(Player* pLeader, std::string_view name)
1137{
1138 // Check if guild with such name already exists
1139 if (sGuildMgr->GetGuildByName(name))
1140 return false;
1141
1142 WorldSession* pLeaderSession = pLeader->GetSession();
1143 if (!pLeaderSession)
1144 return false;
1145
1146 m_id = sGuildMgr->GenerateGuildId();
1147 m_leaderGuid = pLeader->GetGUID();
1148 m_name = name;
1149 m_info = "";
1150 m_motd = "No message set.";
1151 m_bankMoney = 0;
1153
1154 TC_LOG_DEBUG("guild", "GUILD: creating guild [{}] for leader {} {}",
1155 m_name, pLeader->GetName(), m_leaderGuid.ToString());
1156
1157 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1158
1160 stmt->setUInt64(0, m_id);
1161 trans->Append(stmt);
1162
1163 uint8 index = 0;
1164 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD);
1165 stmt->setUInt64( index, m_id);
1166 stmt->setString(++index, m_name);
1167 stmt->setUInt64(++index, m_leaderGuid.GetCounter());
1168 stmt->setString(++index, m_info);
1169 stmt->setString(++index, m_motd);
1170 stmt->setUInt64(++index, uint32(m_createdDate));
1171 stmt->setUInt32(++index, m_emblemInfo.GetStyle());
1172 stmt->setUInt32(++index, m_emblemInfo.GetColor());
1173 stmt->setUInt32(++index, m_emblemInfo.GetBorderStyle());
1174 stmt->setUInt32(++index, m_emblemInfo.GetBorderColor());
1175 stmt->setUInt32(++index, m_emblemInfo.GetBackgroundColor());
1176 stmt->setUInt64(++index, m_bankMoney);
1177 trans->Append(stmt);
1178
1179 _CreateDefaultGuildRanks(trans, pLeaderSession->GetSessionDbLocaleIndex()); // Create default ranks
1180 bool ret = AddMember(trans, m_leaderGuid, GuildRankId::GuildMaster); // Add guildmaster
1181
1182 CharacterDatabase.CommitTransaction(trans);
1183
1184 if (ret)
1185 {
1186 Member* leader = GetMember(m_leaderGuid);
1187 if (leader)
1188 SendEventNewLeader(leader, nullptr);
1189
1190 sScriptMgr->OnGuildCreate(this, pLeader, m_name);
1191 }
1192
1193 return ret;
1194}
1195
1196// Disbands guild and deletes all related data from database
1198{
1199 // Call scripts before guild data removed from database
1200 sScriptMgr->OnGuildDisband(this);
1201
1202 WorldPackets::Guild::GuildEventDisbanded guildEventDisbanded;
1203 guildEventDisbanded.Write();
1204
1205 // Notify the members of club removal.
1206 club::v1::UnsubscribeNotification unsubscribeNotification;
1207 unsubscribeNotification.set_club_id(GetId());
1208
1209 BroadcastWorker([&](Player const* member)
1210 {
1211 member->SendDirectMessage(guildEventDisbanded.GetRawPacket());
1212
1213 // Unsubscribe the removed player from the club to ensure interface updates.
1214 Battlenet::WorldserverService<club::v1::ClubListener>(member->GetSession()).OnUnsubscribe(&unsubscribeNotification, true, true);
1215
1216 // Finally notify the client about leaving the club.
1217 club::v1::membership::ClubRemovedNotification clubRemovedNotification;
1218 clubRemovedNotification.set_allocated_member_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(member->GetGUID()).release());
1219 clubRemovedNotification.set_club_id(GetId());
1221 Battlenet::WorldserverService<club::v1::membership::ClubMembershipListener>(member->GetSession()).OnClubRemoved(&clubRemovedNotification, true, true);
1222 });
1223
1224 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1225 // Remove all members
1226 while (!m_members.empty())
1227 {
1228 auto itr = m_members.begin();
1229 DeleteMember(trans, itr->second.GetGUID(), true);
1230 }
1231
1233 stmt->setUInt64(0, m_id);
1234 trans->Append(stmt);
1235
1236 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_RANKS);
1237 stmt->setUInt64(0, m_id);
1238 trans->Append(stmt);
1239
1240 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_TABS);
1241 stmt->setUInt64(0, m_id);
1242 trans->Append(stmt);
1243
1244 // Free bank tab used memory and delete items stored in them
1245 _DeleteBankItems(trans, true);
1246
1247 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_ITEMS);
1248 stmt->setUInt64(0, m_id);
1249 trans->Append(stmt);
1250
1251 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_RIGHTS);
1252 stmt->setUInt64(0, m_id);
1253 trans->Append(stmt);
1254
1255 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_EVENTLOGS);
1256 stmt->setUInt64(0, m_id);
1257 trans->Append(stmt);
1258
1259 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_EVENTLOGS);
1260 stmt->setUInt64(0, m_id);
1261 trans->Append(stmt);
1262
1263 CharacterDatabase.CommitTransaction(trans);
1264
1265 sGuildMgr->RemoveGuild(m_id);
1266}
1267
1269{
1270 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1271
1272 GetAchievementMgr().SaveToDB(trans);
1273
1274 CharacterDatabase.CommitTransaction(trans);
1275}
1276
1277void Guild::UpdateMemberData(Player* player, uint8 dataid, uint32 value)
1278{
1279 if (Member* member = GetMember(player->GetGUID()))
1280 {
1281 switch (dataid)
1282 {
1284 member->SetZoneId(value);
1285 break;
1287 member->SetAchievementPoints(value);
1288 break;
1290 member->SetLevel(value);
1291 break;
1292 default:
1293 TC_LOG_ERROR("guild", "Guild::UpdateMemberData: Called with incorrect DATAID {} (value {})", dataid, value);
1294 return;
1295 }
1296 //HandleRoster();
1297 }
1298}
1299
1300void Guild::OnPlayerStatusChange(Player* player, uint32 flag, bool state)
1301{
1302 if (Member* member = GetMember(player->GetGUID()))
1303 {
1304 if (state)
1305 member->AddFlag(flag);
1306 else member->RemFlag(flag);
1307 }
1308}
1309
1310bool Guild::SetName(std::string_view name)
1311{
1312 if (m_name == name || name.empty() || name.length() > 24 || sObjectMgr->IsReservedName(name) || !ObjectMgr::IsValidCharterName(name))
1313 return false;
1314
1315 m_name = name;
1317 stmt->setString(0, m_name);
1318 stmt->setUInt64(1, GetId());
1319 CharacterDatabase.Execute(stmt);
1320
1322 guildNameChanged.GuildGUID = GetGUID();
1323 guildNameChanged.GuildName = m_name;
1324 BroadcastPacket(guildNameChanged.Write());
1325
1326 return true;
1327}
1328
1330{
1332
1335 roster.CreateDate += session->GetTimezoneOffset();
1336 roster.GuildFlags = 0;
1337
1338 roster.MemberData.reserve(m_members.size());
1339
1340 bool sendOfficerNote = _HasRankRight(session->GetPlayer(), GR_RIGHT_VIEWOFFNOTE);
1341 for (auto const& [guid, member] : m_members)
1342 {
1343 WorldPackets::Guild::GuildRosterMemberData& memberData = roster.MemberData.emplace_back();
1344
1345 memberData.Guid = member.GetGUID();
1346 memberData.RankID = int32(member.GetRankId());
1347 memberData.AreaID = int32(member.GetZoneId());
1348 memberData.PersonalAchievementPoints = int32(member.GetAchievementPoints());
1349 memberData.GuildReputation = int32(member.GetTotalReputation());
1350 memberData.LastSave = member.GetInactiveDays();
1351
1352 //GuildRosterProfessionData
1353
1355 memberData.Status = member.GetFlags();
1356 memberData.Level = member.GetLevel();
1357 memberData.ClassID = member.GetClass();
1358 memberData.Gender = member.GetGender();
1359 memberData.RaceID = member.GetRace();
1361
1362 memberData.Authenticated = false;
1363 memberData.SorEligible = false;
1364
1365 memberData.Name = member.GetName();
1366 memberData.Note = member.GetPublicNote();
1367 if (sendOfficerNote)
1368 memberData.OfficerNote = member.GetOfficerNote();
1369
1370 }
1371
1372 roster.WelcomeText = m_motd;
1373 roster.InfoText = m_info;
1374
1375 TC_LOG_DEBUG("guild", "SMSG_GUILD_ROSTER [{}]", session->GetPlayerInfo());
1376 session->SendPacket(roster.Write());
1377}
1378
1380{
1382 response.GuildGuid = GetGUID();
1383 response.Info.emplace();
1384
1385 response.Info->GuildGUID = GetGUID();
1386 response.Info->VirtualRealmAddress = GetVirtualRealmAddress();
1387
1388 response.Info->EmblemStyle = m_emblemInfo.GetStyle();
1389 response.Info->EmblemColor = m_emblemInfo.GetColor();
1390 response.Info->BorderStyle = m_emblemInfo.GetBorderStyle();
1391 response.Info->BorderColor = m_emblemInfo.GetBorderColor();
1392 response.Info->BackgroundColor = m_emblemInfo.GetBackgroundColor();
1393
1394 for (RankInfo const& rankInfo : m_ranks)
1395 response.Info->Ranks.emplace_back(AsUnderlyingType(rankInfo.GetId()), AsUnderlyingType(rankInfo.GetOrder()), rankInfo.GetName());
1396
1397 response.Info->GuildName = m_name;
1398
1399 session->SendPacket(response.Write());
1400 TC_LOG_DEBUG("guild", "SMSG_GUILD_QUERY_RESPONSE [{}]", session->GetPlayerInfo());
1401}
1402
1404{
1406
1407 ranks.Ranks.reserve(_GetRanksSize());
1408
1409 for (RankInfo const& rankInfo : m_ranks)
1410 {
1412
1413 rankData.RankID = AsUnderlyingType(rankInfo.GetId());
1414 rankData.RankOrder = AsUnderlyingType(rankInfo.GetOrder());
1415 rankData.Flags = rankInfo.GetRights();
1416 rankData.WithdrawGoldLimit = (rankInfo.GetId() == GuildRankId::GuildMaster ? (-1) : int32(rankInfo.GetBankMoneyPerDay() / GOLD));
1417 rankData.RankName = rankInfo.GetName();
1418
1419 for (uint8 j = 0; j < GUILD_BANK_MAX_TABS; ++j)
1420 {
1421 rankData.TabFlags[j] = uint32(rankInfo.GetBankTabRights(j));
1422 rankData.TabWithdrawItemLimit[j] = uint32(rankInfo.GetBankTabSlotsPerDay(j));
1423 }
1424
1425 ranks.Ranks.push_back(rankData);
1426 }
1427
1428 session->SendPacket(ranks.Write());
1429 TC_LOG_DEBUG("guild", "SMSG_GUILD_RANK [{}]", session->GetPlayerInfo());
1430}
1431
1432void Guild::HandleSetAchievementTracking(WorldSession* session, uint32 const* achievementIdsBegin, uint32 const* achievementIdsEnd)
1433{
1434 Player* player = session->GetPlayer();
1435
1436 if (Member* member = GetMember(player->GetGUID()))
1437 {
1438 std::set<uint32> criteriaIds;
1439
1440 for (uint32 const* achievementIdItr = achievementIdsBegin; achievementIdItr != achievementIdsEnd; ++achievementIdItr)
1441 {
1442 uint32 achievementId = *achievementIdItr;
1443 if (AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementId))
1444 {
1445 if (!(achievement->Flags & ACHIEVEMENT_FLAG_GUILD) || GetAchievementMgr().HasAchieved(achievementId))
1446 continue;
1447
1448 if (CriteriaTree const* tree = sCriteriaMgr->GetCriteriaTree(achievement->CriteriaTree))
1449 {
1450 CriteriaMgr::WalkCriteriaTree(tree, [&criteriaIds](CriteriaTree const* node)
1451 {
1452 if (node->Criteria)
1453 criteriaIds.insert(node->Criteria->ID);
1454 });
1455 }
1456 }
1457 }
1458
1459 GetAchievementMgr().SendAllTrackedCriterias(player, criteriaIds);
1460 member->SetTrackedCriteriaIds(std::move(criteriaIds));
1461 }
1462}
1463
1464void Guild::HandleGetAchievementMembers(WorldSession* session, uint32 achievementId) const
1465{
1466 GetAchievementMgr().SendAchievementMembers(session->GetPlayer(), achievementId);
1467}
1468
1469void Guild::HandleSetMOTD(WorldSession* session, std::string_view motd)
1470{
1471 if (m_motd == motd)
1472 return;
1473
1474 // Player must have rights to set MOTD
1475 if (!_HasRankRight(session->GetPlayer(), GR_RIGHT_SETMOTD))
1477 else
1478 {
1479 m_motd = motd;
1480
1481 sScriptMgr->OnGuildMOTDChanged(this, m_motd);
1482
1484 stmt->setString(0, m_motd);
1485 stmt->setUInt64(1, m_id);
1486 CharacterDatabase.Execute(stmt);
1487
1488 SendEventMOTD(session, true);
1489 }
1490}
1491
1492void Guild::HandleSetInfo(WorldSession* session, std::string_view info)
1493{
1494 if (m_info == info)
1495 return;
1496
1497 // Player must have rights to set guild's info
1499 {
1500 m_info = info;
1501
1502 sScriptMgr->OnGuildInfoChanged(this, m_info);
1503
1505 stmt->setString(0, m_info);
1506 stmt->setUInt64(1, m_id);
1507 CharacterDatabase.Execute(stmt);
1508 }
1509}
1510
1511void Guild::HandleSetEmblem(WorldSession* session, EmblemInfo const& emblemInfo)
1512{
1513 Player* player = session->GetPlayer();
1514 if (!_IsLeader(player))
1515 SendSaveEmblemResult(session, ERR_GUILDEMBLEM_NOTGUILDMASTER); // "Only guild leaders can create emblems."
1516 else if (!player->HasEnoughMoney(uint64(EMBLEM_PRICE)))
1517 SendSaveEmblemResult(session, ERR_GUILDEMBLEM_NOTENOUGHMONEY); // "You can't afford to do that."
1518 else
1519 {
1520 player->ModifyMoney(-int64(EMBLEM_PRICE));
1521
1522 m_emblemInfo = emblemInfo;
1524
1525 SendSaveEmblemResult(session, ERR_GUILDEMBLEM_SUCCESS); // "Guild Emblem saved."
1526
1527 SendQueryResponse(session);
1528 }
1529}
1530
1531void Guild::HandleSetNewGuildMaster(WorldSession* session, std::string_view name, bool isSelfPromote)
1532{
1533 Player* player = session->GetPlayer();
1534
1535 Member* oldGuildMaster = GetMember(GetLeaderGUID());
1536 ASSERT(oldGuildMaster);
1537
1538 Member* newGuildMaster;
1539
1540 if (isSelfPromote)
1541 {
1542 newGuildMaster = GetMember(player->GetGUID());
1543 if (!newGuildMaster)
1544 return;
1545
1546 RankInfo const* oldRank = GetRankInfo(newGuildMaster->GetRankId());
1547
1548 if (oldRank->GetOrder() != GuildRankOrder(1) // only second highest rank can take over guild
1550 {
1552 return;
1553 }
1554 }
1555 else
1556 {
1557 if (!_IsLeader(player))
1558 {
1560 return;
1561 }
1562
1563 newGuildMaster = GetMember(name);
1564 if (!newGuildMaster)
1565 return;
1566 }
1567
1568 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1569
1570 _SetLeader(trans, *newGuildMaster);
1571 oldGuildMaster->ChangeRank(trans, _GetLowestRankId());
1572
1573 SendEventNewLeader(newGuildMaster, oldGuildMaster, isSelfPromote);
1574
1575 CharacterDatabase.CommitTransaction(trans);
1576}
1577
1578void Guild::HandleSetBankTabInfo(WorldSession* session, uint8 tabId, std::string_view name, std::string_view icon)
1579{
1580 BankTab* tab = GetBankTab(tabId);
1581 if (!tab)
1582 {
1583 TC_LOG_ERROR("guild", "Guild::HandleSetBankTabInfo: Player {} trying to change bank tab info from unexisting tab {}.",
1584 session->GetPlayerInfo(), tabId);
1585 return;
1586 }
1587
1588 tab->SetInfo(name, icon);
1589
1591 packet.Tab = tabId;
1592 packet.Name = name;
1593 packet.Icon = icon;
1594 BroadcastPacket(packet.Write());
1595}
1596
1597void Guild::HandleSetMemberNote(WorldSession* session, std::string_view note, ObjectGuid guid, bool isPublic)
1598{
1599 // Player must have rights to set public/officer note
1602 else if (Member* member = GetMember(guid))
1603 {
1604 if (isPublic)
1605 member->SetPublicNote(note);
1606 else
1607 member->SetOfficerNote(note);
1608
1610 updateNote.Member = guid;
1611 updateNote.IsPublic = isPublic;
1612 updateNote.Note = note;
1613 BroadcastPacket(updateNote.Write());
1614 }
1615}
1616
1617void Guild::HandleSetRankInfo(WorldSession* session, GuildRankId rankId, std::string_view name, uint32 rights, uint32 moneyPerDay, std::array<GuildBankRightsAndSlots, GUILD_BANK_MAX_TABS> const& rightsAndSlots)
1618{
1619 // Only leader can modify ranks
1620 if (!_IsLeader(session->GetPlayer()))
1622 else if (RankInfo* rankInfo = GetRankInfo(rankId))
1623 {
1624 rankInfo->SetName(name);
1625 rankInfo->SetRights(rights);
1626 _SetRankBankMoneyPerDay(rankId, moneyPerDay * GOLD);
1627
1628 for (auto itr = rightsAndSlots.begin(); itr != rightsAndSlots.end(); ++itr)
1629 _SetRankBankTabRightsAndSlots(rankId, *itr);
1630
1632 packet.RankID = AsUnderlyingType(rankId);
1633 BroadcastPacket(packet.Write());
1634 }
1635}
1636
1638{
1639 Player* player = session->GetPlayer();
1640 if (!player)
1641 return;
1642
1643 Member const* member = GetMember(player->GetGUID());
1644 if (!member)
1645 return;
1646
1648 return;
1649
1650 if (tabId != _GetPurchasedTabsSize())
1651 return;
1652
1653 if (tabId >= GUILD_BANK_MAX_TABS)
1654 return;
1655
1656 // Do not get money for bank tabs that the GM bought, we had to buy them already.
1657 // This is just a speedup check, GetGuildBankTabPrice will return 0.
1658 if (tabId < GUILD_BANK_MAX_TABS - 2) // 7th tab is actually the 6th
1659 {
1660 int64 tabCost = GetGuildBankTabPrice(tabId) * GOLD;
1661 if (!player->HasEnoughMoney(tabCost)) // Should not happen, this is checked by client
1662 return;
1663
1664 player->ModifyMoney(-tabCost);
1665 }
1666
1668
1670 BroadcastPacket(packet.Write());
1671
1672 SendPermissions(session);
1673}
1674
1675void Guild::HandleInviteMember(WorldSession* session, std::string_view name)
1676{
1677 Player* pInvitee = ObjectAccessor::FindPlayerByName(name);
1678 if (!pInvitee)
1679 {
1681 return;
1682 }
1683
1684 Player* player = session->GetPlayer();
1685 // Do not show invitations from ignored players
1686 if (pInvitee->GetSocial()->HasIgnore(player->GetGUID(), player->GetSession()->GetAccountGUID()))
1687 return;
1688
1689 if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && pInvitee->GetTeam() != player->GetTeam())
1690 {
1692 return;
1693 }
1694
1695 // Invited player cannot be in another guild
1696 if (pInvitee->GetGuildId())
1697 {
1699 return;
1700 }
1701
1702 // Invited player cannot be invited
1703 if (pInvitee->GetGuildIdInvited())
1704 {
1706 return;
1707 }
1708
1709 // Inviting player must have rights to invite
1710 if (!_HasRankRight(player, GR_RIGHT_INVITE))
1711 {
1713 return;
1714 }
1715
1717
1718 TC_LOG_DEBUG("guild", "Player {} invited {} to join his Guild", player->GetName(), pInvitee->GetName());
1719
1720 pInvitee->SetGuildIdInvited(m_id);
1722
1724
1727 invite.GuildGUID = GetGUID();
1728
1735
1736 invite.InviterName = player->GetName();
1737 invite.GuildName = GetName();
1738
1739 if (Guild* oldGuild = pInvitee->GetGuild())
1740 {
1741 invite.OldGuildGUID = oldGuild->GetGUID();
1742 invite.OldGuildName = oldGuild->GetName();
1744 }
1745
1746 pInvitee->SendDirectMessage(invite.Write());
1747 TC_LOG_DEBUG("guild", "SMSG_GUILD_INVITE [{}]", pInvitee->GetName());
1748}
1749
1751{
1752 Player* player = session->GetPlayer();
1753 if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) &&
1754 player->GetTeam() != sCharacterCache->GetCharacterTeamByGuid(GetLeaderGUID()))
1755 return;
1756
1757 CharacterDatabaseTransaction trans(nullptr);
1758 AddMember(trans, player->GetGUID());
1759}
1760
1762{
1763 Player* player = session->GetPlayer();
1764
1765 sCalendarMgr->RemovePlayerGuildEventsAndSignups(player->GetGUID(), GetId());
1766
1767 // If leader is leaving
1768 if (_IsLeader(player))
1769 {
1770 if (m_members.size() > 1)
1771 // Leader cannot leave if he is not the last member
1773 else
1774 {
1775 // Guild is disbanded if leader leaves.
1776 Disband();
1777 }
1778 }
1779 else
1780 {
1783
1785
1786 CharacterDatabaseTransaction trans(nullptr);
1787 DeleteMember(trans, player->GetGUID(), false, false);
1788 }
1789}
1790
1792{
1793 Player* player = session->GetPlayer();
1794
1795 // Player must have rights to remove members
1796 if (!_HasRankRight(player, GR_RIGHT_REMOVE))
1798 else if (Member* member = GetMember(guid))
1799 {
1800 std::string name = member->GetName();
1801
1802 // Guild masters cannot be removed
1803 if (member->IsRank(GuildRankId::GuildMaster))
1805 // Do not allow to remove player with the same rank or higher
1806 else
1807 {
1808 Member* memberMe = GetMember(player->GetGUID());
1809 RankInfo const* myRank = GetRankInfo(memberMe->GetRankId());
1810 RankInfo const* targetRank = GetRankInfo(member->GetRankId());
1811
1812 if (!memberMe || targetRank->GetOrder() <= myRank->GetOrder())
1814 else
1815 {
1817 SendEventPlayerLeft(member, memberMe, true);
1818
1820
1821 // After call to DeleteMember pointer to member becomes invalid
1822 CharacterDatabaseTransaction trans(nullptr);
1823 DeleteMember(trans, guid, false, true);
1824 }
1825 }
1826 }
1827}
1828
1830{
1831 Player* player = session->GetPlayer();
1833 // Player must have rights to promote
1834 if (!_HasRankRight(player, demote ? GR_RIGHT_DEMOTE : GR_RIGHT_PROMOTE))
1836 // Promoted player must be a member of guild
1837 else if (Member* member = GetMember(guid))
1838 {
1839 std::string name = member->GetName();
1840 // Player cannot promote himself
1841 if (member->IsSamePlayer(player->GetGUID()))
1842 {
1844 return;
1845 }
1846
1847 Member const* memberMe = GetMember(player->GetGUID());
1848 ASSERT(memberMe);
1849 RankInfo const* myRank = GetRankInfo(memberMe->GetRankId());
1850 RankInfo const* oldRank = GetRankInfo(member->GetRankId());
1851 GuildRankId newRankId;
1852 if (demote)
1853 {
1854 // Player can demote only lower rank members
1855 if (oldRank->GetOrder() <= myRank->GetOrder())
1856 {
1857 SendCommandResult(session, type, ERR_GUILD_RANK_TOO_HIGH_S, name);
1858 return;
1859 }
1860 // Lowest rank cannot be demoted
1861 RankInfo const* newRank = GetRankInfo(GuildRankOrder(AsUnderlyingType(oldRank->GetOrder()) + 1));
1862 if (!newRank)
1863 {
1864 SendCommandResult(session, type, ERR_GUILD_RANK_TOO_LOW_S, name);
1865 return;
1866 }
1867
1868 newRankId = newRank->GetId();
1869 }
1870 else
1871 {
1872 // Allow to promote only to lower rank than member's rank
1873 // memberMe->GetRankId() + 1 is the highest rank that current player can promote to
1874 if (GuildRankOrder(AsUnderlyingType(oldRank->GetOrder()) - 1) <= myRank->GetOrder())
1875 {
1876 SendCommandResult(session, type, ERR_GUILD_RANK_TOO_HIGH_S, name);
1877 return;
1878 }
1879
1880 newRankId = ASSERT_NOTNULL(GetRankInfo(GuildRankOrder(AsUnderlyingType(oldRank->GetOrder()) - 1)))->GetId();
1881 }
1882
1883 CharacterDatabaseTransaction trans(nullptr);
1884 member->ChangeRank(trans, newRankId);
1885 _LogEvent(demote ? GUILD_EVENT_LOG_DEMOTE_PLAYER : GUILD_EVENT_LOG_PROMOTE_PLAYER, player->GetGUID().GetCounter(), member->GetGUID().GetCounter(), AsUnderlyingType(newRankId));
1886 //_BroadcastEvent(demote ? GE_DEMOTION : GE_PROMOTION, ObjectGuid::Empty, player->GetName().c_str(), name.c_str(), _GetRankName(newRankId).c_str());
1887 }
1888}
1889
1891{
1892 Player* player = session->GetPlayer();
1893 Member* member = GetMember(targetGuid);
1894 if (!member)
1895 return;
1898
1899 RankInfo const* oldRank = GetRankInfo(member->GetRankId());
1900 RankInfo const* newRank = GetRankInfo(rank);
1901 if (!oldRank || !newRank)
1902 return;
1903
1904 if (rank > oldRank->GetOrder())
1905 {
1906 rights = GR_RIGHT_DEMOTE;
1908 }
1909
1910 // Promoted player must be a member of guild
1911 if (!_HasRankRight(player, rights))
1912 {
1914 return;
1915 }
1916
1917 // Player cannot promote himself
1918 if (member->IsSamePlayer(player->GetGUID()))
1919 {
1921 return;
1922 }
1923
1924 SendGuildRanksUpdate(setterGuid, targetGuid, newRank->GetId());
1925}
1926
1927void Guild::HandleAddNewRank(WorldSession* session, std::string_view name)
1928{
1931 return;
1932
1933 // Only leader can add new rank
1934 if (_IsLeader(session->GetPlayer()))
1935 {
1936 CharacterDatabaseTransaction trans(nullptr);
1938 {
1940 BroadcastPacket(eventPacket.Write());
1941 }
1942 }
1943}
1944
1946{
1947 // Cannot remove rank if total count is minimum allowed by the client or is not leader
1948 if (_GetRanksSize() <= GUILD_RANKS_MIN_COUNT || !_IsLeader(session->GetPlayer()))
1949 return;
1950
1951 auto rankItr = std::find_if(m_ranks.begin(), m_ranks.end(), [rankOrder](RankInfo const& rank)
1952 {
1953 return rank.GetOrder() == rankOrder;
1954 });
1955
1956 if (rankItr == m_ranks.end())
1957 return;
1958
1959 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1960
1961 // Delete bank rights for rank
1963 stmt->setUInt64(0, m_id);
1964 stmt->setUInt8(1, AsUnderlyingType(rankItr->GetId()));
1965 trans->Append(stmt);
1966
1967 // Delete rank
1968 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_RANK);
1969 stmt->setUInt64(0, m_id);
1970 stmt->setUInt8(1, AsUnderlyingType(rankItr->GetId()));
1971 trans->Append(stmt);
1972
1973 m_ranks.erase(rankItr);
1974
1975 // correct order of other ranks
1976 for (RankInfo& otherRank : m_ranks)
1977 {
1978 if (otherRank.GetOrder() < rankOrder)
1979 continue;
1980
1981 otherRank.SetOrder(GuildRankOrder(AsUnderlyingType(otherRank.GetOrder()) - 1));
1982
1983 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_RANK_ORDER);
1984 stmt->setUInt8(0, AsUnderlyingType(otherRank.GetOrder()));
1985 stmt->setUInt8(1, AsUnderlyingType(otherRank.GetId()));
1986 stmt->setUInt64(2, m_id);
1987 trans->Append(stmt);
1988 }
1989
1990 CharacterDatabase.CommitTransaction(trans);
1991
1993 BroadcastPacket(eventPacket.Write());
1994}
1995
1996void Guild::HandleShiftRank(WorldSession* session, GuildRankOrder rankOrder, bool shiftUp)
1997{
1998 // Only leader can modify ranks
1999 if (!_IsLeader(session->GetPlayer()))
2000 return;
2001
2002 GuildRankOrder otherRankOrder = GuildRankOrder(AsUnderlyingType(rankOrder) + (shiftUp ? -1 : 1));
2003
2004 RankInfo* rankInfo = GetRankInfo(rankOrder);
2005 RankInfo* otherRankInfo = GetRankInfo(otherRankOrder);
2006 if (!rankInfo || !otherRankInfo)
2007 return;
2008
2009 // can't shift guild master rank (rank id = 0) - there's already a client-side limitation for it so that's just a safe-guard
2010 if (rankInfo->GetId() == GuildRankId::GuildMaster || otherRankInfo->GetId() == GuildRankId::GuildMaster)
2011 return;
2012
2013 rankInfo->SetOrder(otherRankOrder);
2014 otherRankInfo->SetOrder(rankOrder);
2015
2016 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
2017
2019 stmt->setUInt8(0, AsUnderlyingType(rankInfo->GetOrder()));
2020 stmt->setUInt8(1, AsUnderlyingType(rankInfo->GetId()));
2021 stmt->setUInt64(2, m_id);
2022 trans->Append(stmt);
2023
2024 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GUILD_RANK_ORDER);
2025 stmt->setUInt8(0, AsUnderlyingType(otherRankInfo->GetOrder()));
2026 stmt->setUInt8(1, AsUnderlyingType(otherRankInfo->GetId()));
2027 stmt->setUInt64(2, m_id);
2028 trans->Append(stmt);
2029
2030 CharacterDatabase.CommitTransaction(trans);
2031
2032 // force client to re-request SMSG_GUILD_RANKS
2034}
2035
2036void Guild::HandleMemberDepositMoney(WorldSession* session, uint64 amount, bool cashFlow /*=false*/)
2037{
2038 // guild bank cannot have more than MAX_MONEY_AMOUNT
2039 amount = std::min(amount, MAX_MONEY_AMOUNT - m_bankMoney);
2040 if (!amount)
2041 return;
2042
2043 Player* player = session->GetPlayer();
2044
2045 // Call script after validation and before money transfer.
2046 sScriptMgr->OnGuildMemberDepositMoney(this, player, amount);
2047
2048 if (m_bankMoney > GUILD_BANK_MONEY_LIMIT - amount)
2049 {
2050 if (!cashFlow)
2052 return;
2053 }
2054
2055 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
2056 _ModifyBankMoney(trans, amount, true);
2057 if (!cashFlow)
2058 {
2059 player->ModifyMoney(-int64(amount));
2060 player->SaveInventoryAndGoldToDB(trans);
2061 }
2062
2064 CharacterDatabase.CommitTransaction(trans);
2065
2067
2069 {
2070 sLog->OutCommand(player->GetSession()->GetAccountId(),
2071 "GM {} (Account: {}) deposit money (Amount: {}) to guild bank (Guild ID {})",
2072 player->GetName(), player->GetSession()->GetAccountId(), amount, m_id);
2073 }
2074}
2075
2076bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint64 amount, bool repair)
2077{
2078 // clamp amount to MAX_MONEY_AMOUNT, Players can't hold more than that anyway
2079 amount = std::min(amount, MAX_MONEY_AMOUNT);
2080
2081 if (m_bankMoney < amount) // Not enough money in bank
2082 return false;
2083
2084 Player* player = session->GetPlayer();
2085
2086 Member* member = GetMember(player->GetGUID());
2087 if (!member)
2088 return false;
2089
2091 return false;
2092
2093 if (_GetMemberRemainingMoney(*member) < int64(amount)) // Check if we have enough slot/money today
2094 return false;
2095
2096 // Call script after validation and before money transfer.
2097 sScriptMgr->OnGuildMemberWitdrawMoney(this, player, amount, repair);
2098
2099 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
2100 // Add money to player (if required)
2101 if (!repair)
2102 {
2103 if (!player->ModifyMoney(amount))
2104 return false;
2105
2106 player->SaveInventoryAndGoldToDB(trans);
2107 }
2108
2109 // Update remaining money amount
2110 member->UpdateBankMoneyWithdrawValue(trans, amount);
2111 // Remove money from bank
2112 _ModifyBankMoney(trans, amount, false);
2113
2114 // Log guild bank event
2116 CharacterDatabase.CommitTransaction(trans);
2117
2119 return true;
2120}
2121
2123{
2124 Player* player = session->GetPlayer();
2125 if (Member* member = GetMember(player->GetGUID()))
2126 {
2127 member->SetStats(player);
2128 member->UpdateLogoutTime();
2129 member->ResetFlags();
2130 }
2131
2132 SendEventPresenceChanged(session, false, true);
2133 SaveToDB();
2134}
2135
2137{
2138 // Only leader can disband guild
2139 if (_IsLeader(session->GetPlayer()))
2140 {
2141 Disband();
2142 TC_LOG_DEBUG("guild", "{} successfully deleted", GetGUID().ToString());
2143 }
2144}
2145
2147{
2148 Player* player = session->GetPlayer();
2149 Group* group = player->GetGroup();
2150
2151 // Make sure player is a member of the guild and that he is in a group.
2152 if (!IsMember(player->GetGUID()) || !group)
2153 return;
2154
2155 WorldPackets::Guild::GuildPartyState partyStateResponse;
2156 partyStateResponse.InGuildParty = (player->GetMap()->GetOwnerGuildId(player->GetTeam()) == GetId());
2157 partyStateResponse.NumMembers = 0;
2158 partyStateResponse.NumRequired = 0;
2159 partyStateResponse.GuildXPEarnedMult = 0.0f;
2160 session->SendPacket(partyStateResponse.Write());
2161
2162 TC_LOG_DEBUG("guild", "SMSG_GUILD_PARTY_STATE_RESPONSE [{}]", session->GetPlayerInfo());
2163}
2164
2166{
2168
2169 for (int i = 0; i < GUILD_CHALLENGES_TYPES; ++i)
2170 updatePacket.CurrentCount[i] = int32(0);
2171
2172 for (int i = 0; i < GUILD_CHALLENGES_TYPES; ++i)
2173 updatePacket.MaxCount[i] = int32(GuildChallengesMaxCount[i]);
2174
2175 for (int i = 0; i < GUILD_CHALLENGES_TYPES; ++i)
2177
2178 for (int i = 0; i < GUILD_CHALLENGES_TYPES; ++i)
2179 updatePacket.Gold[i] = int32(GuildChallengeGoldReward[i]);
2180
2181 session->SendPacket(updatePacket.Write());
2182}
2183
2185{
2186 std::list<EventLogEntry> const& eventLog = m_eventLog.GetGuildLog();
2187
2189 packet.Entry.reserve(eventLog.size());
2190
2191 for (EventLogEntry const& entry : eventLog)
2192 entry.WritePacket(packet);
2193
2194 session->SendPacket(packet.Write());
2195
2196 TC_LOG_DEBUG("guild", "SMSG_GUILD_EVENT_LOG_QUERY_RESULTS [{}]", session->GetPlayerInfo());
2197}
2198
2200{
2201 std::list<NewsLogEntry> const& newsLog = m_newsLog.GetGuildLog();
2202
2204 packet.NewsEvents.reserve(newsLog.size());
2205
2206 for (NewsLogEntry const& newsLogEntry : newsLog)
2207 {
2208 newsLogEntry.WritePacket(packet);
2209 packet.NewsEvents.back().CompletedDate += session->GetTimezoneOffset();
2210 }
2211
2212 session->SendPacket(packet.Write());
2213
2214 TC_LOG_DEBUG("guild", "SMSG_GUILD_NEWS_UPDATE [{}]", session->GetPlayerInfo());
2215}
2216
2217void Guild::SendBankLog(WorldSession* session, uint8 tabId) const
2218{
2219 // GUILD_BANK_MAX_TABS send by client for money log
2220 if (tabId < _GetPurchasedTabsSize() || tabId == GUILD_BANK_MAX_TABS)
2221 {
2222 std::list<BankEventLogEntry> const& bankEventLog = m_bankEventLog[tabId].GetGuildLog();
2223
2225 packet.Tab = int32(tabId);
2226
2227 //if (tabId == GUILD_BANK_MAX_TABS && hasCashFlow)
2228 // packet.WeeklyBonusMoney.Set(uint64(weeklyBonusMoney));
2229
2230 packet.Entry.reserve(bankEventLog.size());
2231 for (BankEventLogEntry const& entry : bankEventLog)
2232 entry.WritePacket(packet);
2233
2234 session->SendPacket(packet.Write());
2235
2236 TC_LOG_DEBUG("guild", "SMSG_GUILD_BANK_LOG_QUERY_RESULT [{}] TabId: {}", session->GetPlayerInfo(), tabId);
2237 }
2238}
2239
2240void Guild::SendBankTabText(WorldSession* session, uint8 tabId) const
2241{
2242 if (BankTab const* tab = GetBankTab(tabId))
2243 tab->SendText(this, session);
2244}
2245
2247{
2248 Member const* member = GetMember(session->GetPlayer()->GetGUID());
2249 if (!member)
2250 return;
2251
2252 GuildRankId rankId = member->GetRankId();
2253
2255 queryResult.RankID = AsUnderlyingType(rankId);
2256 queryResult.WithdrawGoldLimit = _GetRankBankMoneyPerDay(rankId);
2257 queryResult.Flags = _GetRankRights(rankId);
2258 queryResult.NumTabs = _GetPurchasedTabsSize();
2259 queryResult.Tab.reserve(GUILD_BANK_MAX_TABS);
2260
2261 for (uint8 tabId = 0; tabId < GUILD_BANK_MAX_TABS; ++tabId)
2262 {
2264 tabPerm.Flags = _GetRankBankTabRights(rankId, tabId);
2265 tabPerm.WithdrawItemLimit = _GetMemberRemainingSlots(*member, tabId);
2266 }
2267
2268 session->SendPacket(queryResult.Write());
2269 TC_LOG_DEBUG("guild", "SMSG_GUILD_PERMISSIONS_QUERY_RESULTS [{}] Rank: {}", session->GetPlayerInfo(), uint32(rankId));
2270}
2271
2273{
2274 Member const* member = GetMember(session->GetPlayer()->GetGUID());
2275 if (!member)
2276 return;
2277
2278 int64 amount = _GetMemberRemainingMoney(*member);
2279
2281 packet.RemainingWithdrawMoney = amount;
2282 session->SendPacket(packet.Write());
2283
2284 TC_LOG_DEBUG("guild", "SMSG_GUILD_BANK_MONEY_WITHDRAWN [{}] Money: " SI64FMTD, session->GetPlayerInfo(), amount);
2285}
2286
2288{
2289 Player* player = session->GetPlayer();
2290 Member* member = GetMember(player->GetGUID());
2291 if (!member)
2292 return;
2293
2294 /*
2295 Login sequence:
2296 SMSG_GUILD_EVENT_MOTD
2297 SMSG_GUILD_RANK
2298 SMSG_GUILD_EVENT_PRESENCE_CHANGE - LoggedOn: True
2299 -- learn perks
2300 SMSG_ALL_GUILD_ACHIEVEMENTS
2301 SMSG_GUILD_MEMBER_DAILY_RESET // bank withdrawal reset
2302 */
2303
2304 SendEventMOTD(session);
2305 SendGuildRankInfo(session);
2306 SendEventPresenceChanged(session, true, true); // Broadcast
2307
2308 // Send to self separately, player is not in world yet and is not found by _BroadcastEvent
2309 SendEventPresenceChanged(session, true);
2310
2311 if (member->GetGUID() == GetLeaderGUID())
2312 {
2314 renameFlag.FlagSet = false;
2315 player->GetSession()->SendPacket(renameFlag.Write());
2316 }
2317
2318 for (GuildPerkSpellsEntry const* entry : sGuildPerkSpellsStore)
2319 player->LearnSpell(entry->SpellID, true);
2320
2322
2323 WorldPackets::Guild::GuildMemberDailyReset packet; // tells the client to request bank withdrawal limit
2324 player->GetSession()->SendPacket(packet.Write());
2325
2326 member->SetStats(player);
2328}
2329
2330void Guild::SendEventAwayChanged(ObjectGuid const& memberGuid, bool afk, bool dnd)
2331{
2332 Member* member = GetMember(memberGuid);
2333 if (!member)
2334 return;
2335
2336 if (afk)
2338 else
2340
2341 if (dnd)
2343 else
2345
2347 statusChange.Guid = memberGuid;
2348 statusChange.AFK = afk;
2349 statusChange.DND = dnd;
2350 BroadcastPacket(statusChange.Write());
2351}
2352
2354{
2356 eventPacket.Money = GetBankMoney();
2357 BroadcastPacket(eventPacket.Write());
2358}
2359
2360void Guild::SendEventMOTD(WorldSession* session, bool broadcast) const
2361{
2363 eventPacket.MotdText = GetMOTD();
2364
2365 if (broadcast)
2366 BroadcastPacket(eventPacket.Write());
2367 else
2368 {
2369 session->SendPacket(eventPacket.Write());
2370 TC_LOG_DEBUG("guild", "SMSG_GUILD_EVENT_MOTD [{}] ", session->GetPlayerInfo());
2371 }
2372}
2373
2374void Guild::SendEventNewLeader(Member* newLeader, Member* oldLeader, bool isSelfPromoted) const
2375{
2377 eventPacket.SelfPromoted = isSelfPromoted;
2378
2379 club::v1::MemberRoleChangedNotification memberRoleChangeNotification;
2380 memberRoleChangeNotification.set_club_id(GetId());
2381
2382 if (newLeader)
2383 {
2384 eventPacket.NewLeaderGUID = newLeader->GetGUID();
2385 eventPacket.NewLeaderName = newLeader->GetName();
2387
2388 // Owner/GuildMaster role is always 1.
2389 club::v1::RoleAssignment* newLeaderRoleAssignment = memberRoleChangeNotification.add_assignment();
2390 newLeaderRoleAssignment->set_allocated_member_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(newLeader->GetGUID()).release());
2391 newLeaderRoleAssignment->add_role(AsUnderlyingType(ClubRoleIdentifier::Owner));
2392 }
2393
2394 if (oldLeader)
2395 {
2396 eventPacket.OldLeaderGUID = oldLeader->GetGUID();
2397 eventPacket.OldLeaderName = oldLeader->GetName();
2399
2400 // Non owner members in guilds get the lowest club/community role after a guild master change.
2401 club::v1::RoleAssignment* oldLeaderRoleAssignment = memberRoleChangeNotification.add_assignment();
2402 oldLeaderRoleAssignment->set_allocated_member_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(oldLeader->GetGUID()).release());
2403 oldLeaderRoleAssignment->add_role(AsUnderlyingType(ClubRoleIdentifier::Member));
2404 }
2405
2406 eventPacket.Write();
2407
2408 // We have to send old guild and new club packets so we use a custom broadcast loop here.
2409 BroadcastWorker([&](Player const* member)
2410 {
2411 member->SendDirectMessage(eventPacket.GetRawPacket());
2412 Battlenet::WorldserverService<club::v1::ClubListener>(member->GetSession()).OnMemberRoleChanged(&memberRoleChangeNotification, true, true);
2413 });
2414}
2415
2416void Guild::SendEventPlayerLeft(Member* leaver, Member* remover, bool isRemoved) const
2417{
2419 eventPacket.Removed = isRemoved;
2420 eventPacket.LeaverGUID = leaver->GetGUID();
2421 eventPacket.LeaverName = leaver->GetName();
2423
2424 if (isRemoved && remover != nullptr)
2425 {
2426 eventPacket.RemoverGUID = remover->GetGUID();
2427 eventPacket.RemoverName = remover->GetName();
2429 }
2430
2431 eventPacket.Write();
2432
2433 Player* leaverPlayer = leaver->FindConnectedPlayer();
2434
2435 // Notify the removed member of club removal.
2436 if (leaverPlayer)
2437 {
2438 leaverPlayer->SendDirectMessage(eventPacket.GetRawPacket());
2439
2440 // Unsubscribe the removed player from the club to ensure interface updates.
2441 club::v1::UnsubscribeNotification unsubscribeNotification;
2442 unsubscribeNotification.set_club_id(GetId());
2443 Battlenet::WorldserverService<club::v1::ClubListener>(leaverPlayer->GetSession()).OnUnsubscribe(&unsubscribeNotification, true, true);
2444
2445 // Finally notify the client about leaving the club.
2446 club::v1::membership::ClubRemovedNotification clubRemovedNotification;
2447 clubRemovedNotification.set_club_id(GetId());
2448 clubRemovedNotification.set_reason(isRemoved
2451 clubRemovedNotification.set_allocated_member_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(leaver->GetGUID()).release());
2452 Battlenet::WorldserverService<club::v1::membership::ClubMembershipListener>(leaverPlayer->GetSession()).OnClubRemoved(&clubRemovedNotification, true, true);
2453 }
2454
2455 club::v1::MemberRemovedNotification memberRemovedNotification;
2456 memberRemovedNotification.set_club_id(GetId());
2457
2458 club::v1::MemberRemovedAssignment* removedMemberAssignment = memberRemovedNotification.add_member();
2459 removedMemberAssignment->set_allocated_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(leaver->GetGUID()).release());
2460 removedMemberAssignment->set_reason(isRemoved
2463
2464 // We have to send old guild and new club packets so we use a custom broadcast loop here.
2465 BroadcastWorker([&](Player const* member)
2466 {
2467 // Notify other guild members.
2468 member->SendDirectMessage(eventPacket.GetRawPacket());
2469 Battlenet::WorldserverService<::bgs::protocol::club::v1::ClubListener>(member->GetSession()).OnMemberRemoved(&memberRemovedNotification, true, true);
2470 }, leaverPlayer);
2471}
2472
2473void Guild::SendEventPresenceChanged(WorldSession* session, bool loggedOn, bool broadcast) const
2474{
2475 Player* player = session->GetPlayer();
2476
2478 eventPacket.Guid = player->GetGUID();
2479 eventPacket.Name = player->GetName();
2481 eventPacket.LoggedOn = loggedOn;
2482 eventPacket.Mobile = false;
2483
2484 if (broadcast)
2485 BroadcastPacket(eventPacket.Write());
2486 else
2487 session->SendPacket(eventPacket.Write());
2488}
2489
2490// Loading methods
2492{
2493 m_id = fields[0].GetUInt64();
2494 m_name = fields[1].GetString();
2495 m_leaderGuid = ObjectGuid::Create<HighGuid::Player>(fields[2].GetUInt64());
2496
2497 if (!m_emblemInfo.LoadFromDB(fields))
2498 {
2499 TC_LOG_ERROR("guild", "Guild {} has invalid emblem colors (Background: {}, Border: {}, Emblem: {}), skipped.",
2501 return false;
2502 }
2503
2504 m_info = fields[8].GetString();
2505 m_motd = fields[9].GetString();
2506 m_createdDate = time_t(fields[10].GetUInt32());
2507 m_bankMoney = fields[11].GetUInt64();
2508
2509 uint8 purchasedTabs = uint8(fields[12].GetUInt64());
2510 if (purchasedTabs > GUILD_BANK_MAX_TABS)
2511 purchasedTabs = GUILD_BANK_MAX_TABS;
2512
2513 m_bankTabs.clear();
2514 m_bankTabs.reserve(purchasedTabs);
2515 for (uint8 i = 0; i < purchasedTabs; ++i)
2516 m_bankTabs.emplace_back(m_id, i);
2517 return true;
2518}
2519
2521{
2522 RankInfo rankInfo(m_id);
2523
2524 rankInfo.LoadFromDB(fields);
2525
2526 m_ranks.push_back(rankInfo);
2527}
2528
2530{
2531 ObjectGuid::LowType lowguid = fields[1].GetUInt64();
2532 ObjectGuid playerGuid(ObjectGuid::Create<HighGuid::Player>(lowguid));
2533
2534 auto [memberIt, isNew] = m_members.try_emplace(playerGuid, m_id, playerGuid, GuildRankId(fields[2].GetUInt8()));
2535 if (!isNew)
2536 {
2537 TC_LOG_ERROR("guild", "Tried to add {} to guild '{}'. Member already exists.", playerGuid.ToString(), m_name);
2538 return false;
2539 }
2540
2541 Member& member = memberIt->second;
2542 if (!member.LoadFromDB(fields))
2543 {
2544 CharacterDatabaseTransaction trans(nullptr);
2545 Guild::_DeleteMemberFromDB(trans, lowguid);
2546 m_members.erase(memberIt);
2547 return false;
2548 }
2549
2550 sCharacterCache->UpdateCharacterGuildId(playerGuid, GetId());
2551 return true;
2552}
2553
2555{
2556 // tabId rights slots
2557 GuildBankRightsAndSlots rightsAndSlots(fields[1].GetUInt8(), fields[3].GetInt8(), fields[4].GetInt32());
2558 // rankId
2559 _SetRankBankTabRightsAndSlots(GuildRankId(fields[2].GetUInt8()), rightsAndSlots, false);
2560}
2561
2563{
2564 if (m_eventLog.CanInsert())
2565 {
2566 m_eventLog.LoadEvent(
2567 m_id, // guild id
2568 fields[1].GetUInt32(), // guid
2569 fields[6].GetInt64(), // timestamp
2570 GuildEventLogTypes(fields[2].GetUInt8()), // event type
2571 fields[3].GetUInt64(), // player guid 1
2572 fields[4].GetUInt64(), // player guid 2
2573 fields[5].GetUInt8()); // rank
2574 return true;
2575 }
2576 return false;
2577}
2578
2580{
2581 uint8 dbTabId = fields[1].GetUInt8();
2582 bool isMoneyTab = (dbTabId == GUILD_BANK_MONEY_LOGS_TAB);
2583 if (dbTabId < _GetPurchasedTabsSize() || isMoneyTab)
2584 {
2585 uint8 tabId = isMoneyTab ? uint8(GUILD_BANK_MAX_TABS) : dbTabId;
2587 if (bankLog.CanInsert())
2588 {
2589 uint32 guid = fields[2].GetUInt32();
2590 GuildBankEventLogTypes eventType = GuildBankEventLogTypes(fields[3].GetUInt8());
2591 if (BankEventLogEntry::IsMoneyEvent(eventType))
2592 {
2593 if (!isMoneyTab)
2594 {
2595 TC_LOG_ERROR("guild", "GuildBankEventLog ERROR: MoneyEvent(LogGuid: {}, Guild: {}) does not belong to money tab ({}), ignoring...", guid, m_id, dbTabId);
2596 return false;
2597 }
2598 }
2599 else if (isMoneyTab)
2600 {
2601 TC_LOG_ERROR("guild", "GuildBankEventLog ERROR: non-money event (LogGuid: {}, Guild: {}) belongs to money tab, ignoring...", guid, m_id);
2602 return false;
2603 }
2604 bankLog.LoadEvent(
2605 m_id, // guild id
2606 guid, // guid
2607 fields[8].GetInt64(), // timestamp
2608 dbTabId, // tab id
2609 eventType, // event type
2610 fields[4].GetUInt64(), // player guid
2611 fields[5].GetUInt64(), // item or money
2612 fields[6].GetUInt16(), // itam stack count
2613 fields[7].GetUInt8()); // dest tab id
2614 }
2615 }
2616 return true;
2617}
2618
2620{
2621 if (!m_newsLog.CanInsert())
2622 return;
2623
2624 m_newsLog.LoadEvent(
2625 m_id, // guild id
2626 fields[1].GetUInt32(), // guid
2627 fields[6].GetInt64(), // timestamp //64 bits?
2628 GuildNews(fields[2].GetUInt8()), // type
2629 ObjectGuid::Create<HighGuid::Player>(fields[3].GetUInt64()), // player guid
2630 fields[4].GetUInt32(), // Flags
2631 fields[5].GetUInt32()); // value
2632}
2633
2635{
2636 uint8 tabId = fields[1].GetUInt8();
2637 if (tabId >= _GetPurchasedTabsSize())
2638 TC_LOG_ERROR("guild", "Invalid tab (tabId: {}) in guild bank, skipped.", tabId);
2639 else
2640 m_bankTabs[tabId].LoadFromDB(fields);
2641}
2642
2644{
2645 uint8 tabId = fields[52].GetUInt8();
2646 if (tabId >= _GetPurchasedTabsSize())
2647 {
2648 TC_LOG_ERROR("guild", "Invalid tab for item (GUID: {}, id: #{}) in guild bank, skipped.",
2649 fields[0].GetUInt32(), fields[1].GetUInt32());
2650 return false;
2651 }
2652 return m_bankTabs[tabId].LoadItemFromDB(fields);
2653}
2654
2655// Validates guild data loaded from database. Returns false if guild should be deleted.
2657{
2658 // Validate ranks data
2659 // GUILD RANKS represent a sequence starting from 0 = GUILD_MASTER (ALL PRIVILEGES) to max 9 (lowest privileges).
2660 // The lower rank id is considered higher rank - so promotion does rank-- and demotion does rank++
2661 // Between ranks in sequence cannot be gaps - so 0, 1, 2, 4 is impossible
2662 // Min ranks count is 2 and max is 10.
2663 bool broken_ranks = false;
2664 uint8 ranks = _GetRanksSize();
2665
2666 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
2667 if (ranks < GUILD_RANKS_MIN_COUNT || ranks > GUILD_RANKS_MAX_COUNT)
2668 {
2669 TC_LOG_ERROR("guild", "Guild {} has invalid number of ranks, creating new...", m_id);
2670 broken_ranks = true;
2671 }
2672 else
2673 {
2674 for (uint8 rankId = 0; rankId < ranks; ++rankId)
2675 {
2676 RankInfo* rankInfo = GetRankInfo(GuildRankId(rankId));
2677 if (rankInfo->GetId() != GuildRankId(rankId))
2678 {
2679 TC_LOG_ERROR("guild", "Guild {} has broken rank id {}, creating default set of ranks...", m_id, rankId);
2680 broken_ranks = true;
2681 }
2682 else
2683 rankInfo->CreateMissingTabsIfNeeded(_GetPurchasedTabsSize(), trans, true);
2684 }
2685 }
2686
2687 if (broken_ranks)
2688 {
2689 m_ranks.clear();
2691 }
2692
2693 // Validate members' data
2694 for (auto& [guid, member] : m_members)
2695 if (!GetRankInfo(member.GetRankId()))
2696 member.ChangeRank(trans, _GetLowestRankId());
2697
2698 // Repair the structure of the guild.
2699 // If the guildmaster doesn't exist or isn't member of the guild
2700 // attempt to promote another member.
2701 Member* leader = GetMember(m_leaderGuid);
2702 if (!leader)
2703 {
2704 CharacterDatabaseTransaction dummy(nullptr);
2705 if (DeleteMember(dummy, m_leaderGuid))
2706 return false;
2707 }
2708 else if (!leader->IsRank(GuildRankId::GuildMaster))
2709 _SetLeader(trans, *leader);
2710
2711 // Check config if multiple guildmasters are allowed
2712 if (!sConfigMgr->GetBoolDefault("Guild.AllowMultipleGuildMaster", false))
2713 for (auto& [guid, member] : m_members)
2714 if (member.GetRankId() == GuildRankId::GuildMaster && !member.IsSamePlayer(m_leaderGuid))
2715 member.ChangeRank(trans, GetRankInfo(GuildRankOrder(1))->GetId());
2716
2717 if (trans->GetSize() > 0)
2718 CharacterDatabase.CommitTransaction(trans);
2720 return true;
2721}
2722
2723// Broadcasts
2724void Guild::BroadcastToGuild(WorldSession* session, bool officerOnly, std::string_view msg, uint32 language) const
2725{
2726 if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK))
2727 {
2729 packet.Initialize(officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, Language(language), session->GetPlayer(), nullptr, msg);
2730 WorldPacket const* data = packet.Write();
2731 for (auto const& [guid, member] : m_members)
2732 if (Player* player = member.FindConnectedPlayer())
2733 if (player->GetSession() && _HasRankRight(player, officerOnly ? GR_RIGHT_OFFCHATLISTEN : GR_RIGHT_GCHATLISTEN) &&
2734 !player->GetSocial()->HasIgnore(session->GetPlayer()->GetGUID(), session->GetAccountGUID()))
2735 player->SendDirectMessage(data);
2736 }
2737}
2738
2739void Guild::BroadcastAddonToGuild(WorldSession* session, bool officerOnly, std::string_view msg, std::string_view prefix, bool isLogged) const
2740{
2741 if (session && session->GetPlayer() && _HasRankRight(session->GetPlayer(), officerOnly ? GR_RIGHT_OFFCHATSPEAK : GR_RIGHT_GCHATSPEAK))
2742 {
2744 packet.Initialize(officerOnly ? CHAT_MSG_OFFICER : CHAT_MSG_GUILD, isLogged ? LANG_ADDON_LOGGED : LANG_ADDON, session->GetPlayer(), nullptr, msg, 0, "", DEFAULT_LOCALE, prefix);
2745 WorldPacket const* data = packet.Write();
2746 for (auto const& [guid, member] : m_members)
2747 if (Player* player = member.FindPlayer())
2748 if (player->GetSession() && _HasRankRight(player, officerOnly ? GR_RIGHT_OFFCHATLISTEN : GR_RIGHT_GCHATLISTEN) &&
2749 !player->GetSocial()->HasIgnore(session->GetPlayer()->GetGUID(), session->GetAccountGUID()) &&
2750 player->GetSession()->IsAddonRegistered(prefix))
2751 player->SendDirectMessage(data);
2752 }
2753}
2754
2756{
2757 for (auto const& [guid, member] : m_members)
2758 if (member.IsRank(rankId))
2759 if (Player* player = member.FindConnectedPlayer())
2760 player->SendDirectMessage(packet);
2761}
2762
2763void Guild::BroadcastPacket(WorldPacket const* packet) const
2764{
2765 for (auto const& [guid, member] : m_members)
2766 if (Player* player = member.FindConnectedPlayer())
2767 player->SendDirectMessage(packet);
2768}
2769
2770std::vector<Player*> Guild::GetMembersTrackingCriteria(uint32 criteriaId) const
2771{
2772 std::vector<Player*> members;
2773 for (auto const& [guid, member] : m_members)
2774 if (member.IsTrackingCriteriaId(criteriaId))
2775 if (Player* player = member.FindPlayer())
2776 members.push_back(player);
2777
2778 return members;
2779}
2780
2781void Guild::MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 maxLevel, GuildRankOrder minRank)
2782{
2784
2785 for (auto const& [guid, member] : m_members)
2786 {
2787 // not sure if needed, maybe client checks it as well
2788 if (packet.Invites.size() >= CALENDAR_MAX_INVITES)
2789 {
2790 if (Player* player = session->GetPlayer())
2791 sCalendarMgr->SendCalendarCommandResult(player->GetGUID(), CALENDAR_ERROR_INVITES_EXCEEDED);
2792 return;
2793 }
2794
2795 if (guid == session->GetPlayer()->GetGUID())
2796 continue;
2797
2798 uint32 level = sCharacterCache->GetCharacterLevelByGuid(guid);
2799 if (level < minLevel || level > maxLevel)
2800 continue;
2801
2802 RankInfo const* rank = GetRankInfo(member.GetRankId());
2803 if (rank->GetOrder() > minRank)
2804 continue;
2805
2806 packet.Invites.emplace_back(guid, level);
2807 }
2808
2809 session->SendPacket(packet.Write());
2810}
2811
2812// Members handling
2814{
2816 // Player cannot be in guild
2817 if (player)
2818 {
2819 if (player->GetGuildId())
2820 return false;
2821 }
2822 else if (sCharacterCache->GetCharacterGuildIdByGuid(guid))
2823 return false;
2824
2825 // Remove all player signs from another petitions
2826 // This will be prevent attempt to join many guilds and corrupt guild data integrity
2828
2829 ObjectGuid::LowType lowguid = guid.GetCounter();
2830
2831 // If rank was not passed, assign lowest possible rank
2832 if (!rankId)
2833 rankId = _GetLowestRankId();
2834
2835 auto [memberIt, isNew] = m_members.try_emplace(guid, m_id, guid, *rankId);
2836 if (!isNew)
2837 {
2838 TC_LOG_ERROR("guild", "Tried to add {} to guild '{}'. Member already exists.", guid.ToString(), m_name);
2839 return false;
2840 }
2841
2842 Member& member = memberIt->second;
2843 std::string name;
2844 if (player)
2845 {
2846 player->SetInGuild(m_id);
2847 player->SetGuildIdInvited(UI64LIT(0));
2848 player->SetGuildRank(AsUnderlyingType(*rankId));
2849 player->SetGuildLevel(GetLevel());
2850 member.SetStats(player);
2851 SendLoginInfo(player->GetSession());
2852 name = player->GetName();
2853 }
2854 else
2855 {
2856 member.ResetFlags();
2857
2858 bool ok = false;
2859 // Player must exist
2861 stmt->setUInt64(0, lowguid);
2862 if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
2863 {
2864 Field* fields = result->Fetch();
2865 name = fields[0].GetString();
2866 member.SetStats(
2867 name,
2868 fields[1].GetUInt8(),
2869 fields[2].GetUInt8(),
2870 fields[3].GetUInt8(),
2871 fields[4].GetUInt8(),
2872 fields[5].GetUInt16(),
2873 fields[6].GetUInt32(),
2874 0);
2875
2876 ok = member.CheckStats();
2877 }
2878
2879 if (!ok)
2880 {
2881 m_members.erase(memberIt);
2882 return false;
2883 }
2884 sCharacterCache->UpdateCharacterGuildId(guid, GetId());
2885 }
2886
2887 member.SaveToDB(trans);
2888
2891
2892 WorldPackets::Guild::GuildEventPlayerJoined joinNotificationPacket;
2893 joinNotificationPacket.Guid = guid;
2894 joinNotificationPacket.Name = name;
2895 joinNotificationPacket.VirtualRealmAddress = GetVirtualRealmAddress();
2896 joinNotificationPacket.Write();
2897
2898 // Notify the added member with new club data.
2899 if (player)
2900 {
2901 player->SendDirectMessage(joinNotificationPacket.GetRawPacket());
2902
2903 club::v1::membership::ClubAddedNotification clubAddedNotification;
2904 clubAddedNotification.mutable_membership()->set_allocated_member_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(guid).release());
2905
2906 club::v1::ClubDescription* guildClub = clubAddedNotification.mutable_membership()->mutable_club();
2907 guildClub->set_id(GetId());
2908 guildClub->set_allocated_type(Battlenet::Services::ClubService::CreateGuildClubType().release());
2909 guildClub->set_name(GetName());
2910 guildClub->set_privacy_level(club::v1::PrivacyLevel::PRIVACY_LEVEL_OPEN);
2911 guildClub->set_visibility_level(club::v1::VISIBILITY_LEVEL_PRIVATE);
2912 guildClub->set_member_count(GetMembersCount());
2913
2914 // Set the club owner, guild master in this case.
2915 club::v1::MemberDescription* guildLeaderDescription = guildClub->add_leader();
2916 guildLeaderDescription->set_allocated_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(GetLeaderGUID()).release());
2917
2918 // Date is in microseconds.
2919 guildClub->set_creation_time(
2920 std::chrono::duration_cast<std::chrono::microseconds>(SystemTimePoint::clock::from_time_t(GetCreatedDate()).time_since_epoch()).count());
2921 guildClub->set_timezone("");
2922 guildClub->set_locale("");
2923
2924 Battlenet::WorldserverService<club::v1::membership::ClubMembershipListener>(player->GetSession()).OnClubAdded(&clubAddedNotification, true, true);
2925 }
2926
2927 club::v1::MemberAddedNotification memberAddedNotification;
2928 memberAddedNotification.set_club_id(GetId());
2929
2930 club::v1::Member* addedMember = memberAddedNotification.add_member();
2931 addedMember->set_allocated_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(guid).release());
2933 addedMember->add_role(AsUnderlyingType(ClubRoleIdentifier::Moderator));
2934 else
2935 addedMember->add_role(AsUnderlyingType(ClubRoleIdentifier::Member));
2936 addedMember->set_presence_level(club::v1::PresenceLevel::PRESENCE_LEVEL_RICH);
2937 addedMember->set_whisper_level(club::v1::WhisperLevel::WHISPER_LEVEL_OPEN);
2938 addedMember->set_note("");
2939 addedMember->set_active(member.IsOnline());
2940
2941 // We have to send old guild and new club packets so we use a custom broadcast loop here.
2942 BroadcastWorker([&](Player const* otherMember)
2943 {
2944 // Notify other online guild members.
2945 otherMember->SendDirectMessage(joinNotificationPacket.GetRawPacket());
2946 Battlenet::WorldserverService<club::v1::ClubListener>(otherMember->GetSession()).OnMemberAdded(&memberAddedNotification, true, true);
2947 }, player);
2948
2949 // Call scripts if member was succesfully added (and stored to database)
2950 sScriptMgr->OnGuildAddMember(this, player, AsUnderlyingType(*rankId));
2951
2952 return true;
2953}
2954
2955bool Guild::DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bool isDisbanding, bool isKicked)
2956{
2957 // Guild master can be deleted when loading guild and guid doesn't exist in characters table
2958 // or when he is removed from guild by gm command
2959 if (m_leaderGuid == guid && !isDisbanding)
2960 {
2961 Member* oldLeader = nullptr;
2962 Member* newLeader = nullptr;
2963 for (auto& [memberGuid, member] : m_members)
2964 {
2965 if (memberGuid == guid)
2966 oldLeader = &member;
2967 else if (!newLeader || newLeader->GetRankId() > member.GetRankId())
2968 newLeader = &member;
2969 }
2970
2971 if (!newLeader)
2972 {
2973 Disband();
2974 return true;
2975 }
2976
2977 _SetLeader(trans, *newLeader);
2978
2979 // If leader does not exist (at guild loading with deleted leader) do not send broadcasts
2980 if (oldLeader)
2981 {
2982 SendEventNewLeader(newLeader, oldLeader, true);
2983 SendEventPlayerLeft(oldLeader);
2984 }
2985 }
2986 // Call script on remove before member is actually removed from guild (and database)
2987 sScriptMgr->OnGuildRemoveMember(this, guid, isDisbanding, isKicked);
2988
2989 m_members.erase(guid);
2990
2991 // If player not online data in data field will be loaded from guild tabs no need to update it !!
2993 if (player)
2994 {
2995 player->SetInGuild(UI64LIT(0));
2996 player->SetGuildRank(0);
2997 player->SetGuildLevel(0);
2998
2999 for (GuildPerkSpellsEntry const* entry : sGuildPerkSpellsStore)
3000 player->RemoveSpell(entry->SpellID, false, false);
3001 }
3002 else
3003 sCharacterCache->UpdateCharacterGuildId(guid, 0);
3004
3006 if (!isDisbanding)
3008
3009 if (m_members.empty())
3010 {
3011 Disband();
3012 return true;
3013 }
3014
3015 return false;
3016}
3017
3019{
3020 if (GetRankInfo(newRank)) // Validate rank (allow only existing ranks)
3021 {
3022 if (Member* member = GetMember(guid))
3023 {
3024 member->ChangeRank(trans, newRank);
3025 return true;
3026 }
3027 }
3028
3029 return false;
3030}
3031
3033{
3034 return m_members.find(guid) != m_members.end();
3035}
3036
3038{
3039 Member const* member = GetMember(guid);
3040 if (!member)
3041 return 0;
3042
3043 return std::min(m_bankMoney, static_cast<uint64>(_GetMemberRemainingMoney(*member)));
3044}
3045
3046// Bank (items move)
3047void Guild::SwapItems(Player* player, uint8 tabId, uint8 slotId, uint8 destTabId, uint8 destSlotId, uint32 splitedAmount)
3048{
3049 if (tabId >= _GetPurchasedTabsSize() || slotId >= GUILD_BANK_MAX_SLOTS ||
3050 destTabId >= _GetPurchasedTabsSize() || destSlotId >= GUILD_BANK_MAX_SLOTS)
3051 return;
3052
3053 if (tabId == destTabId && slotId == destSlotId)
3054 return;
3055
3056 BankMoveItemData from(this, player, tabId, slotId);
3057 BankMoveItemData to(this, player, destTabId, destSlotId);
3058 _MoveItems(&from, &to, splitedAmount);
3059}
3060
3061void Guild::SwapItemsWithInventory(Player* player, bool toChar, uint8 tabId, uint8 slotId, uint8 playerBag, uint8 playerSlotId, uint32 splitedAmount)
3062{
3063 if ((slotId >= GUILD_BANK_MAX_SLOTS && slotId != NULL_SLOT) || tabId >= _GetPurchasedTabsSize())
3064 return;
3065
3066 BankMoveItemData bankData(this, player, tabId, slotId);
3067 PlayerMoveItemData charData(this, player, playerBag, playerSlotId);
3068 if (toChar)
3069 _MoveItems(&bankData, &charData, splitedAmount);
3070 else
3071 _MoveItems(&charData, &bankData, splitedAmount);
3072}
3073
3074// Bank tabs
3075void Guild::SetBankTabText(uint8 tabId, std::string_view text)
3076{
3077 if (BankTab* pTab = GetBankTab(tabId))
3078 {
3079 pTab->SetText(text);
3080 pTab->SendText(this, nullptr);
3081
3083 eventPacket.Tab = tabId;
3084 BroadcastPacket(eventPacket.Write());
3085 }
3086}
3087
3088Guild::Guild::RankInfo const* Guild::GetRankInfo(GuildRankId rankId) const
3089{
3090 auto rankItr = std::find_if(m_ranks.begin(), m_ranks.end(), [rankId](RankInfo const& rank)
3091 {
3092 return rank.GetId() == rankId;
3093 });
3094
3095 return rankItr != m_ranks.end() ? &*rankItr : nullptr;
3096}
3097
3099{
3100 auto rankItr = std::find_if(m_ranks.begin(), m_ranks.end(), [rankId](RankInfo const& rank)
3101 {
3102 return rank.GetId() == rankId;
3103 });
3104
3105 return rankItr != m_ranks.end() ? &*rankItr : nullptr;
3106}
3107
3108Guild::Guild::RankInfo const* Guild::GetRankInfo(GuildRankOrder rankOrder) const
3109{
3110 auto rankItr = std::find_if(m_ranks.begin(), m_ranks.end(), [rankOrder](RankInfo const& rank)
3111 {
3112 return rank.GetOrder() == rankOrder;
3113 });
3114
3115 return rankItr != m_ranks.end() ? &*rankItr : nullptr;
3116}
3117
3118Guild::Guild::RankInfo* Guild::GetRankInfo(GuildRankOrder rankOrder)
3119{
3120 auto rankItr = std::find_if(m_ranks.begin(), m_ranks.end(), [rankOrder](RankInfo const& rank)
3121 {
3122 return rank.GetOrder() == rankOrder;
3123 });
3124
3125 return rankItr != m_ranks.end() ? &*rankItr : nullptr;
3126}
3127
3128bool Guild::_HasRankRight(Player const* player, uint32 right) const
3129{
3130 if (player)
3131 if (Member const* member = GetMember(player->GetGUID()))
3132 return (_GetRankRights(member->GetRankId()) & right) != GR_RIGHT_NONE;
3133 return false;
3134}
3135
3137{
3138 return (_GetRankRights(rankId) & rights) != GR_RIGHT_NONE;
3139}
3140
3142{
3144 stmt->setUInt64(0, lowguid);
3145 CharacterDatabase.ExecuteOrAppend(trans, stmt);
3146}
3147
3148// Private methods
3150{
3151 uint8 tabId = _GetPurchasedTabsSize(); // Next free id
3152 m_bankTabs.emplace_back(m_id, tabId);
3153
3154 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
3155
3157 stmt->setUInt64(0, m_id);
3158 stmt->setUInt8 (1, tabId);
3159 trans->Append(stmt);
3160
3161 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_GUILD_BANK_TAB);
3162 stmt->setUInt64(0, m_id);
3163 stmt->setUInt8 (1, tabId);
3164 trans->Append(stmt);
3165
3166 ++tabId;
3167 for (auto itr = m_ranks.begin(); itr != m_ranks.end(); ++itr)
3168 (*itr).CreateMissingTabsIfNeeded(tabId, trans, false);
3169
3170 CharacterDatabase.CommitTransaction(trans);
3171}
3172
3174{
3175 ASSERT(trans);
3176
3178 stmt->setUInt64(0, m_id);
3179 trans->Append(stmt);
3180
3181 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_RIGHTS);
3182 stmt->setUInt64(0, m_id);
3183 trans->Append(stmt);
3184
3185 _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_MASTER, loc), GR_RIGHT_ALL);
3186 _CreateRank(trans, sObjectMgr->GetTrinityString(LANG_GUILD_OFFICER, loc), GR_RIGHT_ALL);
3190}
3191
3192bool Guild::_CreateRank(CharacterDatabaseTransaction trans, std::string_view name, uint32 rights)
3193{
3194 if (m_ranks.size() >= GUILD_RANKS_MAX_COUNT)
3195 return false;
3196
3197 uint8 newRankId = [&]()
3198 {
3199 uint8 freeRankId = 0;
3200 while (GetRankInfo(GuildRankId(freeRankId)))
3201 ++freeRankId;
3202
3203 return freeRankId;
3204 }();
3205
3206 // Ranks represent sequence 0, 1, 2, ... where 0 means guildmaster
3207 RankInfo info(m_id, GuildRankId(newRankId), GuildRankOrder(m_ranks.size()), name, rights, 0);
3208 m_ranks.push_back(info);
3209
3210 bool const isInTransaction = bool(trans);
3211 if (!isInTransaction)
3212 trans = CharacterDatabase.BeginTransaction();
3213
3215 info.SaveToDB(trans);
3216
3217 if (!isInTransaction)
3218 CharacterDatabase.CommitTransaction(trans);
3219
3220 return true;
3221}
3222
3223// Updates the number of accounts that are in the guild
3224// Player may have many characters in the guild, but with the same account
3226{
3227 // We use a set to be sure each element will be unique
3228 std::unordered_set<uint32> accountsIdSet;
3229 for (auto const& [guid, member] : m_members)
3230 accountsIdSet.insert(member.GetAccountId());
3231
3232 m_accountsNumber = accountsIdSet.size();
3233}
3234
3235// Detects if player is the guild master.
3236// Check both leader guid and player's rank (otherwise multiple feature with
3237// multiple guild masters won't work)
3238bool Guild::_IsLeader(Player* player) const
3239{
3240 if (player->GetGUID() == m_leaderGuid)
3241 return true;
3242 if (Member const* member = GetMember(player->GetGUID()))
3243 return member->IsRank(GuildRankId::GuildMaster);
3244 return false;
3245}
3246
3248{
3249 for (uint8 tabId = 0; tabId < _GetPurchasedTabsSize(); ++tabId)
3250 m_bankTabs[tabId].Delete(trans, removeItemsFromDB);
3251
3252 m_bankTabs.clear();
3253}
3254
3256{
3257 if (add)
3258 m_bankMoney += amount;
3259 else
3260 {
3261 // Check if there is enough money in bank.
3262 if (m_bankMoney < amount)
3263 return false;
3264 m_bankMoney -= amount;
3265 }
3266
3268 stmt->setUInt64(0, m_bankMoney);
3269 stmt->setUInt64(1, m_id);
3270 trans->Append(stmt);
3271 return true;
3272}
3273
3275{
3276 bool isInTransaction = bool(trans);
3277 if (!isInTransaction)
3278 trans = CharacterDatabase.BeginTransaction();
3279
3280 m_leaderGuid = leader.GetGUID();
3281 leader.ChangeRank(trans, GuildRankId::GuildMaster);
3282
3284 stmt->setUInt64(0, m_leaderGuid.GetCounter());
3285 stmt->setUInt64(1, m_id);
3286 trans->Append(stmt);
3287
3288 if (!isInTransaction)
3289 CharacterDatabase.CommitTransaction(trans);
3290}
3291
3293{
3294 if (RankInfo* rankInfo = GetRankInfo(rankId))
3295 rankInfo->SetBankMoneyPerDay(moneyPerDay);
3296}
3297
3299{
3300 if (rightsAndSlots.GetTabId() >= _GetPurchasedTabsSize())
3301 return;
3302
3303 if (RankInfo* rankInfo = GetRankInfo(rankId))
3304 rankInfo->SetBankTabSlotsAndRights(rightsAndSlots, saveToDB);
3305}
3306
3307inline std::string Guild::_GetRankName(GuildRankId rankId) const
3308{
3309 if (RankInfo const* rankInfo = GetRankInfo(rankId))
3310 return rankInfo->GetName();
3311 return "<unknown>";
3312}
3313
3315{
3316 if (RankInfo const* rankInfo = GetRankInfo(rankId))
3317 return rankInfo->GetRights();
3318 return 0;
3319}
3320
3322{
3323 if (RankInfo const* rankInfo = GetRankInfo(rankId))
3324 return rankInfo->GetBankMoneyPerDay();
3325 return 0;
3326}
3327
3329{
3330 if (tabId < _GetPurchasedTabsSize())
3331 if (RankInfo const* rankInfo = GetRankInfo(rankId))
3332 return rankInfo->GetBankTabSlotsPerDay(tabId);
3333 return 0;
3334}
3335
3337{
3338 if (RankInfo const* rankInfo = GetRankInfo(rankId))
3339 return rankInfo->GetBankTabRights(tabId);
3340 return 0;
3341}
3342
3343inline int32 Guild::_GetMemberRemainingSlots(Member const& member, uint8 tabId) const
3344{
3345 GuildRankId rankId = member.GetRankId();
3346 if (rankId == GuildRankId::GuildMaster)
3347 return static_cast<int32>(GUILD_WITHDRAW_SLOT_UNLIMITED);
3348 if ((_GetRankBankTabRights(rankId, tabId) & GUILD_BANK_RIGHT_VIEW_TAB) != 0)
3349 {
3350
3351 int32 remaining = _GetRankBankTabSlotsPerDay(rankId, tabId) - member.GetBankTabWithdrawValue(tabId);
3352 if (remaining > 0)
3353 return remaining;
3354
3355 }
3356 return 0;
3357}
3358
3360{
3361 GuildRankId rankId = member.GetRankId();
3362 if (rankId == GuildRankId::GuildMaster)
3363 return std::numeric_limits<int64>::max();
3364
3366 {
3367 int64 remaining = _GetRankBankMoneyPerDay(rankId) - member.GetBankMoneyWithdrawValue();
3368 if (remaining > 0)
3369 return remaining;
3370 }
3371 return 0;
3372}
3373
3375{
3376 if (Member* member = GetMember(guid))
3377 member->UpdateBankTabWithdrawValue(trans, tabId, 1);
3378}
3379
3380inline bool Guild::_MemberHasTabRights(ObjectGuid guid, uint8 tabId, int32 rights) const
3381{
3382 if (Member const* member = GetMember(guid))
3383 {
3384 // Leader always has full rights
3385 if (member->IsRank(GuildRankId::GuildMaster) || m_leaderGuid == guid)
3386 return true;
3387 return (_GetRankBankTabRights(member->GetRankId(), tabId) & rights) == rights;
3388 }
3389 return false;
3390}
3391
3392// Add new event log record
3393inline void Guild::_LogEvent(GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2, uint8 newRank)
3394{
3395 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
3396 m_eventLog.AddEvent(trans, m_id, m_eventLog.GetNextGUID(), eventType, playerGuid1, playerGuid2, newRank);
3397 CharacterDatabase.CommitTransaction(trans);
3398
3399 sScriptMgr->OnGuildEvent(this, uint8(eventType), playerGuid1, playerGuid2, newRank);
3400}
3401
3402// Add new bank event log record
3403void Guild::_LogBankEvent(CharacterDatabaseTransaction trans, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType lowguid, uint64 itemOrMoney, uint16 itemStackCount, uint8 destTabId)
3404{
3405 if (tabId > GUILD_BANK_MAX_TABS)
3406 return;
3407
3408 // not logging moves within the same tab
3409 if (eventType == GUILD_BANK_LOG_MOVE_ITEM && tabId == destTabId)
3410 return;
3411
3412 uint8 dbTabId = tabId;
3413 if (BankEventLogEntry::IsMoneyEvent(eventType))
3414 {
3415 tabId = GUILD_BANK_MAX_TABS;
3416 dbTabId = GUILD_BANK_MONEY_LOGS_TAB;
3417 }
3419 pLog.AddEvent(trans, m_id, pLog.GetNextGUID(), eventType, dbTabId, lowguid, itemOrMoney, itemStackCount, destTabId);
3420
3421 sScriptMgr->OnGuildBankEvent(this, uint8(eventType), tabId, lowguid, itemOrMoney, itemStackCount, destTabId);
3422}
3423
3424inline Item* Guild::_GetItem(uint8 tabId, uint8 slotId) const
3425{
3426 if (BankTab const* tab = GetBankTab(tabId))
3427 return tab->GetItem(slotId);
3428 return nullptr;
3429}
3430
3432{
3433 if (BankTab* pTab = GetBankTab(tabId))
3434 pTab->SetItem(trans, slotId, nullptr);
3435}
3436
3437void Guild::_MoveItems(MoveItemData* pSrc, MoveItemData* pDest, uint32 splitedAmount) const
3438{
3439 // 1. Initialize source item
3440 if (!pSrc->InitItem())
3441 return; // No source item
3442
3443 // 2. Check source item
3444 if (!pSrc->CheckItem(splitedAmount))
3445 return; // Source item or splited amount is invalid
3446
3447 // 3. Check destination rights
3448 if (!pDest->HasStoreRights(pSrc))
3449 return; // Player has no rights to store item in destination
3450
3451 // 4. Check source withdraw rights
3452 if (!pSrc->HasWithdrawRights(pDest))
3453 return; // Player has no rights to withdraw items from source
3454
3455 // 5. Check split
3456 if (splitedAmount)
3457 {
3458 // 5.1. Clone source item
3459 if (!pSrc->CloneItem(splitedAmount))
3460 return; // Item could not be cloned
3461
3462 // 5.2. Move splited item to destination
3463 Guild::_DoItemsMove(pSrc, pDest, true, splitedAmount);
3464 }
3465 else // 6. No split
3466 {
3467 // 6.1. Try to merge items in destination (pDest->GetItem() == nullptr)
3468 InventoryResult mergeAttemptResult = Guild::_DoItemsMove(pSrc, pDest, false);
3469 if (mergeAttemptResult != EQUIP_ERR_OK) // Item could not be merged
3470 {
3471 // 6.2. Try to swap items
3472 // 6.2.1. Initialize destination item
3473 if (!pDest->InitItem())
3474 {
3475 pSrc->SendEquipError(mergeAttemptResult, pSrc->GetItem(false));
3476 return;
3477 }
3478
3479 // 6.2.2. Check rights to store item in source (opposite direction)
3480 if (!pSrc->HasStoreRights(pDest))
3481 return; // Player has no rights to store item in source (opposite direction)
3482
3483 if (!pDest->HasWithdrawRights(pSrc))
3484 return; // Player has no rights to withdraw item from destination (opposite direction)
3485
3486 // 6.2.3. Swap items (pDest->GetItem() != nullptr)
3487 Guild::_DoItemsMove(pSrc, pDest, true);
3488 }
3489 }
3490 // 7. Send changes
3491 _SendBankContentUpdate(pSrc, pDest);
3492}
3493
3494InventoryResult Guild::_DoItemsMove(MoveItemData* pSrc, MoveItemData* pDest, bool sendError, uint32 splitedAmount)
3495{
3496 Item* pDestItem = pDest->GetItem();
3497 bool swap = (pDestItem != nullptr);
3498
3499 Item* pSrcItem = pSrc->GetItem(splitedAmount != 0);
3500 // 1. Can store source item in destination
3501 InventoryResult destResult = pDest->CanStore(pSrcItem, swap, sendError);
3502 if (destResult != EQUIP_ERR_OK)
3503 return destResult;
3504
3505 // 2. Can store destination item in source
3506 if (swap)
3507 {
3508 InventoryResult srcResult = pSrc->CanStore(pDestItem, true, true);
3509 if (srcResult != EQUIP_ERR_OK)
3510 return srcResult;
3511 }
3512
3513 // GM LOG (@todo move to scripts)
3514 pDest->LogAction(pSrc);
3515 if (swap)
3516 pSrc->LogAction(pDest);
3517
3518 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
3519 // 3. Log bank events
3520 pDest->LogBankEvent(trans, pSrc, pSrcItem->GetCount());
3521 if (swap)
3522 pSrc->LogBankEvent(trans, pDest, pDestItem->GetCount());
3523
3524 // 4. Remove item from source
3525 pSrc->RemoveItem(trans, pDest, splitedAmount);
3526
3527 // 5. Remove item from destination
3528 if (swap)
3529 pDest->RemoveItem(trans, pSrc);
3530
3531 // 6. Store item in destination
3532 pDest->StoreItem(trans, pSrcItem);
3533
3534 // 7. Store item in source
3535 if (swap)
3536 pSrc->StoreItem(trans, pDestItem);
3537
3538 CharacterDatabase.CommitTransaction(trans);
3539 return EQUIP_ERR_OK;
3540}
3541
3543{
3544 ASSERT(pSrc->IsBank() || pDest->IsBank());
3545
3546 uint8 tabId = 0;
3547 SlotIds slots;
3548 if (pSrc->IsBank()) // B ->
3549 {
3550 tabId = pSrc->GetContainer();
3551 slots.insert(pSrc->GetSlotId());
3552 if (pDest->IsBank()) // B -> B
3553 {
3554 // Same tab - add destination slots to collection
3555 if (pDest->GetContainer() == pSrc->GetContainer())
3556 pDest->CopySlots(slots);
3557 else // Different tabs - send second message
3558 {
3559 SlotIds destSlots;
3560 pDest->CopySlots(destSlots);
3561 _SendBankContentUpdate(pDest->GetContainer(), destSlots);
3562 }
3563 }
3564 }
3565 else if (pDest->IsBank()) // C -> B
3566 {
3567 tabId = pDest->GetContainer();
3568 pDest->CopySlots(slots);
3569 }
3570
3571 _SendBankContentUpdate(tabId, slots);
3572}
3573
3575{
3576 if (BankTab const* tab = GetBankTab(tabId))
3577 {
3579 packet.FullUpdate = true; // @todo
3580 packet.Tab = int32(tabId);
3581 packet.Money = m_bankMoney;
3582
3583 for (SlotIds::const_iterator itr = slots.begin(); itr != slots.end(); ++itr)
3584 {
3585 Item const* tabItem = tab->GetItem(*itr);
3586
3588
3589 itemInfo.Slot = int32(*itr);
3590 itemInfo.Item.ItemID = int32(tabItem ? tabItem->GetEntry() : 0);
3591 itemInfo.Count = int32(tabItem ? tabItem->GetCount() : 0);
3592 itemInfo.EnchantmentID = int32(tabItem ? tabItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT) : 0);
3593 itemInfo.Charges = int32(tabItem ? abs(tabItem->GetSpellCharges()) : 0);
3594 itemInfo.OnUseEnchantmentID = int32(tabItem ? tabItem->GetEnchantmentId(USE_ENCHANTMENT_SLOT) : 0);
3595 itemInfo.Flags = 0;
3596 itemInfo.Locked = false;
3597
3598 if (tabItem)
3599 {
3600 uint8 i = 0;
3601 for (UF::SocketedGem const& gemData : tabItem->m_itemData->Gems)
3602 {
3603 if (gemData.ItemID)
3604 {
3606 gem.Slot = i;
3607 gem.Item.Initialize(&gemData);
3608 itemInfo.SocketEnchant.push_back(gem);
3609 }
3610 ++i;
3611 }
3612 }
3613
3614 packet.ItemInfo.push_back(itemInfo);
3615 }
3616
3617 for (auto const& [guid, member] : m_members)
3618 {
3619 if (!_MemberHasTabRights(member.GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB))
3620 continue;
3621
3622 Player* player = member.FindPlayer();
3623 if (!player)
3624 continue;
3625
3626 packet.WithdrawalsRemaining = _GetMemberRemainingSlots(member, tabId);
3627 player->GetSession()->SendPacket(packet.Write());
3628 }
3629 }
3630}
3631
3632void Guild::SendBankList(WorldSession* session, uint8 tabId, bool fullUpdate) const
3633{
3634 Member const* member = GetMember(session->GetPlayer()->GetGUID());
3635 if (!member) // Shouldn't happen, just in case
3636 return;
3637
3639
3640 packet.Money = m_bankMoney;
3641 packet.WithdrawalsRemaining = _GetMemberRemainingSlots(*member, tabId);
3642 packet.Tab = int32(tabId);
3643 packet.FullUpdate = fullUpdate;
3644
3645 // TabInfo
3646 if (fullUpdate)
3647 {
3648 packet.TabInfo.reserve(_GetPurchasedTabsSize());
3649 for (uint8 i = 0; i < _GetPurchasedTabsSize(); ++i)
3650 {
3651 WorldPackets::Guild::GuildBankTabInfo& tabInfo = packet.TabInfo.emplace_back();
3652 tabInfo.TabIndex = i;
3653 tabInfo.Name = m_bankTabs[i].GetName();
3654 tabInfo.Icon = m_bankTabs[i].GetIcon();
3655 }
3656 }
3657
3658 // ItemInfo
3659 uint32 itemCount = 0;
3660 if (fullUpdate && _MemberHasTabRights(session->GetPlayer()->GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB))
3661 if (BankTab const* tab = GetBankTab(tabId))
3662 for (uint8 slotId = 0; slotId < GUILD_BANK_MAX_SLOTS; ++slotId)
3663 if (tab->GetItem(slotId))
3664 ++itemCount;
3665
3666 packet.ItemInfo.reserve(itemCount);
3667
3668 if (fullUpdate && _MemberHasTabRights(session->GetPlayer()->GetGUID(), tabId, GUILD_BANK_RIGHT_VIEW_TAB))
3669 {
3670 if (BankTab const* tab = GetBankTab(tabId))
3671 {
3672 for (uint8 slotId = 0; slotId < GUILD_BANK_MAX_SLOTS; ++slotId)
3673 {
3674 if (Item* tabItem = tab->GetItem(slotId))
3675 {
3676 WorldPackets::Guild::GuildBankItemInfo& itemInfo = packet.ItemInfo.emplace_back();
3677
3678 itemInfo.Slot = int32(slotId);
3679 itemInfo.Item.ItemID = tabItem->GetEntry();
3680 itemInfo.Count = int32(tabItem->GetCount());
3681 itemInfo.Charges = int32(abs(tabItem->GetSpellCharges()));
3682 itemInfo.EnchantmentID = int32(tabItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT));
3683 itemInfo.OnUseEnchantmentID = int32(tabItem->GetEnchantmentId(USE_ENCHANTMENT_SLOT));
3684 itemInfo.Flags = tabItem->m_itemData->DynamicFlags;
3685
3686 uint8 i = 0;
3687 for (UF::SocketedGem const& gemData : tabItem->m_itemData->Gems)
3688 {
3689 if (gemData.ItemID)
3690 {
3692 gem.Slot = i;
3693 gem.Item.Initialize(&gemData);
3694 itemInfo.SocketEnchant.push_back(gem);
3695 }
3696 ++i;
3697 }
3698
3699 itemInfo.Locked = false;
3700 }
3701 }
3702 }
3703 }
3704
3705 session->SendPacket(packet.Write());
3706}
3707
3709{
3710 Member* member = GetMember(targetGuid);
3711 ASSERT(member);
3712
3714 rankChange.Officer = setterGuid;
3715 rankChange.Other = targetGuid;
3716 rankChange.RankID = AsUnderlyingType(rank);
3717 rankChange.Promote = (rank < member->GetRankId());
3718 rankChange.Write();
3719
3720 club::v1::MemberRoleChangedNotification memberRoleChangeNotification;
3721 memberRoleChangeNotification.set_club_id(GetId());
3722
3723 club::v1::RoleAssignment* changedRoleAssignment = memberRoleChangeNotification.add_assignment();
3724 changedRoleAssignment->set_allocated_member_id(Battlenet::Services::ClubMembershipService::CreateClubMemberId(targetGuid).release());
3725 if (rank == GuildRankId::GuildMaster)
3726 changedRoleAssignment->add_role(AsUnderlyingType(ClubRoleIdentifier::Owner));
3728 changedRoleAssignment->add_role(AsUnderlyingType(ClubRoleIdentifier::Moderator));
3729 else
3730 changedRoleAssignment->add_role(AsUnderlyingType(ClubRoleIdentifier::Member));
3731
3732 BroadcastWorker([&](Player const* memberPlayer)
3733 {
3734 memberPlayer->SendDirectMessage(rankChange.GetRawPacket());
3735 Battlenet::WorldserverService<club::v1::ClubListener>(memberPlayer->GetSession()).OnMemberRoleChanged(&memberRoleChangeNotification, true, true);
3736 });
3737
3739 member->ChangeRank(trans, rank);
3740
3741 TC_LOG_DEBUG("network", "SMSG_GUILD_RANKS_UPDATE [Broadcast] Target: {}, Issuer: {}, RankId: {}",
3742 targetGuid.ToString(), setterGuid.ToString(), uint32(rank));
3743}
3744
3745void Guild::ResetTimes(bool weekly)
3746{
3747 for (auto& [guid, member] : m_members)
3748 {
3749 member.ResetValues(weekly);
3750 if (Player* player = member.FindPlayer())
3751 {
3752 WorldPackets::Guild::GuildMemberDailyReset packet; // tells the client to request bank withdrawal limit
3753 player->GetSession()->SendPacket(packet.Write());
3754 }
3755 }
3756}
3757
3759{
3760 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
3761 NewsLogEntry& news = m_newsLog.AddEvent(trans, m_id, m_newsLog.GetNextGUID(), GuildNews(type), guid, flags, value);
3762 CharacterDatabase.CommitTransaction(trans);
3763
3764 auto packetBuilder = [&](Player const* receiver)
3765 {
3767 newsPacket.NewsEvents.reserve(1);
3768 news.WritePacket(newsPacket);
3769 newsPacket.NewsEvents.back().CompletedDate += receiver->GetSession()->GetTimezoneOffset();
3770
3771 receiver->SendDirectMessage(newsPacket.Write());
3772 };
3773 BroadcastWorker(packetBuilder);
3774}
3775
3776bool Guild::HasAchieved(uint32 achievementId) const
3777{
3778 return GetAchievementMgr().HasAchieved(achievementId);
3779}
3780
3781void Guild::UpdateCriteria(CriteriaType type, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, WorldObject const* ref, Player* player)
3782{
3783 GetAchievementMgr().UpdateCriteria(type, miscValue1, miscValue2, miscValue3, ref, player);
3784}
3785
3786void Guild::HandleNewsSetSticky(WorldSession* session, uint32 newsId, bool sticky)
3787{
3788 std::list<NewsLogEntry>& newsLog = m_newsLog.GetGuildLog();
3789 auto itr = newsLog.begin();
3790 while (itr != newsLog.end() && itr->GetGUID() != newsId)
3791 ++itr;
3792
3793 if (itr == newsLog.end())
3794 {
3795 TC_LOG_DEBUG("guild", "HandleNewsSetSticky: [{}] requested unknown newsId {} - Sticky: {}",
3796 session->GetPlayerInfo(), newsId, sticky);
3797 return;
3798 }
3799
3800 itr->SetSticky(sticky);
3801
3802 TC_LOG_DEBUG("guild", "HandleNewsSetSticky: [{}] changed newsId {} sticky to {}",
3803 session->GetPlayerInfo(), newsId, sticky);
3804
3806 newsPacket.NewsEvents.reserve(1);
3807 itr->WritePacket(newsPacket);
3808 newsPacket.NewsEvents.back().CompletedDate += session->GetTimezoneOffset();
3809 session->SendPacket(newsPacket.Write());
3810}
#define sCalendarMgr
Definition: CalendarMgr.h:370
@ CALENDAR_ERROR_INVITES_EXCEEDED
Definition: CalendarMgr.h:110
@ CALENDAR_MAX_INVITES
Definition: CalendarMgr.h:136
#define sCharacterCache
@ CHAR_INS_GUILD_MEMBER
@ CHAR_UPD_GUILD_MOTD
@ CHAR_DEL_GUILD_BANK_TABS
@ CHAR_UPD_GUILD_BANK_TAB_TEXT
@ CHAR_INS_GUILD_NEWS
@ 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_INS_GUILD_MEMBER_WITHDRAW_TABS
@ 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_UPD_GUILD_RANK_ORDER
@ CHAR_DEL_GUILD_RANK
@ CHAR_INS_GUILD_BANK_ITEM
@ CHAR_INS_GUILD_MEMBER_WITHDRAW_MONEY
@ CHAR_UPD_GUILD_BANK_TAB_INFO
@ CHAR_INS_GUILD_BANK_RIGHT
LocaleConstant
Definition: Common.h:48
#define DEFAULT_LOCALE
Definition: Common.h:66
@ DAY
Definition: Common.h:31
#define sConfigMgr
Definition: Config.h:61
#define sCriteriaMgr
DB2Storage< AchievementEntry > sAchievementStore("Achievement.db2", &AchievementLoadInfo::Instance)
DB2Storage< GuildColorEmblemEntry > sGuildColorEmblemStore("GuildColorEmblem.db2", &GuildColorEmblemLoadInfo::Instance)
DB2Storage< ChrClassesEntry > sChrClassesStore("ChrClasses.db2", &ChrClassesLoadInfo::Instance)
DB2Storage< GuildPerkSpellsEntry > sGuildPerkSpellsStore("GuildPerkSpells.db2", &GuildPerkSpellsLoadInfo::Instance)
DB2Storage< GuildColorBackgroundEntry > sGuildColorBackgroundStore("GuildColorBackground.db2", &GuildColorBackgroundLoadInfo::Instance)
DB2Storage< ChrRacesEntry > sChrRacesStore("ChrRaces.db2", &ChrRacesLoadInfo::Instance)
DB2Storage< GuildColorBorderEntry > sGuildColorBorderStore("GuildColorBorder.db2", &GuildColorBorderLoadInfo::Instance)
@ ACHIEVEMENT_FLAG_GUILD
Definition: DBCEnums.h:98
CriteriaType
Definition: DBCEnums.h:503
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
uint8_t uint8
Definition: Define.h:144
int64_t int64
Definition: Define.h:137
int8_t int8
Definition: Define.h:140
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
#define UI64LIT(N)
Definition: Define.h:127
uint16_t uint16
Definition: Define.h:143
#define SI64FMTD
Definition: Define.h:129
uint32_t uint32
Definition: Define.h:142
uint16 flags
Definition: DisableMgr.cpp:49
#define ASSERT_NOTNULL(pointer)
Definition: Errors.h:84
#define ASSERT
Definition: Errors.h:68
#define sGuildMgr
Definition: GuildMgr.h:70
uint64 GetGuildBankTabPrice(uint8 tabId)
Definition: Guild.cpp:53
uint32 const EMBLEM_PRICE
Definition: Guild.cpp:51
size_t const MAX_GUILD_BANK_TAB_TEXT_LEN
Definition: Guild.cpp:49
@ GUILD_RANKS_MIN_COUNT
Definition: Guild.h:58
@ GUILD_EVENT_LOG_GUID_UNDEFINED
Definition: Guild.h:63
@ GUILD_WITHDRAW_SLOT_UNLIMITED
Definition: Guild.h:62
@ GUILD_BANK_MONEY_LOGS_TAB
Definition: Guild.h:56
@ GUILD_BANK_MAX_SLOTS
Definition: Guild.h:55
@ GUILD_RANKS_MAX_COUNT
Definition: Guild.h:59
@ GUILD_BANK_MAX_TABS
Definition: Guild.h:54
@ GUILD_MASTER_DETHRONE_INACTIVE_DAYS
Definition: Guild.h:57
@ GUILDMEMBER_STATUS_AFK
Definition: Guild.h:233
@ GUILDMEMBER_STATUS_NONE
Definition: Guild.h:231
@ GUILDMEMBER_STATUS_ONLINE
Definition: Guild.h:232
@ GUILDMEMBER_STATUS_DND
Definition: Guild.h:234
@ GUILD_BANK_RIGHT_VIEW_TAB
Definition: Guild.h:187
@ GUILD_BANK_RIGHT_DEPOSIT_ITEM
Definition: Guild.h:191
constexpr uint64 GUILD_BANK_MONEY_LIMIT
Definition: Guild.h:68
#define GUILD_CHALLENGES_TYPES
Definition: Guild.h:263
GuildCommandType
Definition: Guild.h:130
@ GUILD_COMMAND_PROMOTE_PLAYER
Definition: Guild.h:135
@ GUILD_COMMAND_CHANGE_LEADER
Definition: Guild.h:138
@ GUILD_COMMAND_DEMOTE_PLAYER
Definition: Guild.h:136
@ GUILD_COMMAND_LEAVE_GUILD
Definition: Guild.h:133
@ GUILD_COMMAND_REMOVE_PLAYER
Definition: Guild.h:137
@ GUILD_COMMAND_EDIT_PUBLIC_NOTE
Definition: Guild.h:143
@ GUILD_COMMAND_MOVE_ITEM
Definition: Guild.h:145
@ GUILD_COMMAND_CHANGE_RANK
Definition: Guild.h:142
@ GUILD_COMMAND_INVITE_PLAYER
Definition: Guild.h:132
@ GUILD_COMMAND_EDIT_MOTD
Definition: Guild.h:139
const uint32 GuildChallengeMaxLevelGoldReward[GUILD_CHALLENGES_TYPES]
Definition: Guild.h:266
GuildCommandError
Definition: Guild.h:150
@ ERR_GUILD_COMMAND_SUCCESS
Definition: Guild.h:151
const uint32 GuildChallengeGoldReward[GUILD_CHALLENGES_TYPES]
Definition: Guild.h:265
const uint32 GuildChallengesMaxCount[GUILD_CHALLENGES_TYPES]
Definition: Guild.h:267
std::set< uint8 > SlotIds
Definition: Guild.h:326
GuildNews
Definition: Guild.h:239
@ GUILD_NEWS_ITEM_CRAFTED
Definition: Guild.h:244
@ GUILD_NEWS_ITEM_LOOTED
Definition: Guild.h:243
@ GUILD_NEWS_ITEM_PURCHASED
Definition: Guild.h:245
GuildRankOrder
Definition: Guild.h:100
GuildBankEventLogTypes
Definition: Guild.h:196
@ GUILD_BANK_LOG_MOVE_ITEM
Definition: Guild.h:199
@ GUILD_BANK_LOG_WITHDRAW_ITEM
Definition: Guild.h:198
@ GUILD_BANK_LOG_DEPOSIT_MONEY
Definition: Guild.h:200
@ GUILD_BANK_LOG_DEPOSIT_ITEM
Definition: Guild.h:197
@ GUILD_BANK_LOG_WITHDRAW_MONEY
Definition: Guild.h:201
@ GUILD_BANK_LOG_CASH_FLOW_DEPOSIT
Definition: Guild.h:206
@ GUILD_BANK_LOG_REPAIR_MONEY
Definition: Guild.h:202
@ GUILD_BANK_LOG_MOVE_ITEM2
Definition: Guild.h:203
GuildRankRights
Definition: Guild.h:103
@ GR_RIGHT_EOFFNOTE
Definition: Guild.h:120
@ GR_RIGHT_GCHATSPEAK
Definition: Guild.h:106
@ GR_RIGHT_NONE
Definition: Guild.h:104
@ GR_RIGHT_OFFCHATSPEAK
Definition: Guild.h:108
@ GR_RIGHT_ALL
Definition: Guild.h:126
@ GR_RIGHT_OFFCHATLISTEN
Definition: Guild.h:107
@ GR_RIGHT_GCHATLISTEN
Definition: Guild.h:105
@ GR_RIGHT_SETMOTD
Definition: Guild.h:117
@ GR_RIGHT_MODIFY_GUILD_INFO
Definition: Guild.h:121
@ GR_RIGHT_VIEWOFFNOTE
Definition: Guild.h:119
@ GR_RIGHT_WITHDRAW_REPAIR
Definition: Guild.h:123
@ GR_RIGHT_REMOVE
Definition: Guild.h:110
@ GR_RIGHT_WITHDRAW_GOLD
Definition: Guild.h:124
@ GR_RIGHT_INVITE
Definition: Guild.h:109
@ GR_RIGHT_EDIT_PUBLIC_NOTE
Definition: Guild.h:118
@ GR_RIGHT_DEMOTE
Definition: Guild.h:113
@ GR_RIGHT_PROMOTE
Definition: Guild.h:112
@ GUILD_MEMBER_DATA_LEVEL
Definition: Guild.h:74
@ GUILD_MEMBER_DATA_ACHIEVEMENT_POINTS
Definition: Guild.h:73
@ GUILD_MEMBER_DATA_ZONEID
Definition: Guild.h:72
GuildRankId
Definition: Guild.h:96
GuildEmblemError
Definition: Guild.h:220
GuildEventLogTypes
Definition: Guild.h:210
@ GUILD_EVENT_LOG_LEAVE_GUILD
Definition: Guild.h:216
@ GUILD_EVENT_LOG_PROMOTE_PLAYER
Definition: Guild.h:213
@ GUILD_EVENT_LOG_UNINVITE_PLAYER
Definition: Guild.h:215
@ GUILD_EVENT_LOG_INVITE_PLAYER
Definition: Guild.h:211
@ GUILD_EVENT_LOG_DEMOTE_PLAYER
Definition: Guild.h:214
@ GUILD_EVENT_LOG_JOIN_GUILD
Definition: Guild.h:212
@ PERM_ENCHANTMENT_SLOT
Definition: ItemDefines.h:179
@ USE_ENCHANTMENT_SLOT
Definition: ItemDefines.h:186
InventoryResult
Definition: ItemDefines.h:25
@ EQUIP_ERR_DESTROY_NONEMPTY_BAG
Definition: ItemDefines.h:58
@ EQUIP_ERR_BANK_FULL
Definition: ItemDefines.h:78
@ 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
Item * NewItemOrBag(ItemTemplate const *proto)
Definition: Item.cpp:52
@ ITEM_CHANGED
Definition: Item.h:55
@ ITEM_NEW
Definition: Item.h:56
@ LANG_GUILD_MASTER
Definition: Language.h:763
@ LANG_GUILD_VETERAN
Definition: Language.h:765
@ LANG_GUILD_OFFICER
Definition: Language.h:764
@ LANG_GUILD_INITIATE
Definition: Language.h:767
@ LANG_GUILD_MEMBER
Definition: Language.h:766
#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:1946
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
uint64 const MAX_MONEY_AMOUNT
Definition: Player.cpp:158
#define sScriptMgr
Definition: ScriptMgr.h:1418
Language
@ LANG_ADDON_LOGGED
@ LANG_ADDON
@ ERR_GUILD_PLAYER_NOT_FOUND_S
@ ERR_GUILD_PERMISSIONS
@ ERR_GUILD_NOT_ALLIED
@ ERR_GUILD_NAME_INVALID
@ ERR_GUILD_TOO_MUCH_MONEY
@ ERR_GUILDEMBLEM_NOTENOUGHMONEY
@ ERR_GUILD_RANK_TOO_LOW_S
@ ERR_GUILD_RANK_TOO_HIGH_S
@ ERR_GUILD_LEADER_LEAVE
@ ERR_ALREADY_INVITED_TO_GUILD_S
@ ERR_GUILDEMBLEM_NOTGUILDMASTER
@ ERR_GUILDEMBLEM_SUCCESS
@ ERR_ALREADY_IN_GUILD_S
@ GOLD
@ CHAT_MSG_GUILD
@ CHAT_MSG_OFFICER
@ NULL_SLOT
Definition: Unit.h:63
void utf8truncate(std::string &utf8str, size_t len)
Definition: Util.cpp:362
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition: Util.h:491
uint32 const Entry[5]
bool HasAchieved(uint32 achievementId) const
uint32 GetAchievementPoints() const
static std::unique_ptr< club::v1::MemberId > CreateClubMemberId(ObjectGuid guid)
static std::unique_ptr< club::v1::UniqueClubType > CreateGuildClubType()
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject const *ref=nullptr, Player *referencePlayer=nullptr)
static void WalkCriteriaTree(CriteriaTree const *tree, Func const &func)
void SaveToDB(ObjectGuid::LowType guildId) const
Definition: Guild.cpp:765
uint32 GetStyle() const
Definition: Guild.h:284
uint32 GetColor() const
Definition: Guild.h:285
bool ValidateEmblemColors() const
Definition: Guild.h:278
uint32 GetBackgroundColor() const
Definition: Guild.h:288
uint32 GetBorderStyle() const
Definition: Guild.h:286
bool LoadFromDB(Field *fields)
Definition: Guild.cpp:754
void ReadPacket(WorldPackets::Guild::SaveGuildEmblem &packet)
Definition: Guild.cpp:738
uint32 GetBorderColor() const
Definition: Guild.h:287
Class used to access individual fields of database query result.
Definition: Field.h:90
uint8 GetUInt8() const
Definition: Field.cpp:30
std::string GetString() const
Definition: Field.cpp:118
uint64 GetUInt64() const
Definition: Field.cpp:78
uint32 GetUInt32() const
Definition: Field.cpp:62
Definition: Group.h:197
void SendAchievementMembers(Player *receiver, uint32 achievementId) const
void SendAllData(Player const *receiver) const override
void SendAllTrackedCriterias(Player *receiver, std::set< uint32 > const &trackedCriterias) const
void SaveToDB(CharacterDatabaseTransaction trans)
int32 GetSlots() const
Definition: Guild.h:317
void SetGuildMasterValues()
Definition: Guild.h:306
int8 GetRights() const
Definition: Guild.h:318
int8 GetTabId() const
Definition: Guild.h:316
void SetTabId(uint8 _tabId)
Definition: Guild.h:312
void SaveToDB(CharacterDatabaseTransaction trans) const override
Definition: Guild.cpp:160
void WritePacket(WorldPackets::Guild::GuildBankLogQueryResults &packet) const
Definition: Guild.cpp:184
bool IsMoneyEvent() const
Definition: Guild.h:478
void LogBankEvent(CharacterDatabaseTransaction trans, MoveItemData *pFrom, uint32 count) const override
Definition: Guild.cpp:970
bool _ReserveSpace(uint8 slotId, Item *pItem, Item *pItemDest, uint32 &count)
Definition: Guild.cpp:1029
void LogAction(MoveItemData *pFrom) const override
Definition: Guild.cpp:983
void CanStoreItemInTab(Item *pItem, uint8 skipSlotId, bool merge, uint32 &count)
Definition: Guild.cpp:1052
bool InitItem() override
Definition: Guild.cpp:898
Item * StoreItem(CharacterDatabaseTransaction trans, Item *pItem) override
Definition: Guild.cpp:946
Item * _StoreItem(CharacterDatabaseTransaction trans, BankTab *pTab, Item *pItem, ItemPosCount &pos, bool clone) const
Definition: Guild.cpp:996
void RemoveItem(CharacterDatabaseTransaction trans, MoveItemData *pOther, uint32 splitedAmount) override
Definition: Guild.cpp:927
bool HasStoreRights(MoveItemData *pOther) const override
Definition: Guild.cpp:904
InventoryResult CanStore(Item *pItem, bool swap) override
Definition: Guild.cpp:1072
bool HasWithdrawRights(MoveItemData *pOther) const override
Definition: Guild.cpp:913
void LoadFromDB(Field *fields)
Definition: Guild.cpp:371
void SetText(std::string_view text)
Definition: Guild.cpp:448
void Delete(CharacterDatabaseTransaction trans, bool removeItemsFromDB=false)
Definition: Guild.cpp:417
Item * GetItem(uint8 slotId) const
Definition: Guild.h:637
bool LoadItemFromDB(Field *fields)
Definition: Guild.cpp:378
BankTab(ObjectGuid::LowType guildId, uint8 tabId)
Definition: Guild.cpp:368
void SendText(Guild const *guild, WorldSession *session) const
Definition: Guild.cpp:496
void SetInfo(std::string_view name, std::string_view icon)
Definition: Guild.cpp:432
bool SetItem(CharacterDatabaseTransaction trans, uint8 slotId, Item *item)
Definition: Guild.cpp:465
void SaveToDB(CharacterDatabaseTransaction trans) const override
Definition: Guild.cpp:126
void WritePacket(WorldPackets::Guild::GuildEventLogQueryResults &packet) const
Definition: Guild.cpp:145
LogEntry(ObjectGuid::LowType guildId, uint32 guid)
Definition: Guild.cpp:123
void LoadEvent(Ts &&... args)
Definition: Guild.cpp:90
uint32 GetNextGUID()
Definition: Guild.cpp:112
bool CanInsert() const
Definition: Guild.h:547
Entry & AddEvent(CharacterDatabaseTransaction trans, Ts &&... args)
Definition: Guild.cpp:98
std::string const & GetName() const
Definition: Guild.h:355
void RemFlag(uint8 var)
Definition: Guild.h:348
GuildRankId GetRankId() const
Definition: Guild.h:357
Player * FindConnectedPlayer() const
Definition: Guild.cpp:732
bool IsSamePlayer(ObjectGuid guid) const
Definition: Guild.h:383
void SetPublicNote(std::string_view publicNote)
Definition: Guild.cpp:561
void UpdateLogoutTime()
Definition: Guild.cpp:601
float GetInactiveDays() const
Definition: Guild.cpp:679
void SetOfficerNote(std::string_view officerNote)
Definition: Guild.cpp:574
uint32 GetBankTabWithdrawValue(uint8 tabId) const
Definition: Guild.h:387
bool LoadFromDB(Field *fields)
Definition: Guild.cpp:620
bool CheckStats() const
Definition: Guild.cpp:657
bool IsRank(GuildRankId rankId) const
Definition: Guild.h:382
uint64 GetBankMoneyWithdrawValue() const
Definition: Guild.h:388
void AddFlag(uint8 var)
Definition: Guild.h:347
void ResetFlags()
Definition: Guild.h:349
void ChangeRank(CharacterDatabaseTransaction trans, GuildRankId newRank)
Definition: Guild.cpp:587
Member(ObjectGuid::LowType guildId, ObjectGuid guid, GuildRankId rankId)
Definition: Guild.cpp:516
void UpdateBankMoneyWithdrawValue(CharacterDatabaseTransaction trans, uint64 amount)
Definition: Guild.cpp:703
void UpdateBankTabWithdrawValue(CharacterDatabaseTransaction trans, uint8 tabId, uint32 amount)
Definition: Guild.cpp:687
void SaveToDB(CharacterDatabaseTransaction trans) const
Definition: Guild.cpp:606
bool IsOnline() const
Definition: Guild.h:377
void ResetValues(bool weekly=false)
Definition: Guild.cpp:713
Player * FindPlayer() const
Definition: Guild.cpp:727
ObjectGuid const & GetGUID() const
Definition: Guild.h:354
void SetStats(Player *player)
Definition: Guild.cpp:537
MoveItemData(Guild *guild, Player *player, uint8 container, uint8 slotId)
Definition: Guild.cpp:778
virtual void LogAction(MoveItemData *pFrom) const
Definition: Guild.cpp:818
virtual Item * StoreItem(CharacterDatabaseTransaction trans, Item *pItem)=0
Item * GetItem(bool isCloned=false) const
Definition: Guild.h:683
virtual void LogBankEvent(CharacterDatabaseTransaction trans, MoveItemData *pFrom, uint32 count) const =0
uint8 GetSlotId() const
Definition: Guild.h:685
uint8 GetContainer() const
Definition: Guild.h:684
virtual bool CheckItem(uint32 &splitedAmount)
Definition: Guild.cpp:787
virtual bool HasWithdrawRights(MoveItemData *) const
Definition: Guild.h:665
virtual bool HasStoreRights(MoveItemData *) const
Definition: Guild.h:663
InventoryResult CanStore(Item *pItem, bool swap, bool sendError)
Definition: Guild.cpp:797
void CopySlots(SlotIds &ids) const
Definition: Guild.cpp:827
virtual bool IsBank() const =0
bool CloneItem(uint32 count)
Definition: Guild.cpp:806
virtual bool InitItem()=0
virtual ~MoveItemData()
Definition: Guild.cpp:783
void SendEquipError(InventoryResult result, Item const *item)
Definition: Guild.cpp:833
virtual void RemoveItem(CharacterDatabaseTransaction trans, MoveItemData *pOther, uint32 splitedAmount=0)=0
void WritePacket(WorldPackets::Guild::GuildNews &newsPacket) const
Definition: Guild.cpp:229
void SaveToDB(CharacterDatabaseTransaction trans) const override
Definition: Guild.cpp:215
InventoryResult CanStore(Item *pItem, bool swap) override
Definition: Guild.cpp:892
Item * StoreItem(CharacterDatabaseTransaction trans, Item *pItem) override
Definition: Guild.cpp:876
bool InitItem() override
Definition: Guild.cpp:839
void LogBankEvent(CharacterDatabaseTransaction trans, MoveItemData *pFrom, uint32 count) const override
Definition: Guild.cpp:884
void RemoveItem(CharacterDatabaseTransaction trans, MoveItemData *pOther, uint32 splitedAmount=0) override
Definition: Guild.cpp:860
void SetOrder(GuildRankOrder rankOrder)
Definition: Guild.h:582
void CreateMissingTabsIfNeeded(uint8 ranks, CharacterDatabaseTransaction trans, bool logOnCreate=false)
Definition: Guild.cpp:277
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:347
void SaveToDB(CharacterDatabaseTransaction trans) const
Definition: Guild.cpp:265
GuildRankOrder GetOrder() const
Definition: Guild.h:581
GuildRankId GetId() const
Definition: Guild.h:579
void LoadFromDB(Field *fields)
Definition: Guild.cpp:254
Definition: Guild.h:329
void HandleRemoveRank(WorldSession *session, GuildRankOrder rankOrder)
Definition: Guild.cpp:1945
RankInfo const * GetRankInfo(GuildRankId rankId) const
Definition: Guild.cpp:3088
void HandleSetInfo(WorldSession *session, std::string_view info)
Definition: Guild.cpp:1492
void SwapItemsWithInventory(Player *player, bool toChar, uint8 tabId, uint8 slotId, uint8 playerBag, uint8 playerSlotId, uint32 splitedAmount)
Definition: Guild.cpp:3061
void SendEventNewLeader(Member *newLeader, Member *oldLeader, bool isSelfPromoted=false) const
Definition: Guild.cpp:2374
std::string _GetRankName(GuildRankId rankId) const
Definition: Guild.cpp:3307
GuildRankId _GetLowestRankId() const
Definition: Guild.h:914
void HandleSetMemberRank(WorldSession *session, ObjectGuid guid, ObjectGuid setterGuid, GuildRankOrder rank)
Definition: Guild.cpp:1890
uint64 GetBankMoney() const
Definition: Guild.h:759
uint64 m_bankMoney
Definition: Guild.h:889
void BroadcastPacket(WorldPacket const *packet) const
Definition: Guild.cpp:2763
void UpdateCriteria(CriteriaType type, uint64 miscValue1, uint64 miscValue2, uint64 miscValue3, WorldObject const *ref, Player *player)
Definition: Guild.cpp:3781
int8 _GetRankBankTabRights(GuildRankId rankId, uint8 tabId) const
Definition: Guild.cpp:3336
std::vector< Player * > GetMembersTrackingCriteria(uint32 criteriaId) const
Definition: Guild.cpp:2770
void HandleSetMOTD(WorldSession *session, std::string_view motd)
Definition: Guild.cpp:1469
void _SetRankBankTabRightsAndSlots(GuildRankId rankId, GuildBankRightsAndSlots rightsAndSlots, bool saveToDB=true)
Definition: Guild.cpp:3298
void LoadBankRightFromDB(Field *fields)
Definition: Guild.cpp:2554
static void _DeleteMemberFromDB(CharacterDatabaseTransaction trans, ObjectGuid::LowType lowguid)
Definition: Guild.cpp:3141
void _SetRankBankMoneyPerDay(GuildRankId rankId, uint32 moneyPerDay)
Definition: Guild.cpp:3292
ObjectGuid GetLeaderGUID() const
Definition: Guild.h:754
int64 _GetMemberRemainingMoney(Member const &member) const
Definition: Guild.cpp:3359
void HandleSetAchievementTracking(WorldSession *session, uint32 const *achievementIdsBegin, uint32 const *achievementIdsEnd)
Definition: Guild.cpp:1432
void HandleDelete(WorldSession *session)
Definition: Guild.cpp:2136
void SwapItems(Player *player, uint8 tabId, uint8 slotId, uint8 destTabId, uint8 destSlotId, uint32 splitedAmount)
Definition: Guild.cpp:3047
~Guild()
Definition: Guild.cpp:1129
void _DeleteBankItems(CharacterDatabaseTransaction trans, bool removeItemsFromDB=false)
Definition: Guild.cpp:3247
Guild()
Definition: Guild.cpp:1119
void SendEventPlayerLeft(Member *leaver, Member *remover=nullptr, bool isRemoved=false) const
Definition: Guild.cpp:2416
bool LoadMemberFromDB(Field *fields)
Definition: Guild.cpp:2529
std::vector< BankTab > m_bankTabs
Definition: Guild.h:893
void OnPlayerStatusChange(Player *player, uint32 flag, bool state)
Definition: Guild.cpp:1300
void HandleLeaveMember(WorldSession *session)
Definition: Guild.cpp:1761
std::unique_ptr< GuildAchievementMgr > m_achievementMgr
Definition: Guild.h:899
void MassInviteToEvent(WorldSession *session, uint32 minLevel, uint32 maxLevel, GuildRankOrder minRank)
Definition: Guild.cpp:2781
ObjectGuid::LowType GetId() const
Definition: Guild.h:752
void SendPermissions(WorldSession *session) const
Definition: Guild.cpp:2246
void UpdateMemberData(Player *player, uint8 dataid, uint32 value)
Definition: Guild.cpp:1277
bool HasAchieved(uint32 achievementId) const
Definition: Guild.cpp:3776
uint32 m_accountsNumber
Definition: Guild.h:888
uint8 GetLevel() const
Definition: Guild.h:866
void SendQueryResponse(WorldSession *session)
Definition: Guild.cpp:1379
time_t m_createdDate
Definition: Guild.h:885
int32 _GetMemberRemainingSlots(Member const &member, uint8 tabId) const
Definition: Guild.cpp:3343
void SendEventLog(WorldSession *session) const
Definition: Guild.cpp:2184
bool AddMember(CharacterDatabaseTransaction trans, ObjectGuid guid, Optional< GuildRankId > rankId={})
Definition: Guild.cpp:2813
uint8 _GetPurchasedTabsSize() const
Definition: Guild.h:916
bool LoadBankItemFromDB(Field *fields)
Definition: Guild.cpp:2643
void HandleGuildPartyRequest(WorldSession *session) const
Definition: Guild.cpp:2146
uint32 _GetRankBankMoneyPerDay(GuildRankId rankId) const
Definition: Guild.cpp:3321
void BroadcastToGuild(WorldSession *session, bool officerOnly, std::string_view msg, uint32 language=LANG_UNIVERSAL) const
Definition: Guild.cpp:2724
void HandleUpdateMemberRank(WorldSession *session, ObjectGuid guid, bool demote)
Definition: Guild.cpp:1829
void LoadGuildNewsLogFromDB(Field *fields)
Definition: Guild.cpp:2619
void HandleGuildRequestChallengeUpdate(WorldSession *session) const
Definition: Guild.cpp:2165
std::array< LogHolder< BankEventLogEntry >, GUILD_BANK_MAX_TABS+1 > m_bankEventLog
Definition: Guild.h:897
bool LoadFromDB(Field *fields)
Definition: Guild.cpp:2491
std::vector< RankInfo > m_ranks
Definition: Guild.h:891
static void SendCommandResult(WorldSession *session, GuildCommandType type, GuildCommandError errCode, std::string_view param="")
Definition: Guild.cpp:62
void HandleInviteMember(WorldSession *session, std::string_view name)
Definition: Guild.cpp:1675
void SendLoginInfo(WorldSession *session)
Definition: Guild.cpp:2287
std::string m_name
Definition: Guild.h:881
void HandleSetMemberNote(WorldSession *session, std::string_view note, ObjectGuid guid, bool isPublic)
Definition: Guild.cpp:1597
void SaveToDB()
Definition: Guild.cpp:1268
std::unordered_map< ObjectGuid, Member > m_members
Definition: Guild.h:892
std::string const & GetName() const
Definition: Guild.h:755
void SetBankTabText(uint8 tabId, std::string_view text)
Definition: Guild.cpp:3075
bool HandleMemberWithdrawMoney(WorldSession *session, uint64 amount, bool repair=false)
Definition: Guild.cpp:2076
void _CreateNewBankTab()
Definition: Guild.cpp:3149
void ResetTimes(bool weekly)
Definition: Guild.cpp:3745
void HandleSetRankInfo(WorldSession *session, GuildRankId rankId, std::string_view name, uint32 rights, uint32 moneyPerDay, std::array< GuildBankRightsAndSlots, GUILD_BANK_MAX_TABS > const &rightsAndSlots)
Definition: Guild.cpp:1617
bool SetName(std::string_view name)
Definition: Guild.cpp:1310
bool ChangeMemberRank(CharacterDatabaseTransaction trans, ObjectGuid guid, GuildRankId newRank)
Definition: Guild.cpp:3018
ObjectGuid m_leaderGuid
Definition: Guild.h:882
void BroadcastWorker(Do &&_do, Player const *except=nullptr) const
Definition: Guild.h:836
int32 _GetRankBankTabSlotsPerDay(GuildRankId rankId, uint8 tabId) const
Definition: Guild.cpp:3328
void _UpdateAccountsNumber()
Definition: Guild.cpp:3225
LogHolder< EventLogEntry > m_eventLog
Definition: Guild.h:896
bool Create(Player *pLeader, std::string_view name)
Definition: Guild.cpp:1136
time_t GetCreatedDate() const
Definition: Guild.h:758
bool DeleteMember(CharacterDatabaseTransaction trans, ObjectGuid guid, bool isDisbanding=false, bool isKicked=false)
Definition: Guild.cpp:2955
void _MoveItems(MoveItemData *pSrc, MoveItemData *pDest, uint32 splitedAmount) const
Definition: Guild.cpp:3437
LogHolder< NewsLogEntry > m_newsLog
Definition: Guild.h:898
bool LoadEventLogFromDB(Field *fields)
Definition: Guild.cpp:2562
void BroadcastAddonToGuild(WorldSession *session, bool officerOnly, std::string_view msg, std::string_view prefix, bool isLogged) const
Definition: Guild.cpp:2739
void HandleSetNewGuildMaster(WorldSession *session, std::string_view name, bool isSelfPromote)
Definition: Guild.cpp:1531
void HandleAddNewRank(WorldSession *session, std::string_view name)
Definition: Guild.cpp:1927
void HandleSetBankTabInfo(WorldSession *session, uint8 tabId, std::string_view name, std::string_view icon)
Definition: Guild.cpp:1578
void HandleRemoveMember(WorldSession *session, ObjectGuid guid)
Definition: Guild.cpp:1791
void HandleMemberLogout(WorldSession *session)
Definition: Guild.cpp:2122
bool IsMember(ObjectGuid guid) const
Definition: Guild.cpp:3032
void HandleMemberDepositMoney(WorldSession *session, uint64 amount, bool cashFlow=false)
Definition: Guild.cpp:2036
static InventoryResult _DoItemsMove(MoveItemData *pSrc, MoveItemData *pDest, bool sendError, uint32 splitedAmount=0)
Definition: Guild.cpp:3494
void SendEventMOTD(WorldSession *session, bool broadcast=false) const
Definition: Guild.cpp:2360
void _LogBankEvent(CharacterDatabaseTransaction trans, GuildBankEventLogTypes eventType, uint8 tabId, ObjectGuid::LowType playerGuid, uint64 itemOrMoney, uint16 itemStackCount=0, uint8 destTabId=0)
Definition: Guild.cpp:3403
void SendEventAwayChanged(ObjectGuid const &memberGuid, bool afk, bool dnd)
Definition: Guild.cpp:2330
void SendGuildRankInfo(WorldSession *session) const
Definition: Guild.cpp:1403
void _RemoveItem(CharacterDatabaseTransaction trans, uint8 tabId, uint8 slotId)
Definition: Guild.cpp:3431
bool _IsLeader(Player *player) const
Definition: Guild.cpp:3238
GuildAchievementMgr & GetAchievementMgr()
Definition: Guild.h:862
bool LoadBankEventLogFromDB(Field *fields)
Definition: Guild.cpp:2579
void HandleGetAchievementMembers(WorldSession *session, uint32 achievementId) const
Definition: Guild.cpp:1464
std::string m_motd
Definition: Guild.h:883
void BroadcastPacketToRank(WorldPacket const *packet, GuildRankId rankId) const
Definition: Guild.cpp:2755
void SendGuildRanksUpdate(ObjectGuid setterGuid, ObjectGuid targetGuid, GuildRankId rank)
Definition: Guild.cpp:3708
static void SendSaveEmblemResult(WorldSession *session, GuildEmblemError errCode)
Definition: Guild.cpp:74
void SendBankTabText(WorldSession *session, uint8 tabId) const
Definition: Guild.cpp:2240
uint8 _GetRanksSize() const
Definition: Guild.h:904
void HandleSetEmblem(WorldSession *session, EmblemInfo const &emblemInfo)
Definition: Guild.cpp:1511
BankTab * GetBankTab(uint8 tabId)
Definition: Guild.h:917
bool _ModifyBankMoney(CharacterDatabaseTransaction trans, uint64 amount, bool add)
Definition: Guild.cpp:3255
void Disband()
Definition: Guild.cpp:1197
bool HasAnyRankRight(GuildRankId rankId, GuildRankRights rights) const
Definition: Guild.cpp:3136
std::string const & GetMOTD() const
Definition: Guild.h:756
void SendEventBankMoneyChanged() const
Definition: Guild.cpp:2353
bool _CreateRank(CharacterDatabaseTransaction trans, std::string_view name, uint32 rights)
Definition: Guild.cpp:3192
void HandleShiftRank(WorldSession *session, GuildRankOrder rankOrder, bool shiftUp)
Definition: Guild.cpp:1996
void _SendBankContentUpdate(MoveItemData *pSrc, MoveItemData *pDest) const
Definition: Guild.cpp:3542
void SendBankList(WorldSession *session, uint8 tabId, bool fullUpdate) const
Definition: Guild.cpp:3632
void _SetLeader(CharacterDatabaseTransaction trans, Member &leader)
Definition: Guild.cpp:3274
Member const * GetMember(ObjectGuid const &guid) const
Definition: Guild.h:921
uint64 GetMemberAvailableMoneyForRepairItems(ObjectGuid guid) const
Definition: Guild.cpp:3037
void AddGuildNews(uint8 type, ObjectGuid guid, uint32 flags, uint32 value)
Definition: Guild.cpp:3758
EmblemInfo m_emblemInfo
Definition: Guild.h:887
void _CreateDefaultGuildRanks(CharacterDatabaseTransaction trans, LocaleConstant loc)
Definition: Guild.cpp:3173
void HandleNewsSetSticky(WorldSession *session, uint32 newsId, bool sticky)
Definition: Guild.cpp:3786
void HandleAcceptMember(WorldSession *session)
Definition: Guild.cpp:1750
bool _MemberHasTabRights(ObjectGuid guid, uint8 tabId, int32 rights) const
Definition: Guild.cpp:3380
void _LogEvent(GuildEventLogTypes eventType, ObjectGuid::LowType playerGuid1, ObjectGuid::LowType playerGuid2=UI64LIT(0), uint8 newRank=0)
Definition: Guild.cpp:3393
std::string m_info
Definition: Guild.h:884
Item * _GetItem(uint8 tabId, uint8 slotId) const
Definition: Guild.cpp:3424
void SendMoneyInfo(WorldSession *session) const
Definition: Guild.cpp:2272
uint32 GetMembersCount() const
Definition: Guild.h:850
void SendBankLog(WorldSession *session, uint8 tabId) const
Definition: Guild.cpp:2217
ObjectGuid GetGUID() const
Definition: Guild.h:753
void LoadBankTabFromDB(Field *fields)
Definition: Guild.cpp:2634
void HandleRoster(WorldSession *session)
Definition: Guild.cpp:1329
bool Validate()
Definition: Guild.cpp:2656
void HandleBuyBankTab(WorldSession *session, uint8 tabId)
Definition: Guild.cpp:1637
uint32 _GetRankRights(GuildRankId rankId) const
Definition: Guild.cpp:3314
void SendEventPresenceChanged(WorldSession *session, bool loggedOn, bool broadcast=false) const
Definition: Guild.cpp:2473
bool _HasRankRight(Player const *player, uint32 right) const
Definition: Guild.cpp:3128
void _UpdateMemberWithdrawSlots(CharacterDatabaseTransaction trans, ObjectGuid guid, uint8 tabId)
Definition: Guild.cpp:3374
ObjectGuid::LowType m_id
Definition: Guild.h:880
void LoadRankFromDB(Field *fields)
Definition: Guild.cpp:2520
void SendNewsUpdate(WorldSession *session) const
Definition: Guild.cpp:2199
Definition: Item.h:170
virtual void SaveToDB(CharacterDatabaseTransaction trans)
Definition: Item.cpp:561
uint32 GetEnchantmentId(EnchantmentSlot slot) const
Definition: Item.h:298
int32 GetSpellCharges(uint8 index=0) const
Definition: Item.h:314
Item * CloneItem(uint32 count, Player const *player=nullptr) const
Definition: Item.cpp:1655
void SetCount(uint32 value)
Definition: Item.cpp:1275
ItemTemplate const * GetTemplate() const
Definition: Item.cpp:1141
bool IsSoulBound() const
Definition: Item.h:218
void SetContainedIn(ObjectGuid guid)
Definition: Item.h:191
void FSetState(ItemUpdateState state)
Definition: Item.h:326
virtual bool LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field *fields, uint32 entry)
Definition: Item.cpp:828
uint32 GetCount() const
Definition: Item.h:273
void SetOwnerGUID(ObjectGuid guid)
Definition: Item.h:189
uint32 GetMaxStackCount() const
Definition: Item.h:275
static void DeleteFromDB(CharacterDatabaseTransaction trans, ObjectGuid::LowType itemGuid)
Definition: Item.cpp:1088
UF::UpdateField< UF::ItemData, 0, TYPEID_ITEM > m_itemData
Definition: Item.h:449
virtual ObjectGuid::LowType GetOwnerGuildId(uint32=TEAM_OTHER) const
Definition: Map.h:471
LowType GetCounter() const
Definition: ObjectGuid.h:293
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
std::string ToString() const
Definition: ObjectGuid.cpp:554
uint64 LowType
Definition: ObjectGuid.h:278
static bool IsValidCharterName(std::string_view name)
Definition: ObjectMgr.cpp:8712
uint32 GetEntry() const
Definition: Object.h:161
virtual void AddToWorld()
Definition: Object.cpp:107
virtual void RemoveFromWorld()
Definition: Object.cpp:124
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
bool HasIgnore(ObjectGuid const &ignoreGuid, ObjectGuid const &ignoreAccountGuid)
Definition: SocialMgr.cpp:189
void LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill=0, bool suppressMessaging=false, Optional< int32 > traitDefinitionId={})
Definition: Player.cpp:3216
bool ModifyMoney(int64 amount, bool sendError=true)
Definition: Player.cpp:24098
PlayerSocial * GetSocial() const
Definition: Player.h:1163
static uint32 GetZoneIdFromDB(ObjectGuid guid)
Definition: Player.cpp:7445
Gender GetNativeGender() const override
Definition: Player.h:1217
void SendDirectMessage(WorldPacket const *data) const
Definition: Player.cpp:6324
void SaveInventoryAndGoldToDB(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20364
Guild * GetGuild()
Definition: Player.cpp:29432
WorldSession * GetSession() const
Definition: Player.h:2101
void SetInGuild(ObjectGuid::LowType guildId)
Definition: Player.cpp:7419
ObjectGuid::LowType GetGuildId() const
Definition: Player.h:1993
void SetGuildRank(uint8 rankId)
Definition: Player.h:1988
ObjectGuid::LowType GetGuildIdInvited() const
Definition: Player.h:1996
uint32 GetAchievementPoints() const
Definition: Player.cpp:26741
void RemoveSpell(uint32 spell_id, bool disabled=false, bool learn_low_rank=true, bool suppressMessaging=false)
Definition: Player.cpp:3260
Group * GetGroup(Optional< uint8 > partyIndex)
Definition: Player.h:2606
void SetGuildLevel(uint32 level)
Definition: Player.h:1990
void SetGuildIdInvited(ObjectGuid::LowType GuildId)
Definition: Player.h:1992
static void RemovePetitionsAndSigns(ObjectGuid guid)
Definition: Player.cpp:22452
Team GetTeam() const
Definition: Player.h:2235
bool HasEnoughMoney(uint64 amount) const
Definition: Player.h:1740
void setInt32(const uint8 index, const int32 value)
void setUInt8(const uint8 index, const uint8 value)
void setInt64(const uint8 index, const int64 value)
void setUInt32(const uint8 index, const uint32 value)
void setUInt16(const uint8 index, const uint16 value)
void setString(const uint8 index, const std::string &value)
void setInt8(const uint8 index, const int8 value)
void setUInt64(const uint8 index, const uint64 value)
uint8 GetClass() const
Definition: Unit.h:752
uint8 GetLevel() const
Definition: Unit.h:746
uint8 GetRace() const
Definition: Unit.h:749
Map * GetMap() const
Definition: Object.h:624
std::string const & GetName() const
Definition: Object.h:555
uint32 GetZoneId() const
Definition: Object.h:545
std::vector< CalendarEventInitialInviteInfo > Invites
void Initialize(ChatMsg chatType, Language language, WorldObject const *sender, WorldObject const *receiver, std::string_view message, uint32 achievementId=0, std::string_view channelName="", LocaleConstant locale=DEFAULT_LOCALE, std::string_view addonPrefix="")
WorldPacket const * Write() override
std::vector< GuildBankLogEntry > Entry
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< GuildBankTabInfo > TabInfo
Definition: GuildPackets.h:822
std::vector< GuildBankItemInfo > ItemInfo
Definition: GuildPackets.h:821
WorldPacket const * Write() override
int32 CurrentCount[GUILD_CHALLENGES_TYPES]
int32 MaxLevelGold[GUILD_CHALLENGES_TYPES]
int32 Gold[GUILD_CHALLENGES_TYPES]
WorldPacket const * Write() override
int32 MaxCount[GUILD_CHALLENGES_TYPES]
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: GuildPackets.h:312
std::vector< GuildEventEntry > Entry
Definition: GuildPackets.h:339
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: GuildPackets.h:294
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: GuildPackets.h:379
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: GuildPackets.h:583
WorldPacket const * Write() override
bool IsPublic
0 == Officer, 1 == Public
Definition: GuildPackets.h:574
WorldPacket const * Write() override
std::vector< GuildNewsEvent > NewsEvents
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< GuildRankTabPermissions > Tab
Definition: GuildPackets.h:437
WorldPacket const * Write() override
std::vector< GuildRankData > Ranks
Definition: GuildPackets.h:517
WorldPacket const * Write() override
std::vector< GuildRosterMemberData > MemberData
Definition: GuildPackets.h:131
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * GetRawPacket() const
Definition: Packet.h:38
Player session in the World.
Definition: WorldSession.h:963
LocaleConstant GetSessionDbLocaleIndex() const
ObjectGuid GetAccountGUID() const
Minutes GetTimezoneOffset() const
std::string GetPlayerInfo() const
Player * GetPlayer() const
bool HasPermission(uint32 permissionId)
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
uint32 GetAccountId() const
bool IsAddonRegistered(std::string_view prefix) const
void SetUtcTimeFromUnixTime(std::time_t unixTime)
Definition: WowTime.cpp:86
#define sWorld
Definition: World.h:931
uint32 GetVirtualRealmAddress()
Definition: World.cpp:3968
@ CONFIG_GUILD_EVENT_LOG_COUNT
Definition: World.h:363
@ CONFIG_GUILD_BANK_EVENT_LOG_COUNT
Definition: World.h:364
@ CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD
Definition: World.h:112
uint64 CreateClubMemberId(ObjectGuid guid)
Definition: ClubUtils.cpp:22
time_t GetGameTime()
Definition: GameTime.cpp:44
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 ToString(Type &&val, Params &&... params)
constexpr std::size_t size()
Definition: UpdateField.h:796
@ RBAC_PERM_LOG_GM_TRADE
Definition: RBAC.h:64
STL namespace.
::Criteria const * Criteria
uint32 count
Definition: Player.h:748
bool isContainedIn(std::vector< ItemPosCount > const &vec) const
Definition: Player.cpp:26121
uint16 pos
Definition: Player.h:747
char const * GetDefaultLocaleName() const
UpdateField< int32, 0, 1 > ItemID
Definition: UpdateFields.h:109
WorldPackets::Item::ItemInstance Item
Definition: GuildPackets.h:796
std::vector< Item::ItemGemData > SocketEnchant
Definition: GuildPackets.h:804
Optional< Item::ItemInstance > Item
uint32 TabWithdrawItemLimit[GUILD_BANK_MAX_TABS]
Definition: GuildPackets.h:507
uint32 TabFlags[GUILD_BANK_MAX_TABS]
Definition: GuildPackets.h:506
void Initialize(::Item const *item)