OregonCore  revision fb2a440-git
Your Favourite TBC server
PetHandler.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the OregonCore 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 "Common.h"
19 #include "WorldPacket.h"
20 #include "WorldSession.h"
21 #include "World.h"
22 #include "ObjectMgr.h"
23 #include "SpellMgr.h"
24 #include "Log.h"
25 #include "Opcodes.h"
26 #include "Spell.h"
27 #include "ObjectAccessor.h"
28 #include "MapManager.h"
29 #include "CreatureAI.h"
30 #include "Utilities/Util.h"
31 #include "Pet.h"
32 #include "Language.h"
33 
35 {
36  uint64 guid1;
37  uint16 spellid;
38  uint16 flag;
39  uint64 guid2;
40  recv_data >> guid1; //pet guid
41  recv_data >> spellid;
42  recv_data >> flag; //delete = 0x0700 CastSpell = C100
43  recv_data >> guid2; //tag guid
44 
45  // used also for charmed creature
46  Unit* pet = ObjectAccessor::GetUnit(*_player, guid1);
47  sLog.outDetail("HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.", uint32(GUID_LOPART(guid1)), flag, spellid, uint32(GUID_LOPART(guid2)));
48  if (!pet)
49  {
50  sLog.outError("Pet %u not exist.", uint32(GUID_LOPART(guid1)));
51  return;
52  }
53 
54  if (pet != GetPlayer()->GetFirstControlled())
55  {
56  sLog.outError("HandlePetAction.Pet %u isn't pet of player %s.", uint32(GUID_LOPART(guid1)), GetPlayer()->GetName());
57  return;
58  }
59 
60  if (pet->GetTypeId() == TYPEID_PLAYER)
61  {
62  // controller player can only do melee attack
63  if (!(flag == ACT_COMMAND && spellid == COMMAND_ATTACK))
64  return;
65  }
66  else if (((Creature*)pet)->IsPet())
67  {
68  // pet can have action bar disabled
69  if (((Pet*)pet)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS)
70  return;
71  }
72 
73  if (GetPlayer()->m_Controlled.size() == 1)
74  HandlePetActionHelper(pet, guid1, spellid, flag, guid2);
75  else
76  {
77  //If a pet is dismissed, m_Controlled will change
78  std::vector<Unit*> controlled;
79  for (Unit::ControlList::iterator itr = GetPlayer()->m_Controlled.begin(); itr != GetPlayer()->m_Controlled.end(); ++itr)
80  if ((*itr)->GetEntry() == pet->GetEntry() && (*itr)->IsAlive())
81  controlled.push_back(*itr);
82  for (std::vector<Unit*>::iterator itr = controlled.begin(); itr != controlled.end(); ++itr)
83  HandlePetActionHelper(*itr, guid1, spellid, flag, guid2);
84  }
85 }
86 
87 void WorldSession::HandlePetActionHelper(Unit* pet, uint64 guid1, uint16 spellid, uint16 flag, uint64 guid2)
88 {
89  CharmInfo* charmInfo = pet->GetCharmInfo();
90  if (!charmInfo)
91  {
92  sLog.outError("WorldSession::HandlePetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId());
93  return;
94  }
95 
96  switch (flag)
97  {
98  case ACT_COMMAND: //0x0700
99  switch (spellid)
100  {
101  case COMMAND_STAY: //flat=1792 //STAY
102  pet->AttackStop();
103  pet->InterruptNonMeleeSpells(false);
104  pet->GetMotionMaster()->MoveIdle();
105  charmInfo->SetCommandState(COMMAND_STAY);
106  charmInfo->SetIsCommandFollow(false);
107  charmInfo->SetIsCommandAttack(false);
108  charmInfo->SetIsAtStay(true);
109  charmInfo->SetIsFollowing(false);
110  charmInfo->SetIsReturning(false);
111  charmInfo->SaveStayPosition();
112  break;
113  case COMMAND_FOLLOW: //spellid=1792 //FOLLOW
114  pet->AttackStop();
115  pet->InterruptNonMeleeSpells(false);
116  pet->ClearInPetCombat();
118  charmInfo->SetCommandState(COMMAND_FOLLOW);
119  charmInfo->SetIsCommandFollow(true);
120  charmInfo->SetIsCommandAttack(false);
121  charmInfo->SetIsAtStay(false);
122  charmInfo->SetIsReturning(true);
123  charmInfo->SetIsFollowing(false);
124  break;
125  case COMMAND_ATTACK: //spellid=1792 //ATTACK
126  {
127  // Can't attack if owner is pacified
129  {
130  //pet->SendPetCastFail(spellid, SPELL_FAILED_PACIFIED);
131  //@todo Send proper error message to client
132  return;
133  }
134 
135  // only place where pet can be player
136  Unit* TargetUnit = ObjectAccessor::GetUnit(*_player, guid2);
137  if (!TargetUnit)
138  return;
139 
140  if (Unit* owner = pet->GetOwner())
141  if (!owner->IsValidAttackTarget(TargetUnit))
142  return;
143 
145  // This is true if pet has no target or has target but targets differs.
146  if (pet->GetVictim() != TargetUnit || (pet->GetVictim() == TargetUnit && !pet->GetCharmInfo()->IsCommandAttack()))
147  {
148  if (pet->GetVictim())
149  pet->AttackStop();
150 
151  if (pet->GetTypeId() != TYPEID_PLAYER && pet->ToCreature()->IsAIEnabled)
152  {
153  charmInfo->SetIsCommandAttack(true);
154  charmInfo->SetIsAtStay(false);
155  charmInfo->SetIsFollowing(false);
156  charmInfo->SetIsReturning(false);
157  charmInfo->SetIsCommandFollow(false);
158 
159  pet->ToCreature()->AI()->AttackStart(TargetUnit);
160 
161  //10% chance to play special pet attack talk, else growl
162  if (pet->IsPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10)
164  else
165  {
166  // 90% chance for pet and 100% chance for charmed creature
167  pet->SendPetAIReaction(guid1);
168  }
169  }
170  else // charmed player
171  {
172  charmInfo->SetIsCommandAttack(true);
173  charmInfo->SetIsAtStay(false);
174  charmInfo->SetIsFollowing(false);
175  charmInfo->SetIsReturning(false);
176  charmInfo->SetIsCommandFollow(false);
177  pet->Attack(TargetUnit, true);
178  pet->SendPetAIReaction(guid1);
179  }
180  }
181  break;
182  }
183  case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet)
184  if (pet->GetCharmerGUID() == GetPlayer()->GetGUID())
186  else if (pet->GetOwnerGUID() == GetPlayer()->GetGUID())
187  {
188  assert(pet->GetTypeId() == TYPEID_UNIT);
189  if (pet->IsPet())
190  {
191  if (((Pet*)pet)->getPetType() == HUNTER_PET)
193  else
194  //dismissing a summoned pet is like killing them (this prevents returning a soulshard...)
195  pet->setDeathState(CORPSE);
196  }
197  else if (pet->ToCreature()->HasUnitTypeMask(UNIT_MASK_MINION))
198  ((Minion*)pet)->UnSummon();
199  }
200  break;
201  default:
202  sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", flag, spellid);
203  }
204  break;
205  case ACT_REACTION: // 0x600
206  switch (spellid)
207  {
208  case REACT_PASSIVE: //passive
209  pet->AttackStop();
210  pet->ClearInPetCombat();
211  // no break
212  case REACT_DEFENSIVE: //recovery
213  case REACT_AGGRESSIVE: //activete
214  if (pet->GetTypeId() == TYPEID_UNIT)
215  pet->ToCreature()->SetReactState(ReactStates(spellid));
216  break;
217  }
218  break;
219  case ACT_DISABLED: //0x8100 spell (disabled), ignore
220  case ACT_CAST: //0x0100
221  case ACT_ENABLED: //0xc100 spell
222  {
223  Unit* unit_target = NULL;
224 
225  if (pet->ToCreature()->GetGlobalCooldown() > 0)
226  return;
227 
228  if (guid2)
229  unit_target = ObjectAccessor::GetUnit(*_player, guid2);
230 
231  // do not cast unknown spells
232  SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid);
233  if (!spellInfo)
234  {
235  sLog.outError("WORLD: unknown PET spell id %i", spellid);
236  return;
237  }
238 
239  for (uint32 i = 0; i < 3; ++i)
240  {
242  return;
243  }
244 
245  // do not cast not learned spells
246  if (!pet->HasSpell(spellid) || IsPassiveSpell(spellid))
247  return;
248 
249  // Clear the flags as if owner clicked 'attack'. AI will reset them
250  // after AttackStart, even if spell failed
251  if (pet->GetCharmInfo())
252  {
253  pet->GetCharmInfo()->SetIsAtStay(false);
254  pet->GetCharmInfo()->SetIsCommandAttack(true);
255  pet->GetCharmInfo()->SetIsReturning(false);
256  pet->GetCharmInfo()->SetIsFollowing(false);
257  }
258 
259  Spell* spell = new Spell(pet, spellInfo, false);
260 
261  SpellCastResult result = spell->CheckPetCast(unit_target);
262 
263  //auto turn to target unless possessed
264  if (result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->isPossessed())
265  {
266  pet->SetInFront(unit_target);
267  if (unit_target->GetTypeId() == TYPEID_PLAYER)
268  pet->SendUpdateToPlayer(unit_target->ToPlayer());
269  if (Unit* powner = pet->GetCharmerOrOwner())
270  if (powner->GetTypeId() == TYPEID_PLAYER)
271  pet->SendUpdateToPlayer(powner->ToPlayer());
272  result = SPELL_CAST_OK;
273  }
274 
275  if (result == SPELL_CAST_OK)
276  {
277  pet->ToCreature()->AddCreatureSpellCooldown(spellid);
278  if (pet->IsPet())
279  ((Pet*)pet)->CheckLearning(spellid);
280 
281  unit_target = spell->m_targets.getUnitTarget();
282 
283  //10% chance to play special pet attack talk, else growl
284  //actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
285  if (pet->IsPet() && (((Pet*)pet)->getPetType() == SUMMON_PET) && (pet != unit_target) && (urand(0, 100) < 10))
287  else
288  pet->SendPetAIReaction(guid1);
289 
290  if (unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->isPossessed())
291  {
292  // This is true if pet has no target or has target but targets differs.
293  if (pet->GetVictim() != unit_target)
294  {
295  pet->GetMotionMaster()->Clear();
296  if (pet->ToCreature()->IsAIEnabled)
297  pet->ToCreature()->AI()->AttackStart(unit_target);
298  }
299  }
300 
301  spell->prepare(&(spell->m_targets));
302  }
303  else
304  {
305  if (pet->isPossessed())
306  {
307  WorldPacket data(SMSG_CAST_FAILED, (4 + 1 + 1));
308  data << uint32(spellid) << uint8(2) << uint8(result);
309  switch (result)
310  {
312  data << uint32(spellInfo->RequiresSpellFocus);
313  break;
315  data << uint32(spellInfo->AreaId);
316  break;
317  default:
318  break;
319  }
320  SendPacket(&data);
321  }
322  else
323  pet->SendPetCastFail(spellid, result);
324 
325  if (!pet->ToCreature()->HasSpellCooldown(spellid))
326  pet->SendPetClearCooldown(spellid);
327 
328  spell->finish(false);
329  delete spell;
330 
331  // reset specific flags in case of spell fail. AI will reset other flags
332  if (pet->GetCharmInfo())
333  pet->GetCharmInfo()->SetIsCommandAttack(false);
334  }
335  break;
336  }
337  default:
338  sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.", flag, spellid);
339  }
340 }
342 {
343  DEBUG_LOG("WORLD: Received CMSG_PET_STOP_ATTACK");
344 
345  ObjectGuid petGuid;
346  recv_data >> petGuid;
347 
348  Unit* pet = ObjectAccessor::GetUnit(*_player, petGuid); // pet or controlled creature/player
349  if (!pet)
350  {
351  sLog.outError("HandlePetStopAttack: %s doesn't exist.", petGuid.GetString().c_str());
352  return;
353  }
354 
355  if (GetPlayer()->GetGUID() != pet->GetCharmerOrOwnerGUID())
356  {
357  sLog.outError("HandlePetStopAttack: %s isn't charm/pet of %s.", petGuid.GetString().c_str(), _player->GetGUIDLow());
358  return;
359  }
360 
361  if (!pet->IsAlive())
362  return;
363 
364  pet->AttackStop();
365 }
366 
368 {
369  sLog.outDetail("HandlePetNameQuery. CMSG_PET_NAME_QUERY");
370 
371  uint32 petnumber;
372  uint64 petguid;
373 
374  recv_data >> petnumber;
375  recv_data >> petguid;
376 
377  SendPetNameQuery(petguid, petnumber);
378 }
379 
381 {
383  if (!pet || !pet->GetCharmInfo() || pet->GetCharmInfo()->GetPetNumber() != petnumber)
384  return;
385 
386  std::string name = pet->GetName();
387 
388  WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (4 + 4 + name.size() + 1));
389  data << uint32(petnumber);
390  data << name.c_str();
392 
393  if (pet->IsPet() && ((Pet*)pet)->GetDeclinedNames())
394  {
395  data << uint8(1);
396  for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
397  data << ((Pet*)pet)->GetDeclinedNames()->name[i];
398  }
399  else
400  data << uint8(0);
401 
402  _player->GetSession()->SendPacket(&data);
403 }
404 
406 {
407  sLog.outDetail("HandlePetSetAction. CMSG_PET_SET_ACTION");
408 
409  uint64 petguid;
410  uint32 position;
411  uint16 spell_id;
412  uint16 act_state;
413  uint8 count;
414 
415  recv_data >> petguid;
416 
417  Unit* pet = ObjectAccessor::GetUnit(*_player, petguid);
418  if (!pet || pet != _player->GetFirstControlled())
419  {
420  sLog.outError("HandlePetSetAction: Unknown pet or pet owner.");
421  return;
422  }
423 
424  // pet can have action bar disabled
425  if (pet->IsPet() && ((Pet*)pet)->GetModeFlags() & PET_MODE_DISABLE_ACTIONS)
426  return;
427 
428  CharmInfo* charmInfo = pet->GetCharmInfo();
429  if (!charmInfo)
430  {
431  sLog.outError("WorldSession::HandlePetSetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId());
432  return;
433  }
434 
435  count = (recv_data.size() == 24) ? 2 : 1;
436  for (uint8 i = 0; i < count; i++)
437  {
438  recv_data >> position;
439  recv_data >> spell_id;
440  recv_data >> act_state;
441 
442  sLog.outDetail("Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X", _player->GetName(), position, spell_id, act_state);
443 
444  //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
445  if (!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_CAST) && spell_id && !pet->HasSpell(spell_id)))
446  {
447  //sign for autocast
448  if (act_state == ACT_ENABLED && spell_id)
449  {
450  if (pet->GetTypeId() == TYPEID_UNIT && pet->IsPet())
451  ((Pet*)pet)->ToggleAutocast(spell_id, true);
452  else
453  charmInfo->ToggleCreatureAutocast(spell_id, true);
454  }
455  //sign for no/turn off autocast
456  else if (act_state == ACT_DISABLED && spell_id)
457  {
458  if (pet->GetTypeId() == TYPEID_UNIT && pet->IsPet())
459  ((Pet*)pet)->ToggleAutocast(spell_id, false);
460  else
461  charmInfo->ToggleCreatureAutocast(spell_id, false);
462  }
463 
464  charmInfo->GetActionBarEntry(position)->Type = act_state;
465  charmInfo->GetActionBarEntry(position)->SpellOrAction = spell_id;
466  }
467  }
468 }
469 
471 {
472  sLog.outDetail("HandlePetRename. CMSG_PET_RENAME");
473 
474  uint64 petguid;
475  uint8 isdeclined;
476 
477  std::string name;
478  DeclinedName declinedname;
479 
480  recv_data >> petguid;
481  recv_data >> name;
482  recv_data >> isdeclined;
483 
484  Pet* pet = ObjectAccessor::FindPet(petguid);
485  // check it!
486  if (!pet || !pet->IsPet() || ((Pet*)pet)->getPetType() != HUNTER_PET ||
488  pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo())
489  return;
490 
491  if (!ObjectMgr::IsValidPetName(name))
492  {
494  return;
495  }
496 
497  if (sObjectMgr.IsReservedName(name))
498  {
500  return;
501  }
502 
503  pet->SetName(name);
504 
505  Unit* owner = pet->GetOwner();
506  if (owner && (owner->GetTypeId() == TYPEID_PLAYER) && owner->ToPlayer()->GetGroup())
508 
510 
511  if (isdeclined)
512  {
513  for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
514  recv_data >> declinedname.name[i];
515 
516  std::wstring wname;
517  Utf8toWStr(name, wname);
518  if (!ObjectMgr::CheckDeclinedNames(GetMainPartOfName(wname, 0), declinedname))
519  {
521  return;
522  }
523  }
524 
526  if (isdeclined)
527  {
528  for (int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
529  CharacterDatabase.escape_string(declinedname.name[i]);
530  CharacterDatabase.PExecute("DELETE FROM character_pet_declinedname WHERE owner = '%u' AND id = '%u'", _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber());
531  CharacterDatabase.PExecute("INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u','%u','%s','%s','%s','%s','%s')",
532  pet->GetCharmInfo()->GetPetNumber(), _player->GetGUIDLow(), declinedname.name[0].c_str(), declinedname.name[1].c_str(), declinedname.name[2].c_str(), declinedname.name[3].c_str(), declinedname.name[4].c_str());
533  }
534 
536  CharacterDatabase.PExecute("UPDATE character_pet SET name = '%s', renamed = '1' WHERE owner = '%u' AND id = '%u'", name.c_str(), _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber());
538 
540 }
541 
543 {
544  uint64 guid;
545  recv_data >> guid; //pet guid
546  sLog.outDetail("HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u", GUID_LOPART(guid));
547 
548  if (!_player->IsInWorld())
549  return;
550 
551  // pet/charmed
553  if (pet)
554  {
555  if (pet->IsPet())
556  {
557  if (pet->GetGUID() == _player->GetPetGUID())
558  {
559  uint32 feelty = pet->GetPower(POWER_HAPPINESS);
560  pet->SetPower(POWER_HAPPINESS , (feelty - 50000) > 0 ? (feelty - 50000) : 0);
561  }
562 
564  }
565  else if (pet->GetGUID() == _player->GetCharmGUID())
567  }
568 }
569 
571 {
572  sLog.outDetail("CMSG_PET_UNLEARN");
573  uint64 guid;
574  recvPacket >> guid;
575 
576  Pet* pet = _player->GetPet();
577 
578  if (!pet || pet->getPetType() != HUNTER_PET || pet->m_spells.size() <= 1)
579  return;
580 
581  if (guid != pet->GetGUID())
582  {
583  sLog.outError("HandlePetUnlearnOpcode.Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)), GetPlayer()->GetName());
584  return;
585  }
586 
587  CharmInfo* charmInfo = pet->GetCharmInfo();
588  if (!charmInfo)
589  {
590  sLog.outError("WorldSession::HandlePetUnlearnOpcode: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId());
591  return;
592  }
593 
594  uint32 cost = pet->resetTalentsCost();
595 
596  if (GetPlayer()->GetMoney() < cost)
597  {
599  return;
600  }
601 
602  for (PetSpellMap::iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end();)
603  {
604  uint32 spell_id = itr->first; // Pet::removeSpell can invalidate iterator at erase NEW spell
605  ++itr;
606  pet->removeSpell(spell_id);
607  }
608 
609  pet->SetTP(pet->getLevel() * (pet->GetLoyaltyLevel() - 1));
610 
611  for (uint8 i = 0; i < 10; i++)
612  {
613  if ((charmInfo->GetActionBarEntry(i)->SpellOrAction && charmInfo->GetActionBarEntry(i)->Type == ACT_ENABLED) || charmInfo->GetActionBarEntry(i)->Type == ACT_DISABLED)
614  charmInfo->GetActionBarEntry(i)->SpellOrAction = 0;
615  }
616 
617  // relearn pet passives
618  pet->LearnPetPassives();
619 
620  pet->m_resetTalentsTime = time(NULL);
621  pet->m_resetTalentsCost = cost;
622  GetPlayer()->ModifyMoney(-(int32)cost);
623 
625 }
626 
628 {
629  sLog.outDetail("CMSG_PET_SPELL_AUTOCAST");
630  uint64 guid;
631  uint16 spellid;
632  uint16 spellid2; //maybe second spell, automatically toggled off when first toggled on?
633  uint8 state; //1 for on, 0 for off
634  recvPacket >> guid >> spellid >> spellid2 >> state;
635 
636  if (!_player->GetGuardianPet() && !_player->GetCharm())
637  return;
638 
639  if (ObjectAccessor::FindPlayer(guid))
640  return;
641 
643 
644  if (!pet || (pet != _player->GetGuardianPet() && pet != _player->GetCharm()))
645  {
646  sLog.outError("HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)), GetPlayer()->GetName());
647  return;
648  }
649 
650  // do not add not learned spells/ passive spells
651  if (!pet->HasSpell(spellid) || !IsAutocastableSpell(spellid))
652  return;
653 
654  CharmInfo* charmInfo = pet->GetCharmInfo();
655  if (!charmInfo)
656  {
657  sLog.outError("WorldSession::HandlePetSpellAutocastOpcod: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId());
658  return;
659  }
660 
661  if (pet->IsPet())
662  ((Pet*)pet)->ToggleAutocast(spellid, state);
663  else
664  pet->GetCharmInfo()->ToggleCreatureAutocast(spellid, state);
665 
666  for (uint8 i = 0; i < 10; ++i)
667  {
668  if ((charmInfo->GetActionBarEntry(i)->Type == ACT_ENABLED || charmInfo->GetActionBarEntry(i)->Type == ACT_DISABLED) && spellid == charmInfo->GetActionBarEntry(i)->SpellOrAction)
669  charmInfo->GetActionBarEntry(i)->Type = state ? ACT_ENABLED : ACT_DISABLED;
670  }
671 }
672 
674 {
675  sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL");
676 
677  uint64 guid;
678  uint32 spellid;
679 
680  recvPacket >> guid >> spellid;
681 
682  // This opcode is also sent from charmed and possessed units (players and creatures)
683  if (!_player->GetGuardianPet() && !_player->GetCharm())
684  return;
685 
686  Unit* caster = ObjectAccessor::GetUnit(*_player, guid);
687 
688  if (!caster || (caster != _player->GetGuardianPet() && caster != _player->GetCharm()))
689  {
690  sLog.outError("HandlePetCastSpellOpcode: Pet %u isn't pet of player %s .", uint32(GUID_LOPART(guid)), GetPlayer()->GetName());
691  return;
692  }
693 
694  SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellid);
695  if (!spellInfo)
696  {
697  sLog.outError("WORLD: unknown PET spell id %i", spellid);
698  return;
699  }
700 
701  // do not cast not learned spells
702  if (!caster->HasSpell(spellid) || IsPassiveSpell(spellid))
703  return;
704 
705  if (spellInfo->StartRecoveryCategory > 0) //Check if spell is affected by GCD
706  if (caster->GetTypeId() == TYPEID_UNIT && caster->ToCreature()->GetGlobalCooldown() > 0)
707  {
708  caster->SendPetCastFail(spellid, SPELL_FAILED_NOT_READY);
709  return;
710  }
711 
712  SpellCastTargets targets;
713 
714  recvPacket >> targets.ReadForCaster(caster);
715 
717 
718  Spell* spell = new Spell(caster, spellInfo, false);
719  spell->m_targets = targets;
720 
721  SpellCastResult result = spell->CheckPetCast(NULL);
722  if (result == SPELL_CAST_OK)
723  {
724  if (caster->GetTypeId() == TYPEID_UNIT)
725  {
726  Creature* pet = caster->ToCreature();
727  pet->AddCreatureSpellCooldown(spellid);
728  if (pet->IsPet())
729  {
730  Pet* p = (Pet*)pet;
731  p->CheckLearning(spellid);
732  // 10% chance to play special pet attack talk, else growl
733  // actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
734  if (p->getPetType() == SUMMON_PET && (urand(0, 100) < 10))
736  else
737  pet->SendPetAIReaction(guid);
738  }
739  }
740 
741  spell->prepare(&(spell->m_targets));
742  }
743  else
744  {
745  caster->SendPetCastFail(spellid, result);
746  if (caster->GetTypeId() == TYPEID_PLAYER)
747  {
748  if (!caster->ToPlayer()->HasSpellCooldown(spellid))
749  caster->SendPetClearCooldown(spellid);
750  }
751  else
752  {
753  if (!caster->ToCreature()->HasSpellCooldown(spellid))
754  caster->SendPetClearCooldown(spellid);
755  }
756 
757  spell->finish(false);
758  delete spell;
759  }
760 }
761 
762 void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName* declinedName)
763 {
764  WorldPacket data(SMSG_PET_NAME_INVALID, 4 + name.size() + 1 + 1);
765  data << uint32(error);
766  data << name;
767  if (declinedName)
768  {
769  data << uint8(1);
770  for (uint32 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
771  data << declinedName->name[i];
772  }
773  else
774  data << uint8(0);
775  SendPacket(&data);
776 }
777 
void ClearInPetCombat()
Definition: Unit.cpp:9488
bool AttackStop()
Definition: Unit.cpp:7484
uint32 SpellOrAction
Definition: Unit.h:725
Group * GetGroup()
Definition: Player.h:2577
SpellCastTargetsReader ReadForCaster(Unit *caster)
Definition: Spell.h:86
uint64 GetCharmGUID() const
Definition: Unit.h:1370
orders pet to attack
Definition: Unit.h:770
bool Attack(Unit *victim, bool meleeAttack)
Definition: Unit.cpp:7390
const uint32 & GetUInt32Value(uint16 index) const
Definition: Object.h:234
Guardian * GetGuardianPet() const
Definition: Unit.cpp:7676
void HandlePetRename(WorldPacket &recv_data)
Definition: PetHandler.cpp:470
#define GUID_LOPART(x)
Definition: ObjectGuid.h:110
void SendPetAIReaction(uint64 guid)
Definition: Unit.cpp:11904
void MoveIdle(MovementSlot slot=MOTION_SLOT_ACTIVE)
time_t m_resetTalentsTime
Definition: Pet.h:260
bool IsPassiveSpell(uint32 spellId)
Definition: SpellMgr.cpp:278
void Clear(bool reset=true)
Definition: MotionMaster.h:145
bool BeginTransaction()
Definition: Database.cpp:533
void HandlePetNameQuery(WorldPacket &recv_data)
Definition: PetHandler.cpp:367
void SetIsFollowing(bool val)
Definition: Unit.cpp:13580
void SaveStayPosition()
Definition: Unit.cpp:13558
pet will not attack
Definition: Unit.h:760
SpellCastTargets m_targets
Definition: Spell.h:443
uint64 GetCharmerGUID() const
Definition: Unit.h:1362
bool HasSpellCooldown(uint32 spell_id) const
Definition: Player.h:1696
Definition: Unit.h:752
bool HasSpellCooldown(uint32 spell_id) const
Definition: Creature.cpp:2292
MotionMaster * GetMotionMaster()
Definition: Unit.h:1890
static Pet * FindPet(uint64)
void HandlePetCastSpellOpcode(WorldPacket &recvPacket)
Definition: PetHandler.cpp:673
pet will attack only if he or his owner is attacked
Definition: Unit.h:761
std::wstring GetMainPartOfName(std::wstring wname, uint32 declension)
Definition: Util.cpp:341
UnitActionBarEntry * GetActionBarEntry(uint8 index)
Definition: Unit.h:833
virtual bool HasSpell(uint32) const
Definition: Unit.h:1265
#define sLog
Log class singleton.
Definition: Log.h:187
Unit * getUnitTarget() const
Definition: Spell.h:118
#define PET_FOLLOW_DIST
void SetUInt32Value(uint16 index, uint32 value)
Definition: Object.cpp:779
ACE_INT32 int32
Definition: Define.h:67
unsigned long escape_string(char *to, const char *from, unsigned long length)
Definition: Database.cpp:212
void HandlePetUnlearnOpcode(WorldPacket &recvPacket)
Definition: PetHandler.cpp:570
void prepare(SpellCastTargets *targets, Aura *triggeredByAura=NULL)
Definition: Spell.cpp:2222
static Creature * GetCreatureOrPet(WorldObject const &, uint64)
Player * GetPlayer() const
Definition: WorldSession.h:104
uint32 GetGUIDLow() const
Definition: Object.h:166
Definition: Pet.h:28
Definition: Unit.h:439
#define MAX_DECLINED_NAME_CASES
Definition: Unit.h:728
void HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid, uint16 flag, uint64 guid2)
Definition: PetHandler.cpp:87
void ToggleCreatureAutocast(uint32 spellid, bool apply)
Definition: Unit.cpp:11383
bool Utf8toWStr(char const *utf8str, size_t csize, wchar_t *wstr, size_t &wsize)
Definition: Util.cpp:255
bool IsAIEnabled
Definition: Unit.h:1990
#define sObjectMgr
Definition: ObjectMgr.h:1285
void SendPacket(WorldPacket const *packet)
CharmInfo * GetCharmInfo()
Definition: Unit.h:1458
Unit * GetFirstControlled() const
Definition: Unit.cpp:7902
bool CommitTransaction()
Definition: Database.cpp:551
DBCStorage< SpellEntry > sSpellStore(SpellEntryfmt)
Player * ToPlayer()
Definition: Object.h:392
uint32 GetPower(Powers power) const
Definition: Unit.h:1096
void SetInFront(Unit const *target)
Definition: Unit.h:1675
uint32 RequiresSpellFocus
Definition: DBCStructure.h:690
uint8 getLevel() const
Definition: Unit.h:1057
uint64 GetCharmerOrOwnerGUID() const
Definition: Unit.h:1387
void SetCommandState(CommandStates st)
Definition: Unit.h:809
void ClearUnitState(uint32 f)
Definition: Unit.h:1034
uint8 GetTypeId() const
Definition: Object.h:210
Definition: Pet.h:27
void HandlePetAbandon(WorldPacket &recv_data)
Definition: PetHandler.cpp:542
ACE_UINT8 uint8
Definition: Define.h:73
void SendPetCastFail(uint32 spellid, SpellCastResult msg)
Definition: Unit.cpp:11842
bool IsCommandAttack()
Definition: Unit.cpp:13543
const bool & IsInWorld() const
Definition: Object.h:135
void finish(bool ok=true)
Definition: Spell.cpp:2963
Unit * GetCharm() const
Definition: Unit.cpp:7691
void PetSpellInitialize()
Definition: Player.cpp:17336
abandons the pet
Definition: Unit.h:771
uint32 GetPetNumber() const
Definition: Unit.h:803
void SetIsReturning(bool val)
Definition: Unit.cpp:13590
size_t size() const
Definition: ByteBuffer.h:336
bool IsAlive() const
Definition: Unit.h:1336
Unit * GetVictim() const
Definition: Unit.h:1013
void SetByteValue(uint16 index, uint8 offset, uint8 value)
Definition: Object.cpp:878
void SendPetNameInvalid(uint32 error, const std::string &name, DeclinedName *declinedName)
Definition: PetHandler.cpp:762
CreatureAI * AI() const
Definition: Creature.h:517
static Player * FindPlayer(uint64, bool force=false)
Player * GetOwner()
Definition: Pet.h:286
void LearnPetPassives()
Definition: Pet.cpp:1935
bool HasSpell(uint32 spellID) const override
Definition: Creature.cpp:2303
void RemovePet(Pet *pet, PetSaveMode mode, bool returnreagent=false)
Definition: Player.cpp:17139
uint32 EffectImplicitTargetA[MAX_SPELL_EFFECTS]
Definition: DBCStructure.h:731
uint32 GetGlobalCooldown() const
Definition: Creature.h:736
#define DEBUG_LOG(...)
Definition: Log.h:194
bool isPossessed() const
Definition: Unit.h:1438
uint32 GetLoyaltyLevel()
Definition: Pet.h:204
bool IsAutocastableSpell(uint32 spellId)
Definition: SpellMgr.cpp:291
void SendPetTalk(uint32 pettalk)
Definition: Unit.cpp:11865
void SetTP(int32 TP)
Definition: Pet.cpp:838
bool PExecute(const char *format,...) ATTR_PRINTF(2
Definition: Database.cpp:441
ReactStates
Pet&#39;s behavior.
Definition: Unit.h:758
void SendPetClearCooldown(uint32 spellid)
Definition: Unit.cpp:11892
void SetIsAtStay(bool val)
Definition: Unit.cpp:13570
void SendPetNameQuery(uint64 guid, uint32 petnumber)
Definition: PetHandler.cpp:380
uint64 GetOwnerGUID() const
Definition: Unit.h:1342
ControlList m_Controlled
Definition: Unit.h:1430
bool IsPet() const
Definition: Unit.h:1048
void SendBuyError(uint8 msg, Creature *pCreature, uint32 item, uint32 param)
Definition: Player.cpp:11541
void SetIsCommandAttack(bool val)
Definition: Unit.cpp:13538
const char * GetName() const
Definition: Object.h:704
void HandlePetStopAttack(WorldPacket &recv_data)
Definition: PetHandler.cpp:341
SpellCastResult CheckPetCast(Unit *target)
Definition: Spell.cpp:4737
PetSpellMap m_spells
Definition: Pet.h:247
ACE_UINT64 uint64
Definition: Define.h:70
uint64 GetPetGUID() const
Definition: Unit.h:1378
void HandlePetAction(WorldPacket &recv_data)
Definition: PetHandler.cpp:34
Unit * GetCharmerOrOwner() const
Definition: Unit.h:1410
orders pet to follow
Definition: Unit.h:769
virtual void setDeathState(DeathState s)
Definition: Unit.cpp:10114
Player * _player
Definition: WorldSession.h:730
uint32 AreaId
Definition: DBCStructure.h:771
Unit * GetOwner() const
Definition: Unit.cpp:7625
Creature * ToCreature()
Definition: Object.h:395
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition: Unit.cpp:3576
static bool CheckDeclinedNames(std::wstring mainpart, DeclinedName const &names)
Definition: ObjectMgr.cpp:6954
uint32 HasUnitTypeMask(uint32 mask) const
Definition: Unit.h:1044
void SetName(const std::string &newname)
Definition: Object.h:708
void SetPower(Powers power, uint32 val)
Definition: Unit.cpp:10997
static Unit * GetUnit(WorldObject const &, uint64 guid)
void SetGroupUpdateFlag(uint32 flag)
Definition: Player.h:2598
bool HasAuraType(AuraType auraType) const
Definition: Unit.cpp:832
SpellCastResult
uint32 GetEntry() const
Definition: Object.h:192
WorldSession * GetSession() const
Definition: Player.h:1944
uint32 resetTalentsCost() const
Definition: Pet.cpp:1686
DatabaseType CharacterDatabase
Accessor to the character database.
Definition: Main.cpp:54
void StopCastingCharm()
Definition: Player.cpp:17228
ACE_UINT16 uint16
Definition: Define.h:72
static bool IsValidPetName(const std::string &name)
Definition: ObjectMgr.cpp:6662
void HandlePetSpellAutocastOpcode(WorldPacket &recvPacket)
Definition: PetHandler.cpp:627
void HandlePetSetAction(WorldPacket &recv_data)
Definition: PetHandler.cpp:405
void ModifyMoney(int32 d)
Definition: Player.h:1514
ACE_UINT32 uint32
Definition: Define.h:71
uint32 Type
Definition: Unit.h:724
orders pet to stop moving
Definition: Unit.h:768
Pet * GetPet() const
Definition: Player.cpp:17121
uint32 m_resetTalentsCost
Definition: Pet.h:259
void removeSpell(uint16 spell_id)
Definition: Pet.cpp:1589
void AddCreatureSpellCooldown(uint32 spellid)
Definition: Creature.cpp:2247
Definition: Unit.h:908
void SetIsCommandFollow(bool val)
Definition: Unit.cpp:13548
void SetReactState(ReactStates st)
Definition: Creature.h:495
std::string name[MAX_DECLINED_NAME_CASES]
Definition: Unit.h:732
virtual void AttackStart(Unit *)
Definition: UnitAI.cpp:25
void SendUpdateToPlayer(Player *player)
Definition: Object.cpp:207
uint8 GetByteValue(uint16 index, uint8 offset) const
Definition: Object.h:252
Definition: Pet.h:146
PetType getPetType() const
Definition: Pet.h:155
virtual float GetFollowAngle() const
Definition: Unit.h:1971
void MoveFollow(Unit *target, float dist, float angle, MovementSlot slot=MOTION_SLOT_ACTIVE)
uint32 urand(uint32 min, uint32 max)
Definition: Util.cpp:33
const uint64 & GetGUID() const
Definition: Object.h:162
uint32 StartRecoveryCategory
Definition: DBCStructure.h:757
void CheckLearning(uint32 spellid)
Definition: Pet.cpp:1664
Definition: Spell.h:249