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;
1234 if (result)
1235 {
1236 do
1237 {
1238 int32 damage[3];
1239 int32 baseDamage[3];
1240 Field* fields = result->Fetch();
1241 casterGuid.SetRawValue(fields[0].GetUInt64());
1242 // NULL guid stored - pet is the caster of the spell - see Pet::_SaveAuras
1243 if (!casterGuid)
1244 casterGuid = GetGUID();
1245 uint32 spellid = fields[1].GetUInt32();
1246 uint8 effmask = fields[2].GetUInt8();
1247 uint8 recalculatemask = fields[3].GetUInt8();
1248 uint8 stackcount = fields[4].GetUInt8();
1249 damage[0] = fields[5].GetInt32();
1250 damage[1] = fields[6].GetInt32();
1251 damage[2] = fields[7].GetInt32();
1252 baseDamage[0] = fields[8].GetInt32();
1253 baseDamage[1] = fields[9].GetInt32();
1254 baseDamage[2] = fields[10].GetInt32();
1255 int32 maxduration = fields[11].GetInt32();
1256 int32 remaintime = fields[12].GetInt32();
1257 uint8 remaincharges = fields[13].GetUInt8();
1258 float critChance = fields[14].GetFloat();
1259 bool applyResilience = fields[15].GetBool();
1260
1261 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellid);
1262 if (!spellInfo)
1263 {
1264 TC_LOG_ERROR("entities.pet", "Unknown aura (spellid {}), ignore.", spellid);
1265 continue;
1266 }
1267
1268 // negative effects should continue counting down after logout
1269 if (remaintime != -1 && (!spellInfo->IsPositive() || spellInfo->HasAttribute(SPELL_ATTR4_FADES_WHILE_LOGGED_OUT)))
1270 {
1271 if (remaintime/IN_MILLISECONDS <= int32(timediff))
1272 continue;
1273
1274 remaintime -= timediff*IN_MILLISECONDS;
1275 }
1276
1277 // prevent wrong values of remaincharges
1278 if (spellInfo->ProcCharges)
1279 {
1280 if (remaincharges <= 0 || remaincharges > spellInfo->ProcCharges)
1281 remaincharges = spellInfo->ProcCharges;
1282 }
1283 else
1284 remaincharges = 0;
1285
1286 AuraCreateInfo createInfo(spellInfo, effmask, this);
1287 createInfo
1288 .SetCasterGUID(casterGuid)
1289 .SetBaseAmount(baseDamage);
1290
1291 if (Aura* aura = Aura::TryCreate(createInfo))
1292 {
1293 if (!aura->CanBeSaved())
1294 {
1295 aura->Remove();
1296 continue;
1297 }
1298 aura->SetLoadedState(maxduration, remaintime, remaincharges, stackcount, recalculatemask, critChance, applyResilience, &damage[0]);
1299 aura->ApplyForTargets();
1300 TC_LOG_DEBUG("entities.pet", "Added aura spellid {}, effectmask {}", spellInfo->Id, effmask);
1301 }
1302 }
1303 while (result->NextRow());
1304 }
1305}
1306
1308{
1310 stmt->setUInt32(0, m_charmInfo->GetPetNumber());
1311 trans->Append(stmt);
1312
1313 for (AuraMap::const_iterator itr = m_ownedAuras.begin(); itr != m_ownedAuras.end(); ++itr)
1314 {
1315 // check if the aura has to be saved
1316 if (!itr->second->CanBeSaved() || IsPetAura(itr->second))
1317 continue;
1318
1319 Aura* aura = itr->second;
1320
1321 int32 damage[MAX_SPELL_EFFECTS];
1322 int32 baseDamage[MAX_SPELL_EFFECTS];
1323 uint8 effMask = 0;
1324 uint8 recalculateMask = 0;
1325 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
1326 {
1327 if (aura->GetEffect(i))
1328 {
1329 baseDamage[i] = aura->GetEffect(i)->GetBaseAmount();
1330 damage[i] = aura->GetEffect(i)->GetAmount();
1331 effMask |= (1<<i);
1332 if (aura->GetEffect(i)->CanBeRecalculated())
1333 recalculateMask |= (1<<i);
1334 }
1335 else
1336 {
1337 baseDamage[i] = 0;
1338 damage[i] = 0;
1339 }
1340 }
1341
1342 // 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
1343 ObjectGuid casterGUID = (itr->second->GetCasterGUID() == GetGUID()) ? ObjectGuid::Empty : itr->second->GetCasterGUID();
1344
1345 uint8 index = 0;
1346
1347 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PET_AURA);
1348 stmt->setUInt32(index++, m_charmInfo->GetPetNumber());
1349 stmt->setUInt64(index++, casterGUID.GetRawValue());
1350 stmt->setUInt32(index++, itr->second->GetId());
1351 stmt->setUInt8(index++, effMask);
1352 stmt->setUInt8(index++, recalculateMask);
1353 stmt->setUInt8(index++, itr->second->GetStackAmount());
1354 stmt->setInt32(index++, damage[0]);
1355 stmt->setInt32(index++, damage[1]);
1356 stmt->setInt32(index++, damage[2]);
1357 stmt->setInt32(index++, baseDamage[0]);
1358 stmt->setInt32(index++, baseDamage[1]);
1359 stmt->setInt32(index++, baseDamage[2]);
1360 stmt->setInt32(index++, itr->second->GetMaxDuration());
1361 stmt->setInt32(index++, itr->second->GetDuration());
1362 stmt->setUInt8(index++, itr->second->GetCharges());
1363 stmt->setFloat(index++, itr->second->GetCritChance());
1364 stmt->setBool (index++, itr->second->CanApplyResilience());
1365
1366 trans->Append(stmt);
1367 }
1368}
1369
1370bool Pet::addSpell(uint32 spellId, ActiveStates active /*= ACT_DECIDE*/, PetSpellState state /*= PETSPELL_NEW*/, PetSpellType type /*= PETSPELL_NORMAL*/)
1371{
1372 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
1373 if (!spellInfo)
1374 {
1375 // do pet spell book cleanup
1376 if (state == PETSPELL_UNCHANGED) // spell load case
1377 {
1378 TC_LOG_ERROR("entities.pet", "Pet::addSpell: Non-existed in SpellStore spell #{} request, deleting for all pets in `pet_spell`.", spellId);
1379
1381
1382 stmt->setUInt32(0, spellId);
1383
1384 CharacterDatabase.Execute(stmt);
1385 }
1386 else
1387 TC_LOG_ERROR("entities.pet", "Pet::addSpell: Non-existed in SpellStore spell #{} request.", spellId);
1388
1389 return false;
1390 }
1391
1392 PetSpellMap::iterator itr = m_spells.find(spellId);
1393 if (itr != m_spells.end())
1394 {
1395 if (itr->second.state == PETSPELL_REMOVED)
1396 state = PETSPELL_CHANGED;
1397 else
1398 {
1399 if (state == PETSPELL_UNCHANGED && itr->second.state != PETSPELL_UNCHANGED)
1400 {
1401 // can be in case spell loading but learned at some previous spell loading
1402 itr->second.state = PETSPELL_UNCHANGED;
1403
1404 if (active == ACT_ENABLED)
1405 ToggleAutocast(spellInfo, true);
1406 else if (active == ACT_DISABLED)
1407 ToggleAutocast(spellInfo, false);
1408 }
1409
1410 return false;
1411 }
1412 }
1413
1414 PetSpell newspell;
1415 newspell.state = state;
1416 newspell.type = type;
1417
1418 if (active == ACT_DECIDE) // active was not used before, so we save it's autocast/passive state here
1419 {
1420 if (spellInfo->IsAutocastable())
1421 newspell.active = ACT_DISABLED;
1422 else
1423 newspell.active = ACT_PASSIVE;
1424 }
1425 else
1426 newspell.active = active;
1427
1428 // talent: unlearn all other talent ranks (high and low)
1429 if (TalentSpellPos const* talentPos = GetTalentSpellPos(spellId))
1430 {
1431 if (TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentPos->talent_id))
1432 {
1433 for (uint32 rankSpellId : talentInfo->SpellRank)
1434 {
1435 // skip learning spell and no rank spell case
1436 if (!rankSpellId || rankSpellId == spellId)
1437 continue;
1438
1439 // skip unknown ranks
1440 if (!HasSpell(rankSpellId))
1441 continue;
1442 removeSpell(rankSpellId, false, false);
1443 }
1444 }
1445 }
1446 else if (spellInfo->IsRanked())
1447 {
1448 for (PetSpellMap::const_iterator itr2 = m_spells.begin(); itr2 != m_spells.end(); ++itr2)
1449 {
1450 if (itr2->second.state == PETSPELL_REMOVED)
1451 continue;
1452
1453 SpellInfo const* oldRankSpellInfo = sSpellMgr->GetSpellInfo(itr2->first);
1454
1455 if (!oldRankSpellInfo)
1456 continue;
1457
1458 if (spellInfo->IsDifferentRankOf(oldRankSpellInfo))
1459 {
1460 // replace by new high rank
1461 if (spellInfo->IsHighRankOf(oldRankSpellInfo))
1462 {
1463 newspell.active = itr2->second.active;
1464
1465 if (newspell.active == ACT_ENABLED)
1466 ToggleAutocast(oldRankSpellInfo, false);
1467
1468 unlearnSpell(itr2->first, false, false);
1469 break;
1470 }
1471 // ignore new lesser rank
1472 else
1473 return false;
1474 }
1475 }
1476 }
1477
1478 m_spells[spellId] = newspell;
1479
1480 if (spellInfo->IsPassive() && (!spellInfo->CasterAuraState || HasAuraState(AuraStateType(spellInfo->CasterAuraState))))
1481 CastSpell(this, spellId, true);
1482 else
1483 m_charmInfo->AddSpellToActionBar(spellInfo);
1484
1485 if (newspell.active == ACT_ENABLED)
1486 ToggleAutocast(spellInfo, true);
1487
1488 uint32 talentCost = GetTalentSpellCost(spellId);
1489 if (talentCost)
1490 {
1491 int32 free_points = GetMaxTalentPointsForLevel(GetLevel());
1492 m_usedTalentCount += talentCost;
1493 // update free talent points
1494 free_points -= m_usedTalentCount;
1495 SetFreeTalentPoints(free_points > 0 ? free_points : 0);
1496 }
1497 return true;
1498}
1499
1501{
1502 // prevent duplicated entires in spell book
1503 if (!addSpell(spell_id))
1504 return false;
1505
1506 if (!m_loading)
1507 {
1509 packet.SpellID = spell_id;
1510 GetOwner()->SendDirectMessage(packet.Write());
1512 }
1513 return true;
1514}
1515
1517{
1518 uint8 level = GetLevel();
1519
1520 if (PetLevelupSpellSet const* levelupSpells = GetCreatureTemplate()->family ? sSpellMgr->GetPetLevelupSpellList(GetCreatureTemplate()->family) : nullptr)
1521 {
1522 // PetLevelupSpellSet ordered by levels, process in reversed order
1523 for (PetLevelupSpellSet::const_reverse_iterator itr = levelupSpells->rbegin(); itr != levelupSpells->rend(); ++itr)
1524 {
1525 // will called first if level down
1526 if (itr->first > level)
1527 unlearnSpell(itr->second, true); // will learn prev rank if any
1528 // will called if level up
1529 else
1530 learnSpell(itr->second); // will unlearn prev rank if any
1531 }
1532 }
1533
1535
1536 // default spells (can be not learned if pet level (as owner level decrease result for example) less first possible in normal game)
1537 if (PetDefaultSpellsEntry const* defSpells = sSpellMgr->GetPetDefaultSpellsEntry(petSpellsId))
1538 {
1539 for (uint32 spellId : defSpells->spellid)
1540 {
1541 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
1542 if (!spellInfo)
1543 continue;
1544
1545 // will called first if level down
1546 if (spellInfo->SpellLevel > level)
1547 unlearnSpell(spellInfo->Id, true);
1548 // will called if level up
1549 else
1550 learnSpell(spellInfo->Id);
1551 }
1552 }
1553}
1554
1555bool Pet::unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab)
1556{
1557 if (removeSpell(spell_id, learn_prev, clear_ab))
1558 {
1559 if (!m_loading)
1560 {
1562 packet.SpellID = spell_id;
1563 GetOwner()->SendDirectMessage(packet.Write());
1564 }
1565 return true;
1566 }
1567 return false;
1568}
1569
1570bool Pet::removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab)
1571{
1572 PetSpellMap::iterator itr = m_spells.find(spell_id);
1573 if (itr == m_spells.end())
1574 return false;
1575
1576 if (itr->second.state == PETSPELL_REMOVED)
1577 return false;
1578
1579 if (itr->second.state == PETSPELL_NEW)
1580 m_spells.erase(itr);
1581 else
1582 itr->second.state = PETSPELL_REMOVED;
1583
1584 RemoveAurasDueToSpell(spell_id);
1585
1586 uint32 talentCost = GetTalentSpellCost(spell_id);
1587 if (talentCost > 0)
1588 {
1589 if (m_usedTalentCount > talentCost)
1590 m_usedTalentCount -= talentCost;
1591 else
1593 // update free talent points
1595 SetFreeTalentPoints(free_points > 0 ? free_points : 0);
1596 }
1597
1598 if (learn_prev)
1599 {
1600 if (uint32 prev_id = sSpellMgr->GetPrevSpellInChain (spell_id))
1601 learnSpell(prev_id);
1602 else
1603 learn_prev = false;
1604 }
1605
1606 // if remove last rank or non-ranked then update action bar at server and client if need
1607 if (clear_ab && !learn_prev && m_charmInfo->RemoveSpellFromActionBar(spell_id))
1608 {
1609 if (!m_loading)
1610 GetOwner()->PetSpellInitialize(); // need update action bar for last removed rank
1611 }
1612
1613 return true;
1614}
1615
1617{
1618 for (uint8 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
1620 if (ab->GetAction() && ab->IsActionBarForSpell())
1621 {
1622 if (!HasSpell(ab->GetAction()))
1624 else if (ab->GetType() == ACT_ENABLED)
1625 {
1626 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(ab->GetAction()))
1627 ToggleAutocast(spellInfo, true);
1628 }
1629 }
1630}
1631
1633{
1635 m_spells.clear();
1636
1639
1640 CastPetAuras(false);
1641}
1642
1643bool Pet::resetTalents(bool involuntarily /*= false*/)
1644{
1645 Player* player = GetOwner();
1646
1647 // not need after this call
1650
1652 if (!ci)
1653 return false;
1654 // Check pet talent type
1655 CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family);
1656 if (!pet_family || pet_family->PetTalentType < 0)
1657 return false;
1658
1659 uint8 level = GetLevel();
1660 uint32 talentPointsForLevel = GetMaxTalentPointsForLevel(level);
1661
1662 if (m_usedTalentCount == 0)
1663 {
1664 SetFreeTalentPoints(talentPointsForLevel);
1665 return false;
1666 }
1667
1668 for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
1669 {
1670 TalentEntry const* talentInfo = sTalentStore.LookupEntry(i);
1671
1672 if (!talentInfo)
1673 continue;
1674
1675 TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TabID);
1676
1677 if (!talentTabInfo)
1678 continue;
1679
1680 // unlearn only talents for pets family talent type
1681 if (!((1 << pet_family->PetTalentType) & talentTabInfo->PetTalentMask))
1682 continue;
1683
1684 for (uint32 talentSpellId : talentInfo->SpellRank)
1685 {
1686 for (PetSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end();)
1687 {
1688 if (itr->second.state == PETSPELL_REMOVED)
1689 {
1690 ++itr;
1691 continue;
1692 }
1693 // remove learned spells (all ranks)
1694 uint32 itrFirstId = sSpellMgr->GetFirstSpellInChain(itr->first);
1695
1696 // unlearn if first rank is talent or learned by talent
1697 if (itrFirstId == talentSpellId || sSpellMgr->IsSpellLearnToSpell(talentSpellId, itrFirstId))
1698 {
1699 unlearnSpell(itr->first, false);
1700 itr = m_spells.begin();
1701 continue;
1702 }
1703 else
1704 ++itr;
1705 }
1706 }
1707 }
1708
1709 SetFreeTalentPoints(talentPointsForLevel);
1710
1711 if (!m_loading)
1712 player->PetSpellInitialize();
1713
1714 if (involuntarily)
1716
1717 return true;
1718}
1719
1720void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* onlinePet /*= nullptr*/, bool involuntarily /*= false*/)
1721{
1722 // not need after this call
1725
1726 // reset for online
1727 if (onlinePet)
1728 onlinePet->resetTalents(involuntarily);
1729
1730 PetStable* petStable = owner->GetPetStable();
1731 if (!petStable)
1732 return;
1733
1734 std::unordered_set<uint32> petIds;
1735 if (petStable->CurrentPet)
1736 petIds.insert(petStable->CurrentPet->PetNumber);
1737
1738 for (Optional<PetStable::PetInfo> const& stabledPet : petStable->StabledPets)
1739 if (stabledPet)
1740 petIds.insert(stabledPet->PetNumber);
1741
1742 for (PetStable::PetInfo const& unslottedPet : petStable->UnslottedPets)
1743 petIds.insert(unslottedPet.PetNumber);
1744
1745 // now need only reset for offline pets (all pets except online case)
1746 if (onlinePet)
1747 petIds.erase(onlinePet->GetCharmInfo()->GetPetNumber());
1748
1749 // no offline pets
1750 if (petIds.empty())
1751 return;
1752
1753 if (!onlinePet)
1755
1756 bool need_comma = false;
1757 std::ostringstream ss;
1758 ss << "DELETE FROM pet_spell WHERE guid IN (";
1759
1760 for (uint32 id : petIds)
1761 {
1762 if (need_comma)
1763 ss << ',';
1764
1765 ss << id;
1766
1767 need_comma = true;
1768 }
1769
1770 ss << ") AND spell IN (";
1771
1772 need_comma = false;
1773 for (uint32 spell : sPetTalentSpells)
1774 {
1775 if (need_comma)
1776 ss << ',';
1777
1778 ss << spell;
1779
1780 need_comma = true;
1781 }
1782
1783 ss << ')';
1784
1785 CharacterDatabase.Execute(ss.str().c_str());
1786}
1787
1789{
1790 uint8 level = GetLevel();
1791 uint32 talentPointsForLevel = GetMaxTalentPointsForLevel(level);
1792 // Reset talents in case low level (on level down) or wrong points for level (hunter can unlearn TP increase talent)
1793 if (talentPointsForLevel == 0 || m_usedTalentCount > talentPointsForLevel)
1794 resetTalents(); // Remove all talent points
1795
1796 SetFreeTalentPoints(talentPointsForLevel - m_usedTalentCount);
1797
1798 if (!m_loading)
1800}
1801
1803{
1804 uint8 points = (level >= 20) ? ((level - 16) / 4) : 0;
1805 // Mod points from owner SPELL_AURA_MOD_PET_TALENT_POINTS
1807 return points;
1808}
1809
1810void Pet::ToggleAutocast(SpellInfo const* spellInfo, bool apply)
1811{
1812 ASSERT(spellInfo);
1813
1814 if (!spellInfo->IsAutocastable())
1815 return;
1816
1817 PetSpellMap::iterator itr = m_spells.find(spellInfo->Id);
1818 if (itr == m_spells.end())
1819 return;
1820
1821 auto autospellItr = std::find(m_autospells.begin(), m_autospells.end(), spellInfo->Id);
1822
1823 if (apply)
1824 {
1825 if (autospellItr == m_autospells.end())
1826 {
1827 m_autospells.push_back(spellInfo->Id);
1828
1829 if (itr->second.active != ACT_ENABLED)
1830 {
1831 itr->second.active = ACT_ENABLED;
1832 if (itr->second.state != PETSPELL_NEW)
1833 itr->second.state = PETSPELL_CHANGED;
1834 }
1835 }
1836 }
1837 else
1838 {
1839 if (autospellItr != m_autospells.end())
1840 {
1841 m_autospells.erase(autospellItr);
1842
1843 if (itr->second.active != ACT_DISABLED)
1844 {
1845 itr->second.active = ACT_DISABLED;
1846 if (itr->second.state != PETSPELL_NEW)
1847 itr->second.state = PETSPELL_CHANGED;
1848 }
1849 }
1850 }
1851}
1852
1854{
1855 switch (getPetType())
1856 {
1857 case SUMMON_PET:
1858 switch (owner->GetClass())
1859 {
1860 case CLASS_WARLOCK:
1862 case CLASS_DEATH_KNIGHT:
1864 default:
1865 return false;
1866 }
1867 case HUNTER_PET:
1868 return true;
1869 default:
1870 return false;
1871 }
1872}
1873
1874bool Pet::Create(ObjectGuid::LowType guidlow, Map* map, uint32 phaseMask, uint32 Entry, uint32 petId)
1875{
1876 ASSERT(map);
1877 SetMap(map);
1878
1879 SetPhaseMask(phaseMask, false);
1880 Object::_Create(ObjectGuid::Create<HighGuid::Pet>(petId, guidlow));
1881
1883
1884 if (!InitEntry(Entry))
1885 return false;
1886
1887 // Force regen flag for player pets, just like we do for players themselves
1890
1892
1893 return true;
1894}
1895
1896bool Pet::HasSpell(uint32 spell) const
1897{
1898 PetSpellMap::const_iterator itr = m_spells.find(spell);
1899 return itr != m_spells.end() && itr->second.state != PETSPELL_REMOVED;
1900}
1901
1902// Get all passive spells in our skill line
1904{
1905 CreatureTemplate const* cInfo = GetCreatureTemplate();
1906 if (!cInfo)
1907 return;
1908
1909 CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cInfo->family);
1910 if (!cFamily)
1911 return;
1912
1913 PetFamilySpellsStore::const_iterator petStore = sPetFamilySpellsStore.find(cFamily->ID);
1914 if (petStore != sPetFamilySpellsStore.end())
1915 {
1916 // For general hunter pets skill 270
1917 // Passive 01~10, Passive 00 (20782, not used), Ferocious Inspiration (34457)
1918 // Scale 01~03 (34902~34904, bonus from owner, not used)
1919 for (uint32 spellId : petStore->second)
1921 }
1922}
1923
1924void Pet::CastPetAuras(bool current)
1925{
1926 Player* owner = GetOwner();
1927
1928 if (!IsPermanentPetFor(owner))
1929 return;
1930
1931 for (auto itr = owner->m_petAuras.begin(); itr != owner->m_petAuras.end();)
1932 {
1933 PetAura const* pa = *itr;
1934 ++itr;
1935
1936 if (!current && pa->IsRemovedOnChangePet())
1937 owner->RemovePetAura(pa);
1938 else
1939 CastPetAura(pa);
1940 }
1941}
1942
1943void Pet::CastPetAura(PetAura const* aura)
1944{
1945 uint32 auraId = aura->GetAura(GetEntry());
1946 if (!auraId)
1947 return;
1948
1949 CastSpellExtraArgs args;
1951
1952 if (auraId == 35696) // Demonic Knowledge
1954
1955 CastSpell(this, auraId, args);
1956}
1957
1958bool Pet::IsPetAura(Aura const* aura)
1959{
1960 Player* owner = GetOwner();
1961
1962 // if the owner has that pet aura, return true
1963 for (PetAura const* petAura : owner->m_petAuras)
1964 if (petAura->GetAura(GetEntry()) == aura->GetId())
1965 return true;
1966
1967 return false;
1968}
1969
1971{
1972 learnSpell(spellid);
1973
1974 if (uint32 next = sSpellMgr->GetNextSpellInChain(spellid))
1975 learnSpellHighRank(next);
1976}
1977
1979{
1980 Player* owner = GetOwner();
1981
1982 switch (getPetType())
1983 {
1984 // always same level
1985 case SUMMON_PET:
1986 GivePetLevel(owner->GetLevel());
1987 break;
1988 // can't be greater owner level
1989 case HUNTER_PET:
1990 if (GetLevel() > owner->GetLevel())
1991 GivePetLevel(owner->GetLevel());
1992 else if (GetLevel() + 5 < owner->GetLevel())
1993 GivePetLevel(owner->GetLevel() - 5);
1994 break;
1995 default:
1996 break;
1997 }
1998}
1999
2001{
2002 return Minion::GetOwner()->ToPlayer();
2003}
2004
2006{
2007 CreatureFamilyEntry const* creatureFamily = sCreatureFamilyStore.LookupEntry(GetCreatureTemplate()->family);
2008 if (creatureFamily && creatureFamily->MinScale > 0.0f && getPetType() == HUNTER_PET)
2009 {
2010 float scale;
2011 if (GetLevel() >= creatureFamily->MaxScaleLevel)
2012 scale = creatureFamily->MaxScale;
2013 else if (GetLevel() <= creatureFamily->MinScaleLevel)
2014 scale = creatureFamily->MinScale;
2015 else
2016 scale = creatureFamily->MinScale + float(GetLevel() - creatureFamily->MinScaleLevel) / creatureFamily->MaxScaleLevel * (creatureFamily->MaxScale - creatureFamily->MinScale);
2017
2018 return scale;
2019 }
2020
2022}
2023
2025{
2026 Guardian::SetDisplayId(modelId);
2027
2028 if (!isControlled())
2029 return;
2030
2031 if (GetOwner()->GetGroup())
2033}
2034
2036{
2037 std::ostringstream oss;
2038
2040 {
2041 oss << uint32(m_charmInfo->GetActionBarEntry(i)->GetType()) << ' '
2043 }
2044
2045 return oss.str();
2046}
2047
2048std::string Pet::GetDebugInfo() const
2049{
2050 std::stringstream sstr;
2051 sstr << Guardian::GetDebugInfo() << "\n"
2052 << std::boolalpha
2053 << "PetType: " << std::to_string(getPetType()) << " "
2054 << "PetNumber: " << m_charmInfo->GetPetNumber();
2055 return sstr.str();
2056}
@ 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:388
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:477
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:138
@ UNIT_MASK_CONTROLABLE_GUARDIAN
Definition Unit.h:372
@ UNIT_MASK_HUNTER_PET
Definition Unit.h:371
@ UNIT_MASK_PET
Definition Unit.h:368
#define MAX_UNIT_ACTION_BAR_INDEX
Definition Unit.h:670
@ MINDAMAGE
Definition Unit.h:152
@ MAXDAMAGE
Definition Unit.h:153
UnitMods
Definition Unit.h:157
@ UNIT_MOD_ARMOR
Definition Unit.h:171
@ UNIT_MOD_RESISTANCE_START
Definition Unit.h:187
@ UNIT_MOD_STAT_STAMINA
Definition Unit.h:160
@ ACTION_BAR_INDEX_END
Definition Unit.h:667
@ ACTION_BAR_INDEX_START
Definition Unit.h:664
DeathState
Definition Unit.h:210
@ CORPSE
Definition Unit.h:213
@ ALIVE
Definition Unit.h:211
@ JUST_DIED
Definition Unit.h:212
@ 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
bool CanBeRecalculated() const
int32 GetBaseAmount() const
int32 GetAmount() const
static Aura * TryCreate(AuraCreateInfo &createInfo)
uint32 GetId() const
Definition SpellAuras.h:116
AuraEffect * GetEffect(uint8 effIndex) const
Definition SpellAuras.h:201
void SetPhaseMask(uint32 newPhaseMask, bool update) override
Definition Creature.cpp:652
void setDeathState(DeathState s) override
void SetDisplayId(uint32 modelId) override
void Update(uint32 time) override
Definition Creature.cpp:670
void SetObjectScale(float scale) override
bool AIM_Initialize(CreatureAI *ai=nullptr)
void LoadTemplateImmunities()
void SetReactState(ReactStates st)
Definition Creature.h:119
std::string const & GetNameForLocaleIdx(LocaleConstant locale_idx) const override
time_t m_corpseRemoveTime
Definition Creature.h:387
static float _GetHealthMod(int32 Rank)
CreatureTemplate const * GetCreatureTemplate() const
Definition Creature.h:186
uint32 m_originalEntry
Definition Creature.h:411
float GetNativeObjectScale() const override
ReactStates GetReactState() const
Definition Creature.h:120
bool InitEntry(uint32 entry, CreatureData const *data=nullptr)
Definition Creature.cpp:440
void SetMeleeDamageSchool(SpellSchools school)
Definition Creature.h:159
void Regenerate(Powers power)
Definition Creature.cpp:881
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:281
MapStoredObjectTypesContainer & GetObjectsStore()
Definition Map.h:489
bool AddToMap(T *)
Definition Map.cpp:630
ObjectGuid::LowType GenerateLowGuid()
Definition Map.h:587
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
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:179
uint32 GetUInt32Value(uint16 index) const
Definition Object.cpp:249
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:188
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:585
ObjectGuid GetGUID() const
Definition Object.h:79
static Player * ToPlayer(Object *o)
Definition Object.h:180
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:1903
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:2000
bool IsPetAura(Aura const *aura)
Definition Pet.cpp:1958
bool unlearnSpell(uint32 spell_id, bool learn_prev, bool clear_ab=true)
Definition Pet.cpp:1555
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:1874
void SetDisplayId(uint32 modelId) override
Definition Pet.cpp:2024
void ToggleAutocast(SpellInfo const *spellInfo, bool apply)
Definition Pet.cpp:1810
static void resetTalentsForAllPetsOf(Player *owner, Pet *online_pet=nullptr, bool involuntarily=false)
Definition Pet.cpp:1720
void AddToWorld() override
Definition Pet.cpp:66
void InitTalentForLevel()
Definition Pet.cpp:1788
void CastPetAuras(bool current)
Definition Pet.cpp:1924
void setPetType(PetType type)
Definition Pet.h:52
void SavePetToDB(PetSaveMode mode)
Definition Pet.cpp:437
float GetNativeObjectScale() const override
Definition Pet.cpp:2005
void _SaveAuras(CharacterDatabaseTransaction trans)
Definition Pet.cpp:1307
PetType getPetType() const
Definition Pet.h:51
void SynchronizeLevelWithOwner()
Definition Pet.cpp:1978
std::unique_ptr< DeclinedName > m_declinedname
Definition Pet.h:163
uint8 GetMaxTalentPointsForLevel(uint8 level) const
Definition Pet.cpp:1802
void _SaveSpells(CharacterDatabaseTransaction trans)
Definition Pet.cpp:1180
void learnSpellHighRank(uint32 spellid)
Definition Pet.cpp:1970
bool IsPermanentPetFor(Player *owner) const
Definition Pet.cpp:1853
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:1370
AutoSpellList m_autospells
Definition Pet.h:129
void SetPetExperience(uint32 xp)
Definition Pet.h:86
std::string GetDebugInfo() const override
Definition Pet.cpp:2048
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:1570
bool CreateBaseAtCreature(Creature *creature)
Definition Pet.cpp:790
void CleanupActionBar()
Definition Pet.cpp:1616
bool isTemporarySummoned() const
Definition Pet.h:54
void CastPetAura(PetAura const *aura)
Definition Pet.cpp:1943
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 Update(uint32 diff) override
Definition Pet.cpp:607
void InitPetCreateSpells()
Definition Pet.cpp:1632
void _LoadAuras(PreparedQueryResult result, uint32 timediff)
Definition Pet.cpp:1229
bool HasSpell(uint32 spell) const override
Definition Pet.cpp:1896
bool resetTalents(bool involuntarily=false)
Definition Pet.cpp:1643
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:2035
bool learnSpell(uint32 spell_id)
Definition Pet.cpp:1500
int32 m_duration
Definition Pet.h:158
void InitLevelupSpellsForLevel()
Definition Pet.cpp:1516
void RemoveAtLoginFlag(AtLoginFlags flags, bool persist=false)
Definition Player.cpp:25536
void SendTalentsInfoData(bool pet)
Definition Player.cpp:25366
void SetGroupUpdateFlag(uint32 flag)
Definition Player.h:2177
uint32 GetTemporaryUnsummonedPetNumber() const
Definition Player.h:2124
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6161
bool CanTameExoticPets() const
Definition Player.h:1902
void SetTemporaryUnsummonedPetNumber(uint32 petnumber)
Definition Player.h:2125
bool IsPetNeedBeTemporaryUnsummoned() const
Definition Player.cpp:25231
PetStable * GetPetStable()
Definition Player.h:1067
void PetSpellInitialize()
Definition Player.cpp:20596
Pet * GetPet() const
Definition Player.cpp:20286
WorldSession * GetSession() const
Definition Player.h:1719
void RemovePet(Pet *pet, PetSaveMode mode, bool returnreagent=false)
Definition Player.cpp:20310
Group * GetGroup()
Definition Player.h:2171
std::unordered_set< PetAura const * > m_petAuras
Definition Player.h:1077
bool HasAtLoginFlag(AtLoginFlags f) const
Definition Player.h:2113
void RemovePetAura(PetAura const *petSpell)
Definition Player.cpp:20407
void SendMessageToSet(WorldPacket const *data, bool self) const override
Definition Player.h:1747
void SetLastPetNumber(uint32 petnumber)
Definition Player.h:2163
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:769
void ReplaceAllDynamicFlags(uint32 flag) override
Definition Unit.h:819
void SetMinion(Minion *minion, bool apply)
Definition Unit.cpp:5910
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition Unit.cpp:8439
bool HasPetFlag(UnitPetFlag flags) const
Definition Unit.h:993
bool IsHunterPet() const
Definition Unit.h:885
void SetCreateStat(Stats stat, float val)
Definition Unit.h:1448
void SetGender(Gender gender)
Definition Unit.h:899
void SetFullHealth()
Definition Unit.h:927
ThreatManager & GetThreatManager()
Definition Unit.h:1155
void AddToWorld() override
Definition Unit.cpp:9592
uint8 GetClass() const
Definition Unit.h:895
void SetCreateHealth(uint32 val)
Definition Unit.h:1449
void SetFaction(uint32 faction) override
Definition Unit.h:974
ObjectGuid GetOwnerGUID() const override
Definition Unit.h:1241
void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value, uint8 damageIndex=0)
Definition Unit.h:1552
CharmInfo * m_charmInfo
Definition Unit.h:1889
void ReplaceAllUnitFlags(UnitFlags flags)
Definition Unit.h:956
bool IsPet() const
Definition Unit.h:884
Powers GetPowerType() const
Definition Unit.h:931
void SetCreatedBySpell(int32 spellId)
Definition Unit.h:964
uint32 GetMaxHealth() const
Definition Unit.h:914
Aura * AddAura(uint32 spellId, Unit *target)
Definition Unit.cpp:11964
void SetUnitFlag2(UnitFlags2 flags)
Definition Unit.h:960
void ReplaceAllPetFlags(UnitPetFlag flags)
Definition Unit.h:996
void SetPetNameTimestamp(uint32 timestamp)
Definition Unit.h:1291
bool IsAlive() const
Definition Unit.h:1234
float GetCombatReach() const override
Definition Unit.h:839
DeathState m_deathState
Definition Unit.h:1852
uint32 m_unitTypeMask
Definition Unit.h:1901
void SetHealth(uint32 val)
Definition Unit.cpp:9361
void SetMaxPower(Powers power, uint32 val)
Definition Unit.cpp:9462
CharmInfo * GetCharmInfo()
Definition Unit.h:1287
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4535
void SetNativeDisplayId(uint32 displayId)
Definition Unit.h:1586
void SetCreateMana(uint32 val)
Definition Unit.h:1451
virtual void SetSheath(SheathState sheathed)
Definition Unit.h:970
uint32 GetDisplayId() const
Definition Unit.h:1582
uint32 GetNativeDisplayId() const
Definition Unit.h:1584
bool isPossessed() const
Definition Unit.h:1282
uint32 GetMaxPower(Powers power) const
Definition Unit.h:936
uint32 GetHealth() const
Definition Unit.h:913
uint32 GetFaction() const override
Definition Unit.h:973
void SetPower(Powers power, uint32 val, bool withPowerUpdate=true, bool force=false)
Definition Unit.cpp:9421
bool HasAuraState(AuraStateType flag, SpellInfo const *spellProto=nullptr, Unit const *Caster=nullptr) const
Definition Unit.cpp:5815
uint32 GetArmor() const
Definition Unit.h:905
int32 GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:4792
void SetFullPower(Powers power)
Definition Unit.h:941
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3784
void SetPowerType(Powers power, bool sendUpdate=true)
Definition Unit.cpp:5408
DeathState getDeathState() const
Definition Unit.h:1238
bool IsCritter() const
Definition Unit.h:1117
AuraMap m_ownedAuras
Definition Unit.h:1866
void SetLevel(uint8 lvl, bool sendUpdate=true)
Definition Unit.cpp:9344
void SetCanModifyStats(bool modifyStats)
Definition Unit.h:1532
CharmInfo * InitCharmInfo()
Definition Unit.cpp:9730
void SetClass(uint8 classId)
Definition Unit.h:896
void RemoveFromWorld() override
Definition Unit.cpp:9601
float GetStat(Stats stat) const
Definition Unit.h:903
void RemoveAllAuras()
Definition Unit.cpp:4157
SpellHistory * GetSpellHistory()
Definition Unit.h:1484
void SetCreatorGUID(ObjectGuid creator)
Definition Unit.h:1244
uint32 GetPower(Powers power) const
Definition Unit.h:934
void SetAttackTime(WeaponAttackType att, uint32 val)
Definition Unit.h:946
void SetModCastingSpeed(float castingSpeed)
Definition Unit.h:950
void ReplaceAllNpcFlags(NPCFlags flags)
Definition Unit.h:1099
int32 SpellBaseDamageBonusDone(SpellSchoolMask schoolMask) const
Definition Unit.cpp:6987
void SetStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float val)
Definition Unit.cpp:9066
uint32 GetCreatePowerValue(Powers power) const
Definition Unit.cpp:9487
uint8 GetLevel() const
Definition Unit.h:889
bool IsInCombat() const
Definition Unit.h:1144
float GetTotalAttackPowerValue(WeaponAttackType attType) const
Definition Unit.cpp:9312
void RemoveUnitFlag(UnitFlags flags)
Definition Unit.h:955
ObjectGuid GetPetGUID() const
Definition Unit.h:1247
uint32 GetPhaseMask() const
Definition Object.h:368
Map * GetMap() const
Definition Object.h:449
std::string m_name
Definition Object.h:600
InstanceScript * GetInstanceScript() const
Definition Object.cpp:1087
void GetClosePoint(float &x, float &y, float &z, float size, float distance2d=0, float relAngle=0) const
Definition Object.cpp:3244
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2832
ZoneScript * GetZoneScript() const
Definition Object.h:455
std::string const & GetName() const
Definition Object.h:382
virtual void SetMap(Map *map)
Definition Object.cpp:1808
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:1192
void SetName(std::string newname)
Definition Object.h:383
float GetVisibilityRange() const
Definition Object.cpp:1492
WorldPacket const * Write() override
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:900
@ CONFIG_MAX_PLAYER_LEVEL
Definition World.h:236
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)
TriggerCastFlags TriggerFlags
CastSpellExtraArgs & AddSpellMod(SpellValueMod mod, int32 val)
void SetIsCommandFollow(bool val)
Definition Unit.cpp:13183
uint32 GetPetNumber() const
Definition Unit.h:678
void LoadPetActionBar(const std::string &data)
Definition Unit.cpp:9952
void SetActionBar(uint8 index, uint32 spellOrAction, ActiveStates type)
Definition Unit.h:696
bool AddSpellToActionBar(SpellInfo const *spellInfo, ActiveStates newstate=ACT_DECIDE, uint8 preferredSlot=0)
Definition Unit.cpp:9882
void SetIsAtStay(bool val)
Definition Unit.cpp:13214
void SetPetNumber(uint32 petnumber, bool statwindow)
Definition Unit.cpp:9943
void SetIsFollowing(bool val)
Definition Unit.cpp:13224
void InitPetActionBar()
Definition Unit.cpp:9771
void SetIsReturning(bool val)
Definition Unit.cpp:13234
bool RemoveSpellFromActionBar(uint32 spell_id)
Definition Unit.cpp:9914
UnitActionBarEntry const * GetActionBarEntry(uint8 index) const
Definition Unit.h:700
bool HasCommandState(CommandStates state) const
Definition Unit.h:683
void SetIsCommandAttack(bool val)
Definition Unit.cpp:13173
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:708
uint32 armor
Definition ObjectMgr.h:710
uint16 minDamage
Definition ObjectMgr.h:711
uint16 stats[MAX_STATS]
Definition ObjectMgr.h:707
uint16 maxDamage
Definition ObjectMgr.h:712
uint16 mana
Definition ObjectMgr.h:709
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:626
uint32 GetAction() const
Definition Unit.h:627