aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/base/auth_database.sql50
-rw-r--r--sql/base/characters_database.sql4
-rw-r--r--sql/updates/auth/2015_09_09_00_auth.sql31
-rw-r--r--sql/updates/characters/2015_09_09_00_characters.sql5
-rw-r--r--sql/updates/hotfixes/2015_09_09_00_hotfixes.sql66
-rw-r--r--sql/updates/world/2015_09_09_00_world.sql3928
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp6
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.cpp17
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.h11
-rw-r--r--src/server/database/Database/Implementation/LoginDatabase.cpp9
-rw-r--r--src/server/database/Database/Implementation/LoginDatabase.h8
-rw-r--r--src/server/game/Achievements/AchievementMgr.cpp10
-rw-r--r--src/server/game/BattlePets/BattlePetMgr.cpp467
-rw-r--r--src/server/game/BattlePets/BattlePetMgr.h141
-rw-r--r--src/server/game/CMakeLists.txt3
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp10
-rw-r--r--src/server/game/DataStores/DB2Stores.h5
-rw-r--r--src/server/game/DataStores/DB2Structure.h42
-rw-r--r--src/server/game/DataStores/DB2fmt.h5
-rw-r--r--src/server/game/DataStores/DBCEnums.h1
-rw-r--r--src/server/game/Entities/Item/Item.cpp16
-rw-r--r--src/server/game/Entities/Player/Player.cpp29
-rw-r--r--src/server/game/Entities/Player/Player.h2
-rw-r--r--src/server/game/Guilds/Guild.cpp4
-rw-r--r--src/server/game/Guilds/GuildMgr.cpp10
-rw-r--r--src/server/game/Handlers/BattlePetHandler.cpp80
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp5
-rw-r--r--src/server/game/Handlers/ItemHandler.cpp19
-rw-r--r--src/server/game/Server/Packets/BattlePetPackets.cpp171
-rw-r--r--src/server/game/Server/Packets/BattlePetPackets.h194
-rw-r--r--src/server/game/Server/Packets/ItemPackets.cpp5
-rw-r--r--src/server/game/Server/Packets/ItemPackets.h10
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp29
-rw-r--r--src/server/game/Server/WorldSession.cpp17
-rw-r--r--src/server/game/Server/WorldSession.h28
-rw-r--r--src/server/game/Spells/Spell.h3
-rw-r--r--src/server/game/Spells/SpellEffects.cpp105
-rw-r--r--src/server/game/World/World.cpp4
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));