Core/Skills: implement Archaeology

This commit is contained in:
Ovalord committed 2017-11-09 03:58:28 +01:00
1 parent 899603d352
commit c868e10d9b
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;
}
+12
View File
@@ -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
+12 -1
View File
@@ -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
+6
View File
@@ -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;
+77 -1
View File
@@ -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
+7 -1
View File
@@ -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
+48 -5
View File
@@ -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
+12
View File
@@ -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);
+1 -1
View File
@@ -136,7 +136,7 @@ void WorldSession::HandleLootCurrencyOpcode(WorldPacket& recvData)
return;
}
loot->NotifyCurrencyRemoved(lootSlot);
player->StoreLootCurrency(lootSlot, loot);
}
void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/)
+6
View File
@@ -2096,3 +2096,9 @@ void WorldSession::SendStreamingMovie()
SendPacket(&data);
}
void WorldSession::HandleRequestResearchHistory(WorldPacket & /*recv_data*/)
{
if (Player* player = GetPlayer())
player->NotifyRequestResearchHistory();
}
+10 -6
View File
@@ -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
+34
View File
@@ -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);
+25 -2
View File
@@ -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);
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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);
+1
View File
@@ -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
+2 -9
View File
@@ -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;
}
}
+1
View File
@@ -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);
+31 -2
View File
@@ -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)
+1
View File
@@ -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)
+1
View File
@@ -417,6 +417,7 @@ class TC_GAME_API SpellInfo
uint32 SpellShapeshiftId;
uint32 SpellTargetRestrictionsId;
uint32 SpellTotemsId;
uint32 ResearchProjectId;
// SpellScalingEntry
int32 CastTimeMin;
int32 CastTimeMax;
+3
View File
@@ -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...");