TrinityCore
PetitionsHandler.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 "WorldSession.h"
19#include "Common.h"
20#include "CharacterCache.h"
21#include "DatabaseEnv.h"
22#include "Guild.h"
23#include "GuildMgr.h"
24#include "Item.h"
25#include "Log.h"
26#include "ObjectAccessor.h"
27#include "ObjectMgr.h"
28#include "PetitionMgr.h"
29#include "PetitionPackets.h"
30#include "Player.h"
31#include "World.h"
32#include <sstream>
33
34#define CHARTER_DISPLAY_ID 16161
35#define GUILD_CHARTER_ITEM_ID 5863
36
38{
39 TC_LOG_DEBUG("network", "Petitioner {} tried sell petition: title {}", packet.Unit.ToString(), packet.Title);
40
41 // prevent cheating
43 if (!creature)
44 {
45 TC_LOG_DEBUG("network", "WORLD: HandlePetitionBuyOpcode - {} not found or you can't interact with him.", packet.Unit.ToString());
46 return;
47 }
48
49 // remove fake death
50 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
52
53 uint32 charterItemID = GUILD_CHARTER_ITEM_ID;
54 uint32 cost = sWorld->getIntConfig(CONFIG_CHARTER_COST_GUILD);
55
56 // do not let if already in guild.
57 if (_player->GetGuildId())
58 return;
59
60 if (sGuildMgr->GetGuildByName(packet.Title))
61 {
63 return;
64 }
65
66 if (sObjectMgr->IsReservedName(packet.Title) || !ObjectMgr::IsValidCharterName(packet.Title))
67 {
69 return;
70 }
71
72 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(charterItemID);
73 if (!pProto)
74 {
75 _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, nullptr, charterItemID, 0);
76 return;
77 }
78
79 if (!_player->HasEnoughMoney(uint64(cost)))
80 {
81 _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, creature, charterItemID, 0);
82 return;
83 }
84
85 ItemPosCountVec dest;
86 InventoryResult msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, charterItemID, pProto->GetBuyCount());
87 if (msg != EQUIP_ERR_OK)
88 {
89 _player->SendEquipError(msg, nullptr, nullptr, charterItemID);
90 return;
91 }
92
93 _player->ModifyMoney(-int32(cost));
94 Item* charter = _player->StoreNewItem(dest, charterItemID, true);
95 if (!charter)
96 return;
97
98 charter->SetPetitionId(charter->GetGUID().GetCounter());
99 charter->SetState(ITEM_CHANGED, _player);
100 _player->SendNewItem(charter, 1, true, false);
101
102 // a petition is invalid, if both the owner and the type matches
103 // we checked above, if this player is in an arenateam, so this must be
104 // datacorruption
105 if (Petition const* petition = sPetitionMgr->GetPetitionByOwner(_player->GetGUID()))
106 {
107 // clear from petition store
108 sPetitionMgr->RemovePetition(petition->PetitionGuid);
109 TC_LOG_DEBUG("network", "Invalid petition {}", petition->PetitionGuid.ToString());
110 }
111
112 // fill petition store
113 sPetitionMgr->AddPetition(charter->GetGUID(), _player->GetGUID(), packet.Title, false);
114}
115
117{
118 Petition const* petition = sPetitionMgr->GetPetition(packet.Item);
119 if (!petition)
120 {
121 TC_LOG_DEBUG("entities.player.items", "Petition {} is not found for player {} {}", packet.Item.ToString(), GetPlayer()->GetGUID().ToString(), GetPlayer()->GetName());
122 return;
123 }
124
125 // if has guild => error, return;
126 if (_player->GetGuildId())
127 return;
128
129 TC_LOG_DEBUG("network", "CMSG_PETITION_SHOW_SIGNATURES petition {}", packet.Item.ToString());
130
131 SendPetitionSigns(petition, _player);
132}
133
134void WorldSession::SendPetitionSigns(Petition const* petition, Player* sendTo)
135{
137 signaturesPacket.Item = petition->PetitionGuid;
138 signaturesPacket.Owner = petition->OwnerGuid;
139 signaturesPacket.OwnerAccountID = ObjectGuid::Create<HighGuid::WowAccount>(sCharacterCache->GetCharacterAccountIdByGuid(petition->OwnerGuid));
140 signaturesPacket.PetitionID = petition->PetitionGuid.GetCounter();
141
142 for (Signature const& signature : petition->Signatures)
143 {
145 signaturePkt.Signer = signature.second;
146 signaturePkt.Choice = 0;
147 signaturesPacket.Signatures.push_back(signaturePkt);
148 }
149
150 sendTo->SendDirectMessage(signaturesPacket.Write());
151}
152
154{
155 TC_LOG_DEBUG("network", "Received CMSG_QUERY_PETITION Petition {} PetitionID {}", packet.ItemGUID.ToString(), packet.PetitionID);
156
158}
159
161{
163 responsePacket.PetitionID = uint32(petitionguid.GetCounter()); // PetitionID (in Trinity always same as GUID_LOPART(petition guid))
164 Petition const* petition = sPetitionMgr->GetPetition(petitionguid);
165 if (!petition)
166 {
167 responsePacket.Allow = false;
168 SendPacket(responsePacket.Write());
169
170 TC_LOG_DEBUG("network", "CMSG_PETITION_QUERY failed for petition ({})", petitionguid.ToString());
171 return;
172 }
173
174 uint32 reqSignatures = sWorld->getIntConfig(CONFIG_MIN_PETITION_SIGNS);
175
176 WorldPackets::Petition::PetitionInfo& petitionInfo = responsePacket.Info;
177 petitionInfo.PetitionID = int32(petitionguid.GetCounter());
178 petitionInfo.Petitioner = petition->OwnerGuid;
179 petitionInfo.MinSignatures = reqSignatures;
180 petitionInfo.MaxSignatures = reqSignatures;
181 petitionInfo.Title = petition->PetitionName;
182
183 responsePacket.Allow = true;
184
185 SendPacket(responsePacket.Write());
186}
187
189{
190 Item* item = _player->GetItemByGuid(packet.PetitionGuid);
191 if (!item)
192 return;
193
194 Petition* petition = sPetitionMgr->GetPetition(packet.PetitionGuid);
195 if (!petition)
196 {
197 TC_LOG_DEBUG("network", "CMSG_PETITION_QUERY failed for petition {}", packet.PetitionGuid.ToString());
198 return;
199 }
200
201 if (sGuildMgr->GetGuildByName(packet.NewGuildName))
202 {
204 return;
205 }
206
207 if (sObjectMgr->IsReservedName(packet.NewGuildName) || !ObjectMgr::IsValidCharterName(packet.NewGuildName))
208 {
210 return;
211 }
212
213 // update petition storage
214 petition->UpdateName(packet.NewGuildName);
215
217 renameResponse.PetitionGuid = packet.PetitionGuid;
218 renameResponse.NewGuildName = packet.NewGuildName;
219 SendPacket(renameResponse.Write());
220
221 TC_LOG_DEBUG("network", "Petition {} renamed to '{}'", packet.PetitionGuid.ToString(), packet.NewGuildName);
222}
223
225{
226 Petition* petition = sPetitionMgr->GetPetition(packet.PetitionGUID);
227 if (!petition)
228 {
229 TC_LOG_ERROR("network", "Petition {} is not found for player {} {}", packet.PetitionGUID.ToString(), GetPlayer()->GetGUID().ToString(), GetPlayer()->GetName());
230 return;
231 }
232
233 ObjectGuid ownerGuid = petition->OwnerGuid;
234 uint64 signs = petition->Signatures.size();
235
236 if (ownerGuid == _player->GetGUID())
237 return;
238
239 // not let enemies sign guild charter
240 if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != sCharacterCache->GetCharacterTeamByGuid(ownerGuid))
241 {
243 return;
244 }
245
246 if (_player->GetGuildId())
247 {
249 return;
250 }
251
253 {
255 return;
256 }
257
258 if (++signs > 10) // client signs maximum
259 return;
260
261 // Client doesn't allow to sign petition two times by one character, but not check sign by another character from same account
262 // not allow sign another player from already sign player account
264 signResult.Player = _player->GetGUID();
265 signResult.Item = packet.PetitionGUID;
266
267 bool isSigned = petition->IsPetitionSignedByAccount(GetAccountId());
268 if (isSigned)
269 {
271
272 // close at signer side
273 SendPacket(signResult.Write());
274
275 // update for owner if online
276 if (Player* owner = ObjectAccessor::FindConnectedPlayer(ownerGuid))
277 owner->SendDirectMessage(signResult.GetRawPacket());
278 return;
279 }
280
281 // fill petition store
282 petition->AddSignature(GetAccountId(), _player->GetGUID(), false);
283
284 TC_LOG_DEBUG("network", "PETITION SIGN: {} by player: {} ({} Account: {})", packet.PetitionGUID.ToString(), _player->GetName(), _player->GetGUID().ToString(), GetAccountId());
285
286 signResult.Error = int32(PETITION_SIGN_OK);
287
288 SendPacket(signResult.Write());
289
290 // update signs count on charter
291 if (Item* item = _player->GetItemByGuid(packet.PetitionGUID))
292 {
293 item->SetPetitionNumSignatures(signs);
294 item->SetState(ITEM_CHANGED, _player);
295 }
296
297 // update for owner if online
298 if (Player* owner = ObjectAccessor::FindConnectedPlayer(ownerGuid))
299 owner->SendDirectMessage(signResult.GetRawPacket());
300}
301
303{
304 TC_LOG_DEBUG("network", "Petition {} declined by {}", packet.PetitionGUID.ToString(), _player->GetGUID().ToString());
305
306 // Disabled because packet isn't handled by the client in any way
307 /*
308 Petition const* petition = sPetitionMgr->GetPetition(packet.PetitionGUID);
309 if (!petition)
310 return;
311
312 // petition owner online
313 if (Player* owner = ObjectAccessor::FindConnectedPlayer(petition->OwnerGuid))
314 {
315 WorldPackets::Petition::PetitionDeclined packet;
316 packet.Decliner = _player->GetGUID();
317 owner->SendDirectMessage(packet.Write());
318 }
319 */
320}
321
323{
325 if (!player)
326 return;
327
328 Petition const* petition = sPetitionMgr->GetPetition(packet.ItemGUID);
329 if (!petition)
330 return;
331
332 TC_LOG_DEBUG("network", "OFFER PETITION: {}, to {}", packet.ItemGUID.ToString(), packet.TargetPlayer.ToString());
333
334 if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != player->GetTeam())
335 {
337 return;
338 }
339
340 if (player->GetGuildId())
341 {
343 return;
344 }
345
346 if (player->GetGuildIdInvited())
347 {
349 return;
350 }
351
352 SendPetitionSigns(petition, player);
353}
354
356{
357 // Check if player really has the required petition charter
358 Item* item = _player->GetItemByGuid(packet.Item);
359 if (!item)
360 return;
361
362 TC_LOG_DEBUG("network", "Petition {} turned in by {}", packet.Item.ToString(), _player->GetGUID().ToString());
363
364 Petition const* petition = sPetitionMgr->GetPetition(packet.Item);
365 if (!petition)
366 {
367 TC_LOG_ERROR("entities.player.cheat", "Player {} {} tried to turn in petition ({}) that is not present in the database", _player->GetName(), _player->GetGUID().ToString(), packet.Item.ToString());
368 return;
369 }
370
371 std::string const name = petition->PetitionName; // we need a copy, Guild::AddMember invalidates petition
372
373 // Only the petition owner can turn in the petition
374 if (_player->GetGUID() != petition->OwnerGuid)
375 return;
376
377 // Check if player is already in a guild
378 if (_player->GetGuildId())
379 {
382 SendPacket(resultPacket.Write());
383 return;
384 }
385
386 // Check if guild name is already taken
387 if (sGuildMgr->GetGuildByName(name))
388 {
390 return;
391 }
392
393 SignaturesVector const signatures = petition->Signatures; // we need a copy, Guild::AddMember invalidates petition
394 uint32 requiredSignatures = sWorld->getIntConfig(CONFIG_MIN_PETITION_SIGNS);
395
396 // Notify player if signatures are missing
397 if (signatures.size() < requiredSignatures)
398 {
401 SendPacket(resultPacket.Write());
402 return;
403 }
404
405 // Proceed with guild creation
406
407 // Delete charter item
408 _player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true);
409
410 // Create guild
411 Guild* guild = new Guild;
412
413 if (!guild->Create(_player, name))
414 {
415 delete guild;
416 return;
417 }
418
419 // Register guild and add guild master
420 sGuildMgr->AddGuild(guild);
421
423
424 {
425 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
426
427 // Add members from signatures
428 for (Signature const& signature : signatures)
429 guild->AddMember(trans, signature.second);
430
431 CharacterDatabase.CommitTransaction(trans);
432 }
433
434 sPetitionMgr->RemovePetition(packet.Item);
435
436 // created
437 TC_LOG_DEBUG("network", "Player {} ({}) turning in petition {}", _player->GetName(), _player->GetGUID().ToString(), packet.Item.ToString());
438
440 resultPacket.Result = int32(PETITION_TURN_OK);
441 SendPacket(resultPacket.Write());
442}
443
445{
447}
448
450{
452 if (!creature)
453 {
454 TC_LOG_DEBUG("network", "WORLD: HandlePetitionShowListOpcode - {} not found or you can't interact with him.", guid.ToString());
455 return;
456 }
457
459 packet.Unit = guid;
460 packet.Price = uint32(sWorld->getIntConfig(CONFIG_CHARTER_COST_GUILD));
461 SendPacket(packet.Write());
462
463 TC_LOG_DEBUG("network", "Sent SMSG_PETITION_SHOW_LIST");
464}
#define sCharacterCache
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
uint32_t uint32
Definition: Define.h:142
#define sGuildMgr
Definition: GuildMgr.h:70
@ GUILD_COMMAND_CREATE_GUILD
Definition: Guild.h:131
@ GUILD_COMMAND_INVITE_PLAYER
Definition: Guild.h:132
@ ERR_GUILD_COMMAND_SUCCESS
Definition: Guild.h:151
InventoryResult
Definition: ItemDefines.h:25
@ EQUIP_ERR_OK
Definition: ItemDefines.h:26
@ BUY_ERR_CANT_FIND_ITEM
Definition: ItemDefines.h:150
@ BUY_ERR_NOT_ENOUGHT_MONEY
Definition: ItemDefines.h:152
@ ITEM_CHANGED
Definition: Item.h:55
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define sObjectMgr
Definition: ObjectMgr.h:1946
#define sPetitionMgr
Definition: PetitionMgr.h:87
@ PETITION_SIGN_ALREADY_SIGNED
Definition: PetitionMgr.h:40
@ PETITION_SIGN_OK
Definition: PetitionMgr.h:39
@ PETITION_TURN_NEED_MORE_SIGNATURES
Definition: PetitionMgr.h:31
@ PETITION_TURN_ALREADY_IN_GUILD
Definition: PetitionMgr.h:30
@ PETITION_TURN_OK
Definition: PetitionMgr.h:29
std::pair< uint32, ObjectGuid > Signature
Definition: PetitionMgr.h:50
std::vector< Signature > SignaturesVector
Definition: PetitionMgr.h:51
#define GUILD_CHARTER_ITEM_ID
std::vector< ItemPosCount > ItemPosCountVec
Definition: Player.h:750
@ ERR_GUILD_NOT_ALLIED
@ ERR_GUILD_NAME_INVALID
@ ERR_ALREADY_INVITED_TO_GUILD_S
@ ERR_GUILD_NAME_EXISTS_S
@ ERR_ALREADY_IN_GUILD_S
@ SPELL_AURA_FEIGN_DEATH
@ UNIT_NPC_FLAG_PETITIONER
Definition: UnitDefines.h:315
@ UNIT_NPC_FLAG_2_NONE
Definition: UnitDefines.h:336
@ UNIT_STATE_DIED
Definition: Unit.h:255
@ NULL_BAG
Definition: Unit.h:62
@ NULL_SLOT
Definition: Unit.h:63
Definition: Guild.h:329
bool AddMember(CharacterDatabaseTransaction trans, ObjectGuid guid, Optional< GuildRankId > rankId={})
Definition: Guild.cpp:2813
static void SendCommandResult(WorldSession *session, GuildCommandType type, GuildCommandError errCode, std::string_view param="")
Definition: Guild.cpp:62
bool Create(Player *pLeader, std::string_view name)
Definition: Guild.cpp:1136
Definition: Item.h:170
void SetState(ItemUpdateState state, Player *forplayer=nullptr)
Definition: Item.cpp:1166
uint8 GetSlot() const
Definition: Item.h:280
void SetPetitionId(uint32 petitionId)
Definition: Item.h:444
uint8 GetBagSlot() const
Definition: Item.cpp:1239
LowType GetCounter() const
Definition: ObjectGuid.h:293
std::string ToString() const
Definition: ObjectGuid.cpp:554
static bool IsValidCharterName(std::string_view name)
Definition: ObjectMgr.cpp:8712
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
void SendEquipError(InventoryResult msg, Item const *item1=nullptr, Item const *item2=nullptr, uint32 itemId=0) const
Definition: Player.cpp:13254
Item * StoreNewItem(ItemPosCountVec const &pos, uint32 itemId, bool update, ItemRandomBonusListId randomBonusListId=0, GuidSet const &allowedLooters=GuidSet(), ItemContext context=ItemContext::NONE, std::vector< int32 > const *bonusListIDs=nullptr, bool addToCollection=true)
Definition: Player.cpp:11537
bool ModifyMoney(int64 amount, bool sendError=true)
Definition: Player.cpp:24098
Creature * GetNPCIfCanInteractWith(ObjectGuid const &guid, NPCFlags npcFlags, NPCFlags2 npcFlags2) const
Definition: Player.cpp:1947
void SendDirectMessage(WorldPacket const *data) const
Definition: Player.cpp:6324
void DestroyItem(uint8 bag, uint8 slot, bool update)
Definition: Player.cpp:12180
void SendBuyError(BuyResult msg, Creature *creature, uint32 item, uint32 param) const
Definition: Player.cpp:13300
ObjectGuid::LowType GetGuildId() const
Definition: Player.h:1993
ObjectGuid::LowType GetGuildIdInvited() const
Definition: Player.h:1996
Item * GetItemByGuid(ObjectGuid guid) const
Definition: Player.cpp:9566
InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 item, uint32 count, uint32 *no_space_count=nullptr) const
Definition: Player.cpp:10032
Team GetTeam() const
Definition: Player.h:2235
bool HasEnoughMoney(uint64 amount) const
Definition: Player.h:1740
void SendNewItem(Item *item, uint32 quantity, bool received, bool created, bool broadcast=false, uint32 dungeonEncounterId=0)
Definition: Player.cpp:13990
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3812
std::string const & GetName() const
Definition: Object.h:555
WorldPacket const * GetRawPacket() const
Definition: Packet.h:38
void SendPetitionShowList(ObjectGuid guid)
void HandleDeclinePetition(WorldPackets::Petition::DeclinePetition &packet)
void HandlePetitionBuy(WorldPackets::Petition::PetitionBuy &packet)
void HandleTurnInPetition(WorldPackets::Petition::TurnInPetition &packet)
void HandleSignPetition(WorldPackets::Petition::SignPetition &packet)
void HandlePetitionShowList(WorldPackets::Petition::PetitionShowList &packet)
Player * GetPlayer() const
void HandlePetitionRenameGuild(WorldPackets::Petition::PetitionRenameGuild &packet)
void HandleQueryPetition(WorldPackets::Petition::QueryPetition &packet)
void SendPetitionSigns(Petition const *petition, Player *sendTo)
void SendPetitionQueryOpcode(ObjectGuid petitionguid)
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
uint32 GetAccountId() const
Player * _player
void HandleOfferPetition(WorldPackets::Petition::OfferPetition &packet)
void HandlePetitionShowSignatures(WorldPackets::Petition::PetitionShowSignatures &packet)
#define sWorld
Definition: World.h:931
@ CONFIG_CHARTER_COST_GUILD
Definition: World.h:419
@ CONFIG_MIN_PETITION_SIGNS
Definition: World.h:282
@ CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD
Definition: World.h:112
TC_GAME_API bool GetName(uint32 accountId, std::string &name)
TC_GAME_API Player * FindConnectedPlayer(ObjectGuid const &)
std::string ToString(Type &&val, Params &&... params)
uint32 GetBuyCount() const
Definition: ItemTemplate.h:783
void UpdateName(std::string const &newName)
ObjectGuid OwnerGuid
Definition: PetitionMgr.h:56
SignaturesVector Signatures
Definition: PetitionMgr.h:58
bool IsPetitionSignedByAccount(uint32 accountId) const
ObjectGuid PetitionGuid
Definition: PetitionMgr.h:55
void AddSignature(uint32 accountId, ObjectGuid playerGuid, bool isLoading)
std::string PetitionName
Definition: PetitionMgr.h:57