diff options
author | Krudor <erikstrandberg93@hotmail.com> | 2016-11-06 23:30:49 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2016-11-06 23:30:49 +0100 |
commit | 8444ab736568667cb6425757ce5f832cb6068379 (patch) | |
tree | 375c6a9d25b9d5a4d351f4e3a7c0b52526dd816f | |
parent | 9d88e78961cc92c2914ffb25333f35433a0c9682 (diff) |
Core/Instances: Implemented base scenario system and objectives in dungeons
Closes #17905
Closes #18034
39 files changed, 1786 insertions, 36 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index 6c7aef6c65f..b6c209edd06 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -3245,7 +3245,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','ARCHIVED','2016-04-11 02:24:14',30),('2016_04_11_01_characters.sql','CA90F6D99C1EEA7B25BD58BC8368A8D78234BBEF','ARCHIVED','2016-04-11 18:14:18',0),('2016_05_07_00_characters.sql','D1DB5557B21A552C935564D829B4E98B98149077','ARCHIVED','2016-05-07 00:00:00',0),('2016_05_26_00_characters.sql','4179ADC32B96FD8D7D4CF5509A470B1ACE00BE85','ARCHIVED','2016-05-26 17:06:16',0),('2016_07_16_00_characters.sql','EF267FCB92B383FFB33C700508EAF3FBC1F8AC23','ARCHIVED','2016-07-16 14:45:12',0),('2016_07_19_00_characters.sql','AA2C516FA81B451071EA82F58F447E9D13E5D1BD','ARCHIVED','2016-07-19 14:36:25',0),('2016_07_19_01_characters.sql','E9AF46AF4C7CC2E2779E44254AEEDF880D020166','ARCHIVED','2016-07-19 14:36:25',0),('2016_07_19_02_characters.sql','5B1B334449996F3639C9226F587129E03DC4BF6D','ARCHIVED','2016-07-19 14:36:26',0),('2016_07_19_03_characters.sql','7787C8A67D720492FED4BF60ADB22D3CDE1C536D','ARCHIVED','2016-07-19 14:36:26',0),('2016_07_19_04_characters.sql','6D4B536094367AC9EF7CDFF41A4F96EB00B25EE5','ARCHIVED','2016-07-19 14:36:26',0),('2016_07_19_05_characters.sql','12639268DC5F78CE900B59D5C646B10D70842928','ARCHIVED','2016-07-19 14:36:27',0),('2016_07_19_06_characters.sql','9F5A4B533E6BFBAA718DE5160E1FDCB8471A88BF','ARCHIVED','2016-07-19 14:36:28',0),('2016_07_19_07_characters.sql','1E8273FFD4340CBD7BB71D2406E23E9EF7230CFA','ARCHIVED','2016-07-19 14:36:29',0),('2016_07_19_08_characters.sql','FB41FD2F8A7114FEE154021A9D47488C4B12E2A9','ARCHIVED','2016-07-19 14:36:29',0),('2016_08_15_00_characters.sql','BF0B5F453384210CD77C54E262A19B888AAA4095','ARCHIVED','2016-08-14 18:14:32',0),('2016_08_25_00_characters.sql','4AD506C3FCE54238EF452AC07EC562BD41A9D50C','ARCHIVED','2016-08-25 22:54:11',0),('2016_10_17_00_characters.sql','A0EF594CD73690D46A46031137DB0E895F079235','RELEASED','2016-10-16 16:33:05',25),('2016_10_25_00_characters.sql','CC894484561CE138C10B69D34F7831CEDFAF496B','RELEASED','2016-10-25 17:19:35',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','ARCHIVED','2016-04-11 02:24:14',30),('2016_04_11_01_characters.sql','CA90F6D99C1EEA7B25BD58BC8368A8D78234BBEF','ARCHIVED','2016-04-11 18:14:18',0),('2016_05_07_00_characters.sql','D1DB5557B21A552C935564D829B4E98B98149077','ARCHIVED','2016-05-07 00:00:00',0),('2016_05_26_00_characters.sql','4179ADC32B96FD8D7D4CF5509A470B1ACE00BE85','ARCHIVED','2016-05-26 17:06:16',0),('2016_07_16_00_characters.sql','EF267FCB92B383FFB33C700508EAF3FBC1F8AC23','ARCHIVED','2016-07-16 14:45:12',0),('2016_07_19_00_characters.sql','AA2C516FA81B451071EA82F58F447E9D13E5D1BD','ARCHIVED','2016-07-19 14:36:25',0),('2016_07_19_01_characters.sql','E9AF46AF4C7CC2E2779E44254AEEDF880D020166','ARCHIVED','2016-07-19 14:36:25',0),('2016_07_19_02_characters.sql','5B1B334449996F3639C9226F587129E03DC4BF6D','ARCHIVED','2016-07-19 14:36:26',0),('2016_07_19_03_characters.sql','7787C8A67D720492FED4BF60ADB22D3CDE1C536D','ARCHIVED','2016-07-19 14:36:26',0),('2016_07_19_04_characters.sql','6D4B536094367AC9EF7CDFF41A4F96EB00B25EE5','ARCHIVED','2016-07-19 14:36:26',0),('2016_07_19_05_characters.sql','12639268DC5F78CE900B59D5C646B10D70842928','ARCHIVED','2016-07-19 14:36:27',0),('2016_07_19_06_characters.sql','9F5A4B533E6BFBAA718DE5160E1FDCB8471A88BF','ARCHIVED','2016-07-19 14:36:28',0),('2016_07_19_07_characters.sql','1E8273FFD4340CBD7BB71D2406E23E9EF7230CFA','ARCHIVED','2016-07-19 14:36:29',0),('2016_07_19_08_characters.sql','FB41FD2F8A7114FEE154021A9D47488C4B12E2A9','ARCHIVED','2016-07-19 14:36:29',0),('2016_08_15_00_characters.sql','BF0B5F453384210CD77C54E262A19B888AAA4095','ARCHIVED','2016-08-14 18:14:32',0),('2016_08_25_00_characters.sql','4AD506C3FCE54238EF452AC07EC562BD41A9D50C','ARCHIVED','2016-08-25 22:54:11',0),('2016_10_17_00_characters.sql','A0EF594CD73690D46A46031137DB0E895F079235','RELEASED','2016-10-16 16:33:05',25),('2016_10_25_00_characters.sql','CC894484561CE138C10B69D34F7831CEDFAF496B','RELEASED','2016-10-25 17:19:35',0),('2016_11_06_00_characters.sql','C7EC8B65C1BE7722C53BAB79C52C1549054178C0','RELEASED','2016-11-06 23:05:44',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/characters/master/2016_11_06_00_characters.sql b/sql/updates/characters/master/2016_11_06_00_characters.sql new file mode 100644 index 00000000000..1b4f22e24e7 --- /dev/null +++ b/sql/updates/characters/master/2016_11_06_00_characters.sql @@ -0,0 +1,11 @@ +-- +-- Table structure for table `instance_scenario_progress` +-- +DROP TABLE IF EXISTS `instance_scenario_progress`; +CREATE TABLE `instance_scenario_progress` ( + `id` int(10) unsigned NOT NULL, + `criteria` int(10) unsigned NOT NULL, + `counter` bigint(20) unsigned NOT NULL, + `date` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`id`,`criteria`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/sql/updates/hotfixes/master/2016_11_06_02_hotfixes.sql b/sql/updates/hotfixes/master/2016_11_06_02_hotfixes.sql new file mode 100644 index 00000000000..fae5062d5fc --- /dev/null +++ b/sql/updates/hotfixes/master/2016_11_06_02_hotfixes.sql @@ -0,0 +1,57 @@ +-- +-- Table structure for table `scenario` +-- +DROP TABLE IF EXISTS `scenario`; +CREATE TABLE `scenario` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `Name` text, + `Data` smallint(5) unsigned NOT NULL DEFAULT '0', + `Flags` tinyint(3) unsigned NOT NULL DEFAULT '0', + `Type` 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 `scenario_locale` +-- +DROP TABLE IF EXISTS `scenario_locale`; +CREATE TABLE `scenario_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 `scenario_step` +-- +DROP TABLE IF EXISTS `scenario_step`; +CREATE TABLE `scenario_step` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `Description` text, + `Name` text, + `CriteriaTreeID` smallint(5) unsigned NOT NULL DEFAULT '0', + `ScenarioID` smallint(5) unsigned NOT NULL DEFAULT '0', + `PreviousStepID` smallint(5) unsigned NOT NULL DEFAULT '0', + `QuestRewardID` smallint(5) unsigned NOT NULL DEFAULT '0', + `Step` tinyint(3) unsigned NOT NULL DEFAULT '0', + `Flags` tinyint(3) unsigned NOT NULL DEFAULT '0', + `BonusRequiredStepID` 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 `scenario_step_locale` +-- +DROP TABLE IF EXISTS `scenario_step_locale`; +CREATE TABLE `scenario_step_locale` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `locale` varchar(4) NOT NULL, + `Description_lang` text, + `Name_lang` text, + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`locale`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/sql/updates/world/master/2016_11_06_00_world.sql b/sql/updates/world/master/2016_11_06_00_world.sql new file mode 100644 index 00000000000..4fab752d9e2 --- /dev/null +++ b/sql/updates/world/master/2016_11_06_00_world.sql @@ -0,0 +1,233 @@ +DROP TABLE IF EXISTS `scenarios`; +CREATE TABLE `scenarios` ( + `map` int(10) unsigned NOT NULL DEFAULT '0', + `difficulty` tinyint(3) unsigned NOT NULL DEFAULT '0', + `scenario_A` int(10) unsigned NOT NULL DEFAULT '0', + `scenario_H` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`map`,`difficulty`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +INSERT INTO `scenarios` (`map`, `difficulty`, `scenario_A`, `scenario_H`) VALUES +(33, 1, 516, 516), +(33, 2, 523, 523), +(34, 1, 510, 0), +(36, 1, 641, 641), +(36, 2, 643, 643), +(43, 1, 515, 515), +(47, 1, 654, 654), +(48, 1, 333, 333), +(70, 1, 648, 648), +(90, 1, 649, 649), +(109, 1, 640, 640), +(129, 1, 647, 647), +(209, 1, 644, 644), +(230, 1, 671, 671), +(269, 1, 610, 610), +(269, 2, 611, 611), +(349, 1, 664, 664), +(389, 1, 511, 511), +(429, 1, 668, 668), +(540, 1, 607, 607), +(540, 2, 608, 608), +(542, 1, 634, 634), +(542, 2, 635, 635), +(543, 1, 638, 638), +(543, 2, 639, 639), +(545, 1, 618, 618), +(545, 2, 619, 619), +(546, 1, 630, 630), +(546, 2, 631, 631), +(547, 1, 632, 632), +(547, 2, 633, 633), +(552, 1, 620, 620), +(552, 2, 621, 621), +(553, 1, 612, 612), +(553, 2, 613, 613), +(554, 1, 614, 614), +(554, 2, 615, 615), +(555, 1, 606, 606), +(555, 2, 609, 609), +(556, 1, 622, 622), +(556, 2, 623, 623), +(557, 1, 628, 628), +(557, 2, 629, 629), +(558, 1, 626, 626), +(558, 2, 627, 627), +(560, 1, 624, 624), +(560, 2, 625, 625), +(568, 2, 574, 574), +(574, 1, 596, 596), +(574, 2, 597, 597), +(575, 1, 577, 577), +(575, 2, 579, 579), +(576, 1, 598, 598), +(576, 2, 605, 599), +(578, 1, 575, 575), +(578, 2, 576, 576), +(585, 1, 616, 616), +(585, 2, 617, 617), +(595, 1, 583, 583), +(595, 2, 585, 585), +(599, 1, 582, 582), +(599, 2, 584, 584), +(600, 1, 590, 590), +(600, 2, 591, 591), +(601, 1, 594, 594), +(601, 2, 595, 595), +(602, 1, 580, 580), +(602, 2, 581, 581), +(604, 1, 586, 586), +(604, 2, 587, 587), +(608, 1, 588, 588), +(608, 2, 589, 589), +(619, 1, 592, 592), +(619, 2, 593, 593), +(632, 1, 566, 566), +(632, 2, 568, 568), +(643, 1, 548, 548), +(643, 2, 550, 550), +(644, 1, 558, 558), +(644, 2, 565, 565), +(645, 1, 542, 542), +(645, 2, 545, 545), +(650, 1, 676, 676), +(650, 2, 677, 677), +(657, 1, 551, 551), +(657, 2, 552, 552), +(658, 1, 569, 569), +(658, 2, 571, 571), +(668, 1, 572, 572), +(668, 2, 573, 573), +(670, 1, 553, 553), +(670, 2, 554, 554), +(725, 1, 674, 674), +(725, 2, 675, 675), +(755, 1, 555, 555), +(755, 2, 557, 557), +(859, 2, 556, 556), +(938, 2, 547, 547), +(939, 2, 567, 567), +(940, 2, 570, 570), +(959, 1, 531, 531), +(959, 2, 535, 535), +(959, 8, 46, 46), +(960, 1, 539, 539), +(960, 2, 540, 540), +(960, 8, 44, 44), +(961, 1, 537, 537), +(961, 2, 538, 538), +(961, 8, 45, 45), +(962, 1, 526, 526), +(962, 2, 527, 527), +(962, 8, 48, 48), +(994, 1, 528, 528), +(994, 2, 536, 536), +(994, 8, 50, 50), +(999, 12, 71, 0), +(1000, 12, 0, 72), +(1001, 1, 650, 650), +(1001, 2, 651, 651), +(1001, 8, 52, 52), +(1004, 1, 652, 652), +(1004, 2, 653, 653), +(1004, 8, 53, 53), +(1005, 11, 65, 65), +(1005, 12, 65, 65), +(1007, 1, 645, 645), +(1007, 2, 646, 646), +(1007, 8, 51, 51), +(1011, 1, 524, 524), +(1011, 2, 525, 525), +(1011, 8, 49, 49), +(1024, 12, 40, 40), +(1030, 11, 39, 39), +(1030, 12, 39, 39), +(1031, 11, 58, 58), +(1031, 12, 58, 58), +(1048, 12, 15, 15), +(1051, 12, 63, 63), +(1095, 12, 179, 179), +(1099, 11, 182, 239), +(1099, 12, 182, 239), +(1102, 12, 0, 201), +(1103, 12, 184, 184), +(1104, 12, 183, 183), +(1112, 12, 200, 200), +(1126, 12, 205, 205), +(1130, 11, 210, 210), +(1130, 12, 210, 210), +(1131, 11, 219, 219), +(1131, 12, 219, 219), +(1135, 12, 215, 215), +(1144, 11, 216, 216), +(1144, 12, 216, 216), +(1148, 1, 237, 237), +(1148, 12, 237, 237), +(1161, 12, 257, 257), +(1168, 12, 275, 275), +(1175, 1, 680, 680), +(1175, 2, 681, 681), +(1175, 8, 425, 425), +(1176, 1, 686, 686), +(1176, 2, 687, 687), +(1176, 8, 428, 428), +(1176, 23, 687, 687), +(1182, 1, 678, 678), +(1182, 2, 679, 679), +(1182, 8, 427, 427), +(1182, 23, 679, 679), +(1195, 1, 684, 684), +(1195, 2, 685, 685), +(1195, 8, 426, 426), +(1195, 23, 685, 685), +(1203, 12, 324, 324), +(1207, 12, 331, 331), +(1208, 1, 682, 682), +(1208, 2, 683, 683), +(1208, 8, 429, 429), +(1208, 23, 683, 683), +(1209, 1, 688, 688), +(1209, 2, 689, 689), +(1209, 8, 423, 423), +(1209, 23, 689, 689), +(1277, 12, 449, 449), +(1279, 1, 708, 708), +(1279, 2, 709, 709), +(1279, 8, 430, 430), +(1279, 23, 709, 709), +(1358, 1, 744, 744), +(1358, 2, 329, 329), +(1358, 8, 432, 432), +(1358, 19, 731, 731), +(1402, 12, 320, 320), +(1431, 1, 736, 736), +(1455, 12, 776, 776); + +DROP TABLE IF EXISTS `scenario_poi`; +CREATE TABLE `scenario_poi` ( + `CriteriaTreeID` INT(11) NOT NULL DEFAULT '0', + `BlobIndex` INT(11) NOT NULL DEFAULT '0', + `Idx1` INT(11) NOT NULL DEFAULT '0', + `MapID` INT(11) NOT NULL DEFAULT '0', + `WorldMapAreaId` INT(11) NOT NULL DEFAULT '0', + `Floor` INT(11) NOT NULL DEFAULT '0', + `Priority` INT(11) NOT NULL DEFAULT '0', + `Flags` INT(11) NOT NULL DEFAULT '0', + `WorldEffectID` INT(11) NOT NULL DEFAULT '0', + `PlayerConditionID` INT(11) NOT NULL DEFAULT '0', + `VerifiedBuild` SMALLINT(5) NULL DEFAULT '0', + PRIMARY KEY (`CriteriaTreeID`, `BlobIndex`, `Idx1`), + INDEX `idx` (`CriteriaTreeID`, `BlobIndex`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `scenario_poi_points`; +CREATE TABLE `scenario_poi_points` ( + `CriteriaTreeID` INT(11) NOT NULL DEFAULT '0', + `Idx1` INT(11) NOT NULL DEFAULT '0', + `Idx2` INT(11) NOT NULL DEFAULT '0', + `X` INT(11) NOT NULL DEFAULT '0', + `Y` INT(11) NOT NULL DEFAULT '0', + `VerifiedBuild` SMALLINT(5) NULL DEFAULT '0', + PRIMARY KEY (`CriteriaTreeID`, `Idx1`, `Idx2`), + INDEX `questId_id` (`CriteriaTreeID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index ee5cfeea1ef..5845a0d6a3a 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -732,4 +732,12 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_BLACKMARKET_AUCTIONS, "DELETE FROM blackmarket_auctions WHERE marketId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_BLACKMARKET_AUCTIONS, "UPDATE blackmarket_auctions SET currentBid = ?, time = ?, numBids = ?, bidder = ? WHERE marketId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_BLACKMARKET_AUCTIONS, "INSERT INTO blackmarket_auctions (marketId, currentBid, time, numBids, bidder) VALUES (?, ?, ?, ? ,?)", CONNECTION_ASYNC); + + // Scenario + PrepareStatement(CHAR_SEL_SCENARIO_INSTANCE_CRITERIA_FOR_INSTANCE, "SELECT criteria, counter, date FROM instance_scenario_progress WHERE id = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_SCENARIO_INSTANCE_CRITERIA, "SELECT counter, date FROM instance_scenario_progress WHERE id = ? AND criteria = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_INS_SCENARIO_INSTANCE_CRITERIA, "INSERT INTO instance_scenario_progress (id, criteria, counter, date) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_SCENARIO_INSTANCE_CRITERIA_FOR_INSTANCE, "DELETE FROM instance_scenario_progress WHERE id = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_SCENARIO_INSTANCE_CRITERIA, "UPDATE instance_scenario_progress SET counter = ?, date = ? WHERE id = ? AND criteria = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_INVALID_SCENARIO_INSTANCE_CRITERIA, "DELETE FROM instance_scenario_progress WHERE id = ? AND criteria = ?", CONNECTION_ASYNC); } diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index c94cbdedd04..02969290007 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -623,6 +623,13 @@ enum CharacterDatabaseStatements CHAR_UPD_BLACKMARKET_AUCTIONS, CHAR_INS_BLACKMARKET_AUCTIONS, + CHAR_SEL_SCENARIO_INSTANCE_CRITERIA_FOR_INSTANCE, + CHAR_SEL_SCENARIO_INSTANCE_CRITERIA, + CHAR_INS_SCENARIO_INSTANCE_CRITERIA, + CHAR_DEL_SCENARIO_INSTANCE_CRITERIA_FOR_INSTANCE, + CHAR_UPD_SCENARIO_INSTANCE_CRITERIA, + CHAR_DEL_INVALID_SCENARIO_INSTANCE_CRITERIA, + MAX_CHARACTERDATABASE_STATEMENTS }; diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp index 774477af109..e9210d0eb38 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp @@ -686,6 +686,15 @@ void HotfixDatabaseConnection::DoPrepareStatements() PrepareStatement(HOTFIX_SEL_SCALING_STAT_DISTRIBUTION, "SELECT ID, ItemLevelCurveID, MinLevel, MaxLevel FROM scaling_stat_distribution" " ORDER BY ID DESC", CONNECTION_SYNCH); + // Scenario.db2 + PrepareStatement(HOTFIX_SEL_SCENARIO, "SELECT ID, Name, Data, Flags, Type FROM scenario ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_SCENARIO, "SELECT ID, Name_lang FROM scenario_locale WHERE locale = ?", CONNECTION_SYNCH); + + // ScenarioStep.db2 + PrepareStatement(HOTFIX_SEL_SCENARIO_STEP, "SELECT ID, Description, Name, CriteriaTreeID, ScenarioID, PreviousStepID, QuestRewardID, Step, Flags, " + "BonusRequiredStepID FROM scenario_step ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_SCENARIO_STEP, "SELECT ID, Description_lang, Name_lang FROM scenario_step_locale WHERE locale = ?", CONNECTION_SYNCH); + // SceneScript.db2 PrepareStatement(HOTFIX_SEL_SCENE_SCRIPT, "SELECT ID, Name, Script, PrevScriptId, NextScriptId FROM scene_script 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 eafc14e07e3..552dbdcc491 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.h +++ b/src/server/database/Database/Implementation/HotfixDatabase.h @@ -372,6 +372,12 @@ enum HotfixDatabaseStatements HOTFIX_SEL_SCALING_STAT_DISTRIBUTION, + HOTFIX_SEL_SCENARIO, + HOTFIX_SEL_SCENARIO_LOCALE, + + HOTFIX_SEL_SCENARIO_STEP, + HOTFIX_SEL_SCENARIO_STEP_LOCALE, + HOTFIX_SEL_SCENE_SCRIPT, HOTFIX_SEL_SCENE_SCRIPT_PACKAGE, diff --git a/src/server/game/Achievements/CriteriaHandler.cpp b/src/server/game/Achievements/CriteriaHandler.cpp index b917cb02cb4..01a06c52548 100644 --- a/src/server/game/Achievements/CriteriaHandler.cpp +++ b/src/server/game/Achievements/CriteriaHandler.cpp @@ -2073,9 +2073,9 @@ void CriteriaMgr::LoadCriteriaList() achievementCriteriaTreeIds[achievement->CriteriaTree] = achievement; std::unordered_map<uint32 /*criteriaTreeID*/, ScenarioStepEntry const*> scenarioCriteriaTreeIds; - //for (ScenarioStepEntry const* scenarioStep : sScenarioStepStore) - // if (scenarioStep->CriteriaTreeID) - // scenarioCriteriaTreeIds[scenarioStep->CriteriaTreeID] = scenarioStep; + for (ScenarioStepEntry const* scenarioStep : sScenarioStepStore) + if (scenarioStep->CriteriaTreeID) + scenarioCriteriaTreeIds[scenarioStep->CriteriaTreeID] = scenarioStep; // Load criteria tree nodes for (CriteriaTreeEntry const* tree : sCriteriaTreeStore) diff --git a/src/server/game/DataStores/DB2LoadInfo.h b/src/server/game/DataStores/DB2LoadInfo.h index 4c05ac1b7eb..9975f0a92ea 100644 --- a/src/server/game/DataStores/DB2LoadInfo.h +++ b/src/server/game/DataStores/DB2LoadInfo.h @@ -3359,6 +3359,43 @@ struct ScalingStatDistributionLoadInfo } }; +struct ScenarioLoadInfo +{ + static DB2LoadInfo Instance() + { + static DB2FieldMeta const fields[] = + { + { false, FT_INT, "ID" }, + { false, FT_STRING, "Name" }, + { false, FT_SHORT, "Data" }, + { false, FT_BYTE, "Flags" }, + { false, FT_BYTE, "Type" }, + }; + return { &fields[0], std::extent<decltype(fields)>::value, ScenarioMeta::Instance(), HOTFIX_SEL_SCENARIO }; + } +}; + +struct ScenarioStepLoadInfo +{ + static DB2LoadInfo Instance() + { + static DB2FieldMeta const fields[] = + { + { false, FT_INT, "ID" }, + { false, FT_STRING, "Description" }, + { false, FT_STRING, "Name" }, + { false, FT_SHORT, "CriteriaTreeID" }, + { false, FT_SHORT, "ScenarioID" }, + { false, FT_SHORT, "PreviousStepID" }, + { false, FT_SHORT, "QuestRewardID" }, + { false, FT_BYTE, "Step" }, + { false, FT_BYTE, "Flags" }, + { false, FT_INT, "BonusRequiredStepID" }, + }; + return { &fields[0], std::extent<decltype(fields)>::value, ScenarioStepMeta::Instance(), HOTFIX_SEL_SCENARIO_STEP }; + } +}; + struct SceneScriptLoadInfo { static DB2LoadInfo Instance() diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index 16657ce3960..e6b5290b752 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -170,6 +170,8 @@ DB2Storage<QuestXPEntry> sQuestXPStore("QuestXP.db2", Que DB2Storage<RandPropPointsEntry> sRandPropPointsStore("RandPropPoints.db2", RandPropPointsLoadInfo::Instance()); DB2Storage<RulesetItemUpgradeEntry> sRulesetItemUpgradeStore("RulesetItemUpgrade.db2", RulesetItemUpgradeLoadInfo::Instance()); DB2Storage<ScalingStatDistributionEntry> sScalingStatDistributionStore("ScalingStatDistribution.db2", ScalingStatDistributionLoadInfo::Instance()); +DB2Storage<ScenarioEntry> sScenarioStore("Scenario.db2", ScenarioLoadInfo::Instance()); +DB2Storage<ScenarioStepEntry> sScenarioStepStore("ScenarioStep.db2", ScenarioStepLoadInfo::Instance()); DB2Storage<SceneScriptEntry> sSceneScriptStore("SceneScript.db2", SceneScriptLoadInfo::Instance()); DB2Storage<SceneScriptPackageEntry> sSceneScriptPackageStore("SceneScriptPackage.db2", SceneScriptPackageLoadInfo::Instance()); DB2Storage<SkillLineEntry> sSkillLineStore("SkillLine.db2", SkillLineLoadInfo::Instance()); @@ -465,6 +467,8 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale) LOAD_DB2(sRandPropPointsStore); LOAD_DB2(sRulesetItemUpgradeStore); LOAD_DB2(sScalingStatDistributionStore); + LOAD_DB2(sScenarioStore); + LOAD_DB2(sScenarioStepStore); LOAD_DB2(sSceneScriptStore); LOAD_DB2(sSceneScriptPackageStore); LOAD_DB2(sSkillLineStore); diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index cebd561bb26..2a4e42b27ed 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -135,6 +135,8 @@ TC_GAME_API extern DB2Storage<QuestSortEntry> sQuestSortSt TC_GAME_API extern DB2Storage<QuestXPEntry> sQuestXPStore; TC_GAME_API extern DB2Storage<RandPropPointsEntry> sRandPropPointsStore; TC_GAME_API extern DB2Storage<ScalingStatDistributionEntry> sScalingStatDistributionStore; +TC_GAME_API extern DB2Storage<ScenarioEntry> sScenarioStore; +TC_GAME_API extern DB2Storage<ScenarioStepEntry> sScenarioStepStore; TC_GAME_API extern DB2Storage<SkillLineEntry> sSkillLineStore; TC_GAME_API extern DB2Storage<SceneScriptEntry> sSceneScriptStore; TC_GAME_API extern DB2Storage<SceneScriptPackageEntry> sSceneScriptPackageStore; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 1072a7b2ef4..93cd5833dc8 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -2050,6 +2050,35 @@ struct ScalingStatDistributionEntry uint32 MaxLevel; }; +struct ScenarioEntry +{ + uint32 ID; + LocalizedString* Name; + uint16 Data; // Seems to indicate different things, for zone invasions, this is the area id + uint8 Flags; + uint8 Type; +}; + +struct ScenarioStepEntry +{ + uint32 ID; + LocalizedString* Description; + LocalizedString* Name; + uint16 CriteriaTreeID; + uint16 ScenarioID; + uint16 PreviousStepID; // Used in conjunction with Proving Grounds scenarios, when sequencing steps (Not using step order?) + uint16 QuestRewardID; + uint8 Step; + uint8 Flags; + uint32 BonusRequiredStepID; // Bonus step can only be completed if scenario is in the step specified in this field + + // helpers + bool IsBonusObjective() const + { + return Flags & SCENARIO_STEP_FLAG_BONUS_OBJECTIVE; + } +}; + struct SceneScriptEntry { uint32 ID; diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 7f8d7c23111..3519f7987c9 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -706,6 +706,12 @@ enum QuestPackageFilter QUEST_PACKAGE_FILTER_EVERYONE = 3 // Players can always select this quest reward }; +enum ScenarioStepFlags +{ + SCENARIO_STEP_FLAG_BONUS_OBJECTIVE = 0x1, + SCENARIO_STEP_FLAG_HEROIC_ONLY = 0x2 +}; + enum SkillRaceClassInfoFlags { SKILL_FLAG_NO_SKILLUP_MESSAGE = 0x2, diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 047966d710c..7d557cf2b6c 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -45,6 +45,7 @@ #include "BattlefieldMgr.h" #include "GameObjectPackets.h" #include "MiscPackets.h" +#include "InstanceScenario.h" Object::Object() { @@ -2367,6 +2368,15 @@ void WorldObject::SetZoneScript() } } +Scenario* WorldObject::GetScenario() const +{ + if (IsInWorld()) + if (InstanceMap* instanceMap = GetMap()->ToInstanceMap()) + return instanceMap->GetInstanceScenario(); + + return nullptr; +} + TempSummon* WorldObject::SummonCreature(uint32 entry, const Position &pos, TempSummonType spwtype, uint32 duration, uint32 /*vehId*/) const { if (Map* map = FindMap()) diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 42d53ed2dc0..471e60c42b5 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -82,6 +82,7 @@ class DynamicObject; class GameObject; class InstanceScript; class Player; +class Scenario; class TempSummon; class Transport; class Unit; @@ -643,6 +644,8 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation void SetZoneScript(); ZoneScript* GetZoneScript() const { return m_zoneScript; } + Scenario* GetScenario() const; + TempSummon* SummonCreature(uint32 id, Position const &pos, TempSummonType spwtype = TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime = 0, uint32 vehId = 0) const; TempSummon* SummonCreature(uint32 id, float x, float y, float z, float ang = 0, TempSummonType spwtype = TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime = 0) const; GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime /* s */); diff --git a/src/server/game/Entities/Player/KillRewarder.cpp b/src/server/game/Entities/Player/KillRewarder.cpp index c26c2261c4b..3573a40d956 100644 --- a/src/server/game/Entities/Player/KillRewarder.cpp +++ b/src/server/game/Entities/Player/KillRewarder.cpp @@ -25,6 +25,7 @@ #include "InstanceScript.h" #include "Pet.h" #include "Player.h" +#include "Scenario.h" // == KillRewarder ==================================================== // KillRewarder encapsulates logic of rewarding player upon kill with: @@ -67,6 +68,7 @@ // 4.4. Give kill credit (player must not be in group, or he must be alive or without corpse). // 5. Credit instance encounter. // 6. Update guild achievements. + // 7. Scenario credit KillRewarder::KillRewarder(Player* killer, Unit* victim, bool isBattleGround) : // 1. Initialize internal variables to default values. @@ -269,6 +271,7 @@ void KillRewarder::Reward() // 5. Credit instance encounter. // 6. Update guild achievements. + // 7. Credit scenario criterias if (Creature* victim = _victim->ToCreature()) { if (victim->IsDungeonBoss()) @@ -278,6 +281,8 @@ void KillRewarder::Reward() if (ObjectGuid::LowType guildId = victim->GetMap()->GetOwnerGuildId()) if (Guild* guild = sGuildMgr->GetGuildById(guildId)) guild->UpdateCriteria(CRITERIA_TYPE_KILL_CREATURE, victim->GetEntry(), 1, 0, victim, _killer); - } + if (Scenario* scenario = victim->GetScenario()) + scenario->UpdateCriteria(CRITERIA_TYPE_KILL_CREATURE, victim->GetEntry(), 1, 0, victim, _killer); + } } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 38675cf6b52..aacc602d3d6 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -23,18 +23,18 @@ #include "ArenaTeamMgr.h" #include "Battlefield.h" #include "BattlefieldMgr.h" -#include "BattlefieldWG.h" #include "BattlefieldTB.h" +#include "BattlefieldWG.h" #include "Battleground.h" #include "BattlegroundMgr.h" #include "BattlegroundScore.h" #include "BattlePetMgr.h" #include "CellImpl.h" +#include "Channel.h" #include "ChannelMgr.h" #include "CharacterDatabaseCleaner.h" #include "CharacterPackets.h" #include "Chat.h" -#include "Channel.h" #include "ChatPackets.h" #include "CombatLogPackets.h" #include "CombatPackets.h" @@ -50,6 +50,7 @@ #include "GameEventMgr.h" #include "GameObjectAI.h" #include "Garrison.h" +#include "GitRevision.h" #include "GossipDef.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" @@ -80,7 +81,7 @@ #include "QuestDef.h" #include "QuestPackets.h" #include "ReputationMgr.h" -#include "GitRevision.h" +#include "Scenario.h" #include "SkillDiscovery.h" #include "SocialMgr.h" #include "Spell.h" @@ -90,8 +91,8 @@ #include "SpellMgr.h" #include "SpellPackets.h" #include "TalentPackets.h" -#include "TransmogrificationPackets.h" #include "ToyPackets.h" +#include "TransmogrificationPackets.h" #include "Transport.h" #include "UpdateData.h" #include "UpdateFieldFlags.h" @@ -25367,16 +25368,17 @@ void Player::ResetCriteria(CriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 void Player::UpdateCriteria(CriteriaTypes type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, uint64 miscValue3 /*= 0*/, Unit* unit /*= NULL*/) { m_achievementMgr->UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this); - Guild* guild = sGuildMgr->GetGuildById(GetGuildId()); - if (!guild) - return; // Update only individual achievement criteria here, otherwise we may get multiple updates // from a single boss kill if (CriteriaMgr::IsGroupCriteriaType(type)) return; - guild->UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this); + if (Scenario* scenario = GetScenario()) + scenario->UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this); + + if (Guild* guild = sGuildMgr->GetGuildById(GetGuildId())) + guild->UpdateCriteria(type, miscValue1, miscValue2, miscValue3, unit, this); } void Player::CompletedAchievement(AchievementEntry const* entry) diff --git a/src/server/game/Handlers/ScenarioHandler.cpp b/src/server/game/Handlers/ScenarioHandler.cpp new file mode 100644 index 00000000000..e5745e1bfab --- /dev/null +++ b/src/server/game/Handlers/ScenarioHandler.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2008-2015 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 "ScenarioMgr.h" +#include "ScenarioPackets.h" +#include "WorldSession.h" + +void WorldSession::HandleQueryScenarioPOI(WorldPackets::Scenario::QueryScenarioPOI& queryScenarioPOI) +{ + WorldPackets::Scenario::ScenarioPOIs response; + + // Read criteria tree ids and add the in a unordered_set so we don't send POIs for the same criteria tree multiple times + std::unordered_set<int32> criteriaTreeIds; + for (size_t i = 0; i < queryScenarioPOI.MissingScenarioPOIs.size(); ++i) + criteriaTreeIds.insert(queryScenarioPOI.MissingScenarioPOIs[i]); // CriteriaTreeID + + for (int32 criteriaTreeId : criteriaTreeIds) + { + if (ScenarioPOIVector const* poiVector = sScenarioMgr->GetScenarioPOIs(criteriaTreeId)) + { + WorldPackets::Scenario::ScenarioPOIData scenarioPOIData; + scenarioPOIData.CriteriaTreeID = criteriaTreeId; + scenarioPOIData.ScenarioPOIs = poiVector; + response.ScenarioPOIDataStats.push_back(scenarioPOIData); + } + } + + SendPacket(response.Write()); +} diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp index 4fa2682c7b6..cc088d8954a 100644 --- a/src/server/game/Instances/InstanceSaveMgr.cpp +++ b/src/server/game/Instances/InstanceSaveMgr.cpp @@ -31,6 +31,7 @@ #include "World.h" #include "Group.h" #include "InstanceScript.h" +#include "InstanceScenario.h" uint16 InstanceSaveManager::ResetTimeDelay[] = {3600, 900, 300, 60}; @@ -148,6 +149,10 @@ void InstanceSaveManager::DeleteInstanceFromDB(uint32 instanceid) stmt->setUInt32(0, instanceid); trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_SCENARIO_INSTANCE_CRITERIA_FOR_INSTANCE); + stmt->setUInt32(0, instanceid); + trans->Append(stmt); + CharacterDatabase.CommitTransaction(trans); // Respawn times should be deleted only when the map gets unloaded } @@ -208,6 +213,9 @@ void InstanceSave::SaveToDB() completedEncounters = instanceScript->GetCompletedEncounterMask(); m_entranceId = instanceScript->GetEntranceLocation(); } + + if (InstanceScenario* scenario = map->ToInstanceMap()->GetInstanceScenario()) + scenario->SaveToDB(); } PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_INSTANCE_SAVE); diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index 9854e46f1cb..91101a5aeff 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -32,6 +32,7 @@ #include "Opcodes.h" #include "ScriptReloadMgr.h" #include "ScriptMgr.h" +#include "InstanceScenario.h" BossBoundaryData::~BossBoundaryData() { @@ -54,6 +55,9 @@ _entranceId(0), _temporaryEntranceId(0), _combatResurrectionTimer(0), _combatRes void InstanceScript::SaveToDB() { + if (InstanceScenario* scenario = instance->ToInstanceMap()->GetInstanceScenario()) + scenario->SaveToDB(); + std::string data = GetSaveData(); if (data.empty()) return; diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 0a7138616e0..a40367ad7a3 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -28,6 +28,7 @@ #include "GridStates.h" #include "Group.h" #include "InstancePackets.h" +#include "InstanceScenario.h" #include "InstanceScript.h" #include "MapInstanced.h" #include "MiscPackets.h" @@ -3046,7 +3047,7 @@ template TC_GAME_API void Map::RemoveFromMap(AreaTrigger*, bool); InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _parent) : Map(id, expiry, InstanceId, SpawnMode, _parent), m_resetAfterUnload(false), m_unloadWhenEmpty(false), - i_data(NULL), i_script_id(0) + i_data(NULL), i_script_id(0), i_scenario(nullptr) { //lets initialize visibility distance for dungeons InstanceMap::InitVisibilityDistance(); @@ -3059,7 +3060,7 @@ InstanceMap::InstanceMap(uint32 id, time_t expiry, uint32 InstanceId, uint8 Spaw InstanceMap::~InstanceMap() { delete i_data; - i_data = NULL; + delete i_scenario; } void InstanceMap::InitVisibilityDistance() @@ -3224,6 +3225,9 @@ bool InstanceMap::AddPlayerToMap(Player* player, bool initPlayer /*= true*/) if (i_data) i_data->OnPlayerEnter(player); + if (i_scenario) + i_scenario->OnPlayerEnter(player); + return true; } @@ -3236,6 +3240,9 @@ void InstanceMap::Update(const uint32 t_diff) i_data->Update(t_diff); i_data->UpdateCombatResurrection(t_diff); } + + if (i_scenario) + i_scenario->Update(t_diff); } void InstanceMap::RemovePlayerFromMap(Player* player, bool remove) @@ -3244,6 +3251,8 @@ void InstanceMap::RemovePlayerFromMap(Player* player, bool remove) //if last player set unload timer if (!m_unloadTimer && m_mapRefManager.getSize() == 1) m_unloadTimer = m_unloadWhenEmpty ? MIN_UNLOAD_DELAY : std::max(sWorld->getIntConfig(CONFIG_INSTANCE_UNLOAD_DELAY), (uint32)MIN_UNLOAD_DELAY); + if (i_scenario) + i_scenario->OnPlayerExit(player); Map::RemovePlayerFromMap(player, remove); // for normal instances schedule the reset after all players have left SetResetSchedule(true); diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 89edf9823b7..cca480cf94a 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -42,6 +42,7 @@ class Group; class InstanceMap; class InstanceSave; class InstanceScript; +class InstanceScenario; class MapInstanced; class Object; class Player; @@ -766,6 +767,8 @@ class TC_GAME_API InstanceMap : public Map bool Reset(uint8 method); uint32 GetScriptId() const { return i_script_id; } InstanceScript* GetInstanceScript() { return i_data; } + InstanceScenario* GetInstanceScenario() { return i_scenario; } + void SetInstanceScenario(InstanceScenario* scenario) { i_scenario = scenario; } void PermBindAllPlayers(Player* source); void UnloadAll() override; EnterState CannotEnter(Player* player) override; @@ -784,6 +787,7 @@ class TC_GAME_API InstanceMap : public Map bool m_unloadWhenEmpty; InstanceScript* i_data; uint32 i_script_id; + InstanceScenario* i_scenario; }; class TC_GAME_API BattlegroundMap : public Map diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp index f80c04d7c8c..ad7d1c240be 100644 --- a/src/server/game/Maps/MapInstanced.cpp +++ b/src/server/game/Maps/MapInstanced.cpp @@ -27,6 +27,7 @@ #include "Group.h" #include "Player.h" #include "GarrisonMap.h" +#include "ScenarioMgr.h" MapInstanced::MapInstanced(uint32 id, time_t expiry) : Map(id, expiry, 0, DIFFICULTY_NORMAL) { @@ -178,7 +179,7 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player, u map = FindInstanceMap(newInstanceId); // it is possible that the save exists but the map doesn't if (!map) - map = CreateInstance(newInstanceId, pSave, pSave->GetDifficultyID()); + map = CreateInstance(newInstanceId, pSave, pSave->GetDifficultyID(), player->GetTeamId()); } else { @@ -191,7 +192,7 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player, u //ASSERT(!FindInstanceMap(NewInstanceId)); map = FindInstanceMap(newInstanceId); if (!map) - map = CreateInstance(newInstanceId, NULL, diff); + map = CreateInstance(newInstanceId, NULL, diff, player->GetTeamId()); } } else @@ -205,7 +206,7 @@ Map* MapInstanced::CreateInstanceForPlayer(const uint32 mapId, Player* player, u return map; } -InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, Difficulty difficulty) +InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, Difficulty difficulty, TeamId team) { // load/create a map std::lock_guard<std::mutex> lock(_mapLock); @@ -237,6 +238,8 @@ InstanceMap* MapInstanced::CreateInstance(uint32 InstanceId, InstanceSave* save, bool load_data = save != NULL; map->CreateInstanceData(load_data); + if (InstanceScenario* instanceScenario = sScenarioMgr->CreateInstanceScenario(map, team)) + map->SetInstanceScenario(instanceScenario); if (sWorld->getBoolConfig(CONFIG_INSTANCEMAP_LOAD_GRIDS)) map->LoadAllCells(); diff --git a/src/server/game/Maps/MapInstanced.h b/src/server/game/Maps/MapInstanced.h index 7d89d446846..3e8d60f892e 100644 --- a/src/server/game/Maps/MapInstanced.h +++ b/src/server/game/Maps/MapInstanced.h @@ -66,7 +66,7 @@ class TC_GAME_API MapInstanced : public Map virtual void InitVisibilityDistance() override; private: - InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave* save, Difficulty difficulty); + InstanceMap* CreateInstance(uint32 InstanceId, InstanceSave* save, Difficulty difficulty, TeamId team); BattlegroundMap* CreateBattleground(uint32 InstanceId, Battleground* bg); GarrisonMap* CreateGarrison(uint32 instanceId, Player* owner); diff --git a/src/server/game/Scenarios/InstanceScenario.cpp b/src/server/game/Scenarios/InstanceScenario.cpp new file mode 100644 index 00000000000..60f3a364af5 --- /dev/null +++ b/src/server/game/Scenarios/InstanceScenario.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2008-2015 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 "InstanceScenario.h" +#include "Player.h" +#include "InstanceSaveMgr.h" +#include "ObjectMgr.h" + +InstanceScenario::InstanceScenario(Map* map, ScenarioData const* scenarioData) : Scenario(scenarioData), _map(map) +{ + ASSERT(_map); + LoadInstanceData(_map->GetInstanceId()); + + Map::PlayerList const& players = map->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + if (Player* player = itr->GetSource()->ToPlayer()) + SendScenarioState(player); +} + +void InstanceScenario::SaveToDB() +{ + if (_criteriaProgress.empty()) + return; + + DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(_map->GetDifficultyID()); + if (!difficultyEntry || difficultyEntry->Flags & DIFFICULTY_FLAG_CHALLENGE_MODE) // Map should have some sort of "CanSave" boolean that returns whether or not the map is savable. (Challenge modes cannot be saved for example) + return; + + uint32 id = _map->GetInstanceId(); + if (!id) + { + TC_LOG_DEBUG("scenario", "Scenario::SaveToDB: Can not save scenario progress without an instance save. Map::GetInstanceId() did not return an instance save."); + return; + } + + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + for (auto iter = _criteriaProgress.begin(); iter != _criteriaProgress.end(); ++iter) + { + if (!iter->second.Changed) + continue; + + Criteria const* criteria = sCriteriaMgr->GetCriteria(iter->first); + switch (CriteriaTypes(criteria->Entry->Type)) + { + // Blizzard only appears to store creature kills + case CRITERIA_TYPE_KILL_CREATURE: + break; + default: + continue; + } + + if (iter->second.Counter) + { + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SCENARIO_INSTANCE_CRITERIA); + stmt->setUInt32(0, id); + stmt->setUInt32(1, iter->first); + PreparedQueryResult result = CharacterDatabase.Query(stmt); + if (result) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_SCENARIO_INSTANCE_CRITERIA); + stmt->setUInt64(0, iter->second.Counter); + stmt->setUInt32(1, uint32(iter->second.Date)); + stmt->setUInt32(2, id); + stmt->setUInt32(3, iter->first); + trans->Append(stmt); + } + else + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_SCENARIO_INSTANCE_CRITERIA); + stmt->setUInt32(0, id); + stmt->setUInt32(1, iter->first); + stmt->setUInt64(2, iter->second.Counter); + stmt->setUInt32(3, uint32(iter->second.Date)); + trans->Append(stmt); + } + } + + iter->second.Changed = false; + } + + CharacterDatabase.CommitTransaction(trans); +} + +void InstanceScenario::LoadInstanceData(uint32 instanceId) +{ + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_SCENARIO_INSTANCE_CRITERIA_FOR_INSTANCE); + stmt->setUInt32(0, instanceId); + + PreparedQueryResult result = CharacterDatabase.Query(stmt); + if (result) + { + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + time_t now = time(nullptr); + + std::vector<CriteriaTree const*> criteriaTrees; + do + { + Field* fields = result->Fetch(); + uint32 id = fields[0].GetUInt32(); + uint64 counter = fields[1].GetUInt64(); + time_t date = time_t(fields[2].GetUInt32()); + + Criteria const* criteria = sCriteriaMgr->GetCriteria(id); + if (!criteria) + { + // Removing non-existing criteria data for all instances + TC_LOG_ERROR("criteria.instancescenarios", "Removing scenario criteria %u data from the table `instance_scenario_progress`.", id); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_INVALID_SCENARIO_INSTANCE_CRITERIA); + stmt->setUInt32(0, instanceId); + stmt->setUInt32(1, uint32(id)); + trans->Append(stmt); + continue; + } + + if (criteria->Entry->StartTimer && time_t(date + criteria->Entry->StartTimer) < now) + continue; + + switch (CriteriaTypes(criteria->Entry->Type)) + { + // Blizzard appears to only stores creatures killed progress for unknown reasons. Either technical shortcoming or intentional + case CRITERIA_TYPE_KILL_CREATURE: + break; + default: + continue; + } + + SetCriteriaProgress(criteria, counter, nullptr, PROGRESS_SET); + + if (CriteriaTreeList const* trees = sCriteriaMgr->GetCriteriaTreesByCriteria(criteria->ID)) + for (CriteriaTree const* tree : *trees) + criteriaTrees.push_back(tree); + } + while (result->NextRow()); + + CharacterDatabase.CommitTransaction(trans); + + for (CriteriaTree const* tree : criteriaTrees) + { + ScenarioStepEntry const* step = tree->ScenarioStep; + if (!step) + continue; + + if (IsCompletedCriteriaTree(tree)) + SetStepState(step, SCENARIO_STEP_DONE); + } + } +} + +std::string InstanceScenario::GetOwnerInfo() const +{ + return Trinity::StringFormat("Instance ID %u", _map->GetInstanceId()); +} + +void InstanceScenario::SendPacket(WorldPacket const* data) const +{ + _map->SendToPlayers(data); +} diff --git a/src/server/game/Scenarios/InstanceScenario.h b/src/server/game/Scenarios/InstanceScenario.h new file mode 100644 index 00000000000..9582d0cf2ba --- /dev/null +++ b/src/server/game/Scenarios/InstanceScenario.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2008-2015 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 InstanceScenario_h__ +#define InstanceScenario_h__ + +#include "Scenario.h" + +class Map; + +typedef std::unordered_map<uint8, CriteriaProgressMap> StepCriteriaProgressMap; + +class TC_GAME_API InstanceScenario : public Scenario +{ + public: + InstanceScenario(Map* map, ScenarioData const* scenarioData); + + void SaveToDB(); + void LoadInstanceData(uint32 instanceId); + + protected: + std::string GetOwnerInfo() const override; + void SendPacket(WorldPacket const* data) const override; + + Map* _map; + ScenarioData const* _data; + StepCriteriaProgressMap _stepCriteriaProgress; +}; + +#endif // InstanceScenario_h__ diff --git a/src/server/game/Scenarios/Scenario.cpp b/src/server/game/Scenarios/Scenario.cpp new file mode 100644 index 00000000000..a4e39b2caa6 --- /dev/null +++ b/src/server/game/Scenarios/Scenario.cpp @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2008-2015 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 "Scenario.h" +#include "Player.h" +#include "ScenarioMgr.h" +#include "InstanceSaveMgr.h" +#include "ObjectMgr.h" +#include "ScenarioPackets.h" + +Scenario::Scenario(ScenarioData const* scenarioData) : _data(scenarioData), _currentstep(nullptr) +{ + ASSERT(_data); + + for (auto step : _data->Steps) + SetStepState(step.second, SCENARIO_STEP_NOT_STARTED); + + if (ScenarioStepEntry const* step = GetFirstStep()) + SetStep(step); + else + TC_LOG_ERROR("scenario", "Scenario::Scenario: Could not launch Scenario (id: %u), found no valid scenario step", _data->Entry->ID); +} + +Scenario::~Scenario() +{ + for (ObjectGuid guid : _players) + if (Player* player = ObjectAccessor::FindPlayer(guid)) + SendBootPlayer(player); + + _players.clear(); +} + +void Scenario::Reset() +{ + CriteriaHandler::Reset(); + SetStep(GetFirstStep()); +} + +void Scenario::CompleteStep(ScenarioStepEntry const* step) +{ + if (Quest const* quest = sObjectMgr->GetQuestTemplate(step->QuestRewardID)) + for (ObjectGuid guid : _players) + if (Player* player = ObjectAccessor::FindPlayer(guid)) + player->RewardQuest(quest, 0, nullptr, false); + + if (step->IsBonusObjective()) + return; + + ScenarioStepEntry const* newStep = nullptr; + for (auto _step : _data->Steps) + { + if (_step.second->IsBonusObjective()) + continue; + + if (GetStepState(_step.second) == SCENARIO_STEP_DONE) + continue; + + if (!newStep || _step.second->Step < newStep->Step) + newStep = _step.second; + } + + SetStep(newStep); + if (IsComplete()) + CompleteScenario(); + else + TC_LOG_ERROR("scenario", "Scenario::CompleteStep: Scenario (id: %u, step: %u) was completed, but could not determine new step, or validate scenario completion.", step->ScenarioID, step->ID); +} + +void Scenario::CompleteScenario() +{ + return SendPacket(WorldPackets::Scenario::ScenarioCompleted(_data->Entry->ID).Write()); +} + +void Scenario::SetStep(ScenarioStepEntry const* step) +{ + _currentstep = step; + if (step) + SetStepState(step, SCENARIO_STEP_IN_PROGRESS); + + WorldPackets::Scenario::ScenarioState scenarioState; + BuildScenarioState(&scenarioState); + SendPacket(scenarioState.Write()); +} + +void Scenario::OnPlayerEnter(Player* player) +{ + _players.insert(player->GetGUID()); + SendScenarioState(player); +} + +void Scenario::OnPlayerExit(Player* player) +{ + _players.erase(player->GetGUID()); + SendBootPlayer(player); +} + +bool Scenario::IsComplete() +{ + for (auto step : _data->Steps) + { + if (step.second->IsBonusObjective()) + continue; + + if (GetStepState(step.second) != SCENARIO_STEP_DONE) + return false; + } + + return true; +} + +ScenarioStepState Scenario::GetStepState(ScenarioStepEntry const* step) +{ + std::map<ScenarioStepEntry const*, ScenarioStepState>::const_iterator itr = _stepStates.find(step); + if (itr == _stepStates.end()) + return SCENARIO_STEP_INVALID; + + return itr->second; +} + +void Scenario::SendCriteriaUpdate(Criteria const * criteria, CriteriaProgress const * progress, uint32 timeElapsed, bool timedCompleted) const +{ + WorldPackets::Scenario::ScenarioProgressUpdate progressUpdate; + progressUpdate.CriteriaProgress.Id = criteria->ID; + progressUpdate.CriteriaProgress.Quantity = progress->Counter; + progressUpdate.CriteriaProgress.Player = progress->PlayerGUID; + progressUpdate.CriteriaProgress.Date = progress->Date; + if (criteria->Entry->StartTimer) + progressUpdate.CriteriaProgress.Flags = timedCompleted ? 1 : 0; + + progressUpdate.CriteriaProgress.TimeFromStart = timeElapsed; + progressUpdate.CriteriaProgress.TimeFromCreate = 0; + + SendPacket(progressUpdate.Write()); +} + +bool Scenario::CanUpdateCriteriaTree(Criteria const * /*criteria*/, CriteriaTree const * tree, Player * /*referencePlayer*/) const +{ + ScenarioStepEntry const* step = tree->ScenarioStep; + if (!step) + return false; + + if (step->ScenarioID != _data->Entry->ID) + return false; + + ScenarioStepEntry const* currentStep = GetStep(); + if (!currentStep) + return false; + + if (step->IsBonusObjective()) + return true; + + return currentStep == step; +} + +bool Scenario::CanCompleteCriteriaTree(CriteriaTree const* tree) +{ + ScenarioStepEntry const* step = tree->ScenarioStep; + if (!step) + return false; + + if (step->ScenarioID != _data->Entry->ID) + return false; + + if (step->IsBonusObjective()) + return !IsComplete(); + + if (step != GetStep()) + return false; + + return true; +} + +void Scenario::CompletedCriteriaTree(CriteriaTree const* tree, Player* /*referencePlayer*/) +{ + ScenarioStepEntry const* step = tree->ScenarioStep; + if (!step) + return; + + if (!step->IsBonusObjective() && step != GetStep()) + return; + + if (GetStepState(step) == SCENARIO_STEP_DONE) + return; + + SetStepState(step, SCENARIO_STEP_DONE); + CompleteStep(step); +} + +void Scenario::SendPacket(WorldPacket const* data) const +{ + for (ObjectGuid guid : _players) + if (Player* player = ObjectAccessor::FindPlayer(guid)) + player->SendDirectMessage(data); +} + +void Scenario::BuildScenarioState(WorldPackets::Scenario::ScenarioState* scenarioState) +{ + scenarioState->ScenarioID = _data->Entry->ID; + if (ScenarioStepEntry const* step = GetStep()) + scenarioState->CurrentStep = step->ID; + scenarioState->CriteriaProgress = GetCriteriasProgress(); + scenarioState->BonusObjectives = GetBonusObjectivesData(); + // Don't know exactly what this is for, but seems to contain list of scenario steps that we're either on or that are completed + for (auto state : _stepStates) + { + if (state.first->IsBonusObjective()) + continue; + + switch (state.second) + { + case SCENARIO_STEP_IN_PROGRESS: + case SCENARIO_STEP_DONE: + break; + case SCENARIO_STEP_NOT_STARTED: + default: + continue; + } + + scenarioState->PickedSteps.push_back(state.first->ID); + } + scenarioState->ScenarioComplete = IsComplete(); +} + +ScenarioStepEntry const* Scenario::GetFirstStep() const +{ + // Do it like this because we don't know what order they're in inside the container. + ScenarioStepEntry const* firstStep = nullptr; + for (auto scenarioStep : _data->Steps) + { + if (scenarioStep.second->IsBonusObjective()) + continue; + + if (!firstStep || scenarioStep.second->Step < firstStep->Step) + firstStep = scenarioStep.second; + } + + return firstStep; +} + +void Scenario::SendScenarioState(Player* player) +{ + WorldPackets::Scenario::ScenarioState scenarioState; + BuildScenarioState(&scenarioState); + player->SendDirectMessage(scenarioState.Write()); +} + +std::vector<WorldPackets::Scenario::BonusObjectiveData> Scenario::GetBonusObjectivesData() +{ + std::vector<WorldPackets::Scenario::BonusObjectiveData> bonusObjectivesData; + for (auto itr = _data->Steps.begin(); itr != _data->Steps.end(); ++itr) + { + if (!itr->second->IsBonusObjective()) + continue; + + if (CriteriaTree const* tree = sCriteriaMgr->GetCriteriaTree(itr->second->CriteriaTreeID)) + { + WorldPackets::Scenario::BonusObjectiveData bonusObjectiveData; + bonusObjectiveData.BonusObjectiveID = itr->second->ID; + bonusObjectiveData.ObjectiveComplete = GetStepState(itr->second) == SCENARIO_STEP_DONE; + bonusObjectivesData.push_back(bonusObjectiveData); + } + } + + return bonusObjectivesData; +} + +std::vector<WorldPackets::Achievement::CriteriaProgress> Scenario::GetCriteriasProgress() +{ + std::vector<WorldPackets::Achievement::CriteriaProgress> criteriasProgress; + + if (!_criteriaProgress.empty()) + { + for (auto critItr = _criteriaProgress.begin(); critItr != _criteriaProgress.end(); ++critItr) + { + WorldPackets::Achievement::CriteriaProgress criteriaProgress; + criteriaProgress.Id = critItr->first; + criteriaProgress.Quantity = critItr->second.Counter; + criteriaProgress.Date = critItr->second.Date; + criteriaProgress.Player = critItr->second.PlayerGUID; + criteriasProgress.push_back(criteriaProgress); + } + } + + return criteriasProgress; +} + +CriteriaList const& Scenario::GetCriteriaByType(CriteriaTypes type) const +{ + return sCriteriaMgr->GetScenarioCriteriaByType(type); +} + +void Scenario::SendBootPlayer(Player* player) +{ + WorldPackets::Scenario::ScenarioBoot scenarioBoot; + scenarioBoot.ScenarioID = _data->Entry->ID; + player->SendDirectMessage(scenarioBoot.Write()); +} diff --git a/src/server/game/Scenarios/Scenario.h b/src/server/game/Scenarios/Scenario.h new file mode 100644 index 00000000000..1b37c6abca4 --- /dev/null +++ b/src/server/game/Scenarios/Scenario.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2008-2015 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 Scenario_h__ +#define Scenario_h__ + +#include "CriteriaHandler.h" + +struct ScenarioData; +struct ScenarioStepEntry; + +namespace WorldPackets +{ + namespace Achievement + { + struct CriteriaProgress; + } + + namespace Scenario + { + struct BonusObjectiveData; + class ScenarioState; + } +} + +enum ScenarioStepState +{ + SCENARIO_STEP_INVALID = 0, + SCENARIO_STEP_NOT_STARTED = 1, + SCENARIO_STEP_IN_PROGRESS = 2, + SCENARIO_STEP_DONE = 3 +}; + +class TC_GAME_API Scenario : public CriteriaHandler +{ + public: + Scenario(ScenarioData const* scenarioData); + ~Scenario(); + + void Reset() override; + void SetStep(ScenarioStepEntry const* step); + + virtual void CompleteStep(ScenarioStepEntry const* step); + virtual void CompleteScenario(); + + virtual void OnPlayerEnter(Player* player); + virtual void OnPlayerExit(Player* player); + virtual void Update(uint32 /*diff*/) { } + + bool IsComplete(); + void SetStepState(ScenarioStepEntry const* step, ScenarioStepState state) { _stepStates[step] = state; } + ScenarioStepState GetStepState(ScenarioStepEntry const* step); + ScenarioStepEntry const* GetStep() const { return _currentstep; } + ScenarioStepEntry const* GetFirstStep() const; + + void SendScenarioState(Player* player); + void SendBootPlayer(Player* player); + + protected: + GuidUnorderedSet _players; + + void SendCriteriaUpdate(Criteria const* criteria, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const override; + void SendCriteriaProgressRemoved(uint32 /*criteriaId*/) override { } + + bool CanUpdateCriteriaTree(Criteria const* criteria, CriteriaTree const* tree, Player* referencePlayer) const override; + bool CanCompleteCriteriaTree(CriteriaTree const* tree) override; + void CompletedCriteriaTree(CriteriaTree const* tree, Player* referencePlayer) override; + void AfterCriteriaTreeUpdate(CriteriaTree const* /*tree*/, Player* /*referencePlayer*/) override { } + + void SendPacket(WorldPacket const* data) const override; + + void SendAllData(Player const* /*receiver*/) const override { } + + void BuildScenarioState(WorldPackets::Scenario::ScenarioState* scenarioState); + + std::vector<WorldPackets::Scenario::BonusObjectiveData> GetBonusObjectivesData(); + std::vector<WorldPackets::Achievement::CriteriaProgress> GetCriteriasProgress(); + + CriteriaList const& GetCriteriaByType(CriteriaTypes type) const override; + ScenarioData const* _data; + + private: + ScenarioStepEntry const* _currentstep; + std::map<ScenarioStepEntry const*, ScenarioStepState> _stepStates; +}; + +#endif // Scenario_h__ diff --git a/src/server/game/Scenarios/ScenarioMgr.cpp b/src/server/game/Scenarios/ScenarioMgr.cpp new file mode 100644 index 00000000000..cecf9d6caf0 --- /dev/null +++ b/src/server/game/Scenarios/ScenarioMgr.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2008-2015 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 "ScenarioMgr.h" +#include "DatabaseEnv.h" +#include "DB2Stores.h" +#include "InstanceScenario.h" +#include "Map.h" +#include "ScenarioPackets.h" + +ScenarioMgr* ScenarioMgr::Instance() +{ + static ScenarioMgr instance; + return &instance; +} + +InstanceScenario* ScenarioMgr::CreateInstanceScenario(Map* map, TeamId team) +{ + auto dbDataItr = _scenarioDBData.find(std::make_pair(map->GetId(), map->GetDifficultyID())); + // No scenario registered for this map and difficulty in the database + if (dbDataItr == _scenarioDBData.end()) + return nullptr; + + uint32 scenarioID = 0; + switch (team) + { + case TEAM_ALLIANCE: + scenarioID = dbDataItr->second.Scenario_A; + break; + case TEAM_HORDE: + scenarioID = dbDataItr->second.Scenario_H; + break; + default: + break; + } + + auto itr = _scenarioData.find(scenarioID); + if (itr == _scenarioData.end()) + { + TC_LOG_ERROR("scenario", "Table `scenarios` contained data linking scenario (Id: %u) to map (Id: %u), difficulty (Id: %u) but no scenario data was found related to that scenario Id.", scenarioID, map->GetId(), map->GetDifficultyID()); + return nullptr; + } + + return new InstanceScenario(map, &itr->second); +} + +void ScenarioMgr::LoadDBData() +{ + _scenarioDBData.clear(); + + uint32 oldMSTime = getMSTime(); + + QueryResult result = WorldDatabase.Query("SELECT map, difficulty, scenario_A, scenario_H FROM scenarios"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 scenarios. DB table `scenarios` is empty!"); + return; + } + + do + { + Field* fields = result->Fetch(); + + uint32 mapId = fields[0].GetUInt32(); + uint8 difficulty = fields[1].GetUInt8(); + + uint32 scenarioAllianceId = fields[2].GetUInt32(); + if (scenarioAllianceId > 0 && _scenarioData.find(scenarioAllianceId) == _scenarioData.end()) + { + TC_LOG_ERROR("sql.sql", "ScenarioMgr::LoadDBData: DB Table `scenarios`, column scenario_A contained an invalid scenario (Id: %u)!", scenarioAllianceId); + continue; + } + + uint32 scenarioHordeId = fields[3].GetUInt32(); + if (scenarioHordeId > 0 && _scenarioData.find(scenarioHordeId) == _scenarioData.end()) + { + TC_LOG_ERROR("sql.sql", "ScenarioMgr::LoadDBData: DB Table `scenarios`, column scenario_H contained an invalid scenario (Id: %u)!", scenarioHordeId); + continue; + } + + if (scenarioHordeId == 0) + scenarioHordeId = scenarioAllianceId; + + ScenarioDBData& data = _scenarioDBData[std::make_pair(mapId, difficulty)]; + data.MapID = mapId; + data.DifficultyID = difficulty; + data.Scenario_A = scenarioAllianceId; + data.Scenario_H = scenarioHordeId; + } + while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " instance scenario entries in %u ms", _scenarioDBData.size(), GetMSTimeDiffToNow(oldMSTime)); +} + +void ScenarioMgr::LoadDB2Data() +{ + _scenarioData.clear(); + + std::unordered_map<uint32, std::map<uint8, ScenarioStepEntry const*>> scenarioSteps; + uint32 deepestCriteriaTreeSize = 0; + + for (ScenarioStepEntry const* step : sScenarioStepStore) + { + scenarioSteps[step->ScenarioID][step->Step] = step; + if (CriteriaTree const* tree = sCriteriaMgr->GetCriteriaTree(step->CriteriaTreeID)) + { + uint32 criteriaTreeSize = 0; + CriteriaMgr::WalkCriteriaTree(tree, [&criteriaTreeSize](CriteriaTree const* /*tree*/) + { + ++criteriaTreeSize; + }); + deepestCriteriaTreeSize = std::max(deepestCriteriaTreeSize, criteriaTreeSize); + } + } + + ASSERT(deepestCriteriaTreeSize < MAX_ALLOWED_SCENARIO_POI_QUERY_SIZE, "MAX_ALLOWED_SCENARIO_POI_QUERY_SIZE must be at least %u", deepestCriteriaTreeSize + 1); + + for (ScenarioEntry const* scenario : sScenarioStore) + { + ScenarioData& data = _scenarioData[scenario->ID]; + data.Entry = scenario; + data.Steps = std::move(scenarioSteps[scenario->ID]); + } +} + +void ScenarioMgr::LoadScenarioPOI() +{ + uint32 oldMSTime = getMSTime(); + + _scenarioPOIStore.clear(); // need for reload case + + uint32 count = 0; + + // 0 1 2 6 7 8 9 10 11 12 + QueryResult result = WorldDatabase.Query("SELECT CriteriaTreeID, BlobIndex, Idx1, MapID, WorldMapAreaId, Floor, Priority, Flags, WorldEffectID, PlayerConditionID FROM scenario_poi ORDER BY CriteriaTreeID, Idx1"); + if (!result) + { + TC_LOG_ERROR("server.loading", ">> Loaded 0 scenario POI definitions. DB table `scenario_poi` is empty."); + return; + } + + // 0 1 2 3 + QueryResult points = WorldDatabase.Query("SELECT CriteriaTreeID, Idx1, X, Y FROM scenario_poi_points ORDER BY CriteriaTreeID DESC, Idx1, Idx2"); + + std::vector<std::vector<std::vector<ScenarioPOIPoint>>> POIs; + + if (points) + { + // The first result should have the highest criteriaTreeId + Field* fields = points->Fetch(); + uint32 criteriaTreeIdMax = fields[0].GetInt32(); + POIs.resize(criteriaTreeIdMax + 1); + + do + { + fields = points->Fetch(); + + int32 CriteriaTreeID = fields[0].GetInt32(); + int32 Idx1 = fields[1].GetInt32(); + int32 X = fields[2].GetInt32(); + int32 Y = fields[3].GetInt32(); + + if (int32(POIs[CriteriaTreeID].size()) <= Idx1 + 1) + POIs[CriteriaTreeID].resize(Idx1 + 10); + + ScenarioPOIPoint point(X, Y); + POIs[CriteriaTreeID][Idx1].push_back(point); + } while (points->NextRow()); + } + + do + { + Field* fields = result->Fetch(); + + int32 CriteriaTreeID = fields[0].GetInt32(); + int32 BlobIndex = fields[1].GetInt32(); + int32 Idx1 = fields[2].GetInt32(); + int32 MapID = fields[3].GetInt32(); + int32 WorldMapAreaId = fields[4].GetInt32(); + int32 Floor = fields[5].GetInt32(); + int32 Priority = fields[6].GetInt32(); + int32 Flags = fields[7].GetInt32(); + int32 WorldEffectID = fields[8].GetInt32(); + int32 PlayerConditionID = fields[9].GetInt32(); + + if (!sCriteriaMgr->GetCriteriaTree(CriteriaTreeID)) + TC_LOG_ERROR("sql.sql", "`scenario_poi` CriteriaTreeID (%u) Idx1 (%u) does not correspond to a valid criteria tree", CriteriaTreeID, Idx1); + + if (CriteriaTreeID < int32(POIs.size()) && Idx1 < int32(POIs[CriteriaTreeID].size())) + _scenarioPOIStore[CriteriaTreeID].emplace_back(BlobIndex, MapID, WorldMapAreaId, Floor, Priority, Flags, WorldEffectID, PlayerConditionID, POIs[CriteriaTreeID][Idx1]); + else + TC_LOG_ERROR("server.loading", "Table scenario_poi references unknown scenario poi points for criteria tree id %i POI id %i", CriteriaTreeID, BlobIndex); + + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u scenario POI definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); +} + diff --git a/src/server/game/Scenarios/ScenarioMgr.h b/src/server/game/Scenarios/ScenarioMgr.h new file mode 100644 index 00000000000..00c04ac1e4c --- /dev/null +++ b/src/server/game/Scenarios/ScenarioMgr.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2008-2015 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 ScenarioMgr_h__ +#define ScenarioMgr_h__ + +#include "Common.h" +#include "SharedDefines.h" + +class InstanceScenario; +class Map; +struct ScenarioEntry; +struct ScenarioStepEntry; + +struct ScenarioData +{ + ScenarioEntry const* Entry; + std::map<uint8, ScenarioStepEntry const*> Steps; +}; + +/* + Scenario data should be loaded on demand. + The server will get data from the database which scenario ids is linked with which map id/difficulty/player team. + The first time a scenario is loaded, the map loads and stores the scenario data for future scenario instance launches. +*/ + +struct ScenarioDBData +{ + uint32 MapID; + uint8 DifficultyID; + uint32 Scenario_A; + uint32 Scenario_H; +}; + +typedef std::unordered_map<std::pair<uint32, uint8>, ScenarioDBData> ScenarioDBDataContainer; +typedef std::map<uint32, ScenarioData> ScenarioDataContainer; + +enum ScenarioType +{ + SCENARIO_TYPE_SCENARIO = 0, + SCENARIO_TYPE_CHALLENGE_MODE = 1, + SCENARIO_TYPE_SOLO = 2, + SCENARIO_TYPE_DUNGEON = 10, +}; + +struct ScenarioPOIPoint +{ + int32 X; + int32 Y; + + ScenarioPOIPoint() : X(0), Y(0) { } + ScenarioPOIPoint(int32 _X, int32 _Y) : X(_X), Y(_Y) { } +}; + +struct ScenarioPOI +{ + int32 BlobIndex; + int32 ObjectiveIndex; + int32 QuestObjectiveID; + int32 QuestObjectID; + int32 MapID; + int32 WorldMapAreaID; + int32 Floor; + int32 Priority; + int32 Flags; + int32 WorldEffectID; + int32 PlayerConditionID; + std::vector<ScenarioPOIPoint> Points; + + ScenarioPOI() : BlobIndex(0), MapID(0), WorldMapAreaID(0), Floor(0), Priority(0), Flags(0), WorldEffectID(0), PlayerConditionID(0) { } + + ScenarioPOI(int32 _BlobIndex, int32 _MapID, int32 _WorldMapAreaID, int32 _Floor, int32 _Priority, int32 _Flags, int32 _WorldEffectID, + int32 _PlayerConditionID, std::vector<ScenarioPOIPoint> points) : + BlobIndex(_BlobIndex), MapID(_MapID), WorldMapAreaID(_WorldMapAreaID), Floor(_Floor), Priority(_Priority), Flags(_Flags), WorldEffectID(_WorldEffectID), + PlayerConditionID(_PlayerConditionID), Points(std::move(points)) { } + + ScenarioPOI(ScenarioPOI&& scenarioPOI) : + BlobIndex(scenarioPOI.BlobIndex), MapID(scenarioPOI.MapID), WorldMapAreaID(scenarioPOI.WorldMapAreaID), Floor(scenarioPOI.Floor), Priority(scenarioPOI.Priority), + Flags(scenarioPOI.Flags), WorldEffectID(scenarioPOI.WorldEffectID), PlayerConditionID(scenarioPOI.PlayerConditionID), Points(std::move(scenarioPOI.Points)) { } +}; + +typedef std::vector<ScenarioPOI> ScenarioPOIVector; +typedef std::unordered_map<uint32, ScenarioPOIVector> ScenarioPOIContainer; + +class TC_GAME_API ScenarioMgr +{ +private: + ScenarioMgr() { } + ~ScenarioMgr() { } + +public: + static ScenarioMgr* Instance(); + + void LoadDBData(); + void LoadDB2Data(); + void LoadScenarioPOI(); + + ScenarioPOIVector const* GetScenarioPOIs(int32 CriteriaTreeID) + { + auto itr = _scenarioPOIStore.find(CriteriaTreeID); + if (itr != _scenarioPOIStore.end()) + return &itr->second; + + return nullptr; + } + + InstanceScenario* CreateInstanceScenario(Map* map, TeamId team); + +private: + ScenarioDataContainer _scenarioData; + ScenarioPOIContainer _scenarioPOIStore; + ScenarioDBDataContainer _scenarioDBData; +}; + +#define sScenarioMgr ScenarioMgr::Instance() + +#endif // ScenarioMgr_h__ diff --git a/src/server/game/Server/Packets/AchievementPackets.cpp b/src/server/game/Server/Packets/AchievementPackets.cpp index c5098caa53d..155fa43b806 100644 --- a/src/server/game/Server/Packets/AchievementPackets.cpp +++ b/src/server/game/Server/Packets/AchievementPackets.cpp @@ -27,6 +27,19 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Achievement::EarnedAchiev return data; } +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Achievement::CriteriaProgress const& criteria) +{ + data << uint32(criteria.Id); + data << uint64(criteria.Quantity); + data << criteria.Player; + data.AppendPackedTime(criteria.Date); + data << uint32(criteria.TimeFromStart); + data << uint32(criteria.TimeFromCreate); + data.WriteBits(criteria.Flags, 4); + data.FlushBits(); + return data; +} + ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Achievement::AllAchievements const& allAchievements) { data << uint32(allAchievements.Earned.size()); @@ -36,16 +49,7 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Achievement::AllAchieveme data << earned; for (WorldPackets::Achievement::CriteriaProgress const& progress : allAchievements.Progress) - { - data << uint32(progress.Id); - data << uint64(progress.Quantity); - data << progress.Player; - data.AppendPackedTime(progress.Date); - data << uint32(progress.TimeFromStart); - data << uint32(progress.TimeFromCreate); - data.WriteBits(progress.Flags, 4); - data.FlushBits(); - } + data << progress; return data; } diff --git a/src/server/game/Server/Packets/AchievementPackets.h b/src/server/game/Server/Packets/AchievementPackets.h index bf200ffb242..70feedaf1e4 100644 --- a/src/server/game/Server/Packets/AchievementPackets.h +++ b/src/server/game/Server/Packets/AchievementPackets.h @@ -216,4 +216,6 @@ namespace WorldPackets } } +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Achievement::CriteriaProgress const& criteria); + #endif // game_AchievementPackets_h__ diff --git a/src/server/game/Server/Packets/AllPackets.h b/src/server/game/Server/Packets/AllPackets.h index 7c4f7ba39ab..6f36a93c799 100644 --- a/src/server/game/Server/Packets/AllPackets.h +++ b/src/server/game/Server/Packets/AllPackets.h @@ -60,6 +60,7 @@ #include "QuestPackets.h" #include "ReferAFriendPackets.h" #include "ReputationPackets.h" +#include "ScenarioPackets.h" #include "ScenePackets.h" #include "SocialPackets.h" #include "SpellPackets.h" diff --git a/src/server/game/Server/Packets/ScenarioPackets.cpp b/src/server/game/Server/Packets/ScenarioPackets.cpp new file mode 100644 index 00000000000..46e4324e961 --- /dev/null +++ b/src/server/game/Server/Packets/ScenarioPackets.cpp @@ -0,0 +1,129 @@ +/* + * 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 "ScenarioPackets.h" +#include "ScenarioMgr.h" + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Scenario::BonusObjectiveData const& bonusObjective) +{ + data << int32(bonusObjective.BonusObjectiveID); + data.WriteBit(bonusObjective.ObjectiveComplete); + data.FlushBits(); + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Scenario::ScenarioSpellUpdate const& spell) +{ + data << uint32(spell.SpellID); + data.WriteBit(spell.Usable); + data.FlushBits(); + return data; +} + +WorldPacket const* WorldPackets::Scenario::ScenarioState::Write() +{ + _worldPacket << int32(ScenarioID); + _worldPacket << int32(CurrentStep); + _worldPacket << uint32(DifficultyID); + _worldPacket << uint32(WaveCurrent); + _worldPacket << uint32(WaveMax); + _worldPacket << uint32(TimerDuration); + _worldPacket << uint32(CriteriaProgress.size()); + _worldPacket << uint32(BonusObjectives.size()); + _worldPacket << uint32(PickedSteps.size()); + _worldPacket << uint32(Spells.size()); + + for (uint32 i = 0; i < PickedSteps.size(); ++i) + _worldPacket << uint32(PickedSteps[i]); + + _worldPacket.WriteBit(ScenarioComplete); + _worldPacket.FlushBits(); + + for (WorldPackets::Achievement::CriteriaProgress const& progress : CriteriaProgress) + _worldPacket << progress; + + for (WorldPackets::Scenario::BonusObjectiveData const& bonusObjective : BonusObjectives) + _worldPacket << bonusObjective; + + for (WorldPackets::Scenario::ScenarioSpellUpdate const& spell : Spells) + _worldPacket << spell; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Scenario::ScenarioProgressUpdate::Write() +{ + _worldPacket << CriteriaProgress; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Scenario::ScenarioCompleted::Write() +{ + _worldPacket << uint32(ScenarioID); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Scenario::ScenarioBoot::Write() +{ + _worldPacket << int32(ScenarioID); + _worldPacket << int32(Unk1); + _worldPacket.WriteBits(Unk2, 2); + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +void WorldPackets::Scenario::QueryScenarioPOI::Read() +{ + MissingScenarioPOIs.resize(_worldPacket.read<uint32>()); + for (int32& scenarioPOI : MissingScenarioPOIs) + _worldPacket >> scenarioPOI; +} + +WorldPacket const* WorldPackets::Scenario::ScenarioPOIs::Write() +{ + _worldPacket << uint32(ScenarioPOIDataStats.size()); + + for (ScenarioPOIData const& scenarioPOIData : ScenarioPOIDataStats) + { + _worldPacket << int32(scenarioPOIData.CriteriaTreeID); + _worldPacket << uint32(scenarioPOIData.ScenarioPOIs->size()); + + for (ScenarioPOI const& scenarioPOI : *scenarioPOIData.ScenarioPOIs) + { + _worldPacket << int32(scenarioPOI.BlobIndex); + _worldPacket << int32(scenarioPOI.MapID); + _worldPacket << int32(scenarioPOI.WorldMapAreaID); + _worldPacket << int32(scenarioPOI.Floor); + _worldPacket << int32(scenarioPOI.Priority); + _worldPacket << int32(scenarioPOI.Flags); + _worldPacket << int32(scenarioPOI.WorldEffectID); + _worldPacket << int32(scenarioPOI.PlayerConditionID); + _worldPacket << uint32(scenarioPOI.Points.size()); + + for (ScenarioPOIPoint const& scenarioPOIBlobPoint : scenarioPOI.Points) + { + _worldPacket << int32(scenarioPOIBlobPoint.X); + _worldPacket << int32(scenarioPOIBlobPoint.Y); + } + } + } + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/ScenarioPackets.h b/src/server/game/Server/Packets/ScenarioPackets.h new file mode 100644 index 00000000000..9e365e3a2e9 --- /dev/null +++ b/src/server/game/Server/Packets/ScenarioPackets.h @@ -0,0 +1,125 @@ +/* + * 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 ScenarioPackets_h__ +#define ScenarioPackets_h__ + +#include "Packet.h" +#include "PacketUtilities.h" +#include "AchievementPackets.h" + +#define MAX_ALLOWED_SCENARIO_POI_QUERY_SIZE 35 + +struct ScenarioPOI; + +namespace WorldPackets +{ + namespace Scenario + { + struct BonusObjectiveData + { + int32 BonusObjectiveID = 0; + bool ObjectiveComplete = false; + }; + + struct ScenarioSpellUpdate + { + uint32 SpellID = 0; + bool Usable = true; + }; + + class ScenarioState final : public ServerPacket + { + public: + ScenarioState() : ServerPacket(SMSG_SCENARIO_STATE) { } + + WorldPacket const* Write() override; + + int32 ScenarioID = 0; + int32 CurrentStep = -1; + uint32 DifficultyID = 0; + uint32 WaveCurrent = 0; + uint32 WaveMax = 0; + uint32 TimerDuration = 0; + std::vector<WorldPackets::Achievement::CriteriaProgress> CriteriaProgress; + std::vector<BonusObjectiveData> BonusObjectives; + std::vector<uint32> PickedSteps; + std::vector<ScenarioSpellUpdate> Spells; + bool ScenarioComplete = false; + }; + + class ScenarioProgressUpdate final : public ServerPacket + { + public: + ScenarioProgressUpdate() : ServerPacket(SMSG_SCENARIO_PROGRESS_UPDATE) { } + + WorldPacket const* Write() override; + + WorldPackets::Achievement::CriteriaProgress CriteriaProgress; + }; + + class ScenarioCompleted final : public ServerPacket + { + public: + ScenarioCompleted(uint32 scenarioId) : ServerPacket(SMSG_SCENARIO_COMPLETED, 4), ScenarioID(scenarioId) { } + + WorldPacket const* Write() override; + + uint32 ScenarioID = 0; + }; + + class ScenarioBoot final : public ServerPacket + { + public: + ScenarioBoot() : ServerPacket(SMSG_SCENARIO_BOOT, 4 + 4 + 1) { } + + WorldPacket const* Write() override; + + int32 ScenarioID = 0; + int32 Unk1 = 0; + uint8 Unk2 = 0; + }; + + class QueryScenarioPOI final : public ClientPacket + { + public: + QueryScenarioPOI(WorldPacket&& packet) : ClientPacket(CMSG_QUERY_SCENARIO_POI, std::move(packet)) { } + + void Read() override; + + Array<int32, MAX_ALLOWED_SCENARIO_POI_QUERY_SIZE> MissingScenarioPOIs; + }; + + struct ScenarioPOIData + { + int32 CriteriaTreeID = 0; + std::vector<ScenarioPOI> const* ScenarioPOIs = nullptr; + }; + + class ScenarioPOIs final : public ServerPacket + { + public: + ScenarioPOIs() : ServerPacket(SMSG_SCENARIO_POIS) { } + + WorldPacket const* Write() override; + + std::vector<ScenarioPOIData> ScenarioPOIDataStats; + }; + } +} + +#endif // ScenarioPackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 7cd5e23def7..e24e9153121 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -627,7 +627,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_QUERY_QUEST_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestQueryOpcode); DEFINE_HANDLER(CMSG_QUERY_QUEST_REWARDS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_QUERY_REALM_NAME, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_QUERY_SCENARIO_POI, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_QUERY_SCENARIO_POI, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryScenarioPOI); DEFINE_HANDLER(CMSG_QUERY_TIME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryTimeOpcode); DEFINE_HANDLER(CMSG_QUERY_VOID_STORAGE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleVoidStorageQuery); DEFINE_HANDLER(CMSG_QUEST_CONFIRM_ACCEPT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestConfirmAccept); @@ -1602,12 +1602,12 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_ROLE_CHOSEN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ROLE_POLL_INFORM, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RUNE_REGEN_DEBUG, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_BOOT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_COMPLETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_POIS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_PROGRESS_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_SPELL_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_STATE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_BOOT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_COMPLETED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_POIS, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_PROGRESS_UPDATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_SPELL_UPDATE, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENARIO_STATE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENE_OBJECT_EVENT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENE_OBJECT_PET_BATTLE_FINAL_ROUND, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SCENE_OBJECT_PET_BATTLE_FINISHED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 11ada4c421f..5c49c0887c9 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -581,6 +581,11 @@ namespace WorldPackets class UseToy; } + namespace Scenario + { + class QueryScenarioPOI; + } + namespace Scenes { class SceneTriggerEvent; @@ -1736,6 +1741,9 @@ class TC_GAME_API WorldSession void HandleArtifactSetAppearance(WorldPackets::Artifact::ArtifactSetAppearance& artifactSetAppearance); void HandleConfirmArtifactRespec(WorldPackets::Artifact::ConfirmArtifactRespec& confirmArtifactRespec); + // Scenario + void HandleQueryScenarioPOI(WorldPackets::Scenario::QueryScenarioPOI& queryScenarioPOI); + union ConnectToKey { struct diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 677b40da524..2b6a3da5cd3 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -59,6 +59,7 @@ #include "Player.h" #include "PoolMgr.h" #include "GitRevision.h" +#include "ScenarioMgr.h" #include "ScriptMgr.h" #include "ScriptReloadMgr.h" #include "SkillDiscovery.h" @@ -2120,6 +2121,13 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading battle pets info..."); BattlePetMgr::Initialize(); + TC_LOG_INFO("server.loading", "Loading scenarios"); + sScenarioMgr->LoadDB2Data(); + sScenarioMgr->LoadDBData(); + + TC_LOG_INFO("server.loading", "Loading scenario poi data"); + sScenarioMgr->LoadScenarioPOI(); + // Preload all cells, if required for the base maps if (sWorld->getBoolConfig(CONFIG_BASEMAP_LOAD_GRIDS)) { |