diff --git a/sql/updates/world/4.3.4/2017_12_17_01_world_from_335_was_2017_12_16_03_world.sql b/sql/updates/world/4.3.4/2017_12_17_01_world_from_335_was_2017_12_16_03_world.sql new file mode 100644 index 00000000000..a5031c8e508 --- /dev/null +++ b/sql/updates/world/4.3.4/2017_12_17_01_world_from_335_was_2017_12_16_03_world.sql @@ -0,0 +1,3 @@ +-- +ALTER TABLE `creature_template` ADD COLUMN `spell_school_immune_mask` int(3) unsigned NOT NULL DEFAULT '0' AFTER `mechanic_immune_mask`; + diff --git a/src/server/database/Database/Implementation/WorldDatabase.cpp b/src/server/database/Database/Implementation/WorldDatabase.cpp index 611f63330df..e1943131e86 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.cpp +++ b/src/server/database/Database/Implementation/WorldDatabase.cpp @@ -76,7 +76,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_ID_BY_GUID, "SELECT id FROM waypoint_scripts WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_CREATURE, "DELETE FROM creature WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_COMMANDS, "SELECT name, permission, help FROM command", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, femaleName, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, exp_unk, faction, npcflag, speed_walk, speed_run, scale, rank, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_class, trainer_race, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, femaleName, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, exp_unk, faction, npcflag, speed_walk, speed_run, scale, rank, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_class, trainer_race, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_ITEM_TEMPLATE_BY_NAME, "SELECT entry FROM item_template WHERE name = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?", CONNECTION_SYNCH); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 21ca80f5c2b..043eb0afb79 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -492,6 +492,7 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/, UpdateMovementFlags(); LoadCreaturesAddon(); LoadMechanicTemplateImmunity(); + LoadSpellTemplateImmunity(); return true; } @@ -1875,6 +1876,26 @@ void Creature::LoadMechanicTemplateImmunity() } } +void Creature::LoadSpellTemplateImmunity() +{ + // uint32 max used for "spell id", the immunity system will not perform SpellInfo checks against invalid spells + // used so we know which immunities were loaded from template + static uint32 const placeholderSpellId = std::numeric_limits::max(); + + // unapply template immunities (in case we're updating entry) + for (uint8 i = SPELL_SCHOOL_NORMAL; i <= SPELL_SCHOOL_ARCANE; ++i) + ApplySpellImmune(placeholderSpellId, IMMUNITY_SCHOOL, i, false); + + // don't inherit immunities for hunter pets + if (GetOwnerGUID().IsPlayer() && IsHunterPet()) + return; + + if (uint8 mask = GetCreatureTemplate()->SpellSchoolImmuneMask) + for (uint8 i = SPELL_SCHOOL_NORMAL; i <= SPELL_SCHOOL_ARCANE; ++i) + if (mask & (1 << i)) + ApplySpellImmune(placeholderSpellId, IMMUNITY_SCHOOL, 1 << i, true); +} + bool Creature::IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster) const { if (!spellInfo) diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 27745d1d6b1..17b14eda1c8 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -154,6 +154,7 @@ struct TC_GAME_API CreatureTemplate uint32 movementId; bool RegenHealth; uint32 MechanicImmuneMask; + uint8 SpellSchoolImmuneMask; uint32 flags_extra; uint32 ScriptID; uint32 GetRandomValidModelId() const; @@ -497,6 +498,7 @@ class TC_GAME_API Creature : public Unit, public GridObject, public Ma bool isCanTrainingAndResetTalentsOf(Player* player) const; bool CanCreatureAttack(Unit const* victim, bool force = true) const; void LoadMechanicTemplateImmunity(); + void LoadSpellTemplateImmunity(); bool IsImmunedToSpell(SpellInfo const* spellInfo, Unit* caster) const override; bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index, Unit* caster) const override; bool isElite() const; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index ade3e07a82b..541ba6256a0 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -434,8 +434,8 @@ void ObjectMgr::LoadCreatureTemplates() "spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, " // 64 65 66 67 68 69 70 71 72 "InhabitType, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, " - // 73 74 75 76 77 78 - "RacialLeader, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template"); + // 73 74 75 76 77 78 79 + "RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName FROM creature_template"); if (!result) { @@ -532,12 +532,14 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields) creatureTemplate.ModArmor = fields[70].GetFloat(); creatureTemplate.ModDamage = fields[71].GetFloat(); creatureTemplate.ModExperience = fields[72].GetFloat(); - creatureTemplate.RacialLeader = fields[73].GetBool(); - creatureTemplate.movementId = fields[74].GetUInt32(); - creatureTemplate.RegenHealth = fields[75].GetBool(); - creatureTemplate.MechanicImmuneMask = fields[76].GetUInt32(); - creatureTemplate.flags_extra = fields[77].GetUInt32(); - creatureTemplate.ScriptID = GetScriptId(fields[78].GetCString()); + + creatureTemplate.RacialLeader = fields[73].GetBool(); + creatureTemplate.movementId = fields[74].GetUInt32(); + creatureTemplate.RegenHealth = fields[75].GetBool(); + creatureTemplate.MechanicImmuneMask = fields[76].GetUInt32(); + creatureTemplate.SpellSchoolImmuneMask = fields[77].GetUInt8(); + creatureTemplate.flags_extra = fields[78].GetUInt32(); + creatureTemplate.ScriptID = GetScriptId(fields[79].GetCString()); } void ObjectMgr::LoadCreatureTemplateAddons()