/* * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef TRINITYCORE_CREATURE_H #define TRINITYCORE_CREATURE_H #include "Unit.h" #include "Common.h" #include "CreatureData.h" #include "DatabaseEnvFwd.h" #include "Duration.h" #include "GridObject.h" #include "MapObject.h" #include class CreatureAI; class CreatureGroup; class Quest; class Player; class SpellInfo; class WorldSession; struct Loot; enum MovementGeneratorType : uint8; struct VendorItemCount { VendorItemCount(uint32 _item, uint32 _count); uint32 itemId; uint32 count; time_t lastIncrementTime; }; typedef std::list VendorItemCounts; // max different by z coordinate for creature aggro reaction #define CREATURE_Z_ATTACK_RANGE 3 #define MAX_VENDOR_ITEMS 150 // Limitation in 4.x.x item count in SMSG_LIST_INVENTORY enum class VendorInventoryReason : uint8 { None = 0, Empty = 1 }; enum class VendorDataTypeFlags : int32 { Generic = 0x01, Ammo = 0x02, Food = 0x04, Poison = 0x08, Reagent = 0x10, Petition = 0x20, }; DEFINE_ENUM_FLAG(VendorDataTypeFlags); static constexpr uint8 WILD_BATTLE_PET_DEFAULT_LEVEL = 1; static constexpr size_t CREATURE_TAPPERS_SOFT_CAP = 5; //used for handling non-repeatable random texts typedef std::vector CreatureTextRepeatIds; typedef std::unordered_map CreatureTextRepeatGroup; class TC_GAME_API Creature : public Unit, public GridObject, public MapObject { public: explicit Creature(bool isWorldObject = false); ~Creature(); void AddToWorld() override; void RemoveFromWorld() override; float GetNativeObjectScale() const override; void SetObjectScale(float scale) override; void SetDisplayId(uint32 displayId, bool setNative = false) override; void SetDisplayFromModel(uint32 modelIdx); void DisappearAndDie() { ForcedDespawn(0); } bool Create(ObjectGuid::LowType guidlow, Map* map, uint32 entry, Position const& pos, CreatureData const* data, uint32 vehId, bool dynamic = false); static Creature* CreateCreature(uint32 entry, Map* map, Position const& pos, uint32 vehId = 0); static Creature* CreateCreatureFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap = true, bool allowDuplicate = false); bool LoadCreaturesAddon(); void LoadCreaturesSparringHealth(bool force = false); void SelectLevel(); void UpdateLevelDependantStats(); void SelectWildBattlePetLevel(); void LoadEquipment(int8 id = 1, bool force = false); void SetSpawnHealth(); ObjectGuid::LowType GetSpawnId() const { return m_spawnId; } void Update(uint32 time) override; // overwrited Unit::Update void Heartbeat() override; void GetRespawnPosition(float &x, float &y, float &z, float* ori = nullptr, float* dist = nullptr) const; bool IsSpawnedOnTransport() const { return m_creatureData && m_creatureData->mapId != GetMapId(); } void SetCorpseDelay(uint32 delay, bool ignoreCorpseDecayRatio = false) { m_corpseDelay = delay; if (ignoreCorpseDecayRatio) m_ignoreCorpseDecayRatio = true; } uint32 GetCorpseDelay() const { return m_corpseDelay; } bool IsRacialLeader() const { return GetCreatureTemplate()->RacialLeader; } bool IsCivilian() const { return (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN) != 0; } bool IsTrigger() const { return (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER) != 0; } bool IsGuard() const { return (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_GUARD) != 0; } void InitializeMovementCapabilities(); void UpdateMovementCapabilities(); CreatureMovementData const& GetMovementTemplate() const; // Returns true if CREATURE_STATIC_FLAG_AQUATIC is set which strictly binds the creature to liquids bool IsAquatic() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_AQUATIC); } // Returns true if CREATURE_STATIC_FLAG_AMPHIBIOUS is set which allows a creature to enter and leave liquids while sticking to the ocean floor. These creatures will become able to swim when engaged bool IsAmphibious() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_AMPHIBIOUS); } // Returns true if CREATURE_STATIC_FLAG_FLOATING is set which is disabling the gravity of the creature on spawn and reset bool IsFloating() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_FLOATING); } void SetFloating(bool floating) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_FLOATING, floating); SetDisableGravity(floating); } // Returns true if CREATURE_STATIC_FLAG_SESSILE is set which permanently roots the creature in place bool IsSessile() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_SESSILE); } void SetSessile(bool sessile) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_SESSILE, sessile); SetControlled(sessile, UNIT_STATE_ROOT); } // Returns true if CREATURE_STATIC_FLAG_3_CANNOT_PENETRATE_WATER is set which does not allow the creature to go below liquid surfaces bool CannotPenetrateWater() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_3_CANNOT_PENETRATE_WATER); } void SetCannotPenetrateWater(bool cannotPenetrateWater) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_3_CANNOT_PENETRATE_WATER, cannotPenetrateWater); } // Returns true if CREATURE_STATIC_FLAG_3_CANNOT_SWIM is set which prevents 'Amphibious' creatures from swimming when engaged bool IsSwimDisabled() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_3_CANNOT_SWIM); } // Returns true if CREATURE_STATIC_FLAG_4_PREVENT_SWIM is set which prevents 'Amphibious' creatures from swimming when engaged until the victim is no longer on the ocean floor bool IsSwimPrevented() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_4_PREVENT_SWIM); } bool CanSwim() const override; bool CanEnterWater() const override { return (CanSwim() || IsAmphibious()); }; bool CanFly() const override { return (IsFlying() || HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY)); } MovementGeneratorType GetDefaultMovementType() const override { return m_defaultMovementType; } void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; } CreatureClassifications GetCreatureClassification() const { return GetCreatureTemplate()->Classification; } bool HasClassification(CreatureClassifications classification) const { return GetCreatureTemplate()->Classification == classification; } bool IsDungeonBoss() const { return (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_DUNGEON_BOSS) != 0; } bool IsAffectedByDiminishingReturns() const override { return Unit::IsAffectedByDiminishingReturns() || (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_ALL_DIMINISH) != 0; } Unit* SelectVictim(); void SetReactState(ReactStates st) { m_reactState = st; } ReactStates GetReactState() const { return m_reactState; } bool HasReactState(ReactStates state) const { return (m_reactState == state); } void InitializeReactState(); using Unit::IsImmuneToAll; using Unit::SetImmuneToAll; void SetImmuneToAll(bool apply) override { Unit::SetImmuneToAll(apply, HasReactState(REACT_PASSIVE)); } using Unit::IsImmuneToPC; using Unit::SetImmuneToPC; void SetImmuneToPC(bool apply) override { Unit::SetImmuneToPC(apply, HasReactState(REACT_PASSIVE)); } using Unit::IsImmuneToNPC; using Unit::SetImmuneToNPC; void SetImmuneToNPC(bool apply) override { Unit::SetImmuneToNPC(apply, HasReactState(REACT_PASSIVE)); } void SetUnkillable(bool unkillable) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_UNKILLABLE, unkillable); } /// @todo Rename these properly bool isCanInteractWithBattleMaster(Player* player, bool msg) const; bool CanResetTalents(Player* player) const; bool CanCreatureAttack(Unit const* victim, bool force = true) const; void LoadTemplateImmunities(int32 creatureImmunitiesId); bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute = false) const override; bool IsElite() const; bool isWorldBoss() const; void SetInteractionAllowedWhileHostile(bool interactionAllowed) override; void SetInteractionAllowedInCombat(bool interactionAllowed) override; void UpdateNearbyPlayersInteractions() override; bool HasScalableLevels() const; void ApplyLevelScaling(); uint8 GetLevelForTarget(WorldObject const* target) const override; uint64 GetMaxHealthByLevel(uint8 level) const; float GetHealthMultiplierForTarget(WorldObject const* target) const override; float GetBaseDamageForLevel(uint8 level) const; float GetDamageMultiplierForTarget(WorldObject const* target) const override; float GetBaseArmorForLevel(uint8 level) const; float GetArmorMultiplierForTarget(WorldObject const* target) const override; bool IsInEvadeMode() const { return HasUnitState(UNIT_STATE_EVADE); } bool IsEvadingAttacks() const { return IsInEvadeMode() || CanNotReachTarget(); } bool IsStateRestoredOnEvade() const { return !HasFlag(CREATURE_STATIC_FLAG_5_NO_LEAVECOMBAT_STATE_RESTORE); } void SetRestoreStateOnEvade(bool restoreOnEvade) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_5_NO_LEAVECOMBAT_STATE_RESTORE, !restoreOnEvade); } bool AIM_Destroy(); bool AIM_Create(CreatureAI* ai = nullptr); bool AIM_Initialize(CreatureAI* ai = nullptr); void Motion_Initialize(); CreatureAI* AI() const { return reinterpret_cast(GetAI()); } SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType /*attackType*/ = BASE_ATTACK) const override { return m_meleeDamageSchoolMask; } void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = SpellSchoolMask(1 << school); } bool CanMelee() const { return !_staticFlags.HasFlag(CREATURE_STATIC_FLAG_NO_MELEE_FLEE) && !_staticFlags.HasFlag(CREATURE_STATIC_FLAG_4_NO_MELEE_APPROACH); } void SetCanMelee(bool canMelee, bool fleeFromMelee = false); bool CanIgnoreLineOfSightWhenCastingOnMe() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_4_IGNORE_LOS_WHEN_CASTING_ON_ME); } bool IsTreatedAsRaidUnit() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_4_TREAT_AS_RAID_UNIT_FOR_HELPFUL_SPELLS); } void SetTreatAsRaidUnit(bool treatAsRaidUnit) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_4_TREAT_AS_RAID_UNIT_FOR_HELPFUL_SPELLS, treatAsRaidUnit); } void StartDefaultCombatMovement(Unit* victim, Optional range = {}, Optional angle = {}); bool HasSpell(uint32 spellID) const override; bool UpdateEntry(uint32 entry, CreatureData const* data = nullptr, bool updateLevel = true); int32 GetCreatePowerValue(Powers power) const override; bool UpdateStats(Stats stat) override; bool UpdateAllStats() override; void UpdateArmor() override; void UpdateMaxHealth() override; void UpdateMaxPower(Powers power) override; uint32 GetPowerIndex(Powers power) const override; void UpdateAttackPowerAndDamage(bool ranged = false) override; void CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) const override; void SetCanDualWield(bool value) override; int8 GetOriginalEquipmentId() const { return m_originalEquipmentId; } uint8 GetCurrentEquipmentId() const { return m_equipmentId; } void SetCurrentEquipmentId(uint8 id) { m_equipmentId = id; } float GetSpellDamageMod(CreatureClassifications classification) const; VendorItemData const* GetVendorItems() const; uint32 GetVendorItemCurrentCount(VendorItem const* vItem); uint32 UpdateVendorItemCurrentCount(VendorItem const* vItem, uint32 used_count); void SetVendor(NPCFlags flags, bool apply); void SetPetitioner(bool apply); CreatureTemplate const* GetCreatureTemplate() const { return m_creatureInfo; } CreatureData const* GetCreatureData() const { return m_creatureData; } CreatureDifficulty const* GetCreatureDifficulty() const { return m_creatureDifficulty; } CreatureAddon const* GetCreatureAddon() const; std::string const& GetAIName() const; std::string GetScriptName() const; uint32 GetScriptId() const; void InheritStringIds(Creature const* parent); bool HasStringId(std::string_view id) const; void SetScriptStringId(std::string id); std::string_view GetStringId(StringIdType type) const { return m_stringIds[size_t(type)] ? std::string_view(*m_stringIds[size_t(type)]) : std::string_view(); } SpawnTrackingStateData const* GetSpawnTrackingStateDataForPlayer(Player const* player) const override; // override WorldObject function for proper name localization std::string GetNameForLocaleIdx(LocaleConstant locale) const override; bool HasLabel(int32 cretureLabel) const; std::span GetLabels() const; void setDeathState(DeathState s) override; // override virtual Unit::setDeathState bool LoadFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap, bool allowDuplicate); void SaveToDB(); // overriden in Pet virtual void SaveToDB(uint32 mapid, std::vector const& spawnDifficulties); static bool DeleteFromDB(ObjectGuid::LowType spawnId); bool CanHaveLoot() const { return !_staticFlags.HasFlag(CREATURE_STATIC_FLAG_NO_LOOT); } void SetCanHaveLoot(bool canHaveLoot) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_NO_LOOT, !canHaveLoot); } uint32 GetLootId() const; void SetLootId(Optional lootId); std::unique_ptr m_loot; std::unordered_map> m_personalLoot; void StartPickPocketRefillTimer(); void ResetPickPocketRefillTimer() { _pickpocketLootRestore = 0; } bool CanGeneratePickPocketLoot() const; GuidUnorderedSet const& GetTapList() const { return m_tapList; } void SetTapList(GuidUnorderedSet tapList) { m_tapList = std::move(tapList); } bool hasLootRecipient() const { return !m_tapList.empty(); } bool IsTapListNotClearedOnEvade() const { return m_dontClearTapListOnEvade; } void SetDontClearTapListOnEvade(bool dontClear); bool isTappedBy(Player const* player) const; // return true if the creature is tapped by the player or a member of his party. Loot* GetLootForPlayer(Player const* player) const override; bool IsFullyLooted() const; bool IsSkinnedBy(Player const* player) const; void SetTappedBy(Unit const* unit, bool withGroup = true); void AllLootRemovedFromCorpse(); uint16 GetLootMode() const { return m_LootMode; } bool HasLootMode(uint16 lootMode) const { return (m_LootMode & lootMode) != 0; } void SetLootMode(uint16 lootMode) { m_LootMode = lootMode; } void AddLootMode(uint16 lootMode) { m_LootMode |= lootMode; } void RemoveLootMode(uint16 lootMode) { m_LootMode &= ~lootMode; } void ResetLootMode() { m_LootMode = LOOT_MODE_DEFAULT; } uint32 m_spells[MAX_CREATURE_SPELLS]; bool CanStartAttack(Unit const* u, bool force) const; float GetAttackDistance(Unit const* player) const; float GetAggroRange(Unit const* target) const; void SendAIReaction(AiReaction reactionType); Unit* SelectNearestTarget(float dist = 0, bool playerOnly = false) const; Unit* SelectNearestTargetInAttackDistance(float dist = 0) const; Unit* SelectNearestHostileUnitInAggroRange(bool useLOS = false, bool ignoreCivilians = false) const; void DoFleeToGetAssistance(); void CallForHelp(float fRadius); void CallAssistance(); void SetNoCallAssistance(bool val) { m_AlreadyCallAssistance = val; } void SetNoSearchAssistance(bool val) { m_AlreadySearchedAssistance = val; } bool HasSearchedAssistance() const { return m_AlreadySearchedAssistance; } bool CanAssistTo(Unit const* u, Unit const* enemy, bool checkfaction = true) const; bool _IsTargetAcceptable(Unit const* target) const; bool IsIgnoringFeignDeath() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_2_IGNORE_FEIGN_DEATH); } void SetIgnoreFeignDeath(bool ignoreFeignDeath) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_2_IGNORE_FEIGN_DEATH, ignoreFeignDeath); } bool IsIgnoringSanctuarySpellEffect() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_2_IGNORE_SANCTUARY); } void SetIgnoreSanctuarySpellEffect(bool ignoreSanctuary) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_2_IGNORE_SANCTUARY, ignoreSanctuary); } void RemoveCorpse(bool setSpawnTime = true, bool destroyForNearbyPlayers = true); void DespawnOrUnsummon(Milliseconds timeToDespawn = 0s, Seconds forceRespawnTime = 0s); time_t const& GetRespawnTime() const { return m_respawnTime; } time_t GetRespawnTimeEx() const; void SetRespawnTime(uint32 respawn); void Respawn(bool force = false); void SaveRespawnTime(uint32 forceDelay = 0); uint32 GetRespawnDelay() const { return m_respawnDelay; } void SetRespawnDelay(uint32 delay) { m_respawnDelay = delay; } float GetWanderDistance() const { return m_wanderDistance; } void SetWanderDistance(float dist) { m_wanderDistance = dist; } void DoImmediateBoundaryCheck() { m_boundaryCheckTime = 0; } void SendZoneUnderAttackMessage(Player* attacker); bool hasQuest(uint32 quest_id) const override; bool hasInvolvedQuest(uint32 quest_id) const override; bool CanRegenerateHealth() const { return !_staticFlags.HasFlag(CREATURE_STATIC_FLAG_5_NO_HEALTH_REGEN) && _regenerateHealth; } void SetRegenerateHealth(bool value) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_5_NO_HEALTH_REGEN, !value); } virtual uint8 GetPetAutoSpellSize() const; virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const; float GetPetChaseDistance() const; bool IsIgnoringChaseRange() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_6_ALWAYS_STAND_ON_TOP_OF_TARGET); } void SetIgnoreChaseRange(bool ignoreChaseRange) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_6_ALWAYS_STAND_ON_TOP_OF_TARGET, ignoreChaseRange); } void SetCannotReachTarget(bool cannotReach); bool CanNotReachTarget() const { return m_cannotReachTarget; } void SetDefaultMount(Optional mountCreatureDisplayId); void SetHomePosition(float x, float y, float z, float o) { m_homePosition.Relocate(x, y, z, o); } void SetHomePosition(Position const& pos) { m_homePosition.Relocate(pos); } void GetHomePosition(float& x, float& y, float& z, float& ori) const { m_homePosition.GetPosition(x, y, z, ori); } Position const& GetHomePosition() const { return m_homePosition; } void SetTransportHomePosition(float x, float y, float z, float o) { m_transportHomePosition.Relocate(x, y, z, o); } void SetTransportHomePosition(Position const& pos) { m_transportHomePosition.Relocate(pos); } void GetTransportHomePosition(float& x, float& y, float& z, float& ori) const { m_transportHomePosition.GetPosition(x, y, z, ori); } Position const& GetTransportHomePosition() const { return m_transportHomePosition; } uint32 GetWaypointPathId() const { return _waypointPathId; } void LoadPath(uint32 pathid) { _waypointPathId = pathid; } // nodeId, pathId std::pair GetCurrentWaypointInfo() const { return _currentWaypointNodeInfo; } void UpdateCurrentWaypointInfo(uint32 nodeId, uint32 pathId) { _currentWaypointNodeInfo = { nodeId, pathId }; } bool IsReturningHome() const; void SearchFormation(); CreatureGroup* GetFormation() { return m_formation; } void SetFormation(CreatureGroup* formation) { m_formation = formation; } bool IsFormationLeader() const; void SignalFormationMovement(); bool IsFormationLeaderMoveAllowed() const; void SetDisableReputationGain(bool disable) { DisableReputationGain = disable; } bool IsReputationGainDisabled() const { return DisableReputationGain; } void LowerPlayerDamageReq(uint64 unDamage); void ResetPlayerDamageReq() { m_PlayerDamageReq = GetHealth() / 2; } uint64 m_PlayerDamageReq; uint32 GetOriginalEntry() const { return m_originalEntry; } void SetOriginalEntry(uint32 entry) { m_originalEntry = entry; } // There's many places not ready for dynamic spawns. This allows them to live on for now. void SetRespawnCompatibilityMode(bool mode = true) { m_respawnCompatibilityMode = mode; } bool GetRespawnCompatibilityMode() const { return m_respawnCompatibilityMode; } static float GetDamageMod(CreatureClassifications classification); float m_SightDistance, m_CombatDistance; bool m_isTempWorldObject; //true when possessed // Handling caster facing during spellcast void SetTarget(ObjectGuid const& guid) override; void DoNotReacquireSpellFocusTarget(); void SetSpellFocus(Spell const* focusSpell, WorldObject const* target); bool HasSpellFocus(Spell const* focusSpell = nullptr) const override; void ReleaseSpellFocus(Spell const* focusSpell = nullptr, bool withDelay = true); bool IsMovementPreventedByCasting() const override; // Part of Evade mechanics time_t GetLastDamagedTime() const { return _lastDamagedTime; } void SetLastDamagedTime(time_t val) { _lastDamagedTime = val; } CreatureTextRepeatIds GetTextRepeatGroup(uint8 textGroup); void SetTextRepeatId(uint8 textGroup, uint8 id); void ClearTextRepeatGroup(uint8 textGroup); bool IsEscorted() const; bool CanGiveExperience() const; void SetCanGiveExperience(bool xpEnabled) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_NO_XP, !xpEnabled); } bool IsEngaged() const override; void AtEngage(Unit* target) override; void AtDisengage() override; bool IsThreatFeedbackDisabled() const { return _staticFlags.HasFlag(CREATURE_STATIC_FLAG_3_NO_THREAT_FEEDBACK); } void SetNoThreatFeedback(bool noThreatFeedback) { _staticFlags.ApplyFlag(CREATURE_STATIC_FLAG_3_NO_THREAT_FEEDBACK, noThreatFeedback); } void ForcePartyMembersIntoCombat(); bool IsAggroGracePeriodExpired() { return _aggroGracePeriodExpired; } void OverrideSparringHealthPct(float healthPct) { _sparringHealthPct = healthPct; } void OverrideSparringHealthPct(std::vector const& healthPct); float GetSparringHealthPct() const { return _sparringHealthPct; } uint32 CalculateDamageForSparring(Unit* attacker, uint32 damage); bool ShouldFakeDamageFrom(Unit* attacker); std::string GetDebugInfo() const override; void ExitVehicle(Position const* exitPosition = nullptr) override; bool HasFlag(CreatureStaticFlags flag) const { return _staticFlags.HasFlag(flag); } bool HasFlag(CreatureStaticFlags2 flag) const { return _staticFlags.HasFlag(flag); } bool HasFlag(CreatureStaticFlags3 flag) const { return _staticFlags.HasFlag(flag); } bool HasFlag(CreatureStaticFlags4 flag) const { return _staticFlags.HasFlag(flag); } bool HasFlag(CreatureStaticFlags5 flag) const { return _staticFlags.HasFlag(flag); } bool HasFlag(CreatureStaticFlags6 flag) const { return _staticFlags.HasFlag(flag); } bool HasFlag(CreatureStaticFlags7 flag) const { return _staticFlags.HasFlag(flag); } bool HasFlag(CreatureStaticFlags8 flag) const { return _staticFlags.HasFlag(flag); } uint32 GetGossipMenuId() const; void SetGossipMenuId(uint32 gossipMenuId); uint32 GetTrainerId() const; void SetTrainerId(Optional trainerId); void SummonGraveyardTeleporter(); void InitializeInteractSpellId(); void SetInteractSpellId(int32 interactSpellId) { SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::InteractSpellID), interactSpellId); } UF::OptionalUpdateField m_vendorData; protected: void BuildValuesCreate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const override; void BuildValuesUpdate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const override; public: void BuildValuesUpdateWithFlag(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const override; void BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::ObjectData::Mask const& requestedObjectMask, UF::UnitData::Mask const& requestedUnitMask, Player const* target) const; struct ValuesUpdateForPlayerWithMaskSender // sender compatible with MessageDistDeliverer { explicit ValuesUpdateForPlayerWithMaskSender(Creature const* owner) : Owner(owner) { } Creature const* Owner; UF::ObjectData::Base ObjectMask; UF::UnitData::Base UnitMask; void operator()(Player const* player) const; }; protected: void ClearUpdateMask(bool remove) override; bool CreateFromProto(ObjectGuid::LowType guidlow, uint32 entry, CreatureData const* data = nullptr, uint32 vehId = 0); bool InitEntry(uint32 entry, CreatureData const* data = nullptr); // vendor items VendorItemCounts m_vendorItemCounts; static float GetHealthMod(CreatureClassifications classification); GuidUnorderedSet m_tapList; bool m_dontClearTapListOnEvade; /// Timers time_t _pickpocketLootRestore; time_t m_corpseRemoveTime; // (msecs)timer for death or corpse disappearance time_t m_respawnTime; // (secs) time of next respawn uint32 m_respawnDelay; // (secs) delay between corpse disappearance and respawning uint32 m_corpseDelay; // (secs) delay between death and corpse disappearance bool m_ignoreCorpseDecayRatio; float m_wanderDistance; uint32 m_boundaryCheckTime; // (msecs) remaining time for next evade boundary check ReactStates m_reactState; // for AI, not charmInfo void RegenerateHealth(); void Regenerate(Powers power); MovementGeneratorType m_defaultMovementType; ObjectGuid::LowType m_spawnId; ///< For new or temporary creatures is 0 for saved it is lowguid uint8 m_equipmentId; int8 m_originalEquipmentId; // can be -1 bool m_AlreadyCallAssistance; bool m_AlreadySearchedAssistance; bool m_cannotReachTarget; uint32 m_cannotReachTimer; SpellSchoolMask m_meleeDamageSchoolMask; uint32 m_originalEntry; Position m_homePosition; Position m_transportHomePosition; bool DisableReputationGain; CreatureTemplate const* m_creatureInfo; CreatureData const* m_creatureData; CreatureDifficulty const* m_creatureDifficulty; std::array m_stringIds; Optional m_scriptStringId; Optional m_lootId; uint16 m_LootMode; // Bitmask (default: LOOT_MODE_DEFAULT) that determines what loot will be lootable CreatureStaticFlagsHolder _staticFlags; bool IsInvisibleDueToDespawn(WorldObject const* seer) const override; bool CanAlwaysSee(WorldObject const* obj) const override; private: void ForcedDespawn(uint32 timeMSToDespawn = 0, Seconds forceRespawnTimer = 0s); bool CheckNoGrayAggroConfig(uint32 playerLevel, uint32 creatureLevel) const; // No aggro from gray creatures // Waypoint path uint32 _waypointPathId; std::pair _currentWaypointNodeInfo; // Formation var CreatureGroup* m_formation; bool m_triggerJustAppeared; bool m_respawnCompatibilityMode; bool _aggroGracePeriodExpired; /* Spell focus system */ void ReacquireSpellFocusTarget(); struct { ::Spell const* Spell = nullptr; uint32 Delay = 0; // ms until the creature's target should snap back (0 = no snapback scheduled) ObjectGuid Target; // the creature's "real" target while casting float Orientation = 0.0f; // the creature's "real" orientation while casting } _spellFocusInfo; time_t _lastDamagedTime; // Part of Evade mechanics CreatureTextRepeatGroup m_textRepeat; // Draws data from m_creatureDifficulty and spawn/difficulty based override data and returns a CreatureStaticFlagsHolder value which contains the data of both CreatureStaticFlagsHolder GenerateStaticFlags(CreatureDifficulty const* creatureDifficulty, ObjectGuid::LowType spawnId, Difficulty difficultyId) const; void ApplyAllStaticFlags(CreatureStaticFlagsHolder const& flags); // Regenerate health bool _regenerateHealth; // Set on creation Optional _defaultMountDisplayIdOverride; int32 _creatureImmunitiesId; uint32 _gossipMenuId; Optional _trainerId; float _sparringHealthPct; }; class TC_GAME_API AssistDelayEvent : public BasicEvent { public: AssistDelayEvent(ObjectGuid victim, Unit& owner) : BasicEvent(), m_victim(victim), m_owner(owner) { } bool Execute(uint64 e_time, uint32 p_time) override; void AddAssistant(ObjectGuid guid) { m_assistants.push_back(guid); } private: AssistDelayEvent(); ObjectGuid m_victim; GuidList m_assistants; Unit& m_owner; }; class TC_GAME_API ForcedDespawnDelayEvent : public BasicEvent { public: ForcedDespawnDelayEvent(Creature& owner, Seconds respawnTimer) : BasicEvent(), m_owner(owner), m_respawnTimer(respawnTimer) { } bool Execute(uint64 e_time, uint32 p_time) override; private: Creature& m_owner; Seconds const m_respawnTimer; }; #endif