Merge pull request #33 from araxiaonline/feature/full-expansion-upgrade

Feature/full expansion upgrade
This commit is contained in:
Ben Carter
2025-08-23 20:58:39 -04:00
committed by GitHub
37 changed files with 15322 additions and 1580 deletions

View File

@@ -6,8 +6,8 @@
#
##########################################################
Appender.MythicPlusLog=2,5,0,mod-mythic-plus.log,w
Appender.MythicPlusConsole=1,5,0,"1 9 3 6 5 8"
Appender.MythicPlusLog=2,4,0,mod-mythic-plus.log,w
# Appender.MythicPlusConsole=1,5,0,"1 9 3 6 5 8"
Logger.module.MythicPlus=5,MythicPlusLog MythicPlusConsole
##########################################################
@@ -36,11 +36,13 @@ MythicPlus.EnableDeathLimits = 1
##########################################################
#
# Mythic+ Stat Modifiers By Difficuty
# Mythic+ Global Stat Modifiers By Difficulty
# - These values are used to adjust the difficulty of enemies and bosses base
# stats based on the difficulty of the dungeon.
# - Bosses will only receive their multiplier not the Dungeon multiplier to prevent multiplicative scaling.
# - These values are used to scale the difficulty of all dungeons across new difficulty modes.
#
# To scale individual instances you should use the mp_scale_factors table per instance to increase/reduce Modifiers
##########################################################
MythicPlus.Mythic.DungeonHealth = 1.25
@@ -103,7 +105,7 @@ MythicPlus.Ascendant.DeathAllowance = 15
# - These values are used to set the offset to where items per difficulty will map to.
# - Item drops in this mode use the original item entry + on offset to determine the new item entry reward.
# - This enables a fast lookup at loot drop time as it is just an addition operation.
# - If using the base geneated sql the settings below will map to it. If the offset is incorrect,
# - If using the base generated sql the settings below will map to it. If the offset is incorrect,
# the item will not be found and the original low level item will be rewarded.
#
##########################################################
@@ -112,8 +114,21 @@ MythicPlus.Mythic.ItemOffset = 20000000
MythicPlus.Legendary.ItemOffset = 21000000
MythicPlus.Ascendant.ItemOffset = 22000000
##########################################################
# Diminishing Returns
# - These values are used to set the diminishing returns for the different difficulties.
# - The diminishing returns are used to limit the amount of damage that can be done to a target.
# - The diminishing returns are based on the difficulty of the dungeon and the amount of damage that has been done to the target.
##########################################################
MythicPlus.DiminishingExponent = 0.96
MythicPlus.DiminishingThreshold.Mythic = 10000
MythicPlus.DiminishingThreshold.Legendary = 20000
MythicPlus.DiminishingThreshold.Ascendant = 40000
##############
# Scaling Adjusters
#############
MythicPlus.MeleeAttackPowerDampener = 800
MythicPlus.MeleeAttackPowerStart = 3000
MythicPlus.ElementalMeleeReducer = 0.50
MythicPlus.NormalEnemyReducer = 0.50
MythicPlus.NonCreatureSpellReducer = 0.50

View File

@@ -17,7 +17,7 @@ CREATE TABLE mp_player_instance_data (
guid INT UNSIGNED NOT NULL DEFAULT '0',
difficulty INT UNSIGNED NOT NULL DEFAULT '3',
mapId INT UNSIGNED NOT NULL,
instanceId INT UNSIGNED,
instanceId INT UNSIGNED NOT NULL DEFAULT '0',
deaths INT UNSIGNED NOT NULL,
PRIMARY KEY (guid, mapId, instanceId)

View File

@@ -4,12 +4,12 @@ DROP TABLE IF EXISTS mp_upgrade_ranks;
CREATE TABLE mp_upgrade_ranks (
upgradeRank INT UNSIGNED NOT NULL,
advancementId INT UNSIGNED NOT NULL,
materialId1 INT UNSIGNED NOT NULL,
materialId2 INT UNSIGNED NOT NULL,
materialId3 INT UNSIGNED NOT NULL,
materialCost1 INT UNSIGNED NOT NULL,
materialCost2 INT UNSIGNED NOT NULL,
materialCost3 INT UNSIGNED NOT NULL,
itemEntry1 INT UNSIGNED NOT NULL,
itemEntry2 INT UNSIGNED NOT NULL,
itemEntry3 INT UNSIGNED NOT NULL,
itemCost1 INT UNSIGNED NOT NULL,
itemCost2 INT UNSIGNED NOT NULL,
itemCost3 INT UNSIGNED NOT NULL,
minIncrease1 INT UNSIGNED NOT NULL,
maxIncrease1 INT UNSIGNED NOT NULL,
minIncrease2 INT UNSIGNED NOT NULL,
@@ -23,7 +23,7 @@ CREATE TABLE mp_upgrade_ranks (
PRIMARY KEY (upgradeRank, advancementId)
);
-- Used to allocate trade materials based on slot upgrades
-- Used to allocate trade materials to a category for fusion into new tradeskills
DROP TABLE IF EXISTS mp_material_types;
CREATE TABLE mp_material_types (
materialId INT UNSIGNED NOT NULL,
@@ -38,11 +38,10 @@ CREATE TABLE mp_material_types (
DROP TABLE IF EXISTS mp_scale_factors;
CREATE TABLE mp_scale_factors (
mapId SMALLINT NOT NULL,
dmg_bonus INT DEFAULT '100',
spell_bonus INT DEFAULT '100',
hp_bonus INT DEFAULT '100',
difficulty INT DEFAULT '100',
max INT DEFAULT '100',
melee_bonus FLOAT DEFAULT '1',
spell_bonus FLOAT DEFAULT '1',
heal_bonus FLOAT DEFAULT '1',
hp_bonus FLOAT DEFAULT '1',
difficulty FLOAT DEFAULT '1',
PRIMARY KEY (mapId)
);

View File

@@ -535,3 +535,5 @@ WHERE
'Eternal Mana', -- Central crafting material for arcane resistance gear.
'Saronite Animus' -- Rare drop from arcane-themed enemies in Icecrown Citadel.
);
REPLACE INTO mp_material_types (materialId, entry, name) VALUES (23, 911002, 'Veilstone');

View File

@@ -1,81 +1,152 @@
-- Last Update: 2021/08/15
-- Last Update: 2025/01/17
-- Description: Scale factors for Mythic+ dungeons used to normalize dungeon difficulty across expansions.
-- 1. Pre 60 level dungeons (13 dmg_bonus, 2 hp_bonus, max 23, difficulty 3)
INSERT INTO mp_scale_factors (mapId, dmg_bonus, spell_bonus, hp_bonus, difficulty, max)
-- 1. Pre 60 level dungeons (melee_bonus: 1.9-2.2, spell_bonus: 1.8-1.9, hp_bonus: 2, difficulty: 3)
INSERT INTO mp_scale_factors (mapId, melee_bonus, spell_bonus, heal_bonus, hp_bonus, difficulty)
VALUES
(389, 22, 19,2, 3, 23), -- Ragefire Chasm
(43, 19, 18,2, 3, 23), -- Wailing Caverns
(36, 19, 19,2, 3, 23), -- The Deadmines
(33, 19, 19,2, 3, 23), -- Shadowfang Keep
(34, 19, 19,2, 3, 23), -- The Stockade
(48, 19, 19,2, 3, 23), -- Blackfathom Deeps
(90, 19, 19,2, 3, 23), -- Gnomeregan
(47, 19, 19,2, 3, 23), -- Razorfen Kraul
(189, 19, 19,2, 3, 23), -- Scarlet Monastery (Graveyard)
(129, 19, 19,2, 3, 23), -- Razorfen Downs
(70, 19, 19,2, 3, 23), -- Uldaman
(209, 19, 19,2, 3, 23), -- Zul'Farrak
(349, 19, 19,2, 3, 23) -- Maraudon
ON DUPLICATE KEY UPDATE mapId = mapId;
(389, 2.2, 1.9, 1.9, 2, 3), -- Ragefire Chasm
(43, 1.9, 1.8, 1.8, 2, 3), -- Wailing Caverns
(36, 1.9, 1.9, 1.9, 2, 3), -- The Deadmines
(33, 1.9, 1.9, 1.9, 2, 3), -- Shadowfang Keep
(34, 1.9, 1.9, 1.9, 2, 3), -- The Stockade
(48, 1.9, 1.9, 1.9, 2, 3), -- Blackfathom Deeps
(90, 1.9, 1.9, 1.9, 2, 3), -- Gnomeregan
(47, 1.9, 1.9, 1.9, 2, 3), -- Razorfen Kraul
(189, 1.9, 1.9, 1.9, 2, 3), -- Scarlet Monastery (Graveyard)
(129, 1.9, 1.9, 1.9, 2, 3), -- Razorfen Downs
(70, 1.9, 1.9, 1.9, 2, 3), -- Uldaman
(209, 1.9, 1.9, 1.9, 2, 3), -- Zul'Farrak
(349, 1.9, 1.9, 1.9, 2, 3) -- Maraudon
AS new_values
ON DUPLICATE KEY UPDATE
melee_bonus = new_values.melee_bonus,
spell_bonus = new_values.spell_bonus,
heal_bonus = new_values.heal_bonus,
hp_bonus = new_values.hp_bonus,
difficulty = new_values.difficulty;
-- 2. Level 60 dungeons for classic (15 dmg_bonus, 3 hp_bonus, max 25, difficulty 3)
INSERT INTO mp_scale_factors (mapId, dmg_bonus, spell_bonus, hp_bonus, difficulty, max)
-- 2. Level 60 dungeons for classic (melee_bonus: 1.7, spell_bonus: 2.0, hp_bonus: 3, difficulty: 3)
INSERT INTO mp_scale_factors (mapId, melee_bonus, spell_bonus, heal_bonus, hp_bonus, difficulty)
VALUES
(289, 17, 20,3, 3, 25), -- Scholomance
(109, 17, 20,3, 3, 25), -- Sunken Temple
(329, 17, 20,3, 3, 25), -- Stratholme
(229, 17, 20,3, 3, 25), -- Blackrock Spire (Lower)
(230, 17, 20,3, 3, 25), -- Blackrock Spire (Upper)
(429, 17, 20,3, 3, 25), -- Dire Maul
(269, 17, 20,3, 3, 25) -- Temple of Atal'Hakkar
ON DUPLICATE KEY UPDATE mapId = mapId;
(289, 1.7, 2.0, 2.0, 3, 3), -- Scholomance
(109, 1.7, 2.0, 2.0, 3, 3), -- Sunken Temple
(329, 1.7, 2.0, 2.0, 3, 3), -- Stratholme
(229, 1.7, 2.0, 2.0, 3, 3), -- Blackrock Spire (Lower)
(230, 1.7, 2.0, 2.0, 3, 3), -- Blackrock Spire (Upper)
(429, 1.7, 2.0, 2.0, 3, 3), -- Dire Maul
(269, 1.7, 2.0, 2.0, 3, 3) -- Temple of Atal'Hakkar
AS new_values
ON DUPLICATE KEY UPDATE
melee_bonus = new_values.melee_bonus,
spell_bonus = new_values.spell_bonus,
heal_bonus = new_values.heal_bonus,
hp_bonus = new_values.hp_bonus,
difficulty = new_values.difficulty;
-- 3. Pre 70 dungeons in Burning Crusade (15 dmg_bonus, 4 hp_bonus, max 26, difficulty 3)
INSERT INTO mp_scale_factors (mapId, dmg_bonus, spell_bonus, hp_bonus, difficulty, max)
-- 3. Pre 70 dungeons in Burning Crusade (melee_bonus: 1.6, spell_bonus: 1.4, hp_bonus: 4, difficulty: 3)
INSERT INTO mp_scale_factors (mapId, melee_bonus, spell_bonus, heal_bonus, hp_bonus, difficulty)
VALUES
(542, 16, 14,4, 3, 26), -- Hellfire The Blood Furnace
(543, 16, 14,4, 3, 26), -- Hellfire Ramparts
(545, 16, 14,4, 3, 26), -- Coilfang Steamvaults
(546, 16, 14,4, 3, 26), -- Coilfang Reservoir: The Underbog
(547, 16, 14,4, 3, 26), -- Coilfang Reservoir: The Underbog
(557, 16, 14,4, 3, 26), -- Auchindoun: Mana-Tombs
(558, 16, 14,4, 3, 26), -- Auchindoun: Auchenai Crypts
(560, 16, 14,4, 3, 26) -- Caverns of Time: Old Hillsbrad Foothills
ON DUPLICATE KEY UPDATE mapId = mapId;
(542, 1.6, 1.4, 1.4, 4, 3), -- Hellfire The Blood Furnace
(543, 1.6, 1.4, 1.4, 4, 3), -- Hellfire Ramparts
(545, 1.6, 1.4, 1.4, 4, 3), -- Coilfang Steamvaults
(546, 1.6, 1.4, 1.4, 4, 3), -- Coilfang Reservoir: The Underbog
(547, 1.6, 1.4, 1.4, 4, 3), -- Coilfang Reservoir: The Slave Pens
(557, 1.6, 1.4, 1.4, 4, 3), -- Auchindoun: Mana-Tombs
(558, 1.6, 1.4, 1.4, 4, 3), -- Auchindoun: Auchenai Crypts
(560, 1.6, 1.4, 1.4, 4, 3) -- Caverns of Time: Old Hillsbrad Foothills
AS new_values
ON DUPLICATE KEY UPDATE
melee_bonus = new_values.melee_bonus,
spell_bonus = new_values.spell_bonus,
heal_bonus = new_values.heal_bonus,
hp_bonus = new_values.hp_bonus,
difficulty = new_values.difficulty;
-- 4. Level 70 dungeons in Burning Crusade (14 dmg_bonus, 4 hp_bonus, max 29, difficulty 3)
INSERT INTO mp_scale_factors (mapId, dmg_bonus, spell_bonus, hp_bonus, difficulty, max)
-- 4. Level 70 dungeons in Burning Crusade (melee_bonus: 1.4, spell_bonus: 1.3, hp_bonus: 4, difficulty: 3)
INSERT INTO mp_scale_factors (mapId, melee_bonus, spell_bonus, heal_bonus, hp_bonus, difficulty)
VALUES
(540, 14, 13,4, 3, 29), -- Shattered Halls
(556, 14, 13,4, 3, 29), -- Auchindoun: Sethekk Halls
(555, 14, 13,4, 3, 29), -- Auchindoun: Shadow Labyrinth
(553, 14, 13,4, 3, 29), -- Tempest Keep: The Botanica
(554, 14, 13,4, 3, 29), -- Tempest Keep: The Mechanar
(552, 14, 13,4, 3, 29), -- Tempest Keep: The Arcatraz
(585, 14, 13,4, 3, 29) -- Magisters' Terrace
ON DUPLICATE KEY UPDATE mapId = mapId;
(540, 1.4, 1.3, 1.3, 4, 3), -- Shattered Halls
(556, 1.4, 1.3, 1.3, 4, 3), -- Auchindoun: Sethekk Halls
(555, 1.4, 1.3, 1.3, 4, 3), -- Auchindoun: Shadow Labyrinth
(553, 1.4, 1.3, 1.3, 4, 3), -- Tempest Keep: The Botanica
(554, 1.4, 1.3, 1.3, 4, 3), -- Tempest Keep: The Mechanar
(552, 1.4, 1.3, 1.3, 4, 3), -- Tempest Keep: The Arcatraz
(585, 1.4, 1.3, 1.3, 4, 3) -- Magisters' Terrace
AS new_values
ON DUPLICATE KEY UPDATE
melee_bonus = new_values.melee_bonus,
spell_bonus = new_values.spell_bonus,
heal_bonus = new_values.heal_bonus,
hp_bonus = new_values.hp_bonus,
difficulty = new_values.difficulty;
-- 5. Pre 80 dungeons in Wrath of the Lich King (17 dmg_bonus, 3 hp_bonus, max 30, difficulty 3)
INSERT INTO mp_scale_factors (mapId, dmg_bonus, spell_bonus, hp_bonus, difficulty, max)
-- 5. Pre 80 dungeons in Wrath of the Lich King (melee_bonus: 1.9, spell_bonus: 1.2, hp_bonus: 3, difficulty: 3)
INSERT INTO mp_scale_factors (mapId, melee_bonus, spell_bonus, heal_bonus, hp_bonus, difficulty)
VALUES
(574, 19, 12,3, 3, 30), -- Utgarde Keep
(619, 19, 12,3, 3, 30), -- Ahn'kahet: The Old Kingdom
(576, 19, 12,3, 3, 30), -- The Nexus
(600, 19, 12,3, 3, 30), -- Drak'Tharon Keep
(601, 19, 12,3, 3, 30), -- Azjol-Nerub
(608, 19, 12,3, 3, 30) -- The Violet Hold
ON DUPLICATE KEY UPDATE mapId = mapId;
(574, 1.9, 1.2, 1.2, 3, 3), -- Utgarde Keep
(619, 1.9, 1.2, 1.2, 3, 3), -- Ahn'kahet: The Old Kingdom
(576, 1.9, 1.2, 1.2, 3, 3), -- The Nexus
(600, 1.9, 1.2, 1.2, 3, 3), -- Drak'Tharon Keep
(601, 1.9, 1.2, 1.2, 3, 3), -- Azjol-Nerub
(608, 1.9, 1.2, 1.2, 3, 3) -- The Violet Hold
AS new_values
ON DUPLICATE KEY UPDATE
melee_bonus = new_values.melee_bonus,
spell_bonus = new_values.spell_bonus,
heal_bonus = new_values.heal_bonus,
hp_bonus = new_values.hp_bonus,
difficulty = new_values.difficulty;
-- 6. Level 80 dungeons in Wrath of the Lich King (19 dmg_bonus, 4 hp_bonus, max 33, difficulty 3)
INSERT INTO mp_scale_factors (mapId, dmg_bonus, spell_bonus, hp_bonus, difficulty, max)
-- 6. Level 80 dungeons in Wrath of the Lich King (melee_bonus: 1.9, spell_bonus: 1.3, hp_bonus: 5, difficulty: 3)
INSERT INTO mp_scale_factors (mapId, melee_bonus, spell_bonus, heal_bonus, hp_bonus, difficulty)
VALUES
(595, 19, 13,5, 3, 33), -- The Culling of Stratholme
(604, 19, 13,5, 3, 33), -- Gundrak
(599, 19, 13,5, 3, 33), -- Halls of Stone
(602, 19, 13,5, 3, 33), -- Halls of Lightning
(578, 19, 13,5, 3, 33), -- The Oculus
(650, 19, 13,5, 3, 33), -- Trial of the Champion
(632, 19, 13,5, 3, 33), -- The Forge of Souls
(658, 19, 13,5, 3, 33), -- Pit of Saron
(668, 19, 13,5, 3, 33) -- Halls of Reflection
ON DUPLICATE KEY UPDATE mapId = mapId;
(595, 1.9, 1.3, 1.3, 5, 3), -- The Culling of Stratholme
(604, 1.9, 1.3, 1.3, 5, 3), -- Gundrak
(599, 1.9, 1.3, 1.3, 5, 3), -- Halls of Stone
(602, 1.9, 1.3, 1.3, 5, 3), -- Halls of Lightning
(578, 1.9, 1.3, 1.3, 5, 3), -- The Oculus
(650, 1.9, 1.3, 1.3, 5, 3), -- Trial of the Champion
(632, 1.9, 1.3, 1.3, 5, 3), -- The Forge of Souls
(658, 1.9, 1.3, 1.3, 5, 3), -- Pit of Saron
(668, 1.9, 1.3, 1.3, 5, 3) -- Halls of Reflection
AS new_values
ON DUPLICATE KEY UPDATE
melee_bonus = new_values.melee_bonus,
spell_bonus = new_values.spell_bonus,
heal_bonus = new_values.heal_bonus,
hp_bonus = new_values.hp_bonus,
difficulty = new_values.difficulty;
-- 7. Raid instances (melee_bonus: 2.6, spell_bonus: 2.0, heal_bonus: 1.6, hp_bonus: 3, difficulty: 3)
INSERT INTO mp_scale_factors (mapId, melee_bonus, spell_bonus, heal_bonus, hp_bonus, difficulty)
VALUES
(169, 2.6, 2.0, 1.6, 3, 3), -- Emerald Dream
(249, 2.8, 1.6, 1.6, 3, 3), -- Onyxia's Lair
(309, 2.0, 1.3, 1.6, 3, 3), -- Zul'Gurub
(409, 2.2, 1.4, 1.6, 3, 3), -- Molten Core
(469, 2.6, 2.0, 1.6, 3, 3), -- Blackwing Lair
(509, 2.6, 2.0, 1.6, 3, 3), -- Ruins of Ahn'Qiraj
(531, 2.6, 2.0, 1.6, 3, 3), -- Ahn'Qiraj Temple
(532, 2.6, 2.0, 1.6, 3, 3), -- Karazhan
(533, 2.0, 1.8, 1.6, 3, 3), -- Naxxramas
(534, 2.6, 2.0, 1.6, 3, 3), -- The Battle for Mount Hyjal
(544, 2.0, 2.0, 1.6, 3, 3), -- Magtheridon's Lair
(548, 2.6, 2.0, 1.6, 3, 3), -- Coilfang: Serpentshrine Cavern
(550, 2.6, 2.0, 1.6, 3, 3), -- Tempest Keep
(564, 2.9, 2.8, 1.6, 3, 3), -- Black Temple
(565, 2.6, 2.0, 1.6, 3, 3), -- Gruul's Lair
(568, 2.6, 2.0, 1.6, 3, 3), -- Zul'Aman
(580, 2.6, 2.0, 1.6, 3, 3), -- The Sunwell
(603, 2.6, 2.0, 1.6, 3, 3), -- Ulduar
(615, 2.6, 2.0, 1.6, 3, 3), -- The Obsidian Sanctum
(616, 2.6, 2.0, 1.6, 3, 3), -- The Eye of Eternity
(624, 2.6, 2.0, 1.6, 3, 3), -- Vault of Archavon
(631, 2.8, 2.4, 1.6, 5, 3), -- Icecrown Citadel
(649, 3.0, 2.3, 1.6, 4, 3), -- Trial of the Crusader
(724, 2.68, 2.0, 1.6, 3, 3) -- The Ruby Sanctum
AS new_values
ON DUPLICATE KEY UPDATE
melee_bonus = new_values.melee_bonus,
spell_bonus = new_values.spell_bonus,
heal_bonus = new_values.heal_bonus,
hp_bonus = new_values.hp_bonus,
difficulty = new_values.difficulty;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
REPLACE INTO acore_world.spell_script_names (spell_id, ScriptName) VALUES
('80000001','spell_mp_titans_strength_aura'),
('80000002','spell_mp_steel_forged_aura'),
('80000003','spell_mp_celestial_grace_aura'),
('80000004','spell_mp_forbidden_knowledge_aura'),
('80000005','spell_mp_spectral_reflexes_aura'),
('80000006','spell_mp_eldritch_barrier_aura'),
('80000007','spell_mp_hellfire_shielding_aura'),
('80000008','spell_mp_primal_endurance_aura'),
('80000009','spell_mp_lichs_bane_aura'),
('80000010','spell_mp_glacial_fortress_aura');
DELETE FROM `spell_dbc` WHERE `ID` IN (80000001, 80000002, 80000003, 80000004, 80000005, 80000006, 80000007, 80000008, 80000009, 80000010);
INSERT INTO `spell_dbc` (`ID`, `Attributes`, `AttributesEx`, `DispelType`, `Effect_1`, `EffectAura_1`,`EffectMiscValue_1`, `Name_Lang_enUS`, `Description_Lang_enUS`) VALUES
(80000001, 192, 0, 0, 6, 29, 0, 'Titan\'s Strength', 'Empowers you with the legendary strength of the Titans, enhancing your physical prowess.'),
(80000002, 192, 0, 0, 6, 29, 2, 'Steel Forged', 'Transforms your skin into an impenetrable steel armor, deflecting all but the mightiest blows.'),
(80000003, 192, 0, 0, 6, 29, 4,'Celestial Grace', 'Blessed with celestial wisdom, you inspire and uplift the spirits of allies around you.'),
(80000004, 192, 0, 0, 6, 29, 3,'Forbidden Knowledge', 'You have delved into the forbidden secrets of Azeroth, unlocking arcane mysteries and hidden powers.'),
(80000005, 192, 0, 0, 6, 29, 1,'Spectral Reflexes', 'You become a phantom, mastering the art of the blade and dagger with unparalleled precision.'),
(80000006, 192, 0, 0, 6, 22, 64,'Eldritch Barrier', 'Erects an eldritch barrier that halts arcane forces in their tracks, shielding you from magical harm.'),
(80000007, 192, 0, 0, 6, 22, 4,'Hellfire Shielding', 'You have learned to withstand the infernal flames of hell, emerging unscathed from fiery assaults.'),
(80000008, 192, 0, 0, 6, 22, 8,'Primal Endurance', 'Your endurance has been toughened to resist pestilence and plague, rendering you immune to their effects.'),
(80000009, 192, 0, 0, 6, 22, 32, 'Lich\'s Bane', 'You possess the knowledge to counter the shadows of the undead, protecting your flesh from their dark touch.'),
(80000010, 192, 0, 0, 6, 22, 16, 'Glacial Fortress', 'You can withstand temperatures far below freezing that no mere mortal can endure, encased in a glacial fortress.');

View File

@@ -0,0 +1,97 @@
-- Common dice for stat roles
DELETE FROM `item_template` WHERE (`entry` = 911000);
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
(911000, 15, 4, -1, 'Ancient Dice', 52015, 3, 163840, 0, 1, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 'Ancient dice from an unknown origin, maybe someone or something is looking for them.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0);
-- Rare Item for reseting AA points
DELETE FROM `item_template` WHERE (`entry` = 911001);
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
(911001, 0, 4, -1, 'Onyx Spike Relic', 33851, 4, 0, 0, 0, 0, 10000000, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1000, 0, 0, 65082, 0, 10, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, 'This relic has a dangerous aura. Using this seems fatal', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0);
-- Legendary Veilstone for end game stat upgrades
DELETE FROM `item_template` WHERE (`entry` = 911002);
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
(911002, 15, 4, -1, 'Veilstone', 270622, 5, 0, 0, 1, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1000, 1000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, 'A gem that holds together the boundary between dimensions.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0);
-- mythical fusion items
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911003, 7, 1, -1, 'Fused Ore', '', 270620, 3, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 1, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911004, 7, 1, -1, 'Moltenheart Core', 'Mythical ore from high level fusion', 270608, 4, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 1, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911005, 7, 7, -1, 'Fused Cloth', '', 270613, 3, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 7, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911006, 7, 7, -1, 'Soulthread Shroud', 'Mythical cloth from high level fusion', 270601, 4, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 7, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911007, 7, 8, -1, 'Fused Leather', '', 270619, 3, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 8, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911008, 7, 8, -1, 'Ashwild Pelt', 'Mythical leather from high level fusion', 270607, 4, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 8, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911009, 7, 3, -1, 'Fused Compound', '', 270610, 3, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 3, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911010, 7, 3, -1, 'Elixir of Chaos', 'Mythical alchemy component from high level fusion', 270599, 4, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 3, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911011, 7, 4, -1, 'Fused Gem', '', 270616, 3, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 4, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911012, 7, 4, -1, 'Starfused Prism', 'Mythical gemstone from high level fusion', 270604, 4, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 4, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911013, 7, 0, -1, 'Fused Essence', '', 270615, 3, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 0, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911014, 7, 0, -1, 'Crystalline Echo', 'Mythical enchanting component from high level fusion', 270603, 4, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 0, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911015, 7, 0, -1, 'Fused Frostshard', 'Artifact that emits extreme cold', 270617, 3, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 0, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911016, 7, 0, -1, 'Everfrost Crystal', 'Mythical frost component from high level fusion', 270605, 4, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 0, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911017, 7, 0, -1, 'Fused Infernostone', 'Artifact that emits extreme heat', 270618, 3, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 0, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911018, 7, 0, -1, 'Blazebound Ember', 'Mythical fire component from high level fusion', 270606, 4, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 0, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911019, 7, 0, -1, 'Fused Arcane Crystal', 'Artifact of immense arcane power',270611, 3, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 0, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911020, 7, 0, -1, 'Spellfire Prism', 'Mythical arcane component from high level fusion', 270600, 4, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 0, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911021, 7, 0, -1, 'Fused Shadow Crystal', 'Artifact radiating dark energy', 270621, 3, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 0, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911022, 7, 0, -1, 'Eternal Shadow Crystal', 'Mythical shadow component from high level fusion',270609, 4, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 0, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911023, 7, 0, -1, 'Fused Earth Shard','Artifact emitting dangerously poisonous vapors',270614, 3, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 0, 12340);
REPLACE INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `Description`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `bonding`, `Material`, `VerifiedBuild`) VALUES (911024, 7, 0, -1, 'Verdant Stoneheart', 'Mythical earth component from high level fusion',270602, 4, 262144, 0, 1, 0, 0, 0, -1, -1, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 1, 0, 12340);
-- Flavor Text
DELETE FROM `item_template` WHERE (`entry` = 2595);
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
(2595, 0, 5, -1, 'Jug of Badlands Bourbon', 7921, 1, 0, 0, 1, 50000, 500, 0, -1, -1, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11009, 0, -1, -1, 0, 59, 1000, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 'Mick''s Favorite Drink', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 12340);
-- Currency
DELETE FROM `item_template` WHERE (`entry` = 911050);
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
(911050, 10, 0, -1, 'Badge of the Void', 270626, 4, 2048, 0, 1, 0, 0, 0, -1, -1, 80, 80, 0, 0, 0, 0, 0, 0, 0, 0, 500000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8192, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0);
DELETE FROM `item_template` WHERE (`entry` = 911051);
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
(911051, 10, 0, -1, 'Emblem of Undeath', 270628, 4, 2048, 0, 1, 0, 0, 0, -1, -1, 80, 80, 0, 0, 0, 0, 0, 0, 0, 0, 500000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8192, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0);
DELETE FROM `item_template` WHERE (`entry` = 911052);
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
(911052, 10, 0, -1, 'Emblem of Chaos', 270623, 4, 2048, 0, 1, 0, 0, 0, -1, -1, 80, 80, 0, 0, 0, 0, 0, 0, 0, 0, 500000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8192, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0);
DELETE FROM `item_template` WHERE (`entry` = 911053);
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
(911053, 10, 0, -1, 'Emblem Of Veil', 270632, 4, 2048, 0, 1, 0, 0, 0, -1, -1, 80, 80, 0, 0, 0, 0, 0, 0, 0, 0, 500000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8192, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0);
DELETE FROM `item_template` WHERE (`entry` = 911054);
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
(911054, 10, 0, -1, 'Mythic Badge', 270629, 4, 2048, 0, 1, 0, 0, 0, -1, -1, 80, 80, 0, 0, 0, 0, 0, 0, 0, 0, 500000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8192, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0);
-- Random loot where greens would drop.
DELETE FROM `item_template` WHERE (`entry` = 911100);
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
(911100, 15, 0, -1, 'Shadowy Remains', 270634, 2, 4, 0, 1, 50000000, 12, 0, 32767, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 12340);
DELETE FROM `item_template` WHERE (`entry` = 911101);
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
(911101, 15, 0, -1, 'Veil Fragments', 270635, 2, 0, 0, 1, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 500, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1000, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, 'valuable fragments of a veil stone.', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, '', 0, 0, 0, 0, 0, 0);
-- Loot Templates
DELETE FROM `item_loot_template` WHERE (`Entry` = 911100);
INSERT INTO `item_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
(911100, 33447, 0, 20, 0, 1, 0, 1, 3, 'Runic Healing Potion'),
(911100, 33448, 0, 20, 0, 1, 0, 1, 3, 'Runic Mana Potion'),
(911100, 910001, 0, 10, 0, 1, 0, 1, 2, 'Araxia Tokens'),
(911100, 911000, 0, 10, 0, 1, 0, 1, 3, 'Ancient Dice'),
(911100, 911003, 0, 0.5, 0, 1, 0, 1, 1, 'Fused Ore'),
(911100, 911005, 0, 0.5, 0, 1, 0, 1, 1, 'Fused Cloth'),
(911100, 911007, 0, 0.5, 0, 1, 0, 1, 1, 'Fused Leather'),
(911100, 911009, 0, 0.5, 0, 1, 0, 1, 1, 'Fused Compound'),
(911100, 911011, 0, 0.5, 0, 1, 0, 1, 1, 'Fused Gem'),
(911100, 911013, 0, 0.5, 0, 1, 0, 1, 1, 'Fused Essence'),
(911100, 911015, 0, 0.5, 0, 1, 0, 1, 1, 'Fused Frostshard'),
(911100, 911017, 0, 0.5, 0, 1, 0, 1, 1, 'Fused Infernostone'),
(911100, 911019, 0, 0.5, 0, 1, 0, 1, 1, 'Fused Arcane Crystal'),
(911100, 911021, 0, 0.5, 0, 1, 0, 1, 1, 'Fused Shadow Crystal'),
(911100, 911023, 0, 0.5, 0, 1, 0, 1, 1, 'Fused Earth Shard'),
(911100, 911101, 0, 35.5, 0, 1, 0, 1, 5, 'Veil Fragments');

View File

@@ -0,0 +1,15 @@
REPLACE INTO
spell_ranks (first_spell_id, spell_id, `rank`)
VALUES
(150000, 150000, 1), (150000, 150011, 2), -- Ore Fusion
(150001, 150001, 1), (150001, 150012, 2), -- Cloth Fusion
(150002, 150002, 1), (150002, 150013, 2), -- Leather Fusion
(150003, 150003, 1), (150003, 150014, 2), -- Alchemy Fusion
(150004, 150004, 1), (150004, 150015, 2), -- Gem Fusion
(150005, 150005, 1), (150005, 150016, 2), -- Essence Fusion
(150006, 150006, 1), (150006, 150017, 2), -- Cold Fusion
(150007, 150007, 1), (150007, 150018, 2), -- Flame Fusion
(150008, 150008, 1), (150008, 150019, 2), -- Arcane Fusion
(150009, 150009, 1), (150009, 150020, 2), -- Dark Fusion
(150010, 150010, 1), (150010, 150021, 2) -- Earth Fusion
;

View File

@@ -0,0 +1,201 @@
-- Mick Ashwild
REPLACE INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES
(9500561, 0, 0, 0, 0, 0, 'Mick Ashwild', 'The Mug', NULL, 0, 85, 85, 2, 35, 1, 1, 1.14286, 1, 1, 20, 1, 0, 0, 1.35, 2000, 2000, 1, 1, 1, 33024, 2048, 0, 0, 0, 0, 0, 0, 7, 32, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 0.7, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 12340);
DELETE FROM `creature_template_model` WHERE (`CreatureID` = 9500561);
INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES
(9500561, 0, 9500561, 1, 1, 12340);
DELETE FROM `creature_equip_template` WHERE (`CreatureID` = 9500561);
INSERT INTO `creature_equip_template` (`CreatureID`, `ID`, `ItemID1`, `ItemID2`, `ItemID3`, `VerifiedBuild`) VALUES
(9500561, 1, 4090, 0, 0, 0);
-- Thorin Firehand
DELETE FROM `creature_template` WHERE (`entry` = 9500562);
INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES
(9500562, 0, 0, 0, 0, 0, 'Thorin Firehand', 'The Hammer', NULL, 0, 85, 85, 2, 35, 1, 0.85, 1.14286, 1, 1, 1, 1.1, 3, 0, 2, 1, 0, 2, 2.5, 1, 33024, 2048, 0, 0, 0, 0, 0, 0, 7, 32, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 3, 2, 10, 1, 0, 0, 1, 0, 0, 0, '', 0);
DELETE FROM `creature_equip_template` WHERE (`CreatureID` = 9500562);
INSERT INTO `creature_equip_template` (`CreatureID`, `ID`, `ItemID1`, `ItemID2`, `ItemID3`, `VerifiedBuild`) VALUES
(9500562, 1, 11684, 2565, 0, 0);
DELETE FROM `creature_template_model` WHERE (`CreatureID` = 9500562);
INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES
(9500562, 0, 9500562, 1, 1, 12340);
-- Elowyn Threadbinder
DELETE FROM `creature_template` WHERE (`entry` = 9500563);
INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES
(9500563, 0, 0, 0, 0, 0, 'Elowyn Threadbinder', 'Mystic Artisan', NULL, 0, 85, 85, 0, 35, 1, 1, 1.14286, 1, 1, 30, 1, 3, 0, 1, 2000, 2000, 1, 1, 8, 33024, 2048, 0, 0, 0, 0, 0, 0, 7, 32, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 0);
DELETE FROM `creature_template_model` WHERE (`CreatureID` = 9500563);
INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES
(9500563, 0, 9500563, 1, 1, 12340);
-- Shivey
DELETE FROM `creature_template` WHERE (`entry` = 9500564);
INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES
(9500564, 0, 0, 0, 0, 0, 'Shivey', 'Professional Arson', NULL, 0, 85, 85, 2, 35, 1, 1, 1.14286, 1, 1, 1, 1, 3, 0, 1, 2000, 2500, 1, 1, 4, 33024, 2048, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 0);
DELETE FROM `creature_equip_template` WHERE (`CreatureID` = 9500564);
INSERT INTO `creature_equip_template` (`CreatureID`, `ID`, `ItemID1`, `ItemID2`, `ItemID3`, `VerifiedBuild`) VALUES
(9500564, 1, 28648, 2200, 0, 0);
DELETE FROM `creature_template_model` WHERE (`CreatureID` = 9500564);
INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES
(9500564, 0, 9500564, 1, 1, 0);
-- Steve
DELETE FROM `creature_template` WHERE (`entry` = 9500565);
INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES
(9500565, 0, 0, 0, 0, 0, 'Steve', 'The Indestructible', NULL, 0, 85, 85, 2, 35, 1, 1, 1.14286, 1, 1, 1, 1.25, 3, 0, 100, 2000, 2500, 1, 1, 1, 33024, 2048, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 100, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 0);
DELETE FROM `creature_equip_template` WHERE (`CreatureID` = 9500565);
INSERT INTO `creature_equip_template` (`CreatureID`, `ID`, `ItemID1`, `ItemID2`, `ItemID3`, `VerifiedBuild`) VALUES
(9500565, 1, 51869, 38462, 0, 0);
DELETE FROM `creature_template_model` WHERE (`CreatureID` = 9500565);
INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES
(9500565, 0, 9500565, 1.25, 1, 0);
-- Vaeric
DELETE FROM `creature_template` WHERE (`entry` = 9500566);
INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES
(9500566, 0, 0, 0, 0, 0, 'Vaeric Bloodbane', '', NULL, 0, 85, 85, 2, 35, 1, 1, 1.14286, 1, 1, 1, 1.25, 3, 0, 100, 2000, 2500, 1, 1, 1, 33024, 2048, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 100, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 0);
DELETE FROM `creature_equip_template` WHERE (`CreatureID` = 9500566);
INSERT INTO `creature_equip_template` (`CreatureID`, `ID`, `ItemID1`, `ItemID2`, `ItemID3`, `VerifiedBuild`) VALUES
(9500566, 1, 38632, 0, 0, 0);
DELETE FROM `creature_template_model` WHERE (`CreatureID` = 9500566);
INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES
(9500566, 0, 9500566, 1.25, 1, 0);
-- Agatha
DELETE FROM `creature_template` WHERE (`entry` = 9500567);
INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES
(9500567, 0, 0, 0, 0, 0, 'Agatha Veil', 'The Wise', NULL, 0, 85, 85, 2, 35, 1, 1, 1.14286, 1, 1, 1, 1.25, 3, 0, 100, 2000, 2500, 1, 1, 1, 33024, 2048, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 100, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 0);
DELETE FROM `creature_template_model` WHERE (`CreatureID` = 9500567);
INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES
(9500567, 0, 9500567, 1.25, 1, 0);
-- Sylvia
DELETE FROM `creature_template` WHERE (`entry` = 9500568);
INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES
(9500568, 0, 0, 0, 0, 0, 'Sylvia Steelheart', 'Battle Maiden', NULL, 0, 85, 85, 2, 35, 1, 1, 1.14286, 1, 1, 1, 1.25, 3, 0, 100, 2000, 2500, 1, 1, 1, 33024, 2048, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 100, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 0);
DELETE FROM `creature_equip_template` WHERE (`CreatureID` = 9500568);
INSERT INTO `creature_equip_template` (`CreatureID`, `ID`, `ItemID1`, `ItemID2`, `ItemID3`, `VerifiedBuild`) VALUES
(9500568, 1, 38200, 16887, 0, 0);
DELETE FROM `creature_template_model` WHERE (`CreatureID` = 9500568);
INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES
(9500568, 0, 9500568, 1.25, 1, 0);
-- Model Info Updates
REPLACE INTO creature_model_info (DisplayID, BoundingRadius, CombatReach, Gender, DisplayID_Other_Gender)
VALUES (9500561, 0.35, 1.25, 0, 0);
REPLACE INTO creature_model_info (DisplayID, BoundingRadius, CombatReach, Gender, DisplayID_Other_Gender)
SELECT 9500562, BoundingRadius, CombatReach, Gender, DisplayID_Other_Gender
FROM creature_model_info
WHERE DisplayID = 9500561;
REPLACE INTO creature_model_info (DisplayID, BoundingRadius, CombatReach, Gender, DisplayID_Other_Gender)
SELECT 9500563, BoundingRadius, CombatReach, Gender, DisplayID_Other_Gender
FROM creature_model_info
WHERE DisplayID = 9500561;
REPLACE INTO creature_model_info (DisplayID, BoundingRadius, CombatReach, Gender, DisplayID_Other_Gender)
SELECT 9500564, BoundingRadius, CombatReach, Gender, DisplayID_Other_Gender
FROM creature_model_info
WHERE DisplayID = 9500561;
REPLACE INTO creature_model_info (DisplayID, BoundingRadius, CombatReach, Gender, DisplayID_Other_Gender)
VALUES (9500565, 0.35, 1.25, 0, 0);
REPLACE INTO creature_model_info (DisplayID, BoundingRadius, CombatReach, Gender, DisplayID_Other_Gender)
VALUES (9500566, 0.35, 1.25, 0, 0);
REPLACE INTO creature_model_info (DisplayID, BoundingRadius, CombatReach, Gender, DisplayID_Other_Gender)
VALUES (9500567, 0.35, 1.25, 1, 0);
-- Supporting Cast Spawns
-- Agatha
DELETE FROM `creature` WHERE (`id1` = 9500567);
INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`, `CreateObject`, `Comment`) VALUES
(9001011, 9500567, 0, 0, 530, 0, 0, 1, 1, 0, -1990.6, 5214.14, -44.0752, 0.978763, 300, 0, 0, 1333900, 0, 0, 0, 0, 0, '', NULL, 0, NULL),
(9001014, 9500567, 0, 0, 571, 0, 0, 1, 1, 0, 5804.06, 639.865, 609.886, 5.98164, 300, 0, 0, 1333900, 0, 0, 0, 0, 0, '', NULL, 0, NULL);
-- Vaeric
DELETE FROM `creature` WHERE (`id1` = 9500566);
INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`, `CreateObject`, `Comment`) VALUES
(9001013, 9500566, 0, 0, 530, 0, 0, 1, 1, 1, -1989.96, 5225.28, -44.6008, 5.71627, 300, 0, 0, 1333900, 0, 0, 0, 0, 0, '', NULL, 0, NULL),
(9001015, 9500566, 0, 0, 571, 0, 0, 1, 1, 1, 5826.64, 674.772, 609.885, 5.53385, 300, 0, 0, 1333900, 0, 0, 0, 0, 0, '', NULL, 0, NULL);
-- Slyvia
DELETE FROM `creature` WHERE (`id1` = 9500568);
INSERT INTO `creature` (`guid`, `id1`, `id2`, `id3`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `VerifiedBuild`, `CreateObject`, `Comment`) VALUES
(9001010, 9500568, 0, 0, 530, 0, 0, 1, 1, 1, -1994.38, 5219.83, -44.2111, 0.597826, 300, 0, 0, 1333900, 0, 0, 0, 0, 0, '', NULL, 0, NULL),
(9001016, 9500568, 0, 0, 571, 0, 0, 1, 1, 1, 5831.89, 678.204, 609.885, 5.0846, 300, 0, 0, 1333900, 0, 0, 0, 0, 0, '', NULL, 0, NULL);
-- Gossip Texts
-- Vaeric Starter Intro
DELETE FROM `npc_text` WHERE (`ID` = 60566);
INSERT INTO `npc_text` (`ID`, `text0_0`, `text0_1`, `BroadcastTextID0`, `lang0`, `Probability0`, `em0_0`, `em0_1`, `em0_2`, `em0_3`, `em0_4`, `em0_5`, `text1_0`, `text1_1`, `BroadcastTextID1`, `lang1`, `Probability1`, `em1_0`, `em1_1`, `em1_2`, `em1_3`, `em1_4`, `em1_5`, `text2_0`, `text2_1`, `BroadcastTextID2`, `lang2`, `Probability2`, `em2_0`, `em2_1`, `em2_2`, `em2_3`, `em2_4`, `em2_5`, `text3_0`, `text3_1`, `BroadcastTextID3`, `lang3`, `Probability3`, `em3_0`, `em3_1`, `em3_2`, `em3_3`, `em3_4`, `em3_5`, `text4_0`, `text4_1`, `BroadcastTextID4`, `lang4`, `Probability4`, `em4_0`, `em4_1`, `em4_2`, `em4_3`, `em4_4`, `em4_5`, `text5_0`, `text5_1`, `BroadcastTextID5`, `lang5`, `Probability5`, `em5_0`, `em5_1`, `em5_2`, `em5_3`, `em5_4`, `em5_5`, `text6_0`, `text6_1`, `BroadcastTextID6`, `lang6`, `Probability6`, `em6_0`, `em6_1`, `em6_2`, `em6_3`, `em6_4`, `em6_5`, `text7_0`, `text7_1`, `BroadcastTextID7`, `lang7`, `Probability7`, `em7_0`, `em7_1`, `em7_2`, `em7_3`, `em7_4`, `em7_5`, `VerifiedBuild`) VALUES
(60566, 'The Lich King is dead... but his shadow endures.
You led the final blow against Arthas.
You have strength but can grow stronger yet still.
Fragments of his power linger... You must stop KelThuzad.
$n, Return to the battles you thought were finished.
Face the darkness reborn. And return those once dead back
to dust. While we search for a way to end this.
How can I aid you?', '', 0, 0, 0, 1, 1, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
-- Agatha Starter Intro
DELETE FROM `npc_text` WHERE (`ID` = 60567);
INSERT INTO `npc_text` (`ID`, `text0_0`, `text0_1`, `BroadcastTextID0`, `lang0`, `Probability0`, `em0_0`, `em0_1`, `em0_2`, `em0_3`, `em0_4`, `em0_5`, `text1_0`, `text1_1`, `BroadcastTextID1`, `lang1`, `Probability1`, `em1_0`, `em1_1`, `em1_2`, `em1_3`, `em1_4`, `em1_5`, `text2_0`, `text2_1`, `BroadcastTextID2`, `lang2`, `Probability2`, `em2_0`, `em2_1`, `em2_2`, `em2_3`, `em2_4`, `em2_5`, `text3_0`, `text3_1`, `BroadcastTextID3`, `lang3`, `Probability3`, `em3_0`, `em3_1`, `em3_2`, `em3_3`, `em3_4`, `em3_5`, `text4_0`, `text4_1`, `BroadcastTextID4`, `lang4`, `Probability4`, `em4_0`, `em4_1`, `em4_2`, `em4_3`, `em4_4`, `em4_5`, `text5_0`, `text5_1`, `BroadcastTextID5`, `lang5`, `Probability5`, `em5_0`, `em5_1`, `em5_2`, `em5_3`, `em5_4`, `em5_5`, `text6_0`, `text6_1`, `BroadcastTextID6`, `lang6`, `Probability6`, `em6_0`, `em6_1`, `em6_2`, `em6_3`, `em6_4`, `em6_5`, `text7_0`, `text7_1`, `BroadcastTextID7`, `lang7`, `Probability7`, `em7_0`, `em7_1`, `em7_2`, `em7_3`, `em7_4`, `em7_5`, `VerifiedBuild`) VALUES
(60567, 'Kel\\Thuzad continues to tear through my domain.
He must be erased from existence.
I offer my knowledge —
ancient powers... forbidden relics...
to strengthen your kind against the unyielding shadows now pouring from my realm into yours.
Be quick, what do you need?', 'Kel\\Thuzad continues to tear through my domain.
He must be erased from existence.
I offer my knowledge —
ancient powers... forbidden relics...
to strengthen your kind against the unyielding shadows now pouring from my realm into yours.
Be quick, what do you need?', 0, 0, 0, 1, 1, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
DELETE FROM `npc_text` WHERE (`ID` = 60568);
INSERT INTO `npc_text` (`ID`, `text0_0`, `text0_1`, `BroadcastTextID0`, `lang0`, `Probability0`, `em0_0`, `em0_1`, `em0_2`, `em0_3`, `em0_4`, `em0_5`, `text1_0`, `text1_1`, `BroadcastTextID1`, `lang1`, `Probability1`, `em1_0`, `em1_1`, `em1_2`, `em1_3`, `em1_4`, `em1_5`, `text2_0`, `text2_1`, `BroadcastTextID2`, `lang2`, `Probability2`, `em2_0`, `em2_1`, `em2_2`, `em2_3`, `em2_4`, `em2_5`, `text3_0`, `text3_1`, `BroadcastTextID3`, `lang3`, `Probability3`, `em3_0`, `em3_1`, `em3_2`, `em3_3`, `em3_4`, `em3_5`, `text4_0`, `text4_1`, `BroadcastTextID4`, `lang4`, `Probability4`, `em4_0`, `em4_1`, `em4_2`, `em4_3`, `em4_4`, `em4_5`, `text5_0`, `text5_1`, `BroadcastTextID5`, `lang5`, `Probability5`, `em5_0`, `em5_1`, `em5_2`, `em5_3`, `em5_4`, `em5_5`, `text6_0`, `text6_1`, `BroadcastTextID6`, `lang6`, `Probability6`, `em6_0`, `em6_1`, `em6_2`, `em6_3`, `em6_4`, `em6_5`, `text7_0`, `text7_1`, `BroadcastTextID7`, `lang7`, `Probability7`, `em7_0`, `em7_1`, `em7_2`, `em7_3`, `em7_4`, `em7_5`, `VerifiedBuild`) VALUES
(60568, 'You have bothered my Spirit Healer Goddess enough.
Besides, Vaeric trusts based on your deeds and I trust Vaeric.
I learned enough from Agatha to keep that face of yours upright — ancient powers... blah blah...
Just bring me some dices and fused materials and we can go from there.
', 'You have bothered my Spirit Healer Goddess enough.
Besides, Vaeric trusts based on your deeds and I trust Vaeric.
I learned enough from Agatha to keep that face of yours upright — ancient powers... blah blah...
Just bring me some dices and fused materials and we can go from there.
', 0, 0, 0, 1, 1, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL);

View File

@@ -0,0 +1,6 @@
UPDATE creature_template_npcbot_wander_nodes
SET maxlevel = 85
WHERE maxlevel = 80;
UPDATE battleground_template SET MaxLvl = 85 where MaxLvl = 80;

View File

@@ -0,0 +1,11 @@
-- Supporting Cast Environment items
REPLACE INTO acore_world.gameobject (guid, id, map, zoneId, areaId, spawnMask, phaseMask, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, ScriptName, VerifiedBuild, Comment) VALUES (8001043, 185002, 530, 0, 0, 1, 1, -1992.59, 5211.21, -44.239, 0.985043, -0, -0, -0.472849, -0.881143, 300, 0, 1, '', null, null);
REPLACE INTO acore_world.gameobject (guid, id, map, zoneId, areaId, spawnMask, phaseMask, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, ScriptName, VerifiedBuild, Comment) VALUES (8001046, 190213, 530, 0, 0, 1, 1, -1999.01, 5226.06, -44.2926, 5.86235, -0, -0, -0.20887, 0.977943, 300, 0, 1, '', null, null);
REPLACE INTO acore_world.gameobject (guid, id, map, zoneId, areaId, spawnMask, phaseMask, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, ScriptName, VerifiedBuild, Comment) VALUES (8001047, 182934, 530, 0, 0, 1, 1, -1992.11, 5207.81, -44.7864, 0.95047, -0, -0, -0.457548, -0.889185, 300, 0, 1, '', null, null);
REPLACE INTO acore_world.gameobject (guid, id, map, zoneId, areaId, spawnMask, phaseMask, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, ScriptName, VerifiedBuild, Comment) VALUES (8001050, 192935, 530, 0, 0, 1, 1, -1991.3, 5213.01, -44.0442, 1.02353, -0, -0, -0.489717, -0.871881, 300, 0, 1, '', null, null);
REPLACE INTO acore_world.gameobject (guid, id, map, zoneId, areaId, spawnMask, phaseMask, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, ScriptName, VerifiedBuild, Comment) VALUES (8001051, 194581, 530, 0, 0, 1, 1, -1993.03, 5220.23, -44.2068, 3.67347, -0, -0, -0.964847, 0.262813, 300, 0, 1, '', null, null);
REPLACE INTO acore_world.gameobject (guid, id, map, zoneId, areaId, spawnMask, phaseMask, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, ScriptName, VerifiedBuild, Comment) VALUES (8001052, 182483, 530, 0, 0, 1, 1, -1994.8, 5219.62, -44.2093, 0.71644, -0, -0, -0.350608, -0.936523, 300, 0, 1, '', null, null);
REPLACE INTO acore_world.gameobject (guid, id, map, zoneId, areaId, spawnMask, phaseMask, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, ScriptName, VerifiedBuild, Comment) VALUES (8001055, 179846, 530, 0, 0, 1, 1, -1986.62, 5222.6, -44.6557, 3.55485, -0, -0, -0.978728, 0.205163, 300, 0, 1, '', null, null);
REPLACE INTO acore_world.gameobject (guid, id, map, zoneId, areaId, spawnMask, phaseMask, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, ScriptName, VerifiedBuild, Comment) VALUES (8001057, 192935, 571, 0, 0, 1, 1, 5804.06, 639.865, 609.886, 5.84656, -0, -0, -0.216585, 0.976264, 300, 0, 1, '', null, null);
REPLACE INTO acore_world.gameobject (guid, id, map, zoneId, areaId, spawnMask, phaseMask, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, ScriptName, VerifiedBuild, Comment) VALUES (8001059, 187082, 571, 0, 0, 1, 1, 5829.63, 674.817, 609.886, 5.36498, -0, -0, -0.443142, 0.896452, 300, 0, 1, '', null, null);

View File

@@ -0,0 +1,172 @@
-- This rebalances lower level iLevel gear
UPDATE item_template
SET
stat_value1 = CASE
WHEN stat_type1 IN (38, 45) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value1 * 0.75)
WHEN stat_type1 IN (38, 45) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value1 * 0.80)
WHEN stat_type1 IN (38, 45) AND ItemLevel > 315 AND ItemLevel <= 325 THEN FLOOR(stat_value1 * 0.90)
ELSE stat_value1
END,
stat_value2 = CASE
WHEN stat_type2 IN (38, 45) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value2 * 0.75)
WHEN stat_type2 IN (38, 45) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value2 * 0.80)
WHEN stat_type2 IN (38, 45) AND ItemLevel > 315 AND ItemLevel <= 325 THEN FLOOR(stat_value2 * 0.90)
ELSE stat_value2
END,
stat_value3 = CASE
WHEN stat_type3 IN (38, 45) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value3 * 0.75)
WHEN stat_type3 IN (38, 45) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value3 * 0.80)
WHEN stat_type3 IN (38, 45) AND ItemLevel > 315 AND ItemLevel <= 325 THEN FLOOR(stat_value3 * 0.90)
ELSE stat_value3
END,
stat_value4 = CASE
WHEN stat_type4 IN (38, 45) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value4 * 0.75)
WHEN stat_type4 IN (38, 45) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value4 * 0.80)
WHEN stat_type4 IN (38, 45) AND ItemLevel > 315 AND ItemLevel <= 325 THEN FLOOR(stat_value4 * 0.90)
ELSE stat_value4
END,
stat_value5 = CASE
WHEN stat_type5 IN (38, 45) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value5 * 0.75)
WHEN stat_type5 IN (38, 45) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value5 * 0.80)
WHEN stat_type5 IN (38, 45) AND ItemLevel > 315 AND ItemLevel <= 325 THEN FLOOR(stat_value5 * 0.90)
ELSE stat_value5
END,
stat_value6 = CASE
WHEN stat_type6 IN (38, 45) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value6 * 0.75)
WHEN stat_type6 IN (38, 45) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value6 * 0.80)
WHEN stat_type6 IN (38, 45) AND ItemLevel > 315 AND ItemLevel <= 325 THEN FLOOR(stat_value6 * 0.90)
ELSE stat_value6
END,
stat_value7 = CASE
WHEN stat_type7 IN (38, 45) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value7 * 0.75)
WHEN stat_type7 IN (38, 45) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value7 * 0.80)
WHEN stat_type7 IN (38, 45) AND ItemLevel > 315 AND ItemLevel <= 325 THEN FLOOR(stat_value7 * 0.90) ELSE stat_value7
END,
stat_value8 = CASE
WHEN stat_type8 IN (38, 45) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value8 * 0.75)
WHEN stat_type8 IN (38, 45) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value8 * 0.80)
WHEN stat_type8 IN (38, 45) AND ItemLevel > 315 AND ItemLevel <= 325 THEN FLOOR(stat_value8 * 0.90)
ELSE stat_value8
END
WHERE
entry BETWEEN 20000000 and 21000000;
-- Rebalance primary strength, agi, intellect down for lower ilvl items
UPDATE item_template
SET
stat_value1 = CASE
WHEN stat_type1 IN (3,4,5) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value1 * 0.85)
WHEN stat_type1 IN (3,4,5) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value1 * 0.90)
ELSE stat_value1
END,
stat_value2 = CASE
WHEN stat_type2 IN (3,4,5) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value2 * 0.85)
WHEN stat_type2 IN (3,4,5) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value2 * 0.90)
ELSE stat_value2
END,
stat_value3 = CASE
WHEN stat_type3 IN (3,4,5) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value3 * 0.85)
WHEN stat_type3 IN (3,4,5) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value3 * 0.90)
ELSE stat_value3
END,
stat_value4 = CASE
WHEN stat_type4 IN (3,4,5) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value4 * 0.85)
WHEN stat_type4 IN (3,4,5) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value4 * 0.90)
ELSE stat_value4
END,
stat_value5 = CASE
WHEN stat_type5 IN (3,4,5) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value5 * 0.85)
WHEN stat_type5 IN (3,4,5) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value5 * 0.90)
ELSE stat_value5
END,
stat_value6 = CASE
WHEN stat_type6 IN (3,4,5) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value6 * 0.85)
WHEN stat_type6 IN (3,4,5) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value6 * 0.90)
ELSE stat_value6
END,
stat_value7 = CASE
WHEN stat_type7 IN (3,4,5) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value7 * 0.85)
WHEN stat_type7 IN (3,4,5) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value7 * 0.90)
ELSE stat_value7
END,
stat_value8 = CASE
WHEN stat_type8 IN (3,4,5) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value8 * 0.85)
WHEN stat_type8 IN (3,4,5) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value8 * 0.90)
ELSE stat_value8
END
WHERE
entry BETWEEN 20000000 and 21000000;
-- Nerf hit / spell hit crit rating and others items 300-315 by 15% and 10%
UPDATE item_template
SET
stat_value1 = CASE
WHEN (stat_type1 BETWEEN 16 AND 37 OR stat_type1 = 44) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value1 * 0.85)
WHEN (stat_type1 BETWEEN 16 AND 37 OR stat_type1 = 44) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value1 * 0.90)
ELSE stat_value1
END,
stat_value2 = CASE
WHEN (stat_type2 BETWEEN 16 AND 37 OR stat_type2 = 44) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value2 * 0.85)
WHEN (stat_type2 BETWEEN 16 AND 37 OR stat_type2 = 44) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value2 * 0.90)
ELSE stat_value2
END,
stat_value3 = CASE
WHEN (stat_type3 BETWEEN 16 AND 37 OR stat_type3 = 44) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value3 * 0.85)
WHEN (stat_type3 BETWEEN 16 AND 37 OR stat_type3 = 44) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value3 * 0.90)
ELSE stat_value3
END,
stat_value4 = CASE
WHEN (stat_type4 BETWEEN 16 AND 37 OR stat_type4 = 44) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value4 * 0.85)
WHEN (stat_type4 BETWEEN 16 AND 37 OR stat_type4 = 44) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value4 * 0.90)
ELSE stat_value4
END,
stat_value5 = CASE
WHEN (stat_type5 BETWEEN 16 AND 37 OR stat_type5 = 44) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value5 * 0.85)
WHEN (stat_type5 BETWEEN 16 AND 37 OR stat_type5 = 44) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value5 * 0.90)
ELSE stat_value5
END,
stat_value6 = CASE
WHEN (stat_type6 BETWEEN 16 AND 37 OR stat_type6 = 44) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value6 * 0.85)
WHEN (stat_type6 BETWEEN 16 AND 37 OR stat_type6 = 44) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value6 * 0.90)
ELSE stat_value6
END,
stat_value7 = CASE
WHEN (stat_type7 BETWEEN 16 AND 37 OR stat_type7 = 44) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value7 * 0.85)
WHEN (stat_type7 BETWEEN 16 AND 37 OR stat_type7 = 44) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value7 * 0.90)
ELSE stat_value7
END,
stat_value8 = CASE
WHEN (stat_type8 BETWEEN 16 AND 37 OR stat_type8 = 44) AND ItemLevel BETWEEN 300 AND 305 THEN FLOOR(stat_value8 * 0.85)
WHEN (stat_type8 BETWEEN 16 AND 37 OR stat_type8 = 44) AND ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(stat_value8 * 0.90)
ELSE stat_value8
END
WHERE
entry BETWEEN 20000000 and 21000000;
-- reduce damage on lower level items
UPDATE item_template
SET
dmg_min1 = CASE
WHEN ItemLevel BETWEEN 300 AND 305 THEN FLOOR(dmg_min1 * 0.85)
WHEN ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(dmg_min1 * 0.90)
ELSE dmg_min1
END,
dmg_max1 = CASE
WHEN ItemLevel BETWEEN 300 AND 305 THEN FLOOR(dmg_max1 * 0.85)
WHEN ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(dmg_max1 * 0.90)
ELSE dmg_max1
END,
dmg_min2 = CASE
WHEN ItemLevel BETWEEN 300 AND 305 THEN FLOOR(dmg_min2 * 0.85)
WHEN ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(dmg_min2 * 0.90)
ELSE dmg_min2
END,
dmg_max2 = CASE
WHEN ItemLevel BETWEEN 300 AND 305 THEN FLOOR(dmg_max2 * 0.85)
WHEN ItemLevel > 305 AND ItemLevel <= 315 THEN FLOOR(dmg_max2 * 0.90)
ELSE dmg_max2
END
WHERE
entry BETWEEN 20000000 and 21000000;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,67 @@
-- Tier 1 and 2 Vendors
DELETE FROM `creature_template` WHERE (`entry` = 9500800);
INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES
(9500800, 0, 0, 0, 0, 0, 'Champion Miluria', 'Mythic I Weapons and Gear', '', 0, 80, 80, 2, 2027, 128, 1, 1.14286, 1, 1, 20, 1, 0, 0, 1, 2000, 2000, 1, 1, 8, 768, 2048, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 10314);
DELETE FROM `creature_template_model` WHERE (`CreatureID` = 9500800);
INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES
(9500800, 0, 29832, 1, 1, 10314);
DELETE FROM `creature_equip_template` WHERE (`CreatureID` = 9500800);
INSERT INTO `creature_equip_template` (`CreatureID`, `ID`, `ItemID1`, `ItemID2`, `ItemID3`, `VerifiedBuild`) VALUES
(9500800, 1, 29405, 6618, 0, 18019);
DELETE FROM `creature_template` WHERE (`entry` = 9500801);
INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES
(9500801, 0, 0, 0, 0, 0, 'Paldesse', 'Mythic I Cloth Armor', '', 0, 80, 80, 0, 2007, 4224, 1, 1.14286, 1, 1, 20, 1, 0, 0, 1, 2000, 2000, 1, 1, 8, 512, 2048, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 12340);
DELETE FROM `creature_template_model` WHERE (`CreatureID` = 9500801);
INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES
(9500801, 0, 25594, 1, 1, 12340);
DELETE FROM `creature_template` WHERE (`entry` = 9500802);
INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES
(9500802, 0, 0, 0, 0, 0, 'Griselda Hunderland', 'Mythic I Plate Armor', '', 0, 80, 80, 0, 2007, 4224, 1, 1.14286, 1, 1, 20, 1, 0, 0, 1, 2000, 2000, 1, 1, 1, 512, 2048, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'SmartAI', 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 12340);
DELETE FROM `creature_template_model` WHERE (`CreatureID` = 9500802);
INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES
(9500802, 0, 25881, 1, 1, 12340);
DELETE FROM `creature_template` WHERE (`entry` = 9500803);
INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES
(9500803, 0, 0, 0, 0, 0, 'Valerie Langrom', 'Mythic I Leather Armor', '', 0, 80, 80, 2, 2007, 4224, 1, 1.14286, 1, 1, 20, 1, 0, 0, 1, 2000, 2000, 1, 1, 1, 0, 2048, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 12340);
DELETE FROM `creature_template_model` WHERE (`CreatureID` = 9500803);
INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES
(9500803, 0, 25878, 1, 1, 12340);
DELETE FROM `creature_template` WHERE (`entry` = 9500804);
INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES
(9500804, 0, 0, 0, 0, 0, 'Bragund Brightlink', 'Mythic I Mail Armor', '', 0, 80, 80, 2, 2007, 4224, 1, 1.14286, 1, 1, 20, 1, 0, 0, 1, 2000, 2000, 1, 1, 1, 0, 2048, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'SmartAI', 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 12340);
DELETE FROM `creature_template_model` WHERE (`CreatureID` = 9500804);
INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES
(9500804, 0, 26321, 1, 1, 12340);
-- Tiers 3 and 4
DELETE FROM `creature_template` WHERE (`entry` = 9500805);
INSERT INTO `creature_template` (`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `KillCredit1`, `KillCredit2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `speed_walk`, `speed_run`, `speed_swim`, `speed_flight`, `detection_range`, `scale`, `rank`, `dmgschool`, `DamageModifier`, `BaseAttackTime`, `RangeAttackTime`, `BaseVariance`, `RangeVariance`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `HoverHeight`, `HealthModifier`, `ManaModifier`, `ArmorModifier`, `ExperienceModifier`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `spell_school_immune_mask`, `flags_extra`, `ScriptName`, `VerifiedBuild`) VALUES
(9500805, 0, 0, 0, 0, 0, 'Captain Dirgehammer', 'Mythic II Weapons and Gear ', NULL, 0, 65, 65, 1, 1078, 4224, 1, 1.14286, 1, 1, 18, 1, 0, 0, 1, 2000, 2000, 1, 1, 1, 4864, 2048, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 1, 2, 1, 1, 1, 0, 0, 1, 0, 0, 0, '', 12340);
DELETE FROM `creature_template_model` WHERE (`CreatureID` = 9500805);
INSERT INTO `creature_template_model` (`CreatureID`, `Idx`, `CreatureDisplayID`, `DisplayScale`, `Probability`, `VerifiedBuild`) VALUES
(9500805, 0, 12917, 1, 1, 12340);
-- Tier 5
-- Spawns
REPLACE INTO acore_world.creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES (9001025, 9500800, 0, 0, 571, 0, 0, 1, 1, 1, 5738.66, 741.002, 641.74, 4.1062, 300, 0, 0, 10080, 8814, 0, 0, 0, 0, '', null, 0, null);
REPLACE INTO acore_world.creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES (9001026, 9500801, 0, 0, 571, 0, 0, 1, 1, 0, 5736.61, 742.711, 641.75, 4.04965, 300, 0, 0, 3739, 8814, 0, 0, 0, 0, '', null, 0, null);
REPLACE INTO acore_world.creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES (9001027, 9500802, 0, 0, 571, 0, 0, 1, 1, 0, 5732.59, 746.182, 641.762, 4.01431, 300, 0, 0, 5342, 0, 0, 0, 0, 0, '', null, 0, null);
REPLACE INTO acore_world.creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES (9001028, 9500803, 0, 0, 571, 0, 0, 1, 1, 0, 5730.76, 747.711, 641.761, 4.16746, 300, 0, 0, 12600, 0, 0, 0, 0, 0, '', null, 0, null);
REPLACE INTO acore_world.creature (guid, id1, id2, id3, map, zoneId, areaId, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags, ScriptName, VerifiedBuild, CreateObject, Comment) VALUES (9001029, 9500804, 0, 0, 571, 0, 0, 1, 1, 0, 5725.58, 750.971, 641.768, 4.48476, 300, 0, 0, 12600, 0, 0, 0, 0, 0, '', null, 0, null);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@ package main
import (
"fmt"
"math"
"os"
)
@@ -15,13 +16,80 @@ const (
)
const (
RESIST_FROST = iota
RESIST_ARCANE = iota
RESIST_FIRE
RESIST_NATURE
RESIST_FROST
RESIST_SHADOW
RESIST_ARCANE
)
// Return the itemEntry for a state item and based on quality (3 - rare, 4 - epic)
func getStatItemEntry(statID int, quality int) int {
switch statID {
case STAT_INTELLECT:
if quality == 3 {
return 911005
}
return 911006
case STAT_SPIRIT:
if quality == 3 {
return 911009
}
return 911010
case STAT_STRENGTH:
if quality == 3 {
return 911003
}
return 911004
case STAT_AGILITY:
if quality == 3 {
return 911007
}
return 911008
case STAT_STAMINA:
if quality == 3 {
return 911011
}
return 911012
default:
return 0
}
}
func getResistItemEntry(resistID int, quality int) int {
switch resistID {
case RESIST_FROST:
if quality == 3 {
return 911015
}
return 911016
case RESIST_FIRE:
if quality == 3 {
return 911017
}
return 911018
case RESIST_NATURE:
if quality == 3 {
return 911023
}
return 911024
case RESIST_SHADOW:
if quality == 3 {
return 911021
}
return 911022
case RESIST_ARCANE:
if quality == 3 {
return 911019
}
return 911020
default:
return 0
}
}
func main() {
// Output file for the SQL script
outputFile, err := os.Create("generate_stat_upgrades.sql")
@@ -40,9 +108,17 @@ func main() {
STAT_STAMINA: "Stamina",
}
resistTypes := map[int]string{
RESIST_ARCANE: "Arcane",
RESIST_FIRE: "Fire",
RESIST_NATURE: "Nature",
RESIST_FROST: "Frost",
RESIST_SHADOW: "Shadow",
}
// Start writing the SQL script
fmt.Fprintln(outputFile, "-- SQL Script to Insert 50 Ranks for Each Stat")
fmt.Fprintln(outputFile, "INSERT INTO mp_upgrade_ranks (upgradeRank, advancementId, materialId1, materialCost1, materialId2, materialCost2, materialId3, materialCost3, minIncrease1, maxIncrease1, minIncrease2, maxIncrease2, minIncrease3, maxIncrease3, chanceCost1, chanceCost2, chanceCost3) VALUES")
fmt.Fprintln(outputFile, "INSERT INTO mp_upgrade_ranks (upgradeRank, advancementId, itemEntry1, itemCost1, itemEntry2, itemCost2, itemEntry3, itemCost3, minIncrease1, maxIncrease1, minIncrease2, maxIncrease2, minIncrease3, maxIncrease3, chanceCost1, chanceCost2, chanceCost3) VALUES")
// Iterate over stats
for statID := range stats {
@@ -59,6 +135,9 @@ func main() {
materialCost = 1000 + (rank-30)*18
}
// Make adjustment for new fusion core types
itemCost1 := int(math.Ceil(float64(materialCost) / 20))
// Stat growth
minIncrease1 := 1 + (rank-1)/10*2
maxIncrease1 := 10 + (rank-1)/10*2
@@ -74,47 +153,49 @@ func main() {
chanceCost3 := 75 + (rank-1)*3
// use material ids from the mp_material_types table material1 should be common stuff.
materialId1 := statID*2 + 1
itemEntry1 := getStatItemEntry(statID, 3)
// material2 should be rare stuff only required after rank 10 at growth rate of 5 per rank
materialId2, materialCost2 := 0, 0
itemEntry2, itemCost2 := 0, 0
if rank > 10 {
materialId2 = statID*2 + 2
materialCost2 = (rank - 11) * 10
itemEntry2 = getStatItemEntry(statID, 4)
itemCost2 = (rank - 11) * 10
}
materialId3, materialCost3 := 0, 0
// Adjust from old formula to new mythic fusion core types
itemCost2 = int(math.Ceil(float64(itemCost2) / 5))
itemEntry3, itemCost3 := 0, 0
if rank >= 30 {
materialId3 = 20 // Group lot of raid only items
materialCost3 = (rank - 29) * 3
itemEntry3 = 911002 // veilstones
itemCost3 = (rank - 29) * 3
if itemCost3 > 15 {
itemCost3 = 15
}
}
// Write SQL insert statement for this rank
sql := fmt.Sprintf(
"(%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)",
rank, statID, materialId1, materialCost, materialId2, materialCost2, materialId3, materialCost3,
rank, statID, itemEntry1, itemCost1, itemEntry2, itemCost2, itemEntry3, itemCost3,
minIncrease1, maxIncrease1, minIncrease2, maxIncrease1, minIncrease3, maxIncrease3,
chanceCost1, chanceCost2, chanceCost3,
)
// Add a comma for all but the last line
sql += ","
fmt.Fprintln(outputFile, sql)
isLastStat := statID == STAT_STAMINA && rank == 50
isLastResist := false
isLast := isLastStat && len(resistTypes) == 0 || isLastResist
if !isLast {
sql += ","
}
fmt.Fprintln(outputFile, sql)
}
}
resists := map[int]string{
RESIST_FROST: "Frost",
RESIST_FIRE: "Fire",
RESIST_NATURE: "Nature",
RESIST_SHADOW: "Shadow",
RESIST_ARCANE: "Arcane",
}
// Iterate over stats
for resistId := range resists {
// Iterate over resists
for resistId := range resistTypes {
resistIdbump := resistId + 5
for rank := 1; rank <= 50; rank++ {
// Material cost increases by 50 per rank
@@ -129,6 +210,9 @@ func main() {
materialCost = 700 + (rank-30)*18
}
// Make adjustment for new fusion core types
itemCost1 := int(math.Ceil(float64(materialCost) / 20))
// Stat growth
minIncrease1 := 1 + (rank-1)/5*2
maxIncrease1 := 5 + (rank-1)/5*2
@@ -145,31 +229,36 @@ func main() {
chanceCost3 := 75 + (rank-1)*3
// use material ids from the mp_material_types table material1 should be common stuff.
materialId1 := resistIdbump*2 + 1
itemEntry1 := getResistItemEntry(resistId, 3)
// material2 should be rare stuff only required after rank 10 at growth rate of 5 per rank
materialId2, materialCost2 := 0, 0
itemEntry2, itemCost2 := 0, 0
if rank > 10 {
materialId2 = resistIdbump*2 + 2
materialCost2 = (rank - 11) * 10
itemEntry2 = getResistItemEntry(resistId, 4)
itemCost2 = (rank - 11) * 10
}
materialId3, materialCost3 := 0, 0
// Adjust from old formula to new mythic fusion core types
itemCost2 = int(math.Ceil(float64(itemCost2) / 5))
itemEntry3, itemCost3 := 0, 0
if rank >= 30 {
materialId3 = 20 // Group lot of raid only items
materialCost3 = (rank - 29) * 3
itemEntry3 = 911002 // veilstones
itemCost3 = (rank - 29) * 3
}
// Write SQL insert statement for this rank
sql := fmt.Sprintf(
"(%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)",
rank, resistIdbump, materialId1, materialCost, materialId2, materialCost2, materialId3, materialCost3,
rank, resistIdbump, itemEntry1, itemCost1, itemEntry2, itemCost2, itemEntry3, itemCost3,
minIncrease1, maxIncrease1, minIncrease2, maxIncrease1, minIncrease3, maxIncrease3,
chanceCost1, chanceCost2, chanceCost3,
)
// Add a comma for all but the last line
if !(resistId == RESIST_ARCANE && rank == 50) {
isLast := resistId == RESIST_ARCANE && rank == 50
if !isLast {
sql += ","
}
fmt.Fprintln(outputFile, sql)

View File

@@ -34,12 +34,12 @@ std::string MpAdvancementsToString(MpAdvancements advancement)
*
* upgradeRank INT UNSIGNED NOT NULL,
* advancementId INT UNSIGNED NOT NULL,
* materialId1 INT UNSIGNED NOT NULL,
* materialId2 INT UNSIGNED NOT NULL,
* materialId3 INT UNSIGNED NOT NULL,
* materialCost INT UNSIGNED NOT NULL,
* materialCost2 INT UNSIGNED NOT NULL,
* materialCost3 INT UNSIGNED NOT NULL,
* itemEntry1 INT UNSIGNED NOT NULL,
* itemEntry2 INT UNSIGNED NOT NULL,
* itemEntry3 INT UNSIGNED NOT NULL,
* itemCost1 INT UNSIGNED NOT NULL,
* itemCost2 INT UNSIGNED NOT NULL,
* itemCost3 INT UNSIGNED NOT NULL,
* minIncrease1 INT UNSIGNED NOT NULL,
* maxIncrease1 INT UNSIGNED NOT NULL,
* minIncrease2 INT UNSIGNED NOT NULL,
@@ -64,12 +64,12 @@ int32 AdvancementMgr::LoadAdvancementRanks() {
SELECT
upgradeRank,
advancementId,
materialId1,
materialId2,
materialId3,
materialCost1,
materialCost2,
materialCost3,
itemEntry1,
itemEntry2,
itemEntry3,
itemCost1,
itemCost2,
itemCost3,
minIncrease1,
maxIncrease1,
minIncrease2,
@@ -84,7 +84,7 @@ int32 AdvancementMgr::LoadAdvancementRanks() {
QueryResult result = WorldDatabase.Query(query);
if (!result) {
MpLogger::error("Failed to load mythic scale factors from database");
MpLogger::error("Failed to load advancement ranks from database");
return 0;
}
@@ -96,12 +96,12 @@ int32 AdvancementMgr::LoadAdvancementRanks() {
Field* fields = result->Fetch();
uint32 upgradeRank = fields[0].Get<uint32>();
uint32 advancementId = fields[1].Get<uint32>();
uint32 materialId1 = fields[2].Get<uint32>();
uint32 materialId2 = fields[3].Get<uint32>();
uint32 materialId3 = fields[4].Get<uint32>();
uint32 materialCost1 = fields[5].Get<uint32>();
uint32 materialCost2 = fields[6].Get<uint32>();
uint32 materialCost3 = fields[7].Get<uint32>();
uint32 itemEntry1 = fields[2].Get<uint32>();
uint32 itemEntry2 = fields[3].Get<uint32>();
uint32 itemEntry3 = fields[4].Get<uint32>();
uint32 itemCost1 = fields[5].Get<uint32>();
uint32 itemCost2 = fields[6].Get<uint32>();
uint32 itemCost3 = fields[7].Get<uint32>();
uint32 minIncrease1 = fields[8].Get<uint32>();
uint32 maxIncrease1 = fields[9].Get<uint32>();
uint32 minIncrease2 = fields[10].Get<uint32>();
@@ -124,9 +124,9 @@ int32 AdvancementMgr::LoadAdvancementRanks() {
.lowRange = std::make_pair(minIncrease1, maxIncrease1),
.midRange = std::make_pair(minIncrease2, maxIncrease2),
.highRange = std::make_pair(minIncrease3, maxIncrease3),
.material1 = std::make_pair(materialId1, materialCost1),
.material2 = std::make_pair(materialId2, materialCost2),
.material3 = std::make_pair(materialId3, materialCost3)
.material1 = std::make_pair(itemEntry1, itemCost1),
.material2 = std::make_pair(itemEntry2, itemCost2),
.material3 = std::make_pair(itemEntry3, itemCost3)
};
_advancementRanks.try_emplace(std::make_pair(upgradeRank, advancement), rank);
@@ -172,24 +172,34 @@ void AdvancementMgr::LoadPlayerAdvancements(Player* player) {
return;
}
Field* fields = result->Fetch();
uint32 guid = fields[0].Get<uint32>();
uint32 advancementId = fields[1].Get<uint32>();
float bonus = fields[2].Get<float>();
uint32 upgradeRank = fields[3].Get<uint32>();
uint32 diceSpent = fields[4].Get<uint32>();
uint32 count = 0;
uint32 guid = player->GetGUID().GetCounter();
MpAdvancements advancement = static_cast<MpAdvancements>(advancementId);
MpPlayerRank playerRank = MpPlayerRank();
playerRank.rank = upgradeRank;
playerRank.advancementId = advancement;
playerRank.diceSpent = diceSpent;
playerRank.bonus = bonus;
// Loop through all results to load all advancements for this player
do {
Field* fields = result->Fetch();
uint32 advancementId = fields[1].Get<uint32>();
float bonus = fields[2].Get<float>();
uint32 upgradeRank = fields[3].Get<uint32>();
uint32 diceSpent = fields[4].Get<uint32>();
// List of all ranks keyed by rank, advancementId
_playerAdvancements[guid][advancement] = playerRank;
MpAdvancements advancement = static_cast<MpAdvancements>(advancementId);
MpPlayerRank playerRank = MpPlayerRank();
playerRank.rank = upgradeRank;
playerRank.advancementId = advancement;
playerRank.diceSpent = diceSpent;
playerRank.bonus = bonus;
MpLogger::info("Loaded player {} advancement {} rank {}", player->GetName(), playerRank.advancementId, upgradeRank);
// List of all ranks keyed by rank, advancementId
_playerAdvancements[guid][advancement] = playerRank;
MpLogger::debug("Loaded player {} advancement {} rank {} with bonus {}",
player->GetName(), static_cast<int>(advancement), upgradeRank, bonus);
count++;
} while (result->NextRow());
MpLogger::info("Loaded {} advancements for player {}", count, player->GetName());
}
/**
@@ -204,21 +214,25 @@ int32 AdvancementMgr::LoadMaterialTypes() {
FROM mp_material_types
)";
QueryResult result = WorldDatabase.Query(query);
if(QueryResult result = WorldDatabase.Query(query)) {
do {
Field* fields = result->Fetch();
uint32 materialId = fields[0].Get<uint32>();
uint32 entry = fields[1].Get<uint32>();
do {
Field* fields = result->Fetch();
uint32 materialId = fields[0].Get<uint32>();
uint32 entry = fields[1].Get<uint32>();
if(!_materialTypes.contains(materialId)) {
_materialTypes.emplace(materialId,std::vector<uint32>());
}
_materialTypes.at(materialId).push_back(entry);
if(!_materialTypes.contains(materialId)) {
_materialTypes.emplace(materialId,std::vector<uint32>());
}
_materialTypes.at(materialId).push_back(entry);
} while (result->NextRow());
} while (result->NextRow());
return result->GetRowCount();
return result->GetRowCount();
} else {
MpLogger::error("Query failed to load material types from database");
return 0;
}
}
MpAdvancementRank* AdvancementMgr::GetAdvancementRank(uint32 rank, MpAdvancements advancement)
@@ -250,7 +264,7 @@ MpPlayerRank* AdvancementMgr::GetPlayerAdvancementRank(Player* player, MpAdvance
return nullptr;
}
uint32 AdvancementMgr::UpgradeAdvancement(Player* player, MpAdvancements advancement, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3)
uint32 AdvancementMgr::UpgradeAdvancement(Player* player, MpAdvancements advancement, uint32 diceCostLevel)
{
std::lock_guard<std::mutex> lock(_playerAdvancementMutex);
@@ -262,9 +276,6 @@ uint32 AdvancementMgr::UpgradeAdvancement(Player* player, MpAdvancements advance
if(diceCostLevel < 1 || diceCostLevel > 3) {
throw new std::runtime_error(Acore::StringFormat("Invalid dice cost level valid vales (1,2,3) received {} for player {}", diceCostLevel, player->GetName()));
}
if(itemEntry1 == 0) {
throw new std::runtime_error(Acore::StringFormat("Material1 can not be 0 can not perform advancement upgrade for player {} Advancement {}", player->GetName(), advancement));
}
MpPlayerRank* playerRank = GetPlayerAdvancementRank(player, advancement);
@@ -285,10 +296,16 @@ uint32 AdvancementMgr::UpgradeAdvancement(Player* player, MpAdvancements advance
uint32 newRank = playerRank->rank + 1;
MpAdvancementRank* advancementRank = GetAdvancementRank(newRank, advancement);
if(!advancementRank->IsValid()) {
throw std::runtime_error("Advancement rank could not be found. Rank: " + std::to_string(newRank) + " Advancement: " + std::to_string(advancement));
if(advancementRank == nullptr || !advancementRank->IsValid()) {
MpLogger::error("Advancement rank could not be found. Rank: {} Advancement: {}", newRank, static_cast<int>(advancement));
return 0;
}
// Get the items needed to upgrade this advancement
uint32 itemEntry1 = advancementRank->material1.first;
uint32 itemEntry2 = advancementRank->material2.first;
uint32 itemEntry3 = advancementRank->material3.first;
// If the player has the items needed to upgrade this advancement, then remove the items from the player inventory and apply the upgrade
if(!_PlayerHasItems(player, advancementRank, diceCostLevel, itemEntry1, itemEntry2, itemEntry3)) {
MpLogger::debug("Player {} does not have the required items to upgrade advancement {}", player->GetName(), advancement);
@@ -315,6 +332,17 @@ uint32 AdvancementMgr::UpgradeAdvancement(Player* player, MpAdvancements advance
// Save the advancement to the database
_SaveAdvancement(player, advancementRank, playerRank, advancementRank->rollCost[diceCostLevel-1], roll, itemEntry1, itemEntry2, itemEntry3);
// Remove and reapply the aura to refresh the spell with the latest bonuses
uint32 spellId = MpConstants::GetAdvancementAura(advancement);
if (spellId > 0)
{
MpLogger::info("Refreshing advancement aura {} for player {}", spellId, player->GetName());
// First remove the aura completely
player->RemoveAura(spellId);
player->AddAura(spellId, player);
}
return roll;
}
@@ -352,7 +380,7 @@ float AdvancementMgr::_RollAdvancement(MpAdvancementRank* advancementRank, uint3
max = advancementRank->highRange.second;
break;
default:
MpLogger::error("Invalid dice cost level valid vales (1,2,3) received {} for rank roll", diceCostLevel, advancementRank->rank);
MpLogger::error("Invalid dice cost level valid vales (1,2,3) received {} for rank roll {}", diceCostLevel, advancementRank->rank);
break;
}
@@ -367,79 +395,92 @@ float AdvancementMgr::_RollAdvancement(MpAdvancementRank* advancementRank, uint3
*/
bool AdvancementMgr::_PlayerHasItems(Player* player, MpAdvancementRank* advancementRank, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3)
{
MpLogger::debug("Debugging player dice {} item1 {} item2 {} item3 {}", diceCostLevel, itemEntry1, itemEntry2, itemEntry3);
MpLogger::debug("Advancement Rank dice info {} {} {} {}", advancementRank->materialCost[1], advancementRank->materialCost[2], advancementRank->materialCost[3]);
MpLogger::debug("Checking items for player {} dice level {} item1 {} item2 {} item3 {}",
player->GetName(), diceCostLevel, itemEntry1, itemEntry2, itemEntry3);
// Check if player has the required dice to upgrade the advancement if not do nothing.
// Check if player has the required dice to upgrade the advancement
uint32 diceCost = advancementRank->rollCost[diceCostLevel-1];
if(!player->HasItemCount(MpConstants::ANCIENT_DICE, diceCost)) {
MpLogger::info("Player {} does not have enough dice to upgrade advancement {}", player->GetName(), advancementRank->advancementId);
MpLogger::info("Player {} does not have enough dice to upgrade advancement {}",
player->GetName(), advancementRank->advancementId);
return false;
}
// Create arrays of material data for easier iteration
std::pair<uint32, uint32> materials[] = {
advancementRank->material1,
advancementRank->material2,
advancementRank->material3
};
uint32 itemEntries[] = {itemEntry1, itemEntry2, itemEntry3};
// Validate each material
for (size_t i = 0; i < 3; ++i) {
uint32 materialId = materials[i].first;
uint32 requiredCount = materials[i].second;
uint32 itemEntry = itemEntries[i];
// if the materialID is not set and is not the first material then return true as no material is required
if (materialId == 0 && i != 0) {
return true;
// Check material 1 (required)
if (advancementRank->material1.first > 0) {
if (itemEntry1 == 0) {
throw std::runtime_error("Primary material entry is required but was not provided");
}
if (itemEntry == 0 && materialId != 0) {
throw std::runtime_error("The entry for materialId: " + std::to_string(materialId) + " was not passed in.");
}
std::vector<uint32> entries = _materialTypes.at(materialId);
if (entries.empty()) {
throw std::runtime_error("MaterialId: " + std::to_string(materialId) + " could not be found in the materials list");
}
if (std::find(entries.begin(), entries.end(), itemEntry) == entries.end()) {
throw std::runtime_error("Incorrect material entry" + std::to_string(itemEntry) + " passed in passed in for Advancement id:" + std::to_string(advancementRank->advancementId));
}
if (!player->HasItemCount(itemEntry, requiredCount)) {
MpLogger::info("Player {} does not have enough material {} to upgrade advancement {} requires: {}",
player->GetName(), itemEntry, advancementRank->advancementId, requiredCount);
uint32 requiredCount = advancementRank->material1.second;
if (!player->HasItemCount(itemEntry1, requiredCount)) {
MpLogger::info("Player {} does not have enough of item {} for advancement {}, requires: {}",
player->GetName(), itemEntry1, advancementRank->advancementId, requiredCount);
return false;
}
}
// Check material 2 (optional)
if (advancementRank->material2.first > 0) {
if (itemEntry2 == 0) {
MpLogger::debug("Secondary material is required but not provided");
return false;
}
uint32 requiredCount = advancementRank->material2.second;
if (!player->HasItemCount(itemEntry2, requiredCount)) {
MpLogger::info("Player {} does not have enough of item {} for advancement {}, requires: {}",
player->GetName(), itemEntry2, advancementRank->advancementId, requiredCount);
return false;
}
}
// Check material 3 (optional)
if (advancementRank->material3.first > 0) {
if (itemEntry3 == 0) {
MpLogger::debug("Tertiary material is required but not provided");
return false;
}
uint32 requiredCount = advancementRank->material3.second;
if (!player->HasItemCount(itemEntry3, requiredCount)) {
MpLogger::info("Player {} does not have enough of item {} for advancement {}, requires: {}",
player->GetName(), itemEntry3, advancementRank->advancementId, requiredCount);
return false;
}
}
MpLogger::debug("Player {} has all required materials to upgrade advancement {}",
player->GetName(), advancementRank->advancementId);
return true;
}
// Remove all items required for the upgrade.
void AdvancementMgr::_ChargeItemCost(Player *player, MpAdvancementRank* advancementRank, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3)
{
MpLogger::debug("Charging player dice {} item1 {} item2 {} item3 {}", diceCostLevel, itemEntry1, itemEntry2, itemEntry3);
MpLogger::debug("Charging player {} dice level {} item1 {} item2 {} item3 {}",
player->GetName(), diceCostLevel, itemEntry1, itemEntry2, itemEntry3);
// Remove the dice cost
uint32 diceCost = advancementRank->rollCost[diceCostLevel-1];
player->DestroyItemCount(MpConstants::ANCIENT_DICE, diceCost, true);
std::vector<std::pair<uint32, uint32>> items = {
{itemEntry1, advancementRank->material1.second},
{itemEntry2, advancementRank->material2.second},
{itemEntry3, advancementRank->material3.second}
};
for (const auto& item : items) {
if (item.first > 0) {
player->DestroyItemCount(item.first, item.second, true);
}
// Remove material 1 if it exists
if (itemEntry1 > 0 && advancementRank->material1.first > 0) {
player->DestroyItemCount(itemEntry1, advancementRank->material1.second, true);
}
return;
// Remove material 2 if it exists
if (itemEntry2 > 0 && advancementRank->material2.first > 0) {
player->DestroyItemCount(itemEntry2, advancementRank->material2.second, true);
}
// Remove material 3 if it exists
if (itemEntry3 > 0 && advancementRank->material3.first > 0) {
player->DestroyItemCount(itemEntry3, advancementRank->material3.second, true);
}
MpLogger::debug("Successfully charged player {} for advancement upgrade", player->GetName());
}
void AdvancementMgr::_SaveAdvancement(Player* player, MpAdvancementRank* advancementRank, MpPlayerRank* playerRank, uint32 diceCost, float roll, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3)

View File

@@ -121,7 +121,7 @@ public:
* mixed materials is more complicated and the UI to support it is much more complex, while this is not as nice it is much simpler to implement.
* That means all materials have to be selected and passed in at the time of making this call.
*/
uint32 UpgradeAdvancement(Player* player, MpAdvancements advancement, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3);
uint32 UpgradeAdvancement(Player* player, MpAdvancements advancement, uint32 diceCostLevel);
// Used to reset all advancements for a specific player
bool ResetPlayerAdvancements(Player* player);
@@ -146,7 +146,7 @@ private:
void _SaveAdvancement(Player* player, MpAdvancementRank* advancementRank, MpPlayerRank* playerRank, uint32 diceCost, float roll, uint32 itemEntry1, uint32 itemEntry2 = 0, uint32 itemEntry3 = 0);
// This will save the advancement purchase to the history database
void _DBSaveAdvancement(Player* player, MpAdvancementRank* advancementRank, MpPlayerRank* playerRank, uint32 diceCost, float roll);
// void _DBSaveAdvancement(Player* player, MpAdvancementRank* advancementRank, MpPlayerRank* playerRank, uint32 diceCost, float roll);
};

View File

@@ -35,7 +35,7 @@ inline std::unordered_map<std::string_view, MpEvent> MpEventMap = {{
{"ResetAdvancement", MpEvent::ResetAdvancement},
{"ResetAllAdvancements", MpEvent::ResetAllAdvancements},
{"GetPlayerRank", MpEvent::GetPlayerRank},
{"GetAdvancementRank", MpEvent::ResetAllAdvancements}
{"GetAdvancementRank", MpEvent::GetAdvancementRank}
}};
inline std::unordered_map<MpClientEvent, std::string_view> MpClientEventNames = {{

View File

@@ -50,7 +50,7 @@ std::string EventCodeToString(MP_EVENT_CODE code)
}
// Send an error event to the client
bool SendEventError(Player* player, const std::string& method, MP_EVENT_CODE code, std::string message)
bool SendEventError(Player* player, const std::string& /* method*/, MP_EVENT_CODE code, std::string message)
{
std::vector<std::string> clientError = { std::to_string(static_cast<int>(code)), message };
MpLogger::error("(Event Processor) Sending client error: {} {}", code, message);
@@ -63,7 +63,7 @@ bool SendEventError(Player* player, const std::string& method, MP_EVENT_CODE cod
* Message Format:
* p|playerGuid|UpgradeAdvancement|advancementId|diceLevel|itemEntry1|itemEntry2|itemEntry3
*/
class UpdateAdvancements : public MpEventInterface
class UpgradeAdvancements : public MpEventInterface
{
public:
const std::string EventName() const override
@@ -82,40 +82,47 @@ class UpdateAdvancements : public MpEventInterface
MpLogger::info("{} Arg: {}", EventName(), arg);
}
// Validate the message is int he right format
if(args.size() != 5) {
return SendEventError(player, EventName(),MP_EVENT_CODE::INVALID_ARGUMENT_SIZE, "Invalid number of arguments expected 5, found " + std::to_string(args.size()));
// Validate the message is in the right format
if(args.size() != 2) {
return SendEventError(player, EventName(), MP_EVENT_CODE::INVALID_ARGUMENT_SIZE, "Invalid number of arguments expected 2, found " + std::to_string(args.size()));
}
uint32 advancementId = std::stoi(args[0]);
uint32 advancementId, diceLevel;
try {
advancementId = std::stoi(args[0]);
} catch (const std::exception& e) {
return SendEventError(player, EventName(), MP_EVENT_CODE::INVALID_ARGUMENT, "Invalid advancement id format: " + args[0]);
}
if(advancementId >= MpAdvancements::MP_ADV_MAX) {
return SendEventError(player, EventName(),MP_EVENT_CODE::INVALID_ARGUMENT, "Invalid advancement id " + args[0] + " max is " + std::to_string(MpAdvancements::MP_ADV_MAX));
return SendEventError(player, EventName(), MP_EVENT_CODE::INVALID_ARGUMENT, "Invalid advancement id " + args[0] + " max valid id is " + std::to_string(MpAdvancements::MP_ADV_MAX - 1));
}
uint32 diceLevel = std::stoi(args[1]);
try {
diceLevel = std::stoi(args[1]);
} catch (const std::exception& e) {
return SendEventError(player, EventName(), MP_EVENT_CODE::INVALID_ARGUMENT, "Invalid dice level format: " + args[1]);
}
if(diceLevel < 1 || diceLevel > 3) {
return SendEventError(player, EventName(),MP_EVENT_CODE::INVALID_ARGUMENT, "Invalid dice level " + args[1] + " valid values are 1,2,3");
return SendEventError(player, EventName(), MP_EVENT_CODE::INVALID_ARGUMENT, "Invalid dice level " + args[1] + " valid values are 1,2,3");
}
uint32 itemEntry1 = std::stoi(args[2]);
if(itemEntry1 == 0) {
return SendEventError(player, EventName(),MP_EVENT_CODE::INVALID_ARGUMENT, "Invalid item entry1 can not be empty " + args[2]);
}
uint32 itemEntry2 = std::stoi(args[3]);
uint32 itemEntry3 = std::stoi(args[4]);
uint32 increase;
try {
increase = sAdvancementMgr->UpgradeAdvancement(player, static_cast<MpAdvancements>(advancementId), diceLevel, itemEntry1, itemEntry2, itemEntry3);
if( increase == 0) {
return SendEventError(player, EventName(),MP_EVENT_CODE::INVALID_ARGUMENT, "Failed to upgrade advancement invalid request see error logs for player " + player->GetName());
increase = sAdvancementMgr->UpgradeAdvancement(player, static_cast<MpAdvancements>(advancementId), diceLevel);
if(increase == 0) {
return SendEventError(player, EventName(), MP_EVENT_CODE::INVALID_ARGUMENT, "Failed to upgrade advancement invalid request see error logs for player " + player->GetName());
}
} catch(const std::exception& e) {
return SendEventError(player, EventName(),MP_EVENT_CODE::FAILED_UPGRADE_ADV, "Failed to upgrade: " + std::string(e.what()) + " for player " + player->GetName());
return SendEventError(player, EventName(), MP_EVENT_CODE::FAILED_UPGRADE_ADV, "Failed to upgrade: " + std::string(e.what()) + " for player " + player->GetName());
}
// Only proceed to here if no errors occurred
MpPlayerRank* playerRank = sAdvancementMgr->GetPlayerAdvancementRank(player, static_cast<MpAdvancements>(advancementId));
if (!playerRank) {
return SendEventError(player, EventName(), MP_EVENT_CODE::INVALID_ARGUMENT, "Failed to get advancement rank for player " + player->GetName());
}
// Format the success event data for client increase|newrank|bonus
eventData = {
@@ -164,9 +171,15 @@ class GetPlayerRank : public MpEventInterface
return SendEventError(player, EventName(),MP_EVENT_CODE::INVALID_ARGUMENT_SIZE, "Invalid number of arguments expected 1, found " + std::to_string(args.size()));
}
uint32 advancementId = std::stoi(args[0]);
uint32 advancementId;
try {
advancementId = std::stoi(args[0]);
} catch (const std::exception& e) {
return SendEventError(player, EventName(), MP_EVENT_CODE::INVALID_ARGUMENT, "Invalid advancement id format: " + args[0]);
}
if(advancementId >= MpAdvancements::MP_ADV_MAX) {
return SendEventError(player, EventName(),MP_EVENT_CODE::INVALID_ARGUMENT, "Invalid advancement id " + args[0] + " max is " + std::to_string(MpAdvancements::MP_ADV_MAX));
return SendEventError(player, EventName(),MP_EVENT_CODE::INVALID_ARGUMENT, "Invalid advancement id " + args[0] + " max valid id is " + std::to_string(MpAdvancements::MP_ADV_MAX - 1));
}
MpPlayerRank* playerRank = sAdvancementMgr->GetPlayerAdvancementRank(player, static_cast<MpAdvancements>(advancementId));
@@ -206,16 +219,27 @@ class GetAdvancementRank : public MpEventInterface {
bool Execute(Player* player, std::vector<std::string>& args) override
{
if(args.size() != 3) {
return SendEventError(player, EventName(),MP_EVENT_CODE::INVALID_ARGUMENT_SIZE, "Invalid number of arguments expected 3, found " + std::to_string(args.size()));
if(args.size() != 2) {
return SendEventError(player, EventName(),MP_EVENT_CODE::INVALID_ARGUMENT_SIZE, "Invalid number of arguments expected 2, found " + std::to_string(args.size()));
}
uint32 advancementId = std::stoi(args[0]);
uint32 advancementId, rank;
try {
advancementId = std::stoi(args[0]);
} catch (const std::exception& e) {
return SendEventError(player, EventName(), MP_EVENT_CODE::INVALID_ARGUMENT, "Invalid advancement id format: " + args[0]);
}
if(advancementId >= MpAdvancements::MP_ADV_MAX) {
return SendEventError(player, EventName(),MP_EVENT_CODE::INVALID_ARGUMENT, "Invalid advancement id " + args[0] + " max is " + std::to_string(MpAdvancements::MP_ADV_MAX));
return SendEventError(player, EventName(),MP_EVENT_CODE::INVALID_ARGUMENT, "Invalid advancement id " + args[0] + " max valid id is " + std::to_string(MpAdvancements::MP_ADV_MAX - 1));
}
uint32 rank = std::stoi(args[1]);
try {
rank = std::stoi(args[1]);
} catch (const std::exception& e) {
return SendEventError(player, EventName(), MP_EVENT_CODE::INVALID_ARGUMENT, "Invalid rank format: " + args[1]);
}
if(rank == 0) {
return SendEventError(player, EventName(),MP_EVENT_CODE::INVALID_ARGUMENT, "Invalid rank " + args[1] + " can not be empty");
}
@@ -251,7 +275,7 @@ class GetAdvancementRank : public MpEventInterface {
void MP_Register_EventHandlers()
{
sMpEventProcessor->RegisterHandler(MpEvent::UpgradeAdvancement, std::make_shared<UpdateAdvancements>());
sMpEventProcessor->RegisterHandler(MpEvent::UpgradeAdvancement, std::make_shared<UpgradeAdvancements>());
sMpEventProcessor->RegisterHandler(MpEvent::GetPlayerRank, std::make_shared<GetPlayerRank>());
sMpEventProcessor->RegisterHandler(MpEvent::GetAdvancementRank, std::make_shared<GetAdvancementRank>());
}

View File

@@ -68,7 +68,7 @@ bool MpEventProcessor::Dispatch(MpEvent event, Player* player, std::vector<std::
if(!_eventHandlers.contains(event)) {
// Send a client message back also to the player
std::vector<std::string> clientError = { std::to_string(static_cast<int>(event)), "No handler registered for event: " + std::to_string(static_cast<int>(event)) };
std::vector<std::string> clientError = { "Error", "No handler registered for event: " + std::to_string(static_cast<int>(event)) };
sMpClientDispatcher->Dispatch(MpClientEvent::Error, player, clientError);
MpLogger::warn("No handler registered for event: {}", event);
return false;

View File

@@ -1,11 +1,112 @@
#ifndef MP_CONSTANTS_H
#define MP_CONSTANTS_H
#include "AdvancementMgr.h"
namespace MpConstants
{
// Spell IDs for passive stat and resist bonuses
constexpr int TITANS_STRENGTH_AURA = 80000001; // strength
constexpr int STEEL_FORGED_AURA = 80000002; // stamina
constexpr int CELESTIAL_GRACE_AURA = 80000003; // spirit
constexpr int FORBIDDEN_KNOWLEDGE_AURA = 80000004; // intellect
constexpr int SPECTRAL_REFLEXES_AURA = 80000005; // agility
constexpr int ELDRITCH_BARRIER_AURA = 80000006; // arcane resistance
constexpr int HELLFIRE_SHIELDING_AURA = 80000007; // fire resistance
constexpr int PRIMAL_ENDURACE_AURA = 80000008; // nature resistance
constexpr int LICHS_BANE_AURA = 80000009; // shadow resistance
constexpr int GLACIAL_FORTRESS_AURA = 80000010; // frost resistance
/**
* @brief Adds a static method for looking up the corect advancement aura based on the advancement type.
*
* @param advancement
* @return int
*/
static int GetAdvancementAura(MpAdvancements advancement)
{
switch (advancement)
{
case MpAdvancements::MP_ADV_INTELLECT:
return MpConstants::FORBIDDEN_KNOWLEDGE_AURA;
case MpAdvancements::MP_ADV_SPIRIT:
return MpConstants::CELESTIAL_GRACE_AURA;
case MpAdvancements::MP_ADV_STRENGTH:
return MpConstants::TITANS_STRENGTH_AURA;
case MpAdvancements::MP_ADV_AGILITY:
return MpConstants::SPECTRAL_REFLEXES_AURA;
case MpAdvancements::MP_ADV_STAMINA:
return MpConstants::STEEL_FORGED_AURA;
case MpAdvancements::MP_ADV_RESIST_ARCANE:
return MpConstants::ELDRITCH_BARRIER_AURA;
case MpAdvancements::MP_ADV_RESIST_FIRE:
return MpConstants::HELLFIRE_SHIELDING_AURA;
case MpAdvancements::MP_ADV_RESIST_NATURE:
return MpConstants::PRIMAL_ENDURACE_AURA;
case MpAdvancements::MP_ADV_RESIST_FROST:
return MpConstants::GLACIAL_FORTRESS_AURA;
case MpAdvancements::MP_ADV_RESIST_SHADOW:
return MpConstants::LICHS_BANE_AURA;
default:
return 0;
}
}
// Spells used for learning how to make items used for advancement.
constexpr int SPELL_ORE_FUSION = 150000;
constexpr int SPELL_CLOTH_FUSION = 150001;
constexpr int SPELL_LEATHER_FUSION = 150002;
constexpr int SPELL_ALCHEMY_FUSION = 150003;
constexpr int SPELL_GEM_FUSION = 150004;
constexpr int SPELL_ESSENCE_FUSION = 150005;
constexpr int SPELL_COLD_FUSION = 150006;
constexpr int SPELL_FLAME_FUSION = 150007;
constexpr int SPELL_ARCANE_FUSION = 150008;
constexpr int SPELL_DARK_FUSION = 150009;
constexpr int SPELL_EARTH_FUSION = 150010;
constexpr int SPELL_ORE_FUSION_RANK_2 = 150011;
constexpr int SPELL_CLOTH_FUSION_RANK_2 = 150012;
constexpr int SPELL_LEATHER_FUSION_RANK_2 = 150013;
constexpr int SPELL_ALCHEMY_FUSION_RANK_2 = 150014;
constexpr int SPELL_GEM_FUSION_RANK_2 = 150015;
constexpr int SPELL_ESSENCE_FUSION_RANK_2 = 150016;
constexpr int SPELL_COLD_FUSION_RANK_2 = 150017;
constexpr int SPELL_FLAME_FUSION_RANK_2 = 150018;
constexpr int SPELL_ARCANE_FUSION_RANK_2 = 150019;
constexpr int SPELL_DARK_FUSION_RANK_2 = 150020;
constexpr int SPELL_EARTH_FUSION_RANK_2 = 150021;
// New dropping unique items for mythic plus
constexpr int ANCIENT_DICE = 911000;
constexpr int DARK_SPIKE = 911001;
constexpr int DARK_SPIKE = 911001;
constexpr int VEILSTONE = 911002;
// Item IDs for fused materials used in advancement crafting
constexpr int FUSED_RARE_ORE = 911003;
constexpr int FUSED_MYTHIC_ORE = 911004;
constexpr int FUSED_RARE_CLOTH = 911005;
constexpr int FUSED_MYTHIC_CLOTH = 911006;
constexpr int FUSED_RARE_LEATHER = 911007;
constexpr int FUSED_MYTHIC_LEATHER = 911008;
constexpr int FUSED_RARE_ALCHEMY = 911009;
constexpr int FUSED_MYTHIC_ALCHEMY = 911010;
constexpr int FUSED_RARE_GEM = 911011;
constexpr int FUSED_MYTHIC_GEM = 911012;
constexpr int FUSED_RARE_ESSENCE = 911013;
constexpr int FUSED_MYTHIC_ESSENCE = 911014;
constexpr int FUSED_RARE_ICE_STONE = 911015;
constexpr int FUSED_MYTHIC_ICE_STONE = 911016;
constexpr int FUSED_RARE_INFERNAL_STONE = 911017;
constexpr int FUSED_MYTHIC_INFERNAL_STONE = 911018;
constexpr int FUSED_RARE_ARCANE_CRYSTAL = 911019;
constexpr int FUSED_MYTHIC_ARCANE_CRYSTAL = 911020;
constexpr int FUSED_RARE_DARK_CRYSTAL = 911021;
constexpr int FUSED_MYTHIC_DARK_CRYSTAL = 911022;
constexpr int FUSED_RARE_EARTH_STONE = 911023;
constexpr int FUSED_MYTHIC_EARTH_STONE = 911024;
// Shadowy Remains
constexpr int SHADOWY_REMAINS = 911100;
}
#endif

View File

@@ -135,7 +135,7 @@ void MpDataStore::RemoveGroupData(Group *group) {
MpLogger::debug("RemoveGroupData for group {}", group->GetGUID().GetCounter());
_groupData->erase(group->GetGUID());
CharacterDatabase.Execute("DELETE FROM group_difficulty WHERE guid = {}) ", group->GetGUID().GetCounter());
CharacterDatabase.Execute("DELETE FROM group_difficulty WHERE guid = {}", group->GetGUID().GetCounter());
}
// Adds PlayerData related to MythicRun Status to map
@@ -173,7 +173,7 @@ void MpDataStore::RemoveInstanceData(uint32 mapId, uint32 instanceId) {
void MpDataStore::AddCreatureData(ObjectGuid guid, MpCreatureData creatureData) {
// MpLogger::debug("AddInstanceCreatureData for creature {}", guid.GetCounter());
_instanceCreatureData->emplace(guid, creatureData);
_instanceCreatureData->insert_or_assign(guid, std::move(creatureData));
}
MpCreatureData* MpDataStore::GetCreatureData(ObjectGuid guid) {
@@ -220,45 +220,61 @@ MpScaleFactor MpDataStore::GetScaleFactor(int32 mapId, int32 difficulty) const {
return _scaleFactors->at(key);
}
// Just send back untouched bonus database will override.
return MpScaleFactor{
.dmgBonus = 3,
.healthBonus = 2,
.maxDamageBonus = 30
.meleeBonus = 1.0f,
.spellBonus = 1.0f,
.healBonus = 1.0f,
.healthBonus = 1.0f
};
}
int32 MpDataStore::GetHealthScaleFactor(int32 mapId, int32 difficulty) const {
float MpDataStore::GetHealthScaleFactor(int32 mapId, int32 difficulty) const {
return GetScaleFactor(mapId, difficulty).healthBonus;
}
int32 MpDataStore::GetDamageScaleFactor(int32 mapId, int32 difficulty) const {
return GetScaleFactor(mapId, difficulty).dmgBonus;
float MpDataStore::GetMeleeScaleFactor(int32 mapId, int32 difficulty) const {
return GetScaleFactor(mapId, difficulty).meleeBonus;
}
int32 MpDataStore::GetSpellScaleFactor(int32 mapId, int32 difficulty) const {
float MpDataStore::GetSpellScaleFactor(int32 mapId, int32 difficulty) const {
return GetScaleFactor(mapId, difficulty).spellBonus;
}
int32 MpDataStore::GetMaxDamageScaleFactor(int32 mapId, int32 difficulty) const {
return GetScaleFactor(mapId, difficulty).maxDamageBonus;
float MpDataStore::GetHealScaleFactor(int32 mapId, int32 difficulty) const {
return GetScaleFactor(mapId, difficulty).healBonus;
}
void MpDataStore::SetHealthScaleFactor(int32 mapId, int32 difficulty, int32 newValue) {
uint32 MpDataStore::GetPlayerHealthAvg(uint32 level) const {
if (_playerHealthAvg.contains(level)) {
return _playerHealthAvg.at(level);
}
return 0;
}
void MpDataStore::SetHealScaleFactor(int32 mapId, int32 difficulty, float newValue) {
auto key = GetScaleFactorKey(mapId, difficulty);
if (_scaleFactors && _scaleFactors->contains(key)) {
_scaleFactors->at(key).healBonus = newValue;
}
}
void MpDataStore::SetHealthScaleFactor(int32 mapId, int32 difficulty, float newValue) {
auto key = GetScaleFactorKey(mapId, difficulty);
if (_scaleFactors && _scaleFactors->contains(key)) {
_scaleFactors->at(key).healthBonus = newValue;
}
}
void MpDataStore::SetDamageScaleFactor(int32 mapId, int32 difficulty, int32 newValue) {
void MpDataStore::SetMeleeScaleFactor(int32 mapId, int32 difficulty, float newValue) {
auto key = GetScaleFactorKey(mapId, difficulty);
if (_scaleFactors && _scaleFactors->contains(key)) {
_scaleFactors->at(key).dmgBonus = newValue;
_scaleFactors->at(key).meleeBonus = newValue;
}
}
void MpDataStore::SetSpellScaleFactor(int32 mapId, int32 difficulty, int32 newValue) {
void MpDataStore::SetSpellScaleFactor(int32 mapId, int32 difficulty, float newValue) {
auto key = GetScaleFactorKey(mapId, difficulty);
if (_scaleFactors && _scaleFactors->contains(key)) {
_scaleFactors->at(key).spellBonus = newValue;
@@ -269,7 +285,7 @@ int32 MpDataStore::LoadScaleFactors() {
_scaleFactors->clear();
// 0 1 2 3 4 5
QueryResult result = WorldDatabase.Query("SELECT mapId, dmg_bonus, spell_bonus, hp_bonus, difficulty, max FROM mp_scale_factors");
QueryResult result = WorldDatabase.Query("SELECT mapId, melee_bonus, spell_bonus, heal_bonus, hp_bonus, difficulty FROM mp_scale_factors");
if (!result) {
MpLogger::error("Failed to load mythic scale factors from database");
return 0;
@@ -278,17 +294,17 @@ int32 MpDataStore::LoadScaleFactors() {
do {
Field* fields = result->Fetch();
uint32 mapId = fields[0].Get<uint32>();
int32 damageBonus = fields[1].Get<int32>();
int32 spellBonus = fields[2].Get<int32>();
int32 healthBonus = fields[3].Get<int32>();
int32 difficulty = fields[4].Get<int32>();
int32 maxDamageBonus = fields[5].Get<int32>();
float meleeBonus = fields[1].Get<float>();
float spellBonus = fields[2].Get<float>();
float healBonus = fields[3].Get<float>();
float healthBonus = fields[4].Get<float>();
int32 difficulty = fields[5].Get<int32>();
MpScaleFactor scaleFactor = {
.dmgBonus = damageBonus,
.healthBonus = healthBonus,
.meleeBonus = meleeBonus,
.spellBonus = spellBonus,
.maxDamageBonus = maxDamageBonus
.healBonus = healBonus,
.healthBonus = healthBonus
};
_scaleFactors->emplace(GetScaleFactorKey(mapId, difficulty), scaleFactor);
@@ -298,6 +314,45 @@ int32 MpDataStore::LoadScaleFactors() {
return int32(_scaleFactors->size());
}
void MpDataStore::LoadPlayerHealthAvg() {
_playerHealthAvg.clear();
std::string_view query = R"(
SELECT
Level,
ROUND(CASE
WHEN Level BETWEEN 1 AND 30 THEN ((AVG(Stamina) - 20) * 10 + AVG(BaseHP) + 20) * 1.5
WHEN Level BETWEEN 31 AND 50 THEN ((AVG(Stamina) - 20) * 10 + AVG(BaseHP) + 20) * 1.7
WHEN Level BETWEEN 51 AND 59 THEN ((AVG(Stamina) - 20) * 10 + AVG(BaseHP) + 20) * 2.0
WHEN Level BETWEEN 60 AND 69 THEN ((AVG(Stamina) - 20) * 10 + AVG(BaseHP) + 20) * 2.3
WHEN Level BETWEEN 70 AND 79 THEN ((AVG(Stamina) - 20) * 10 + AVG(BaseHP) + 20) * 2.6
WHEN Level BETWEEN 80 AND 84 THEN ((AVG(Stamina) - 20) * 10 + AVG(BaseHP) + 20) * 3.0
WHEN Level >= 85 THEN ((AVG(Stamina) - 20) * 10 + AVG(BaseHP) + 20) * 4.0
ELSE ((AVG(Stamina) - 20) * 10 + AVG(BaseHP) + 20)
END) AS BaseHealth
FROM
player_class_stats
GROUP BY
Level
ORDER BY
Level;
)";
if (QueryResult result = WorldDatabase.Query(query.data())) {
do {
Field* fields = result->Fetch();
uint32 level = fields[0].Get<uint32>();
uint32 baseHealth = fields[1].Get<uint32>();
_playerHealthAvg[level] = baseHealth;
} while (result->NextRow());
} else {
MpLogger::error("Failed to load player health averages from database");
}
}
/**
* Database Calls below for storing player data.
* @todo refactor to use prepared statements

View File

@@ -143,17 +143,22 @@ struct MpGroupData
};
/**
* @brief Struct used for internal scaling of mythic+ difficulty. Fine-tuned in
* database.
*/
struct MpScaleFactor
{
int32 dmgBonus;
int32 healthBonus;
int32 spellBonus;
int32 maxDamageBonus;
float meleeBonus;
float spellBonus;
float healBonus;
float healthBonus;
std::string ToString() const {
return "MpScaleFactor: { dmgBonus: " + std::to_string(dmgBonus) +
return "MpScaleFactor: { meleeBonus: " + std::to_string(meleeBonus) +
", healthBonus: " + std::to_string(healthBonus) +
", spellBonus: " + std::to_string(spellBonus) + "}";
", spellBonus: " + std::to_string(spellBonus) +
", healBonus: " + std::to_string(healBonus) + "}";
}
};
@@ -211,6 +216,7 @@ struct MpCreatureData
{
Creature* creature;
bool scaled;
DeathState lastDeathState; // used to determine if a creature has been respawned
// AttackPower calculated based on settings
uint32 NewAttackPower;
@@ -220,6 +226,7 @@ struct MpCreatureData
// Original information about the creature that was altered.
uint8 originalLevel;
uint32 originalInstanceHealth; // Health the creature would have in instance before Mythic+ scaling
CreatureBaseStats const* originalStats;
MpDifficulty difficulty;
@@ -229,7 +236,7 @@ struct MpCreatureData
std::vector<std::string> affixes;
MpCreatureData(Creature* creature)
: creature(creature), scaled(false)
: creature(creature), scaled(false), originalInstanceHealth(0)
{
if(creature) {
originalLevel = creature->GetLevel();
@@ -237,6 +244,9 @@ struct MpCreatureData
originalLevel,
creature->GetCreatureTemplate()->unit_class
);
originalInstanceHealth = creature->GetMaxHealth();
}
auras.reserve(3);
@@ -259,7 +269,7 @@ struct MpCreatureData
std::string origStatsStr;
if(originalStats) {
uint32 health = *originalStats->BaseHealth;
uint32 health = originalInstanceHealth;
uint32 mana = originalStats->BaseMana;
uint32 armor = originalStats->BaseArmor;
uint32 ap = originalStats->AttackPower;
@@ -323,6 +333,10 @@ private:
// use to mimic pattern normals scale to heroic (loaded at server start)
std::unique_ptr<std::map<std::pair<int32,int32>,MpScaleFactor>> _scaleFactors; // {mapId,difficulty}
// Player mapping of level to average amount of health for that level, this is used for scaling against
// percentages to more consistently scale damage from spells and healing from creatures.
std::unordered_map<uint32, uint32> _playerHealthAvg; // level -> avg health
// Single creature multipliers used to scale creatures individually that may need tuned up or down.
// std::unique_ptr<std::unordered_map<uint32, CreatureOverride>> _creatureOverrides;
@@ -377,15 +391,19 @@ public:
std::vector<MpCreatureData*> GetUnscaledCreatures(uint32 mapId, uint32 instanceId);
// Scale factors are used to determine a base bonus for enemies base on the instance difficulty
int32 GetHealthScaleFactor(int32 mapId, int32 difficulty) const;
int32 GetDamageScaleFactor(int32 mapId, int32 difficulty) const;
int32 GetMaxDamageScaleFactor(int32 mapId, int32 difficulty) const;
int32 GetSpellScaleFactor(int32 mapId, int32 difficulty) const;
float GetHealthScaleFactor(int32 mapId, int32 difficulty) const;
float GetMeleeScaleFactor(int32 mapId, int32 difficulty) const;
float GetSpellScaleFactor(int32 mapId, int32 difficulty) const;
float GetHealScaleFactor(int32 mapId, int32 difficulty) const;
MpScaleFactor GetScaleFactor(int32 mapId, int32 difficulty) const;
void SetDamageScaleFactor(int32 mapId, int32 difficulty, int32 value);
void SetHealthScaleFactor(int32 mapId, int32 difficulty, int32 value);
void SetSpellScaleFactor(int32 mapId, int32 difficulty, int32 value);
void SetMeleeScaleFactor(int32 mapId, int32 difficulty, float value);
void SetHealthScaleFactor(int32 mapId, int32 difficulty, float value);
void SetSpellScaleFactor(int32 mapId, int32 difficulty, float value);
void SetHealScaleFactor(int32 mapId, int32 difficulty, float value);
// Retrieves the average players hp pool for a player level
uint32 GetPlayerHealthAvg(uint32 level) const;
// Individual Creature Scaling Multipliers
// void AddCreatureOverride(uint32 entry, CreatureOverride* override);
@@ -401,6 +419,9 @@ public:
// Used at initial server load
int32 LoadScaleFactors();
// Load the player health average from the database
void LoadPlayerHealthAvg();
// Database API calls
void DBUpdatePlayerInstanceData(ObjectGuid playerGuid, MpDifficulty difficulty, uint32 mapId = 0, uint32 instanceId = 0, uint32 deaths = 0);

View File

@@ -143,9 +143,13 @@ bool MythicPlus::IsCreatureEligible(Creature* creature)
#if defined(MOD_PRESENT_NPCBOTS)
// Safely check if the creature is an NPC Bot
if (creature->IsNPCBot()) {
MpLogger::debug("Creature {} is an NPC Bot, do not scale", creature->GetName());
return false;
}
if(creature->GetBotOwner()) {
return false;
}
#endif
// Check for NPC-related flags (vendor, gossip, quest giver, trainer, etc.)
@@ -181,6 +185,10 @@ void MythicPlus::AddCreatureForScaling(Creature* creature)
void MythicPlus::AddScaledCreature(Creature* creature, MpInstanceData* instanceData)
{
MpCreatureData creatureData = MpCreatureData(creature);
creatureData.SetScaled(true);
creatureData.SetDifficulty(instanceData->difficulty);
creatureData.lastDeathState = creature->getDeathState();
sMpDataStore->AddCreatureData(creature->GetGUID(), creatureData);
// allow small variance in level for non-boss creatures
@@ -197,24 +205,7 @@ void MythicPlus::AddScaledCreature(Creature* creature, MpInstanceData* instanceD
// We know the creature is scaled and in the instance to fire the event.
// sCreatureHooks->AddToInstance(creature);
std::string name = creature->GetName();
// Assign random affix for now.
if (roll_chance_i(50)) {
uint32 irand = urand(0, 2);
if(irand == 0) {
creature->AddAura(23341, creature);
} else if(irand == 1) {
creature->AddAura(34711, creature);
} else {
creature->AddAura(774, creature);
}
}
creatureData.SetScaled(true);
creatureData.SetDifficulty(instanceData->difficulty);
// MpLogger::debug("Scaled Creature {} Entry {} Id {} level from {} to {}",
// creature->GetName(),
@@ -237,7 +228,10 @@ void MythicPlus::ScaleAll(Player* player, MpInstanceData* instanceData)
{
std::vector<MpCreatureData*> creatures = sMpDataStore->GetInstanceCreatures(player->GetMapId(), player->GetInstanceId());
for (MpCreatureData* creatureData : creatures) {
ScaleCreature(creatureData->creature->GetLevel(), creatureData->creature, &instanceData->creature, instanceData->difficulty);
// Only scale living creatures
if (creatureData->creature && creatureData->creature->IsAlive()) {
ScaleCreature(creatureData->creature->GetLevel(), creatureData->creature, &instanceData->creature, instanceData->difficulty);
}
}
}
@@ -254,16 +248,23 @@ void MythicPlus::RemoveCreature(Creature* creature)
void MythicPlus::ScaleCreature(uint8 level, Creature* creature, MpMultipliers* multipliers, MpDifficulty difficulty)
{
uint32 origLevel = creature->GetLevel();
CreatureTemplate const* cInfo = creature->GetCreatureTemplate();
uint32 mapId = creature->GetMapId();
// get the map difficulty from the map instance to see if it is a heroic or normal set instance
InstanceMap *instanceMap = creature->GetMap()->ToInstanceMap();
if (!instanceMap) {
MpLogger::error("Invalid instance map ScaleCreature()");
return;
}
creature->SetLevel(level);
CreatureBaseStats const* stats = sObjectMgr->GetCreatureBaseStats(
level,
cInfo->unit_class
);
// Scale the creatures base health
uint32 basehp = stats->BaseHealth[EXPANSION_WRATH_OF_THE_LICH_KING];
uint32 health = CalculateNewHealth(creature, cInfo, mapId, difficulty, basehp, multipliers->health);
@@ -276,6 +277,7 @@ void MythicPlus::ScaleCreature(uint8 level, Creature* creature, MpMultipliers* m
/**
* @TODO: Figure out mana later for unit_types 2 and 8
*/
// Scale the creatures mana pool
uint32 mana = uint32(std::ceil(stats->BaseMana * cInfo->ModMana));
creature->SetCreateMana(mana);
creature->SetMaxPower(POWER_MANA, mana);
@@ -290,29 +292,31 @@ void MythicPlus::ScaleCreature(uint8 level, Creature* creature, MpMultipliers* m
}
MpInstanceData *instanceData = sMpDataStore->GetInstanceData(creature->GetMapId(), creature->GetInstanceId());
int32 meleeDamage = sMpDataStore->GetDamageScaleFactor(creature->GetMapId(), instanceData->difficulty);
if(creature->IsDungeonBoss() || creature->GetEntry() == 23682) {
// Give the boss an increase in casting speed.
creature->SetFloatValue(UNIT_MOD_CAST_SPEED, 1.20f);
// Handle new melee/range scaling with simple formula (for simplicity range will just be 80% of melee bonus)
float meleeMultiplier = sMpDataStore->GetMeleeScaleFactor(creature->GetMapId(), instanceData->difficulty);
// Since Heroic Scaling can get out of hand. Reduce the instance multiplier by way too much 10%
if(instanceMap->IsHeroic() || instanceMap->Is25ManRaid()) {
// if the enemy is a boss reduce it by less
meleeMultiplier *= 0.9f;
}
// Calculate the level difference
float levelDifference = creature->GetLevel() - origLevel;
// Scale up the attack power based on the instance set in the database difficulty table.
uint32 ap = std::ceil(stats->AttackPower * meleeMultiplier);
uint32 rangeAp = std::ceil(stats->RangedAttackPower * meleeMultiplier * 0.4f);
// New formula with adjusted divisor for smoother scaling
float scalingFactor;
uint32 ap = uint32(sMythicPlus->meleeAttackPowerStart - sMythicPlus->meleeAttackPowerDampener);
uint32 rangeAp = irand(215, 357);
scalingFactor = CalculateScaling(levelDifference, meleeDamage);
ap = uint32(stats->AttackPower * scalingFactor);
rangeAp = uint32(rangeAp * scalingFactor);
// Additionally need to add in a decrease in attack power for normal non elite enemies
if (creature->GetCreatureTemplate()->rank == CREATURE_ELITE_NORMAL) {
// Reduced scaling for elite/boss spells to prevent them from hitting too hard
ap *= normalEnemyReducer;
rangeAp *= normalEnemyReducer;
}
MpCreatureData* creatureData = sMpDataStore->GetCreatureData(creature->GetGUID());
if(creatureData) {
creatureData->NewAttackPower = ap;
creatureData->AttackPowerScaleMultiplier = scalingFactor;
creatureData->AttackPowerScaleMultiplier = meleeMultiplier;
}
// Set scaled attack power
@@ -321,7 +325,10 @@ void MythicPlus::ScaleCreature(uint8 level, Creature* creature, MpMultipliers* m
// set the base weapon damage
creature->SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, stats->BaseDamage[EXPANSION_WRATH_OF_THE_LICH_KING], 0);
creature->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, stats->BaseDamage[EXPANSION_WRATH_OF_THE_LICH_KING], 0);
creature->SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, stats->BaseDamage[EXPANSION_WRATH_OF_THE_LICH_KING] * 1.5f, 0);
creature->SetBaseWeaponDamage(RANGED_ATTACK, MINDAMAGE, stats->BaseDamage[EXPANSION_WRATH_OF_THE_LICH_KING] * 0.5f, 0);
creature->SetBaseWeaponDamage(RANGED_ATTACK, MAXDAMAGE, stats->BaseDamage[EXPANSION_WRATH_OF_THE_LICH_KING] * 0.8f, 0);
// Update all stats to apply the new damage values
creature->UpdateAllStats();
@@ -330,154 +337,311 @@ void MythicPlus::ScaleCreature(uint8 level, Creature* creature, MpMultipliers* m
uint32 armor = uint32(std::ceil(stats->BaseArmor * multipliers->armor * cInfo->ModArmor));
creature->SetArmor(armor);
float updatedAp = creature->GetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE);
float updatedRangeAp = creature->GetModifierValue(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE);
MpLogger::debug("Updated Attack Powers: {} {}", updatedAp, updatedRangeAp);
}
int32 MythicPlus::ScaleDamageSpell(SpellInfo const * spellInfo, uint32 damage, MpCreatureData* creatureData, Creature* creature, Unit* target, float damageMultiplier)
{
int32 MythicPlus::CalculateSpellDamage(uint32 baseDamage, int originalLevel, int targetLevel) {
float origHpPool = sMpDataStore->GetPlayerHealthAvg(originalLevel);
float targetHpPool = sMpDataStore->GetPlayerHealthAvg(targetLevel);
// Using a % of expected damage of the average player pool creates a better consistent experience when scaling spells
float percentDamage = baseDamage / origHpPool;
// If the percentage damage is less than 2% cap it at 2% to prevent spells from being too powerful
if(percentDamage < 0.02f) {
percentDamage = 0.02f;
}
MpLogger::debug("OrigHpPool: {} TargetHpPool: {} Percent Damage: {}", origHpPool, targetHpPool, percentDamage);
MpLogger::debug("Original Damage: {} Scaled Damage: {}", baseDamage, static_cast<int32>(std::ceil(percentDamage * targetHpPool)));
int32 scaledDamage = static_cast<int32>(std::ceil(percentDamage * targetHpPool));
return scaledDamage;
}
int32 MythicPlus::CalculateHealScaling(uint32 baseHeal, uint32 originalTargetHealth, uint32 targetMaxHealth) {
if (originalTargetHealth == 0) {
MpLogger::debug("Original target health is 0, returning base heal: {}", baseHeal);
return baseHeal;
}
// Calculate the percentage of the original heal relative to original creature health
float percentHeal = static_cast<float>(baseHeal) / static_cast<float>(originalTargetHealth);
if (percentHeal < 0.01f) {
percentHeal = 0.01f;
}
// Cap the percentage at 100% aka full heal of current max health of caster
if (percentHeal > 1.0f) {
percentHeal = 1.0f;
}
// Scale the heal based on the current creature's max health
int32 scaledHeal = static_cast<int32>(std::ceil(percentHeal * targetMaxHealth));
MpLogger::debug("HEALING: >>> OrigHealth: {} CurrentMaxHealth: {} Percent Heal: {} Original Heal: {} Scaled Heal: {}",
originalTargetHealth, targetMaxHealth, percentHeal, baseHeal, scaledHeal);
return scaledHeal;
}
int32 MythicPlus::ScaleDamageSpell(SpellInfo const * spellInfo, uint32 damage, MpCreatureData* creatureData, Creature* creature, Unit* /* target */, float damageMultiplier)
{
if (!spellInfo) {
MpLogger::error("Invalid spell info ScaleDamageSpell()");
return damage;
}
if(!creatureData) {
// this is probably a summoned object or totem so going to cheat here and just use the flat modifer
// Handle totems that do some nasty things to us Slave Pens anyone
if(creature->IsTotem()) {
Unit* owner = creature->GetOwner();
if(owner) {
float lvlDmgBonus = float(85 - owner->GetLevel() / 10.0f);
return int32(damage * lvlDmgBonus * damageMultiplier);
} else {
return damage * damageMultiplier;
}
}
MpLogger::error("Invalid creature data ScaleDamageSpell()");
return damage * damageMultiplier;
}
if(!creature) {
MpLogger::error("Invalid creature ScaleDamageSpell()");
return damage * damageMultiplier;
}
int32 originalLevel = creatureData->originalLevel;
MpInstanceData *instanceData = sMpDataStore->GetInstanceData(creature->GetMapId(), creature->GetInstanceId());
int32 spellBonus = sMpDataStore->GetSpellScaleFactor(creature->GetMapId(), instanceData->difficulty);
// if((creature->IsDungeonBoss() && creature->isElite()) || creature->GetEntry() == 23682) {
// spellBonus *= 1.15;
// }
// Calculate the level difference
float levelDifference = creature->GetLevel() - originalLevel;
// New formula with adjusted divisor for smoother scaling
// float scalingFactor = 1 + (std::log2(levelDifference + 1) * (float(spellBonus)));
float scalingFactor = CalculateScaling(levelDifference, spellBonus);
// float scalingFactor = pow(float((creature->GetLevel() - originalLevel) / 10.0f ), float(spellBonus) / 5.0f);
// MpLogger::debug("Creature {} original level: {} New Level{} and Scaling level {}", creature->GetName(), originalLevel, creature->GetLevel(), scalingFactor);
int32 totalDamage = 0;
auto effects = spellInfo->GetEffects();
for (uint8 i = 0; i < effects.size(); ++i)
{
SpellEffectInfo effect = effects[i];
if(effect.IsAura()) {
switch(spellInfo->Effects[i].ApplyAuraName) {
case SPELL_AURA_PERIODIC_DAMAGE:
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
case SPELL_AURA_POWER_BURN:
case SPELL_AURA_PERIODIC_LEECH:
case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
case SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE:
case SPELL_AURA_PERIODIC_DUMMY:
case SPELL_AURA_DUMMY:
totalDamage += effect.CalcValue(creature, nullptr, target);
break;
default:
break;
}
} else {
switch(effect.Effect)
{
case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
case SPELL_EFFECT_WEAPON_DAMAGE:
case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
return damage;
case SPELL_EFFECT_SCHOOL_DAMAGE:
case SPELL_EFFECT_ENVIRONMENTAL_DAMAGE:
case SPELL_EFFECT_POWER_BURN:
case SPELL_EFFECT_HEALTH_LEECH:
case SPELL_EFFECT_TRIGGER_SPELL:
case SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE:
case SPELL_EFFECT_DUMMY:
totalDamage += effect.CalcValue(creature, nullptr, target);
break;
default:
break;
}
}
}
if(totalDamage == 0) {
if (!instanceData) {
MpLogger::debug("No instance data found for spell scaling, using original damage");
return damage;
}
MpLogger::debug(" >>> Spell {} damage scaled from for spell New Damage: {} using: scaling Factor: {} and damage Multi: {}",spellInfo->SpellName[0], totalDamage, scalingFactor, damageMultiplier);
float scaleFactor = sMpDataStore->GetSpellScaleFactor(creature->GetMapId(), instanceData->difficulty);
// Apply scaling factor and the set multiplier from the instance data
totalDamage = int32(totalDamage * scalingFactor * damageMultiplier);
MpLogger::debug("DAMAGE SPELL: >> ScaleFactor: {} DamageMultiplier: {}", scaleFactor, damageMultiplier);
// MpLogger::debug("Spell {} damage scaled from for spell New Damage: {} using: scaling Factor: {} and damage Multi: {}",spellInfo->SpellName[0], totalDamage, scalingFactor, damageMultiplier);
return totalDamage;
// calculate the global modifier x instance modifier
float totalModifier = damageMultiplier * scaleFactor;
// If for some reason there is not a creature, just use the global modifier x instance modifier
if(!creature) {
MpLogger::error("Invalid creature ScaleDamageSpell()");
return damage * totalModifier;
}
// Use the already calculated damage as the base for scaling
int32 newDamage = damage;
// Handle Summoned unit modifiers as
if(!creatureData) {
// handle if bot pets if NPCBot is installed.
#ifdef NPCBOT
if(creature->IsNPCBotOrPet()) {
return damage;
}
#endif
// Handle totems and summons - scale based on owner's details because they will not have creature data
if(creature->IsTotem() || creature->IsSummon()) {
Unit* owner = creature->GetOwner();
if(owner && owner->IsCreature()) {
Creature* ownerCreature = owner->ToCreature();
// Look up the owner creature's original level from MpDataStore
MpCreatureData* ownerCreatureData = sMpDataStore->GetCreatureData(ownerCreature->GetGUID());
if (ownerCreatureData) {
MpLogger::debug("DAMAGE SPELL: >> Creature is a totem or summon Creature Name {} and owner {} owner original level {} owner level {}", creature->GetName(), ownerCreature->GetName(), ownerCreatureData->originalLevel, ownerCreature->GetLevel());
int32 ownerOriginalLevel = ownerCreatureData->originalLevel;
if (ownerCreature->GetCreatureTemplate()->rank == CREATURE_ELITE_NORMAL) {
totalModifier = totalModifier * normalEnemyReducer;
}
newDamage = CalculateSpellDamage(damage, ownerOriginalLevel, ownerCreature->GetLevel());
} else {
// Fallback if no creature data found - use current level
if(ownerCreature->GetCreatureTemplate()->rank == CREATURE_ELITE_NORMAL) {
totalModifier = totalModifier * normalEnemyReducer;
}
newDamage = CalculateSpellDamage(damage, ownerCreature->GetLevel(), ownerCreature->GetLevel());
MpLogger::debug("No creature data found for owner {}, using current level for scaling", ownerCreature->GetGUID().ToString());
}
}
}
else {
MpLogger::error("Invalid creature data ScaleDamageSpell()");
return damage * totalModifier;
}
} else {
newDamage = CalculateSpellDamage(damage, creatureData->originalLevel, creature->GetLevel());
if (creature->GetCreatureTemplate()->rank == CREATURE_ELITE_NORMAL) {
// Reduced scaling for elite/boss spells to prevent them from hitting too hard
totalModifier = totalModifier * 0.85f;
}
}
// Calculate the additional damage from scaling (scaled damage - original damage)
int32 additionalDamage = newDamage - damage;
// Apply the scaling modifier to the additional damage only
int32 scaledAdditionalDamage = additionalDamage * totalModifier;
// Use the diminishing return values from the configuration
uint32 threshold = sMythicPlus->diminishingThresholds[instanceData->difficulty];
float diminishingExponent = sMythicPlus->diminishingExponent;
// Apply diminishing returns only to the additional scaled damage if it exceeds threshold
if (static_cast<uint32>(scaledAdditionalDamage) > threshold) {
// Calculate the diminished excess additional damage
float excess = scaledAdditionalDamage - threshold;
float diminishedExcess = pow(excess, diminishingExponent);
scaledAdditionalDamage = threshold + diminishedExcess;
MpLogger::debug("DAMAGE SPELL: >> Above Diminishing Threshold for Spell {} - Original: {}, Additional: {}, Diminished Additional: {}, Final: {}",
spellInfo->SpellName[0], damage, additionalDamage * totalModifier, scaledAdditionalDamage, damage + scaledAdditionalDamage);
} else {
MpLogger::debug("DAMAGE SPELL: >> Below Diminishing Threshold for Spell {} - Original: {}, Additional: {}, Final: {}",
spellInfo->SpellName[0], damage, scaledAdditionalDamage, damage + scaledAdditionalDamage);
}
// If this is a heroic instance the additional spell damage should be increased by 50%
InstanceMap* instanceMap = creature->GetMap()->ToInstanceMap();
if (instanceMap && (instanceMap->IsHeroic() || instanceMap->Is25ManRaid())) {
scaledAdditionalDamage = scaledAdditionalDamage * 1.5f;
}
// Return original damage + scaled additional damage (with potential diminishing returns)
return damage + scaledAdditionalDamage;
}
int32 MythicPlus::ScaleHealSpell(SpellInfo const * spellInfo, uint32 heal, MpCreatureData* creatureData, Creature* creature, Creature* /* target */, float healMultiplier)
int32 MythicPlus::ScaleHealSpell(SpellInfo const * spellInfo, uint32 heal, MpCreatureData* creatureData, Creature* creature, Creature* target, float healMultiplier)
{
if (!spellInfo) {
MpLogger::error("Invalid spell info ScaleHealSpell()");
return 0;
return heal;
}
if(!creatureData) {
MpLogger::error("Invalid creature data ScaleHealSpell()");
return 0;
MpInstanceData *instanceData = sMpDataStore->GetInstanceData(creature->GetMapId(), creature->GetInstanceId());
if (!instanceData) {
MpLogger::debug("No instance data found for heal scaling, using original heal");
return heal;
}
float scaleFactor = sMpDataStore->GetHealScaleFactor(creature->GetMapId(), instanceData->difficulty);
MpLogger::debug("HEALING: >>> HealScaleFactor: {} HealMultiplier: {}", scaleFactor, healMultiplier);
// calculate the global modifier x instance modifier
float totalModifier = healMultiplier * scaleFactor;
// If for some reason there is not a creature, just use the global modifier x instance modifier
if(!creature) {
MpLogger::error("Invalid creature ScaleHealSpell()");
return 0;
return heal * totalModifier;
}
auto effects = spellInfo->GetEffects();
for (uint8 i = 0; i < effects.size(); ++i)
{
MpLogger::debug(" >>> Spell {} effect {} value: {} by creature {}", spellInfo->SpellName[i], effects[i].Effect, heal, creature->GetName());
// Use the already calculated heal as the base for scaling
int32 newHeal = heal;
// Handle Summoned unit modifiers
if(!creatureData) {
// handle if bot pets if NPCBot is installed.
#ifdef NPCBOT
if(creature->IsNPCBotOrPet()) {
return heal;
}
#endif
MpLogger::debug("HEALING: >>> Scaling heal to target: {} with spell: {}", target->GetName(), spellInfo->SpellName[0]);
// Handle totems and summons - scale based on owner's details because they will not have creature data
if(creature->IsTotem() || creature->IsSummon()) {
Unit* owner = creature->GetOwner();
if(owner && owner->IsCreature()) {
Creature* ownerCreature = owner->ToCreature();
// Look up the owner creature's original level from MpDataStore
MpCreatureData* ownerCreatureData = sMpDataStore->GetCreatureData(ownerCreature->GetGUID());
if (ownerCreatureData) {
if (ownerCreature->GetCreatureTemplate()->rank == CREATURE_ELITE_NORMAL) {
totalModifier = totalModifier * normalEnemyReducer; // Less reduction for heals than damage
}
// Scale heal based on target's health, not caster's health
if (target) {
MpCreatureData* targetCreatureData = sMpDataStore->GetCreatureData(target->GetGUID());
uint32 targetOriginalHealth = targetCreatureData && targetCreatureData->originalInstanceHealth > 0 ?
targetCreatureData->originalInstanceHealth : target->GetMaxHealth();
MpLogger::debug("HEALING: >>> Scaling heal to target: {} Original Instance Health: {} New Health: {}", target->GetName(), targetOriginalHealth, target->GetMaxHealth());
newHeal = CalculateHealScaling(heal, targetOriginalHealth, target->GetMaxHealth());
} else {
newHeal = heal;
}
} else {
// Fallback if no creature data found - use current level
if(ownerCreature->GetCreatureTemplate()->rank == CREATURE_ELITE_NORMAL) {
totalModifier = totalModifier * normalEnemyReducer; // Less reduction for heals than damage
}
// Scale heal based on target's health, not caster's health
if (target) {
MpCreatureData* targetCreatureData = sMpDataStore->GetCreatureData(target->GetGUID());
uint32 targetOriginalHealth = targetCreatureData && targetCreatureData->originalInstanceHealth > 0 ?
targetCreatureData->originalInstanceHealth : target->GetMaxHealth();
MpLogger::debug("HEALING: >>> Scaling heal to target: {} Original Instance Health: {} New Health: {}", target->GetName(), targetOriginalHealth, target->GetMaxHealth());
newHeal = CalculateHealScaling(heal, targetOriginalHealth, target->GetMaxHealth());
} else {
newHeal = heal;
}
MpLogger::debug("No creature data found for owner {}, using current level for scaling", ownerCreature->GetGUID().ToString());
}
}
}
else {
MpLogger::error("Invalid creature data ScaleHealSpell()");
return heal * totalModifier;
}
} else {
// Scale heal based on target's health, not caster's health
if (target) {
// Get target's original instance health for scaling comparison
MpCreatureData* targetCreatureData = sMpDataStore->GetCreatureData(target->GetGUID());
uint32 targetOriginalHealth = targetCreatureData && targetCreatureData->originalInstanceHealth > 0 ?
targetCreatureData->originalInstanceHealth : target->GetMaxHealth();
MpLogger::debug("HEALING: >>> Scaling heal to target: {} Original Instance Health: {} New Health: {}", target->GetName(), targetOriginalHealth, target->GetMaxHealth());
newHeal = CalculateHealScaling(heal, targetOriginalHealth, target->GetMaxHealth());
} else {
// No target available, use original heal
newHeal = heal;
}
}
int32 originalLevel = creatureData->originalLevel;
// Calculate the additional heal from scaling (scaled heal - original heal)
int32 additionalHeal = newHeal - heal;
float levelDifference = creature->GetLevel() - originalLevel;
float spellBonus = sMpDataStore->GetSpellScaleFactor(creature->GetMapId(), creature->GetInstanceId());
// Apply the scaling modifier to the additional heal only
int32 scaledAdditionalHeal = additionalHeal * totalModifier;
float scalingFactor = CalculateScaling(levelDifference, spellBonus, 2.5f);
// Use the diminishing return values from the configuration (same as damage)
uint32 threshold = sMythicPlus->diminishingThresholds[instanceData->difficulty];
float diminishingExponent = sMythicPlus->diminishingExponent;
MpLogger::debug(" >>> Spell {} healed scaled from for spell New Heal: {} using: scaling Factor: {} and damage Multi: {}",spellInfo->SpellName[0], heal, scalingFactor, healMultiplier);
return int32(heal * scalingFactor * healMultiplier);
// Apply diminishing returns only to the additional scaled heal if it exceeds threshold * 2 since enemies have much more health.
if (scaledAdditionalHeal > threshold * 2.0f) {
// Calculate the diminished excess additional heal
float excess = scaledAdditionalHeal - threshold;
float diminishedExcess = pow(excess, diminishingExponent * 0.95f); // slightly reduce the diminishing returns for heals
scaledAdditionalHeal = threshold + diminishedExcess;
MpLogger::debug("HEALING: >>> Above Diminishing Threshold for Heal Spell {} - Original: {}, Additional: {}, Diminished Additional: {}, Final: {}",
spellInfo->SpellName[0], heal, additionalHeal * totalModifier, scaledAdditionalHeal, heal + scaledAdditionalHeal);
} else {
MpLogger::debug("HEALING: >>> Below Diminishing Threshold for Heal Spell {} - Original: {}, Additional: {}, Final: {}",
spellInfo->SpellName[0], heal, scaledAdditionalHeal, heal + scaledAdditionalHeal);
}
// If this is a heroic instance the additional heal be only slightly increased
InstanceMap* instanceMap = creature->GetMap()->ToInstanceMap();
if (instanceMap && (instanceMap->IsHeroic() || instanceMap->Is25ManRaid())) {
scaledAdditionalHeal = scaledAdditionalHeal * 1.15f;
}
// Return original heal + scaled additional heal (with potential diminishing returns)
return heal + scaledAdditionalHeal;
}
void MythicPlus::GroupReset(Group* /*group*/, Map* /* map */) {
// Stubbed out for later implementation
}
bool MythicPlus::IsFinalBoss(Creature* creature) {
std::array<uint32, 128> finalBosses = {
// --- WoW Classic Dungeons ---
@@ -638,46 +802,87 @@ float GetTypeHealthModifier(int32 Rank)
// This takes the orignal health and scales flat based on the factor then applies the configuration modifier from the conf file
uint32 CalculateNewHealth(Creature* creature, CreatureTemplate const* cInfo, uint32 mapId, MpDifficulty difficulty, uint32 origHealth, float confHPMod)
{
//
int32 rank = 0;
if(cInfo && cInfo->rank > 0) {
rank = cInfo->rank;
}
// These Factors that increase or decrease health based on different settings applied to the creature
// Health Variation is used to create some random element to HP so not all creatures of the same level
// have the same HP for more variety.
float healthVariation;
// if(creature->IsPet() || creature->IsSummon() || creature->IsTotem()) {
// return origHealth;
// }
// This is the fine grained hpScaleFactor set for the instance (and/or) creature overrides in the database.
int32 hpScaleFactor = sMpDataStore->GetHealthScaleFactor(mapId, difficulty);
// Add some variance to the healthpool so enemies are not all the same
if(creature->IsDungeonBoss() || creature->GetEntry() == HEADLESS_HORSEMAN || creature->isWorldBoss()) { // Is a boss of some kind
healthVariation = frand(1.1f, 1.2f);
} else if(creature->isElite() || cInfo->rank == CREATURE_ELITE_RARE) { // Is Elite Mob
healthVariation = frand(1.0f, 1.10f);
hpScaleFactor *= 0.90;
} else if(creature->IsSummon() || creature->IsPet() || creature->IsTotem()) { // Is a pet or summon
if(creature->IsDungeonBoss() || creature->isWorldBoss() || creature->isElite() || cInfo->rank == CREATURE_ELITE_RARE) {
healthVariation = frand(1.0f, 1.15f);
} else { // This addresses Normals and other trash from getting to big a HP bonus
healthVariation = frand(1.0f, 1.05f);
hpScaleFactor *= 0.65;
} else {
hpScaleFactor *= 0.50;
}
// Add in special overrides here as necessary:
if(creature->GetEntry() == HEADLESS_HORSEMAN) {
healthVariation = frand(1.0f, 1.1f);
hpScaleFactor *= 0.55;
}
float unitTypeMod = GetTypeHealthModifier(rank);
uint32 basehp = uint32(std::ceil(origHealth * unitTypeMod * healthVariation));
uint32 basehp;
// Only apply unitTypeMod for non-normal enemies
if (rank != CREATURE_ELITE_NORMAL) {
basehp = uint32(std::ceil(origHealth * healthVariation * unitTypeMod));
} else {
basehp = uint32(std::ceil(origHealth * healthVariation));
}
// if it is a heroic instance give the enemy an additional 20% boost
InstanceMap* instanceMap = creature->GetMap()->ToInstanceMap();
if (instanceMap && instanceMap->IsRaidOrHeroicDungeon()) {
basehp *= 1.25f;
}
/**
* @brief Calculating the final creature health encompasses all the potential modifiers
* CreatureTemplate.HealthModifier (ModHealth) - Creatures that are capable of being in a Heroic instance get a boost here
* even though they are the same. In this case we allow
*
* hpScaleFactor: allows to tweak the bonus modifier more directly at a creature or instance level, since
* you can not override it in cInfo directly as it is loaded statically from database
*
* confHPMod: is from the mythic settings directly.
*/
if(cInfo->ModHealth > 0.0f) {
return uint32(basehp * (cInfo->ModHealth + hpScaleFactor) * confHPMod);
} else {
return uint32(basehp * (hpScaleFactor) * confHPMod);
return uint32(basehp * hpScaleFactor * confHPMod);
}
}
// Calculates a logarithmic growth curve using scaling factor of percentages increase 50 = 1.5, 100 = 2.0,... this allows for fine grain tuning per instance.
float CalculateScaling(int levelDifference, float scaleFactor, float constant, float growthFactor) {
float scaling = constant * std::pow(2.0f, levelDifference / growthFactor) * (1 + (scaleFactor / 100.0f));
// Calculates a balanced growth curve that provides good scaling across all level ranges
float CalculateScaling(int levelDifference, float scaleFactor, float constant, float /*growthFactor*/) {
float levelMultiplier;
if (levelDifference <= 0) {
// High-level creatures need a minimum boost
levelMultiplier = 1.5f; // Minimum 50% boost for near-level or higher creatures
} else if (levelDifference <= 10) {
// Moderate scaling for small level differences
levelMultiplier = 1.5f + (levelDifference * 0.2f); // 1.5x to 3.5x
} else if (levelDifference <= 30) {
// Higher scaling for medium level differences
levelMultiplier = 3.5f + ((levelDifference - 10) * 0.15f); // 3.5x to 6.5x
} else {
// Cap extreme scaling for very low level creatures
levelMultiplier = 6.5f + std::min((levelDifference - 30) * 0.05f, 3.5f); // Cap at 10x
}
float scaling = constant * levelMultiplier * (1 + (scaleFactor / 100.0f));
return scaling;
}
@@ -699,4 +904,3 @@ float GetTypeDamageModifier(int32 Rank)
return sWorld->getRate(RATE_CREATURE_ELITE_ELITE_DAMAGE);
}
}

View File

@@ -69,10 +69,20 @@ public:
uint32 legendaryItemOffset;
uint32 ascendantItemOffset;
// Scaling modifiers
// Scaling modifiers (Deprecated)
uint32 meleeAttackPowerDampener;
uint32 meleeAttackPowerStart;
// Spell Damage Diminishing Returns
float diminishingExponent;
std::unordered_map<MpDifficulty, uint32> diminishingThresholds;
// Specialized variables used in calculations
float elementalMeleeReducer;
float normalEnemyReducer;
float nonCreatureSpellReducer;
enum MP_UNIT_EVENT_TYPE
{
UNIT_EVENT_MELEE,
@@ -132,6 +142,12 @@ public:
// This scales a heal spell up based on the how much % the original heal spell was
int32 ScaleHealSpell(SpellInfo const * spellInfo, uint32 heal, MpCreatureData* creatureData, Creature* creature, Creature* target, float healMultiplier);
// Calculate spell damage based on player health pools
int32 CalculateSpellDamage(uint32 baseDamage, int originalLevel, int targetLevel);
// Calculate heal scaling based on creature health percentages
int32 CalculateHealScaling(uint32 baseHeal, uint32 originalHealth, uint32 currentMaxHealth);
static bool IsFinalBoss(Creature* creature);
static void GroupReset(Group* group, Map* map);
@@ -146,6 +162,8 @@ float CalculateScaling(int levelDifference, float scaleFactor, float constant =
uint32 CalculateNewHealth(Creature* creature, CreatureTemplate const* cInfo, uint32 mapId, MpDifficulty difficulty, uint32 origHealth, float confHPMod);
float CalculateNewBaseDamage(CreatureTemplate const* cInfo, uint32 mapId, MpDifficulty difficulty, float origDamage);
#define sMythicPlus MythicPlus::instance()
#endif // MYTHICPLUS_H

View File

@@ -1,5 +1,6 @@
#include "MpScheduler.h"
#include "MpLogger.h"
#include "Spells/AdvancmentSpells.cpp"
// Creature Overrides
enum {
@@ -8,7 +9,6 @@ enum {
// This adds schedulers for use across scripts scoped to MythicPlus
void Add_MP_Schedulers() {
MpLogger::debug("Add_MP_Schedulers()");
new MpScheduler_WorldScript();
}
@@ -23,20 +23,25 @@ void Add_MP_UnitScripts();
void Add_MP_WorldScripts();
void Add_MP_PlayerMessageEvents();
// Spell Scripts
void AddSC_AdvancementSpells();
void Addmod_mythic_plusScripts() {
Add_MP_AllCreatureScripts();
Add_MP_AllMapScripts();
Add_MP_CommandScripts();
Add_MP_GlobalScripts();
// Add_MP_GroupScripts();
Add_MP_PlayerScripts();
Add_MP_UnitScripts();
Add_MP_WorldScripts();
Add_MP_Schedulers();
Add_MP_PlayerMessageEvents();
// new Ragefire_Bazzalan_Mythic();
// Spell Scripts
AddSC_AdvancementSpells();
// new Ragefire_Bazzalan_Mythic();
// Add_MP_GroupScripts();
// list of boss / creature event handlers
// new Ragefire_Bazzalan_Mythic(RAGEFIRE_BAZZALAN);

View File

@@ -7,6 +7,9 @@
class MythicPlus_AllCreatureScript : public AllCreatureScript
{
private:
std::unordered_map<ObjectGuid, uint32> m_creatureUpdateTimers;
public:
MythicPlus_AllCreatureScript() : AllCreatureScript("MythicPlus_AllCreatureScript") {}
@@ -14,9 +17,89 @@ public:
// {
// }
// void OnAllCreatureUpdate(Creature* creature, uint32 diff) override
// {
// }
void OnCreatureRespawn(Creature* creature)
{
Map* map = creature->GetMap();
if (!sMythicPlus->IsMapEligible(map)) {
return;
}
if (!sMythicPlus->IsCreatureEligible(creature)) {
return;
}
// If we have instance data, scale the creature, otherwise add it to be scaled later
if (MpInstanceData* instanceData = sMpDataStore->GetInstanceData(map->GetId(), map->GetInstanceId())) {
sMythicPlus->AddScaledCreature(creature, instanceData);
} else {
sMythicPlus->AddCreatureForScaling(creature);
}
}
/**
* @brief This hook runs every update for all creatures in the world.
* We only need to concern ourselves with creatures in the scope of our mythic+ instances.
* Need to detect the following changes:
* - Creature Death State - to trigger respawn scaling.
* - Other events where a creature enters the instance that is not scaled, then should be scaled up. Some special events normal enemies will be scripted
* to show up in encounters these will not trigger the OnCreatureAddWorld, because they were not during the initial load of the instance. (Though sometimes summons do trigger this?)
*
* @param creature
* @param diff
*/
void OnAllCreatureUpdate(Creature* creature, uint32 diff) override
{
// Skip any creatures not in an instance we are scaling first to avoid unnecessary work
if (!sMythicPlus->IsMapEligible(creature->GetMap())) {
return;
}
if (!sMythicPlus->IsCreatureEligible(creature)) {
return;
}
// throttle this check per creature to only run if more than 20ms has passed since last check
ObjectGuid creatureGuid = creature->GetGUID();
m_creatureUpdateTimers[creatureGuid] += diff;
if(m_creatureUpdateTimers[creatureGuid] < 20) {
return;
}
m_creatureUpdateTimers[creatureGuid] = 0;
auto instanceData = sMpDataStore->GetInstanceData(creature->GetMapId(), creature->GetInstanceId());
// no instance data yet means dont scale.
if(!instanceData) {
return;
}
MpCreatureData* creatureData = sMpDataStore->GetCreatureData(creature->GetGUID());
// this is a creature that was not scaled at instance load time, we need to scale it now.
if(!creatureData) {
MpLogger::debug("OnAllCreatureUpdate: Unknown Creature Add event scaling creature: {}", creature->GetName());
sMythicPlus->AddScaledCreature(creature, sMpDataStore->GetInstanceData(creature->GetMap()->GetId(), creature->GetMap()->GetInstanceId()));
return;
}
DeathState currentState = creature->getDeathState();
// record the death of our scaled creature
if(currentState == DeathState::Corpse && creatureData->lastDeathState != DeathState::Corpse) {
creatureData->lastDeathState = currentState;
return;
}
if(currentState == DeathState::Alive && creatureData->lastDeathState == DeathState::Corpse) {
MpLogger::debug("OnAllCreatureUpdate: Creature Death event scaling creature: {} level: {} guid: {} event: {}", creature->GetName(), creatureData->creature->GetLevel(), creature->GetGUID().ToString(), creature->getDeathState());
if(creature->IsDungeonBoss() || creature->GetEntry() == 23682) {
sMythicPlus->AddScaledCreature(creature, instanceData);
} else {
sMythicPlus->AddScaledCreature(creature, instanceData);
}
}
}
// When a new creature is added into a mythic+ map add it to the list of creatures to scale later.
void OnCreatureAddWorld(Creature* creature) override
@@ -32,6 +115,7 @@ public:
// if we have instance data about zone then just scale the creature otherwise add to be scaled once we do.
MpInstanceData* instanceData = sMpDataStore->GetInstanceData(map->GetId(), map->GetInstanceId());
if(instanceData) {
sMythicPlus->AddScaledCreature(creature, instanceData);
} else {

View File

@@ -157,7 +157,7 @@ public:
group->SetDungeonDifficulty(DUNGEON_DIFFICULTY_NORMAL);
}
else {
handler->PSendSysMessage("|cFFFF0000 Invalid difficulty level. Expected values are 'mythic', 'legendary', or 'ascendant'.");
handler->PSendSysMessage("|cFFFF0000 Invalid difficulty level. Expected values are 'normal', 'heroic', 'mythic', 'legendary', or 'ascendant'.");
return true;
}
@@ -311,8 +311,8 @@ public:
auto groupData = sMpDataStore->GetGroupData(player->GetGroup()->GetGUID());
if(groupData) {
uint32 value = std::stoi(args[0]);
sMpDataStore->SetDamageScaleFactor(player->GetMapId(), groupData->difficulty, value);
float value = std::stof(args[0]);
sMpDataStore->SetMeleeScaleFactor(player->GetMapId(), groupData->difficulty, value);
handler->PSendSysMessage(Acore::StringFormat("Melee scale factor set to: {}", value));
return true;
}
@@ -339,7 +339,7 @@ public:
auto groupData = sMpDataStore->GetGroupData(player->GetGroup()->GetGUID());
if(groupData) {
uint32 value = std::stoi(args[0]);
float value = std::stof(args[0]);
sMpDataStore->SetSpellScaleFactor(player->GetMapId(), groupData->difficulty, value);
handler->PSendSysMessage(Acore::StringFormat("Spell scale factor set to: {}", value));
return true;
@@ -367,7 +367,7 @@ public:
auto groupData = sMpDataStore->GetGroupData(player->GetGroup()->GetGUID());
if(groupData) {
uint32 value = std::stoi(args[0]);
float value = std::stof(args[0]);
sMpDataStore->SetHealthScaleFactor(player->GetMapId(), groupData->difficulty, value);
handler->PSendSysMessage(Acore::StringFormat("Health scale factor set to: {}", value));
return true;

View File

@@ -1,5 +1,6 @@
#include "MpLogger.h"
#include "MythicPlus.h"
#include "MpConstants.h"
#include "ScriptMgr.h"
#include "Player.h"
#include "Map.h"
@@ -11,7 +12,7 @@ public:
MythicPlus_GlobalScript() : GlobalScript("MythicPlus_GlobalScript") { }
// This adds the mythic+ item scaling to the loot table for enemies
void OnBeforeDropAddItem(Player const* player, Loot& /*loot*/, bool /*canRate*/, uint16 /*lootMode*/, LootStoreItem* LootStoreItem, LootStore const& store) override {
void OnBeforeDropAddItem(Player const* player, Loot& loot, bool /*canRate*/, uint16 /*lootMode*/, LootStoreItem* LootStoreItem, LootStore const& store) override {
if(LootStoreItem->itemid == 0) {
return;
@@ -44,8 +45,30 @@ public:
// get the item to scale up
ItemTemplate const* origItem = sObjectMgr->GetItemTemplate(LootStoreItem->itemid);
if (!origItem) {
MpLogger::warn("Item not found for itemid {} in OnBeforeDropAddItem()", LootStoreItem->itemid);
return;
// If there is not a scaled up item and the item is a below quality green then set an invalid item_id so it is not added to loot
ItemTemplate const* nonMythicItem = sObjectMgr->GetItemTemplate(LootStoreItem->itemid);
if (nonMythicItem->Quality < 2) {
LootStoreItem->itemid = 0;
return;
}
// otherwise roll a chance to see a shadowy remains item is provided instead only if there is not already a shadowy remains item on the corpse
bool hasShadowyRemains = false;
for (auto& item : loot.items) {
if(item.itemid == MpConstants::SHADOWY_REMAINS) {
hasShadowyRemains = true;
break;
}
}
if (!hasShadowyRemains) {
LootStoreItem->itemid = MpConstants::SHADOWY_REMAINS;
return;
} else {
LootStoreItem->itemid = 0;
return;
}
}
uint32 newItemId = origItem->ItemId + mythicSettings->itemOffset;

View File

@@ -7,6 +7,7 @@
#include "ScriptMgr.h"
#include "TaskScheduler.h"
#include "AdvancementMgr.h"
#include "Formulas.h"
class MythicPlus_PlayerScript : public PlayerScript
{
@@ -108,18 +109,107 @@ public:
// // ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID_BOSS_EMOTE, LANG_UNIVERSAL, nullptr, player, message);
// // player->GetSession()->SendPacket(&data);
// }
// map->ToInstanceMap()->Reset(0);
// );
// }
}
void OnBeforeLootMoney(Player* player, Loot* loot) override
{
if (!loot->sourceWorldObjectGUID.IsCreature()) return;
Creature* creature = player->GetMap()->GetCreature(loot->sourceWorldObjectGUID);
if (!creature) return;
#ifdef NPC_BOT
if(creature->IsNPCBotOrPet()) {
return;
}
#endif
// Check if this is a Mythic+ scaled creature
MpCreatureData* creatureData = sMpDataStore->GetCreatureData(creature->GetGUID());
if (!creatureData || !creatureData->IsScaled()) return;
// Different gold ranges based on creature rank
uint32 bossMinGold = 10000;
uint32 bossMaxGold = 13500;
uint32 minGold, maxGold;
// Determine gold range based on creature rank
if (creature->isWorldBoss() || creature->IsDungeonBoss())
{
// Boss: full range
minGold = bossMinGold;
maxGold = bossMaxGold;
}
else if (creature->GetCreatureTemplate()->rank == CREATURE_ELITE_RARE ||
creature->GetCreatureTemplate()->rank == CREATURE_ELITE_ELITE)
{
// Elite: 70% of boss range
minGold = uint32(bossMinGold * 0.7f);
maxGold = uint32(bossMaxGold * 0.7f);
}
else
{
// Normal: 40% of boss range
minGold = uint32(bossMinGold * 0.4f);
maxGold = uint32(bossMaxGold * 0.4f);
}
// Generate random gold amount in appropriate range
uint32 newGold = urand(minGold, maxGold);
// Apply server money rate
newGold = uint32(newGold * sWorld->getRate(RATE_DROP_MONEY));
loot->gold = newGold;
}
void OnGiveXP(Player* player, uint32& amount, Unit* victim, uint8 xpSource) override
{
if (xpSource != XPSOURCE_KILL || !victim) return;
Creature* creature = victim->ToCreature();
if (!creature) return;
#ifdef NPC_BOT
if(creature->IsNPCBotOrPet()) {
return;
}
#endif
// Check if this is a Mythic+ scaled creature
MpCreatureData* creatureData = sMpDataStore->GetCreatureData(creature->GetGUID());
if (!creatureData || !creatureData->IsScaled()) return;
// Recalculate XP using scaled level instead of original level
uint32 newBaseXP = Acore::XP::BaseGain(
player->GetLevel(),
creature->GetLevel(), // This is now the scaled level
GetContentLevelsForMapAndZone(creature->GetMapId(), creature->GetZoneId())
);
// Apply same modifiers as original calculation
float xpMod = 1.0f;
if (creature->isElite()) {
xpMod *= creature->GetMap()->IsDungeon() ? 2.75f : 2.0f;
}
xpMod *= creature->GetCreatureTemplate()->ModExperience;
amount = uint32(newBaseXP * xpMod * 1.5f); // flat bonus modifier for mythic dungeons
}
void OnLogin(Player* player) override
{
MpLogger::info("Player {} logged in", player->GetName());
// Load the player advancement data for the player when they login
sAdvancementMgr->LoadPlayerAdvancements(player);
// Cast all unique advancement spells
for(uint32 i = 1; i <= 10; ++i) {
uint32 spellId = 80000000 + i;
MpLogger::info("Casting spell {} to player {}", spellId, player->GetName());
player->AddAura(spellId, player);
}
}
// When a player is bound to an instance need to make sure they are saved in the data soure to retrieve later.

View File

@@ -2,12 +2,251 @@
#include "Player.h"
#include "MythicPlus.h"
#include "ScriptMgr.h"
#include "SpellAuraEffects.h"
class MythicPlus_UnitScript : public UnitScript
{
public:
MythicPlus_UnitScript() : UnitScript("MythicPlus_UnitScript", true) { }
private:
/**
* Handles damage from non-creature sources (GameObjects, Players, etc.)
* @tparam DamageType Type of damage (int32/float)
* @param target Target of the damage
* @param attacker The non-creature attacker (passed by reference and may be modified)
* @param damage Reference to damage value (will be modified)
* @param spellInfo The spell being cast
* @param eventType Type of event (spell/melee/etc)
*/
template<typename DamageType>
void HandleNonCreatureAttacker(Unit* target, Unit*& attacker, DamageType& damage,
SpellInfo const* spellInfo, MythicPlus::MP_UNIT_EVENT_TYPE eventType)
{
Map* map = target ? target->GetMap() : nullptr;
std::string attackerType = "nullptr";
std::string attackerName = "unknown";
uint32 entry = 0;
if (attacker) {
if (attacker->GetTypeId() == TYPEID_GAMEOBJECT) {
attackerType = "GameObject";
if (GameObject* go = attacker->ToGameObject()) {
entry = go->GetEntry();
if (GameObjectTemplate const* goInfo = go->GetGOInfo()) {
attackerName = goInfo->name;
}
}
} else if (attacker->GetTypeId() == TYPEID_PLAYER) {
attackerType = "Player";
attackerName = attacker->GetName();
} else if (attacker->GetTypeId() == TYPEID_UNIT) {
attackerType = "Unit (non-creature)";
attackerName = attacker->GetName();
} else {
attackerType = "Unknown Type";
}
}
// Try to find a creature attacker from target's attackers list if we have one use it for scaling
Unit::AttackerSet const& attackers = target ? target->getAttackers() : Unit::AttackerSet();
if (!attackers.empty()) {
attacker = *attackers.begin();
if (Creature* creatureAttacker = attacker->ToCreature()) {
if (MpCreatureData* creatureData = sMpDataStore->GetCreatureData(creatureAttacker->GetGUID())) {
damage = static_cast<DamageType>(modifyIncomingDmgHeal(eventType, target, creatureAttacker,
static_cast<uint32>(damage), spellInfo)) * sMythicPlus->nonCreatureSpellReducer;
return;
}
} else {
MpLogger::debug("====== SPELL SCALING: Non-Creature attacker - Name: {}, Spell: {}({}), Damage: {}",
attackerName,
spellInfo ? spellInfo->SpellName[0] : "No Spell",
spellInfo ? spellInfo->Id : 0,
damage);
if (map) {
if (MpInstanceData* instanceData = sMpDataStore->GetInstanceData(map->GetId(), map->GetInstanceId())) {
damage = static_cast<DamageType>(damage * instanceData->creature.spell * sMythicPlus->nonCreatureSpellReducer);
return;
}
}
}
}
// Fallback to instance-based scaling if we can't find a nearest creature
else if (map) {
if (MpInstanceData* instanceData = sMpDataStore->GetInstanceData(map->GetId(), map->GetInstanceId())) {
damage = static_cast<DamageType>(damage * instanceData->creature.spell * sMythicPlus->nonCreatureSpellReducer);
return;
}
}
// Default scaling if no specific handler applied
return;
}
// Helper function to determine if a spell scales with Attack Power
bool IsAttackPowerScalingSpell(SpellInfo const* spellInfo) {
if (!spellInfo || spellInfo->Effects.empty()) {
return false;
}
auto mainEffect = spellInfo->Effects[0];
// Check 1: Direct weapon damage effects
bool isWeaponEffect = (mainEffect.Effect == SPELL_EFFECT_WEAPON_DAMAGE ||
mainEffect.Effect == SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL ||
mainEffect.Effect == SPELL_EFFECT_NORMALIZED_WEAPON_DMG ||
mainEffect.Effect == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE);
// Check 2: Damage class indicates melee/ranged (scales with AP)
bool isMeleeOrRanged = (spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE ||
spellInfo->DmgClass == SPELL_DAMAGE_CLASS_RANGED);
// Check 3: Requires weapon equipment
bool requiresWeapon = (spellInfo->EquippedItemClass == ITEM_CLASS_WEAPON);
// Check 4: Specific spell families known to scale with AP
bool isKnownAPSpell = false;
if (spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE) {
// Rogue poisons and weapon-based abilities
isKnownAPSpell = (spellInfo->SpellFamilyFlags[0] & 0x10000) || // Deadly Poison flag
(spellInfo->SpellFamilyFlags[1] & 0x80000); // Other poison flags
}
// Return true if any indicator suggests AP scaling
return (isWeaponEffect || isMeleeOrRanged || requiresWeapon || isKnownAPSpell);
}
/**
* @brief This functions processes spell damage for DOTs and Direct Damage Spells it
* handles special cases for Melee scaling spells and AP scaling spells also so they
* are not scaled up twice and murder all my friends
*
* @tparam DamageType
* @param target
* @param attacker
* @param damage
* @param spellInfo
* @param eventType
* @param logPrefix
*/
template<typename DamageType>
void ProcessSpellDamage(Unit* target, Unit* attacker, DamageType& damage, SpellInfo const* spellInfo, MythicPlus::MP_UNIT_EVENT_TYPE eventType, const std::string& logPrefix) {
if(damage == 0) {
return;
}
// If this is a special case where the attacker is not a creature
if (!attacker || !attacker->ToCreature()) {
return HandleNonCreatureAttacker(target, attacker, damage, spellInfo, eventType);
}
Creature* creatureCaster = attacker->ToCreature();
MpCreatureData* creatureData = sMpDataStore->GetCreatureData(creatureCaster->GetGUID());
if (!creatureCaster) {
MpLogger::error("Creature caster is null in map {}", attacker ? attacker->GetMap()->GetId() : 0);
return;
}
if (!creatureData) {
MpLogger::error("Failed to get creature data for {} in map {}", creatureCaster->GetName(), attacker ? attacker->GetMap()->GetId() : 0);
return;
}
// Check if this spell scales with Attack Power
if (IsAttackPowerScalingSpell(spellInfo)) {
// need another special case here to determine if a spell was not scaled up by AP meaning the incoming damage is close to the
// original effect of the spell and therefore should instead use spell effect scaling it should be no more than 15% of the original effect
bool notScaledByAP = false;
if (spellInfo && !spellInfo->Effects.empty()) {
int32 baseEffect = spellInfo->Effects[0].CalcValue(attacker, nullptr, nullptr);
if (damage <= (baseEffect * 1.15f)) {
// MpLogger::debug(">>>> MELEE SPELL SCALING: Spell {} (ID: {}) is not scaled by AP damage: {} vs originalEffect: {}",
// spellInfo->SpellName[0], spellInfo->Id, damage, baseEffect);
notScaledByAP = true;
}
} else {
// If we can't determine the base effect, default to treating it as not AP-scaled
notScaledByAP = true;
// MpLogger::debug(">>>> MELEE SPELL SCALING: Could not determine base effect for spell, defaulting to spell scaling");
}
// if the effect type of the spell is not physical (aka not mitigated by armor/defense) then it needs to instead have the typical
// spell damage multiplier applied instead of melee damage scaling
if (! notScaledByAP && (spellInfo->SchoolMask == SPELL_SCHOOL_NORMAL || spellInfo->SchoolMask == SPELL_SCHOOL_MASK_NORMAL)) {
uint32 meleeDamage = static_cast<uint32>(std::max(0, static_cast<int32>(damage)));
damage = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_MELEE, target, attacker, meleeDamage);
// MpLogger::debug(">>MELEE SPELL SCALING: {} hits with spell: {} ID: {} meleeDamage: {} damage: {}", attacker->GetName(), spellInfo->SpellName[0], spellInfo->Id, meleeDamage, damage);
} else {
// get the creatures original attack power
SpellEffectInfo const& effect = spellInfo->Effects[0];
uint32 spellDmg = static_cast<uint32>(effect.CalcValue(attacker, nullptr, nullptr) * effect.CalcDamageMultiplier(attacker, nullptr));
// now take the original attack power * 0.08 and add it to the spell damage
uint32 apDmg = static_cast<uint32>(creatureData->originalStats->AttackPower * 0.10f);
uint32 finalDmg = spellDmg + apDmg;
// MpLogger::debug(">> AP BASED DAMAGE Scaledown: origDamage: {} | spellDmg: {} | apDmg: {} | finalDmg: {}", static_cast<int32>(damage), spellDmg, apDmg, finalDmg);
damage = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_SPELL, target, attacker, finalDmg, spellInfo);
// need to take into consideration if this is a stacking spell and multiply the final damage by the number of stacks
if(spellInfo->AttributesEx3 & SPELL_ATTR3_DOT_STACKING_RULE) {
Aura* aura = target->GetAura(spellInfo->Id, attacker->GetGUID());
uint32 stacks = aura ? aura->GetStackAmount() : 1;
if(aura) {
damage *= stacks;
}
}
}
return;
}
// Reverse the CalcValue scaling to get original base damage
int32 originalDamage = static_cast<int32>(damage);
if (creatureCaster && creatureData && creatureData->originalLevel < 70) {
CreatureTemplate const* cInfo = creatureCaster->GetCreatureTemplate();
// Get the scaling factors used in CalcValue
CreatureBaseStats const* pCBS = sObjectMgr->GetCreatureBaseStats(creatureCaster->GetLevel(), creatureCaster->getClass());
float CBSPowerCreature = pCBS->BaseDamage[cInfo->expansion];
uint32 tempLevel = spellInfo->SpellLevel;
if(tempLevel == 0) {
tempLevel = creatureData->originalLevel;
}
CreatureBaseStats const* spellCBS = sObjectMgr->GetCreatureBaseStats(tempLevel, creatureCaster->getClass());
float CBSPowerSpell = spellCBS->BaseDamage[cInfo->expansion];
// MpLogger::debug("SPELL SCALING: Creature Lvl {} -> {} | Spell Lvl {} | tempLevel: {} | CBSPowerCreature: {} CBSPowerSpell: {}",
// creatureData->originalLevel, creatureCaster->GetLevel(), tempLevel, CBSPowerCreature, CBSPowerSpell);
// Reverse the CalcValue scaling: originalDamage = scaledDamage / (CBSPowerCreature / CBSPowerSpell)
if (CBSPowerCreature > 0.0f) {
originalDamage = static_cast<int32>(static_cast<int32>(damage) * (CBSPowerSpell / CBSPowerCreature));
// MpLogger::debug("SPELL SCALING: Reversed CalcValue scaling - Scaled: {} -> Original: {} (Factor: {:.2f})",
// damage, originalDamage, CBSPowerSpell / CBSPowerCreature);
}
}
// Apply Mythic+ scaling to the original base damage
damage = static_cast<DamageType>(modifyIncomingDmgHeal(eventType, target, attacker, static_cast<uint32>(originalDamage), spellInfo));
}
public:
void ModifyPeriodicDamageAurasTick(Unit* target, Unit* attacker, uint32& damage, SpellInfo const* spellInfo) override {
if (!target && !attacker) {
return;
@@ -32,16 +271,20 @@ public:
}
}
if(isHot) {
damage = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_HOT, target, attacker, damage, spellInfo);
} else {
damage = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_DOT, target, attacker, damage, spellInfo);
ProcessSpellDamage(target, attacker, damage, spellInfo, MythicPlus::UNIT_EVENT_DOT, "DOT DAMAGE");
}
}
void ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage, SpellInfo const* spellInfo) override {
if (!target && !attacker) {
if(spellInfo) {
// MpLogger::info("ModifySpellDamageTaken: Target and attacker are null for spell: {} ID: {}", spellInfo->SpellName[0], spellInfo->Id);
}
return;
}
@@ -50,11 +293,17 @@ public:
return;
}
if(sMythicPlus->EligibleDamageTarget(target)) {
MpLogger::debug("ModifySpellDamageTaken: {} hits {} with spell: {}", attacker->GetName(), target->GetName(), spellInfo->SpellName[0]);
if(!sMythicPlus->EligibleDamageTarget(target)) {
if(spellInfo) {
// MpLogger::info("ModifySpellDamageTaken: Target is not eligible for spell: {} ID: {}", spellInfo->SpellName[0], spellInfo->Id);
}
return;
}
damage = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_SPELL, target, attacker, damage, spellInfo);
// MpLogger::debug("ModifySpellDamageTaken: {} hits {} with spell: {} ID: {}", attacker ? attacker->GetName() : "[null]", target ? target->GetName() : "[null]", spellInfo ? spellInfo->SpellName[0] : "[no spell]", spellInfo ? spellInfo->Id : 0);
// Use the generic ProcessSpellDamage function
ProcessSpellDamage(target, attacker, damage, spellInfo, MythicPlus::UNIT_EVENT_SPELL, "SPELL DAMAGE");
}
/**
@@ -90,6 +339,7 @@ public:
uint32 modifyIncomingDmgHeal(MythicPlus::MP_UNIT_EVENT_TYPE eventType,Unit* target, Unit* attacker, uint32 damageOrHeal, SpellInfo const* spellInfo = nullptr) {
if (!target && !attacker) {
// MpLogger::info("modifyIncomingDmgHeal: Target and attacker are null for event {}", eventType);
return damageOrHeal;
}
@@ -105,7 +355,7 @@ public:
}
#if defined(MOD_PRESENT_NPCBOTS)
if (attacker && attacker->IsNPCBot()) {
if (attacker && attacker->IsNPCBotOrPet()) {
return damageOrHeal;
}
#endif
@@ -148,34 +398,42 @@ public:
*/
switch (eventType) {
case MythicPlus::UNIT_EVENT_MELEE:
if(creature->IsDungeonBoss() || creature->GetEntry() == 23682) {
// Damage that is not mitigated by armor needs to be debuffed as it hits too hard and without resists
// it hits too hard give everyone a benefit of 30% armor reduction
MpLogger::debug(">>> Modify Melee Damage: Creature Name: {} alteredDmgHeal: {} School Mask: {}", creature->GetName(), alteredDmgHeal, creature->GetMeleeDamageSchoolMask());
if(creature->GetMeleeDamageSchoolMask() != SPELL_SCHOOL_MASK_NORMAL && creature->GetMeleeDamageSchoolMask() != SPELL_SCHOOL_MASK_NONE) {
damageOrHeal = damageOrHeal * 0.50f;
}
if(creature->IsDungeonBoss() || creature->isWorldBoss() || creature->GetEntry() == 23682) {
alteredDmgHeal = damageOrHeal * instanceData->boss.melee;
} else {
alteredDmgHeal = damageOrHeal * instanceData->creature.melee;
}
MpLogger::debug("Incoming Melee New Damage: {}({}) {} hits {}", alteredDmgHeal, damageOrHeal, attacker->GetName(), target->GetName());
// MpLogger::debug(">>>>>>>>>>>> Incoming Melee New Damage: {}({}) {} hits {}", alteredDmgHeal, damageOrHeal, attacker->GetName(), target->GetName());
break;
case MythicPlus::UNIT_EVENT_DOT:
case MythicPlus::UNIT_EVENT_SPELL:
if(creature->IsDungeonBoss() || creature->GetEntry() == 23682) {
if(creature->IsDungeonBoss() || creature->isWorldBoss() || creature->GetEntry() == 23682) {
if(spellInfo) {
// MpLogger::debug("Scaling spell {} using ScaleDamageSpell() Original Damage: {} New Damage: {}", spellInfo->SpellName[0], damageOrHeal, alteredDmgHeal);
alteredDmgHeal = sMythicPlus->ScaleDamageSpell(spellInfo, damageOrHeal, sMpDataStore->GetCreatureData(attacker->GetGUID()), creature, target, instanceData->boss.spell);
} else {
alteredDmgHeal = damageOrHeal * instanceData->boss.spell;
// MpLogger::debug("Scaling spell {} using flat modifier Original Damage: {} New Damage: {}", spellInfo->SpellName[0], damageOrHeal, alteredDmgHeal);
}
} else {
if(spellInfo) {
// MpLogger::debug("Scaling spell {} using ScaleDamageSpell() Original Damage: {} New Damage: {}", spellInfo->SpellName[0], damageOrHeal, alteredDmgHeal);
alteredDmgHeal = sMythicPlus->ScaleDamageSpell(spellInfo, damageOrHeal, sMpDataStore->GetCreatureData(attacker->GetGUID()), creature, target, instanceData->creature.spell);
} else {
// MpLogger::debug("Scaling spell {} using flat modifier Original Damage: {} New Damage: {}", spellInfo->SpellName[0], damageOrHeal, alteredDmgHeal);
alteredDmgHeal = damageOrHeal * instanceData->creature.spell;
}
}
if(spellInfo) {
MpLogger::debug("Incoming spell New Damage: {}({}) {} hits {} spell: {} ID: {}", alteredDmgHeal, damageOrHeal, attacker->GetName(), target->GetName(), spellInfo->SpellName[0], spellInfo->Id);
} else {
MpLogger::debug("Incoming spell New Damage: {}({}) {} hits {}", alteredDmgHeal, damageOrHeal, attacker->GetName(), target->GetName());
}
break;
case MythicPlus::UNIT_EVENT_HEAL:
case MythicPlus::UNIT_EVENT_HOT:
@@ -189,18 +447,22 @@ public:
if(sMythicPlus->EligibleHealTarget(target) && (eventType == MythicPlus::UNIT_EVENT_HEAL || eventType == MythicPlus::UNIT_EVENT_HOT)) {
if(creature->IsDungeonBoss()) {
if(spellInfo) {
alteredDmgHeal = sMythicPlus->ScaleHealSpell(spellInfo, damageOrHeal, sMpDataStore->GetCreatureData(attacker->GetGUID()), creature, attacker->ToCreature(), instanceData->boss.spell);
alteredDmgHeal = sMythicPlus->ScaleHealSpell(spellInfo, damageOrHeal, sMpDataStore->GetCreatureData(attacker->GetGUID()), creature, attacker->ToCreature(), instanceData->boss.spell * 0.7f);
} else {
alteredDmgHeal = damageOrHeal * instanceData->boss.spell;
alteredDmgHeal = damageOrHeal * instanceData->boss.spell * 0.7f;
}
} else {
if(spellInfo) {
alteredDmgHeal = sMythicPlus->ScaleHealSpell(spellInfo, damageOrHeal, sMpDataStore->GetCreatureData(attacker->GetGUID()), creature, attacker->ToCreature(), instanceData->creature.spell);
alteredDmgHeal = sMythicPlus->ScaleHealSpell(spellInfo, damageOrHeal, sMpDataStore->GetCreatureData(attacker->GetGUID()), creature, attacker->ToCreature(), instanceData->creature.spell * 0.7f);
} else {
alteredDmgHeal = damageOrHeal * instanceData->creature.spell;
alteredDmgHeal = damageOrHeal * instanceData->creature.spell * 0.70f;
}
}
MpLogger::debug("Incoming heal: {}({}) {} hits {}", alteredDmgHeal, damageOrHeal, attacker->GetName(), target->GetName());
MpLogger::debug("Incoming heal: {}({}) {} hits {}",
alteredDmgHeal,
damageOrHeal,
attacker ? attacker->GetName() : "[null]",
target ? target->GetName() : "[null]");
}
return alteredDmgHeal > 0 ? alteredDmgHeal : damageOrHeal;

View File

@@ -89,8 +89,17 @@ public:
sMythicPlus->legendaryItemOffset = sConfigMgr->GetOption<uint32>("MythicPlus.Legendary.ItemOffset", 21000000);
sMythicPlus->ascendantItemOffset = sConfigMgr->GetOption<uint32>("MythicPlus.Ascendant.ItemOffset", 22000000);
sMythicPlus->meleeAttackPowerDampener = sConfigMgr->GetOption<uint32>("MythicPlus.MeleeAttackPowerDampener", 2000);
sMythicPlus->meleeAttackPowerStart = sConfigMgr->GetOption<uint32>("MythicPlus.MeleeAttackPowerStart", 10000);
// Get diminishing returns from configuration
sMythicPlus->diminishingExponent = sConfigMgr->GetOption<float>("MythicPlus.DiminishingExponent", 0.975f);
sMythicPlus->diminishingThresholds = {
{MpDifficulty::MP_DIFFICULTY_MYTHIC, sConfigMgr->GetOption<uint32>("MythicPlus.DiminishingThreshold.Mythic", 10000)},
{MpDifficulty::MP_DIFFICULTY_LEGENDARY, sConfigMgr->GetOption<uint32>("MythicPlus.DiminishingThreshold.Legendary", 20000)},
{MpDifficulty::MP_DIFFICULTY_ASCENDANT, sConfigMgr->GetOption<uint32>("MythicPlus.DiminishingThreshold.Ascendant", 40000)}
};
sMythicPlus->elementalMeleeReducer = sConfigMgr->GetOption<float>("MythicPlus.ElementalMeleeReducer", 0.50f);
sMythicPlus->normalEnemyReducer = sConfigMgr->GetOption<float>("MythicPlus.NormalEnemyReducer", 0.50f);
sMythicPlus->nonCreatureSpellReducer = sConfigMgr->GetOption<float>("MythicPlus.NonCreatureSpellReducer", 0.50f);
}
void OnStartup() override
@@ -104,6 +113,9 @@ public:
size = sAdvancementMgr->LoadMaterialTypes();
MpLogger::info("Loaded {} material types...", size);
sMpDataStore->LoadPlayerHealthAvg();
MpLogger::info("Loaded player health averages used for scaling calculations...");
// Registering event handlers for the Mythic+ events from client
MP_Register_EventHandlers();
MpLogger::info("Registered Mythic+ Event Handlers...");

View File

@@ -0,0 +1,277 @@
#include "CreatureScript.h"
#include "MpConstants.h"
#include "PetDefines.h"
#include "Player.h"
#include "AdvancementMgr.h"
#include "MpLogger.h"
#include "SpellAuraEffects.h"
#include "SpellInfo.h"
#include "SpellMgr.h"
#include "SpellScript.h"
#include "SpellScriptLoader.h"
#include "UnitAI.h"
#include "World.h"
class spell_mp_titans_strength_aura : public AuraScript
{
PrepareAuraScript(spell_mp_titans_strength_aura);
void HandleEffectCalcAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
Player* player = GetCaster()->ToPlayer();
auto rank = sAdvancementMgr->GetPlayerAdvancementRank(player, MpAdvancements::MP_ADV_STRENGTH);
if(!rank) {
amount = 0; // player does not have an advancement
return;
}
amount = static_cast<int32>(rank->bonus);
MpLogger::info("In Calc Amount Advancement Titans Strength to Player {} bonus {}", player->GetName(), amount);
}
void Register() override
{
MpLogger::info("Registering spell_mp_titans_strength_aura");
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_mp_titans_strength_aura::HandleEffectCalcAmount, EFFECT_0, SPELL_AURA_MOD_STAT);
}
};
class spell_mp_steel_forged_aura : public AuraScript
{
PrepareAuraScript(spell_mp_steel_forged_aura);
void HandleEffectCalcAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
Player* player = GetCaster()->ToPlayer();
auto rank = sAdvancementMgr->GetPlayerAdvancementRank(player, MpAdvancements::MP_ADV_STAMINA);
if(!rank) {
amount = 0; // player does not have an advancement
return;
}
amount = static_cast<int32>(rank->bonus);
MpLogger::info("In Calc Amount Advancement Steel Forged to Player {} bonus {}", player->GetName(), amount);
}
void Register() override
{
MpLogger::info("Registering spell_mp_steel_forged_aura");
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_mp_steel_forged_aura::HandleEffectCalcAmount, EFFECT_0, SPELL_AURA_MOD_STAT);
}
};
class spell_mp_celestial_grace_aura : public AuraScript
{
PrepareAuraScript(spell_mp_celestial_grace_aura);
void HandleEffectCalcAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
Player* player = GetCaster()->ToPlayer();
auto rank = sAdvancementMgr->GetPlayerAdvancementRank(player, MpAdvancements::MP_ADV_SPIRIT);
if(!rank) {
amount = 0; // player does not have an advancement
return;
}
amount = static_cast<int32>(rank->bonus);
MpLogger::info("In Calc Amount Advancement Celestial Grace to Player {} bonus {}", player->GetName(), amount);
}
void Register() override
{
MpLogger::info("Registering spell_mp_celestial_grace_aura");
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_mp_celestial_grace_aura::HandleEffectCalcAmount, EFFECT_0, SPELL_AURA_MOD_STAT);
}
};
class spell_mp_forbidden_knowledge_aura : public AuraScript
{
PrepareAuraScript(spell_mp_forbidden_knowledge_aura);
void HandleEffectCalcAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
Player* player = GetCaster()->ToPlayer();
auto rank = sAdvancementMgr->GetPlayerAdvancementRank(player, MpAdvancements::MP_ADV_INTELLECT);
if(!rank) {
amount = 0; // player does not have an advancement
return;
}
amount = static_cast<int32>(rank->bonus);
MpLogger::info("In Calc Amount Advancement Forbidden Knowledge to Player {} bonus {}", player->GetName(), amount);
}
void Register() override
{
MpLogger::info("Registering spell_mp_forbidden_knowledge_aura");
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_mp_forbidden_knowledge_aura::HandleEffectCalcAmount, EFFECT_0, SPELL_AURA_MOD_STAT);
}
};
class spell_mp_spectral_reflexes_aura : public AuraScript
{
PrepareAuraScript(spell_mp_spectral_reflexes_aura);
void HandleEffectCalcAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
Player* player = GetCaster()->ToPlayer();
auto rank = sAdvancementMgr->GetPlayerAdvancementRank(player, MpAdvancements::MP_ADV_AGILITY);
if(!rank) {
amount = 0; // player does not have an advancement
return;
}
amount = static_cast<int32>(rank->bonus);
MpLogger::info("In Calc Amount Advancement Spectral Reflexes to Player {} bonus {}", player->GetName(), amount);
}
void Register() override
{
MpLogger::info("Registering spell_mp_spectral_reflexes_aura");
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_mp_spectral_reflexes_aura::HandleEffectCalcAmount, EFFECT_0, SPELL_AURA_MOD_STAT);
}
};
class spell_mp_eldritch_barrier_aura : public AuraScript
{
PrepareAuraScript(spell_mp_eldritch_barrier_aura);
void HandleEffectCalcAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
Player* player = GetCaster()->ToPlayer();
auto rank = sAdvancementMgr->GetPlayerAdvancementRank(player, MpAdvancements::MP_ADV_RESIST_ARCANE);
if(!rank) {
amount = 0; // player does not have an advancement
return;
}
amount = static_cast<int32>(rank->bonus);
MpLogger::info("In Calc Amount Advancement Eldritch Barrier to Player {} bonus {}", player->GetName(), amount);
}
void Register() override
{
MpLogger::info("Registering spell_mp_eldritch_barrier_aura");
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_mp_eldritch_barrier_aura::HandleEffectCalcAmount, EFFECT_0, SPELL_AURA_MOD_RESISTANCE);
}
};
class spell_mp_hellfire_shielding_aura : public AuraScript
{
PrepareAuraScript(spell_mp_hellfire_shielding_aura);
void HandleEffectCalcAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
Player* player = GetCaster()->ToPlayer();
auto rank = sAdvancementMgr->GetPlayerAdvancementRank(player, MpAdvancements::MP_ADV_RESIST_FIRE);
if(!rank) {
amount = 0; // player does not have an advancement
return;
}
amount = static_cast<int32>(rank->bonus);
MpLogger::info("In Calc Amount Advancement Hellfire Shielding to Player {} bonus {}", player->GetName(), amount);
}
void Register() override
{
MpLogger::info("Registering spell_mp_hellfire_shielding_aura");
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_mp_hellfire_shielding_aura::HandleEffectCalcAmount, EFFECT_0, SPELL_AURA_MOD_RESISTANCE);
}
};
class spell_mp_primal_endurance_aura : public AuraScript
{
PrepareAuraScript(spell_mp_primal_endurance_aura);
void HandleEffectCalcAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
Player* player = GetCaster()->ToPlayer();
auto rank = sAdvancementMgr->GetPlayerAdvancementRank(player, MpAdvancements::MP_ADV_RESIST_NATURE);
if(!rank) {
amount = 0; // player does not have an advancement
return;
}
amount = static_cast<int32>(rank->bonus);
MpLogger::info("In Calc Amount Advancement Primal Endurance to Player {} bonus {}", player->GetName(), amount);
}
void Register() override
{
MpLogger::info("Registering spell_mp_primal_endurance_aura");
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_mp_primal_endurance_aura::HandleEffectCalcAmount, EFFECT_0, SPELL_AURA_MOD_RESISTANCE);
}
};
class spell_mp_lichs_bane_aura : public AuraScript
{
PrepareAuraScript(spell_mp_lichs_bane_aura);
void HandleEffectCalcAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
Player* player = GetCaster()->ToPlayer();
auto rank = sAdvancementMgr->GetPlayerAdvancementRank(player, MpAdvancements::MP_ADV_RESIST_SHADOW);
if(!rank) {
amount = 0; // player does not have an advancement
return;
}
amount = static_cast<int32>(rank->bonus);
MpLogger::info("In Calc Amount Advancement Lich's Bane to Player {} bonus {}", player->GetName(), amount);
}
void Register() override
{
MpLogger::info("Registering spell_mp_lichs_bane_aura");
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_mp_lichs_bane_aura::HandleEffectCalcAmount, EFFECT_0, SPELL_AURA_MOD_RESISTANCE);
}
};
class spell_mp_glacial_fortress_aura : public AuraScript
{
PrepareAuraScript(spell_mp_glacial_fortress_aura);
void HandleEffectCalcAmount(AuraEffect const* /*aurEff*/, int32& amount, bool& /*canBeRecalculated*/)
{
Player* player = GetCaster()->ToPlayer();
auto rank = sAdvancementMgr->GetPlayerAdvancementRank(player, MpAdvancements::MP_ADV_RESIST_FROST);
if(!rank) {
amount = 0; // player does not have an advancement
return;
}
amount = static_cast<int32>(rank->bonus);
MpLogger::info("In Calc Amount Advancement Glacial Fortress to Player {} bonus {}", player->GetName(), amount);
}
void Register() override
{
MpLogger::info("Registering spell_mp_glacial_fortress_aura");
DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_mp_glacial_fortress_aura::HandleEffectCalcAmount, EFFECT_0, SPELL_AURA_MOD_RESISTANCE);
}
};
void AddSC_AdvancementSpells()
{
RegisterSpellScript(spell_mp_titans_strength_aura);
RegisterSpellScript(spell_mp_steel_forged_aura);
RegisterSpellScript(spell_mp_celestial_grace_aura);
RegisterSpellScript(spell_mp_forbidden_knowledge_aura);
RegisterSpellScript(spell_mp_spectral_reflexes_aura);
RegisterSpellScript(spell_mp_eldritch_barrier_aura);
RegisterSpellScript(spell_mp_hellfire_shielding_aura);
RegisterSpellScript(spell_mp_primal_endurance_aura);
RegisterSpellScript(spell_mp_lichs_bane_aura);
RegisterSpellScript(spell_mp_glacial_fortress_aura);
}

View File

@@ -1,70 +0,0 @@
// #include "CreatureScript.h"
// #include "PetDefines.h"
// #include "Player.h"
// #include "MpLogger.h"
// #include "SpellAuraEffects.h"
// #include "SpellInfo.h"
// #include "SpellMgr.h"
// #include "SpellScript.h"
// #include "SpellScriptLoader.h"
// #include "UnitAI.h"
// #include "World.h"
// class spell_mp_toughness_aura : public AuraScript
// {
// PrepareAuraScript(spell_mp_toughness_aura);
// void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
// {
// Player* player = GetTarget()->ToPlayer();
// if (!player)
// return;
// MpLogger::info("Applying Advancement Toughness to Player {}", player->GetName());
// if (Unit* caster = GetCaster())
// {
// if (caster->IsPlayer())
// {
// Player* player = caster->ToPlayer();
// // Add 500 Strength
// player->HandleStatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, 500, true);
// // Apply red glow visual effect
// caster->SendPlaySpellVisual(11674); // Visual ID 11674 for red glow
// }
// }
// }
// void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
// {
// LOG_INFO("server.worldserver", "spell_custom_red_glow_strength_aura::HandleEffectRemove");
// if (Unit* caster = GetCaster())
// {
// if (caster->IsPlayer())
// {
// Player* player = caster->ToPlayer();
// // Remove 500 Strength
// player->HandleStatModifier(UNIT_MOD_STAT_STRENGTH, TOTAL_VALUE, 500, false);
// }
// }
// }
// void Register() override
// {
// LOG_INFO("server.worldserver", "spell_custom_red_glow_strength_aura::Register");
// OnEffectApply += AuraEffectApplyFn(spell_custom_red_glow_strength_aura::HandleEffectApply, EFFECT_0, SPELL_AURA_MOD_STAT, AURA_EFFECT_HANDLE_REAL);
// OnEffectRemove += AuraEffectRemoveFn(spell_custom_red_glow_strength_aura::HandleEffectRemove, EFFECT_0, SPELL_AURA_MOD_STAT, AURA_EFFECT_HANDLE_REAL);
// }
// };
// void AddSC_spell_custom_red_glow_strength_aura()
// {
// // LOG_INFO("server.loading", "Registering spell custom_red_glow_strength_aura");
// RegisterSpellScript(spell_custom_red_glow_strength_aura);
// }