Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
PetHandler.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "Common.h"
7#include "CreatureAI.h"
8#include "Group.h"
9#include "Log.h"
10#include "ObjectAccessor.h"
11#include "ObjectMgr.h"
12#include "Opcodes.h"
13#include "Pet.h"
14#include "Player.h"
15#include "Spell.h"
16#include "SpellInfo.h"
17#include "SpellMgr.h"
18#include "Util.h"
19#include "Vehicle.h"
20#include "World.h"
21#include "WorldPacket.h"
22#include "WorldSession.h"
23
24namespace
25{
26struct PetGuidRequest
27{
28 ObjectGuid guid;
29};
30
31struct PetActionRequest
32{
33 ObjectGuid petGuid;
34 ObjectGuid targetGuid;
35 uint32 action;
36 float x;
37 float y;
38 float z;
39};
40
41struct PetNameQueryRequest
42{
43 ObjectGuid petGuid;
44 ObjectGuid petNumber;
45};
46
47struct PetSetActionRequest
48{
49 ObjectGuid petGuid;
50 uint32 action;
51 uint32 index;
52};
53
54struct PetRenameRequest
55{
56 DeclinedName declinedName;
57 std::string name;
58 uint32 petNumber;
59 bool hasDeclinedNames;
60};
61
62struct PetSpellAutocastRequest
63{
64 ObjectGuid petGuid;
65 uint32 spellId;
66 bool state;
67};
68
69struct PetCastSpellRequest
70{
71 ObjectGuid targetGuid;
72 ObjectGuid transportDstGuid;
73 ObjectGuid itemGuid;
74 ObjectGuid transportSrcGuid;
75 ObjectGuid petGuid;
76 uint32 spellId;
77 uint32 targetFlags;
78 WorldLocation dstLoc;
79 WorldLocation srcLoc;
80 float missileSpeed;
81 float elevation;
82 uint8 castCount;
83 uint8 castFlags;
84};
85
86struct SetPetSpecializationRequest
87{
88 ObjectGuid petGuid;
89 uint32 talentTab;
90};
91
92PetGuidRequest ReadDismissCritterRequest(WorldPacket& recvData)
93{
94 PetGuidRequest request;
95 recvData.ReadGuidMask(request.guid, 4, 6, 7, 5, 1, 0, 2, 3);
96 recvData.ReadGuidBytes(request.guid, 2, 4, 5, 0, 1, 7, 3, 6);
97 return request;
98}
99
100PetActionRequest ReadPetActionRequest(WorldPacket& recvData)
101{
102 PetActionRequest request;
103 recvData >> request.action;
104
105 // Position
106 recvData >> request.y >> request.z >> request.x;
107
108 request.petGuid[1] = recvData.ReadBit();
109 request.petGuid[0] = recvData.ReadBit();
110 request.petGuid[6] = recvData.ReadBit();
111 request.petGuid[7] = recvData.ReadBit();
112 request.petGuid[5] = recvData.ReadBit();
113 request.targetGuid[7] = recvData.ReadBit();
114 request.petGuid[2] = recvData.ReadBit();
115 request.petGuid[3] = recvData.ReadBit();
116 request.targetGuid[6] = recvData.ReadBit();
117 request.targetGuid[3] = recvData.ReadBit();
118 request.targetGuid[0] = recvData.ReadBit();
119 request.targetGuid[2] = recvData.ReadBit();
120 request.targetGuid[5] = recvData.ReadBit();
121 request.petGuid[4] = recvData.ReadBit();
122 request.targetGuid[4] = recvData.ReadBit();
123 request.targetGuid[1] = recvData.ReadBit();
124
125 recvData.ReadByteSeq(request.petGuid[7]);
126 recvData.ReadByteSeq(request.petGuid[6]);
127 recvData.ReadByteSeq(request.petGuid[1]);
128 recvData.ReadByteSeq(request.petGuid[2]);
129 recvData.ReadByteSeq(request.petGuid[5]);
130 recvData.ReadByteSeq(request.petGuid[4]);
131 recvData.ReadByteSeq(request.targetGuid[5]);
132 recvData.ReadByteSeq(request.petGuid[3]);
133 recvData.ReadByteSeq(request.targetGuid[0]);
134 recvData.ReadByteSeq(request.targetGuid[1]);
135 recvData.ReadByteSeq(request.targetGuid[7]);
136 recvData.ReadByteSeq(request.targetGuid[4]);
137 recvData.ReadByteSeq(request.targetGuid[6]);
138 recvData.ReadByteSeq(request.targetGuid[2]);
139 recvData.ReadByteSeq(request.targetGuid[3]);
140 recvData.ReadByteSeq(request.petGuid[0]);
141
142 return request;
143}
144
145PetGuidRequest ReadPetStopAttackRequest(WorldPacket& recvData)
146{
147 PetGuidRequest request;
148
149 request.guid[7] = recvData.ReadBit();
150 request.guid[5] = recvData.ReadBit();
151 request.guid[1] = recvData.ReadBit();
152 request.guid[6] = recvData.ReadBit();
153 request.guid[0] = recvData.ReadBit();
154 request.guid[2] = recvData.ReadBit();
155 request.guid[4] = recvData.ReadBit();
156 request.guid[3] = recvData.ReadBit();
157
158 recvData.ReadByteSeq(request.guid[2]);
159 recvData.ReadByteSeq(request.guid[5]);
160 recvData.ReadByteSeq(request.guid[0]);
161 recvData.ReadByteSeq(request.guid[4]);
162 recvData.ReadByteSeq(request.guid[1]);
163 recvData.ReadByteSeq(request.guid[7]);
164 recvData.ReadByteSeq(request.guid[6]);
165 recvData.ReadByteSeq(request.guid[3]);
166
167 return request;
168}
169
170PetNameQueryRequest ReadPetNameQueryRequest(WorldPacket& recvData)
171{
172 PetNameQueryRequest request;
173
174 request.petNumber[0] = recvData.ReadBit();
175 request.petNumber[5] = recvData.ReadBit();
176 request.petGuid[1] = recvData.ReadBit();
177 request.petGuid[7] = recvData.ReadBit();
178 request.petNumber[7] = recvData.ReadBit();
179 request.petGuid[6] = recvData.ReadBit();
180 request.petGuid[4] = recvData.ReadBit();
181 request.petGuid[5] = recvData.ReadBit();
182 request.petGuid[0] = recvData.ReadBit();
183 request.petNumber[3] = recvData.ReadBit();
184 request.petNumber[6] = recvData.ReadBit();
185 request.petNumber[2] = recvData.ReadBit();
186 request.petGuid[3] = recvData.ReadBit();
187 request.petGuid[2] = recvData.ReadBit();
188 request.petNumber[1] = recvData.ReadBit();
189 request.petNumber[4] = recvData.ReadBit();
190
191 recvData.ReadByteSeq(request.petNumber[2]);
192 recvData.ReadByteSeq(request.petNumber[1]);
193 recvData.ReadByteSeq(request.petNumber[0]);
194 recvData.ReadByteSeq(request.petNumber[7]);
195 recvData.ReadByteSeq(request.petGuid[5]);
196 recvData.ReadByteSeq(request.petGuid[0]);
197 recvData.ReadByteSeq(request.petNumber[6]);
198 recvData.ReadByteSeq(request.petGuid[4]);
199 recvData.ReadByteSeq(request.petNumber[5]);
200 recvData.ReadByteSeq(request.petGuid[2]);
201 recvData.ReadByteSeq(request.petGuid[6]);
202 recvData.ReadByteSeq(request.petNumber[3]);
203 recvData.ReadByteSeq(request.petGuid[3]);
204 recvData.ReadByteSeq(request.petNumber[4]);
205 recvData.ReadByteSeq(request.petGuid[1]);
206 recvData.ReadByteSeq(request.petGuid[7]);
207
208 return request;
209}
210
211PetSetActionRequest ReadPetSetActionRequest(WorldPacket& recvData)
212{
213 PetSetActionRequest request;
214 recvData >> request.index;
215 recvData >> request.action;
216 recvData.ReadGuidMask(request.petGuid, 1, 0, 5, 3, 2, 7, 6, 4);
217 recvData.ReadGuidBytes(request.petGuid, 5, 6, 7, 3, 2, 1, 4, 0);
218 return request;
219}
220
221PetRenameRequest ReadPetRenameRequest(WorldPacket& recvData)
222{
223 PetRenameRequest request;
224 uint8 declinedNamesLength[MAX_DECLINED_NAME_CASES];
225
226 recvData >> request.petNumber;
227 bool hasName = !recvData.ReadBit();
228 request.hasDeclinedNames = recvData.ReadBit();
229 if (request.hasDeclinedNames)
230 for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
231 declinedNamesLength[i] = recvData.ReadBits(7);
232 if (hasName)
233 request.name = recvData.ReadString(recvData.ReadBits(8));
234 if (request.hasDeclinedNames)
235 for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
236 request.declinedName.name[i] = recvData.ReadString(declinedNamesLength[i]);
237
238 return request;
239}
240
241PetGuidRequest ReadPetAbandonRequest(WorldPacket& recvData)
242{
243 PetGuidRequest request;
244
245 request.guid[7] = recvData.ReadBit();
246 request.guid[3] = recvData.ReadBit();
247 request.guid[4] = recvData.ReadBit();
248 request.guid[2] = recvData.ReadBit();
249 request.guid[5] = recvData.ReadBit();
250 request.guid[6] = recvData.ReadBit();
251 request.guid[1] = recvData.ReadBit();
252 request.guid[0] = recvData.ReadBit();
253
254 recvData.ReadByteSeq(request.guid[0]);
255 recvData.ReadByteSeq(request.guid[2]);
256 recvData.ReadByteSeq(request.guid[5]);
257 recvData.ReadByteSeq(request.guid[6]);
258 recvData.ReadByteSeq(request.guid[7]);
259 recvData.ReadByteSeq(request.guid[1]);
260 recvData.ReadByteSeq(request.guid[4]);
261 recvData.ReadByteSeq(request.guid[3]);
262
263 return request;
264}
265
266PetSpellAutocastRequest ReadPetSpellAutocastRequest(WorldPacket& recvPacket)
267{
268 PetSpellAutocastRequest request;
269
270 recvPacket >> request.spellId;
271 recvPacket.ReadGuidMask(request.petGuid, 0, 4, 2, 6, 1, 5, 3, 7);
272 request.state = recvPacket.ReadBit();
273 recvPacket.ReadGuidBytes(request.petGuid, 5, 0, 4, 1, 7, 2, 3, 6);
274
275 return request;
276}
277
278PetCastSpellRequest ReadPetCastSpellRequest(WorldPacket& recvPacket)
279{
280 PetCastSpellRequest request = PetCastSpellRequest();
281 ObjectGuid transportGuid;
282 ObjectGuid movementGuid;
283
284 bool hasUnkMovementField = false;
285 bool hasTransport = false;
286 bool hasTransportTime2 = false;
287 bool hasTransportTime3 = false;
288 bool hasMovementFlags = false;
289 bool hasMovementFlags2 = false;
290 bool hasFallDirection = false;
291 bool hasFallData = false;
292 bool hasPitch = false;
293 bool hasOrientation = false;
294 bool hasSplineElevation = false;
295 bool hasTimestamp = false;
296
297 uint32 targetStrLength = 0;
298 uint32 movementForcesCount = 0;
299 uint32 archeologyCount = 0;
300
301 bool hasDestLocation = recvPacket.ReadBit();
302 request.petGuid[7] = recvPacket.ReadBit();
303 bool hasMissileSpeed = !recvPacket.ReadBit();
304 bool hasSrcLocation = recvPacket.ReadBit();
305 request.petGuid[1] = recvPacket.ReadBit();
306 archeologyCount = recvPacket.ReadBits(2);
307 bool hasTargetMask = !recvPacket.ReadBit();
308 request.petGuid[4] = recvPacket.ReadBit();
309 recvPacket.ReadBit();
310 request.petGuid[6] = recvPacket.ReadBit();
311 bool hasTargetString = !recvPacket.ReadBit();
312 recvPacket.ReadBit();
313 bool hasMovement = recvPacket.ReadBit();
314 bool hasCastFlags = !recvPacket.ReadBit();
315 bool hasSpellId = !recvPacket.ReadBit();
316 request.petGuid[0] = recvPacket.ReadBit();
317 request.petGuid[5] = recvPacket.ReadBit();
318 request.petGuid[2] = recvPacket.ReadBit();
319 for (uint32 i = 0; i < archeologyCount; ++i)
320 recvPacket.ReadBits(2); // archeologyType
321 request.petGuid[3] = recvPacket.ReadBit();
322 bool hasGlyphIndex = !recvPacket.ReadBit();
323 bool hasCastCount = !recvPacket.ReadBit();
324 bool hasElevation = !recvPacket.ReadBit();
325
326 if (hasMovement)
327 {
328 hasOrientation = !recvPacket.ReadBit();
329 hasSplineElevation = !recvPacket.ReadBit();
330 recvPacket.ReadBit();
331 movementGuid[5] = recvPacket.ReadBit();
332 movementGuid[7] = recvPacket.ReadBit();
333 hasMovementFlags2 = !recvPacket.ReadBit();
334 hasTimestamp = !recvPacket.ReadBit();
335 hasFallData = recvPacket.ReadBit();
336 hasMovementFlags = !recvPacket.ReadBit();
337 hasUnkMovementField = !recvPacket.ReadBit();
338
339 if (hasMovementFlags)
340 recvPacket.ReadBits(30); // Movement Flags
341
342 recvPacket.ReadBit();
343 movementGuid[6] = recvPacket.ReadBit();
344 hasTransport = recvPacket.ReadBit();
345 movementGuid[0] = recvPacket.ReadBit();
346 movementForcesCount = recvPacket.ReadBits(22);
347
348 if (hasTransport)
349 {
350 hasTransportTime2 = recvPacket.ReadBit();
351 hasTransportTime3 = recvPacket.ReadBit();
352 transportGuid[5] = recvPacket.ReadBit();
353 transportGuid[6] = recvPacket.ReadBit();
354 transportGuid[4] = recvPacket.ReadBit();
355 transportGuid[0] = recvPacket.ReadBit();
356 transportGuid[1] = recvPacket.ReadBit();
357 transportGuid[2] = recvPacket.ReadBit();
358 transportGuid[7] = recvPacket.ReadBit();
359 transportGuid[3] = recvPacket.ReadBit();
360 }
361
362 movementGuid[1] = recvPacket.ReadBit();
363
364 if (hasMovementFlags2)
365 recvPacket.ReadBits(13); // Movement Flags 2
366
367 movementGuid[3] = recvPacket.ReadBit();
368 movementGuid[2] = recvPacket.ReadBit();
369 recvPacket.ReadBit();
370 hasPitch = !recvPacket.ReadBit();
371 movementGuid[4] = recvPacket.ReadBit();
372
373 if (hasFallData)
374 hasFallDirection = recvPacket.ReadBit();
375 }
376
377 if (hasDestLocation)
378 recvPacket.ReadGuidMask(request.transportDstGuid, 2, 0, 1, 4, 5, 6, 3, 7);
379
380 if (hasCastFlags)
381 request.castFlags = recvPacket.ReadBits(5); // Cast Flags
382
383 recvPacket.ReadGuidMask(request.itemGuid, 2, 4, 7, 0, 6, 1, 5, 3);
384
385 if (hasTargetMask)
386 request.targetFlags = recvPacket.ReadBits(20); // Target Flags
387
388 if (hasTargetString)
389 targetStrLength = recvPacket.ReadBits(7); // Target String
390
391 if (hasSrcLocation)
392 recvPacket.ReadGuidMask(request.transportSrcGuid, 2, 0, 3, 1, 6, 7, 4, 5);
393
394 recvPacket.ReadGuidMask(request.targetGuid, 6, 0, 3, 4, 2, 1, 5, 7);
395
396 recvPacket.ReadGuidBytes(request.petGuid, 2, 6, 3);
397
398 for (uint32 i = 0; i < archeologyCount; ++i)
399 {
400 recvPacket.read_skip<uint32>(); // unk1
401 recvPacket.read_skip<uint32>(); // unk2
402 }
403 recvPacket.ReadGuidBytes(request.petGuid, 1, 7, 0, 4, 5);
404
405 if (hasDestLocation)
406 {
407 recvPacket.ReadByteSeq(request.transportDstGuid[4]);
408 recvPacket.ReadByteSeq(request.transportDstGuid[1]);
409 recvPacket.ReadByteSeq(request.transportDstGuid[7]);
410 request.dstLoc.m_positionZ = recvPacket.read<float>(); // Position Z
411 request.dstLoc.m_positionY = recvPacket.read<float>(); // Position Y
412 recvPacket.ReadByteSeq(request.transportDstGuid[6]);
413 recvPacket.ReadByteSeq(request.transportDstGuid[3]);
414 request.dstLoc.m_positionX = recvPacket.read<float>(); // Position X
415 recvPacket.ReadByteSeq(request.transportDstGuid[2]);
416 recvPacket.ReadByteSeq(request.transportDstGuid[5]);
417 recvPacket.ReadByteSeq(request.transportDstGuid[0]);
418 }
419
420 if (hasMovement)
421 {
422 if (hasPitch)
423 recvPacket.read_skip<float>(); // Pitch
424
425 if (hasTransport)
426 {
427 if (hasTransportTime3)
428 recvPacket.read_skip<int32>(); // Transport Time 3
429
430 if (hasTransportTime2)
431 recvPacket.read_skip<int32>(); // Transport Time 2
432
433 recvPacket.read_skip<uint8>(); // Transport Seat
434 recvPacket.read_skip<float>(); // Orientation
435 recvPacket.read_skip<float>(); // Position Z
436 recvPacket.ReadByteSeq(transportGuid[2]);
437 recvPacket.read_skip<int32>(); // Transport Time
438 recvPacket.ReadByteSeq(transportGuid[3]);
439 recvPacket.read_skip<float>(); // Position X
440 recvPacket.ReadByteSeq(transportGuid[6]);
441 recvPacket.ReadByteSeq(transportGuid[5]);
442 recvPacket.ReadByteSeq(transportGuid[7]);
443 recvPacket.ReadByteSeq(transportGuid[0]);
444 recvPacket.read_skip<float>(); // Position Y
445 recvPacket.ReadByteSeq(transportGuid[4]);
446 recvPacket.ReadByteSeq(transportGuid[1]);
447 }
448
449 if (hasUnkMovementField)
450 recvPacket.read_skip<int32>();
451
452 for (uint32 i = 0; i < movementForcesCount; ++i)
453 recvPacket.read_skip<uint32>(); // Movement Forces
454
455 recvPacket.ReadByteSeq(movementGuid[3]);
456
457 if (hasOrientation)
458 recvPacket.read_skip<float>(); // Orientation
459
460 recvPacket.ReadByteSeq(movementGuid[5]);
461
462 if (hasFallData)
463 {
464 recvPacket.read_skip<float>(); // Z Speed
465
466 if (hasFallDirection)
467 {
468 recvPacket.read_skip<float>(); // CosAngle
469 recvPacket.read_skip<float>(); // XY Speed
470 recvPacket.read_skip<float>(); // SinAngle
471 }
472 recvPacket.read_skip<int32>(); // FallTime
473 }
474
475 if (hasTimestamp)
476 recvPacket.read_skip<int32>(); // Timestamp
477
478 recvPacket.ReadByteSeq(movementGuid[6]);
479 recvPacket.read_skip<float>(); // Position X
480 recvPacket.ReadByteSeq(movementGuid[1]);
481 recvPacket.read_skip<float>(); // Position Z
482 recvPacket.ReadByteSeq(movementGuid[2]);
483 recvPacket.ReadByteSeq(movementGuid[7]);
484 recvPacket.ReadByteSeq(movementGuid[0]);
485 recvPacket.read_skip<float>(); // Position Y
486 recvPacket.ReadByteSeq(movementGuid[4]);
487
488 if (hasSplineElevation)
489 recvPacket.read_skip<float>(); // Spline Elevation
490 }
491
492 if (hasSrcLocation)
493 {
494 recvPacket.ReadByteSeq(request.transportSrcGuid[3]);
495 recvPacket.ReadByteSeq(request.transportSrcGuid[4]);
496 recvPacket.ReadByteSeq(request.transportSrcGuid[2]);
497 recvPacket.ReadByteSeq(request.transportSrcGuid[1]);
498 recvPacket.ReadByteSeq(request.transportSrcGuid[0]);
499 recvPacket.ReadByteSeq(request.transportSrcGuid[7]);
500 request.srcLoc.m_positionZ = recvPacket.read<float>(); // Position Z
501 recvPacket.ReadByteSeq(request.transportSrcGuid[6]);
502 recvPacket.ReadByteSeq(request.transportSrcGuid[5]);
503 request.srcLoc.m_positionX = recvPacket.read<float>(); // Position X
504 request.srcLoc.m_positionY = recvPacket.read<float>(); // Position Y
505 }
506
507 if (hasMissileSpeed)
508 request.missileSpeed = recvPacket.read<float>(); // missileSpeed
509
510 recvPacket.ReadGuidBytes(request.itemGuid, 1, 2, 5, 7, 4, 6, 3, 0);
511
512 recvPacket.ReadGuidBytes(request.targetGuid, 1, 5, 7, 3, 0, 2, 4, 6);
513
514 if (hasElevation)
515 request.elevation = recvPacket.read<float>(); // Elevation
516
517 if (hasCastCount)
518 request.castCount = recvPacket.read<uint8>(); // Cast Count
519
520 if (hasTargetString)
521 recvPacket.ReadString(targetStrLength);
522
523 if (hasGlyphIndex)
524 recvPacket.read_skip<int32>(); // Glyph Index
525
526 if (hasSpellId)
527 request.spellId = recvPacket.read<uint32>();
528
529 return request;
530}
531
532SetPetSpecializationRequest ReadSetPetSpecializationRequest(WorldPacket& recvData)
533{
534 SetPetSpecializationRequest request;
535 recvData >> request.talentTab;
536 recvData.ReadGuidMask(request.petGuid, 5, 7, 3, 0, 6, 4, 1, 2);
537 recvData.ReadGuidBytes(request.petGuid, 7, 5, 4, 3, 0, 2, 6, 1);
538 return request;
539}
540
541Unit* ValidatePetActionRequest(Player* player, PetActionRequest& request, uint8 flag, uint32 spellId)
542{
543 Unit* pet = ObjectAccessor::GetUnit(*player, request.petGuid);
544 if (!pet)
545 {
546 SF_LOG_ERROR("network", "HandlePetAction: Pet (GUID: %u) doesn't exist for player %s (GUID: %u)", uint32(GUID_LOPART(request.petGuid)), player->GetName().c_str(), GUID_LOPART(player->GetGUID()));
547 return NULL;
548 }
549
550 if (pet != player->GetFirstControlled())
551 {
552 SF_LOG_ERROR("network", "HandlePetAction: Pet (GUID: %u) does not belong to player %s (GUID: %u)", uint32(GUID_LOPART(request.petGuid)), player->GetName().c_str(), GUID_LOPART(player->GetGUID()));
553 return NULL;
554 }
555
556 if (!pet->IsAlive())
557 {
558 SpellInfo const* spell = (flag == ACT_ENABLED || flag == ACT_PASSIVE) ? sSpellMgr->GetSpellInfo(spellId) : NULL;
559 if (!spell)
560 return NULL;
562 return NULL;
563 }
564
566 if (pet->GetTypeId() == TypeID::TYPEID_PLAYER && !(flag == ACT_COMMAND && spellId == COMMAND_ATTACK))
567 return NULL;
568
569 return pet;
570}
571
572Unit* ValidatePetStopAttackRequest(Player* player, PetGuidRequest& request)
573{
574 Unit* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*player, request.guid);
575 if (!pet)
576 {
577 SF_LOG_ERROR("network", "HandlePetStopAttack: Pet %u does not exist", uint32(GUID_LOPART(request.guid)));
578 return NULL;
579 }
580
581 if (pet != player->GetPet() && pet != player->GetCharm())
582 {
583 SF_LOG_ERROR("network", "HandlePetStopAttack: Pet GUID %u isn't a pet or charmed creature of player %s",
584 uint32(GUID_LOPART(request.guid)), player->GetName().c_str());
585 return NULL;
586 }
587
588 if (!pet->IsAlive())
589 return NULL;
590
591 return pet;
592}
593
594Unit* ValidatePetSetActionRequest(Player* player, PetSetActionRequest& request, CharmInfo*& charmInfo)
595{
596 charmInfo = NULL;
597
598 Unit* pet = ObjectAccessor::GetUnit(*player, request.petGuid);
599 if (!pet || pet != player->GetFirstControlled())
600 {
601 SF_LOG_ERROR("network", "HandlePetSetAction: Unknown pet (GUID: %u) or pet owner (GUID: %u)", GUID_LOPART(request.petGuid), player->GetGUIDLow());
602 return NULL;
603 }
604
605 charmInfo = pet->GetCharmInfo();
606 if (!charmInfo)
607 {
608 SF_LOG_ERROR("network", "WorldSession::HandlePetSetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), uint8(pet->GetTypeId()));
609 return NULL;
610 }
611
612 //ignore invalid position
613 if (request.index >= MAX_UNIT_ACTION_BAR_INDEX)
614 return NULL;
615
616 return pet;
617}
618
619Pet* ValidatePetRenameTarget(Player* player)
620{
621 Pet* pet = player->GetPet();
622
623 if (!pet || pet->getPetType() != PetType::HUNTER_PET ||
625 !pet->GetCharmInfo())
626 return NULL;
627
628 return pet;
629}
630
631bool ValidatePetRenameName(WorldSession* session, PetRenameRequest& request)
632{
634 if (res != PET_NAME_SUCCESS)
635 {
636 session->SendPetNameInvalid(res, request.name, NULL, request.petNumber);
637 return false;
638 }
639
640 if (sObjectMgr->IsReservedName(request.name))
641 {
642 session->SendPetNameInvalid(PET_NAME_RESERVED, request.name, NULL, request.petNumber);
643 return false;
644 }
645
646 return true;
647}
648
649bool ValidatePetDeclinedNames(WorldSession* session, PetRenameRequest& request)
650{
651 std::wstring wname;
652 if (!Utf8toWStr(request.name, wname))
653 return false;
654
655 if (!ObjectMgr::CheckDeclinedNames(wname, request.declinedName))
656 {
657 session->SendPetNameInvalid(PET_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME, request.name, &request.declinedName, request.petNumber);
658 return false;
659 }
660
661 return true;
662}
663
664Creature* ValidatePetAbandonRequest(Player* player, PetGuidRequest& request)
665{
666 if (!player->IsInWorld())
667 return NULL;
668
669 return ObjectAccessor::GetCreatureOrPetOrVehicle(*player, request.guid);
670}
671
672Creature* ValidatePetAutocastRequest(Player* player, PetSpellAutocastRequest& request, SpellInfo const*& spellInfo, CharmInfo*& charmInfo)
673{
674 spellInfo = NULL;
675 charmInfo = NULL;
676
677 if (!player->GetGuardianPet() && !player->GetCharm())
678 return NULL;
679
680 if (ObjectAccessor::FindPlayer(request.petGuid))
681 return NULL;
682
683 Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*player, request.petGuid);
684 if (!pet || (pet != player->GetGuardianPet() && pet != player->GetCharm()))
685 {
686 SF_LOG_ERROR("network", "HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s (GUID: %u).", uint32(GUID_LOPART(request.petGuid)), player->GetName().c_str(), GUID_LOPART(player->GetGUID()));
687 return NULL;
688 }
689
690 spellInfo = sSpellMgr->GetSpellInfo(request.spellId);
691 // do not add not learned spells/ passive spells
692 if (!pet->HasSpell(request.spellId) || !spellInfo->IsAutocastable())
693 return NULL;
694
695 charmInfo = pet->GetCharmInfo();
696 if (!charmInfo)
697 {
698 SF_LOG_ERROR("network", "WorldSession::HandlePetSpellAutocastOpcod: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), uint8(pet->GetTypeId()));
699 return NULL;
700 }
701
702 return pet;
703}
704
705Unit* ValidatePetCastRequest(Player* player, PetCastSpellRequest& request, SpellInfo const*& spellInfo)
706{
707 spellInfo = NULL;
708
709 // This opcode is also sent from charmed and possessed units (players and creatures)
710 if (!player->GetGuardianPet() && !player->GetCharm())
711 return NULL;
712
713 Unit* caster = ObjectAccessor::GetUnit(*player, request.petGuid);
714 if (!caster || (caster != player->GetGuardianPet() && caster != player->GetCharm()))
715 {
716 SF_LOG_ERROR("network", "HandlePetCastSpellOpcode: Pet %u isn't pet of player %s (GUID: %u).", uint32(GUID_LOPART(request.petGuid)), player->GetName().c_str(), GUID_LOPART(player->GetGUID()));
717 return NULL;
718 }
719
720 spellInfo = sSpellMgr->GetSpellInfo(request.spellId);
721 if (!spellInfo)
722 {
723 SF_LOG_ERROR("network", "WORLD: unknown PET spell id %i", request.spellId);
724 return NULL;
725 }
726
727 // do not cast not learned spells
728 if (!caster->HasSpell(request.spellId) || spellInfo->IsPassive())
729 return NULL;
730
731 return caster;
732}
733
734Pet* ValidatePetSpecializationRequest(Player* player, SetPetSpecializationRequest& request)
735{
736 if (!player->IsInWorld())
737 return NULL;
738
739 Pet* pet = ObjectAccessor::GetPet(*player, request.petGuid);
740 if (!pet || !pet->IsPet() || pet->getPetType() != PetType::HUNTER_PET ||
741 pet->GetOwnerGUID() != player->GetGUID() || !pet->GetCharmInfo())
742 return NULL;
743
744 return pet;
745}
746}
747
749{
750 PetGuidRequest request = ReadDismissCritterRequest(recvData);
751
752 SF_LOG_DEBUG("network", "WORLD: Received CMSG_DISMISS_CRITTER for (guid: %u)", uint32(GUID_LOPART(request.guid)));
753
755
756 if (!pet)
757 {
758 SF_LOG_DEBUG("network", "Vanitypet (guid: %u) does not exist - player '%s' (guid: %u / account: %u) attempted to dismiss it (possibly lagged out)",
759 uint32(GUID_LOPART(request.guid)), GetPlayer()->GetName().c_str(), GetPlayer()->GetGUIDLow(), GetAccountId());
760 return;
761 }
762
763 if (_player->GetCritterGUID() == pet->GetGUID())
764 {
765 if (pet->GetTypeId() == TypeID::TYPEID_UNIT && pet->ToCreature()->IsSummon())
766 pet->ToTempSummon()->UnSummon();
767 }
768}
769
770void WorldSession::HandlePetAction(WorldPacket& recvData) // sub_68C8FD [5.4.8 18291]
771{
772 PetActionRequest request = ReadPetActionRequest(recvData);
773
774 uint32 SpellID = UNIT_ACTION_BUTTON_ACTION(request.action);
775 uint8 Flag = UNIT_ACTION_BUTTON_TYPE(request.action); //delete = 0x07 CastSpell = C1
776
777 // used also for charmed creature
778 SF_LOG_DEBUG("network", "HandlePetAction: Pet (GUID: %u) - Flag: %u, SpellID: %u, Target: %u.", uint32(GUID_LOPART(request.petGuid)), uint32(Flag), SpellID, uint32(GUID_LOPART(request.targetGuid)));
779
780 Unit* pet = ValidatePetActionRequest(GetPlayer(), request, Flag, SpellID);
781 if (!pet)
782 return;
783
784 if (GetPlayer()->m_Controlled.size() == 1)
785 HandlePetActionHelper(pet, request.petGuid, SpellID, Flag, request.targetGuid, request.x, request.y, request.z);
786 else
787 {
788 //If a pet is dismissed, m_Controlled will change
789 std::vector<Unit*> controlled;
790 for (Unit::ControlList::iterator itr = GetPlayer()->m_Controlled.begin(); itr != GetPlayer()->m_Controlled.end(); ++itr)
791 if ((*itr)->GetEntry() == pet->GetEntry() && (*itr)->IsAlive())
792 controlled.push_back(*itr);
793 for (std::vector<Unit*>::iterator itr = controlled.begin(); itr != controlled.end(); ++itr)
794 HandlePetActionHelper(*itr, request.petGuid, SpellID, Flag, request.targetGuid, request.x, request.y, request.z);
795 }
796}
797
799{
800 PetGuidRequest request = ReadPetStopAttackRequest(recvData);
801
802 SF_LOG_DEBUG("network", "WORLD: Received CMSG_PET_STOP_ATTACK for GUID " UI64FMTD "", (uint64)request.guid);
803
804 Unit* pet = ValidatePetStopAttackRequest(GetPlayer(), request);
805 if (!pet)
806 return;
807
808 pet->AttackStop();
809}
810
811void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint32 spellid, uint16 flag, uint64 guid2, float x, float y, float z)
812{
813 CharmInfo* charmInfo = pet->GetCharmInfo();
814 if (!charmInfo)
815 {
816 SF_LOG_ERROR("network", "WorldSession::HandlePetAction(petGuid: " UI64FMTD ", tagGuid: " UI64FMTD ", spellId: %u, flag: %u): object (entry: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!",
817 guid1, guid2, spellid, flag, pet->GetGUIDLow(), uint8(pet->GetTypeId()));
818 return;
819 }
820
821 switch (flag)
822 {
823 case ACT_COMMAND: //0x07
824 switch (spellid)
825 {
826 case COMMAND_STAY: //flat=1792 //STAY
827 pet->StopMoving();
828 pet->GetMotionMaster()->Clear(false);
829 pet->GetMotionMaster()->MoveIdle();
830 charmInfo->SetCommandState(COMMAND_STAY);
831
832 charmInfo->SetIsCommandAttack(false);
833 charmInfo->SetIsAtStay(true);
834 charmInfo->SetIsCommandFollow(false);
835 charmInfo->SetIsFollowing(false);
836 charmInfo->SetIsReturning(false);
837 charmInfo->SaveStayPosition();
838 break;
839 case COMMAND_FOLLOW: //spellid=1792 //FOLLOW
840 pet->AttackStop();
841 pet->InterruptNonMeleeSpells(false);
844
845 charmInfo->SetIsCommandAttack(false);
846 charmInfo->SetIsAtStay(false);
847 charmInfo->SetIsReturning(true);
848 charmInfo->SetIsCommandFollow(true);
849 charmInfo->SetIsFollowing(false);
850 break;
851 case COMMAND_ATTACK: //spellid=1792 //ATTACK
852 {
853 // Can't attack if owner is pacified
854 if (_player->HasAuraType(SPELL_AURA_MOD_PACIFY))
855 {
856 //pet->SendPetCastFail(spellid, SPELL_FAILED_PACIFIED);
858 return;
859 }
860
861 // only place where pet can be player
862 Unit* TargetUnit = ObjectAccessor::GetUnit(*_player, guid2);
863 if (!TargetUnit)
864 return;
865
866 if (Unit* owner = pet->GetOwner())
867 if (!owner->IsValidAttackTarget(TargetUnit))
868 return;
869
871 // This is true if pet has no target or has target but targets differs.
872 if (pet->GetVictim() != TargetUnit || (pet->GetVictim() == TargetUnit && !pet->GetCharmInfo()->IsCommandAttack()))
873 {
874 if (pet->GetVictim())
875 pet->AttackStop();
876
877 if (pet->GetTypeId() != TypeID::TYPEID_PLAYER && pet->ToCreature()->IsAIEnabled)
878 {
879 charmInfo->SetIsCommandAttack(true);
880 charmInfo->SetIsAtStay(false);
881 charmInfo->SetIsFollowing(false);
882 charmInfo->SetIsCommandFollow(false);
883 charmInfo->SetIsReturning(false);
884
885 pet->ToCreature()->AI()->AttackStart(TargetUnit);
886
887 //10% chance to play special pet attack talk, else growl
888 if (pet->ToCreature()->IsPet() && ((Pet*)pet)->getPetType() == PetType::SUMMON_PET && pet != TargetUnit && (std::rand() % 100) < 10)
890 else
891 {
892 // 90% chance for pet and 100% chance for charmed creature
893 pet->SendPetAIReaction(guid1);
894 }
895 }
896 else // charmed player
897 {
898 if (pet->GetVictim() && pet->GetVictim() != TargetUnit)
899 pet->AttackStop();
900
901 charmInfo->SetIsCommandAttack(true);
902 charmInfo->SetIsAtStay(false);
903 charmInfo->SetIsFollowing(false);
904 charmInfo->SetIsCommandFollow(false);
905 charmInfo->SetIsReturning(false);
906
907 pet->Attack(TargetUnit, true);
908 pet->SendPetAIReaction(guid1);
909 }
910 }
911 break;
912 }
913 case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet)
914 if (pet->GetCharmerGUID() == GetPlayer()->GetGUID())
915 _player->StopCastingCharm();
916 else if (pet->GetOwnerGUID() == GetPlayer()->GetGUID())
917 {
919 if (pet->IsPet())
920 {
921 if (((Pet*)pet)->getPetType() == PetType::HUNTER_PET)
923 else
924 //dismissing a summoned pet is like killing them (this prevents returning a soulshard...)
926 }
927 else if (pet->HasUnitTypeMask(UNIT_MASK_MINION))
928 {
929 ((Minion*)pet)->UnSummon();
930 }
931 }
932 break;
933 case COMMAND_MOVE_TO:
934 pet->StopMoving();
935 pet->GetMotionMaster()->Clear(false);
936 pet->GetMotionMaster()->MovePoint(0, x, y, z);
938
939 charmInfo->SetIsCommandAttack(false);
940 charmInfo->SetIsAtStay(true);
941 charmInfo->SetIsFollowing(false);
942 charmInfo->SetIsReturning(false);
943 charmInfo->SaveStayPosition();
944 break;
945 default:
946 SF_LOG_ERROR("network", "WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid);
947 }
948 break;
949 case ACT_REACTION: // 0x6
950 switch (spellid)
951 {
952 case REACT_ASSIST: //assist
953 case REACT_PASSIVE: //passive
954 pet->AttackStop();
955 case REACT_DEFENSIVE: //recovery
956 case REACT_AGGRESSIVE: //activete
957 if (pet->GetTypeId() == TypeID::TYPEID_UNIT)
958 pet->ToCreature()->SetReactState(ReactStates(spellid));
959 break;
960 }
961 break;
962 case ACT_DISABLED: // 0x81 spell (disabled), ignore
963 case ACT_PASSIVE: // 0x01
964 case ACT_ENABLED: // 0xC1 spell
965 {
966 Unit* unit_target = NULL;
967
968 if (guid2)
969 unit_target = ObjectAccessor::GetUnit(*_player, guid2);
970
971 // do not cast unknown spells
972 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid);
973 if (!spellInfo)
974 {
975 SF_LOG_ERROR("network", "WORLD: unknown PET spell id %i", spellid);
976 return;
977 }
978
979 for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
980 {
982 return;
983 }
984
985 // do not cast not learned spells
986 if (!pet->HasSpell(spellid) || spellInfo->IsPassive())
987 return;
988
989 // Clear the flags as if owner clicked 'attack'. AI will reset them
990 // after AttackStart, even if spell failed
991 if (pet->GetCharmInfo())
992 {
993 pet->GetCharmInfo()->SetIsAtStay(false);
994 pet->GetCharmInfo()->SetIsCommandAttack(true);
995 pet->GetCharmInfo()->SetIsReturning(false);
996 pet->GetCharmInfo()->SetIsFollowing(false);
997 }
998
999 Spell* spell = new Spell(pet, spellInfo, TRIGGERED_NONE);
1000
1001 SpellCastResult result = spell->CheckPetCast(unit_target);
1002
1003 //auto turn to target unless possessed
1004 if (result == SpellCastResult::SPELL_FAILED_UNIT_NOT_INFRONT && !pet->isPossessed() && !pet->IsVehicle())
1005 {
1006 if (unit_target)
1007 {
1008 pet->SetInFront(unit_target);
1009 if (Player* player = unit_target->ToPlayer())
1010 pet->SendUpdateToPlayer(player);
1011 }
1012 else if (Unit* unit_target2 = spell->m_targets.GetUnitTarget())
1013 {
1014 pet->SetInFront(unit_target2);
1015 if (Player* player = unit_target2->ToPlayer())
1016 pet->SendUpdateToPlayer(player);
1017 }
1018
1019 if (Unit* powner = pet->GetCharmerOrOwner())
1020 if (Player* player = powner->ToPlayer())
1021 pet->SendUpdateToPlayer(player);
1022
1024 }
1025
1026 if (result == SpellCastResult::SPELL_CAST_OK)
1027 {
1028 pet->ToCreature()->AddCreatureSpellCooldown(spellid);
1029
1030 unit_target = spell->m_targets.GetUnitTarget();
1031
1032 //10% chance to play special pet attack talk, else growl
1033 //actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
1034 if (pet->ToCreature()->IsPet() && (((Pet*)pet)->getPetType() == PetType::SUMMON_PET) && (pet != unit_target) && ((std::rand() % 100) < 10))
1036 else
1037 {
1038 pet->SendPetAIReaction(guid1);
1039 }
1040
1041 if (unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->isPossessed() && !pet->IsVehicle())
1042 {
1043 // This is true if pet has no target or has target but targets differs.
1044 if (pet->GetVictim() != unit_target)
1045 {
1046 if (pet->GetVictim())
1047 pet->AttackStop();
1048 pet->GetMotionMaster()->Clear();
1049 if (pet->ToCreature()->IsAIEnabled)
1050 pet->ToCreature()->AI()->AttackStart(unit_target);
1051 }
1052 }
1053
1054 spell->prepare(&(spell->m_targets));
1055 }
1056 else
1057 {
1058 if (pet->isPossessed() || pet->IsVehicle())
1059 Spell::SendCastResult(GetPlayer(), spellInfo, 0, result);
1060 else
1061 spell->SendPetCastResult(result);
1062
1063 if (!pet->ToCreature()->HasSpellCooldown(spellid))
1064 GetPlayer()->SendClearCooldown(spellid, pet);
1065
1066 spell->finish(false);
1067 delete spell;
1068
1069 // reset specific flags in case of spell fail. AI will reset other flags
1070 if (pet->GetCharmInfo())
1071 pet->GetCharmInfo()->SetIsCommandAttack(false);
1072 }
1073 break;
1074 }
1075 default:
1076 SF_LOG_ERROR("network", "WORLD: unknown PET flag Action %i and spellid %i.", uint32(flag), spellid);
1077 }
1078}
1079
1081{
1082 SF_LOG_INFO("network", "HandlePetNameQuery. CMSG_PET_NAME_QUERY");
1083
1084 PetNameQueryRequest request = ReadPetNameQueryRequest(recvData);
1085 SendPetNameQuery(request.petGuid, request.petNumber);
1086}
1087
1089{
1091 if (!pet)
1092 {
1094 data.WriteBit(0);
1095 data.FlushBits();
1096 data << uint64(petNumber);
1097
1098 _player->GetSession()->SendPacket(&data);
1099 return;
1100 }
1101
1102 WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (8 + 1 + 1 + 5 + pet->GetName().size() + 4));
1103 data.WriteBit(1); // has data
1104
1105 bool declinedNames = pet->IsPet() && ((Pet*)pet)->GetDeclinedNames();
1106
1107 for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
1108 {
1109 if (declinedNames)
1110 data.WriteBits(((Pet*)pet)->GetDeclinedNames()->name[i].size(), 7);
1111 else
1112 data.WriteBits(0, 7);
1113 }
1114
1115 data.WriteBit(0); // unknown
1116 data.WriteBits(pet->GetName().size(), 8);
1117 data.FlushBits();
1118
1119 if (declinedNames)
1120 for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
1121 data.WriteString(((Pet*)pet)->GetDeclinedNames()->name[i]);
1122
1123 data.WriteString(pet->GetName());
1125 data << uint64(petNumber);
1126
1127 _player->GetSession()->SendPacket(&data);
1128}
1129
1131{
1132 // spell case or GM
1133 if (guid == GetPlayer()->GetGUID())
1134 {
1135 if (!GetPlayer()->IsGameMaster())
1136 {
1137 SF_LOG_DEBUG("network", "Player (GUID:%u) attempt open stable in cheating way.", GUID_LOPART(guid));
1138 return false;
1139 }
1140 }
1141 // stable master case
1142 else
1143 {
1144 if (!GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_STABLEMASTER))
1145 {
1146 SF_LOG_DEBUG("network", "Stablemaster (GUID:%u) not found or you can't interact with him.", GUID_LOPART(guid));
1147 return false;
1148 }
1149 }
1150 return true;
1151}
1152
1154{
1155 SF_LOG_INFO("network", "HandlePetSetAction. CMSG_PET_SET_ACTION");
1156
1157 PetSetActionRequest request = ReadPetSetActionRequest(recvData);
1158
1159 CharmInfo* charmInfo = NULL;
1160 Unit* pet = ValidatePetSetActionRequest(GetPlayer(), request, charmInfo);
1161 if (!pet)
1162 return;
1163
1164 uint32 spell_id = UNIT_ACTION_BUTTON_ACTION(request.action);
1165 uint8 act_state = UNIT_ACTION_BUTTON_TYPE(request.action);
1166
1167 SF_LOG_INFO("network", "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X",
1168 _player->GetName().c_str(), request.index, spell_id, uint32(act_state));
1169
1170 //if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add
1171 if (!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_PASSIVE) && spell_id && !pet->HasSpell(spell_id)))
1172 {
1173 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id))
1174 {
1175 //sign for autocast
1176 if (act_state == ACT_ENABLED)
1177 {
1178 if (pet->GetTypeId() == TypeID::TYPEID_UNIT && pet->ToCreature()->IsPet())
1179 ((Pet*)pet)->ToggleAutocast(spellInfo, true);
1180 else
1181 for (Unit::ControlList::iterator itr = GetPlayer()->m_Controlled.begin(); itr != GetPlayer()->m_Controlled.end(); ++itr)
1182 if ((*itr)->GetEntry() == pet->GetEntry())
1183 (*itr)->GetCharmInfo()->ToggleCreatureAutocast(spellInfo, true);
1184 }
1185 //sign for no/turn off autocast
1186 else if (act_state == ACT_DISABLED)
1187 {
1188 if (pet->GetTypeId() == TypeID::TYPEID_UNIT && pet->ToCreature()->IsPet())
1189 ((Pet*)pet)->ToggleAutocast(spellInfo, false);
1190 else
1191 for (Unit::ControlList::iterator itr = GetPlayer()->m_Controlled.begin(); itr != GetPlayer()->m_Controlled.end(); ++itr)
1192 if ((*itr)->GetEntry() == pet->GetEntry())
1193 (*itr)->GetCharmInfo()->ToggleCreatureAutocast(spellInfo, false);
1194 }
1195 }
1196 charmInfo->SetActionBar(request.index, spell_id, ActiveStates(act_state));
1197 }
1198}
1199
1201{
1202 SF_LOG_INFO("network", "HandlePetRename. CMSG_PET_RENAME");
1203
1204 PetRenameRequest request = ReadPetRenameRequest(recvData);
1205
1206 Pet* pet = ValidatePetRenameTarget(GetPlayer());
1207 if (!pet)
1208 return;
1209
1210 if (!ValidatePetRenameName(this, request))
1211 return;
1212
1213 pet->SetName(request.name);
1214
1215 if (_player->GetGroup())
1216 _player->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_NAME);
1217
1219
1220 if (request.hasDeclinedNames)
1221 if (!ValidatePetDeclinedNames(this, request))
1222 return;
1223
1224 SQLTransaction trans = CharacterDatabase.BeginTransaction();
1225 if (request.hasDeclinedNames)
1226 {
1228 stmt->setUInt32(0, pet->GetCharmInfo()->GetPetNumber());
1229 trans->Append(stmt);
1230
1231 stmt = CharacterDatabase.GetPreparedStatement(CHAR_ADD_CHAR_PET_DECLINEDNAME);
1232 stmt->setUInt32(0, _player->GetGUIDLow());
1233
1234 for (uint8 i = 0; i < 5; i++)
1235 stmt->setString(i + 1, request.declinedName.name[i]);
1236
1237 trans->Append(stmt);
1238 }
1239
1240 PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_NAME);
1241 stmt->setString(0, request.name);
1242 stmt->setUInt32(1, _player->GetGUIDLow());
1243 stmt->setUInt32(2, pet->GetCharmInfo()->GetPetNumber());
1244 trans->Append(stmt);
1245
1246 CharacterDatabase.CommitTransaction(trans);
1247
1248 pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, uint32(time(NULL))); // cast can't be helped
1249}
1250
1252{
1253 PetGuidRequest request = ReadPetAbandonRequest(recvData);
1254
1255 SF_LOG_INFO("network", "HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u", GUID_LOPART(request.guid));
1256
1257 // pet/charmed
1258 Creature* pet = ValidatePetAbandonRequest(GetPlayer(), request);
1259 if (pet)
1260 {
1261 if (pet->IsPet())
1262 _player->RemovePet((Pet*)pet, PET_SAVE_AS_DELETED);
1263 else if (pet->GetGUID() == _player->GetCharmGUID())
1264 _player->StopCastingCharm();
1265 }
1266}
1267
1269{
1270 SF_LOG_INFO("network", "CMSG_PET_SPELL_AUTOCAST");
1271
1272 PetSpellAutocastRequest request = ReadPetSpellAutocastRequest(recvPacket);
1273
1274 SpellInfo const* spellInfo = NULL;
1275 CharmInfo* charmInfo = NULL;
1276 Creature* pet = ValidatePetAutocastRequest(GetPlayer(), request, spellInfo, charmInfo);
1277 if (!pet)
1278 return;
1279
1280 if (pet->IsPet())
1281 ((Pet*)pet)->ToggleAutocast(spellInfo, request.state);
1282 else
1283 pet->GetCharmInfo()->ToggleCreatureAutocast(spellInfo, request.state);
1284
1285 charmInfo->SetSpellAutocast(spellInfo, request.state);
1286}
1287
1289{
1290 SF_LOG_DEBUG("network", "WORLD: CMSG_PET_CAST_SPELL");
1291
1292 PetCastSpellRequest request = ReadPetCastSpellRequest(recvPacket);
1293
1294 SF_LOG_DEBUG("network", "WORLD: CMSG_PET_CAST_SPELL, guid: " UI64FMTD ", castCount: %u, spellId %u, castFlags %u", uint64(request.petGuid), request.castCount, request.spellId, request.castFlags);
1295
1296 SpellInfo const* spellInfo = NULL;
1297 Unit* caster = ValidatePetCastRequest(GetPlayer(), request, spellInfo);
1298 if (!caster)
1299 return;
1300
1301 SpellCastTargets targets;
1302 targets.Initialize(request.targetFlags, request.targetGuid, request.itemGuid, request.transportDstGuid, request.dstLoc, request.transportSrcGuid, request.srcLoc);
1303 targets.SetElevation(request.elevation);
1304 targets.SetSpeed(request.missileSpeed);
1305 targets.Update(caster);
1306
1308
1309 Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE);
1310 spell->m_cast_count = request.castCount; // probably pending spell cast
1311 spell->m_targets = targets;
1312
1313 Unit* unit_target = request.targetGuid ? ObjectAccessor::GetUnit(*_player, request.targetGuid) : nullptr;
1314 if (!unit_target && caster->GetVehicleKit() && caster->GetVehicleKit()->GetPassenger(0))
1315 unit_target = caster->GetVehicleKit()->GetPassenger(0);
1316 SpellCastResult result = spell->CheckPetCast(unit_target ? unit_target : nullptr);
1317
1318 if (result == SpellCastResult::SPELL_CAST_OK)
1319 {
1320 spell->prepare(&(spell->m_targets));
1321
1322 if (Creature* creature = caster->ToCreature())
1323 {
1324 creature->AddCreatureSpellCooldown(request.spellId);
1325 if (Pet* pet = creature->ToPet())
1326 {
1327 // 10% chance to play special pet attack talk, else growl
1328 // actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
1329 if (pet->getPetType() == PetType::SUMMON_PET && ((std::rand() % 100) < 10))
1331 else
1332 pet->SendPetAIReaction(request.petGuid);
1333 }
1334 }
1335 }
1336 else
1337 {
1338 spell->SendPetCastResult(result);
1339
1340 if (caster->GetTypeId() == TypeID::TYPEID_PLAYER)
1341 {
1342 if (!caster->ToPlayer()->HasSpellCooldown(request.spellId))
1343 GetPlayer()->SendClearCooldown(request.spellId, caster);
1344 }
1345 else
1346 {
1347 if (!caster->ToCreature()->HasSpellCooldown(request.spellId))
1348 GetPlayer()->SendClearCooldown(request.spellId, caster);
1349 }
1350
1351 spell->finish(false);
1352 delete spell;
1353 }
1354}
1355
1356void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName* declinedName, uint32 petNumber)
1357{
1358 WorldPacket data(SMSG_PET_NAME_INVALID, 4 + name.size() + 1 + 1 + 1 + 4);
1359 data.WriteBit(1);
1360 data.WriteBits(name.size(), 8);
1361 data.WriteBit(declinedName ? 1 : 0);
1362 data.FlushBits();
1363
1364 if (declinedName)
1365 {
1366 for (uint32 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
1367 data.WriteBits(declinedName->name[i].size(), 7);
1368
1369 for (uint32 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
1370 data.WriteString(declinedName->name[i]);
1371 }
1372
1373 data.WriteString(name);
1374 data << uint8(error);
1375 data << uint32(petNumber);
1376
1377 SendPacket(&data);
1378}
1379
1381{
1382 SF_LOG_DEBUG("network", "WORLD: CMSG_PET_LEARN_TALENT");
1383}
1384
1386{
1387 SF_LOG_DEBUG("network", "CMSG_LEARN_PREVIEW_TALENTS_PET");
1388}
1389
1391{
1392 SF_LOG_DEBUG("network", "CMSG_SET_PET_SPECIALIZATION");
1393
1394 SetPetSpecializationRequest request = ReadSetPetSpecializationRequest(recvData);
1395
1396 Pet* pet = ValidatePetSpecializationRequest(GetPlayer(), request);
1397 if (!pet)
1398 return;
1399
1400 pet->SetSpec(pet->GetPetSpecByTalentTab(request.talentTab));
1401}
@ CHAR_ADD_CHAR_PET_DECLINEDNAME
@ CHAR_UPD_CHAR_PET_NAME
@ CHAR_DEL_CHAR_PET_DECLINEDNAME
#define MAX_SPELL_EFFECTS
std::int32_t int32
Definition Define.h:73
#define UI64FMTD
Definition Define.h:64
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
std::uint64_t uint64
Definition Define.h:76
std::uint16_t uint16
Definition Define.h:78
#define ASSERT
Definition Errors.h:29
@ GROUP_UPDATE_FLAG_PET_NAME
Definition Group.h:89
#define SF_LOG_DEBUG(filterType__,...)
Definition Log.h:134
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
#define SF_LOG_INFO(filterType__,...)
Definition Log.h:137
@ TYPEID_PLAYER
Definition Object.h:55
@ TYPEID_UNIT
Definition Object.h:54
uint32 GUID_LOPART(uint64 x)
#define sObjectMgr
Definition ObjectMgr.h:1617
@ PET_SAVE_AS_DELETED
Definition PetDefines.h:21
#define PET_FOLLOW_DIST
Definition PetDefines.h:57
@ PET_TALK_SPECIAL_SPELL
Definition PetDefines.h:53
@ PET_TALK_ATTACK
Definition PetDefines.h:54
@ SUMMON_PET
Definition PetDefines.h:11
@ HUNTER_PET
Definition PetDefines.h:12
@ SPELL_ATTR0_CASTABLE_WHILE_DEAD
@ TARGET_DEST_DYNOBJ_ENEMY
@ TARGET_UNIT_DEST_AREA_ENEMY
@ TARGET_UNIT_SRC_AREA_ENEMY
PetNameInvalidReason
@ PET_NAME_RESERVED
@ PET_NAME_SUCCESS
@ PET_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME
SpellCastResult
@ SPELL_AURA_MOD_PACIFY
#define sSpellMgr
Definition SpellMgr.h:744
Skyfire::AutoPtr< Transaction, Skyfire::Mutex > SQLTransaction
Definition Transaction.h:42
@ UNIT_NPC_FLAG_STABLEMASTER
Definition Unit.h:709
@ UNIT_CAN_BE_RENAMED
Definition Unit.h:268
@ UNIT_MASK_MINION
Definition Unit.h:806
#define MAX_UNIT_ACTION_BAR_INDEX
Definition Unit.h:1233
#define UNIT_ACTION_BUTTON_ACTION(X)
Definition Unit.h:1171
@ CORPSE
Definition Unit.h:505
@ COMMAND_ATTACK
Definition Unit.h:1166
@ COMMAND_MOVE_TO
Definition Unit.h:1168
@ COMMAND_ABANDON
Definition Unit.h:1167
@ COMMAND_STAY
Definition Unit.h:1164
@ COMMAND_FOLLOW
Definition Unit.h:1165
#define MAX_DECLINED_NAME_CASES
Definition Unit.h:1098
@ TRIGGERED_NONE
Definition Unit.h:416
#define UNIT_ACTION_BUTTON_TYPE(X)
Definition Unit.h:1172
ActiveStates
Definition Unit.h:1144
@ ACT_REACTION
Definition Unit.h:1150
@ ACT_COMMAND
Definition Unit.h:1149
@ ACT_ENABLED
Definition Unit.h:1148
@ ACT_PASSIVE
Definition Unit.h:1145
@ ACT_DISABLED
Definition Unit.h:1147
@ UNIT_STATE_FOLLOW
Definition Unit.h:521
ReactStates
Definition Unit.h:1155
@ REACT_DEFENSIVE
Definition Unit.h:1157
@ REACT_PASSIVE
Definition Unit.h:1156
@ REACT_AGGRESSIVE
Definition Unit.h:1158
@ REACT_ASSIST
Definition Unit.h:1159
@ UNIT_FIELD_SHAPESHIFT_FORM
@ UNIT_FIELD_PET_NAME_TIMESTAMP
bool Utf8toWStr(char const *utf8str, size_t csize, wchar_t *wstr, size_t &wsize)
Definition Util.cpp:305
bool WriteBit(uint32 bit)
Definition ByteBuffer.h:164
void read_skip()
Definition ByteBuffer.h:502
void WriteString(std::string const &str)
Definition ByteBuffer.h:578
uint32 ReadBits(size_t bits)
Definition ByteBuffer.h:198
void ReadGuidBytes(ObjectGuid &guid, Offsets... offsets)
Definition ByteBuffer.h:256
void ReadByteSeq(uint8 &b)
Definition ByteBuffer.h:215
std::string ReadString(size_t length)
Definition ByteBuffer.h:565
void ReadGuidMask(ObjectGuid &guid, Offsets... offsets)
Definition ByteBuffer.h:240
void WriteBits(T value, size_t bits)
Definition ByteBuffer.h:192
void FlushBits()
Definition ByteBuffer.h:154
bool ReadBit()
Definition ByteBuffer.h:180
void SetReactState(ReactStates st)
Definition Creature.h:460
void AddCreatureSpellCooldown(uint32 spellid)
bool HasSpell(uint32 spellID) const OVERRIDE
bool HasSpellCooldown(uint32 spell_id) const
CreatureAI * AI() const
Definition Creature.h:483
void MoveFollow(Unit *target, float dist, float angle, MovementSlot slot=MOTION_SLOT_ACTIVE)
void MovePoint(uint32 id, Position const &pos, bool generatePath=true)
void Clear(bool reset=true)
static Creature * GetCreatureOrPetOrVehicle(WorldObject const &, uint64)
static Unit * GetUnit(WorldObject const &, uint64 guid)
static Player * FindPlayer(uint64)
static Pet * GetPet(WorldObject const &, uint64 guid)
uint64 GetGUID() const
Definition Object.h:119
uint32 GetUInt32Value(uint16 index) const
Definition Object.cpp:325
Player * ToPlayer()
Definition Object.h:204
bool IsInWorld() const
Definition Object.h:114
uint32 GetGUIDLow() const
Definition Object.h:120
TypeID GetTypeId() const
Definition Object.h:131
uint32 GetEntry() const
Definition Object.h:125
Creature * ToCreature()
Definition Object.h:207
void RemoveByteFlag(uint16 index, uint8 offset, uint8 newFlag)
Definition Object.cpp:1345
bool HasByteFlag(uint16 index, uint8 offset, uint8 flag) const
Definition Object.cpp:1376
void SendUpdateToPlayer(Player *player)
Definition Object.cpp:259
void SetUInt32Value(uint16 index, uint32 value)
Definition Object.cpp:1038
static bool CheckDeclinedNames(const std::wstring &w_ownname, DeclinedName const &names)
static PetNameInvalidReason CheckPetName(std::string const &name)
Definition Pet.h:28
void setDeathState(DeathState s)
Definition Pet.cpp:521
PetType getPetType() const
Definition Pet.h:38
uint16 GetPetSpecByTalentTab(uint16 talenttab)
Definition Pet.cpp:2143
void SetSpec(uint16 spec)
Definition Pet.cpp:2194
bool HasSpellCooldown(uint32 spell_id) const
Definition Player.cpp:17498
Pet * GetPet() const
Definition Player.cpp:15640
void RemovePet(Pet *pet, PetSaveMode mode, bool returnreagent=false)
Definition Player.cpp:15663
void SendClearCooldown(uint32 spell_id, Unit *target)
Definition Player.cpp:21596
void setString(const uint8 index, const std::string &value)
void setUInt32(const uint8 index, const uint32 value)
void SetSpeed(float speed)
Definition Spell.h:223
void Initialize(uint32 flags, uint64 target, uint64 itemTarget, uint64 dest, WorldLocation destPos, uint64 src, WorldLocation srcPos)
Definition Spell.h:153
void SetElevation(float elevation)
Definition Spell.h:221
Unit * GetUnitTarget() const
Definition Spell.cpp:221
void Update(Unit *caster)
Definition Spell.cpp:430
SpellImplicitTargetInfo TargetA
Definition SpellInfo.h:102
Definition Spell.h:289
static void SendCastResult(Player *caster, SpellInfo const *spellInfo, uint8 cast_count, SpellCastResult result, SpellCustomErrors customError=SPELL_CUSTOM_ERROR_NONE, Opcodes opcode=SMSG_CAST_FAILED)
Definition Spell.cpp:3874
SpellCastTargets m_targets
Definition Spell.h:535
void SendPetCastResult(SpellCastResult result)
Definition Spell.cpp:3862
void prepare(SpellCastTargets const *targets, AuraEffect const *triggeredByAura=NULL)
Definition Spell.cpp:2939
uint8 m_cast_count
Definition Spell.h:533
SpellCastResult CheckPetCast(Unit *target)
Definition Spell.cpp:6365
void finish(bool ok=true)
Definition Spell.cpp:3762
SpellEffectInfo Effects[MAX_SPELL_EFFECTS]
Definition SpellInfo.h:255
bool IsAutocastable() const
bool IsPassive() const
uint32 Attributes
Definition SpellInfo.h:164
virtual void UnSummon(uint32 msTime=0)
virtual void AttackStart(Unit *)
Definition UnitAI.cpp:16
Definition Unit.h:1367
void ClearUnitState(uint32 f)
Definition Unit.h:1489
bool IsVehicle() const
Definition Unit.h:1523
Unit * GetCharm() const
Definition Unit.cpp:2405
Unit * GetOwner() const
Definition Unit.cpp:2339
Pet * ToPet()
Definition Unit.h:2803
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition Unit.cpp:1433
MotionMaster * GetMotionMaster()
Definition Unit.h:2605
bool IsPet() const
Definition Unit.h:1511
bool IsAlive() const
Definition Unit.h:2032
void StopMoving()
-------—End of Pet responses methods-------—
Definition Unit.cpp:5877
TempSummon * ToTempSummon()
Definition Unit.h:2821
CharmInfo * GetCharmInfo()
Definition Unit.h:2148
uint64 GetCharmerGUID() const
Definition Unit.h:2071
virtual bool HasSpell(uint32) const
Definition Unit.h:1910
Unit * GetCharmerOrOwner() const
Definition Unit.cpp:2419
bool Attack(Unit *victim, bool meleeAttack)
bool isPossessed() const
Definition Unit.h:2140
bool IsSummon() const
Definition Unit.h:1503
void SendPetTalk(uint32 pettalk) const
Definition Unit.cpp:5844
virtual float GetFollowAngle() const
Definition Unit.h:2788
Unit * GetVictim() const
Definition Unit.h:1468
Unit * GetFirstControlled() const
Definition Unit.cpp:2769
bool IsAIEnabled
Definition Unit.h:2735
uint32 HasUnitTypeMask(uint32 mask) const
Definition Unit.h:1495
uint64 GetOwnerGUID() const
Definition Unit.h:2050
void SetInFront(WorldObject const *target)
Definition Unit.cpp:9108
Vehicle * GetVehicleKit() const
Definition Unit.h:2739
Guardian * GetGuardianPet() const
Definition Unit.cpp:2390
bool AttackStop()
void SendPetAIReaction(ObjectGuid UnitGUID) const
Definition Unit.cpp:5858
Unit * GetPassenger(int8 seatId) const
Gets a passenger on specified seat.
Definition Vehicle.cpp:306
void SetName(std::string const &newname)
Definition Object.h:665
std::string const & GetName() const
Definition Object.h:664
Player session in the World.
void HandleDismissCritter(WorldPacket &recvData)
void HandlePetRename(WorldPacket &recvData)
void HandlePetCastSpellOpcode(WorldPacket &recvPacket)
bool CheckStableMaster(uint64 guid)
void SendPetNameInvalid(uint32 error, std::string const &name, DeclinedName *declinedName, uint32 petNumber)
void HandleSetPetSpecialization(WorldPacket &recvData)
Player * GetPlayer() const
void HandlePetSetAction(WorldPacket &recvData)
void HandleLearnPreviewTalentsPet(WorldPacket &recvPacket)
void HandlePetSpellAutocastOpcode(WorldPacket &recvPacket)
void HandlePetAction(WorldPacket &recvData)
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
uint32 GetAccountId() const
void HandlePetAbandon(WorldPacket &recvData)
void HandlePetLearnTalent(WorldPacket &recvPacket)
Player * _player
void HandlePetNameQuery(WorldPacket &recvData)
void HandlePetActionHelper(Unit *pet, uint64 guid1, uint32 spellid, uint16 flag, uint64 guid2, float x, float y, float z)
void SendPetNameQuery(ObjectGuid guid, uint64 petNumber)
void HandlePetStopAttack(WorldPacket &recvData)
CharacterDatabaseWorkerPool CharacterDatabase
Accessor to the character database.
Definition Main.cpp:41
@ SMSG_PET_NAME_INVALID
Definition Opcodes.h:869
@ SMSG_PET_NAME_QUERY_RESPONSE
Definition Opcodes.h:870
void SaveStayPosition()
Definition Unit.cpp:9077
bool IsCommandAttack() const
Definition Unit.h:1293
void SetIsCommandFollow(bool val)
Definition Unit.cpp:9072
uint32 GetPetNumber() const
Definition Unit.h:1241
void SetActionBar(uint8 index, uint32 spellOrAction, ActiveStates type)
Definition Unit.h:1271
void SetIsAtStay(bool val)
Definition Unit.cpp:9093
void SetIsFollowing(bool val)
Definition Unit.cpp:9098
void SetIsReturning(bool val)
Definition Unit.cpp:9103
void SetSpellAutocast(SpellInfo const *spellInfo, bool state)
Definition Unit.cpp:5784
void ToggleCreatureAutocast(SpellInfo const *spellInfo, bool apply)
Definition Unit.cpp:5727
void SetCommandState(CommandStates st)
Definition Unit.h:1247
void SetIsCommandAttack(bool val)
Definition Unit.cpp:9067
std::string name[MAX_DECLINED_NAME_CASES]
Definition Unit.h:1102
float m_positionZ
Definition Object.h:289
float m_positionX
Definition Object.h:287
float m_positionY
Definition Object.h:288