diff --git a/Source/Game/Entities/Creature/Creature.Fields.cs b/Source/Game/Entities/Creature/Creature.Fields.cs index 7dea8c978..6e15614fe 100644 --- a/Source/Game/Entities/Creature/Creature.Fields.cs +++ b/Source/Game/Entities/Creature/Creature.Fields.cs @@ -130,6 +130,18 @@ namespace Game.Entities _flags8 = (CreatureStaticFlags8)flags8; } + public CreatureStaticFlagsHolder(CreatureStaticFlags flags, CreatureStaticFlags2 flags2, CreatureStaticFlags3 flags3, CreatureStaticFlags4 flags4, CreatureStaticFlags5 flags5, CreatureStaticFlags6 flags6, CreatureStaticFlags7 flags7, CreatureStaticFlags8 flags8) + { + _flags = flags; + _flags2 = flags2; + _flags3 = flags3; + _flags4 = flags4; + _flags5 = flags5; + _flags6 = flags6; + _flags7 = flags7; + _flags8 = flags8; + } + public bool HasFlag(CreatureStaticFlags flag) { return _flags.HasFlag(flag); } public bool HasFlag(CreatureStaticFlags2 flag) { return _flags2.HasFlag(flag); } public bool HasFlag(CreatureStaticFlags3 flag) { return _flags3.HasFlag(flag); } @@ -147,5 +159,27 @@ namespace Game.Entities public void ApplyFlag(CreatureStaticFlags6 flag, bool apply) { if (apply) _flags6 |= flag; else _flags6 &= ~flag; } public void ApplyFlag(CreatureStaticFlags7 flag, bool apply) { if (apply) _flags7 |= flag; else _flags7 &= ~flag; } public void ApplyFlag(CreatureStaticFlags8 flag, bool apply) { if (apply) _flags8 |= flag; else _flags8 &= ~flag; } + + public CreatureStaticFlags GetFlags() { return _flags; } + public CreatureStaticFlags2 GetFlags2() { return _flags2; } + public CreatureStaticFlags3 GetFlags3() { return _flags3; } + public CreatureStaticFlags4 GetFlags4() { return _flags4; } + public CreatureStaticFlags5 GetFlags5() { return _flags5; } + public CreatureStaticFlags6 GetFlags6() { return _flags6; } + public CreatureStaticFlags7 GetFlags7() { return _flags7; } + public CreatureStaticFlags8 GetFlags8() { return _flags8; } + } + + // `creature_static_flags_override` table + public class CreatureStaticFlagsOverride + { + public CreatureStaticFlags? StaticFlags1; + public CreatureStaticFlags2? StaticFlags2; + public CreatureStaticFlags3? StaticFlags3; + public CreatureStaticFlags4? StaticFlags4; + public CreatureStaticFlags5? StaticFlags5; + public CreatureStaticFlags6? StaticFlags6; + public CreatureStaticFlags7? StaticFlags7; + public CreatureStaticFlags8? StaticFlags8; } } diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 46c305ea9..39c3bfe37 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -280,7 +280,8 @@ namespace Game.Entities for (byte i = 0; i < SharedConst.MaxCreatureSpells; ++i) m_spells[i] = GetCreatureTemplate().Spells[i]; - ApplyAllStaticFlags(m_creatureDifficulty.StaticFlags); + CreatureStaticFlagsHolder staticFlags = GenerateStaticFlags(m_creatureDifficulty, GetSpawnId(), GetMap().GetDifficultyID()); + ApplyAllStaticFlags(staticFlags); _staticFlags.ApplyFlag(CreatureStaticFlags.NoXp, creatureInfo.CreatureType == CreatureType.Critter || IsPet() || IsTotem() || creatureInfo.FlagsExtra.HasFlag(CreatureFlagsExtra.NoXP)); @@ -416,6 +417,30 @@ namespace Game.Entities return true; } + /// + /// 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 creatureDifficulty, ulong spawnId, Difficulty difficultyId) + { + CreatureStaticFlagsOverride staticFlagsOverride = Global.ObjectMgr.GetCreatureStaticFlagsOverride(spawnId, difficultyId); + if (staticFlagsOverride == null) + return creatureDifficulty.StaticFlags; + + return new CreatureStaticFlagsHolder( + staticFlagsOverride.StaticFlags1.GetValueOrDefault(creatureDifficulty.StaticFlags.GetFlags()), + staticFlagsOverride.StaticFlags2.GetValueOrDefault(creatureDifficulty.StaticFlags.GetFlags2()), + staticFlagsOverride.StaticFlags3.GetValueOrDefault(creatureDifficulty.StaticFlags.GetFlags3()), + staticFlagsOverride.StaticFlags4.GetValueOrDefault(creatureDifficulty.StaticFlags.GetFlags4()), + staticFlagsOverride.StaticFlags5.GetValueOrDefault(creatureDifficulty.StaticFlags.GetFlags5()), + staticFlagsOverride.StaticFlags6.GetValueOrDefault(creatureDifficulty.StaticFlags.GetFlags6()), + staticFlagsOverride.StaticFlags7.GetValueOrDefault(creatureDifficulty.StaticFlags.GetFlags7()), + staticFlagsOverride.StaticFlags8.GetValueOrDefault(creatureDifficulty.StaticFlags.GetFlags8())); + } + void ApplyAllStaticFlags(CreatureStaticFlagsHolder flags) { _staticFlags = flags; diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index 8709734ae..8511f57e9 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -10100,6 +10100,65 @@ namespace Game Log.outInfo(LogFilter.ServerLoading, $"Loaded {count} creature quest currencies in {Time.GetMSTimeDiffToNow(oldMSTime)} ms"); } + public void LoadCreatureStaticFlagsOverride() + { + // reload case + _creatureStaticFlagsOverrideStorage.Clear(); + + uint oldMSTime = Time.GetMSTime(); + + // 0 1 2 3 4 5 6 7 8 9 + SQLResult result = DB.World.Query("SELECT SpawnId, DifficultyId, StaticFlags1, StaticFlags2, StaticFlags3, StaticFlags4, StaticFlags5, StaticFlags6, StaticFlags7, StaticFlags8 FROM creature_static_flags_override"); + if (result.IsEmpty()) + { + Log.outInfo(LogFilter.ServerLoading, "Loaded 0 creature static flag overrides. DB table `creature_static_flags_override` is empty."); + return; + } + + uint count = 0; + do + { + ulong spawnId = result.Read(0); + Difficulty difficultyId = (Difficulty)result.Read(1); + + CreatureData creatureData = GetCreatureData(spawnId); + if (creatureData == null) + { + Log.outError(LogFilter.Sql, $"Table `creature_static_flags_override` has data for nonexistent creature (SpawnId: {spawnId}), skipped"); + continue; + } + + if (!creatureData.SpawnDifficulties.Contains(difficultyId)) + { + Log.outError(LogFilter.Sql, $"Table `creature_static_flags_override` has data for a creature that is not available for the specified DifficultyId (SpawnId: {spawnId}, DifficultyId: {difficultyId}), skipped"); + continue; + } + + CreatureStaticFlagsOverride staticFlagsOverride = new(); + if (!result.IsNull(2)) + staticFlagsOverride.StaticFlags1 = (CreatureStaticFlags)result.Read(2); + if (!result.IsNull(3)) + staticFlagsOverride.StaticFlags2 = (CreatureStaticFlags2)result.Read(3); + if (!result.IsNull(4)) + staticFlagsOverride.StaticFlags3 = (CreatureStaticFlags3)result.Read(4); + if (!result.IsNull(5)) + staticFlagsOverride.StaticFlags4 = (CreatureStaticFlags4)result.Read(5); + if (!result.IsNull(6)) + staticFlagsOverride.StaticFlags5 = (CreatureStaticFlags5)result.Read(6); + if (!result.IsNull(7)) + staticFlagsOverride.StaticFlags6 = (CreatureStaticFlags6)result.Read(7); + if (!result.IsNull(8)) + staticFlagsOverride.StaticFlags7 = (CreatureStaticFlags7)result.Read(8); + if (!result.IsNull(9)) + staticFlagsOverride.StaticFlags8 = (CreatureStaticFlags8)result.Read(9); + + _creatureStaticFlagsOverrideStorage[(spawnId, difficultyId)] = staticFlagsOverride; + ++count; + } while (result.NextRow()); + + Log.outInfo(LogFilter.ServerLoading, $"Loaded {count} creature static flag overrides in {Time.GetMSTimeDiffToNow(oldMSTime)} ms"); + } + public void InitializeQueriesData(QueryDataGroup mask) { uint oldMSTime = Time.GetMSTime(); @@ -10133,6 +10192,7 @@ namespace Game Log.outInfo(LogFilter.ServerLoading, $"Initialized query cache data in {Time.GetMSTimeDiffToNow(oldMSTime)} ms"); } + public void LoadJumpChargeParams() { uint oldMSTime = Time.GetMSTime(); @@ -10204,6 +10264,7 @@ namespace Game Log.outInfo(LogFilter.ServerLoading, $"Loaded {_jumpChargeParams.Count} Jump Charge Params in {Time.GetMSTimeDiffToNow(oldMSTime)} ms"); } + public void LoadPhaseNames() { uint oldMSTime = Time.GetMSTime(); @@ -10649,6 +10710,10 @@ namespace Game { return _jumpChargeParams.LookupByKey(id); } + public CreatureStaticFlagsOverride GetCreatureStaticFlagsOverride(ulong spawnId, Difficulty difficultyId) + { + return _creatureStaticFlagsOverrideStorage.LookupByKey((spawnId, difficultyId)); + } public string GetPhaseName(uint phaseId) { return _phaseNameStorage.TryGetValue(phaseId, out string value) ? value : "Unknown Name"; @@ -10867,6 +10932,7 @@ namespace Game Dictionary _sceneTemplateStorage = new(); Dictionary _jumpChargeParams = new(); Dictionary _phaseNameStorage = new(); + Dictionary<(ulong, Difficulty), CreatureStaticFlagsOverride> _creatureStaticFlagsOverrideStorage = new(); Dictionary _raceUnlockRequirementStorage = new(); List _classExpansionRequirementStorage = new(); diff --git a/Source/Game/World/WorldManager.cs b/Source/Game/World/WorldManager.cs index a443c8456..2e1c7b638 100644 --- a/Source/Game/World/WorldManager.cs +++ b/Source/Game/World/WorldManager.cs @@ -985,6 +985,9 @@ namespace Game Log.outInfo(LogFilter.ServerLoading, "Loading Creature Text Locales..."); Global.CreatureTextMgr.LoadCreatureTextLocales(); + Log.outInfo(LogFilter.ServerLoading, "Loading creature StaticFlags overrides..."); + Global.ObjectMgr.LoadCreatureStaticFlagsOverride(); // must be after LoadCreatures + Log.outInfo(LogFilter.ServerLoading, "Initializing Scripts..."); Global.ScriptMgr.Initialize(); Global.ScriptMgr.OnConfigLoad(false); // must be done after the ScriptMgr has been properly initialized