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