diff options
38 files changed, 5504 insertions, 46 deletions
diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 27a9f4be522..4abfe487c20 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -168,6 +168,56 @@ LOCK TABLES `autobroadcast` WRITE; UNLOCK TABLES; -- +-- Table structure for table `battle_pets` +-- + +DROP TABLE IF EXISTS `battle_pets`; +CREATE TABLE `battle_pets` ( + `guid` bigint(20) NOT NULL, + `battlenetAccountId` int(10) NOT NULL, + `species` int(10) NOT NULL, + `breed` smallint(5) NOT NULL, + `level` smallint(5) NOT NULL DEFAULT '1', + `exp` smallint(5) NOT NULL DEFAULT '0', + `health` int(10) NOT NULL DEFAULT '1', + `quality` tinyint(3) NOT NULL DEFAULT '0', + `flags` smallint(5) NOT NULL DEFAULT '0', + `name` varchar(12) NOT NULL, + PRIMARY KEY (`guid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `battle_pets` +-- + +LOCK TABLES `battle_pets` WRITE; +/*!40000 ALTER TABLE `battle_pets` DISABLE KEYS */; +/*!40000 ALTER TABLE `battle_pets` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `battle_pet_slots` +-- + +DROP TABLE IF EXISTS `battle_pet_slots`; +CREATE TABLE `battle_pet_slots` ( + `id` tinyint(3) NOT NULL, + `battlenetAccountId` int(10) NOT NULL, + `battlePetGuid` bigint(20) NOT NULL, + `locked` tinyint(3) NOT NULL DEFAULT '1', + PRIMARY KEY (`id`,`battlenetAccountId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `battle_pet_slots` +-- + +LOCK TABLES `battle_pet_slots` WRITE; +/*!40000 ALTER TABLE `battle_pet_slots` DISABLE KEYS */; +/*!40000 ALTER TABLE `battle_pet_slots` ENABLE KEYS */; +UNLOCK TABLES; + +-- -- Table structure for table `battlenet_account_bans` -- diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index 57db40a7ee4..50195e9bda7 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -2523,6 +2523,10 @@ CREATE TABLE `item_instance` ( `transmogrification` int(10) unsigned NOT NULL DEFAULT '0', `upgradeId` int(10) unsigned NOT NULL DEFAULT '0', `enchantIllusion` int(10) unsigned NOT NULL DEFAULT '0', + `battlePetSpeciesId` int(10) unsigned NOT NULL DEFAULT '0', + `battlePetBreedData` int(10) unsigned NOT NULL DEFAULT '0', + `battlePetLevel` smallint(5) unsigned NOT NULL DEFAULT '0', + `battlePetDisplayId` int(10) unsigned NOT NULL DEFAULT '0', `bonusListIDs` text, PRIMARY KEY (`guid`), KEY `idx_owner_guid` (`owner_guid`) diff --git a/sql/updates/auth/2015_09_09_00_auth.sql b/sql/updates/auth/2015_09_09_00_auth.sql new file mode 100644 index 00000000000..ccb5d97cf4a --- /dev/null +++ b/sql/updates/auth/2015_09_09_00_auth.sql @@ -0,0 +1,31 @@ +-- +-- Table structure for table `battle_pets` +-- + +DROP TABLE IF EXISTS `battle_pets`; +CREATE TABLE `battle_pets` ( + `guid` bigint(20) NOT NULL, + `battlenetAccountId` int(10) NOT NULL, + `species` int(10) NOT NULL, + `breed` smallint(5) NOT NULL, + `level` smallint(5) NOT NULL DEFAULT '1', + `exp` smallint(5) NOT NULL DEFAULT '0', + `health` int(10) NOT NULL DEFAULT '1', + `quality` tinyint(3) NOT NULL DEFAULT '0', + `flags` smallint(5) NOT NULL DEFAULT '0', + `name` varchar(12) NOT NULL, + PRIMARY KEY (`guid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `battle_pet_slots` +-- + +DROP TABLE IF EXISTS `battle_pet_slots`; +CREATE TABLE `battle_pet_slots` ( + `id` tinyint(3) NOT NULL, + `battlenetAccountId` int(10) NOT NULL, + `battlePetGuid` bigint(20) NOT NULL, + `locked` tinyint(3) NOT NULL DEFAULT '1', + PRIMARY KEY (`id`,`battlenetAccountId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/sql/updates/characters/2015_09_09_00_characters.sql b/sql/updates/characters/2015_09_09_00_characters.sql new file mode 100644 index 00000000000..d6ceca53f38 --- /dev/null +++ b/sql/updates/characters/2015_09_09_00_characters.sql @@ -0,0 +1,5 @@ +ALTER TABLE `item_instance` + ADD `battlePetSpeciesId` int(10) unsigned NOT NULL DEFAULT '0' AFTER `enchantIllusion`, + ADD `battlePetBreedData` int(10) unsigned NOT NULL DEFAULT '0' AFTER `battlePetSpeciesId`, + ADD `battlePetLevel` smallint(5) unsigned NOT NULL DEFAULT '0' AFTER `battlePetBreedData`, + ADD `battlePetDisplayId` int(10) unsigned NOT NULL DEFAULT '0' AFTER `battlePetLevel`; diff --git a/sql/updates/hotfixes/2015_09_09_00_hotfixes.sql b/sql/updates/hotfixes/2015_09_09_00_hotfixes.sql new file mode 100644 index 00000000000..1ca4e984e0b --- /dev/null +++ b/sql/updates/hotfixes/2015_09_09_00_hotfixes.sql @@ -0,0 +1,66 @@ +DELETE FROM `battle_pet_species` WHERE `ID` IN (1449,1636); -- already in BattlePetSpecies.db2 + +-- +-- Table structure for table `battle_pet_breed_quality` +-- + +DROP TABLE IF EXISTS `battle_pet_breed_quality`; +CREATE TABLE `battle_pet_breed_quality` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `Quality` int(10) unsigned NOT NULL DEFAULT '0', + `Modifier` int(11) NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `battle_pet_breed_state` +-- + +DROP TABLE IF EXISTS `battle_pet_breed_state`; +CREATE TABLE `battle_pet_breed_state` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `BreedID` int(10) unsigned NOT NULL DEFAULT '0', + `State` int(10) unsigned NOT NULL DEFAULT '0', + `Value` int(11) NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `battle_pet_species_locale` +-- + +DROP TABLE IF EXISTS `battle_pet_species_locale`; +CREATE TABLE `battle_pet_species_locale` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `locale` varchar(4) NOT NULL, + `SourceText` text, + `Description` text, + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`locale`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `battle_pet_species_state` +-- + +DROP TABLE IF EXISTS `battle_pet_species_state`; +CREATE TABLE `battle_pet_species_state` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `SpeciesID` int(10) unsigned NOT NULL DEFAULT '0', + `State` int(10) unsigned NOT NULL DEFAULT '0', + `Value` int(11) NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `item_to_battle_pet_species` +-- + +DROP TABLE IF EXISTS `item_to_battle_pet_species`; +CREATE TABLE `item_to_battle_pet_species` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `BattlePetSpeciesID` int(10) unsigned NOT NULL DEFAULT '0' +) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/sql/updates/world/2015_09_09_00_world.sql b/sql/updates/world/2015_09_09_00_world.sql new file mode 100644 index 00000000000..5bd7b48aaf9 --- /dev/null +++ b/sql/updates/world/2015_09_09_00_world.sql @@ -0,0 +1,3928 @@ +/* +Sources: http://petsear.ch/excel/Breeds/BreedsPerPet.xlsx + http://petsear.ch/Breeds/TamerPets + http://www.wowhead.com + +TODO: Around 90 battle pets missing here, these are kind of special cases (non-combat pets etc.) or as of 6.2.2 + some new pets available only during some world events (Feast of Winter Veil, Hallow's End) - data not gathered yet. + Sort out what to do with them. +*/ + +-- +-- Table structure for table `battle_pet_breeds` +-- + +DROP TABLE IF EXISTS `battle_pet_breeds`; +CREATE TABLE `battle_pet_breeds` ( + `speciesId` int(10) unsigned NOT NULL DEFAULT '0', + `breedId` smallint(5) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`speciesId`,`breedId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `battle_pet_breeds` +-- + +INSERT INTO `battle_pet_breeds` (`speciesId`,`breedId`) VALUES +(39,11), +(39,21), +(40,8), +(40,18), +(41,4), +(42,7), +(43,3), +(43,13), +(44,5), +(44,15), +(45,3), +(46,12), +(46,22), +(47,3), +(47,5), +(47,13), +(47,15), +(49,3), +(50,11), +(50,21), +(51,3), +(51,5), +(51,13), +(51,15), +(52,13), +(52,20), +(52,21), +(52,22), +(55,3), +(55,5), +(55,6), +(55,9), +(55,13), +(55,15), +(55,16), +(55,19), +(56,18), +(57,4), +(58,8), +(58,18), +(59,19), +(64,9), +(65,12), +(65,22), +(67,3), +(67,8), +(67,10), +(67,13), +(67,18), +(67,20), +(68,3), +(68,6), +(68,7), +(68,13), +(68,16), +(68,17), +(69,3), +(69,10), +(69,11), +(69,13), +(69,20), +(69,21), +(70,3), +(70,5), +(70,12), +(70,13), +(70,15), +(70,22), +(72,3), +(72,5), +(72,11), +(72,13), +(72,15), +(72,21), +(74,11), +(74,21), +(75,5), +(75,15), +(77,3), +(77,13), +(78,12), +(78,22), +(83,18), +(84,13), +(84,20), +(84,21), +(84,22), +(85,9), +(86,7), +(87,5), +(89,6), +(90,17), +(92,3), +(93,4), +(94,5), +(95,3), +(106,10), +(107,3), +(111,12), +(114,12), +(115,3), +(116,12), +(117,3), +(118,3), +(119,3), +(120,13), +(121,13), +(122,5), +(124,3), +(125,5), +(126,10), +(127,7), +(128,3), +(130,3), +(131,8), +(132,6), +(136,3), +(136,7), +(136,10), +(136,12), +(136,13), +(136,17), +(136,20), +(136,22), +(137,3), +(137,5), +(137,11), +(137,13), +(137,15), +(137,21), +(138,3), +(138,12), +(138,13), +(138,22), +(139,3), +(139,8), +(139,12), +(139,13), +(139,18), +(139,22), +(140,3), +(140,4), +(140,12), +(140,13), +(140,14), +(140,22), +(141,3), +(141,6), +(141,12), +(141,13), +(141,16), +(141,22), +(142,3), +(142,5), +(142,13), +(142,15), +(143,3), +(143,5), +(143,8), +(143,13), +(143,15), +(143,18), +(144,3), +(144,5), +(144,11), +(144,13), +(144,15), +(144,21), +(145,3), +(145,5), +(145,6), +(145,8), +(145,13), +(145,15), +(145,16), +(145,18), +(146,3), +(146,5), +(146,9), +(146,12), +(149,9), +(153,7), +(155,7), +(156,3), +(157,3), +(158,3), +(159,16), +(160,4), +(162,10), +(163,8), +(164,3), +(165,9), +(166,7), +(167,3), +(167,6), +(167,9), +(167,13), +(167,16), +(167,19), +(168,15), +(169,3), +(169,5), +(170,7), +(171,7), +(172,10), +(173,7), +(174,3), +(175,5), +(179,7), +(180,7), +(183,3), +(186,3), +(186,4), +(186,5), +(186,8), +(186,13), +(186,14), +(186,15), +(186,18), +(187,8), +(188,6), +(189,3), +(190,6), +(190,7), +(190,12), +(191,3), +(192,9), +(193,4), +(194,3), +(194,5), +(194,8), +(194,9), +(194,11), +(194,13), +(194,15), +(194,18), +(194,19), +(194,21), +(195,5), +(195,8), +(195,9), +(195,11), +(195,15), +(195,18), +(195,19), +(195,21), +(196,7), +(197,8), +(198,11), +(199,10), +(200,15), +(201,7), +(202,7), +(203,22), +(204,3), +(205,7), +(206,3), +(206,9), +(206,11), +(206,13), +(206,19), +(206,21), +(207,8), +(207,18), +(209,3), +(209,13), +(210,5), +(211,6), +(212,3), +(213,5), +(215,10), +(215,20), +(217,7), +(218,4), +(220,9), +(224,10), +(224,20), +(225,3), +(226,4), +(227,4), +(228,7), +(229,3), +(231,3), +(232,8), +(233,18), +(234,10), +(235,20), +(236,6), +(236,16), +(237,3), +(238,21), +(239,14), +(240,3), +(241,12), +(242,8), +(243,20), +(244,7), +(245,8), +(246,3), +(247,6), +(248,8), +(249,7), +(250,8), +(251,3), +(253,3), +(254,3), +(254,5), +(254,8), +(254,13), +(254,15), +(254,18), +(255,6), +(256,7), +(258,6), +(259,12), +(260,8), +(261,4), +(262,5), +(264,8), +(265,6), +(266,18), +(267,3), +(268,4), +(270,9), +(271,3), +(271,9), +(271,10), +(271,13), +(271,19), +(271,20), +(272,6), +(272,9), +(272,16), +(272,19), +(277,11), +(278,9), +(279,8), +(285,10), +(286,7), +(287,3), +(289,6), +(291,22), +(292,3), +(293,9), +(294,8), +(296,3), +(297,4), +(298,3), +(301,11), +(302,7), +(303,15), +(306,21), +(307,3), +(308,3), +(309,18), +(310,8), +(311,3), +(316,3), +(317,3), +(318,3), +(319,20), +(320,17), +(321,6), +(323,8), +(325,5), +(325,8), +(325,10), +(325,15), +(325,18), +(325,20), +(328,4), +(329,8), +(330,10), +(333,11), +(335,12), +(337,12), +(338,7), +(339,12), +(340,13), +(341,3), +(342,3), +(343,3), +(343,8), +(343,13), +(343,18), +(346,3), +(347,3), +(348,8), +(374,7), +(374,8), +(374,9), +(374,10), +(374,11), +(374,12), +(374,17), +(374,18), +(374,19), +(374,20), +(374,21), +(374,22), +(378,3), +(378,5), +(378,7), +(378,9), +(378,11), +(378,12), +(378,13), +(378,17), +(378,19), +(378,21), +(378,22), +(379,3), +(379,5), +(379,10), +(379,11), +(379,12), +(379,13), +(379,15), +(379,20), +(379,21), +(379,22), +(380,3), +(380,12), +(380,13), +(380,22), +(381,9), +(381,19), +(383,8), +(383,11), +(383,18), +(383,21), +(385,3), +(385,5), +(385,8), +(385,11), +(385,12), +(385,13), +(385,15), +(385,18), +(385,21), +(385,22), +(386,3), +(386,5), +(386,11), +(386,13), +(386,15), +(386,21), +(387,3), +(387,5), +(387,13), +(387,15), +(388,3), +(388,6), +(388,7), +(388,13), +(388,16), +(388,17), +(389,3), +(389,4), +(389,5), +(389,6), +(389,7), +(389,8), +(389,9), +(389,10), +(389,11), +(389,12), +(391,3), +(391,5), +(391,9), +(391,13), +(391,15), +(391,19), +(392,3), +(392,5), +(392,9), +(392,11), +(392,13), +(392,15), +(392,19), +(392,21), +(393,5), +(393,6), +(393,7), +(393,9), +(393,11), +(393,12), +(393,15), +(393,16), +(393,17), +(393,19), +(393,21), +(393,22), +(395,3), +(395,6), +(395,7), +(395,13), +(395,16), +(395,17), +(396,11), +(396,18), +(396,21), +(397,3), +(397,9), +(397,11), +(397,12), +(397,13), +(397,19), +(397,21), +(397,22), +(398,3), +(398,5), +(398,9), +(398,11), +(398,13), +(398,15), +(398,19), +(398,21), +(399,3), +(399,5), +(399,8), +(399,13), +(399,15), +(399,18), +(400,11), +(400,13), +(400,14), +(400,19), +(400,21), +(401,3), +(401,6), +(401,7), +(401,13), +(401,16), +(401,17), +(402,3), +(402,9), +(402,12), +(402,13), +(402,19), +(402,22), +(403,3), +(403,5), +(403,8), +(403,10), +(403,13), +(403,15), +(403,18), +(403,20), +(404,3), +(404,12), +(404,13), +(404,22), +(405,3), +(405,4), +(405,7), +(405,13), +(405,14), +(405,17), +(406,3), +(406,6), +(406,7), +(406,9), +(406,13), +(406,16), +(406,17), +(406,19), +(407,11), +(407,13), +(407,15), +(407,18), +(407,21), +(408,3), +(408,5), +(408,11), +(408,13), +(408,15), +(408,21), +(409,5), +(409,8), +(409,10), +(409,15), +(409,18), +(409,20), +(410,3), +(410,5), +(410,9), +(410,11), +(410,13), +(410,15), +(410,19), +(410,21), +(411,3), +(411,4), +(411,13), +(411,14), +(412,11), +(412,13), +(412,15), +(414,3), +(414,8), +(414,13), +(414,18), +(415,6), +(415,7), +(415,9), +(415,16), +(415,17), +(415,19), +(416,3), +(416,5), +(416,8), +(416,13), +(416,15), +(416,18), +(417,3), +(417,5), +(417,9), +(417,11), +(417,13), +(417,15), +(417,19), +(417,21), +(418,3), +(418,11), +(418,13), +(418,21), +(419,3), +(419,11), +(419,13), +(419,21), +(420,3), +(420,7), +(420,12), +(420,13), +(420,17), +(420,22), +(421,3), +(421,9), +(421,12), +(421,13), +(421,19), +(421,22), +(422,3), +(422,5), +(422,8), +(422,13), +(422,15), +(422,18), +(423,3), +(423,6), +(423,9), +(424,5), +(424,6), +(424,7), +(424,9), +(424,11), +(424,12), +(424,15), +(424,16), +(424,17), +(424,19), +(424,21), +(424,22), +(425,3), +(425,8), +(425,10), +(425,13), +(425,18), +(425,20), +(427,9), +(427,13), +(427,19), +(428,11), +(428,13), +(428,15), +(428,18), +(428,21), +(429,4), +(429,6), +(429,7), +(429,9), +(429,14), +(429,16), +(429,17), +(429,19), +(430,5), +(430,15), +(431,8), +(431,9), +(431,18), +(431,19), +(432,3), +(432,8), +(432,13), +(432,18), +(433,3), +(433,5), +(433,7), +(433,13), +(433,15), +(433,17), +(437,3), +(437,10), +(438,6), +(438,9), +(438,16), +(438,19), +(439,6), +(439,9), +(439,16), +(439,19), +(440,3), +(440,4), +(440,8), +(440,13), +(440,14), +(440,18), +(441,5), +(441,7), +(441,9), +(441,15), +(441,17), +(441,19), +(442,6), +(442,7), +(442,9), +(442,12), +(442,16), +(442,17), +(442,19), +(442,22), +(443,3), +(443,5), +(443,7), +(443,9), +(443,11), +(443,12), +(443,13), +(443,17), +(443,19), +(443,21), +(443,22), +(445,6), +(445,7), +(445,9), +(445,10), +(446,3), +(446,4), +(446,6), +(446,9), +(447,3), +(447,5), +(447,9), +(447,11), +(447,12), +(447,13), +(447,15), +(447,19), +(447,21), +(447,22), +(448,3), +(448,5), +(448,7), +(448,9), +(448,11), +(448,12), +(448,13), +(448,17), +(448,19), +(448,21), +(448,22), +(449,3), +(449,5), +(449,11), +(449,13), +(449,15), +(449,21), +(450,3), +(450,6), +(450,13), +(450,16), +(452,3), +(452,5), +(452,10), +(452,11), +(452,12), +(452,13), +(452,15), +(452,20), +(452,21), +(452,22), +(453,6), +(453,7), +(453,16), +(453,17), +(454,3), +(454,5), +(454,9), +(454,11), +(454,13), +(454,15), +(454,19), +(454,21), +(455,7), +(455,8), +(455,10), +(455,17), +(455,18), +(455,20), +(456,3), +(456,6), +(456,7), +(456,8), +(456,13), +(456,16), +(456,17), +(456,18), +(457,6), +(457,9), +(457,16), +(457,19), +(458,3), +(458,6), +(458,13), +(458,16), +(459,3), +(459,5), +(459,8), +(459,11), +(459,13), +(459,15), +(459,18), +(459,21), +(460,3), +(460,6), +(460,9), +(461,3), +(461,13), +(463,6), +(463,9), +(463,16), +(463,19), +(464,3), +(464,5), +(464,9), +(464,13), +(464,15), +(464,19), +(465,3), +(465,4), +(465,8), +(465,13), +(465,14), +(465,18), +(466,3), +(466,5), +(466,7), +(466,13), +(466,15), +(466,17), +(467,3), +(467,6), +(467,7), +(467,9), +(467,13), +(467,16), +(467,17), +(467,19), +(468,3), +(468,6), +(468,7), +(468,9), +(468,13), +(468,16), +(468,17), +(468,19), +(469,3), +(469,4), +(469,6), +(469,7), +(469,9), +(469,13), +(469,14), +(469,16), +(469,17), +(469,19), +(470,11), +(470,13), +(470,14), +(470,17), +(471,13), +(471,15), +(471,16), +(471,18), +(471,19), +(471,20), +(472,3), +(472,4), +(472,5), +(472,6), +(472,7), +(472,8), +(472,10), +(472,11), +(473,3), +(473,9), +(473,13), +(473,19), +(474,5), +(474,15), +(475,3), +(475,12), +(475,13), +(475,22), +(477,3), +(477,11), +(477,13), +(477,21), +(478,3), +(478,9), +(478,11), +(478,12), +(478,13), +(478,19), +(478,21), +(478,22), +(479,3), +(479,11), +(479,13), +(479,21), +(480,3), +(480,6), +(480,9), +(482,3), +(482,5), +(482,13), +(482,15), +(483,3), +(483,12), +(483,13), +(483,22), +(484,11), +(484,13), +(484,15), +(484,18), +(485,6), +(485,7), +(485,9), +(485,16), +(485,17), +(485,19), +(487,3), +(487,5), +(487,7), +(487,10), +(487,11), +(487,12), +(487,13), +(487,15), +(487,17), +(487,20), +(487,21), +(487,22), +(488,12), +(488,22), +(489,4), +(489,8), +(489,10), +(489,14), +(489,18), +(489,20), +(491,5), +(491,8), +(491,15), +(491,18), +(492,3), +(492,6), +(492,9), +(492,13), +(492,16), +(492,19), +(493,3), +(493,6), +(493,7), +(493,13), +(493,16), +(493,17), +(494,3), +(494,6), +(494,7), +(494,13), +(494,16), +(494,17), +(495,3), +(495,12), +(495,13), +(495,22), +(496,3), +(496,9), +(496,12), +(496,13), +(496,19), +(496,22), +(497,6), +(497,7), +(497,9), +(497,12), +(497,16), +(497,17), +(497,19), +(497,22), +(498,3), +(498,8), +(498,9), +(498,13), +(498,18), +(498,19), +(499,7), +(499,17), +(500,3), +(500,4), +(500,6), +(500,7), +(500,8), +(500,10), +(502,3), +(502,12), +(502,13), +(502,22), +(503,3), +(503,5), +(503,11), +(503,13), +(503,15), +(503,21), +(504,3), +(504,4), +(504,10), +(504,13), +(504,14), +(504,20), +(505,3), +(505,5), +(505,7), +(505,11), +(505,13), +(505,15), +(505,17), +(505,21), +(506,11), +(506,13), +(506,16), +(506,19), +(507,3), +(507,9), +(507,12), +(507,13), +(507,19), +(507,22), +(508,3), +(508,4), +(508,7), +(508,13), +(508,14), +(508,17), +(509,6), +(509,7), +(509,9), +(511,3), +(511,5), +(511,11), +(511,13), +(511,15), +(511,21), +(512,4), +(512,6), +(512,9), +(512,12), +(512,14), +(512,16), +(512,19), +(512,22), +(513,3), +(513,4), +(513,5), +(513,6), +(513,7), +(513,8), +(513,9), +(513,10), +(513,11), +(513,12), +(513,13), +(513,14), +(513,15), +(513,16), +(513,17), +(513,18), +(513,19), +(513,20), +(513,21), +(513,22), +(514,3), +(514,4), +(514,5), +(514,6), +(514,7), +(514,8), +(514,9), +(514,10), +(514,11), +(514,12), +(515,3), +(515,4), +(515,5), +(515,6), +(515,7), +(515,8), +(515,9), +(515,10), +(515,11), +(515,12), +(515,13), +(515,14), +(515,15), +(515,16), +(515,17), +(515,18), +(515,19), +(515,20), +(515,21), +(515,22), +(517,3), +(517,8), +(517,13), +(517,18), +(518,3), +(518,6), +(518,13), +(518,16), +(519,6), +(519,7), +(519,9), +(521,10), +(521,20), +(523,6), +(523,9), +(523,16), +(523,19), +(525,3), +(525,5), +(525,12), +(525,13), +(525,15), +(525,22), +(528,9), +(528,12), +(528,19), +(528,22), +(529,4), +(529,7), +(529,14), +(529,17), +(530,3), +(530,6), +(530,7), +(530,9), +(532,4), +(532,6), +(532,14), +(532,16), +(534,3), +(534,4), +(534,5), +(534,8), +(534,10), +(534,13), +(534,14), +(534,15), +(534,18), +(534,20), +(535,3), +(535,9), +(536,7), +(536,9), +(536,17), +(536,19), +(537,3), +(537,4), +(537,6), +(537,7), +(537,13), +(537,14), +(537,16), +(537,17), +(538,6), +(538,8), +(538,16), +(538,18), +(539,3), +(539,5), +(539,10), +(539,11), +(539,12), +(539,13), +(539,15), +(539,20), +(539,21), +(539,22), +(540,3), +(540,5), +(540,10), +(540,11), +(540,12), +(540,13), +(540,15), +(540,20), +(540,21), +(540,22), +(541,5), +(541,6), +(541,7), +(541,9), +(541,15), +(541,16), +(541,17), +(541,19), +(542,3), +(542,12), +(542,13), +(542,22), +(543,3), +(543,5), +(543,9), +(543,13), +(543,15), +(543,19), +(544,5), +(544,11), +(544,12), +(544,15), +(544,21), +(544,22), +(545,3), +(545,5), +(545,8), +(545,13), +(545,15), +(545,18), +(546,6), +(546,9), +(546,12), +(546,16), +(546,19), +(546,22), +(547,3), +(547,5), +(547,7), +(547,9), +(547,10), +(547,11), +(547,13), +(547,15), +(547,17), +(547,19), +(547,20), +(547,21), +(548,3), +(548,4), +(548,5), +(548,6), +(548,7), +(548,8), +(548,9), +(548,10), +(548,11), +(548,12), +(548,13), +(548,14), +(548,15), +(548,16), +(548,17), +(548,18), +(548,19), +(548,20), +(548,21), +(548,22), +(549,3), +(549,5), +(549,10), +(549,11), +(549,12), +(549,13), +(549,15), +(549,20), +(549,21), +(549,22), +(550,3), +(550,5), +(550,10), +(550,11), +(550,12), +(550,13), +(550,15), +(550,20), +(550,21), +(550,22), +(552,3), +(552,4), +(552,6), +(552,7), +(552,11), +(552,13), +(552,14), +(552,16), +(552,17), +(552,21), +(553,3), +(553,5), +(553,10), +(553,11), +(553,12), +(553,13), +(553,15), +(553,20), +(553,21), +(553,22), +(554,3), +(554,7), +(554,9), +(555,5), +(555,6), +(555,7), +(555,9), +(555,15), +(555,16), +(555,17), +(555,19), +(556,6), +(556,9), +(556,12), +(556,16), +(556,19), +(556,22), +(557,4), +(557,5), +(557,7), +(557,10), +(557,11), +(557,14), +(557,15), +(557,17), +(557,20), +(557,21), +(558,8), +(558,18), +(559,4), +(559,6), +(559,7), +(559,9), +(560,3), +(560,5), +(560,10), +(560,13), +(560,15), +(560,20), +(562,3), +(562,5), +(562,8), +(562,13), +(562,15), +(562,18), +(564,3), +(564,6), +(564,12), +(564,13), +(564,16), +(564,22), +(565,3), +(565,12), +(565,13), +(565,22), +(566,3), +(566,9), +(566,12), +(566,13), +(566,19), +(566,22), +(567,5), +(567,10), +(567,15), +(567,20), +(568,3), +(568,9), +(568,13), +(568,19), +(569,3), +(569,12), +(569,13), +(569,22), +(570,3), +(570,10), +(570,13), +(570,20), +(571,3), +(571,5), +(571,13), +(571,15), +(572,4), +(572,6), +(572,14), +(572,16), +(573,3), +(573,5), +(573,10), +(573,11), +(573,13), +(573,15), +(573,20), +(573,21), +(626,4), +(626,5), +(626,7), +(626,8), +(626,10), +(626,11), +(626,14), +(626,15), +(626,17), +(626,18), +(626,20), +(626,21), +(627,7), +(627,10), +(627,17), +(627,20), +(628,3), +(628,10), +(628,13), +(628,20), +(629,3), +(629,4), +(629,7), +(629,13), +(629,14), +(629,17), +(630,3), +(630,5), +(630,8), +(630,10), +(630,13), +(630,15), +(630,18), +(630,20), +(631,7), +(631,9), +(631,17), +(631,19), +(632,3), +(632,10), +(632,13), +(632,20), +(633,3), +(633,7), +(633,9), +(633,12), +(633,13), +(633,17), +(633,19), +(633,22), +(634,9), +(634,13), +(634,19), +(635,3), +(635,8), +(635,10), +(635,13), +(635,18), +(635,20), +(637,11), +(637,13), +(637,15), +(638,5), +(638,6), +(638,7), +(638,9), +(638,15), +(638,16), +(638,17), +(638,19), +(639,3), +(639,5), +(639,10), +(639,11), +(639,12), +(639,13), +(639,15), +(639,20), +(639,21), +(639,22), +(640,3), +(640,5), +(640,7), +(640,9), +(640,11), +(640,12), +(640,13), +(640,17), +(640,19), +(640,21), +(640,22), +(641,3), +(641,5), +(641,7), +(641,9), +(641,11), +(641,12), +(641,13), +(641,17), +(641,19), +(641,21), +(641,22), +(644,3), +(644,5), +(644,10), +(644,11), +(644,12), +(644,13), +(644,15), +(644,20), +(644,21), +(644,22), +(645,3), +(645,8), +(645,9), +(645,13), +(645,18), +(645,19), +(646,13), +(646,15), +(646,21), +(646,22), +(647,3), +(647,5), +(647,8), +(647,10), +(647,11), +(647,13), +(647,15), +(647,18), +(647,20), +(647,21), +(648,3), +(648,6), +(648,7), +(648,12), +(648,13), +(648,16), +(648,17), +(648,22), +(649,3), +(649,7), +(649,8), +(649,13), +(649,17), +(649,18), +(650,8), +(652,21), +(665,11), +(671,8), +(671,18), +(675,3), +(675,5), +(675,10), +(675,11), +(675,12), +(675,13), +(675,15), +(675,20), +(675,21), +(675,22), +(677,3), +(677,5), +(677,8), +(677,13), +(677,15), +(677,18), +(678,6), +(678,9), +(678,16), +(678,19), +(679,5), +(679,11), +(679,15), +(679,21), +(680,5), +(680,11), +(680,15), +(680,21), +(699,11), +(699,13), +(699,19), +(699,22), +(702,3), +(702,5), +(702,12), +(702,13), +(702,15), +(702,22), +(703,3), +(703,11), +(703,13), +(703,21), +(706,3), +(706,5), +(706,8), +(706,13), +(706,15), +(706,18), +(707,3), +(707,5), +(707,13), +(707,15), +(708,3), +(708,5), +(708,10), +(708,11), +(708,12), +(708,13), +(708,15), +(708,20), +(708,21), +(708,22), +(709,3), +(709,5), +(709,11), +(709,12), +(709,13), +(709,15), +(709,21), +(709,22), +(710,3), +(710,9), +(710,11), +(710,13), +(710,19), +(710,21), +(711,3), +(711,5), +(711,11), +(711,13), +(711,15), +(711,21), +(712,3), +(712,5), +(712,11), +(712,13), +(712,15), +(712,21), +(713,3), +(713,9), +(713,13), +(713,19), +(714,11), +(714,13), +(714,14), +(714,20), +(716,9), +(716,17), +(716,19), +(717,5), +(717,6), +(717,9), +(717,12), +(717,15), +(717,16), +(717,19), +(717,22), +(718,3), +(718,8), +(718,9), +(718,13), +(718,18), +(718,19), +(722,3), +(722,9), +(722,10), +(722,12), +(723,3), +(723,6), +(723,9), +(723,13), +(723,16), +(723,19), +(724,5), +(724,10), +(724,15), +(724,20), +(725,3), +(725,11), +(725,13), +(725,21), +(726,3), +(726,5), +(726,7), +(726,13), +(726,15), +(726,17), +(727,3), +(727,5), +(727,8), +(727,11), +(727,12), +(727,13), +(727,15), +(727,18), +(727,21), +(727,22), +(728,13), +(728,15), +(728,21), +(728,22), +(729,3), +(729,5), +(729,7), +(729,9), +(729,11), +(729,12), +(729,13), +(729,17), +(729,19), +(729,21), +(729,22), +(730,3), +(730,5), +(730,9), +(730,11), +(730,12), +(730,13), +(730,19), +(730,21), +(730,22), +(731,7), +(731,9), +(731,17), +(731,19), +(732,8), +(732,9), +(732,18), +(732,19), +(733,3), +(733,5), +(733,11), +(733,13), +(733,15), +(733,21), +(737,5), +(737,8), +(737,15), +(737,18), +(739,5), +(739,8), +(739,15), +(739,18), +(740,3), +(740,9), +(740,10), +(740,11), +(740,12), +(740,13), +(740,19), +(740,20), +(740,21), +(740,22), +(741,3), +(741,12), +(741,13), +(741,22), +(742,3), +(742,5), +(742,13), +(742,15), +(743,3), +(743,5), +(743,12), +(743,13), +(743,15), +(743,22), +(744,5), +(744,6), +(744,7), +(744,9), +(744,11), +(744,12), +(744,15), +(744,16), +(744,17), +(744,19), +(744,21), +(744,22), +(745,3), +(745,9), +(745,13), +(745,19), +(746,4), +(746,6), +(746,14), +(746,16), +(747,3), +(747,9), +(747,10), +(747,12), +(748,3), +(748,5), +(748,7), +(748,8), +(748,9), +(748,10), +(748,11), +(748,12), +(748,13), +(748,15), +(748,17), +(748,18), +(748,19), +(748,20), +(748,21), +(748,22), +(749,5), +(749,11), +(749,15), +(749,21), +(750,3), +(750,5), +(750,11), +(750,13), +(750,15), +(750,21), +(751,3), +(751,9), +(751,11), +(751,12), +(751,13), +(751,19), +(751,21), +(751,22), +(752,3), +(752,4), +(752,12), +(752,13), +(752,14), +(752,22), +(753,3), +(753,9), +(753,13), +(753,19), +(754,3), +(754,5), +(754,7), +(754,8), +(754,9), +(754,11), +(754,12), +(754,13), +(754,15), +(754,17), +(754,18), +(754,19), +(754,21), +(754,22), +(755,8), +(755,10), +(755,18), +(755,20), +(756,3), +(756,5), +(756,9), +(756,13), +(756,15), +(756,19), +(757,15), +(758,18), +(792,3), +(792,12), +(792,13), +(792,22), +(802,4), +(817,7), +(818,8), +(819,15), +(820,22), +(821,11), +(821,21), +(823,3), +(823,5), +(823,9), +(823,12), +(823,13), +(823,15), +(823,19), +(823,22), +(834,7), +(835,5), +(835,15), +(836,5), +(837,3), +(837,4), +(837,5), +(837,6), +(837,7), +(837,8), +(837,9), +(837,10), +(837,11), +(837,12), +(838,3), +(838,4), +(838,5), +(838,6), +(838,7), +(838,8), +(838,9), +(838,10), +(838,11), +(838,12), +(844,5), +(845,3), +(845,8), +(845,10), +(845,13), +(845,18), +(845,20), +(846,5), +(846,15), +(847,22), +(848,3), +(848,5), +(848,9), +(848,13), +(848,15), +(848,19), +(851,3), +(851,5), +(851,7), +(851,13), +(851,15), +(851,17), +(855,3), +(856,9), +(856,12), +(868,9), +(903,10), +(1013,3), +(1013,6), +(1013,9), +(1013,13), +(1013,16), +(1013,19), +(1039,6), +(1039,16), +(1040,6), +(1040,16), +(1042,8), +(1061,5), +(1062,3), +(1062,9), +(1062,10), +(1062,12), +(1063,8), +(1068,3), +(1068,5), +(1068,8), +(1068,10), +(1068,13), +(1068,15), +(1068,18), +(1068,20), +(1073,22), +(1117,3), +(1124,8), +(1125,3), +(1126,7), +(1127,8), +(1128,3), +(1128,12), +(1128,13), +(1128,22), +(1142,11), +(1143,18), +(1144,9), +(1145,5), +(1146,7), +(1147,4), +(1149,8), +(1150,9), +(1151,7), +(1152,6), +(1153,4), +(1154,9), +(1155,6), +(1156,18), +(1157,3), +(1157,12), +(1157,13), +(1157,22), +(1158,12), +(1159,12), +(1160,8), +(1161,4), +(1161,8), +(1161,10), +(1161,14), +(1161,18), +(1161,20), +(1162,5), +(1162,8), +(1162,15), +(1162,18), +(1163,6), +(1163,7), +(1163,16), +(1163,17), +(1164,3), +(1164,5), +(1164,11), +(1164,13), +(1164,15), +(1164,21), +(1165,4), +(1165,8), +(1165,10), +(1165,14), +(1165,18), +(1165,20), +(1166,4), +(1166,8), +(1166,10), +(1166,14), +(1166,18), +(1166,20), +(1167,4), +(1167,8), +(1167,10), +(1167,14), +(1167,18), +(1167,20), +(1168,22), +(1174,12), +(1175,3), +(1175,12), +(1175,13), +(1175,22), +(1176,3), +(1176,11), +(1176,13), +(1177,6), +(1177,7), +(1177,9), +(1177,10), +(1178,4), +(1179,3), +(1180,4), +(1180,5), +(1180,8), +(1180,10), +(1181,6), +(1181,9), +(1181,16), +(1181,19), +(1182,3), +(1182,12), +(1182,13), +(1182,22), +(1183,4), +(1184,4), +(1184,14), +(1185,9), +(1185,19), +(1196,9), +(1196,19), +(1197,7), +(1197,17), +(1197,21), +(1198,8), +(1198,18), +(1200,8), +(1200,10), +(1200,18), +(1201,10), +(1202,3), +(1202,10), +(1202,13), +(1202,20), +(1204,11), +(1205,3), +(1205,6), +(1205,7), +(1205,9), +(1205,10), +(1205,13), +(1205,16), +(1205,17), +(1205,19), +(1205,20), +(1206,20), +(1206,22), +(1207,22), +(1208,21), +(1208,22), +(1209,13), +(1211,14), +(1211,15), +(1211,18), +(1211,20), +(1212,4), +(1212,5), +(1212,8), +(1212,10), +(1213,14), +(1213,15), +(1213,18), +(1213,20), +(1226,3), +(1226,4), +(1226,5), +(1226,8), +(1226,10), +(1227,6), +(1227,7), +(1227,9), +(1228,4), +(1228,6), +(1228,8), +(1229,5), +(1229,8), +(1229,10), +(1230,6), +(1230,7), +(1230,9), +(1231,3), +(1231,10), +(1231,11), +(1231,12), +(1232,3), +(1232,10), +(1232,12), +(1233,4), +(1233,6), +(1233,7), +(1233,8), +(1234,3), +(1234,6), +(1234,7), +(1234,9), +(1235,5), +(1235,11), +(1235,12), +(1236,8), +(1237,8), +(1238,3), +(1238,6), +(1238,13), +(1238,16), +(1243,8), +(1244,7), +(1245,3), +(1245,6), +(1245,9), +(1248,3), +(1256,10), +(1256,11), +(1266,4), +(1276,14), +(1276,15), +(1276,18), +(1303,18), +(1304,8), +(1305,8), +(1320,5), +(1321,4), +(1321,5), +(1321,7), +(1321,8), +(1321,10), +(1321,14), +(1321,15), +(1321,17), +(1321,18), +(1321,20), +(1322,4), +(1322,6), +(1322,7), +(1323,3), +(1323,4), +(1323,5), +(1323,10), +(1323,11), +(1324,3), +(1324,8), +(1324,9), +(1324,11), +(1324,13), +(1324,18), +(1324,19), +(1324,21), +(1325,3), +(1325,8), +(1325,9), +(1325,13), +(1325,18), +(1325,19), +(1326,3), +(1326,8), +(1326,9), +(1326,13), +(1326,18), +(1326,19), +(1328,13), +(1328,16), +(1328,17), +(1328,19), +(1328,22), +(1329,5), +(1329,8), +(1329,9), +(1329,11), +(1329,15), +(1329,18), +(1329,19), +(1329,21), +(1330,13), +(1330,14), +(1330,15), +(1330,16), +(1330,18), +(1331,14), +(1331,18), +(1331,20), +(1332,14), +(1332,15), +(1332,16), +(1333,13), +(1333,15), +(1333,18), +(1333,19), +(1334,6), +(1334,7), +(1334,9), +(1335,8), +(1336,13), +(1336,16), +(1336,17), +(1336,19), +(1336,22), +(1337,4), +(1337,6), +(1337,14), +(1337,16), +(1338,3), +(1338,7), +(1338,12), +(1338,13), +(1338,17), +(1338,22), +(1343,4), +(1343,5), +(1343,7), +(1343,8), +(1343,9), +(1344,7), +(1344,17), +(1345,6), +(1345,9), +(1345,16), +(1345,19), +(1346,9), +(1346,19), +(1348,8), +(1349,4), +(1351,7), +(1363,8), +(1364,4), +(1365,9), +(1384,7), +(1385,13), +(1385,14), +(1385,15), +(1385,18), +(1385,20), +(1386,14), +(1387,14), +(1387,16), +(1387,17), +(1387,18), +(1387,20), +(1394,16), +(1395,16), +(1396,8), +(1403,14), +(1403,15), +(1403,17), +(1403,20), +(1403,21), +(1411,20), +(1412,14), +(1412,15), +(1412,16), +(1416,17), +(1426,6), +(1427,13), +(1427,14), +(1427,15), +(1427,16), +(1427,17), +(1427,18), +(1427,22), +(1428,17), +(1430,13), +(1430,14), +(1430,15), +(1430,16), +(1430,17), +(1430,18), +(1430,19), +(1430,20), +(1430,21), +(1430,22), +(1432,13), +(1432,14), +(1432,15), +(1432,16), +(1432,17), +(1432,18), +(1432,19), +(1432,20), +(1432,21), +(1432,22), +(1434,13), +(1434,14), +(1434,15), +(1434,16), +(1434,17), +(1434,18), +(1434,19), +(1434,20), +(1434,21), +(1434,22), +(1435,13), +(1435,16), +(1441,13), +(1441,22), +(1442,16), +(1446,20), +(1447,14), +(1447,16), +(1447,17), +(1447,18), +(1448,13), +(1448,20), +(1448,21), +(1448,22), +(1449,14), +(1450,18), +(1451,15), +(1455,13), +(1455,20), +(1455,21), +(1455,22), +(1456,13), +(1456,20), +(1456,21), +(1456,22), +(1457,13), +(1457,20), +(1457,21), +(1457,22), +(1458,13), +(1458,20), +(1458,21), +(1458,22), +(1462,13), +(1462,20), +(1462,21), +(1462,22), +(1463,13), +(1463,20), +(1463,21), +(1463,22), +(1464,13), +(1464,20), +(1464,21), +(1464,22), +(1465,13), +(1465,20), +(1465,21), +(1465,22), +(1467,14), +(1467,15), +(1468,13), +(1468,14), +(1468,17), +(1468,20), +(1468,22), +(1469,13), +(1469,14), +(1469,17), +(1469,20), +(1469,22), +(1470,13), +(1470,14), +(1470,17), +(1470,20), +(1470,22), +(1471,20), +(1478,17), +(1495,3), +(1495,4), +(1495,5), +(1495,10), +(1495,11), +(1511,5), +(1515,18), +(1516,20), +(1517,4), +(1517,14), +(1521,18), +(1523,5), +(1524,17), +(1524,19), +(1530,14), +(1531,17), +(1532,8), +(1532,18), +(1533,8), +(1536,3), +(1537,6), +(1538,5), +(1539,4), +(1540,8), +(1541,20), +(1542,18), +(1543,17), +(1544,20), +(1545,13), +(1545,20), +(1545,21), +(1545,22), +(1546,20), +(1563,14), +(1563,15), +(1563,17), +(1563,19), +(1564,17), +(1565,14), +(1565,15), +(1565,17), +(1565,20), +(1565,21), +(1566,15), +(1567,18), +(1568,8), +(1569,17), +(1570,8), +(1570,18), +(1571,13), +(1571,16), +(1571,17), +(1571,19), +(1572,13), +(1572,14), +(1572,15), +(1572,19), +(1572,20), +(1573,13), +(1573,14), +(1573,15), +(1573,19), +(1573,20), +(1574,18), +(1575,20), +(1576,14), +(1577,13), +(1577,20), +(1577,21), +(1577,22), +(1578,14), +(1578,16), +(1579,14), +(1579,16), +(1581,4), +(1581,6), +(1581,14), +(1581,16), +(1582,14), +(1582,16), +(1583,14), +(1583,16), +(1586,3), +(1586,8), +(1586,9), +(1586,13), +(1586,18), +(1586,19), +(1587,13), +(1587,18), +(1587,19), +(1588,3), +(1588,8), +(1588,9), +(1588,13), +(1588,18), +(1588,19), +(1589,3), +(1589,8), +(1589,9), +(1589,13), +(1589,18), +(1589,19), +(1590,13), +(1590,19), +(1590,20), +(1590,22), +(1591,3), +(1591,9), +(1591,10), +(1591,12), +(1592,3), +(1592,9), +(1592,10), +(1592,12), +(1593,13), +(1593,19), +(1593,20), +(1593,22), +(1594,13), +(1594,16), +(1594,17), +(1594,19), +(1595,13), +(1595,16), +(1595,17), +(1595,19), +(1596,8), +(1596,18), +(1597,8), +(1597,18), +(1598,3), +(1598,6), +(1598,9), +(1598,13), +(1598,16), +(1598,19), +(1599,13), +(1599,16), +(1599,19), +(1600,13), +(1600,15), +(1600,16), +(1600,18), +(1601,14), +(1602,8), +(1603,19), +(1605,17), +(1615,13), +(1615,15), +(1615,17), +(1622,6), +(1623,17), +(1623,20), +(1623,22), +(1624,4), +(1625,7), +(1626,12), +(1627,19), +(1628,13), +(1628,20), +(1628,21), +(1628,22), +(1629,10), +(1629,11), +(1629,12), +(1631,15), +(1632,6), +(1632,7), +(1632,9), +(1633,10), +(1634,3), +(1636,17), +(1639,17), +(1655,13), +(1655,14), +(1655,15), +(1655,17), +(1655,21), +(1655,22), +(1656,13), +(1656,14), +(1656,15), +(1656,16), +(1656,17), +(1656,18), +(1656,19), +(1656,20), +(1656,21), +(1656,22), +(1660,15), +(1661,18), +(1662,14), +(1663,16), +(1663,17), +(1664,3), +(1665,9), +(1672,6), +(1687,3), +(1688,4), +(1688,6), +(1688,7), +(1688,8), +(1690,8), +(1692,10), +(1693,14), +(1764,5), +(1765,6), +(1766,4), +-- Tamer pets +-- I've used only male breeds here since I have no more info +(872,3), +(873,3), +(874,3), +(875,8), +(876,7), +(877,9), +(878,3), +(879,7), +(880,7), +(881,8), +(882,9), +(883,6), +(884,8), +(885,8), +(886,9), +(887,8), +(888,3), +(889,3), +(890,3), +(891,5), +(892,8), +(893,3), +(894,5), +(895,8), +(896,6), +(897,9), +(898,3), +(899,8), +(900,6), +(901,6), +(902,9), +(904,9), +(905,8), +(906,5), +(907,9), +(908,8), +(909,5), +(911,7), +(912,4), +(913,8), +(915,7), +(916,8), +(917,6), +(921,7), +(922,4), +(923,6), +(924,9), +(925,7), +(926,8), +(927,5), +(928,8), +(929,9), +(931,9), +(932,6), +(933,5), +(934,6), +(935,8), +(936,3), +(937,8), +(938,9), +(939,7), +(941,8), +(942,6), +(943,9), +(944,6), +(945,7), +(946,5), +(947,9), +(948,5), +(949,8), +(950,6), +(951,7), +(952,7), +(953,6), +(954,3), +(955,5), +(956,6), +(957,8), +(958,3), +(959,8), +(960,4), +(961,4), +(962,8), +(963,7), +(964,3), +(965,3), +(966,9), +(967,8), +(968,7), +(969,9), +(970,8), +(971,7), +(972,9), +(973,8), +(974,8), +(975,6), +(976,7), +(977,9), +(978,8), +(979,6), +(980,6), +(981,8), +(982,5), +(983,6), +(984,9), +(985,7), +(986,4), +(987,9), +(988,8), +(989,9), +(990,5), +(991,8), +(992,6), +(993,5), +(994,8), +(995,9), +(996,6), +(997,7), +(998,9), +(999,6), +(1000,8), +(1001,8), +(1002,9), +(1003,9), +(1004,9), +(1005,9), +(1006,6), +(1007,4), +(1008,6), +(1009,7), +(1010,8), +(1011,7), +(1012,5), +(1065,8), +(1066,10), +(1067,7), +(1129,7), +(1130,8), +(1131,11), +(1132,5), +(1133,10), +(1134,9), +(1135,12), +(1136,3), +(1137,6), +(1138,9), +(1139,8), +(1140,3), +(1141,7), +(1187,4), +(1188,3), +(1189,9), +(1190,11), +(1191,6), +(1192,10), +(1193,12), +(1194,8), +(1195,5), +(1267,3), +(1268,6), +(1269,4), +(1271,5), +(1277,5), +(1278,4), +(1279,6), +(1280,6), +(1281,5), +(1282,8), +(1283,4), +(1284,6), +(1285,5), +(1286,5), +(1287,4), +(1288,6), +(1289,4), +(1290,3), +(1291,3), +(1292,7), +(1293,5), +(1295,8), +(1296,6), +(1297,5), +(1298,4), +(1299,5), +(1300,4), +(1301,6), +(1311,8), +(1317,8), +(1319,6), +(1339,3), +(1400,3), +(1401,3), +(1402,3), +(1409,3), +(1472,3), +(1473,3), +(1474,3), +(1475,3), +(1476,3), +(1477,3), +(1479,3), +(1480,3), +(1482,3), +(1483,3), +(1484,3), +(1485,3), +(1486,3), +(1487,3), +(1488,3), +(1489,3), +(1490,3), +(1492,3), +(1493,3), +(1494,3), +(1496,3), +(1497,3), +(1498,3), +(1499,3), +(1500,3), +(1501,3), +(1502,3), +(1503,3), +(1504,3), +(1505,3), +(1506,3), +(1507,3), +(1508,3), +(1509,3), +(1510,3), +(1637,3), +(1640,3), +(1641,3), +(1642,3), +(1643,3), +(1644,3), +(1645,3), +(1646,3), +(1647,3), +(1648,3), +(1649,3), +(1651,3), +(1652,3), +(1653,3), +(1654,3), +(1671,3), +(1673,3), +(1674,3), +(1675,3), +(1676,3), +(1677,3), +(1678,3), +(1679,3), +(1680,3), +(1681,3), +(1682,3), +(1683,3), +(1684,3), +(1685,3), +(1686,3); + +-- +-- Table structure for table `battle_pet_quality` +-- + +DROP TABLE IF EXISTS `battle_pet_quality`; +CREATE TABLE `battle_pet_quality` ( + `speciesId` int(10) unsigned NOT NULL DEFAULT '0', + `quality` tinyint(3) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`speciesId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `battle_pet_quality` +-- + +INSERT INTO `battle_pet_quality` (`speciesId`,`quality`) VALUES +(39,2), +(40,2), +(41,2), +(42,2), +(43,2), +(44,2), +(45,2), +(46,2), +(47,2), +(49,3), +(50,2), +(51,2), +(52,2), +(55,2), +(56,3), +(57,3), +(58,3), +(59,3), +(64,2), +(65,2), +(67,2), +(68,2), +(69,0), +(70,2), +(72,2), +(74,2), +(75,2), +(77,2), +(78,2), +(83,2), +(84,2), +(85,2), +(86,2), +(87,3), +(89,2), +(90,2), +(92,3), +(93,3), +(94,3), +(95,2), +(106,2), +(107,3), +(111,3), +(114,3), +(115,2), +(116,2), +(117,2), +(118,2), +(119,2), +(120,2), +(121,2), +(122,2), +(124,2), +(125,2), +(126,2), +(127,2), +(128,2), +(130,3), +(131,3), +(132,3), +(136,2), +(137,2), +(138,2), +(139,2), +(140,2), +(141,2), +(142,2), +(143,2), +(144,2), +(145,2), +(146,3), +(149,2), +(153,2), +(155,3), +(156,3), +(157,2), +(158,2), +(159,2), +(160,3), +(162,3), +(163,3), +(164,3), +(165,3), +(166,2), +(167,3), +(168,3), +(169,1), +(170,2), +(171,2), +(172,3), +(173,3), +(174,3), +(175,3), +(179,3), +(180,2), +(183,3), +(186,3), +(187,3), +(188,3), +(189,3), +(190,2), +(191,2), +(192,2), +(193,3), +(194,2), +(195,2), +(196,2), +(197,2), +(198,3), +(199,3), +(200,2), +(201,2), +(202,2), +(203,3), +(204,2), +(205,2), +(206,2), +(207,2), +(209,2), +(210,2), +(211,3), +(212,2), +(213,2), +(215,2), +(217,3), +(218,2), +(220,2), +(224,2), +(225,2), +(226,2), +(227,2), +(228,3), +(229,3), +(231,2), +(232,2), +(233,2), +(234,3), +(235,2), +(236,2), +(237,2), +(238,2), +(239,3), +(240,2), +(241,3), +(242,3), +(243,3), +(244,3), +(245,3), +(246,3), +(247,2), +(248,3), +(249,3), +(250,2), +(251,2), +(253,3), +(254,2), +(255,3), +(256,3), +(258,3), +(259,2), +(260,2), +(261,2), +(262,2), +(264,3), +(265,3), +(266,3), +(267,2), +(268,3), +(270,3), +(271,2), +(272,2), +(277,3), +(278,3), +(279,3), +(285,3), +(286,3), +(287,2), +(289,2), +(291,3), +(292,2), +(293,3), +(294,3), +(296,3), +(297,3), +(298,3), +(301,3), +(302,3), +(303,3), +(306,2), +(307,3), +(308,2), +(309,3), +(310,3), +(311,3), +(316,3), +(317,3), +(318,3), +(319,2), +(320,3), +(321,2), +(323,3), +(325,3), +(328,3), +(329,3), +(330,3), +(333,3), +(335,3), +(337,3), +(338,3), +(339,3), +(340,2), +(341,2), +(342,2), +(343,3), +(346,3), +(347,3), +(348,3), +(374,0), +(378,0), +(379,0), +(380,0), +(381,3), +(383,0), +(385,0), +(386,0), +(387,0), +(388,0), +(389,0), +(391,0), +(392,0), +(393,0), +(395,0), +(396,0), +(397,0), +(398,0), +(399,0), +(400,0), +(401,0), +(402,0), +(403,0), +(404,0), +(405,0), +(406,0), +(407,0), +(408,0), +(409,0), +(410,0), +(411,0), +(412,0), +(414,0), +(415,0), +(416,0), +(417,0), +(418,0), +(419,0), +(420,0), +(421,0), +(422,0), +(423,0), +(424,0), +(425,0), +(427,0), +(428,0), +(429,0), +(430,0), +(431,0), +(432,0), +(433,0), +(437,0), +(438,0), +(439,0), +(440,0), +(441,0), +(442,0), +(443,0), +(445,0), +(446,0), +(447,0), +(448,0), +(449,0), +(450,0), +(452,0), +(453,0), +(454,0), +(455,0), +(456,0), +(457,0), +(458,0), +(459,0), +(460,0), +(461,0), +(463,0), +(464,0), +(465,0), +(466,0), +(467,0), +(468,0), +(469,0), +(470,0), +(471,0), +(472,0), +(473,0), +(474,0), +(475,0), +(477,0), +(478,0), +(479,0), +(480,0), +(482,0), +(483,0), +(484,0), +(485,0), +(487,0), +(488,0), +(489,0), +(491,0), +(492,0), +(493,0), +(494,0), +(495,0), +(496,0), +(497,0), +(498,0), +(499,0), +(500,0), +(502,0), +(503,0), +(504,0), +(505,0), +(506,0), +(507,0), +(508,0), +(509,0), +(511,0), +(512,0), +(513,0), +(514,0), +(515,0), +(517,0), +(518,0), +(519,0), +(521,0), +(523,0), +(525,0), +(528,0), +(529,0), +(530,0), +(532,0), +(534,0), +(535,0), +(536,0), +(537,0), +(538,0), +(539,0), +(540,0), +(541,0), +(542,0), +(543,0), +(544,0), +(545,0), +(546,0), +(547,0), +(548,0), +(549,0), +(550,0), +(552,0), +(553,0), +(554,0), +(555,0), +(556,0), +(557,0), +(558,0), +(559,0), +(560,0), +(562,0), +(564,0), +(565,0), +(566,0), +(567,0), +(568,0), +(569,0), +(570,0), +(571,0), +(572,0), +(573,0), +(626,0), +(627,0), +(628,0), +(629,2), +(630,2), +(631,0), +(632,0), +(633,0), +(634,0), +(635,0), +(637,0), +(638,0), +(639,0), +(640,0), +(641,0), +(644,0), +(645,0), +(646,0), +(647,0), +(648,0), +(649,0), +(650,3), +(652,2), +(665,3), +(671,3), +(675,0), +(677,0), +(678,0), +(679,0), +(680,0), +(699,0), +(702,0), +(703,0), +(706,0), +(707,0), +(708,0), +(709,0), +(710,0), +(711,0), +(712,0), +(713,0), +(714,0), +(716,0), +(717,0), +(718,0), +(722,0), +(723,0), +(724,0), +(725,0), +(726,0), +(727,0), +(728,0), +(729,0), +(730,0), +(731,0), +(732,0), +(733,0), +(737,0), +(739,0), +(740,0), +(741,0), +(742,0), +(743,0), +(744,0), +(745,0), +(746,0), +(747,0), +(748,0), +(749,0), +(750,0), +(751,0), +(752,0), +(753,0), +(754,0), +(755,0), +(756,0), +(757,2), +(758,2), +(792,2), +(802,2), +(817,0), +(818,0), +(819,0), +(820,2), +(821,3), +(823,0), +(834,3), +(835,3), +(836,3), +(837,0), +(838,0), +(844,2), +(845,2), +(846,0), +(847,2), +(848,3), +(851,0), +(855,3), +(856,3), +(868,3), +(903,3), +(1013,0), +(1039,2), +(1040,2), +(1042,0), +(1061,2), +(1062,0), +(1063,3), +(1068,0), +(1073,3), +(1117,3), +(1124,3), +(1125,3), +(1126,3), +(1127,3), +(1128,0), +(1142,3), +(1143,3), +(1144,3), +(1145,3), +(1146,3), +(1147,3), +(1149,3), +(1150,3), +(1151,3), +(1152,3), +(1153,3), +(1154,3), +(1155,3), +(1156,3), +(1157,0), +(1158,0), +(1159,0), +(1160,0), +(1161,0), +(1162,0), +(1163,0), +(1164,0), +(1165,0), +(1166,0), +(1167,0), +(1168,3), +(1174,2), +(1175,0), +(1176,3), +(1177,3), +(1178,3), +(1179,0), +(1180,3), +(1181,0), +(1182,0), +(1183,3), +(1184,3), +(1185,3), +(1196,3), +(1197,3), +(1198,3), +(1200,3), +(1201,3), +(1202,3), +(1204,3), +(1205,3), +(1206,3), +(1207,3), +(1208,3), +(1209,3), +(1211,3), +(1212,3), +(1213,3), +(1226,3), +(1227,3), +(1228,3), +(1229,3), +(1230,3), +(1231,3), +(1232,3), +(1233,3), +(1234,3), +(1235,3), +(1236,3), +(1237,3), +(1238,0), +(1243,3), +(1244,3), +(1245,3), +(1248,3), +(1256,3), +(1266,3), +(1276,3), +(1303,3), +(1304,3), +(1305,3), +(1320,2), +(1321,2), +(1322,3), +(1323,2), +(1324,0), +(1325,0), +(1326,0), +(1328,3), +(1329,3), +(1330,2), +(1331,3), +(1332,3), +(1333,3), +(1334,3), +(1335,3), +(1336,3), +(1337,3), +(1338,3), +(1343,3), +(1344,3), +(1345,2), +(1346,3), +(1348,3), +(1349,2), +(1351,2), +(1363,3), +(1364,3), +(1365,3), +(1384,3), +(1385,0), +(1386,3), +(1387,3), +(1394,3), +(1395,3), +(1396,3), +(1403,3), +(1411,3), +(1412,3), +(1416,2), +(1426,1), +(1427,0), +(1428,3), +(1430,3), +(1432,3), +(1434,3), +(1435,0), +(1441,0), +(1442,3), +(1446,2), +(1447,0), +(1448,3), +(1449,3), +(1450,3), +(1451,3), +(1455,0), +(1456,0), +(1457,0), +(1458,3), +(1462,0), +(1463,0), +(1464,0), +(1465,0), +(1467,3), +(1468,0), +(1469,0), +(1470,0), +(1471,2), +(1478,3), +(1495,3), +(1511,3), +(1515,2), +(1516,3), +(1517,2), +(1521,3), +(1523,3), +(1524,3), +(1530,3), +(1531,3), +(1532,2), +(1533,3), +(1536,3), +(1537,2), +(1538,2), +(1539,3), +(1540,2), +(1541,3), +(1542,3), +(1543,3), +(1544,3), +(1545,3), +(1546,3), +(1563,3), +(1564,3), +(1565,3), +(1566,3), +(1567,3), +(1568,3), +(1569,3), +(1570,3), +(1571,3), +(1572,0), +(1573,0), +(1574,3), +(1575,2), +(1576,3), +(1577,3), +(1578,0), +(1579,0), +(1581,3), +(1582,0), +(1583,0), +(1586,0), +(1587,0), +(1588,3), +(1589,0), +(1590,0), +(1591,0), +(1592,0), +(1593,0), +(1594,0), +(1595,0), +(1596,2), +(1597,2), +(1598,3), +(1599,0), +(1600,3), +(1601,2), +(1602,3), +(1603,3), +(1605,3), +(1615,0), +(1622,3), +(1623,3), +(1624,3), +(1625,3), +(1626,3), +(1627,3), +(1628,3), +(1629,3), +(1631,3), +(1632,3), +(1633,3), +(1634,3), +(1636,3), +(1639,3), +(1655,3), +(1656,3), +(1660,3), +(1661,3), +(1662,3), +(1663,3), +(1664,3), +(1665,3), +(1672,3), +(1687,3), +(1688,3), +(1690,3), +(1692,3), +(1693,3), +(1764,3), +(1765,3), +(1766,3), +-- Tamer pets +(872,1), +(873,1), +(874,1), +(875,1), +(876,1), +(877,1), +(878,1), +(879,1), +(880,1), +(881,1), +(882,1), +(883,1), +(884,1), +(885,1), +(886,2), +(887,2), +(888,2), +(889,1), +(890,1), +(891,1), +(892,1), +(893,1), +(894,1), +(895,1), +(896,1), +(897,1), +(898,1), +(899,1), +(900,1), +(901,1), +(902,1), +(904,2), +(905,2), +(906,2), +(907,2), +(908,2), +(909,2), +(911,2), +(912,2), +(913,2), +(915,2), +(916,2), +(917,2), +(921,2), +(922,2), +(923,2), +(924,2), +(925,2), +(926,2), +(927,2), +(928,2), +(929,2), +(931,2), +(932,2), +(933,2), +(934,2), +(935,2), +(936,2), +(937,2), +(938,2), +(939,2), +(941,2), +(942,2), +(943,2), +(944,2), +(945,2), +(946,2), +(947,2), +(948,2), +(949,2), +(950,2), +(951,2), +(952,2), +(953,2), +(954,2), +(955,2), +(956,2), +(957,2), +(958,2), +(959,2), +(960,2), +(961,2), +(962,3), +(963,3), +(964,3), +(965,3), +(966,3), +(967,3), +(968,3), +(969,3), +(970,3), +(971,3), +(972,3), +(973,3), +(974,3), +(975,3), +(976,3), +(977,3), +(978,3), +(979,3), +(980,3), +(981,3), +(982,3), +(983,3), +(984,3), +(985,3), +(986,3), +(987,3), +(988,3), +(989,4), +(990,4), +(991,4), +(992,4), +(993,4), +(994,4), +(995,4), +(996,4), +(997,4), +(998,4), +(999,4), +(1000,4), +(1001,4), +(1002,4), +(1003,4), +(1004,4), +(1005,4), +(1006,4), +(1007,4), +(1008,4), +(1009,4), +(1010,5), +(1011,5), +(1012,5), +(1065,4), +(1066,4), +(1067,4), +(1129,5), +(1130,5), +(1131,5), +(1132,5), +(1133,5), +(1134,5), +(1135,5), +(1136,5), +(1137,5), +(1138,5), +(1139,5), +(1140,5), +(1141,5), +(1187,5), +(1188,5), +(1189,5), +(1190,5), +(1191,5), +(1192,5), +(1193,5), +(1194,5), +(1195,5), +(1267,5), +(1268,5), +(1269,5), +(1271,5), +(1277,5), +(1278,5), +(1279,5), +(1280,5), +(1281,5), +(1282,5), +(1283,5), +(1284,5), +(1285,5), +(1286,5), +(1287,5), +(1288,5), +(1289,5), +(1290,5), +(1291,5), +(1292,5), +(1293,5), +(1295,5), +(1296,5), +(1297,5), +(1298,5), +(1299,5), +(1300,5), +(1301,5), +(1311,5), +(1317,5), +(1319,5), +(1339,5), +(1400,3), +(1401,3), +(1402,3), +(1409,3), +(1472,3), +(1473,3), +(1474,3), +(1475,5), +(1476,5), +(1477,5), +(1479,3), +(1480,3), +(1482,3), +(1483,3), +(1484,3), +(1485,3), +(1486,3), +(1487,3), +(1488,3), +(1489,3), +(1490,3), +(1492,3), +(1493,3), +(1494,3), +(1496,3), +(1497,3), +(1498,3), +(1499,3), +(1500,3), +(1501,3), +(1502,3), +(1503,3), +(1504,3), +(1505,3), +(1506,3), +(1507,3), +(1508,3), +(1509,3), +(1510,3), +(1637,3), +(1640,3), +(1641,3), +(1642,3), +(1643,3), +(1644,3), +(1645,3), +(1646,3), +(1647,3), +(1648,3), +(1649,3), +(1651,3), +(1652,3), +(1653,3), +(1654,3), +(1671,5), +(1673,5), +(1674,5), +(1675,5), +(1676,5), +(1677,5), +(1678,5), +(1679,5), +(1680,5), +(1681,5), +(1682,5), +(1683,5), +(1684,5), +(1685,5), +(1686,5); diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index f79fb8faf41..2de1dc0645b 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -22,7 +22,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() if (!m_reconnecting) m_stmts.resize(MAX_CHARACTERDATABASE_STATEMENTS); -#define SelectItemInstanceContent "ii.guid, ii.itemEntry, ii.creatorGuid, ii.giftCreatorGuid, ii.count, ii.duration, ii.charges, ii.flags, ii.enchantments, ii.randomPropertyId, ii.durability, ii.playedTime, ii.text, ii.transmogrification, ii.upgradeId, ii.enchantIllusion, ii.bonusListIDs" +#define SelectItemInstanceContent "ii.guid, ii.itemEntry, ii.creatorGuid, ii.giftCreatorGuid, ii.count, ii.duration, ii.charges, ii.flags, ii.enchantments, ii.randomPropertyId, ii.durability, ii.playedTime, ii.text, ii.transmogrification, ii.upgradeId, ii.enchantIllusion, ii.battlePetSpeciesId, ii.battlePetBreedData, ii.battlePetLevel, ii.battlePetDisplayId, ii.bonusListIDs" PrepareStatement(CHAR_DEL_QUEST_POOL_SAVE, "DELETE FROM pool_quest_save WHERE pool_id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_QUEST_POOL_SAVE, "INSERT INTO pool_quest_save (pool_id, quest_id) VALUES (?, ?)", CONNECTION_ASYNC); @@ -159,8 +159,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_ITEM_BOP_TRADE, "DELETE FROM item_soulbound_trade_data WHERE itemGuid = ? LIMIT 1", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_ITEM_BOP_TRADE, "INSERT INTO item_soulbound_trade_data VALUES (?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_REP_INVENTORY_ITEM, "REPLACE INTO character_inventory (guid, bag, slot, item) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_REP_ITEM_INSTANCE, "REPLACE INTO item_instance (itemEntry, owner_guid, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, transmogrification, upgradeId, enchantIllusion, bonusListIDs, guid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); - PrepareStatement(CHAR_UPD_ITEM_INSTANCE, "UPDATE item_instance SET itemEntry = ?, owner_guid = ?, creatorGuid = ?, giftCreatorGuid = ?, count = ?, duration = ?, charges = ?, flags = ?, enchantments = ?, randomPropertyId = ?, durability = ?, playedTime = ?, text = ?, transmogrification = ?, upgradeId = ?, enchantIllusion = ?, bonusListIDs = ? WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_REP_ITEM_INSTANCE, "REPLACE INTO item_instance (itemEntry, owner_guid, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, transmogrification, upgradeId, enchantIllusion, battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, bonusListIDs, guid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_ITEM_INSTANCE, "UPDATE item_instance SET itemEntry = ?, owner_guid = ?, creatorGuid = ?, giftCreatorGuid = ?, count = ?, duration = ?, charges = ?, flags = ?, enchantments = ?, randomPropertyId = ?, durability = ?, playedTime = ?, text = ?, transmogrification = ?, upgradeId = ?, enchantIllusion = ?, battlePetSpeciesId = ?, battlePetBreedData = ?, battlePetLevel = ?, battlePetDisplayId = ?, bonusListIDs = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ITEM_INSTANCE_ON_LOAD, "UPDATE item_instance SET duration = ?, flags = ?, durability = ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE, "DELETE FROM item_instance WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE_BY_OWNER, "DELETE FROM item_instance WHERE owner_guid = ?", CONNECTION_ASYNC); diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp index f2eb88589e1..104b5e2bbc7 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp @@ -47,6 +47,20 @@ void HotfixDatabaseConnection::DoPrepareStatements() " ORDER BY ID DESC", CONNECTION_SYNCH); PREPARE_LOCALE_STMT(HOTFIX_SEL_BARBER_SHOP_STYLE, "SELECT ID, DisplayName_lang, Description_lang FROM barber_shop_style_locale WHERE locale = ?", CONNECTION_SYNCH); + // BattlePetBreedQuality.db2 + PrepareStatement(HOTFIX_SEL_BATTLE_PET_BREED_QUALITY, "SELECT ID, Quality, Modifier FROM battle_pet_breed_quality ORDER BY ID DESC", CONNECTION_SYNCH); + + // BattlePetBreedState.db2 + PrepareStatement(HOTFIX_SEL_BATTLE_PET_BREED_STATE, "SELECT ID, BreedID, State, Value FROM battle_pet_breed_state ORDER BY ID DESC", CONNECTION_SYNCH); + + // BattlePetSpecies.db2 + PrepareStatement(HOTFIX_SEL_BATTLE_PET_SPECIES, "SELECT ID, CreatureID, IconFileID, SummonSpellID, PetType, Source, Flags, " + "SourceText, Description FROM battle_pet_species ORDER BY ID DESC", CONNECTION_SYNCH); + PREPARE_LOCALE_STMT(HOTFIX_SEL_BATTLE_PET_SPECIES, "SELECT ID, SourceText, Description FROM battle_pet_species_locale WHERE locale = ?", CONNECTION_SYNCH); + + // BattlePetSpeciesState.db2 + PrepareStatement(HOTFIX_SEL_BATTLE_PET_SPECIES_STATE, "SELECT ID, SpeciesID, State, Value FROM battle_pet_species_state ORDER BY ID DESC", CONNECTION_SYNCH); + // BroadcastText.db2 PrepareStatement(HOTFIX_SEL_BROADCAST_TEXT, "SELECT ID, Language, MaleText, FemaleText, EmoteID1, EmoteID2, EmoteID3, EmoteDelay1, EmoteDelay2, " "EmoteDelay3, SoundID, UnkEmoteID, Type FROM broadcast_text ORDER BY ID DESC", CONNECTION_SYNCH); @@ -277,6 +291,9 @@ void HotfixDatabaseConnection::DoPrepareStatements() // ItemSpecOverride.db2 PrepareStatement(HOTFIX_SEL_ITEM_SPEC_OVERRIDE, "SELECT ID, ItemID, SpecID FROM item_spec_override ORDER BY ID DESC", CONNECTION_SYNCH); + // ItemToBattlePetSpecies.db2 + PrepareStatement(HOTFIX_SEL_ITEM_TO_BATTLE_PET_SPECIES, "SELECT ID, BattlePetSpeciesID FROM item_to_battle_pet_species ORDER BY ID DESC", CONNECTION_SYNCH); + // ItemXBonusTree.db2 PrepareStatement(HOTFIX_SEL_ITEM_X_BONUS_TREE, "SELECT ID, ItemID, BonusTreeID FROM item_x_bonus_tree ORDER BY ID DESC", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h index cbff13a4fbf..196d7602da7 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.h +++ b/src/server/database/Database/Implementation/HotfixDatabase.h @@ -42,6 +42,15 @@ enum HotfixDatabaseStatements HOTFIX_SEL_BARBER_SHOP_STYLE, HOTFIX_SEL_BARBER_SHOP_STYLE_LOCALE, + HOTFIX_SEL_BATTLE_PET_BREED_QUALITY, + + HOTFIX_SEL_BATTLE_PET_BREED_STATE, + + HOTFIX_SEL_BATTLE_PET_SPECIES, + HOTFIX_SEL_BATTLE_PET_SPECIES_LOCALE, + + HOTFIX_SEL_BATTLE_PET_SPECIES_STATE, + HOTFIX_SEL_BROADCAST_TEXT, HOTFIX_SEL_BROADCAST_TEXT_LOCALE, @@ -159,6 +168,8 @@ enum HotfixDatabaseStatements HOTFIX_SEL_ITEM_SPEC_OVERRIDE, + HOTFIX_SEL_ITEM_TO_BATTLE_PET_SPECIES, + HOTFIX_SEL_ITEM_X_BONUS_TREE, HOTFIX_SEL_KEY_CHAIN, diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index 869dc617246..9526e012fa2 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -144,4 +144,13 @@ void LoginDatabaseConnection::DoPrepareStatements() // Account wide toys PrepareStatement(LOGIN_SEL_ACCOUNT_TOYS, "SELECT itemId, isFavourite FROM battlenet_account_toys WHERE accountId = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_REP_ACCOUNT_TOYS, "REPLACE INTO battlenet_account_toys (accountId, itemId, isFavourite) VALUES (?, ?, ?)", CONNECTION_ASYNC); + + // Battle Pets + PrepareStatement(LOGIN_SEL_BATTLE_PETS, "SELECT guid, species, breed, level, exp, health, quality, flags, name FROM battle_pets WHERE battlenetAccountId = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_INS_BATTLE_PETS, "INSERT INTO battle_pets (guid, battlenetAccountId, species, breed, level, exp, health, quality, flags, name) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_DEL_BATTLE_PETS, "DELETE FROM battle_pets WHERE battlenetAccountId = ? AND guid = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_UPD_BATTLE_PETS, "UPDATE battle_pets SET level = ?, exp = ?, health = ?, quality = ?, flags = ?, name = ? WHERE battlenetAccountId = ? AND guid = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_SEL_BATTLE_PET_SLOTS, "SELECT id, battlePetGuid, locked FROM battle_pet_slots WHERE battlenetAccountId = ?", CONNECTION_ASYNC); + PrepareStatement(LOGIN_INS_BATTLE_PET_SLOTS, "INSERT INTO battle_pet_slots (id, battlenetAccountId, battlePetGuid, locked) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(LOGIN_DEL_BATTLE_PET_SLOTS, "DELETE FROM battle_pet_slots WHERE battlenetAccountId = ?", CONNECTION_ASYNC); } diff --git a/src/server/database/Database/Implementation/LoginDatabase.h b/src/server/database/Database/Implementation/LoginDatabase.h index cd66be205f5..9ef214a3120 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.h +++ b/src/server/database/Database/Implementation/LoginDatabase.h @@ -133,6 +133,14 @@ enum LoginDatabaseStatements LOGIN_SEL_ACCOUNT_TOYS, LOGIN_REP_ACCOUNT_TOYS, + LOGIN_SEL_BATTLE_PETS, + LOGIN_INS_BATTLE_PETS, + LOGIN_DEL_BATTLE_PETS, + LOGIN_UPD_BATTLE_PETS, + LOGIN_SEL_BATTLE_PET_SLOTS, + LOGIN_INS_BATTLE_PET_SLOTS, + LOGIN_DEL_BATTLE_PET_SLOTS, + MAX_LOGINDATABASE_STATEMENTS }; diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 68d76272e22..91d97746ae1 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -1057,6 +1057,7 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type, case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: // This also behaves like ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: case ACHIEVEMENT_CRITERIA_TYPE_PLACE_GARRISON_BUILDING: + case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET_COUNT: SetCriteriaProgress(achievementCriteria, 1, referencePlayer, PROGRESS_ACCUMULATE); break; // std case: increment at miscValue1 @@ -1164,6 +1165,7 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type, case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM: case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER: + case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET: SetCriteriaProgress(achievementCriteria, 1, referencePlayer); break; case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT: @@ -1280,8 +1282,6 @@ void AchievementMgr<T>::UpdateAchievementCriteria(AchievementCriteriaTypes type, case ACHIEVEMENT_CRITERIA_TYPE_COUNT_OF_LFR_QUEUE_BOOSTS_BY_TANK: case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO_COUNT: case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_SCENARIO: - case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET: - case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET_COUNT: case ACHIEVEMENT_CRITERIA_TYPE_CAPTURE_BATTLE_PET: case ACHIEVEMENT_CRITERIA_TYPE_WIN_PET_BATTLE: case ACHIEVEMENT_CRITERIA_TYPE_LEVEL_BATTLE_PET: @@ -1444,12 +1444,14 @@ bool AchievementMgr<T>::IsCompletedCriteria(AchievementCriteria const* achieveme case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: case ACHIEVEMENT_CRITERIA_TYPE_CURRENCY: case ACHIEVEMENT_CRITERIA_TYPE_PLACE_GARRISON_BUILDING: + case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET_COUNT: return progress->counter >= requiredAmount; case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT: case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL: case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA: case ACHIEVEMENT_CRITERIA_TYPE_RECRUIT_GARRISON_FOLLOWER: + case ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET: return progress->counter >= 1; case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL: return progress->counter >= (requiredAmount * 75); @@ -2533,6 +2535,10 @@ bool AchievementMgr<T>::AdditionalRequirementsSatisfied(ModifierTreeNode const* if (!unit || unit->GetHealthPct() >= reqValue) return false; break; + case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_SPECIES: // 91 + if (miscValue1 != reqValue) + return false; + break; case ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_QUALITY: // 145 { if (!referencePlayer) diff --git a/src/server/game/BattlePets/BattlePetMgr.cpp b/src/server/game/BattlePets/BattlePetMgr.cpp new file mode 100644 index 00000000000..b65302f4050 --- /dev/null +++ b/src/server/game/BattlePets/BattlePetMgr.cpp @@ -0,0 +1,467 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "BattlePetMgr.h" +#include "Containers.h" +#include "Player.h" +#include "WorldSession.h" + +void BattlePetMgr::BattlePet::CalculateStats() +{ + float health = 0.0f; + float power = 0.0f; + float speed = 0.0f; + + // get base breed stats + auto breedState = _battlePetBreedStates.find(PacketInfo.Breed); + if (breedState == _battlePetBreedStates.end()) // non existing breed id + return; + + health = breedState->second[STATE_STAT_STAMINA]; + power = breedState->second[STATE_STAT_POWER]; + speed = breedState->second[STATE_STAT_SPEED]; + + // modify stats depending on species - not all pets have this + auto speciesState = _battlePetSpeciesStates.find(PacketInfo.Species); + if (speciesState != _battlePetSpeciesStates.end()) + { + health += speciesState->second[STATE_STAT_STAMINA]; + power += speciesState->second[STATE_STAT_POWER]; + speed += speciesState->second[STATE_STAT_SPEED]; + } + + // modify stats by quality + for (auto itr : sBattlePetBreedQualityStore) + { + if (itr->Quality == PacketInfo.Quality) + { + health *= itr->Modifier; + power *= itr->Modifier; + speed *= itr->Modifier; + break; + } + // TOOD: add check if pet has existing quality + } + + // scale stats depending on level + health *= PacketInfo.Level; + power *= PacketInfo.Level; + speed *= PacketInfo.Level; + + // set stats + // round, ceil or floor? verify this + PacketInfo.MaxHealth = uint32((round(health / 20) + 100)); + PacketInfo.Power = uint32(round(power / 100)); + PacketInfo.Speed = uint32(round(speed / 100)); +} + +std::unordered_map<uint16 /*BreedID*/, std::unordered_map<BattlePetState /*state*/, int32 /*value*/, std::hash<std::underlying_type<BattlePetState>::type> >> BattlePetMgr::_battlePetBreedStates; +std::unordered_map<uint32 /*SpeciesID*/, std::unordered_map<BattlePetState /*state*/, int32 /*value*/, std::hash<std::underlying_type<BattlePetState>::type> >> BattlePetMgr::_battlePetSpeciesStates; +std::unordered_map<uint32 /*SpeciesID*/, std::unordered_set<uint8 /*breed*/>> BattlePetMgr::_availableBreedsPerSpecies; +std::unordered_map<uint32 /*SpeciesID*/, uint8 /*quality*/> BattlePetMgr::_defaultQualityPerSpecies; + +void BattlePetMgr::Initialize() +{ + if (QueryResult result = LoginDatabase.Query("SELECT MAX(guid) FROM battle_pets")) + sObjectMgr->GetGenerator<HighGuid::BattlePet>().Set((*result)[0].GetUInt64() + 1); + + for (auto itr : sBattlePetBreedStateStore) + _battlePetBreedStates[itr->BreedID][BattlePetState(itr->State)] = itr->Value; + + for (auto itr : sBattlePetSpeciesStateStore) + _battlePetSpeciesStates[itr->SpeciesID][BattlePetState(itr->State)] = itr->Value; + + LoadAvailablePetBreeds(); + LoadDefaultPetQualities(); +} + +void BattlePetMgr::LoadAvailablePetBreeds() +{ + QueryResult result = WorldDatabase.Query("SELECT speciesId, breedId FROM battle_pet_breeds"); + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 battle pet breeds. DB table `battle_pet_breeds` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + uint32 speciesId = fields[0].GetUInt32(); + uint16 breedId = fields[1].GetUInt16(); + + if (!sBattlePetSpeciesStore.LookupEntry(speciesId)) + { + TC_LOG_ERROR("sql.sql", "Non-existing BattlePetSpecies.db2 entry %u was referenced in `battle_pet_breeds` by row (%u, %u).", speciesId, speciesId, breedId); + continue; + } + + // TODO: verify breed id (3 - 12 (male) or 3 - 22 (male and female)) if needed + + _availableBreedsPerSpecies[speciesId].insert(breedId); + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u battle pet breeds.", count); +} + +void BattlePetMgr::LoadDefaultPetQualities() +{ + QueryResult result = WorldDatabase.Query("SELECT speciesId, quality FROM battle_pet_quality"); + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 battle pet qualities. DB table `battle_pet_quality` is empty."); + return; + } + + do + { + Field* fields = result->Fetch(); + uint32 speciesId = fields[0].GetUInt32(); + uint8 quality = fields[1].GetUInt8(); + + if (!sBattlePetSpeciesStore.LookupEntry(speciesId)) + { + TC_LOG_ERROR("sql.sql", "Non-existing BattlePetSpecies.db2 entry %u was referenced in `battle_pet_quality` by row (%u, %u).", speciesId, speciesId, quality); + continue; + } + + // TODO: verify quality (0 - 3 for player pets or 0 - 5 for both player and tamer pets) if needed + + _defaultQualityPerSpecies[speciesId] = quality; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u battle pet qualities.", uint32(_defaultQualityPerSpecies.size())); +} + +uint16 BattlePetMgr::RollPetBreed(uint32 species) +{ + auto itr = _availableBreedsPerSpecies.find(species); + if (itr == _availableBreedsPerSpecies.end()) + return 3; // default B/B + + return Trinity::Containers::SelectRandomContainerElement(itr->second); +} + +uint8 BattlePetMgr::GetDefaultPetQuality(uint32 species) +{ + auto itr = _defaultQualityPerSpecies.find(species); + if (itr == _defaultQualityPerSpecies.end()) + return 0; // default poor + + return itr->second; +} + +BattlePetMgr::BattlePetMgr(WorldSession* owner) +{ + _owner = owner; + for (uint8 i = 0; i < MAX_PET_BATTLE_SLOTS; ++i) + { + WorldPackets::BattlePet::BattlePetSlot slot; + slot.Index = i; + _slots.push_back(slot); + } +} + +void BattlePetMgr::LoadFromDB(PreparedQueryResult pets, PreparedQueryResult slots) +{ + if (pets) + { + do + { + Field* fields = pets->Fetch(); + uint32 species = fields[1].GetUInt32(); + + if (BattlePetSpeciesEntry const* speciesEntry = sBattlePetSpeciesStore.LookupEntry(species)) + { + if (GetPetCount(species) >= MAX_BATTLE_PETS_PER_SPECIES) + { + TC_LOG_ERROR("misc", "Battlenet account with id %u has more than 3 battle pets of species %u", _owner->GetBattlenetAccountId(), species); + continue; + } + + BattlePet pet; + pet.PacketInfo.Guid = ObjectGuid::Create<HighGuid::BattlePet>(fields[0].GetUInt64()); + pet.PacketInfo.Species = species; + pet.PacketInfo.Breed = fields[2].GetUInt16(); + pet.PacketInfo.Level = fields[3].GetUInt16(); + pet.PacketInfo.Exp = fields[4].GetUInt16(); + pet.PacketInfo.Health = fields[5].GetUInt32(); + pet.PacketInfo.Quality = fields[6].GetUInt8(); + pet.PacketInfo.Flags = fields[7].GetUInt16(); + pet.PacketInfo.Name = fields[8].GetString(); + pet.PacketInfo.CreatureID = speciesEntry->CreatureID; + pet.SaveInfo = BATTLE_PET_UNCHANGED; + pet.CalculateStats(); + _pets[pet.PacketInfo.Guid.GetCounter()] = pet; + } + } while (pets->NextRow()); + } + + if (slots) + { + uint8 i = 0; // slots->GetRowCount() should equal MAX_BATTLE_PET_SLOTS + + do + { + Field* fields = slots->Fetch(); + _slots[i].Index = fields[0].GetUInt8(); + auto itr = _pets.find(fields[1].GetUInt64()); + if (itr != _pets.end()) + _slots[i].Pet = itr->second.PacketInfo; + _slots[i].Locked = fields[2].GetBool(); + i++; + } while (slots->NextRow()); + } +} + +void BattlePetMgr::SaveToDB(SQLTransaction& trans) +{ + PreparedStatement* stmt = nullptr; + + for (auto itr = _pets.begin(); itr != _pets.end();) + { + switch (itr->second.SaveInfo) + { + case BATTLE_PET_NEW: + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BATTLE_PETS); + stmt->setUInt64(0, itr->first); + stmt->setUInt32(1, _owner->GetBattlenetAccountId()); + stmt->setUInt32(2, itr->second.PacketInfo.Species); + stmt->setUInt16(3, itr->second.PacketInfo.Breed); + stmt->setUInt16(4, itr->second.PacketInfo.Level); + stmt->setUInt16(5, itr->second.PacketInfo.Exp); + stmt->setUInt32(6, itr->second.PacketInfo.Health); + stmt->setUInt8(7, itr->second.PacketInfo.Quality); + stmt->setUInt16(8, itr->second.PacketInfo.Flags); + stmt->setString(9, itr->second.PacketInfo.Name); + trans->Append(stmt); + itr->second.SaveInfo = BATTLE_PET_UNCHANGED; + ++itr; + break; + case BATTLE_PET_CHANGED: + stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BATTLE_PETS); + stmt->setUInt16(0, itr->second.PacketInfo.Level); + stmt->setUInt16(1, itr->second.PacketInfo.Exp); + stmt->setUInt32(2, itr->second.PacketInfo.Health); + stmt->setUInt8(3, itr->second.PacketInfo.Quality); + stmt->setUInt16(4, itr->second.PacketInfo.Flags); + stmt->setString(5, itr->second.PacketInfo.Name); + stmt->setUInt32(6, _owner->GetBattlenetAccountId()); + stmt->setUInt64(7, itr->first); + trans->Append(stmt); + itr->second.SaveInfo = BATTLE_PET_UNCHANGED; + ++itr; + break; + case BATTLE_PET_REMOVED: + stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_BATTLE_PETS); + stmt->setUInt32(0, _owner->GetBattlenetAccountId()); + stmt->setUInt64(1, itr->first); + trans->Append(stmt); + itr = _pets.erase(itr); + break; + default: + ++itr; + break; + } + } + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_BATTLE_PET_SLOTS); + stmt->setUInt32(0, _owner->GetBattlenetAccountId()); + trans->Append(stmt); + + for (WorldPackets::BattlePet::BattlePetSlot const& slot : _slots) + { + stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BATTLE_PET_SLOTS); + stmt->setUInt8(0, slot.Index); + stmt->setUInt32(1, _owner->GetBattlenetAccountId()); + stmt->setUInt64(2, slot.Pet.Guid.GetCounter()); + stmt->setBool(3, slot.Locked); + trans->Append(stmt); + } +} + +BattlePetMgr::BattlePet* BattlePetMgr::GetPet(ObjectGuid guid) +{ + auto itr = _pets.find(guid.GetCounter()); + if (itr != _pets.end()) + return &itr->second; + + return nullptr; +} + +void BattlePetMgr::AddPet(uint32 species, uint32 creatureId, uint16 breed, uint8 quality, uint16 level /*= 1*/) +{ + BattlePetSpeciesEntry const* battlePetSpecies = sBattlePetSpeciesStore.LookupEntry(species); + if (!battlePetSpecies) // should never happen + return; + + BattlePet pet; + pet.PacketInfo.Guid = ObjectGuid::Create<HighGuid::BattlePet>(sObjectMgr->GetGenerator<HighGuid::BattlePet>().Generate()); + pet.PacketInfo.Species = species; + pet.PacketInfo.CreatureID = creatureId; + pet.PacketInfo.Level = level; + pet.PacketInfo.Exp = 0; + pet.PacketInfo.Flags = 0; + pet.PacketInfo.Breed = breed; + pet.PacketInfo.Quality = quality; + pet.PacketInfo.Name = ""; + pet.CalculateStats(); + pet.PacketInfo.Health = pet.PacketInfo.MaxHealth; + pet.SaveInfo = BATTLE_PET_NEW; + + _pets[pet.PacketInfo.Guid.GetCounter()] = pet; + + std::vector<BattlePet> updates; + updates.push_back(pet); + SendUpdates(updates, true); + + _owner->GetPlayer()->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET, species); +} + +void BattlePetMgr::RemovePet(ObjectGuid guid) +{ + BattlePet* pet = GetPet(guid); + if (!pet) + return; + + pet->SaveInfo = BATTLE_PET_REMOVED; + + // spell is not unlearned on retail + /*if (GetPetCount(pet->PacketInfo.Species) == 0) + if (BattlePetSpeciesEntry const* speciesEntry = sBattlePetSpeciesStore.LookupEntry(pet->PacketInfo.Species)) + _owner->GetPlayer()->RemoveSpell(speciesEntry->SummonSpellID);*/ +} + +uint8 BattlePetMgr::GetPetCount(uint32 species) const +{ + uint8 count = 0; + for (auto& itr : _pets) + if (itr.second.PacketInfo.Species == species && itr.second.SaveInfo != BATTLE_PET_REMOVED) + count++; + + return count; +} + +void BattlePetMgr::UnlockSlot(uint8 slot) +{ + if (!_slots[slot].Locked) + return; + + _slots[slot].Locked = false; + + WorldPackets::BattlePet::PetBattleSlotUpdates updates; + updates.Slots.push_back(_slots[slot]); + updates.AutoSlotted = false; // what's this? + updates.NewSlot = true; // causes the "new slot unlocked" bubble to appear + _owner->SendPacket(updates.Write()); +} + +std::vector<BattlePetMgr::BattlePet> BattlePetMgr::GetLearnedPets() const +{ + std::vector<BattlePet> pets; + for (auto& pet : _pets) + if (pet.second.SaveInfo != BATTLE_PET_REMOVED) + pets.push_back(pet.second); + + return pets; +} + +void BattlePetMgr::CageBattlePet(ObjectGuid guid) +{ + BattlePet* pet = GetPet(guid); + if (!pet) + return; + + ItemPosCountVec dest; + + if (_owner->GetPlayer()->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, BATTLE_PET_CAGE_ITEM_ID, 1) != EQUIP_ERR_OK) + return; + + Item* item = _owner->GetPlayer()->StoreNewItem(dest, BATTLE_PET_CAGE_ITEM_ID, true); + if (!item) + return; + + item->SetModifier(ITEM_MODIFIER_BATTLE_PET_SPECIES_ID, pet->PacketInfo.Species); + item->SetModifier(ITEM_MODIFIER_BATTLE_PET_BREED_DATA, pet->PacketInfo.Breed | (pet->PacketInfo.Quality << 24)); + item->SetModifier(ITEM_MODIFIER_BATTLE_PET_LEVEL, pet->PacketInfo.Level); + item->SetModifier(ITEM_MODIFIER_BATTLE_PET_DISPLAY_ID, pet->PacketInfo.CreatureID); + + // FIXME: "You create: ." - item name missing in chat + _owner->GetPlayer()->SendNewItem(item, 1, true, true); + + RemovePet(guid); + + WorldPackets::BattlePet::BattlePetDeleted deletePet; + deletePet.PetGuid = guid; + _owner->SendPacket(deletePet.Write()); +} + +void BattlePetMgr::HealBattlePetsPct(uint8 pct) +{ + // TODO: After each Pet Battle, any injured companion will automatically + // regain 50 % of the damage that was taken during combat + std::vector<BattlePet> updates; + + for (auto& pet : _pets) + if (pet.second.PacketInfo.Health != pet.second.PacketInfo.MaxHealth) + { + pet.second.PacketInfo.Health += CalculatePct(pet.second.PacketInfo.MaxHealth, pct); + // don't allow Health to be greater than MaxHealth + pet.second.PacketInfo.Health = std::min(pet.second.PacketInfo.Health, pet.second.PacketInfo.MaxHealth); + if (pet.second.SaveInfo != BATTLE_PET_NEW) + pet.second.SaveInfo = BATTLE_PET_CHANGED; + updates.push_back(pet.second); + } + + SendUpdates(updates, false); +} + +void BattlePetMgr::SummonPet(ObjectGuid guid) +{ + BattlePet* pet = GetPet(guid); + if (!pet) + return; + + BattlePetSpeciesEntry const* speciesEntry = sBattlePetSpeciesStore.LookupEntry(pet->PacketInfo.Species); + if (!speciesEntry) + return; + + // TODO: set proper CreatureID for spell DEFAULT_SUMMON_BATTLE_PET_SPELL (default EffectMiscValueA is 40721 - Murkimus the Gladiator) + _owner->GetPlayer()->CastSpell(_owner->GetPlayer(), speciesEntry->SummonSpellID ? speciesEntry->SummonSpellID : DEFAULT_SUMMON_BATTLE_PET_SPELL); + + // TODO: set pet level, quality... update fields +} + +void BattlePetMgr::SendUpdates(std::vector<BattlePet> pets, bool petAdded) +{ + WorldPackets::BattlePet::BattlePetUpdates updates; + for (auto pet : pets) + updates.Pets.push_back(pet.PacketInfo); + + updates.PetAdded = petAdded; + _owner->SendPacket(updates.Write()); +} + +void BattlePetMgr::SendError(BattlePetError error, uint32 creatureId) +{ + WorldPackets::BattlePet::BattlePetError battlePetError; + battlePetError.Result = error; + battlePetError.CreatureID = creatureId; + _owner->SendPacket(battlePetError.Write()); +} diff --git a/src/server/game/BattlePets/BattlePetMgr.h b/src/server/game/BattlePets/BattlePetMgr.h new file mode 100644 index 00000000000..97b1b34c13c --- /dev/null +++ b/src/server/game/BattlePets/BattlePetMgr.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef BattlePetMgr_h__ +#define BattlePetMgr_h__ + +#include "DB2Stores.h" +#include "BattlePetPackets.h" + +enum BattlePetMisc +{ + MAX_PET_BATTLE_SLOTS = 3, + MAX_BATTLE_PETS_PER_SPECIES = 3, + BATTLE_PET_CAGE_ITEM_ID = 82800, + DEFAULT_SUMMON_BATTLE_PET_SPELL = 118301 +}; + +// TODO: fix values in this enum +enum BattlePetError +{ + BATTLEPETRESULT_CANT_HAVE_MORE_PETS_OF_THAT_TYPE = 9, + BATTLEPETRESULT_TOO_HIGH_LEVEL_TO_UNCAGE = 12, + BATTLEPETRESULT_CANT_HAVE_MORE_PETS = 13, + + // wrong order + BATTLEPETRESULT_DUPLICATE_CONVERTED_PET, + BATTLEPETRESULT_NEED_TO_UNLOCK, + BATTLEPETRESULT_BAD_PARAM, + BATTLEPETRESULT_LOCKED_PET_ALREADY_EXISTS, + BATTLEPETRESULT_OK, + BATTLEPETRESULT_UNCAPTURABLE, + BATTLEPETRESULT_CANT_INVALID_CHARACTER_GUID +}; + +// taken from BattlePetState.db2 - it seems to store some initial values for battle pets +// there are only values used in BattlePetSpeciesState.db2 and BattlePetBreedState.db2 +// TODO: expand this enum if needed +enum BattlePetState +{ + STATE_MAX_HEALTH_BONUS = 2, + STATE_INTERNAL_INITIAL_LEVEL = 17, + STATE_STAT_POWER = 18, + STATE_STAT_STAMINA = 19, + STATE_STAT_SPEED = 20, + STATE_MOD_DAMAGE_DEALT_PERCENT = 23, + STATE_GENDER = 78, // 1 - male, 2 - female + STATE_COSMETIC_WATER_BUBBLED = 85, + STATE_SPECIAL_IS_COCKROACH = 93, + STATE_COSMETIC_FLY_TIER = 128, + STATE_COSMETIC_BIGGLESWORTH = 144, + STATE_PASSIVE_ELITE = 153, + STATE_PASSIVE_BOSS = 162, + STATE_COSMETIC_TREASURE_GOBLIN = 176, + // these are not in BattlePetState.db2 but are used in BattlePetSpeciesState.db2 + STATE_START_WITH_BUFF = 183, + STATE_START_WITH_BUFF_2 = 184 +}; + +enum BattlePetSaveInfo +{ + BATTLE_PET_UNCHANGED = 0, + BATTLE_PET_CHANGED = 1, + BATTLE_PET_NEW = 2, + BATTLE_PET_REMOVED = 3 +}; + +class BattlePetMgr +{ +public: + struct BattlePet + { + void CalculateStats(); + + WorldPackets::BattlePet::BattlePet PacketInfo; + BattlePetSaveInfo SaveInfo; + }; + + explicit BattlePetMgr(WorldSession* owner); + + static void Initialize(); + + static uint16 RollPetBreed(uint32 species); + static uint8 GetDefaultPetQuality(uint32 species); + + void LoadFromDB(PreparedQueryResult pets, PreparedQueryResult slots); + void SaveToDB(SQLTransaction& trans); + + BattlePet* GetPet(ObjectGuid guid); + void AddPet(uint32 species, uint32 creatureId, uint16 breed, uint8 quality, uint16 level = 1); + void RemovePet(ObjectGuid guid); + + uint8 GetPetCount(uint32 species) const; + + WorldPackets::BattlePet::BattlePetSlot* GetSlot(uint8 slot) { return &_slots[slot]; } + void UnlockSlot(uint8 slot); + + WorldSession* GetOwner() const { return _owner; } + + uint16 GetTrapLevel() const { return _trapLevel; } + std::vector<BattlePet> GetLearnedPets() const; + std::vector<WorldPackets::BattlePet::BattlePetSlot> GetSlots() const { return _slots; } + + void CageBattlePet(ObjectGuid guid); + void HealBattlePetsPct(uint8 pct); + + void SummonPet(ObjectGuid guid); + + void SendUpdates(std::vector<BattlePet> pets, bool petAdded); + void SendError(BattlePetError error, uint32 creatureId); + +private: + WorldSession* _owner; + uint16 _trapLevel = 0; + std::unordered_map<uint64 /*battlePetGuid*/, BattlePet> _pets; + std::vector<WorldPackets::BattlePet::BattlePetSlot> _slots; + + static void LoadAvailablePetBreeds(); + static void LoadDefaultPetQualities(); + + // hash no longer required in C++14 + static std::unordered_map<uint16 /*BreedID*/, std::unordered_map<BattlePetState /*state*/, int32 /*value*/, std::hash<std::underlying_type<BattlePetState>::type> >> _battlePetBreedStates; + static std::unordered_map<uint32 /*SpeciesID*/, std::unordered_map<BattlePetState /*state*/, int32 /*value*/, std::hash<std::underlying_type<BattlePetState>::type> >> _battlePetSpeciesStates; + static std::unordered_map<uint32 /*SpeciesID*/, std::unordered_set<uint8 /*breed*/>> _availableBreedsPerSpecies; + static std::unordered_map<uint32 /*SpeciesID*/, uint8 /*quality*/> _defaultQualityPerSpecies; +}; + +#endif // BattlePetMgr_h__ diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 0ed6b78d580..14bb8f25389 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -16,6 +16,7 @@ file(GLOB_RECURSE sources_AuctionHouse AuctionHouse/*.cpp AuctionHouse/*.h) file(GLOB_RECURSE sources_AuctionHouseBot AuctionHouseBot/*.cpp AuctionHouseBot/*.h) file(GLOB_RECURSE sources_Battlefield Battlefield/*.cpp Battlefield/*.h) file(GLOB_RECURSE sources_Battlegrounds Battlegrounds/*.cpp Battlegrounds/*.h) +file(GLOB_RECURSE sources_BattlePets BattlePets/*.cpp BattlePets/*.h) file(GLOB_RECURSE sources_Calendar Calendar/*.cpp Calendar/*.h) file(GLOB_RECURSE sources_Chat Chat/*.cpp Chat/*.h) file(GLOB_RECURSE sources_Combat Combat/*.cpp Combat/*.h) @@ -68,6 +69,7 @@ set(game_STAT_SRCS ${sources_AuctionHouseBot} ${sources_Battlefield} ${sources_Battlegrounds} + ${sources_BattlePets} ${sources_Calendar} ${sources_Chat} ${sources_Combat} @@ -118,6 +120,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Battlefield/Zones ${CMAKE_CURRENT_SOURCE_DIR}/Battlegrounds ${CMAKE_CURRENT_SOURCE_DIR}/Battlegrounds/Zones + ${CMAKE_CURRENT_SOURCE_DIR}/BattlePets ${CMAKE_CURRENT_SOURCE_DIR}/Calendar ${CMAKE_CURRENT_SOURCE_DIR}/Chat ${CMAKE_CURRENT_SOURCE_DIR}/Chat/Channels diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index 0485715f287..ae26119986c 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -29,6 +29,10 @@ DB2Storage<AreaGroupEntry> sAreaGroupStore("AreaGroup.db2", DB2Storage<AreaGroupMemberEntry> sAreaGroupMemberStore("AreaGroupMember.db2", AreaGroupMemberFormat, HOTFIX_SEL_AREA_GROUP_MEMBER); DB2Storage<AuctionHouseEntry> sAuctionHouseStore("AuctionHouse.db2", AuctionHouseFormat, HOTFIX_SEL_AUCTION_HOUSE); DB2Storage<BarberShopStyleEntry> sBarberShopStyleStore("BarberShopStyle.db2", BarberShopStyleFormat, HOTFIX_SEL_BARBER_SHOP_STYLE); +DB2Storage<BattlePetBreedQualityEntry> sBattlePetBreedQualityStore("BattlePetBreedQuality.db2", BattlePetBreedQualityFormat, HOTFIX_SEL_BATTLE_PET_BREED_QUALITY); +DB2Storage<BattlePetBreedStateEntry> sBattlePetBreedStateStore("BattlePetBreedState.db2", BattlePetBreedStateFormat, HOTFIX_SEL_BATTLE_PET_BREED_STATE); +DB2Storage<BattlePetSpeciesEntry> sBattlePetSpeciesStore("BattlePetSpecies.db2", BattlePetSpeciesFormat, HOTFIX_SEL_BATTLE_PET_SPECIES); +DB2Storage<BattlePetSpeciesStateEntry> sBattlePetSpeciesStateStore("BattlePetSpeciesState.db2", BattlePetSpeciesStateFormat, HOTFIX_SEL_BATTLE_PET_SPECIES_STATE); DB2Storage<BroadcastTextEntry> sBroadcastTextStore("BroadcastText.db2", BroadcastTextFormat, HOTFIX_SEL_BROADCAST_TEXT); DB2Storage<CharStartOutfitEntry> sCharStartOutfitStore("CharStartOutfit.db2", CharStartOutfitFormat, HOTFIX_SEL_CHAR_START_OUTFIT); DB2Storage<ChrClassesXPowerTypesEntry> sChrClassesXPowerTypesStore("ChrClassesXPowerTypes.db2", ChrClassesXPowerTypesFormat, HOTFIX_SEL_CHR_CLASSES_X_POWER_TYPES); @@ -78,6 +82,7 @@ DB2Storage<ItemRandomSuffixEntry> sItemRandomSuffixStore("ItemRand DB2Storage<ItemSparseEntry> sItemSparseStore("Item-sparse.db2", ItemSparseFormat, HOTFIX_SEL_ITEM_SPARSE); DB2Storage<ItemSpecEntry> sItemSpecStore("ItemSpec.db2", ItemSpecFormat, HOTFIX_SEL_ITEM_SPEC); DB2Storage<ItemSpecOverrideEntry> sItemSpecOverrideStore("ItemSpecOverride.db2", ItemSpecOverrideFormat, HOTFIX_SEL_ITEM_SPEC_OVERRIDE); +DB2Storage<ItemToBattlePetSpeciesEntry> sItemToBattlePetSpeciesStore("ItemToBattlePetSpecies.db2", ItemToBattlePetSpeciesFormat, HOTFIX_SEL_ITEM_TO_BATTLE_PET_SPECIES); DB2Storage<ItemXBonusTreeEntry> sItemXBonusTreeStore("ItemXBonusTree.db2", ItemXBonusTreeFormat, HOTFIX_SEL_ITEM_X_BONUS_TREE); DB2Storage<KeyChainEntry> sKeyChainStore("KeyChain.db2", KeyChainFormat, HOTFIX_SEL_KEY_CHAIN); DB2Storage<MailTemplateEntry> sMailTemplateStore("MailTemplate.db2", MailTemplateFormat, HOTFIX_SEL_MAIL_TEMPLATE); @@ -196,8 +201,12 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale) LOAD_DB2(sAchievementStore); LOAD_DB2(sAreaGroupMemberStore); LOAD_DB2(sAreaGroupStore); + LOAD_DB2(sBattlePetBreedQualityStore); + LOAD_DB2(sBattlePetBreedStateStore); LOAD_DB2(sAuctionHouseStore); LOAD_DB2(sBarberShopStyleStore); + LOAD_DB2(sBattlePetSpeciesStore); + LOAD_DB2(sBattlePetSpeciesStateStore); LOAD_DB2(sBroadcastTextStore); LOAD_DB2(sCharStartOutfitStore); LOAD_DB2(sChrClassesXPowerTypesStore); @@ -247,6 +256,7 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale) LOAD_DB2(sItemSpecOverrideStore); LOAD_DB2(sItemSpecStore); LOAD_DB2(sItemStore); + LOAD_DB2(sItemToBattlePetSpeciesStore); LOAD_DB2(sItemXBonusTreeStore); LOAD_DB2(sKeyChainStore); LOAD_DB2(sMailTemplateStore); diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index 685d251f685..4184ab5b5d4 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -27,6 +27,10 @@ extern DB2Storage<AchievementEntry> sAchievementStore; extern DB2Storage<AuctionHouseEntry> sAuctionHouseStore; extern DB2Storage<BarberShopStyleEntry> sBarberShopStyleStore; +extern DB2Storage<BattlePetBreedQualityEntry> sBattlePetBreedQualityStore; +extern DB2Storage<BattlePetBreedStateEntry> sBattlePetBreedStateStore; +extern DB2Storage<BattlePetSpeciesEntry> sBattlePetSpeciesStore; +extern DB2Storage<BattlePetSpeciesStateEntry> sBattlePetSpeciesStateStore; extern DB2Storage<BroadcastTextEntry> sBroadcastTextStore; extern DB2Storage<CharStartOutfitEntry> sCharStartOutfitStore; extern DB2Storage<CinematicSequencesEntry> sCinematicSequencesStore; @@ -70,6 +74,7 @@ extern DB2Storage<ItemRandomSuffixEntry> sItemRandomSuffixStore; extern DB2Storage<ItemSparseEntry> sItemSparseStore; extern DB2Storage<ItemSpecEntry> sItemSpecStore; extern DB2Storage<ItemSpecOverrideEntry> sItemSpecOverrideStore; +extern DB2Storage<ItemToBattlePetSpeciesEntry> sItemToBattlePetSpeciesStore; extern DB2Storage<MailTemplateEntry> sMailTemplateStore; extern DB2Storage<ModifierTreeEntry> sModifierTreeStore; extern DB2Storage<MountCapabilityEntry> sMountCapabilityStore; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 289d895c024..f2f8bec2b68 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -77,6 +77,42 @@ struct BarberShopStyleEntry uint32 Data; // 7 (real ID to hair/facial hair) }; +struct BattlePetBreedQualityEntry +{ + uint32 ID; // 0 + uint32 Quality; // 1 + float Modifier; // 2 +}; + +struct BattlePetBreedStateEntry +{ + uint32 ID; // 0 + uint32 BreedID; // 1 + uint32 State; // 2 + int32 Value; // 3 +}; + +struct BattlePetSpeciesEntry +{ + uint32 ID; // 0 + uint32 CreatureID; // 1 + uint32 IconFileID; // 2 + uint32 SummonSpellID; // 3 + uint32 PetType; // 4 + int32 Source; // 5 + uint32 Flags; // 6 + LocalizedString* SourceText; // 7 + LocalizedString* Description; // 8 +}; + +struct BattlePetSpeciesStateEntry +{ + uint32 ID; // 0 + uint32 SpeciesID; // 1 + uint32 State; // 2 + int32 Value; // 3 +}; + #define MAX_BROADCAST_TEXT_EMOTES 3 struct BroadcastTextEntry @@ -830,6 +866,12 @@ struct ItemSpecOverrideEntry uint32 SpecID; // 2 }; +struct ItemToBattlePetSpeciesEntry +{ + uint32 ID; // 0 + uint32 BattlePetSpeciesID; // 1 +}; + struct ItemXBonusTreeEntry { uint32 ID; // 0 diff --git a/src/server/game/DataStores/DB2fmt.h b/src/server/game/DataStores/DB2fmt.h index 0ebf8d2063e..ab9e2e0ae4e 100644 --- a/src/server/game/DataStores/DB2fmt.h +++ b/src/server/game/DataStores/DB2fmt.h @@ -23,6 +23,10 @@ char const AreaGroupFormat[] = "n"; char const AreaGroupMemberFormat[] = "nii"; char const AuctionHouseFormat[] = "niiis"; char const BarberShopStyleFormat[] = "nissfiii"; +char const BattlePetBreedQualityFormat[] = "nif"; +char const BattlePetBreedStateFormat[] = "niii"; +char const BattlePetSpeciesFormat[] = "niiiiiiss"; +char const BattlePetSpeciesStateFormat[] = "niii"; char const BroadcastTextFormat[] = "nissiiiiiiiii"; char const CharStartOutfitFormat[] = "nbbbbiiiiiiiiiiiiiiiiiiiiiiiiii"; char const ChrClassesXPowerTypesFormat[] = "iii"; @@ -72,6 +76,7 @@ char const ItemRandomSuffixFormat[] = "nssiiiiiiiiii"; char const ItemSparseFormat[] = "niiiiffiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiffffffffffiiifisssssiiiiiiiiiiiiiiiiiiifiiifiii"; char const ItemSpecFormat[] = "niiiiii"; char const ItemSpecOverrideFormat[] = "nii"; +char const ItemToBattlePetSpeciesFormat[] = "ni"; char const ItemXBonusTreeFormat[] = "nii"; char const KeyChainFormat[] = "nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"; char const MailTemplateFormat[] = "ns"; diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index d7125293671..ed1a1470e91 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -159,6 +159,7 @@ enum AchievementCriteriaAdditionalCondition ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_RATED_BATTLEGROUND = 63, // NYI ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_PROJECT_RARITY = 65, ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_PROJECT_RACE = 66, + ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_BATTLE_PET_SPECIES = 91, ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_QUALITY = 145, ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_FOLLOWER_LEVEL = 146, ACHIEVEMENT_CRITERIA_ADDITIONAL_CONDITION_GARRISON_RARE_MISSION = 147, // NYI diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 4d65598c298..6c7d390c069 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -351,6 +351,10 @@ void Item::SaveToDB(SQLTransaction& trans) stmt->setUInt32(++index, GetModifier(ITEM_MODIFIER_TRANSMOG_ITEM_ID) | (GetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_MOD) << 24)); stmt->setUInt32(++index, GetModifier(ITEM_MODIFIER_UPGRADE_ID)); stmt->setUInt32(++index, GetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION)); + stmt->setUInt32(++index, GetModifier(ITEM_MODIFIER_BATTLE_PET_SPECIES_ID)); + stmt->setUInt32(++index, GetModifier(ITEM_MODIFIER_BATTLE_PET_BREED_DATA)); + stmt->setUInt32(++index, GetModifier(ITEM_MODIFIER_BATTLE_PET_LEVEL)); + stmt->setUInt32(++index, GetModifier(ITEM_MODIFIER_BATTLE_PET_DISPLAY_ID)); std::ostringstream bonusListIDs; for (uint32 bonusListID : GetDynamicValues(ITEM_DYNAMIC_FIELD_BONUSLIST_IDS)) @@ -405,8 +409,10 @@ void Item::SaveToDB(SQLTransaction& trans) bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fields, uint32 entry) { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - //result = CharacterDatabase.PQuery("SELECT guid, itemEntry, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, transmogrification, upgradeId, enchantIllusion, bonusListIDs FROM item_instance WHERE guid = '%u'", guid); + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + //result = CharacterDatabase.PQuery("SELECT guid, itemEntry, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, + // 13 14 15 16 17 18 19 20 + // transmogrification, upgradeId, enchantIllusion, battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, bonusListIDs FROM item_instance WHERE guid = '%u'", guid); // create item before any checks for store correct guid // and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB @@ -482,8 +488,12 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie } SetModifier(ITEM_MODIFIER_UPGRADE_ID, fields[14].GetUInt32()); SetModifier(ITEM_MODIFIER_ENCHANT_ILLUSION, fields[15].GetUInt32()); + SetModifier(ITEM_MODIFIER_BATTLE_PET_SPECIES_ID, fields[16].GetUInt32()); + SetModifier(ITEM_MODIFIER_BATTLE_PET_BREED_DATA, fields[17].GetUInt32()); + SetModifier(ITEM_MODIFIER_BATTLE_PET_LEVEL, fields[18].GetUInt16()); + SetModifier(ITEM_MODIFIER_BATTLE_PET_DISPLAY_ID, fields[19].GetUInt32()); - Tokenizer bonusListIDs(fields[16].GetString(), ' '); + Tokenizer bonusListIDs(fields[20].GetString(), ' '); for (char const* token : bonusListIDs) { uint32 bonusListID = atoul(token); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 3b62f9f59a1..901bd81ecba 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -27,6 +27,7 @@ #include "Battleground.h" #include "BattlegroundMgr.h" #include "BattlegroundScore.h" +#include "BattlePetMgr.h" #include "CellImpl.h" #include "ChannelMgr.h" #include "CharacterDatabaseCleaner.h" @@ -13699,10 +13700,10 @@ void Player::SendNewItem(Item* item, uint32 quantity, bool pushed, bool created, packet.Quantity = quantity; packet.QuantityInInventory = GetItemCount(item->GetEntry()); //packet.DungeonEncounterID; - //packet.BattlePetBreedID; - //packet.BattlePetBreedQuality; - //packet.BattlePetSpeciesID; - //packet.BattlePetLevel; + packet.BattlePetBreedID = item->GetModifier(ITEM_MODIFIER_BATTLE_PET_BREED_DATA) & 0xFFFFFF; + packet.BattlePetBreedQuality = (item->GetModifier(ITEM_MODIFIER_BATTLE_PET_BREED_DATA) >> 24) & 0xFF; + packet.BattlePetSpeciesID = item->GetModifier(ITEM_MODIFIER_BATTLE_PET_SPECIES_ID); + packet.BattlePetLevel = item->GetModifier(ITEM_MODIFIER_BATTLE_PET_LEVEL); packet.ItemGUID = item->GetGUID(); @@ -17650,8 +17651,10 @@ void Player::LoadCorpse() void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 - // SELECT ii.guid, ii.itemEntry, ii.creatorGuid, ii.giftCreatorGuid, ii.count, ii.duration, ii.charges, ii.flags, ii.enchantments, ii.randomPropertyId, ii.durability, ii.playedTime, ii.text, ii.transmogrification, ii.upgradeId, ii.enchantIllusion, ii.bonusListIDs, bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ? ORDER BY bag, slot + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 + // SELECT ii.guid, ii.itemEntry, ii.creatorGuid, ii.giftCreatorGuid, ii.count, ii.duration, ii.charges, ii.flags, ii.enchantments, ii.randomPropertyId, ii.durability, ii.playedTime, ii.text, ii.transmogrification, ii.upgradeId + // 15 16 17 18 19 20 21 22 + // ii.enchantIllusion, battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, ii.bonusListIDs, bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ? ORDER BY bag, slot //NOTE: the "order by `bag`" is important because it makes sure //the bagMap is filled before items in the bags are loaded //NOTE2: the "order by `slot`" is needed because mainhand weapons are (wrongly?) @@ -17673,8 +17676,8 @@ void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff) Field* fields = result->Fetch(); if (Item* item = _LoadItem(trans, zoneId, timeDiff, fields)) { - ObjectGuid bagGuid = fields[17].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[17].GetUInt64()) : ObjectGuid::Empty; - uint8 slot = fields[18].GetUInt8(); + ObjectGuid bagGuid = fields[21].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[21].GetUInt64()) : ObjectGuid::Empty; + uint8 slot = fields[22].GetUInt8(); uint8 err = EQUIP_ERR_OK; // Item is not in bag @@ -17995,7 +17998,7 @@ void Player::_LoadMailedItems(Mail* mail) Item* item = NewItemOrBag(proto); - ObjectGuid ownerGuid = fields[17].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[17].GetUInt64()) : ObjectGuid::Empty; + ObjectGuid ownerGuid = fields[21].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[21].GetUInt64()) : ObjectGuid::Empty; if (!item->LoadFromDB(itemGuid, ownerGuid, fields, itemEntry)) { TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems - Item in mail (%u) doesn't exist !!!! - item guid: " UI64FMTD ", deleted from mail", mail->messageID, itemGuid); @@ -19188,9 +19191,11 @@ void Player::SaveToDB(bool create /*=false*/) CharacterDatabase.CommitTransaction(trans); - SQLTransaction transLogin = LoginDatabase.BeginTransaction(); - GetSession()->SaveAccountToys(transLogin); - LoginDatabase.CommitTransaction(transLogin); + // TODO: Move this out + trans = LoginDatabase.BeginTransaction(); + GetSession()->SaveAccountToys(trans); + GetSession()->GetBattlePetMgr()->SaveToDB(trans); + LoginDatabase.CommitTransaction(trans); // save pet (hunter pet level and experience and all type pets health/mana). if (Pet* pet = GetPet()) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index cddcfd1ef80..d4973e0f332 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -532,7 +532,7 @@ enum PlayerFlags PLAYER_FLAGS_UNK21 = 0x00200000, PLAYER_FLAGS_COMMENTATOR2 = 0x00400000, PLAYER_ALLOW_ONLY_ABILITY = 0x00800000, // used by bladestorm and killing spree, allowed only spells with SPELL_ATTR0_REQ_AMMO, SPELL_EFFECT_ATTACK, checked only for active player - PLAYER_FLAGS_UNK24 = 0x01000000, // disabled all melee ability on tab include autoattack + PLAYER_FLAGS_PET_BATTLES_UNLOCKED = 0x01000000, // enables pet battles PLAYER_FLAGS_NO_XP_GAIN = 0x02000000, PLAYER_FLAGS_UNK26 = 0x04000000, PLAYER_FLAGS_AUTO_DECLINE_GUILD = 0x08000000, // Automatically declines guild invites diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index e93a1da83b3..e7347a00732 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -368,7 +368,7 @@ void Guild::BankTab::LoadFromDB(Field* fields) bool Guild::BankTab::LoadItemFromDB(Field* fields) { - uint8 slotId = fields[19].GetUInt8(); + uint8 slotId = fields[23].GetUInt8(); ObjectGuid::LowType itemGuid = fields[0].GetUInt64(); uint32 itemEntry = fields[1].GetUInt32(); if (slotId >= GUILD_BANK_MAX_SLOTS) @@ -2395,7 +2395,7 @@ void Guild::LoadBankTabFromDB(Field* fields) bool Guild::LoadBankItemFromDB(Field* fields) { - uint8 tabId = fields[18].GetUInt8(); + uint8 tabId = fields[22].GetUInt8(); if (tabId >= _GetPurchasedTabsSize()) { TC_LOG_ERROR("guild", "Invalid tab for item (GUID: %u, id: #%u) in guild bank, skipped.", diff --git a/src/server/game/Guilds/GuildMgr.cpp b/src/server/game/Guilds/GuildMgr.cpp index 44816f5fd67..6db5b84a696 100644 --- a/src/server/game/Guilds/GuildMgr.cpp +++ b/src/server/game/Guilds/GuildMgr.cpp @@ -395,10 +395,10 @@ void GuildMgr::LoadGuilds() // Delete orphan guild bank items CharacterDatabase.DirectExecute("DELETE gbi FROM guild_bank_item gbi LEFT JOIN guild g ON gbi.guildId = g.guildId WHERE g.guildId IS NULL"); - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - // SELECT guid, itemEntry, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, transmogrification, upgradeId, enchantIllusion, bonusListIDs, - // 17 18 19 - // guildid, TabId, SlotId FROM guild_bank_item gbi INNER JOIN item_instance ii ON gbi.item_guid = ii.guid + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // SELECT guid, itemEntry, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, transmogrification, upgradeId, enchantIllusion, + // 17 18 19 20 21 22 23 + // battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, guildid, TabId, SlotId FROM guild_bank_item gbi INNER JOIN item_instance ii ON gbi.item_guid = ii.guid PreparedQueryResult result = CharacterDatabase.Query(CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_BANK_ITEMS)); if (!result) @@ -411,7 +411,7 @@ void GuildMgr::LoadGuilds() do { Field* fields = result->Fetch(); - uint64 guildId = fields[17].GetUInt64(); + uint64 guildId = fields[21].GetUInt64(); if (Guild* guild = GetGuildById(guildId)) guild->LoadBankItemFromDB(fields); diff --git a/src/server/game/Handlers/BattlePetHandler.cpp b/src/server/game/Handlers/BattlePetHandler.cpp new file mode 100644 index 00000000000..bd44ab73791 --- /dev/null +++ b/src/server/game/Handlers/BattlePetHandler.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "WorldSession.h" +#include "BattlePetMgr.h" +#include "BattlePetPackets.h" +#include "Player.h" + +void WorldSession::HandleBattlePetRequestJournal(WorldPackets::BattlePet::BattlePetRequestJournal& /*battlePetRequestJournal*/) +{ + // TODO: Move this to BattlePetMgr::SendJournal() just to have all packets in one file + WorldPackets::BattlePet::BattlePetJournal battlePetJournal; + battlePetJournal.Trap = GetBattlePetMgr()->GetTrapLevel(); + + for (auto itr : GetBattlePetMgr()->GetLearnedPets()) + battlePetJournal.Pets.push_back(itr.PacketInfo); + + battlePetJournal.Slots = GetBattlePetMgr()->GetSlots(); + SendPacket(battlePetJournal.Write()); +} + +void WorldSession::HandleBattlePetSetBattleSlot(WorldPackets::BattlePet::BattlePetSetBattleSlot& battlePetSetBattleSlot) +{ + if (BattlePetMgr::BattlePet* pet = GetBattlePetMgr()->GetPet(battlePetSetBattleSlot.PetGuid)) + GetBattlePetMgr()->GetSlot(battlePetSetBattleSlot.Slot)->Pet = pet->PacketInfo; +} + +void WorldSession::HandleBattlePetModifyName(WorldPackets::BattlePet::BattlePetModifyName& battlePetModifyName) +{ + if (BattlePetMgr::BattlePet* pet = GetBattlePetMgr()->GetPet(battlePetModifyName.PetGuid)) + { + pet->PacketInfo.Name = battlePetModifyName.Name; + + if (pet->SaveInfo != BATTLE_PET_NEW) + pet->SaveInfo = BATTLE_PET_CHANGED; + } +} + +void WorldSession::HandleBattlePetDeletePet(WorldPackets::BattlePet::BattlePetDeletePet& battlePetDeletePet) +{ + GetBattlePetMgr()->RemovePet(battlePetDeletePet.PetGuid); +} + +void WorldSession::HandleBattlePetSetFlags(WorldPackets::BattlePet::BattlePetSetFlags& battlePetSetFlags) +{ + if (BattlePetMgr::BattlePet* pet = GetBattlePetMgr()->GetPet(battlePetSetFlags.PetGuid)) + { + if (battlePetSetFlags.ControlType == 2) // 2 - apply + pet->PacketInfo.Flags |= battlePetSetFlags.Flags; + else // 3 - remove + pet->PacketInfo.Flags &= ~battlePetSetFlags.Flags; + + if (pet->SaveInfo != BATTLE_PET_NEW) + pet->SaveInfo = BATTLE_PET_CHANGED; + } +} + +void WorldSession::HandleCageBattlePet(WorldPackets::BattlePet::CageBattlePet& cageBattlePet) +{ + GetBattlePetMgr()->CageBattlePet(cageBattlePet.PetGuid); +} + +void WorldSession::HandleBattlePetSummon(WorldPackets::BattlePet::BattlePetSummon& battlePetSummon) +{ + GetBattlePetMgr()->SummonPet(battlePetSummon.PetGuid); +} diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index dfbd48f0dec..d50e721fb1d 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -22,6 +22,7 @@ #include "AuthenticationPackets.h" #include "Battleground.h" #include "BattlenetServerManager.h" +#include "BattlePetPackets.h" #include "CalendarMgr.h" #include "CharacterPackets.h" #include "Chat.h" @@ -985,6 +986,10 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) hotfixInfo.Hotfixes = sDB2Manager.GetHotfixData(); SendPacket(hotfixInfo.Write()); + // TODO: Move this to BattlePetMgr::SendJournalLock() just to have all packets in one file + WorldPackets::BattlePet::BattlePetJournalLockAcquired lock; + SendPacket(lock.Write()); + pCurrChar->SendInitialPacketsBeforeAddToMap(); //Show cinematic at the first time that player login diff --git a/src/server/game/Handlers/ItemHandler.cpp b/src/server/game/Handlers/ItemHandler.cpp index 425f021ed22..ccd3dd77109 100644 --- a/src/server/game/Handlers/ItemHandler.cpp +++ b/src/server/game/Handlers/ItemHandler.cpp @@ -27,6 +27,7 @@ #include "DB2Stores.h" #include "NPCPackets.h" #include "ItemPackets.h" +#include "BattlePetMgr.h" void WorldSession::HandleSplitItemOpcode(WorldPackets::Item::SplitItem& splitItem) { @@ -1264,3 +1265,21 @@ bool WorldSession::CanUseBank(ObjectGuid bankerGUID) const return true; } + +void WorldSession::HandleUseCritterItem(WorldPackets::Item::UseCritterItem& useCritterItem) +{ + Item* item = _player->GetItemByGuid(useCritterItem.ItemGuid); + if (!item) + return; + + ItemToBattlePetSpeciesEntry const* itemToBattlePetSpecies = sItemToBattlePetSpeciesStore.LookupEntry(item->GetEntry()); + if (!itemToBattlePetSpecies) + return; + + BattlePetSpeciesEntry const* battlePetSpecies = sBattlePetSpeciesStore.LookupEntry(itemToBattlePetSpecies->BattlePetSpeciesID); + if (!battlePetSpecies) + return; + + GetBattlePetMgr()->AddPet(battlePetSpecies->ID, battlePetSpecies->CreatureID, BattlePetMgr::RollPetBreed(battlePetSpecies->ID), BattlePetMgr::GetDefaultPetQuality(battlePetSpecies->ID)); + _player->DestroyItem(item->GetBagSlot(), item->GetSlot(), true); +} diff --git a/src/server/game/Server/Packets/BattlePetPackets.cpp b/src/server/game/Server/Packets/BattlePetPackets.cpp new file mode 100644 index 00000000000..435b9f54338 --- /dev/null +++ b/src/server/game/Server/Packets/BattlePetPackets.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "BattlePetPackets.h" +#include "World.h" + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::BattlePet::BattlePetSlot const& slot) +{ + data << (slot.Pet.Guid.IsEmpty() ? ObjectGuid::Create<HighGuid::BattlePet>(0) : slot.Pet.Guid); + data << slot.CollarID; + data << slot.Index; + data.WriteBit(slot.Locked); + data.FlushBits(); + + return data; +} + +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::BattlePet::BattlePet const& pet) +{ + data << pet.Guid; + data << pet.Species; + data << pet.CreatureID; + data << pet.CollarID; + data << pet.Breed; + data << pet.Level; + data << pet.Exp; + data << pet.Flags; + data << pet.Power; + data << pet.Health; + data << pet.MaxHealth; + data << pet.Speed; + data << pet.Quality; + data.WriteBits(pet.Name.size(), 7); + data.WriteBit(!pet.Owner.IsEmpty()); // HasOwnerInfo + data.WriteBit(pet.Name.empty()); // NoRename + data.FlushBits(); + + if (!pet.Owner.IsEmpty()) + { + data << pet.Owner; + data << GetVirtualRealmAddress(); // Virtual + data << GetVirtualRealmAddress(); // Native + } + + data.WriteString(pet.Name); + + return data; +} + +WorldPacket const* WorldPackets::BattlePet::BattlePetJournal::Write() +{ + _worldPacket << Trap; + _worldPacket << Slots.size(); + _worldPacket << Pets.size(); + + for (auto const& slot : Slots) + _worldPacket << slot; + + for (auto const& pet : Pets) + _worldPacket << pet; + + _worldPacket.WriteBit(1); // HasJournalLock + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::BattlePet::BattlePetUpdates::Write() +{ + _worldPacket << Pets.size(); + + for (auto const& pet : Pets) + _worldPacket << pet; + + _worldPacket.WriteBit(PetAdded); + _worldPacket.FlushBits(); + + return &_worldPacket; +} + + +WorldPacket const* WorldPackets::BattlePet::PetBattleSlotUpdates::Write() +{ + _worldPacket << Slots.size(); + + for (auto const& slot : Slots) + _worldPacket << slot; + + _worldPacket.WriteBit(NewSlot); + _worldPacket.WriteBit(AutoSlotted); + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +void WorldPackets::BattlePet::BattlePetSetBattleSlot::Read() +{ + _worldPacket >> PetGuid; + _worldPacket >> Slot; +} + +void WorldPackets::BattlePet::BattlePetModifyName::Read() +{ + _worldPacket >> PetGuid; + uint32 nameLength = _worldPacket.ReadBits(7); + bool hasDeclinedNames = _worldPacket.ReadBit(); + Name = _worldPacket.ReadString(nameLength); + + if (hasDeclinedNames) + { + uint8 declinedNameLengths[MAX_DECLINED_NAME_CASES]; + + for (uint8 i = 0; i < 5; ++i) + declinedNameLengths[i] = _worldPacket.ReadBits(7); + + for (uint8 i = 0; i < 5; ++i) + Declined.name[i] = _worldPacket.ReadString(declinedNameLengths[i]); + } +} + +void WorldPackets::BattlePet::BattlePetDeletePet::Read() +{ + _worldPacket >> PetGuid; +} + +void WorldPackets::BattlePet::BattlePetSetFlags::Read() +{ + _worldPacket >> PetGuid; + _worldPacket >> Flags; + ControlType = _worldPacket.ReadBits(2); +} + +void WorldPackets::BattlePet::CageBattlePet::Read() +{ + _worldPacket >> PetGuid; +} + +WorldPacket const* WorldPackets::BattlePet::BattlePetDeleted::Write() +{ + _worldPacket << PetGuid; + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::BattlePet::BattlePetError::Write() +{ + _worldPacket.WriteBits(Result, 4); + _worldPacket.FlushBits(); + _worldPacket << CreatureID; + + return &_worldPacket; +} + +void WorldPackets::BattlePet::BattlePetSummon::Read() +{ + _worldPacket >> PetGuid; +} diff --git a/src/server/game/Server/Packets/BattlePetPackets.h b/src/server/game/Server/Packets/BattlePetPackets.h new file mode 100644 index 00000000000..844cb855464 --- /dev/null +++ b/src/server/game/Server/Packets/BattlePetPackets.h @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef BattlePetPackets_h__ +#define BattlePetPackets_h__ + +#include "Packet.h" +#include "ObjectGuid.h" + +namespace WorldPackets +{ + namespace BattlePet + { + struct BattlePet + { + ObjectGuid Guid; + uint32 Species = 0; + uint32 CreatureID = 0; + uint32 CollarID = 0; // what's this? + uint16 Breed = 0; + uint16 Level = 0; + uint16 Exp = 0; + uint16 Flags = 0; + uint32 Power = 0; + uint32 Health = 0; + uint32 MaxHealth = 0; + uint32 Speed = 0; + uint8 Quality = 0; + ObjectGuid Owner; // for non-account wide pets only? (Guild Page, Guild Herald) + std::string Name; + }; + + struct BattlePetSlot + { + BattlePet Pet; + uint32 CollarID = 0; // what's this? + uint8 Index = 0; + bool Locked = true; + }; + + class BattlePetJournal final : public ServerPacket + { + public: + BattlePetJournal() : ServerPacket(SMSG_BATTLE_PET_JOURNAL) { } + + WorldPacket const* Write() override; + + uint16 Trap = 0; + std::vector<BattlePetSlot> Slots; + std::vector<BattlePet> Pets; + }; + + class BattlePetJournalLockAcquired final : public ServerPacket + { + public: + BattlePetJournalLockAcquired() : ServerPacket(SMSG_BATTLE_PET_JOURNAL_LOCK_ACQUIRED, 0) { } + + WorldPacket const* Write() override { return &_worldPacket; } + }; + + class BattlePetRequestJournal final : public ClientPacket + { + public: + BattlePetRequestJournal(WorldPacket&& packet) : ClientPacket(CMSG_BATTLE_PET_REQUEST_JOURNAL, std::move(packet)) { } + + void Read() override { } + }; + + class BattlePetUpdates final : public ServerPacket + { + public: + BattlePetUpdates() : ServerPacket(SMSG_BATTLE_PET_UPDATES) { } + + WorldPacket const* Write() override; + + std::vector<BattlePet> Pets; + bool PetAdded = false; + }; + + class PetBattleSlotUpdates final : public ServerPacket + { + public: + PetBattleSlotUpdates() : ServerPacket(SMSG_PET_BATTLE_SLOT_UPDATES) { } + + WorldPacket const* Write() override; + + std::vector<BattlePetSlot> Slots; + bool AutoSlotted = false; + bool NewSlot = false; + }; + + class BattlePetSetBattleSlot final : public ClientPacket + { + public: + BattlePetSetBattleSlot(WorldPacket&& packet) : ClientPacket(CMSG_BATTLE_PET_SET_BATTLE_SLOT, std::move(packet)) { } + + void Read() override; + + ObjectGuid PetGuid; + uint8 Slot = 0; + }; + + class BattlePetModifyName final : public ClientPacket + { + public: + BattlePetModifyName(WorldPacket&& packet) : ClientPacket(CMSG_BATTLE_PET_MODIFY_NAME, std::move(packet)) { } + + void Read() override; + + ObjectGuid PetGuid; + std::string Name; + DeclinedName Declined; + }; + + class BattlePetDeletePet final : public ClientPacket + { + public: + BattlePetDeletePet(WorldPacket&& packet) : ClientPacket(CMSG_BATTLE_PET_DELETE_PET, std::move(packet)) { } + + void Read() override; + + ObjectGuid PetGuid; + }; + + class BattlePetSetFlags final : public ClientPacket + { + public: + BattlePetSetFlags(WorldPacket&& packet) : ClientPacket(CMSG_BATTLE_PET_SET_FLAGS, std::move(packet)) { } + + void Read() override; + + ObjectGuid PetGuid; + uint32 Flags = 0; + uint8 ControlType = 0; + }; + + class CageBattlePet final : public ClientPacket + { + public: + CageBattlePet(WorldPacket&& packet) : ClientPacket(CMSG_CAGE_BATTLE_PET, std::move(packet)) { } + + void Read() override; + + ObjectGuid PetGuid; + }; + + class BattlePetDeleted final : public ServerPacket + { + public: + BattlePetDeleted() : ServerPacket(SMSG_BATTLE_PET_DELETED, 16) { } + + WorldPacket const* Write() override; + + ObjectGuid PetGuid; + }; + + class BattlePetError final : public ServerPacket + { + public: + BattlePetError() : ServerPacket(SMSG_BATTLE_PET_ERROR, 5) { } + + WorldPacket const* Write() override; + + uint8 Result = 0; + uint32 CreatureID = 0; + }; + + class BattlePetSummon final : public ClientPacket + { + public: + BattlePetSummon(WorldPacket&& packet) : ClientPacket(CMSG_BATTLE_PET_SUMMON, std::move(packet)) { } + + void Read() override; + + ObjectGuid PetGuid; + }; + } +} + +#endif // BattlePetPackets_h__ diff --git a/src/server/game/Server/Packets/ItemPackets.cpp b/src/server/game/Server/Packets/ItemPackets.cpp index 80bafbba104..b6b69b84eac 100644 --- a/src/server/game/Server/Packets/ItemPackets.cpp +++ b/src/server/game/Server/Packets/ItemPackets.cpp @@ -461,3 +461,8 @@ void WorldPackets::Item::TransmogrifyItems::Read() for (TransmogrifyItem& item : Items) _worldPacket >> item; } + +void WorldPackets::Item::UseCritterItem::Read() +{ + _worldPacket >> ItemGuid; +} diff --git a/src/server/game/Server/Packets/ItemPackets.h b/src/server/game/Server/Packets/ItemPackets.h index 943a681edbe..db7e9a01c0a 100644 --- a/src/server/game/Server/Packets/ItemPackets.h +++ b/src/server/game/Server/Packets/ItemPackets.h @@ -428,6 +428,16 @@ namespace WorldPackets Array<TransmogrifyItem, MAX_TRANSMOGRIFY_ITEMS> Items; }; + class UseCritterItem final : public ClientPacket + { + public: + UseCritterItem(WorldPacket&& packet) : ClientPacket(CMSG_USE_CRITTER_ITEM, std::move(packet)) { } + + void Read() override; + + ObjectGuid ItemGuid; + }; + ByteBuffer& operator>>(ByteBuffer& data, InvUpdate& invUpdate); } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 24a01eb9057..a214fd44556 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -22,6 +22,7 @@ #include "Packets/AuctionHousePackets.h" #include "Packets/BankPackets.h" #include "Packets/BattlegroundPackets.h" +#include "Packets/BattlePetPackets.h" #include "Packets/BlackMarketPackets.h" #include "Packets/CalendarPackets.h" #include "Packets/ChannelPackets.h" @@ -205,14 +206,14 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_BATTLE_PAY_GET_PURCHASE_LIST, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_BATTLE_PAY_START_PURCHASE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_BATTLE_PAY_START_VAS_PURCHASE, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_BATTLE_PET_DELETE_PET, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_BATTLE_PET_DELETE_PET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::BattlePet::BattlePetDeletePet, &WorldSession::HandleBattlePetDeletePet); DEFINE_HANDLER(CMSG_BATTLE_PET_DELETE_PET_CHEAT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_BATTLE_PET_MODIFY_NAME, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_BATTLE_PET_REQUEST_JOURNAL, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_BATTLE_PET_MODIFY_NAME, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::BattlePet::BattlePetModifyName, &WorldSession::HandleBattlePetModifyName); + DEFINE_HANDLER(CMSG_BATTLE_PET_REQUEST_JOURNAL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::BattlePet::BattlePetRequestJournal, &WorldSession::HandleBattlePetRequestJournal); DEFINE_HANDLER(CMSG_BATTLE_PET_REQUEST_JOURNAL_LOCK, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_BATTLE_PET_SET_BATTLE_SLOT, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_BATTLE_PET_SET_FLAGS, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_BATTLE_PET_SUMMON, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_BATTLE_PET_SET_BATTLE_SLOT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::BattlePet::BattlePetSetBattleSlot, &WorldSession::HandleBattlePetSetBattleSlot); + DEFINE_HANDLER(CMSG_BATTLE_PET_SET_FLAGS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::BattlePet::BattlePetSetFlags, &WorldSession::HandleBattlePetSetFlags); + DEFINE_HANDLER(CMSG_BATTLE_PET_SUMMON, STATUS_LOGGEDIN, PROCESS_INPLACE, WorldPackets::BattlePet::BattlePetSummon, &WorldSession::HandleBattlePetSummon); DEFINE_HANDLER(CMSG_BATTLE_PET_UPDATE_NOTIFY, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_BEGIN_TRADE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Trade::BeginTrade, &WorldSession::HandleBeginTradeOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_BF_MGR_ENTRY_INVITE_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleBfEntryInviteResponse ); @@ -231,7 +232,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_BUY_REAGENT_BANK, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_BUY_WOW_TOKEN_CONFIRM, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_BUY_WOW_TOKEN_START, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_CAGE_BATTLE_PET, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_CAGE_BATTLE_PET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::BattlePet::CageBattlePet, &WorldSession::HandleCageBattlePet); DEFINE_HANDLER(CMSG_CALENDAR_ADD_EVENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Calendar::CalendarAddEvent, &WorldSession::HandleCalendarAddEvent); DEFINE_OPCODE_HANDLER_OLD(CMSG_CALENDAR_COMPLAIN, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCalendarComplain ); DEFINE_HANDLER(CMSG_CALENDAR_COPY_EVENT, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Calendar::CalendarCopyEvent, &WorldSession::HandleCalendarCopyEvent); @@ -813,7 +814,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_UPGRADE_GARRISON, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_UPGRADE_ITEM, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_USED_FOLLOW, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); - DEFINE_HANDLER(CMSG_USE_CRITTER_ITEM, STATUS_UNHANDLED, PROCESS_INPLACE, WorldPackets::Null, &WorldSession::Handle_NULL); + DEFINE_HANDLER(CMSG_USE_CRITTER_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Item::UseCritterItem, &WorldSession::HandleUseCritterItem); DEFINE_HANDLER(CMSG_USE_EQUIPMENT_SET, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::EquipmentSet::UseEquipmentSet, &WorldSession::HandleUseEquipmentSet); DEFINE_HANDLER(CMSG_USE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Spells::UseItem, &WorldSession::HandleUseItemOpcode); DEFINE_HANDLER(CMSG_USE_TOY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, WorldPackets::Toy::UseToy, &WorldSession::HandleUseToy); @@ -916,16 +917,16 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PAY_START_PURCHASE_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PETS_HEALED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_CAGE_DATE_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_DELETED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_JOURNAL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_JOURNAL_LOCK_ACQUIRED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_DELETED, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_ERROR, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_JOURNAL, STATUS_NEVER, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_JOURNAL_LOCK_ACQUIRED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_JOURNAL_LOCK_DENIED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_LICENSE_CHANGED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_RESTORED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_REVOKED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_TRAP_LEVEL, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_UPDATES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_UPDATES, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BF_MGR_DROP_TIMER_CANCELLED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BF_MGR_DROP_TIMER_STARTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BF_MGR_EJECTED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); @@ -1458,7 +1459,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_BATTLE_REPLACEMENTS_MADE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_BATTLE_REQUEST_FAILED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_BATTLE_ROUND_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_BATTLE_SLOT_UPDATES, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_BATTLE_SLOT_UPDATES, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_CAST_FAILED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_CLEAR_SPELLS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PET_DISMISS_SOUND, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 37f2e2899fc..4e60c366a66 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -48,6 +48,7 @@ #include "ClientConfigPackets.h" #include "MiscPackets.h" #include "ChatPackets.h" +#include "BattlePetMgr.h" #include "PacketUtilities.h" #include <zlib.h> @@ -130,7 +131,8 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccoun _RBACData(NULL), expireTime(60000), // 1 min after socket loss, session is deleted forceExit(false), - m_currentBankerGUID() + m_currentBankerGUID(), + _battlePetMgr(Trinity::make_unique<BattlePetMgr>(this)) { memset(_tutorials, 0, sizeof(_tutorials)); @@ -1191,6 +1193,8 @@ public: enum { GLOBAL_ACCOUNT_TOYS = 0, + BATTLE_PETS, + BATTLE_PET_SLOTS, MAX_QUERIES }; @@ -1205,6 +1209,14 @@ public: stmt->setUInt32(0, battlenetAccountId); ok = SetPreparedQuery(GLOBAL_ACCOUNT_TOYS, stmt) && ok; + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BATTLE_PETS); + stmt->setUInt32(0, battlenetAccountId); + ok = SetPreparedQuery(BATTLE_PETS, stmt) && ok; + + stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BATTLE_PET_SLOTS); + stmt->setUInt32(0, battlenetAccountId); + ok = SetPreparedQuery(BATTLE_PET_SLOTS, stmt) && ok; + return ok; } }; @@ -1252,6 +1264,9 @@ void WorldSession::InitializeSessionCallback(SQLQueryHolder* realmHolder, SQLQue SendClientCacheVersion(sWorld->getIntConfig(CONFIG_CLIENTCACHE_VERSION)); SendTutorialsData(); + _battlePetMgr->LoadFromDB(holder->GetPreparedResult(AccountInfoQueryHolder::BATTLE_PETS), + holder->GetPreparedResult(AccountInfoQueryHolder::BATTLE_PET_SLOTS)); + delete realmHolder; delete holder; } diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index bc1faf778df..54c794ad0ca 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -33,6 +33,7 @@ #include "AccountMgr.h" #include <unordered_set> +class BattlePetMgr; class Channel; class Creature; class GameObject; @@ -117,6 +118,17 @@ namespace WorldPackets class ReportPvPPlayerAFK; } + namespace BattlePet + { + class BattlePetRequestJournal; + class BattlePetSetBattleSlot; + class BattlePetModifyName; + class BattlePetDeletePet; + class BattlePetSetFlags; + class BattlePetSummon; + class CageBattlePet; + } + namespace BlackMarket { class BlackMarketOpen; @@ -320,6 +332,7 @@ namespace WorldPackets class WrapItem; class CancelTempEnchantment; class TransmogrifyItems; + class UseCritterItem; } namespace Loot @@ -987,6 +1000,9 @@ class WorldSession uint32 GetRecruiterId() const { return recruiterId; } bool IsARecruiter() const { return isRecruiter; } + // Battle Pets + BattlePetMgr* GetBattlePetMgr() const { return _battlePetMgr.get(); } + public: // opcodes handlers void Handle_NULL(WorldPackets::Null& null); // not used @@ -1306,6 +1322,7 @@ class WorldSession void HandleSwapItem(WorldPackets::Item::SwapItem& swapItem); void HandleBuybackItem(WorldPackets::Item::BuyBackItem& packet); void HandleWrapItem(WorldPackets::Item::WrapItem& packet); + void HandleUseCritterItem(WorldPackets::Item::UseCritterItem& packet); void HandleAttackSwingOpcode(WorldPackets::Combat::AttackSwing& packet); void HandleAttackStopOpcode(WorldPackets::Combat::AttackStop& packet); @@ -1581,6 +1598,15 @@ class WorldSession void HandleGarrisonRequestBlueprintAndSpecializationData(WorldPackets::Garrison::GarrisonRequestBlueprintAndSpecializationData& garrisonRequestBlueprintAndSpecializationData); void HandleGarrisonGetBuildingLandmarks(WorldPackets::Garrison::GarrisonGetBuildingLandmarks& garrisonGetBuildingLandmarks); + // Battle Pets + void HandleBattlePetRequestJournal(WorldPackets::BattlePet::BattlePetRequestJournal& battlePetRequestJournal); + void HandleBattlePetSetBattleSlot(WorldPackets::BattlePet::BattlePetSetBattleSlot& battlePetSetBattleSlot); + void HandleBattlePetModifyName(WorldPackets::BattlePet::BattlePetModifyName& battlePetModifyName); + void HandleBattlePetDeletePet(WorldPackets::BattlePet::BattlePetDeletePet& battlePetDeletePet); + void HandleBattlePetSetFlags(WorldPackets::BattlePet::BattlePetSetFlags& battlePetSetFlags); + void HandleBattlePetSummon(WorldPackets::BattlePet::BattlePetSummon& battlePetSummon); + void HandleCageBattlePet(WorldPackets::BattlePet::CageBattlePet& cageBattlePet); + private: void InitializeQueryCallbackParameters(); void ProcessQueryCallbacks(); @@ -1694,6 +1720,8 @@ class WorldSession ObjectGuid m_currentBankerGUID; ToyBoxContainer _toys; + std::unique_ptr<BattlePetMgr> _battlePetMgr; + WorldSession(WorldSession const& right) = delete; WorldSession& operator=(WorldSession const& right) = delete; }; diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index c894c53aaf2..d5ed0a3c0a8 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -434,6 +434,9 @@ class Spell void EffectCreateGarrison(SpellEffIndex effIndex); void EffectAddGarrisonFollower(SpellEffIndex effIndex); void EffectActivateGarrisonBuilding(SpellEffIndex effIndex); + void EffectHealBattlePetPct(SpellEffIndex effIndex); + void EffectEnableBattlePets(SpellEffIndex effIndex); + void EffectUncageBattlePet(SpellEffIndex effIndex); typedef std::set<Aura*> UsedSpellMods; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index d10f76b76d3..1cb344da5aa 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -56,6 +56,7 @@ #include "Guild.h" #include "ReputationMgr.h" #include "AreaTrigger.h" +#include "BattlePetMgr.h" #include "Garrison.h" #include "CombatLogPackets.h" #include "DuelPackets.h" @@ -256,7 +257,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectNULL, //189 SPELL_EFFECT_LOOT &Spell::EffectNULL, //190 SPELL_EFFECT_190 &Spell::EffectNULL, //191 SPELL_EFFECT_TELEPORT_TO_DIGSITE - &Spell::EffectNULL, //192 SPELL_EFFECT_UNCAGE_BATTLEPET + &Spell::EffectUncageBattlePet, //192 SPELL_EFFECT_UNCAGE_BATTLEPET &Spell::EffectNULL, //193 SPELL_EFFECT_START_PET_BATTLE &Spell::EffectNULL, //194 SPELL_EFFECT_194 &Spell::EffectNULL, //195 SPELL_EFFECT_195 @@ -264,8 +265,8 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectNULL, //197 SPELL_EFFECT_197 &Spell::EffectNULL, //198 SPELL_EFFECT_198 &Spell::EffectNULL, //199 SPELL_EFFECT_199 - &Spell::EffectNULL, //200 SPELL_EFFECT_HEAL_BATTLEPET_PCT - &Spell::EffectNULL, //201 SPELL_EFFECT_ENABLE_BATTLE_PETS + &Spell::EffectHealBattlePetPct, //200 SPELL_EFFECT_HEAL_BATTLEPET_PCT + &Spell::EffectEnableBattlePets, //201 SPELL_EFFECT_ENABLE_BATTLE_PETS &Spell::EffectNULL, //202 SPELL_EFFECT_202 &Spell::EffectNULL, //203 SPELL_EFFECT_203 &Spell::EffectNULL, //204 SPELL_EFFECT_CHANGE_BATTLEPET_QUALITY @@ -2259,6 +2260,22 @@ void Spell::EffectLearnSpell(SpellEffIndex effIndex) uint32 spellToLearn = (m_spellInfo->Id == 483 || m_spellInfo->Id == 55884) ? damage : effectInfo->TriggerSpell; player->LearnSpell(spellToLearn, false); + if (m_spellInfo->Id == 55884) + { + if (BattlePetMgr* battlePetMgr = player->GetSession()->GetBattlePetMgr()) + { + for (auto entry : sBattlePetSpeciesStore) + { + if (entry->SummonSpellID == spellToLearn) + { + battlePetMgr->AddPet(entry->ID, entry->CreatureID, BattlePetMgr::RollPetBreed(entry->ID), BattlePetMgr::GetDefaultPetQuality(entry->ID)); + player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_OWN_BATTLE_PET_COUNT); + break; + } + } + } + } + TC_LOG_DEBUG("spells", "Spell: %s has learned spell %u from %s", player->GetGUID().ToString().c_str(), spellToLearn, m_caster->GetGUID().ToString().c_str()); } @@ -5861,3 +5878,85 @@ void Spell::EffectActivateGarrisonBuilding(SpellEffIndex effIndex) if (Garrison* garrison = unitTarget->ToPlayer()->GetGarrison()) garrison->ActivateBuilding(GetEffect(effIndex)->MiscValue); } + +void Spell::EffectHealBattlePetPct(SpellEffIndex effIndex) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) + return; + + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + if (BattlePetMgr* battlePetMgr = unitTarget->ToPlayer()->GetSession()->GetBattlePetMgr()) + battlePetMgr->HealBattlePetsPct(GetEffect(effIndex)->BasePoints); +} + +void Spell::EffectEnableBattlePets(SpellEffIndex /*effIndex*/) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) + return; + + if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) + return; + + Player* plr = unitTarget->ToPlayer(); + plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_PET_BATTLES_UNLOCKED); + plr->GetSession()->GetBattlePetMgr()->UnlockSlot(0); +} + +void Spell::EffectUncageBattlePet(SpellEffIndex /*effIndex*/) +{ + if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT) + return; + + if (!m_CastItem || !m_caster || m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + Player* plr = m_caster->ToPlayer(); + + // are we allowed to learn battle pets without it? + /*if (plr->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_PET_BATTLES_UNLOCKED)) + return; // send some error*/ + + uint32 speciesId = m_CastItem->GetModifier(ITEM_MODIFIER_BATTLE_PET_SPECIES_ID); + uint16 breed = m_CastItem->GetModifier(ITEM_MODIFIER_BATTLE_PET_BREED_DATA) & 0xFFFFFF; + uint8 quality = (m_CastItem->GetModifier(ITEM_MODIFIER_BATTLE_PET_BREED_DATA) >> 24) & 0xFF; + uint16 level = m_CastItem->GetModifier(ITEM_MODIFIER_BATTLE_PET_LEVEL); + uint32 creatureId = m_CastItem->GetModifier(ITEM_MODIFIER_BATTLE_PET_DISPLAY_ID); + + BattlePetSpeciesEntry const* speciesEntry = sBattlePetSpeciesStore.LookupEntry(speciesId); + if (!speciesEntry) + return; + + BattlePetMgr* battlePetMgr = plr->GetSession()->GetBattlePetMgr(); + if (!battlePetMgr) + return; + + uint16 maxLearnedLevel = 0; + + for (auto pet : battlePetMgr->GetLearnedPets()) + maxLearnedLevel = std::max(pet.PacketInfo.Level, maxLearnedLevel); + + // TODO: This means if you put your highest lvl pet into cage, you won't be able to uncage it again which is probably wrong. + // We will need to store maxLearnedLevel somewhere to avoid this behaviour. + if (maxLearnedLevel < level) + { + battlePetMgr->SendError(BATTLEPETRESULT_TOO_HIGH_LEVEL_TO_UNCAGE, creatureId); // or speciesEntry.CreatureID + SendCastResult(SPELL_FAILED_CANT_ADD_BATTLE_PET); + return; + } + + if (battlePetMgr->GetPetCount(speciesId) >= MAX_BATTLE_PETS_PER_SPECIES) + { + battlePetMgr->SendError(BATTLEPETRESULT_CANT_HAVE_MORE_PETS_OF_THAT_TYPE, creatureId); // or speciesEntry.CreatureID + SendCastResult(SPELL_FAILED_CANT_ADD_BATTLE_PET); + return; + } + + if (!plr->HasSpell(speciesEntry->SummonSpellID)) + plr->LearnSpell(speciesEntry->SummonSpellID, false); + + battlePetMgr->AddPet(speciesId, creatureId, breed, quality, level); + plr->DestroyItem(m_CastItem->GetBagSlot(), m_CastItem->GetSlot(), true); + m_CastItem = nullptr; +} diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index af1d7134663..d6cceac46fb 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -27,6 +27,7 @@ #include "AuctionHouseMgr.h" #include "BattlefieldMgr.h" #include "BattlegroundMgr.h" +#include "BattlePetMgr.h" #include "CalendarMgr.h" #include "Channel.h" #include "CharacterDatabaseCleaner.h" @@ -2026,6 +2027,9 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading realm names..."); sObjectMgr->LoadRealmNames(); + TC_LOG_INFO("server.loading", "Loading battle pets info..."); + BattlePetMgr::Initialize(); + uint32 startupDuration = GetMSTimeDiffToNow(startupBegin); TC_LOG_INFO("server.worldserver", "World initialized in %u minutes %u seconds", (startupDuration / 60000), ((startupDuration % 60000) / 1000)); |