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