diff --git a/Source/Framework/Database/Databases/WorldDatabase.cs b/Source/Framework/Database/Databases/WorldDatabase.cs index f49e2d365..f1588b295 100644 --- a/Source/Framework/Database/Databases/WorldDatabase.cs +++ b/Source/Framework/Database/Databases/WorldDatabase.cs @@ -76,7 +76,7 @@ namespace Framework.Database 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.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, ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, 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_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, VehicleId, mingold, maxgold, AIName, MovementType, ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, 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_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_"); diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index 1fa944828..79f7d6e48 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -1748,6 +1748,9 @@ namespace Game LoadCreatureTemplate(result.GetFields()); } while (result.NextRow()); + LoadCreatureTemplateResistances(); + LoadCreatureTemplateSpells(); + // We load the creature models after loading but before checking LoadCreatureTemplateModels(); @@ -1807,57 +1810,136 @@ namespace Game creature.SkinLootId = fields.Read(40); for (var i = (int)SpellSchools.Holy; i < (int)SpellSchools.Max; ++i) - creature.Resistance[i] = fields.Read(41 + i - 1); + creature.Resistance[i] = 0; for (var i = 0; i < SharedConst.MaxCreatureSpells; ++i) - creature.Spells[i] = fields.Read(47 + i); + creature.Spells[i] = 0; - creature.VehicleId = fields.Read(55); - creature.MinGold = fields.Read(56); - creature.MaxGold = fields.Read(57); - creature.AIName = fields.Read(58); - creature.MovementType = fields.Read(59); + creature.VehicleId = fields.Read(41); + creature.MinGold = fields.Read(42); + creature.MaxGold = fields.Read(43); + creature.AIName = fields.Read(44); + creature.MovementType = fields.Read(45); - if (!fields.IsNull(60)) - creature.Movement.Ground = (CreatureGroundMovementType)fields.Read(60); + if (!fields.IsNull(46)) + creature.Movement.Ground = (CreatureGroundMovementType)fields.Read(46); - if (!fields.IsNull(61)) - creature.Movement.Swim = fields.Read(61); + if (!fields.IsNull(47)) + creature.Movement.Swim = fields.Read(47); - if (!fields.IsNull(62)) - creature.Movement.Flight = (CreatureFlightMovementType)fields.Read(62); + if (!fields.IsNull(48)) + creature.Movement.Flight = (CreatureFlightMovementType)fields.Read(48); - if (!fields.IsNull(63)) - creature.Movement.Rooted = fields.Read(63); + if (!fields.IsNull(49)) + creature.Movement.Rooted = fields.Read(49); - if (!fields.IsNull(64)) - creature.Movement.Chase = (CreatureChaseMovementType)fields.Read(64); + if (!fields.IsNull(50)) + creature.Movement.Chase = (CreatureChaseMovementType)fields.Read(50); - if (!fields.IsNull(65)) - creature.Movement.Random = (CreatureRandomMovementType)fields.Read(65); + if (!fields.IsNull(51)) + creature.Movement.Random = (CreatureRandomMovementType)fields.Read(51); - creature.HoverHeight = fields.Read(66); - creature.ModHealth = fields.Read(67); - creature.ModHealthExtra = fields.Read(68); - creature.ModMana = fields.Read(69); - creature.ModManaExtra = fields.Read(70); - creature.ModArmor = fields.Read(71); - creature.ModDamage = fields.Read(72); - creature.ModExperience = fields.Read(73); - creature.RacialLeader = fields.Read(74); - creature.MovementId = fields.Read(75); - creature.CreatureDifficultyID = fields.Read(76); - creature.WidgetSetID = fields.Read(77); - creature.WidgetSetUnitConditionID = fields.Read(78); - creature.RegenHealth = fields.Read(79); - creature.MechanicImmuneMask = fields.Read(80); - creature.SpellSchoolImmuneMask = fields.Read(81); - creature.FlagsExtra = (CreatureFlagsExtra)fields.Read(82); - creature.ScriptID = GetScriptId(fields.Read(83)); + creature.HoverHeight = fields.Read(52); + creature.ModHealth = fields.Read(53); + creature.ModHealthExtra = fields.Read(54); + creature.ModMana = fields.Read(55); + creature.ModManaExtra = fields.Read(56); + creature.ModArmor = fields.Read(57); + creature.ModDamage = fields.Read(58); + creature.ModExperience = fields.Read(59); + creature.RacialLeader = fields.Read(60); + creature.MovementId = fields.Read(61); + creature.CreatureDifficultyID = fields.Read(62); + creature.WidgetSetID = fields.Read(63); + creature.WidgetSetUnitConditionID = fields.Read(64); + creature.RegenHealth = fields.Read(65); + creature.MechanicImmuneMask = fields.Read(66); + creature.SpellSchoolImmuneMask = fields.Read(67); + creature.FlagsExtra = (CreatureFlagsExtra)fields.Read(68); + creature.ScriptID = GetScriptId(fields.Read(69)); creatureTemplateStorage[entry] = creature; } + void LoadCreatureTemplateResistances() + { + uint oldMSTime = Time.GetMSTime(); + + // 0 1 2 + SQLResult result = DB.World.Query("SELECT CreatureID, School, Resistance FROM creature_template_resistance"); + if (result.IsEmpty()) + { + Log.outInfo(LogFilter.ServerLoading, "Loaded 0 creature template resistance definitions. DB table `creature_template_resistance` is empty."); + return; + } + + uint count = 0; + + do + { + uint creatureID = result.Read(0); + SpellSchools school = (SpellSchools)result.Read(1); + + if (school == SpellSchools.Normal || school >= SpellSchools.Max) + { + Log.outInfo(LogFilter.Sql, $"creature_template_resistance has resistance definitions for creature {creatureID} but this school {school} doesn't exist"); + continue; + } + + if (!creatureTemplateStorage.TryGetValue(creatureID, out CreatureTemplate creatureTemplate)) + { + Log.outInfo(LogFilter.Sql, $"creature_template_resistance has resistance definitions for creature {creatureID} but this creature doesn't exist"); + continue; + } + + creatureTemplate.Resistance[(int)school] = result.Read(2); + + ++count; + + } while (result.NextRow()); + + Log.outInfo(LogFilter.ServerLoading, $"Loaded {count} creature template resistances in {Time.GetMSTimeDiffToNow(oldMSTime)} ms"); + } + + void LoadCreatureTemplateSpells() + { + uint oldMSTime = Time.GetMSTime(); + + // 0 1 2 + SQLResult result = DB.World.Query("SELECT CreatureID, `Index`, Spell FROM creature_template_spell"); + if (result.IsEmpty()) + { + Log.outInfo(LogFilter.ServerLoading, "Loaded 0 creature template spell definitions. DB table `creature_template_spell` is empty."); + return; + } + + uint count = 0; + + do + { + uint creatureID = result.Read(0); + byte index = result.Read(1); + + if (index >= SharedConst.MaxCreatureSpells) + { + Log.outInfo(LogFilter.Sql, $"creature_template_spell has spell definitions for creature {creatureID} with a incorrect index {index}"); + continue; + } + + if (!creatureTemplateStorage.TryGetValue(creatureID, out CreatureTemplate creatureTemplate)) + { + Log.outError(LogFilter.Sql, $"creature_template_spell has spell definitions for creature {creatureID} but this creature doesn't exist"); + continue; + } + + creatureTemplate.Spells[index] = result.Read(2); + + ++count; + + } while (result.NextRow()); + + Log.outInfo(LogFilter.ServerLoading, $"Loaded {count} creature template spells in {Time.GetMSTimeDiffToNow(oldMSTime)} ms"); + } void LoadCreatureTemplateModels() { uint oldMSTime = Time.GetMSTime(); diff --git a/sql/updates/world/master/2021_12_11_08_world_2019_06_15_01_world.sql b/sql/updates/world/master/2021_12_11_08_world_2019_06_15_01_world.sql new file mode 100644 index 000000000..8e2bceaa6 --- /dev/null +++ b/sql/updates/world/master/2021_12_11_08_world_2019_06_15_01_world.sql @@ -0,0 +1,59 @@ +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!50503 SET NAMES utf8mb4 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; + +DROP TABLE IF EXISTS `creature_template_resistance`; +CREATE TABLE IF NOT EXISTS `creature_template_resistance` ( + `CreatureID` INT(10) UNSIGNED NOT NULL, + `School` TINYINT(3) UNSIGNED NOT NULL, + `Resistance` SMALLINT(6) NOT NULL, + `VerifiedBuild` INT(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`CreatureID`, `School`) +) ENGINE=INNODB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `creature_template_spell`; +CREATE TABLE IF NOT EXISTS `creature_template_spell` ( + `CreatureID` INT(10) unsigned NOT NULL, + `Index` TINYINT(3) unsigned NOT NULL DEFAULT '0', + `Spell` INT(10) unsigned NOT NULL, + `VerifiedBuild` INT(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`CreatureID`, `Index`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; + +INSERT INTO creature_template_resistance SELECT entry, 1, resistance1, VerifiedBuild FROM creature_template WHERE resistance1 <> 0; +INSERT INTO creature_template_resistance SELECT entry, 2, resistance2, VerifiedBuild FROM creature_template WHERE resistance2 <> 0; +INSERT INTO creature_template_resistance SELECT entry, 3, resistance3, VerifiedBuild FROM creature_template WHERE resistance3 <> 0; +INSERT INTO creature_template_resistance SELECT entry, 4, resistance4, VerifiedBuild FROM creature_template WHERE resistance4 <> 0; +INSERT INTO creature_template_resistance SELECT entry, 5, resistance5, VerifiedBuild FROM creature_template WHERE resistance5 <> 0; +INSERT INTO creature_template_resistance SELECT entry, 6, resistance6, VerifiedBuild FROM creature_template WHERE resistance6 <> 0; + +INSERT INTO creature_template_spell SELECT entry, 0, spell1, VerifiedBuild FROM creature_template WHERE spell1 <> 0; +INSERT INTO creature_template_spell SELECT entry, 1, spell2, VerifiedBuild FROM creature_template WHERE spell2 <> 0; +INSERT INTO creature_template_spell SELECT entry, 2, spell3, VerifiedBuild FROM creature_template WHERE spell3 <> 0; +INSERT INTO creature_template_spell SELECT entry, 3, spell4, VerifiedBuild FROM creature_template WHERE spell4 <> 0; +INSERT INTO creature_template_spell SELECT entry, 4, spell5, VerifiedBuild FROM creature_template WHERE spell5 <> 0; +INSERT INTO creature_template_spell SELECT entry, 5, spell6, VerifiedBuild FROM creature_template WHERE spell6 <> 0; +INSERT INTO creature_template_spell SELECT entry, 6, spell7, VerifiedBuild FROM creature_template WHERE spell7 <> 0; +INSERT INTO creature_template_spell SELECT entry, 7, spell8, VerifiedBuild FROM creature_template WHERE spell8 <> 0; + +ALTER TABLE `creature_template` + DROP COLUMN `resistance1`, + DROP COLUMN `resistance2`, + DROP COLUMN `resistance3`, + DROP COLUMN `resistance4`, + DROP COLUMN `resistance5`, + DROP COLUMN `resistance6`, + DROP COLUMN `spell1`, + DROP COLUMN `spell2`, + DROP COLUMN `spell3`, + DROP COLUMN `spell4`, + DROP COLUMN `spell5`, + DROP COLUMN `spell6`, + DROP COLUMN `spell7`, + DROP COLUMN `spell8`;