TrinityCore
Loading...
Searching...
No Matches
Pet.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 "Pet.h"
19#include "Common.h"
20#include "DatabaseEnv.h"
21#include "Formulas.h"
22#include "Group.h"
23#include "InstanceScript.h"
24#include "Log.h"
25#include "ObjectMgr.h"
26#include "PetPackets.h"
27#include "Player.h"
28#include "QueryHolder.h"
29#include "Spell.h"
30#include "SpellAuraEffects.h"
31#include "SpellAuras.h"
32#include "SpellHistory.h"
33#include "SpellMgr.h"
34#include "SpellPackets.h"
35#include "TalentPackets.h"
36#include "Unit.h"
37#include "Util.h"
38#include "WorldPacket.h"
39#include "WorldSession.h"
40#include "ZoneScript.h"
41
42#define PET_XP_FACTOR 0.05f
43
44Pet::Pet(Player* owner, PetType type) :
45 Guardian(nullptr, owner, true), m_usedTalentCount(0), m_removed(false),
46 m_happinessTimer(7500), m_petType(type), m_duration(0), m_auraRaidUpdateMask(0), m_loading(false)
47{
49
51 if (type == HUNTER_PET)
53
55 {
58 }
59
60 m_name = "Pet";
62}
63
64Pet::~Pet() = default;
65
67{
69 if (!IsInWorld())
70 {
75 if (ZoneScript* zoneScript = GetZoneScript() ? GetZoneScript() : GetInstanceScript())
76 zoneScript->OnCreatureCreate(this);
77 }
78
79 // Prevent stuck pets when zoning. Pets default to "follow" when added to world
80 // so we'll reset flags and let the AI handle things
82 {
85 GetCharmInfo()->SetIsAtStay(false);
88 }
89}
90
92{
94 if (IsInWorld())
95 {
99 }
100}
101
102std::pair<PetStable::PetInfo const*, PetSaveMode> Pet::GetLoadPetInfo(PetStable const& stable, uint32 petEntry, uint32 petnumber, bool current)
103{
104 if (petnumber)
105 {
106 // Known petnumber entry
107 if (stable.CurrentPet && stable.CurrentPet->PetNumber == petnumber)
108 return { &stable.CurrentPet.value(), PET_SAVE_AS_CURRENT };
109
110 for (std::size_t stableSlot = 0; stableSlot < stable.StabledPets.size(); ++stableSlot)
111 if (stable.StabledPets[stableSlot] && stable.StabledPets[stableSlot]->PetNumber == petnumber)
112 return { &stable.StabledPets[stableSlot].value(), PetSaveMode(PET_SAVE_FIRST_STABLE_SLOT + stableSlot) };
113
114 for (PetStable::PetInfo const& pet : stable.UnslottedPets)
115 if (pet.PetNumber == petnumber)
116 return { &pet, PET_SAVE_NOT_IN_SLOT };
117 }
118 else if (current)
119 {
120 // Current pet (slot 0)
121 if (stable.CurrentPet)
122 return { &stable.CurrentPet.value(), PET_SAVE_AS_CURRENT };
123 }
124 else if (petEntry)
125 {
126 // known petEntry entry (unique for summoned pet, but non unique for hunter pet (only from current or not stabled pets)
127 if (stable.CurrentPet && stable.CurrentPet->CreatureId == petEntry)
128 return { &stable.CurrentPet.value(), PET_SAVE_AS_CURRENT };
129
130 for (PetStable::PetInfo const& pet : stable.UnslottedPets)
131 if (pet.CreatureId == petEntry)
132 return { &pet, PET_SAVE_NOT_IN_SLOT };
133 }
134 else
135 {
136 // Any current or other non-stabled pet (for hunter "call pet")
137 if (stable.CurrentPet)
138 return { &stable.CurrentPet.value(), PET_SAVE_AS_CURRENT };
139
140 if (!stable.UnslottedPets.empty())
141 return { &stable.UnslottedPets.front(), PET_SAVE_NOT_IN_SLOT };
142 }
143
144 return { nullptr, PET_SAVE_AS_DELETED };
145}
146
148{
149public:
150 enum
151 {
156
157 MAX
158 };
159
161 {
162 SetSize(MAX);
163
165
166 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_DECLINED_NAME);
167 stmt->setUInt32(0, ownerGuid);
168 stmt->setUInt32(1, petNumber);
170
171 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_AURA);
172 stmt->setUInt32(0, petNumber);
173 SetPreparedQuery(AURAS, stmt);
174
175 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SPELL);
176 stmt->setUInt32(0, petNumber);
178
179 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PET_SPELL_COOLDOWN);
180 stmt->setUInt32(0, petNumber);
182 }
183};
184
185bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool current)
186{
187 m_loading = true;
188
189 PetStable* petStable = ASSERT_NOTNULL(owner->GetPetStable());
190
191 ObjectGuid::LowType ownerid = owner->GetGUID().GetCounter();
192 std::pair<PetStable::PetInfo const*, PetSaveMode> info = GetLoadPetInfo(*petStable, petEntry, petnumber, current);
193 PetStable::PetInfo const* petInfo = info.first;
194 PetSaveMode slot = info.second;
195 if (!petInfo)
196 {
197 m_loading = false;
198 return false;
199 }
200
201 // Don't try to reload the current pet
202 if (petStable->CurrentPet && owner->GetPet() && petStable->CurrentPet.value().PetNumber == petInfo->PetNumber)
203 return false;
204
205 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(petInfo->CreatedBySpellId);
206
207 bool isTemporarySummon = spellInfo && spellInfo->GetDuration() > 0;
208 if (current && isTemporarySummon)
209 return false;
210
211 if (petInfo->Type == HUNTER_PET)
212 {
213 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(petInfo->CreatureId);
214 if (!creatureInfo || !creatureInfo->IsTameable(owner->CanTameExoticPets()))
215 return false;
216 }
217
218 if (current && owner->IsPetNeedBeTemporaryUnsummoned())
219 {
221 return false;
222 }
223
224 Map* map = owner->GetMap();
225 if (!Create(map->GenerateLowGuid<HighGuid::Pet>(), map, owner->GetPhaseMask(), petInfo->CreatureId, petInfo->PetNumber))
226 return false;
227
228 setPetType(petInfo->Type);
229 SetFaction(owner->GetFaction());
231
232 if (IsCritter())
233 {
234 float px, py, pz;
236 Relocate(px, py, pz, owner->GetOrientation());
237
238 if (!IsPositionValid())
239 {
240 TC_LOG_ERROR("entities.pet", "Pet{} not loaded. Suggested coordinates isn't valid (X: {} Y: {})",
242 return false;
243 }
244
245 map->AddToMap(ToCreature());
246 return true;
247 }
248
250
251 SetDisplayId(petInfo->DisplayId);
253 uint8 petlevel = petInfo->Level;
255 SetName(petInfo->Name);
256
257 switch (getPetType())
258 {
259 case SUMMON_PET:
260 petlevel = owner->GetLevel();
262 ReplaceAllUnitFlags(UNIT_FLAG_PLAYER_CONTROLLED); // this enables popup window (pet dismiss, cancel)
263 break;
264 case HUNTER_PET:
269 ReplaceAllUnitFlags(UNIT_FLAG_PLAYER_CONTROLLED); // this enables popup window (pet abandon, cancel)
272 break;
273 default:
274 if (!IsPetGhoul())
275 TC_LOG_ERROR("entities.pet", "Pet have incorrect type ({}) for pet loading.", getPetType());
276 break;
277 }
278
279 SetPetNameTimestamp(uint32(GameTime::GetGameTime())); // cast can't be helped here
280 SetCreatorGUID(owner->GetGUID());
281
282 InitStatsForLevel(petlevel);
284
286
287 // Set pet's position after setting level, its size depends on it
288 float px, py, pz;
290 Relocate(px, py, pz, owner->GetOrientation());
291 if (!IsPositionValid())
292 {
293 TC_LOG_ERROR("entities.pet", "Pet {} not loaded. Suggested coordinates isn't valid (X: {} Y: {})",
295 return false;
296 }
297
298 SetReactState(petInfo->ReactState);
299 SetCanModifyStats(true);
300
301 if (getPetType() == SUMMON_PET && !current) //all (?) summon pets come with full health when called, but not when they are current
303 else
304 {
305 uint32 savedhealth = petInfo->Health;
306 uint32 savedmana = petInfo->Mana;
307 if (!savedhealth && getPetType() == HUNTER_PET)
309 else
310 {
311 SetHealth(savedhealth > GetMaxHealth() ? GetMaxHealth() : savedhealth);
312 SetPower(POWER_MANA, savedmana > GetMaxPower(POWER_MANA) ? GetMaxPower(POWER_MANA) : savedmana);
313 }
314 }
315
316 // set current pet as current
317 // 0=current
318 // 1..MAX_PET_STABLES in stable slot
319 // PET_SAVE_NOT_IN_SLOT(100) = not stable slot (summoning))
320 if (slot == PET_SAVE_NOT_IN_SLOT)
321 {
322 uint32 petInfoNumber = petInfo->PetNumber;
323 if (petStable->CurrentPet)
324 owner->RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT);
325
326 auto unslottedPetItr = std::find_if(petStable->UnslottedPets.begin(), petStable->UnslottedPets.end(), [&](PetStable::PetInfo const& unslottedPet)
327 {
328 return unslottedPet.PetNumber == petInfoNumber;
329 });
330 ASSERT(!petStable->CurrentPet);
331 ASSERT(unslottedPetItr != petStable->UnslottedPets.end());
332
333 petStable->CurrentPet = std::move(*unslottedPetItr);
334 petStable->UnslottedPets.erase(unslottedPetItr);
335
336 // old petInfo pointer is no longer valid, refresh it
337 petInfo = &petStable->CurrentPet.value();
338 }
339 else if (PET_SAVE_FIRST_STABLE_SLOT <= slot && slot <= PET_SAVE_LAST_STABLE_SLOT)
340 {
341 auto stabledPet = std::find_if(petStable->StabledPets.begin(), petStable->StabledPets.end(), [petnumber](Optional<PetStable::PetInfo> const& pet)
342 {
343 return pet && pet->PetNumber == petnumber;
344 });
345 ASSERT(stabledPet != petStable->StabledPets.end());
346
347 std::swap(*stabledPet, petStable->CurrentPet);
348
349 // old petInfo pointer is no longer valid, refresh it
350 petInfo = &petStable->CurrentPet.value();
351 }
352
353 // Send fake summon spell cast - this is needed for correct cooldown application for spells
354 // Example: 46584 - without this cooldown (which should be set always when pet is loaded) isn't set clientside
356 if (petInfo->CreatedBySpellId)
357 {
359 spellGo.Cast.CasterGUID = owner->GetGUID();
360 spellGo.Cast.CasterUnit = owner->GetGUID();
361 spellGo.Cast.SpellID = petInfo->CreatedBySpellId;
364 owner->SendMessageToSet(spellGo.Write(), true);
365 }
366
367 owner->SetMinion(this, true);
368
369 if (!isTemporarySummon)
371
372 map->AddToMap(ToCreature());
373
374 //set last used pet number (for use in BG's)
376 owner->ToPlayer()->SetLastPetNumber(petInfo->PetNumber);
377
378 owner->GetSession()->AddQueryHolderCallback(CharacterDatabase.DelayQueryHolder(std::make_shared<PetLoadQueryHolder>(ownerid, petInfo->PetNumber)))
379 .AfterComplete([this, owner, session = owner->GetSession(), isTemporarySummon, current, lastSaveTime = petInfo->LastSaveTime](SQLQueryHolderBase const& holder)
380 {
381 if (session->GetPlayer() != owner || owner->GetPet() != this)
382 return;
383
384 // passing previous checks ensure that 'this' is still valid
385 if (m_removed)
386 return;
387
388 InitTalentForLevel(); // set original talents points before spell loading
389
390 uint32 timediff = uint32(GameTime::GetGameTime() - lastSaveTime);
391 _LoadAuras(holder.GetPreparedResult(PetLoadQueryHolder::AURAS), timediff);
392
393 // load action bar, if data broken will fill later by default spells.
394 if (!isTemporarySummon)
395 {
396 _LoadSpells(holder.GetPreparedResult(PetLoadQueryHolder::SPELLS));
397 InitTalentForLevel(); // re-init to check talent count
398 GetSpellHistory()->LoadFromDB<Pet>(holder.GetPreparedResult(PetLoadQueryHolder::COOLDOWNS));
399 LearnPetPassives();
400 InitLevelupSpellsForLevel();
401 if (GetMap()->IsBattleArena())
402 RemoveArenaAuras();
403
404 CastPetAuras(current);
405 }
406
407 CleanupActionBar(); // remove unknown spells from action bar after load
408
409 TC_LOG_DEBUG("entities.pet", "New Pet has {}", GetGUID().ToString());
410
411 owner->PetSpellInitialize();
412
413 if (owner->GetGroup())
415
416 owner->SendTalentsInfoData(true);
417
418 if (getPetType() == HUNTER_PET)
419 {
421 {
422 m_declinedname = std::make_unique<DeclinedName>();
423 Field* fields = result->Fetch();
424 for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
425 m_declinedname->name[i] = fields[i].GetString();
426 }
427 }
428
429 // must be after SetMinion (owner guid check)
431 m_loading = false;
432 });
433
434 return true;
435}
436
438{
439 if (!GetEntry())
440 return;
441
442 // save only fully controlled creature
443 if (!isControlled())
444 return;
445
446 // not save not player pets
447 if (!GetOwnerGUID().IsPlayer())
448 return;
449
450 Player* owner = GetOwner();
451
452 // not save pet as current if another pet temporary unsummoned
455 {
456 // pet will lost anyway at restore temporary unsummoned
457 if (getPetType() == HUNTER_PET)
458 return;
459
460 // for warlock case
462 }
463
464 uint32 curhealth = GetHealth();
465 uint32 curmana = GetPower(POWER_MANA);
466
467 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
468 // save auras before possibly removing them
469 _SaveAuras(trans);
470
471 // stable and not in slot saves
472 if (mode > PET_SAVE_AS_CURRENT)
474
475 _SaveSpells(trans);
476 GetSpellHistory()->SaveToDB<Pet>(trans);
477 CharacterDatabase.CommitTransaction(trans);
478
479 // current/stable/not_in_slot
480 if (mode >= PET_SAVE_AS_CURRENT)
481 {
483 trans = CharacterDatabase.BeginTransaction();
484 // remove current data
485
488 trans->Append(stmt);
489
490 // prevent existence another hunter pet in PET_SAVE_AS_CURRENT and PET_SAVE_NOT_IN_SLOT
492 {
493 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_BY_SLOT);
494 stmt->setUInt32(0, ownerLowGUID);
497 trans->Append(stmt);
498 }
499
500 // save pet
501 std::string actionBar = GenerateActionBarData();
502
503 ASSERT(owner->GetPetStable()->CurrentPet && owner->GetPetStable()->CurrentPet->PetNumber == m_charmInfo->GetPetNumber());
504 FillPetInfo(&owner->GetPetStable()->CurrentPet.value());
505
506 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET);
508 stmt->setUInt32(1, GetEntry());
509 stmt->setUInt32(2, ownerLowGUID);
510 stmt->setUInt32(3, GetNativeDisplayId());
511 stmt->setUInt8(4, GetLevel());
513 stmt->setUInt8(6, GetReactState());
514 stmt->setUInt8(7, mode);
515 stmt->setString(8, m_name);
517 stmt->setUInt32(10, curhealth);
518 stmt->setUInt32(11, curmana);
520 stmt->setString(13, actionBar);
521 stmt->setUInt32(14, GameTime::GetGameTime());
523 stmt->setUInt8(16, getPetType());
524 trans->Append(stmt);
525
526 CharacterDatabase.CommitTransaction(trans);
527 }
528 // delete
529 else
530 {
533 }
534}
535
537{
538 petInfo->PetNumber = m_charmInfo->GetPetNumber();
539 petInfo->CreatureId = GetEntry();
540 petInfo->DisplayId = GetNativeDisplayId();
541 petInfo->Level = GetLevel();
543 petInfo->ReactState = GetReactState();
544 petInfo->Name = GetName();
546 petInfo->Health = GetHealth();
547 petInfo->Mana = GetPower(POWER_MANA);
549 petInfo->ActionBar = GenerateActionBarData();
552 petInfo->Type = getPetType();
553}
554
556{
557 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
558
560 stmt->setUInt32(0, guidlow);
561 trans->Append(stmt);
562
563 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_DECLINEDNAME);
564 stmt->setUInt32(0, guidlow);
565 trans->Append(stmt);
566
567 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PET_AURAS);
568 stmt->setUInt32(0, guidlow);
569 trans->Append(stmt);
570
571 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PET_SPELLS);
572 stmt->setUInt32(0, guidlow);
573 trans->Append(stmt);
574
575 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PET_SPELL_COOLDOWNS);
576 stmt->setUInt32(0, guidlow);
577 trans->Append(stmt);
578
579 CharacterDatabase.CommitTransaction(trans);
580}
581
582void Pet::setDeathState(DeathState s) // overwrite virtual Creature::setDeathState and Unit::setDeathState
583{
585 if (getDeathState() == CORPSE)
586 {
587 if (getPetType() == HUNTER_PET)
588 {
589 // pet corpse non lootable and non skinnable
592
593 // lose happiness when died and not in BG/Arena
594 if (!GetMap()->IsBattlegroundOrArena())
596
597 //SetUnitFlag(UNIT_FLAG_STUNNED);
598 }
599 }
600 else if (getDeathState() == ALIVE)
601 {
602 //RemoveUnitFlag(UNIT_FLAG_STUNNED);
603 CastPetAuras(true);
604 }
605}
606
608{
609 if (m_removed) // pet already removed, just wait in remove queue, no updates
610 return;
611
612 if (m_loading)
613 return;
614
615 switch (m_deathState)
616 {
617 case CORPSE:
618 {
620 {
621 Remove(PET_SAVE_NOT_IN_SLOT); //hunters' pets never get removed because of death, NEVER!
622 return;
623 }
624 break;
625 }
626 case ALIVE:
627 {
628 // unsummon pet that lost owner
629 Player* owner = GetOwner();
630 if ((!IsWithinDistInMap(owner, GetMap()->GetVisibilityRange()) && !isPossessed()) || (isControlled() && !owner->GetPetGUID()))
631 //if (!owner || (!IsWithinDistInMap(owner, GetMap()->GetVisibilityDistance()) && (owner->GetCharmGUID() && (owner->GetCharmGUID() != GetGUID()))) || (isControlled() && !owner->GetPetGUID()))
632 {
634 return;
635 }
636
637 if (isControlled())
638 {
639 if (owner->GetPetGUID() != GetGUID())
640 {
641 TC_LOG_ERROR("entities.pet", "Pet {} is not pet of owner {}, removed", GetEntry(), GetOwner()->GetName());
642 ASSERT(getPetType() != HUNTER_PET, "Unexpected unlinked pet found for owner %s", owner->GetSession()->GetPlayerInfo().c_str());
644 return;
645 }
646 }
647
648 if (m_duration > 0)
649 {
650 if (uint32(m_duration) > diff)
651 m_duration -= diff;
652 else
653 {
655 return;
656 }
657 }
658
659 //regenerate focus for hunter pets or energy for deathknight's ghoul
661 {
662 if (m_focusRegenTimer > diff)
663 m_focusRegenTimer -= diff;
664 else
665 {
666 switch (GetPowerType())
667 {
668 case POWER_FOCUS:
672
673 // Reset if large diff (lag) causes focus to get 'stuck'
676
677 break;
678
679 // in creature::update
680 //case POWER_ENERGY:
681 // Regenerate(POWER_ENERGY);
682 // m_regenTimer += CREATURE_REGEN_INTERVAL - diff;
683 // if (!m_regenTimer) ++m_regenTimer;
684 // break;
685 default:
687 break;
688 }
689 }
690 }
691
692 if (getPetType() != HUNTER_PET)
693 break;
694
695 if (m_happinessTimer <= diff)
696 {
698 m_happinessTimer = 7500;
699 }
700 else
701 m_happinessTimer -= diff;
702
703 break;
704 }
705 default:
706 break;
707 }
708 Creature::Update(diff);
709}
710
712{
713 uint32 curValue = GetPower(POWER_HAPPINESS);
714 if (curValue <= 0)
715 return;
716 int32 addvalue = 670; //value is 70/35/17/8/4 (per min) * 1000 / 8 (timer 7.5 secs)
717 if (IsInCombat()) //we know in combat happiness fades faster, multiplier guess
718 addvalue = int32(addvalue * 1.5f);
719 ModifyPower(POWER_HAPPINESS, -addvalue);
720}
721
723{
725 return UNHAPPY;
727 return HAPPY;
728 else
729 return CONTENT;
730}
731
732void Pet::Remove(PetSaveMode mode, bool returnreagent)
733{
734 GetOwner()->RemovePet(this, mode, returnreagent);
735}
736
738{
739 if (getPetType() != HUNTER_PET)
740 return;
741
742 if (xp < 1)
743 return;
744
745 if (!IsAlive())
746 return;
747
748 uint8 maxlevel = std::min((uint8)sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL), GetOwner()->GetLevel());
749 uint8 petlevel = GetLevel();
750
751 // If pet is detected to be at, or above(?) the players level, don't hand out XP
752 if (petlevel >= maxlevel)
753 return;
754
757 uint32 newXP = curXP + xp;
758
759 // Check how much XP the pet should receive, and hand off have any left from previous levelups
760 while (newXP >= nextLvlXP && petlevel < maxlevel)
761 {
762 // Subtract newXP from amount needed for nextlevel, and give pet the level
763 newXP -= nextLvlXP;
764 ++petlevel;
765
766 GivePetLevel(petlevel);
767
769 }
770 // Not affected by special conditions - give it new XP
771 SetPetExperience(petlevel < maxlevel ? newXP : 0);
772}
773
775{
776 if (!level || level == GetLevel())
777 return;
778
779 if (getPetType() == HUNTER_PET)
780 {
783 }
784
785 InitStatsForLevel(level);
788}
789
791{
792 ASSERT(creature);
793
794 if (!CreateBaseAtTamed(creature->GetCreatureTemplate(), creature->GetMap(), creature->GetPhaseMask()))
795 return false;
796
797 Relocate(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetOrientation());
798
799 if (!IsPositionValid())
800 {
801 TC_LOG_ERROR("entities.pet", "Pet {} not created base at creature. Suggested coordinates isn't valid (X: {} Y: {})",
803 return false;
804 }
805
806 CreatureTemplate const* cinfo = GetCreatureTemplate();
807 if (!cinfo)
808 {
809 TC_LOG_ERROR("entities.pet", "CreateBaseAtCreature() failed, creatureInfo is missing!");
810 return false;
811 }
812
813 SetDisplayId(creature->GetDisplayId());
814
815 if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family))
816 SetName(cFamily->Name[sWorld->GetDefaultDbcLocale()]);
817 else
818 SetName(creature->GetNameForLocaleIdx(sObjectMgr->GetDBCLocaleIndex()));
819
820 return true;
821}
822
824{
825 if (!CreateBaseAtTamed(cinfo, owner->GetMap(), owner->GetPhaseMask()))
826 return false;
827
828 if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family))
829 SetName(cFamily->Name[sWorld->GetDefaultDbcLocale()]);
830
831 Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), owner->GetOrientation());
832
833 return true;
834}
835
836bool Pet::CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map, uint32 phaseMask)
837{
838 TC_LOG_DEBUG("entities.pet", "Pet::CreateBaseForTamed");
839 if (!Create(map->GenerateLowGuid<HighGuid::Pet>(), map, phaseMask, cinfo->Entry, sObjectMgr->GeneratePetNumber()))
840 return false;
841
843 SetPower(POWER_HAPPINESS, 166500);
848
849 if (cinfo->type == CREATURE_TYPE_BEAST)
850 {
855 }
856
857 return true;
858}
859
862{
863 CreatureTemplate const* cinfo = GetCreatureTemplate();
864 ASSERT(cinfo);
865
866 SetLevel(petlevel);
867
868 //Determine pet type
869 PetType petType = MAX_PET_TYPE;
870 if (IsPet() && GetOwner()->GetTypeId() == TYPEID_PLAYER)
871 {
873 || GetOwner()->GetClass() == CLASS_SHAMAN // Fire Elemental
874 || GetOwner()->GetClass() == CLASS_DEATH_KNIGHT) // Risen Ghoul
875 {
876 petType = SUMMON_PET;
877 }
878 else if (GetOwner()->GetClass() == CLASS_HUNTER)
879 {
880 petType = HUNTER_PET;
882 }
883 else
884 {
885 TC_LOG_ERROR("entities.pet", "Unknown type pet {} is summoned by player class {}",
886 GetEntry(), GetOwner()->GetClass());
887 }
888 }
889
890 uint32 creature_ID = (petType == HUNTER_PET) ? 1 : cinfo->Entry;
891
893
894 SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(petlevel * 50));
895
899
900 SetModCastingSpeed(1.0f);
901
902 //scale
904
905 // Resistance
906 // Hunters pet should not inherit resistances from creature_template, they have separate auras for that
907 if (!IsHunterPet())
908 for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
910
911 // Health, Mana or Power, Armor
912 PetLevelInfo const* pInfo = sObjectMgr->GetPetLevelInfo(creature_ID, petlevel);
913 if (pInfo) // exist in DB
914 {
915 SetCreateHealth(pInfo->health);
916 SetCreateMana(pInfo->mana);
917
918 if (pInfo->armor > 0)
920
921 for (uint8 stat = 0; stat < MAX_STATS; ++stat)
922 SetCreateStat(Stats(stat), float(pInfo->stats[stat]));
923 }
924 else // not exist in DB, use some default fake data
925 {
926 // remove elite bonuses included in DB values
927 CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(petlevel, cinfo->unit_class);
928 float healthmod = _GetHealthMod(cinfo->rank);
929 uint32 basehp = stats->GenerateHealth(cinfo);
930 uint32 health = uint32(basehp * healthmod);
931 uint32 mana = stats->GenerateMana(cinfo);
932
933 SetCreateHealth(health);
934 SetCreateMana(mana);
940 }
941
942 // Power
943 if (petType == HUNTER_PET) // Hunter pets have focus
945 else if (IsPetGhoul() || IsRisenAlly()) // DK pets have energy
946 {
949 }
950 else
952
953 // Damage
955 switch (petType)
956 {
957 case SUMMON_PET:
958 {
959 // the damage bonus used for pets is either fire or shadow damage, whatever is higher
962 int32 val = (fire > shadow) ? fire : shadow;
963 if (val < 0)
964 val = 0;
965
966 SetBonusDamage(val * 0.15f);
967
968 if (pInfo)
969 {
972 }
973 else
974 {
975 SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
976 SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
977 }
978
979 //SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, float(cinfo->attackpower));
980 break;
981 }
982 case HUNTER_PET:
983 {
985 //these formula may not be correct; however, it is designed to be close to what it should be
986 //this makes dps 0.5 of pets level
987 SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
988 //damage range is then petlevel / 2
989 SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
990 //damage is increased afterwards as strength and pet scaling modify attack power
991 break;
992 }
993 default:
994 {
995 switch (GetEntry())
996 {
997 case 510: // mage Water Elemental
998 {
1000 break;
1001 }
1002 case 1964: //force of nature
1003 {
1004 if (!pInfo)
1005 SetCreateHealth(30 + 30*petlevel);
1006 float bonusDmg = GetOwner()->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_NATURE) * 0.15f;
1007 SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel * 2.5f - (petlevel / 2) + bonusDmg));
1008 SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel * 2.5f + (petlevel / 2) + bonusDmg));
1009 break;
1010 }
1011 case 15352: //earth elemental 36213
1012 {
1013 if (!pInfo)
1014 SetCreateHealth(100 + 120*petlevel);
1015 SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
1016 SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
1017 break;
1018 }
1019 case 15438: //fire elemental
1020 {
1021 if (!pInfo)
1022 {
1023 SetCreateHealth(40*petlevel);
1024 SetCreateMana(28 + 10*petlevel);
1025 }
1027 SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel * 4 - petlevel));
1028 SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel * 4 + petlevel));
1029 break;
1030 }
1031 case 19668: // Shadowfiend
1032 {
1033 if (!pInfo)
1034 {
1035 SetCreateMana(28 + 10*petlevel);
1036 SetCreateHealth(28 + 30*petlevel);
1037 }
1039 SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float((petlevel * 4 - petlevel) + bonus_dmg));
1040 SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float((petlevel * 4 + petlevel) + bonus_dmg));
1041
1042 break;
1043 }
1044 case 19833: //Snake Trap - Venomous Snake
1045 {
1046 SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float((petlevel / 2) - 25));
1047 SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float((petlevel / 2) - 18));
1048 break;
1049 }
1050 case 19921: //Snake Trap - Viper
1051 {
1052 SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel / 2 - 10));
1053 SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel / 2));
1054 break;
1055 }
1056 case 29264: // Feral Spirit
1057 {
1058 if (!pInfo)
1059 SetCreateHealth(30*petlevel);
1060
1061 // wolf attack speed is 1.5s
1063
1064 SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float((petlevel * 4 - petlevel)));
1065 SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float((petlevel * 4 + petlevel)));
1066
1067 SetStatFlatModifier(UNIT_MOD_ARMOR, BASE_VALUE, float(GetOwner()->GetArmor()) * 0.35f); // Bonus Armor (35% of player armor)
1068 SetStatFlatModifier(UNIT_MOD_STAT_STAMINA, BASE_VALUE, float(GetOwner()->GetStat(STAT_STAMINA)) * 0.3f); // Bonus Stamina (30% of player stamina)
1069 if (!HasAura(58877))//prevent apply twice for the 2 wolves
1070 AddAura(58877, this);//Spirit Hunt, passive, Spirit Wolves' attacks heal them and their master for 150% of damage done.
1071 break;
1072 }
1073 case 31216: // Mirror Image
1074 {
1077 if (!pInfo)
1078 {
1079 SetCreateMana(28 + 30*petlevel);
1080 SetCreateHealth(28 + 10*petlevel);
1081 }
1082 break;
1083 }
1084 case 27829: // Ebon Gargoyle
1085 {
1086 if (!pInfo)
1087 {
1088 SetCreateMana(28 + 10*petlevel);
1089 SetCreateHealth(28 + 30*petlevel);
1090 }
1092 SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - (petlevel / 4)));
1093 SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel + (petlevel / 4)));
1094 break;
1095 }
1096 case 28017: // Bloodworms
1097 {
1098 SetCreateHealth(4 * petlevel);
1100 SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float(petlevel - 30 - (petlevel / 4)));
1101 SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float(petlevel - 30 + (petlevel / 4)));
1102 break;
1103 }
1104 default:
1105 {
1106 /* ToDo: Check what 5f5d2028 broke/fixed and how much of Creature::UpdateLevelDependantStats()
1107 * should be copied here (or moved to another method or if that function should be called here
1108 * or not just for this default case)
1109 */
1110 CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(petlevel, cinfo->unit_class);
1111 float basedamage = stats->GenerateBaseDamage(cinfo);
1112
1113 float weaponBaseMinDamage = basedamage;
1114 float weaponBaseMaxDamage = basedamage * 1.5f;
1115
1116 SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, weaponBaseMinDamage);
1117 SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, weaponBaseMaxDamage);
1118 break;
1119 }
1120 }
1121 break;
1122 }
1123 }
1124
1126
1127 SetFullHealth();
1129 return true;
1130}
1131
1132bool Pet::HaveInDiet(ItemTemplate const* item) const
1133{
1134 if (!item->FoodType)
1135 return false;
1136
1137 CreatureTemplate const* cInfo = GetCreatureTemplate();
1138 if (!cInfo)
1139 return false;
1140
1141 CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->family);
1142 if (!cFamily)
1143 return false;
1144
1145 uint32 diet = cFamily->PetFoodMask;
1146 uint32 FoodMask = 1 << (item->FoodType-1);
1147 return (diet & FoodMask) != 0;
1148}
1149
1151{
1152 // -5 or greater food level
1153 if (GetLevel() <= itemlevel + 5) //possible to feed level 60 pet with level 55 level food for full effect
1154 return 35000;
1155 // -10..-6
1156 else if (GetLevel() <= itemlevel + 10) //pure guess, but sounds good
1157 return 17000;
1158 // -14..-11
1159 else if (GetLevel() <= itemlevel + 14) //level 55 food gets green on 70, makes sense to me
1160 return 8000;
1161 // -15 or less
1162 else
1163 return 0; //food too low level
1164}
1165
1167{
1168 if (result)
1169 {
1170 do
1171 {
1172 Field* fields = result->Fetch();
1173
1174 addSpell(fields[0].GetUInt32(), ActiveStates(fields[1].GetUInt8()), PETSPELL_UNCHANGED);
1175 }
1176 while (result->NextRow());
1177 }
1178}
1179
1181{
1182 for (PetSpellMap::iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next)
1183 {
1184 ++next;
1185
1186 // prevent saving family passives to DB
1187 if (itr->second.type == PETSPELL_FAMILY)
1188 continue;
1189
1191
1192 switch (itr->second.state)
1193 {
1194 case PETSPELL_REMOVED:
1195 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PET_SPELL_BY_SPELL);
1196 stmt->setUInt32(0, m_charmInfo->GetPetNumber());
1197 stmt->setUInt32(1, itr->first);
1198 trans->Append(stmt);
1199
1200 m_spells.erase(itr);
1201 continue;
1202 case PETSPELL_CHANGED:
1203 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PET_SPELL_BY_SPELL);
1204 stmt->setUInt32(0, m_charmInfo->GetPetNumber());
1205 stmt->setUInt32(1, itr->first);
1206 trans->Append(stmt);
1207
1208 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET_SPELL);
1209 stmt->setUInt32(0, m_charmInfo->GetPetNumber());
1210 stmt->setUInt32(1, itr->first);
1211 stmt->setUInt8(2, itr->second.active);
1212 trans->Append(stmt);
1213
1214 break;
1215 case PETSPELL_NEW:
1216 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET_SPELL);
1217 stmt->setUInt32(0, m_charmInfo->GetPetNumber());
1218 stmt->setUInt32(1, itr->first);
1219 stmt->setUInt8(2, itr->second.active);
1220 trans->Append(stmt);
1221 break;
1222 case PETSPELL_UNCHANGED:
1223 continue;
1224 }
1225 itr->second.state = PETSPELL_UNCHANGED;
1226 }
1227}
1228
1230{
1231 TC_LOG_DEBUG("entities.pet", "Loading auras for pet {}", GetGUID().ToString());
1232
1233 ObjectGuid casterGuid, itemGuid;
1234 if (auraResult)
1235 {
1236 do
1237 {
1238 Field* fields = auraResult->Fetch();
1239 // NULL guid stored - pet is the caster of the spell - see Pet::_SaveAuras
1240 casterGuid.SetRawValue(fields[0].GetUInt64());
1241 if (casterGuid.IsEmpty())
1242 casterGuid = GetGUID();
1243
1244 AuraKey key{ casterGuid, itemGuid, fields[1].GetUInt32(), fields[2].GetUInt8() };
1245 AuraLoadEffectInfo info;
1246 uint8 recalculateMask = fields[3].GetUInt8();
1247 uint8 stackCount = fields[4].GetUInt8();
1248 info.Amounts[0] = fields[5].GetInt32();
1249 info.Amounts[1] = fields[6].GetInt32();
1250 info.Amounts[2] = fields[7].GetInt32();
1251 info.BaseAmounts[0] = fields[8].GetInt32();
1252 info.BaseAmounts[1] = fields[9].GetInt32();
1253 info.BaseAmounts[2] = fields[10].GetInt32();
1254 int32 maxDuration = fields[11].GetInt32();
1255 int32 remainTime = fields[12].GetInt32();
1256 uint8 remainCharges = fields[13].GetUInt8();
1257 float critChance = fields[14].GetFloat();
1258 bool applyResilience = fields[15].GetBool();
1259
1260 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(key.SpellId);
1261 if (!spellInfo)
1262 {
1263 TC_LOG_ERROR("entities.pet", "Unknown aura (spellid {}), ignore.", key.SpellId);
1264 continue;
1265 }
1266
1267 // negative effects should continue counting down after logout
1268 if (remainTime != -1 && (!spellInfo->IsPositive() || spellInfo->HasAttribute(SPELL_ATTR4_FADES_WHILE_LOGGED_OUT)))
1269 {
1270 if (remainTime/IN_MILLISECONDS <= int32(timediff))
1271 continue;
1272
1273 remainTime -= timediff*IN_MILLISECONDS;
1274 }
1275
1276 // prevent wrong values of remainCharges
1277 if (spellInfo->ProcCharges)
1278 {
1279 // we have no control over the order of applying auras and modifiers allow auras
1280 // to have more charges than value in SpellInfo
1281 if (remainCharges <= 0/* || remainCharges > spellproto->procCharges*/)
1282 remainCharges = spellInfo->ProcCharges;
1283 }
1284 else
1285 remainCharges = 0;
1286
1287 AuraCreateInfo createInfo(spellInfo, key.EffectMask, this);
1288 createInfo
1289 .SetCasterGUID(casterGuid)
1290 .SetBaseAmount(info.BaseAmounts.data());
1291
1292 if (Aura* aura = Aura::TryCreate(createInfo))
1293 {
1294 if (!aura->CanBeSaved())
1295 {
1296 aura->Remove();
1297 continue;
1298 }
1299
1300 aura->SetLoadedState(maxDuration, remainTime, remainCharges, stackCount, recalculateMask, critChance, applyResilience, info.Amounts.data());
1301 aura->ApplyForTargets();
1302 TC_LOG_DEBUG("entities.pet", "Added aura spellid {}, effectmask {}", spellInfo->Id, key.EffectMask);
1303 }
1304 }
1305 while (auraResult->NextRow());
1306 }
1307}
1308
1310{
1312 stmt->setUInt32(0, m_charmInfo->GetPetNumber());
1313 trans->Append(stmt);
1314
1315 for (AuraMap::const_iterator itr = m_ownedAuras.begin(); itr != m_ownedAuras.end(); ++itr)
1316 {
1317 // check if the aura has to be saved
1318 if (!itr->second->CanBeSaved() || IsPetAura(itr->second))
1319 continue;
1320
1321 Aura* aura = itr->second;
1322
1323 std::array<int32, MAX_SPELL_EFFECTS> damage = { };
1324 std::array<int32, MAX_SPELL_EFFECTS> baseDamage = { };
1325 uint8 effMask = 0;
1326 uint8 recalculateMask = 0;
1327 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
1328 {
1329 if (AuraEffect const* effect = aura->GetEffect(i))
1330 {
1331 baseDamage[i] = effect->GetBaseAmount();
1332 damage[i] = effect->GetAmount();
1333 effMask |= 1 << i;
1334 if (effect->CanBeRecalculated())
1335 recalculateMask |= 1 << i;
1336 }
1337 }
1338
1339 // don't save guid of caster in case we are caster of the spell - guid for pet is generated every pet load, so it won't match saved guid anyways
1340 ObjectGuid casterGUID = (itr->second->GetCasterGUID() == GetGUID()) ? ObjectGuid::Empty : itr->second->GetCasterGUID();
1341
1342 uint8 index = 0;
1343
1344 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET_AURA);
1345 stmt->setUInt32(index++, m_charmInfo->GetPetNumber());
1346 stmt->setUInt64(index++, casterGUID.GetRawValue());
1347 stmt->setUInt32(index++, itr->second->GetId());
1348 stmt->setUInt8(index++, effMask);
1349 stmt->setUInt8(index++, recalculateMask);
1350 stmt->setUInt8(index++, itr->second->GetStackAmount());
1351 stmt->setInt32(index++, damage[0]);
1352 stmt->setInt32(index++, damage[1]);
1353 stmt->setInt32(index++, damage[2]);
1354 stmt->setInt32(index++, baseDamage[0]);
1355 stmt->setInt32(index++, baseDamage[1]);
1356 stmt->setInt32(index++, baseDamage[2]);
1357 stmt->setInt32(index++, itr->second->GetMaxDuration());
1358 stmt->setInt32(index++, itr->second->GetDuration());
1359 stmt->setUInt8(index++, itr->second->GetCharges());
1360 stmt->setFloat(index++, itr->second->GetCritChance());
1361 stmt->setBool (index++, itr->second->CanApplyResilience());
1362
1363 trans->Append(stmt);
1364 }
1365}
1366
1367bool Pet::addSpell(uint32 spellId, ActiveStates active /*= ACT_DECIDE*/, PetSpellState state /*= PETSPELL_NEW*/, PetSpellType type /*= PETSPELL_NORMAL*/)
1368{
1369 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
1370 if (!spellInfo)
1371 {
1372 // do pet spell book cleanup
1373 if (state == PETSPELL_UNCHANGED) // spell load case
1374 {
1375 TC_LOG_ERROR("entities.pet", "Pet::addSpell: Non-existed in SpellStore spell #{} request, deleting for all pets in `pet_spell`.", spellId);
1376
1378
1379 stmt->setUInt32(0, spellId);
1380
1381 CharacterDatabase.Execute(stmt);
1382 }
1383 else
1384 TC_LOG_ERROR("entities.pet", "Pet::addSpell: Non-existed in SpellStore spell #{} request.", spellId);
1385
1386 return false;
1387 }
1388
1389 PetSpellMap::iterator itr = m_spells.find(spellId);
1390 if (itr != m_spells.end())
1391 {
1392 if (itr->second.state == PETSPELL_REMOVED)
1393 state = PETSPELL_CHANGED;
1394 else
1395 {
1396 if (state == PETSPELL_UNCHANGED && itr->second.state != PETSPELL_UNCHANGED)
1397 {
1398 // can be in case spell loading but learned at some previous spell loading
1399 itr->second.state = PETSPELL_UNCHANGED;
1400
1401 if (active == ACT_ENABLED)
1402 ToggleAutocast(spellInfo, true);
1403 else if (active == ACT_DISABLED)
1404 ToggleAutocast(spellInfo, false);
1405 }
1406
1407 return false;
1408 }
1409 }
1410
1411 PetSpell newspell;
1412 newspell.state = state;
1413 newspell.type = type;
1414
1415 if (active == ACT_DECIDE) // active was not used before, so we save it's autocast/passive state here
1416 {
1417 if (spellInfo->IsAutocastable())
1418 newspell.active = ACT_DISABLED;
1419 else
1420 newspell.active = ACT_PASSIVE;
1421 }
1422 else
1423 newspell.active = active;
1424
1425 // talent: unlearn all other talent ranks (high and low)
1426 if (TalentSpellPos const* talentPos = GetTalentSpellPos(spellId))
1427 {
1428 if (TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentPos->talent_id))
1429 {
1430 for (uint32 rankSpellId : talentInfo->SpellRank)
1431 {
1432 // skip learning spell and no rank spell case
1433 if (!rankSpellId || rankSpellId == spellId)
1434 continue;
1435
1436 // skip unknown ranks
1437 if (!HasSpell(rankSpellId))
1438 continue;
1439 removeSpell(rankSpellId, false, false);
1440 }
1441 }
1442 }
1443 else if (spellInfo->IsRanked())
1444 {
1445 for (PetSpellMap::const_iterator itr2 = m_spells.begin(); itr2 != m_spells.end(); ++itr2)
1446 {
1447 if (itr2->second.state == PETSPELL_REMOVED)
1448 continue;
1449
1450 SpellInfo const* oldRankSpellInfo = sSpellMgr->GetSpellInfo(itr2->first);
1451
1452 if (!oldRankSpellInfo)
1453 continue;
1454
1455 if (spellInfo->IsDifferentRankOf(oldRankSpellInfo))
1456 {
1457 // replace by new high rank
1458 if (spellInfo->IsHighRankOf(oldRankSpellInfo))
1459 {
1460 newspell.active = itr2->second.active;
1461
1462 if (newspell.active == ACT_ENABLED)
1463 ToggleAutocast(oldRankSpellInfo, false);
1464
1465 unlearnSpell(itr2->first, false, false);
1466 break;
1467 }
1468 // ignore new lesser rank
1469 else
1470 return false;
1471 }
1472 }
1473 }
1474
1475 m_spells[spellId] = newspell;
1476
1477 if (spellInfo->IsPassive() && (!spellInfo->CasterAuraState || HasAuraState(AuraStateType(spellInfo->CasterAuraState))))
1478 CastSpell(this, spellId, true);
1479 else
1480 m_charmInfo->AddSpellToActionBar(spellInfo);
1481
1482 if (newspell.active == ACT_ENABLED)
1483 ToggleAutocast(spellInfo, true);
1484
1485 uint32 talentCost = GetTalentSpellCost(spellId);
1486 if (talentCost)
1487 {
1488 int32 free_points = GetMaxTalentPointsForLevel(GetLevel());
1489 m_usedTalentCount += talentCost;
1490 // update free talent points
1491 free_points -= m_usedTalentCount;
1492 SetFreeTalentPoints(free_points > 0 ? free_points : 0);
1493 }
1494 return true;
1495}
1496
1498{
1499 // prevent duplicated entires in spell book
1500 if (!addSpell(spell_id))
1501 return false;
1502
1503 if (!m_loading)
1504 {
1506 packet.SpellID = spell_id;
1507 GetOwner()->SendDirectMessage(packet.Write());
1509 }
1510 return true;
1511}
1512
1514{
1515 uint8 level = GetLevel();
1516
1517 if (PetLevelupSpellSet const* levelupSpells = GetCreatureTemplate()->family ? sSpellMgr->GetPetLevelupSpellList(GetCreatureTemplate()->family) : nullptr)
1518 {
1519 // PetLevelupSpellSet ordered by levels, process in reversed order
1520 for (PetLevelupSpellSet::const_reverse_iterator itr = levelupSpells->rbegin(); itr != levelupSpells->rend(); ++itr)
1521 {
1522 // will called first if level down
1523 if (itr->first > level)
1524 unlearnSpell(itr->second, true); // will learn prev rank if any
1525 // will called if level up
1526 else
1527 learnSpell(itr->second); // will unlearn prev rank if any
1528 }
1529 }
1530
1532
1533 // default spells (can be not learned if pet level (as owner level decrease result for example) less first possible in normal game)
1534 if (PetDefaultSpellsEntry const* defSpells = sSpellMgr->GetPetDefaultSpellsEntry(petSpellsId))
1535 {
1536 for (uint32 spellId : defSpells->spellid)
1537 {
1538 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
1539 if (!spellInfo)
1540 continue;
1541
1542 // will called first if level down
1543 if (spellInfo->SpellLevel > level)
1544 unlearnSpell(spellInfo->Id, true);
1545 // will called if level up
1546 else
1547 learnSpell(spellInfo->Id);
1548 }
1549 }
1550}
1551
1552bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab)
1553{
1554 if (removeSpell(spell_id, learn_prev, clear_ab))
1555 {
1556 if (!m_loading)
1557 {
1559 packet.SpellID = spell_id;
1560 GetOwner()->SendDirectMessage(packet.Write());
1561 }
1562 return true;
1563 }
1564 return false;
1565}
1566
1567bool Pet::removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab)
1568{
1569 PetSpellMap::iterator itr = m_spells.find(spell_id);
1570 if (itr == m_spells.end())
1571 return false;
1572
1573 if (itr->second.state == PETSPELL_REMOVED)
1574 return false;
1575
1576 if (itr->second.state == PETSPELL_NEW)
1577 m_spells.erase(itr);
1578 else
1579 itr->second.state = PETSPELL_REMOVED;
1580
1581 RemoveAurasDueToSpell(spell_id);
1582
1583 uint32 talentCost = GetTalentSpellCost(spell_id);
1584 if (talentCost > 0)
1585 {
1586 if (m_usedTalentCount > talentCost)
1587 m_usedTalentCount -= talentCost;
1588 else
1590 // update free talent points
1592 SetFreeTalentPoints(free_points > 0 ? free_points : 0);
1593 }
1594
1595 if (learn_prev)
1596 {
1597 if (uint32 prev_id = sSpellMgr->GetPrevSpellInChain (spell_id))
1598 learnSpell(prev_id);
1599 else
1600 learn_prev = false;
1601 }
1602
1603 // if remove last rank or non-ranked then update action bar at server and client if need
1604 if (clear_ab && !learn_prev && m_charmInfo->RemoveSpellFromActionBar(spell_id))
1605 {
1606 if (!m_loading)
1607 GetOwner()->PetSpellInitialize(); // need update action bar for last removed rank
1608 }
1609
1610 return true;
1611}
1612
1614{
1615 for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
1617 if (ab->GetAction() && ab->IsActionBarForSpell())
1618 {
1619 if (!HasSpell(ab->GetAction()))
1621 else if (ab->GetType() == ACT_ENABLED)
1622 {
1623 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(ab->GetAction()))
1624 ToggleAutocast(spellInfo, true);
1625 }
1626 }
1627}
1628
1630{
1632 m_spells.clear();
1633
1636
1637 CastPetAuras(false);
1638}
1639
1640bool Pet::resetTalents(bool involuntarily /*= false*/)
1641{
1642 Player* player = GetOwner();
1643
1644 // not need after this call
1647
1649 if (!ci)
1650 return false;
1651 // Check pet talent type
1652 CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family);
1653 if (!pet_family || pet_family->PetTalentType < 0)
1654 return false;
1655
1656 uint8 level = GetLevel();
1657 uint32 talentPointsForLevel = GetMaxTalentPointsForLevel(level);
1658
1659 if (m_usedTalentCount == 0)
1660 {
1661 SetFreeTalentPoints(talentPointsForLevel);
1662 return false;
1663 }
1664
1665 for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
1666 {
1667 TalentEntry const* talentInfo = sTalentStore.LookupEntry(i);
1668
1669 if (!talentInfo)
1670 continue;
1671
1672 TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TabID);
1673
1674 if (!talentTabInfo)
1675 continue;
1676
1677 // unlearn only talents for pets family talent type
1678 if (!((1 << pet_family->PetTalentType) & talentTabInfo->PetTalentMask))
1679 continue;
1680
1681 for (uint32 talentSpellId : talentInfo->SpellRank)
1682 {
1683 for (PetSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end();)
1684 {
1685 if (itr->second.state == PETSPELL_REMOVED)
1686 {
1687 ++itr;
1688 continue;
1689 }
1690 // remove learned spells (all ranks)
1691 uint32 itrFirstId = sSpellMgr->GetFirstSpellInChain(itr->first);
1692
1693 // unlearn if first rank is talent or learned by talent
1694 if (itrFirstId == talentSpellId || sSpellMgr->IsSpellLearnToSpell(talentSpellId, itrFirstId))
1695 {
1696 unlearnSpell(itr->first, false);
1697 itr = m_spells.begin();
1698 continue;
1699 }
1700 else
1701 ++itr;
1702 }
1703 }
1704 }
1705
1706 SetFreeTalentPoints(talentPointsForLevel);
1707
1708 if (!m_loading)
1709 player->PetSpellInitialize();
1710
1711 if (involuntarily)
1713
1714 return true;
1715}
1716
1717void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* onlinePet /*= nullptr*/, bool involuntarily /*= false*/)
1718{
1719 // not need after this call
1722
1723 // reset for online
1724 if (onlinePet)
1725 onlinePet->resetTalents(involuntarily);
1726
1727 PetStable* petStable = owner->GetPetStable();
1728 if (!petStable)
1729 return;
1730
1731 std::unordered_set<uint32> petIds;
1732 if (petStable->CurrentPet)
1733 petIds.insert(petStable->CurrentPet->PetNumber);
1734
1735 for (Optional<PetStable::PetInfo> const& stabledPet : petStable->StabledPets)
1736 if (stabledPet)
1737 petIds.insert(stabledPet->PetNumber);
1738
1739 for (PetStable::PetInfo const& unslottedPet : petStable->UnslottedPets)
1740 petIds.insert(unslottedPet.PetNumber);
1741
1742 // now need only reset for offline pets (all pets except online case)
1743 if (onlinePet)
1744 petIds.erase(onlinePet->GetCharmInfo()->GetPetNumber());
1745
1746 // no offline pets
1747 if (petIds.empty())
1748 return;
1749
1750 if (!onlinePet)
1752
1753 bool need_comma = false;
1754 std::ostringstream ss;
1755 ss << "DELETE FROM pet_spell WHERE guid IN (";
1756
1757 for (uint32 id : petIds)
1758 {
1759 if (need_comma)
1760 ss << ',';
1761
1762 ss << id;
1763
1764 need_comma = true;
1765 }
1766
1767 ss << ") AND spell IN (";
1768
1769 need_comma = false;
1770 for (uint32 spell : sPetTalentSpells)
1771 {
1772 if (need_comma)
1773 ss << ',';
1774
1775 ss << spell;
1776
1777 need_comma = true;
1778 }
1779
1780 ss << ')';
1781
1782 CharacterDatabase.Execute(ss.str().c_str());
1783}
1784
1786{
1787 uint8 level = GetLevel();
1788 uint32 talentPointsForLevel = GetMaxTalentPointsForLevel(level);
1789 // Reset talents in case low level (on level down) or wrong points for level (hunter can unlearn TP increase talent)
1790 if (talentPointsForLevel == 0 || m_usedTalentCount > talentPointsForLevel)
1791 resetTalents(); // Remove all talent points
1792
1793 SetFreeTalentPoints(talentPointsForLevel - m_usedTalentCount);
1794
1795 if (!m_loading)
1797}
1798
1800{
1801 uint8 points = (level >= 20) ? ((level - 16) / 4) : 0;
1802 // Mod points from owner SPELL_AURA_MOD_PET_TALENT_POINTS
1804 return points;
1805}
1806
1807void Pet::ToggleAutocast(SpellInfo const* spellInfo, bool apply)
1808{
1809 ASSERT(spellInfo);
1810
1811 if (!spellInfo->IsAutocastable())
1812 return;
1813
1814 PetSpellMap::iterator itr = m_spells.find(spellInfo->Id);
1815 if (itr == m_spells.end())
1816 return;
1817
1818 auto autospellItr = std::find(m_autospells.begin(), m_autospells.end(), spellInfo->Id);
1819
1820 if (apply)
1821 {
1822 if (autospellItr == m_autospells.end())
1823 {
1824 m_autospells.push_back(spellInfo->Id);
1825
1826 if (itr->second.active != ACT_ENABLED)
1827 {
1828 itr->second.active = ACT_ENABLED;
1829 if (itr->second.state != PETSPELL_NEW)
1830 itr->second.state = PETSPELL_CHANGED;
1831 }
1832 }
1833 }
1834 else
1835 {
1836 if (autospellItr != m_autospells.end())
1837 {
1838 m_autospells.erase(autospellItr);
1839
1840 if (itr->second.active != ACT_DISABLED)
1841 {
1842 itr->second.active = ACT_DISABLED;
1843 if (itr->second.state != PETSPELL_NEW)
1844 itr->second.state = PETSPELL_CHANGED;
1845 }
1846 }
1847 }
1848}
1849
1851{
1852 switch (getPetType())
1853 {
1854 case SUMMON_PET:
1855 switch (owner->GetClass())
1856 {
1857 case CLASS_WARLOCK:
1859 case CLASS_DEATH_KNIGHT:
1861 default:
1862 return false;
1863 }
1864 case HUNTER_PET:
1865 return true;
1866 default:
1867 return false;
1868 }
1869}
1870
1871bool Pet::Create(ObjectGuid::LowType guidlow, Map* map, uint32 phaseMask, uint32 Entry, uint32 petId)
1872{
1873 ASSERT(map);
1874 SetMap(map);
1875
1876 SetPhaseMask(phaseMask, false);
1877 Object::_Create(ObjectGuid::Create<HighGuid::Pet>(petId, guidlow));
1878
1880
1881 if (!InitEntry(Entry))
1882 return false;
1883
1884 // Force regen flag for player pets, just like we do for players themselves
1887
1889
1890 return true;
1891}
1892
1893bool Pet::HasSpell(uint32 spell) const
1894{
1895 PetSpellMap::const_iterator itr = m_spells.find(spell);
1896 return itr != m_spells.end() && itr->second.state != PETSPELL_REMOVED;
1897}
1898
1899// Get all passive spells in our skill line
1901{
1902 CreatureTemplate const* cInfo = GetCreatureTemplate();
1903 if (!cInfo)
1904 return;
1905
1906 CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->family);
1907 if (!cFamily)
1908 return;
1909
1910 PetFamilySpellsStore::const_iterator petStore = sPetFamilySpellsStore.find(cFamily->ID);
1911 if (petStore != sPetFamilySpellsStore.end())
1912 {
1913 // For general hunter pets skill 270
1914 // Passive 01~10, Passive 00 (20782, not used), Ferocious Inspiration (34457)
1915 // Scale 01~03 (34902~34904, bonus from owner, not used)
1916 for (uint32 spellId : petStore->second)
1918 }
1919}
1920
1921void Pet::CastPetAuras(bool current)
1922{
1923 Player* owner = GetOwner();
1924
1925 if (!IsPermanentPetFor(owner))
1926 return;
1927
1928 for (auto itr = owner->m_petAuras.begin(); itr != owner->m_petAuras.end();)
1929 {
1930 PetAura const* pa = *itr;
1931 ++itr;
1932
1933 if (!current && pa->IsRemovedOnChangePet())
1934 owner->RemovePetAura(pa);
1935 else
1936 CastPetAura(pa);
1937 }
1938}
1939
1940void Pet::CastPetAura(PetAura const* aura)
1941{
1942 uint32 auraId = aura->GetAura(GetEntry());
1943 if (!auraId)
1944 return;
1945
1946 CastSpellExtraArgs args;
1948
1949 if (auraId == 35696) // Demonic Knowledge
1951
1952 CastSpell(this, auraId, args);
1953}
1954
1955bool Pet::IsPetAura(Aura const* aura)
1956{
1957 Player* owner = GetOwner();
1958
1959 // if the owner has that pet aura, return true
1960 for (PetAura const* petAura : owner->m_petAuras)
1961 if (petAura->GetAura(GetEntry()) == aura->GetId())
1962 return true;
1963
1964 return false;
1965}
1966
1968{
1969 learnSpell(spellid);
1970
1971 if (uint32 next = sSpellMgr->GetNextSpellInChain(spellid))
1972 learnSpellHighRank(next);
1973}
1974
1976{
1977 Player* owner = GetOwner();
1978
1979 switch (getPetType())
1980 {
1981 // always same level
1982 case SUMMON_PET:
1983 GivePetLevel(owner->GetLevel());
1984 break;
1985 // can't be greater owner level
1986 case HUNTER_PET:
1987 if (GetLevel() > owner->GetLevel())
1988 GivePetLevel(owner->GetLevel());
1989 else if (GetLevel() + 5 < owner->GetLevel())
1990 GivePetLevel(owner->GetLevel() - 5);
1991 break;
1992 default:
1993 break;
1994 }
1995}
1996
1998{
1999 return Minion::GetOwner()->ToPlayer();
2000}
2001
2003{
2004 CreatureFamilyEntry const* creatureFamily = sCreatureFamilyStore.LookupEntry(GetCreatureTemplate()->family);
2005 if (creatureFamily && creatureFamily->MinScale > 0.0f && getPetType() == HUNTER_PET)
2006 {
2007 float scale;
2008 if (GetLevel() >= creatureFamily->MaxScaleLevel)
2009 scale = creatureFamily->MaxScale;
2010 else if (GetLevel() <= creatureFamily->MinScaleLevel)
2011 scale = creatureFamily->MinScale;
2012 else
2013 scale = creatureFamily->MinScale + float(GetLevel() - creatureFamily->MinScaleLevel) / creatureFamily->MaxScaleLevel * (creatureFamily->MaxScale - creatureFamily->MinScale);
2014
2015 return scale;
2016 }
2017
2019}
2020
2022{
2023 Guardian::SetDisplayId(modelId);
2024
2025 if (!isControlled())
2026 return;
2027
2028 if (GetOwner()->GetGroup())
2030}
2031
2033{
2034 std::ostringstream oss;
2035
2037 {
2038 oss << uint32(m_charmInfo->GetActionBarEntry(i)->GetType()) << ' '
2040 }
2041
2042 return oss.str();
2043}
2044
2045std::string Pet::GetDebugInfo() const
2046{
2047 std::stringstream sstr;
2048 sstr << Guardian::GetDebugInfo() << "\n"
2049 << std::boolalpha
2050 << "PetType: " << std::to_string(getPetType()) << " "
2051 << "PetNumber: " << m_charmInfo->GetPetNumber();
2052 return sstr.str();
2053}
@ CHAR_SEL_PET_AURA
@ CHAR_DEL_CHAR_PET_BY_SLOT
@ CHAR_DEL_INVALID_PET_SPELL
@ CHAR_DEL_PET_SPELLS
@ CHAR_INS_PET
@ CHAR_INS_PET_SPELL
@ CHAR_DEL_CHAR_PET_BY_ID
@ CHAR_DEL_PET_AURAS
@ CHAR_SEL_PET_DECLINED_NAME
@ CHAR_DEL_PET_SPELL_BY_SPELL
@ CHAR_DEL_PET_SPELL_COOLDOWNS
@ CHAR_SEL_PET_SPELL
@ CHAR_SEL_PET_SPELL_COOLDOWN
@ CHAR_INS_PET_AURA
@ CHAR_DEL_CHAR_PET_DECLINEDNAME
@ IN_MILLISECONDS
Definition Common.h:35
static const uint32 PET_FOCUS_REGEN_INTERVAL
#define MAX_SPELL_EFFECTS
Definition DBCEnums.h:386
DBCStorage< TalentTabEntry > sTalentTabStore(TalentTabEntryfmt)
TalentSpellPos const * GetTalentSpellPos(uint32 spellId)
uint32 GetTalentSpellCost(uint32 spellId)
std::unordered_set< uint32 > sPetTalentSpells
DBCStorage< CreatureFamilyEntry > sCreatureFamilyStore(CreatureFamilyfmt)
DBCStorage< TalentEntry > sTalentStore(TalentEntryfmt)
PetFamilySpellsStore sPetFamilySpellsStore
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
#define ASSERT_NOTNULL(pointer)
Definition Errors.h:84
#define ASSERT
Definition Errors.h:68
@ GROUP_UPDATE_FLAG_PET_MODEL_ID
Definition Group.h:113
@ GROUP_UPDATE_PET
Definition Group.h:121
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
@ TYPEID_PLAYER
Definition ObjectGuid.h:39
#define sObjectMgr
Definition ObjectMgr.h:1721
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
PetSpellState
Definition PetDefines.h:56
@ PETSPELL_NEW
Definition PetDefines.h:59
@ PETSPELL_UNCHANGED
Definition PetDefines.h:57
@ PETSPELL_CHANGED
Definition PetDefines.h:58
@ PETSPELL_REMOVED
Definition PetDefines.h:60
PetSaveMode
Definition PetDefines.h:40
@ PET_SAVE_FIRST_STABLE_SLOT
Definition PetDefines.h:43
@ PET_SAVE_LAST_STABLE_SLOT
Definition PetDefines.h:44
@ PET_SAVE_AS_DELETED
Definition PetDefines.h:41
@ PET_SAVE_NOT_IN_SLOT
Definition PetDefines.h:45
@ PET_SAVE_AS_CURRENT
Definition PetDefines.h:42
#define PET_FOLLOW_DIST
Definition PetDefines.h:85
PetType
Definition PetDefines.h:30
@ SUMMON_PET
Definition PetDefines.h:31
@ HUNTER_PET
Definition PetDefines.h:32
@ MAX_PET_TYPE
Definition PetDefines.h:33
PetSpellType
Definition PetDefines.h:64
@ PETSPELL_FAMILY
Definition PetDefines.h:66
HappinessState
Definition PetDefines.h:49
@ HAPPY
Definition PetDefines.h:52
@ CONTENT
Definition PetDefines.h:51
@ UNHAPPY
Definition PetDefines.h:50
#define PET_XP_FACTOR
Definition Pet.cpp:42
#define HAPPINESS_LEVEL_SIZE
Definition Pet.h:24
@ AT_LOGIN_RESET_PET_TALENTS
Definition Player.h:485
SpellSchools
@ SPELL_SCHOOL_SHADOW
@ SPELL_SCHOOL_FIRE
@ SPELL_SCHOOL_HOLY
@ MAX_SPELL_SCHOOL
@ GENDER_NONE
@ SPELL_SCHOOL_MASK_SHADOW
@ SPELL_SCHOOL_MASK_NATURE
@ SPELL_SCHOOL_MASK_FIRE
@ SPELL_SCHOOL_MASK_FROST
@ CREATURE_TYPE_UNDEAD
@ CREATURE_TYPE_DEMON
@ CREATURE_TYPE_BEAST
@ UNIT_DYNFLAG_NONE
@ OFF_ATTACK
@ BASE_ATTACK
@ RANGED_ATTACK
@ CLASS_HUNTER
@ CLASS_SHAMAN
@ CLASS_WARRIOR
@ CLASS_WARLOCK
@ CLASS_MAGE
@ CLASS_DEATH_KNIGHT
@ POWER_HAPPINESS
@ POWER_ENERGY
@ POWER_MANA
@ POWER_FOCUS
AuraStateType
Stats
@ STAT_SPIRIT
@ STAT_INTELLECT
@ MAX_STATS
@ STAT_AGILITY
@ STAT_STRENGTH
@ STAT_STAMINA
@ SPELL_ATTR4_FADES_WHILE_LOGGED_OUT
@ SPELL_AURA_MOD_PET_TALENT_POINTS
@ TRIGGERED_FULL_MASK
Will return SPELL_FAILED_DONT_REPORT in CheckCast functions.
@ SPELLVALUE_BASE_POINT0
#define sSpellMgr
Definition SpellMgr.h:738
std::multimap< uint32, uint32 > PetLevelupSpellSet
Definition SpellMgr.h:539
@ CAST_FLAG_UNKNOWN_9
Definition Spell.h:86
@ UNIT_FLAG2_REGENERATE_POWER
@ UNIT_PET_FLAG_CAN_BE_ABANDONED
@ UNIT_PET_FLAG_CAN_BE_RENAMED
#define BASE_ATTACK_TIME
Definition UnitDefines.h:27
#define MAX_DECLINED_NAME_CASES
ActiveStates
@ ACT_DECIDE
@ ACT_ENABLED
@ ACT_PASSIVE
@ ACT_DISABLED
@ UNIT_NPC_FLAG_NONE
@ SHEATH_STATE_MELEE
Definition UnitDefines.h:99
@ COMMAND_FOLLOW
@ UNIT_FLAG_PLAYER_CONTROLLED
@ UNIT_FLAG_SKINNABLE
@ BASE_VALUE
Definition Unit.h:139
@ UNIT_MASK_CONTROLABLE_GUARDIAN
Definition Unit.h:386
@ UNIT_MASK_HUNTER_PET
Definition Unit.h:385
@ UNIT_MASK_PET
Definition Unit.h:382
#define MAX_UNIT_ACTION_BAR_INDEX
Definition Unit.h:684
@ MINDAMAGE
Definition Unit.h:153
@ MAXDAMAGE
Definition Unit.h:154
UnitMods
Definition Unit.h:158
@ UNIT_MOD_ARMOR
Definition Unit.h:172
@ UNIT_MOD_RESISTANCE_START
Definition Unit.h:186
@ UNIT_MOD_STAT_STAMINA
Definition Unit.h:161
@ ACTION_BAR_INDEX_END
Definition Unit.h:681
@ ACTION_BAR_INDEX_START
Definition Unit.h:678
DeathState
Definition Unit.h:224
@ CORPSE
Definition Unit.h:227
@ ALIVE
Definition Unit.h:225
@ JUST_DIED
Definition Unit.h:226
@ PLAYER_FIELD_MOD_DAMAGE_DONE_POS
@ UNIT_FIELD_PETEXPERIENCE
@ UNIT_FIELD_PETNEXTLEVELEXP
@ UNIT_CREATED_BY_SPELL
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:554
T CalculatePct(T base, U pct)
Definition Util.h:71
static Aura * TryCreate(AuraCreateInfo &createInfo)
uint32 GetId() const
Definition SpellAuras.h:141
AuraEffect * GetEffect(uint8 effIndex) const
Definition SpellAuras.h:226
void SetPhaseMask(uint32 newPhaseMask, bool update) override
Definition Creature.cpp:653
void setDeathState(DeathState s) override
void SetDisplayId(uint32 modelId) override
void Update(uint32 time) override
Definition Creature.cpp:671
void SetObjectScale(float scale) override
bool AIM_Initialize(CreatureAI *ai=nullptr)
void LoadTemplateImmunities()
void SetReactState(ReactStates st)
Definition Creature.h:128
std::string const & GetNameForLocaleIdx(LocaleConstant locale_idx) const override
time_t m_corpseRemoveTime
Definition Creature.h:396
static float _GetHealthMod(int32 Rank)
CreatureTemplate const * GetCreatureTemplate() const
Definition Creature.h:195
uint32 m_originalEntry
Definition Creature.h:422
float GetNativeObjectScale() const override
ReactStates GetReactState() const
Definition Creature.h:129
bool InitEntry(uint32 entry, CreatureData const *data=nullptr)
Definition Creature.cpp:441
void SetMeleeDamageSchool(SpellSchools school)
Definition Creature.h:168
void Regenerate(Powers power)
Definition Creature.cpp:882
Class used to access individual fields of database query result.
Definition Field.h:92
uint8 GetUInt8() const
Definition Field.cpp:29
std::string GetString() const
Definition Field.cpp:125
float GetFloat() const
Definition Field.cpp:93
bool GetBool() const
Definition Field.h:100
uint32 GetUInt32() const
Definition Field.cpp:61
int32 GetInt32() const
Definition Field.cpp:69
void SetBonusDamage(int32 damage)
bool InitStatsForLevel(uint8 level)
Definition Pet.cpp:861
std::string GetDebugInfo() const override
bool UpdateAllStats() override
Definition Map.h:302
MapStoredObjectTypesContainer & GetObjectsStore()
Definition Map.h:509
bool AddToMap(T *)
Definition Map.cpp:630
ObjectGuid::LowType GenerateLowGuid()
Definition Map.h:607
Unit * GetOwner() const
bool IsRisenAlly() const
float GetFollowAngle() const override
bool IsPetGhoul() const
LowType GetCounter() const
Definition ObjectGuid.h:156
static ObjectGuid const Empty
Definition ObjectGuid.h:140
bool IsEmpty() const
Definition ObjectGuid.h:172
void SetRawValue(uint64 guid)
Definition ObjectGuid.h:149
uint64 GetRawValue() const
Definition ObjectGuid.h:148
uint32 LowType
Definition ObjectGuid.h:142
bool IsPlayer() const
Definition Object.h:182
uint32 GetUInt32Value(uint16 index) const
Definition Object.cpp:241
bool IsInWorld() const
Definition Object.h:73
TypeID GetTypeId() const
Definition Object.h:93
uint32 GetEntry() const
Definition Object.h:81
Creature * ToCreature()
Definition Object.h:191
void _Create(ObjectGuid const &guid)
Definition Object.cpp:109
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
void SetUInt32Value(uint16 index, uint32 value)
Definition Object.cpp:577
ObjectGuid GetGUID() const
Definition Object.h:79
static Player * ToPlayer(Object *o)
Definition Object.h:183
int32 GetDamage() const
Definition SpellMgr.h:457
uint32 GetAura(uint32 petEntry) const
Definition SpellMgr.h:436
bool IsRemovedOnChangePet() const
Definition SpellMgr.h:452
PetLoadQueryHolder(ObjectGuid::LowType ownerGuid, uint32 petNumber)
Definition Pet.cpp:160
std::array< Optional< PetInfo >, MAX_PET_STABLES > StabledPets
Definition PetDefines.h:113
Optional< PetInfo > CurrentPet
Definition PetDefines.h:112
std::vector< PetInfo > UnslottedPets
Definition PetDefines.h:115
Definition Pet.h:40
void LearnPetPassives()
Definition Pet.cpp:1900
Pet(Player *owner, PetType type=MAX_PET_TYPE)
Definition Pet.cpp:44
void GivePetLevel(uint8 level)
Definition Pet.cpp:774
void RemoveFromWorld() override
Definition Pet.cpp:91
bool m_loading
Definition Pet.h:160
Player * GetOwner() const
Definition Pet.cpp:1997
bool IsPetAura(Aura const *aura)
Definition Pet.cpp:1955
bool unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab=true)
Definition Pet.cpp:1552
void FillPetInfo(PetStable::PetInfo *petInfo) const
Definition Pet.cpp:536
uint32 m_focusRegenTimer
Definition Pet.h:161
uint32 m_usedTalentCount
Definition Pet.h:141
bool Create(ObjectGuid::LowType guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 pet_number)
Definition Pet.cpp:1871
void SetDisplayId(uint32 modelId) override
Definition Pet.cpp:2021
void ToggleAutocast(SpellInfo const *spellInfo, bool apply)
Definition Pet.cpp:1807
static void resetTalentsForAllPetsOf(Player *owner, Pet *online_pet=nullptr, bool involuntarily=false)
Definition Pet.cpp:1717
void AddToWorld() override
Definition Pet.cpp:66
void InitTalentForLevel()
Definition Pet.cpp:1785
void CastPetAuras(bool current)
Definition Pet.cpp:1921
void setPetType(PetType type)
Definition Pet.h:52
void SavePetToDB(PetSaveMode mode)
Definition Pet.cpp:437
float GetNativeObjectScale() const override
Definition Pet.cpp:2002
void _SaveAuras(CharacterDatabaseTransaction trans)
Definition Pet.cpp:1309
PetType getPetType() const
Definition Pet.h:51
void SynchronizeLevelWithOwner()
Definition Pet.cpp:1975
std::unique_ptr< DeclinedName > m_declinedname
Definition Pet.h:163
uint8 GetMaxTalentPointsForLevel(uint8 level) const
Definition Pet.cpp:1799
void _SaveSpells(CharacterDatabaseTransaction trans)
Definition Pet.cpp:1180
void learnSpellHighRank(uint32 spellid)
Definition Pet.cpp:1967
bool IsPermanentPetFor(Player *owner) const
Definition Pet.cpp:1850
bool HaveInDiet(ItemTemplate const *item) const
Definition Pet.cpp:1132
bool addSpell(uint32 spellId, ActiveStates active=ACT_DECIDE, PetSpellState state=PETSPELL_NEW, PetSpellType type=PETSPELL_NORMAL)
Definition Pet.cpp:1367
AutoSpellList m_autospells
Definition Pet.h:129
void SetPetExperience(uint32 xp)
Definition Pet.h:86
std::string GetDebugInfo() const override
Definition Pet.cpp:2045
static void DeleteFromDB(ObjectGuid::LowType guidlow)
Definition Pet.cpp:555
bool CreateBaseAtTamed(CreatureTemplate const *cinfo, Map *map, uint32 phaseMask)
Definition Pet.cpp:836
uint32 m_happinessTimer
Definition Pet.h:156
bool CreateBaseAtCreatureInfo(CreatureTemplate const *cinfo, Unit *owner)
Definition Pet.cpp:823
HappinessState GetHappinessState()
Definition Pet.cpp:722
bool removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab=true)
Definition Pet.cpp:1567
bool CreateBaseAtCreature(Creature *creature)
Definition Pet.cpp:790
void CleanupActionBar()
Definition Pet.cpp:1613
bool isTemporarySummoned() const
Definition Pet.h:54
void CastPetAura(PetAura const *aura)
Definition Pet.cpp:1940
void _LoadSpells(PreparedQueryResult result)
Definition Pet.cpp:1166
bool isControlled() const
Definition Pet.h:53
virtual ~Pet()
void SetPetNextLevelExperience(uint32 xp)
Definition Pet.h:87
void setDeathState(DeathState s) override
Definition Pet.cpp:582
bool m_removed
Definition Pet.h:149
void SetFreeTalentPoints(uint8 points)
Definition Pet.h:139
void Remove(PetSaveMode mode, bool returnreagent=false)
Definition Pet.cpp:732
void _LoadAuras(PreparedQueryResult auraResult, uint32 timediff)
Definition Pet.cpp:1229
void Update(uint32 diff) override
Definition Pet.cpp:607
void InitPetCreateSpells()
Definition Pet.cpp:1629
bool HasSpell(uint32 spell) const override
Definition Pet.cpp:1893
bool resetTalents(bool involuntarily=false)
Definition Pet.cpp:1640
uint32 GetCurrentFoodBenefitLevel(uint32 itemlevel) const
Definition Pet.cpp:1150
PetSpellMap m_spells
Definition Pet.h:128
static std::pair< PetStable::PetInfo const *, PetSaveMode > GetLoadPetInfo(PetStable const &stable, uint32 petEntry, uint32 petnumber, bool current)
Definition Pet.cpp:102
bool LoadPetFromDB(Player *owner, uint32 petEntry, uint32 petnumber, bool current)
Definition Pet.cpp:185
void LoseHappiness()
Definition Pet.cpp:711
void GivePetXP(uint32 xp)
Definition Pet.cpp:737
std::string GenerateActionBarData() const
Definition Pet.cpp:2032
bool learnSpell(uint32 spell_id)
Definition Pet.cpp:1497
int32 m_duration
Definition Pet.h:158
void InitLevelupSpellsForLevel()
Definition Pet.cpp:1513
void RemoveAtLoginFlag(AtLoginFlags flags, bool persist=false)
Definition Player.cpp:25490
void SendTalentsInfoData(bool pet)
Definition Player.cpp:25337
void SetGroupUpdateFlag(uint32 flag)
Definition Player.h:2165
uint32 GetTemporaryUnsummonedPetNumber() const
Definition Player.h:2112
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6163
bool CanTameExoticPets() const
Definition Player.h:1889
void SetTemporaryUnsummonedPetNumber(uint32 petnumber)
Definition Player.h:2113
bool IsPetNeedBeTemporaryUnsummoned() const
Definition Player.cpp:25202
PetStable * GetPetStable()
Definition Player.h:1045
void PetSpellInitialize()
Definition Player.cpp:20594
Pet * GetPet() const
Definition Player.cpp:20284
WorldSession * GetSession() const
Definition Player.h:1705
void RemovePet(Pet *pet, PetSaveMode mode, bool returnreagent=false)
Definition Player.cpp:20308
Group * GetGroup()
Definition Player.h:2159
std::unordered_set< PetAura const * > m_petAuras
Definition Player.h:1055
bool HasAtLoginFlag(AtLoginFlags f) const
Definition Player.h:2101
void RemovePetAura(PetAura const *petSpell)
Definition Player.cpp:20405
void SendMessageToSet(WorldPacket const *data, bool self) const override
Definition Player.h:1733
void SetLastPetNumber(uint32 petnumber)
Definition Player.h:2151
void setUInt32(uint8 index, uint32 value)
void setBool(uint8 index, bool value)
void setFloat(uint8 index, float value)
void setUInt64(uint8 index, uint64 value)
void setInt32(uint8 index, int32 value)
void setUInt8(uint8 index, uint8 value)
void setString(uint8 index, std::string const &value)
void SetSize(size_t size)
PreparedQueryResult GetPreparedResult(size_t index) const
void AfterComplete(std::function< void(SQLQueryHolderBase const &)> callback) &
Definition QueryHolder.h:76
bool SetPreparedQuery(size_t index, PreparedStatement< T > *stmt)
Definition QueryHolder.h:44
void SaveToDB(CharacterDatabaseTransaction trans)
uint32 SpellLevel
Definition SpellInfo.h:329
bool IsAutocastable() const
bool IsPassive() const
uint32 Id
Definition SpellInfo.h:289
uint32 ProcCharges
Definition SpellInfo.h:326
bool IsRanked() const
bool IsHighRankOf(SpellInfo const *spellInfo) const
uint32 CasterAuraState
Definition SpellInfo.h:308
bool HasAttribute(SpellAttr0 attribute) const
Definition SpellInfo.h:375
int32 GetDuration() const
bool IsDifferentRankOf(SpellInfo const *spellInfo) const
bool IsPositive() const
bool Remove(KEY_TYPE const &handle)
bool Insert(KEY_TYPE const &handle, SPECIFIC_TYPE *obj)
Definition Unit.h:783
void ReplaceAllDynamicFlags(uint32 flag) override
Definition Unit.h:833
void SetMinion(Minion *minion, bool apply)
Definition Unit.cpp:5852
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition Unit.cpp:8379
bool HasPetFlag(UnitPetFlag flags) const
Definition Unit.h:1007
bool IsHunterPet() const
Definition Unit.h:899
void SetCreateStat(Stats stat, float val)
Definition Unit.h:1461
void SetGender(Gender gender)
Definition Unit.h:913
void SetFullHealth()
Definition Unit.h:941
ThreatManager & GetThreatManager()
Definition Unit.h:1169
void AddToWorld() override
Definition Unit.cpp:9569
uint8 GetClass() const
Definition Unit.h:909
void SetCreateHealth(uint32 val)
Definition Unit.h:1462
void SetFaction(uint32 faction) override
Definition Unit.h:988
ObjectGuid GetOwnerGUID() const override
Definition Unit.h:1254
void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value, uint8 damageIndex=0)
Definition Unit.h:1568
CharmInfo * m_charmInfo
Definition Unit.h:1907
void ReplaceAllUnitFlags(UnitFlags flags)
Definition Unit.h:970
bool IsPet() const
Definition Unit.h:898
Powers GetPowerType() const
Definition Unit.h:945
void SetCreatedBySpell(int32 spellId)
Definition Unit.h:978
uint32 GetMaxHealth() const
Definition Unit.h:928
Aura * AddAura(uint32 spellId, Unit *target)
Definition Unit.cpp:11935
void SetUnitFlag2(UnitFlags2 flags)
Definition Unit.h:974
void ReplaceAllPetFlags(UnitPetFlag flags)
Definition Unit.h:1010
void SetPetNameTimestamp(uint32 timestamp)
Definition Unit.h:1304
bool IsAlive() const
Definition Unit.h:1247
float GetCombatReach() const override
Definition Unit.h:853
DeathState m_deathState
Definition Unit.h:1868
uint32 m_unitTypeMask
Definition Unit.h:1919
void SetHealth(uint32 val)
Definition Unit.cpp:9338
void SetMaxPower(Powers power, uint32 val)
Definition Unit.cpp:9439
CharmInfo * GetCharmInfo()
Definition Unit.h:1300
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4558
void SetNativeDisplayId(uint32 displayId)
Definition Unit.h:1602
void SetCreateMana(uint32 val)
Definition Unit.h:1464
virtual void SetSheath(SheathState sheathed)
Definition Unit.h:984
uint32 GetDisplayId() const
Definition Unit.h:1598
uint32 GetNativeDisplayId() const
Definition Unit.h:1600
bool isPossessed() const
Definition Unit.h:1295
uint32 GetMaxPower(Powers power) const
Definition Unit.h:950
uint32 GetHealth() const
Definition Unit.h:927
uint32 GetFaction() const override
Definition Unit.h:987
void SetPower(Powers power, uint32 val, bool withPowerUpdate=true, bool force=false)
Definition Unit.cpp:9398
bool HasAuraState(AuraStateType flag, SpellInfo const *spellProto=nullptr, Unit const *Caster=nullptr) const
Definition Unit.cpp:5757
uint32 GetArmor() const
Definition Unit.h:919
int32 GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:4815
void SetFullPower(Powers power)
Definition Unit.h:955
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3807
void SetPowerType(Powers power, bool sendUpdate=true)
Definition Unit.cpp:5350
DeathState getDeathState() const
Definition Unit.h:1251
bool IsCritter() const
Definition Unit.h:1131
AuraMap m_ownedAuras
Definition Unit.h:1883
void SetLevel(uint8 lvl, bool sendUpdate=true)
Definition Unit.cpp:9321
void SetCanModifyStats(bool modifyStats)
Definition Unit.h:1548
CharmInfo * InitCharmInfo()
Definition Unit.cpp:9707
void SetClass(uint8 classId)
Definition Unit.h:910
void RemoveFromWorld() override
Definition Unit.cpp:9578
float GetStat(Stats stat) const
Definition Unit.h:917
void RemoveAllAuras()
Definition Unit.cpp:4180
SpellHistory * GetSpellHistory()
Definition Unit.h:1497
void SetCreatorGUID(ObjectGuid creator)
Definition Unit.h:1257
uint32 GetPower(Powers power) const
Definition Unit.h:948
void SetAttackTime(WeaponAttackType att, uint32 val)
Definition Unit.h:960
void SetModCastingSpeed(float castingSpeed)
Definition Unit.h:964
void ReplaceAllNpcFlags(NPCFlags flags)
Definition Unit.h:1113
int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const
Definition Unit.cpp:6927
void SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
Definition Unit.cpp:9011
uint32 GetCreatePowerValue(Powers power) const
Definition Unit.cpp:9464
uint8 GetLevel() const
Definition Unit.h:903
bool IsInCombat() const
Definition Unit.h:1158
float GetTotalAttackPowerValue(WeaponAttackType attType) const
Definition Unit.cpp:9289
void RemoveUnitFlag(UnitFlags flags)
Definition Unit.h:969
ObjectGuid GetPetGUID() const
Definition Unit.h:1260
uint32 GetPhaseMask() const
Definition Object.h:370
Map * GetMap() const
Definition Object.h:451
std::string m_name
Definition Object.h:602
InstanceScript * GetInstanceScript() const
Definition Object.cpp:1088
void GetClosePoint(float &x, float &y, float &z, float size, float distance2d=0, float relAngle=0) const
Definition Object.cpp:3245
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2833
ZoneScript * GetZoneScript() const
Definition Object.h:457
std::string const & GetName() const
Definition Object.h:384
virtual void SetMap(Map *map)
Definition Object.cpp:1809
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:1193
void SetName(std::string newname)
Definition Object.h:385
float GetVisibilityRange() const
Definition Object.cpp:1493
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
std::string GetPlayerInfo() const
SQLQueryHolderCallback & AddQueryHolderCallback(SQLQueryHolderCallback &&callback)
#define sWorld
Definition World.h:901
@ CONFIG_MAX_PLAYER_LEVEL
Definition World.h:237
uint32 const Entry[5]
time_t GetGameTime()
Definition GameTime.cpp:42
uint32 GetGameTimeMS()
Definition GameTime.cpp:47
AuraCreateInfo & SetBaseAmount(int32 const *bp)
AuraCreateInfo & SetCasterGUID(ObjectGuid const &guid)
std::array< int32, MAX_SPELL_EFFECTS > BaseAmounts
Definition SpellAuras.h:112
std::array< int32, MAX_SPELL_EFFECTS > Amounts
Definition SpellAuras.h:111
TriggerCastFlags TriggerFlags
CastSpellExtraArgs & AddSpellMod(SpellValueMod mod, int32 val)
void SetIsCommandFollow(bool val)
Definition Unit.cpp:13159
uint32 GetPetNumber() const
Definition Unit.h:692
void LoadPetActionBar(const std::string &data)
Definition Unit.cpp:9929
void SetActionBar(uint8 index, uint32 spellOrAction, ActiveStates type)
Definition Unit.h:710
bool AddSpellToActionBar(SpellInfo const *spellInfo, ActiveStates newstate=ACT_DECIDE, uint8 preferredSlot=0)
Definition Unit.cpp:9859
void SetIsAtStay(bool val)
Definition Unit.cpp:13190
void SetPetNumber(uint32 petnumber, bool statwindow)
Definition Unit.cpp:9920
void SetIsFollowing(bool val)
Definition Unit.cpp:13200
void InitPetActionBar()
Definition Unit.cpp:9748
void SetIsReturning(bool val)
Definition Unit.cpp:13210
bool RemoveSpellFromActionBar(uint32 spell_id)
Definition Unit.cpp:9891
UnitActionBarEntry const * GetActionBarEntry(uint8 index) const
Definition Unit.h:714
bool HasCommandState(CommandStates state) const
Definition Unit.h:697
void SetIsCommandAttack(bool val)
Definition Unit.cpp:13149
float GenerateBaseDamage(CreatureTemplate const *info) const
uint32 GenerateMana(CreatureTemplate const *info) const
uint32 GenerateHealth(CreatureTemplate const *info) const
CreatureFamily family
int32 resistance[MAX_SPELL_SCHOOL]
bool IsTameable(bool canTameExotic) const
uint16 health
Definition ObjectMgr.h:702
uint32 armor
Definition ObjectMgr.h:704
uint16 minDamage
Definition ObjectMgr.h:705
uint16 stats[MAX_STATS]
Definition ObjectMgr.h:701
uint16 maxDamage
Definition ObjectMgr.h:706
uint16 mana
Definition ObjectMgr.h:703
Definition Pet.h:27
PetSpellState state
Definition Pet.h:29
PetSpellType type
Definition Pet.h:30
ActiveStates active
Definition Pet.h:28
ReactStates ReactState
Definition PetDefines.h:107
std::string Name
Definition PetDefines.h:95
std::string ActionBar
Definition PetDefines.h:96
std::string ToString() const
Definition Position.cpp:149
float GetPositionZ() const
Definition Position.h:81
float GetOrientation() const
Definition Position.h:82
bool IsPositionValid() const
Definition Position.cpp:44
float GetPositionX() const
Definition Position.h:79
float GetPositionY() const
Definition Position.h:80
void Relocate(float x, float y)
Definition Position.h:66
std::array< uint32, MAX_TALENT_RANK > SpellRank
ActiveStates GetType() const
Definition Unit.h:640
uint32 GetAction() const
Definition Unit.h:641