diff options
author | Shauren <shauren.trinity@gmail.com> | 2016-08-15 00:03:38 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2016-08-15 00:03:38 +0200 |
commit | fea0cb16f2e73ec21891ac14cdc10d9d8f518cfe (patch) | |
tree | 7e3a6ee9b3876ca5b3a7115a9d932ce8125c41e1 | |
parent | f8c5a2c723c734513eddc98a5c7f380c2f00e479 (diff) |
Core/Items: Implemented artifacts
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(); } |