TrinityCore
Creature.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 "Creature.h"
19#include "BattlegroundMgr.h"
20#include "CellImpl.h"
21#include "CharmInfo.h"
22#include "CombatPackets.h"
23#include "Containers.h"
24#include "CreatureAI.h"
25#include "CreatureAISelector.h"
26#include "CreatureGroups.h"
27#include "DatabaseEnv.h"
28#include "DB2Stores.h"
29#include "Formulas.h"
30#include "GameEventMgr.h"
31#include "GameTime.h"
32#include "GridNotifiersImpl.h"
33#include "Group.h"
34#include "ItemTemplate.h"
35#include "Log.h"
36#include "Loot.h"
37#include "LootMgr.h"
38#include "MapManager.h"
39#include "MiscPackets.h"
40#include "MotionMaster.h"
41#include "ObjectAccessor.h"
42#include "ObjectMgr.h"
43#include "PhasingHandler.h"
44#include "Player.h"
45#include "PoolMgr.h"
46#include "QueryPackets.h"
47#include "ScriptedGossip.h"
48#include "Spell.h"
49#include "SpellAuraEffects.h"
50#include "SpellMgr.h"
51#include "TemporarySummon.h"
52#include "Vehicle.h"
53#include "World.h"
54#include "ZoneScript.h"
55#include <G3D/g3dmath.h>
56#include <sstream>
57
59Random(CreatureRandomMovementType::Walk), InteractionPauseTimer(sWorld->getIntConfig(CONFIG_CREATURE_STOP_FOR_PLAYER)) { }
60
62{
63 char const* const ChaseStates[] = { "Run", "CanWalk", "AlwaysWalk" };
64 char const* const RandomStates[] = { "Walk", "CanRun", "AlwaysRun" };
65
66 std::ostringstream str;
67 str << std::boolalpha
68 << ", HoverInitiallyEnabled: " << HoverInitiallyEnabled
69 << ", Chase: " << ChaseStates[AsUnderlyingType(Chase)]
70 << ", Random: " << RandomStates[AsUnderlyingType(Random)];
71 str << ", InteractionPauseTimer: " << InteractionPauseTimer;
72
73 return str.str();
74}
75
77 : itemId(_item), count(_count), lastIncrementTime(GameTime::GetGameTime()) { }
78
80{
81 auto newEnd = std::remove_if(m_items.begin(), m_items.end(), [=](VendorItem const& vendorItem)
82 {
83 return vendorItem.item == item_id && vendorItem.Type == type;
84 });
85
86 bool found = newEnd != m_items.end();
87 m_items.erase(newEnd, m_items.end());
88 return found;
89}
90
91VendorItem const* VendorItemData::FindItemCostPair(uint32 item_id, uint32 extendedCost, uint8 type) const
92{
93 for (VendorItem const& vendorItem : m_items)
94 if (vendorItem.item == item_id && vendorItem.ExtendedCost == extendedCost && vendorItem.Type == type)
95 return &vendorItem;
96 return nullptr;
97}
98
101
103{
104 return idx < Models.size() ? &Models[idx] : nullptr;
105}
106
108{
109 if (!Models.size())
110 return nullptr;
111
112 // If only one element, ignore the Probability (even if 0)
113 if (Models.size() == 1)
114 return &Models[0];
115
117 {
118 return model.Probability;
119 });
120
121 return &(*selectedItr);
122}
123
125{
126 for (CreatureModel const& model : Models)
127 if (model.CreatureDisplayID)
128 return &model;
129
130 return nullptr;
131}
132
134{
135 for (CreatureModel const& model : Models)
136 if (displayId == model.CreatureDisplayID)
137 return &model;
138
139 return nullptr;
140}
141
143{
144 for (CreatureModel const& model : Models)
145 if (CreatureModelInfo const* modelInfo = sObjectMgr->GetCreatureModelInfo(model.CreatureDisplayID))
146 if (modelInfo && modelInfo->is_trigger)
147 return &model;
148
150}
151
153{
154 for (CreatureModel const& model : Models)
155 if (CreatureModelInfo const* modelInfo = sObjectMgr->GetCreatureModelInfo(model.CreatureDisplayID))
156 if (modelInfo && !modelInfo->is_trigger)
157 return &model;
158
160}
161
163{
164 for (uint8 loc = LOCALE_enUS; loc < TOTAL_LOCALES; ++loc)
165 QueryData[loc] = BuildQueryData(static_cast<LocaleConstant>(loc), DIFFICULTY_NONE);
166}
167
169{
170 CreatureDifficulty const* creatureDifficulty = GetDifficulty(difficulty);
171
173
174 queryTemp.CreatureID = Entry;
175
176 queryTemp.Allow = true;
177
178 WorldPackets::Query::CreatureStats& stats = queryTemp.Stats;
179
180 stats.Leader = RacialLeader;
181
182 stats.Name[0] = Name;
183 stats.NameAlt[0] = FemaleName;
184
185 stats.Flags[0] = creatureDifficulty->TypeFlags;
186 stats.Flags[1] = creatureDifficulty->TypeFlags2;
187
188 stats.CreatureType = type;
189 stats.CreatureFamily = family;
191
192 for (uint32 i = 0; i < MAX_KILL_CREDIT; ++i)
193 stats.ProxyCreatureID[i] = KillCredit[i];
194
195 std::transform(Models.begin(), Models.end(), std::back_inserter(stats.Display.CreatureDisplay),
197 {
198 stats.Display.TotalProbability += model.Probability;
199 return { model.CreatureDisplayID, model.DisplayScale, model.Probability };
200 });
201
202 stats.HpMulti = creatureDifficulty->HealthModifier;
203 stats.EnergyMulti = creatureDifficulty->ManaModifier;
204
205 stats.CreatureMovementInfoID = movementId;
206 stats.RequiredExpansion = RequiredExpansion;
207 stats.HealthScalingExpansion = creatureDifficulty->HealthScalingExpansion;
208 stats.VignetteID = VignetteID;
209 stats.Class = unit_class;
210 stats.CreatureDifficultyID = creatureDifficulty->CreatureDifficultyID;
211 stats.WidgetSetID = WidgetSetID;
212 stats.WidgetSetUnitConditionID = WidgetSetUnitConditionID;
213
214 stats.Title = SubName;
215 stats.TitleAlt = TitleAlt;
216 stats.CursorName = IconName;
217
218 if (std::vector<uint32> const* items = sObjectMgr->GetCreatureQuestItemList(Entry, difficulty))
219 stats.QuestItems.assign(items->begin(), items->end());
220
221 if (std::vector<int32> const* currencies = sObjectMgr->GetCreatureQuestCurrencyList(Entry))
222 stats.QuestCurrencies.assign(currencies->begin(), currencies->end());
223
224 if (loc != LOCALE_enUS)
225 if (CreatureLocale const* creatureLocale = sObjectMgr->GetCreatureLocale(Entry))
226 {
227 ObjectMgr::GetLocaleString(creatureLocale->Name, loc, stats.Name[0]);
228 ObjectMgr::GetLocaleString(creatureLocale->NameAlt, loc, stats.NameAlt[0]);
229 ObjectMgr::GetLocaleString(creatureLocale->Title, loc, stats.Title);
230 ObjectMgr::GetLocaleString(creatureLocale->TitleAlt, loc, stats.TitleAlt);
231 }
232
233 queryTemp.Write();
234 queryTemp.ShrinkToFit();
235 return queryTemp.Move();
236}
237
239{
240 auto it = difficultyStore.find(difficulty);
241 if (it != difficultyStore.end())
242 return &it->second;
243
244 // If there is no data for the difficulty, try to get data for the fallback difficulty
245 DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(difficulty);
246 if (difficultyEntry)
247 return GetDifficulty(Difficulty(difficultyEntry->FallbackDifficultyID));
248
249 // No data for DIFFICULTY_NONE (0)
250 struct DefaultCreatureDifficulty : public CreatureDifficulty
251 {
252 DefaultCreatureDifficulty()
253 {
254 DeltaLevelMin = 0;
255 DeltaLevelMax = 0;
256 ContentTuningID = 0;
257 HealthScalingExpansion = 0;
258 HealthModifier = 1.f;
259 ManaModifier = 1.f;
260 ArmorModifier = 1.f;
261 DamageModifier = 1.f;
262 CreatureDifficultyID = 0;
263 TypeFlags = 0;
264 TypeFlags2 = 0;
265 LootID = 0;
266 PickPocketLootID = 0;
267 SkinLootID = 0;
268 GoldMin = 0;
269 GoldMax = 0;
270 }
271 };
272 static const DefaultCreatureDifficulty defDifficulty;
273 return &defDifficulty;
274}
275
276bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
277{
279 {
280 while (!m_assistants.empty())
281 {
283 m_assistants.pop_front();
284
285 if (assistant && assistant->CanAssistTo(&m_owner, victim))
286 {
287 assistant->SetNoCallAssistance(true);
288 assistant->EngageWithTarget(victim);
289 }
290 }
291 }
292 return true;
293}
294
296{
297 return sObjectMgr->GetCreatureBaseStats(level, unitClass);
298}
299
301{
302 m_owner.DespawnOrUnsummon(0s, m_respawnTimer); // since we are here, we are not TempSummon as object type cannot change during runtime
303 return true;
304}
305
306Creature::Creature(bool isWorldObject) : Unit(isWorldObject), MapObject(), m_PlayerDamageReq(0), m_dontClearTapListOnEvade(false), _pickpocketLootRestore(0),
307 m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_ignoreCorpseDecayRatio(false), m_wanderDistance(0.0f), m_boundaryCheckTime(2500), m_combatPulseTime(0), m_combatPulseDelay(0), m_reactState(REACT_AGGRESSIVE),
308 m_defaultMovementType(IDLE_MOTION_TYPE), m_spawnId(UI64LIT(0)), m_equipmentId(0), m_originalEquipmentId(0), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_cannotReachTarget(false), m_cannotReachTimer(0),
309 m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_creatureDifficulty(nullptr), _waypointPathId(0), _currentWaypointNodeInfo(0, 0),
310 m_formation(nullptr), m_triggerJustAppeared(true), m_respawnCompatibilityMode(false), _lastDamagedTime(0),
311 _regenerateHealth(true), _creatureImmunitiesId(0), _gossipMenuId(0), _sparringHealthPct(0)
312{
314
315 for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)
316 m_spells[i] = 0;
317
318 DisableReputationGain = false;
319
321 m_CombatDistance = 0;//MELEE_RANGE;
322
323 ResetLootMode(); // restore default loot mode
324 m_isTempWorldObject = false;
325}
326
327Creature::~Creature() = default;
328
330{
332 if (!IsInWorld())
333 {
335 if (m_spawnId)
336 GetMap()->GetCreatureBySpawnIdStore().insert(std::make_pair(m_spawnId, this));
337
341 if (IsVehicle())
343
344 if (GetZoneScript())
346 }
347}
348
350{
351 if (IsInWorld())
352 {
353 if (GetZoneScript())
355
356 if (m_formation)
357 sFormationMgr->RemoveCreatureFromGroup(m_formation, this);
358
360
361 if (m_spawnId)
362 Trinity::Containers::MultimapErasePair(GetMap()->GetCreatureBySpawnIdStore(), m_spawnId, this);
364 }
365}
366
368{
369 if (GetMotionMaster()->GetCurrentMovementGeneratorType() == HOME_MOTION_TYPE)
370 return true;
371
372 return false;
373}
374
376{
377 if (IsSummon())
378 return;
379
381 if (!lowguid)
382 return;
383
384 if (FormationInfo const* formationInfo = sFormationMgr->GetFormationInfo(lowguid))
385 sFormationMgr->AddCreatureToGroup(formationInfo->LeaderSpawnId, this);
386}
387
389{
390 if (!m_formation)
391 return false;
392
393 return m_formation->IsLeader(this);
394}
395
397{
398 if (!m_formation)
399 return;
400
401 if (!m_formation->IsLeader(this))
402 return;
403
405}
406
408{
409 if (!m_formation)
410 return false;
411
413}
414
415void Creature::RemoveCorpse(bool setSpawnTime, bool destroyForNearbyPlayers)
416{
417 if (getDeathState() != CORPSE)
418 return;
419
421 {
425 m_loot = nullptr;
426 uint32 respawnDelay = m_respawnDelay;
427 if (CreatureAI* ai = AI())
428 ai->CorpseRemoved(respawnDelay);
429
430 if (destroyForNearbyPlayers)
432
433 // Should get removed later, just keep "compatibility" with scripts
434 if (setSpawnTime)
435 m_respawnTime = std::max<time_t>(GameTime::GetGameTime() + respawnDelay, m_respawnTime);
436
437 // if corpse was removed during falling, the falling will continue and override relocation to respawn position
438 if (IsFalling())
439 StopMoving();
440
441 float x, y, z, o;
442 GetRespawnPosition(x, y, z, &o);
443
444 // We were spawned on transport, calculate real position
446 {
448 pos.m_positionX = x;
449 pos.m_positionY = y;
450 pos.m_positionZ = z;
451 pos.SetOrientation(o);
452
453 if (TransportBase* transport = GetDirectTransport())
454 transport->CalculatePassengerPosition(x, y, z, &o);
455 }
456
457 UpdateAllowedPositionZ(x, y, z);
458 SetHomePosition(x, y, z, o);
459 GetMap()->CreatureRelocation(this, x, y, z, o);
460 }
461 else
462 {
463 if (CreatureAI* ai = AI())
464 ai->CorpseRemoved(m_respawnDelay);
465
466 // In case this is called directly and normal respawn timer not set
467 // Since this timer will be longer than the already present time it
468 // will be ignored if the correct place added a respawn timer
469 if (setSpawnTime)
470 {
471 uint32 respawnDelay = m_respawnDelay;
472 m_respawnTime = std::max<time_t>(GameTime::GetGameTime() + respawnDelay, m_respawnTime);
473
475 }
476
477 if (TempSummon* summon = ToTempSummon())
478 summon->UnSummon();
479 else
481 }
482}
483
487bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/)
488{
489 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(entry);
490 if (!creatureInfo)
491 {
492 TC_LOG_ERROR("sql.sql", "Creature::InitEntry creature entry {} does not exist.", entry);
493 return false;
494 }
495
496 m_creatureInfo = creatureInfo;
497 SetEntry(entry);
498 m_creatureDifficulty = creatureInfo->GetDifficulty(!IsPet() ? GetMap()->GetDifficultyID() : DIFFICULTY_NONE);
499
500 // equal to player Race field, but creature does not have race
502
503 // known valid are: CLASS_WARRIOR, CLASS_PALADIN, CLASS_ROGUE, CLASS_MAGE
504 SetClass(uint8(creatureInfo->unit_class));
505
506 // Cancel load if no model defined
507 if (!(creatureInfo->GetFirstValidModel()))
508 {
509 TC_LOG_ERROR("sql.sql", "Creature (Entry: {}) has no model defined in table `creature_template`, can't load. ", entry);
510 return false;
511 }
512
513 CreatureModel model = *ObjectMgr::ChooseDisplayId(creatureInfo, data);
514 CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelRandomGender(&model, creatureInfo);
515 if (!minfo) // Cancel load if no model defined
516 {
517 TC_LOG_ERROR("sql.sql", "Creature (Entry: {}) has invalid model {} defined in table `creature_template`, can't load.", entry, model.CreatureDisplayID);
518 return false;
519 }
520
521 SetDisplayId(model.CreatureDisplayID, true);
522
523 // Load creature equipment
524 if (!data)
525 LoadEquipment(); // use default equipment (if available) for summons
526 else if (data->equipmentId == 0)
527 LoadEquipment(0); // 0 means no equipment for creature table
528 else
529 {
532 }
533
534 SetName(creatureInfo->Name); // at normal entry always
535
536 SetModCastingSpeed(1.0f);
537 SetModSpellHaste(1.0f);
538 SetModHaste(1.0f);
539 SetModRangedHaste(1.0f);
540 SetModHasteRegen(1.0f);
541 SetModTimeRate(1.0f);
542
543 SetSpeedRate(MOVE_WALK, creatureInfo->speed_walk);
544 SetSpeedRate(MOVE_RUN, creatureInfo->speed_run);
545 SetSpeedRate(MOVE_SWIM, 1.0f); // using 1.0 rate
546 SetSpeedRate(MOVE_FLIGHT, 1.0f); // using 1.0 rate
547
548 // Will set UNIT_FIELD_BOUNDINGRADIUS, UNIT_FIELD_COMBATREACH and UNIT_FIELD_DISPLAYSCALE
550
552
553 // checked at loading
557
558 for (uint8 i = 0; i < MAX_CREATURE_SPELLS; ++i)
560
562
564 || IsPet()
565 || IsTotem()
566 || creatureInfo->flags_extra & CREATURE_FLAG_EXTRA_NO_XP);
567
568 // TODO: migrate these in DB
573
574 return true;
575}
576
577bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/, bool updateLevel /* = true */)
578{
579 if (!InitEntry(entry, data))
580 return false;
581
582 CreatureTemplate const* cInfo = GetCreatureTemplate();
583
585
586 // creatures always have melee weapon ready if any unless specified otherwise
587 if (!GetCreatureAddon())
589
590 SetFaction(cInfo->faction);
591
592 uint64 npcFlags;
593 uint32 unitFlags, unitFlags2, unitFlags3;
594 ObjectMgr::ChooseCreatureFlags(cInfo, &npcFlags, &unitFlags, &unitFlags2, &unitFlags3, _staticFlags, data);
595
597 npcFlags |= sGameEventMgr->GetNPCFlag(this);
598
599 ReplaceAllNpcFlags(NPCFlags(npcFlags & 0xFFFFFFFF));
600 ReplaceAllNpcFlags2(NPCFlags2(npcFlags >> 32));
601
602 // if unit is in combat, keep this flag
603 unitFlags &= ~UNIT_FLAG_IN_COMBAT;
604 if (IsInCombat())
605 unitFlags |= UNIT_FLAG_IN_COMBAT;
606
607 ReplaceAllUnitFlags(UnitFlags(unitFlags));
608 ReplaceAllUnitFlags2(UnitFlags2(unitFlags2));
609 ReplaceAllUnitFlags3(UnitFlags3(unitFlags3));
610
612
614
616
620
621 if (updateLevel)
622 SelectLevel();
623 else if (!IsGuardian())
624 {
625 uint32 previousHealth = GetHealth();
626 UpdateLevelDependantStats(); // We still re-initialize level dependant stats on entry update
627 if (previousHealth > 0)
628 SetHealth(previousHealth);
629 }
630
631 // Do not update guardian stats here - they are handled in Guardian::InitStatsForLevel()
632 if (!IsGuardian())
633 {
641
642 SetCanModifyStats(true);
644 }
645
646 // checked and error show at loading templates
647 if (FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction))
648 {
649 SetPvP((factionTemplate->Flags & FACTION_TEMPLATE_FLAG_PVP) != 0);
650 if (IsTaxi())
651 {
652 uint32 taxiNodesId = sObjectMgr->GetNearestTaxiNode(GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId(),
653 factionTemplate->FactionGroup & FACTION_MASK_ALLIANCE ? ALLIANCE : HORDE);
655 }
656 }
657
658 // updates spell bars for vehicles and set player's faction - should be called here, to overwrite faction that is set from the new template
659 if (IsVehicle())
660 {
661 if (Player* owner = Creature::GetCharmerOrOwnerPlayerOrPlayerItself()) // this check comes in case we don't have a player
662 {
663 SetFaction(owner->GetFaction()); // vehicles should have same as owner faction
664 owner->VehicleSpellInitialize();
665 }
666 }
667
668 // trigger creature is always uninteractible and can not be attacked
669 if (IsTrigger())
670 SetUninteractible(true);
671
674
676
678 {
681 }
682
684
686
690
692
693 //We must update last scriptId or it looks like we reloaded a script, breaking some things such as gossip temporarily
695
696 m_stringIds[0] = cInfo->StringId;
697
698 return true;
699}
700
702{
704
705 // Apply all other side effects of flag changes
707}
708
710{
712 {
715
718 m_triggerJustAppeared = false;
719 AI()->JustAppeared();
720 }
721
723
724 switch (m_deathState)
725 {
726 case JUST_RESPAWNED:
727 // Must not be called, see Creature::setDeathState JUST_RESPAWNED -> ALIVE promoting.
728 TC_LOG_ERROR("entities.unit", "Creature {} in wrong state: JUST_RESPAWNED (4)", GetGUID().ToString());
729 break;
730 case JUST_DIED:
731 // Must not be called, see Creature::setDeathState JUST_DIED -> CORPSE promoting.
732 TC_LOG_ERROR("entities.unit", "Creature {} in wrong state: JUST_DIED (1)", GetGUID().ToString());
733 break;
734 case DEAD:
735 {
737 {
738 TC_LOG_ERROR("entities.unit", "Creature {} in wrong state: DEAD (3)", GetGUID().ToString());
739 break;
740 }
741 time_t now = GameTime::GetGameTime();
742 if (m_respawnTime <= now)
743 {
744 // Delay respawn if spawn group is not active
745 if (m_creatureData && !GetMap()->IsSpawnGroupActive(m_creatureData->spawnGroupData->groupId))
746 {
747 m_respawnTime = now + urand(4,7);
748 break; // Will be rechecked on next Update call after delay expires
749 }
750
751 ObjectGuid dbtableHighGuid = ObjectGuid::Create<HighGuid::Creature>(GetMapId(), GetEntry(), m_spawnId);
752 time_t linkedRespawnTime = GetMap()->GetLinkedRespawnTime(dbtableHighGuid);
753 if (!linkedRespawnTime) // Can respawn
754 Respawn();
755 else // the master is dead
756 {
757 ObjectGuid targetGuid = sObjectMgr->GetLinkedRespawnGuid(dbtableHighGuid);
758 if (targetGuid == dbtableHighGuid) // if linking self, never respawn
760 else
761 {
762 // else copy time from master and add a little
763 time_t baseRespawnTime = std::max(linkedRespawnTime, now);
764 time_t const offset = urand(5, MINUTE);
765
766 // linked guid can be a boss, uses std::numeric_limits<time_t>::max to never respawn in that instance
767 // we shall inherit it instead of adding and causing an overflow
768 if (baseRespawnTime <= std::numeric_limits<time_t>::max() - offset)
769 m_respawnTime = baseRespawnTime + offset;
770 else
771 m_respawnTime = std::numeric_limits<time_t>::max();
772 }
773 SaveRespawnTime(); // also save to DB immediately
774 }
775 }
776 break;
777 }
778 case CORPSE:
779 {
780 Unit::Update(diff);
781 // deathstate changed on spells update, prevent problems
782 if (m_deathState != CORPSE)
783 break;
784
785 if (IsEngaged())
786 Unit::AIUpdateTick(diff);
787
788 if (m_loot)
789 m_loot->Update();
790
791 for (auto&& [playerOwner, loot] : m_personalLoot)
792 loot->Update();
793
795 {
796 RemoveCorpse(false);
797 TC_LOG_DEBUG("entities.unit", "Removing corpse... {} ", GetEntry());
798 }
799 break;
800 }
801 case ALIVE:
802 {
803 Unit::Update(diff);
804
805 // creature can be dead after Unit::Update call
806 // CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly)
807 if (!IsAlive())
808 break;
809
810 GetThreatManager().Update(diff);
811 if (_spellFocusInfo.Delay)
812 {
813 if (_spellFocusInfo.Delay <= diff)
815 else
816 _spellFocusInfo.Delay -= diff;
817 }
818
819 // periodic check to see if the creature has passed an evade boundary
820 if (IsAIEnabled() && !IsInEvadeMode() && IsEngaged())
821 {
822 if (diff >= m_boundaryCheckTime)
823 {
824 AI()->CheckInRoom();
825 m_boundaryCheckTime = 2500;
826 } else
827 m_boundaryCheckTime -= diff;
828 }
829
830 // if periodic combat pulse is enabled and we are both in combat and in a dungeon, do this now
831 if (m_combatPulseDelay > 0 && IsEngaged() && GetMap()->IsDungeon())
832 {
833 if (diff > m_combatPulseTime)
835 else
836 m_combatPulseTime -= diff;
837
838 if (m_combatPulseTime == 0)
839 {
840 Map::PlayerList const& players = GetMap()->GetPlayers();
841 if (!players.isEmpty())
842 for (Map::PlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
843 {
844 if (Player* player = it->GetSource())
845 {
846 if (player->IsGameMaster())
847 continue;
848
849 if (player->IsAlive() && IsHostileTo(player))
850 EngageWithTarget(player);
851 }
852 }
853
855 }
856 }
857
858 Unit::AIUpdateTick(diff);
859
861
862 // creature can be dead after UpdateAI call
863 // CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly)
864 if (!IsAlive())
865 break;
866
867 if (m_regenTimer > 0)
868 {
869 if (diff >= m_regenTimer)
870 m_regenTimer = 0;
871 else
872 m_regenTimer -= diff;
873 }
874
875 if (m_regenTimer == 0)
876 {
877 if (!IsInEvadeMode())
878 {
879 // regenerate health if not in combat or if polymorphed)
880 if (!IsEngaged() || IsPolymorphed())
882 else if (CanNotReachTarget())
883 {
884 // regenerate health if cannot reach the target and the setting is set to do so.
885 // this allows to disable the health regen of raid bosses if pathfinding has issues for whatever reason
886 if (sWorld->getBoolConfig(CONFIG_REGEN_HP_CANNOT_REACH_TARGET_IN_RAID) || !GetMap()->IsRaid())
887 {
889 TC_LOG_DEBUG("entities.unit.chase", "RegenerateHealth() enabled because Creature cannot reach the target. Detail: {}", GetDebugInfo());
890 }
891 else
892 TC_LOG_DEBUG("entities.unit.chase", "RegenerateHealth() disabled even if the Creature cannot reach the target. Detail: {}", GetDebugInfo());
893 }
894 }
895
896 if (GetPowerType() == POWER_ENERGY)
898 else
900
902 }
903
904 if (CanNotReachTarget() && !IsInEvadeMode() && !GetMap()->IsRaid())
905 {
906 m_cannotReachTimer += diff;
908 if (CreatureAI* ai = AI())
909 ai->EnterEvadeMode(EvadeReason::NoPath);
910 }
911 break;
912 }
913 default:
914 break;
915 }
916}
917
919{
920 uint32 curValue = GetPower(power);
921 uint32 maxValue = GetMaxPower(power);
922
924 return;
925
926 if (curValue >= maxValue)
927 return;
928
929 float addvalue = 0.0f;
930
931 switch (power)
932 {
933 case POWER_FOCUS:
934 {
935 // For hunter pets.
936 addvalue = 24 * sWorld->getRate(RATE_POWER_FOCUS);
937 break;
938 }
939 case POWER_ENERGY:
940 {
941 // For deathknight's ghoul.
942 addvalue = 20;
943 break;
944 }
945 case POWER_MANA:
946 {
947 // Combat and any controlled creature
948 if (IsInCombat() || GetCharmerOrOwnerGUID().IsEmpty())
949 {
950 float ManaIncreaseRate = sWorld->getRate(RATE_POWER_MANA);
951
952 addvalue = uint32((27.0f / 5.0f + 17.0f) * ManaIncreaseRate);
953 }
954 else
955 addvalue = maxValue / 3;
956
957 break;
958 }
959 default:
960 return;
961 }
962
963 // Apply modifiers (if any).
965
967
968 ModifyPower(power, int32(addvalue));
969}
970
972{
973 if (!CanRegenerateHealth())
974 return;
975
976 uint32 curValue = GetHealth();
977 uint32 maxValue = GetMaxHealth();
978
979 if (curValue >= maxValue)
980 return;
981
982 uint32 addvalue = 0;
983
984 // Not only pet, but any controlled creature (and not polymorphed)
985 if (!GetCharmerOrOwnerGUID().IsEmpty() && !IsPolymorphed())
986 {
987 float HealthIncreaseRate = sWorld->getRate(RATE_HEALTH);
988
989 addvalue = 0.015f * ((float)GetMaxHealth()) * HealthIncreaseRate;
990 }
991 else
992 addvalue = maxValue/3;
993
994 // Apply modifiers (if any).
996
998
999 ModifyHealth(addvalue);
1000}
1001
1003{
1004 if (!GetVictim())
1005 return;
1006
1008 return;
1009
1010 float radius = sWorld->getFloatConfig(CONFIG_CREATURE_FAMILY_FLEE_ASSISTANCE_RADIUS);
1011 if (radius >0)
1012 {
1013 Creature* creature = nullptr;
1016 Cell::VisitGridObjects(this, searcher, radius);
1017
1019
1020 if (!creature)
1023 else
1024 GetMotionMaster()->MoveSeekAssistance(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ());
1025 }
1026}
1027
1029{
1030 PopAI();
1031 RefreshAI();
1032 return true;
1033}
1034
1035bool Creature::AIM_Create(CreatureAI* ai /*= nullptr*/)
1036{
1038
1039 SetAI(ai ? ai : FactorySelector::SelectAI(this));
1040
1041 return true;
1042}
1043
1045{
1046 if (!AIM_Create(ai))
1047 return false;
1048
1049 AI()->InitializeAI();
1050 if (GetVehicleKit())
1051 GetVehicleKit()->Reset();
1052 return true;
1053}
1054
1056{
1057 if (m_formation)
1058 {
1059 if (m_formation->GetLeader() == this)
1061 else if (m_formation->IsFormed())
1062 {
1063 GetMotionMaster()->MoveIdle(); // wait the order of leader
1064 return;
1065 }
1066 }
1067
1069}
1070
1071bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 entry, Position const& pos, CreatureData const* data /*= nullptr*/, uint32 vehId /*= 0*/, bool dynamic)
1072{
1073 ASSERT(map);
1074 SetMap(map);
1075
1076 if (data)
1077 {
1080 }
1081
1082 // Set if this creature can handle dynamic spawns
1083 if (!dynamic)
1085
1086 CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(entry);
1087 if (!cinfo)
1088 {
1089 TC_LOG_ERROR("sql.sql", "Creature::Create(): creature template (guidlow: {}, entry: {}) does not exist.", guidlow, entry);
1090 return false;
1091 }
1092
1093 CreatureDifficulty const* creatureDifficulty = cinfo->GetDifficulty(GetMap()->GetDifficultyID());
1094
1097 Relocate(pos);
1098
1099 // Check if the position is valid before calling CreateFromProto(), otherwise we might add Auras to Creatures at
1100 // invalid position, triggering a crash about Auras not removed in the destructor
1101 if (!IsPositionValid())
1102 {
1103 TC_LOG_ERROR("entities.unit", "Creature::Create(): given coordinates for creature (guidlow {}, entry {}) are not valid (X: {}, Y: {}, Z: {}, O: {})", guidlow, entry, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation());
1104 return false;
1105 }
1106 {
1107 // area/zone id is needed immediately for ZoneScript::GetCreatureEntry hook before it is known which creature template to load (no model/scale available yet)
1108 PositionFullTerrainStatus terrainStatus;
1110 ProcessPositionDataChanged(terrainStatus);
1111 }
1112
1113 // Allow players to see those units while dead, do it here (mayby altered by addon auras)
1114 if (creatureDifficulty->TypeFlags & CREATURE_TYPE_FLAG_VISIBLE_TO_GHOSTS)
1116
1117 if (!CreateFromProto(guidlow, entry, data, vehId))
1118 return false;
1119
1120 cinfo = GetCreatureTemplate(); // might be different than initially requested
1122 m_respawnDelay = 0; // special value, prevents respawn for dungeon bosses unless overridden
1123
1124 switch (GetCreatureClassification())
1125 {
1128 break;
1131 break;
1134 break;
1137 break;
1140 break;
1143 break;
1144 default:
1146 break;
1147 }
1148
1151
1154
1156
1158 {
1161 }
1162
1165
1167 {
1170 }
1171
1173
1174 return true;
1175}
1176
1177Creature* Creature::CreateCreature(uint32 entry, Map* map, Position const& pos, uint32 vehId /*= 0*/)
1178{
1179 CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(entry);
1180 if (!cInfo)
1181 return nullptr;
1182
1183 ObjectGuid::LowType lowGuid;
1184 if (vehId || cInfo->VehicleId)
1185 lowGuid = map->GenerateLowGuid<HighGuid::Vehicle>();
1186 else
1187 lowGuid = map->GenerateLowGuid<HighGuid::Creature>();
1188
1189 Creature* creature = new Creature();
1190 if (!creature->Create(lowGuid, map, entry, pos, nullptr, vehId))
1191 {
1192 delete creature;
1193 return nullptr;
1194 }
1195
1196 return creature;
1197}
1198
1199Creature* Creature::CreateCreatureFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap /*= true*/, bool allowDuplicate /*= false*/)
1200{
1201 Creature* creature = new Creature();
1202 if (!creature->LoadFromDB(spawnId, map, addToMap, allowDuplicate))
1203 {
1204 delete creature;
1205 return nullptr;
1206 }
1207
1208 return creature;
1209}
1210
1212{
1213 Unit* target = nullptr;
1214
1215 if (CanHaveThreatList())
1217 else if (!HasReactState(REACT_PASSIVE))
1218 {
1219 // We're a player pet, probably
1220 target = getAttackerForHelper();
1221 if (!target && IsSummon())
1222 {
1223 if (Unit* owner = ToTempSummon()->GetOwner())
1224 {
1225 if (owner->IsInCombat())
1226 target = owner->getAttackerForHelper();
1227 if (!target)
1228 {
1229 for (ControlList::const_iterator itr = owner->m_Controlled.begin(); itr != owner->m_Controlled.end(); ++itr)
1230 {
1231 if ((*itr)->IsInCombat())
1232 {
1233 target = (*itr)->getAttackerForHelper();
1234 if (target)
1235 break;
1236 }
1237 }
1238 }
1239 }
1240 }
1241 }
1242 else
1243 return nullptr;
1244
1245 if (target && _IsTargetAcceptable(target) && CanCreatureAttack(target))
1246 {
1247 if (!HasSpellFocus())
1248 SetInFront(target);
1249 return target;
1250 }
1251
1253 if (GetVehicle())
1254 return nullptr;
1255
1257 if (!iAuras.empty())
1258 {
1259 for (Unit::AuraEffectList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr)
1260 {
1261 if ((*itr)->GetBase()->IsPermanent())
1262 {
1264 break;
1265 }
1266 }
1267 return nullptr;
1268 }
1269
1270 // enter in evade mode in other case
1272
1273 return nullptr;
1274}
1275
1277{
1278 if (IsTotem() || IsTrigger() || IsCritter() || IsSpiritService())
1280 /*
1281 else if (IsCivilian())
1282 SetReactState(REACT_DEFENSIVE);
1283 */
1284 else
1286}
1287
1289{
1290 if (!IsBattleMaster())
1291 return false;
1292
1293 BattlegroundTypeId bgTypeId = sBattlegroundMgr->GetBattleMasterBG(GetEntry());
1294 if (!msg)
1295 return player->GetBGAccessByLevel(bgTypeId);
1296
1297 if (!player->GetBGAccessByLevel(bgTypeId))
1298 {
1299 ClearGossipMenuFor(player);
1300 switch (bgTypeId)
1301 {
1302 case BATTLEGROUND_AV: SendGossipMenuFor(player, 7616, this); break;
1303 case BATTLEGROUND_WS: SendGossipMenuFor(player, 7599, this); break;
1304 case BATTLEGROUND_AB: SendGossipMenuFor(player, 7642, this); break;
1305 case BATTLEGROUND_EY:
1306 case BATTLEGROUND_NA:
1307 case BATTLEGROUND_BE:
1308 case BATTLEGROUND_AA:
1309 case BATTLEGROUND_RL:
1310 case BATTLEGROUND_SA:
1311 case BATTLEGROUND_DS:
1312 case BATTLEGROUND_RV: SendGossipMenuFor(player, 10024, this); break;
1313 default: break;
1314 }
1315 return false;
1316 }
1317 return true;
1318}
1319
1321{
1322 return player->GetLevel() >= 15
1323 && player->GetClass() == GetCreatureTemplate()->trainer_class;
1324}
1325
1327{
1328 if (m_lootId)
1329 return *m_lootId;
1330
1331 return GetCreatureDifficulty()->LootID;
1332}
1333
1335{
1336 m_lootId = lootId;
1337}
1338
1339void Creature::SetTappedBy(Unit const* unit, bool withGroup)
1340{
1341 // set the player whose group should receive the right
1342 // to loot the creature after it dies
1343 // should be set to nullptr after the loot disappears
1344
1345 if (!unit)
1346 {
1347 m_tapList.clear();
1349 return;
1350 }
1351
1353 return;
1354
1355 if (unit->GetTypeId() != TYPEID_PLAYER && !unit->IsVehicle())
1356 return;
1357
1359 if (!player) // normal creature, no player involved
1360 return;
1361
1362 m_tapList.insert(player->GetGUID());
1363 if (withGroup)
1364 if (Group const* group = player->GetGroup())
1365 for (auto const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
1366 if (GetMap()->IsRaid() || group->SameSubGroup(player, itr->GetSource()))
1367 m_tapList.insert(itr->GetSource()->GetGUID());
1368
1371}
1372
1374{
1375 // only temporary summons are allowed to not clear their tap list
1376 if (!m_spawnId)
1377 m_dontClearTapListOnEvade = dontClear;
1378}
1379
1380// return true if this creature is tapped by the player or by a member of his group.
1381bool Creature::isTappedBy(Player const* player) const
1382{
1383 return m_tapList.find(player->GetGUID()) != m_tapList.end();
1384}
1385
1387{
1388 if (m_personalLoot.empty())
1389 return m_loot.get();
1390
1391 if (std::unique_ptr<Loot> const* loot = Trinity::Containers::MapGetValuePtr(m_personalLoot, player->GetGUID()))
1392 return loot->get();
1393
1394 return nullptr;
1395}
1396
1398{
1399 if (m_loot && !m_loot->isLooted())
1400 return false;
1401
1402 for (auto const& [_, loot] : m_personalLoot)
1403 if (!loot->isLooted())
1404 return false;
1405
1406 return true;
1407}
1408
1409bool Creature::IsSkinnedBy(Player const* player) const
1410{
1411 if (Loot* loot = GetLootForPlayer(player))
1412 return loot->loot_type == LOOT_SKINNING;
1413
1414 return false;
1415}
1416
1418{
1419 // this should only be used when the creature has already been loaded
1420 // preferably after adding to map, because mapid may not be valid otherwise
1421 CreatureData const* data = sObjectMgr->GetCreatureData(m_spawnId);
1422 if (!data)
1423 {
1424 TC_LOG_ERROR("entities.unit", "Creature::SaveToDB failed, cannot get creature data!");
1425 return;
1426 }
1427
1428 uint32 mapId = GetMapId();
1429 if (TransportBase* transport = GetTransport())
1430 if (transport->GetMapIdForSpawning() >= 0)
1431 mapId = transport->GetMapIdForSpawning();
1432
1433 SaveToDB(mapId, data->spawnDifficulties);
1434}
1435
1436void Creature::SaveToDB(uint32 mapid, std::vector<Difficulty> const& spawnDifficulties)
1437{
1438 // update in loaded data
1439 if (!m_spawnId)
1440 m_spawnId = sObjectMgr->GenerateCreatureSpawnId();
1441
1442 CreatureData& data = sObjectMgr->NewOrExistCreatureData(m_spawnId);
1443
1444 uint32 displayId = GetNativeDisplayId();
1445 uint64 spawnNpcFlags = (uint64(m_unitData->NpcFlags[1]) << 32) | m_unitData->NpcFlags[0];
1446 Optional<uint64> npcflag;
1447 Optional<uint32> unitFlags;
1448 Optional<uint32> unitFlags2;
1449 Optional<uint32> unitFlags3;
1450
1451 // check if it's a custom model and if not, use 0 for displayId
1452 CreatureTemplate const* cinfo = GetCreatureTemplate();
1453 if (cinfo)
1454 {
1455 for (CreatureModel const& model : cinfo->Models)
1456 if (displayId && displayId == model.CreatureDisplayID)
1457 displayId = 0;
1458
1459 if (spawnNpcFlags != cinfo->npcflag)
1460 npcflag = spawnNpcFlags;
1461
1462 if (m_unitData->Flags != cinfo->unit_flags)
1463 unitFlags = m_unitData->Flags;
1464
1465 if (m_unitData->Flags2 != cinfo->unit_flags2)
1466 unitFlags2 = m_unitData->Flags2;
1467
1468 if (m_unitData->Flags3 != cinfo->unit_flags3)
1469 unitFlags3 = m_unitData->Flags3;
1470 }
1471
1472 if (!data.spawnId)
1473 data.spawnId = m_spawnId;
1474 ASSERT(data.spawnId == m_spawnId);
1475 data.id = GetEntry();
1476 if (displayId)
1477 data.display.emplace(displayId, DEFAULT_PLAYER_DISPLAY_SCALE, 1.0f);
1478 else
1479 data.display.reset();
1481 if (!GetTransport())
1482 {
1483 data.mapId = GetMapId();
1484 data.spawnPoint.Relocate(this);
1485 }
1486 else
1487 {
1488 data.mapId = mapid;
1490 }
1492 // prevent add data integrity problems
1494 data.currentwaypoint = 0;
1495 data.curhealth = GetHealth();
1496 data.curmana = GetPower(POWER_MANA);
1497 // prevent add data integrity problems
1500 data.spawnDifficulties = spawnDifficulties;
1501 data.npcflag = npcflag;
1502 data.unit_flags = unitFlags;
1503 data.unit_flags2 = unitFlags2;
1504 data.unit_flags3 = unitFlags3;
1505 if (!data.spawnGroupData)
1506 data.spawnGroupData = sObjectMgr->GetDefaultSpawnGroup();
1507
1508 data.phaseId = GetDBPhase() > 0 ? GetDBPhase() : data.phaseId;
1509 data.phaseGroup = GetDBPhase() < 0 ? -GetDBPhase() : data.phaseGroup;
1510
1511 // update in DB
1512 WorldDatabaseTransaction trans = WorldDatabase.BeginTransaction();
1513
1515 stmt->setUInt64(0, m_spawnId);
1516 trans->Append(stmt);
1517
1518 uint8 index = 0;
1519
1520 stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_CREATURE);
1521 stmt->setUInt64(index++, m_spawnId);
1522 stmt->setUInt32(index++, GetEntry());
1523 stmt->setUInt16(index++, uint16(mapid));
1524 stmt->setString(index++, [&data]() -> std::string
1525 {
1526 if (data.spawnDifficulties.empty())
1527 return "";
1528
1529 std::ostringstream os;
1530 auto itr = data.spawnDifficulties.begin();
1531 os << int32(*itr++);
1532
1533 for (; itr != data.spawnDifficulties.end(); ++itr)
1534 os << ',' << int32(*itr);
1535
1536 return os.str();
1537 }());
1538 stmt->setUInt32(index++, data.phaseId);
1539 stmt->setUInt32(index++, data.phaseGroup);
1540 stmt->setUInt32(index++, displayId);
1541 stmt->setUInt8(index++, GetCurrentEquipmentId());
1542 stmt->setFloat(index++, GetPositionX());
1543 stmt->setFloat(index++, GetPositionY());
1544 stmt->setFloat(index++, GetPositionZ());
1545 stmt->setFloat(index++, GetOrientation());
1546 stmt->setUInt32(index++, m_respawnDelay);
1547 stmt->setFloat(index++, m_wanderDistance);
1548 stmt->setUInt32(index++, 0);
1549 stmt->setUInt32(index++, GetHealth());
1550 stmt->setUInt32(index++, GetPower(POWER_MANA));
1551 stmt->setUInt8(index++, uint8(GetDefaultMovementType()));
1552 if (npcflag.has_value())
1553 stmt->setUInt64(index++, *npcflag);
1554 else
1555 stmt->setNull(index++);
1556
1557 if (unitFlags.has_value())
1558 stmt->setUInt32(index++, *unitFlags);
1559 else
1560 stmt->setNull(index++);
1561
1562 if (unitFlags2.has_value())
1563 stmt->setUInt32(index++, *unitFlags2);
1564 else
1565 stmt->setNull(index++);
1566
1567 if (unitFlags3.has_value())
1568 stmt->setUInt32(index++, *unitFlags3);
1569 else
1570 stmt->setNull(index++);
1571 trans->Append(stmt);
1572
1573 WorldDatabase.CommitTransaction(trans);
1574}
1575
1577{
1578 // Level
1580 int32 levelWithDelta = m_unitData->ScalingLevelMax + m_unitData->ScalingLevelDelta;
1581 uint8 level = RoundToInterval<int32>(levelWithDelta, 1, STRONG_MAX_LEVEL);
1582 SetLevel(level);
1583
1585}
1586
1588{
1589 CreatureTemplate const* cInfo = GetCreatureTemplate();
1591 uint8 level = GetLevel();
1592 CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(level, cInfo->unit_class);
1593
1594 // health
1595 float healthmod = GetHealthMod(classification);
1596
1597 uint32 basehp = GetMaxHealthByLevel(level);
1598 uint32 health = uint32(basehp * healthmod);
1599
1600 SetCreateHealth(health);
1601 SetMaxHealth(health);
1602 SetHealth(health);
1604
1606
1607 // mana
1608 Powers powerType = CalculateDisplayPowerType();
1609 SetCreateMana(stats->BaseMana);
1611 SetPowerType(powerType);
1612
1613 if (PowerTypeEntry const* powerTypeEntry = sDB2Manager.GetPowerTypeEntry(powerType))
1614 {
1615 if (powerTypeEntry->GetFlags().HasFlag(PowerTypeFlags::UnitsUseDefaultPowerOnInit))
1616 SetPower(powerType, powerTypeEntry->DefaultPower);
1617 else
1618 SetFullPower(powerType);
1619 }
1620
1621 // damage
1622 float basedamage = GetBaseDamageForLevel(level);
1623
1624 float weaponBaseMinDamage = basedamage;
1625 float weaponBaseMaxDamage = basedamage * 1.5f;
1626
1627 SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, weaponBaseMinDamage);
1628 SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, weaponBaseMaxDamage);
1629
1630 SetBaseWeaponDamage(OFF_ATTACK, MINDAMAGE, weaponBaseMinDamage);
1631 SetBaseWeaponDamage(OFF_ATTACK, MAXDAMAGE, weaponBaseMaxDamage);
1632
1633 SetBaseWeaponDamage(RANGED_ATTACK, MINDAMAGE, weaponBaseMinDamage);
1634 SetBaseWeaponDamage(RANGED_ATTACK, MAXDAMAGE, weaponBaseMaxDamage);
1635
1638
1639 float armor = GetBaseArmorForLevel(level);
1641}
1642
1644{
1645 if (IsWildBattlePet())
1646 {
1647 uint8 wildBattlePetLevel = WILD_BATTLE_PET_DEFAULT_LEVEL;
1648
1649 if (AreaTableEntry const* areaTable = sAreaTableStore.LookupEntry(GetZoneId()))
1650 if (areaTable->WildBattlePetLevelMin > 0)
1651 wildBattlePetLevel = urand(areaTable->WildBattlePetLevelMin, areaTable->WildBattlePetLevelMax);
1652
1653 SetWildBattlePetLevel(wildBattlePetLevel);
1654 }
1655}
1656
1658{
1659 switch (classification)
1660 {
1662 return sWorld->getRate(RATE_CREATURE_HP_NORMAL);
1664 return sWorld->getRate(RATE_CREATURE_HP_ELITE);
1666 return sWorld->getRate(RATE_CREATURE_HP_RAREELITE);
1668 return sWorld->getRate(RATE_CREATURE_HP_OBSOLETE);
1670 return sWorld->getRate(RATE_CREATURE_HP_RARE);
1672 return sWorld->getRate(RATE_CREATURE_HP_TRIVIAL);
1674 return sWorld->getRate(RATE_CREATURE_HP_MINUSMOB);
1675 default:
1676 return sWorld->getRate(RATE_CREATURE_HP_ELITE);
1677 }
1678}
1679
1681{
1683 m_PlayerDamageReq > unDamage ? m_PlayerDamageReq -= unDamage : m_PlayerDamageReq = 0;
1684}
1685
1687{
1688 switch (classification)
1689 {
1691 return sWorld->getRate(RATE_CREATURE_DAMAGE_NORMAL);
1693 return sWorld->getRate(RATE_CREATURE_DAMAGE_ELITE);
1695 return sWorld->getRate(RATE_CREATURE_DAMAGE_RAREELITE);
1697 return sWorld->getRate(RATE_CREATURE_DAMAGE_OBSOLETE);
1699 return sWorld->getRate(RATE_CREATURE_DAMAGE_RARE);
1701 return sWorld->getRate(RATE_CREATURE_DAMAGE_TRIVIAL);
1703 return sWorld->getRate(RATE_CREATURE_DAMAGE_MINUSMOB);
1704 default:
1705 return sWorld->getRate(RATE_CREATURE_DAMAGE_ELITE);
1706 }
1707}
1708
1710{
1711 switch (classification)
1712 {
1716 return sWorld->getRate(RATE_CREATURE_SPELLDAMAGE_ELITE);
1722 return sWorld->getRate(RATE_CREATURE_SPELLDAMAGE_RARE);
1727 default:
1728 return sWorld->getRate(RATE_CREATURE_SPELLDAMAGE_ELITE);
1729 }
1730}
1731
1732void Creature::OverrideSparringHealthPct(std::vector<float> const& healthPct)
1733{
1735}
1736
1738{
1739 if (GetSparringHealthPct() == 0)
1740 return damage;
1741
1742 if (!attacker)
1743 return damage;
1744
1746 return damage;
1747
1749 return 0;
1750
1751 uint32 sparringHealth = GetMaxHealth() * GetSparringHealthPct() / 100;
1752 if (GetHealth() - damage <= sparringHealth)
1753 return GetHealth() - sparringHealth;
1754
1755 if (damage >= GetHealth())
1756 return GetHealth() - 1;
1757
1758 return damage;
1759}
1760
1762{
1763 if (!GetSparringHealthPct())
1764 return false;
1765
1766 if (!attacker)
1767 return false;
1768
1769 if (!attacker->IsCreature())
1770 return false;
1771
1773 return false;
1774
1776 return false;
1777
1778 return true;
1779}
1780
1781bool Creature::CreateFromProto(ObjectGuid::LowType guidlow, uint32 entry, CreatureData const* data /*= nullptr*/, uint32 vehId /*= 0*/)
1782{
1783 SetZoneScript();
1784 if (GetZoneScript() && data)
1785 {
1786 entry = GetZoneScript()->GetCreatureEntry(guidlow, data);
1787 if (!entry)
1788 return false;
1789 }
1790
1791 CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(entry);
1792 if (!cinfo)
1793 {
1794 TC_LOG_ERROR("sql.sql", "Creature::CreateFromProto(): creature template (guidlow: {}, entry: {}) does not exist.", guidlow, entry);
1795 return false;
1796 }
1797
1798 SetOriginalEntry(entry);
1799
1800 if (vehId || cinfo->VehicleId)
1801 Object::_Create(ObjectGuid::Create<HighGuid::Vehicle>(GetMapId(), entry, guidlow));
1802 else
1803 Object::_Create(ObjectGuid::Create<HighGuid::Creature>(GetMapId(), entry, guidlow));
1804
1805 if (!UpdateEntry(entry, data))
1806 return false;
1807
1808 if (!vehId)
1809 {
1810 if (GetCreatureTemplate()->VehicleId)
1811 {
1812 vehId = GetCreatureTemplate()->VehicleId;
1813 entry = GetCreatureTemplate()->Entry;
1814 }
1815 else
1816 vehId = cinfo->VehicleId;
1817 }
1818
1819 if (vehId)
1820 if (CreateVehicleKit(vehId, entry, true))
1822
1823 if (!IsPet())
1824 if (uint32 vignetteId = GetCreatureTemplate()->VignetteID)
1825 SetVignette(vignetteId);
1826
1827 return true;
1828}
1829
1830bool Creature::LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap, bool allowDuplicate)
1831{
1832 if (!allowDuplicate)
1833 {
1834 // If an alive instance of this spawnId is already found, skip creation
1835 // If only dead instance(s) exist, despawn them and spawn a new (maybe also dead) version
1836 const auto creatureBounds = map->GetCreatureBySpawnIdStore().equal_range(spawnId);
1837 std::vector <Creature*> despawnList;
1838
1839 if (creatureBounds.first != creatureBounds.second)
1840 {
1841 for (auto itr = creatureBounds.first; itr != creatureBounds.second; ++itr)
1842 {
1843 if (itr->second->IsAlive())
1844 {
1845 TC_LOG_DEBUG("maps", "Would have spawned {} but {} already exists", spawnId, creatureBounds.first->second->GetGUID().ToString());
1846 return false;
1847 }
1848 else
1849 {
1850 despawnList.push_back(itr->second);
1851 TC_LOG_DEBUG("maps", "Despawned dead instance of spawn {} ({})", spawnId, itr->second->GetGUID().ToString());
1852 }
1853 }
1854
1855 for (Creature* despawnCreature : despawnList)
1856 {
1857 despawnCreature->AddObjectToRemoveList();
1858 }
1859 }
1860 }
1861
1862 CreatureData const* data = sObjectMgr->GetCreatureData(spawnId);
1863 if (!data)
1864 {
1865 TC_LOG_ERROR("sql.sql", "Creature (SpawnID {}) not found in table `creature`, can't load. ", spawnId);
1866 return false;
1867 }
1868
1869 m_spawnId = spawnId;
1870
1872 m_creatureData = data;
1875
1876 if (!Create(map->GenerateLowGuid<HighGuid::Creature>(), map, data->id, data->spawnPoint, data, 0U , !m_respawnCompatibilityMode))
1877 return false;
1878
1879 //We should set first home position, because then AI calls home movement
1880 SetHomePosition(*this);
1881
1883
1885
1887 {
1889 {
1890 // @todo pools need fixing! this is just a temporary thing, but they violate dynspawn principles
1891 if (!data->poolId)
1892 {
1893 TC_LOG_ERROR("entities.unit", "Creature (SpawnID {}) trying to load in inactive spawn group '{}':\n{}", spawnId, data->spawnGroupData->name, GetDebugInfo());
1894 return false;
1895 }
1896 }
1897
1899 }
1900
1901 if (m_respawnTime)
1902 {
1904 {
1905 // @todo same as above
1906 if (!data->poolId)
1907 {
1908 TC_LOG_ERROR("entities.unit", "Creature (SpawnID {}) trying to load despite a respawn timer in progress:\n{}", spawnId, GetDebugInfo());
1909 return false;
1910 }
1911 }
1912 else
1913 {
1914 // compatibility mode creatures will be respawned in ::Update()
1916 }
1917
1918 if (CanFly())
1919 {
1920 float tz = map->GetHeight(GetPhaseShift(), data->spawnPoint, true, MAX_FALL_DISTANCE);
1921 if (data->spawnPoint.GetPositionZ() - tz > 0.1f && Trinity::IsValidMapCoord(tz))
1923 }
1924 }
1925
1927
1929
1930 // checked at creature_template loading
1932
1933 m_stringIds[1] = data->StringId;
1934
1935 if (addToMap && !GetMap()->AddToMap(this))
1936 return false;
1937 return true;
1938}
1939
1941{
1942 Unit::SetCanDualWield(value);
1944}
1945
1946void Creature::LoadEquipment(int8 id, bool force /*= true*/)
1947{
1948 if (id == 0)
1949 {
1950 if (force)
1951 {
1952 for (uint8 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i)
1953 SetVirtualItem(i, 0);
1954 m_equipmentId = 0;
1955 }
1956
1957 return;
1958 }
1959
1960 EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(GetEntry(), id);
1961 if (!einfo)
1962 return;
1963
1964 m_equipmentId = id;
1965 for (uint8 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i)
1966 SetVirtualItem(i, einfo->Items[i].ItemId, einfo->Items[i].AppearanceModId, einfo->Items[i].ItemVisual);
1967}
1968
1970{
1972 return;
1973
1974 uint32 curhealth;
1976 {
1977 curhealth = m_creatureData->curhealth;
1978 if (curhealth)
1979 {
1980 curhealth = uint32(curhealth*GetHealthMod(GetCreatureTemplate()->Classification));
1981 if (curhealth < 1)
1982 curhealth = 1;
1983 }
1985 }
1986 else
1987 {
1988 curhealth = GetMaxHealth();
1990 }
1991
1992 SetHealth((m_deathState == ALIVE || m_deathState == JUST_RESPAWNED) ? curhealth : 0);
1993}
1994
1995bool Creature::hasQuest(uint32 quest_id) const
1996{
1997 return sObjectMgr->GetCreatureQuestRelations(GetEntry()).HasQuest(quest_id);
1998}
1999
2001{
2002 return sObjectMgr->GetCreatureQuestInvolvedRelations(GetEntry()).HasQuest(quest_id);
2003}
2004
2006{
2007 CreatureData const* data = sObjectMgr->GetCreatureData(spawnId);
2008 if (!data)
2009 return false;
2010
2011 CharacterDatabaseTransaction charTrans = CharacterDatabase.BeginTransaction();
2012
2013 sMapMgr->DoForAllMapsWithMapId(data->mapId,
2014 [spawnId, charTrans](Map* map) -> void
2015 {
2016 // despawn all active creatures, and remove their respawns
2017 std::vector<Creature*> toUnload;
2018 for (auto const& pair : Trinity::Containers::MapEqualRange(map->GetCreatureBySpawnIdStore(), spawnId))
2019 toUnload.push_back(pair.second);
2020 for (Creature* creature : toUnload)
2021 map->AddObjectToRemoveList(creature);
2022 map->RemoveRespawnTime(SPAWN_TYPE_CREATURE, spawnId, charTrans);
2023 }
2024 );
2025
2026 // delete data from memory ...
2027 sObjectMgr->DeleteCreatureData(spawnId);
2028
2029 CharacterDatabase.CommitTransaction(charTrans);
2030
2031 WorldDatabaseTransaction trans = WorldDatabase.BeginTransaction();
2032
2033 // ... and the database
2035 stmt->setUInt64(0, spawnId);
2036 trans->Append(stmt);
2037
2038 stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_SPAWNGROUP_MEMBER);
2040 stmt->setUInt64(1, spawnId);
2041 trans->Append(stmt);
2042
2043 stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_CREATURE_ADDON);
2044 stmt->setUInt64(0, spawnId);
2045 trans->Append(stmt);
2046
2047 stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GAME_EVENT_CREATURE);
2048 stmt->setUInt64(0, spawnId);
2049 trans->Append(stmt);
2050
2051 stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_GAME_EVENT_MODEL_EQUIP);
2052 stmt->setUInt64(0, spawnId);
2053 trans->Append(stmt);
2054
2055 stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_LINKED_RESPAWN);
2056 stmt->setUInt64(0, spawnId);
2058 trans->Append(stmt);
2059
2060 stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_LINKED_RESPAWN);
2061 stmt->setUInt64(0, spawnId);
2063 trans->Append(stmt);
2064
2065 stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_LINKED_RESPAWN_MASTER);
2066 stmt->setUInt64(0, spawnId);
2068 trans->Append(stmt);
2069
2070 stmt = WorldDatabase.GetPreparedStatement(WORLD_DEL_LINKED_RESPAWN_MASTER);
2071 stmt->setUInt64(0, spawnId);
2073 trans->Append(stmt);
2074
2075 WorldDatabase.CommitTransaction(trans);
2076
2077 return true;
2078}
2079
2081{
2083 return true;
2084
2086 return false;
2087
2088 return true;
2089}
2090
2092{
2093 if (IsAIEnabled() && AI()->CanSeeAlways(obj))
2094 return true;
2095
2096 return false;
2097}
2098
2099bool Creature::CanStartAttack(Unit const* who, bool force) const
2100{
2101 if (IsCivilian())
2102 return false;
2103
2104 // This set of checks is should be done only for creatures
2107 return false;
2108
2109 // Do not attack non-combat pets
2111 return false;
2112
2114 //|| who->IsControlledByPlayer() && who->IsFlying()))
2115 // we cannot check flying for other creatures, too much map/vmap calculation
2117 return false;
2118
2119 if (!force)
2120 {
2121 if (!_IsTargetAcceptable(who))
2122 return false;
2123
2125 return false;
2126 }
2127
2128 if (!CanCreatureAttack(who, force))
2129 return false;
2130
2131 // No aggro from gray creatures
2133 return false;
2134
2135 return IsWithinLOSInMap(who);
2136}
2137
2138bool Creature::CheckNoGrayAggroConfig(uint32 playerLevel, uint32 creatureLevel) const
2139{
2140 if (Trinity::XP::GetColorCode(playerLevel, creatureLevel) != XP_GRAY)
2141 return false;
2142
2143 uint32 notAbove = sWorld->getIntConfig(CONFIG_NO_GRAY_AGGRO_ABOVE);
2144 uint32 notBelow = sWorld->getIntConfig(CONFIG_NO_GRAY_AGGRO_BELOW);
2145 if (notAbove == 0 && notBelow == 0)
2146 return false;
2147
2148 if (playerLevel <= notBelow || (playerLevel >= notAbove && notAbove > 0))
2149 return true;
2150 return false;
2151}
2152
2153float Creature::GetAttackDistance(Unit const* player) const
2154{
2155 float aggroRate = sWorld->getRate(RATE_CREATURE_AGGRO);
2156 if (aggroRate == 0)
2157 return 0.0f;
2158
2159 // WoW Wiki: the minimum radius seems to be 5 yards, while the maximum range is 45 yards
2160 float maxRadius = 45.0f * aggroRate;
2161 float minRadius = 5.0f * aggroRate;
2162
2163 int32 expansionMaxLevel = int32(GetMaxLevelForExpansion(GetCreatureTemplate()->RequiredExpansion));
2164 int32 playerLevel = player->GetLevelForTarget(this);
2165 int32 creatureLevel = GetLevelForTarget(player);
2166 int32 levelDifference = creatureLevel - playerLevel;
2167
2168 // The aggro radius for creatures with equal level as the player is 20 yards.
2169 // The combatreach should not get taken into account for the distance so we drop it from the range (see Supremus as expample)
2170 float baseAggroDistance = 20.0f - GetCombatReach();
2171
2172 // + - 1 yard for each level difference between player and creature
2173 float aggroRadius = baseAggroDistance + float(levelDifference);
2174
2175 // detect range auras
2176 if (uint32(creatureLevel + 5) <= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))
2177 {
2180 }
2181
2182 // The aggro range of creatures with higher levels than the total player level for the expansion should get the maxlevel treatment
2183 // This makes sure that creatures such as bosses wont have a bigger aggro range than the rest of the npc's
2184 // The following code is used for blizzlike behaviour such as skippable bosses
2185 if (creatureLevel > expansionMaxLevel)
2186 aggroRadius = baseAggroDistance + float(expansionMaxLevel - playerLevel);
2187
2188 // Make sure that we wont go over the total range limits
2189 if (aggroRadius > maxRadius)
2190 aggroRadius = maxRadius;
2191 else if (aggroRadius < minRadius)
2192 aggroRadius = minRadius;
2193
2194 return (aggroRadius * aggroRate);
2195}
2196
2198{
2200
2201 if (s == JUST_DIED)
2202 {
2204
2205 uint32 respawnDelay = m_respawnDelay;
2206 if (uint32 scalingMode = sWorld->getIntConfig(CONFIG_RESPAWN_DYNAMICMODE))
2207 GetMap()->ApplyDynamicModeRespawnScaling(this, m_spawnId, respawnDelay, scalingMode);
2208
2209 // @todo remove the boss respawn time hack in a dynspawn follow-up once we have creature groups in instances
2211 {
2212 if (IsDungeonBoss() && !m_respawnDelay)
2213 m_respawnTime = std::numeric_limits<time_t>::max(); // never respawn in this instance
2214 else
2216 }
2217 else
2218 {
2219 if (IsDungeonBoss() && !m_respawnDelay)
2220 m_respawnTime = std::numeric_limits<time_t>::max(); // never respawn in this instance
2221 else
2222 m_respawnTime = GameTime::GetGameTime() + respawnDelay;
2223 }
2224
2226
2227 ReleaseSpellFocus(nullptr, false); // remove spellcast focus
2228 DoNotReacquireSpellFocusTarget(); // cancel delayed re-target
2229 SetTarget(ObjectGuid::Empty); // drop target - dead mobs shouldn't ever target things
2230
2233
2234 SetMountDisplayId(0); // if creature is mounted on a virtual mount, remove it at death
2235
2236 setActive(false);
2237
2238 SetNoSearchAssistance(false);
2239
2240 //Dismiss group if is leader
2241 if (m_formation && m_formation->GetLeader() == this)
2243
2244 bool needsFalling = (IsFlying() || IsHovering()) && !IsUnderWater() && !HasUnitState(UNIT_STATE_ROOT);
2245 SetHover(false, false);
2246 SetDisableGravity(false, false);
2247
2248 if (needsFalling)
2250
2252 }
2253 else if (s == JUST_RESPAWNED)
2254 {
2255 if (IsPet())
2256 SetFullHealth();
2257 else
2259
2260 SetTappedBy(nullptr);
2262
2263 SetCannotReachTarget(false);
2265
2267
2268 if (!IsPet())
2269 {
2271 CreatureTemplate const* cInfo = GetCreatureTemplate();
2272
2273 uint64 npcFlags;
2274 uint32 unitFlags, unitFlags2, unitFlags3;
2275 ObjectMgr::ChooseCreatureFlags(cInfo, &npcFlags, &unitFlags, &unitFlags2, &unitFlags3, _staticFlags, creatureData);
2276
2278 npcFlags |= sGameEventMgr->GetNPCFlag(this);
2279
2280 ReplaceAllNpcFlags(NPCFlags(npcFlags & 0xFFFFFFFF));
2281 ReplaceAllNpcFlags2(NPCFlags2(npcFlags >> 32));
2282
2283 ReplaceAllUnitFlags(UnitFlags(unitFlags));
2284 ReplaceAllUnitFlags2(UnitFlags2(unitFlags2));
2285 ReplaceAllUnitFlags3(UnitFlags3(unitFlags3));
2287
2289
2291
2292 if (uint32 vignetteId = cInfo->VignetteID)
2293 SetVignette(vignetteId);
2294 }
2295
2300 }
2301}
2302
2303void Creature::Respawn(bool force)
2304{
2305 if (force)
2306 {
2307 if (IsAlive())
2309 else if (getDeathState() != CORPSE)
2311 }
2312
2314 {
2316 RemoveCorpse(false, false);
2317
2318 if (getDeathState() == DEAD)
2319 {
2320 TC_LOG_DEBUG("entities.unit", "Respawning creature {} ({})", GetName(), GetGUID().ToString());
2321 m_respawnTime = 0;
2323 m_loot = nullptr;
2324
2325 if (m_originalEntry != GetEntry())
2327
2328 SelectLevel();
2329
2331
2333 if (sObjectMgr->GetCreatureModelRandomGender(&display, GetCreatureTemplate()))
2334 SetDisplayId(display.CreatureDisplayID, true);
2335
2337
2338 // Re-initialize reactstate that could be altered by movementgenerators
2340
2341 if (UnitAI* ai = AI()) // reset the AI to be sure no dirty or uninitialized values will be used till next tick
2342 ai->Reset();
2343
2344 m_triggerJustAppeared = true;
2345
2346 uint32 poolid = GetCreatureData() ? GetCreatureData()->poolId : 0;
2347 if (poolid)
2348 sPoolMgr->UpdatePool<Creature>(GetMap()->GetPoolData(), poolid, GetSpawnId());
2349 }
2351 }
2352 else
2353 {
2354 if (m_spawnId)
2356 }
2357
2358 TC_LOG_DEBUG("entities.unit", "Respawning creature {} ({})",
2359 GetName(), GetGUID().ToString());
2360
2361}
2362
2363void Creature::ForcedDespawn(uint32 timeMSToDespawn, Seconds forceRespawnTimer)
2364{
2365 if (timeMSToDespawn)
2366 {
2367 m_Events.AddEvent(new ForcedDespawnDelayEvent(*this, forceRespawnTimer), m_Events.CalculateTime(Milliseconds(timeMSToDespawn)));
2368 return;
2369 }
2370
2372 {
2373 uint32 corpseDelay = GetCorpseDelay();
2374 uint32 respawnDelay = GetRespawnDelay();
2375
2376 // do it before killing creature
2378
2379 bool overrideRespawnTime = false;
2380 if (IsAlive())
2381 {
2382 if (forceRespawnTimer > Seconds::zero())
2383 {
2384 SetCorpseDelay(0);
2385 SetRespawnDelay(forceRespawnTimer.count());
2386 overrideRespawnTime = true;
2387 }
2388
2390 }
2391
2392 // Skip corpse decay time
2393 RemoveCorpse(!overrideRespawnTime, false);
2394
2395 SetCorpseDelay(corpseDelay);
2396 SetRespawnDelay(respawnDelay);
2397 }
2398 else
2399 {
2400 if (forceRespawnTimer > Seconds::zero())
2401 SaveRespawnTime(forceRespawnTimer.count());
2402 else
2403 {
2404 uint32 respawnDelay = m_respawnDelay;
2405 if (uint32 scalingMode = sWorld->getIntConfig(CONFIG_RESPAWN_DYNAMICMODE))
2406 GetMap()->ApplyDynamicModeRespawnScaling(this, m_spawnId, respawnDelay, scalingMode);
2407 m_respawnTime = GameTime::GetGameTime() + respawnDelay;
2409 }
2410
2412 }
2413}
2414
2415void Creature::DespawnOrUnsummon(Milliseconds timeToDespawn /*= 0s*/, Seconds forceRespawnTimer /*= 0s*/)
2416{
2417 if (TempSummon* summon = ToTempSummon())
2418 summon->UnSummon(timeToDespawn.count());
2419 else
2420 ForcedDespawn(timeToDespawn.count(), forceRespawnTimer);
2421}
2422
2423void Creature::LoadTemplateImmunities(int32 creatureImmunitiesId)
2424{
2425 // uint32 max used for "spell id", the immunity system will not perform SpellInfo checks against invalid spells
2426 // used so we know which immunities were loaded from template
2427 static uint32 constexpr placeholderSpellId = std::numeric_limits<uint32>::max();
2428
2429 auto applyCreatureImmunities = [this](CreatureImmunities const* immunities, bool apply)
2430 {
2431 for (std::size_t i = 0; i < immunities->School.size(); ++i)
2432 if (immunities->School[i])
2433 ApplySpellImmune(placeholderSpellId, IMMUNITY_SCHOOL, 1 << i, apply);
2434
2435 for (std::size_t i = 0; i < immunities->DispelType.size(); ++i)
2436 if (immunities->DispelType[i])
2437 ApplySpellImmune(placeholderSpellId, IMMUNITY_DISPEL, i, apply);
2438
2439 for (std::size_t i = 0; i < immunities->Mechanic.size(); ++i)
2440 if (immunities->Mechanic[i])
2441 ApplySpellImmune(placeholderSpellId, IMMUNITY_MECHANIC, i, apply);
2442
2443 for (SpellEffectName effect : immunities->Effect)
2444 ApplySpellImmune(placeholderSpellId, IMMUNITY_EFFECT, effect, apply);
2445
2446 for (AuraType aura : immunities->Aura)
2447 ApplySpellImmune(placeholderSpellId, IMMUNITY_STATE, aura, apply);
2448
2449 if (immunities->Other != SpellOtherImmunity::None)
2450 ApplySpellImmune(placeholderSpellId, IMMUNITY_OTHER, immunities->Other.AsUnderlyingType(), apply);
2451 };
2452
2453 // unapply template immunities (in case we're updating entry)
2455 applyCreatureImmunities(immunities, false);
2456
2457 // apply new immunities
2458 if (CreatureImmunities const* immunities = SpellMgr::GetCreatureImmunities(creatureImmunitiesId))
2459 {
2460 _creatureImmunitiesId = creatureImmunitiesId;
2461 applyCreatureImmunities(immunities, true);
2462 }
2463 else
2465}
2466
2467bool Creature::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster,
2468 bool requireImmunityPurgesEffectAttribute /*= false*/) const
2469{
2471 return true;
2472
2473 return Unit::IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute);
2474}
2475
2477{
2478 if (IsPet())
2479 return false;
2480
2482}
2483
2485{
2486 if (IsPet())
2487 return false;
2488
2489 return (GetCreatureDifficulty()->TypeFlags & CREATURE_TYPE_FLAG_BOSS_MOB) != 0;
2490}
2491
2492// select nearest hostile unit within the given distance (regardless of threat list).
2493Unit* Creature::SelectNearestTarget(float dist, bool playerOnly /* = false */) const
2494{
2495 if (dist == 0.0f)
2497
2498 Unit* target = nullptr;
2499 Trinity::NearestHostileUnitCheck u_check(this, dist, playerOnly);
2501 Cell::VisitAllObjects(this, searcher, dist);
2502 return target;
2503}
2504
2505// select nearest hostile unit within the given attack distance (i.e. distance is ignored if > than ATTACK_DISTANCE), regardless of threat list.
2507{
2508 if (dist > MAX_VISIBILITY_DISTANCE)
2509 {
2510 TC_LOG_ERROR("entities.unit", "Creature {} SelectNearestTargetInAttackDistance called with dist > MAX_VISIBILITY_DISTANCE. Distance set to ATTACK_DISTANCE.", GetGUID().ToString());
2511 dist = ATTACK_DISTANCE;
2512 }
2513
2514 Unit* target = nullptr;
2517 Cell::VisitAllObjects(this, searcher, std::max(dist, ATTACK_DISTANCE));
2518 return target;
2519}
2520
2522{
2524
2525 packet.UnitGUID = GetGUID();
2526 packet.Reaction = reactionType;
2527
2528 SendMessageToSet(packet.Write(), true);
2529
2530 TC_LOG_DEBUG("network", "WORLD: Sent SMSG_AI_REACTION, type {}.", reactionType);
2531}
2532
2534{
2535 if (!m_AlreadyCallAssistance && GetVictim() && !IsPet() && !IsCharmed())
2536 {
2537 SetNoCallAssistance(true);
2538
2539 float radius = sWorld->getFloatConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS);
2540
2541 if (radius > 0)
2542 {
2543 std::list<Creature*> assistList;
2544 Trinity::AnyAssistCreatureInRangeCheck u_check(this, GetVictim(), radius);
2546 Cell::VisitGridObjects(this, searcher, radius);
2547
2548 if (!assistList.empty())
2549 {
2551 while (!assistList.empty())
2552 {
2553 // Pushing guids because in delay can happen some creature gets despawned => invalid pointer
2554 e->AddAssistant((*assistList.begin())->GetGUID());
2555 assistList.pop_front();
2556 }
2558 }
2559 }
2560 }
2561}
2562
2563void Creature::CallForHelp(float radius)
2564{
2565 if (radius <= 0.0f || !IsEngaged() || !IsAlive() || IsPet() || IsCharmed())
2566 return;
2567
2569 if (!target)
2570 target = GetThreatManager().GetAnyTarget();
2571 if (!target)
2572 target = GetCombatManager().GetAnyTarget();
2573
2574 if (!target)
2575 {
2576 TC_LOG_ERROR("entities.unit", "Creature {} ({}) trying to call for help without being in combat.", GetEntry(), GetName());
2577 return;
2578 }
2579
2580 Trinity::CallOfHelpCreatureInRangeDo u_do(this, target, radius);
2582 Cell::VisitGridObjects(this, worker, radius);
2583}
2584
2585bool Creature::CanAssistTo(Unit const* u, Unit const* enemy, bool checkfaction /*= true*/) const
2586{
2587 // is it true?
2589 return false;
2590
2591 // we don't need help from zombies :)
2592 if (!IsAlive())
2593 return false;
2594
2595 // we cannot assist in evade mode
2596 if (IsInEvadeMode())
2597 return false;
2598
2599 // or if enemy is in evade mode
2600 if (enemy->GetTypeId() == TYPEID_UNIT && enemy->ToCreature()->IsInEvadeMode())
2601 return false;
2602
2603 // we don't need help from non-combatant ;)
2604 if (IsCivilian())
2605 return false;
2606
2608 return false;
2609
2610 // skip fighting creature
2611 if (IsEngaged())
2612 return false;
2613
2614 // only free creature
2615 if (!GetCharmerOrOwnerGUID().IsEmpty())
2616 return false;
2617
2618 // only from same creature faction
2619 if (checkfaction)
2620 {
2621 if (GetFaction() != u->GetFaction())
2622 return false;
2623 }
2624 else
2625 {
2626 if (!IsFriendlyTo(u))
2627 return false;
2628 }
2629
2630 // skip non hostile to caster enemy creatures
2631 if (!IsHostileTo(enemy))
2632 return false;
2633
2634 return true;
2635}
2636
2637// use this function to avoid having hostile creatures attack
2638// friendlies and other mobs they shouldn't attack
2639bool Creature::_IsTargetAcceptable(Unit const* target) const
2640{
2641 ASSERT(target);
2642
2643 // if the target cannot be attacked, the target is not acceptable
2644 if (IsFriendlyTo(target)
2645 || !target->isTargetableForAttack(false)
2646 || (m_vehicle && (IsOnVehicle(target) || m_vehicle->GetBase()->IsOnVehicle(target))))
2647 return false;
2648
2649 if (target->HasUnitState(UNIT_STATE_DIED))
2650 {
2651 // some creatures can detect fake death
2653 return true;
2654 else
2655 return false;
2656 }
2657
2658 // if I'm already fighting target, or I'm hostile towards the target, the target is acceptable
2659 if (IsEngagedBy(target) || IsHostileTo(target))
2660 return true;
2661
2662 // if the target's victim is not friendly, or the target is friendly, the target is not acceptable
2663 return false;
2664}
2665
2667{
2669 return;
2670
2672 {
2673 RespawnInfo ri;
2675 ri.spawnId = m_spawnId;
2678 return;
2679 }
2680
2681 time_t thisRespawnTime = forceDelay ? GameTime::GetGameTime() + forceDelay : m_respawnTime;
2683}
2684
2685// this should not be called by petAI or
2686bool Creature::CanCreatureAttack(Unit const* victim, bool /*force*/) const
2687{
2688 if (!victim->IsInMap(this))
2689 return false;
2690
2691 if (!IsValidAttackTarget(victim))
2692 return false;
2693
2694 if (!victim->isInAccessiblePlaceFor(this))
2695 return false;
2696
2697 if (CreatureAI* ai = AI())
2698 if (!ai->CanAIAttack(victim))
2699 return false;
2700
2701 // we cannot attack in evade mode
2702 if (IsInEvadeMode())
2703 return false;
2704
2705 // or if enemy is in evade mode
2706 if (victim->GetTypeId() == TYPEID_UNIT && victim->ToCreature()->IsInEvadeMode())
2707 return false;
2708
2710 {
2711 if (GetMap()->IsDungeon())
2712 return true;
2713
2714 // don't check distance to home position if recently damaged, this should include taunt auras
2716 return true;
2717 }
2718
2719 // Map visibility range, but no more than 2*cell size
2720 float dist = std::min<float>(GetMap()->GetVisibilityRange(), SIZE_OF_GRID_CELL * 2);
2721
2722 if (Unit* unit = GetCharmerOrOwner())
2723 return victim->IsWithinDist(unit, dist);
2724 else
2725 {
2726 // include sizes for huge npcs
2727 dist += GetCombatReach() + victim->GetCombatReach();
2728
2729 // to prevent creatures in air ignore attacks because distance is already too high...
2730 if (CanFly())
2731 return victim->IsInDist2d(&m_homePosition, dist);
2732 else
2733 return victim->IsInDist(&m_homePosition, dist);
2734 }
2735}
2736
2738{
2739 if (m_spawnId)
2740 {
2741 if (CreatureAddon const* addon = sObjectMgr->GetCreatureAddon(m_spawnId))
2742 return addon;
2743 }
2744
2745 return sObjectMgr->GetCreatureTemplateAddon(GetEntry());
2746}
2747
2748//creature_addon table
2750{
2751 CreatureAddon const* creatureAddon = GetCreatureAddon();
2752 if (!creatureAddon)
2753 return false;
2754
2755 if (uint32 mountDisplayId = _defaultMountDisplayIdOverride.value_or(creatureAddon->mount); mountDisplayId != 0)
2756 Mount(mountDisplayId);
2757
2759 ReplaceAllVisFlags(UnitVisFlags(creatureAddon->visFlags));
2760 SetAnimTier(AnimTier(creatureAddon->animTier), false);
2761
2762 SetSheath(SheathState(creatureAddon->sheathState));
2764
2765 // These fields must only be handled by core internals and must not be modified via scripts/DB dat
2768
2769 if (creatureAddon->emote != 0)
2770 SetEmoteState(Emote(creatureAddon->emote));
2771
2772 SetAIAnimKitId(creatureAddon->aiAnimKit);
2773 SetMovementAnimKitId(creatureAddon->movementAnimKit);
2774 SetMeleeAnimKitId(creatureAddon->meleeAnimKit);
2775
2776 // Check if visibility distance different
2779
2780 // Load Path
2781 if (creatureAddon->PathId != 0)
2782 _waypointPathId = creatureAddon->PathId;
2783
2784 if (!creatureAddon->auras.empty())
2785 {
2786 for (std::vector<uint32>::const_iterator itr = creatureAddon->auras.begin(); itr != creatureAddon->auras.end(); ++itr)
2787 {
2788 SpellInfo const* AdditionalSpellInfo = sSpellMgr->GetSpellInfo(*itr, GetMap()->GetDifficultyID());
2789 if (!AdditionalSpellInfo)
2790 {
2791 TC_LOG_ERROR("sql.sql", "Creature {} has wrong spell {} defined in `auras` field.", GetGUID().ToString(), *itr);
2792 continue;
2793 }
2794
2795 // skip already applied aura
2796 if (HasAura(*itr))
2797 continue;
2798
2799 AddAura(*itr, this);
2800 TC_LOG_DEBUG("entities.unit", "Spell: {} added to creature {}", *itr, GetGUID().ToString());
2801 }
2802 }
2803 return true;
2804}
2805
2806void Creature::LoadCreaturesSparringHealth(bool force /*= false*/)
2807{
2808 if (std::vector<float> const* templateValues = sObjectMgr->GetCreatureTemplateSparringValues(GetCreatureTemplate()->Entry))
2809 if (force || std::find(templateValues->begin(), templateValues->end(), _sparringHealthPct) != templateValues->end()) // only re-randomize sparring value if it was loaded from template (not when set to custom value from script)
2811}
2812
2815{
2816 uint32 enemy_team = attacker->GetTeam();
2818 packet.AreaID = GetAreaId();
2819 sWorld->SendGlobalMessage(packet.Write(), nullptr, (enemy_team == ALLIANCE ? HORDE : ALLIANCE));
2820}
2821
2822void Creature::SetCanMelee(bool canMelee, bool fleeFromMelee /*= false*/)
2823{
2824 bool wasFleeingFromMelee = HasFlag(CREATURE_STATIC_FLAG_NO_MELEE_FLEE);
2825
2826 _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_NO_MELEE_FLEE, !canMelee && fleeFromMelee);
2828
2829 if (wasFleeingFromMelee == HasFlag(CREATURE_STATIC_FLAG_NO_MELEE_FLEE))
2830 return;
2831
2832 Unit* victim = GetVictim();
2833 if (!victim)
2834 return;
2835
2837 if (!currentMovement)
2838 return;
2839
2840 bool canChangeMovement = [&]
2841 {
2842 if (wasFleeingFromMelee)
2844
2845 return currentMovement->GetMovementGeneratorType() == CHASE_MOTION_TYPE;
2846 }();
2847
2848 if (!canChangeMovement)
2849 return;
2850
2851 GetMotionMaster()->Remove(currentMovement);
2853}
2854
2856{
2858 GetMotionMaster()->MoveChase(victim, range, angle);
2859 else
2860 GetMotionMaster()->MoveFleeing(victim);
2861}
2862
2863bool Creature::HasSpell(uint32 spellID) const
2864{
2865 return std::find(std::begin(m_spells), std::end(m_spells), spellID) != std::end(m_spells);
2866}
2867
2869{
2870 time_t now = GameTime::GetGameTime();
2871 if (m_respawnTime > now)
2872 return m_respawnTime;
2873 else
2874 return now;
2875}
2876
2878{
2879 m_respawnTime = respawn ? GameTime::GetGameTime() + respawn : 0;
2880}
2881
2882void Creature::GetRespawnPosition(float &x, float &y, float &z, float* ori, float* dist) const
2883{
2884 if (m_creatureData)
2885 {
2886 if (ori)
2887 m_creatureData->spawnPoint.GetPosition(x, y, z, *ori);
2888 else
2890
2891 if (dist)
2893 }
2894 else
2895 {
2896 Position const& homePos = GetHomePosition();
2897 if (ori)
2898 homePos.GetPosition(x, y, z, *ori);
2899 else
2900 homePos.GetPosition(x, y, z);
2901 if (dist)
2902 *dist = 0;
2903 }
2904}
2905
2907{
2908 SetHover(GetMovementTemplate().IsHoverInitiallyEnabled());
2911
2912 // If an amphibious creatures was swimming while engaged, disable swimming again
2915
2917}
2918
2920{
2921 // Do not update movement flags if creature is controlled by a player (charm/vehicle)
2922 if (m_playerMovingMe)
2923 return;
2924
2925 // Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc)
2926 float ground = GetFloorZ();
2927 bool isInAir = (G3D::fuzzyGt(GetPositionZ(), ground + GetHoverOffset() + GROUND_HEIGHT_TOLERANCE) || G3D::fuzzyLt(GetPositionZ(), ground - GROUND_HEIGHT_TOLERANCE)); // Can be underground too, prevent the falling
2928 if (!isInAir)
2930
2931 // Some Amphibious creatures toggle swimming while engaged
2933 if (!IsSwimPrevented() || (GetVictim() && !GetVictim()->IsOnOceanFloor()))
2935
2936 SetSwim(IsInWater() && CanSwim());
2937}
2938
2940{
2941 if (CreatureMovementData const* movementOverride = sObjectMgr->GetCreatureMovementOverride(m_spawnId))
2942 return *movementOverride;
2943
2944 return GetCreatureTemplate()->Movement;
2945}
2946
2948{
2949 if (Unit::CanSwim())
2950 return true;
2951
2952 if (IsPet())
2953 return true;
2954
2955 return false;
2956}
2957
2959{
2960 time_t now = GameTime::GetGameTime();
2961 // Do not reset corpse remove time if corpse is already removed
2962 if (m_corpseRemoveTime <= now)
2963 return;
2964
2965 // Scripts can choose to ignore RATE_CORPSE_DECAY_LOOTED by calling SetCorpseDelay(timer, true)
2966 float decayRate = m_ignoreCorpseDecayRatio ? 1.f : sWorld->getRate(RATE_CORPSE_DECAY_LOOTED);
2967
2968 // corpse skinnable, but without skinning flag, and then skinned, corpse will despawn next update
2969 bool isFullySkinned = [&]() -> bool
2970 {
2971 if (m_loot && m_loot->loot_type == LOOT_SKINNING && m_loot->isLooted())
2972 return true;
2973
2974 bool hasSkinningLoot = false;
2975 for (auto const& [_, loot] : m_personalLoot)
2976 {
2977 if (loot->loot_type == LOOT_SKINNING)
2978 {
2979 if (!loot->isLooted())
2980 return false;
2981
2982 hasSkinningLoot = true;
2983 }
2984 }
2985
2986 return hasSkinningLoot;
2987 }();
2988
2989 if (isFullySkinned)
2990 m_corpseRemoveTime = now;
2991 else
2992 m_corpseRemoveTime = now + uint32(m_corpseDelay * decayRate);
2993
2995}
2996
2998{
3000 Unit::SetInteractionAllowedWhileHostile(interactionAllowed);
3001}
3002
3003void Creature::SetInteractionAllowedInCombat(bool interactionAllowed)
3004{
3006 Unit::SetInteractionAllowedInCombat(interactionAllowed);
3007}
3008
3010{
3012
3013 // If as a result of npcflag updates we stop seeing UNIT_NPC_FLAG_QUESTGIVER then
3014 // we must also send SMSG_QUEST_GIVER_STATUS_MULTIPLE because client will not request it automatically
3015 if (IsQuestGiver())
3016 {
3017 auto sender = [&](Player const* receiver)
3018 {
3019 receiver->PlayerTalkClass->SendQuestGiverStatus(receiver->GetQuestDialogStatus(this), GetGUID());
3020 };
3021 Trinity::MessageDistDeliverer notifier(this, sender, GetVisibilityRange());
3023 }
3024}
3025
3027{
3028 return m_unitData->ContentTuningID != 0;
3029}
3030
3032{
3033 CreatureDifficulty const* creatureDifficulty = GetCreatureDifficulty();
3034
3035 if (Optional<ContentTuningLevels> levels = sDB2Manager.GetContentTuningData(creatureDifficulty->ContentTuningID, 0))
3036 {
3039 }
3040
3041 int32 mindelta = std::min(creatureDifficulty->DeltaLevelMax, creatureDifficulty->DeltaLevelMin);
3042 int32 maxdelta = std::max(creatureDifficulty->DeltaLevelMax, creatureDifficulty->DeltaLevelMin);
3043 int32 delta = mindelta == maxdelta ? mindelta : irand(mindelta, maxdelta);
3044
3047}
3048
3050{
3051 CreatureTemplate const* cInfo = GetCreatureTemplate();
3052 CreatureDifficulty const* creatureDifficulty = GetCreatureDifficulty();
3053 float baseHealth = sDB2Manager.EvaluateExpectedStat(ExpectedStatType::CreatureHealth, level, creatureDifficulty->GetHealthScalingExpansion(), creatureDifficulty->ContentTuningID, Classes(cInfo->unit_class), 0);
3054 return std::max(baseHealth * creatureDifficulty->HealthModifier, 1.0f);
3055}
3056
3058{
3059 if (!HasScalableLevels())
3060 return 1.0f;
3061
3062 uint8 levelForTarget = GetLevelForTarget(target);
3063 if (GetLevel() < levelForTarget)
3064 return 1.0f;
3065
3066 return double(GetMaxHealthByLevel(levelForTarget)) / double(GetCreateHealth());
3067}
3068
3070{
3071 CreatureTemplate const* cInfo = GetCreatureTemplate();
3072 CreatureDifficulty const* creatureDifficulty = GetCreatureDifficulty();
3073 return sDB2Manager.EvaluateExpectedStat(ExpectedStatType::CreatureAutoAttackDps, level, creatureDifficulty->GetHealthScalingExpansion(), creatureDifficulty->ContentTuningID, Classes(cInfo->unit_class), 0);
3074}
3075
3077{
3078 if (!HasScalableLevels())
3079 return 1.0f;
3080
3081 uint8 levelForTarget = GetLevelForTarget(target);
3082
3083 return GetBaseDamageForLevel(levelForTarget) / GetBaseDamageForLevel(GetLevel());
3084}
3085
3087{
3088 CreatureTemplate const* cInfo = GetCreatureTemplate();
3089 CreatureDifficulty const* creatureDifficulty = GetCreatureDifficulty();
3090 float baseArmor = sDB2Manager.EvaluateExpectedStat(ExpectedStatType::CreatureArmor, level, creatureDifficulty->GetHealthScalingExpansion(), creatureDifficulty->ContentTuningID, Classes(cInfo->unit_class), 0);
3091 return baseArmor * creatureDifficulty->ArmorModifier;
3092}
3093
3095{
3096 if (!HasScalableLevels())
3097 return 1.0f;
3098
3099 uint8 levelForTarget = GetLevelForTarget(target);
3100
3101 return GetBaseArmorForLevel(levelForTarget) / GetBaseArmorForLevel(GetLevel());
3102}
3103
3105{
3106 if (Unit const* unitTarget = target->ToUnit())
3107 {
3108 if (isWorldBoss())
3109 {
3110 uint8 level = unitTarget->GetLevel() + sWorld->getIntConfig(CONFIG_WORLD_BOSS_LEVEL_DIFF);
3111 return RoundToInterval<uint8>(level, 1u, 255u);
3112 }
3113
3114 // If this creature should scale level, adapt level depending of target level
3115 // between UNIT_FIELD_SCALING_LEVEL_MIN and UNIT_FIELD_SCALING_LEVEL_MAX
3116 if (HasScalableLevels())
3117 {
3118 int32 scalingLevelMin = m_unitData->ScalingLevelMin;
3119 int32 scalingLevelMax = m_unitData->ScalingLevelMax;
3120 int32 scalingLevelDelta = m_unitData->ScalingLevelDelta;
3121 int32 scalingFactionGroup = m_unitData->ScalingFactionGroup;
3122 int32 targetLevel = unitTarget->m_unitData->EffectiveLevel;
3123 if (!targetLevel)
3124 targetLevel = unitTarget->GetLevel();
3125
3126 int32 targetLevelDelta = 0;
3127
3128 if (Player const* playerTarget = target->ToPlayer())
3129 {
3130 if (scalingFactionGroup && sFactionTemplateStore.AssertEntry(sChrRacesStore.AssertEntry(playerTarget->GetRace())->FactionID)->FactionGroup != scalingFactionGroup)
3131 scalingLevelMin = scalingLevelMax;
3132
3133 int32 maxCreatureScalingLevel = playerTarget->m_activePlayerData->MaxCreatureScalingLevel;
3134 targetLevelDelta = std::min(maxCreatureScalingLevel > 0 ? maxCreatureScalingLevel - targetLevel : 0, *playerTarget->m_activePlayerData->ScalingPlayerLevelDelta);
3135 }
3136
3137 int32 levelWithDelta = targetLevel + targetLevelDelta;
3138 int32 level = RoundToInterval(levelWithDelta, scalingLevelMin, scalingLevelMax) + scalingLevelDelta;
3139 return RoundToInterval(level, 1, MAX_LEVEL + 3);
3140 }
3141 }
3142
3143 return Unit::GetLevelForTarget(target);
3144}
3145
3146std::string const& Creature::GetAIName() const
3147{
3148 return sObjectMgr->GetCreatureTemplate(GetEntry())->AIName;
3149}
3150
3151std::string Creature::GetScriptName() const
3152{
3153 return sObjectMgr->GetScriptName(GetScriptId());
3154}
3155
3157{
3159 if (uint32 scriptId = creatureData->scriptId)
3160 return scriptId;
3161
3162 return ASSERT_NOTNULL(sObjectMgr->GetCreatureTemplate(GetEntry()))->ScriptID;
3163}
3164
3165bool Creature::HasStringId(std::string_view id) const
3166{
3167 return std::find(m_stringIds.begin(), m_stringIds.end(), id) != m_stringIds.end();
3168}
3169
3171{
3172 if (!id.empty())
3173 {
3174 m_scriptStringId.emplace(std::move(id));
3176 }
3177 else
3178 {
3179 m_scriptStringId.reset();
3180 m_stringIds[2] = {};
3181 }
3182}
3183
3185{
3186 return sObjectMgr->GetNpcVendorItemList(GetEntry());
3187}
3188
3190{
3191 if (!vItem->maxcount)
3192 return vItem->maxcount;
3193
3194 VendorItemCounts::iterator itr = m_vendorItemCounts.begin();
3195 for (; itr != m_vendorItemCounts.end(); ++itr)
3196 if (itr->itemId == vItem->item)
3197 break;
3198
3199 if (itr == m_vendorItemCounts.end())
3200 return vItem->maxcount;
3201
3202 VendorItemCount* vCount = &*itr;
3203
3204 time_t ptime = GameTime::GetGameTime();
3205
3206 if (time_t(vCount->lastIncrementTime + vItem->incrtime) <= ptime)
3207 if (ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(vItem->item))
3208 {
3209 uint32 diff = uint32((ptime - vCount->lastIncrementTime)/vItem->incrtime);
3210 if ((vCount->count + diff * pProto->GetBuyCount()) >= vItem->maxcount)
3211 {
3212 m_vendorItemCounts.erase(itr);
3213 return vItem->maxcount;
3214 }
3215
3216 vCount->count += diff * pProto->GetBuyCount();
3217 vCount->lastIncrementTime = ptime;
3218 }
3219
3220 return vCount->count;
3221}
3222
3224{
3225 if (!vItem->maxcount)
3226 return 0;
3227
3228 VendorItemCounts::iterator itr = m_vendorItemCounts.begin();
3229 for (; itr != m_vendorItemCounts.end(); ++itr)
3230 if (itr->itemId == vItem->item)
3231 break;
3232
3233 if (itr == m_vendorItemCounts.end())
3234 {
3235 uint32 new_count = vItem->maxcount > used_count ? vItem->maxcount-used_count : 0;
3236 m_vendorItemCounts.push_back(VendorItemCount(vItem->item, new_count));
3237 return new_count;
3238 }
3239
3240 VendorItemCount* vCount = &*itr;
3241
3242 time_t ptime = GameTime::GetGameTime();
3243
3244 if (time_t(vCount->lastIncrementTime + vItem->incrtime) <= ptime)
3245 if (ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(vItem->item))
3246 {
3247 uint32 diff = uint32((ptime - vCount->lastIncrementTime)/vItem->incrtime);
3248 if ((vCount->count + diff * pProto->GetBuyCount()) < vItem->maxcount)
3249 vCount->count += diff * pProto->GetBuyCount();
3250 else
3251 vCount->count = vItem->maxcount;
3252 }
3253
3254 vCount->count = vCount->count > used_count ? vCount->count-used_count : 0;
3255 vCount->lastIncrementTime = ptime;
3256 return vCount->count;
3257}
3258
3259// overwrite WorldObject function for proper name localization
3261{
3262 if (locale != DEFAULT_LOCALE)
3263 if (CreatureLocale const* cl = sObjectMgr->GetCreatureLocale(GetEntry()))
3264 if (cl->Name.size() > locale && !cl->Name[locale].empty())
3265 return cl->Name[locale];
3266
3267 return GetName();
3268}
3269
3271{
3272 return MAX_SPELL_CHARM;
3273}
3274
3276{
3277 if (pos >= MAX_SPELL_CHARM || !m_charmInfo || m_charmInfo->GetCharmSpell(pos)->GetType() != ACT_ENABLED)
3278 return 0;
3279 else
3280 return m_charmInfo->GetCharmSpell(pos)->GetAction();
3281}
3282
3284{
3285 float range = 0.f;
3286
3287 for (uint8 i = 0; i < GetPetAutoSpellSize(); ++i)
3288 {
3289 uint32 spellID = GetPetAutoSpellOnPos(i);
3290 if (!spellID)
3291 continue;
3292
3293 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellID, GetMap()->GetDifficultyID()))
3294 {
3295 if (spellInfo->GetRecoveryTime() == 0 && spellInfo->RangeEntry && spellInfo->RangeEntry->ID != 1 /*Self*/ && spellInfo->RangeEntry->ID != 2 /*Combat Range*/ && spellInfo->GetMaxRange() > range)
3296 range = spellInfo->GetMaxRange();
3297 }
3298 }
3299
3300 return range;
3301}
3302
3304{
3305 if (cannotReach == m_cannotReachTarget)
3306 return;
3307 m_cannotReachTarget = cannotReach;
3309
3310 if (cannotReach)
3311 TC_LOG_DEBUG("entities.unit.chase", "Creature::SetCannotReachTarget() called with true. Details: {}", GetDebugInfo());
3312}
3313
3315{
3316 if (mountCreatureDisplayId && !sCreatureDisplayInfoStore.HasRecord(*mountCreatureDisplayId))
3317 mountCreatureDisplayId.reset();
3318
3319 _defaultMountDisplayIdOverride = mountCreatureDisplayId;
3320}
3321
3322float Creature::GetAggroRange(Unit const* target) const
3323{
3324 // Determines the aggro range for creatures (usually pets), used mainly for aggressive pet target selection.
3325 // Based on data from wowwiki due to lack of 3.3.5a data
3326
3327 if (target && IsPet())
3328 {
3329 uint32 targetLevel = 0;
3330
3331 if (target->GetTypeId() == TYPEID_PLAYER)
3332 targetLevel = target->GetLevelForTarget(this);
3333 else if (target->GetTypeId() == TYPEID_UNIT)
3334 targetLevel = target->ToCreature()->GetLevelForTarget(this);
3335
3336 uint32 myLevel = GetLevelForTarget(target);
3337 int32 levelDiff = int32(targetLevel) - int32(myLevel);
3338
3339 // The maximum Aggro Radius is capped at 45 yards (25 level difference)
3340 if (levelDiff < -25)
3341 levelDiff = -25;
3342
3343 // The base aggro radius for mob of same level
3344 float aggroRadius = 20;
3345
3346 // Aggro Radius varies with level difference at a rate of roughly 1 yard/level
3347 aggroRadius -= (float)levelDiff;
3348
3349 // detect range auras
3351
3352 // detected range auras
3354
3355 // Just in case, we don't want pets running all over the map
3356 if (aggroRadius > MAX_AGGRO_RADIUS)
3357 aggroRadius = MAX_AGGRO_RADIUS;
3358
3359 // Minimum Aggro Radius for a mob seems to be combat range (5 yards)
3360 // hunter pets seem to ignore minimum aggro radius so we'll default it a little higher
3361 if (aggroRadius < 10)
3362 aggroRadius = 10;
3363
3364 return (aggroRadius);
3365 }
3366
3367 // Default
3368 return 0.0f;
3369}
3370
3371Unit* Creature::SelectNearestHostileUnitInAggroRange(bool useLOS, bool ignoreCivilians) const
3372{
3373 // Selects nearest hostile target within creature's aggro range. Used primarily by
3374 // pets set to aggressive. Will not return neutral or friendly targets.
3375
3376 Unit* target = nullptr;
3377
3378 Trinity::NearestHostileUnitInAggroRangeCheck u_check(this, useLOS, ignoreCivilians);
3380
3382
3383 return target;
3384}
3385
3387{
3388 return GetCreatureTemplate()->scale;
3389}
3390
3392{
3393 Unit::SetObjectScale(scale);
3394
3395 if (CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(GetDisplayId()))
3396 {
3397 SetBoundingRadius((IsPet() ? 1.0f : minfo->bounding_radius) * scale * GetDisplayScale());
3398 SetCombatReach((IsPet() ? DEFAULT_PLAYER_COMBAT_REACH : minfo->combat_reach) * scale * GetDisplayScale());
3399 }
3400}
3401
3402void Creature::SetDisplayId(uint32 displayId, bool setNative /*= false*/)
3403{
3404 Unit::SetDisplayId(displayId, setNative);
3405
3406 if (CreatureModelInfo const* modelInfo = sObjectMgr->GetCreatureModelInfo(displayId))
3407 {
3408 SetBoundingRadius((IsPet() ? 1.0f : modelInfo->bounding_radius) * GetObjectScale() * GetDisplayScale());
3409 SetCombatReach((IsPet() ? DEFAULT_PLAYER_COMBAT_REACH : modelInfo->combat_reach) * GetObjectScale() * GetDisplayScale());
3410 }
3411}
3412
3414{
3415 if (CreatureModel const* model = GetCreatureTemplate()->GetModelByIdx(modelIdx))
3416 SetDisplayId(model->CreatureDisplayID);
3417}
3418
3420{
3421 if (HasSpellFocus())
3422 _spellFocusInfo.Target = guid;
3423 else
3425}
3426
3427void Creature::SetSpellFocus(Spell const* focusSpell, WorldObject const* target)
3428{
3429 // Pointer validation and checking for a already existing focus
3430 if (_spellFocusInfo.Spell || !focusSpell)
3431 return;
3432
3433 // Prevent dead / feign death creatures from setting a focus target
3435 return;
3436
3437 // Don't allow stunned creatures to set a focus target
3439 return;
3440
3441 // some spells shouldn't track targets
3442 if (focusSpell->IsFocusDisabled())
3443 return;
3444
3445 SpellInfo const* spellInfo = focusSpell->GetSpellInfo();
3446
3447 // don't use spell focus for vehicle spells
3448 if (spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE))
3449 return;
3450
3451 // instant non-channeled casts and non-target spells don't need facing updates
3452 if (!target && (!focusSpell->GetCastTime() && !spellInfo->IsChanneled()))
3453 return;
3454
3455 // store pre-cast values for target and orientation (used to later restore)
3456 if (!_spellFocusInfo.Delay)
3457 { // only overwrite these fields if we aren't transitioning from one spell focus to another
3458 _spellFocusInfo.Target = GetTarget();
3459 _spellFocusInfo.Orientation = GetOrientation();
3460 }
3461 else // don't automatically reacquire target for the previous spellcast
3462 _spellFocusInfo.Delay = 0;
3463
3464 _spellFocusInfo.Spell = focusSpell;
3465
3466 bool const noTurnDuringCast = spellInfo->HasAttribute(SPELL_ATTR5_AI_DOESNT_FACE_TARGET);
3467 bool const turnDisabled = CannotTurn();
3468 // set target, then force send update packet to players if it changed to provide appropriate facing
3469 ObjectGuid newTarget = (target && !noTurnDuringCast && !turnDisabled) ? target->GetGUID() : ObjectGuid::Empty;
3470 if (GetTarget() != newTarget)
3472
3473 // If we are not allowed to turn during cast but have a focus target, face the target
3474 if (!turnDisabled && noTurnDuringCast && target)
3475 SetFacingToObject(target, false);
3476
3477 if (noTurnDuringCast)
3479}
3480
3481bool Creature::HasSpellFocus(Spell const* focusSpell) const
3482{
3483 if (isDead()) // dead creatures cannot focus
3484 {
3485 if (_spellFocusInfo.Spell || _spellFocusInfo.Delay)
3486 {
3487 TC_LOG_WARN("entities.unit", "Creature '{}' (entry {}) has spell focus (spell id {}, delay {}ms) despite being dead.",
3488 GetName(), GetEntry(), _spellFocusInfo.Spell ? _spellFocusInfo.Spell->GetSpellInfo()->Id : 0, _spellFocusInfo.Delay);
3489 }
3490 return false;
3491 }
3492
3493 if (focusSpell)
3494 return (focusSpell == _spellFocusInfo.Spell);
3495 else
3496 return (_spellFocusInfo.Spell || _spellFocusInfo.Delay);
3497}
3498
3499void Creature::ReleaseSpellFocus(Spell const* focusSpell, bool withDelay)
3500{
3501 if (!_spellFocusInfo.Spell)
3502 return;
3503
3504 // focused to something else
3505 if (focusSpell && focusSpell != _spellFocusInfo.Spell)
3506 return;
3507
3508 if (_spellFocusInfo.Spell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_AI_DOESNT_FACE_TARGET))
3510
3511 if (IsPet()) // player pets do not use delay system
3512 {
3513 if (!CannotTurn())
3515 }
3516 else // don't allow re-target right away to prevent visual bugs
3517 _spellFocusInfo.Delay = withDelay ? 1000 : 1;
3518
3519 _spellFocusInfo.Spell = nullptr;
3520}
3521
3523{
3524 if (!HasSpellFocus())
3525 {
3526 TC_LOG_ERROR("entities.unit", "Creature::ReacquireSpellFocusTarget() being called with HasSpellFocus() returning false. {}", GetDebugInfo());
3527 return;
3528 }
3529
3531
3532 if (!CannotTurn())
3533 {
3534 if (!_spellFocusInfo.Target.IsEmpty())
3535 {
3536 if (WorldObject const* objTarget = ObjectAccessor::GetWorldObject(*this, _spellFocusInfo.Target))
3537 SetFacingToObject(objTarget, false);
3538 }
3539 else
3540 SetFacingTo(_spellFocusInfo.Orientation, false);
3541 }
3542 _spellFocusInfo.Delay = 0;
3543}
3544
3546{
3547 _spellFocusInfo.Delay = 0;
3548 _spellFocusInfo.Spell = nullptr;
3549}
3550
3552{
3554 return false;
3555
3556 return true;
3557}
3558
3560{
3562}
3563
3565{
3567}
3568
3570{
3571 CreatureTextRepeatIds& repeats = m_textRepeat[textGroup];
3572 if (std::find(repeats.begin(), repeats.end(), id) == repeats.end())
3573 repeats.push_back(id);
3574 else
3575 TC_LOG_ERROR("sql.sql", "CreatureTextMgr: TextGroup {} for Creature({}) {}, id {} already added", uint32(textGroup), GetName(), GetGUID().ToString(), uint32(id));
3576}
3577
3579{
3581
3582 CreatureTextRepeatGroup::const_iterator groupItr = m_textRepeat.find(textGroup);
3583 if (groupItr != m_textRepeat.end())
3584 ids = groupItr->second;
3585
3586 return ids;
3587}
3588
3590{
3591 CreatureTextRepeatGroup::iterator groupItr = m_textRepeat.find(textGroup);
3592 if (groupItr != m_textRepeat.end())
3593 groupItr->second.clear();
3594}
3595
3597{
3599}
3600
3602{
3603 if (CreatureAI const* ai = AI())
3604 return ai->IsEngaged();
3605 return false;
3606}
3607
3609{
3610 Unit::AtEngage(target);
3611
3613 Dismount();
3614
3615 if (IsPet() || IsGuardian()) // update pets' speed for catchup OOC speed
3616 {
3620 }
3621
3623 if (movetype == WAYPOINT_MOTION_TYPE || movetype == POINT_MOTION_TYPE || (IsAIEnabled() && AI()->IsEscorted()))
3624 {
3626
3627 // if its a vehicle, set the home positon of every creature passenger at engage
3628 // so that they are in combat range if hostile
3629 if (Vehicle* vehicle = GetVehicleKit())
3630 {
3631 for (auto seat = vehicle->Seats.begin(); seat != vehicle->Seats.end(); ++seat)
3632 if (Unit* passenger = ObjectAccessor::GetUnit(*this, seat->second.Passenger.Guid))
3633 if (Creature* creature = passenger->ToCreature())
3634 creature->SetHomePosition(GetPosition());
3635 }
3636 }
3637
3638 if (CreatureAI* ai = AI())
3639 ai->JustEngagedWith(target);
3640 if (CreatureGroup* formation = GetFormation())
3641 formation->MemberEngagingTarget(this, target);
3642}
3643
3645{
3647
3651
3652 if (IsPet() || IsGuardian()) // update pets' speed for catchup OOC speed
3653 {
3657 }
3658}
3659
3661{
3662 if (CreatureAI const* ai = AI())
3663 return ai->IsEscorted();
3664 return false;
3665}
3666
3667std::string Creature::GetDebugInfo() const
3668{
3669 std::stringstream sstr;
3670 sstr << Unit::GetDebugInfo() << "\n"
3671 << "AIName: " << GetAIName() << " ScriptName: " << GetScriptName()
3672 << " WaypointPath: " << GetWaypointPathId() << " SpawnId: " << GetSpawnId();
3673 return sstr.str();
3674}
3675
3676void Creature::ExitVehicle(Position const* /*exitPosition*/)
3677{
3679
3680 // if the creature exits a vehicle, set it's home position to the
3681 // exited position so it won't run away (home) and evade if it's hostile
3683}
3684
3686{
3687 return _gossipMenuId;
3688}
3689
3691{
3692 _gossipMenuId = gossipMenuId;
3693}
3694
3696{
3697 if (_trainerId)
3698 return *_trainerId;
3699
3700 return sObjectMgr->GetCreatureDefaultTrainer(GetEntry());
3701}
3702
3704{
3705 _trainerId = trainerId;
3706}
3707
3709{
3713
3715{
3716 if (!IsAreaSpiritHealer())
3717 return;
3718
3720
3721 // maybe NPC is summoned with these spells:
3722 // ID - 24237 Summon Alliance Graveyard Teleporter (SERVERSIDE)
3723 // ID - 46894 Summon Horde Graveyard Teleporter (SERVERSIDE)
3724 SummonCreature(npcEntry, GetPosition(), TEMPSUMMON_TIMED_DESPAWN, 1s, 0, 0);
3725}
3726
3728{
3729 auto clickBounds = sObjectMgr->GetSpellClickInfoMapBounds(GetEntry());
3730 auto itr = clickBounds.begin();
3731 // Set InteractSpellID if there is only one row in npc_spellclick_spells in db for this creature
3732 if (itr != clickBounds.end() && ++itr == clickBounds.end())
3733 SetInteractSpellId(clickBounds.begin()->second.spellId);
3734 else
3736}
#define sBattlegroundMgr
@ SPELL_SPIRIT_HEAL_CHANNEL_AOE
Definition: Battleground.h:101
constexpr uint8 MAX_SPELL_CHARM
Definition: CharmInfo.h:28
LocaleConstant
Definition: Common.h:48
@ TOTAL_LOCALES
Definition: Common.h:62
@ LOCALE_enUS
Definition: Common.h:49
#define DEFAULT_LOCALE
Definition: Common.h:66
@ IN_MILLISECONDS
Definition: Common.h:35
@ MINUTE
Definition: Common.h:29
@ WEEK
Definition: Common.h:32
const uint32 CREATURE_REGEN_INTERVAL
Definition: CreatureData.h:412
@ CREATURE_FLAG_EXTRA_DUNGEON_BOSS
Definition: CreatureData.h:362
@ CREATURE_FLAG_EXTRA_IGNORE_PATHFINDING
Definition: CreatureData.h:363
@ CREATURE_FLAG_EXTRA_CANNOT_ENTER_COMBAT
Definition: CreatureData.h:347
@ CREATURE_FLAG_EXTRA_NO_XP
Definition: CreatureData.h:340
@ CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK
Definition: CreatureData.h:364
@ CREATURE_FLAG_EXTRA_IGNORE_FEIGN_DEATH
Definition: CreatureData.h:350
@ CREATURE_FLAG_EXTRA_NO_TAUNT
Definition: CreatureData.h:342
@ CREATURE_FLAG_EXTRA_GHOST_VISIBILITY
Definition: CreatureData.h:344
@ CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK
Definition: CreatureData.h:345
@ CREATURE_FLAG_EXTRA_WORLDEVENT
Definition: CreatureData.h:348
@ CREATURE_STATIC_FLAG_CAN_SWIM
Definition: CreatureData.h:66
@ CREATURE_STATIC_FLAG_NO_XP
Definition: CreatureData.h:39
@ CREATURE_STATIC_FLAG_NO_MELEE_FLEE
Definition: CreatureData.h:58
CreatureChaseMovementType
Definition: CreatureData.h:376
const uint8 MAX_KILL_CREDIT
Definition: CreatureData.h:416
@ CREATURE_STATIC_FLAG_4_NO_BIRTH_ANIM
Definition: CreatureData.h:152
@ CREATURE_STATIC_FLAG_4_NO_MELEE_APPROACH
Definition: CreatureData.h:161
@ CREATURE_STATIC_FLAG_5_NO_HEALTH_REGEN
Definition: CreatureData.h:217
@ CREATURE_STATIC_FLAG_5_INTERACT_WHILE_HOSTILE
Definition: CreatureData.h:198
CreatureRandomMovementType
Definition: CreatureData.h:385
const uint32 CREATURE_NOPATH_EVADE_TIME
Definition: CreatureData.h:414
@ CREATURE_STATIC_FLAG_3_ALLOW_INTERACTION_WHILE_IN_COMBAT
Definition: CreatureData.h:132
@ CREATURE_STATIC_FLAG_2_ALLOW_MOUNTED_COMBAT
Definition: CreatureData.h:94
const uint32 MAX_CREATURE_SPELLS
Definition: CreatureData.h:419
const uint32 PET_FOCUS_REGEN_INTERVAL
Definition: CreatureData.h:413
#define sFormationMgr
AreaSpiritHealerData
Definition: Creature.cpp:3709
@ NPC_ALLIANCE_GRAVEYARD_TELEPORT
Definition: Creature.cpp:3710
@ NPC_HORDE_GRAVEYARD_TELEPORT
Definition: Creature.cpp:3711
std::vector< uint8 > CreatureTextRepeatIds
Definition: Creature.h:66
#define CREATURE_Z_ATTACK_RANGE
Definition: Creature.h:52
static constexpr uint8 WILD_BATTLE_PET_DEFAULT_LEVEL
Definition: Creature.h:62
static constexpr size_t CREATURE_TAPPERS_SOFT_CAP
Definition: Creature.h:63
DB2Storage< DifficultyEntry > sDifficultyStore("Difficulty.db2", &DifficultyLoadInfo::Instance)
DB2Storage< ChrRacesEntry > sChrRacesStore("ChrRaces.db2", &ChrRacesLoadInfo::Instance)
DB2Storage< CreatureDisplayInfoEntry > sCreatureDisplayInfoStore("CreatureDisplayInfo.db2", &CreatureDisplayInfoLoadInfo::Instance)
DB2Storage< FactionTemplateEntry > sFactionTemplateStore("FactionTemplate.db2", &FactionTemplateLoadInfo::Instance)
DB2Storage< AreaTableEntry > sAreaTableStore("AreaTable.db2", &AreaTableLoadInfo::Instance)
#define sDB2Manager
Definition: DB2Stores.h:538
@ MAX_LEVEL
Definition: DBCEnums.h:51
@ STRONG_MAX_LEVEL
Definition: DBCEnums.h:55
Difficulty
Definition: DBCEnums.h:873
@ DIFFICULTY_NONE
Definition: DBCEnums.h:874
@ FACTION_MASK_ALLIANCE
Definition: DBCEnums.h:950
@ UnitsUseDefaultPowerOnInit
@ FACTION_TEMPLATE_FLAG_PVP
Definition: DBCEnums.h:942
SQLTransaction< WorldDatabaseConnection > WorldDatabaseTransaction
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
Definition: DatabaseEnv.cpp:20
uint8_t uint8
Definition: Define.h:144
int8_t int8
Definition: Define.h:140
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
#define UI64LIT(N)
Definition: Define.h:127
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
uint16 flags
Definition: DisableMgr.cpp:49
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition: Duration.h:32
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition: Duration.h:29
#define ASSERT_NOTNULL(pointer)
Definition: Errors.h:84
#define ASSERT
Definition: Errors.h:68
#define sGameEventMgr
Definition: GameEventMgr.h:177
#define MAX_FALL_DISTANCE
Definition: GridDefines.h:62
#define SIZE_OF_GRID_CELL
Definition: GridDefines.h:48
#define TC_LOG_WARN(filterType__,...)
Definition: Log.h:162
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
@ LOOT_SKINNING
Definition: Loot.h:106
#define sMapMgr
Definition: MapManager.h:184
MovementGeneratorType
@ IDLE_MOTION_TYPE
@ CHASE_MOTION_TYPE
@ WAYPOINT_MOTION_TYPE
@ FLEEING_MOTION_TYPE
@ HOME_MOTION_TYPE
@ POINT_MOTION_TYPE
@ RANDOM_MOTION_TYPE
#define ATTACK_DISTANCE
Definition: ObjectDefines.h:25
#define MAX_VISIBILITY_DISTANCE
Definition: ObjectDefines.h:28
#define DEFAULT_PLAYER_COMBAT_REACH
Definition: ObjectDefines.h:40
@ TEMPSUMMON_TIMED_DESPAWN
Definition: ObjectDefines.h:65
#define DEFAULT_PLAYER_DISPLAY_SCALE
Definition: ObjectDefines.h:41
@ TYPEID_UNIT
Definition: ObjectGuid.h:40
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
#define sObjectMgr
Definition: ObjectMgr.h:1946
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
#define sPoolMgr
Definition: PoolMgr.h:179
@ RACE_NONE
Definition: RaceMask.h:27
int32 irand(int32 min, int32 max)
Definition: Random.cpp:35
uint32 urand(uint32 min, uint32 max)
Definition: Random.cpp:42
void SendGossipMenuFor(Player *player, uint32 npcTextID, ObjectGuid const &guid)
void ClearGossipMenuFor(Player *player)
@ SERVERSIDE_VISIBILITY_GHOST
Classes
constexpr uint32 GetMaxLevelForExpansion(uint32 expansion)
@ SPELL_ATTR5_AI_DOESNT_FACE_TARGET
@ XP_GRAY
Emote
@ SPELL_SCHOOL_MASK_NORMAL
@ CREATURE_TYPE_CRITTER
@ CREATURE_TYPE_NON_COMBAT_PET
@ CREATURE_TYPE_MECHANICAL
@ UNIT_DYNFLAG_TAPPED
@ UNIT_DYNFLAG_LOOTABLE
@ UNIT_DYNFLAG_NONE
AiReaction
SpellEffectName
@ SPELL_EFFECT_HEAL
@ SPELL_EFFECT_ATTACK_ME
@ SPELL_EFFECT_KNOCK_BACK_DEST
@ SPELL_EFFECT_KNOCK_BACK
@ OFF_ATTACK
@ BASE_ATTACK
@ RANGED_ATTACK
float const GROUND_HEIGHT_TOLERANCE
Definition: SharedDefines.h:25
@ IMMUNITY_STATE
@ IMMUNITY_EFFECT
@ IMMUNITY_MECHANIC
@ IMMUNITY_SCHOOL
@ IMMUNITY_OTHER
@ IMMUNITY_DISPEL
@ ALLIANCE
@ HORDE
Powers
@ POWER_ENERGY
@ POWER_MANA
@ POWER_FOCUS
BattlegroundTypeId
@ BATTLEGROUND_AA
@ BATTLEGROUND_WS
@ BATTLEGROUND_EY
@ BATTLEGROUND_AV
@ BATTLEGROUND_BE
@ BATTLEGROUND_RV
@ BATTLEGROUND_NA
@ BATTLEGROUND_DS
@ BATTLEGROUND_SA
@ BATTLEGROUND_AB
@ BATTLEGROUND_RL
@ GHOST_VISIBILITY_ALIVE
@ GHOST_VISIBILITY_GHOST
CreatureClassifications
@ FACTION_ALLIANCE_GENERIC
SpellSchools
@ SPELL_SCHOOL_SHADOW
@ SPELL_SCHOOL_NATURE
@ SPELL_SCHOOL_FROST
@ SPELL_SCHOOL_ARCANE
@ SPELL_SCHOOL_FIRE
@ SPELL_SCHOOL_HOLY
@ CREATURE_TYPE_FLAG_VISIBLE_TO_GHOSTS
@ CREATURE_TYPE_FLAG_BOSS_MOB
@ CREATURE_TYPE_FLAG_ALLOW_INTERACTION_WHILE_IN_COMBAT
@ CREATURE_TYPE_FLAG_TREAT_AS_RAID_UNIT
Creature can be targeted by spells that require target to be in caster's party/raid.
@ CREATURE_TYPE_FLAG_ALLOW_MOUNTED_COMBAT
@ SPAWNGROUP_FLAG_COMPATIBILITY_MODE
Definition: SpawnData.h:55
@ LINKED_RESPAWN_CREATURE_TO_GO
Definition: SpawnData.h:123
@ LINKED_RESPAWN_CREATURE_TO_CREATURE
Definition: SpawnData.h:122
@ LINKED_RESPAWN_GO_TO_CREATURE
Definition: SpawnData.h:125
@ SPAWN_TYPE_CREATURE
Definition: SpawnData.h:34
AuraType
@ SPELL_AURA_MOD_POWER_REGEN
@ SPELL_AURA_PREVENTS_FLEEING
@ SPELL_AURA_CONTROL_VEHICLE
@ SPELL_AURA_MOD_INVISIBILITY
@ SPELL_AURA_MOD_HEALTH_REGEN_PERCENT
@ SPELL_AURA_MOD_DETECTED_RANGE
@ SPELL_AURA_MOD_TAUNT
@ SPELL_AURA_FEIGN_DEATH
@ SPELL_AURA_MOD_POWER_REGEN_PERCENT
@ SPELL_AURA_MOD_DETECT_RANGE
@ SPELL_AURA_MOD_REGEN
@ FORM_NONE
#define sSpellMgr
Definition: SpellMgr.h:849
@ MOVE_FLIGHT
Definition: UnitDefines.h:123
@ MOVE_SWIM
Definition: UnitDefines.h:120
@ MOVE_RUN
Definition: UnitDefines.h:118
@ MOVE_WALK
Definition: UnitDefines.h:117
UnitFlags2
Definition: UnitDefines.h:193
@ UNIT_FLAG2_FEIGN_DEATH
Definition: UnitDefines.h:194
@ UNIT_FLAG2_REGENERATE_POWER
Definition: UnitDefines.h:205
@ UNIT_PET_FLAG_NONE
Definition: UnitDefines.h:108
@ REACT_PASSIVE
Definition: UnitDefines.h:506
@ REACT_AGGRESSIVE
Definition: UnitDefines.h:508
UnitStandStateType
Definition: UnitDefines.h:41
@ MOVEMENTFLAG_FALLING
Definition: UnitDefines.h:369
@ ACT_ENABLED
Definition: UnitDefines.h:498
NPCFlags
Non Player Character flags.
Definition: UnitDefines.h:295
@ UNIT_NPC_FLAG_NONE
Definition: UnitDefines.h:296
@ UNIT_NPC_FLAG_SPELLCLICK
Definition: UnitDefines.h:321
UnitFlags3
Definition: UnitDefines.h:245
SheathState
Definition: UnitDefines.h:81
@ SHEATH_STATE_MELEE
Definition: UnitDefines.h:83
#define MAX_EQUIPMENT_ITEMS
Definition: UnitDefines.h:37
NPCFlags2
Definition: UnitDefines.h:335
@ UNIT_NPC_FLAG_2_NONE
Definition: UnitDefines.h:336
UnitPVPStateFlags
Definition: UnitDefines.h:91
AnimTier
Definition: UnitDefines.h:69
UnitVisFlags
Definition: UnitDefines.h:58
UnitFlags
Definition: UnitDefines.h:143
@ UNIT_FLAG_STUNNED
Definition: UnitDefines.h:162
@ UNIT_FLAG_NON_ATTACKABLE
Definition: UnitDefines.h:145
@ UNIT_FLAG_IN_COMBAT
Definition: UnitDefines.h:163
@ UNIT_FLAG_CAN_SWIM
Definition: UnitDefines.h:159
@ UNIT_FLAG_FLEEING
Definition: UnitDefines.h:167
@ UNIT_FLAG_CANT_SWIM
Definition: UnitDefines.h:158
@ UNIT_FLAG_PLAYER_CONTROLLED
Definition: UnitDefines.h:147
@ BASE_VALUE
Definition: Unit.h:152
@ MINDAMAGE
Definition: Unit.h:167
@ MAXDAMAGE
Definition: Unit.h:168
UnitMods
Definition: Unit.h:172
@ UNIT_MOD_ARMOR
Definition: Unit.h:204
@ UNIT_MOD_RESISTANCE_SHADOW
Definition: Unit.h:209
@ UNIT_MOD_RESISTANCE_FROST
Definition: Unit.h:208
@ UNIT_MOD_ATTACK_POWER
Definition: Unit.h:211
@ UNIT_MOD_RESISTANCE_HOLY
Definition: Unit.h:205
@ UNIT_MOD_RESISTANCE_ARCANE
Definition: Unit.h:210
@ UNIT_MOD_HEALTH
Definition: Unit.h:177
@ UNIT_MOD_POWER_START
Definition: Unit.h:222
@ UNIT_MOD_RESISTANCE_FIRE
Definition: Unit.h:206
@ UNIT_MOD_RESISTANCE_NATURE
Definition: Unit.h:207
@ UNIT_MOD_ATTACK_POWER_RANGED
Definition: Unit.h:212
#define MAX_AGGRO_RADIUS
Definition: Unit.h:44
DeathState
Definition: Unit.h:245
@ CORPSE
Definition: Unit.h:248
@ DEAD
Definition: Unit.h:249
@ ALIVE
Definition: Unit.h:246
@ JUST_RESPAWNED
Definition: Unit.h:250
@ JUST_DIED
Definition: Unit.h:247
@ UNIT_STATE_DIED
Definition: Unit.h:255
@ UNIT_STATE_ATTACK_PLAYER
Definition: Unit.h:269
@ UNIT_STATE_ROOT
Definition: Unit.h:265
@ UNIT_STATE_IGNORE_PATHFINDING
Definition: Unit.h:283
@ UNIT_STATE_FLEEING
Definition: Unit.h:262
@ UNIT_STATE_FOCUSING
Definition: Unit.h:261
@ UNIT_STATE_ALL_ERASABLE
Definition: Unit.h:302
@ BASE_PCT
Definition: Unit.h:160
T RoundToInterval(T &num, T floor, T ceil)
Definition: Util.h:97
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition: Util.h:491
@ WORLD_DEL_SPAWNGROUP_MEMBER
Definition: WorldDatabase.h:84
@ WORLD_DEL_GAME_EVENT_MODEL_EQUIP
Definition: WorldDatabase.h:77
@ WORLD_DEL_CREATURE_ADDON
Definition: WorldDatabase.h:66
@ WORLD_DEL_LINKED_RESPAWN
Definition: WorldDatabase.h:31
@ WORLD_DEL_GAME_EVENT_CREATURE
Definition: WorldDatabase.h:76
@ WORLD_DEL_CREATURE
Definition: WorldDatabase.h:68
@ WORLD_DEL_LINKED_RESPAWN_MASTER
Definition: WorldDatabase.h:32
@ WORLD_INS_CREATURE
Definition: WorldDatabase.h:75
uint32 const Entry[5]
Unit & m_owner
Definition: Creature.h:583
ObjectGuid m_victim
Definition: Creature.h:581
bool Execute(uint64 e_time, uint32 p_time) override
Definition: Creature.cpp:276
void AddAssistant(ObjectGuid guid)
Definition: Creature.h:577
GuidList m_assistants
Definition: Creature.h:582
Unit * GetAnyTarget() const
virtual void EnterEvadeMode(EvadeReason why=EvadeReason::Other)
Definition: CreatureAI.cpp:219
virtual void JustAppeared()
Definition: CreatureAI.cpp:194
virtual bool CheckInRoom()
Definition: CreatureAI.cpp:453
Creature * GetLeader() const
void FormationReset(bool dismiss)
bool IsFormed() const
void LeaderStartedMoving()
bool IsLeader(Creature const *creature) const
bool CanLeaderStartMoving() const
bool HasFlag(CreatureStaticFlags flag) const
Definition: CreatureData.h:302
void ApplyFlag(CreatureStaticFlags flag, bool apply)
Definition: CreatureData.h:311
bool IsSwimPrevented() const
Definition: Creature.h:143
bool HasClassification(CreatureClassifications classification) const
Definition: Creature.h:153
bool LoadCreaturesAddon()
Definition: Creature.cpp:2749
time_t _pickpocketLootRestore
Timers.
Definition: Creature.h:487
bool HasSpell(uint32 spellID) const override
Definition: Creature.cpp:2863
uint32 CalculateDamageForSparring(Unit *attacker, uint32 damage)
Definition: Creature.cpp:1737
bool AIM_Destroy()
Definition: Creature.cpp:1028
VendorItemCounts m_vendorItemCounts
Definition: Creature.h:479
void SetHomePosition(float x, float y, float z, float o)
Definition: Creature.h:371
float m_wanderDistance
Definition: Creature.h:493
void SetNoSearchAssistance(bool val)
Definition: Creature.h:318
void ReleaseSpellFocus(Spell const *focusSpell=nullptr, bool withDelay=true)
Definition: Creature.cpp:3499
CreatureDifficulty const * m_creatureDifficulty
Definition: Creature.h:521
void SetCanMelee(bool canMelee, bool fleeFromMelee=false)
Definition: Creature.cpp:2822
bool IsTrigger() const
Definition: Creature.h:113
void Respawn(bool force=false)
Definition: Creature.cpp:2303
void SetInteractionAllowedInCombat(bool interactionAllowed) override
Definition: Creature.cpp:3003
void ResetLootMode()
Definition: Creature.h:300
struct Creature::@208 _spellFocusInfo
bool CanSwim() const override
Definition: Creature.cpp:2947
void RegenerateHealth()
Definition: Creature.cpp:971
CreatureTextRepeatGroup m_textRepeat
Definition: Creature.h:557
void GetRespawnPosition(float &x, float &y, float &z, float *ori=nullptr, float *dist=nullptr) const
Definition: Creature.cpp:2882
VendorItemData const * GetVendorItems() const
Definition: Creature.cpp:3184
void StartDefaultCombatMovement(Unit *victim, Optional< float > range={}, Optional< float > angle={})
Definition: Creature.cpp:2855
float _sparringHealthPct
Definition: Creature.h:568
bool CreateFromProto(ObjectGuid::LowType guidlow, uint32 entry, CreatureData const *data=nullptr, uint32 vehId=0)
Definition: Creature.cpp:1781
bool _regenerateHealth
Definition: Creature.h:562
CreatureStaticFlagsHolder _staticFlags
Definition: Creature.h:528
bool IsDungeonBoss() const
Definition: Creature.h:155
bool LoadFromDB(ObjectGuid::LowType spawnId, Map *map, bool addToMap, bool allowDuplicate)
Definition: Creature.cpp:1830
float GetHealthMultiplierForTarget(WorldObject const *target) const override
Definition: Creature.cpp:3057
bool isWorldBoss() const
Definition: Creature.cpp:2484
bool IsReturningHome() const
Definition: Creature.cpp:367
Optional< uint32 > m_lootId
Definition: Creature.h:525
void UpdateLevelDependantStats()
Definition: Creature.cpp:1587
int8 m_originalEquipmentId
Definition: Creature.h:504
void setDeathState(DeathState s) override
Definition: Creature.cpp:2197
static Creature * CreateCreatureFromDB(ObjectGuid::LowType spawnId, Map *map, bool addToMap=true, bool allowDuplicate=false)
Definition: Creature.cpp:1199
bool UpdateAllStats() override
Definition: StatSystem.cpp:902
void CallForHelp(float fRadius)
Definition: Creature.cpp:2563
float GetAttackDistance(Unit const *player) const
Definition: Creature.cpp:2153
ObjectGuid::LowType m_spawnId
For new or temporary creatures is 0 for saved it is lowguid.
Definition: Creature.h:502
std::unique_ptr< Loot > m_loot
Definition: Creature.h:277
void Update(uint32 time) override
Definition: Creature.cpp:709
CreatureDifficulty const * GetCreatureDifficulty() const
Definition: Creature.h:252
bool _IsTargetAcceptable(Unit const *target) const
Definition: Creature.cpp:2639
CreatureClassifications GetCreatureClassification() const
Definition: Creature.h:152
Optional< uint32 > _defaultMountDisplayIdOverride
Definition: Creature.h:564
bool IsSessile() const
Definition: Creature.h:132
bool IsIgnoringFeignDeath() const
Definition: Creature.h:322
bool IsCivilian() const
Definition: Creature.h:112
float GetSparringHealthPct() const
Definition: Creature.h:446
void SetRespawnTime(uint32 respawn)
Definition: Creature.cpp:2877
void SetObjectScale(float scale) override
Definition: Creature.cpp:3391
Optional< std::string > m_scriptStringId
Definition: Creature.h:523
uint32 m_spells[MAX_CREATURE_SPELLS]
Definition: Creature.h:302
void ApplyAllStaticFlags(CreatureStaticFlagsHolder const &flags)
Definition: Creature.cpp:701
static float GetDamageMod(CreatureClassifications classification)
Definition: Creature.cpp:1686
bool m_cannotReachTarget
Definition: Creature.h:508
bool m_respawnCompatibilityMode
Definition: Creature.h:544
void SelectWildBattlePetLevel()
Definition: Creature.cpp:1643
std::string GetNameForLocaleIdx(LocaleConstant locale) const override
Definition: Creature.cpp:3260
bool IsFloating() const
Definition: Creature.h:128
std::unordered_map< ObjectGuid, std::unique_ptr< Loot > > m_personalLoot
Definition: Creature.h:278
CreatureTemplate const * m_creatureInfo
Definition: Creature.h:519
bool IsSpawnedOnTransport() const
Definition: Creature.h:102
void UpdateNearbyPlayersInteractions() override
Definition: Creature.cpp:3009
bool CanFly() const override
Definition: Creature.h:147
Position const & GetHomePosition() const
Definition: Creature.h:374
bool CanGiveExperience() const
Definition: Creature.cpp:3596
CreatureTextRepeatIds GetTextRepeatGroup(uint8 textGroup)
Definition: Creature.cpp:3578
void LoadEquipment(int8 id=1, bool force=false)
Definition: Creature.cpp:1946
uint8 GetLevelForTarget(WorldObject const *target) const override
Definition: Creature.cpp:3104
void SetTrainerId(Optional< uint32 > trainerId)
Definition: Creature.cpp:3703
bool HasReactState(ReactStates state) const
Definition: Creature.h:162
bool AIM_Initialize(CreatureAI *ai=nullptr)
Definition: Creature.cpp:1044
void DoNotReacquireSpellFocusTarget()
Definition: Creature.cpp:3545
void RemoveCorpse(bool setSpawnTime=true, bool destroyForNearbyPlayers=true)
Definition: Creature.cpp:415
void SendZoneUnderAttackMessage(Player *attacker)
Send a message to LocalDefense channel for players opposition team in the zone.
Definition: Creature.cpp:2814
bool m_triggerJustAppeared
Definition: Creature.h:543
void StartPickPocketRefillTimer()
Definition: Creature.cpp:3559
void AllLootRemovedFromCorpse()
Definition: Creature.cpp:2958
static Creature * CreateCreature(uint32 entry, Map *map, Position const &pos, uint32 vehId=0)
Definition: Creature.cpp:1177
float GetAggroRange(Unit const *target) const
Definition: Creature.cpp:3322
void LoadTemplateImmunities(int32 creatureImmunitiesId)
Definition: Creature.cpp:2423
void SignalFormationMovement()
Definition: Creature.cpp:396
void SetDisplayFromModel(uint32 modelIdx)
Definition: Creature.cpp:3413
bool IsEngaged() const override
Definition: Creature.cpp:3601
MovementGeneratorType m_defaultMovementType
Definition: Creature.h:501
Unit * SelectNearestHostileUnitInAggroRange(bool useLOS=false, bool ignoreCivilians=false) const
Definition: Creature.cpp:3371
bool Create(ObjectGuid::LowType guidlow, Map *map, uint32 entry, Position const &pos, CreatureData const *data, uint32 vehId, bool dynamic=false)
Definition: Creature.cpp:1071
void SetReactState(ReactStates st)
Definition: Creature.h:160
uint32 GetTrainerId() const
Definition: Creature.cpp:3695
void RemoveFromWorld() override
Definition: Creature.cpp:349
void SetTextRepeatId(uint8 textGroup, uint8 id)
Definition: Creature.cpp:3569
uint32 _waypointPathId
Definition: Creature.h:538
void ResetPlayerDamageReq()
Definition: Creature.h:400
float m_SightDistance
Definition: Creature.h:412
int32 _creatureImmunitiesId
Definition: Creature.h:565
void SetRespawnCompatibilityMode(bool mode=true)
Definition: Creature.h:407
void SetCannotReachTarget(bool cannotReach)
Definition: Creature.cpp:3303
bool ShouldFakeDamageFrom(Unit *attacker)
Definition: Creature.cpp:1761
void ApplyLevelScaling()
Definition: Creature.cpp:3031
void ClearTextRepeatGroup(uint8 textGroup)
Definition: Creature.cpp:3589
void SetRespawnDelay(uint32 delay)
Definition: Creature.h:338
void AddToWorld() override
Definition: Creature.cpp:329
uint32 m_cannotReachTimer
Definition: Creature.h:509
uint32 m_respawnDelay
Definition: Creature.h:490
void SetScriptStringId(std::string id)
Definition: Creature.cpp:3170
void SetTappedBy(Unit const *unit, bool withGroup=true)
Definition: Creature.cpp:1339
void InitializeMovementCapabilities()
Definition: Creature.cpp:2906
void InitializeInteractSpellId()
Definition: Creature.cpp:3727
bool IsSkinnedBy(Player const *player) const
Definition: Creature.cpp:1409
time_t m_corpseRemoveTime
Definition: Creature.h:488
void ForcedDespawn(uint32 timeMSToDespawn=0, Seconds forceRespawnTimer=0s)
Definition: Creature.cpp:2363
uint32 m_combatPulseDelay
Definition: Creature.h:496
float GetPetChaseDistance() const
Definition: Creature.cpp:3283
bool IsFormationLeaderMoveAllowed() const
Definition: Creature.cpp:407
void SummonGraveyardTeleporter()
Definition: Creature.cpp:3714
bool IsImmuneToNPC() const
Definition: Unit.h:1033
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
Definition: Creature.cpp:2415
bool UpdateEntry(uint32 entry, CreatureData const *data=nullptr, bool updateLevel=true)
Definition: Creature.cpp:577
float GetArmorMultiplierForTarget(WorldObject const *target) const override
Definition: Creature.cpp:3094
bool HasStringId(std::string_view id) const
Definition: Creature.cpp:3165
float GetSpellDamageMod(CreatureClassifications classification) const
Definition: Creature.cpp:1709
time_t m_respawnTime
Definition: Creature.h:489
void DoFleeToGetAssistance()
Definition: Creature.cpp:1002
float GetDamageMultiplierForTarget(WorldObject const *target) const override
Definition: Creature.cpp:3076
uint32 _gossipMenuId
Definition: Creature.h:566
bool CanResetTalents(Player *player) const
Definition: Creature.cpp:1320
bool IsEscorted() const
Definition: Creature.cpp:3660
void AtEngage(Unit *target) override
Definition: Creature.cpp:3608
uint32 GetScriptId() const
Definition: Creature.cpp:3156
CreatureData const * m_creatureData
Definition: Creature.h:520
float m_CombatDistance
Definition: Creature.h:412
void AtDisengage() override
Definition: Creature.cpp:3644
bool hasInvolvedQuest(uint32 quest_id) const override
Definition: Creature.cpp:2000
uint32 m_boundaryCheckTime
Definition: Creature.h:494
bool isCanInteractWithBattleMaster(Player *player, bool msg) const
Definition: Creature.cpp:1288
Position m_homePosition
Definition: Creature.h:514
uint32 GetWaypointPathId() const
Definition: Creature.h:381
Loot * GetLootForPlayer(Player const *player) const override
Definition: Creature.cpp:1386
CreatureData const * GetCreatureData() const
Definition: Creature.h:251
bool CanGeneratePickPocketLoot() const
Definition: Creature.cpp:3564
ObjectGuid::LowType GetSpawnId() const
Definition: Creature.h:98
void SetInteractionAllowedWhileHostile(bool interactionAllowed) override
Definition: Creature.cpp:2997
bool CanNotReachTarget() const
Definition: Creature.h:367
bool m_AlreadyCallAssistance
Definition: Creature.h:506
CreatureTemplate const * GetCreatureTemplate() const
Definition: Creature.h:250
uint32 GetRespawnDelay() const
Definition: Creature.h:337
void SetDontClearTapListOnEvade(bool dontClear)
Definition: Creature.cpp:1373
bool IsFormationLeader() const
Definition: Creature.cpp:388
bool CanCreatureAttack(Unit const *victim, bool force=true) const
Definition: Creature.cpp:2686
bool CanRegenerateHealth() const
Definition: Creature.h:357
bool DisableReputationGain
Definition: Creature.h:517
void SetTarget(ObjectGuid const &guid) override
Definition: Creature.cpp:3419
float GetBaseDamageForLevel(uint8 level) const
Definition: Creature.cpp:3069
uint32 GetLootId() const
Definition: Creature.cpp:1326
CreatureGroup * m_formation
Definition: Creature.h:542
static bool DeleteFromDB(ObjectGuid::LowType spawnId)
Definition: Creature.cpp:2005
void SetInteractSpellId(int32 interactSpellId)
Definition: Creature.h:472
void InitializeReactState()
Definition: Creature.cpp:1276
bool AIM_Create(CreatureAI *ai=nullptr)
Definition: Creature.cpp:1035
uint32 m_corpseDelay
Definition: Creature.h:491
void Motion_Initialize()
Definition: Creature.cpp:1055
bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const override
Definition: Creature.cpp:2467
std::array< std::string_view, 3 > m_stringIds
Definition: Creature.h:522
void LoadCreaturesSparringHealth(bool force=false)
Definition: Creature.cpp:2806
uint32 UpdateVendorItemCurrentCount(VendorItem const *vItem, uint32 used_count)
Definition: Creature.cpp:3223
void SetSpawnHealth()
Definition: Creature.cpp:1969
bool CheckNoGrayAggroConfig(uint32 playerLevel, uint32 creatureLevel) const
Definition: Creature.cpp:2138
uint8 m_equipmentId
Definition: Creature.h:503
bool IsElite() const
Definition: Creature.cpp:2476
bool isTappedBy(Player const *player) const
Definition: Creature.cpp:1381
Creature(bool isWorldObject=false)
Definition: Creature.cpp:306
CreatureGroup * GetFormation()
Definition: Creature.h:391
uint32 GetCorpseDelay() const
Definition: Creature.h:110
GuidUnorderedSet m_tapList
Definition: Creature.h:483
bool m_dontClearTapListOnEvade
Definition: Creature.h:484
uint64 GetMaxHealthByLevel(uint8 level) const
Definition: Creature.cpp:3049
void OverrideSparringHealthPct(float healthPct)
Definition: Creature.h:444
bool CanAssistTo(Unit const *u, Unit const *enemy, bool checkfaction=true) const
Definition: Creature.cpp:2585
uint32 m_originalEntry
Definition: Creature.h:512
float GetNativeObjectScale() const override
Definition: Creature.cpp:3386
bool HasScalableLevels() const
Definition: Creature.cpp:3026
void SetDefaultMount(Optional< uint32 > mountCreatureDisplayId)
Definition: Creature.cpp:3314
void ExitVehicle(Position const *exitPosition=nullptr) override
Definition: Creature.cpp:3676
Unit * SelectVictim()
Definition: Creature.cpp:1211
void SearchFormation()
Definition: Creature.cpp:375
uint32 GetVendorItemCurrentCount(VendorItem const *vItem)
Definition: Creature.cpp:3189
float GetBaseArmorForLevel(uint8 level) const
Definition: Creature.cpp:3086
bool m_isTempWorldObject
Definition: Creature.h:414
void SetDisplayId(uint32 displayId, bool setNative=false) override
Definition: Creature.cpp:3402
std::string GetScriptName() const
Definition: Creature.cpp:3151
void LowerPlayerDamageReq(uint64 unDamage)
Definition: Creature.cpp:1680
time_t GetLastDamagedTime() const
Definition: Creature.h:426
MovementGeneratorType GetDefaultMovementType() const override
Definition: Creature.h:149
void SetSpellFocus(Spell const *focusSpell, WorldObject const *target)
Definition: Creature.cpp:3427
Optional< uint32 > _trainerId
Definition: Creature.h:567
bool HasFlag(CreatureStaticFlags flag) const
Definition: Creature.h:454
bool IsInvisibleDueToDespawn(WorldObject const *seer) const override
Definition: Creature.cpp:2080
bool IsFullyLooted() const
Definition: Creature.cpp:1397
void SaveRespawnTime(uint32 forceDelay=0)
Definition: Creature.cpp:2666
uint8 GetCurrentEquipmentId() const
Definition: Creature.h:241
bool InitEntry(uint32 entry, CreatureData const *data=nullptr)
Definition: Creature.cpp:487
Unit * SelectNearestTarget(float dist=0, bool playerOnly=false) const
Definition: Creature.cpp:2493
void SetCorpseDelay(uint32 delay, bool ignoreCorpseDecayRatio=false)
Definition: Creature.h:104
void SetMeleeDamageSchool(SpellSchools school)
Definition: Creature.h:217
static float GetHealthMod(CreatureClassifications classification)
Definition: Creature.cpp:1657
void SaveToDB()
Definition: Creature.cpp:1417
Unit * SelectNearestTargetInAttackDistance(float dist=0) const
Definition: Creature.cpp:2506
void SelectLevel()
Definition: Creature.cpp:1576
CreatureMovementData const & GetMovementTemplate() const
Definition: Creature.cpp:2939
void SendAIReaction(AiReaction reactionType)
Definition: Creature.cpp:2521
void SetGossipMenuId(uint32 gossipMenuId)
Definition: Creature.cpp:3690
bool IsAmphibious() const
Definition: Creature.h:125
void ResetPickPocketRefillTimer()
Definition: Creature.h:280
void SetNoCallAssistance(bool val)
Definition: Creature.h:317
void SetTreatAsRaidUnit(bool treatAsRaidUnit)
Definition: Creature.h:222
void UpdateMovementCapabilities()
Definition: Creature.cpp:2919
bool m_ignoreCorpseDecayRatio
Definition: Creature.h:492
bool CanAlwaysSee(WorldObject const *obj) const override
Definition: Creature.cpp:2091
bool hasQuest(uint32 quest_id) const override
Definition: Creature.cpp:1995
void Regenerate(Powers power)
Definition: Creature.cpp:918
time_t GetRespawnTimeEx() const
Definition: Creature.cpp:2868
CreatureAddon const * GetCreatureAddon() const
Definition: Creature.cpp:2737
std::string const & GetAIName() const
Definition: Creature.cpp:3146
void CallAssistance()
Definition: Creature.cpp:2533
void SetLootId(Optional< uint32 > lootId)
Definition: Creature.cpp:1334
bool IsImmuneToPC() const
Definition: Unit.h:1030
void SetCanDualWield(bool value) override
Definition: Creature.cpp:1940
bool IsInEvadeMode() const
Definition: Creature.h:203
void ReacquireSpellFocusTarget()
Definition: Creature.cpp:3522
CreatureAI * AI() const
Definition: Creature.h:214
virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const
Definition: Creature.cpp:3275
std::string GetDebugInfo() const override
Definition: Creature.cpp:3667
bool CanStartAttack(Unit const *u, bool force) const
Definition: Creature.cpp:2099
bool IsMovementPreventedByCasting() const override
Definition: Creature.cpp:3551
void SetOriginalEntry(uint32 entry)
Definition: Creature.h:404
bool HasSpellFocus(Spell const *focusSpell=nullptr) const override
Definition: Creature.cpp:3481
uint32 GetGossipMenuId() const
Definition: Creature.cpp:3685
void SetIgnoreFeignDeath(bool ignoreFeignDeath)
Definition: Creature.h:323
uint32 m_combatPulseTime
Definition: Creature.h:495
uint64 m_PlayerDamageReq
Definition: Creature.h:401
virtual uint8 GetPetAutoSpellSize() const
Definition: Creature.cpp:3270
constexpr std::underlying_type_t< T > AsUnderlyingType() const
Definition: EnumFlag.h:122
void AddEvent(BasicEvent *event, Milliseconds e_time, bool set_addtime=true)
Milliseconds CalculateTime(Milliseconds t_offset) const
void SetValue(FLAG_TYPE flag, T_VALUES value)
Definition: Object.h:446
Seconds const m_respawnTimer
Definition: Creature.h:594
bool Execute(uint64 e_time, uint32 p_time) override
Definition: Creature.cpp:300
Definition: Group.h:197
bool isEmpty() const
Definition: LinkedList.h:110
iterator end()
Definition: MapRefManager.h:35
iterator begin()
Definition: MapRefManager.h:34
Definition: Map.h:189
bool IsDungeon() const
Definition: Map.cpp:3238
void CreatureRelocation(Creature *creature, float x, float y, float z, float ang, bool respawnRelocationOnFail=true)
Definition: Map.cpp:1080
MapStoredObjectTypesContainer & GetObjectsStore()
Definition: Map.h:422
time_t GetLinkedRespawnTime(ObjectGuid guid) const
Definition: Map.cpp:3642