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