mirror of
https://github.com/araxiaonline/mod-mythic-plus.git
synced 2026-06-13 03:02:24 -04:00
Compare commits
81 Commits
feat/add-m
...
refactor-s
| Author | SHA1 | Date | |
|---|---|---|---|
| ad39d53c58 | |||
| b4013b7024 | |||
| 7d1a9018df | |||
| d4fa53d435 | |||
| 2aeafa689a | |||
| f42cba3099 | |||
| aa58b493ba | |||
| 5387960965 | |||
| 4be3fae368 | |||
| d410220bd0 | |||
| 4df7800afa | |||
| 173d19bcd3 | |||
| 738194fbfa | |||
| 81b7a87ced | |||
| 8e0809cb1c | |||
| cb48af9e9d | |||
| acf11d25f2 | |||
| 41fd4876cf | |||
| ef62c10df3 | |||
| 5fbb0eac74 | |||
| 0982e24f06 | |||
| fa7389f24a | |||
| 8436460350 | |||
| 3bd1f3cdc6 | |||
| 6115459150 | |||
| 3093ab3280 | |||
| fa6f3f3eab | |||
| ccf222ec4f | |||
| 91d3f91dfc | |||
| 9612974b01 | |||
| fd5e186032 | |||
| baf0d8e6e7 | |||
| f3230a6559 | |||
| 86d5ba83f1 | |||
|
|
318244f0fd | ||
| 73018100ac | |||
| fbcb218dd6 | |||
| 322243abf4 | |||
| 9d009d0feb | |||
| a0fdfc9836 | |||
| a6de416efb | |||
| 1695f33f68 | |||
| 88d894eaaf | |||
| f66b861079 | |||
| 79cb4d9835 | |||
| c32b64bb1f | |||
| f083748c4a | |||
| 3cf1e17c99 | |||
| 0a0236b273 | |||
| 8942d53b13 | |||
| 41819432e9 | |||
| d35a934b8a | |||
| 46d5a99f04 | |||
| f8ecc0d1b9 | |||
| fcce3a0453 | |||
| 68efd1a732 | |||
| 9f4ea9d539 | |||
| 803cb246bf | |||
| 1bd94e56fa | |||
| 0ee3ead805 | |||
| ec1663aa34 | |||
| 3d0f314c39 | |||
| 5877e9122c | |||
| 5847754197 | |||
| 6936f8b73e | |||
| a35e4b646d | |||
| a4d7b00036 | |||
| 73c2b8923b | |||
| d3af7990cb | |||
| 25f74e1b5a | |||
| cbec66031d | |||
| 4a8731c876 | |||
| a62df56099 | |||
| 7f78971e49 | |||
| c73dba69d7 | |||
| b9825b47e0 | |||
| cbde9bbfe2 | |||
| af9e7b3f3f | |||
| 5b6805dcc7 | |||
| 78648bd511 | |||
|
|
fd4c9d2b51 |
22
.vscode/c_cpp_properties.json
vendored
Normal file
22
.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "AzerothCore",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/src/common/Logging/**",
|
||||
"${workspaceFolder}/src",
|
||||
"${workspaceFolder}/deps",
|
||||
"${workspaceFolder}/**",
|
||||
"/opt/homebrew/include"
|
||||
],
|
||||
"defines": [
|
||||
"AZEROTHCORE"
|
||||
],
|
||||
"compilerPath": "/usr/bin/clang++", // macOS typically uses clang as the default compiler
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17",
|
||||
"intelliSenseMode": "macos-clang-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
@@ -112,3 +112,8 @@ MythicPlus.Mythic.ItemOffset = 20000000
|
||||
MythicPlus.Legendary.ItemOffset = 21000000
|
||||
MythicPlus.Ascendant.ItemOffset = 22000000
|
||||
|
||||
##############
|
||||
# Scaling Adjusters
|
||||
#############
|
||||
MythicPlus.MeleeAttackPowerDampener = 800
|
||||
MythicPlus.MeleeAttackPowerStart = 3000
|
||||
|
||||
0
data/sql/db-characters/base/.gitkeep
Normal file
0
data/sql/db-characters/base/.gitkeep
Normal file
100
data/sql/db-characters/base/01_mp_schema.sql
Normal file
100
data/sql/db-characters/base/01_mp_schema.sql
Normal file
@@ -0,0 +1,100 @@
|
||||
-- Used for tracking group instance data for mythic runs
|
||||
DROP TABLE IF EXISTS mp_group_data;
|
||||
CREATE TABLE mp_group_data (
|
||||
groupId INT UNSIGNED NOT NULL DEFAULT '0',
|
||||
difficulty INT UNSIGNED,
|
||||
mapId INT UNSIGNED,
|
||||
instanceId INT UNSIGNED,
|
||||
instanceTimer INT UNSIGNED,
|
||||
deaths INT UNSIGNED,
|
||||
|
||||
PRIMARY KEY (groupId)
|
||||
);
|
||||
|
||||
-- Used for tracking current instance data for players
|
||||
DROP TABLE IF EXISTS mp_player_instance_data;
|
||||
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,
|
||||
deaths INT UNSIGNED NOT NULL,
|
||||
|
||||
PRIMARY KEY (guid, mapId, instanceId)
|
||||
);
|
||||
|
||||
-- Used for tracking player deaths to specific creatures in mythic runs
|
||||
DROP TABLE IF EXISTS mp_player_death_stats;
|
||||
CREATE TABLE mp_player_death_stats (
|
||||
guid INT UNSIGNED NOT NULL DEFAULT '0',
|
||||
creatureEntry INT UNSIGNED NOT NULL,
|
||||
difficulty TINYINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
numDeaths INT UNSIGNED NOT NULL DEFAULT '0',
|
||||
lastUpdated TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
PRIMARY KEY (guid, creatureEntry, difficulty)
|
||||
);
|
||||
|
||||
-- Used for tracking player runs in mythic dungeons
|
||||
DROP TABLE IF EXISTS mp_player_runs;
|
||||
CREATE TABLE mp_player_runs (
|
||||
runId INT UNSIGNED AUTO_INCREMENT,
|
||||
guid INT UNSIGNED NOT NULL DEFAULT '0',
|
||||
difficulty INT UNSIGNED NOT NULL DEFAULT '3',
|
||||
mapId INT UNSIGNED NOT NULL DEFAULT '0',
|
||||
groupDeaths INT UNSIGNED NOT NULL DEFAULT '0',
|
||||
personalDeaths INT UNSIGNED NOT NULL DEFAULT '0',
|
||||
startTime INT UNSIGNED,
|
||||
completeTime TIMESTAMP,
|
||||
botCount TINYINT UNSIGNED DEFAULT '0',
|
||||
|
||||
PRIMARY KEY (runId),
|
||||
INDEX idx_guid (guid),
|
||||
INDEX idx_mapId (mapId)
|
||||
);
|
||||
|
||||
-- Used for tracking player stats in mythic dungeons
|
||||
DROP TABLE IF EXISTS mp_player_stats;
|
||||
CREATE TABLE mp_player_stats (
|
||||
guid INT UNSIGNED NOT NULL DEFAULT '0',
|
||||
mapId INT UNSIGNED NOT NULL DEFAULT '0',
|
||||
difficulty TINYINT UNSIGNED NOT NULL DEFAULT '0',
|
||||
deaths INT UNSIGNED DEFAULT '0',
|
||||
runs INT UNSIGNED DEFAULT '0',
|
||||
completions INT UNSIGNED DEFAULT '0',
|
||||
totalTime INT UNSIGNED DEFAULT '0',
|
||||
bestTime INT UNSIGNED DEFAULT '0',
|
||||
|
||||
PRIMARY KEY (guid, mapId, difficulty)
|
||||
);
|
||||
|
||||
-- Used to enable custom stat upgrades from materials and drops in mythic dungeons
|
||||
DROP TABLE IF EXISTS mp_player_advancements;
|
||||
CREATE TABLE mp_player_advancements (
|
||||
guid INT UNSIGNED NOT NULL,
|
||||
advancementId INT UNSIGNED NOT NULL,
|
||||
bonus FLOAT NOT NULL,
|
||||
upgradeRank INT UNSIGNED NOT NULL,
|
||||
diceSpent INT UNSIGNED NOT NULL DEFAULT '0',
|
||||
|
||||
PRIMARY KEY (guid, advancementId)
|
||||
);
|
||||
|
||||
-- Used to show historic player roll data by advancement.
|
||||
DROP TABLE IF EXISTS mp_player_advancement_history;
|
||||
CREATE TABLE mp_player_advancement_history (
|
||||
guid INT UNSIGNED NOT NULL,
|
||||
advancementId INT UNSIGNED NOT NULL,
|
||||
bonus FLOAT NOT NULL,
|
||||
upgradeRank INT UNSIGNED NOT NULL,
|
||||
diceSpent INT UNSIGNED NOT NULL DEFAULT '0',
|
||||
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,
|
||||
added TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (guid, advancementId)
|
||||
);
|
||||
|
||||
0
data/sql/db-characters/updates/.gitkeep
Normal file
0
data/sql/db-characters/updates/.gitkeep
Normal file
0
data/sql/db-world/base/.gitkeep
Normal file
0
data/sql/db-world/base/.gitkeep
Normal file
48
data/sql/db-world/base/01_mp_world_schema.sql
Normal file
48
data/sql/db-world/base/01_mp_world_schema.sql
Normal file
@@ -0,0 +1,48 @@
|
||||
-- Used to track upgrade ranks for stat improvements and min/max values
|
||||
DROP TABLE IF EXISTS mp_stat_upgrade_ranks;
|
||||
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,
|
||||
minIncrease1 INT UNSIGNED NOT NULL,
|
||||
maxIncrease1 INT UNSIGNED NOT NULL,
|
||||
minIncrease2 INT UNSIGNED NOT NULL,
|
||||
maxIncrease2 INT UNSIGNED NOT NULL,
|
||||
minIncrease3 INT UNSIGNED NOT NULL,
|
||||
maxIncrease3 INT UNSIGNED NOT NULL,
|
||||
chanceCost1 INT UNSIGNED NOT NULL,
|
||||
chanceCost2 INT UNSIGNED NOT NULL,
|
||||
chanceCost3 INT UNSIGNED NOT NULL,
|
||||
|
||||
PRIMARY KEY (upgradeRank, advancementId)
|
||||
);
|
||||
|
||||
-- Used to allocate trade materials based on slot upgrades
|
||||
DROP TABLE IF EXISTS mp_material_types;
|
||||
CREATE TABLE mp_material_types (
|
||||
materialId INT UNSIGNED NOT NULL,
|
||||
entry INT UNSIGNED NOT NULL,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
|
||||
PRIMARY KEY (materialId, entry)
|
||||
);
|
||||
|
||||
|
||||
-- Description: Scale factors for Mythic+ dungeons used to normalize dungeon difficulty across expansions.
|
||||
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',
|
||||
|
||||
PRIMARY KEY (mapId)
|
||||
);
|
||||
537
data/sql/db-world/base/02_mp_material_types.sql
Normal file
537
data/sql/db-world/base/02_mp_material_types.sql
Normal file
@@ -0,0 +1,537 @@
|
||||
TRUNCATE TABLE mp_material_types;
|
||||
|
||||
-- MaterialID for all droppable cloth items
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT DISTINCT
|
||||
1 AS materialId, -- Assign the same materialId to all rows
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
LEFT JOIN creature_loot_template clt ON (it.entry = clt.Item)
|
||||
WHERE it.name LIKE '%Cloth'
|
||||
AND it.class = 7
|
||||
AND it.subclass = 5
|
||||
AND it.name NOT LIKE 'Bolt%'
|
||||
AND it.VerifiedBuild = 12340
|
||||
AND clt.Entry IS NOT NULL;
|
||||
|
||||
-- Crafted cloth items that are not dropped by enemies
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
2 AS materialId, -- Assign the same materialId to all rows
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
LEFT JOIN creature_loot_template clt ON (it.entry = clt.Item)
|
||||
WHERE it.name LIKE '%Cloth'
|
||||
AND it.class = 7
|
||||
AND it.subclass = 5
|
||||
AND it.name NOT LIKE 'Bolt%'
|
||||
AND it.VerifiedBuild = 12340
|
||||
AND clt.Entry IS NULL;
|
||||
|
||||
-- Common Herbs available to herbalists
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
3 AS materialId,
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE it.class = 7
|
||||
AND it.subclass = 9
|
||||
AND it.VerifiedBuild = 12340
|
||||
AND it.RequiredSkillRank != 0
|
||||
AND it.name NOT IN (
|
||||
'Black Lotus',
|
||||
'Ghost Mushroom',
|
||||
'Dreamfoil',
|
||||
'Bloodvine',
|
||||
'Fel Lotus',
|
||||
'Netherbloom',
|
||||
'Nightmare Vine',
|
||||
'Frost Lotus',
|
||||
"Adder's Tongue",
|
||||
'Fire Leaf',
|
||||
'Lichbloom',
|
||||
'Icethorn',
|
||||
"Talandra's Rose"
|
||||
);
|
||||
-- Rare Herbs that are harder to find or drop in raids
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
4 AS materialId,
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE it.name IN (
|
||||
'Black Lotus', -- Classic: Rare spawn in Dire Maul and outdoor zones, extremely rare in raids.
|
||||
'Ghost Mushroom', -- Classic: Found in Maraudon (Dungeon-only herb).
|
||||
'Bloodvine', -- Classic: Drops from enemies in Zul'Gurub.
|
||||
'Fel Lotus', -- TBC: Extremely rare herb drop while gathering Felweed, Dreaming Glory, etc., in Outland.
|
||||
'Netherbloom', -- TBC: Rare spawn in Netherstorm, also dropped by some elites.
|
||||
'Nightmare Vine', -- TBC: Found in Shadowmoon Valley and drops in Black Temple from specific mobs.
|
||||
'Frost Lotus', -- Wrath: Extremely rare spawn from herb nodes or dungeons like Utgarde Pinnacle.
|
||||
"Adder's Tongue", -- Wrath: Rare spawn from dungeon nodes in Drak'Tharon Keep and Gundrak.
|
||||
'Fire Leaf', -- Wrath: Rare herb found in Wintergrasp, sometimes in dungeon PvP areas.
|
||||
'Icethorn', -- Wrath: Harvested from specific dungeon nodes in higher-level Northrend zones.
|
||||
"Talandra's Rose" -- Wrath: Found sparsely in Zul'Drak dungeons like Gundrak.
|
||||
);
|
||||
|
||||
-- Common ores that are easy to find in the world
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT DISTINCT
|
||||
5 AS materialId,
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE it.class = 7
|
||||
AND it.subclass = 7
|
||||
AND it.VerifiedBuild = 12340
|
||||
AND it.name NOT LIKE '%Bar'
|
||||
AND it.name NOT LIKE '%Ingot'
|
||||
AND it.name NOT LIKE '%Stone'
|
||||
AND it.name NOT LIKE '%Shard'
|
||||
AND it.name NOT IN ('Coal', 'Elemental Flux', 'Hardened Khorium')
|
||||
AND it.name NOT IN ('Elementium Ore', 'Dark Iron Ore', 'Primal Nether', 'Runed Orb', 'Crusader Orb', 'Blood of the Mountain')
|
||||
ORDER BY it.name;
|
||||
|
||||
-- Rare ores that are harder to find or drop in raids
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT DISTINCT
|
||||
6 AS materialId,
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE
|
||||
it.name Like '%Obsidian Shard%'
|
||||
OR it.name IN ('Elementium Ore', 'Dark Iron Ore', 'Primal Nether', 'Runed Orb', 'Crusader Orb', 'Blood of the Mountain')
|
||||
and entry <= 2000000
|
||||
ORDER BY it.name;
|
||||
|
||||
-- Common skins that are easy to find in the world
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
7 AS materialId, -- Unique ID for commonly skinnable materials
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE it.name IN (
|
||||
'Borean Leather',
|
||||
'Heavy Leather',
|
||||
'Heavy Hide',
|
||||
'Light Leather',
|
||||
'Light Hide',
|
||||
'Medium Leather',
|
||||
'Medium Hide',
|
||||
'Rugged Leather',
|
||||
'Rugged Hide',
|
||||
'Thick Leather',
|
||||
'Thick Hide',
|
||||
'Knothide Leather',
|
||||
'Icy Dragonscale',
|
||||
'Jormungar Scale',
|
||||
'Nerubian Chitin',
|
||||
'Turtle Scale'
|
||||
);
|
||||
-- Rare skinning material found in the world or dropped by enemies
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
8 AS materialId, -- Unique ID for rare skinnable and non-skinnable materials
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE it.name IN (
|
||||
'Black Dragonscale',
|
||||
'Blue Dragonscale',
|
||||
'Green Dragonscale',
|
||||
'Red Dragonscale',
|
||||
'Scale of Onyxia',
|
||||
'Nether Dragonscales',
|
||||
'Wind Scales',
|
||||
'Thick Clefthoof Leather',
|
||||
'Cobra Scales',
|
||||
'Devilsaur Leather',
|
||||
'Green Whelp Scale',
|
||||
'Black Whelp Scale',
|
||||
'Perfect Deviate Scale',
|
||||
'Core Leather',
|
||||
'Dreamscale',
|
||||
'Primal Bat Leather',
|
||||
'Primal Tiger Leather'
|
||||
);
|
||||
|
||||
-- Common uncut gems that are easy to find in the world
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
9 AS materialId, -- Unique ID for common uncut gems
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE
|
||||
it.VerifiedBuild = 12340 -- Wrath of the Lich King build
|
||||
AND it.name NOT LIKE '%Cut%' -- Exclude pre-cut gems
|
||||
AND it.name IN (
|
||||
'Malachite',
|
||||
'Tigerseye',
|
||||
'Moss Agate',
|
||||
'Shadowgem',
|
||||
'Jade',
|
||||
'Lesser Moonstone',
|
||||
'Citrine',
|
||||
'Aquamarine',
|
||||
'Star Ruby',
|
||||
'Azerothian Diamond',
|
||||
'Huge Emerald',
|
||||
'Large Opal',
|
||||
'Blue Sapphire',
|
||||
'Arcane Crystal',
|
||||
'Bloodstone',
|
||||
'Sun Crystal',
|
||||
'Chalcedony',
|
||||
'Dark Jade',
|
||||
'Shadow Crystal',
|
||||
'Huge Citrine',
|
||||
'Monarch Topaz',
|
||||
'Forest Emerald',
|
||||
'Sky Sapphire',
|
||||
"Autumn's Glow",
|
||||
'Twilight Opal',
|
||||
'Scarlet Ruby'
|
||||
);
|
||||
|
||||
-- Rare gems that are harder to find or drop in raids
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
10 AS materialId,
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE
|
||||
it.name IN (
|
||||
-- TBC Epic Gems
|
||||
'Crimson Spinel',
|
||||
'Empyrean Sapphire',
|
||||
'Lionseye',
|
||||
'Shadowsong Amethyst',
|
||||
'Pyrestone',
|
||||
'Seaspray Emerald',
|
||||
|
||||
-- WotLK Epic Gems
|
||||
'Cardinal Ruby',
|
||||
'Ametrine',
|
||||
"King's Amber",
|
||||
'Eye of Zul',
|
||||
'Majestic Zircon',
|
||||
'Dreadstone'
|
||||
);
|
||||
|
||||
-- common enchantment materials that are easy to find in the world
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
11 AS materialId, -- Example materialId for enchantment items
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE
|
||||
it.class = 7
|
||||
AND it.subclass = 12
|
||||
AND it.VerifiedBuild = 12340
|
||||
AND it.name NOT LIKE '%Rod%'
|
||||
AND it.name NOT IN (
|
||||
-- Classic Rare Enchantment Items
|
||||
'Righteous Orb', -- Drops in Stratholme.
|
||||
'Lava Core', -- Rare drop in Molten Core.
|
||||
'Black Diamond', -- Rare drop in Blackrock Depths and related areas.
|
||||
'Essence of the Red', -- Reward from Vaelastrasz in Blackwing Lair.
|
||||
'Onyxia Scale', -- Dropped by Onyxia, used in fire resistance recipes.
|
||||
|
||||
-- TBC Rare Enchantment Items
|
||||
'Primal Might', -- Crafted using all Primals, very rare due to material costs.
|
||||
'Heart of Darkness', -- Rare drop in Black Temple.
|
||||
'Sunmote', -- Drops in Sunwell Plateau.
|
||||
'Nether Vortex', -- Raid-exclusive crafting material in TBC.
|
||||
|
||||
-- WotLK Rare Enchantment Items
|
||||
'Eternal Might', -- Custom material replacing Eternal combinations, rare in high-level content.
|
||||
'Frozen Orb', -- Drops in WotLK heroic dungeons.
|
||||
'Runed Orb', -- Drops in Ulduar.
|
||||
'Crusader Orb' -- Drops in Trial of the Crusader raid.
|
||||
);
|
||||
|
||||
-- Rare enchantment materials that are harder to find or drop in raids
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
12 AS materialId, -- Example materialId for enchantment items
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE
|
||||
it.name IN (
|
||||
-- Classic Rare Enchantment Items
|
||||
'Righteous Orb', -- Drops in Stratholme.
|
||||
'Lava Core', -- Rare drop in Molten Core.
|
||||
'Black Diamond', -- Rare drop in Blackrock Depths and related areas.
|
||||
'Essence of the Red', -- Reward from Vaelastrasz in Blackwing Lair.
|
||||
'Onyxia Scale', -- Dropped by Onyxia, used in fire resistance recipes.
|
||||
|
||||
-- TBC Rare Enchantment Items
|
||||
'Primal Might', -- Crafted using all Primals, very rare due to material costs.
|
||||
'Heart of Darkness', -- Rare drop in Black Temple.
|
||||
'Sunmote', -- Drops in Sunwell Plateau.
|
||||
'Nether Vortex', -- Raid-exclusive crafting material in TBC.
|
||||
|
||||
-- WotLK Rare Enchantment Items
|
||||
'Eternal Might', -- Custom material replacing Eternal combinations, rare in high-level content.
|
||||
'Frozen Orb', -- Drops in WotLK heroic dungeons.
|
||||
'Runed Orb', -- Drops in Ulduar.
|
||||
'Crusader Orb' -- Drops in Trial of the Crusader raid.
|
||||
);
|
||||
|
||||
-- Common materials that related to water / frost
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
13 AS materialId,
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE
|
||||
it.name IN (
|
||||
-- Classic
|
||||
'Elemental Water',
|
||||
'Essence of Water',
|
||||
'Glacial Fragments',
|
||||
|
||||
-- TBC
|
||||
'Arctic Fur',
|
||||
'Thick Dawnstone',
|
||||
|
||||
-- WotLK
|
||||
'Frost Lotus',
|
||||
'Frostweave Cloth'
|
||||
);
|
||||
|
||||
-- Rare materials that related to water / frost
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
14 AS materialId, -- Unique ID for rare frost resistance materials
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE
|
||||
it.name IN (
|
||||
-- Classic
|
||||
'Frozen Rune',
|
||||
'Core of Earth',
|
||||
|
||||
-- TBC
|
||||
'Frost-Infused Shard',
|
||||
'Nether Residuum',
|
||||
'Primal Water',
|
||||
|
||||
-- WotLK
|
||||
'Primordial Saronite',
|
||||
'Icy Dragonscale',
|
||||
'Eternal Water'
|
||||
);
|
||||
|
||||
-- Common materials that relate to fire
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
15 AS materialId,
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE
|
||||
it.name IN (
|
||||
-- Classic
|
||||
'Elemental Fire',
|
||||
'Essence of Fire',
|
||||
'Heart of Fire',
|
||||
'Small Flame Sac',
|
||||
'Core of Flame',
|
||||
|
||||
-- TBC
|
||||
'Mote of Fire',
|
||||
'Flame Spessarite', -- Common fire-themed gem for jewelcrafting.
|
||||
'Smoldering Core', -- Fire-themed drop from elementals.
|
||||
|
||||
-- WotLK
|
||||
'Fire Leaf',
|
||||
'Crystallized Fire'
|
||||
);
|
||||
|
||||
-- Rare materials that relate to fire resistance gear or fire-themed weapons
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
16 AS materialId, -- Unique ID for rare fire resistance and fire weapon crafting materials
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE
|
||||
it.name IN (
|
||||
-- Classic
|
||||
'Fiery Core', -- Key material for crafting fire resistance gear in Molten Core.
|
||||
'Lava Core', -- Used in crafting fire resistance gear and recipes.
|
||||
'Sulfuron Ingot', -- Rare drop from Molten Core, used for crafting legendary fire weapons.
|
||||
|
||||
-- TBC
|
||||
'Primal Fire', -- Core material for fire crafting in TBC.
|
||||
'Hardened Adamantite Bar', -- Material for crafting fire-resistant shields and gear.
|
||||
|
||||
-- WotLK
|
||||
'Primordial Saronite', -- Used for crafting high-level resistance and utility gear.
|
||||
'Eternal Fire', -- Central material for fire-themed crafting.
|
||||
'Runed Orb', -- Used in crafting fire-related weapons and gear.
|
||||
'Smouldering Crystals', -- High-value fire crafting material from fire-themed mobs.
|
||||
'Burning Embers' -- Rare crafting material for WotLK fire-themed items.
|
||||
);
|
||||
|
||||
-- Common materials that relate to nature
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
17 AS materialId,
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE
|
||||
it.name IN (
|
||||
-- Classic
|
||||
'Elemental Earth',
|
||||
'Essence of Earth',
|
||||
'Living Essence',
|
||||
'Small Venom Sac',
|
||||
"Un'Goro Soil",
|
||||
'Ichor of Undeath', -- Used in nature-themed recipes.
|
||||
|
||||
-- TBC
|
||||
'Mote of Earth', -- Combines into Primal Earth.
|
||||
'Mote of Life', -- Combines into Primal Life.
|
||||
'Terocone', -- Nature-themed herb used in alchemy.
|
||||
|
||||
-- WotLK
|
||||
'Crystallized Earth', -- Combines into Eternal Earth.
|
||||
'Crystallized Life', -- Combines into Eternal Life.
|
||||
'Icethorn', -- Herb with thematic ties to nature resistance potions.
|
||||
'Ancient Moss'
|
||||
);
|
||||
|
||||
-- Rare Nature resistance materials
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
18 AS materialId, -- Unique ID for rare nature resistance and nature weapon crafting materials
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE
|
||||
it.name IN (
|
||||
-- Classic
|
||||
'Heart of the Wild', -- Rare material for crafting nature resistance gear.
|
||||
'Living Essence', -- Rare crafting material dropped by nature elementals.
|
||||
"Gahz'rilla's Electrified Scale",-- Rare item from Zul'Farrak for nature resistance gear.
|
||||
|
||||
-- TBC
|
||||
'Primal Earth', -- Central crafting material for resistance and nature-themed items.
|
||||
'Primal Life', -- Rare material for nature-themed crafting.
|
||||
|
||||
-- WotLK
|
||||
'Eternal Earth', -- Central material for nature-themed crafting.
|
||||
'Eternal Life', -- Rare material for nature-themed crafting.
|
||||
'Runed Orb', -- Rare crafting material for nature-themed gear.
|
||||
"Adder's Tongue" -- Herb used in nature resistance recipes.
|
||||
);
|
||||
|
||||
|
||||
-- Common materials that relate to shadow
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
19 AS materialId,
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE
|
||||
it.name IN (
|
||||
-- Classic
|
||||
'Shadowgem', -- Common low-level gem with shadow theme.
|
||||
'Elemental Shadow', -- Basic crafting reagent from shadow elementals.
|
||||
'Essence of Shadow', -- Dropped by shadow-themed elementals in high-level zones.
|
||||
|
||||
-- TBC
|
||||
'Mote of Shadow', -- Combines into Primal Shadow, used in crafting.
|
||||
'Dark Rune', -- Dropped in Scholomance and used for shadow resistance crafting.
|
||||
|
||||
-- WotLK
|
||||
'Crystallized Shadow', -- Combines into Eternal Shadow.
|
||||
'Deadnettle', -- Herb with thematic ties to shadow crafting.
|
||||
'Shadowy Essence' -- Rare Northrend material for shadow crafting.
|
||||
);
|
||||
|
||||
-- Rare materials that relate to shadow resistance gear or shadow-themed weapons
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
20 AS materialId, -- Unique ID for rare shadow resistance and shadow weapon crafting materials
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE
|
||||
it.name IN (
|
||||
-- Classic
|
||||
'Heart of Darkness', -- Rare drop used for shadow resistance gear in TBC and Classic.
|
||||
'Shadow Oil', -- Crafted alchemical reagent for shadow resistance.
|
||||
'Black Lotus', -- Rare herb used in high-level shadow potions.
|
||||
|
||||
-- TBC
|
||||
'Primal Shadow', -- Central crafting material for shadow resistance.
|
||||
'Nightmare Seed', -- Rare herb used in shadow resistance recipes.
|
||||
'Felcloth', -- Cloth with shadow resistance used in tailoring.
|
||||
|
||||
|
||||
-- WotLK
|
||||
'Eternal Shadow', -- Core material for shadow resistance crafting.
|
||||
'Runed Orb' -- Rare material for shadow-themed gear and weapons.
|
||||
);
|
||||
|
||||
-- Common materials that relate to arcane resistance gear or arcane-themed weapons
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
21 AS materialId,
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE
|
||||
it.name IN (
|
||||
-- Classic
|
||||
'Arcane Crystal', -- Rare mining material used in Arcanite Bars.
|
||||
'Essence of Magic', -- Dropped by arcane elementals.
|
||||
'Lesser Magic Essence', -- Early enchanting material.
|
||||
'Greater Magic Essence', -- Enchanting material with arcane ties.
|
||||
|
||||
-- TBC
|
||||
'Mote of Mana', -- Combines into Primal Mana.
|
||||
|
||||
-- WotLK
|
||||
'Crystallized Mana' -- Combines into Eternal Mana.
|
||||
);
|
||||
|
||||
|
||||
-- Rare materials that relate to arcane resistance gear or arcane-themed weapons
|
||||
REPLACE INTO mp_material_types (materialId, entry, name)
|
||||
SELECT
|
||||
22 AS materialId, -- Unique ID for rare arcane resistance and arcane weapon crafting materials
|
||||
it.entry,
|
||||
it.name
|
||||
FROM item_template it
|
||||
WHERE
|
||||
it.name IN (
|
||||
-- Classic
|
||||
'Golden Pearl', -- Rare material used in crafting arcane resistance gear.
|
||||
'Arcanite Bar', -- Transmuted from Arcane Crystals, used in crafting high-end gear.
|
||||
|
||||
-- TBC
|
||||
'Primal Mana', -- Essential for arcane resistance crafting.
|
||||
'Nether Vortex', -- Raid-exclusive crafting material.
|
||||
'Void Sphere', -- Rare arcane-themed gem obtained through badge purchases or raids.
|
||||
|
||||
-- WotLK
|
||||
'Eternal Mana', -- Central crafting material for arcane resistance gear.
|
||||
'Saronite Animus' -- Rare drop from arcane-themed enemies in Icecrown Citadel.
|
||||
);
|
||||
81
data/sql/db-world/base/03_mp_scale_factors.sql
Normal file
81
data/sql/db-world/base/03_mp_scale_factors.sql
Normal file
@@ -0,0 +1,81 @@
|
||||
-- Last Update: 2021/08/15
|
||||
-- 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)
|
||||
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;
|
||||
|
||||
-- 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)
|
||||
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;
|
||||
|
||||
-- 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)
|
||||
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;
|
||||
|
||||
-- 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)
|
||||
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;
|
||||
|
||||
-- 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)
|
||||
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;
|
||||
|
||||
-- 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)
|
||||
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;
|
||||
82
data/sql/db-world/base/04_creature_classlevelstats.sql
Normal file
82
data/sql/db-world/base/04_creature_classlevelstats.sql
Normal file
@@ -0,0 +1,82 @@
|
||||
REPLACE creature_classlevelstats (class, `level`, basehp0, basehp1, basehp2,
|
||||
basemana, basearmor, attackpower, rangedattackpower, damage_base, damage_exp1, damage_exp2) VALUES
|
||||
(1, 81, 5489.19, 9449.55, 12640.32, 0.00, 10033.36, 714.66, 111.97, 47.9043, 131.5509, 166.3098),
|
||||
(1, 82, 5641.53, 9700.79, 12855.00, 0.00, 10337.65, 790.54, 121.09, 48.5708, 131.9685, 169.2029),
|
||||
(1, 83, 5797.46, 9956.22, 13042.96, 0.00, 10642.47, 872.71, 130.74, 49.2374, 132.0348, 171.8720),
|
||||
(1, 84, 5956.98, 10215.83, 13204.22, 0.00, 10947.81, 961.17, 140.89, 49.9039, 131.7497, 174.3170),
|
||||
(1, 85, 6120.07, 10479.62, 13338.76, 0.00, 11253.67, 1055.90, 151.56, 50.5705, 131.1133, 176.5379),
|
||||
(1, 86, 6286.76, 10747.60, 13446.59, 0.00, 11560.05, 1156.93, 162.75, 51.2370, 130.1256, 178.5348),
|
||||
(1, 87, 6457.02, 11019.76, 13527.71, 0.00, 11866.95, 1264.23, 174.45, 51.9035, 128.7865, 180.3077),
|
||||
(1, 88, 6630.87, 11296.10, 13582.12, 0.00, 12174.38, 1377.82, 186.66, 52.5700, 127.0960, 181.8565),
|
||||
(1, 89, 6808.31, 11576.62, 13609.82, 0.00, 12482.32, 1497.69, 199.39, 53.2365, 125.0542, 183.1813),
|
||||
(1, 90, 6989.33, 11861.33, 13610.80, 0.00, 12790.79, 1623.85, 212.64, 53.9030, 122.6611, 184.2821),
|
||||
(1, 91, 7173.93, 12150.22, 13585.08, 0.00, 13099.78, 1756.29, 226.40, 54.5695, 119.9166, 185.1587),
|
||||
(1, 92, 7362.12, 12443.29, 13532.64, 0.00, 13409.29, 1895.01, 240.67, 55.2360, 116.8207, 185.8114),
|
||||
(1, 93, 7553.90, 12740.55, 13453.49, 0.00, 13719.32, 2040.02, 255.46, 55.9024, 113.3736, 186.2400),
|
||||
(1, 94, 7749.25, 13041.99, 13347.63, 0.00, 14029.88, 2191.31, 270.76, 56.5689, 109.5750, 186.4446),
|
||||
(1, 95, 7948.20, 13347.61, 13215.06, 0.00, 14340.95, 2348.88, 286.57, 57.2353, 105.4251, 186.4251),
|
||||
(1, 96, 8150.72, 13657.41, 13055.78, 0.00, 14652.55, 2512.74, 302.90, 57.9018, 100.9239, 186.1815),
|
||||
(1, 97, 8356.83, 13971.40, 12869.79, 0.00, 14964.67, 2682.88, 319.75, 58.5682, 96.0713, 185.7140),
|
||||
(1, 98, 8566.53, 14289.57, 12657.08, 0.00, 15277.30, 2859.31, 337.11, 59.2346, 90.8674, 185.0224),
|
||||
(1, 99, 8779.81, 14611.92, 12417.67, 0.00, 15590.47, 3042.02, 354.98, 59.9010, 85.3122, 184.1067),
|
||||
(1, 100, 8996.67, 14938.46, 12151.54, 0.00, 15904.15, 3231.01, 373.37, 60.5674, 79.4055, 182.9670),
|
||||
(2, 81, 4391.71, 7560.03, 12640.32, 4078.27, 10008.59, 677.15, 87.20, 44.8582, 112.1715, 166.3095),
|
||||
(2, 82, 4513.65, 7760.95, 12855.00, 4169.46, 10311.04, 749.46, 94.48, 45.5146, 112.7114, 169.2025),
|
||||
(2, 83, 4638.44, 7965.20, 13042.96, 4261.79, 10613.90, 827.78, 102.16, 46.1711, 113.0756, 171.8714),
|
||||
(2, 84, 4766.11, 8172.77, 13204.22, 4355.28, 10917.17, 912.11, 110.26, 46.8275, 113.2640, 174.3162),
|
||||
(2, 85, 4896.64, 8383.67, 13338.76, 4449.92, 11220.87, 1002.43, 118.77, 47.4839, 113.2768, 176.5370),
|
||||
(2, 86, 5030.04, 8597.90, 13446.59, 4545.71, 11524.99, 1098.77, 127.69, 48.1402, 113.1139, 178.5337),
|
||||
(2, 87, 5166.31, 8815.44, 13527.71, 4642.65, 11829.52, 1201.10, 137.02, 48.7965, 112.7753, 180.3063),
|
||||
(2, 88, 5305.45, 9036.31, 13582.12, 4740.74, 12134.48, 1309.44, 146.76, 49.4528, 112.2609, 181.8549),
|
||||
(2, 89, 5447.45, 9260.51, 13609.82, 4839.99, 12439.85, 1423.78, 156.92, 50.1091, 111.5709, 183.1795),
|
||||
(2, 90, 5592.32, 9488.03, 13610.80, 4940.38, 12745.64, 1544.13, 167.48, 50.7653, 110.7051, 184.2800),
|
||||
(2, 91, 5740.05, 9718.88, 13585.08, 5041.93, 13051.85, 1670.48, 178.46, 51.4215, 109.6637, 185.1564),
|
||||
(2, 92, 5890.66, 9953.05, 13532.64, 5144.64, 13358.47, 1802.84, 189.85, 52.0777, 108.4465, 185.8087),
|
||||
(2, 93, 6044.13, 10190.55, 13453.49, 5248.49, 13665.52, 1941.20, 201.65, 52.7338, 107.0536, 186.2370),
|
||||
(2, 94, 6200.47, 10431.37, 13347.63, 5353.49, 13972.98, 2085.56, 213.87, 53.3899, 105.4850, 186.4413),
|
||||
(2, 95, 6359.67, 10675.51, 13215.06, 5459.65, 14280.87, 2235.93, 226.49, 54.0460, 103.7407, 186.4215),
|
||||
(2, 96, 6521.74, 10922.98, 13055.78, 5566.96, 14589.17, 2392.30, 239.53, 54.7021, 101.8207, 186.1776),
|
||||
(2, 97, 6686.68, 11173.77, 12869.79, 5675.42, 14897.89, 2554.68, 252.97, 55.3581, 99.7250, 185.7096),
|
||||
(2, 98, 6854.49, 11427.89, 12657.08, 5785.03, 15207.03, 2723.06, 266.83, 56.0141, 97.4536, 185.0176),
|
||||
(2, 99, 7025.16, 11685.34, 12417.67, 5895.80, 15516.59, 2897.44, 281.10, 56.6700, 95.0065, 184.1016),
|
||||
(2, 100, 7198.70, 11946.10, 12151.54, 6007.71, 15826.56, 3077.83, 295.79, 57.3260, 92.3837, 182.9615),
|
||||
(4, 81, 5489.19, 8862.85, 12640.32, 0.00, 9050.32, 714.66, 111.97, 47.9043, 131.5509, 166.3098),
|
||||
(4, 82, 5641.53, 8991.59, 12855.00, 0.00, 9324.66, 790.54, 121.09, 48.5708, 131.9685, 169.2029),
|
||||
(4, 83, 5797.46, 9113.21, 13042.96, 0.00, 9599.46, 872.71, 130.74, 49.2374, 132.0348, 171.8720),
|
||||
(4, 84, 5956.98, 9227.74, 13204.22, 0.00, 9874.72, 961.17, 140.89, 49.9039, 131.7497, 174.3170),
|
||||
(4, 85, 6120.07, 9335.15, 13338.76, 0.00, 10150.45, 1055.90, 151.56, 50.5705, 131.1133, 176.5379),
|
||||
(4, 86, 6286.76, 9435.46, 13446.59, 0.00, 10426.65, 1156.93, 162.75, 51.2370, 130.1256, 178.5348),
|
||||
(4, 87, 6457.02, 9528.66, 13527.71, 0.00, 10703.30, 1264.23, 174.45, 51.9035, 128.7865, 180.3077),
|
||||
(4, 88, 6630.87, 9614.75, 13582.12, 0.00, 10980.43, 1377.82, 186.66, 52.5700, 127.0960, 181.8565),
|
||||
(4, 89, 6808.31, 9693.74, 13609.82, 0.00, 11258.01, 1497.69, 199.39, 53.2365, 125.0542, 183.1813),
|
||||
(4, 90, 6989.33, 9765.61, 13610.80, 0.00, 11536.07, 1623.85, 212.64, 53.9030, 122.6611, 184.2821),
|
||||
(4, 91, 7173.93, 9830.39, 13585.08, 0.00, 11814.58, 1756.29, 226.40, 54.5695, 119.9166, 185.1587),
|
||||
(4, 92, 7362.12, 9888.05, 13532.64, 0.00, 12093.56, 1895.01, 240.67, 55.2360, 116.8207, 185.8114),
|
||||
(4, 93, 7553.90, 9938.61, 13453.49, 0.00, 12373.01, 2040.02, 255.46, 55.9024, 113.3736, 186.2400),
|
||||
(4, 94, 7749.25, 9982.06, 13347.63, 0.00, 12652.92, 2191.31, 270.76, 56.5689, 109.5750, 186.4446),
|
||||
(4, 95, 7948.20, 10018.40, 13215.06, 0.00, 12933.29, 2348.88, 286.57, 57.2353, 105.4251, 186.4251),
|
||||
(4, 96, 8150.72, 10047.64, 13055.78, 0.00, 13214.13, 2512.74, 302.90, 57.9018, 100.9239, 186.1815),
|
||||
(4, 97, 8356.83, 10069.76, 12869.79, 0.00, 13495.44, 2682.88, 319.75, 58.5682, 96.0713, 185.7140),
|
||||
(4, 98, 8566.53, 10084.79, 12657.08, 0.00, 13777.20, 2859.31, 337.11, 59.2346, 90.8674, 185.0224),
|
||||
(4, 99, 8779.81, 10092.70, 12417.67, 0.00, 14059.44, 3042.02, 354.98, 59.9010, 85.3122, 184.1067),
|
||||
(4, 100, 8996.67, 10093.51, 12151.54, 0.00, 14342.13, 3231.01, 373.37, 60.5674, 79.4055, 182.9670),
|
||||
(8, 81, 3853.15, 6497.25, 10112.28, 8981.17, 8066.17, 319.55, 75.82, 40.6653, 133.4978, 153.8368),
|
||||
(8, 82, 3957.29, 6645.09, 10284.07, 9154.91, 8310.42, 353.50, 82.44, 41.2315, 137.6156, 156.5130),
|
||||
(8, 83, 4063.40, 6793.05, 10434.49, 9330.41, 8555.06, 390.26, 89.47, 41.7978, 141.7353, 158.9818),
|
||||
(8, 84, 4171.48, 6941.12, 10563.54, 9507.68, 8800.11, 429.82, 96.90, 42.3640, 145.8569, 161.2435),
|
||||
(8, 85, 4281.53, 7089.30, 10671.23, 9686.70, 9045.55, 472.19, 104.72, 42.9302, 149.9803, 163.2979),
|
||||
(8, 86, 4393.56, 7237.60, 10757.54, 9867.49, 9291.39, 517.36, 112.95, 43.4965, 154.1056, 165.1450),
|
||||
(8, 87, 4507.55, 7386.01, 10822.49, 10050.04, 9537.63, 565.34, 121.58, 44.0627, 158.2327, 166.7849),
|
||||
(8, 88, 4623.52, 7534.53, 10866.07, 10234.35, 9784.27, 616.12, 130.61, 44.6289, 162.3617, 168.2176),
|
||||
(8, 89, 4741.45, 7683.17, 10888.28, 10420.42, 10031.31, 669.71, 140.04, 45.1951, 166.4926, 169.4430),
|
||||
(8, 90, 4861.36, 7831.91, 10889.12, 10608.25, 10278.75, 726.10, 149.87, 45.7613, 170.6253, 170.4611),
|
||||
(8, 91, 4983.24, 7980.78, 10868.59, 10797.85, 10526.58, 785.30, 160.10, 46.3276, 174.7599, 171.2721),
|
||||
(8, 92, 5107.09, 8129.75, 10826.70, 10989.20, 10774.82, 847.30, 170.73, 46.8938, 178.8964, 171.8757),
|
||||
(8, 93, 5232.91, 8278.84, 10763.43, 11182.32, 11023.45, 912.11, 181.76, 47.4600, 183.0347, 172.2722),
|
||||
(8, 94, 5360.71, 8428.05, 10678.80, 11377.19, 11272.48, 979.72, 193.19, 48.0262, 187.1749, 172.4614),
|
||||
(8, 95, 5490.47, 8577.36, 10572.80, 11573.83, 11521.91, 1050.14, 205.03, 48.5924, 191.3170, 172.4433),
|
||||
(8, 96, 5622.20, 8726.79, 10445.43, 11772.23, 11771.74, 1123.36, 217.26, 49.1586, 195.4609, 172.2180),
|
||||
(8, 97, 5755.91, 8876.34, 10296.69, 11972.39, 12021.96, 1199.39, 229.90, 49.7248, 199.6067, 171.7855),
|
||||
(8, 98, 5891.58, 9025.99, 10126.58, 12174.31, 12272.59, 1278.23, 242.93, 50.2910, 203.7543, 171.1457),
|
||||
(8, 99, 6029.23, 9175.76, 9935.10, 12378.00, 12523.61, 1359.87, 256.37, 50.8572, 207.9038, 170.2986),
|
||||
(8, 100, 6168.85, 9325.65, 9722.26, 12583.44, 12775.04, 1444.31, 270.20, 51.4234, 212.0552, 169.2444);
|
||||
247
data/sql/db-world/base/05_pet_levelstats.sql
Normal file
247
data/sql/db-world/base/05_pet_levelstats.sql
Normal file
@@ -0,0 +1,247 @@
|
||||
-- acore_world.pet_levelstats
|
||||
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (575, 81, 4399, 2307, 53, 112, 68, 39, 148, 96, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (575, 82, 4473, 2349, 53, 114, 70, 40, 151, 98, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (575, 83, 4548, 2390, 52, 116, 71, 41, 154, 100, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (575, 84, 4622, 2432, 51, 118, 72, 41, 156, 102, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (575, 85, 4697, 2473, 50, 120, 73, 42, 159, 103, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (575, 86, 4771, 2515, 49, 121, 74, 43, 162, 105, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (575, 87, 4846, 2556, 49, 123, 75, 43, 164, 107, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1860, 81, 4219, 2751, 11953, 200, 57, 325, 142, 159, 185, 284);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1860, 82, 4280, 2790, 12131, 203, 58, 330, 144, 161, 188, 288);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1860, 83, 4341, 2829, 12308, 205, 59, 334, 146, 163, 191, 293);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1860, 84, 4402, 2868, 12486, 208, 60, 338, 148, 165, 194, 297);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1860, 85, 4463, 2907, 12664, 211, 61, 342, 150, 167, 197, 302);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1860, 86, 4525, 2945, 12841, 213, 61, 347, 152, 169, 200, 306);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1860, 87, 4586, 2984, 13019, 216, 62, 351, 153, 171, 203, 311);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (3450, 81, 1279, 2497, 1, 188, 43, 118, 386, 388, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (3450, 82, 1297, 2530, 1, 190, 43, 120, 391, 393, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (3450, 83, 1315, 2562, 1, 193, 43, 121, 396, 398, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (3450, 84, 1333, 2595, 1, 195, 44, 123, 401, 403, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (3450, 85, 1351, 2628, 1, 197, 44, 124, 406, 409, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (3450, 86, 1368, 2661, 1, 200, 44, 125, 411, 414, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (3450, 87, 1386, 2694, 1, 202, 45, 127, 417, 419, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (10979, 81, 1279, 2497, 1, 188, 43, 118, 386, 388, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (10979, 82, 1297, 2530, 1, 190, 43, 120, 391, 393, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (10979, 83, 1315, 2562, 1, 193, 43, 121, 396, 398, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (10979, 84, 1333, 2595, 1, 195, 44, 123, 401, 403, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (10979, 85, 1351, 2628, 1, 197, 44, 124, 406, 409, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (10979, 86, 1368, 2661, 1, 200, 44, 125, 411, 414, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (10979, 87, 1386, 2694, 1, 202, 45, 127, 417, 419, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (14385, 81, 4635, 2170, 5204, 180, 97, 94, 101, 89, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (14385, 82, 4693, 2197, 5273, 182, 98, 95, 102, 90, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (14385, 83, 4750, 2223, 5341, 184, 99, 96, 103, 91, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (14385, 84, 4808, 2249, 5410, 186, 100, 97, 104, 92, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (14385, 85, 4865, 2275, 5478, 188, 101, 98, 105, 93, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (14385, 86, 4923, 2301, 5547, 190, 102, 99, 106, 94, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (14385, 87, 4980, 2328, 5616, 192, 103, 100, 107, 95, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15438, 81, 4280, 1253, 601, 139, 86, 65, 211, 233, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15438, 82, 4356, 1275, 612, 142, 88, 66, 214, 237, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15438, 83, 4432, 1297, 622, 144, 89, 67, 218, 241, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15438, 84, 4508, 1319, 633, 147, 91, 68, 222, 245, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15438, 85, 4584, 1341, 644, 149, 92, 69, 225, 249, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15438, 86, 4660, 1364, 654, 152, 94, 71, 229, 253, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15438, 87, 4735, 1386, 665, 154, 95, 72, 233, 257, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (329, 81, 4251, 2478, 1602, 131, 40, 225, 367, 352, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (329, 82, 4319, 2511, 1623, 133, 40, 227, 372, 357, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (329, 83, 4387, 2545, 1644, 134, 41, 230, 377, 361, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (329, 84, 4455, 2578, 1665, 135, 41, 232, 382, 366, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (329, 85, 4523, 2611, 1685, 137, 42, 234, 387, 371, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (329, 86, 4591, 2645, 1706, 138, 42, 237, 392, 376, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (329, 87, 4658, 2678, 1727, 139, 43, 239, 397, 380, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (26101, 81, 1045, 1133, 275, 84, 21, 56, 185, 206, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (26101, 82, 1064, 1153, 280, 85, 21, 57, 188, 209, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (26101, 83, 1082, 1174, 285, 87, 21, 58, 191, 213, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (26101, 84, 1100, 1194, 289, 88, 22, 59, 195, 217, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (26101, 85, 1119, 1214, 294, 90, 22, 60, 198, 220, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (26101, 86, 1137, 1234, 299, 91, 23, 61, 201, 224, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (26101, 87, 1155, 1255, 303, 93, 23, 62, 205, 228, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24815, 81, 1279, 2497, 1, 188, 43, 118, 386, 388, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24815, 82, 1297, 2530, 1, 190, 43, 120, 391, 393, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24815, 83, 1315, 2562, 1, 193, 43, 121, 396, 398, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24815, 84, 1333, 2595, 1, 195, 44, 123, 401, 403, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24815, 85, 1351, 2628, 1, 197, 44, 124, 406, 409, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24815, 86, 1368, 2661, 1, 200, 44, 125, 411, 414, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24815, 87, 1386, 2694, 1, 202, 45, 127, 417, 419, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15352, 81, 4774, 1, 4996, 122, 51, 75, 97, 257, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15352, 82, 4858, 1, 5084, 124, 52, 76, 99, 261, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15352, 83, 4942, 1, 5172, 127, 53, 78, 100, 266, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15352, 84, 5026, 1, 5260, 129, 54, 79, 102, 270, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15352, 85, 5111, 1, 5349, 131, 54, 80, 104, 275, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15352, 86, 5195, 1, 5437, 133, 55, 82, 106, 279, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15352, 87, 5279, 1, 5525, 135, 56, 83, 107, 284, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24656, 81, 3348, 2277, 4266, 83, 59, 161, 78, 77, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24656, 82, 3408, 2318, 4343, 84, 60, 164, 79, 78, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24656, 83, 3467, 2358, 4419, 85, 61, 167, 81, 80, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24656, 84, 3527, 2399, 4496, 87, 63, 170, 82, 81, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24656, 85, 3587, 2440, 4572, 88, 64, 173, 83, 82, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24656, 86, 3647, 2481, 4649, 90, 65, 176, 85, 84, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24656, 87, 3707, 2522, 4725, 91, 66, 178, 86, 85, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (25566, 81, 3701, 3657, 4117, 168, 80, 219, 265, 259, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (25566, 82, 3763, 3711, 4191, 170, 80, 222, 268, 262, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (25566, 83, 3824, 3765, 4265, 172, 81, 226, 271, 265, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (25566, 84, 3885, 3818, 4338, 174, 82, 229, 274, 268, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (25566, 85, 3947, 3872, 4412, 176, 83, 232, 277, 271, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (25566, 86, 4008, 3926, 4486, 178, 84, 235, 280, 274, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (25566, 87, 4069, 3980, 4560, 180, 85, 238, 283, 276, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (26125, 81, 4635, 2170, 5204, 187, 105, 107, 101, 89, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (26125, 82, 4693, 2197, 5273, 189, 106, 108, 102, 90, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (26125, 83, 4750, 2223, 5341, 192, 107, 109, 103, 91, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (26125, 84, 4808, 2249, 5410, 194, 108, 111, 104, 92, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (26125, 85, 4865, 2275, 5478, 196, 109, 112, 105, 93, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (26125, 86, 4923, 2301, 5547, 198, 110, 113, 106, 94, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (26125, 87, 4980, 2328, 5616, 200, 112, 115, 107, 95, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (5766, 81, 2931, 1473, 5001, 178, 88, 327, 226, 210, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (5766, 82, 2976, 1488, 5083, 181, 89, 331, 228, 212, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (5766, 83, 3020, 1504, 5165, 183, 90, 335, 231, 214, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (5766, 84, 3064, 1519, 5247, 185, 91, 340, 233, 217, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (5766, 85, 3108, 1534, 5329, 187, 93, 344, 236, 219, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (5766, 86, 3152, 1550, 5411, 190, 94, 348, 238, 221, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (5766, 87, 3196, 1565, 5492, 192, 95, 352, 241, 223, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (416, 81, 2865, 2704, 4623, 185, 49, 113, 373, 306, 207, 312);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (416, 82, 2906, 2741, 4691, 188, 50, 114, 377, 310, 211, 317);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (416, 83, 2947, 2778, 4758, 190, 50, 116, 382, 314, 214, 322);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (416, 84, 2989, 2815, 4826, 192, 51, 117, 387, 318, 217, 327);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (416, 85, 3030, 2852, 4894, 195, 51, 118, 391, 322, 220, 332);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (416, 86, 3071, 2890, 4962, 197, 51, 119, 396, 326, 224, 337);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (416, 87, 3112, 2927, 5030, 200, 52, 121, 401, 330, 227, 342);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (5058, 81, 5070, 2339, 7812, 179, 131, 359, 121, 120, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (5058, 82, 5147, 2367, 7932, 181, 133, 364, 123, 121, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (5058, 83, 5224, 2396, 8053, 184, 135, 368, 124, 122, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (5058, 84, 5300, 2424, 8174, 186, 136, 373, 125, 124, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (5058, 85, 5377, 2453, 8295, 188, 138, 378, 127, 125, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (5058, 86, 5454, 2481, 8415, 190, 139, 382, 128, 126, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (5058, 87, 5530, 2509, 8536, 193, 141, 387, 130, 127, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (6250, 81, 2931, 1473, 5001, 178, 88, 327, 226, 210, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (6250, 82, 2976, 1488, 5083, 181, 89, 331, 228, 212, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (6250, 83, 3020, 1504, 5165, 183, 90, 335, 231, 214, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (6250, 84, 3064, 1519, 5247, 185, 91, 340, 233, 217, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (6250, 85, 3108, 1534, 5329, 187, 93, 344, 236, 219, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (6250, 86, 3152, 1550, 5411, 190, 94, 348, 238, 221, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (6250, 87, 3196, 1565, 5492, 192, 95, 352, 241, 223, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (8996, 81, 3280, 2467, 4389, 197, 90, 244, 252, 310, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (8996, 82, 3319, 2500, 4438, 199, 90, 247, 256, 315, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (8996, 83, 3357, 2533, 4487, 202, 91, 250, 260, 319, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (8996, 84, 3396, 2566, 4536, 205, 92, 253, 264, 324, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (8996, 85, 3435, 2600, 4585, 207, 93, 255, 268, 328, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (8996, 86, 3473, 2633, 4634, 210, 94, 258, 271, 333, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (8996, 87, 3512, 2666, 4683, 212, 95, 261, 275, 337, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (30230, 81, 4635, 2170, 5204, 187, 105, 107, 101, 89, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (30230, 82, 4693, 2197, 5273, 189, 106, 108, 102, 90, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (30230, 83, 4750, 2223, 5341, 192, 107, 109, 103, 91, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (30230, 84, 4808, 2249, 5410, 194, 108, 111, 104, 92, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (30230, 85, 4865, 2275, 5478, 196, 109, 112, 105, 93, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (30230, 86, 4923, 2301, 5547, 198, 110, 113, 106, 94, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (30230, 87, 4980, 2328, 5616, 200, 112, 115, 107, 95, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1, 81, 4531, 1, 7244, 183, 141, 347, 65, 108, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1, 82, 4596, 1, 7351, 185, 143, 352, 66, 109, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1, 83, 4661, 1, 7458, 187, 145, 356, 66, 110, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1, 84, 4725, 1, 7565, 189, 146, 360, 67, 111, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1, 85, 4790, 1, 7671, 192, 148, 365, 67, 113, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1, 86, 4855, 1, 7778, 194, 150, 369, 68, 114, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1, 87, 4920, 1, 7885, 196, 152, 374, 69, 115, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (37994, 81, 6409, 2978, 4804, 177, 126, 128, 311, 215, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (37994, 82, 6505, 3018, 4873, 179, 127, 129, 316, 218, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (37994, 83, 6602, 3057, 4943, 181, 129, 130, 320, 221, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (37994, 84, 6698, 3096, 5013, 184, 131, 131, 325, 223, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (37994, 85, 6794, 3135, 5083, 186, 132, 132, 330, 226, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (37994, 86, 6891, 3175, 5153, 188, 134, 133, 334, 229, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (37994, 87, 6987, 3214, 5223, 190, 135, 134, 339, 232, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (22362, 81, 1279, 2497, 1084, 188, 43, 118, 386, 388, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (22362, 82, 1297, 2530, 1095, 190, 43, 120, 391, 393, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (22362, 83, 1315, 2562, 1107, 193, 43, 121, 396, 398, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (22362, 84, 1333, 2595, 1118, 195, 44, 123, 401, 403, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (22362, 85, 1351, 2628, 1129, 197, 44, 124, 406, 409, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (22362, 86, 1368, 2661, 1141, 200, 44, 125, 411, 414, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (22362, 87, 1386, 2694, 1152, 202, 45, 127, 417, 419, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1863, 81, 3508, 2779, 7257, 204, 59, 330, 146, 162, 240, 361);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1863, 82, 3560, 2819, 7368, 207, 60, 335, 148, 165, 244, 367);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1863, 83, 3612, 2859, 7479, 210, 60, 339, 150, 167, 248, 372);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1863, 84, 3664, 2899, 7589, 213, 61, 344, 152, 169, 252, 378);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1863, 85, 3717, 2940, 7700, 216, 62, 349, 154, 171, 255, 384);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1863, 86, 3769, 2980, 7810, 218, 63, 353, 156, 174, 259, 390);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (1863, 87, 3821, 3020, 7921, 221, 64, 358, 158, 176, 263, 395);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (19668, 81, 1728, 3131, 35, 126, 88, 54, 202, 131, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (19668, 82, 1756, 3186, 34, 128, 90, 55, 206, 133, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (19668, 83, 1785, 3241, 33, 130, 91, 56, 209, 136, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (19668, 84, 1814, 3296, 32, 132, 93, 57, 213, 138, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (19668, 85, 1842, 3351, 30, 134, 94, 58, 217, 140, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (19668, 86, 1871, 3407, 29, 136, 95, 59, 220, 143, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (19668, 87, 1900, 3462, 28, 139, 97, 60, 224, 145, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (89, 81, 16398, 3013, 11256, 186, 54, 296, 132, 148, 823, 1145);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (89, 82, 16677, 3063, 11445, 189, 55, 301, 134, 150, 837, 1165);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (89, 83, 16955, 3113, 11634, 192, 56, 306, 137, 153, 851, 1184);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (89, 84, 17234, 3162, 11823, 195, 56, 311, 139, 155, 865, 1204);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (89, 85, 17512, 3212, 12012, 198, 57, 316, 141, 158, 879, 1223);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (89, 86, 17790, 3262, 12201, 201, 58, 320, 143, 160, 892, 1243);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (89, 87, 18069, 3311, 12390, 204, 59, 325, 145, 163, 906, 1262);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (3939, 81, 3783, 3632, 5236, 172, 79, 331, 260, 223, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (3939, 82, 3842, 3686, 5322, 175, 80, 335, 263, 226, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (3939, 83, 3902, 3740, 5408, 177, 81, 339, 266, 228, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (3939, 84, 3961, 3795, 5494, 179, 82, 343, 269, 231, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (3939, 85, 4021, 3849, 5580, 181, 83, 348, 272, 233, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (3939, 86, 4080, 3903, 5666, 183, 84, 352, 275, 235, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (3939, 87, 4139, 3957, 5752, 185, 85, 356, 278, 238, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (10928, 81, 1900, 2464, 2053, 202, 89, 248, 242, 316, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (10928, 82, 1924, 2497, 2079, 205, 90, 251, 246, 321, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (10928, 83, 1948, 2530, 2105, 207, 91, 254, 250, 326, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (10928, 84, 1973, 2564, 2130, 210, 92, 257, 254, 330, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (10928, 85, 1997, 2597, 2156, 213, 93, 260, 258, 335, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (10928, 86, 2021, 2630, 2182, 216, 94, 263, 262, 340, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (10928, 87, 2046, 2663, 2208, 219, 95, 266, 265, 345, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (12922, 81, 1279, 2497, 1, 188, 43, 118, 386, 388, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (12922, 82, 1297, 2530, 1, 190, 43, 120, 391, 393, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (12922, 83, 1315, 2562, 1, 193, 43, 121, 396, 398, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (12922, 84, 1333, 2595, 1, 195, 44, 123, 401, 403, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (12922, 85, 1351, 2628, 1, 197, 44, 124, 406, 409, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (12922, 86, 1368, 2661, 1, 200, 44, 125, 411, 414, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (12922, 87, 1386, 2694, 1, 202, 45, 127, 417, 419, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (510, 81, 6409, 2978, 4804, 177, 126, 128, 311, 215, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (510, 82, 6505, 3018, 4873, 179, 127, 129, 316, 218, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (510, 83, 6602, 3057, 4943, 181, 129, 130, 320, 221, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (510, 84, 6698, 3096, 5013, 184, 131, 131, 325, 223, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (510, 85, 6794, 3135, 5083, 186, 132, 132, 330, 226, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (510, 86, 6891, 3175, 5153, 188, 134, 133, 334, 229, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (510, 87, 6987, 3214, 5223, 190, 135, 134, 339, 232, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (8477, 81, 3280, 2467, 4389, 197, 90, 244, 252, 310, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (8477, 82, 3319, 2500, 4438, 199, 90, 247, 256, 315, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (8477, 83, 3357, 2533, 4487, 202, 91, 250, 260, 319, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (8477, 84, 3396, 2566, 4536, 205, 92, 253, 264, 324, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (8477, 85, 3435, 2600, 4585, 207, 93, 255, 268, 328, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (8477, 86, 3473, 2633, 4634, 210, 94, 258, 271, 333, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (8477, 87, 3512, 2666, 4683, 212, 95, 261, 275, 337, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15214, 81, 3783, 3632, 5236, 172, 79, 331, 260, 223, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15214, 82, 3842, 3686, 5322, 175, 80, 335, 263, 226, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15214, 83, 3902, 3740, 5408, 177, 81, 339, 266, 228, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15214, 84, 3961, 3795, 5494, 179, 82, 343, 269, 231, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15214, 85, 4021, 3849, 5580, 181, 83, 348, 272, 233, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15214, 86, 4080, 3903, 5666, 183, 84, 352, 275, 235, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (15214, 87, 4139, 3957, 5752, 185, 85, 356, 278, 238, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (17252, 81, 3926, 2540, 9780, 186, 54, 296, 132, 148, 216, 327);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (17252, 82, 3992, 2582, 9944, 189, 55, 301, 134, 150, 219, 333);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (17252, 83, 4057, 2624, 10109, 192, 56, 306, 137, 153, 223, 338);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (17252, 84, 4122, 2666, 10273, 195, 56, 311, 139, 155, 227, 344);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (17252, 85, 4187, 2708, 10437, 198, 57, 316, 141, 158, 230, 349);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (17252, 86, 4253, 2750, 10601, 201, 58, 320, 143, 160, 234, 355);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (17252, 87, 4318, 2792, 10765, 204, 59, 325, 145, 163, 238, 361);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24476, 81, 2931, 1473, 5001, 178, 88, 327, 226, 210, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24476, 82, 2976, 1488, 5083, 181, 89, 331, 228, 212, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24476, 83, 3020, 1504, 5165, 183, 90, 335, 231, 214, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24476, 84, 3064, 1519, 5247, 185, 91, 340, 233, 217, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24476, 85, 3108, 1534, 5329, 187, 93, 344, 236, 219, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24476, 86, 3152, 1550, 5411, 190, 94, 348, 238, 221, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (24476, 87, 3196, 1565, 5492, 192, 95, 352, 241, 223, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (25553, 81, 3783, 3632, 5236, 172, 79, 331, 260, 223, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (25553, 82, 3842, 3686, 5322, 175, 80, 335, 263, 226, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (25553, 83, 3902, 3740, 5408, 177, 81, 339, 266, 228, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (25553, 84, 3961, 3795, 5494, 179, 82, 343, 269, 231, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (25553, 85, 4021, 3849, 5580, 181, 83, 348, 272, 233, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (25553, 86, 4080, 3903, 5666, 183, 84, 352, 275, 235, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (25553, 87, 4139, 3957, 5752, 185, 85, 356, 278, 238, 1, 1);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (417, 81, 3713, 2790, 5836, 205, 59, 332, 147, 163, 170, 262);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (417, 82, 3770, 2832, 5928, 208, 60, 337, 149, 166, 173, 267);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (417, 83, 3827, 2874, 6019, 211, 61, 342, 151, 168, 175, 271);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (417, 84, 3884, 2916, 6111, 214, 62, 347, 153, 171, 178, 275);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (417, 85, 3941, 2958, 6203, 217, 63, 352, 155, 173, 181, 280);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (417, 86, 3998, 3000, 6294, 221, 63, 357, 158, 176, 184, 284);
|
||||
REPLACE INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) VALUES (417, 87, 4055, 3042, 6386, 224, 64, 361, 160, 178, 187, 295);
|
||||
51
data/sql/db-world/base/06_player_class_stats.sql
Normal file
51
data/sql/db-world/base/06_player_class_stats.sql
Normal file
@@ -0,0 +1,51 @@
|
||||
/** Attempts to insert all post-80 player class stats into the database. */
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (1, 81, 9485, 0, 209, 138, 193, 45, 71);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (1, 82, 10434, 0, 211, 139, 195, 45, 72);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (1, 83, 11477, 0, 213, 140, 197, 45, 73);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (1, 84, 12594, 0, 215, 142, 199, 46, 74);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (1, 85, 13793, 0, 218, 143, 201, 46, 75);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (2, 81, 7449, 4564, 166, 100, 158, 109, 112);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (2, 82, 8078, 4693, 169, 101, 161, 111, 113);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (2, 83, 8737, 4822, 172, 103, 164, 112, 115);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (2, 84, 9427, 4951, 175, 104, 166, 114, 116);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (2, 85, 10151, 5080, 178, 106, 169, 116, 118);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (3, 81, 7482, 4916, 78, 189, 134, 94, 102);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (3, 82, 8070, 5084, 79, 192, 136, 95, 103);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (3, 83, 8681, 5252, 80, 195, 138, 97, 105);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (3, 84, 9315, 5419, 81, 198, 140, 98, 107);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (3, 85, 9973, 5587, 82, 201, 142, 100, 108);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (4, 81, 7246, 0, 121, 200, 113, 47, 71);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (4, 82, 7814, 0, 123, 203, 114, 48, 72);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (4, 83, 8407, 0, 124, 206, 116, 48, 73);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (4, 84, 9025, 0, 126, 209, 117, 49, 74);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (4, 85, 9670, 0, 128, 212, 119, 50, 75);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (5, 81, 7395, 4153, 49, 57, 74, 197, 205);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (5, 82, 7975, 4280, 49, 58, 75, 201, 208);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (5, 83, 8581, 4407, 50, 58, 76, 204, 211);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (5, 84, 9215, 4534, 50, 59, 77, 207, 215);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (5, 85, 9876, 4661, 51, 60, 78, 210, 218);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (6, 81, 8118, 0, 176, 114, 166, 37, 58);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (6, 82, 8740, 0, 179, 116, 169, 37, 59);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (6, 83, 9390, 0, 181, 117, 172, 37, 60);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (6, 84, 10070, 0, 184, 119, 175, 38, 61);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (6, 85, 10802, 0, 187, 121, 178, 38, 61);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (7, 81, 7382, 4562, 123, 77, 139, 131, 145);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (7, 82, 7981, 4692, 123, 78, 141, 134, 147);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (7, 83, 8607, 4823, 125, 79, 143, 137, 149);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (7, 84, 9259, 4953, 126, 80, 145, 139, 151);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (7, 85, 9939, 5083, 128, 81, 147, 142, 153);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (8, 81, 7382, 3446, 39, 47, 61, 207, 197);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (8, 82, 7981, 3546, 39, 47, 62, 211, 201);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (8, 83, 8607, 3647, 40, 48, 63, 214, 204);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (8, 84, 9259, 3748, 40, 48, 63, 218, 208);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (8, 85, 9939, 3849, 40, 49, 64, 221, 211);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (9, 81, 7153, 3690, 61, 69, 92, 158, 165);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (9, 82, 7700, 3817, 62, 70, 93, 161, 168);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (9, 83, 8266, 3944, 63, 71, 94, 164, 171);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (9, 84, 8852, 4072, 63, 72, 95, 166, 175);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (9, 85, 9460, 4199, 64, 73, 96, 169, 178);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (11, 81, 5694, 3227, 99, 90, 106, 163, 180);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (11, 82, 6132, 3342, 100, 91, 108, 166, 183);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (11, 83, 6596, 3458, 101, 92, 109, 168, 186);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (11, 84, 7086, 3573, 102, 94, 111, 171, 190);
|
||||
insert ignore into acore_world.player_class_stats (Class, Level, BaseHP, BaseMana, Strength, Agility, Stamina, Intellect, Spirit) values (11, 85, 7601, 3688, 104, 95, 113, 174, 193);
|
||||
253
data/sql/db-world/base/07_mp_upgrade_ranks.sql
Normal file
253
data/sql/db-world/base/07_mp_upgrade_ranks.sql
Normal file
@@ -0,0 +1,253 @@
|
||||
-- SQL Script to Insert 50 Ranks for Each Stat
|
||||
REPLACE INTO mp_upgrade_ranks (upgradeRank, advancementId, materialId1, materialCost1, materialId2, materialCost2, materialId3, materialCost3, minIncrease1, maxIncrease1, minIncrease2, maxIncrease2, minIncrease3, maxIncrease3, chanceCost1, chanceCost2, chanceCost3) VALUES
|
||||
(1, 3, 7, 100, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 20, 50, 75),
|
||||
(2, 3, 7, 150, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 23, 53, 78),
|
||||
(3, 3, 7, 200, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 26, 56, 81),
|
||||
(4, 3, 7, 250, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 29, 59, 84),
|
||||
(5, 3, 7, 300, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 32, 62, 87),
|
||||
(6, 3, 7, 350, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 35, 65, 90),
|
||||
(7, 3, 7, 400, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 38, 68, 93),
|
||||
(8, 3, 7, 450, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 41, 71, 96),
|
||||
(9, 3, 7, 500, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 44, 74, 99),
|
||||
(10, 3, 7, 550, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 47, 77, 102),
|
||||
(11, 3, 7, 500, 8, 0, 0, 0, 3, 12, 7, 12, 12, 15, 50, 80, 105),
|
||||
(12, 3, 7, 525, 8, 10, 0, 0, 3, 12, 7, 12, 12, 15, 53, 83, 108),
|
||||
(13, 3, 7, 550, 8, 20, 0, 0, 3, 12, 7, 12, 12, 15, 56, 86, 111),
|
||||
(14, 3, 7, 575, 8, 30, 0, 0, 3, 12, 7, 12, 12, 15, 59, 89, 114),
|
||||
(15, 3, 7, 600, 8, 40, 0, 0, 3, 12, 7, 12, 12, 15, 62, 92, 117),
|
||||
(16, 3, 7, 625, 8, 50, 0, 0, 3, 12, 7, 12, 12, 15, 65, 95, 120),
|
||||
(17, 3, 7, 650, 8, 60, 0, 0, 3, 12, 7, 12, 12, 15, 68, 98, 123),
|
||||
(18, 3, 7, 675, 8, 70, 0, 0, 3, 12, 7, 12, 12, 15, 71, 101, 126),
|
||||
(19, 3, 7, 700, 8, 80, 0, 0, 3, 12, 7, 12, 12, 15, 74, 104, 129),
|
||||
(20, 3, 7, 725, 8, 90, 0, 0, 3, 12, 7, 12, 12, 15, 77, 107, 132),
|
||||
(21, 3, 7, 750, 8, 100, 0, 0, 5, 14, 9, 14, 16, 19, 80, 110, 135),
|
||||
(22, 3, 7, 775, 8, 110, 0, 0, 5, 14, 9, 14, 16, 19, 83, 113, 138),
|
||||
(23, 3, 7, 800, 8, 120, 0, 0, 5, 14, 9, 14, 16, 19, 86, 116, 141),
|
||||
(24, 3, 7, 825, 8, 130, 0, 0, 5, 14, 9, 14, 16, 19, 89, 119, 144),
|
||||
(25, 3, 7, 850, 8, 140, 0, 0, 5, 14, 9, 14, 16, 19, 92, 122, 147),
|
||||
(26, 3, 7, 875, 8, 150, 0, 0, 5, 14, 9, 14, 16, 19, 95, 125, 150),
|
||||
(27, 3, 7, 900, 8, 160, 0, 0, 5, 14, 9, 14, 16, 19, 98, 128, 153),
|
||||
(28, 3, 7, 925, 8, 170, 0, 0, 5, 14, 9, 14, 16, 19, 101, 131, 156),
|
||||
(29, 3, 7, 950, 8, 180, 0, 0, 5, 14, 9, 14, 16, 19, 104, 134, 159),
|
||||
(30, 3, 7, 1000, 8, 190, 20, 3, 5, 14, 9, 14, 16, 19, 107, 137, 162),
|
||||
(31, 3, 7, 1018, 8, 200, 20, 6, 7, 16, 11, 16, 20, 23, 110, 140, 165),
|
||||
(32, 3, 7, 1036, 8, 210, 20, 9, 7, 16, 11, 16, 20, 23, 113, 143, 168),
|
||||
(33, 3, 7, 1054, 8, 220, 20, 12, 7, 16, 11, 16, 20, 23, 116, 146, 171),
|
||||
(34, 3, 7, 1072, 8, 230, 20, 15, 7, 16, 11, 16, 20, 23, 119, 149, 174),
|
||||
(35, 3, 7, 1090, 8, 240, 20, 18, 7, 16, 11, 16, 20, 23, 122, 152, 177),
|
||||
(36, 3, 7, 1108, 8, 250, 20, 21, 7, 16, 11, 16, 20, 23, 125, 155, 180),
|
||||
(37, 3, 7, 1126, 8, 260, 20, 24, 7, 16, 11, 16, 20, 23, 128, 158, 183),
|
||||
(38, 3, 7, 1144, 8, 270, 20, 27, 7, 16, 11, 16, 20, 23, 131, 161, 186),
|
||||
(39, 3, 7, 1162, 8, 280, 20, 30, 7, 16, 11, 16, 20, 23, 134, 164, 189),
|
||||
(40, 3, 7, 1180, 8, 290, 20, 33, 7, 16, 11, 16, 20, 23, 137, 167, 192),
|
||||
(41, 3, 7, 1198, 8, 300, 20, 36, 9, 18, 13, 18, 24, 27, 140, 170, 195),
|
||||
(42, 3, 7, 1216, 8, 310, 20, 39, 9, 18, 13, 18, 24, 27, 143, 173, 198),
|
||||
(43, 3, 7, 1234, 8, 320, 20, 42, 9, 18, 13, 18, 24, 27, 146, 176, 201),
|
||||
(44, 3, 7, 1252, 8, 330, 20, 45, 9, 18, 13, 18, 24, 27, 149, 179, 204),
|
||||
(45, 3, 7, 1270, 8, 340, 20, 48, 9, 18, 13, 18, 24, 27, 152, 182, 207),
|
||||
(46, 3, 7, 1288, 8, 350, 20, 51, 9, 18, 13, 18, 24, 27, 155, 185, 210),
|
||||
(47, 3, 7, 1306, 8, 360, 20, 54, 9, 18, 13, 18, 24, 27, 158, 188, 213),
|
||||
(48, 3, 7, 1324, 8, 370, 20, 57, 9, 18, 13, 18, 24, 27, 161, 191, 216),
|
||||
(49, 3, 7, 1342, 8, 380, 20, 60, 9, 18, 13, 18, 24, 27, 164, 194, 219),
|
||||
(50, 3, 7, 1360, 8, 390, 20, 63, 9, 18, 13, 18, 24, 27, 167, 197, 222),
|
||||
(1, 4, 9, 100, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 20, 50, 75),
|
||||
(2, 4, 9, 150, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 23, 53, 78),
|
||||
(3, 4, 9, 200, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 26, 56, 81),
|
||||
(4, 4, 9, 250, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 29, 59, 84),
|
||||
(5, 4, 9, 300, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 32, 62, 87),
|
||||
(6, 4, 9, 350, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 35, 65, 90),
|
||||
(7, 4, 9, 400, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 38, 68, 93),
|
||||
(8, 4, 9, 450, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 41, 71, 96),
|
||||
(9, 4, 9, 500, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 44, 74, 99),
|
||||
(10, 4, 9, 550, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 47, 77, 102),
|
||||
(11, 4, 9, 500, 10, 0, 0, 0, 3, 12, 7, 12, 12, 15, 50, 80, 105),
|
||||
(12, 4, 9, 525, 10, 10, 0, 0, 3, 12, 7, 12, 12, 15, 53, 83, 108),
|
||||
(13, 4, 9, 550, 10, 20, 0, 0, 3, 12, 7, 12, 12, 15, 56, 86, 111),
|
||||
(14, 4, 9, 575, 10, 30, 0, 0, 3, 12, 7, 12, 12, 15, 59, 89, 114),
|
||||
(15, 4, 9, 600, 10, 40, 0, 0, 3, 12, 7, 12, 12, 15, 62, 92, 117),
|
||||
(16, 4, 9, 625, 10, 50, 0, 0, 3, 12, 7, 12, 12, 15, 65, 95, 120),
|
||||
(17, 4, 9, 650, 10, 60, 0, 0, 3, 12, 7, 12, 12, 15, 68, 98, 123),
|
||||
(18, 4, 9, 675, 10, 70, 0, 0, 3, 12, 7, 12, 12, 15, 71, 101, 126),
|
||||
(19, 4, 9, 700, 10, 80, 0, 0, 3, 12, 7, 12, 12, 15, 74, 104, 129),
|
||||
(20, 4, 9, 725, 10, 90, 0, 0, 3, 12, 7, 12, 12, 15, 77, 107, 132),
|
||||
(21, 4, 9, 750, 10, 100, 0, 0, 5, 14, 9, 14, 16, 19, 80, 110, 135),
|
||||
(22, 4, 9, 775, 10, 110, 0, 0, 5, 14, 9, 14, 16, 19, 83, 113, 138),
|
||||
(23, 4, 9, 800, 10, 120, 0, 0, 5, 14, 9, 14, 16, 19, 86, 116, 141),
|
||||
(24, 4, 9, 825, 10, 130, 0, 0, 5, 14, 9, 14, 16, 19, 89, 119, 144),
|
||||
(25, 4, 9, 850, 10, 140, 0, 0, 5, 14, 9, 14, 16, 19, 92, 122, 147),
|
||||
(26, 4, 9, 875, 10, 150, 0, 0, 5, 14, 9, 14, 16, 19, 95, 125, 150),
|
||||
(27, 4, 9, 900, 10, 160, 0, 0, 5, 14, 9, 14, 16, 19, 98, 128, 153),
|
||||
(28, 4, 9, 925, 10, 170, 0, 0, 5, 14, 9, 14, 16, 19, 101, 131, 156),
|
||||
(29, 4, 9, 950, 10, 180, 0, 0, 5, 14, 9, 14, 16, 19, 104, 134, 159),
|
||||
(30, 4, 9, 1000, 10, 190, 20, 3, 5, 14, 9, 14, 16, 19, 107, 137, 162),
|
||||
(31, 4, 9, 1018, 10, 200, 20, 6, 7, 16, 11, 16, 20, 23, 110, 140, 165),
|
||||
(32, 4, 9, 1036, 10, 210, 20, 9, 7, 16, 11, 16, 20, 23, 113, 143, 168),
|
||||
(33, 4, 9, 1054, 10, 220, 20, 12, 7, 16, 11, 16, 20, 23, 116, 146, 171),
|
||||
(34, 4, 9, 1072, 10, 230, 20, 15, 7, 16, 11, 16, 20, 23, 119, 149, 174),
|
||||
(35, 4, 9, 1090, 10, 240, 20, 18, 7, 16, 11, 16, 20, 23, 122, 152, 177),
|
||||
(36, 4, 9, 1108, 10, 250, 20, 21, 7, 16, 11, 16, 20, 23, 125, 155, 180),
|
||||
(37, 4, 9, 1126, 10, 260, 20, 24, 7, 16, 11, 16, 20, 23, 128, 158, 183),
|
||||
(38, 4, 9, 1144, 10, 270, 20, 27, 7, 16, 11, 16, 20, 23, 131, 161, 186),
|
||||
(39, 4, 9, 1162, 10, 280, 20, 30, 7, 16, 11, 16, 20, 23, 134, 164, 189),
|
||||
(40, 4, 9, 1180, 10, 290, 20, 33, 7, 16, 11, 16, 20, 23, 137, 167, 192),
|
||||
(41, 4, 9, 1198, 10, 300, 20, 36, 9, 18, 13, 18, 24, 27, 140, 170, 195),
|
||||
(42, 4, 9, 1216, 10, 310, 20, 39, 9, 18, 13, 18, 24, 27, 143, 173, 198),
|
||||
(43, 4, 9, 1234, 10, 320, 20, 42, 9, 18, 13, 18, 24, 27, 146, 176, 201),
|
||||
(44, 4, 9, 1252, 10, 330, 20, 45, 9, 18, 13, 18, 24, 27, 149, 179, 204),
|
||||
(45, 4, 9, 1270, 10, 340, 20, 48, 9, 18, 13, 18, 24, 27, 152, 182, 207),
|
||||
(46, 4, 9, 1288, 10, 350, 20, 51, 9, 18, 13, 18, 24, 27, 155, 185, 210),
|
||||
(47, 4, 9, 1306, 10, 360, 20, 54, 9, 18, 13, 18, 24, 27, 158, 188, 213),
|
||||
(48, 4, 9, 1324, 10, 370, 20, 57, 9, 18, 13, 18, 24, 27, 161, 191, 216),
|
||||
(49, 4, 9, 1342, 10, 380, 20, 60, 9, 18, 13, 18, 24, 27, 164, 194, 219),
|
||||
(50, 4, 9, 1360, 10, 390, 20, 63, 9, 18, 13, 18, 24, 27, 167, 197, 222),
|
||||
(1, 0, 1, 100, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 20, 50, 75),
|
||||
(2, 0, 1, 150, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 23, 53, 78),
|
||||
(3, 0, 1, 200, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 26, 56, 81),
|
||||
(4, 0, 1, 250, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 29, 59, 84),
|
||||
(5, 0, 1, 300, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 32, 62, 87),
|
||||
(6, 0, 1, 350, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 35, 65, 90),
|
||||
(7, 0, 1, 400, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 38, 68, 93),
|
||||
(8, 0, 1, 450, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 41, 71, 96),
|
||||
(9, 0, 1, 500, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 44, 74, 99),
|
||||
(10, 0, 1, 550, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 47, 77, 102),
|
||||
(11, 0, 1, 500, 2, 0, 0, 0, 3, 12, 7, 12, 12, 15, 50, 80, 105),
|
||||
(12, 0, 1, 525, 2, 10, 0, 0, 3, 12, 7, 12, 12, 15, 53, 83, 108),
|
||||
(13, 0, 1, 550, 2, 20, 0, 0, 3, 12, 7, 12, 12, 15, 56, 86, 111),
|
||||
(14, 0, 1, 575, 2, 30, 0, 0, 3, 12, 7, 12, 12, 15, 59, 89, 114),
|
||||
(15, 0, 1, 600, 2, 40, 0, 0, 3, 12, 7, 12, 12, 15, 62, 92, 117),
|
||||
(16, 0, 1, 625, 2, 50, 0, 0, 3, 12, 7, 12, 12, 15, 65, 95, 120),
|
||||
(17, 0, 1, 650, 2, 60, 0, 0, 3, 12, 7, 12, 12, 15, 68, 98, 123),
|
||||
(18, 0, 1, 675, 2, 70, 0, 0, 3, 12, 7, 12, 12, 15, 71, 101, 126),
|
||||
(19, 0, 1, 700, 2, 80, 0, 0, 3, 12, 7, 12, 12, 15, 74, 104, 129),
|
||||
(20, 0, 1, 725, 2, 90, 0, 0, 3, 12, 7, 12, 12, 15, 77, 107, 132),
|
||||
(21, 0, 1, 750, 2, 100, 0, 0, 5, 14, 9, 14, 16, 19, 80, 110, 135),
|
||||
(22, 0, 1, 775, 2, 110, 0, 0, 5, 14, 9, 14, 16, 19, 83, 113, 138),
|
||||
(23, 0, 1, 800, 2, 120, 0, 0, 5, 14, 9, 14, 16, 19, 86, 116, 141),
|
||||
(24, 0, 1, 825, 2, 130, 0, 0, 5, 14, 9, 14, 16, 19, 89, 119, 144),
|
||||
(25, 0, 1, 850, 2, 140, 0, 0, 5, 14, 9, 14, 16, 19, 92, 122, 147),
|
||||
(26, 0, 1, 875, 2, 150, 0, 0, 5, 14, 9, 14, 16, 19, 95, 125, 150),
|
||||
(27, 0, 1, 900, 2, 160, 0, 0, 5, 14, 9, 14, 16, 19, 98, 128, 153),
|
||||
(28, 0, 1, 925, 2, 170, 0, 0, 5, 14, 9, 14, 16, 19, 101, 131, 156),
|
||||
(29, 0, 1, 950, 2, 180, 0, 0, 5, 14, 9, 14, 16, 19, 104, 134, 159),
|
||||
(30, 0, 1, 1000, 2, 190, 20, 3, 5, 14, 9, 14, 16, 19, 107, 137, 162),
|
||||
(31, 0, 1, 1018, 2, 200, 20, 6, 7, 16, 11, 16, 20, 23, 110, 140, 165),
|
||||
(32, 0, 1, 1036, 2, 210, 20, 9, 7, 16, 11, 16, 20, 23, 113, 143, 168),
|
||||
(33, 0, 1, 1054, 2, 220, 20, 12, 7, 16, 11, 16, 20, 23, 116, 146, 171),
|
||||
(34, 0, 1, 1072, 2, 230, 20, 15, 7, 16, 11, 16, 20, 23, 119, 149, 174),
|
||||
(35, 0, 1, 1090, 2, 240, 20, 18, 7, 16, 11, 16, 20, 23, 122, 152, 177),
|
||||
(36, 0, 1, 1108, 2, 250, 20, 21, 7, 16, 11, 16, 20, 23, 125, 155, 180),
|
||||
(37, 0, 1, 1126, 2, 260, 20, 24, 7, 16, 11, 16, 20, 23, 128, 158, 183),
|
||||
(38, 0, 1, 1144, 2, 270, 20, 27, 7, 16, 11, 16, 20, 23, 131, 161, 186),
|
||||
(39, 0, 1, 1162, 2, 280, 20, 30, 7, 16, 11, 16, 20, 23, 134, 164, 189),
|
||||
(40, 0, 1, 1180, 2, 290, 20, 33, 7, 16, 11, 16, 20, 23, 137, 167, 192),
|
||||
(41, 0, 1, 1198, 2, 300, 20, 36, 9, 18, 13, 18, 24, 27, 140, 170, 195),
|
||||
(42, 0, 1, 1216, 2, 310, 20, 39, 9, 18, 13, 18, 24, 27, 143, 173, 198),
|
||||
(43, 0, 1, 1234, 2, 320, 20, 42, 9, 18, 13, 18, 24, 27, 146, 176, 201),
|
||||
(44, 0, 1, 1252, 2, 330, 20, 45, 9, 18, 13, 18, 24, 27, 149, 179, 204),
|
||||
(45, 0, 1, 1270, 2, 340, 20, 48, 9, 18, 13, 18, 24, 27, 152, 182, 207),
|
||||
(46, 0, 1, 1288, 2, 350, 20, 51, 9, 18, 13, 18, 24, 27, 155, 185, 210),
|
||||
(47, 0, 1, 1306, 2, 360, 20, 54, 9, 18, 13, 18, 24, 27, 158, 188, 213),
|
||||
(48, 0, 1, 1324, 2, 370, 20, 57, 9, 18, 13, 18, 24, 27, 161, 191, 216),
|
||||
(49, 0, 1, 1342, 2, 380, 20, 60, 9, 18, 13, 18, 24, 27, 164, 194, 219),
|
||||
(50, 0, 1, 1360, 2, 390, 20, 63, 9, 18, 13, 18, 24, 27, 167, 197, 222),
|
||||
(1, 1, 3, 100, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 20, 50, 75),
|
||||
(2, 1, 3, 150, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 23, 53, 78),
|
||||
(3, 1, 3, 200, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 26, 56, 81),
|
||||
(4, 1, 3, 250, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 29, 59, 84),
|
||||
(5, 1, 3, 300, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 32, 62, 87),
|
||||
(6, 1, 3, 350, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 35, 65, 90),
|
||||
(7, 1, 3, 400, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 38, 68, 93),
|
||||
(8, 1, 3, 450, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 41, 71, 96),
|
||||
(9, 1, 3, 500, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 44, 74, 99),
|
||||
(10, 1, 3, 550, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 47, 77, 102),
|
||||
(11, 1, 3, 500, 4, 0, 0, 0, 3, 12, 7, 12, 12, 15, 50, 80, 105),
|
||||
(12, 1, 3, 525, 4, 10, 0, 0, 3, 12, 7, 12, 12, 15, 53, 83, 108),
|
||||
(13, 1, 3, 550, 4, 20, 0, 0, 3, 12, 7, 12, 12, 15, 56, 86, 111),
|
||||
(14, 1, 3, 575, 4, 30, 0, 0, 3, 12, 7, 12, 12, 15, 59, 89, 114),
|
||||
(15, 1, 3, 600, 4, 40, 0, 0, 3, 12, 7, 12, 12, 15, 62, 92, 117),
|
||||
(16, 1, 3, 625, 4, 50, 0, 0, 3, 12, 7, 12, 12, 15, 65, 95, 120),
|
||||
(17, 1, 3, 650, 4, 60, 0, 0, 3, 12, 7, 12, 12, 15, 68, 98, 123),
|
||||
(18, 1, 3, 675, 4, 70, 0, 0, 3, 12, 7, 12, 12, 15, 71, 101, 126),
|
||||
(19, 1, 3, 700, 4, 80, 0, 0, 3, 12, 7, 12, 12, 15, 74, 104, 129),
|
||||
(20, 1, 3, 725, 4, 90, 0, 0, 3, 12, 7, 12, 12, 15, 77, 107, 132),
|
||||
(21, 1, 3, 750, 4, 100, 0, 0, 5, 14, 9, 14, 16, 19, 80, 110, 135),
|
||||
(22, 1, 3, 775, 4, 110, 0, 0, 5, 14, 9, 14, 16, 19, 83, 113, 138),
|
||||
(23, 1, 3, 800, 4, 120, 0, 0, 5, 14, 9, 14, 16, 19, 86, 116, 141),
|
||||
(24, 1, 3, 825, 4, 130, 0, 0, 5, 14, 9, 14, 16, 19, 89, 119, 144),
|
||||
(25, 1, 3, 850, 4, 140, 0, 0, 5, 14, 9, 14, 16, 19, 92, 122, 147),
|
||||
(26, 1, 3, 875, 4, 150, 0, 0, 5, 14, 9, 14, 16, 19, 95, 125, 150),
|
||||
(27, 1, 3, 900, 4, 160, 0, 0, 5, 14, 9, 14, 16, 19, 98, 128, 153),
|
||||
(28, 1, 3, 925, 4, 170, 0, 0, 5, 14, 9, 14, 16, 19, 101, 131, 156),
|
||||
(29, 1, 3, 950, 4, 180, 0, 0, 5, 14, 9, 14, 16, 19, 104, 134, 159),
|
||||
(30, 1, 3, 1000, 4, 190, 20, 3, 5, 14, 9, 14, 16, 19, 107, 137, 162),
|
||||
(31, 1, 3, 1018, 4, 200, 20, 6, 7, 16, 11, 16, 20, 23, 110, 140, 165),
|
||||
(32, 1, 3, 1036, 4, 210, 20, 9, 7, 16, 11, 16, 20, 23, 113, 143, 168),
|
||||
(33, 1, 3, 1054, 4, 220, 20, 12, 7, 16, 11, 16, 20, 23, 116, 146, 171),
|
||||
(34, 1, 3, 1072, 4, 230, 20, 15, 7, 16, 11, 16, 20, 23, 119, 149, 174),
|
||||
(35, 1, 3, 1090, 4, 240, 20, 18, 7, 16, 11, 16, 20, 23, 122, 152, 177),
|
||||
(36, 1, 3, 1108, 4, 250, 20, 21, 7, 16, 11, 16, 20, 23, 125, 155, 180),
|
||||
(37, 1, 3, 1126, 4, 260, 20, 24, 7, 16, 11, 16, 20, 23, 128, 158, 183),
|
||||
(38, 1, 3, 1144, 4, 270, 20, 27, 7, 16, 11, 16, 20, 23, 131, 161, 186),
|
||||
(39, 1, 3, 1162, 4, 280, 20, 30, 7, 16, 11, 16, 20, 23, 134, 164, 189),
|
||||
(40, 1, 3, 1180, 4, 290, 20, 33, 7, 16, 11, 16, 20, 23, 137, 167, 192),
|
||||
(41, 1, 3, 1198, 4, 300, 20, 36, 9, 18, 13, 18, 24, 27, 140, 170, 195),
|
||||
(42, 1, 3, 1216, 4, 310, 20, 39, 9, 18, 13, 18, 24, 27, 143, 173, 198),
|
||||
(43, 1, 3, 1234, 4, 320, 20, 42, 9, 18, 13, 18, 24, 27, 146, 176, 201),
|
||||
(44, 1, 3, 1252, 4, 330, 20, 45, 9, 18, 13, 18, 24, 27, 149, 179, 204),
|
||||
(45, 1, 3, 1270, 4, 340, 20, 48, 9, 18, 13, 18, 24, 27, 152, 182, 207),
|
||||
(46, 1, 3, 1288, 4, 350, 20, 51, 9, 18, 13, 18, 24, 27, 155, 185, 210),
|
||||
(47, 1, 3, 1306, 4, 360, 20, 54, 9, 18, 13, 18, 24, 27, 158, 188, 213),
|
||||
(48, 1, 3, 1324, 4, 370, 20, 57, 9, 18, 13, 18, 24, 27, 161, 191, 216),
|
||||
(49, 1, 3, 1342, 4, 380, 20, 60, 9, 18, 13, 18, 24, 27, 164, 194, 219),
|
||||
(50, 1, 3, 1360, 4, 390, 20, 63, 9, 18, 13, 18, 24, 27, 167, 197, 222),
|
||||
(1, 2, 5, 100, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 20, 50, 75),
|
||||
(2, 2, 5, 150, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 23, 53, 78),
|
||||
(3, 2, 5, 200, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 26, 56, 81),
|
||||
(4, 2, 5, 250, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 29, 59, 84),
|
||||
(5, 2, 5, 300, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 32, 62, 87),
|
||||
(6, 2, 5, 350, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 35, 65, 90),
|
||||
(7, 2, 5, 400, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 38, 68, 93),
|
||||
(8, 2, 5, 450, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 41, 71, 96),
|
||||
(9, 2, 5, 500, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 44, 74, 99),
|
||||
(10, 2, 5, 550, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 47, 77, 102),
|
||||
(11, 2, 5, 500, 6, 0, 0, 0, 3, 12, 7, 12, 12, 15, 50, 80, 105),
|
||||
(12, 2, 5, 525, 6, 10, 0, 0, 3, 12, 7, 12, 12, 15, 53, 83, 108),
|
||||
(13, 2, 5, 550, 6, 20, 0, 0, 3, 12, 7, 12, 12, 15, 56, 86, 111),
|
||||
(14, 2, 5, 575, 6, 30, 0, 0, 3, 12, 7, 12, 12, 15, 59, 89, 114),
|
||||
(15, 2, 5, 600, 6, 40, 0, 0, 3, 12, 7, 12, 12, 15, 62, 92, 117),
|
||||
(16, 2, 5, 625, 6, 50, 0, 0, 3, 12, 7, 12, 12, 15, 65, 95, 120),
|
||||
(17, 2, 5, 650, 6, 60, 0, 0, 3, 12, 7, 12, 12, 15, 68, 98, 123),
|
||||
(18, 2, 5, 675, 6, 70, 0, 0, 3, 12, 7, 12, 12, 15, 71, 101, 126),
|
||||
(19, 2, 5, 700, 6, 80, 0, 0, 3, 12, 7, 12, 12, 15, 74, 104, 129),
|
||||
(20, 2, 5, 725, 6, 90, 0, 0, 3, 12, 7, 12, 12, 15, 77, 107, 132),
|
||||
(21, 2, 5, 750, 6, 100, 0, 0, 5, 14, 9, 14, 16, 19, 80, 110, 135),
|
||||
(22, 2, 5, 775, 6, 110, 0, 0, 5, 14, 9, 14, 16, 19, 83, 113, 138),
|
||||
(23, 2, 5, 800, 6, 120, 0, 0, 5, 14, 9, 14, 16, 19, 86, 116, 141),
|
||||
(24, 2, 5, 825, 6, 130, 0, 0, 5, 14, 9, 14, 16, 19, 89, 119, 144),
|
||||
(25, 2, 5, 850, 6, 140, 0, 0, 5, 14, 9, 14, 16, 19, 92, 122, 147),
|
||||
(26, 2, 5, 875, 6, 150, 0, 0, 5, 14, 9, 14, 16, 19, 95, 125, 150),
|
||||
(27, 2, 5, 900, 6, 160, 0, 0, 5, 14, 9, 14, 16, 19, 98, 128, 153),
|
||||
(28, 2, 5, 925, 6, 170, 0, 0, 5, 14, 9, 14, 16, 19, 101, 131, 156),
|
||||
(29, 2, 5, 950, 6, 180, 0, 0, 5, 14, 9, 14, 16, 19, 104, 134, 159),
|
||||
(30, 2, 5, 1000, 6, 190, 20, 3, 5, 14, 9, 14, 16, 19, 107, 137, 162),
|
||||
(31, 2, 5, 1018, 6, 200, 20, 6, 7, 16, 11, 16, 20, 23, 110, 140, 165),
|
||||
(32, 2, 5, 1036, 6, 210, 20, 9, 7, 16, 11, 16, 20, 23, 113, 143, 168),
|
||||
(33, 2, 5, 1054, 6, 220, 20, 12, 7, 16, 11, 16, 20, 23, 116, 146, 171),
|
||||
(34, 2, 5, 1072, 6, 230, 20, 15, 7, 16, 11, 16, 20, 23, 119, 149, 174),
|
||||
(35, 2, 5, 1090, 6, 240, 20, 18, 7, 16, 11, 16, 20, 23, 122, 152, 177),
|
||||
(36, 2, 5, 1108, 6, 250, 20, 21, 7, 16, 11, 16, 20, 23, 125, 155, 180),
|
||||
(37, 2, 5, 1126, 6, 260, 20, 24, 7, 16, 11, 16, 20, 23, 128, 158, 183),
|
||||
(38, 2, 5, 1144, 6, 270, 20, 27, 7, 16, 11, 16, 20, 23, 131, 161, 186),
|
||||
(39, 2, 5, 1162, 6, 280, 20, 30, 7, 16, 11, 16, 20, 23, 134, 164, 189),
|
||||
(40, 2, 5, 1180, 6, 290, 20, 33, 7, 16, 11, 16, 20, 23, 137, 167, 192),
|
||||
(41, 2, 5, 1198, 6, 300, 20, 36, 9, 18, 13, 18, 24, 27, 140, 170, 195),
|
||||
(42, 2, 5, 1216, 6, 310, 20, 39, 9, 18, 13, 18, 24, 27, 143, 173, 198),
|
||||
(43, 2, 5, 1234, 6, 320, 20, 42, 9, 18, 13, 18, 24, 27, 146, 176, 201),
|
||||
(44, 2, 5, 1252, 6, 330, 20, 45, 9, 18, 13, 18, 24, 27, 149, 179, 204),
|
||||
(45, 2, 5, 1270, 6, 340, 20, 48, 9, 18, 13, 18, 24, 27, 152, 182, 207),
|
||||
(46, 2, 5, 1288, 6, 350, 20, 51, 9, 18, 13, 18, 24, 27, 155, 185, 210),
|
||||
(47, 2, 5, 1306, 6, 360, 20, 54, 9, 18, 13, 18, 24, 27, 158, 188, 213),
|
||||
(48, 2, 5, 1324, 6, 370, 20, 57, 9, 18, 13, 18, 24, 27, 161, 191, 216),
|
||||
(49, 2, 5, 1342, 6, 380, 20, 60, 9, 18, 13, 18, 24, 27, 164, 194, 219),
|
||||
(50, 2, 5, 1360, 6, 390, 20, 63, 9, 18, 13, 18, 24, 27, 167, 197, 222)
|
||||
;
|
||||
0
data/sql/db-world/updates/.gitkeep
Normal file
0
data/sql/db-world/updates/.gitkeep
Normal file
253
scripts/advancement_stats_ranks/generate_stat_upgrades.sql
Normal file
253
scripts/advancement_stats_ranks/generate_stat_upgrades.sql
Normal file
@@ -0,0 +1,253 @@
|
||||
-- SQL Script to Insert 50 Ranks for Each Stat
|
||||
INSERT INTO mp_stat_upgrade_ranks (upgradeRank, statTypeId, materialId1, materialCost, materialId2, materialCost2, materialId3, materialCost3, minIncrease1, maxIncrease1, minIncrease2, maxIncrease2, minIncrease3, maxIncrease3, chanceCost1, chanceCost2, chanceCost3) VALUES
|
||||
(1, 1, 1001, 100, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 20, 50, 75),
|
||||
(2, 1, 1001, 150, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 23, 53, 78),
|
||||
(3, 1, 1001, 200, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 26, 56, 81),
|
||||
(4, 1, 1001, 250, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 29, 59, 84),
|
||||
(5, 1, 1001, 300, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 32, 62, 87),
|
||||
(6, 1, 1001, 350, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 35, 65, 90),
|
||||
(7, 1, 1001, 400, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 38, 68, 93),
|
||||
(8, 1, 1001, 450, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 41, 71, 96),
|
||||
(9, 1, 1001, 500, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 44, 74, 99),
|
||||
(10, 1, 1001, 550, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 47, 77, 102),
|
||||
(11, 1, 1001, 600, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 50, 80, 105),
|
||||
(12, 1, 1001, 650, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 53, 83, 108),
|
||||
(13, 1, 1001, 700, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 56, 86, 111),
|
||||
(14, 1, 1001, 750, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 59, 89, 114),
|
||||
(15, 1, 1001, 800, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 62, 92, 117),
|
||||
(16, 1, 1001, 850, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 65, 95, 120),
|
||||
(17, 1, 1001, 900, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 68, 98, 123),
|
||||
(18, 1, 1001, 950, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 71, 101, 126),
|
||||
(19, 1, 1001, 1000, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 74, 104, 129),
|
||||
(20, 1, 1001, 1050, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 77, 107, 132),
|
||||
(21, 1, 1001, 1100, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 80, 110, 135),
|
||||
(22, 1, 1001, 1150, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 83, 113, 138),
|
||||
(23, 1, 1001, 1200, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 86, 116, 141),
|
||||
(24, 1, 1001, 1250, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 89, 119, 144),
|
||||
(25, 1, 1001, 1300, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 92, 122, 147),
|
||||
(26, 1, 1001, 1350, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 95, 125, 150),
|
||||
(27, 1, 1001, 1400, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 98, 128, 153),
|
||||
(28, 1, 1001, 1450, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 101, 131, 156),
|
||||
(29, 1, 1001, 1500, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 104, 134, 159),
|
||||
(30, 1, 1001, 1550, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 107, 137, 162),
|
||||
(31, 1, 1001, 1600, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 110, 140, 165),
|
||||
(32, 1, 1001, 1650, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 113, 143, 168),
|
||||
(33, 1, 1001, 1700, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 116, 146, 171),
|
||||
(34, 1, 1001, 1750, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 119, 149, 174),
|
||||
(35, 1, 1001, 1800, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 122, 152, 177),
|
||||
(36, 1, 1001, 1850, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 125, 155, 180),
|
||||
(37, 1, 1001, 1900, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 128, 158, 183),
|
||||
(38, 1, 1001, 1950, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 131, 161, 186),
|
||||
(39, 1, 1001, 2000, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 134, 164, 189),
|
||||
(40, 1, 1001, 2050, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 137, 167, 192),
|
||||
(41, 1, 1001, 2100, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 140, 170, 195),
|
||||
(42, 1, 1001, 2150, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 143, 173, 198),
|
||||
(43, 1, 1001, 2200, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 146, 176, 201),
|
||||
(44, 1, 1001, 2250, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 149, 179, 204),
|
||||
(45, 1, 1001, 2300, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 152, 182, 207),
|
||||
(46, 1, 1001, 2350, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 155, 185, 210),
|
||||
(47, 1, 1001, 2400, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 158, 188, 213),
|
||||
(48, 1, 1001, 2450, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 161, 191, 216),
|
||||
(49, 1, 1001, 2500, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 164, 194, 219),
|
||||
(50, 1, 1001, 2550, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 167, 197, 222),
|
||||
(1, 2, 1001, 100, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 20, 50, 75),
|
||||
(2, 2, 1001, 150, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 23, 53, 78),
|
||||
(3, 2, 1001, 200, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 26, 56, 81),
|
||||
(4, 2, 1001, 250, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 29, 59, 84),
|
||||
(5, 2, 1001, 300, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 32, 62, 87),
|
||||
(6, 2, 1001, 350, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 35, 65, 90),
|
||||
(7, 2, 1001, 400, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 38, 68, 93),
|
||||
(8, 2, 1001, 450, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 41, 71, 96),
|
||||
(9, 2, 1001, 500, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 44, 74, 99),
|
||||
(10, 2, 1001, 550, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 47, 77, 102),
|
||||
(11, 2, 1001, 600, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 50, 80, 105),
|
||||
(12, 2, 1001, 650, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 53, 83, 108),
|
||||
(13, 2, 1001, 700, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 56, 86, 111),
|
||||
(14, 2, 1001, 750, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 59, 89, 114),
|
||||
(15, 2, 1001, 800, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 62, 92, 117),
|
||||
(16, 2, 1001, 850, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 65, 95, 120),
|
||||
(17, 2, 1001, 900, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 68, 98, 123),
|
||||
(18, 2, 1001, 950, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 71, 101, 126),
|
||||
(19, 2, 1001, 1000, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 74, 104, 129),
|
||||
(20, 2, 1001, 1050, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 77, 107, 132),
|
||||
(21, 2, 1001, 1100, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 80, 110, 135),
|
||||
(22, 2, 1001, 1150, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 83, 113, 138),
|
||||
(23, 2, 1001, 1200, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 86, 116, 141),
|
||||
(24, 2, 1001, 1250, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 89, 119, 144),
|
||||
(25, 2, 1001, 1300, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 92, 122, 147),
|
||||
(26, 2, 1001, 1350, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 95, 125, 150),
|
||||
(27, 2, 1001, 1400, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 98, 128, 153),
|
||||
(28, 2, 1001, 1450, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 101, 131, 156),
|
||||
(29, 2, 1001, 1500, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 104, 134, 159),
|
||||
(30, 2, 1001, 1550, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 107, 137, 162),
|
||||
(31, 2, 1001, 1600, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 110, 140, 165),
|
||||
(32, 2, 1001, 1650, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 113, 143, 168),
|
||||
(33, 2, 1001, 1700, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 116, 146, 171),
|
||||
(34, 2, 1001, 1750, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 119, 149, 174),
|
||||
(35, 2, 1001, 1800, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 122, 152, 177),
|
||||
(36, 2, 1001, 1850, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 125, 155, 180),
|
||||
(37, 2, 1001, 1900, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 128, 158, 183),
|
||||
(38, 2, 1001, 1950, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 131, 161, 186),
|
||||
(39, 2, 1001, 2000, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 134, 164, 189),
|
||||
(40, 2, 1001, 2050, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 137, 167, 192),
|
||||
(41, 2, 1001, 2100, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 140, 170, 195),
|
||||
(42, 2, 1001, 2150, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 143, 173, 198),
|
||||
(43, 2, 1001, 2200, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 146, 176, 201),
|
||||
(44, 2, 1001, 2250, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 149, 179, 204),
|
||||
(45, 2, 1001, 2300, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 152, 182, 207),
|
||||
(46, 2, 1001, 2350, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 155, 185, 210),
|
||||
(47, 2, 1001, 2400, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 158, 188, 213),
|
||||
(48, 2, 1001, 2450, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 161, 191, 216),
|
||||
(49, 2, 1001, 2500, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 164, 194, 219),
|
||||
(50, 2, 1001, 2550, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 167, 197, 222),
|
||||
(1, 3, 1001, 100, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 20, 50, 75),
|
||||
(2, 3, 1001, 150, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 23, 53, 78),
|
||||
(3, 3, 1001, 200, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 26, 56, 81),
|
||||
(4, 3, 1001, 250, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 29, 59, 84),
|
||||
(5, 3, 1001, 300, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 32, 62, 87),
|
||||
(6, 3, 1001, 350, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 35, 65, 90),
|
||||
(7, 3, 1001, 400, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 38, 68, 93),
|
||||
(8, 3, 1001, 450, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 41, 71, 96),
|
||||
(9, 3, 1001, 500, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 44, 74, 99),
|
||||
(10, 3, 1001, 550, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 47, 77, 102),
|
||||
(11, 3, 1001, 600, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 50, 80, 105),
|
||||
(12, 3, 1001, 650, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 53, 83, 108),
|
||||
(13, 3, 1001, 700, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 56, 86, 111),
|
||||
(14, 3, 1001, 750, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 59, 89, 114),
|
||||
(15, 3, 1001, 800, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 62, 92, 117),
|
||||
(16, 3, 1001, 850, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 65, 95, 120),
|
||||
(17, 3, 1001, 900, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 68, 98, 123),
|
||||
(18, 3, 1001, 950, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 71, 101, 126),
|
||||
(19, 3, 1001, 1000, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 74, 104, 129),
|
||||
(20, 3, 1001, 1050, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 77, 107, 132),
|
||||
(21, 3, 1001, 1100, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 80, 110, 135),
|
||||
(22, 3, 1001, 1150, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 83, 113, 138),
|
||||
(23, 3, 1001, 1200, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 86, 116, 141),
|
||||
(24, 3, 1001, 1250, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 89, 119, 144),
|
||||
(25, 3, 1001, 1300, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 92, 122, 147),
|
||||
(26, 3, 1001, 1350, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 95, 125, 150),
|
||||
(27, 3, 1001, 1400, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 98, 128, 153),
|
||||
(28, 3, 1001, 1450, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 101, 131, 156),
|
||||
(29, 3, 1001, 1500, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 104, 134, 159),
|
||||
(30, 3, 1001, 1550, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 107, 137, 162),
|
||||
(31, 3, 1001, 1600, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 110, 140, 165),
|
||||
(32, 3, 1001, 1650, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 113, 143, 168),
|
||||
(33, 3, 1001, 1700, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 116, 146, 171),
|
||||
(34, 3, 1001, 1750, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 119, 149, 174),
|
||||
(35, 3, 1001, 1800, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 122, 152, 177),
|
||||
(36, 3, 1001, 1850, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 125, 155, 180),
|
||||
(37, 3, 1001, 1900, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 128, 158, 183),
|
||||
(38, 3, 1001, 1950, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 131, 161, 186),
|
||||
(39, 3, 1001, 2000, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 134, 164, 189),
|
||||
(40, 3, 1001, 2050, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 137, 167, 192),
|
||||
(41, 3, 1001, 2100, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 140, 170, 195),
|
||||
(42, 3, 1001, 2150, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 143, 173, 198),
|
||||
(43, 3, 1001, 2200, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 146, 176, 201),
|
||||
(44, 3, 1001, 2250, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 149, 179, 204),
|
||||
(45, 3, 1001, 2300, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 152, 182, 207),
|
||||
(46, 3, 1001, 2350, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 155, 185, 210),
|
||||
(47, 3, 1001, 2400, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 158, 188, 213),
|
||||
(48, 3, 1001, 2450, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 161, 191, 216),
|
||||
(49, 3, 1001, 2500, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 164, 194, 219),
|
||||
(50, 3, 1001, 2550, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 167, 197, 222),
|
||||
(1, 4, 1001, 100, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 20, 50, 75),
|
||||
(2, 4, 1001, 150, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 23, 53, 78),
|
||||
(3, 4, 1001, 200, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 26, 56, 81),
|
||||
(4, 4, 1001, 250, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 29, 59, 84),
|
||||
(5, 4, 1001, 300, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 32, 62, 87),
|
||||
(6, 4, 1001, 350, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 35, 65, 90),
|
||||
(7, 4, 1001, 400, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 38, 68, 93),
|
||||
(8, 4, 1001, 450, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 41, 71, 96),
|
||||
(9, 4, 1001, 500, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 44, 74, 99),
|
||||
(10, 4, 1001, 550, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 47, 77, 102),
|
||||
(11, 4, 1001, 600, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 50, 80, 105),
|
||||
(12, 4, 1001, 650, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 53, 83, 108),
|
||||
(13, 4, 1001, 700, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 56, 86, 111),
|
||||
(14, 4, 1001, 750, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 59, 89, 114),
|
||||
(15, 4, 1001, 800, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 62, 92, 117),
|
||||
(16, 4, 1001, 850, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 65, 95, 120),
|
||||
(17, 4, 1001, 900, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 68, 98, 123),
|
||||
(18, 4, 1001, 950, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 71, 101, 126),
|
||||
(19, 4, 1001, 1000, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 74, 104, 129),
|
||||
(20, 4, 1001, 1050, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 77, 107, 132),
|
||||
(21, 4, 1001, 1100, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 80, 110, 135),
|
||||
(22, 4, 1001, 1150, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 83, 113, 138),
|
||||
(23, 4, 1001, 1200, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 86, 116, 141),
|
||||
(24, 4, 1001, 1250, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 89, 119, 144),
|
||||
(25, 4, 1001, 1300, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 92, 122, 147),
|
||||
(26, 4, 1001, 1350, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 95, 125, 150),
|
||||
(27, 4, 1001, 1400, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 98, 128, 153),
|
||||
(28, 4, 1001, 1450, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 101, 131, 156),
|
||||
(29, 4, 1001, 1500, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 104, 134, 159),
|
||||
(30, 4, 1001, 1550, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 107, 137, 162),
|
||||
(31, 4, 1001, 1600, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 110, 140, 165),
|
||||
(32, 4, 1001, 1650, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 113, 143, 168),
|
||||
(33, 4, 1001, 1700, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 116, 146, 171),
|
||||
(34, 4, 1001, 1750, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 119, 149, 174),
|
||||
(35, 4, 1001, 1800, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 122, 152, 177),
|
||||
(36, 4, 1001, 1850, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 125, 155, 180),
|
||||
(37, 4, 1001, 1900, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 128, 158, 183),
|
||||
(38, 4, 1001, 1950, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 131, 161, 186),
|
||||
(39, 4, 1001, 2000, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 134, 164, 189),
|
||||
(40, 4, 1001, 2050, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 137, 167, 192),
|
||||
(41, 4, 1001, 2100, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 140, 170, 195),
|
||||
(42, 4, 1001, 2150, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 143, 173, 198),
|
||||
(43, 4, 1001, 2200, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 146, 176, 201),
|
||||
(44, 4, 1001, 2250, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 149, 179, 204),
|
||||
(45, 4, 1001, 2300, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 152, 182, 207),
|
||||
(46, 4, 1001, 2350, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 155, 185, 210),
|
||||
(47, 4, 1001, 2400, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 158, 188, 213),
|
||||
(48, 4, 1001, 2450, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 161, 191, 216),
|
||||
(49, 4, 1001, 2500, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 164, 194, 219),
|
||||
(50, 4, 1001, 2550, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 167, 197, 222)
|
||||
(1, 0, 1001, 100, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 20, 50, 75),
|
||||
(2, 0, 1001, 150, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 23, 53, 78),
|
||||
(3, 0, 1001, 200, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 26, 56, 81),
|
||||
(4, 0, 1001, 250, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 29, 59, 84),
|
||||
(5, 0, 1001, 300, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 32, 62, 87),
|
||||
(6, 0, 1001, 350, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 35, 65, 90),
|
||||
(7, 0, 1001, 400, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 38, 68, 93),
|
||||
(8, 0, 1001, 450, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 41, 71, 96),
|
||||
(9, 0, 1001, 500, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 44, 74, 99),
|
||||
(10, 0, 1001, 550, 0, 0, 0, 0, 1, 10, 5, 10, 8, 11, 47, 77, 102),
|
||||
(11, 0, 1001, 600, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 50, 80, 105),
|
||||
(12, 0, 1001, 650, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 53, 83, 108),
|
||||
(13, 0, 1001, 700, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 56, 86, 111),
|
||||
(14, 0, 1001, 750, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 59, 89, 114),
|
||||
(15, 0, 1001, 800, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 62, 92, 117),
|
||||
(16, 0, 1001, 850, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 65, 95, 120),
|
||||
(17, 0, 1001, 900, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 68, 98, 123),
|
||||
(18, 0, 1001, 950, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 71, 101, 126),
|
||||
(19, 0, 1001, 1000, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 74, 104, 129),
|
||||
(20, 0, 1001, 1050, 0, 0, 0, 0, 3, 12, 7, 12, 12, 15, 77, 107, 132),
|
||||
(21, 0, 1001, 1100, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 80, 110, 135),
|
||||
(22, 0, 1001, 1150, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 83, 113, 138),
|
||||
(23, 0, 1001, 1200, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 86, 116, 141),
|
||||
(24, 0, 1001, 1250, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 89, 119, 144),
|
||||
(25, 0, 1001, 1300, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 92, 122, 147),
|
||||
(26, 0, 1001, 1350, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 95, 125, 150),
|
||||
(27, 0, 1001, 1400, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 98, 128, 153),
|
||||
(28, 0, 1001, 1450, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 101, 131, 156),
|
||||
(29, 0, 1001, 1500, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 104, 134, 159),
|
||||
(30, 0, 1001, 1550, 0, 0, 0, 0, 5, 14, 9, 14, 16, 19, 107, 137, 162),
|
||||
(31, 0, 1001, 1600, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 110, 140, 165),
|
||||
(32, 0, 1001, 1650, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 113, 143, 168),
|
||||
(33, 0, 1001, 1700, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 116, 146, 171),
|
||||
(34, 0, 1001, 1750, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 119, 149, 174),
|
||||
(35, 0, 1001, 1800, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 122, 152, 177),
|
||||
(36, 0, 1001, 1850, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 125, 155, 180),
|
||||
(37, 0, 1001, 1900, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 128, 158, 183),
|
||||
(38, 0, 1001, 1950, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 131, 161, 186),
|
||||
(39, 0, 1001, 2000, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 134, 164, 189),
|
||||
(40, 0, 1001, 2050, 0, 0, 0, 0, 7, 16, 11, 16, 20, 23, 137, 167, 192),
|
||||
(41, 0, 1001, 2100, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 140, 170, 195),
|
||||
(42, 0, 1001, 2150, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 143, 173, 198),
|
||||
(43, 0, 1001, 2200, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 146, 176, 201),
|
||||
(44, 0, 1001, 2250, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 149, 179, 204),
|
||||
(45, 0, 1001, 2300, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 152, 182, 207),
|
||||
(46, 0, 1001, 2350, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 155, 185, 210),
|
||||
(47, 0, 1001, 2400, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 158, 188, 213),
|
||||
(48, 0, 1001, 2450, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 161, 191, 216),
|
||||
(49, 0, 1001, 2500, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 164, 194, 219),
|
||||
(50, 0, 1001, 2550, 0, 0, 0, 0, 9, 18, 13, 18, 24, 27, 167, 197, 222),
|
||||
;
|
||||
77
scripts/advancement_stats_ranks/main.go
Normal file
77
scripts/advancement_stats_ranks/main.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Stats enum
|
||||
const (
|
||||
STAT_STRENGTH = iota
|
||||
STAT_AGILITY
|
||||
STAT_STAMINA
|
||||
STAT_INTELLECT
|
||||
STAT_SPIRIT
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Output file for the SQL script
|
||||
outputFile, err := os.Create("generate_stat_upgrades.sql")
|
||||
if err != nil {
|
||||
fmt.Println("Error creating file:", err)
|
||||
return
|
||||
}
|
||||
defer outputFile.Close()
|
||||
|
||||
// Stats names for clarity
|
||||
stats := map[int]string{
|
||||
STAT_STRENGTH: "STAT_STRENGTH",
|
||||
STAT_AGILITY: "STAT_AGILITY",
|
||||
STAT_STAMINA: "STAT_STAMINA",
|
||||
STAT_INTELLECT: "STAT_INTELLECT",
|
||||
STAT_SPIRIT: "STAT_SPIRIT",
|
||||
}
|
||||
|
||||
// Start writing the SQL script
|
||||
fmt.Fprintln(outputFile, "-- SQL Script to Insert 50 Ranks for Each Stat")
|
||||
fmt.Fprintln(outputFile, "INSERT INTO mp_stat_upgrade_ranks (upgradeRank, statTypeId, materialId1, materialCost, materialId2, materialCost2, materialId3, materialCost3, minIncrease1, maxIncrease1, minIncrease2, maxIncrease2, minIncrease3, maxIncrease3, chanceCost1, chanceCost2, chanceCost3) VALUES")
|
||||
|
||||
// Iterate over stats
|
||||
for statID := range stats {
|
||||
for rank := 1; rank <= 50; rank++ {
|
||||
// Material cost increases by 50 per rank
|
||||
materialCost := 100 + (rank-1)*50
|
||||
|
||||
// Stat growth
|
||||
minIncrease1 := 1 + (rank-1)/10*2
|
||||
maxIncrease1 := 10 + (rank-1)/10*2
|
||||
|
||||
minIncrease2 := (minIncrease1 + maxIncrease1) / 2
|
||||
maxIncrease3Bonus := (rank-1)/10*2 + 1
|
||||
maxIncrease3 := maxIncrease1 + maxIncrease3Bonus
|
||||
minIncrease3 := maxIncrease3 - 3
|
||||
|
||||
// Dice costs
|
||||
chanceCost1 := 20 + (rank-1)*3
|
||||
chanceCost2 := 50 + (rank-1)*3
|
||||
chanceCost3 := 75 + (rank-1)*3
|
||||
|
||||
// Write SQL insert statement for this rank
|
||||
sql := fmt.Sprintf(
|
||||
"(%d, %d, 1001, %d, 0, 0, 0, 0, %d, %d, %d, %d, %d, %d, %d, %d, %d)",
|
||||
rank, statID, materialCost,
|
||||
minIncrease1, maxIncrease1, minIncrease2, maxIncrease1, minIncrease3, maxIncrease3,
|
||||
chanceCost1, chanceCost2, chanceCost3,
|
||||
)
|
||||
|
||||
// Add a comma for all but the last line
|
||||
if !(statID == STAT_SPIRIT && rank == 50) {
|
||||
sql += ","
|
||||
}
|
||||
fmt.Fprintln(outputFile, sql)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintln(outputFile, ";")
|
||||
fmt.Println("SQL script generated: generate_stat_upgrades.sql")
|
||||
}
|
||||
39202
scripts/pet_80_plus_stats/creatures.json
Normal file
39202
scripts/pet_80_plus_stats/creatures.json
Normal file
File diff suppressed because it is too large
Load Diff
153
scripts/pet_80_plus_stats/main.go
Normal file
153
scripts/pet_80_plus_stats/main.go
Normal file
@@ -0,0 +1,153 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Creature struct {
|
||||
CreatureEntry int `json:"creature_entry"`
|
||||
Level int `json:"level"`
|
||||
HP int `json:"hp"`
|
||||
Mana int `json:"mana"`
|
||||
Armor int `json:"armor"`
|
||||
Str int `json:"str"`
|
||||
Agi int `json:"agi"`
|
||||
Sta int `json:"sta"`
|
||||
Int int `json:"inte"`
|
||||
Spi int `json:"spi"`
|
||||
MinDmg int `json:"min_dmg"`
|
||||
MaxDmg int `json:"max_dmg"`
|
||||
}
|
||||
|
||||
// RegressionResult stores the slope and intercept of a linear regression
|
||||
type RegressionResult struct {
|
||||
Slope float64
|
||||
Intercept float64
|
||||
}
|
||||
|
||||
// LinearRegression performs a simple linear regression on the given data points
|
||||
func LinearRegression(levels []float64, stats []float64) RegressionResult {
|
||||
n := len(levels)
|
||||
if n != len(stats) {
|
||||
panic("levels and stats arrays must have the same length")
|
||||
}
|
||||
|
||||
// Calculate averages
|
||||
var sumX, sumY, sumXY, sumXX float64
|
||||
for i := 0; i < n; i++ {
|
||||
sumX += levels[i]
|
||||
sumY += stats[i]
|
||||
sumXY += levels[i] * stats[i]
|
||||
sumXX += levels[i] * levels[i]
|
||||
}
|
||||
|
||||
avgX := sumX / float64(n)
|
||||
avgY := sumY / float64(n)
|
||||
|
||||
// Calculate slope and intercept
|
||||
slope := (sumXY - float64(n)*avgX*avgY) / (sumXX - float64(n)*avgX*avgX)
|
||||
intercept := avgY - slope*avgX
|
||||
|
||||
return RegressionResult{
|
||||
Slope: slope,
|
||||
Intercept: intercept,
|
||||
}
|
||||
}
|
||||
|
||||
// PredictStat returns the predicted stat value for a given level based on a linear regression model
|
||||
func PredictStat(reg RegressionResult, level int) float64 {
|
||||
return reg.Intercept + reg.Slope*float64(level)
|
||||
}
|
||||
|
||||
// ScaleCreatures generates stats for levels 81 to 87 based on linear regression and outputs SQL statements
|
||||
func ScaleCreatures(creatures []Creature) {
|
||||
creatureMap := make(map[int][]Creature)
|
||||
|
||||
// Group creatures by their creature_entry
|
||||
for _, creature := range creatures {
|
||||
creatureMap[creature.CreatureEntry] = append(creatureMap[creature.CreatureEntry], creature)
|
||||
}
|
||||
|
||||
// Process each creature entry independently
|
||||
for creatureEntry, creatureList := range creatureMap {
|
||||
var levels []float64
|
||||
var hp, mana, armor, str, agi, sta, inte, spi, minDmg, maxDmg []float64
|
||||
|
||||
// Collect data for linear regression from levels 1 to 80
|
||||
for _, creature := range creatureList {
|
||||
if creature.Level <= 80 {
|
||||
levels = append(levels, float64(creature.Level))
|
||||
hp = append(hp, float64(creature.HP))
|
||||
mana = append(mana, float64(creature.Mana))
|
||||
armor = append(armor, float64(creature.Armor))
|
||||
str = append(str, float64(creature.Str))
|
||||
agi = append(agi, float64(creature.Agi))
|
||||
sta = append(sta, float64(creature.Sta))
|
||||
inte = append(inte, float64(creature.Int))
|
||||
spi = append(spi, float64(creature.Spi))
|
||||
minDmg = append(minDmg, float64(creature.MinDmg))
|
||||
maxDmg = append(maxDmg, float64(creature.MaxDmg))
|
||||
}
|
||||
}
|
||||
|
||||
// Perform linear regression on each stat
|
||||
hpReg := LinearRegression(levels, hp)
|
||||
manaReg := LinearRegression(levels, mana)
|
||||
armorReg := LinearRegression(levels, armor)
|
||||
strReg := LinearRegression(levels, str)
|
||||
agiReg := LinearRegression(levels, agi)
|
||||
staReg := LinearRegression(levels, sta)
|
||||
inteReg := LinearRegression(levels, inte)
|
||||
spiReg := LinearRegression(levels, spi)
|
||||
minDmgReg := LinearRegression(levels, minDmg)
|
||||
maxDmgReg := LinearRegression(levels, maxDmg)
|
||||
|
||||
// Generate SQL insert statements for levels 81 to 87 for each creature_entry
|
||||
for level := 81; level <= 87; level++ {
|
||||
newCreature := Creature{
|
||||
CreatureEntry: creatureEntry, // Process per creature_entry
|
||||
Level: level,
|
||||
HP: int(math.Round(math.Max(PredictStat(hpReg, level), 1))), // Round and ensure positive
|
||||
Mana: int(math.Round(math.Max(PredictStat(manaReg, level), 1))),
|
||||
Armor: int(math.Round(math.Max(PredictStat(armorReg, level), 1))), // Armor scaling
|
||||
Str: int(math.Round(math.Max(PredictStat(strReg, level), 1))),
|
||||
Agi: int(math.Round(math.Max(PredictStat(agiReg, level), 1))),
|
||||
Sta: int(math.Round(math.Max(PredictStat(staReg, level), 1))),
|
||||
Int: int(math.Round(math.Max(PredictStat(inteReg, level), 1))),
|
||||
Spi: int(math.Round(math.Max(PredictStat(spiReg, level), 1))),
|
||||
MinDmg: int(math.Round(math.Max(PredictStat(minDmgReg, level), 1))),
|
||||
MaxDmg: int(math.Round(math.Max(PredictStat(maxDmgReg, level), 1))),
|
||||
}
|
||||
|
||||
// Output SQL INSERT statement for each creature_entry and level
|
||||
fmt.Printf("INSERT INTO pet_levelstats (creature_entry, level, hp, mana, armor, str, agi, sta, inte, spi, min_dmg, max_dmg) "+
|
||||
"VALUES (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d);\n",
|
||||
newCreature.CreatureEntry, newCreature.Level, newCreature.HP, newCreature.Mana, newCreature.Armor,
|
||||
newCreature.Str, newCreature.Agi, newCreature.Sta, newCreature.Int, newCreature.Spi,
|
||||
newCreature.MinDmg, newCreature.MaxDmg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Read the JSON file
|
||||
file, err := os.Open("creatures.json")
|
||||
if err != nil {
|
||||
fmt.Println("Error reading file:", err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
byteValue, _ := ioutil.ReadAll(file)
|
||||
|
||||
// Parse the JSON data
|
||||
var creatures []Creature
|
||||
json.Unmarshal(byteValue, &creatures)
|
||||
|
||||
// Scale creatures and generate SQL for levels 81 to 87
|
||||
ScaleCreatures(creatures)
|
||||
}
|
||||
110
scripts/upgrade_ranks/main.go
Normal file
110
scripts/upgrade_ranks/main.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Stats enum
|
||||
const (
|
||||
STAT_INTELLECT = iota
|
||||
STAT_SPIRIT
|
||||
STAT_STRENGTH
|
||||
STAT_AGILITY
|
||||
STAT_STAMINA
|
||||
)
|
||||
|
||||
const (
|
||||
RESIST_FROST = iota
|
||||
RESIST_FIRE
|
||||
RESIST_NATURE
|
||||
RESIST_SHADOW
|
||||
RESIST_ARCANE
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Output file for the SQL script
|
||||
outputFile, err := os.Create("generate_stat_upgrades.sql")
|
||||
if err != nil {
|
||||
fmt.Println("Error creating file:", err)
|
||||
return
|
||||
}
|
||||
defer outputFile.Close()
|
||||
|
||||
// Stats names for clarity
|
||||
stats := map[int]string{
|
||||
STAT_INTELLECT: "Intellect",
|
||||
STAT_SPIRIT: "Spirit",
|
||||
STAT_STRENGTH: "Strength",
|
||||
STAT_AGILITY: "Agility",
|
||||
STAT_STAMINA: "Stamina",
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
// Iterate over stats
|
||||
for statID := range stats {
|
||||
for rank := 1; rank <= 50; rank++ {
|
||||
// Material cost increases by 50 per rank
|
||||
materialCost := 50
|
||||
if rank < 11 {
|
||||
materialCost = 100 + (rank-1)*50
|
||||
}
|
||||
if rank >= 11 && rank < 30 {
|
||||
materialCost = 500 + (rank-11)*25
|
||||
}
|
||||
if rank >= 30 {
|
||||
materialCost = 1000 + (rank-30)*18
|
||||
}
|
||||
|
||||
// Stat growth
|
||||
minIncrease1 := 1 + (rank-1)/10*2
|
||||
maxIncrease1 := 10 + (rank-1)/10*2
|
||||
|
||||
minIncrease2 := (minIncrease1 + maxIncrease1) / 2
|
||||
maxIncrease3Bonus := (rank-1)/10*2 + 1
|
||||
maxIncrease3 := maxIncrease1 + maxIncrease3Bonus
|
||||
minIncrease3 := maxIncrease3 - 3
|
||||
|
||||
// Dice costs
|
||||
chanceCost1 := 20 + (rank-1)*3
|
||||
chanceCost2 := 50 + (rank-1)*3
|
||||
chanceCost3 := 75 + (rank-1)*3
|
||||
|
||||
// use material ids from the mp_material_types table material1 should be common stuff.
|
||||
materialId1 := statID*2 + 1
|
||||
|
||||
// material2 should be rare stuff only required after rank 10 at growth rate of 5 per rank
|
||||
materialId2, materialCost2 := 0, 0
|
||||
if rank > 10 {
|
||||
materialId2 = statID*2 + 2
|
||||
materialCost2 = (rank - 11) * 10
|
||||
}
|
||||
|
||||
materialId3, materialCost3 := 0, 0
|
||||
if rank >= 30 {
|
||||
materialId3 = 20 // Group lot of raid only items
|
||||
materialCost3 = (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, statID, materialId1, materialCost, materialId2, materialCost2, materialId3, materialCost3,
|
||||
minIncrease1, maxIncrease1, minIncrease2, maxIncrease1, minIncrease3, maxIncrease3,
|
||||
chanceCost1, chanceCost2, chanceCost3,
|
||||
)
|
||||
|
||||
// Add a comma for all but the last line
|
||||
if !(statID == STAT_SPIRIT && rank == 50) {
|
||||
sql += ","
|
||||
}
|
||||
fmt.Fprintln(outputFile, sql)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintln(outputFile, ";")
|
||||
fmt.Println("SQL script generated: generate_stat_upgrades.sql")
|
||||
}
|
||||
415
src/AdvancementMgr.cpp
Normal file
415
src/AdvancementMgr.cpp
Normal file
@@ -0,0 +1,415 @@
|
||||
#include "AdvancementMgr.h"
|
||||
#include "CharacterDatabase.h"
|
||||
#include "WorldDatabase.h"
|
||||
#include "Player.h"
|
||||
#include "MpLogger.h"
|
||||
#include "MythicPlus.h"
|
||||
#include "MpConstants.h"
|
||||
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <mutex>
|
||||
|
||||
/**
|
||||
* Table schema for upgrade ranks populated by go script:
|
||||
*
|
||||
* 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,
|
||||
* minIncrease1 INT UNSIGNED NOT NULL,
|
||||
* maxIncrease1 INT UNSIGNED NOT NULL,
|
||||
* minIncrease2 INT UNSIGNED NOT NULL,
|
||||
* maxIncrease2 INT UNSIGNED NOT NULL,
|
||||
* minIncrease3 INT UNSIGNED NOT NULL,
|
||||
* maxIncrease3 INT UNSIGNED NOT NULL,
|
||||
* chanceCost1 INT UNSIGNED NOT NULL,
|
||||
* chanceCost2 INT UNSIGNED NOT NULL,
|
||||
* chanceCost3 INT UNSIGNED NOT NULL,
|
||||
*
|
||||
* PRIMARY KEY (upgradeRank, statTypeId)
|
||||
*
|
||||
* This loads the ranks from the database and stores them into memory for access. This should only be
|
||||
* called on server start-up as it is static data that should only change no new builds.
|
||||
*/
|
||||
int32 AdvancementMgr::LoadAdvancementRanks() {
|
||||
_advancementRanks.clear();
|
||||
|
||||
//
|
||||
// const char*
|
||||
constexpr std::string_view query = R"(
|
||||
SELECT
|
||||
upgradeRank,
|
||||
advancementId,
|
||||
materialId1,
|
||||
materialId2,
|
||||
materialId3,
|
||||
materialCost1,
|
||||
materialCost2,
|
||||
materialCost3,
|
||||
minIncrease1,
|
||||
maxIncrease1,
|
||||
minIncrease2,
|
||||
maxIncrease2,
|
||||
minIncrease3,
|
||||
maxIncrease3,
|
||||
chanceCost1,
|
||||
chanceCost2,
|
||||
chanceCost3
|
||||
FROM mp_upgrade_ranks
|
||||
)";
|
||||
|
||||
QueryResult result = WorldDatabase.Query(query);
|
||||
if (!result) {
|
||||
MpLogger::error("Failed to load mythic scale factors from database");
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
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 minIncrease1 = fields[8].Get<uint32>();
|
||||
uint32 maxIncrease1 = fields[9].Get<uint32>();
|
||||
uint32 minIncrease2 = fields[10].Get<uint32>();
|
||||
uint32 maxIncrease2 = fields[11].Get<uint32>();
|
||||
uint32 minIncrease3 = fields[12].Get<uint32>();
|
||||
uint32 maxIncrease3 = fields[13].Get<uint32>();
|
||||
uint32 chanceCost1 = fields[14].Get<uint32>();
|
||||
uint32 chanceCost2 = fields[15].Get<uint32>();
|
||||
uint32 chanceCost3 = fields[16].Get<uint32>();
|
||||
|
||||
// Should add validator... but let's do it without and trust in the o-DB-Wan-kenobe
|
||||
MpAdvancements advancement = static_cast<MpAdvancements>(advancementId);
|
||||
|
||||
// List of all ranks keyed by rank, advancementId
|
||||
MpAdvancementRank rank = {
|
||||
.rank = upgradeRank,
|
||||
.advancementId = advancement,
|
||||
.materialCost = std::unordered_map<uint32, uint32>(),
|
||||
.rollCost = {chanceCost1, chanceCost2, chanceCost3},
|
||||
.lowRange = std::make_pair(minIncrease1, maxIncrease1),
|
||||
.midRange = std::make_pair(minIncrease2, maxIncrease2),
|
||||
.highRange = std::make_pair(minIncrease3, maxIncrease3)
|
||||
};
|
||||
|
||||
rank.materialCost.emplace(materialId1, materialCost1);
|
||||
rank.materialCost.emplace(materialId2, materialCost2);
|
||||
rank.materialCost.emplace(materialId3, materialCost3);
|
||||
|
||||
_advancementRanks.try_emplace(std::make_pair(upgradeRank, advancement), rank);
|
||||
|
||||
} while (result->NextRow());
|
||||
|
||||
return _advancementRanks.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* guid INT UNSIGNED NOT NULL,
|
||||
* advancementId INT UNSIGNED NOT NULL,
|
||||
* bonus FLOAT NOT NULL,
|
||||
* upgradeRank INT UNSIGNED NOT NULL,
|
||||
* diceSpent INT UNSIGNED NOT NULL DEFAULT '0',
|
||||
*
|
||||
* PRIMARY KEY (guid, advancementId)
|
||||
*
|
||||
* This loads the player advancements when a player logs in stores it into memory for access by spell scripts that
|
||||
* are applied to the player on login to apply the bonuses.
|
||||
*/
|
||||
int32 AdvancementMgr::LoadPlayerAdvancements(Player* player) {
|
||||
|
||||
std::lock_guard<std::mutex> lock(_playerAdvancementMutex);
|
||||
|
||||
constexpr std::string_view query = R"(
|
||||
SELECT
|
||||
guid,
|
||||
advancementId,
|
||||
bonus,
|
||||
upgradeRank,
|
||||
diceSpent
|
||||
FROM mp_player_advancements
|
||||
WHERE guid = {}
|
||||
)";
|
||||
|
||||
QueryResult result = CharacterDatabase.Query(query, player->GetGUID().GetCounter());
|
||||
|
||||
// If the player does not have any upgrades just return perfectly fine not a problem until they purchase one.
|
||||
if(!result) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
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>();
|
||||
|
||||
MpAdvancements advancement = static_cast<MpAdvancements>(advancementId);
|
||||
MpPlayerRank playerRank = MpPlayerRank();
|
||||
playerRank.rank = upgradeRank;
|
||||
playerRank.advancementId = advancement;
|
||||
playerRank.diceSpent = diceSpent;
|
||||
playerRank.bonus = bonus;
|
||||
|
||||
// List of all ranks keyed by rank, advancementId
|
||||
_playerAdvancements[guid][advancement] = playerRank;
|
||||
|
||||
} while (result->NextRow());
|
||||
|
||||
return result->GetRowCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Material Types from the database into memory
|
||||
*/
|
||||
int32 AdvancementMgr::LoadMaterialTypes() {
|
||||
|
||||
constexpr std::string_view query = R"(
|
||||
SELECT
|
||||
materialId,
|
||||
entry
|
||||
FROM mp_material_types
|
||||
)";
|
||||
|
||||
QueryResult result = WorldDatabase.Query(query);
|
||||
|
||||
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);
|
||||
|
||||
} while (result->NextRow());
|
||||
|
||||
return result->GetRowCount();
|
||||
}
|
||||
|
||||
MpAdvancementRank* AdvancementMgr::GetAdvancementRank(uint32 rank, MpAdvancements advancement)
|
||||
{
|
||||
auto key = std::make_pair(rank, advancement);
|
||||
if (_advancementRanks.contains(key))
|
||||
{
|
||||
return &_advancementRanks.at(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
MpLogger::error("Advancement Id {} and rank {} could not be found", rank, advancement);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
MpPlayerRank* AdvancementMgr::GetPlayerAdvancementRank(Player* player, MpAdvancements advancement)
|
||||
{
|
||||
if(!player) {
|
||||
MpLogger::error("Could not retrieve player advancement for null player {}", player->GetName());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (_playerAdvancements.contains(player->GetGUID().GetCounter()) && _playerAdvancements[player->GetGUID().GetCounter()].contains(advancement))
|
||||
{
|
||||
return &_playerAdvancements[player->GetGUID().GetCounter()][advancement];
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool AdvancementMgr::UpgradeAdvancement(Player* player, MpAdvancements advancement, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_playerAdvancementMutex);
|
||||
|
||||
// Validators to make sure inputs are correct to perform the upgrade
|
||||
if(!player) {
|
||||
MpLogger::error("Could not upgrade advancement for player, player was nullpointer");
|
||||
return false;
|
||||
}
|
||||
if(diceCostLevel < 1 || diceCostLevel > 3) {
|
||||
MpLogger::error("Invalid dice cost level valid vales (1,2,3) received {} for player {}", diceCostLevel, player->GetName());
|
||||
return false;
|
||||
}
|
||||
if(itemEntry1 == 0) {
|
||||
MpLogger::error("Material1 can not be 0 can not perform advancement upgrade for player {} Advancement {}", player->GetName(), advancement);
|
||||
return false;
|
||||
}
|
||||
|
||||
MpPlayerRank* playerRank = GetPlayerAdvancementRank(player, advancement);
|
||||
|
||||
// IF there is not create the base struct and add to the player map for this advancement
|
||||
if(!playerRank) {
|
||||
MpPlayerRank newPlayerRank;
|
||||
newPlayerRank.advancementId = advancement;
|
||||
|
||||
auto& playerAdvMap = _playerAdvancements[player->GetGUID().GetCounter()];
|
||||
playerAdvMap.emplace(advancement, newPlayerRank);
|
||||
playerRank = &playerAdvMap.at(advancement);
|
||||
}
|
||||
|
||||
if(playerRank->rank == MP_MAX_ADVANCEMENT_RANK) {
|
||||
MpLogger::error("Player {} has reached the maximum rank for advancement {}", player->GetName(), advancement);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 newRank = playerRank->rank + 1;
|
||||
MpAdvancementRank* advancementRank = GetAdvancementRank(newRank, advancement);
|
||||
if(!advancementRank->IsValid()) {
|
||||
MpLogger::error("Advancement {} rank {} could not be found", advancement, newRank);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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::info("Player {} does not have the required items to upgrade advancement {}", player->GetName(), advancement);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Charge the player the cost of the upgrade
|
||||
_ChargeItemCost(player, advancementRank, diceCostLevel, itemEntry1, itemEntry2, itemEntry3);
|
||||
|
||||
// Finally get the bonus to apply for the player
|
||||
float roll = _RollAdvancement(advancementRank, diceCostLevel);
|
||||
|
||||
// Update the player advancement rank in memory and database
|
||||
playerRank->rank = newRank;
|
||||
playerRank->diceSpent += advancementRank->rollCost[diceCostLevel];
|
||||
playerRank->bonus += roll;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AdvancementMgr::ResetPlayerAdvancements(Player* /*player*/)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_playerAdvancementMutex);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AdvancementMgr::_ResetPlayerAdvancement(Player* player, MpAdvancements advancement)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_playerAdvancementMutex);
|
||||
return;
|
||||
}
|
||||
|
||||
// Roll them stats DnD style.
|
||||
float AdvancementMgr::_RollAdvancement(MpAdvancementRank* advancementRank, uint32 diceCostLevel)
|
||||
{
|
||||
uint32 min, max;
|
||||
|
||||
switch (diceCostLevel)
|
||||
{
|
||||
case 1:
|
||||
min = advancementRank->lowRange.first;
|
||||
max = advancementRank->lowRange.second;
|
||||
break;
|
||||
case 2:
|
||||
min = advancementRank->midRange.first;
|
||||
max = advancementRank->midRange.second;
|
||||
break;
|
||||
case 3:
|
||||
min = advancementRank->highRange.first;
|
||||
max = advancementRank->highRange.second;
|
||||
break;
|
||||
default:
|
||||
MpLogger::error("Invalid dice cost level valid vales (1,2,3) received {} for rank roll", diceCostLevel, advancementRank->rank);
|
||||
break;
|
||||
}
|
||||
|
||||
return frand(min, max);
|
||||
}
|
||||
|
||||
// Checks the players inventory to validate they have the required items to perform an upgrade based on the set cost for the passed in level.
|
||||
bool AdvancementMgr::_PlayerHasItems(Player* player, MpAdvancementRank* advancementRank, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3)
|
||||
{
|
||||
// Check if player has the required dice to upgrade the advancement if not do nothing.
|
||||
uint32 diceCost = advancementRank->materialCost.at(diceCostLevel);
|
||||
if(!player->HasItemCount(MpConstants::ANCIENT_DICE, diceCost)) {
|
||||
MpLogger::info("Player {} does not have enough dice to upgrade advancement {}", player->GetName(), advancementRank->advancementId);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate the passed in item for materialId 1 is valid and the player has enough to purchase.
|
||||
if(itemEntry1 > 0) {
|
||||
if(!advancementRank->HasMaterial(itemEntry1)) {
|
||||
MpLogger::error("Material1 {} is not a valid material for advancement {}", itemEntry1, advancementRank->advancementId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!player->HasItemCount(itemEntry1, advancementRank->materialCost[itemEntry1])) {
|
||||
MpLogger::info("Player {} does not have enough material {} to upgrade advancement {}", player->GetName(), itemEntry1, advancementRank->advancementId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(itemEntry2 > 0) {
|
||||
if(!advancementRank->HasMaterial(itemEntry2)) {
|
||||
MpLogger::error("Material1 {} is not a valid material for advancement {}", itemEntry2, advancementRank->advancementId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!player->HasItemCount(itemEntry2, advancementRank->materialCost[itemEntry2])) {
|
||||
MpLogger::info("Player {} does not have enough material {} to upgrade advancement {}", player->GetName(), itemEntry2, advancementRank->advancementId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(itemEntry3 > 0) {
|
||||
if(!advancementRank->HasMaterial(itemEntry3)) {
|
||||
MpLogger::error("Material1 {} is not a valid material for advancement {}", itemEntry3, advancementRank->advancementId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!player->HasItemCount(itemEntry3, advancementRank->materialCost[itemEntry3])) {
|
||||
MpLogger::info("Player {} does not have enough material {} to upgrade advancement {}", player->GetName(), itemEntry3, advancementRank->advancementId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remove all items required for the upgrade.
|
||||
void AdvancementMgr::_ChargeItemCost(Player *player, MpAdvancementRank* advancementRank, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3)
|
||||
{
|
||||
uint32 diceCost = advancementRank->materialCost[diceCostLevel];
|
||||
Item* item = player->GetItemByEntry(MpConstants::ANCIENT_DICE);
|
||||
item->SetCount(item->GetCount() - diceCost);
|
||||
item->SendUpdateToPlayer(player);
|
||||
|
||||
// Remove the material from the player inventory
|
||||
if(itemEntry1 > 0) {
|
||||
item = player->GetItemByEntry(itemEntry1);
|
||||
item->SetCount(item->GetCount() - advancementRank->materialCost[itemEntry1]);
|
||||
item->SendUpdateToPlayer(player); // Update the client with the new dice count
|
||||
}
|
||||
|
||||
if(itemEntry2 > 0) {
|
||||
item = player->GetItemByEntry(itemEntry2);
|
||||
item->SetCount(item->GetCount() - advancementRank->materialCost[itemEntry2]);
|
||||
item->SendUpdateToPlayer(player); // Update the client with the new dice count
|
||||
}
|
||||
|
||||
if(itemEntry3 > 0) {
|
||||
item = player->GetItemByEntry(itemEntry3);
|
||||
item->SetCount(item->GetCount() - advancementRank->materialCost[itemEntry3]);
|
||||
item->SendUpdateToPlayer(player); // Update the client with the new dice count
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
144
src/AdvancementMgr.h
Normal file
144
src/AdvancementMgr.h
Normal file
@@ -0,0 +1,144 @@
|
||||
#ifndef ADVANCEMENT_MGR_H
|
||||
#define ADVANCEMENT_MGR_H
|
||||
|
||||
#include "SharedDefines.h"
|
||||
#include "Player.h"
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
enum MpAdvancements
|
||||
{
|
||||
MP_ADV_STRENGTH = 0,
|
||||
MP_ADV_AGILITY = 1,
|
||||
MP_ADV_STAMINA = 2,
|
||||
MP_ADV_INTELLECT = 3,
|
||||
MP_ADV_SPIRIT = 4,
|
||||
MP_ADV_RESIST_FIRE = 5,
|
||||
MP_ADV_RESIST_NATURE = 6,
|
||||
MP_ADV_RESIST_FROST = 7,
|
||||
MP_ADV_RESIST_SHADOW = 8,
|
||||
MP_ADV_RESIST_ARCANE = 9,
|
||||
MP_ADV_MAX = 10
|
||||
};
|
||||
|
||||
/**
|
||||
* Advancement Rank represents each level for a stat increase that has can be purchases.
|
||||
* It includes materials, type, and range of successful roll.
|
||||
*/
|
||||
struct MpAdvancementRank
|
||||
{
|
||||
uint32 rank;
|
||||
MpAdvancements advancementId;
|
||||
std::unordered_map<uint32 /*item_entry*/,uint32 /*quantity*/> materialCost;
|
||||
|
||||
std::array<int, 3> rollCost; // 0 = low, 1 = mid, 2 = high
|
||||
|
||||
// Range of status based on bet dice roll.
|
||||
std::pair<uint32 /*min*/, uint32 /*max*/> lowRange;
|
||||
std::pair<uint32 /*min*/, uint32 /*max*/> midRange;
|
||||
std::pair<uint32 /*min*/, uint32 /*max*/> highRange;
|
||||
|
||||
// Used to validate this struct is set correctly
|
||||
bool IsValid() {
|
||||
return (rank > 0 && advancementId >= 0 && advancementId < MP_ADV_MAX);
|
||||
}
|
||||
|
||||
// Check if the map has an the item entry for the passed in material
|
||||
bool HasMaterial(uint32 itemEntry) {
|
||||
return materialCost.contains(itemEntry);
|
||||
}
|
||||
};
|
||||
|
||||
// Struct is used for tracking player advancement bonuses for improving stats
|
||||
struct MpPlayerRank
|
||||
{
|
||||
uint32 rank;
|
||||
MpAdvancements advancementId;
|
||||
uint32 diceSpent;
|
||||
float bonus;
|
||||
|
||||
MpPlayerRank() : rank(0), diceSpent(0), bonus(0.0f) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* This singleton class is responsible for managing the advancement system
|
||||
* used to improve player stats enough to challenge harder difficulties on existing dungeons.
|
||||
*
|
||||
* Advancements are purchased by players using based on the mp_material_type table with a "bet"
|
||||
* on dice roll. This enables players to increase their stats in a random way that is not
|
||||
* guaranteed to be successful. (Similar to how DND stats rolls work on character creation. )
|
||||
*/
|
||||
class AdvancementMgr
|
||||
{
|
||||
|
||||
// Shared mutex for handling writes to shared player advancement data
|
||||
std::mutex _playerAdvancementMutex;
|
||||
|
||||
// All advancement levels for each stat [rank][advancement_id] = AdvancementLevel
|
||||
std::map<std::pair<uint32 /*rank*/, MpAdvancements>, MpAdvancementRank> _advancementRanks;
|
||||
|
||||
// Map of player advancements [player_guid][advancement_id] = rank
|
||||
std::unordered_map<uint32 /*player_guid*/, std::unordered_map<MpAdvancements, MpPlayerRank>> _playerAdvancements;
|
||||
|
||||
// Map of different material types used fo advancing stats for players
|
||||
std::unordered_map<uint32 /*material_id*/, std::vector<uint32> /* item entries */> _materialTypes;
|
||||
|
||||
public:
|
||||
static AdvancementMgr* instance() {
|
||||
static AdvancementMgr instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
// Loads advancement information from the database into memory when players are logged in or server starts.
|
||||
int32 LoadAdvancementRanks();
|
||||
int32 LoadMaterialTypes();
|
||||
int32 LoadPlayerAdvancements(Player* player);
|
||||
|
||||
// Methods for looking up advancement rank data
|
||||
MpAdvancementRank* GetAdvancementRank(uint32 rank, MpAdvancements advancement);
|
||||
|
||||
// Methods for updating and setting data related to current player advancements
|
||||
MpPlayerRank* GetPlayerAdvancementRank(Player* player, MpAdvancements advancement);
|
||||
|
||||
/**
|
||||
* This upgrades a player Advancement on the server side, which will handle the following actions:
|
||||
* 1. Validating player has enough dice and materials to upgrade the advancement
|
||||
* 2. Rolling the dice to see what bonus is rewarded
|
||||
* 3. Removing the dice and materials from the player inventory
|
||||
* 4. Updating the player advancement rank in memory and database
|
||||
*
|
||||
* Since different materials can be used for each advancement, at the moment only support one material type from the list. supporting
|
||||
* 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.
|
||||
*/
|
||||
bool UpgradeAdvancement(Player* player, MpAdvancements advancement, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3);
|
||||
|
||||
// Used to reset all advancements for a specific player
|
||||
bool ResetPlayerAdvancements(Player* player);
|
||||
|
||||
private:
|
||||
AdvancementMgr() {}
|
||||
~AdvancementMgr() {}
|
||||
|
||||
// Will reset all the player advancements and refund the spent dice and material with a penalty for the reset.
|
||||
void _ResetPlayerAdvancement(Player* player, MpAdvancements advancement);
|
||||
|
||||
// Rolls the dice to see how much a bonus is given based on the dice spend level
|
||||
float _RollAdvancement(MpAdvancementRank* advancementRank, uint32 diceCostLevel);
|
||||
|
||||
// Determines if a player has required items to upgrade
|
||||
bool _PlayerHasItems(Player* player, MpAdvancementRank* advancementRank, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3);
|
||||
|
||||
// Removes items from player inventory based on the required advancement rank.
|
||||
void _ChargeItemCost(Player* player, MpAdvancementRank* advancementRank, uint32 diceCostLevel, uint32 itemEntry1, uint32 itemEntry2, uint32 itemEntry3);
|
||||
|
||||
// This will save the advancement purchase to the history database
|
||||
void _DBSaveAdvancement(Player* player, MpAdvancementRank* advancementRank, MpPlayerRank* playerRank, uint32 diceCost, float roll);
|
||||
|
||||
};
|
||||
|
||||
#define sAdvancementMgr AdvancementMgr::instance()
|
||||
#endif
|
||||
@@ -1,214 +0,0 @@
|
||||
|
||||
#include "Chat.h"
|
||||
#include "MpDataStore.h"
|
||||
#include "MythicPlus.h"
|
||||
#include "MpDataStore.h"
|
||||
#include "MpLogger.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
|
||||
using namespace Acore::ChatCommands;
|
||||
|
||||
// make sure this is the new way to do this, i think it's the old busted shit
|
||||
class MythicPlus_CommandScript : public CommandScript
|
||||
{
|
||||
public:
|
||||
MythicPlus_CommandScript() : CommandScript("MythicPlus_CommandScript")
|
||||
{
|
||||
}
|
||||
|
||||
ChatCommandTable GetCommands() const override
|
||||
{
|
||||
static ChatCommandTable commandTableMain =
|
||||
{
|
||||
{"", HandleHelp, SEC_PLAYER, Console::No},
|
||||
{"status", HandleStatus, SEC_PLAYER, Console::No},
|
||||
{"showstats", HandleDebug, SEC_PLAYER, Console::No},
|
||||
// {"mythic",HandleMythic, SEC_PLAYER, Console::No},
|
||||
// {"legendary",HandleLegendary, SEC_PLAYER, Console::No},
|
||||
// {"ascendant",HandleAscendant, SEC_PLAYER, Console::No},
|
||||
{"set", HandleSetDifficulty, SEC_PLAYER, Console::No},
|
||||
{"disable", HandleDisable, SEC_ADMINISTRATOR, Console::Yes},
|
||||
{"enable", HandleEnable, SEC_ADMINISTRATOR, Console::Yes}
|
||||
};
|
||||
|
||||
static ChatCommandTable commandTable =
|
||||
{
|
||||
{"mp", commandTableMain},
|
||||
{"mythicplus", commandTableMain},
|
||||
{"mp debug", HandleDebug, SEC_PLAYER, Console::No}
|
||||
};
|
||||
|
||||
return commandTable;
|
||||
}
|
||||
|
||||
static bool HandleHelp(ChatHandler* handler, const std::vector<std::string>& /*args*/)
|
||||
{
|
||||
std::string helpText = "Mythic+ Commands:\n"
|
||||
" .mp status - show current global settings of Mythic+ mod\n"
|
||||
" .mp set [mythic,legendary,ascendant] - Set Mythic+ difficulty in current beta only supports mythic.\n"
|
||||
" .mp [enable,disable] - enable or disable this mod\n"
|
||||
" .mp - Show this help message\n";
|
||||
handler->PSendSysMessage(helpText);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleDebug(ChatHandler* handler, const std::vector<std::string>& args)
|
||||
{
|
||||
|
||||
Creature* target = handler->getSelectedCreature();
|
||||
if(!target) {
|
||||
handler->PSendSysMessage("You must select a creature to debug.");
|
||||
return true;
|
||||
}
|
||||
|
||||
handler->PSendSysMessage(LANG_NPCINFO_LEVEL, target->GetLevel());
|
||||
handler->PSendSysMessage(LANG_NPCINFO_HEALTH, target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth());
|
||||
handler->PSendSysMessage("WeaponDmg Main {} - {}",
|
||||
target->GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE),
|
||||
target->GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE)
|
||||
);
|
||||
handler->PSendSysMessage("WeaponDmg Range {} - {}",
|
||||
target->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),
|
||||
target->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE)
|
||||
);
|
||||
handler->PSendSysMessage("WeaponDmg Offhand {} - {}",
|
||||
target->GetWeaponDamageRange(OFF_ATTACK, MINDAMAGE),
|
||||
target->GetWeaponDamageRange(OFF_ATTACK, MAXDAMAGE)
|
||||
);
|
||||
handler->PSendSysMessage("Attack Power Main {}", target->GetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE));
|
||||
handler->PSendSysMessage("Attack Power Ranged {}", target->GetModifierValue(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE));
|
||||
handler->PSendSysMessage(LANG_NPCINFO_ARMOR, target->GetArmor());
|
||||
handler->PSendSysMessage("Damage Modifier {}", target->GetModifierValue(UNIT_MOD_DAMAGE_MAINHAND, BASE_VALUE));
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// sets the difficluty for the group
|
||||
static bool HandleSetDifficulty(ChatHandler* handler, const std::vector<std::string>& args)
|
||||
{
|
||||
|
||||
Player* player = handler->GetSession()->GetPlayer();
|
||||
Group* group = player->GetGroup();
|
||||
|
||||
if (!group) {
|
||||
MpLogger::debug("HandleSetMythic() No Group for player: {}", player->GetName());
|
||||
handler->PSendSysMessage("|cFFFF0000 You must be in a group to be able to set a Mythic+ difficulty.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.empty()) {
|
||||
handler->PSendSysMessage("|cFFFF0000 You must specify a difficulty level. Expected values are 'mythic', 'legendary', or 'ascendant'.");
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string difficulty = args[0];
|
||||
// if(!sMythicPlus->IsDifficultyEnabled(difficulty)) {
|
||||
// handler->PSendSysMessage("|cFFFF0000 The difficulty level you have selected is not enabled.");
|
||||
// return true;
|
||||
// }
|
||||
|
||||
if (!group->IsLeader(player->GetGUID())) {
|
||||
handler->PSendSysMessage("|cFFFF0000 You must be the group leader to set a Mythic+ difficulty.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (player->GetMap()->IsDungeon()) {
|
||||
player->ResetInstances(player->GetGUID(), INSTANCE_RESET_CHANGE_DIFFICULTY, false);
|
||||
player->SendResetInstanceSuccess(player->GetMap()->GetId());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (difficulty == "mythic") {
|
||||
sMpDataStore->AddGroupData(group, MpGroupData(group, MP_DIFFICULTY_MYTHIC, 0));
|
||||
}
|
||||
else if (difficulty == "legendary") {
|
||||
sMpDataStore->AddGroupData(group,MpGroupData(group, MP_DIFFICULTY_LEGENDARY, 0));
|
||||
}
|
||||
else if (difficulty == "ascendant") {
|
||||
sMpDataStore->AddGroupData(group, MpGroupData(group, MP_DIFFICULTY_ASCENDANT, 0));
|
||||
}
|
||||
else {
|
||||
handler->PSendSysMessage("|cFFFF0000 Invalid difficulty level. Expected values are 'mythic', 'legendary', or 'ascendant'.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
handler->PSendSysMessage("Mythic+ difficulty set to: " + difficulty);
|
||||
MpLogger::debug("HandleSetMythic() Set difficulty player: {} {}", player->GetName(), difficulty);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleMythic(ChatHandler* handler, const std::vector<std::string>& /*args*/)
|
||||
{
|
||||
return HandleSetDifficulty(handler, {"mythic"});
|
||||
}
|
||||
|
||||
static bool HandleLegendary(ChatHandler* handler, const std::vector<std::string>& /*args*/)
|
||||
{
|
||||
return HandleSetDifficulty(handler, {"legendary"});
|
||||
}
|
||||
|
||||
static bool HandleAscendant(ChatHandler* handler, const std::vector<std::string>& /*args*/)
|
||||
{
|
||||
return HandleSetDifficulty(handler, {"ascendant"});
|
||||
}
|
||||
|
||||
static bool HandleStatus(ChatHandler* handler)
|
||||
{
|
||||
Player* player = handler->GetPlayer();
|
||||
|
||||
std::string status = Acore::StringFormat(
|
||||
"Mythic+ Status:\n"
|
||||
" Mythic+ Enabled: %s\n"
|
||||
" Mythic+ Item Rewards: %s\n"
|
||||
" Mythic+ DeathLimits: %s\n",
|
||||
sMythicPlus->Enabled ? "Yes" : "No",
|
||||
sMythicPlus->EnableItemRewards ? "Yes" : "No",
|
||||
sMythicPlus->EnableDeathLimits ? "Yes" : "No");
|
||||
|
||||
if (player->GetGroup()) {
|
||||
auto groupData = sMpDataStore->GetGroupData(player->GetGroup()->GetGUID());
|
||||
if (groupData) {
|
||||
status += Acore::StringFormat(
|
||||
" Group Difficulty: %u\n"
|
||||
" Group Deaths: %u\n",
|
||||
groupData->difficulty,
|
||||
groupData->deaths);
|
||||
} else {
|
||||
status += " Group Difficulty: Not Set\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
handler->PSendSysMessage(status);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleDisable(ChatHandler* handler)
|
||||
{
|
||||
MpLogger::debug("HandleDisable()");
|
||||
sMythicPlus->Enabled = false;
|
||||
handler->SendSysMessage("Mythic+ mod has been disabled.");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleEnable(ChatHandler* handler)
|
||||
{
|
||||
MpLogger::debug("HandleEnable()");
|
||||
sMythicPlus->Enabled = false;
|
||||
handler->SendSysMessage("Mythic+ mod has been enabled.");
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void Add_MP_CommandScripts()
|
||||
{
|
||||
MpLogger::debug("Add_MP_CommandScripts()");
|
||||
new MythicPlus_CommandScript();
|
||||
}
|
||||
35
src/Creature/BaseCreatureHandler.h
Normal file
35
src/Creature/BaseCreatureHandler.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "CreatureHooks.h"
|
||||
#include "MpLogger.h"
|
||||
|
||||
class BaseCreatureHandler {
|
||||
public:
|
||||
BaseCreatureHandler(uint32 entry) {
|
||||
|
||||
ASSERT(entry > 0);
|
||||
|
||||
MpLogger::debug("Registering JustDied and OnSpawn events for entry: ", entry);
|
||||
|
||||
// Register the JustDied event
|
||||
sCreatureHooks->RegisterJustDied(entry, [this](Creature* creature, Unit* killer) {
|
||||
this->OnJustDied(creature, killer);
|
||||
});
|
||||
|
||||
// Register the OnSpawn event
|
||||
sCreatureHooks->RegisterOnSpawn(entry, [this](Creature* creature) {
|
||||
this->OnJustSpawned(creature);
|
||||
});
|
||||
|
||||
sCreatureHooks->RegisterOnAddToInstance(entry, [this](Creature* creature) {
|
||||
this->OnAddToInstance(creature);
|
||||
});
|
||||
}
|
||||
|
||||
// Virtual event handlers to be overridden by bosses
|
||||
virtual void OnJustDied(Creature* /*creature*/, Unit* /*killer*/) {}
|
||||
|
||||
virtual void OnJustSpawned(Creature* /*creature*/) {}
|
||||
|
||||
virtual void OnAddToInstance(Creature* /*creature*/) {}
|
||||
|
||||
virtual ~BaseCreatureHandler() {}
|
||||
};
|
||||
84
src/Creature/CreatureHooks.cpp
Normal file
84
src/Creature/CreatureHooks.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#include "CreatureHooks.h"
|
||||
#include "MythicPlus.h"
|
||||
#include "MpLogger.h"
|
||||
|
||||
void CreatureHooks::RegisterJustDied(uint32 entry, CreatureHook<Creature*, Unit*> callback) {
|
||||
(*_JustDiedHandlers)[entry].push_back(callback);
|
||||
}
|
||||
|
||||
void CreatureHooks::RegisterOnSpawn(uint32 entry, CreatureHook<Creature*>callback) {
|
||||
(*_OnSpawnHandlers)[entry].push_back(callback);
|
||||
}
|
||||
|
||||
void CreatureHooks::RegisterOnAddToInstance(uint32 entry, CreatureHook<Creature*> callback) {
|
||||
(*_OnAddToInstanceHandlers)[entry].push_back(callback);
|
||||
}
|
||||
|
||||
// Call health events if the creature's health is at or below the percentage
|
||||
// void CheckHealthEvents(Creature* creature) {
|
||||
// uint32 entry = creature->GetEntry();
|
||||
// uint32 currentHealthPct = creature->GetHealthPct();
|
||||
|
||||
// if (_healthPercentEvents->contains(entry)) {
|
||||
// for (const auto& [percent, callbacks] : _healthPercentEvents->at(entry)) {
|
||||
// if (currentHealthPct <= percent) {
|
||||
// for (auto& callback : callbacks) {
|
||||
// callback(creature); // Trigger custom behavior
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
void CreatureHooks::JustDied(Creature* creature, Unit* killer) {
|
||||
if(!creature) {
|
||||
MpLogger::debug("JustDied() called with nullptr for creature");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!killer) {
|
||||
MpLogger::debug("JustDied() called with nullptr for killer");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uint32 entry = creature->GetEntry();
|
||||
if (_JustDiedHandlers->contains(entry)) {
|
||||
for (auto& callback : _JustDiedHandlers->at(entry)) {
|
||||
MpLogger::debug("JustDied() called for creature: {}", entry);
|
||||
callback(creature, killer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureHooks::JustSpawned(Creature* creature) {
|
||||
if(!creature) {
|
||||
MpLogger::debug("JustSpawned() called with nullptr for creature");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 entry = creature->GetEntry();
|
||||
MpInstanceData* instanceData = sMpDataStore->GetInstanceData(creature->GetMapId(), creature->GetInstanceId());
|
||||
|
||||
if(instanceData) {
|
||||
sMythicPlus->AddScaledCreature(creature, instanceData);
|
||||
}
|
||||
|
||||
if (_OnSpawnHandlers->contains(entry)) {
|
||||
for (auto& callback : _OnSpawnHandlers->at(entry)) {
|
||||
callback(creature);
|
||||
MpLogger::debug("JustSpawned() called in CreatureHook: {}", entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureHooks::AddToInstance(Creature* creature) {
|
||||
uint32 entry = creature->GetEntry();
|
||||
|
||||
if (_OnAddToInstanceHandlers->contains(entry)) {
|
||||
for (auto& callback : _OnAddToInstanceHandlers->at(entry)) {
|
||||
callback(creature);
|
||||
MpLogger::debug("AddedToInstance() called in CreatureHook: {}", entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
92
src/Creature/CreatureHooks.h
Normal file
92
src/Creature/CreatureHooks.h
Normal file
@@ -0,0 +1,92 @@
|
||||
#ifndef CREATUREHOOKS_H
|
||||
#define CREATUREHOOKS_H
|
||||
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "Creature.h"
|
||||
#include "ObjectGuid.h"
|
||||
|
||||
// Struct to store the state of which handlers have been fired for a creature
|
||||
struct CreatureEventState {
|
||||
bool onDeathEventFired = false;
|
||||
bool onSpawnEventFired = false;
|
||||
bool onAddedToInstanceEventFired = false;
|
||||
uint8 deaths = 0; // Count of deaths
|
||||
};
|
||||
|
||||
// Type aliases for creature event handling
|
||||
// using CreatureHook = std::function<void(Creature*)>;
|
||||
// using HookList = std::vector<CreatureHook>;
|
||||
// using HandlerMap = std::unordered_map<uint32, HookList>;
|
||||
|
||||
// Type alias for variadic event hooks
|
||||
template<typename... Args>
|
||||
using CreatureHook = std::function<void(Args...)>;
|
||||
|
||||
// Type alias for a list of hooks that take varying arguments
|
||||
template<typename... Args>
|
||||
using HandlersList = std::vector<CreatureHook<Args...>>;
|
||||
|
||||
// HandlerMap using variadic templates
|
||||
template<typename... Args>
|
||||
using HandlerMap = std::unordered_map<uint32, HandlersList<Args...>>;
|
||||
|
||||
using CreatureEventStateMap = std::map<ObjectGuid, CreatureEventState>;
|
||||
|
||||
class CreatureHooks {
|
||||
private:
|
||||
|
||||
CreatureHooks():
|
||||
_OnSpawnHandlers(std::make_unique<HandlerMap<Creature*>>()),
|
||||
_JustDiedHandlers(std::make_unique<HandlerMap<Creature*, Unit*>>()),
|
||||
_OnAddToInstanceHandlers(std::make_unique<HandlerMap<Creature*>>()),
|
||||
_eventStates(std::make_unique<CreatureEventStateMap>())
|
||||
{
|
||||
_OnSpawnHandlers->reserve(128);
|
||||
_JustDiedHandlers->reserve(128);
|
||||
_OnAddToInstanceHandlers->reserve(100);
|
||||
}
|
||||
|
||||
~CreatureHooks() {
|
||||
_OnSpawnHandlers->clear();
|
||||
_JustDiedHandlers->clear();
|
||||
_OnAddToInstanceHandlers->clear();
|
||||
_eventStates->clear();
|
||||
}
|
||||
|
||||
// ensure we only ever have one instance of this class
|
||||
CreatureHooks(const CreatureHooks&) = delete;
|
||||
CreatureHooks& operator=(const CreatureHooks&) = delete;
|
||||
|
||||
// Data members for storing event handlers
|
||||
std::unique_ptr<HandlerMap<Creature*>> _OnSpawnHandlers;
|
||||
std::unique_ptr<HandlerMap<Creature*, Unit*>> _JustDiedHandlers;
|
||||
std::unique_ptr<HandlerMap<Creature*>> _OnAddToInstanceHandlers;
|
||||
|
||||
// Tracks state to know which handlers need to be fired again
|
||||
std::unique_ptr<CreatureEventStateMap> _eventStates;
|
||||
|
||||
public:
|
||||
static CreatureHooks* instance() {
|
||||
static CreatureHooks instance;
|
||||
|
||||
return &instance;
|
||||
}
|
||||
|
||||
// Register events for specific actions
|
||||
void RegisterJustDied(uint32 entry, CreatureHook<Creature*, Unit*> callback);
|
||||
void RegisterOnSpawn(uint32 entry, CreatureHook<Creature*> callback);
|
||||
void RegisterOnAddToInstance(uint32 entry, CreatureHook<Creature*> callback);
|
||||
|
||||
|
||||
// Event triggers
|
||||
void JustDied(Creature* creature, Unit* killer);
|
||||
void JustSpawned(Creature* creature);
|
||||
void AddToInstance(Creature* creature);
|
||||
};
|
||||
|
||||
#define sCreatureHooks CreatureHooks::instance()
|
||||
|
||||
#endif // CREATUREHOOKS_H
|
||||
32
src/Creature/CreatureOverride.h
Normal file
32
src/Creature/CreatureOverride.h
Normal file
@@ -0,0 +1,32 @@
|
||||
// #include "MpDataStore.h"
|
||||
// #include "MpLogger.h"
|
||||
|
||||
// class CreatureOverride {
|
||||
// public:
|
||||
// uint32 entry;
|
||||
// MpDifficulty difficulty;
|
||||
// Creature* creature;
|
||||
|
||||
// CreatureOverride(uint32 entry): entry(entry), difficulty(difficulty) {
|
||||
// sMpDataStore->AddCreatureOverride(this->entry, this);
|
||||
// }
|
||||
|
||||
// virtual void Modify(Creature* creature) final {
|
||||
// this->creature = creature;
|
||||
// }
|
||||
|
||||
// virtual void HandleModify() = 0;
|
||||
|
||||
|
||||
// void ModifyAttackPower(uint32 ap) {
|
||||
// if(this)
|
||||
// }
|
||||
|
||||
// void ModifyHealth(uint32 health) {}
|
||||
|
||||
// void ModifyArmor(uint32 armor) {}
|
||||
|
||||
// void ModifySpellPower(uint32 sp) {}
|
||||
|
||||
// ~CreatureOverride() {}
|
||||
// };
|
||||
45
src/Event/MpClientDispatch.cpp
Normal file
45
src/Event/MpClientDispatch.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#include "MpClientDispatcher.h"
|
||||
#include "MpEventProcessor.h"
|
||||
#include "Player.h"
|
||||
#include "MpLogger.h"
|
||||
#include "Chat.h"
|
||||
#include "WorldPacket.h"
|
||||
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* In order to allow communication from client UIs without modifying mod-eluna directly to support
|
||||
* This sends a packet directly using the AddOn message channel in the background.
|
||||
*/
|
||||
bool MpClientDispatcher::Dispatch(MpClientEvent event, Player* player, std::vector<std::string>& args)
|
||||
{
|
||||
if(!MpClientEventNames.contains(event)) {
|
||||
MpLogger::warn("No event registered for event: {}", event);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build the message string in same format to send to the client.
|
||||
std::string_view eventName = MpClientEventNames.at(event);
|
||||
std::string message = std::to_string(player->GetGUID().GetCounter()) + "|" + eventName.data();
|
||||
for(auto& arg : args) {
|
||||
message += "|" + arg;
|
||||
}
|
||||
|
||||
std::string prefix = std::string(MP_DATA_CHAT_CHANNEL);
|
||||
std::string fullmsg = prefix + "\t" + message;
|
||||
|
||||
WorldPacket data(SMSG_MESSAGECHAT, 100);
|
||||
data << uint8(CHAT_MSG_ADDON);
|
||||
data << int32(LANG_ADDON);
|
||||
data << player->GetGUID().GetCounter();
|
||||
data << uint32(0);
|
||||
data << player->GetGUID().GetCounter();
|
||||
data << uint32(fullmsg.length() + 1);
|
||||
data << fullmsg;
|
||||
data << uint8(0);
|
||||
player->GetSession()->SendPacket(&data);
|
||||
return 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
35
src/Event/MpClientDispatcher.h
Normal file
35
src/Event/MpClientDispatcher.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef MYTHIC_PLUS_CLIENT_DISPATCHER_H
|
||||
#define MYTHIC_PLUS_CLIENT_DISPATCHER_H
|
||||
|
||||
#include "MpEvent.h"
|
||||
#include "Player.h"
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
class MpClientDispatcher
|
||||
{
|
||||
|
||||
public:
|
||||
static MpClientDispatcher* instance() {
|
||||
static MpClientDispatcher instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
MpClientDispatcher(const MpClientDispatcher&) = delete;
|
||||
MpClientDispatcher& operator=(const MpClientDispatcher&) = delete;
|
||||
|
||||
// encode and send a message to the client for an event in the map
|
||||
bool Dispatch(MpClientEvent event, Player* player, std::vector<std::string>& args);
|
||||
|
||||
private:
|
||||
MpClientDispatcher() {};
|
||||
~MpClientDispatcher() {};
|
||||
|
||||
};
|
||||
|
||||
#define sMpClientDispatcher MpClientDispatcher::instance()
|
||||
|
||||
#endif
|
||||
|
||||
47
src/Event/MpEvent.h
Normal file
47
src/Event/MpEvent.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#include <array>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#ifndef MP_EVENTS_H
|
||||
#define MP_EVENTS_H
|
||||
|
||||
// This defines list of incoming events typically from the client
|
||||
enum class MpEvent
|
||||
{
|
||||
None, // Default catch all for no event
|
||||
Invalid, // Used to capture identify error events
|
||||
UpgradeAdvancement, // Upgrades a player advancement 1 level
|
||||
ResetAdvancement, // Resets a player Advancement back to 0
|
||||
ResetAllAdvancements, // Resets all player advancements
|
||||
GetAdvancementRank // Get the details about the rank of a specific advancement (cost, bonus, etc)
|
||||
};
|
||||
|
||||
// Client events that are communicated to the over an addon message to the player client
|
||||
enum class MpClientEvent
|
||||
{
|
||||
Error,
|
||||
UpgradeAdvancement,
|
||||
ResetAdvancement,
|
||||
ResetAllAdvancements,
|
||||
GetAdvancementRank
|
||||
};
|
||||
|
||||
// Mapping of Event Strings to EventNames for Event Callbacks from client
|
||||
inline std::unordered_map<std::string_view, MpEvent> MpEventMap = {{
|
||||
{"UpgradeAdvancement", MpEvent::UpgradeAdvancement},
|
||||
{"ResetAdvancement", MpEvent::ResetAdvancement},
|
||||
{"ResetAllAdvancements", MpEvent::ResetAllAdvancements},
|
||||
{"GetAdvancementRank", MpEvent::ResetAllAdvancements}
|
||||
}};
|
||||
|
||||
inline std::unordered_map<MpClientEvent, std::string_view> MpClientEventNames = {{
|
||||
{MpClientEvent::Error, "Error"},
|
||||
{MpClientEvent::UpgradeAdvancement, "UpgradeAdvancement"},
|
||||
{MpClientEvent::ResetAdvancement, "ResetAdvancement"},
|
||||
{MpClientEvent::ResetAllAdvancements, "ResetAllAdvancements"},
|
||||
{MpClientEvent::GetAdvancementRank, "GetAdvancementRank"}
|
||||
}};
|
||||
|
||||
|
||||
#endif
|
||||
139
src/Event/MpEventHandlers.cpp
Normal file
139
src/Event/MpEventHandlers.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
#include "MpEvent.h"
|
||||
#include "MpLogger.h"
|
||||
#include "AdvancementMgr.h"
|
||||
#include "MpEventProcessor.h"
|
||||
#include "MpClientDispatcher.h"
|
||||
#include "Player.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* All handlers for passed between client and server handlers are managed
|
||||
* here.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles Updates to a players advancement system
|
||||
* Event format
|
||||
* p|playerGuid|UpgradeAdvancement|advancementId|rank|diceSpent|bonus
|
||||
*/
|
||||
enum class MP_EVENT_CODE
|
||||
{
|
||||
SUCCESS = 0,
|
||||
INVALID_EVENT = 100,
|
||||
INVALID_ARGUMENT_SIZE = 201,
|
||||
INVALID_ARGUMENT = 202,
|
||||
INVALID_ARGUMENT_TYPE = 203,
|
||||
|
||||
};
|
||||
|
||||
// Send an error event to the client
|
||||
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);
|
||||
sMpClientDispatcher->Dispatch(MpClientEvent::Error, player, clientError);
|
||||
return false;
|
||||
}
|
||||
|
||||
class UpdateAdvancements : public MpEventInterface
|
||||
{
|
||||
public:
|
||||
const std::string EventName() const override
|
||||
{
|
||||
return "UpgradeAdvancement";
|
||||
}
|
||||
|
||||
bool Execute(Player* player, std::vector<std::string>& args)
|
||||
{
|
||||
// Store the event data to send back to the client for parsing
|
||||
std::vector<std::string> eventData;
|
||||
|
||||
MpLogger::info("(EventProcessor) Executing {}}", EventName());
|
||||
for(auto& arg : args) {
|
||||
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()));
|
||||
}
|
||||
|
||||
uint32 advancementId = std::stoi(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));
|
||||
}
|
||||
|
||||
uint32 diceLevel = std::stoi(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");
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
// Upgrade the advancement for the player!
|
||||
if(! sAdvancementMgr->UpgradeAdvancement(player, static_cast<MpAdvancements>(advancementId), diceLevel, itemEntry1, itemEntry2, itemEntry3)) {
|
||||
return SendEventError(player, EventName(),MP_EVENT_CODE::INVALID_ARGUMENT, "Failed to upgrade advancement for player " + player->GetName());
|
||||
}
|
||||
eventData = {"0", "success"};
|
||||
|
||||
// Send response back to the client
|
||||
sMpClientDispatcher->Dispatch(MpClientEvent::UpgradeAdvancement, player, eventData);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class GetAdvancementRank : public MpEventInterface
|
||||
{
|
||||
public:
|
||||
const std::string EventName() const override
|
||||
{
|
||||
return "GetAdvancementRank";
|
||||
}
|
||||
|
||||
bool Execute(Player* player, std::vector<std::string>& args)
|
||||
{
|
||||
// Store the event data to send back to the client for parsing
|
||||
std::vector<std::string> eventData;
|
||||
|
||||
MpLogger::info("(EventProcessor) Executing {}}", EventName());
|
||||
for(auto& arg : args) {
|
||||
MpLogger::info("{} Arg: {}", EventName(), arg);
|
||||
}
|
||||
|
||||
// Validate the message is int he right format
|
||||
if(args.size() != 1) {
|
||||
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]);
|
||||
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));
|
||||
}
|
||||
|
||||
MpAdvancementRank* rank = sAdvancementMgr->GetAdvancementRank(1, static_cast<MpAdvancements>(advancementId));
|
||||
if(!rank) {
|
||||
return SendEventError(player, EventName(),MP_EVENT_CODE::INVALID_ARGUMENT, "Failed to get advancement rank for player " + player->GetName());
|
||||
}
|
||||
|
||||
eventData = {std::to_string(rank->rank), std::to_string(rank->advancementId)};
|
||||
|
||||
// Send response back to the client
|
||||
sMpClientDispatcher->Dispatch(MpClientEvent::GetAdvancementRank, player, eventData);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void MP_Register_EventHandlers()
|
||||
{
|
||||
auto updateAdvancements = std::make_shared<UpdateAdvancements>();
|
||||
sMpEventProcessor->RegisterHandler(MpEvent::UpgradeAdvancement, updateAdvancements);
|
||||
}
|
||||
131
src/Event/MpEventProcessor.cpp
Normal file
131
src/Event/MpEventProcessor.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
|
||||
#include "MpEventProcessor.h"
|
||||
#include "MythicPlus.h"
|
||||
#include "MpLogger.h"
|
||||
#include "Player.h"
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
bool MpEventProcessor::ProcessMessage(Player* player, const std::string& msg) {
|
||||
|
||||
if(!player) {
|
||||
MpLogger::error("Null player passed to processMessage");
|
||||
return false;
|
||||
}
|
||||
|
||||
// check prefix of message channel is formatted correctly
|
||||
if(! msg.starts_with(MP_DATA_CHAT_CHANNEL)) {
|
||||
MpLogger::error("Invalid message format received from player {} message: {}", player->GetName(), msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string message = msg;
|
||||
|
||||
// shift the message identifier off the front including first '|' character
|
||||
message.erase(0, MP_DATA_CHAT_CHANNEL.size()+1);
|
||||
|
||||
// clean up the message before passing it to the parser
|
||||
boost::replace_all(message, "||", "|");
|
||||
|
||||
EventParseRslt result = _parsePlayerMessage(player, message);
|
||||
MpEvent event = std::get<0>(result);
|
||||
uint32 guid = std::get<1>(result);
|
||||
std::vector<std::string> args = std::get<2>(result);
|
||||
|
||||
MpLogger::info("MpEvent Processor - event: {} guid: {} args: {}", event, guid, args.size());
|
||||
|
||||
// If th message was not able to be parsed it is a failure
|
||||
if(event == MpEvent::Invalid) {
|
||||
MpLogger::warn("Invalid event, could not be parsed for player {} message: {}", player->GetName(), message);
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the message is not from the same player who called it ignore it as it is attempt to hack the system
|
||||
if(player->GetGUID().GetCounter() != guid) {
|
||||
MpLogger::warn("Player {} sent a message {} for eventId: {} player guid does not match", player->GetName(), message, event);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the event is not registered ignore it
|
||||
if(!_eventHandlers.contains(event)) {
|
||||
MpLogger::info("No handler registered for event: {}", event);
|
||||
return false;
|
||||
}
|
||||
|
||||
return Dispatch(event, player, args);
|
||||
}
|
||||
|
||||
void MpEventProcessor::RegisterHandler(MpEvent event, std::shared_ptr<MpEventInterface> handler) {
|
||||
_eventHandlers[event] = handler;
|
||||
}
|
||||
|
||||
// This fires the execution to the actual event.
|
||||
bool MpEventProcessor::Dispatch(MpEvent event, Player* player, std::vector<std::string>& args) {
|
||||
if(!_eventHandlers.contains(event)) {
|
||||
MpLogger::warn("No handler registered for event: {}", event);
|
||||
return false;
|
||||
}
|
||||
|
||||
return _eventHandlers[event]->Execute(player, args);
|
||||
}
|
||||
|
||||
// Find our eventId using the string name
|
||||
MpEvent MpEventProcessor::_getEventByName(std::string_view eventName)
|
||||
{
|
||||
auto it = MpEventMap.find(eventName);
|
||||
return (it != MpEventMap.end()) ? it->second : MpEvent::None;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the incoming message into id, event, and handler arguments
|
||||
*/
|
||||
EventParseRslt MpEventProcessor::_parsePlayerMessage(Player* player, const std::string& msg)
|
||||
{
|
||||
if(msg[0] != 'p') {
|
||||
MpLogger::warn("Invalid player message format received from player {} message: {}", player->GetName(), msg);
|
||||
return EventParseRslt{MpEvent::Invalid, 0, {}};
|
||||
}
|
||||
|
||||
std::vector<std::string> handlerArgs;
|
||||
char delimiter = '|';
|
||||
|
||||
// split the protocol into valid parts
|
||||
std::vector<std::string> parts = _splitString(msg, delimiter);
|
||||
|
||||
if (parts.size() < 3) {
|
||||
MpLogger::warn("Malformed player message received from player {}: {}", player->GetName(), msg);
|
||||
return EventParseRslt{MpEvent::Invalid, 0, {}};
|
||||
}
|
||||
|
||||
MpEvent event = _getEventByName(parts[2]);
|
||||
|
||||
handlerArgs.assign(parts.begin() + 3, parts.end());
|
||||
|
||||
MpLogger::info("Player {} sent a client event message {} for event: {} eventId: {} ", player->GetName(), msg, MP_DATA_CHAT_CHANNEL, parts[2], event);
|
||||
return EventParseRslt{event, player->GetGUID().GetCounter(), std::move(handlerArgs)};
|
||||
}
|
||||
|
||||
// Split the string passed in by delimiters
|
||||
std::vector<std::string> MpEventProcessor::_splitString(const std::string& s, char delimiter) {
|
||||
std::vector<std::string> tokens;
|
||||
size_t start = 0;
|
||||
size_t end = s.find(delimiter);
|
||||
|
||||
while (end != std::string::npos) {
|
||||
if (end != start) {
|
||||
tokens.emplace_back(s.substr(start, end - start));
|
||||
}
|
||||
start = end + 1;
|
||||
end = s.find(delimiter, start);
|
||||
}
|
||||
|
||||
// Add the last token if it's not empty
|
||||
if (start < s.length()) {
|
||||
tokens.emplace_back(s.substr(start));
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
86
src/Event/MpEventProcessor.h
Normal file
86
src/Event/MpEventProcessor.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef MYTHIC_PLUS_EVENT_PROCESSOR_H
|
||||
#define MYTHIC_PLUS_EVENT_PROCESSOR_H
|
||||
|
||||
#include "MpEvent.h"
|
||||
#include "Player.h"
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
|
||||
/**
|
||||
* In order to allow communication from client UIs without modifying mod-eluna directly to support
|
||||
* this mods functionality the following custom chat channel below is for all MP UI Client interactions.
|
||||
*
|
||||
* p|playerGuid|action|input1|input2|input3...
|
||||
*/
|
||||
inline const std::string_view MP_DATA_CHAT_CHANNEL = "MPUi";
|
||||
|
||||
/**
|
||||
* Interface for all Mythic+ Event communication between client and server
|
||||
*/
|
||||
class MpEventInterface
|
||||
{
|
||||
public:
|
||||
MpEventInterface() = default;
|
||||
virtual ~MpEventInterface() = default;
|
||||
[[nodiscard]] virtual bool Execute(Player* player, std::vector<std::string>& args) = 0;
|
||||
|
||||
[[nodiscard]] virtual const std::string EventName() const = 0;
|
||||
};
|
||||
|
||||
using EventParseRslt = std::tuple<MpEvent, uint32_t, std::vector<std::string>>;
|
||||
|
||||
/**
|
||||
* This class is responsible for processing events that are send from the client. Events
|
||||
* are processed FIFO and executed. This is specifically to allow AddOn or AIO
|
||||
* communication to this module without requiring additional changes to mod-eluna or the core.
|
||||
*
|
||||
* Message Body Format
|
||||
* Client Player Events
|
||||
* - p|playerGuid|action|input1|input2|input3...
|
||||
* i.e) p|5793|UpgradeAdvancement|0|10|2
|
||||
*/
|
||||
class MpEventProcessor
|
||||
{
|
||||
|
||||
public:
|
||||
static MpEventProcessor* instance() {
|
||||
static MpEventProcessor instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
MpEventProcessor(const MpEventProcessor&) = delete;
|
||||
MpEventProcessor& operator=(const MpEventProcessor&) = delete;
|
||||
|
||||
// Process a message from a specific player
|
||||
bool ProcessMessage(Player* player, const std::string& msg);
|
||||
|
||||
// Registers a handler for a valid MpEvent specified in the MpEvent enum
|
||||
// In this design Event:Handler is 1:1
|
||||
void RegisterHandler(MpEvent event, std::shared_ptr<MpEventInterface> handler);
|
||||
|
||||
// Dispatch will execute the event handler
|
||||
bool Dispatch(MpEvent event, Player* player, std::vector<std::string>& args);
|
||||
|
||||
private:
|
||||
MpEventProcessor() {}
|
||||
~MpEventProcessor() {}
|
||||
|
||||
// List of registered handlers for event management
|
||||
std::unordered_map<MpEvent, std::shared_ptr<MpEventInterface>> _eventHandlers;
|
||||
|
||||
// Get the correct Event associated to handlers by the message strong
|
||||
MpEvent _getEventByName(std::string_view eventName);
|
||||
|
||||
// Parse a message from the player
|
||||
EventParseRslt _parsePlayerMessage(Player* player, const std::string& msg);
|
||||
|
||||
// Helper to break up a string into pieces used in parsing the message
|
||||
std::vector<std::string> _splitString(const std::string& s, char delimiter = '|');
|
||||
};
|
||||
|
||||
#define sMpEventProcessor MpEventProcessor::instance()
|
||||
|
||||
#endif // MYTHIC_PLUS_EVENT_PROCESSOR_H
|
||||
@@ -1,35 +0,0 @@
|
||||
|
||||
#include "MpDataStore.h"
|
||||
#include "MpLogger.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "Group.h"
|
||||
|
||||
// this handles updating custom group difficulties used in auto balancing mobs and
|
||||
// scripts that enable buffs on mobs randomly
|
||||
class MythicPlus_GroupScript : public GroupScript
|
||||
{
|
||||
public:
|
||||
MythicPlus_GroupScript() : GroupScript("MythicPlus_GroupScript") { }
|
||||
|
||||
void OnCreate(Group* group, Player* leader) override {
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!leader) {
|
||||
return;
|
||||
}
|
||||
|
||||
// sMpDataStore->AddGroupData(group->GetGUID(), gd);
|
||||
}
|
||||
|
||||
void OnDisband(Group* group) override {
|
||||
sMpDataStore->RemoveGroupData(group);
|
||||
}
|
||||
};
|
||||
|
||||
void Add_MP_GroupScripts()
|
||||
{
|
||||
MpLogger::debug("Add_MP_GroupScripts()");
|
||||
new MythicPlus_GroupScript();
|
||||
}
|
||||
26
src/Instances/Ragefire/boss_bazzalan.cpp
Normal file
26
src/Instances/Ragefire/boss_bazzalan.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// #include "BaseCreatureHandler.h"
|
||||
// #include "Spell.h"
|
||||
|
||||
// /**
|
||||
// * Bazzalan need some upgrades so made him more formidable
|
||||
// */
|
||||
// class Ragefire_Bazzalan_Mythic : public BaseCreatureHandler
|
||||
// {
|
||||
// public:
|
||||
// Ragefire_Bazzalan_Mythic() : BaseCreatureHandler(11519) {}
|
||||
|
||||
|
||||
// void OnAddToInstance(Creature* creature) override {
|
||||
|
||||
// uint32 health = creature->GetMaxHealth() * 2;
|
||||
// creature->SetCreateHealth(health);
|
||||
// creature->SetMaxHealth(health);
|
||||
// creature->SetHealth(health);
|
||||
// creature->ResetPlayerDamageReq();
|
||||
// creature->SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, (float)health);
|
||||
|
||||
// creature->AddExtraAttacks(3);
|
||||
// creature->SetObjectScale(2.0f);
|
||||
|
||||
// }
|
||||
// };
|
||||
11
src/MpConstants.h
Normal file
11
src/MpConstants.h
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
#ifndef MP_CONSTANTS_H
|
||||
#define MP_CONSTANTS_H
|
||||
|
||||
namespace MpConstants
|
||||
{
|
||||
constexpr int ANCIENT_DICE = 911000;
|
||||
constexpr int DARK_SPIKE = 911001;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,9 +1,16 @@
|
||||
#include "CharacterDatabase.h"
|
||||
#include "MpDataStore.h"
|
||||
#include "Chat.h"
|
||||
#include "Group.h"
|
||||
#include "MpLogger.h"
|
||||
|
||||
// Adds an entry for the group difficult to memory and updats database
|
||||
void MpDataStore::AddGroupData(Group *group, MpGroupData groupData) {
|
||||
if(!group) {
|
||||
MpLogger::error("AddGroupData called with null group pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectGuid guid = group->GetGUID();
|
||||
|
||||
if (!guid) {
|
||||
@@ -15,19 +22,81 @@ void MpDataStore::AddGroupData(Group *group, MpGroupData groupData) {
|
||||
MpLogger::error("AddGroupData called with invalid difficulty");
|
||||
return;
|
||||
}
|
||||
// if we already have data override it
|
||||
if (_groupData->contains(guid)) {
|
||||
_groupData->at(guid) = groupData;
|
||||
} else {
|
||||
_groupData->emplace(guid, groupData);
|
||||
|
||||
Player* leader = group->GetLeader();
|
||||
if(!leader) {
|
||||
MpLogger::error("AddGroupData called with null group leader");
|
||||
return;
|
||||
}
|
||||
|
||||
MpLogger::debug("Add Group difficulty for group {} to {}", guid.GetCounter());
|
||||
Map* map = leader->GetMap();
|
||||
if (!map) {
|
||||
MpLogger::error("AddGroupData called with null map for group leader");
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterDatabase.Execute("REPLACE INTO group_difficulty (guid, difficulty) VALUES ({},{}) ",
|
||||
guid.GetCounter(),
|
||||
groupData.difficulty
|
||||
);
|
||||
auto instance = map->ToInstanceMap();
|
||||
|
||||
// if we already have data override it
|
||||
if (_groupData->contains(guid)) {
|
||||
|
||||
MpGroupData existingData = _groupData->at(guid);
|
||||
if(groupData.difficulty == MP_DIFFICULTY_HEROIC || groupData.difficulty == MP_DIFFICULTY_NORMAL || groupData.difficulty != existingData.difficulty) {
|
||||
|
||||
// if we set a lower difficulty and we are in an instance we need to kick the group out and reset the instance.
|
||||
if(instance && instance->HavePlayers()) {
|
||||
|
||||
instance->Reset(2); // 2 = reset all
|
||||
|
||||
const Map::PlayerList players = map->GetPlayers();
|
||||
for (auto itr = players.begin(); itr != players.end(); ++itr) {
|
||||
Player* player = itr->GetSource();
|
||||
|
||||
if(!player) {
|
||||
MpLogger::error("AddGroupData called with null player in instance");
|
||||
}
|
||||
ChatHandler(player->GetSession()).SendSysMessage("The group leader has changed the difficulty setting. You have been removed from the instance.");
|
||||
//("The group leader has changed the difficulty setting. You have been removed from the instance.");
|
||||
// player->GetSession()->SendNotification("The group leader has changed the difficulty setting. You have been removed from the instance.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_groupData->at(guid) = groupData;
|
||||
|
||||
} else {
|
||||
|
||||
if(instance && instance->HavePlayers()) {
|
||||
|
||||
instance->Reset(2); // 2 = reset all
|
||||
|
||||
const Map::PlayerList players = map->GetPlayers();
|
||||
for (auto itr = players.begin(); itr != players.end(); ++itr) {
|
||||
Player* player = itr->GetSource();
|
||||
|
||||
if(!player) {
|
||||
MpLogger::error("AddGroupData called with null player in instance");
|
||||
}
|
||||
|
||||
if(player) {
|
||||
ChatHandler(player->GetSession()).SendSysMessage("The group leader has changed the difficulty setting. You have been removed from the instance.");
|
||||
// player->GetSession()->SendNotification("The group leader has changed the difficulty setting. You have been removed from the instance."); -- previous implementation for older core users
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_groupData->emplace(guid, groupData);
|
||||
|
||||
}
|
||||
const Group::MemberSlotList members = group->GetMemberSlots();
|
||||
for (const auto &memberSlot : members) {
|
||||
Player* player = ObjectAccessor::FindPlayer(memberSlot.guid);
|
||||
if (player) {
|
||||
|
||||
DBUpdatePlayerInstanceData(player->GetGUID(), groupData.difficulty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MpGroupData* MpDataStore::GetGroupData(Group* group) {
|
||||
@@ -61,7 +130,7 @@ void MpDataStore::PushGroupInstanceKey(Group *group, uint32 mapId, uint32 instan
|
||||
return;
|
||||
}
|
||||
|
||||
_groupData->at(guid).instanceDataKeys.push_back(GetInstanceDataKey(mapId, instanceId));
|
||||
// Need to potentialy reset here?
|
||||
}
|
||||
|
||||
// This clears out any group data from memory and the database
|
||||
@@ -72,9 +141,10 @@ void MpDataStore::RemoveGroupData(Group *group) {
|
||||
CharacterDatabase.Execute("DELETE FROM group_difficulty WHERE guid = {}) ", group->GetGUID().GetCounter());
|
||||
}
|
||||
|
||||
void MpDataStore::AddPlayerData(ObjectGuid guid, MpPlayerData pd) {
|
||||
MpLogger::debug("AddPlayerData for player {}", guid.GetCounter());
|
||||
// Adds PlayerData related to MythicRun Status to map
|
||||
void MpDataStore::AddPlayerData(ObjectGuid guid, MpPlayerData* pd) {
|
||||
_playerData->emplace(guid, pd);
|
||||
|
||||
}
|
||||
|
||||
void MpDataStore::RemovePlayerData(ObjectGuid guid) {
|
||||
@@ -82,6 +152,11 @@ void MpDataStore::RemovePlayerData(ObjectGuid guid) {
|
||||
_playerData->erase(guid);
|
||||
}
|
||||
|
||||
void MpDataStore::ResetPlayerData(ObjectGuid guid) {
|
||||
MpLogger::debug("ResetPlayerData for player {}", guid.GetCounter());
|
||||
_playerData->erase(guid);
|
||||
}
|
||||
|
||||
void MpDataStore::AddInstanceData(uint32 mapId, uint32 instanceId, MpInstanceData instanceSettings) {
|
||||
_instanceData->emplace(GetInstanceDataKey(mapId, instanceId), instanceSettings);
|
||||
}
|
||||
@@ -100,7 +175,7 @@ void MpDataStore::RemoveInstanceData(uint32 mapId, uint32 instanceId) {
|
||||
}
|
||||
|
||||
void MpDataStore::AddCreatureData(ObjectGuid guid, MpCreatureData creatureData) {
|
||||
MpLogger::debug("AddInstanceCreatureData for creature {}", guid.GetCounter());
|
||||
// MpLogger::debug("AddInstanceCreatureData for creature {}", guid.GetCounter());
|
||||
_instanceCreatureData->emplace(guid, creatureData);
|
||||
}
|
||||
|
||||
@@ -112,6 +187,18 @@ MpCreatureData* MpDataStore::GetCreatureData(ObjectGuid guid) {
|
||||
return &_instanceCreatureData->at(guid);
|
||||
}
|
||||
|
||||
std::vector<MpCreatureData*> MpDataStore::GetInstanceCreatures(uint32 mapId, uint32 instanceId) {
|
||||
std::vector<MpCreatureData*> creatures;
|
||||
for (auto& [guid, creatureData] : *_instanceCreatureData) {
|
||||
Creature* creature = creatureData.creature;
|
||||
|
||||
if (creature->GetMapId() == mapId && creature->GetInstanceId() == instanceId) {
|
||||
creatures.push_back(&creatureData);
|
||||
}
|
||||
}
|
||||
return creatures;
|
||||
}
|
||||
|
||||
std::vector<MpCreatureData*> MpDataStore::GetUnscaledCreatures(uint32 mapId, uint32 instanceId) {
|
||||
std::vector<MpCreatureData*> creatures;
|
||||
for (auto& [guid, creatureData] : *_instanceCreatureData) {
|
||||
@@ -151,13 +238,41 @@ int32 MpDataStore::GetDamageScaleFactor(int32 mapId, int32 difficulty) const {
|
||||
return GetScaleFactor(mapId, difficulty).dmgBonus;
|
||||
}
|
||||
|
||||
int32 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;
|
||||
}
|
||||
|
||||
void MpDataStore::SetHealthScaleFactor(int32 mapId, int32 difficulty, int32 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) {
|
||||
auto key = GetScaleFactorKey(mapId, difficulty);
|
||||
|
||||
if (_scaleFactors && _scaleFactors->contains(key)) {
|
||||
_scaleFactors->at(key).dmgBonus = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
void MpDataStore::SetSpellScaleFactor(int32 mapId, int32 difficulty, int32 newValue) {
|
||||
auto key = GetScaleFactorKey(mapId, difficulty);
|
||||
if (_scaleFactors && _scaleFactors->contains(key)) {
|
||||
_scaleFactors->at(key).spellBonus = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
int32 MpDataStore::LoadScaleFactors() {
|
||||
// 0 1 2 3 4
|
||||
QueryResult result = WorldDatabase.Query("SELECT mapId, dmg_bonus, hp_bonus, difficulty, max FROM mythic_plus_scale_factors");
|
||||
_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");
|
||||
if (!result) {
|
||||
MpLogger::error("Failed to load mythic scale factors from database");
|
||||
return 0;
|
||||
@@ -167,22 +282,180 @@ int32 MpDataStore::LoadScaleFactors() {
|
||||
Field* fields = result->Fetch();
|
||||
uint32 mapId = fields[0].Get<uint32>();
|
||||
int32 damageBonus = fields[1].Get<int32>();
|
||||
int32 healthBonus = fields[2].Get<int32>();
|
||||
int32 difficulty = fields[3].Get<int32>();
|
||||
int32 maxDamageBonus = fields[4].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>();
|
||||
|
||||
MpScaleFactor scaleFactor = {
|
||||
.dmgBonus = damageBonus,
|
||||
.healthBonus = healthBonus,
|
||||
.spellBonus = spellBonus,
|
||||
.maxDamageBonus = maxDamageBonus
|
||||
};
|
||||
|
||||
_mutableScaleFactors->emplace(GetScaleFactorKey(mapId, difficulty), scaleFactor);
|
||||
_scaleFactors->emplace(GetScaleFactorKey(mapId, difficulty), scaleFactor);
|
||||
|
||||
} while (result->NextRow());
|
||||
|
||||
// move to const map one loaded so can not be changed after
|
||||
_scaleFactors = std::move(_mutableScaleFactors);
|
||||
|
||||
return int32(_scaleFactors->size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Database Calls below for storing player data.
|
||||
* @todo refactor to use prepared statements
|
||||
*/
|
||||
void MpDataStore::DBUpdatePlayerInstanceData(ObjectGuid playerGuid, MpDifficulty difficulty, uint32 mapId, uint32 instanceId, uint32 deaths) {
|
||||
if (!playerGuid) {
|
||||
MpLogger::error("DBAddPlayerData called with invalid playerData");
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterDatabase.Execute("REPLACE INTO mp_player_instance_data (guid, difficulty, mapId, instanceId, deaths) VALUES ({},{},{},{},{}) ",
|
||||
playerGuid.GetCounter(),
|
||||
difficulty,
|
||||
mapId,
|
||||
instanceId,
|
||||
deaths
|
||||
);
|
||||
}
|
||||
|
||||
void MpDataStore::DBResetPlayerDeaths(Player* player) {
|
||||
if (!player) {
|
||||
MpLogger::error("DBUpdateDeaths called with invalid playerId");
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterDatabase.Execute("UPDATE mp_player_instance_data SET deaths = 0 WHERE guid = {} and mapId = {} and instanceId = {}",
|
||||
player->GetGUID().GetCounter(),
|
||||
player->GetMapId(),
|
||||
player->GetInstanceId()
|
||||
);
|
||||
}
|
||||
|
||||
void MpDataStore::DBAddPlayerDeath(Player* player) {
|
||||
if (!player) {
|
||||
MpLogger::error("DBAddPlayerDeath called with invalid player");
|
||||
return;
|
||||
}
|
||||
CharacterDatabase.Execute("UPDATE mp_player_instance_data SET deaths = deaths + 1 WHERE guid = {} and mapId = {} and instanceId = {}",
|
||||
player->GetGUID().GetCounter(),
|
||||
player->GetMapId(),
|
||||
player->GetInstanceId()
|
||||
);
|
||||
}
|
||||
|
||||
// Logs death for player that occurs by a creature directly.
|
||||
void MpDataStore::DBAddPlayerDeath(Player* player, Creature* creature, MpDifficulty difficulty) {
|
||||
if (!player) {
|
||||
MpLogger::error("DBAddPlayerDeath called with invalid player");
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterDatabase.Execute("UPDATE mp_player_instance_data SET deaths = deaths + 1 WHERE guid = {} and mapId = {} and instanceId = {}",
|
||||
player->GetGUID().GetCounter(),
|
||||
player->GetMapId(),
|
||||
player->GetInstanceId()
|
||||
);
|
||||
|
||||
CharacterDatabase.Execute(
|
||||
"INSERT INTO mp_player_death_stats (guid, creatureEntry, difficulty, numDeaths, lastUpdated) "
|
||||
"VALUES ({}, {}, {}, 1, CURRENT_TIMESTAMP) "
|
||||
"ON DUPLICATE KEY UPDATE numDeaths = numDeaths + 1, lastUpdated = CURRENT_TIMESTAMP",
|
||||
player->GetGUID().GetCounter(),
|
||||
creature->GetEntry(),
|
||||
difficulty
|
||||
);
|
||||
}
|
||||
|
||||
void MpDataStore::DBUpdateGroupData(ObjectGuid groupGuid, MpDifficulty difficulty, uint32 mapId, uint32 instanceId, uint32 deaths) {
|
||||
if (!groupGuid) {
|
||||
MpLogger::error("DBUpdateGroupData called with invalid groupGuid");
|
||||
return;
|
||||
}
|
||||
CharacterDatabase.Execute("REPLACE INTO mp_group_data (groupId, difficulty, mapId, instanceId, deaths) VALUES ({},{},{},{},{}) ",
|
||||
groupGuid.GetCounter(),
|
||||
difficulty,
|
||||
mapId,
|
||||
instanceId,
|
||||
deaths
|
||||
);
|
||||
}
|
||||
|
||||
void MpDataStore::DBAddGroupDeath(Group* group, uint32 mapId, uint32 instanceId, MpDifficulty difficulty) {
|
||||
if (!group) {
|
||||
MpLogger::error("DBAddGroupDeath called with invalid group");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!difficulty) {
|
||||
MpLogger::error("DBAddGroupDeath called with invalid difficulty");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!mapId || !instanceId) {
|
||||
MpLogger::error("DBAddGroupDeath called with invalid mapId or instanceId");
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterDatabase.Execute("UPDATE mp_group_data SET deaths = deaths + 1 WHERE groupId = {} and mapId = {} and instanceId = {} and difficulty = {}",
|
||||
group->GetGUID().GetCounter(),
|
||||
mapId,
|
||||
instanceId,
|
||||
difficulty
|
||||
);
|
||||
}
|
||||
|
||||
void MpDataStore::DBRemovePlayerData(ObjectGuid playerGuid) {
|
||||
if (!playerGuid) {
|
||||
MpLogger::error("DBRemovePlayerData called with invalid playerGuid");
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterDatabase.Execute("DELETE FROM mp_player_instance_data WHERE guid = {} ", playerGuid.GetCounter());
|
||||
}
|
||||
|
||||
void MpDataStore::DBRemovePlayerInstanceData(uint32 instanceId) {
|
||||
if (!instanceId) {
|
||||
MpLogger::error("DBRemovePlayerInstanceData: missing instanceId to remove player instance ");
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterDatabase.Execute("DELETE FROM mp_player_instance_data WHERE instanceId = {} ", instanceId);
|
||||
}
|
||||
|
||||
|
||||
void MpDataStore::DBUpdateGroupTimerDeaths(ObjectGuid groupGuid, uint32 mapId, uint32 instanceId, uint32 timer, uint32 deaths) {
|
||||
if (!groupGuid) {
|
||||
MpLogger::error("DBUpdateGroupTimerDeaths called with invalid groupGuid");
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterDatabase.Execute("REPLACE INTO mp_group_data (groupId, mapId, instanceId, instanceTimer, deaths) VALUES ({},{},{},{},{}) ",
|
||||
groupGuid.GetCounter(),
|
||||
mapId,
|
||||
instanceId,
|
||||
timer,
|
||||
deaths
|
||||
);
|
||||
}
|
||||
|
||||
void MpDataStore::DBRemoveGroupData(ObjectGuid groupGuid) {
|
||||
if (!groupGuid) {
|
||||
MpLogger::error("DBRemoveGroupData called with invalid groupGuid");
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterDatabase.Execute("DELETE FROM mp_group_data WHERE groupId = {} ", groupGuid.GetCounter());
|
||||
}
|
||||
|
||||
// Remove instance data using the instanceId
|
||||
void MpDataStore::DBRemoveGroupInstanceData(uint32 instanceId) {
|
||||
if (!instanceId) {
|
||||
MpLogger::error("DBRemoveGroupData called with invalid groupGuid");
|
||||
return;
|
||||
}
|
||||
|
||||
CharacterDatabase.Execute("DELETE FROM mp_group_data WHERE instanceId = {} ", instanceId);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
#define MYTHICPLUS_DATASTORE_H
|
||||
|
||||
#include "Creature.h"
|
||||
// #include "CreatureOverride.h"
|
||||
#include "Group.h"
|
||||
#include "MapMgr.h"
|
||||
#include "Player.h"
|
||||
#include "MpLogger.h"
|
||||
#include "ObjectGuid.h"
|
||||
|
||||
#include <unordered_map>
|
||||
@@ -13,7 +15,8 @@
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
enum MpDifficulty {
|
||||
enum MpDifficulty
|
||||
{
|
||||
MP_DIFFICULTY_NORMAL = 0,
|
||||
MP_DIFFICULTY_HEROIC = 1,
|
||||
MP_DIFFICULTY_EPIC = 2,
|
||||
@@ -21,22 +24,118 @@ enum MpDifficulty {
|
||||
MP_DIFFICULTY_LEGENDARY = 4,
|
||||
MP_DIFFICULTY_ASCENDANT = 5
|
||||
};
|
||||
|
||||
class MpDataStore;
|
||||
|
||||
struct MpPlayerInstanceData
|
||||
{
|
||||
uint32 deaths = 0;
|
||||
};
|
||||
|
||||
// struct used to track player performance in an instance.
|
||||
struct MpPlayerData
|
||||
{
|
||||
Player* player;
|
||||
MpDifficulty difficulty;
|
||||
uint32 groupId;
|
||||
|
||||
// list of maps and instance player is bound to and mythic data related to it
|
||||
std::map<std::pair<uint32,uint32>,MpPlayerInstanceData> instanceData;
|
||||
|
||||
MpPlayerData(Player* p, MpDifficulty diff, uint32_t groupId)
|
||||
: player(p), difficulty(diff), groupId(groupId) {
|
||||
}
|
||||
|
||||
void AddDeath(uint32 mapId, uint32 instanceId) {
|
||||
auto key = std::make_pair(mapId, instanceId);
|
||||
|
||||
if(instanceData.contains(key)) {
|
||||
instanceData[key].deaths++;
|
||||
} else {
|
||||
instanceData[key] = MpPlayerInstanceData{.deaths = 1};
|
||||
}
|
||||
|
||||
MpLogger::info("========= Player {} added death to instance data {}", player->GetName(), instanceData[key].deaths);
|
||||
}
|
||||
|
||||
uint32 GetDeaths(uint32 mapId, uint32 instanceId) const {
|
||||
auto key = std::make_pair(mapId, instanceId);
|
||||
if(instanceData.contains(key)) {
|
||||
return instanceData.at(key).deaths;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ResetDeathCount(uint32 mapId, uint32 instanceId) {
|
||||
auto key = std::make_pair(mapId, instanceId);
|
||||
if(instanceData.contains(key)) {
|
||||
instanceData[key].deaths = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ResetAllDeathCounts() {
|
||||
for(auto& [key, data] : instanceData) {
|
||||
data.deaths = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Struct used to track entire group performance.
|
||||
struct MpGroupData
|
||||
{
|
||||
Group* group;
|
||||
MpDifficulty difficulty;
|
||||
uint32 deaths;
|
||||
std::vector<MpPlayerData*> players;
|
||||
|
||||
|
||||
MpGroupData() : group(nullptr), difficulty(MpDifficulty{}) {
|
||||
players.reserve(5);
|
||||
|
||||
std::vector<std::pair<uint32,uint32>> instanceDataKeys;
|
||||
MpGroupData() : group(nullptr), difficulty(MpDifficulty{}), deaths(0) {
|
||||
instanceDataKeys.reserve(32);
|
||||
}
|
||||
MpGroupData(Group* group, MpDifficulty difficulty, uint32 deaths)
|
||||
: group(group), difficulty(difficulty), deaths(deaths) {
|
||||
instanceDataKeys.reserve(32);
|
||||
|
||||
MpGroupData(Group* group, MpDifficulty difficulty)
|
||||
: group(group), difficulty(difficulty) {
|
||||
players.reserve(5);
|
||||
}
|
||||
|
||||
uint32 GetDeaths(uint32 mapId, uint32 instanceId) const {
|
||||
uint32 deaths = 0;
|
||||
for (const MpPlayerData* player : players) {
|
||||
deaths += player->GetDeaths(mapId, instanceId);
|
||||
}
|
||||
return deaths;
|
||||
}
|
||||
|
||||
void ResetGroupDeaths(uint32 mapId, uint32 instanceId) {
|
||||
for (MpPlayerData* player : players) {
|
||||
player->ResetDeathCount(mapId, instanceId);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void AddPlayerData(MpPlayerData* playerData) {
|
||||
// Check if the playerData is already in the vector
|
||||
if (std::any_of(players.begin(), players.end(), [playerData](MpPlayerData* existingData) {
|
||||
return existingData->player == playerData->player;
|
||||
})) {
|
||||
|
||||
MpLogger::warn("PlayerData for player {} is already in the players vector", playerData->player->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
// Add playerData to the vector
|
||||
players.push_back(playerData);
|
||||
}
|
||||
|
||||
std::string ToString() const {
|
||||
Map* map = group->GetLeader()->GetMap();
|
||||
|
||||
uint32 deaths = 0;
|
||||
if(map) {
|
||||
deaths = GetDeaths(map->GetId(), map->GetInstanceId());
|
||||
}
|
||||
|
||||
return "MpGroupData: { group: " + std::to_string(group->GetGUID().GetCounter()) +
|
||||
", difficulty: " + std::to_string(difficulty) +
|
||||
", deaths: " + std::to_string(deaths) + " }";
|
||||
@@ -44,23 +143,17 @@ struct MpGroupData
|
||||
|
||||
};
|
||||
|
||||
struct MpPlayerData
|
||||
{
|
||||
Player* player;
|
||||
uint8 difficulty;
|
||||
uint32 deaths;
|
||||
};
|
||||
|
||||
struct MpScaleFactor
|
||||
{
|
||||
int32 dmgBonus;
|
||||
int32 healthBonus;
|
||||
int32 spellBonus;
|
||||
int32 maxDamageBonus;
|
||||
|
||||
std::string ToString() const {
|
||||
return "MpScaleFactor: { dmgBonus: " + std::to_string(dmgBonus) +
|
||||
", healthBonus: " + std::to_string(healthBonus) +
|
||||
", maxDamageBonus: " + std::to_string(maxDamageBonus) + " }";
|
||||
", spellBonus: " + std::to_string(spellBonus) + "}";
|
||||
}
|
||||
|
||||
};
|
||||
@@ -110,8 +203,6 @@ struct MpInstanceData
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Simple struct for managing information about creatures that
|
||||
* are in a mythic+ instance.
|
||||
@@ -121,9 +212,17 @@ struct MpCreatureData
|
||||
Creature* creature;
|
||||
bool scaled;
|
||||
|
||||
// AttackPower calculated based on settings
|
||||
uint32 NewAttackPower;
|
||||
|
||||
// New Scaling Multiplier based on database factors + level growth formula
|
||||
float AttackPowerScaleMultiplier;
|
||||
|
||||
// Original information about the creature that was altered.
|
||||
uint8 originalLevel;
|
||||
|
||||
CreatureBaseStats const* originalStats;
|
||||
MpDifficulty difficulty;
|
||||
|
||||
// Custom difficulty modifiers to creatures at higher difficulties.
|
||||
std::vector<uint32> auras;
|
||||
@@ -148,30 +247,69 @@ struct MpCreatureData
|
||||
this->scaled = scaled;
|
||||
}
|
||||
|
||||
void SetDifficulty(MpDifficulty difficulty) {
|
||||
this->difficulty = difficulty;
|
||||
}
|
||||
|
||||
bool IsScaled() {
|
||||
return scaled;
|
||||
}
|
||||
|
||||
std::string ToString() const {
|
||||
|
||||
std::string origStatsStr;
|
||||
if(originalStats) {
|
||||
uint32 health = *originalStats->BaseHealth;
|
||||
uint32 mana = originalStats->BaseMana;
|
||||
uint32 armor = originalStats->BaseArmor;
|
||||
uint32 ap = originalStats->AttackPower;
|
||||
|
||||
origStatsStr = "Original Stats: \n Health: " + std::to_string(health) + "\n" +
|
||||
"Mana: " + std::to_string(mana) + "\n" +
|
||||
"Armor: " + std::to_string(armor) + "\n" +
|
||||
"Attack Power: " + std::to_string(ap) + "\n";
|
||||
|
||||
} else {
|
||||
origStatsStr = "Original Stats Display Failed: \n Did you select target or in an non-scaled instance? \n";
|
||||
}
|
||||
|
||||
|
||||
|
||||
return " MpCreatureData: \n Original level: " + std::to_string(originalLevel) + "\n" +
|
||||
origStatsStr +
|
||||
" NewAttackPower: " + std::to_string(NewAttackPower) + "\n" +
|
||||
" AttackPowerScaleMultiplier: " + std::to_string(AttackPowerScaleMultiplier) + "\n" +
|
||||
" Difficulty: " + std::to_string(difficulty) + "\n" +
|
||||
" Scaled: " + (scaled ? "true" : "false") + "\n";
|
||||
}
|
||||
|
||||
/**@todo Add Affixes and Aura Spell methods */
|
||||
};
|
||||
|
||||
class MpDataStore {
|
||||
class MpDataStore
|
||||
{
|
||||
private:
|
||||
MpDataStore()
|
||||
: _playerData(std::make_unique<std::unordered_map<ObjectGuid, MpPlayerData>>()),
|
||||
: _playerData(std::make_unique<std::unordered_map<ObjectGuid, MpPlayerData*>>()),
|
||||
_instanceData(std::make_unique<std::map<std::pair<uint32, uint32>, MpInstanceData>>()),
|
||||
_groupData(std::make_unique<std::unordered_map<ObjectGuid, MpGroupData>>()),
|
||||
_instanceCreatureData(std::make_unique<std::unordered_map<ObjectGuid, MpCreatureData>>()),
|
||||
_mutableScaleFactors(std::make_unique<std::map<std::pair<int32, int32>,MpScaleFactor>>())
|
||||
_scaleFactors(std::make_unique<std::map<std::pair<int32, int32>,MpScaleFactor>>())
|
||||
{
|
||||
_playerData->reserve(32);
|
||||
_groupData->reserve(32);
|
||||
_instanceCreatureData->reserve(500);
|
||||
};
|
||||
|
||||
inline ~MpDataStore() {}
|
||||
inline ~MpDataStore() {
|
||||
for (auto& [guid, playerData] : *_playerData) {
|
||||
delete playerData;
|
||||
}
|
||||
|
||||
std::unique_ptr<std::unordered_map<ObjectGuid, MpPlayerData>> _playerData;
|
||||
_playerData->clear();
|
||||
}
|
||||
|
||||
std::unique_ptr<std::unordered_map<ObjectGuid, MpPlayerData*>> _playerData;
|
||||
|
||||
// Instance data containes information about how to scale creatures
|
||||
std::unique_ptr<std::map<std::pair<uint32,uint32>,MpInstanceData>> _instanceData; // {mapId,instanceId}
|
||||
@@ -183,9 +321,10 @@ private:
|
||||
std::unique_ptr<std::unordered_map<ObjectGuid, MpCreatureData>> _instanceCreatureData;
|
||||
|
||||
// use to mimic pattern normals scale to heroic (loaded at server start)
|
||||
std::unique_ptr<std::map<std::pair<int32,int32>,MpScaleFactor>> _mutableScaleFactors; // {mapId,difficulty}
|
||||
std::unique_ptr<const std::map<std::pair<int32,int32>,MpScaleFactor>> _scaleFactors; // {mapId,difficulty}
|
||||
std::unique_ptr<std::map<std::pair<int32,int32>,MpScaleFactor>> _scaleFactors; // {mapId,difficulty}
|
||||
|
||||
// Single creature multipliers used to scale creatures individually that may need tuned up or down.
|
||||
// std::unique_ptr<std::unordered_map<uint32, CreatureOverride>> _creatureOverrides;
|
||||
|
||||
public:
|
||||
|
||||
@@ -193,15 +332,15 @@ public:
|
||||
MpDataStore(const MpDataStore&) = delete;
|
||||
MpDataStore& operator=(const MpDataStore&) = delete;
|
||||
|
||||
const MpPlayerData* GetPlayerData(ObjectGuid guid) const {
|
||||
MpPlayerData* GetPlayerData(ObjectGuid guid) {
|
||||
try {
|
||||
return &_playerData->at(guid);
|
||||
return _playerData->at(guid);
|
||||
} catch (const std::out_of_range& oor) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const MpGroupData* GetGroupData(ObjectGuid guid) const {
|
||||
MpGroupData* GetGroupData(ObjectGuid guid) {
|
||||
|
||||
if (_groupData->contains(guid)) {
|
||||
return &_groupData->at(guid);
|
||||
@@ -210,7 +349,7 @@ public:
|
||||
}
|
||||
|
||||
}
|
||||
const MpGroupData* GetGroupData(Player *player) const {
|
||||
MpGroupData* GetGroupData(Player *player) {
|
||||
return GetGroupData(player->GetGroup()->GetGUID());
|
||||
};
|
||||
|
||||
@@ -220,8 +359,10 @@ public:
|
||||
MpGroupData* GetGroupData(Group *group);
|
||||
void PushGroupInstanceKey(Group *group, uint32 mapId, uint32 instanceId);
|
||||
|
||||
void AddPlayerData(ObjectGuid guid, MpPlayerData pd);
|
||||
// Data related to player settings and stags
|
||||
void AddPlayerData(ObjectGuid guid, MpPlayerData* pd);
|
||||
void RemovePlayerData(ObjectGuid guid);
|
||||
void ResetPlayerData(ObjectGuid guid);
|
||||
|
||||
// Each Map/Instance is a unique key that contains scaling information based on difficulty
|
||||
void AddInstanceData(uint32 mapId, uint32 instanceId, MpInstanceData );
|
||||
@@ -232,14 +373,24 @@ public:
|
||||
void AddCreatureData(ObjectGuid guid, MpCreatureData creatureData);
|
||||
MpCreatureData* GetCreatureData(ObjectGuid guid);
|
||||
void RemoveCreatureData(ObjectGuid guid);
|
||||
std::vector<MpCreatureData*> GetInstanceCreatures(uint32 mapId, uint32 instanceId);
|
||||
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;
|
||||
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);
|
||||
|
||||
// Individual Creature Scaling Multipliers
|
||||
// void AddCreatureOverride(uint32 entry, CreatureOverride* override);
|
||||
// MpMultipliers* GetCreatureOverride(uint32 entry);
|
||||
|
||||
auto GetInstanceDataKey(uint32 mapId, uint32 instanceId) const {
|
||||
return std::make_pair(mapId, instanceId);
|
||||
}
|
||||
@@ -250,6 +401,23 @@ public:
|
||||
// Used at initial server load
|
||||
int32 LoadScaleFactors();
|
||||
|
||||
// Database API calls
|
||||
void DBUpdatePlayerInstanceData(ObjectGuid playerGuid, MpDifficulty difficulty, uint32 mapId = 0, uint32 instanceId = 0, uint32 deaths = 0);
|
||||
|
||||
void DBResetPlayerDeaths(Player* player);
|
||||
void DBAddPlayerDeath(Player* player, Creature* killer, MpDifficulty difficulty);
|
||||
void DBAddPlayerDeath(Player* player);
|
||||
|
||||
void DBRemovePlayerData(ObjectGuid playerGuid);
|
||||
void DBRemovePlayerInstanceData(uint32 instanceId);
|
||||
void DBRemoveGroupInstanceData(uint32 instanceId);
|
||||
void DBUpdateGroupData(ObjectGuid groupGuid, MpDifficulty difficulty, uint32 mapId, uint32 instanceId, uint32 deaths);
|
||||
void DBUpdateGroupTimerDeaths(ObjectGuid groupGuid, uint32 mapId, uint32 instanceId, uint32 timer, uint32 deaths);
|
||||
void DBRemoveGroupData(ObjectGuid groupGuid);
|
||||
void DBAddGroupDeath(Group* group, uint32 mapId, uint32 instanceId, MpDifficulty difficulty);
|
||||
|
||||
//SavePlayerDungeonStats(Group* group, MpGroupData const* groupData);
|
||||
|
||||
static MpDataStore* instance() {
|
||||
static MpDataStore instance;
|
||||
return &instance;
|
||||
|
||||
61
src/MpScheduler.h
Normal file
61
src/MpScheduler.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef MYTHICPLUS_SCHEDULER_H
|
||||
#define MYTHICPLUS_SCHEDULER_H
|
||||
|
||||
#include "MpLogger.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "TaskScheduler.h"
|
||||
#include <chrono>
|
||||
|
||||
enum MP_SCHEDULE_GROUP
|
||||
{
|
||||
MP_WORLD_TASK_GROUP = 100
|
||||
};
|
||||
|
||||
/**
|
||||
* Global scheduler specifically for handling events fired inside of mythic
|
||||
* scripts
|
||||
*
|
||||
* Example usage:
|
||||
* void ScheduleWorldTask(std::chrono::nanoseconds const& time, std::function<void (TaskContext)> task) {
|
||||
* sMpScheduler.Schedule(time, MP_WORLD_TASK_GROUP, [](TaskContext ctx) {
|
||||
* // do the things you want for Mp Task Group
|
||||
* return;
|
||||
* });
|
||||
* }
|
||||
*/
|
||||
class MpScheduler
|
||||
{
|
||||
public:
|
||||
static MpScheduler* instance () {
|
||||
static MpScheduler instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
MpScheduler(const MpScheduler&) = delete;
|
||||
MpScheduler& operator=(const MpScheduler&) = delete;
|
||||
|
||||
TaskScheduler& GetWorldScheduler() {
|
||||
return _worldScheduler;
|
||||
}
|
||||
|
||||
private:
|
||||
MpScheduler() {}
|
||||
~MpScheduler() {}
|
||||
|
||||
TaskScheduler _worldScheduler;
|
||||
};
|
||||
|
||||
#define sMpScheduler MpScheduler::instance()
|
||||
#endif // MYTHICPLUS_SCHEDULER_H
|
||||
|
||||
// Attach the world scheduler to listen to world events
|
||||
class MpScheduler_WorldScript : public WorldScript
|
||||
{
|
||||
public:
|
||||
MpScheduler_WorldScript() : WorldScript("MpScheduler_GlobalScript") { }
|
||||
|
||||
void OnUpdate(uint32 diff) override {
|
||||
sMpScheduler->GetWorldScheduler().Update(diff);
|
||||
}
|
||||
};
|
||||
|
||||
39
src/MpScriptAI.h
Normal file
39
src/MpScriptAI.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "Creature.h"
|
||||
#include "CreatureAI.h"
|
||||
// #include "CreatureHooks.h"
|
||||
#include "MpLogger.h"
|
||||
#include "MythicPlus.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "ScriptedCreature.h"
|
||||
|
||||
#ifdef _ELUNA_CREATURE_AI_H
|
||||
#include "ElunaCreatureAI.h"
|
||||
using BaseAI = ElunaCreatureAI;
|
||||
#else
|
||||
using BaseAI = ScriptedAI;
|
||||
#endif
|
||||
|
||||
class MpScriptAI : public BaseAI
|
||||
{
|
||||
MpDifficulty _difficulty;
|
||||
|
||||
public:
|
||||
MpScriptAI(Creature* creature, MpDifficulty difficulty) : BaseAI(creature) {
|
||||
_difficulty = difficulty;
|
||||
}
|
||||
|
||||
MpScriptAI(Creature* creature) : BaseAI(creature) {
|
||||
_difficulty = MpDifficulty::MP_DIFFICULTY_MYTHIC;
|
||||
}
|
||||
|
||||
void JustDied(Unit* killer) override {
|
||||
// sCreatureHooks->JustDied(me->ToCreature(), killer);
|
||||
BaseAI::JustDied(killer);
|
||||
}
|
||||
|
||||
void Reset() override {
|
||||
// sCreatureHooks->JustSpawned(me->ToCreature());
|
||||
|
||||
BaseAI::Reset();
|
||||
}
|
||||
};
|
||||
@@ -5,10 +5,16 @@
|
||||
#include "ScriptMgr.h"
|
||||
#include "Group.h"
|
||||
#include "Unit.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "UpdateMask.h"
|
||||
#include "MpScriptAI.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
// Special case for Headless Horseman Event
|
||||
const uint32 HEADLESS_HORSEMAN = 23682;
|
||||
|
||||
bool MythicPlus::IsMapEligible(Map* map)
|
||||
{
|
||||
if (!Enabled) {
|
||||
@@ -62,12 +68,15 @@ bool MythicPlus::EligibleHealTarget(Unit* target)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((target->IsPet() || target->IsSummon() || target->IsHunterPet()) && target->GetOwner()->IsNPCBot()) {
|
||||
// Null check for GetOwner to avoid dereferencing a null pointer
|
||||
if ((target->IsPet() || target->IsSummon() || target->IsHunterPet()) && target->GetOwner() && target->GetOwner()->IsNPCBot()) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(sMythicPlus->IsCreatureEligible(target->ToCreature())) {
|
||||
// Ensure target is a valid creature before checking eligibility
|
||||
Creature* creatureTarget = target->ToCreature();
|
||||
if (creatureTarget && sMythicPlus->IsCreatureEligible(creatureTarget)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -81,7 +90,6 @@ bool MythicPlus::EligibleDamageTarget(Unit* target)
|
||||
}
|
||||
|
||||
if (target->GetTypeId() == TYPEID_PLAYER) {
|
||||
MpLogger::debug("Target {} is a player", target->GetName());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -90,13 +98,13 @@ bool MythicPlus::EligibleDamageTarget(Unit* target)
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((target->IsPet() || target->IsSummon() || target->IsHunterPet()) && target->GetOwner()->IsNPCBot()) {
|
||||
if ((target->IsPet() || target->IsSummon() || target->IsHunterPet()) && target->GetOwner() && target->GetOwner()->IsNPCBot()) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
Creature* creature = target->ToCreature();
|
||||
if((creature->IsPet() || creature->IsSummon() || creature->IsHunterPet()) && creature->IsControlledByPlayer()) {
|
||||
if (creature && (creature->IsPet() || creature->IsSummon() || creature->IsHunterPet()) && creature->GetOwner() && creature->IsControlledByPlayer()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -105,40 +113,51 @@ bool MythicPlus::EligibleDamageTarget(Unit* target)
|
||||
|
||||
bool MythicPlus::IsCreatureEligible(Creature* creature)
|
||||
{
|
||||
if(!creature) {
|
||||
if (!creature) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string scriptName = creature->GetScriptName();
|
||||
if(scriptName.starts_with("boss_")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (creature->IsDungeonBoss()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (creature->GetEntry() == HEADLESS_HORSEMAN) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the creature is a pet or summon controlled by a player
|
||||
if ((creature->IsHunterPet() || creature->IsPet() || creature->IsSummon()) && creature->IsControlledByPlayer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip critters, totems, and triggers
|
||||
if (creature->IsCritter() || creature->IsTotem() || creature->IsTrigger()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
# if defined(MOD_PRESENT_NPCBOTS)
|
||||
#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());
|
||||
MpLogger::debug("Creature {} is an NPC Bot, do not scale", creature->GetName());
|
||||
return false;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// throw out NPCs
|
||||
if ((creature->IsVendor() ||
|
||||
creature->HasNpcFlag(UNIT_NPC_FLAG_GOSSIP) ||
|
||||
creature->HasNpcFlag(UNIT_NPC_FLAG_QUESTGIVER) ||
|
||||
creature->HasNpcFlag(UNIT_NPC_FLAG_TRAINER) ||
|
||||
creature->HasNpcFlag(UNIT_NPC_FLAG_TRAINER_PROFESSION) ||
|
||||
creature->HasNpcFlag(UNIT_NPC_FLAG_REPAIR) ||
|
||||
creature->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC) ||
|
||||
creature->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) &&
|
||||
(!creature->IsDungeonBoss())
|
||||
)
|
||||
// Check for NPC-related flags (vendor, gossip, quest giver, trainer, etc.)
|
||||
if ((creature->IsVendor() ||
|
||||
creature->HasNpcFlag(UNIT_NPC_FLAG_GOSSIP) ||
|
||||
creature->HasNpcFlag(UNIT_NPC_FLAG_QUESTGIVER) ||
|
||||
creature->HasNpcFlag(UNIT_NPC_FLAG_TRAINER) ||
|
||||
creature->HasNpcFlag(UNIT_NPC_FLAG_TRAINER_PROFESSION) ||
|
||||
creature->HasNpcFlag(UNIT_NPC_FLAG_REPAIR) ||
|
||||
creature->HasUnitFlag(UNIT_FLAG_IMMUNE_TO_PC) ||
|
||||
creature->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)) &&
|
||||
(!creature->IsDungeonBoss()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -153,25 +172,49 @@ void MythicPlus::AddCreatureForScaling(Creature* creature)
|
||||
}
|
||||
|
||||
sMpDataStore->AddCreatureData(creature->GetGUID(), MpCreatureData(creature));
|
||||
MpLogger::debug("Added creature {} to instance data for instance {}",
|
||||
creature->GetName(),
|
||||
creature->GetMap()->GetMapName()
|
||||
);
|
||||
// MpLogger::debug("Added creature {} to instance data for instance {}",
|
||||
// creature->GetName(),
|
||||
// creature->GetMap()->GetMapName()
|
||||
// );
|
||||
}
|
||||
|
||||
void MythicPlus::AddScaledCreature(Creature* creature, MpInstanceData* instanceData)
|
||||
{
|
||||
MpCreatureData creatureData = MpCreatureData(creature);
|
||||
sMpDataStore->AddCreatureData(creature->GetGUID(), creatureData);
|
||||
|
||||
// allow small variance in level for non-boss creatures
|
||||
uint8 level = uint8(urand(instanceData->creature.avgLevel - 1, instanceData->creature.avgLevel + 1));
|
||||
if(creature->IsDungeonBoss()) {
|
||||
if(creature->IsDungeonBoss() || creature->GetEntry() == 23682) {
|
||||
ScaleCreature(instanceData->boss.avgLevel, creature, &instanceData->boss, instanceData->difficulty);
|
||||
} else {
|
||||
ScaleCreature(level, creature, &instanceData->creature, instanceData->difficulty);
|
||||
}
|
||||
|
||||
MpCreatureData creatureData = MpCreatureData(creature);
|
||||
// Update AI now the creature has been scaled.
|
||||
// auto ai = new MpScriptAI(creature, instanceData->difficulty);
|
||||
// creature->SetAI(ai);
|
||||
|
||||
// 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);
|
||||
sMpDataStore->AddCreatureData(creature->GetGUID(), creatureData);
|
||||
creatureData.SetDifficulty(instanceData->difficulty);
|
||||
|
||||
// MpLogger::debug("Scaled Creature {} Entry {} Id {} level from {} to {}",
|
||||
// creature->GetName(),
|
||||
@@ -190,6 +233,14 @@ void MythicPlus::ScaleRemaining(Player* player, MpInstanceData* instanceData)
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Perform any memory cleanup when the creature is removed from the world and no longer needed.
|
||||
void MythicPlus::RemoveCreature(Creature* creature)
|
||||
{
|
||||
@@ -214,13 +265,7 @@ void MythicPlus::ScaleCreature(uint8 level, Creature* creature, MpMultipliers* m
|
||||
);
|
||||
|
||||
uint32 basehp = stats->BaseHealth[EXPANSION_WRATH_OF_THE_LICH_KING];
|
||||
uint32 health = CalculateNewHealth(cInfo, mapId, difficulty, basehp, multipliers->health);
|
||||
|
||||
MpLogger::debug("Creature {} base health scaled from {} to {}",
|
||||
creature->GetName(),
|
||||
basehp,
|
||||
health
|
||||
);
|
||||
uint32 health = CalculateNewHealth(creature, cInfo, mapId, difficulty, basehp, multipliers->health);
|
||||
|
||||
creature->SetCreateHealth(health);
|
||||
creature->SetMaxHealth(health);
|
||||
@@ -244,94 +289,158 @@ void MythicPlus::ScaleCreature(uint8 level, Creature* creature, MpMultipliers* m
|
||||
creature->SetModifierValue(UNIT_MOD_MANA, BASE_VALUE, (float)mana * 3.0f);
|
||||
}
|
||||
|
||||
// need to calcuate a new base weapon damage that makes sense for the level and class
|
||||
uint32 ap = stats->AttackPower;
|
||||
uint32 rangeAp = irand(115, 157);
|
||||
MpLogger::debug("Creature {} base attack power{}",
|
||||
creature->GetName(),
|
||||
ap
|
||||
);
|
||||
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);
|
||||
}
|
||||
|
||||
ap = pow(float(creature->GetLevel() / origLevel), 1.8f) * 1000;
|
||||
// Calculate the level difference
|
||||
float levelDifference = creature->GetLevel() - origLevel;
|
||||
|
||||
// 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);
|
||||
|
||||
MpCreatureData* creatureData = sMpDataStore->GetCreatureData(creature->GetGUID());
|
||||
if(creatureData) {
|
||||
creatureData->NewAttackPower = ap;
|
||||
creatureData->AttackPowerScaleMultiplier = scalingFactor;
|
||||
}
|
||||
|
||||
// Set scaled attack power
|
||||
creature->SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, ap);
|
||||
creature->SetModifierValue(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, rangeAp);
|
||||
|
||||
// This works out a bonus damage to apply to the mob using the database and original mod settings.
|
||||
// the thought behind this is some mobs in dungeons are intended to hit harder than others
|
||||
// so applying a flat bonus keeps the ratios the same but increases the overall difficulty.
|
||||
// Of course within reason.
|
||||
int32 damageBonus = sMpDataStore->GetDamageScaleFactor(mapId, difficulty);
|
||||
int32 maxBonus = sMpDataStore->GetMaxDamageScaleFactor(mapId, difficulty);
|
||||
float dmgMod = cInfo->DamageModifier + damageBonus;
|
||||
|
||||
// Allow bosses to scale as high as they want but limit non-bosses to a max bonus
|
||||
if(!creature->IsDungeonBoss() && damageBonus > maxBonus) {
|
||||
dmgMod = maxBonus;
|
||||
}
|
||||
float oldDmgModifier = creature->GetModifierValue(UNIT_MOD_DAMAGE_MAINHAND, BASE_VALUE);
|
||||
creature->SetModifierValue(UNIT_MOD_DAMAGE_MAINHAND,BASE_VALUE, dmgMod);
|
||||
creature->SetModifierValue(UNIT_MOD_DAMAGE_OFFHAND,BASE_VALUE, dmgMod*0.85f);
|
||||
creature->SetModifierValue(UNIT_MOD_DAMAGE_RANGED,BASE_VALUE, dmgMod);
|
||||
|
||||
MpLogger::debug("Creature new attack damage scaled from {} to {}",
|
||||
oldDmgModifier,
|
||||
dmgMod
|
||||
);
|
||||
// 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);
|
||||
|
||||
// Update all stats to apply the new damage values
|
||||
creature->UpdateAllStats();
|
||||
|
||||
// Scale up the armor with some variance also to make some tougher enemies in the mix
|
||||
uint32 armor = uint32(std::ceil(stats->BaseArmor * multipliers->armor * cInfo->ModArmor));
|
||||
creature->SetArmor(armor);
|
||||
|
||||
/**
|
||||
* @TODO: Explore scaling other variable stats and resistances on the creature type at a later date.
|
||||
*/
|
||||
// creature->SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, stats->AttackPower * multipliers->melee);
|
||||
// creature->SetModifierValue(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, stats->RangedAttackPower * multipliers->melee);
|
||||
}
|
||||
|
||||
int32 MythicPlus::ScaleDamageSpell(SpellInfo const * spellInfo, MpCreatureData* creatureData, Creature* creature, float damageMultiplier)
|
||||
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 0;
|
||||
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 0;
|
||||
return damage * damageMultiplier;
|
||||
}
|
||||
|
||||
if(!creature) {
|
||||
MpLogger::error("Invalid creature ScaleDamageSpell()");
|
||||
return 0;
|
||||
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;
|
||||
|
||||
// Calculate the scaling factor using the 1.8 exponent
|
||||
float scalingFactor = pow(float(creature->GetLevel() / originalLevel), 1.8f);
|
||||
auto effects = spellInfo->GetEffects();
|
||||
|
||||
// Loop through all spell effects to scale their base damage
|
||||
for (uint8 i = 0; i < effects.size(); ++i)
|
||||
{
|
||||
SpellEffectInfo effect = effects[i];
|
||||
totalDamage += effect.CalcValue(creature, nullptr,nullptr);
|
||||
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) {
|
||||
return damage;
|
||||
}
|
||||
|
||||
MpLogger::debug(" >>> Spell {} damage scaled from for spell New Damage: {} using: scaling Factor: {} and damage Multi: {}",spellInfo->SpellName[0], totalDamage, scalingFactor, damageMultiplier);
|
||||
|
||||
// Apply scaling factor and the set multiplier from the instance data
|
||||
totalDamage = int32(totalDamage * scalingFactor * damageMultiplier);
|
||||
|
||||
MpLogger::debug("Spell damage scaled from for spell New Damage: {}", totalDamage);
|
||||
// MpLogger::debug("Spell {} damage scaled from for spell New Damage: {} using: scaling Factor: {} and damage Multi: {}",spellInfo->SpellName[0], totalDamage, scalingFactor, damageMultiplier);
|
||||
return totalDamage;
|
||||
}
|
||||
|
||||
int32 MythicPlus::ScaleHealSpell(SpellInfo const * spellInfo, 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;
|
||||
@@ -347,26 +456,161 @@ int32 MythicPlus::ScaleHealSpell(SpellInfo const * spellInfo, MpCreatureData* cr
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!target) {
|
||||
MpLogger::error("Invalid target ScaleHealSpell()");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 originalHp = creatureData->originalStats->BaseHealth[EXPANSION_WRATH_OF_THE_LICH_KING];
|
||||
int32 currentHealth = creature->GetHealth();
|
||||
int32 totalHeal = 0;
|
||||
|
||||
auto effects = spellInfo->GetEffects();
|
||||
// Loop through all spell effects to scale their base healing
|
||||
for (uint8 i = 0; i < effects.size(); ++i)
|
||||
{
|
||||
SpellEffectInfo effect = effects[i];
|
||||
totalHeal += effect.CalcValue(creature, nullptr, target);
|
||||
MpLogger::debug(" >>> Spell {} effect {} value: {} by creature {}", spellInfo->SpellName[i], effects[i].Effect, heal, creature->GetName());
|
||||
}
|
||||
|
||||
// Apply scaling factor and the set multiplier from the instance data
|
||||
MpLogger::debug("Spell healing scaled from for spell New Damage: {}", totalHeal);
|
||||
return pow((totalHeal / originalHp) * currentHealth, 0.8f) * healMultiplier;
|
||||
int32 originalLevel = creatureData->originalLevel;
|
||||
|
||||
float levelDifference = creature->GetLevel() - originalLevel;
|
||||
float spellBonus = sMpDataStore->GetSpellScaleFactor(creature->GetMapId(), creature->GetInstanceId());
|
||||
|
||||
float scalingFactor = CalculateScaling(levelDifference, spellBonus, 2.5f);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 ---
|
||||
11519, /* Bazzalan Ragefire */
|
||||
639, /* Edwin VanCleef Deadmines */
|
||||
3654, /* Mutanus the Devourer Wailing Caverns */
|
||||
4275, /* Archmage Arugal Shadowfang Keep */
|
||||
1716, /* Bazil Thredd Stockades */
|
||||
4829, /* Aku'mai blackfathom Deeps */
|
||||
7800, /* Mekgineer Thermaplugg Gnomeregan */
|
||||
4421, /* Charlga Razorflank Razorfen Kraul */
|
||||
4543, /* Bloodmage Thalnos Scarlet Monastery */
|
||||
3975, /* Herod Scarlet Monastery */
|
||||
3977, /* High Inquisitor Whitemane Scarlet Monastery */
|
||||
7350, /* Amnennar the Coldbringer Razorfen Downs */
|
||||
2748, /* Archaedas Uldaman */
|
||||
7267, /* Chief Ukorz Sandscalp Zul'Farrak */
|
||||
12201, /* Princess Theradras Maraudon */
|
||||
5709, /* Shade of Eranikus Sunken Temple */
|
||||
9019, /* Emperor Dagran Thaurissan Blackrock Depths */
|
||||
9568, /* Overlord Wyrmthalak Lower Blackrock Spire */
|
||||
10363, /* General Drakkisath Upper Blackrock Spire */
|
||||
11492, /* alzzin the Wildshaper Dire Maul */
|
||||
11496, /* Immol'thar Dire Maul */
|
||||
11501, /* King Gordok Dire Maul */
|
||||
1853, /* Darkmaster Gandling Scholomance */
|
||||
10812, /* Grand Crusader Dathrohan Stratholme */
|
||||
10440, /* Baron Rivendare Stratholme */
|
||||
|
||||
// --- WoW Classic Raids ---
|
||||
11583, /* Nefarian Blackwing Lair */
|
||||
11502, /* Ragnaros Molten Core */
|
||||
14834, /* Hakkar Zul'Gurub */
|
||||
15727, /* C'Thun Temple of Ahn'Qiraj */
|
||||
15339, /* Ossirian the Unscarred Ruins of Ahn'Qiraj */
|
||||
|
||||
// --- The Burning Crusade ---
|
||||
17536, /* Nazan - Hellfire Ramparts Normal */
|
||||
17536, /* Nazan - Hellfire Ramparts Normal */
|
||||
17377, /* Kelidan the Breaker - Blood Furnace Normal */
|
||||
18607, /* Kelidan the Breaker - Blood Furnace Heroic */
|
||||
17942, /* Quagmirran - The Slave Pens Normal */
|
||||
19894, /* Quagmirran - The Slave Pens Heoric */
|
||||
17882, /* The Black Stalker - The Underbog Normal */
|
||||
20184, /* The Black Stalker - The Underbog Heroic */
|
||||
24420, /* The Black Stalker - The Underbog Heroic(2) */
|
||||
18344, /* Nexus-Prince Shaffar - Mana-Tombs Normal */
|
||||
20256, /* Nexus-Prince Shaffar - Mana-Tombs Heroic */
|
||||
18373, /* Exarch Maladaar - Auchenai Crypts Normal */
|
||||
20306, /* Exarch Maladaar - Auchenai Crypts Heoric */
|
||||
18096, /* Epoch Hunter - Old Hillsbrad Foothills Normal */
|
||||
20531, /* Epoch Hunter - Old Hillsbrad Foothills Heroic */
|
||||
18473, /* Talon King Ikiss - Sethekk Halls Normal */
|
||||
20706, /* Talon King Ikiss - Sethekk Halls Heroic */
|
||||
17798, /* Warlord Kalithresh - The Steamvault Normal */
|
||||
20633, /* Warlord Kalithresh - The Steamvault Heroic */
|
||||
18708, /* Murmur - Shadow Labyrinth Normal */
|
||||
20657, /* Murmur - Shadow Labyrinth Heroic */
|
||||
16808, /* Warchief Kargath Bladefist - The Shattered Halls Normal */
|
||||
20597, /* Warchief Kargath Bladefist - The Shattered Halls Heroic */
|
||||
17881, /* Aeonus - The Black Morass Normal */
|
||||
20737, /* Aeonus - The Black Morass Heroic */
|
||||
17977, /* Warp Splinter - The Botanica Normal */
|
||||
21582, /* Warp Splinter - The Botanica Heroic */
|
||||
19220, /* Pathaleon the Calculator - The Mechanar Normal */
|
||||
21537, /* Pathaleon the Calculator - The Mechanar Heroic */
|
||||
20912, /* Harbinger Skyriss - The Arcatraz Normal */
|
||||
21601, /* Harbinger Skyriss - The Arcatraz Heroic */
|
||||
19622, /* Kael'thas Sunstrider - Magisters' Terrace Normal */
|
||||
24857, /* Kael'thas Sunstrider - Magisters' Terrace Heroic */
|
||||
|
||||
// --- Burning Crusade Raids ---
|
||||
15690, /* Prince Malchezaar - Karazhan */
|
||||
23863, /* Zul'jin - Zul'Aman */
|
||||
19044, /* Gruul the Dragonkiller - Gruul's Lair */
|
||||
17257, /* Magtheridon - Magtheridon's Lair */
|
||||
21212, /* Lady Vashj - Serpentshrine Cavern */
|
||||
24664, /* Kael'thas Sunstrider - The Eye */
|
||||
24855, /* Kael'thas Sunstrider - The Eye */
|
||||
17968, /* Archimonde - Hyjal Summit */
|
||||
22917, /* Illidan Stormrage - Black Temple */
|
||||
25315, /* Kil'jaeden - Sunwell Plateau */
|
||||
|
||||
// --- Wrath of the Lich King ---
|
||||
23954, /* Ingvar the Plunderer - Utgarde Keep Normal */
|
||||
31673, /* Ingvar the Plunderer - Utgarde Keep Heroic */
|
||||
26861, /* King Ymiron - Utgarde Pinnacle Normal */
|
||||
30788, /* King Ymiron - Utgarde Pinnacle Heroic */
|
||||
26723, /* Keristrasza - The Nexus Normal */
|
||||
30540, /* Keristrasza - The Nexus Heroic */
|
||||
26632, /* The Prophet Tharon'ja - Drak'Tharon Keep Normal */
|
||||
31360, /* The Prophet Tharon'ja - Drak'Tharon Keep Heroic */
|
||||
27656, /* Ley-Guardian Eregos - The Oculus Normal */
|
||||
31561, /* Ley-Guardian Eregos - The Oculus Heroic */
|
||||
29311, /* Herald Volazj - Ahn'kahet: The Old Kingdom Normal */
|
||||
31464, /* Herald Volazj - Ahn'kahet: The Old Kingdom Heroic */
|
||||
29120, /* Anub'arak - Azjol-Nerub Normal */
|
||||
31610, /* Anub'arak - Azjol-Nerub Heroic */
|
||||
29306, /* Gal'darah - Gundrak Normal */
|
||||
31368, /* Gal'darah - Gundrak Heroic */
|
||||
26533, /* Mal'Ganis - Culling of Stratholme Normal */
|
||||
31217, /* Mal'Ganis - Culling of Stratholme Heroic */
|
||||
31134, /* Cyanigosa - Violet Hold Normal */
|
||||
31506, /* Cyanigosa - Violet Hold Heroic */
|
||||
27978, /* Sjonnir the Ironshaper - Halls of Stone Normal */
|
||||
31386, /* Sjonnir the Ironshaper - Halls of Stone Heroic */
|
||||
28923, /* Loken - Halls of Lightning Normal */
|
||||
31538, /* Loken - Halls of Lightning Heroic */
|
||||
35451, /* The Black Knight - Trial of the Champion Normal */
|
||||
35490, /* The Black Knight - Trial of the Champion Heroic */
|
||||
36502, /* Devourer of Souls - The Forge of Souls Normal */
|
||||
37677, /* Devourer of Souls - The Forge of Souls Heroic */
|
||||
36658, /* Scourgelord Tyrannus - Pit of Saron Normal */
|
||||
36938, /* Scourgelord Tyrannus - Pit of Saron Heroic */
|
||||
37226, /* The Lich King Encounter - Halls of Reflection Normal */
|
||||
39166, /* The Lich King Encounter - Halls of Reflection Heroic */
|
||||
|
||||
// --- Wrath of the Lich King Raids ---
|
||||
15990, /* Kel'Thuzad - Naxxramas */
|
||||
28859, /* Malygos - The Eye of Eternity */
|
||||
28860, /* Sartharion - Obsidian Sanctum */
|
||||
31125, /* Archavon the Stone Watcher - Vault of Archavon */
|
||||
33993, /* Emalon the Storm Watcher - Vault of Archavon */
|
||||
35013, /* Koralon the Flame Watcher - Vault of Archavon */
|
||||
38433, /* Toravon the Ice Watcher - Vault of Archavon */
|
||||
33288, /* Yogg-Saron - Ulduar */
|
||||
34564, /* Anub'arak - Trial of the Crusader */
|
||||
10184, /* Onyxia - Onyxia's Lair (re-released in Wrath) */
|
||||
36597, /* The Lich King - Icecrown Citadel */
|
||||
39863, /* Halion - Ruby Sanctum */
|
||||
};
|
||||
|
||||
return std::find(finalBosses.begin(), finalBosses.end(), creature->GetEntry()) != finalBosses.end();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -392,19 +636,38 @@ 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(CreatureTemplate const* cInfo, uint32 mapId, MpDifficulty difficulty, uint32 origHealth, float confHPMod)
|
||||
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;
|
||||
}
|
||||
|
||||
float healthVariation;
|
||||
|
||||
// if(creature->IsPet() || creature->IsSummon() || creature->IsTotem()) {
|
||||
// return origHealth;
|
||||
// }
|
||||
|
||||
int32 hpScaleFactor = sMpDataStore->GetHealthScaleFactor(mapId, difficulty);
|
||||
|
||||
// Add some variance to the healthpool so enemies are not all the same
|
||||
float healthVariation = frand(0.85f, 1.15f);
|
||||
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
|
||||
healthVariation = frand(1.0f, 1.05f);
|
||||
hpScaleFactor *= 0.65;
|
||||
} else {
|
||||
healthVariation = frand(1.0f, 1.1f);
|
||||
hpScaleFactor *= 0.55;
|
||||
}
|
||||
|
||||
float unitTypeMod = GetTypeHealthModifier(rank);
|
||||
uint32 basehp = uint32(std::ceil(origHealth * unitTypeMod * healthVariation));
|
||||
|
||||
int32 hpScaleFactor = sMpDataStore->GetHealthScaleFactor(mapId, difficulty);
|
||||
if(cInfo->ModHealth > 0.0f) {
|
||||
return uint32(basehp * (cInfo->ModHealth + hpScaleFactor) * confHPMod);
|
||||
} else {
|
||||
@@ -412,6 +675,12 @@ uint32 CalculateNewHealth(CreatureTemplate const* cInfo, uint32 mapId, MpDifficu
|
||||
}
|
||||
}
|
||||
|
||||
// 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));
|
||||
return scaling;
|
||||
}
|
||||
|
||||
float GetTypeDamageModifier(int32 Rank)
|
||||
{
|
||||
switch (Rank)
|
||||
@@ -430,3 +699,4 @@ float GetTypeDamageModifier(int32 Rank)
|
||||
return sWorld->getRate(RATE_CREATURE_ELITE_ELITE_DAMAGE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,25 @@
|
||||
#include "Player.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "Unit.h"
|
||||
#include "TaskScheduler.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
// Used to limit the total advancment rank and allow for changing the max rank in one place.
|
||||
inline const uint8 MP_MAX_ADVANCEMENT_RANK = 50;
|
||||
|
||||
/**
|
||||
* Main Class for the mod responsible for controls related to scaling instances,
|
||||
* handling logic related to setting up instances for MythicPlus to work.
|
||||
*
|
||||
* MpDataStore is heavily used as well for storing data in memory and interactions with
|
||||
* database storage.
|
||||
*
|
||||
* This is a singleton instance that can be accessed through sMythicPlus.
|
||||
*/
|
||||
class MythicPlus
|
||||
{
|
||||
public:
|
||||
@@ -56,6 +69,10 @@ public:
|
||||
uint32 legendaryItemOffset;
|
||||
uint32 ascendantItemOffset;
|
||||
|
||||
// Scaling modifiers
|
||||
uint32 meleeAttackPowerDampener;
|
||||
uint32 meleeAttackPowerStart;
|
||||
|
||||
enum MP_UNIT_EVENT_TYPE
|
||||
{
|
||||
UNIT_EVENT_MELEE,
|
||||
@@ -100,6 +117,9 @@ public:
|
||||
*/
|
||||
void ScaleRemaining(Player* player, MpInstanceData* instanceData);
|
||||
|
||||
// Rescales all creatures for an instance based on set data
|
||||
void ScaleAll(Player* player, MpInstanceData* instanceData);
|
||||
|
||||
// This will attempt to scale a creature using instancedata
|
||||
void AddScaledCreature(Creature* creature, MpInstanceData* instanceData);
|
||||
|
||||
@@ -107,10 +127,13 @@ public:
|
||||
void ScaleCreature(uint8 level, Creature* creature, MpMultipliers* multipliers, MpDifficulty difficulty);
|
||||
|
||||
// Scales a damage spell up based on the level increase
|
||||
int32 ScaleDamageSpell(SpellInfo const * spellInfo, MpCreatureData* creatureData, Creature* creature, float damageMultiplier);
|
||||
int32 ScaleDamageSpell(SpellInfo const * spellInfo, uint32 damage, MpCreatureData* creatureData, Creature* creature, Unit* target, float damageMultiplier);
|
||||
|
||||
// This scales a heal spell up based on the how much % the original heal spell was
|
||||
int32 ScaleHealSpell(SpellInfo const * spellInfo, MpCreatureData* creatureData, Creature* creature, Creature* target, float healMultiplier);
|
||||
int32 ScaleHealSpell(SpellInfo const * spellInfo, uint32 heal, MpCreatureData* creatureData, Creature* creature, Creature* target, float healMultiplier);
|
||||
|
||||
static bool IsFinalBoss(Creature* creature);
|
||||
static void GroupReset(Group* group, Map* map);
|
||||
|
||||
private:
|
||||
MythicPlus() { }
|
||||
@@ -119,7 +142,8 @@ public:
|
||||
|
||||
float GetTypeHealthModifier(int32 rank);
|
||||
float GetTypeDamageModifier(int32 rank);
|
||||
uint32 CalculateNewHealth(CreatureTemplate const* cInfo, uint32 mapId, MpDifficulty difficulty, uint32 origHealth, float confHPMod);
|
||||
float CalculateScaling(int levelDifference, float scaleFactor, float constant = 1.25f, float growthFactor = 20.0f);
|
||||
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()
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
#include "MpScheduler.h"
|
||||
#include "MpLogger.h"
|
||||
|
||||
// Creature Overrides
|
||||
enum {
|
||||
RAGEFIRE_BAZZALAN = 11519
|
||||
};
|
||||
|
||||
// This adds schedulers for use across scripts scoped to MythicPlus
|
||||
void Add_MP_Schedulers() {
|
||||
MpLogger::debug("Add_MP_Schedulers()");
|
||||
new MpScheduler_WorldScript();
|
||||
}
|
||||
|
||||
void Addmod_mythic_plusScripts();
|
||||
void Add_MP_AllCreatureScripts();
|
||||
@@ -8,15 +21,23 @@ void Add_MP_GroupScripts();
|
||||
void Add_MP_PlayerScripts();
|
||||
void Add_MP_UnitScripts();
|
||||
void Add_MP_WorldScripts();
|
||||
void Add_MP_PlayerMessageEvents();
|
||||
|
||||
void Addmod_mythic_plusScripts()
|
||||
{
|
||||
void Addmod_mythic_plusScripts() {
|
||||
Add_MP_AllCreatureScripts();
|
||||
Add_MP_AllMapScripts();
|
||||
Add_MP_CommandScripts();
|
||||
Add_MP_GlobalScripts();
|
||||
// Add_MP_GroupScripts();
|
||||
// Add_MP_PlayerScripts();
|
||||
Add_MP_PlayerScripts();
|
||||
Add_MP_UnitScripts();
|
||||
Add_MP_WorldScripts();
|
||||
Add_MP_Schedulers();
|
||||
Add_MP_PlayerMessageEvents();
|
||||
|
||||
// new Ragefire_Bazzalan_Mythic();
|
||||
|
||||
// list of boss / creature event handlers
|
||||
// new Ragefire_Bazzalan_Mythic(RAGEFIRE_BAZZALAN);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
#include "MpLogger.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
|
||||
class MythicPlus_PlayerScript : public PlayerScript
|
||||
{
|
||||
public:
|
||||
MythicPlus_PlayerScript() : PlayerScript("MythicPlus_PlayerScript") { }
|
||||
|
||||
};
|
||||
|
||||
void Add_MP_PlayerScripts()
|
||||
{
|
||||
MpLogger::debug("Add_MP_PlayerScripts()");
|
||||
new MythicPlus_PlayerScript();
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "CreatureAI.h"
|
||||
#include "MpDataStore.h"
|
||||
#include "MpLogger.h"
|
||||
#include "MythicPlus.h"
|
||||
#include "MpScriptAI.h"
|
||||
#include "ScriptMgr.h"
|
||||
|
||||
class MythicPlus_AllCreatureScript : public AllCreatureScript
|
||||
@@ -14,7 +14,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void OnCreateMap(Map* map) { }
|
||||
void OnCreateMap(Map* /*map*/) { }
|
||||
|
||||
/**
|
||||
* When a player enters the map check it needs to set up the instance data
|
||||
@@ -101,6 +101,11 @@ public:
|
||||
);
|
||||
sMpDataStore->AddInstanceData(map->GetId(), map->GetInstanceId(), instanceData);
|
||||
|
||||
// Save the instance data for the user to the database
|
||||
if (player) {
|
||||
sMpDataStore->DBUpdatePlayerInstanceData(player->GetGUID(), groupData->difficulty, map->GetId(), map->GetInstanceId(), 0);
|
||||
}
|
||||
|
||||
// Once we have instance data set we can scale the remaining characters in our instance
|
||||
sMythicPlus->ScaleRemaining(player, &instanceData);
|
||||
}
|
||||
@@ -111,7 +116,13 @@ public:
|
||||
if (!sMythicPlus->IsMapEligible(map)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Removes currenct GroupData Instance Data and removes from database storage
|
||||
sMpDataStore->RemoveInstanceData(map->GetId(), map->GetInstanceId());
|
||||
|
||||
// remove group instance and group instance data from database during a reset
|
||||
sMpDataStore->DBRemovePlayerInstanceData(map->GetInstanceId());
|
||||
sMpDataStore->DBRemoveGroupInstanceData(map->GetInstanceId());
|
||||
}
|
||||
};
|
||||
|
||||
391
src/Scripts/CommandScript.cpp
Normal file
391
src/Scripts/CommandScript.cpp
Normal file
@@ -0,0 +1,391 @@
|
||||
|
||||
#include "Chat.h"
|
||||
#include "MpDataStore.h"
|
||||
#include "MythicPlus.h"
|
||||
#include "MpDataStore.h"
|
||||
#include "MpLogger.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
|
||||
using namespace Acore::ChatCommands;
|
||||
|
||||
// make sure this is the new way to do this, i think it's the old busted shit
|
||||
class MythicPlus_CommandScript : public CommandScript
|
||||
{
|
||||
public:
|
||||
MythicPlus_CommandScript() : CommandScript("MythicPlus_CommandScript")
|
||||
{
|
||||
}
|
||||
|
||||
ChatCommandTable GetCommands() const override
|
||||
{
|
||||
static ChatCommandTable commandTableMain =
|
||||
{
|
||||
{"", HandleHelp, SEC_PLAYER, Console::No},
|
||||
{"status", HandleStatus, SEC_PLAYER, Console::No},
|
||||
{"set", HandleSetDifficulty, SEC_PLAYER, Console::No},
|
||||
{"disable", HandleDisable, SEC_ADMINISTRATOR, Console::Yes},
|
||||
{"enable", HandleEnable, SEC_ADMINISTRATOR, Console::Yes},
|
||||
{"rescale", HandleReScale, SEC_GAMEMASTER, Console::No},
|
||||
{"rescale all", HandleReScaleAll, SEC_GAMEMASTER, Console::No},
|
||||
{"change melee", HandleChangeMelee, SEC_ADMINISTRATOR, Console::Yes},
|
||||
{"change spell", HandleChangeSpell, SEC_ADMINISTRATOR, Console::Yes},
|
||||
{"change health", HandleChangeHealth, SEC_ADMINISTRATOR, Console::Yes}
|
||||
};
|
||||
|
||||
static ChatCommandTable commandTable =
|
||||
{
|
||||
{"mp", commandTableMain},
|
||||
{"mythicplus", commandTableMain},
|
||||
{"mp debug", HandleDebug, SEC_PLAYER, Console::No},
|
||||
{"mp reload", HandleReload, SEC_GAMEMASTER, Console::No}
|
||||
};
|
||||
|
||||
return commandTable;
|
||||
}
|
||||
|
||||
static bool HandleHelp(ChatHandler* handler, const std::vector<std::string>& /*args*/)
|
||||
{
|
||||
std::string helpText = "Mythic+ Commands:\n"
|
||||
" .mp status - show current global settings of Mythic+ mod\n"
|
||||
" .mp set [normal, heroic, mythic,legendary,ascendant] - Set Mythic+ difficulty in current beta only supports mythic.\n"
|
||||
" .mp [enable,disable] - enable or disable this mod\n"
|
||||
" .mp - Show this help message\n";
|
||||
handler->PSendSysMessage(helpText);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleReload(ChatHandler* handler)
|
||||
{
|
||||
sMpDataStore->LoadScaleFactors();
|
||||
handler->PSendSysMessage("Mythic+ scale factors updated.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleDebug(ChatHandler* handler)
|
||||
{
|
||||
|
||||
Creature* target = handler->getSelectedCreature();
|
||||
if(!target) {
|
||||
handler->PSendSysMessage("You must select a creature to debug.");
|
||||
return true;
|
||||
}
|
||||
|
||||
CreatureTemplate const* creatureTemplate = target->GetCreatureTemplate();
|
||||
MpCreatureData* creatureData = sMpDataStore->GetCreatureData(target->GetGUID());
|
||||
|
||||
|
||||
handler->PSendSysMessage(LANG_NPCINFO_LEVEL, target->GetLevel());
|
||||
handler->PSendSysMessage(LANG_NPCINFO_HEALTH, target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth());
|
||||
handler->PSendSysMessage("WeaponDmg Main {} - {}",
|
||||
target->GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE),
|
||||
target->GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE)
|
||||
);
|
||||
handler->PSendSysMessage("WeaponDmg Range {} - {}",
|
||||
target->GetWeaponDamageRange(RANGED_ATTACK, MINDAMAGE),
|
||||
target->GetWeaponDamageRange(RANGED_ATTACK, MAXDAMAGE)
|
||||
);
|
||||
handler->PSendSysMessage("WeaponDmg Offhand {} - {}",
|
||||
target->GetWeaponDamageRange(OFF_ATTACK, MINDAMAGE),
|
||||
target->GetWeaponDamageRange(OFF_ATTACK, MAXDAMAGE)
|
||||
);
|
||||
handler->PSendSysMessage("Attack Power Main {}", target->GetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE));
|
||||
handler->PSendSysMessage("Attack Power Ranged {}", target->GetModifierValue(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE));
|
||||
handler->PSendSysMessage("Armor {}", target->GetArmor());
|
||||
handler->PSendSysMessage("Damage Modifier on template {}",creatureTemplate->DamageModifier);
|
||||
|
||||
if(creatureData) {
|
||||
handler->PSendSysMessage("CreatureData: {}", creatureData->ToString());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
// sets the difficluty for the group
|
||||
static bool HandleSetDifficulty(ChatHandler* handler, const std::vector<std::string>& args)
|
||||
{
|
||||
Player* player = handler->GetSession()->GetPlayer();
|
||||
Group* group = player->GetGroup();
|
||||
|
||||
if (!group) {
|
||||
MpLogger::debug("HandleSetMythic() No Group for player: {}", player->GetName());
|
||||
handler->PSendSysMessage("|cFFFF0000 You must be in a group to be able to set a Mythic+ difficulty.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.empty()) {
|
||||
handler->PSendSysMessage("|cFFFF0000 You must specify a difficulty level. Expected values are 'mythic', 'legendary', or 'ascendant'.");
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string difficulty = args[0];
|
||||
// if(!sMythicPlus->IsDifficultyEnabled(difficulty)) {
|
||||
// handler->PSendSysMessage("|cFFFF0000 The difficulty level you have selected is not enabled.");
|
||||
// return true;
|
||||
// }
|
||||
|
||||
if (!group->IsLeader(player->GetGUID())) {
|
||||
handler->PSendSysMessage("|cFFFF0000 You must be the group leader to set a Mythic+ difficulty.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (player->GetMap()->IsDungeon()) {
|
||||
player->ResetInstances(player->GetGUID(), INSTANCE_RESET_CHANGE_DIFFICULTY, false);
|
||||
player->SendResetInstanceSuccess(player->GetMap()->GetId());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (difficulty == "mythic") {
|
||||
sMpDataStore->AddGroupData(group, MpGroupData(group, MP_DIFFICULTY_MYTHIC));
|
||||
}
|
||||
else if (difficulty == "legendary") {
|
||||
sMpDataStore->AddGroupData(group,MpGroupData(group, MP_DIFFICULTY_LEGENDARY));
|
||||
}
|
||||
else if (difficulty == "ascendant") {
|
||||
sMpDataStore->AddGroupData(group, MpGroupData(group, MP_DIFFICULTY_ASCENDANT));
|
||||
}
|
||||
else if (difficulty == "heroic") {
|
||||
sMpDataStore->RemoveGroupData(group);
|
||||
group->SetDungeonDifficulty(DUNGEON_DIFFICULTY_HEROIC);
|
||||
}
|
||||
else if (difficulty == "normal") {
|
||||
sMpDataStore->RemoveGroupData(group);
|
||||
group->SetDungeonDifficulty(DUNGEON_DIFFICULTY_NORMAL);
|
||||
}
|
||||
else {
|
||||
handler->PSendSysMessage("|cFFFF0000 Invalid difficulty level. Expected values are 'mythic', 'legendary', or 'ascendant'.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
handler->PSendSysMessage("Mythic+ difficulty set to: " + difficulty);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleMythic(ChatHandler* handler, const std::vector<std::string>& /*args*/)
|
||||
{
|
||||
return HandleSetDifficulty(handler, {"mythic"});
|
||||
}
|
||||
|
||||
static bool HandleLegendary(ChatHandler* handler, const std::vector<std::string>& /*args*/)
|
||||
{
|
||||
return HandleSetDifficulty(handler, {"legendary"});
|
||||
}
|
||||
|
||||
static bool HandleAscendant(ChatHandler* handler, const std::vector<std::string>& /*args*/)
|
||||
{
|
||||
return HandleSetDifficulty(handler, {"ascendant"});
|
||||
}
|
||||
|
||||
static bool HandleStatus(ChatHandler* handler)
|
||||
{
|
||||
Player* player = handler->GetPlayer();
|
||||
|
||||
Map* map = player->GetMap();
|
||||
uint32 mapId = player->GetMapId();
|
||||
|
||||
std::string status = Acore::StringFormat(
|
||||
"Mythic+ Status:\n"
|
||||
" Mythic+ Enabled: %s\n"
|
||||
" Mythic+ Item Rewards: %s\n"
|
||||
" Mythic+ DeathLimits: %s\n",
|
||||
sMythicPlus->Enabled ? "Yes" : "No",
|
||||
sMythicPlus->EnableItemRewards ? "Yes" : "No",
|
||||
sMythicPlus->EnableDeathLimits ? "Yes" : "No");
|
||||
|
||||
if (player->GetGroup()) {
|
||||
auto groupData = sMpDataStore->GetGroupData(player->GetGroup()->GetGUID());
|
||||
if (groupData) {
|
||||
MpScaleFactor scaleFactors;
|
||||
|
||||
if(map->IsDungeon()) {
|
||||
scaleFactors = sMpDataStore->GetScaleFactor(mapId, groupData->difficulty);
|
||||
}
|
||||
|
||||
status += Acore::StringFormat(
|
||||
" Group Difficulty: %u\n"
|
||||
" Group Deaths: %u\n"
|
||||
" Scale FactorStr %s\n",
|
||||
(groupData->difficulty) ? groupData->difficulty : 0,
|
||||
(groupData->GetDeaths(player->GetMapId(), player->GetInstanceId())),
|
||||
scaleFactors.ToString()
|
||||
);
|
||||
} else {
|
||||
status += " Group Difficulty: Not Set\n";
|
||||
}
|
||||
}
|
||||
|
||||
handler->PSendSysMessage(status);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleReScale(ChatHandler* handler)
|
||||
{
|
||||
Creature* creature = handler->getSelectedCreature();
|
||||
if(!creature) {
|
||||
handler->PSendSysMessage("You must select a creature to rescale.");
|
||||
return true;
|
||||
}
|
||||
|
||||
MpCreatureData* creatureData = sMpDataStore->GetCreatureData(creature->GetGUID());
|
||||
if(!creatureData) {
|
||||
handler->PSendSysMessage("Creature is not eligible for rescaling.");
|
||||
return true;
|
||||
}
|
||||
|
||||
auto instanceData = sMpDataStore->GetInstanceData(creature->GetMapId(), creature->GetInstanceId());
|
||||
if(!instanceData) {
|
||||
handler->PSendSysMessage("No instance data found for this creature.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if(creature->IsDungeonBoss() || creature->GetEntry() == 23682) {
|
||||
sMythicPlus->ScaleCreature(creature->GetLevel(), creature, &instanceData->boss, instanceData->difficulty);
|
||||
} else {
|
||||
sMythicPlus->ScaleCreature(creature->GetLevel(), creature, &instanceData->creature, instanceData->difficulty);
|
||||
}
|
||||
|
||||
handler->PSendSysMessage("Creature rescaled: %s", creature->GetName());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleReScaleAll(ChatHandler* handler)
|
||||
{
|
||||
Player* player = handler->GetPlayer();
|
||||
if(!player) {
|
||||
handler->PSendSysMessage("You must be a player to rescale all creatures.");
|
||||
return true;
|
||||
}
|
||||
|
||||
Map* map = player->GetMap();
|
||||
if(!map) {
|
||||
handler->PSendSysMessage("You must be in a map to rescale all creatures.");
|
||||
return true;
|
||||
}
|
||||
|
||||
int32 mapId = map->GetId();
|
||||
int32 instanceId = map->GetInstanceId();
|
||||
|
||||
auto instanceData = sMpDataStore->GetInstanceData(mapId, instanceId);
|
||||
if(!instanceData) {
|
||||
handler->PSendSysMessage("No mythic instance data found for this map.");
|
||||
return true;
|
||||
}
|
||||
|
||||
sMythicPlus->ScaleAll(player, instanceData);
|
||||
handler->PSendSysMessage("All creatures rescaled.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleDisable(ChatHandler* handler)
|
||||
{
|
||||
MpLogger::debug("HandleDisable()");
|
||||
sMythicPlus->Enabled = false;
|
||||
handler->SendSysMessage("Mythic+ mod has been disabled.");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleEnable(ChatHandler* handler)
|
||||
{
|
||||
MpLogger::debug("HandleEnable()");
|
||||
sMythicPlus->Enabled = false;
|
||||
handler->SendSysMessage("Mythic+ mod has been enabled.");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleChangeMelee(ChatHandler* handler, const std::vector<std::string>& args)
|
||||
{
|
||||
if (args.empty()) {
|
||||
handler->PSendSysMessage("|cFFFF0000 You must specify a value to set the melee scale factor.");
|
||||
return true;
|
||||
}
|
||||
|
||||
Player* player = handler->GetSession()->GetPlayer();
|
||||
if (!player) {
|
||||
handler->PSendSysMessage("|cFFFF0000 Invalid session or player.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (player->GetGroup()) {
|
||||
auto groupData = sMpDataStore->GetGroupData(player->GetGroup()->GetGUID());
|
||||
|
||||
if(groupData) {
|
||||
uint32 value = std::stoi(args[0]);
|
||||
sMpDataStore->SetDamageScaleFactor(player->GetMapId(), groupData->difficulty, value);
|
||||
handler->PSendSysMessage(Acore::StringFormat("Melee scale factor set to: %u", value));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
handler->PSendSysMessage("|cFFFF0000 You must be in a group and mythic+ instance to set a melee scale factor.");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleChangeSpell(ChatHandler* handler, const std::vector<std::string>& args)
|
||||
{
|
||||
if (args.empty()) {
|
||||
handler->PSendSysMessage("|cFFFF0000 You must specify a value to set the spell scale factor.");
|
||||
return true;
|
||||
}
|
||||
|
||||
Player* player = handler->GetSession()->GetPlayer();
|
||||
if (!player) {
|
||||
handler->PSendSysMessage("|cFFFF0000 Invalid session or player.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (player->GetGroup()) {
|
||||
auto groupData = sMpDataStore->GetGroupData(player->GetGroup()->GetGUID());
|
||||
|
||||
if(groupData) {
|
||||
uint32 value = std::stoi(args[0]);
|
||||
sMpDataStore->SetSpellScaleFactor(player->GetMapId(), groupData->difficulty, value);
|
||||
handler->PSendSysMessage(Acore::StringFormat("Spell scale factor set to: %u", value));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
handler->PSendSysMessage("|cFFFF0000 You must be in a group and mythic+ instance to set a melee scale factor.");
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleChangeHealth(ChatHandler* handler, const std::vector<std::string>& args)
|
||||
{
|
||||
if (args.empty()) {
|
||||
handler->PSendSysMessage("|cFFFF0000 You must specify a value to set the health scale factor.");
|
||||
return true;
|
||||
}
|
||||
|
||||
Player* player = handler->GetSession()->GetPlayer();
|
||||
if (!player) {
|
||||
handler->PSendSysMessage("|cFFFF0000 Invalid session or player.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (player->GetGroup()) {
|
||||
auto groupData = sMpDataStore->GetGroupData(player->GetGroup()->GetGUID());
|
||||
|
||||
if(groupData) {
|
||||
uint32 value = std::stoi(args[0]);
|
||||
sMpDataStore->SetHealthScaleFactor(player->GetMapId(), groupData->difficulty, value);
|
||||
handler->PSendSysMessage(Acore::StringFormat("Health scale factor set to: %u", value));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
handler->PSendSysMessage("|cFFFF0000 You must be in a group and mythic+ instance to set a melee scale factor.");
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void Add_MP_CommandScripts()
|
||||
{
|
||||
MpLogger::debug("Add_MP_CommandScripts()");
|
||||
new MythicPlus_CommandScript();
|
||||
}
|
||||
@@ -11,7 +11,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;
|
||||
100
src/Scripts/GroupScript.cpp
Normal file
100
src/Scripts/GroupScript.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
|
||||
#include "MpDataStore.h"
|
||||
#include "MpLogger.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "Group.h"
|
||||
|
||||
// this handles updating custom group difficulties used in auto balancing mobs and
|
||||
// scripts that enable buffs on mobs randomly
|
||||
class MythicPlus_GroupScript : public GroupScript
|
||||
{
|
||||
public:
|
||||
MythicPlus_GroupScript() : GroupScript("MythicPlus_GroupScript") { }
|
||||
|
||||
void OnAddMember(Group* group, ObjectGuid guid) override {
|
||||
if (!group || !guid) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player* player = ObjectAccessor::FindPlayer(guid);
|
||||
if (!player) {
|
||||
MpLogger::warn("Player not found for guid {}", guid.GetCounter());
|
||||
return;
|
||||
}
|
||||
|
||||
MpGroupData *gd = sMpDataStore->GetGroupData(group->GetGUID());
|
||||
MpPlayerData* pd = sMpDataStore->GetPlayerData(guid);
|
||||
if(!pd) {
|
||||
|
||||
MpDifficulty difficulty = GetPlayerDifficulty(player);
|
||||
MpPlayerData playerData = MpPlayerData(player, difficulty, group->GetGUID().GetCounter());
|
||||
sMpDataStore->AddPlayerData(guid, &playerData);
|
||||
} else {
|
||||
|
||||
// If the player is joining a new group then reset the death counters otherwise let them ride
|
||||
if (pd->groupId != group->GetGUID().GetCounter()) {
|
||||
pd->groupId = group->GetGUID().GetCounter();
|
||||
pd->ResetAllDeathCounts();
|
||||
}
|
||||
}
|
||||
|
||||
if(!gd) {
|
||||
MpLogger::warn("Group data not found for group {}", group->GetGUID().GetCounter());
|
||||
return;
|
||||
}
|
||||
|
||||
gd->AddPlayerData(pd);
|
||||
}
|
||||
|
||||
void OnCreate(Group* group, Player* leader) override {
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!leader) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Start a group and set the data up for the group
|
||||
MpDifficulty difficulty = GetPlayerDifficulty(leader);
|
||||
MpGroupData gd = MpGroupData(group, difficulty);
|
||||
|
||||
// Insert the leader of the group after group data struct is built
|
||||
MpPlayerData* pd = sMpDataStore->GetPlayerData(leader->GetGUID());
|
||||
if(pd) {
|
||||
gd.AddPlayerData(pd);
|
||||
} else {
|
||||
MpPlayerData playerData = MpPlayerData(leader, difficulty, group->GetGUID().GetCounter());
|
||||
gd.AddPlayerData(&playerData);
|
||||
}
|
||||
|
||||
// Store the data into our memory store
|
||||
sMpDataStore->AddGroupData(group, gd);
|
||||
}
|
||||
|
||||
void OnDisband(Group* group) override {
|
||||
sMpDataStore->RemoveGroupData(group);
|
||||
}
|
||||
|
||||
// Get the difficulty for a player that is assigned
|
||||
MpDifficulty GetPlayerDifficulty(Player* player) {
|
||||
if(!player) {
|
||||
return MP_DIFFICULTY_NORMAL;
|
||||
}
|
||||
|
||||
MpPlayerData* pd = sMpDataStore->GetPlayerData(player->GetGUID());
|
||||
if(pd) {
|
||||
return pd->difficulty;
|
||||
} else {
|
||||
return player->GetDifficulty(false) == Difficulty::DUNGEON_DIFFICULTY_NORMAL ? MP_DIFFICULTY_NORMAL : MP_DIFFICULTY_HEROIC;
|
||||
}
|
||||
|
||||
return MP_DIFFICULTY_NORMAL;
|
||||
}
|
||||
};
|
||||
|
||||
void Add_MP_GroupScripts()
|
||||
{
|
||||
MpLogger::debug("Add_MP_GroupScripts()");
|
||||
new MythicPlus_GroupScript();
|
||||
}
|
||||
91
src/Scripts/PlayerMessageEvents.cpp
Normal file
91
src/Scripts/PlayerMessageEvents.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
#include "MpLogger.h"
|
||||
#include "MythicPlus.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "AdvancementMgr.h"
|
||||
#include "Chat.h"
|
||||
#include "Channel.h"
|
||||
#include "ChannelMgr.h"
|
||||
#include "MpEventProcessor.h"
|
||||
#include <boost/algorithm/string/predicate.hpp> // For starts_with
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <ranges>
|
||||
|
||||
/**
|
||||
* This script file is a special event handler attached to the chat channel for MythicPlus to intercept
|
||||
* message events from the client hidden chat channel and process them, as well as return events back to
|
||||
* the client. It's a very simplified version of how Eluna / AIO manage messages from UI to C++ mods.
|
||||
*
|
||||
* All Messages come into a chat channel from a specific user on a hidden channel with details in the MythicPlus.h
|
||||
* class for the protocol data definition.
|
||||
*/
|
||||
|
||||
class MythicPlus_PlayerMessageEvents : public PlayerScript
|
||||
{
|
||||
public:
|
||||
MythicPlus_PlayerMessageEvents() : PlayerScript("MythicPlus_PlayerMessageEvents") {}
|
||||
|
||||
/**
|
||||
* Listens to AddOn Chat channel for Mythic+ communication between UI and server mythic+ functionality
|
||||
*/
|
||||
void OnChat(Player* player, uint32 type, uint32 lang, std::string& msg, Player* receiver) override
|
||||
{
|
||||
// All communication from the client should be a whisper to themselves over tha addon channel
|
||||
if(!player || !receiver) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(lang == LANG_ADDON) {
|
||||
if(msg.empty()) {
|
||||
MpLogger::info("Empty AddOn message received from player: {}", player->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
// if the message begins with our prefix for our data channel then process the event
|
||||
if(boost::starts_with(msg, MP_DATA_CHAT_CHANNEL)) {
|
||||
sMpEventProcessor->ProcessMessage(player, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When a player logs in add them to the data channel specifically for Mythic+ communication
|
||||
* between UI and server module.
|
||||
*
|
||||
* Load advancement data for the player at load time used to apply buffs.
|
||||
*/
|
||||
// void OnLogin(Player* player) override
|
||||
// {
|
||||
// if(!player) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Create a channel called MpEx if it does not exist
|
||||
// MpLogger::info("Player {} logged in on team {}", player->GetName(), player->GetTeamId());
|
||||
// ChannelMgr* cmg = ChannelMgr::forTeam(player->GetTeamId());
|
||||
|
||||
// if(!cmg) {
|
||||
// MpLogger::error("Failed to get channel manager for team {}", player->GetTeamId());
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Channel* channel = cmg->GetChannel(static_cast<std::string>(MP_DATA_CHAT_CHANNEL), player);
|
||||
// if(!channel) {
|
||||
// MpLogger::error("Failed to get mythic data channel for player {}", player->GetName());
|
||||
// Channel* nchan = new Channel(static_cast<std::string>(MP_DATA_CHAT_CHANNEL), 17, 0, player->GetTeamId());
|
||||
// if(!nchan) {
|
||||
// MpLogger::error("Failed to create mythic data channel for player {}", player->GetName());
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
};
|
||||
|
||||
void Add_MP_PlayerMessageEvents()
|
||||
{
|
||||
MpLogger::debug("Add_MP_PlayerEventMessages");
|
||||
new MythicPlus_PlayerMessageEvents();
|
||||
}
|
||||
194
src/Scripts/PlayerScript.cpp
Normal file
194
src/Scripts/PlayerScript.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
#include "MpLogger.h"
|
||||
#include "MpDataStore.h"
|
||||
#include "MpScheduler.h"
|
||||
#include "MythicPlus.h"
|
||||
#include "Player.h"
|
||||
#include "Group.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "TaskScheduler.h"
|
||||
#include "AdvancementMgr.h"
|
||||
|
||||
class MythicPlus_PlayerScript : public PlayerScript
|
||||
{
|
||||
public:
|
||||
MythicPlus_PlayerScript() : PlayerScript("MythicPlus_PlayerScript") {}
|
||||
|
||||
/**
|
||||
* Mythic+ special actions when a player dies:
|
||||
* - Track the death for the group
|
||||
* - Update the player death stats
|
||||
* - Determine whether or not the Group failed the instance due to death count setting.
|
||||
*/
|
||||
|
||||
void OnPlayerKilledByCreature(Creature* killer, Player* player) override
|
||||
{
|
||||
Map* map = player->GetMap();
|
||||
if(!sMythicPlus->IsMapEligible(map)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player) {
|
||||
return;
|
||||
}
|
||||
|
||||
Group* group = player->GetGroup();
|
||||
if(!group) {
|
||||
MpLogger::warn("Missing group data for player {}", player->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
MpGroupData *data = sMpDataStore->GetGroupData(player->GetGroup());
|
||||
if (!data) {
|
||||
MpLogger::warn("Missin group data for player {}", player->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
MpPlayerData *playerData = sMpDataStore->GetPlayerData(player->GetGUID());
|
||||
if (!playerData) {
|
||||
MpLogger::warn("Missin player data for player {}", player->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
playerData->AddDeath(map->GetId(), map->GetInstanceId());
|
||||
|
||||
if(killer) {
|
||||
sMpDataStore->DBAddPlayerDeath(player, killer, data->difficulty);
|
||||
} else {
|
||||
sMpDataStore->DBAddPlayerDeath(player);
|
||||
}
|
||||
|
||||
sMpDataStore->DBAddGroupDeath(group, player->GetMapId(), player->GetInstanceId(), data->difficulty);
|
||||
|
||||
uint32 totalDeaths = data->GetDeaths(player->GetMapId(), player->GetInstanceId());
|
||||
MpLogger::info("Total Deaths: {}", totalDeaths);
|
||||
if(totalDeaths > 1) {
|
||||
MpLogger::debug(" :::: Player Deaths for Group too high! ::::::");
|
||||
|
||||
TaskScheduler& wScheduler = sMpScheduler->GetWorldScheduler();
|
||||
wScheduler.Schedule(10s, MP_WORLD_TASK_GROUP, [player, map](TaskContext /*ctx*/) {
|
||||
Group* group = player->GetGroup();
|
||||
if(!group) {
|
||||
return;
|
||||
}
|
||||
|
||||
MythicPlus::GroupReset(group, map);
|
||||
});
|
||||
}
|
||||
// if(totalDeaths > 1) {
|
||||
// Map* map = player->GetMap();
|
||||
// if(!map) {
|
||||
// return;
|
||||
// }
|
||||
// Group* group = player->GetGroup();
|
||||
// if(!group) {
|
||||
// MpLogger::warn("Player {} is not in a group.", player->GetName());
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // map->RemoveAllPlayers();
|
||||
// MpLogger::info("Starting scheduled failure notification");
|
||||
// // auto testlambda = [](TaskContext ctx) { return; };
|
||||
// sMpScheduler->ScheduleWorldTask(1s, [](TaskContext ctx) {
|
||||
// MpLogger::info("<<<<<<<<<<< Player Death Scheduler fire >>>>>>>>>>>>>");
|
||||
// });
|
||||
|
||||
// sMpScheduler->GetWorldScheduler().Schedule(1s, [playerName = player->GetName()](TaskContext ctx) {
|
||||
// MpLogger::info("<<<<<<<<<<< Player Death Scheduler fire {} >>>>>>>>>>>>>", playerName);
|
||||
// return;
|
||||
// });
|
||||
// std::vector<Player*> players = GetGroupMembers(player);
|
||||
// MpLogger::info("Failed mythic+ instance run notification fired. ");
|
||||
// WorldPacket data;
|
||||
|
||||
// for(Player* player : players)
|
||||
// {
|
||||
// MpLogger::info("Seding notification of failure to player: {}", player->GetName());
|
||||
// player->GetSession()->SendShowBank(player->GetGUID());
|
||||
// // player->GetSession()->SendNotification("Your group has died too many time to continue.");
|
||||
// // ChatHandler::BuildChatPacket(data, CHAT_MSG_RAID_BOSS_EMOTE, LANG_UNIVERSAL, nullptr, player, message);
|
||||
// // player->GetSession()->SendPacket(&data);
|
||||
// }
|
||||
|
||||
// map->ToInstanceMap()->Reset(0);
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
void OnLogin(Player* player) override
|
||||
{
|
||||
// Load the player advancement data for the player when they login
|
||||
int32 size = sAdvancementMgr->LoadPlayerAdvancements(player);
|
||||
MpLogger::info("Loaded {} player advancements for player {}", size, player->GetName());
|
||||
}
|
||||
|
||||
// When a player is bound to an instance need to make sure they are saved in the data soure to retrieve later.
|
||||
void OnBindToInstance(Player* player, Difficulty /*difficulty*/, uint32 mapId, bool /*permanent*/) override
|
||||
{
|
||||
if(!player) {
|
||||
return;
|
||||
}
|
||||
|
||||
Group* group = player->GetGroup();
|
||||
|
||||
// If they are not in a group do nothing.
|
||||
if(!group) {
|
||||
return;
|
||||
}
|
||||
|
||||
MpGroupData* data = sMpDataStore->GetGroupData(group);
|
||||
|
||||
// If there is not any mythic+ data set for this group do nothing.
|
||||
if(!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map* map = player->GetMap();
|
||||
if(!map) {
|
||||
MpLogger::warn("Player {} is not in a map", player->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
// get the player data or set it up
|
||||
MpPlayerData* playerData = sMpDataStore->GetPlayerData(player->GetGUID());
|
||||
if(!playerData) {
|
||||
playerData = new MpPlayerData(player, data->difficulty, group->GetGUID().GetCounter());
|
||||
sMpDataStore->AddPlayerData(player->GetGUID(), playerData);
|
||||
}
|
||||
|
||||
// Add this players data to the group data
|
||||
data->AddPlayerData(playerData);
|
||||
|
||||
auto mapKey = sMpDataStore->GetInstanceDataKey(mapId, player->GetInstanceId());
|
||||
playerData->instanceData.emplace(mapKey, MpPlayerInstanceData{
|
||||
.deaths = 0,
|
||||
});
|
||||
|
||||
sMpDataStore->DBUpdatePlayerInstanceData(player->GetGUID(), data->difficulty, map->GetId(), map->GetInstanceId());
|
||||
sMpDataStore->DBUpdateGroupData(group->GetGUID(), data->difficulty, map->GetId(), map->GetInstanceId(), 0);
|
||||
}
|
||||
|
||||
std::vector<Player*> GetGroupMembers(Player* currentPlayer)
|
||||
{
|
||||
std::vector<Player*> groupPlayers;
|
||||
|
||||
Group* group = currentPlayer->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
MpLogger::warn("Player is not in a group.");
|
||||
return groupPlayers;
|
||||
}
|
||||
|
||||
group->DoForAllMembers([&](Player* member) {
|
||||
groupPlayers.push_back(member);
|
||||
});
|
||||
|
||||
return groupPlayers;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void Add_MP_PlayerScripts()
|
||||
{
|
||||
MpLogger::debug("Add_MP_PlayerScripts()");
|
||||
new MythicPlus_PlayerScript();
|
||||
}
|
||||
@@ -18,22 +18,29 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
bool haspositiveeffect = false;
|
||||
auto effects = spellInfo->Effects;
|
||||
bool isHot = false;
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) {
|
||||
if (spellInfo->_IsPositiveEffect(i, true)) {
|
||||
haspositiveeffect = true;
|
||||
break;
|
||||
switch(effects[i].Effect) {
|
||||
case SPELL_EFFECT_HEAL:
|
||||
case SPELL_EFFECT_HEAL_MAX_HEALTH:
|
||||
case SPELL_EFFECT_HEAL_MECHANICAL:
|
||||
case SPELL_EFFECT_HEAL_PCT:
|
||||
case SPELL_EFFECT_SPIRIT_HEAL:
|
||||
isHot = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(haspositiveeffect) {
|
||||
damage = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_HOT, target, attacker, damage);
|
||||
|
||||
if(isHot) {
|
||||
damage = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_HOT, target, attacker, damage, spellInfo);
|
||||
} else {
|
||||
damage = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_DOT, target, attacker, damage);
|
||||
damage = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_DOT, target, attacker, damage, spellInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage, SpellInfo const* /*spellInfo*/) override {
|
||||
void ModifySpellDamageTaken(Unit* target, Unit* attacker, int32& damage, SpellInfo const* spellInfo) override {
|
||||
if (!target && !attacker) {
|
||||
return;
|
||||
}
|
||||
@@ -43,7 +50,11 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
damage = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_SPELL, target, attacker, damage);
|
||||
if(sMythicPlus->EligibleDamageTarget(target)) {
|
||||
MpLogger::debug("ModifySpellDamageTaken: {} hits {} with spell: {}", attacker->GetName(), target->GetName(), spellInfo->SpellName[0]);
|
||||
}
|
||||
|
||||
damage = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_SPELL, target, attacker, damage, spellInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,7 +75,7 @@ public:
|
||||
}
|
||||
|
||||
// When a healing spell hits a mythic+ enemy modify based on the modifiers for the difficulty
|
||||
void ModifyHealReceived(Unit* target, Unit* healer, uint32& healing, SpellInfo const* /*spellInfo*/) override {
|
||||
void ModifyHealReceived(Unit* target, Unit* healer, uint32& healing, SpellInfo const* spellInfo) override {
|
||||
if (!target && !healer) {
|
||||
return;
|
||||
}
|
||||
@@ -74,7 +85,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
healing = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_HEAL, target, healer, healing);
|
||||
healing = modifyIncomingDmgHeal(MythicPlus::UNIT_EVENT_HEAL, target, healer, healing, spellInfo);
|
||||
}
|
||||
|
||||
uint32 modifyIncomingDmgHeal(MythicPlus::MP_UNIT_EVENT_TYPE eventType,Unit* target, Unit* attacker, uint32 damageOrHeal, SpellInfo const* spellInfo = nullptr) {
|
||||
@@ -129,9 +140,6 @@ public:
|
||||
break;
|
||||
}
|
||||
|
||||
MpLogger::debug("Incoming Event Type ({}): {} hits {} before mod: {}", eventName, attacker->GetName(), target->GetName(), damageOrHeal);
|
||||
|
||||
bool isHeal = false;
|
||||
// If the target is the enemy then increase the amount of healing by the instance data modifier for spell output.
|
||||
if(sMythicPlus->EligibleDamageTarget(target)) {
|
||||
/**
|
||||
@@ -140,7 +148,7 @@ public:
|
||||
*/
|
||||
switch (eventType) {
|
||||
case MythicPlus::UNIT_EVENT_MELEE:
|
||||
if(creature->IsDungeonBoss()) {
|
||||
if(creature->IsDungeonBoss() || creature->GetEntry() == 23682) {
|
||||
alteredDmgHeal = damageOrHeal * instanceData->boss.melee;
|
||||
} else {
|
||||
alteredDmgHeal = damageOrHeal * instanceData->creature.melee;
|
||||
@@ -149,40 +157,45 @@ public:
|
||||
break;
|
||||
case MythicPlus::UNIT_EVENT_DOT:
|
||||
case MythicPlus::UNIT_EVENT_SPELL:
|
||||
if(creature->IsDungeonBoss()) {
|
||||
if(creature->IsDungeonBoss() || creature->GetEntry() == 23682) {
|
||||
if(spellInfo) {
|
||||
alteredDmgHeal = sMythicPlus->ScaleDamageSpell(spellInfo, sMpDataStore->GetCreatureData(attacker->GetGUID()), creature, instanceData->boss.spell);
|
||||
alteredDmgHeal = sMythicPlus->ScaleDamageSpell(spellInfo, damageOrHeal, sMpDataStore->GetCreatureData(attacker->GetGUID()), creature, target, instanceData->boss.spell);
|
||||
} else {
|
||||
alteredDmgHeal = damageOrHeal * instanceData->boss.spell;
|
||||
}
|
||||
} else {
|
||||
if(spellInfo) {
|
||||
alteredDmgHeal = sMythicPlus->ScaleDamageSpell(spellInfo, sMpDataStore->GetCreatureData(attacker->GetGUID()), creature, instanceData->creature.spell);
|
||||
alteredDmgHeal = sMythicPlus->ScaleDamageSpell(spellInfo, damageOrHeal, sMpDataStore->GetCreatureData(attacker->GetGUID()), creature, target, instanceData->creature.spell);
|
||||
} else {
|
||||
alteredDmgHeal = damageOrHeal * instanceData->creature.spell;
|
||||
}
|
||||
}
|
||||
MpLogger::debug("Incoming spell or dot New Damage: {}({}) {} hits {}", alteredDmgHeal, damageOrHeal, attacker->GetName(), target->GetName());
|
||||
|
||||
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:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @TODO: Add more granular control over the scaling of healing spells
|
||||
*/
|
||||
if(sMythicPlus->EligibleHealTarget(target) && (eventType == MythicPlus::UNIT_EVENT_HEAL || eventType == MythicPlus::UNIT_EVENT_HOT)) {
|
||||
isHeal = true;
|
||||
if(creature->IsDungeonBoss()) {
|
||||
if(spellInfo) {
|
||||
alteredDmgHeal = sMythicPlus->ScaleHealSpell(spellInfo, 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);
|
||||
} else {
|
||||
alteredDmgHeal = damageOrHeal * instanceData->boss.spell;
|
||||
}
|
||||
} else {
|
||||
if(spellInfo) {
|
||||
alteredDmgHeal = sMythicPlus->ScaleHealSpell(spellInfo, 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);
|
||||
} else {
|
||||
alteredDmgHeal = damageOrHeal * instanceData->creature.spell;
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
#include "Config.h"
|
||||
#include "MythicPlus.h"
|
||||
#include "MpDataStore.h"
|
||||
#include "AdvancementMgr.h"
|
||||
#include "MpLogger.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "MpEventHandlers.cpp"
|
||||
|
||||
class MythicPlus_WorldScript : public WorldScript
|
||||
{
|
||||
@@ -86,6 +88,9 @@ public:
|
||||
sMythicPlus->mythicItemOffset = sConfigMgr->GetOption<uint32>("MythicPlus.Mythic.ItemOffset", 20000000);
|
||||
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);
|
||||
}
|
||||
|
||||
void OnStartup() override
|
||||
@@ -93,6 +98,15 @@ public:
|
||||
int32 size = sMpDataStore->LoadScaleFactors();
|
||||
MpLogger::info("Loaded {} Mythic+ Scaling Factors from database...", size);
|
||||
|
||||
size = sAdvancementMgr->LoadAdvancementRanks();
|
||||
MpLogger::info("Loaded {} advancement ranks...", size);
|
||||
|
||||
size = sAdvancementMgr->LoadMaterialTypes();
|
||||
MpLogger::info("Loaded {} material types...", size);
|
||||
|
||||
// Registering event handlers for the Mythic+ events from client
|
||||
MP_Register_EventHandlers();
|
||||
MpLogger::info("Registered Mythic+ Event Handlers...");
|
||||
}
|
||||
};
|
||||
|
||||
70
src/Spells/Toughness.cpp
Normal file
70
src/Spells/Toughness.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
// #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);
|
||||
// }
|
||||
Reference in New Issue
Block a user