Core/Creatures: Reworked setting move types in database

Port From (https://github.com/TrinityCore/TrinityCore/commit/f8c03a90661610e289029c78d2055d7b73a5ad98)
This commit is contained in:
hondacrx
2021-08-24 12:23:39 -04:00
parent 89058fec83
commit e4240fcd94
13 changed files with 669 additions and 492 deletions
@@ -375,4 +375,22 @@ namespace Framework.Constants
MembersAssistMember = (MembersAssistLeader | LeaderAssistsMember), // every member will assist if any member is attacked MembersAssistMember = (MembersAssistLeader | LeaderAssistsMember), // every member will assist if any member is attacked
IdleInFormation = 0x200, // The member will follow the leader when pathing idly IdleInFormation = 0x200, // The member will follow the leader when pathing idly
} }
public enum CreatureGroundMovementType
{
None,
Run,
Hover,
Max
}
public enum CreatureFlightMovementType
{
None,
DisableGravity,
CanFly,
Max
}
} }
+1 -1
View File
@@ -1173,7 +1173,7 @@ namespace Framework.Constants
BanAccountYoubannedmessageWorld = 11006, BanAccountYoubannedmessageWorld = 11006,
BanAccountYoupermbannedmessageWorld = 11007, BanAccountYoupermbannedmessageWorld = 11007,
NpcinfoInhabitType = 11008, NpcinfoMovementData = 11008,
NpcinfoFlagsExtra = 11009, NpcinfoFlagsExtra = 11009,
InstanceLoginGamemasterException = 11010, InstanceLoginGamemasterException = 11010,
@@ -76,7 +76,7 @@ namespace Framework.Database
PrepareStatement(WorldStatements.SEL_WAYPOINT_SCRIPT_ID_BY_GUID, "SELECT id FROM waypoint_scripts WHERE guid = ?"); PrepareStatement(WorldStatements.SEL_WAYPOINT_SCRIPT_ID_BY_GUID, "SELECT id FROM waypoint_scripts WHERE guid = ?");
PrepareStatement(WorldStatements.DEL_CREATURE, "DELETE FROM creature WHERE guid = ?"); PrepareStatement(WorldStatements.DEL_CREATURE, "DELETE FROM creature WHERE guid = ?");
PrepareStatement(WorldStatements.SEL_COMMANDS, "SELECT name, permission, help FROM command"); PrepareStatement(WorldStatements.SEL_COMMANDS, "SELECT name, permission, help FROM command");
PrepareStatement(WorldStatements.SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, name, femaleName, subname, TitleAlt, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, RequiredExpansion, VignetteID, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, CreatureDifficultyID, WidgetSetID, WidgetSetUnitConditionID, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ? OR 1 = ?"); PrepareStatement(WorldStatements.SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, name, femaleName, subname, TitleAlt, IconName, gossip_menu_id, minlevel, maxlevel, HealthScalingExpansion, RequiredExpansion, VignetteID, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, VehicleId, mingold, maxgold, AIName, MovementType, ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, CreatureDifficultyID, WidgetSetID, WidgetSetUnitConditionID, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ? OR 1 = ?");
PrepareStatement(WorldStatements.SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?"); PrepareStatement(WorldStatements.SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?");
PrepareStatement(WorldStatements.SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?"); PrepareStatement(WorldStatements.SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?");
PrepareStatement(WorldStatements.SEL_GAMEOBJECT_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM gameobject WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_"); PrepareStatement(WorldStatements.SEL_GAMEOBJECT_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM gameobject WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_");
+5
View File
@@ -121,5 +121,10 @@ namespace Framework.Database
return values; return values;
} }
public bool IsNull(int column)
{
return _currentRow[column] == DBNull.Value;
}
} }
} }
+1 -1
View File
@@ -148,7 +148,7 @@ namespace Game.Chat
handler.SendSysMessage(CypherStrings.NpcinfoLevel, target.GetLevel()); handler.SendSysMessage(CypherStrings.NpcinfoLevel, target.GetLevel());
handler.SendSysMessage(CypherStrings.NpcinfoEquipment, target.GetCurrentEquipmentId(), target.GetOriginalEquipmentId()); handler.SendSysMessage(CypherStrings.NpcinfoEquipment, target.GetCurrentEquipmentId(), target.GetOriginalEquipmentId());
handler.SendSysMessage(CypherStrings.NpcinfoHealth, target.GetCreateHealth(), target.GetMaxHealth(), target.GetHealth()); handler.SendSysMessage(CypherStrings.NpcinfoHealth, target.GetCreateHealth(), target.GetMaxHealth(), target.GetHealth());
handler.SendSysMessage(CypherStrings.NpcinfoInhabitType, cInfo.InhabitType); handler.SendSysMessage(CypherStrings.NpcinfoMovementData, target.GetMovementTemplate().ToString());
handler.SendSysMessage(CypherStrings.NpcinfoUnitFieldFlags, (uint)target.m_unitData.Flags); handler.SendSysMessage(CypherStrings.NpcinfoUnitFieldFlags, (uint)target.m_unitData.Flags);
foreach (UnitFlags value in Enum.GetValues(typeof(UnitFlags))) foreach (UnitFlags value in Enum.GetValues(typeof(UnitFlags)))
@@ -169,6 +169,15 @@ namespace Game.Chat
return true; return true;
} }
[Command("creature_movement_override", RBACPermissions.CommandReloadCreatureMovementOverride, true)]
static bool HandleReloadCreatureMovementOverrideCommand(StringArguments args, CommandHandler handler)
{
Log.outInfo(LogFilter.Server, "Re-Loading Creature movement overrides...");
Global.ObjectMgr.LoadCreatureMovementOverrides();
handler.SendGlobalGMSysMessage("DB table `creature_movement_override` reloaded.");
return true;
}
[Command("creature_onkill_reputation", RBACPermissions.CommandReloadCreatureOnkillReputation, true)] [Command("creature_onkill_reputation", RBACPermissions.CommandReloadCreatureOnkillReputation, true)]
static bool HandleReloadOnKillReputationCommand(StringArguments args, CommandHandler handler) static bool HandleReloadOnKillReputationCommand(StringArguments args, CommandHandler handler)
{ {
@@ -985,6 +994,7 @@ namespace Game.Chat
HandleReloadCypherStringCommand(args, handler); HandleReloadCypherStringCommand(args, handler);
HandleReloadGameTeleCommand(args, handler); HandleReloadGameTeleCommand(args, handler);
HandleReloadCreatureMovementOverrideCommand(args, handler);
HandleReloadCreatureSummonGroupsCommand(args, handler); HandleReloadCreatureSummonGroupsCommand(args, handler);
HandleReloadVehicleAccessoryCommand(args, handler); HandleReloadVehicleAccessoryCommand(args, handler);
+28 -19
View File
@@ -416,7 +416,7 @@ namespace Game.Entities
ApplySpellImmune(0, SpellImmunity.Effect, SpellEffectName.AttackMe, true); ApplySpellImmune(0, SpellImmunity.Effect, SpellEffectName.AttackMe, true);
} }
if (cInfo.InhabitType.HasAnyFlag(InhabitType.Root)) if (GetMovementTemplate().IsRooted())
SetControlled(true, UnitState.Root); SetControlled(true, UnitState.Root);
UpdateMovementFlags(); UpdateMovementFlags();
@@ -2311,7 +2311,7 @@ namespace Game.Entities
dist += GetCombatReach() + victim.GetCombatReach(); dist += GetCombatReach() + victim.GetCombatReach();
// to prevent creatures in air ignore attacks because distance is already too high... // to prevent creatures in air ignore attacks because distance is already too high...
if (GetCreatureTemplate().InhabitType.HasAnyFlag(InhabitType.Air)) if (GetMovementTemplate().IsFlightAllowed())
return victim.IsInDist2d(m_homePosition, dist); return victim.IsInDist2d(m_homePosition, dist);
else else
return victim.IsInDist(m_homePosition, dist); return victim.IsInDist(m_homePosition, dist);
@@ -2356,7 +2356,7 @@ namespace Game.Entities
//! Check using InhabitType as movement flags are assigned dynamically //! Check using InhabitType as movement flags are assigned dynamically
//! basing on whether the creature is in air or not //! basing on whether the creature is in air or not
//! Set MovementFlag_Hover. Otherwise do nothing. //! Set MovementFlag_Hover. Otherwise do nothing.
if (Convert.ToBoolean(m_unitData.AnimTier & (byte)UnitBytes1Flags.Hover) && !Convert.ToBoolean(GetCreatureTemplate().InhabitType & InhabitType.Air)) if (CanHover())
AddUnitMovementFlag(MovementFlag.Hover); AddUnitMovementFlag(MovementFlag.Hover);
} }
@@ -2463,6 +2463,15 @@ namespace Game.Entities
bool IsSpawnedOnTransport() { return m_creatureData != null && m_creatureData.spawnPoint.GetMapId() != GetMapId(); } bool IsSpawnedOnTransport() { return m_creatureData != null && m_creatureData.spawnPoint.GetMapId() != GetMapId(); }
public CreatureMovementData GetMovementTemplate()
{
CreatureMovementData movementOverride = Global.ObjectMgr.GetCreatureMovementOverride(m_spawnId);
if (movementOverride != null)
return movementOverride;
return GetCreatureTemplate().Movement;
}
public void AllLootRemovedFromCorpse() public void AllLootRemovedFromCorpse()
{ {
if (loot.loot_type != LootType.Skinning && !IsPet() && GetCreatureTemplate().SkinLootId != 0 && HasLootRecipient()) if (loot.loot_type != LootType.Skinning && !IsPet() && GetCreatureTemplate().SkinLootId != 0 && HasLootRecipient())
@@ -2822,25 +2831,31 @@ namespace Game.Entities
// Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc) // Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc)
float ground = GetFloorZ(); float ground = GetFloorZ();
bool isInAir = (MathFunctions.fuzzyGt(GetPositionZ(), ground + MapConst.GroundHeightTolerance) || MathFunctions.fuzzyLt(GetPositionZ(), ground - MapConst.GroundHeightTolerance)); // Can be underground too, prevent the falling bool canHover = CanHover();
bool isInAir = (MathFunctions.fuzzyGt(GetPositionZ(), ground + (canHover ? m_unitData.HoverHeight : 0.0f) + MapConst.GroundHeightTolerance) || MathFunctions.fuzzyLt(GetPositionZ(), ground - MapConst.GroundHeightTolerance)); // Can be underground too, prevent the falling
if (GetCreatureTemplate().InhabitType.HasAnyFlag(InhabitType.Air) && isInAir && !IsFalling()) if (GetMovementTemplate().IsFlightAllowed() && isInAir && !IsFalling())
{ {
if (GetCreatureTemplate().InhabitType.HasAnyFlag(InhabitType.Ground)) if (GetMovementTemplate().Flight == CreatureFlightMovementType.CanFly)
SetCanFly(true); SetCanFly(true);
else else
SetDisableGravity(true); SetDisableGravity(true);
if (!HasAuraType(AuraType.Hover))
SetHover(false);
} }
else else
{ {
SetCanFly(false); SetCanFly(false);
SetDisableGravity(false); SetDisableGravity(false);
if (CanHover() || HasAuraType(AuraType.Hover))
SetHover(true);
} }
if (!isInAir) if (!isInAir)
SetFall(false); SetFall(false);
SetSwim(GetCreatureTemplate().InhabitType.HasAnyFlag(InhabitType.Water) && IsInWater()); SetSwim(GetMovementTemplate().IsSwimAllowed() && IsInWater());
} }
public override void SetObjectScale(float scale) public override void SetObjectScale(float scale)
@@ -3034,18 +3049,12 @@ namespace Game.Entities
{ {
return GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.Guard); return GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.Guard);
} }
public bool CanWalk()
{ public bool CanWalk() { return GetMovementTemplate().IsGroundAllowed(); }
return GetCreatureTemplate().InhabitType.HasAnyFlag(InhabitType.Ground); public override bool CanSwim() { return GetMovementTemplate().IsSwimAllowed() || IsPet();}
} public override bool CanFly() { return GetMovementTemplate().IsFlightAllowed(); }
public override bool CanSwim() bool CanHover() { return GetMovementTemplate().Ground == CreatureGroundMovementType.Hover; }
{
return GetCreatureTemplate().InhabitType.HasAnyFlag(InhabitType.Water);
}
public override bool CanFly()
{
return GetCreatureTemplate().InhabitType.HasAnyFlag(InhabitType.Air);
}
public bool IsDungeonBoss() { return (GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.DungeonBoss)); } public bool IsDungeonBoss() { return (GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.DungeonBoss)); }
public override bool IsAffectedByDiminishingReturns() { return base.IsAffectedByDiminishingReturns() || GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.AllDiminish); } public override bool IsAffectedByDiminishingReturns() { return base.IsAffectedByDiminishingReturns() || GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.AllDiminish); }
+29 -1
View File
@@ -74,7 +74,7 @@ namespace Game.Entities
public uint MaxGold; public uint MaxGold;
public string AIName; public string AIName;
public uint MovementType; public uint MovementType;
public InhabitType InhabitType; public CreatureMovementData Movement;
public float HoverHeight; public float HoverHeight;
public float ModHealth; public float ModHealth;
public float ModHealthExtra; public float ModHealthExtra;
@@ -347,6 +347,34 @@ namespace Game.Entities
public CreatureData() : base(SpawnObjectType.Creature) { } public CreatureData() : base(SpawnObjectType.Creature) { }
} }
public class CreatureMovementData
{
public CreatureGroundMovementType Ground;
public CreatureFlightMovementType Flight;
public bool Swim;
public bool Rooted;
public CreatureMovementData()
{
Ground = CreatureGroundMovementType.Run;
Flight = CreatureFlightMovementType.None;
Swim = true;
Rooted = false;
}
bool IsGroundAllowed() { return Ground != CreatureGroundMovementType.None; }
bool IsSwimAllowed() { return Swim; }
bool IsFlightAllowed() { return Flight != CreatureFlightMovementType.None; }
bool IsRooted() { return Rooted; }
public override string ToString()
{
return $"Ground: {Ground}, Swim: {Swim}, Flight: {Flight} {(Rooted ? ", Rooted" : "")}";
}
}
public class CreatureModelInfo public class CreatureModelInfo
{ {
public float BoundingRadius; public float BoundingRadius;
+119 -59
View File
@@ -42,8 +42,8 @@ namespace Game
{ {
for (var i = 0; i < SharedConst.MaxCreatureDifficulties; ++i) for (var i = 0; i < SharedConst.MaxCreatureDifficulties; ++i)
{ {
_difficultyEntries[i] = new List<uint>(); difficultyEntries[i] = new List<uint>();
_hasDifficultyEntries[i] = new List<uint>(); hasDifficultyEntries[i] = new List<uint>();
} }
} }
@@ -1744,10 +1744,10 @@ namespace Game
LoadCreatureTemplateModels(); LoadCreatureTemplateModels();
// Checking needs to be done after loading because of the difficulty self referencing // Checking needs to be done after loading because of the difficulty self referencing
foreach (var template in _creatureTemplateStorage.Values) foreach (var template in creatureTemplateStorage.Values)
CheckCreatureTemplate(template); CheckCreatureTemplate(template);
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} creature definitions in {1} ms", _creatureTemplateStorage.Count, Time.GetMSTimeDiffToNow(time)); Log.outInfo(LogFilter.ServerLoading, "Loaded {0} creature definitions in {1} ms", creatureTemplateStorage.Count, Time.GetMSTimeDiffToNow(time));
} }
public void LoadCreatureTemplate(SQLFields fields) public void LoadCreatureTemplate(SQLFields fields)
{ {
@@ -1809,27 +1809,36 @@ namespace Game
creature.MaxGold = fields.Read<uint>(57); creature.MaxGold = fields.Read<uint>(57);
creature.AIName = fields.Read<string>(58); creature.AIName = fields.Read<string>(58);
creature.MovementType = fields.Read<uint>(59); creature.MovementType = fields.Read<uint>(59);
creature.InhabitType = (InhabitType)fields.Read<uint>(60);
creature.HoverHeight = fields.Read<float>(61);
creature.ModHealth = fields.Read<float>(62);
creature.ModHealthExtra = fields.Read<float>(63);
creature.ModMana = fields.Read<float>(64);
creature.ModManaExtra = fields.Read<float>(65);
creature.ModArmor = fields.Read<float>(66);
creature.ModDamage = fields.Read<float>(67);
creature.ModExperience = fields.Read<float>(68);
creature.RacialLeader = fields.Read<bool>(69);
creature.MovementId = fields.Read<uint>(70);
creature.CreatureDifficultyID = fields.Read<int>(71);
creature.WidgetSetID = fields.Read<int>(72);
creature.WidgetSetUnitConditionID = fields.Read<int>(73);
creature.RegenHealth = fields.Read<bool>(74);
creature.MechanicImmuneMask = fields.Read<uint>(75);
creature.SpellSchoolImmuneMask = fields.Read<uint>(76);
creature.FlagsExtra = (CreatureFlagsExtra)fields.Read<uint>(77);
creature.ScriptID = GetScriptId(fields.Read<string>(78));
_creatureTemplateStorage[entry] = creature; if (!fields.IsNull(60))
creature.Movement.Ground = (CreatureGroundMovementType)fields.Read<byte>(60);
creature.Movement.Swim = fields.Read<bool>(61);
if (!fields.IsNull(62))
creature.Movement.Flight = (CreatureFlightMovementType)fields.Read<byte>(62);
creature.Movement.Rooted = fields.Read<uint>(63);
creature.HoverHeight = fields.Read<float>(64);
creature.ModHealth = fields.Read<float>(65);
creature.ModHealthExtra = fields.Read<float>(66);
creature.ModMana = fields.Read<float>(67);
creature.ModManaExtra = fields.Read<float>(68);
creature.ModArmor = fields.Read<float>(69);
creature.ModDamage = fields.Read<float>(70);
creature.ModExperience = fields.Read<float>(71);
creature.RacialLeader = fields.Read<bool>(72);
creature.MovementId = fields.Read<uint>(73);
creature.CreatureDifficultyID = fields.Read<int>(74);
creature.WidgetSetID = fields.Read<int>(75);
creature.WidgetSetUnitConditionID = fields.Read<int>(76);
creature.RegenHealth = fields.Read<bool>(77);
creature.MechanicImmuneMask = fields.Read<uint>(78);
creature.SpellSchoolImmuneMask = fields.Read<uint>(79);
creature.FlagsExtra = (CreatureFlagsExtra)fields.Read<uint>(80);
creature.ScriptID = GetScriptId(fields.Read<string>(81));
creatureTemplateStorage[entry] = creature;
} }
void LoadCreatureTemplateModels() void LoadCreatureTemplateModels()
@@ -2120,7 +2129,7 @@ namespace Game
uint item = result.Read<uint>(1); uint item = result.Read<uint>(1);
uint idx = result.Read<uint>(2); uint idx = result.Read<uint>(2);
if (!_creatureTemplateStorage.ContainsKey(entry)) if (!creatureTemplateStorage.ContainsKey(entry))
{ {
Log.outError(LogFilter.Sql, "Table `creature_questitem` has data for nonexistent creature (entry: {0}, idx: {1}), skipped", entry, idx); Log.outError(LogFilter.Sql, "Table `creature_questitem` has data for nonexistent creature (entry: {0}, idx: {1}), skipped", entry, idx);
continue; continue;
@@ -2132,7 +2141,7 @@ namespace Game
continue; continue;
} }
_creatureQuestItemStorage.Add(entry, item); creatureQuestItemStorage.Add(entry, item);
++count; ++count;
} }
@@ -2224,6 +2233,42 @@ namespace Game
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} equipment templates in {1} ms", count, Time.GetMSTimeDiffToNow(time)); Log.outInfo(LogFilter.ServerLoading, "Loaded {0} equipment templates in {1} ms", count, Time.GetMSTimeDiffToNow(time));
} }
public void LoadCreatureMovementOverrides()
{
uint oldMSTime = Time.GetMSTime();
creatureMovementOverrides.Clear();
SQLResult result = DB.World.Query("SELECT SpawnId, Ground, Swim, Flight, Rooted from creature_movement_override");
if (result.IsEmpty())
{
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 creature movement overrides. DB table `creature_movement_override` is empty!");
return;
}
do
{
ulong spawnId = result.Read<ulong>(0);
if (GetCreatureData(spawnId) == null)
{
Log.outError(LogFilter.Sql, $"Creature (GUID: {spawnId}) does not exist but has a record in `creature_movement_override`");
continue;
}
CreatureMovementData movement = new();
movement.Ground = (CreatureGroundMovementType)result.Read<byte>(1);
movement.Swim = result.Read<bool>(2);
movement.Flight = (CreatureFlightMovementType)result.Read<byte>(3);
movement.Rooted = result.Read<bool>(4);
CheckCreatureMovement("creature_movement_override", spawnId, movement);
creatureMovementOverrides[spawnId] = movement;
}
while (result.NextRow());
Log.outInfo(LogFilter.ServerLoading, $"Loaded {creatureMovementOverrides.Count} movement overrides in {Time.GetMSTimeDiffToNow(oldMSTime)} ms");
}
public void LoadCreatureClassLevelStats() public void LoadCreatureClassLevelStats()
{ {
var time = Time.GetMSTime(); var time = Time.GetMSTime();
@@ -2258,7 +2303,7 @@ namespace Game
++count; ++count;
} while (result.NextRow()); } while (result.NextRow());
foreach (var creatureTemplate in _creatureTemplateStorage.Values) foreach (var creatureTemplate in creatureTemplateStorage.Values)
{ {
for (short lvl = creatureTemplate.Minlevel; lvl <= creatureTemplate.Maxlevel; ++lvl) for (short lvl = creatureTemplate.Minlevel; lvl <= creatureTemplate.Maxlevel; ++lvl)
{ {
@@ -2352,7 +2397,7 @@ namespace Game
uint entry = result.Read<uint>(0); uint entry = result.Read<uint>(0);
Difficulty difficulty = (Difficulty)result.Read<byte>(1); Difficulty difficulty = (Difficulty)result.Read<byte>(1);
var template = _creatureTemplateStorage.LookupByKey(entry); var template = creatureTemplateStorage.LookupByKey(entry);
if (template == null) if (template == null)
{ {
Log.outError(LogFilter.Sql, $"Creature template (Entry: {entry}) does not exist but has a record in `creature_template_scaling`"); Log.outError(LogFilter.Sql, $"Creature template (Entry: {entry}) does not exist but has a record in `creature_template_scaling`");
@@ -2395,20 +2440,20 @@ namespace Game
for (uint diff2 = 0; diff2 < SharedConst.MaxCreatureDifficulties && ok2; ++diff2) for (uint diff2 = 0; diff2 < SharedConst.MaxCreatureDifficulties && ok2; ++diff2)
{ {
ok2 = false; ok2 = false;
if (_difficultyEntries[diff2].Contains(cInfo.Entry)) if (difficultyEntries[diff2].Contains(cInfo.Entry))
{ {
Log.outError(LogFilter.Sql, "Creature (Entry: {0}) is listed as `difficulty_entry_{1}` of another creature, but itself lists {2} in `difficulty_entry_{3}`.", Log.outError(LogFilter.Sql, "Creature (Entry: {0}) is listed as `difficulty_entry_{1}` of another creature, but itself lists {2} in `difficulty_entry_{3}`.",
cInfo.Entry, diff2 + 1, cInfo.DifficultyEntry[diff], diff + 1); cInfo.Entry, diff2 + 1, cInfo.DifficultyEntry[diff], diff + 1);
continue; continue;
} }
if (_difficultyEntries[diff2].Contains(cInfo.DifficultyEntry[diff])) if (difficultyEntries[diff2].Contains(cInfo.DifficultyEntry[diff]))
{ {
Log.outError(LogFilter.Sql, "Creature (Entry: {0}) already listed as `difficulty_entry_{1}` for another entry.", cInfo.DifficultyEntry[diff], diff2 + 1); Log.outError(LogFilter.Sql, "Creature (Entry: {0}) already listed as `difficulty_entry_{1}` for another entry.", cInfo.DifficultyEntry[diff], diff2 + 1);
continue; continue;
} }
if (_hasDifficultyEntries[diff2].Contains(cInfo.DifficultyEntry[diff])) if (hasDifficultyEntries[diff2].Contains(cInfo.DifficultyEntry[diff]))
{ {
Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has `difficulty_entry_{1}`={2} but creature entry {3} has itself a value in `difficulty_entry_{4}`.", Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has `difficulty_entry_{1}`={2} but creature entry {3} has itself a value in `difficulty_entry_{4}`.",
cInfo.Entry, diff + 1, cInfo.DifficultyEntry[diff], cInfo.DifficultyEntry[diff], diff2 + 1); cInfo.Entry, diff + 1, cInfo.DifficultyEntry[diff], cInfo.DifficultyEntry[diff], diff2 + 1);
@@ -2532,8 +2577,8 @@ namespace Game
continue; continue;
} }
_hasDifficultyEntries[diff].Add(cInfo.Entry); hasDifficultyEntries[diff].Add(cInfo.Entry);
_difficultyEntries[diff].Add(cInfo.DifficultyEntry[diff]); difficultyEntries[diff].Add(cInfo.DifficultyEntry[diff]);
ok = true; ok = true;
} }
@@ -2606,11 +2651,7 @@ namespace Game
cInfo.Family = CreatureFamily.None; cInfo.Family = CreatureFamily.None;
} }
if (cInfo.InhabitType <= 0 || cInfo.InhabitType > InhabitType.Anywhere) CheckCreatureMovement("creature_template_movement", cInfo.Entry, cInfo.Movement);
{
Log.outError(LogFilter.Sql, "Creature (Entry: {0}) has wrong value ({1}) in `InhabitType`, creature will not correctly walk/swim/fly.", cInfo.Entry, cInfo.InhabitType);
cInfo.InhabitType = InhabitType.Anywhere;
}
if (cInfo.HoverHeight < 0.0f) if (cInfo.HoverHeight < 0.0f)
{ {
@@ -2676,6 +2717,20 @@ namespace Game
cInfo.ModDamage *= Creature._GetDamageMod(cInfo.Rank); cInfo.ModDamage *= Creature._GetDamageMod(cInfo.Rank);
} }
void CheckCreatureMovement(string table, ulong id, CreatureMovementData creatureMovement)
{
if (creatureMovement.Ground >= CreatureGroundMovementType.Max)
{
Log.outError(LogFilter.Sql, $"`{table}`.`Ground` wrong value ({creatureMovement.Ground}) for Id {id}, setting to Run.");
creatureMovement.Ground = CreatureGroundMovementType.Run;
}
if (creatureMovement.Flight >= CreatureFlightMovementType.Max)
{
Log.outError(LogFilter.Sql, $"`{table}`.`Flight` wrong value ({creatureMovement.Flight}) for Id {id}, setting to None.");
creatureMovement.Flight = CreatureFlightMovementType.None;
}
}
public void LoadLinkedRespawn() public void LoadLinkedRespawn()
{ {
uint oldMSTime = Time.GetMSTime(); uint oldMSTime = Time.GetMSTime();
@@ -2865,7 +2920,7 @@ namespace Game
{ {
uint oldMSTime = Time.GetMSTime(); uint oldMSTime = Time.GetMSTime();
_npcTextStorage.Clear(); npcTextStorage.Clear();
SQLResult result = DB.World.Query("SELECT ID, Probability0, Probability1, Probability2, Probability3, Probability4, Probability5, Probability6, Probability7, " + SQLResult result = DB.World.Query("SELECT ID, Probability0, Probability1, Probability2, Probability3, Probability4, Probability5, Probability6, Probability7, " +
"BroadcastTextID0, BroadcastTextID1, BroadcastTextID2, BroadcastTextID3, BroadcastTextID4, BroadcastTextID5, BroadcastTextID6, BroadcastTextID7 FROM npc_text"); "BroadcastTextID0, BroadcastTextID1, BroadcastTextID2, BroadcastTextID3, BroadcastTextID4, BroadcastTextID5, BroadcastTextID6, BroadcastTextID7 FROM npc_text");
@@ -2912,10 +2967,10 @@ namespace Game
npcText.Data[i].Probability = 0; npcText.Data[i].Probability = 0;
} }
} }
_npcTextStorage[textID] = npcText; npcTextStorage[textID] = npcText;
} while (result.NextRow()); } while (result.NextRow());
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} npc texts in {1} ms", _npcTextStorage.Count, Time.GetMSTimeDiffToNow(oldMSTime)); Log.outInfo(LogFilter.ServerLoading, "Loaded {0} npc texts in {1} ms", npcTextStorage.Count, Time.GetMSTimeDiffToNow(oldMSTime));
} }
public void LoadTrainers() public void LoadTrainers()
@@ -2923,7 +2978,7 @@ namespace Game
uint oldMSTime = Time.GetMSTime(); uint oldMSTime = Time.GetMSTime();
// For reload case // For reload case
_trainers.Clear(); trainers.Clear();
MultiMap<uint, TrainerSpell> spellsByTrainer = new(); MultiMap<uint, TrainerSpell> spellsByTrainer = new();
SQLResult trainerSpellsResult = DB.World.Query("SELECT TrainerId, SpellId, MoneyCost, ReqSkillLine, ReqSkillRank, ReqAbility1, ReqAbility2, ReqAbility3, ReqLevel FROM trainer_spell"); SQLResult trainerSpellsResult = DB.World.Query("SELECT TrainerId, SpellId, MoneyCost, ReqSkillLine, ReqSkillRank, ReqAbility1, ReqAbility2, ReqAbility3, ReqLevel FROM trainer_spell");
@@ -2990,7 +3045,7 @@ namespace Game
spellsByTrainer.Remove(trainerId); spellsByTrainer.Remove(trainerId);
} }
_trainers.Add(trainerId, new Trainer(trainerId, trainerType, greeting, spells)); trainers.Add(trainerId, new Trainer(trainerId, trainerType, greeting, spells));
} while (trainersResult.NextRow()); } while (trainersResult.NextRow());
} }
@@ -3013,7 +3068,7 @@ namespace Game
if (!SharedConst.IsValidLocale(locale) || locale == Locale.enUS) if (!SharedConst.IsValidLocale(locale) || locale == Locale.enUS)
continue; continue;
Trainer trainer = _trainers.LookupByKey(trainerId); Trainer trainer = trainers.LookupByKey(trainerId);
if (trainer != null) if (trainer != null)
trainer.AddGreetingLocale(locale, trainerLocalesResult.Read<String>(2)); trainer.AddGreetingLocale(locale, trainerLocalesResult.Read<String>(2));
else else
@@ -3022,7 +3077,7 @@ namespace Game
} while (trainerLocalesResult.NextRow()); } while (trainerLocalesResult.NextRow());
} }
Log.outInfo(LogFilter.ServerLoading, $"Loaded {_trainers.Count} Trainers in {Time.GetMSTimeDiffToNow(oldMSTime)} ms"); Log.outInfo(LogFilter.ServerLoading, $"Loaded {trainers.Count} Trainers in {Time.GetMSTimeDiffToNow(oldMSTime)} ms");
} }
public void LoadCreatureTrainers() public void LoadCreatureTrainers()
{ {
@@ -3274,7 +3329,7 @@ namespace Game
bool ok = true; bool ok = true;
for (uint diff = 0; diff < SharedConst.MaxCreatureDifficulties && ok; ++diff) for (uint diff = 0; diff < SharedConst.MaxCreatureDifficulties && ok; ++diff)
{ {
if (_difficultyEntries[diff].Contains(data.Id)) if (difficultyEntries[diff].Contains(data.Id))
{ {
Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0}) that listed as difficulty {1} template (entry: {2}) in `creaturetemplate`, skipped.", guid, diff + 1, data.Id); Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0}) that listed as difficulty {1} template (entry: {2}) in `creaturetemplate`, skipped.", guid, diff + 1, data.Id);
ok = false; ok = false;
@@ -3471,7 +3526,7 @@ namespace Game
} }
public List<uint> GetCreatureQuestItemList(uint id) public List<uint> GetCreatureQuestItemList(uint id)
{ {
return _creatureQuestItemStorage.LookupByKey(id); return creatureQuestItemStorage.LookupByKey(id);
} }
public CreatureAddon GetCreatureAddon(ulong lowguid) public CreatureAddon GetCreatureAddon(ulong lowguid)
{ {
@@ -3479,7 +3534,7 @@ namespace Game
} }
public CreatureTemplate GetCreatureTemplate(uint entry) public CreatureTemplate GetCreatureTemplate(uint entry)
{ {
return _creatureTemplateStorage.LookupByKey(entry); return creatureTemplateStorage.LookupByKey(entry);
} }
public CreatureAddon GetCreatureTemplateAddon(uint entry) public CreatureAddon GetCreatureTemplateAddon(uint entry)
{ {
@@ -3495,7 +3550,7 @@ namespace Game
} }
public Dictionary<uint, CreatureTemplate> GetCreatureTemplates() public Dictionary<uint, CreatureTemplate> GetCreatureTemplates()
{ {
return _creatureTemplateStorage; return creatureTemplateStorage;
} }
public Dictionary<ulong, CreatureData> GetAllCreatureData() { return creatureDataStorage; } public Dictionary<ulong, CreatureData> GetAllCreatureData() { return creatureDataStorage; }
public CreatureData GetCreatureData(ulong guid) public CreatureData GetCreatureData(ulong guid)
@@ -3622,7 +3677,7 @@ namespace Game
} }
public NpcText GetNpcText(uint textId) public NpcText GetNpcText(uint textId)
{ {
return _npcTextStorage.LookupByKey(textId); return npcTextStorage.LookupByKey(textId);
} }
//GameObjects //GameObjects
@@ -4760,7 +4815,7 @@ namespace Game
} }
public Trainer GetTrainer(uint trainerId) public Trainer GetTrainer(uint trainerId)
{ {
return _trainers.LookupByKey(trainerId); return trainers.LookupByKey(trainerId);
} }
public void AddVendorItem(uint entry, VendorItem vItem, bool persist = true) public void AddVendorItem(uint entry, VendorItem vItem, bool persist = true)
{ {
@@ -4909,6 +4964,10 @@ namespace Game
{ {
return cacheVendorItemStorage.LookupByKey(entry); return cacheVendorItemStorage.LookupByKey(entry);
} }
public CreatureMovementData GetCreatureMovementOverride(ulong spawnId)
{
return creatureMovementOverrides.lookupbykey(spawnId);
}
public EquipmentInfo GetEquipmentInfo(uint entry, int id) public EquipmentInfo GetEquipmentInfo(uint entry, int id)
{ {
var equip = equipmentInfoStorage.LookupByKey(entry); var equip = equipmentInfoStorage.LookupByKey(entry);
@@ -9664,7 +9723,7 @@ namespace Game
// Initialize Query data for creatures // Initialize Query data for creatures
if (mask.HasAnyFlag(QueryDataGroup.Creatures)) if (mask.HasAnyFlag(QueryDataGroup.Creatures))
foreach (var creaturePair in _creatureTemplateStorage) foreach (var creaturePair in creatureTemplateStorage)
creaturePair.Value.InitializeQueryData(); creaturePair.Value.InitializeQueryData();
// Initialize Query Data for gameobjects // Initialize Query Data for gameobjects
@@ -10062,7 +10121,7 @@ namespace Game
public List<TempSummonData> GetSummonGroup(uint summonerId, SummonerType summonerType, byte group) public List<TempSummonData> GetSummonGroup(uint summonerId, SummonerType summonerType, byte group)
{ {
Tuple<uint, SummonerType,byte> key = Tuple.Create(summonerId, summonerType, group); Tuple<uint, SummonerType, byte> key = Tuple.Create(summonerId, summonerType, group);
return _tempSummonDataStorage.LookupByKey(key); return _tempSummonDataStorage.LookupByKey(key);
} }
@@ -10282,21 +10341,22 @@ namespace Game
Dictionary<uint, PointOfInterest> pointsOfInterestStorage = new(); Dictionary<uint, PointOfInterest> pointsOfInterestStorage = new();
//Creature //Creature
Dictionary<uint, CreatureTemplate> _creatureTemplateStorage = new(); Dictionary<uint, CreatureTemplate> creatureTemplateStorage = new();
Dictionary<uint, CreatureModelInfo> creatureModelStorage = new(); Dictionary<uint, CreatureModelInfo> creatureModelStorage = new();
Dictionary<ulong, CreatureData> creatureDataStorage = new(); Dictionary<ulong, CreatureData> creatureDataStorage = new();
Dictionary<ulong, CreatureAddon> creatureAddonStorage = new(); Dictionary<ulong, CreatureAddon> creatureAddonStorage = new();
MultiMap<uint, uint> _creatureQuestItemStorage = new(); MultiMap<uint, uint> creatureQuestItemStorage = new();
Dictionary<uint, CreatureAddon> creatureTemplateAddonStorage = new(); Dictionary<uint, CreatureAddon> creatureTemplateAddonStorage = new();
Dictionary<ulong, CreatureMovementData> creatureMovementOverrides = new();
MultiMap<uint, Tuple<uint, EquipmentInfo>> equipmentInfoStorage = new(); MultiMap<uint, Tuple<uint, EquipmentInfo>> equipmentInfoStorage = new();
Dictionary<ObjectGuid, ObjectGuid> linkedRespawnStorage = new(); Dictionary<ObjectGuid, ObjectGuid> linkedRespawnStorage = new();
Dictionary<uint, CreatureBaseStats> creatureBaseStatsStorage = new(); Dictionary<uint, CreatureBaseStats> creatureBaseStatsStorage = new();
Dictionary<uint, VendorItemData> cacheVendorItemStorage = new(); Dictionary<uint, VendorItemData> cacheVendorItemStorage = new();
Dictionary<uint, Trainer> _trainers = new(); Dictionary<uint, Trainer> trainers = new();
Dictionary<(uint creatureId, uint gossipMenuId, uint gossipOptionIndex), uint> _creatureDefaultTrainers = new(); Dictionary<(uint creatureId, uint gossipMenuId, uint gossipOptionIndex), uint> _creatureDefaultTrainers = new();
List<uint>[] _difficultyEntries = new List<uint>[SharedConst.MaxCreatureDifficulties]; // already loaded difficulty 1 value in creatures, used in CheckCreatureTemplate List<uint>[] difficultyEntries = new List<uint>[SharedConst.MaxCreatureDifficulties]; // already loaded difficulty 1 value in creatures, used in CheckCreatureTemplate
List<uint>[] _hasDifficultyEntries = new List<uint>[SharedConst.MaxCreatureDifficulties]; // already loaded creatures with difficulty 1 values, used in CheckCreatureTemplate List<uint>[] hasDifficultyEntries = new List<uint>[SharedConst.MaxCreatureDifficulties]; // already loaded creatures with difficulty 1 values, used in CheckCreatureTemplate
Dictionary<uint, NpcText> _npcTextStorage = new(); Dictionary<uint, NpcText> npcTextStorage = new();
//GameObject //GameObject
Dictionary<uint, GameObjectTemplate> _gameObjectTemplateStorage = new(); Dictionary<uint, GameObjectTemplate> _gameObjectTemplateStorage = new();
+3
View File
@@ -616,6 +616,9 @@ namespace Game
Log.outInfo(LogFilter.ServerLoading, "Loading Creature Addon Data..."); Log.outInfo(LogFilter.ServerLoading, "Loading Creature Addon Data...");
Global.ObjectMgr.LoadCreatureAddons(); Global.ObjectMgr.LoadCreatureAddons();
Log.outInfo(LogFilter.ServerLoading, "Loading Creature Movement Overrides...");
Global.ObjectMgr.LoadCreatureMovementOverrides(); // must be after LoadCreatures()
Log.outInfo(LogFilter.ServerLoading, "Loading GameObjects..."); Log.outInfo(LogFilter.ServerLoading, "Loading GameObjects...");
Global.ObjectMgr.LoadGameObjects(); Global.ObjectMgr.LoadGameObjects();
+3
View File
@@ -1198,6 +1198,7 @@ INSERT INTO `rbac_linked_permissions` VALUES
(196,870), (196,870),
(196,871), (196,871),
(196,872), (196,872),
(196,873),
(196,881), (196,881),
(197,232), (197,232),
(197,236), (197,236),
@@ -2130,6 +2131,7 @@ INSERT INTO `rbac_permissions` VALUES
(870,'Command: debug threatinfo'), (870,'Command: debug threatinfo'),
(871,'Command: debug instancespawn'), (871,'Command: debug instancespawn'),
(872,'Command: server debug'), (872,'Command: server debug'),
(873,'Command: reload creature_movement_override'),
(881,'Command: reload vehicle_template'); (881,'Command: reload vehicle_template');
/*!40000 ALTER TABLE `rbac_permissions` ENABLE KEYS */; /*!40000 ALTER TABLE `rbac_permissions` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;
@@ -2347,6 +2349,7 @@ INSERT INTO `updates` VALUES
('2018_02_18_00_auth.sql','8489DD3EFFE14A7486B593435F0BA2BC69B6EABF','ARCHIVED','2018-02-18 16:35:55',0), ('2018_02_18_00_auth.sql','8489DD3EFFE14A7486B593435F0BA2BC69B6EABF','ARCHIVED','2018-02-18 16:35:55',0),
('2018_02_19_00_auth.sql','07CE658C5EF88693D3C047EF8E724F94ADA74C15','ARCHIVED','2018-02-19 22:33:32',0), ('2018_02_19_00_auth.sql','07CE658C5EF88693D3C047EF8E724F94ADA74C15','ARCHIVED','2018-02-19 22:33:32',0),
('2018_02_28_00_auth.sql','E92EF4ABF7FA0C66649E1633DD0459F44C09EB83','ARCHIVED','2018-02-28 23:07:59',0), ('2018_02_28_00_auth.sql','E92EF4ABF7FA0C66649E1633DD0459F44C09EB83','ARCHIVED','2018-02-28 23:07:59',0),
('2018_03_08_00_auth.sql','624C58A07E0B4DDC4C1347E8BA8EFEEFD5B43DA7','RELEASED','2018-01-12 15:10:11',0),
('2018_03_14_00_auth.sql','2D71E93DF7419A30D0D21D8A80CF05698302575A','ARCHIVED','2018-03-14 23:07:59',0), ('2018_03_14_00_auth.sql','2D71E93DF7419A30D0D21D8A80CF05698302575A','ARCHIVED','2018-03-14 23:07:59',0),
('2018_04_06_00_auth.sql','D8416F0C4751763202B1997C81423F6EE2FCF9A6','ARCHIVED','2018-04-06 18:00:32',0), ('2018_04_06_00_auth.sql','D8416F0C4751763202B1997C81423F6EE2FCF9A6','ARCHIVED','2018-04-06 18:00:32',0),
('2018_05_13_00_auth.sql','A9E20F2EB1E2FDBB982DB6B00DB7301852B27CD4','ARCHIVED','2018-05-13 20:22:32',0), ('2018_05_13_00_auth.sql','A9E20F2EB1E2FDBB982DB6B00DB7301852B27CD4','ARCHIVED','2018-05-13 20:22:32',0),
@@ -0,0 +1,7 @@
DELETE FROM `rbac_permissions` WHERE `id` = 873;
INSERT INTO `rbac_permissions` (`id`,`name`) VALUES
(873, 'Command: reload creature_movement_override');
DELETE FROM `rbac_linked_permissions` WHERE `linkedId` = 873;
INSERT INTO `rbac_linked_permissions` (`id`,`linkedId`) VALUES
(196, 873);
@@ -0,0 +1,34 @@
DROP TABLE IF EXISTS `creature_template_movement`;
CREATE TABLE `creature_template_movement` (
`CreatureId` int(10) unsigned NOT NULL DEFAULT '0',
`Ground` tinyint(3) unsigned NOT NULL DEFAULT '1',
`Swim` tinyint(3) unsigned NOT NULL DEFAULT '1',
`Flight` tinyint(3) unsigned NOT NULL DEFAULT '0',
`Rooted` tinyint(3) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`CreatureId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `creature_movement_override`;
CREATE TABLE `creature_movement_override` (
`SpawnId` bigint(20) unsigned NOT NULL DEFAULT '0',
`Ground` tinyint(3) unsigned NOT NULL DEFAULT '1',
`Swim` tinyint(3) unsigned NOT NULL DEFAULT '1',
`Flight` tinyint(3) unsigned NOT NULL DEFAULT '0',
`Rooted` tinyint(3) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`SpawnId`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `creature_template_movement` SELECT `entry`,0,0,0,0 FROM `creature_template` WHERE `InhabitType`!=3;
UPDATE `creature_template_movement` SET `Ground`=1 WHERE `CreatureId` IN (SELECT `entry` FROM `creature_template` WHERE `InhabitType` & 1);
UPDATE `creature_template_movement` SET `Swim`=1 WHERE `CreatureId` IN (SELECT `entry` FROM `creature_template` WHERE `InhabitType` & 2);
UPDATE `creature_template_movement` SET `Flight`=1 WHERE `CreatureId` IN (SELECT `entry` FROM `creature_template` WHERE (`InhabitType` & 5) = 4);
UPDATE `creature_template_movement` SET `Flight`=2 WHERE `CreatureId` IN (SELECT `entry` FROM `creature_template` WHERE (`InhabitType` & 5) = 5);
UPDATE `creature_template_movement` SET `Rooted`=1 WHERE `CreatureId` IN (SELECT `entry` FROM `creature_template` WHERE `InhabitType` & 8);
ALTER TABLE `creature_template` DROP `InhabitType`;
UPDATE `trinity_string` SET `content_default`='Movement type: %s' WHERE `entry`=11008;
DELETE FROM `command` WHERE `name`='reload creature_movement_override';
INSERT INTO `command` (`name`,`permission`,`help`) VALUES
('reload creature_movement_override',873,'Syntax: .reload creature_movement_override\nReload creature_movement_override table.');