Core/Skills: implement Archaeology
This commit is contained in:
commit
3ba5756c1c
38 files changed
+2903
-34
No files matched your search
@@ -0,0 +1,41 @@
|
||||
/*Table structure for table `character_archaeology_completed` */
|
||||
|
||||
DROP TABLE IF EXISTS `character_archaeology_completed`;
|
||||
|
||||
CREATE TABLE `character_archaeology_completed` (
|
||||
`guid` int(10) unsigned NOT NULL,
|
||||
`project` smallint(5) unsigned NOT NULL,
|
||||
`time` int(10) NOT NULL,
|
||||
`count` int(10) NOT NULL,
|
||||
PRIMARY KEY (`guid`,`project`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
/*Data for the table `character_archaeology_completed` */
|
||||
|
||||
/*Table structure for table `character_archaeology_projects` */
|
||||
|
||||
DROP TABLE IF EXISTS `character_archaeology_projects`;
|
||||
|
||||
CREATE TABLE `character_archaeology_projects` (
|
||||
`guid` int(10) unsigned NOT NULL,
|
||||
`branch` tinyint(3) unsigned NOT NULL,
|
||||
`project` mediumint(8) unsigned NOT NULL,
|
||||
PRIMARY KEY (`guid`,`branch`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
/*Data for the table `character_archaeology_projects` */
|
||||
|
||||
/*Table structure for table `character_archaeology_sites` */
|
||||
|
||||
DROP TABLE IF EXISTS `character_archaeology_sites`;
|
||||
|
||||
CREATE TABLE `character_archaeology_sites` (
|
||||
`guid` int(10) unsigned NOT NULL,
|
||||
`site` tinyint(3) unsigned NOT NULL,
|
||||
`type` smallint(5) unsigned NOT NULL,
|
||||
`finds` tinyint(3) unsigned NOT NULL,
|
||||
PRIMARY KEY (`guid`,`site`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
/*Data for the table `character_archaeology_sites` */
|
||||
|
||||
@@ -0,0 +1,373 @@
|
||||
|
||||
/*Table structure for table `archaeology_sites` */
|
||||
|
||||
DROP TABLE IF EXISTS `archaeology_sites`;
|
||||
|
||||
CREATE TABLE `archaeology_sites` (
|
||||
`Id` smallint(5) unsigned NOT NULL,
|
||||
`MapId` int(10) unsigned NOT NULL,
|
||||
`QuestPOI` smallint(5) unsigned NOT NULL,
|
||||
`ReqSkill` int(10) unsigned NOT NULL,
|
||||
`MinLevel` int(10) unsigned NOT NULL,
|
||||
`GameobjectEntry` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
/*Data for the table `archaeology_sites` */
|
||||
|
||||
INSERT INTO `archaeology_sites`(`Id`,`MapId`,`QuestPOI`,`ReqSkill`,`MinLevel`,`GameobjectEntry`) VALUES
|
||||
(9,0,54097,0,10,204282),
|
||||
(10,0,54124,0,20,204282),
|
||||
(12,0,54126,0,20,204282),
|
||||
(13,0,54127,0,20,206836),
|
||||
(15,0,54129,0,25,204282),
|
||||
(18,0,54132,0,25,202655),
|
||||
(19,0,54133,0,20,204282),
|
||||
(20,0,54134,0,20,206836),
|
||||
(21,0,54135,0,20,206836),
|
||||
(22,0,54136,0,30,204282),
|
||||
(23,0,54137,0,30,202655),
|
||||
(24,0,54138,0,30,202655),
|
||||
(25,0,54139,0,30,202655),
|
||||
(26,0,54140,0,30,202655),
|
||||
(27,0,54141,0,30,202655),
|
||||
(144,0,54832,0,44,204282),
|
||||
(146,0,54834,0,44,204282),
|
||||
(150,0,54838,0,44,204282),
|
||||
(152,0,54862,0,52,202655),
|
||||
(154,0,54864,0,52,206836),
|
||||
(163,0,55350,0,20,203071),
|
||||
(165,0,55352,0,20,206836),
|
||||
(167,1,55354,0,10,203071),
|
||||
(169,1,55356,0,20,203071),
|
||||
(171,1,55398,0,20,203071),
|
||||
(173,1,55400,0,20,203071),
|
||||
(175,1,55402,0,20,203071),
|
||||
(177,1,55404,0,25,203071),
|
||||
(179,1,55406,0,25,203071),
|
||||
(181,1,55408,0,25,206836),
|
||||
(183,1,55410,0,30,204282),
|
||||
(185,1,55412,0,10,203071),
|
||||
(187,1,55414,0,10,203071),
|
||||
(189,0,55416,0,15,206836),
|
||||
(191,1,55418,0,30,203071),
|
||||
(193,1,55420,0,30,203071),
|
||||
(195,1,55422,0,30,206836),
|
||||
(197,1,55424,0,30,203071),
|
||||
(199,1,55426,0,30,206836),
|
||||
(201,1,55428,0,30,203071),
|
||||
(203,0,55434,0,54,206836),
|
||||
(205,0,55436,0,54,206836),
|
||||
(207,0,55438,0,47,204282),
|
||||
(209,0,55440,0,47,204282),
|
||||
(211,0,55442,0,49,204282),
|
||||
(213,0,55444,0,49,204282),
|
||||
(215,0,55446,0,49,206836),
|
||||
(217,0,55448,0,40,202655),
|
||||
(219,0,55450,0,40,203071),
|
||||
(221,0,55452,0,40,206836),
|
||||
(223,0,55454,0,25,202655),
|
||||
(225,0,55456,0,25,202655),
|
||||
(227,0,55458,0,25,202655),
|
||||
(229,0,55460,0,25,202655),
|
||||
(231,0,55462,0,25,202655),
|
||||
(233,0,55464,0,25,202655),
|
||||
(235,0,55466,0,25,202655),
|
||||
(237,0,55468,0,25,206836),
|
||||
(239,0,55470,0,30,202655),
|
||||
(241,0,55472,0,30,202655),
|
||||
(243,0,55474,0,30,202655),
|
||||
(245,0,55476,0,30,202655),
|
||||
(247,0,55478,0,35,206836),
|
||||
(249,0,55480,0,35,206836),
|
||||
(251,0,55482,0,35,206836),
|
||||
(259,1,55755,0,35,206836),
|
||||
(261,1,55757,0,35,206836),
|
||||
(279,1,56327,0,35,203071),
|
||||
(281,1,56329,0,35,203071),
|
||||
(283,1,56331,0,35,203071),
|
||||
(285,1,56333,0,35,203071),
|
||||
(287,1,56335,0,35,203071),
|
||||
(289,1,56337,0,35,203071),
|
||||
(291,1,56339,0,35,203071),
|
||||
(293,1,56341,0,35,203071),
|
||||
(295,1,56343,0,45,203071),
|
||||
(297,1,56345,0,45,203071),
|
||||
(299,1,56347,0,45,203071),
|
||||
(301,1,56349,0,45,203071),
|
||||
(303,1,56351,0,50,203071),
|
||||
(305,1,56354,0,50,203071),
|
||||
(307,1,56356,0,50,203071),
|
||||
(309,1,56358,0,30,206836),
|
||||
(313,1,56362,0,30,203071),
|
||||
(315,1,56364,0,45,202655),
|
||||
(317,1,56367,0,45,202655),
|
||||
(319,1,56369,0,45,202655),
|
||||
(321,1,56371,0,45,202655),
|
||||
(323,1,56373,0,45,206836),
|
||||
(325,1,56375,0,45,206836),
|
||||
(327,1,56380,0,50,206836),
|
||||
(329,1,56382,0,50,206836),
|
||||
(331,1,56384,0,50,206836),
|
||||
(333,1,56386,0,50,206836),
|
||||
(335,1,56388,0,50,206836),
|
||||
(337,1,56390,0,55,203071),
|
||||
(339,530,56392,300,58,207187),
|
||||
(341,530,56394,300,58,207187),
|
||||
(343,530,56396,300,58,207187),
|
||||
(345,530,56398,300,58,207187),
|
||||
(347,530,56400,300,58,207188),
|
||||
(349,530,56402,300,60,207188),
|
||||
(351,530,56404,300,60,207188),
|
||||
(353,530,56406,300,67,207188),
|
||||
(355,530,56408,300,67,207188),
|
||||
(357,530,56410,300,67,207188),
|
||||
(359,530,56412,300,64,207187),
|
||||
(363,530,56416,300,64,207187),
|
||||
(365,530,56418,300,64,207187),
|
||||
(367,530,56420,300,64,207187),
|
||||
(369,530,56422,300,64,207188),
|
||||
(371,530,56424,300,62,207187),
|
||||
(373,530,56426,300,62,207188),
|
||||
(375,530,56428,300,62,207187),
|
||||
(377,530,56430,300,62,207187),
|
||||
(379,530,56432,300,62,207188),
|
||||
(381,530,56434,300,62,207188),
|
||||
(383,530,56437,300,62,207188),
|
||||
(385,530,56439,300,67,207188),
|
||||
(387,530,56441,300,67,207188),
|
||||
(391,530,56446,300,67,207188),
|
||||
(393,530,56448,300,67,207188),
|
||||
(395,530,56450,300,67,207187),
|
||||
(399,530,56455,300,67,207187),
|
||||
(401,571,56504,375,68,207189),
|
||||
(403,571,56506,375,68,207189),
|
||||
(405,571,56508,375,68,207189),
|
||||
(407,571,56510,375,68,207189),
|
||||
(409,571,56512,375,68,207189),
|
||||
(411,571,56514,375,68,207189),
|
||||
(413,571,56516,375,68,207189),
|
||||
(415,571,56518,375,71,203078),
|
||||
(417,571,56520,375,71,203071),
|
||||
(419,571,56522,375,68,203078),
|
||||
(421,571,56524,375,74,203078),
|
||||
(423,571,56526,375,68,203071),
|
||||
(425,571,56528,375,77,203071),
|
||||
(427,571,56530,375,77,203071),
|
||||
(429,571,56533,375,74,202655),
|
||||
(431,571,56535,375,74,202655),
|
||||
(433,571,56537,375,74,202655),
|
||||
(435,571,56539,375,74,202655),
|
||||
(437,571,56541,375,68,203078),
|
||||
(439,571,56543,375,73,207189),
|
||||
(443,571,56547,375,73,202655),
|
||||
(445,571,56549,375,77,207189),
|
||||
(447,571,56551,375,77,207189),
|
||||
(449,571,56553,375,77,207189),
|
||||
(451,571,56555,375,77,203078),
|
||||
(455,571,56560,375,77,207189),
|
||||
(457,571,56562,375,77,207189),
|
||||
(459,571,56564,375,77,207189),
|
||||
(461,1,56566,0,80,203071),
|
||||
(463,1,56568,0,80,203071),
|
||||
(465,1,56570,0,80,203071),
|
||||
(467,1,56572,0,80,203071),
|
||||
(469,1,56574,0,80,203071),
|
||||
(477,0,56583,0,84,204282),
|
||||
(479,0,56585,0,84,204282),
|
||||
(481,0,56587,0,84,204282),
|
||||
(485,1,56591,475,83,207190),
|
||||
(487,1,56593,475,83,207190),
|
||||
(489,1,56595,475,83,207190),
|
||||
(491,1,56597,475,83,207190),
|
||||
(493,1,56599,475,83,207190),
|
||||
(495,1,56601,475,83,207190),
|
||||
(497,1,56603,475,83,207190),
|
||||
(499,1,56605,475,83,207190),
|
||||
(501,1,56607,475,83,207190),
|
||||
(570,1,60350,475,83,207190),
|
||||
(572,1,60352,475,83,207190),
|
||||
(574,1,60354,475,83,207190),
|
||||
(576,1,60356,475,83,207190),
|
||||
(578,1,60358,475,83,207190),
|
||||
(581,1,60361,475,83,207190),
|
||||
(583,1,60363,475,83,207190),
|
||||
(587,571,60367,375,77,203078),
|
||||
(589,571,60369,375,68,203078),
|
||||
(615,0,60442,0,40,203078),
|
||||
(617,0,60444,0,40,203078);
|
||||
|
||||
|
||||
|
||||
DROP TABLE IF EXISTS `archaeology_projects`;
|
||||
|
||||
CREATE TABLE `archaeology_projects` (
|
||||
`Entry` smallint(5) unsigned NOT NULL DEFAULT '0',
|
||||
`Branch` tinyint(3) unsigned NOT NULL,
|
||||
`Rarity` tinyint(3) unsigned NOT NULL,
|
||||
`ReqSkill` smallint(5) unsigned NOT NULL,
|
||||
`Fragments` tinyint(3) unsigned NOT NULL,
|
||||
`Keystone` tinyint(3) unsigned NOT NULL,
|
||||
`Spell` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`entry`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
/*Data for the table `archaeology_projects` */
|
||||
|
||||
INSERT INTO `archaeology_projects`(`Entry`,`Branch`,`Rarity`,`ReqSkill`,`Fragments`,`Keystone`,`Spell`) VALUES
|
||||
(9,1,0,1,35,1,86857),
|
||||
(40,1,0,1,35,1,86864),
|
||||
(42,1,0,1,30,0,86865),
|
||||
(44,1,0,1,32,0,86866),
|
||||
(70,1,0,1,35,1,88180),
|
||||
(72,1,0,1,34,1,88181),
|
||||
(77,8,0,1,27,0,88262),
|
||||
(87,8,0,1,30,0,88907),
|
||||
(89,8,0,1,32,0,88908),
|
||||
(91,1,0,1,28,0,88909),
|
||||
(93,1,0,1,34,0,88910),
|
||||
(95,3,0,1,31,0,88929),
|
||||
(97,3,0,1,25,0,88930),
|
||||
(99,4,0,1,30,0,89009),
|
||||
(101,4,0,1,30,0,89012),
|
||||
(103,4,0,1,30,0,89014),
|
||||
(106,3,3,50,85,0,89693),
|
||||
(108,4,0,1,35,1,89696),
|
||||
(112,8,0,1,35,1,89701),
|
||||
(114,8,0,1,34,1,89711),
|
||||
(118,1,0,1,34,1,89717),
|
||||
(120,8,0,1,35,1,89890),
|
||||
(122,8,0,1,35,1,89891),
|
||||
(124,4,0,1,35,1,89893),
|
||||
(126,4,0,1,35,1,89894),
|
||||
(128,3,0,1,35,0,89895),
|
||||
(130,4,0,1,35,1,89896),
|
||||
(139,1,0,1,35,1,90410),
|
||||
(141,1,0,1,35,1,90411),
|
||||
(143,1,0,1,34,1,90412),
|
||||
(145,1,0,1,35,1,90413),
|
||||
(147,1,0,1,35,1,90415),
|
||||
(149,1,0,1,36,1,90419),
|
||||
(153,8,0,1,35,1,90420),
|
||||
(155,8,0,1,35,1,90421),
|
||||
(157,8,0,1,35,1,90423),
|
||||
(159,8,0,1,35,1,90429),
|
||||
(161,3,0,1,35,0,90432),
|
||||
(163,3,0,1,35,0,90433),
|
||||
(165,4,0,1,35,1,90451),
|
||||
(167,3,0,1,35,0,90452),
|
||||
(169,4,0,1,35,1,90453),
|
||||
(171,4,0,1,35,1,90458),
|
||||
(173,4,3,150,100,3,90464),
|
||||
(175,4,3,150,100,3,90493),
|
||||
(177,1,0,1,35,1,90504),
|
||||
(179,1,0,1,35,1,90506),
|
||||
(181,1,0,1,35,1,90509),
|
||||
(183,1,0,1,35,1,90518),
|
||||
(185,1,0,1,35,1,90519),
|
||||
(187,1,3,225,100,3,90521),
|
||||
(189,1,3,150,100,3,90553),
|
||||
(191,8,0,1,35,1,90558),
|
||||
(193,8,0,1,35,1,90581),
|
||||
(195,8,4,450,150,3,90608),
|
||||
(197,4,0,1,35,1,90609),
|
||||
(199,4,0,1,34,1,90610),
|
||||
(201,4,0,1,35,1,90611),
|
||||
(203,4,0,1,35,1,90612),
|
||||
(205,4,3,225,98,3,90614),
|
||||
(207,4,4,225,100,3,90616),
|
||||
(209,3,0,1,33,0,90617),
|
||||
(211,3,0,1,35,0,90618),
|
||||
(213,3,4,150,100,0,90619),
|
||||
(215,6,0,300,45,2,90622),
|
||||
(217,6,0,300,45,2,90720),
|
||||
(219,6,0,300,45,2,90728),
|
||||
(221,6,0,300,45,2,90730),
|
||||
(223,6,0,300,45,2,90732),
|
||||
(225,6,0,300,45,2,90734),
|
||||
(231,6,0,300,45,2,90833),
|
||||
(233,6,0,300,45,2,90832),
|
||||
(235,6,0,300,45,2,90831),
|
||||
(237,6,4,300,130,3,90843),
|
||||
(239,2,0,300,45,2,90853),
|
||||
(241,2,0,300,45,2,90860),
|
||||
(243,2,0,300,46,2,90861),
|
||||
(245,2,0,300,46,2,90864),
|
||||
(250,2,0,300,46,2,90968),
|
||||
(252,2,0,300,44,2,90974),
|
||||
(254,2,0,300,45,2,90975),
|
||||
(256,2,3,300,124,3,90983),
|
||||
(258,2,3,300,130,3,90984),
|
||||
(260,2,0,300,45,2,90987),
|
||||
(262,27,0,375,45,2,90988),
|
||||
(264,27,4,375,130,3,90997),
|
||||
(266,27,0,375,45,2,91008),
|
||||
(268,27,0,375,45,2,91012),
|
||||
(270,27,0,375,45,2,91014),
|
||||
(273,27,0,375,45,2,91084),
|
||||
(275,3,0,300,45,0,91089),
|
||||
(277,3,0,300,45,0,91132),
|
||||
(279,5,0,375,45,2,91133),
|
||||
(283,5,0,375,45,2,91170),
|
||||
(285,5,0,375,45,3,91188),
|
||||
(287,5,0,375,45,2,91191),
|
||||
(289,5,0,375,45,2,91197),
|
||||
(291,5,0,375,45,2,91209),
|
||||
(293,5,0,375,45,2,91211),
|
||||
(295,5,4,375,140,3,91214),
|
||||
(297,5,4,375,140,3,91215),
|
||||
(301,1,0,1,45,2,91219),
|
||||
(303,1,0,1,45,2,91221),
|
||||
(305,1,0,1,45,2,91223),
|
||||
(307,1,0,1,45,2,91224),
|
||||
(309,1,0,1,45,2,91225),
|
||||
(313,1,3,150,150,3,91226),
|
||||
(315,1,4,450,150,3,91227),
|
||||
(317,4,4,450,150,3,91757),
|
||||
(319,4,4,450,150,3,91761),
|
||||
(323,4,0,450,45,2,91762),
|
||||
(325,4,0,450,45,2,91766),
|
||||
(327,4,0,450,45,2,91769),
|
||||
(329,4,4,450,150,3,91773),
|
||||
(331,7,0,450,45,2,91775),
|
||||
(333,7,0,450,45,2,91779),
|
||||
(335,7,0,450,45,2,91780),
|
||||
(339,7,0,450,45,2,91782),
|
||||
(341,7,0,450,45,2,91785),
|
||||
(343,7,1,450,45,2,91790),
|
||||
(345,7,0,450,45,2,91792),
|
||||
(347,1,0,1,45,2,91793),
|
||||
(349,7,4,450,150,3,92137),
|
||||
(351,7,4,450,150,3,92139),
|
||||
(353,7,4,450,150,3,92145),
|
||||
(355,7,4,450,150,3,92148),
|
||||
(357,7,4,450,150,3,92163),
|
||||
(359,7,4,450,150,3,92168),
|
||||
(371,1,0,1,30,0,93440),
|
||||
(372,4,0,1,30,0,93441),
|
||||
(374,3,0,1,30,0,93442),
|
||||
(378,3,0,1,35,0,93443),
|
||||
(380,8,0,1,32,0,93444),
|
||||
(628,3,4,450,150,0,98533),
|
||||
(633,8,3,150,100,3,98556),
|
||||
(635,3,3,225,100,0,98560),
|
||||
(637,27,3,500,100,3,98569),
|
||||
(639,3,3,225,120,0,98582),
|
||||
(641,8,3,150,100,3,98588);
|
||||
|
||||
DELETE FROM `achievement_criteria_data` WHERE `criteria_id` IN (5315, 5469,5470);
|
||||
INSERT INTO `achievement_criteria_data` (`criteria_id`, `type`, `value1`, `value2`, `ScriptName`) VALUES
|
||||
(5315, 8, 10, 3, ""),
|
||||
(5469, 8, 50, 3, ""),
|
||||
(5470, 8, 100, 3, "");
|
||||
|
||||
DELETE FROM `achievement_reward` WHERE `ID` IN (4854, 4855, 4856);
|
||||
INSERT INTO `achievement_reward` (`ID`, `TitleA`, `TitleH`) VALUES
|
||||
(4854, 189, 189),
|
||||
(4855, 190, 190),
|
||||
(4856, 191, 191);
|
||||
|
||||
DELETE FROM `trinity_string` WHERE `entry`= 810;
|
||||
INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES
|
||||
(810, "You can't use that here.");
|
||||
|
||||
@@ -1258,6 +1258,7 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type,
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_CURRENCY:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS:
|
||||
SetCriteriaProgress(achievementCriteria, miscValue2, referencePlayer, PROGRESS_ACCUMULATE);
|
||||
break;
|
||||
// std case: high value at miscValue1
|
||||
@@ -1486,7 +1487,6 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type,
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_GUILD:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILLS_GUILD:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE_GUILD:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE_TYPE:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_GUILD_CHALLENGE:
|
||||
break; // Not implemented yet :(
|
||||
@@ -1543,6 +1543,8 @@ bool AchievementMgr<T>::IsCompletedCriteria(AchievementCriteriaEntry const* achi
|
||||
return progress->counter >= achievementCriteria->win_bg.winCount;
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
|
||||
return progress->counter >= achievementCriteria->kill_creature.creatureCount;
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS:
|
||||
return progress->counter >= achievementCriteria->archaeology.count;
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
|
||||
case ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL:
|
||||
return progress->counter >= achievementCriteria->reach_level.level;
|
||||
@@ -2913,6 +2915,32 @@ bool AchievementMgr<T>::AdditionalRequirementsSatisfied(AchievementCriteriaEntry
|
||||
if (!unit || unit->GetHealthPct() >= reqValue)
|
||||
return false;
|
||||
break;
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_PROJECT_RARITY: // 65
|
||||
{
|
||||
if (!miscValue1)
|
||||
return false;
|
||||
|
||||
ResearchProjectEntry const* rp = sResearchProjectStore.LookupEntry(miscValue1);
|
||||
if (!rp) return false;
|
||||
|
||||
if (rp->hasReward != reqValue)
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_PROJECT_RACE: // 66
|
||||
{
|
||||
if (!miscValue1)
|
||||
return false;
|
||||
|
||||
ResearchProjectEntry const* rp = sResearchProjectStore.LookupEntry(miscValue1);
|
||||
if (!rp) return false;
|
||||
|
||||
if (rp->ResearchBranchID != reqValue)
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -592,12 +592,24 @@ enum VehicleSeatFlagsB
|
||||
// CurrencyTypes.dbc
|
||||
enum CurrencyTypes
|
||||
{
|
||||
// PvE and PvP
|
||||
CURRENCY_TYPE_CONQUEST_POINTS = 390,
|
||||
CURRENCY_TYPE_HONOR_POINTS = 392,
|
||||
CURRENCY_TYPE_JUSTICE_POINTS = 395,
|
||||
CURRENCY_TYPE_VALOR_POINTS = 396,
|
||||
CURRENCY_TYPE_CONQUEST_META_ARENA = 483,
|
||||
CURRENCY_TYPE_CONQUEST_META_RBG = 484,
|
||||
|
||||
// Archaeology
|
||||
CURRENCY_TYPE_DWARF_FRAGMENT = 384,
|
||||
CURRENCY_TYPE_TROLL_FRAGMENT = 385,
|
||||
CURRENCY_TYPE_FOSSIL_FRAGMENT = 393,
|
||||
CURRENCY_TYPE_NELF_FRAGMENT = 394,
|
||||
CURRENCY_TYPE_ORC_FRAGMENT = 397,
|
||||
CURRENCY_TYPE_DRAENEI_FRAGMENT = 398,
|
||||
CURRENCY_TYPE_VRYKUL_FRAGMENT = 399,
|
||||
CURRENCY_TYPE_NERUBIAN_FRAGMENT = 400,
|
||||
CURRENCY_TYPE_TOLVIR_FRAGMENT = 401,
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -188,6 +188,8 @@ DBCStorage <PvPDifficultyEntry> sPvPDifficultyStore(PvPDifficultyfmt);
|
||||
DBCStorage <QuestSortEntry> sQuestSortStore(QuestSortEntryfmt);
|
||||
DBCStorage <QuestXPEntry> sQuestXPStore(QuestXPfmt);
|
||||
DBCStorage <QuestFactionRewEntry> sQuestFactionRewardStore(QuestFactionRewardfmt);
|
||||
DBCStorage <QuestPOIBlobEntry> sQuestPOIBlobStore(QuestPOIBlobfmt);
|
||||
DBCStorage <QuestPOIPointEntry> sQuestPOIPointStore(QuestPOIPointfmt);
|
||||
DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore(RandomPropertiesPointsfmt);
|
||||
DBCStorage <ScalingStatDistributionEntry> sScalingStatDistributionStore(ScalingStatDistributionfmt);
|
||||
DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore(ScalingStatValuesfmt);
|
||||
@@ -205,6 +207,10 @@ DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionSt
|
||||
DBCStorage <SpellEntry> sSpellStore(SpellEntryfmt);
|
||||
PetFamilySpellsStore sPetFamilySpellsStore;
|
||||
|
||||
DBCStorage <ResearchBranchEntry> sResearchBranchStore(ResearchBranchEntryfmt);
|
||||
DBCStorage <ResearchFieldEntry> sResearchFieldStore(ResearchFieldEntryfmt);
|
||||
DBCStorage <ResearchProjectEntry> sResearchProjectStore(ResearchProjectEntryfmt);
|
||||
DBCStorage <ResearchSiteEntry> sResearchSiteStore(ResearchSiteEntryfmt);
|
||||
|
||||
DBCStorage <SpellReagentsEntry> sSpellReagentsStore(SpellReagentsEntryfmt);
|
||||
DBCStorage <SpellScalingEntry> sSpellScalingStore(SpellScalingEntryfmt);
|
||||
@@ -563,9 +569,15 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sQuestXPStore, dbcPath, "QuestXP.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sQuestFactionRewardStore, dbcPath, "QuestFactionReward.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sQuestPOIBlobStore, dbcPath, "QuestPOIBlob.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sQuestPOIPointStore, dbcPath, "QuestPOIPoint.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sQuestSortStore, dbcPath, "QuestSort.dbc");//15595
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sRandomPropertiesPointsStore, dbcPath, "RandPropPoints.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sResearchBranchStore, dbcPath, "ResearchBranch.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sResearchFieldStore, dbcPath, "ResearchField.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sResearchProjectStore, dbcPath, "ResearchProject.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sResearchSiteStore, dbcPath, "ResearchSite.dbc");//15595
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sScalingStatDistributionStore, dbcPath, "ScalingStatDistribution.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sScalingStatValuesStore, dbcPath, "ScalingStatValues.dbc");//15595
|
||||
@@ -582,7 +594,6 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellStore, dbcPath, "Spell.dbc", &CustomSpellEntryfmt, &CustomSpellEntryIndex);//
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCategoriesStore, dbcPath,"SpellCategories.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCategoryStore, dbcPath, "SpellCategory.dbc");
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellReagentsStore, dbcPath,"SpellReagents.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellScalingStore, dbcPath,"SpellScaling.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellTotemsStore, dbcPath,"SpellTotems.dbc");//15595
|
||||
|
||||
@@ -193,7 +193,13 @@ TC_GAME_API extern DBCStorage <PowerDisplayEntry> sPowerDisplayStore;
|
||||
TC_GAME_API extern DBCStorage <QuestSortEntry> sQuestSortStore;
|
||||
TC_GAME_API extern DBCStorage <QuestXPEntry> sQuestXPStore;
|
||||
TC_GAME_API extern DBCStorage <QuestFactionRewEntry> sQuestFactionRewardStore;
|
||||
TC_GAME_API extern DBCStorage <QuestPOIPointEntry> sQuestPOIPointStore;
|
||||
TC_GAME_API extern DBCStorage <QuestPOIBlobEntry> sQuestPOIBlobStore;
|
||||
TC_GAME_API extern DBCStorage <RandomPropertiesPointsEntry> sRandomPropertiesPointsStore;
|
||||
TC_GAME_API extern DBCStorage <ResearchBranchEntry> sResearchBranchStore;
|
||||
TC_GAME_API extern DBCStorage <ResearchFieldEntry> sResearchFieldStore;
|
||||
TC_GAME_API extern DBCStorage <ResearchProjectEntry> sResearchProjectStore;
|
||||
TC_GAME_API extern DBCStorage <ResearchSiteEntry> sResearchSiteStore;
|
||||
TC_GAME_API extern DBCStorage <ScalingStatDistributionEntry> sScalingStatDistributionStore;
|
||||
TC_GAME_API extern DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore;
|
||||
TC_GAME_API extern DBCStorage <SkillLineEntry> sSkillLineStore;
|
||||
|
||||
@@ -74,6 +74,13 @@ struct AchievementCriteriaEntry
|
||||
uint64 winCount; // 4
|
||||
} win_bg;
|
||||
|
||||
// ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS = 3
|
||||
struct
|
||||
{
|
||||
uint32 unused; // 3
|
||||
uint32 count; // 4
|
||||
} archaeology;
|
||||
|
||||
// ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL = 5
|
||||
// ACHIEVEMENT_CRITERIA_TYPE_REACH_GUILD_LEVEL = 125
|
||||
struct
|
||||
@@ -1782,6 +1789,22 @@ struct QuestFactionRewEntry
|
||||
int32 QuestRewFactionValue[10];
|
||||
};
|
||||
|
||||
struct QuestPOIBlobEntry
|
||||
{
|
||||
uint32 id; // 0 m_id
|
||||
uint32 type; // 1 m_type
|
||||
uint32 mapId; // 2 m_mapId
|
||||
uint32 unk; // 3 m_unk
|
||||
};
|
||||
|
||||
struct QuestPOIPointEntry
|
||||
{
|
||||
uint32 id; // 0 m_id
|
||||
int32 x; // 1 m_zoneX
|
||||
int32 y; // 2 m_zoneY
|
||||
uint32 blobId; // 3 m_blobId
|
||||
};
|
||||
|
||||
struct RandomPropertiesPointsEntry
|
||||
{
|
||||
//uint32 Id; // 0 hidden key
|
||||
@@ -1791,6 +1814,59 @@ struct RandomPropertiesPointsEntry
|
||||
uint32 UncommonPropertiesPoints[5]; // 12-16
|
||||
};
|
||||
|
||||
// ResearchBranch.dbc
|
||||
struct ResearchBranchEntry
|
||||
{
|
||||
uint32 ID;
|
||||
char* Name;
|
||||
uint32 FieldID;
|
||||
uint32 CurrencyID;
|
||||
char* Icon;
|
||||
uint32 ItemID;
|
||||
};
|
||||
|
||||
// ResearchField.dbc
|
||||
struct ResearchFieldEntry
|
||||
{
|
||||
uint32 ID;
|
||||
char* Name;
|
||||
uint32 Unk3; //Unknown?
|
||||
};
|
||||
|
||||
// ResearchProject.dbc
|
||||
struct ResearchProjectEntry
|
||||
{
|
||||
uint32 ID;
|
||||
char* Name;
|
||||
char* Description;
|
||||
uint32 hasReward;
|
||||
uint32 ResearchBranchID;
|
||||
uint32 ProjectSpell;
|
||||
uint32 Complexity;
|
||||
char* Path;
|
||||
uint32 RequiredFragments;
|
||||
};
|
||||
|
||||
// ResearchSite.dbc
|
||||
struct ResearchSiteEntry
|
||||
{
|
||||
uint32 ID;
|
||||
uint32 MapId;
|
||||
uint32 QuestPOI;
|
||||
char* Name;
|
||||
char* Flags;
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return ID != 140 && // template
|
||||
ID != 142 && // template
|
||||
ID != 161 && // template
|
||||
ID != 471 && // Vashj'ir
|
||||
ID != 473 && // Vashj'ir
|
||||
ID != 475; // Vashj'ir
|
||||
}
|
||||
};
|
||||
|
||||
struct ScalingStatDistributionEntry
|
||||
{
|
||||
uint32 Id; // 0
|
||||
@@ -2022,7 +2098,7 @@ struct SpellEntry
|
||||
uint32 SpellShapeshiftId; // 44 SpellShapeshift.dbc
|
||||
uint32 SpellTargetRestrictionsId; // 45 SpellTargetRestrictions.dbc
|
||||
uint32 SpellTotemsId; // 46 SpellTotems.dbc
|
||||
//uint32 ResearchProject; // 47 ResearchProject.dbc
|
||||
uint32 ResearchProjectId; // 47 ResearchProject.dbc
|
||||
};
|
||||
|
||||
// SpellCategories.dbc
|
||||
|
||||
@@ -119,11 +119,17 @@ char const NameGenfmt[] = "dsii";
|
||||
char const NumTalentsAtLevelfmt[] = "df";
|
||||
char const OverrideSpellDatafmt[] = "niiiiiiiiiixx";
|
||||
char const QuestFactionRewardfmt[] = "niiiiiiiiii";
|
||||
const char QuestPOIBlobfmt[] = "niii";
|
||||
const char QuestPOIPointfmt[] = "niii";
|
||||
char const QuestSortEntryfmt[] = "nx";
|
||||
char const QuestXPfmt[] = "niiiiiiiiii";
|
||||
char const PowerDisplayfmt[] = "nixxxx";
|
||||
char const PvPDifficultyfmt[] = "diiiii";
|
||||
char const RandomPropertiesPointsfmt[] = "niiiiiiiiiiiiiii";
|
||||
char const ResearchBranchEntryfmt[] = "nsiisi";
|
||||
char const ResearchFieldEntryfmt[] = "nsi";
|
||||
char const ResearchProjectEntryfmt[] = "nssiiiisi";
|
||||
char const ResearchSiteEntryfmt[] = "niiss";
|
||||
char const ScalingStatDistributionfmt[] = "niiiiiiiiiiiiiiiiiiiixi";
|
||||
char const ScalingStatValuesfmt[] = "iniiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii";
|
||||
char const SkillLinefmt[] = "nisxixi";
|
||||
@@ -143,7 +149,7 @@ char const SpellEffectEntryfmt[] = "nifiiiffiiiiiifiifiiiiiiiix";
|
||||
const std::string CustomSpellEffectEntryfmt = "ppppppppppppppappppppppppp";
|
||||
const std::string CustomSpellEffectEntryIndex = "Id";
|
||||
// 0 10 20 30 40 47
|
||||
char const SpellEntryfmt[] = "niiiiiiiiiiiiiiifiiiissxxiixxifiiiiiiixiiiiiiiix";
|
||||
char const SpellEntryfmt[] = "niiiiiiiiiiiiiiifiiiissxxiixxifiiiiiiixiiiiiiiii";
|
||||
const std::string CustomSpellEntryfmt = "ppppppppppppppapaaaaaaaaapaaaaaapapppaapppaaapa";
|
||||
const std::string CustomSpellEntryIndex = "Id";
|
||||
char const SpellFocusObjectfmt[] = "nx";
|
||||
|
||||
@@ -807,6 +807,11 @@ void GameObject::getFishLootJunk(Loot* fishloot, Player* loot_owner)
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::getArchaeologyLoot(Loot* loot, Player* loot_owner)
|
||||
{
|
||||
loot->AddCurrency(sArchaeologyMgr->GetFindCurrency(GetEntry()), 4, 9);
|
||||
}
|
||||
|
||||
void GameObject::SaveToDB()
|
||||
{
|
||||
// this should only be used when the gameobject has already been loaded
|
||||
|
||||
@@ -776,6 +776,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
|
||||
void SendGameObjectDespawn();
|
||||
void getFishLoot(Loot* loot, Player* loot_owner);
|
||||
void getFishLootJunk(Loot* loot, Player* loot_owner);
|
||||
void getArchaeologyLoot(Loot* loot, Player* loot_owner);
|
||||
GameobjectTypes GetGoType() const { return GameobjectTypes(GetByteValue(GAMEOBJECT_BYTES_1, 1)); }
|
||||
void SetGoType(GameobjectTypes type) { SetByteValue(GAMEOBJECT_BYTES_1, 1, type); }
|
||||
GOState GetGoState() const { return GOState(GetByteValue(GAMEOBJECT_BYTES_1, 0)); }
|
||||
|
||||
@@ -240,6 +240,7 @@ enum CurrencyFlags
|
||||
enum CurrencyCategory
|
||||
{
|
||||
// ...
|
||||
CURRENCY_CATEGORY_ARCHAEOLOGY = 82,
|
||||
CURRENCY_CATEGORY_META_CONQUEST = 89,
|
||||
// ...
|
||||
};
|
||||
|
||||
@@ -504,8 +504,8 @@ enum EPlayerFields
|
||||
PLAYER_FIELD_GLYPHS_1 = UNIT_END + 0x04B2, // Size: 9, Type: INT, Flags: PRIVATE
|
||||
PLAYER_GLYPHS_ENABLED = UNIT_END + 0x04BB, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_PET_SPELL_POWER = UNIT_END + 0x04BC, // Size: 1, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_RESEARCHING_1 = UNIT_END + 0x04BD, // Size: 8, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_FIELD_RESERACH_SITE_1 = UNIT_END + 0x04C5, // Size: 8, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_FIELD_RESEARCH_PROJECT_1 = UNIT_END + 0x04BD, // Size: 8, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_FIELD_RESEARCH_SITE_1 = UNIT_END + 0x04C5, // Size: 8, Type: TWO_SHORT, Flags: PRIVATE
|
||||
PLAYER_PROFESSION_SKILL_LINE_1 = UNIT_END + 0x04CD, // Size: 2, Type: INT, Flags: PRIVATE
|
||||
PLAYER_FIELD_UI_HIT_MODIFIER = UNIT_END + 0x04CF, // Size: 1, Type: FLOAT, Flags: PRIVATE
|
||||
PLAYER_FIELD_UI_SPELL_HIT_MODIFIER = UNIT_END + 0x04D0, // Size: 1, Type: FLOAT, Flags: PRIVATE
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "Player.h"
|
||||
#include "AccountMgr.h"
|
||||
#include "AchievementMgr.h"
|
||||
#include "Archaeology.h"
|
||||
#include "ArenaTeam.h"
|
||||
#include "ArenaTeamMgr.h"
|
||||
#include "Battlefield.h"
|
||||
@@ -303,7 +304,7 @@ std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi)
|
||||
return ss;
|
||||
}
|
||||
|
||||
Player::Player(WorldSession* session): Unit(true)
|
||||
Player::Player(WorldSession* session): Unit(true), _archaeology(this)
|
||||
{
|
||||
m_speakTime = 0;
|
||||
m_speakCount = 0;
|
||||
@@ -5668,6 +5669,10 @@ bool Player::UpdateSkill(uint32 skill_id, uint32 step)
|
||||
|
||||
UpdateSkillEnchantments(skill_id, value, new_value);
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, skill_id);
|
||||
|
||||
if (skill_id == SKILL_ARCHAEOLOGY)
|
||||
_archaeology.Update();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5727,6 +5732,8 @@ bool Player::UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLeve
|
||||
// For skinning and Mining chance decrease with level. 1-74 - no decrease, 75-149 - 2 times, 225-299 - 8 times
|
||||
switch (SkillId)
|
||||
{
|
||||
case SKILL_ARCHAEOLOGY:
|
||||
return UpdateSkillPro(SkillId, ((SkillValue < 50) ? 1000 : 0) * Multiplicator, gathering_skill_gain);
|
||||
case SKILL_HERBALISM:
|
||||
case SKILL_LOCKPICKING:
|
||||
case SKILL_JEWELCRAFTING:
|
||||
@@ -5962,6 +5969,10 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal)
|
||||
if (newVal > currVal)
|
||||
UpdateSkillEnchantments(id, currVal, newVal);
|
||||
|
||||
// archaeology skill updated
|
||||
if (id == SKILL_ARCHAEOLOGY)
|
||||
_archaeology.Update();
|
||||
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL, id);
|
||||
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL, id);
|
||||
}
|
||||
@@ -5994,6 +6005,10 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal)
|
||||
SetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1, 0);
|
||||
else if (GetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1 + 1) == id)
|
||||
SetUInt32Value(PLAYER_PROFESSION_SKILL_LINE_1 + 1, 0);
|
||||
|
||||
// archaeology skill unlearned
|
||||
if (id == SKILL_ARCHAEOLOGY)
|
||||
_archaeology.UnLearn();
|
||||
}
|
||||
}
|
||||
else if (newVal) //add
|
||||
@@ -6057,6 +6072,10 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal)
|
||||
// Learn all spells for skill
|
||||
LearnSkillRewardedSpells(id, newVal);
|
||||
return;
|
||||
|
||||
// archaeology skill learned
|
||||
if (id == SKILL_ARCHAEOLOGY)
|
||||
_archaeology.Learn();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7141,6 +7160,10 @@ void Player::ModifyCurrency(uint32 id, int32 count, bool printLog/* = true*/, bo
|
||||
return;
|
||||
}
|
||||
|
||||
if (itr->second.state == PLAYERCURRENCY_NEW && HasSkill(SKILL_ARCHAEOLOGY) &&
|
||||
currency->Category == CURRENCY_CATEGORY_ARCHAEOLOGY)
|
||||
_archaeology.ActivateBranch(sArchaeologyMgr->Currency2BranchId(currency->ID));
|
||||
|
||||
WorldPacket packet(SMSG_UPDATE_CURRENCY, 12);
|
||||
|
||||
packet.WriteBit(weekCap != 0);
|
||||
@@ -8581,6 +8604,8 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
|
||||
go->getFishLoot(loot, this);
|
||||
else if (loot_type == LOOT_FISHING_JUNK)
|
||||
go->getFishLootJunk(loot, this);
|
||||
else if (loot_type == LOOT_ARCHAEOLOGY)
|
||||
go->getArchaeologyLoot(loot, this);
|
||||
|
||||
if (go->GetGOInfo()->type == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.groupLootRules)
|
||||
{
|
||||
@@ -8844,7 +8869,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
|
||||
{
|
||||
SetLootGUID(guid);
|
||||
|
||||
WorldPacket data(SMSG_LOOT_RESPONSE, (9 + 50)); // we guess size
|
||||
WorldPacket data(SMSG_LOOT_RESPONSE, 8 + 1 + 50 + 1 + 1); // we guess size
|
||||
data << uint64(guid);
|
||||
data << uint8(loot_type);
|
||||
data << LootView(*loot, this, permission);
|
||||
@@ -8884,9 +8909,9 @@ void Player::SendNotifyLootItemRemoved(uint8 lootSlot) const
|
||||
|
||||
void Player::SendNotifyCurrencyLootRemoved(uint8 lootSlot)
|
||||
{
|
||||
WorldPacket data(SMSG_CURRENCY_LOOT_REMOVED, 1);
|
||||
data << uint8(lootSlot);
|
||||
GetSession()->SendPacket(&data);
|
||||
WorldPacket data(SMSG_CURRENCY_LOOT_REMOVED, 1);
|
||||
data << uint8(lootSlot);
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void Player::SendUpdateWorldState(uint32 Field, uint32 Value) const
|
||||
@@ -25210,6 +25235,21 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot)
|
||||
SendEquipError(msg, nullptr, nullptr, item->itemid);
|
||||
}
|
||||
|
||||
|
||||
void Player::StoreLootCurrency(uint8 lootSlot, Loot* loot)
|
||||
{
|
||||
LootCurrency* currency = loot->LootCurrencyInSlot(lootSlot, this);
|
||||
|
||||
if (!currency)
|
||||
{
|
||||
SendEquipError(EQUIP_ERR_LOOT_GONE, nullptr, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
loot->NotifyCurrencyRemoved(lootSlot);
|
||||
ModifyCurrency(currency->id, currency->count);
|
||||
}
|
||||
|
||||
uint32 Player::CalculateTalentsPoints() const
|
||||
{
|
||||
// this dbc file has entries only up to level 100
|
||||
@@ -25360,6 +25400,9 @@ void Player::_LoadSkills(PreparedQueryResult result)
|
||||
mSkillStatus.insert(SkillStatusMap::value_type(skill, SkillStatusData(count, SKILL_UNCHANGED)));
|
||||
loadedSkillValues[skill] = value;
|
||||
|
||||
if (skill == SKILL_ARCHAEOLOGY)
|
||||
_archaeology.Initialize();
|
||||
|
||||
++count;
|
||||
|
||||
if (count >= PLAYER_MAX_SKILLS) // client limit
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "GroupReference.h"
|
||||
#include "MapReference.h"
|
||||
|
||||
#include "Archaeology.h"
|
||||
#include "Item.h"
|
||||
#include "PetDefines.h"
|
||||
#include "QuestDef.h"
|
||||
@@ -58,6 +59,7 @@ class PlayerSocial;
|
||||
class SpellCastTargets;
|
||||
class UpdateMask;
|
||||
class PlayerAI;
|
||||
class Archaeology;
|
||||
|
||||
struct CharacterCustomizeInfo;
|
||||
|
||||
@@ -1410,6 +1412,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
void AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore const& store, bool broadcast = false);
|
||||
void AutoStoreLoot(uint32 loot_id, LootStore const& store, bool broadcast = false) { AutoStoreLoot(NULL_BAG, NULL_SLOT, loot_id, store, broadcast); }
|
||||
void StoreLootItem(uint8 lootSlot, Loot* loot);
|
||||
void StoreLootCurrency(uint8 lootSlot, Loot* loot);
|
||||
|
||||
InventoryResult CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count = NULL, uint32* itemLimitCategory = NULL) const;
|
||||
InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 entry, uint32 count, Item* pItem = NULL, bool swap = false, uint32* no_space_count = NULL) const;
|
||||
@@ -1953,6 +1956,13 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
bool UpdateGatherSkill(uint32 SkillId, uint32 SkillValue, uint32 RedLevel, uint32 Multiplicator = 1);
|
||||
bool UpdateFishingSkill();
|
||||
|
||||
inline void SurveyDigSite() { _archaeology.UseSite(); }
|
||||
inline void NotifyRequestResearchHistory() { _archaeology.SendResearchHistory(); }
|
||||
inline bool ArchProjectCompleteable(uint32 projectId) { return _archaeology.ProjectCompleteable(uint16(projectId)); }
|
||||
inline bool HasArchProject(uint32 projectId) { return _archaeology.ProjectExists(uint16(projectId)); }
|
||||
inline void CompleteArchProject(uint32 projectId) { _archaeology.CompleteProject(uint16(projectId)); }
|
||||
inline void SetArchData(struct ArchData *data) { _archaeology.SetArchData(data); }
|
||||
|
||||
float GetHealthBonusFromStamina();
|
||||
float GetManaBonusFromIntellect();
|
||||
|
||||
@@ -2887,6 +2897,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
uint32 manaBeforeDuel;
|
||||
|
||||
WorldLocation _corpseLocation;
|
||||
|
||||
Archaeology _archaeology;
|
||||
};
|
||||
|
||||
TC_GAME_API void AddItemsSetItem(Player* player, Item* item);
|
||||
|
||||
@@ -136,7 +136,7 @@ void WorldSession::HandleLootCurrencyOpcode(WorldPacket& recvData)
|
||||
return;
|
||||
}
|
||||
|
||||
loot->NotifyCurrencyRemoved(lootSlot);
|
||||
player->StoreLootCurrency(lootSlot, loot);
|
||||
}
|
||||
|
||||
void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/)
|
||||
|
||||
@@ -2096,3 +2096,9 @@ void WorldSession::SendStreamingMovie()
|
||||
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
void WorldSession::HandleRequestResearchHistory(WorldPacket & /*recv_data*/)
|
||||
{
|
||||
if (Player* player = GetPlayer())
|
||||
player->NotifyRequestResearchHistory();
|
||||
}
|
||||
@@ -54,7 +54,8 @@ void WorldSession::HandleClientCastFlags(WorldPacket& recvPacket, uint8 castFlag
|
||||
}
|
||||
else if (castFlags & 0x8) // Archaeology
|
||||
{
|
||||
uint32 count, entry, usedCount;
|
||||
ArchData* archData = new ArchData();
|
||||
uint32 count;
|
||||
uint8 type;
|
||||
recvPacket >> count;
|
||||
for (uint32 i = 0; i < count; ++i)
|
||||
@@ -63,15 +64,17 @@ void WorldSession::HandleClientCastFlags(WorldPacket& recvPacket, uint8 castFlag
|
||||
switch (type)
|
||||
{
|
||||
case 2: // Keystones
|
||||
recvPacket >> entry; // Item id
|
||||
recvPacket >> usedCount; // Item count
|
||||
recvPacket >> archData->keyId; // Item id
|
||||
recvPacket >> archData->keyCount; // Item count
|
||||
break;
|
||||
case 1: // Fragments
|
||||
recvPacket >> entry; // Currency id
|
||||
recvPacket >> usedCount; // Currency count
|
||||
recvPacket >> archData->fragId; // Currency id
|
||||
recvPacket >> archData->fragCount; // Currency count
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (Player* player = GetPlayer())
|
||||
player->SetArchData(archData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,7 +392,8 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
|
||||
caster = _player;
|
||||
}
|
||||
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellInfo->Id) && !spellInfo->IsRaidMarker())
|
||||
if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellInfo->Id) && !spellInfo->IsRaidMarker() &&
|
||||
!caster->ToPlayer()->HasArchProject(spellInfo->ResearchProjectId))
|
||||
{
|
||||
// not have spell in spellbook
|
||||
recvPacket.rfinish(); // prevent spam at ignore packet
|
||||
|
||||
@@ -440,6 +440,27 @@ void Loot::AddItem(LootStoreItem const& item)
|
||||
}
|
||||
}
|
||||
|
||||
void Loot::AddCurrency(uint32 entry, uint32 min, uint32 max)
|
||||
{
|
||||
uint32 amount = urand(min, max);
|
||||
|
||||
currencies.push_back(LootCurrency(entry, amount));
|
||||
|
||||
unlootedCurrency++;
|
||||
}
|
||||
|
||||
LootCurrency* Loot::LootCurrencyInSlot(uint32 lootSlot, Player* player)
|
||||
{
|
||||
if (currencies[lootSlot].looted)
|
||||
return NULL;
|
||||
|
||||
currencies[lootSlot].looted = true;
|
||||
|
||||
unlootedCurrency--;
|
||||
|
||||
return &(currencies[lootSlot]);
|
||||
}
|
||||
|
||||
// Calls processor of corresponding LootTemplate (which handles everything including references)
|
||||
bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bool personal, bool noEmptyError, uint16 lootMode /*= LOOT_MODE_DEFAULT*/)
|
||||
{
|
||||
@@ -1104,6 +1125,19 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv)
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8 i = 0; i < l.currencies.size(); ++i)
|
||||
{
|
||||
if (l.currencies[i].count == 0 || l.currencies[i].id == 0 || l.currencies[i].looted)
|
||||
continue;
|
||||
|
||||
l.currencies[i].index = currenciesShown + itemsShown;
|
||||
|
||||
b << uint8(l.currencies[i].index);
|
||||
b << uint32(l.currencies[i].id);
|
||||
b << uint32(l.currencies[i].count);
|
||||
++currenciesShown;
|
||||
}
|
||||
|
||||
//update number of items and currencies shown
|
||||
b.put<uint8>(count_pos, itemsShown);
|
||||
b.put<uint8>(currency_count_pos, currenciesShown);
|
||||
|
||||
@@ -87,6 +87,8 @@ enum LootType : uint8
|
||||
LOOT_PROSPECTING = 7,
|
||||
LOOT_MILLING = 8,
|
||||
|
||||
LOOT_ARCHAEOLOGY = 10,
|
||||
|
||||
LOOT_FISHINGHOLE = 20, // unsupported by client, sending LOOT_FISHING instead
|
||||
LOOT_INSIGNIA = 21, // unsupported by client, sending LOOT_CORPSE instead
|
||||
LOOT_FISHING_JUNK = 22 // unsupported by client, sending LOOT_FISHING instead
|
||||
@@ -193,6 +195,20 @@ struct NotNormalLootItem
|
||||
: index(_index), is_looted(_islooted) { }
|
||||
};
|
||||
|
||||
struct LootCurrency
|
||||
{
|
||||
uint8 index;
|
||||
uint32 id;
|
||||
uint32 count;
|
||||
bool looted;
|
||||
|
||||
LootCurrency()
|
||||
: index(0), id(0), count(0), looted(false) { }
|
||||
|
||||
LootCurrency(uint32 _id, uint32 _count)
|
||||
: index(0), id(_id), count(_count), looted(false) { }
|
||||
};
|
||||
|
||||
struct Loot;
|
||||
class LootTemplate;
|
||||
|
||||
@@ -316,8 +332,11 @@ struct TC_GAME_API Loot
|
||||
|
||||
std::vector<LootItem> items;
|
||||
std::vector<LootItem> quest_items;
|
||||
std::vector<LootCurrency> currencies;
|
||||
|
||||
uint32 gold;
|
||||
uint8 unlootedCount;
|
||||
uint8 unlootedCurrency;
|
||||
ObjectGuid roundRobinPlayer; // GUID of the player having the Round-Robin ownership for the loot. If 0, round robin owner has released.
|
||||
LootType loot_type; // required for achievement system
|
||||
uint8 maxDuplicates; // Max amount of items with the same entry that can drop (default is 1; on 25 man raid mode 3)
|
||||
@@ -326,7 +345,7 @@ struct TC_GAME_API Loot
|
||||
// Only set for inventory items that can be right-click looted
|
||||
uint32 containerID;
|
||||
|
||||
Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), roundRobinPlayer(), loot_type(LOOT_CORPSE), maxDuplicates(1), containerID(0) { }
|
||||
Loot(uint32 _gold = 0) : gold(_gold), unlootedCount(0), roundRobinPlayer(), unlootedCurrency(0), loot_type(LOOT_CORPSE), maxDuplicates(1), containerID(0) { }
|
||||
~Loot() { clear(); }
|
||||
|
||||
// For deleting items at loot removal since there is no backward interface to the Item()
|
||||
@@ -359,13 +378,14 @@ struct TC_GAME_API Loot
|
||||
quest_items.clear();
|
||||
gold = 0;
|
||||
unlootedCount = 0;
|
||||
unlootedCurrency = 0;
|
||||
roundRobinPlayer.Clear();
|
||||
loot_type = LOOT_NONE;
|
||||
i_LootValidatorRefManager.clearReferences();
|
||||
}
|
||||
|
||||
bool empty() const { return items.empty() && gold == 0; }
|
||||
bool isLooted() const { return gold == 0 && unlootedCount == 0; }
|
||||
bool isLooted() const { return gold == 0 && unlootedCount == 0 && unlootedCurrency == 0; }
|
||||
|
||||
void NotifyItemRemoved(uint8 lootIndex);
|
||||
void NotifyQuestItemRemoved(uint8 questIndex);
|
||||
@@ -386,6 +406,9 @@ struct TC_GAME_API Loot
|
||||
bool hasItemFor(Player* player) const;
|
||||
bool hasOverThresholdItem() const;
|
||||
|
||||
void AddCurrency(uint32 entry, uint32 min, uint32 max);
|
||||
LootCurrency* LootCurrencyInSlot(uint32 lootSlot, Player* player);
|
||||
|
||||
private:
|
||||
void FillNotNormalLootFor(Player* player, bool presentAtLooting);
|
||||
NotNormalLootItemList* FillFFALoot(Player* player);
|
||||
|
||||
@@ -780,7 +780,7 @@ enum TrinityStrings
|
||||
LANG_NEED_CHARACTER_NAME = 807,
|
||||
LANG_PLAYER_NOT_EXIST_OR_OFFLINE = 808,
|
||||
LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND = 809,
|
||||
// unused = 810,
|
||||
LANG_YOU_CANT_USE_THAT_HERE = 810,
|
||||
LANG_GUILD_MASTER = 811,
|
||||
LANG_GUILD_OFFICER = 812,
|
||||
LANG_GUILD_VETERAN = 813,
|
||||
|
||||
@@ -2948,7 +2948,8 @@ enum LockType
|
||||
LOCKTYPE_SLOW_CLOSE = 18,
|
||||
LOCKTYPE_FISHING = 19,
|
||||
LOCKTYPE_INSCRIPTION = 20,
|
||||
LOCKTYPE_OPEN_FROM_VEHICLE = 21
|
||||
LOCKTYPE_OPEN_FROM_VEHICLE = 21,
|
||||
LOCKTYPE_ARCHAEOLOGY = 22,
|
||||
};
|
||||
|
||||
enum TrainerType // this is important type for npcs!
|
||||
@@ -3415,6 +3416,7 @@ inline SkillType SkillByLockType(LockType locktype)
|
||||
case LOCKTYPE_MINING: return SKILL_MINING;
|
||||
case LOCKTYPE_FISHING: return SKILL_FISHING;
|
||||
case LOCKTYPE_INSCRIPTION: return SKILL_INSCRIPTION;
|
||||
case LOCKTYPE_ARCHAEOLOGY: return SKILL_ARCHAEOLOGY;
|
||||
default: break;
|
||||
}
|
||||
return SKILL_NONE;
|
||||
|
||||
@@ -460,7 +460,7 @@ void OpcodeTable::Initialize()
|
||||
DEFINE_OPCODE_HANDLER(CMSG_REQUEST_RAID_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestRaidInfoOpcode );
|
||||
DEFINE_OPCODE_HANDLER(CMSG_REQUEST_RATED_BG_INFO, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleRequestRatedBgInfo );
|
||||
DEFINE_OPCODE_HANDLER(CMSG_REQUEST_RATED_BG_STATS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleRequestRatedBgStats );
|
||||
DEFINE_OPCODE_HANDLER(CMSG_REQUEST_RESEARCH_HISTORY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL );
|
||||
DEFINE_OPCODE_HANDLER(CMSG_REQUEST_RESEARCH_HISTORY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestResearchHistory );
|
||||
DEFINE_OPCODE_HANDLER(CMSG_REQUEST_VEHICLE_EXIT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRequestVehicleExit );
|
||||
DEFINE_OPCODE_HANDLER(CMSG_REQUEST_VEHICLE_NEXT_SEAT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChangeSeatsOnControlledVehicle);
|
||||
DEFINE_OPCODE_HANDLER(CMSG_REQUEST_VEHICLE_PREV_SEAT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleChangeSeatsOnControlledVehicle);
|
||||
|
||||
@@ -1077,6 +1077,7 @@ class TC_GAME_API WorldSession
|
||||
void HandleObjectUpdateFailedOpcode(WorldPacket& recvPacket);
|
||||
void HandleRequestCategoryCooldowns(WorldPacket& recvPacket);
|
||||
void SendStreamingMovie();
|
||||
void HandleRequestResearchHistory(WorldPacket& recv_data);
|
||||
int32 HandleEnableNagleAlgorithm();
|
||||
|
||||
public:
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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 "Archaeology.h"
|
||||
#include "DBCStore.h"
|
||||
#include "Player.h"
|
||||
|
||||
Archaeology::Archaeology(Player* player): _player(player)
|
||||
{
|
||||
memset(_site, 0, sizeof(struct SiteData) * CONTINENT_SITES * COUNT_CONT);
|
||||
|
||||
_continentState[CONT_EASTERN] = STATE_NULL;
|
||||
_continentState[CONT_KALIMDOR] = STATE_NULL;
|
||||
_continentState[CONT_OUTLAND] = STATE_NULL;
|
||||
_continentState[CONT_NORTHREND] = STATE_NULL;
|
||||
}
|
||||
|
||||
void Archaeology::Initialize()
|
||||
{
|
||||
if (!_player || !_player->HasSkill(SKILL_ARCHAEOLOGY))
|
||||
return;
|
||||
|
||||
LoadSitesFromDB();
|
||||
VerifySites();
|
||||
|
||||
LoadCompletedProjectsFromDB();
|
||||
LoadCurrentProjectsFromDB();
|
||||
VerifyProjects();
|
||||
}
|
||||
|
||||
void Archaeology::Learn()
|
||||
{
|
||||
_continentState[CONT_EASTERN] = STATE_USE;
|
||||
_continentState[CONT_KALIMDOR] = STATE_USE;
|
||||
_continentState[CONT_OUTLAND] = STATE_NULL;
|
||||
_continentState[CONT_NORTHREND] = STATE_NULL;
|
||||
RegenerateAllSites();
|
||||
|
||||
InitBranches();
|
||||
VerifyProjects();
|
||||
}
|
||||
|
||||
void Archaeology::UnLearn()
|
||||
{
|
||||
_continentState[CONT_EASTERN] = STATE_NULL;
|
||||
_continentState[CONT_KALIMDOR] = STATE_NULL;
|
||||
_continentState[CONT_OUTLAND] = STATE_NULL;
|
||||
_continentState[CONT_NORTHREND] = STATE_NULL;
|
||||
RegenerateAllSites();
|
||||
|
||||
CleanProjects();
|
||||
}
|
||||
|
||||
void Archaeology::Update()
|
||||
{
|
||||
uint16 skillValue = _player->GetSkillValue(SKILL_ARCHAEOLOGY);
|
||||
|
||||
if (SKILL_OUTLAND <= skillValue && _continentState[CONT_OUTLAND] == STATE_NULL)
|
||||
{
|
||||
_continentState[CONT_OUTLAND] = STATE_USE;
|
||||
RegenerateContinent(CONT_OUTLAND);
|
||||
}
|
||||
|
||||
if(SKILL_NORTHREND <= skillValue && _continentState[CONT_NORTHREND] == STATE_NULL)
|
||||
{
|
||||
_continentState[CONT_NORTHREND] = STATE_USE;
|
||||
RegenerateContinent(CONT_NORTHREND);
|
||||
}
|
||||
|
||||
if(SKILL_CATA <= skillValue)
|
||||
{
|
||||
_continentState[CONT_EASTERN] = STATE_EXT;
|
||||
_continentState[CONT_KALIMDOR] = STATE_EXT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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 _ARCHAEOLOGY_H
|
||||
#define _ARCHAEOLOGY_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "WorldSession.h"
|
||||
#include "ArchaeologyMgr.h"
|
||||
|
||||
#define DIGS_PER_SITE 3
|
||||
class Player;
|
||||
|
||||
struct ArchData
|
||||
{
|
||||
ArchData() : fragId(0), fragCount(0), keyId(0), keyCount(0) { }
|
||||
|
||||
uint32 fragId;
|
||||
uint32 fragCount;
|
||||
uint32 keyId;
|
||||
uint32 keyCount;
|
||||
};
|
||||
|
||||
enum ContinentState
|
||||
{
|
||||
STATE_NULL = 0,
|
||||
STATE_USE = 1,
|
||||
STATE_EXT = 2,
|
||||
};
|
||||
|
||||
class Archaeology
|
||||
{
|
||||
public:
|
||||
Archaeology(Player* player);
|
||||
|
||||
void Initialize();
|
||||
|
||||
void Learn();
|
||||
void UnLearn();
|
||||
void Update();
|
||||
|
||||
void UseSite();
|
||||
|
||||
void SendResearchHistory();
|
||||
|
||||
void ActivateBranch(uint8 branchId, bool force = false);
|
||||
bool ProjectCompleteable(uint16 projectId);
|
||||
bool ProjectExists(uint16 projectId);
|
||||
|
||||
void CompleteProject(uint16 projectId);
|
||||
void SetArchData(struct ArchData *data)
|
||||
{
|
||||
ASSERT(data);
|
||||
archData = data;
|
||||
}
|
||||
|
||||
private:
|
||||
Player* _player;
|
||||
ArchData *archData;
|
||||
|
||||
// Site Functionality
|
||||
ContinentState _continentState[4];
|
||||
SiteData _site[CONTINENT_SITES * COUNT_CONT];
|
||||
|
||||
void LoadSitesFromDB();
|
||||
void VerifySites();
|
||||
|
||||
Continent GetContinent();
|
||||
uint32 GetNearestSite(float &distance);
|
||||
void SetSite(uint32 posi, uint16 entry, uint32 state = 0);
|
||||
void RegeneratePosition(uint32 position, Continent continent);
|
||||
void RegenerateContinent(Continent continent);
|
||||
void RegenerateAllSites();
|
||||
|
||||
// Project Functionality
|
||||
std::map<uint16, std::pair<int32, int32> > _completedProjects;
|
||||
std::map<uint8, BranchData> _branches;
|
||||
|
||||
void LoadCompletedProjectsFromDB();
|
||||
void LoadCurrentProjectsFromDB();
|
||||
void InitBranches();
|
||||
void VerifyProjects();
|
||||
void CleanProjects();
|
||||
|
||||
void RegenerateBranch(uint8 branch);
|
||||
void VisualizeBranch(uint8 position, uint16 project);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,380 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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 "ArchaeologyMgr.h"
|
||||
#include "DBCStores.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Timer.h"
|
||||
|
||||
namespace archaeology
|
||||
{
|
||||
|
||||
ArchaeologyMgr::ArchaeologyMgr()
|
||||
{
|
||||
}
|
||||
|
||||
ArchaeologyMgr::~ArchaeologyMgr()
|
||||
{
|
||||
}
|
||||
|
||||
ArchaeologyMgr* ArchaeologyMgr::instance()
|
||||
{
|
||||
static ArchaeologyMgr instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
void ArchaeologyMgr::LoadData()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
std::list<std::pair<uint16, uint32> > sites;
|
||||
|
||||
QueryResult result = WorldDatabase.Query("SELECT Id, MapId, QuestPOI, ReqSkill, MinLevel, GameobjectEntry FROM archaeology_sites");
|
||||
|
||||
if (!result)
|
||||
{
|
||||
TC_LOG_INFO("server.loading", ">> Loaded 0 archaeology sites. DB table `archaeology_site` is empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 count = 0;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
SiteEntry entry;
|
||||
entry.id = fields[0].GetUInt16();
|
||||
entry.mapId = fields[1].GetUInt32();
|
||||
entry.questPOI = fields[2].GetUInt16();
|
||||
entry.reqSkill = fields[3].GetUInt32();
|
||||
entry.minLevel = fields[4].GetUInt32();
|
||||
_objectMap[entry.id] = fields[5].GetUInt32();
|
||||
|
||||
switch (entry.mapId)
|
||||
{
|
||||
case 0:
|
||||
_siteMap[CONT_EASTERN + COUNT_CONT].push_back(entry);
|
||||
|
||||
if (entry.reqSkill < 450)
|
||||
_siteMap[CONT_EASTERN].push_back(entry);
|
||||
break;
|
||||
case 1:
|
||||
_siteMap[CONT_KALIMDOR + COUNT_CONT].push_back(entry);
|
||||
|
||||
if (entry.reqSkill < 450)
|
||||
_siteMap[CONT_KALIMDOR].push_back(entry);
|
||||
break;
|
||||
case 530:
|
||||
_siteMap[CONT_OUTLAND].push_back(entry);
|
||||
break;
|
||||
case 571:
|
||||
_siteMap[CONT_NORTHREND].push_back(entry);
|
||||
break;
|
||||
}
|
||||
|
||||
sites.push_back(std::pair<uint16, uint32>(entry.id, entry.questPOI));
|
||||
++count;
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u archaeology sites in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
|
||||
oldMSTime = getMSTime();
|
||||
count = 0;
|
||||
|
||||
for (uint32 i = 0; i < sQuestPOIPointStore.GetNumRows(); i++)
|
||||
{
|
||||
const QuestPOIPointEntry* entry = sQuestPOIPointStore.LookupEntry(i);
|
||||
if (!entry)
|
||||
continue;
|
||||
|
||||
for (std::list<std::pair<uint16, uint32> >::iterator itr = sites.begin(); itr != sites.end();)
|
||||
{
|
||||
if (itr->second == entry->blobId)
|
||||
{
|
||||
uint16 site = itr->first;
|
||||
uint16 poiRel = itr->second;
|
||||
|
||||
if (_polygonMap[site])
|
||||
{
|
||||
TC_LOG_ERROR("server.loading", "Archaeology: Tried to overwrite polygonData of site %u", site);
|
||||
break;
|
||||
}
|
||||
|
||||
// Create Site Polygon
|
||||
_polygonMap[site] = new SitePolygonGraph();
|
||||
_polygonMap[site]->add_node(entry->x, entry->y);
|
||||
|
||||
for (uint32 j = 1; j < 12; j++)
|
||||
{
|
||||
entry = sQuestPOIPointStore.LookupEntry(++i);
|
||||
if (poiRel != entry->blobId)
|
||||
{
|
||||
TC_LOG_ERROR("server.loading", "Archaeology: Tried to use POI %u not related to site %u", entry->id, poiRel);
|
||||
break;
|
||||
}
|
||||
|
||||
// Add new perimeter point
|
||||
_polygonMap[site]->add_node(entry->x, entry->y);
|
||||
}
|
||||
|
||||
// Generate ALL inscribed and boundary geometries for the polygon!
|
||||
_polygonMap[site]->finalize_polygon();
|
||||
|
||||
// NEXT!
|
||||
count++;
|
||||
sites.erase(itr++);
|
||||
}
|
||||
else
|
||||
itr++;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::list<std::pair<uint16, uint32> >::iterator itr = sites.begin(); itr != sites.end(); itr++)
|
||||
TC_LOG_ERROR("player.skills", "Archaeology: SiteEntry:%u links at POIBlob:%u which does not exist", itr->first, itr->second);
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u archaeology site polygons in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
|
||||
oldMSTime = getMSTime();
|
||||
count = 0;
|
||||
|
||||
for (uint32 branchId = 0; branchId < sResearchBranchStore.GetNumRows(); branchId++)
|
||||
if (const ResearchBranchEntry* branchEntry = sResearchBranchStore.LookupEntry(branchId))
|
||||
{
|
||||
if (branchEntry->CurrencyID == 0)
|
||||
continue;
|
||||
|
||||
_currencyMap[branchEntry->CurrencyID] = branchId;
|
||||
|
||||
BranchEntry branch;
|
||||
branch.fieldId = ++count;
|
||||
branch.rareChance = 0;
|
||||
branch.currencyId = branchEntry->CurrencyID;
|
||||
branch.keystoneId = branchEntry->ItemID;
|
||||
_branchMap[branchId] = branch;
|
||||
}
|
||||
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u archaeology branches in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
|
||||
oldMSTime = getMSTime();
|
||||
count = 0;
|
||||
|
||||
std::map<uint8, uint8> rareCount, epicCount;
|
||||
|
||||
result = WorldDatabase.Query("SELECT Entry, Branch, Rarity, ReqSkill, Fragments, Keystone, Spell FROM archaeology_projects");
|
||||
if (!result)
|
||||
{
|
||||
TC_LOG_INFO("server.loading", ">> Loaded 0 archaeology projects. DB table `archaeology_projects` is empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint16 entry = fields[0].GetUInt16();
|
||||
|
||||
ProjectEntry project;
|
||||
project.entry = entry;
|
||||
project.branch = fields[1].GetUInt8();
|
||||
project.rarity = fields[2].GetUInt8();
|
||||
project.reqSkill = fields[3].GetUInt16();
|
||||
project.fragments = fields[4].GetUInt8();
|
||||
project.keystone = fields[5].GetUInt8();
|
||||
project.spell = fields[6].GetUInt32();
|
||||
|
||||
_projects[entry] = project;
|
||||
|
||||
if (ITEM_QUALITY_RARE > project.rarity)
|
||||
_commonProjects[project.branch].push_back(entry);
|
||||
else
|
||||
{
|
||||
_rareProjects[project.branch].push_back(entry);
|
||||
if (project.rarity == ITEM_QUALITY_RARE)
|
||||
rareCount[project.branch]++;
|
||||
else
|
||||
epicCount[project.branch]++;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
while (result->NextRow());
|
||||
TC_LOG_INFO("server.loading", ">> Loaded %u archaeology projects in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
|
||||
oldMSTime = getMSTime();
|
||||
count = 0;
|
||||
|
||||
for (std::map<uint8, BranchEntry>::iterator itr = _branchMap.begin(); itr != _branchMap.end(); ++itr)
|
||||
{
|
||||
uint8 entry = itr->first;
|
||||
float chance = 1.0f;
|
||||
chance -= float(epicCount[entry]) * EPIC_CHANCE;
|
||||
chance /= float(rareCount[entry]);
|
||||
itr->second.rareChance = std::min(chance, MAX_RARE_CHANCE);
|
||||
|
||||
++count;
|
||||
}
|
||||
TC_LOG_INFO("server.loading", ">> Calculated %u archaeology branch chances in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
}
|
||||
|
||||
bool ArchaeologyMgr::isSiteValid(SiteData* sites, uint16 entry)
|
||||
{
|
||||
for (uint32 i = 0; i < CONTINENT_SITES; i++)
|
||||
if (sites[i].entry == entry)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16 ArchaeologyMgr::GetNewSite(Continent continent, SiteData* sites, bool extended, uint32 playerLevel)
|
||||
{
|
||||
std::vector<SiteEntry>* siteList;
|
||||
uint32 offset = continent* CONTINENT_SITES;
|
||||
uint16 entry;
|
||||
|
||||
if (extended)
|
||||
siteList = &(_siteMap[continent + COUNT_CONT]);
|
||||
else
|
||||
siteList = &(_siteMap[continent]);
|
||||
|
||||
do
|
||||
{
|
||||
uint32 position = urand(0, siteList->size() - 1);
|
||||
entry = uint16(siteList->at(position).id);
|
||||
if (siteList->at(position).minLevel > playerLevel)
|
||||
continue;
|
||||
}
|
||||
while (!isSiteValid(&(sites[offset]), entry));
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
bool ArchaeologyMgr::SetSiteCoords(SiteData &site)
|
||||
{
|
||||
if (SitePolygonGraph* poly = _polygonMap[site.entry])
|
||||
{
|
||||
// Calculate random point of interest
|
||||
SitePolygonGraphNode node = poly->randomize_poi();
|
||||
|
||||
// Get random point into Polygon
|
||||
site.x = node.getX();
|
||||
site.y = node.getY();
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 ArchaeologyMgr::GetSiteType(uint16 entry)
|
||||
{
|
||||
if (!_objectMap[entry])
|
||||
TC_LOG_ERROR("player.skills", "Archaeology: Entry %u has no find object Type!", entry);
|
||||
|
||||
return _objectMap[entry];
|
||||
}
|
||||
|
||||
uint32 ArchaeologyMgr::GetFindCurrency(uint32 go_entry)
|
||||
{
|
||||
switch (go_entry)
|
||||
{
|
||||
case FIND_OBJECT_DRAENEI:
|
||||
return CURRENCY_TYPE_DRAENEI_FRAGMENT;
|
||||
case FIND_OBJECT_DWARF:
|
||||
return CURRENCY_TYPE_DWARF_FRAGMENT;
|
||||
case FIND_OBJECT_FOSSIL:
|
||||
return CURRENCY_TYPE_FOSSIL_FRAGMENT;
|
||||
case FIND_OBJECT_NERUBIAN:
|
||||
return CURRENCY_TYPE_NERUBIAN_FRAGMENT;
|
||||
case FIND_OBJECT_NIGHT_ELF:
|
||||
return CURRENCY_TYPE_NELF_FRAGMENT;
|
||||
case FIND_OBJECT_ORC:
|
||||
return CURRENCY_TYPE_ORC_FRAGMENT;
|
||||
case FIND_OBJECT_TOL_VIR:
|
||||
return CURRENCY_TYPE_TOLVIR_FRAGMENT;
|
||||
case FIND_OBJECT_TROLL:
|
||||
return CURRENCY_TYPE_TROLL_FRAGMENT;
|
||||
case FIND_OBJECT_VRYKUL:
|
||||
return CURRENCY_TYPE_VRYKUL_FRAGMENT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16 ArchaeologyMgr::GetNewProject(BranchData* branch, std::map<uint16, std::pair<int32, int32> >* completedMap, uint32 playerSkill)
|
||||
{
|
||||
uint8 branchId = branch->branchId;
|
||||
std::vector<uint16>* _rares = &_rareProjects[branchId];
|
||||
std::vector<uint16>* _commons = &_commonProjects[branchId];
|
||||
|
||||
float rareChance = float(_rares->size() - branch->completedRares) / float(_commons->size() + _rares->size());
|
||||
float roll1 = frand(.0f, 1.0f);
|
||||
|
||||
// Are we eligible for a Rare Project ?
|
||||
if (rareChance > roll1)
|
||||
{
|
||||
float roll2 = frand(.0f, 1.0f);
|
||||
float rareChance = _branchMap[branchId].rareChance;
|
||||
|
||||
for (std::vector<uint16>::iterator itr = _rares->begin(); itr != _rares->end(); ++itr)
|
||||
{
|
||||
float chance = (_projects[*itr].rarity == ITEM_QUALITY_RARE)? rareChance: EPIC_CHANCE;
|
||||
|
||||
// Are we in our choose range ?
|
||||
if (chance < roll2)
|
||||
{
|
||||
roll2 -= chance;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Do we have the required SkillLevel ?
|
||||
if (_projects[*itr].reqSkill > playerSkill)
|
||||
break;
|
||||
|
||||
// Did we already complete the artifact ?
|
||||
if (completedMap->find(*itr) != completedMap->end())
|
||||
break;
|
||||
|
||||
return *itr;
|
||||
}
|
||||
}
|
||||
|
||||
// did we already complete all commons of the branch
|
||||
uint32 begin = urand(0, _commons->size() - 1);
|
||||
uint32 end = (begin == 0) ? _commons->size() - 1 : begin - 1;
|
||||
|
||||
uint32 secondArtifact = 0;
|
||||
|
||||
for (uint16 itr = begin; itr != end ; itr = (itr + 1) % _commons->size())
|
||||
{
|
||||
uint16 projectId = _commons->at(itr);
|
||||
|
||||
// Do we have the required SkillLevel ?
|
||||
if (_projects[projectId].reqSkill > playerSkill)
|
||||
continue;
|
||||
|
||||
// Did we already complete the artifact ?
|
||||
if (completedMap->find(projectId) != completedMap->end())
|
||||
{
|
||||
if (!secondArtifact)
|
||||
secondArtifact = projectId;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
return _projects[projectId].entry;
|
||||
}
|
||||
// looks like we didn't find an eligible common artifact => relax the non repetitive restriction
|
||||
return secondArtifact;
|
||||
}
|
||||
|
||||
} // namespace archaeology
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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 _ARCHAEOLOGY_MGR_H
|
||||
#define _ARCHAEOLOGY_MGR_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "SitePolygonGraph.h"
|
||||
#include "Define.h"
|
||||
|
||||
#define CONTINENT_SITES 4
|
||||
#define MAX_PROJECTS 16
|
||||
#define POINT_PER_POLYGON 12
|
||||
#define EPIC_CHANCE 0.05f
|
||||
#define MAX_RARE_CHANCE 0.2f
|
||||
|
||||
enum Continent
|
||||
{
|
||||
CONT_EASTERN = 0,
|
||||
CONT_KALIMDOR = 1,
|
||||
CONT_OUTLAND = 2,
|
||||
CONT_NORTHREND = 3,
|
||||
COUNT_CONT = 4,
|
||||
};
|
||||
|
||||
enum SkillStart
|
||||
{
|
||||
SKILL_OUTLAND = 300,
|
||||
SKILL_NORTHREND = 375,
|
||||
SKILL_CATA = 450,
|
||||
};
|
||||
|
||||
enum FindObject
|
||||
{
|
||||
FIND_OBJECT_DRAENEI = 207188,
|
||||
FIND_OBJECT_DWARF = 204282,
|
||||
FIND_OBJECT_FOSSIL = 206836,
|
||||
FIND_OBJECT_NERUBIAN = 203078,
|
||||
FIND_OBJECT_NIGHT_ELF = 203071,
|
||||
FIND_OBJECT_ORC = 207187,
|
||||
FIND_OBJECT_TOL_VIR = 207190,
|
||||
FIND_OBJECT_TROLL = 202655,
|
||||
FIND_OBJECT_VRYKUL = 207189,
|
||||
};
|
||||
|
||||
struct SiteEntry
|
||||
{
|
||||
uint16 id;
|
||||
uint32 mapId;
|
||||
uint16 questPOI;
|
||||
uint32 reqSkill;
|
||||
uint32 minLevel;
|
||||
};
|
||||
|
||||
struct SiteData
|
||||
{
|
||||
uint16 entry;
|
||||
uint16 state;
|
||||
float x;
|
||||
float y;
|
||||
float tele_x;
|
||||
float tele_y;
|
||||
float tele_angle;
|
||||
};
|
||||
|
||||
struct BranchEntry
|
||||
{
|
||||
uint8 fieldId;
|
||||
float rareChance;
|
||||
uint32 currencyId;
|
||||
uint32 keystoneId;
|
||||
};
|
||||
|
||||
struct BranchData
|
||||
{
|
||||
uint8 branchId;
|
||||
uint8 completedRares;
|
||||
uint32 project;
|
||||
};
|
||||
|
||||
struct ProjectEntry
|
||||
{
|
||||
uint16 entry;
|
||||
uint8 branch;
|
||||
uint8 rarity;
|
||||
uint32 reqSkill;
|
||||
uint32 fragments;
|
||||
uint8 keystone;
|
||||
uint32 spell;
|
||||
};
|
||||
|
||||
namespace archaeology
|
||||
{
|
||||
|
||||
class TC_GAME_API ArchaeologyMgr
|
||||
{
|
||||
public:
|
||||
static ArchaeologyMgr* instance();
|
||||
void LoadData();
|
||||
|
||||
// Site Functionality
|
||||
static uint32 GetFindCurrency(uint32 go_entry);
|
||||
uint16 GetNewSite(Continent continent, SiteData *sites, bool extended, uint32 playerLevel);
|
||||
bool SetSiteCoords(SiteData &site);
|
||||
uint32 GetSiteType(uint16 entry);
|
||||
|
||||
// Project Functionality
|
||||
uint8 Currency2BranchId(uint32 currencyId) { return _currencyMap[currencyId]; }
|
||||
const BranchEntry *GetBranchEntry(uint8 branchId) { return &_branchMap[branchId]; }
|
||||
const ProjectEntry *GetProjectEntry(uint16 projectId) { return &_projects[projectId]; }
|
||||
|
||||
bool IsRareProject(uint16 project) { return _projects[project].rarity >= ITEM_QUALITY_RARE; }
|
||||
uint16 GetNewProject(BranchData *branch, std::map<uint16, std::pair<int32, int32> > *completedMap, uint32 PlayerSkill);
|
||||
|
||||
private:
|
||||
ArchaeologyMgr();
|
||||
~ArchaeologyMgr();
|
||||
|
||||
bool isSiteValid(SiteData *sites, uint16 entry);
|
||||
|
||||
std::map<uint32, std::vector<SiteEntry> > _siteMap;
|
||||
std::map<uint16, SitePolygonGraph* > _polygonMap;
|
||||
std::map<uint16, uint32> _objectMap;
|
||||
|
||||
std::map<uint32, uint8> _currencyMap; // currencyId -> branchId
|
||||
std::map<uint8, BranchEntry> _branchMap; // branchId -> BranchEntry
|
||||
|
||||
std::map<uint16, ProjectEntry> _projects;
|
||||
std::map<uint8, std::vector<uint16> > _commonProjects;
|
||||
std::map<uint8, std::vector<uint16> > _rareProjects;
|
||||
};
|
||||
|
||||
} // namespace archaeology
|
||||
|
||||
#define sArchaeologyMgr archaeology::ArchaeologyMgr::instance()
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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 "Archaeology.h"
|
||||
#include "DBCStore.h"
|
||||
#include "Player.h"
|
||||
|
||||
void Archaeology::LoadCompletedProjectsFromDB()
|
||||
{
|
||||
QueryResult result;
|
||||
|
||||
result = CharacterDatabase.PQuery("SELECT project, time, count FROM character_archaeology_completed WHERE guid=%u",
|
||||
_player->GetGUID());
|
||||
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
uint32 count = 0;
|
||||
do {
|
||||
Field *fields = result->Fetch();
|
||||
uint16 project = fields[0].GetUInt16();
|
||||
int32 time = fields[1].GetInt32();
|
||||
int32 count = fields[2].GetInt32();
|
||||
|
||||
_completedProjects[project].first = time;
|
||||
_completedProjects[project].second = count;
|
||||
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
void Archaeology::InitBranches()
|
||||
{
|
||||
for (uint8 i = 0; i < sResearchBranchStore.GetNumRows(); ++i)
|
||||
if (const ResearchBranchEntry *branch = sResearchBranchStore.LookupEntry(i))
|
||||
if (branch->CurrencyID)
|
||||
{
|
||||
struct BranchData branchData;
|
||||
branchData.branchId = branch->ID;
|
||||
branchData.completedRares = 0;
|
||||
branchData.project = 0;
|
||||
_branches[i] = branchData;
|
||||
}
|
||||
}
|
||||
|
||||
void Archaeology::LoadCurrentProjectsFromDB()
|
||||
{
|
||||
QueryResult result;
|
||||
|
||||
InitBranches();
|
||||
|
||||
result = CharacterDatabase.PQuery("SELECT branch, project FROM character_archaeology_projects WHERE guid=%u",
|
||||
_player->GetGUID());
|
||||
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
uint32 count = 0;
|
||||
do {
|
||||
Field *fields = result->Fetch();
|
||||
uint8 branch = fields[0].GetUInt8();
|
||||
uint16 project = fields[1].GetUInt16();
|
||||
|
||||
if (uint16 old_project = _branches[branch].project)
|
||||
{
|
||||
TC_LOG_ERROR("player.skills", "ERROR - Archaeology: Tried to assign project %u to branch %u, which already holds project %u!",
|
||||
project, branch, old_project);
|
||||
continue;
|
||||
}
|
||||
|
||||
_branches[branch].project = project;
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
void Archaeology::VisualizeBranch(uint8 position, uint16 project)
|
||||
{
|
||||
if (position < MAX_PROJECTS)
|
||||
_player->SetUInt16Value(PLAYER_FIELD_RESEARCH_PROJECT_1 + (position / 2), position % 2, project);
|
||||
}
|
||||
|
||||
void Archaeology::RegenerateBranch(uint8 branch)
|
||||
{
|
||||
uint16 project = sArchaeologyMgr->GetNewProject(&_branches[branch], &_completedProjects, _player->GetSkillValue(SKILL_ARCHAEOLOGY));
|
||||
_branches[branch].project = project;
|
||||
|
||||
CharacterDatabase.PExecute("REPLACE INTO character_archaeology_projects VALUES (%u, %u, %u)",
|
||||
_player->GetGUID(), branch, project);
|
||||
}
|
||||
|
||||
void Archaeology::VerifyProjects()
|
||||
{
|
||||
for (std::map<uint8, BranchData>::iterator itr = _branches.begin(); itr != _branches.end(); ++itr)
|
||||
if (const BranchEntry* branch = sArchaeologyMgr->GetBranchEntry(itr->first))
|
||||
{
|
||||
uint16 project = itr->second.project;
|
||||
if (project)
|
||||
{
|
||||
if (_completedProjects.find(project) != _completedProjects.end() && sArchaeologyMgr->IsRareProject(project))
|
||||
RegenerateBranch(itr->first);
|
||||
}
|
||||
else if (_player->GetCurrency(branch->currencyId, false))
|
||||
RegenerateBranch(itr->first);
|
||||
else
|
||||
continue;
|
||||
|
||||
VisualizeBranch(branch->fieldId, _branches[itr->first].project);
|
||||
}
|
||||
}
|
||||
|
||||
void Archaeology::CleanProjects()
|
||||
{
|
||||
CharacterDatabase.PExecute("delete from character_archaeology_projects where guid=%u",
|
||||
_player->GetGUID());
|
||||
|
||||
for (uint8 i = 0; i < MAX_PROJECTS; ++i)
|
||||
VisualizeBranch(i, 0);
|
||||
|
||||
_branches.clear();
|
||||
}
|
||||
|
||||
void Archaeology::ActivateBranch(uint8 branchId, bool force)
|
||||
{
|
||||
if (_branches[branchId].project && !force)
|
||||
return;
|
||||
|
||||
RegenerateBranch(branchId);
|
||||
VisualizeBranch(sArchaeologyMgr->GetBranchEntry(branchId)->fieldId, _branches[branchId].project);
|
||||
}
|
||||
|
||||
bool Archaeology::ProjectExists(uint16 projectId)
|
||||
{
|
||||
if (const ProjectEntry* project = sArchaeologyMgr->GetProjectEntry(projectId))
|
||||
return (_branches[project->branch].project == projectId);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Archaeology::ProjectCompleteable(uint16 projectId)
|
||||
{
|
||||
if (!archData)
|
||||
return false;
|
||||
|
||||
if (const ProjectEntry* project = sArchaeologyMgr->GetProjectEntry(projectId))
|
||||
if (_branches[project->branch].project == projectId)
|
||||
{
|
||||
const BranchEntry* branchEntry = sArchaeologyMgr->GetBranchEntry(project->branch);
|
||||
|
||||
// Check Ids
|
||||
uint32 currencyId = branchEntry->currencyId;
|
||||
uint32 keystoneId = branchEntry->keystoneId;
|
||||
if (currencyId != archData->fragId || (archData->keyId && archData->keyId != keystoneId))
|
||||
return false;
|
||||
|
||||
// Project can have keystones ?
|
||||
if (project->keystone < archData->keyCount)
|
||||
return false;
|
||||
|
||||
// Check if the given fragment/keystone usage would be enough
|
||||
if (archData->fragCount + archData->keyCount * 12 != project->fragments)
|
||||
return false;
|
||||
|
||||
// Check if the player has the keystones
|
||||
if (_player->GetCurrency(archData->fragId, false) < archData->fragCount)
|
||||
return false;
|
||||
|
||||
// Check if the player has the fragments
|
||||
return (!archData->keyId || _player->GetItemCount(archData->keyId) >= archData->keyCount);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Archaeology::CompleteProject(uint16 projectId)
|
||||
{
|
||||
const ProjectEntry *project = sArchaeologyMgr->GetProjectEntry(projectId);
|
||||
ASSERT(project);
|
||||
ASSERT(_branches[project->branch].project == projectId);
|
||||
ASSERT(archData);
|
||||
|
||||
_player->ModifyCurrency(archData->fragId, -int32(archData->fragCount), false, true);
|
||||
_player->DestroyItemCount(archData->keyId, archData->keyCount, true, false);
|
||||
|
||||
if (_completedProjects.find(projectId) == _completedProjects.end())
|
||||
{
|
||||
_completedProjects[projectId].first = time(NULL);
|
||||
_completedProjects[projectId].second = 1;
|
||||
|
||||
CharacterDatabase.PExecute("REPLACE INTO character_archaeology_completed VALUES (%u, %u, %u, 1);",
|
||||
_player->GetGUID(), projectId, time(NULL));
|
||||
}
|
||||
else
|
||||
{
|
||||
_completedProjects[projectId].second++;
|
||||
|
||||
CharacterDatabase.PExecute("UPDATE character_archaeology_completed SET count=%u WHERE guid=%u and project=%u;",
|
||||
_completedProjects[projectId].second, _player->GetGUID(), projectId);
|
||||
}
|
||||
|
||||
_player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ARCHAEOLOGY_PROJECTS, projectId, 1);
|
||||
|
||||
delete archData;
|
||||
ActivateBranch(project->branch, true);
|
||||
}
|
||||
|
||||
void Archaeology::SendResearchHistory()
|
||||
{
|
||||
uint32 count = _completedProjects.size();
|
||||
WorldPacket packet(SMSG_RESEARCH_SETUP_HISTORY, 4 + 4 + (4 + 4 + 4) * count);
|
||||
packet.WriteBits(count, 22);
|
||||
|
||||
packet.FlushBits();
|
||||
|
||||
for (std::map<uint16, std::pair<int32, int32> >::iterator itr = _completedProjects.begin(); itr != _completedProjects.end(); ++itr)
|
||||
{
|
||||
packet << int32(itr->first);
|
||||
packet << int32(itr->second.second);
|
||||
packet << uint32(itr->second.first);
|
||||
}
|
||||
|
||||
_player->GetSession()->SendPacket(&packet);
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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 "Archaeology.h"
|
||||
#include "DBCStore.h"
|
||||
#include "Player.h"
|
||||
#include "Language.h"
|
||||
#include <G3D\Quat.h>
|
||||
|
||||
|
||||
// use squared distances so we don't have to use the squareroot
|
||||
enum DigSiteDist
|
||||
{
|
||||
DIST_FAR = 10000, // 100 yards
|
||||
DIST_MED = 900, // 30 yards
|
||||
DIST_CLOSE = 100, // 10 yards
|
||||
};
|
||||
|
||||
enum SurveyBot
|
||||
{
|
||||
FAR_SURVEYBOT = 206590,
|
||||
MED_SURVEYBOT = 206589,
|
||||
CLOSE_SURVEYBOT = 204272,
|
||||
};
|
||||
|
||||
void Archaeology::LoadSitesFromDB()
|
||||
{
|
||||
QueryResult result = CharacterDatabase.PQuery("SELECT site, type, finds FROM character_archaeology_sites WHERE guid=%u", _player->GetGUID());
|
||||
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
uint32 count = 0;
|
||||
do {
|
||||
Field *fields = result->Fetch();
|
||||
uint32 site = fields[0].GetUInt8();
|
||||
uint16 type = fields[1].GetUInt16();
|
||||
uint8 finds = fields[2].GetUInt8();
|
||||
SetSite(site, type, finds);
|
||||
count++;
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
void Archaeology::VerifySites()
|
||||
{
|
||||
uint16 skillValue = _player->GetSkillValue(SKILL_ARCHAEOLOGY);
|
||||
|
||||
if (skillValue >= SKILL_OUTLAND)
|
||||
_continentState[CONT_OUTLAND] = STATE_USE;
|
||||
else
|
||||
_continentState[CONT_OUTLAND] = STATE_NULL;
|
||||
|
||||
if (skillValue >= SKILL_NORTHREND)
|
||||
_continentState[CONT_NORTHREND] = STATE_USE;
|
||||
else
|
||||
_continentState[CONT_NORTHREND] = STATE_NULL;
|
||||
|
||||
if (skillValue >= SKILL_CATA)
|
||||
{
|
||||
_continentState[CONT_EASTERN] = STATE_EXT;
|
||||
_continentState[CONT_KALIMDOR] = STATE_EXT;
|
||||
}
|
||||
else
|
||||
{
|
||||
_continentState[CONT_EASTERN] = STATE_USE;
|
||||
_continentState[CONT_KALIMDOR] = STATE_USE;
|
||||
}
|
||||
|
||||
RegenerateAllSites();
|
||||
}
|
||||
|
||||
void Archaeology::UseSite()
|
||||
{
|
||||
float dist;
|
||||
uint32 position = GetNearestSite(dist);
|
||||
|
||||
if (0 == position)
|
||||
return;
|
||||
|
||||
position--;
|
||||
|
||||
if (dist > DIST_CLOSE)
|
||||
{
|
||||
uint32 surveyGoID;
|
||||
float angle = std::atan2(_site[position].y - _player->GetPositionY(), _site[position].x - _player->GetPositionX());
|
||||
float pi = float(M_PI);
|
||||
|
||||
if (dist < DIST_MED)
|
||||
{
|
||||
surveyGoID = CLOSE_SURVEYBOT; // within the med radius -> green light
|
||||
angle += frand(-pi / 12, pi / 12);
|
||||
}
|
||||
else if (dist < DIST_FAR)
|
||||
{
|
||||
surveyGoID = MED_SURVEYBOT; // within the far radius -> yellow light
|
||||
angle += frand(-pi / 6, pi / 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
surveyGoID = FAR_SURVEYBOT; // outside far radius -> red light
|
||||
angle += frand(-pi / 3, pi / 3);
|
||||
}
|
||||
|
||||
float o = _player->GetOrientation();
|
||||
float x = _player->GetPositionX() + cos(o) * 2.0f;
|
||||
float y = _player->GetPositionY() + sin(o) * 2.0f;
|
||||
float z = _player->GetPositionZ();
|
||||
float ground = _player->GetMap()->GetWaterOrGroundLevel(_player->GetPhases(), x, y, z, &ground, _player->IsInWater());
|
||||
|
||||
G3D::Quat rot = G3D::Matrix3::fromEulerAnglesZYX(angle, 0.f, 0.f);
|
||||
if (abs(z - ground) < 1.5f)
|
||||
{
|
||||
_player->SummonGameObject(surveyGoID, Position(x, y, ground, angle), rot, 4);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_player->GetSession()->SendNotification(LANG_YOU_CANT_USE_THAT_HERE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Spawn the correct Find Object Here
|
||||
uint32 goId = sArchaeologyMgr->GetSiteType(_site[position].entry);
|
||||
float o = _player->GetOrientation();
|
||||
float x = _player->GetPositionX() + cos(o) * 2.0f;
|
||||
float y = _player->GetPositionY() + sin(o) * 2.0f;
|
||||
float z = _player->GetPositionZ();
|
||||
float ground = _player->GetMap()->GetWaterOrGroundLevel(_player->GetPhases(), x, y, z, &ground, _player->IsInWater());
|
||||
|
||||
// Spawn object
|
||||
_player->SummonGameObject(goId, Position(x, y, ground, o), G3D::Quat(), 60);
|
||||
(_site[position].state)++;
|
||||
|
||||
if (_site[position].state >= DIGS_PER_SITE)
|
||||
RegeneratePosition(position, GetContinent());
|
||||
else
|
||||
{
|
||||
CharacterDatabase.PExecute("UPDATE character_archaeology_sites SET finds = %u WHERE site= %u AND guid= %u", _site[position].state, position, _player->GetGUID());
|
||||
sArchaeologyMgr->SetSiteCoords(_site[position]);
|
||||
}
|
||||
}
|
||||
|
||||
Continent Archaeology::GetContinent()
|
||||
{
|
||||
switch (_player->GetMapId())
|
||||
{
|
||||
case 0:
|
||||
return CONT_EASTERN;
|
||||
case 1:
|
||||
return CONT_KALIMDOR;
|
||||
case 530:
|
||||
return CONT_OUTLAND;
|
||||
case 571:
|
||||
return CONT_NORTHREND;
|
||||
}
|
||||
return COUNT_CONT;
|
||||
}
|
||||
|
||||
uint32 Archaeology::GetNearestSite(float &distance)
|
||||
{
|
||||
uint32 cont = GetContinent();
|
||||
|
||||
if (COUNT_CONT == cont)
|
||||
return 0;
|
||||
|
||||
uint32 position = cont * CONTINENT_SITES;
|
||||
|
||||
float pX = _player->GetPositionX();
|
||||
float pY = _player->GetPositionY();
|
||||
|
||||
float dist = (pX - _site[position].x) * (pX - _site[position].x) + (pY - _site[position].y) * (pY - _site[position].y);
|
||||
|
||||
for (uint32 i = cont * CONTINENT_SITES + 1; i < (cont + 1) * CONTINENT_SITES; i++)
|
||||
{
|
||||
float dist2 = (pX -_site[i].x) * (pX -_site[i].x) + (pY - _site[i].y) * (pY - _site[i].y);
|
||||
if (dist2 < dist)
|
||||
{
|
||||
position = i;
|
||||
dist = dist2;
|
||||
}
|
||||
}
|
||||
distance = dist;
|
||||
|
||||
return position + 1;
|
||||
}
|
||||
|
||||
void Archaeology::SetSite(uint32 position, uint16 entry, uint32 state)
|
||||
{
|
||||
_site[position].entry = entry;
|
||||
_site[position].state = state;
|
||||
_player->SetUInt16Value(PLAYER_FIELD_RESEARCH_SITE_1 + (position / 2), position % 2, entry);
|
||||
|
||||
if (entry == 0)
|
||||
{
|
||||
_site[position].x = 0.f;
|
||||
_site[position].y = 0.f;
|
||||
}
|
||||
else
|
||||
sArchaeologyMgr->SetSiteCoords(_site[position]);
|
||||
}
|
||||
|
||||
void Archaeology::RegeneratePosition(uint32 position, Continent continent)
|
||||
{
|
||||
if (_site[position].entry && sResearchSiteStore.LookupEntry(_site[position].entry) && _site[position].state < DIGS_PER_SITE)
|
||||
return;
|
||||
|
||||
uint16 entry = sArchaeologyMgr->GetNewSite(continent, _site, _continentState[continent] == STATE_EXT, _player->getLevel());
|
||||
SetSite(position, entry);
|
||||
CharacterDatabase.PExecute("REPLACE INTO character_archaeology_sites values (%u, %u, %u, %u);", _player->GetGUID(), position, entry, _site[position].state);
|
||||
}
|
||||
|
||||
void Archaeology::RegenerateContinent(Continent continent)
|
||||
{
|
||||
if (_continentState[continent] == STATE_NULL)
|
||||
{
|
||||
uint32 position = continent * CONTINENT_SITES;
|
||||
|
||||
for (int i = 0; i < CONTINENT_SITES; i++)
|
||||
SetSite(position + i, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 position = continent * CONTINENT_SITES;
|
||||
|
||||
for (uint32 i = 0; i < CONTINENT_SITES; i++)
|
||||
RegeneratePosition(position + i, continent);
|
||||
}
|
||||
|
||||
void Archaeology::RegenerateAllSites()
|
||||
{
|
||||
for (uint32 i = 0; i < COUNT_CONT; i++)
|
||||
RegenerateContinent(Continent(i));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,565 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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 "SitePolygonGraph.h"
|
||||
|
||||
//===========================================================================//
|
||||
// RESIZE NODES
|
||||
//===========================================================================//
|
||||
|
||||
bool SitePolygonGraph::resize_nodes()
|
||||
{
|
||||
SitePolygonGraphNode* tmpNodes = _nodes;
|
||||
index_type tmpSize = _size_nodes++;
|
||||
_nodes = 0;
|
||||
|
||||
try
|
||||
{
|
||||
if(_size_nodes > 0) _nodes = new SitePolygonGraphNode[_size_nodes];
|
||||
else _nodes = 0;
|
||||
|
||||
for(index_type i = 0; i < tmpSize; i++)
|
||||
_nodes[i].set(tmpNodes[i].get());
|
||||
|
||||
delete[] tmpNodes;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
_nodes = tmpNodes;
|
||||
_size_nodes = tmpSize;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================//
|
||||
// RESIZE ARCHES
|
||||
//===========================================================================//
|
||||
|
||||
bool SitePolygonGraph::resize_arches()
|
||||
{
|
||||
if(_size_nodes <= 0)
|
||||
return false;
|
||||
|
||||
SitePolygonGraphArch* tmpArches = _arches;
|
||||
index_type tmpSizeArches = _size_arches++;
|
||||
_arches = 0;
|
||||
|
||||
try
|
||||
{
|
||||
if(_size_arches > 0) _arches = new SitePolygonGraphArch[_size_arches];
|
||||
else _arches = 0;
|
||||
|
||||
for(index_type i = 0; i < tmpSizeArches; i++)
|
||||
_arches[i].set(tmpArches[i].get());
|
||||
|
||||
delete[] tmpArches;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
_arches = tmpArches;
|
||||
_size_arches = tmpSizeArches;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================//
|
||||
// BOUNDARY GEOMETRY GENERATOR
|
||||
//===========================================================================//
|
||||
|
||||
void SitePolygonGraph::generate_geometry()
|
||||
{
|
||||
SitePolygonGraphNode last = _nodes[_size_nodes - 1];
|
||||
float x = last.getX();
|
||||
float y = last.getY();
|
||||
|
||||
float x_plus = x + 1.0;
|
||||
float x_minus = x - 1.0;
|
||||
float y_plus = y + 1.0;
|
||||
float y_minus = y - 1.0;
|
||||
|
||||
float ax_point = float();
|
||||
float ay_point = float();
|
||||
float bx_point = float();
|
||||
float by_point = float();
|
||||
|
||||
if(_geometry.isNull())
|
||||
{
|
||||
_geometry.setLeft(x_minus, y_plus, x_minus, y_minus);
|
||||
_geometry.setBottom(x_minus, y_minus, x_plus, y_minus);
|
||||
_geometry.setRight(x_plus, y_minus, x_plus, y_plus);
|
||||
_geometry.setTop(x_plus, y_plus, x_minus, y_plus);
|
||||
|
||||
_geometry.setNull(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// LEFT ARCH
|
||||
ax_point = _geometry.getLeft().getA().getX();
|
||||
ax_point = (ax_point >= x - 1.0) ? x_minus : ax_point;
|
||||
ay_point = _geometry.getLeft().getA().getY();
|
||||
ay_point = (ay_point <= y + 1.0) ? y_plus : ay_point;
|
||||
|
||||
bx_point = _geometry.getLeft().getB().getX();
|
||||
bx_point = (bx_point >= x - 1.0) ? x_minus : bx_point;
|
||||
by_point = _geometry.getLeft().getB().getY();
|
||||
by_point = (by_point >= y - 1.0) ? y_minus : by_point;
|
||||
|
||||
_geometry.setLeft(ax_point, ay_point, bx_point, by_point);
|
||||
|
||||
// BOTTOM ARCH
|
||||
ax_point = _geometry.getBottom().getA().getX();
|
||||
ax_point = (ax_point >= x - 1.0) ? x_minus : ax_point;
|
||||
ay_point = _geometry.getBottom().getA().getY();
|
||||
ay_point = (ay_point >= y - 1.0) ? y_minus : ay_point;
|
||||
|
||||
bx_point = _geometry.getBottom().getB().getX();
|
||||
bx_point = (bx_point <= x + 1.0) ? x_plus : bx_point;
|
||||
by_point = _geometry.getBottom().getB().getY();
|
||||
by_point = (by_point >= y - 1.0) ? y_minus : by_point;
|
||||
|
||||
_geometry.setBottom(ax_point, ay_point, bx_point, by_point);
|
||||
|
||||
// RIGHT ARCH
|
||||
ax_point = _geometry.getRight().getA().getX();
|
||||
ax_point = (ax_point <= x + 1.0) ? x_plus : ax_point;
|
||||
ay_point = _geometry.getRight().getA().getY();
|
||||
ay_point = (ay_point >= y - 1.0) ? y_minus : ay_point;
|
||||
|
||||
bx_point = _geometry.getRight().getB().getX();
|
||||
bx_point = (bx_point <= x + 1.0) ? x_plus : bx_point;
|
||||
by_point = _geometry.getRight().getB().getY();
|
||||
by_point = (by_point <= y + 1.0) ? y_plus : by_point;
|
||||
|
||||
_geometry.setRight(ax_point, ay_point, bx_point, by_point);
|
||||
|
||||
// TOP ARCH
|
||||
ax_point = _geometry.getTop().getA().getX();
|
||||
ax_point = (ax_point <= x + 1.0) ? x_plus : ax_point;
|
||||
ay_point = _geometry.getTop().getA().getY();
|
||||
ay_point = (ay_point <= y + 1.0) ? y_plus : ay_point;
|
||||
|
||||
bx_point = _geometry.getTop().getB().getX();
|
||||
bx_point = (bx_point >= x - 1.0) ? x_minus : bx_point;
|
||||
by_point = _geometry.getTop().getB().getY();
|
||||
by_point = (by_point <= y + 1.0) ? y_plus : by_point;
|
||||
|
||||
_geometry.setTop(ax_point, ay_point, bx_point, by_point);
|
||||
}
|
||||
|
||||
//===========================================================================//
|
||||
// GEOMETRY INSCRIBED GENERATOR
|
||||
//===========================================================================//
|
||||
|
||||
void SitePolygonGraph::generate_geometry_inscribed()
|
||||
{
|
||||
if(_size_nodes <= 1 && _size_arches <= 0)
|
||||
return;
|
||||
|
||||
index_type max_value = _size_arches;
|
||||
|
||||
for(index_type i = 0; i < _size_nodes; i++)
|
||||
{
|
||||
SitePolygonGraphNode node = _nodes[i];
|
||||
|
||||
for(index_type n = 0; n < max_value; n++)
|
||||
{
|
||||
// Temporary arch
|
||||
SitePolygonGraphArch arch = _arches[n];
|
||||
|
||||
// Create temporary arch for check
|
||||
SitePolygonGraphArch tmp;
|
||||
tmp.setA(node);
|
||||
tmp.setB(arch.getMidPoint());
|
||||
|
||||
// Skip loops on nodes
|
||||
if(node == arch.getA() || node == arch.getB())
|
||||
continue;
|
||||
|
||||
// Check if arches contains tmp
|
||||
if(arch_exists(tmp))
|
||||
continue;
|
||||
|
||||
add_arch(tmp.getA(), tmp.getB());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================//
|
||||
// GEOMETRY INSCRIBED GENERATOR
|
||||
//===========================================================================//
|
||||
|
||||
bool SitePolygonGraph::generate_geometry_fragmentation(SitePolygonGraphArch &base_arch)
|
||||
{
|
||||
if(_size_arches <= 0)
|
||||
return false;
|
||||
|
||||
// Number of intersection
|
||||
index_type N_INTSECD = 0;
|
||||
index_type N_REACHED = 0;
|
||||
|
||||
// Test node
|
||||
SitePolygonGraphNode node_test;
|
||||
SitePolygonGraphNode node_test_boundary;
|
||||
|
||||
// FRAGMENTATION WITH GEOMETRY BOUNDARY
|
||||
//-------------------------------------------------------------------------
|
||||
SitePolygonGraphArch geometry_arches[4];
|
||||
geometry_arches[0] = _geometry.getLeft();
|
||||
geometry_arches[1] = _geometry.getBottom();
|
||||
geometry_arches[2] = _geometry.getRight();
|
||||
geometry_arches[3] = _geometry.getTop();
|
||||
|
||||
for(index_type n = 0; n < 4; n++)
|
||||
{
|
||||
// Arch from geometry
|
||||
SitePolygonGraphArch boundary_arch = geometry_arches[n];
|
||||
float intersect_X = float();
|
||||
float intersect_Y = float();
|
||||
bool check_intersect_strict = false;
|
||||
bool check_intersect = get_xy_intersect(base_arch, boundary_arch, intersect_X, intersect_Y, check_intersect_strict);
|
||||
bool skip_check = false;
|
||||
|
||||
// Save for current step
|
||||
SitePolygonGraphNode tmp_check;
|
||||
tmp_check.setX(intersect_X);
|
||||
tmp_check.setY(intersect_Y);
|
||||
|
||||
if(n > 0)
|
||||
{
|
||||
// Check for duplicate start/end point
|
||||
skip_check = (node_test_boundary == tmp_check && check_intersect_strict);
|
||||
}
|
||||
|
||||
// Save for next step
|
||||
node_test_boundary.setX(intersect_X);
|
||||
node_test_boundary.setY(intersect_Y);
|
||||
|
||||
if(check_intersect && !skip_check)
|
||||
N_INTSECD += 1;
|
||||
}
|
||||
|
||||
// FRAGMENTATION WITH GEOMETRY INSCRIBED
|
||||
//-------------------------------------------------------------------------
|
||||
bool is_ab_start = false;
|
||||
bool is_md_start = false;
|
||||
//-------------------------------------------------------------------------
|
||||
SitePolygonGraphNode ab_point;
|
||||
SitePolygonGraphNode md_point;
|
||||
|
||||
for(index_type n = 0; n < SITE_POLYGON_GRAPH_MAX_VERTEX; n++)
|
||||
{
|
||||
// Arch from perimeter
|
||||
SitePolygonGraphArch boundary_arch = _arches[n];
|
||||
float intersect_X = float();
|
||||
float intersect_Y = float();
|
||||
bool check_intersect_strict = false;
|
||||
bool check_intersect_line = get_xy_intersect(base_arch, boundary_arch, intersect_X, intersect_Y, check_intersect_strict);
|
||||
|
||||
// Set new values for test
|
||||
node_test.setX(intersect_X);
|
||||
node_test.setY(intersect_Y);
|
||||
|
||||
// Pre-Check for possibile skip
|
||||
bool check_is_ab_point = ((node_test == boundary_arch.getA() || node_test == boundary_arch.getB()) && check_intersect_strict);
|
||||
bool check_is_md_point = ((node_test == boundary_arch.getMidPoint()) && check_intersect_strict);
|
||||
|
||||
// Check for possibile skip
|
||||
if(check_is_ab_point && !is_ab_start)
|
||||
{
|
||||
is_ab_start = true;
|
||||
N_REACHED += 1;
|
||||
|
||||
ab_point.setX(intersect_X);
|
||||
ab_point.setY(intersect_Y);
|
||||
}
|
||||
else if(check_is_md_point && !is_md_start)
|
||||
{
|
||||
is_md_start = true;
|
||||
N_REACHED += 1;
|
||||
|
||||
md_point.setX(intersect_X);
|
||||
md_point.setY(intersect_Y);
|
||||
}
|
||||
// SAVE OTHERWISE!
|
||||
else if(check_intersect_line)
|
||||
{
|
||||
// Skip duplicate points on A, B, MD poi!
|
||||
if((is_ab_start && (ab_point == node_test)) ||
|
||||
(is_md_start && (md_point == node_test)))
|
||||
continue;
|
||||
|
||||
if(check_intersect_strict)
|
||||
{
|
||||
N_REACHED += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
N_INTSECD += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIX FRAGMENTATION WITH GEOMETRY
|
||||
//-------------------------------------------------------------------------
|
||||
if(N_REACHED == 2 && is_ab_start && is_md_start)
|
||||
{
|
||||
if(N_INTSECD == 2)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Force FALSE
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================//
|
||||
// MERGE PERIMETER
|
||||
//===========================================================================//
|
||||
|
||||
bool SitePolygonGraph::merge_perimeter()
|
||||
{
|
||||
SitePolygonGraphNode prev = _nodes[_size_nodes - 2];
|
||||
SitePolygonGraphNode last = _nodes[_size_nodes - 1];
|
||||
bool check = true;
|
||||
|
||||
if(_size_nodes > 2)
|
||||
{
|
||||
check = (check && add_arch(prev, last, true));
|
||||
_arches[0].setA(last);
|
||||
}
|
||||
else
|
||||
{
|
||||
check = (check && add_arch(last, prev, true));
|
||||
check = (check && add_arch(prev, last, true));
|
||||
}
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
//===========================================================================//
|
||||
// CHECK SAVED ARCHES
|
||||
//===========================================================================//
|
||||
|
||||
bool SitePolygonGraph::arch_exists(const SitePolygonGraphArch &arch)
|
||||
{
|
||||
if(_size_arches <= 0)
|
||||
return false;
|
||||
|
||||
for(index_type i = 0; i < _size_arches; i++)
|
||||
if(_arches[i] == arch)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//===========================================================================//
|
||||
// CALCULATE INTERSECTION FROM TWO ARCHES
|
||||
//===========================================================================//
|
||||
|
||||
bool SitePolygonGraph::get_xy_intersect(const SitePolygonGraphArch &arch1, const SitePolygonGraphArch &arch2, float &TX, float &TY, bool &DCHECK)
|
||||
{
|
||||
TX = float();
|
||||
TY = float();
|
||||
DCHECK = false;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Arch flag
|
||||
bool is_m1_null = false;
|
||||
bool is_m1_inf = false;
|
||||
bool is_m2_null = false;
|
||||
bool is_m2_inf = false;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Temporary save base_arch values
|
||||
float P1_X = arch1.getA().getX();
|
||||
float P1_Y = arch1.getA().getY();
|
||||
float P2_X = arch1.getB().getX();
|
||||
float P2_Y = arch1.getB().getY();
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Temporary save perimeter_arch values
|
||||
float P3_X = arch2.getA().getX();
|
||||
float P3_Y = arch2.getA().getY();
|
||||
float P4_X = arch2.getB().getX();
|
||||
float P4_Y = arch2.getB().getY();
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Swap values
|
||||
float PX_1 = P1_X > P2_X ? P2_X : P1_X;
|
||||
float PY_1 = P1_X > P2_X ? P2_Y : P1_Y;
|
||||
float PX_2 = P1_X > P2_X ? P1_X : P2_X;
|
||||
float PY_2 = P1_X > P2_X ? P1_Y : P2_Y;
|
||||
|
||||
float PX_3 = P3_X > P4_X ? P4_X : P3_X;
|
||||
float PY_3 = P3_X > P4_X ? P4_Y : P3_Y;
|
||||
float PX_4 = P3_X > P4_X ? P3_X : P4_X;
|
||||
float PY_4 = P3_X > P4_X ? P3_Y : P4_Y;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Calculate line ONE
|
||||
float DX_1 = PX_2 - PX_1;
|
||||
float DY_1 = PY_2 - PY_1;
|
||||
float M_1 = float();
|
||||
|
||||
if(DX_1 == 0)
|
||||
{
|
||||
is_m1_inf = true;
|
||||
M_1 = 0;
|
||||
}
|
||||
else if(DY_1 == 0)
|
||||
{
|
||||
is_m1_null = true;
|
||||
M_1 = 0;
|
||||
}
|
||||
else M_1 = DY_1 / DX_1;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Calculate intercept for line ONE
|
||||
float INTCP_1 = PY_1 - M_1 * PX_1;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Calculate line TWO
|
||||
float DX_2 = PX_4 - PX_3;
|
||||
float DY_2 = PY_4 - PY_3;
|
||||
float M_2 = float();
|
||||
|
||||
if(DX_2 == 0)
|
||||
{
|
||||
is_m2_inf = true;
|
||||
M_2 = 0;
|
||||
}
|
||||
else if(DY_2 == 0)
|
||||
{
|
||||
is_m2_null = true;
|
||||
M_2 = 0;
|
||||
}
|
||||
else M_2 = DY_2 / DX_2;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Calculate intercept for line TWO
|
||||
float INTCP_2 = PY_3 - M_2 * PX_3;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Check deltas
|
||||
if(((M_1 - M_2) != 0) || is_m1_inf || is_m2_inf)
|
||||
{
|
||||
// Calculate T parameter from segment equation
|
||||
float TK_1X = float();
|
||||
float TK_1Y = float();
|
||||
float TK_2X = float();
|
||||
float TK_2Y = float();
|
||||
|
||||
// Save temporary XY
|
||||
float IX = float();
|
||||
float IY = float();
|
||||
|
||||
if(M_1 != 0 && M_2 != 0)
|
||||
{
|
||||
IX = (INTCP_2 - INTCP_1) / (M_1 - M_2);
|
||||
IY = (M_1 * IX + INTCP_1);
|
||||
TK_1X = (IX - PX_1) / (PX_2 - PX_1);
|
||||
TK_1Y = (IY - PY_1) / (PY_2 - PY_1);
|
||||
TK_2X = (IX - PX_3) / (PX_4 - PX_3);
|
||||
TK_2Y = (IY - PY_3) / (PY_4 - PY_3);
|
||||
}
|
||||
else if(is_m1_inf && M_2 != 0)
|
||||
{
|
||||
IX = PX_1;
|
||||
IY = M_2 * IX + INTCP_2;
|
||||
TK_1X = 1;
|
||||
TK_1Y = (IY - PY_1) / (PY_2 - PY_1);
|
||||
TK_2X = (IX - PX_3) / (PX_4 - PX_3);
|
||||
TK_2Y = (IY - PY_3) / (PY_4 - PY_3);
|
||||
}
|
||||
else if(is_m1_null && M_2 != 0)
|
||||
{
|
||||
IY = PY_1;
|
||||
IX = (IY - INTCP_2) / M_2;
|
||||
TK_1Y = 1;
|
||||
TK_1X = (IX - PX_1) / (PX_2 - PX_1);
|
||||
TK_2X = (IX - PX_3) / (PX_4 - PX_3);
|
||||
TK_2Y = (IY - PY_3) / (PY_4 - PY_3);
|
||||
}
|
||||
else if(is_m2_inf && M_1 != 0)
|
||||
{
|
||||
IX = PX_3;
|
||||
IY = M_1 * IX + INTCP_1;
|
||||
TK_1X = (IX - PX_1) / (PX_2 - PX_1);
|
||||
TK_1Y = (IY - PY_1) / (PY_2 - PY_1);
|
||||
TK_2Y = (IY - PY_3) / (PY_4 - PY_3);
|
||||
TK_2X = 1;
|
||||
}
|
||||
else if(is_m2_null && M_1 != 0)
|
||||
{
|
||||
IY = PY_3;
|
||||
IX = (IY - INTCP_1) / M_1;
|
||||
TK_1X = (IX - PX_1) / (PX_2 - PX_1);
|
||||
TK_1Y = (IY - PY_1) / (PY_2 - PY_1);
|
||||
TK_2X = (IX - PX_3) / (PX_4 - PX_3);
|
||||
TK_2Y = 1;
|
||||
}
|
||||
else if((is_m1_null && is_m2_inf) || (is_m2_null && is_m1_inf))
|
||||
{
|
||||
IX = PX_1;
|
||||
IY = PY_3;
|
||||
|
||||
if(is_m1_null && is_m2_inf)
|
||||
{
|
||||
TK_1Y = 1;
|
||||
TK_1X = (IX - PX_1) / (PX_2 - PX_1);
|
||||
TK_2Y = (IY - PY_3) / (PY_4 - PY_3);
|
||||
TK_2X = 1;
|
||||
}
|
||||
else if(is_m2_null && is_m1_inf)
|
||||
{
|
||||
TK_1X = 1;
|
||||
TK_1Y = (IY - PY_1) / (PY_2 - PY_1);
|
||||
TK_2X = (IX - PX_3) / (PX_4 - PX_3);
|
||||
TK_2Y = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if T is valid into (0; 1)
|
||||
bool CKTK_1X = (TK_1X >= 0.0 && TK_1X <= 1.0);
|
||||
bool CKTK_1Y = (TK_1Y >= 0.0 && TK_1Y <= 1.0);
|
||||
bool CKTK_2X = (TK_2X >= 0.0 && TK_2X <= 1.0);
|
||||
bool CKTK_2Y = (TK_2Y >= 0.0 && TK_2Y <= 1.0);
|
||||
|
||||
// Double check
|
||||
bool T_CHECK = (CKTK_2X && CKTK_2Y);
|
||||
DCHECK = (CKTK_1X && CKTK_1Y && CKTK_2X && CKTK_2Y);
|
||||
|
||||
// Return value
|
||||
if(T_CHECK)
|
||||
{
|
||||
// Set XY
|
||||
TX = IX;
|
||||
TY = IY;
|
||||
|
||||
// Return TRUE
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Force FALSE
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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 "SitePolygonGraph.h"
|
||||
|
||||
//===========================================================================//
|
||||
// CLASS BASE METHODS
|
||||
//===========================================================================//
|
||||
|
||||
SitePolygonGraph::SitePolygonGraph()
|
||||
{
|
||||
// Commons
|
||||
_arches = 0;
|
||||
_nodes = 0;
|
||||
_size_nodes = 0;
|
||||
_size_arches = 0;
|
||||
_geometry = SitePolygonGraphGeometry();
|
||||
|
||||
// use current time as seed for random generator
|
||||
std::srand(std::time(0));
|
||||
}
|
||||
|
||||
SitePolygonGraph::~SitePolygonGraph()
|
||||
{
|
||||
// Mem. Leaks free
|
||||
if(!_nodes) return;
|
||||
delete[] _nodes;
|
||||
|
||||
// Mem. Leaks free
|
||||
if(!_arches) return;
|
||||
delete[] _arches;
|
||||
}
|
||||
|
||||
//===========================================================================//
|
||||
// ADD NEW NODE TO POOL
|
||||
//===========================================================================//
|
||||
|
||||
bool SitePolygonGraph::add_node(const SitePolygonGraphNode &node)
|
||||
{
|
||||
return add_node(node.getX(), node.getY());
|
||||
}
|
||||
|
||||
bool SitePolygonGraph::add_node(const float &x, const float &y)
|
||||
{
|
||||
if(!resize_nodes())
|
||||
return false;
|
||||
|
||||
_nodes[_size_nodes - 1].setX(x);
|
||||
_nodes[_size_nodes - 1].setY(y);
|
||||
|
||||
// Generate boundary rectangle
|
||||
generate_geometry();
|
||||
|
||||
if(_size_nodes > 1)
|
||||
return this->merge_perimeter();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================//
|
||||
// ADD NEW ARCH TO POOL
|
||||
//===========================================================================//
|
||||
|
||||
bool SitePolygonGraph::add_arch(const SitePolygonGraphNode &nodeA, const SitePolygonGraphNode &nodeB, bool skip_check)
|
||||
{
|
||||
SitePolygonGraphArch tmp;
|
||||
tmp.setA(nodeA);
|
||||
tmp.setB(nodeB);
|
||||
|
||||
// Check selector
|
||||
bool check = skip_check ? true : generate_geometry_fragmentation(tmp);
|
||||
|
||||
// CHECK FOR FRAGMENTATION
|
||||
if(check)
|
||||
{
|
||||
if(!resize_arches())
|
||||
return false;
|
||||
|
||||
// SAVE ARCH AND RETURN
|
||||
_arches[_size_arches - 1].set(tmp);
|
||||
}
|
||||
else return false;
|
||||
|
||||
// Force TRUE
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================//
|
||||
// FINALIZE CREATION OF POLYGON (GEOMETRY INSCRIBED)
|
||||
//===========================================================================//
|
||||
|
||||
void SitePolygonGraph::finalize_polygon()
|
||||
{
|
||||
// Arches filtering
|
||||
generate_geometry_inscribed();
|
||||
}
|
||||
|
||||
//===========================================================================//
|
||||
// CALCULATE RANDOM POINT ON RANDOM ARCH FOR SPAWN POI
|
||||
//===========================================================================//
|
||||
|
||||
SitePolygonGraphNode SitePolygonGraph::randomize_poi()
|
||||
{
|
||||
SitePolygonGraphNode poi_node;
|
||||
index_type i_poi[SITE_POLYGON_GRAPH_MAX_VERTEX];
|
||||
|
||||
if(_size_arches <= 0 || _size_arches <= 0)
|
||||
return poi_node;
|
||||
|
||||
for(index_type i = 0; i < SITE_POLYGON_GRAPH_MAX_VERTEX; i++)
|
||||
i_poi[i] = std::rand() % _size_arches;
|
||||
|
||||
index_type i_idx = std::rand() % SITE_POLYGON_GRAPH_MAX_VERTEX;
|
||||
float i_segment = ((float) std::rand() / RAND_MAX);
|
||||
SitePolygonGraphArch arch = _arches[i_poi[i_idx]];
|
||||
float x_segment = arch.getA().getX() + i_segment * (arch.getB().getX() - arch.getA().getX());
|
||||
float y_segment = arch.getA().getY() + i_segment * (arch.getB().getY() - arch.getA().getY());
|
||||
|
||||
poi_node.setX(x_segment);
|
||||
poi_node.setY(y_segment);
|
||||
|
||||
return poi_node;
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2017 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 SITE_POLYGON_GRAPH_GENERATOR_H
|
||||
#define SITE_POLYGON_GRAPH_GENERATOR_H
|
||||
|
||||
#include <cstdlib> /* srand, rand */
|
||||
#include <ctime> /* time */
|
||||
#include <cmath> /* math, roundf */
|
||||
|
||||
//===========================================================================//
|
||||
// GLOBAL DEFINE
|
||||
//===========================================================================//
|
||||
|
||||
#define SITE_POLYGON_GRAPH_MAX_VERTEX 12
|
||||
|
||||
//===========================================================================//
|
||||
// POLYGON SUB-STRUCT FOR NODES
|
||||
//===========================================================================//
|
||||
|
||||
struct SitePolygonGraphNode
|
||||
{
|
||||
public:
|
||||
SitePolygonGraphNode()
|
||||
{
|
||||
_pointX = float();
|
||||
_pointY = float();
|
||||
}
|
||||
|
||||
bool operator==(const SitePolygonGraphNode &other) const
|
||||
{
|
||||
float tX = other.getX();
|
||||
float tY = other.getY();
|
||||
|
||||
float cX_m = _pointX - 0.1;
|
||||
float cY_m = _pointY - 0.1;
|
||||
float cX_p = _pointX + 0.1;
|
||||
float cY_p = _pointY + 0.1;
|
||||
|
||||
bool x = (cX_m <= tX && tX <= cX_p);
|
||||
bool y = (cY_m <= tY && tY <= cY_p);
|
||||
|
||||
if(x && y) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
void set(const SitePolygonGraphNode &node) { _pointX = node.getX(); _pointY = node.getY(); _round_p(); }
|
||||
void set(const float &x, const float &y) { _pointX = x; _pointY = y; _round_p(); }
|
||||
|
||||
void setX(const float &x) { _pointX = x; _round_p(); }
|
||||
void setY(const float &y) { _pointY = y; _round_p(); }
|
||||
|
||||
const float getX() const { return _pointX; }
|
||||
const float getY() const { return _pointY; }
|
||||
|
||||
const SitePolygonGraphNode get() const { return (*this); }
|
||||
|
||||
private:
|
||||
void _round_p()
|
||||
{
|
||||
_pointX = roundf(_pointX * 10) / 10;
|
||||
_pointY = roundf(_pointY * 10) / 10;
|
||||
}
|
||||
|
||||
float _pointX;
|
||||
float _pointY;
|
||||
};
|
||||
|
||||
//===========================================================================//
|
||||
// POLYGON SUB-STRUCT FOR ARCHES
|
||||
//===========================================================================//
|
||||
|
||||
struct SitePolygonGraphArch
|
||||
{
|
||||
public:
|
||||
SitePolygonGraphArch()
|
||||
{
|
||||
_pointA = SitePolygonGraphNode();
|
||||
_pointB = SitePolygonGraphNode();
|
||||
_midpoint = SitePolygonGraphNode();
|
||||
}
|
||||
|
||||
void set(const SitePolygonGraphArch &arch)
|
||||
{
|
||||
_pointA.set(arch.getA());
|
||||
_pointB.set(arch.getB());
|
||||
|
||||
_calculateMidPoint();
|
||||
}
|
||||
|
||||
bool operator==(const SitePolygonGraphArch &other) const
|
||||
{
|
||||
bool an = (other.getA() == _pointA);
|
||||
bool bn = (other.getB() == _pointB);
|
||||
bool ai = (other.getA() == _pointB);
|
||||
bool bi = (other.getB() == _pointA);
|
||||
|
||||
if((an && bn) || (ai && bi)) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
void setA(const SitePolygonGraphNode &node) { _pointA.set(node.get()); _calculateMidPoint(); }
|
||||
void setB(const SitePolygonGraphNode &node) { _pointB.set(node.get()); _calculateMidPoint(); }
|
||||
|
||||
void setA(const float &x, const float &y) { _pointA.set(x, y); _calculateMidPoint(); }
|
||||
void setB(const float &x, const float &y) { _pointB.set(x, y); _calculateMidPoint(); }
|
||||
|
||||
const SitePolygonGraphArch get() const { return (*this); }
|
||||
const SitePolygonGraphNode getA() const { return _pointA; }
|
||||
const SitePolygonGraphNode getB() const { return _pointB; }
|
||||
const SitePolygonGraphNode getMidPoint() const { return _midpoint; }
|
||||
|
||||
private:
|
||||
void _calculateMidPoint()
|
||||
{
|
||||
float midX = (_pointB.getX() + _pointA.getX()) / 2;
|
||||
float midY = (_pointB.getY() + _pointA.getY()) / 2;
|
||||
|
||||
_midpoint.set(midX, midY);
|
||||
}
|
||||
|
||||
SitePolygonGraphNode _pointA;
|
||||
SitePolygonGraphNode _pointB;
|
||||
SitePolygonGraphNode _midpoint;
|
||||
};
|
||||
|
||||
//===========================================================================//
|
||||
// POLYGON SUB-STRUCT FOR GEOMETRY
|
||||
//===========================================================================//
|
||||
|
||||
struct SitePolygonGraphGeometry
|
||||
{
|
||||
public:
|
||||
SitePolygonGraphGeometry()
|
||||
{
|
||||
_archL = SitePolygonGraphArch();
|
||||
_archB = SitePolygonGraphArch();
|
||||
_archR = SitePolygonGraphArch();
|
||||
_archT = SitePolygonGraphArch();
|
||||
_isNull = true;
|
||||
}
|
||||
|
||||
void set(const SitePolygonGraphGeometry &geo)
|
||||
{
|
||||
_archL.set(geo.getLeft());
|
||||
_archB.set(geo.getBottom());
|
||||
_archR.set(geo.getRight());
|
||||
_archT.set(geo.getTop());
|
||||
}
|
||||
|
||||
void setLeft(const SitePolygonGraphArch &arch) { _archL.set(arch.get()); }
|
||||
void setBottom(const SitePolygonGraphArch &arch) { _archB.set(arch.get()); }
|
||||
void setRight(const SitePolygonGraphArch &arch) { _archR.set(arch.get()); }
|
||||
void setTop(const SitePolygonGraphArch &arch) { _archT.set(arch.get()); }
|
||||
void setNull(const bool &val) { _isNull = val; }
|
||||
|
||||
void setLeft(const SitePolygonGraphNode &nodeA,
|
||||
const SitePolygonGraphNode &nodeB) { _archL.setA(nodeA); _archL.setB(nodeB); }
|
||||
void setBottom(const SitePolygonGraphNode &nodeA,
|
||||
const SitePolygonGraphNode &nodeB) { _archB.setA(nodeA); _archB.setB(nodeB); }
|
||||
void setRight(const SitePolygonGraphNode &nodeA,
|
||||
const SitePolygonGraphNode &nodeB) { _archR.setA(nodeA); _archR.setB(nodeB); }
|
||||
void setTop(const SitePolygonGraphNode &nodeA,
|
||||
const SitePolygonGraphNode &nodeB) { _archT.setA(nodeA); _archT.setB(nodeB); }
|
||||
|
||||
void setLeft(const float &ax, const float &ay,
|
||||
const float &bx, const float &by) { _archL.setA(ax, ay); _archL.setB(bx, by); }
|
||||
void setBottom(const float &ax, const float &ay,
|
||||
const float &bx, const float &by) { _archB.setA(ax, ay); _archB.setB(bx, by); }
|
||||
void setRight(const float &ax, const float &ay,
|
||||
const float &bx, const float &by) { _archR.setA(ax, ay); _archR.setB(bx, by); }
|
||||
void setTop(const float &ax, const float &ay,
|
||||
const float &bx, const float &by) { _archT.setA(ax, ay); _archT.setB(bx, by); }
|
||||
|
||||
const SitePolygonGraphGeometry get() const { return (*this); }
|
||||
const SitePolygonGraphArch getLeft() const { return _archL; }
|
||||
const SitePolygonGraphArch getBottom() const { return _archB; }
|
||||
const SitePolygonGraphArch getRight() const { return _archR; }
|
||||
const SitePolygonGraphArch getTop() const { return _archT; }
|
||||
const bool isNull() const { return _isNull; }
|
||||
|
||||
private:
|
||||
SitePolygonGraphArch _archL;
|
||||
SitePolygonGraphArch _archR;
|
||||
SitePolygonGraphArch _archT;
|
||||
SitePolygonGraphArch _archB;
|
||||
bool _isNull;
|
||||
};
|
||||
|
||||
//===========================================================================//
|
||||
// POLYGON GRAPH MASTER CLASS
|
||||
//===========================================================================//
|
||||
|
||||
class SitePolygonGraph
|
||||
{
|
||||
public:
|
||||
SitePolygonGraph();
|
||||
~SitePolygonGraph();
|
||||
|
||||
bool add_node(const SitePolygonGraphNode &node);
|
||||
bool add_node(const float &x, const float &y);
|
||||
bool add_arch(const SitePolygonGraphNode &nodeA, const SitePolygonGraphNode &nodeB, bool skip_check = false);
|
||||
|
||||
void finalize_polygon();
|
||||
SitePolygonGraphNode randomize_poi();
|
||||
|
||||
private:
|
||||
bool resize_nodes();
|
||||
bool resize_arches();
|
||||
|
||||
bool merge_perimeter();
|
||||
bool arch_exists(const SitePolygonGraphArch &arch);
|
||||
|
||||
void generate_geometry();
|
||||
void generate_geometry_inscribed();
|
||||
bool generate_geometry_fragmentation(SitePolygonGraphArch &base_arch);
|
||||
|
||||
bool get_xy_intersect(const SitePolygonGraphArch &arch1, const SitePolygonGraphArch &arch2, float &TX, float &TY, bool &dcheck);
|
||||
|
||||
typedef unsigned int index_type;
|
||||
typedef float value_type;
|
||||
|
||||
SitePolygonGraphNode* _nodes;
|
||||
SitePolygonGraphArch* _arches;
|
||||
SitePolygonGraphGeometry _geometry;
|
||||
|
||||
index_type _size_nodes;
|
||||
index_type _size_arches;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------//
|
||||
|
||||
#endif // SITE_POLYGON_GRAPH_GENERATOR_H
|
||||
@@ -5440,12 +5440,6 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
|
||||
if (ReqValue > skillValue)
|
||||
return SPELL_FAILED_LOW_CASTLEVEL;
|
||||
|
||||
// chance for fail at orange skinning attempt
|
||||
if ((m_selfContainer && (*m_selfContainer) == this) &&
|
||||
skillValue < sWorld->GetConfigMaxSkillValue() &&
|
||||
(ReqValue < 0 ? 0 : ReqValue) > irand(skillValue - 25, skillValue + 37))
|
||||
return SPELL_FAILED_TRY_AGAIN;
|
||||
|
||||
break;
|
||||
}
|
||||
case SPELL_EFFECT_OPEN_LOCK:
|
||||
@@ -5504,10 +5498,10 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint
|
||||
// second check prevent fail at rechecks
|
||||
if (skillId != SKILL_NONE && (!m_selfContainer || ((*m_selfContainer) != this)))
|
||||
{
|
||||
bool canFailAtMax = skillId != SKILL_HERBALISM && skillId != SKILL_MINING;
|
||||
bool canFailAtMax = skillId != SKILL_HERBALISM && skillId != SKILL_MINING && skillId != SKILL_ARCHAEOLOGY;
|
||||
|
||||
// chance for failure in orange gather / lockpick (gathering skill can't fail at maxskill)
|
||||
if ((canFailAtMax || skillValue < sWorld->GetConfigMaxSkillValue()) && reqSkillValue > irand(skillValue - 25, skillValue + 37))
|
||||
if ((canFailAtMax && skillValue < sWorld->GetConfigMaxSkillValue()) && reqSkillValue > irand(skillValue - 25, skillValue + 37))
|
||||
return SPELL_FAILED_TRY_AGAIN;
|
||||
}
|
||||
break;
|
||||
@@ -7312,7 +7306,6 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk
|
||||
if (skillValue < reqSkillValue)
|
||||
return SPELL_FAILED_LOW_CASTLEVEL;
|
||||
}
|
||||
|
||||
return SPELL_CAST_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,6 +282,7 @@ class TC_GAME_API Spell
|
||||
void EffectHealMaxHealth(SpellEffIndex effIndex);
|
||||
void EffectInterruptCast(SpellEffIndex effIndex);
|
||||
void EffectSummonObjectWild(SpellEffIndex effIndex);
|
||||
void EffectSurvey(SpellEffIndex effIndex);
|
||||
void EffectSummonRaidMarker(SpellEffIndex effIndex);
|
||||
void EffectSummonDynObj(SpellEffIndex effIndex);
|
||||
void EffectScriptEffect(SpellEffIndex effIndex);
|
||||
|
||||
@@ -167,7 +167,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
|
||||
&Spell::EffectDismissPet, //102 SPELL_EFFECT_DISMISS_PET
|
||||
&Spell::EffectReputation, //103 SPELL_EFFECT_REPUTATION
|
||||
&Spell::EffectSummonObject, //104 SPELL_EFFECT_SUMMON_OBJECT_SLOT1
|
||||
&Spell::EffectSummonObject, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2
|
||||
&Spell::EffectSurvey, //105 SPELL_EFFECT_SUMMON_OBJECT_SLOT2
|
||||
&Spell::EffectSummonRaidMarker, //106 SPELL_EFFECT_SUMMON_OBJECT_SLOT3
|
||||
&Spell::EffectSummonObject, //107 SPELL_EFFECT_SUMMON_OBJECT_SLOT4
|
||||
&Spell::EffectDispelMechanic, //108 SPELL_EFFECT_DISPEL_MECHANIC
|
||||
@@ -1422,6 +1422,14 @@ void Spell::DoCreateItem(uint32 /*i*/, uint32 itemtype)
|
||||
|
||||
if (num_to_add)
|
||||
{
|
||||
uint32 projectId = GetSpellInfo()->ResearchProjectId;
|
||||
|
||||
if (projectId && !player->ArchProjectCompleteable(projectId))
|
||||
{
|
||||
player->SendEquipError(EQUIP_ERR_SPELL_FAILED_REAGENTS_GENERIC, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
// create the new item and store it
|
||||
Item* pItem = player->StoreNewItem(dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
|
||||
|
||||
@@ -1432,6 +1440,9 @@ void Spell::DoCreateItem(uint32 /*i*/, uint32 itemtype)
|
||||
return;
|
||||
}
|
||||
|
||||
if (projectId)
|
||||
player->CompleteArchProject(projectId);
|
||||
|
||||
// set the "Crafted by ..." property of the item
|
||||
if (pItem->GetTemplate()->Class != ITEM_CLASS_CONSUMABLE && pItem->GetTemplate()->Class != ITEM_CLASS_QUEST && newitemid != 6265 && newitemid != 6948)
|
||||
pItem->SetGuidValue(ITEM_FIELD_CREATOR, player->GetGUID());
|
||||
@@ -1789,7 +1800,12 @@ void Spell::EffectOpenLock(SpellEffIndex effIndex)
|
||||
}
|
||||
|
||||
if (gameObjTarget)
|
||||
SendLoot(guid, LOOT_SKINNING);
|
||||
{
|
||||
if (skillId == SKILL_ARCHAEOLOGY)
|
||||
SendLoot(guid, LOOT_ARCHAEOLOGY);
|
||||
else
|
||||
SendLoot(guid, LOOT_SKINNING);
|
||||
}
|
||||
else if (itemTarget)
|
||||
itemTarget->SetFlag(ITEM_FIELD_FLAGS, ITEM_FIELD_FLAG_UNLOCKED);
|
||||
|
||||
@@ -3173,6 +3189,19 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex)
|
||||
}
|
||||
}
|
||||
|
||||
void Spell::EffectSurvey(SpellEffIndex effIndex)
|
||||
{
|
||||
if (effectHandleMode != SPELL_EFFECT_HANDLE_LAUNCH)
|
||||
return;
|
||||
|
||||
if (!m_caster || m_spellInfo->Id != uint32(80451) || effIndex != EFFECT_0)
|
||||
return;
|
||||
|
||||
if (Player *player = m_caster->ToPlayer())
|
||||
if (player->HasSkill(SKILL_ARCHAEOLOGY))
|
||||
player->SurveyDigSite();
|
||||
}
|
||||
|
||||
void Spell::EffectScriptEffect(SpellEffIndex effIndex)
|
||||
{
|
||||
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
|
||||
|
||||
@@ -908,6 +908,7 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntry const** effe
|
||||
SpellShapeshiftId = spellEntry->SpellShapeshiftId;
|
||||
SpellTargetRestrictionsId = spellEntry->SpellTargetRestrictionsId;
|
||||
SpellTotemsId = spellEntry->SpellTotemsId;
|
||||
ResearchProjectId = spellEntry->ResearchProjectId;
|
||||
|
||||
// SpellDifficultyEntry
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
|
||||
@@ -417,6 +417,7 @@ class TC_GAME_API SpellInfo
|
||||
uint32 SpellShapeshiftId;
|
||||
uint32 SpellTargetRestrictionsId;
|
||||
uint32 SpellTotemsId;
|
||||
uint32 ResearchProjectId;
|
||||
// SpellScalingEntry
|
||||
int32 CastTimeMin;
|
||||
int32 CastTimeMax;
|
||||
|
||||
@@ -1826,6 +1826,9 @@ void World::SetInitialWorldSettings()
|
||||
TC_LOG_INFO("server.loading", "Loading Skill Fishing base level requirements...");
|
||||
sObjectMgr->LoadFishingBaseSkillLevel();
|
||||
|
||||
TC_LOG_INFO("server.loading", "Loading Archaeology store...");
|
||||
sArchaeologyMgr->LoadData();
|
||||
|
||||
TC_LOG_INFO("server.loading", "Loading Achievements...");
|
||||
sAchievementMgr->LoadAchievementReferenceList();
|
||||
TC_LOG_INFO("server.loading", "Loading Achievement Criteria Lists...");
|
||||
|
||||
Reference in new issue
Block a user