TrinityCore
Loading...
Searching...
No Matches
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 "GossipDef.h"
23#include "Guild.h"
24#include "GuildMgr.h"
25#include "Item.h"
26#include "Log.h"
27#include "ObjectAccessor.h"
28#include "ObjectMgr.h"
29#include "PetitionMgr.h"
30#include "PetitionPackets.h"
31#include "Player.h"
32#include "World.h"
33#include <sstream>
34
35#define CHARTER_DISPLAY_ID 16161
36#define GUILD_CHARTER_ITEM_ID 5863
37
39{
40 TC_LOG_DEBUG("network", "Petitioner {} tried sell petition: title {}", packet.Unit.ToString(), packet.Title);
41
42 // prevent cheating
44 if (!creature)
45 {
46 TC_LOG_DEBUG("network", "WORLD: HandlePetitionBuyOpcode - {} not found or you can't interact with him.", packet.Unit.ToString());
47 return;
48 }
49
50 // remove fake death
51 if (GetPlayer()->HasUnitState(UNIT_STATE_DIED))
53
54 uint32 charterItemID = GUILD_CHARTER_ITEM_ID;
55 uint32 cost = sWorld->getIntConfig(CONFIG_CHARTER_COST_GUILD);
56
57 // do not let if already in guild.
58 if (_player->GetGuildId())
59 return;
60
61 if (sGuildMgr->GetGuildByName(packet.Title))
62 {
64 return;
65 }
66
67 if (sObjectMgr->IsReservedName(packet.Title) || !ObjectMgr::IsValidCharterName(packet.Title))
68 {
70 return;
71 }
72
73 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(charterItemID);
74 if (!pProto)
75 {
76 _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, nullptr, charterItemID, 0);
77 return;
78 }
79
80 if (!_player->HasEnoughMoney(uint64(cost)))
81 {
82 _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, creature, charterItemID, 0);
83 return;
84 }
85
86 ItemPosCountVec dest;
87 InventoryResult msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, charterItemID, pProto->GetBuyCount());
88 if (msg != EQUIP_ERR_OK)
89 {
90 _player->SendEquipError(msg, nullptr, nullptr, charterItemID);
91 return;
92 }
93
94 _player->ModifyMoney(-int32(cost));
95 Item* charter = _player->StoreNewItem(dest, charterItemID, true);
96 if (!charter)
97 return;
98
99 charter->SetPetitionId(charter->GetGUID().GetCounter());
100 charter->SetState(ITEM_CHANGED, _player);
101 _player->SendNewItem(charter, 1, true, false);
102
103 // a petition is invalid, if both the owner and the type matches
104 // we checked above, if this player is in an arenateam, so this must be
105 // datacorruption
106 if (Petition const* petition = sPetitionMgr->GetPetitionByOwner(_player->GetGUID()))
107 {
108 // clear from petition store
109 sPetitionMgr->RemovePetition(petition->PetitionGuid);
110 TC_LOG_DEBUG("network", "Invalid petition {}", petition->PetitionGuid.ToString());
111 }
112
113 // fill petition store
114 sPetitionMgr->AddPetition(charter->GetGUID(), _player->GetGUID(), packet.Title, false);
115}
116
118{
119 Petition const* petition = sPetitionMgr->GetPetition(packet.Item);
120 if (!petition)
121 {
122 TC_LOG_DEBUG("entities.player.items", "Petition {} is not found for player {} {}", packet.Item.ToString(), GetPlayer()->GetGUID().ToString(), GetPlayer()->GetName());
123 return;
124 }
125
126 // if has guild => error, return;
127 if (_player->GetGuildId())
128 return;
129
130 TC_LOG_DEBUG("network", "CMSG_PETITION_SHOW_SIGNATURES petition {}", packet.Item.ToString());
131
132 SendPetitionSigns(petition, _player);
133}
134
135void WorldSession::SendPetitionSigns(Petition const* petition, Player* sendTo)
136{
138 signaturesPacket.Item = petition->PetitionGuid;
139 signaturesPacket.Owner = petition->OwnerGuid;
140 signaturesPacket.OwnerAccountID = ObjectGuid::Create<HighGuid::WowAccount>(sCharacterCache->GetCharacterAccountIdByGuid(petition->OwnerGuid));
141 signaturesPacket.PetitionID = petition->PetitionGuid.GetCounter();
142
143 for (Signature const& signature : petition->Signatures)
144 {
146 signaturePkt.Signer = signature.second;
147 signaturePkt.Choice = 0;
148 signaturesPacket.Signatures.push_back(signaturePkt);
149 }
150
151 sendTo->SendDirectMessage(signaturesPacket.Write());
152}
153
155{
156 TC_LOG_DEBUG("network", "Received CMSG_QUERY_PETITION Petition {} PetitionID {}", packet.ItemGUID.ToString(), packet.PetitionID);
157
159}
160
162{
164 responsePacket.PetitionID = uint32(petitionguid.GetCounter()); // PetitionID (in Trinity always same as GUID_LOPART(petition guid))
165 Petition const* petition = sPetitionMgr->GetPetition(petitionguid);
166 if (!petition)
167 {
168 responsePacket.Allow = false;
169 SendPacket(responsePacket.Write());
170
171 TC_LOG_DEBUG("network", "CMSG_PETITION_QUERY failed for petition ({})", petitionguid.ToString());
172 return;
173 }
174
175 uint32 reqSignatures = sWorld->getIntConfig(CONFIG_MIN_PETITION_SIGNS);
176
177 WorldPackets::Petition::PetitionInfo& petitionInfo = responsePacket.Info;
178 petitionInfo.PetitionID = int32(petitionguid.GetCounter());
179 petitionInfo.Petitioner = petition->OwnerGuid;
180 petitionInfo.MinSignatures = reqSignatures;
181 petitionInfo.MaxSignatures = reqSignatures;
182 petitionInfo.Title = petition->PetitionName;
183
184 responsePacket.Allow = true;
185
186 SendPacket(responsePacket.Write());
187}
188
190{
191 Item* item = _player->GetItemByGuid(packet.PetitionGuid);
192 if (!item)
193 return;
194
195 Petition* petition = sPetitionMgr->GetPetition(packet.PetitionGuid);
196 if (!petition)
197 {
198 TC_LOG_DEBUG("network", "CMSG_PETITION_QUERY failed for petition {}", packet.PetitionGuid.ToString());
199 return;
200 }
201
202 if (sGuildMgr->GetGuildByName(packet.NewGuildName))
203 {
205 return;
206 }
207
208 if (sObjectMgr->IsReservedName(packet.NewGuildName) || !ObjectMgr::IsValidCharterName(packet.NewGuildName))
209 {
211 return;
212 }
213
214 // update petition storage
215 petition->UpdateName(packet.NewGuildName);
216
218 renameResponse.PetitionGuid = packet.PetitionGuid;
219 renameResponse.NewGuildName = packet.NewGuildName;
220 SendPacket(renameResponse.Write());
221
222 TC_LOG_DEBUG("network", "Petition {} renamed to '{}'", packet.PetitionGuid.ToString(), packet.NewGuildName);
223}
224
226{
227 Petition* petition = sPetitionMgr->GetPetition(packet.PetitionGUID);
228 if (!petition)
229 {
230 TC_LOG_ERROR("network", "Petition {} is not found for player {} {}", packet.PetitionGUID.ToString(), GetPlayer()->GetGUID().ToString(), GetPlayer()->GetName());
231 return;
232 }
233
234 ObjectGuid ownerGuid = petition->OwnerGuid;
235 uint64 signs = petition->Signatures.size();
236
237 if (ownerGuid == _player->GetGUID())
238 return;
239
240 // not let enemies sign guild charter
241 if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != sCharacterCache->GetCharacterTeamByGuid(ownerGuid))
242 {
244 return;
245 }
246
247 if (_player->GetGuildId())
248 {
250 return;
251 }
252
254 {
256 return;
257 }
258
259 if (++signs > 10) // client signs maximum
260 return;
261
262 // Client doesn't allow to sign petition two times by one character, but not check sign by another character from same account
263 // not allow sign another player from already sign player account
265 signResult.Player = _player->GetGUID();
266 signResult.Item = packet.PetitionGUID;
267
268 bool isSigned = petition->IsPetitionSignedByAccount(GetAccountId());
269 if (isSigned)
270 {
272
273 // close at signer side
274 SendPacket(signResult.Write());
275
276 // update for owner if online
277 if (Player* owner = ObjectAccessor::FindConnectedPlayer(ownerGuid))
278 owner->SendDirectMessage(signResult.GetRawPacket());
279 return;
280 }
281
282 // fill petition store
283 petition->AddSignature(GetAccountId(), _player->GetGUID(), false);
284
285 TC_LOG_DEBUG("network", "PETITION SIGN: {} by player: {} ({} Account: {})", packet.PetitionGUID.ToString(), _player->GetName(), _player->GetGUID().ToString(), GetAccountId());
286
287 signResult.Error = int32(PETITION_SIGN_OK);
288
289 SendPacket(signResult.Write());
290
291 // update signs count on charter
292 if (Item* item = _player->GetItemByGuid(packet.PetitionGUID))
293 {
294 item->SetPetitionNumSignatures(signs);
295 item->SetState(ITEM_CHANGED, _player);
296 }
297
298 // update for owner if online
299 if (Player* owner = ObjectAccessor::FindConnectedPlayer(ownerGuid))
300 owner->SendDirectMessage(signResult.GetRawPacket());
301}
302
304{
305 TC_LOG_DEBUG("network", "Petition {} declined by {}", packet.PetitionGUID.ToString(), _player->GetGUID().ToString());
306
307 // Disabled because packet isn't handled by the client in any way
308 /*
309 Petition const* petition = sPetitionMgr->GetPetition(packet.PetitionGUID);
310 if (!petition)
311 return;
312
313 // petition owner online
314 if (Player* owner = ObjectAccessor::FindConnectedPlayer(petition->OwnerGuid))
315 {
316 WorldPackets::Petition::PetitionDeclined packet;
317 packet.Decliner = _player->GetGUID();
318 owner->SendDirectMessage(packet.Write());
319 }
320 */
321}
322
324{
326 if (!player)
327 return;
328
329 Petition const* petition = sPetitionMgr->GetPetition(packet.ItemGUID);
330 if (!petition)
331 return;
332
333 TC_LOG_DEBUG("network", "OFFER PETITION: {}, to {}", packet.ItemGUID.ToString(), packet.TargetPlayer.ToString());
334
335 if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != player->GetTeam())
336 {
338 return;
339 }
340
341 if (player->GetGuildId())
342 {
344 return;
345 }
346
347 if (player->GetGuildIdInvited())
348 {
350 return;
351 }
352
353 SendPetitionSigns(petition, player);
354}
355
357{
358 // Check if player really has the required petition charter
359 Item* item = _player->GetItemByGuid(packet.Item);
360 if (!item)
361 return;
362
363 TC_LOG_DEBUG("network", "Petition {} turned in by {}", packet.Item.ToString(), _player->GetGUID().ToString());
364
365 Petition const* petition = sPetitionMgr->GetPetition(packet.Item);
366 if (!petition)
367 {
368 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());
369 return;
370 }
371
372 std::string const name = petition->PetitionName; // we need a copy, Guild::AddMember invalidates petition
373
374 // Only the petition owner can turn in the petition
375 if (_player->GetGUID() != petition->OwnerGuid)
376 return;
377
378 // Check if player is already in a guild
379 if (_player->GetGuildId())
380 {
383 SendPacket(resultPacket.Write());
384 return;
385 }
386
387 // Check if guild name is already taken
388 if (sGuildMgr->GetGuildByName(name))
389 {
391 return;
392 }
393
394 SignaturesVector const signatures = petition->Signatures; // we need a copy, Guild::AddMember invalidates petition
395 uint32 requiredSignatures = sWorld->getIntConfig(CONFIG_MIN_PETITION_SIGNS);
396
397 // Notify player if signatures are missing
398 if (signatures.size() < requiredSignatures)
399 {
402 SendPacket(resultPacket.Write());
403 return;
404 }
405
406 // Proceed with guild creation
407
408 // Delete charter item
409 _player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true);
410
411 // Create guild
412 Guild* guild = new Guild;
413
414 if (!guild->Create(_player, name))
415 {
416 delete guild;
417 return;
418 }
419
420 // Register guild and add guild master
421 sGuildMgr->AddGuild(guild);
422
424
425 {
426 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
427
428 // Add members from signatures
429 for (Signature const& signature : signatures)
430 guild->AddMember(trans, signature.second);
431
432 CharacterDatabase.CommitTransaction(trans);
433 }
434
435 sPetitionMgr->RemovePetition(packet.Item);
436
437 // created
438 TC_LOG_DEBUG("network", "Player {} ({}) turning in petition {}", _player->GetName(), _player->GetGUID().ToString(), packet.Item.ToString());
439
441 resultPacket.Result = int32(PETITION_TURN_OK);
442 SendPacket(resultPacket.Write());
443}
444
449
451{
453 if (!creature)
454 {
455 TC_LOG_DEBUG("network", "WORLD: HandlePetitionShowListOpcode - {} not found or you can't interact with him.", guid.ToString());
456 return;
457 }
458
459 GetPlayer()->PlayerTalkClass->GetInteractionData().StartInteraction(guid, PlayerInteractionType::PetitionVendor);
460
462 packet.Unit = guid;
463 packet.Price = uint32(sWorld->getIntConfig(CONFIG_CHARTER_COST_GUILD));
464 SendPacket(packet.Write());
465}
#define sCharacterCache
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
uint32_t uint32
Definition Define.h:154
#define sGuildMgr
Definition GuildMgr.h:76
@ GUILD_COMMAND_CREATE_GUILD
Definition Guild.h:131
@ GUILD_COMMAND_INVITE_PLAYER
Definition Guild.h:132
@ ERR_ALREADY_IN_GUILD_S
Definition Guild.h:154
@ ERR_GUILD_COMMAND_SUCCESS
Definition Guild.h:151
@ ERR_GUILD_NOT_ALLIED
Definition Guild.h:164
@ ERR_GUILD_NAME_EXISTS_S
Definition Guild.h:158
@ ERR_ALREADY_INVITED_TO_GUILD_S
Definition Guild.h:156
@ ERR_GUILD_NAME_INVALID
Definition Guild.h:157
InventoryResult
Definition ItemDefines.h:25
@ EQUIP_ERR_OK
Definition ItemDefines.h:26
@ BUY_ERR_CANT_FIND_ITEM
@ BUY_ERR_NOT_ENOUGHT_MONEY
@ ITEM_CHANGED
Definition Item.h:47
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:181
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define sObjectMgr
Definition ObjectMgr.h:1885
#define sPetitionMgr
Definition PetitionMgr.h:91
@ 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:841
@ SPELL_AURA_FEIGN_DEATH
@ UNIT_NPC_FLAG_PETITIONER
@ UNIT_NPC_FLAG_2_NONE
@ UNIT_STATE_DIED
Definition Unit.h:261
@ NULL_BAG
Definition Unit.h:63
@ NULL_SLOT
Definition Unit.h:64
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
Definition Guild.h:329
bool AddMember(CharacterDatabaseTransaction trans, ObjectGuid guid, Optional< GuildRankId > rankId={})
Definition Guild.cpp:2816
static void SendCommandResult(WorldSession *session, GuildCommandType type, GuildCommandError errCode, std::string_view param="")
Definition Guild.cpp:64
bool Create(Player *pLeader, std::string_view name)
Definition Guild.cpp:1138
Definition Item.h:179
void SetState(ItemUpdateState state, Player *forplayer=nullptr)
Definition Item.cpp:1258
uint8 GetSlot() const
Definition Item.h:290
void SetPetitionId(uint32 petitionId)
Definition Item.h:454
uint8 GetBagSlot() const
Definition Item.cpp:1331
LowType GetCounter() const
Definition ObjectGuid.h:336
std::string ToString() const
static bool IsValidCharterName(std::string_view name)
void SendEquipError(InventoryResult msg, Item const *item1=nullptr, Item const *item2=nullptr, uint32 itemId=0) const
Definition Player.cpp:13130
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:11370
bool ModifyMoney(int64 amount, bool sendError=true)
Definition Player.cpp:24850
Creature * GetNPCIfCanInteractWith(ObjectGuid const &guid, NPCFlags npcFlags, NPCFlags2 npcFlags2) const
Definition Player.cpp:1903
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6283
void DestroyItem(uint8 bag, uint8 slot, bool update)
Definition Player.cpp:12121
void SendBuyError(BuyResult msg, Creature *creature, uint32 item, uint32 param) const
Definition Player.cpp:13178
ObjectGuid::LowType GetGuildId() const
Definition Player.h:2164
ObjectGuid::LowType GetGuildIdInvited() const
Definition Player.h:2167
Item * GetItemByGuid(ObjectGuid guid) const
Definition Player.cpp:9614
InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 item, uint32 count, uint32 *no_space_count=nullptr) const
Definition Player.cpp:10050
std::unique_ptr< PlayerMenu > PlayerTalkClass
Definition Player.h:2570
Team GetTeam() const
Definition Player.h:2423
bool HasEnoughMoney(uint64 amount) const
Definition Player.h:1907
void SendNewItem(Item *item, uint32 quantity, bool received, bool created, bool broadcast=false, uint32 dungeonEncounterId=0)
Definition Player.cpp:13878
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3955
std::string const & GetName() const
Definition Object.h:342
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:916
@ CONFIG_CHARTER_COST_GUILD
Definition World.h:408
@ CONFIG_MIN_PETITION_SIGNS
Definition World.h:280
@ CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD
Definition World.h:113
TC_GAME_API Player * FindConnectedPlayer(ObjectGuid const &)
uint32 GetBuyCount() const
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