diff --git a/sql/characters.sql b/sql/characters.sql index 5d24fb5c8..89b6732ca 100644 --- a/sql/characters.sql +++ b/sql/characters.sql @@ -21,7 +21,7 @@ DROP TABLE IF EXISTS `character_db_version`; CREATE TABLE `character_db_version` ( - `required_s1350_11716_09_characters_mail` bit(1) default NULL + `required_s1980_xxxxx_01_characters_characters` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB'; -- @@ -230,6 +230,7 @@ CREATE TABLE `characters` ( `ammoId` int(10) UNSIGNED NOT NULL default '0', `knownTitles` longtext, `actionBars` tinyint(3) UNSIGNED NOT NULL default '0', + `grantableLevels` tinyint(3) UNSIGNED NOT NULL default '0', `deleteInfos_Account` int(11) UNSIGNED default NULL, `deleteInfos_Name` varchar(12) default NULL, `deleteDate` bigint(20) unsigned default NULL, diff --git a/sql/mangos.sql b/sql/mangos.sql index aa36b0bff..27df11cf3 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -23,7 +23,7 @@ DROP TABLE IF EXISTS `db_version`; CREATE TABLE `db_version` ( `version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL, - `required_s1957_12440_01_mangos_spell_area` bit(1) default NULL + `required_s1980_xxxxx_03_mangos_playercreateinfo_spell` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -438,6 +438,9 @@ INSERT INTO `command` VALUES ('account characters',3,'Syntax: .account characters [#accountId|$accountName]\r\n\r\nShow list all characters for account selected by provided #accountId or $accountName, or for selected player in game.'), ('account create',4,'Syntax: .account create $account $password\r\n\r\nCreate account and set password to it.'), ('account delete',4,'Syntax: .account delete $account\r\n\r\nDelete account with all characters.'), +('account friend add',3,'Syntax: .account friend add [#accountId|$accountName] [#friendaccountId|$friendaccountName]\r\n\r\nSet friend account.'), +('account friend delete',3,'Syntax: .account friend delete [#accountId|$accountName] [#friendaccountId|$friendaccountName]\r\n\r\nDelete friend account.'), +('account friend list',3,'Syntax: .account friend list [#accountId|$accountName]\r\n\r\nList friends for account.'), ('account lock',0,'Syntax: .account lock [on|off]\r\n\r\nAllow login from account only from current used IP or remove this requirement.'), ('account onlinelist',4,'Syntax: .account onlinelist\r\n\r\nShow list of online accounts.'), ('account password',0,'Syntax: .account password $old_password $new_password $new_password\r\n\r\nChange your account password.'), @@ -3807,7 +3810,9 @@ INSERT INTO `mangos_string` VALUES (1633,'|cffffff00The Alliance has taken control of Halaa!|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1634,'|cffffff00Halaa is defenseless!|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1635,'|cffffff00The Horde has collected 200 silithyst!|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), -(1636,'|cffffff00The Alliance has collected 200 silithyst!|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); +(1636,'|cffffff00The Alliance has collected 200 silithyst!|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(1700,'RAF system ok.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(1701,'RAF system error.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); /*!40000 ALTER TABLE `mangos_string` ENABLE KEYS */; UNLOCK TABLES; @@ -9285,6 +9290,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (1,1,22027,'Remove Insignia'), (1,1,22810,'Opening - No Text'), (1,1,32215,'Victorious State'), +(1,1,45927,'Summon Friend'), (1,2,81,'Dodge'), (1,2,107,'Block'), (1,2,198,'One-Handed Maces'), @@ -9324,6 +9330,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (1,2,22027,'Remove Insignia'), (1,2,22810,'Opening - No Text'), (1,2,27762,'Libram'), +(1,2,45927,'Summon Friend'), (1,4,81,'Dodge'), (1,4,203,'Unarmed'), (1,4,204,'Defense'), @@ -9362,6 +9369,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (1,4,21652,'Closing'), (1,4,22027,'Remove Insignia'), (1,4,22810,'Opening - No Text'), +(1,4,45927,'Summon Friend'), (1,5,81,'Dodge'), (1,5,198,'One-Handed Maces'), (1,5,203,'Unarmed'), @@ -9397,6 +9405,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (1,5,21652,'Closing'), (1,5,22027,'Remove Insignia'), (1,5,22810,'Opening - No Text'), +(1,5,45927,'Summon Friend'), (1,8,81,'Dodge'), (1,8,133,'Fireball'), (1,8,168,'Frost Armor'), @@ -9432,6 +9441,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (1,8,21652,'Closing'), (1,8,22027,'Remove Insignia'), (1,8,22810,'Opening - No Text'), +(1,8,45927,'Summon Friend'), (1,9,81,'Dodge'), (1,9,203,'Unarmed'), (1,9,204,'Defense'), @@ -9467,6 +9477,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (1,9,21652,'Closing'), (1,9,22027,'Remove Insignia'), (1,9,22810,'Opening - No Text'), +(1,9,45927,'Summon Friend'), (2,1,78,'Heroic Strike'), (2,1,81,'Dodge'), (2,1,107,'Block'), @@ -9507,6 +9518,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (2,1,22027,'Remove Insignia'), (2,1,22810,'Opening - No Text'), (2,1,32215,'Victorious State'), +(2,1,45927,'Summon Friend'), (2,3,75,'Auto Shot'), (2,3,81,'Dodge'), (2,3,196,'One-Handed Axes'), @@ -9544,6 +9556,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (2,3,22810,'Opening - No Text'), (2,3,24949,'Defensive State 2(DND)'), (2,3,34082,'Advantaged State(DND)'), +(2,3,45927,'Summon Friend'), (2,4,81,'Dodge'), (2,4,203,'Unarmed'), (2,4,204,'Defense'), @@ -9581,6 +9594,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (2,4,21652,'Closing'), (2,4,22027,'Remove Insignia'), (2,4,22810,'Opening - No Text'), +(2,4,45927,'Summon Friend'), (2,7,81,'Dodge'), (2,7,107,'Block'), (2,7,198,'One-Handed Maces'), @@ -9618,6 +9632,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (2,7,22810,'Opening - No Text'), (2,7,27763,'Totem'), (2,7,33697,'Blood Fury'), +(2,7,45927,'Summon Friend'), (2,9,81,'Dodge'), (2,9,203,'Unarmed'), (2,9,204,'Defense'), @@ -9652,6 +9667,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (2,9,22027,'Remove Insignia'), (2,9,22810,'Opening - No Text'), (2,9,33702,'Blood Fury'), +(2,9,45927,'Summon Friend'), (3,1,78,'Heroic Strike'), (3,1,81,'Dodge'), (3,1,107,'Block'), @@ -9693,6 +9709,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (3,1,22027,'Remove Insignia'), (3,1,22810,'Opening - No Text'), (3,1,32215,'Victorious State'), +(3,1,45927,'Summon Friend'), (3,2,81,'Dodge'), (3,2,107,'Block'), (3,2,198,'One-Handed Maces'), @@ -9732,6 +9749,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (3,2,22027,'Remove Insignia'), (3,2,22810,'Opening - No Text'), (3,2,27762,'Libram'), +(3,2,45927,'Summon Friend'), (3,3,75,'Auto Shot'), (3,3,81,'Dodge'), (3,3,196,'One-Handed Axes'), @@ -9770,6 +9788,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (3,3,22810,'Opening - No Text'), (3,3,24949,'Defensive State 2(DND)'), (3,3,34082,'Advantaged State(DND)'), +(3,3,45927,'Summon Friend'), (3,4,81,'Dodge'), (3,4,203,'Unarmed'), (3,4,204,'Defense'), @@ -9808,6 +9827,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (3,4,21652,'Closing'), (3,4,22027,'Remove Insignia'), (3,4,22810,'Opening - No Text'), +(3,4,45927,'Summon Friend'), (3,5,81,'Dodge'), (3,5,198,'One-Handed Maces'), (3,5,203,'Unarmed'), @@ -9843,6 +9863,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (3,5,21652,'Closing'), (3,5,22027,'Remove Insignia'), (3,5,22810,'Opening - No Text'), +(3,5,45927,'Summon Friend'), (4,1,78,'Heroic Strike'), (4,1,81,'Dodge'), (4,1,107,'Block'), @@ -9885,6 +9906,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (4,1,22027,'Remove Insignia'), (4,1,22810,'Opening - No Text'), (4,1,32215,'Victorious State'), +(4,1,45927,'Summon Friend'), (4,3,75,'Auto Shot'), (4,3,81,'Dodge'), (4,3,203,'Unarmed'), @@ -9924,6 +9946,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (4,3,22810,'Opening - No Text'), (4,3,24949,'Defensive State 2(DND)'), (4,3,34082,'Advantaged State(DND)'), +(4,3,45927,'Summon Friend'), (4,4,81,'Dodge'), (4,4,203,'Unarmed'), (4,4,204,'Defense'), @@ -9963,6 +9986,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (4,4,21652,'Closing'), (4,4,22027,'Remove Insignia'), (4,4,22810,'Opening - No Text'), +(4,4,45927,'Summon Friend'), (4,5,81,'Dodge'), (4,5,198,'One-Handed Maces'), (4,5,203,'Unarmed'), @@ -9999,6 +10023,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (4,5,21652,'Closing'), (4,5,22027,'Remove Insignia'), (4,5,22810,'Opening - No Text'), +(4,5,45927,'Summon Friend'), (4,11,81,'Dodge'), (4,11,203,'Unarmed'), (4,11,204,'Defense'), @@ -10036,6 +10061,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (4,11,22027,'Remove Insignia'), (4,11,22810,'Opening - No Text'), (4,11,27764,'Fetish'), +(4,11,45927,'Summon Friend'), (5,1,78,'Heroic Strike'), (5,1,81,'Dodge'), (5,1,107,'Block'), @@ -10077,6 +10103,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (5,1,22027,'Remove Insignia'), (5,1,22810,'Opening - No Text'), (5,1,32215,'Victorious State'), +(5,1,45927,'Summon Friend'), (5,4,81,'Dodge'), (5,4,203,'Unarmed'), (5,4,204,'Defense'), @@ -10115,6 +10142,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (5,4,21652,'Closing'), (5,4,22027,'Remove Insignia'), (5,4,22810,'Opening - No Text'), +(5,4,45927,'Summon Friend'), (5,5,81,'Dodge'), (5,5,198,'One-Handed Maces'), (5,5,203,'Unarmed'), @@ -10150,6 +10178,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (5,5,21652,'Closing'), (5,5,22027,'Remove Insignia'), (5,5,22810,'Opening - No Text'), +(5,5,45927,'Summon Friend'), (5,8,81,'Dodge'), (5,8,133,'Fireball'), (5,8,168,'Frost Armor'), @@ -10185,6 +10214,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (5,8,21652,'Closing'), (5,8,22027,'Remove Insignia'), (5,8,22810,'Opening - No Text'), +(5,8,45927,'Summon Friend'), (5,9,81,'Dodge'), (5,9,203,'Unarmed'), (5,9,204,'Defense'), @@ -10220,6 +10250,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (5,9,21652,'Closing'), (5,9,22027,'Remove Insignia'), (5,9,22810,'Opening - No Text'), +(5,9,45927,'Summon Friend'), (6,1,78,'Heroic Strike'), (6,1,81,'Dodge'), (6,1,107,'Block'), @@ -10261,6 +10292,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (6,1,22027,'Remove Insignia'), (6,1,22810,'Opening - No Text'), (6,1,32215,'Victorious State'), +(6,1,45927,'Summon Friend'), (6,3,75,'Auto Shot'), (6,3,81,'Dodge'), (6,3,196,'One-Handed Axes'), @@ -10299,6 +10331,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (6,3,22810,'Opening - No Text'), (6,3,24949,'Defensive State 2(DND)'), (6,3,34082,'Advantaged State(DND)'), +(6,3,45927,'Summon Friend'), (6,7,81,'Dodge'), (6,7,107,'Block'), (6,7,198,'One-Handed Maces'), @@ -10337,6 +10370,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (6,7,22027,'Remove Insignia'), (6,7,22810,'Opening - No Text'), (6,7,27763,'Totem'), +(6,7,45927,'Summon Friend'), (6,11,81,'Dodge'), (6,11,198,'One-Handed Maces'), (6,11,203,'Unarmed'), @@ -10373,6 +10407,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (6,11,22027,'Remove Insignia'), (6,11,22810,'Opening - No Text'), (6,11,27764,'Fetish'), +(6,11,45927,'Summon Friend'), (7,1,78,'Heroic Strike'), (7,1,81,'Dodge'), (7,1,107,'Block'), @@ -10414,6 +10449,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (7,1,22027,'Remove Insignia'), (7,1,22810,'Opening - No Text'), (7,1,32215,'Victorious State'), +(7,1,45927,'Summon Friend'), (7,4,81,'Dodge'), (7,4,203,'Unarmed'), (7,4,204,'Defense'), @@ -10452,6 +10488,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (7,4,21652,'Closing'), (7,4,22027,'Remove Insignia'), (7,4,22810,'Opening - No Text'), +(7,4,45927,'Summon Friend'), (7,8,81,'Dodge'), (7,8,133,'Fireball'), (7,8,168,'Frost Armor'), @@ -10487,6 +10524,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (7,8,21652,'Closing'), (7,8,22027,'Remove Insignia'), (7,8,22810,'Opening - No Text'), +(7,8,45927,'Summon Friend'), (7,9,81,'Dodge'), (7,9,203,'Unarmed'), (7,9,204,'Defense'), @@ -10522,6 +10560,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (7,9,21652,'Closing'), (7,9,22027,'Remove Insignia'), (7,9,22810,'Opening - No Text'), +(7,9,45927,'Summon Friend'), (8,1,78,'Heroic Strike'), (8,1,81,'Dodge'), (8,1,107,'Block'), @@ -10565,6 +10604,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (8,1,26290,'Bow Specialization'), (8,1,26296,'Berserking'), (8,1,32215,'Victorious State'), +(8,1,45927,'Summon Friend'), (8,3,75,'Auto Shot'), (8,3,81,'Dodge'), (8,3,196,'One-Handed Axes'), @@ -10604,6 +10644,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (8,3,24949,'Defensive State 2(DND)'), (8,3,26290,'Bow Specialization'), (8,3,34082,'Advantaged State(DND)'), +(8,3,45927,'Summon Friend'), (8,4,81,'Dodge'), (8,4,203,'Unarmed'), (8,4,204,'Defense'), @@ -10643,6 +10684,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (8,4,22810,'Opening - No Text'), (8,4,26290,'Bow Specialization'), (8,4,26297,'Berserking'), +(8,4,45927,'Summon Friend'), (8,5,81,'Dodge'), (8,5,198,'One-Handed Maces'), (8,5,203,'Unarmed'), @@ -10679,6 +10721,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (8,5,22027,'Remove Insignia'), (8,5,22810,'Opening - No Text'), (8,5,26290,'Bow Specialization'), +(8,5,45927,'Summon Friend'), (8,7,81,'Dodge'), (8,7,107,'Block'), (8,7,198,'One-Handed Maces'), @@ -10718,6 +10761,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (8,7,22810,'Opening - No Text'), (8,7,26290,'Bow Specialization'), (8,7,27763,'Totem'), +(8,7,45927,'Summon Friend'), (8,8,81,'Dodge'), (8,8,133,'Fireball'), (8,8,168,'Frost Armor'), @@ -10754,6 +10798,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (8,8,22027,'Remove Insignia'), (8,8,22810,'Opening - No Text'), (8,8,26290,'Bow Specialization'), +(8,8,45927,'Summon Friend'), (10,2,81,'Dodge'), (10,2,107,'Block'), (10,2,201,'One-Handed Swords'), @@ -10793,6 +10838,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (10,2,28730,'Arcane Torrent'), (10,2,28734,'Mana Tap'), (10,2,28877,'Arcane Affinity'), +(10,2,45927,'Summon Friend'), (10,3,75,'Auto Shot'), (10,3,81,'Dodge'), (10,3,203,'Unarmed'), @@ -10831,6 +10877,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (10,3,28734,'Mana Tap'), (10,3,28877,'Arcane Affinity'), (10,3,34082,'Advantaged State(DND)'), +(10,3,45927,'Summon Friend'), (10,4,81,'Dodge'), (10,4,203,'Unarmed'), (10,4,204,'Defense'), @@ -10869,6 +10916,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (10,4,25046,'Arcane Torrent'), (10,4,28734,'Mana Tap'), (10,4,28877,'Arcane Affinity'), +(10,4,45927,'Summon Friend'), (10,5,81,'Dodge'), (10,5,198,'One-Handed Maces'), (10,5,203,'Unarmed'), @@ -10904,6 +10952,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (10,5,28730,'Arcane Torrent'), (10,5,28734,'Mana Tap'), (10,5,28877,'Arcane Affinity'), +(10,5,45927,'Summon Friend'), (10,8,81,'Dodge'), (10,8,133,'Fireball'), (10,8,168,'Frost Armor'), @@ -10939,6 +10988,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (10,8,28730,'Arcane Torrent'), (10,8,28734,'Mana Tap'), (10,8,28877,'Arcane Affinity'), +(10,8,45927,'Summon Friend'), (10,9,81,'Dodge'), (10,9,203,'Unarmed'), (10,9,204,'Defense'), @@ -10974,6 +11024,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (10,9,28730,'Arcane Torrent'), (10,9,28734,'Mana Tap'), (10,9,28877,'Arcane Affinity'), +(10,9,45927,'Summon Friend'), (11,1,78,'Heroic Strike'), (11,1,81,'Dodge'), (11,1,107,'Block'), @@ -11015,6 +11066,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (11,1,28880,'Gift of the Naaru'), (11,1,29932,'Language Draenei'), (11,1,32215,'Victorious State'), +(11,1,45927,'Summon Friend'), (11,2,81,'Dodge'), (11,2,107,'Block'), (11,2,198,'One-Handed Maces'), @@ -11054,6 +11106,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (11,2,28875,'Gemcutting'), (11,2,28880,'Gift of the Naaru'), (11,2,29932,'Language Draenei'), +(11,2,45927,'Summon Friend'), (11,3,75,'Auto Shot'), (11,3,81,'Dodge'), (11,3,201,'One-Handed Swords'), @@ -11092,6 +11145,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (11,3,28880,'Gift of the Naaru'), (11,3,29932,'Language Draenei'), (11,3,34082,'Advantaged State(DND)'), +(11,3,45927,'Summon Friend'), (11,5,81,'Dodge'), (11,5,198,'One-Handed Maces'), (11,5,203,'Unarmed'), @@ -11127,6 +11181,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (11,5,28878,'Inspiring Presence'), (11,5,28880,'Gift of the Naaru'), (11,5,29932,'Language Draenei'), +(11,5,45927,'Summon Friend'), (11,7,81,'Dodge'), (11,7,107,'Block'), (11,7,198,'One-Handed Maces'), @@ -11165,6 +11220,7 @@ INSERT INTO `playercreateinfo_spell` VALUES (11,7,28878,'Inspiring Presence'), (11,7,28880,'Gift of the Naaru'), (11,7,29932,'Language Draenei'), +(11,7,45927,'Summon Friend'), (11,8,81,'Dodge'), (11,8,133,'Fireball'), (11,8,168,'Frost Armor'), @@ -11199,7 +11255,8 @@ INSERT INTO `playercreateinfo_spell` VALUES (11,8,28875,'Gemcutting'), (11,8,28878,'Inspiring Presence'), (11,8,28880,'Gift of the Naaru'), -(11,8,29932,'Language Draenei'); +(11,8,29932,'Language Draenei'), +(11,8,45927,'Summon Friend'); /*!40000 ALTER TABLE `playercreateinfo_spell` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/realmd.sql b/sql/realmd.sql index 0fe246f44..648572b19 100644 --- a/sql/realmd.sql +++ b/sql/realmd.sql @@ -21,7 +21,7 @@ DROP TABLE IF EXISTS `realmd_db_version`; CREATE TABLE `realmd_db_version` ( - `required_10008_01_realmd_realmd_db_version` bit(1) default NULL + `required_s1980_xxxxx_01_realmd_account_friends` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB'; -- @@ -101,6 +101,28 @@ LOCK TABLES `account_banned` WRITE; /*!40000 ALTER TABLE `account_banned` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Table structure for table `account_friends` +-- + +DROP TABLE IF EXISTS `account_friends`; +CREATE TABLE `account_friends` ( + `id` int(11) unsigned NOT NULL DEFAULT '0', + `friend_id` int(11) unsigned NOT NULL DEFAULT '0', + `bind_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Bring Date', + `expire_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Expire Date', + PRIMARY KEY (`id`,`friend_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0 COMMENT='Stores accounts for Refer-a-Friend System.'; + +-- +-- Dumping data for table `account_friends` +-- + +LOCK TABLES `account_friends` WRITE; +/*!40000 ALTER TABLE `account_friends` DISABLE KEYS */; +/*!40000 ALTER TABLE `account_friends` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `ip_banned` -- diff --git a/sql/updates/s1980_xxxxx_01_characters_characters.sql b/sql/updates/s1980_xxxxx_01_characters_characters.sql new file mode 100644 index 000000000..56a3d6b42 --- /dev/null +++ b/sql/updates/s1980_xxxxx_01_characters_characters.sql @@ -0,0 +1,3 @@ +ALTER TABLE character_db_version CHANGE COLUMN required_s1350_11716_09_characters_mail required_s1980_xxxxx_01_characters_characters bit; + +ALTER TABLE `characters` ADD COLUMN `grantableLevels` tinyint(3) unsigned NOT NULL default '0' AFTER `actionBars`; diff --git a/sql/updates/s1980_xxxxx_01_mangos_command.sql b/sql/updates/s1980_xxxxx_01_mangos_command.sql new file mode 100644 index 000000000..28f1ea595 --- /dev/null +++ b/sql/updates/s1980_xxxxx_01_mangos_command.sql @@ -0,0 +1,12 @@ +ALTER TABLE db_version CHANGE COLUMN required_s1957_12440_01_mangos_spell_area required_s1980_xxxxx_01_mangos_command bit; + +DELETE FROM command WHERE name IN ( + 'account friend add', + 'account friend delete', + 'account friend list' +); + +INSERT INTO `command` (`name`,`security`,`help`) VALUES +('account friend add',3,'Syntax: .account friend add [#accountId|$accountName] [#friendaccountId|$friendaccountName]\r\n\r\nSet friend account.'), +('account friend delete',3,'Syntax: .account friend delete [#accountId|$accountName] [#friendaccountId|$friendaccountName]\r\n\r\nDelete friend account.'), +('account friend list',3,'Syntax: .account friend list [#accountId|$accountName]\r\n\r\nList friends for account.'); diff --git a/sql/updates/s1980_xxxxx_01_realmd_account_friends.sql b/sql/updates/s1980_xxxxx_01_realmd_account_friends.sql new file mode 100644 index 000000000..ca716687c --- /dev/null +++ b/sql/updates/s1980_xxxxx_01_realmd_account_friends.sql @@ -0,0 +1,11 @@ +ALTER TABLE realmd_db_version CHANGE COLUMN required_10008_01_realmd_realmd_db_version required_s1980_xxxxx_01_realmd_account_friends bit; + +DROP TABLE IF EXISTS `account_friends`; + +CREATE TABLE `account_friends` ( + `id` int(11) unsigned NOT NULL DEFAULT '0', + `friend_id` int(11) unsigned NOT NULL DEFAULT '0', + `bind_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Bring Date', + `expire_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Expire Date', + PRIMARY KEY (`id`,`friend_id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0 COMMENT='Stores accounts for Refer-a-Friend System.'; diff --git a/sql/updates/s1980_xxxxx_02_mangos_mangos_string.sql b/sql/updates/s1980_xxxxx_02_mangos_mangos_string.sql new file mode 100644 index 000000000..c26a3116e --- /dev/null +++ b/sql/updates/s1980_xxxxx_02_mangos_mangos_string.sql @@ -0,0 +1,6 @@ +ALTER TABLE db_version CHANGE COLUMN required_s1980_xxxxx_01_mangos_command required_s1980_xxxxx_02_mangos_mangos_string bit; + +DELETE FROM `mangos_string` WHERE `entry` IN (11133,11134); +INSERT INTO `mangos_string` VALUES +(1700,'RAF system ok.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(1701,'RAF system error.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); diff --git a/sql/updates/s1980_xxxxx_03_mangos_playercreateinfo_spell.sql b/sql/updates/s1980_xxxxx_03_mangos_playercreateinfo_spell.sql new file mode 100644 index 000000000..c32463de8 --- /dev/null +++ b/sql/updates/s1980_xxxxx_03_mangos_playercreateinfo_spell.sql @@ -0,0 +1,57 @@ +ALTER TABLE db_version CHANGE COLUMN required_s1980_xxxxx_02_mangos_mangos_string required_s1980_xxxxx_03_mangos_playercreateinfo_spell bit; + +DELETE FROM `playercreateinfo_spell` WHERE spell=45927; + +INSERT INTO `playercreateinfo_spell` VALUES +(1,1,45927,'Summon Friend'), +(1,2,45927,'Summon Friend'), +(1,4,45927,'Summon Friend'), +(1,5,45927,'Summon Friend'), +(1,8,45927,'Summon Friend'), +(1,9,45927,'Summon Friend'), +(2,1,45927,'Summon Friend'), +(2,3,45927,'Summon Friend'), +(2,4,45927,'Summon Friend'), +(2,7,45927,'Summon Friend'), +(2,9,45927,'Summon Friend'), +(3,1,45927,'Summon Friend'), +(3,2,45927,'Summon Friend'), +(3,3,45927,'Summon Friend'), +(3,4,45927,'Summon Friend'), +(3,5,45927,'Summon Friend'), +(4,1,45927,'Summon Friend'), +(4,3,45927,'Summon Friend'), +(4,4,45927,'Summon Friend'), +(4,5,45927,'Summon Friend'), +(4,11,45927,'Summon Friend'), +(5,1,45927,'Summon Friend'), +(5,4,45927,'Summon Friend'), +(5,5,45927,'Summon Friend'), +(5,8,45927,'Summon Friend'), +(5,9,45927,'Summon Friend'), +(6,1,45927,'Summon Friend'), +(6,3,45927,'Summon Friend'), +(6,7,45927,'Summon Friend'), +(6,11,45927,'Summon Friend'), +(7,1,45927,'Summon Friend'), +(7,4,45927,'Summon Friend'), +(7,8,45927,'Summon Friend'), +(7,9,45927,'Summon Friend'), +(8,1,45927,'Summon Friend'), +(8,3,45927,'Summon Friend'), +(8,4,45927,'Summon Friend'), +(8,5,45927,'Summon Friend'), +(8,7,45927,'Summon Friend'), +(8,8,45927,'Summon Friend'), +(10,2,45927,'Summon Friend'), +(10,3,45927,'Summon Friend'), +(10,4,45927,'Summon Friend'), +(10,5,45927,'Summon Friend'), +(10,8,45927,'Summon Friend'), +(10,9,45927,'Summon Friend'), +(11,1,45927,'Summon Friend'), +(11,2,45927,'Summon Friend'), +(11,3,45927,'Summon Friend'), +(11,5,45927,'Summon Friend'), +(11,7,45927,'Summon Friend'), +(11,8,45927,'Summon Friend'); diff --git a/src/game/AccountMgr.cpp b/src/game/AccountMgr.cpp index 79889e23b..816857bd0 100644 --- a/src/game/AccountMgr.cpp +++ b/src/game/AccountMgr.cpp @@ -21,6 +21,7 @@ #include "ObjectAccessor.h" #include "ObjectGuid.h" #include "Player.h" +#include "World.h" #include "Policies/Singleton.h" #include "Util.h" #include "Auth/Sha1.h" @@ -244,3 +245,46 @@ std::string AccountMgr::CalculateShaPassHash(std::string& name, std::string& pas return encoded; } + +std::vector AccountMgr::GetRAFAccounts(uint32 accid, bool referred) +{ + + QueryResult* result; + + if (referred) + result = LoginDatabase.PQuery("SELECT `friend_id` FROM `account_friends` WHERE `id` = %u AND `expire_date` > NOW() LIMIT %u", accid, sWorld.getConfig(CONFIG_UINT32_RAF_MAXREFERERS)); + else + result = LoginDatabase.PQuery("SELECT `id` FROM `account_friends` WHERE `friend_id` = %u AND `expire_date` > NOW() LIMIT %u", accid, sWorld.getConfig(CONFIG_UINT32_RAF_MAXREFERALS)); + + std::vector acclist; + + if (result) + { + do + { + Field* fields = result->Fetch(); + uint32 refaccid = fields[0].GetUInt32(); + acclist.push_back(refaccid); + } + while (result->NextRow()); + delete result; + } + + return acclist; +} + +AccountOpResult AccountMgr::AddRAFLink(uint32 accid, uint32 friendid) +{ + if (!LoginDatabase.PExecute("INSERT INTO `account_friends` (`id`, `friend_id`, `expire_date`) VALUES (%u,%u,NOW() + INTERVAL 3 MONTH)", accid, friendid)) + return AOR_DB_INTERNAL_ERROR; + + return AOR_OK; +} + +AccountOpResult AccountMgr::DeleteRAFLink(uint32 accid, uint32 friendid) +{ + if (!LoginDatabase.PExecute("DELETE FROM `account_friends` WHERE `id` = %u AND `friend_id` = %u", accid, friendid)) + return AOR_DB_INTERNAL_ERROR; + + return AOR_OK; +} diff --git a/src/game/AccountMgr.h b/src/game/AccountMgr.h index 9edb96762..44c7d1d70 100644 --- a/src/game/AccountMgr.h +++ b/src/game/AccountMgr.h @@ -53,6 +53,10 @@ class AccountMgr uint32 GetCharactersCount(uint32 acc_id); std::string CalculateShaPassHash(std::string& name, std::string& password); + std::vector GetRAFAccounts(uint32 accid, bool referred = true); + AccountOpResult AddRAFLink(uint32 accid, uint32 friendid); + AccountOpResult DeleteRAFLink(uint32 accid, uint32 friendid); + static bool normalizeString(std::string& utf8str); }; diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp index 90a357194..369bc6d93 100644 --- a/src/game/CharacterHandler.cpp +++ b/src/game/CharacterHandler.cpp @@ -73,7 +73,7 @@ bool LoginQueryHolder::Initialize() "position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost," "resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty," "arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk," - "health, power1, power2, power3, power4, power5, exploredZones, equipmentCache, ammoId, knownTitles, actionBars FROM characters WHERE guid = '%u'", m_guid.GetCounter()); + "health, power1, power2, power3, power4, power5, exploredZones, equipmentCache, ammoId, knownTitles, actionBars, grantableLevels FROM characters WHERE guid = '%u'", m_guid.GetCounter()); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT groupId FROM group_member WHERE memberGuid ='%u'", m_guid.GetCounter()); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", m_guid.GetCounter()); res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,item_guid,spell,stackcount,remaincharges,basepoints0,basepoints1,basepoints2,periodictime0,periodictime1,periodictime2,maxduration,remaintime,effIndexMask FROM character_aura WHERE guid = '%u'", m_guid.GetCounter()); diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index b8f86eeb6..7fab42d59 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -70,6 +70,14 @@ ChatCommand* ChatHandler::getCommandTable() { NULL, 0, false, NULL, "", NULL } }; + static ChatCommand accountFriendCommandTable[] = + { + { "add" , SEC_ADMINISTRATOR, true, &ChatHandler::HandleAccountFriendAddCommand, "", NULL }, + { "delete", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAccountFriendDeleteCommand, "", NULL }, + { "list", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAccountFriendListCommand, "", NULL }, + { NULL, 0, false, NULL, "", NULL } + }; + static ChatCommand accountCommandTable[] = { { "characters", SEC_ADMINISTRATOR, true, &ChatHandler::HandleAccountCharactersCommand, "", NULL }, @@ -78,6 +86,7 @@ ChatCommand* ChatHandler::getCommandTable() { "onlinelist", SEC_CONSOLE, true, &ChatHandler::HandleAccountOnlineListCommand, "", NULL }, { "lock", SEC_PLAYER, true, &ChatHandler::HandleAccountLockCommand, "", NULL }, { "set", SEC_ADMINISTRATOR, true, NULL, "", accountSetCommandTable }, + { "friend", SEC_ADMINISTRATOR, true, NULL, "", accountFriendCommandTable }, { "password", SEC_PLAYER, true, &ChatHandler::HandleAccountPasswordCommand, "", NULL }, { "", SEC_PLAYER, true, &ChatHandler::HandleAccountCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } diff --git a/src/game/Chat.h b/src/game/Chat.h index 7744a98fd..458df5330 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -152,6 +152,10 @@ class MANGOS_DLL_SPEC ChatHandler bool HandleAHBotReloadCommand(char* args); bool HandleAHBotStatusCommand(char* args); + bool HandleAccountFriendAddCommand(char* args); + bool HandleAccountFriendDeleteCommand(char* args); + bool HandleAccountFriendListCommand(char* args); + bool HandleAuctionAllianceCommand(char* args); bool HandleAuctionGoblinCommand(char* args); bool HandleAuctionHordeCommand(char* args); diff --git a/src/game/Group.h b/src/game/Group.h index 178499642..d0a9b6f1c 100644 --- a/src/game/Group.h +++ b/src/game/Group.h @@ -76,6 +76,7 @@ enum GroupMemberOnlineStatus MEMBER_STATUS_UNK3 = 0x0020, // used in calls from Lua_GetPlayerMapPosition/Lua_GetBattlefieldFlagPosition MEMBER_STATUS_AFK = 0x0040, // Lua_UnitIsAFK MEMBER_STATUS_DND = 0x0080, // Lua_UnitIsDND + MEMBER_STATUS_RAF = 0x0100, // RAF status in party/raid }; enum GroupType diff --git a/src/game/GroupHandler.cpp b/src/game/GroupHandler.cpp index b2dca8cfc..5a29f2713 100644 --- a/src/game/GroupHandler.cpp +++ b/src/game/GroupHandler.cpp @@ -793,9 +793,11 @@ void WorldSession::HandleRequestPartyMemberStatsOpcode(WorldPacket& recv_data) if (pet) mask1 = 0x7FFFFFFF; // for hunters and other classes with pets + uint16 online_status = GetPlayer()->IsReferAFriendLinked(player) ? (MEMBER_STATUS_ONLINE | MEMBER_STATUS_RAF) : MEMBER_STATUS_ONLINE; + Powers powerType = player->getPowerType(); data << uint32(mask1); // group update mask - data << uint16(MEMBER_STATUS_ONLINE); // member's online status + data << uint16(online_status); // member's online status data << uint16(player->GetHealth()); // GROUP_UPDATE_FLAG_CUR_HP data << uint16(player->GetMaxHealth()); // GROUP_UPDATE_FLAG_MAX_HP data << uint8(powerType); // GROUP_UPDATE_FLAG_POWER_TYPE diff --git a/src/game/Language.h b/src/game/Language.h index 1cf965c9b..e928e0b52 100644 --- a/src/game/Language.h +++ b/src/game/Language.h @@ -1015,7 +1015,11 @@ enum MangosStrings LANG_OPVP_SI_CAPTURE_H = 1635, LANG_OPVP_SI_CAPTURE_A = 1636, - // FREE IDS 1700-9999 + // Refer-A-Friend + LANG_COMMAND_FRIEND = 1700, + LANG_COMMAND_FRIEND_ERROR = 1701, + + // FREE IDS 1800-9999 // Use for not-in-official-sources patches // 10000-10999 diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index b7376a1ec..82f78c0fd 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -6642,3 +6642,73 @@ bool ChatHandler::HandleMmapTestArea(char* args) return true; } + +// Set friends for account +bool ChatHandler::HandleAccountFriendAddCommand(char* args) +{ + ///- Get the command line arguments + std::string account_name; + uint32 targetAccountId = ExtractAccountId(&args, &account_name); + + if (!targetAccountId) + return false; + + std::string account_friend_name; + uint32 friendAccountId = ExtractAccountId(&args, &account_friend_name); + + if (!friendAccountId) + return false; + + AccountOpResult result = sAccountMgr.AddRAFLink(targetAccountId, friendAccountId); + + switch(result) + { + case AOR_OK: + SendSysMessage(LANG_COMMAND_FRIEND); + break; + default: + SendSysMessage(LANG_COMMAND_FRIEND_ERROR); + SetSentErrorMessage(true); + return false; + } + + return true; +} + +// Delete friends for account +bool ChatHandler::HandleAccountFriendDeleteCommand(char* args) +{ + ///- Get the command line arguments + std::string account_name; + uint32 targetAccountId = ExtractAccountId(&args, &account_name); + + if (!targetAccountId) + return false; + + std::string account_friend_name; + uint32 friendAccountId = ExtractAccountId(&args, &account_friend_name); + + if (!friendAccountId) + return false; + + AccountOpResult result = sAccountMgr.DeleteRAFLink(targetAccountId, friendAccountId); + + switch(result) + { + case AOR_OK: + SendSysMessage(LANG_COMMAND_FRIEND); + break; + default: + SendSysMessage(LANG_COMMAND_FRIEND_ERROR); + SetSentErrorMessage(true); + return false; + } + + return true; +} + +// List friends for account +bool ChatHandler::HandleAccountFriendListCommand(char* args) +{ + return false; +} diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp index 0e565395a..493dfaf86 100644 --- a/src/game/MiscHandler.cpp +++ b/src/game/MiscHandler.cpp @@ -399,13 +399,13 @@ void WorldSession::HandleSetSelectionOpcode(WorldPacket& recv_data) ObjectGuid guid; recv_data >> guid; - _player->SetSelectionGuid(guid); - // update reputation list if need Unit* unit = ObjectAccessor::GetUnit(*_player, guid); // can select group members at diff maps if (!unit) return; + _player->SetSelectionGuid(guid); + if (FactionTemplateEntry const* factionTemplateEntry = sFactionTemplateStore.LookupEntry(unit->getFaction())) _player->GetReputationMgr().SetVisible(factionTemplateEntry); } @@ -1411,3 +1411,59 @@ void WorldSession::HandleSetTaxiBenchmarkOpcode(WorldPacket& recv_data) DEBUG_LOG("Client used \"/timetest %d\" command", mode); } + +// Refer-A-Friend +void WorldSession::HandleGrantLevel(WorldPacket& recv_data) +{ + DEBUG_LOG("WORLD: CMSG_GRANT_LEVEL"); + + ObjectGuid guid; + recv_data >> guid.ReadAsPacked(); + + if (!guid.IsPlayer()) + return; + + Player * target = sObjectMgr.GetPlayer(guid); + + // cheating and other check + ReferAFriendError err = _player->GetReferFriendError(target, false); + + if (err) + { + _player->SendReferFriendError(err, target); + return; + } + + target->AccessGrantableLevel(_player->GetObjectGuid()); + + WorldPacket data(SMSG_PROPOSE_LEVEL_GRANT, 8); + data << _player->GetPackGUID(); + target->GetSession()->SendPacket(&data); +} + +void WorldSession::HandleAcceptGrantLevel(WorldPacket& recv_data) +{ + DEBUG_LOG("WORLD: CMSG_ACCEPT_LEVEL_GRANT"); + + ObjectGuid guid; + recv_data >> guid.ReadAsPacked(); + + if (!guid.IsPlayer()) + return; + + if (!_player->IsAccessGrantableLevel(guid)) + return; + + _player->AccessGrantableLevel(ObjectGuid()); + Player * grant_giver = sObjectMgr.GetPlayer(guid); + + if (!grant_giver) + return; + + if (grant_giver->GetGrantableLevels()) + grant_giver->ChangeGrantableLevels(0); + else + return; + + _player->GiveLevel(_player->getLevel() + 1); +} diff --git a/src/game/Object.cpp b/src/game/Object.cpp index 3e0cf28f5..49a1d2af9 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -519,6 +519,14 @@ void Object::BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, UpdateMask* u else *data << uint32(0); // disable quest object } + // hide RAF flag if need + else if (index == UNIT_DYNAMIC_FLAGS && GetTypeId() == TYPEID_PLAYER) + { + if (!((Player*)this)->IsReferAFriendLinked(target)) + *data << (m_uint32Values[index] & ~UNIT_DYNFLAG_REFER_A_FRIEND); + else + *data << m_uint32Values[index]; + } else *data << m_uint32Values[index]; // other cases } diff --git a/src/game/Opcodes.cpp b/src/game/Opcodes.cpp index 484b9ff2b..d0ace13ca 100644 --- a/src/game/Opcodes.cpp +++ b/src/game/Opcodes.cpp @@ -1062,7 +1062,7 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x409*/ { "MSG_QUERY_GUILD_BANK_TEXT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleQueryGuildBankTabText }, /*0x40A*/ { "CMSG_SET_GUILD_BANK_TEXT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSetGuildBankTabText }, /*0x40B*/ { "CMSG_SET_GRANTABLE_LEVELS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x40C*/ { "CMSG_GRANT_LEVEL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, + /*0x40C*/ { "CMSG_GRANT_LEVEL", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGrantLevel }, /*0x40D*/ { "CMSG_REFER_A_FRIEND", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, /*0x40E*/ { "MSG_GM_CHANGE_ARENA_RATING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, /*0x40F*/ { "CMSG_DECLINE_CHANNEL_INVITE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, @@ -1081,8 +1081,8 @@ OpcodeHandler opcodeTable[NUM_MSG_TYPES] = /*0x41C*/ { "SMSG_SERVER_BUCK_DATA", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, /*0x41D*/ { "SMSG_SEND_UNLEARN_SPELLS", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, /*0x41E*/ { "SMSG_PROPOSE_LEVEL_GRANT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, - /*0x41F*/ { "CMSG_ACCEPT_LEVEL_GRANT", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL }, - /*0x420*/ { "SMSG_REFER_A_FRIEND_FAILURE", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, + /*0x41F*/ { "CMSG_ACCEPT_LEVEL_GRANT", STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAcceptGrantLevel }, + /*0x420*/ { "SMSG_REFER_A_FRIEND_ERROR", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, /*0x421*/ { "SMSG_SPLINE_MOVE_SET_FLYING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, /*0x422*/ { "SMSG_SPLINE_MOVE_UNSET_FLYING", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, /*0x423*/ { "SMSG_SUMMON_CANCEL", STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide }, diff --git a/src/game/Opcodes.h b/src/game/Opcodes.h index 275868614..420bbd310 100644 --- a/src/game/Opcodes.h +++ b/src/game/Opcodes.h @@ -1090,7 +1090,7 @@ enum Opcodes SMSG_SEND_UNLEARN_SPELLS = 0x41D, SMSG_PROPOSE_LEVEL_GRANT = 0x41E, CMSG_ACCEPT_LEVEL_GRANT = 0x41F, - SMSG_REFER_A_FRIEND_FAILURE = 0x420, + SMSG_REFER_A_FRIEND_ERROR = 0x420, SMSG_SPLINE_MOVE_SET_FLYING = 0x421, SMSG_SPLINE_MOVE_UNSET_FLYING = 0x422, SMSG_SUMMON_CANCEL = 0x423 diff --git a/src/game/Player.cpp b/src/game/Player.cpp index cb4ce3741..2bdbd7662 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -62,6 +62,7 @@ #include "Mail.h" #include "DBCStores.h" #include "SQLStorages.h" +#include "AccountMgr.h" #include @@ -546,6 +547,10 @@ Player::Player(WorldSession* session): Unit(), m_mover(this), m_camera(this), m_ m_lastFallTime = 0; m_lastFallZ = 0; + + // Refer-A-Friend + m_GrantableLevelsCount = 0; + } Player::~Player() @@ -661,7 +666,13 @@ bool Player::Create(uint32 guidlow, const std::string& name, uint8 race, uint8 c SetByteValue(PLAYER_BYTES, 3, hairColor); SetByteValue(PLAYER_BYTES_2, 0, facialHair); - SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_NORMAL); + + LoadAccountLinkedState(); + + if (GetAccountLinkedState() != STATE_NOT_LINKED) + SetByteValue(PLAYER_BYTES_2, 3, 0x06); // rest state = refer-a-friend + else + SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_NORMAL); // rest state = normal SetUInt16Value(PLAYER_BYTES_3, 0, gender); // only GENDER_MALE/GENDER_FEMALE (1 bit) allowed, drunk state = 0 SetByteValue(PLAYER_BYTES_3, 3, 0); // BattlefieldArenaFaction (0 or 1) @@ -2292,18 +2303,18 @@ void Player::RemoveFromGroup(Group* group, ObjectGuid guid) } } -void Player::SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 RestXP) +void Player::SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 BonusXP, bool ReferAFriend) { WorldPacket data(SMSG_LOG_XPGAIN, 21); data << (victim ? victim->GetObjectGuid() : ObjectGuid());// guid - data << uint32(GivenXP + RestXP); // given experience + data << uint32(GivenXP + BonusXP); // total experience data << uint8(victim ? 0 : 1); // 00-kill_xp type, 01-non_kill_xp type if (victim) { data << uint32(GivenXP); // experience without rested bonus data << float(1); // 1 - none 0 - 100% group bonus output } - data << uint8(0); // new 2.4.0 + data << uint8(ReferAFriend ? 1 : 0); // Refer-A-Friend State GetSession()->SendPacket(&data); } @@ -2326,21 +2337,47 @@ void Player::GiveXP(uint32 xp, Unit* victim) for (Unit::AuraList::const_iterator i = ModXPPctAuras.begin(); i != ModXPPctAuras.end(); ++i) xp = uint32(xp * (1.0f + (*i)->GetModifier()->m_amount / 100.0f)); - // XP resting bonus for kill - uint32 rested_bonus_xp = victim ? GetXPRestBonus(xp) : 0; + uint32 bonus_xp = 0; + bool ReferAFriend = false; + if (CheckRAFConditions()) + { + // RAF bonus exp don't decrease rest exp + bool ReferAFriend = true; + bonus_xp = xp * (sWorld.getConfig(CONFIG_FLOAT_RATE_RAF_XP) - 1); + } + else + // XP resting bonus for kill + bonus_xp = victim ? GetXPRestBonus(xp) : 0; - SendLogXPGain(xp, victim, rested_bonus_xp); + SendLogXPGain(xp, victim, bonus_xp, ReferAFriend); uint32 curXP = GetUInt32Value(PLAYER_XP); uint32 nextLvlXP = GetUInt32Value(PLAYER_NEXT_LEVEL_XP); - uint32 newXP = curXP + xp + rested_bonus_xp; + uint32 newXP = curXP + xp + bonus_xp; while (newXP >= nextLvlXP && level < sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL)) { newXP -= nextLvlXP; if (level < sWorld.getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL)) + { GiveLevel(level + 1); + level = getLevel(); + // Refer-A-Friend + if (GetAccountLinkedState() == STATE_REFERRAL || GetAccountLinkedState() == STATE_DUAL) + { + if (level < sWorld.getConfig(CONFIG_UINT32_RAF_MAXGRANTLEVEL)) + { + if (sWorld.getConfig(CONFIG_FLOAT_RATE_RAF_LEVELPERLEVEL) < 1.0f) + { + if ( level%uint8(1.0f/sWorld.getConfig(CONFIG_FLOAT_RATE_RAF_LEVELPERLEVEL)) == 0 ) + ChangeGrantableLevels(1); + } + else + ChangeGrantableLevels(uint8(sWorld.getConfig(CONFIG_FLOAT_RATE_RAF_LEVELPERLEVEL))); + } + } + } level = getLevel(); nextLvlXP = GetUInt32Value(PLAYER_NEXT_LEVEL_XP); @@ -4177,6 +4214,10 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) SetWaterWalk(false); SetRoot(false); + // refer-a-friend flag - maybe wrong and hacky + if (GetAccountLinkedState() != STATE_NOT_LINKED) + SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_REFER_A_FRIEND); + m_deathTimer = 0; // set health/powers (0- will be set in caller) @@ -5994,6 +6035,11 @@ int32 Player::CalculateReputationGain(ReputationSource source, int32 rep, int32 percent *= repRate; } + if (CheckRAFConditions()) + { + percent *= sWorld.getConfig(CONFIG_FLOAT_RATE_RAF_REPUTATION); + } + return int32(sWorld.getConfig(CONFIG_FLOAT_RATE_REPUTATION_GAIN) * rep * percent / 100.0f); } @@ -14548,8 +14594,8 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder) //"resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty," // 39 40 41 42 43 44 45 46 47 48 //"arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk," - // 49 50 51 52 53 54 55 56 57 58 59 - //"health, power1, power2, power3, power4, power5, exploredZones, equipmentCache, ammoId, knownTitles, actionBars FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid)); + // 49 50 51 52 53 54 55 56 57 58 59 60 + //"health, power1, power2, power3, power4, power5, exploredZones, equipmentCache, ammoId, knownTitles, actionBars, grantableLevels FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid)); QueryResult* result = holder->GetResult(PLAYER_LOGIN_QUERY_LOADFROM); if (!result) @@ -14957,6 +15003,17 @@ bool Player::LoadFromDB(ObjectGuid guid, SqlQueryHolder* holder) _LoadMailedItems(holder->GetResult(PLAYER_LOGIN_QUERY_LOADMAILEDITEMS)); UpdateNextMailTimeAndUnreads(); + m_GrantableLevelsCount = fields[60].GetUInt32(); + + // refer-a-friend flag - maybe wrong and hacky + LoadAccountLinkedState(); + if (GetAccountLinkedState() != STATE_NOT_LINKED) + SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_REFER_A_FRIEND); + + // set grant flag + if (m_GrantableLevelsCount > 0) + SetByteValue(PLAYER_FIELD_BYTES, 1, 0x01); + _LoadAuras(holder->GetResult(PLAYER_LOGIN_QUERY_LOADAURAS), time_diff); // add ghost flag (must be after aura load: PLAYER_FLAGS_GHOST set in aura) @@ -16159,7 +16216,7 @@ void Player::SaveToDB() "trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, " "death_expire_time, taxi_path, arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, " "todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, health, power1, power2, power3, " - "power4, power5, exploredZones, equipmentCache, ammoId, knownTitles, actionBars) " + "power4, power5, exploredZones, equipmentCache, ammoId, knownTitles, actionBars, grantableLevels) " "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " "?, ?, ?, ?, ?, ?, " "?, ?, ?, " @@ -16167,7 +16224,7 @@ void Player::SaveToDB() "?, ?, ?, ?, ?, ?, ?, ?, ?, " "?, ?, ?, ?, ?, ?, ?, " "?, ?, ?, ?, ?, ?, ?, ?, ?, " - "?, ?, ?, ?, ?, ?, ?) "); + "?, ?, ?, ?, ?, ?, ?, ?) "); uberInsert.addUInt32(GetGUIDLow()); uberInsert.addUInt32(GetSession()->GetAccountId()); @@ -16294,6 +16351,8 @@ void Player::SaveToDB() uberInsert.addUInt32(uint32(GetByteValue(PLAYER_FIELD_BYTES, 2))); + uberInsert.addUInt32(m_GrantableLevelsCount); + uberInsert.Execute(); if (m_mailsUpdated) // save mails only when needed @@ -17564,10 +17623,15 @@ void Player::SetRestBonus(float rest_bonus_new) m_rest_bonus = rest_bonus_new; // update data for client - if (m_rest_bonus > 10) - SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_RESTED); - else if (m_rest_bonus <= 1) - SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_NORMAL); + if (GetAccountLinkedState() != STATE_NOT_LINKED) + SetByteValue(PLAYER_BYTES_2, 3, 0x06); // Set Reststate = Refer-A-Friend + else + { + if (m_rest_bonus > 10) + SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_RESTED); // Set Reststate = Rested + else if (m_rest_bonus<=1) + SetByteValue(PLAYER_BYTES_2, 3, REST_STATE_NORMAL); // Set Reststate = Normal + } // RestTickUpdate SetUInt32Value(PLAYER_REST_STATE_EXPERIENCE, uint32(m_rest_bonus)); @@ -20927,3 +20991,165 @@ AreaLockStatus Player::GetAreaTriggerLockStatus(AreaTrigger const* at, uint32& m return AREA_LOCKSTATUS_OK; }; + +// Refer-A-Friend +void Player::SendReferFriendError(ReferAFriendError err, Player * target) +{ + WorldPacket data(SMSG_REFER_A_FRIEND_ERROR, 24); + data << uint32(err); + if (target && (err == ERR_REFER_A_FRIEND_NOT_IN_GROUP || err == ERR_REFER_A_FRIEND_SUMMON_OFFLINE_S)) + data << target->GetName(); + + GetSession()->SendPacket(&data); +} + +ReferAFriendError Player::GetReferFriendError(Player * target, bool summon) +{ + if (!target || target->GetTypeId() != TYPEID_PLAYER) + return summon ? ERR_REFER_A_FRIEND_SUMMON_OFFLINE_S : ERR_REFER_A_FRIEND_NO_TARGET; + + if (!IsReferAFriendLinked(target)) + return ERR_REFER_A_FRIEND_NOT_REFERRED_BY; + + if (Group * gr1 = GetGroup()) + { + Group * gr2 = target->GetGroup(); + + if (!gr2 || gr1->GetId() != gr2->GetId()) + return ERR_REFER_A_FRIEND_NOT_IN_GROUP; + } + + if (summon) + { + if (HasSpellCooldown(45927)) + return ERR_REFER_A_FRIEND_SUMMON_COOLDOWN; + if (target->getLevel() > sWorld.getConfig(CONFIG_UINT32_RAF_MAXGRANTLEVEL)) + return ERR_REFER_A_FRIEND_SUMMON_LEVEL_MAX_I; + + if (MapEntry const* mEntry = sMapStore.LookupEntry(GetMapId())) + if (mEntry->Expansion() > target->GetSession()->Expansion()) + return ERR_REFER_A_FRIEND_INSUF_EXPAN_LVL; + } + else + { + if (GetTeam() != target->GetTeam() && !sWorld.getConfig(CONFIG_BOOL_ALLOW_TWO_SIDE_INTERACTION_GROUP)) + return ERR_REFER_A_FRIEND_DIFFERENT_FACTION; + if (getLevel() <= target->getLevel()) + return ERR_REFER_A_FRIEND_TARGET_TOO_HIGH; + if (!GetGrantableLevels()) + return ERR_REFER_A_FRIEND_INSUFFICIENT_GRANTABLE_LEVELS; + if (GetDistance(target) > DEFAULT_VISIBILITY_DISTANCE || !target->IsVisibleGloballyFor(this)) + return ERR_REFER_A_FRIEND_TOO_FAR; + if (target->getLevel() >= sWorld.getConfig(CONFIG_UINT32_RAF_MAXGRANTLEVEL)) + return ERR_REFER_A_FRIEND_GRANT_LEVEL_MAX_I; + } + + return ERR_REFER_A_FRIEND_NONE; +} + +void Player::ChangeGrantableLevels(uint8 increase) +{ + if (increase) + { + if (m_GrantableLevelsCount <= uint32(sWorld.getConfig(CONFIG_UINT32_RAF_MAXGRANTLEVEL) * sWorld.getConfig(CONFIG_FLOAT_RATE_RAF_LEVELPERLEVEL))) + m_GrantableLevelsCount += increase; + } + else + { + m_GrantableLevelsCount -= 1; + + if (m_GrantableLevelsCount < 0) + m_GrantableLevelsCount = 0; + } + + // set/unset flag - granted levels + if (m_GrantableLevelsCount > 0) + { + if (!HasByteFlag(PLAYER_FIELD_BYTES, 1, 0x01)) + SetByteFlag(PLAYER_FIELD_BYTES, 1, 0x01); + } + else + { + if (HasByteFlag(PLAYER_FIELD_BYTES, 1, 0x01)) + RemoveByteFlag(PLAYER_FIELD_BYTES, 1, 0x01); + } + +} + +bool Player::CheckRAFConditions() +{ + if (Group * grp = GetGroup()) + { + for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) + { + Player* member = itr->getSource(); + + if (!member || !member->isAlive()) + continue; + + if (GetObjectGuid() == member->GetObjectGuid()) + continue; + + if (member->GetAccountLinkedState() == STATE_NOT_LINKED) + continue; + + if (GetDistance(member) < 100 && (getLevel() <= member->getLevel() + 4)) + return true; + } + } + + return false; +} + +AccountLinkedState Player::GetAccountLinkedState() +{ + + if (!m_referredAccounts.empty() && !m_referalAccounts.empty()) + return STATE_DUAL; + + if (!m_referredAccounts.empty()) + return STATE_REFER; + + if (!m_referalAccounts.empty()) + return STATE_REFERRAL; + + return STATE_NOT_LINKED; +} + +void Player::LoadAccountLinkedState() +{ + m_referredAccounts.clear(); + m_referredAccounts = sAccountMgr.GetRAFAccounts(GetSession()->GetAccountId(), true); + + if (m_referredAccounts.size() > sWorld.getConfig(CONFIG_UINT32_RAF_MAXREFERERS)) + sLog.outError("Player:RAF:Warning: loaded %u referred accounts instead of %u for player %u",m_referredAccounts.size(),sWorld.getConfig(CONFIG_UINT32_RAF_MAXREFERERS),GetObjectGuid().GetCounter()); + else + DEBUG_LOG("Player:RAF: loaded %u referred accounts for player %u",m_referredAccounts.size(),GetObjectGuid().GetCounter()); + + m_referalAccounts.clear(); + m_referalAccounts = sAccountMgr.GetRAFAccounts(GetSession()->GetAccountId(), false); + + if (m_referalAccounts.size() > sWorld.getConfig(CONFIG_UINT32_RAF_MAXREFERALS)) + sLog.outError("Player:RAF:Warning: loaded %u referal accounts instead of %u for player %u",m_referalAccounts.size(),sWorld.getConfig(CONFIG_UINT32_RAF_MAXREFERALS),GetObjectGuid().GetCounter()); + else + DEBUG_LOG("Player:RAF: loaded %u referal accounts for player %u",m_referalAccounts.size(),GetObjectGuid().GetCounter()); +} + +bool Player::IsReferAFriendLinked(Player* target) +{ + // check link this(refer) - target(referral) + for (std::vector::const_iterator itr = m_referalAccounts.begin(); itr != m_referalAccounts.end(); ++itr) + { + if ((*itr) == target->GetSession()->GetAccountId()) + return true; + } + + // check link target(refer) - this(referral) + for (std::vector::const_iterator itr = m_referredAccounts.begin(); itr != m_referredAccounts.end(); ++itr) + { + if ((*itr) == target->GetSession()->GetAccountId()) + return true; + } + + return false; +} diff --git a/src/game/Player.h b/src/game/Player.h index 4960bcb6c..61b6a49c3 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -643,6 +643,32 @@ enum TransferAbortReason TRANSFER_ABORT_DIFFICULTY = 0x07, // difficulty mode is not available for %s. }; +enum ReferAFriendError +{ + ERR_REFER_A_FRIEND_NONE = 0x00, + ERR_REFER_A_FRIEND_NOT_REFERRED_BY = 0x01, + ERR_REFER_A_FRIEND_TARGET_TOO_HIGH = 0x02, + ERR_REFER_A_FRIEND_INSUFFICIENT_GRANTABLE_LEVELS = 0x03, + ERR_REFER_A_FRIEND_TOO_FAR = 0x04, + ERR_REFER_A_FRIEND_DIFFERENT_FACTION = 0x05, + ERR_REFER_A_FRIEND_NOT_NOW = 0x06, + ERR_REFER_A_FRIEND_GRANT_LEVEL_MAX_I = 0x07, + ERR_REFER_A_FRIEND_NO_TARGET = 0x08, + ERR_REFER_A_FRIEND_NOT_IN_GROUP = 0x09, + ERR_REFER_A_FRIEND_SUMMON_LEVEL_MAX_I = 0x0A, + ERR_REFER_A_FRIEND_SUMMON_COOLDOWN = 0x0B, + ERR_REFER_A_FRIEND_INSUF_EXPAN_LVL = 0x0C, + ERR_REFER_A_FRIEND_SUMMON_OFFLINE_S = 0x0D +}; + +enum AccountLinkedState +{ + STATE_NOT_LINKED = 0x00, + STATE_REFER = 0x01, + STATE_REFERRAL = 0x02, + STATE_DUAL = 0x04, +}; + enum InstanceResetWarningType { RAID_INSTANCE_WARNING_HOURS = 1, // WARNING! %s is scheduled to reset in %d hour(s). @@ -1670,7 +1696,7 @@ class MANGOS_DLL_SPEC Player : public Unit void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const override; void DestroyForPlayer(Player* target) const override; - void SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 RestXP); + void SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 BonusXP, bool ReferAFriend); uint8 LastSwingErrorMsg() const { return m_swingErrorMsg; } void SwingErrorMsg(uint8 val) { m_swingErrorMsg = val; } @@ -1997,6 +2023,22 @@ class MANGOS_DLL_SPEC Player : public Unit bool CanSpeak() const; void ChangeSpeakTime(int utime); + /*********************************************************/ + /*** REFER-A-FRIEND SYSTEM ***/ + /*********************************************************/ + void SendReferFriendError(ReferAFriendError err, Player * target = NULL); + ReferAFriendError GetReferFriendError(Player * target, bool summon); + void AccessGrantableLevel(ObjectGuid guid) { m_curGrantLevelGiverGuid = guid; } + bool IsAccessGrantableLevel(ObjectGuid guid) { return m_curGrantLevelGiverGuid == guid; } + uint32 GetGrantableLevels() { return m_GrantableLevelsCount; } + void ChangeGrantableLevels(uint8 increase = 0); + bool CheckRAFConditions(); + AccountLinkedState GetAccountLinkedState(); + bool IsReferAFriendLinked(Player * target); + void LoadAccountLinkedState(); + std::vector m_referredAccounts; + std::vector m_referalAccounts; + /*********************************************************/ /*** VARIOUS SYSTEMS ***/ /*********************************************************/ @@ -2351,6 +2393,12 @@ class MANGOS_DLL_SPEC Player : public Unit float m_summon_z; DeclinedName* m_declinedname; + + // Refer-A-Friend + ObjectGuid m_curGrantLevelGiverGuid; + + int32 m_GrantableLevelsCount; + private: // internal common parts for CanStore/StoreItem functions InventoryResult _CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemPosCountVec& dest, ItemPrototype const* pProto, uint32& count, bool swap, Item* pSrcItem) const; diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index afefb7641..b1fdfd501 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -707,7 +707,7 @@ enum SpellEffects SPELL_EFFECT_CHARGE2 = 149, SPELL_EFFECT_150 = 150, SPELL_EFFECT_TRIGGER_SPELL_2 = 151, - SPELL_EFFECT_152 = 152, + SPELL_EFFECT_FRIEND_SUMMON = 152, SPELL_EFFECT_153 = 153, TOTAL_SPELL_EFFECTS = 154 }; @@ -2161,6 +2161,7 @@ enum UnitDynFlags UNIT_DYNFLAG_ROOTED = 0x0008, UNIT_DYNFLAG_SPECIALINFO = 0x0010, UNIT_DYNFLAG_DEAD = 0x0020, + UNIT_DYNFLAG_REFER_A_FRIEND = 0x0040, }; enum CorpseDynFlags diff --git a/src/game/SocialMgr.cpp b/src/game/SocialMgr.cpp index 2e15d8185..76fc4ff37 100644 --- a/src/game/SocialMgr.cpp +++ b/src/game/SocialMgr.cpp @@ -202,11 +202,12 @@ void SocialMgr::GetFriendInfo(Player* player, uint32 friend_lowguid, FriendInfo& ((pFriend->GetTeam() == team || allowTwoSideWhoList) && (pFriend->GetSession()->GetSecurity() <= gmLevelInWhoList))) && pFriend->IsVisibleGloballyFor(player)) { - friendInfo.Status = FRIEND_STATUS_ONLINE; - if (pFriend->isAFK()) - friendInfo.Status = FRIEND_STATUS_AFK; - if (pFriend->isDND()) - friendInfo.Status = FRIEND_STATUS_DND; + friendInfo.Status |= FRIEND_STATUS_ONLINE; + + pFriend->isAFK() ? friendInfo.Status |= FRIEND_STATUS_AFK : friendInfo.Status &= ~FRIEND_STATUS_AFK; + pFriend->isDND() ? friendInfo.Status |= FRIEND_STATUS_DND : friendInfo.Status &= ~FRIEND_STATUS_DND; + pFriend->IsReferAFriendLinked(player) ? friendInfo.Status |= FRIEND_STATUS_RAF : friendInfo.Status &= ~FRIEND_STATUS_RAF; + friendInfo.Area = pFriend->GetZoneId(); friendInfo.Level = pFriend->getLevel(); friendInfo.Class = pFriend->getClass(); diff --git a/src/game/SocialMgr.h b/src/game/SocialMgr.h index 8823420d0..07a6fe470 100644 --- a/src/game/SocialMgr.h +++ b/src/game/SocialMgr.h @@ -30,11 +30,11 @@ class WorldPacket; enum FriendStatus { - FRIEND_STATUS_OFFLINE = 0, - FRIEND_STATUS_ONLINE = 1, - FRIEND_STATUS_AFK = 2, - FRIEND_STATUS_UNK3 = 3, - FRIEND_STATUS_DND = 4 + FRIEND_STATUS_OFFLINE = 0x00, + FRIEND_STATUS_ONLINE = 0x01, + FRIEND_STATUS_AFK = 0x02, + FRIEND_STATUS_DND = 0x04, + FRIEND_STATUS_RAF = 0x08, }; enum SocialFlag @@ -46,7 +46,7 @@ enum SocialFlag struct FriendInfo { - FriendStatus Status; + uint8 Status; uint32 Flags; uint32 Area; uint32 Level; diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index 8bc0d73ad..9aa50735b 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -2494,6 +2494,7 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList& else if (m_spellInfo->Effect[effIndex] == SPELL_EFFECT_TRIGGER_SPELL) targetUnitMap.push_back(m_caster); break; + case SPELL_EFFECT_FRIEND_SUMMON: case SPELL_EFFECT_SUMMON_PLAYER: if (m_caster->GetTypeId() == TYPEID_PLAYER && ((Player*)m_caster)->GetSelectionGuid()) if (Player* target = sObjectMgr.GetPlayer(((Player*)m_caster)->GetSelectionGuid())) @@ -4941,7 +4942,11 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_BAD_TARGETS; Player* target = sObjectMgr.GetPlayer(((Player*)m_caster)->GetSelectionGuid()); - if (!target || ((Player*)m_caster) == target || !target->IsInSameRaidWith((Player*)m_caster)) + + if ( !target || ((Player*)m_caster) == target) + return SPELL_FAILED_BAD_TARGETS; + + if (!target->IsInSameRaidWith((Player*)m_caster) && m_spellInfo->Id != 48955) return SPELL_FAILED_BAD_TARGETS; // check if our map is dungeon @@ -4957,6 +4962,21 @@ SpellCastResult Spell::CheckCast(bool strict) } break; } + case SPELL_EFFECT_FRIEND_SUMMON: + { + if(m_caster->GetTypeId() != TYPEID_PLAYER) + return SPELL_FAILED_BAD_TARGETS; + + if(((Player*)m_caster)->GetSelectionGuid().IsEmpty()) + return SPELL_FAILED_BAD_TARGETS; + + Player* target = sObjectMgr.GetPlayer(((Player*)m_caster)->GetSelectionGuid()); + + if (!target || !target->IsReferAFriendLinked(((Player*)m_caster))) + return SPELL_FAILED_BAD_TARGETS; + + break; + } case SPELL_EFFECT_LEAP: case SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER: { @@ -6130,6 +6150,7 @@ bool Spell::CheckTarget(Unit* target, SpellEffectIndex eff) // Check targets for LOS visibility (except spells without range limitations ) switch (m_spellInfo->Effect[eff]) { + case SPELL_EFFECT_FRIEND_SUMMON: case SPELL_EFFECT_SUMMON_PLAYER: // from anywhere break; case SPELL_EFFECT_DUMMY: diff --git a/src/game/Spell.h b/src/game/Spell.h index 55131778a..66b53ef25 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -314,6 +314,7 @@ class Spell void EffectPlaySound(SpellEffectIndex eff_idx); void EffectPlayMusic(SpellEffectIndex eff_idx); void EffectKnockBackFromPosition(SpellEffectIndex eff_idx); + void EffectFriendSummon(SpellEffectIndex eff_idx); Spell(Unit* caster, SpellEntry const* info, bool triggered, ObjectGuid originalCasterGUID = ObjectGuid(), SpellEntry const* triggeredBy = NULL); ~Spell(); diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 027699041..c35a1baf9 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -207,7 +207,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS] = &Spell::EffectCharge2, //149 SPELL_EFFECT_CHARGE2 swoop &Spell::EffectUnused, //150 SPELL_EFFECT_150 unused &Spell::EffectTriggerRitualOfSummoning, //151 SPELL_EFFECT_TRIGGER_SPELL_2 - &Spell::EffectNULL, //152 SPELL_EFFECT_152 summon Refer-a-Friend + &Spell::EffectFriendSummon, //152 SPELL_EFFECT_FRIEND_SUMMON summon Refer-a-Friend &Spell::EffectNULL, //153 SPELL_EFFECT_CREATE_PET misc value is creature entry }; @@ -6902,3 +6902,20 @@ void Spell::EffectKnockBackFromPosition(SpellEffectIndex eff_idx) float verticalSpeed = damage * 0.1f; ((Player*)unitTarget)->GetSession()->SendKnockBack(angle, horizontalSpeed, verticalSpeed); } + +void Spell::EffectFriendSummon(SpellEffectIndex eff_idx) +{ + if (m_caster->GetTypeId() != TYPEID_PLAYER) + return; + + if (((Player*)m_caster)->GetSelectionGuid().IsEmpty() || !((Player*)m_caster)->GetSelectionGuid().IsPlayer()) + { + DEBUG_LOG( "Spell::EffectFriendSummon is called, but no selection or selection is not player"); + return; + } + + DEBUG_LOG( "Spell::EffectFriendSummon called for player %u", ((Player*)m_caster)->GetSelectionGuid().GetCounter()); + + m_caster->CastSpell(m_caster, m_spellInfo->EffectTriggerSpell[eff_idx], true); + +} diff --git a/src/game/World.cpp b/src/game/World.cpp index 6e0e6bedd..86dccabc5 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -570,6 +570,13 @@ void World::LoadConfigSettings(bool reload) setConfigMinMax(CONFIG_UINT32_START_PLAYER_LEVEL, "StartPlayerLevel", 1, 1, getConfig(CONFIG_UINT32_MAX_PLAYER_LEVEL)); + setConfigMinMax(CONFIG_UINT32_RAF_MAXGRANTLEVEL, "RAF.MaxGrantLevel", 60, 1, 80); + setConfigMinMax(CONFIG_UINT32_RAF_MAXREFERALS, "RAF.MaxReferals", 5, 0, 15); + setConfigMinMax(CONFIG_UINT32_RAF_MAXREFERERS, "RAF.MaxReferers", 5, 0, 15); + setConfig(CONFIG_FLOAT_RATE_RAF_XP, "Rate.RAF.XP", 3.0f); + setConfig(CONFIG_FLOAT_RATE_RAF_REPUTATION, "Rate.RAF.Reputation", 1.1f); + setConfig(CONFIG_FLOAT_RATE_RAF_LEVELPERLEVEL, "Rate.RAF.LevelPerLevel", 0.5f); + setConfigMinMax(CONFIG_UINT32_START_PLAYER_MONEY, "StartPlayerMoney", 0, 0, MAX_MONEY_AMOUNT); setConfig(CONFIG_UINT32_MAX_HONOR_POINTS, "MaxHonorPoints", 75000); diff --git a/src/game/World.h b/src/game/World.h index c11a953ea..a712317c8 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -177,6 +177,9 @@ enum eConfigUInt32Values CONFIG_UINT32_CHARDELETE_MIN_LEVEL, CONFIG_UINT32_GUID_RESERVE_SIZE_CREATURE, CONFIG_UINT32_GUID_RESERVE_SIZE_GAMEOBJECT, + CONFIG_UINT32_RAF_MAXGRANTLEVEL, + CONFIG_UINT32_RAF_MAXREFERALS, + CONFIG_UINT32_RAF_MAXREFERERS, CONFIG_UINT32_VALUE_COUNT }; @@ -213,6 +216,9 @@ enum eConfigFloatValues CONFIG_FLOAT_RATE_XP_KILL, CONFIG_FLOAT_RATE_XP_QUEST, CONFIG_FLOAT_RATE_XP_EXPLORE, + CONFIG_FLOAT_RATE_RAF_XP, + CONFIG_FLOAT_RATE_RAF_REPUTATION, + CONFIG_FLOAT_RATE_RAF_LEVELPERLEVEL, CONFIG_FLOAT_RATE_REPUTATION_GAIN, CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_KILL, CONFIG_FLOAT_RATE_REPUTATION_LOWLEVEL_QUEST, diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h index 038792f8a..f3f97d7be 100644 --- a/src/game/WorldSession.h +++ b/src/game/WorldSession.h @@ -739,6 +739,11 @@ class MANGOS_DLL_SPEC WorldSession void HandleSetGuildBankTabText(WorldPacket& recv_data); void HandleGetMirrorimageData(WorldPacket& recv_data); + + // Refer-A-Friend + void HandleGrantLevel(WorldPacket& recv_data); + void HandleAcceptGrantLevel(WorldPacket& recv_data); + private: // private trade methods void moveItems(Item* myItems[], Item* hisItems[]); diff --git a/src/mangosd/mangosd.conf.dist.in b/src/mangosd/mangosd.conf.dist.in index 0e2e3810c..0fb80713e 100644 --- a/src/mangosd/mangosd.conf.dist.in +++ b/src/mangosd/mangosd.conf.dist.in @@ -1629,3 +1629,33 @@ SOAP.Port = 7878 CharDelete.Method = 0 CharDelete.MinLevel = 0 CharDelete.KeepDays = 30 + +################################################################################################################### +# REFER-A-FRIEND SYSTEM +# +# RAF.MaxGrantLevel +# Default: 60 - max level for granting level bonuses +# +# RAF.MaxReferals +# Default: 5 - max referals for one account +# +# RAF.MaxReferers +# Default: 5 - max referred accounts for one account +# +# Rate.RAF.XP +# Default: 3 - XP bonus for referred friends in party +# +# Rate.RAF.Reputation +# Default: 1.1 - Reputation bonus for referred friends in party +# +# Rate.RAF.LevelPerLevel +# Default: 0.5 - bonus levels per referal level +# +################################################################################################################### + +RAF.MaxGrantLevel = 60 +RAF.MaxReferals = 5 +RAF.MaxReferers = 5 +Rate.RAF.XP = 3 +Rate.RAF.Reputation = 1.1 +Rate.RAF.LevelPerLevel = 0.5 diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index ed45ca491..c6e1fa87f 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "1979" + #define REVISION_NR "1980" #endif // __REVISION_NR_H__ diff --git a/src/shared/revision_sql.h b/src/shared/revision_sql.h index b7d57557d..0851411f4 100644 --- a/src/shared/revision_sql.h +++ b/src/shared/revision_sql.h @@ -1,6 +1,6 @@ #ifndef __REVISION_SQL_H__ #define __REVISION_SQL_H__ - #define REVISION_DB_CHARACTERS "required_s1350_11716_09_characters_mail" - #define REVISION_DB_MANGOS "required_s1957_12440_01_mangos_spell_area" - #define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version" + #define REVISION_DB_CHARACTERS "required_s1980_xxxxx_01_characters_characters" + #define REVISION_DB_MANGOS "required_s1980_xxxxx_03_mangos_playercreateinfo_spell" + #define REVISION_DB_REALMD "required_s1980_xxxxx_01_realmd_account_friends" #endif // __REVISION_SQL_H__