aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2016-08-15 00:03:38 +0200
committerShauren <shauren.trinity@gmail.com>2016-08-15 00:03:38 +0200
commitfea0cb16f2e73ec21891ac14cdc10d9d8f518cfe (patch)
tree7e3a6ee9b3876ca5b3a7115a9d932ce8125c41e1
parentf8c5a2c723c734513eddc98a5c7f380c2f00e479 (diff)
Core/Items: Implemented artifacts
-rw-r--r--sql/base/characters_database.sql75
-rw-r--r--sql/updates/characters/6.x/2016_08_15_00_characters.sql36
-rw-r--r--sql/updates/hotfixes/6.x/2016_08_15_00_hotfixes.sql182
-rw-r--r--sql/updates/world/6.x/2016_08_15_00_world.sql6
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp25
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.h10
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.cpp37
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.h21
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp68
-rw-r--r--src/server/game/DataStores/DB2Stores.h23
-rw-r--r--src/server/game/DataStores/DB2Structure.h91
-rw-r--r--src/server/game/DataStores/DBCEnums.h37
-rw-r--r--src/server/game/DataStores/GameTables.cpp2
-rw-r--r--src/server/game/DataStores/GameTables.h6
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp29
-rw-r--r--src/server/game/Entities/Item/Item.cpp350
-rw-r--r--src/server/game/Entities/Item/Item.h26
-rw-r--r--src/server/game/Entities/Item/ItemEnchantmentMgr.cpp1
-rw-r--r--src/server/game/Entities/Item/ItemTemplate.h1
-rw-r--r--src/server/game/Entities/Player/Player.cpp158
-rw-r--r--src/server/game/Entities/Player/Player.h17
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp6
-rw-r--r--src/server/game/Entities/Unit/Unit.h3
-rw-r--r--src/server/game/Guilds/Guild.cpp4
-rw-r--r--src/server/game/Guilds/GuildMgr.cpp8
-rw-r--r--src/server/game/Handlers/ArtifactHandler.cpp220
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp4
-rw-r--r--src/server/game/Handlers/ItemHandler.cpp21
-rw-r--r--src/server/game/Handlers/VoidStorageHandler.cpp4
-rw-r--r--src/server/game/Server/Packets/AllPackets.h1
-rw-r--r--src/server/game/Server/Packets/ArtifactPackets.cpp71
-rw-r--r--src/server/game/Server/Packets/ArtifactPackets.h105
-rw-r--r--src/server/game/Server/Packets/ItemPackets.cpp9
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp11
-rw-r--r--src/server/game/Server/Protocol/Opcodes.h1
-rw-r--r--src/server/game/Server/WorldSession.h12
-rw-r--r--src/server/game/Spells/Spell.cpp19
-rw-r--r--src/server/game/Spells/Spell.h3
-rw-r--r--src/server/game/Spells/SpellEffects.cpp30
-rw-r--r--src/server/scripts/Spells/spell_item.cpp76
40 files changed, 1744 insertions, 65 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql
index e43b08cac0a..d6a0e0db2d4 100644
--- a/sql/base/characters_database.sql
+++ b/sql/base/characters_database.sql
@@ -1552,6 +1552,8 @@ CREATE TABLE `character_void_storage` (
`randomProperty` int(10) unsigned NOT NULL DEFAULT '0',
`suffixFactor` int(10) unsigned NOT NULL DEFAULT '0',
`upgradeId` int(10) unsigned NOT NULL DEFAULT '0',
+ `fixedScalingLevel` int(10) unsigned DEFAULT '0',
+ `artifactKnowledgeLevel` int(10) unsigned DEFAULT '0',
`bonusListIDs` text,
PRIMARY KEY (`itemId`),
UNIQUE KEY `idx_player_slot` (`playerGuid`,`slot`),
@@ -2553,6 +2555,54 @@ LOCK TABLES `item_instance` WRITE;
UNLOCK TABLES;
--
+-- Table structure for table `item_instance_artifact`
+--
+
+DROP TABLE IF EXISTS `item_instance_artifact`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `item_instance_artifact` (
+ `itemGuid` bigint(20) unsigned NOT NULL,
+ `xp` int(10) unsigned NOT NULL DEFAULT '0',
+ `artifactAppearanceId` int(10) unsigned NOT NULL DEFAULT '0',
+ PRIMARY KEY (`itemGuid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `item_instance_artifact`
+--
+
+LOCK TABLES `item_instance_artifact` WRITE;
+/*!40000 ALTER TABLE `item_instance_artifact` DISABLE KEYS */;
+/*!40000 ALTER TABLE `item_instance_artifact` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `item_instance_artifact_powers`
+--
+
+DROP TABLE IF EXISTS `item_instance_artifact_powers`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `item_instance_artifact_powers` (
+ `itemGuid` bigint(20) unsigned NOT NULL,
+ `artifactPowerId` int(10) unsigned NOT NULL,
+ `purchasedRank` tinyint(3) unsigned DEFAULT '0',
+ PRIMARY KEY (`itemGuid`,`artifactPowerId`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `item_instance_artifact_powers`
+--
+
+LOCK TABLES `item_instance_artifact_powers` WRITE;
+/*!40000 ALTER TABLE `item_instance_artifact_powers` DISABLE KEYS */;
+/*!40000 ALTER TABLE `item_instance_artifact_powers` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
-- Table structure for table `item_instance_gems`
--
@@ -2583,6 +2633,29 @@ LOCK TABLES `item_instance_gems` WRITE;
/*!40000 ALTER TABLE `item_instance_gems` ENABLE KEYS */;
UNLOCK TABLES;
+-- Table structure for table `item_instance_modifiers`
+--
+
+DROP TABLE IF EXISTS `item_instance_modifiers`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `item_instance_modifiers` (
+ `itemGuid` bigint(20) unsigned NOT NULL,
+ `fixedScalingLevel` int(10) unsigned DEFAULT '0',
+ `artifactKnowledgeLevel` int(10) unsigned DEFAULT '0',
+ PRIMARY KEY (`itemGuid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `item_instance_modifiers`
+--
+
+LOCK TABLES `item_instance_modifiers` WRITE;
+/*!40000 ALTER TABLE `item_instance_modifiers` DISABLE KEYS */;
+/*!40000 ALTER TABLE `item_instance_modifiers` ENABLE KEYS */;
+UNLOCK TABLES;
+
--
-- Table structure for table `item_instance_transmog`
--
@@ -3147,7 +3220,7 @@ CREATE TABLE `updates` (
LOCK TABLES `updates` WRITE;
/*!40000 ALTER TABLE `updates` DISABLE KEYS */;
-INSERT INTO `updates` VALUES ('2014_10_20_00_characters.sql','A5882DA0979CF4DAE33DA011EBAA006C24BE7230','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_23_00_characters.sql','E2AC4758133EE19B7F08464A445802154D1261C8','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_23_01_characters.sql','20029E6323D9773B32C34D84FFED1711CC60F09F','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_23_02_characters.sql','8A7A16886EE71E7ACDDB3DDA6D0ECAC2FD2FDCA8','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_24_00_characters.sql','D008FE81AE844FCA686439D6ECC5108FB0DD1EB9','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_25_00_characters.sql','A39C7BE46686B54776BDAB9D7A882D91EDEC51A4','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_26_00_characters.sql','C787954CC35FE34B4101FDE6527F14C027F4947C','ARCHIVED','2015-03-21 15:55:55',0),('2014_11_12_00_characters.sql','B160BB2313F1BD5F3B076A5A9279DC10D4796E34','ARCHIVED','2015-03-21 15:55:55',0),('2014_12_23_00_characters.sql','3D9D648B2387B357F4BD090B33F80682F7924882','ARCHIVED','2015-03-21 15:55:55',0),('2014_12_28_00_characters.sql','5362922FF4483A336311D73082A5727309CD9219','ARCHIVED','2015-03-21 15:55:55',0),('2014_12_31_00_characters.sql','498DDF2DD936CF156D74A8208DC93DCE9FCAB5AA','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_02_00_characters.sql','E5940BE836F253982E07930120422E598D08BDE1','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_10_00_characters.sql','30796056C8623699B2FE1BF626A19D38262E9284','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_16_00_characters.sql','96642760A54C8D799AAFE438049A63AA521656F2','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_27_00_characters.sql','EB710E3EB9F2CAFD84AB62CDC84E898403A80A4F','ARCHIVED','2015-03-21 15:55:55',0),('2015_02_13_00_characters.sql','405BEB4ED207DC6076442A37EE2AFB1F21E274A0','ARCHIVED','2015-03-21 15:55:55',0),('2015_02_13_01_characters.sql','35F582D4F33BF55D1685A1BA89273ED895FD09C5','ARCHIVED','2015-03-21 15:55:55',0),('2015_02_17_00_characters.sql','8D21FC5A55BF8B55D6DCDCE5F02CF2B640230E94','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_10_00_characters.sql','E565B89B145C340067742DFF2DEF1B74F5F1BD4E','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_20_00_characters.sql','B761760804EA73BD297F296C5C1919687DF7191C','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_20_01_characters.sql','20BD68468C57FCF7E665B4DA185DCD52FACE8B3F','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_20_02_characters.sql','0296995DCD3676BA9AE6024CA7C91C5F39D927A3','ARCHIVED','2015-03-21 15:56:46',0),('2015_03_29_00_characters.sql','95D6A46BB746A8BD3EE3FE2086DF1A07F7C33B92','ARCHIVED','2015-05-02 15:43:06',0),('2015_04_21_00_characters.sql','F2032B9BF4EDA7EDE5065554724ED392FD91657D','ARCHIVED','2015-05-02 15:43:06',0),('2015_04_28_00_characters.sql','949F62DB3A3461D420A1230ECF7A6A3ED6435703','ARCHIVED','2015-05-02 15:43:06',0),('2015_05_08_00_characters.sql','0F14B7821618D1C872625B6EDDAA9A667B211167','ARCHIVED','2015-07-10 19:32:17',0),('2015_05_22_00_characters.sql','65B82152413FAB23BE413656E59A486A74447FF7','ARCHIVED','2015-07-10 19:32:17',0),('2015_07_08_00_characters.sql','DAB25360ACB5244C8F8E6214CF6BD97160588A5B','ARCHIVED','2015-07-10 19:32:17',0),('2015_07_11_00_characters.sql','B421B6C0E57BD0FD587071358863D9DABF4BA849','ARCHIVED','2015-07-13 21:50:02',0),('2015_07_12_00_characters.sql','E98E7FD61EF6426E7EDE8ED9AD8C15D8D7132589','ARCHIVED','2015-07-13 21:50:02',0),('2015_07_28_00_characters.sql','0711BC3A658D189EF71B0CB68DCFF2E9B781C4A0','ARCHIVED','2015-07-29 16:23:56',0),('2015_08_08_00_characters.sql','EA12BB2DC24FAF2300A96D0888A45BBEA158D5DC','ARCHIVED','2015-08-08 16:34:07',0),('2015_08_12_00_characters.sql','4FD7F89FE5DA51D4E0C33E520719986AA3EBD31B','ARCHIVED','2015-08-12 12:35:20',0),('2015_09_05_00_characters.sql','4C22BB29365BE4B6B95E64DAD84B63CA002304EA','ARCHIVED','2015-09-05 12:35:20',0),('2015_09_09_00_characters.sql','AFC32E693BC17CFD9A17919FE5317B8FE337ACAD','ARCHIVED','2015-09-09 12:35:20',0),('2015_09_10_00_characters.sql','4555A7F35C107E54C13D74D20F141039ED42943E','ARCHIVED','2015-09-10 22:50:42',0),('2015_10_16_00_characters.sql','E3A3FFF0CB42F04A8DCF0CE4362143C16E2083AF','ARCHIVED','2015-10-15 21:54:11',0),('2015_11_06_00_characters_2015_10_12_00.sql','D6F9927BDED72AD0A81D6EC2C6500CBC34A39FA2','ARCHIVED','2015-11-06 23:43:27',0),('2015_11_08_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2015-11-08 00:51:45',15),('2015_11_23_00_characters.sql','9FC828E9E48E8E2E9B99A5A0073D6614C5BFC6B5','ARCHIVED','2015-11-22 23:27:34',0),('2016_01_05_00_characters.sql','0EAD24977F40DE2476B4567DA2B477867CC0DA1A','ARCHIVED','2016-01-04 23:07:40',0),('2016_04_05_00_characters_2016_02_10_00_characters.sql','F1B4DA202819CABC7319A4470A2D224A34609E97','ARCHIVED','2016-04-05 20:34:41',0),('2016_04_11_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','RELEASED','2016-04-11 02:24:14',30),('2016_04_11_01_characters.sql','CA90F6D99C1EEA7B25BD58BC8368A8D78234BBEF','RELEASED','2016-04-11 18:14:18',0),('2016_05_07_00_characters.sql','D1DB5557B21A552C935564D829B4E98B98149077','RELEASED','2016-05-07 00:00:00',0),('2016_05_26_00_characters.sql','4179ADC32B96FD8D7D4CF5509A470B1ACE00BE85','RELEASED','2016-05-26 17:06:16',0),('2016_07_16_00_characters.sql','EF267FCB92B383FFB33C700508EAF3FBC1F8AC23','RELEASED','2016-07-16 14:45:12',0),('2016_07_19_00_characters.sql','AA2C516FA81B451071EA82F58F447E9D13E5D1BD','RELEASED','2016-07-19 14:36:25',0),('2016_07_19_01_characters.sql','E9AF46AF4C7CC2E2779E44254AEEDF880D020166','RELEASED','2016-07-19 14:36:25',0),('2016_07_19_02_characters.sql','5B1B334449996F3639C9226F587129E03DC4BF6D','RELEASED','2016-07-19 14:36:26',0),('2016_07_19_03_characters.sql','7787C8A67D720492FED4BF60ADB22D3CDE1C536D','RELEASED','2016-07-19 14:36:26',0),('2016_07_19_04_characters.sql','6D4B536094367AC9EF7CDFF41A4F96EB00B25EE5','RELEASED','2016-07-19 14:36:26',0),('2016_07_19_05_characters.sql','12639268DC5F78CE900B59D5C646B10D70842928','RELEASED','2016-07-19 14:36:27',0),('2016_07_19_06_characters.sql','9F5A4B533E6BFBAA718DE5160E1FDCB8471A88BF','RELEASED','2016-07-19 14:36:28',0),('2016_07_19_07_characters.sql','1E8273FFD4340CBD7BB71D2406E23E9EF7230CFA','RELEASED','2016-07-19 14:36:29',0),('2016_07_19_08_characters.sql','FB41FD2F8A7114FEE154021A9D47488C4B12E2A9','RELEASED','2016-07-19 14:36:29',0);
+INSERT INTO `updates` VALUES ('2014_10_20_00_characters.sql','A5882DA0979CF4DAE33DA011EBAA006C24BE7230','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_23_00_characters.sql','E2AC4758133EE19B7F08464A445802154D1261C8','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_23_01_characters.sql','20029E6323D9773B32C34D84FFED1711CC60F09F','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_23_02_characters.sql','8A7A16886EE71E7ACDDB3DDA6D0ECAC2FD2FDCA8','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_24_00_characters.sql','D008FE81AE844FCA686439D6ECC5108FB0DD1EB9','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_25_00_characters.sql','A39C7BE46686B54776BDAB9D7A882D91EDEC51A4','ARCHIVED','2015-03-21 15:55:55',0),('2014_10_26_00_characters.sql','C787954CC35FE34B4101FDE6527F14C027F4947C','ARCHIVED','2015-03-21 15:55:55',0),('2014_11_12_00_characters.sql','B160BB2313F1BD5F3B076A5A9279DC10D4796E34','ARCHIVED','2015-03-21 15:55:55',0),('2014_12_23_00_characters.sql','3D9D648B2387B357F4BD090B33F80682F7924882','ARCHIVED','2015-03-21 15:55:55',0),('2014_12_28_00_characters.sql','5362922FF4483A336311D73082A5727309CD9219','ARCHIVED','2015-03-21 15:55:55',0),('2014_12_31_00_characters.sql','498DDF2DD936CF156D74A8208DC93DCE9FCAB5AA','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_02_00_characters.sql','E5940BE836F253982E07930120422E598D08BDE1','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_10_00_characters.sql','30796056C8623699B2FE1BF626A19D38262E9284','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_16_00_characters.sql','96642760A54C8D799AAFE438049A63AA521656F2','ARCHIVED','2015-03-21 15:55:55',0),('2015_01_27_00_characters.sql','EB710E3EB9F2CAFD84AB62CDC84E898403A80A4F','ARCHIVED','2015-03-21 15:55:55',0),('2015_02_13_00_characters.sql','405BEB4ED207DC6076442A37EE2AFB1F21E274A0','ARCHIVED','2015-03-21 15:55:55',0),('2015_02_13_01_characters.sql','35F582D4F33BF55D1685A1BA89273ED895FD09C5','ARCHIVED','2015-03-21 15:55:55',0),('2015_02_17_00_characters.sql','8D21FC5A55BF8B55D6DCDCE5F02CF2B640230E94','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_10_00_characters.sql','E565B89B145C340067742DFF2DEF1B74F5F1BD4E','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_20_00_characters.sql','B761760804EA73BD297F296C5C1919687DF7191C','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_20_01_characters.sql','20BD68468C57FCF7E665B4DA185DCD52FACE8B3F','ARCHIVED','2015-03-21 15:55:55',0),('2015_03_20_02_characters.sql','0296995DCD3676BA9AE6024CA7C91C5F39D927A3','ARCHIVED','2015-03-21 15:56:46',0),('2015_03_29_00_characters.sql','95D6A46BB746A8BD3EE3FE2086DF1A07F7C33B92','ARCHIVED','2015-05-02 15:43:06',0),('2015_04_21_00_characters.sql','F2032B9BF4EDA7EDE5065554724ED392FD91657D','ARCHIVED','2015-05-02 15:43:06',0),('2015_04_28_00_characters.sql','949F62DB3A3461D420A1230ECF7A6A3ED6435703','ARCHIVED','2015-05-02 15:43:06',0),('2015_05_08_00_characters.sql','0F14B7821618D1C872625B6EDDAA9A667B211167','ARCHIVED','2015-07-10 19:32:17',0),('2015_05_22_00_characters.sql','65B82152413FAB23BE413656E59A486A74447FF7','ARCHIVED','2015-07-10 19:32:17',0),('2015_07_08_00_characters.sql','DAB25360ACB5244C8F8E6214CF6BD97160588A5B','ARCHIVED','2015-07-10 19:32:17',0),('2015_07_11_00_characters.sql','B421B6C0E57BD0FD587071358863D9DABF4BA849','ARCHIVED','2015-07-13 21:50:02',0),('2015_07_12_00_characters.sql','E98E7FD61EF6426E7EDE8ED9AD8C15D8D7132589','ARCHIVED','2015-07-13 21:50:02',0),('2015_07_28_00_characters.sql','0711BC3A658D189EF71B0CB68DCFF2E9B781C4A0','ARCHIVED','2015-07-29 16:23:56',0),('2015_08_08_00_characters.sql','EA12BB2DC24FAF2300A96D0888A45BBEA158D5DC','ARCHIVED','2015-08-08 16:34:07',0),('2015_08_12_00_characters.sql','4FD7F89FE5DA51D4E0C33E520719986AA3EBD31B','ARCHIVED','2015-08-12 12:35:20',0),('2015_09_05_00_characters.sql','4C22BB29365BE4B6B95E64DAD84B63CA002304EA','ARCHIVED','2015-09-05 12:35:20',0),('2015_09_09_00_characters.sql','AFC32E693BC17CFD9A17919FE5317B8FE337ACAD','ARCHIVED','2015-09-09 12:35:20',0),('2015_09_10_00_characters.sql','4555A7F35C107E54C13D74D20F141039ED42943E','ARCHIVED','2015-09-10 22:50:42',0),('2015_10_16_00_characters.sql','E3A3FFF0CB42F04A8DCF0CE4362143C16E2083AF','ARCHIVED','2015-10-15 21:54:11',0),('2015_11_06_00_characters_2015_10_12_00.sql','D6F9927BDED72AD0A81D6EC2C6500CBC34A39FA2','ARCHIVED','2015-11-06 23:43:27',0),('2015_11_08_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','ARCHIVED','2015-11-08 00:51:45',15),('2015_11_23_00_characters.sql','9FC828E9E48E8E2E9B99A5A0073D6614C5BFC6B5','ARCHIVED','2015-11-22 23:27:34',0),('2016_01_05_00_characters.sql','0EAD24977F40DE2476B4567DA2B477867CC0DA1A','ARCHIVED','2016-01-04 23:07:40',0),('2016_04_05_00_characters_2016_02_10_00_characters.sql','F1B4DA202819CABC7319A4470A2D224A34609E97','ARCHIVED','2016-04-05 20:34:41',0),('2016_04_11_00_characters.sql','0ACDD35EC9745231BCFA701B78056DEF94D0CC53','RELEASED','2016-04-11 02:24:14',30),('2016_04_11_01_characters.sql','CA90F6D99C1EEA7B25BD58BC8368A8D78234BBEF','RELEASED','2016-04-11 18:14:18',0),('2016_05_07_00_characters.sql','D1DB5557B21A552C935564D829B4E98B98149077','RELEASED','2016-05-07 00:00:00',0),('2016_05_26_00_characters.sql','4179ADC32B96FD8D7D4CF5509A470B1ACE00BE85','RELEASED','2016-05-26 17:06:16',0),('2016_07_16_00_characters.sql','EF267FCB92B383FFB33C700508EAF3FBC1F8AC23','RELEASED','2016-07-16 14:45:12',0),('2016_07_19_00_characters.sql','AA2C516FA81B451071EA82F58F447E9D13E5D1BD','RELEASED','2016-07-19 14:36:25',0),('2016_07_19_01_characters.sql','E9AF46AF4C7CC2E2779E44254AEEDF880D020166','RELEASED','2016-07-19 14:36:25',0),('2016_07_19_02_characters.sql','5B1B334449996F3639C9226F587129E03DC4BF6D','RELEASED','2016-07-19 14:36:26',0),('2016_07_19_03_characters.sql','7787C8A67D720492FED4BF60ADB22D3CDE1C536D','RELEASED','2016-07-19 14:36:26',0),('2016_07_19_04_characters.sql','6D4B536094367AC9EF7CDFF41A4F96EB00B25EE5','RELEASED','2016-07-19 14:36:26',0),('2016_07_19_05_characters.sql','12639268DC5F78CE900B59D5C646B10D70842928','RELEASED','2016-07-19 14:36:27',0),('2016_07_19_06_characters.sql','9F5A4B533E6BFBAA718DE5160E1FDCB8471A88BF','RELEASED','2016-07-19 14:36:28',0),('2016_07_19_07_characters.sql','1E8273FFD4340CBD7BB71D2406E23E9EF7230CFA','RELEASED','2016-07-19 14:36:29',0),('2016_07_19_08_characters.sql','FB41FD2F8A7114FEE154021A9D47488C4B12E2A9','RELEASED','2016-07-19 14:36:29',0),('2016_08_15_00_characters.sql','BF0B5F453384210CD77C54E262A19B888AAA4095','RELEASED','2016-08-14 18:14:32',0);
/*!40000 ALTER TABLE `updates` ENABLE KEYS */;
UNLOCK TABLES;
diff --git a/sql/updates/characters/6.x/2016_08_15_00_characters.sql b/sql/updates/characters/6.x/2016_08_15_00_characters.sql
new file mode 100644
index 00000000000..2bc7bae21f3
--- /dev/null
+++ b/sql/updates/characters/6.x/2016_08_15_00_characters.sql
@@ -0,0 +1,36 @@
+--
+-- Table structure for table `item_instance_artifact`
+--
+DROP TABLE IF EXISTS `item_instance_artifact`;
+CREATE TABLE `item_instance_artifact` (
+ `itemGuid` bigint(20) unsigned NOT NULL,
+ `xp` int(10) unsigned NOT NULL DEFAULT '0',
+ `artifactAppearanceId` int(10) unsigned NOT NULL DEFAULT '0',
+ PRIMARY KEY (`itemGuid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `item_instance_artifact_powers`
+--
+DROP TABLE IF EXISTS `item_instance_artifact_powers`;
+CREATE TABLE `item_instance_artifact_powers` (
+ `itemGuid` bigint(20) unsigned NOT NULL,
+ `artifactPowerId` int(10) unsigned NOT NULL,
+ `purchasedRank` tinyint(3) unsigned DEFAULT '0',
+ PRIMARY KEY (`itemGuid`,`artifactPowerId`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `item_instance_modifiers`
+--
+DROP TABLE IF EXISTS `item_instance_modifiers`;
+CREATE TABLE `item_instance_modifiers` (
+ `itemGuid` bigint(20) unsigned NOT NULL,
+ `fixedScalingLevel` int(10) unsigned DEFAULT '0',
+ `artifactKnowledgeLevel` int(10) unsigned DEFAULT '0',
+ PRIMARY KEY (`itemGuid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+ALTER TABLE `character_void_storage`
+ ADD `fixedScalingLevel` int(10) unsigned DEFAULT '0' AFTER `upgradeId`,
+ ADD `artifactKnowledgeLevel` int(10) unsigned DEFAULT '0' AFTER `fixedScalingLevel`;
diff --git a/sql/updates/hotfixes/6.x/2016_08_15_00_hotfixes.sql b/sql/updates/hotfixes/6.x/2016_08_15_00_hotfixes.sql
new file mode 100644
index 00000000000..8c8a9df6f63
--- /dev/null
+++ b/sql/updates/hotfixes/6.x/2016_08_15_00_hotfixes.sql
@@ -0,0 +1,182 @@
+--
+-- Table structure for table `artifact`
+--
+DROP TABLE IF EXISTS `artifact`;
+CREATE TABLE `artifact` (
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `Name` text,
+ `BarConnectedColor` int(10) unsigned NOT NULL DEFAULT '0',
+ `BarDisconnectedColor` int(10) unsigned NOT NULL DEFAULT '0',
+ `TitleColor` int(10) unsigned NOT NULL DEFAULT '0',
+ `ClassUiTextureKitID` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `SpecID` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `ArtifactCategoryID` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `Flags` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `artifact_locale`
+--
+DROP TABLE IF EXISTS `artifact_locale`;
+CREATE TABLE `artifact_locale` (
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `locale` varchar(4) NOT NULL,
+ `Name_lang` text,
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`,`locale`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `artifact_appearance`
+--
+DROP TABLE IF EXISTS `artifact_appearance`;
+CREATE TABLE `artifact_appearance` (
+ `Name` text,
+ `SwatchColor` int(10) unsigned NOT NULL DEFAULT '0',
+ `ModelDesaturation` float NOT NULL DEFAULT '0',
+ `ModelAlpha` float NOT NULL DEFAULT '0',
+ `ShapeshiftDisplayID` int(10) unsigned NOT NULL DEFAULT '0',
+ `ArtifactAppearanceSetID` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `PlayerConditionID` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `Unknown` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `DisplayIndex` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `AppearanceModID` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `Flags` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `ModifiesShapeshiftFormDisplay` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `ItemAppearanceID` int(10) unsigned NOT NULL DEFAULT '0',
+ `AltItemAppearanceID` int(10) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `artifact_appearance_locale`
+--
+DROP TABLE IF EXISTS `artifact_appearance_locale`;
+CREATE TABLE `artifact_appearance_locale` (
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `locale` varchar(4) NOT NULL,
+ `Name_lang` text,
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`,`locale`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `artifact_appearance_set`
+--
+DROP TABLE IF EXISTS `artifact_appearance_set`;
+CREATE TABLE `artifact_appearance_set` (
+ `Name` text,
+ `Name2` text,
+ `UiCameraID` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `AltHandUICameraID` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `ArtifactID` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `DisplayIndex` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `AttachmentPoint` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `Flags` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `artifact_appearance_set_locale`
+--
+DROP TABLE IF EXISTS `artifact_appearance_set_locale`;
+CREATE TABLE `artifact_appearance_set_locale` (
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `locale` varchar(4) NOT NULL,
+ `Name_lang` text,
+ `Name2_lang` text,
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`,`locale`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `artifact_category`
+--
+DROP TABLE IF EXISTS `artifact_category`;
+CREATE TABLE `artifact_category` (
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `ArtifactKnowledgeCurrencyID` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `ArtifactKnowledgeMultiplierCurveID` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `artifact_power`
+--
+DROP TABLE IF EXISTS `artifact_power`;
+CREATE TABLE `artifact_power` (
+ `PosX` float NOT NULL DEFAULT '0',
+ `PosY` float NOT NULL DEFAULT '0',
+ `ArtifactID` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `Flags` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `MaxRank` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `RelicType` int(10) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `artifact_power_link`
+--
+DROP TABLE IF EXISTS `artifact_power_link`;
+CREATE TABLE `artifact_power_link` (
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `FromArtifactPowerID` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `ToArtifactPowerID` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `artifact_power_rank`
+--
+DROP TABLE IF EXISTS `artifact_power_rank`;
+CREATE TABLE `artifact_power_rank` (
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `SpellID` int(10) unsigned NOT NULL DEFAULT '0',
+ `Value` float NOT NULL DEFAULT '0',
+ `ArtifactPowerID` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `Unknown` smallint(5) unsigned NOT NULL DEFAULT '0',
+ `Rank` tinyint(3) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `artifact_quest_xp`
+--
+DROP TABLE IF EXISTS `artifact_quest_xp`;
+CREATE TABLE `artifact_quest_xp` (
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `Exp1` int(10) unsigned NOT NULL DEFAULT '0',
+ `Exp2` int(10) unsigned NOT NULL DEFAULT '0',
+ `Exp3` int(10) unsigned NOT NULL DEFAULT '0',
+ `Exp4` int(10) unsigned NOT NULL DEFAULT '0',
+ `Exp5` int(10) unsigned NOT NULL DEFAULT '0',
+ `Exp6` int(10) unsigned NOT NULL DEFAULT '0',
+ `Exp7` int(10) unsigned NOT NULL DEFAULT '0',
+ `Exp8` int(10) unsigned NOT NULL DEFAULT '0',
+ `Exp9` int(10) unsigned NOT NULL DEFAULT '0',
+ `Exp10` int(10) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `item_bonus_list_level_delta`
+--
+DROP TABLE IF EXISTS `item_bonus_list_level_delta`;
+CREATE TABLE `item_bonus_list_level_delta` (
+ `Delta` smallint(6) NOT NULL DEFAULT '0',
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
diff --git a/sql/updates/world/6.x/2016_08_15_00_world.sql b/sql/updates/world/6.x/2016_08_15_00_world.sql
new file mode 100644
index 00000000000..7253a22ea73
--- /dev/null
+++ b/sql/updates/world/6.x/2016_08_15_00_world.sql
@@ -0,0 +1,6 @@
+DELETE FROM `spell_script_names` WHERE `ScriptName` IN ('spell_item_artifical_stamina','spell_item_artifical_damage');
+INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES
+(211309,'spell_item_artifical_stamina'),
+(213428,'spell_item_artifical_damage'),
+(219655,'spell_item_artifical_damage'),
+(226829,'spell_item_artifical_damage');
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index daa75e5cae8..0380cd45c2f 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -26,7 +26,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
"ii.durability, ii.playedTime, ii.text, ii.upgradeId, ii.battlePetSpeciesId, ii.battlePetBreedData, ii.battlePetLevel, ii.battlePetDisplayId, ii.bonusListIDs, " \
"iit.itemModifiedAppearanceAllSpecs, iit.itemModifiedAppearanceSpec1, iit.itemModifiedAppearanceSpec2, iit.itemModifiedAppearanceSpec3, iit.itemModifiedAppearanceSpec4, " \
"iit.spellItemEnchantmentAllSpecs, iit.spellItemEnchantmentSpec1, iit.spellItemEnchantmentSpec2, iit.spellItemEnchantmentSpec3, iit.spellItemEnchantmentSpec4, " \
- "ig.gemItemId1, ig.gemBonuses1, ig.gemContext1, ig.gemItemId2, ig.gemBonuses2, ig.gemContext2, ig.gemItemId3, ig.gemBonuses3, ig.gemContext3"
+ "ig.gemItemId1, ig.gemBonuses1, ig.gemContext1, ig.gemItemId2, ig.gemBonuses2, ig.gemContext2, ig.gemItemId3, ig.gemBonuses3, ig.gemContext3, " \
+ "im.fixedScalingLevel, im.artifactKnowledgeLevel"
PrepareStatement(CHAR_DEL_QUEST_POOL_SAVE, "DELETE FROM pool_quest_save WHERE pool_id = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_QUEST_POOL_SAVE, "INSERT INTO pool_quest_save (pool_id, quest_id) VALUES (?, ?)", CONNECTION_ASYNC);
@@ -112,7 +113,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT, "DELETE FROM character_queststatus_seasonal WHERE event = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_SEL_CHARACTER_INVENTORY, "SELECT " SelectItemInstanceContent ", bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid WHERE ci.guid = ? ORDER BY bag, slot", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_CHARACTER_INVENTORY, "SELECT " SelectItemInstanceContent ", bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid WHERE ci.guid = ? ORDER BY bag, slot", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS, "SELECT a.button, a.action, a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.spec = c.activeTalentGroup AND a.guid = ? ORDER BY button", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_MAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = ? AND (checked & 1) = 0 AND deliver_time <= ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_MAILDATE, "SELECT MIN(deliver_time) FROM mail WHERE receiver = ? AND (checked & 1) = 0", CONNECTION_ASYNC);
@@ -142,8 +143,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES, "SELECT instanceId, releaseTime FROM account_instance_times WHERE accountId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC, "SELECT button, action, type FROM character_action WHERE guid = ? AND spec = ? ORDER BY button", CONNECTION_SYNCH);
- PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT " SelectItemInstanceContent ", ii.owner_guid FROM mail_items mi JOIN item_instance ii ON mi.item_guid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid WHERE mail_id = ?", CONNECTION_SYNCH);
- PrepareStatement(CHAR_SEL_AUCTION_ITEMS, "SELECT " SelectItemInstanceContent " FROM auctionhouse ah JOIN item_instance ii ON ah.itemguid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT " SelectItemInstanceContent ", ii.owner_guid FROM mail_items mi JOIN item_instance ii ON mi.item_guid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid WHERE mail_id = ?", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_AUCTION_ITEMS, "SELECT " SelectItemInstanceContent " FROM auctionhouse ah JOIN item_instance ii ON ah.itemguid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid", CONNECTION_SYNCH);
PrepareStatement(CHAR_SEL_AUCTIONS, "SELECT id, auctioneerguid, itemguid, itemEntry, count, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit FROM auctionhouse ah INNER JOIN item_instance ii ON ii.guid = ah.itemguid", CONNECTION_SYNCH);
PrepareStatement(CHAR_INS_AUCTION, "INSERT INTO auctionhouse (id, auctioneerguid, itemguid, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_AUCTION, "DELETE FROM auctionhouse WHERE id = ?", CONNECTION_ASYNC);
@@ -177,6 +178,16 @@ void CharacterDatabaseConnection::DoPrepareStatements()
"spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_ITEM_INSTANCE_TRANSMOG, "DELETE FROM item_instance_transmog WHERE itemGuid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_ITEM_INSTANCE_TRANSMOG_BY_OWNER, "DELETE iit FROM item_instance_transmog iit LEFT JOIN item_instance ii ON iit.itemGuid = ii.guid WHERE ii.owner_guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_ITEM_INSTANCE_ARTIFACT, "SELECT a.itemGuid, a.xp, a.artifactAppearanceId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid INNER JOIN character_inventory ci ON ci.item = ap.itemGuid WHERE ci.guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_ITEM_INSTANCE_ARTIFACT, "INSERT INTO item_instance_artifact (itemGuid, xp, artifactAppearanceId) VALUES (?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT, "DELETE FROM item_instance_artifact WHERE itemGuid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_BY_OWNER, "DELETE iia FROM item_instance_artifact iia LEFT JOIN item_instance ii ON iia.itemGuid = ii.guid WHERE ii.owner_guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_ITEM_INSTANCE_ARTIFACT_POWERS, "INSERT INTO item_instance_artifact_powers (itemGuid, artifactPowerId, purchasedRank) VALUES (?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS, "DELETE FROM item_instance_artifact_powers WHERE itemGuid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS_BY_OWNER, "DELETE iiap FROM item_instance_artifact_powers iiap LEFT JOIN item_instance ii ON iiap.itemGuid = ii.guid WHERE ii.owner_guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_ITEM_INSTANCE_MODIFIERS, "INSERT INTO item_instance_modifiers (itemGuid, fixedScalingLevel, artifactKnowledgeLevel) VALUES (?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS, "DELETE FROM item_instance_modifiers WHERE itemGuid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS_BY_OWNER, "DELETE im FROM item_instance_modifiers im LEFT JOIN item_instance ii ON im.itemGuid = ii.guid WHERE ii.owner_guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_GIFT_OWNER, "UPDATE character_gifts SET guid = ? WHERE item_guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_GIFT, "DELETE FROM character_gifts WHERE item_guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_GIFT_BY_ITEM, "SELECT entry, flags FROM character_gifts WHERE item_guid = ?", CONNECTION_SYNCH);
@@ -208,7 +219,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
// 0: uint32, 1: uint8, 2: uint8, 3: uint32, 4: uint32
PrepareStatement(CHAR_INS_GUILD_BANK_ITEM, "INSERT INTO guild_bank_item (guildid, TabId, SlotId, item_guid) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_GUILD_BANK_ITEM, "DELETE FROM guild_bank_item WHERE guildid = ? AND TabId = ? AND SlotId = ?", CONNECTION_ASYNC); // 0: uint32, 1: uint8, 2: uint8
- PrepareStatement(CHAR_SEL_GUILD_BANK_ITEMS, "SELECT " SelectItemInstanceContent ", guildid, TabId, SlotId FROM guild_bank_item gbi INNER JOIN item_instance ii ON gbi.item_guid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid", CONNECTION_SYNCH);
+ PrepareStatement(CHAR_SEL_GUILD_BANK_ITEMS, "SELECT " SelectItemInstanceContent ", guildid, TabId, SlotId FROM guild_bank_item gbi INNER JOIN item_instance ii ON gbi.item_guid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid", CONNECTION_SYNCH);
PrepareStatement(CHAR_DEL_GUILD_BANK_ITEMS, "DELETE FROM guild_bank_item WHERE guildid = ?", CONNECTION_ASYNC); // 0: uint32
// 0: uint32, 1: uint8, 2: uint8, 3: uint8, 4: uint32
PrepareStatement(CHAR_INS_GUILD_BANK_RIGHT, "INSERT INTO guild_bank_right (guildid, TabId, rid, gbright, SlotPerDay) VALUES (?, ?, ?, ?, ?) "
@@ -606,8 +617,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_UPD_CHAR_LIST_SLOT, "UPDATE characters SET slot = ? WHERE guid = ? AND account = ?", CONNECTION_ASYNC);
// Void Storage
- PrepareStatement(CHAR_SEL_CHAR_VOID_STORAGE, "SELECT itemId, itemEntry, slot, creatorGuid, randomProperty, suffixFactor, upgradeId, bonusListIDs FROM character_void_storage WHERE playerGuid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_REP_CHAR_VOID_STORAGE_ITEM, "REPLACE INTO character_void_storage (itemId, playerGuid, itemEntry, slot, creatorGuid, randomProperty, suffixFactor, upgradeId, bonusListIDs) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_CHAR_VOID_STORAGE, "SELECT itemId, itemEntry, slot, creatorGuid, randomProperty, suffixFactor, upgradeId, fixedScalingLevel, artifactKnowledgeLevel, bonusListIDs FROM character_void_storage WHERE playerGuid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_REP_CHAR_VOID_STORAGE_ITEM, "REPLACE INTO character_void_storage (itemId, playerGuid, itemEntry, slot, creatorGuid, randomProperty, suffixFactor, upgradeId, fixedScalingLevel, artifactKnowledgeLevel, bonusListIDs) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_VOID_STORAGE_ITEM_BY_CHAR_GUID, "DELETE FROM character_void_storage WHERE playerGuid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_VOID_STORAGE_ITEM_BY_SLOT, "DELETE FROM character_void_storage WHERE slot = ? AND playerGuid = ?", CONNECTION_ASYNC);
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h
index e58debb7939..a8c26cdc316 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.h
+++ b/src/server/database/Database/Implementation/CharacterDatabase.h
@@ -150,6 +150,16 @@ enum CharacterDatabaseStatements
CHAR_INS_ITEM_INSTANCE_TRANSMOG,
CHAR_DEL_ITEM_INSTANCE_TRANSMOG,
CHAR_DEL_ITEM_INSTANCE_TRANSMOG_BY_OWNER,
+ CHAR_SEL_ITEM_INSTANCE_ARTIFACT,
+ CHAR_INS_ITEM_INSTANCE_ARTIFACT,
+ CHAR_DEL_ITEM_INSTANCE_ARTIFACT,
+ CHAR_DEL_ITEM_INSTANCE_ARTIFACT_BY_OWNER,
+ CHAR_INS_ITEM_INSTANCE_ARTIFACT_POWERS,
+ CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS,
+ CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS_BY_OWNER,
+ CHAR_INS_ITEM_INSTANCE_MODIFIERS,
+ CHAR_DEL_ITEM_INSTANCE_MODIFIERS,
+ CHAR_DEL_ITEM_INSTANCE_MODIFIERS_BY_OWNER,
CHAR_UPD_GIFT_OWNER,
CHAR_DEL_GIFT,
CHAR_SEL_CHARACTER_GIFT_BY_ITEM,
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp
index 65d1b825570..b62d54626f6 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.cpp
+++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp
@@ -55,6 +55,40 @@ void HotfixDatabaseConnection::DoPrepareStatements()
// ArmorLocation.db2
PrepareStatement(HOTFIX_SEL_ARMOR_LOCATION, "SELECT ID, Modifier1, Modifier2, Modifier3, Modifier4, Modifier5 FROM armor_location ORDER BY ID DESC", CONNECTION_SYNCH);
+ // Artifact.db2
+ PrepareStatement(HOTFIX_SEL_ARTIFACT, "SELECT ID, Name, BarConnectedColor, BarDisconnectedColor, TitleColor, ClassUiTextureKitID, SpecID, "
+ "ArtifactCategoryID, Flags FROM artifact ORDER BY ID DESC", CONNECTION_SYNCH);
+ PREPARE_LOCALE_STMT(HOTFIX_SEL_ARTIFACT, "SELECT ID, Name_lang FROM artifact_locale WHERE locale = ?", CONNECTION_SYNCH);
+
+ // ArtifactAppearance.db2
+ PrepareStatement(HOTFIX_SEL_ARTIFACT_APPEARANCE, "SELECT Name, SwatchColor, ModelDesaturation, ModelAlpha, ShapeshiftDisplayID, "
+ "ArtifactAppearanceSetID, PlayerConditionID, Unknown, DisplayIndex, AppearanceModID, Flags, ModifiesShapeshiftFormDisplay, ID, "
+ "ItemAppearanceID, AltItemAppearanceID FROM artifact_appearance ORDER BY ID DESC", CONNECTION_SYNCH);
+ PREPARE_LOCALE_STMT(HOTFIX_SEL_ARTIFACT_APPEARANCE, "SELECT ID, Name_lang FROM artifact_appearance_locale WHERE locale = ?", CONNECTION_SYNCH);
+
+ // ArtifactAppearanceSet.db2
+ PrepareStatement(HOTFIX_SEL_ARTIFACT_APPEARANCE_SET, "SELECT Name, Name2, UiCameraID, AltHandUICameraID, ArtifactID, DisplayIndex, "
+ "AttachmentPoint, Flags, ID FROM artifact_appearance_set ORDER BY ID DESC", CONNECTION_SYNCH);
+ PREPARE_LOCALE_STMT(HOTFIX_SEL_ARTIFACT_APPEARANCE_SET, "SELECT ID, Name_lang, Name2_lang FROM artifact_appearance_set_locale WHERE locale = ?", CONNECTION_SYNCH);
+
+ // ArtifactCategory.db2
+ PrepareStatement(HOTFIX_SEL_ARTIFACT_CATEGORY, "SELECT ID, ArtifactKnowledgeCurrencyID, ArtifactKnowledgeMultiplierCurveID FROM artifact_category"
+ " ORDER BY ID DESC", CONNECTION_SYNCH);
+
+ // ArtifactPower.db2
+ PrepareStatement(HOTFIX_SEL_ARTIFACT_POWER, "SELECT PosX, PosY, ArtifactID, Flags, MaxRank, ID, RelicType FROM artifact_power ORDER BY ID DESC", CONNECTION_SYNCH);
+
+ // ArtifactPowerLink.db2
+ PrepareStatement(HOTFIX_SEL_ARTIFACT_POWER_LINK, "SELECT ID, FromArtifactPowerID, ToArtifactPowerID FROM artifact_power_link ORDER BY ID DESC", CONNECTION_SYNCH);
+
+ // ArtifactPowerRank.db2
+ PrepareStatement(HOTFIX_SEL_ARTIFACT_POWER_RANK, "SELECT ID, SpellID, Value, ArtifactPowerID, Unknown, Rank FROM artifact_power_rank"
+ " ORDER BY ID DESC", CONNECTION_SYNCH);
+
+ // ArtifactQuestXp.db2
+ PrepareStatement(HOTFIX_SEL_ARTIFACT_QUEST_XP, "SELECT ID, Exp1, Exp2, Exp3, Exp4, Exp5, Exp6, Exp7, Exp8, Exp9, Exp10 FROM artifact_quest_xp"
+ " ORDER BY ID DESC", CONNECTION_SYNCH);
+
// AuctionHouse.db2
PrepareStatement(HOTFIX_SEL_AUCTION_HOUSE, "SELECT ID, Name, FactionID, DepositRate, ConsignmentRate FROM auction_house ORDER BY ID DESC", CONNECTION_SYNCH);
PREPARE_LOCALE_STMT(HOTFIX_SEL_AUCTION_HOUSE, "SELECT ID, Name_lang FROM auction_house_locale WHERE locale = ?", CONNECTION_SYNCH);
@@ -377,6 +411,9 @@ void HotfixDatabaseConnection::DoPrepareStatements()
// ItemBonus.db2
PrepareStatement(HOTFIX_SEL_ITEM_BONUS, "SELECT ID, Value1, Value2, BonusListID, Type, `Index` FROM item_bonus ORDER BY ID DESC", CONNECTION_SYNCH);
+ // ItemBonusListLevelDelta.db2
+ PrepareStatement(HOTFIX_SEL_ITEM_BONUS_LIST_LEVEL_DELTA, "SELECT Delta, ID FROM item_bonus_list_level_delta ORDER BY ID DESC", CONNECTION_SYNCH);
+
// ItemBonusTreeNode.db2
PrepareStatement(HOTFIX_SEL_ITEM_BONUS_TREE_NODE, "SELECT ID, BonusTreeID, SubTreeID, BonusListID, BonusTreeModID FROM item_bonus_tree_node"
" ORDER BY ID DESC", CONNECTION_SYNCH);
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h
index 1b6fef8b5d0..f209c0d569b 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.h
+++ b/src/server/database/Database/Implementation/HotfixDatabase.h
@@ -46,6 +46,25 @@ enum HotfixDatabaseStatements
HOTFIX_SEL_ARMOR_LOCATION,
+ HOTFIX_SEL_ARTIFACT,
+ HOTFIX_SEL_ARTIFACT_LOCALE,
+
+ HOTFIX_SEL_ARTIFACT_APPEARANCE,
+ HOTFIX_SEL_ARTIFACT_APPEARANCE_LOCALE,
+
+ HOTFIX_SEL_ARTIFACT_APPEARANCE_SET,
+ HOTFIX_SEL_ARTIFACT_APPEARANCE_SET_LOCALE,
+
+ HOTFIX_SEL_ARTIFACT_CATEGORY,
+
+ HOTFIX_SEL_ARTIFACT_POWER,
+
+ HOTFIX_SEL_ARTIFACT_POWER_LINK,
+
+ HOTFIX_SEL_ARTIFACT_POWER_RANK,
+
+ HOTFIX_SEL_ARTIFACT_QUEST_XP,
+
HOTFIX_SEL_AUCTION_HOUSE,
HOTFIX_SEL_AUCTION_HOUSE_LOCALE,
@@ -215,6 +234,8 @@ enum HotfixDatabaseStatements
HOTFIX_SEL_ITEM_BONUS,
+ HOTFIX_SEL_ITEM_BONUS_LIST_LEVEL_DELTA,
+
HOTFIX_SEL_ITEM_BONUS_TREE_NODE,
HOTFIX_SEL_ITEM_CHILD_EQUIPMENT,
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index c1ebbd4cd4c..a893bcc5ece 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -30,6 +30,14 @@ DB2Storage<AreaGroupMemberEntry> sAreaGroupMemberStore("AreaGroup
DB2Storage<AreaTableEntry> sAreaTableStore("AreaTable.db2", AreaTableMeta::Instance(), HOTFIX_SEL_AREA_TABLE);
DB2Storage<AreaTriggerEntry> sAreaTriggerStore("AreaTrigger.db2", AreaTriggerMeta::Instance(), HOTFIX_SEL_AREA_TRIGGER);
DB2Storage<ArmorLocationEntry> sArmorLocationStore("ArmorLocation.db2", ArmorLocationMeta::Instance(), HOTFIX_SEL_ARMOR_LOCATION);
+DB2Storage<ArtifactEntry> sArtifactStore("Artifact.db2", ArtifactMeta::Instance(), HOTFIX_SEL_ARTIFACT);
+DB2Storage<ArtifactAppearanceEntry> sArtifactAppearanceStore("ArtifactAppearance.db2", ArtifactAppearanceMeta::Instance(), HOTFIX_SEL_ARTIFACT_APPEARANCE);
+DB2Storage<ArtifactAppearanceSetEntry> sArtifactAppearanceSetStore("ArtifactAppearanceSet.db2", ArtifactAppearanceSetMeta::Instance(), HOTFIX_SEL_ARTIFACT_APPEARANCE_SET);
+DB2Storage<ArtifactCategoryEntry> sArtifactCategoryStore("ArtifactCategory.db2", ArtifactCategoryMeta::Instance(), HOTFIX_SEL_ARTIFACT_CATEGORY);
+DB2Storage<ArtifactPowerEntry> sArtifactPowerStore("ArtifactPower.db2", ArtifactPowerMeta::Instance(), HOTFIX_SEL_ARTIFACT_POWER);
+DB2Storage<ArtifactPowerLinkEntry> sArtifactPowerLinkStore("ArtifactPowerLink.db2", ArtifactPowerLinkMeta::Instance(), HOTFIX_SEL_ARTIFACT_POWER_LINK);
+DB2Storage<ArtifactPowerRankEntry> sArtifactPowerRankStore("ArtifactPowerRank.db2", ArtifactPowerRankMeta::Instance(), HOTFIX_SEL_ARTIFACT_POWER_RANK);
+DB2Storage<ArtifactQuestXPEntry> sArtifactQuestXPStore("ArtifactQuestXP.db2", ArtifactQuestXPMeta::Instance(), HOTFIX_SEL_ARTIFACT_QUEST_XP);
DB2Storage<AuctionHouseEntry> sAuctionHouseStore("AuctionHouse.db2", AuctionHouseMeta::Instance(), HOTFIX_SEL_AUCTION_HOUSE);
DB2Storage<BankBagSlotPricesEntry> sBankBagSlotPricesStore("BankBagSlotPrices.db2", BankBagSlotPricesMeta::Instance(), HOTFIX_SEL_BANK_BAG_SLOT_PRICES);
DB2Storage<BannedAddOnsEntry> sBannedAddOnsStore("BannedAddOns.db2", BannedAddOnsMeta::Instance(), HOTFIX_SEL_BANNED_ADDONS);
@@ -100,6 +108,7 @@ DB2Storage<ItemArmorShieldEntry> sItemArmorShieldStore("ItemArmor
DB2Storage<ItemArmorTotalEntry> sItemArmorTotalStore("ItemArmorTotal.db2", ItemArmorTotalMeta::Instance(), HOTFIX_SEL_ITEM_ARMOR_TOTAL);
DB2Storage<ItemBagFamilyEntry> sItemBagFamilyStore("ItemBagFamily.db2", ItemBagFamilyMeta::Instance(), HOTFIX_SEL_ITEM_BAG_FAMILY);
DB2Storage<ItemBonusEntry> sItemBonusStore("ItemBonus.db2", ItemBonusMeta::Instance(), HOTFIX_SEL_ITEM_BONUS);
+DB2Storage<ItemBonusListLevelDeltaEntry> sItemBonusListLevelDeltaStore("ItemBonusListLevelDelta.db2", ItemBonusListLevelDeltaMeta::Instance(), HOTFIX_SEL_ITEM_BONUS_LIST_LEVEL_DELTA);
DB2Storage<ItemBonusTreeNodeEntry> sItemBonusTreeNodeStore("ItemBonusTreeNode.db2", ItemBonusTreeNodeMeta::Instance(), HOTFIX_SEL_ITEM_BONUS_TREE_NODE);
DB2Storage<ItemChildEquipmentEntry> sItemChildEquipmentStore("ItemChildEquipment.db2", ItemChildEquipmentMeta::Instance(), HOTFIX_SEL_ITEM_CHILD_EQUIPMENT);
DB2Storage<ItemClassEntry> sItemClassStore("ItemClass.db2", ItemClassMeta::Instance(), HOTFIX_SEL_ITEM_CLASS);
@@ -293,6 +302,13 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
LOAD_DB2(sAreaTableStore);
LOAD_DB2(sAreaTriggerStore);
LOAD_DB2(sArmorLocationStore);
+ LOAD_DB2(sArtifactStore);
+ LOAD_DB2(sArtifactAppearanceStore);
+ LOAD_DB2(sArtifactAppearanceSetStore);
+ LOAD_DB2(sArtifactCategoryStore);
+ LOAD_DB2(sArtifactPowerStore);
+ LOAD_DB2(sArtifactPowerLinkStore);
+ LOAD_DB2(sArtifactPowerRankStore);
LOAD_DB2(sAuctionHouseStore);
LOAD_DB2(sBankBagSlotPricesStore);
LOAD_DB2(sBannedAddOnsStore);
@@ -363,6 +379,7 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
LOAD_DB2(sItemArmorTotalStore);
LOAD_DB2(sItemBagFamilyStore);
LOAD_DB2(sItemBonusStore);
+ LOAD_DB2(sItemBonusListLevelDeltaStore);
LOAD_DB2(sItemBonusTreeNodeStore);
LOAD_DB2(sItemChildEquipmentStore);
LOAD_DB2(sItemClassStore);
@@ -482,6 +499,18 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
for (AreaGroupMemberEntry const* areaGroupMember : sAreaGroupMemberStore)
_areaGroupMembers[areaGroupMember->AreaGroupID].push_back(areaGroupMember->AreaID);
+ for (ArtifactPowerEntry const* artifactPower : sArtifactPowerStore)
+ _artifactPowers[artifactPower->ArtifactID].push_back(artifactPower);
+
+ for (ArtifactPowerLinkEntry const* artifactPowerLink : sArtifactPowerLinkStore)
+ {
+ _artifactPowerLinks[artifactPowerLink->FromArtifactPowerID].insert(artifactPowerLink->ToArtifactPowerID);
+ _artifactPowerLinks[artifactPowerLink->ToArtifactPowerID].insert(artifactPowerLink->FromArtifactPowerID);
+ }
+
+ for (ArtifactPowerRankEntry const* artifactPowerRank : sArtifactPowerRankStore)
+ _artifactPowerRanks[std::pair<uint32, uint8>{ artifactPowerRank->ArtifactPowerID, artifactPowerRank->Rank }] = artifactPowerRank;
+
std::unordered_map<uint32, std::set<std::pair<uint8, uint8>>> addedSections;
for (CharSectionsEntry const* charSection : sCharSectionsStore)
{
@@ -601,6 +630,9 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
for (ItemBonusEntry const* bonus : sItemBonusStore)
_itemBonusLists[bonus->BonusListID].push_back(bonus);
+ for (ItemBonusListLevelDeltaEntry const* itemBonusListLevelDelta : sItemBonusListLevelDeltaStore)
+ _itemLevelDeltaToBonusListContainer[itemBonusListLevelDelta->Delta] = itemBonusListLevelDelta->ID;
+
for (ItemBonusTreeNodeEntry const* bonusTreeNode : sItemBonusTreeNodeStore)
{
uint32 bonusTreeId = bonusTreeNode->BonusTreeID;
@@ -918,6 +950,33 @@ std::vector<uint32> DB2Manager::GetAreasForGroup(uint32 areaGroupId) const
return std::vector<uint32>();
}
+std::vector<ArtifactPowerEntry const*> DB2Manager::GetArtifactPowers(uint8 artifactId) const
+{
+ auto itr = _artifactPowers.find(artifactId);
+ if (itr != _artifactPowers.end())
+ return itr->second;
+
+ return std::vector<ArtifactPowerEntry const*>{};
+}
+
+std::unordered_set<uint32> const* DB2Manager::GetArtifactPowerLinks(uint32 artifactPowerId) const
+{
+ auto itr = _artifactPowerLinks.find(artifactPowerId);
+ if (itr != _artifactPowerLinks.end())
+ return &itr->second;
+
+ return nullptr;
+}
+
+ArtifactPowerRankEntry const* DB2Manager::GetArtifactPowerRank(uint32 artifactPowerId, uint8 rank) const
+{
+ auto itr = _artifactPowerRanks.find({ artifactPowerId, rank });
+ if (itr != _artifactPowerRanks.end())
+ return itr->second;
+
+ return nullptr;
+}
+
char const* DB2Manager::GetBroadcastTextValue(BroadcastTextEntry const* broadcastText, LocaleConstant locale /*= DEFAULT_LOCALE*/, uint8 gender /*= GENDER_MALE*/, bool forceGender /*= false*/)
{
if (gender == GENDER_FEMALE && (forceGender || broadcastText->FemaleText->Str[DEFAULT_LOCALE][0] != '\0'))
@@ -1195,6 +1254,15 @@ DB2Manager::ItemBonusList const* DB2Manager::GetItemBonusList(uint32 bonusListId
return nullptr;
}
+uint32 DB2Manager::GetItemBonusListForItemLevelDelta(int16 delta) const
+{
+ auto itr = _itemLevelDeltaToBonusListContainer.find(delta);
+ if (itr != _itemLevelDeltaToBonusListContainer.end())
+ return itr->second;
+
+ return 0;
+}
+
std::set<uint32> DB2Manager::GetItemBonusTree(uint32 itemId, uint32 itemBonusTreeMod) const
{
std::set<uint32> bonusListIDs;
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index f5aff6432a7..b8e5569ec9b 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -28,6 +28,11 @@ TC_GAME_API extern DB2Storage<AnimKitEntry> sAnimKitStor
TC_GAME_API extern DB2Storage<AreaTableEntry> sAreaTableStore;
TC_GAME_API extern DB2Storage<AreaTriggerEntry> sAreaTriggerStore;
TC_GAME_API extern DB2Storage<ArmorLocationEntry> sArmorLocationStore;
+TC_GAME_API extern DB2Storage<ArtifactEntry> sArtifactStore;
+TC_GAME_API extern DB2Storage<ArtifactCategoryEntry> sArtifactCategoryStore;
+TC_GAME_API extern DB2Storage<ArtifactAppearanceEntry> sArtifactAppearanceStore;
+TC_GAME_API extern DB2Storage<ArtifactAppearanceSetEntry> sArtifactAppearanceSetStore;
+TC_GAME_API extern DB2Storage<ArtifactPowerEntry> sArtifactPowerStore;
TC_GAME_API extern DB2Storage<AuctionHouseEntry> sAuctionHouseStore;
TC_GAME_API extern DB2Storage<BankBagSlotPricesEntry> sBankBagSlotPricesStore;
TC_GAME_API extern DB2Storage<BannedAddOnsEntry> sBannedAddOnsStore;
@@ -208,7 +213,7 @@ struct HotfixNotify
typedef std::vector<HotfixNotify> HotfixData;
#define DEFINE_DB2_SET_COMPARATOR(structure) \
- struct structure ## Comparator : public std::binary_function<structure const*, structure const*, bool> \
+ struct structure ## Comparator \
{ \
bool operator()(structure const* left, structure const* right) const { return Compare(left, right); } \
static bool Compare(structure const* left, structure const* right); \
@@ -217,11 +222,14 @@ typedef std::vector<HotfixNotify> HotfixData;
class TC_GAME_API DB2Manager
{
public:
- DEFINE_DB2_SET_COMPARATOR(ChrClassesXPowerTypesEntry);
- DEFINE_DB2_SET_COMPARATOR(MountTypeXCapabilityEntry);
+ DEFINE_DB2_SET_COMPARATOR(ChrClassesXPowerTypesEntry)
+ DEFINE_DB2_SET_COMPARATOR(MountTypeXCapabilityEntry)
typedef std::map<uint32 /*hash*/, DB2StorageBase*> StorageMap;
typedef std::unordered_map<uint32 /*areaGroupId*/, std::vector<uint32/*areaId*/>> AreaGroupMemberContainer;
+ typedef std::unordered_map<uint32, std::vector<ArtifactPowerEntry const*>> ArtifactPowersContainer;
+ typedef std::unordered_map<uint32, std::unordered_set<uint32>> ArtifactPowerLinksContainer;
+ typedef std::unordered_map<std::pair<uint32, uint8>, ArtifactPowerRankEntry const*> ArtifactPowerRanksContainer;
typedef std::unordered_multimap<uint32, CharSectionsEntry const*> CharSectionsContainer;
typedef std::unordered_map<uint32, CharStartOutfitEntry const*> CharStartOutfitContainer;
typedef ChrSpecializationEntry const* ChrSpecializationByIndexContainer[MAX_CLASSES + 1][MAX_SPECIALIZATIONS];
@@ -231,6 +239,7 @@ public:
typedef std::unordered_map<uint32, HeirloomEntry const*> HeirloomItemsContainer;
typedef std::vector<ItemBonusEntry const*> ItemBonusList;
typedef std::unordered_map<uint32 /*bonusListId*/, ItemBonusList> ItemBonusListContainer;
+ typedef std::unordered_map<int16, uint32> ItemBonusListLevelDeltaContainer;
typedef std::unordered_multimap<uint32 /*itemId*/, uint32 /*bonusTreeId*/> ItemToBonusTreeContainer;
typedef std::unordered_map<uint32 /*itemId*/, ItemChildEquipmentEntry const*> ItemChildEquipmentContainer;
typedef std::unordered_map<uint32 /*itemId | appearanceMod << 24*/, ItemModifiedAppearanceEntry const*> ItemModifiedAppearanceByItemContainer;
@@ -267,6 +276,9 @@ public:
time_t GetHotfixDate(uint32 entry, uint32 type) const;
std::vector<uint32> GetAreasForGroup(uint32 areaGroupId) const;
+ std::vector<ArtifactPowerEntry const*> GetArtifactPowers(uint8 artifactId) const;
+ std::unordered_set<uint32> const* GetArtifactPowerLinks(uint32 artifactPowerId) const;
+ ArtifactPowerRankEntry const* GetArtifactPowerRank(uint32 artifactPowerId, uint8 rank) const;
static char const* GetBroadcastTextValue(BroadcastTextEntry const* broadcastText, LocaleConstant locale = DEFAULT_LOCALE, uint8 gender = GENDER_MALE, bool forceGender = false);
CharSectionsEntry const* GetCharSectionEntry(uint8 race, CharSectionType genType, uint8 gender, uint8 type, uint8 color) const;
CharStartOutfitEntry const* GetCharStartOutfitEntry(uint8 race, uint8 class_, uint8 gender) const;
@@ -280,6 +292,7 @@ public:
std::vector<uint32> const* GetFactionTeamList(uint32 faction) const;
HeirloomEntry const* GetHeirloomByItemId(uint32 itemId) const;
ItemBonusList const* GetItemBonusList(uint32 bonusListId) const;
+ uint32 GetItemBonusListForItemLevelDelta(int16 delta) const;
std::set<uint32> GetItemBonusTree(uint32 itemId, uint32 itemBonusTreeMod) const;
ItemChildEquipmentEntry const* GetItemChildEquipment(uint32 itemId) const;
bool HasItemCurrencyCost(uint32 itemId) const { return _itemsWithCurrencyCost.count(itemId) > 0; }
@@ -324,6 +337,9 @@ private:
HotfixData _hotfixData;
AreaGroupMemberContainer _areaGroupMembers;
+ ArtifactPowersContainer _artifactPowers;
+ ArtifactPowerLinksContainer _artifactPowerLinks;
+ ArtifactPowerRanksContainer _artifactPowerRanks;
CharSectionsContainer _charSections;
CharStartOutfitContainer _charStartOutfits;
uint32 _powersByClass[MAX_CLASSES][MAX_POWERS];
@@ -333,6 +349,7 @@ private:
FactionTeamContainer _factionTeams;
HeirloomItemsContainer _heirlooms;
ItemBonusListContainer _itemBonusLists;
+ ItemBonusListLevelDeltaContainer _itemLevelDeltaToBonusListContainer;
ItemBonusTreeContainer _itemBonusTrees;
ItemChildEquipmentContainer _itemChildEquipment;
std::unordered_set<uint32> _itemsWithCurrencyCost;
diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h
index 32868b632c3..627b2f6b916 100644
--- a/src/server/game/DataStores/DB2Structure.h
+++ b/src/server/game/DataStores/DB2Structure.h
@@ -119,6 +119,91 @@ struct ArmorLocationEntry
float Modifier[5];
};
+struct ArtifactEntry
+{
+ uint32 ID;
+ LocalizedString* Name;
+ uint32 BarConnectedColor;
+ uint32 BarDisconnectedColor;
+ uint32 TitleColor;
+ uint16 ClassUiTextureKitID;
+ uint16 SpecID;
+ uint8 ArtifactCategoryID;
+ uint8 Flags;
+};
+
+struct ArtifactAppearanceEntry
+{
+ LocalizedString* Name;
+ uint32 SwatchColor;
+ float ModelDesaturation;
+ float ModelAlpha;
+ uint32 ShapeshiftDisplayID;
+ uint16 ArtifactAppearanceSetID;
+ uint16 PlayerConditionID;
+ uint16 Unknown;
+ uint8 DisplayIndex;
+ uint8 AppearanceModID;
+ uint8 Flags;
+ uint8 ModifiesShapeshiftFormDisplay;
+ uint32 ID;
+ uint32 ItemAppearanceID;
+ uint32 AltItemAppearanceID;
+};
+
+struct ArtifactAppearanceSetEntry
+{
+ LocalizedString* Name;
+ LocalizedString* Name2;
+ uint16 UiCameraID;
+ uint16 AltHandUICameraID;
+ uint8 ArtifactID;
+ uint8 DisplayIndex;
+ uint8 AttachmentPoint;
+ uint8 Flags;
+ uint32 ID;
+};
+
+struct ArtifactCategoryEntry
+{
+ uint32 ID;
+ uint16 ArtifactKnowledgeCurrencyID;
+ uint16 ArtifactKnowledgeMultiplierCurveID;
+};
+
+struct ArtifactPowerEntry
+{
+ DBCPosition2D Pos;
+ uint8 ArtifactID;
+ uint8 Flags;
+ uint8 MaxRank;
+ uint32 ID;
+ uint32 RelicType;
+};
+
+struct ArtifactPowerLinkEntry
+{
+ uint32 ID;
+ uint16 FromArtifactPowerID;
+ uint16 ToArtifactPowerID;
+};
+
+struct ArtifactPowerRankEntry
+{
+ uint32 ID;
+ uint32 SpellID;
+ float Value;
+ uint16 ArtifactPowerID;
+ uint16 Unknown;
+ uint8 Rank;
+};
+
+struct ArtifactQuestXPEntry
+{
+ uint32 ID;
+ uint32 Exp[10];
+};
+
struct AuctionHouseEntry
{
uint32 ID;
@@ -1180,6 +1265,12 @@ struct ItemBonusEntry
uint8 Index;
};
+struct ItemBonusListLevelDeltaEntry
+{
+ int16 Delta;
+ uint32 ID;
+};
+
struct ItemBonusTreeNodeEntry
{
uint32 ID;
diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h
index 94e421b4445..0d23ee12084 100644
--- a/src/server/game/DataStores/DBCEnums.h
+++ b/src/server/game/DataStores/DBCEnums.h
@@ -138,6 +138,15 @@ enum AreaFlags
AREA_FLAG_UNK9 = 0x40000000
};
+enum ArtifactPowerFlag : uint8
+{
+ ARTIFACT_POWER_FLAG_GOLD = 0x01,
+ ARTIFACT_POWER_FLAG_FIRST = 0x02,
+ ARTIFACT_POWER_FLAG_FINAL = 0x04,
+ ARTIFACT_POWER_FLAG_SCALES_WITH_NUM_POWERS = 0x08,
+ ARTIFACT_POWER_FLAG_DONT_COUNT_FIRST_BONUS_RANK = 0x10,
+};
+
enum ChrSpecializationFlag
{
CHR_SPECIALIZATION_FLAG_CASTER = 0x01,
@@ -456,6 +465,11 @@ enum CharSectionType
SECTION_TYPE_CUSTOM_DISPLAY_3 = 15
};
+enum Curves
+{
+ CURVE_ID_ARTIFACT_RELIC_ITEM_LEVEL_BONUS = 1718
+};
+
enum Difficulty : uint8
{
DIFFICULTY_NONE = 0,
@@ -566,15 +580,19 @@ enum GlyphSlotType
enum ItemEnchantmentType
{
- ITEM_ENCHANTMENT_TYPE_NONE = 0,
- ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL = 1,
- ITEM_ENCHANTMENT_TYPE_DAMAGE = 2,
- ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL = 3,
- ITEM_ENCHANTMENT_TYPE_RESISTANCE = 4,
- ITEM_ENCHANTMENT_TYPE_STAT = 5,
- ITEM_ENCHANTMENT_TYPE_TOTEM = 6,
- ITEM_ENCHANTMENT_TYPE_USE_SPELL = 7,
- ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET = 8
+ ITEM_ENCHANTMENT_TYPE_NONE = 0,
+ ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL = 1,
+ ITEM_ENCHANTMENT_TYPE_DAMAGE = 2,
+ ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL = 3,
+ ITEM_ENCHANTMENT_TYPE_RESISTANCE = 4,
+ ITEM_ENCHANTMENT_TYPE_STAT = 5,
+ ITEM_ENCHANTMENT_TYPE_TOTEM = 6,
+ ITEM_ENCHANTMENT_TYPE_USE_SPELL = 7,
+ ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET = 8,
+ ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_TYPE = 9,
+ ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_ID = 10,
+ ITEM_ENCHANTMENT_TYPE_BONUS_LIST_ID = 11,
+ ITEM_ENCHANTMENT_TYPE_BONUS_LIST_CURVE = 12
};
enum ItemExtendedCostFlags
@@ -853,6 +871,7 @@ enum CurrencyTypes
CURRENCY_TYPE_CONQUEST_META_ARENA = 483,
CURRENCY_TYPE_CONQUEST_META_RBG = 484,
CURRENCY_TYPE_APEXIS_CRYSTALS = 823,
+ CURRENCY_TYPE_ARTIFACT_KNOWLEDGE = 1171,
};
#endif
diff --git a/src/server/game/DataStores/GameTables.cpp b/src/server/game/DataStores/GameTables.cpp
index 709441745a2..4a38b703b7a 100644
--- a/src/server/game/DataStores/GameTables.cpp
+++ b/src/server/game/DataStores/GameTables.cpp
@@ -23,6 +23,7 @@
#include <fstream>
GameTable<GtArmorMitigationByLvlEntry> sArmorMitigationByLvlGameTable;
+GameTable<GtArtifactLevelXPEntry> sArtifactLevelXPGameTable;
GameTable<GtBarberShopCostBaseEntry> sBarberShopCostBaseGameTable;
GameTable<GtBaseMPEntry> sBaseMPGameTable;
GameTable<GtCombatRatingsEntry> sCombatRatingsGameTable;
@@ -107,6 +108,7 @@ void LoadGameTables(std::string const& dataPath)
#define LOAD_GT(store, file) gameTableCount += LoadGameTable(bad_gt_files, store, gtPath / file); ++expectedGameTableCount;
LOAD_GT(sArmorMitigationByLvlGameTable, "ArmorMitigationByLvl.txt");
+ LOAD_GT(sArtifactLevelXPGameTable, "artifactLevelXP.txt");
LOAD_GT(sBarberShopCostBaseGameTable, "BarberShopCostBase.txt");
LOAD_GT(sBaseMPGameTable, "BaseMp.txt");
LOAD_GT(sCombatRatingsGameTable, "CombatRatings.txt");
diff --git a/src/server/game/DataStores/GameTables.h b/src/server/game/DataStores/GameTables.h
index c9b9547847c..4b9660621d2 100644
--- a/src/server/game/DataStores/GameTables.h
+++ b/src/server/game/DataStores/GameTables.h
@@ -26,6 +26,11 @@ struct GtArmorMitigationByLvlEntry
float Mitigation = 0.0f;
};
+struct GtArtifactLevelXPEntry
+{
+ float XP = 0.0f;
+};
+
struct GtBarberShopCostBaseEntry
{
float Cost = 0.0f;
@@ -182,6 +187,7 @@ private:
};
TC_GAME_API extern GameTable<GtArmorMitigationByLvlEntry> sArmorMitigationByLvlGameTable;
+TC_GAME_API extern GameTable<GtArtifactLevelXPEntry> sArtifactLevelXPGameTable;
TC_GAME_API extern GameTable<GtBarberShopCostBaseEntry> sBarberShopCostBaseGameTable;
TC_GAME_API extern GameTable<GtBaseMPEntry> sBaseMPGameTable;
TC_GAME_API extern GameTable<GtCombatRatingsEntry> sCombatRatingsGameTable;
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index eb7b3ec9d85..56e4ca80c59 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -25,6 +25,7 @@
#include "GridNotifiersImpl.h"
#include "Group.h"
#include "GroupMgr.h"
+#include "ArtifactPackets.h"
#include "MiscPackets.h"
#include "ObjectMgr.h"
#include "OutdoorPvPMgr.h"
@@ -1816,6 +1817,34 @@ void GameObject::Use(Unit* user)
player->SetStandState(UnitStandStateType(UNIT_STAND_STATE_SIT_LOW_CHAIR + info->barberChair.chairheight), info->barberChair.SitAnimKit);
return;
}
+ case GAMEOBJECT_TYPE_ARTIFACT_FORGE:
+ {
+ GameObjectTemplate const* info = GetGOInfo();
+ if (!info)
+ return;
+
+ if (user->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ Player* player = user->ToPlayer();
+ if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(info->artifactForge.conditionID1))
+ if (!sConditionMgr->IsPlayerMeetingCondition(player, playerCondition))
+ return;
+
+ Aura const* artifactAura = player->GetAura(ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE);
+ Item const* item = artifactAura ? player->GetItemByGuid(artifactAura->GetCastItemGUID()) : nullptr;
+ if (!item)
+ {
+ player->SendDirectMessage(WorldPackets::Misc::DisplayGameError(GameError::ERR_MUST_EQUIP_ARTIFACT).Write());
+ return;
+ }
+
+ WorldPackets::Artifact::ArtifactForgeOpened artifactForgeOpened;
+ artifactForgeOpened.ArtifactGUID = item->GetGUID();
+ artifactForgeOpened.ForgeGUID = GetGUID();
+ player->SendDirectMessage(artifactForgeOpened.Write());
+ return;
+ }
default:
if (GetGoType() >= MAX_GAMEOBJECT_TYPE)
TC_LOG_ERROR("misc", "GameObject::Use(): unit (type: %u, %s, name: %s) tries to use object (%s, name: %s) of unknown type (%u)",
diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp
index b01508c3933..d79bf16ac07 100644
--- a/src/server/game/Entities/Item/Item.cpp
+++ b/src/server/game/Entities/Item/Item.cpp
@@ -33,6 +33,7 @@
#include "TradeData.h"
#include "GameTables.h"
#include "CollectionMgr.h"
+#include "ArtifactPackets.h"
void AddItemsSetItem(Player* player, Item* item)
{
@@ -308,11 +309,40 @@ bool Item::Create(ObjectGuid::LowType guidlow, uint32 itemid, Player const* owne
SetUInt32Value(ITEM_FIELD_MAXDURABILITY, itemProto->MaxDurability);
SetUInt32Value(ITEM_FIELD_DURABILITY, itemProto->MaxDurability);
- for (uint8 i = 0; i < itemProto->Effects.size() && i < 5; ++i)
- SetSpellCharges(i, itemProto->Effects[i]->Charges);
+ for (std::size_t i = 0; i < itemProto->Effects.size(); ++i)
+ {
+ if (i < 5)
+ SetSpellCharges(i, itemProto->Effects[i]->Charges);
+ if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itemProto->Effects[i]->SpellID))
+ if (spellInfo->HasEffect(SPELL_EFFECT_GIVE_ARTIFACT_POWER))
+ if (uint32 artifactKnowledgeLevel = owner->GetCurrency(CURRENCY_TYPE_ARTIFACT_KNOWLEDGE))
+ SetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL, artifactKnowledgeLevel + 1);
+ }
SetUInt32Value(ITEM_FIELD_DURATION, itemProto->GetDuration());
SetUInt32Value(ITEM_FIELD_CREATE_PLAYED_TIME, 0);
+
+ if (itemProto->GetArtifactID())
+ {
+ InitArtifactPowers(itemProto->GetArtifactID());
+ for (ArtifactAppearanceEntry const* artifactAppearance : sArtifactAppearanceStore)
+ {
+ if (ArtifactAppearanceSetEntry const* artifactAppearanceSet = sArtifactAppearanceSetStore.LookupEntry(artifactAppearance->ArtifactAppearanceSetID))
+ {
+ if (itemProto->GetArtifactID() != artifactAppearanceSet->ArtifactID)
+ continue;
+
+ if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(artifactAppearance->PlayerConditionID))
+ if (!sConditionMgr->IsPlayerMeetingCondition(owner, playerCondition))
+ continue;
+
+ SetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID, artifactAppearance->ID);
+ SetAppearanceModId(artifactAppearance->AppearanceModID);
+ break;
+ }
+ }
+ }
+
return true;
}
@@ -481,6 +511,51 @@ void Item::SaveToDB(SQLTransaction& trans)
trans->Append(stmt);
}
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT);
+ stmt->setUInt64(0, GetGUID().GetCounter());
+ trans->Append(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS);
+ stmt->setUInt64(0, GetGUID().GetCounter());
+ trans->Append(stmt);
+
+ if (GetTemplate()->GetArtifactID())
+ {
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_INSTANCE_ARTIFACT);
+ stmt->setUInt64(0, GetGUID().GetCounter());
+ stmt->setUInt32(1, GetUInt32Value(ITEM_FIELD_ARTIFACT_XP));
+ stmt->setUInt32(2, GetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID));
+ trans->Append(stmt);
+
+ for (ItemDynamicFieldArtifactPowers const& artifactPower : GetArtifactPowers())
+ {
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_INSTANCE_ARTIFACT_POWERS);
+ stmt->setUInt64(0, GetGUID().GetCounter());
+ stmt->setUInt32(1, artifactPower.ArtifactPowerId);
+ stmt->setUInt8(2, artifactPower.PurchasedRank);
+ trans->Append(stmt);
+ }
+ }
+
+ static ItemModifier const modifiersTable[] =
+ {
+ ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL,
+ ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL
+ };
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS);
+ stmt->setUInt64(0, GetGUID().GetCounter());
+ trans->Append(stmt);
+
+ if (std::find_if(std::begin(modifiersTable), std::end(modifiersTable), [this](ItemModifier modifier) { return GetModifier(modifier) != 0; }) != std::end(modifiersTable))
+ {
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_INSTANCE_MODIFIERS);
+ stmt->setUInt64(0, GetGUID().GetCounter());
+ stmt->setUInt32(1, GetModifier(ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL));
+ stmt->setUInt32(2, GetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL));
+ trans->Append(stmt);
+ }
+
break;
}
case ITEM_REMOVED:
@@ -497,6 +572,18 @@ void Item::SaveToDB(SQLTransaction& trans)
stmt->setUInt64(0, GetGUID().GetCounter());
trans->Append(stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT);
+ stmt->setUInt64(0, GetGUID().GetCounter());
+ trans->Append(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS);
+ stmt->setUInt64(0, GetGUID().GetCounter());
+ trans->Append(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS);
+ stmt->setUInt64(0, GetGUID().GetCounter());
+ trans->Append(stmt);
+
if (HasFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_WRAPPED))
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GIFT);
@@ -534,8 +621,8 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
// itemModifiedAppearanceAllSpecs, itemModifiedAppearanceSpec1, itemModifiedAppearanceSpec2, itemModifiedAppearanceSpec3, itemModifiedAppearanceSpec4,
// 24 25 26 27 28
// spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4,
- // 29 30 31 32 33 34 35 36 37
- // gemItemId1, gemBonuses1, gemContext1, gemItemId2, gemBonuses2, gemContext2, gemItemId3, gemBonuses3, gemContext3 FROM item_instance
+ // 29 30 31 32 33 34 35 36 37 38 39
+ // gemItemId1, gemBonuses1, gemContext1, gemItemId2, gemBonuses2, gemContext2, gemItemId3, gemBonuses3, gemContext3, fixedScalingLevel, artifactKnowledgeLevel FROM item_instance
// create item before any checks for store correct guid
// and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB
@@ -665,6 +752,9 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
SetGem(i, &gemData[i]);
}
+ SetModifier(ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL, fields[38].GetUInt32());
+ SetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL, fields[39].GetUInt32());
+
if (need_save) // normal item changed state set not work at loading
{
uint8 index = 0;
@@ -680,6 +770,58 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie
return true;
}
+void Item::LoadArtifactData(uint32 xp, uint32 artifactAppearanceId, std::vector<ItemDynamicFieldArtifactPowers>& powers)
+{
+ InitArtifactPowers(GetTemplate()->GetArtifactID());
+ SetUInt32Value(ITEM_FIELD_ARTIFACT_XP, xp);
+ SetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID, artifactAppearanceId);
+ if (ArtifactAppearanceEntry const* artifactAppearance = sArtifactAppearanceStore.LookupEntry(artifactAppearanceId))
+ SetAppearanceModId(artifactAppearance->AppearanceModID);
+
+ uint8 totalPurchasedRanks = 0;
+ for (ItemDynamicFieldArtifactPowers& power : powers)
+ {
+ power.CurrentRankWithBonus += power.PurchasedRank;
+ totalPurchasedRanks += power.PurchasedRank;
+
+ ArtifactPowerEntry const* artifactPower = sArtifactPowerStore.AssertEntry(power.ArtifactPowerId);
+ for (uint32 e = SOCK_ENCHANTMENT_SLOT; e <= SOCK_ENCHANTMENT_SLOT_3; ++e)
+ {
+ if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(GetEnchantmentId(EnchantmentSlot(e))))
+ {
+ for (uint32 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i)
+ {
+ switch (enchant->Effect[i])
+ {
+ case ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_TYPE:
+ if (artifactPower->RelicType == enchant->EffectSpellID[i])
+ power.CurrentRankWithBonus += enchant->EffectPointsMin[i];
+ break;
+ case ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_ID:
+ if (artifactPower->ID == enchant->EffectSpellID[i])
+ power.CurrentRankWithBonus += enchant->EffectPointsMin[i];
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ SetArtifactPower(&power);
+ }
+
+ for (ItemDynamicFieldArtifactPowers& power : powers)
+ {
+ ArtifactPowerEntry const* scaledArtifactPowerEntry = sArtifactPowerStore.AssertEntry(power.ArtifactPowerId);
+ if (!(scaledArtifactPowerEntry->Flags & ARTIFACT_POWER_FLAG_SCALES_WITH_NUM_POWERS))
+ continue;
+
+ power.CurrentRankWithBonus = totalPurchasedRanks;
+ SetArtifactPower(&power);
+ }
+}
+
/*static*/
void Item::DeleteFromDB(SQLTransaction& trans, ObjectGuid::LowType itemGuid)
{
@@ -1049,6 +1191,9 @@ void Item::SetEnchantment(EnchantmentSlot slot, uint32 id, uint32 duration, uint
owner->GetSession()->SendEnchantmentLog(GetOwnerGUID(), caster, GetEntry(), id);
}
+ ApplyArtifactPowerEnchantmentBonuses(GetEnchantmentId(slot), false, owner);
+ ApplyArtifactPowerEnchantmentBonuses(id, true, owner);
+
SetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot * MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_ID_OFFSET, id);
SetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot * MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_DURATION_OFFSET, duration);
SetUInt32Value(ITEM_FIELD_ENCHANTMENT + slot * MAX_ENCHANTMENT_OFFSET + ENCHANTMENT_CHARGES_OFFSET, charges);
@@ -1098,6 +1243,49 @@ ItemDynamicFieldGems const* Item::GetGem(uint16 slot) const
void Item::SetGem(uint16 slot, ItemDynamicFieldGems const* gem)
{
ASSERT(slot < MAX_GEM_SOCKETS);
+ _bonusData.GemItemLevelBonus[slot] = 0;
+ if (ItemTemplate const* gemTemplate = sObjectMgr->GetItemTemplate(gem->ItemId))
+ {
+ if (GemPropertiesEntry const* gemProperties = sGemPropertiesStore.LookupEntry(gemTemplate->GetGemProperties()))
+ {
+ if (SpellItemEnchantmentEntry const* gemEnchant = sSpellItemEnchantmentStore.LookupEntry(gemProperties->EnchantID))
+ {
+ BonusData gemBonus;
+ gemBonus.Initialize(gemTemplate);
+ for (uint16 bonusListId : gem->BonusListIDs)
+ if (DB2Manager::ItemBonusList const* bonuses = sDB2Manager.GetItemBonusList(bonusListId))
+ for (ItemBonusEntry const* itemBonus : *bonuses)
+ gemBonus.AddBonus(itemBonus->Type, itemBonus->Value);
+
+ for (uint32 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i)
+ {
+ switch (gemEnchant->Effect[i])
+ {
+ case ITEM_ENCHANTMENT_TYPE_BONUS_LIST_ID:
+ {
+ if (DB2Manager::ItemBonusList const* bonuses = sDB2Manager.GetItemBonusList(gemEnchant->EffectSpellID[i]))
+ for (ItemBonusEntry const* itemBonus : *bonuses)
+ if (itemBonus->Type == ITEM_BONUS_ITEM_LEVEL)
+ _bonusData.GemItemLevelBonus[slot] += itemBonus->Value[0];
+ break;
+ }
+ case ITEM_ENCHANTMENT_TYPE_BONUS_LIST_CURVE:
+ {
+ if (uint32 bonusListId = sDB2Manager.GetItemBonusListForItemLevelDelta(int16(sDB2Manager.GetCurveValueAt(CURVE_ID_ARTIFACT_RELIC_ITEM_LEVEL_BONUS, gemTemplate->GetBaseItemLevel() + gemBonus.ItemLevel))))
+ if (DB2Manager::ItemBonusList const* bonuses = sDB2Manager.GetItemBonusList(bonusListId))
+ for (ItemBonusEntry const* itemBonus : *bonuses)
+ if (itemBonus->Type == ITEM_BONUS_ITEM_LEVEL)
+ _bonusData.GemItemLevelBonus[slot] += itemBonus->Value[0];
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
SetDynamicStructuredValue(ITEM_DYNAMIC_FIELD_GEMS, slot, gem);
}
@@ -1978,6 +2166,9 @@ uint32 Item::GetItemLevel(Player const* owner) const
if (ItemUpgradeEntry const* upgrade = sItemUpgradeStore.LookupEntry(GetModifier(ITEM_MODIFIER_UPGRADE_ID)))
itemLevel += upgrade->ItemLevelBonus;
+ for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i)
+ itemLevel += _bonusData.GemItemLevelBonus[i];
+
return std::min(std::max(itemLevel + _bonusData.ItemLevel, uint32(MIN_ITEM_LEVEL)), uint32(MAX_ITEM_LEVEL));
}
@@ -2081,6 +2272,154 @@ void Item::AddBonuses(uint32 bonusListID)
}
}
+DynamicFieldStructuredView<ItemDynamicFieldArtifactPowers> Item::GetArtifactPowers() const
+{
+ return GetDynamicStructuredValues<ItemDynamicFieldArtifactPowers>(ITEM_DYNAMIC_FIELD_ARTIFACT_POWERS);
+}
+
+ItemDynamicFieldArtifactPowers const* Item::GetArtifactPower(uint32 artifactPowerId) const
+{
+ auto indexItr = m_artifactPowerIdToIndex.find(artifactPowerId);
+ if (indexItr != m_artifactPowerIdToIndex.end())
+ return GetDynamicStructuredValue<ItemDynamicFieldArtifactPowers>(ITEM_DYNAMIC_FIELD_ARTIFACT_POWERS, indexItr->second);
+
+ return nullptr;
+}
+
+void Item::SetArtifactPower(ItemDynamicFieldArtifactPowers const* artifactPower, bool createIfMissing /*= false*/)
+{
+ auto indexItr = m_artifactPowerIdToIndex.find(artifactPower->ArtifactPowerId);
+ uint16 index;
+ if (indexItr != m_artifactPowerIdToIndex.end())
+ index = indexItr->second;
+ else
+ {
+ if (!createIfMissing)
+ return;
+
+ index = uint16(m_artifactPowerIdToIndex.size());
+ m_artifactPowerIdToIndex[artifactPower->ArtifactPowerId] = index;
+ }
+
+ SetDynamicStructuredValue(ITEM_DYNAMIC_FIELD_ARTIFACT_POWERS, index, artifactPower);
+}
+
+void Item::InitArtifactPowers(uint8 artifactId)
+{
+ for (ArtifactPowerEntry const* artifactPower : sDB2Manager.GetArtifactPowers(artifactId))
+ {
+ if (m_artifactPowerIdToIndex.find(artifactPower->ID) != m_artifactPowerIdToIndex.end())
+ continue;
+
+ ItemDynamicFieldArtifactPowers powerData;
+ memset(&powerData, 0, sizeof(powerData));
+ powerData.ArtifactPowerId = artifactPower->ID;
+ powerData.PurchasedRank = 0;
+ powerData.CurrentRankWithBonus = (artifactPower->Flags & ARTIFACT_POWER_FLAG_FIRST) ? 1 : 0;
+ SetArtifactPower(&powerData, true);
+ }
+}
+
+uint32 Item::GetTotalPurchasedArtifactPowers() const
+{
+ uint32 purchasedRanks = 0;
+ for (ItemDynamicFieldArtifactPowers const& power : GetArtifactPowers())
+ purchasedRanks += power.PurchasedRank;
+
+ return purchasedRanks;
+}
+
+void Item::ApplyArtifactPowerEnchantmentBonuses(uint32 enchantId, bool apply, Player* owner)
+{
+ if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId))
+ {
+ for (uint32 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i)
+ {
+ switch (enchant->Effect[i])
+ {
+ case ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_TYPE:
+ for (ItemDynamicFieldArtifactPowers const& artifactPower : GetArtifactPowers())
+ {
+ if (sArtifactPowerStore.AssertEntry(artifactPower.ArtifactPowerId)->RelicType == enchant->EffectSpellID[i])
+ {
+ ItemDynamicFieldArtifactPowers newPower = artifactPower;
+ if (apply)
+ newPower.CurrentRankWithBonus += enchant->EffectPointsMin[i];
+ else
+ newPower.CurrentRankWithBonus -= enchant->EffectPointsMin[i];
+
+ if (IsEquipped())
+ if (ArtifactPowerRankEntry const* artifactPowerRank = sDB2Manager.GetArtifactPowerRank(artifactPower.ArtifactPowerId, newPower.CurrentRankWithBonus ? newPower.CurrentRankWithBonus - 1 : 0))
+ owner->ApplyArtifactPowerRank(this, artifactPowerRank, newPower.CurrentRankWithBonus != 0);
+
+ SetArtifactPower(&newPower);
+ }
+ }
+ break;
+ case ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_ID:
+ if (ItemDynamicFieldArtifactPowers const* artifactPower = GetArtifactPower(enchant->EffectSpellID[i]))
+ {
+ ItemDynamicFieldArtifactPowers newPower = *artifactPower;
+ if (apply)
+ newPower.CurrentRankWithBonus += enchant->EffectPointsMin[i];
+ else
+ newPower.CurrentRankWithBonus -= enchant->EffectPointsMin[i];
+
+ if (IsEquipped())
+ if (ArtifactPowerRankEntry const* artifactPowerRank = sDB2Manager.GetArtifactPowerRank(artifactPower->ArtifactPowerId, newPower.CurrentRankWithBonus ? newPower.CurrentRankWithBonus - 1 : 0))
+ owner->ApplyArtifactPowerRank(this, artifactPowerRank, newPower.CurrentRankWithBonus != 0);
+
+ SetArtifactPower(&newPower);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void Item::CopyArtifactDataFromParent(Item* parent)
+{
+ memcpy(_bonusData.GemItemLevelBonus, parent->GetBonus()->GemItemLevelBonus, sizeof(_bonusData.GemItemLevelBonus));
+ SetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID, parent->GetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID));
+ SetAppearanceModId(parent->GetAppearanceModId());
+}
+
+void Item::GiveArtifactXp(int32 amount, Item* sourceItem, uint32 artifactCategoryId)
+{
+ Player const* owner = GetOwner();
+ if (!owner)
+ return;
+
+ if (artifactCategoryId)
+ {
+ if (ArtifactCategoryEntry const* artifactCategory = sArtifactCategoryStore.LookupEntry(artifactCategoryId))
+ {
+ uint32 artifactKnowledgeLevel = 0;
+ if (sourceItem && sourceItem->GetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL))
+ artifactKnowledgeLevel = sourceItem->GetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL) - 1;
+ else
+ artifactKnowledgeLevel = owner->GetCurrency(artifactCategory->ArtifactKnowledgeCurrencyID);
+
+ amount = int32(amount * sDB2Manager.GetCurveValueAt(artifactCategory->ArtifactKnowledgeMultiplierCurveID, artifactKnowledgeLevel));
+ if (amount >= 5000)
+ amount = 50 * (amount / 50);
+ else if (amount >= 1000)
+ amount = 25 * (amount / 25);
+ else if (amount >= 50)
+ amount = 5 * (amount / 5);
+ }
+ }
+
+ ApplyModInt32Value(ITEM_FIELD_ARTIFACT_XP, amount, true);
+
+ WorldPackets::Artifact::ArtifactXpGain artifactXpGain;
+ artifactXpGain.ArtifactGUID = GetGUID();
+ artifactXpGain.Amount = amount;
+ owner->SendDirectMessage(artifactXpGain.Write());
+}
+
void BonusData::Initialize(ItemTemplate const* proto)
{
Quality = proto->GetQuality();
@@ -2099,7 +2438,10 @@ void BonusData::Initialize(ItemTemplate const* proto)
ItemStatSocketCostMultiplier[i] = proto->GetItemStatSocketCostMultiplier(i);
for (uint32 i = 0; i < MAX_ITEM_PROTO_SOCKETS; ++i)
+ {
SocketColor[i] = proto->GetSocketColor(i);
+ GemItemLevelBonus[i] = 0;
+ }
AppearanceModID = 0;
if (ItemModifiedAppearanceEntry const* defaultAppearance = sDB2Manager.GetDefaultItemModifiedAppearance(proto->GetId()))
diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h
index fe86591ccc3..204eb8e44d3 100644
--- a/src/server/game/Entities/Item/Item.h
+++ b/src/server/game/Entities/Item/Item.h
@@ -249,6 +249,7 @@ enum ItemModifier : uint16
ITEM_MODIFIER_CHALLENGE_KEYSTONE_AFFIX_ID_2 = 20,
ITEM_MODIFIER_CHALLENGE_KEYSTONE_AFFIX_ID_3 = 21,
ITEM_MODIFIER_CHALLENGE_KEYSTONE_IS_CHARGED = 22,
+ ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL = 23,
MAX_ITEM_MODIFIERS
};
@@ -273,12 +274,22 @@ struct BonusData
float RepairCostMultiplier;
uint32 ScalingStatDistribution;
+ uint32 GemItemLevelBonus[MAX_ITEM_PROTO_SOCKETS];
+
void Initialize(ItemTemplate const* proto);
void Initialize(WorldPackets::Item::ItemInstance const& itemInstance);
void AddBonus(uint32 type, int32 const (&values)[2]);
};
#pragma pack(push, 1)
+struct ItemDynamicFieldArtifactPowers
+{
+ uint32 ArtifactPowerId;
+ uint8 PurchasedRank;
+ uint8 CurrentRankWithBonus;
+ uint16 Padding;
+};
+
struct ItemDynamicFieldGems
{
uint32 ItemId;
@@ -313,6 +324,7 @@ class TC_GAME_API Item : public Object
bool IsBoundByEnchant() const;
virtual void SaveToDB(SQLTransaction& trans);
virtual bool LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fields, uint32 entry);
+ void LoadArtifactData(uint32 xp, uint32 artifactAppearanceId, std::vector<ItemDynamicFieldArtifactPowers>& powers); // must be called after LoadFromDB to have gems (relics) initialized
void AddBonuses(uint32 bonusListID);
@@ -426,7 +438,8 @@ class TC_GAME_API Item : public Object
int32 GetItemStatType(uint32 index) const { ASSERT(index < MAX_ITEM_PROTO_STATS); return _bonusData.ItemStatType[index]; }
int32 GetItemStatValue(uint32 index, Player const* owner) const;
SocketColor GetSocketColor(uint32 index) const { ASSERT(index < MAX_ITEM_PROTO_SOCKETS); return SocketColor(_bonusData.SocketColor[index]); }
- uint32 GetAppearanceModId() const { return _bonusData.AppearanceModID; }
+ uint32 GetAppearanceModId() const { return GetUInt32Value(ITEM_FIELD_APPEARANCE_MOD_ID); }
+ void SetAppearanceModId(uint32 appearanceModId) { SetUInt32Value(ITEM_FIELD_APPEARANCE_MOD_ID, appearanceModId); }
uint32 GetArmor(Player const* owner) const { return GetTemplate()->GetArmor(GetItemLevel(owner)); }
void GetDamage(Player const* owner, float& minDamage, float& maxDamage) const { GetTemplate()->GetDamage(GetItemLevel(owner), minDamage, maxDamage); }
uint32 GetDisplayId(Player const* owner) const;
@@ -480,6 +493,16 @@ class TC_GAME_API Item : public Object
ObjectGuid GetChildItem() const { return m_childItem; }
void SetChildItem(ObjectGuid childItem) { m_childItem = childItem; }
+ DynamicFieldStructuredView<ItemDynamicFieldArtifactPowers> GetArtifactPowers() const;
+ ItemDynamicFieldArtifactPowers const* GetArtifactPower(uint32 artifactPowerId) const;
+ void SetArtifactPower(ItemDynamicFieldArtifactPowers const* artifactPower, bool createIfMissing = false);
+
+ void InitArtifactPowers(uint8 artifactId);
+ uint32 GetTotalPurchasedArtifactPowers() const;
+ void ApplyArtifactPowerEnchantmentBonuses(uint32 enchantId, bool apply, Player* owner);
+ void CopyArtifactDataFromParent(Item* parent);
+
+ void GiveArtifactXp(int32 amount, Item* sourceItem, uint32 artifactCategoryId);
protected:
BonusData _bonusData;
@@ -496,5 +519,6 @@ class TC_GAME_API Item : public Object
uint32 m_paidExtendedCost;
GuidSet allowedGUIDs;
ObjectGuid m_childItem;
+ std::unordered_map<uint32, uint16> m_artifactPowerIdToIndex;
};
#endif
diff --git a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp
index a36a4a4c246..ac9000ded5e 100644
--- a/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp
+++ b/src/server/game/Entities/Item/ItemEnchantmentMgr.cpp
@@ -190,6 +190,7 @@ TC_GAME_API uint32 GetRandomPropertyPoints(uint32 itemLevel, uint32 quality, uin
return randPropPointsEntry->RarePropertiesPoints[propIndex];
case ITEM_QUALITY_EPIC:
case ITEM_QUALITY_LEGENDARY:
+ case ITEM_QUALITY_ARTIFACT:
return randPropPointsEntry->EpicPropertiesPoints[propIndex];
}
diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h
index bbf89d18dbf..4d2ec62621c 100644
--- a/src/server/game/Entities/Item/ItemTemplate.h
+++ b/src/server/game/Entities/Item/ItemTemplate.h
@@ -757,6 +757,7 @@ struct TC_GAME_API ItemTemplate
uint32 GetItemLimitCategory() const { return ExtendedData->ItemLimitCategory; }
HolidayIds GetHolidayID() const { return HolidayIds(ExtendedData->HolidayID); }
float GetStatScalingFactor() const { return ExtendedData->StatScalingFactor; }
+ uint8 GetArtifactID() const { return ExtendedData->ArtifactID; }
uint32 GetBaseArmor() const { return GetArmor(ExtendedData->ItemLevel); }
void GetBaseDamage(float& minDamage, float& maxDamage) const { GetDamage(ExtendedData->ItemLevel, minDamage, maxDamage); }
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index e1d5c92b80e..849aab0af79 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -4012,6 +4012,18 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
stmt->setUInt64(0, guid);
trans->Append(stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_BY_OWNER);
+ stmt->setUInt64(0, guid);
+ trans->Append(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS_BY_OWNER);
+ stmt->setUInt64(0, guid);
+ trans->Append(stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS_BY_OWNER);
+ stmt->setUInt64(0, guid);
+ trans->Append(stmt);
+
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_BY_OWNER);
stmt->setUInt64(0, guid);
trans->Append(stmt);
@@ -7212,6 +7224,7 @@ void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply)
_ApplyItemBonuses(item, slot, apply);
ApplyItemEquipSpell(item, apply);
+ ApplyArtifactPowers(item, apply);
ApplyEnchantment(item, apply);
TC_LOG_DEBUG("entities.player.items", "Player::_ApplyItemMods: completed");
@@ -7683,6 +7696,80 @@ void Player::UpdateItemSetAuras(bool formChange /*= false*/)
}
}
+void Player::ApplyArtifactPowers(Item* item, bool apply)
+{
+ for (ItemDynamicFieldArtifactPowers const& artifactPower : item->GetArtifactPowers())
+ {
+ uint8 rank = artifactPower.CurrentRankWithBonus;
+ if (!rank)
+ continue;
+
+ ArtifactPowerRankEntry const* artifactPowerRank = sDB2Manager.GetArtifactPowerRank(artifactPower.ArtifactPowerId, rank - 1);
+ if (!artifactPowerRank)
+ continue;
+
+ ApplyArtifactPowerRank(item, artifactPowerRank, apply);
+ }
+}
+
+void Player::ApplyArtifactPowerRank(Item* artifact, ArtifactPowerRankEntry const* artifactPowerRank, bool apply)
+{
+ SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(artifactPowerRank->SpellID);
+ if (!spellInfo)
+ return;
+
+ if (spellInfo->IsPassive())
+ {
+ AuraApplication* powerAura = GetAuraApplication(artifactPowerRank->SpellID, ObjectGuid::Empty, artifact->GetGUID());
+ if (powerAura)
+ {
+ if (apply)
+ {
+ for (AuraEffect* auraEffect : powerAura->GetBase()->GetAuraEffects())
+ {
+ if (!auraEffect)
+ continue;
+
+ if (powerAura->HasEffect(auraEffect->GetEffIndex()))
+ auraEffect->ChangeAmount(artifactPowerRank->Value ? artifactPowerRank->Value : auraEffect->GetSpellEffectInfo()->CalcValue());
+ }
+ }
+ else
+ RemoveAura(powerAura);
+ }
+ else if (apply)
+ {
+ CustomSpellValues csv;
+ if (artifactPowerRank->Value)
+ for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i)
+ if (spellInfo->GetEffect(i))
+ csv.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0 + i), artifactPowerRank->Value);
+
+ CastCustomSpell(artifactPowerRank->SpellID, csv, this, TRIGGERED_FULL_MASK, artifact);
+ }
+ }
+ else
+ {
+ if (apply && !HasSpell(artifactPowerRank->SpellID))
+ {
+ AddTemporarySpell(artifactPowerRank->SpellID);
+ WorldPackets::Spells::LearnedSpells learnedSpells;
+ learnedSpells.SuppressMessaging = true;
+ learnedSpells.SpellID.push_back(artifactPowerRank->SpellID);
+ SendDirectMessage(learnedSpells.Write());
+ }
+ else if (!apply)
+ {
+ RemoveTemporarySpell(artifactPowerRank->SpellID);
+ WorldPackets::Spells::UnlearnedSpells unlearnedSpells;
+ unlearnedSpells.SuppressMessaging = true;
+ unlearnedSpells.SpellID.push_back(artifactPowerRank->SpellID);
+ SendDirectMessage(unlearnedSpells.Write());
+ }
+ }
+
+}
+
void Player::CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx)
{
if (!target || !target->IsAlive() || target == this)
@@ -7944,6 +8031,7 @@ void Player::_RemoveAllItemMods()
ApplyItemEquipSpell(m_items[i], false);
ApplyEnchantment(m_items[i], false);
+ ApplyArtifactPowers(m_items[i], false);
}
}
@@ -8000,6 +8088,7 @@ void Player::_ApplyAllItemMods()
continue;
ApplyItemEquipSpell(m_items[i], true);
+ ApplyArtifactPowers(m_items[i], true);
ApplyEnchantment(m_items[i], true);
}
}
@@ -11387,6 +11476,10 @@ InventoryResult Player::CanUseItem(ItemTemplate const* proto) const
if (HasSpell(proto->Effects[1]->SpellID))
return EQUIP_ERR_INTERNAL_BAG_ERROR;
+ if (ArtifactEntry const* artifact = sArtifactStore.LookupEntry(proto->GetArtifactID()))
+ if (artifact->SpecID != GetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID))
+ return EQUIP_ERR_CANT_USE_ITEM;
+
return EQUIP_ERR_OK;
}
@@ -11515,10 +11608,12 @@ Item* Player::StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool updat
{
childItem->SetGuidValue(ITEM_FIELD_CREATOR, item->GetGUID());
childItem->SetFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_CHILD);
+ item->SetChildItem(childItem->GetGUID());
}
}
}
}
+
return item;
}
@@ -17608,7 +17703,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
// must be before inventory (some items required reputation check)
m_reputationMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_REPUTATION));
- _LoadInventory(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INVENTORY), time_diff);
+ _LoadInventory(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INVENTORY), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARTIFACTS), time_diff);
if (IsVoidStorageUnlocked())
_LoadVoidStorage(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE));
@@ -17969,7 +18064,7 @@ void Player::LoadCorpse(PreparedQueryResult result)
RemoveAtLoginFlag(AT_LOGIN_RESURRECT);
}
-void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff)
+void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult artifactsResult, uint32 timeDiff)
{
// 0 1 2 3 4 5 6 7 8 9 10 11 12
// SELECT guid, itemEntry, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text,
@@ -17979,13 +18074,40 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff)
// itemModifiedAppearanceAllSpecs, itemModifiedAppearanceSpec1, itemModifiedAppearanceSpec2, itemModifiedAppearanceSpec3, itemModifiedAppearanceSpec4,
// 24 25 26 27 28
// spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4,
- // 29 30 31 32 33 34 35 36 37 38 39
+ // 29 30 31 32 33 34 35 36 37 40 41
// gemItemId1, gemBonuses1, gemContext1, gemItemId2, gemBonuses2, gemContext2, gemItemId3, gemBonuses3, gemContext3, bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ? ORDER BY bag, slot
//NOTE: the "order by `bag`" is important because it makes sure
//the bagMap is filled before items in the bags are loaded
//NOTE2: the "order by `slot`" is needed because mainhand weapons are (wrongly?)
//expected to be equipped before offhand items (@todo fixme)
+ // 0 1 2 3 4
+ // SELECT a.itemGuid, a.xp, a.artifactAppearanceId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid INNER JOIN character_inventory ci ON ci.item = ap.guid WHERE ci.guid = ?
+ std::unordered_map<ObjectGuid, std::tuple<uint32, uint32, std::vector<ItemDynamicFieldArtifactPowers>>> artifactData;
+ if (artifactsResult)
+ {
+ do
+ {
+ Field* fields = artifactsResult->Fetch();
+ auto& artifactDataEntry = artifactData[ObjectGuid::Create<HighGuid::Item>(fields[0].GetUInt64())];
+ std::get<0>(artifactDataEntry) = fields[1].GetUInt32();
+ std::get<1>(artifactDataEntry) = fields[2].GetUInt32();
+ ItemDynamicFieldArtifactPowers artifactPowerData;
+ artifactPowerData.ArtifactPowerId = fields[3].GetUInt32();
+ artifactPowerData.PurchasedRank = fields[4].GetUInt8();
+ if (ArtifactPowerEntry const* artifactPower = sArtifactPowerStore.LookupEntry(artifactPowerData.ArtifactPowerId))
+ {
+ if (artifactPowerData.PurchasedRank > artifactPower->MaxRank)
+ artifactPowerData.PurchasedRank = artifactPower->MaxRank;
+
+ artifactPowerData.CurrentRankWithBonus = (artifactPower->Flags & ARTIFACT_POWER_FLAG_FIRST) ? 1 : 0;
+
+ std::get<2>(artifactDataEntry).push_back(artifactPowerData);
+ }
+
+ } while (artifactsResult->NextRow());
+ }
+
if (result)
{
uint32 zoneId = GetZoneId();
@@ -18003,8 +18125,12 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff)
Field* fields = result->Fetch();
if (Item* item = _LoadItem(trans, zoneId, timeDiff, fields))
{
- ObjectGuid bagGuid = fields[38].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[38].GetUInt64()) : ObjectGuid::Empty;
- uint8 slot = fields[39].GetUInt8();
+ auto artifactDataItr = artifactData.find(item->GetGUID());
+ if (item->GetTemplate()->GetArtifactID() && artifactDataItr != artifactData.end())
+ item->LoadArtifactData(std::get<0>(artifactDataItr->second), std::get<1>(artifactDataItr->second), std::get<2>(artifactDataItr->second));
+
+ ObjectGuid bagGuid = fields[40].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[40].GetUInt64()) : ObjectGuid::Empty;
+ uint8 slot = fields[41].GetUInt8();
GetSession()->GetCollectionMgr()->CheckHeirloomUpgrades(item);
GetSession()->GetCollectionMgr()->AddItemAppearance(item);
@@ -18079,7 +18205,6 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff)
}
-
// Item's state may have changed after storing
if (err == EQUIP_ERR_OK)
{
@@ -18116,7 +18241,12 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff)
for (Item* childItem : childItems)
{
if (Item* parent = GetItemByGuid(childItem->GetGuidValue(ITEM_FIELD_CREATOR)))
+ {
parent->SetChildItem(childItem->GetGUID());
+ childItem->CopyArtifactDataFromParent(parent);
+ if (childItem->IsEquipped())
+ SetVisibleItemSlot(childItem->GetSlot(), childItem);
+ }
else
childItem->SetState(ITEM_REMOVED, this);
}
@@ -18134,7 +18264,7 @@ void Player::_LoadVoidStorage(PreparedQueryResult result)
do
{
- // SELECT itemId, itemEntry, slot, creatorGuid, randomProperty, suffixFactor, upgradeId, bonusListIDs FROM character_void_storage WHERE playerGuid = ?
+ // SELECT itemId, itemEntry, slot, creatorGuid, randomProperty, suffixFactor, upgradeId, fixedScalingLevel, artifactKnowledgeLevel, bonusListIDs FROM character_void_storage WHERE playerGuid = ?
Field* fields = result->Fetch();
uint64 itemId = fields[0].GetUInt64();
@@ -18144,8 +18274,10 @@ void Player::_LoadVoidStorage(PreparedQueryResult result)
uint32 randomProperty = fields[4].GetUInt32();
uint32 suffixFactor = fields[5].GetUInt32();
uint32 upgradeId = fields[6].GetUInt32();
+ uint32 fixedScalingLevel = fields[7].GetUInt32();
+ uint32 artifactKnowledgeLevel = fields[8].GetUInt32();
std::vector<uint32> bonusListIDs;
- Tokenizer bonusListIdTokens(fields[7].GetString(), ' ');
+ Tokenizer bonusListIdTokens(fields[9].GetString(), ' ');
for (char const* token : bonusListIdTokens)
bonusListIDs.push_back(atoul(token));
@@ -18170,7 +18302,7 @@ void Player::_LoadVoidStorage(PreparedQueryResult result)
continue;
}
- _voidStorageItems[slot] = new VoidStorageItem(itemId, itemEntry, creatorGuid, randomProperty, suffixFactor, upgradeId, bonusListIDs);
+ _voidStorageItems[slot] = new VoidStorageItem(itemId, itemEntry, creatorGuid, randomProperty, suffixFactor, upgradeId, fixedScalingLevel, artifactKnowledgeLevel, bonusListIDs);
WorldPackets::Item::ItemInstance voidInstance;
voidInstance.Initialize(_voidStorageItems[slot]);
@@ -18346,7 +18478,7 @@ void Player::_LoadMailedItems(Mail* mail)
Item* item = NewItemOrBag(proto);
- ObjectGuid ownerGuid = fields[38].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[38].GetUInt64()) : ObjectGuid::Empty;
+ ObjectGuid ownerGuid = fields[40].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[40].GetUInt64()) : ObjectGuid::Empty;
if (!item->LoadFromDB(itemGuid, ownerGuid, fields, itemEntry))
{
TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems: Item (GUID: " UI64FMTD ") in mail (%u) doesn't exist, deleted from mail.", itemGuid, mail->messageID);
@@ -19875,7 +20007,7 @@ void Player::_SaveVoidStorage(SQLTransaction& trans)
}
else
{
- // REPLACE INTO character_inventory (itemId, playerGuid, itemEntry, slot, creatorGuid, randomProperty, suffixFactor, upgradeId, bonusListIDs) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
+ // REPLACE INTO character_void_storage (itemId, playerGuid, itemEntry, slot, creatorGuid, randomProperty, suffixFactor, upgradeId, fixedScalingLevel, artifactKnowledgeLevel, bonusListIDs) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_VOID_STORAGE_ITEM);
stmt->setUInt64(0, _voidStorageItems[i]->ItemId);
stmt->setUInt64(1, GetGUID().GetCounter());
@@ -19885,10 +20017,12 @@ void Player::_SaveVoidStorage(SQLTransaction& trans)
stmt->setUInt32(5, _voidStorageItems[i]->ItemRandomPropertyId);
stmt->setUInt32(6, _voidStorageItems[i]->ItemSuffixFactor);
stmt->setUInt32(7, _voidStorageItems[i]->ItemUpgradeId);
+ stmt->setUInt32(8, _voidStorageItems[i]->FixedScalingLevel);
+ stmt->setUInt32(9, _voidStorageItems[i]->ArtifactKnowledgeLevel);
std::ostringstream bonusListIDs;
for (int32 bonusListID : _voidStorageItems[i]->BonusListIDs)
bonusListIDs << bonusListID << ' ';
- stmt->setString(8, bonusListIDs.str());
+ stmt->setString(10, bonusListIDs.str());
}
trans->Append(stmt);
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index f25e5cbb3dc..421a15729dc 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -956,6 +956,7 @@ enum PlayerLoginQueryIndex
PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS,
PLAYER_LOGIN_QUERY_LOAD_REPUTATION,
PLAYER_LOGIN_QUERY_LOAD_INVENTORY,
+ PLAYER_LOGIN_QUERY_LOAD_ARTIFACTS,
PLAYER_LOGIN_QUERY_LOAD_ACTIONS,
PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT,
PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE,
@@ -1123,15 +1124,17 @@ struct BGData
struct VoidStorageItem
{
- VoidStorageItem() : ItemId(0), ItemEntry(0), ItemRandomPropertyId(0), ItemSuffixFactor(0), ItemUpgradeId(0) { }
- VoidStorageItem(uint64 id, uint32 entry, ObjectGuid const& creator, uint32 randomPropertyId, uint32 suffixFactor, uint32 upgradeId, std::vector<uint32> const& bonuses)
+ VoidStorageItem() : ItemId(0), ItemEntry(0), ItemRandomPropertyId(0), ItemSuffixFactor(0), ItemUpgradeId(0), FixedScalingLevel(0), ArtifactKnowledgeLevel(0) { }
+ VoidStorageItem(uint64 id, uint32 entry, ObjectGuid const& creator, uint32 randomPropertyId, uint32 suffixFactor,
+ uint32 upgradeId, uint32 fixedScalingLevel, uint32 artifactKnowledgeLevel, std::vector<uint32> const& bonuses)
: ItemId(id), ItemEntry(entry), CreatorGuid(creator), ItemRandomPropertyId(randomPropertyId),
- ItemSuffixFactor(suffixFactor), ItemUpgradeId(upgradeId)
+ ItemSuffixFactor(suffixFactor), ItemUpgradeId(upgradeId), FixedScalingLevel(fixedScalingLevel), ArtifactKnowledgeLevel(artifactKnowledgeLevel)
{
BonusListIDs.insert(BonusListIDs.end(), bonuses.begin(), bonuses.end());
}
VoidStorageItem(VoidStorageItem&& vsi) : ItemId(vsi.ItemId), ItemEntry(vsi.ItemEntry), CreatorGuid(vsi.CreatorGuid), ItemRandomPropertyId(vsi.ItemRandomPropertyId),
- ItemSuffixFactor(vsi.ItemSuffixFactor), ItemUpgradeId(vsi.ItemUpgradeId), BonusListIDs(std::move(vsi.BonusListIDs)) { }
+ ItemSuffixFactor(vsi.ItemSuffixFactor), ItemUpgradeId(vsi.ItemUpgradeId), FixedScalingLevel(vsi.FixedScalingLevel),
+ ArtifactKnowledgeLevel(vsi.ArtifactKnowledgeLevel), BonusListIDs(std::move(vsi.BonusListIDs)) { }
uint64 ItemId;
uint32 ItemEntry;
@@ -1139,6 +1142,8 @@ struct VoidStorageItem
uint32 ItemRandomPropertyId;
uint32 ItemSuffixFactor;
uint32 ItemUpgradeId;
+ uint32 FixedScalingLevel;
+ uint32 ArtifactKnowledgeLevel;
std::vector<int32> BonusListIDs;
};
@@ -2152,6 +2157,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply, bool formChange = false);
void UpdateEquipSpellsAtFormChange();
void UpdateItemSetAuras(bool formChange = false);
+ void ApplyArtifactPowers(Item* item, bool apply);
+ void ApplyArtifactPowerRank(Item* artifact, ArtifactPowerRankEntry const* artifactPowerRank, bool apply);
void CastItemCombatSpell(Unit* target, WeaponAttackType attType, uint32 procVictim, uint32 procEx);
void CastItemUseSpell(Item* item, SpellCastTargets const& targets, ObjectGuid castCount, int32* misc);
@@ -2518,7 +2525,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
void _LoadActions(PreparedQueryResult result);
void _LoadAuras(PreparedQueryResult auraResult, PreparedQueryResult effectResult, uint32 timediff);
void _LoadBoundInstances(PreparedQueryResult result);
- void _LoadInventory(PreparedQueryResult result, uint32 timeDiff);
+ void _LoadInventory(PreparedQueryResult result, PreparedQueryResult artifactsResult, uint32 timeDiff);
void _LoadVoidStorage(PreparedQueryResult result);
void _LoadMailInit(PreparedQueryResult resultUnread, PreparedQueryResult resultDelivery);
void _LoadMail();
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index c8cd3645721..d665225edc1 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -14214,6 +14214,12 @@ uint32 Unit::GetModelForForm(ShapeshiftForm form) const
{
if (GetTypeId() == TYPEID_PLAYER)
{
+ if (Aura* artifactAura = GetAura(ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE))
+ if (Item* artifact = ToPlayer()->GetItemByGuid(artifactAura->GetCastItemGUID()))
+ if (ArtifactAppearanceEntry const* artifactAppearance = sArtifactAppearanceStore.LookupEntry(artifact->GetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID)))
+ if (ShapeshiftForm(artifactAppearance->ModifiesShapeshiftFormDisplay) == form)
+ return artifactAppearance->ShapeshiftDisplayID;
+
switch (form)
{
case FORM_CAT_FORM:
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 246a8a09818..4847723fb9c 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -31,6 +31,7 @@
#include <boost/container/flat_set.hpp>
#define WORLD_TRIGGER 12999
+#define ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE 197886
enum SpellInterruptFlags
{
@@ -773,7 +774,7 @@ enum NPCFlags : uint64
UNIT_NPC_FLAG_SPELLCLICK = 0x0001000000, // cause client to send 1015 opcode (spell click)
UNIT_NPC_FLAG_PLAYER_VEHICLE = 0x0002000000, // players with mounts that have vehicle data should have it set
UNIT_NPC_FLAG_MAILBOX = 0x0004000000, // mailbox
- UNIT_NPC_FLAG_REFORGER = 0x0008000000, // reforging
+ UNIT_NPC_FLAG_ARTIFACT_POWER_RESPEC = 0x0008000000, // artifact powers reset
UNIT_NPC_FLAG_TRANSMOGRIFIER = 0x0010000000, // transmogrification
UNIT_NPC_FLAG_VAULTKEEPER = 0x0020000000, // void storage
UNIT_NPC_FLAG_BLACK_MARKET = 0x0080000000, // black market
diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp
index 5140b74547b..02ed7a1c146 100644
--- a/src/server/game/Guilds/Guild.cpp
+++ b/src/server/game/Guilds/Guild.cpp
@@ -368,7 +368,7 @@ void Guild::BankTab::LoadFromDB(Field* fields)
bool Guild::BankTab::LoadItemFromDB(Field* fields)
{
- uint8 slotId = fields[26].GetUInt8();
+ uint8 slotId = fields[42].GetUInt8();
ObjectGuid::LowType itemGuid = fields[0].GetUInt64();
uint32 itemEntry = fields[1].GetUInt32();
if (slotId >= GUILD_BANK_MAX_SLOTS)
@@ -2394,7 +2394,7 @@ void Guild::LoadBankTabFromDB(Field* fields)
bool Guild::LoadBankItemFromDB(Field* fields)
{
- uint8 tabId = fields[39].GetUInt8();
+ uint8 tabId = fields[41].GetUInt8();
if (tabId >= _GetPurchasedTabsSize())
{
TC_LOG_ERROR("guild", "Invalid tab for item (GUID: %u, id: #%u) in guild bank, skipped.",
diff --git a/src/server/game/Guilds/GuildMgr.cpp b/src/server/game/Guilds/GuildMgr.cpp
index bb65c6c00bd..00cf52ef92f 100644
--- a/src/server/game/Guilds/GuildMgr.cpp
+++ b/src/server/game/Guilds/GuildMgr.cpp
@@ -409,8 +409,10 @@ void GuildMgr::LoadGuilds()
// itemModifiedAppearanceAllSpecs, itemModifiedAppearanceSpec1, itemModifiedAppearanceSpec2, itemModifiedAppearanceSpec3, itemModifiedAppearanceSpec4,
// 24 25 26 27 28
// spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4,
- // 29 30 31 32 33 34 35 36 37 38 39
- // gemItemId1, gemBonuses1, gemContext1, gemItemId2, gemBonuses2, gemContext2, gemItemId3, gemBonuses3, gemContext3, guildid, TabId, SlotId FROM guild_bank_item gbi INNER JOIN item_instance ii ON gbi.item_guid = ii.guid
+ // 29 30 31 32 33 34 35 36 37 38 39
+ // gemItemId1, gemBonuses1, gemContext1, gemItemId2, gemBonuses2, gemContext2, gemItemId3, gemBonuses3, gemContext3, fixedScalingLevel, artifactKnowledgeLevel,
+ // 40 41 42
+ // guildid, TabId, SlotId FROM guild_bank_item gbi INNER JOIN item_instance ii ON gbi.item_guid = ii.guid
PreparedQueryResult result = CharacterDatabase.Query(CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_BANK_ITEMS));
if (!result)
@@ -423,7 +425,7 @@ void GuildMgr::LoadGuilds()
do
{
Field* fields = result->Fetch();
- uint64 guildId = fields[38].GetUInt64();
+ uint64 guildId = fields[40].GetUInt64();
if (Guild* guild = GetGuildById(guildId))
guild->LoadBankItemFromDB(fields);
diff --git a/src/server/game/Handlers/ArtifactHandler.cpp b/src/server/game/Handlers/ArtifactHandler.cpp
new file mode 100644
index 00000000000..87ee711cc7a
--- /dev/null
+++ b/src/server/game/Handlers/ArtifactHandler.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "WorldSession.h"
+#include "ArtifactPackets.h"
+#include "ConditionMgr.h"
+#include "GameTables.h"
+#include "Player.h"
+#include "SpellAuraEffects.h"
+#include "SpellInfo.h"
+#include "SpellPackets.h"
+
+void WorldSession::HandleArtifactAddPower(WorldPackets::Artifact::ArtifactAddPower& artifactAddPower)
+{
+ if (!_player->GetGameObjectIfCanInteractWith(artifactAddPower.ForgeGUID, GAMEOBJECT_TYPE_ARTIFACT_FORGE))
+ return;
+
+ Item* artifact = _player->GetItemByGuid(artifactAddPower.ArtifactGUID);
+ if (!artifact)
+ return;
+
+ int32 xpCost = 0;
+ if (GtArtifactLevelXPEntry const* cost = sArtifactLevelXPGameTable.GetRow(artifact->GetTotalPurchasedArtifactPowers() + 1))
+ xpCost = int32(cost->XP);
+
+ if (xpCost > artifact->GetInt32Value(ITEM_FIELD_ARTIFACT_XP))
+ return;
+
+ if (artifactAddPower.PowerChoices.empty())
+ return;
+
+ ItemDynamicFieldArtifactPowers const* artifactPower = artifact->GetArtifactPower(artifactAddPower.PowerChoices[0].ArtifactPowerID);
+ if (!artifactPower)
+ return;
+
+ ArtifactPowerEntry const* artifactPowerEntry = sArtifactPowerStore.LookupEntry(artifactPower->ArtifactPowerId);
+ if (!artifactPowerEntry)
+ return;
+
+ if (artifactAddPower.PowerChoices[0].Rank != artifactPower->PurchasedRank + 1 ||
+ artifactAddPower.PowerChoices[0].Rank > artifactPowerEntry->MaxRank)
+ return;
+
+ if (std::unordered_set<uint32> const* artifactPowerLinks = sDB2Manager.GetArtifactPowerLinks(artifactPower->ArtifactPowerId))
+ {
+ bool hasAnyLink = false;
+ for (uint32 artifactPowerLinkId : *artifactPowerLinks)
+ {
+ ArtifactPowerEntry const* artifactPowerLink = sArtifactPowerStore.LookupEntry(artifactPowerLinkId);
+ if (!artifactPowerLink)
+ continue;
+
+ ItemDynamicFieldArtifactPowers const* artifactPowerLinkLearned = artifact->GetArtifactPower(artifactPowerLinkId);
+ if (!artifactPowerLinkLearned)
+ continue;
+
+ if (artifactPowerLinkLearned->PurchasedRank >= artifactPowerLink->MaxRank)
+ {
+ hasAnyLink = true;
+ break;
+ }
+ }
+
+ if (!hasAnyLink)
+ return;
+ }
+
+ ArtifactPowerRankEntry const* artifactPowerRank = sDB2Manager.GetArtifactPowerRank(artifactPower->ArtifactPowerId, artifactPower->CurrentRankWithBonus + 1 - 1); // need data for next rank, but -1 because of how db2 data is structured
+ if (!artifactPowerRank)
+ return;
+
+ ItemDynamicFieldArtifactPowers newPower = *artifactPower;
+ ++newPower.PurchasedRank;
+ ++newPower.CurrentRankWithBonus;
+ artifact->SetArtifactPower(&newPower);
+
+ if (artifact->IsEquipped())
+ {
+ _player->ApplyArtifactPowerRank(artifact, artifactPowerRank, true);
+
+ for (ItemDynamicFieldArtifactPowers const& power : artifact->GetArtifactPowers())
+ {
+ ArtifactPowerEntry const* scaledArtifactPowerEntry = sArtifactPowerStore.AssertEntry(power.ArtifactPowerId);
+ if (!(scaledArtifactPowerEntry->Flags & ARTIFACT_POWER_FLAG_SCALES_WITH_NUM_POWERS))
+ continue;
+
+ ArtifactPowerRankEntry const* scaledArtifactPowerRank = sDB2Manager.GetArtifactPowerRank(scaledArtifactPowerEntry->ID, 0);
+ if (!scaledArtifactPowerRank)
+ continue;
+
+ ItemDynamicFieldArtifactPowers newScaledPower = power;
+ ++newScaledPower.CurrentRankWithBonus;
+ artifact->SetArtifactPower(&newScaledPower);
+
+ _player->ApplyArtifactPowerRank(artifact, scaledArtifactPowerRank, false);
+ _player->ApplyArtifactPowerRank(artifact, scaledArtifactPowerRank, true);
+ }
+ }
+
+ artifact->ApplyModInt32Value(ITEM_FIELD_ARTIFACT_XP, xpCost, false);
+ artifact->SetState(ITEM_CHANGED, _player);
+}
+
+void WorldSession::HandleArtifactSetAppearance(WorldPackets::Artifact::ArtifactSetAppearance& artifactSetAppearance)
+{
+ if (!_player->GetGameObjectIfCanInteractWith(artifactSetAppearance.ForgeGUID, GAMEOBJECT_TYPE_ARTIFACT_FORGE))
+ return;
+
+ ArtifactAppearanceEntry const* artifactAppearance = sArtifactAppearanceStore.LookupEntry(artifactSetAppearance.ArtifactAppearanceID);
+ if (!artifactAppearance)
+ return;
+
+ Item* artifact = _player->GetItemByGuid(artifactSetAppearance.ArtifactGUID);
+ if (!artifact)
+ return;
+
+ ArtifactAppearanceSetEntry const* artifactAppearanceSet = sArtifactAppearanceSetStore.LookupEntry(artifactAppearance->ArtifactAppearanceSetID);
+ if (!artifactAppearanceSet || artifactAppearanceSet->ArtifactID != artifact->GetTemplate()->GetArtifactID())
+ return;
+
+ if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(artifactAppearance->PlayerConditionID))
+ if (!sConditionMgr->IsPlayerMeetingCondition(_player, playerCondition))
+ return;
+
+ artifact->SetAppearanceModId(artifactAppearance->AppearanceModID);
+ artifact->SetModifier(ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID, artifactAppearance->ID);
+ artifact->SetState(ITEM_CHANGED, _player);
+ Item* childItem = _player->GetChildItemByGuid(artifact->GetChildItem());
+ if (childItem)
+ {
+ childItem->SetAppearanceModId(artifactAppearance->AppearanceModID);
+ childItem->SetState(ITEM_CHANGED, _player);
+ }
+
+ if (artifact->IsEquipped())
+ {
+ // change weapon appearance
+ _player->SetVisibleItemSlot(artifact->GetSlot(), artifact);
+ if (childItem)
+ _player->SetVisibleItemSlot(childItem->GetSlot(), childItem);
+
+ // change druid form appearance
+ if (artifactAppearance->ShapeshiftDisplayID && artifactAppearance->ModifiesShapeshiftFormDisplay && _player->GetShapeshiftForm() == ShapeshiftForm(artifactAppearance->ModifiesShapeshiftFormDisplay))
+ _player->RestoreDisplayId();
+ }
+}
+
+void WorldSession::HandleConfirmArtifactRespec(WorldPackets::Artifact::ConfirmArtifactRespec& confirmArtifactRespec)
+{
+ if (!_player->GetNPCIfCanInteractWith(confirmArtifactRespec.NpcGUID, UNIT_NPC_FLAG_ARTIFACT_POWER_RESPEC))
+ return;
+
+ Item* artifact = _player->GetItemByGuid(confirmArtifactRespec.ArtifactGUID);
+ if (!artifact)
+ return;
+
+ uint32 xpCost = 0;
+ if (GtArtifactLevelXPEntry const* cost = sArtifactLevelXPGameTable.GetRow(artifact->GetTotalPurchasedArtifactPowers() + 1))
+ xpCost = uint32(cost->XP);
+
+ if (xpCost > artifact->GetUInt32Value(ITEM_FIELD_ARTIFACT_XP))
+ return;
+
+ uint32 newAmount = artifact->GetUInt32Value(ITEM_FIELD_ARTIFACT_XP) - xpCost;
+ for (uint32 i = 0; i <= artifact->GetTotalPurchasedArtifactPowers(); ++i)
+ if (GtArtifactLevelXPEntry const* cost = sArtifactLevelXPGameTable.GetRow(i))
+ newAmount += uint32(cost->XP);
+
+ for (ItemDynamicFieldArtifactPowers const& artifactPower : artifact->GetArtifactPowers())
+ {
+ uint8 oldPurchasedRank = artifactPower.PurchasedRank;
+ if (!oldPurchasedRank)
+ continue;
+
+ ItemDynamicFieldArtifactPowers newPower = artifactPower;
+ newPower.PurchasedRank -= oldPurchasedRank;
+ newPower.CurrentRankWithBonus -= oldPurchasedRank;
+ artifact->SetArtifactPower(&newPower);
+
+ if (artifact->IsEquipped())
+ {
+ ArtifactPowerRankEntry const* artifactPowerRank = sDB2Manager.GetArtifactPowerRank(artifactPower.ArtifactPowerId, 0);
+ _player->ApplyArtifactPowerRank(artifact, artifactPowerRank, false);
+ }
+ }
+
+ for (ItemDynamicFieldArtifactPowers const& power : artifact->GetArtifactPowers())
+ {
+ ArtifactPowerEntry const* scaledArtifactPowerEntry = sArtifactPowerStore.AssertEntry(power.ArtifactPowerId);
+ if (!(scaledArtifactPowerEntry->Flags & ARTIFACT_POWER_FLAG_SCALES_WITH_NUM_POWERS))
+ continue;
+
+ ArtifactPowerRankEntry const* scaledArtifactPowerRank = sDB2Manager.GetArtifactPowerRank(scaledArtifactPowerEntry->ID, 0);
+ if (!scaledArtifactPowerRank)
+ continue;
+
+ ItemDynamicFieldArtifactPowers newScaledPower = power;
+ newScaledPower.CurrentRankWithBonus = 0;
+ artifact->SetArtifactPower(&newScaledPower);
+
+ _player->ApplyArtifactPowerRank(artifact, scaledArtifactPowerRank, false);
+ }
+
+ artifact->SetUInt32Value(ITEM_FIELD_ARTIFACT_XP, newAmount);
+ artifact->SetState(ITEM_CHANGED, _player);
+}
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index d1f2c3d7563..efbd3bcdcef 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -131,6 +131,10 @@ bool LoginQueryHolder::Initialize()
stmt->setUInt64(0, lowGuid);
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_INVENTORY, stmt);
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_INSTANCE_ARTIFACT);
+ stmt->setUInt64(0, lowGuid);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_ARTIFACTS, stmt);
+
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_VOID_STORAGE);
stmt->setUInt64(0, lowGuid);
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE, stmt);
diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp
index 26f88bc6528..303e6158a16 100644
--- a/src/server/game/Handlers/ItemHandler.cpp
+++ b/src/server/game/Handlers/ItemHandler.cpp
@@ -1046,9 +1046,9 @@ void WorldSession::HandleSocketGems(WorldPackets::Item::SocketGems& socketGems)
//if a meta gem is being equipped, all information has to be written to the item before testing if the conditions for the gem are met
- //remove ALL enchants
- for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT + MAX_GEM_SOCKETS; ++enchant_slot)
- _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), false);
+ //remove ALL mods - gem can change item level
+ if (itemTarget->IsEquipped())
+ _player->_ApplyItemMods(itemTarget, itemTarget->GetSlot(), false);
for (uint16 i = 0; i < MAX_GEM_SOCKETS; ++i)
{
@@ -1057,15 +1057,24 @@ void WorldSession::HandleSocketGems(WorldPackets::Item::SocketGems& socketGems)
itemTarget->SetGem(i, &gemData[i]);
if (gemProperties[i] && gemProperties[i]->EnchantID)
- itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT+i), gemProperties[i]->EnchantID, 0, 0, _player->GetGUID());
+ itemTarget->SetEnchantment(EnchantmentSlot(SOCK_ENCHANTMENT_SLOT + i), gemProperties[i]->EnchantID, 0, 0, _player->GetGUID());
uint32 gemCount = 1;
_player->DestroyItemCount(gems[i], gemCount, true);
}
}
- for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+MAX_GEM_SOCKETS; ++enchant_slot)
- _player->ApplyEnchantment(itemTarget, EnchantmentSlot(enchant_slot), true);
+ if (itemTarget->IsEquipped())
+ _player->_ApplyItemMods(itemTarget, itemTarget->GetSlot(), true);
+
+ if (Item* childItem = _player->GetChildItemByGuid(itemTarget->GetChildItem()))
+ {
+ if (childItem->IsEquipped())
+ _player->_ApplyItemMods(childItem, childItem->GetSlot(), false);
+ childItem->CopyArtifactDataFromParent(itemTarget);
+ if (childItem->IsEquipped())
+ _player->_ApplyItemMods(childItem, childItem->GetSlot(), true);
+ }
bool SocketBonusToBeActivated = itemTarget->GemsFitSockets();//current socketbonus state
if (SocketBonusActivated ^ SocketBonusToBeActivated) //if there was a change...
diff --git a/src/server/game/Handlers/VoidStorageHandler.cpp b/src/server/game/Handlers/VoidStorageHandler.cpp
index 6575f7b045c..ee4d43dff08 100644
--- a/src/server/game/Handlers/VoidStorageHandler.cpp
+++ b/src/server/game/Handlers/VoidStorageHandler.cpp
@@ -155,7 +155,9 @@ void WorldSession::HandleVoidStorageTransfer(WorldPackets::VoidStorage::VoidStor
}
VoidStorageItem itemVS(sObjectMgr->GenerateVoidStorageItemId(), item->GetEntry(), item->GetGuidValue(ITEM_FIELD_CREATOR),
- item->GetItemRandomPropertyId(), item->GetItemSuffixFactor(), item->GetModifier(ITEM_MODIFIER_UPGRADE_ID), item->GetDynamicValues(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS));
+ item->GetItemRandomPropertyId(), item->GetItemSuffixFactor(), item->GetModifier(ITEM_MODIFIER_UPGRADE_ID),
+ item->GetModifier(ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL), item->GetModifier(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL),
+ item->GetDynamicValues(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS));
WorldPackets::VoidStorage::VoidItem voidItem;
voidItem.Guid = ObjectGuid::Create<HighGuid::Item>(itemVS.ItemId);
diff --git a/src/server/game/Server/Packets/AllPackets.h b/src/server/game/Server/Packets/AllPackets.h
index 932b38bbd5e..7c4f7ba39ab 100644
--- a/src/server/game/Server/Packets/AllPackets.h
+++ b/src/server/game/Server/Packets/AllPackets.h
@@ -19,6 +19,7 @@
#define AllPackets_h__
#include "AchievementPackets.h"
+#include "ArtifactPackets.h"
#include "AuctionHousePackets.h"
#include "AuthenticationPackets.h"
#include "BankPackets.h"
diff --git a/src/server/game/Server/Packets/ArtifactPackets.cpp b/src/server/game/Server/Packets/ArtifactPackets.cpp
new file mode 100644
index 00000000000..1f80789076a
--- /dev/null
+++ b/src/server/game/Server/Packets/ArtifactPackets.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ArtifactPackets.h"
+
+ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Artifact::ArtifactAddPower::ArtifactPowerChoice& artifactPowerChoice)
+{
+ data >> artifactPowerChoice.ArtifactPowerID;
+ data >> artifactPowerChoice.Rank;
+ return data;
+}
+
+void WorldPackets::Artifact::ArtifactAddPower::Read()
+{
+ _worldPacket >> ArtifactGUID;
+ _worldPacket >> ForgeGUID;
+ PowerChoices.resize(_worldPacket.read<uint32>());
+ for (ArtifactPowerChoice& artifactPowerChoice : PowerChoices)
+ _worldPacket >> artifactPowerChoice;
+}
+
+void WorldPackets::Artifact::ArtifactSetAppearance::Read()
+{
+ _worldPacket >> ArtifactGUID;
+ _worldPacket >> ForgeGUID;
+ _worldPacket >> ArtifactAppearanceID;
+}
+
+void WorldPackets::Artifact::ConfirmArtifactRespec::Read()
+{
+ _worldPacket >> ArtifactGUID;
+ _worldPacket >> NpcGUID;
+}
+
+WorldPacket const* WorldPackets::Artifact::ArtifactForgeOpened::Write()
+{
+ _worldPacket << ArtifactGUID;
+ _worldPacket << ForgeGUID;
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Artifact::ArtifactRespecConfirm::Write()
+{
+ _worldPacket << ArtifactGUID;
+ _worldPacket << NpcGUID;
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Artifact::ArtifactXpGain::Write()
+{
+ _worldPacket << ArtifactGUID;
+ _worldPacket << int32(Amount);
+
+ return &_worldPacket;
+}
diff --git a/src/server/game/Server/Packets/ArtifactPackets.h b/src/server/game/Server/Packets/ArtifactPackets.h
new file mode 100644
index 00000000000..f8ad3011ce0
--- /dev/null
+++ b/src/server/game/Server/Packets/ArtifactPackets.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ArtifactPackets_h__
+#define ArtifactPackets_h__
+
+#include "Packet.h"
+#include "PacketUtilities.h"
+#include "ObjectGuid.h"
+
+namespace WorldPackets
+{
+ namespace Artifact
+ {
+ class ArtifactAddPower final : public ClientPacket
+ {
+ public:
+ struct ArtifactPowerChoice
+ {
+ int32 ArtifactPowerID = 0;
+ uint8 Rank = 0;
+ };
+
+ ArtifactAddPower(WorldPacket&& packet) : ClientPacket(CMSG_ARTIFACT_ADD_POWER, std::move(packet)) { }
+
+ void Read() override;
+
+ ObjectGuid ArtifactGUID;
+ ObjectGuid ForgeGUID;
+ Array<ArtifactPowerChoice, 1 /*lua allows only 1 power per call*/> PowerChoices;
+ };
+
+ class ArtifactSetAppearance final : public ClientPacket
+ {
+ public:
+ ArtifactSetAppearance(WorldPacket&& packet) : ClientPacket(CMSG_ARTIFACT_SET_APPEARANCE, std::move(packet)) { }
+
+ void Read() override;
+
+ ObjectGuid ArtifactGUID;
+ ObjectGuid ForgeGUID;
+ int32 ArtifactAppearanceID = 0;
+ };
+
+ class ConfirmArtifactRespec final : public ClientPacket
+ {
+ public:
+ ConfirmArtifactRespec(WorldPacket&& packet) : ClientPacket(CMSG_CONFIRM_ARTIFACT_RESPEC, std::move(packet)) { }
+
+ void Read() override;
+
+ ObjectGuid ArtifactGUID;
+ ObjectGuid NpcGUID;
+ };
+
+ class ArtifactForgeOpened final : public ServerPacket
+ {
+ public:
+ ArtifactForgeOpened() : ServerPacket(SMSG_ARTIFACT_FORGE_OPENED, 16 + 16) { }
+
+ WorldPacket const* Write() override;
+
+ ObjectGuid ArtifactGUID;
+ ObjectGuid ForgeGUID;
+ };
+
+ class ArtifactRespecConfirm final : public ServerPacket
+ {
+ public:
+ ArtifactRespecConfirm() : ServerPacket(SMSG_ARTIFACT_RESPEC_CONFIRM, 16 + 16) { }
+
+ WorldPacket const* Write() override;
+
+ ObjectGuid ArtifactGUID;
+ ObjectGuid NpcGUID;
+ };
+
+ class ArtifactXpGain final : public ServerPacket
+ {
+ public:
+ ArtifactXpGain() : ServerPacket(SMSG_ARTIFACT_XP_GAIN, 16 + 4) { }
+
+ WorldPacket const* Write() override;
+
+ ObjectGuid ArtifactGUID;
+ int32 Amount = 0;
+ };
+ }
+}
+
+#endif // ArtifactPackets_h__
diff --git a/src/server/game/Server/Packets/ItemPackets.cpp b/src/server/game/Server/Packets/ItemPackets.cpp
index 54bc120d178..73225ae8e02 100644
--- a/src/server/game/Server/Packets/ItemPackets.cpp
+++ b/src/server/game/Server/Packets/ItemPackets.cpp
@@ -319,10 +319,15 @@ void WorldPackets::Item::ItemInstance::Initialize(::VoidStorageItem const* voidI
ItemID = voidItem->ItemEntry;
RandomPropertiesID = voidItem->ItemRandomPropertyId;
RandomPropertiesSeed = voidItem->ItemSuffixFactor;
- if (voidItem->ItemUpgradeId)
+ if (voidItem->ItemUpgradeId || voidItem->FixedScalingLevel || voidItem->ArtifactKnowledgeLevel)
{
Modifications = boost::in_place();
- Modifications->Insert(ITEM_MODIFIER_UPGRADE_ID, voidItem->ItemUpgradeId);
+ if (voidItem->ItemUpgradeId)
+ Modifications->Insert(ITEM_MODIFIER_UPGRADE_ID, voidItem->ItemUpgradeId);
+ if (voidItem->FixedScalingLevel)
+ Modifications->Insert(ITEM_MODIFIER_SCALING_STAT_DISTRIBUTION_FIXED_LEVEL, voidItem->FixedScalingLevel);
+ if (voidItem->ArtifactKnowledgeLevel)
+ Modifications->Insert(ITEM_MODIFIER_ARTIFACT_KNOWLEDGE_LEVEL, voidItem->ArtifactKnowledgeLevel);
}
if (!voidItem->BonusListIDs.empty())
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index ca86d3de4e3..9a6d7adba71 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -140,8 +140,8 @@ void OpcodeTable::Initialize()
DEFINE_HANDLER(CMSG_AREA_SPIRIT_HEALER_QUERY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAreaSpiritHealerQueryOpcode);
DEFINE_HANDLER(CMSG_AREA_SPIRIT_HEALER_QUEUE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAreaSpiritHealerQueueOpcode);
DEFINE_HANDLER(CMSG_AREA_TRIGGER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAreaTriggerOpcode);
- DEFINE_HANDLER(CMSG_ARTIFACT_ADD_POWER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
- DEFINE_HANDLER(CMSG_ARTIFACT_SET_APPEARANCE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
+ DEFINE_HANDLER(CMSG_ARTIFACT_ADD_POWER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArtifactAddPower);
+ DEFINE_HANDLER(CMSG_ARTIFACT_SET_APPEARANCE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleArtifactSetAppearance);
DEFINE_HANDLER(CMSG_ATTACK_STOP, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleAttackStopOpcode);
DEFINE_HANDLER(CMSG_ATTACK_SWING, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleAttackSwingOpcode);
DEFINE_HANDLER(CMSG_AUCTION_HELLO_REQUEST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionHelloOpcode);
@@ -310,7 +310,7 @@ void OpcodeTable::Initialize()
DEFINE_HANDLER(CMSG_COMPLAINT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleComplaint);
DEFINE_HANDLER(CMSG_COMPLETE_CINEMATIC, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleCompleteCinematic);
DEFINE_HANDLER(CMSG_COMPLETE_MOVIE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
- DEFINE_HANDLER(CMSG_CONFIRM_ARTIFACT_RESPEC, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
+ DEFINE_HANDLER(CMSG_CONFIRM_ARTIFACT_RESPEC, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleConfirmArtifactRespec);
DEFINE_HANDLER(CMSG_CONFIRM_RESPEC_WIPE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleConfirmRespecWipeOpcode);
DEFINE_HANDLER(CMSG_CONNECT_TO_FAILED, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_EarlyProccess);
DEFINE_HANDLER(CMSG_CONVERT_RAID, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleConvertRaidOpcode);
@@ -858,9 +858,10 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_PREP_OPPONENT_SPECIALIZATIONS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARTIFACT_APPEARANCE_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARTIFACT_FORGE_OPENED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARTIFACT_FORGE_OPENED, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARTIFACT_POWERS_UPDATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
- DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARTIFACT_XP_GAIN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARTIFACT_RESPEC_CONFIRM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+ DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARTIFACT_XP_GAIN, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACKER_STATE_UPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACK_START, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_ATTACK_STOP, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h
index 223d55cc9d0..3dde86efe49 100644
--- a/src/server/game/Server/Protocol/Opcodes.h
+++ b/src/server/game/Server/Protocol/Opcodes.h
@@ -775,6 +775,7 @@ enum OpcodeServer : uint32
SMSG_ARTIFACT_APPEARANCE_CHANGED = 0x27E3,
SMSG_ARTIFACT_FORGE_OPENED = 0x27E1,
SMSG_ARTIFACT_POWERS_UPDATED = 0x27E2,
+ SMSG_ARTIFACT_RESPEC_CONFIRM = 0x27E4,
SMSG_ARTIFACT_XP_GAIN = 0x2823,
SMSG_ATTACKER_STATE_UPDATE = 0x27CE,
SMSG_ATTACK_START = 0x2669,
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index 6fdf5c560bf..be4060bdc9b 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -80,6 +80,13 @@ namespace WorldPackets
class GuildSetFocusedAchievement;
}
+ namespace Artifact
+ {
+ class ArtifactAddPower;
+ class ArtifactSetAppearance;
+ class ConfirmArtifactRespec;
+ }
+
namespace AuctionHouse
{
class AuctionHelloRequest;
@@ -1718,6 +1725,11 @@ class TC_GAME_API WorldSession
std::unordered_map<uint32, uint8> const& GetRealmCharacterCounts() const { return _realmCharacterCounts; }
+ // Artifact
+ void HandleArtifactAddPower(WorldPackets::Artifact::ArtifactAddPower& artifactAddPower);
+ void HandleArtifactSetAppearance(WorldPackets::Artifact::ArtifactSetAppearance& artifactSetAppearance);
+ void HandleConfirmArtifactRespec(WorldPackets::Artifact::ConfirmArtifactRespec& confirmArtifactRespec);
+
union ConnectToKey
{
struct
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 16227861a26..14d5f27b182 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -5416,6 +5416,25 @@ SpellCastResult Spell::CheckCast(bool strict)
return SPELL_FAILED_CANT_UNTALENT;
break;
}
+ case SPELL_EFFECT_GIVE_ARTIFACT_POWER:
+ case SPELL_EFFECT_GIVE_ARTIFACT_POWER_NO_BONUS:
+ {
+ if (m_caster->GetTypeId() != TYPEID_PLAYER)
+ return SPELL_FAILED_BAD_TARGETS;
+ Aura* artifactAura = m_caster->GetAura(ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE);
+ if (!artifactAura)
+ return SPELL_FAILED_NO_ARTIFACT_EQUIPPED;
+ Item* artifact = m_caster->ToPlayer()->GetItemByGuid(artifactAura->GetCastItemGUID());
+ if (!artifact)
+ return SPELL_FAILED_NO_ARTIFACT_EQUIPPED;
+ if (effect->Effect == SPELL_EFFECT_GIVE_ARTIFACT_POWER)
+ {
+ ArtifactEntry const* artifactEntry = sArtifactStore.LookupEntry(artifact->GetTemplate()->GetArtifactID());
+ if (!artifactEntry || artifactEntry->ArtifactCategoryID != effect->MiscValue)
+ return SPELL_FAILED_WRONG_ARTIFACT_EQUIPPED;
+ }
+ break;
+ }
default:
break;
}
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index e369ed29242..33e3107dc03 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -394,7 +394,6 @@ class TC_GAME_API Spell
void EffectMilling(SpellEffIndex effIndex);
void EffectRenamePet(SpellEffIndex effIndex);
void EffectSendTaxi(SpellEffIndex effIndex);
- void EffectSummonCritter(SpellEffIndex effIndex);
void EffectKnockBack(SpellEffIndex effIndex);
void EffectPullTowards(SpellEffIndex effIndex);
void EffectDispelMechanic(SpellEffIndex effIndex);
@@ -453,6 +452,8 @@ class TC_GAME_API Spell
void EffectApplyEnchantIllusion(SpellEffIndex effIndex);
void EffectUpdatePlayerPhase(SpellEffIndex effIndex);
void EffectUpdateZoneAurasAndPhases(SpellEffIndex effIndex);
+ void EffectGiveArtifactPower(SpellEffIndex effIndex);
+ void EffectGiveArtifactPowerNoBonus(SpellEffIndex effIndex);
typedef std::set<Aura*> UsedSpellMods;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index f84704f09c6..4e95cb81afb 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -304,9 +304,9 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectNULL, //237 SPELL_EFFECT_GIVE_RESTED_EXPERIENCE_BONUS
&Spell::EffectNULL, //238 SPELL_EFFECT_INCREASE_SKILL
&Spell::EffectNULL, //239 SPELL_EFFECT_END_GARRISON_BUILDING_CONSTRUCTION
- &Spell::EffectNULL, //240 SPELL_EFFECT_GIVE_ARTIFACT_POWER
+ &Spell::EffectGiveArtifactPower, //240 SPELL_EFFECT_GIVE_ARTIFACT_POWER
&Spell::EffectNULL, //241 SPELL_EFFECT_241
- &Spell::EffectNULL, //242 SPELL_EFFECT_GIVE_ARTIFACT_POWER_NO_BONUS
+ &Spell::EffectGiveArtifactPowerNoBonus, //242 SPELL_EFFECT_GIVE_ARTIFACT_POWER_NO_BONUS
&Spell::EffectApplyEnchantIllusion, //243 SPELL_EFFECT_APPLY_ENCHANT_ILLUSION
&Spell::EffectNULL, //244 SPELL_EFFECT_LEARN_FOLLOWER_ABILITY
&Spell::EffectUpgradeHeirloom, //245 SPELL_EFFECT_UPGRADE_HEIRLOOM
@@ -5831,3 +5831,29 @@ void Spell::EffectUpdateZoneAurasAndPhases(SpellEffIndex /*effIndex*/)
unitTarget->ToPlayer()->UpdateAreaDependentAuras(unitTarget->GetAreaId());
}
+
+void Spell::EffectGiveArtifactPower(SpellEffIndex /*effIndex*/)
+{
+ if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
+ return;
+
+ if (m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ if (Aura* artifactAura = m_caster->GetAura(ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE))
+ if (Item* artifact = m_caster->ToPlayer()->GetItemByGuid(artifactAura->GetCastItemGUID()))
+ artifact->GiveArtifactXp(damage, m_CastItem, uint32(effectInfo->MiscValue));
+}
+
+void Spell::EffectGiveArtifactPowerNoBonus(SpellEffIndex /*effIndex*/)
+{
+ if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH_TARGET)
+ return;
+
+ if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ if (Aura* artifactAura = unitTarget->GetAura(ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE))
+ if (Item* artifact = unitTarget->ToPlayer()->GetItemByGuid(artifactAura->GetCastItemGUID()))
+ artifact->GiveArtifactXp(damage, m_CastItem, 0);
+}
diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp
index 6619a108009..b797d8689fb 100644
--- a/src/server/scripts/Spells/spell_item.cpp
+++ b/src/server/scripts/Spells/spell_item.cpp
@@ -2728,6 +2728,80 @@ public:
}
};
+class spell_item_artifical_stamina : public SpellScriptLoader
+{
+public:
+ spell_item_artifical_stamina() : SpellScriptLoader("spell_item_artifical_stamina") { }
+
+ class spell_item_artifical_stamina_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_artifical_stamina_AuraScript);
+
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ return spellInfo->GetEffect(EFFECT_1) != nullptr;
+ }
+
+ bool Load() override
+ {
+ return GetOwner()->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated)
+ {
+ if (Item* artifact = GetOwner()->ToPlayer()->GetItemByGuid(GetAura()->GetCastItemGUID()))
+ amount = GetSpellInfo()->GetEffect(EFFECT_1)->BasePoints * std::max(artifact->GetTotalPurchasedArtifactPowers(), 34u) / 100;
+ }
+
+ void Register() override
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_item_artifical_stamina_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_artifical_stamina_AuraScript();
+ }
+};
+
+class spell_item_artifical_damage : public SpellScriptLoader
+{
+public:
+ spell_item_artifical_damage() : SpellScriptLoader("spell_item_artifical_damage") { }
+
+ class spell_item_artifical_damage_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_item_artifical_damage_AuraScript);
+
+ bool Validate(SpellInfo const* spellInfo) override
+ {
+ return spellInfo->GetEffect(EFFECT_1) != nullptr;
+ }
+
+ bool Load() override
+ {
+ return GetOwner()->GetTypeId() == TYPEID_PLAYER;
+ }
+
+ void CalculateAmount(AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated)
+ {
+ if (Item* artifact = GetOwner()->ToPlayer()->GetItemByGuid(GetAura()->GetCastItemGUID()))
+ amount = GetSpellInfo()->GetEffect(EFFECT_1)->BasePoints * std::max(artifact->GetTotalPurchasedArtifactPowers(), 34u) / 100;
+ }
+
+ void Register() override
+ {
+ DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_item_artifical_damage_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_item_artifical_damage_AuraScript();
+ }
+};
+
void AddSC_item_spell_scripts()
{
// 23074 Arcanite Dragonling
@@ -2798,4 +2872,6 @@ void AddSC_item_spell_scripts()
new spell_item_muisek_vessel();
new spell_item_greatmothers_soulcatcher();
new spell_item_toy_train_set_pulse();
+ new spell_item_artifical_stamina();
+ new spell_item_artifical_damage();
}